Replace add-contact prompt with inline row form on messages page
- inline Name + Email inputs when clicking '+ Add to contacts' - uses existing POST /api/contacts via TanStack mutation
This commit is contained in:
@ -8,6 +8,9 @@ export default function MessagesPage() {
|
|||||||
const [dateTo, setDateTo] = useState("");
|
const [dateTo, setDateTo] = useState("");
|
||||||
const [unreadOnly, setUnreadOnly] = useState(false);
|
const [unreadOnly, setUnreadOnly] = useState(false);
|
||||||
const [expanded, setExpanded] = useState<number | null>(null);
|
const [expanded, setExpanded] = useState<number | null>(null);
|
||||||
|
const [addingId, setAddingId] = useState<number | null>(null);
|
||||||
|
const [addName, setAddName] = useState("");
|
||||||
|
const [addEmail, setAddEmail] = useState("");
|
||||||
const qc = useQueryClient();
|
const qc = useQueryClient();
|
||||||
|
|
||||||
const { data, isLoading, error } = useQuery({
|
const { data, isLoading, error } = useQuery({
|
||||||
@ -23,9 +26,26 @@ export default function MessagesPage() {
|
|||||||
mutationFn: (id: number) => api.deleteMessage(id),
|
mutationFn: (id: number) => api.deleteMessage(id),
|
||||||
onSuccess: () => qc.invalidateQueries({ queryKey: ["messages"] }),
|
onSuccess: () => qc.invalidateQueries({ queryKey: ["messages"] }),
|
||||||
});
|
});
|
||||||
|
const addContact = useMutation({
|
||||||
|
mutationFn: (data: { name: string; number?: string; email?: string | null }) => api.createContact(data),
|
||||||
|
onSuccess: () => {
|
||||||
|
qc.invalidateQueries({ queryKey: ["contacts"] });
|
||||||
|
qc.invalidateQueries({ queryKey: ["messages"] });
|
||||||
|
setAddingId(null);
|
||||||
|
setAddName("");
|
||||||
|
setAddEmail("");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const onSubmit = (e: React.FormEvent) => e.preventDefault();
|
const onSubmit = (e: React.FormEvent) => e.preventDefault();
|
||||||
|
|
||||||
|
const startAdd = (m: { id: number; contact_name?: string; callerid?: string }) => {
|
||||||
|
const num = (m.callerid || "").replace(/[^\d+]/g, "");
|
||||||
|
setAddName(m.contact_name || "");
|
||||||
|
setAddEmail("");
|
||||||
|
setAddingId(m.id);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<form onSubmit={onSubmit} className="card" style={{ padding: "12px 16px" }}>
|
<form onSubmit={onSubmit} className="card" style={{ padding: "12px 16px" }}>
|
||||||
@ -48,6 +68,7 @@ export default function MessagesPage() {
|
|||||||
const whoRaw = m.contact_name || m.callerid || "Unknown caller";
|
const whoRaw = m.contact_name || m.callerid || "Unknown caller";
|
||||||
const num = (m.callerid || "").replace(/[^\d+]/g, "");
|
const num = (m.callerid || "").replace(/[^\d+]/g, "");
|
||||||
const showAdd = !m.contact_name && num;
|
const showAdd = !m.contact_name && num;
|
||||||
|
const isAdding = addingId === m.id;
|
||||||
return (
|
return (
|
||||||
<div key={m.id} className={"card" + (m.is_read ? "" : " unread")}>
|
<div key={m.id} className={"card" + (m.is_read ? "" : " unread")}>
|
||||||
<div className="who">
|
<div className="who">
|
||||||
@ -74,7 +95,7 @@ export default function MessagesPage() {
|
|||||||
) : null}
|
) : null}
|
||||||
{m.numbers?.length ? (
|
{m.numbers?.length ? (
|
||||||
<div className="meta" style={{ marginTop: 6 }}>
|
<div className="meta" style={{ marginTop: 6 }}>
|
||||||
📞 Callback:{" "}
|
📞 Callback:{" "}
|
||||||
{m.numbers.map((n: string) => {
|
{m.numbers.map((n: string) => {
|
||||||
const digits = n.replace(/[^\d+]/g, "");
|
const digits = n.replace(/[^\d+]/g, "");
|
||||||
return <a key={n} href={"tel:" + digits}>{n}</a>;
|
return <a key={n} href={"tel:" + digits}>{n}</a>;
|
||||||
@ -88,13 +109,16 @@ export default function MessagesPage() {
|
|||||||
</button>
|
</button>
|
||||||
{m.has_audio && <a className="btn" href={"/audio/" + m.id + "?dl=1"}>Download</a>}
|
{m.has_audio && <a className="btn" href={"/audio/" + m.id + "?dl=1"}>Download</a>}
|
||||||
<button className="danger" onClick={() => deleteMsg.mutate(m.id)}>Delete</button>
|
<button className="danger" onClick={() => deleteMsg.mutate(m.id)}>Delete</button>
|
||||||
{showAdd && (
|
{showAdd && !isAdding && (
|
||||||
<button className="add-btn" onClick={() => {
|
<button className="add-btn" onClick={() => startAdd(m)}>+ Add to contacts</button>
|
||||||
const name = prompt("Contact name:", whoRaw);
|
)}
|
||||||
if (name !== null) {
|
{isAdding && (
|
||||||
(window as any).api?.addContact?.({ number: num, name }).then(() => qc.invalidateQueries({ queryKey: ["messages"] }));
|
<form className="row" style={{ gap: 6, marginTop: 0 }} onSubmit={(e) => { e.preventDefault(); if (!addName.trim()) return; addContact.mutate({ name: addName.trim(), number: num, email: addEmail.trim() || null }); }}>
|
||||||
}
|
<input value={addName} onChange={(e) => setAddName(e.target.value)} placeholder="Name" required style={{ flex: 1, minWidth: 120 }} />
|
||||||
}}>+ Add to contacts</button>
|
<input value={addEmail} onChange={(e) => setAddEmail(e.target.value)} placeholder="Email" type="email" style={{ flex: 1, minWidth: 140 }} />
|
||||||
|
<button type="submit" className="primary" disabled={addContact.isPending}>Save</button>
|
||||||
|
<button type="button" className="btn" onClick={() => setAddingId(null)}>Cancel</button>
|
||||||
|
</form>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user