mirror of
https://github.com/temetro/temetro.git
synced 2026-08-20 23:22:18 +00:00
feat(meetings): live invite, scheduling calendar, Discord-style redesign
- 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>
This commit is contained in:
@@ -39,6 +39,51 @@ meetingsRouter.post("/", async (req, res, next) => {
|
||||
}
|
||||
});
|
||||
|
||||
// --- Scheduled meetings (calendar) -----------------------------------------
|
||||
|
||||
meetingsRouter.get("/events", async (req, res, next) => {
|
||||
try {
|
||||
res.json(await meetings.listMeetingEvents(req.organizationId!, req.user!.id));
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
const eventSchema = z.object({
|
||||
title: z.string().trim().min(1).max(120),
|
||||
date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
|
||||
time: z.string().regex(/^\d{2}:\d{2}$/),
|
||||
participants: z.array(z.string()).max(50).default([]),
|
||||
});
|
||||
|
||||
meetingsRouter.post("/events", async (req, res, next) => {
|
||||
try {
|
||||
const input = eventSchema.parse(req.body);
|
||||
const event = await meetings.createMeetingEvent(
|
||||
req.organizationId!,
|
||||
req.user!.id,
|
||||
input,
|
||||
);
|
||||
res.status(201).json(event);
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
meetingsRouter.delete("/events/:id", async (req, res, next) => {
|
||||
try {
|
||||
const ok = await meetings.deleteMeetingEvent(
|
||||
req.organizationId!,
|
||||
req.user!.id,
|
||||
String(req.params.id ?? ""),
|
||||
);
|
||||
if (!ok) throw new HttpError(404, "Meeting not found.");
|
||||
res.status(204).end();
|
||||
} catch (err) {
|
||||
next(err);
|
||||
}
|
||||
});
|
||||
|
||||
meetingsRouter.delete("/:id", async (req, res, next) => {
|
||||
try {
|
||||
const ok = await meetings.deleteRoom(
|
||||
|
||||
Reference in New Issue
Block a user