LFFE-12 Merge branch 'feature/LFFE-12_synchronization_projects' into 'develop'

This commit is contained in:
AmirHossein Mahmoodi
2023-11-05 12:44:17 +00:00
49 changed files with 280 additions and 192 deletions

View File

@@ -360,7 +360,8 @@
"permission_min_error": "حداقل باید یک دسترسی انتخاب شود",
"type_id": "نوع کاربر",
"navgan_id": "کد ناوگان",
"button-update": "ویرایش"
"button-update": "ویرایش",
"loading_permissions_list": "درحال دریافت لیست دسترسی ها"
},
"UploadSystem": {
"upload_file": "فایل خود را بارگذاری کنید",
@@ -467,6 +468,7 @@
"type_id": "نوع کاربر",
"navgan_id": "کد ناوگان",
"button-cancel": "انصراف",
"button-add": "ثبت"
"button-add": "ثبت",
"loading_permissions_list": "درحال دریافت لیست دسترسی ها"
}
}

View File

@@ -37,7 +37,7 @@ const ConfirmContent = ({rowId, mutate, setOpenConfirmDialog}) => {
onSubmit: (values, {setSubmitting}) => {
const formData = new FormData();
formData.append("proposed_amount", values.proposed_amount);
if (values.description != "") formData.append("description", values.description);
if (values.description != "") formData.append("expert_description", values.description);
if (values.confirm_img != null) formData.append("attachment", values.confirm_img);
requestServer(`${CONFIRM_MACHINARY_OFFICE}/${rowId}`, 'post', {

View File

@@ -6,7 +6,7 @@ import {useFormik} from "formik";
import {useTranslations} from "next-intl";
import {useState} from "react";
import * as Yup from "yup";
import {REJECT_INSPECTOR_EXPERT} from "@/core/data/apiRoutes";
import {REJECT_MACHINARY_OFFICE} from "@/core/data/apiRoutes";
const RejectContent = ({rowId, mutate, setOpenRejectDialog}) => {
const [selectedImage, setSelectedImage] = useState("");
@@ -29,10 +29,10 @@ const RejectContent = ({rowId, mutate, setOpenRejectDialog}) => {
validationSchema,
onSubmit: (values, {setSubmitting}) => {
const formData = new FormData();
formData.append("description", values.description);
formData.append("expert_description", values.description);
if (values.reject_img != null) formData.append("attachment", values.reject_img);
requestServer(`${REJECT_INSPECTOR_EXPERT}/${rowId}`, 'post', {
requestServer(`${REJECT_MACHINARY_OFFICE}/${rowId}`, 'post', {
data: formData,
}).then((response) => {
setOpenRejectDialog(false)

View File

@@ -24,7 +24,7 @@ const ConfirmContent = ({rowId, mutate, setOpenConfirmDialog}) => {
},
onSubmit: (values, {setSubmitting}) => {
const formData = new FormData();
if (values.description != "") formData.append("description", values.description);
if (values.description != "") formData.append("expert_description", values.description);
if (values.confirm_img != null) formData.append("attachment", values.confirm_img);
requestServer(`${CONFIRM_NAVGAN_PROVINCE_MANAGER}/${rowId}`, 'post', {

View File

@@ -29,7 +29,7 @@ const RejectContent = ({rowId, mutate, setOpenRejectDialog}) => {
validationSchema,
onSubmit: (values, {setSubmitting}) => {
const formData = new FormData();
formData.append("description", values.description);
formData.append("expert_description", values.description);
if (values.reject_img != null) formData.append("attachment", values.reject_img);
requestServer(`${REJECT_NAVGAN_PROVINCE_MANAGER}/${rowId}`, 'post', {

View File

@@ -37,7 +37,7 @@ const ConfirmContent = ({rowId, mutate, setOpenConfirmDialog}) => {
onSubmit: (values, {setSubmitting}) => {
const formData = new FormData();
formData.append("approved_amount", values.approved_amount);
if (values.description != "") formData.append("description", values.description);
if (values.description != "") formData.append("expert_description", values.description);
if (values.confirm_img != null) formData.append("attachment", values.confirm_img);
requestServer(`${CONFIRM_PASSENGER_BOSS}/${rowId}`, 'post', {

View File

@@ -29,7 +29,7 @@ const RejectContent = ({rowId, mutate, setOpenRejectDialog}) => {
validationSchema,
onSubmit: (values, {setSubmitting}) => {
const formData = new FormData();
formData.append("description", values.description);
formData.append("expert_description", values.description);
if (values.reject_img != null) formData.append("attachment", values.reject_img);
requestServer(`${REJECT_PASSENGER_BOSS}/${rowId}`, 'post', {

View File

@@ -29,7 +29,7 @@ const RejectContent = ({rowId, mutate, setOpenRejectDialog}) => {
validationSchema,
onSubmit: (values, {setSubmitting}) => {
const formData = new FormData();
formData.append("description", values.description);
formData.append("expert_description", values.description);
if (values.reject_img != null) formData.append("attachment", values.reject_img);
requestServer(`${REJECT_PASSENGER_OFFICE}/${rowId}`, 'post', {

View File

@@ -1,6 +1,6 @@
import {
Button,
Checkbox,
Checkbox, CircularProgress,
DialogActions,
DialogContent,
FormControl,
@@ -9,7 +9,7 @@ import {
FormLabel,
Grid,
Stack,
TextField
TextField, Typography
} from "@mui/material";
import {useTranslations} from "next-intl";
import useRequest from "@/lib/app/hooks/useRequest";
@@ -21,7 +21,7 @@ import usePermissions from "@/lib/app/hooks/usePermissions";
const CreateContent = ({mutate, setOpenConfirmDialog}) => {
const t = useTranslations();
const requestServer = useRequest({auth: true})
const {permissions_list} = usePermissions()
const {permissions_list, isLoading} = usePermissions()
const validationSchema = Yup.object().shape({
name: Yup.string().required(t("AddDialog.name_error")),
name_fa: Yup.string().required(t("AddDialog.name_fa_error")),
@@ -93,29 +93,40 @@ const CreateContent = ({mutate, setOpenConfirmDialog}) => {
sx={{mt: 2}}
>
<FormHelperText>{formik.touched.permissions && formik.errors.permissions}</FormHelperText>
<Grid container spacing={2}>
{permissions_list ? (
permissions_list.map((permission) => (
<Grid key={permission.id} item xs={6}>
<FormControlLabel
control={
<Checkbox
checked={formik.values.permissions.includes(permission.id)}
onChange={(e) => {
if (e.target.checked) {
formik.setFieldValue("permissions", [...formik.values.permissions, permission.id])
} else {
formik.setFieldValue("permissions", formik.values.permissions.filter((id) => id !== permission.id))
}
}}
{isLoading ?
<Stack direction={'row'} alignItems={'center'} spacing={2}
justifyContent={'center'}>
<CircularProgress size={20}/>
<Typography
variant={'caption'}>{t("AddDialog.loading_permissions_list")}</Typography>
</Stack>
: (
<Grid container spacing={2}>
<>
{permissions_list.map((permission, index) => (
<Grid key={permission.id} item xs={6} data-testid= "PermissionList-checkbox">
<FormControlLabel
control={
<Checkbox
data-testid= {`PermissionList-checkbox-${index}`}
checked={formik.values.permissions.includes(permission.id)}
onChange={(e) => {
if (e.target.checked) {
formik.setFieldValue("permissions", [...formik.values.permissions, permission.id])
} else {
formik.setFieldValue("permissions", formik.values.permissions.filter((id) => id !== permission.id))
}
}}
/>
}
label={permission.name_fa}
/>
}
label={permission.name_fa}
/>
</Grid>
))
) : null}
</Grid>
</Grid>
))}
</>
</Grid>
)
}
</FormControl>
</FormLabel>
</Stack>

View File

@@ -4,7 +4,7 @@ import usePermissions from "@/lib/app/hooks/usePermissions";
import useRequest from "@/lib/app/hooks/useRequest";
import {
Button,
Checkbox,
Checkbox, CircularProgress,
DialogActions,
DialogContent,
FormControl,
@@ -13,7 +13,7 @@ import {
FormLabel,
Grid,
Stack,
TextField
TextField, Typography
} from "@mui/material"
import {useFormik} from "formik";
import {useTranslations} from "next-intl";
@@ -23,7 +23,7 @@ const UpdateContent = ({row, mutate, setOpenConfirmDialog}) => {
const t = useTranslations();
const requestServer = useRequest({auth: true})
const {update_notification} = useNotification()
const {permissions_list} = usePermissions()
const {permissions_list, isLoading} = usePermissions()
const validationSchema = Yup.object().shape({
name: Yup.string().required(t("UpdateDialog.name_error")),
@@ -93,29 +93,40 @@ const UpdateContent = ({row, mutate, setOpenConfirmDialog}) => {
sx={{mt: 2}}
>
<FormHelperText>{formik.touched.permissions && formik.errors.permissions}</FormHelperText>
<Grid container spacing={2}>
{permissions_list ? (
permissions_list.map((permission) => (
<Grid key={permission.id} item xs={6}>
<FormControlLabel
control={
<Checkbox
checked={formik.values.permissions.includes(permission.id)}
onChange={(e) => {
if (e.target.checked) {
formik.setFieldValue("permissions", [...formik.values.permissions, permission.id])
} else {
formik.setFieldValue("permissions", formik.values.permissions.filter((id) => id !== permission.id))
}
}}
{isLoading ?
<Stack direction={'row'} alignItems={'center'} spacing={2}
justifyContent={'center'}>
<CircularProgress size={20}/>
<Typography
variant={'caption'}>{t("UpdateDialog.loading_permissions_list")}</Typography>
</Stack>
: (
<Grid container spacing={2}>
<>
{permissions_list.map((permission) => (
<Grid key={permission.id} item xs={6}>
<FormControlLabel
control={
<Checkbox
data-testid="PermissionList-checkbox"
checked={formik.values.permissions.includes(permission.id)}
onChange={(e) => {
if (e.target.checked) {
formik.setFieldValue("permissions", [...formik.values.permissions, permission.id])
} else {
formik.setFieldValue("permissions", formik.values.permissions.filter((id) => id !== permission.id))
}
}}
/>
}
label={permission.name_fa}
/>
}
label={permission.name_fa}
/>
</Grid>
))
) : null}
</Grid>
</Grid>
))}
</>
</Grid>
)
}
</FormControl>
</FormLabel>
</Stack>

View File

@@ -24,7 +24,7 @@ const ConfirmContent = ({rowId, mutate, setOpenConfirmDialog}) => {
},
onSubmit: (values, {setSubmitting}) => {
const formData = new FormData();
if (values.description != "") formData.append("description", values.description);
if (values.description != "") formData.append("expert_description", values.description);
if (values.confirm_img != null) formData.append("attachment", values.confirm_img);
requestServer(`${CONFIRM_TRANSPORTATION_ASSISTANCE}/${rowId}`, 'post', {
@@ -106,7 +106,7 @@ const ConfirmContent = ({rowId, mutate, setOpenConfirmDialog}) => {
{t("ConfirmDialog.button-cancel")}
</Button>
<Button onClick={formik.handleSubmit} variant="contained" color="primary"
disabled={formik.isSubmitting || !formik.dirty || !formik.isValid}>
disabled={formik.isSubmitting}>
{t("ConfirmDialog.button-confirm")}
</Button>
</DialogActions>

View File

@@ -29,7 +29,7 @@ const RejectContent = ({rowId, mutate, setOpenRejectDialog}) => {
validationSchema,
onSubmit: (values, {setSubmitting}) => {
const formData = new FormData();
formData.append("description", values.description);
formData.append("expert_description", values.description);
if (values.reject_img != null) formData.append("attachment", values.reject_img);
requestServer(`${REJECT_TRANSPORTATION_ASSISTANCE}/${rowId}`, 'post', {

View File

@@ -1,5 +1,4 @@
import LinkRouting from "@/core/components/LinkRouting";
import PasswordField from "@/core/components/PasswordField";
import StyledForm from "@/core/components/StyledForm";
import {GET_USER_TOKEN} from "@/core/data/apiRoutes";
import CenterLayout from "@/layouts/CenterLayout";
@@ -14,6 +13,7 @@ import * as Yup from "yup";
import useDirection from "@/lib/app/hooks/useDirection";
import SvgLogin from "@/core/components/svgs/SvgLogin";
import useRequest from "@/lib/app/hooks/useRequest";
import PasswordField from "@/core/components/PasswordField";
const LoginComponent = () => {
const t = useTranslations();

View File

@@ -14,7 +14,6 @@ function DataTable(props) {
const [columnFilters, setColumnFilters] = useState([]);
const [sorting, setSorting] = useState(props.sorting || []);
const [pagination, setPagination] = useState({pageIndex: 0, pageSize: 10});
const [rowCount, setRowCount] = useState(0);
const [columnFilterFns, setColumnFilterFns] = useState(() => {
let output = {};
const list = props.columns.map((item) => item.enableColumnFilter ? {[item.id]: item.filterFn} : {[item.id]: ""});
@@ -34,8 +33,11 @@ function DataTable(props) {
const tableLocalization = useMemo(() => languageList.find((item) => item.key == languageApp).tableLocalization, [languageApp, languageList]);
const fetchUrl = useMemo(() => {
const url = new URL(props.tableUrl);
url.searchParams.set("start", `${pagination.pageIndex * pagination.pageSize}`);
const params = new URLSearchParams();
params.set(
"start",
`${pagination.pageIndex * pagination.pageSize}`
);
const filters = columnFilters.map((filter) => {
let datatype;
for (const i in props.columns) {
@@ -47,10 +49,10 @@ function DataTable(props) {
...filter, fn: columnFilterFns[filter.id], datatype: datatype,
};
});
url.searchParams.set("size", pagination.pageSize);
url.searchParams.set("filters", JSON.stringify(filters ?? []));
url.searchParams.set("sorting", JSON.stringify(sorting ?? []));
return url;
params.set("size", pagination.pageSize);
params.set("filters", JSON.stringify(filters ?? []));
params.set("sorting", JSON.stringify(sorting ?? []));
return `${props.tableUrl}?${params}`;
}, [props.tableUrl, columnFilters, columnFilterFns, pagination, sorting, props.columns,]);
const {data, isValidating, mutate} = useSWR(fetchUrl, (...args) =>

View File

@@ -2,8 +2,8 @@ import DangerousIcon from "@mui/icons-material/Dangerous";
import {Box, Typography} from "@mui/material";
import {toast} from "react-toastify";
const ErrorNotification = (t, status, message) => {
toast(
const ErrorNotification = (pushToastList, notificationType, t, status, message) => {
const toastId = toast(
() => (
<>
<Box
@@ -29,11 +29,13 @@ const ErrorNotification = (t, status, message) => {
</>
),
{
containerId: 'validation',
autoClose: false,
closeOnClick: false,
draggable: false,
}
);
pushToastList(notificationType, toastId);
};
export default ErrorNotification;
export default ErrorNotification;

View File

@@ -1,12 +1,14 @@
import {toast} from "react-toastify";
const PendingNotification = (t) => {
toast(t("notifications.pending"), {
const PendingNotification = (pushToastList, notificationType, t) => {
const toastId = toast(t("notifications.pending"), {
containerId: 'validation',
autoClose: false,
closeButton: false,
closeOnClick: false,
draggable: false,
});
pushToastList(notificationType, toastId);
};
export default PendingNotification;
export default PendingNotification;

View File

@@ -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 = (pushToastList, notificationType, t, status) => {
const toastId = toast(
() => (
<>
<Box
@@ -30,6 +30,7 @@ const SuccessNotification = (t, status) => {
</>
),
{
containerId: 'validation',
autoClose: 3000,
hideProgressBar: true,
pauseOnHover: true,
@@ -37,6 +38,7 @@ const SuccessNotification = (t, status) => {
draggable: true,
}
);
pushToastList(notificationType, toastId);
};
export default SuccessNotification;
export default SuccessNotification;

View File

@@ -26,6 +26,8 @@ const UploadFileNotification = (t) => {
</>
),
{
containerId: 'validation',
toastId: 'upload',
autoClose: 3000,
hideProgressBar: true,
pauseOnHover: true,
@@ -35,4 +37,4 @@ const UploadFileNotification = (t) => {
);
};
export default UploadFileNotification;
export default UploadFileNotification;

View File

@@ -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 = (pushToastList, notificationType, t, status) => {
const toastId = toast(
() => (
<>
<Box
@@ -30,11 +30,13 @@ const WarningNotification = (t, status) => {
</>
),
{
containerId: 'validation',
autoClose: false,
closeOnClick: false,
draggable: false,
}
);
pushToastList(notificationType, toastId);
};
export default WarningNotification;
export default WarningNotification;

View File

@@ -1,54 +1,27 @@
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);
const Notifications = (pushToastList, notificationType, t, status, message) => {
switch (notificationType) {
case "pending":
pendingNotification(pushToastList, notificationType, t);
break;
case 400:
ErrorNotification(t, status);
case "warning":
WarningNotification(pushToastList, notificationType, t, status);
break;
case 401:
ErrorNotification(t, status);
case "error":
if (message) {
ErrorNotification(pushToastList, notificationType, t, status, message)
} else {
ErrorNotification(pushToastList, notificationType, 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,
});
case "success":
SuccessNotification(pushToastList, notificationType, t, status);
break;
}
};
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
*/

View File

@@ -1,45 +1,48 @@
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();
export const errorSetting = (dismissToastList, t, notification) => {
if (notification) {
dismissToastList(["pending", "warning", "error", "success"])
}
}
export const errorRequest = (t, notification) => {
if (notification) toast.dismiss();
}
export const errorResponse = (response, clearToken, t, notification) => {
if (notification) toast.dismiss();
if (isServerError(response.status)) {
errorServer(response, t, notification)
} else if (isClientError(response.status)) {
errorClient(response, clearToken, t, notification)
export const errorRequest = (dismissToastList, t, notification) => {
if (notification) {
dismissToastList(["pending", "warning", "error", "success"])
}
}
const errorServer = (response, t, notification) => {
if (notification) WarningNotification(t, response.status);
export const errorResponse = (pushToastList, dismissToastList, response, clearToken, t, notification) => {
if (notification) {
dismissToastList(["pending", "warning", "error", "success"])
}
if (isServerError(response.status)) {
errorServer(pushToastList, response, t, notification)
} else if (isClientError(response.status)) {
errorClient(pushToastList, response, clearToken, t, notification)
}
}
const errorClient = (response, clearToken, t, notification) => {
const errorServer = (pushToastList, response, t, notification) => {
if (notification) Notifications(pushToastList, "warning", t, response.status);
}
const errorClient = (pushToastList, response, clearToken, t, notification) => {
switch (response.status) {
case 401:
clearToken()
if (notification) ErrorNotification(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) ErrorNotification(t, response.status)
if (notification) Notifications(pushToastList, "error", t, response.status);
break
default:
if (notification) ErrorNotification(t, response.status)
if (notification) Notifications(pushToastList, "error", t, response.status);
break
}
}
@@ -47,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) ErrorNotification(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) => {
ErrorNotification(t, response.status, errorsArray[item][0]);
Notifications(pushToastList, "error", t, response.status, errorsArray[item][0]);
})
}
}

View File

@@ -1,9 +1,8 @@
import SuccessNotification from "@/core/components/notifications/SuccessNotification";
import {toast} from "react-toastify";
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) {
toast.dismiss();
SuccessNotification(t, response.status)
dismissToastList(["pending", "warning", "error", "success"])
Notifications(pushToastList, "success", t, response.status);
}
}

View File

@@ -1,8 +1,8 @@
import {FA_DATATABLE_LOCALIZATION} from "&/locales/fa/datatable";
import {FA_CHART_LOCALIZATION} from "&/locales/fa/chart";
import {useRouter} from "next/router";
import {createContext, useEffect, useState} from "react";
import useUser from "../hooks/useUser";
import {FA_CHART_LOCALIZATION} from "&/locales/fa/chart";
export const LanguageContext = createContext();
@@ -20,7 +20,7 @@ export const LanguageProvider = ({children}) => {
];
const {user, userChangedLanguage, changeLanguageState} = useUser();
const [languageIsReady, setLanguageIsReady] = useState(false);
const [languageApp, setLanguageApp] = useState();
const [languageApp, setLanguageApp] = useState(process.env.NEXT_PUBLIC_DEFAULT_LANGUAGE);
const [directionApp, setDirectionApp] = useState(
process.env.NEXT_PUBLIC_DEFAULT_DIRECTION
);
@@ -28,9 +28,7 @@ export const LanguageProvider = ({children}) => {
useEffect(() => {
const lang = localStorage.getItem("_language");
if (!lang && !languageApp) {
setLanguageApp(process.env.NEXT_PUBLIC_DEFAULT_LANGUAGE);
} else if (lang) {
if (lang) {
setLanguageApp(lang);
}
}, []);

View File

@@ -0,0 +1,37 @@
import {createContext, useReducer} from "react";
import {toast} from "react-toastify";
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]
};
case "DISMISS":
action.toast_type.map((item) => {
state[item].map((id) => {
toast.dismiss(id);
})
state[item] = []
});
return state;
}
};
export const ToastProvider = ({children}) => {
const [state, dispatch] = useReducer(reducer, {
pending: [],
error: [],
warning: [],
success: []
});
return (
<ToastContext.Provider value={{state, dispatch}}>
{children}
</ToastContext.Provider>
);
};

View File

@@ -1,7 +1,6 @@
import {GET_USER_ROUTE} from "@/core/data/apiRoutes";
import axios from "axios";
import {createContext, useCallback, useEffect, useReducer} from "react";
import {errorRequest, errorResponse, errorSetting} from "@/core/utils/errorHandler";
const initialUser = {
isAuth: false,
@@ -78,13 +77,7 @@ export const UserProvider = ({children}) => {
if (typeof callback === "function") callback(data);
})
.catch(error => {
if (error.response) {
errorResponse(error.response, clearToken, null, false)
} else if (error.request) {
errorRequest(null, false)
} else {
errorSetting(null, false)
}
if (error.response.status === 401) clearToken()
})
},
[state.token]

View File

@@ -11,15 +11,16 @@ const usePermissions = () => {
})
};
const {data} = useSWR(GET_PERMISSIONS_LIST, fetcher, {
const {data, isLoading} = useSWR(GET_PERMISSIONS_LIST, fetcher, {
revalidateIfStale: false,
revalidateOnFocus: false,
revalidateOnReconnect: false
revalidateOnReconnect: false,
keepPreviousData : true
})
const permissions_list = data
//swr config
// render data
return {permissions_list}
return {permissions_list, isLoading}
}
export default usePermissions;

View File

@@ -1,10 +1,11 @@
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";
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, dismissToastList} = useToast();
let _options = {...defaultOptions, ...initOptions}
function requestServer(url = '', method = 'get', options) {
@@ -33,27 +35,30 @@ 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) PendingNotification(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)
})

View File

@@ -0,0 +1,21 @@
import {useContext} from "react";
import {ToastContext} from "@/lib/app/contexts/toast";
const useToast = () => {
const {dispatch} = useContext(ToastContext);
const pushToastList = (toast_type, toast_id) => {
dispatch({type: "PUSH", toast_type, toast_id});
};
const dismissToastList = (toast_type) => {
dispatch({type: "DISMISS", toast_type});
};
return {
pushToastList,
dismissToastList
}
};
export default useToast;

View File

@@ -8,6 +8,7 @@ import "moment/locale/fa";
import {NextIntlProvider} from "next-intl";
import TitlePage from "@/core/components/TitlePage";
import Layout from "@/layouts";
import {ToastProvider} from "@/lib/app/contexts/toast";
const App = ({Component, pageProps}) => {
@@ -19,11 +20,13 @@ const App = ({Component, pageProps}) => {
<MuiLayout isBot={pageProps.isBot}>
{pageProps.messages ? <TitlePage text={pageProps.title}/> : ''}
<LoadingProvider>
<AppLayout isBot={pageProps.isBot}>
<Layout layout={pageProps.layout}>
<Component {...pageProps} />
</Layout>
</AppLayout>
<ToastProvider>
<AppLayout isBot={pageProps.isBot}>
<Layout layout={pageProps.layout}>
<Component {...pageProps} />
</Layout>
</AppLayout>
</ToastProvider>
</LoadingProvider>
</MuiLayout>
</NextIntlProvider>

View File

@@ -14,6 +14,7 @@ export async function getServerSideProps({req, locale}) {
messages: (await import(`&/locales/${locale}/app.json`)).default,
title: "Dashboard.change_password",
isBot,
locale,
layout: {name: 'DashboardLayout'}
},
};

View File

@@ -14,6 +14,7 @@ export async function getServerSideProps({req, locale}) {
messages: (await import(`&/locales/${locale}/app.json`)).default,
title: "Dashboard.commercial_chief_page",
isBot,
locale,
layout: {name: 'DashboardLayout', props: {permissions: ["manage_commercial_refahi"]}}
},
};

View File

@@ -14,6 +14,7 @@ export async function getServerSideProps({req, locale}) {
messages: (await import(`&/locales/${locale}/app.json`)).default,
title: "Dashboard.development_assistant_page",
isBot,
locale,
layout: {name: 'DashboardLayout', props: {permissions: ["manage_development_refahi"]}}
},
};

View File

@@ -14,6 +14,7 @@ export async function getServerSideProps({req, locale}) {
messages: (await import(`&/locales/${locale}/app.json`)).default,
title: "Dashboard.edit_profile",
isBot,
locale,
layout: {name: 'DashboardLayout'}
},
};

View File

@@ -14,7 +14,8 @@ export async function getServerSideProps({req, locale}) {
messages: (await import(`&/locales/${locale}/app.json`)).default,
title: "Dashboard.expert_management",
isBot,
layout: {name: 'DashboardLayout', props: {permissions: ["manage_transportation_navgan"]}}
locale,
layout: {name: 'DashboardLayout', props: {permissions: ["manage_experts"]}}
},
};
}

View File

@@ -14,6 +14,7 @@ export async function getServerSideProps({req, locale}) {
messages: (await import(`&/locales/${locale}/app.json`)).default,
title: "Dashboard.dashboard_page",
isBot,
locale,
layout: {name: 'DashboardLayout'}
},
};

View File

@@ -14,6 +14,7 @@ export async function getServerSideProps({req, locale}) {
messages: (await import(`&/locales/${locale}/app.json`)).default,
title: "Dashboard.inspector_expert_page",
isBot,
locale,
layout: {name: 'DashboardLayout', props: {permissions: ["manage_inspector_refahi"]}}
},
};

View File

@@ -14,6 +14,7 @@ export async function getServerSideProps({req, locale}) {
messages: (await import(`&/locales/${locale}/app.json`)).default,
title: "Dashboard.machinary_office_page",
isBot,
locale,
layout: {name: 'DashboardLayout', props: {permissions: ["manage_machinery_navgan"]}}
},
};

View File

@@ -14,6 +14,7 @@ export async function getServerSideProps({req, locale}) {
messages: (await import(`&/locales/${locale}/app.json`)).default,
title: "Dashboard.loan_management_page",
isBot,
locale,
layout: {name: 'DashboardLayout', props: {permissions: ["manage_navgan_loan"]}}
},
};

View File

@@ -14,6 +14,7 @@ export async function getServerSideProps({req, locale}) {
messages: (await import(`&/locales/${locale}/app.json`)).default,
title: "Dashboard.province_manager_page",
isBot,
locale,
layout: {name: 'DashboardLayout', props: {permissions: ["manage_province_affairs_navgan"]}}
},
};

View File

@@ -14,6 +14,7 @@ export async function getServerSideProps({req, locale}) {
messages: (await import(`&/locales/${locale}/app.json`)).default,
title: "Dashboard.passenger_boss_page",
isBot,
locale,
layout: {name: 'DashboardLayout', props: {permissions: ["manage_province_working_group_navgan"]}}
},
};

View File

@@ -14,6 +14,7 @@ export async function getServerSideProps({req, locale}) {
messages: (await import(`&/locales/${locale}/app.json`)).default,
title: "Dashboard.passenger_office_page",
isBot,
locale,
layout: {name: 'DashboardLayout', props: {permissions: ["manage_passenger_office_navgan"]}}
},
};

View File

@@ -14,6 +14,7 @@ export async function getServerSideProps({req, locale}) {
messages: (await import(`&/locales/${locale}/app.json`)).default,
title: "Dashboard.province_head_expert",
isBot,
locale,
layout: {name: 'DashboardLayout', props: {permissions: ["manage_province_headquarter_refahi"]}}
},
};

View File

@@ -14,6 +14,7 @@ export async function getServerSideProps({req, locale}) {
messages: (await import(`&/locales/${locale}/app.json`)).default,
title: "Dashboard.loan_management_page",
isBot,
locale,
layout: {name: 'DashboardLayout', props: {permissions: ["manage_refahi_loan"]}}
},
};

View File

@@ -14,6 +14,7 @@ export async function getServerSideProps({req, locale}) {
messages: (await import(`&/locales/${locale}/app.json`)).default,
title: "Dashboard.province_manager_page",
isBot,
locale,
layout: {name: 'DashboardLayout', props: {permissions: ["manage_province_affairs_refahi"]}}
},
};

View File

@@ -14,6 +14,7 @@ export async function getServerSideProps({req, locale}) {
messages: (await import(`&/locales/${locale}/app.json`)).default,
title: "Dashboard.role_management_page",
isBot,
locale,
layout: {name: 'DashboardLayout', props: {permissions: ["manage_roles"]}}
},
};

View File

@@ -14,6 +14,7 @@ export async function getServerSideProps({req, locale}) {
messages: (await import(`&/locales/${locale}/app.json`)).default,
title: "Dashboard.transportation_assistance",
isBot,
locale,
layout: {name: 'DashboardLayout', props: {permissions: ["manage_transportation_navgan"]}}
},
};

View File

@@ -14,6 +14,7 @@ export async function getServerSideProps({req, locale}) {
messages: (await import(`&/locales/${locale}/app.json`)).default,
title: "Dashboard.user_management_page",
isBot,
locale,
layout: {name: 'DashboardLayout', props: {permissions: ["manage_users"]}}
},
};

View File

@@ -17,6 +17,7 @@ export async function getServerSideProps({req, locale}) {
messages: (await import(`&/locales/${locale}/app.json`)).default,
title: "Titles.title_login_expert_page",
isBot,
locale
},
};
}