fix(geoportal-v2): gate condo-owners on IS_CONDOMINIUM + visible empty state
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) <noreply@anthropic.com>
This commit is contained in:
@@ -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<string, unknown>;
|
||||
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
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 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) && (
|
||||
<div className="mx-2 my-2">
|
||||
<p className="mb-1 flex items-center gap-1 px-1 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<Users className="h-3 w-3" />
|
||||
@@ -1181,6 +1204,11 @@ export function FeatureInfoPanel({ feature, onClose, onSelectFeature, basic = fa
|
||||
<Loader2 className="h-3 w-3 animate-spin" /> se încarcă…
|
||||
</div>
|
||||
)}
|
||||
{!condoLoading && condoOwners != null && condoOwners.length === 0 && (
|
||||
<p className="px-1 text-[11px] italic text-muted-foreground">
|
||||
Fără apartamente înregistrate la ANCPI.
|
||||
</p>
|
||||
)}
|
||||
{condoOwners && condoOwners.length > 0 && (
|
||||
<div className="space-y-1.5">
|
||||
{condoOwners.map((u, i) => (
|
||||
|
||||
Reference in New Issue
Block a user