'use client'; import { useState, useMemo, useRef } from 'react'; import { Paperclip, X, Clock, Plus } from 'lucide-react'; import type { CompanyId } from '@/core/auth/types'; import type { RegistryEntry, RegistryDirection, RegistryStatus, DocumentType, RegistryAttachment, TrackedDeadline, DeadlineResolution } from '../types'; 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 { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/shared/components/ui/select'; import { useContacts } from '@/modules/address-book/hooks/use-contacts'; import { v4 as uuid } from 'uuid'; import { DeadlineCard } from './deadline-card'; import { DeadlineAddDialog } from './deadline-add-dialog'; import { DeadlineResolveDialog } from './deadline-resolve-dialog'; import { createTrackedDeadline, resolveDeadline as resolveDeadlineFn } from '../services/deadline-service'; import { getDeadlineType } from '../services/deadline-catalog'; interface RegistryEntryFormProps { initial?: RegistryEntry; allEntries?: RegistryEntry[]; onSubmit: (data: Omit) => void; onCancel: () => void; } const DOC_TYPE_LABELS: Record = { contract: 'Contract', oferta: 'Ofertă', factura: 'Factură', scrisoare: 'Scrisoare', aviz: 'Aviz', 'nota-de-comanda': 'Notă de comandă', raport: 'Raport', cerere: 'Cerere', altele: 'Altele', }; export function RegistryEntryForm({ initial, allEntries, onSubmit, onCancel }: RegistryEntryFormProps) { const { allContacts } = useContacts(); const fileInputRef = useRef(null); const [direction, setDirection] = useState(initial?.direction ?? 'intrat'); const [documentType, setDocumentType] = useState(initial?.documentType ?? 'scrisoare'); const [subject, setSubject] = useState(initial?.subject ?? ''); 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 [status, setStatus] = useState(initial?.status ?? 'deschis'); const [deadline, setDeadline] = useState(initial?.deadline ?? ''); const [notes, setNotes] = useState(initial?.notes ?? ''); const [linkedEntryIds, setLinkedEntryIds] = useState(initial?.linkedEntryIds ?? []); const [attachments, setAttachments] = useState(initial?.attachments ?? []); const [trackedDeadlines, setTrackedDeadlines] = useState(initial?.trackedDeadlines ?? []); // ── Deadline dialogs ── const [deadlineAddOpen, setDeadlineAddOpen] = useState(false); const [resolvingDeadline, setResolvingDeadline] = useState(null); const handleAddDeadline = (typeId: string, startDate: string, chainParentId?: string) => { const tracked = createTrackedDeadline(typeId, startDate, chainParentId); if (tracked) setTrackedDeadlines((prev) => [...prev, tracked]); }; 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)) ); // Handle chain if (chainNext) { 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]); } } setResolvingDeadline(null); }; const handleRemoveDeadline = (deadlineId: string) => { setTrackedDeadlines((prev) => prev.filter((d) => d.id !== deadlineId)); }; // ── Sender/Recipient autocomplete suggestions ── const [senderFocused, setSenderFocused] = useState(false); const [recipientFocused, setRecipientFocused] = useState(false); const senderSuggestions = useMemo(() => { if (!sender || sender.length < 2) return []; const q = sender.toLowerCase(); return allContacts.filter((c) => c.name.toLowerCase().includes(q) || c.company.toLowerCase().includes(q)).slice(0, 5); }, [allContacts, sender]); const recipientSuggestions = useMemo(() => { if (!recipient || recipient.length < 2) return []; const q = recipient.toLowerCase(); return allContacts.filter((c) => c.name.toLowerCase().includes(q) || c.company.toLowerCase().includes(q)).slice(0, 5); }, [allContacts, recipient]); const handleFileUpload = (e: React.ChangeEvent) => { const files = e.target.files; if (!files) return; for (const file of Array.from(files)) { 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(), }, ]); }; reader.readAsDataURL(file); } if (fileInputRef.current) fileInputRef.current.value = ''; }; const removeAttachment = (id: string) => { setAttachments((prev) => prev.filter((a) => a.id !== id)); }; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); onSubmit({ direction, documentType, subject, date, sender, senderContactId: senderContactId || undefined, recipient, recipientContactId: recipientContactId || undefined, company, status, deadline: deadline || undefined, linkedEntryIds, attachments, trackedDeadlines: trackedDeadlines.length > 0 ? trackedDeadlines : undefined, notes, tags: initial?.tags ?? [], visibility: initial?.visibility ?? 'all', }); }; return (
{/* Row 1: Direction + Document type + Date */}
setDate(e.target.value)} className="mt-1" />
{/* Subject */}
setSubject(e.target.value)} className="mt-1" required />
{/* Sender / Recipient with autocomplete */}
{ setSender(e.target.value); setSenderContactId(''); }} onFocus={() => setSenderFocused(true)} onBlur={() => setTimeout(() => setSenderFocused(false), 200)} className="mt-1" placeholder="Nume sau companie..." /> {senderFocused && senderSuggestions.length > 0 && (
{senderSuggestions.map((c) => ( ))}
)}
{ setRecipient(e.target.value); setRecipientContactId(''); }} onFocus={() => setRecipientFocused(true)} onBlur={() => setTimeout(() => setRecipientFocused(false), 200)} className="mt-1" placeholder="Nume sau companie..." /> {recipientFocused && recipientSuggestions.length > 0 && (
{recipientSuggestions.map((c) => ( ))}
)}
{/* Company + Status + Deadline */}
setDeadline(e.target.value)} className="mt-1" />
{/* Linked entries */} {allEntries && allEntries.length > 0 && (
{allEntries .filter((e) => e.id !== initial?.id) .slice(0, 20) .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 */}
{attachments.length > 0 && (
{attachments.map((att) => (
{att.name} {(att.size / 1024).toFixed(0)} KB
))}
)}
{/* Notes */}