diff --git a/src/app/(withAuth)/dashboard/fast-react/supervisor/loading.jsx b/src/app/(withAuth)/dashboard/fast-react/supervisor/loading.jsx
new file mode 100644
index 0000000..4535a8d
--- /dev/null
+++ b/src/app/(withAuth)/dashboard/fast-react/supervisor/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/fast-react/supervisor/page.js b/src/app/(withAuth)/dashboard/fast-react/supervisor/page.js
new file mode 100644
index 0000000..820c1af
--- /dev/null
+++ b/src/app/(withAuth)/dashboard/fast-react/supervisor/page.js
@@ -0,0 +1,13 @@
+import WithPermission from "@/core/middlewares/withPermission";
+import SupervisorPage from "@/components/dashboard/fastReact/supervisor";
+import ActivityCodeLog from "@/core/components/ActivityCodeLog";
+const Page = () => {
+ return (
+
+
+
+
+ );
+};
+
+export default Page;
diff --git a/src/components/dashboard/fastReact/complaintList/ComplaintListTable.jsx b/src/components/dashboard/fastReact/complaintList/ComplaintListTable.jsx
new file mode 100644
index 0000000..158d879
--- /dev/null
+++ b/src/components/dashboard/fastReact/complaintList/ComplaintListTable.jsx
@@ -0,0 +1,271 @@
+import { useEffect, useMemo, useState } from "react";
+import { Box, Button, Dialog, DialogActions, Stack, Typography } from "@mui/material";
+import DataTableWithAuth from "@/core/components/DataTableWithAuth";
+import Toolbar from "./Toolbar";
+import RowActions from "./RowActions";
+import { GET_FAST_REACT_COMPLAINTS } from "@/core/utils/routes";
+import useProvinces from "@/lib/hooks/useProvince";
+import CustomSelectByDependency from "@/core/components/DataTable/filter/fieldsType/CustomSelectByDependency";
+import { usePermissions } from "@/lib/hooks/usePermissions";
+import { useAuth } from "@/lib/contexts/auth";
+import useEdaratLists from "@/lib/hooks/useEdaratLists";
+import DescriptionForm from "./RowActions/DescriptionDialog";
+import LocationForm from "./RowActions/LocationDialog";
+import moment from "jalali-moment";
+
+const ComplaintListTable = ({ open, setOpen, mutate }) => {
+ const { data: userPermissions } = usePermissions();
+ const hasCountryPermission = userPermissions?.includes("show-fast-react");
+ const { user } = useAuth();
+ const columns = useMemo(() => {
+ const dynamicColumns = {
+ header: "استان",
+ id: "road_observeds__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,
+ },
+ {
+ accessorKey: "fk_RegisteredEventMessage",
+ header: "کد سوانح",
+ id: "fk_RegisteredEventMessage",
+ enableColumnFilter: true,
+ datatype: "text",
+ filterMode: "equals",
+ sortDescFirst: false,
+ columnFilterModeOptions: ["equals", "contains"],
+ grow: false,
+ size: 100,
+ },
+ ...(hasCountryPermission ? [dynamicColumns] : []),
+ {
+ header: "اداره",
+ id: "edarat_id",
+ enableColumnFilter: true,
+ datatype: "numeric",
+ filterMode: "equals",
+ dependencyId: hasCountryPermission ? "road_observeds__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.city_fa}>,
+ },
+ {
+ accessorKey: "Title",
+ header: "موضوع گزارش",
+ id: "Title",
+ enableColumnFilter: true,
+ datatype: "text",
+ filterMode: "equals",
+ sortDescFirst: false,
+ columnFilterModeOptions: ["equals", "contains"],
+ grow: false,
+ size: 100,
+ },
+ {
+ accessorKey: "FeatureTypeTitle",
+ header: "نوع گزارش",
+ id: "FeatureTypeTitle",
+ enableColumnFilter: true,
+ datatype: "text",
+ filterMode: "equals",
+ sortDescFirst: false,
+ columnFilterModeOptions: ["equals", "contains"],
+ grow: false,
+ size: 100,
+ },
+ {
+ accessorKey: "Description",
+ header: "توضیح گزارش",
+ id: "Description",
+ enableColumnFilter: false,
+ datatype: "text",
+ filterMode: "equals",
+ sortDescFirst: 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 بدون توضیحات;
+ },
+ },
+ {
+ 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 (
+
+
+
+ );
+ },
+ },
+ {
+ accessorKey: "MobileForSendEventSms",
+ header: "شماره تماس گیرنده",
+ id: "MobileForSendEventSms",
+ enableColumnFilter: true,
+ datatype: "text",
+ filterMode: "equals",
+ sortDescFirst: false,
+ columnFilterModeOptions: ["equals", "contains"],
+ 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,
+ },
+ ];
+ }, []);
+
+ return (
+
+ );
+};
+export default ComplaintListTable;
diff --git a/src/components/dashboard/fastReact/complaintList/RowActions/DescriptionDialog/index.jsx b/src/components/dashboard/fastReact/complaintList/RowActions/DescriptionDialog/index.jsx
new file mode 100644
index 0000000..4d80ac4
--- /dev/null
+++ b/src/components/dashboard/fastReact/complaintList/RowActions/DescriptionDialog/index.jsx
@@ -0,0 +1,50 @@
+import { Dialog, DialogContent, DialogTitle, IconButton, Tooltip, Typography, Card, CardContent } from "@mui/material";
+import { useState } from "react";
+import RemoveRedEyeIcon from "@mui/icons-material/RemoveRedEye";
+import CloseIcon from "@mui/icons-material/Close";
+
+const DescriptionForm = ({ description, title, icon: IconComponent = RemoveRedEyeIcon }) => {
+ const [openOfficerDescriptionDialog, setOpenOfficerDescriptionDialog] = useState(false);
+
+ return (
+ <>
+
+ setOpenOfficerDescriptionDialog(true)}>
+
+
+
+
+ >
+ );
+};
+export default DescriptionForm;
diff --git a/src/components/dashboard/fastReact/complaintList/RowActions/LocationDialog/LocationFormContent.jsx b/src/components/dashboard/fastReact/complaintList/RowActions/LocationDialog/LocationFormContent.jsx
new file mode 100644
index 0000000..94f091d
--- /dev/null
+++ b/src/components/dashboard/fastReact/complaintList/RowActions/LocationDialog/LocationFormContent.jsx
@@ -0,0 +1,30 @@
+"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/fastReact/complaintList/RowActions/LocationDialog/index.jsx b/src/components/dashboard/fastReact/complaintList/RowActions/LocationDialog/index.jsx
new file mode 100644
index 0000000..09df6ad
--- /dev/null
+++ b/src/components/dashboard/fastReact/complaintList/RowActions/LocationDialog/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)}>
+
+
+
+
+ >
+ );
+};
+export default LocationForm;
diff --git a/src/components/dashboard/fastReact/complaintList/RowActions/index.jsx b/src/components/dashboard/fastReact/complaintList/RowActions/index.jsx
new file mode 100644
index 0000000..9fb298d
--- /dev/null
+++ b/src/components/dashboard/fastReact/complaintList/RowActions/index.jsx
@@ -0,0 +1,6 @@
+import { Box } from "@mui/material";
+
+const RowActions = ({ row, mutate }) => {
+ return ;
+};
+export default RowActions;
diff --git a/src/components/dashboard/fastReact/complaintList/Toolbar.jsx b/src/components/dashboard/fastReact/complaintList/Toolbar.jsx
new file mode 100644
index 0000000..1f291d1
--- /dev/null
+++ b/src/components/dashboard/fastReact/complaintList/Toolbar.jsx
@@ -0,0 +1,6 @@
+import { Stack } from "@mui/material";
+
+const Toolbar = ({ table, filterData, mutate }) => {
+ return ;
+};
+export default Toolbar;
diff --git a/src/components/dashboard/fastReact/complaintList/index.jsx b/src/components/dashboard/fastReact/complaintList/index.jsx
new file mode 100644
index 0000000..5c3edc6
--- /dev/null
+++ b/src/components/dashboard/fastReact/complaintList/index.jsx
@@ -0,0 +1,36 @@
+import { Button, IconButton, useMediaQuery } from "@mui/material";
+import ChecklistIcon from "@mui/icons-material/Checklist";
+import { useTheme } from "@emotion/react";
+import { useState } from "react";
+import ComplaintListTable from "./ComplaintListTable";
+
+const ComplaintList = ({ 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 ComplaintList;
diff --git a/src/components/dashboard/fastReact/supervisor/ExcelPrint/index.jsx b/src/components/dashboard/fastReact/supervisor/ExcelPrint/index.jsx
new file mode 100644
index 0000000..ae703fa
--- /dev/null
+++ b/src/components/dashboard/fastReact/supervisor/ExcelPrint/index.jsx
@@ -0,0 +1,75 @@
+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 { EXPORT_ROAD_ITEMS_SUPERVISOR_LIST } from "@/core/utils/routes";
+import { useTheme } from "@emotion/react";
+import DataTableFilterDataStructure from "@/core/utils/DataTableFilterDataStructure";
+import isArrayEmpty from "@/core/utils/isArrayEmpty";
+
+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_ROAD_ITEMS_SUPERVISOR_LIST}?${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/fastReact/supervisor/RowActions/ConfirmDialog/ConfirmContent.jsx b/src/components/dashboard/fastReact/supervisor/RowActions/ConfirmDialog/ConfirmContent.jsx
new file mode 100644
index 0000000..5944db3
--- /dev/null
+++ b/src/components/dashboard/fastReact/supervisor/RowActions/ConfirmDialog/ConfirmContent.jsx
@@ -0,0 +1,69 @@
+import { Button, DialogActions, DialogContent, Stack, TextField } from "@mui/material";
+import { useForm } from "react-hook-form";
+import useRequest from "@/lib/hooks/useRequest";
+import { VERIFY_BY_FAST_REACT_SUPERVISOR } from "@/core/utils/routes";
+
+const ConfirmContent = ({ rowId, mutate, setOpenConfirmDialog }) => {
+ const requestServer = useRequest({ notificationSuccess: true });
+
+ const {
+ register,
+ handleSubmit,
+ formState: { isSubmitting },
+ } = useForm({
+ defaultValues: {
+ description: "",
+ },
+ });
+
+ const onSubmit = async (data) => {
+ const formData = new FormData();
+ data.description !== "" && formData.append("description", data.description);
+ formData.append("verify", 1);
+ requestServer(`${VERIFY_BY_FAST_REACT_SUPERVISOR}/${rowId}`, "post", {
+ data: formData,
+ })
+ .then(() => {
+ mutate();
+ setOpenConfirmDialog(false);
+ })
+ .catch(() => {});
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+export default ConfirmContent;
diff --git a/src/components/dashboard/fastReact/supervisor/RowActions/ConfirmDialog/index.jsx b/src/components/dashboard/fastReact/supervisor/RowActions/ConfirmDialog/index.jsx
new file mode 100644
index 0000000..10e6048
--- /dev/null
+++ b/src/components/dashboard/fastReact/supervisor/RowActions/ConfirmDialog/index.jsx
@@ -0,0 +1,29 @@
+import { Dialog, DialogTitle, IconButton, Tooltip } from "@mui/material";
+import { useState } from "react";
+import ConfirmContent from "./ConfirmContent";
+import DoneIcon from "@mui/icons-material/Done";
+const ConfirmForm = ({ rowId, mutate }) => {
+ const [openConfirmDialog, setOpenConfirmDialog] = useState(false);
+ return (
+ <>
+
+ setOpenConfirmDialog(true)}>
+
+
+
+
+ >
+ );
+};
+export default ConfirmForm;
diff --git a/src/components/dashboard/fastReact/supervisor/RowActions/DescriptionDialog/index.jsx b/src/components/dashboard/fastReact/supervisor/RowActions/DescriptionDialog/index.jsx
new file mode 100644
index 0000000..4d80ac4
--- /dev/null
+++ b/src/components/dashboard/fastReact/supervisor/RowActions/DescriptionDialog/index.jsx
@@ -0,0 +1,50 @@
+import { Dialog, DialogContent, DialogTitle, IconButton, Tooltip, Typography, Card, CardContent } from "@mui/material";
+import { useState } from "react";
+import RemoveRedEyeIcon from "@mui/icons-material/RemoveRedEye";
+import CloseIcon from "@mui/icons-material/Close";
+
+const DescriptionForm = ({ description, title, icon: IconComponent = RemoveRedEyeIcon }) => {
+ const [openOfficerDescriptionDialog, setOpenOfficerDescriptionDialog] = useState(false);
+
+ return (
+ <>
+
+ setOpenOfficerDescriptionDialog(true)}>
+
+
+
+
+ >
+ );
+};
+export default DescriptionForm;
diff --git a/src/components/dashboard/fastReact/supervisor/RowActions/ImageDialog/ImageFormContent.jsx b/src/components/dashboard/fastReact/supervisor/RowActions/ImageDialog/ImageFormContent.jsx
new file mode 100644
index 0000000..9aaa92e
--- /dev/null
+++ b/src/components/dashboard/fastReact/supervisor/RowActions/ImageDialog/ImageFormContent.jsx
@@ -0,0 +1,44 @@
+import { Box, DialogContent, Paper, Stack, Typography, useTheme } from "@mui/material";
+import Image from "next/image";
+
+const ImageFormContent = ({ image, title }) => {
+ const theme = useTheme();
+ return (
+
+
+ {title}
+
+
+
+
+
+ );
+};
+export default ImageFormContent;
diff --git a/src/components/dashboard/fastReact/supervisor/RowActions/ImageDialog/index.jsx b/src/components/dashboard/fastReact/supervisor/RowActions/ImageDialog/index.jsx
new file mode 100644
index 0000000..de3b76a
--- /dev/null
+++ b/src/components/dashboard/fastReact/supervisor/RowActions/ImageDialog/index.jsx
@@ -0,0 +1,46 @@
+import PhotoLibraryIcon from "@mui/icons-material/PhotoLibrary";
+import { Button, Dialog, DialogActions, DialogContent, DialogTitle, IconButton, Tooltip } from "@mui/material";
+import { useState } from "react";
+import ImageFormContent from "./ImageFormContent";
+
+const ImageDialog = ({ image_before, image_after }) => {
+ const [openImageDialog, setOpenImageDialog] = useState(false);
+
+ return (
+ <>
+
+ setOpenImageDialog(true)}>
+
+
+
+
+ >
+ );
+};
+export default ImageDialog;
diff --git a/src/components/dashboard/fastReact/supervisor/RowActions/LocationDialog/LocationFormContent.jsx b/src/components/dashboard/fastReact/supervisor/RowActions/LocationDialog/LocationFormContent.jsx
new file mode 100644
index 0000000..94f091d
--- /dev/null
+++ b/src/components/dashboard/fastReact/supervisor/RowActions/LocationDialog/LocationFormContent.jsx
@@ -0,0 +1,30 @@
+"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/fastReact/supervisor/RowActions/LocationDialog/index.jsx b/src/components/dashboard/fastReact/supervisor/RowActions/LocationDialog/index.jsx
new file mode 100644
index 0000000..09df6ad
--- /dev/null
+++ b/src/components/dashboard/fastReact/supervisor/RowActions/LocationDialog/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)}>
+
+
+
+
+ >
+ );
+};
+export default LocationForm;
diff --git a/src/components/dashboard/fastReact/supervisor/RowActions/RejectDialog/RejectFormContent.jsx b/src/components/dashboard/fastReact/supervisor/RowActions/RejectDialog/RejectFormContent.jsx
new file mode 100644
index 0000000..5c51886
--- /dev/null
+++ b/src/components/dashboard/fastReact/supervisor/RowActions/RejectDialog/RejectFormContent.jsx
@@ -0,0 +1,83 @@
+import { Button, DialogActions, DialogContent, Stack, TextField } from "@mui/material";
+import { useForm } from "react-hook-form";
+import { yupResolver } from "@hookform/resolvers/yup";
+import * as Yup from "yup";
+import useRequest from "@/lib/hooks/useRequest";
+import { REJECT_BY_FAST_REACT_SUPERVISOR } from "@/core/utils/routes";
+
+const RejectContent = ({ rowId, mutate, setOpenRejectDialog }) => {
+ const requestServer = useRequest({ notificationSuccess: true });
+
+ const validationSchema = Yup.object().shape({
+ description: Yup.string().required("لطفاً توضیحات را وارد کنید."),
+ });
+
+ const {
+ register,
+ handleSubmit,
+ formState: { errors, isSubmitting },
+ reset,
+ } = useForm({
+ defaultValues: {
+ description: "",
+ },
+ resolver: yupResolver(validationSchema),
+ mode: "onBlur",
+ });
+
+ const onSubmit = async (data) => {
+ const formData = new FormData();
+ formData.append("description", data.description);
+ formData.append("verify", 2);
+ requestServer(`${REJECT_BY_FAST_REACT_SUPERVISOR}/${rowId}`, "post", {
+ data: formData,
+ })
+ .then(() => {
+ mutate();
+ setOpenRejectDialog(false);
+ })
+ .catch(() => {})
+ .finally(() => {
+ reset();
+ });
+ };
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+export default RejectContent;
diff --git a/src/components/dashboard/fastReact/supervisor/RowActions/RejectDialog/index.jsx b/src/components/dashboard/fastReact/supervisor/RowActions/RejectDialog/index.jsx
new file mode 100644
index 0000000..5d754a5
--- /dev/null
+++ b/src/components/dashboard/fastReact/supervisor/RowActions/RejectDialog/index.jsx
@@ -0,0 +1,29 @@
+import { Dialog, DialogTitle, IconButton, Tooltip } from "@mui/material";
+import { useState } from "react";
+import ClearIcon from "@mui/icons-material/Clear";
+import RejectContent from "./RejectFormContent";
+const RejectForm = ({ rowId, mutate }) => {
+ const [openRejectDialog, setOpenRejectDialog] = useState(false);
+ return (
+ <>
+
+ setOpenRejectDialog(true)}>
+
+
+
+
+ >
+ );
+};
+export default RejectForm;
diff --git a/src/components/dashboard/fastReact/supervisor/RowActions/index.jsx b/src/components/dashboard/fastReact/supervisor/RowActions/index.jsx
new file mode 100644
index 0000000..ad2e492
--- /dev/null
+++ b/src/components/dashboard/fastReact/supervisor/RowActions/index.jsx
@@ -0,0 +1,22 @@
+import {Box} from "@mui/material";
+import ConfirmForm from "./ConfirmDialog";
+import RejectForm from "./RejectDialog";
+import {usePermissions} from "@/lib/hooks/usePermissions";
+
+const RowActions = ({row, mutate}) => {
+ const {data: userPermissions} = usePermissions();
+ const hasSupervisePermission = userPermissions.some((item) =>
+ ["supervise-fast-react", "supervise-fast-react-province"].includes(item)
+ );
+ return (
+
+ {hasSupervisePermission && row.original?.status === 0 && (
+
+ )}
+ {hasSupervisePermission && row.original?.status === 0 &&(
+
+ )}
+
+ );
+};
+export default RowActions;
diff --git a/src/components/dashboard/fastReact/supervisor/SupervisorList.jsx b/src/components/dashboard/fastReact/supervisor/SupervisorList.jsx
new file mode 100644
index 0000000..cb13855
--- /dev/null
+++ b/src/components/dashboard/fastReact/supervisor/SupervisorList.jsx
@@ -0,0 +1,405 @@
+import { useEffect, useMemo, useState } from "react";
+import { Box, Stack, Typography } from "@mui/material";
+import DataTableWithAuth from "@/core/components/DataTableWithAuth";
+import Toolbar from "./Toolbar";
+import moment from "jalali-moment";
+import RowActions from "./RowActions";
+import { GET_FAST_REACT_SUPERVISOR } from "@/core/utils/routes";
+import useProvinces from "@/lib/hooks/useProvince";
+import CustomSelectByDependency from "@/core/components/DataTable/filter/fieldsType/CustomSelectByDependency";
+import { usePermissions } from "@/lib/hooks/usePermissions";
+import { useAuth } from "@/lib/contexts/auth";
+import useEdaratLists from "@/lib/hooks/useEdaratLists";
+import DescriptionForm from "./RowActions/DescriptionDialog";
+import LocationForm from "./RowActions/LocationDialog";
+import EngineeringIcon from "@mui/icons-material/Engineering";
+import ThreePIcon from "@mui/icons-material/ThreeP";
+import ImageDialog from "./RowActions/ImageDialog";
+
+const SupervisorList = () => {
+ const { data: userPermissions } = usePermissions();
+ const hasCountryPermission = userPermissions?.includes("show-fast-react");
+ const { user } = useAuth();
+ const statusOptions = [
+ { value: "", label: "همه وضعیت ها" },
+ { value: 0, label: "درحال بررسی" },
+ { value: 1, label: "تایید شده" },
+ { value: 2, label: "عدم تایید" },
+ ];
+
+ const columns = useMemo(() => {
+ const dynamicColumns = {
+ header: "استان",
+ id: "road_observeds__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,
+ },
+ {
+ accessorKey: "fk_RegisteredEventMessage",
+ header: "کد سوانح",
+ id: "fk_RegisteredEventMessage",
+ enableColumnFilter: true,
+ datatype: "text",
+ filterMode: "equals",
+ sortDescFirst: false,
+ columnFilterModeOptions: ["equals", "contains"],
+ grow: false,
+ size: 100,
+ },
+ ...(hasCountryPermission ? [dynamicColumns] : []),
+ {
+ header: "اداره",
+ id: "edarat_id",
+ enableColumnFilter: true,
+ datatype: "numeric",
+ filterMode: "equals",
+ dependencyId: hasCountryPermission ? "road_observeds__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: ({ renderedCellValue, row }) => <>{row.original.city_fa}>,
+ },
+ {
+ accessorKey: "Title",
+ header: "موضوع گزارش",
+ id: "Title",
+ enableColumnFilter: true,
+ datatype: "text",
+ filterMode: "equals",
+ sortDescFirst: false,
+ columnFilterModeOptions: ["equals", "contains"],
+ grow: false,
+ size: 100,
+ },
+ {
+ accessorKey: "FeatureTypeTitle",
+ header: "نوع گزارش",
+ id: "FeatureTypeTitle",
+ enableColumnFilter: true,
+ datatype: "text",
+ filterMode: "equals",
+ sortDescFirst: false,
+ columnFilterModeOptions: ["equals", "contains"],
+ grow: false,
+ size: 100,
+ },
+ {
+ accessorKey: "Description",
+ header: "توضیح گزارش",
+ id: "Description",
+ enableColumnFilter: false,
+ datatype: "text",
+ filterMode: "equals",
+ sortDescFirst: 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 بدون توضیحات;
+ },
+ },
+ {
+ 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: "images",
+ 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 }) => {
+ if (!row.original?.image_before && !row.original?.image_after) return <>بدون تصویر>;
+ return (
+
+ {row.original?.image_before && row.original?.image_after && (
+
+ )}
+
+ );
+ },
+ },
+ {
+ accessorKey: "MobileForSendEventSms",
+ header: "شماره تماس گیرنده",
+ id: "MobileForSendEventSms",
+ enableColumnFilter: true,
+ datatype: "text",
+ filterMode: "equals",
+ sortDescFirst: false,
+ columnFilterModeOptions: ["equals", "contains"],
+ 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,
+ },
+ {
+ accessorFn: (row) => moment(row.rms_last_activity).locale("fa").format("HH:mm | yyyy/MM/DD"),
+ header: "تاریخ اقدام",
+ id: "rms_last_activity",
+ enableColumnFilter: true,
+ datatype: "date",
+ filterMode: "between",
+ grow: false,
+ size: 100,
+ },
+ {
+ accessorKey: "rms_description",
+ header: "توضیح مامور",
+ id: "rms_description",
+ enableColumnFilter: false,
+ datatype: "text",
+ filterMode: "equals",
+ sortDescFirst: 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: "supervisor_description",
+ header: "توضیح کارشناس",
+ id: "supervisor_description",
+ enableColumnFilter: false,
+ datatype: "text",
+ filterMode: "equals",
+ sortDescFirst: 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: "status",
+ header: "وضعیت",
+ id: "status",
+ 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.status_fa}>,
+ },
+ ];
+ }, []);
+
+ return (
+ <>
+
+
+
+ >
+ );
+};
+export default SupervisorList;
diff --git a/src/components/dashboard/fastReact/supervisor/Toolbar.jsx b/src/components/dashboard/fastReact/supervisor/Toolbar.jsx
new file mode 100644
index 0000000..479ae4e
--- /dev/null
+++ b/src/components/dashboard/fastReact/supervisor/Toolbar.jsx
@@ -0,0 +1,13 @@
+import PrintExcel from "./ExcelPrint";
+import ComplaintList from "../complaintList";
+import { Stack } from "@mui/material";
+
+const Toolbar = ({ table, filterData, mutate }) => {
+ return (
+
+
+
+
+ );
+};
+export default Toolbar;
diff --git a/src/components/dashboard/fastReact/supervisor/index.jsx b/src/components/dashboard/fastReact/supervisor/index.jsx
new file mode 100644
index 0000000..3fa490b
--- /dev/null
+++ b/src/components/dashboard/fastReact/supervisor/index.jsx
@@ -0,0 +1,14 @@
+"use client";
+import PageTitle from "@/core/components/PageTitle";
+import { Stack } from "@mui/material";
+import SupervisorList from "./SupervisorList";
+
+const SupervisorPage = () => {
+ return (
+
+
+
+
+ );
+};
+export default SupervisorPage;
diff --git a/src/components/dashboard/roadItems/operator/RowActions/LocationForm/LocationFormContent.jsx b/src/components/dashboard/roadItems/operator/RowActions/LocationForm/LocationFormContent.jsx
index 1e20921..14b3db3 100644
--- a/src/components/dashboard/roadItems/operator/RowActions/LocationForm/LocationFormContent.jsx
+++ b/src/components/dashboard/roadItems/operator/RowActions/LocationForm/LocationFormContent.jsx
@@ -32,5 +32,4 @@ const LocationFormContent = ({ setOpenLocationDialog, start_lat, start_lng, end_
>
);
};
-
export default LocationFormContent;
diff --git a/src/components/dashboard/roadItems/supervisor/SupervisorList.jsx b/src/components/dashboard/roadItems/supervisor/SupervisorList.jsx
index 314004c..f4b42cf 100644
--- a/src/components/dashboard/roadItems/supervisor/SupervisorList.jsx
+++ b/src/components/dashboard/roadItems/supervisor/SupervisorList.jsx
@@ -78,7 +78,7 @@ const SupervisorList = () => {
},
...(hasCountryPermission ? [dynamicColumns] : []),
{
- header: "اداره", // Office
+ header: "اداره",
id: "edarat_id",
enableColumnFilter: true,
datatype: "numeric",
diff --git a/src/core/utils/pageMenu.js b/src/core/utils/pageMenu.js
index 94569b3..2eaf65b 100644
--- a/src/core/utils/pageMenu.js
+++ b/src/core/utils/pageMenu.js
@@ -369,8 +369,8 @@ export const pageMenu = [
id: "roadObservationsManagmentSupervisorCartable",
label: "کارتابل",
type: "page",
- route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_observations/supervisor/cartable",
- permissions: ["supervise-fast-react", "supervise-fast-react-province"],
+ route: "/dashboard/fast-react/supervisor",
+ permissions: ["show-fast-react", "show-fast-react-province"],
},
],
},
diff --git a/src/core/utils/routes.js b/src/core/utils/routes.js
index 06c6212..21e97b8 100644
--- a/src/core/utils/routes.js
+++ b/src/core/utils/routes.js
@@ -110,3 +110,9 @@ export const EXPORT_PROVINCE_RECEIPT_REPORT = api + "/api/v3/receipt_reports/pro
// activity code log
export const ACTIVITY_LOG = api + "/api/v3/profile/add_activity";
+
+// fast react
+export const GET_FAST_REACT_SUPERVISOR = api + "/api/v3/road_observations/supervisor_index";
+export const GET_FAST_REACT_COMPLAINTS = api + "/api/v3/road_observations/complaints_index";
+export const VERIFY_BY_FAST_REACT_SUPERVISOR = api + "/api/v3/road_observations/verify";
+export const REJECT_BY_FAST_REACT_SUPERVISOR = api + "/api/v3/road_observations/verify";