diff --git a/src/modules/geoportal/v2/feature-info-panel.tsx b/src/modules/geoportal/v2/feature-info-panel.tsx index cf67760..ef4ce0a 100644 --- a/src/modules/geoportal/v2/feature-info-panel.tsx +++ b/src/modules/geoportal/v2/feature-info-panel.tsx @@ -1,6 +1,6 @@ "use client"; -import { useEffect, useMemo, useRef, useState } from "react"; +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { signIn } from "next-auth/react"; import { X, RefreshCw, Loader2, FileText, Download, AlertCircle, @@ -409,7 +409,7 @@ export function FeatureInfoPanel({ feature, onClose, basic = false }: Props) { }; }, [isCladiri, feature.siruta, feature.cadastralRef, basic]); - const refreshFromAncpi = async () => { + const refreshFromAncpi = useCallback(async () => { if (!feature.siruta || !feature.cadastralRef) { setError("missing_siruta_or_cad"); return; @@ -432,15 +432,26 @@ export function FeatureInfoPanel({ feature, onClose, basic = false }: Props) { return; } const techData = await res.json().catch(() => null); - // Refresh stored detail via parcela.get if uuid known. - if (detail?.id || feature.id) { - const id = detail?.id ?? feature.id; - const updated = await fetch( - `/api/gis/parcela/${encodeURIComponent(id)}`, + // After orchestrator updates the central DB, re-fetch via the + // server-side find/get path so we land on the canonical shape + // (and pick up rich enrichment that the tech response itself + // doesn't carry). + const id = detail?.id ?? feature.id; + let updated: Response | null = null; + if (id) { + updated = await fetch(`/api/gis/parcela/${encodeURIComponent(id)}`); + } else { + updated = await fetch( + `/api/gis/parcela/find?siruta=${encodeURIComponent(feature.siruta)}` + + `&cad=${encodeURIComponent(feature.cadastralRef)}` + + `&layerId=${encodeURIComponent(feature.layerId)}`, ); - if (updated.ok) setDetail(await updated.json()); + } + if (updated.ok) { + setDetail(await updated.json()); } else if (techData) { - // Project the orchestrator response into the panel directly. + // Final fallback — project the orchestrator response if we + // can't re-fetch the canonical record. const inner = (techData?.data as Record | undefined) ?? techData; setDetail({ @@ -456,7 +467,44 @@ export function FeatureInfoPanel({ feature, onClose, basic = false }: Props) { } finally { setRefreshing(false); } - }; + }, [ + feature.id, + feature.siruta, + feature.cadastralRef, + feature.layerId, + feature.areaValue, + detail?.id, + ]); + + // Auto-fetch from ANCPI when the central DB has only tech-level keys + // (no NR_CF / ADRESA / PROPRIETARI). The orchestrator caches its results + // for 30 days so repeat clicks on the same parcel don't re-spend quota. + // Dedupe per parcel-key via sessionStorage so a remount or React + // strict-mode double-fire doesn't double the call. + useEffect(() => { + if (basic || !detail || refreshing) return; + const e = (detail.enrichment ?? {}) as Record; + const richPresent = Boolean(e.NR_CF || e.ADRESA || e.PROPRIETARI); + if (richPresent) return; + + const parcelKey = + String(detail.id ?? "") || + `${feature.siruta}:${feature.cadastralRef}:${feature.layerId}`; + const ssKey = `gis_auto_enrich_${parcelKey}`; + if (typeof sessionStorage === "undefined") return; + if (sessionStorage.getItem(ssKey)) return; + sessionStorage.setItem(ssKey, "1"); + + void refreshFromAncpi(); + }, [ + basic, + detail, + refreshing, + feature.siruta, + feature.cadastralRef, + feature.layerId, + refreshFromAncpi, + ]); const exportGpkg = () => { const url = `https://eterra.live/harta?siruta=${encodeURIComponent( @@ -585,6 +633,14 @@ export function FeatureInfoPanel({ feature, onClose, basic = false }: Props) { )} + {/* Auto-enrich is running in background (sparse DB record → fetched from ANCPI) */} + {refreshing && !loading && ( +
+ + Se preiau date suplimentare din ANCPI… +
+ )} + {/* Forbidden after a silent re-grant attempt already failed once — likely Authentik scope misconfig. Stays discreet (no call-to-action), only diag info for the operator. */}