queue-med/shared/types.ts

105 lines
2.6 KiB
TypeScript

// Shared TypeScript types between client and server.
// Type-only — safe to import from both sides without bundling runtime code.
export type UserRole = "user" | "admin";
export type SubscriptionPlan = "trial" | "basic" | "pro";
export type SubscriptionStatus =
| "trialing"
| "active"
| "past_due"
| "canceled"
| "expired";
export type QueueEntryStatus =
| "waiting"
| "called"
| "in_consultation"
| "done"
| "absent"
| "canceled";
export type AnalyticsEventType =
| "patient_joined"
| "patient_called"
| "patient_done"
| "patient_absent"
| "queue_opened"
| "queue_closed";
export interface PublicUser {
id: number;
email: string;
name: string | null;
role: UserRole;
}
export interface ClinicSummary {
id: number;
name: string;
color: string | null;
isQueueOpen: boolean;
avgConsultationMinutes: number | null;
}
export interface PublicQueueEntry {
id: number;
ticketNumber: number;
status: QueueEntryStatus;
position: number;
estimatedWaitMinutes: number | null;
patientName: string | null;
}
// ─── Socket.io event payloads ────────────────────────────────────────────────
export interface QueueUpdatePayload {
clinic: ClinicSummary | unknown;
queue: PublicQueueEntry[];
callingNow: { ticketNumber: number; patientName: string | null } | null;
waitingCount: number;
}
export interface PatientUpdatePayload {
entry: {
id: number;
ticketNumber: number;
status: QueueEntryStatus;
position: number;
estimatedWaitMinutes: number | null;
};
position: number;
estimatedWaitMinutes: number | null;
callingNow: { ticketNumber: number; patientName: string | null } | null;
waitingCount: number;
}
export interface PatientCalledPayload {
ticketNumber: number;
clinicId: number;
}
export interface QrRotatedPayload {
qrToken: string;
qrTokenExpiresAt: string | Date | null;
}
export const SOCKET_EVENTS = {
// Doctor / display rooms
QUEUE_UPDATE: "queue:update",
QR_ROTATED: "qr:rotated",
// Patient room
PATIENT_UPDATE: "patient:update",
PATIENT_CALLED: "patient:called",
PATIENT_APPROACHING: "patient:approaching",
PATIENT_ABSENT: "patient:absent",
PATIENT_DONE: "patient:done",
// Subscription topics
CLINIC_SUBSCRIBE: "clinic:subscribe",
CLINIC_UNSUBSCRIBE: "clinic:unsubscribe",
DISPLAY_SUBSCRIBE: "display:subscribe",
DISPLAY_UNSUBSCRIBE: "display:unsubscribe",
PATIENT_SUBSCRIBE: "patient:subscribe",
PATIENT_UNSUBSCRIBE: "patient:unsubscribe",
} as const;
export type SocketEventName = (typeof SOCKET_EVENTS)[keyof typeof SOCKET_EVENTS];