mirror of
https://github.com/temetro/temetro.git
synced 2026-07-26 11:58:14 +00:00
913a217e1d
- Live invite: ring a clinic member into a room (socket call:invite + a bell notification); the invitee gets a toast with a Join action. Notifications of type "meeting" deep-link to /messages/meetings?room=, which auto-joins. - Scheduling: new scheduled_meetings table + /api/meetings/events (list mine, create, delete); a Calendar tab on the Meetings page with a month picker (meeting-day dots), the day's agenda, and a Schedule-meeting dialog (title/date/time/participants). - Redesign: rounded control bar with tooltips (mic/cam/screen/invite + separated red Leave), speaking ring on tiles (Web Audio), and live room-occupancy counts via call:presence broadcasts. Migration 0025. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
72 lines
1.8 KiB
TypeScript
72 lines
1.8 KiB
TypeScript
import { apiFetch } from "@/lib/api-client";
|
|
|
|
// A persistent staff meeting room (Discord-style voice/video channel). The live
|
|
// call (participants/media) is ephemeral and runs over the socket; this is just
|
|
// the room list.
|
|
export type MeetingRoom = {
|
|
id: string;
|
|
name: string;
|
|
createdAt: string;
|
|
};
|
|
|
|
export function listMeetingRooms(): Promise<MeetingRoom[]> {
|
|
return apiFetch<MeetingRoom[]>("/api/meetings");
|
|
}
|
|
|
|
export function createMeetingRoom(name: string): Promise<MeetingRoom> {
|
|
return apiFetch<MeetingRoom>("/api/meetings", {
|
|
method: "POST",
|
|
body: JSON.stringify({ name }),
|
|
});
|
|
}
|
|
|
|
export function deleteMeetingRoom(id: string): Promise<void> {
|
|
return apiFetch<void>(`/api/meetings/${encodeURIComponent(id)}`, {
|
|
method: "DELETE",
|
|
});
|
|
}
|
|
|
|
// Max peers in a mesh call — mirrors the backend cap (mesh degrades past ~4).
|
|
export const MAX_CALL_PEERS = 4;
|
|
|
|
// A remote peer in a live call.
|
|
export type CallPeer = {
|
|
socketId: string;
|
|
userId: string;
|
|
userName: string;
|
|
};
|
|
|
|
// --- Scheduled meetings (calendar) -----------------------------------------
|
|
|
|
export type ScheduledMeeting = {
|
|
id: string;
|
|
title: string;
|
|
date: string; // YYYY-MM-DD
|
|
time: string; // HH:mm
|
|
participants: string[];
|
|
participantNames: string[];
|
|
createdBy: string | null;
|
|
};
|
|
|
|
export function listMeetingEvents(): Promise<ScheduledMeeting[]> {
|
|
return apiFetch<ScheduledMeeting[]>("/api/meetings/events");
|
|
}
|
|
|
|
export function createMeetingEvent(input: {
|
|
title: string;
|
|
date: string;
|
|
time: string;
|
|
participants: string[];
|
|
}): Promise<ScheduledMeeting> {
|
|
return apiFetch<ScheduledMeeting>("/api/meetings/events", {
|
|
method: "POST",
|
|
body: JSON.stringify(input),
|
|
});
|
|
}
|
|
|
|
export function deleteMeetingEvent(id: string): Promise<void> {
|
|
return apiFetch<void>(`/api/meetings/events/${encodeURIComponent(id)}`, {
|
|
method: "DELETE",
|
|
});
|
|
}
|