feat(registratura): 3.02 bidirectional integration, simplified status, threads

- Dynamic document types: string-based DocumentType synced with Tag Manager
  (new types auto-create tags under 'document-type' category)
- Added default types: 'Apel telefonic', 'Videoconferinta'
- Bidirectional Address Book: quick-create contacts from sender/recipient/
  assignee fields via QuickContactDialog popup
- Simplified status: Switch toggle replaces dropdown (default open)
- Responsabil (Assignee) field with contact autocomplete (ERP-ready)
- Entry threads: threadParentId links entries as replies, ThreadView shows
  parent/current/children tree with branching support
- Info tooltips on deadline, status, and assignee fields
- New Resp. column and thread icon in registry table
- All changes backward-compatible with existing data
This commit is contained in:
AI Assistant
2026-02-27 15:33:29 +02:00
parent b2618c041d
commit 2be0462e0d
10 changed files with 1199 additions and 273 deletions
@@ -0,0 +1,111 @@
"use client";
import { useState } from "react";
import { UserPlus } from "lucide-react";
import { Input } from "@/shared/components/ui/input";
import { Label } from "@/shared/components/ui/label";
import { Button } from "@/shared/components/ui/button";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogFooter,
} from "@/shared/components/ui/dialog";
interface QuickContactDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
/** Pre-filled name from the text the user typed */
initialName: string;
onConfirm: (data: { name: string; phone: string; email: string }) => void;
}
/**
* Rapid popup for creating a new Address Book contact from Registratura.
* Only requires Name; Phone and Email are optional.
*/
export function QuickContactDialog({
open,
onOpenChange,
initialName,
onConfirm,
}: QuickContactDialogProps) {
const [name, setName] = useState(initialName);
const [phone, setPhone] = useState("");
const [email, setEmail] = useState("");
// Reset when dialog opens with new name
const handleOpenChange = (o: boolean) => {
if (o) {
setName(initialName);
setPhone("");
setEmail("");
}
onOpenChange(o);
};
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (!name.trim()) return;
onConfirm({ name: name.trim(), phone: phone.trim(), email: email.trim() });
};
return (
<Dialog open={open} onOpenChange={handleOpenChange}>
<DialogContent className="sm:max-w-md">
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
<UserPlus className="h-4 w-4" />
Contact nou rapid
</DialogTitle>
</DialogHeader>
<form onSubmit={handleSubmit} className="space-y-3">
<div>
<Label>Nume *</Label>
<Input
value={name}
onChange={(e) => setName(e.target.value)}
className="mt-1"
required
autoFocus
/>
</div>
<div className="grid gap-3 sm:grid-cols-2">
<div>
<Label>Telefon</Label>
<Input
value={phone}
onChange={(e) => setPhone(e.target.value)}
className="mt-1"
placeholder="Opțional"
/>
</div>
<div>
<Label>Email</Label>
<Input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="mt-1"
placeholder="Opțional"
/>
</div>
</div>
<DialogFooter>
<Button
type="button"
variant="outline"
onClick={() => onOpenChange(false)}
>
Anulează
</Button>
<Button type="submit" disabled={!name.trim()}>
Creează contact
</Button>
</DialogFooter>
</form>
</DialogContent>
</Dialog>
);
}