Feature/complaint create
This commit is contained in:
@@ -4,7 +4,6 @@ import { yupResolver } from "@hookform/resolvers/yup";
|
||||
import { array, mixed, number, object, string } from "yup";
|
||||
import { Box, Button, DialogActions, DialogContent, Tab, Tabs } from "@mui/material";
|
||||
import StyledForm from "@/core/components/StyledForm";
|
||||
import FileCopyIcon from "@mui/icons-material/FileCopy";
|
||||
import InfoIcon from "@mui/icons-material/Info";
|
||||
import ExitToAppIcon from "@mui/icons-material/ExitToApp";
|
||||
import KeyboardDoubleArrowRightIcon from "@mui/icons-material/KeyboardDoubleArrowRight";
|
||||
|
||||
@@ -242,7 +242,7 @@ const ComplaintListTable = ({ open, setOpen, mutate }) => {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Dialog onClose={() => setOpen(false)} open={open} fullWidth maxWidth={"md"}>
|
||||
<Dialog onClose={() => setOpen(false)} open={open} fullWidth maxWidth={"xl"}>
|
||||
{open && (
|
||||
<Box sx={{ p: 1, border: 1, borderColor: "divider", borderRadius: 1 }}>
|
||||
<DataTableWithAuth
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import { FormControl, FormHelperText } from "@mui/material";
|
||||
import UploadSystem from "@/core/components/UploadSystem";
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
const ImageUpload = ({ name, value, onChange, error, title }) => {
|
||||
const [beforeImg, setBeforeImg] = useState(value ? value : null);
|
||||
const [beforeFileType, setBeforeFileType] = useState(value ? "image/" : null);
|
||||
const [beforeFileName, setBeforeFileName] = useState(null);
|
||||
const [showBeforeImage, setShowBeforeImage] = useState(!value);
|
||||
|
||||
useEffect(() => {
|
||||
if (value) {
|
||||
setShowBeforeImage(false);
|
||||
if (typeof value === "string") {
|
||||
setBeforeImg(value);
|
||||
setBeforeFileType("image/");
|
||||
} else if (value instanceof File) {
|
||||
setBeforeImg(URL.createObjectURL(value));
|
||||
setBeforeFileType(value.type);
|
||||
}
|
||||
}
|
||||
}, [value]);
|
||||
|
||||
const handleFileChange = (event) => {
|
||||
const uploadedFile = event.target?.files?.[0];
|
||||
if (uploadedFile) {
|
||||
const fileType = event.target?.files?.[0].type;
|
||||
const fileName = event.target?.files?.[0].name;
|
||||
setBeforeImg(URL.createObjectURL(uploadedFile));
|
||||
setBeforeFileType(fileType);
|
||||
setBeforeFileName(fileName);
|
||||
onChange(uploadedFile);
|
||||
setShowBeforeImage(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<FormControl
|
||||
error={error}
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<FormHelperText
|
||||
sx={{
|
||||
fontSize: 14,
|
||||
border: 1,
|
||||
borderBottom: 0,
|
||||
borderColor: "divider",
|
||||
px: 2,
|
||||
py: 1,
|
||||
borderRadius: 2,
|
||||
borderBottomRightRadius: 0,
|
||||
borderBottomLeftRadius: 0,
|
||||
}}
|
||||
id={name}
|
||||
>
|
||||
{title}
|
||||
</FormHelperText>
|
||||
<UploadSystem
|
||||
selectedImage={beforeImg}
|
||||
handleUploadChange={handleFileChange}
|
||||
fileType={beforeFileType}
|
||||
fileName={beforeFileName}
|
||||
setSelectedImage={setBeforeImg}
|
||||
imageSize={[250, 150]}
|
||||
setShowAddIcon={setShowBeforeImage}
|
||||
showAddIcon={showBeforeImage}
|
||||
/>
|
||||
<FormHelperText id={name}>{error ? error.message : null}</FormHelperText>
|
||||
</FormControl>
|
||||
);
|
||||
};
|
||||
export default ImageUpload;
|
||||
@@ -0,0 +1,108 @@
|
||||
import { Button, DialogActions, DialogContent, FormControlLabel, RadioGroup, Stack } from "@mui/material";
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import Radio from "@mui/material/Radio";
|
||||
import StyledForm from "@/core/components/StyledForm";
|
||||
import { useState } from "react";
|
||||
import RegisterActionDone from "./RegisterActionDone";
|
||||
import RegisterActionUndone from "./RegisterActionUndone";
|
||||
import { yupResolver } from "@hookform/resolvers/yup";
|
||||
import { mixed, object, string } from "yup";
|
||||
import BeenhereIcon from "@mui/icons-material/Beenhere";
|
||||
|
||||
const RegisterActionContent = ({ setOpen, defaultValues, onBaseSubmit }) => {
|
||||
const [selectedOption, setSelectedOption] = useState("1");
|
||||
|
||||
const handleOptionChange = (e) => {
|
||||
setSelectedOption(e.target.value);
|
||||
};
|
||||
const validationSchema = object({
|
||||
description: string().required("توضیحات الزامی است"),
|
||||
start_point: mixed().when("rms_status", {
|
||||
is: "1",
|
||||
then: (schema) => schema.required("مکان اقدام الزامی است"),
|
||||
otherwise: (schema) => schema.notRequired(),
|
||||
}),
|
||||
image_before_1: mixed().when("rms_status", {
|
||||
is: "1",
|
||||
then: (schema) => schema.required("تصویر قبل از اقدام الزامی است"),
|
||||
otherwise: (schema) => schema.notRequired(),
|
||||
}),
|
||||
image_after_1: mixed().when("rms_status", {
|
||||
is: "1",
|
||||
then: (schema) => schema.required("تصویر بعد از اقدام الزامی است"),
|
||||
otherwise: (schema) => schema.notRequired(),
|
||||
}),
|
||||
});
|
||||
|
||||
const {
|
||||
control,
|
||||
handleSubmit,
|
||||
setValue,
|
||||
formState: { isSubmitting, errors },
|
||||
} = useForm({
|
||||
defaultValues,
|
||||
resolver: yupResolver(validationSchema),
|
||||
mode: "onChange",
|
||||
});
|
||||
|
||||
const onSubmit = async (data) => {
|
||||
console.log(data);
|
||||
await onBaseSubmit(data);
|
||||
};
|
||||
|
||||
return (
|
||||
<StyledForm onSubmit={handleSubmit(onSubmit)}>
|
||||
<DialogContent dividers sx={{ overflowY: "auto", maxHeight: "70vh" }}>
|
||||
<RadioGroup
|
||||
aria-label="file-options"
|
||||
name="status-options"
|
||||
value={selectedOption}
|
||||
onChange={handleOptionChange}
|
||||
>
|
||||
<Stack direction={"row"} alignItems={"center"} justifyContent={"center"}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Controller
|
||||
name="rms_status"
|
||||
control={control}
|
||||
render={({ field }) => <Radio {...field} value="1" />}
|
||||
/>
|
||||
}
|
||||
label="اقدام انجام شد"
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Controller
|
||||
name="rms_status"
|
||||
control={control}
|
||||
render={({ field }) => <Radio {...field} value="2" />}
|
||||
/>
|
||||
}
|
||||
label="اقدام انجام نشد"
|
||||
/>
|
||||
</Stack>
|
||||
</RadioGroup>
|
||||
{selectedOption === "1" ? (
|
||||
<RegisterActionDone control={control} setValue={setValue} errors={errors} />
|
||||
) : (
|
||||
<RegisterActionUndone control={control} />
|
||||
)}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button color={"secondary"} variant={"outlined"} onClick={() => setOpen(false)}>
|
||||
بستن
|
||||
</Button>
|
||||
<Button
|
||||
disabled={isSubmitting}
|
||||
endIcon={<BeenhereIcon />}
|
||||
color={"primary"}
|
||||
variant={"contained"}
|
||||
type={"submit"}
|
||||
>
|
||||
{isSubmitting ? "درحال ثبت اقدام..." : "ثبت اقدام"}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</StyledForm>
|
||||
);
|
||||
};
|
||||
export default RegisterActionContent;
|
||||
@@ -0,0 +1,86 @@
|
||||
import { Controller, useWatch } from "react-hook-form";
|
||||
import { Grid, Stack, TextField } from "@mui/material";
|
||||
import ImageUpload from "./ImageUpload";
|
||||
import MapInfoOneMarker from "@/core/components/MapInfoOneMarker";
|
||||
|
||||
const RegisterActionDone = ({ control, setValue, errors }) => {
|
||||
const StartPoint = useWatch({ control, name: "rms_start_latlng" });
|
||||
return (
|
||||
<Stack spacing={2}>
|
||||
<Stack>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} sm={12}>
|
||||
<Controller
|
||||
name="description"
|
||||
control={control}
|
||||
render={({ field, fieldState: { error } }) => {
|
||||
return (
|
||||
<TextField
|
||||
name={field.name}
|
||||
value={field.value}
|
||||
label={"توضیحات"}
|
||||
placeholder={"لطفا توضیحات خود را وارد کنید"}
|
||||
onChange={field.onChange}
|
||||
fullWidth
|
||||
multiline
|
||||
rows={4}
|
||||
error={error}
|
||||
helperText={error ? error.message : null}
|
||||
size={"small"}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Stack>
|
||||
<Stack>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} sm={6}>
|
||||
<Controller
|
||||
name="image_before_1"
|
||||
control={control}
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<ImageUpload
|
||||
name={field.name}
|
||||
value={field.value}
|
||||
error={error}
|
||||
onChange={field.onChange}
|
||||
title={"تصویر قبل از اقدام"}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6}>
|
||||
<Controller
|
||||
name="image_after_1"
|
||||
control={control}
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<ImageUpload
|
||||
name={field.name}
|
||||
value={field.value}
|
||||
error={error}
|
||||
onChange={field.onChange}
|
||||
title={"تصویر بعد از اقدام"}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Stack>
|
||||
<Stack>
|
||||
<Grid container>
|
||||
<Grid item xs={12} sm={12}>
|
||||
<MapInfoOneMarker
|
||||
setValue={setValue}
|
||||
StartPoint={StartPoint}
|
||||
errors={errors}
|
||||
title={"برای ثبت محل اقدام، لطفاً نقشه را بیشتر زوم کنید."}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
export default RegisterActionDone;
|
||||
@@ -0,0 +1,37 @@
|
||||
import { Grid, Stack, TextField } from "@mui/material";
|
||||
import { Controller } from "react-hook-form";
|
||||
|
||||
const RegisterActionUndone = ({ control }) => {
|
||||
return (
|
||||
<Stack spacing={2}>
|
||||
<Stack>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12} sm={12}>
|
||||
<Controller
|
||||
name="description"
|
||||
control={control}
|
||||
render={({ field, fieldState: { error } }) => {
|
||||
return (
|
||||
<TextField
|
||||
name={field.name}
|
||||
value={field.value}
|
||||
label={"توضیحات"}
|
||||
placeholder={"لطفا توضیحات خود را وارد کنید"}
|
||||
onChange={field.onChange}
|
||||
fullWidth
|
||||
multiline
|
||||
rows={4}
|
||||
error={error}
|
||||
helperText={error ? error.message : null}
|
||||
size={"small"}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
export default RegisterActionUndone;
|
||||
@@ -0,0 +1,66 @@
|
||||
import { Dialog, DialogTitle, IconButton, Tooltip } from "@mui/material";
|
||||
import { useState } from "react";
|
||||
import RegisterActionContent from "./RegisterActionContent";
|
||||
import AppRegistrationIcon from "@mui/icons-material/AppRegistration";
|
||||
import useRequest from "@/lib/hooks/useRequest";
|
||||
import { REGISTER_COMPLAINTS_LIST } from "@/core/utils/routes";
|
||||
const RegisterAction = ({ rowId, mutate }) => {
|
||||
const requestServer = useRequest({ notificationSuccess: true });
|
||||
const [openRegisterActionDialog, setOpenRegisterActionDialog] = useState(false);
|
||||
const defaultValues = {
|
||||
rms_status: "1",
|
||||
description: "",
|
||||
start_point: "",
|
||||
image_before_1: null,
|
||||
image_after_1: null,
|
||||
};
|
||||
const onBaseSubmit = async (result) => {
|
||||
console.log(result);
|
||||
const formData = new FormData();
|
||||
const rmsLatLng = `${result.start_point.lat},${result.start_point.lng}`;
|
||||
if (result.rms_status === "1") {
|
||||
formData.append("rms_description", result.description);
|
||||
formData.append("rms_status", 1);
|
||||
formData.append("start_point", rmsLatLng);
|
||||
formData.append("image_before", result.image_before_1);
|
||||
formData.append("image_after", result.image_after_1);
|
||||
} else {
|
||||
formData.append("rms_description", result.description);
|
||||
formData.append("rms_status", 2);
|
||||
}
|
||||
await requestServer(`${REGISTER_COMPLAINTS_LIST}/${rowId}`, "post", {
|
||||
data: formData,
|
||||
})
|
||||
.then((res) => {
|
||||
mutate();
|
||||
setOpenRegisterActionDialog(false);
|
||||
})
|
||||
.catch(() => {});
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<Tooltip title="ثبت اقدام">
|
||||
<IconButton color="primary" onClick={() => setOpenRegisterActionDialog(true)}>
|
||||
<AppRegistrationIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Dialog
|
||||
fullWidth
|
||||
open={openRegisterActionDialog}
|
||||
PaperProps={{
|
||||
sx: {
|
||||
boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<DialogTitle>ثبت اقدام</DialogTitle>
|
||||
<RegisterActionContent
|
||||
setOpen={setOpenRegisterActionDialog}
|
||||
onBaseSubmit={onBaseSubmit}
|
||||
defaultValues={defaultValues}
|
||||
/>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default RegisterAction;
|
||||
@@ -1,10 +1,12 @@
|
||||
import { Box } from "@mui/material";
|
||||
import RegisterAction from "../Form/registerAction";
|
||||
import ReferList from "./ReferList";
|
||||
import Refer from "./Refer";
|
||||
|
||||
const RowActions = ({ row, mutate }) => {
|
||||
return (
|
||||
<Box sx={{ display: "flex", gap: 1 }}>
|
||||
<RegisterAction mutate={mutate} rowId={row.getValue("id")} />
|
||||
<Refer rowId={row.getValue("id")} mutate={mutate} />
|
||||
<ReferList rowId={row.getValue("id")} />
|
||||
</Box>
|
||||
|
||||
@@ -13,12 +13,12 @@ const RowActions = ({ row, mutate }) => {
|
||||
return (
|
||||
<Box sx={{ display: "flex", gap: 1 }}>
|
||||
{hasSupervisePermission && row.original?.status === 0 && (
|
||||
<ConfirmForm rowId={row.getValue("id")} mutate={mutate} />
|
||||
<ConfirmForm rowId={row.getValue("road_observeds__id")} mutate={mutate} />
|
||||
)}
|
||||
{hasSupervisePermission && row.original?.status === 0 && (
|
||||
<RejectForm rowId={row.getValue("id")} mutate={mutate} />
|
||||
<RejectForm rowId={row.getValue("road_observeds__id")} mutate={mutate} />
|
||||
)}
|
||||
{hasRestorePermission && <RestoreForm rowId={row.getValue("id")} mutate={mutate} />}
|
||||
{hasRestorePermission && <RestoreForm rowId={row.getValue("road_observeds__id")} mutate={mutate} />}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -67,7 +67,7 @@ const SupervisorList = () => {
|
||||
{
|
||||
accessorKey: "id",
|
||||
header: "کد یکتا",
|
||||
id: "id",
|
||||
id: "road_observeds__id",
|
||||
enableColumnFilter: true,
|
||||
datatype: "text",
|
||||
filterMode: "equals",
|
||||
@@ -91,7 +91,7 @@ const SupervisorList = () => {
|
||||
...(hasCountryPermission ? [dynamicColumns] : []),
|
||||
{
|
||||
header: "اداره",
|
||||
id: "edarat_id",
|
||||
id: "city_id",
|
||||
enableColumnFilter: true,
|
||||
datatype: "numeric",
|
||||
filterMode: "equals",
|
||||
@@ -272,7 +272,7 @@ const SupervisorList = () => {
|
||||
{
|
||||
accessorFn: (row) => moment(row.created_at).locale("fa").format("HH:mm | yyyy/MM/DD"),
|
||||
header: "تاریخ ثبت",
|
||||
id: "created_at",
|
||||
id: "road_observeds__created_at",
|
||||
enableColumnFilter: true,
|
||||
datatype: "date",
|
||||
filterMode: "between",
|
||||
@@ -280,7 +280,11 @@ const SupervisorList = () => {
|
||||
size: 100,
|
||||
},
|
||||
{
|
||||
accessorFn: (row) => moment(row.rms_last_activity).locale("fa").format("HH:mm | yyyy/MM/DD"),
|
||||
accessorFn: (row) => {
|
||||
return row.rms_last_activity
|
||||
? moment(row?.rms_last_activity).locale("fa").format("HH:mm | yyyy/MM/DD")
|
||||
: "بدون تاریخ";
|
||||
},
|
||||
header: "تاریخ اقدام",
|
||||
id: "rms_last_activity",
|
||||
enableColumnFilter: true,
|
||||
|
||||
@@ -116,6 +116,7 @@ export const GET_FAST_REACT_SUPERVISOR = api + "/api/v3/road_observations/superv
|
||||
export const GET_FAST_REACT_COMPLAINTS = api + "/api/v3/road_observations/complaints_index";
|
||||
export const VERIFY_BY_FAST_REACT_SUPERVISOR = api + "/api/v3/road_observations/verify";
|
||||
export const REJECT_BY_FAST_REACT_SUPERVISOR = api + "/api/v3/road_observations/verify";
|
||||
export const REGISTER_COMPLAINTS_LIST = api + "/api/v3/road_observations/register";
|
||||
export const GET_FAST_REACT_OPERATOR = api + "/api/v3/road_observations/operator_index";
|
||||
export const GET_FAST_REACT_REFER_LIST = api + "/api/v3/road_observations/refer_list";
|
||||
export const REFER_FAST_REACT = api + "/api/v3/road_observations/refer";
|
||||
|
||||
Reference in New Issue
Block a user