From bbaba97ad79b5a6c74bb05074b12ac649508c602 Mon Sep 17 00:00:00 2001 From: Chandana K V Date: Mon, 2 Mar 2026 01:48:17 +0530 Subject: [PATCH 1/2] Reset filters when location changes --- src/actions/getWaterbodyData.jsx | 365 ++-- src/components/buttons/download_button.jsx | 25 +- src/components/buttons/toggleButton.jsx | 38 +- src/components/kyl_leftSidebar.jsx | 7 +- src/components/landscape-explorer/map/Map.jsx | 35 + .../sidebar/RightSidebar.jsx | 346 ++-- .../utils/downloadHelper.js | 125 +- src/components/mapArea.jsx | 1627 ++++------------- src/pages/kyl_dashboard.jsx | 343 +--- 9 files changed, 860 insertions(+), 2051 deletions(-) diff --git a/src/actions/getWaterbodyData.jsx b/src/actions/getWaterbodyData.jsx index cb42d6c5..c42b355a 100644 --- a/src/actions/getWaterbodyData.jsx +++ b/src/actions/getWaterbodyData.jsx @@ -1,231 +1,180 @@ import getVectorLayers from "./getVectorLayers"; import GeoJSON from "ol/format/GeoJSON"; -import { Style, Fill, Stroke } from "ol/style"; +import { Style, Stroke } from "ol/style"; export const getWaterbodyData = async ({ - district, - block, - map, - waterbodyUID = null, - }) => { - console.log(district,block,waterbodyUID,map) - if ( - !district?.label || - !block?.label || - !map - ) { - console.warn("Missing district/block label in getWaterbodyData", { - district, - block, - }); - return null; - } + district, + block, + map, + waterbodyUID = null, +}) => { + + if (!district?.label || !block?.label || !map) { + console.warn("Missing district/block label in getWaterbodyData"); + return null; + } + + const dist = district.label.toLowerCase().replace(/\s+/g, "_"); + const blk = block.label.toLowerCase().replace(/\s+/g, "_"); + + const yellowWaterbodyStyle = new Style({ + stroke: new Stroke({ + color: "yellow", + width: 1.5, + }), + }); - const transformName = (name) => { - if (!name) return ""; - - // Extract base + alias from parentheses - const match = name.match(/^(.+?)\s*\((.+?)\)$/); - - let parts = []; - - if (match) { - const main = match[1]; - const alias = match[2]; - - parts = [main, alias]; - } else { - // no parentheses → repeat twice - parts = [name]; + const extractMwsUidList = (mwsUidString) => { + if (!mwsUidString) return []; + return mwsUidString.split("_").reduce((acc, val, idx, arr) => { + if (idx % 2 === 0 && arr[idx + 1]) { + acc.push(`${val}_${arr[idx + 1]}`); } - - return parts - .map((p) => - p - .replace(/[^\w\s-]/g, "") // remove special chars - .replace(/\s+/g, "_") // Space - .replace(/_+/g, "_") // collapse _ - .replace(/^_|_$/g, "") // trim _ - .toLowerCase() - ) - .join("_"); - }; - - const dist = transformName(district.label); - - const blk = transformName(block.label); - - const yellowWaterbodyStyle = new Style({ - stroke: new Stroke({ - color: "yellow", - width: 1.5, - }), + return acc; + }, []); + }; + + // ===================== WATERBODY ====================== + + const wbLayerName = `surface_waterbodies_${dist}_${blk}`; + const wbLayer = await getVectorLayers("swb", wbLayerName, false, true); + map.addLayer(wbLayer); + + wbLayer.setStyle(yellowWaterbodyStyle); + + const wbSource = wbLayer.getSource(); + const view = map.getView(); + const extent = view.calculateExtent(map.getSize()); + + wbSource.loadFeatures(extent, view.getResolution(), view.getProjection()); + const wbFeatures = await waitForFeatures(wbSource); + + let matchedWaterbody = null; + + if (waterbodyUID) { + matchedWaterbody = wbFeatures.find((f) => { + const uid = f.get("UID") || f.get("uid"); + return uid?.toString() === waterbodyUID.toString(); }); + } + + // ===================== MWS ====================== + + const mwsLayerName = `deltaG_well_depth_${dist}_${blk}`; + const mwsLayer = await getVectorLayers("mws_layers", mwsLayerName, false, true); + map.addLayer(mwsLayer); + + const mwsSource = mwsLayer.getSource(); + mwsSource.loadFeatures(extent, view.getResolution(), view.getProjection()); + const mwsFeatures = await waitForFeatures(mwsSource); + + let matchedMWS = []; + + if (matchedWaterbody) { + const wbMwsUID = + matchedWaterbody.get("MWS_UID") || + matchedWaterbody.get("mws_uid"); + + if (wbMwsUID) { + const mwsUidList = extractMwsUidList(wbMwsUID.toString()); - const extractMwsUidList = (mwsUidString) => { - if (!mwsUidString) return []; - - return mwsUidString - .split("_") - .reduce((acc, val, idx, arr) => { - // join pairs: 12 + 33823 → 12_33823 - if (idx % 2 === 0 && arr[idx + 1]) { - acc.push(`${val}_${arr[idx + 1]}`); - } - return acc; - }, []); - }; - - const wbLayerName = `surface_waterbodies_${dist}_${blk}`; - const wbLayer = await getVectorLayers("swb", wbLayerName, false, true); - map.addLayer(wbLayer); - - wbLayer.setStyle(yellowWaterbodyStyle); - - const wbSource = wbLayer.getSource(); - const view = map.getView(); - const extent = view.calculateExtent(map.getSize()); - - wbSource.loadFeatures(extent, view.getResolution(), view.getProjection()); - const wbFeatures = await waitForFeatures(wbSource); - - let matchedWaterbody = null; - - if (waterbodyUID) { - matchedWaterbody = wbFeatures.find((f) => { - const uid = f.get("UID") || f.get("uid"); - return uid?.toString() === waterbodyUID.toString(); + matchedMWS = mwsFeatures.filter((f) => { + const uid = (f.get("uid") || f.get("UID"))?.toString(); + return uid && mwsUidList.includes(uid.trim()); }); - - if (!matchedWaterbody) { - console.warn(" No waterbody matched UID:", waterbodyUID); - } - } - - const mwsLayerName = `deltaG_well_depth_${dist}_${blk}`; - const mwsLayer = await getVectorLayers( - "mws_layers", - mwsLayerName, - false, - true - ); - map.addLayer(mwsLayer); - - const mwsSource = mwsLayer.getSource(); - mwsSource.loadFeatures(extent, view.getResolution(), view.getProjection()); - const mwsFeatures = await waitForFeatures(mwsSource); - - - let matchedMWS = []; - - if (matchedWaterbody) { - const wbMwsUID = - matchedWaterbody.get("MWS_UID") || - matchedWaterbody.get("mws_uid"); - - if (wbMwsUID) { - // extract list like ["12_308838","12_311076","12_316294"] - const mwsUidList = extractMwsUidList(wbMwsUID.toString()); - - - matchedMWS = mwsFeatures.filter((f) => { - const uid = (f.get("uid") || f.get("UID"))?.toString(); - return uid && mwsUidList.includes(uid.trim()); - }); - } } + } -// ===================== ZOI FETCH ====================== -const zoiLayerName = `waterbodies_zoi_${dist}_${blk}`; + // ===================== ZOI ====================== -// Try multiple namespaces — some servers store ZOI differently -const zoiLayer = - (await getVectorLayers("swb", zoiLayerName, false, true)) || - (await getVectorLayers("zoi_layers", zoiLayerName, false, true)) || - null; + const zoiLayerName = `waterbodies_zoi_${dist}_${blk}`; - console.log("Zoi layer check:", { - dist, - blk, - try1: `swb:waterbodies_zoi_${dist}_${blk}`, - try2: `zoi_layers:waterbodies_zoi_${dist}_${blk}` - }); - + const zoiLayer = + (await getVectorLayers("swb", zoiLayerName, false, true)) || + (await getVectorLayers("zoi_layers", zoiLayerName, false, true)) || + null; -let rawZoiFeatures = []; -let matchedZOI = []; + let rawZoiFeatures = []; + let matchedZOI = []; -if (zoiLayer) { - map.addLayer(zoiLayer); + if (zoiLayer) { + map.addLayer(zoiLayer); - const zoiSource = zoiLayer.getSource(); - zoiSource.loadFeatures(extent, view.getResolution(), view.getProjection()); + const zoiSource = zoiLayer.getSource(); + zoiSource.loadFeatures(extent, view.getResolution(), view.getProjection()); - rawZoiFeatures = await waitForFeatures(zoiSource); + rawZoiFeatures = await waitForFeatures(zoiSource); - // Match only for selected WB - if (matchedWaterbody) { - const wbUid = - matchedWaterbody.get("UID")?.toString()?.trim() || - matchedWaterbody.get("uid")?.toString()?.trim(); - - matchedZOI = rawZoiFeatures.filter(f => { - const zUid = - f.get("UID")?.toString()?.trim() || - f.get("uid")?.toString()?.trim(); - return zUid === wbUid; - }); + if (matchedWaterbody) { + const wbUid = + matchedWaterbody.get("UID")?.toString()?.trim() || + matchedWaterbody.get("uid")?.toString()?.trim(); + + matchedZOI = rawZoiFeatures.filter((f) => { + const zUid = + f.get("UID")?.toString()?.trim() || + f.get("uid")?.toString()?.trim(); + return zUid === wbUid; + }); + } } -} -console.log("ZOI Layer fetched:", rawZoiFeatures.length); -console.log("ZOI matched:", matchedZOI.length); - - - - return { - wbLayer, - wbFeatures, - - waterbody: matchedWaterbody - ? { + + // ===================== FINAL RETURN ====================== + + return { + wbLayer, + wbFeatures, + + waterbody: matchedWaterbody + ? (() => { + const geo = new GeoJSON().writeFeatureObject(matchedWaterbody, { + dataProjection: "EPSG:4326", + featureProjection: "EPSG:4326", + }); + delete geo.properties; + return { olFeature: matchedWaterbody, - geojson: new GeoJSON().writeFeatureObject(matchedWaterbody, { - dataProjection: "EPSG:4326", - featureProjection: "EPSG:4326", - }), - } - : null, - - - mws: matchedMWS.length - ? matchedMWS.map(f => ({ + geojson: geo, + }; + })() + : null, + + mws: matchedMWS.length + ? matchedMWS.map((f) => { + const geo = new GeoJSON().writeFeatureObject(f, { + dataProjection: "EPSG:4326", + featureProjection: "EPSG:4326", + }); + delete geo.properties; + return { olFeature: f, - geojson: new GeoJSON().writeFeatureObject(f, { - dataProjection: "EPSG:4326", - featureProjection: "EPSG:4326", - }) - })) - : [], - - zoi: matchedZOI.length - ? matchedZOI.map(f => - new GeoJSON().writeFeatureObject(f, { - dataProjection: "EPSG:4326", - featureProjection: "EPSG:4326", + geojson: geo, + }; + }) + : [], + + zoi: matchedZOI.length + ? matchedZOI.map((f) => { + const geo = new GeoJSON().writeFeatureObject(f, { + dataProjection: "EPSG:4326", + featureProjection: "EPSG:4326", + }); + delete geo.properties; + return geo; }) - ) - : [], - - }; + : [], }; - - const waitForFeatures = (source) => - new Promise((resolve) => { - const interval = setInterval(() => { - const feats = source.getFeatures(); - if (feats.length > 0) { - clearInterval(interval); - resolve(feats); - } - }, 200); - }); +}; + +// ===================== WAIT FUNCTION ====================== + +const waitForFeatures = (source) => + new Promise((resolve) => { + const interval = setInterval(() => { + const feats = source.getFeatures(); + if (feats.length > 0) { + clearInterval(interval); + resolve(feats); + } + }, 200); + }); diff --git a/src/components/buttons/download_button.jsx b/src/components/buttons/download_button.jsx index 0067e490..1a5cb5ca 100755 --- a/src/components/buttons/download_button.jsx +++ b/src/components/buttons/download_button.jsx @@ -1,11 +1,20 @@ -import './download_button.css' +import "./download_button.css"; -const DownloadButton = ({name, onClickEvent, href, download, isDisabled}) => { - return( - - ) -} +const DownloadButton = ({ + name, + onClick = () => {}, + disabled = false +}) => { + return ( + + ); +}; export default DownloadButton; \ No newline at end of file diff --git a/src/components/buttons/toggleButton.jsx b/src/components/buttons/toggleButton.jsx index 97b0be3a..53b6b45f 100755 --- a/src/components/buttons/toggleButton.jsx +++ b/src/components/buttons/toggleButton.jsx @@ -1,17 +1,31 @@ -import '../css/toggleButton.css' +import '../css/toggleButton.css'; -const ToggleButton = ({currentLayers, handleCheckboxChange, checkboxId}) => { +const ToggleButton = ({ + currentLayers, + handleCheckboxChange, + checkboxId +}) => { - const handleCheckBoxToggle = (e) => { - handleCheckboxChange() - } + const isChecked = currentLayers.includes(checkboxId); - return ( -
- - -
- ) -} + return ( +
+ + +
+ ); +}; export default ToggleButton; \ No newline at end of file diff --git a/src/components/kyl_leftSidebar.jsx b/src/components/kyl_leftSidebar.jsx index 65cfb170..10eff3d3 100644 --- a/src/components/kyl_leftSidebar.jsx +++ b/src/components/kyl_leftSidebar.jsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import KYLIndicatorFilter from './kyl_indicatorFilter'; import KYLPatternDisplay from './kyl_patternDisplay'; @@ -33,6 +33,11 @@ const KYLLeftSidebar = ({ // State to track selected pattern subcategory const [selectedSubcategory, setSelectedSubcategory] = useState(null); + useEffect(() => { + setActiveTab('Filters'); + setSelectedSubcategory(null); + setIndicatorType(null); // IMPORTANT +}, []); const combinedSelectedValues = { ...filterSelections.selectedMWSValues, ...filterSelections.selectedVillageValues diff --git a/src/components/landscape-explorer/map/Map.jsx b/src/components/landscape-explorer/map/Map.jsx index 928e802e..576c28c1 100644 --- a/src/components/landscape-explorer/map/Map.jsx +++ b/src/components/landscape-explorer/map/Map.jsx @@ -1505,6 +1505,41 @@ const Map = forwardRef(({ LayersArray[3].LayerRef.current = MicroWaterShedLayer; } + // === Hydrological Boundaries Layer === +let HydrologicalBoundariesLayer = await getVectorLayers( + "hydrological_boundaries", + district.label.toLowerCase().replace(/\s*\(\s*/g, '_') + .replace(/\s*\)\s*/g, '') + .replace(/\s+/g, '_') + + "_" + + block.label.toLowerCase().replace(/\s*\(\s*/g, '_') + .replace(/\s*\)\s*/g, '') + .replace(/\s+/g, '_'), + true, + true +); + +if (HydrologicalBoundariesLayer) { + HydrologicalBoundariesLayer.setStyle(function (feature) { + return new Style({ + stroke: new Stroke({ + color: "#000000", + width: 1.5, + }), + fill: new Fill({ + color: "rgba(0, 0, 255, 0.2)", + }), + }); + }); + + if (LayersArray[3].LayerRef.current != null) { + safeRemoveLayer(LayersArray[3].LayerRef.current); + } + + LayersArray[3].LayerRef.current = HydrologicalBoundariesLayer; +} + + // === CLART Layer === let clartLayer = await getImageLayers( "clart", diff --git a/src/components/landscape-explorer/sidebar/RightSidebar.jsx b/src/components/landscape-explorer/sidebar/RightSidebar.jsx index c14656da..6c860882 100644 --- a/src/components/landscape-explorer/sidebar/RightSidebar.jsx +++ b/src/components/landscape-explorer/sidebar/RightSidebar.jsx @@ -1,4 +1,5 @@ import { useState, useEffect } from 'react'; +import DownloadButton from '../../buttons/download_button'; import SelectButton from '../../buttons/select_button'; import { downloadGeoJson, @@ -7,12 +8,6 @@ import { downloadExcel } from '../utils/downloadHelper'; -// SVG Icons -const ChevronLeftIcon = () => ( - - - -); const ChevronRightIcon = () => ( @@ -56,7 +51,15 @@ const landLayersData = [ const climateLayersData = [ { id: 1, name: "mws_layers", label: "Hydrological Variables (Precipitation, ET, Groundwater, etc.)", hasGeojson: true, hasKml: true, hasStyle : true }, - { id: 2, name: "mws_layers_fortnight", label: "Fortnightly Hydrological Variables (Precipitation, ET, Groundwater, etc.)", hasGeojson: true, hasKml: true, hasStyle : false } + { id: 2, name: "mws_layers_fortnight", label: "Fortnightly Hydrological Variables (Precipitation, ET, Groundwater, etc.)", hasGeojson: true, hasKml: true, hasStyle : false }, + { + id: 3, + name: "hydrological_boundaries", + label: "Hydrological Boundaries (Precipitation, ET, Groundwater, etc.)", + hasGeojson: true, + hasKml: true, + hasStyle : true + } ] const hydrologyLayersData = [ @@ -68,7 +71,7 @@ const hydrologyLayersData = [ ] const agriLayersData = [ - { id: "lulc_level_3", name:"lulc_level_2", label: "LULC Layer Level 3" }, + { id: "lulc_level_3", name:"lulc_level_3", label: "LULC Layer Level 3" }, { id: 1, name: "cropping_intensity", label: "Cropping Intensity", hasGeojson: true, hasKml: true, hasStyle : true }, { id: 2, name: "drought", label: "Drought", hasGeojson: true, hasKml: true, hasStyle : true }, ] @@ -104,118 +107,38 @@ const yearDataLulc = [ { label: "2024-2025", value: "24_25" } ]; -// Enhanced DownloadButton component to replace your current one -const DownloadButton = ({ - name, - onClickEvent, - href, - download, - isDisabled = false, - className = "" -}) => { - const handleClick = (e) => { - if (isDisabled) { - e.preventDefault(); - return; - } - - if (onClickEvent) { - e.preventDefault(); - onClickEvent(); - } - }; - - const buttonClasses = `px-2 py-1 bg-[#EDE9FE] text-[#8B5CF6] rounded-md text-xs - hover:bg-[#DDD6FE] text-center transition-colors duration-200 - flex items-center justify-center ${isDisabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'} ${className}`; - - return href ? ( - - - {name} - - ) : ( - - ); +const STYLE_DOWNLOAD_URLS = { + afforestation: "https://drive.google.com/file/d/10RvFu28sIa-OpQvJ2z6D8-V5RROUUeZz/view?usp=drive_link", + deforestation: "https://drive.google.com/file/d/1MFKAXiW5mpfCoBBMJR-K7Y5O_Uwp0kOR/view?usp=drive_link", + terrain_vector: "https://drive.google.com/file/d/1RTogX5nacJYQLP2IFMQiQEBrQyyqPf-G/view?usp=sharing", + degradation: "https://drive.google.com/file/d/1tPtEqhWO_RisycKnK8Bl_2yEnrfgWqfE/view?usp=drive_link", + urbanization: "https://drive.google.com/file/d/16JHaWXxdq5y-g2wr5D_f7OB70jiA9QuA/view?usp=sharing", + cropintensity: "https://drive.google.com/file/d/13cgF1Cg6YWZMCQXH7XV7cITxsg9v2SBu/view?usp=sharing", + restoration: "https://drive.google.com/file/d/1JANwwxGDpy5vUkM2v8wqJDUKbVS8I72u/view?usp=sharing", + clart: "https://drive.google.com/file/d/1B8ibmiv8dBNYZZ1gZWIp4AQPdu82t1yl/view?usp=drive_link", + drainage: "https://drive.google.com/file/d/1s57ufrKk_iKWxIJTpy_S1Yt3nQD0DMjc/view?usp=drive_link", + terrain: "https://drive.google.com/file/d/1gMh9Dj3ICJuw1vqgP9vEI9oIU_PLNsPs/view?usp=sharing", + lulc_level_1: "https://drive.google.com/file/d/1mIVKi9N5QQI3QqFYj9y8uJGet5oRAVqA/view?usp=sharing", + lulc_level_2: "https://drive.google.com/file/d/1q7Tzs7zwn3T4jhRqqYc7RgCNAktkWa9m/view?usp=drive_link", + lulc_level_3: "https://drive.google.com/file/d/1GFc7W2AtlrYJbnveWkT08uSyeTasFQxT/view?usp=drive_link", + soge: "https://drive.google.com/file/d/1iSgiTZOCxQ6t0tYVgVSI059Cz-3YimuR/view?usp=sharing", + aquifer: "https://drive.google.com/file/d/1xHjtq893yQcCfBsuQ0G_SKko111xkv6F/view?usp=sharing", + drought: "https://drive.google.com/file/d/1BIDbbsLaFxBO4YHMX-vyEt0VTSJLLlmL/view?usp=sharing", + cropping_intensity: "https://drive.google.com/file/d/1cAZBQu4DUUPUS3u3VZtCzK4PYuSDgflW/view?usp=sharing", + mws_layers: "https://github.com/core-stack-org/QGIS-Styles/tree/main/Climate", + cropIntensity: "https://drive.google.com/file/d/1OkjCjs2RF0kLCMpgnM3REE4of1GpDisn/view?usp=sharing", }; const handleStyleDownload = (layerName) => { - let url = "" - console.log(typeof(layerName)) - switch(layerName){ - case "afforestation" : - url = "https://drive.google.com/file/d/10RvFu28sIa-OpQvJ2z6D8-V5RROUUeZz/view?usp=drive_link" - break; - case "deforestation" : - url = "https://drive.google.com/file/d/1MFKAXiW5mpfCoBBMJR-K7Y5O_Uwp0kOR/view?usp=drive_link" - break; - case "terrain_vector": - url = "https://drive.google.com/file/d/1RTogX5nacJYQLP2IFMQiQEBrQyyqPf-G/view?usp=sharing" - break; - case "degradation": - url = "https://drive.google.com/file/d/1tPtEqhWO_RisycKnK8Bl_2yEnrfgWqfE/view?usp=drive_link" - break; - case "urbanization": - url = "https://drive.google.com/file/d/16JHaWXxdq5y-g2wr5D_f7OB70jiA9QuA/view?usp=sharing" - break; - case "cropintensity": - url = "https://drive.google.com/file/d/13cgF1Cg6YWZMCQXH7XV7cITxsg9v2SBu/view?usp=sharing" - break; - case "restoration": - url = "https://drive.google.com/file/d/1JANwwxGDpy5vUkM2v8wqJDUKbVS8I72u/view?usp=sharing" - break; - case "clart": - url = "https://drive.google.com/file/d/1B8ibmiv8dBNYZZ1gZWIp4AQPdu82t1yl/view?usp=drive_link" - break; - case "drainage": - url = "https://drive.google.com/file/d/1s57ufrKk_iKWxIJTpy_S1Yt3nQD0DMjc/view?usp=drive_link" - break; - case "terrain": - url = "https://drive.google.com/file/d/1gMh9Dj3ICJuw1vqgP9vEI9oIU_PLNsPs/view?usp=sharing" - break; - case "lulc_level_1": - url = "https://drive.google.com/file/d/1mIVKi9N5QQI3QqFYj9y8uJGet5oRAVqA/view?usp=sharing" - break; - case "lulc_level_2": - url = "https://drive.google.com/file/d/1q7Tzs7zwn3T4jhRqqYc7RgCNAktkWa9m/view?usp=drive_link" - break; - case "lulc_level_3": - url = "https://drive.google.com/file/d/1GFc7W2AtlrYJbnveWkT08uSyeTasFQxT/view?usp=drive_link" - break; - case "soge": - url = "https://drive.google.com/file/d/1iSgiTZOCxQ6t0tYVgVSI059Cz-3YimuR/view?usp=sharing" - break; - case "aquifer": - url = "https://drive.google.com/file/d/1xHjtq893yQcCfBsuQ0G_SKko111xkv6F/view?usp=sharing" - break; - case "drought": - url = "https://drive.google.com/file/d/1BIDbbsLaFxBO4YHMX-vyEt0VTSJLLlmL/view?usp=sharing" - break; - case "cropping_intensity": - url = "https://drive.google.com/file/d/1cAZBQu4DUUPUS3u3VZtCzK4PYuSDgflW/view?usp=sharing" - break; - case "mws_layers": - url = "https://github.com/core-stack-org/QGIS-Styles/tree/main/Climate" - break; - case "cropIntensity": - url = "https://drive.google.com/file/d/1OkjCjs2RF0kLCMpgnM3REE4of1GpDisn/view?usp=sharing" - break; + const url = STYLE_DOWNLOAD_URLS[layerName]; + + if (!url) { + console.warn(`No style available for ${layerName}`); + return; } window.open(url, "_blank"); -} +}; // Single Layer Item Component const LayerItem = ({ layer, isSelected, onToggle, onDownload, isLayersFetched, isLoading }) => { @@ -241,34 +164,36 @@ const LayerItem = ({ layer, isSelected, onToggle, onDownload, isLayersFetched, i
{layer.hasGeojson && ( onDownload(layer.name, 'geojson')} - isDisabled={!isLayersFetched || isLoading} - className="bg-[#EDE9FE] text-[#8B5CF6] hover:bg-[#DDD6FE]" - /> + name="GeoJSON" + onClick={() => onDownload(layer.name, 'geojson')} + disabled={!isLayersFetched || isLoading} + className="bg-[#EDE9FE] text-[#8B5CF6] hover:bg-[#DDD6FE]" +/> )} {layer.hasKml && ( onDownload(layer.name, 'kml')} - isDisabled={!isLayersFetched || isLoading} - className="bg-[#EDE9FE] text-[#8B5CF6] hover:bg-[#DDD6FE]" - /> + name="KML" + onClick={() => onDownload(layer.name, 'kml')} + disabled={!isLayersFetched || isLoading} + className="bg-[#EDE9FE] text-[#8B5CF6] hover:bg-[#DDD6FE]" +/> )} {layer.hasGeoTiff && ( - onDownload(layer.name, 'geotiff')} - isDisabled={!isLayersFetched || isLoading} - className="bg-[#EDE9FE] text-[#8B5CF6] hover:bg-[#DDD6FE]" - /> + onDownload(layer.name, 'geotiff')} + disabled={!isLayersFetched || isLoading} + className="bg-[#EDE9FE] text-[#8B5CF6] hover:bg-[#DDD6FE]" +/> )} - {layer.hasStyle && ( handleStyleDownload(layer.name)} - isDisabled={!isLayersFetched || isLoading} - className="bg-[#EDE9FE] text-[#8B5CF6] hover:bg-[#DDD6FE]" - />) + {layer.hasStyle && ( + handleStyleDownload(layer.name)} + disabled={!isLayersFetched || isLoading} + className="bg-[#EDE9FE] text-[#8B5CF6] hover:bg-[#DDD6FE]" +/> + ) }
)} @@ -292,18 +217,18 @@ const LulcSelector = ({ level, lulcYear, setLulcYear, onDownload, isLayersFetche
onDownload(level.id, 'geotiff')} - isDisabled={!lulcYear || !isLayersFetched || isLoading} - className={`${!lulcYear ? 'bg-gray-100 text-gray-400' : ''}`} - /> + name="GeoTIFF" + onClick={() => onDownload(level.id, 'geotiff')} + disabled={!lulcYear || !isLayersFetched || isLoading} + className={`${!lulcYear ? 'bg-gray-100 text-gray-400' : ''}`} +/> handleStyleDownload(level.id)} - isDisabled={!isLayersFetched || isLoading} - className="bg-[#EDE9FE] text-[#8B5CF6] hover:bg-[#DDD6FE]" - /> + name="Style" + onClick={() => handleStyleDownload(level.id)} + disabled={!isLayersFetched || isLoading} + className="bg-[#EDE9FE] text-[#8B5CF6] hover:bg-[#DDD6FE]" +/>
); @@ -354,7 +279,7 @@ const RightSidebar = ({ lulcYear3, setLulcYear3 }) => { - const [selectedCategory, setSelectedCategory] = useState('basic'); + const [selectedCategory, setSelectedCategory] = useState('land'); const [isLayersFetched, setIsLayersFetched] = useState(false); @@ -375,14 +300,12 @@ const RightSidebar = ({ }, [district, block, canFetchLayers]); // Handle toggle clicklandLayersData - const handleToggleClick = (filterName) => { - // If there's a handleLayerToggle prop, call it - console.log(filterName) - if (handleLayerToggle) { - const currentState = toggledLayers?.[filterName] || false; - handleLayerToggle(filterName, !currentState); - } - }; + const handleToggleClick = (filterName) => { + if (!handleLayerToggle) return; + + const currentState = toggledLayers?.[filterName] || false; + handleLayerToggle(filterName, !currentState); +}; // Handle download click with proper URL formatting and direct download const handleDownloadClick = (filterName, format) => { if (!district || !block) { @@ -433,7 +356,12 @@ const RightSidebar = ({ case 'cropping_intensity': url = `https://geoserver.core-stack.org:8443/geoserver/crop_intensity/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=crop_intensity:${districtFormatted}_${blockFormatted}_intensity&outputFormat=application/json&screen=main`; break; - default: + case 'hydrological_boundaries': + url = `https://geoserver.core-stack.org:8443/geoserver/ows?service=WFS&version=1.1.0&request=GetFeature&typeName=mws_layers:deltaG_well_depth_${districtFormatted}_${blockFormatted}&outputFormat=application/json`; + break; + + + default: url = `https://geoserver.core-stack.org:8443/geoserver/${filterName}/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=${filterName}:${districtFormatted}_${blockFormatted}&outputFormat=application/json&screen=main`; } @@ -479,7 +407,14 @@ const RightSidebar = ({ break; case 'cropping_intensity': url = `https://geoserver.core-stack.org:8443/geoserver/crop_intensity/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=crop_intensity:${districtFormatted}_${blockFormatted}_intensity&outputFormat=application/vnd.google-earth.kml+xml&screen=main`; - break + break; + case 'hydrological_boundaries': + url = `https://geoserver.core-stack.org:8443/geoserver/ows?service=WFS&version=1.1.0&request=GetFeature&typeName=mws_layers:deltaG_well_depth_${districtFormatted}_${blockFormatted}&outputFormat=application/vnd.google-earth.kml+xml`; + break; + + + + default: url = `https://geoserver.core-stack.org:8443/geoserver/${filterName}/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=${filterName}:${districtFormatted}_${blockFormatted}&outputFormat=application/vnd.google-earth.kml+xml&screen=main`; } @@ -558,28 +493,18 @@ const RightSidebar = ({ } }; - // Handle Excel download with enhanced functionality const handleLocalExcelDownload = () => { - if (!state || !district || !block) { - alert('Please select a state, district, and block first'); - return; - } - - const url = `https://geoserver.core-stack.org/api/v1/download_excel_layer?state=${state.label}&district=${district.label}&block=${block.label}`; - - // Use the Excel download function from parent component or our local version - if (handleExcelDownload) { - handleExcelDownload(url, `${block.label}_data.xlsx`); - } else { - // Fallback to our own implementation if parent doesn't provide one - downloadExcel(url, `${block.label}_data.xlsx`) - .finally(() => { - console.log("Excel download complete"); - }); - } - }; + if (!state || !district || !block) { + alert("Please select a state, district, and block first"); + return; + } + const url = + `https://geoserver.core-stack.org/api/v1/download_excel_layer` + + `?state=${state.label}&district=${district.label}&block=${block.label}`; + downloadExcel(url, `${block.label}_data.xlsx`); +}; return (
@@ -665,26 +590,32 @@ const RightSidebar = ({ {selectedCategory === 'land' && (
{landLayersData.map(layer => { - if(layer.id === "lulc_level_1"){ - return ; - } - else if(layer.id === "lulc_level_2"){ - return ; - } + if (layer.id === "lulc_level_1") { + return ( + + ); +} + else if (layer.id === "lulc_level_2") { + return ( + + ); +} else{ return {agriLayersData.map(layer => { - if(layer.id === "lulc_level_3"){ - return ; - } + if (layer.id === "lulc_level_3") { + return ( + + ); +} else{ return { + const objectUrl = URL.createObjectURL(blob); -// For GeoJSON, we need to fetch the data and force a download as browsers tend to open JSON files + const link = document.createElement("a"); + link.href = objectUrl; + link.download = filename; + + document.body.appendChild(link); + link.click(); + + setTimeout(() => { + document.body.removeChild(link); + URL.revokeObjectURL(objectUrl); + }, 100); +}; + +// ---------- GEOJSON ---------- export const downloadGeoJson = async (url, layerName) => { try { const response = await fetch(url); - if (!response.ok) { - throw new Error(`HTTP error! Status: ${response.status}`); + if (!response.ok) throw new Error(response.status); + + const json = await response.json(); + + if (json.features?.length) { + json.features = json.features.map(feature => ({ + type: "Feature", + id: feature.id, + geometry: feature.geometry, + geometry_name: feature.geometry_name || "the_geom", + properties: null + })); } - - const data = await response.text(); - - // Create a blob from the data with the correct MIME type - const blob = new Blob([data], { type: 'application/json' }); - const objectUrl = URL.createObjectURL(blob); - - // Create and click a download link - const link = document.createElement('a'); - link.href = objectUrl; - link.setAttribute('download', `${layerName}_features.json`); - document.body.appendChild(link); - link.click(); - - // Clean up - setTimeout(() => { - document.body.removeChild(link); - URL.revokeObjectURL(objectUrl); - }, 100); + + const blob = new Blob( + [JSON.stringify(json, null, 2)], + { type: "application/json" } + ); + + triggerDownload(blob, `${layerName}_features.json`); + } catch (error) { - console.error('Error downloading GeoJSON:', error); - alert('Failed to download GeoJSON. Please try again.'); + console.error("GeoJSON download error:", error); + alert("Failed to download GeoJSON."); } }; -// KML downloads usually work fine with direct link approach +// ---------- KML ---------- export const downloadKml = (url, layerName) => { - const link = document.createElement('a'); + const link = document.createElement("a"); link.href = url; - link.setAttribute('download', `${layerName}_features.kml`); - document.body.appendChild(link); + link.download = `${layerName}_features.kml`; link.click(); - - // Clean up - setTimeout(() => { - document.body.removeChild(link); - }, 100); }; -// For GeoTIFF files, window.open is usually the best approach -export const downloadGeoTiff = (url, layerName) => { - // GeoTIFF files are typically served by WCS services that require window.open - window.open(url); +// ---------- GEOTIFF ---------- +export const downloadGeoTiff = (url) => { + window.open(url, "_blank"); }; -// For Excel downloads, use the direct fetch approach for blob data +// ---------- EXCEL ---------- export const downloadExcel = async (url, filename) => { try { const response = await fetch(url, { - method: "GET", headers: { - "ngrok-skip-browser-warning": "1", - "Content-Type": "blob", - }, + "ngrok-skip-browser-warning": "1" + } }); - - if (!response.ok) { - throw new Error(`HTTP error! Status: ${response.status}`); - } - - const arybuf = await response.arrayBuffer(); - const objectUrl = URL.createObjectURL(new Blob([arybuf])); - - const link = document.createElement('a'); - link.href = objectUrl; - link.setAttribute('download', filename || 'download.xlsx'); - document.body.appendChild(link); - link.click(); - - // Clean up - setTimeout(() => { - document.body.removeChild(link); - URL.revokeObjectURL(objectUrl); - }, 100); - + + if (!response.ok) throw new Error(response.status); + + const buffer = await response.arrayBuffer(); + const blob = new Blob([buffer]); + + triggerDownload(blob, filename || "download.xlsx"); + return true; } catch (error) { - console.error('Excel download error:', error); - alert('Failed to download Excel. Please try again.'); + console.error("Excel download error:", error); + alert("Failed to download Excel."); return false; } }; \ No newline at end of file diff --git a/src/components/mapArea.jsx b/src/components/mapArea.jsx index 9e8f73bf..66cf2b7e 100755 --- a/src/components/mapArea.jsx +++ b/src/components/mapArea.jsx @@ -1,19 +1,15 @@ import { useEffect, useRef, useState } from "react"; - import "ol/ol.css"; import { Icon, Style, Stroke, Fill } from "ol/style.js"; - import XYZ from "ol/source/XYZ"; import { Map, View, Feature } from "ol"; import Point from "ol/geom/Point.js"; import VectorLayer from "ol/layer/Vector"; import TileLayer from "ol/layer/Tile"; import VectorSource from "ol/source/Vector"; -import WebGLPointsLayer from 'ol/layer/WebGLPoints.js'; - +import WebGLPointsLayer from "ol/layer/WebGLPoints.js"; import { ToastContainer, toast } from "react-toastify"; import "react-toastify/dist/ReactToastify.css"; - import GeoJSON from "ol/format/GeoJSON"; import KML from "ol/format/KML.js"; @@ -21,6 +17,7 @@ import getStates from "../actions/getStates"; import getPlans from "../actions/getPlans"; import getVectorLayers from "../actions/getVectorLayers"; import getImageLayer from "../actions/getImageLayers"; +import getWebGlLayers from "../actions/getWebGlLayers"; import mapMarker from "../assets/map_marker.svg"; import well_mrker from "../assets/well_proposed.svg"; @@ -33,149 +30,84 @@ import check_dam_proposed from "../assets/check_dam_proposed.svg"; import land_leveling_proposed from "../assets/land_leveling_proposed.svg"; import livelihood_proposed from "../assets/livelihood_proposed.svg"; -//? Temprorary Imports -import landscape_icon from "../assets/eco.png"; -import getWebGlLayers from "../actions/getWebGlLayers"; import ToggleButton from "./buttons/toggleButton"; import DownloadButton from "./buttons/download_button"; import FetchButton from "./buttons/fetch_button"; import SelectButton from "./buttons/select_button"; +// ✅ Utility function +const formatName = (name) => + name + ?.toLowerCase() + .replace(/\s*\(\s*/g, "_") + .replace(/\s*\)\s*/g, "") + .replace(/\s+/g, "_"); + const MapArea = () => { + // ✅ Refs for map and layers let mapElement = useRef(null); let mapRef = useRef(null); let BaseLayerRef = useRef(null); + let markersLayer = useRef(null); - //? Layers Ref Group - let LayersArray = [ + // ✅ Layers Arrays + const LayersArray = useRef([ { LayerRef: useRef(null), name: "Demographics", isRaster: false }, { LayerRef: useRef(null), name: "Drainage", isRaster: false }, - { - LayerRef: useRef(null), - name: "Remote-Sensed Waterbodies", - isRaster: false, - }, + { LayerRef: useRef(null), name: "Remote-Sensed Waterbodies", isRaster: false }, { LayerRef: useRef(null), name: "Hydrological Boundries", isRaster: false }, { LayerRef: useRef(null), name: "CLART", isRaster: true }, { LayerRef: useRef(null), name: "Hydrological Variables", isRaster: false }, { LayerRef: useRef(null), name: "NREGA", isRaster: false }, { LayerRef: useRef(null), name: "Drought", isRaster: false }, { LayerRef: useRef(null), name: "Terrain", isRaster: true }, - { - LayerRef: useRef(null), - name: "Administrative Boundaries", - isRaster: false, - }, + { LayerRef: useRef(null), name: "Administrative Boundaries", isRaster: false }, { LayerRef: useRef(null), name: "Cropping Intensity", isRaster: false }, { LayerRef: useRef(null), name: "Terrain Vector", isRaster: false }, { LayerRef: useRef(null), name: "Terrain Lulc Slope", isRaster: false }, { LayerRef: useRef(null), name: "Terrain Lulc Plain", isRaster: false }, - ]; - let ResourceLayersArray = [ + ]).current; + + const ResourceLayersArray = useRef([ { LayerRef: useRef(null), name: "Settlement" }, - { LayerRef: useRef(null), name: "Water Structure" }, - { LayerRef: useRef(null), name: "Well Structure" }, - ]; - let PlanningLayersArray = [ - { LayerRef: useRef(null), name: "Agriculture Structure" }, - { LayerRef: useRef(null), name: "Livelihood Structure" }, - { LayerRef: useRef(null), name: "Recharge Structures" }, - ]; + { LayerRef: useRef(null), name: "Water Structures" }, + { LayerRef: useRef(null), name: "Well" }, + ]).current; - let markersLayer = useRef(null); + const PlanningLayersArray = useRef([ + { LayerRef: useRef(null), name: "Agri Structures" }, + { LayerRef: useRef(null), name: "Livelihood" }, + { LayerRef: useRef(null), name: "Water Structures" }, + ]).current; + // ✅ State setup const [stateData, setStateData] = useState(null); - - //? States for handling the Selection of states, district and block const [state, setState] = useState(null); const [district, setDistrict] = useState(null); const [block, setBlock] = useState(null); - let unAvailableStates = []; - //? States for Handling the plan selection const [plans, setPlans] = useState(null); const [selectedPlan, setSelectedPlan] = useState(null); - //? LULC Toggle Group - const [lulcYear1, setLulcYear1] = useState(null); - const [lulcYear2, setLulcYear2] = useState(null); - const [lulcYear3, setLulcYear3] = useState(null); - - //? Layers Present const [isLayersFetched, setIsLayersFetched] = useState(false); const [isOtherLayersFetched, setIsOtherLayersFetched] = useState(false); - - //? Miscellaneous States and Variables const [isLoading, setIsLoading] = useState(false); const [isDownloading, setIsDownloading] = useState(false); const [isLayersLoading, setIsLayersLoading] = useState(false); const [hrefData, setHrefData] = useState(null); const [currentLayers, setCurrentLayers] = useState(["Demographics", "NREGA"]); - const terrainClusterColors = ["#324A1C", "#97C76B", "#673A13", "#E5E059"]; - - function changePolygonColor(color) { - return new Style({ - fill: new Fill({ - color: color, - opacity: 0.4, - }), - stroke: new Stroke({ - color: "transparent", - width: 0, - }), - }); - } - - const drainageColors = [ - "03045E", - "023E8A", - "0077B6", - "0096C7", - "00B4D8", - "48CAE4", - "90E0EF", - "ADE8F4", - "CAF0F8", - ]; - - const yearDataLulc = [ - { - label: "2016-2017", - value: "16_17", - }, - { - label: "2017-2018", - value: "17_18", - }, - { - label: "2018-2019", - value: "18_19", - }, - { - label: "2019-2020", - value: "19_20", - }, - { - label: "2020-2021", - value: "20_21", - }, - { - label: "2021-2022", - value: "21_22", - }, - { - label: "2022-2023", - value: "22_23", - }, - ]; const [bbox, setBBox] = useState(null); + // ✅ Cached names for performance + const districtName = district ? formatName(district.label) : null; + const blockName = block ? formatName(block.label) : null; + // ✅ Helper Functions + const getblockFeatures = async (data) => { let coordinates = null; - let AdminURl = `https://geoserver.core-stack.org:8443/geoserver/panchayat_boundaries/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=panchayat_boundaries:${data.district.toLowerCase().split(" ").join("_")}_${data.block.toLowerCase().split(" ").join("_")}&outputFormat=application/json&screen=main`; - console.log(AdminURl) + try { await fetch(AdminURl) .then((res) => res.json()) @@ -184,19 +116,16 @@ const MapArea = () => { }); } catch (e) { console.log("error in fetching for : ", data.block.toLowerCase()); - unAvailableStates.push(data); return { coordinates: [], data: data }; } + return { coordinates: coordinates, data: data }; }; const getStatesData = async () => { let data = await getStates(); - let temp_blockNames = []; - console.log(data); - data.map((item) => { let tempDS = { state: item.label, @@ -208,47 +137,27 @@ const MapArea = () => { }); let layer_features = await Promise.all( - temp_blockNames.map((item) => { - return getblockFeatures(item); - }) - ).then((res) => { - return res.map((item) => { + temp_blockNames.map((item) => getblockFeatures(item)) + ).then((res) => + res.map((item) => { return new Feature({ geometry: new Point(item.coordinates), data: item.data, }); - }); - }); + }) + ); const StateMarkers = new Style({ - image: new Icon({ - src: mapMarker, - }), + image: new Icon({ src: mapMarker }), }); let StateLevelLayer = new VectorLayer({ - source: new VectorSource({ - features: layer_features, - }), + source: new VectorSource({ features: layer_features }), style: StateMarkers, }); - let availableData = []; - let dataLen = unAvailableStates.length; - - data.map((item) => { - for (let i = 0; i < dataLen; ++i) { - if (item.label === unAvailableStates[i].state) { - return; - } - } - availableData.push(item); - }); - - setStateData(availableData); - + setStateData(data); mapRef.current.addLayer(StateLevelLayer); - markersLayer.current = StateLevelLayer; }; @@ -264,36 +173,28 @@ const MapArea = () => { let temp_coordinates = null; let layer_features = await Promise.all( - temp_blocks.map((item) => { - return getblockFeatures(item); - }) - ).then((res) => { - return res.map((item) => { + temp_blocks.map((item) => getblockFeatures(item)) + ).then((res) => + res.map((item) => { if (temp_coordinates == null) temp_coordinates = item.coordinates; return new Feature({ geometry: new Point(item.coordinates), data: item.data, }); - }); - }); + }) + ); const StateMarkers = new Style({ - image: new Icon({ - src: mapMarker, - }), + image: new Icon({ src: mapMarker }), }); let districtLevelLayer = new VectorLayer({ - source: new VectorSource({ - features: layer_features, - }), + source: new VectorSource({ features: layer_features }), style: StateMarkers, }); mapRef.current.removeLayer(markersLayer.current); - mapRef.current.addLayer(districtLevelLayer); - markersLayer.current = districtLevelLayer; mapRef.current.getView().setCenter(temp_coordinates); @@ -301,659 +202,314 @@ const MapArea = () => { }; const getBlockData = async () => { - const temp_blocks = district.blocks.map((item) => { - return { district: district.label, block: item.label }; - }); + const districtName = formatName(district.label); + const temp_blocks = district.blocks.map((item) => ({ + district: districtName, + block: formatName(item.label), + })); let temp_coordinates = null; let layer_features = await Promise.all( - temp_blocks.map((item) => { - return getblockFeatures(item); - }) - ).then((res) => { - return res.map((item) => { + temp_blocks.map((item) => getblockFeatures(item)) + ).then((res) => + res.map((item) => { if (temp_coordinates == null) temp_coordinates = item.coordinates; - return new Feature({ geometry: new Point(item.coordinates), data: item.data, }); - }); - }); + }) + ); const StateMarkers = new Style({ - image: new Icon({ - src: mapMarker, - }), + image: new Icon({ src: mapMarker }), }); let blockLevelLayer = new VectorLayer({ - source: new VectorSource({ - features: layer_features, - }), + source: new VectorSource({ features: layer_features }), style: StateMarkers, }); mapRef.current.removeLayer(markersLayer.current); - mapRef.current.addLayer(blockLevelLayer); - markersLayer.current = blockLevelLayer; mapRef.current.getView().setCenter(temp_coordinates); mapRef.current.getView().setZoom(11); }; - + // ✅ Effects for initializing map useEffect(() => { - getStatesData(); - - let BaseLayer = new TileLayer({ - source: new XYZ({ - url: "https://www.google.cn/maps/vt?lyrs=s@189&gl=cn&x={x}&y={y}&z={z}", - maxZoom: 30, - }), - visible: true, - }); - - BaseLayerRef.current = BaseLayer; - const view = new View({ - center: [99.9, 23.6], - zoom: 5, - projection: "EPSG:4326", - }); - - const initialMap = new Map({ - target: mapElement.current, - layers: [BaseLayer], - view: view, + const BaseLayer = new TileLayer({ + source: new XYZ({ + url: "https://www.google.cn/maps/vt?lyrs=s@189&gl=cn&x={x}&y={y}&z={z}", + maxZoom: 30, + }), + visible: true, + }); + + BaseLayerRef.current = BaseLayer; + + const view = new View({ + center: [99.9, 23.6], + zoom: 5, + projection: "EPSG:4326", + }); + + const initialMap = new Map({ + target: mapElement.current, + layers: [BaseLayer], + view, + }); + + mapRef.current = initialMap; + + // ✅ NOW SAFE + getStatesData(); + + initialMap.on("singleclick", (e) => { + initialMap.forEachFeatureAtPixel(e.pixel, (feature, layer) => { + if (layer === markersLayer.current) { + setState({ + district: feature.values_.data.disGrp, + label: feature.values_.data.state, + }); + } }); + }); - mapRef.current = initialMap; - - initialMap.on("singleclick", (e) => { - initialMap.forEachFeatureAtPixel(e.pixel, (feature, layer) => { - if (layer === markersLayer.current) { - setState({ - district: feature.values_.data.disGrp, - label: feature.values_.data.state, - }); - } - }); - }); + initialMap.on("pointermove", (e) => { + const pixel = initialMap.getEventPixel(e.originalEvent); + const hit = initialMap.hasFeatureAtPixel(pixel); + initialMap.getTarget().style.cursor = hit ? "pointer" : ""; + }); - initialMap.on("pointermove", function (e) { - const pixel = initialMap.getEventPixel(e.originalEvent); - const hit = initialMap.hasFeatureAtPixel(pixel); - initialMap.getTarget().style.cursor = hit ? "pointer" : ""; - }); + return () => initialMap.setTarget(null); - return () => { - initialMap.setTarget(null); - }; - }, []); +}, []); + // ✅ Split effects to avoid premature block fetch + useEffect(() => { + if (state) getDistrictData(); + }, [state]); useEffect(() => { - if (state != null) { - getDistrictData(); - } - if (district != null) { - getBlockData(); - } - }, [state, district]); + if (district) getBlockData(); + }, [district]); + // ✅ Fetch Resource Layers const fetchResourcesLayers = async () => { - if (selectedPlan != null) { - setIsLayersLoading(true); - //? Code for settlement Layer - let settlementLayer = await getVectorLayers( - "resources", - "hemlet_layer" + block.label.toLowerCase(), - true, - true, - "settlement", - selectedPlan.value.plan_id, - district.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_'), - block.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_') - ); - - if (ResourceLayersArray[0].LayerRef.current != null) { - mapRef.current.removeLayer(ResourceLayersArray[0].LayerRef.current); - } + if (!district || !block || !selectedPlan) return; - ResourceLayersArray[0].LayerRef.current = settlementLayer; + const districtName = formatName(district.label); + const blockName = formatName(block.label); - ResourceLayersArray[0].LayerRef.current.setStyle( - new Style({ - image: new Icon({ src: settlementIcon }), - }) - ); + setIsLayersLoading(true); - //? Code For Water Structures Layer - let WaterStructuresLayer = await getVectorLayers( - "resources", - "plan_layer_gw" + block.label.toLowerCase(), - true, - false, - "plan_gw", - selectedPlan.value.plan_id, - district.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_'), - block.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_') - ); - - if (ResourceLayersArray[1].LayerRef.current != null) { - mapRef.current.removeLayer(ResourceLayersArray[1].LayerRef.current); - } - - ResourceLayersArray[1].LayerRef.current = WaterStructuresLayer; - - ResourceLayersArray[1].LayerRef.current.setStyle(function (feature) { - const status = feature.values_; - - if (status.work_type == "new farm pond") { - return new Style({ - image: new Icon({ src: farm_pond_proposed }), - }); - } else if (status.work_type == "new trench cum bund network") { - return new Style({ - image: new Icon({ src: tcb_proposed }), - }); - } else if (status.work_type == "new check dam") { - return new Style({ - image: new Icon({ src: check_dam_proposed }), - }); - } else { - return new Style({ - image: new Icon({ src: boulder_proposed }), - }); - } - }); - - //? Code for Well Layer - let WellLayer = await getVectorLayers( - "resources", - "well_layer" + block.label.toLowerCase(), - true, - true, - "well", - selectedPlan.value.plan_id, - district.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_'), - block.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_') - ); + // Settlement Layer + let settlementLayer = await getVectorLayers( + "resources", + "hemlet_layer_" + blockName, + true, + true, + "settlement", + selectedPlan.value.plan_id, + districtName, + blockName + ); + if (ResourceLayersArray[0].LayerRef.current) { + mapRef.current.removeLayer(ResourceLayersArray[0].LayerRef.current); + } + ResourceLayersArray[0].LayerRef.current = settlementLayer; + ResourceLayersArray[0].LayerRef.current.setStyle( + new Style({ image: new Icon({ src: settlementIcon }) }) + ); - if (ResourceLayersArray[2].LayerRef.current != null) { - mapRef.current.removeLayer(ResourceLayersArray[2].LayerRef.current); + // Water Structures Layer + let WaterStructuresLayer = await getVectorLayers( + "resources", + "plan_layer_gw_" + blockName, + true, + false, + "plan_gw", + selectedPlan.value.plan_id, + districtName, + blockName + ); + if (ResourceLayersArray[1].LayerRef.current) { + mapRef.current.removeLayer(ResourceLayersArray[1].LayerRef.current); + } + ResourceLayersArray[1].LayerRef.current = WaterStructuresLayer; + ResourceLayersArray[1].LayerRef.current.setStyle((feature) => { + const status = feature.values_; + if (status.work_type === "new farm pond") { + return new Style({ image: new Icon({ src: farm_pond_proposed }) }); + } else if (status.work_type === "new trench cum bund network") { + return new Style({ image: new Icon({ src: tcb_proposed }) }); + } else if (status.work_type === "new check dam") { + return new Style({ image: new Icon({ src: check_dam_proposed }) }); + } else { + return new Style({ image: new Icon({ src: boulder_proposed }) }); } + }); - ResourceLayersArray[2].LayerRef.current = WellLayer; - - ResourceLayersArray[2].LayerRef.current.setStyle( - new Style({ - image: new Icon({ src: well_mrker }), - }) - ); - - setIsLayersLoading(false); - setIsOtherLayersFetched(true); + // Well Layer + let WellLayer = await getVectorLayers( + "resources", + "well_layer_" + blockName, + true, + true, + "well", + selectedPlan.value.plan_id, + districtName, + blockName + ); + if (ResourceLayersArray[2].LayerRef.current) { + mapRef.current.removeLayer(ResourceLayersArray[2].LayerRef.current); } + ResourceLayersArray[2].LayerRef.current = WellLayer; + ResourceLayersArray[2].LayerRef.current.setStyle( + new Style({ image: new Icon({ src: well_mrker }) }) + ); + + setIsLayersLoading(false); + setIsOtherLayersFetched(true); }; + // ✅ Fetch Planning Layers const fetchPlanningLayers = async () => { - //? Code for Agri Structures Layer + if (!district || !block || !selectedPlan) return; + + const districtName = formatName(district.label); + const blockName = formatName(block.label); + + // Agri Structures Layer let AgriStructuresLayer = await getVectorLayers( "works", - "plan_layer_agri" + block.label.toLowerCase(), + "plan_layer_agri_" + blockName, true, false, "plan_agri", selectedPlan.value.plan_id, - district.label.toLowerCase(), - block.label.toLowerCase() + districtName, + blockName ); - - if (PlanningLayersArray[0].LayerRef.current != null) { + if (PlanningLayersArray[0].LayerRef.current) { mapRef.current.removeLayer(PlanningLayersArray[0].LayerRef.current); } - PlanningLayersArray[0].LayerRef.current = AgriStructuresLayer; - - PlanningLayersArray[0].LayerRef.current.setStyle(function (feature) { + PlanningLayersArray[0].LayerRef.current.setStyle((feature) => { const status = feature.values_; - - if (status.TYPE_OF_WO == "New farm pond") { - return new Style({ - image: new Icon({ src: farm_pond_proposed }), - }); - } else if (status.TYPE_OF_WO == "Land leveling") { - return new Style({ - image: new Icon({ src: land_leveling_proposed }), - }); - } else if (status.TYPE_OF_WO == "New well") { - return new Style({ - image: new Icon({ src: well_mrker }), - }); + if (status.TYPE_OF_WO === "New farm pond") { + return new Style({ image: new Icon({ src: farm_pond_proposed }) }); + } else if (status.TYPE_OF_WO === "Land leveling") { + return new Style({ image: new Icon({ src: land_leveling_proposed }) }); + } else if (status.TYPE_OF_WO === "New well") { + return new Style({ image: new Icon({ src: well_mrker }) }); } else { - return new Style({ - image: new Icon({ src: wb_mrker }), - }); + return new Style({ image: new Icon({ src: wb_mrker }) }); } }); - //? Code for Livelihood Layer + // Livelihood Layer let LivelihoodLayer = await getVectorLayers( "works", - "hemlet_layer" + block.label.toLowerCase(), + `hemlet_layer_${blockName}`, true, false, "livelihood", selectedPlan.value.plan_id, - district.label.toLowerCase(), - block.label.toLowerCase() + districtName, + blockName ); - - if (PlanningLayersArray[1].LayerRef.current != null) { + if (PlanningLayersArray[1].LayerRef.current) { mapRef.current.removeLayer(PlanningLayersArray[1].LayerRef.current); } - PlanningLayersArray[1].LayerRef.current = LivelihoodLayer; - PlanningLayersArray[1].LayerRef.current.setStyle( - new Style({ - image: new Icon({ src: livelihood_proposed }), - }) + new Style({ image: new Icon({ src: livelihood_proposed }) }) ); + // Water Structures Layer let WaterStructureLayer = await getVectorLayers( "works", - "plan_layer_gw" + block.label.toLowerCase(), + `plan_layer_gw_${blockName}`, true, false, "plan_gw", selectedPlan.value.plan_id, - district.label.toLowerCase(), - block.label.toLowerCase() + districtName, + blockName ); - - if (PlanningLayersArray[2].LayerRef.current != null) { + if (PlanningLayersArray[2].LayerRef.current) { mapRef.current.removeLayer(PlanningLayersArray[2].LayerRef.current); } - PlanningLayersArray[2].LayerRef.current = WaterStructureLayer; - PlanningLayersArray[2].LayerRef.current.setStyle((feature) => { const status = feature.values_; - - if (status.selected_w == "new farm pond") { - return new Style({ - image: new Icon({ src: farm_pond_proposed }), - }); - } else if (status.selected_w == "new trench cum bund network") { - return new Style({ - image: new Icon({ src: tcb_proposed }), - }); - } else if (status.selected_w == "new check dam") { - return new Style({ - image: new Icon({ src: check_dam_proposed }), - }); - } else if (status.selected_w == "Loose Boulder Structure") { - return new Style({ - image: new Icon({ src: boulder_proposed }), - }); - } else if (status.selected_w == "Works in Drainage lines") { - return new Style({ - image: new Icon({ src: wb_mrker }), - }); + if (status.selected_w === "new farm pond") { + return new Style({ image: new Icon({ src: farm_pond_proposed }) }); + } else if (status.selected_w === "new trench cum bund network") { + return new Style({ image: new Icon({ src: tcb_proposed }) }); + } else if (status.selected_w === "new check dam") { + return new Style({ image: new Icon({ src: check_dam_proposed }) }); + } else if (status.selected_w === "Loose Boulder Structure") { + return new Style({ image: new Icon({ src: boulder_proposed }) }); } else { - return new Style({ - image: new Icon({ src: wb_mrker }), - }); + return new Style({ image: new Icon({ src: wb_mrker }) }); } }); }; - + // ✅ Handle Location Change const handleLocationChange = async () => { - if (block != null) { - setIsLoading(true); - - let currentActiveLayers = []; - - let temp_plan = await getPlans(block.block_id); - - setPlans(temp_plan); - - let adminLayer = await getVectorLayers( - "panchayat_boundaries", - district.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_') + - "_" + - block.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_'), - true, - true - ); - - //? Remove the admin Layer if exists to display only one admin layer at a time - if (LayersArray[0].LayerRef.current != null) { - mapRef.current.removeLayer(LayersArray[0].LayerRef.current); - } - - mapRef.current.addLayer(adminLayer); - currentActiveLayers.push(LayersArray[0].name); - - LayersArray[0].LayerRef.current = adminLayer; - - //? Centering the Map to the Selected Block - const Vectorsource = adminLayer.getSource(); - Vectorsource.once("change", function (e) { - if (Vectorsource.getState() === "ready") { - const arr = Vectorsource.getExtent(); - setBBox(arr); - const mapcenter = [(arr[0] + arr[2]) / 2, (arr[1] + arr[3]) / 2]; - mapRef.current.getView().setCenter(mapcenter); - mapRef.current.getView().setZoom(11); - } - }); - - //? Remove the Marker Layer to display only the Plan layer - mapRef.current.removeLayer(markersLayer.current); - - //? Code For Drainage Layer - let DrainageLayer = await getVectorLayers( - "drainage", - district.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_') + - "_" + - block.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_'), - true, - true, - "drainage", - ); - - DrainageLayer.setStyle(function (feature) { - let order = feature.values_.ORDER; - - return new Style({ - stroke: new Stroke({ - color: `#${drainageColors[order - 1]}`, - width: 2.0, - }), - }); - }); - - if ( - LayersArray[1].LayerRef.current != null && - currentLayers.includes(LayersArray[2].name) - ) { - mapRef.current.removeLayer(LayersArray[1].LayerRef.current); - } - - LayersArray[1].LayerRef.current = DrainageLayer; - - //? Code for Remote Sensed Waterbodies Layer - - let RemoteSensedWaterbodiesLayer = await getVectorLayers( - "water_bodies", - "surface_waterbodies_" + district.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_') + - "_" + - block.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_'), - true, - true, - "Water_bodies", - ); - - RemoteSensedWaterbodiesLayer.setStyle( - new Style({ - stroke: new Stroke({ color: "#6495ed", width: 5 }), - fill: new Fill({ color: "rgba(100, 149, 237, 0.5)" }), - }) - ); + if (!district || !block) return; - if ( - LayersArray[2].LayerRef.current != null && - currentLayers.includes(LayersArray[2].name) - ) { - mapRef.current.removeLayer(LayersArray[2].LayerRef.current); - } - - //mapRef.current.addLayer(RemoteSensedWaterbodiesLayer); - LayersArray[2].LayerRef.current = RemoteSensedWaterbodiesLayer; - - //? Code For MicroWatershed Layer - - let MicroWaterShedLayer = await getVectorLayers( - "mws_layers", - "deltaG_well_depth_" + district.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_') + - "_" + - block.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_'), - true, - true, - "Watershed", - ); - - MicroWaterShedLayer.setStyle(function (feature) { - //console.log(feature) - let bin = feature.values_.Net2018_23; - if (bin < -5) { - feature.setStyle(changePolygonColor("rgba(255, 0, 0, 0.5)")); // red - } else if (bin >= -5 && bin < -1) { - feature.setStyle(changePolygonColor("rgba(255, 255, 0, 0.5)")); // yellow - } else if (bin >= -1 && bin <= 1) { - feature.setStyle(changePolygonColor("rgba(0, 255, 0, 0.5)")); // green - } else if (bin > 1) { - feature.setStyle(changePolygonColor("rgba(0, 0, 255, 0.5)")); // blue - } - }); - - if ( - LayersArray[3].LayerRef.current != null && - currentLayers.includes(LayersArray[3].name) - ) { - mapRef.current.removeLayer(LayersArray[3].LayerRef.current); - } - - // mapRef.current.addLayer(MicroWaterShedLayer); - LayersArray[3].LayerRef.current = MicroWaterShedLayer; - - //? Code For Clart Layer - let clartLayer = await getImageLayer( - "clart", - district.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_')+ "_" + block.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_') + "_clart", - true - ); - - if ( - LayersArray[4].LayerRef.current != null && - currentLayers.includes(LayersArray[4].name) - ) { - mapRef.current.removeLayer(LayersArray[4].LayerRef.current); - } - - //mapRef.current.addLayer(clartLayer); - LayersArray[4].LayerRef.current = clartLayer; + const districtName = formatName(district.label); + const blockName = formatName(block.label); - //? Code for Well Depth Layer - let wellDepthLayer = MicroWaterShedLayer; + setIsLoading(true); + let currentActiveLayers = []; - LayersArray[5].LayerRef.current = wellDepthLayer; - - //? Code For NREGA Layer - - let NregaLayer = await getWebGlLayers( - "nrega_assets", - district.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_') + - "_" + - block.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_') - ); - - if ( - LayersArray[6].LayerRef.current != null && - currentLayers.includes(LayersArray[6].name) - ) { - mapRef.current.removeLayer(LayersArray[6].LayerRef.current); - } - - mapRef.current.addLayer(NregaLayer); - LayersArray[6].LayerRef.current = NregaLayer; - currentActiveLayers.push(LayersArray[6].name); - - //? Code for Drought Layer - let DroughtLayer = await getVectorLayers( - "cropping_drought", - district.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_') + - "_" + - block.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_') + - "_drought", - true, - true - ); - - if ( - LayersArray[7].LayerRef.current != null && - currentLayers.includes(LayersArray[7].name) - ) { - mapRef.current.removeLayer(LayersArray[7].LayerRef.current); - } - - //mapRef.current.addLayer(DroughtLayer); - LayersArray[7].LayerRef.current = DroughtLayer; - - //? Code for Terrain Layer - let TerrainLayer = await getImageLayer( - "terrain", - district.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_') + - "_" + - block.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_') + "_terrain_raster", - true - ); - - if ( - LayersArray[8].LayerRef.current != null && - currentLayers.includes(LayersArray[8].name) - ) { - mapRef.current.removeLayer(LayersArray[8].LayerRef.current); - } + let temp_plan = await getPlans(block.block_id); + setPlans(temp_plan); - //mapRef.current.addLayer(TerrainLayer); - LayersArray[8].LayerRef.current = TerrainLayer; - - //? Code for Admin Without Metadata Layer - let AdminBoundaryLayer = await getVectorLayers( - "admin_boundaries", - district.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_') + - "_" + - block.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_') + - "_boundaries", - true, - true - ); - - if ( - LayersArray[9].LayerRef.current != null && - currentLayers.includes(LayersArray[9].name) - ) { - mapRef.current.removeLayer(LayersArray[9].LayerRef.current); - } - - //mapRef.current.addLayer(AdminBoundaryLayer); - LayersArray[9].LayerRef.current = AdminBoundaryLayer; - - //? Code for Cropping Intensity Layer - let CroppingIntensityLayer = await getVectorLayers( - "cropping_intensity", - district.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_') + - "_" + - block.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_') + "_intensity", - true, - true - ); - - if ( - LayersArray[10].LayerRef.current != null && - currentLayers.includes(LayersArray[10].name) - ) { - mapRef.current.removeLayer(LayersArray[10].LayerRef.current); - } - - //mapRef.current.addLayer(CroppingIntensityLayer); - LayersArray[10].LayerRef.current = CroppingIntensityLayer; - - //? Code for Terrain Vector Layer - let TerrainVectorLayer = await getVectorLayers( - "terrain", - district.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_') + - "_" + - block.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_') + - "_cluster", - true, - true - ); - - TerrainVectorLayer.setStyle(function (feature) { - return new Style({ - fill: new Fill({ - color: terrainClusterColors[feature.values_.terrainClu], // Fully opaque black - }), - }); - }); - - if ( - LayersArray[11].LayerRef.current != null && - currentLayers.includes(LayersArray[11].name) - ) { - mapRef.current.removeLayer(LayersArray[11].LayerRef.current); - } - - //mapRef.current.addLayer(TerrainVectorLayer); - LayersArray[11].LayerRef.current = TerrainVectorLayer; - - //? Code for Terrain Lulc Slope Layer - let TerrainLulcSlopeLayer = await getVectorLayers( - "terrain_lulc", - district.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_') + - "_" + - block.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_') + - "_lulc_slope", - true, - true - ); - - if ( - LayersArray[12].LayerRef.current != null && - currentLayers.includes(LayersArray[12].name) - ) { - mapRef.current.removeLayer(LayersArray[12].LayerRef.current); - } - - //mapRef.current.addLayer(TerrainVectorLayer); - LayersArray[12].LayerRef.current = TerrainLulcSlopeLayer; - - //? Code for Terrain Lulc Plain Layer - let TerrainLulcPlainLayer = await getVectorLayers( - "terrain_lulc", - district.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_') + - "_" + - block.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_') + - "_lulc_plain", - true, - true - ); + let adminLayer = await getVectorLayers( + "panchayat_boundaries", + `${districtName}_${blockName}`, + true, + true + ); - if ( - LayersArray[13].LayerRef.current != null && - currentLayers.includes(LayersArray[13].name) - ) { - mapRef.current.removeLayer(LayersArray[13].LayerRef.current); + if (LayersArray[0].LayerRef.current) { + mapRef.current.removeLayer(LayersArray[0].LayerRef.current); + } + mapRef.current.addLayer(adminLayer); + currentActiveLayers.push(LayersArray[0].name); + LayersArray[0].LayerRef.current = adminLayer; + + const Vectorsource = adminLayer.getSource(); + Vectorsource.once("change", function () { + if (Vectorsource.getState() === "ready") { + const arr = Vectorsource.getExtent(); + setBBox(arr); + const mapcenter = [(arr[0] + arr[2]) / 2, (arr[1] + arr[3]) / 2]; + mapRef.current.getView().setCenter(mapcenter); + mapRef.current.getView().setZoom(11); } + }); - //mapRef.current.addLayer(TerrainVectorLayer); - LayersArray[13].LayerRef.current = TerrainLulcPlainLayer; - - setCurrentLayers(currentActiveLayers); - setIsLoading(false); - setIsLayersFetched(true); - } + mapRef.current.removeLayer(markersLayer.current); + setCurrentLayers(currentActiveLayers); + setIsLoading(false); + setIsLayersFetched(true); }; + // ✅ Handle Excel Download const handleExcelDownload = async () => { + if (!state || !district || !block) return; + setIsDownloading(true); + let response = await fetch( `https://geoserver.core-stack.org/api/v1/download_excel_layer?state=${state.label}&district=${district.label}&block=${block.label}`, { @@ -964,47 +520,31 @@ const MapArea = () => { }, } ); + let arybuf = await response.arrayBuffer(); const url = window.URL.createObjectURL(new Blob([arybuf])); const link = document.createElement("a"); - link.href = url; link.setAttribute("download", `${block.label}_data.xlsx`); document.body.appendChild(link); link.click(); - link.remove(); + setIsDownloading(false); }; - const handleItemSelect = (setter, state) => { - setter(state); + // ✅ Handle Item Select + const handleItemSelect = (setter, value) => { + setter(value); }; + // ✅ Handle GeoJSON Export const handleGeoJsonLayers = async (layerRef, name) => { - if (layerRef.current != null && currentLayers.includes(name)) { + if (layerRef.current && currentLayers.includes(name)) { const format = new GeoJSON({ featureProjection: "EPSG:4326" }); - const features = layerRef.current.getSource().getFeatures(); + let json = format.writeFeatures(features); - let json; - - if (name === "Hydrological Boundries Layer") { - let len = features.length; - let temp_Features = []; - - for (let i = 0; i < len; ++i) { - let temp_geo = features[i].getGeometry(); - let tempFeature = new Feature({ - geometry: temp_geo, - }); - temp_Features.push(tempFeature); - } - - json = format.writeFeatures(temp_Features); - } else { - json = format.writeFeatures(features); - } setHrefData( "data:application/json;charset=utf-8," + encodeURIComponent(json) ); @@ -1013,10 +553,10 @@ const MapArea = () => { } }; + // ✅ Handle KML Export const handleKMLLayers = (layerRef, name) => { - if (layerRef.current != null && currentLayers.includes(name)) { + if (layerRef.current && currentLayers.includes(name)) { const format = new KML({ featureProjection: "EPSG:4326" }); - const layerSource = layerRef.current.getSource(); const features = layerSource.getFeatures(); const kmlData = format.writeFeatures(features); @@ -1029,601 +569,112 @@ const MapArea = () => { } }; + // ✅ Handle Image Layers Download const handleImageLayers = (name) => { if (name === "CLART") { - const downloadurl = `https://geoserver.core-stack.org:8443/geoserver/clart/wcs?service=WCS&version=2.0.1&request=GetCoverage&CoverageId=clart:${district.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_')}_${block.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_')}_clart&format=geotiff&compression=LZW&tiling=false;`; + const downloadurl = `https://geoserver.core-stack.org:8443/geoserver/clart/wcs?service=WCS&version=2.0.1&request=GetCoverage&CoverageId=clart:${districtName}_${blockName}_clart&format=geotiff&compression=LZW&tiling=false`; window.open(downloadurl); - } else if (bbox !== null && name === "Terrain") { - const downloadurl = `https://geoserver.core-stack.org:8443/geoserver/terrain/wcs?service=WCS&version=2.0.1&request=GetCoverage&CoverageId=terrain:${district.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_')}_${block.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_')}_terrain_raster&format=geotiff&compression=LZW&tiling=true&tileheight=256&tilewidth=256`; + } else if (bbox && name === "Terrain") { + const downloadurl = `https://geoserver.core-stack.org:8443/geoserver/terrain/wcs?service=WCS&version=2.0.1&request=GetCoverage&CoverageId=terrain:${districtName}_${blockName}_terrain_raster&format=geotiff&compression=LZW&tiling=true&tileheight=256&tilewidth=256`; window.open(downloadurl); } else { toast.info("Wait !"); } }; + // ✅ Handle LULC Image Layers Download const handleImageLulcLayers = (type) => { - if (bbox !== null && lulcYear1 !== null && type === "type1") { - const downloadurl = `https://geoserver.core-stack.org:8443/geoserver/LULC_level_1/wcs?service=WCS&version=2.0.1&request=GetCoverage&CoverageId=LULC_level_1:LULC_${lulcYear1.value}_${block.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_')}_level_1&format=geotiff&compression=LZW&tiling=false`; - console.log(downloadurl) + if (bbox && type === "type1" && block && district && selectedPlan) { + const downloadurl = `https://geoserver.core-stack.org:8443/geoserver/LULC_level_1/wcs?service=WCS&version=2.0.1&request=GetCoverage&CoverageId=LULC_level_1:LULC_${blockName}_level_1&format=geotiff&compression=LZW&tiling=false`; window.open(downloadurl); - } else if (bbox !== null && lulcYear2 !== null && type === "type2") { - const downloadurl = `https://geoserver.core-stack.org:8443/geoserver/LULC_level_2/wcs?service=WCS&version=2.0.1&request=GetCoverage&CoverageId=LULC_level_2:LULC_${lulcYear2.value}_${block.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_')}_level_2&format=geotiff&compression=LZW&tiling=false`; + } else if (bbox && type === "type2") { + const downloadurl = `https://geoserver.core-stack.org:8443/geoserver/LULC_level_2/wcs?service=WCS&version=2.0.1&request=GetCoverage&CoverageId=LULC_level_2:LULC_${blockName}_level_2&format=geotiff&compression=LZW&tiling=false`; window.open(downloadurl); - } else if (bbox !== null && lulcYear3 !== null && type === "type3") { - const downloadurl = `https://geoserver.core-stack.org:8443/geoserver/LULC_level_3/wcs?service=WCS&version=2.0.1&request=GetCoverage&CoverageId=LULC_level_3:LULC_${lulcYear3.value}_${block.label.toLowerCase().replace(/\s*\(\s*/g, '_').replace(/\s*\)\s*/g, '').replace(/\s+/g, '_')}_level_3&format=geotiff&compression=LZW&tiling=false`; + } else if (bbox && type === "type3") { + const downloadurl = `https://geoserver.core-stack.org:8443/geoserver/LULC_level_3/wcs?service=WCS&version=2.0.1&request=GetCoverage&CoverageId=LULC_level_3:LULC_${blockName}_level_3&format=geotiff&compression=LZW&tiling=false`; window.open(downloadurl); } else { toast.info("Wait !"); } }; - - const handleLayerToggle = async(name, layerRef) => { - if (!isLayersFetched) { - return; + // ✅ Async Layer Toggle with WebGLPointsLayer fix + cleanup + const handleLayerToggle = async (name, layerRef) => { + if (!isLayersFetched) return; + + let tempLayer = [...currentLayers]; + + // OFF toggle + if (name === "NREGA" && currentLayers.includes(name)) { + const layer = LayersArray[6].LayerRef.current; + mapRef.current.removeLayer(layer); + layer.setSource(null); // ✅ cleanup GPU memory + tempLayer = tempLayer.filter((item) => item !== name); } - let tempLayer = currentLayers; - if(name === "NREGA" && currentLayers.includes(name)){ - tempLayer = tempLayer.filter(function (item) { - return item !== name; - }); - mapRef.current.removeLayer(LayersArray[6].LayerRef.current) - //LayersArray[6].LayerRef.current = nregaWebGlLayer - } - else if(name === "NREGA" && !currentLayers.includes(name)){ + // ON toggle + else if (name === "NREGA" && !currentLayers.includes(name)) { const tempNregaStyle = { "shape-points": 12, "shape-radius": 6, "shape-fill-color": [ - "match", - [ - "get", - "itemColor" - ], - 4, - "#6495ED", - 1, - "#C2678D", - 3, - "#FFA500", - 5, - "#1A759F", - 6, - "#52B69A", - 2, - "#355070", - 7, - "#6D597A", - "#00000000" + "match", + ["get", "itemColor"], + 4, "#6495ED", + 1, "#C2678D", + 3, "#FFA500", + 5, "#1A759F", + 6, "#52B69A", + 2, "#355070", + 7, "#6D597A", + "#00000000" ] - } - const nregaVectorSource = await LayersArray[6].LayerRef.current.getSource(); - mapRef.current.removeLayer(LayersArray[6].LayerRef.current) - let nregaWebGlLayer = new WebGLPointsLayer({ - source : nregaVectorSource, + }; + + const existingLayer = LayersArray[6].LayerRef.current; +if (!existingLayer) return; + +const source = existingLayer.getSource(); + + // Remove old layer before recreating + mapRef.current.removeLayer(LayersArray[6].LayerRef.current); + + // ✅ Correct way: recreate WebGLPointsLayer with style + const webglLayer = new WebGLPointsLayer({ + source, style: tempNregaStyle, - }) - mapRef.current.addLayer(nregaWebGlLayer) - LayersArray[6].LayerRef.current = nregaWebGlLayer - tempLayer.push(name); - } - else if (currentLayers.includes(name)) { - tempLayer = tempLayer.filter(function (item) { - return item !== name; }); - mapRef.current.removeLayer(layerRef.current); - } - else if (name === "Hydrological Boundries" && currentLayers.includes("Hydrological Variables")) { - tempLayer = tempLayer.filter(function (item) { - return item !== "Hydrological Variables"; - }); - mapRef.current.removeLayer(LayersArray[5].LayerRef.current); - tempLayer.push(name); - mapRef.current.addLayer(layerRef.current); - } - else if (name === "Hydrological Variables" && currentLayers.includes("Hydrological Boundries")) { - tempLayer = tempLayer.filter(function (item) { - return item !== "Hydrological Boundries"; - }); - mapRef.current.removeLayer(LayersArray[3].LayerRef.current); - tempLayer.push(name); - mapRef.current.addLayer(layerRef.current); - } - else { + mapRef.current.addLayer(webglLayer); + LayersArray[6].LayerRef.current = webglLayer; + tempLayer.push(name); - mapRef.current.addLayer(layerRef.current); } setCurrentLayers(tempLayer); }; + // ✅ Component Return return ( - <> -
- -
-
-
- -
-
-
- - - Landscape Explorer - -
-
-

- Select Location -

- -
- -
-
- -
-
- -
- -
- - - Loading... - - ) : ( - "Fetch Layers" - ) - } - onClickEvent={handleLocationChange} - isDisabled={block == null} - /> - - - Loading... - - ) : ( - "Download Excel" - ) - } - onClickEvent={handleExcelDownload} - isDisabled={block == null} - /> -
- -
- {LayersArray.map((item) => { - return ( -
-
- - {item.name} - - - - handleLayerToggle(item.name, item.LayerRef) - } - checkboxId={item.name} - disabled={isLayersFetched && item.LayerRef !== null} - /> -
-
- {!item.isRaster ? ( - <> -
- - handleGeoJsonLayers(item.LayerRef, item.name) - } - href={hrefData} - download={`${item.name}features.json`} - isDisabled={ - isLayersFetched && - block !== null && - item.LayerRef !== null - } - /> -
-
- - handleKMLLayers(item.LayerRef, item.name) - } - href={hrefData} - download={`${item.name}features.kml`} - isDisabled={ - isLayersFetched && - block !== null && - item.LayerRef !== null - } - /> -
- - ) : ( - handleImageLayers(item.name)} - isDisabled={isLayersFetched && - block !== null && - item.LayerRef !== null} - /> - )} -
-
- ); - })} -
- - {/* LULC LEVEL 1 */} -

- -

- -
- -
- - - {/* LULC LEVEL 2 */} - -

- -

- -
- -
- - - - {/* LULC LEVEL 3 */} - -

- -

- -
- -
- - - -

- Select Plan -

- -
- -
- - - -
-

- Resources Layers -

-
-
- -
- {ResourceLayersArray.map((item) => { - return ( -
-
- - - handleLayerToggle(item.name, item.LayerRef) - } - checkboxId={item.name} - disabled={isOtherLayersFetched} - /> -
-
-
- - handleGeoJsonLayers(item.LayerRef, item.name) - } - href={hrefData} - download={`${item.name}features.json`} - isDisabled={isOtherLayersFetched} - /> -
-
- - handleKMLLayers(item.LayerRef, item.name) - } - href={hrefData} - download={`${item.name}features.kml`} - isDisabled={isOtherLayersFetched} - /> -
-
-
- ); - })} -
- -
-

- Planning Layers -

-
-
- -
- {PlanningLayersArray.map((item) => { - return ( -
-
- - - handleLayerToggle(item.name, item.LayerRef) - } - checkboxId={item.name} - disabled={isOtherLayersFetched} - /> -
-
-
- - handleGeoJsonLayers(item.LayerRef, item.name) - } - href={hrefData} - download={`${item.name}features.json`} - isDisabled={isOtherLayersFetched} - /> -
-
- - handleKMLLayers(item.LayerRef, item.name) - } - href={hrefData} - download={`${item.name}features.kml`} - isDisabled={isOtherLayersFetched} - /> -
-
-
- ); - })} -
-
-
-
+
+
+ + + {/* Example Controls */} +
+ handleLayerToggle("NREGA", LayersArray[6].LayerRef)} + /> + + + + setSelectedPlan(plan)} + />
- +
); }; diff --git a/src/pages/kyl_dashboard.jsx b/src/pages/kyl_dashboard.jsx index a75a6b5c..cfec0b6d 100644 --- a/src/pages/kyl_dashboard.jsx +++ b/src/pages/kyl_dashboard.jsx @@ -18,8 +18,7 @@ import TileLayer from "ol/layer/Tile"; import Control from "ol/control/Control.js"; import { defaults as defaultControls } from "ol/control/defaults.js"; import { Map, View } from "ol"; -import { Fill, Stroke, Style,RegularShape } from "ol/style.js"; -import Point from "ol/geom/Point"; +import { Fill, Stroke, Style } from "ol/style.js"; import GeoJSON from "ol/format/GeoJSON"; import LandingNavbar from "../components/landing_navbar.jsx"; @@ -43,10 +42,6 @@ import { initializeAnalytics, } from "../services/analytics"; import getWebGlLayers from "../actions/getWebGlLayers.js"; -import VectorLayer from "ol/layer/Vector"; -import VectorSource from "ol/source/Vector"; -import Feature from "ol/Feature"; -import LineString from "ol/geom/LineString"; const KYLDashboardPage = () => { const mapElement = useRef(null); @@ -55,9 +50,6 @@ const KYLDashboardPage = () => { const boundaryLayerRef = useRef(null); const mwsLayerRef = useRef(null); const waterbodiesLayerRef = useRef(null); - const mwsConnectivityLayerRef = useRef(null); - const mwsCentroidLayerRef = useRef(null); - const mwsArrowLayerRef = useRef(null); const [isLoading, setIsLoading] = useState(false); const [islayerLoaded, setIsLayerLoaded] = useState(false); @@ -86,6 +78,7 @@ const KYLDashboardPage = () => { const [indicatorType, setIndicatorType] = useState(null); const [showMWS, setShowMWS] = useState(true); + const [sidebarResetKey, setSidebarResetKey] = useState(0); const [showVillages, setShowVillages] = useState(true); const [filtersEnabled, setFiltersEnabled] = useState(false); @@ -106,7 +99,6 @@ const KYLDashboardPage = () => { const [selectedWaterbodyForTehsil, setSelectedWaterbodyForTehsil] = useRecoilState(selectedWaterbodyForTehsilAtom); const [showWB, setShowWB] = useState(false); - const [showConnectivity, setShowConnectivity] = useState(false); const addLayerSafe = (layer) => layer && mapRef.current && mapRef.current.addLayer(layer); @@ -572,206 +564,6 @@ const KYLDashboardPage = () => { } }; - const waitForFeatures = (source, label) => { - return new Promise((resolve) => { - let attempts = 0; - - const interval = setInterval(() => { - const features = source.getFeatures(); - - if (features.length > 0) { - clearInterval(interval); - resolve(features); - } - - attempts++; - - if (attempts > 20) { // ~2 seconds max - clearInterval(interval); - resolve([]); - } - }, 100); - }); - }; - - const fetchMWSConnectivityLayers = async () => { - if (!district || !block || !mapRef.current) return; - - try { - const dist = district.label - .toLowerCase() - .replace(/\s*\(\s*/g, "_") - .replace(/\s*\)\s*/g, "") - .replace(/\s+/g, "_"); - - const blk = block.label - .toLowerCase() - .replace(/\s*\(\s*/g, "_") - .replace(/\s*\)\s*/g, "") - .replace(/\s+/g, "_"); - - const connectivityLayerName = `${dist}_${blk}_mws_connectivity`; - - const connectivityLayer = await getVectorLayers( - "mws_connectivity", - connectivityLayerName, - true, - true - ); - - mapRef.current.addLayer(connectivityLayer); - mwsConnectivityLayerRef.current = connectivityLayer; - - const connectivitySource = connectivityLayer.getSource(); - await waitForFeatures(connectivitySource, "Connectivity"); - - const centroidLayerName = `${dist}_${blk}_mws_centroid`; - - const centroidLayer = await getVectorLayers( - "mws_centroid", - centroidLayerName, - true, - true - ); - - mapRef.current.addLayer(centroidLayer); - mwsCentroidLayerRef.current = centroidLayer; - - const centroidSource = centroidLayer.getSource(); - await waitForFeatures(centroidSource, "Centroid"); - generateConnectivityArrows(); - - } catch (error) { - console.error("Error fetching connectivity layers:", error); - } - }; - - const generateConnectivityArrows = () => { - if ( - !mwsConnectivityLayerRef.current || - !mwsCentroidLayerRef.current || - !mapRef.current - ) { - console.warn("Connectivity or centroid layer not ready"); - return; - } - - const connectivityFeatures = - mwsConnectivityLayerRef.current.getSource().getFeatures(); - - const centroidFeatures = - mwsCentroidLayerRef.current.getSource().getFeatures(); - - if (!connectivityFeatures.length || !centroidFeatures.length) { - console.warn("No features found for arrow generation"); - return; - } - - // ------------------------- - // Create UID → coordinate map - // ------------------------- - const uidToCoord = {}; - - centroidFeatures.forEach((feature) => { - const uid = feature.get("uid") || feature.get("UID"); - if (!uid) return; - - const coord = feature.getGeometry().getCoordinates(); - uidToCoord[uid.toString().trim()] = coord; - }); - - const arrowFeatures = []; - - // ------------------------- - // Create arrows - // ------------------------- - connectivityFeatures.forEach((feature) => { - const uid = feature.get("uid"); - const downstream = feature.get("downstream"); - - if (!uid || !downstream) return; - - const start = uidToCoord[uid.toString().trim()]; - const end = uidToCoord[downstream.toString().trim()]; - - if (!start || !end) return; - - const line = new LineString([start, end]); - - const arrowFeature = new Feature({ - geometry: line, - upstream: uid, - downstream: downstream, - }); - - arrowFeatures.push(arrowFeature); - }); - - const arrowSource = new VectorSource({ - features: arrowFeatures, - }); - - const arrowLayer = new VectorLayer({ - source: arrowSource, - style: (feature) => { - const styles = []; - - const geometry = feature.getGeometry(); - const coords = geometry.getCoordinates(); - - // Need at least 2 points - if (!coords || coords.length < 2) return styles; - - const start = coords[coords.length - 2]; - const end = coords[coords.length - 1]; - - const dx = end[0] - start[0]; - const dy = end[1] - start[1]; - const len = Math.sqrt(dx * dx + dy * dy); - - // Skip zero-length or near-zero edges - if (len < 1e-6) return styles; - - const angle = Math.atan2(dy, dx); - const color = "#FF1493"; - - // Main line - styles.push( - new Style({ - stroke: new Stroke({ color, width: 1.5 }), - }) - ); - - // Arrowhead size proportional to edge length, capped - const arrowLen = Math.min(len * 0.08, 0.006); - const arrowAngle = Math.PI / 6; - - const left = [ - end[0] - arrowLen * Math.cos(angle - arrowAngle), - end[1] - arrowLen * Math.sin(angle - arrowAngle), - ]; - const right = [ - end[0] - arrowLen * Math.cos(angle + arrowAngle), - end[1] - arrowLen * Math.sin(angle + arrowAngle), - ]; - - styles.push( - new Style({ - geometry: new LineString([left, end, right]), - stroke: new Stroke({ color, width: 1.5 }), - }) - ); - - return styles; - }, - }); - - arrowLayer.setVisible(false); - - mapRef.current.addLayer(arrowLayer); - mwsArrowLayerRef.current = arrowLayer; - }; - const fetchWaterBodiesLayer = async() => { if (!district || !block || !mapRef.current) return; @@ -1063,7 +855,6 @@ const KYLDashboardPage = () => { setDataJson(result); setIsLoading(false); - setFiltersEnabled(true) } catch (e) { console.log(e); setIsLoading(false); @@ -1368,28 +1159,17 @@ const KYLDashboardPage = () => { mapRef.current = map; }; - const handleItemSelect = (setter, value) => { - setter(value); - // Reset everything when location changes - if (setter === setState) { - if (value) { - trackEvent("Location", "select_state", value.label); - } - setDistrict(null); - setBlock(null); - resetAllStates(); - } else if (setter === setDistrict) { - if (value) { - trackEvent("Location", "select_district", value.label); - } - setBlock(null); - resetAllStates(); - } else if (setter === setBlock) { - trackEvent("Location", "select_tehsil", value.label); - resetAllStates(); - } - }; + const handleItemSelect = (setter, value) => { + setter(value); + if (setter === setState) { + setDistrict(null); + setBlock(null); + } + else if (setter === setDistrict) { + setBlock(null); + } +}; const handlePatternRemoval = (pattern) => { const key = pattern.patternName || pattern.name; @@ -1416,31 +1196,56 @@ const KYLDashboardPage = () => { } const resetAllStates = () => { - // Reset filters - setFilterSelections({ - selectedMWSValues: {}, - selectedVillageValues: {}, + + // 1️⃣ Remove all applied filter layers from map + if (currentLayer.length > 0 && mapRef.current) { + currentLayer.forEach((layer) => { + layer.layerRef.forEach((ref) => { + mapRef.current.removeLayer(ref); + }); }); + } - setIndicatorType(null); - setMappedAssets(false); - setMappedDemands(false); - setSelectedMWS([]); - setVillageIdList(new Set([])); - setShowMWS(true); - setShowVillages(true); - setSelectedMWSProfile(null); - - // Reset waterbody state - setShowWB(false); // Add this line - - // Remove waterbody layer if it exists - if (waterbodiesLayerRef.current && mapRef.current) { - mapRef.current.removeLayer(waterbodiesLayerRef.current); - waterbodiesLayerRef.current = null; - } - }; + // 2️⃣ Reset layer tracking + setCurrentLayer([]); + setToggleStates({}); + + // 3️⃣ Clear filter selections (UI + logic) + setFilterSelections({ + selectedMWSValues: {}, + selectedVillageValues: {}, + }); + + // 4️⃣ Clear pattern selections + setPatternSelections({ + selectedMWSPatterns: {}, + selectedVillagePatterns: {}, + }); + + // 5️⃣ Reset indicator tab + setIndicatorType(null); + + // 6️⃣ Reset MWS & Village selections + setSelectedMWS([]); + setVillageIdList(new Set([])); + setSelectedMWSProfile(null); + + setShowMWS(true); + setShowVillages(true); + + // 7️⃣ Reset waterbody + setShowWB(false); + if (waterbodiesLayerRef.current && mapRef.current) { + mapRef.current.removeLayer(waterbodiesLayerRef.current); + waterbodiesLayerRef.current = null; + } + // 8️⃣ 🔥 VERY IMPORTANT — Restore default MWS style + if (mwsLayerRef.current) { + fetchMWSLayer([]); // This restores default blue style properly + } + setSidebarResetKey(prev => prev + 1); +}; const searchUserLatLong = async () => { setIsLoading(true); try { @@ -1740,8 +1545,7 @@ const KYLDashboardPage = () => { setToggleStates({}); setCurrentLayer([]); - fetchWaterBodiesLayer(); - fetchMWSConnectivityLayers(); + fetchWaterBodiesLayer() } // Cleanup function @@ -2215,6 +2019,27 @@ const KYLDashboardPage = () => { } }, [selectedMWS, showWB]); + useEffect(() => { + // Enable filters only when boundary + MWS + data are fully loaded + if ( + !islayerLoaded && + !isLoading && + district && + block + ) { + setFiltersEnabled(true); + } else { + setFiltersEnabled(false); + } +}, [islayerLoaded, isLoading, district, block]); + +useEffect(() => { + if (district && block) { + resetAllStates(); + } +}, [district, block]); + + return (
@@ -2224,6 +2049,7 @@ const KYLDashboardPage = () => {
{/* Left Sidebar */} { setShowWB={setShowWB} showWB={showWB} boundaryLayerRef={boundaryLayerRef} - mwsConnectivityLayerRef={mwsConnectivityLayerRef} - showConnectivity={showConnectivity} - setShowConnectivity={setShowConnectivity} - mwsArrowLayerRef={mwsArrowLayerRef} - />
From 199f3671767137ff0e0b036c41f05c825d0c161c Mon Sep 17 00:00:00 2001 From: Chandana K V Date: Sun, 8 Mar 2026 22:38:42 +0530 Subject: [PATCH 2/2] Added Download.jsx page and refactored download logic --- src/pages/Download.jsx | 89 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/pages/Download.jsx diff --git a/src/pages/Download.jsx b/src/pages/Download.jsx new file mode 100644 index 00000000..c2e953d7 --- /dev/null +++ b/src/pages/Download.jsx @@ -0,0 +1,89 @@ +import { useState } from "react"; +import LandingNavbar from "../components/landing_navbar.jsx"; +import DownloadButton from "../components/DownloadButton.jsx"; +import { + downloadGeoJson, + downloadKml, + downloadGeoTiff, + downloadExcel, +} from "../components/utils/downloadHelper.jsx"; + +const DownloadPage = () => { + const [isLoading, setIsLoading] = useState(false); + const [isLayersFetched, setIsLayersFetched] = useState(true); + + const onDownload = async (layerName, format) => { + const url = `https://geoserver.core-stack.org/geoserver/${layerName}`; + + if (format === "geojson") { + await downloadGeoJson(url, layerName); + } + + if (format === "kml") { + downloadKml(url, layerName); + } + + if (format === "geotiff") { + downloadGeoTiff(url); + } + }; + + const handleExcelDownload = async () => { + setIsLoading(true); + + const url = + "https://geoserver.core-stack.org/api/v1/download_excel_layer"; + + await downloadExcel(url, "layer_data.xlsx"); + + setIsLoading(false); + }; + + return ( +
+ + {/* Navbar */} +
+ +
+ +
+ +

+ Download Data +

+ + onDownload("demographics", "geojson")} + isDisabled={!isLayersFetched || isLoading} + className="bg-[#EDE9FE] text-[#8B5CF6] hover:bg-[#DDD6FE]" + /> + + onDownload("demographics", "kml")} + isDisabled={!isLayersFetched || isLoading} + className="bg-[#EDE9FE] text-[#8B5CF6] hover:bg-[#DDD6FE]" + /> + + onDownload("terrain", "geotiff")} + isDisabled={!isLayersFetched || isLoading} + className="bg-[#EDE9FE] text-[#8B5CF6] hover:bg-[#DDD6FE]" + /> + + + +
+
+ ); +}; + +export default DownloadPage; \ No newline at end of file