/* contacts.jsx — записная книжка: список контактов, поиск, карточка с историей. */ function ContactsScreen({ onOpenNote }) { const [items, setItems] = React.useState([]); const [loading, setLoading] = React.useState(true); const [q, setQ] = React.useState(""); const [openId, setOpenId] = React.useState(null); const load = React.useCallback(async () => { setLoading(true); setItems(await api.getContacts({ q: q || undefined })); setLoading(false); }, [q]); React.useEffect(() => { const t = setTimeout(load, 200); return () => clearTimeout(t); }, [q]); return (
setQ(e.target.value)} placeholder="Поиск по имени, телефону, ЖК…" className="w-full h-11 rounded-xl border border-[var(--border)] bg-[var(--surface)] pl-10 pr-3 text-sm text-[var(--text)] outline-none focus:border-[var(--accent)] transition placeholder:text-[var(--muted)]" />
{loading ? (
{[0, 1, 2].map((i) =>
)}
) : items.length === 0 ? ( ) : (
{items.map((c, i) => setOpenId(c.id)} />)}
)} setOpenId(null)} onChanged={load} onOpenNote={onOpenNote} />
); } function ContactRow({ c, index = 0, onOpen }) { const initials = (c.name || c.phone || "?").trim().slice(0, 1).toUpperCase(); return ( ); } function ContactModal({ contactId, open, onClose, onChanged, onOpenNote }) { const [data, setData] = React.useState(null); const [form, setForm] = React.useState({}); const [busy, setBusy] = React.useState(false); const [confirmDel, setConfirmDel] = React.useState(false); React.useEffect(() => { if (open && contactId) { setData(null); setConfirmDel(false); api.getContact(contactId).then((d) => { setData(d); setForm({ name: d.name, address: d.address, social: d.social, note: d.note, phone: d.phone }); }); } }, [open, contactId]); const set = (k, v) => setForm((f) => ({ ...f, [k]: v })); const save = async () => { setBusy(true); await api.updateContact(contactId, form); setBusy(false); onChanged && onChanged(); onClose(); }; const del = async () => { setBusy(true); await api.deleteContact(contactId); setBusy(false); onChanged && onChanged(); onClose(); }; return (

{(form.name || form.phone || "Контакт")}

{!data ? (
) : ( <>
set("name", e.target.value)} className="w-full rounded-xl border border-[var(--border)] bg-[var(--surface-2)] px-3.5 h-[42px] text-sm text-[var(--text)] outline-none focus:border-[var(--accent)] transition" />
set("phone", e.target.value)} className="mono flex-1 rounded-xl border border-[var(--border)] bg-[var(--surface-2)] px-3.5 h-[42px] text-sm text-[var(--text)] outline-none focus:border-[var(--accent)] transition" />
set("address", e.target.value)} className="w-full rounded-xl border border-[var(--border)] bg-[var(--surface-2)] px-3.5 h-[42px] text-sm text-[var(--text)] outline-none focus:border-[var(--accent)] transition" />
set("social", e.target.value)} placeholder="https://t.me/…" className="flex-1 rounded-xl border border-[var(--border)] bg-[var(--surface-2)] px-3.5 h-[42px] text-sm text-[var(--text)] outline-none focus:border-[var(--accent)] transition" /> {form.social && /^https?:\/\//i.test(form.social) && }