"use client"; import { useState } from "react"; import { useTranslations } from "next-intl"; import { X, Plus } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import type { ContactCard } from "@/lib/jmap/types"; interface EmailEntry { address: string; context: "work" | "private" | ""; } interface PhoneEntry { number: string; context: "work" | "private" | ""; } interface ContactFormProps { contact?: ContactCard | null; onSave: (data: Partial) => Promise; onCancel: () => void; } export function ContactForm({ contact, onSave, onCancel }: ContactFormProps) { const t = useTranslations("contacts.form"); const isEditing = !!contact; const givenInit = contact?.name?.components?.find(c => c.kind === "given")?.value || ""; const surnameInit = contact?.name?.components?.find(c => c.kind === "surname")?.value || ""; const [givenName, setGivenName] = useState(givenInit); const [surname, setSurname] = useState(surnameInit); const [emails, setEmails] = useState(() => { if (contact?.emails) { return Object.values(contact.emails).map(e => ({ address: e.address, context: e.contexts?.work ? "work" : e.contexts?.private ? "private" : "", })); } return [{ address: "", context: "" }]; }); const [phones, setPhones] = useState(() => { if (contact?.phones) { return Object.values(contact.phones).map(p => ({ number: p.number, context: p.contexts?.work ? "work" : p.contexts?.private ? "private" : "", })); } return []; }); const [organization, setOrganization] = useState( contact?.organizations ? Object.values(contact.organizations)[0]?.name || "" : "" ); const [note, setNote] = useState( contact?.notes ? Object.values(contact.notes)[0]?.note || "" : "" ); const [isSaving, setIsSaving] = useState(false); const [error, setError] = useState(null); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setError(null); if (!givenName.trim() && !surname.trim()) { setError(t("name_required")); return; } const validEmails = emails.filter(e => e.address.trim()); for (const entry of validEmails) { if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(entry.address.trim())) { setError(t("email_invalid")); return; } } const emailsMap: Record }> = {}; validEmails.forEach((entry, i) => { const obj: { address: string; contexts?: Record } = { address: entry.address.trim() }; if (entry.context) { obj.contexts = { [entry.context]: true }; } emailsMap[`e${i}`] = obj; }); const validPhones = phones.filter(p => p.number.trim()); const phonesMap: Record }> = {}; validPhones.forEach((entry, i) => { const obj: { number: string; contexts?: Record } = { number: entry.number.trim() }; if (entry.context) { obj.contexts = { [entry.context]: true }; } phonesMap[`p${i}`] = obj; }); const nameComponents = []; if (givenName.trim()) { nameComponents.push({ kind: "given" as const, value: givenName.trim() }); } if (surname.trim()) { nameComponents.push({ kind: "surname" as const, value: surname.trim() }); } const data: Partial = { name: { components: nameComponents, isOrdered: true }, emails: Object.keys(emailsMap).length > 0 ? emailsMap : undefined, phones: Object.keys(phonesMap).length > 0 ? phonesMap : undefined, organizations: organization.trim() ? { o0: { name: organization.trim() } } : undefined, notes: note.trim() ? { n0: { note: note.trim() } } : undefined, }; setIsSaving(true); try { await onSave(data); } catch (err) { setError(err instanceof Error ? err.message : t("save_failed")); } finally { setIsSaving(false); } }; return (

{isEditing ? t("edit_title") : t("create_title")}

{error && (
{error}
)}
setGivenName(e.target.value)} placeholder={t("given_name")} autoFocus />
setSurname(e.target.value)} placeholder={t("surname")} />
{emails.map((entry, i) => (
{ const next = [...emails]; next[i] = { ...next[i], address: e.target.value }; setEmails(next); }} placeholder={t("email_placeholder")} className="flex-1" /> {emails.length > 1 && ( )}
))}
{phones.map((entry, i) => (
{ const next = [...phones]; next[i] = { ...next[i], number: e.target.value }; setPhones(next); }} placeholder={t("phone_placeholder")} className="flex-1" />
))}
setOrganization(e.target.value)} placeholder={t("organization_placeholder")} />