Maintenance Love :)
This commit is contained in:
parent
784bd4d903
commit
021dc7b0c3
@ -426,10 +426,12 @@ export function GadmPicker({ map, active, onClose, onSelectionChange, className
|
||||
if (processingGids.current.has(gid)) return;
|
||||
processingGids.current.add(gid);
|
||||
|
||||
const targetLevel = (forceLevel !== undefined) ? forceLevel : (resolutionOption > gadmLevel ? resolutionOption : gadmLevel);
|
||||
|
||||
let isDuplicate = false;
|
||||
setSelectedRegions(prev => {
|
||||
if (prev.some(r => r.gid === gid)) { isDuplicate = true; return prev; }
|
||||
return [...prev, { gid, gadmName: name, level: gadmLevel, raw: region }];
|
||||
return [...prev, { gid, gadmName: name, level: targetLevel, raw: region }];
|
||||
});
|
||||
|
||||
if (isDuplicate) {
|
||||
@ -441,12 +443,17 @@ export function GadmPicker({ map, active, onClose, onSelectionChange, className
|
||||
setLoadingGid(gid, true);
|
||||
|
||||
try {
|
||||
const targetLevel = (forceLevel !== undefined) ? forceLevel : (resolutionOption > gadmLevel ? resolutionOption : gadmLevel);
|
||||
|
||||
const geojson = await fetchRegionBoundary(
|
||||
let geojson = await fetchRegionBoundary(
|
||||
gid, name || '', targetLevel, enrich
|
||||
);
|
||||
|
||||
if (!geojson.features || geojson.features.length === 0) {
|
||||
console.warn(`No subdivisions found for ${gid} at level ${targetLevel}. Snapping back to level ${gadmLevel}`);
|
||||
|
||||
setSelectedRegions(prev => prev.map(r => r.gid === gid ? { ...r, level: gadmLevel } : r));
|
||||
geojson = await fetchRegionBoundary(gid, name || '', gadmLevel, enrich);
|
||||
}
|
||||
|
||||
let activeStats: Record<string, any> | undefined;
|
||||
if (enrich && geojson.features && geojson.features.length > 0) {
|
||||
const props = geojson.features[0].properties;
|
||||
@ -477,6 +484,27 @@ export function GadmPicker({ map, active, onClose, onSelectionChange, className
|
||||
});
|
||||
};
|
||||
|
||||
const handleFlyToRegion = async (gid: string) => {
|
||||
if (!map) return;
|
||||
const gj = geojsons[gid];
|
||||
if (!gj || !gj.features || gj.features.length === 0) return;
|
||||
|
||||
try {
|
||||
const turf = await import('@turf/turf');
|
||||
const bbox = turf.bbox(gj as any);
|
||||
map.fitBounds(bbox as any, { padding: 50, duration: 800 });
|
||||
} catch (e) {
|
||||
console.error("Failed to fit bounds", e);
|
||||
}
|
||||
};
|
||||
|
||||
const handleReResolveRegion = (region: any, targetLevel: number) => {
|
||||
if (loadingBoundaryIds.has(region.gid)) return;
|
||||
if (targetLevel === region.level) return;
|
||||
handleRemoveRegion(region.gid);
|
||||
handleSelectRegion({ gid: region.gid, gadmName: region.gadmName, level: region.level }, targetLevel, true);
|
||||
};
|
||||
|
||||
const handleCopyToClipboard = async () => {
|
||||
const data = selectedRegions.map(r => ({ gid: r.gid, name: r.gadmName, level: r.level, raw: r.raw }));
|
||||
await navigator.clipboard.writeText(JSON.stringify(data, null, 2));
|
||||
@ -567,15 +595,7 @@ export function GadmPicker({ map, active, onClose, onSelectionChange, className
|
||||
}, [updateMapFeatures]);
|
||||
|
||||
const sidebarContent = active ? (
|
||||
<div className={`p-4 bg-white dark:bg-gray-800 border dark:border-gray-700 rounded-lg shadow-sm w-full h-full max-h-[80vh] flex flex-col space-y-4 ${className}`}>
|
||||
<div className="flex justify-between items-center flex-shrink-0">
|
||||
<h3 className="font-semibold text-gray-800 dark:text-gray-200">GADM Area Selector</h3>
|
||||
{onClose && (
|
||||
<button onClick={onClose} className="text-gray-500 hover:text-gray-700 dark:hover:text-gray-300">
|
||||
<X size={18} />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div className={`w-full h-full flex flex-col space-y-4 ${className}`}>
|
||||
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400 flex-shrink-0">
|
||||
Click anywhere on the map to inspect administrative areas, or use the search below.
|
||||
@ -677,7 +697,14 @@ export function GadmPicker({ map, active, onClose, onSelectionChange, className
|
||||
{selectedRegions.map((region) => {
|
||||
const loading = loadingBoundaryIds.has(region.gid);
|
||||
return (
|
||||
<div key={region.gid} className="flex flex-col bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800/50 rounded-lg p-2">
|
||||
<div
|
||||
key={region.gid}
|
||||
className="flex flex-col bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800/50 rounded-lg p-2 cursor-pointer hover:bg-yellow-100 dark:hover:bg-yellow-900/40 transition-colors"
|
||||
onClick={(e) => {
|
||||
if ((e.target as HTMLElement).closest('button')) return;
|
||||
handleFlyToRegion(region.gid);
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center gap-1.5 justify-between">
|
||||
<div className="flex items-center gap-1.5 font-medium text-yellow-800 dark:text-yellow-300 text-sm">
|
||||
{loading && <Loader2 className="w-3 h-3 animate-spin text-yellow-600"/>}
|
||||
@ -686,8 +713,8 @@ export function GadmPicker({ map, active, onClose, onSelectionChange, className
|
||||
<span className="text-xs opacity-70">({region.gid})</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => handleRemoveRegion(region.gid)}
|
||||
className="text-yellow-600 hover:text-red-500 flex-shrink-0 focus:outline-none ml-2 bg-yellow-100/50 dark:bg-yellow-800/30 p-1 rounded"
|
||||
onClick={(e) => { e.stopPropagation(); handleRemoveRegion(region.gid); }}
|
||||
className="text-yellow-600 hover:text-red-500 flex-shrink-0 focus:outline-none ml-2 bg-yellow-100/50 dark:bg-yellow-800/30 p-1 rounded transition-colors"
|
||||
>
|
||||
<X className="w-3 h-3" />
|
||||
</button>
|
||||
@ -698,6 +725,28 @@ export function GadmPicker({ map, active, onClose, onSelectionChange, className
|
||||
<span><strong className="font-semibold">Pop:</strong> {region.stats.ghsPopulation ? Math.round(region.stats.ghsPopulation).toLocaleString() : 'N/A'}</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="mt-2 flex items-center justify-between border-t border-yellow-200/50 dark:border-yellow-800/50 pt-2 px-1">
|
||||
<span className="text-[10px] uppercase font-bold text-yellow-600/70 dark:text-yellow-500/70 tracking-wider">Change Level</span>
|
||||
<div className="flex items-center bg-yellow-100/50 dark:bg-yellow-900/30 p-0.5 rounded border border-yellow-200 dark:border-yellow-700/50">
|
||||
{[0, 1, 2, 3, 4, 5].map((lvl) => {
|
||||
const isSelected = lvl === region.level;
|
||||
return (
|
||||
<button
|
||||
key={lvl}
|
||||
onClick={(e) => { e.stopPropagation(); handleReResolveRegion(region, lvl); }}
|
||||
className={`px-2 py-0.5 text-[10px] font-bold rounded transition-colors ${
|
||||
isSelected
|
||||
? 'bg-yellow-400 text-yellow-900 shadow-sm'
|
||||
: 'text-yellow-700 dark:text-yellow-400 hover:bg-yellow-200/50 dark:hover:bg-yellow-800/50'
|
||||
}`}
|
||||
title={`Change to Level ${lvl}`}
|
||||
>
|
||||
L{lvl}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user