From 863bdaca95bbf5087777a0e9f8c5c9453a6d5ace Mon Sep 17 00:00:00 2001 From: Amirhossein Mahmoodi Date: Tue, 9 Jul 2024 11:28:59 +0330 Subject: [PATCH] add auth and base functions and fixed bug --- .env.local.example | 1 + package.json | 1 + public/global.scss | 6 +- src/app/(withAuth)/dashboard/layout.js | 11 - src/app/(withAuth)/dashboard/page.js | 24 ++- src/app/(withAuth)/dashboard/template.js | 22 +- src/app/(withAuth)/layout.js | 14 ++ src/app/layout.js | 14 +- src/app/lfwd/page.js | 51 +++++ src/app/template.js | 16 +- src/core/components/Toasts/error.jsx | 191 ++++++++++++++++++ src/core/components/Toasts/success.jsx | 35 ++++ src/core/middlewares/withAuth.js | 22 ++ src/core/utils/errorResponse.js | 61 ++++++ src/core/utils/pageMenu.js | 60 +++--- src/core/utils/routes.js | 4 + src/core/utils/successRequest.js | 10 + .../contexts/{DataTable.jsx => DataTable.js} | 0 src/lib/contexts/auth.js | 76 +++++++ .../{tableSetting.jsx => tableSetting.js} | 0 .../{useDataTable.jsx => useDataTable.js} | 0 src/lib/hooks/useRequest.js | 42 ++++ ...useTableSetting.jsx => useTableSetting.js} | 0 23 files changed, 592 insertions(+), 69 deletions(-) delete mode 100644 src/app/(withAuth)/dashboard/layout.js create mode 100644 src/app/(withAuth)/layout.js create mode 100644 src/app/lfwd/page.js create mode 100644 src/core/components/Toasts/error.jsx create mode 100644 src/core/components/Toasts/success.jsx create mode 100644 src/core/middlewares/withAuth.js create mode 100644 src/core/utils/errorResponse.js create mode 100644 src/core/utils/routes.js create mode 100644 src/core/utils/successRequest.js rename src/lib/contexts/{DataTable.jsx => DataTable.js} (100%) create mode 100644 src/lib/contexts/auth.js rename src/lib/contexts/{tableSetting.jsx => tableSetting.js} (100%) rename src/lib/hooks/{useDataTable.jsx => useDataTable.js} (100%) create mode 100644 src/lib/hooks/useRequest.js rename src/lib/hooks/{useTableSetting.jsx => useTableSetting.js} (100%) diff --git a/.env.local.example b/.env.local.example index e69de29..05bae5f 100644 --- a/.env.local.example +++ b/.env.local.example @@ -0,0 +1 @@ +NEXT_PUBLIC_API_URL="https://rms.witel.ir" \ No newline at end of file diff --git a/package.json b/package.json index b4ddfd0..4beef0b 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@mui/material": "^5.15.6", "@mui/material-nextjs": "^5.15.6", "@mui/x-date-pickers": "^6.19.5", + "axios": "^1.7.2", "date-fns": "^3.3.1", "date-fns-jalali": "^2.13.0-0", "dayjs": "^1.11.10", diff --git a/public/global.scss b/public/global.scss index a383b5f..1af3ae3 100644 --- a/public/global.scss +++ b/public/global.scss @@ -1,7 +1,9 @@ @import "fontiran"; +@import "react-toastify/dist/ReactToastify.css"; .filter-toast { - box-shadow: rgba(50, 50, 93, 0.25) 0px 13px 27px -5px, rgba(0, 0, 0, 0.3) 0px 8px 16px -8px; + box-shadow: rgba(50, 50, 93, 0.25) 0px 13px 27px -5px, + rgba(0, 0, 0, 0.3) 0px 8px 16px -8px; background-color: #d0dfe8; border: 1px dashed #095b8c; -} \ No newline at end of file +} diff --git a/src/app/(withAuth)/dashboard/layout.js b/src/app/(withAuth)/dashboard/layout.js deleted file mode 100644 index 213bb0a..0000000 --- a/src/app/(withAuth)/dashboard/layout.js +++ /dev/null @@ -1,11 +0,0 @@ -import 'react-toastify/dist/ReactToastify.css'; - -const Layout = ({children}) => { - return ( - <> - {children} - - ) -} - -export default Layout \ No newline at end of file diff --git a/src/app/(withAuth)/dashboard/page.js b/src/app/(withAuth)/dashboard/page.js index f0731fe..915b3de 100644 --- a/src/app/(withAuth)/dashboard/page.js +++ b/src/app/(withAuth)/dashboard/page.js @@ -1,6 +1,28 @@ +'use client' +import { Button } from "@mui/material" +import axios from "axios" + const Page = () => { + const handler = () => { + try { + axios.get('https://rms.witel.ir/test_login?username=witel', { withCredentials: true }) + } catch (error) { + console.log(error); + } + } + const handler2 = () => { + try { + const res = axios.get('https://rms.witel.ir/webapi/user/get-permission', { withCredentials: true }) + console.log(res); + } catch (error) { + console.log(error); + } + } return ( -
dashboard
+ <> + + + ) } diff --git a/src/app/(withAuth)/dashboard/template.js b/src/app/(withAuth)/dashboard/template.js index 62759c6..eb7d2ef 100644 --- a/src/app/(withAuth)/dashboard/template.js +++ b/src/app/(withAuth)/dashboard/template.js @@ -1,17 +1,19 @@ -import {Box, Stack} from "@mui/material"; +import { Box, Stack } from "@mui/material"; import HeaderWithLogo from "@/components/layouts/dashboard/headerWithLogo"; import HeaderWithSidebar from "@/components/layouts/dashboard/headerWithSidebar"; import 'react-toastify/dist/ReactToastify.css'; -const Template = ({children}) => { - return ( - - - - {children} - - - ) +const Template = ({ children }) => { + return ( + + + + + {children} + + + + ) } export default Template \ No newline at end of file diff --git a/src/app/(withAuth)/layout.js b/src/app/(withAuth)/layout.js new file mode 100644 index 0000000..5a5cca8 --- /dev/null +++ b/src/app/(withAuth)/layout.js @@ -0,0 +1,14 @@ +import WithAuthMiddleware from "@/core/middlewares/withAuth" +import { AuthProvider } from "@/lib/contexts/auth" + +const Layout = ({ children }) => { + return ( + + + {children} + + + ) +} + +export default Layout \ No newline at end of file diff --git a/src/app/layout.js b/src/app/layout.js index c23a7ec..1d4819e 100644 --- a/src/app/layout.js +++ b/src/app/layout.js @@ -1,17 +1,17 @@ -import {TableSettingProvider} from "@/lib/contexts/tableSetting"; +import { TableSettingProvider } from "@/lib/contexts/tableSetting"; export const metadata = { title: 'سامانه جامع راهداری', } -export default function RootLayout({children}) { +export default function RootLayout({ children }) { return ( - - - {children} - - + + + {children} + + ) } diff --git a/src/app/lfwd/page.js b/src/app/lfwd/page.js new file mode 100644 index 0000000..55eca31 --- /dev/null +++ b/src/app/lfwd/page.js @@ -0,0 +1,51 @@ +'use client' + +import { GET_LOGIN_ROUTE } from "@/core/utils/routes" +import useRequest from "@/lib/hooks/useRequest" +import { Button, Stack, Typography, Zoom } from "@mui/material" +import Link from "next/link" +import { useEffect, useState } from "react" + +const Page = () => { + const [login, setLogin] = useState(0) + const request = useRequest() + + useEffect(() => { + const login = async () => { + try { + const res = await request(`${GET_LOGIN_ROUTE}?username=witel`) + setLogin(1) + } catch (error) { + setLogin(2) + } + } + + login() + }, []) + + const retry = async () => { + setLogin(0) + try { + const res = await request(`${GET_LOGIN_ROUTE}?username=witel`) + setLogin(1) + } catch (error) { + setLogin(2) + } + } + + + return ( + + + {login === 0 ? 'درحال دریافت مجوز برای ارتباط با سرور...' : login === 1 ? 'ارتباط با سرور برقرار شد.' : 'ارتباط با سرور برقرار نشد. مشکلی وجود دارد.'} + + + + + + + + + ) +} +export default Page \ No newline at end of file diff --git a/src/app/template.js b/src/app/template.js index 14f15b6..71830af 100644 --- a/src/app/template.js +++ b/src/app/template.js @@ -1,18 +1,18 @@ import cacheProviderRtl from "@/core/utils/cacheRtl"; -import {CssBaseline, ThemeProvider} from "@mui/material"; +import { CssBaseline, ThemeProvider } from "@mui/material"; import theme from "@/core/utils/theme"; -import {AppRouterCacheProvider} from "@mui/material-nextjs/v14-appRouter"; -import 'react-toastify/dist/ReactToastify.css'; +import { AppRouterCacheProvider } from "@mui/material-nextjs/v14-appRouter"; import "^/global.scss"; -import {ToastContainer} from "react-toastify"; +import { ToastContainer } from "react-toastify"; -const Template = ({children}) => { +const Template = ({ children }) => { return ( - + - + {children} - + + ) diff --git a/src/core/components/Toasts/error.jsx b/src/core/components/Toasts/error.jsx new file mode 100644 index 0000000..d0d9760 --- /dev/null +++ b/src/core/components/Toasts/error.jsx @@ -0,0 +1,191 @@ +import { toast } from "react-toastify"; +import { Box, Typography } from "@mui/material"; +import { Dangerous } from "@mui/icons-material"; + +export const errorServerToast = (toastContainer) => + toast.error( + () => ( + + + + + + {"The request failed due to an internal error."} + + + + + ), + { + icon: false, + containerId: toastContainer, + autoClose: 5000, + hideProgressBar: true, + pauseOnHover: true, + closeOnClick: false, + draggable: true, + } + ); + +export const errorUnauthorizedToast = (toastContainer) => + toast.error( + () => ( + + + + + + {"The user is not authorized to make the request."} + + + + + ), + { + icon: false, + containerId: toastContainer, + autoClose: 3000, + hideProgressBar: true, + pauseOnHover: true, + closeOnClick: false, + draggable: true, + } + ); + +export const errorLogicToast = (message, toastContainer) => + toast.error( + () => ( + + + + + + {message || + "The request was well-formed but was unable to be followed due to semantic errors."} + + + + + ), + { + icon: false, + containerId: toastContainer, + autoClose: false, + closeOnClick: false, + draggable: false, + } + ); + +export const errorValidationToast = (message, toastContainer) => + toast.error( + () => ( + + + + + + {message || + "The request was well-formed but was unable to be followed due to semantic errors."} + + + + + ), + { + icon: false, + containerId: toastContainer, + autoClose: false, + closeOnClick: false, + draggable: false, + } + ); + +export const errorTooManyToast = (toastContainer) => + toast.error( + () => ( + + + + + + {"Too many requests have been sent within a given time span."} + + + + + ), + { + icon: false, + containerId: toastContainer, + autoClose: false, + closeOnClick: false, + draggable: false, + } + ); + +export const errorClientToast = (toastContainer) => + toast.error( + () => ( + + + + + + { + "The API request is invalid or improperly formed. Consequently, the API server could not understand the request." + } + + + + + ), + { + icon: false, + containerId: toastContainer, + autoClose: false, + closeOnClick: false, + draggable: false, + } + ); diff --git a/src/core/components/Toasts/success.jsx b/src/core/components/Toasts/success.jsx new file mode 100644 index 0000000..b405a04 --- /dev/null +++ b/src/core/components/Toasts/success.jsx @@ -0,0 +1,35 @@ +import { toast } from "react-toastify"; +import { Box, Typography } from "@mui/material"; +import { Beenhere } from "@mui/icons-material"; + +export const successToast = (toastContainer) => + toast.success( + () => ( + + + + + + {"Your operation was successful"} + + + + + ), + { + icon: false, + containerId: toastContainer, + autoClose: 3000, + hideProgressBar: true, + pauseOnHover: true, + closeOnClick: false, + draggable: true, + } + ); diff --git a/src/core/middlewares/withAuth.js b/src/core/middlewares/withAuth.js new file mode 100644 index 0000000..1b93025 --- /dev/null +++ b/src/core/middlewares/withAuth.js @@ -0,0 +1,22 @@ +'use client' +import { useAuth } from "@/lib/contexts/auth"; +import { usePathname, useRouter } from "next/navigation"; +import { useEffect } from "react"; + +function WithAuthMiddleware({ children }) { + const router = useRouter() + const pathName = usePathname() + const { isAuth, initAuthState } = useAuth(); + + useEffect(() => { + if (!initAuthState) return + if (!isAuth) { + router.replace(`${process.env.NEXT_PUBLIC_API_URL}/login?_back=${encodeURIComponent(pathName)}`) + } + }, [isAuth, initAuthState]) + + if (!initAuthState || !isAuth) return null; + return <>{children} +} + +export default WithAuthMiddleware \ No newline at end of file diff --git a/src/core/utils/errorResponse.js b/src/core/utils/errorResponse.js new file mode 100644 index 0000000..3accb8f --- /dev/null +++ b/src/core/utils/errorResponse.js @@ -0,0 +1,61 @@ +'use client' +import { toast } from "react-toastify"; +import { + errorClientToast, + errorLogicToast, + errorServerToast, + errorTooManyToast, + errorUnauthorizedToast, + errorValidationToast +} from "@/core/components/toasts/error"; + +const isServerError = status => status >= 500 && status <= 599; +const isClientError = status => status >= 400 && status <= 499; + +const errorServer = (response, notification, toastContainer) => { + if (notification) errorServerToast(toastContainer) +} + +const errorClient = (response, notification, toastContainer) => { + switch (response.status) { + case 401: + if (notification) errorUnauthorizedToast(toastContainer) + break; + case 422: + if ('type' in response.data) { + if (Array.isArray(response.data.message)) { + response.data.message.map((item) => { + if (notification) errorLogicToast(item, toastContainer) + }) + } else { + if (notification) errorLogicToast(response.data.message, toastContainer) + } + break; + } + if (notification) { + const errorsMap = Object.keys(response.data.errors) + const errorsArray = response.data.errors + + errorsMap.map((item, index) => { + errorValidationToast(errorsArray[item][0], toastContainer); + }) + + } + break; + case 429: + if (notification) errorTooManyToast(toastContainer) + break + default: + if (notification) errorClientToast(toastContainer) + break + } +} + +export const errorResponse = (response, notification, toastContainer) => { + if (notification) toast.dismiss({ container: toastContainer }) + if (isServerError(response.status)) { + errorServer(response, notification, toastContainer) + } else if (isClientError(response.status)) { + errorClient(response, notification, toastContainer) + } +} diff --git a/src/core/utils/pageMenu.js b/src/core/utils/pageMenu.js index b97199a..81cb873 100644 --- a/src/core/utils/pageMenu.js +++ b/src/core/utils/pageMenu.js @@ -12,7 +12,7 @@ export const pageMenu = [ id: 'userManagement', label: 'مدیریت کاربران', type: "page", - route: "./v2/user_management", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/user_management", icon: , }, { @@ -26,35 +26,35 @@ export const pageMenu = [ id: 'projectsManagmentFinance', label: 'ثبت قرارداد و پروژه', type: "page", - route: "./v2/rahdari_projects/finance", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/rahdari_projects/finance", icon: , }, { id: 'projectsManagmentList', label: 'لیست پروژه ها', type: "page", - route: "./v2/rahdari_projects/projects_list", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/rahdari_projects/projects_list", icon: , }, { id: 'projectsManagmentProposal', label: 'پروژه های پیشنهادی', type: "page", - route: "./v2/rahdari_projects/proposal", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/rahdari_projects/proposal", icon: , }, { id: 'projectsManagmentLawmaker', label: 'درخواست نمایندگان', type: "page", - route: "./v2/rahdari_projects/lawmakers", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/rahdari_projects/lawmakers", icon: , }, { id: 'projectsManagmentMap', label: 'پراکندگی بر روی نقشه', type: "page", - route: "./v2/map?type=rahdari_projects", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=rahdari_projects", icon: , }, ] @@ -77,7 +77,7 @@ export const pageMenu = [ id: 'roadItemManagmentSupervisorCartable', label: 'کارتابل', type: "page", - route: "./v2/road_items/supervisor/cartable", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_items/supervisor/cartable", }, ] }, @@ -92,13 +92,13 @@ export const pageMenu = [ id: 'roadItemManagmentOparationCreate', label: 'ثبت فعالیت', type: "page", - route: "./v2/road_items/operator/create", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_items/operator/create", }, { id: 'roadItemManagmentOparationCartable', label: 'کارتابل', type: "page", - route: "./v2/road_items/operator/cartable", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_items/operator/cartable", }, ] }, @@ -106,14 +106,14 @@ export const pageMenu = [ id: 'roadItemManagmentMap', label: 'پراکندگی بر روی نقشه', type: "page", - route: "./v2/map?type=road_items", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=road_items", icon: , }, { id: 'roadItemManagmentReport', label: 'گزارش ها', type: "page", - route: "./v2/road_items/report", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_items/report", icon: , }, ] @@ -136,7 +136,7 @@ export const pageMenu = [ id: 'roadPatrolManagmentSupervisorCartable', label: 'کارتابل', type: "page", - route: "./road_patrols/supervisor/cartable", + route: process.env.NEXT_PUBLIC_API_URL + "/road_patrols/supervisor/cartable", }, ] }, @@ -151,13 +151,13 @@ export const pageMenu = [ id: 'roadPatrolManagmentOparationCreate', label: 'ثبت اقدام', type: "page", - route: "./v2/road_patrols/operator/create", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_patrols/operator/create", }, { id: 'roadPatrolManagmentOparationCartable', label: 'کارتابل', type: "page", - route: "./v2/road_patrols/operator/cartable", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_patrols/operator/cartable", }, ] }, @@ -165,14 +165,14 @@ export const pageMenu = [ id: 'roadPatrolManagmentMap', label: 'پراکندگی بر روی نقشه', type: "page", - route: "./v2/map?type=road_patrols", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=road_patrols", icon: , }, { id: 'roadPatrolManagmentReport', label: 'گزارش ها', type: "page", - route: "./v2/road_patrols/report", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_patrols/report", icon: , }, ] @@ -195,13 +195,13 @@ export const pageMenu = [ id: 'safetyAndPrivacyManagmentOparationCreate', label: 'ثبت فعالیت', type: "page", - route: "./safety_and_privacy/operator/first_step", + route: process.env.NEXT_PUBLIC_API_URL + "/safety_and_privacy/operator/first_step", }, { id: 'safetyAndPrivacyManagmentOparationCartable', label: 'کارتابل', type: "page", - route: "./v2/safety_and_privacy/operator/cartable", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/safety_and_privacy/operator/cartable", }, ] }, @@ -209,14 +209,14 @@ export const pageMenu = [ id: 'safetyAndPrivacyManagmentMap', label: 'پراکندگی بر روی نقشه', type: "page", - route: "./v2/map?type=safety_and_privacy", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=safety_and_privacy", icon: , }, { id: 'safetyAndPrivacyManagmentReport', label: 'گزارش ها', type: "page", - route: "./v2/safety_and_privacy/report", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/safety_and_privacy/report", icon: , }, ] @@ -239,7 +239,7 @@ export const pageMenu = [ id: 'roadObservationsManagmentSupervisorCartable', label: 'کارتابل', type: "page", - route: "./v2/road_observations/supervisor/cartable", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_observations/supervisor/cartable", }, ] }, @@ -247,7 +247,7 @@ export const pageMenu = [ id: 'roadObservationsManagmentList', label: 'رسیدگی به شکایات', type: "page", - route: "./v2/road_observations", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_observations", icon: , }, { @@ -261,7 +261,7 @@ export const pageMenu = [ id: 'roadObservationsManagmentOparationCartable', label: 'کارتابل', type: "page", - route: "./v2/road_observations/operator/cartable", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_observations/operator/cartable", }, ] }, @@ -269,14 +269,14 @@ export const pageMenu = [ id: 'roadObservationsManagmentMap', label: 'پراکندگی بر روی نقشه', type: "page", - route: "./v2/map?type=road_observations", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=road_observations", icon: , }, { id: 'roadObservationsManagmentReport', label: 'گزارش ها', type: "page", - route: "./v2/road_observations/report/index", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_observations/report/index", icon: , }, ] @@ -292,21 +292,21 @@ export const pageMenu = [ id: 'winterCampManagmentBlocking', label: 'محور های انسدادی', type: "page", - route: "./v2/winter_camp", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/winter_camp", icon: , }, { id: 'winterCampManagmentFirstRing', label: 'محور های حلقه اول', type: "page", - route: "./v2/map?type=camp", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=camp", icon: , }, { id: 'winterCampManagmentReport', label: 'گزارش ها', type: "page", - route: "./v2/map?type=campNew", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=campNew", icon: , }, ] @@ -329,7 +329,7 @@ export const pageMenu = [ id: 'receiptManagmentOparationCartable', label: 'کارتابل', type: "page", - route: "./v2/receipt", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/receipt", }, ] }, @@ -337,7 +337,7 @@ export const pageMenu = [ id: 'receiptManagmentReport', label: 'گزارش ها', type: "page", - route: "./v2/receipt/report", + route: process.env.NEXT_PUBLIC_API_URL + "/v2/receipt/report", icon: , }, ] diff --git a/src/core/utils/routes.js b/src/core/utils/routes.js new file mode 100644 index 0000000..39b6b09 --- /dev/null +++ b/src/core/utils/routes.js @@ -0,0 +1,4 @@ +const api = process.env.NEXT_PUBLIC_API_URL + +export const GET_USER_ROUTE = api + '/webapi/user/get-permission' +export const GET_LOGIN_ROUTE = api + '/test_login' \ No newline at end of file diff --git a/src/core/utils/successRequest.js b/src/core/utils/successRequest.js new file mode 100644 index 0000000..5138d7a --- /dev/null +++ b/src/core/utils/successRequest.js @@ -0,0 +1,10 @@ +'use client' +import { toast } from "react-toastify"; +import { successToast } from "@/core/components/toasts/success"; + +export const successRequest = (notification, toastContainer) => { + if (notification) { + toast.dismiss({ container: toastContainer }) + successToast(toastContainer) + } +} \ No newline at end of file diff --git a/src/lib/contexts/DataTable.jsx b/src/lib/contexts/DataTable.js similarity index 100% rename from src/lib/contexts/DataTable.jsx rename to src/lib/contexts/DataTable.js diff --git a/src/lib/contexts/auth.js b/src/lib/contexts/auth.js new file mode 100644 index 0000000..e60f413 --- /dev/null +++ b/src/lib/contexts/auth.js @@ -0,0 +1,76 @@ +'use client' +import { createContext, useCallback, useContext, useEffect, useReducer } from 'react'; +import useRequest from '../hooks/useRequest'; +import { GET_USER_ROUTE } from '@/core/utils/routes'; + +const initAuth = { + initAuthState: false, + isAuth: false, + user: {} +}; + +const authReducer = (state, action) => { + switch (action.type) { + case "CLEAR_USER": + return { ...state, user: {} }; + case "CHANGE_USER": + return { ...state, user: action.user }; + case "CHANGE_AUTH_STATE": + return { ...state, isAuth: action.isAuth }; + case "CHANGE_INIT_AUTH": + return { ...state, initAuthState: action.initAuthState }; + default: + return state; + } +}; + +const AuthContext = createContext(); + +export const AuthProvider = ({ children }) => { + const [state, dispatch] = useReducer(authReducer, initAuth); + const request = useRequest() + + const clearUser = useCallback(() => { + dispatch({ type: "CLEAR_USER" }); + }, []); + + const changeUser = useCallback((user) => { + dispatch({ type: "CHANGE_USER", user }); + }, []); + + const changeAuthState = useCallback((isAuth) => { + dispatch({ type: "CHANGE_AUTH_STATE", isAuth }); + }, []); + + const changeInitAuth = useCallback((initAuthState) => { + dispatch({ type: "CHANGE_INIT_AUTH", initAuthState }); + }, []); + + const getUser = useCallback(async () => { + try { + const { data } = await request(GET_USER_ROUTE, 'get') + changeUser(data); + changeAuthState(true); + changeInitAuth(true); + } catch (error) { + if (error.response && error.response.status === 401) { + clearUser(); + changeAuthState(false); + changeInitAuth(true); + } + } + }, [clearUser, changeUser, changeAuthState, changeInitAuth]); + + useEffect(() => { + getUser() + }, []) + + return {children}; +}; + +export const useAuth = () => useContext(AuthContext); \ No newline at end of file diff --git a/src/lib/contexts/tableSetting.jsx b/src/lib/contexts/tableSetting.js similarity index 100% rename from src/lib/contexts/tableSetting.jsx rename to src/lib/contexts/tableSetting.js diff --git a/src/lib/hooks/useDataTable.jsx b/src/lib/hooks/useDataTable.js similarity index 100% rename from src/lib/hooks/useDataTable.jsx rename to src/lib/hooks/useDataTable.js diff --git a/src/lib/hooks/useRequest.js b/src/lib/hooks/useRequest.js new file mode 100644 index 0000000..8beee2e --- /dev/null +++ b/src/lib/hooks/useRequest.js @@ -0,0 +1,42 @@ +import { errorResponse } from "@/core/utils/errorResponse"; +import { successRequest } from "@/core/utils/successRequest"; +import axios from "axios"; + +const defaultOptions = { + data: {}, + requestOptions: { + headers: {} + }, + notification: { + show: true, + success: false, + failed: true + }, +} + +const useRequest = (initOptions) => { + const _options = Object.assign({}, defaultOptions, initOptions); + + return async (url = '', method = 'get', options) => { + const mergedOptions = Object.assign({}, _options, options); + + try { + const response = await axios({ + url, + method, + data: method === 'get' ? null : mergedOptions.data, + withCredentials: true, + ...mergedOptions.requestOptions + }); + successRequest(mergedOptions.notification.show && mergedOptions.notification.success, 'request_data'); + return response; + } catch (error) { + if (error.response) { + errorResponse(error.response, mergedOptions.notification.show && mergedOptions.notification.failed, 'request_data'); + } + throw error; + } + } +} + +export default useRequest \ No newline at end of file diff --git a/src/lib/hooks/useTableSetting.jsx b/src/lib/hooks/useTableSetting.js similarity index 100% rename from src/lib/hooks/useTableSetting.jsx rename to src/lib/hooks/useTableSetting.js