diff --git a/.env.local.example b/.env.local.example index fe53ba8..7dbb472 100644 --- a/.env.local.example +++ b/.env.local.example @@ -1,3 +1,3 @@ -NEXT_PUBLIC_VERSION="0.12.0" +NEXT_PUBLIC_VERSION="0.13.0" NEXT_PUBLIC_API_URL="https://rms.witel.ir" NEXT_PUBLIC_MAPTILE_ENDPOINT="https://rmsmap.rmto.ir/141map" \ No newline at end of file diff --git a/src/app/(withAuth)/dashboard/azmayesh/page.js b/src/app/(withAuth)/dashboard/azmayesh/page.js index d27371a..164a4b6 100644 --- a/src/app/(withAuth)/dashboard/azmayesh/page.js +++ b/src/app/(withAuth)/dashboard/azmayesh/page.js @@ -1,10 +1,12 @@ import AzmayeshPage from "@/components/dashboard/azmayesh"; import WithPermission from "@/core/middlewares/withPermission"; +import ActivityCodeLog from "@/core/components/ActivityCodeLog"; const Page = () => { return ( + ); }; diff --git a/src/app/(withAuth)/dashboard/azmayesh_type/page.js b/src/app/(withAuth)/dashboard/azmayesh_type/page.js index 4032594..77a604a 100644 --- a/src/app/(withAuth)/dashboard/azmayesh_type/page.js +++ b/src/app/(withAuth)/dashboard/azmayesh_type/page.js @@ -1,10 +1,12 @@ import AzmayeshTypePage from "@/components/dashboard/azmayeshType"; import WithPermission from "@/core/middlewares/withPermission"; +import ActivityCodeLog from "@/core/components/ActivityCodeLog"; const Page = () => { return ( + ); }; diff --git a/src/app/(withAuth)/dashboard/road-items/operator/page.js b/src/app/(withAuth)/dashboard/road-items/operator/page.js index 9c3d8ca..324c997 100644 --- a/src/app/(withAuth)/dashboard/road-items/operator/page.js +++ b/src/app/(withAuth)/dashboard/road-items/operator/page.js @@ -1,9 +1,11 @@ import WithPermission from "@/core/middlewares/withPermission"; import OperatorPage from "@/components/dashboard/roadItems/operator"; +import ActivityCodeLog from "@/core/components/ActivityCodeLog"; const Page = () => { return ( + ); }; diff --git a/src/app/(withAuth)/dashboard/road-items/supervisor/page.js b/src/app/(withAuth)/dashboard/road-items/supervisor/page.js index 58c47d8..2de82eb 100644 --- a/src/app/(withAuth)/dashboard/road-items/supervisor/page.js +++ b/src/app/(withAuth)/dashboard/road-items/supervisor/page.js @@ -1,11 +1,13 @@ import WithPermission from "@/core/middlewares/withPermission"; import SupervisorPage from "@/components/dashboard/roadItems/supervisor"; +import ActivityCodeLog from "@/core/components/ActivityCodeLog"; const Page = () => { return ( + ); }; diff --git a/src/app/(withAuth)/dashboard/road-patrols/operator/page.js b/src/app/(withAuth)/dashboard/road-patrols/operator/page.js index 73fa9cf..44725da 100644 --- a/src/app/(withAuth)/dashboard/road-patrols/operator/page.js +++ b/src/app/(withAuth)/dashboard/road-patrols/operator/page.js @@ -1,10 +1,12 @@ import WithPermission from "@/core/middlewares/withPermission"; import OperatorPage from "@/components/dashboard/roadPatrols/operator"; +import ActivityCodeLog from "@/core/components/ActivityCodeLog"; const Page = () => { return ( + ); }; diff --git a/src/app/(withAuth)/dashboard/road-patrols/supervisor/page.js b/src/app/(withAuth)/dashboard/road-patrols/supervisor/page.js index 1afb8c4..4093c15 100644 --- a/src/app/(withAuth)/dashboard/road-patrols/supervisor/page.js +++ b/src/app/(withAuth)/dashboard/road-patrols/supervisor/page.js @@ -1,9 +1,11 @@ import WithPermission from "@/core/middlewares/withPermission"; import SupervisorPage from "@/components/dashboard/roadPatrols/supervisor"; +import ActivityCodeLog from "@/core/components/ActivityCodeLog"; const Page = () => { return ( + ); }; diff --git a/src/components/dashboard/roadItems/operator/Actions/Create/Forms/CreateFormContent.jsx b/src/components/dashboard/roadItems/operator/Actions/Create/Forms/CreateFormContent.jsx index de60a7e..cf29fec 100644 --- a/src/components/dashboard/roadItems/operator/Actions/Create/Forms/CreateFormContent.jsx +++ b/src/components/dashboard/roadItems/operator/Actions/Create/Forms/CreateFormContent.jsx @@ -1,9 +1,8 @@ import React, { useState } from "react"; import { useForm } from "react-hook-form"; import { yupResolver } from "@hookform/resolvers/yup"; -import { array, mixed, object, string } from "yup"; +import { array, mixed, number, object, string } from "yup"; import { useTheme } from "@emotion/react"; -import useRequest from "@/lib/hooks/useRequest"; import { Box, Button, DialogActions, DialogContent, Tab, Tabs, useMediaQuery } from "@mui/material"; import StyledForm from "@/core/components/StyledForm"; import InsertDriveFileIcon from "@mui/icons-material/InsertDriveFile"; @@ -15,7 +14,6 @@ import BeenhereIcon from "@mui/icons-material/Beenhere"; import GetItemsForm from "@/components/dashboard/roadItems/operator/Actions/Create/Forms/GetItemsForm"; import GetSubItemsForm from "@/components/dashboard/roadItems/operator/Actions/Create/Forms/GetSubItemsForm"; import GetItemInfo from "@/components/dashboard/roadItems/operator/Actions/Create/Forms/GetItemInfo"; -import { CREATE_ROAD_ITEMS } from "@/core/utils/routes"; function TabPanel(props) { const { children, value, index } = props; @@ -26,27 +24,30 @@ function TabPanel(props) { ); } -const defaultValues = { - itemId: null, - itemSubId: null, - amount: "", - action_date: "", - start_date: "", - before_image: null, - after_image: null, - cmms_machines: null, - rahdaran_id: null, - start_point: "", - end_point: "", -}; const validationSchema = object({ - itemId: string().required("نوع آیتم را مشخص کنید!"), - itemSubId: string().required("موضوع مشاهده شده را مشخص کنید!"), + item_id: number().required("نوع آیتم را مشخص کنید!"), + sub_item_id: number().required("موضوع مشاهده شده را مشخص کنید!"), amount: string().required("وارد کردن مقدار الزامیست!"), cmms_machines: array().required("وارد کردن کد خودرو الزامیست!"), rahdaran_id: array().required("وارد کردن کد راهداران الزامیست!").min(1, "حداقل یک کد راهدار باید وارد شود!"), // بررسی حداقل یک آیتم, - action_date: string().required("لطفا زمان فعالیت را انتخاب کنید!"), - start_date: string().required("لطفاً تاریخ شروع فعالیت را انتخاب کنید!"), + activity_time: string().test("activity-time-conditional", "لطفا زمان فعالیت را انتخاب کنید!", function (value) { + const { is_gasht } = this.options.context; // دسترسی به context + if (is_gasht) { + return true; // اگر is_gasht true باشد، این فیلد نیاز به اعتبارسنجی ندارد + } + return !!value; // در غیر این صورت مقدار فیلد باید وجود داشته باشد + }), + activity_date: string().test( + "activity-date-conditional", + "لطفاً تاریخ شروع فعالیت را انتخاب کنید!", + function (value) { + const { is_gasht } = this.options.context; // دسترسی به context + if (is_gasht) { + return true; // اگر is_gasht true باشد، این فیلد نیاز به اعتبارسنجی ندارد + } + return !!value; // در غیر این صورت مقدار فیلد باید وجود داشته باشد + } + ), before_image: mixed() .nullable() .test("before-image-required", "لطفا عکس قبل از اقدام را بارگذاری کنید!", function (value) { @@ -82,12 +83,26 @@ const validationSchema = object({ }), }); -const CreateFormContent = ({ setOpen, mutate, onSubmit }) => { +const CreateFormContent = ({ setOpen, onSubmit, is_gasht = false }) => { + const defaultValues = { + item_id: null, + sub_item_id: null, + amount: "", + before_image: null, + after_image: null, + cmms_machines: null, + rahdaran_id: null, + start_point: "", + end_point: "", + ...(!is_gasht && { activity_time: "", activity_date: "" }), + }; + const [tabState, setTabState] = useState(0); const [itemsList, setItemsList] = useState(); const [subItemsList, setSubItemsList] = useState([]); const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down("sm")); + const handleClose = () => { setOpen(false); }; @@ -100,8 +115,8 @@ const CreateFormContent = ({ setOpen, mutate, onSubmit }) => { if (tabState === 2) { const fieldsToReset = [ "amount", - "action_date", - "start_date", + "activity_time", + "activity_date", "before_image", "after_image", "cmms_machines", @@ -130,11 +145,59 @@ const CreateFormContent = ({ setOpen, mutate, onSubmit }) => { defaultValues, resolver: yupResolver(validationSchema), mode: "onBlur", - context: { subItemsList }, + context: { subItemsList, is_gasht }, }); + const onSubmitBase = async (data) => { + let result = { ...data }; + + if (result.before_image === null) { + delete result.before_image; + delete data.before_image; + } + + if (result.after_image === null) { + delete result.after_image; + delete data.after_image; + } + + if (result.end_point === "") { + delete result.end_point; + delete data.end_point; + } else { + result.end_point = `${result.end_point.lat},${result.end_point.lng}`; + } + + if (result.start_point === "") { + delete result.start_point; + delete data.start_point; + } else { + result.start_point = `${result.start_point.lat},${result.start_point.lng}`; + } + + result.rahdaran_id.forEach((rahdar, index) => { + result[`rahdaran_id[${index}]`] = rahdar.id; + }); + delete result.rahdaran_id; + + result.cmms_machines.forEach((cmms_machine, index) => { + result[`machines_id[${index}]`] = cmms_machine.id; + }); + delete result.cmms_machines; + + await onSubmit({ + result, + data: { + ...data, + item_name: itemsList.name, + sub_item_name: subItemsList.name, + unit_fa: subItemsList.unit, + }, + }); + }; + console.log(errors); return ( - + { variant={`${isMobile ? "scrollable" : "fullWidth"}`} sx={{ display: "flex", - justifyContent: "space-around", + justifyContent: "center", + alignItems: "center", width: "100%", backgroundColor: "#efefef", }} @@ -181,6 +245,7 @@ const CreateFormContent = ({ setOpen, mutate, onSubmit }) => { register={register} watch={watch} getValues={getValues} + is_gasht={is_gasht} /> @@ -189,7 +254,7 @@ const CreateFormContent = ({ setOpen, mutate, onSubmit }) => { + {tabState === 1 && ( + + )} + + + ); +}; +export default GashtCreateContent; diff --git a/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/LocationForm/LocationFormContent.jsx b/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/LocationForm/LocationFormContent.jsx new file mode 100644 index 0000000..f012434 --- /dev/null +++ b/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/LocationForm/LocationFormContent.jsx @@ -0,0 +1,31 @@ +"use client"; +import { Box, Button, DialogActions, DialogContent, Stack } from "@mui/material"; +import React from "react"; +import dynamic from "next/dynamic"; +import MapLoading from "@/core/components/MapLayer/Loading"; +import ShowLocationMarker from "@/core/components/ShowLocationMarker"; +const MapLayer = dynamic(() => import("@/core/components/MapLayer"), { + loading: () => , + ssr: false, +}); + +const LocationFormContent = ({ setOpenLocationDialog, start_lat, start_lng }) => { + return ( + <> + + + + + + + + + + + + ); +}; + +export default LocationFormContent; diff --git a/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/LocationForm/index.jsx b/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/LocationForm/index.jsx new file mode 100644 index 0000000..09df6ad --- /dev/null +++ b/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/LocationForm/index.jsx @@ -0,0 +1,36 @@ +import React, { useState } from "react"; +import { Tooltip, IconButton, Dialog, DialogTitle } from "@mui/material"; +import ExploreIcon from "@mui/icons-material/Explore"; +import LocationFormContent from "./LocationFormContent"; +const LocationForm = ({ start_lat, start_lng }) => { + const [openLocationDialog, setOpenLocationDialog] = useState(false); + + return ( + <> + + setOpenLocationDialog(true)}> + + + + setOpenLocationDialog(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={"md"} + > + موقعیت + + + + ); +}; +export default LocationForm; diff --git a/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/RowActions/CompleteItem.jsx b/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/RowActions/CompleteItem.jsx new file mode 100644 index 0000000..059aac9 --- /dev/null +++ b/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/RowActions/CompleteItem.jsx @@ -0,0 +1,231 @@ +import { Button, DialogActions, Grid, Stack } from "@mui/material"; +import PreviousStatesInfo from "./PreviousStatesInfo"; +import NumberField from "@/core/components/NumberField"; +import { Controller, useForm } from "react-hook-form"; +import CarCode from "@/core/components/CarCode"; +import RahdarCode from "@/core/components/RahdarCode"; +import ImageUpload from "@/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/RowActions/ImageUpload"; +import MuiDatePicker from "@/core/components/MuiDatePicker"; +import MuiTimePicker from "@/core/components/MuiTimePicker"; +import MapInfoTwoMarker from "@/core/components/MapInfoTwoMarker"; +import MapInfoOneMarker from "@/core/components/MapInfoOneMarker"; +import { yupResolver } from "@hookform/resolvers/yup"; +import StyledForm from "@/core/components/StyledForm"; +import { array, mixed, number, object, string } from "yup"; +import useRequest from "@/lib/hooks/useRequest"; +import BeenhereIcon from "@mui/icons-material/Beenhere"; +import React, { useEffect } from "react"; +import { CREATE_ROAD_ITEMS } from "@/core/utils/routes"; + +const CompleteItem = ({ subItem, itemInfo, setSubmitCompleteForm, mutate, setOpen }) => { + const requestServer = useRequest({ notificationSuccess: true }); + + const defaultValues = { + item_id: itemInfo?.item_id || null, + sub_item_id: itemInfo?.sub_item_id || null, + amount: "", + activity_time: "", + activity_date: "", + before_image: null, + after_image: null, + cmms_machines: null, + rahdaran_id: null, + start_point: { lat: itemInfo?.start_lat || "", lng: itemInfo?.start_lon || "" }, + end_point: { lat: itemInfo?.end_lat || "", lng: itemInfo?.end_lon || "" }, + }; + + const validationSchema = object({ + item_id: number().required("نوع آیتم را مشخص کنید!"), + sub_item_id: number().required("موضوع مشاهده شده را مشخص کنید!"), + amount: string().required("وارد کردن مقدار الزامیست!"), + cmms_machines: array().required("وارد کردن کد خودرو الزامیست!"), + rahdaran_id: array().required("وارد کردن کد راهداران الزامیست!").min(1, "حداقل یک کد راهدار باید وارد شود!"), // بررسی حداقل یک آیتم, + activity_time: string().required("لطفا زمان فعالیت را انتخاب کنید!"), + activity_date: string().required("لطفاً تاریخ شروع فعالیت را انتخاب کنید!"), + before_image: mixed() + .nullable() + .test("before-image-required", "لطفا عکس قبل از اقدام را بارگذاری کنید!", function (value) { + const { subItem } = this.options.context; + const needsImage = subItem?.needs_image === 1; + if (needsImage) { + return !!value; + } + return true; + }), + after_image: mixed() + .nullable() + .test("after-image-required", "لطفا عکس بعد از اقدام را بارگذاری کنید!", function (value) { + const { subItem } = this.options.context; + const needsImage = subItem?.needs_image === 1; + if (needsImage) { + return !!value; + } + return true; + }), + start_point: mixed() + .test("start-point-required", "لطفاً نقطه شروع را مشخص کنید!", function (value) { + return !!value; // چک می‌کند که مقدار موجود است + }) + .required("لطفاً نقطه شروع را مشخص کنید!"), + end_point: mixed().test("end-point-required", "لطفاً نقطه پایان را مشخص کنید!", function (value) { + const { subItem } = this.options.context; + const needsEndPoint = subItem?.needs_end_point === 1; + if (needsEndPoint) { + return !!value; // چک می‌کند که مقدار موجود است + } + return true; + }), + }); + + const { + control, + watch, + getValues, + register, + handleSubmit, + setValue, + resetField, + formState: { errors, isSubmitting }, + } = useForm({ + defaultValues, + resolver: yupResolver(validationSchema), + mode: "onBlur", + context: { subItem }, + }); + + useEffect(() => { + setSubmitCompleteForm(isSubmitting); + }, [isSubmitting]); + const onSubmit = async (data) => { + let endPoint; + let startPoint = `${data.start_point.lat},${data.start_point.lng}`; + if (subItem.needs_end_point === 1) { + endPoint = `${data.end_point.lat},${data.end_point.lng}`; + } + const formData = new FormData(); + data.after_image !== null && formData.append("after_image", data.after_image); + data.before_image !== null && formData.append("before_image", data.before_image); + subItem.needs_end_point === 1 && formData.append("end_point", endPoint); + formData.append("start_point", startPoint); + formData.append("activity_time", data.activity_time); + formData.append("activity_date", data.activity_date); + formData.append("amount", data.amount); + formData.append("item_id", data.item_id); + formData.append("sub_item_id", data.sub_item_id); + data.cmms_machines.forEach((machine, index) => formData.append(`machines_id[${index}]`, machine.id)); + data.rahdaran_id.forEach((rahdar, index) => formData.append(`rahdaran_id[${index}]`, rahdar.id)); + + await requestServer(CREATE_ROAD_ITEMS, "post", { + data: formData, + }) + .then((response) => { + mutate(); + setOpen(false); + }) + .catch((error) => {}); + }; + + return ( + + + + + + + { + if (!isNaN(event.target.value)) { + setValue("amount", event.target.value); + } else { + setValue("amount", watch("amount")); + } + }} + helperText={errors.amount ? errors.amount.message : null} + variant="outlined" + fullWidth + /> + + + { + return ( + field.onChange(value || [])} + error={error} + multiple={true} + /> + ); + }} + name={"cmms_machines"} + /> + + + { + return ( + field.onChange(value || [])} + error={error} + /> + ); + }} + name={"rahdaran_id"} + /> + + + {subItem.needs_image ? ( + + ) : null} + + + + + + + + + + + + + {subItem?.needs_end_point === 1 ? ( + + ) : ( + + )} + + + + ); +}; +export default CompleteItem; diff --git a/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/RowActions/GetItemInfo.jsx b/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/RowActions/GetItemInfo.jsx new file mode 100644 index 0000000..e11fbd3 --- /dev/null +++ b/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/RowActions/GetItemInfo.jsx @@ -0,0 +1,28 @@ +import { LinearProgress, Typography } from "@mui/material"; +import useRoadItemGetISubtems from "@/lib/hooks/useRoadItemGetISubtems"; +import CompleteItem from "./CompleteItem"; + +const GetItemInfo = ({ itemInfo, setSubmitCompleteForm, mutate, setOpen }) => { + const { subItemsList, loadingSubItemsList, errorSubItemsList } = useRoadItemGetISubtems(itemInfo?.item_id); + const subItem = subItemsList.find((SubItem) => SubItem.sub_item === itemInfo?.sub_item_id); + return ( + <> + {loadingSubItemsList ? ( + + ) : errorSubItemsList ? ( + + خطا در دریافت اطلاعات!!! + + ) : ( + + )} + + ); +}; +export default GetItemInfo; diff --git a/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/RowActions/ImageUpload.jsx b/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/RowActions/ImageUpload.jsx new file mode 100644 index 0000000..3efd1d9 --- /dev/null +++ b/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/RowActions/ImageUpload.jsx @@ -0,0 +1,131 @@ +import { FormControl, FormHelperText, Grid } from "@mui/material"; +import UploadSystem from "@/core/components/UploadSystem"; +import { Controller } from "react-hook-form"; +import React, { useEffect, useState } from "react"; + +const ImageUpload = ({ control, setValue, errors, getValues, beforeImage = null, afterImage = null }) => { + const [beforeImg, setBeforeImg] = useState(beforeImage ? beforeImage : null); + const [beforeFileType, setBeforeFileType] = useState(beforeImage ? "image/" : null); + const [beforeFileName, setBeforeFileName] = useState(null); + const [showBeforeImage, setShowBeforeImage] = useState(!beforeImage); + + const [afterImg, setAfterImg] = useState(afterImage ? afterImage : null); + const [afterFileType, setAfterFileType] = useState(afterImage ? "image/" : null); + const [afterFileName, setAfterFileName] = useState(null); + const [showAfterImage, setShowAfterImage] = useState(!afterImage); + + useEffect(() => { + if (getValues("before_image")) { + setShowBeforeImage(false); + setBeforeImg(getValues("before_image")); + setBeforeFileType("image/"); + } + if (getValues("after_image")) { + setShowAfterImage(false); + setAfterImg(getValues("after_image")); + setAfterFileType("image/"); + } + }, [getValues]); + + const handleBeforeFileChange = (event) => { + const uploadedFile = event.target?.files?.[0]; + if (uploadedFile) { + const fileType = event.target?.files?.[0].type; + const fileName = event.target?.files?.[0].name; + setBeforeImg(URL.createObjectURL(uploadedFile)); + setBeforeFileType(fileType); + setBeforeFileName(fileName); + setValue("before_image", uploadedFile); + setShowBeforeImage(false); + } + }; + const handleAfterFileChange = (event) => { + const uploadedFile = event.target?.files?.[0]; + if (uploadedFile) { + const fileType = event.target?.files?.[0].type; + const fileName = event.target?.files?.[0].name; + setAfterImg(URL.createObjectURL(uploadedFile)); + setAfterFileType(fileType); + setAfterFileName(fileName); + setValue("after_image", uploadedFile); + setShowAfterImage(false); + } + }; + return ( + + + { + return ( + + + عکس قبل از اقدام + + + + {errors.before_image ? errors.before_image.message : null} + + + ); + }} + /> + + + { + return ( + + + عکس بعد از اقدام + + + + {errors.after_image ? errors.after_image.message : null} + + + ); + }} + /> + + + ); +}; +export default ImageUpload; diff --git a/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/RowActions/PreviousStatesInfo.jsx b/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/RowActions/PreviousStatesInfo.jsx new file mode 100644 index 0000000..57c8839 --- /dev/null +++ b/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/RowActions/PreviousStatesInfo.jsx @@ -0,0 +1,43 @@ +import { Box, Chip, Divider, Grid, Typography } from "@mui/material"; +import InsertDriveFileIcon from "@mui/icons-material/InsertDriveFile"; +import FileCopyIcon from "@mui/icons-material/FileCopy"; + +const PreviousStatesInfo = ({ itemInfo }) => { + return ( + + + + } + label={ + + آیتم انتخاب ‌شده + + } + /> + + + + {itemInfo.item_name || "هیچ آیتمی انتخاب نشده است"} + + + + + } + label={ + + موضوع مشاهده‌شده + + } + /> + + + + {itemInfo?.sub_item_name || "هیچ موضوعی انتخاب نشده است"} + + + + ); +}; +export default PreviousStatesInfo; diff --git a/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/RowActions/SubItemForm/index.jsx b/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/RowActions/SubItemForm/index.jsx new file mode 100644 index 0000000..ba8a902 --- /dev/null +++ b/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/RowActions/SubItemForm/index.jsx @@ -0,0 +1,21 @@ +import React from "react"; +import { Tooltip, IconButton } from "@mui/material"; +import UndoIcon from "@mui/icons-material/Undo"; +const SubItemForm = ({ row, setTabState, setItemInfo }) => { + return ( + <> + + { + setTabState(1); + setItemInfo(row.original); + }} + > + + + + + ); +}; +export default SubItemForm; diff --git a/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/RowActions/index.jsx b/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/RowActions/index.jsx new file mode 100644 index 0000000..84e8a31 --- /dev/null +++ b/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/RowActions/index.jsx @@ -0,0 +1,11 @@ +import { Box } from "@mui/material"; +import SubItemForm from "./SubItemForm"; + +const RowActions = ({ row, mutate, setTabState, setItemInfo }) => { + return ( + + + + ); +}; +export default RowActions; diff --git a/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/SearchItemInfo.jsx b/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/SearchItemInfo.jsx new file mode 100644 index 0000000..611e7d8 --- /dev/null +++ b/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/SearchItemInfo.jsx @@ -0,0 +1,42 @@ +import { LinearProgress, Typography } from "@mui/material"; +import useRoadItemGetItems from "@/lib/hooks/useRoadItemGetItems"; +import React from "react"; +import SearchItems from "./SearchItems"; +import TableInfo from "./TableInfo"; + +const SearchItemInfo = ({ + watch, + errors, + setValue, + register, + specialFilter, + setTabState, + setItemInfo, + isSubmitting, +}) => { + const { itemsList, loadingItemsList, errorItemsList } = useRoadItemGetItems(); + return ( + <> + {loadingItemsList ? ( + + ) : errorItemsList ? ( + + خطا در دریافت اطلاعات!!! + + ) : ( + <> + + + + )} + + ); +}; +export default SearchItemInfo; diff --git a/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/SearchItems.jsx b/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/SearchItems.jsx new file mode 100644 index 0000000..775b933 --- /dev/null +++ b/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/SearchItems.jsx @@ -0,0 +1,96 @@ +import { Button, FormControl, FormHelperText, InputLabel, MenuItem, Select, Stack, TextField } from "@mui/material"; +import MuiDatePicker from "@/core/components/MuiDatePicker"; +import SearchIcon from "@mui/icons-material/Search"; +import React from "react"; + +const SearchItems = ({ setValue, itemsList, watch, errors, register, isSubmitting }) => { + const disabledButton = + (!!watch("start_date") && !!watch("end_date")) || !!watch("item_id") || !!watch("road_patrol_id"); + + return ( + + + + + + + + + + آیتم فعالیت + + {/*{errors.item_id ? (*/} + {/* */} + {/* errors.item_id.message*/} + {/* */} + {/*) : null}*/} + + + + { + if (!isNaN(event.target.value)) { + setValue("road_patrol_id", event.target.value); + } else { + setValue("road_patrol_id", watch("road_patrol_id")); + } + }} + helperText={errors.road_patrol_id ? errors.road_patrol_id.message : null} + variant="outlined" + /> + + + + + + ); +}; +export default SearchItems; diff --git a/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/TableInfo.jsx b/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/TableInfo.jsx new file mode 100644 index 0000000..c16dba4 --- /dev/null +++ b/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/TableInfo.jsx @@ -0,0 +1,115 @@ +import { useMemo } from "react"; +import { Box, Stack } from "@mui/material"; +import DataTableWithAuth from "@/core/components/DataTableWithAuth"; +import RowActions from "./RowActions"; +import { GET_OBSERVED_GASHT_LIST } from "@/core/utils/routes"; +import LocationForm from "./LocationForm"; + +const TableInfo = ({ specialFilter, setTabState, setItemInfo }) => { + const columns = useMemo( + () => [ + { + accessorKey: "road_patrol_id", + header: "کد یکتا گشت", + id: "road_patrol_id", + enableColumnFilter: false, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 50, + }, + { + accessorKey: "priority_fa", + header: "اولویت", + id: "priority_fa", + enableColumnFilter: false, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 80, + }, + { + accessorKey: "local_name", + header: "نام محلی", + id: "local_name", + enableColumnFilter: false, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "item_name", + header: "نام ایتم", + id: "item_name", + enableColumnFilter: false, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "sub_item_name", + header: "موضوع مشاهده شده", + id: "sub_item_name", + enableColumnFilter: false, + datatype: "text", + filterMode: "equals", + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + }, + { + accessorKey: "location", + header: "موقعیت", // Location + id: "location", + enableColumnFilter: false, + enableSorting: false, + datatype: "array", + grow: false, + size: 50, + muiTableBodyCellProps: { + sx: { + borderLeft: "1px solid #e1e1e1", + py: 0, + "&:first-of-type": { + borderLeft: "unset", + }, + }, + }, + Cell: ({ renderedCellValue, row }) => { + return ( + + + + ); + }, + }, + ], + [] + ); + return ( + <> + + ( + + )} + /> + + + ); +}; +export default TableInfo; diff --git a/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/index.jsx b/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/index.jsx new file mode 100644 index 0000000..4379040 --- /dev/null +++ b/src/components/dashboard/roadItems/operator/Actions/ObservedGashtCreate/index.jsx @@ -0,0 +1,42 @@ +"use client"; +import { Button, IconButton, useMediaQuery } from "@mui/material"; +import { useTheme } from "@emotion/react"; +import { useState } from "react"; +import AddRoadIcon from "@mui/icons-material/AddRoad"; +import GashtCreate from "./GashtCreate"; + +const ObservedGashtCreate = ({ mutate }) => { + const theme = useTheme(); + const isMobile = useMediaQuery(theme.breakpoints.down("sm")); + const [open, setOpen] = useState(false); + + const handleOpen = () => { + setOpen(true); + }; + + return ( + <> + {isMobile ? ( + + + + ) : ( + + )} + {open && } + + ); +}; +export default ObservedGashtCreate; diff --git a/src/components/dashboard/roadItems/operator/OperatorList.jsx b/src/components/dashboard/roadItems/operator/OperatorList.jsx index c5cfaba..9f818e8 100644 --- a/src/components/dashboard/roadItems/operator/OperatorList.jsx +++ b/src/components/dashboard/roadItems/operator/OperatorList.jsx @@ -193,7 +193,7 @@ const OperatorList = () => { }, { accessorKey: "cmms_machines", - header: "کد خودرو", // Car ID + header: "خودرو ها", // Car ID id: "cmmsMachines__machine_code", enableColumnFilter: true, datatype: "text", @@ -241,20 +241,17 @@ const OperatorList = () => { }, }, Cell: ({ renderedCellValue }) => { - if (renderedCellValue) { - return ( - - - - ); - } - return بدون شخص; + return ( + + + + ); }, }, { - accessorFn: (row) => moment(row.created_at).locale("fa").format("HH:mm | yyyy/MM/DD"), - header: "تاریخ ثبت", // Register Date - id: "created_at", + accessorFn: (row) => moment(row.activity_date_time).locale("fa").format("HH:mm | yyyy/MM/DD"), + header: "تاریخ فعالیت", // Start Date + id: "activity_date_time", enableColumnFilter: true, datatype: "date", filterMode: "equals", @@ -263,9 +260,9 @@ const OperatorList = () => { size: 100, }, { - accessorFn: (row) => moment(row.activity_date_time).locale("fa").format("HH:mm | yyyy/MM/DD"), - header: "تاریخ فعالیت", // Start Date - id: "activity_date_time", + accessorFn: (row) => moment(row.created_at).locale("fa").format("HH:mm | yyyy/MM/DD"), + header: "تاریخ ثبت", // Register Date + id: "created_at", enableColumnFilter: true, datatype: "date", filterMode: "equals", @@ -296,6 +293,7 @@ const OperatorList = () => { header: "توضیحات کارشناس", // Description id: "supervisor_description", enableColumnFilter: false, + enableSorting: false, datatype: "text", filterMode: "equals", columnFilterModeOptions: ["equals", "contains"], @@ -311,11 +309,14 @@ const OperatorList = () => { }, }, Cell: ({ renderedCellValue }) => { - return ( - - - - ); + if (renderedCellValue) { + return ( + + + + ); + } + return بدون توضیحات; }, }, ], diff --git a/src/components/dashboard/roadItems/operator/RowActions/DescriptionForm/index.jsx b/src/components/dashboard/roadItems/operator/RowActions/DescriptionForm/index.jsx index 3f748c9..481e2d6 100644 --- a/src/components/dashboard/roadItems/operator/RowActions/DescriptionForm/index.jsx +++ b/src/components/dashboard/roadItems/operator/RowActions/DescriptionForm/index.jsx @@ -37,7 +37,7 @@ const DescriptionForm = ({ description }) => { - + {description || "هیچ توضیحی موجود نیست"} diff --git a/src/components/dashboard/roadItems/operator/RowActions/EditForm/EditController.jsx b/src/components/dashboard/roadItems/operator/RowActions/EditForm/EditController.jsx index 423bb00..164fc70 100644 --- a/src/components/dashboard/roadItems/operator/RowActions/EditForm/EditController.jsx +++ b/src/components/dashboard/roadItems/operator/RowActions/EditForm/EditController.jsx @@ -1,29 +1,54 @@ -import { LinearProgress, Typography } from "@mui/material"; +import { Dialog, DialogTitle } from "@mui/material"; import EditFormContent from "./EditFormContent"; -import useRoadItemGetISubtems from "@/lib/hooks/useRoadItemGetISubtems"; +import { UPDATE_ROAD_ITEMS } from "@/core/utils/routes"; +import useRequest from "@/lib/hooks/useRequest"; -const EditController = ({ rowId, mutate, setOpenEditDialog, row }) => { - const { subItemsList, loadingSubItemsList, errorSubItemsList } = useRoadItemGetISubtems(row.original?.item); - const subItem = subItemsList.find((SubItem) => SubItem.sub_item === row.original?.sub_item); +const EditController = ({ rowId, mutate, setOpenEditDialog, openEditDialog, row }) => { + const requestServer = useRequest({ notificationSuccess: true }); + + const HandleSubmit = async ({ result }) => { + const formData = new FormData(); + for (const [key, value] of Object.entries(result)) { + formData.append(key, value); + } + await requestServer(`${UPDATE_ROAD_ITEMS}/${rowId}`, "post", { + data: formData, + }) + .then((response) => { + mutate(); + setOpenEditDialog(false); + }) + .catch((error) => {}); + }; return ( - <> - {errorSubItemsList ? ( - - خطا در دریافت اطلاعات!!! - - ) : loadingSubItemsList ? ( - - ) : ( - - )} - + + ویرایش اطلاعات + + ); }; export default EditController; diff --git a/src/components/dashboard/roadItems/operator/RowActions/EditForm/EditFormContent.jsx b/src/components/dashboard/roadItems/operator/RowActions/EditForm/EditFormContent.jsx index 92f7432..530583b 100644 --- a/src/components/dashboard/roadItems/operator/RowActions/EditForm/EditFormContent.jsx +++ b/src/components/dashboard/roadItems/operator/RowActions/EditForm/EditFormContent.jsx @@ -1,215 +1,88 @@ -import { Button, DialogActions, DialogContent, Stack, TextField } from "@mui/material"; -import useRequest from "@/lib/hooks/useRequest"; -import { Controller, useForm } from "react-hook-form"; -import { yupResolver } from "@hookform/resolvers/yup"; -import { array, mixed, object, string } from "yup"; -import StyledForm from "@/core/components/StyledForm"; +import { LinearProgress, Typography } from "@mui/material"; import React from "react"; -import ImageUpload from "@/components/dashboard/roadItems/operator/Actions/Create/Forms/ImageUpload"; -import MapInfoTwoMarker from "@/core/components/MapInfoTwoMarker"; -import MapInfoOneMarker from "@/core/components/MapInfoOneMarker"; -import { UPDATE_ROAD_ITEMS } from "@/core/utils/routes"; -import CarCode from "@/core/components/CarCode"; -import RahdarCode from "@/core/components/RahdarCode"; import useRoadItemGetISubtems from "@/lib/hooks/useRoadItemGetISubtems"; -import NumberField from "@/core/components/NumberField"; +import EditFormCreate from "@/components/dashboard/roadItems/operator/RowActions/EditForm/EditFormCreate"; -const validationSchema = object({ - amount: string().required("وارد کردن مقدار الزامیست!"), - cmms_machines: array().required("وارد کردن کد خودرو الزامیست!"), - rahdaran_id: array().required("وارد کردن کد راهداران الزامیست!").min(1, "حداقل یک کد راهدار باید وارد شود!"), - before_image: mixed() - .nullable() - .test("before-image-required", "لطفا عکس قبل از اقدام را بارگذاری کنید!", function (value) { - const { subItem } = this.options.context; - const needsImage = subItem?.needs_image === 1; - if (needsImage) { - return !!value; - } - return true; - }), - after_image: mixed() - .nullable() - .test("after-image-required", "لطفا عکس بعد از اقدام را بارگذاری کنید!", function (value) { - const { subItem } = this.options.context; - const needsImage = subItem?.needs_image === 1; - if (needsImage) { - return !!value; - } - return true; - }), - start_point: mixed() - .test("start-point-required", "لطفاً نقطه شروع را مشخص کنید!", function (value) { - return !!value; // چک می‌کند که مقدار موجود است - }) - .required("لطفاً نقطه شروع را مشخص کنید!"), - end_point: mixed().test("end-point-required", "لطفاً نقطه پایان را مشخص کنید!", function (value) { - const { subItem } = this.options.context; - const needsEndPoint = subItem?.needs_end_point === 1; - if (needsEndPoint) { - return !!value; // چک می‌کند که مقدار موجود است - } - return true; - }), -}); +const EditFormContent = ({ setOpenEditDialog, onSubmit, defaultData }) => { + const { subItemsList, loadingSubItemsList, errorSubItemsList } = useRoadItemGetISubtems(defaultData?.item_id); + const subItem = subItemsList.find((SubItem) => SubItem.sub_item === defaultData?.sub_item_id); -const EditFormContent = ({ row, mutate, setOpenEditDialog, rowId, subItem }) => { const defaultValues = { - before_image: row.original?.files[0]?.full_path_for_fast_react || null, - after_image: row.original?.files[1]?.full_path_for_fast_react || null, - amount: row.original.sub_item_data || null, - start_point: { lat: row.original.start_lat || "", lng: row.original.start_lng || "" }, - end_point: { lat: row.original.end_lat || "", lng: row.original.end_lng || "" }, - cmms_machines: row.original.cmms_machines || null, - rahdaran_id: row.original.rahdaran || null, + before_image: defaultData?.before_image || null, + after_image: defaultData?.after_image || null, + amount: defaultData?.amount || null, + start_point: defaultData?.start_point || { lat: "", lng: "" }, + end_point: defaultData?.end_point || { lat: "", lng: "" }, + cmms_machines: defaultData?.cmms_machines || null, + rahdaran_id: defaultData?.rahdaran_id || null, }; - const requestServer = useRequest(); - const { - control, - getValues, - watch, - register, - handleSubmit, - setValue, - formState: { errors, isSubmitting }, - } = useForm({ - defaultValues, - resolver: yupResolver(validationSchema), - mode: "onBlur", - context: { subItem }, - }); + const onSubmitBase = async (data) => { + let result = { ...data }; + if (result.before_image === null) { + delete result.before_image; + delete data.before_image; + } - const onSubmit = async (data) => { - let endPoint; - let startPoint = `${data.start_point.lat},${data.start_point.lng}`; - subItem.needs_end_point === 1 && (endPoint = `${data.end_point.lat},${data.end_point.lng}`); - const formData = new FormData(); - subItem.needs_image === 1 && - data.before_image !== defaultValues.before_image && - formData.append("before_image", data.before_image); - subItem.needs_image === 1 && - data.after_image !== defaultValues.after_image && - formData.append("after_image", data.after_image); - formData.append("amount", data.amount); - data.cmms_machines.map((machine, index) => formData.append(`machines_id[${index}]`, machine.id)); - data.rahdaran_id.map((rahdar, index) => formData.append(`rahdaran_id[${index}]`, rahdar.id)); - formData.append("start_point", startPoint); - subItem.needs_end_point === 1 && formData.append("end_point", endPoint); + if (result.after_image === null) { + delete result.after_image; + delete data.after_image; + } - await requestServer(`${UPDATE_ROAD_ITEMS}/${rowId}`, "post", { - notificationSuccess: true, - data: formData, - }) - .then((res) => { - mutate(); - setOpenEditDialog(false); - }) - .catch((err) => {}); + if (result.end_point === "") { + delete result.end_point; + delete data.end_point; + } else { + result.end_point = `${result.end_point.lat},${result.end_point.lng}`; + } + + if (result.start_point === "") { + delete result.start_point; + delete data.start_point; + } else { + result.start_point = `${result.start_point.lat},${result.start_point.lng}`; + } + + result.rahdaran_id.forEach((rahdar, index) => { + result[`rahdaran_id[${index}]`] = rahdar.id; + }); + delete result.rahdaran_id; + + result.cmms_machines.forEach((cmms_machine, index) => { + result[`machines_id[${index}]`] = cmms_machine.id; + }); + delete result.cmms_machines; + + await onSubmit({ + result, + data: { + ...data, + item_name: subItem.item_str, + sub_item_name: subItem.name, + unit_fa: subItem.unit, + item_id: subItem.item, + sub_item_id: subItem.sub_item, + }, + }); }; return ( <> - - - - - {subItem.needs_image === 1 ? ( - - ) : null} - - - { - if (!isNaN(event.target.value)) { - setValue("amount", event.target.value); - } else { - setValue("amount", watch("amount")); - } - }} - helperText={errors.amount ? errors.amount.message : null} - variant="outlined" - fullWidth - /> - - - { - return ( - field.onChange(value || [])} - inputValueDefault={row.original.cmms_machines} - multiple={true} - error={error} // اگر خطا وجود داشته باشد - /> - ); - }} - name={"cmms_machines"} - /> - - - { - return ( - field.onChange(value || [])} - error={error} - /> - ); - }} - name={"rahdaran_id"} - /> - - - {subItem.needs_end_point === 1 ? ( - - ) : ( - - )} - - - - - - - - + {errorSubItemsList ? ( + + خطا در دریافت اطلاعات!!! + + ) : loadingSubItemsList ? ( + + ) : ( + + )} ); }; diff --git a/src/components/dashboard/roadItems/operator/RowActions/EditForm/EditFormCreate.jsx b/src/components/dashboard/roadItems/operator/RowActions/EditForm/EditFormCreate.jsx new file mode 100644 index 0000000..f4d3280 --- /dev/null +++ b/src/components/dashboard/roadItems/operator/RowActions/EditForm/EditFormCreate.jsx @@ -0,0 +1,178 @@ +import { Button, DialogActions, DialogContent, Stack } from "@mui/material"; +import ImageUpload from "@/components/dashboard/roadItems/operator/Actions/Create/Forms/ImageUpload"; +import NumberField from "@/core/components/NumberField"; +import { Controller, useForm } from "react-hook-form"; +import CarCode from "@/core/components/CarCode"; +import RahdarCode from "@/core/components/RahdarCode"; +import MapInfoTwoMarker from "@/core/components/MapInfoTwoMarker"; +import MapInfoOneMarker from "@/core/components/MapInfoOneMarker"; +import StyledForm from "@/core/components/StyledForm"; +import React from "react"; +import { yupResolver } from "@hookform/resolvers/yup"; +import { array, mixed, object, string } from "yup"; + +const validationSchema = object({ + amount: string().required("وارد کردن مقدار الزامیست!"), + cmms_machines: array().required("وارد کردن کد خودرو الزامیست!"), + rahdaran_id: array().required("وارد کردن کد راهداران الزامیست!").min(1, "حداقل یک کد راهدار باید وارد شود!"), + before_image: mixed() + .nullable() + .test("before-image-required", "لطفا عکس قبل از اقدام را بارگذاری کنید!", function (value) { + const { subItem } = this.options.context; + const needsImage = subItem?.needs_image === 1; + if (needsImage) { + return !!value; + } + return true; + }), + after_image: mixed() + .nullable() + .test("after-image-required", "لطفا عکس بعد از اقدام را بارگذاری کنید!", function (value) { + const { subItem } = this.options.context; + const needsImage = subItem?.needs_image === 1; + if (needsImage) { + return !!value; + } + return true; + }), + start_point: mixed() + .test("start-point-required", "لطفاً نقطه شروع را مشخص کنید!", function (value) { + return !!value; // چک می‌کند که مقدار موجود است + }) + .required("لطفاً نقطه شروع را مشخص کنید!"), + end_point: mixed().test("end-point-required", "لطفاً نقطه پایان را مشخص کنید!", function (value) { + const { subItem } = this.options.context; + const needsEndPoint = subItem?.needs_end_point === 1; + if (needsEndPoint) { + return !!value; + } + return true; + }), +}); + +const EditFormCreate = ({ defaultData, subItem, onSubmitBase, defaultValues, setOpenEditDialog }) => { + const { + control, + getValues, + watch, + register, + handleSubmit, + setValue, + formState: { errors, isSubmitting }, + } = useForm({ + defaultValues, + resolver: yupResolver(validationSchema), + mode: "onBlur", + context: { subItem }, + }); + + return ( + + + + + {subItem.needs_image === 1 ? ( + + ) : null} + + + { + if (!isNaN(event.target.value)) { + setValue("amount", event.target.value); + } else { + setValue("amount", watch("amount")); + } + }} + helperText={errors.amount ? errors.amount.message : null} + variant="outlined" + fullWidth + /> + + + { + return ( + field.onChange(value || [])} + inputValueDefault={defaultData?.cmms_machines} + multiple={true} + error={error} // اگر خطا وجود داشته باشد + /> + ); + }} + name={"cmms_machines"} + /> + + + { + return ( + field.onChange(value || [])} + error={error} + /> + ); + }} + name={"rahdaran_id"} + /> + + + {subItem.needs_end_point === 1 ? ( + + ) : ( + + )} + + + + + + + + + ); +}; +export default EditFormCreate; diff --git a/src/components/dashboard/roadItems/operator/RowActions/EditForm/index.jsx b/src/components/dashboard/roadItems/operator/RowActions/EditForm/index.jsx index 888e166..9302918 100644 --- a/src/components/dashboard/roadItems/operator/RowActions/EditForm/index.jsx +++ b/src/components/dashboard/roadItems/operator/RowActions/EditForm/index.jsx @@ -19,19 +19,13 @@ const EditForm = ({ row, mutate, rowId }) => { - - ویرایش اطلاعات - - + ); }; diff --git a/src/components/dashboard/roadItems/operator/RowActions/LocationForm/LocationFormContent.jsx b/src/components/dashboard/roadItems/operator/RowActions/LocationForm/LocationFormContent.jsx index 6c17f3a..1e20921 100644 --- a/src/components/dashboard/roadItems/operator/RowActions/LocationForm/LocationFormContent.jsx +++ b/src/components/dashboard/roadItems/operator/RowActions/LocationForm/LocationFormContent.jsx @@ -25,7 +25,7 @@ const LocationFormContent = ({ setOpenLocationDialog, start_lat, start_lng, end_ - diff --git a/src/components/dashboard/roadItems/operator/Toolbar.jsx b/src/components/dashboard/roadItems/operator/Toolbar.jsx index c98ae05..d8c6fad 100644 --- a/src/components/dashboard/roadItems/operator/Toolbar.jsx +++ b/src/components/dashboard/roadItems/operator/Toolbar.jsx @@ -1,12 +1,14 @@ import PrintExcel from "./ExcelPrint"; import OperatorCreate from "./Actions/Create"; import { Stack } from "@mui/material"; +import ObservedGashtCreate from "./Actions/ObservedGashtCreate"; const Toolbar = ({ table, filterData, mutate }) => { return ( + ); }; diff --git a/src/components/dashboard/roadItems/supervisor/RowActions/DeleteForm/DeleteContent.jsx b/src/components/dashboard/roadItems/supervisor/RowActions/DeleteForm/DeleteContent.jsx index 18198a8..485ac40 100644 --- a/src/components/dashboard/roadItems/supervisor/RowActions/DeleteForm/DeleteContent.jsx +++ b/src/components/dashboard/roadItems/supervisor/RowActions/DeleteForm/DeleteContent.jsx @@ -28,10 +28,10 @@ const DeleteContent = ({ rowId, mutate, setOpenDeleteDialog }) => { - - diff --git a/src/components/dashboard/roadItems/supervisor/RowActions/LocationForm/LocationFormContent.jsx b/src/components/dashboard/roadItems/supervisor/RowActions/LocationForm/LocationFormContent.jsx index 6c17f3a..1e20921 100644 --- a/src/components/dashboard/roadItems/supervisor/RowActions/LocationForm/LocationFormContent.jsx +++ b/src/components/dashboard/roadItems/supervisor/RowActions/LocationForm/LocationFormContent.jsx @@ -25,7 +25,7 @@ const LocationFormContent = ({ setOpenLocationDialog, start_lat, start_lng, end_ - diff --git a/src/components/dashboard/roadItems/supervisor/SupervisorList.jsx b/src/components/dashboard/roadItems/supervisor/SupervisorList.jsx index 4f3420b..8ef88db 100644 --- a/src/components/dashboard/roadItems/supervisor/SupervisorList.jsx +++ b/src/components/dashboard/roadItems/supervisor/SupervisorList.jsx @@ -257,7 +257,7 @@ const SupervisorList = () => { }, { accessorKey: "cmms_machines", - header: "کد خودرو", // Car ID + header: "خودرو ها", // Car ID id: "cmmsMachines__machine_code", enableColumnFilter: true, datatype: "text", @@ -316,9 +316,9 @@ const SupervisorList = () => { }, }, { - accessorFn: (row) => moment(row.created_at).locale("fa").format("HH:mm | yyyy/MM/DD"), - header: "تاریخ ثبت", // Register Date - id: "created_at", + accessorFn: (row) => moment(row.activity_date_time).locale("fa").format("HH:mm | yyyy/MM/DD"), + header: "تاریخ فعالیت", // Start Date + id: "activity_date_time", enableColumnFilter: true, datatype: "date", filterMode: "equals", @@ -327,9 +327,9 @@ const SupervisorList = () => { size: 100, }, { - accessorFn: (row) => moment(row.activity_date_time).locale("fa").format("HH:mm | yyyy/MM/DD"), - header: "تاریخ فعالیت", // Start Date - id: "activity_date_time", + accessorFn: (row) => moment(row.created_at).locale("fa").format("HH:mm | yyyy/MM/DD"), + header: "تاریخ ثبت", // Register Date + id: "created_at", enableColumnFilter: true, datatype: "date", filterMode: "equals", diff --git a/src/components/dashboard/roadPatrols/operator/Actions/Create/index.jsx b/src/components/dashboard/roadPatrols/operator/Actions/Create/index.jsx new file mode 100644 index 0000000..a76a68a --- /dev/null +++ b/src/components/dashboard/roadPatrols/operator/Actions/Create/index.jsx @@ -0,0 +1,33 @@ +"use client"; + +import { Button, IconButton, useMediaQuery } from "@mui/material"; +import { useTheme } from "@emotion/react"; +import { useState } from "react"; +import { AddCircle } from "@mui/icons-material"; +import CreatePatrol from "../../Forms/CreatePatrol"; + +const OperatorCreate = ({ mutate }) => { + const theme = useTheme(); + const isMobile = useMediaQuery(theme.breakpoints.down("sm")); + const [open, setOpen] = useState(false); + + const handleOpen = () => { + setOpen(true); + }; + + return ( + <> + {isMobile ? ( + + + + ) : ( + + )} + {open && } + + ); +}; +export default OperatorCreate; diff --git a/src/components/dashboard/roadPatrols/operator/ExcelPrint/index.jsx b/src/components/dashboard/roadPatrols/operator/ExcelPrint/index.jsx index 54df4da..1c635c8 100644 --- a/src/components/dashboard/roadPatrols/operator/ExcelPrint/index.jsx +++ b/src/components/dashboard/roadPatrols/operator/ExcelPrint/index.jsx @@ -45,7 +45,6 @@ const PrintExcel = ({ table, filterData }) => { + + + + {ActionsList.length !== 0 ? ( + + {ActionsList.map((action, index) => ( + + deleteAction(index)} + /> + + ))} + + ) : ( + + + فعالیتی ثبت نکرده اید + + + )} + + + + + + + ); +}; + +export default ActionsDuringPatrol; diff --git a/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/CompeleteRequest.jsx b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/CompeleteRequest.jsx new file mode 100644 index 0000000..3299e47 --- /dev/null +++ b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/CompeleteRequest.jsx @@ -0,0 +1,229 @@ +"use client"; + +import React, { useEffect, useState } from "react"; +import { + Box, + Button, + Chip, + Divider, + FormControl, + Grid, + InputLabel, + OutlinedInput, + Slide, + Stack, + Typography, +} from "@mui/material"; +import BeenhereIcon from "@mui/icons-material/Beenhere"; +import ForwardToInboxIcon from "@mui/icons-material/ForwardToInbox"; +import { formatCounter } from "@/core/utils/formatCounter"; +import useRequest from "@/lib/hooks/useRequest"; +import { GET_OTP_TOKEN } from "@/core/utils/routes"; +import moment from "jalali-moment"; + +const CompeleteRequest = ({ watch, isSubmitting, setValue, register }) => { + const requestServer = useRequest({ auth: true }); + const [delayPerRequest, setDelayPerRequest] = useState(false); + const [phoneNumber, setPhoneNumber] = useState(""); + const [validPhone, setValidPhone] = useState(false); + const [verificationCode, setVerificationCode] = useState(""); + const [counter, setCounter] = useState(120); + const [otpSended, setOtpSended] = useState(false); + const [readyToVerify, setReadyToVerify] = useState(false); + + const handleNumericInput = (e) => { + e.target.value = e.target.value.replace(/[^0-9]/g, ""); + }; + + useEffect(() => { + if (phoneNumber.length === 11) { + setValidPhone(true); + } else { + setValidPhone(false); + } + if (verificationCode.length === 6 && phoneNumber.length === 11) { + setReadyToVerify(true); + } else { + setReadyToVerify(false); + } + }, [phoneNumber, verificationCode]); + + useEffect(() => { + if (counter === 0) { + setDelayPerRequest(false); + return; + } + if (delayPerRequest && counter > 0) { + const timer = setInterval(() => { + setCounter((prevCounter) => prevCounter - 1); + }, 1000); + + return () => clearInterval(timer); + } + }, [counter, delayPerRequest]); + + const sendOtp = () => { + if (!validPhone) return false; + requestServer(`${GET_OTP_TOKEN}?phone_number=${phoneNumber}`, "get") + .then((response) => { + setOtpSended(true); + setDelayPerRequest(true); + }) + .catch(() => {}); + }; + + return ( + + + + + + {moment(watch("start_time")).locale("fa").format("YYYY/MM/DD | HH:mm")} + + + + + {moment(watch("end_time")).locale("fa").format("YYYY/MM/DD | HH:mm")} + + + + + + + + {watch("vehicle_runtime")} + + + + + {watch("fuel_consumption")} + + + + + {watch("stop_points").length} + + + + + {watch("distance")} + + + + + {watch("observed_items").length} + + + + + + + + + کد + + {watch("road_patrol_machines_id.machine_code")} + + + نام + + {watch("road_patrol_machines_id.car_name")} + + + پلاک + + {watch("road_patrol_machines_id.plak_number")} + + + + + + + {watch("road_patrol_rahdaran_id")?.map((rahdar, index) => ( + + نام و کد راهدار + + + {rahdar.name} | {rahdar.code} + + + ))} + + + + + + شماره تلفن مامور گشت + setPhoneNumber(e.target.value)} + onInput={handleNumericInput} + type="text" + inputProps={{ + maxLength: 11, + }} + /> + + + + + + + کد پیامک شده + setVerificationCode(e.target.value)} + onInput={handleNumericInput} + type="text" + inputProps={{ + maxLength: 6, + inputMode: "numeric", + style: { + textAlign: "center", + letterSpacing: "10px", + }, + }} + /> + + + + + + + + ); +}; + +export default CompeleteRequest; diff --git a/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/EditActionDuringPatrol.jsx b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/EditActionDuringPatrol.jsx new file mode 100644 index 0000000..1693c39 --- /dev/null +++ b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/EditActionDuringPatrol.jsx @@ -0,0 +1,57 @@ +"use client"; + +import React, { useState } from "react"; +import dynamic from "next/dynamic"; +import MapLoading from "@/core/components/MapLayer/Loading"; +import { Dialog, DialogTitle, IconButton } from "@mui/material"; +import EditIcon from "@mui/icons-material/Edit"; +import EditFormContent from "@/components/dashboard/roadItems/operator/RowActions/EditForm/EditFormContent"; + +const MapLayer = dynamic(() => import("@/core/components/MapLayer"), { + loading: () => , + ssr: false, +}); + +const EditActionDuringPatrol = ({ action, index, setActionsList }) => { + const [open, setOpen] = useState(false); + + const handleOpen = () => { + setOpen(true); + }; + + const HandleSubmit = async (newData) => { + setActionsList((prev) => { + const updatedList = [...prev]; + updatedList[index] = { + ...updatedList[index], + data: newData.data, + result: newData.result, + }; + return updatedList; + }); + setOpen(false); + }; + + return ( + <> + + + + + ویرایش اطلاعات + + + + ); +}; + +export default EditActionDuringPatrol; diff --git a/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/ModalActionsDuringPatrol.jsx b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/ModalActionsDuringPatrol.jsx new file mode 100644 index 0000000..073fd9e --- /dev/null +++ b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/ModalActionsDuringPatrol.jsx @@ -0,0 +1,16 @@ +import CreateFormContent from "@/components/dashboard/roadItems/operator/Actions/Create/Forms/CreateFormContent"; +import { Dialog } from "@mui/material"; + +const ModalActionsDuringPatrol = ({ open, setOpen, setActionsList }) => { + const HandleSubmit = async (data) => { + setActionsList((prev) => [...prev, data]); + setOpen(false); + }; + + return ( + + + + ); +}; +export default ModalActionsDuringPatrol; diff --git a/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/PatrolDetail.jsx b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/PatrolDetail.jsx new file mode 100644 index 0000000..487f38e --- /dev/null +++ b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/PatrolDetail.jsx @@ -0,0 +1,203 @@ +"use client"; + +import { Box, Button, Chip, Divider, IconButton, InputAdornment, Stack } from "@mui/material"; +import React, { useEffect, useState } from "react"; +import CarCode from "@/core/components/CarCode"; +import SearchIcon from "@mui/icons-material/Search"; +import { AdapterDateFnsJalali } from "@mui/x-date-pickers/AdapterDateFnsJalali"; +import { faIR } from "@mui/x-date-pickers/locales"; +import { LocalizationProvider, MobileDateTimePicker } from "@mui/x-date-pickers"; +import ClearIcon from "@mui/icons-material/Clear"; +import moment from "jalali-moment"; +import dynamic from "next/dynamic"; +import MapLoading from "@/core/components/MapLayer/Loading"; +import { Controller } from "react-hook-form"; +import { GET_FMS_DATA } from "@/core/utils/routes"; +import useRequest from "@/lib/hooks/useRequest"; +import PatrolDetailInfo from "./PatrolDetailInfo"; +import PatrolResultCodeErrors from "./PatrolResultCodeErrors"; + +const MapLayer = dynamic(() => import("@/core/components/MapLayer"), { + loading: () => , + ssr: false, +}); + +const PatrolDetail = ({ control, watch, setValue, tabState, setTabState }) => { + const requestServer = useRequest({ notificationSuccess: true }); + const [patrolResultStatus, setPatrolResultStatus] = useState(null); + const [readyToRequest, setReadyToRequest] = useState(false); + const [patrolData, setPatrolData] = useState(null); + + const requestPatrolInfo = async () => { + const formData = new FormData(); + formData.append("machineCode", watch("road_patrol_machines_id").machine_code); + formData.append("startDT", moment(watch("start_time")).format("YYYY-MM-DDTHH:mm")); + formData.append("endDT", moment(watch("end_time")).format("YYYY-MM-DDTHH:mm")); + await requestServer(GET_FMS_DATA, "post", { + data: formData, + }) + .then((response) => { + const data = response.data.data; + setPatrolData({ + ...data, + roadPatrolMachinesId: watch("road_patrol_machines_id"), + start_time: watch("start_time"), + end_time: watch("end_time"), + }); + setPatrolResultStatus(data.resultCode); + }) + .catch((error) => {}); + }; + + useEffect(() => { + const roadPatrolMachinesId = watch("road_patrol_machines_id"); + const startTime = watch("start_time"); + const endTime = watch("end_time"); + + const isReady = roadPatrolMachinesId !== null && startTime !== "" && endTime !== ""; + setReadyToRequest(isReady); + }, [watch("road_patrol_machines_id"), watch("start_time"), watch("end_time")]); + + return ( + + + + { + return ( + field.onChange(value)} + error={error} + /> + ); + }} + name={"road_patrol_machines_id"} + /> + + + + { + const date = new Date(start_time); + const formattedDate = moment(date).locale("en").format("YYYY-MM-DD HH:mm"); + setValue("start_time", formattedDate); + }} + slotProps={{ + textField: { + size: "small", + placeholder: "تاریخ و ساعت شروع گشت", + InputProps: { + endAdornment: ( + + { + event.stopPropagation(); + setValue("start_time", ""); + }} + sx={{ + color: "#bfbfbf", + "&:hover": { + backgroundColor: "rgba(189, 189, 189, 0.1)", + color: "#363434", + }, + }} + > + + + + ), + }, + }, + }} + label="تاریخ و ساعت شروع گشت" + /> + { + const date = new Date(end_time); + const formattedDate = moment(date).locale("en").format("YYYY-MM-DD HH:mm"); + setValue("end_time", formattedDate); + }} + slotProps={{ + textField: { + size: "small", + placeholder: "تاریخ و ساعت پایان گشت", + InputProps: { + endAdornment: ( + + { + event.stopPropagation(); + setValue("end_time", ""); + }} + sx={{ + color: "#bfbfbf", + "&:hover": { + backgroundColor: "rgba(189, 189, 189, 0.1)", + color: "#363434", + }, + }} + > + + + + ), + }, + }, + }} + label="تاریخ و ساعت پایان گشت" + /> + + + + + + + + {patrolResultStatus === 0 ? ( + + ) : ( + + )} + + ); +}; + +export default PatrolDetail; diff --git a/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/PatrolDetailInfo.jsx b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/PatrolDetailInfo.jsx new file mode 100644 index 0000000..81fb7f0 --- /dev/null +++ b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/PatrolDetailInfo.jsx @@ -0,0 +1,177 @@ +"use client"; + +import { Box, Button, Card, CardActions, CardContent, Chip, Divider, Slide, Stack, Typography } from "@mui/material"; +import React, { useEffect } from "react"; +import dynamic from "next/dynamic"; +import MapLoading from "@/core/components/MapLayer/Loading"; +import LocalGasStationIcon from "@mui/icons-material/LocalGasStation"; +import DirectionsCarFilledIcon from "@mui/icons-material/DirectionsCarFilled"; +import WatchLaterIcon from "@mui/icons-material/WatchLater"; +import QueryBuilderIcon from "@mui/icons-material/QueryBuilder"; +import AddRoadIcon from "@mui/icons-material/AddRoad"; +import ShareLocationIcon from "@mui/icons-material/ShareLocation"; +import ElectricCarIcon from "@mui/icons-material/ElectricCar"; +import KeyboardDoubleArrowLeftIcon from "@mui/icons-material/KeyboardDoubleArrowLeft"; +import QrCode2Icon from "@mui/icons-material/QrCode2"; +import moment from "jalali-moment"; +import PatrolMapFeatures from "./PatrolMapFeatures"; +import { useMap } from "react-leaflet"; + +const MapLayer = dynamic(() => import("@/core/components/MapLayer"), { + loading: () => , + ssr: false, +}); + +const MapItemViewBound = ({ patrolData, bound }) => { + const map = useMap(); + + useEffect(() => { + if (bound.length !== 0) { + map.fitBounds(bound, { paddingTopLeft: [16, 16], paddingBottomRight: [16, 130] }); + } + }, [bound]); + + return ( + <> + {patrolData.stopPoints.map((stopPoint, index) => ( + + + + ))} + + ); +}; + +const PatrolDetailInfo = ({ patrolData, tabState, setTabState, setValue }) => { + const bound = patrolData.stopPoints.map((point) => [point.latitude, point.longitude]); + + const SendPatrolInfo = () => { + setValue("vehicle_runtime", patrolData.accOnDuration); + setValue("fuel_consumption", patrolData.fuelConsumption); + setValue("distance", patrolData.mileage); + setValue("stop_points", patrolData.stopPoints); + setTabState(tabState + 1); + }; + + return ( + + + + + + } /> + + + {Math.floor(patrolData.accOnDuration / 60)} دقیقه + + + + } /> + + + {patrolData.roadPatrolMachinesId.car_name} + + + + } /> + + + {patrolData.roadPatrolMachinesId.machine_code} + + + + } /> + + + {patrolData.roadPatrolMachinesId.plak_number} + + + + } /> + + + {moment(patrolData.start_time).locale("fa").format("HH:mm | YYYY/MM/DD")} + + + + } /> + + + {moment(patrolData.end_time).locale("fa").format("HH:mm | YYYY/MM/DD")} + + + + } /> + + + {(patrolData.mileage / 1000).toFixed(1)} کیلومتر + + + + } /> + + + {Math.round(patrolData.fuelConsumption * 10) / 10} لیتر + + + + } /> + + + {patrolData.stopPoints.length} مورد + + + + + + + + + + + + + + + + + + + + + + ); +}; + +export default PatrolDetailInfo; diff --git a/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/PatrolForms.jsx b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/PatrolForms.jsx new file mode 100644 index 0000000..bc67467 --- /dev/null +++ b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/PatrolForms.jsx @@ -0,0 +1,179 @@ +"use client"; + +import { Box, DialogContent, Tab, Tabs, useMediaQuery } from "@mui/material"; +import { useTheme } from "@emotion/react"; +import React, { useEffect, useState } from "react"; +import TaxiAlertIcon from "@mui/icons-material/TaxiAlert"; +import EngineeringIcon from "@mui/icons-material/Engineering"; +import HandymanIcon from "@mui/icons-material/Handyman"; +import VerifiedIcon from "@mui/icons-material/Verified"; +import PatrolTimeLine from "./PatrolTimeLine"; +import PatrolDetail from "./PatrolDetail"; +import SuperVisorsDetail from "./SuperVisorsDetail"; +import ActionsDuringPatrol from "./ActionsDurigPatrol"; +import { useForm } from "react-hook-form"; +import StyledForm from "@/core/components/StyledForm"; +import useRequest from "@/lib/hooks/useRequest"; +import CompeleteRequest from "./CompeleteRequest"; + +function TabPanel(props) { + const { children, value, index } = props; + + return ( + + ); +} + +const defaultValues = { + road_patrol_rahdaran_id: null, + road_patrol_machines_id: null, + start_time: "", + end_time: "", + stop_points: null, + vehicle_runtime: "", + fuel_consumption: "", + distance: "", + observed_items: null, + phone_number: "", + otp_token: "", +}; + +const PatrolForms = ({ mutate, setOpen }) => { + const requestServer = useRequest({ notificationSuccess: true }); + const theme = useTheme(); + const isMobile = useMediaQuery(theme.breakpoints.down("md")); + const [tabState, setTabState] = useState(0); + const [activeUpTo, setActiveUpTo] = useState(0); + + const handleChangeTab = (event, newValue) => { + setTabState(newValue); + }; + + useEffect(() => { + if (activeUpTo < tabState) { + setActiveUpTo(tabState); + } + }, [tabState]); + + const { + control, + watch, + getValues, + register, + handleSubmit, + setValue, + resetField, + formState: { isSubmitting }, + } = useForm({ + defaultValues, + mode: "onBlur", + }); + + const onSubmit = async (data) => { + console.log("data", data); + // const formData = new FormData(); + // data.road_patrol_rahdaran_id.forEach((rahdar, index) => formData.append(`road_patrol_rahdaran_id[${index}]`, rahdar.id)); + // formData.append(`road_patrol_machines_id[0]`, data.road_patrol_machines_id.id) + // data.stop_points.forEach((stop_point, index) => formData.append(`stop_points[${index}]`, stop_point)) + // data.observed_items.forEach((observed_item, index) => { + // formData.append(`observed_items[${index}][instant_action]`, 1); + // formData.append(`observed_items[${index}][local_name]`, ""); + // formData.append(`observed_items[${index}][start_point]`, observed_item.start_point); + // formData.append(`observed_items[${index}][start_point]`, observed_item.end_point); + // formData.append(`observed_items[${index}][amount]`, observed_item.amount); + // formData.append(`observed_items[${index}][before_image]`, observed_item.before_image); + // formData.append(`observed_items[${index}][after_image]`, observed_item.after_image); + // observed_item.cmms_machines.forEach((machine) => formData.append(`observed_items[${index}][cmms_machines][]`, machine.id)) + // observed_item.rahdaran_id.forEach((rahdar) => formData.append(`observed_items[${index}][rahdaran_id][]`, rahdar.id)) + // formData.append(`observed_items[${index}][sub_item_id]`, observed_item.sub_item_id); + // }) + // formData.append("start_time", data.start_time); + // formData.append("end_time", data.end_time); + // formData.append("vehicle_runtime", data.vehicle_runtime); + // formData.append("fuel_consumption", +data.fuel_consumption); + // formData.append("distance", data.distance); + // formData.append("description", ""); + // formData.append("phone_number", data.phone_number); + // formData.append("verification_code", data.verification_code); + // if (data.phone_number !== "" && data.verification_code !== "") { + // try { + // await requestServer(CREATE_PATROL, "post", { + // data: formData, + // }); + // mutate(); + // setOpen(false); + // } catch (error) { + // } + // } else { + // console.log("error phone number") + // } + }; + + return ( + + + = 0)} icon={} label="مشخصات گشت"> + = 1)} icon={} label="مشخصات راهداران"> + = 2)} icon={} label="اقدامات حین گشت"> + = 3)} icon={} label="تکمیل درخواست"> + + + + + + + + + + + + + + + + + {!isMobile && ( + + + + )} + + + ); +}; +export default PatrolForms; diff --git a/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/PatrolMapFeatures.jsx b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/PatrolMapFeatures.jsx new file mode 100644 index 0000000..1a8b785 --- /dev/null +++ b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/PatrolMapFeatures.jsx @@ -0,0 +1,38 @@ +"use client"; + +import { Typography } from "@mui/material"; +import React, { useRef } from "react"; +import { Marker, Popup } from "react-leaflet"; +import AzmayeshIcon from "@/assets/images/examine_marker.png"; + +const PatrolMapFeatures = ({ stopPoint }) => { + const position = [stopPoint.latitude, stopPoint.longitude]; + const mapPatrolMarker = useRef(); + const createCustomIcon = (size, iconUrl) => { + return L.icon({ + iconUrl: iconUrl, + iconSize: size, + iconAnchor: [size[0] / 2, size[1]], + popupAnchor: [0, -size[1]], + }); + }; + + return ( + + + مدت زمان توقف: {stopPoint.duration} ثانیه + + + ); +}; + +export default PatrolMapFeatures; diff --git a/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/PatrolResultCodeErrors.jsx b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/PatrolResultCodeErrors.jsx new file mode 100644 index 0000000..da28921 --- /dev/null +++ b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/PatrolResultCodeErrors.jsx @@ -0,0 +1,25 @@ +"use client"; + +import { Box, Typography } from "@mui/material"; +import React from "react"; + +const PatrolResultCodeErrors = ({ ResultCode }) => { + const errorMessages = { + [-1]: "نام کاربری یا کلمه عبور صحیح نمیباشد", + [-2]: "ردیاب به خودرو انتخابی متصل نیست", + [-3]: "کاربر دسترسی لازم به اطلاعات خودرو انتخابی را ندارد", + [-4]: "خطای درخواست مکرر", + }; + + const message = errorMessages[ResultCode] || "ابتدا اطلاعات بالا را تکمیل نمایید"; + + return ( + + + {message} + + + ); +}; + +export default PatrolResultCodeErrors; diff --git a/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/PatrolTimeLine.jsx b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/PatrolTimeLine.jsx new file mode 100644 index 0000000..4edaa2f --- /dev/null +++ b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/PatrolTimeLine.jsx @@ -0,0 +1,119 @@ +"use client"; + +import { Box, CircularProgress, Typography } from "@mui/material"; +import TaxiAlertIcon from "@mui/icons-material/TaxiAlert"; +import EngineeringIcon from "@mui/icons-material/Engineering"; +import HandymanIcon from "@mui/icons-material/Handyman"; +import VerifiedIcon from "@mui/icons-material/Verified"; +import { + Timeline, + TimelineConnector, + TimelineContent, + TimelineDot, + TimelineItem, + timelineItemClasses, + TimelineSeparator, +} from "@mui/lab"; + +const PatrolTimeLine = ({ tabState }) => { + return ( + + + + + + + {tabState === 0 ? ( + + ) : ( + 0 ? "success" : "error"} + sx={{ width: "1.5rem", height: "1.5rem" }} + /> + )} + + + + + مشخصات گشت + + تایید اطلاعات اولیه گشت + + + + + + + + {tabState === 1 ? ( + + ) : ( + 1 ? "success" : "error"} + sx={{ width: "1.5rem", height: "1.5rem" }} + /> + )} + + + + + مشخصات راهداران + + راهدار / راهداران حاضر در گشت + + + + + + + + {tabState === 2 ? ( + + ) : ( + 2 ? "success" : "error"} + sx={{ width: "1.5rem", height: "1.5rem" }} + /> + )} + + + + + اقدامات حین گشت + + ثبت فعالیت های صورت گرفته حین گشت + + + + + + + + {tabState === 3 ? ( + + ) : ( + 3 ? "success" : "error"} + sx={{ width: "1.5rem", height: "1.5rem" }} + /> + )} + + + + + تکمیل درخواست + + تکمیل درخواست و ثبت نهایی + + + + + + ); +}; +export default PatrolTimeLine; diff --git a/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/PhoneValidation.jsx b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/PhoneValidation.jsx new file mode 100644 index 0000000..0c9cb30 --- /dev/null +++ b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/PhoneValidation.jsx @@ -0,0 +1,118 @@ +"use client"; + +import { Box, Button, FormControl, InputLabel, OutlinedInput } from "@mui/material"; +import React, { useEffect, useState } from "react"; +import ForwardToInboxIcon from "@mui/icons-material/ForwardToInbox"; +import useRequest from "@/lib/hooks/useRequest"; +import { GET_OTP_TOKEN, VERIFY_OTP } from "@/core/utils/routes"; +import { formatCounter } from "@/core/utils/formatCounter"; + +const PhoneValidation = ({ tabState, setTabState }) => { + const requestServer = useRequest({ auth: true }); + const [phoneNumber, setPhoneNumber] = useState(""); + const [verificationCode, setVerificationCode] = useState(""); + const [validPhone, setValidPhone] = useState(false); + const [delayPerRequest, setDelayPerRequest] = useState(false); + const [counter, setCounter] = useState(120); + const [otpSended, setOtpSended] = useState(false); + const [readyToVerify, setReadyToVerify] = useState(false); + + const handleNumericInput = (e) => { + e.target.value = e.target.value.replace(/[^0-9]/g, ""); + }; + + useEffect(() => { + if (phoneNumber.length === 11) { + setValidPhone(true); + } else { + setValidPhone(false); + } + if (verificationCode.length === 6 && phoneNumber.length === 11) { + setReadyToVerify(true); + } else { + setReadyToVerify(false); + } + }, [phoneNumber, verificationCode]); + + useEffect(() => { + if (counter === 0) { + setDelayPerRequest(false); + return; + } + if (delayPerRequest && counter > 0) { + const timer = setInterval(() => { + setCounter((prevCounter) => prevCounter - 1); + }, 1000); + + return () => clearInterval(timer); + } + }, [counter, delayPerRequest]); + + const sendOtp = () => { + if (!validPhone) return false; + requestServer(`${GET_OTP_TOKEN}?phone_number=${phoneNumber}`, "get") + .then((response) => {}) + .catch(() => {}); + //////////**** (mohammad) this part should keep in success but for now we go next level ****//////////// + setOtpSended(true); + setDelayPerRequest(true); + }; + + const phoneRegister = () => { + const formData = new FormData(); + formData.append("phone_number", phoneNumber); + formData.append("verification_code", verificationCode); + + setTabState(tabState + 1); + requestServer(VERIFY_OTP, "post", { + data: formData, + }) + .then(() => {}) + .catch(() => {}); + }; + + return ( + + + + شماره تلفن مامور گشت + setPhoneNumber(e.target.value)} + onInput={handleNumericInput} + type="text" + inputProps={{ + maxLength: 11, + }} + /> + + + + + ); +}; + +export default PhoneValidation; diff --git a/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/SuperVisorInfo.jsx b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/SuperVisorInfo.jsx new file mode 100644 index 0000000..c70c5f4 --- /dev/null +++ b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/SuperVisorInfo.jsx @@ -0,0 +1,38 @@ +"use client"; + +import { Box, Card, IconButton, Stack, Typography } from "@mui/material"; +import AccountCircleIcon from "@mui/icons-material/AccountCircle"; +import DeleteIcon from "@mui/icons-material/Delete"; +import React from "react"; + +const SuperVisorInfo = ({ superVisor, deleteSuperVisor }) => { + return ( + + + + + + {superVisor.name} + + کد راهدار: {superVisor.code} + + + + deleteSuperVisor(superVisor.id)}> + + + + + ); +}; + +export default SuperVisorInfo; diff --git a/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/SuperVisorsDetail.jsx b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/SuperVisorsDetail.jsx new file mode 100644 index 0000000..668c546 --- /dev/null +++ b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/SuperVisorsDetail.jsx @@ -0,0 +1,139 @@ +"use client"; + +import { Box, Button, Chip, Divider, Grid, Stack, Typography } from "@mui/material"; +import SaveAltIcon from "@mui/icons-material/SaveAlt"; +import React, { useEffect, useState } from "react"; +import RahdarCode from "@/core/components/RahdarCode"; +import SuperVisorInfo from "@/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/SuperVisorInfo"; +import KeyboardDoubleArrowRightIcon from "@mui/icons-material/KeyboardDoubleArrowRight"; +import KeyboardDoubleArrowLeftIcon from "@mui/icons-material/KeyboardDoubleArrowLeft"; +import { Controller } from "react-hook-form"; + +const SuperVisorsDetail = ({ control, watch, setValue, tabState, setTabState }) => { + const [SuperVisorList, setSuperVisorList] = useState([]); + const [readyToRequest, setReadyToRequest] = useState(false); + + const requestPatrolInfo = () => { + setSuperVisorList((prev) => [...prev, watch("road_patrol_rahdaran_id")]); + setReadyToRequest(false); + setValue("road_patrol_rahdaran_id", null); + }; + + const deleteSuperVisor = (id) => { + setSuperVisorList((prev) => prev.filter((superVisor) => superVisor.id !== id)); + }; + + useEffect(() => { + setReadyToRequest(watch("road_patrol_rahdaran_id") != null); + }, [watch("road_patrol_rahdaran_id")]); + + const SendSuperVisor = () => { + setValue("road_patrol_rahdaran_id", SuperVisorList); + setTabState(tabState + 1); + }; + + return ( + + + + + { + return ( + field.onChange(value)} + error={error} + multiple={false} + /> + ); + }} + name={"road_patrol_rahdaran_id"} + /> + + + + + + + + {SuperVisorList.length !== 0 ? ( + <> + + {SuperVisorList.map((superVisor) => ( + + + + ))} + + + + + + + ) : ( + + + ابتدا اطلاعات بالا را تکمیل نمایید + + + )} + + ); +}; + +export default SuperVisorsDetail; diff --git a/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/index.jsx b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/index.jsx new file mode 100644 index 0000000..3c1c72c --- /dev/null +++ b/src/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/index.jsx @@ -0,0 +1,13 @@ +"use client"; + +import { Dialog } from "@mui/material"; +import PatrolForms from "./PatrolForms"; + +const CreatePatrol = ({ open, setOpen, mutate }) => { + return ( + + + + ); +}; +export default CreatePatrol; diff --git a/src/components/dashboard/roadPatrols/operator/OperatorList.jsx b/src/components/dashboard/roadPatrols/operator/OperatorList.jsx index a68bdcc..c5e8d7a 100644 --- a/src/components/dashboard/roadPatrols/operator/OperatorList.jsx +++ b/src/components/dashboard/roadPatrols/operator/OperatorList.jsx @@ -1,11 +1,14 @@ "use client"; import { useMemo } from "react"; -import { Box, Typography } from "@mui/material"; +import { Box, Stack, Typography } from "@mui/material"; import DataTableWithAuth from "@/core/components/DataTableWithAuth"; import Toolbar from "./Toolbar"; import { GET_ROAD_PATROL_OPERATOR_LIST } from "@/core/utils/routes"; import moment from "jalali-moment"; import RowActions from "./RowActions"; +import ReportForm from "./RowActions/ReportForm"; +import MachinesCodeDialog from "./RowActions/MachinesCodeForm"; +import RahdaranDialog from "./RowActions/RahdaranForm"; const OperatorList = () => { const columns = useMemo( @@ -22,31 +25,64 @@ const OperatorList = () => { size: 100, }, { - accessorKey: "operator_name", - header: "نام مامور", - id: "operator_name", + accessorKey: "cmms_machines", + header: "خودرو", // Car ID + id: "cmmsMachines__machine_code", enableColumnFilter: true, datatype: "text", - filterMode: "equals", + filterMode: "contains", + enableSorting: false, columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + muiTableBodyCellProps: { + sx: { + borderLeft: "1px solid #e1e1e1", + py: 0, + "&:first-of-type": { + borderLeft: "unset", + }, + }, + }, + Cell: ({ renderedCellValue }) => { + if (renderedCellValue) { + return ( + + + + ); + } + return کد خودرویی وجود ندارد; + }, }, { - accessorKey: "officer_phone_number", - header: "تلفن همراه", - id: "officer_phone_number", - enableColumnFilter: true, - datatype: "text", - filterMode: "equals", - columnFilterModeOptions: ["equals", "contains"], - }, - { - accessorKey: "car_id", - header: "کد خودرو", - id: "car_id", - enableColumnFilter: true, - datatype: "text", - filterMode: "equals", - columnFilterModeOptions: ["equals", "contains"], + accessorKey: "rahdaran", + header: "راهداران", + id: "rahdaran", + enableColumnFilter: false, + enableSorting: false, + datatype: "array", + grow: false, + size: 100, + muiTableBodyCellProps: { + sx: { + borderLeft: "1px solid #e1e1e1", + py: 0, + "&:first-of-type": { + borderLeft: "unset", + }, + }, + }, + Cell: ({ renderedCellValue }) => { + if (renderedCellValue) { + return ( + + + + ); + } + return بدون شخص; + }, }, { accessorFn: (row) => moment(row.start_date).locale("fa").format("HH:mm | yyyy/MM/DD"), @@ -81,6 +117,29 @@ const OperatorList = () => { grow: false, size: 100, }, + { + header: "گزارش مامور", + enableColumnFilter: false, + datatype: "text", + grow: false, + size: 100, + muiTableBodyCellProps: { + sx: { + borderLeft: "1px solid #e1e1e1", + py: 0, + "&:first-of-type": { + borderLeft: "unset", + }, + }, + }, + Cell: ({ renderedCellValue, row }) => { + return ( + + + + ); + }, + }, ], [] ); @@ -89,7 +148,6 @@ const OperatorList = () => { <> { + return ( + <> + + + + + + + کد ماشین + نام خودرو + پلاک + + + + {machinesLists.map((machine) => { + return ( + + {machine.machine_code} + {machine.car_name} + + {machine.plak_number ? ( + + ) : null} + + + ); + })} + +
+
+
+
+ + ); +}; +export default MachinesCodeContent; diff --git a/src/components/dashboard/roadPatrols/operator/RowActions/MachinesCodeForm/index.jsx b/src/components/dashboard/roadPatrols/operator/RowActions/MachinesCodeForm/index.jsx new file mode 100644 index 0000000..d8e8754 --- /dev/null +++ b/src/components/dashboard/roadPatrols/operator/RowActions/MachinesCodeForm/index.jsx @@ -0,0 +1,43 @@ +import { Button, Dialog, DialogActions, DialogTitle, IconButton, Tooltip } from "@mui/material"; +import DirectionsCarIcon from "@mui/icons-material/DirectionsCar"; +import { useState } from "react"; +import MachinesCodeContent from "./MachinesCodeContent"; + +const MachinesCodeDialog = ({ machinesLists }) => { + const [openMachinesCodeDialog, setOpenMachinesCodeDialog] = useState(false); + return ( + <> + + setOpenMachinesCodeDialog(true)}> + + + + setOpenMachinesCodeDialog(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={"md"} + > + کد خودرو + + + + + + + ); +}; +export default MachinesCodeDialog; diff --git a/src/components/dashboard/roadPatrols/operator/RowActions/RahdaranForm/RahdaranContent.jsx b/src/components/dashboard/roadPatrols/operator/RowActions/RahdaranForm/RahdaranContent.jsx new file mode 100644 index 0000000..d1e9b15 --- /dev/null +++ b/src/components/dashboard/roadPatrols/operator/RowActions/RahdaranForm/RahdaranContent.jsx @@ -0,0 +1,48 @@ +import { DialogContent, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from "@mui/material"; + +const RahdaranContent = ({ rahdarLists }) => { + return ( + <> + + + + + + + کد راهدار + نام + + + + {rahdarLists.map((rahdar) => { + return ( + + {rahdar.code} + {rahdar.name} + + ); + })} + +
+
+
+
+ + ); +}; +export default RahdaranContent; diff --git a/src/components/dashboard/roadPatrols/operator/RowActions/RahdaranForm/index.jsx b/src/components/dashboard/roadPatrols/operator/RowActions/RahdaranForm/index.jsx new file mode 100644 index 0000000..2c73d80 --- /dev/null +++ b/src/components/dashboard/roadPatrols/operator/RowActions/RahdaranForm/index.jsx @@ -0,0 +1,38 @@ +import { Button, Dialog, DialogActions, DialogTitle, IconButton, Tooltip } from "@mui/material"; +import GroupsIcon from "@mui/icons-material/Groups"; +import { useState } from "react"; +import RahdaranContent from "./RahdaranContent"; + +const RahdaranDialog = ({ rahdarLists }) => { + const [openRahdaranDialog, setOpenRahdaranDialog] = useState(false); + return ( + <> + + setOpenRahdaranDialog(true)}> + + + + setOpenRahdaranDialog(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={"md"} + > + لیست راهداران + + + + + + + ); +}; +export default RahdaranDialog; diff --git a/src/components/dashboard/roadPatrols/operator/RowActions/ReportForm/index.jsx b/src/components/dashboard/roadPatrols/operator/RowActions/ReportForm/index.jsx index 8abb152..0319aaf 100644 --- a/src/components/dashboard/roadPatrols/operator/RowActions/ReportForm/index.jsx +++ b/src/components/dashboard/roadPatrols/operator/RowActions/ReportForm/index.jsx @@ -2,8 +2,7 @@ import { Tooltip, IconButton } from "@mui/material"; import PrintIcon from "@mui/icons-material/Print"; const ReportForm = ({ rowId }) => { - const reportUrl = "https://rms.rmto.ir/v2/road_patrols/operator/report/96872"; // TODO replace id here - + const reportUrl = `https://rms.rmto.ir/v2/road_patrols/operator/report/${rowId}`; return ( { - return ( - - - - ); + return ; }; export default RowActions; diff --git a/src/components/dashboard/roadPatrols/operator/Toolbar.jsx b/src/components/dashboard/roadPatrols/operator/Toolbar.jsx index 32c4395..d10e83d 100644 --- a/src/components/dashboard/roadPatrols/operator/Toolbar.jsx +++ b/src/components/dashboard/roadPatrols/operator/Toolbar.jsx @@ -1,10 +1,13 @@ import PrintExcel from "./ExcelPrint"; +import OperatorCreate from "./Actions/Create"; +import { Box } from "@mui/material"; -const Toolbar = ({ table, filterData }) => { +const Toolbar = ({ table, filterData, mutate }) => { return ( - <> + + - + ); }; export default Toolbar; diff --git a/src/components/dashboard/roadPatrols/operator/index.jsx b/src/components/dashboard/roadPatrols/operator/index.jsx index 7835954..a2b328c 100644 --- a/src/components/dashboard/roadPatrols/operator/index.jsx +++ b/src/components/dashboard/roadPatrols/operator/index.jsx @@ -1,7 +1,7 @@ "use client"; import PageTitle from "@/core/components/PageTitle"; import { Stack } from "@mui/material"; -import OperatorList from "@/components/dashboard/roadPatrols/operator/OperatorList"; +import OperatorList from "./OperatorList"; const OperatorPage = () => { return ( diff --git a/src/components/dashboard/roadPatrols/supervisor/RowActions/DeleteForm/DeleteContent.jsx b/src/components/dashboard/roadPatrols/supervisor/RowActions/DeleteForm/DeleteContent.jsx index 52d266c..bb9303d 100644 --- a/src/components/dashboard/roadPatrols/supervisor/RowActions/DeleteForm/DeleteContent.jsx +++ b/src/components/dashboard/roadPatrols/supervisor/RowActions/DeleteForm/DeleteContent.jsx @@ -1,9 +1,45 @@ import { Button, DialogActions, DialogContent, Stack, Typography, List, ListItem } from "@mui/material"; import useRequest from "@/lib/hooks/useRequest"; -import React from "react"; +import React, { useState } from "react"; +import { DELETE_ROAD_PATROL_SUPERVISOR } from "@/core/utils/routes"; const DeleteContent = ({ rowId, mutate, setOpenDeleteDialog }) => { - const requestServer = useRequest(); + const requestServer = useRequest({ notificationSuccess: true }); + const [submittingPartial, setSubmittingPartial] = useState(false); + const [submittingGeneral, setSubmittingGeneral] = useState(false); + const handleGeneralDelete = () => { + setSubmittingGeneral(true); + requestServer(`${DELETE_ROAD_PATROL_SUPERVISOR}/${rowId}`, "post", { + data: { + type: 2, + }, + }) + .then(() => { + mutate(); + setOpenDeleteDialog(false); + setSubmittingGeneral(false); + }) + .catch(() => { + setSubmittingGeneral(false); + }); + }; + + const handlePartialDelete = () => { + setSubmittingPartial(true); + requestServer(`${DELETE_ROAD_PATROL_SUPERVISOR}/${rowId}`, "post", { + data: { + type: 1, + }, + }) + .then(() => { + mutate(); + setOpenDeleteDialog(false); + setSubmittingPartial(false); + }) + .catch(() => { + setSubmittingPartial(false); + }); + }; return ( <> @@ -42,23 +78,11 @@ const DeleteContent = ({ rowId, mutate, setOpenDeleteDialog }) => { - - diff --git a/src/components/dashboard/roadPatrols/supervisor/RowActions/MachinesCodeForm/MachinesCodeContent.jsx b/src/components/dashboard/roadPatrols/supervisor/RowActions/MachinesCodeForm/MachinesCodeContent.jsx new file mode 100644 index 0000000..1eef774 --- /dev/null +++ b/src/components/dashboard/roadPatrols/supervisor/RowActions/MachinesCodeForm/MachinesCodeContent.jsx @@ -0,0 +1,55 @@ +import { DialogContent, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from "@mui/material"; +import ShowPlak from "@/core/components/ShowPlak"; + +const MachinesCodeContent = ({ machinesLists }) => { + return ( + <> + + + + + + + کد ماشین + نام خودرو + پلاک + + + + {machinesLists.map((machine) => { + return ( + + {machine.machine_code} + {machine.car_name} + + {machine.plak_number ? ( + + ) : null} + + + ); + })} + +
+
+
+
+ + ); +}; +export default MachinesCodeContent; diff --git a/src/components/dashboard/roadPatrols/supervisor/RowActions/MachinesCodeForm/index.jsx b/src/components/dashboard/roadPatrols/supervisor/RowActions/MachinesCodeForm/index.jsx new file mode 100644 index 0000000..9696333 --- /dev/null +++ b/src/components/dashboard/roadPatrols/supervisor/RowActions/MachinesCodeForm/index.jsx @@ -0,0 +1,43 @@ +import { Button, Dialog, DialogActions, DialogTitle, IconButton, Tooltip } from "@mui/material"; +import DirectionsCarIcon from "@mui/icons-material/DirectionsCar"; +import { useState } from "react"; +import MachinesCodeContent from "./MachinesCodeContent"; + +const MachinesCodeDialog = ({ machinesLists }) => { + const [openMachinesCodeDialog, setOpenMachinesCodeDialog] = useState(false); + return ( + <> + + setOpenMachinesCodeDialog(true)}> + + + + setOpenMachinesCodeDialog(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={"md"} + > + کد خودرو + + + + + + + ); +}; +export default MachinesCodeDialog; \ No newline at end of file diff --git a/src/components/dashboard/roadPatrols/supervisor/RowActions/OfficerDescription/index.jsx b/src/components/dashboard/roadPatrols/supervisor/RowActions/OfficerDescription/index.jsx index 8b3675b..04b5946 100644 --- a/src/components/dashboard/roadPatrols/supervisor/RowActions/OfficerDescription/index.jsx +++ b/src/components/dashboard/roadPatrols/supervisor/RowActions/OfficerDescription/index.jsx @@ -1,26 +1,10 @@ import { Dialog, DialogContent, DialogTitle, IconButton, Tooltip, Typography, Card, CardContent } from "@mui/material"; import { useState } from "react"; -import useRequest from "@/lib/hooks/useRequest"; import RemoveRedEyeIcon from "@mui/icons-material/RemoveRedEye"; import CloseIcon from "@mui/icons-material/Close"; -const OfficerDescriptionForm = ({ row }) => { +const OfficerDescriptionForm = ({ description }) => { const [openOfficerDescriptionDialog, setOpenOfficerDescriptionDialog] = useState(false); - const requestServer = useRequest(); - - const handleSubmit = () => { - // requestServer(`${RESERVE_PASSENGER_BOSS}/${rowId}`, "post", { description }) - // .then((response) => { - // setOpenOfficerDescriptionDialog(false); - // mutate(); - // }) - // .catch((error) => { - // console.error(error); - // }) - // .finally(() => { - // setIsSubmitting(false); - // }); - }; return ( <> @@ -55,18 +39,7 @@ const OfficerDescriptionForm = ({ row }) => { - - توضیحات : - - - {row.original.description || "هیچ توضیحی موجود نیست"}{" "} - {/* should replace row.original.description with the back end*/} - + {description || "هیچ توضیحی موجود نیست"} @@ -74,5 +47,4 @@ const OfficerDescriptionForm = ({ row }) => { ); }; - export default OfficerDescriptionForm; diff --git a/src/components/dashboard/roadPatrols/supervisor/RowActions/RahdaranForm/RahdaranContent.jsx b/src/components/dashboard/roadPatrols/supervisor/RowActions/RahdaranForm/RahdaranContent.jsx new file mode 100644 index 0000000..d1e9b15 --- /dev/null +++ b/src/components/dashboard/roadPatrols/supervisor/RowActions/RahdaranForm/RahdaranContent.jsx @@ -0,0 +1,48 @@ +import { DialogContent, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from "@mui/material"; + +const RahdaranContent = ({ rahdarLists }) => { + return ( + <> + + + + + + + کد راهدار + نام + + + + {rahdarLists.map((rahdar) => { + return ( + + {rahdar.code} + {rahdar.name} + + ); + })} + +
+
+
+
+ + ); +}; +export default RahdaranContent; diff --git a/src/components/dashboard/roadPatrols/supervisor/RowActions/RahdaranForm/index.jsx b/src/components/dashboard/roadPatrols/supervisor/RowActions/RahdaranForm/index.jsx new file mode 100644 index 0000000..2c73d80 --- /dev/null +++ b/src/components/dashboard/roadPatrols/supervisor/RowActions/RahdaranForm/index.jsx @@ -0,0 +1,38 @@ +import { Button, Dialog, DialogActions, DialogTitle, IconButton, Tooltip } from "@mui/material"; +import GroupsIcon from "@mui/icons-material/Groups"; +import { useState } from "react"; +import RahdaranContent from "./RahdaranContent"; + +const RahdaranDialog = ({ rahdarLists }) => { + const [openRahdaranDialog, setOpenRahdaranDialog] = useState(false); + return ( + <> + + setOpenRahdaranDialog(true)}> + + + + setOpenRahdaranDialog(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={"md"} + > + لیست راهداران + + + + + + + ); +}; +export default RahdaranDialog; diff --git a/src/components/dashboard/roadPatrols/supervisor/RowActions/ReportForm/index.jsx b/src/components/dashboard/roadPatrols/supervisor/RowActions/ReportForm/index.jsx index 8abb152..0319aaf 100644 --- a/src/components/dashboard/roadPatrols/supervisor/RowActions/ReportForm/index.jsx +++ b/src/components/dashboard/roadPatrols/supervisor/RowActions/ReportForm/index.jsx @@ -2,8 +2,7 @@ import { Tooltip, IconButton } from "@mui/material"; import PrintIcon from "@mui/icons-material/Print"; const ReportForm = ({ rowId }) => { - const reportUrl = "https://rms.rmto.ir/v2/road_patrols/operator/report/96872"; // TODO replace id here - + const reportUrl = `https://rms.rmto.ir/v2/road_patrols/operator/report/${rowId}`; return ( { return ( - - ); diff --git a/src/components/dashboard/roadPatrols/supervisor/SupervisorList.jsx b/src/components/dashboard/roadPatrols/supervisor/SupervisorList.jsx index 5d71669..5ec3369 100644 --- a/src/components/dashboard/roadPatrols/supervisor/SupervisorList.jsx +++ b/src/components/dashboard/roadPatrols/supervisor/SupervisorList.jsx @@ -1,15 +1,18 @@ "use client"; import { useMemo } from "react"; -import { Box, Typography } from "@mui/material"; +import {Box, Stack, Typography} from "@mui/material"; import DataTableWithAuth from "@/core/components/DataTableWithAuth"; import Toolbar from "./Toolbar"; import { GET_ROAD_PATROL_SUPERVISOR_LIST } from "@/core/utils/routes"; import moment from "jalali-moment"; import RowActions from "./RowActions"; import useProvinces from "@/lib/hooks/useProvince"; -import useRoadItemGetItems from "@/lib/hooks/useRoadItemGetItems"; import CustomSelectByDependency from "@/core/components/DataTable/filter/fieldsType/CustomSelectByDependency"; import useEdaratLists from "@/lib/hooks/useEdaratLists"; +import OfficerDescriptionForm from "./RowActions/OfficerDescription"; +import ReportForm from "./RowActions/ReportForm"; +import MachinesCodeDialog from "./RowActions/MachinesCodeForm"; +import RahdaranDialog from "./RowActions/RahdaranForm"; const OperatorList = () => { const columns = useMemo( @@ -92,31 +95,64 @@ const OperatorList = () => { Cell: ({ renderedCellValue, row }) => <>{row.original.edare_name}, }, { - accessorKey: "operator_name", - header: "نام مامور", - id: "operator_name", + accessorKey: "cmms_machines", + header: "خودرو", // Car ID + id: "cmmsMachines__machine_code", enableColumnFilter: true, datatype: "text", - filterMode: "equals", + filterMode: "contains", + enableSorting: false, columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + muiTableBodyCellProps: { + sx: { + borderLeft: "1px solid #e1e1e1", + py: 0, + "&:first-of-type": { + borderLeft: "unset", + }, + }, + }, + Cell: ({ renderedCellValue }) => { + if (renderedCellValue) { + return ( + + + + ); + } + return کد خودرویی وجود ندارد; + }, }, { - accessorKey: "officer_phone_number", - header: "تلفن همراه", - id: "officer_phone_number", - enableColumnFilter: true, - datatype: "text", - filterMode: "equals", - columnFilterModeOptions: ["equals", "contains"], - }, - { - accessorKey: "car_id", - header: "کد خودرو", - id: "car_id", - enableColumnFilter: true, - datatype: "text", - filterMode: "equals", - columnFilterModeOptions: ["equals", "contains"], + accessorKey: "rahdaran", + header: "راهداران", + id: "rahdaran", + enableColumnFilter: false, + enableSorting: false, + datatype: "array", + grow: false, + size: 100, + muiTableBodyCellProps: { + sx: { + borderLeft: "1px solid #e1e1e1", + py: 0, + "&:first-of-type": { + borderLeft: "unset", + }, + }, + }, + Cell: ({ renderedCellValue }) => { + if (renderedCellValue) { + return ( + + + + ); + } + return بدون شخص; + }, }, { accessorFn: (row) => moment(row.start_date).locale("fa").format("HH:mm | yyyy/MM/DD"), @@ -151,6 +187,54 @@ const OperatorList = () => { grow: false, size: 100, }, + { + accessorKey: "description", + header: "توضیحات مامور", + id: "description", + enableColumnFilter: false, + datatype: "text", + grow: false, + size: 100, + muiTableBodyCellProps: { + sx: { + borderLeft: "1px solid #e1e1e1", + py: 0, + "&:first-of-type": { + borderLeft: "unset", + }, + }, + }, + Cell: ({ renderedCellValue }) => { + return ( + + + + ); + }, + }, + { + header: "گزارش مامور", + enableColumnFilter: false, + datatype: "text", + grow: false, + size: 100, + muiTableBodyCellProps: { + sx: { + borderLeft: "1px solid #e1e1e1", + py: 0, + "&:first-of-type": { + borderLeft: "unset", + }, + }, + }, + Cell: ({ renderedCellValue, row }) => { + return ( + + + + ); + }, + }, ], [] ); @@ -159,7 +243,6 @@ const OperatorList = () => { <> { return ( - + ); }; diff --git a/src/core/components/ActivityCodeLog.jsx b/src/core/components/ActivityCodeLog.jsx new file mode 100644 index 0000000..cf284e6 --- /dev/null +++ b/src/core/components/ActivityCodeLog.jsx @@ -0,0 +1,36 @@ +"use client"; + +import { useEffect, useState, memo } from "react"; +import useRequest from "@/lib/hooks/useRequest"; +import { ACTIVITY_LOG } from "@/core/utils/routes"; + +const ActivityCodeLog = memo(({ activity_code }) => { + const requestServer = useRequest({ notificationShow: false }); + const [hasLogged, setHasLogged] = useState(false); + + useEffect(() => { + if (!activity_code || hasLogged) return; + + const controller = new AbortController(); + + const fetchActivityLog = async () => { + try { + await requestServer(ACTIVITY_LOG, "post", { + data: { activityCode: activity_code }, + signal: controller.signal, + }); + setHasLogged(true); + } catch (error) {} + }; + + fetchActivityLog(); + + return () => { + controller.abort(); + }; + }, [activity_code, hasLogged, requestServer]); + + return null; +}); + +export default ActivityCodeLog; diff --git a/src/core/components/CarCode.jsx b/src/core/components/CarCode.jsx index e765d24..a5e5ea7 100644 --- a/src/core/components/CarCode.jsx +++ b/src/core/components/CarCode.jsx @@ -21,7 +21,9 @@ const CarCode = ({ carCode, setCarCode, inputValueDefault = "", error, multiple requestOptions: { signal: controller.signal }, }) .then((response) => { - setOptions(response.data.data || []); + const combinedArray = carCode ? [...carCode, ...response.data.data] : [...response.data.data]; + const uniqueArray = Array.from(new Map(combinedArray.map((item) => [item.id, item])).values()); + setOptions(uniqueArray || []); }) .catch(() => { setOptions([]); @@ -38,7 +40,6 @@ const CarCode = ({ carCode, setCarCode, inputValueDefault = "", error, multiple fetchCarCodes(inputValue, controller); return () => controller.abort(); }, [inputValue]); - return ( { table_title, RowActions, specific_data, + specialFilter, } = props; const flatColumns = flattenArrayOfObjects(columns, "columns"); const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10 }); @@ -33,29 +34,34 @@ const DataTable_Main = (props) => { }; const fetchUrl = useMemo(() => { + const params = new URLSearchParams(); + params.set("start", `${pagination.pageIndex * pagination.pageSize}`); + params.set("size", pagination.pageSize); const isValueEmpty = (value) => { if (Array.isArray(value)) { return value.length === 0 || value.every((v) => v === ""); } return value === "" || value === null || value === undefined; }; + if (specialFilter) { + const filteredSpecialFilterData = Object.values(specialFilter).filter( + (filter) => !isValueEmpty(filter.value) + ); + params.set("filters", JSON.stringify(filteredSpecialFilterData || [])); + } else { + const filteredFilterData = Object.values(filterData) + .filter((filter) => !isValueEmpty(filter.value)) + .map(({ filterMode, id, ...rest }) => ({ + ...rest, + id: id.replace(/__/g, "."), + fn: filterMode, + })); - const filteredFilterData = Object.values(filterData) - .filter((filter) => !isValueEmpty(filter.value)) - .map(({ filterMode, id, ...rest }) => ({ - ...rest, - id: id.replace(/__/g, "."), - fn: filterMode, - })); - - const params = new URLSearchParams(); - params.set("start", `${pagination.pageIndex * pagination.pageSize}`); - params.set("size", pagination.pageSize); - params.set("filters", JSON.stringify(filteredFilterData.length === 0 ? [] : filteredFilterData)); + params.set("filters", JSON.stringify(filteredFilterData.length === 0 ? [] : filteredFilterData)); + } params.set("sorting", JSON.stringify(sortData)); return `${table_url}?${params}`; - }, [table_url, filterData, pagination, columns, sortData]); - + }, [table_url, filterData, pagination, columns, sortData, specialFilter]); const fetcher = async (url) => { try { const response = await request(url); @@ -143,5 +149,4 @@ const DataTable_Main = (props) => { /> ); }; - export default DataTable_Main; diff --git a/src/core/components/MapInfoOneMarker.jsx b/src/core/components/MapInfoOneMarker.jsx index 95ccc2b..a0817bf 100644 --- a/src/core/components/MapInfoOneMarker.jsx +++ b/src/core/components/MapInfoOneMarker.jsx @@ -12,24 +12,19 @@ const MapLayer = dynamic(() => import("@/core/components/MapLayer"), { ssr: false, }); -const createCustomIcon = (size, iconUrl, labelText) => { +const createCustomIcon = (size, iconUrl, labelText, color) => { if (labelText) { return L.divIcon({ + className: "custom-marker", // Apply your custom CSS class html: ` -
- icon -
- ${labelText} +
+
+ ${labelText}
-
- `, - iconSize: size, - iconAnchor: [size[0] / 2, size[1]], - popupAnchor: [0, -size[1]], +
+
`, + iconSize: [50, 50], + iconAnchor: [25, 50], }); } @@ -45,6 +40,7 @@ const MAX_ZOOM_FOR_MARKER = 13; const MapInteraction = ({ setValue, startLat, startLng }) => { const [isMarkerLocked, setIsMarkerLocked] = useState(!!(startLat && startLng)); // وضعیت قفل مارکر const [enableSend, setEnableSend] = useState(false); + const [startIconColor, setStartIconColor] = useState(startLat ? "#1CAC66" : "#003d4f"); // رنگ آیکن شروع const [markerPosition, setMarkerPosition] = useState( startLat && startLng ? { lat: startLat, lng: startLng } : null ); @@ -79,6 +75,7 @@ const MapInteraction = ({ setValue, startLat, startLng }) => { setValue("start_point", { lat: center.lat.toString(), lng: center.lng.toString() }); setMarkerPosition({ lat: center.lat, lng: center.lng }); // به‌روزرسانی موقعیت مارکر setIsMarkerLocked(true); + setStartIconColor("#1CAC66"); } }; @@ -86,6 +83,7 @@ const MapInteraction = ({ setValue, startLat, startLng }) => { setValue("start_point", null); // حذف مقدار قبلی setIsMarkerLocked(false); // باز کردن قفل مارکر setMarkerPosition(null); // تنظیم مارکر به مرکز نقشه + setStartIconColor("#003d4f"); }; return ( @@ -93,7 +91,7 @@ const MapInteraction = ({ setValue, startLat, startLng }) => { import("@/core/components/MapLayer"), { loading: () => , ssr: false, }); -const createCustomIcon = (size, iconUrl, labelText) => { +const createCustomIcon = (size, iconUrl, labelText, color) => { if (labelText) { return L.divIcon({ + className: "custom-marker", // Apply your custom CSS class html: ` -
- icon -
- ${labelText} +
+
+ ${labelText}
-
- `, - iconSize: size, - iconAnchor: [size[0] / 2, size[1]], - popupAnchor: [0, -size[1]], +
+
`, + iconSize: [50, 50], + iconAnchor: [25, 50], }); } - return L.icon({ iconUrl: iconUrl, iconSize: size, @@ -48,6 +42,8 @@ const MapInteraction = ({ setValue, startLat, startLng, endLat, endLng }) => { const [startPosition, setStartPosition] = useState(startLat && startLng ? { lat: startLat, lng: startLng } : null); const [endPosition, setEndPosition] = useState(endLat && endLng ? { lat: endLat, lng: endLng } : null); const [enableSend, setEnableSend] = useState(false); + const [startIconColor, setStartIconColor] = useState(startLat ? "#1CAC66" : "#003d4f"); // رنگ آیکن شروع + const [endIconColor, setEndIconColor] = useState(endLat ? "#D13131" : "#003d4f"); // رنگ آیکن پایان const startRef = useRef(); const endRef = useRef(); @@ -86,6 +82,7 @@ const MapInteraction = ({ setValue, startLat, startLng, endLat, endLng }) => { setIsStartLocked(false); setStartPosition(null); setValue("start_point", null); + setStartIconColor("#003d4f"); }; const handleUnlockEnd = () => { @@ -95,6 +92,8 @@ const MapInteraction = ({ setValue, startLat, startLng, endLat, endLng }) => { setStartPosition(null); setValue("end_point", ""); setValue("start_point", null); + setStartIconColor("#003d4f"); + setEndIconColor("#003d4f"); }; return ( @@ -102,7 +101,7 @@ const MapInteraction = ({ setValue, startLat, startLng, endLat, endLng }) => { { if (!enableSend) return; @@ -111,6 +110,8 @@ const MapInteraction = ({ setValue, startLat, startLng, endLat, endLng }) => { setValue("start_point", { lat: center.lat.toString(), lng: center.lng.toString() }); setStartPosition({ lat: center.lat, lng: center.lng }); setIsStartLocked(true); + setStartIconColor("#1CAC66"); + map.panBy([25, 25]) } }, }} @@ -172,7 +173,7 @@ const MapInteraction = ({ setValue, startLat, startLng, endLat, endLng }) => { { if (!enableSend) return; @@ -181,6 +182,14 @@ const MapInteraction = ({ setValue, startLat, startLng, endLat, endLng }) => { setValue("end_point", { lat: center.lat.toString(), lng: center.lng.toString() }); setEndPosition({ lat: center.lat, lng: center.lng }); setIsEndLocked(true); + setEndIconColor("#D13131"); + map.fitBounds( + [ + startPosition, + map.getCenter(), + ], + { paddingTopLeft: [16, 16], paddingBottomRight: [16, 16] } + ); } }, }} diff --git a/src/core/components/MuiDatePicker.jsx b/src/core/components/MuiDatePicker.jsx index 78ffe58..10d5dff 100644 --- a/src/core/components/MuiDatePicker.jsx +++ b/src/core/components/MuiDatePicker.jsx @@ -59,9 +59,11 @@ function MuiDatePicker({ value, setFieldValue, name, minDate, maxDate, helperTex }, }} /> - - {helperText ? helperText : ""} - + {helperText ? ( + + {helperText} + + ) : null} ); diff --git a/src/core/components/MuiTimePicker.jsx b/src/core/components/MuiTimePicker.jsx index 35532fd..8aeace6 100644 --- a/src/core/components/MuiTimePicker.jsx +++ b/src/core/components/MuiTimePicker.jsx @@ -64,9 +64,11 @@ function MuiTimePicker({ value, setFieldValue, name, minTime, maxTime, helperTex }, }} /> - - {helperText ? helperText : ""} - + {helperText ? ( + + {helperText} + + ) : null} ); diff --git a/src/core/components/RahdarCode.jsx b/src/core/components/RahdarCode.jsx index 76592ef..1c374ee 100644 --- a/src/core/components/RahdarCode.jsx +++ b/src/core/components/RahdarCode.jsx @@ -22,7 +22,11 @@ const RahdarCode = ({ rahdarsCode, setRahdarsCode, error, multiple = true }) => requestOptions: { signal: controller.signal }, }) .then((response) => { - setOptions(response.data.data || []); + const combinedArray = rahdarsCode + ? [...rahdarsCode, ...response.data.data] + : [...response.data.data]; + const uniqueArray = Array.from(new Map(combinedArray.map((item) => [item.id, item])).values()); + setOptions(uniqueArray || []); }) .catch(() => { setOptions([]); diff --git a/src/core/middlewares/withPermission.js b/src/core/middlewares/withPermission.js index c6e3661..0da81c9 100644 --- a/src/core/middlewares/withPermission.js +++ b/src/core/middlewares/withPermission.js @@ -2,16 +2,24 @@ import { Box, Typography } from "@mui/material"; import { usePermissions } from "@/lib/hooks/usePermissions"; +import { useEffect, useState } from "react"; function WithPermission({ children, permission_name }) { const { data, error, isLoading } = usePermissions(); + const [cachedData, setCachedData] = useState(null); - if (error || isLoading || !data || !permission_name) { + useEffect(() => { + if (data) { + setCachedData(data); + } + }, [data]); + + if (error || isLoading || !cachedData || !permission_name) { return null; } const hasPermission = - permission_name.includes("all") || permission_name.some((permission) => data.includes(permission)); + permission_name.includes("all") || permission_name.some((permission) => cachedData.includes(permission)); if (!hasPermission) { return ( diff --git a/src/core/utils/formatCounter.js b/src/core/utils/formatCounter.js new file mode 100644 index 0000000..7cf9122 --- /dev/null +++ b/src/core/utils/formatCounter.js @@ -0,0 +1,7 @@ +export const formatCounter = (counter) => { + const minutes = Math.floor(counter / 60) + .toString() + .padStart(2, "0"); + const seconds = (counter % 60).toString().padStart(2, "0"); + return `${minutes}:${seconds}`; +}; diff --git a/src/core/utils/pageMenu.js b/src/core/utils/pageMenu.js index f77574f..bf392e4 100644 --- a/src/core/utils/pageMenu.js +++ b/src/core/utils/pageMenu.js @@ -195,13 +195,6 @@ export const pageMenu = [ hasSubitems: true, badges: ["road_patrols.operation_cnt"], Subitems: [ - { - id: "roadPatrolManagmentOparationCreate", - label: "ثبت اقدام", - type: "page", - route: "/dashboard/road-patrols/operator", - permissions: ["add-road-patrol"], - }, { id: "roadPatrolManagmentOparationCartable", label: "کارتابل", diff --git a/src/core/utils/routes.js b/src/core/utils/routes.js index db6c244..06fe15d 100644 --- a/src/core/utils/routes.js +++ b/src/core/utils/routes.js @@ -30,9 +30,13 @@ export const UPDATE_AZMAYESH_TYPE = api + "/api/v3/azmayesh_types/update"; //road patrol export const GET_ROAD_PATROL_OPERATOR_LIST = api + "/api/v3/road_patrols/operator_index"; -export const EXPORT_ROAD_PATROL_OPERATOR_LIST = "https://rms.rmto.ir/v2/road_patrols/operator/cartable/report"; +export const EXPORT_ROAD_PATROL_OPERATOR_LIST = "https://rms.witel.ir/v2/road_patrols/operator/cartable/report"; export const GET_ROAD_PATROL_SUPERVISOR_LIST = api + "/api/v3/road_patrols/supervisor_index"; -export const EXPORT_ROAD_PATROL_SUPERVISOR_LIST = "https://rms.rmto.ir/v2/road_patrols/supervisor/cartable/report"; +export const EXPORT_ROAD_PATROL_SUPERVISOR_LIST = "https://rms.witel.ir/v2/road_patrols/supervisor/cartable/report"; +export const DELETE_ROAD_PATROL_SUPERVISOR = api + "/api/v3/road_patrols/delete"; +export const CREATE_PATROL = api + "/api/v3/road_patrols/store"; +export const GET_FMS_DATA = api + "/api/v3/fms_vehicle/get_activity"; +export const GET_OTP_TOKEN = api + "/v2/get_otp_token"; // road items export const GET_ROAD_ITEMS_SUPERVISOR_LIST = api + "/api/v3/road_items/supervisor_index"; @@ -50,3 +54,7 @@ export const DELETE_BY_SUPERVISOR = api + "/api/v3/road_items/delete"; export const RESTORE_BY_SUPERVISOR = api + "/api/v3/road_items/restore"; export const GET_CAR_LIST_SEARCH = api + "/api/v3/cmms_machines/search"; export const GET_RAHDARANS_LIST_SEARCH = api + "/api/v3/rahdaran/search"; +export const GET_OBSERVED_GASHT_LIST = api + "/api/v3/observed_items/filter"; + +// activity code log +export const ACTIVITY_LOG = api + "/api/v3/profile/add_activity"; diff --git a/src/core/utils/theme.js b/src/core/utils/theme.js index 85c8f68..7cde9e0 100644 --- a/src/core/utils/theme.js +++ b/src/core/utils/theme.js @@ -1,5 +1,6 @@ "use client"; import { createTheme } from "@mui/material"; +import { grey } from '@mui/material/colors'; const theme = createTheme({ direction: "rtl", @@ -16,6 +17,9 @@ const theme = createTheme({ main: "#015688", contrastText: "#fff", }, + secondary: { + main: grey[700], + } }, components: { MuiBackdrop: { diff --git a/src/lib/hooks/usePermissions.js b/src/lib/hooks/usePermissions.js index 004ff6d..3fb4921 100644 --- a/src/lib/hooks/usePermissions.js +++ b/src/lib/hooks/usePermissions.js @@ -14,5 +14,5 @@ export const usePermissions = () => { } }; - return useSWR(GET_PERMISSIONS_ROUTE, fetcher, { keepPreviousData: true }); + return useSWR(GET_PERMISSIONS_ROUTE, fetcher, { keepPreviousData: true, dedupingInterval: 30000 }); }; diff --git a/src/lib/hooks/useRequest.js b/src/lib/hooks/useRequest.js index f160f53..8e6d121 100644 --- a/src/lib/hooks/useRequest.js +++ b/src/lib/hooks/useRequest.js @@ -20,7 +20,6 @@ const useRequest = (initOptions) => { return async (url = "", method = "get", options) => { const mergedOptions = Object.assign({}, _options, options); - try { const response = await axios({ url, diff --git a/src/lib/hooks/useSidebarBadge.js b/src/lib/hooks/useSidebarBadge.js index 621ce55..29e5fed 100644 --- a/src/lib/hooks/useSidebarBadge.js +++ b/src/lib/hooks/useSidebarBadge.js @@ -14,5 +14,5 @@ export const useSidebarBadge = () => { } }; - return useSWR(GET_SIDEBAR_BADGE_ROUTE, fetcher, { keepPreviousData: true }); + return useSWR(GET_SIDEBAR_BADGE_ROUTE, fetcher, { keepPreviousData: true, dedupingInterval: 10000 }); };