From 26924102f742e1e0047b20b9359a5529d7efb8cb Mon Sep 17 00:00:00 2001 From: mhmjalali Date: Tue, 4 Nov 2025 09:06:04 +0330 Subject: [PATCH] work on privacy_office --- package.json | 1 + .../inquiry-privacy/privacy-office/page.js | 3 +- .../MapDrawPolygon/DrawBound.jsx | 242 ++++++++++-------- .../FeedbackAction/MapDrawPolygon/index.jsx | 10 +- .../RowActions/FeedbackAction/index.jsx | 37 +-- .../city-admin/RowActions/index.jsx | 2 +- .../privacy-office/PrivacyOfficeList.jsx | 239 +++++++++++++++++ .../RowActions/RejectAction/index.jsx | 2 +- .../ShowPrimaryArea/ShowBound.jsx | 29 +++ .../privacy-office/ShowPrimaryArea/index.jsx | 61 +++++ .../inquiryPrivacy/privacy-office/index.jsx | 14 + src/core/utils/geoCalculations.js | 35 +++ src/core/utils/routes.js | 3 +- 13 files changed, 550 insertions(+), 128 deletions(-) create mode 100644 src/components/dashboard/inquiryPrivacy/privacy-office/PrivacyOfficeList.jsx create mode 100644 src/components/dashboard/inquiryPrivacy/privacy-office/ShowPrimaryArea/ShowBound.jsx create mode 100644 src/components/dashboard/inquiryPrivacy/privacy-office/ShowPrimaryArea/index.jsx create mode 100644 src/core/utils/geoCalculations.js diff --git a/package.json b/package.json index a4532cb..8a2e759 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "@mui/material-nextjs": "^5.16.6", "@mui/x-date-pickers": "^6.19.5", "@mui/x-tree-view": "^7.11.0", + "@turf/turf": "^7.2.0", "axios": "^1.7.2", "date-fns": "^3.3.1", "date-fns-jalali": "^2.13.0-0", diff --git a/src/app/(withAuth)/(dashboardLayout)/dashboard/inquiry-privacy/privacy-office/page.js b/src/app/(withAuth)/(dashboardLayout)/dashboard/inquiry-privacy/privacy-office/page.js index ed381eb..c0de9c5 100644 --- a/src/app/(withAuth)/(dashboardLayout)/dashboard/inquiry-privacy/privacy-office/page.js +++ b/src/app/(withAuth)/(dashboardLayout)/dashboard/inquiry-privacy/privacy-office/page.js @@ -1,3 +1,4 @@ +import PrivacyOfficePage from "@/components/dashboard/inquiryPrivacy/privacy-office"; import WithPermission from "@/core/middlewares/withPermission"; export const metadata = { title: "کارتابل اداره حریم", @@ -5,7 +6,7 @@ export const metadata = { const Page = () => { return ( -

کارتابل اداره حریم

+
); }; diff --git a/src/components/dashboard/inquiryPrivacy/city-admin/RowActions/FeedbackAction/MapDrawPolygon/DrawBound.jsx b/src/components/dashboard/inquiryPrivacy/city-admin/RowActions/FeedbackAction/MapDrawPolygon/DrawBound.jsx index e715f3e..31b9706 100644 --- a/src/components/dashboard/inquiryPrivacy/city-admin/RowActions/FeedbackAction/MapDrawPolygon/DrawBound.jsx +++ b/src/components/dashboard/inquiryPrivacy/city-admin/RowActions/FeedbackAction/MapDrawPolygon/DrawBound.jsx @@ -2,113 +2,151 @@ import React, { useCallback, useEffect, useRef, useState } from "react"; import L from "leaflet"; import { FeatureGroup, useMap } from "react-leaflet"; import "leaflet-draw"; +import { calculatePolygonMetrics } from "@/core/utils/geoCalculations"; const DrawPolygon = ({ control, controlDispach, drawBound, setDrawBound }) => { - const map = useMap(); - const featureRef = useRef(null); - const [area, setArea] = useState(); - const drawControlRef = useRef(null); + const map = useMap(); + const featureRef = useRef(null); + const drawControlRef = useRef(null); - const safeFitBounds = (layer) => { - if (!layer || !map) return; - try { - const latLngs = layer.getLatLngs(); - map.fitBounds(latLngs, { - paddingTopLeft: [20, 35], - paddingBottomRight: [20, 55], - }); - } catch (e) { - console.warn("fitBounds failed:", e); - } + const [area, setArea] = useState(0); + const [sideLengths, setSideLengths] = useState([]); + + const calculatePolygonMetricsForLayer = useCallback( + (layer) => { + if (!layer) return; + + const latlngs = layer.getLatLngs()[0]; + if (!latlngs || latlngs.length < 3) return; + + const coordinates = latlngs.map((p) => [p.lat, p.lng]); + + const metrics = calculatePolygonMetrics(coordinates, true); + + setArea(metrics.area); + setSideLengths(metrics.sides); + + setDrawBound({ + layer, + metrics, + }); + }, + [setDrawBound] + ); + + const safeFitBounds = (layer) => { + if (!layer || !map) return; + try { + const latLngs = layer.getLatLngs(); + map.fitBounds(latLngs, { + paddingTopLeft: [20, 35], + paddingBottomRight: [20, 55], + }); + } catch (e) { + console.warn("fitBounds failed:", e); + } + }; + + const bindEditEvent = useCallback( + (layer) => { + if (!layer) return; + layer.on("edit", function (e) { + const editedLayer = e.target; + calculatePolygonMetricsForLayer(editedLayer); + }); + }, + [calculatePolygonMetricsForLayer] + ); + + const handlerCreatedBound = useCallback( + (event) => { + const { layer } = event; + layer.editing.enable(); + featureRef.current.addLayer(layer); + + calculatePolygonMetricsForLayer(layer); + bindEditEvent(layer); + + controlDispach({ type: "SET_STATUS", status: 2 }); + }, + [calculatePolygonMetricsForLayer, bindEditEvent, controlDispach] + ); + + useEffect(() => { + if ( + control.status === 1 && + drawControlRef.current && + drawControlRef.current._toolbars?.draw?._modes?.polygon?.handler + ) { + drawControlRef.current._toolbars.draw._modes.polygon.handler.enable(); + } + }, [control.status]); + + useEffect(() => { + if (control.status === 0 && featureRef.current) { + featureRef.current.clearLayers(); + setArea(0); + setSideLengths([]); + setDrawBound(null); + } + }, [control.status, setDrawBound]); + + useEffect(() => { + if (control.status === 2 && drawBound && featureRef.current) { + const { layer, metrics } = drawBound; + featureRef.current.addLayer(layer); + layer.editing.enable(); + safeFitBounds(layer); + bindEditEvent(layer); + + setArea(metrics?.area || 0); + setSideLengths(metrics?.sides || []); + } + }, [control.status, drawBound, bindEditEvent]); + + useEffect(() => { + if (!featureRef.current) return; + + L.drawLocal.draw.handlers.polygon.tooltip.start = + "برای شروع ترسیم محدوده، روی نقشه کلیک کنید"; + L.drawLocal.draw.handlers.polygon.tooltip.cont = + "برای ادامه ترسیم، نقاط بعدی را کلیک کنید"; + L.drawLocal.draw.handlers.polygon.tooltip.end = + "برای بستن محدوده، روی نقطه‌ی شروع کلیک کنید"; + + const drawControl = new L.Control.Draw({ + draw: { + polygon: { + shapeOptions: { + color: "red", + weight: 3, + clickable: true, + }, + }, + polyline: false, + rectangle: false, + circle: false, + marker: false, + circlemarker: false, + }, + edit: { + featureGroup: featureRef.current, + edit: true, + remove: true, + }, + }); + + drawControlRef.current = drawControl; + map.addControl(drawControl); + map.on(L.Draw.Event.CREATED, handlerCreatedBound); + + return () => { + map.off(L.Draw.Event.CREATED, handlerCreatedBound); + map.removeControl(drawControl); }; + }, [map, handlerCreatedBound]); - const bindEditEvent = (layer) => { - if (!layer) return; - layer.on("edit", function (e) { - const editedLayer = e.target; - setArea(editedLayer); - setDrawBound(editedLayer); - }); - }; - - const handlerCreatedBound = useCallback((event) => { - const { layer } = event; - layer.editing.enable(); - featureRef.current.addLayer(layer); - setArea(layer); - setDrawBound(layer); - bindEditEvent(layer); - controlDispach({ type: "SET_STATUS", status: 2 }); - }, []); - - useEffect(() => { - if ( - control.status === 1 && - drawControlRef.current && - drawControlRef.current._toolbars?.draw?._modes?.polygon?.handler - ) { - drawControlRef.current._toolbars.draw._modes.polygon.handler.enable(); - } - }, [control.status]); - - useEffect(() => { - if (control.status === 0 && area && featureRef.current) { - featureRef.current.removeLayer(area); - setArea(null); - setDrawBound(null); - } - }, [control.status, area]); - - useEffect(() => { - if (control.status === 2 && drawBound && featureRef.current) { - setArea(drawBound); - featureRef.current.addLayer(drawBound); - drawBound.editing.enable(); - safeFitBounds(drawBound); - bindEditEvent(drawBound); - } - }, [control.status, drawBound]); - - useEffect(() => { - if (!featureRef.current) return; - - L.drawLocal.draw.handlers.polygon.tooltip.start = "برای شروع ترسیم محدوده، روی نقشه کلیک کنید"; - L.drawLocal.draw.handlers.polygon.tooltip.cont = "برای ادامه ترسیم، نقاط بعدی را کلیک کنید"; - L.drawLocal.draw.handlers.polygon.tooltip.end = "برای بستن محدوده، روی نقطه‌ی شروع کلیک کنید"; - - const drawControl = new L.Control.Draw({ - draw: { - polygon: { - shapeOptions: { - color: "red", - weight: 3, - clickable: true, - }, - }, - polyline: false, - rectangle: false, - circle: false, - marker: false, - circlemarker: false, - }, - edit: { - featureGroup: featureRef.current, - edit: true, - remove: false, - }, - }); - - drawControlRef.current = drawControl; - map.addControl(drawControl); - map.on(L.Draw.Event.CREATED, handlerCreatedBound); - - return () => { - map.off(L.Draw.Event.CREATED, handlerCreatedBound); - map.removeControl(drawControl); - }; - }, [map, handlerCreatedBound]); - - return ; + return ; }; export default DrawPolygon; diff --git a/src/components/dashboard/inquiryPrivacy/city-admin/RowActions/FeedbackAction/MapDrawPolygon/index.jsx b/src/components/dashboard/inquiryPrivacy/city-admin/RowActions/FeedbackAction/MapDrawPolygon/index.jsx index bef1529..41ebf0f 100644 --- a/src/components/dashboard/inquiryPrivacy/city-admin/RowActions/FeedbackAction/MapDrawPolygon/index.jsx +++ b/src/components/dashboard/inquiryPrivacy/city-admin/RowActions/FeedbackAction/MapDrawPolygon/index.jsx @@ -63,10 +63,10 @@ const MapDrawPolygon = ({ drawBound, setDrawBound }) => { return ( <> - { {statusType.find((st) => st.id == control.status).message} - + { background: "linear-gradient(to top, rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0))", }} > - + {statusType .find((st) => st.id == control.status) .buttons.map((button) => ( @@ -108,7 +108,7 @@ const MapDrawPolygon = ({ drawBound, setDrawBound }) => { {button.label} ))} - + ); diff --git a/src/components/dashboard/inquiryPrivacy/city-admin/RowActions/FeedbackAction/index.jsx b/src/components/dashboard/inquiryPrivacy/city-admin/RowActions/FeedbackAction/index.jsx index e954aeb..d20160a 100644 --- a/src/components/dashboard/inquiryPrivacy/city-admin/RowActions/FeedbackAction/index.jsx +++ b/src/components/dashboard/inquiryPrivacy/city-admin/RowActions/FeedbackAction/index.jsx @@ -5,7 +5,7 @@ import { yupResolver } from "@hookform/resolvers/yup"; import CloseIcon from "@mui/icons-material/Close"; import ForumIcon from '@mui/icons-material/Forum'; import { Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, IconButton, TextField, Tooltip, Typography } from '@mui/material'; -import { useEffect, useMemo, useState } from 'react'; +import { useMemo, useState } from 'react'; import { useForm } from "react-hook-form"; import { object, string } from 'yup'; import ShowBound from "../../ShowPrimaryArea/ShowBound"; @@ -25,38 +25,41 @@ const FeedbackAction = ({rowId, mutate, rowPrimaryArea}) => { ? L.polygon(latLngCoords) : L.polyline(latLngCoords); }, [rowPrimaryArea]); - - - useEffect(() => { - console.log("drawBound", drawBound); - - }, [drawBound]) const { - control, register, handleSubmit, - setValue, formState: { isSubmitting, errors }, } = useForm({ - defaultValues: {expert_description: "", forbidden_area: ""}, + defaultValues: {expert_description: "", forbidden_area: "", forbidden_area_space: ""}, resolver: yupResolver(validationSchema), mode: "all" }); - const onSubmit = async (data) => { - const formData = new FormData(); - formData.append("expert_description", data.expert_description); - try { + const payload = { + expert_description: data.expert_description, + }; + + if (drawBound && drawBound.metrics) { + const { metrics } = drawBound; + payload.forbidden_area = { + type: "polygon", + coordinates: metrics.coordinates, + }; + payload.forbidden_area_space = metrics.area.toFixed(2); + } await requestServer(`${CITY_ADMIN_FEEDBACK}/${rowId}`, "post", { - data: formData, + data: payload, }); + mutate(); setOpenFeedbackDialog(false); - } catch (error) {} + } catch (error) { + console.error("❌ Error submitting feedback:", error); + } }; @@ -64,7 +67,7 @@ const FeedbackAction = ({rowId, mutate, rowPrimaryArea}) => { <> - setOpenFeedbackDialog(true)}> + setOpenFeedbackDialog(true)}> diff --git a/src/components/dashboard/inquiryPrivacy/city-admin/RowActions/index.jsx b/src/components/dashboard/inquiryPrivacy/city-admin/RowActions/index.jsx index a823158..69d588a 100644 --- a/src/components/dashboard/inquiryPrivacy/city-admin/RowActions/index.jsx +++ b/src/components/dashboard/inquiryPrivacy/city-admin/RowActions/index.jsx @@ -4,7 +4,7 @@ import FeedbackAction from "./FeedbackAction"; const RowActions = ({ row, mutate }) => { return ( - + {row.original.state_id === 1 ? : "-"} ); }; diff --git a/src/components/dashboard/inquiryPrivacy/privacy-office/PrivacyOfficeList.jsx b/src/components/dashboard/inquiryPrivacy/privacy-office/PrivacyOfficeList.jsx new file mode 100644 index 0000000..20fe52d --- /dev/null +++ b/src/components/dashboard/inquiryPrivacy/privacy-office/PrivacyOfficeList.jsx @@ -0,0 +1,239 @@ +import CustomSelectByDependency from '@/core/components/DataTable/filter/fieldsType/CustomSelectByDependency'; +import DataTableWithAuth from '@/core/components/DataTableWithAuth'; +import useInquiryPrivacyState from '@/lib/hooks/useInquiryPrivacyState'; +import AutorenewIcon from '@mui/icons-material/Autorenew'; +import DangerousIcon from '@mui/icons-material/Dangerous'; +import ManageAccountsIcon from '@mui/icons-material/ManageAccounts'; +import MapsHomeWorkIcon from '@mui/icons-material/MapsHomeWork'; +import PsychologyAltIcon from '@mui/icons-material/PsychologyAlt'; +import ReceiptLongIcon from '@mui/icons-material/ReceiptLong'; +import SecurityIcon from '@mui/icons-material/Security'; +import WindowIcon from '@mui/icons-material/Window'; +import { Box, Stack } from '@mui/material'; +import moment from 'jalali-moment'; +import { useMemo } from 'react'; +import RowActions from './RowActions'; +import { GET_PRIVACY_ADMIN_LIST } from '@/core/utils/routes'; +import ShowPrimaryArea from './ShowPrimaryArea'; + +const PrivacyOfficeList = () => { + const stateIcon = (state_id) => { + if (state_id === 1) return ; + if (state_id === 2 || state_id === 5 || state_id === 13) return ; + if (state_id === 3 || state_id === 6 || state_id === 14) return ; + if (state_id === 4 || state_id === 7 || state_id === 15) return ; + if (state_id === 8) return ; + if (state_id === 9 || state_id === 11) return ; + if (state_id === 10) return ; + if (state_id === 12) return ; + }; + const columns = useMemo(() => { + return [ + { + accessorKey: "panjare_vahed_id", + header: "کدرهگیری درخواست", + id: "panjare_vahed_id", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + sortDescFirst: false, + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + Cell: ({ row }) => <>{row.original.panjare_vahed_id}, + }, + { + accessorKey: "national_id", + header: "کد ملی", + id: "national_id", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + sortDescFirst: false, + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + Cell: ({ row }) => <>{row.original.national_id}, + }, + { + accessorKey: "state_id", + header: "وضعیت", + id: "state_id", + enableColumnFilter: true, + datatype: "numeric", + filterMode: "equals", + sortDescFirst: false, + grow: false, + size: 100, + ColumnSelectComponent: (props) => { + const { itemsList, loadingItemsList, errorItemsList } = useInquiryPrivacyState(); + + const getColumnSelectOptions = useMemo(() => { + if (loadingItemsList) { + return [{ value: "loading", label: "در حال بارگذاری..." }]; + } + if (errorItemsList) { + return [{ value: "error", label: "خطا در بارگذاری" }]; + } + return [ + { value: "", label: "همه موارد" }, + ...itemsList.map((item) => ({ + value: item.id, + label: item.name, + })), + ]; + }, [itemsList, loadingItemsList, errorItemsList]); + + return ( + + ); + }, + Cell: ({ row }) => ( + + {stateIcon(row.original.state_id)} + + {row.original.state_name} + + + ), + }, + { + accessorKey: "plan_title", + header: "عنوان طرح", + id: "plan_title", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + sortDescFirst: false, + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + Cell: ({ row }) => <>{row.original.plan_title}, + }, + { + accessorKey: "plan_group", + header: "گروه طرح", + id: "plan_group", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + sortDescFirst: false, + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + Cell: ({ row }) => <>{row.original.plan_group}, + }, + { + accessorKey: "requested_organization", + header: "دستگاه صادر کننده", + id: "requested_organization", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + sortDescFirst: false, + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + Cell: ({ row }) => <>{row.original.requested_organization}, + }, + { + accessorKey: "worksheet_id", + header: "شناسه کاربرگ", + id: "worksheet_id", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + sortDescFirst: false, + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + Cell: ({ row }) => <>{row.original.worksheet_id}, + }, + { + accessorKey: "primary_area", + header: "نمایش محدوده طرح", + id: "primary_area", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + sortDescFirst: false, + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + Cell: ({ row }) => row.original.primary_area ? ( + + + + ) : ("-"), + }, + { + accessorKey: "province_id", + header: "استان", + id: "province_id", + enableColumnFilter: false, + datatype: "numeric", + sortDescFirst: false, + grow: false, + size: 100, + Cell: ({ row }) => <>{row.original.province_name}, + }, + { + accessorKey: "city_id", + header: "شهر", + id: "city_id", + enableColumnFilter: false, + datatype: "numeric", + sortDescFirst: false, + grow: false, + size: 100, + Cell: ({ row }) => <>{row.original.city_name}, + }, + { + accessorKey: "isic", + header: "کد آیسیک", + id: "isic", + enableColumnFilter: true, + datatype: "text", + filterMode: "equals", + sortDescFirst: false, + columnFilterModeOptions: ["equals", "contains"], + grow: false, + size: 100, + Cell: ({ row }) => <>{row.original.isic}, + }, + { + accessorFn: (row) => moment(row.request_date).locale("fa").format("YYYY/MM/DD"), + header: "تاریخ درخواست", + id: "request_date", + enableColumnFilter: true, + datatype: "date", + filterMode: "between", + grow: false, + size: 100, + }, + ]; + }, []); + + return ( + <> + + + + + ) +} + +export default PrivacyOfficeList \ No newline at end of file diff --git a/src/components/dashboard/inquiryPrivacy/privacy-office/RowActions/RejectAction/index.jsx b/src/components/dashboard/inquiryPrivacy/privacy-office/RowActions/RejectAction/index.jsx index ccdffaf..c8a7e96 100644 --- a/src/components/dashboard/inquiryPrivacy/privacy-office/RowActions/RejectAction/index.jsx +++ b/src/components/dashboard/inquiryPrivacy/privacy-office/RowActions/RejectAction/index.jsx @@ -6,7 +6,7 @@ const RejectAction = ({ rowId, mutate }) => { const [openRejectDialog, setOpenRejectDialog] = useState(false); return ( <> - + setOpenRejectDialog(true)}> diff --git a/src/components/dashboard/inquiryPrivacy/privacy-office/ShowPrimaryArea/ShowBound.jsx b/src/components/dashboard/inquiryPrivacy/privacy-office/ShowPrimaryArea/ShowBound.jsx new file mode 100644 index 0000000..24db476 --- /dev/null +++ b/src/components/dashboard/inquiryPrivacy/privacy-office/ShowPrimaryArea/ShowBound.jsx @@ -0,0 +1,29 @@ +import { useEffect, useRef } from "react"; +import { FeatureGroup, useMap } from "react-leaflet"; + +const ShowBound = ({ bound }) => { + const map = useMap(); + const featureRef = useRef(null); + + const safeFitBounds = (layer) => { + if (!layer || !map) return; + try { + const latLngs = layer.getLatLngs(); + map.fitBounds(latLngs, { + paddingTopLeft: [20, 20], + paddingBottomRight: [20, 20], + }); + } catch (e) { + console.warn("fitBounds failed:", e); + } + }; + + useEffect(() => { + bound?.editing?.disable(); + featureRef.current.addLayer(bound); + safeFitBounds(bound); + }, []); + + return ; +}; +export default ShowBound; diff --git a/src/components/dashboard/inquiryPrivacy/privacy-office/ShowPrimaryArea/index.jsx b/src/components/dashboard/inquiryPrivacy/privacy-office/ShowPrimaryArea/index.jsx new file mode 100644 index 0000000..7300a1f --- /dev/null +++ b/src/components/dashboard/inquiryPrivacy/privacy-office/ShowPrimaryArea/index.jsx @@ -0,0 +1,61 @@ +const { Button, IconButton, Tooltip, Box, Dialog, DialogTitle, Typography, DialogContent, DialogActions } = require("@mui/material"); +import LayersIcon from '@mui/icons-material/Layers'; +import CloseIcon from "@mui/icons-material/Close"; +import { useMemo, useState } from 'react'; +import MapLayer from '@/core/components/MapLayer'; +import ShowBound from './ShowBound'; + +const ShowPrimaryArea = ({primaryArea}) => { + const [openShowAreaDialog, setOpenShowAreaDialog] = useState(false); + const bound = useMemo(() => { + const latLngCoords = primaryArea.coordinates.map(coord => [coord[1], coord[0]]); + return primaryArea.type === "polygon" + ? L.polygon(latLngCoords) + : L.polyline(latLngCoords); + }, [primaryArea]); + + return ( + + + setOpenShowAreaDialog(true)}> + + + + setOpenShowAreaDialog(false)} + PaperProps={{ + sx: { + transition: "all .3s", + boxShadow: "rgba(60, 64, 67, 0.3) 0px 1px 16px 0px, rgba(60, 64, 67, 0.15) 0px 1px 10px 0px", + borderRadius: 2, + padding: 1, + }, + }} + maxWidth="sm" + fullWidth + dir="rtl" + > + + + محدوده طرح + + setOpenShowAreaDialog(false)} size="small"> + + + + + + + + + + + + + + + ) +} + +export default ShowPrimaryArea \ No newline at end of file diff --git a/src/components/dashboard/inquiryPrivacy/privacy-office/index.jsx b/src/components/dashboard/inquiryPrivacy/privacy-office/index.jsx index e69de29..ce52276 100644 --- a/src/components/dashboard/inquiryPrivacy/privacy-office/index.jsx +++ b/src/components/dashboard/inquiryPrivacy/privacy-office/index.jsx @@ -0,0 +1,14 @@ +"use client"; +import PageTitle from "@/core/components/PageTitle"; +import { Stack } from "@mui/material"; +import PrivacyOfficeList from "./PrivacyOfficeList"; + +const PrivacyOfficePage = () => { + return ( + + + + + ); +}; +export default PrivacyOfficePage; diff --git a/src/core/utils/geoCalculations.js b/src/core/utils/geoCalculations.js new file mode 100644 index 0000000..f0f9f03 --- /dev/null +++ b/src/core/utils/geoCalculations.js @@ -0,0 +1,35 @@ +import * as turf from "@turf/turf"; + +export const calculatePolygonMetrics = (coordinates, isLatLngOrder = true) => { + if (!coordinates || coordinates.length < 3) { + return { area: 0, sides: [], coordinates: [] }; + } + + const geoCoords = isLatLngOrder + ? coordinates.map(([lat, lng]) => [lng, lat]) + : coordinates.map(([lng, lat]) => [lng, lat]); + + if ( + geoCoords[0][0] !== geoCoords[geoCoords.length - 1][0] || + geoCoords[0][1] !== geoCoords[geoCoords.length - 1][1] + ) { + geoCoords.push(geoCoords[0]); + } + + const polygon = turf.polygon([geoCoords]); + + const area = turf.area(polygon); + + const sides = []; + for (let i = 0; i < geoCoords.length - 1; i++) { + const line = turf.lineString([geoCoords[i], geoCoords[i + 1]]); + const length = turf.length(line, { units: "meters" }); + sides.push(length); + } + + return { + area, + sides, + coordinates: geoCoords, + }; +}; \ No newline at end of file diff --git a/src/core/utils/routes.js b/src/core/utils/routes.js index 0a3ee79..d51af49 100644 --- a/src/core/utils/routes.js +++ b/src/core/utils/routes.js @@ -238,4 +238,5 @@ export const CREATE_RAHDARAN_ITEM = api + "/api/v3/rahdaran"; // estelam harim export const GET_CITY_ADMIN_LIST = api + "/api/v3/harim/province_office"; export const GET_INQUIRY_PRIVACY_STATE_LIST = api + "/api/v3/harim/detail/states"; -export const CITY_ADMIN_FEEDBACK = api + "/api/v3/harim/province_office/feedback"; \ No newline at end of file +export const CITY_ADMIN_FEEDBACK = api + "/api/v3/harim/province_office/feedback"; +export const GET_PRIVACY_ADMIN_LIST = api + "/api/v3/harim/harim_office" \ No newline at end of file