feat: quick contact dialog from registratura supports name OR company

- QuickContactDialog now has Company/Organization field
- Either name or company is required (same logic as address book)
- Auto-sets type to "institution" when only company is provided
- Display name in registry form uses company as fallback

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
AI Assistant
2026-03-13 21:10:34 +02:00
parent 9d73697fb0
commit 8e2534ebe3
3 changed files with 55 additions and 21 deletions
@@ -13,17 +13,24 @@ import {
DialogFooter, DialogFooter,
} from "@/shared/components/ui/dialog"; } from "@/shared/components/ui/dialog";
export interface QuickContactData {
name: string;
company: string;
phone: string;
email: string;
}
interface QuickContactDialogProps { interface QuickContactDialogProps {
open: boolean; open: boolean;
onOpenChange: (open: boolean) => void; onOpenChange: (open: boolean) => void;
/** Pre-filled name from the text the user typed */ /** Pre-filled name from the text the user typed */
initialName: string; initialName: string;
onConfirm: (data: { name: string; phone: string; email: string }) => void; onConfirm: (data: QuickContactData) => void;
} }
/** /**
* Rapid popup for creating a new Address Book contact from Registratura. * Rapid popup for creating a new Address Book contact from Registratura.
* Only requires Name; Phone and Email are optional. * Requires either Name or Company; Phone and Email are optional.
*/ */
export function QuickContactDialog({ export function QuickContactDialog({
open, open,
@@ -32,27 +39,34 @@ export function QuickContactDialog({
onConfirm, onConfirm,
}: QuickContactDialogProps) { }: QuickContactDialogProps) {
const [name, setName] = useState(initialName); const [name, setName] = useState(initialName);
const [company, setCompany] = useState("");
const [phone, setPhone] = useState(""); const [phone, setPhone] = useState("");
const [email, setEmail] = useState(""); const [email, setEmail] = useState("");
// Sync name with initialName whenever the dialog opens // Sync name with initialName whenever the dialog opens
// (useState(initialName) only works on first mount; controlled open
// bypasses onOpenChange so we need useEffect)
useEffect(() => { useEffect(() => {
if (open) { if (open) {
setName(initialName); setName(initialName);
setCompany("");
setPhone(""); setPhone("");
setEmail(""); setEmail("");
} }
}, [open, initialName]); }, [open, initialName]);
const hasIdentifier = name.trim() || company.trim();
const handleSubmit = (e: React.FormEvent) => { const handleSubmit = (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
// Stop propagation so the submit doesn't bubble through the React portal // Stop propagation so the submit doesn't bubble through the React portal
// to the outer registry-entry-form, which would close the whole form. // to the outer registry-entry-form, which would close the whole form.
e.stopPropagation(); e.stopPropagation();
if (!name.trim()) return; if (!hasIdentifier) return;
onConfirm({ name: name.trim(), phone: phone.trim(), email: email.trim() }); onConfirm({
name: name.trim(),
company: company.trim(),
phone: phone.trim(),
email: email.trim(),
});
}; };
return ( return (
@@ -65,15 +79,31 @@ export function QuickContactDialog({
</DialogTitle> </DialogTitle>
</DialogHeader> </DialogHeader>
<form onSubmit={handleSubmit} className="space-y-3"> <form onSubmit={handleSubmit} className="space-y-3">
<div> {!hasIdentifier && (
<Label>Nume *</Label> <p className="text-xs text-destructive">
<Input Completează cel puțin Numele sau Compania/Organizația.
value={name} </p>
onChange={(e) => setName(e.target.value)} )}
className="mt-1" <div className="grid gap-3 sm:grid-cols-2">
required <div>
autoFocus <Label>Nume {!company.trim() ? "*" : ""}</Label>
/> <Input
value={name}
onChange={(e) => setName(e.target.value)}
className="mt-1"
required={!company.trim()}
autoFocus
/>
</div>
<div>
<Label>Companie/Organizație {!name.trim() ? "*" : ""}</Label>
<Input
value={company}
onChange={(e) => setCompany(e.target.value)}
className="mt-1"
required={!name.trim()}
/>
</div>
</div> </div>
<div className="grid gap-3 sm:grid-cols-2"> <div className="grid gap-3 sm:grid-cols-2">
<div> <div>
@@ -104,7 +134,7 @@ export function QuickContactDialog({
> >
Anulează Anulează
</Button> </Button>
<Button type="submit" disabled={!name.trim()}> <Button type="submit" disabled={!hasIdentifier}>
Creează contact Creează contact
</Button> </Button>
</DialogFooter> </DialogFooter>
@@ -93,6 +93,7 @@ export function RegistraturaModule() {
const handleCreateContact = useCallback( const handleCreateContact = useCallback(
async (data: { async (data: {
name: string; name: string;
company: string;
phone: string; phone: string;
email: string; email: string;
}): Promise<AddressContact | undefined> => { }): Promise<AddressContact | undefined> => {
@@ -101,8 +102,8 @@ export function RegistraturaModule() {
const contact: AddressContact = { const contact: AddressContact = {
id: uuid(), id: uuid(),
name: data.name, name: data.name,
company: "", company: data.company,
type: "collaborator", type: data.company && !data.name ? "institution" : "collaborator",
email: data.email, email: data.email,
email2: "", email2: "",
phone: data.phone, phone: data.phone,
@@ -100,6 +100,7 @@ interface RegistryEntryFormProps {
/** Callback to create a new Address Book contact */ /** Callback to create a new Address Book contact */
onCreateContact?: (data: { onCreateContact?: (data: {
name: string; name: string;
company: string;
phone: string; phone: string;
email: string; email: string;
}) => Promise<AddressContact | undefined>; }) => Promise<AddressContact | undefined>;
@@ -513,15 +514,17 @@ export function RegistryEntryForm({
const handleQuickContactConfirm = async (data: { const handleQuickContactConfirm = async (data: {
name: string; name: string;
company: string;
phone: string; phone: string;
email: string; email: string;
}) => { }) => {
if (!onCreateContact) return; if (!onCreateContact) return;
const contact = await onCreateContact(data); const contact = await onCreateContact(data);
if (contact) { if (contact) {
const displayName = contact.company const displayName =
? `${contact.name} (${contact.company})` contact.name && contact.company
: contact.name; ? `${contact.name} (${contact.company})`
: contact.name || contact.company;
if (quickContactField === "sender") { if (quickContactField === "sender") {
setSender(displayName); setSender(displayName);
setSenderContactId(contact.id); setSenderContactId(contact.id);