"use client"; import { useState, useCallback } from "react"; import { BarChart3, MapPin, Users, Building2, TreePine, Ruler, Sparkles, FileQuestion, Lightbulb, X, Loader2, ChevronDown, ChevronUp, } from "lucide-react"; import { Card, CardContent } from "@/shared/components/ui/card"; import { Button } from "@/shared/components/ui/button"; import { Badge } from "@/shared/components/ui/badge"; import { cn } from "@/shared/lib/utils"; import type { UatDashboardData } from "@/app/api/eterra/uat-dashboard/route"; /* ------------------------------------------------------------------ */ /* Bar component (CSS only) */ /* ------------------------------------------------------------------ */ function Bar({ pct, color = "bg-emerald-500", className, }: { pct: number; color?: string; className?: string; }) { return (
); } /* ------------------------------------------------------------------ */ /* KPI Card */ /* ------------------------------------------------------------------ */ function KpiCard({ icon: Icon, label, value, sub, accent = "text-foreground", }: { icon: React.ComponentType<{ className?: string }>; label: string; value: string | number; sub?: string; accent?: string; }) { return (

{label}

{typeof value === "number" ? value.toLocaleString("ro-RO") : value}

{sub && (

{sub}

)}
); } /* ------------------------------------------------------------------ */ /* Horizontal bar chart */ /* ------------------------------------------------------------------ */ function HBarChart({ data, labelKey, valueKey, pctKey, color = "bg-emerald-500", maxBars = 10, formatValue, }: { data: Record[]; labelKey: string; valueKey: string; pctKey: string; color?: string; maxBars?: number; formatValue?: (v: number) => string; }) { const items = data.slice(0, maxBars); if (items.length === 0) return

Fără date

; const maxPct = Math.max(...items.map((d) => Number(d[pctKey] ?? 0)), 1); return (
{items.map((d, i) => { const pct = Number(d[pctKey] ?? 0); const val = Number(d[valueKey] ?? 0); const label = String(d[labelKey] ?? ""); return (
{label}
{formatValue ? formatValue(val) : val.toLocaleString("ro-RO")}
{pct}%
); })}
); } /* ------------------------------------------------------------------ */ /* Donut-ish ring (CSS conic-gradient) */ /* ------------------------------------------------------------------ */ function DonutRing({ segments, size = 80, }: { segments: { pct: number; color: string; label: string }[]; size?: number; }) { let cumulative = 0; const stops: string[] = []; for (const seg of segments) { const start = cumulative; cumulative += seg.pct; stops.push(`${seg.color} ${start}% ${cumulative}%`); } if (cumulative < 100) { stops.push(`hsl(var(--muted)) ${cumulative}% 100%`); } return (
{segments.map((seg) => (
{seg.label} {seg.pct}%
))}
); } /* ------------------------------------------------------------------ */ /* Main dashboard component */ /* ------------------------------------------------------------------ */ export function UatDashboard({ siruta, uatName, onClose, }: { siruta: string; uatName: string; onClose: () => void; }) { const [data, setData] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(""); const [expanded, setExpanded] = useState>({}); const [loaded, setLoaded] = useState(false); const toggle = (key: string) => setExpanded((prev) => ({ ...prev, [key]: !prev[key] })); const fetchDashboard = useCallback(async () => { setLoading(true); setError(""); try { const res = await fetch( `/api/eterra/uat-dashboard?siruta=${encodeURIComponent(siruta)}`, ); const json = await res.json(); if (json.error) { setError(json.error); } else { setData(json as UatDashboardData); } } catch { setError("Eroare de rețea."); } setLoading(false); setLoaded(true); }, [siruta]); // Auto-fetch on first render if (!loaded && !loading) { void fetchDashboard(); } if (loading && !data) { return (

Se calculează dashboard-ul pentru {uatName}…

); } if (error) { return (

{error}

); } if (!data) return null; return (
{/* ── Header ─────────────────────────────────── */}

Dashboard — {data.uatName}

{data.county && ( ({data.county}) )} {data.siruta}
{/* ── KPI Grid ───────────────────────────────── */}
30 ? "text-red-500" : "text-muted-foreground" } />
{/* ── Row 2: Donut + Area distribution ───────── */}
{/* Intravilan/Extravilan donut */}

Intravilan / Extravilan

0 ? Math.round( (data.mixtCount / (data.intravilanCount + data.extravilanCount + data.mixtCount || 1)) * 100, ) : 0), color: "hsl(30, 70%, 50%)", label: `Extravilan (${data.extravilanCount.toLocaleString("ro-RO")})`, }, ...(data.mixtCount > 0 ? [ { pct: Math.round( (data.mixtCount / (data.intravilanCount + data.extravilanCount + data.mixtCount || 1)) * 100, ), color: "hsl(200, 50%, 55%)", label: `Mixt (${data.mixtCount.toLocaleString("ro-RO")})`, }, ] : []), ]} />
{/* Area distribution */}

Distribuție suprafețe (mp)

[] } labelKey="bucket" valueKey="count" pctKey="pct" color="bg-indigo-500" />
{/* ── Row 3: Land use + Top owners ──────────── */}
{/* Land use */} {(expanded.landuse ?? true) && (
[] } labelKey="category" valueKey="count" pctKey="pct" color="bg-green-500" />
)}
{/* Top owners */} {(expanded.owners ?? true) && (
{data.topOwners.length === 0 ? (

Fără date proprietari (necesită îmbogățire Magic)

) : ( data.topOwners.map((o, i) => (
{i + 1}. {o.name} {o.count} parcele
)) )}
)}
{/* ── Fun facts ────────────────────────────── */} {data.funFacts.length > 0 && (

Observații

    {data.funFacts.map((fact, i) => (
  • {fact}
  • ))}
)} {/* ── Footer meta ──────────────────────────── */}
Ultimul sync:{" "} {data.lastSyncDate ? new Date(data.lastSyncDate).toLocaleString("ro-RO") : "—"} {data.syncRunCount > 0 && ` · ${data.syncRunCount} sync-uri totale`} {data.totalNoGeom > 0 && `${data.totalNoGeom.toLocaleString("ro-RO")} fără geometrie · `} Date la {new Date().toLocaleDateString("ro-RO")}
); }