mirror of
https://github.com/temetro/temetro.git
synced 2026-08-06 00:47:41 +00:00
91e4f4ed30
Same layout, better inbox: avatars on conversation rows, a numeric unread badge (kept live by the socket handler), primary-tinted timestamps for unread rows and softer hover states. In the thread: day separators (Today/Yesterday/date), consecutive same-sender messages within 5 minutes grouped with one sender label + one timestamp and tightened corners, and a "Start a conversation" button on the empty state. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
72 lines
1.8 KiB
TypeScript
72 lines
1.8 KiB
TypeScript
import { apiFetch } from "@/lib/api-client";
|
|
|
|
// Messaging shapes. Mirror the backend `src/types/messaging.ts`.
|
|
export type Participant = {
|
|
id: string;
|
|
name: string;
|
|
};
|
|
|
|
export type ConversationMessage = {
|
|
id: string;
|
|
conversationId: string;
|
|
senderId: string;
|
|
senderName: string;
|
|
body: string;
|
|
createdAt: string;
|
|
};
|
|
|
|
export type ConversationSummary = {
|
|
id: string;
|
|
name: string;
|
|
isGroup: boolean;
|
|
participants: Participant[];
|
|
lastMessage: ConversationMessage | null;
|
|
unread: boolean;
|
|
// Messages from others newer than the caller's read pointer.
|
|
unreadCount: number;
|
|
updatedAt: string;
|
|
};
|
|
|
|
export function listConversations(): Promise<ConversationSummary[]> {
|
|
return apiFetch<ConversationSummary[]>("/api/conversations");
|
|
}
|
|
|
|
export function listClinicMembers(): Promise<Participant[]> {
|
|
return apiFetch<Participant[]>("/api/conversations/members");
|
|
}
|
|
|
|
export function createConversation(input: {
|
|
participantIds: string[];
|
|
name?: string | null;
|
|
}): Promise<ConversationSummary> {
|
|
return apiFetch<ConversationSummary>("/api/conversations", {
|
|
method: "POST",
|
|
body: JSON.stringify(input),
|
|
});
|
|
}
|
|
|
|
export function getMessages(
|
|
conversationId: string,
|
|
): Promise<ConversationMessage[]> {
|
|
return apiFetch<ConversationMessage[]>(
|
|
`/api/conversations/${conversationId}/messages`,
|
|
);
|
|
}
|
|
|
|
// REST fallback for sending (the realtime path is the socket "message:send").
|
|
export function sendMessageRest(
|
|
conversationId: string,
|
|
body: string,
|
|
): Promise<ConversationMessage> {
|
|
return apiFetch<ConversationMessage>(
|
|
`/api/conversations/${conversationId}/messages`,
|
|
{ method: "POST", body: JSON.stringify({ body }) },
|
|
);
|
|
}
|
|
|
|
export function markConversationRead(conversationId: string): Promise<void> {
|
|
return apiFetch<void>(`/api/conversations/${conversationId}/read`, {
|
|
method: "POST",
|
|
});
|
|
}
|