diff --git a/src/app/(withAuth)/dashboard/road-safety/operator/loading.jsx b/src/app/(withAuth)/dashboard/road-safety/operator/loading.jsx
new file mode 100644
index 0000000..4535a8d
--- /dev/null
+++ b/src/app/(withAuth)/dashboard/road-safety/operator/loading.jsx
@@ -0,0 +1,7 @@
+"use client";
+import PageLoading from "@/core/components/PageLoading";
+
+const Loading = () => {
+ return ;
+};
+export default Loading;
diff --git a/src/app/(withAuth)/dashboard/road-safety/operator/page.js b/src/app/(withAuth)/dashboard/road-safety/operator/page.js
new file mode 100644
index 0000000..468d2d6
--- /dev/null
+++ b/src/app/(withAuth)/dashboard/road-safety/operator/page.js
@@ -0,0 +1,20 @@
+import WithPermission from "@/core/middlewares/withPermission";
+import OperatorPage from "@/components/dashboard/roadSafety/operator";
+// import ActivityCodeLog from "@/core/components/ActivityCodeLog";
+
+const Page = () => {
+ return (
+
+
+ {/**/}
+
+ );
+};
+
+export default Page;
diff --git a/src/components/dashboard/roadSafety/operator/ExcelPrint/index.jsx b/src/components/dashboard/roadSafety/operator/ExcelPrint/index.jsx
new file mode 100644
index 0000000..2970e57
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/ExcelPrint/index.jsx
@@ -0,0 +1,74 @@
+import { Button, CircularProgress, IconButton, useMediaQuery } from "@mui/material";
+import { useMemo, useState } from "react";
+import moment from "jalali-moment";
+import FileSaver from "file-saver";
+import DescriptionIcon from "@mui/icons-material/Description";
+import useRequest from "@/lib/hooks/useRequest";
+import { useTheme } from "@emotion/react";
+import DataTableFilterDataStructure from "@/core/utils/DataTableFilterDataStructure";
+import isArrayEmpty from "@/core/utils/isArrayEmpty";
+import { EXPORT_OPERATOR_ROAD_SAFETY } from "@/core/utils/routes";
+
+const PrintExcel = ({ table, filterData }) => {
+ const [loading, setLoading] = useState(false);
+ const theme = useTheme();
+ const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
+ const requestServer = useRequest();
+ const activeFilters = Object.entries(filterData).reduce((acc, [key, filter]) => {
+ if (filter.value && (!Array.isArray(filter.value) || filter.value.some((item) => item.trim() !== ""))) {
+ acc.push({ id: key, value: filter.value });
+ }
+ return acc;
+ }, []);
+
+ const filterParams = useMemo(() => {
+ const params = new URLSearchParams();
+ if (activeFilters.length > 0) {
+ activeFilters.map((filter, index) => {
+ const filteredFilterData = DataTableFilterDataStructure(filterData, isArrayEmpty);
+ params.set("filters", JSON.stringify(filteredFilterData.length === 0 ? [] : filteredFilterData));
+ });
+ } else {
+ params.set("filters", JSON.stringify([]));
+ }
+ return params;
+ }, [activeFilters]);
+
+ const clickHandler = () => {
+ setLoading(true);
+ requestServer(`${EXPORT_OPERATOR_ROAD_SAFETY}?${filterParams}`, "get", {
+ requestOptions: { responseType: "blob" },
+ })
+ .then((response) => {
+ const filename = `خروجی کارتابل عملیات نگهداری حریم تاریخ_${moment().format("jYYYY_jMM_jDD")}.xlsx`;
+ FileSaver.saveAs(response.data, filename);
+ })
+ .catch(() => {})
+ .finally(() => {
+ setLoading(false);
+ });
+ };
+
+ return (
+ <>
+ {isMobile ? (
+
+
+
+ ) : (
+ : }
+ onClick={clickHandler}
+ >
+ خروجی اکسل
+
+ )}
+ >
+ );
+};
+export default PrintExcel;
diff --git a/src/components/dashboard/roadSafety/operator/Form/StepOne/CreateFormContent.jsx b/src/components/dashboard/roadSafety/operator/Form/StepOne/CreateFormContent.jsx
new file mode 100644
index 0000000..3ff2907
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/Form/StepOne/CreateFormContent.jsx
@@ -0,0 +1,154 @@
+import React, { useState } from "react";
+import { useForm } from "react-hook-form";
+import { yupResolver } from "@hookform/resolvers/yup";
+import { mixed, number, object, string } from "yup";
+import { Box, Button, DialogActions, DialogContent, Tab, Tabs } from "@mui/material";
+import StyledForm from "@/core/components/StyledForm";
+import InsertDriveFileIcon from "@mui/icons-material/InsertDriveFile";
+import FileCopyIcon from "@mui/icons-material/FileCopy";
+import ExitToAppIcon from "@mui/icons-material/ExitToApp";
+import KeyboardDoubleArrowRightIcon from "@mui/icons-material/KeyboardDoubleArrowRight";
+import BeenhereIcon from "@mui/icons-material/Beenhere";
+import useRequest from "@/lib/hooks/useRequest";
+import GetItemInfo from "./GetItemInfo";
+import GetSubItemInfo from "./GetSubItemInfo";
+import { format } from "date-fns";
+import { FIRST_STEP_STORE } from "@/core/utils/routes";
+
+function TabPanel(props) {
+ const { children, value, index } = props;
+ return (
+
+ {value === index && {children}}
+
+ );
+}
+
+const validationSchema = object({
+ recognize_picture: mixed().nullable().required("لطفا عکس فعالیت را بارگذاری کنید!"),
+ info_id: number().required("نوع آیتم را مشخص کنید!"),
+ axis_type_id: number().required("نوع محور را مشخص کنید!"),
+ start_point: mixed()
+ .test("start-point-required", "لطفاً نقطه شروع را مشخص کنید!", function (value) {
+ return !!value; // چک میکند که مقدار موجود است
+ })
+ .required("لطفاً نقطه فعالیت را مشخص کنید!"),
+ activity_time: string().required("لطفا زمان فعالیت را انتخاب کنید!"),
+ activity_date: string().required("لطفا تاریخ فعالیت را انتخاب کنید!"),
+});
+
+const CreateFormContent = ({ setOpen, mutate }) => {
+ const requestServer = useRequest({ notificationSuccess: true });
+ const [itemsList, setItemsList] = useState();
+ const defaultValues = {
+ info_id: null,
+ axis_type_id: null,
+ recognize_picture: null,
+ activity_date: "",
+ activity_time: "",
+ start_point: "",
+ };
+
+ const [tabState, setTabState] = useState(0);
+ const handleClose = () => {
+ setOpen(false);
+ };
+ const handleChangeTab = (event, newValue) => {
+ setTabState(newValue);
+ };
+
+ const handlePrev = () => {
+ if (tabState === 2) {
+ const fieldsToReset = ["recognize_picture", "activity_time", "activity_date", "start_point"];
+ fieldsToReset.forEach((field) => resetField(field));
+ }
+ if (tabState === 0) {
+ handleClose();
+ } else {
+ setTabState(tabState - 1);
+ }
+ };
+ const {
+ control,
+ handleSubmit,
+ resetField,
+ setValue,
+ formState: { errors, isSubmitting },
+ } = useForm({
+ defaultValues,
+ resolver: yupResolver(validationSchema),
+ mode: "onBlur",
+ });
+ const onSubmitBase = async (data) => {
+ const startPoint = `${data.start_point.lat},${data.start_point.lng}`;
+ const formData = new FormData();
+ formData.append("activity_date", data.activity_date);
+ formData.append("activity_time", format(new Date(data.activity_time), "HH:mm"));
+ formData.append("info_id", data.info_id);
+ formData.append("axis_type_id", data.axis_type_id);
+ formData.append("recognize_picture", data.recognize_picture);
+ formData.append("point", startPoint);
+ await requestServer(FIRST_STEP_STORE, "post", {
+ data: formData,
+ })
+ .then((response) => {
+ mutate();
+ setOpen(false);
+ })
+ .catch((error) => {});
+ };
+
+ return (
+
+
+ } label="انتخاب آیتم" />
+ } label="اطلاعات مورد مشاهده شده" />
+
+
+
+
+
+
+
+
+
+
+
+
+ : }
+ >
+ {tabState === 0 ? "بستن" : "مرحله قبل"}
+
+ {tabState === 1 && (
+ }
+ >
+ {isSubmitting ? "در حال ثبت فعالیت" : "ثبت فعالیت"}
+
+ )}
+
+
+ );
+};
+export default CreateFormContent;
diff --git a/src/components/dashboard/roadSafety/operator/Form/StepOne/GetItemInfo.jsx b/src/components/dashboard/roadSafety/operator/Form/StepOne/GetItemInfo.jsx
new file mode 100644
index 0000000..da3c533
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/Form/StepOne/GetItemInfo.jsx
@@ -0,0 +1,63 @@
+import React from "react";
+import { Card, CardActionArea, Grid, LinearProgress, Typography } from "@mui/material";
+import Image from "next/image";
+import { Controller } from "react-hook-form";
+import useSafetyAndPrivacyGetItems from "@/lib/hooks/useSafetyAndPrivacyGetItems";
+
+const GetItemInfo = ({ setItemsList, setTabState, control }) => {
+ const { itemsList, loadingItemsList, errorItemsList } = useSafetyAndPrivacyGetItems();
+
+ return (
+ <>
+ {errorItemsList ? (
+
+ خطا در دریافت لیست آیتم ها
+
+ ) : loadingItemsList ? (
+
+ ) : (
+
+ (
+ <>
+ {itemsList.map((item) => (
+
+ {
+ field.onChange(item.id);
+ setItemsList(item);
+ setTabState(1);
+ }}
+ >
+
+ {item.name}
+
+
+
+ ))}
+ >
+ )}
+ />
+
+ )}
+ >
+ );
+};
+export default GetItemInfo;
diff --git a/src/components/dashboard/roadSafety/operator/Form/StepOne/GetSubItemInfo.jsx b/src/components/dashboard/roadSafety/operator/Form/StepOne/GetSubItemInfo.jsx
new file mode 100644
index 0000000..9a6ae21
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/Form/StepOne/GetSubItemInfo.jsx
@@ -0,0 +1,129 @@
+import { Box, Chip, Divider, Grid, Stack, Typography } from "@mui/material";
+import InsertDriveFileIcon from "@mui/icons-material/InsertDriveFile";
+import ImageUpload from "./ImageUpload";
+import { Controller, useWatch } from "react-hook-form";
+import MapInfoOneMarker from "@/core/components/MapInfoOneMarker";
+import MuiDatePicker from "@/core/components/MuiDatePicker";
+import MuiTimePicker from "@/core/components/MuiTimePicker";
+import SelectBox from "@/core/components/SelectBox";
+
+const GetSubItemInfo = ({ itemsList, control, setValue, errors }) => {
+ const StartPoint = useWatch({ control, name: "start_point" });
+ return (
+
+
+
+
+
+ }
+ label={
+
+ آیتم انتخاب شده
+
+ }
+ />
+
+
+
+ {itemsList?.name || "هیچ آیتمی انتخاب نشده است"}
+
+
+
+
+
+
+
+ (
+
+ )}
+ />
+
+
+
+
+
+
+ {
+ return (
+ field.onChange(value || [])}
+ helperText={error ? error.message : null}
+ />
+ );
+ }}
+ name={"activity_date"}
+ />
+
+
+ {
+ return (
+ field.onChange(value || null)}
+ helperText={error ? error.message : null}
+ />
+ );
+ }}
+ name={"activity_time"}
+ />
+
+
+ (
+
+ )}
+ />
+
+
+
+
+
+
+
+ );
+};
+export default GetSubItemInfo;
diff --git a/src/components/dashboard/roadSafety/operator/Form/StepOne/ImageUpload.jsx b/src/components/dashboard/roadSafety/operator/Form/StepOne/ImageUpload.jsx
new file mode 100644
index 0000000..5186a4b
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/Form/StepOne/ImageUpload.jsx
@@ -0,0 +1,77 @@
+import { FormControl, FormHelperText } from "@mui/material";
+import UploadSystem from "@/core/components/UploadSystem";
+import React, { useEffect, useState } from "react";
+
+const ImageUpload = ({ name, value, onChange, error, title }) => {
+ const [beforeImg, setBeforeImg] = useState(value ? value : null);
+ const [beforeFileType, setBeforeFileType] = useState(value ? "image/" : null);
+ const [beforeFileName, setBeforeFileName] = useState(null);
+ const [showBeforeImage, setShowBeforeImage] = useState(!value);
+
+ useEffect(() => {
+ if (value) {
+ setShowBeforeImage(false);
+ if (typeof value === "string") {
+ setBeforeImg(value);
+ setBeforeFileType("image/");
+ } else if (value instanceof File) {
+ setBeforeImg(URL.createObjectURL(value));
+ setBeforeFileType(value.type);
+ }
+ }
+ }, [value]);
+
+ const handleFileChange = (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);
+ onChange(uploadedFile);
+ setShowBeforeImage(false);
+ }
+ };
+
+ return (
+
+
+ {title}
+
+
+ {error ? error.message : null}
+
+ );
+};
+export default ImageUpload;
diff --git a/src/components/dashboard/roadSafety/operator/Form/StepOne/OperatorCreateForm.jsx b/src/components/dashboard/roadSafety/operator/Form/StepOne/OperatorCreateForm.jsx
new file mode 100644
index 0000000..44b2828
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/Form/StepOne/OperatorCreateForm.jsx
@@ -0,0 +1,26 @@
+"use client";
+import { Dialog, IconButton } from "@mui/material";
+import CreateFormContent from "./CreateFormContent";
+import CloseIcon from "@mui/icons-material/Close";
+
+const OperatorCreateForm = ({ open, setOpen, mutate }) => {
+ return (
+
+ );
+};
+export default OperatorCreateForm;
diff --git a/src/components/dashboard/roadSafety/operator/Form/StepOne/index.jsx b/src/components/dashboard/roadSafety/operator/Form/StepOne/index.jsx
new file mode 100644
index 0000000..e390936
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/Form/StepOne/index.jsx
@@ -0,0 +1,36 @@
+import { Button, IconButton, useMediaQuery } from "@mui/material";
+import { AddCircle } from "@mui/icons-material";
+import { useTheme } from "@emotion/react";
+import { useState } from "react";
+import OperatorCreateForm from "./OperatorCreateForm";
+
+const StepOne = ({ mutate }) => {
+ const theme = useTheme();
+ const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
+ const [open, setOpen] = useState(false);
+
+ const handleOpen = () => {
+ setOpen(true);
+ };
+ return (
+ <>
+ {isMobile ? (
+
+
+
+ ) : (
+ }
+ onClick={handleOpen}
+ >
+ ثبت فعالیت
+
+ )}
+
+ >
+ );
+};
+export default StepOne;
diff --git a/src/components/dashboard/roadSafety/operator/Form/StepThree/ImageUpload.jsx b/src/components/dashboard/roadSafety/operator/Form/StepThree/ImageUpload.jsx
new file mode 100644
index 0000000..5186a4b
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/Form/StepThree/ImageUpload.jsx
@@ -0,0 +1,77 @@
+import { FormControl, FormHelperText } from "@mui/material";
+import UploadSystem from "@/core/components/UploadSystem";
+import React, { useEffect, useState } from "react";
+
+const ImageUpload = ({ name, value, onChange, error, title }) => {
+ const [beforeImg, setBeforeImg] = useState(value ? value : null);
+ const [beforeFileType, setBeforeFileType] = useState(value ? "image/" : null);
+ const [beforeFileName, setBeforeFileName] = useState(null);
+ const [showBeforeImage, setShowBeforeImage] = useState(!value);
+
+ useEffect(() => {
+ if (value) {
+ setShowBeforeImage(false);
+ if (typeof value === "string") {
+ setBeforeImg(value);
+ setBeforeFileType("image/");
+ } else if (value instanceof File) {
+ setBeforeImg(URL.createObjectURL(value));
+ setBeforeFileType(value.type);
+ }
+ }
+ }, [value]);
+
+ const handleFileChange = (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);
+ onChange(uploadedFile);
+ setShowBeforeImage(false);
+ }
+ };
+
+ return (
+
+
+ {title}
+
+
+ {error ? error.message : null}
+
+ );
+};
+export default ImageUpload;
diff --git a/src/components/dashboard/roadSafety/operator/Form/StepThree/StepThreeContent.jsx b/src/components/dashboard/roadSafety/operator/Form/StepThree/StepThreeContent.jsx
new file mode 100644
index 0000000..c0902c3
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/Form/StepThree/StepThreeContent.jsx
@@ -0,0 +1,69 @@
+import { Button, DialogActions, DialogContent, Stack } from "@mui/material";
+import { Controller, useForm } from "react-hook-form";
+import { yupResolver } from "@hookform/resolvers/yup";
+import StyledForm from "@/core/components/StyledForm";
+import { mixed, object } from "yup";
+import ImageUpload from "./ImageUpload";
+import useRequest from "@/lib/hooks/useRequest";
+import { THIRD_STEP_STORE } from "@/core/utils/routes";
+
+const StepThreeContent = ({ setOpen, mutate, rowId }) => {
+ const requestServer = useRequest({ notificationSuccess: true });
+ const defaultValues = {
+ action_picture: null,
+ };
+ const validationSchema = object({
+ action_picture: mixed().nullable().required("لطفا عکس اقدام را بارگذاری کنید!"),
+ });
+ const {
+ control,
+ handleSubmit,
+ formState: { isSubmitting, errors },
+ } = useForm({
+ defaultValues,
+ resolver: yupResolver(validationSchema),
+ mode: "onBlur",
+ });
+ const onSubmit = async (data) => {
+ const formData = new FormData();
+ formData.append("action_picture", data.action_picture);
+ await requestServer(`${THIRD_STEP_STORE}/${rowId}`, "post", {
+ data: formData,
+ })
+ .then((response) => {
+ mutate();
+ setOpen(false);
+ })
+ .catch((error) => {});
+ };
+ return (
+
+
+
+ (
+
+ )}
+ />
+
+
+
+
+
+
+
+ );
+};
+export default StepThreeContent;
diff --git a/src/components/dashboard/roadSafety/operator/Form/StepThree/index.jsx b/src/components/dashboard/roadSafety/operator/Form/StepThree/index.jsx
new file mode 100644
index 0000000..a2bb0ad
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/Form/StepThree/index.jsx
@@ -0,0 +1,32 @@
+import { Dialog, DialogTitle, IconButton, Tooltip } from "@mui/material";
+import { useState } from "react";
+import StepThreeContent from "./StepThreeContent";
+import AddPhotoAlternateIcon from "@mui/icons-material/AddPhotoAlternate";
+const StepThree = ({ mutate, rowId }) => {
+ const [open, setOpen] = useState(false);
+ return (
+ <>
+
+ setOpen(true)}>
+
+
+
+
+ >
+ );
+};
+export default StepThree;
diff --git a/src/components/dashboard/roadSafety/operator/Form/StepTwo/ShowDocuments.jsx b/src/components/dashboard/roadSafety/operator/Form/StepTwo/ShowDocuments.jsx
new file mode 100644
index 0000000..93958c8
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/Form/StepTwo/ShowDocuments.jsx
@@ -0,0 +1,37 @@
+import { Box, Card, IconButton, Stack, Typography } from "@mui/material";
+import DeleteIcon from "@mui/icons-material/Delete";
+import React from "react";
+import MinorCrashIcon from "@mui/icons-material/MinorCrash";
+
+const ShowDocuments = ({ deleteDamageItem, selectedDamageItem }) => {
+ return (
+
+
+
+
+
+ {selectedDamageItem.name}
+
+
+
+
+
+ deleteDamageItem(selectedDamageItem.name)}>
+
+
+
+
+ );
+};
+export default ShowDocuments;
diff --git a/src/components/dashboard/roadSafety/operator/Form/StepTwo/StepTwoContent.jsx b/src/components/dashboard/roadSafety/operator/Form/StepTwo/StepTwoContent.jsx
new file mode 100644
index 0000000..b21be85
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/Form/StepTwo/StepTwoContent.jsx
@@ -0,0 +1,129 @@
+import { Box, Button, Chip, DialogActions, DialogContent, Divider, Fade, Grid, Stack, Typography } from "@mui/material";
+import { useEffect, useState } from "react";
+import { Controller, useForm } from "react-hook-form";
+import { yupResolver } from "@hookform/resolvers/yup";
+import { mixed, object } from "yup";
+import ShowDocuments from "./ShowDocuments";
+import StyledForm from "@/core/components/StyledForm";
+import { SECOND_STEP_STORE } from "@/core/utils/routes";
+import useRequest from "@/lib/hooks/useRequest";
+
+const StepTwoContent = ({ setOpenStepTwoDialog, mutate, rowId }) => {
+ const requestServer = useRequest({ notificationSuccess: true });
+ const [selectedDamageItemList, setSelectedDamageItemList] = useState([]);
+ const defaultValues = {
+ judiciary_document: null,
+ };
+ const validationSchema = object({
+ judiciary_document: mixed().test("is-array", "لطفا حداقل یک فایل بارگذاری کنید!", (value) => {
+ return Array.isArray(value) && value.length > 0;
+ }),
+ });
+ const {
+ control,
+ handleSubmit,
+ setValue,
+ formState: { isSubmitting, errors },
+ } = useForm({
+ defaultValues,
+ resolver: yupResolver(validationSchema),
+ mode: "onBlur",
+ });
+
+ const handleCreateDamage = (files) => {
+ setSelectedDamageItemList((prev) => {
+ const newFiles = files.filter((file) => !prev.some((item) => item.name === file.name));
+ return [...prev, ...newFiles];
+ });
+ };
+ useEffect(() => {
+ setValue("judiciary_document", selectedDamageItemList);
+ }, [selectedDamageItemList]);
+
+ const deleteDamageItem = (name) => {
+ setSelectedDamageItemList((prev) => prev.filter((documentItem) => documentItem.name !== name));
+ };
+ const onSubmit = async (data) => {
+ const formData = new FormData();
+ data.judiciary_document.map((item, index) => formData.append(`judiciary_document[${index}]`, item));
+ await requestServer(`${SECOND_STEP_STORE}/${rowId}`, "post", {
+ data: formData,
+ })
+ .then((response) => {
+ mutate();
+ setOpenStepTwoDialog(false);
+ })
+ .catch((error) => {});
+ };
+ return (
+
+
+
+ (
+ <>
+
+ {error && {error.message}}
+ >
+ )}
+ />
+
+
+
+
+ {selectedDamageItemList.length === 0 && (
+
+
+ فایل موردنظر را بارگذاری کنید.
+
+
+ )}
+
+
+ {selectedDamageItemList.length !== 0 &&
+ selectedDamageItemList.map((selectedDamageItem, index) => (
+
+
+
+ ))}
+
+
+
+
+
+
+
+
+ );
+};
+export default StepTwoContent;
diff --git a/src/components/dashboard/roadSafety/operator/Form/StepTwo/index.jsx b/src/components/dashboard/roadSafety/operator/Form/StepTwo/index.jsx
new file mode 100644
index 0000000..2308d02
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/Form/StepTwo/index.jsx
@@ -0,0 +1,33 @@
+import UploadFileIcon from "@mui/icons-material/UploadFile";
+import { Dialog, DialogTitle, IconButton, Tooltip } from "@mui/material";
+import { useState } from "react";
+import StepTwoContent from "./StepTwoContent";
+
+const StepTwo = ({ mutate, rowId }) => {
+ const [openStepTwoDialog, setOpenStepTwoDialog] = useState(false);
+ return (
+ <>
+
+ setOpenStepTwoDialog(true)}>
+
+
+
+
+ >
+ );
+};
+export default StepTwo;
diff --git a/src/components/dashboard/roadSafety/operator/OperatorList.jsx b/src/components/dashboard/roadSafety/operator/OperatorList.jsx
new file mode 100644
index 0000000..5efb488
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/OperatorList.jsx
@@ -0,0 +1,426 @@
+"use client";
+import CustomSelectByDependency from "@/core/components/DataTable/filter/fieldsType/CustomSelectByDependency";
+import DataTableWithAuth from "@/core/components/DataTableWithAuth";
+import { Box, Stack } from "@mui/material";
+import moment from "jalali-moment";
+import { useEffect, useMemo, useState } from "react";
+import RowActions from "./RowActions";
+import Toolbar from "./Toolbar";
+import { usePermissions } from "@/lib/hooks/usePermissions";
+import { useAuth } from "@/lib/contexts/auth";
+import useProvinces from "@/lib/hooks/useProvince";
+import useEdaratLists from "@/lib/hooks/useEdaratLists";
+import { GET_SAFETY_AND_PRIVACY } from "@/core/utils/routes";
+import RecognizePictureDialog from "./RowActions/RecognizePictureDialog";
+import ActionPictureDialog from "./RowActions/ActionPictureDialog";
+import JudiciaryDocumentDialog from "./RowActions/JudiciaryDocumentDialog";
+import LocationForm from "./RowActions/LocationForm";
+
+const OperatorList = () => {
+ const { data: userPermissions } = usePermissions();
+ const hasCountryPermission = userPermissions?.includes("show-fast-react");
+ const { user } = useAuth();
+ const statusOptions = [
+ { value: "", label: "همه وضعیت ها" },
+ { value: 1, label: "گام اول (شناسایی)" },
+ { value: 2, label: "گام دوم (مستندات قضایی)" },
+ { value: 3, label: "گام سوم (برخورد)" },
+ ];
+ const axisOptions = [
+ { value: "", label: "همه محور ها" },
+ { value: 1, label: "آزادراه" },
+ { value: 2, label: "بزرگراه" },
+ { value: 3, label: "اصلی" },
+ { value: 4, label: "فرعی" },
+ { value: 5, label: "روستایی" },
+ ];
+
+ const columns = useMemo(() => {
+ const dynamicColumns = {
+ header: "استان",
+ id: "province_id",
+ enableColumnFilter: true,
+ datatype: "numeric",
+ filterMode: "equals",
+ grow: false,
+ size: 130,
+ ColumnSelectComponent: (props) => {
+ const { provinces, errorProvinces, loadingProvinces } = useProvinces();
+ const getColumnSelectOptions = useMemo(() => {
+ if (loadingProvinces) {
+ return [{ value: "loading", label: "در حال بارگذاری..." }];
+ }
+ if (errorProvinces) {
+ return [{ value: "error", label: "خطا در بارگذاری" }];
+ }
+ return [
+ { value: "", label: "کل کشور" },
+ ...provinces.map((province) => ({
+ value: province.id,
+ label: province.name_fa,
+ })),
+ ];
+ }, [provinces, errorProvinces, loadingProvinces]);
+ return (
+
+ );
+ },
+ Cell: ({ row }) => <>{row.original.province_fa}>,
+ };
+ return [
+ {
+ accessorKey: "id",
+ header: "کد یکتا",
+ id: "id",
+ enableColumnFilter: true,
+ datatype: "text",
+ filterMode: "equals",
+ sortDescFirst: false,
+ columnFilterModeOptions: ["equals", "contains"],
+ grow: false,
+ size: 100,
+ },
+ ...(hasCountryPermission ? [dynamicColumns] : []),
+ {
+ header: "اداره",
+ id: "edare_shahri_id",
+ enableColumnFilter: true,
+ datatype: "numeric",
+ filterMode: "equals",
+ dependencyId: hasCountryPermission ? "province_id" : null,
+ grow: false,
+ size: 120,
+ ColumnSelectComponent: (props) => {
+ const { edaratList, loadingEdaratList, errorEdaratList } = useEdaratLists(
+ hasCountryPermission ? props.dependencyFieldValue.value : user.province_id
+ );
+ const [prevDependency, setPrevDependency] = useState(
+ hasCountryPermission ? props.dependencyFieldValue.value : user.province_id
+ );
+
+ const getColumnSelectOptions = useMemo(() => {
+ if (hasCountryPermission && props.dependencyFieldValue.value === "") {
+ return [{ value: "empty", label: "ابتدا استان را انتخاب کنید" }];
+ }
+ if (loadingEdaratList) {
+ return [{ value: "loading", label: "در حال بارگذاری..." }];
+ }
+ if (errorEdaratList) {
+ return [{ value: "error", label: "خطا در بارگذاری" }];
+ }
+ return [
+ { value: "", label: "کل ادارات" },
+ ...edaratList.map((edare) => ({
+ value: edare.id,
+ label: edare.name_fa,
+ })),
+ ];
+ }, [edaratList, loadingEdaratList, errorEdaratList]);
+ useEffect(() => {
+ if (hasCountryPermission) return;
+ if (prevDependency === props.dependencyFieldValue?.value) return;
+ props.handleChange({ ...props.filterParameters, value: "" });
+ setPrevDependency(props.dependencyFieldValue?.value);
+ }, [props.dependencyFieldValue?.value, hasCountryPermission]);
+ return (
+
+ );
+ },
+ Cell: ({ row }) => <>{row.original.edare_shahri_name}>,
+ },
+ {
+ header: "اطلاعات فعالیت",
+ id: "info",
+ enableColumnFilter: false,
+ enableSorting: false,
+ datatype: "text",
+ grow: false,
+ size: 50,
+ columns: [
+ {
+ accessorKey: "info_id",
+ header: "موضوع مشاهده شده",
+ id: "info_id",
+ enableColumnFilter: true,
+ datatype: "text",
+ filterMode: "equals",
+ sortDescFirst: false,
+ columnFilterModeOptions: ["equals", "contains"],
+ grow: false,
+ size: 100,
+ Cell: ({ row }) => <>{row.original.info_fa}>,
+ },
+ {
+ accessorKey: "axis_type_id",
+ header: "نوع محور",
+ id: "axis_type_id",
+ enableColumnFilter: true,
+ datatype: "numeric",
+ filterMode: "equals",
+ sortDescFirst: true,
+ grow: false,
+ size: 100,
+ columnSelectOption: () => {
+ return axisOptions.map((status) => ({
+ value: status.value,
+ label: status.label,
+ }));
+ },
+ Cell: ({ row }) =>
+ row.original?.axis_type_name ? <>{row.original.axis_type_name}> : <>بدون محور>,
+ },
+ {
+ accessorKey: "location",
+ header: "موقعیت",
+ id: "location",
+ enableColumnFilter: false,
+ enableSorting: false,
+ datatype: "array",
+ grow: false,
+ size: 100,
+ muiTableBodyCellProps: {
+ sx: {
+ borderLeft: "1px solid #e1e1e1",
+ py: 0,
+ "&:first-of-type": {
+ borderLeft: "unset",
+ },
+ },
+ },
+ Cell: ({ row }) => {
+ return (
+
+
+
+ );
+ },
+ },
+ ],
+ },
+ {
+ header: "گام اول",
+ id: "stepOne",
+ enableColumnFilter: false,
+ enableSorting: false,
+ datatype: "text",
+ grow: false,
+ size: 50,
+ columns: [
+ {
+ accessorKey: "recognize_picture",
+ header: "تصویر بازدید",
+ id: "recognize_picture",
+ enableColumnFilter: false,
+ enableSorting: false,
+ datatype: "text",
+ grow: false,
+ size: 100,
+ muiTableBodyCellProps: {
+ sx: {
+ borderLeft: "1px solid #e1e1e1",
+ py: 0,
+ "&:first-of-type": {
+ borderLeft: "unset",
+ },
+ },
+ },
+ Cell: ({ renderedCellValue }) => {
+ return renderedCellValue ? (
+
+
+
+ ) : (
+ <>بدون تصویر>
+ );
+ },
+ },
+ {
+ accessorFn: (row) =>
+ row.activity_date_time ? (
+ moment(row.activity_date_time).locale("fa").format("HH:mm | yyyy/MM/DD")
+ ) : (
+ <>بدون تاریخ>
+ ),
+ header: "تاریخ بازدید",
+ id: "activity_date_time",
+ enableColumnFilter: true,
+ datatype: "date",
+ filterMode: "between",
+ grow: false,
+ size: 100,
+ },
+ ],
+ },
+ {
+ header: "گام دوم",
+ id: "stepTwo",
+ enableColumnFilter: false,
+ enableSorting: false,
+ datatype: "text",
+ grow: false,
+ size: 50,
+ columns: [
+ {
+ header: "مستندات قضایی",
+ id: "judiciary_document",
+ enableColumnFilter: false,
+ enableSorting: false,
+ datatype: "text",
+ grow: false,
+ size: 100,
+ muiTableBodyCellProps: {
+ sx: {
+ borderLeft: "1px solid #e1e1e1",
+ py: 0,
+ "&:first-of-type": {
+ borderLeft: "unset",
+ },
+ },
+ },
+ Cell: ({ row }) => {
+ return (
+
+
+
+ );
+ },
+ },
+ {
+ accessorFn: (row) => {
+ const date = row.judiciary_document_upload_date;
+ if (!date || date === "0000-00-00 00:00:00") {
+ return <>بدون تاریخ>;
+ }
+ return moment(date, "YYYY-MM-DD HH:mm:ss").locale("fa").format("HH:mm | yyyy/MM/DD");
+ },
+
+ header: "تاریخ مستندات قضایی",
+ id: "judiciary_document_upload_date",
+ enableColumnFilter: true,
+ datatype: "date",
+ filterMode: "between",
+ grow: false,
+ size: 100,
+ },
+ ],
+ },
+ {
+ header: "گام سوم",
+ id: "stepThree",
+ enableColumnFilter: false,
+ enableSorting: false,
+ datatype: "text",
+ grow: false,
+ size: 50,
+ columns: [
+ {
+ accessorKey: "action_picture",
+ header: "تصویر اقدام",
+ id: "action_picture",
+ enableColumnFilter: false,
+ enableSorting: false,
+ datatype: "text",
+ grow: false,
+ size: 100,
+ muiTableBodyCellProps: {
+ sx: {
+ borderLeft: "1px solid #e1e1e1",
+ py: 0,
+ "&:first-of-type": {
+ borderLeft: "unset",
+ },
+ },
+ },
+ Cell: ({ renderedCellValue }) => {
+ return renderedCellValue ? (
+
+
+
+ ) : (
+ <>بدون تصویر>
+ );
+ },
+ },
+ {
+ accessorFn: (row) =>
+ row.action_picture_document_upload_date ? (
+ moment(row.action_picture_document_upload_date)
+ .locale("fa")
+ .format("HH:mm | yyyy/MM/DD")
+ ) : (
+ <>بدون تاریخ>
+ ),
+ header: "تاریخ اقدام",
+ id: "action_picture_document_upload_date",
+ enableColumnFilter: true,
+ datatype: "date",
+ filterMode: "between",
+ grow: false,
+ size: 100,
+ },
+ ],
+ },
+ {
+ accessorFn: (row) => moment(row.created_at).locale("fa").format("HH:mm | yyyy/MM/DD"),
+ header: "تاریخ ثبت",
+ id: "created_at",
+ enableColumnFilter: true,
+ datatype: "date",
+ filterMode: "between",
+ grow: false,
+ size: 100,
+ },
+ {
+ header: "وضعیت",
+ id: "step",
+ enableColumnFilter: true,
+ datatype: "numeric",
+ filterMode: "equals",
+ sortDescFirst: true,
+ grow: false,
+ size: 100,
+ columnSelectOption: () => {
+ return statusOptions.map((status) => ({
+ value: status.value,
+ label: status.label,
+ }));
+ },
+ Cell: ({ row }) => <>{row.original.step_fa}>,
+ },
+ ];
+ }, []);
+
+ return (
+ <>
+
+
+
+ >
+ );
+};
+export default OperatorList;
diff --git a/src/components/dashboard/roadSafety/operator/RowActions/ActionPictureDialog/ActionPictureContent.jsx b/src/components/dashboard/roadSafety/operator/RowActions/ActionPictureDialog/ActionPictureContent.jsx
new file mode 100644
index 0000000..f27255b
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/RowActions/ActionPictureDialog/ActionPictureContent.jsx
@@ -0,0 +1,44 @@
+import { Box, Stack, Typography, useTheme } from "@mui/material";
+import Image from "next/image";
+
+const ActionPictureContent = ({ image, title }) => {
+ const theme = useTheme();
+ return (
+
+
+ {title}
+
+
+
+
+
+ );
+};
+export default ActionPictureContent;
diff --git a/src/components/dashboard/roadSafety/operator/RowActions/ActionPictureDialog/index.jsx b/src/components/dashboard/roadSafety/operator/RowActions/ActionPictureDialog/index.jsx
new file mode 100644
index 0000000..4c2911c
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/RowActions/ActionPictureDialog/index.jsx
@@ -0,0 +1,40 @@
+import PhotoLibraryIcon from "@mui/icons-material/PhotoLibrary";
+import { Button, Dialog, DialogActions, DialogContent, IconButton, Tooltip } from "@mui/material";
+import { useState } from "react";
+import ActionPictureContent from "./ActionPictureContent";
+
+const ActionPictureDialog = ({ image }) => {
+ const [openImageDialog, setOpenImageDialog] = useState(false);
+
+ return (
+ <>
+
+ setOpenImageDialog(true)}>
+
+
+
+
+ >
+ );
+};
+export default ActionPictureDialog;
diff --git a/src/components/dashboard/roadSafety/operator/RowActions/DeleteDialog/DeleteContent.jsx b/src/components/dashboard/roadSafety/operator/RowActions/DeleteDialog/DeleteContent.jsx
new file mode 100644
index 0000000..7a83c08
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/RowActions/DeleteDialog/DeleteContent.jsx
@@ -0,0 +1,40 @@
+import { Button, DialogActions, DialogContent, Stack, Typography } from "@mui/material";
+import React, { useState } from "react";
+import useRequest from "@/lib/hooks/useRequest";
+import { DELETE_SAFETY_AND_PRIVACY } from "@/core/utils/routes";
+
+const DeleteContent = ({ rowId, mutate, setOpenDeleteDialog }) => {
+ const [submitting, setSubmitting] = useState(false);
+ const requestServer = useRequest({ notificationSuccess: true });
+ const handleClick = () => {
+ setSubmitting(true);
+ requestServer(`${DELETE_SAFETY_AND_PRIVACY}/${rowId}`, "delete")
+ .then(() => {
+ mutate();
+ setOpenDeleteDialog(false);
+ setSubmitting(false);
+ })
+ .catch(() => {
+ setSubmitting(false);
+ });
+ };
+ return (
+ <>
+
+
+ آیا از حذف فعالیت اطمینان دارید؟
+
+
+
+
+
+
+ >
+ );
+};
+
+export default DeleteContent;
diff --git a/src/components/dashboard/roadSafety/operator/RowActions/DeleteDialog/index.jsx b/src/components/dashboard/roadSafety/operator/RowActions/DeleteDialog/index.jsx
new file mode 100644
index 0000000..596cf9a
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/RowActions/DeleteDialog/index.jsx
@@ -0,0 +1,32 @@
+import DeleteIcon from "@mui/icons-material/Delete";
+import { Dialog, DialogTitle, IconButton, Tooltip } from "@mui/material";
+import { useState } from "react";
+import DeleteContent from "./DeleteContent";
+const DeleteForm = ({ rowId, mutate }) => {
+ const [openDeleteDialog, setOpenDeleteDialog] = useState(false);
+
+ return (
+ <>
+
+ setOpenDeleteDialog(true)}>
+
+
+
+
+ >
+ );
+};
+export default DeleteForm;
diff --git a/src/components/dashboard/roadSafety/operator/RowActions/JudiciaryDocumentDialog/JudiciaryDocumentContent.jsx b/src/components/dashboard/roadSafety/operator/RowActions/JudiciaryDocumentDialog/JudiciaryDocumentContent.jsx
new file mode 100644
index 0000000..95a3f1e
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/RowActions/JudiciaryDocumentDialog/JudiciaryDocumentContent.jsx
@@ -0,0 +1,43 @@
+import { Box, Button, Chip, Divider, Grid, Typography } from "@mui/material";
+import DownloadIcon from "@mui/icons-material/Download";
+import ArticleIcon from "@mui/icons-material/Article";
+
+const JudiciaryDocumentContent = ({ judiciaryDocumentDetails }) => {
+ return (
+
+ {judiciaryDocumentDetails.map((judiciaryDocument, index) => {
+ return (
+
+
+ }
+ label={
+
+ مستندات قضایی {index + 1}
+
+ }
+ />
+
+
+ }
+ onClick={() => {
+ if (judiciaryDocument) {
+ window.open(judiciaryDocument, "_blank");
+ } else {
+ alert("فایلی برای دانلود موجود نیست.");
+ }
+ }}
+ >
+ دانلود فایل
+
+
+ );
+ })}
+
+ );
+};
+export default JudiciaryDocumentContent;
diff --git a/src/components/dashboard/roadSafety/operator/RowActions/JudiciaryDocumentDialog/JudiciaryDocumentController.jsx b/src/components/dashboard/roadSafety/operator/RowActions/JudiciaryDocumentDialog/JudiciaryDocumentController.jsx
new file mode 100644
index 0000000..0773130
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/RowActions/JudiciaryDocumentDialog/JudiciaryDocumentController.jsx
@@ -0,0 +1,35 @@
+import { useEffect, useState } from "react";
+import useRequest from "@/lib/hooks/useRequest";
+import DialogLoading from "@/core/components/DialogLoading";
+import JudiciaryDocumentContent from "./JudiciaryDocumentContent";
+import { DESERIALIZE_JUDICIARY_DOCUMENT } from "@/core/utils/routes";
+import { Typography } from "@mui/material";
+
+const JudiciaryDocumentController = ({ rowId }) => {
+ const requestServer = useRequest();
+ const [judiciaryDocumentDetails, setJudiciaryDocumentDetails] = useState([]);
+ const [judiciaryDocumentDetailsLoading, setJudiciaryDocumentDetailsLoading] = useState(false);
+ useEffect(() => {
+ setJudiciaryDocumentDetailsLoading(true);
+ requestServer(`${DESERIALIZE_JUDICIARY_DOCUMENT}/${rowId}`, "get")
+ .then((response) => {
+ setJudiciaryDocumentDetails(response.data.data);
+ setJudiciaryDocumentDetailsLoading(false);
+ })
+ .catch((e) => {
+ setJudiciaryDocumentDetailsLoading(false);
+ });
+ }, [rowId]);
+ return (
+ <>
+ {judiciaryDocumentDetailsLoading ? (
+
+ ) : judiciaryDocumentDetails.length > 0 ? (
+
+ ) : (
+ بدون مستندات
+ )}
+ >
+ );
+};
+export default JudiciaryDocumentController;
diff --git a/src/components/dashboard/roadSafety/operator/RowActions/JudiciaryDocumentDialog/index.jsx b/src/components/dashboard/roadSafety/operator/RowActions/JudiciaryDocumentDialog/index.jsx
new file mode 100644
index 0000000..0ff10cc
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/RowActions/JudiciaryDocumentDialog/index.jsx
@@ -0,0 +1,40 @@
+import { Button, Dialog, DialogActions, DialogContent, DialogTitle, IconButton, Tooltip } from "@mui/material";
+import ArticleIcon from "@mui/icons-material/Article";
+import React, { useState } from "react";
+import JudiciaryDocumentController from "./JudiciaryDocumentController";
+
+const JudiciaryDocumentDialog = ({ rowId }) => {
+ const [openJudiciaryDocumentDialog, setOpenJudiciaryDocumentDialog] = useState(false);
+ return (
+ <>
+
+ setOpenJudiciaryDocumentDialog(true)}>
+
+
+
+
+ >
+ );
+};
+export default JudiciaryDocumentDialog;
diff --git a/src/components/dashboard/roadSafety/operator/RowActions/LocationForm/LocationFormContent.jsx b/src/components/dashboard/roadSafety/operator/RowActions/LocationForm/LocationFormContent.jsx
new file mode 100644
index 0000000..14b3db3
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/RowActions/LocationForm/LocationFormContent.jsx
@@ -0,0 +1,35 @@
+"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, end_lat, end_lng }) => {
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+export default LocationFormContent;
diff --git a/src/components/dashboard/roadSafety/operator/RowActions/LocationForm/index.jsx b/src/components/dashboard/roadSafety/operator/RowActions/LocationForm/index.jsx
new file mode 100644
index 0000000..d614215
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/RowActions/LocationForm/index.jsx
@@ -0,0 +1,40 @@
+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, end_lat, end_lng }) => {
+ const [openLocationDialog, setOpenLocationDialog] = useState(false);
+
+ return (
+ <>
+
+ setOpenLocationDialog(true)}>
+
+
+
+
+ >
+ );
+};
+export default LocationForm;
diff --git a/src/components/dashboard/roadSafety/operator/RowActions/RecognizePictureDialog/RecognizePictureContent.jsx b/src/components/dashboard/roadSafety/operator/RowActions/RecognizePictureDialog/RecognizePictureContent.jsx
new file mode 100644
index 0000000..39dbdcf
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/RowActions/RecognizePictureDialog/RecognizePictureContent.jsx
@@ -0,0 +1,44 @@
+import { Box, Stack, Typography, useTheme } from "@mui/material";
+import Image from "next/image";
+
+const RecognizePictureContent = ({ image, title }) => {
+ const theme = useTheme();
+ return (
+
+
+ {title}
+
+
+
+
+
+ );
+};
+export default RecognizePictureContent;
diff --git a/src/components/dashboard/roadSafety/operator/RowActions/RecognizePictureDialog/index.jsx b/src/components/dashboard/roadSafety/operator/RowActions/RecognizePictureDialog/index.jsx
new file mode 100644
index 0000000..72ef4ea
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/RowActions/RecognizePictureDialog/index.jsx
@@ -0,0 +1,40 @@
+import PhotoLibraryIcon from "@mui/icons-material/PhotoLibrary";
+import { Button, Dialog, DialogActions, DialogContent, IconButton, Tooltip } from "@mui/material";
+import { useState } from "react";
+import RecognizePictureContent from "./RecognizePictureContent";
+
+const RecognizePictureDialog = ({ image }) => {
+ const [openImageDialog, setOpenImageDialog] = useState(false);
+
+ return (
+ <>
+
+ setOpenImageDialog(true)}>
+
+
+
+
+ >
+ );
+};
+export default RecognizePictureDialog;
diff --git a/src/components/dashboard/roadSafety/operator/RowActions/index.jsx b/src/components/dashboard/roadSafety/operator/RowActions/index.jsx
new file mode 100644
index 0000000..1a9fb7c
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/RowActions/index.jsx
@@ -0,0 +1,15 @@
+import { Box } from "@mui/material";
+import DeleteForm from "./DeleteDialog";
+import StepTwo from "../Form/StepTwo";
+import StepThree from "../Form/StepThree";
+
+const RowActions = ({ row, mutate }) => {
+ return (
+
+ {row.original?.step === 1 && }
+ {row.original?.step === 2 && }
+
+
+ );
+};
+export default RowActions;
diff --git a/src/components/dashboard/roadSafety/operator/Toolbar.jsx b/src/components/dashboard/roadSafety/operator/Toolbar.jsx
new file mode 100644
index 0000000..2dd0b65
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/Toolbar.jsx
@@ -0,0 +1,16 @@
+import { Stack } from "@mui/material";
+import StepOne from "./Form/StepOne";
+import PrintExcel from "./ExcelPrint";
+import { usePermissions } from "@/lib/hooks/usePermissions";
+
+const Toolbar = ({ table, filterData, mutate }) => {
+ const { data: userPermissions } = usePermissions();
+ const hasCreatePermission = userPermissions?.includes("add-safety-and-privacy");
+ return (
+
+
+ {hasCreatePermission && }
+
+ );
+};
+export default Toolbar;
diff --git a/src/components/dashboard/roadSafety/operator/index.jsx b/src/components/dashboard/roadSafety/operator/index.jsx
new file mode 100644
index 0000000..a2b328c
--- /dev/null
+++ b/src/components/dashboard/roadSafety/operator/index.jsx
@@ -0,0 +1,14 @@
+"use client";
+import PageTitle from "@/core/components/PageTitle";
+import { Stack } from "@mui/material";
+import OperatorList from "./OperatorList";
+
+const OperatorPage = () => {
+ return (
+
+
+
+
+ );
+};
+export default OperatorPage;
diff --git a/src/core/utils/pageMenu.js b/src/core/utils/pageMenu.js
index 2b00efb..98d8bd6 100644
--- a/src/core/utils/pageMenu.js
+++ b/src/core/utils/pageMenu.js
@@ -312,7 +312,7 @@ export const pageMenu = [
id: "safetyAndPrivacyManagmentOparationCartable",
label: "کارتابل",
type: "page",
- route: process.env.NEXT_PUBLIC_API_URL + "/v2/safety_and_privacy/operator/cartable",
+ route: "/dashboard/road-safety/operator",
permissions: [
"show-safety-and-privacy-operator-cartable",
"show-safety-and-privacy-operator-cartable-province",
diff --git a/src/core/utils/routes.js b/src/core/utils/routes.js
index 13da8ae..b224b3a 100644
--- a/src/core/utils/routes.js
+++ b/src/core/utils/routes.js
@@ -129,5 +129,13 @@ export const EXPORT_FAST_REACT_OPERATOR_LIST = api + "/api/v3/road_observations/
export const EXPORT_FAST_REACT_COMPLAINT_LIST = api + "/api/v3/road_observations/complaints_report";
// road safety
+export const GET_SAFETY_AND_PRIVACY = api + "/api/v3/safety_and_privacy";
+export const DELETE_SAFETY_AND_PRIVACY = api + "/api/v3/safety_and_privacy";
+export const DESERIALIZE_JUDICIARY_DOCUMENT = api + "/api/v3/safety_and_privacy/deserialize";
+export const GET_SAFETY_AND_PRIVACY_ITEM = api + "/api/v3/safety_and_privacy/sub_items";
+export const FIRST_STEP_STORE = api + "/api/v3/safety_and_privacy/first_step_store";
+export const SECOND_STEP_STORE = api + "/api/v3/safety_and_privacy/second_step_store";
+export const THIRD_STEP_STORE = api + "/api/v3/safety_and_privacy/third_step_store";
+export const EXPORT_OPERATOR_ROAD_SAFETY = api + "/api/v3/safety_and_privacy/excel_report";
export const GET_ROAD_SAFETY_PROVINCE_ACTIVITY_REPORT = api + "/api/v3/safety_and_privacy_report/country_activity";
export const GET_ROAD_SAFETY_CITY_ACTIVITY_REPORT = api + "/api/v3/safety_and_privacy_report/province_activity";
diff --git a/src/lib/hooks/useSafetyAndPrivacyGetItems.js b/src/lib/hooks/useSafetyAndPrivacyGetItems.js
new file mode 100644
index 0000000..d97dbbf
--- /dev/null
+++ b/src/lib/hooks/useSafetyAndPrivacyGetItems.js
@@ -0,0 +1,30 @@
+import { useEffect, useState } from "react";
+import useRequest from "@/lib/hooks/useRequest";
+import { GET_SAFETY_AND_PRIVACY_ITEM } from "@/core/utils/routes";
+
+const useSafetyAndPrivacyGetItems = () => {
+ const requestServer = useRequest();
+ const [itemsList, setItemsList] = useState([]);
+ const [loadingItemsList, setLoadingItemsList] = useState(true);
+ const [errorItemsList, setErrorItemsList] = useState(null);
+
+ useEffect(() => {
+ const fetchItems = async () => {
+ try {
+ const response = await requestServer(`${GET_SAFETY_AND_PRIVACY_ITEM}`);
+ setItemsList(response.data.data);
+ setLoadingItemsList(false);
+ setErrorItemsList(false);
+ } catch (e) {
+ setErrorItemsList(e);
+ setLoadingItemsList(false);
+ }
+ };
+
+ fetchItems();
+ }, []);
+
+ return { itemsList, loadingItemsList, errorItemsList };
+};
+
+export default useSafetyAndPrivacyGetItems;