"use client"; import { ArrowDownToLine, ArrowUpFromLine, Calendar, CheckCircle2, Clock, Copy, ExternalLink, FileText, FolderOpen, GitBranch, HardDrive, Link2, Paperclip, Pencil, Trash2, User, X, Image as ImageIcon, } from "lucide-react"; import { Button } from "@/shared/components/ui/button"; import { Badge } from "@/shared/components/ui/badge"; import { Separator } from "@/shared/components/ui/separator"; import { ScrollArea } from "@/shared/components/ui/scroll-area"; import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription, } from "@/shared/components/ui/sheet"; import type { RegistryEntry } from "../types"; import { DEFAULT_DOC_TYPE_LABELS } from "../types"; import { getOverdueDays } from "../services/registry-service"; import { shortDisplayPath, shareLabelFor } from "@/config/nas-paths"; import { cn } from "@/shared/lib/utils"; import { useState, useCallback } from "react"; interface RegistryEntryDetailProps { entry: RegistryEntry | null; open: boolean; onOpenChange: (open: boolean) => void; onEdit: (entry: RegistryEntry) => void; onClose: (id: string) => void; onDelete: (id: string) => void; allEntries: RegistryEntry[]; } const DIRECTION_CONFIG = { intrat: { label: "Intrat", icon: ArrowDownToLine, class: "bg-blue-100 text-blue-800 dark:bg-blue-900/40 dark:text-blue-300", }, iesit: { label: "Ieșit", icon: ArrowUpFromLine, class: "bg-orange-100 text-orange-800 dark:bg-orange-900/40 dark:text-orange-300", }, } as const; const STATUS_CONFIG = { deschis: { label: "Deschis", class: "bg-emerald-100 text-emerald-800 dark:bg-emerald-900/40 dark:text-emerald-300", }, inchis: { label: "Închis", class: "bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400", }, } as const; const RESOLUTION_LABELS: Record = { finalizat: "Finalizat", "aprobat-tacit": "Aprobat tacit", respins: "Respins", retras: "Retras", altele: "Altele", }; const DEADLINE_RES_LABELS: Record = { pending: "În așteptare", completed: "Finalizat", "aprobat-tacit": "Aprobat tacit", respins: "Respins", anulat: "Anulat", }; function getDocTypeLabel(type: string): string { const label = DEFAULT_DOC_TYPE_LABELS[type]; if (label) return label; return type.replace(/-/g, " ").replace(/^\w/, (c) => c.toUpperCase()); } function formatDate(iso: string): string { try { return new Date(iso).toLocaleDateString("ro-RO", { day: "2-digit", month: "2-digit", year: "numeric", }); } catch { return iso; } } function formatDateTime(iso: string): string { try { return new Date(iso).toLocaleString("ro-RO", { day: "2-digit", month: "2-digit", year: "numeric", hour: "2-digit", minute: "2-digit", }); } catch { return iso; } } export function RegistryEntryDetail({ entry, open, onOpenChange, onEdit, onClose, onDelete, allEntries, }: RegistryEntryDetailProps) { const [previewAttachment, setPreviewAttachment] = useState( null, ); const [copiedPath, setCopiedPath] = useState(null); const copyPath = useCallback(async (path: string) => { await navigator.clipboard.writeText(path); setCopiedPath(path); setTimeout(() => setCopiedPath(null), 2000); }, []); if (!entry) return null; const dir = DIRECTION_CONFIG[entry.direction] ?? DIRECTION_CONFIG.intrat; const DirIcon = dir.icon; const status = STATUS_CONFIG[entry.status] ?? STATUS_CONFIG.deschis; const overdueDays = entry.status === "deschis" ? getOverdueDays(entry.deadline) : null; const isOverdue = overdueDays !== null && overdueDays > 0; const threadParent = entry.threadParentId ? allEntries.find((e) => e.id === entry.threadParentId) : null; const threadChildren = allEntries.filter( (e) => e.threadParentId === entry.id, ); return (
{entry.number} {entry.subject}
{/* Action bar */}
{entry.status === "deschis" && ( )}
{/* ── Status row ── */}
{dir.label} {status.label} {getDocTypeLabel(entry.documentType)} {entry.company && ( {entry.company} )}
{/* ── Closure info ── */} {entry.closureInfo && (
Rezoluție: {RESOLUTION_LABELS[entry.closureInfo.resolution] ?? entry.closureInfo.resolution}
{entry.closureInfo.reason && (

Motiv:{" "} {entry.closureInfo.reason}

)} {entry.closureInfo.closedBy && (

Închis de {entry.closureInfo.closedBy} la{" "} {formatDateTime(entry.closureInfo.closedAt)}

)}
)} {/* ── Date ── */}
{entry.registrationDate && entry.registrationDate !== entry.date && ( )} {entry.deadline && ( 0 ? `(${overdueDays} zile depășit)` : overdueDays !== null && overdueDays < 0 ? `(mai sunt ${Math.abs(overdueDays)} zile)` : undefined } /> )} {entry.expiryDate && ( )}
{/* ── Parties ── */}
{entry.sender && ( )} {entry.recipient && ( )} {entry.assignee && ( } /> )}
{(entry.recipientRegNumber || entry.recipientRegDate) && (
{entry.recipientRegNumber && ( Nr. destinatar: {entry.recipientRegNumber} )} {entry.recipientRegDate && ( Data: {formatDate(entry.recipientRegDate)} )}
)}
{/* ── Thread links ── */} {(threadParent || threadChildren.length > 0 || (entry.linkedEntryIds ?? []).length > 0) && ( {threadParent && (
Răspuns la: {threadParent.number} — {threadParent.subject}
)} {threadChildren.length > 0 && (

Răspunsuri ({threadChildren.length}):

{threadChildren.map((child) => (
{child.number} {child.subject}
))}
)} {(entry.linkedEntryIds ?? []).length > 0 && (

{entry.linkedEntryIds.length} înregistrăr {entry.linkedEntryIds.length === 1 ? "e" : "i"} legat {entry.linkedEntryIds.length === 1 ? "ă" : "e"}

)}
)} {/* ── Attachments ── */} {entry.attachments.length > 0 && (
{entry.attachments.map((att) => att.networkPath ? (
copyPath(att.networkPath!)} title="Click pentru a copia calea — lipește în Explorer" >
{shortDisplayPath(att.networkPath)}
{shareLabelFor(att.networkPath) ?? "NAS"} {copiedPath === att.networkPath ? ( Copiat! ) : ( )}

{att.networkPath}

) : (
{att.type.startsWith("image/") ? ( ) : ( )}

{att.name}

{(att.size / 1024).toFixed(0)} KB •{" "} {att.type.split("/")[1]?.toUpperCase() ?? att.type}

{/* Preview for images */} {att.type.startsWith("image/") && att.data && att.data !== "" && att.data !== "__network__" && ( )} {/* Download for files with data */} {att.data && att.data !== "" && att.data !== "__network__" && ( )} Fișier
), )}
{/* Image preview modal */} {previewAttachment && (
{(() => { const att = entry.attachments.find( (a) => a.id === previewAttachment, ); if ( !att || !att.type.startsWith("image/") || !att.data || att.data === "" || att.data === "__network__" ) return (

Previzualizare indisponibilă (fișierul nu conține date inline).

); return (

{att.name}

{/* eslint-disable-next-line @next/next/no-img-element */} {att.name}
); })()}
)}
)} {/* ── Legal deadlines ── */} {(entry.trackedDeadlines ?? []).length > 0 && (
{entry.trackedDeadlines!.map((dl) => (
{dl.typeId} {DEADLINE_RES_LABELS[dl.resolution] ?? dl.resolution}
Start: {formatDate(dl.startDate)} Scadent: {formatDate(dl.dueDate)}
{dl.resolutionNote && (

{dl.resolutionNote}

)}
))}
)} {/* ── External tracking ── */} {(entry.externalStatusUrl || entry.externalTrackingId) && (
{entry.externalTrackingId && ( )} {entry.externalStatusUrl && ( )}
)} {/* ── Tags ── */} {entry.tags.length > 0 && (
{entry.tags.map((tag) => ( {tag} ))}
)} {/* ── Notes ── */} {entry.notes && (

{entry.notes}

)}
); } // ── Sub-components ── function DetailSection({ title, children, }: { title: string; children: React.ReactNode; }) { return (

{title}

{children}
); } function DetailField({ label, value, className, extra, icon, }: { label: string; value: string; className?: string; extra?: string; icon?: React.ReactNode; }) { return (

{label}

{icon && {icon}} {value} {extra && ( {extra} )}

); }