diff --git a/public/locales/fa/app.json b/public/locales/fa/app.json index 18aec33..c7e476a 100644 --- a/public/locales/fa/app.json +++ b/public/locales/fa/app.json @@ -36,6 +36,7 @@ "inspector-expert": "بازدید کارشناس", "province-head-expert": "کارشناس ستادی", "change-password": "تغییر رمز عبور", + "development-assistant": "معاون توسعه", "edit-profile": "ویرایش پروفایل" }, "secondary": { @@ -80,11 +81,9 @@ "province_manager_page": "مدیر کل استانی", "passenger_office_page": "اداره مسافر", "machinary_office_page": "ماشین آلات", -<<<<<<< public/locales/fa/app.json + "development_assistant": "معاون توسعه", "inspector_expert_page": "بازدید کارشناس", -======= "commercial_chief_page": "رئیس اداره بازرگانی", ->>>>>>> public/locales/fa/app.json "edit_profile": "ویرایش پروفایل" }, "MuiDatePicker": { @@ -170,6 +169,17 @@ "vehicle_type": "نوع ماشین", "state_name": "وضعیت درخواست" }, + "DevelopmentAssistant": { + "name": "نام", + "id": "کد یکتا", + "national_id": "کد ملی", + "phone_number": "موبایل", + "created_at": "تاریخ درخواست", + "updated_at": "تاریخ بروزرسانی", + "navgan_id": "کد ناوگان", + "vehicle_type": "نوع ماشین", + "state_name": "وضعیت درخواست" + }, "ProvinceHeadExpert": { "name": "نام", "id": "کد یکتا", diff --git a/src/components/dashboard/development-assistant/Form/ConfirmForm.jsx b/src/components/dashboard/development-assistant/Form/ConfirmForm.jsx new file mode 100644 index 0000000..e3732f1 --- /dev/null +++ b/src/components/dashboard/development-assistant/Form/ConfirmForm.jsx @@ -0,0 +1,137 @@ +import {useTranslations} from "next-intl"; +import {useState} from "react"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + Stack, + TextField, + Tooltip, + Typography +} from "@mui/material"; +import ThumbUpAltIcon from "@mui/icons-material/ThumbUpAlt"; +import UploadSystem from "@/core/components/UploadSystem"; +import {useFormik} from "formik"; +import UploadFileNotification from "@/core/components/notifications/UploadFileNotification"; +import {CONFIRM_DEVELOPMENT_ASSISTANT} from "@/core/data/apiRoutes"; +import useRequest from "@/lib/app/hooks/useRequest"; + +const Confirm = ({rowId, fetchUrl, mutate}) => { + const t = useTranslations(); + const [selectedImage, setSelectedImage] = useState(""); + const [fileType, setfileType] = useState(null); + const [fileName, setfileName] = useState(null); + const [showAddIcon, setShowAddIcon] = useState(true); + const [openConfirmDialog, setOpenConfirmDialog] = useState(false); + const requestServer = useRequest({auth: true}) + + const formik = useFormik({ + initialValues: { + description: "", + confirm_img: null + }, + onSubmit: (values, {setSubmitting}) => { + const formData = new FormData(); + if (values.description != "") formData.append("expert_description", values.description); + if (values.confirm_img != null) formData.append("attachment", values.confirm_img); + + requestServer(`${CONFIRM_DEVELOPMENT_ASSISTANT}/${rowId}`, 'post', { + data: formData, + }).then((response) => { + mutate(fetchUrl) + }).catch(() => { + }).finally(() => { + setSubmitting(false); + }); + }, + }); + + const handleDescriptionChange = (event) => { + formik.setFieldValue("description", event.target.value) + }; + const handleUploadChange = (event) => { + const uploadedFile = event.target?.files?.[0]; + if (uploadedFile) { + const maxFileSize = 2 * 1024 * 1024; + if (uploadedFile.size > maxFileSize) { + UploadFileNotification(t); + event.target.value = ""; + return; + } + + const fileType = event.target?.files?.[0].type; + const fileName = event.target?.files?.[0].name; + setSelectedImage(URL.createObjectURL(uploadedFile)); + setfileType(fileType); + setfileName(fileName); + formik.setFieldValue("confirm_img", uploadedFile); + setShowAddIcon(false); + } + }; + return ( + <> + + { + setOpenConfirmDialog(true) + }} + > + + + + + {t("ConfirmDialog.confirm")} + + + + + {t("ConfirmDialog.description")}{t("ConfirmDialog.optional")}} + value={formik.values.description} + onChange={handleDescriptionChange} + fullWidth + variant="outlined" + sx={{mt: 1}} + /> + + + {t("UploadSystem.upload_file")}{t("UploadSystem.optional")} + + + + + + + + + + + ); +}; +export default Confirm; \ No newline at end of file diff --git a/src/components/dashboard/development-assistant/Form/RejectForm.jsx b/src/components/dashboard/development-assistant/Form/RejectForm.jsx new file mode 100644 index 0000000..81d54ea --- /dev/null +++ b/src/components/dashboard/development-assistant/Form/RejectForm.jsx @@ -0,0 +1,142 @@ +import {REJECT_DEVELOPMENT_ASSISTANT} from "@/core/data/apiRoutes"; +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogTitle, + IconButton, + Stack, + TextField, + Tooltip, + Typography, +} from "@mui/material"; +import {useTranslations} from "next-intl"; +import {useFormik} from "formik"; +import * as Yup from "yup"; +import {useState} from "react"; +import UploadSystem from "@/core/components/UploadSystem"; +import UploadFileNotification from "@/core/components/notifications/UploadFileNotification"; +import ThumbDownIcon from "@mui/icons-material/ThumbDown"; +import useRequest from "@/lib/app/hooks/useRequest"; + +const Reject = ({rowId, fetchUrl, mutate}) => { + const [selectedImage, setSelectedImage] = useState(""); + const [fileType, setfileType] = useState(null); + const [fileName, setfileName] = useState(null); + const [showAddIcon, setShowAddIcon] = useState(true); + const t = useTranslations(); + const [openRejectDialog, setOpenRejectDialog] = useState(false); + const requestServer = useRequest({auth: true}) + + const validationSchema = Yup.object().shape({ + description: Yup.string().required(t("RejectDialog.description_error")), + }); + + const formik = useFormik({ + initialValues: { + description: "", + reject_img: null + }, + validationSchema, + onSubmit: (values, {setSubmitting}) => { + const formData = new FormData(); + formData.append("expert_description", values.description); + if (values.reject_img != null) formData.append("attachment", values.reject_img); + + requestServer(`${REJECT_DEVELOPMENT_ASSISTANT}/${rowId}`, 'post', { + data: formData, + }).then((response) => { + mutate(fetchUrl) + }).catch(() => { + }).finally(() => { + setSubmitting(false); + }); + }, + }); + + const handleDescriptionChange = (event) => { + formik.setFieldValue("description", event.target.value); + formik.handleChange(event); + }; + const handleUploadChange = (event) => { + const uploadedFile = event.target?.files?.[0]; + if (uploadedFile) { + const maxFileSize = 2 * 1024 * 1024; + if (uploadedFile.size > maxFileSize) { + UploadFileNotification(t); + event.target.value = ""; + return; + } + const fileType = event.target?.files?.[0].type; + const fileName = event.target?.files?.[0].name; + setSelectedImage(URL.createObjectURL(uploadedFile)); + setfileType(fileType); + setfileName(fileName); + formik.setFieldValue("reject_img", uploadedFile); + setShowAddIcon(false); + } + }; + return ( + <> + + setOpenRejectDialog(true)}> + + + + + {t("RejectDialog.reject")} + + + + + + + {t("UploadSystem.upload_file")}{t("UploadSystem.optional")} + + + + + + + + + + + ); +}; +export default Reject; \ No newline at end of file diff --git a/src/components/dashboard/development-assistant/TableRowActions.jsx b/src/components/dashboard/development-assistant/TableRowActions.jsx new file mode 100644 index 0000000..601240f --- /dev/null +++ b/src/components/dashboard/development-assistant/TableRowActions.jsx @@ -0,0 +1,23 @@ +import {Box} from "@mui/material"; +import ConfirmForm from "./Form/ConfirmForm" +import RejectForm from "./Form/RejectForm" + +const TableRow = ({row, mutate, fetchUrl}) => { + + return ( + + + + + ); +}; + +export default TableRow; diff --git a/src/components/dashboard/development-assistant/TableTollbar.jsx b/src/components/dashboard/development-assistant/TableTollbar.jsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/dashboard/development-assistant/index.jsx b/src/components/dashboard/development-assistant/index.jsx new file mode 100644 index 0000000..b18b6ae --- /dev/null +++ b/src/components/dashboard/development-assistant/index.jsx @@ -0,0 +1,237 @@ +import DashboardLayouts from "@/layouts/dashboardLayouts"; +import {Box, IconButton, Typography} from "@mui/material"; +import ClearIcon from "@mui/icons-material/Clear"; +import {useMemo} from "react"; +import {GET_DEVELOPMENT_ASSISTANT} from "@/core/data/apiRoutes"; +import {useTranslations} from "next-intl"; +import TableRowActions from "./TableRowActions"; +import {LocalizationProvider, MobileDateTimePicker,} from "@mui/x-date-pickers"; +import {AdapterDateFnsJalali} from "@mui/x-date-pickers/AdapterDateFnsJalali"; +import moment from "jalali-moment"; +import {faIR} from "@mui/x-date-pickers/locales"; +import DataTable from "@/core/components/DataTable"; + +function DashboardDevelopmentAssistantComponent() { + const t = useTranslations(); + + const columns = useMemo( + () => [ + { + accessorFn: (row) => row.id, + id: "id", + header: t("DevelopmentAssistant.id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.name, + id: "name", + header: t("DevelopmentAssistant.name"), + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: ["contains", "equals", "notEquals"], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.national_id, + id: "national_id", + header: t("DevelopmentAssistant.national_id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.phone_number, + id: "phone_number", + header: t("DevelopmentAssistant.phone_number"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => + moment(row.created_at).locale("fa").format("HH:mm | yyyy/MM/DD"), + id: "created_at", + header: t("DevelopmentAssistant.created_at"), + enableColumnFilter: true, + datatype: "date", + filterFn: "lessThan", + columnFilterModeOptions: ["lessThan", "greaterThan"], + Cell: ({renderedCellValue}) => { + return {renderedCellValue}; + }, + Header: ({column}) => {column.columnDef.header}, + Filter: ({column}) => { + const filterFnValue = column.columnDef._filterFn; + return ( + + + { + const date = new Date(newValue); + const formattedDate = moment(date) + .locale("en") + .format("YYYY-MM-DD HH:mm"); + column.setFilterValue(formattedDate); + }} + slotProps={{ + textField: { + placeholder: "تاریخ خود را وارد کنید", + helperText: `${t("filter_mode")}: ${t(filterFnValue)}`, + sx: {minWidth: "120px"}, + variant: "standard", + }, + }} + value={ + column.getFilterValue() + ? new Date(column.getFilterValue()) + : null + } + /> + + { + column.setFilterValue(null); + }} + sx={{ + color: column.getFilterValue() + ? "rgba(0, 0, 0, 0.54)" + : "#bfbfbf", + }} + > + + + + ); + }, + }, + { + accessorFn: (row) => + moment(row.updated_at).locale("fa").format("HH:mm | yyyy/MM/DD"), + id: "updated_at", + header: t("DevelopmentAssistant.updated_at"), + enableColumnFilter: false, + datatype: "numeric", + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + // { + // accessorFn: (row) => row.navgan_id, + // id: "navgan_id", + // header: t("DevelopmentAssistant.navgan_id"), + // enableColumnFilter: true, + // datatype: "numeric", + // filterFn: "equals", + // columnFilterModeOptions: [ + // "equals", + // "notEquals", + // "contains", + // "lessThan", + // "greaterThan", + // "between", + // ], + // Cell: ({renderedCellValue}) => ( + // {renderedCellValue} + // ), + // }, + // { + // accessorFn: (row) => row.vehicle_type, + // id: "vehicle_type", + // header: t("DevelopmentAssistant.vehicle_type"), + // enableColumnFilter: true, + // datatype: "text", + // filterFn: "contains", + // columnFilterModeOptions: ["contains", "equals", "notEquals"], + // Cell: ({renderedCellValue}) => ( + // {renderedCellValue} + // ), + // }, + { + accessorFn: (row) => row.state_name, + id: "state_id", + header: t("DevelopmentAssistant.state_name"), + enableColumnFilter: false, + datatype: "numeric", + // filterFn: "equals", + // filterSelectOptions: [ + // ], + // filterVariant: "select", + Cell: ({renderedCellValue}) => ( + {renderedCellValue} + ), + }, + ], + [] + ); + return ( + + + + + + ); +} + +export default DashboardDevelopmentAssistantComponent; diff --git a/src/core/data/apiRoutes.js b/src/core/data/apiRoutes.js index 884ad35..1a63114 100644 --- a/src/core/data/apiRoutes.js +++ b/src/core/data/apiRoutes.js @@ -78,6 +78,17 @@ export const REJECT_PROVINCE_MANAGER = BASE_URL + "/dashboard/province_manager/reject"; //province manager +// development assistant +export const GET_DEVELOPMENT_ASSISTANT = + BASE_URL + "/dashboard/development_assistant/show"; + +export const CONFIRM_DEVELOPMENT_ASSISTANT = + BASE_URL + "/dashboard/development_assistant/confirm"; + +export const REJECT_DEVELOPMENT_ASSISTANT = + BASE_URL + "/dashboard/development_assistant/reject"; +//development assistant + // inspector expert export const GET_INSPECTOR_EXPERT = BASE_URL + "/dashboard/inspector_expert/show"; diff --git a/src/core/data/sidebarMenu.jsx b/src/core/data/sidebarMenu.jsx index 5043b73..dc42c7d 100644 --- a/src/core/data/sidebarMenu.jsx +++ b/src/core/data/sidebarMenu.jsx @@ -65,6 +65,14 @@ const sidebarMenu = [ selected: false, role: "province_manager", }, + { + key: "sidebar.development-assistant", + type: "page", + route: "/dashboard/development-assistant", + icon: , + selected: false, + role: "development_assistant", + }, { key: "sidebar.inspector-expert", type: "page", diff --git a/src/pages/dashboard/development-assistant/index.jsx b/src/pages/dashboard/development-assistant/index.jsx new file mode 100644 index 0000000..1db0d2e --- /dev/null +++ b/src/pages/dashboard/development-assistant/index.jsx @@ -0,0 +1,26 @@ +import RolePermissionMiddleware from "@/middlewares/RolePermission"; +import WithAuthMiddleware from "@/middlewares/WithAuth"; +import {parse} from "next-useragent"; +import DashboardDevelopmentAssistantComponent from "@/components/dashboard/development-assistant"; + +const requiredPermissions = ["development_assistant"]; +export default function PassengerBoss() { + return ( + + + + + + ); +} + +export async function getServerSideProps({req, locale}) { + const {isBot} = parse(req.headers["user-agent"]); + return { + props: { + messages: (await import(`&/locales/${locale}/app.json`)).default, + title: "Dashboard.development_assistant", + isBot, + }, + }; +}