From 2b0b08ae4ef069c765187a269838e6e08faa9598 Mon Sep 17 00:00:00 2001 From: popovspiridon99 Date: Wed, 24 Sep 2025 17:54:38 +0900 Subject: [PATCH] Region/district select; proper Map tabs --- client/src/components/map/MapComponent.tsx | 337 ++++++++++++++++----- client/src/components/map/mapUtils.ts | 25 +- client/src/pages/MapTest.tsx | 73 ++--- client/src/store/app.ts | 78 +++-- client/src/store/map.ts | 111 +++++-- client/src/store/objects.ts | 6 +- client/src/store/regions.ts | 36 +++ 7 files changed, 469 insertions(+), 197 deletions(-) create mode 100644 client/src/store/regions.ts diff --git a/client/src/components/map/MapComponent.tsx b/client/src/components/map/MapComponent.tsx index f69b977..40d1d68 100644 --- a/client/src/components/map/MapComponent.tsx +++ b/client/src/components/map/MapComponent.tsx @@ -10,12 +10,12 @@ import { customMapSource, googleMapsSatelliteSource, yandexMapsSatelliteSource } import { Geometry, SimpleGeometry } from 'ol/geom' import { fromExtent } from 'ol/geom/Polygon' import { Coordinate } from 'ol/coordinate' -import { addInteractions, handleImageDrop, loadFeatures, processFigure, processLine } from './mapUtils' +import { addInteractions, getFeatureByEntityId, handleImageDrop, loadFeatures, processFigure, processLine, zoomToFeature } from './mapUtils' import useSWR, { SWRConfiguration } from 'swr' import { fetcher } from '../../http/axiosInstance' import { BASE_URL } from '../../constants' -import { IconBoxMultiple, IconBoxPadding, IconChevronLeft, IconPlus, IconUpload, } from '@tabler/icons-react' -import { ICitySettings, IFigure, ILine } from '../../interfaces/gis' +import { IconBoxMultiple, IconBoxPadding, IconChevronLeft, IconPlus, IconUpload, IconX, } from '@tabler/icons-react' +import { ICitySettings, IDistrict, IFigure, ILine } from '../../interfaces/gis' import axios from 'axios' import MapToolbar from './MapToolbar/MapToolbar' import MapStatusbar from './MapStatusbar/MapStatusbar' @@ -33,9 +33,11 @@ import GisService from '../../services/GisService' import MapMode from './MapMode' import { satMapsProviders, schemas } from '../../constants/map' import MapPrint from './MapPrint/MapPrint' -import { Field, Menu, MenuButton, MenuList, MenuPopover, MenuTrigger, Combobox, Option, Button, Divider, Spinner, Portal, Dropdown } from '@fluentui/react-components' +import { Field, Menu, MenuButton, MenuList, MenuPopover, MenuTrigger, Combobox, Option, Button, Divider, Spinner, Portal, Dropdown, Tooltip, Drawer, DrawerHeader, DrawerBody, Text, Link } from '@fluentui/react-components' import { IRegion } from '../../interfaces/fuel' import { useAppStore } from '../../store/app' +import { getDistrictData, getRegionData, setDistrictsData, setRegionsData } from '../../store/regions' +import { ArrowLeft24Regular } from '@fluentui/react-icons' const swrOptions: SWRConfiguration = { revalidateOnFocus: false @@ -70,8 +72,8 @@ const MapComponent = ({ polygonExtent, rectCoords, draw, snap, translate, drawingLayerSource, satLayer, staticMapLayer, figuresLayer, linesLayer, - regionsLayer, districtBoundLayer, baseLayer, - printAreaDraw, + regionsLayer, districtBoundLayer, baseLayer, districtsLayer, + printAreaDraw, statusText, statusTextPosition, regionSelect, districtSelect } = useMapStore().id[id] // Tab settings @@ -103,7 +105,7 @@ const MapComponent = ({ if (regionsLayer && regionBoundsData) { if (Array.isArray(regionBoundsData)) { regionBoundsData.map(bound => { - const geoJson = new GeoJSON({ featureProjection: 'EPSG:3857' }) + const geoJson = new GeoJSON() //new GeoJSON({ featureProjection: 'EPSG:3857' }) const geometry = geoJson.readGeometry(bound) as Geometry const feature = new Feature(geometry) @@ -111,8 +113,15 @@ const MapComponent = ({ regionsLayer.getSource()?.addFeature(feature) }) + + if (map) { + const extent = regionsLayer.getSource()?.getExtent() + + if (extent) { + map.getView().fit(fromExtent(extent)) + } + } } - //regionsLayer.current.getSource()?.addFeature() } }, [regionBoundsData]) @@ -126,7 +135,7 @@ const MapComponent = ({ districtBoundLayer.setSource(bounds) bounds.on('featuresloadend', function () { - // map.current?.setView(new View({ + // map?.setView(new View({ // extent: bounds.getExtent() // })) }) @@ -275,9 +284,15 @@ const MapComponent = ({ } }, [currentObjectId]) - const { data: regionsData } = useSWR(`/general/regions`, (url) => fetcher(url, BASE_URL.ems), swrOptions) + const { data: regionsData } = useSWR(`/general/regions`, (url) => fetcher(url, BASE_URL.ems).then(res => { + setRegionsData(res) + return res + }), swrOptions) - const { data: districtsData } = useSWR(selectedRegion ? `/general/districts/?region_id=${selectedRegion}` : null, (url) => fetcher(url, BASE_URL.ems), swrOptions) + const { data: districtsData } = useSWR(selectedRegion ? `/general/districts/?region_id=${selectedRegion}` : null, (url) => fetcher(url, BASE_URL.ems).then(res => { + setDistrictsData(res) + return res + }), swrOptions) const { data: searchData } = useSWR( throttledSearchObject !== "" && selectedDistrict && selectedYear ? `/general/search/objects?q=${throttledSearchObject}&id_city=${selectedDistrict}&year=${selectedYear}` : null, @@ -384,7 +399,7 @@ const MapComponent = ({ useEffect(() => { if (!selectedRegion) { - setSelectedRegion(id, undefined) + setSelectedRegion(id, null) setSelectedYear(id, null) } }, [selectedRegion, selectedDistrict, id]) @@ -466,8 +481,94 @@ const MapComponent = ({ } }, [mode, map, printAreaDraw]) + useEffect(() => { + if (districtsData && Array.isArray(districtsData)) { + const list: Number[] = [] + districtsData.map(district => { + list.push(district.id as Number) + }) + + fetch(`${BASE_URL.ems}/gis/bounds/city`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ list }) + }).then(async response => { + const data = await response.json() + + if (Array.isArray(data)) { + data.map(bound => { + const geoJson = new GeoJSON() //new GeoJSON({ featureProjection: 'EPSG:3857' }) + const geometry = geoJson.readGeometry(bound) as Geometry + + const feature = new Feature(geometry) + feature.setProperties(bound.properties) + + districtsLayer.getSource()?.addFeature(feature) + }) + } + }) + } + }, [districtsData]) + + const mapTooltipRef = useRef(null) + + useEffect(() => { + if (mapTooltipRef.current) { + const leftOffset = 30 + const topOffset = -30 + mapTooltipRef.current.style.left = (statusTextPosition[0] + leftOffset).toString() + 'px' + mapTooltipRef.current.style.top = (statusTextPosition[1] + topOffset).toString() + 'px' + } + }, [statusTextPosition, mapTooltipRef]) + + // zoom on region select + useEffect(() => { + if (selectedRegion && !selectedDistrict) { + const feature = getFeatureByEntityId(selectedRegion, regionsLayer) + + if (feature) { + regionSelect.getFeatures().push(feature) + } + + zoomToFeature(id, feature) + } + }, [selectedRegion, selectedDistrict]) + + // zoom on district select + useEffect(() => { + if (selectedDistrict) { + const feature = getFeatureByEntityId(selectedDistrict, districtsLayer) + + if (feature) { + districtSelect.getFeatures().push(feature) + + regionsLayer.setOpacity(0) + } + + zoomToFeature(id, feature) + } + }, [selectedDistrict]) + + useEffect(() => { + if (selectedYear) { + regionsLayer.setOpacity(0) + districtsLayer.setOpacity(0) + } + }, [selectedYear]) + return ( - <> +
+ + {statusText && active && !selectedYear && + +
+ {/* {statusText} */} +
+
+ } + {active && @@ -499,7 +600,7 @@ const MapComponent = ({ : null} - )) : null} - + */} - - - - { - if (data.optionValue) { - setSelectedYear(id, Number(data.optionValue)); - } else { - setSelectedYear(id, null); - } - }} - > - {schemas.map((el) => ( - - ))} - + */} - - - {'Настройка видимости слоёв'} - - - - setSatMapsProvider(id, value as SatelliteMapsProvider)} /> - - - submitOverlay(file, polygonExtent, rectCoords)}> - - - - - - - - - - - */}
}
+ {!selectedRegion && + + {/* + + */} + + +
+ {regionsData && regionsData.map((region: IRegion) => ( + setSelectedRegion(id, region.id)} + onMouseEnter={() => { + const feature = getFeatureByEntityId(region.id, regionsLayer) + + if (feature) { + regionSelect.getFeatures().push(feature) + } + }} + onMouseLeave={() => { + regionSelect.getFeatures().clear() + }} + >{region.name} + ))} +
+
+
} + + + +
-
e.preventDefault()} onDrop={(e) => handleImageDrop(e, id)}> +
e.preventDefault()} onDrop={(e) => handleImageDrop(e, id)}>
@@ -743,7 +918,13 @@ const MapComponent = ({
)} - +
+ +
+ ) } diff --git a/client/src/components/map/mapUtils.ts b/client/src/components/map/mapUtils.ts index 7efed33..5cf0712 100644 --- a/client/src/components/map/mapUtils.ts +++ b/client/src/components/map/mapUtils.ts @@ -18,6 +18,8 @@ import { measureStyleFunction, modifyStyle } from "./Measure/MeasureStyles"; import { getCurrentTool, getDraw, getDrawingLayerSource, getImageLayer, getMap, getMeasureClearPrevious, getMeasureDraw, getMeasureModify, getMeasureSource, getMeasureType, getOverlayLayerSource, getSnap, getTipPoint, getTranslate, PrintOrientation, setDraw, setFile, setMeasureDraw, setPolygonExtent, setRectCoords, setSnap, setTranslate } from "../../store/map"; import Collection from "ol/Collection"; import { SketchCoordType } from "ol/interaction/Draw"; +import VectorImageLayer from "ol/layer/VectorImage"; +import VectorSource from "ol/source/Vector"; const calculateAngle = (coords: [number, number][]) => { const [start, end] = coords; @@ -482,18 +484,25 @@ export const addInteractions = ( } } -export const zoomToFeature = (map_id: string, feature: Feature) => { - const geometry = feature.getGeometry() - const extent = geometry?.getExtent() +export const zoomToFeature = (map_id: string, feature: Feature | undefined) => { + if (feature) { + const geometry = feature.getGeometry() + const extent = geometry?.getExtent() - if (getMap(map_id) && extent) { - getMap(map_id)?.getView().fit(extent, { - duration: 300, - maxZoom: 19, - }) + if (getMap(map_id) && extent) { + getMap(map_id)?.getView().fit(extent, { + duration: 300, + maxZoom: 19, + }) + } } } +export const getFeatureByEntityId = (entity_id: number, layer: VectorImageLayer, VectorSource>>) => { + console.log(entity_id, layer.getSource()?.getFeatures()) + return layer.getSource()?.getFeatures().find(feature => feature.getProperties().entity_id === entity_id) +} + // Function to save features to localStorage export const saveFeatures = (map_id: string) => { const features = getDrawingLayerSource(map_id).getFeatures() diff --git a/client/src/pages/MapTest.tsx b/client/src/pages/MapTest.tsx index 38d23fb..948d1bf 100644 --- a/client/src/pages/MapTest.tsx +++ b/client/src/pages/MapTest.tsx @@ -1,5 +1,3 @@ -import { useEffect } from "react"; -import { v4 as uuidv4 } from "uuid"; import { Tab, TabList } from "@fluentui/react-tabs"; import MapComponent from "../components/map/MapComponent"; @@ -7,76 +5,49 @@ import { useAppStore, setCurrentTab, deleteMapTab, + addMapTab, } from "../store/app"; import { initializeMapState, useMapStore } from "../store/map"; import { initializeObjectsState } from "../store/objects"; +import { Button } from "@fluentui/react-components"; +import { Add12Filled, Dismiss12Filled, Map16Regular } from "@fluentui/react-icons"; function MapTest() { - const { mapTab, currentTab } = useAppStore(); - const { id } = useMapStore(); - - const tabs = [ - { - id: uuidv4(), - year: 2018, - region: 11, - district: 146, - }, - // { - // id: uuidv4(), - // year: 2023, - // region: 11, - // district: 146, - // }, - ]; - - useEffect(() => { - tabs.forEach((tab) => { - useAppStore.setState((state) => { - initializeObjectsState(tab.id, tab.region, tab.district, null, tab.year); - initializeMapState(tab.id); - - return { - mapTab: { - ...state.mapTab, - [tab.id]: { - year: tab.year, - region: tab.region, - district: tab.district, - }, - }, - }; - }); - }); - - setCurrentTab(tabs[0].id); - - return () => { - tabs.forEach((tab) => deleteMapTab(tab.id)); - }; - }, []); + const { mapTab, currentTab } = useAppStore() + const { id } = useMapStore() return (
setCurrentTab(data.value as string)} + style={{ borderBottom: '1px solid var(--colorNeutralShadowKey)' }} > {Object.entries(mapTab).map(([key]) => ( - + }> {id[key]?.mapLabel ?? `Tab ${key}`} + +
diff --git a/client/src/store/app.ts b/client/src/store/app.ts index 70f7544..5560f40 100644 --- a/client/src/store/app.ts +++ b/client/src/store/app.ts @@ -1,38 +1,52 @@ -import { create } from 'zustand'; +import { create } from 'zustand' +import { v4 as uuidv4 } from 'uuid' +import { initializeObjectsState } from './objects' +import { initializeMapState } from './map' export type Mode = 'edit' | 'view' export type ColorScheme = 'light' | 'dark' | 'auto' +export interface MapTabState { + year: number | null + region: number | null + district: number | null +} + export interface AppState { colorScheme: ColorScheme, - mapTab: Record, + mapTab: Record, currentTab: string | null; } -export const useAppStore = create(() => ({ - colorScheme: 'auto', - currentTab: null, - mapTab: {} -})) +export const useAppStore = create(() => { + const firstId = uuidv4() -const getColorScheme = () => { + initializeObjectsState(firstId, null, null, null, null); + initializeMapState(firstId) + + return { + colorScheme: "auto", + currentTab: firstId, + mapTab: { + [firstId]: { year: null, region: null, district: null }, + }, + } +}) + +export const getColorScheme = () => { useAppStore.getState().colorScheme } -const setColorScheme = (colorScheme: ColorScheme) => { +export const setColorScheme = (colorScheme: ColorScheme) => { useAppStore.setState(() => ({ colorScheme: colorScheme })) localStorage.setItem('colorScheme', colorScheme.toString()) } -const getCurrentTab = () => useAppStore.getState().currentTab -const setCurrentTab = (id: string | null) => useAppStore.setState(() => ({ currentTab: id })) +export const getCurrentTab = () => useAppStore.getState().currentTab +export const setCurrentTab = (id: string | null) => useAppStore.setState(() => ({ currentTab: id })) -const setMapTabYear = (id: string, year: number | null) => +export const setMapTabYear = (id: string, year: number | null) => useAppStore.setState((state) => { return { mapTab: { @@ -42,17 +56,31 @@ const setMapTabYear = (id: string, year: number | null) => } }) -const deleteMapTab = (id: string) => +export const deleteMapTab = (id: string) => useAppStore.setState((state) => { const { [id]: _, ...remainingTabs } = state.mapTab; - return { mapTab: remainingTabs }; + const keys = Object.keys(remainingTabs); + + return { + mapTab: remainingTabs, + currentTab: keys.length > 0 ? keys[keys.length - 1] : null, + }; }) -export { - deleteMapTab, - getCurrentTab, - setCurrentTab, - setMapTabYear, - getColorScheme, - setColorScheme +export const addMapTab = () => { + const id = uuidv4(); + + useAppStore.setState((state) => ({ + mapTab: { + ...state.mapTab, + [id]: { + year: null, + region: null, + district: null, + }, + }, + currentTab: id, // optionally switch to this new tab + })); + + return id; // so you can use the new id in your components } \ No newline at end of file diff --git a/client/src/store/map.ts b/client/src/store/map.ts index 46898b3..d94725b 100644 --- a/client/src/store/map.ts +++ b/client/src/store/map.ts @@ -21,11 +21,12 @@ import { VectorImage } from 'ol/layer'; import { click, pointerMove } from 'ol/events/condition'; import { measureStyleFunction, modifyStyle } from '../components/map/Measure/MeasureStyles'; import MapBrowserEvent from 'ol/MapBrowserEvent'; -import { transform } from 'ol/proj'; -import { applyTransformations, calculateTransformations, fixedAspectRatioBox, zoomToFeature } from '../components/map/mapUtils'; -import { setCurrentObjectId, setSelectedRegion } from './objects'; +import { get, transform } from 'ol/proj'; +import { applyTransformations, calculateTransformations, fixedAspectRatioBox, getGridCellPosition, zoomToFeature } from '../components/map/mapUtils'; +import { getSelectedRegion, setCurrentObjectId, setSelectedDistrict, setSelectedRegion } from './objects'; import View from 'ol/View'; import { getPrintOrientation } from './print'; +import { getDistrictsData, getRegionsData } from './regions'; export type Mode = 'edit' | 'view' | 'print' @@ -45,7 +46,8 @@ interface MapState { currentX: number | undefined; currentY: number | undefined; currentCoordinate: Coordinate | null; - statusText: string; + statusText: string | null; + statusTextPosition: [number, number]; satMapsProvider: SatelliteMapsProvider; selectedObjectType: number | null; alignMode: boolean; @@ -72,7 +74,7 @@ interface MapState { figuresLayer: VectorLayer; linesLayer: VectorLayer; regionsLayer: VectorImage; - citiesLayer: VectorLayer; + districtsLayer: VectorImage; districtBoundLayer: VectorImage; imageLayer: ImageLayer; selectedArea: Feature | null; @@ -81,6 +83,7 @@ interface MapState { measureModify: Modify; overlayLayer: VectorLayer; regionSelect: Select; + districtSelect: Select; lineSelect: Select; previousView: View | undefined | null; printArea: Extent | null; @@ -115,6 +118,8 @@ export const initializeMapState = ( // Region select const regionSelect = new Select({ condition: pointerMove, style: selectStyle, layers: (layer) => layer.get('type') === 'region' }) + const districtSelect = new Select({ condition: pointerMove, style: selectStyle, layers: (layer) => layer.get('type') === 'district' }) + // Line select const lineSelect = new Select({ condition: click, style: highlightStyleRed, hitTolerance: hitTolerance, layers: (layer) => layer.get('type') === 'line', }) lineSelect.on('select', (e) => { @@ -183,7 +188,7 @@ export const initializeMapState = ( const districtBoundLayer = new VectorImage({ style: new Style({ stroke: new Stroke({ color: 'red', width: 2 }), }) }) - const citiesLayer = new VectorLayer({ source: new VectorSource(), properties: { id: uuidv4(), name: 'Города' } }) + const districtsLayer = new VectorImage({ source: new VectorSource(), properties: { id: uuidv4(), name: 'Населенные пункты', type: 'district' } }) const linesLayer = new VectorLayer({ source: new VectorSource(), @@ -266,10 +271,10 @@ export const initializeMapState = ( baseLayer, satLayer, staticMapLayer, - regionsLayer, - districtBoundLayer, - citiesLayer, linesLayer, + districtsLayer, + districtBoundLayer, + regionsLayer, figuresLayer, drawingLayer, imageLayer, @@ -282,30 +287,48 @@ export const initializeMapState = ( }) map.addInteraction(regionSelect) + map.addInteraction(districtSelect) map.addInteraction(lineSelect) map.addInteraction(lineHover) map.addInteraction(figureSelect) map.addInteraction(figureHover) - // map.on('pointermove', function (e: MapBrowserEvent) { - // setCurrentCoordinate(id, e.coordinate) - // const currentExtent = get('EPSG:3857')?.getExtent() as Extent - // const { tileX, tileY } = getGridCellPosition(e.coordinate[0], e.coordinate[1], currentExtent, Number(map?.getView().getZoom()?.toFixed(0))) - // setCurrentZ(id, Number(map?.getView().getZoom()?.toFixed(0))) - // setCurrentX(id, tileX) - // setCurrentY(id, tileY) + const pointerHandler = (e: MapBrowserEvent) => { + setCurrentCoordinate(id, e.coordinate) + const currentExtent = get('EPSG:3857')?.getExtent() as Extent + const { tileX, tileY } = getGridCellPosition(e.coordinate[0], e.coordinate[1], currentExtent, Number(map?.getView().getZoom()?.toFixed(0))) + setCurrentZ(id, Number(map?.getView().getZoom()?.toFixed(0))) + setCurrentX(id, tileX) + setCurrentY(id, tileY) - // const pixel = map?.getEventPixel(e.originalEvent) - // if (pixel) { - // map?.forEachFeatureAtPixel(pixel, function (feature, layer) { - // if (layer.get('type') === 'region') { - // if (feature.get('entity_id')) { - // setStatusText(id, feature.get('entity_id')) - // } - // } - // }) - // } - // }) + const pixel = map?.getEventPixel(e.originalEvent) + if (pixel) { + let found = false; + map?.forEachFeatureAtPixel(pixel, (feature, layer) => { + if (layer.get("type") === "region" && feature.get("entity_id")) { + found = true + + const name = getRegionsData()?.find(region => region.id === feature.get("entity_id"))?.name || feature.get("entity_id") || "" + setStatusText(id, name); + setStatusTextPosition(id, pixel[0], pixel[1]); + } + + if (layer.get("type") === "district" && feature.get("entity_id")) { + found = true + + const name = getDistrictsData()?.find(district => district.id === feature.get("entity_id"))?.name || feature.get("entity_id") || "" + setStatusText(id, name); + setStatusTextPosition(id, pixel[0], pixel[1]); + } + }); + + if (!found) { + setStatusText(id, ""); + } + } + } + + map.on('pointermove', pointerHandler) map.on('click', function (e: MapBrowserEvent) { if (getAlignMode(id)) { @@ -332,11 +355,22 @@ export const initializeMapState = ( if (pixel) { map?.forEachFeatureAtPixel(pixel, function (feature, layer) { if (layer) { - if (layer.get('type') === 'region') { + if (layer.get('type') === 'region' && layer.getOpacity() !== 0) { zoomToFeature(id, feature as Feature) if (feature.get('entity_id')) { setSelectedRegion(id, feature.get('entity_id')) + + //regionsLayer.setVisible(false) + regionsLayer.setOpacity(0) + } + } + + if (layer.get('type') === 'district' && layer.getOpacity() !== 0) { + zoomToFeature(id, feature as Feature) + + if (feature.get('entity_id')) { + setSelectedDistrict(id, feature.get('entity_id')) } } } @@ -360,7 +394,9 @@ export const initializeMapState = ( } }) - regionsLayer.setVisible(!isViewCovered) + if (!getSelectedRegion(id)) { + regionsLayer.setOpacity(isViewCovered ? 0 : 1) + } }) map.setView( @@ -386,7 +422,8 @@ export const initializeMapState = ( currentX: undefined, currentY: undefined, currentCoordinate: null, - statusText: '', + statusText: null, + statusTextPosition: [0, 0], satMapsProvider: 'google', selectedObjectType: null, alignMode: false, @@ -411,8 +448,8 @@ export const initializeMapState = ( staticMapLayer: staticMapLayer, figuresLayer: figuresLayer, linesLayer: linesLayer, + districtsLayer: districtsLayer, regionsLayer: regionsLayer, - citiesLayer: citiesLayer, districtBoundLayer: districtBoundLayer, imageLayer: imageLayer, selectedArea: null, @@ -421,6 +458,7 @@ export const initializeMapState = ( measureModify: measureModify, nodeLayer: nodeLayer, overlayLayer: overlayLayer, + districtSelect: districtSelect, regionSelect: regionSelect, lineSelect: lineSelect, previousView: null, @@ -644,7 +682,16 @@ export const setCurrentCoordinate = (id: string, c: Coordinate | null) => useMap } }) -export const setStatusText = (id: string, t: string) => useMapStore.setState((state) => { +export const setStatusTextPosition = (id: string, left: number, top: number) => useMapStore.setState((state) => { + return { + id: { + ...state.id, + [id]: { ...state.id[id], statusTextPosition: [left, top] } + } + } +}) + +export const setStatusText = (id: string, t: string | null) => useMapStore.setState((state) => { return { id: { ...state.id, diff --git a/client/src/store/objects.ts b/client/src/store/objects.ts index acefc72..9f35440 100644 --- a/client/src/store/objects.ts +++ b/client/src/store/objects.ts @@ -2,7 +2,7 @@ import { create } from 'zustand'; interface ObjectsState { id: Record(() => ({ export const initializeObjectsState = ( id: string, - selectedRegion: number | undefined, + selectedRegion: number | null, selectedDistrict: number | null, selectedCity: number | null, selectedYear: number | null, @@ -46,7 +46,7 @@ export const setSelectedCity = (id: string, city: number | null) => useObjectsSt }) export const getSelectedRegion = (id: string) => useObjectsStore.getState().id[id].selectedRegion -export const setSelectedRegion = (id: string, region: number | undefined) => useObjectsStore.setState((state) => { +export const setSelectedRegion = (id: string, region: number | null) => useObjectsStore.setState((state) => { return { id: { ...state.id, diff --git a/client/src/store/regions.ts b/client/src/store/regions.ts new file mode 100644 index 0000000..6af55cc --- /dev/null +++ b/client/src/store/regions.ts @@ -0,0 +1,36 @@ +import { create } from 'zustand'; +import { IDistrict, IRegion } from '../interfaces/gis'; + +export interface RegionsState { + regionsData: IRegion[], + districtsData: IDistrict[], +} + +export const useRegionsStore = create(() => ({ + regionsData: [], + districtsData: [] +})) + +export const getRegionData = (id: number) => { + return useRegionsStore.getState().regionsData.find(region => region.id === id) +} + +export const getRegionsData = () => { + return useRegionsStore.getState().regionsData +} + +export const setRegionsData = (regionsData: any) => { + useRegionsStore.setState(() => ({ regionsData: regionsData })) +} + +export const getDistrictData = (id: number) => { + return useRegionsStore.getState().districtsData.find(district => district.id === id) +} + +export const getDistrictsData = () => { + return useRegionsStore.getState().districtsData +} + +export const setDistrictsData = (districtsData: any) => { + useRegionsStore.setState(() => ({ districtsData: districtsData })) +} \ No newline at end of file