Web Developer Work - I
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

2571 lines
91 KiB

// import React, { useState, useEffect, useRef } from "react";
// import FeatureLayer from "@arcgis/core/layers/FeatureLayer";
// import { type AllWidgetProps } from 'jimu-core';
// import "./simple_widget.css";
// import { JimuMapViewComponent, type JimuMapView } from 'jimu-arcgis';
// import { mapViewManager } from '../../../utils/mapview';
// import Graphic from "@arcgis/core/Graphic";
// import SimpleFillSymbol from "@arcgis/core/symbols/SimpleFillSymbol";
// import SimpleLineSymbol from "@arcgis/core/symbols/SimpleLineSymbol";
// import zoomInIcon from './assets/zoom-in.svg';
// import jsPDF from "jspdf";
// import autoTable from "jspdf-autotable";
// const RoadAssetFilter = (props: AllWidgetProps<any>) => {
// // State variables
// const [selectedZone, setSelectedZone] = useState<string>("");
// const [selectedWard, setSelectedWard] = useState<string>("");
// const [zoneOptions, setZoneOptions] = useState<string[]>([]);
// const [wardOptions, setWardOptions] = useState<string[]>([]);
// const [jimuMapView, setJimuMapView] = useState<JimuMapView>();
// const [selectedLayer, setSelectedLayer] = useState<string>("");
// const [selectedUtilityLayer, setSelectedUtilityLayer] = useState<string>("All");
// const [utilityCount, setUtilityCount] = useState<number | null>(null);
// const [tableData, setTableData] = useState<any[]>([]);
// const [utilityLayerOptions, setUtilityLayerOptions] = useState<string[]>([]);
// const [selectedRoadName, setSelectedRoadName] = useState<string>("");
// const [roadNameOptions, setRoadNameOptions] = useState<string[]>([]);
// const [isLoading, setIsLoading] = useState(false);
// const [activeStep, setActiveStep] = useState<number>(0);
// const addedUtilityLayerRef = useRef<any | null>(null);
// // Refs for cleanup
// const highlightRef = useRef<any>(null);
// const graphicsLayerRef = useRef<any>(null);
// // URLs for layers
// const ZONE_LAYER_URL = "https://gisgcc.chennaicorporation.gov.in/server/rest/services/GCCDepts/GCC_Administration_Boundaries/FeatureServer/3";
// const WARD_LAYER_URL = "https://gisgcc.chennaicorporation.gov.in/server/rest/services/GCCDepts/GCC_Administration_Boundaries/FeatureServer/4";
// const UTILITY_GROUP_URL = "https://gisgcc.chennaicorporation.gov.in/server/rest/services/GCCDepts/Utility/FeatureServer";
// const ROAD_LAYER_URL = "https://gisgcc.chennaicorporation.gov.in/server/rest/services/GCCDepts/Transporations/FeatureServer/0";
// // Utility layer configuration
// const utilityLayers = [
// { id: 1, title: "CCTV" },
// { id: 2, title: "Gantry Sign Boards" },
// { id: 3, title: "Garbage Bins" },
// { id: 4, title: "Hand Pump" },
// { id: 7, title: "Manhole" },
// { id: 8, title: "Permanent Bunkshop" },
// { id: 11, title: "Police Booth" },
// { id: 12, title: "Public Taps" },
// { id: 17, title: "Street Name Board" },
// { id: 19, title: "Traffic Signals" },
// { id: 21, title: "Transformer" },
// { id: 23, title: "Water Tanks" },
// { id: 30, title: "Bus Terminus" },
// { id: 33, title: "Footpath" },
// { id: 34, title: "Median" },
// { id: 36, title: "Parking Stretch" },
// { id: 40, title: "Traffic Island" }
// ];
// // Utility to escape single quotes in SQL
// const safe = (val: string) => val.replace(/'/g, "''");
// // Populate Zone dropdown
// const populateZone = async () => {
// try {
// const layer = new FeatureLayer({ url: ZONE_LAYER_URL });
// const query = layer.createQuery();
// query.returnDistinctValues = true;
// query.returnGeometry = false;
// query.outFields = ["zone"];
// query.where = "1=1";
// const result = await layer.queryFeatures(query);
// if (result) {
// const zones = Array.from(new Set(result.features.map(f => f.attributes.zone).filter(Boolean)));
// zones.sort((a, b) => Number(a) - Number(b));
// setZoneOptions(['All', ...zones]);
// }
// } catch (error) {
// console.error("Error fetching zones:", error);
// }
// };
// useEffect(() => {
// populateZone();
// }, []);
// // Populate Ward dropdown based on selected Zone
// const populateWard = async () => {
// try {
// const layer = new FeatureLayer({ url: WARD_LAYER_URL });
// const query = layer.createQuery();
// query.returnDistinctValues = true;
// query.returnGeometry = false;
// query.outFields = ["ward_no"];
// if (selectedZone && selectedZone !== 'All') {
// query.where = `zone_no = '${safe(selectedZone)}'`;
// } else {
// query.where = "1=1";
// }
// const result = await layer.queryFeatures(query);
// if (result) {
// const wards = Array.from(new Set(result.features.map(f => f.attributes.ward_no).filter(Boolean)));
// wards.sort((a, b) => Number(a) - Number(b));
// setWardOptions(['All', ...wards]);
// setSelectedWard(""); // Reset ward when zone changes
// setActiveStep(1); // Move to next step
// }
// } catch (error) {
// console.error("Error fetching wards:", error);
// }
// };
// useEffect(() => {
// if (selectedZone) {
// populateWard();
// }
// }, [selectedZone]);
// // Populate utility layer options
// useEffect(() => {
// if (selectedLayer === "Utility") {
// const titles = utilityLayers.map(l => l.title);
// setUtilityLayerOptions(["All", ...titles]);
// setSelectedUtilityLayer("All");
// setActiveStep(2); // Move to next step
// }
// }, [selectedLayer]);
// // Populate road names for selected utility layer
// const populateRoadNames = async (utilityLayer: string) => {
// if (!selectedZone || !selectedWard || !utilityLayer || utilityLayer === "All") return;
// const layerInfo = utilityLayers.find(l => l.title === utilityLayer);
// if (!layerInfo) return;
// const layerUrl = `${UTILITY_GROUP_URL}/${layerInfo.id}`;
// const layer = new FeatureLayer({ url: layerUrl });
// try {
// const query = layer.createQuery();
// query.returnDistinctValues = true;
// query.outFields = ["road_name"];
// query.returnGeometry = false;
// let whereClause = "";
// if (selectedZone && selectedZone !== 'All') {
// whereClause += `zone_number = '${safe(selectedZone)}'`;
// }
// if (selectedWard && selectedWard !== 'All') {
// whereClause += whereClause ? ` AND ward_number = '${safe(selectedWard)}'` : `ward_number = '${safe(selectedWard)}'`;
// }
// query.where = whereClause || "1=1";
// const result = await layer.queryFeatures(query);
// const names = Array.from(
// new Set(result.features.map(f => f.attributes.road_name).filter(Boolean))
// );
// setRoadNameOptions(names.sort());
// setActiveStep(3); // Move to next step
// } catch (err) {
// console.error("Failed to fetch road names:", err);
// setRoadNameOptions([]);
// }
// };
// // Build where clause for queries
// const buildWhereClause = () => {
// const clauses: string[] = [];
// if (selectedZone && selectedZone !== 'All') {
// clauses.push(`zone_number = '${safe(selectedZone)}'`);
// }
// if (selectedWard && selectedWard !== 'All') {
// clauses.push(`ward_number = '${safe(selectedWard)}'`);
// }
// if (selectedRoadName) {
// clauses.push(`road_name = '${safe(selectedRoadName)}'`);
// }
// return clauses.length > 0 ? clauses.join(" AND ") : "1=1";
// };
// // Zoom to zone geometry
// const zoomToZoneGeometry = async (zoneValue: string) => {
// if (!jimuMapView || !zoneValue || zoneValue === 'All') return;
// const view = jimuMapView.view;
// const zoneLayer = new FeatureLayer({ url: ZONE_LAYER_URL });
// try {
// await zoneLayer.load();
// const query = zoneLayer.createQuery();
// query.where = `zone = '${safe(zoneValue)}'`;
// query.outFields = ["*"];
// query.returnGeometry = true;
// const result = await zoneLayer.queryFeatures(query);
// if (result.features.length > 0) {
// const geometry = result.features[0].geometry;
// await view.goTo({
// target: geometry,
// padding: { top: 50, bottom: 50, left: 50, right: 50 },
// duration: 1000
// });
// }
// } catch (error) {
// console.error("Error zooming to zone:", error);
// }
// };
// // Zoom to ward geometry
// const zoomToWardGeometry = async (wardValue: string) => {
// if (!jimuMapView || !wardValue || wardValue === 'All') return;
// const view = jimuMapView.view;
// const wardLayer = new FeatureLayer({ url: WARD_LAYER_URL });
// try {
// await wardLayer.load();
// const query = wardLayer.createQuery();
// query.where = `ward_no = '${safe(wardValue)}'`;
// query.outFields = ["*"];
// query.returnGeometry = true;
// const result = await wardLayer.queryFeatures(query);
// if (result.features.length > 0) {
// const geometry = result.features[0].geometry;
// await view.goTo({
// target: geometry,
// padding: { top: 50, bottom: 50, left: 50, right: 50 },
// duration: 1000
// });
// }
// } catch (error) {
// console.error("Error zooming to ward:", error);
// }
// };
// // Get feature count for utility layer
// const getFeatureCount = async (layerUrl: string): Promise<number> => {
// const layer = new FeatureLayer({ url: layerUrl });
// const query = layer.createQuery();
// query.where = buildWhereClause();
// query.returnGeometry = false;
// try {
// return await layer.queryFeatureCount(query);
// } catch (error) {
// console.error("Error counting features:", error);
// return 0;
// }
// };
// // Update utility count when filters change
// useEffect(() => {
// const fetchCount = async () => {
// if (selectedUtilityLayer && selectedUtilityLayer !== "All") {
// const layerInfo = utilityLayers.find(l => l.title === selectedUtilityLayer);
// if (layerInfo) {
// const count = await getFeatureCount(`${UTILITY_GROUP_URL}/${layerInfo.id}`);
// setUtilityCount(count);
// }
// } else {
// setUtilityCount(null);
// }
// };
// if (selectedLayer === "Utility") {
// fetchCount();
// }
// }, [selectedZone, selectedWard, selectedUtilityLayer, selectedRoadName]);
// // Function to update ward boundary visibility
// const updateWardBoundaryVisibility = async (wardValue: string) => {
// if (!jimuMapView?.view) return;
// const map = jimuMapView.view.map;
// try {
// // Find the ward boundary layer in the map
// const wardLayer = map.layers.find(layer =>
// layer.url === WARD_LAYER_URL
// ) as FeatureLayer;
// if (wardLayer) {
// if (wardValue && wardValue !== "All") {
// // Show only the selected ward
// wardLayer.definitionExpression = `ward_no = '${safe(wardValue)}'`;
// wardLayer.visible = true;
// } else {
// // Show all wards when "All" is selected
// wardLayer.definitionExpression = "1=1";
// wardLayer.visible = true;
// }
// }
// } catch (error) {
// console.error("Error updating ward boundary visibility:", error);
// }
// };
// //Apply filters to utility layers
// const applyFilters = async () => {
// if (!jimuMapView?.view) return;
// const view = jimuMapView.view;
// const map = view.map;
// const defExp = buildWhereClause() || "1=1";
// const selected = (selectedUtilityLayer ?? "").toString().trim();
// // ✅ Instead of hiding Asset & Road groups, keep them visible and just apply filters
// const roadLayerTitles = ["Road", "CarraigeWay"];
// const assetLayerTitles = ["Asset Point", "Asset Building"];
// // --- Road group ---
// const roadGroup = map.layers.find(l => l.title === "Transporations") as __esri.GroupLayer;
// if (roadGroup && "layers" in roadGroup) {
// roadGroup.visible = true;
// roadGroup.layers.forEach((sub: any) => {
// if (roadLayerTitles.includes(sub.title) && "definitionExpression" in sub) {
// // Road schema field is `ward`
// sub.definitionExpression = defExp.replace(/ward_number/gi, "ward");
// }
// sub.visible = true;
// });
// }
// // --- Asset group ---
// const assetGroup = map.layers.find(l => l.title === "GCC Asset Layers") as __esri.GroupLayer;
// if (assetGroup && "layers" in assetGroup) {
// assetGroup.visible = true;
// assetGroup.layers.forEach((sub: any) => {
// if (assetLayerTitles.includes(sub.title) && "definitionExpression" in sub) {
// // Asset schema field is `ward_no`
// sub.definitionExpression = defExp.replace(/ward_number/gi, "ward_no");
// }
// sub.visible = true;
// });
// }
// // helper
// const safeTitle = (t?: string | null) => (t ?? "").toString().trim();
// const lower = (s?: string) => safeTitle(s).toLowerCase();
// try {
// // 1) Find Utility group and hide all its children (so we start clean)
// // const utilityGroup = map.layers.find(
// // (l: any) => safeTitle(l.title).toLowerCase().includes("utility")
// // );
// // if (utilityGroup && "layers" in utilityGroup && typeof utilityGroup.layers?.toArray === "function") {
// // const children = utilityGroup.layers.toArray();
// // for (const child of children) {
// // try {
// // child.visible = false;
// // if ("definitionExpression" in child) {
// // try { child.definitionExpression = "1=0"; } catch (e) { /* some sublayers may not accept */ }
// // }
// // } catch (e) {
// // console.warn("Error hiding utility child", child, e);
// // }
// // }
// // // hide group itself to avoid stray visuals until we show the selected layer
// // utilityGroup.visible = false;
// // }
// // 1) Find Utility group and hide all its children (start clean)
// const utilityGroup = map.layers.find(
// (l: any) => safeTitle(l.title).toLowerCase().includes("utility")
// );
// if (utilityGroup && "layers" in utilityGroup && typeof utilityGroup.layers?.toArray === "function") {
// const children = utilityGroup.layers.toArray();
// for (const child of children) {
// try {
// child.visible = false;
// if ("definitionExpression" in child) {
// child.definitionExpression = "1=0";
// }
// } catch (e) {
// console.warn("Error hiding utility child", child, e);
// }
// }
// // ❌ Don’t hide the group itself
// utilityGroup.visible = true; // keep group visible so Transportation & Assets stay untouched
// }
// // 2) Remove any previously added temporary FeatureLayer (we'll add a new one if needed)
// if (addedUtilityLayerRef.current) {
// try {
// // remove from map
// map.layers.remove(addedUtilityLayerRef.current);
// } catch (e) { /* ignore */ }
// addedUtilityLayerRef.current = null;
// }
// // If "All" -> show all relevant children (try to show children and apply defExp where possible)
// if (selected === "" || lower(selected) === "all") {
// if (utilityGroup && "layers" in utilityGroup && typeof utilityGroup.layers?.toArray === "function") {
// const children = utilityGroup.layers.toArray();
// for (const child of children) {
// try {
// child.visible = true;
// if ("definitionExpression" in child) {
// try { child.definitionExpression = defExp; } catch (e) { /* ignore */ }
// }
// } catch (e) { console.warn("Error enabling child for All", child, e); }
// }
// utilityGroup.visible = true;
// }
// return;
// }
// // 3) Find the utilityLayers entry and service URL for the selected utility
// const layerInfo = utilityLayers.find(u => lower(u.title) === lower(selected));
// if (!layerInfo) {
// console.warn("Selected utility not found in utilityLayers config:", selected);
// return;
// }
// const serviceUrl = `${UTILITY_GROUP_URL}/${layerInfo.id}`;
// // 4) Try to find an existing layer in the map whose .url matches the service url
// // or whose sublayer has that url (some map configs attach FeatureLayer as child).
// let foundLayer: any = null;
// const walkAndFindByUrl = (top: any) => {
// // top-level url
// if (top?.url && top.url === serviceUrl) return top;
// // child layers (.layers)
// if ("layers" in top && typeof top.layers?.toArray === "function") {
// for (const c of top.layers.toArray()) {
// if (c?.url && c.url === serviceUrl) return c;
// }
// }
// // sublayers (.sublayers)
// if ("sublayers" in top && typeof top.sublayers?.toArray === "function") {
// for (const s of top.sublayers.toArray()) {
// if (s?.url && s.url === serviceUrl) return s;
// }
// }
// return null;
// };
// for (const topLayer of map.layers.toArray()) {
// try {
// const match = walkAndFindByUrl(topLayer);
// if (match) { foundLayer = match; break; }
// } catch (e) { /* ignore per-layer errors */ }
// }
// // 5) If found in map, show and apply definitionExpression (best-case)
// if (foundLayer) {
// try {
// foundLayer.visible = true;
// if ("definitionExpression" in foundLayer) {
// try { foundLayer.definitionExpression = defExp; } catch (e) { /* ignore */ }
// }
// // If it has a parent group, make parent visible too:
// // (some APIs provide foundLayer.parent or you can set utilityGroup.visible)
// if (utilityGroup) utilityGroup.visible = true;
// return;
// } catch (err) {
// console.warn("Error enabling existing layer:", err);
// }
// }
// // 6) If no matching layer found in map, add a new client FeatureLayer that points to the service endpoint.
// // Client FeatureLayer is guaranteed to allow definitionExpression (unless service denies).
// try {
// const fl = new FeatureLayer({
// url: serviceUrl,
// title: `${selected} (temp)`,
// visible: true,
// definitionExpression: defExp
// });
// await fl.load();
// map.layers.add(fl); // add top-level
// addedUtilityLayerRef.current = fl;
// // ensure Utility group is visible so user sees it in TOC if needed
// if (utilityGroup) utilityGroup.visible = true;
// return;
// } catch (err) {
// console.error("Failed to add FeatureLayer for selected utility:", err);
// }
// } catch (err) {
// console.error("applyFilters error:", err);
// }
// };
// const applyWardFilterToLayers = async (wardValue: string, viewMap: __esri.Map) => {
// if (!wardValue || wardValue === "All") {
// // Reset → show all features in all layers
// viewMap.layers.forEach(layer => {
// if ("layers" in layer) {
// layer.layers.forEach((sub: any) => {
// if ("definitionExpression" in sub) {
// sub.definitionExpression = "1=1"; // show all features
// }
// sub.visible = true; // keep all visible
// });
// }
// });
// return;
// }
// const roadLayerTitles = ["Road", "CarraigeWay"];
// const assetLayerTitles = ["Asset Point", "Asset Building"];
// // 🔹 Transportation group (filter by `ward`)
// const roadGroup = viewMap.layers.find(l => l.title === "Transporations") as __esri.GroupLayer;
// if (roadGroup) {
// roadGroup.visible = true;
// roadGroup.layers.forEach((sub: any) => {
// if (roadLayerTitles.includes(sub.title) && "definitionExpression" in sub) {
// sub.definitionExpression = `ward = '${wardValue}'`; // ✅ correct field
// }
// sub.visible = true;
// });
// }
// // 🔹 Asset group (filter by `ward_no`)
// const assetGroup = viewMap.layers.find(l => l.title === "GCC Asset Layers") as __esri.GroupLayer;
// if (assetGroup) {
// assetGroup.visible = true;
// assetGroup.layers.forEach((sub: any) => {
// if (assetLayerTitles.includes(sub.title) && "definitionExpression" in sub) {
// sub.definitionExpression = `ward_no = '${wardValue}'`; // ✅ correct field
// }
// sub.visible = true;
// });
// }
// };
// useEffect(() => {
// if (jimuMapView?.view && selectedWard) {
// applyWardFilterToLayers(selectedWard, jimuMapView.view.map);
// updateWardBoundaryVisibility(selectedWard); // Add this line to update ward boundary visibility
// }
// }, [selectedWard, jimuMapView]);
// // Apply filters when any filter changes
// useEffect(() => {
// if (jimuMapView && selectedLayer === "Utility") {
// applyFilters();
// }
// }, [selectedZone, selectedWard, selectedUtilityLayer, selectedRoadName, jimuMapView]);
// const handleSubmit = async (e: React.MouseEvent) => {
// e.preventDefault();
// setIsLoading(true);
// if (!selectedZone) {
// alert("Please select a Zone");
// setIsLoading(false);
// return;
// }
// if (!jimuMapView?.view) {
// setIsLoading(false);
// return;
// }
// try {
// // 1. Apply filters first
// await applyFilters();
// let zoomed = false;
// // 2. Query features only when a single utility is selected
// if (selectedLayer === "Utility" && selectedUtilityLayer && selectedUtilityLayer !== "All") {
// const layerInfo = utilityLayers.find(l => l.title === selectedUtilityLayer);
// if (layerInfo) {
// const layer = new FeatureLayer({ url: `${UTILITY_GROUP_URL}/${layerInfo.id}` });
// const query = layer.createQuery();
// query.where = buildWhereClause();
// query.outFields = ["*"];
// query.returnGeometry = true;
// const result = await layer.queryFeatures(query);
// setTableData(result.features);
// // Zoom to filtered features if any
// if (result.features.length > 0) {
// const extent = result.features.reduce(
// (acc, f) => acc ? acc.union(f.geometry.extent) : f.geometry.extent,
// null as __esri.Extent | null
// );
// if (extent) {
// await jimuMapView.view.goTo({ target: extent, padding: 100, duration: 1000 });
// zoomed = true;
// }
// }
// }
// } else if (selectedLayer === "Utility" && selectedUtilityLayer === "All") {
// // Clear table when all utilities are shown
// setTableData([]);
// }
// // 3. If nothing was zoomed yet, zoom to ward/zone
// if (!zoomed) {
// if (selectedWard && selectedWard !== "All") {
// await zoomToWardGeometry(selectedWard);
// } else if (selectedZone && selectedZone !== "All") {
// await zoomToZoneGeometry(selectedZone);
// }
// }
// } catch (error) {
// console.error("Error in handleSubmit:", error);
// } finally {
// setIsLoading(false);
// }
// };
// // Zoom to individual feature with highlight
// const zoomToFeature = async (feature: any) => {
// if (!jimuMapView?.view || !feature?.geometry) return;
// const view = jimuMapView.view;
// try {
// // Clear previous highlight
// if (highlightRef.current) {
// highlightRef.current.remove();
// highlightRef.current = null;
// }
// // Clear any existing graphics
// if (graphicsLayerRef.current) {
// view.graphics.remove(graphicsLayerRef.current);
// }
// // Create highlight symbol based on feature type
// let highlightSymbol;
// if (feature.geometry.type === "point") {
// highlightSymbol = {
// type: "simple-marker",
// color: [255, 0, 0, 0.8],
// size: 12,
// outline: {
// color: [255, 255, 255],
// width: 2
// }
// };
// } else if (feature.geometry.type === "polyline") {
// highlightSymbol = new SimpleLineSymbol({
// color: [255, 0, 0, 0.8],
// width: 4
// });
// } else {
// highlightSymbol = new SimpleFillSymbol({
// color: [255, 0, 0, 0.3],
// outline: {
// color: [255, 0, 0],
// width: 2
// }
// });
// }
// // Create highlight graphic
// const highlightGraphic = new Graphic({
// geometry: feature.geometry,
// symbol: highlightSymbol
// });
// // Add to map and store reference
// view.graphics.add(highlightGraphic);
// graphicsLayerRef.current = highlightGraphic;
// // Zoom to feature
// await view.goTo({
// target: feature.geometry,
// zoom: feature.geometry.type === "point" ? 18 : 14,
// duration: 1000
// });
// } catch (error) {
// console.error("Error zooming to feature:", error);
// }
// };
// // Reset button handler
// const handleReset = () => {
// setSelectedZone("");
// setSelectedWard("");
// setSelectedLayer("");
// setSelectedUtilityLayer("All");
// setSelectedRoadName("");
// setUtilityCount(null);
// setTableData([]);
// setRoadNameOptions([]);
// setActiveStep(0);
// // Clear graphics & highlights
// jimuMapView?.view?.graphics.removeAll();
// highlightRef.current?.remove();
// highlightRef.current = null;
// if (jimuMapView?.view) {
// const map = jimuMapView.view.map;
// // Reset all utility layers
// map.layers.forEach(layer => {
// if (layer.type === "feature") {
// (layer as __esri.FeatureLayer).definitionExpression = "1=1";
// layer.visible = true;
// } else if ("layers" in layer) {
// layer.layers.forEach((sub: any) => {
// sub.visible = true;
// if (sub.type === "feature") sub.definitionExpression = "1=1";
// });
// }
// });
// // Remove dynamically added utility layer
// if (addedUtilityLayerRef.current) {
// map.layers.remove(addedUtilityLayerRef.current);
// addedUtilityLayerRef.current = null;
// }
// // Restore GCC Asset Layers (and its subs)
// const assetGroup = map.layers.find(l => l.title === "GCC Asset Layers");
// if (assetGroup && "layers" in assetGroup) {
// assetGroup.visible = true;
// assetGroup.layers.forEach((sub: any) => sub.visible = true);
// }
// // Reset ward boundary layer to show all wards
// const wardLayer = map.layers.find(layer =>
// layer.url === WARD_LAYER_URL
// ) as FeatureLayer;
// if (wardLayer) {
// wardLayer.definitionExpression = "1=1";
// wardLayer.visible = true;
// }
// }
// };
// // Active view change handler
// const activeViewChangeHandler = (jmv: JimuMapView) => {
// if (jmv) setJimuMapView(jmv);
// };
// // Initialize map view
// useEffect(() => {
// const interval = setInterval(() => {
// const view = mapViewManager.getMapView();
// if (view) {
// setJimuMapView(view);
// clearInterval(interval);
// }
// }, 500);
// return () => clearInterval(interval);
// }, []);
// return (
// <div className="property-widget-parent">
// <div className="property-widget">
// <JimuMapViewComponent
// useMapWidgetId={props.useMapWidgetIds?.[0]}
// onActiveViewChange={activeViewChangeHandler}
// />
// <h3 className="widget-title">Utility Asset Filter</h3>
// {/* Zone selection */}
// <div className="property_form">
// <label>Zone:<span style={{ color: 'red' }}>*</span></label>
// <select
// value={selectedZone}
// onChange={e => {
// const value = e.target.value;
// setSelectedZone(value);
// setSelectedWard("");
// setSelectedRoadName("");
// setRoadNameOptions([]);
// if (value && value !== "All") {
// zoomToZoneGeometry(value);
// }
// }}
// required
// >
// <option value="">--Select Zone--</option>
// {zoneOptions.map(zone => (
// <option key={zone} value={zone}>{zone}</option>
// ))}
// </select>
// </div>
// {/* Ward selection */}
// <div className="property_form">
// <label>Ward:</label>
// <select
// value={selectedWard}
// onChange={e => {
// const value = e.target.value;
// setSelectedWard(value);
// setSelectedRoadName("");
// setRoadNameOptions([]);
// if (value && value !== "All") {
// zoomToWardGeometry(value);
// if (jimuMapView?.view) {
// applyWardFilterToLayers(value, jimuMapView.view.map);
// updateWardBoundaryVisibility(value); // ✅ finish call here
// }
// } else {
// // Reset when "All" is selected
// if (jimuMapView?.view) {
// applyWardFilterToLayers("All", jimuMapView.view.map);
// updateWardBoundaryVisibility("All"); // ✅ reset visibility
// }
// }
// }}
// >
// <option value="">--Select Ward--</option>
// {wardOptions.map(ward => (
// <option key={ward} value={ward}>{ward}</option>
// ))}
// </select>
// </div>
// {/* Layer selection */}
// <div className="property_form">
// <label>Select Layer:</label>
// <select
// value={selectedLayer}
// onChange={e => {
// const layer = e.target.value;
// setSelectedLayer(layer);
// setSelectedUtilityLayer("All");
// setSelectedRoadName("");
// setRoadNameOptions([]);
// setUtilityCount(null);
// }}
// >
// <option value="">--Select Layer--</option>
// <option value="Utility">Utility</option>
// </select>
// </div>
// {/* Show filtering options when Utility is selected */}
// {selectedLayer === "Utility" && (
// <>
// {/* Utility Layer selection */}
// <div className="property_form">
// <label>Select Utility Type:</label>
// <select
// value={selectedUtilityLayer}
// onChange={e => {
// const value = e.target.value;
// setSelectedUtilityLayer(value);
// setSelectedRoadName("");
// if (value !== "All") {
// populateRoadNames(value);
// } else {
// setRoadNameOptions([]);
// }
// }}
// disabled={!selectedZone || selectedZone === "All"}
// >
// <option value="All">All Utilities</option>
// {utilityLayerOptions.map(name => (
// <option key={name} value={name}>
// {name}{selectedUtilityLayer === name && utilityCount !== null ? ` (${utilityCount})` : ""}
// </option>
// ))}
// </select>
// </div>
// {/* Road Name selection */}
// {selectedUtilityLayer !== "All" && roadNameOptions.length > 0 && (
// <div className="property_form">
// <label>Select Road Name:</label>
// <select
// value={selectedRoadName}
// onChange={e => setSelectedRoadName(e.target.value)}
// >
// <option value="">--All Roads--</option>
// {roadNameOptions.map(name => (
// <option key={name} value={name}>{name}</option>
// ))}
// </select>
// </div>
// )}
// </>
// )}
// {/* Action buttons */}
// <div className="button-group">
// <button
// type="button"
// className={`submit-button ${isLoading ? 'loading' : ''}`}
// onClick={handleSubmit}
// disabled={isLoading || !selectedZone || !selectedLayer}
// >
// {isLoading ? <div className="spinner"></div> : "Apply Filters"}
// </button>
// <button
// type="button"
// className="reset-button"
// onClick={handleReset}
// >
// Reset All
// </button>
// </div>
// {/* Results table */}
// {tableData.length > 0 && (
// <div className="attribute-table">
// <h4>Asset Details ({tableData.length} features)</h4>
// <div className="table-container">
// <table>
// <thead>
// <tr>
// <th>ID</th>
// <th>Zone</th>
// <th>Ward</th>
// <th>Road Name</th>
// <th>Action</th>
// </tr>
// </thead>
// <tbody>
// {tableData.map((feature, index) => {
// const attr = feature.attributes;
// return (
// <tr key={feature.attributes.OBJECTID || index}>
// <td>{attr.OBJECTID || index + 1}</td>
// <td>{attr.zone_number || 'N/A'}</td>
// <td>{attr.ward_number || 'N/A'}</td>
// <td>{attr.road_name || 'N/A'}</td>
// <td>
// <button
// onClick={() => zoomToFeature(feature)}
// className="zoom-button"
// title="Zoom to feature"
// >
// <img src={zoomInIcon} alt="Zoom" width={16} height={16} />
// </button>
// </td>
// </tr>
// );
// })}
// </tbody>
// </table>
// </div>
// </div>
// )}
// {tableData.length === 0 && selectedLayer && (
// <div className="no-results">
// <p>No assets found with the current filters.</p>
// </div>
// )}
// </div>
// </div>
// );
// };
// export default RoadAssetFilter;
import React, { useState, useEffect, useRef } from "react";
import FeatureLayer from "@arcgis/core/layers/FeatureLayer";
import { type AllWidgetProps } from 'jimu-core';
import "./simple_widget.css";
import { JimuMapViewComponent, type JimuMapView } from 'jimu-arcgis';
import { mapViewManager } from '../../../utils/mapview';
import Graphic from "@arcgis/core/Graphic";
import SimpleFillSymbol from "@arcgis/core/symbols/SimpleFillSymbol";
import SimpleLineSymbol from "@arcgis/core/symbols/SimpleLineSymbol";
import zoomInIcon from './assets/zoom-in.svg';
import jsPDF from "jspdf";
import autoTable from "jspdf-autotable";
const RoadAssetFilter = (props: AllWidgetProps<any>) => {
// State variables
const [selectedZone, setSelectedZone] = useState<string>("");
const [selectedWard, setSelectedWard] = useState<string>("");
const [zoneOptions, setZoneOptions] = useState<string[]>([]);
const [wardOptions, setWardOptions] = useState<string[]>([]);
const [jimuMapView, setJimuMapView] = useState<JimuMapView>();
const [selectedLayer, setSelectedLayer] = useState<string>("");
const [selectedUtilityLayer, setSelectedUtilityLayer] = useState<string>("All");
const [utilityCount, setUtilityCount] = useState<number | null>(null);
const [tableData, setTableData] = useState<any[]>([]);
const [utilityLayerOptions, setUtilityLayerOptions] = useState<string[]>([]);
const [selectedRoadName, setSelectedRoadName] = useState<string>("");
const [roadNameOptions, setRoadNameOptions] = useState<string[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [activeStep, setActiveStep] = useState<number>(0);
const addedUtilityLayerRef = useRef<any | null>(null);
// Refs for cleanup
const highlightRef = useRef<any>(null);
const graphicsLayerRef = useRef<any>(null);
// URLs for layers
const ZONE_LAYER_URL = "https://gisgcc.chennaicorporation.gov.in/server/rest/services/GCCDepts/GCC_Administration_Boundaries/FeatureServer/3";
const WARD_LAYER_URL = "https://gisgcc.chennaicorporation.gov.in/server/rest/services/GCCDepts/GCC_Administration_Boundaries/FeatureServer/4";
const UTILITY_GROUP_URL = "https://gisgcc.chennaicorporation.gov.in/server/rest/services/GCCDepts/Utility/FeatureServer";
const ROAD_LAYER_URL = "https://gisgcc.chennaicorporation.gov.in/server/rest/services/GCCDepts/Transporations/FeatureServer/0";
// Utility layer configuration
const utilityLayers = [
{ id: 1, title: "CCTV" },
{ id: 2, title: "Gantry Sign Boards" },
{ id: 3, title: "Garbage Bins" },
{ id: 4, title: "Hand Pump" },
{ id: 7, title: "Manhole" },
{ id: 8, title: "Permanent Bunkshop" },
{ id: 11, title: "Police Booth" },
{ id: 12, title: "Public Taps" },
{ id: 17, title: "Street Name Board" },
{ id: 19, title: "Traffic Signals" },
{ id: 21, title: "Transformer" },
{ id: 23, title: "Water Tanks" },
{ id: 30, title: "Bus Terminus" },
{ id: 33, title: "Footpath" },
{ id: 34, title: "Median" },
{ id: 36, title: "Parking Stretch" },
{ id: 40, title: "Traffic Island" }
];
// Utility to escape single quotes in SQL
const safe = (val: string) => val.replace(/'/g, "''");
// Apply selected utility layer visibility + filter
const applyUtilityLayerSelection = async (
map: __esri.Map,
selectedUtilityLayer: string,
defExp: string,
utilityLayers: { id: number; title: string }[],
UTILITY_GROUP_URL: string,
addedUtilityLayerRef: React.MutableRefObject<any | null>
) => {
const safeTitle = (t?: string | null) => (t ?? "").toString().trim();
const lower = (s?: string) => safeTitle(s).toLowerCase();
// 1) Find Utility group and hide all its children first
const utilityGroup = map.layers.find(
(l: any) => lower(l.title).includes("utility")
);
if (utilityGroup && "layers" in utilityGroup && typeof utilityGroup.layers?.toArray === "function") {
const children = utilityGroup.layers.toArray();
for (const child of children) {
child.visible = false;
if ("definitionExpression" in child) {
child.definitionExpression = "1=0"; // hide
}
}
utilityGroup.visible = true;
}
// 2) Remove any previously added temporary FeatureLayer
if (addedUtilityLayerRef.current) {
try { map.layers.remove(addedUtilityLayerRef.current); } catch {}
addedUtilityLayerRef.current = null;
}
// 3) If "All" → show all children
if (!selectedUtilityLayer || lower(selectedUtilityLayer) === "all") {
if (utilityGroup && "layers" in utilityGroup && typeof utilityGroup.layers?.toArray === "function") {
const children = utilityGroup.layers.toArray();
for (const child of children) {
child.visible = true;
if ("definitionExpression" in child) {
child.definitionExpression = defExp;
}
}
utilityGroup.visible = true;
}
return;
}
// 4) Find service url for selected utility
const layerInfo = utilityLayers.find(u => lower(u.title) === lower(selectedUtilityLayer));
if (!layerInfo) return;
const serviceUrl = `${UTILITY_GROUP_URL}/${layerInfo.id}`;
// 5) Try to find in map by URL
let foundLayer: any = null;
const walkAndFindByUrl = (top: any): any => {
if (top?.url && top.url === serviceUrl) return top;
if ("layers" in top && typeof top.layers?.toArray === "function") {
for (const c of top.layers.toArray()) {
const match = walkAndFindByUrl(c);
if (match) return match;
}
}
if ("sublayers" in top && typeof top.sublayers?.toArray === "function") {
for (const s of top.sublayers.toArray()) {
if (s?.url && s.url === serviceUrl) return s;
}
}
return null;
};
for (const topLayer of map.layers.toArray()) {
const match = walkAndFindByUrl(topLayer);
if (match) { foundLayer = match; break; }
}
if (foundLayer) {
foundLayer.visible = true;
if ("definitionExpression" in foundLayer) {
foundLayer.definitionExpression = defExp;
}
if (utilityGroup) utilityGroup.visible = true;
return;
}
// 6) If not found → add as new FeatureLayer
const fl = new FeatureLayer({
url: serviceUrl,
title: `${selectedUtilityLayer} (temp)`,
visible: true,
definitionExpression: defExp
});
await fl.load();
map.layers.add(fl);
addedUtilityLayerRef.current = fl;
if (utilityGroup) utilityGroup.visible = true;
};
// Populate Zone dropdown
const populateZone = async () => {
try {
const layer = new FeatureLayer({ url: ZONE_LAYER_URL });
const query = layer.createQuery();
query.returnDistinctValues = true;
query.returnGeometry = false;
query.outFields = ["zone"];
query.where = "1=1";
const result = await layer.queryFeatures(query);
if (result) {
const zones = Array.from(new Set(result.features.map(f => f.attributes.zone).filter(Boolean)));
zones.sort((a, b) => Number(a) - Number(b));
setZoneOptions(['All', ...zones]);
}
} catch (error) {
console.error("Error fetching zones:", error);
}
};
useEffect(() => {
populateZone();
}, []);
// Populate Ward dropdown based on selected Zone
const populateWard = async () => {
try {
const layer = new FeatureLayer({ url: WARD_LAYER_URL });
const query = layer.createQuery();
query.returnDistinctValues = true;
query.returnGeometry = false;
query.outFields = ["ward_no"];
if (selectedZone && selectedZone !== 'All') {
query.where = `zone_no = '${safe(selectedZone)}'`;
} else {
query.where = "1=1";
}
const result = await layer.queryFeatures(query);
if (result) {
const wards = Array.from(new Set(result.features.map(f => f.attributes.ward_no).filter(Boolean)));
wards.sort((a, b) => Number(a) - Number(b));
setWardOptions(['All', ...wards]);
setSelectedWard(""); // Reset ward when zone changes
setActiveStep(1); // Move to next step
}
} catch (error) {
console.error("Error fetching wards:", error);
}
};
useEffect(() => {
if (selectedZone) {
populateWard();
}
}, [selectedZone]);
// Populate utility layer options
useEffect(() => {
if (selectedLayer === "Utility") {
const titles = utilityLayers.map(l => l.title);
setUtilityLayerOptions(["All", ...titles]);
setSelectedUtilityLayer("All");
setActiveStep(2); // Move to next step
}
}, [selectedLayer]);
// Populate road names for selected utility layer
const populateRoadNames = async (utilityLayer: string) => {
if (!selectedZone || !selectedWard || !utilityLayer || utilityLayer === "All") return;
const layerInfo = utilityLayers.find(l => l.title === utilityLayer);
if (!layerInfo) return;
const layerUrl = `${UTILITY_GROUP_URL}/${layerInfo.id}`;
const layer = new FeatureLayer({ url: layerUrl });
try {
const query = layer.createQuery();
query.returnDistinctValues = true;
query.outFields = ["road_name"];
query.returnGeometry = false;
let whereClause = "";
if (selectedZone && selectedZone !== 'All') {
whereClause += `zone_number = '${safe(selectedZone)}'`;
}
if (selectedWard && selectedWard !== 'All') {
whereClause += whereClause ? ` AND ward_number = '${safe(selectedWard)}'` : `ward_number = '${safe(selectedWard)}'`;
}
query.where = whereClause || "1=1";
const result = await layer.queryFeatures(query);
const names = Array.from(
new Set(result.features.map(f => f.attributes.road_name).filter(Boolean))
);
setRoadNameOptions(names.sort());
setActiveStep(3); // Move to next step
} catch (err) {
console.error("Failed to fetch road names:", err);
setRoadNameOptions([]);
}
};
// Build where clause for queries
const buildWhereClause = () => {
const clauses: string[] = [];
if (selectedZone && selectedZone !== 'All') {
clauses.push(`zone_number = '${safe(selectedZone)}'`);
}
if (selectedWard && selectedWard !== 'All') {
clauses.push(`ward_number = '${safe(selectedWard)}'`);
}
if (selectedRoadName) {
clauses.push(`road_name = '${safe(selectedRoadName)}'`);
}
return clauses.length > 0 ? clauses.join(" AND ") : "1=1";
};
// Zoom to zone geometry
const zoomToZoneGeometry = async (zoneValue: string) => {
if (!jimuMapView || !zoneValue || zoneValue === 'All') return;
const view = jimuMapView.view;
const zoneLayer = new FeatureLayer({ url: ZONE_LAYER_URL });
try {
await zoneLayer.load();
const query = zoneLayer.createQuery();
query.where = `zone = '${safe(zoneValue)}'`;
query.outFields = ["*"];
query.returnGeometry = true;
const result = await zoneLayer.queryFeatures(query);
if (result.features.length > 0) {
const geometry = result.features[0].geometry;
await view.goTo({
target: geometry,
padding: { top: 50, bottom: 50, left: 50, right: 50 },
duration: 1000
});
}
} catch (error) {
console.error("Error zooming to zone:", error);
}
};
// Zoom to ward geometry
const zoomToWardGeometry = async (wardValue: string) => {
if (!jimuMapView || !wardValue || wardValue === 'All') return;
const view = jimuMapView.view;
const wardLayer = new FeatureLayer({ url: WARD_LAYER_URL });
try {
await wardLayer.load();
const query = wardLayer.createQuery();
query.where = `ward_no = '${safe(wardValue)}'`;
query.outFields = ["*"];
query.returnGeometry = true;
const result = await wardLayer.queryFeatures(query);
if (result.features.length > 0) {
const geometry = result.features[0].geometry;
await view.goTo({
target: geometry,
padding: { top: 50, bottom: 50, left: 50, right: 50 },
duration: 1000
});
}
} catch (error) {
console.error("Error zooming to ward:", error);
}
};
// Get feature count for utility layer
const getFeatureCount = async (layerUrl: string): Promise<number> => {
const layer = new FeatureLayer({ url: layerUrl });
const query = layer.createQuery();
query.where = buildWhereClause();
query.returnGeometry = false;
try {
return await layer.queryFeatureCount(query);
} catch (error) {
console.error("Error counting features:", error);
return 0;
}
};
// Update utility count when filters change
useEffect(() => {
const fetchCount = async () => {
if (selectedUtilityLayer && selectedUtilityLayer !== "All") {
const layerInfo = utilityLayers.find(l => l.title === selectedUtilityLayer);
if (layerInfo) {
const count = await getFeatureCount(`${UTILITY_GROUP_URL}/${layerInfo.id}`);
setUtilityCount(count);
}
} else {
setUtilityCount(null);
}
};
if (selectedLayer === "Utility") {
fetchCount();
}
}, [selectedZone, selectedWard, selectedUtilityLayer, selectedRoadName]);
// Function to update ward boundary visibility
const updateWardBoundaryVisibility = async (wardValue: string) => {
if (!jimuMapView?.view) return;
const map = jimuMapView.view.map;
try {
// Find the ward boundary layer in the map
const wardLayer = map.layers.find(layer =>
layer.url === WARD_LAYER_URL
) as FeatureLayer;
if (wardLayer) {
if (wardValue && wardValue !== "All") {
// Show only the selected ward
wardLayer.definitionExpression = `ward_no = '${safe(wardValue)}'`;
wardLayer.visible = true;
} else {
// Show all wards when "All" is selected
wardLayer.definitionExpression = "1=1";
wardLayer.visible = true;
}
}
} catch (error) {
console.error("Error updating ward boundary visibility:", error);
}
};
const applyFilters = async () => {
if (!jimuMapView?.view) return;
const view = jimuMapView.view;
const map = view.map;
const defExp = buildWhereClause() || "1=1";
const selected = (selectedUtilityLayer ?? "").toString().trim().toLowerCase();
// --- Keep Road group visible & filtered ---
const roadGroup = map.layers.find(l => l.title === "Transporations") as __esri.GroupLayer;
if (roadGroup && "layers" in roadGroup) {
roadGroup.visible = true;
roadGroup.layers.forEach((sub: any) => {
if (["Road", "CarraigeWay"].includes(sub.title) && "definitionExpression" in sub) {
sub.definitionExpression = defExp.replace(/ward_number/gi, "ward");
}
sub.visible = true;
});
}
// --- Keep Asset group visible & filtered ---
const assetGroup = map.layers.find(l => l.title === "GCC Asset Layers") as __esri.GroupLayer;
if (assetGroup && "layers" in assetGroup) {
assetGroup.visible = true;
assetGroup.layers.forEach((sub: any) => {
if (["Asset Point", "Asset Building"].includes(sub.title) && "definitionExpression" in sub) {
sub.definitionExpression = defExp.replace(/ward_number/gi, "ward_no");
}
sub.visible = true;
});
}
// --- Handle Utility layers ---
const utilityGroup = map.layers.find(
(l: any) => (l.title ?? "").toString().toLowerCase().includes("utility")
) as __esri.GroupLayer;
if (!utilityGroup || !("layers" in utilityGroup)) return;
utilityGroup.visible = true;
const children = utilityGroup.layers.toArray();
for (const child of children) {
const layerTitle = (child.title ?? "").toLowerCase();
const layerInfo = utilityLayers.find(u => u.title.toLowerCase() === layerTitle);
if (!layerInfo) continue;
if (selected === "all" || layerTitle === selected) {
child.visible = true;
if (typeof child.definitionExpression !== "undefined") {
child.definitionExpression = defExp; // apply filters
}
} else {
child.visible = false; // hide all other utility layers
}
}
};
// --- Toggle Utility layer visibility (no filter change) ---
// const toggleUtilityLayerVisibility = (
// map: __esri.Map,
// selectedUtilityLayer: string
// ) => {
// const utilityGroup = map.layers.find(
// (l: any) => (l.title ?? "").toString().toLowerCase().includes("utility")
// ) as __esri.GroupLayer;
// if (!utilityGroup || !("layers" in utilityGroup)) return;
// utilityGroup.visible = true;
// const children = utilityGroup.layers.toArray();
// for (const child of children) {
// const layerTitle = (child.title ?? "").toLowerCase();
// // Case 1: "all" → show all utility layers
// if (selectedUtilityLayer === "all") {
// child.visible = true;
// }
// // Case 2: specific layer selected → only show that one
// else if (layerTitle === selectedUtilityLayer) {
// child.visible = true;
// }
// // Hide everything else
// else {
// child.visible = false;
// }
// }
// };
// const toggleUtilityLayerVisibility = (
// map: __esri.Map,
// selectedUtilityLayer: string
// ) => {
// // find the right group layer (adjust title match if needed)
// const utilityGroup = map.layers.find(
// (l: any) =>
// (l.title ?? "").toString().trim().toLowerCase() === "utility" ||
// (l.title ?? "").toString().toLowerCase().includes("utility")
// ) as __esri.GroupLayer;
// if (!utilityGroup || !("layers" in utilityGroup)) {
// console.warn("Utility group not found");
// return;
// }
// utilityGroup.visible = true;
// const children = utilityGroup.layers.toArray();
// children.forEach(child => {
// const layerTitle = (child.title ?? "").toLowerCase();
// if (selectedUtilityLayer === "all") {
// child.visible = true;
// } else if (layerTitle === selectedUtilityLayer.toLowerCase()) {
// child.visible = true;
// } else {
// child.visible = false;
// }
// });
// };
// const toggleUtilityLayerVisibility = (
// map: __esri.Map,
// selectedUtilityLayer: string
// ) => {
// const utilityGroup = map.layers.find(
// (l: any) =>
// (l.title ?? "").toString().trim().toLowerCase() === "utility" ||
// (l.title ?? "").toString().toLowerCase().includes("utility")
// ) as __esri.GroupLayer;
// if (!utilityGroup || !("layers" in utilityGroup)) {
// console.warn("Utility group not found");
// return;
// }
// utilityGroup.visible = true;
// const children = utilityGroup.layers.toArray();
// children.forEach(child => {
// const layerTitle = (child.title ?? "").toLowerCase();
// console.log("Comparing:", layerTitle, "with", selectedUtilityLayer.toLowerCase());
// if (selectedUtilityLayer === "all") {
// child.visible = true;
// } else if (layerTitle === selectedUtilityLayer.toLowerCase()) {
// child.visible = true;
// } else {
// // don't touch visibility if not matching
// console.log("Skipping:", layerTitle);
// }
// });
// };
// const toggleUtilityLayerVisibility = (
// map: __esri.Map,
// selectedUtilityLayer: string
// ) => {
// const utilityGroup = map.layers.find(
// (l: any) =>
// (l.title ?? "").toString().trim().toLowerCase() === "utility" ||
// (l.title ?? "").toLowerCase().includes("utility")
// ) as __esri.GroupLayer;
// if (!utilityGroup || !("layers" in utilityGroup)) {
// console.warn("Utility group not found");
// return;
// }
// utilityGroup.visible = true;
// // Recursive function to check children (FeatureLayers or GroupLayers)
// const toggleChildren = (layers: __esri.Collection<__esri.Layer>) => {
// layers.forEach((child: any) => {
// const childTitle = (child.title ?? "").toLowerCase();
// if ("layers" in child) {
// // child is a subgroup → recurse
// toggleChildren(child.layers);
// } else {
// if (selectedUtilityLayer === "all") {
// child.visible = true;
// console.log("Showing:", child.title);
// } else if (childTitle === selectedUtilityLayer.toLowerCase()) {
// child.visible = true;
// console.log("Matched:", child.title);
// } else {
// child.visible = false;
// console.log("Hiding:", child.title);
// }
// }
// });
// };
// toggleChildren(utilityGroup.layers);
// };
// const toggleUtilityLayerVisibility = (
// map: __esri.Map,
// selectedUtilityLayer: string
// ) => {
// const utilityGroup = map.layers.find(
// (l: any) =>
// (l.title ?? "").toString().trim().toLowerCase() === "utility" ||
// (l.title ?? "").toLowerCase().includes("utility")
// ) as __esri.GroupLayer;
// if (!utilityGroup || !("layers" in utilityGroup)) {
// console.warn("Utility group not found");
// return;
// }
// // keep the utility group itself visible
// utilityGroup.visible = true;
// // 🚨 Do NOT touch other top-level layers like Road, Asset, etc.
// // Only change children inside Utility group
// const toggleChildren = (layers: __esri.Collection<__esri.Layer>) => {
// layers.forEach((child: any) => {
// const childTitle = (child.title ?? "").trim().toLowerCase();
// if ("layers" in child) {
// // recurse if subgroup
// toggleChildren(child.layers);
// } else {
// if (selectedUtilityLayer === "all") {
// child.visible = true; // show all utility sublayers
// } else if (childTitle === selectedUtilityLayer.toLowerCase()) {
// child.visible = true; // show only selected
// } else {
// child.visible = false; // hide other utility sublayers
// }
// }
// });
// };
// toggleChildren(utilityGroup.layers);
// };
const toggleUtilityLayerVisibility = (
map: __esri.Map,
selectedUtilityLayer: string
) => {
const utilityGroup = map.layers.find(
(l: any) =>
(l.title ?? "").toString().trim().toLowerCase() === "utility" ||
(l.title ?? "").toLowerCase().includes("utility")
) as __esri.GroupLayer;
if (!utilityGroup || !("layers" in utilityGroup)) {
console.warn("Utility group not found");
return;
}
utilityGroup.visible = true;
// names of layers we DON'T want to affect
const exclude = ["road", "asset"];
const toggleChildren = (layers: __esri.Collection<__esri.Layer>) => {
layers.forEach((child: any) => {
const childTitle = (child.title ?? "").trim().toLowerCase();
if ("layers" in child) {
toggleChildren(child.layers);
} else {
if (exclude.includes(childTitle)) {
// 🚫 skip road/asset etc.
child.visible = true;
return;
}
if (selectedUtilityLayer === "all") {
child.visible = true;
} else if (childTitle === selectedUtilityLayer.toLowerCase()) {
child.visible = true;
} else {
child.visible = false;
}
}
});
};
toggleChildren(utilityGroup.layers);
};
//Apply filters to utility layers
// const applyFilters = async () => {
// if (!jimuMapView?.view) return;
// const view = jimuMapView.view;
// const map = view.map;
// const defExp = buildWhereClause() || "1=1";
// const selected = (selectedUtilityLayer ?? "").toString().trim();
// // Keep Road & Asset groups visible & filtered
// const roadLayerTitles = ["Road", "CarraigeWay"];
// const assetLayerTitles = ["Asset Point", "Asset Building"];
// // --- Road group ---
// const roadGroup = map.layers.find(l => l.title === "Transporations") as __esri.GroupLayer;
// if (roadGroup && "layers" in roadGroup) {
// roadGroup.visible = true;
// roadGroup.layers.forEach((sub: any) => {
// if (roadLayerTitles.includes(sub.title) && "definitionExpression" in sub) {
// // Road schema field is `ward`
// sub.definitionExpression = defExp.replace(/ward_number/gi, "ward");
// }
// sub.visible = true;
// });
// }
// // --- Asset group ---
// const assetGroup = map.layers.find(l => l.title === "GCC Asset Layers") as __esri.GroupLayer;
// if (assetGroup && "layers" in assetGroup) {
// assetGroup.visible = true;
// assetGroup.layers.forEach((sub: any) => {
// if (assetLayerTitles.includes(sub.title) && "definitionExpression" in sub) {
// // Asset schema field is `ward_no`
// sub.definitionExpression = defExp.replace(/ward_number/gi, "ward_no");
// }
// sub.visible = true;
// });
// }
// const safeTitle = (t?: string | null) => (t ?? "").toString().trim();
// const lower = (s?: string) => safeTitle(s).toLowerCase();
// try {
// // Find Utility group (do NOT hide it by default) and ensure it's visible
// const utilityGroup = map.layers.find(
// (l: any) => safeTitle(l.title).toLowerCase().includes("utility")
// );
// if (utilityGroup) utilityGroup.visible = true;
// // Remove any previously added temporary FeatureLayer (we'll add a new one if needed)
// if (addedUtilityLayerRef.current) {
// try {
// map.layers.remove(addedUtilityLayerRef.current);
// } catch (e) { /* ignore */ }
// addedUtilityLayerRef.current = null;
// }
// // If "All" -> show all relevant children and apply defExp where possible
// if (selected === "" || lower(selected) === "all") {
// if (utilityGroup && "layers" in utilityGroup && typeof utilityGroup.layers?.toArray === "function") {
// const children = utilityGroup.layers.toArray();
// for (const child of children) {
// try {
// if ("definitionExpression" in child) {
// try { child.definitionExpression = defExp; } catch (e) { /* ignore */ }
// }
// child.visible = true;
// } catch (e) { console.warn("Error enabling child for All", child, e); }
// }
// utilityGroup.visible = true;
// }
// return;
// }
// // 3) Find the utilityLayers entry and service URL for the selected utility
// const layerInfo = utilityLayers.find(u => lower(u.title) === lower(selected));
// if (!layerInfo) {
// console.warn("Selected utility not found in utilityLayers config:", selected);
// return;
// }
// const serviceUrl = `${UTILITY_GROUP_URL}/${layerInfo.id}`;
// // 4) Try to find an existing layer in the map whose .url matches the service url
// let foundLayer: any = null;
// const walkAndFindByUrl = (top: any) => {
// if (top?.url && top.url === serviceUrl) return top;
// if ("layers" in top && typeof top.layers?.toArray === "function") {
// for (const c of top.layers.toArray()) {
// if (c?.url && c.url === serviceUrl) return c;
// }
// }
// if ("sublayers" in top && typeof top.sublayers?.toArray === "function") {
// for (const s of top.sublayers.toArray()) {
// if (s?.url && s.url === serviceUrl) return s;
// }
// }
// return null;
// };
// for (const topLayer of map.layers.toArray()) {
// try {
// const match = walkAndFindByUrl(topLayer);
// if (match) { foundLayer = match; break; }
// } catch (e) { /* ignore per-layer errors */ }
// }
// // 5) If found in map, show and apply definitionExpression (best-case)
// // if (foundLayer) {
// // try {
// // // Make sure road & asset groups remain visible (don't hide them)
// // foundLayer.visible = true;
// // if ("definitionExpression" in foundLayer) {
// // try { foundLayer.definitionExpression = defExp; } catch (e) { /* ignore */ }
// // }
// // if (utilityGroup) utilityGroup.visible = true;
// // // Hide other utility children (optional) but keep ROAD/ASSET visible. We'll hide other utilities so user sees selected one clearly.
// // if (utilityGroup && "layers" in utilityGroup && typeof utilityGroup.layers?.toArray === "function") {
// // const children = utilityGroup.layers.toArray();
// // for (const child of children) {
// // try {
// // if (child?.url && child.url === serviceUrl) {
// // child.visible = true;
// // if ("definitionExpression" in child) child.definitionExpression = defExp;
// // } else {
// // // hide other utility types (still keep groups for Road/Asset untouched)
// // try { child.visible = false; } catch (e) { /* ignore */ }
// // }
// // } catch (e) { /* ignore */ }
// // }
// // }
// // return;
// // } catch (err) {
// // console.warn("Error enabling existing layer:", err);
// // }
// // }
// if (foundLayer) {
// try {
// foundLayer.visible = true;
// const where = buildWhereClause(); // uses ward_number by design
// // apply to the found layer
// try { if (typeof foundLayer.definitionExpression !== 'undefined') foundLayer.definitionExpression = where; } catch(e){}
// // if it has sublayers (MapImageLayer), apply to sublayers too
// if (foundLayer.sublayers && typeof foundLayer.sublayers.toArray === 'function') {
// foundLayer.sublayers.toArray().forEach((sl: any) => {
// try { if (typeof sl.definitionExpression !== 'undefined') sl.definitionExpression = where; } catch(e){}
// });
// }
// if (utilityGroup) utilityGroup.visible = true;
// // Optionally hide other utility children so the selected one stands out (comment/uncomment)
// if (utilityGroup && "layers" in utilityGroup && typeof utilityGroup.layers?.toArray === "function") {
// const children = utilityGroup.layers.toArray();
// for (const child of children) {
// try {
// if (child?.url && child.url === serviceUrl) {
// child.visible = true;
// if (typeof child.definitionExpression !== 'undefined') child.definitionExpression = where;
// } else {
// // hide other utility children (if you want)
// try { child.visible = false; } catch(e) {}
// }
// } catch (e) { /* ignore */ }
// }
// }
// return;
// } catch (err) {
// console.warn("Error enabling existing layer:", err);
// }
// }
// // 6) If no matching layer found in map, add a new client FeatureLayer that points to the service endpoint.
// try {
// // const fl = new FeatureLayer({
// // url: serviceUrl,
// // title: `${selected} (temp)`,
// // visible: true,
// // definitionExpression: defExp
// // });
// // await fl.load();
// // map.layers.add(fl); // add top-level
// // addedUtilityLayerRef.current = fl;
// const fl = new FeatureLayer({
// url: serviceUrl,
// title: `${selected} (temp)`,
// visible: true
// });
// await fl.load();
// // apply the same ward-level where clause (buildWhereClause uses ward_number)
// try { fl.definitionExpression = buildWhereClause(); } catch(e) {}
// map.layers.add(fl);
// addedUtilityLayerRef.current = fl;
// if (utilityGroup) utilityGroup.visible = true;
// return;
// } catch (err) {
// console.error("Failed to add FeatureLayer for selected utility:", err);
// }
// } catch (err) {
// console.error("applyFilters error:", err);
// }
// };
// Replace your existing applyWardFilterToLayers with this implementation
// const applyWardFilterToLayers = async (wardValue: string, viewMap: __esri.Map) => {
// if (!viewMap) return;
// // Reset: show everything and clear any dynamically added utility layer
// if (!wardValue || wardValue === "All") {
// const topLayers: any[] = (viewMap.layers && typeof (viewMap.layers as any).toArray === "function")
// ? (viewMap.layers as any).toArray()
// : Array.from((viewMap.layers as any) || []);
// topLayers.forEach((layer: any) => {
// try {
// // Group layers with children
// if (layer.layers && typeof layer.layers.toArray === 'function') {
// const children = layer.layers.toArray();
// children.forEach((child: any) => {
// try {
// if (typeof child.definitionExpression !== 'undefined') {
// child.definitionExpression = "1=1";
// } else if (child.sublayers && typeof child.sublayers.toArray === 'function') {
// child.sublayers.toArray().forEach((sl: any) => {
// try { if (typeof sl.definitionExpression !== 'undefined') sl.definitionExpression = "1=1"; } catch(e) {}
// });
// }
// try { child.visible = true; } catch(e) {}
// } catch(e) {}
// });
// return;
// }
// // Top-level feature layers
// try { if (typeof (layer as any).definitionExpression !== 'undefined') (layer as any).definitionExpression = "1=1"; } catch(e) {}
// try { layer.visible = true; } catch(e) {}
// } catch(e) {}
// });
// // Remove any temporary utility layer we added before
// if (addedUtilityLayerRef.current) {
// try { viewMap.layers.remove(addedUtilityLayerRef.current); } catch(e) {}
// addedUtilityLayerRef.current = null;
// }
// return;
// }
// // Specific ward -> apply ward filter to each group/sub-layer.
// const wardFilter = `ward_number = '${safe(wardValue)}'`;
// const topLayers: any[] = (viewMap.layers && typeof (viewMap.layers as any).toArray === "function")
// ? (viewMap.layers as any).toArray()
// : Array.from((viewMap.layers as any) || []);
// for (const layer of topLayers) {
// try {
// // Transportation group: filter by ward (field name is ward)
// if ((layer.title || '').toString().toLowerCase().includes('transpor') && layer.layers && typeof layer.layers.toArray === 'function') {
// layer.visible = true;
// layer.layers.toArray().forEach((sub: any) => {
// try {
// if (typeof sub.definitionExpression !== 'undefined') {
// // Road layer uses 'ward' field in your schema
// sub.definitionExpression = wardFilter.replace(/ward_number/gi, 'ward');
// }
// sub.visible = true;
// } catch (e) {}
// });
// continue;
// }
// // Asset group: filter by ward_no (if required)
// if ((layer.title || '').toString().toLowerCase().includes('asset') && layer.layers && typeof layer.layers.toArray === 'function') {
// layer.visible = true;
// layer.layers.toArray().forEach((sub: any) => {
// try {
// if (typeof sub.definitionExpression !== 'undefined') {
// sub.definitionExpression = wardFilter.replace(/ward_number/gi, 'ward_no');
// }
// sub.visible = true;
// } catch (e) {}
// });
// continue;
// }
// // Utility group: apply ward_number filter to every child (they all use ward_number)
// if ((layer.title || '').toString().toLowerCase().includes('utility')) {
// layer.visible = true;
// // If the utility layer is a GroupLayer with .layers
// if (layer.layers && typeof layer.layers.toArray === 'function') {
// const children = layer.layers.toArray();
// for (const child of children) {
// try {
// if (typeof child.definitionExpression !== 'undefined') {
// // APPLY ward_number directly (you said all utility layers have ward_number)
// child.definitionExpression = wardFilter;
// } else if (child.sublayers && typeof child.sublayers.toArray === 'function') {
// // MapImageLayer sublayers
// child.sublayers.toArray().forEach((sl: any) => {
// try { if (typeof sl.definitionExpression !== 'undefined') sl.definitionExpression = wardFilter; } catch(e) {}
// });
// } else {
// // fallback: just make sure child is visible
// try { child.visible = true; } catch(e) {}
// }
// } catch (e) {
// console.warn('applyWardFilterToLayers: error applying to utility child', e);
// }
// }
// } else {
// // If the utility layer itself is a FeatureLayer
// try { if (typeof (layer as any).definitionExpression !== 'undefined') (layer as any).definitionExpression = wardFilter; } catch(e) {}
// try { layer.visible = true; } catch(e) {}
// }
// }
// } catch (err) {
// console.warn('applyWardFilterToLayers: loop error', err);
// }
// } // end for
// };
const applyWardFilterToLayers = async (wardValue: string, viewMap: __esri.Map) => {
if (!viewMap) return;
// Helper to safely apply ward filter recursively
const applyWardToLayer = (layer: any, filter: string) => {
try {
// Skip ZoneBoundary and WardBoundary layers
const title = (layer.title || '').toLowerCase();
if (title.includes('zoneboundary') || title.includes('wardboundary')) {
layer.visible = true;
return;
}
// FeatureLayer
if (layer.type === 'feature' && typeof layer.definitionExpression !== 'undefined') {
layer.definitionExpression = filter;
layer.visible = true;
}
// MapImageLayer or GroupLayer with sublayers
else if (layer.sublayers && typeof layer.sublayers.toArray === 'function') {
layer.sublayers.toArray().forEach((sl: any) => applyWardToLayer(sl, filter));
}
else if (layer.layers && typeof layer.layers.toArray === 'function') {
layer.layers.toArray().forEach((child: any) => applyWardToLayer(child, filter));
}
else {
layer.visible = true; // fallback
}
} catch (e) {
console.warn('applyWardToLayer error', e);
}
};
// Reset all layers if "All" is selected
if (!wardValue || wardValue === "All") {
const topLayers: any[] = (viewMap.layers && typeof (viewMap.layers as any).toArray === "function")
? (viewMap.layers as any).toArray()
: Array.from((viewMap.layers as any) || []);
topLayers.forEach((layer: any) => applyWardToLayer(layer, "1=1"));
if (addedUtilityLayerRef.current) {
try { viewMap.layers.remove(addedUtilityLayerRef.current); } catch(e) {}
addedUtilityLayerRef.current = null;
}
return;
}
// Specific ward filter
const wardFilter = `ward_number = '${safe(wardValue)}'`;
const topLayers: any[] = (viewMap.layers && typeof (viewMap.layers as any).toArray === "function")
? (viewMap.layers as any).toArray()
: Array.from((viewMap.layers as any) || []);
for (const layer of topLayers) {
try {
const title = (layer.title || '').toLowerCase();
// Skip zone/ward boundary layers
if (title.includes('zoneboundary') || title.includes('wardboundary')) continue;
// Transportation group: field is 'ward'
if (title.includes('transpor')) {
layer.visible = true;
if (layer.layers && typeof layer.layers.toArray === 'function') {
layer.layers.toArray().forEach((sub: any) => {
applyWardToLayer(sub, wardFilter.replace(/ward_number/gi, 'ward'));
});
}
continue;
}
// Asset group: field is 'ward_no'
if (title.includes('asset')) {
layer.visible = true;
if (layer.layers && typeof layer.layers.toArray === 'function') {
layer.layers.toArray().forEach((sub: any) => {
applyWardToLayer(sub, wardFilter.replace(/ward_number/gi, 'ward_no'));
});
}
continue;
}
// Utility group: all use 'ward_number'
if (title.includes('utility')) {
layer.visible = true;
applyWardToLayer(layer, wardFilter);
continue;
}
// Other top-level layers: fallback
applyWardToLayer(layer, wardFilter);
} catch (err) {
console.warn('applyWardFilterToLayers loop error', err);
}
}
};
// const applyWardFilterToLayers = async (wardValue: string, viewMap: __esri.Map) => {
// if (!wardValue || wardValue === "All") {
// // Reset → show all features in all layers
// viewMap.layers.forEach(layer => {
// if ("layers" in layer) {
// layer.layers.forEach((sub: any) => {
// if ("definitionExpression" in sub) {
// sub.definitionExpression = "1=1"; // show all features
// }
// sub.visible = true; // keep all visible
// });
// } else if ((layer as any).type === 'feature') {
// try { (layer as any).definitionExpression = "1=1"; } catch(e){}
// layer.visible = true;
// }
// });
// // Also reset any dynamically added utility layer
// if (addedUtilityLayerRef.current) {
// try {
// viewMap.layers.remove(addedUtilityLayerRef.current);
// } catch (e) { /* ignore */ }
// addedUtilityLayerRef.current = null;
// }
// return;
// }
// const roadLayerTitles = ["Road", "CarraigeWay"];
// const assetLayerTitles = ["Asset Point", "Asset Building"];
// // 🔹 Transportation group (filter by `ward`)
// const roadGroup = viewMap.layers.find(l => l.title === "Transporations") as __esri.GroupLayer;
// if (roadGroup) {
// roadGroup.visible = true;
// roadGroup.layers.forEach((sub: any) => {
// if (roadLayerTitles.includes(sub.title) && "definitionExpression" in sub) {
// sub.definitionExpression = `ward = '${wardValue}'`; // ✅ correct field
// }
// sub.visible = true;
// });
// }
// // 🔹 Asset group (filter by `ward_no`)
// const assetGroup = viewMap.layers.find(l => l.title === "GCC Asset Layers") as __esri.GroupLayer;
// if (assetGroup) {
// assetGroup.visible = true;
// assetGroup.layers.forEach((sub: any) => {
// if (assetLayerTitles.includes(sub.title) && "definitionExpression" in sub) {
// sub.definitionExpression = `ward_no = '${wardValue}'`; // ✅ correct field
// }
// sub.visible = true;
// });
// }
// // 🔹 Utility group (filter utilities by ward_number) — ensure we DON'T hide the group
// const utilityGroup = viewMap.layers.find((l: any) => (l.title ?? '').toString().toLowerCase().includes('utility')) as __esri.GroupLayer;
// if (utilityGroup && "layers" in utilityGroup && typeof utilityGroup.layers?.toArray === 'function') {
// utilityGroup.visible = true;
// const children = utilityGroup.layers.toArray();
// for (const child of children) {
// try {
// if ("definitionExpression" in child) {
// // apply ward filter on utility children using ward_number
// child.definitionExpression = `ward_number = '${safe(wardValue)}'`;
// }
// // Keep utilities visible so user can see them filtered by ward
// child.visible = true;
// } catch (e) {
// console.warn('Error applying ward filter to utility child', child, e);
// }
// }
// }
// };
useEffect(() => {
if (jimuMapView?.view && selectedWard) {
applyWardFilterToLayers(selectedWard, jimuMapView.view.map);
updateWardBoundaryVisibility(selectedWard); // Add this line to update ward boundary visibility
}
}, [selectedWard, jimuMapView]);
// Apply filters when utility-related filters change
useEffect(() => {
if (jimuMapView && selectedLayer === "Utility") {
applyFilters();
}
}, [selectedZone, selectedWard, selectedUtilityLayer, selectedRoadName, jimuMapView]);
const handleSubmit = async (e: React.MouseEvent) => {
e.preventDefault();
setIsLoading(true);
if (!selectedZone) {
alert("Please select a Zone");
setIsLoading(false);
return;
}
if (!jimuMapView?.view) {
setIsLoading(false);
return;
}
try {
// 1. Apply filters first
await applyFilters();
let zoomed = false;
// 2. Query features only when a single utility is selected
if (selectedLayer === "Utility" && selectedUtilityLayer && selectedUtilityLayer !== "All") {
const layerInfo = utilityLayers.find(l => l.title === selectedUtilityLayer);
if (layerInfo) {
const layer = new FeatureLayer({ url: `${UTILITY_GROUP_URL}/${layerInfo.id}` });
const query = layer.createQuery();
query.where = buildWhereClause();
query.outFields = ["*"];
query.returnGeometry = true;
const result = await layer.queryFeatures(query);
setTableData(result.features);
// Zoom to filtered features if any
if (result.features.length > 0) {
const extent = result.features.reduce(
(acc, f) => acc ? acc.union(f.geometry.extent) : f.geometry.extent,
null as __esri.Extent | null
);
if (extent) {
await jimuMapView.view.goTo({ target: extent, padding: 100, duration: 1000 });
zoomed = true;
}
}
}
} else if (selectedLayer === "Utility" && selectedUtilityLayer === "All") {
// Clear table when all utilities are shown
setTableData([]);
}
// 3. If nothing was zoomed yet, zoom to ward/zone
if (!zoomed) {
if (selectedWard && selectedWard !== "All") {
await zoomToWardGeometry(selectedWard);
} else if (selectedZone && selectedZone !== "All") {
await zoomToZoneGeometry(selectedZone);
}
}
} catch (error) {
console.error("Error in handleSubmit:", error);
} finally {
setIsLoading(false);
}
};
// Zoom to individual feature with highlight
const zoomToFeature = async (feature: any) => {
if (!jimuMapView?.view || !feature?.geometry) return;
const view = jimuMapView.view;
try {
// Clear previous highlight
if (highlightRef.current) {
highlightRef.current.remove();
highlightRef.current = null;
}
// Clear any existing graphics
if (graphicsLayerRef.current) {
view.graphics.remove(graphicsLayerRef.current);
}
// Create highlight symbol based on feature type
let highlightSymbol;
if (feature.geometry.type === "point") {
highlightSymbol = {
type: "simple-marker",
color: [255, 0, 0, 0.8],
size: 12,
outline: {
color: [255, 255, 255],
width: 2
}
};
} else if (feature.geometry.type === "polyline") {
highlightSymbol = new SimpleLineSymbol({
color: [255, 0, 0, 0.8],
width: 4
});
} else {
highlightSymbol = new SimpleFillSymbol({
color: [255, 0, 0, 0.3],
outline: {
color: [255, 0, 0],
width: 2
}
});
}
// Create highlight graphic
const highlightGraphic = new Graphic({
geometry: feature.geometry,
symbol: highlightSymbol
});
// Add to map and store reference
view.graphics.add(highlightGraphic);
graphicsLayerRef.current = highlightGraphic;
// Zoom to feature
await view.goTo({
target: feature.geometry,
zoom: feature.geometry.type === "point" ? 18 : 14,
duration: 1000
});
} catch (error) {
console.error("Error zooming to feature:", error);
}
};
// Reset button handler
const handleReset = () => {
setSelectedZone("");
setSelectedWard("");
setSelectedLayer("");
setSelectedUtilityLayer("All");
setSelectedRoadName("");
setUtilityCount(null);
setTableData([]);
setRoadNameOptions([]);
setActiveStep(0);
// Clear graphics & highlights
jimuMapView?.view?.graphics.removeAll();
highlightRef.current?.remove();
highlightRef.current = null;
if (jimuMapView?.view) {
const map = jimuMapView.view.map;
// Reset all utility layers and other groups
map.layers.forEach(layer => {
if (layer.type === "feature") {
try { (layer as __esri.FeatureLayer).definitionExpression = "1=1"; } catch(e){}
layer.visible = true;
} else if ("layers" in layer) {
layer.layers.forEach((sub: any) => {
sub.visible = true;
if (sub.type === "feature") try { sub.definitionExpression = "1=1"; } catch(e){}
});
}
});
// Remove dynamically added utility layer
if (addedUtilityLayerRef.current) {
try { map.layers.remove(addedUtilityLayerRef.current); } catch(e){}
addedUtilityLayerRef.current = null;
}
// Restore GCC Asset Layers (and its subs)
const assetGroup = map.layers.find(l => l.title === "GCC Asset Layers");
if (assetGroup && "layers" in assetGroup) {
assetGroup.visible = true;
assetGroup.layers.forEach((sub: any) => sub.visible = true);
}
// Reset ward boundary layer to show all wards
const wardLayer = map.layers.find(layer =>
layer.url === WARD_LAYER_URL
) as FeatureLayer;
if (wardLayer) {
wardLayer.definitionExpression = "1=1";
wardLayer.visible = true;
}
}
};
// Active view change handler
const activeViewChangeHandler = (jmv: JimuMapView) => {
if (jmv) setJimuMapView(jmv);
};
// Initialize map view
useEffect(() => {
const interval = setInterval(() => {
const view = mapViewManager.getMapView();
if (view) {
setJimuMapView(view);
clearInterval(interval);
}
}, 500);
return () => clearInterval(interval);
}, []);
return (
<div className="property-widget-parent">
<div className="property-widget">
<JimuMapViewComponent
useMapWidgetId={props.useMapWidgetIds?.[0]}
onActiveViewChange={activeViewChangeHandler}
/>
<h3 className="widget-title">Utility Asset Filter</h3>
{/* Zone selection */}
<div className="property_form">
<label>Zone:<span style={{ color: 'red' }}>*</span></label>
<select
value={selectedZone}
onChange={e => {
const value = e.target.value;
setSelectedZone(value);
setSelectedWard("");
setSelectedRoadName("");
setRoadNameOptions([]);
if (value && value !== "All") {
zoomToZoneGeometry(value);
}
}}
required
>
<option value="">--Select Zone--</option>
{zoneOptions.map(zone => (
<option key={zone} value={zone}>{zone}</option>
))}
</select>
</div>
{/* Ward selection */}
<div className="property_form">
<label>Ward:</label>
<select
value={selectedWard}
onChange={e => {
const value = e.target.value;
setSelectedWard(value);
setSelectedRoadName("");
setRoadNameOptions([]);
if (value && value !== "All") {
zoomToWardGeometry(value);
if (jimuMapView?.view) {
applyWardFilterToLayers(value, jimuMapView.view.map);
updateWardBoundaryVisibility(value); // ✅ finish call here
}
} else {
// Reset when "All" is selected
if (jimuMapView?.view) {
applyWardFilterToLayers("All", jimuMapView.view.map);
updateWardBoundaryVisibility("All"); // ✅ reset visibility
}
}
}}
>
<option value="">--Select Ward--</option>
{wardOptions.map(ward => (
<option key={ward} value={ward}>{ward}</option>
))}
</select>
</div>
{/* Layer selection */}
<div className="property_form">
<label>Select Layer:</label>
<select
value={selectedLayer}
onChange={e => {
const layer = e.target.value;
setSelectedLayer(layer);
setSelectedUtilityLayer("All");
setSelectedRoadName("");
setRoadNameOptions([]);
setUtilityCount(null);
}}
>
<option value="">--Select Layer--</option>
<option value="Utility">Utility</option>
</select>
</div>
{/* Show filtering options when Utility is selected */}
{selectedLayer === "Utility" && (
<>
{/* Utility Layer selection */}
<div className="property_form">
<label>Select Utility Type:</label>
<select
value={selectedUtilityLayer}
onChange={e => {
const value = e.target.value;
setSelectedUtilityLayer(value);
setSelectedRoadName("");
if (value !== "All") {
populateRoadNames(value);
} else {
setRoadNameOptions([]);
}
if (jimuMapView?.view) {
const map = jimuMapView.view.map;
toggleUtilityLayerVisibility(map, value.toLowerCase()); // function from earlier
}
}}
disabled={!selectedZone || selectedZone === "All"}
>
<option value="All">All Utilities</option>
{utilityLayerOptions.map(name => (
<option key={name} value={name}>
{name}{selectedUtilityLayer === name && utilityCount !== null ? ` (${utilityCount})` : ""}
</option>
))}
</select>
</div>
{/* Road Name selection */}
{selectedUtilityLayer !== "All" && roadNameOptions.length > 0 && (
<div className="property_form">
<label>Select Road Name:</label>
<select
value={selectedRoadName}
onChange={e => setSelectedRoadName(e.target.value)}
>
<option value="">--All Roads--</option>
{roadNameOptions.map(name => (
<option key={name} value={name}>{name}</option>
))}
</select>
</div>
)}
</>
)}
{/* Action buttons */}
<div className="button-group">
<button
type="button"
className={`submit-button ${isLoading ? 'loading' : ''}`}
onClick={handleSubmit}
disabled={isLoading || !selectedZone || !selectedLayer}
>
{isLoading ? <div className="spinner"></div> : "Apply Filters"}
</button>
<button
type="button"
className="reset-button"
onClick={handleReset}
>
Reset All
</button>
</div>
{/* Results table */}
{tableData.length > 0 && (
<div className="attribute-table">
<h4>Asset Details ({tableData.length} features)</h4>
<div className="table-container">
<table>
<thead>
<tr>
<th>ID</th>
<th>Zone</th>
<th>Ward</th>
<th>Road Name</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{tableData.map((feature, index) => {
const attr = feature.attributes;
return (
<tr key={feature.attributes.OBJECTID || index}>
<td>{attr.OBJECTID || index + 1}</td>
<td>{attr.zone_number || 'N/A'}</td>
<td>{attr.ward_number || 'N/A'}</td>
<td>{attr.road_name || 'N/A'}</td>
<td>
<button
onClick={() => zoomToFeature(feature)}
className="zoom-button"
title="Zoom to feature"
>
<img src={zoomInIcon} alt="Zoom" width={16} height={16} />
</button>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
</div>
)}
{tableData.length === 0 && selectedLayer && (
<div className="no-results">
<p>No assets found with the current filters.</p>
</div>
)}
</div>
</div>
);
};
export default RoadAssetFilter;