From caaff22c666452e58fd797186dbcc2686bbdaa9a Mon Sep 17 00:00:00 2001 From: AminGhasempoor Date: Sun, 14 Jun 2026 09:56:03 +0330 Subject: [PATCH 1/4] machine type report completed --- .../reports/machineTypeReports/page.js | 18 +++ .../machinesTypeReports/ExcelPrint/index.jsx | 79 +++++++++++++ .../MachinesReportsList.jsx | 61 ++++++++++ .../MachineMissionsList/index.jsx | 106 +++++++++++++++++ .../RowActions/MissionDitails/Form/index.jsx | 27 +++++ .../RowActions/MissionDitails/index.jsx | 47 ++++++++ .../RowActions/RouteDetail/ShowRoute.jsx | 46 ++++++++ .../RowActions/RouteDetail/index.jsx | 57 +++++++++ .../machinesTypeReports/RowActions/index.jsx | 10 ++ .../Search/FromDateController.jsx | 27 +++++ .../Search/SearchReportField.jsx | 44 +++++++ .../Search/SelectProvince.jsx | 45 +++++++ .../Search/ToDateController.jsx | 30 +++++ .../machinesTypeReports/Search/index.jsx | 13 +++ .../reports/machinesTypeReports/Toolbar.jsx | 11 ++ .../reports/machinesTypeReports/index.jsx | 110 ++++++++++++++++++ src/core/utils/pageMenu.js | 12 +- src/core/utils/pageMenuDev.js | 12 +- src/core/utils/routes.js | 9 ++ 19 files changed, 762 insertions(+), 2 deletions(-) create mode 100644 src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/machineTypeReports/page.js create mode 100644 src/components/dashboard/roadMissions/reports/machinesTypeReports/ExcelPrint/index.jsx create mode 100644 src/components/dashboard/roadMissions/reports/machinesTypeReports/MachinesReportsList.jsx create mode 100644 src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/MissionDitails/Form/MachineMissionsDetailsDialog/MachineMissionsList/index.jsx create mode 100644 src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/MissionDitails/Form/index.jsx create mode 100644 src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/MissionDitails/index.jsx create mode 100644 src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/RouteDetail/ShowRoute.jsx create mode 100644 src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/RouteDetail/index.jsx create mode 100644 src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/index.jsx create mode 100644 src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/FromDateController.jsx create mode 100644 src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/SearchReportField.jsx create mode 100644 src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/SelectProvince.jsx create mode 100644 src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/ToDateController.jsx create mode 100644 src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/index.jsx create mode 100644 src/components/dashboard/roadMissions/reports/machinesTypeReports/Toolbar.jsx create mode 100644 src/components/dashboard/roadMissions/reports/machinesTypeReports/index.jsx diff --git a/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/machineTypeReports/page.js b/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/machineTypeReports/page.js new file mode 100644 index 0000000..e8725f1 --- /dev/null +++ b/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/machineTypeReports/page.js @@ -0,0 +1,18 @@ +import WithPermission from "@/core/middlewares/withPermission"; +import MachinesTypeReportsPage from "@/components/dashboard/roadMissions/reports/machinesTypeReports"; + +export const metadata = { + title: "کارتابل گزارش نوع ماشین‌ها", +}; + +export default function Page() { + return ( + + + + ); +} diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/ExcelPrint/index.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/ExcelPrint/index.jsx new file mode 100644 index 0000000..c105b97 --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/ExcelPrint/index.jsx @@ -0,0 +1,79 @@ +"use client"; +import { + EXPORT_GET_MACHINES_COUNTRY_ACTIVITY_REPORT, + EXPORT_GET_MACHINES_PROVINCE_ACTIVITY_REPORT, + EXPORT_GET_MACHINES_TYPE_COUNTRY_ACTIVITY_REPORT, + EXPORT_GET_MACHINES_TYPE_PROVINCE_ACTIVITY_REPORT, +} from "@/core/utils/routes"; +import useRequest from "@/lib/hooks/useRequest"; +import { useTheme } from "@emotion/react"; +import DescriptionIcon from "@mui/icons-material/Description"; +import { Button, CircularProgress, IconButton, useMediaQuery } from "@mui/material"; +import FileSaver from "file-saver"; +import moment from "jalali-moment"; +import { useMemo, useState } from "react"; + +const PrintExcel = ({ table, filterData }) => { + const theme = useTheme(); + const isMobile = useMediaQuery(theme.breakpoints.down("sm")); + const [loading, setLoading] = useState(false); + const requestServer = useRequest({ notificationSuccess: true }); + const activeFilters = Object.entries(filterData).reduce((acc, [key, filter]) => { + if (filter.value) { + acc.push({ id: filter.id, value: filter.value }); + } + return acc; + }, []); + + const filterParams = useMemo(() => { + const params = new URLSearchParams(); + activeFilters.length > 0 && + activeFilters.map((filter, index) => { + params.set(`${filter.id}`, filter.value); + }); + return params; + }, [activeFilters]); + + const clickHandler = () => { + setLoading(true); + const CountryOrProvince = activeFilters.find((item) => item.id === "province_id"); + const requestUrl = + CountryOrProvince.value === "-1" + ? EXPORT_GET_MACHINES_TYPE_COUNTRY_ACTIVITY_REPORT + : EXPORT_GET_MACHINES_TYPE_PROVINCE_ACTIVITY_REPORT; + requestServer(`${requestUrl}?${filterParams}`, "get", { + requestOptions: { responseType: "blob" }, + }) + .then((response) => { + const filename = `خروجی کارتابل گزارشات گشت راهداری تاریخ_${moment().format("jYYYY_jMM_jDD")}.xlsx`; + FileSaver.saveAs(response.data, filename); + }) + .catch(() => {}) + .finally(() => { + setLoading(false); + }); + }; + + return ( + <> + {isMobile ? ( + + + + ) : ( + + )} + + ); +}; +export default PrintExcel; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/MachinesReportsList.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/MachinesReportsList.jsx new file mode 100644 index 0000000..5fb261d --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/MachinesReportsList.jsx @@ -0,0 +1,61 @@ +"use client"; +import DataTableWithAuth from "@/core/components/DataTableWithAuth"; +import { Box } from "@mui/material"; +import { useMemo } from "react"; +import Toolbar from "./Toolbar"; +// import RowActions from "./RowActions"; + +const MachinesReportsList = ({ data, specialFilter }) => { + const columns = useMemo(() => { + return [ + { + accessorKey: "car_type", + header: "نوع ماشین", + id: "car_type", + enableColumnFilter: false, + enableSorting: false, + datatype: "text", + grow: false, + size: 50, + }, + { + accessorKey: "func", + header: "کارکرد", + id: "func", + enableColumnFilter: false, + enableSorting: false, + datatype: "number", + grow: false, + size: 50, + }, + { + accessorKey: "missions", + header: "تعداد ماموریت", + id: "missions", + enableColumnFilter: false, + enableSorting: false, + datatype: "number", + grow: false, + size: 50, + }, + ]; + }, []); + + return ( + + + + ); +}; + +export default MachinesReportsList; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/MissionDitails/Form/MachineMissionsDetailsDialog/MachineMissionsList/index.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/MissionDitails/Form/MachineMissionsDetailsDialog/MachineMissionsList/index.jsx new file mode 100644 index 0000000..ada49f4 --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/MissionDitails/Form/MachineMissionsDetailsDialog/MachineMissionsList/index.jsx @@ -0,0 +1,106 @@ +import DataTableWithAuth from "@/core/components/DataTableWithAuth"; +import { GET_MACHINE_MISSIONS_DETAILS, GET_MACHINE_TYPE_MISSIONS_DETAILS } from "@/core/utils/routes"; +import { Box } from "@mui/material"; +import { useMemo } from "react"; + +const MachineMissionsList = ({ row }) => { + const columns = useMemo( + () => [ + { + accessorKey: "id", + header: "کد یکتا", + id: "id", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 80, + }, + { + accessorKey: "province_name", + header: "استان", + id: "province_name", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "city_name", + header: "شهر", + id: "city_name", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "station_name", + header: "راهدارخانه", + id: "station_name", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "driver_name", + header: "راننده", + id: "driver_name", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "km", + header: "کیلومتر شروع", + id: "km", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "end_km", + header: "کیلومتر پایان", + id: "end_km", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + ], + [] + ); + + return ( + <> + + + + + ); +}; +export default MachineMissionsList; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/MissionDitails/Form/index.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/MissionDitails/Form/index.jsx new file mode 100644 index 0000000..5e79bfa --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/MissionDitails/Form/index.jsx @@ -0,0 +1,27 @@ +import { Box, Button, DialogActions, DialogContent } from "@mui/material"; +import { Stack } from "@mui/system"; +import MachineMissionsList from "./MachineMissionsDetailsDialog/MachineMissionsList"; + +const MachineMissionsDetailsTable = ({ row, setOpenMachineMissionsDetails }) => { + return ( + <> + + + + + + + + + + + + + + + + ); +}; +export default MachineMissionsDetailsTable; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/MissionDitails/index.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/MissionDitails/index.jsx new file mode 100644 index 0000000..21a8263 --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/MissionDitails/index.jsx @@ -0,0 +1,47 @@ +import { Close, RemoveRedEye } from "@mui/icons-material"; +import { Dialog, DialogTitle, IconButton, Tooltip } from "@mui/material"; +import { useState } from "react"; +import MachineMissionsDetailsTable from "./Form"; + +const MissionDetails = ({ row }) => { + const [openMachineMissionsDetails, setOpenMachineMissionsDetails] = useState(false); + + return ( + <> + + { + setOpenMachineMissionsDetails(true); + }} + > + + + + + setOpenMachineMissionsDetails(false)} + sx={(theme) => ({ + position: "absolute", + right: 8, + top: 8, + zIndex: 50, + color: theme.palette.grey[500], + })} + > + + + ریز گزارشات نوع خودرو + {openMachineMissionsDetails && ( + + )} + + + ); +}; +export default MissionDetails; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/RouteDetail/ShowRoute.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/RouteDetail/ShowRoute.jsx new file mode 100644 index 0000000..5e1a4bd --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/RouteDetail/ShowRoute.jsx @@ -0,0 +1,46 @@ +import { useEffect, useRef } from "react"; +import { Marker, Polyline, useMap } from "react-leaflet"; +import L from "leaflet"; +import polyline from "@mapbox/polyline"; +import SourceIcon from "@/assets/images/source-icon.svg"; +import DestIcon from "@/assets/images/destination-icon.svg"; + +const ShowRoute = ({ area }) => { + const map = useMap(); + const defaultIconSize = [35, 35]; + + const createCustomIcon = (size, iconUrl) => { + return L.icon({ + iconUrl: iconUrl, + iconSize: size, + iconAnchor: [size[0] / 2, size[1]], + popupAnchor: [0, -size[1]], + }); + }; + + useEffect(() => { + if (coords.length > 0) { + map.flyToBounds(coords, { padding: [50, 50], duration: 1.5 }); + } + }, [area]); + const sourceIcon = createCustomIcon(defaultIconSize, SourceIcon.src); + const destIcon = createCustomIcon(defaultIconSize, DestIcon.src); + + if (!area) return null; + const coords = polyline.decode(area, 6); + + if (coords.length === 0) return null; + + const sourcePosition = coords[0]; + const destPosition = coords[coords.length - 1]; + + return ( + <> + + + + + ); +}; + +export default ShowRoute; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/RouteDetail/index.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/RouteDetail/index.jsx new file mode 100644 index 0000000..4501d35 --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/RouteDetail/index.jsx @@ -0,0 +1,57 @@ +import { Box, Button, Dialog, DialogActions, DialogTitle, IconButton, Tooltip } from "@mui/material"; +import { useState } from "react"; +import MapIcon from "@mui/icons-material/Map"; +import MapLayer from "@/core/components/MapLayer"; +import ShowRoute from "./ShowRoute"; + +const RouteDetail = ({ encoded_route }) => { + const [openRouteDetailDialog, setOpenRouteDetailDialog] = useState(false); + return ( + <> + + setOpenRouteDetailDialog(true)}> + + + + setOpenRouteDetailDialog(false)} + PaperProps={{ + sx: { + boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px", + }, + }} + dir="rtl" + maxWidth={"sm"} + > + مسیر انتخابی + + + + + + + + + + + + + ); +}; +export default RouteDetail; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/index.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/index.jsx new file mode 100644 index 0000000..2690157 --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/index.jsx @@ -0,0 +1,10 @@ +// import MissionDetails from "./MissionDitails"; + +const RowActions = ({ row }) => { + return ( + <> + {/**/} + + ); +}; +export default RowActions; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/FromDateController.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/FromDateController.jsx new file mode 100644 index 0000000..490ee7b --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/FromDateController.jsx @@ -0,0 +1,27 @@ +import MuiDatePicker from "@/core/components/MuiDatePicker"; +import moment from "jalali-moment"; +import { Controller } from "react-hook-form"; + +const FromDateController = ({ control }) => { + return ( + ( + { + const formattedDate = moment(new Date(newValue)).locale("en").format("YYYY-MM-DD"); + onChange(formattedDate); // Update the field value in react-hook-form + }} + helperText={error ? error.message : null} + /> + )} + /> + ); +}; +export default FromDateController; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/SearchReportField.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/SearchReportField.jsx new file mode 100644 index 0000000..bde2a4c --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/SearchReportField.jsx @@ -0,0 +1,44 @@ +import SearchIcon from "@mui/icons-material/Search"; +import { Button, Grid } from "@mui/material"; +import { Controller } from "react-hook-form"; +import FromDateController from "./FromDateController"; +import SelectProvince from "./SelectProvince"; +import ToDateController from "./ToDateController"; + +const SearchReportField = ({ control, hasProvincesPermission }) => { + return ( + + + + + + + + {hasProvincesPermission && ( + + + + )} + + ( + + )} + /> + + + ); +}; + +export default SearchReportField; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/SelectProvince.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/SelectProvince.jsx new file mode 100644 index 0000000..2b24d67 --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/SelectProvince.jsx @@ -0,0 +1,45 @@ +import useProvinces from "@/lib/hooks/useProvince"; +import { FormControl, FormHelperText, InputLabel, MenuItem, Select } from "@mui/material"; +import { Controller } from "react-hook-form"; + +const SelectProvince = ({ control }) => { + const { provinces, loadingProvinces, errorProvinces } = useProvinces(); + return ( + ( + + استان + + {error && {error.message}} + + )} + /> + ); +}; +export default SelectProvince; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/ToDateController.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/ToDateController.jsx new file mode 100644 index 0000000..fc4a776 --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/ToDateController.jsx @@ -0,0 +1,30 @@ +import MuiDatePicker from "@/core/components/MuiDatePicker"; +import moment from "jalali-moment"; +import { Controller, useWatch } from "react-hook-form"; + +const ToDateController = ({ control }) => { + const minDate = useWatch({ control, name: "from_date" }); + return ( + ( + { + const formattedDate = moment(new Date(newValue)).locale("en").format("YYYY-MM-DD"); + onChange(formattedDate); // Update the field value in react-hook-form + }} + helperText={error ? error.message : null} + /> + )} + /> + ); +}; +export default ToDateController; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/index.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/index.jsx new file mode 100644 index 0000000..f29d302 --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/index.jsx @@ -0,0 +1,13 @@ +import StyledForm from "@/core/components/StyledForm"; +import SearchReportField from "./SearchReportField"; + +const SearchReportList = ({ handleSubmit, onSearchSubmit, control, hasProvincesPermission }) => { + return ( + <> + + + + + ); +}; +export default SearchReportList; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/Toolbar.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/Toolbar.jsx new file mode 100644 index 0000000..0f726c7 --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/Toolbar.jsx @@ -0,0 +1,11 @@ +import { Box } from "@mui/material"; +import PrintExcel from "./ExcelPrint"; + +const Toolbar = ({ table, filterData, mutate }) => { + return ( + + + + ); +}; +export default Toolbar; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/index.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/index.jsx new file mode 100644 index 0000000..add1f5c --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/index.jsx @@ -0,0 +1,110 @@ +"use client"; +import PageTitle from "@/core/components/PageTitle"; +import { + GET_MACHINES_TYPE_COUNTRY_ACTIVITY_REPORT, + GET_MACHINES_TYPE_PROVINCE_ACTIVITY_REPORT, +} from "@/core/utils/routes"; +import { useAuth } from "@/lib/contexts/auth"; +import { usePermissions } from "@/lib/hooks/usePermissions"; +import useRequest from "@/lib/hooks/useRequest"; +import { yupResolver } from "@hookform/resolvers/yup"; +import { LinearProgress, Stack } from "@mui/material"; +import moment from "jalali-moment"; +import { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import * as yup from "yup"; +import MachinesReportsList from "./MachinesReportsList"; +import SearchReportList from "./Search"; + +const MachinesTypeReportsPage = () => { + const [data, setData] = useState(null); + const { data: userPermissions } = usePermissions(); + const { user } = useAuth(); + const requestServer = useRequest(); + const hasProvincesPermission = userPermissions?.includes("mission-report-country"); + + const defaultValues = { + from_date: moment(new Date()).format("YYYY-MM-DD"), + date_to: moment(new Date()).format("YYYY-MM-DD"), + province_id: user.province_id || "-1", + }; + const defaultFilter = [ + { value: `${defaultValues.province_id}`, datatype: "numeric", id: "province_id", fn: "equals" }, + { value: `${defaultValues.from_date}`, datatype: "date", id: "from_date", fn: "between" }, + { value: `${defaultValues.date_to}`, datatype: "date", id: "date_to", fn: "between" }, + ]; + const [specialFilter, setSpecialFilter] = useState(defaultFilter); + + const onSearchSubmit = async (data) => { + const params = new URLSearchParams(); + params.set("from_date", `${data.from_date} 00:00:00`); + params.set("date_to", `${data.date_to} 23:59:59`); + setSpecialFilter([ + { value: `${data.province_id}`, datatype: "numeric", id: "province_id", fn: "equals" }, + { value: `${data.from_date}`, datatype: "date", id: "from_date", fn: "between" }, + { value: `${data.date_to}`, datatype: "date", id: "date_to", fn: "between" }, + ]); + if (data.province_id === "-1") { + try { + const response = await requestServer(`${GET_MACHINES_TYPE_COUNTRY_ACTIVITY_REPORT}?${params}`); + const result = response.data.data; + + setData({ + data: result.activities, + filters: data, + }); + } catch (e) {} + } else { + try { + params.set("province_id", `${data.province_id}`); + const response = await requestServer(`${GET_MACHINES_TYPE_PROVINCE_ACTIVITY_REPORT}?${params}`); + + const result = response.data.data; + + setData({ + data: result.activities, + filters: data, + }); + } catch (e) {} + } + }; + + useEffect(() => { + if (!userPermissions) return; + onSearchSubmit(defaultValues); + }, [userPermissions]); + + const validationSchema = yup.object().shape({ + from_date: yup + .string() + .required("تاریخ شروع الزامی است!") + .matches(/^\d{4}-\d{2}-\d{2}$/, "تاریخ شروع الزامی است!") + .test("is-valid-date", "تاریخ شروع معتبر نیست!", (value) => moment(value, "YYYY-MM-DD", true).isValid()), + date_to: yup + .string() + .required("تاریخ پایان الزامی است!") + .matches(/^\d{4}-\d{2}-\d{2}$/, "تاریخ پایان الزامی است!") + .test("is-valid-date", "تاریخ پایان معتبر نیست!", (value) => moment(value, "YYYY-MM-DD", true).isValid()), + province_id: yup.string().nullable(), + }); + + const { control, handleSubmit } = useForm({ + defaultValues, + resolver: yupResolver(validationSchema), + mode: "all", + }); + + return ( + + + + {!data ? : } + + ); +}; +export default MachinesTypeReportsPage; diff --git a/src/core/utils/pageMenu.js b/src/core/utils/pageMenu.js index bd24701..703c244 100644 --- a/src/core/utils/pageMenu.js +++ b/src/core/utils/pageMenu.js @@ -1,4 +1,4 @@ -import { ReportProblem, RvHookup } from "@mui/icons-material"; +import { DriveEtaOutlined, ReportProblem, RvHookup } from "@mui/icons-material"; import AccountTreeIcon from "@mui/icons-material/AccountTree"; import AdminPanelSettingsIcon from "@mui/icons-material/AdminPanelSettings"; import AssessmentIcon from "@mui/icons-material/Assessment"; @@ -34,6 +34,7 @@ import SecurityIcon from "@mui/icons-material/Security"; import SpaceDashboardIcon from "@mui/icons-material/SpaceDashboard"; import SpeedIcon from "@mui/icons-material/Speed"; import SupervisedUserCircleIcon from "@mui/icons-material/SupervisedUserCircle"; +import TaxiAlertIcon from "@mui/icons-material/TaxiAlert"; export const pageMenu = [ { @@ -201,6 +202,15 @@ export const pageMenu = [ badges: [{ key: "mission.request_portal" }], permissions: ["all"], }, + { + id: "machinesTypeReports", + label: "نوع ماشین‌ها", + icon: , + type: "page", + route: "/dashboard/road-missions/reports/machineTypeReports", + badges: [{ key: "mission.request_portal" }], + permissions: ["all"], + }, ], }, ], diff --git a/src/core/utils/pageMenuDev.js b/src/core/utils/pageMenuDev.js index ab888c7..e1c3a01 100644 --- a/src/core/utils/pageMenuDev.js +++ b/src/core/utils/pageMenuDev.js @@ -1,4 +1,4 @@ -import { Mediation, ReportProblem, RvHookup } from "@mui/icons-material"; +import { DriveEtaOutlined, Mediation, ReportProblem, RvHookup } from "@mui/icons-material"; import AccountTreeIcon from "@mui/icons-material/AccountTree"; import AdminPanelSettingsIcon from "@mui/icons-material/AdminPanelSettings"; import AssessmentIcon from "@mui/icons-material/Assessment"; @@ -31,6 +31,7 @@ import ScienceIcon from "@mui/icons-material/Science"; import SecurityIcon from "@mui/icons-material/Security"; import SpaceDashboardIcon from "@mui/icons-material/SpaceDashboard"; import SpeedIcon from "@mui/icons-material/Speed"; +import TaxiAlertIcon from "@mui/icons-material/TaxiAlert"; import SupervisedUserCircleIcon from "@mui/icons-material/SupervisedUserCircle"; export const pageMenuDev = [ @@ -199,6 +200,15 @@ export const pageMenuDev = [ badges: [{ key: "mission.request_portal" }], permissions: ["all"], }, + { + id: "machinesTypeReports", + label: "نوع ماشین‌ها", + icon: , + type: "page", + route: "/dashboard/road-missions/reports/machineTypeReports", + badges: [{ key: "mission.request_portal" }], + permissions: ["all"], + }, ], }, ], diff --git a/src/core/utils/routes.js b/src/core/utils/routes.js index 64c2bee..969e100 100644 --- a/src/core/utils/routes.js +++ b/src/core/utils/routes.js @@ -255,6 +255,14 @@ export const EXPORT_GET_MACHINES_COUNTRY_ACTIVITY_REPORT = api + "/api/v3/missions/report_machine/country_machines_activity_excel"; export const EXPORT_GET_MACHINES_PROVINCE_ACTIVITY_REPORT = api + "/api/v3/missions/report_machine/province_machines_activity_excel"; + +export const GET_MACHINES_TYPE_COUNTRY_ACTIVITY_REPORT = + api + "/api/v3/missions/report_machine/country_machine_types_activity"; +export const GET_MACHINES_TYPE_PROVINCE_ACTIVITY_REPORT = api + "/api/v3/missions/report_machine/province_machine_types_activity"; +export const EXPORT_GET_MACHINES_TYPE_COUNTRY_ACTIVITY_REPORT = + api + "/api/v3/missions/report_machine/country_machine_types_activity_excel"; +export const EXPORT_GET_MACHINES_TYPE_PROVINCE_ACTIVITY_REPORT = + api + "/api/v3/missions/report_machine/province_machine_types_activity_excel"; export const CREATE_VIOLATION = api + "/api/v3/missions/violation_management"; export const EDIT_VIOLATION = api + "/api/v3/missions/violation_management"; export const EXPORT_COUNTRY_ROAD_MISSIONS_REPORTS = api + "/api/v3/missions/report/country_excel_activity"; @@ -295,3 +303,4 @@ export const GET_CITIES_LIST = api + "/api/v3/cities/list"; export const GET_STATIONS_LIST = api + "/api/v3/road_maintenance_station"; export const UPDATE_MACHINE_STATUS_AND_LOCATION = api + "/api/v3/cmms_machines"; export const GET_MACHINE_MISSIONS_DETAILS = api + "/api/v3/missions/report_machine/machine_details_report"; +export const GET_MACHINE_TYPE_MISSIONS_DETAILS = api + "/api/v3/missions/report_machine/machine_type_details_report"; -- 2.49.1 From a80e35a510e2c5dcb80f3f84d4b87441be8268e2 Mon Sep 17 00:00:00 2001 From: AminGhasempoor Date: Sun, 14 Jun 2026 11:47:24 +0330 Subject: [PATCH 2/4] driver reports completed --- .../reports/driverReports/page.js | 18 +++ .../diverReports/DriverReportsList.jsx | 71 +++++++++++ .../reports/diverReports/ExcelPrint/index.jsx | 77 ++++++++++++ .../DriverDetailsDialog/DriverList/index.jsx | 106 +++++++++++++++++ .../RowActions/DriverDetails/Form/index.jsx | 27 +++++ .../RowActions/DriverDetails/index.jsx | 47 ++++++++ .../RowActions/RouteDetail/ShowRoute.jsx | 46 ++++++++ .../RowActions/RouteDetail/index.jsx | 57 +++++++++ .../reports/diverReports/RowActions/index.jsx | 6 + .../Search/FromDateController.jsx | 27 +++++ .../diverReports/Search/SearchReportField.jsx | 44 +++++++ .../diverReports/Search/SelectProvince.jsx | 45 +++++++ .../diverReports/Search/ToDateController.jsx | 30 +++++ .../reports/diverReports/Search/index.jsx | 13 +++ .../reports/diverReports/Toolbar.jsx | 11 ++ .../reports/diverReports/index.jsx | 110 ++++++++++++++++++ .../MachineMissionsList/index.jsx | 2 +- .../Actions/CreateViolation/Form/index.jsx | 2 +- .../Actions/EditViolation/EditController.jsx | 4 +- src/core/utils/pageMenu.js | 10 ++ src/core/utils/pageMenuDev.js | 10 ++ src/core/utils/routes.js | 8 ++ 22 files changed, 767 insertions(+), 4 deletions(-) create mode 100644 src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/driverReports/page.js create mode 100644 src/components/dashboard/roadMissions/reports/diverReports/DriverReportsList.jsx create mode 100644 src/components/dashboard/roadMissions/reports/diverReports/ExcelPrint/index.jsx create mode 100644 src/components/dashboard/roadMissions/reports/diverReports/RowActions/DriverDetails/Form/DriverDetailsDialog/DriverList/index.jsx create mode 100644 src/components/dashboard/roadMissions/reports/diverReports/RowActions/DriverDetails/Form/index.jsx create mode 100644 src/components/dashboard/roadMissions/reports/diverReports/RowActions/DriverDetails/index.jsx create mode 100644 src/components/dashboard/roadMissions/reports/diverReports/RowActions/RouteDetail/ShowRoute.jsx create mode 100644 src/components/dashboard/roadMissions/reports/diverReports/RowActions/RouteDetail/index.jsx create mode 100644 src/components/dashboard/roadMissions/reports/diverReports/RowActions/index.jsx create mode 100644 src/components/dashboard/roadMissions/reports/diverReports/Search/FromDateController.jsx create mode 100644 src/components/dashboard/roadMissions/reports/diverReports/Search/SearchReportField.jsx create mode 100644 src/components/dashboard/roadMissions/reports/diverReports/Search/SelectProvince.jsx create mode 100644 src/components/dashboard/roadMissions/reports/diverReports/Search/ToDateController.jsx create mode 100644 src/components/dashboard/roadMissions/reports/diverReports/Search/index.jsx create mode 100644 src/components/dashboard/roadMissions/reports/diverReports/Toolbar.jsx create mode 100644 src/components/dashboard/roadMissions/reports/diverReports/index.jsx diff --git a/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/driverReports/page.js b/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/driverReports/page.js new file mode 100644 index 0000000..95cfc33 --- /dev/null +++ b/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/driverReports/page.js @@ -0,0 +1,18 @@ +import WithPermission from "@/core/middlewares/withPermission"; +import DriverReportsPage from "@/components/dashboard/roadMissions/reports/diverReports"; + +export const metadata = { + title: "کارتابل گزارش راننده", +}; + +export default function Page() { + return ( + + + + ); +} diff --git a/src/components/dashboard/roadMissions/reports/diverReports/DriverReportsList.jsx b/src/components/dashboard/roadMissions/reports/diverReports/DriverReportsList.jsx new file mode 100644 index 0000000..94880cd --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/diverReports/DriverReportsList.jsx @@ -0,0 +1,71 @@ +"use client"; +import DataTableWithAuth from "@/core/components/DataTableWithAuth"; +import { Box } from "@mui/material"; +import { useMemo } from "react"; +import Toolbar from "./Toolbar"; +import RowActions from "./RowActions"; + +const DriverReportsList = ({ data, specialFilter }) => { + const columns = useMemo(() => { + return [ + { + accessorKey: "driver_id", + header: "کد یکتا", + id: "driver_id", + enableColumnFilter: false, + enableSorting: false, + datatype: "numeric", + grow: false, + size: 50, + }, + { + accessorKey: "driver_name", + header: "نام راننده", + id: "driver_name", + enableColumnFilter: false, + enableSorting: false, + datatype: "text", + grow: false, + size: 50, + }, + { + accessorKey: "func", + header: "کارکرد", + id: "func", + enableColumnFilter: false, + enableSorting: false, + datatype: "number", + grow: false, + size: 50, + }, + { + accessorKey: "missions", + header: "تعداد ماموریت", + id: "missions", + enableColumnFilter: false, + enableSorting: false, + datatype: "number", + grow: false, + size: 50, + }, + ]; + }, []); + + return ( + + + + ); +}; + +export default DriverReportsList; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/ExcelPrint/index.jsx b/src/components/dashboard/roadMissions/reports/diverReports/ExcelPrint/index.jsx new file mode 100644 index 0000000..daab8a9 --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/diverReports/ExcelPrint/index.jsx @@ -0,0 +1,77 @@ +"use client"; +import { + EXPORT_GET_DRIVER_COUNTRY_ACTIVITY_REPORT, + EXPORT_GET_DRIVER_PROVINCE_ACTIVITY_REPORT, +} from "@/core/utils/routes"; +import useRequest from "@/lib/hooks/useRequest"; +import { useTheme } from "@emotion/react"; +import DescriptionIcon from "@mui/icons-material/Description"; +import { Button, CircularProgress, IconButton, useMediaQuery } from "@mui/material"; +import FileSaver from "file-saver"; +import moment from "jalali-moment"; +import { useMemo, useState } from "react"; + +const PrintExcel = ({ table, filterData }) => { + const theme = useTheme(); + const isMobile = useMediaQuery(theme.breakpoints.down("sm")); + const [loading, setLoading] = useState(false); + const requestServer = useRequest({ notificationSuccess: true }); + const activeFilters = Object.entries(filterData).reduce((acc, [key, filter]) => { + if (filter.value) { + acc.push({ id: filter.id, value: filter.value }); + } + return acc; + }, []); + + const filterParams = useMemo(() => { + const params = new URLSearchParams(); + activeFilters.length > 0 && + activeFilters.map((filter, index) => { + params.set(`${filter.id}`, filter.value); + }); + return params; + }, [activeFilters]); + + const clickHandler = () => { + setLoading(true); + const CountryOrProvince = activeFilters.find((item) => item.id === "province_id"); + const requestUrl = + CountryOrProvince.value === "-1" + ? EXPORT_GET_DRIVER_COUNTRY_ACTIVITY_REPORT + : EXPORT_GET_DRIVER_PROVINCE_ACTIVITY_REPORT; + requestServer(`${requestUrl}?${filterParams}`, "get", { + requestOptions: { responseType: "blob" }, + }) + .then((response) => { + const filename = `خروجی کارتابل گزارشات راننده تاریخ_${moment().format("jYYYY_jMM_jDD")}.xlsx`; + FileSaver.saveAs(response.data, filename); + }) + .catch(() => {}) + .finally(() => { + setLoading(false); + }); + }; + + return ( + <> + {isMobile ? ( + + + + ) : ( + + )} + + ); +}; +export default PrintExcel; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/RowActions/DriverDetails/Form/DriverDetailsDialog/DriverList/index.jsx b/src/components/dashboard/roadMissions/reports/diverReports/RowActions/DriverDetails/Form/DriverDetailsDialog/DriverList/index.jsx new file mode 100644 index 0000000..3fc9f6f --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/diverReports/RowActions/DriverDetails/Form/DriverDetailsDialog/DriverList/index.jsx @@ -0,0 +1,106 @@ +import DataTableWithAuth from "@/core/components/DataTableWithAuth"; +import { GET_DRIVER_DETAILS } from "@/core/utils/routes"; +import { Box } from "@mui/material"; +import { useMemo } from "react"; + +const DriverList = ({ row }) => { + const columns = useMemo( + () => [ + { + accessorKey: "id", + header: "کد یکتا", + id: "id", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 80, + }, + { + accessorKey: "province_name", + header: "استان", + id: "province_name", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "city_name", + header: "شهر", + id: "city_name", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "station_name", + header: "راهدارخانه", + id: "station_name", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "driver_name", + header: "راننده", + id: "driver_name", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "km", + header: "کیلومتر شروع", + id: "km", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "end_km", + header: "کیلومتر پایان", + id: "end_km", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + ], + [] + ); + + return ( + <> + + + + + ); +}; +export default DriverList; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/RowActions/DriverDetails/Form/index.jsx b/src/components/dashboard/roadMissions/reports/diverReports/RowActions/DriverDetails/Form/index.jsx new file mode 100644 index 0000000..3fcc57c --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/diverReports/RowActions/DriverDetails/Form/index.jsx @@ -0,0 +1,27 @@ +import { Box, Button, DialogActions, DialogContent } from "@mui/material"; +import { Stack } from "@mui/system"; +import DriverList from "./DriverDetailsDialog/DriverList"; + +const DriverDetailsTable = ({ row, setOpenDriverDetails }) => { + return ( + <> + + + + + + + + + + + + + + + + ); +}; +export default DriverDetailsTable; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/RowActions/DriverDetails/index.jsx b/src/components/dashboard/roadMissions/reports/diverReports/RowActions/DriverDetails/index.jsx new file mode 100644 index 0000000..4a02707 --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/diverReports/RowActions/DriverDetails/index.jsx @@ -0,0 +1,47 @@ +import { Close, RemoveRedEye } from "@mui/icons-material"; +import { Dialog, DialogTitle, IconButton, Tooltip } from "@mui/material"; +import { useState } from "react"; +import DriverDetailsTable from "./Form"; + +const DriverDetails = ({ row }) => { + const [openDriverDetails, setOpenDriverDetails] = useState(false); + + return ( + <> + + { + setOpenDriverDetails(true); + }} + > + + + + + setOpenDriverDetails(false)} + sx={(theme) => ({ + position: "absolute", + right: 8, + top: 8, + zIndex: 50, + color: theme.palette.grey[500], + })} + > + + + ریز گزارشات راننده + {openDriverDetails && ( + + )} + + + ); +}; +export default DriverDetails; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/RowActions/RouteDetail/ShowRoute.jsx b/src/components/dashboard/roadMissions/reports/diverReports/RowActions/RouteDetail/ShowRoute.jsx new file mode 100644 index 0000000..5e1a4bd --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/diverReports/RowActions/RouteDetail/ShowRoute.jsx @@ -0,0 +1,46 @@ +import { useEffect, useRef } from "react"; +import { Marker, Polyline, useMap } from "react-leaflet"; +import L from "leaflet"; +import polyline from "@mapbox/polyline"; +import SourceIcon from "@/assets/images/source-icon.svg"; +import DestIcon from "@/assets/images/destination-icon.svg"; + +const ShowRoute = ({ area }) => { + const map = useMap(); + const defaultIconSize = [35, 35]; + + const createCustomIcon = (size, iconUrl) => { + return L.icon({ + iconUrl: iconUrl, + iconSize: size, + iconAnchor: [size[0] / 2, size[1]], + popupAnchor: [0, -size[1]], + }); + }; + + useEffect(() => { + if (coords.length > 0) { + map.flyToBounds(coords, { padding: [50, 50], duration: 1.5 }); + } + }, [area]); + const sourceIcon = createCustomIcon(defaultIconSize, SourceIcon.src); + const destIcon = createCustomIcon(defaultIconSize, DestIcon.src); + + if (!area) return null; + const coords = polyline.decode(area, 6); + + if (coords.length === 0) return null; + + const sourcePosition = coords[0]; + const destPosition = coords[coords.length - 1]; + + return ( + <> + + + + + ); +}; + +export default ShowRoute; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/RowActions/RouteDetail/index.jsx b/src/components/dashboard/roadMissions/reports/diverReports/RowActions/RouteDetail/index.jsx new file mode 100644 index 0000000..4501d35 --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/diverReports/RowActions/RouteDetail/index.jsx @@ -0,0 +1,57 @@ +import { Box, Button, Dialog, DialogActions, DialogTitle, IconButton, Tooltip } from "@mui/material"; +import { useState } from "react"; +import MapIcon from "@mui/icons-material/Map"; +import MapLayer from "@/core/components/MapLayer"; +import ShowRoute from "./ShowRoute"; + +const RouteDetail = ({ encoded_route }) => { + const [openRouteDetailDialog, setOpenRouteDetailDialog] = useState(false); + return ( + <> + + setOpenRouteDetailDialog(true)}> + + + + setOpenRouteDetailDialog(false)} + PaperProps={{ + sx: { + boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px", + }, + }} + dir="rtl" + maxWidth={"sm"} + > + مسیر انتخابی + + + + + + + + + + + + + ); +}; +export default RouteDetail; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/RowActions/index.jsx b/src/components/dashboard/roadMissions/reports/diverReports/RowActions/index.jsx new file mode 100644 index 0000000..af9b70a --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/diverReports/RowActions/index.jsx @@ -0,0 +1,6 @@ +import DriverDetails from "./DriverDetails"; + +const RowActions = ({ row }) => { + return ; +}; +export default RowActions; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/Search/FromDateController.jsx b/src/components/dashboard/roadMissions/reports/diverReports/Search/FromDateController.jsx new file mode 100644 index 0000000..490ee7b --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/diverReports/Search/FromDateController.jsx @@ -0,0 +1,27 @@ +import MuiDatePicker from "@/core/components/MuiDatePicker"; +import moment from "jalali-moment"; +import { Controller } from "react-hook-form"; + +const FromDateController = ({ control }) => { + return ( + ( + { + const formattedDate = moment(new Date(newValue)).locale("en").format("YYYY-MM-DD"); + onChange(formattedDate); // Update the field value in react-hook-form + }} + helperText={error ? error.message : null} + /> + )} + /> + ); +}; +export default FromDateController; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/Search/SearchReportField.jsx b/src/components/dashboard/roadMissions/reports/diverReports/Search/SearchReportField.jsx new file mode 100644 index 0000000..bde2a4c --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/diverReports/Search/SearchReportField.jsx @@ -0,0 +1,44 @@ +import SearchIcon from "@mui/icons-material/Search"; +import { Button, Grid } from "@mui/material"; +import { Controller } from "react-hook-form"; +import FromDateController from "./FromDateController"; +import SelectProvince from "./SelectProvince"; +import ToDateController from "./ToDateController"; + +const SearchReportField = ({ control, hasProvincesPermission }) => { + return ( + + + + + + + + {hasProvincesPermission && ( + + + + )} + + ( + + )} + /> + + + ); +}; + +export default SearchReportField; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/Search/SelectProvince.jsx b/src/components/dashboard/roadMissions/reports/diverReports/Search/SelectProvince.jsx new file mode 100644 index 0000000..2b24d67 --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/diverReports/Search/SelectProvince.jsx @@ -0,0 +1,45 @@ +import useProvinces from "@/lib/hooks/useProvince"; +import { FormControl, FormHelperText, InputLabel, MenuItem, Select } from "@mui/material"; +import { Controller } from "react-hook-form"; + +const SelectProvince = ({ control }) => { + const { provinces, loadingProvinces, errorProvinces } = useProvinces(); + return ( + ( + + استان + + {error && {error.message}} + + )} + /> + ); +}; +export default SelectProvince; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/Search/ToDateController.jsx b/src/components/dashboard/roadMissions/reports/diverReports/Search/ToDateController.jsx new file mode 100644 index 0000000..fc4a776 --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/diverReports/Search/ToDateController.jsx @@ -0,0 +1,30 @@ +import MuiDatePicker from "@/core/components/MuiDatePicker"; +import moment from "jalali-moment"; +import { Controller, useWatch } from "react-hook-form"; + +const ToDateController = ({ control }) => { + const minDate = useWatch({ control, name: "from_date" }); + return ( + ( + { + const formattedDate = moment(new Date(newValue)).locale("en").format("YYYY-MM-DD"); + onChange(formattedDate); // Update the field value in react-hook-form + }} + helperText={error ? error.message : null} + /> + )} + /> + ); +}; +export default ToDateController; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/Search/index.jsx b/src/components/dashboard/roadMissions/reports/diverReports/Search/index.jsx new file mode 100644 index 0000000..f29d302 --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/diverReports/Search/index.jsx @@ -0,0 +1,13 @@ +import StyledForm from "@/core/components/StyledForm"; +import SearchReportField from "./SearchReportField"; + +const SearchReportList = ({ handleSubmit, onSearchSubmit, control, hasProvincesPermission }) => { + return ( + <> + + + + + ); +}; +export default SearchReportList; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/Toolbar.jsx b/src/components/dashboard/roadMissions/reports/diverReports/Toolbar.jsx new file mode 100644 index 0000000..0f726c7 --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/diverReports/Toolbar.jsx @@ -0,0 +1,11 @@ +import { Box } from "@mui/material"; +import PrintExcel from "./ExcelPrint"; + +const Toolbar = ({ table, filterData, mutate }) => { + return ( + + + + ); +}; +export default Toolbar; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/index.jsx b/src/components/dashboard/roadMissions/reports/diverReports/index.jsx new file mode 100644 index 0000000..cae06cb --- /dev/null +++ b/src/components/dashboard/roadMissions/reports/diverReports/index.jsx @@ -0,0 +1,110 @@ +"use client"; +import PageTitle from "@/core/components/PageTitle"; +import { + GET_DRIVER_COUNTRY_ACTIVITY_REPORT, + GET_DRIVER_PROVINCE_ACTIVITY_REPORT, +} from "@/core/utils/routes"; +import { useAuth } from "@/lib/contexts/auth"; +import { usePermissions } from "@/lib/hooks/usePermissions"; +import useRequest from "@/lib/hooks/useRequest"; +import { yupResolver } from "@hookform/resolvers/yup"; +import { LinearProgress, Stack } from "@mui/material"; +import moment from "jalali-moment"; +import { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import * as yup from "yup"; +import DriverReportsList from "./DriverReportsList"; +import SearchReportList from "./Search"; + +const DriverReportsPage = () => { + const [data, setData] = useState(null); + const { data: userPermissions } = usePermissions(); + const { user } = useAuth(); + const requestServer = useRequest(); + const hasProvincesPermission = userPermissions?.includes("mission-report-country"); + + const defaultValues = { + from_date: moment(new Date()).format("YYYY-MM-DD"), + date_to: moment(new Date()).format("YYYY-MM-DD"), + province_id: user.province_id || "-1", + }; + const defaultFilter = [ + { value: `${defaultValues.province_id}`, datatype: "numeric", id: "province_id", fn: "equals" }, + { value: `${defaultValues.from_date}`, datatype: "date", id: "from_date", fn: "between" }, + { value: `${defaultValues.date_to}`, datatype: "date", id: "date_to", fn: "between" }, + ]; + const [specialFilter, setSpecialFilter] = useState(defaultFilter); + + const onSearchSubmit = async (data) => { + const params = new URLSearchParams(); + params.set("from_date", `${data.from_date} 00:00:00`); + params.set("date_to", `${data.date_to} 23:59:59`); + setSpecialFilter([ + { value: `${data.province_id}`, datatype: "numeric", id: "province_id", fn: "equals" }, + { value: `${data.from_date}`, datatype: "date", id: "from_date", fn: "between" }, + { value: `${data.date_to}`, datatype: "date", id: "date_to", fn: "between" }, + ]); + if (data.province_id === "-1") { + try { + const response = await requestServer(`${GET_DRIVER_COUNTRY_ACTIVITY_REPORT}?${params}`); + const result = response.data.data; + + setData({ + data: result.activities, + filters: data, + }); + } catch (e) {} + } else { + try { + params.set("province_id", `${data.province_id}`); + const response = await requestServer(`${GET_DRIVER_PROVINCE_ACTIVITY_REPORT}?${params}`); + + const result = response.data.data; + + setData({ + data: result.activities, + filters: data, + }); + } catch (e) {} + } + }; + + useEffect(() => { + if (!userPermissions) return; + onSearchSubmit(defaultValues); + }, [userPermissions]); + + const validationSchema = yup.object().shape({ + from_date: yup + .string() + .required("تاریخ شروع الزامی است!") + .matches(/^\d{4}-\d{2}-\d{2}$/, "تاریخ شروع الزامی است!") + .test("is-valid-date", "تاریخ شروع معتبر نیست!", (value) => moment(value, "YYYY-MM-DD", true).isValid()), + date_to: yup + .string() + .required("تاریخ پایان الزامی است!") + .matches(/^\d{4}-\d{2}-\d{2}$/, "تاریخ پایان الزامی است!") + .test("is-valid-date", "تاریخ پایان معتبر نیست!", (value) => moment(value, "YYYY-MM-DD", true).isValid()), + province_id: yup.string().nullable(), + }); + + const { control, handleSubmit } = useForm({ + defaultValues, + resolver: yupResolver(validationSchema), + mode: "all", + }); + + return ( + + + + {!data ? : } + + ); +}; +export default DriverReportsPage; diff --git a/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/MissionDitails/Form/MachineMissionsDetailsDialog/MachineMissionsList/index.jsx b/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/MissionDitails/Form/MachineMissionsDetailsDialog/MachineMissionsList/index.jsx index 037aec7..9bd3373 100644 --- a/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/MissionDitails/Form/MachineMissionsDetailsDialog/MachineMissionsList/index.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/MissionDitails/Form/MachineMissionsDetailsDialog/MachineMissionsList/index.jsx @@ -94,7 +94,7 @@ const MachineMissionsList = ({ row }) => { need_filter={true} columns={columns} sorting={[{ id: "id", desc: true }]} - table_url={`${GET_MACHINE_MISSIONS_DETAILS}?machine_id=${row.machine_id}`} + table_url={`${GET_MACHINE_MISSIONS_DETAILS}/${row.machine_id}`} page_name={"roadMissionsTransportation"} table_name={"roadMissionsTransportationMachinesList"} positionActionsColumn={"first"} diff --git a/src/components/dashboard/roadMissions/violations/Actions/CreateViolation/Form/index.jsx b/src/components/dashboard/roadMissions/violations/Actions/CreateViolation/Form/index.jsx index 5d94b1f..ad34476 100644 --- a/src/components/dashboard/roadMissions/violations/Actions/CreateViolation/Form/index.jsx +++ b/src/components/dashboard/roadMissions/violations/Actions/CreateViolation/Form/index.jsx @@ -20,7 +20,7 @@ const ViolationForm = ({ setOpenMachinesDialog, mutate, openMachinesDialog }) => data: { machine_code: result.machinesId.machine_code, km: result.km, - exit_station: `${result.start_date} ${moment(result.start_time).format("HH:mm")}`, + exit_time: `${result.start_date} ${moment(result.start_time).format("HH:mm")}`, }, }) .then((response) => { diff --git a/src/components/dashboard/roadMissions/violations/Actions/EditViolation/EditController.jsx b/src/components/dashboard/roadMissions/violations/Actions/EditViolation/EditController.jsx index 6b3bfa3..85fd833 100644 --- a/src/components/dashboard/roadMissions/violations/Actions/EditViolation/EditController.jsx +++ b/src/components/dashboard/roadMissions/violations/Actions/EditViolation/EditController.jsx @@ -11,13 +11,13 @@ const EditController = ({ rowId, mutate, setOpen, row }) => { const defaultData = { end_date: endDate, - end_time: row?.original?.enter_station ? new Date(row.original.enter_station) : null, + end_time: row?.original?.enter_time ? new Date(row.original.enter_time) : null, }; const handleSubmit = async (result) => { const payload = {}; if (result.end_date && result.end_time) { - payload.enter_station = `${result.end_date} ${moment(result.end_time).format("HH:mm")}`; + payload.enter_time = `${result.end_date} ${moment(result.end_time).format("HH:mm")}`; } await requestServer(`${EDIT_VIOLATION}/${rowId}`, "post", { diff --git a/src/core/utils/pageMenu.js b/src/core/utils/pageMenu.js index 703c244..c7e8262 100644 --- a/src/core/utils/pageMenu.js +++ b/src/core/utils/pageMenu.js @@ -35,6 +35,7 @@ import SpaceDashboardIcon from "@mui/icons-material/SpaceDashboard"; import SpeedIcon from "@mui/icons-material/Speed"; import SupervisedUserCircleIcon from "@mui/icons-material/SupervisedUserCircle"; import TaxiAlertIcon from "@mui/icons-material/TaxiAlert"; +import AirlineSeatReclineNormalIcon from "@mui/icons-material/AirlineSeatReclineNormal"; export const pageMenu = [ { @@ -211,6 +212,15 @@ export const pageMenu = [ badges: [{ key: "mission.request_portal" }], permissions: ["all"], }, + { + id: "driverReports", + label: "راننده", + icon: , + type: "page", + route: "/dashboard/road-missions/reports/driverReports", + badges: [{ key: "mission.request_portal" }], + permissions: ["all"], + }, ], }, ], diff --git a/src/core/utils/pageMenuDev.js b/src/core/utils/pageMenuDev.js index e1c3a01..49a00d6 100644 --- a/src/core/utils/pageMenuDev.js +++ b/src/core/utils/pageMenuDev.js @@ -33,6 +33,7 @@ import SpaceDashboardIcon from "@mui/icons-material/SpaceDashboard"; import SpeedIcon from "@mui/icons-material/Speed"; import TaxiAlertIcon from "@mui/icons-material/TaxiAlert"; import SupervisedUserCircleIcon from "@mui/icons-material/SupervisedUserCircle"; +import AirlineSeatReclineNormalIcon from "@mui/icons-material/AirlineSeatReclineNormal"; export const pageMenuDev = [ { @@ -209,6 +210,15 @@ export const pageMenuDev = [ badges: [{ key: "mission.request_portal" }], permissions: ["all"], }, + { + id: "driverReports", + label: "راننده", + icon: , + type: "page", + route: "/dashboard/road-missions/reports/driverReports", + badges: [{ key: "mission.request_portal" }], + permissions: ["all"], + }, ], }, ], diff --git a/src/core/utils/routes.js b/src/core/utils/routes.js index 969e100..d77593e 100644 --- a/src/core/utils/routes.js +++ b/src/core/utils/routes.js @@ -256,6 +256,13 @@ export const EXPORT_GET_MACHINES_COUNTRY_ACTIVITY_REPORT = export const EXPORT_GET_MACHINES_PROVINCE_ACTIVITY_REPORT = api + "/api/v3/missions/report_machine/province_machines_activity_excel"; +export const GET_DRIVER_COUNTRY_ACTIVITY_REPORT = api + "/api/v3/missions/report_machine/country_machine_drivers_activity"; +export const GET_DRIVER_PROVINCE_ACTIVITY_REPORT = api + "/api/v3/missions/report_machine/province_machine_drivers_activity"; +export const EXPORT_GET_DRIVER_COUNTRY_ACTIVITY_REPORT = + api + "/api/v3/missions/report_machine/country_machine_drivers_activity_excel"; +export const EXPORT_GET_DRIVER_PROVINCE_ACTIVITY_REPORT = + api + "/api/v3/missions/report_machine/province_machine_drivers_activity_excel"; + export const GET_MACHINES_TYPE_COUNTRY_ACTIVITY_REPORT = api + "/api/v3/missions/report_machine/country_machine_types_activity"; export const GET_MACHINES_TYPE_PROVINCE_ACTIVITY_REPORT = api + "/api/v3/missions/report_machine/province_machine_types_activity"; @@ -304,3 +311,4 @@ export const GET_STATIONS_LIST = api + "/api/v3/road_maintenance_station"; export const UPDATE_MACHINE_STATUS_AND_LOCATION = api + "/api/v3/cmms_machines"; export const GET_MACHINE_MISSIONS_DETAILS = api + "/api/v3/missions/report_machine/machine_details_report"; export const GET_MACHINE_TYPE_MISSIONS_DETAILS = api + "/api/v3/missions/report_machine/machine_type_details_report"; +export const GET_DRIVER_DETAILS = api + "/api/v3/missions/report_machine/machine_driver_details_report"; -- 2.49.1 From 806854327add50b79f93c8392fdbf34b5a4a6710 Mon Sep 17 00:00:00 2001 From: AminGhasempoor Date: Sun, 14 Jun 2026 11:48:34 +0330 Subject: [PATCH 3/4] build and format --- .../reports/driverReports/page.js | 36 +-- .../reports/machineTypeReports/page.js | 36 +-- .../reports/machinesReports/page.js | 36 +-- .../diverReports/DriverReportsList.jsx | 142 ++++++------ .../DriverDetailsDialog/DriverList/index.jsx | 212 ++++++++--------- .../RowActions/DriverDetails/Form/index.jsx | 54 ++--- .../RowActions/DriverDetails/index.jsx | 91 ++++---- .../RowActions/RouteDetail/ShowRoute.jsx | 92 ++++---- .../RowActions/RouteDetail/index.jsx | 114 +++++----- .../reports/diverReports/RowActions/index.jsx | 12 +- .../Search/FromDateController.jsx | 54 ++--- .../diverReports/Search/SearchReportField.jsx | 88 +++---- .../diverReports/Search/SelectProvince.jsx | 90 ++++---- .../diverReports/Search/ToDateController.jsx | 60 ++--- .../reports/diverReports/Search/index.jsx | 26 +-- .../reports/diverReports/Toolbar.jsx | 22 +- .../reports/diverReports/index.jsx | 5 +- .../machinesReports/ExcelPrint/index.jsx | 154 ++++++------- .../machinesReports/MachinesReportsList.jsx | 162 ++++++------- .../MachineMissionsList/index.jsx | 212 ++++++++--------- .../RowActions/MissionDitails/Form/index.jsx | 54 ++--- .../RowActions/MissionDitails/index.jsx | 94 ++++---- .../RowActions/RouteDetail/ShowRoute.jsx | 92 ++++---- .../RowActions/RouteDetail/index.jsx | 114 +++++----- .../machinesReports/RowActions/index.jsx | 12 +- .../Search/FromDateController.jsx | 54 ++--- .../Search/SearchReportField.jsx | 88 +++---- .../machinesReports/Search/SelectProvince.jsx | 90 ++++---- .../Search/ToDateController.jsx | 60 ++--- .../reports/machinesReports/Search/index.jsx | 26 +-- .../reports/machinesReports/Toolbar.jsx | 22 +- .../reports/machinesReports/index.jsx | 214 +++++++++--------- .../MachinesReportsList.jsx | 122 +++++----- .../MachineMissionsList/index.jsx | 212 ++++++++--------- .../RowActions/MissionDitails/Form/index.jsx | 54 ++--- .../RowActions/MissionDitails/index.jsx | 94 ++++---- .../RowActions/RouteDetail/ShowRoute.jsx | 92 ++++---- .../RowActions/RouteDetail/index.jsx | 114 +++++----- .../machinesTypeReports/RowActions/index.jsx | 16 +- .../Search/FromDateController.jsx | 54 ++--- .../Search/SearchReportField.jsx | 88 +++---- .../Search/SelectProvince.jsx | 90 ++++---- .../Search/ToDateController.jsx | 60 ++--- .../machinesTypeReports/Search/index.jsx | 26 +-- .../reports/machinesTypeReports/Toolbar.jsx | 22 +- src/core/utils/routes.js | 9 +- 46 files changed, 1832 insertions(+), 1839 deletions(-) diff --git a/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/driverReports/page.js b/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/driverReports/page.js index 95cfc33..6df3acd 100644 --- a/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/driverReports/page.js +++ b/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/driverReports/page.js @@ -1,18 +1,18 @@ -import WithPermission from "@/core/middlewares/withPermission"; -import DriverReportsPage from "@/components/dashboard/roadMissions/reports/diverReports"; - -export const metadata = { - title: "کارتابل گزارش راننده", -}; - -export default function Page() { - return ( - - - - ); -} +import WithPermission from "@/core/middlewares/withPermission"; +import DriverReportsPage from "@/components/dashboard/roadMissions/reports/diverReports"; + +export const metadata = { + title: "کارتابل گزارش راننده", +}; + +export default function Page() { + return ( + + + + ); +} diff --git a/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/machineTypeReports/page.js b/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/machineTypeReports/page.js index e8725f1..0eb121e 100644 --- a/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/machineTypeReports/page.js +++ b/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/machineTypeReports/page.js @@ -1,18 +1,18 @@ -import WithPermission from "@/core/middlewares/withPermission"; -import MachinesTypeReportsPage from "@/components/dashboard/roadMissions/reports/machinesTypeReports"; - -export const metadata = { - title: "کارتابل گزارش نوع ماشین‌ها", -}; - -export default function Page() { - return ( - - - - ); -} +import WithPermission from "@/core/middlewares/withPermission"; +import MachinesTypeReportsPage from "@/components/dashboard/roadMissions/reports/machinesTypeReports"; + +export const metadata = { + title: "کارتابل گزارش نوع ماشین‌ها", +}; + +export default function Page() { + return ( + + + + ); +} diff --git a/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/machinesReports/page.js b/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/machinesReports/page.js index 0656840..97c952d 100644 --- a/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/machinesReports/page.js +++ b/src/app/(withAuth)/(dashboardLayout)/dashboard/road-missions/reports/machinesReports/page.js @@ -1,18 +1,18 @@ -import MachinesReportsPage from "@/components/dashboard/roadMissions/reports/machinesReports"; -import WithPermission from "@/core/middlewares/withPermission"; - -export const metadata = { - title: "کارتابل گزارش ماشین‌ها", -}; - -export default function Page() { - return ( - - - - ); -} +import MachinesReportsPage from "@/components/dashboard/roadMissions/reports/machinesReports"; +import WithPermission from "@/core/middlewares/withPermission"; + +export const metadata = { + title: "کارتابل گزارش ماشین‌ها", +}; + +export default function Page() { + return ( + + + + ); +} diff --git a/src/components/dashboard/roadMissions/reports/diverReports/DriverReportsList.jsx b/src/components/dashboard/roadMissions/reports/diverReports/DriverReportsList.jsx index 94880cd..a279dc4 100644 --- a/src/components/dashboard/roadMissions/reports/diverReports/DriverReportsList.jsx +++ b/src/components/dashboard/roadMissions/reports/diverReports/DriverReportsList.jsx @@ -1,71 +1,71 @@ -"use client"; -import DataTableWithAuth from "@/core/components/DataTableWithAuth"; -import { Box } from "@mui/material"; -import { useMemo } from "react"; -import Toolbar from "./Toolbar"; -import RowActions from "./RowActions"; - -const DriverReportsList = ({ data, specialFilter }) => { - const columns = useMemo(() => { - return [ - { - accessorKey: "driver_id", - header: "کد یکتا", - id: "driver_id", - enableColumnFilter: false, - enableSorting: false, - datatype: "numeric", - grow: false, - size: 50, - }, - { - accessorKey: "driver_name", - header: "نام راننده", - id: "driver_name", - enableColumnFilter: false, - enableSorting: false, - datatype: "text", - grow: false, - size: 50, - }, - { - accessorKey: "func", - header: "کارکرد", - id: "func", - enableColumnFilter: false, - enableSorting: false, - datatype: "number", - grow: false, - size: 50, - }, - { - accessorKey: "missions", - header: "تعداد ماموریت", - id: "missions", - enableColumnFilter: false, - enableSorting: false, - datatype: "number", - grow: false, - size: 50, - }, - ]; - }, []); - - return ( - - - - ); -}; - -export default DriverReportsList; +"use client"; +import DataTableWithAuth from "@/core/components/DataTableWithAuth"; +import { Box } from "@mui/material"; +import { useMemo } from "react"; +import Toolbar from "./Toolbar"; +import RowActions from "./RowActions"; + +const DriverReportsList = ({ data, specialFilter }) => { + const columns = useMemo(() => { + return [ + { + accessorKey: "driver_id", + header: "کد یکتا", + id: "driver_id", + enableColumnFilter: false, + enableSorting: false, + datatype: "numeric", + grow: false, + size: 50, + }, + { + accessorKey: "driver_name", + header: "نام راننده", + id: "driver_name", + enableColumnFilter: false, + enableSorting: false, + datatype: "text", + grow: false, + size: 50, + }, + { + accessorKey: "func", + header: "کارکرد", + id: "func", + enableColumnFilter: false, + enableSorting: false, + datatype: "number", + grow: false, + size: 50, + }, + { + accessorKey: "missions", + header: "تعداد ماموریت", + id: "missions", + enableColumnFilter: false, + enableSorting: false, + datatype: "number", + grow: false, + size: 50, + }, + ]; + }, []); + + return ( + + + + ); +}; + +export default DriverReportsList; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/RowActions/DriverDetails/Form/DriverDetailsDialog/DriverList/index.jsx b/src/components/dashboard/roadMissions/reports/diverReports/RowActions/DriverDetails/Form/DriverDetailsDialog/DriverList/index.jsx index 3fc9f6f..2d13661 100644 --- a/src/components/dashboard/roadMissions/reports/diverReports/RowActions/DriverDetails/Form/DriverDetailsDialog/DriverList/index.jsx +++ b/src/components/dashboard/roadMissions/reports/diverReports/RowActions/DriverDetails/Form/DriverDetailsDialog/DriverList/index.jsx @@ -1,106 +1,106 @@ -import DataTableWithAuth from "@/core/components/DataTableWithAuth"; -import { GET_DRIVER_DETAILS } from "@/core/utils/routes"; -import { Box } from "@mui/material"; -import { useMemo } from "react"; - -const DriverList = ({ row }) => { - const columns = useMemo( - () => [ - { - accessorKey: "id", - header: "کد یکتا", - id: "id", - enableColumnFilter: true, - datatype: "text", - filterMode: "equals", - columnFilterModeOptions: ["equals", "contains"], - grow: false, - size: 80, - }, - { - accessorKey: "province_name", - header: "استان", - id: "province_name", - enableColumnFilter: true, - datatype: "text", - filterMode: "equals", - columnFilterModeOptions: ["equals", "contains"], - grow: false, - size: 100, - }, - { - accessorKey: "city_name", - header: "شهر", - id: "city_name", - enableColumnFilter: true, - datatype: "text", - filterMode: "equals", - columnFilterModeOptions: ["equals", "contains"], - grow: false, - size: 100, - }, - { - accessorKey: "station_name", - header: "راهدارخانه", - id: "station_name", - enableColumnFilter: true, - datatype: "text", - filterMode: "equals", - columnFilterModeOptions: ["equals", "contains"], - grow: false, - size: 100, - }, - { - accessorKey: "driver_name", - header: "راننده", - id: "driver_name", - enableColumnFilter: true, - datatype: "text", - filterMode: "equals", - columnFilterModeOptions: ["equals", "contains"], - grow: false, - size: 100, - }, - { - accessorKey: "km", - header: "کیلومتر شروع", - id: "km", - enableColumnFilter: true, - datatype: "text", - filterMode: "equals", - columnFilterModeOptions: ["equals", "contains"], - grow: false, - size: 100, - }, - { - accessorKey: "end_km", - header: "کیلومتر پایان", - id: "end_km", - enableColumnFilter: true, - datatype: "text", - filterMode: "equals", - columnFilterModeOptions: ["equals", "contains"], - grow: false, - size: 100, - }, - ], - [] - ); - - return ( - <> - - - - - ); -}; -export default DriverList; +import DataTableWithAuth from "@/core/components/DataTableWithAuth"; +import { GET_DRIVER_DETAILS } from "@/core/utils/routes"; +import { Box } from "@mui/material"; +import { useMemo } from "react"; + +const DriverList = ({ row }) => { + const columns = useMemo( + () => [ + { + accessorKey: "id", + header: "کد یکتا", + id: "id", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 80, + }, + { + accessorKey: "province_name", + header: "استان", + id: "province_name", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "city_name", + header: "شهر", + id: "city_name", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "station_name", + header: "راهدارخانه", + id: "station_name", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "driver_name", + header: "راننده", + id: "driver_name", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "km", + header: "کیلومتر شروع", + id: "km", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "end_km", + header: "کیلومتر پایان", + id: "end_km", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + ], + [] + ); + + return ( + <> + + + + + ); +}; +export default DriverList; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/RowActions/DriverDetails/Form/index.jsx b/src/components/dashboard/roadMissions/reports/diverReports/RowActions/DriverDetails/Form/index.jsx index 3fcc57c..d4c1c65 100644 --- a/src/components/dashboard/roadMissions/reports/diverReports/RowActions/DriverDetails/Form/index.jsx +++ b/src/components/dashboard/roadMissions/reports/diverReports/RowActions/DriverDetails/Form/index.jsx @@ -1,27 +1,27 @@ -import { Box, Button, DialogActions, DialogContent } from "@mui/material"; -import { Stack } from "@mui/system"; -import DriverList from "./DriverDetailsDialog/DriverList"; - -const DriverDetailsTable = ({ row, setOpenDriverDetails }) => { - return ( - <> - - - - - - - - - - - - - - - - ); -}; -export default DriverDetailsTable; +import { Box, Button, DialogActions, DialogContent } from "@mui/material"; +import { Stack } from "@mui/system"; +import DriverList from "./DriverDetailsDialog/DriverList"; + +const DriverDetailsTable = ({ row, setOpenDriverDetails }) => { + return ( + <> + + + + + + + + + + + + + + + + ); +}; +export default DriverDetailsTable; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/RowActions/DriverDetails/index.jsx b/src/components/dashboard/roadMissions/reports/diverReports/RowActions/DriverDetails/index.jsx index 4a02707..9e32458 100644 --- a/src/components/dashboard/roadMissions/reports/diverReports/RowActions/DriverDetails/index.jsx +++ b/src/components/dashboard/roadMissions/reports/diverReports/RowActions/DriverDetails/index.jsx @@ -1,47 +1,44 @@ -import { Close, RemoveRedEye } from "@mui/icons-material"; -import { Dialog, DialogTitle, IconButton, Tooltip } from "@mui/material"; -import { useState } from "react"; -import DriverDetailsTable from "./Form"; - -const DriverDetails = ({ row }) => { - const [openDriverDetails, setOpenDriverDetails] = useState(false); - - return ( - <> - - { - setOpenDriverDetails(true); - }} - > - - - - - setOpenDriverDetails(false)} - sx={(theme) => ({ - position: "absolute", - right: 8, - top: 8, - zIndex: 50, - color: theme.palette.grey[500], - })} - > - - - ریز گزارشات راننده - {openDriverDetails && ( - - )} - - - ); -}; -export default DriverDetails; +import { Close, RemoveRedEye } from "@mui/icons-material"; +import { Dialog, DialogTitle, IconButton, Tooltip } from "@mui/material"; +import { useState } from "react"; +import DriverDetailsTable from "./Form"; + +const DriverDetails = ({ row }) => { + const [openDriverDetails, setOpenDriverDetails] = useState(false); + + return ( + <> + + { + setOpenDriverDetails(true); + }} + > + + + + + setOpenDriverDetails(false)} + sx={(theme) => ({ + position: "absolute", + right: 8, + top: 8, + zIndex: 50, + color: theme.palette.grey[500], + })} + > + + + ریز گزارشات راننده + {openDriverDetails && ( + + )} + + + ); +}; +export default DriverDetails; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/RowActions/RouteDetail/ShowRoute.jsx b/src/components/dashboard/roadMissions/reports/diverReports/RowActions/RouteDetail/ShowRoute.jsx index 5e1a4bd..7d47ba8 100644 --- a/src/components/dashboard/roadMissions/reports/diverReports/RowActions/RouteDetail/ShowRoute.jsx +++ b/src/components/dashboard/roadMissions/reports/diverReports/RowActions/RouteDetail/ShowRoute.jsx @@ -1,46 +1,46 @@ -import { useEffect, useRef } from "react"; -import { Marker, Polyline, useMap } from "react-leaflet"; -import L from "leaflet"; -import polyline from "@mapbox/polyline"; -import SourceIcon from "@/assets/images/source-icon.svg"; -import DestIcon from "@/assets/images/destination-icon.svg"; - -const ShowRoute = ({ area }) => { - const map = useMap(); - const defaultIconSize = [35, 35]; - - const createCustomIcon = (size, iconUrl) => { - return L.icon({ - iconUrl: iconUrl, - iconSize: size, - iconAnchor: [size[0] / 2, size[1]], - popupAnchor: [0, -size[1]], - }); - }; - - useEffect(() => { - if (coords.length > 0) { - map.flyToBounds(coords, { padding: [50, 50], duration: 1.5 }); - } - }, [area]); - const sourceIcon = createCustomIcon(defaultIconSize, SourceIcon.src); - const destIcon = createCustomIcon(defaultIconSize, DestIcon.src); - - if (!area) return null; - const coords = polyline.decode(area, 6); - - if (coords.length === 0) return null; - - const sourcePosition = coords[0]; - const destPosition = coords[coords.length - 1]; - - return ( - <> - - - - - ); -}; - -export default ShowRoute; +import { useEffect, useRef } from "react"; +import { Marker, Polyline, useMap } from "react-leaflet"; +import L from "leaflet"; +import polyline from "@mapbox/polyline"; +import SourceIcon from "@/assets/images/source-icon.svg"; +import DestIcon from "@/assets/images/destination-icon.svg"; + +const ShowRoute = ({ area }) => { + const map = useMap(); + const defaultIconSize = [35, 35]; + + const createCustomIcon = (size, iconUrl) => { + return L.icon({ + iconUrl: iconUrl, + iconSize: size, + iconAnchor: [size[0] / 2, size[1]], + popupAnchor: [0, -size[1]], + }); + }; + + useEffect(() => { + if (coords.length > 0) { + map.flyToBounds(coords, { padding: [50, 50], duration: 1.5 }); + } + }, [area]); + const sourceIcon = createCustomIcon(defaultIconSize, SourceIcon.src); + const destIcon = createCustomIcon(defaultIconSize, DestIcon.src); + + if (!area) return null; + const coords = polyline.decode(area, 6); + + if (coords.length === 0) return null; + + const sourcePosition = coords[0]; + const destPosition = coords[coords.length - 1]; + + return ( + <> + + + + + ); +}; + +export default ShowRoute; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/RowActions/RouteDetail/index.jsx b/src/components/dashboard/roadMissions/reports/diverReports/RowActions/RouteDetail/index.jsx index 4501d35..48b84a2 100644 --- a/src/components/dashboard/roadMissions/reports/diverReports/RowActions/RouteDetail/index.jsx +++ b/src/components/dashboard/roadMissions/reports/diverReports/RowActions/RouteDetail/index.jsx @@ -1,57 +1,57 @@ -import { Box, Button, Dialog, DialogActions, DialogTitle, IconButton, Tooltip } from "@mui/material"; -import { useState } from "react"; -import MapIcon from "@mui/icons-material/Map"; -import MapLayer from "@/core/components/MapLayer"; -import ShowRoute from "./ShowRoute"; - -const RouteDetail = ({ encoded_route }) => { - const [openRouteDetailDialog, setOpenRouteDetailDialog] = useState(false); - return ( - <> - - setOpenRouteDetailDialog(true)}> - - - - setOpenRouteDetailDialog(false)} - PaperProps={{ - sx: { - boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px", - }, - }} - dir="rtl" - maxWidth={"sm"} - > - مسیر انتخابی - - - - - - - - - - - - - ); -}; -export default RouteDetail; +import { Box, Button, Dialog, DialogActions, DialogTitle, IconButton, Tooltip } from "@mui/material"; +import { useState } from "react"; +import MapIcon from "@mui/icons-material/Map"; +import MapLayer from "@/core/components/MapLayer"; +import ShowRoute from "./ShowRoute"; + +const RouteDetail = ({ encoded_route }) => { + const [openRouteDetailDialog, setOpenRouteDetailDialog] = useState(false); + return ( + <> + + setOpenRouteDetailDialog(true)}> + + + + setOpenRouteDetailDialog(false)} + PaperProps={{ + sx: { + boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px", + }, + }} + dir="rtl" + maxWidth={"sm"} + > + مسیر انتخابی + + + + + + + + + + + + + ); +}; +export default RouteDetail; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/RowActions/index.jsx b/src/components/dashboard/roadMissions/reports/diverReports/RowActions/index.jsx index af9b70a..f37d403 100644 --- a/src/components/dashboard/roadMissions/reports/diverReports/RowActions/index.jsx +++ b/src/components/dashboard/roadMissions/reports/diverReports/RowActions/index.jsx @@ -1,6 +1,6 @@ -import DriverDetails from "./DriverDetails"; - -const RowActions = ({ row }) => { - return ; -}; -export default RowActions; +import DriverDetails from "./DriverDetails"; + +const RowActions = ({ row }) => { + return ; +}; +export default RowActions; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/Search/FromDateController.jsx b/src/components/dashboard/roadMissions/reports/diverReports/Search/FromDateController.jsx index 490ee7b..0a81488 100644 --- a/src/components/dashboard/roadMissions/reports/diverReports/Search/FromDateController.jsx +++ b/src/components/dashboard/roadMissions/reports/diverReports/Search/FromDateController.jsx @@ -1,27 +1,27 @@ -import MuiDatePicker from "@/core/components/MuiDatePicker"; -import moment from "jalali-moment"; -import { Controller } from "react-hook-form"; - -const FromDateController = ({ control }) => { - return ( - ( - { - const formattedDate = moment(new Date(newValue)).locale("en").format("YYYY-MM-DD"); - onChange(formattedDate); // Update the field value in react-hook-form - }} - helperText={error ? error.message : null} - /> - )} - /> - ); -}; -export default FromDateController; +import MuiDatePicker from "@/core/components/MuiDatePicker"; +import moment from "jalali-moment"; +import { Controller } from "react-hook-form"; + +const FromDateController = ({ control }) => { + return ( + ( + { + const formattedDate = moment(new Date(newValue)).locale("en").format("YYYY-MM-DD"); + onChange(formattedDate); // Update the field value in react-hook-form + }} + helperText={error ? error.message : null} + /> + )} + /> + ); +}; +export default FromDateController; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/Search/SearchReportField.jsx b/src/components/dashboard/roadMissions/reports/diverReports/Search/SearchReportField.jsx index bde2a4c..e1b71cd 100644 --- a/src/components/dashboard/roadMissions/reports/diverReports/Search/SearchReportField.jsx +++ b/src/components/dashboard/roadMissions/reports/diverReports/Search/SearchReportField.jsx @@ -1,44 +1,44 @@ -import SearchIcon from "@mui/icons-material/Search"; -import { Button, Grid } from "@mui/material"; -import { Controller } from "react-hook-form"; -import FromDateController from "./FromDateController"; -import SelectProvince from "./SelectProvince"; -import ToDateController from "./ToDateController"; - -const SearchReportField = ({ control, hasProvincesPermission }) => { - return ( - - - - - - - - {hasProvincesPermission && ( - - - - )} - - ( - - )} - /> - - - ); -}; - -export default SearchReportField; +import SearchIcon from "@mui/icons-material/Search"; +import { Button, Grid } from "@mui/material"; +import { Controller } from "react-hook-form"; +import FromDateController from "./FromDateController"; +import SelectProvince from "./SelectProvince"; +import ToDateController from "./ToDateController"; + +const SearchReportField = ({ control, hasProvincesPermission }) => { + return ( + + + + + + + + {hasProvincesPermission && ( + + + + )} + + ( + + )} + /> + + + ); +}; + +export default SearchReportField; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/Search/SelectProvince.jsx b/src/components/dashboard/roadMissions/reports/diverReports/Search/SelectProvince.jsx index 2b24d67..89395f0 100644 --- a/src/components/dashboard/roadMissions/reports/diverReports/Search/SelectProvince.jsx +++ b/src/components/dashboard/roadMissions/reports/diverReports/Search/SelectProvince.jsx @@ -1,45 +1,45 @@ -import useProvinces from "@/lib/hooks/useProvince"; -import { FormControl, FormHelperText, InputLabel, MenuItem, Select } from "@mui/material"; -import { Controller } from "react-hook-form"; - -const SelectProvince = ({ control }) => { - const { provinces, loadingProvinces, errorProvinces } = useProvinces(); - return ( - ( - - استان - - {error && {error.message}} - - )} - /> - ); -}; -export default SelectProvince; +import useProvinces from "@/lib/hooks/useProvince"; +import { FormControl, FormHelperText, InputLabel, MenuItem, Select } from "@mui/material"; +import { Controller } from "react-hook-form"; + +const SelectProvince = ({ control }) => { + const { provinces, loadingProvinces, errorProvinces } = useProvinces(); + return ( + ( + + استان + + {error && {error.message}} + + )} + /> + ); +}; +export default SelectProvince; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/Search/ToDateController.jsx b/src/components/dashboard/roadMissions/reports/diverReports/Search/ToDateController.jsx index fc4a776..ef3ff49 100644 --- a/src/components/dashboard/roadMissions/reports/diverReports/Search/ToDateController.jsx +++ b/src/components/dashboard/roadMissions/reports/diverReports/Search/ToDateController.jsx @@ -1,30 +1,30 @@ -import MuiDatePicker from "@/core/components/MuiDatePicker"; -import moment from "jalali-moment"; -import { Controller, useWatch } from "react-hook-form"; - -const ToDateController = ({ control }) => { - const minDate = useWatch({ control, name: "from_date" }); - return ( - ( - { - const formattedDate = moment(new Date(newValue)).locale("en").format("YYYY-MM-DD"); - onChange(formattedDate); // Update the field value in react-hook-form - }} - helperText={error ? error.message : null} - /> - )} - /> - ); -}; -export default ToDateController; +import MuiDatePicker from "@/core/components/MuiDatePicker"; +import moment from "jalali-moment"; +import { Controller, useWatch } from "react-hook-form"; + +const ToDateController = ({ control }) => { + const minDate = useWatch({ control, name: "from_date" }); + return ( + ( + { + const formattedDate = moment(new Date(newValue)).locale("en").format("YYYY-MM-DD"); + onChange(formattedDate); // Update the field value in react-hook-form + }} + helperText={error ? error.message : null} + /> + )} + /> + ); +}; +export default ToDateController; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/Search/index.jsx b/src/components/dashboard/roadMissions/reports/diverReports/Search/index.jsx index f29d302..9d504f2 100644 --- a/src/components/dashboard/roadMissions/reports/diverReports/Search/index.jsx +++ b/src/components/dashboard/roadMissions/reports/diverReports/Search/index.jsx @@ -1,13 +1,13 @@ -import StyledForm from "@/core/components/StyledForm"; -import SearchReportField from "./SearchReportField"; - -const SearchReportList = ({ handleSubmit, onSearchSubmit, control, hasProvincesPermission }) => { - return ( - <> - - - - - ); -}; -export default SearchReportList; +import StyledForm from "@/core/components/StyledForm"; +import SearchReportField from "./SearchReportField"; + +const SearchReportList = ({ handleSubmit, onSearchSubmit, control, hasProvincesPermission }) => { + return ( + <> + + + + + ); +}; +export default SearchReportList; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/Toolbar.jsx b/src/components/dashboard/roadMissions/reports/diverReports/Toolbar.jsx index 0f726c7..afc132c 100644 --- a/src/components/dashboard/roadMissions/reports/diverReports/Toolbar.jsx +++ b/src/components/dashboard/roadMissions/reports/diverReports/Toolbar.jsx @@ -1,11 +1,11 @@ -import { Box } from "@mui/material"; -import PrintExcel from "./ExcelPrint"; - -const Toolbar = ({ table, filterData, mutate }) => { - return ( - - - - ); -}; -export default Toolbar; +import { Box } from "@mui/material"; +import PrintExcel from "./ExcelPrint"; + +const Toolbar = ({ table, filterData, mutate }) => { + return ( + + + + ); +}; +export default Toolbar; diff --git a/src/components/dashboard/roadMissions/reports/diverReports/index.jsx b/src/components/dashboard/roadMissions/reports/diverReports/index.jsx index cae06cb..967a8a6 100644 --- a/src/components/dashboard/roadMissions/reports/diverReports/index.jsx +++ b/src/components/dashboard/roadMissions/reports/diverReports/index.jsx @@ -1,9 +1,6 @@ "use client"; import PageTitle from "@/core/components/PageTitle"; -import { - GET_DRIVER_COUNTRY_ACTIVITY_REPORT, - GET_DRIVER_PROVINCE_ACTIVITY_REPORT, -} from "@/core/utils/routes"; +import { GET_DRIVER_COUNTRY_ACTIVITY_REPORT, GET_DRIVER_PROVINCE_ACTIVITY_REPORT } from "@/core/utils/routes"; import { useAuth } from "@/lib/contexts/auth"; import { usePermissions } from "@/lib/hooks/usePermissions"; import useRequest from "@/lib/hooks/useRequest"; diff --git a/src/components/dashboard/roadMissions/reports/machinesReports/ExcelPrint/index.jsx b/src/components/dashboard/roadMissions/reports/machinesReports/ExcelPrint/index.jsx index ef85a7f..8377ab4 100644 --- a/src/components/dashboard/roadMissions/reports/machinesReports/ExcelPrint/index.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesReports/ExcelPrint/index.jsx @@ -1,77 +1,77 @@ -"use client"; -import { - EXPORT_GET_MACHINES_COUNTRY_ACTIVITY_REPORT, - EXPORT_GET_MACHINES_PROVINCE_ACTIVITY_REPORT, -} from "@/core/utils/routes"; -import useRequest from "@/lib/hooks/useRequest"; -import { useTheme } from "@emotion/react"; -import DescriptionIcon from "@mui/icons-material/Description"; -import { Button, CircularProgress, IconButton, useMediaQuery } from "@mui/material"; -import FileSaver from "file-saver"; -import moment from "jalali-moment"; -import { useMemo, useState } from "react"; - -const PrintExcel = ({ table, filterData }) => { - const theme = useTheme(); - const isMobile = useMediaQuery(theme.breakpoints.down("sm")); - const [loading, setLoading] = useState(false); - const requestServer = useRequest({ notificationSuccess: true }); - const activeFilters = Object.entries(filterData).reduce((acc, [key, filter]) => { - if (filter.value) { - acc.push({ id: filter.id, value: filter.value }); - } - return acc; - }, []); - - const filterParams = useMemo(() => { - const params = new URLSearchParams(); - activeFilters.length > 0 && - activeFilters.map((filter, index) => { - params.set(`${filter.id}`, filter.value); - }); - return params; - }, [activeFilters]); - - const clickHandler = () => { - setLoading(true); - const CountryOrProvince = activeFilters.find((item) => item.id === "province_id"); - const requestUrl = - CountryOrProvince.value === "-1" - ? EXPORT_GET_MACHINES_COUNTRY_ACTIVITY_REPORT - : EXPORT_GET_MACHINES_PROVINCE_ACTIVITY_REPORT; - requestServer(`${requestUrl}?${filterParams}`, "get", { - requestOptions: { responseType: "blob" }, - }) - .then((response) => { - const filename = `خروجی کارتابل گزارشات گشت راهداری تاریخ_${moment().format("jYYYY_jMM_jDD")}.xlsx`; - FileSaver.saveAs(response.data, filename); - }) - .catch(() => {}) - .finally(() => { - setLoading(false); - }); - }; - - return ( - <> - {isMobile ? ( - - - - ) : ( - - )} - - ); -}; -export default PrintExcel; +"use client"; +import { + EXPORT_GET_MACHINES_COUNTRY_ACTIVITY_REPORT, + EXPORT_GET_MACHINES_PROVINCE_ACTIVITY_REPORT, +} from "@/core/utils/routes"; +import useRequest from "@/lib/hooks/useRequest"; +import { useTheme } from "@emotion/react"; +import DescriptionIcon from "@mui/icons-material/Description"; +import { Button, CircularProgress, IconButton, useMediaQuery } from "@mui/material"; +import FileSaver from "file-saver"; +import moment from "jalali-moment"; +import { useMemo, useState } from "react"; + +const PrintExcel = ({ table, filterData }) => { + const theme = useTheme(); + const isMobile = useMediaQuery(theme.breakpoints.down("sm")); + const [loading, setLoading] = useState(false); + const requestServer = useRequest({ notificationSuccess: true }); + const activeFilters = Object.entries(filterData).reduce((acc, [key, filter]) => { + if (filter.value) { + acc.push({ id: filter.id, value: filter.value }); + } + return acc; + }, []); + + const filterParams = useMemo(() => { + const params = new URLSearchParams(); + activeFilters.length > 0 && + activeFilters.map((filter, index) => { + params.set(`${filter.id}`, filter.value); + }); + return params; + }, [activeFilters]); + + const clickHandler = () => { + setLoading(true); + const CountryOrProvince = activeFilters.find((item) => item.id === "province_id"); + const requestUrl = + CountryOrProvince.value === "-1" + ? EXPORT_GET_MACHINES_COUNTRY_ACTIVITY_REPORT + : EXPORT_GET_MACHINES_PROVINCE_ACTIVITY_REPORT; + requestServer(`${requestUrl}?${filterParams}`, "get", { + requestOptions: { responseType: "blob" }, + }) + .then((response) => { + const filename = `خروجی کارتابل گزارشات گشت راهداری تاریخ_${moment().format("jYYYY_jMM_jDD")}.xlsx`; + FileSaver.saveAs(response.data, filename); + }) + .catch(() => {}) + .finally(() => { + setLoading(false); + }); + }; + + return ( + <> + {isMobile ? ( + + + + ) : ( + + )} + + ); +}; +export default PrintExcel; diff --git a/src/components/dashboard/roadMissions/reports/machinesReports/MachinesReportsList.jsx b/src/components/dashboard/roadMissions/reports/machinesReports/MachinesReportsList.jsx index 34badf1..363c85f 100644 --- a/src/components/dashboard/roadMissions/reports/machinesReports/MachinesReportsList.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesReports/MachinesReportsList.jsx @@ -1,81 +1,81 @@ -"use client"; -import DataTableWithAuth from "@/core/components/DataTableWithAuth"; -import { Box } from "@mui/material"; -import { useMemo } from "react"; -import Toolbar from "./Toolbar"; -import RowActions from "./RowActions"; - -const MachinesReportsList = ({ data, specialFilter }) => { - const columns = useMemo(() => { - return [ - { - accessorKey: "machine_id", - header: "کد یکتا", - id: "machine_id", - enableColumnFilter: false, - enableSorting: false, - datatype: "numeric", - grow: false, - size: 50, - }, - { - accessorKey: "car_name", - header: "مدل ماشین", - id: "car_name", - enableColumnFilter: false, - enableSorting: false, - datatype: "text", - grow: false, - size: 50, - }, - { - accessorKey: "machine_code", - header: "کد ماشین", - id: "machine_code", - enableColumnFilter: false, - enableSorting: false, - datatype: "text", - grow: false, - size: 50, - }, - { - accessorKey: "func", - header: "کارکرد", - id: "func", - enableColumnFilter: false, - enableSorting: false, - datatype: "number", - grow: false, - size: 50, - }, - { - accessorKey: "missions", - header: "تعداد ماموریت", - id: "missions", - enableColumnFilter: false, - enableSorting: false, - datatype: "number", - grow: false, - size: 50, - }, - ]; - }, []); - - return ( - - - - ); -}; - -export default MachinesReportsList; +"use client"; +import DataTableWithAuth from "@/core/components/DataTableWithAuth"; +import { Box } from "@mui/material"; +import { useMemo } from "react"; +import Toolbar from "./Toolbar"; +import RowActions from "./RowActions"; + +const MachinesReportsList = ({ data, specialFilter }) => { + const columns = useMemo(() => { + return [ + { + accessorKey: "machine_id", + header: "کد یکتا", + id: "machine_id", + enableColumnFilter: false, + enableSorting: false, + datatype: "numeric", + grow: false, + size: 50, + }, + { + accessorKey: "car_name", + header: "مدل ماشین", + id: "car_name", + enableColumnFilter: false, + enableSorting: false, + datatype: "text", + grow: false, + size: 50, + }, + { + accessorKey: "machine_code", + header: "کد ماشین", + id: "machine_code", + enableColumnFilter: false, + enableSorting: false, + datatype: "text", + grow: false, + size: 50, + }, + { + accessorKey: "func", + header: "کارکرد", + id: "func", + enableColumnFilter: false, + enableSorting: false, + datatype: "number", + grow: false, + size: 50, + }, + { + accessorKey: "missions", + header: "تعداد ماموریت", + id: "missions", + enableColumnFilter: false, + enableSorting: false, + datatype: "number", + grow: false, + size: 50, + }, + ]; + }, []); + + return ( + + + + ); +}; + +export default MachinesReportsList; diff --git a/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/MissionDitails/Form/MachineMissionsDetailsDialog/MachineMissionsList/index.jsx b/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/MissionDitails/Form/MachineMissionsDetailsDialog/MachineMissionsList/index.jsx index 9bd3373..36d781a 100644 --- a/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/MissionDitails/Form/MachineMissionsDetailsDialog/MachineMissionsList/index.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/MissionDitails/Form/MachineMissionsDetailsDialog/MachineMissionsList/index.jsx @@ -1,106 +1,106 @@ -import DataTableWithAuth from "@/core/components/DataTableWithAuth"; -import { GET_MACHINE_MISSIONS_DETAILS } from "@/core/utils/routes"; -import { Box } from "@mui/material"; -import { useMemo } from "react"; - -const MachineMissionsList = ({ row }) => { - const columns = useMemo( - () => [ - { - accessorKey: "id", - header: "کد یکتا", - id: "id", - enableColumnFilter: true, - datatype: "text", - filterMode: "equals", - columnFilterModeOptions: ["equals", "contains"], - grow: false, - size: 80, - }, - { - accessorKey: "province_name", - header: "استان", - id: "province_name", - enableColumnFilter: true, - datatype: "text", - filterMode: "equals", - columnFilterModeOptions: ["equals", "contains"], - grow: false, - size: 100, - }, - { - accessorKey: "city_name", - header: "شهر", - id: "city_name", - enableColumnFilter: true, - datatype: "text", - filterMode: "equals", - columnFilterModeOptions: ["equals", "contains"], - grow: false, - size: 100, - }, - { - accessorKey: "station_name", - header: "راهدارخانه", - id: "station_name", - enableColumnFilter: true, - datatype: "text", - filterMode: "equals", - columnFilterModeOptions: ["equals", "contains"], - grow: false, - size: 100, - }, - { - accessorKey: "driver_name", - header: "راننده", - id: "driver_name", - enableColumnFilter: true, - datatype: "text", - filterMode: "equals", - columnFilterModeOptions: ["equals", "contains"], - grow: false, - size: 100, - }, - { - accessorKey: "km", - header: "کیلومتر شروع", - id: "km", - enableColumnFilter: true, - datatype: "text", - filterMode: "equals", - columnFilterModeOptions: ["equals", "contains"], - grow: false, - size: 100, - }, - { - accessorKey: "end_km", - header: "کیلومتر پایان", - id: "end_km", - enableColumnFilter: true, - datatype: "text", - filterMode: "equals", - columnFilterModeOptions: ["equals", "contains"], - grow: false, - size: 100, - }, - ], - [] - ); - - return ( - <> - - - - - ); -}; -export default MachineMissionsList; +import DataTableWithAuth from "@/core/components/DataTableWithAuth"; +import { GET_MACHINE_MISSIONS_DETAILS } from "@/core/utils/routes"; +import { Box } from "@mui/material"; +import { useMemo } from "react"; + +const MachineMissionsList = ({ row }) => { + const columns = useMemo( + () => [ + { + accessorKey: "id", + header: "کد یکتا", + id: "id", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 80, + }, + { + accessorKey: "province_name", + header: "استان", + id: "province_name", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "city_name", + header: "شهر", + id: "city_name", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "station_name", + header: "راهدارخانه", + id: "station_name", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "driver_name", + header: "راننده", + id: "driver_name", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "km", + header: "کیلومتر شروع", + id: "km", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "end_km", + header: "کیلومتر پایان", + id: "end_km", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + ], + [] + ); + + return ( + <> + + + + + ); +}; +export default MachineMissionsList; diff --git a/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/MissionDitails/Form/index.jsx b/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/MissionDitails/Form/index.jsx index 5e79bfa..117e6ea 100644 --- a/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/MissionDitails/Form/index.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/MissionDitails/Form/index.jsx @@ -1,27 +1,27 @@ -import { Box, Button, DialogActions, DialogContent } from "@mui/material"; -import { Stack } from "@mui/system"; -import MachineMissionsList from "./MachineMissionsDetailsDialog/MachineMissionsList"; - -const MachineMissionsDetailsTable = ({ row, setOpenMachineMissionsDetails }) => { - return ( - <> - - - - - - - - - - - - - - - - ); -}; -export default MachineMissionsDetailsTable; +import { Box, Button, DialogActions, DialogContent } from "@mui/material"; +import { Stack } from "@mui/system"; +import MachineMissionsList from "./MachineMissionsDetailsDialog/MachineMissionsList"; + +const MachineMissionsDetailsTable = ({ row, setOpenMachineMissionsDetails }) => { + return ( + <> + + + + + + + + + + + + + + + + ); +}; +export default MachineMissionsDetailsTable; diff --git a/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/MissionDitails/index.jsx b/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/MissionDitails/index.jsx index 3b65c8f..f3ef62e 100644 --- a/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/MissionDitails/index.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/MissionDitails/index.jsx @@ -1,47 +1,47 @@ -import { Close, RemoveRedEye } from "@mui/icons-material"; -import { Dialog, DialogTitle, IconButton, Tooltip } from "@mui/material"; -import { useState } from "react"; -import MachineMissionsDetailsTable from "./Form"; - -const MissionDetails = ({ row }) => { - const [openMachineMissionsDetails, setOpenMachineMissionsDetails] = useState(false); - - return ( - <> - - { - setOpenMachineMissionsDetails(true); - }} - > - - - - - setOpenMachineMissionsDetails(false)} - sx={(theme) => ({ - position: "absolute", - right: 8, - top: 8, - zIndex: 50, - color: theme.palette.grey[500], - })} - > - - - ریز گزارشات خودرو - {openMachineMissionsDetails && ( - - )} - - - ); -}; -export default MissionDetails; +import { Close, RemoveRedEye } from "@mui/icons-material"; +import { Dialog, DialogTitle, IconButton, Tooltip } from "@mui/material"; +import { useState } from "react"; +import MachineMissionsDetailsTable from "./Form"; + +const MissionDetails = ({ row }) => { + const [openMachineMissionsDetails, setOpenMachineMissionsDetails] = useState(false); + + return ( + <> + + { + setOpenMachineMissionsDetails(true); + }} + > + + + + + setOpenMachineMissionsDetails(false)} + sx={(theme) => ({ + position: "absolute", + right: 8, + top: 8, + zIndex: 50, + color: theme.palette.grey[500], + })} + > + + + ریز گزارشات خودرو + {openMachineMissionsDetails && ( + + )} + + + ); +}; +export default MissionDetails; diff --git a/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/RouteDetail/ShowRoute.jsx b/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/RouteDetail/ShowRoute.jsx index 5e1a4bd..7d47ba8 100644 --- a/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/RouteDetail/ShowRoute.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/RouteDetail/ShowRoute.jsx @@ -1,46 +1,46 @@ -import { useEffect, useRef } from "react"; -import { Marker, Polyline, useMap } from "react-leaflet"; -import L from "leaflet"; -import polyline from "@mapbox/polyline"; -import SourceIcon from "@/assets/images/source-icon.svg"; -import DestIcon from "@/assets/images/destination-icon.svg"; - -const ShowRoute = ({ area }) => { - const map = useMap(); - const defaultIconSize = [35, 35]; - - const createCustomIcon = (size, iconUrl) => { - return L.icon({ - iconUrl: iconUrl, - iconSize: size, - iconAnchor: [size[0] / 2, size[1]], - popupAnchor: [0, -size[1]], - }); - }; - - useEffect(() => { - if (coords.length > 0) { - map.flyToBounds(coords, { padding: [50, 50], duration: 1.5 }); - } - }, [area]); - const sourceIcon = createCustomIcon(defaultIconSize, SourceIcon.src); - const destIcon = createCustomIcon(defaultIconSize, DestIcon.src); - - if (!area) return null; - const coords = polyline.decode(area, 6); - - if (coords.length === 0) return null; - - const sourcePosition = coords[0]; - const destPosition = coords[coords.length - 1]; - - return ( - <> - - - - - ); -}; - -export default ShowRoute; +import { useEffect, useRef } from "react"; +import { Marker, Polyline, useMap } from "react-leaflet"; +import L from "leaflet"; +import polyline from "@mapbox/polyline"; +import SourceIcon from "@/assets/images/source-icon.svg"; +import DestIcon from "@/assets/images/destination-icon.svg"; + +const ShowRoute = ({ area }) => { + const map = useMap(); + const defaultIconSize = [35, 35]; + + const createCustomIcon = (size, iconUrl) => { + return L.icon({ + iconUrl: iconUrl, + iconSize: size, + iconAnchor: [size[0] / 2, size[1]], + popupAnchor: [0, -size[1]], + }); + }; + + useEffect(() => { + if (coords.length > 0) { + map.flyToBounds(coords, { padding: [50, 50], duration: 1.5 }); + } + }, [area]); + const sourceIcon = createCustomIcon(defaultIconSize, SourceIcon.src); + const destIcon = createCustomIcon(defaultIconSize, DestIcon.src); + + if (!area) return null; + const coords = polyline.decode(area, 6); + + if (coords.length === 0) return null; + + const sourcePosition = coords[0]; + const destPosition = coords[coords.length - 1]; + + return ( + <> + + + + + ); +}; + +export default ShowRoute; diff --git a/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/RouteDetail/index.jsx b/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/RouteDetail/index.jsx index 4501d35..48b84a2 100644 --- a/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/RouteDetail/index.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/RouteDetail/index.jsx @@ -1,57 +1,57 @@ -import { Box, Button, Dialog, DialogActions, DialogTitle, IconButton, Tooltip } from "@mui/material"; -import { useState } from "react"; -import MapIcon from "@mui/icons-material/Map"; -import MapLayer from "@/core/components/MapLayer"; -import ShowRoute from "./ShowRoute"; - -const RouteDetail = ({ encoded_route }) => { - const [openRouteDetailDialog, setOpenRouteDetailDialog] = useState(false); - return ( - <> - - setOpenRouteDetailDialog(true)}> - - - - setOpenRouteDetailDialog(false)} - PaperProps={{ - sx: { - boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px", - }, - }} - dir="rtl" - maxWidth={"sm"} - > - مسیر انتخابی - - - - - - - - - - - - - ); -}; -export default RouteDetail; +import { Box, Button, Dialog, DialogActions, DialogTitle, IconButton, Tooltip } from "@mui/material"; +import { useState } from "react"; +import MapIcon from "@mui/icons-material/Map"; +import MapLayer from "@/core/components/MapLayer"; +import ShowRoute from "./ShowRoute"; + +const RouteDetail = ({ encoded_route }) => { + const [openRouteDetailDialog, setOpenRouteDetailDialog] = useState(false); + return ( + <> + + setOpenRouteDetailDialog(true)}> + + + + setOpenRouteDetailDialog(false)} + PaperProps={{ + sx: { + boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px", + }, + }} + dir="rtl" + maxWidth={"sm"} + > + مسیر انتخابی + + + + + + + + + + + + + ); +}; +export default RouteDetail; diff --git a/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/index.jsx b/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/index.jsx index dbf9aa7..5cb6a4d 100644 --- a/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/index.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesReports/RowActions/index.jsx @@ -1,6 +1,6 @@ -import MissionDetails from "./MissionDitails"; - -const RowActions = ({ row }) => { - return ; -}; -export default RowActions; +import MissionDetails from "./MissionDitails"; + +const RowActions = ({ row }) => { + return ; +}; +export default RowActions; diff --git a/src/components/dashboard/roadMissions/reports/machinesReports/Search/FromDateController.jsx b/src/components/dashboard/roadMissions/reports/machinesReports/Search/FromDateController.jsx index 490ee7b..0a81488 100644 --- a/src/components/dashboard/roadMissions/reports/machinesReports/Search/FromDateController.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesReports/Search/FromDateController.jsx @@ -1,27 +1,27 @@ -import MuiDatePicker from "@/core/components/MuiDatePicker"; -import moment from "jalali-moment"; -import { Controller } from "react-hook-form"; - -const FromDateController = ({ control }) => { - return ( - ( - { - const formattedDate = moment(new Date(newValue)).locale("en").format("YYYY-MM-DD"); - onChange(formattedDate); // Update the field value in react-hook-form - }} - helperText={error ? error.message : null} - /> - )} - /> - ); -}; -export default FromDateController; +import MuiDatePicker from "@/core/components/MuiDatePicker"; +import moment from "jalali-moment"; +import { Controller } from "react-hook-form"; + +const FromDateController = ({ control }) => { + return ( + ( + { + const formattedDate = moment(new Date(newValue)).locale("en").format("YYYY-MM-DD"); + onChange(formattedDate); // Update the field value in react-hook-form + }} + helperText={error ? error.message : null} + /> + )} + /> + ); +}; +export default FromDateController; diff --git a/src/components/dashboard/roadMissions/reports/machinesReports/Search/SearchReportField.jsx b/src/components/dashboard/roadMissions/reports/machinesReports/Search/SearchReportField.jsx index bde2a4c..e1b71cd 100644 --- a/src/components/dashboard/roadMissions/reports/machinesReports/Search/SearchReportField.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesReports/Search/SearchReportField.jsx @@ -1,44 +1,44 @@ -import SearchIcon from "@mui/icons-material/Search"; -import { Button, Grid } from "@mui/material"; -import { Controller } from "react-hook-form"; -import FromDateController from "./FromDateController"; -import SelectProvince from "./SelectProvince"; -import ToDateController from "./ToDateController"; - -const SearchReportField = ({ control, hasProvincesPermission }) => { - return ( - - - - - - - - {hasProvincesPermission && ( - - - - )} - - ( - - )} - /> - - - ); -}; - -export default SearchReportField; +import SearchIcon from "@mui/icons-material/Search"; +import { Button, Grid } from "@mui/material"; +import { Controller } from "react-hook-form"; +import FromDateController from "./FromDateController"; +import SelectProvince from "./SelectProvince"; +import ToDateController from "./ToDateController"; + +const SearchReportField = ({ control, hasProvincesPermission }) => { + return ( + + + + + + + + {hasProvincesPermission && ( + + + + )} + + ( + + )} + /> + + + ); +}; + +export default SearchReportField; diff --git a/src/components/dashboard/roadMissions/reports/machinesReports/Search/SelectProvince.jsx b/src/components/dashboard/roadMissions/reports/machinesReports/Search/SelectProvince.jsx index 2b24d67..89395f0 100644 --- a/src/components/dashboard/roadMissions/reports/machinesReports/Search/SelectProvince.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesReports/Search/SelectProvince.jsx @@ -1,45 +1,45 @@ -import useProvinces from "@/lib/hooks/useProvince"; -import { FormControl, FormHelperText, InputLabel, MenuItem, Select } from "@mui/material"; -import { Controller } from "react-hook-form"; - -const SelectProvince = ({ control }) => { - const { provinces, loadingProvinces, errorProvinces } = useProvinces(); - return ( - ( - - استان - - {error && {error.message}} - - )} - /> - ); -}; -export default SelectProvince; +import useProvinces from "@/lib/hooks/useProvince"; +import { FormControl, FormHelperText, InputLabel, MenuItem, Select } from "@mui/material"; +import { Controller } from "react-hook-form"; + +const SelectProvince = ({ control }) => { + const { provinces, loadingProvinces, errorProvinces } = useProvinces(); + return ( + ( + + استان + + {error && {error.message}} + + )} + /> + ); +}; +export default SelectProvince; diff --git a/src/components/dashboard/roadMissions/reports/machinesReports/Search/ToDateController.jsx b/src/components/dashboard/roadMissions/reports/machinesReports/Search/ToDateController.jsx index fc4a776..ef3ff49 100644 --- a/src/components/dashboard/roadMissions/reports/machinesReports/Search/ToDateController.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesReports/Search/ToDateController.jsx @@ -1,30 +1,30 @@ -import MuiDatePicker from "@/core/components/MuiDatePicker"; -import moment from "jalali-moment"; -import { Controller, useWatch } from "react-hook-form"; - -const ToDateController = ({ control }) => { - const minDate = useWatch({ control, name: "from_date" }); - return ( - ( - { - const formattedDate = moment(new Date(newValue)).locale("en").format("YYYY-MM-DD"); - onChange(formattedDate); // Update the field value in react-hook-form - }} - helperText={error ? error.message : null} - /> - )} - /> - ); -}; -export default ToDateController; +import MuiDatePicker from "@/core/components/MuiDatePicker"; +import moment from "jalali-moment"; +import { Controller, useWatch } from "react-hook-form"; + +const ToDateController = ({ control }) => { + const minDate = useWatch({ control, name: "from_date" }); + return ( + ( + { + const formattedDate = moment(new Date(newValue)).locale("en").format("YYYY-MM-DD"); + onChange(formattedDate); // Update the field value in react-hook-form + }} + helperText={error ? error.message : null} + /> + )} + /> + ); +}; +export default ToDateController; diff --git a/src/components/dashboard/roadMissions/reports/machinesReports/Search/index.jsx b/src/components/dashboard/roadMissions/reports/machinesReports/Search/index.jsx index f29d302..9d504f2 100644 --- a/src/components/dashboard/roadMissions/reports/machinesReports/Search/index.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesReports/Search/index.jsx @@ -1,13 +1,13 @@ -import StyledForm from "@/core/components/StyledForm"; -import SearchReportField from "./SearchReportField"; - -const SearchReportList = ({ handleSubmit, onSearchSubmit, control, hasProvincesPermission }) => { - return ( - <> - - - - - ); -}; -export default SearchReportList; +import StyledForm from "@/core/components/StyledForm"; +import SearchReportField from "./SearchReportField"; + +const SearchReportList = ({ handleSubmit, onSearchSubmit, control, hasProvincesPermission }) => { + return ( + <> + + + + + ); +}; +export default SearchReportList; diff --git a/src/components/dashboard/roadMissions/reports/machinesReports/Toolbar.jsx b/src/components/dashboard/roadMissions/reports/machinesReports/Toolbar.jsx index 0f726c7..afc132c 100644 --- a/src/components/dashboard/roadMissions/reports/machinesReports/Toolbar.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesReports/Toolbar.jsx @@ -1,11 +1,11 @@ -import { Box } from "@mui/material"; -import PrintExcel from "./ExcelPrint"; - -const Toolbar = ({ table, filterData, mutate }) => { - return ( - - - - ); -}; -export default Toolbar; +import { Box } from "@mui/material"; +import PrintExcel from "./ExcelPrint"; + +const Toolbar = ({ table, filterData, mutate }) => { + return ( + + + + ); +}; +export default Toolbar; diff --git a/src/components/dashboard/roadMissions/reports/machinesReports/index.jsx b/src/components/dashboard/roadMissions/reports/machinesReports/index.jsx index e62f273..655944d 100644 --- a/src/components/dashboard/roadMissions/reports/machinesReports/index.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesReports/index.jsx @@ -1,107 +1,107 @@ -"use client"; -import PageTitle from "@/core/components/PageTitle"; -import { GET_MACHINES_COUNTRY_ACTIVITY_REPORT, GET_MACHINES_PROVINCE_ACTIVITY_REPORT } from "@/core/utils/routes"; -import { useAuth } from "@/lib/contexts/auth"; -import { usePermissions } from "@/lib/hooks/usePermissions"; -import useRequest from "@/lib/hooks/useRequest"; -import { yupResolver } from "@hookform/resolvers/yup"; -import { LinearProgress, Stack } from "@mui/material"; -import moment from "jalali-moment"; -import { useEffect, useState } from "react"; -import { useForm } from "react-hook-form"; -import * as yup from "yup"; -import MachinesReportsList from "./MachinesReportsList"; -import SearchReportList from "./Search"; - -const MachinesReportsPage = () => { - const [data, setData] = useState(null); - const { data: userPermissions } = usePermissions(); - const { user } = useAuth(); - const requestServer = useRequest(); - const hasProvincesPermission = userPermissions?.includes("mission-report-country"); - - const defaultValues = { - from_date: moment(new Date()).format("YYYY-MM-DD"), - date_to: moment(new Date()).format("YYYY-MM-DD"), - province_id: user.province_id || "-1", - }; - const defaultFilter = [ - { value: `${defaultValues.province_id}`, datatype: "numeric", id: "province_id", fn: "equals" }, - { value: `${defaultValues.from_date}`, datatype: "date", id: "from_date", fn: "between" }, - { value: `${defaultValues.date_to}`, datatype: "date", id: "date_to", fn: "between" }, - ]; - const [specialFilter, setSpecialFilter] = useState(defaultFilter); - - const onSearchSubmit = async (data) => { - const params = new URLSearchParams(); - params.set("from_date", `${data.from_date} 00:00:00`); - params.set("date_to", `${data.date_to} 23:59:59`); - setSpecialFilter([ - { value: `${data.province_id}`, datatype: "numeric", id: "province_id", fn: "equals" }, - { value: `${data.from_date}`, datatype: "date", id: "from_date", fn: "between" }, - { value: `${data.date_to}`, datatype: "date", id: "date_to", fn: "between" }, - ]); - if (data.province_id === "-1") { - try { - const response = await requestServer(`${GET_MACHINES_COUNTRY_ACTIVITY_REPORT}?${params}`); - const result = response.data.data; - - setData({ - data: result.activities, - filters: data, - }); - } catch (e) {} - } else { - try { - params.set("province_id", `${data.province_id}`); - const response = await requestServer(`${GET_MACHINES_PROVINCE_ACTIVITY_REPORT}?${params}`); - - const result = response.data.data; - - setData({ - data: result.activities, - filters: data, - }); - } catch (e) {} - } - }; - - useEffect(() => { - if (!userPermissions) return; - onSearchSubmit(defaultValues); - }, [userPermissions]); - - const validationSchema = yup.object().shape({ - from_date: yup - .string() - .required("تاریخ شروع الزامی است!") - .matches(/^\d{4}-\d{2}-\d{2}$/, "تاریخ شروع الزامی است!") - .test("is-valid-date", "تاریخ شروع معتبر نیست!", (value) => moment(value, "YYYY-MM-DD", true).isValid()), - date_to: yup - .string() - .required("تاریخ پایان الزامی است!") - .matches(/^\d{4}-\d{2}-\d{2}$/, "تاریخ پایان الزامی است!") - .test("is-valid-date", "تاریخ پایان معتبر نیست!", (value) => moment(value, "YYYY-MM-DD", true).isValid()), - province_id: yup.string().nullable(), - }); - - const { control, handleSubmit } = useForm({ - defaultValues, - resolver: yupResolver(validationSchema), - mode: "all", - }); - - return ( - - - - {!data ? : } - - ); -}; -export default MachinesReportsPage; +"use client"; +import PageTitle from "@/core/components/PageTitle"; +import { GET_MACHINES_COUNTRY_ACTIVITY_REPORT, GET_MACHINES_PROVINCE_ACTIVITY_REPORT } from "@/core/utils/routes"; +import { useAuth } from "@/lib/contexts/auth"; +import { usePermissions } from "@/lib/hooks/usePermissions"; +import useRequest from "@/lib/hooks/useRequest"; +import { yupResolver } from "@hookform/resolvers/yup"; +import { LinearProgress, Stack } from "@mui/material"; +import moment from "jalali-moment"; +import { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; +import * as yup from "yup"; +import MachinesReportsList from "./MachinesReportsList"; +import SearchReportList from "./Search"; + +const MachinesReportsPage = () => { + const [data, setData] = useState(null); + const { data: userPermissions } = usePermissions(); + const { user } = useAuth(); + const requestServer = useRequest(); + const hasProvincesPermission = userPermissions?.includes("mission-report-country"); + + const defaultValues = { + from_date: moment(new Date()).format("YYYY-MM-DD"), + date_to: moment(new Date()).format("YYYY-MM-DD"), + province_id: user.province_id || "-1", + }; + const defaultFilter = [ + { value: `${defaultValues.province_id}`, datatype: "numeric", id: "province_id", fn: "equals" }, + { value: `${defaultValues.from_date}`, datatype: "date", id: "from_date", fn: "between" }, + { value: `${defaultValues.date_to}`, datatype: "date", id: "date_to", fn: "between" }, + ]; + const [specialFilter, setSpecialFilter] = useState(defaultFilter); + + const onSearchSubmit = async (data) => { + const params = new URLSearchParams(); + params.set("from_date", `${data.from_date} 00:00:00`); + params.set("date_to", `${data.date_to} 23:59:59`); + setSpecialFilter([ + { value: `${data.province_id}`, datatype: "numeric", id: "province_id", fn: "equals" }, + { value: `${data.from_date}`, datatype: "date", id: "from_date", fn: "between" }, + { value: `${data.date_to}`, datatype: "date", id: "date_to", fn: "between" }, + ]); + if (data.province_id === "-1") { + try { + const response = await requestServer(`${GET_MACHINES_COUNTRY_ACTIVITY_REPORT}?${params}`); + const result = response.data.data; + + setData({ + data: result.activities, + filters: data, + }); + } catch (e) {} + } else { + try { + params.set("province_id", `${data.province_id}`); + const response = await requestServer(`${GET_MACHINES_PROVINCE_ACTIVITY_REPORT}?${params}`); + + const result = response.data.data; + + setData({ + data: result.activities, + filters: data, + }); + } catch (e) {} + } + }; + + useEffect(() => { + if (!userPermissions) return; + onSearchSubmit(defaultValues); + }, [userPermissions]); + + const validationSchema = yup.object().shape({ + from_date: yup + .string() + .required("تاریخ شروع الزامی است!") + .matches(/^\d{4}-\d{2}-\d{2}$/, "تاریخ شروع الزامی است!") + .test("is-valid-date", "تاریخ شروع معتبر نیست!", (value) => moment(value, "YYYY-MM-DD", true).isValid()), + date_to: yup + .string() + .required("تاریخ پایان الزامی است!") + .matches(/^\d{4}-\d{2}-\d{2}$/, "تاریخ پایان الزامی است!") + .test("is-valid-date", "تاریخ پایان معتبر نیست!", (value) => moment(value, "YYYY-MM-DD", true).isValid()), + province_id: yup.string().nullable(), + }); + + const { control, handleSubmit } = useForm({ + defaultValues, + resolver: yupResolver(validationSchema), + mode: "all", + }); + + return ( + + + + {!data ? : } + + ); +}; +export default MachinesReportsPage; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/MachinesReportsList.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/MachinesReportsList.jsx index 5fb261d..4f8b994 100644 --- a/src/components/dashboard/roadMissions/reports/machinesTypeReports/MachinesReportsList.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/MachinesReportsList.jsx @@ -1,61 +1,61 @@ -"use client"; -import DataTableWithAuth from "@/core/components/DataTableWithAuth"; -import { Box } from "@mui/material"; -import { useMemo } from "react"; -import Toolbar from "./Toolbar"; -// import RowActions from "./RowActions"; - -const MachinesReportsList = ({ data, specialFilter }) => { - const columns = useMemo(() => { - return [ - { - accessorKey: "car_type", - header: "نوع ماشین", - id: "car_type", - enableColumnFilter: false, - enableSorting: false, - datatype: "text", - grow: false, - size: 50, - }, - { - accessorKey: "func", - header: "کارکرد", - id: "func", - enableColumnFilter: false, - enableSorting: false, - datatype: "number", - grow: false, - size: 50, - }, - { - accessorKey: "missions", - header: "تعداد ماموریت", - id: "missions", - enableColumnFilter: false, - enableSorting: false, - datatype: "number", - grow: false, - size: 50, - }, - ]; - }, []); - - return ( - - - - ); -}; - -export default MachinesReportsList; +"use client"; +import DataTableWithAuth from "@/core/components/DataTableWithAuth"; +import { Box } from "@mui/material"; +import { useMemo } from "react"; +import Toolbar from "./Toolbar"; +// import RowActions from "./RowActions"; + +const MachinesReportsList = ({ data, specialFilter }) => { + const columns = useMemo(() => { + return [ + { + accessorKey: "car_type", + header: "نوع ماشین", + id: "car_type", + enableColumnFilter: false, + enableSorting: false, + datatype: "text", + grow: false, + size: 50, + }, + { + accessorKey: "func", + header: "کارکرد", + id: "func", + enableColumnFilter: false, + enableSorting: false, + datatype: "number", + grow: false, + size: 50, + }, + { + accessorKey: "missions", + header: "تعداد ماموریت", + id: "missions", + enableColumnFilter: false, + enableSorting: false, + datatype: "number", + grow: false, + size: 50, + }, + ]; + }, []); + + return ( + + + + ); +}; + +export default MachinesReportsList; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/MissionDitails/Form/MachineMissionsDetailsDialog/MachineMissionsList/index.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/MissionDitails/Form/MachineMissionsDetailsDialog/MachineMissionsList/index.jsx index ada49f4..87f612d 100644 --- a/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/MissionDitails/Form/MachineMissionsDetailsDialog/MachineMissionsList/index.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/MissionDitails/Form/MachineMissionsDetailsDialog/MachineMissionsList/index.jsx @@ -1,106 +1,106 @@ -import DataTableWithAuth from "@/core/components/DataTableWithAuth"; -import { GET_MACHINE_MISSIONS_DETAILS, GET_MACHINE_TYPE_MISSIONS_DETAILS } from "@/core/utils/routes"; -import { Box } from "@mui/material"; -import { useMemo } from "react"; - -const MachineMissionsList = ({ row }) => { - const columns = useMemo( - () => [ - { - accessorKey: "id", - header: "کد یکتا", - id: "id", - enableColumnFilter: true, - datatype: "text", - filterMode: "equals", - columnFilterModeOptions: ["equals", "contains"], - grow: false, - size: 80, - }, - { - accessorKey: "province_name", - header: "استان", - id: "province_name", - enableColumnFilter: true, - datatype: "text", - filterMode: "equals", - columnFilterModeOptions: ["equals", "contains"], - grow: false, - size: 100, - }, - { - accessorKey: "city_name", - header: "شهر", - id: "city_name", - enableColumnFilter: true, - datatype: "text", - filterMode: "equals", - columnFilterModeOptions: ["equals", "contains"], - grow: false, - size: 100, - }, - { - accessorKey: "station_name", - header: "راهدارخانه", - id: "station_name", - enableColumnFilter: true, - datatype: "text", - filterMode: "equals", - columnFilterModeOptions: ["equals", "contains"], - grow: false, - size: 100, - }, - { - accessorKey: "driver_name", - header: "راننده", - id: "driver_name", - enableColumnFilter: true, - datatype: "text", - filterMode: "equals", - columnFilterModeOptions: ["equals", "contains"], - grow: false, - size: 100, - }, - { - accessorKey: "km", - header: "کیلومتر شروع", - id: "km", - enableColumnFilter: true, - datatype: "text", - filterMode: "equals", - columnFilterModeOptions: ["equals", "contains"], - grow: false, - size: 100, - }, - { - accessorKey: "end_km", - header: "کیلومتر پایان", - id: "end_km", - enableColumnFilter: true, - datatype: "text", - filterMode: "equals", - columnFilterModeOptions: ["equals", "contains"], - grow: false, - size: 100, - }, - ], - [] - ); - - return ( - <> - - - - - ); -}; -export default MachineMissionsList; +import DataTableWithAuth from "@/core/components/DataTableWithAuth"; +import { GET_MACHINE_MISSIONS_DETAILS, GET_MACHINE_TYPE_MISSIONS_DETAILS } from "@/core/utils/routes"; +import { Box } from "@mui/material"; +import { useMemo } from "react"; + +const MachineMissionsList = ({ row }) => { + const columns = useMemo( + () => [ + { + accessorKey: "id", + header: "کد یکتا", + id: "id", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 80, + }, + { + accessorKey: "province_name", + header: "استان", + id: "province_name", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "city_name", + header: "شهر", + id: "city_name", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "station_name", + header: "راهدارخانه", + id: "station_name", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "driver_name", + header: "راننده", + id: "driver_name", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "km", + header: "کیلومتر شروع", + id: "km", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "end_km", + header: "کیلومتر پایان", + id: "end_km", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + ], + [] + ); + + return ( + <> + + + + + ); +}; +export default MachineMissionsList; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/MissionDitails/Form/index.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/MissionDitails/Form/index.jsx index 5e79bfa..117e6ea 100644 --- a/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/MissionDitails/Form/index.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/MissionDitails/Form/index.jsx @@ -1,27 +1,27 @@ -import { Box, Button, DialogActions, DialogContent } from "@mui/material"; -import { Stack } from "@mui/system"; -import MachineMissionsList from "./MachineMissionsDetailsDialog/MachineMissionsList"; - -const MachineMissionsDetailsTable = ({ row, setOpenMachineMissionsDetails }) => { - return ( - <> - - - - - - - - - - - - - - - - ); -}; -export default MachineMissionsDetailsTable; +import { Box, Button, DialogActions, DialogContent } from "@mui/material"; +import { Stack } from "@mui/system"; +import MachineMissionsList from "./MachineMissionsDetailsDialog/MachineMissionsList"; + +const MachineMissionsDetailsTable = ({ row, setOpenMachineMissionsDetails }) => { + return ( + <> + + + + + + + + + + + + + + + + ); +}; +export default MachineMissionsDetailsTable; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/MissionDitails/index.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/MissionDitails/index.jsx index 21a8263..05be524 100644 --- a/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/MissionDitails/index.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/MissionDitails/index.jsx @@ -1,47 +1,47 @@ -import { Close, RemoveRedEye } from "@mui/icons-material"; -import { Dialog, DialogTitle, IconButton, Tooltip } from "@mui/material"; -import { useState } from "react"; -import MachineMissionsDetailsTable from "./Form"; - -const MissionDetails = ({ row }) => { - const [openMachineMissionsDetails, setOpenMachineMissionsDetails] = useState(false); - - return ( - <> - - { - setOpenMachineMissionsDetails(true); - }} - > - - - - - setOpenMachineMissionsDetails(false)} - sx={(theme) => ({ - position: "absolute", - right: 8, - top: 8, - zIndex: 50, - color: theme.palette.grey[500], - })} - > - - - ریز گزارشات نوع خودرو - {openMachineMissionsDetails && ( - - )} - - - ); -}; -export default MissionDetails; +import { Close, RemoveRedEye } from "@mui/icons-material"; +import { Dialog, DialogTitle, IconButton, Tooltip } from "@mui/material"; +import { useState } from "react"; +import MachineMissionsDetailsTable from "./Form"; + +const MissionDetails = ({ row }) => { + const [openMachineMissionsDetails, setOpenMachineMissionsDetails] = useState(false); + + return ( + <> + + { + setOpenMachineMissionsDetails(true); + }} + > + + + + + setOpenMachineMissionsDetails(false)} + sx={(theme) => ({ + position: "absolute", + right: 8, + top: 8, + zIndex: 50, + color: theme.palette.grey[500], + })} + > + + + ریز گزارشات نوع خودرو + {openMachineMissionsDetails && ( + + )} + + + ); +}; +export default MissionDetails; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/RouteDetail/ShowRoute.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/RouteDetail/ShowRoute.jsx index 5e1a4bd..7d47ba8 100644 --- a/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/RouteDetail/ShowRoute.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/RouteDetail/ShowRoute.jsx @@ -1,46 +1,46 @@ -import { useEffect, useRef } from "react"; -import { Marker, Polyline, useMap } from "react-leaflet"; -import L from "leaflet"; -import polyline from "@mapbox/polyline"; -import SourceIcon from "@/assets/images/source-icon.svg"; -import DestIcon from "@/assets/images/destination-icon.svg"; - -const ShowRoute = ({ area }) => { - const map = useMap(); - const defaultIconSize = [35, 35]; - - const createCustomIcon = (size, iconUrl) => { - return L.icon({ - iconUrl: iconUrl, - iconSize: size, - iconAnchor: [size[0] / 2, size[1]], - popupAnchor: [0, -size[1]], - }); - }; - - useEffect(() => { - if (coords.length > 0) { - map.flyToBounds(coords, { padding: [50, 50], duration: 1.5 }); - } - }, [area]); - const sourceIcon = createCustomIcon(defaultIconSize, SourceIcon.src); - const destIcon = createCustomIcon(defaultIconSize, DestIcon.src); - - if (!area) return null; - const coords = polyline.decode(area, 6); - - if (coords.length === 0) return null; - - const sourcePosition = coords[0]; - const destPosition = coords[coords.length - 1]; - - return ( - <> - - - - - ); -}; - -export default ShowRoute; +import { useEffect, useRef } from "react"; +import { Marker, Polyline, useMap } from "react-leaflet"; +import L from "leaflet"; +import polyline from "@mapbox/polyline"; +import SourceIcon from "@/assets/images/source-icon.svg"; +import DestIcon from "@/assets/images/destination-icon.svg"; + +const ShowRoute = ({ area }) => { + const map = useMap(); + const defaultIconSize = [35, 35]; + + const createCustomIcon = (size, iconUrl) => { + return L.icon({ + iconUrl: iconUrl, + iconSize: size, + iconAnchor: [size[0] / 2, size[1]], + popupAnchor: [0, -size[1]], + }); + }; + + useEffect(() => { + if (coords.length > 0) { + map.flyToBounds(coords, { padding: [50, 50], duration: 1.5 }); + } + }, [area]); + const sourceIcon = createCustomIcon(defaultIconSize, SourceIcon.src); + const destIcon = createCustomIcon(defaultIconSize, DestIcon.src); + + if (!area) return null; + const coords = polyline.decode(area, 6); + + if (coords.length === 0) return null; + + const sourcePosition = coords[0]; + const destPosition = coords[coords.length - 1]; + + return ( + <> + + + + + ); +}; + +export default ShowRoute; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/RouteDetail/index.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/RouteDetail/index.jsx index 4501d35..48b84a2 100644 --- a/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/RouteDetail/index.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/RouteDetail/index.jsx @@ -1,57 +1,57 @@ -import { Box, Button, Dialog, DialogActions, DialogTitle, IconButton, Tooltip } from "@mui/material"; -import { useState } from "react"; -import MapIcon from "@mui/icons-material/Map"; -import MapLayer from "@/core/components/MapLayer"; -import ShowRoute from "./ShowRoute"; - -const RouteDetail = ({ encoded_route }) => { - const [openRouteDetailDialog, setOpenRouteDetailDialog] = useState(false); - return ( - <> - - setOpenRouteDetailDialog(true)}> - - - - setOpenRouteDetailDialog(false)} - PaperProps={{ - sx: { - boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px", - }, - }} - dir="rtl" - maxWidth={"sm"} - > - مسیر انتخابی - - - - - - - - - - - - - ); -}; -export default RouteDetail; +import { Box, Button, Dialog, DialogActions, DialogTitle, IconButton, Tooltip } from "@mui/material"; +import { useState } from "react"; +import MapIcon from "@mui/icons-material/Map"; +import MapLayer from "@/core/components/MapLayer"; +import ShowRoute from "./ShowRoute"; + +const RouteDetail = ({ encoded_route }) => { + const [openRouteDetailDialog, setOpenRouteDetailDialog] = useState(false); + return ( + <> + + setOpenRouteDetailDialog(true)}> + + + + setOpenRouteDetailDialog(false)} + PaperProps={{ + sx: { + boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px", + }, + }} + dir="rtl" + maxWidth={"sm"} + > + مسیر انتخابی + + + + + + + + + + + + + ); +}; +export default RouteDetail; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/index.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/index.jsx index 2690157..9f5e29d 100644 --- a/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/index.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/RowActions/index.jsx @@ -1,10 +1,6 @@ -// import MissionDetails from "./MissionDitails"; - -const RowActions = ({ row }) => { - return ( - <> - {/**/} - - ); -}; -export default RowActions; +// import MissionDetails from "./MissionDitails"; + +const RowActions = ({ row }) => { + return <>{/**/}; +}; +export default RowActions; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/FromDateController.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/FromDateController.jsx index 490ee7b..0a81488 100644 --- a/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/FromDateController.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/FromDateController.jsx @@ -1,27 +1,27 @@ -import MuiDatePicker from "@/core/components/MuiDatePicker"; -import moment from "jalali-moment"; -import { Controller } from "react-hook-form"; - -const FromDateController = ({ control }) => { - return ( - ( - { - const formattedDate = moment(new Date(newValue)).locale("en").format("YYYY-MM-DD"); - onChange(formattedDate); // Update the field value in react-hook-form - }} - helperText={error ? error.message : null} - /> - )} - /> - ); -}; -export default FromDateController; +import MuiDatePicker from "@/core/components/MuiDatePicker"; +import moment from "jalali-moment"; +import { Controller } from "react-hook-form"; + +const FromDateController = ({ control }) => { + return ( + ( + { + const formattedDate = moment(new Date(newValue)).locale("en").format("YYYY-MM-DD"); + onChange(formattedDate); // Update the field value in react-hook-form + }} + helperText={error ? error.message : null} + /> + )} + /> + ); +}; +export default FromDateController; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/SearchReportField.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/SearchReportField.jsx index bde2a4c..e1b71cd 100644 --- a/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/SearchReportField.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/SearchReportField.jsx @@ -1,44 +1,44 @@ -import SearchIcon from "@mui/icons-material/Search"; -import { Button, Grid } from "@mui/material"; -import { Controller } from "react-hook-form"; -import FromDateController from "./FromDateController"; -import SelectProvince from "./SelectProvince"; -import ToDateController from "./ToDateController"; - -const SearchReportField = ({ control, hasProvincesPermission }) => { - return ( - - - - - - - - {hasProvincesPermission && ( - - - - )} - - ( - - )} - /> - - - ); -}; - -export default SearchReportField; +import SearchIcon from "@mui/icons-material/Search"; +import { Button, Grid } from "@mui/material"; +import { Controller } from "react-hook-form"; +import FromDateController from "./FromDateController"; +import SelectProvince from "./SelectProvince"; +import ToDateController from "./ToDateController"; + +const SearchReportField = ({ control, hasProvincesPermission }) => { + return ( + + + + + + + + {hasProvincesPermission && ( + + + + )} + + ( + + )} + /> + + + ); +}; + +export default SearchReportField; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/SelectProvince.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/SelectProvince.jsx index 2b24d67..89395f0 100644 --- a/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/SelectProvince.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/SelectProvince.jsx @@ -1,45 +1,45 @@ -import useProvinces from "@/lib/hooks/useProvince"; -import { FormControl, FormHelperText, InputLabel, MenuItem, Select } from "@mui/material"; -import { Controller } from "react-hook-form"; - -const SelectProvince = ({ control }) => { - const { provinces, loadingProvinces, errorProvinces } = useProvinces(); - return ( - ( - - استان - - {error && {error.message}} - - )} - /> - ); -}; -export default SelectProvince; +import useProvinces from "@/lib/hooks/useProvince"; +import { FormControl, FormHelperText, InputLabel, MenuItem, Select } from "@mui/material"; +import { Controller } from "react-hook-form"; + +const SelectProvince = ({ control }) => { + const { provinces, loadingProvinces, errorProvinces } = useProvinces(); + return ( + ( + + استان + + {error && {error.message}} + + )} + /> + ); +}; +export default SelectProvince; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/ToDateController.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/ToDateController.jsx index fc4a776..ef3ff49 100644 --- a/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/ToDateController.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/ToDateController.jsx @@ -1,30 +1,30 @@ -import MuiDatePicker from "@/core/components/MuiDatePicker"; -import moment from "jalali-moment"; -import { Controller, useWatch } from "react-hook-form"; - -const ToDateController = ({ control }) => { - const minDate = useWatch({ control, name: "from_date" }); - return ( - ( - { - const formattedDate = moment(new Date(newValue)).locale("en").format("YYYY-MM-DD"); - onChange(formattedDate); // Update the field value in react-hook-form - }} - helperText={error ? error.message : null} - /> - )} - /> - ); -}; -export default ToDateController; +import MuiDatePicker from "@/core/components/MuiDatePicker"; +import moment from "jalali-moment"; +import { Controller, useWatch } from "react-hook-form"; + +const ToDateController = ({ control }) => { + const minDate = useWatch({ control, name: "from_date" }); + return ( + ( + { + const formattedDate = moment(new Date(newValue)).locale("en").format("YYYY-MM-DD"); + onChange(formattedDate); // Update the field value in react-hook-form + }} + helperText={error ? error.message : null} + /> + )} + /> + ); +}; +export default ToDateController; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/index.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/index.jsx index f29d302..9d504f2 100644 --- a/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/index.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/Search/index.jsx @@ -1,13 +1,13 @@ -import StyledForm from "@/core/components/StyledForm"; -import SearchReportField from "./SearchReportField"; - -const SearchReportList = ({ handleSubmit, onSearchSubmit, control, hasProvincesPermission }) => { - return ( - <> - - - - - ); -}; -export default SearchReportList; +import StyledForm from "@/core/components/StyledForm"; +import SearchReportField from "./SearchReportField"; + +const SearchReportList = ({ handleSubmit, onSearchSubmit, control, hasProvincesPermission }) => { + return ( + <> + + + + + ); +}; +export default SearchReportList; diff --git a/src/components/dashboard/roadMissions/reports/machinesTypeReports/Toolbar.jsx b/src/components/dashboard/roadMissions/reports/machinesTypeReports/Toolbar.jsx index 0f726c7..afc132c 100644 --- a/src/components/dashboard/roadMissions/reports/machinesTypeReports/Toolbar.jsx +++ b/src/components/dashboard/roadMissions/reports/machinesTypeReports/Toolbar.jsx @@ -1,11 +1,11 @@ -import { Box } from "@mui/material"; -import PrintExcel from "./ExcelPrint"; - -const Toolbar = ({ table, filterData, mutate }) => { - return ( - - - - ); -}; -export default Toolbar; +import { Box } from "@mui/material"; +import PrintExcel from "./ExcelPrint"; + +const Toolbar = ({ table, filterData, mutate }) => { + return ( + + + + ); +}; +export default Toolbar; diff --git a/src/core/utils/routes.js b/src/core/utils/routes.js index d77593e..e8cd60f 100644 --- a/src/core/utils/routes.js +++ b/src/core/utils/routes.js @@ -256,8 +256,10 @@ export const EXPORT_GET_MACHINES_COUNTRY_ACTIVITY_REPORT = export const EXPORT_GET_MACHINES_PROVINCE_ACTIVITY_REPORT = api + "/api/v3/missions/report_machine/province_machines_activity_excel"; -export const GET_DRIVER_COUNTRY_ACTIVITY_REPORT = api + "/api/v3/missions/report_machine/country_machine_drivers_activity"; -export const GET_DRIVER_PROVINCE_ACTIVITY_REPORT = api + "/api/v3/missions/report_machine/province_machine_drivers_activity"; +export const GET_DRIVER_COUNTRY_ACTIVITY_REPORT = + api + "/api/v3/missions/report_machine/country_machine_drivers_activity"; +export const GET_DRIVER_PROVINCE_ACTIVITY_REPORT = + api + "/api/v3/missions/report_machine/province_machine_drivers_activity"; export const EXPORT_GET_DRIVER_COUNTRY_ACTIVITY_REPORT = api + "/api/v3/missions/report_machine/country_machine_drivers_activity_excel"; export const EXPORT_GET_DRIVER_PROVINCE_ACTIVITY_REPORT = @@ -265,7 +267,8 @@ export const EXPORT_GET_DRIVER_PROVINCE_ACTIVITY_REPORT = export const GET_MACHINES_TYPE_COUNTRY_ACTIVITY_REPORT = api + "/api/v3/missions/report_machine/country_machine_types_activity"; -export const GET_MACHINES_TYPE_PROVINCE_ACTIVITY_REPORT = api + "/api/v3/missions/report_machine/province_machine_types_activity"; +export const GET_MACHINES_TYPE_PROVINCE_ACTIVITY_REPORT = + api + "/api/v3/missions/report_machine/province_machine_types_activity"; export const EXPORT_GET_MACHINES_TYPE_COUNTRY_ACTIVITY_REPORT = api + "/api/v3/missions/report_machine/country_machine_types_activity_excel"; export const EXPORT_GET_MACHINES_TYPE_PROVINCE_ACTIVITY_REPORT = -- 2.49.1 From 241f5835722f7e30f0c3089f161672bc95a40512 Mon Sep 17 00:00:00 2001 From: AminGhasempoor Date: Sun, 14 Jun 2026 11:50:40 +0330 Subject: [PATCH 4/4] merge develop --- .../Dialog/Form/Area/Routing/AlarmText.jsx | 56 +-- .../Dialog/Form/Area/Routing/DataBox.jsx | 106 ++--- .../Dialog/Form/Area/Routing/ShowRoute.jsx | 92 ++-- .../Dialog/Form/Area/Routing/index.jsx | 438 +++++++++--------- 4 files changed, 346 insertions(+), 346 deletions(-) diff --git a/src/components/dashboard/roadMissions/operator/RowActions/Add/AddController/Dialog/Form/Area/Routing/AlarmText.jsx b/src/components/dashboard/roadMissions/operator/RowActions/Add/AddController/Dialog/Form/Area/Routing/AlarmText.jsx index 0a3be1b..0ddf8a0 100644 --- a/src/components/dashboard/roadMissions/operator/RowActions/Add/AddController/Dialog/Form/Area/Routing/AlarmText.jsx +++ b/src/components/dashboard/roadMissions/operator/RowActions/Add/AddController/Dialog/Form/Area/Routing/AlarmText.jsx @@ -1,28 +1,28 @@ -import { Box, Typography } from "@mui/material"; - -const AlarmText = ({ isSource }) => { - if (isSource) return null; - return ( - - - با کلیک بر روی مارکر موقعیت را انتخاب کنید - - - ); -}; - -export default AlarmText; +import { Box, Typography } from "@mui/material"; + +const AlarmText = ({ isSource }) => { + if (isSource) return null; + return ( + + + با کلیک بر روی مارکر موقعیت را انتخاب کنید + + + ); +}; + +export default AlarmText; diff --git a/src/components/dashboard/roadMissions/operator/RowActions/Add/AddController/Dialog/Form/Area/Routing/DataBox.jsx b/src/components/dashboard/roadMissions/operator/RowActions/Add/AddController/Dialog/Form/Area/Routing/DataBox.jsx index c19cb6f..5768f75 100644 --- a/src/components/dashboard/roadMissions/operator/RowActions/Add/AddController/Dialog/Form/Area/Routing/DataBox.jsx +++ b/src/components/dashboard/roadMissions/operator/RowActions/Add/AddController/Dialog/Form/Area/Routing/DataBox.jsx @@ -1,53 +1,53 @@ -import { Box, Button, TextField } from "@mui/material"; - -const DataBox = ({ isSource, isDest, sourcePosition, destPosition, editingTarget, onEditSource, onEditDest }) => { - if (!isSource) return null; - - return ( - -
- - {isSource && isDest && ( - - )} -
- {isDest && ( -
- - -
- )} -
- ); -}; - -export default DataBox; +import { Box, Button, TextField } from "@mui/material"; + +const DataBox = ({ isSource, isDest, sourcePosition, destPosition, editingTarget, onEditSource, onEditDest }) => { + if (!isSource) return null; + + return ( + +
+ + {isSource && isDest && ( + + )} +
+ {isDest && ( +
+ + +
+ )} +
+ ); +}; + +export default DataBox; diff --git a/src/components/dashboard/roadMissions/operator/RowActions/Add/AddController/Dialog/Form/Area/Routing/ShowRoute.jsx b/src/components/dashboard/roadMissions/operator/RowActions/Add/AddController/Dialog/Form/Area/Routing/ShowRoute.jsx index 5e1a4bd..7d47ba8 100644 --- a/src/components/dashboard/roadMissions/operator/RowActions/Add/AddController/Dialog/Form/Area/Routing/ShowRoute.jsx +++ b/src/components/dashboard/roadMissions/operator/RowActions/Add/AddController/Dialog/Form/Area/Routing/ShowRoute.jsx @@ -1,46 +1,46 @@ -import { useEffect, useRef } from "react"; -import { Marker, Polyline, useMap } from "react-leaflet"; -import L from "leaflet"; -import polyline from "@mapbox/polyline"; -import SourceIcon from "@/assets/images/source-icon.svg"; -import DestIcon from "@/assets/images/destination-icon.svg"; - -const ShowRoute = ({ area }) => { - const map = useMap(); - const defaultIconSize = [35, 35]; - - const createCustomIcon = (size, iconUrl) => { - return L.icon({ - iconUrl: iconUrl, - iconSize: size, - iconAnchor: [size[0] / 2, size[1]], - popupAnchor: [0, -size[1]], - }); - }; - - useEffect(() => { - if (coords.length > 0) { - map.flyToBounds(coords, { padding: [50, 50], duration: 1.5 }); - } - }, [area]); - const sourceIcon = createCustomIcon(defaultIconSize, SourceIcon.src); - const destIcon = createCustomIcon(defaultIconSize, DestIcon.src); - - if (!area) return null; - const coords = polyline.decode(area, 6); - - if (coords.length === 0) return null; - - const sourcePosition = coords[0]; - const destPosition = coords[coords.length - 1]; - - return ( - <> - - - - - ); -}; - -export default ShowRoute; +import { useEffect, useRef } from "react"; +import { Marker, Polyline, useMap } from "react-leaflet"; +import L from "leaflet"; +import polyline from "@mapbox/polyline"; +import SourceIcon from "@/assets/images/source-icon.svg"; +import DestIcon from "@/assets/images/destination-icon.svg"; + +const ShowRoute = ({ area }) => { + const map = useMap(); + const defaultIconSize = [35, 35]; + + const createCustomIcon = (size, iconUrl) => { + return L.icon({ + iconUrl: iconUrl, + iconSize: size, + iconAnchor: [size[0] / 2, size[1]], + popupAnchor: [0, -size[1]], + }); + }; + + useEffect(() => { + if (coords.length > 0) { + map.flyToBounds(coords, { padding: [50, 50], duration: 1.5 }); + } + }, [area]); + const sourceIcon = createCustomIcon(defaultIconSize, SourceIcon.src); + const destIcon = createCustomIcon(defaultIconSize, DestIcon.src); + + if (!area) return null; + const coords = polyline.decode(area, 6); + + if (coords.length === 0) return null; + + const sourcePosition = coords[0]; + const destPosition = coords[coords.length - 1]; + + return ( + <> + + + + + ); +}; + +export default ShowRoute; diff --git a/src/components/dashboard/roadMissions/operator/RowActions/Add/AddController/Dialog/Form/Area/Routing/index.jsx b/src/components/dashboard/roadMissions/operator/RowActions/Add/AddController/Dialog/Form/Area/Routing/index.jsx index 06e7c9b..49c4651 100644 --- a/src/components/dashboard/roadMissions/operator/RowActions/Add/AddController/Dialog/Form/Area/Routing/index.jsx +++ b/src/components/dashboard/roadMissions/operator/RowActions/Add/AddController/Dialog/Form/Area/Routing/index.jsx @@ -1,219 +1,219 @@ -import { Marker, Polyline, useMapEvents } from "react-leaflet"; -import L from "leaflet"; -import polyline from "@mapbox/polyline"; -import SourceIcon from "@/assets/images/source-icon.svg"; -import PrevSourceIcon from "@/assets/images/prev-source-icon.svg"; -import PrevDestIcon from "@/assets/images/prev-destination-icon.svg"; -import DestIcon from "@/assets/images/destination-icon.svg"; -import { useEffect, useRef, useState } from "react"; -import DataBox from "./DataBox"; -import AlarmText from "./AlarmText"; - -const Routing = ({ setArea, setLocations, locations, area }) => { - const mapPrevSourceMarker = useRef(); - const mapPrevDestMarker = useRef(); - const mapRef = useRef(null); - const defaultIconSize = [35, 35]; - const [isSource, setIsSource] = useState(false); - const [sourcePosition, setSourcePosition] = useState(null); - const [isDest, setIsDest] = useState(false); - const [destPosition, setDestPosition] = useState(null); - const [routeCoords, setRouteCoords] = useState([]); - const [alternateCoords, setAlternateCoords] = useState([]); - const [editingTarget, setEditingTarget] = useState(null); - const [selectedRoute, setSelectedRoute] = useState(null); - - const createCustomIcon = (size, iconUrl) => { - return L.icon({ - iconUrl: iconUrl, - iconSize: size, - iconAnchor: [size[0] / 2, size[1]], - popupAnchor: [0, -size[1]], - }); - }; - - const defaultIcon = createCustomIcon( - defaultIconSize, - isSource && editingTarget !== "source" ? SourceIcon.src : PrevSourceIcon.src - ); - - const prevDestIcon = createCustomIcon( - defaultIconSize, - isDest && editingTarget !== "dest" ? DestIcon.src : PrevDestIcon.src - ); - - const isMovingSource = !isSource || editingTarget === "source"; - const isMovingDest = isSource && (!isDest || editingTarget === "dest"); - - const map = useMapEvents({ - move(e) { - if (isMovingSource) mapPrevSourceMarker.current.setLatLng(e.target.getCenter()); - if (isMovingDest && mapPrevDestMarker.current) mapPrevDestMarker.current.setLatLng(e.target.getCenter()); - }, - movestart() { - if (isMovingSource) mapPrevSourceMarker.current.setIcon(createCustomIcon([45, 45], PrevSourceIcon.src)); - if (isMovingDest && mapPrevDestMarker.current) - mapPrevDestMarker.current.setIcon(createCustomIcon([45, 45], PrevDestIcon.src)); - }, - moveend() { - if (isMovingSource) - mapPrevSourceMarker.current.setIcon(createCustomIcon(defaultIconSize, PrevSourceIcon.src)); - if (isMovingDest && mapPrevDestMarker.current) - mapPrevDestMarker.current.setIcon(createCustomIcon(defaultIconSize, PrevDestIcon.src)); - }, - }); - - useEffect(() => { - mapRef.current = map; - }, [map]); - - useEffect(() => { - if (locations.length < 2) return; - const restoredSource = { lat: locations[0].lat, lng: locations[0].lon }; - const restoredDest = { lat: locations[1].lat, lng: locations[1].lon }; - setSourcePosition(restoredSource); - setDestPosition(restoredDest); - setIsSource(true); - setIsDest(true); - if (area) { - const decoded = polyline.decode(area, 6); - setRouteCoords(decoded); - setSelectedRoute({ index: "main", coords: decoded }); - setTimeout(() => { - mapRef.current?.flyToBounds(decoded, { padding: [50, 50], duration: 1.5 }); - }, 100); - } else { - fetchRoute(restoredSource, restoredDest); - } - }, []); - - const fetchRoute = async (source, dest) => { - const locs = [ - { lat: source.lat, lon: source.lng }, - { lat: dest.lat, lon: dest.lng }, - ]; - try { - const response = await fetch("https://jouya.141.ir/api/router/drive", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ locations: locs }), - }); - const data = await response.json(); - const shape = data.trip.legs[0].shape; - setLocations(locs); - setArea(shape); - const decoded = polyline.decode(shape, 6); - setRouteCoords(decoded); - setSelectedRoute({ index: "main", coords: decoded }); - - if (data.alternates?.length > 0) { - const decodedAlternates = data.alternates.map((alt) => polyline.decode(alt.trip.legs[0].shape, 6)); - setAlternateCoords(decodedAlternates); - } else { - setAlternateCoords([]); - } - map.flyToBounds(decoded, { padding: [50, 50], duration: 1.5 }); - } catch (error) { - console.error("Routing error:", error); - } - }; - - const handleMarkerClick = async () => { - if (!isSource || editingTarget === "source") { - const clickedPosition = mapPrevSourceMarker.current.getLatLng(); - setSourcePosition(clickedPosition); - setIsSource(true); - setEditingTarget(null); - setRouteCoords([]); - setAlternateCoords([]); - setSelectedRoute(null); - - if (editingTarget === "source" && destPosition) { - await fetchRoute(clickedPosition, destPosition); - } - } - }; - - const handleDestMarkerClick = async () => { - if (!isDest || editingTarget === "dest") { - const clickedPosition = mapPrevDestMarker.current.getLatLng(); - setDestPosition(clickedPosition); - setIsDest(true); - setEditingTarget(null); - - await fetchRoute(sourcePosition, clickedPosition); - } - }; - - const handleEditSource = () => { - setEditingTarget("source"); - setRouteCoords([]); - setAlternateCoords([]); - setSelectedRoute(null); - }; - - const handleEditDest = () => { - setEditingTarget("dest"); - setRouteCoords([]); - setAlternateCoords([]); - setSelectedRoute(null); - }; - - const handleSelectRoute = (index, coords) => { - setSelectedRoute({ index, coords }); - const encoded = polyline.encode(coords, 6); - setArea(encoded); - map.flyToBounds(coords, { padding: [50, 50], duration: 0.3 }); - }; - - return ( - <> - - - - {isSource && ( - - )} - {alternateCoords.map((coords, index) => ( - handleSelectRoute(index, coords) }} - /> - ))} - {routeCoords.length > 0 && ( - handleSelectRoute("main", routeCoords) }} - /> - )} - - ); -}; - -export default Routing; +import { Marker, Polyline, useMapEvents } from "react-leaflet"; +import L from "leaflet"; +import polyline from "@mapbox/polyline"; +import SourceIcon from "@/assets/images/source-icon.svg"; +import PrevSourceIcon from "@/assets/images/prev-source-icon.svg"; +import PrevDestIcon from "@/assets/images/prev-destination-icon.svg"; +import DestIcon from "@/assets/images/destination-icon.svg"; +import { useEffect, useRef, useState } from "react"; +import DataBox from "./DataBox"; +import AlarmText from "./AlarmText"; + +const Routing = ({ setArea, setLocations, locations, area }) => { + const mapPrevSourceMarker = useRef(); + const mapPrevDestMarker = useRef(); + const mapRef = useRef(null); + const defaultIconSize = [35, 35]; + const [isSource, setIsSource] = useState(false); + const [sourcePosition, setSourcePosition] = useState(null); + const [isDest, setIsDest] = useState(false); + const [destPosition, setDestPosition] = useState(null); + const [routeCoords, setRouteCoords] = useState([]); + const [alternateCoords, setAlternateCoords] = useState([]); + const [editingTarget, setEditingTarget] = useState(null); + const [selectedRoute, setSelectedRoute] = useState(null); + + const createCustomIcon = (size, iconUrl) => { + return L.icon({ + iconUrl: iconUrl, + iconSize: size, + iconAnchor: [size[0] / 2, size[1]], + popupAnchor: [0, -size[1]], + }); + }; + + const defaultIcon = createCustomIcon( + defaultIconSize, + isSource && editingTarget !== "source" ? SourceIcon.src : PrevSourceIcon.src + ); + + const prevDestIcon = createCustomIcon( + defaultIconSize, + isDest && editingTarget !== "dest" ? DestIcon.src : PrevDestIcon.src + ); + + const isMovingSource = !isSource || editingTarget === "source"; + const isMovingDest = isSource && (!isDest || editingTarget === "dest"); + + const map = useMapEvents({ + move(e) { + if (isMovingSource) mapPrevSourceMarker.current.setLatLng(e.target.getCenter()); + if (isMovingDest && mapPrevDestMarker.current) mapPrevDestMarker.current.setLatLng(e.target.getCenter()); + }, + movestart() { + if (isMovingSource) mapPrevSourceMarker.current.setIcon(createCustomIcon([45, 45], PrevSourceIcon.src)); + if (isMovingDest && mapPrevDestMarker.current) + mapPrevDestMarker.current.setIcon(createCustomIcon([45, 45], PrevDestIcon.src)); + }, + moveend() { + if (isMovingSource) + mapPrevSourceMarker.current.setIcon(createCustomIcon(defaultIconSize, PrevSourceIcon.src)); + if (isMovingDest && mapPrevDestMarker.current) + mapPrevDestMarker.current.setIcon(createCustomIcon(defaultIconSize, PrevDestIcon.src)); + }, + }); + + useEffect(() => { + mapRef.current = map; + }, [map]); + + useEffect(() => { + if (locations.length < 2) return; + const restoredSource = { lat: locations[0].lat, lng: locations[0].lon }; + const restoredDest = { lat: locations[1].lat, lng: locations[1].lon }; + setSourcePosition(restoredSource); + setDestPosition(restoredDest); + setIsSource(true); + setIsDest(true); + if (area) { + const decoded = polyline.decode(area, 6); + setRouteCoords(decoded); + setSelectedRoute({ index: "main", coords: decoded }); + setTimeout(() => { + mapRef.current?.flyToBounds(decoded, { padding: [50, 50], duration: 1.5 }); + }, 100); + } else { + fetchRoute(restoredSource, restoredDest); + } + }, []); + + const fetchRoute = async (source, dest) => { + const locs = [ + { lat: source.lat, lon: source.lng }, + { lat: dest.lat, lon: dest.lng }, + ]; + try { + const response = await fetch("https://jouya.141.ir/api/router/drive", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ locations: locs }), + }); + const data = await response.json(); + const shape = data.trip.legs[0].shape; + setLocations(locs); + setArea(shape); + const decoded = polyline.decode(shape, 6); + setRouteCoords(decoded); + setSelectedRoute({ index: "main", coords: decoded }); + + if (data.alternates?.length > 0) { + const decodedAlternates = data.alternates.map((alt) => polyline.decode(alt.trip.legs[0].shape, 6)); + setAlternateCoords(decodedAlternates); + } else { + setAlternateCoords([]); + } + map.flyToBounds(decoded, { padding: [50, 50], duration: 1.5 }); + } catch (error) { + console.error("Routing error:", error); + } + }; + + const handleMarkerClick = async () => { + if (!isSource || editingTarget === "source") { + const clickedPosition = mapPrevSourceMarker.current.getLatLng(); + setSourcePosition(clickedPosition); + setIsSource(true); + setEditingTarget(null); + setRouteCoords([]); + setAlternateCoords([]); + setSelectedRoute(null); + + if (editingTarget === "source" && destPosition) { + await fetchRoute(clickedPosition, destPosition); + } + } + }; + + const handleDestMarkerClick = async () => { + if (!isDest || editingTarget === "dest") { + const clickedPosition = mapPrevDestMarker.current.getLatLng(); + setDestPosition(clickedPosition); + setIsDest(true); + setEditingTarget(null); + + await fetchRoute(sourcePosition, clickedPosition); + } + }; + + const handleEditSource = () => { + setEditingTarget("source"); + setRouteCoords([]); + setAlternateCoords([]); + setSelectedRoute(null); + }; + + const handleEditDest = () => { + setEditingTarget("dest"); + setRouteCoords([]); + setAlternateCoords([]); + setSelectedRoute(null); + }; + + const handleSelectRoute = (index, coords) => { + setSelectedRoute({ index, coords }); + const encoded = polyline.encode(coords, 6); + setArea(encoded); + map.flyToBounds(coords, { padding: [50, 50], duration: 0.3 }); + }; + + return ( + <> + + + + {isSource && ( + + )} + {alternateCoords.map((coords, index) => ( + handleSelectRoute(index, coords) }} + /> + ))} + {routeCoords.length > 0 && ( + handleSelectRoute("main", routeCoords) }} + /> + )} + + ); +}; + +export default Routing; -- 2.49.1