"use client"; import { useState, useMemo, useRef, useCallback } from "react"; import { Paperclip, X, Clock, Plus, UserPlus, Info, GitBranch, Loader2, AlertTriangle, Calendar, Globe, ArrowDownToLine, ArrowUpFromLine, HardDrive, FolderOpen, Link2, } from "lucide-react"; import type { CompanyId } from "@/core/auth/types"; import { extractTemplates, assembleSubject, filterTemplates, filterSubjects, getRecommendedTemplates, getSubjectPlaceholder, createDynamicTemplate, } from "../services/subject-template-service"; import type { SubjectTemplate } from "../services/subject-template-service"; import { SubjectTemplateInput } from "./subject-template-input"; import { SubjectAutocompleteDropdown } from "./subject-autocomplete-dropdown"; import type { RegistryEntry, RegistryDirection, DocumentType, RegistryAttachment, TrackedDeadline, DeadlineResolution, ACValidityTracking, } from "../types"; import { DEFAULT_DOC_TYPE_LABELS } from "../types"; import { isNetworkPath, toUncPath, pathFileName, shortDisplayPath, shareLabelFor, } from "@/config/nas-paths"; import { Input } from "@/shared/components/ui/input"; import { Label } from "@/shared/components/ui/label"; import { Textarea } from "@/shared/components/ui/textarea"; import { Button } from "@/shared/components/ui/button"; import { Badge } from "@/shared/components/ui/badge"; import { Switch } from "@/shared/components/ui/switch"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/shared/components/ui/select"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@/shared/components/ui/tooltip"; import { useContacts } from "@/modules/address-book/hooks/use-contacts"; import { useTags } from "@/core/tagging"; import type { AddressContact } from "@/modules/address-book/types"; import { v4 as uuid } from "uuid"; import { DeadlineCard } from "./deadline-card"; import { DeadlineAddDialog } from "./deadline-add-dialog"; import { DeadlineResolveDialog } from "./deadline-resolve-dialog"; import { QuickContactDialog } from "./quick-contact-dialog"; import { ThreadView } from "./thread-view"; import { ClosureBanner } from "./closure-banner"; import { ACValidityTracker } from "./ac-validity-tracker"; import { cn } from "@/shared/lib/utils"; import { createTrackedDeadline, resolveDeadline as resolveDeadlineFn, } from "../services/deadline-service"; import { getDeadlineType } from "../services/deadline-catalog"; interface RegistryEntryFormProps { initial?: RegistryEntry; /** Pre-fill as reply to this entry — sets threadParentId, flips direction (used by "Inchide") */ replyTo?: RegistryEntry; /** Pre-fill as related/conex entry — adds to linkedEntryIds, keeps direction (used by "Conex") */ conexTo?: RegistryEntry; allEntries?: RegistryEntry[]; onSubmit: ( data: Omit, ) => void | Promise; onCancel: () => void; /** Callback to create a new Address Book contact */ onCreateContact?: (data: { name: string; phone: string; email: string; }) => Promise; /** Callback to create a new document type tag in Tag Manager */ onCreateDocType?: (label: string) => Promise; /** Navigate to an entry (for thread clicks) */ onNavigateEntry?: (entry: RegistryEntry) => void; } export function RegistryEntryForm({ initial, replyTo, conexTo, allEntries, onSubmit, onCancel, onCreateContact, onCreateDocType, onNavigateEntry, }: RegistryEntryFormProps) { const { allContacts, refresh: refreshContacts } = useContacts(); const { tags: docTypeTags } = useTags("document-type"); const { tags: projectTags } = useTags("project"); const fileInputRef = useRef(null); // Track locally-added custom types that may not yet be in Tag Manager const [localCustomTypes, setLocalCustomTypes] = useState>( new Map(), ); // ── Build dynamic doc type list from defaults + Tag Manager + local ── const allDocTypes = useMemo(() => { const map = new Map(); // Add defaults for (const [key, label] of Object.entries(DEFAULT_DOC_TYPE_LABELS)) { map.set(key, label); } // Add from Tag Manager (document-type category) for (const tag of docTypeTags) { const key = tag.label.toLowerCase().replace(/\s+/g, "-"); if (!map.has(key)) { map.set(key, tag.label); } } // Add locally-created types (before Tag Manager syncs) for (const [key, label] of localCustomTypes) { if (!map.has(key)) { map.set(key, label); } } // Preserve initial doc type even if not in defaults or Tag Manager // (e.g., custom type whose tag was deleted, or tag not yet loaded) if (initial?.documentType && !map.has(initial.documentType)) { const fallbackLabel = initial.documentType.charAt(0).toUpperCase() + initial.documentType.slice(1).replace(/-/g, " "); map.set(initial.documentType, fallbackLabel); } // Sort alphabetically by label const sorted = new Map( [...map.entries()].sort((a, b) => a[1].localeCompare(b[1], "ro")), ); return sorted; }, [docTypeTags, localCustomTypes, initial?.documentType]); // When replyTo is provided, flip direction (intrat→iesit, iesit→intrat) const replyDirection: RegistryDirection | undefined = replyTo ? replyTo.direction === "intrat" ? "iesit" : "intrat" : undefined; const [direction, setDirection] = useState( initial?.direction ?? replyDirection ?? "intrat", ); const defaultDocType = initial?.documentType ?? (direction === "intrat" ? "aviz" : "cerere"); const [documentType, setDocumentType] = useState(defaultDocType); const [customDocType, setCustomDocType] = useState(""); const [subject, setSubject] = useState(initial?.subject ?? ""); const [subjectQuery, setSubjectQuery] = useState(initial?.subject ?? ""); const [subjectFocused, setSubjectFocused] = useState(false); const [activeTemplate, setActiveTemplate] = useState(null); const [templateFieldValues, setTemplateFieldValues] = useState>({}); const [date, setDate] = useState( initial?.date ?? new Date().toISOString().slice(0, 10), ); const [sender, setSender] = useState(initial?.sender ?? ""); const [senderContactId, setSenderContactId] = useState( initial?.senderContactId ?? "", ); const [recipient, setRecipient] = useState(initial?.recipient ?? ""); const [recipientContactId, setRecipientContactId] = useState( initial?.recipientContactId ?? "", ); const [company, setCompany] = useState( initial?.company ?? "beletage", ); const [isClosed, setIsClosed] = useState(initial?.status === "inchis"); const [deadline, setDeadline] = useState(initial?.deadline ?? ""); const [assignee, setAssignee] = useState(initial?.assignee ?? ""); const [assigneeContactId, setAssigneeContactId] = useState( initial?.assigneeContactId ?? "", ); const [threadParentId, setThreadParentId] = useState( initial?.threadParentId ?? replyTo?.id ?? "", ); const [notes, setNotes] = useState(initial?.notes ?? ""); const [linkedEntryIds, setLinkedEntryIds] = useState( initial?.linkedEntryIds ?? (conexTo ? [conexTo.id] : []), ); const [attachments, setAttachments] = useState( initial?.attachments ?? [], ); const [trackedDeadlines, setTrackedDeadlines] = useState( initial?.trackedDeadlines ?? [], ); const [linkedSearch, setLinkedSearch] = useState(""); const [threadSearch, setThreadSearch] = useState(""); // ── 3.03 new fields ── const [recipientRegNumber, setRecipientRegNumber] = useState( initial?.recipientRegNumber ?? "", ); const [recipientRegDate, setRecipientRegDate] = useState( initial?.recipientRegDate ?? "", ); const [expiryDate, setExpiryDate] = useState(initial?.expiryDate ?? ""); const [expiryAlertDays, setExpiryAlertDays] = useState( initial?.expiryAlertDays ?? 30, ); const [externalStatusUrl, setExternalStatusUrl] = useState( initial?.externalStatusUrl ?? "", ); const [externalTrackingId, setExternalTrackingId] = useState( initial?.externalTrackingId ?? "", ); const [acValidity, setAcValidity] = useState( initial?.acValidity, ); // ── Submission lock + file upload tracking ── const [isSubmitting, setIsSubmitting] = useState(false); const [uploadingCount, setUploadingCount] = useState(0); const isUploading = uploadingCount > 0; // ── Deadline dialogs ── const [deadlineAddOpen, setDeadlineAddOpen] = useState(false); const [resolvingDeadline, setResolvingDeadline] = useState(null); // ── Quick contact creation ── const [quickContactOpen, setQuickContactOpen] = useState(false); const [quickContactField, setQuickContactField] = useState< "sender" | "recipient" | "assignee" >("sender"); const [quickContactName, setQuickContactName] = useState(""); const handleAddDeadline = ( typeId: string, startDate: string, options?: { isCJ?: boolean; isComisie?: boolean; chainParentId?: string }, ) => { const tracked = createTrackedDeadline( typeId, startDate, options?.chainParentId, ); if (tracked) { const newDeadlines = [tracked]; // Auto-create verification deadline for CU emitere types const isCUEmitere = typeId === "cu-emitere-l50" || typeId === "cu-emitere-l350"; if (isCUEmitere) { const verification = createTrackedDeadline( "cu-verificare", startDate, ); if (verification) newDeadlines.push(verification); } // Auto-create CJ sub-deadlines if CJ toggle is on if (isCUEmitere && options?.isCJ) { const cjRequest = createTrackedDeadline( "cu-cj-solicitare-aviz", startDate, ); if (cjRequest) { newDeadlines.push(cjRequest); // Chain: primar responds 5 days from when arhitect-sef requests (3 days from start) const requestDue = new Date(startDate); requestDue.setDate(requestDue.getDate() + 3); const y = requestDue.getFullYear(); const m = String(requestDue.getMonth() + 1).padStart(2, "0"); const d = String(requestDue.getDate()).padStart(2, "0"); const cjResponse = createTrackedDeadline( "cu-cj-aviz-primar", `${y}-${m}-${d}`, cjRequest.id, ); if (cjResponse) newDeadlines.push(cjResponse); } } // Auto-create verification deadline for AC emitere types const isACEmitere = typeId === "ac-emitere" || typeId === "ac-emitere-urgenta" || typeId === "ac-emitere-anexe"; if (isACEmitere) { const acVerification = createTrackedDeadline( "ac-verificare", startDate, ); if (acVerification) newDeadlines.push(acVerification); } // Auto-create completari limit for avize (when Comisie toggle is OFF) const addedDef = getDeadlineType(typeId); if (addedDef?.category === "avize" && !options?.isComisie) { const completariLimit = createTrackedDeadline( "aviz-completari-limit", startDate, ); if (completariLimit) newDeadlines.push(completariLimit); } // Auto-create Cultura Phase 1 (depunere la comisie) when adding cultura-comisie if (typeId === "aviz-cultura-comisie") { const culturaPhase1 = createTrackedDeadline( "aviz-cultura-depunere-comisie", startDate, ); if (culturaPhase1) newDeadlines.push(culturaPhase1); } // Auto-create comunicare catre beneficiar for all iesit deadlines // (legal obligation: institution must communicate on the day of issuance) if (direction === "iesit") { const comunicare = createTrackedDeadline( "comunicare-aviz-beneficiar", startDate, ); if (comunicare) newDeadlines.push(comunicare); } setTrackedDeadlines((prev) => [...prev, ...newDeadlines]); } }; const handleResolveDeadline = ( resolution: DeadlineResolution, note: string, chainNext: boolean, ) => { if (!resolvingDeadline) return; const resolved = resolveDeadlineFn(resolvingDeadline, resolution, note); setTrackedDeadlines((prev) => prev.map((d) => (d.id === resolved.id ? resolved : d)), ); // Standard chain (completed / aprobat-tacit) if (chainNext && resolution !== "intrerupt") { const def = getDeadlineType(resolvingDeadline.typeId); if (def?.chainNextTypeId) { const resolvedDate = new Date().toISOString().slice(0, 10); const chained = createTrackedDeadline( def.chainNextTypeId, resolvedDate, resolvingDeadline.id, ); if (chained) setTrackedDeadlines((prev) => [...prev, chained]); } } // Interruption chain — institution requested completions, term interrupted // Creates chained deadline with today as placeholder start date // User must update start date when completions are actually submitted if (resolution === "intrerupt") { const def = getDeadlineType(resolvingDeadline.typeId); if (def?.chainNextTypeId) { const today = new Date().toISOString().slice(0, 10); const chained = createTrackedDeadline( def.chainNextTypeId, today, resolvingDeadline.id, ); if (chained) { chained.auditLog = [ ...(chained.auditLog ?? []), { action: "modified", timestamp: new Date().toISOString(), detail: "ATENTIE: Actualizati data start cand se depun completarile/clarificarile", }, ]; setTrackedDeadlines((prev) => [...prev, chained]); } } } setResolvingDeadline(null); }; const handleRemoveDeadline = (deadlineId: string) => { setTrackedDeadlines((prev) => prev.filter((d) => d.id !== deadlineId)); }; // ── Contact autocomplete ── const [senderFocused, setSenderFocused] = useState(false); const [recipientFocused, setRecipientFocused] = useState(false); const [assigneeFocused, setAssigneeFocused] = useState(false); const filterContacts = useCallback( (query: string) => { if (!query || query.length < 2) return []; const q = query.toLowerCase(); return allContacts .filter( (c) => c.name.toLowerCase().includes(q) || c.company.toLowerCase().includes(q), ) .slice(0, 5); }, [allContacts], ); const senderSuggestions = useMemo( () => filterContacts(sender), [filterContacts, sender], ); const recipientSuggestions = useMemo( () => filterContacts(recipient), [filterContacts, recipient], ); const assigneeSuggestions = useMemo( () => filterContacts(assignee), [filterContacts, assignee], ); // ── Subject autocomplete ── const allSubjects = useMemo(() => { if (!allEntries) return []; const unique = new Set(); for (const e of allEntries) { if (e.subject && !e.isReserved) unique.add(e.subject); } return Array.from(unique); }, [allEntries]); const allTemplates = useMemo( () => extractTemplates(allSubjects), [allSubjects], ); const matchingTemplates = useMemo( () => subjectQuery.length >= 2 ? filterTemplates(allTemplates, subjectQuery).slice(0, 5) : [], [allTemplates, subjectQuery], ); const matchingSuggestions = useMemo( () => subjectQuery.length >= 2 ? filterSubjects(allSubjects, subjectQuery, 5) : [], [allSubjects, subjectQuery], ); // Recommended templates for current doc type (seeds + DB-learned) const recommendedTemplates = useMemo( () => getRecommendedTemplates(documentType, allTemplates), [documentType, allTemplates], ); // Recent subjects from DB (last 5 unique, sorted by newest first) const recentSubjects = useMemo(() => { if (!allEntries || allEntries.length === 0) return []; const sorted = [...allEntries] .filter((e) => e.subject && !e.isReserved) .sort((a, b) => b.createdAt.localeCompare(a.createdAt)); const seen = new Set(); const result: string[] = []; for (const e of sorted) { if (result.length >= 5) break; const lower = e.subject.toLowerCase(); if (!seen.has(lower)) { seen.add(lower); result.push(e.subject); } } return result; }, [allEntries]); // Dynamic placeholder based on document type + direction const subjectPlaceholder = useMemo( () => getSubjectPlaceholder(documentType, direction), [documentType, direction], ); // ── Quick contact creation handler ── const openQuickContact = ( field: "sender" | "recipient" | "assignee", name: string, ) => { setQuickContactField(field); setQuickContactName(name); setQuickContactOpen(true); }; const handleQuickContactConfirm = async (data: { name: string; phone: string; email: string; }) => { if (!onCreateContact) return; const contact = await onCreateContact(data); if (contact) { const displayName = contact.company ? `${contact.name} (${contact.company})` : contact.name; if (quickContactField === "sender") { setSender(displayName); setSenderContactId(contact.id); } else if (quickContactField === "recipient") { setRecipient(displayName); setRecipientContactId(contact.id); } else { setAssignee(displayName); setAssigneeContactId(contact.id); } await refreshContacts(); } setQuickContactOpen(false); }; // ── Custom doc type creation — adds to local state immediately + Tag Manager ── const handleAddCustomDocType = async () => { const label = customDocType.trim(); if (!label) return; const key = label.toLowerCase().replace(/\s+/g, "-"); // Add to local types immediately so it appears in the select setLocalCustomTypes((prev) => new Map(prev).set(key, label)); // Select the newly created type setDocumentType(key); setCustomDocType(""); if (onCreateDocType) { await onCreateDocType(label); } }; const handleFileUpload = (e: React.ChangeEvent) => { const files = e.target.files; if (!files) return; const fileArr = Array.from(files); setUploadingCount((prev) => prev + fileArr.length); for (const file of fileArr) { const reader = new FileReader(); reader.onload = () => { const base64 = reader.result as string; setAttachments((prev) => [ ...prev, { id: uuid(), name: file.name, data: base64, type: file.type, size: file.size, addedAt: new Date().toISOString(), }, ]); setUploadingCount((prev) => Math.max(0, prev - 1)); }; reader.onerror = () => { setUploadingCount((prev) => Math.max(0, prev - 1)); }; reader.readAsDataURL(file); } if (fileInputRef.current) fileInputRef.current.value = ""; }; const removeAttachment = (id: string) => { setAttachments((prev) => prev.filter((a) => a.id !== id)); }; // Network path support const [networkPathInput, setNetworkPathInput] = useState(""); const [showNetworkInput, setShowNetworkInput] = useState(false); const handleAddNetworkPath = () => { const raw = networkPathInput.trim(); if (!raw) return; const unc = toUncPath(raw); const fileName = pathFileName(raw); setAttachments((prev) => [ ...prev, { id: uuid(), name: fileName, data: "__network__", type: "network/path", size: 0, addedAt: new Date().toISOString(), networkPath: unc, }, ]); setNetworkPathInput(""); setShowNetworkInput(false); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (isSubmitting || isUploading) return; setIsSubmitting(true); try { await onSubmit({ direction, documentType, subject, date, sender, senderContactId: senderContactId || undefined, recipient, recipientContactId: recipientContactId || undefined, company, status: isClosed ? "inchis" : "deschis", deadline: deadline || undefined, assignee: assignee || undefined, assigneeContactId: assigneeContactId || undefined, threadParentId: threadParentId || "", recipientRegNumber: recipientRegNumber || undefined, recipientRegDate: recipientRegDate || undefined, expiryDate: expiryDate || undefined, expiryAlertDays: expiryDate ? expiryAlertDays : undefined, externalStatusUrl: externalStatusUrl || undefined, externalTrackingId: externalTrackingId || undefined, acValidity: acValidity, linkedEntryIds, attachments, trackedDeadlines: trackedDeadlines.length > 0 ? trackedDeadlines : undefined, notes, tags: initial?.tags ?? [], visibility: initial?.visibility ?? "all", }); } finally { setIsSubmitting(false); } }; // ── Contact autocomplete dropdown renderer ── const renderContactDropdown = ( suggestions: AddressContact[], focused: boolean, fieldName: "sender" | "recipient" | "assignee", currentValue: string, onSelect: (c: AddressContact) => void, ) => { if (!focused) return null; const hasExactMatch = suggestions.some( (c) => c.name.toLowerCase() === currentValue.toLowerCase() || `${c.name} (${c.company})`.toLowerCase() === currentValue.toLowerCase(), ); const showCreateButton = currentValue.length >= 2 && !hasExactMatch && onCreateContact; if (suggestions.length === 0 && !showCreateButton) return null; return (
{suggestions.map((c) => ( ))} {showCreateButton && ( )}
); }; // Thread parent entry for display const threadParent = threadParentId && allEntries ? allEntries.find((e) => e.id === threadParentId) : null; return (
{/* Closure info banner (if editing a closed entry) */} {initial?.closureInfo && ( )} {/* Thread view (if editing an entry that's in a thread) */} {initial && allEntries && (initial.threadParentId || allEntries.some((e) => e.threadParentId === initial.id)) && ( )} {/* Row 1: Direction + Document type + Date */}
{/* Add custom type inline */}
setCustomDocType(e.target.value)} placeholder="Tip nou..." className="text-xs h-7" onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); handleAddCustomDocType(); } }} />
setDate(e.target.value)} className="mt-1" /> {!initial && date !== new Date().toISOString().slice(0, 10) && (

Data diferă de azi — înregistrarea retroactivă va primi următorul nr. secvențial.

)} {/* Late receipt indicator for incoming admin acts */} {direction === "intrat" && documentType === "aviz" && date && (() => { const docDate = new Date(date); const today = new Date(); docDate.setHours(0, 0, 0, 0); today.setHours(0, 0, 0, 0); const diffDays = Math.floor( (today.getTime() - docDate.getTime()) / (1000 * 60 * 60 * 24), ); if (diffDays > 0) { return (

Actul are data emiterii cu {diffDays}{" "} {diffDays === 1 ? "zi" : "zile"} in urma — primit cu intarziere fata de obligatia de comunicare in ziua emiterii (L350 art. 44).

); } return null; })()}
{/* Subject with autocomplete + template mode */}
{activeTemplate ? ( { const next = { ...templateFieldValues, [fieldId]: value }; setTemplateFieldValues(next); setSubject(assembleSubject(activeTemplate, next)); }} onClear={() => { setActiveTemplate(null); setSubjectQuery(subject); }} projectTags={projectTags} /> ) : ( { const val = e.target.value; setSubjectQuery(val); setSubject(val); // Auto-detect {proiect}, {nr}, {an}, {detalii}, {text} placeholders // and switch to template mode when a closing } is typed if (val.includes("{") && val.includes("}")) { const dynTemplate = createDynamicTemplate(val); if (dynTemplate) { // Pre-fill default values (e.g. current year for {an}) const prefill: Record = {}; for (const field of dynTemplate.fields) { if (field.defaultValue) { prefill[field.id] = field.defaultValue; } } setActiveTemplate(dynTemplate); setTemplateFieldValues(prefill); setSubject(assembleSubject(dynTemplate, prefill)); setSubjectFocused(false); return; } } }} onFocus={() => setSubjectFocused(true)} onBlur={() => setTimeout(() => setSubjectFocused(false), 200)} className="mt-1" required placeholder={subjectPlaceholder} /> )} { // Pre-fill year fields with current year const prefill: Record = {}; for (const field of t.fields) { if (field.defaultValue) { prefill[field.id] = field.defaultValue; } } setActiveTemplate(t); setTemplateFieldValues(prefill); setSubject(assembleSubject(t, prefill)); setSubjectFocused(false); }} onSelectSuggestion={(s) => { setSubject(s); setSubjectQuery(s); setSubjectFocused(false); }} />
{/* Sender / Recipient with autocomplete + quick create */}
{/* Sender */}
{ setSender(e.target.value); setSenderContactId(""); }} onFocus={() => setSenderFocused(true)} onBlur={() => setTimeout(() => setSenderFocused(false), 200)} className="mt-1" placeholder="Nume sau companie..." /> {renderContactDropdown( senderSuggestions, senderFocused, "sender", sender, (c) => { setSender(c.company ? `${c.name} (${c.company})` : c.name); setSenderContactId(c.id); setSenderFocused(false); }, )}
{/* Recipient */}
{ setRecipient(e.target.value); setRecipientContactId(""); }} onFocus={() => setRecipientFocused(true)} onBlur={() => setTimeout(() => setRecipientFocused(false), 200)} className="mt-1" placeholder="Nume sau companie..." /> {renderContactDropdown( recipientSuggestions, recipientFocused, "recipient", recipient, (c) => { setRecipient(c.company ? `${c.name} (${c.company})` : c.name); setRecipientContactId(c.id); setRecipientFocused(false); }, )}
{/* Recipient registration fields — only for outgoing (iesit) documents */} {direction === "iesit" && (

Termenul legal pentru ieșiri curge DOAR de la data înregistrării la destinatar, nu de la data trimiterii. Completează aceste câmpuri când primești confirmarea.

setRecipientRegNumber(e.target.value)} className="mt-1" placeholder="Ex: 12345/2026" />
setRecipientRegDate(e.target.value)} className="mt-1" />
{!recipientRegNumber && !recipientRegDate && (

Atenție: Datele de la destinatar nu sunt completate. Termenele legale atașate nu vor porni până la completarea lor.

)}
)} {/* Assignee (Responsabil) — kept below */}
{ setAssignee(e.target.value); setAssigneeContactId(""); }} onFocus={() => setAssigneeFocused(true)} onBlur={() => setTimeout(() => setAssigneeFocused(false), 200)} className="mt-1" placeholder="Persoana responsabilă..." /> {renderContactDropdown( assigneeSuggestions, assigneeFocused, "assignee", assignee, (c) => { setAssignee(c.company ? `${c.name} (${c.company})` : c.name); setAssigneeContactId(c.id); setAssigneeFocused(false); }, )}
{/* Company + Closed switch + Deadline */}
{isClosed ? "Închis" : "Deschis"}
setDeadline(e.target.value)} className="mt-1" />
{/* Document Expiry — CU/AC validity tracking (only for act administrativ) */} {documentType === "aviz" && ( <>
setExpiryDate(e.target.value)} className="mt-1" />
{expiryDate && (
setExpiryAlertDays(parseInt(e.target.value, 10) || 30) } className="mt-1" min={1} max={365} />
)}
{expiryDate && (() => { const expiry = new Date(expiryDate); const now = new Date(); now.setHours(0, 0, 0, 0); expiry.setHours(0, 0, 0, 0); const daysLeft = Math.ceil( (expiry.getTime() - now.getTime()) / (1000 * 60 * 60 * 24), ); if (daysLeft < 0) { return (

Document expirat de {Math.abs(daysLeft)} zile!

); } if (daysLeft <= expiryAlertDays) { return (

Expiră în {daysLeft} zile — inițiați procedurile de prelungire.

); } return null; })()}
{/* AC Validity Tracker */} )} {/* Web scraping prep — external tracking */}
setExternalStatusUrl(e.target.value)} className="mt-1 text-xs" placeholder="https://portal.primaria.ro/..." />
setExternalTrackingId(e.target.value)} className="mt-1 text-xs" placeholder="Ex: REF-2026-001" />
{/* Thread parent — reply to another entry */} {allEntries && allEntries.length > 0 && (
{threadParentId && (
{threadParent ? ( <> {threadParent.direction === "intrat" ? "\u2193" : "\u2191"} {threadParent.number} {threadParent.subject} ) : ( Legat de o inregistrare (ID: {threadParentId.slice(0, 8)}...) )}
)} {!threadParentId && ( <> setThreadSearch(e.target.value)} /> {threadSearch.trim().length >= 2 && (
{allEntries .filter((e) => { if (e.id === initial?.id) return false; const q = threadSearch.toLowerCase(); return ( e.number.toLowerCase().includes(q) || e.subject.toLowerCase().includes(q) ); }) .slice(0, 8) .map((e) => ( ))}
)} )}
)} {/* Linked entries */} {allEntries && allEntries.length > 0 && (
setLinkedSearch(e.target.value)} />
{allEntries .filter((e) => { if (e.id === initial?.id) return false; if (!linkedSearch.trim()) return true; const q = linkedSearch.toLowerCase(); return ( e.number.toLowerCase().includes(q) || e.subject.toLowerCase().includes(q) || (e.sender ?? "").toLowerCase().includes(q) ); }) .map((e) => ( ))}
)} {/* Tracked Deadlines */}
{trackedDeadlines.length > 0 && (
{trackedDeadlines.map((dl) => ( ))}
)} {trackedDeadlines.length === 0 && (

Niciun termen legal. Apăsați "Adaugă termen" pentru a urmări un termen.

)}
{ if (!open) setResolvingDeadline(null); }} onResolve={handleResolveDeadline} /> {/* Attachments */}
{/* Network path input */} {showNetworkInput && (
setNetworkPathInput(e.target.value)} placeholder="P:\\095 - 2020 - Duplex\\99_DOC\\CU 1348-2024.pdf" className="flex-1 font-mono text-xs" onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); handleAddNetworkPath(); } }} />
{networkPathInput.trim() && isNetworkPath(networkPathInput) && (

→ {shortDisplayPath(networkPathInput)}

)} {networkPathInput.trim() && !isNetworkPath(networkPathInput) && (

Calea nu pare a fi pe NAS. Introdu o cale de tip A:\ O:\ P:\ T:\ sau \\newamun\\...

)}
)} {attachments.length > 0 && (
{attachments.map((att) => att.networkPath ? ( // Network path attachment — distinct visual
{shareLabelFor(att.networkPath) ?? "NAS"}
) : ( // Normal uploaded file attachment
{att.name} {(att.size / 1024).toFixed(0)} KB
), )}
)}
{/* Notes */}