From 36840f31f6d4441c53dbcb53d5aafc86cad7ab69 Mon Sep 17 00:00:00 2001 From: Claude VM Date: Wed, 20 May 2026 22:03:18 +0300 Subject: [PATCH] fix(geoportal-v2): gate condo-owners on IS_CONDOMINIUM + visible empty state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two issues from Marius's cladiri screenshots: 1. APARTAMENTE "se încarcă…" sat for ~10s then vanished — useEffect fired for every CLADIRI click regardless of whether the building was actually a condo. Orchestrator's /api/v1/building/condo-owners hit eTerra live, got back an empty list for non-condos, returned [], section auto-hid → user saw the spinner blink and disappear. New gate: useEffect waits for `detail` to land, then reads IS_CONDOMINIUM / PARCEL_IS_CONDOMINIUM from enrichment. If neither is `1`, skip the fetch entirely. Non-condos no longer pay the 10s eTerra round-trip just to show nothing. 2. EMPTY CONDO LISTS WERE HIDING SILENTLY — for buildings flagged condo where ANCPI hasn't registered units yet, the section would still vanish (`condoOwners.length > 0` check). Now: if the fetch returns [] AND the building is a condo, render the section with "Fără apartamente înregistrate la ANCPI." That's the truthful UX. Same fallback when the fetch errors — treat as empty rather than swallow. Render trigger flipped from (condoLoading || (condoOwners && condoOwners.length > 0)) to (condoLoading || condoOwners != null) so the section shows whenever the gate decided to fetch. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../geoportal/v2/feature-info-panel.tsx | 36 ++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/src/modules/geoportal/v2/feature-info-panel.tsx b/src/modules/geoportal/v2/feature-info-panel.tsx index cdc0a28..efc0470 100644 --- a/src/modules/geoportal/v2/feature-info-panel.tsx +++ b/src/modules/geoportal/v2/feature-info-panel.tsx @@ -576,8 +576,22 @@ export function FeatureInfoPanel({ feature, onClose, onSelectFeature, basic = fa }, [buildings]); // ── Condo owners for buildings ────────────────────────── + // Only fires for buildings flagged IS_CONDOMINIUM=1 (or + // PARCEL_IS_CONDOMINIUM=1). For everything else the orchestrator's + // eTerra round-trip would take ~10s and come back empty — bad UX. + // We wait for `detail` to land so we can read the flag from enrichment. useEffect(() => { if (basic || !isCladiri || !feature.siruta || !feature.cadastralRef) return; + if (!detail) return; + const e = (detail.enrichment ?? {}) as Record; + const isCondo = + Number(e.IS_CONDOMINIUM ?? 0) === 1 || + Number(e.PARCEL_IS_CONDOMINIUM ?? 0) === 1; + if (!isCondo) { + setCondoOwners(null); + setCondoLoading(false); + return; + } let cancelled = false; setCondoOwners(null); setCondoLoading(true); @@ -593,6 +607,9 @@ export function FeatureInfoPanel({ feature, onClose, onSelectFeature, basic = fa }); if (cancelled) return; if (!r.ok) { + // Treat any failure as "no apartments known" — keep section + // visible with a note instead of hiding silently. + setCondoOwners([]); setCondoLoading(false); return; } @@ -608,14 +625,17 @@ export function FeatureInfoPanel({ feature, onClose, onSelectFeature, basic = fa setCondoLoading(false); } } catch { - if (!cancelled) setCondoLoading(false); + if (!cancelled) { + setCondoOwners([]); + setCondoLoading(false); + } } }; void run(); return () => { cancelled = true; }; - }, [isCladiri, feature.siruta, feature.cadastralRef, basic]); + }, [isCladiri, feature.siruta, feature.cadastralRef, basic, detail]); // ── Manual + auto refresh (deep enrich) ───────────────── const refreshFromAncpi = useCallback( @@ -1164,8 +1184,11 @@ export function FeatureInfoPanel({ feature, onClose, onSelectFeature, basic = fa )} - {/* Apartamente (cladiri only) */} - {!loading && isCladiri && (condoLoading || (condoOwners && condoOwners.length > 0)) && ( + {/* Apartamente (cladiri only — only mounted when IS_CONDOMINIUM=1 + per the gating useEffect; non-condos skip the fetch entirely + so we never sit on a 10s eTerra round-trip just to discover + there's nothing to show). */} + {!loading && isCladiri && (condoLoading || condoOwners != null) && (

@@ -1181,6 +1204,11 @@ export function FeatureInfoPanel({ feature, onClose, onSelectFeature, basic = fa se încarcă…

)} + {!condoLoading && condoOwners != null && condoOwners.length === 0 && ( +

+ Fără apartamente înregistrate la ANCPI. +

+ )} {condoOwners && condoOwners.length > 0 && (
{condoOwners.map((u, i) => (