From 3be39d451cbdce01d822f180fdd0209feb7ff852 Mon Sep 17 00:00:00 2001 From: Mohammad Jalali Date: Sun, 29 Oct 2023 17:42:31 +0330 Subject: [PATCH 1/5] CFE-6 debugging notifications --- .../dashboard/edit-profile/index.jsx | 49 ++++--------- .../notifications/ErrorNotification.jsx | 1 + .../notifications/PendingNotification.jsx | 4 +- .../notifications/SuccessNotification.jsx | 1 + .../notifications/UploadFileNotification.jsx | 2 + .../notifications/WarningNotification.jsx | 1 + src/core/components/notifications/index.jsx | 69 ++++++------------- src/core/utils/errorHandler.js | 27 +++++--- src/core/utils/succesHandler.js | 4 +- src/layouts/AppLayout.jsx | 26 ++++--- src/lib/app/contexts/socket.jsx | 15 +++- src/lib/app/hooks/useRequest.jsx | 4 +- 12 files changed, 89 insertions(+), 114 deletions(-) diff --git a/src/components/dashboard/edit-profile/index.jsx b/src/components/dashboard/edit-profile/index.jsx index e35e3bf..d15d467 100644 --- a/src/components/dashboard/edit-profile/index.jsx +++ b/src/components/dashboard/edit-profile/index.jsx @@ -7,19 +7,18 @@ import * as Yup from "yup"; import {Field, Formik} from "formik"; import {useTranslations} from "next-intl"; import AvatarUpload from "@/core/components/AvatarUpload"; -import axios from "axios"; import {UPDATE_AVATAR} from "@/core/data/apiRoutes"; import useDirection from "@/lib/app/hooks/useDirection"; -import Notifications from "@/core/components/notifications"; import ImageResizer from "@/core/components/ImageConvertor"; +import useRequest from "@/lib/app/hooks/useRequest"; const DashboardEditProfile = () => { const t = useTranslations(); + const requestServer = useRequest({auth: true}) const {user, token, getUser, changeUser} = useUser(); const {directionApp} = useDirection(); const editAvatar = async (avatar) => { - Notifications(t); try { const formData = new FormData(); @@ -28,15 +27,12 @@ const DashboardEditProfile = () => { resizedAvatar = await ImageResizer(avatar); formData.append("avatar", resizedAvatar); } - - await axios.post(UPDATE_AVATAR, formData, { - headers: { - authorization: `Bearer ${token}`, - "Content-Type": "multipart/form-data", - }, - }); + await requestServer(UPDATE_AVATAR, 'post', {formData}).then((response) => { + }) + .catch(() => { + }).finally(() => { + }); } catch (error) { - Notifications(t, error.response); throw error; } }; @@ -99,11 +95,7 @@ const DashboardEditProfile = () => { margin="normal" size="small" disabled={true} - error={ - props.touched.username && props.errors.username - ? true - : false - } + error={!!(props.touched.username && props.errors.username)} helperText={ props.touched.username ? props.errors.username @@ -123,11 +115,7 @@ const DashboardEditProfile = () => { margin="normal" size="small" disabled={true} - error={ - props.touched.name && props.errors.name - ? true - : false - } + error={!!(props.touched.name && props.errors.name)} helperText={ props.touched.name ? props.errors.name : null } @@ -145,11 +133,7 @@ const DashboardEditProfile = () => { margin="normal" size="small" disabled={true} - error={ - props.touched.email && props.errors.email - ? true - : false - } + error={!!(props.touched.email && props.errors.email)} helperText={ props.touched.email ? props.errors.email : null } @@ -168,12 +152,7 @@ const DashboardEditProfile = () => { margin="normal" size="small" disabled={true} - error={ - props.touched.province_name && - props.errors.province_name - ? true - : false - } + error={!!(props.touched.province_name && props.errors.province_name)} helperText={ props.touched.province_name ? props.errors.province_name @@ -193,11 +172,7 @@ const DashboardEditProfile = () => { margin="normal" size="small" disabled={true} - error={ - props.touched.position && props.errors.position - ? true - : false - } + error={!!(props.touched.position && props.errors.position)} helperText={ props.touched.position ? props.errors.position diff --git a/src/core/components/notifications/ErrorNotification.jsx b/src/core/components/notifications/ErrorNotification.jsx index 05e2fb9..2face73 100644 --- a/src/core/components/notifications/ErrorNotification.jsx +++ b/src/core/components/notifications/ErrorNotification.jsx @@ -29,6 +29,7 @@ const ErrorNotification = (t, status, message) => { ), { + containerId: 'validation', autoClose: false, closeOnClick: false, draggable: false, diff --git a/src/core/components/notifications/PendingNotification.jsx b/src/core/components/notifications/PendingNotification.jsx index 6183f6b..1e482fd 100644 --- a/src/core/components/notifications/PendingNotification.jsx +++ b/src/core/components/notifications/PendingNotification.jsx @@ -1,12 +1,14 @@ import {toast} from "react-toastify"; +let a = {pending: []} const PendingNotification = (t) => { toast(t("notifications.pending"), { + containerId: 'validation', autoClose: false, closeButton: false, closeOnClick: false, draggable: false, - }); + }) }; export default PendingNotification; \ No newline at end of file diff --git a/src/core/components/notifications/SuccessNotification.jsx b/src/core/components/notifications/SuccessNotification.jsx index 3507cef..264d764 100644 --- a/src/core/components/notifications/SuccessNotification.jsx +++ b/src/core/components/notifications/SuccessNotification.jsx @@ -30,6 +30,7 @@ const SuccessNotification = (t, status) => { ), { + containerId: 'validation', autoClose: 3000, hideProgressBar: true, pauseOnHover: true, diff --git a/src/core/components/notifications/UploadFileNotification.jsx b/src/core/components/notifications/UploadFileNotification.jsx index 89ebbb2..1c20ba3 100644 --- a/src/core/components/notifications/UploadFileNotification.jsx +++ b/src/core/components/notifications/UploadFileNotification.jsx @@ -26,6 +26,8 @@ const UploadFileNotification = (t) => { ), { + containerId: 'validation', + toastId: 'upload', autoClose: 3000, hideProgressBar: true, pauseOnHover: true, diff --git a/src/core/components/notifications/WarningNotification.jsx b/src/core/components/notifications/WarningNotification.jsx index 19d6a2f..8d29dca 100644 --- a/src/core/components/notifications/WarningNotification.jsx +++ b/src/core/components/notifications/WarningNotification.jsx @@ -30,6 +30,7 @@ const WarningNotification = (t, status) => { ), { + containerId: 'validation', autoClose: false, closeOnClick: false, draggable: false, diff --git a/src/core/components/notifications/index.jsx b/src/core/components/notifications/index.jsx index bc8eb66..4fe5473 100644 --- a/src/core/components/notifications/index.jsx +++ b/src/core/components/notifications/index.jsx @@ -1,54 +1,25 @@ -import {toast} from "react-toastify"; -import ErrorNotification from "./ErrorNotification"; -import WarningNotification from "./WarningNotification"; -import SuccessNotification from "./SuccessNotification"; +import pendingNotification from "@/core/components/notifications/PendingNotification"; +import WarningNotification from "@/core/components/notifications/WarningNotification"; +import ErrorNotification from "@/core/components/notifications/ErrorNotification"; +import SuccessNotification from "@/core/components/notifications/SuccessNotification"; -const Notifications = async (t, response) => { - const {status, data} = response != undefined ? response : "" - toast.dismiss(); - switch (status) { - case 200: - SuccessNotification(t, status); - break; - case 400: - ErrorNotification(t, status); - break; - case 401: - ErrorNotification(t, status); - break; - case 403: - ErrorNotification(t, status); - break; - case 422: - ErrorNotification(t, status, data.message); - break; - case 500: - WarningNotification(t, status); - break; - case 503: - WarningNotification(t, status); - break; - case 504: - WarningNotification(t, status); - break; - default: - toast(t("notifications.pending"), { - autoClose: false, - closeOnClick: false, - draggable: false, - }); - break; +const Notifications = (notificationType, t, status, message) => { + let notification_type_id = { + pending: [], + error: [], + warning: [], + success: [] + } + + if (notificationType === "pending") { + pendingNotification(t); + } else if (notificationType === "warning") { + WarningNotification(t, status); + } else if (notificationType === "error") { + message ? ErrorNotification(t, status, message) : ErrorNotification(t, status); + } else if (notificationType === "success") { + SuccessNotification(t, status); } }; export default Notifications; - -/* -usage document - -** for pending use ( Notifications( t, undefined) ) this before your request. -** for success use ( Notifications( t, response) ) this inside .then() of your request. -** for Error and Warning use ( Notifications( t, error.response) ) this inside .catche() of your request. - -end usage document -*/ diff --git a/src/core/utils/errorHandler.js b/src/core/utils/errorHandler.js index 8dbd364..3f1d341 100644 --- a/src/core/utils/errorHandler.js +++ b/src/core/utils/errorHandler.js @@ -1,17 +1,22 @@ -import ErrorNotification from "@/core/components/notifications/ErrorNotification"; -import WarningNotification from "@/core/components/notifications/WarningNotification"; import {toast} from "react-toastify"; +import Notifications from "@/core/components/notifications"; export const errorSetting = (t, notification) => { - if (notification) toast.dismiss(); + if (notification) { + toast.dismiss() + } } export const errorRequest = (t, notification) => { - if (notification) toast.dismiss(); + if (notification) { + toast.dismiss() + } } export const errorResponse = (response, clearToken, t, notification) => { - if (notification) toast.dismiss(); + if (notification) { + toast.dismiss() + } if (isServerError(response.status)) { errorServer(response, t, notification) } else if (isClientError(response.status)) { @@ -20,13 +25,13 @@ export const errorResponse = (response, clearToken, t, notification) => { } const errorServer = (response, t, notification) => { - if (notification) WarningNotification(t, response.status); + if (notification) Notifications("warning", t, response.status); } const errorClient = (response, clearToken, t, notification) => { switch (response.status) { case 401: clearToken() - if (notification) ErrorNotification(t, response.status) + if (notification) Notifications("error", t, response.status); break; case 422: if ('type' in response.data) { @@ -36,10 +41,10 @@ const errorClient = (response, clearToken, t, notification) => { errorValidation(response, t, notification) break; case 429: - if (notification) ErrorNotification(t, response.status) + if (notification) Notifications("error", t, response.status); break default: - if (notification) ErrorNotification(t, response.status) + if (notification) Notifications("error", t, response.status); break } } @@ -48,7 +53,7 @@ const isServerError = status => status >= 500 && status <= 599; const isClientError = status => status >= 400 && status <= 499; const errorLogic = (response, t, notification) => { - if (notification) ErrorNotification(t, response.status, response.data.message) + if (notification) Notifications("error", t, response.status, response.data.message); } const errorValidation = (response, t, notification) => { if (notification) { @@ -56,7 +61,7 @@ const errorValidation = (response, t, notification) => { const errorsArray = response.data.errors errorsMap.map((item, index) => { - ErrorNotification(t, response.status, errorsArray[item][0]); + Notifications("error", t, errorsArray[item][0], response.data.message); }) } } \ No newline at end of file diff --git a/src/core/utils/succesHandler.js b/src/core/utils/succesHandler.js index a61ac85..f8bd707 100644 --- a/src/core/utils/succesHandler.js +++ b/src/core/utils/succesHandler.js @@ -1,9 +1,9 @@ import SuccessNotification from "@/core/components/notifications/SuccessNotification"; -import {toast} from "react-toastify"; +import Notifications from "@/core/components/notifications"; export const successRequest = (response, t, options) => { if (options.notification && options.success.notification.show) { - toast.dismiss(); SuccessNotification(t, response.status) + Notifications("success", t, response.status); } } \ No newline at end of file diff --git a/src/layouts/AppLayout.jsx b/src/layouts/AppLayout.jsx index 4fc5e1d..5bb1d23 100644 --- a/src/layouts/AppLayout.jsx +++ b/src/layouts/AppLayout.jsx @@ -41,16 +41,22 @@ function AppLayout({children, isBot}) { if (!languageIsReady) return; } - return (<> - - - - - {children} - ); + return ( + <> + + + + + {children} + + ); } export default AppLayout; diff --git a/src/lib/app/contexts/socket.jsx b/src/lib/app/contexts/socket.jsx index 47154c8..68826e1 100644 --- a/src/lib/app/contexts/socket.jsx +++ b/src/lib/app/contexts/socket.jsx @@ -2,9 +2,10 @@ import {createContext, useEffect, useMemo, useRef, useState} from "react"; import {io} from "socket.io-client"; import useUser from "@/lib/app/hooks/useUser"; import {useTranslations} from "next-intl"; -import {toast} from "react-toastify"; +import {toast, ToastContainer} from "react-toastify"; import PowerIcon from "@mui/icons-material/Power"; import PowerOffIcon from "@mui/icons-material/PowerOff"; +import useDirection from "@/lib/app/hooks/useDirection"; export const SocketContext = createContext() @@ -13,6 +14,7 @@ export const SocketProvider = ({children}) => { const [connectionError, setConnectionError] = useState(false) const socketToastId = useRef(null); const t = useTranslations() + const {directionApp} = useDirection(); const socket = useMemo(() => io(process.env.NEXT_PUBLIC_SERVER_SOCKET_URL, { autoConnect: false, auth: { @@ -57,11 +59,20 @@ export const SocketProvider = ({children}) => { return } socketToastId.current = toast.warn(t('socket_is_not_connect_message'), { + containerId: 'socket', draggable: false, autoClose: false, closeButton: false, closeOnClick: false, icon: }) }, [connectionError]); - return {children} + return ( + + + {children} + + ) } \ No newline at end of file diff --git a/src/lib/app/hooks/useRequest.jsx b/src/lib/app/hooks/useRequest.jsx index d361e08..8aa5730 100644 --- a/src/lib/app/hooks/useRequest.jsx +++ b/src/lib/app/hooks/useRequest.jsx @@ -1,10 +1,10 @@ import axios from "axios"; import {successRequest} from "@/core/utils/succesHandler"; -import PendingNotification from "@/core/components/notifications/PendingNotification"; import {useTranslations} from "next-intl"; import useUser from "@/lib/app/hooks/useUser"; import {errorRequest, errorResponse, errorSetting} from "@/core/utils/errorHandler"; import useNetwork from "@/lib/app/hooks/useNetwork"; +import Notifications from "@/core/components/notifications"; const defaultOptions = { auth: false, data: {}, requestOptions: { @@ -39,7 +39,7 @@ const useRequest = (initOptions) => { reject() return } - if (_options.notification && _options.failed.notification.show && _options.pending) PendingNotification(t) + if (_options.notification && _options.failed.notification.show && _options.pending) Notifications("pending", t) axios({ url: url, method: method, data: _options.data, ..._options.requestOptions }) From 73ca237817c2e3089f004d1cbc93f407f148eed1 Mon Sep 17 00:00:00 2001 From: Mohammad Jalali Date: Mon, 30 Oct 2023 16:35:08 +0330 Subject: [PATCH 2/5] CFE-6 notification bug fix --- .../notifications/ErrorNotification.jsx | 7 ++-- .../notifications/PendingNotification.jsx | 11 ++++--- .../notifications/SuccessNotification.jsx | 5 +-- .../notifications/WarningNotification.jsx | 5 +-- src/core/components/notifications/index.jsx | 32 ++++++++++--------- src/layouts/DashboardLayout.jsx | 3 +- src/lib/app/contexts/toast.jsx | 30 +++++++++++++++++ src/lib/app/hooks/useRequest.jsx | 4 ++- src/lib/app/hooks/useToast.jsx | 22 +++++++++++++ src/pages/_app.jsx | 19 ++++++----- 10 files changed, 102 insertions(+), 36 deletions(-) create mode 100644 src/lib/app/contexts/toast.jsx create mode 100644 src/lib/app/hooks/useToast.jsx diff --git a/src/core/components/notifications/ErrorNotification.jsx b/src/core/components/notifications/ErrorNotification.jsx index 2face73..27ae26e 100644 --- a/src/core/components/notifications/ErrorNotification.jsx +++ b/src/core/components/notifications/ErrorNotification.jsx @@ -1,9 +1,11 @@ import DangerousIcon from "@mui/icons-material/Dangerous"; import {Box, Typography} from "@mui/material"; import {toast} from "react-toastify"; +import useToast from "@/lib/app/hooks/useToast"; -const ErrorNotification = (t, status, message) => { - toast( +const ErrorNotification = (notificationType, t, status, message) => { + const {pushToastList} = useToast(); + const toastId = toast( () => ( <> { draggable: false, } ); + pushToastList(notificationType, toastId); }; export default ErrorNotification; \ No newline at end of file diff --git a/src/core/components/notifications/PendingNotification.jsx b/src/core/components/notifications/PendingNotification.jsx index 1e482fd..fe0d47f 100644 --- a/src/core/components/notifications/PendingNotification.jsx +++ b/src/core/components/notifications/PendingNotification.jsx @@ -1,14 +1,17 @@ import {toast} from "react-toastify"; +import useToast from "@/lib/app/hooks/useToast"; -let a = {pending: []} -const PendingNotification = (t) => { - toast(t("notifications.pending"), { +const PendingNotification = (notificationType, t) => { + const {pushToastList} = useToast(); + + const toastId = toast(t("notifications.pending"), { containerId: 'validation', autoClose: false, closeButton: false, closeOnClick: false, draggable: false, - }) + }); + pushToastList(notificationType, toastId); }; export default PendingNotification; \ No newline at end of file diff --git a/src/core/components/notifications/SuccessNotification.jsx b/src/core/components/notifications/SuccessNotification.jsx index 264d764..0ad83cd 100644 --- a/src/core/components/notifications/SuccessNotification.jsx +++ b/src/core/components/notifications/SuccessNotification.jsx @@ -2,8 +2,8 @@ import BeenhereIcon from "@mui/icons-material/Beenhere"; import {Box, Typography} from "@mui/material"; import {toast} from "react-toastify"; -const SuccessNotification = (t, status) => { - toast( +const SuccessNotification = (notificationType, t, status) => { + const toastId = toast( () => ( <> { draggable: true, } ); + notification_type_id.success.push(toastId); }; export default SuccessNotification; \ No newline at end of file diff --git a/src/core/components/notifications/WarningNotification.jsx b/src/core/components/notifications/WarningNotification.jsx index 8d29dca..8284f7a 100644 --- a/src/core/components/notifications/WarningNotification.jsx +++ b/src/core/components/notifications/WarningNotification.jsx @@ -2,8 +2,8 @@ import ReportIcon from "@mui/icons-material/Report"; import {Box, Typography} from "@mui/material"; import {toast} from "react-toastify"; -const WarningNotification = (t, status) => { - toast( +const WarningNotification = (notificationType, t, status) => { + const toastId = toast( () => ( <> { draggable: false, } ); + notification_type_id.warning.push(toastId); }; export default WarningNotification; \ No newline at end of file diff --git a/src/core/components/notifications/index.jsx b/src/core/components/notifications/index.jsx index 4fe5473..8383009 100644 --- a/src/core/components/notifications/index.jsx +++ b/src/core/components/notifications/index.jsx @@ -4,21 +4,23 @@ import ErrorNotification from "@/core/components/notifications/ErrorNotification import SuccessNotification from "@/core/components/notifications/SuccessNotification"; const Notifications = (notificationType, t, status, message) => { - let notification_type_id = { - pending: [], - error: [], - warning: [], - success: [] - } - - if (notificationType === "pending") { - pendingNotification(t); - } else if (notificationType === "warning") { - WarningNotification(t, status); - } else if (notificationType === "error") { - message ? ErrorNotification(t, status, message) : ErrorNotification(t, status); - } else if (notificationType === "success") { - SuccessNotification(t, status); + switch (notificationType) { + case "pending": + pendingNotification(notificationType, t); + break; + case "warning": + WarningNotification(notificationType, t, status); + break; + case "error": + if (message) { + ErrorNotification(notificationType, t, status, message) + } else { + ErrorNotification(notificationType, t, status) + } + break; + case "success": + SuccessNotification(notificationType, t, status); + break; } }; diff --git a/src/layouts/DashboardLayout.jsx b/src/layouts/DashboardLayout.jsx index 3c62a77..37554cd 100644 --- a/src/layouts/DashboardLayout.jsx +++ b/src/layouts/DashboardLayout.jsx @@ -1,4 +1,3 @@ -import CallWidget from "src/components/layouts/Dashboard/CallWidget"; import Dashboard from "src/components/layouts/Dashboard"; const DashboardLayout = (props) => { @@ -6,7 +5,7 @@ const DashboardLayout = (props) => { return ( <> - + {/**/} ); }; diff --git a/src/lib/app/contexts/toast.jsx b/src/lib/app/contexts/toast.jsx new file mode 100644 index 0000000..e8c7bc6 --- /dev/null +++ b/src/lib/app/contexts/toast.jsx @@ -0,0 +1,30 @@ +import {createContext, useReducer} from "react"; + +export const ToastContext = createContext() + +const reducer = (state, action) => { + switch (action.type) { + case "PUSH": + return { + ...state, + [action.toast_type]: [...state[action.toast_type], action.toast_id] + }; + } +}; + +export const ToastProvider = ({children}) => { + const [state, dispatch] = useReducer(reducer, { + pending: [], + error: [], + warning: [], + success: [] + }); + + console.log(state) + + return ( + + {children} + + ); +}; diff --git a/src/lib/app/hooks/useRequest.jsx b/src/lib/app/hooks/useRequest.jsx index 8aa5730..a4c305b 100644 --- a/src/lib/app/hooks/useRequest.jsx +++ b/src/lib/app/hooks/useRequest.jsx @@ -5,6 +5,7 @@ import useUser from "@/lib/app/hooks/useUser"; import {errorRequest, errorResponse, errorSetting} from "@/core/utils/errorHandler"; import useNetwork from "@/lib/app/hooks/useNetwork"; import Notifications from "@/core/components/notifications"; +import useToast from "@/lib/app/hooks/useToast"; const defaultOptions = { auth: false, data: {}, requestOptions: { @@ -23,6 +24,7 @@ const useRequest = (initOptions) => { const network = useNetwork() const t = useTranslations() const {token, clearToken} = useUser() + const {pushToastList} = useToast(); let _options = {...defaultOptions, ...initOptions} function requestServer(url = '', method = 'get', options) { @@ -33,13 +35,13 @@ const useRequest = (initOptions) => { headers: {..._options.requestOptions.headers, authorization: `Bearer ${token}`} } } - return new Promise((resolve, reject) => { if (!network.online) { reject() return } if (_options.notification && _options.failed.notification.show && _options.pending) Notifications("pending", t) + axios({ url: url, method: method, data: _options.data, ..._options.requestOptions }) diff --git a/src/lib/app/hooks/useToast.jsx b/src/lib/app/hooks/useToast.jsx new file mode 100644 index 0000000..8cc7875 --- /dev/null +++ b/src/lib/app/hooks/useToast.jsx @@ -0,0 +1,22 @@ +import {useContext} from "react"; +import {ToastContext} from "@/lib/app/contexts/toast"; + +const useToast = () => { + const {state, dispatch} = useContext(ToastContext); + + const pushToastList = (toast_type, toast_id) => { + console.log() + dispatch({type: "PUSH", toast_type, toast_id}); + }; + + const dismissToastList = () => { + dispatch({type: "DISMISS"}); + }; + + return { + pushToastList, + dismissToastList + } +}; + +export default useToast; \ No newline at end of file diff --git a/src/pages/_app.jsx b/src/pages/_app.jsx index 4cd2a1d..2d23745 100644 --- a/src/pages/_app.jsx +++ b/src/pages/_app.jsx @@ -8,21 +8,24 @@ import "moment/locale/fa"; import {NextIntlProvider} from "next-intl"; import TitlePage from "@/core/components/TitlePage"; import {SocketProvider} from "@/lib/app/contexts/socket"; +import {ToastProvider} from "@/lib/app/contexts/toast"; const App = ({Component, pageProps}) => { return (<> - - - {pageProps.messages ? : ''} + + + {pageProps.messages ? : ''} - - - - - + + + + + + + From cd90adee01d7a86988aa9d027d0aab71cf79bc74 Mon Sep 17 00:00:00 2001 From: Mohammad Jalali Date: Tue, 31 Oct 2023 15:11:53 +0330 Subject: [PATCH 3/5] CFE-6 bug fix toast and make better flow for remove and add toast in page --- .../notifications/ErrorNotification.jsx | 4 +- .../notifications/PendingNotification.jsx | 5 +- .../notifications/SuccessNotification.jsx | 4 +- .../notifications/WarningNotification.jsx | 4 +- src/core/components/notifications/index.jsx | 12 ++--- src/core/utils/errorHandler.js | 48 +++++++++---------- src/core/utils/succesHandler.js | 7 ++- src/lib/app/contexts/toast.jsx | 11 ++++- src/lib/app/hooks/useRequest.jsx | 15 +++--- src/lib/app/hooks/useToast.jsx | 7 ++- 10 files changed, 59 insertions(+), 58 deletions(-) diff --git a/src/core/components/notifications/ErrorNotification.jsx b/src/core/components/notifications/ErrorNotification.jsx index 27ae26e..776c904 100644 --- a/src/core/components/notifications/ErrorNotification.jsx +++ b/src/core/components/notifications/ErrorNotification.jsx @@ -1,10 +1,8 @@ import DangerousIcon from "@mui/icons-material/Dangerous"; import {Box, Typography} from "@mui/material"; import {toast} from "react-toastify"; -import useToast from "@/lib/app/hooks/useToast"; -const ErrorNotification = (notificationType, t, status, message) => { - const {pushToastList} = useToast(); +const ErrorNotification = (pushToastList, notificationType, t, status, message) => { const toastId = toast( () => ( <> diff --git a/src/core/components/notifications/PendingNotification.jsx b/src/core/components/notifications/PendingNotification.jsx index fe0d47f..cc28a58 100644 --- a/src/core/components/notifications/PendingNotification.jsx +++ b/src/core/components/notifications/PendingNotification.jsx @@ -1,9 +1,6 @@ import {toast} from "react-toastify"; -import useToast from "@/lib/app/hooks/useToast"; - -const PendingNotification = (notificationType, t) => { - const {pushToastList} = useToast(); +const PendingNotification = (pushToastList, notificationType, t) => { const toastId = toast(t("notifications.pending"), { containerId: 'validation', autoClose: false, diff --git a/src/core/components/notifications/SuccessNotification.jsx b/src/core/components/notifications/SuccessNotification.jsx index 0ad83cd..1207000 100644 --- a/src/core/components/notifications/SuccessNotification.jsx +++ b/src/core/components/notifications/SuccessNotification.jsx @@ -2,7 +2,7 @@ import BeenhereIcon from "@mui/icons-material/Beenhere"; import {Box, Typography} from "@mui/material"; import {toast} from "react-toastify"; -const SuccessNotification = (notificationType, t, status) => { +const SuccessNotification = (pushToastList, notificationType, t, status) => { const toastId = toast( () => ( <> @@ -38,7 +38,7 @@ const SuccessNotification = (notificationType, t, status) => { draggable: true, } ); - notification_type_id.success.push(toastId); + pushToastList(notificationType, toastId); }; export default SuccessNotification; \ No newline at end of file diff --git a/src/core/components/notifications/WarningNotification.jsx b/src/core/components/notifications/WarningNotification.jsx index 8284f7a..bc2a1fb 100644 --- a/src/core/components/notifications/WarningNotification.jsx +++ b/src/core/components/notifications/WarningNotification.jsx @@ -2,7 +2,7 @@ import ReportIcon from "@mui/icons-material/Report"; import {Box, Typography} from "@mui/material"; import {toast} from "react-toastify"; -const WarningNotification = (notificationType, t, status) => { +const WarningNotification = (pushToastList, notificationType, t, status) => { const toastId = toast( () => ( <> @@ -36,7 +36,7 @@ const WarningNotification = (notificationType, t, status) => { draggable: false, } ); - notification_type_id.warning.push(toastId); + pushToastList(notificationType, toastId); }; export default WarningNotification; \ No newline at end of file diff --git a/src/core/components/notifications/index.jsx b/src/core/components/notifications/index.jsx index 8383009..34e44f3 100644 --- a/src/core/components/notifications/index.jsx +++ b/src/core/components/notifications/index.jsx @@ -3,23 +3,23 @@ import WarningNotification from "@/core/components/notifications/WarningNotifica import ErrorNotification from "@/core/components/notifications/ErrorNotification"; import SuccessNotification from "@/core/components/notifications/SuccessNotification"; -const Notifications = (notificationType, t, status, message) => { +const Notifications = (pushToastList, notificationType, t, status, message) => { switch (notificationType) { case "pending": - pendingNotification(notificationType, t); + pendingNotification(pushToastList, notificationType, t); break; case "warning": - WarningNotification(notificationType, t, status); + WarningNotification(pushToastList, notificationType, t, status); break; case "error": if (message) { - ErrorNotification(notificationType, t, status, message) + ErrorNotification(pushToastList, notificationType, t, status, message) } else { - ErrorNotification(notificationType, t, status) + ErrorNotification(pushToastList, notificationType, t, status) } break; case "success": - SuccessNotification(notificationType, t, status); + SuccessNotification(pushToastList, notificationType, t, status); break; } }; diff --git a/src/core/utils/errorHandler.js b/src/core/utils/errorHandler.js index 3f1d341..2c12ab2 100644 --- a/src/core/utils/errorHandler.js +++ b/src/core/utils/errorHandler.js @@ -1,50 +1,48 @@ -import {toast} from "react-toastify"; import Notifications from "@/core/components/notifications"; -export const errorSetting = (t, notification) => { +export const errorSetting = (dismissToastList, t, notification) => { if (notification) { - toast.dismiss() + dismissToastList(["pending", "warning", "error", "success"]) + } +} +export const errorRequest = (dismissToastList, t, notification) => { + if (notification) { + dismissToastList(["pending", "warning", "error", "success"]) } } -export const errorRequest = (t, notification) => { +export const errorResponse = (pushToastList, dismissToastList, response, clearToken, t, notification) => { if (notification) { - toast.dismiss() - } -} - -export const errorResponse = (response, clearToken, t, notification) => { - if (notification) { - toast.dismiss() + dismissToastList(["pending", "warning", "error", "success"]) } if (isServerError(response.status)) { - errorServer(response, t, notification) + errorServer(pushToastList, response, t, notification) } else if (isClientError(response.status)) { - errorClient(response, clearToken, t, notification) + errorClient(pushToastList, response, clearToken, t, notification) } } -const errorServer = (response, t, notification) => { - if (notification) Notifications("warning", t, response.status); +const errorServer = (pushToastList, response, t, notification) => { + if (notification) Notifications(pushToastList, "warning", t, response.status); } -const errorClient = (response, clearToken, t, notification) => { +const errorClient = (pushToastList, response, clearToken, t, notification) => { switch (response.status) { case 401: clearToken() - if (notification) Notifications("error", t, response.status); + if (notification) Notifications(pushToastList, "error", t, response.status); break; case 422: if ('type' in response.data) { - errorLogic(response, t, notification) + errorLogic(pushToastList, response, t, notification) break; } - errorValidation(response, t, notification) + errorValidation(pushToastList, response, t, notification) break; case 429: - if (notification) Notifications("error", t, response.status); + if (notification) Notifications(pushToastList, "error", t, response.status); break default: - if (notification) Notifications("error", t, response.status); + if (notification) Notifications(pushToastList, "error", t, response.status); break } } @@ -52,16 +50,16 @@ const errorClient = (response, clearToken, t, notification) => { const isServerError = status => status >= 500 && status <= 599; const isClientError = status => status >= 400 && status <= 499; -const errorLogic = (response, t, notification) => { - if (notification) Notifications("error", t, response.status, response.data.message); +const errorLogic = (pushToastList, response, t, notification) => { + if (notification) Notifications(pushToastList, "error", t, response.status, response.data.message); } -const errorValidation = (response, t, notification) => { +const errorValidation = (pushToastList, response, t, notification) => { if (notification) { const errorsMap = Object.keys(response.data.errors) const errorsArray = response.data.errors errorsMap.map((item, index) => { - Notifications("error", t, errorsArray[item][0], response.data.message); + Notifications(pushToastList, "error", t, errorsArray[item][0], response.data.message); }) } } \ No newline at end of file diff --git a/src/core/utils/succesHandler.js b/src/core/utils/succesHandler.js index f8bd707..c852f86 100644 --- a/src/core/utils/succesHandler.js +++ b/src/core/utils/succesHandler.js @@ -1,9 +1,8 @@ -import SuccessNotification from "@/core/components/notifications/SuccessNotification"; import Notifications from "@/core/components/notifications"; -export const successRequest = (response, t, options) => { +export const successRequest = (pushToastList, dismissToastList, response, t, options) => { if (options.notification && options.success.notification.show) { - SuccessNotification(t, response.status) - Notifications("success", t, response.status); + dismissToastList(["pending", "warning", "error", "success"]) + Notifications(pushToastList, "success", t, response.status); } } \ No newline at end of file diff --git a/src/lib/app/contexts/toast.jsx b/src/lib/app/contexts/toast.jsx index e8c7bc6..b9d4cbc 100644 --- a/src/lib/app/contexts/toast.jsx +++ b/src/lib/app/contexts/toast.jsx @@ -1,4 +1,5 @@ import {createContext, useReducer} from "react"; +import {toast} from "react-toastify"; export const ToastContext = createContext() @@ -9,6 +10,14 @@ const reducer = (state, action) => { ...state, [action.toast_type]: [...state[action.toast_type], action.toast_id] }; + case "DISMISS": + action.toast_type.map((item) => { + state[item].map((id) => { + toast.dismiss(id); + }) + state[item] = [] + }); + return state; } }; @@ -20,8 +29,6 @@ export const ToastProvider = ({children}) => { success: [] }); - console.log(state) - return ( {children} diff --git a/src/lib/app/hooks/useRequest.jsx b/src/lib/app/hooks/useRequest.jsx index a4c305b..4c3be1d 100644 --- a/src/lib/app/hooks/useRequest.jsx +++ b/src/lib/app/hooks/useRequest.jsx @@ -24,7 +24,7 @@ const useRequest = (initOptions) => { const network = useNetwork() const t = useTranslations() const {token, clearToken} = useUser() - const {pushToastList} = useToast(); + const {pushToastList, dismissToastList} = useToast(); let _options = {...defaultOptions, ...initOptions} function requestServer(url = '', method = 'get', options) { @@ -40,22 +40,25 @@ const useRequest = (initOptions) => { reject() return } - if (_options.notification && _options.failed.notification.show && _options.pending) Notifications("pending", t) + if (_options.notification && _options.failed.notification.show && _options.pending) { + dismissToastList(["pending", "warning", "error", "success"]); + Notifications(pushToastList, "pending", t); + } axios({ url: url, method: method, data: _options.data, ..._options.requestOptions }) .then(response => { - successRequest(response, t, _options) + successRequest(pushToastList, dismissToastList, response, t, _options) resolve(response) }) .catch(error => { if (error.response) { - errorResponse(error.response, clearToken, t, _options.notification && _options.failed.notification.show) + errorResponse(pushToastList, dismissToastList, error.response, clearToken, t, _options.notification && _options.failed.notification.show) } else if (error.request) { - errorRequest(t, _options.notification && _options.failed.notification.show) + errorRequest(dismissToastList, t, _options.notification && _options.failed.notification.show) } else { - errorSetting(t, _options.notification && _options.failed.notification.show) + errorSetting(dismissToastList, t, _options.notification && _options.failed.notification.show) } reject(error) }) diff --git a/src/lib/app/hooks/useToast.jsx b/src/lib/app/hooks/useToast.jsx index 8cc7875..5e1d5b4 100644 --- a/src/lib/app/hooks/useToast.jsx +++ b/src/lib/app/hooks/useToast.jsx @@ -2,15 +2,14 @@ import {useContext} from "react"; import {ToastContext} from "@/lib/app/contexts/toast"; const useToast = () => { - const {state, dispatch} = useContext(ToastContext); + const {dispatch} = useContext(ToastContext); const pushToastList = (toast_type, toast_id) => { - console.log() dispatch({type: "PUSH", toast_type, toast_id}); }; - const dismissToastList = () => { - dispatch({type: "DISMISS"}); + const dismissToastList = (toast_type) => { + dispatch({type: "DISMISS", toast_type}); }; return { From 5f3d2862df01b1e6a6c965648237354229d27990 Mon Sep 17 00:00:00 2001 From: Mohammad Jalali Date: Tue, 31 Oct 2023 15:16:16 +0330 Subject: [PATCH 4/5] CFE-6 add item to expert table and change add button text in expert page --- public/locales/fa/app.json | 3 ++- .../dashboard/expert-management/DataTable/index.jsx | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/public/locales/fa/app.json b/public/locales/fa/app.json index 0a1c31b..ae51967 100644 --- a/public/locales/fa/app.json +++ b/public/locales/fa/app.json @@ -196,6 +196,7 @@ "name": "نام کامل", "username": "نام کاربری", "email": "پست الکترونیک", + "telephone_id": "کد تلفن", "phone_number": "شماره همراه", "national_id": "کد ملی", "position": "سمت", @@ -205,7 +206,7 @@ "male": "مرد", "female": "زن", "updated_at": "آخرین بروزرسانی", - "create": "افزودن کارشناس", + "create": "افزودن", "personal_info": "مشخصات کارشناس", "user_info": "اطلاعات کاربری", "rest_info": "اطلاعات تکمیلی", diff --git a/src/components/dashboard/expert-management/DataTable/index.jsx b/src/components/dashboard/expert-management/DataTable/index.jsx index 3f76ca5..41dd1e6 100644 --- a/src/components/dashboard/expert-management/DataTable/index.jsx +++ b/src/components/dashboard/expert-management/DataTable/index.jsx @@ -67,6 +67,18 @@ function ExpertManagementDataTable() { {renderedCellValue} ), }, + { + accessorFn: (row) => row.telephone_id, + id: "telephone_id", + header: t("ExpertMangement.telephone_id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: ["contains", "equals", "notEquals"], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, { accessorFn: (row) => row.phone_number, id: "phone_number", From 23ff9fd7dab78078d1cac16ce7f0b67a41f0492a Mon Sep 17 00:00:00 2001 From: Mohammad Jalali Date: Tue, 31 Oct 2023 15:39:22 +0330 Subject: [PATCH 5/5] CFE-6 debug test problem refer expert management components --- .../DataTable/__tests__/index.test.js | 2 ++ .../Form/CreateForm/__tests__/index.test.js | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/components/dashboard/expert-management/DataTable/__tests__/index.test.js b/src/components/dashboard/expert-management/DataTable/__tests__/index.test.js index 0ed26eb..cfc0a60 100644 --- a/src/components/dashboard/expert-management/DataTable/__tests__/index.test.js +++ b/src/components/dashboard/expert-management/DataTable/__tests__/index.test.js @@ -10,6 +10,7 @@ describe("ExpertManagementDatatable Component From Expert Management", () => { const nameHeader = screen.queryByText("نام کامل"); const usernameHeader = screen.queryByText("نام کاربری"); const emailHeader = screen.queryByText("پست الکترونیک"); + const telephone_idHeader = screen.queryByText("کد تلفن"); const phone_numberHeader = screen.queryByText("شماره همراه"); const national_idHeader = screen.queryByText("کد ملی"); const positionHeader = screen.queryByText("سمت"); @@ -21,6 +22,7 @@ describe("ExpertManagementDatatable Component From Expert Management", () => { expect(nameHeader).toBeInTheDocument(); expect(usernameHeader).toBeInTheDocument(); expect(emailHeader).toBeInTheDocument(); + expect(telephone_idHeader).toBeInTheDocument(); expect(phone_numberHeader).toBeInTheDocument(); expect(national_idHeader).toBeInTheDocument(); expect(positionHeader).toBeInTheDocument(); diff --git a/src/components/dashboard/expert-management/Form/CreateForm/__tests__/index.test.js b/src/components/dashboard/expert-management/Form/CreateForm/__tests__/index.test.js index 8bf825d..dda7f82 100644 --- a/src/components/dashboard/expert-management/Form/CreateForm/__tests__/index.test.js +++ b/src/components/dashboard/expert-management/Form/CreateForm/__tests__/index.test.js @@ -18,22 +18,22 @@ describe("CreateForm Component From Expert Management", () => { describe("Rendering", () => { it("Create Button Rendered", () => { render(); - const CreateButton = screen.getByRole('button', {name: "افزودن کارشناس"}); + const CreateButton = screen.getByRole('button', {name: "افزودن"}); expect(CreateButton).toBeInTheDocument(); }); it("Dialog Header Rendered", () => { render(); - const CreateDialogHeader = screen.queryByText("افزودن کارشناس"); + const CreateDialogHeader = screen.queryByText("افزودن"); expect(CreateDialogHeader).toBeInTheDocument(); }); }); describe("Behavioral", () => { it("by Clicking Create Button Dialog Should Append To Document", async () => { render(); - const CreateButton = screen.getByRole('button', {name: "افزودن کارشناس"}); + const CreateButton = screen.getByRole('button', {name: "افزودن"}); fireEvent.click(CreateButton); await act(() => { - const CreateDialog = screen.getByRole('dialog', {name: "افزودن کارشناس"}) + const CreateDialog = screen.getByRole('dialog', {name: "افزودن"}) expect(CreateDialog).toBeInTheDocument(); }); }); @@ -42,7 +42,7 @@ describe("CreateForm Component From Expert Management", () => { it('Should request to api and if get success close dialog', async () => { render(); - const CreateButton = screen.getByRole('button', {name: "افزودن کارشناس"}); + const CreateButton = screen.getByRole('button', {name: "افزودن"}); fireEvent.click(CreateButton); const submitButton = screen.queryByText('ثبت'); @@ -80,7 +80,7 @@ describe("CreateForm Component From Expert Management", () => { it('Should request to api and if get error keep previous data', async () => { render(); - const CreateButton = screen.getByRole('button', {name: "افزودن کارشناس"}); + const CreateButton = screen.getByRole('button', {name: "افزودن"}); fireEvent.click(CreateButton); const submitButton = screen.queryByText('ثبت');