"use client"; import { useEffect, useRef, useState } from "react"; import { createPortal } from "react-dom"; import { X, Loader2, Download, AlertCircle, FileText, Map as MapIcon } from "lucide-react"; import { cn } from "@/shared/lib/utils"; import { SignAsPicker } from "../sign-as/sign-as-picker"; import type { SignerPayload } from "../sign-as/types"; export type ExportKind = "piz" | "pad" | "coords" | "dxf"; export interface ExportModalProps { open: boolean; kind: ExportKind; /** GisFeature uuid (when known) — used in the route path. */ parcelId: string; /** Display-only metadata for the modal header. */ cadastralRef: string | null; uatName: string | null; layerId: string | null; onClose: () => void; } const TITLE: Record = { piz: "Plan de încadrare în zonă", pad: "Plan de situație (PAD)", coords: "Coordonate Stereo70 (XLSX)", dxf: "Export DXF", }; const DESCRIPTION: Record = { piz: "PDF A4 cu parcela încadrată la scara 1:5000 peste imagine satelit / ortofoto ANCPI.", pad: "PDF cu plan de amplasament + delimitare, cu cartuș (CF, topo, categorie, adresă) și tabel de coordonate.", coords: "Tabel Excel cu coordonatele vârfurilor (X/Y Stereo70), lungimile segmentelor și suprafața.", dxf: "Fișier DXF al parcelei (+ vecini și clădiri din intersecție) pentru deschidere în AutoCAD / QCAD.", }; const NEEDS_SIGNER: Record = { piz: true, pad: true, coords: false, dxf: false, }; const NEEDS_BASEMAP: Record = { piz: true, pad: false, coords: false, dxf: false, }; const FILE_EXT: Record = { piz: "pdf", pad: "pdf", coords: "xlsx", dxf: "dxf", }; type State = | { kind: "idle" } | { kind: "running" } | { kind: "done"; blobUrl: string; filename: string } | { kind: "error"; message: string }; export function ExportModal({ open, kind, parcelId, cadastralRef, uatName, layerId, onClose, }: ExportModalProps) { const [signer, setSigner] = useState(null); const [coSigner, setCoSigner] = useState(null); const [basemap, setBasemap] = useState<"google" | "orto">("google"); const [state, setState] = useState({ kind: "idle" }); const lastBlobUrl = useRef(null); // Reset transient state when the modal closes or jumps to a new parcel. useEffect(() => { if (!open) { setState({ kind: "idle" }); if (lastBlobUrl.current) { URL.revokeObjectURL(lastBlobUrl.current); lastBlobUrl.current = null; } } }, [open, parcelId]); if (!open) return null; if (typeof document === "undefined") return null; const handleGenerate = async () => { setState({ kind: "running" }); try { const body: Record = {}; if (NEEDS_SIGNER[kind]) { if (!signer) { setState({ kind: "error", message: "Selectează un semnatar." }); return; } body.signer = signer; if (coSigner) body.coSigner = coSigner; } if (NEEDS_BASEMAP[kind]) { body.basemap = basemap; } if (layerId) body.layerId = layerId; const isJsonOnly = kind === "coords" || kind === "dxf"; const res = await fetch(`/api/gis/parcel/${parcelId}/${kind}`, { method: isJsonOnly && kind === "coords" ? "GET" : "POST", headers: { "Content-Type": "application/json" }, body: isJsonOnly && kind === "coords" ? undefined : JSON.stringify(body), }); if (!res.ok) { let msg = `Eroare HTTP ${res.status}`; const text = await res.text(); try { const j = JSON.parse(text); if (typeof j.error === "string") msg = j.error; else if (typeof j.message === "string") msg = j.message; } catch { if (text) msg += `: ${text.slice(0, 200)}`; } setState({ kind: "error", message: msg }); return; } const blob = await res.blob(); const url = URL.createObjectURL(blob); lastBlobUrl.current = url; const cd = res.headers.get("content-disposition") ?? ""; const m = /filename\*?=(?:UTF-8''|"?)([^";]+)/i.exec(cd); const fallback = `${kind}_${cadastralRef ?? parcelId}.${FILE_EXT[kind]}`; const filename = m?.[1] ? decodeURIComponent(m[1]) : fallback; setState({ kind: "done", blobUrl: url, filename }); // Auto-download — most users just want the file. const a = document.createElement("a"); a.href = url; a.download = filename; a.click(); } catch (err) { setState({ kind: "error", message: err instanceof Error ? err.message : String(err), }); } }; return createPortal(
e.stopPropagation()} >
{kind === "piz" ? ( ) : ( )}
{TITLE[kind]}
{cadastralRef && {cadastralRef}} {cadastralRef && uatName && " · "} {uatName}

{DESCRIPTION[kind]}

{NEEDS_BASEMAP[kind] && (
Fundal hartă
)} {NEEDS_SIGNER[kind] && ( )} {state.kind === "error" && (
{state.message}
)} {state.kind === "done" && ( )}
, document.body, ); }