"use client"; import { useState, useMemo } from "react"; import { GitBranch, Search, Calendar, Clock } from "lucide-react"; import { Badge } from "@/shared/components/ui/badge"; import { Button } from "@/shared/components/ui/button"; import { Input } from "@/shared/components/ui/input"; import type { RegistryEntry } from "../types"; import { FlowDiagram } from "./flow-diagram"; import { cn } from "@/shared/lib/utils"; interface ThreadExplorerProps { entries: RegistryEntry[]; onNavigateEntry?: (entry: RegistryEntry) => void; } /** A thread is a chain of entries linked by threadParentId */ interface Thread { id: string; root: RegistryEntry; chain: RegistryEntry[]; totalDays: number; isActive: boolean; } function daysBetween(d1: string, d2: string): number { const a = new Date(d1); const b = new Date(d2); a.setHours(0, 0, 0, 0); b.setHours(0, 0, 0, 0); return Math.max( 0, Math.round(Math.abs(b.getTime() - a.getTime()) / (1000 * 60 * 60 * 24)), ); } function formatShortDate(iso: string): string { try { return new Date(iso).toLocaleDateString("ro-RO", { day: "2-digit", month: "short", }); } catch { return iso; } } /** Build threads from all entries */ function buildThreads(entries: RegistryEntry[]): Thread[] { const byId = new Map(entries.map((e) => [e.id, e])); const childrenMap = new Map(); const rootIds = new Set(); for (const entry of entries) { if (entry.threadParentId) { const existing = childrenMap.get(entry.threadParentId) ?? []; existing.push(entry); childrenMap.set(entry.threadParentId, existing); } } for (const entry of entries) { if (!entry.threadParentId && childrenMap.has(entry.id)) { rootIds.add(entry.id); } if (entry.threadParentId) { let current = entry; while (current.threadParentId) { const parent = byId.get(current.threadParentId); if (!parent) break; current = parent; } rootIds.add(current.id); } } const threads: Thread[] = []; for (const rootId of rootIds) { const root = byId.get(rootId); if (!root) continue; const chain: RegistryEntry[] = []; const queue = [rootId]; const visited = new Set(); while (queue.length > 0) { const id = queue.shift()!; if (visited.has(id)) continue; visited.add(id); const entry = byId.get(id); if (!entry) continue; chain.push(entry); const children = childrenMap.get(id) ?? []; for (const child of children) { queue.push(child.id); } } chain.sort( (a, b) => new Date(a.date).getTime() - new Date(b.date).getTime(), ); if (chain.length < 2) continue; const firstDate = chain[0]!.date; const lastDate = chain[chain.length - 1]!.date; const totalDays = daysBetween(firstDate, lastDate); const isActive = chain.some((e) => e.status === "deschis"); threads.push({ id: rootId, root, chain, totalDays, isActive }); } threads.sort((a, b) => { if (a.isActive !== b.isActive) return a.isActive ? -1 : 1; const aLast = a.chain[a.chain.length - 1]!.date; const bLast = b.chain[b.chain.length - 1]!.date; return bLast.localeCompare(aLast); }); return threads; } export function ThreadExplorer({ entries, onNavigateEntry, }: ThreadExplorerProps) { const [search, setSearch] = useState(""); const [activeOnly, setActiveOnly] = useState(false); const threads = useMemo(() => buildThreads(entries), [entries]); const filtered = useMemo(() => { return threads.filter((t) => { if (activeOnly && !t.isActive) return false; if (search.trim()) { const q = search.toLowerCase(); return t.chain.some( (e) => e.number.toLowerCase().includes(q) || e.subject.toLowerCase().includes(q) || e.sender.toLowerCase().includes(q) || e.recipient.toLowerCase().includes(q), ); } return true; }); }, [threads, search, activeOnly]); const activeCount = threads.filter((t) => t.isActive).length; const closedCount = threads.length - activeCount; return (
{/* Summary + filters */}

{activeCount}{" "} {activeCount === 1 ? "dosar activ" : "dosare active"},{" "} {closedCount}{" "} finalizate

setSearch(e.target.value)} className="h-9 w-[200px] pl-9" />
{/* Thread list with flow diagrams */} {filtered.length === 0 ? (

{threads.length === 0 ? "Niciun dosar. Inchideti o inregistrare cu raspuns (Inchide) pentru a forma un dosar." : "Niciun dosar corespunde filtrelor."}

) : (
{filtered.map((thread) => ( ))}
)}
); } // ── Thread card with flow diagram ── function ThreadCard({ thread, allEntries, onNodeClick, }: { thread: Thread; allEntries: RegistryEntry[]; onNodeClick?: (entry: RegistryEntry) => void; }) { return (
{/* Header */}
{thread.root.subject} {thread.isActive ? "Activ" : "Finalizat"}
{formatShortDate(thread.chain[0]!.date)} —{" "} {formatShortDate(thread.chain[thread.chain.length - 1]!.date)} {thread.totalDays}z {thread.chain.length} doc.
{/* Flow diagram */}
); }