diff --git a/public/locales/fa/app.json b/public/locales/fa/app.json index 7437875..c644b8c 100644 --- a/public/locales/fa/app.json +++ b/public/locales/fa/app.json @@ -23,7 +23,7 @@ "machinary-office": "ماشین آلات", "passenger-boss": "رئیس مسافر (کارگروه استانی)", "transportation-assistance": "معاونت حمل و نقل", - "manager": "مدیر کل", + "province-manager": "مدیر کل استانی", "change-password": "تغییر رمز عبور", "edit-profile": "ویرایش پروفایل" }, @@ -47,8 +47,9 @@ }, "Dashboard": { "dashboard_page": "داشبورد", - "passenger_boss": "رئیس مسافر", + "passenger_boss_page": "رئیس مسافر", "change_password": "تغییر رمز عبور", + "province_manager_page": "مدیر کل استانی", "passenger_office_page": "اداره مسافر", "machinary_office_page": "ماشین آلات", "edit_profile": "ویرایش پروفایل" @@ -103,6 +104,17 @@ "vehicle_type": "نوع ماشین", "state_name": "وضعیت درخواست" }, + "ProvinceManager": { + "name": "نام", + "id": "کد یکتا", + "national_id": "کد ملی", + "phone_number": "موبایل", + "created_at": "تاریخ درخواست", + "updated_at": "تاریخ بروزرسانی", + "navgan_id": "کد ناوگان", + "vehicle_type": "نوع ماشین", + "state_name": "وضعیت درخواست" + }, "PassengerBoss": { "name": "نام", "id": "کد یکتا", diff --git a/src/components/dashboard/machinary-office/index.jsx b/src/components/dashboard/machinary-office/index.jsx index 44b2a79..12a6316 100644 --- a/src/components/dashboard/machinary-office/index.jsx +++ b/src/components/dashboard/machinary-office/index.jsx @@ -24,6 +24,7 @@ function DashboardMachinaryOfficeComponent() { enableColumnFilter: true, datatype: "numeric", filterFn: "equals", + maxSize: 100, columnFilterModeOptions: [ "equals", "notEquals", @@ -94,13 +95,10 @@ function DashboardMachinaryOfficeComponent() { enableColumnFilter: true, datatype: "date", filterFn: "lessThan", + minSize: 200, columnFilterModeOptions: ["lessThan", "greaterThan"], Cell: ({ renderedCellValue }) => { - return ( - - {renderedCellValue} - - ); + return {renderedCellValue}; }, Header: ({ column }) => {column.columnDef.header}, Filter: ({ column }) => { @@ -147,6 +145,7 @@ function DashboardMachinaryOfficeComponent() { enableColumnFilter: true, datatype: "numeric", filterFn: "equals", + maxSize: 100, columnFilterModeOptions: [ "equals", "notEquals", diff --git a/src/components/dashboard/passenger-boss/index.jsx b/src/components/dashboard/passenger-boss/index.jsx index c39322d..444e405 100644 --- a/src/components/dashboard/passenger-boss/index.jsx +++ b/src/components/dashboard/passenger-boss/index.jsx @@ -26,6 +26,7 @@ function DashboardPassengerOfficeComponent() { enableColumnFilter: true, datatype: "numeric", filterFn: "equals", + maxSize: 100, columnFilterModeOptions: [ "equals", "notEquals", @@ -96,13 +97,10 @@ function DashboardPassengerOfficeComponent() { enableColumnFilter: true, datatype: "date", filterFn: "lessThan", + minSize: 200, columnFilterModeOptions: ["lessThan", "greaterThan"], Cell: ({ renderedCellValue }) => { - return ( - - {renderedCellValue} - - ); + return {renderedCellValue}; }, Header: ({ column }) => {column.columnDef.header}, Filter: ({ column }) => { @@ -149,6 +147,7 @@ function DashboardPassengerOfficeComponent() { enableColumnFilter: true, datatype: "numeric", filterFn: "equals", + maxSize: 100, columnFilterModeOptions: [ "equals", "notEquals", diff --git a/src/components/dashboard/passenger-office/index.jsx b/src/components/dashboard/passenger-office/index.jsx index 0452e08..2694501 100644 --- a/src/components/dashboard/passenger-office/index.jsx +++ b/src/components/dashboard/passenger-office/index.jsx @@ -25,6 +25,7 @@ function DashboardPassengerOfficeComponent() { header: t("PassengerOffice.id"), enableColumnFilter: true, datatype: "numeric", + maxSize: 100, filterFn: "equals", columnFilterModeOptions: [ "equals", @@ -96,13 +97,10 @@ function DashboardPassengerOfficeComponent() { enableColumnFilter: true, datatype: "date", filterFn: "lessThan", + minSize: 200, columnFilterModeOptions: ["lessThan", "greaterThan"], Cell: ({ renderedCellValue }) => { - return ( - - {renderedCellValue} - - ); + return {renderedCellValue}; }, Header: ({ column }) => {column.columnDef.header}, Filter: ({ column }) => { @@ -148,6 +146,7 @@ function DashboardPassengerOfficeComponent() { header: t("PassengerOffice.navgan_id"), enableColumnFilter: true, datatype: "numeric", + maxSize: 100, filterFn: "equals", columnFilterModeOptions: [ "equals", diff --git a/src/components/dashboard/province-manager/Form/ConfirmForm.jsx b/src/components/dashboard/province-manager/Form/ConfirmForm.jsx new file mode 100644 index 0000000..b2ef723 --- /dev/null +++ b/src/components/dashboard/province-manager/Form/ConfirmForm.jsx @@ -0,0 +1,128 @@ +import { CONFIRM_PROVINCE_MANAGER } from "@/core/data/apiRoutes"; +import { + Dialog, + DialogTitle, + DialogContent, + DialogContentText, + DialogActions, + Button, + TextField, + FormHelperText, +} from "@mui/material"; +import { useFormik } from "formik"; +import { useTranslations } from "next-intl"; +import { useRef, useState } from "react"; +const MAX_FILE_SIZE_IN_BYTES = 2 * 1024 * 1024; + +const ConfirmForm = ({ open, handleClose, rowId, confirmData }) => { + const t = useTranslations(); + const [description, setDescription] = useState(""); + const [fileData, setFileData] = useState(null); + const inputRef = useRef(null); + + const formik = useFormik({ + initialValues: { + description: "", + fileData: null, + }, + onSubmit: () => { + const formData = new FormData(); + if (description !== "") + formData.append("expert_description", description); + if (fileData !== null) formData.append("file", fileData); + handleClose(); + confirmData(CONFIRM_PROVINCE_MANAGER, rowId, formData); + }, + }); + + const handleUploadClick = () => { + // 👇 We redirect the click event onto the hidden input element + inputRef.current?.click(); + }; + + const handleDescriptionChange = (event) => { + setDescription(event.target.value); + formik.handleChange(event); + }; + + const handleFileChange = (e) => { + const selectedFile = e.target.files[0]; + if (selectedFile) { + const fileSizeInBytes = selectedFile.size; + if (fileSizeInBytes > MAX_FILE_SIZE_IN_BYTES) { + formik.setFieldError( + "fileData", + `File size exceeds the limit (${MAX_FILE_SIZE_IN_BYTES / 1000000} MB)` + ); + e.target.value = null; + } else { + setFileData(selectedFile); + formik.setFieldValue("fileData", selectedFile); + formik.setFieldError("fileData", ""); + } + } + }; + + return ( + + {t("ConfirmDialog.confirm")} + + {t("ConfirmDialog.context")} + + + + + {fileData ? ( + <> + Name : {fileData.name} + + Size : {fileData.size} + > + ) : ( + <>{t("ConfirmDialog.choose_file")}> + )} + + + + + + {formik.errors.fileData && formik.errors.fileData} + + + + + {t("ConfirmDialog.button-confirm")} + + + {t("ConfirmDialog.button-cancel")} + + + + ); +}; +export default ConfirmForm; diff --git a/src/components/dashboard/province-manager/Form/RejectForm.jsx b/src/components/dashboard/province-manager/Form/RejectForm.jsx new file mode 100644 index 0000000..53f3c62 --- /dev/null +++ b/src/components/dashboard/province-manager/Form/RejectForm.jsx @@ -0,0 +1,76 @@ +import { REJECT_PROVINCE_MANAGER } from "@/core/data/apiRoutes"; +import { + Dialog, + DialogTitle, + DialogContent, + DialogContentText, + DialogActions, + Button, + TextField, +} from "@mui/material"; +import { useTranslations } from "next-intl"; +import { useFormik } from "formik"; +import * as Yup from "yup"; +import { useState } from "react"; + +const RejectForm = ({ open, handleClose, rowId, rejectData }) => { + const t = useTranslations(); + const [description, setDescription] = useState(""); + + const validationSchema = Yup.object().shape({ + description: Yup.string().required(t("RejectDialog.description_error")), + }); + + const formik = useFormik({ + initialValues: { + description: "", + }, + validationSchema, + onSubmit: () => { + const formData = new FormData(); + formData.append("expert_description", description); + handleClose(); + rejectData(REJECT_PROVINCE_MANAGER, rowId, formData); + }, + }); + + const handleDescriptionChange = (event) => { + setDescription(event.target.value); + formik.handleChange(event); + }; + + return ( + + {t("RejectDialog.reject")} + + {t("RejectDialog.context")} + + + + + {t("RejectDialog.button-reject")} + + + {t("RejectDialog.button-cancel")} + + + + ); +}; + +export default RejectForm; diff --git a/src/components/dashboard/province-manager/TableRowActions.jsx b/src/components/dashboard/province-manager/TableRowActions.jsx new file mode 100644 index 0000000..e9e815e --- /dev/null +++ b/src/components/dashboard/province-manager/TableRowActions.jsx @@ -0,0 +1,54 @@ +import ThumbUpAltIcon from "@mui/icons-material/ThumbUpAlt"; +import ThumbDownIcon from "@mui/icons-material/ThumbDown"; +import { Box, IconButton } from "@mui/material"; +import { useContext } from "react"; +import { DataTableContext } from "@/lib/app/contexts/DataTableContext"; +import ConfirmForm from "./Form/ConfirmForm"; +import RejectForm from "./Form/RejectForm"; + +const TableRowActions = ({ row }) => { + const { + openConfirmDialog, + openRejectDialog, + handleOpenConfirmDialog, + handleOpenRejectDialog, + handleCloseConfirmDialog, + handleCloseRejectDialog, + rowId, + confirmData, + rejectData, + } = useContext(DataTableContext); + return ( + + { + handleOpenConfirmDialog(row); + }} + > + + + {openConfirmDialog && ( + + )} + handleOpenRejectDialog(row)}> + + + {openRejectDialog && ( + + )} + + ); +}; + +export default TableRowActions; diff --git a/src/components/dashboard/province-manager/TableTollbar.jsx b/src/components/dashboard/province-manager/TableTollbar.jsx new file mode 100644 index 0000000..3f06d3b --- /dev/null +++ b/src/components/dashboard/province-manager/TableTollbar.jsx @@ -0,0 +1,13 @@ +import { Stack, Tooltip } from "@mui/material"; +import { useTranslations } from "next-intl"; + +function TableToolbar() { + const t = useTranslations(); + return ( + + + + ); +} + +export default TableToolbar; diff --git a/src/components/dashboard/province-manager/index.jsx b/src/components/dashboard/province-manager/index.jsx new file mode 100644 index 0000000..71d2e96 --- /dev/null +++ b/src/components/dashboard/province-manager/index.jsx @@ -0,0 +1,217 @@ +import DataTableStructure from "@/core/components/DatatableStructure"; +import DashboardLayouts from "@/layouts/dashboardLayouts"; +import { Box, Typography } from "@mui/material"; +import { useMemo } from "react"; +// import TableToolbar from "./TableTollbar"; +import { GET_PROVINCE_MANAGER } from "@/core/data/apiRoutes"; +import { useTranslations } from "next-intl"; +import TableRowActions from "./TableRowActions"; +import { format } from "date-fns-jalali"; +import { + LocalizationProvider, + MobileDateTimePicker, +} from "@mui/x-date-pickers"; +import { AdapterDateFnsJalali } from "@mui/x-date-pickers/AdapterDateFnsJalali"; +import moment from "moment"; + +function DashboardProvinceManagerComponent() { + const t = useTranslations(); + + const columns = useMemo( + () => [ + { + accessorFn: (row) => row.id, + id: "id", + header: t("ProvinceManager.id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + maxSize: 100, + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({ renderedCellValue }) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.name, + id: "name", + header: t("ProvinceManager.name"), + enableColumnFilter: true, + datatype: "text", + filterFn: "contains", + columnFilterModeOptions: ["contains", "equals", "notEquals"], + Cell: ({ renderedCellValue }) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.national_id, + id: "national_id", + header: t("ProvinceManager.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("ProvinceManager.phone_number"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({ renderedCellValue }) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => + format(new Date(row.created_at), "HH:mm | yyyy/mm/dd"), + id: "created_at", + header: t("ProvinceManager.created_at"), + enableColumnFilter: true, + datatype: "date", + filterFn: "lessThan", + minSize: 200, + columnFilterModeOptions: ["lessThan", "greaterThan"], + Cell: ({ renderedCellValue }) => { + return {renderedCellValue}; + }, + Header: ({ column }) => {column.columnDef.header}, + Filter: ({ column }) => { + return ( + + { + const date = new Date(newValue); + const formattedDate = moment(date) + .locale("en") + .format("YYYY-MM-DD HH:mm"); + column.setFilterValue(formattedDate); + }} + slotProps={{ + textField: { + helperText: `Filter Mode: ${column.columnDef._filterFn}`, + sx: { minWidth: "120px" }, + variant: "standard", + }, + }} + value={moment(column.getFilterValue()) + .locale("fa") + .format("yyyy/mm/dd HH:mm")} + /> + + ); + }, + }, + { + accessorFn: (row) => + format(new Date(row.updated_at), "HH:mm | yyyy/mm/dd"), + id: "updated_at", + header: t("ProvinceManager.updated_at"), + enableColumnFilter: false, + datatype: "numeric", + Cell: ({ renderedCellValue }) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.navgan_id, + id: "navgan_id", + header: t("ProvinceManager.navgan_id"), + enableColumnFilter: true, + datatype: "numeric", + filterFn: "equals", + maxSize: 100, + columnFilterModeOptions: [ + "equals", + "notEquals", + "contains", + "lessThan", + "greaterThan", + "between", + ], + Cell: ({ renderedCellValue }) => ( + {renderedCellValue} + ), + }, + { + accessorFn: (row) => row.vehicle_type, + id: "vehicle_type", + header: t("ProvinceManager.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("ProvinceManager.state_name"), + enableColumnFilter: false, + datatype: "numeric", + // filterFn: "equals", + // filterSelectOptions: [ + // ], + // filterVariant: "select", + Cell: ({ renderedCellValue }) => ( + {renderedCellValue} + ), + }, + ], + [] + ); + return ( + + + } + enableLastUpdate={true} + enablePinning={true} + enableDensityToggle={true} + enableColumnFilters={true} + enableHiding={true} + enableFullScreenToggle={false} + enableGlobalFilter={false} + enableColumnResizing={false} // if you want true this you shold change renderRowActions props ** see https://www.material-react-table.com/docs/guides/row-actions + enableRowActions={true} + renderRowActions={({ row }) => } + /> + + + ); +} + +export default DashboardProvinceManagerComponent; diff --git a/src/components/dashboard/transportation-assistance/index.jsx b/src/components/dashboard/transportation-assistance/index.jsx index 3b6b630..0984d8b 100644 --- a/src/components/dashboard/transportation-assistance/index.jsx +++ b/src/components/dashboard/transportation-assistance/index.jsx @@ -24,6 +24,7 @@ function DashboardTransportationAssistanceComponent() { enableColumnFilter: true, datatype: "numeric", filterFn: "equals", + maxSize: 100, columnFilterModeOptions: [ "equals", "notEquals", @@ -94,12 +95,11 @@ function DashboardTransportationAssistanceComponent() { header: t("TransportationAssistance.created_at"), enableColumnFilter: true, datatype: "date", + minSize: 200, filterFn: "lessThan", columnFilterModeOptions: ["lessThan", "greaterThan"], Cell: ({ renderedCellValue }) => ( - - {renderedCellValue} - + {renderedCellValue} ), Header: ({ column }) => {column.columnDef.header}, Filter: ({ column }) => { @@ -146,6 +146,7 @@ function DashboardTransportationAssistanceComponent() { enableColumnFilter: true, datatype: "numeric", filterFn: "equals", + maxSize: 100, columnFilterModeOptions: [ "equals", "notEquals", diff --git a/src/core/components/Datatable.jsx b/src/core/components/Datatable.jsx index 04be089..2d34ece 100644 --- a/src/core/components/Datatable.jsx +++ b/src/core/components/Datatable.jsx @@ -44,7 +44,6 @@ const DataTable = (props) => { const [sorting, setSorting] = useState([]); const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 }); const [rowCount, setRowCount] = useState(0); - console.log(moment()); const [updateTime, setupdateTime] = useState( moment().format("HH:mm | jYYYY/jM/jD") ); diff --git a/src/core/data/apiRoutes.js b/src/core/data/apiRoutes.js index eb28399..2c84765 100644 --- a/src/core/data/apiRoutes.js +++ b/src/core/data/apiRoutes.js @@ -55,3 +55,14 @@ export const CONFIRM_MACHINARY_OFFICE = export const REJECT_MACHINARY_OFFICE = BASE_URL + "/dashboard/machinery_expert/reject"; //passenger office + +//province manager +export const GET_PROVINCE_MANAGER = + BASE_URL + "/dashboard/province_manager/show"; + +export const CONFIRM_PROVINCE_MANAGER = + BASE_URL + "/dashboard/province_manager/confirm"; + +export const REJECT_PROVINCE_MANAGER = + BASE_URL + "/dashboard/province_manager/reject"; +//province manager diff --git a/src/core/data/sidebarMenu.jsx b/src/core/data/sidebarMenu.jsx index cf2aacb..f452edf 100644 --- a/src/core/data/sidebarMenu.jsx +++ b/src/core/data/sidebarMenu.jsx @@ -47,12 +47,12 @@ const sidebarMenu = [ role: "transportation-assistance", }, { - key: "sidebar.manager", + key: "sidebar.province-manager", type: "page", - route: "/dashboard/manager", + route: "/dashboard/province-manager", icon: , selected: false, - role: "manager", + role: "province-manager", }, ], ]; diff --git a/src/pages/dashboard/passenger-boss/index.jsx b/src/pages/dashboard/passenger-boss/index.jsx index 961d766..ea0566a 100644 --- a/src/pages/dashboard/passenger-boss/index.jsx +++ b/src/pages/dashboard/passenger-boss/index.jsx @@ -6,7 +6,7 @@ import { parse } from "next-useragent"; export default function PassengerBoss() { return ( - + ); diff --git a/src/pages/dashboard/province-manager/index.jsx b/src/pages/dashboard/province-manager/index.jsx new file mode 100644 index 0000000..7fbc181 --- /dev/null +++ b/src/pages/dashboard/province-manager/index.jsx @@ -0,0 +1,23 @@ +import DashboardProvinceManagerComponent from "@/components/dashboard/province-manager"; +import TitlePage from "@/core/components/TitlePage"; +import WithAuthMiddleware from "@/middlewares/WithAuth"; +import { parse } from "next-useragent"; + +export default function PassengerOffice() { + return ( + + + + + ); +} + +export async function getServerSideProps({ req, locale }) { + const { isBot } = parse(req.headers["user-agent"]); + return { + props: { + messages: (await import(`&/locales/${locale}/app.json`)).default, + isBot, + }, + }; +}