formatting

This commit is contained in:
2025-01-06 13:09:46 +03:30
parent 6371630380
commit 82d8f1c7e9
28 changed files with 718 additions and 640 deletions

View File

@@ -1,9 +1,9 @@
import React, {useState} from "react"; import React, { useState } from "react";
import {useForm} from "react-hook-form"; import { useForm } from "react-hook-form";
import {yupResolver} from "@hookform/resolvers/yup"; import { yupResolver } from "@hookform/resolvers/yup";
import {array, mixed, number, object, string} from "yup"; import { array, mixed, number, object, string } from "yup";
import {useTheme} from "@emotion/react"; import { useTheme } from "@emotion/react";
import {Box, Button, DialogActions, DialogContent, Tab, Tabs, useMediaQuery} from "@mui/material"; import { Box, Button, DialogActions, DialogContent, Tab, Tabs, useMediaQuery } from "@mui/material";
import StyledForm from "@/core/components/StyledForm"; import StyledForm from "@/core/components/StyledForm";
import InsertDriveFileIcon from "@mui/icons-material/InsertDriveFile"; import InsertDriveFileIcon from "@mui/icons-material/InsertDriveFile";
import FileCopyIcon from "@mui/icons-material/FileCopy"; import FileCopyIcon from "@mui/icons-material/FileCopy";
@@ -16,7 +16,7 @@ import GetSubItemsForm from "@/components/dashboard/roadItems/operator/Actions/C
import GetItemInfo from "@/components/dashboard/roadItems/operator/Actions/Create/Forms/GetItemInfo"; import GetItemInfo from "@/components/dashboard/roadItems/operator/Actions/Create/Forms/GetItemInfo";
function TabPanel(props) { function TabPanel(props) {
const {children, value, index} = props; const { children, value, index } = props;
return ( return (
<div role="tabpanel" hidden={value !== index}> <div role="tabpanel" hidden={value !== index}>
{value === index && <Box>{children}</Box>} {value === index && <Box>{children}</Box>}
@@ -30,26 +30,28 @@ const validationSchema = object({
amount: string().required("وارد کردن مقدار الزامیست!"), amount: string().required("وارد کردن مقدار الزامیست!"),
cmms_machines: array().required("وارد کردن کد خودرو الزامیست!"), cmms_machines: array().required("وارد کردن کد خودرو الزامیست!"),
rahdaran_id: array().required("وارد کردن کد راهداران الزامیست!").min(1, "حداقل یک کد راهدار باید وارد شود!"), // بررسی حداقل یک آیتم, rahdaran_id: array().required("وارد کردن کد راهداران الزامیست!").min(1, "حداقل یک کد راهدار باید وارد شود!"), // بررسی حداقل یک آیتم,
activity_time: string() activity_time: string().test("activity-time-conditional", "لطفا زمان فعالیت را انتخاب کنید!", function (value) {
.test("activity-time-conditional", "لطفا زمان فعالیت را انتخاب کنید!", function (value) { const { is_gasht } = this.options.context; // دسترسی به context
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) { if (is_gasht) {
return true; // اگر is_gasht true باشد، این فیلد نیاز به اعتبارسنجی ندارد return true; // اگر is_gasht true باشد، این فیلد نیاز به اعتبارسنجی ندارد
} }
return !!value; // در غیر این صورت مقدار فیلد باید وجود داشته باشد 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() before_image: mixed()
.nullable() .nullable()
.test("before-image-required", "لطفا عکس قبل از اقدام را بارگذاری کنید!", function (value) { .test("before-image-required", "لطفا عکس قبل از اقدام را بارگذاری کنید!", function (value) {
const {subItemsList} = this.options.context; const { subItemsList } = this.options.context;
const needsImage = subItemsList?.needs_image === 1; const needsImage = subItemsList?.needs_image === 1;
if (needsImage) { if (needsImage) {
return !!value; return !!value;
@@ -59,7 +61,7 @@ const validationSchema = object({
after_image: mixed() after_image: mixed()
.nullable() .nullable()
.test("after-image-required", "لطفا عکس بعد از اقدام را بارگذاری کنید!", function (value) { .test("after-image-required", "لطفا عکس بعد از اقدام را بارگذاری کنید!", function (value) {
const {subItemsList} = this.options.context; const { subItemsList } = this.options.context;
const needsImage = subItemsList?.needs_image === 1; const needsImage = subItemsList?.needs_image === 1;
if (needsImage) { if (needsImage) {
return !!value; return !!value;
@@ -72,7 +74,7 @@ const validationSchema = object({
}) })
.required("لطفاً نقطه شروع را مشخص کنید!"), .required("لطفاً نقطه شروع را مشخص کنید!"),
end_point: mixed().test("end-point-required", "لطفاً نقطه پایان را مشخص کنید!", function (value) { end_point: mixed().test("end-point-required", "لطفاً نقطه پایان را مشخص کنید!", function (value) {
const {subItemsList} = this.options.context; const { subItemsList } = this.options.context;
const needsEndPoint = subItemsList?.needs_end_point === 1; const needsEndPoint = subItemsList?.needs_end_point === 1;
if (needsEndPoint) { if (needsEndPoint) {
return !!value; // چک می‌کند که مقدار موجود است return !!value; // چک می‌کند که مقدار موجود است
@@ -81,7 +83,7 @@ const validationSchema = object({
}), }),
}); });
const CreateFormContent = ({setOpen, onSubmit, is_gasht = false}) => { const CreateFormContent = ({ setOpen, onSubmit, is_gasht = false }) => {
const defaultValues = { const defaultValues = {
item_id: null, item_id: null,
sub_item_id: null, sub_item_id: null,
@@ -92,7 +94,7 @@ const CreateFormContent = ({setOpen, onSubmit, is_gasht = false}) => {
rahdaran_id: null, rahdaran_id: null,
start_point: "", start_point: "",
end_point: "", end_point: "",
...(!is_gasht && {activity_time: "", activity_date: ""}), ...(!is_gasht && { activity_time: "", activity_date: "" }),
}; };
const [tabState, setTabState] = useState(0); const [tabState, setTabState] = useState(0);
@@ -138,15 +140,15 @@ const CreateFormContent = ({setOpen, onSubmit, is_gasht = false}) => {
handleSubmit, handleSubmit,
setValue, setValue,
resetField, resetField,
formState: {errors, isSubmitting}, formState: { errors, isSubmitting },
} = useForm({ } = useForm({
defaultValues, defaultValues,
resolver: yupResolver(validationSchema), resolver: yupResolver(validationSchema),
mode: "onBlur", mode: "onBlur",
context: {subItemsList, is_gasht}, context: { subItemsList, is_gasht },
}); });
const onSubmitBase = (data) => { const onSubmitBase = (data) => {
let result = {...data}; let result = { ...data };
if (result.before_image === null) { if (result.before_image === null) {
delete result.before_image; delete result.before_image;
@@ -192,7 +194,7 @@ const CreateFormContent = ({setOpen, onSubmit, is_gasht = false}) => {
}, },
}); });
}; };
console.log(errors) console.log(errors);
return ( return (
<StyledForm onSubmit={handleSubmit(onSubmitBase)} id="road_items"> <StyledForm onSubmit={handleSubmit(onSubmitBase)} id="road_items">
@@ -208,12 +210,12 @@ const CreateFormContent = ({setOpen, onSubmit, is_gasht = false}) => {
backgroundColor: "#efefef", backgroundColor: "#efefef",
}} }}
> >
<Tab icon={<InsertDriveFileIcon/>} label="انتخاب آیتم"/> <Tab icon={<InsertDriveFileIcon />} label="انتخاب آیتم" />
<Tab disabled={tabState === 0} icon={<FileCopyIcon/>} label="انتخاب موضوع مشاهده شده"/> <Tab disabled={tabState === 0} icon={<FileCopyIcon />} label="انتخاب موضوع مشاهده شده" />
<Tab disabled={tabState === 0 || tabState === 1} icon={<InfoIcon/>} label="اطلاعات فعالیت"/> <Tab disabled={tabState === 0 || tabState === 1} icon={<InfoIcon />} label="اطلاعات فعالیت" />
</Tabs> </Tabs>
<DialogContent dividers sx={{overflowY: "auto", maxHeight: "70vh"}}> <DialogContent dividers sx={{ overflowY: "auto", maxHeight: "70vh" }}>
<Box sx={{flex: 1}}> <Box sx={{ flex: 1 }}>
<TabPanel value={tabState} index={0}> <TabPanel value={tabState} index={0}>
<GetItemsForm <GetItemsForm
setItemsList={setItemsList} setItemsList={setItemsList}
@@ -247,13 +249,13 @@ const CreateFormContent = ({setOpen, onSubmit, is_gasht = false}) => {
</TabPanel> </TabPanel>
</Box> </Box>
</DialogContent> </DialogContent>
<DialogActions sx={{alignItems: "center", justifyContent: "center"}}> <DialogActions sx={{ alignItems: "center", justifyContent: "center" }}>
<Button <Button
onClick={handlePrev} onClick={handlePrev}
variant="outlined" variant="outlined"
color="error" color="error"
size="large" size="large"
startIcon={tabState === 0 ? <ExitToAppIcon/> : <KeyboardDoubleArrowRightIcon/>} startIcon={tabState === 0 ? <ExitToAppIcon /> : <KeyboardDoubleArrowRightIcon />}
> >
{tabState === 0 ? "بستن" : "مرحله قبل"} {tabState === 0 ? "بستن" : "مرحله قبل"}
</Button> </Button>
@@ -264,7 +266,7 @@ const CreateFormContent = ({setOpen, onSubmit, is_gasht = false}) => {
disabled={isSubmitting} disabled={isSubmitting}
type={"submit"} type={"submit"}
form="road_items" form="road_items"
endIcon={<BeenhereIcon/>} endIcon={<BeenhereIcon />}
> >
{isSubmitting ? "در حال ثبت فعالیت" : "ثبت فعالیت"} {isSubmitting ? "در حال ثبت فعالیت" : "ثبت فعالیت"}
</Button> </Button>

View File

@@ -1,20 +1,20 @@
import {Grid, Stack} from "@mui/material"; import { Grid, Stack } from "@mui/material";
import ImageUpload from "./ImageUpload"; import ImageUpload from "./ImageUpload";
import MuiDatePicker from "@/core/components/MuiDatePicker"; import MuiDatePicker from "@/core/components/MuiDatePicker";
import MuiTimePicker from "@/core/components/MuiTimePicker"; import MuiTimePicker from "@/core/components/MuiTimePicker";
import MapInfoTwoMarker from "@/core/components/MapInfoTwoMarker"; import MapInfoTwoMarker from "@/core/components/MapInfoTwoMarker";
import MapInfoOneMarker from "@/core/components/MapInfoOneMarker"; import MapInfoOneMarker from "@/core/components/MapInfoOneMarker";
import {Controller} from "react-hook-form"; import { Controller } from "react-hook-form";
import CarCode from "@/core/components/CarCode"; import CarCode from "@/core/components/CarCode";
import RahdarCode from "@/core/components/RahdarCode"; import RahdarCode from "@/core/components/RahdarCode";
import PreviousStatesInfo from "./PreviousStatesInfo"; import PreviousStatesInfo from "./PreviousStatesInfo";
import NumberField from "@/core/components/NumberField"; import NumberField from "@/core/components/NumberField";
const GetItemInfo = ({register, itemsList, subItemsList, control, setValue, errors, watch, getValues, is_gasht}) => { const GetItemInfo = ({ register, itemsList, subItemsList, control, setValue, errors, watch, getValues, is_gasht }) => {
return ( return (
<Stack spacing={2}> <Stack spacing={2}>
<Stack> <Stack>
<PreviousStatesInfo itemsList={itemsList} subItemsList={subItemsList}/> <PreviousStatesInfo itemsList={itemsList} subItemsList={subItemsList} />
</Stack> </Stack>
<Stack> <Stack>
<NumberField <NumberField
@@ -45,7 +45,7 @@ const GetItemInfo = ({register, itemsList, subItemsList, control, setValue, erro
<Stack> <Stack>
<Controller <Controller
control={control} control={control}
render={({field, fieldState: {error}}) => { render={({ field, fieldState: { error } }) => {
return ( return (
<CarCode <CarCode
carCode={field.value || []} carCode={field.value || []}
@@ -61,7 +61,7 @@ const GetItemInfo = ({register, itemsList, subItemsList, control, setValue, erro
<Stack> <Stack>
<Controller <Controller
control={control} control={control}
render={({field, fieldState: {error}}) => { render={({ field, fieldState: { error } }) => {
return ( return (
<RahdarCode <RahdarCode
rahdarsCode={field.value || []} rahdarsCode={field.value || []}
@@ -75,7 +75,7 @@ const GetItemInfo = ({register, itemsList, subItemsList, control, setValue, erro
</Stack> </Stack>
<Stack> <Stack>
{subItemsList.needs_image ? ( {subItemsList.needs_image ? (
<ImageUpload setValue={setValue} control={control} errors={errors} getValues={getValues}/> <ImageUpload setValue={setValue} control={control} errors={errors} getValues={getValues} />
) : null} ) : null}
</Stack> </Stack>
{!is_gasht ? ( {!is_gasht ? (
@@ -106,9 +106,9 @@ const GetItemInfo = ({register, itemsList, subItemsList, control, setValue, erro
) : null} ) : null}
<Stack> <Stack>
{subItemsList?.needs_end_point === 1 ? ( {subItemsList?.needs_end_point === 1 ? (
<MapInfoTwoMarker setValue={setValue} errors={errors}/> <MapInfoTwoMarker setValue={setValue} errors={errors} />
) : ( ) : (
<MapInfoOneMarker setValue={setValue} errors={errors}/> <MapInfoOneMarker setValue={setValue} errors={errors} />
)} )}
</Stack> </Stack>
</Stack> </Stack>

View File

@@ -1,9 +1,9 @@
import {FormControl, FormHelperText, Grid} from "@mui/material"; import { FormControl, FormHelperText, Grid } from "@mui/material";
import UploadSystem from "@/core/components/UploadSystem"; import UploadSystem from "@/core/components/UploadSystem";
import {Controller} from "react-hook-form"; import { Controller } from "react-hook-form";
import React, {useEffect, useState} from "react"; import React, { useEffect, useState } from "react";
const ImageUpload = ({control, setValue, errors, getValues, beforeImage = null, afterImage = null}) => { const ImageUpload = ({ control, setValue, errors, getValues, beforeImage = null, afterImage = null }) => {
const [beforeImg, setBeforeImg] = useState(beforeImage ? beforeImage : null); const [beforeImg, setBeforeImg] = useState(beforeImage ? beforeImage : null);
const [beforeFileType, setBeforeFileType] = useState(beforeImage ? "image/" : null); const [beforeFileType, setBeforeFileType] = useState(beforeImage ? "image/" : null);
const [beforeFileName, setBeforeFileName] = useState(null); const [beforeFileName, setBeforeFileName] = useState(null);
@@ -73,7 +73,7 @@ const ImageUpload = ({control, setValue, errors, getValues, beforeImage = null,
<Controller <Controller
name="before_image" name="before_image"
control={control} control={control}
render={({field: {value, onChange}}) => { render={({ field: { value, onChange } }) => {
return ( return (
<FormControl <FormControl
error={errors.before_image} error={errors.before_image}
@@ -84,7 +84,7 @@ const ImageUpload = ({control, setValue, errors, getValues, beforeImage = null,
justifyContent: "center", justifyContent: "center",
}} }}
> >
<FormHelperText sx={{fontSize: "large"}} id="before_image"> <FormHelperText sx={{ fontSize: "large" }} id="before_image">
عکس قبل از اقدام عکس قبل از اقدام
</FormHelperText> </FormHelperText>
<UploadSystem <UploadSystem
@@ -109,7 +109,7 @@ const ImageUpload = ({control, setValue, errors, getValues, beforeImage = null,
<Controller <Controller
name="after_image" name="after_image"
control={control} control={control}
render={({field: {value, onChange}}) => { render={({ field: { value, onChange } }) => {
return ( return (
<FormControl <FormControl
error={errors.before_image} error={errors.before_image}
@@ -120,7 +120,7 @@ const ImageUpload = ({control, setValue, errors, getValues, beforeImage = null,
justifyContent: "center", justifyContent: "center",
}} }}
> >
<FormHelperText sx={{fontSize: "large"}} id="before_image"> <FormHelperText sx={{ fontSize: "large" }} id="before_image">
عکس بعد از اقدام عکس بعد از اقدام
</FormHelperText> </FormHelperText>
<UploadSystem <UploadSystem

View File

@@ -1,24 +1,24 @@
import {LinearProgress, Typography} from "@mui/material"; import { LinearProgress, Typography } from "@mui/material";
import React from "react"; import React from "react";
import useRoadItemGetISubtems from "@/lib/hooks/useRoadItemGetISubtems"; import useRoadItemGetISubtems from "@/lib/hooks/useRoadItemGetISubtems";
import EditFormCreate from "@/components/dashboard/roadItems/operator/RowActions/EditForm/EditFormCreate"; import EditFormCreate from "@/components/dashboard/roadItems/operator/RowActions/EditForm/EditFormCreate";
const EditFormContent = ({setOpenEditDialog, onSubmit, defaultData}) => { const EditFormContent = ({ setOpenEditDialog, onSubmit, defaultData }) => {
const {subItemsList, loadingSubItemsList, errorSubItemsList} = useRoadItemGetISubtems(defaultData?.item_id); const { subItemsList, loadingSubItemsList, errorSubItemsList } = useRoadItemGetISubtems(defaultData?.item_id);
const subItem = subItemsList.find((SubItem) => SubItem.sub_item === defaultData?.sub_item_id); const subItem = subItemsList.find((SubItem) => SubItem.sub_item === defaultData?.sub_item_id);
const defaultValues = { const defaultValues = {
before_image: defaultData?.before_image || null, before_image: defaultData?.before_image || null,
after_image: defaultData?.after_image || null, after_image: defaultData?.after_image || null,
amount: defaultData?.amount || null, amount: defaultData?.amount || null,
start_point: defaultData?.start_point || {lat: "", lng: ""}, start_point: defaultData?.start_point || { lat: "", lng: "" },
end_point: defaultData?.end_point || {lat: "", lng: ""}, end_point: defaultData?.end_point || { lat: "", lng: "" },
cmms_machines: defaultData?.cmms_machines || null, cmms_machines: defaultData?.cmms_machines || null,
rahdaran_id: defaultData?.rahdaran_id || null, rahdaran_id: defaultData?.rahdaran_id || null,
}; };
const onSubmitBase = (data) => { const onSubmitBase = (data) => {
let result = {...data}; let result = { ...data };
if (result.before_image === null) { if (result.before_image === null) {
delete result.before_image; delete result.before_image;
delete data.before_image; delete data.before_image;
@@ -73,7 +73,7 @@ const EditFormContent = ({setOpenEditDialog, onSubmit, defaultData}) => {
خطا در دریافت اطلاعات!!! خطا در دریافت اطلاعات!!!
</Typography> </Typography>
) : loadingSubItemsList ? ( ) : loadingSubItemsList ? (
<LinearProgress/> <LinearProgress />
) : ( ) : (
<EditFormCreate <EditFormCreate
onSubmitBase={onSubmitBase} onSubmitBase={onSubmitBase}

View File

@@ -1,15 +1,15 @@
import {Button, DialogActions, DialogContent, Stack} from "@mui/material"; import { Button, DialogActions, DialogContent, Stack } from "@mui/material";
import ImageUpload from "@/components/dashboard/roadItems/operator/Actions/Create/Forms/ImageUpload"; import ImageUpload from "@/components/dashboard/roadItems/operator/Actions/Create/Forms/ImageUpload";
import NumberField from "@/core/components/NumberField"; import NumberField from "@/core/components/NumberField";
import {Controller, useForm} from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
import CarCode from "@/core/components/CarCode"; import CarCode from "@/core/components/CarCode";
import RahdarCode from "@/core/components/RahdarCode"; import RahdarCode from "@/core/components/RahdarCode";
import MapInfoTwoMarker from "@/core/components/MapInfoTwoMarker"; import MapInfoTwoMarker from "@/core/components/MapInfoTwoMarker";
import MapInfoOneMarker from "@/core/components/MapInfoOneMarker"; import MapInfoOneMarker from "@/core/components/MapInfoOneMarker";
import StyledForm from "@/core/components/StyledForm"; import StyledForm from "@/core/components/StyledForm";
import React from "react"; import React from "react";
import {yupResolver} from "@hookform/resolvers/yup"; import { yupResolver } from "@hookform/resolvers/yup";
import {array, mixed, object, string} from "yup"; import { array, mixed, object, string } from "yup";
const validationSchema = object({ const validationSchema = object({
amount: string().required("وارد کردن مقدار الزامیست!"), amount: string().required("وارد کردن مقدار الزامیست!"),
@@ -18,7 +18,7 @@ const validationSchema = object({
before_image: mixed() before_image: mixed()
.nullable() .nullable()
.test("before-image-required", "لطفا عکس قبل از اقدام را بارگذاری کنید!", function (value) { .test("before-image-required", "لطفا عکس قبل از اقدام را بارگذاری کنید!", function (value) {
const {subItem} = this.options.context; const { subItem } = this.options.context;
const needsImage = subItem?.needs_image === 1; const needsImage = subItem?.needs_image === 1;
if (needsImage) { if (needsImage) {
return !!value; return !!value;
@@ -28,7 +28,7 @@ const validationSchema = object({
after_image: mixed() after_image: mixed()
.nullable() .nullable()
.test("after-image-required", "لطفا عکس بعد از اقدام را بارگذاری کنید!", function (value) { .test("after-image-required", "لطفا عکس بعد از اقدام را بارگذاری کنید!", function (value) {
const {subItem} = this.options.context; const { subItem } = this.options.context;
const needsImage = subItem?.needs_image === 1; const needsImage = subItem?.needs_image === 1;
if (needsImage) { if (needsImage) {
return !!value; return !!value;
@@ -41,7 +41,7 @@ const validationSchema = object({
}) })
.required("لطفاً نقطه شروع را مشخص کنید!"), .required("لطفاً نقطه شروع را مشخص کنید!"),
end_point: mixed().test("end-point-required", "لطفاً نقطه پایان را مشخص کنید!", function (value) { end_point: mixed().test("end-point-required", "لطفاً نقطه پایان را مشخص کنید!", function (value) {
const {subItem} = this.options.context; const { subItem } = this.options.context;
const needsEndPoint = subItem?.needs_end_point === 1; const needsEndPoint = subItem?.needs_end_point === 1;
if (needsEndPoint) { if (needsEndPoint) {
return !!value; return !!value;
@@ -50,7 +50,7 @@ const validationSchema = object({
}), }),
}); });
const EditFormCreate = ({defaultData, subItem, onSubmitBase, defaultValues, setOpenEditDialog}) => { const EditFormCreate = ({ defaultData, subItem, onSubmitBase, defaultValues, setOpenEditDialog }) => {
const { const {
control, control,
getValues, getValues,
@@ -58,17 +58,17 @@ const EditFormCreate = ({defaultData, subItem, onSubmitBase, defaultValues, setO
register, register,
handleSubmit, handleSubmit,
setValue, setValue,
formState: {errors, isSubmitting}, formState: { errors, isSubmitting },
} = useForm({ } = useForm({
defaultValues, defaultValues,
resolver: yupResolver(validationSchema), resolver: yupResolver(validationSchema),
mode: "onBlur", mode: "onBlur",
context: {subItem}, context: { subItem },
}); });
return ( return (
<StyledForm onSubmit={handleSubmit(onSubmitBase)} id="edit_road_items"> <StyledForm onSubmit={handleSubmit(onSubmitBase)} id="edit_road_items">
<DialogContent sx={{overflowY: "auto", maxHeight: "70vh"}}> <DialogContent sx={{ overflowY: "auto", maxHeight: "70vh" }}>
<Stack spacing={2}> <Stack spacing={2}>
<Stack> <Stack>
{subItem.needs_image === 1 ? ( {subItem.needs_image === 1 ? (
@@ -111,7 +111,7 @@ const EditFormCreate = ({defaultData, subItem, onSubmitBase, defaultValues, setO
<Stack> <Stack>
<Controller <Controller
control={control} control={control}
render={({field, fieldState: {error}}) => { render={({ field, fieldState: { error } }) => {
return ( return (
<CarCode <CarCode
carCode={field.value || []} carCode={field.value || []}
@@ -128,7 +128,7 @@ const EditFormCreate = ({defaultData, subItem, onSubmitBase, defaultValues, setO
<Stack> <Stack>
<Controller <Controller
control={control} control={control}
render={({field, fieldState: {error}}) => { render={({ field, fieldState: { error } }) => {
return ( return (
<RahdarCode <RahdarCode
rahdarsCode={field.value || []} rahdarsCode={field.value || []}
@@ -162,8 +162,13 @@ const EditFormCreate = ({defaultData, subItem, onSubmitBase, defaultValues, setO
<Button onClick={() => setOpenEditDialog(false)} variant="outlined" color="primary" autoFocus> <Button onClick={() => setOpenEditDialog(false)} variant="outlined" color="primary" autoFocus>
بستن بستن
</Button> </Button>
<Button form="edit_road_items" disabled={isSubmitting} type={"submit"} variant="contained" <Button
color="primary"> form="edit_road_items"
disabled={isSubmitting}
type={"submit"}
variant="contained"
color="primary"
>
{isSubmitting ? "در حال ویرایش" : "ویرایش"} {isSubmitting ? "در حال ویرایش" : "ویرایش"}
</Button> </Button>
</DialogActions> </DialogActions>

View File

@@ -1,12 +1,12 @@
"use client"; "use client";
import {Button, IconButton, useMediaQuery} from "@mui/material"; import { Button, IconButton, useMediaQuery } from "@mui/material";
import {useTheme} from "@emotion/react"; import { useTheme } from "@emotion/react";
import {useState} from "react"; import { useState } from "react";
import {AddCircle} from "@mui/icons-material"; import { AddCircle } from "@mui/icons-material";
import CreatePatrol from "../../Forms/CreatePatrol"; import CreatePatrol from "../../Forms/CreatePatrol";
const OperatorCreate = ({mutate}) => { const OperatorCreate = ({ mutate }) => {
const theme = useTheme(); const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down("sm")); const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
@@ -19,14 +19,14 @@ const OperatorCreate = ({mutate}) => {
<> <>
{isMobile ? ( {isMobile ? (
<IconButton aria-label="ثبت اقدام جدید" color="primary" onClick={handleOpen}> <IconButton aria-label="ثبت اقدام جدید" color="primary" onClick={handleOpen}>
<AddCircle sx={{fontSize: "25px"}}/> <AddCircle sx={{ fontSize: "25px" }} />
</IconButton> </IconButton>
) : ( ) : (
<Button variant="contained" color="primary" startIcon={<AddCircle/>} onClick={handleOpen}> <Button variant="contained" color="primary" startIcon={<AddCircle />} onClick={handleOpen}>
ثبت اقدام ثبت اقدام
</Button> </Button>
)} )}
{open && <CreatePatrol open={open} setOpen={setOpen} mutate={mutate}/>} {open && <CreatePatrol open={open} setOpen={setOpen} mutate={mutate} />}
</> </>
); );
}; };

View File

@@ -1,18 +1,18 @@
import {Button, CircularProgress} from "@mui/material"; import { Button, CircularProgress } from "@mui/material";
import {useMemo, useState} from "react"; import { useMemo, useState } from "react";
import moment from "jalali-moment"; import moment from "jalali-moment";
import FileSaver from "file-saver"; import FileSaver from "file-saver";
import DescriptionIcon from "@mui/icons-material/Description"; import DescriptionIcon from "@mui/icons-material/Description";
import useRequest from "@/lib/hooks/useRequest"; import useRequest from "@/lib/hooks/useRequest";
import {EXPORT_ROAD_PATROL_OPERATOR_LIST} from "@/core/utils/routes"; import { EXPORT_ROAD_PATROL_OPERATOR_LIST } from "@/core/utils/routes";
const PrintExcel = ({table, filterData}) => { const PrintExcel = ({ table, filterData }) => {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const requestServer = useRequest(); const requestServer = useRequest();
const activeFilters = Object.entries(filterData).reduce((acc, [key, filter]) => { const activeFilters = Object.entries(filterData).reduce((acc, [key, filter]) => {
if (filter.value) { if (filter.value) {
// Check if there's an active filter // Check if there's an active filter
acc.push({id: key, value: filter.value}); acc.push({ id: key, value: filter.value });
} }
return acc; return acc;
}, []); }, []);
@@ -20,23 +20,22 @@ const PrintExcel = ({table, filterData}) => {
const filterParams = useMemo(() => { const filterParams = useMemo(() => {
const params = new URLSearchParams(); const params = new URLSearchParams();
activeFilters.length > 0 && activeFilters.length > 0 &&
activeFilters.map((filter, index) => { activeFilters.map((filter, index) => {
params.set(`${filter.id}`, filter.value); params.set(`${filter.id}`, filter.value);
}); });
return params; return params;
}, [activeFilters]); }, [activeFilters]);
const clickHandler = () => { const clickHandler = () => {
setLoading(true); setLoading(true);
requestServer(`${EXPORT_ROAD_PATROL_OPERATOR_LIST}?${filterParams}`, "get", { requestServer(`${EXPORT_ROAD_PATROL_OPERATOR_LIST}?${filterParams}`, "get", {
requestOptions: {responseType: "blob"}, requestOptions: { responseType: "blob" },
}) })
.then((response) => { .then((response) => {
const filename = `خروجی کارتابل عملیات تاریخ_${moment().format("jYYYY_jMM_jDD")}.xlsx`; const filename = `خروجی کارتابل عملیات تاریخ_${moment().format("jYYYY_jMM_jDD")}.xlsx`;
FileSaver.saveAs(response.data, filename); FileSaver.saveAs(response.data, filename);
}) })
.catch(() => { .catch(() => {})
})
.finally(() => { .finally(() => {
setLoading(false); setLoading(false);
}); });
@@ -47,8 +46,8 @@ const PrintExcel = ({table, filterData}) => {
color="primary" color="primary"
variant="contained" variant="contained"
disabled={loading} disabled={loading}
sx={{textTransform: "unset", alignSelf: "center"}} sx={{ textTransform: "unset", alignSelf: "center" }}
startIcon={loading ? <CircularProgress size={18} color="inherit"/> : <DescriptionIcon/>} startIcon={loading ? <CircularProgress size={18} color="inherit" /> : <DescriptionIcon />}
onClick={clickHandler} onClick={clickHandler}
> >
خروجی اکسل خروجی اکسل

View File

@@ -13,44 +13,40 @@ import {
Divider, Divider,
IconButton, IconButton,
Stack, Stack,
Typography Typography,
} from "@mui/material"; } from "@mui/material";
import HandymanIcon from '@mui/icons-material/Handyman'; import HandymanIcon from "@mui/icons-material/Handyman";
import DeleteIcon from "@mui/icons-material/Delete"; import DeleteIcon from "@mui/icons-material/Delete";
import DirectionsCarIcon from '@mui/icons-material/DirectionsCar'; import DirectionsCarIcon from "@mui/icons-material/DirectionsCar";
import PersonIcon from '@mui/icons-material/Person'; import PersonIcon from "@mui/icons-material/Person";
import DesignServicesIcon from '@mui/icons-material/DesignServices'; import DesignServicesIcon from "@mui/icons-material/DesignServices";
import EditActionDuringPatrol from "./EditActionDuringPatrol"; import EditActionDuringPatrol from "./EditActionDuringPatrol";
const MapLayer = dynamic(() => import("@/core/components/MapLayer"), { const MapLayer = dynamic(() => import("@/core/components/MapLayer"), {
loading: () => <MapLoading/>, loading: () => <MapLoading />,
ssr: false, ssr: false,
}); });
const ActionInfo = ({action, setActionsList, index, deleteAction}) => { const ActionInfo = ({ action, setActionsList, index, deleteAction }) => {
return ( return (
<Card sx={{maxWidth: 300}}> <Card sx={{ maxWidth: 300 }}>
<CardHeader <CardHeader
avatar={ avatar={<HandymanIcon color="primary" sx={{ width: "30px", height: "30px" }} />}
<HandymanIcon color="primary" sx={{width: "30px", height: "30px"}}/> title={<Typography sx={{ fontSize: "14px", fontWeight: 500 }}>{action.data.item_name}</Typography>}
}
title={<Typography sx={{fontSize: "14px", fontWeight: 500}}>{action.data.item_name}</Typography>}
subheader={action.data.sub_item_name} subheader={action.data.sub_item_name}
/> />
<CardContent> <CardContent>
<Stack sx={{gap: 1}}> <Stack sx={{ gap: 1 }}>
<Box sx={{display: "flex", alignItems: "center", gap: 1}}> <Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
<DesignServicesIcon/> <DesignServicesIcon />
<Typography variant="button"> <Typography variant="button">میزان فعالیت انجام شده:</Typography>
میزان فعالیت انجام شده:
</Typography>
<Typography variant="button"> <Typography variant="button">
{action.data.amount}({action.data.unit_fa}) {action.data.amount}({action.data.unit_fa})
</Typography> </Typography>
</Box> </Box>
<Box> <Box>
<Divider sx={{mb: 1}}> <Divider sx={{ mb: 1 }}>
<Chip size="small" label="خودرو ها" icon={<DirectionsCarIcon/>}/> <Chip size="small" label="خودرو ها" icon={<DirectionsCarIcon />} />
</Divider> </Divider>
<Stack> <Stack>
{action.data.cmms_machines.map((cmms_machine, index) => ( {action.data.cmms_machines.map((cmms_machine, index) => (
@@ -61,8 +57,8 @@ const ActionInfo = ({action, setActionsList, index, deleteAction}) => {
</Stack> </Stack>
</Box> </Box>
<Box> <Box>
<Divider sx={{mb: 1}}> <Divider sx={{ mb: 1 }}>
<Chip size="small" label="راهداران" icon={<PersonIcon/>}/> <Chip size="small" label="راهداران" icon={<PersonIcon />} />
</Divider> </Divider>
<Stack> <Stack>
{action.data.rahdaran_id.map((rahdar, index) => ( {action.data.rahdaran_id.map((rahdar, index) => (
@@ -77,13 +73,13 @@ const ActionInfo = ({action, setActionsList, index, deleteAction}) => {
<CardActions disableSpacing> <CardActions disableSpacing>
<Box> <Box>
<IconButton aria-label="حذف فعالیت" color="error" onClick={deleteAction}> <IconButton aria-label="حذف فعالیت" color="error" onClick={deleteAction}>
<DeleteIcon/> <DeleteIcon />
</IconButton> </IconButton>
<EditActionDuringPatrol action={action} index={index} setActionsList={setActionsList}/> <EditActionDuringPatrol action={action} index={index} setActionsList={setActionsList} />
</Box> </Box>
</CardActions> </CardActions>
</Card> </Card>
); );
}; };
export default ActionInfo; export default ActionInfo;

View File

@@ -1,13 +1,13 @@
"use client"; "use client";
import {Box, Button, Divider, Grid, Typography} from "@mui/material"; import { Box, Button, Divider, Grid, Typography } from "@mui/material";
import AddCircleIcon from '@mui/icons-material/AddCircle'; import AddCircleIcon from "@mui/icons-material/AddCircle";
import React, {useState} from "react"; import React, { useState } from "react";
import ModalActionsDuringPatrol from "./ModalActionsDuringPatrol"; import ModalActionsDuringPatrol from "./ModalActionsDuringPatrol";
import ActionInfo from "./ActionInfo"; import ActionInfo from "./ActionInfo";
import KeyboardDoubleArrowLeftIcon from "@mui/icons-material/KeyboardDoubleArrowLeft"; import KeyboardDoubleArrowLeftIcon from "@mui/icons-material/KeyboardDoubleArrowLeft";
const ActionsDuringPatrol = ({setValue, tabState, setTabState}) => { const ActionsDuringPatrol = ({ setValue, tabState, setTabState }) => {
const [ActionsList, setActionsList] = useState([]); const [ActionsList, setActionsList] = useState([]);
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const handleOpen = () => { const handleOpen = () => {
@@ -20,29 +20,37 @@ const ActionsDuringPatrol = ({setValue, tabState, setTabState}) => {
const SubmitActionDuringPatrol = () => { const SubmitActionDuringPatrol = () => {
setTabState(tabState + 1); setTabState(tabState + 1);
const resultItems = ActionsList.map(item => item.result); const resultItems = ActionsList.map((item) => item.result);
console.log("resultItems", resultItems); console.log("resultItems", resultItems);
setValue("observed_items", resultItems); setValue("observed_items", resultItems);
} };
return ( return (
<Box> <Box>
<Box sx={{display: "flex", alignItems: "center", justifyContent: "space-between"}}> <Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<Typography variant="h6">لیست اقدامات حین گشت</Typography> <Typography variant="h6">لیست اقدامات حین گشت</Typography>
<Button onClick={handleOpen} startIcon={<AddCircleIcon/>} variant="outlined" <Button
sx={{mb: 1, alignSelf: "end"}}> onClick={handleOpen}
startIcon={<AddCircleIcon />}
variant="outlined"
sx={{ mb: 1, alignSelf: "end" }}
>
ثبت اقدام ثبت اقدام
</Button> </Button>
<ModalActionsDuringPatrol open={open} setOpen={setOpen} setActionsList={setActionsList}/> <ModalActionsDuringPatrol open={open} setOpen={setOpen} setActionsList={setActionsList} />
</Box> </Box>
<Divider/> <Divider />
{ActionsList.length !== 0 ? {ActionsList.length !== 0 ? (
<Grid container spacing={2} sx={{ <Grid
p: 1, container
mt: 1, spacing={2}
maxHeight: "300px", sx={{
overflowY: "auto", p: 1,
}}> mt: 1,
maxHeight: "300px",
overflowY: "auto",
}}
>
{ActionsList.map((action, index) => ( {ActionsList.map((action, index) => (
<Grid key={index} item xs={12} sm={6} lg={4}> <Grid key={index} item xs={12} sm={6} lg={4}>
<ActionInfo <ActionInfo
@@ -54,18 +62,23 @@ const ActionsDuringPatrol = ({setValue, tabState, setTabState}) => {
</Grid> </Grid>
))} ))}
</Grid> </Grid>
: ) : (
<Box sx={{my: 5, width: "100%", textAlign: "center"}}> <Box sx={{ my: 5, width: "100%", textAlign: "center" }}>
<Typography variant="h6" sx={{letterSpacing: "2px", color: "#606060"}}> <Typography variant="h6" sx={{ letterSpacing: "2px", color: "#606060" }}>
فعالیتی ثبت نکرده اید فعالیتی ثبت نکرده اید
</Typography> </Typography>
</Box> </Box>
} )}
<Box> <Box>
<Box sx={{display: "flex", gap: 1, justifyContent: "center"}}> <Box sx={{ display: "flex", gap: 1, justifyContent: "center" }}>
<Button variant="contained" color="primary" onClick={SubmitActionDuringPatrol} <Button
disabled={ActionsList === []} variant="contained"
endIcon={<KeyboardDoubleArrowLeftIcon/>} sx={{mt: 2}}> color="primary"
onClick={SubmitActionDuringPatrol}
disabled={ActionsList === []}
endIcon={<KeyboardDoubleArrowLeftIcon />}
sx={{ mt: 2 }}
>
نهایی کردن درخواست نهایی کردن درخواست
</Button> </Button>
</Box> </Box>
@@ -74,4 +87,4 @@ const ActionsDuringPatrol = ({setValue, tabState, setTabState}) => {
); );
}; };
export default ActionsDuringPatrol; export default ActionsDuringPatrol;

View File

@@ -1,6 +1,6 @@
"use client"; "use client";
import React, {useEffect, useState} from "react"; import React, { useEffect, useState } from "react";
import { import {
Box, Box,
Button, Button,
@@ -12,17 +12,17 @@ import {
OutlinedInput, OutlinedInput,
Slide, Slide,
Stack, Stack,
Typography Typography,
} from "@mui/material"; } from "@mui/material";
import BeenhereIcon from "@mui/icons-material/Beenhere"; import BeenhereIcon from "@mui/icons-material/Beenhere";
import ForwardToInboxIcon from "@mui/icons-material/ForwardToInbox"; import ForwardToInboxIcon from "@mui/icons-material/ForwardToInbox";
import {formatCounter} from "@/core/utils/formatCounter"; import { formatCounter } from "@/core/utils/formatCounter";
import useRequest from "@/lib/hooks/useRequest"; import useRequest from "@/lib/hooks/useRequest";
import {GET_OTP_TOKEN} from "@/core/utils/routes"; import { GET_OTP_TOKEN } from "@/core/utils/routes";
import moment from "jalali-moment"; import moment from "jalali-moment";
const CompeleteRequest = ({watch, isSubmitting, setValue, register}) => { const CompeleteRequest = ({ watch, isSubmitting, setValue, register }) => {
const requestServer = useRequest({auth: true}); const requestServer = useRequest({ auth: true });
const [delayPerRequest, setDelayPerRequest] = useState(false); const [delayPerRequest, setDelayPerRequest] = useState(false);
const [phoneNumber, setPhoneNumber] = useState(""); const [phoneNumber, setPhoneNumber] = useState("");
const [validPhone, setValidPhone] = useState(false); const [validPhone, setValidPhone] = useState(false);
@@ -32,7 +32,7 @@ const CompeleteRequest = ({watch, isSubmitting, setValue, register}) => {
const [readyToVerify, setReadyToVerify] = useState(false); const [readyToVerify, setReadyToVerify] = useState(false);
const handleNumericInput = (e) => { const handleNumericInput = (e) => {
e.target.value = e.target.value.replace(/[^0-9]/g, ''); e.target.value = e.target.value.replace(/[^0-9]/g, "");
}; };
useEffect(() => { useEffect(() => {
@@ -55,7 +55,7 @@ const CompeleteRequest = ({watch, isSubmitting, setValue, register}) => {
} }
if (delayPerRequest && counter > 0) { if (delayPerRequest && counter > 0) {
const timer = setInterval(() => { const timer = setInterval(() => {
setCounter(prevCounter => prevCounter - 1); setCounter((prevCounter) => prevCounter - 1);
}, 1000); }, 1000);
return () => clearInterval(timer); return () => clearInterval(timer);
@@ -69,82 +69,89 @@ const CompeleteRequest = ({watch, isSubmitting, setValue, register}) => {
setOtpSended(true); setOtpSended(true);
setDelayPerRequest(true); setDelayPerRequest(true);
}) })
.catch(() => { .catch(() => {});
});
}; };
return ( return (
<Stack> <Stack>
<Stack> <Stack>
<Box sx={{display: "flex", alignItems: "center", justifyContent: "space-between"}}> <Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<Box> <Box>
<Typography sx={{color: "#777777", fontWeight: 500}} <Typography sx={{ color: "#777777", fontWeight: 500 }} variant="body1">
variant="body1">{moment(watch("start_time")).locale("fa").format("YYYY/MM/DD | HH:mm")}</Typography> {moment(watch("start_time")).locale("fa").format("YYYY/MM/DD | HH:mm")}
</Typography>
</Box> </Box>
<Box> <Box>
<Typography sx={{color: "#777777", fontWeight: 500}} <Typography sx={{ color: "#777777", fontWeight: 500 }} variant="body1">
variant="body1">{moment(watch("end_time")).locale("fa").format("YYYY/MM/DD | HH:mm")}</Typography> {moment(watch("end_time")).locale("fa").format("YYYY/MM/DD | HH:mm")}
</Typography>
</Box> </Box>
</Box> </Box>
<Grid container spacing={2} sx={{alignItems: "start", my: 1}}> <Grid container spacing={2} sx={{ alignItems: "start", my: 1 }}>
<Grid item xs={12} lg={6} sx={{display: "flex", alignItems: "center"}}> <Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}>
<Chip label="مدت زمان روشن بودن خودرو"/> <Chip label="مدت زمان روشن بودن خودرو" />
<Divider sx={{flex: 1, mx: 2}}/> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography>{watch("vehicle_runtime")}</Typography> <Typography>{watch("vehicle_runtime")}</Typography>
</Grid> </Grid>
<Grid item xs={12} lg={6} sx={{display: "flex", alignItems: "center"}}> <Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}>
<Chip label="میزان سوخت مصرفی"/> <Chip label="میزان سوخت مصرفی" />
<Divider sx={{flex: 1, mx: 2}}/> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography>{watch("fuel_consumption")}</Typography> <Typography>{watch("fuel_consumption")}</Typography>
</Grid> </Grid>
<Grid item xs={12} lg={6} sx={{display: "flex", alignItems: "center"}}> <Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}>
<Chip label="تعداد نقاط توقف"/> <Chip label="تعداد نقاط توقف" />
<Divider sx={{flex: 1, mx: 2}}/> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography>{watch("stop_points").length}</Typography> <Typography>{watch("stop_points").length}</Typography>
</Grid> </Grid>
<Grid item xs={12} lg={6} sx={{display: "flex", alignItems: "center"}}> <Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}>
<Chip label="مسافت پیموده شده"/> <Chip label="مسافت پیموده شده" />
<Divider sx={{flex: 1, mx: 2}}/> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography>{watch("distance")}</Typography> <Typography>{watch("distance")}</Typography>
</Grid> </Grid>
<Grid item xs={12} lg={6} sx={{display: "flex", alignItems: "center"}}> <Grid item xs={12} lg={6} sx={{ display: "flex", alignItems: "center" }}>
<Chip label="تعداد فعالیت های حین گشت"/> <Chip label="تعداد فعالیت های حین گشت" />
<Divider sx={{flex: 1, mx: 2}}/> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography>{watch("observed_items").length}</Typography> <Typography>{watch("observed_items").length}</Typography>
</Grid> </Grid>
</Grid> </Grid>
<Grid container spacing={3} sx={{alignItems: "start", my: 2}}> <Grid container spacing={3} sx={{ alignItems: "start", my: 2 }}>
<Grid item xs={12} lg={6}> <Grid item xs={12} lg={6}>
<Divider><Chip label="خودرو گشت"/></Divider> <Divider>
<Box sx={{display: "flex", alignItems: "center", my: 1}}> <Chip label="خودرو گشت" />
</Divider>
<Box sx={{ display: "flex", alignItems: "center", my: 1 }}>
<Typography>کد</Typography> <Typography>کد</Typography>
<Divider sx={{flex: 1, mx: 2}}/> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography>{watch("road_patrol_machines_id.machine_code")}</Typography> <Typography>{watch("road_patrol_machines_id.machine_code")}</Typography>
</Box> </Box>
<Box sx={{display: "flex", alignItems: "center", my: 1}}> <Box sx={{ display: "flex", alignItems: "center", my: 1 }}>
<Typography>نام</Typography> <Typography>نام</Typography>
<Divider sx={{flex: 1, mx: 2}}/> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography>{watch("road_patrol_machines_id.car_name")}</Typography> <Typography>{watch("road_patrol_machines_id.car_name")}</Typography>
</Box> </Box>
<Box sx={{display: "flex", alignItems: "center", my: 1}}> <Box sx={{ display: "flex", alignItems: "center", my: 1 }}>
<Typography>پلاک</Typography> <Typography>پلاک</Typography>
<Divider sx={{flex: 1, mx: 2}}/> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography>{watch("road_patrol_machines_id.plak_number")}</Typography> <Typography>{watch("road_patrol_machines_id.plak_number")}</Typography>
</Box> </Box>
</Grid> </Grid>
<Grid item xs={12} lg={6}> <Grid item xs={12} lg={6}>
<Divider><Chip label="راهدار / راهداران حاضر در گشت"/></Divider> <Divider>
<Chip label="راهدار / راهداران حاضر در گشت" />
</Divider>
{watch("road_patrol_rahdaran_id")?.map((rahdar, index) => ( {watch("road_patrol_rahdaran_id")?.map((rahdar, index) => (
<Box sx={{display: "flex", alignItems: "center", my: 1}}> <Box sx={{ display: "flex", alignItems: "center", my: 1 }}>
<Typography>نام و کد راهدار</Typography> <Typography>نام و کد راهدار</Typography>
<Divider sx={{flex: 1, mx: 2}}/> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography>{rahdar.name} | {rahdar.code}</Typography> <Typography>
{rahdar.name} | {rahdar.code}
</Typography>
</Box> </Box>
))} ))}
</Grid> </Grid>
</Grid> </Grid>
<Box sx={{display: "flex", gap: 2, my: 2, justifyContent: "space-around"}}> <Box sx={{ display: "flex", gap: 2, my: 2, justifyContent: "space-around" }}>
<Box sx={{display: "flex", alignItems: "center", gap: 2}}> <Box sx={{ display: "flex", alignItems: "center", gap: 2 }}>
<FormControl size="small" fullWidth variant="outlined"> <FormControl size="small" fullWidth variant="outlined">
<InputLabel htmlFor="phone_number">شماره تلفن مامور گشت</InputLabel> <InputLabel htmlFor="phone_number">شماره تلفن مامور گشت</InputLabel>
<OutlinedInput <OutlinedInput
@@ -160,14 +167,18 @@ const CompeleteRequest = ({watch, isSubmitting, setValue, register}) => {
onInput={handleNumericInput} onInput={handleNumericInput}
type="text" type="text"
inputProps={{ inputProps={{
maxLength: 11 maxLength: 11,
}} }}
/> />
</FormControl> </FormControl>
<Button onClick={sendOtp} disabled={!validPhone || delayPerRequest} variant="contained" <Button
color="success" onClick={sendOtp}
sx={{textWrap: "nowrap", px: 4}} disabled={!validPhone || delayPerRequest}
endIcon={<ForwardToInboxIcon/>}> variant="contained"
color="success"
sx={{ textWrap: "nowrap", px: 4 }}
endIcon={<ForwardToInboxIcon />}
>
{delayPerRequest ? formatCounter(counter) : "دریافت کد"} {delayPerRequest ? formatCounter(counter) : "دریافت کد"}
</Button> </Button>
</Box> </Box>
@@ -207,7 +218,7 @@ const CompeleteRequest = ({watch, isSubmitting, setValue, register}) => {
disabled={isSubmitting} disabled={isSubmitting}
type={"submit"} type={"submit"}
form="patrol_form" form="patrol_form"
endIcon={<BeenhereIcon/>} endIcon={<BeenhereIcon />}
> >
{isSubmitting ? "در حال ثبت فعالیت" : "ثبت فعالیت"} {isSubmitting ? "در حال ثبت فعالیت" : "ثبت فعالیت"}
</Button> </Button>
@@ -215,4 +226,4 @@ const CompeleteRequest = ({watch, isSubmitting, setValue, register}) => {
); );
}; };
export default CompeleteRequest; export default CompeleteRequest;

View File

@@ -1,18 +1,18 @@
"use client"; "use client";
import React, {useState} from "react"; import React, { useState } from "react";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import MapLoading from "@/core/components/MapLayer/Loading"; import MapLoading from "@/core/components/MapLayer/Loading";
import {Dialog, DialogTitle, IconButton} from "@mui/material"; import { Dialog, DialogTitle, IconButton } from "@mui/material";
import EditIcon from "@mui/icons-material/Edit"; import EditIcon from "@mui/icons-material/Edit";
import EditFormContent from "@/components/dashboard/roadItems/operator/RowActions/EditForm/EditFormContent"; import EditFormContent from "@/components/dashboard/roadItems/operator/RowActions/EditForm/EditFormContent";
const MapLayer = dynamic(() => import("@/core/components/MapLayer"), { const MapLayer = dynamic(() => import("@/core/components/MapLayer"), {
loading: () => <MapLoading/>, loading: () => <MapLoading />,
ssr: false, ssr: false,
}); });
const EditActionDuringPatrol = ({action, index, setActionsList}) => { const EditActionDuringPatrol = ({ action, index, setActionsList }) => {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const handleOpen = () => { const handleOpen = () => {
@@ -35,7 +35,7 @@ const EditActionDuringPatrol = ({action, index, setActionsList}) => {
return ( return (
<> <>
<IconButton aria-label="ویرایش فعالیت" color="primary" onClick={handleOpen}> <IconButton aria-label="ویرایش فعالیت" color="primary" onClick={handleOpen}>
<EditIcon/> <EditIcon />
</IconButton> </IconButton>
<Dialog <Dialog
maxWidth="sm" maxWidth="sm"
@@ -48,10 +48,10 @@ const EditActionDuringPatrol = ({action, index, setActionsList}) => {
}} }}
> >
<DialogTitle>ویرایش اطلاعات</DialogTitle> <DialogTitle>ویرایش اطلاعات</DialogTitle>
<EditFormContent setOpenEditDialog={setOpen} onSubmit={HandleSubmit} defaultData={action.data}/> <EditFormContent setOpenEditDialog={setOpen} onSubmit={HandleSubmit} defaultData={action.data} />
</Dialog> </Dialog>
</> </>
); );
}; };
export default EditActionDuringPatrol; export default EditActionDuringPatrol;

View File

@@ -1,17 +1,16 @@
import CreateFormContent from "@/components/dashboard/roadItems/operator/Actions/Create/Forms/CreateFormContent"; import CreateFormContent from "@/components/dashboard/roadItems/operator/Actions/Create/Forms/CreateFormContent";
import {Dialog} from "@mui/material"; import { Dialog } from "@mui/material";
const ModalActionsDuringPatrol = ({open, setOpen, setActionsList}) => {
const ModalActionsDuringPatrol = ({ open, setOpen, setActionsList }) => {
const HandleSubmit = async (data) => { const HandleSubmit = async (data) => {
setActionsList((prev) => [...prev, data]); setActionsList((prev) => [...prev, data]);
setOpen(false); setOpen(false);
} };
return ( return (
<Dialog open={open} fullWidth maxWidth="sm"> <Dialog open={open} fullWidth maxWidth="sm">
<CreateFormContent setOpen={setOpen} onSubmit={HandleSubmit} is_gasht={true}/> <CreateFormContent setOpen={setOpen} onSubmit={HandleSubmit} is_gasht={true} />
</Dialog> </Dialog>
); );
} };
export default ModalActionsDuringPatrol; export default ModalActionsDuringPatrol;

View File

@@ -1,30 +1,30 @@
"use client"; "use client";
import {Box, Button, Chip, Divider, IconButton, InputAdornment, Stack} from "@mui/material"; import { Box, Button, Chip, Divider, IconButton, InputAdornment, Stack } from "@mui/material";
import React, {useEffect, useState} from "react"; import React, { useEffect, useState } from "react";
import CarCode from "@/core/components/CarCode"; import CarCode from "@/core/components/CarCode";
import SearchIcon from '@mui/icons-material/Search'; import SearchIcon from "@mui/icons-material/Search";
import {AdapterDateFnsJalali} from "@mui/x-date-pickers/AdapterDateFnsJalali"; import { AdapterDateFnsJalali } from "@mui/x-date-pickers/AdapterDateFnsJalali";
import {faIR} from "@mui/x-date-pickers/locales"; import { faIR } from "@mui/x-date-pickers/locales";
import {LocalizationProvider, MobileDateTimePicker} from "@mui/x-date-pickers"; import { LocalizationProvider, MobileDateTimePicker } from "@mui/x-date-pickers";
import ClearIcon from "@mui/icons-material/Clear"; import ClearIcon from "@mui/icons-material/Clear";
import moment from "jalali-moment"; import moment from "jalali-moment";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import MapLoading from "@/core/components/MapLayer/Loading"; import MapLoading from "@/core/components/MapLayer/Loading";
import {Controller} from "react-hook-form"; import { Controller } from "react-hook-form";
import {GET_FMS_DATA} from "@/core/utils/routes"; import { GET_FMS_DATA } from "@/core/utils/routes";
import useRequest from "@/lib/hooks/useRequest"; import useRequest from "@/lib/hooks/useRequest";
import PatrolDetailInfo from "./PatrolDetailInfo"; import PatrolDetailInfo from "./PatrolDetailInfo";
import PatrolResultCodeErrors from "./PatrolResultCodeErrors"; import PatrolResultCodeErrors from "./PatrolResultCodeErrors";
const MapLayer = dynamic(() => import("@/core/components/MapLayer"), { const MapLayer = dynamic(() => import("@/core/components/MapLayer"), {
loading: () => <MapLoading/>, loading: () => <MapLoading />,
ssr: false, ssr: false,
}); });
const PatrolDetail = ({control, watch, setValue, tabState, setTabState}) => { const PatrolDetail = ({ control, watch, setValue, tabState, setTabState }) => {
const requestServer = useRequest({notificationSuccess: true}); const requestServer = useRequest({ notificationSuccess: true });
const [patrolResultStatus, setPatrolResultStatus] = useState(null) const [patrolResultStatus, setPatrolResultStatus] = useState(null);
const [readyToRequest, setReadyToRequest] = useState(false); const [readyToRequest, setReadyToRequest] = useState(false);
const [patrolData, setPatrolData] = useState(null); const [patrolData, setPatrolData] = useState(null);
@@ -35,18 +35,19 @@ const PatrolDetail = ({control, watch, setValue, tabState, setTabState}) => {
formData.append("endDT", moment(watch("end_time")).format("YYYY-MM-DDTHH:mm")); formData.append("endDT", moment(watch("end_time")).format("YYYY-MM-DDTHH:mm"));
await requestServer(GET_FMS_DATA, "post", { await requestServer(GET_FMS_DATA, "post", {
data: formData, data: formData,
}).then((response) => { })
const data = response.data.data; .then((response) => {
setPatrolData({ const data = response.data.data;
...data, setPatrolData({
roadPatrolMachinesId: watch("road_patrol_machines_id"), ...data,
start_time: watch("start_time"), roadPatrolMachinesId: watch("road_patrol_machines_id"),
end_time: watch("end_time") start_time: watch("start_time"),
}); end_time: watch("end_time"),
setPatrolResultStatus(data.resultCode); });
}).catch((error) => { setPatrolResultStatus(data.resultCode);
}); })
} .catch((error) => {});
};
useEffect(() => { useEffect(() => {
const roadPatrolMachinesId = watch("road_patrol_machines_id"); const roadPatrolMachinesId = watch("road_patrol_machines_id");
@@ -64,14 +65,14 @@ const PatrolDetail = ({control, watch, setValue, tabState, setTabState}) => {
flexDirection: "column", flexDirection: "column",
alignItems: "center", alignItems: "center",
justifyContent: "center", justifyContent: "center",
my: 3 my: 3,
}} }}
> >
<Box sx={{display: "flex", flexDirection: {xs: "column", lg: "row"}, gap: 2}}> <Box sx={{ display: "flex", flexDirection: { xs: "column", lg: "row" }, gap: 2 }}>
<Stack sx={{minWidth: "200px"}}> <Stack sx={{ minWidth: "200px" }}>
<Controller <Controller
control={control} control={control}
render={({field, fieldState: {error}}) => { render={({ field, fieldState: { error } }) => {
return ( return (
<CarCode <CarCode
carCode={field.value} carCode={field.value}
@@ -83,103 +84,120 @@ const PatrolDetail = ({control, watch, setValue, tabState, setTabState}) => {
name={"road_patrol_machines_id"} name={"road_patrol_machines_id"}
/> />
</Stack> </Stack>
<Box sx={{display: "flex", gap: 2}}> <Box sx={{ display: "flex", gap: 2 }}>
<LocalizationProvider <LocalizationProvider
dateAdapter={AdapterDateFnsJalali} dateAdapter={AdapterDateFnsJalali}
localeText={faIR.components.MuiLocalizationProvider.defaultProps.localeText} localeText={faIR.components.MuiLocalizationProvider.defaultProps.localeText}
> >
<MobileDateTimePicker value={watch("start_time") ? new Date(watch("start_time")) : null} <MobileDateTimePicker
ampm={false} value={watch("start_time") ? new Date(watch("start_time")) : null}
name="تاریخ و ساعت شروع گشت" ampm={false}
closeOnSelect name="تاریخ و ساعت شروع گشت"
maxDateTime={watch("end_time") ? new Date(watch("end_time")) : null} closeOnSelect
onChange={(start_time) => { maxDateTime={watch("end_time") ? new Date(watch("end_time")) : null}
const date = new Date(start_time); onChange={(start_time) => {
const formattedDate = moment(date).locale("en").format("YYYY-MM-DD HH:mm"); const date = new Date(start_time);
setValue("start_time", formattedDate); const formattedDate = moment(date).locale("en").format("YYYY-MM-DD HH:mm");
}} setValue("start_time", formattedDate);
slotProps={{ }}
textField: { slotProps={{
size: "small", textField: {
placeholder: "تاریخ و ساعت شروع گشت", size: "small",
InputProps: { placeholder: "تاریخ و ساعت شروع گشت",
endAdornment: ( InputProps: {
<InputAdornment position="end"> endAdornment: (
<IconButton <InputAdornment position="end">
size="small" <IconButton
onClick={(event) => { size="small"
event.stopPropagation(); onClick={(event) => {
setValue("start_time", ""); event.stopPropagation();
}} setValue("start_time", "");
sx={{ }}
color: "#bfbfbf", sx={{
"&:hover": { color: "#bfbfbf",
backgroundColor: "rgba(189, 189, 189, 0.1)", "&:hover": {
color: "#363434", backgroundColor: "rgba(189, 189, 189, 0.1)",
}, color: "#363434",
}} },
> }}
<ClearIcon/> >
</IconButton> <ClearIcon />
</InputAdornment> </IconButton>
), </InputAdornment>
}, ),
}, },
}} label="تاریخ و ساعت شروع گشت" },
}}
label="تاریخ و ساعت شروع گشت"
/>
<MobileDateTimePicker
value={watch("end_time") ? new Date(watch("end_time")) : null}
ampm={false}
name="تاریخ و ساعت پایان گشت"
closeOnSelect
minDateTime={watch("start_time") ? new Date(watch("start_time")) : null}
onChange={(end_time) => {
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: (
<InputAdornment position="end">
<IconButton
size="small"
onClick={(event) => {
event.stopPropagation();
setValue("end_time", "");
}}
sx={{
color: "#bfbfbf",
"&:hover": {
backgroundColor: "rgba(189, 189, 189, 0.1)",
color: "#363434",
},
}}
>
<ClearIcon />
</IconButton>
</InputAdornment>
),
},
},
}}
label="تاریخ و ساعت پایان گشت"
/> />
<MobileDateTimePicker value={watch("end_time") ? new Date(watch("end_time")) : null}
ampm={false}
name="تاریخ و ساعت پایان گشت"
closeOnSelect
minDateTime={watch("start_time") ? new Date(watch("start_time")) : null}
onChange={(end_time) => {
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: (
<InputAdornment position="end">
<IconButton
size="small"
onClick={(event) => {
event.stopPropagation();
setValue("end_time", "");
}}
sx={{
color: "#bfbfbf",
"&:hover": {
backgroundColor: "rgba(189, 189, 189, 0.1)",
color: "#363434",
},
}}
>
<ClearIcon/>
</IconButton>
</InputAdornment>
),
},
},
}} label="تاریخ و ساعت پایان گشت"/>
</LocalizationProvider> </LocalizationProvider>
</Box> </Box>
<Button variant="contained" onClick={requestPatrolInfo} color="success" disabled={!readyToRequest} <Button
endIcon={<SearchIcon/>}>درخواست variant="contained"
اطلاعات</Button> onClick={requestPatrolInfo}
color="success"
disabled={!readyToRequest}
endIcon={<SearchIcon />}
>
درخواست اطلاعات
</Button>
</Box> </Box>
<Divider sx={{my: 2, width: "100%"}}> <Divider sx={{ my: 2, width: "100%" }}>
<Chip color="success" label="مشخصات گشت"/> <Chip color="success" label="مشخصات گشت" />
</Divider> </Divider>
{patrolResultStatus === 0 ? {patrolResultStatus === 0 ? (
<PatrolDetailInfo patrolData={patrolData} tabState={tabState} setTabState={setTabState} <PatrolDetailInfo
setValue={setValue}/> : patrolData={patrolData}
<PatrolResultCodeErrors ResultCode={patrolResultStatus}/>} tabState={tabState}
setTabState={setTabState}
setValue={setValue}
/>
) : (
<PatrolResultCodeErrors ResultCode={patrolResultStatus} />
)}
</Box> </Box>
); );
}; };
export default PatrolDetail; export default PatrolDetail;

View File

@@ -1,35 +1,33 @@
"use client"; "use client";
import {Box, Button, Card, CardActions, CardContent, Chip, Divider, Slide, Stack, Typography} from "@mui/material"; import { Box, Button, Card, CardActions, CardContent, Chip, Divider, Slide, Stack, Typography } from "@mui/material";
import React, {useEffect} from "react"; import React, { useEffect } from "react";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import MapLoading from "@/core/components/MapLayer/Loading"; import MapLoading from "@/core/components/MapLayer/Loading";
import LocalGasStationIcon from '@mui/icons-material/LocalGasStation'; import LocalGasStationIcon from "@mui/icons-material/LocalGasStation";
import DirectionsCarFilledIcon from '@mui/icons-material/DirectionsCarFilled'; import DirectionsCarFilledIcon from "@mui/icons-material/DirectionsCarFilled";
import WatchLaterIcon from '@mui/icons-material/WatchLater'; import WatchLaterIcon from "@mui/icons-material/WatchLater";
import QueryBuilderIcon from '@mui/icons-material/QueryBuilder'; import QueryBuilderIcon from "@mui/icons-material/QueryBuilder";
import AddRoadIcon from '@mui/icons-material/AddRoad'; import AddRoadIcon from "@mui/icons-material/AddRoad";
import ShareLocationIcon from '@mui/icons-material/ShareLocation'; import ShareLocationIcon from "@mui/icons-material/ShareLocation";
import ElectricCarIcon from '@mui/icons-material/ElectricCar'; import ElectricCarIcon from "@mui/icons-material/ElectricCar";
import KeyboardDoubleArrowLeftIcon from "@mui/icons-material/KeyboardDoubleArrowLeft"; import KeyboardDoubleArrowLeftIcon from "@mui/icons-material/KeyboardDoubleArrowLeft";
import QrCode2Icon from '@mui/icons-material/QrCode2'; import QrCode2Icon from "@mui/icons-material/QrCode2";
import moment from "jalali-moment"; import moment from "jalali-moment";
import PatrolMapFeatures from "./PatrolMapFeatures"; import PatrolMapFeatures from "./PatrolMapFeatures";
import {useMap} from "react-leaflet"; import { useMap } from "react-leaflet";
const MapLayer = dynamic(() => import("@/core/components/MapLayer"), { const MapLayer = dynamic(() => import("@/core/components/MapLayer"), {
loading: () => <MapLoading/>, loading: () => <MapLoading />,
ssr: false, ssr: false,
}); });
const MapItemViewBound = ({patrolData, bound}) => { const MapItemViewBound = ({ patrolData, bound }) => {
const map = useMap(); const map = useMap();
useEffect(() => { useEffect(() => {
if (bound.length !== 0) { if (bound.length !== 0) {
map.fitBounds(bound, map.fitBounds(bound, { paddingTopLeft: [16, 16], paddingBottomRight: [16, 130] });
{paddingTopLeft: [16, 16], paddingBottomRight: [16, 130]}
);
} }
}, [bound]); }, [bound]);
@@ -37,102 +35,103 @@ const MapItemViewBound = ({patrolData, bound}) => {
<> <>
{patrolData.stopPoints.map((stopPoint, index) => ( {patrolData.stopPoints.map((stopPoint, index) => (
<React.Fragment key={index}> <React.Fragment key={index}>
<PatrolMapFeatures stopPoint={stopPoint}/> <PatrolMapFeatures stopPoint={stopPoint} />
</React.Fragment> </React.Fragment>
))} ))}
</> </>
); );
}; };
const PatrolDetailInfo = ({patrolData, tabState, setTabState, setValue}) => { const PatrolDetailInfo = ({ patrolData, tabState, setTabState, setValue }) => {
const bound = patrolData.stopPoints.map(point => [point.latitude, point.longitude]); const bound = patrolData.stopPoints.map((point) => [point.latitude, point.longitude]);
const SendPatrolInfo = () => { const SendPatrolInfo = () => {
setValue("vehicle_runtime", patrolData.accOnDuration) setValue("vehicle_runtime", patrolData.accOnDuration);
setValue("fuel_consumption", patrolData.fuelConsumption) setValue("fuel_consumption", patrolData.fuelConsumption);
setValue("distance", patrolData.mileage) setValue("distance", patrolData.mileage);
setValue("stop_points", patrolData.stopPoints) setValue("stop_points", patrolData.stopPoints);
setTabState(tabState + 1) setTabState(tabState + 1);
} };
return ( return (
<Slide in={true} sx={{width: "100%"}}> <Slide in={true} sx={{ width: "100%" }}>
<Card> <Card>
<CardContent <CardContent
sx={{ sx={{
display: "flex", display: "flex",
flexDirection: {xs: "column", lg: "row"}, flexDirection: { xs: "column", lg: "row" },
alignItems: "center", alignItems: "center",
justifyContent: "space-between", justifyContent: "space-between",
gap: {xs: 2, lg: 0}, gap: { xs: 2, lg: 0 },
}}> }}
<Stack sx={{minWidth: {xs: "100%", lg: "300px"}, gap: 2}}> >
<Box sx={{display: "flex", alignItems: "center", justifyContent: "space-between"}}> <Stack sx={{ minWidth: { xs: "100%", lg: "300px" }, gap: 2 }}>
<Chip size="small" label="مدت زمان روشن بودن خودرو" icon={<ElectricCarIcon/>}/> <Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<Divider sx={{flex: 1, mx: 2}}/> <Chip size="small" label="مدت زمان روشن بودن خودرو" icon={<ElectricCarIcon />} />
<Typography sx={{fontSize: "13px", fontWeight: 400}}> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography sx={{ fontSize: "13px", fontWeight: 400 }}>
{Math.floor(patrolData.accOnDuration / 60)} دقیقه {Math.floor(patrolData.accOnDuration / 60)} دقیقه
</Typography> </Typography>
</Box> </Box>
<Box sx={{display: "flex", alignItems: "center", justifyContent: "space-between"}}> <Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<Chip size="small" label="نام خودرو" icon={<DirectionsCarFilledIcon/>}/> <Chip size="small" label="نام خودرو" icon={<DirectionsCarFilledIcon />} />
<Divider sx={{flex: 1, mx: 2}}/> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography sx={{fontSize: "13px", fontWeight: 400}}> <Typography sx={{ fontSize: "13px", fontWeight: 400 }}>
{patrolData.roadPatrolMachinesId.car_name} {patrolData.roadPatrolMachinesId.car_name}
</Typography> </Typography>
</Box> </Box>
<Box sx={{display: "flex", alignItems: "center", justifyContent: "space-between"}}> <Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<Chip size="small" label="کد خودرو" icon={<QrCode2Icon/>}/> <Chip size="small" label="کد خودرو" icon={<QrCode2Icon />} />
<Divider sx={{flex: 1, mx: 2}}/> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography sx={{fontSize: "13px", fontWeight: 400}}> <Typography sx={{ fontSize: "13px", fontWeight: 400 }}>
{patrolData.roadPatrolMachinesId.machine_code} {patrolData.roadPatrolMachinesId.machine_code}
</Typography> </Typography>
</Box> </Box>
<Box sx={{display: "flex", alignItems: "center", justifyContent: "space-between"}}> <Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<Chip size="small" label="پلاک خودرو" icon={<DirectionsCarFilledIcon/>}/> <Chip size="small" label="پلاک خودرو" icon={<DirectionsCarFilledIcon />} />
<Divider sx={{flex: 1, mx: 2}}/> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography sx={{fontSize: "13px", fontWeight: 400}}> <Typography sx={{ fontSize: "13px", fontWeight: 400 }}>
{patrolData.roadPatrolMachinesId.plak_number} {patrolData.roadPatrolMachinesId.plak_number}
</Typography> </Typography>
</Box> </Box>
<Box sx={{display: "flex", alignItems: "center", justifyContent: "space-between"}}> <Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<Chip size="small" label="زمان شروع گشت" icon={<QueryBuilderIcon/>}/> <Chip size="small" label="زمان شروع گشت" icon={<QueryBuilderIcon />} />
<Divider sx={{flex: 1, mx: 2}}/> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography sx={{fontSize: "13px", fontWeight: 400}}> <Typography sx={{ fontSize: "13px", fontWeight: 400 }}>
{moment(patrolData.start_time).locale("fa").format("HH:mm | YYYY/MM/DD")} {moment(patrolData.start_time).locale("fa").format("HH:mm | YYYY/MM/DD")}
</Typography> </Typography>
</Box> </Box>
<Box sx={{display: "flex", alignItems: "center", justifyContent: "space-between"}}> <Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<Chip size="small" label="زمان پایان گشت" icon={<WatchLaterIcon/>}/> <Chip size="small" label="زمان پایان گشت" icon={<WatchLaterIcon />} />
<Divider sx={{flex: 1, mx: 2}}/> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography sx={{fontSize: "13px", fontWeight: 400}}> <Typography sx={{ fontSize: "13px", fontWeight: 400 }}>
{moment(patrolData.end_time).locale("fa").format("HH:mm | YYYY/MM/DD")} {moment(patrolData.end_time).locale("fa").format("HH:mm | YYYY/MM/DD")}
</Typography> </Typography>
</Box> </Box>
<Box sx={{display: "flex", alignItems: "center", justifyContent: "space-between"}}> <Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<Chip size="small" label="مسافت" icon={<AddRoadIcon/>}/> <Chip size="small" label="مسافت" icon={<AddRoadIcon />} />
<Divider sx={{flex: 1, mx: 2}}/> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography sx={{fontSize: "13px", fontWeight: 400}}> <Typography sx={{ fontSize: "13px", fontWeight: 400 }}>
{(patrolData.mileage / 1000).toFixed(1)} کیلومتر {(patrolData.mileage / 1000).toFixed(1)} کیلومتر
</Typography> </Typography>
</Box> </Box>
<Box sx={{display: "flex", alignItems: "center", justifyContent: "space-between"}}> <Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<Chip size="small" label="میزان مصرف سوخت" icon={<LocalGasStationIcon/>}/> <Chip size="small" label="میزان مصرف سوخت" icon={<LocalGasStationIcon />} />
<Divider sx={{flex: 1, mx: 2}}/> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography sx={{fontSize: "13px", fontWeight: 400}}> <Typography sx={{ fontSize: "13px", fontWeight: 400 }}>
{Math.round(patrolData.fuelConsumption * 10) / 10} لیتر {Math.round(patrolData.fuelConsumption * 10) / 10} لیتر
</Typography> </Typography>
</Box> </Box>
<Box sx={{display: "flex", alignItems: "center", justifyContent: "space-between"}}> <Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
<Chip size="small" label="تعداد توقف در مسیر" icon={<ShareLocationIcon/>}/> <Chip size="small" label="تعداد توقف در مسیر" icon={<ShareLocationIcon />} />
<Divider sx={{flex: 1, mx: 2}}/> <Divider sx={{ flex: 1, mx: 2 }} />
<Typography sx={{fontSize: "13px", fontWeight: 400}}> <Typography sx={{ fontSize: "13px", fontWeight: 400 }}>
{patrolData.stopPoints.length} مورد {patrolData.stopPoints.length} مورد
</Typography> </Typography>
</Box> </Box>
</Stack> </Stack>
<Divider orientation="vertical" flexItem/> <Divider orientation="vertical" flexItem />
<Stack spacing={1} sx={{height: "300px", width: {xs: "100%", lg: "350px"}}}> <Stack spacing={1} sx={{ height: "300px", width: { xs: "100%", lg: "350px" } }}>
<Box <Box
sx={{ sx={{
p: 1, p: 1,
@@ -151,16 +150,21 @@ const PatrolDetailInfo = ({patrolData, tabState, setTabState, setValue}) => {
}} }}
> >
<MapLayer position={bound}> <MapLayer position={bound}>
<MapItemViewBound patrolData={patrolData} bound={bound}/> <MapItemViewBound patrolData={patrolData} bound={bound} />
</MapLayer> </MapLayer>
</Box> </Box>
</Box> </Box>
</Stack> </Stack>
</CardContent> </CardContent>
<CardActions sx={{alignItems: "center", justifyContent: "center"}}> <CardActions sx={{ alignItems: "center", justifyContent: "center" }}>
<Box sx={{display: "flex", gap: 1}}> <Box sx={{ display: "flex", gap: 1 }}>
<Button variant="contained" color="primary" onClick={SendPatrolInfo} <Button
endIcon={<KeyboardDoubleArrowLeftIcon/>} sx={{mt: 2}}> variant="contained"
color="primary"
onClick={SendPatrolInfo}
endIcon={<KeyboardDoubleArrowLeftIcon />}
sx={{ mt: 2 }}
>
تایید اطلاعات و رفتن به مرحله بعد تایید اطلاعات و رفتن به مرحله بعد
</Button> </Button>
</Box> </Box>
@@ -170,4 +174,4 @@ const PatrolDetailInfo = ({patrolData, tabState, setTabState, setValue}) => {
); );
}; };
export default PatrolDetailInfo; export default PatrolDetailInfo;

View File

@@ -1,23 +1,23 @@
"use client"; "use client";
import {Box, DialogContent, Tab, Tabs, useMediaQuery} from "@mui/material"; import { Box, DialogContent, Tab, Tabs, useMediaQuery } from "@mui/material";
import {useTheme} from "@emotion/react"; import { useTheme } from "@emotion/react";
import React, {useEffect, useState} from "react"; import React, { useEffect, useState } from "react";
import TaxiAlertIcon from '@mui/icons-material/TaxiAlert'; import TaxiAlertIcon from "@mui/icons-material/TaxiAlert";
import EngineeringIcon from '@mui/icons-material/Engineering'; import EngineeringIcon from "@mui/icons-material/Engineering";
import HandymanIcon from '@mui/icons-material/Handyman'; import HandymanIcon from "@mui/icons-material/Handyman";
import VerifiedIcon from '@mui/icons-material/Verified'; import VerifiedIcon from "@mui/icons-material/Verified";
import PatrolTimeLine from "./PatrolTimeLine"; import PatrolTimeLine from "./PatrolTimeLine";
import PatrolDetail from "./PatrolDetail"; import PatrolDetail from "./PatrolDetail";
import SuperVisorsDetail from "./SuperVisorsDetail"; import SuperVisorsDetail from "./SuperVisorsDetail";
import ActionsDuringPatrol from "./ActionsDurigPatrol"; import ActionsDuringPatrol from "./ActionsDurigPatrol";
import {useForm} from "react-hook-form"; import { useForm } from "react-hook-form";
import StyledForm from "@/core/components/StyledForm"; import StyledForm from "@/core/components/StyledForm";
import useRequest from "@/lib/hooks/useRequest"; import useRequest from "@/lib/hooks/useRequest";
import CompeleteRequest from "./CompeleteRequest"; import CompeleteRequest from "./CompeleteRequest";
function TabPanel(props) { function TabPanel(props) {
const {children, value, index} = props; const { children, value, index } = props;
return ( return (
<div role="tabpanel" hidden={value !== index}> <div role="tabpanel" hidden={value !== index}>
@@ -37,11 +37,11 @@ const defaultValues = {
distance: "", distance: "",
observed_items: null, observed_items: null,
phone_number: "", phone_number: "",
otp_token: "" otp_token: "",
}; };
const PatrolForms = ({mutate, setOpen}) => { const PatrolForms = ({ mutate, setOpen }) => {
const requestServer = useRequest({notificationSuccess: true}); const requestServer = useRequest({ notificationSuccess: true });
const theme = useTheme(); const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down("md")); const isMobile = useMediaQuery(theme.breakpoints.down("md"));
const [tabState, setTabState] = useState(0); const [tabState, setTabState] = useState(0);
@@ -65,14 +65,14 @@ const PatrolForms = ({mutate, setOpen}) => {
handleSubmit, handleSubmit,
setValue, setValue,
resetField, resetField,
formState: {isSubmitting}, formState: { isSubmitting },
} = useForm({ } = useForm({
defaultValues, defaultValues,
mode: "onBlur" mode: "onBlur",
}); });
const onSubmit = async (data) => { const onSubmit = async (data) => {
console.log("data", data) console.log("data", data);
// const formData = new FormData(); // const formData = new FormData();
// data.road_patrol_rahdaran_id.forEach((rahdar, index) => formData.append(`road_patrol_rahdaran_id[${index}]`, rahdar.id)); // 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) // formData.append(`road_patrol_machines_id[0]`, data.road_patrol_machines_id.id)
@@ -109,7 +109,6 @@ const PatrolForms = ({mutate, setOpen}) => {
// } else { // } else {
// console.log("error phone number") // console.log("error phone number")
// } // }
}; };
return ( return (
@@ -126,13 +125,13 @@ const PatrolForms = ({mutate, setOpen}) => {
backgroundColor: "#efefef", backgroundColor: "#efefef",
}} }}
> >
<Tab disabled={!(activeUpTo >= 0)} icon={<TaxiAlertIcon/>} label="مشخصات گشت"></Tab> <Tab disabled={!(activeUpTo >= 0)} icon={<TaxiAlertIcon />} label="مشخصات گشت"></Tab>
<Tab disabled={!(activeUpTo >= 1)} icon={<EngineeringIcon/>} label="مشخصات راهداران"></Tab> <Tab disabled={!(activeUpTo >= 1)} icon={<EngineeringIcon />} label="مشخصات راهداران"></Tab>
<Tab disabled={!(activeUpTo >= 2)} icon={<HandymanIcon/>} label="اقدامات حین گشت"></Tab> <Tab disabled={!(activeUpTo >= 2)} icon={<HandymanIcon />} label="اقدامات حین گشت"></Tab>
<Tab disabled={!(activeUpTo >= 3)} icon={<VerifiedIcon/>} label="تکمیل درخواست"></Tab> <Tab disabled={!(activeUpTo >= 3)} icon={<VerifiedIcon />} label="تکمیل درخواست"></Tab>
</Tabs> </Tabs>
<DialogContent dividers sx={{display: "flex"}}> <DialogContent dividers sx={{ display: "flex" }}>
<Box sx={{flex: 1}}> <Box sx={{ flex: 1 }}>
<TabPanel value={tabState} index={0}> <TabPanel value={tabState} index={0}>
<PatrolDetail <PatrolDetail
control={control} control={control}
@@ -148,7 +147,8 @@ const PatrolForms = ({mutate, setOpen}) => {
setValue={setValue} setValue={setValue}
watch={watch} watch={watch}
tabState={tabState} tabState={tabState}
setTabState={setTabState}/> setTabState={setTabState}
/>
</TabPanel> </TabPanel>
<TabPanel value={tabState} index={2}> <TabPanel value={tabState} index={2}>
<ActionsDuringPatrol <ActionsDuringPatrol
@@ -168,8 +168,8 @@ const PatrolForms = ({mutate, setOpen}) => {
</TabPanel> </TabPanel>
</Box> </Box>
{!isMobile && ( {!isMobile && (
<Box sx={{display: "flex", alignItems: "center"}}> <Box sx={{ display: "flex", alignItems: "center" }}>
<PatrolTimeLine tabState={tabState}/> <PatrolTimeLine tabState={tabState} />
</Box> </Box>
)} )}
</DialogContent> </DialogContent>

View File

@@ -1,11 +1,11 @@
"use client"; "use client";
import {Typography} from "@mui/material"; import { Typography } from "@mui/material";
import React, {useRef} from "react"; import React, { useRef } from "react";
import {Marker, Popup} from "react-leaflet"; import { Marker, Popup } from "react-leaflet";
import AzmayeshIcon from "@/assets/images/examine_marker.png"; import AzmayeshIcon from "@/assets/images/examine_marker.png";
const PatrolMapFeatures = ({stopPoint}) => { const PatrolMapFeatures = ({ stopPoint }) => {
const position = [stopPoint.latitude, stopPoint.longitude]; const position = [stopPoint.latitude, stopPoint.longitude];
const mapPatrolMarker = useRef(); const mapPatrolMarker = useRef();
const createCustomIcon = (size, iconUrl) => { const createCustomIcon = (size, iconUrl) => {
@@ -18,21 +18,21 @@ const PatrolMapFeatures = ({stopPoint}) => {
}; };
return ( return (
<Marker ref={mapPatrolMarker} <Marker
icon={L.icon({ ref={mapPatrolMarker}
iconUrl: AzmayeshIcon.src, icon={L.icon({
iconSize: [35, 35], iconUrl: AzmayeshIcon.src,
iconAnchor: [35 / 2, 35], iconSize: [35, 35],
popupAnchor: [0, -35], iconAnchor: [35 / 2, 35],
})} popupAnchor: [0, -35],
position={position} })}
position={position}
> >
<Popup> <Popup>
<Typography variant="button">مدت زمان <Typography variant="button">مدت زمان توقف: {stopPoint.duration} ثانیه</Typography>
توقف: {stopPoint.duration} ثانیه</Typography>
</Popup> </Popup>
</Marker> </Marker>
); );
}; };
export default PatrolMapFeatures; export default PatrolMapFeatures;

View File

@@ -1,9 +1,9 @@
"use client"; "use client";
import {Box, Typography} from "@mui/material"; import { Box, Typography } from "@mui/material";
import React from "react"; import React from "react";
const PatrolResultCodeErrors = ({ResultCode}) => { const PatrolResultCodeErrors = ({ ResultCode }) => {
const errorMessages = { const errorMessages = {
[-1]: "نام کاربری یا کلمه عبور صحیح نمیباشد", [-1]: "نام کاربری یا کلمه عبور صحیح نمیباشد",
[-2]: "ردیاب به خودرو انتخابی متصل نیست", [-2]: "ردیاب به خودرو انتخابی متصل نیست",
@@ -14,12 +14,12 @@ const PatrolResultCodeErrors = ({ResultCode}) => {
const message = errorMessages[ResultCode] || "ابتدا اطلاعات بالا را تکمیل نمایید"; const message = errorMessages[ResultCode] || "ابتدا اطلاعات بالا را تکمیل نمایید";
return ( return (
<Box sx={{my: 5}}> <Box sx={{ my: 5 }}>
<Typography variant="h6" sx={{letterSpacing: "2px", color: ResultCode ? "error.main" : "#606060"}}> <Typography variant="h6" sx={{ letterSpacing: "2px", color: ResultCode ? "error.main" : "#606060" }}>
{message} {message}
</Typography> </Typography>
</Box> </Box>
); );
}; };
export default PatrolResultCodeErrors; export default PatrolResultCodeErrors;

View File

@@ -1,10 +1,10 @@
"use client"; "use client";
import {Box, CircularProgress, Typography} from "@mui/material"; import { Box, CircularProgress, Typography } from "@mui/material";
import TaxiAlertIcon from '@mui/icons-material/TaxiAlert'; import TaxiAlertIcon from "@mui/icons-material/TaxiAlert";
import EngineeringIcon from '@mui/icons-material/Engineering'; import EngineeringIcon from "@mui/icons-material/Engineering";
import HandymanIcon from '@mui/icons-material/Handyman'; import HandymanIcon from "@mui/icons-material/Handyman";
import VerifiedIcon from '@mui/icons-material/Verified'; import VerifiedIcon from "@mui/icons-material/Verified";
import { import {
Timeline, Timeline,
TimelineConnector, TimelineConnector,
@@ -15,83 +15,99 @@ import {
TimelineSeparator, TimelineSeparator,
} from "@mui/lab"; } from "@mui/lab";
const PatrolTimeLine = ({tabState}) => { const PatrolTimeLine = ({ tabState }) => {
return ( return (
<Box sx={{display: "flex", alignItems: "center"}}> <Box sx={{ display: "flex", alignItems: "center" }}>
<Timeline <Timeline
position="right" position="right"
sx={{ sx={{
[`& .${timelineItemClasses.root}:before`]: {flex: 0, padding: 0}, [`& .${timelineItemClasses.root}:before`]: { flex: 0, padding: 0 },
}} }}
> >
<TimelineItem> <TimelineItem>
<TimelineSeparator> <TimelineSeparator>
<TimelineConnector/> <TimelineConnector />
<TimelineDot sx={{backgroundColor: "#fff"}}> <TimelineDot sx={{ backgroundColor: "#fff" }}>
{tabState === 0 ? <CircularProgress size="23px"/> : <TaxiAlertIcon {tabState === 0 ? (
color={tabState > 0 ? "success" : "error"} <CircularProgress size="23px" />
sx={{width: "1.5rem", height: "1.5rem"}} ) : (
/>} <TaxiAlertIcon
color={tabState > 0 ? "success" : "error"}
sx={{ width: "1.5rem", height: "1.5rem" }}
/>
)}
</TimelineDot> </TimelineDot>
<TimelineConnector/> <TimelineConnector />
</TimelineSeparator> </TimelineSeparator>
<TimelineContent sx={{py: "12px", px: 2}}> <TimelineContent sx={{ py: "12px", px: 2 }}>
<Typography variant="h6">مشخصات گشت</Typography> <Typography variant="h6">مشخصات گشت</Typography>
<Typography variant="caption" sx={{color: "#606060"}}> <Typography variant="caption" sx={{ color: "#606060" }}>
تایید اطلاعات اولیه گشت تایید اطلاعات اولیه گشت
</Typography> </Typography>
</TimelineContent> </TimelineContent>
</TimelineItem> </TimelineItem>
<TimelineItem> <TimelineItem>
<TimelineSeparator> <TimelineSeparator>
<TimelineConnector/> <TimelineConnector />
<TimelineDot sx={{backgroundColor: "#fff"}}> <TimelineDot sx={{ backgroundColor: "#fff" }}>
{tabState === 1 ? <CircularProgress size="23px"/> : <EngineeringIcon {tabState === 1 ? (
color={tabState > 1 ? "success" : "error"} <CircularProgress size="23px" />
sx={{width: "1.5rem", height: "1.5rem"}} ) : (
/>} <EngineeringIcon
color={tabState > 1 ? "success" : "error"}
sx={{ width: "1.5rem", height: "1.5rem" }}
/>
)}
</TimelineDot> </TimelineDot>
<TimelineConnector/> <TimelineConnector />
</TimelineSeparator> </TimelineSeparator>
<TimelineContent sx={{py: "12px", px: 2}}> <TimelineContent sx={{ py: "12px", px: 2 }}>
<Typography variant="h6">مشخصات راهداران</Typography> <Typography variant="h6">مشخصات راهداران</Typography>
<Typography variant="caption" sx={{color: "#606060"}}> <Typography variant="caption" sx={{ color: "#606060" }}>
راهدار / راهداران حاضر در گشت راهدار / راهداران حاضر در گشت
</Typography> </Typography>
</TimelineContent> </TimelineContent>
</TimelineItem> </TimelineItem>
<TimelineItem> <TimelineItem>
<TimelineSeparator> <TimelineSeparator>
<TimelineConnector/> <TimelineConnector />
<TimelineDot sx={{backgroundColor: "#fff"}}> <TimelineDot sx={{ backgroundColor: "#fff" }}>
{tabState === 2 ? <CircularProgress size="23px"/> : <HandymanIcon {tabState === 2 ? (
color={tabState > 2 ? "success" : "error"} <CircularProgress size="23px" />
sx={{width: "1.5rem", height: "1.5rem"}} ) : (
/>} <HandymanIcon
color={tabState > 2 ? "success" : "error"}
sx={{ width: "1.5rem", height: "1.5rem" }}
/>
)}
</TimelineDot> </TimelineDot>
<TimelineConnector/> <TimelineConnector />
</TimelineSeparator> </TimelineSeparator>
<TimelineContent sx={{py: "12px", px: 2}}> <TimelineContent sx={{ py: "12px", px: 2 }}>
<Typography variant="h6">اقدامات حین گشت</Typography> <Typography variant="h6">اقدامات حین گشت</Typography>
<Typography variant="caption" sx={{color: "#606060"}}> <Typography variant="caption" sx={{ color: "#606060" }}>
ثبت فعالیت های صورت گرفته حین گشت ثبت فعالیت های صورت گرفته حین گشت
</Typography> </Typography>
</TimelineContent> </TimelineContent>
</TimelineItem> </TimelineItem>
<TimelineItem> <TimelineItem>
<TimelineSeparator> <TimelineSeparator>
<TimelineConnector/> <TimelineConnector />
<TimelineDot sx={{backgroundColor: "#fff"}}> <TimelineDot sx={{ backgroundColor: "#fff" }}>
{tabState === 3 ? <CircularProgress size="23px"/> : <VerifiedIcon {tabState === 3 ? (
color={tabState > 3 ? "success" : "error"} <CircularProgress size="23px" />
sx={{width: "1.5rem", height: "1.5rem"}} ) : (
/>} <VerifiedIcon
color={tabState > 3 ? "success" : "error"}
sx={{ width: "1.5rem", height: "1.5rem" }}
/>
)}
</TimelineDot> </TimelineDot>
<TimelineConnector/> <TimelineConnector />
</TimelineSeparator> </TimelineSeparator>
<TimelineContent sx={{py: "12px", px: 2}}> <TimelineContent sx={{ py: "12px", px: 2 }}>
<Typography variant="h6">تکمیل درخواست</Typography> <Typography variant="h6">تکمیل درخواست</Typography>
<Typography variant="caption" sx={{color: "#606060"}}> <Typography variant="caption" sx={{ color: "#606060" }}>
تکمیل درخواست و ثبت نهایی تکمیل درخواست و ثبت نهایی
</Typography> </Typography>
</TimelineContent> </TimelineContent>

View File

@@ -1,14 +1,14 @@
"use client"; "use client";
import {Box, Button, FormControl, InputLabel, OutlinedInput} from "@mui/material"; import { Box, Button, FormControl, InputLabel, OutlinedInput } from "@mui/material";
import React, {useEffect, useState} from "react"; import React, { useEffect, useState } from "react";
import ForwardToInboxIcon from '@mui/icons-material/ForwardToInbox'; import ForwardToInboxIcon from "@mui/icons-material/ForwardToInbox";
import useRequest from "@/lib/hooks/useRequest"; import useRequest from "@/lib/hooks/useRequest";
import {GET_OTP_TOKEN, VERIFY_OTP} from "@/core/utils/routes"; import { GET_OTP_TOKEN, VERIFY_OTP } from "@/core/utils/routes";
import {formatCounter} from "@/core/utils/formatCounter"; import { formatCounter } from "@/core/utils/formatCounter";
const PhoneValidation = ({tabState, setTabState}) => { const PhoneValidation = ({ tabState, setTabState }) => {
const requestServer = useRequest({auth: true}); const requestServer = useRequest({ auth: true });
const [phoneNumber, setPhoneNumber] = useState(""); const [phoneNumber, setPhoneNumber] = useState("");
const [verificationCode, setVerificationCode] = useState(""); const [verificationCode, setVerificationCode] = useState("");
const [validPhone, setValidPhone] = useState(false); const [validPhone, setValidPhone] = useState(false);
@@ -18,7 +18,7 @@ const PhoneValidation = ({tabState, setTabState}) => {
const [readyToVerify, setReadyToVerify] = useState(false); const [readyToVerify, setReadyToVerify] = useState(false);
const handleNumericInput = (e) => { const handleNumericInput = (e) => {
e.target.value = e.target.value.replace(/[^0-9]/g, ''); e.target.value = e.target.value.replace(/[^0-9]/g, "");
}; };
useEffect(() => { useEffect(() => {
@@ -41,7 +41,7 @@ const PhoneValidation = ({tabState, setTabState}) => {
} }
if (delayPerRequest && counter > 0) { if (delayPerRequest && counter > 0) {
const timer = setInterval(() => { const timer = setInterval(() => {
setCounter(prevCounter => prevCounter - 1); setCounter((prevCounter) => prevCounter - 1);
}, 1000); }, 1000);
return () => clearInterval(timer); return () => clearInterval(timer);
@@ -51,10 +51,8 @@ const PhoneValidation = ({tabState, setTabState}) => {
const sendOtp = () => { const sendOtp = () => {
if (!validPhone) return false; if (!validPhone) return false;
requestServer(`${GET_OTP_TOKEN}?phone_number=${phoneNumber}`, "get") requestServer(`${GET_OTP_TOKEN}?phone_number=${phoneNumber}`, "get")
.then((response) => { .then((response) => {})
}) .catch(() => {});
.catch(() => {
});
//////////**** (mohammad) this part should keep in success but for now we go next level ****//////////// //////////**** (mohammad) this part should keep in success but for now we go next level ****////////////
setOtpSended(true); setOtpSended(true);
setDelayPerRequest(true); setDelayPerRequest(true);
@@ -65,25 +63,25 @@ const PhoneValidation = ({tabState, setTabState}) => {
formData.append("phone_number", phoneNumber); formData.append("phone_number", phoneNumber);
formData.append("verification_code", verificationCode); formData.append("verification_code", verificationCode);
setTabState(tabState + 1) setTabState(tabState + 1);
requestServer(VERIFY_OTP, "post", { requestServer(VERIFY_OTP, "post", {
data: formData, data: formData,
}) })
.then(() => { .then(() => {})
}) .catch(() => {});
.catch(() => { };
});
}
return ( return (
<Box sx={{ <Box
display: "flex", sx={{
flexDirection: "column", display: "flex",
alignItems: "center", flexDirection: "column",
justifyContent: "center", alignItems: "center",
my: 3 justifyContent: "center",
}}> my: 3,
<Box sx={{display: "flex", alignItems: "center", gap: 2, width: {xs: "100%", sm: "70%"}}}> }}
>
<Box sx={{ display: "flex", alignItems: "center", gap: 2, width: { xs: "100%", sm: "70%" } }}>
<FormControl size="small" fullWidth variant="outlined"> <FormControl size="small" fullWidth variant="outlined">
<InputLabel htmlFor="phone_number">شماره تلفن مامور گشت</InputLabel> <InputLabel htmlFor="phone_number">شماره تلفن مامور گشت</InputLabel>
<OutlinedInput <OutlinedInput
@@ -98,19 +96,23 @@ const PhoneValidation = ({tabState, setTabState}) => {
onInput={handleNumericInput} onInput={handleNumericInput}
type="text" type="text"
inputProps={{ inputProps={{
maxLength: 11 maxLength: 11,
}} }}
/> />
</FormControl> </FormControl>
<Button onClick={sendOtp} disabled={!validPhone || delayPerRequest} variant="contained" color="success" <Button
sx={{width: "200px", height: "37px"}} onClick={sendOtp}
endIcon={<ForwardToInboxIcon/>}> disabled={!validPhone || delayPerRequest}
variant="contained"
color="success"
sx={{ width: "200px", height: "37px" }}
endIcon={<ForwardToInboxIcon />}
>
{delayPerRequest ? formatCounter(counter) : "دریافت کد"} {delayPerRequest ? formatCounter(counter) : "دریافت کد"}
</Button> </Button>
</Box> </Box>
</Box> </Box>
); );
}; };
export default PhoneValidation; export default PhoneValidation;

View File

@@ -1,30 +1,38 @@
"use client"; "use client";
import {Box, Card, IconButton, Stack, Typography} from "@mui/material"; import { Box, Card, IconButton, Stack, Typography } from "@mui/material";
import AccountCircleIcon from '@mui/icons-material/AccountCircle'; import AccountCircleIcon from "@mui/icons-material/AccountCircle";
import DeleteIcon from '@mui/icons-material/Delete'; import DeleteIcon from "@mui/icons-material/Delete";
import React from "react"; import React from "react";
const SuperVisorInfo = ({superVisor, deleteSuperVisor}) => { const SuperVisorInfo = ({ superVisor, deleteSuperVisor }) => {
return ( return (
<Card elevation={3} sx={{ <Card
display: "flex", alignItems: "center", elevation={3}
justifyContent: "space-between", sx={{
px: 1, py: 1, display: "flex",
}}> alignItems: "center",
<Box sx={{display: "flex"}}> justifyContent: "space-between",
<AccountCircleIcon color="primary" sx={{width: "50px", height: "50px"}}/> px: 1,
<Stack sx={{ml: 1, justifyContent: "center"}}> py: 1,
<Typography variant="body1" }}
sx={{letterSpacing: "1px", fontWeight: 500}}>{superVisor.name}</Typography> >
<Box sx={{ display: "flex" }}>
<AccountCircleIcon color="primary" sx={{ width: "50px", height: "50px" }} />
<Stack sx={{ ml: 1, justifyContent: "center" }}>
<Typography variant="body1" sx={{ letterSpacing: "1px", fontWeight: 500 }}>
{superVisor.name}
</Typography>
<Typography variant="caption">کد راهدار: {superVisor.code}</Typography> <Typography variant="caption">کد راهدار: {superVisor.code}</Typography>
</Stack> </Stack>
</Box> </Box>
<Box> <Box>
<IconButton color="error" onClick={() => deleteSuperVisor(superVisor.id)}><DeleteIcon/></IconButton> <IconButton color="error" onClick={() => deleteSuperVisor(superVisor.id)}>
<DeleteIcon />
</IconButton>
</Box> </Box>
</Card> </Card>
); );
}; };
export default SuperVisorInfo; export default SuperVisorInfo;

View File

@@ -1,15 +1,15 @@
"use client"; "use client";
import {Box, Button, Chip, Divider, Grid, Stack, Typography} from "@mui/material"; import { Box, Button, Chip, Divider, Grid, Stack, Typography } from "@mui/material";
import SaveAltIcon from '@mui/icons-material/SaveAlt'; import SaveAltIcon from "@mui/icons-material/SaveAlt";
import React, {useEffect, useState} from "react"; import React, { useEffect, useState } from "react";
import RahdarCode from "@/core/components/RahdarCode"; import RahdarCode from "@/core/components/RahdarCode";
import SuperVisorInfo from "@/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/SuperVisorInfo"; import SuperVisorInfo from "@/components/dashboard/roadPatrols/operator/Forms/CreatePatrol/SuperVisorInfo";
import KeyboardDoubleArrowRightIcon from "@mui/icons-material/KeyboardDoubleArrowRight"; import KeyboardDoubleArrowRightIcon from "@mui/icons-material/KeyboardDoubleArrowRight";
import KeyboardDoubleArrowLeftIcon from "@mui/icons-material/KeyboardDoubleArrowLeft"; import KeyboardDoubleArrowLeftIcon from "@mui/icons-material/KeyboardDoubleArrowLeft";
import {Controller} from "react-hook-form"; import { Controller } from "react-hook-form";
const SuperVisorsDetail = ({control, watch, setValue, tabState, setTabState}) => { const SuperVisorsDetail = ({ control, watch, setValue, tabState, setTabState }) => {
const [SuperVisorList, setSuperVisorList] = useState([]); const [SuperVisorList, setSuperVisorList] = useState([]);
const [readyToRequest, setReadyToRequest] = useState(false); const [readyToRequest, setReadyToRequest] = useState(false);
@@ -17,7 +17,7 @@ const SuperVisorsDetail = ({control, watch, setValue, tabState, setTabState}) =>
setSuperVisorList((prev) => [...prev, watch("road_patrol_rahdaran_id")]); setSuperVisorList((prev) => [...prev, watch("road_patrol_rahdaran_id")]);
setReadyToRequest(false); setReadyToRequest(false);
setValue("road_patrol_rahdaran_id", null); setValue("road_patrol_rahdaran_id", null);
} };
const deleteSuperVisor = (id) => { const deleteSuperVisor = (id) => {
setSuperVisorList((prev) => prev.filter((superVisor) => superVisor.id !== id)); setSuperVisorList((prev) => prev.filter((superVisor) => superVisor.id !== id));
@@ -30,7 +30,7 @@ const SuperVisorsDetail = ({control, watch, setValue, tabState, setTabState}) =>
const SendSuperVisor = () => { const SendSuperVisor = () => {
setValue("road_patrol_rahdaran_id", SuperVisorList); setValue("road_patrol_rahdaran_id", SuperVisorList);
setTabState(tabState + 1); setTabState(tabState + 1);
} };
return ( return (
<Box <Box
@@ -39,16 +39,19 @@ const SuperVisorsDetail = ({control, watch, setValue, tabState, setTabState}) =>
flexDirection: "column", flexDirection: "column",
alignItems: "center", alignItems: "center",
justifyContent: "center", justifyContent: "center",
my: 3 my: 3,
}} }}
> >
<Grid container sx={{display: "flex", alignItems: "center", justifyContent: "center"}}> <Grid container sx={{ display: "flex", alignItems: "center", justifyContent: "center" }}>
<Grid item xs={6} <Grid
sx={{display: "flex", alignItems: "center", flexDirection: {xs: "column", lg: "row"}, gap: 2}}> item
<Stack sx={{minWidth: "250px"}}> xs={6}
sx={{ display: "flex", alignItems: "center", flexDirection: { xs: "column", lg: "row" }, gap: 2 }}
>
<Stack sx={{ minWidth: "250px" }}>
<Controller <Controller
control={control} control={control}
render={({field, fieldState: {error}}) => { render={({ field, fieldState: { error } }) => {
return ( return (
<RahdarCode <RahdarCode
rahdarsCode={field.value} rahdarsCode={field.value}
@@ -61,33 +64,36 @@ const SuperVisorsDetail = ({control, watch, setValue, tabState, setTabState}) =>
name={"road_patrol_rahdaran_id"} name={"road_patrol_rahdaran_id"}
/> />
</Stack> </Stack>
<Button variant="contained" onClick={requestPatrolInfo} <Button
color="success" variant="contained"
sx={{textWrap: "nowrap", px: 3}} onClick={requestPatrolInfo}
disabled={!readyToRequest} color="success"
endIcon={<SaveAltIcon/>} sx={{ textWrap: "nowrap", px: 3 }}
disabled={!readyToRequest}
endIcon={<SaveAltIcon />}
> >
ثبت راهدار ثبت راهدار
</Button> </Button>
</Grid> </Grid>
</Grid> </Grid>
<Divider sx={{my: 2, width: "100%"}}> <Divider sx={{ my: 2, width: "100%" }}>
<Chip color="success" variant="outlined" label="لیست راهداران انتخاب شده"/> <Chip color="success" variant="outlined" label="لیست راهداران انتخاب شده" />
</Divider> </Divider>
{SuperVisorList.length !== 0 ? ( {SuperVisorList.length !== 0 ? (
<> <>
<Grid container spacing={2} sx={{ <Grid
p: 1, container
mt: 1, spacing={2}
maxHeight: "300px", sx={{
overflowY: "auto", p: 1,
}}> mt: 1,
maxHeight: "300px",
overflowY: "auto",
}}
>
{SuperVisorList.map((superVisor) => ( {SuperVisorList.map((superVisor) => (
<Grid key={superVisor.id} item xs={12} sm={6} lg={4}> <Grid key={superVisor.id} item xs={12} sm={6} lg={4}>
<SuperVisorInfo <SuperVisorInfo superVisor={superVisor} deleteSuperVisor={deleteSuperVisor} />
superVisor={superVisor}
deleteSuperVisor={deleteSuperVisor}
/>
</Grid> </Grid>
))} ))}
</Grid> </Grid>
@@ -103,8 +109,8 @@ const SuperVisorsDetail = ({control, watch, setValue, tabState, setTabState}) =>
<Button <Button
variant="outlined" variant="outlined"
color="error" color="error"
startIcon={<KeyboardDoubleArrowRightIcon/>} startIcon={<KeyboardDoubleArrowRightIcon />}
sx={{mt: 2}} sx={{ mt: 2 }}
> >
بازگشت بازگشت
</Button> </Button>
@@ -112,16 +118,16 @@ const SuperVisorsDetail = ({control, watch, setValue, tabState, setTabState}) =>
variant="contained" variant="contained"
color="primary" color="primary"
onClick={SendSuperVisor} onClick={SendSuperVisor}
endIcon={<KeyboardDoubleArrowLeftIcon/>} endIcon={<KeyboardDoubleArrowLeftIcon />}
sx={{mt: 2}} sx={{ mt: 2 }}
> >
تایید اطلاعات و رفتن به مرحله بعد تایید اطلاعات و رفتن به مرحله بعد
</Button> </Button>
</Box> </Box>
</> </>
) : ( ) : (
<Box sx={{my: 5, width: "100%", textAlign: "center"}}> <Box sx={{ my: 5, width: "100%", textAlign: "center" }}>
<Typography variant="h6" sx={{letterSpacing: "2px", color: "#606060"}}> <Typography variant="h6" sx={{ letterSpacing: "2px", color: "#606060" }}>
ابتدا اطلاعات بالا را تکمیل نمایید ابتدا اطلاعات بالا را تکمیل نمایید
</Typography> </Typography>
</Box> </Box>

View File

@@ -1,15 +1,12 @@
"use client"; "use client";
import {Dialog} from "@mui/material"; import { Dialog } from "@mui/material";
import PatrolForms from "./PatrolForms"; import PatrolForms from "./PatrolForms";
const CreatePatrol = ({open, setOpen, mutate}) => { const CreatePatrol = ({ open, setOpen, mutate }) => {
return ( return (
<Dialog open={open} fullWidth maxWidth="lg"> <Dialog open={open} fullWidth maxWidth="lg">
<PatrolForms <PatrolForms setOpen={setOpen} mutate={mutate} />
setOpen={setOpen}
mutate={mutate}
/>
</Dialog> </Dialog>
); );
}; };

View File

@@ -1,12 +1,12 @@
import PrintExcel from "./ExcelPrint"; import PrintExcel from "./ExcelPrint";
import OperatorCreate from "./Actions/Create"; import OperatorCreate from "./Actions/Create";
import {Box} from "@mui/material"; import { Box } from "@mui/material";
const Toolbar = ({table, filterData, mutate}) => { const Toolbar = ({ table, filterData, mutate }) => {
return ( return (
<Box sx={{display: "flex", gap: 1}}> <Box sx={{ display: "flex", gap: 1 }}>
<OperatorCreate table={table} mutate={mutate}/> <OperatorCreate table={table} mutate={mutate} />
<PrintExcel table={table} filterData={filterData}/> <PrintExcel table={table} filterData={filterData} />
</Box> </Box>
); );
}; };

View File

@@ -1,13 +1,13 @@
"use client"; "use client";
import PageTitle from "@/core/components/PageTitle"; import PageTitle from "@/core/components/PageTitle";
import {Stack} from "@mui/material"; import { Stack } from "@mui/material";
import OperatorList from "./OperatorList"; import OperatorList from "./OperatorList";
const OperatorPage = () => { const OperatorPage = () => {
return ( return (
<Stack spacing={1}> <Stack spacing={1}>
<PageTitle title={"عملیات"}/> <PageTitle title={"عملیات"} />
<OperatorList/> <OperatorList />
</Stack> </Stack>
); );
}; };

View File

@@ -1,13 +1,13 @@
"use client"; "use client";
import PageTitle from "@/core/components/PageTitle"; import PageTitle from "@/core/components/PageTitle";
import {Stack} from "@mui/material"; import { Stack } from "@mui/material";
import SuperviserList from "./SupervisorList"; import SuperviserList from "./SupervisorList";
const SupervisorPage = () => { const SupervisorPage = () => {
return ( return (
<Stack spacing={1}> <Stack spacing={1}>
<PageTitle title={"ارزیابی"}/> <PageTitle title={"ارزیابی"} />
<SuperviserList/> <SuperviserList />
</Stack> </Stack>
); );
}; };

View File

@@ -1,5 +1,7 @@
export const formatCounter = (counter) => { export const formatCounter = (counter) => {
const minutes = Math.floor(counter / 60).toString().padStart(2, '0'); const minutes = Math.floor(counter / 60)
const seconds = (counter % 60).toString().padStart(2, '0'); .toString()
.padStart(2, "0");
const seconds = (counter % 60).toString().padStart(2, "0");
return `${minutes}:${seconds}`; return `${minutes}:${seconds}`;
}; };

View File

@@ -28,7 +28,7 @@ export const pageMenu = [
label: "پیشخوان", label: "پیشخوان",
type: "page", type: "page",
route: "/dashboard", route: "/dashboard",
icon: <SpaceDashboardIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <SpaceDashboardIcon sx={{ width: "inherit", height: "inherit" }} />,
permissions: ["all"], permissions: ["all"],
}, },
{ {
@@ -36,14 +36,14 @@ export const pageMenu = [
label: "مدیریت کاربران", label: "مدیریت کاربران",
type: "page", type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/user_management", route: process.env.NEXT_PUBLIC_API_URL + "/v2/user_management",
icon: <GroupsIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <GroupsIcon sx={{ width: "inherit", height: "inherit" }} />,
permissions: ["full-user-management", "limited-user-management"], permissions: ["full-user-management", "limited-user-management"],
}, },
{ {
id: "projectsManagment", id: "projectsManagment",
label: "پروژه های راهداری", label: "پروژه های راهداری",
type: "menu", type: "menu",
icon: <AccountTreeIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <AccountTreeIcon sx={{ width: "inherit", height: "inherit" }} />,
hasSubitems: true, hasSubitems: true,
Subitems: [ Subitems: [
{ {
@@ -51,7 +51,7 @@ export const pageMenu = [
label: "ثبت قرارداد و پروژه", label: "ثبت قرارداد و پروژه",
type: "page", type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/rahdari_projects/finance", route: process.env.NEXT_PUBLIC_API_URL + "/v2/rahdari_projects/finance",
icon: <GavelIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <GavelIcon sx={{ width: "inherit", height: "inherit" }} />,
permissions: ["show-contract", "show-contract-province"], permissions: ["show-contract", "show-contract-province"],
}, },
{ {
@@ -59,7 +59,7 @@ export const pageMenu = [
label: "لیست پروژه ها", label: "لیست پروژه ها",
type: "page", type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/rahdari_projects/projects_list", route: process.env.NEXT_PUBLIC_API_URL + "/v2/rahdari_projects/projects_list",
icon: <BallotIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <BallotIcon sx={{ width: "inherit", height: "inherit" }} />,
permissions: ["all"], permissions: ["all"],
}, },
{ {
@@ -67,7 +67,7 @@ export const pageMenu = [
label: "پروژه های پیشنهادی", label: "پروژه های پیشنهادی",
type: "page", type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/rahdari_projects/proposal", route: process.env.NEXT_PUBLIC_API_URL + "/v2/rahdari_projects/proposal",
icon: <AssistantIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <AssistantIcon sx={{ width: "inherit", height: "inherit" }} />,
permissions: ["show-proposal", "show-proposal-province"], permissions: ["show-proposal", "show-proposal-province"],
}, },
{ {
@@ -75,7 +75,7 @@ export const pageMenu = [
label: "درخواست نمایندگان", label: "درخواست نمایندگان",
type: "page", type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/rahdari_projects/lawmakers", route: process.env.NEXT_PUBLIC_API_URL + "/v2/rahdari_projects/lawmakers",
icon: <AdminPanelSettingsIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <AdminPanelSettingsIcon sx={{ width: "inherit", height: "inherit" }} />,
permissions: ["show-lawmaker", "show-lawmaker-province"], permissions: ["show-lawmaker", "show-lawmaker-province"],
}, },
{ {
@@ -83,7 +83,7 @@ export const pageMenu = [
label: "پراکندگی بر روی نقشه", label: "پراکندگی بر روی نقشه",
type: "page", type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=rahdari_projects", route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=rahdari_projects",
icon: <MapIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <MapIcon sx={{ width: "inherit", height: "inherit" }} />,
permissions: ["all"], permissions: ["all"],
}, },
], ],
@@ -92,7 +92,7 @@ export const pageMenu = [
id: "roadItemManagment", id: "roadItemManagment",
label: "فعالیت های روزانه", label: "فعالیت های روزانه",
type: "menu", type: "menu",
icon: <FactCheckIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <FactCheckIcon sx={{ width: "inherit", height: "inherit" }} />,
hasSubitems: true, hasSubitems: true,
badges: ["road_items.total"], badges: ["road_items.total"],
Subitems: [ Subitems: [
@@ -100,7 +100,7 @@ export const pageMenu = [
id: "roadItemManagmentSupervisor", id: "roadItemManagmentSupervisor",
label: "ارزیابی", label: "ارزیابی",
type: "menu", type: "menu",
icon: <SpeedIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <SpeedIcon sx={{ width: "inherit", height: "inherit" }} />,
hasSubitems: true, hasSubitems: true,
badges: ["road_items.supervise_cnt"], badges: ["road_items.supervise_cnt"],
Subitems: [ Subitems: [
@@ -120,7 +120,7 @@ export const pageMenu = [
id: "roadItemManagmentOparation", id: "roadItemManagmentOparation",
label: "عملیات", label: "عملیات",
type: "menu", type: "menu",
icon: <EngineeringIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <EngineeringIcon sx={{ width: "inherit", height: "inherit" }} />,
hasSubitems: true, hasSubitems: true,
badges: ["road_items.operation_cnt"], badges: ["road_items.operation_cnt"],
Subitems: [ Subitems: [
@@ -138,7 +138,7 @@ export const pageMenu = [
label: "پراکندگی بر روی نقشه", label: "پراکندگی بر روی نقشه",
type: "page", type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=road_items", route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=road_items",
icon: <MapIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <MapIcon sx={{ width: "inherit", height: "inherit" }} />,
permissions: [ permissions: [
"show-road-item-supervise-cartable", "show-road-item-supervise-cartable",
"show-road-item-supervise-cartable-province", "show-road-item-supervise-cartable-province",
@@ -150,7 +150,7 @@ export const pageMenu = [
label: "گزارش ها", label: "گزارش ها",
type: "page", type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_items/report", route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_items/report",
icon: <AssessmentIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <AssessmentIcon sx={{ width: "inherit", height: "inherit" }} />,
permissions: [ permissions: [
"show-road-item-supervise-cartable", "show-road-item-supervise-cartable",
"show-road-item-supervise-cartable-province", "show-road-item-supervise-cartable-province",
@@ -163,7 +163,7 @@ export const pageMenu = [
id: "roadPatrolManagment", id: "roadPatrolManagment",
label: "گشت راهداری و ترابری", label: "گشت راهداری و ترابری",
type: "menu", type: "menu",
icon: <FireTruckIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <FireTruckIcon sx={{ width: "inherit", height: "inherit" }} />,
hasSubitems: true, hasSubitems: true,
badges: ["road_patrols.total"], badges: ["road_patrols.total"],
Subitems: [ Subitems: [
@@ -171,7 +171,7 @@ export const pageMenu = [
id: "roadPatrolManagmentSupervisor", id: "roadPatrolManagmentSupervisor",
label: "ارزیابی", label: "ارزیابی",
type: "menu", type: "menu",
icon: <SpeedIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <SpeedIcon sx={{ width: "inherit", height: "inherit" }} />,
hasSubitems: true, hasSubitems: true,
badges: ["road_patrols.supervise_cnt"], badges: ["road_patrols.supervise_cnt"],
Subitems: [ Subitems: [
@@ -191,7 +191,7 @@ export const pageMenu = [
id: "roadPatrolManagmentOparation", id: "roadPatrolManagmentOparation",
label: "عملیات", label: "عملیات",
type: "menu", type: "menu",
icon: <EngineeringIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <EngineeringIcon sx={{ width: "inherit", height: "inherit" }} />,
hasSubitems: true, hasSubitems: true,
badges: ["road_patrols.operation_cnt"], badges: ["road_patrols.operation_cnt"],
Subitems: [ Subitems: [
@@ -209,7 +209,7 @@ export const pageMenu = [
label: "پراکندگی بر روی نقشه", label: "پراکندگی بر روی نقشه",
type: "page", type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=road_patrols", route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=road_patrols",
icon: <MapIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <MapIcon sx={{ width: "inherit", height: "inherit" }} />,
permissions: [ permissions: [
"add-road-patrol", "add-road-patrol",
"show-road-patrol-supervise-cartable", "show-road-patrol-supervise-cartable",
@@ -221,7 +221,7 @@ export const pageMenu = [
label: "گزارش ها", label: "گزارش ها",
type: "page", type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_patrols/report", route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_patrols/report",
icon: <AssessmentIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <AssessmentIcon sx={{ width: "inherit", height: "inherit" }} />,
permissions: [ permissions: [
"add-road-patrol", "add-road-patrol",
"show-road-patrol-supervise-cartable", "show-road-patrol-supervise-cartable",
@@ -234,7 +234,7 @@ export const pageMenu = [
id: "inquiryPrivacyManagment", id: "inquiryPrivacyManagment",
label: "استعلام حریم راه", label: "استعلام حریم راه",
type: "menu", type: "menu",
icon: <DoorbellIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <DoorbellIcon sx={{ width: "inherit", height: "inherit" }} />,
hasSubitems: true, hasSubitems: true,
Subitems: [ Subitems: [
{ {
@@ -271,7 +271,7 @@ export const pageMenu = [
id: "safetyAndPrivacyManagment", id: "safetyAndPrivacyManagment",
label: "نگهداری حریم راه", label: "نگهداری حریم راه",
type: "menu", type: "menu",
icon: <RouteIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <RouteIcon sx={{ width: "inherit", height: "inherit" }} />,
hasSubitems: true, hasSubitems: true,
badges: ["safety_and_privacy.step_one", "safety_and_privacy.step_two"], badges: ["safety_and_privacy.step_one", "safety_and_privacy.step_two"],
Subitems: [ Subitems: [
@@ -279,7 +279,7 @@ export const pageMenu = [
id: "safetyAndPrivacyManagmentOparation", id: "safetyAndPrivacyManagmentOparation",
label: "عملیات", label: "عملیات",
type: "menu", type: "menu",
icon: <EngineeringIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <EngineeringIcon sx={{ width: "inherit", height: "inherit" }} />,
hasSubitems: true, hasSubitems: true,
Subitems: [ Subitems: [
{ {
@@ -307,7 +307,7 @@ export const pageMenu = [
label: "پراکندگی بر روی نقشه", label: "پراکندگی بر روی نقشه",
type: "page", type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=safety_and_privacy", route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=safety_and_privacy",
icon: <MapIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <MapIcon sx={{ width: "inherit", height: "inherit" }} />,
permissions: [ permissions: [
"show-safety-and-privacy-operator-cartable", "show-safety-and-privacy-operator-cartable",
"show-safety-and-privacy-operator-cartable-province", "show-safety-and-privacy-operator-cartable-province",
@@ -320,7 +320,7 @@ export const pageMenu = [
label: "گزارش ها", label: "گزارش ها",
type: "page", type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/safety_and_privacy/report", route: process.env.NEXT_PUBLIC_API_URL + "/v2/safety_and_privacy/report",
icon: <AssessmentIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <AssessmentIcon sx={{ width: "inherit", height: "inherit" }} />,
permissions: [ permissions: [
"show-safety-and-privacy-operator-cartable", "show-safety-and-privacy-operator-cartable",
"show-safety-and-privacy-operator-cartable-province", "show-safety-and-privacy-operator-cartable-province",
@@ -334,7 +334,7 @@ export const pageMenu = [
id: "roadObservationsManagment", id: "roadObservationsManagment",
label: "واکنش سریع", label: "واکنش سریع",
type: "menu", type: "menu",
icon: <ElectricBoltIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <ElectricBoltIcon sx={{ width: "inherit", height: "inherit" }} />,
hasSubitems: true, hasSubitems: true,
badges: ["road_observations.total"], badges: ["road_observations.total"],
Subitems: [ Subitems: [
@@ -342,7 +342,7 @@ export const pageMenu = [
id: "roadObservationsManagmentSupervisor", id: "roadObservationsManagmentSupervisor",
label: "ارزیابی", label: "ارزیابی",
type: "menu", type: "menu",
icon: <SpeedIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <SpeedIcon sx={{ width: "inherit", height: "inherit" }} />,
hasSubitems: true, hasSubitems: true,
badges: ["road_observations.supervise_cnt"], badges: ["road_observations.supervise_cnt"],
Subitems: [ Subitems: [
@@ -360,14 +360,14 @@ export const pageMenu = [
label: "رسیدگی به شکایات", label: "رسیدگی به شکایات",
type: "page", type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_observations", route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_observations",
icon: <AssignmentLateIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <AssignmentLateIcon sx={{ width: "inherit", height: "inherit" }} />,
permissions: ["show-fast-react", "show-fast-react-province", "show-fast-react-edarate-shahri"], permissions: ["show-fast-react", "show-fast-react-province", "show-fast-react-edarate-shahri"],
}, },
{ {
id: "roadObservationsManagmentOparation", id: "roadObservationsManagmentOparation",
label: "عملیات", label: "عملیات",
type: "menu", type: "menu",
icon: <EngineeringIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <EngineeringIcon sx={{ width: "inherit", height: "inherit" }} />,
hasSubitems: true, hasSubitems: true,
badges: ["road_observations.operation_cnt"], badges: ["road_observations.operation_cnt"],
Subitems: [ Subitems: [
@@ -385,7 +385,7 @@ export const pageMenu = [
label: "پراکندگی بر روی نقشه", label: "پراکندگی بر روی نقشه",
type: "page", type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=road_observations", route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=road_observations",
icon: <MapIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <MapIcon sx={{ width: "inherit", height: "inherit" }} />,
permissions: ["all"], permissions: ["all"],
}, },
{ {
@@ -393,7 +393,7 @@ export const pageMenu = [
label: "گزارش ها", label: "گزارش ها",
type: "page", type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_observations/report/index", route: process.env.NEXT_PUBLIC_API_URL + "/v2/road_observations/report/index",
icon: <AssessmentIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <AssessmentIcon sx={{ width: "inherit", height: "inherit" }} />,
permissions: ["all"], permissions: ["all"],
}, },
], ],
@@ -402,7 +402,7 @@ export const pageMenu = [
id: "winterCampManagment", id: "winterCampManagment",
label: "قرارگاه زمستانی", label: "قرارگاه زمستانی",
type: "menu", type: "menu",
icon: <CottageIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <CottageIcon sx={{ width: "inherit", height: "inherit" }} />,
hasSubitems: true, hasSubitems: true,
Subitems: [ Subitems: [
{ {
@@ -410,7 +410,7 @@ export const pageMenu = [
label: "محور های انسدادی", label: "محور های انسدادی",
type: "page", type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/winter_camp", route: process.env.NEXT_PUBLIC_API_URL + "/v2/winter_camp",
icon: <LineAxisIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <LineAxisIcon sx={{ width: "inherit", height: "inherit" }} />,
permissions: ["show-camp", "show-camp-province"], permissions: ["show-camp", "show-camp-province"],
}, },
{ {
@@ -418,7 +418,7 @@ export const pageMenu = [
label: "محور های حلقه اول", label: "محور های حلقه اول",
type: "page", type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=camp", route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=camp",
icon: <LineAxisIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <LineAxisIcon sx={{ width: "inherit", height: "inherit" }} />,
permissions: ["show-camp", "show-camp-province"], permissions: ["show-camp", "show-camp-province"],
}, },
{ {
@@ -426,7 +426,7 @@ export const pageMenu = [
label: "گزارش ها", label: "گزارش ها",
type: "page", type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=campNew", route: process.env.NEXT_PUBLIC_API_URL + "/v2/map?type=campNew",
icon: <AssessmentIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <AssessmentIcon sx={{ width: "inherit", height: "inherit" }} />,
permissions: ["show-camp", "show-camp-province"], permissions: ["show-camp", "show-camp-province"],
}, },
], ],
@@ -435,14 +435,14 @@ export const pageMenu = [
id: "receiptManagment", id: "receiptManagment",
label: "خسارات وارده بر ابنیه فنی و تاسیسات راه", label: "خسارات وارده بر ابنیه فنی و تاسیسات راه",
type: "menu", type: "menu",
icon: <GppMaybeIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <GppMaybeIcon sx={{ width: "inherit", height: "inherit" }} />,
hasSubitems: true, hasSubitems: true,
Subitems: [ Subitems: [
{ {
id: "receiptManagmentOparation", id: "receiptManagmentOparation",
label: "عملیات", label: "عملیات",
type: "menu", type: "menu",
icon: <EngineeringIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <EngineeringIcon sx={{ width: "inherit", height: "inherit" }} />,
hasSubitems: true, hasSubitems: true,
Subitems: [ Subitems: [
{ {
@@ -459,7 +459,7 @@ export const pageMenu = [
label: "گزارش ها", label: "گزارش ها",
type: "page", type: "page",
route: process.env.NEXT_PUBLIC_API_URL + "/v2/receipt/report", route: process.env.NEXT_PUBLIC_API_URL + "/v2/receipt/report",
icon: <AssessmentIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <AssessmentIcon sx={{ width: "inherit", height: "inherit" }} />,
permissions: ["all"], permissions: ["all"],
}, },
], ],
@@ -469,7 +469,7 @@ export const pageMenu = [
label: "آزمایشات (OPTS)", label: "آزمایشات (OPTS)",
type: "page", type: "page",
route: "/dashboard/azmayesh", route: "/dashboard/azmayesh",
icon: <ScienceIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <ScienceIcon sx={{ width: "inherit", height: "inherit" }} />,
permissions: ["azmayesh-management"], permissions: ["azmayesh-management"],
}, },
{ {
@@ -477,7 +477,7 @@ export const pageMenu = [
label: "نوع آزمایشات", label: "نوع آزمایشات",
type: "page", type: "page",
route: "/dashboard/azmayesh_type", route: "/dashboard/azmayesh_type",
icon: <BiotechIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <BiotechIcon sx={{ width: "inherit", height: "inherit" }} />,
permissions: ["azmayesh-type-management"], permissions: ["azmayesh-type-management"],
}, },
{ {
@@ -485,7 +485,7 @@ export const pageMenu = [
label: "اطلاعات خودرو", label: "اطلاعات خودرو",
type: "page", type: "page",
route: "/dashboard/car-details", route: "/dashboard/car-details",
icon: <DriveEtaIcon sx={{width: "inherit", height: "inherit"}}/>, icon: <DriveEtaIcon sx={{ width: "inherit", height: "inherit" }} />,
permissions: [""], permissions: [""],
}, },
]; ];

View File

@@ -1,7 +1,7 @@
import {errorResponse} from "@/core/utils/errorResponse"; import { errorResponse } from "@/core/utils/errorResponse";
import {successRequest} from "@/core/utils/successRequest"; import { successRequest } from "@/core/utils/successRequest";
import axios from "axios"; import axios from "axios";
import {useAuth} from "../contexts/auth"; import { useAuth } from "../contexts/auth";
const defaultOptions = { const defaultOptions = {
data: {}, data: {},
@@ -14,7 +14,7 @@ const defaultOptions = {
}; };
const useRequest = (initOptions) => { const useRequest = (initOptions) => {
const {logout} = useAuth(); const { logout } = useAuth();
const _options = Object.assign({}, defaultOptions, initOptions); const _options = Object.assign({}, defaultOptions, initOptions);