Initial commit: ANOUMA website with Payload CMS, WebRTC meetings, and booking system

- Next.js 16 App Router site with the ANOUMA design system
- Payload CMS (PostgreSQL) for offers, events, posts and page content
- WebRTC video-call system with custom signaling server
- SMTP email reminders and booking-request notifications
- Customer accounts, calendar-based availability, and booking workflow
This commit is contained in:
maro
2026-08-25 16:40:51 +02:00
commit 45261a0461
138 changed files with 23263 additions and 0 deletions
+51
View File
@@ -0,0 +1,51 @@
export type MeetingStatus = "scheduled" | "open" | "live" | "ended";
/**
* Payload's "time only" date fields still store a full ISO timestamp, just
* with an arbitrary date portion — this combines the real event date with
* the hour/minute from a time-only field into one correct Date.
*/
export function combineDateAndTime(dateISO: string, timeISO?: string | null): Date {
const date = new Date(dateISO);
if (!timeISO) return date;
const time = new Date(timeISO);
const combined = new Date(date);
combined.setHours(time.getHours(), time.getMinutes(), 0, 0);
return combined;
}
export type MeetingWindow = {
start: Date;
end: Date;
joinWindowMinutes: number;
closeAfterMinutes: number;
now?: Date;
};
export function getMeetingStatus({
start,
end,
joinWindowMinutes,
closeAfterMinutes,
now = new Date(),
}: MeetingWindow): MeetingStatus {
const openAt = start.getTime() - joinWindowMinutes * 60_000;
const closeAt = end.getTime() + closeAfterMinutes * 60_000;
const t = now.getTime();
if (t >= closeAt) return "ended";
if (t >= start.getTime()) return "live";
if (t >= openAt) return "open";
return "scheduled";
}
export function canJoinMeeting(status: MeetingStatus): boolean {
return status === "open" || status === "live";
}
export const statusLabel: Record<MeetingStatus, string> = {
scheduled: "Online-Termin",
open: "Termin beginnt bald",
live: "Jetzt teilnehmen",
ended: "Termin beendet",
};