Feature/map modify

This commit is contained in:
2024-10-12 06:57:10 +00:00
committed by AmirHossein Mahmoodi
parent c025eb26e7
commit 12e73ee502
17 changed files with 385 additions and 28 deletions

View File

@@ -34,6 +34,7 @@
"react-dom": "^18",
"react-hook-form": "^7.52.1",
"react-leaflet": "^4.2.1",
"react-leaflet-draw": "^0.20.4",
"react-toastify": "^10.0.5",
"sass": "^1.75.0",
"sharp": "^0.33.4",

View File

@@ -0,0 +1,28 @@
.leaflet-draw-tooltip {
background-color: #4f4f4f;
font-family: IRANSans;
color: #fff;
font-size: 10px;
padding: 2px 8px;
margin-right: 15px;
border-radius: 4px;
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
}
.leaflet-draw-tooltip:before {
content: "";
position: absolute;
bottom: 100%;
left: 103%;
transform: rotate(90deg);
margin-left: -6px;
border-width: 6px;
border-style: solid;
border-color: transparent transparent #333 transparent;
}
.leaflet-draw-tooltip-subtext {
font-size: 12px;
color: #ffeb3b;
}

View File

@@ -1,10 +1,10 @@
import {Card, CardContent, FormControl, FormLabel, Stack, Typography} from "@mui/material";
import { Card, CardContent, FormControl, FormLabel, Stack, Typography } from "@mui/material";
const QuestionSafetyForm = () => {
return (
<Stack sx={{py: 2}}>
<Stack sx={{ py: 2 }}>
<Card
sx={{display: "flex", justifyContent: "center", alignItems: "center", borderColor: "primary.main"}}
sx={{ display: "flex", justifyContent: "center", alignItems: "center", borderColor: "primary.main" }}
variant="outlined"
>
<CardContent>
@@ -15,13 +15,11 @@ const QuestionSafetyForm = () => {
</Typography>
</FormLabel>
<Stack
sx={{pt: 2, display: "flex", justifyContent: "center", alignItems: "center"}}
sx={{ pt: 2, display: "flex", justifyContent: "center", alignItems: "center" }}
spacing={1}
direction={"row"}
>
<Typography variant={"subtitle1"}>
دفتر حریم راه :{" "}
</Typography>
<Typography variant={"subtitle1"}>دفتر حریم راه : </Typography>
<Typography variant={"h5"} fontWeight={"bolder"}>
بله
</Typography>

View File

@@ -40,7 +40,7 @@ const RoadSafetyFormContext = ({ rowId, mutate, setOpenRoadSafetyForm }) => {
const defaultValues = {
description: "",
};
const requestServer = useRequest({ notification : {success : true, show : true} });
const requestServer = useRequest({ notification: { success: true, show: true } });
const { message, loadingMessage, errorMessage } = usePrevStateOpinion();
const {
register,

View File

@@ -31,7 +31,7 @@ const ReferFormContext = ({ setOpenReferDialog, rowId, mutate }) => {
city: "",
};
const { cities, loadingCities, errorCities } = useCities();
const requestServer = useRequest({notification : {show : true, success : true}});
const requestServer = useRequest({ notification: { show: true, success: true } });
const {
control,
register,

View File

@@ -1,10 +1,10 @@
import {Card, CardContent, FormControl, FormLabel, Stack, Typography} from "@mui/material";
import { Card, CardContent, FormControl, FormLabel, Stack, Typography } from "@mui/material";
const QuestionSafetyForm = () => {
return (
<Stack sx={{py: 2}}>
<Stack sx={{ py: 2 }}>
<Card
sx={{display: "flex", justifyContent: "center", alignItems: "center", borderColor: "primary.main"}}
sx={{ display: "flex", justifyContent: "center", alignItems: "center", borderColor: "primary.main" }}
variant="outlined"
>
<CardContent>
@@ -15,13 +15,11 @@ const QuestionSafetyForm = () => {
</Typography>
</FormLabel>
<Stack
sx={{pt: 2, display: "flex", justifyContent: "center", alignItems: "center"}}
sx={{ pt: 2, display: "flex", justifyContent: "center", alignItems: "center" }}
spacing={1}
direction={"row"}
>
<Typography variant={"subtitle1"}>
دفتر حریم راه :{" "}
</Typography>
<Typography variant={"subtitle1"}>دفتر حریم راه : </Typography>
<Typography variant={"h5"} fontWeight={"bolder"}>
بله
</Typography>

View File

@@ -40,7 +40,7 @@ const RoadSafetyFormContext = ({ rowId, mutate, setOpenRoadSafetyForm }) => {
const defaultValues = {
description: "",
};
const requestServer = useRequest({ notification : {success : true, show : true} });
const requestServer = useRequest({ notification: { success: true, show: true } });
const { message, loadingMessage, errorMessage } = usePrevStateOpinion();
const {
register,

View File

@@ -0,0 +1,96 @@
import {Box, Button, ButtonGroup} from "@mui/material";
import AutoModeIcon from "@mui/icons-material/AutoMode";
import DeleteIcon from "@mui/icons-material/Delete";
import EditLocationAltIcon from "@mui/icons-material/EditLocationAlt";
import SaveIcon from "@mui/icons-material/Save";
import CancelIcon from "@mui/icons-material/Cancel";
const MapActionButtons = ({
disableToCreate,
disableToEditAndDelete,
disableToSaveAndCancel,
onDraw,
onEdit,
onRemove,
onSave,
onCancel,
}) => (
<>
<Box sx={{
background: "#ffffff",
position: "absolute",
zIndex: "1999",
bottom: 0,
left: 0,
p: 2,
pl: 0.5,
pb: 0.5,
borderTopRightRadius: 8,
}}>
<ButtonGroup variant="contained" orientation="vertical" aria-label="map action group button">
<Button
sx={{justifyContent: "space-between"}}
startIcon={<AutoModeIcon/>}
color="primary"
disabled={disableToCreate}
onClick={onDraw}
>
اصلاح
</Button>
<Button
sx={{justifyContent: "space-between"}}
startIcon={<EditLocationAltIcon/>}
color="warning"
disabled={disableToEditAndDelete}
onClick={onEdit}
>
ویرایش
</Button>
<Button
sx={{justifyContent: "space-between"}}
startIcon={<DeleteIcon/>}
color="error"
disabled={disableToEditAndDelete}
onClick={onRemove}
>
حذف
</Button>
</ButtonGroup>
</Box>
<Box sx={{
position: "absolute",
zIndex: "1999",
right: 10,
top: 10,
background: "#fff",
borderRadius: 1,
padding: 0.5,
}}>
<Button
sx={{justifyContent: "space-between", mr: 1}}
startIcon={<SaveIcon/>}
variant="outlined"
size="small"
color="success"
disabled={disableToSaveAndCancel}
onClick={onSave}
>
ذخیره
</Button>
<Button
sx={{justifyContent: "space-between"}}
startIcon={<CancelIcon/>}
variant="outlined"
size="small"
color="error"
disabled={disableToSaveAndCancel}
onClick={onCancel}
>
لغو تغییرات
</Button>
</Box>
</>
);
export default MapActionButtons;

View File

@@ -0,0 +1,91 @@
"use client";
import {
Box,
Button,
Chip,
Dialog,
DialogActions,
DialogContent,
Divider,
FormControl,
FormControlLabel,
FormLabel,
Radio,
RadioGroup,
Typography,
} from "@mui/material";
import dynamic from "next/dynamic";
import MapLoading from "@/core/components/MapLayer/Loading";
import "leaflet-draw/dist/leaflet.draw.css";
import GppMaybeIcon from "@mui/icons-material/GppMaybe";
import PolygonForDesign from "./PolygonForDesign";
const MapLayer = dynamic(() => import("@/core/components/MapLayer"), {
loading: () => <MapLoading/>,
ssr: false,
});
const MapModifyDialog = ({mapModifyModal, setMapModifyModal}) => {
const handleClose = () => {
setMapModifyModal(false);
};
return (
<Dialog open={mapModifyModal} onClose={handleClose} maxWidth="lg" fullWidth>
<DialogContent sx={{p: 2}} dividers>
<Divider sx={{my: 3}}>
<Chip color="primary" sx={{mx: 1, fontSize: "13px", fontWeight: 500}}
label="بررسی پلیگان طرح متقاضی"/>
</Divider>
<Box sx={{
width: "100%",
height: "400px",
borderRadius: 3,
borderBottomLeftRadius: 0,
overflow: "hidden",
}}>
<MapLayer>
<PolygonForDesign/>
</MapLayer>
</Box>
<Box sx={{display: "flex", my: 2, alignItems: "center"}}>
<GppMaybeIcon color="warning"/>
<Typography variant="button" sx={{color: "warning.main", ml: 1}}>
نکته: اصلاح ننمودن طرح به منزله تایید طرح میباشد.
</Typography>
</Box>
<Box sx={{
display: "flex",
alignItems: "center",
justifyContent: "center",
border: "1px solid #e1e1e1",
p: 2,
borderRadius: 1,
}}>
<FormControl sx={{flexDirection: "row", alignItems: "center", gap: 2}}>
<FormLabel id="way-status" sx={{fontWeight: 500, fontSize: "16px", color: "warning.main"}}>آیا
طرح نیاز به ایجاد راه
دسترسی
دارد؟</FormLabel>
<RadioGroup
row
aria-labelledby="way-status"
defaultValue={0}
name="radio-buttons-group"
>
<FormControlLabel value={1} control={<Radio color="warning"/>} label="بله"/>
<FormControlLabel value={0} control={<Radio color="warning"/>} label="خیر"/>
</RadioGroup>
</FormControl>
</Box>
</DialogContent>
<DialogActions sx={{justifyContent: "center", py: 2}}>
<Button size="large" variant="outlined">بستن</Button>
<Button size="large" variant="contained">ثبت</Button>
</DialogActions>
</Dialog>
);
};
export default MapModifyDialog;

View File

@@ -0,0 +1,118 @@
"use client";
import "leaflet-draw/dist/leaflet.draw.css";
import "@/assets/scss/map-styles.scss"
import {FeatureGroup, useMap} from "react-leaflet";
import {EditControl} from "react-leaflet-draw";
import {useEffect, useRef, useState} from "react";
import MapActionButtons from "./MapActionButtons";
const PolygonForDesign = () => {
const map = useMap();
const editableFG = useRef(null);
const [polygonLayer, setPolygonLayer] = useState(null);
const [disableToCreate, setDisableToCreate] = useState(false);
const [disableToEditAndDelete, setDisableToEditAndDelete] = useState(true);
const [disableToSaveAndCancel, setDisableToSaveAndCancel] = useState(true);
const [editToolbar, setEditToolbar] = useState(null);
useEffect(() => {
const {L} = window;
L.drawLocal.draw.handlers.polygon.tooltip = {
start: "برای شروع کشیدن پلیگان، کلیک کنید.",
cont: "گوشه های دیگر پلیگان را نیز انتخاب کنید.",
end: "برای اتمام رسم پلیگان، نقطه آخر را به اول متصل نمایید.",
};
L.drawLocal.edit.handlers.edit.tooltip = {
text: "برای ذخیر یا لغو تغییرات، از دکمه های بالا سمت چپ استفاده نمایید.",
subtext: "نقاط مشخص شده را گرفته و برای ویرایش جابجا نمایید.",
};
}, []);
const handleDrawPolygon = () => {
const {L} = window;
const drawControl = new L.Draw.Polygon(map);
drawControl.enable();
setDisableToCreate(true);
};
const handleEditPolygon = () => {
const {L} = window;
if (editableFG.current && polygonLayer) {
const editControlInstance = new L.EditToolbar.Edit(map, {
featureGroup: editableFG.current,
});
editControlInstance.enable();
setEditToolbar(editControlInstance);
setDisableToEditAndDelete(true);
setDisableToSaveAndCancel(false);
}
};
const handleRemovePolygon = () => {
if (polygonLayer && editableFG.current) {
editableFG.current.removeLayer(polygonLayer);
setPolygonLayer(null);
setDisableToEditAndDelete(true);
setDisableToCreate(false);
}
};
const handleSavePolygon = () => {
if (editToolbar) {
editToolbar.save();
editToolbar.disable();
setDisableToEditAndDelete(false);
setDisableToSaveAndCancel(true);
}
};
const handleCancelEdit = () => {
if (editToolbar) {
editToolbar.revertLayers();
editToolbar.disable();
setDisableToEditAndDelete(false);
setDisableToSaveAndCancel(true);
}
};
const handlePolygonCreate = (e) => {
const layer = e.layer;
setPolygonLayer(layer);
editableFG.current.addLayer(layer);
setDisableToEditAndDelete(false);
};
return (
<>
<FeatureGroup ref={editableFG}>
<EditControl
position="bottomright"
onCreated={handlePolygonCreate}
draw={{
polygon: false,
circlemarker: false,
marker: false,
circle: false,
rectangle: false,
polyline: false,
}}
edit={{edit: false, remove: false}}
/>
</FeatureGroup>
<MapActionButtons
disableToCreate={disableToCreate}
disableToEditAndDelete={disableToEditAndDelete}
disableToSaveAndCancel={disableToSaveAndCancel}
onDraw={handleDrawPolygon}
onEdit={handleEditPolygon}
onRemove={handleRemovePolygon}
onSave={handleSavePolygon}
onCancel={handleCancelEdit}
/>
</>
);
};
export default PolygonForDesign;

View File

@@ -0,0 +1,25 @@
import {IconButton, Tooltip} from "@mui/material";
import MapIcon from "@mui/icons-material/Map";
import {useState} from "react";
import MapModifyDialog from "./MapModifyDialog";
const MapModify = ({rowId, mutate}) => {
const [mapModifyModal, setMapModifyModal] = useState(false);
const openMapModifyDialog = () => {
setMapModifyModal(true);
};
return (
<>
<Tooltip title="بررسی پلیگان طرح" arrow placement="right">
<IconButton color="primary" onClick={openMapModifyDialog}>
<MapIcon/>
</IconButton>
</Tooltip>
<MapModifyDialog mapModifyModal={mapModifyModal} setMapModifyModal={setMapModifyModal} rowId={rowId}
mutate={mutate}/>
</>
);
};
export default MapModify;

View File

@@ -31,7 +31,7 @@ const ReferFormContext = ({ setOpenReferDialog, rowId, mutate }) => {
province: "",
};
const { provinces, loadingProvinces, errorProvinces } = useProvinces();
const requestServer = useRequest({notification : {show : true, success : true}});
const requestServer = useRequest({ notification: { show: true, success: true } });
const {
control,
register,

View File

@@ -41,7 +41,7 @@ const RoadSafetyFormContext = ({ rowId, mutate, setOpenRoadSafetyForm }) => {
description: "",
RadioGroup: "",
};
const requestServer = useRequest({ notification : {success : true, show : true} });
const requestServer = useRequest({ notification: { success: true, show: true } });
const {
register,
handleSubmit,

View File

@@ -1,14 +1,16 @@
import ReferForm from "./Refer";
import TaskDetail from "./TaskDetail";
import { Box } from "@mui/material";
import {Box} from "@mui/material";
import RoadSafetyForm from "./RoadSafetyForm";
import MapModify from "./MapModify";
const RowActions = ({ row, mutate }) => {
const RowActions = ({row, mutate}) => {
return (
<Box sx={{ display: "flex", gap: 1 }}>
<ReferForm mutate={mutate} rowId={row.getValue("id")} />
<TaskDetail mutate={mutate} rowId={row.getValue("id")} />
<RoadSafetyForm rowId={row.getValue("id")} mutate={mutate} />
<Box sx={{display: "flex", gap: 1}}>
<MapModify mutate={mutate} rowId={row.getValue("id")}/>
<ReferForm mutate={mutate} rowId={row.getValue("id")}/>
<TaskDetail mutate={mutate} rowId={row.getValue("id")}/>
<RoadSafetyForm rowId={row.getValue("id")} mutate={mutate}/>
</Box>
);
};

View File

@@ -4,7 +4,7 @@ import { GET_CITY_LISTS } from "@/core/utils/routes";
import useRequest from "@/lib/hooks/useRequest";
const useCities = () => {
const requestServer = useRequest()
const requestServer = useRequest();
const [cities, setCities] = useState([]);
const [loadingCities, setLoadingCities] = useState(true);
const [errorCities, setErrorCities] = useState(null);

View File

@@ -4,7 +4,7 @@ import { GET_PREV_STATE_OPINION } from "@/core/utils/routes";
import useRequest from "@/lib/hooks/useRequest";
const usePrevStateOpinion = () => {
const requestServer = useRequest()
const requestServer = useRequest();
const [message, setMessage] = useState([]);
const [loadingMessage, setLoadingMessage] = useState(true);
const [errorMessage, setErrorMessage] = useState(null);

View File

@@ -4,7 +4,7 @@ import { GET_PROVINCE_LISTS } from "@/core/utils/routes";
import useRequest from "@/lib/hooks/useRequest";
const useProvinces = () => {
const requestServer = useRequest()
const requestServer = useRequest();
const [provinces, setProvinces] = useState([]);
const [loadingProvinces, setLoadingProvinces] = useState(true);
const [errorProvinces, setErrorProvinces] = useState(null);