import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { api } from "../lib/api"; import { useState } from "react"; export default function MessagesPage() { const [q, setQ] = useState(""); const [dateFrom, setDateFrom] = useState(""); const [dateTo, setDateTo] = useState(""); const [unreadOnly, setUnreadOnly] = useState(false); const [expanded, setExpanded] = useState(null); const [addingId, setAddingId] = useState(null); const [addName, setAddName] = useState(""); const [addEmail, setAddEmail] = useState(""); const qc = useQueryClient(); const { data, isLoading, error } = useQuery({ queryKey: ["messages", q, dateFrom, dateTo, unreadOnly], queryFn: () => api.messages({ q, date_from: dateFrom, date_to: dateTo, unread: unreadOnly ? "1" : "" }), }); const toggleRead = useMutation({ mutationFn: (id: number) => api.toggleRead(id), onSuccess: () => qc.invalidateQueries({ queryKey: ["messages"] }), }); const deleteMsg = useMutation({ mutationFn: (id: number) => api.deleteMessage(id), 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 sanitiseNumber = (raw?: string) => { if (!raw) return ""; const bracket = raw.match(/<([^>]+)>/); if (bracket) return bracket[1].trim(); return raw.replace(/[^\d+]/g, "").trim(); }; const startAdd = (m: { id: number; contact_name?: string; callerid?: string }) => { setAddName(m.contact_name || ""); setAddEmail(""); setAddingId(m.id); }; return ( <>
setQ(e.target.value)} placeholder="Search caller, transcript..." style={{ flex: 1, minWidth: 180 }} /> setDateFrom(e.target.value)} style={{ width: "auto" }} /> setDateTo(e.target.value)} style={{ width: "auto" }} /> {(q || dateFrom || dateTo || unreadOnly) && Clear all}
{isLoading &&
Loading...
} {error &&
{(error as Error).message}
} {data?.messages?.map((m) => { const whoRaw = m.contact_name || m.callerid || "Unknown caller"; const num = sanitiseNumber(m.callerid); const showAdd = !m.contact_name && num; return (
{m.contact_name && num ? ( {whoRaw} ) : ( {whoRaw} )}
{m.time}{m.duration_fmt ? ` · ${m.duration_fmt}` : ""}
{m.summary || "(no speech detected)"}
{m.transcript && (
Full transcript
{m.transcript}
)} {m.tags?.length ? (
{m.tags.map((t: string) => {t})}
) : null} {m.numbers?.length ? (
📞 Callback:{" "} {m.numbers.map((n: string) => { const digits = n.replace(/[^\d+]/g, ""); return {n}; }).reduce((prev: any, curr: any, i: number) => i === 0 ? [curr] : [...prev, " · ", curr], [])}
) : null} {m.has_audio &&
); })} {data?.messages?.length === 0 && (
No voicemails match your filters.
)} {addingId !== null && (
setAddingId(null)}>
e.stopPropagation()}>

Add contact

{(() => { const target = data?.messages?.find((x: any) => x.id === addingId); const num = sanitiseNumber(target?.callerid); return num ?
Number: {num}
: null; })()}
{ e.preventDefault(); if (!addName.trim()) return; const target = data?.messages?.find((x: any) => x.id === addingId); const targetNum = sanitiseNumber(target?.callerid); addContact.mutate({ name: addName.trim(), number: targetNum || undefined, email: addEmail.trim() || null }); }}> setAddName(e.target.value)} required /> setAddEmail(e.target.value)} />
)} ); }