- ContactsPage: drop whiteSpace:nowrap on the action cell; wrap the Edit/History/Delete/⋮ buttons in a flex container with flex-wrap so they reflow instead of forcing the table wider than the viewport; allow the name/number/email cell to break long strings. - index.css: td word-break:break-word + table max-width:100% as a guard. - Sync the UI repo (ContactsPage/ContactHistory/MessagesPage implicit-any annotations that unblock npm run build) into the frontend/ mirror.
30 lines
1.3 KiB
TypeScript
30 lines
1.3 KiB
TypeScript
import { useQuery } from "@tanstack/react-query";
|
|
import { useParams } from "react-router-dom";
|
|
import { api } from "../lib/api";
|
|
|
|
export default function ContactHistory() {
|
|
const { num } = useParams();
|
|
const { data, isLoading, error } = useQuery({ queryKey: ["history", num], queryFn: () => api.contactHistory(num || ""), enabled: !!num });
|
|
return (
|
|
<div className="wrap">
|
|
<div className="card" style={{ padding: "12px 16px" }}>
|
|
<div className="meta">
|
|
<a href="/contacts">← Back to contacts</a>
|
|
{data && <> · {data.messages?.length ?? 0} message(s) from <b>{data.contact}</b></>}
|
|
</div>
|
|
</div>
|
|
{isLoading && <div className="card empty">Loading...</div>}
|
|
{error && <div className="card err">{(error as Error).message}</div>}
|
|
{data?.messages?.map((m: any) => (
|
|
<div key={m.id} className={"card" + (m.is_read ? "" : " unread")}>
|
|
<div className="who">{data.contact}</div>
|
|
<div className="meta">{m.time}{m.duration_fmt ? ` · ${m.duration_fmt}` : ""}</div>
|
|
<div className="sum">{m.summary || "(no speech detected)"}</div>
|
|
{m.has_audio && <audio controls preload="none" src={`/audio/${m.id}`} />}
|
|
</div>
|
|
))}
|
|
{data?.messages?.length === 0 && <div className="card empty">No voicemails from this caller yet.</div>}
|
|
</div>
|
|
);
|
|
}
|