feat(registratura): rework with company-prefixed numbering, directions, deadlines, attachments

- Company-specific numbering (B-0001/2026, US-0001/2026, SDT-0001/2026)
- Direction: Intrat/Ieșit replaces old 3-way type
- 9 document types: Contract, Ofertă, Factură, Scrisoare, etc.
- Status simplified to Deschis/Închis with cascade close for linked entries
- Address Book autocomplete for sender/recipient
- Deadline tracking with overdue day counter
- File attachment support (base64 encoding)
- Linked entries system

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Marius Tarau
2026-02-18 06:35:23 +02:00
parent 84d9db4515
commit 98eda56035
8 changed files with 550 additions and 109 deletions

View File

@@ -3,13 +3,14 @@
import { useState, useEffect, useCallback } from 'react';
import { useStorage } from '@/core/storage';
import { v4 as uuid } from 'uuid';
import type { RegistryEntry, RegistryEntryType, RegistryEntryStatus } from '../types';
import type { RegistryEntry, RegistryDirection, RegistryStatus, DocumentType } from '../types';
import { getAllEntries, saveEntry, deleteEntry, generateRegistryNumber } from '../services/registry-service';
export interface RegistryFilters {
search: string;
type: RegistryEntryType | 'all';
status: RegistryEntryStatus | 'all';
direction: RegistryDirection | 'all';
status: RegistryStatus | 'all';
documentType: DocumentType | 'all';
company: string;
}
@@ -19,8 +20,9 @@ export function useRegistry() {
const [loading, setLoading] = useState(true);
const [filters, setFilters] = useState<RegistryFilters>({
search: '',
type: 'all',
direction: 'all',
status: 'all',
documentType: 'all',
company: 'all',
});
@@ -36,18 +38,18 @@ export function useRegistry() {
const addEntry = useCallback(async (data: Omit<RegistryEntry, 'id' | 'number' | 'createdAt' | 'updatedAt'>) => {
const now = new Date().toISOString();
const nextIndex = entries.length + 1;
const number = generateRegistryNumber(data.company, data.date, entries);
const entry: RegistryEntry = {
...data,
id: uuid(),
number: generateRegistryNumber(data.date, nextIndex),
number,
createdAt: now,
updatedAt: now,
};
await saveEntry(storage, entry);
await refresh();
return entry;
}, [storage, refresh, entries.length]);
}, [storage, refresh, entries]);
const updateEntry = useCallback(async (id: string, updates: Partial<RegistryEntry>) => {
const existing = entries.find((e) => e.id === id);
@@ -69,13 +71,35 @@ export function useRegistry() {
await refresh();
}, [storage, refresh]);
/** Close an entry and optionally its linked entries */
const closeEntry = useCallback(async (id: string, closeLinked: boolean) => {
const entry = entries.find((e) => e.id === id);
if (!entry) return;
await updateEntry(id, { status: 'inchis' });
if (closeLinked && entry.linkedEntryIds.length > 0) {
for (const linkedId of entry.linkedEntryIds) {
const linked = entries.find((e) => e.id === linkedId);
if (linked && linked.status !== 'inchis') {
const updatedLinked: RegistryEntry = {
...linked,
status: 'inchis',
updatedAt: new Date().toISOString(),
};
await saveEntry(storage, updatedLinked);
}
}
await refresh();
}
}, [entries, updateEntry, storage, refresh]);
const updateFilter = useCallback(<K extends keyof RegistryFilters>(key: K, value: RegistryFilters[K]) => {
setFilters((prev) => ({ ...prev, [key]: value }));
}, []);
const filteredEntries = entries.filter((entry) => {
if (filters.type !== 'all' && entry.type !== filters.type) return false;
if (filters.direction !== 'all' && entry.direction !== filters.direction) return false;
if (filters.status !== 'all' && entry.status !== filters.status) return false;
if (filters.documentType !== 'all' && entry.documentType !== filters.documentType) return false;
if (filters.company !== 'all' && entry.company !== filters.company) return false;
if (filters.search) {
const q = filters.search.toLowerCase();
@@ -83,7 +107,7 @@ export function useRegistry() {
entry.subject.toLowerCase().includes(q) ||
entry.sender.toLowerCase().includes(q) ||
entry.recipient.toLowerCase().includes(q) ||
entry.number.includes(q)
entry.number.toLowerCase().includes(q)
);
}
return true;
@@ -98,6 +122,7 @@ export function useRegistry() {
addEntry,
updateEntry,
removeEntry,
closeEntry,
refresh,
};
}