mirror of
https://github.com/temetro/temetro.git
synced 2026-08-03 15:37:46 +00:00
730e07fcfc
Add conversations/participants/messages tables, a participant-scoped REST API (/api/conversations) and a Socket.io server (session-authenticated handshake; per-user + per-conversation rooms) sharing the HTTP port. New messages broadcast live and create per-recipient notifications. Also lands the notifications table + service + routes (used by the message flow). The Messages page is rewritten: live threads, unread state, and a compose dialog to start a conversation with a clinic member. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
70 lines
1.7 KiB
TypeScript
70 lines
1.7 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;
|
|
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",
|
|
});
|
|
}
|