70 lines
2.2 KiB
TypeScript
70 lines
2.2 KiB
TypeScript
import { randomUUID } from 'node:crypto';
|
|
import { createActionLog, openDb, type Appointment, type AppointmentStatus } from '@when/db';
|
|
import { APP_DB_PATH } from './database.ts';
|
|
|
|
const MINUTE_MS = 60_000;
|
|
const DAY_MS = 24 * 60 * MINUTE_MS;
|
|
|
|
// The meeting's key is both its URL slug and its `event_type_id`.
|
|
export const CHAT_MEETING = {
|
|
slug: 'chat',
|
|
title: '30-minute chat',
|
|
durationMinutes: 30
|
|
};
|
|
|
|
// Live rows in the same test are unique on (event_type_id, start_time).
|
|
// A month out so seeds do not occupy the near days a booking journey picks.
|
|
let seedsInThisWorker = 0;
|
|
function unusedStart(): Date {
|
|
return new Date(Date.now() + 30 * DAY_MS + seedsInThisWorker++ * MINUTE_MS);
|
|
}
|
|
|
|
export interface SeedAppointmentOptions {
|
|
eventTypeId?: string;
|
|
status?: AppointmentStatus;
|
|
start?: Date;
|
|
durationMinutes?: number;
|
|
guestName?: string;
|
|
guestEmail?: string | null;
|
|
}
|
|
|
|
export async function seedAppointment(options: SeedAppointmentOptions = {}): Promise<Appointment> {
|
|
const start = options.start ?? unusedStart();
|
|
const durationMinutes = options.durationMinutes ?? CHAT_MEETING.durationMinutes;
|
|
const id = `e2e-${randomUUID()}`;
|
|
const db = openDb(APP_DB_PATH);
|
|
|
|
try {
|
|
const appointment = await db
|
|
.insertInto('appointments')
|
|
.values({
|
|
id,
|
|
event_type_id: options.eventTypeId ?? CHAT_MEETING.slug,
|
|
start_time: start.toISOString(),
|
|
end_time: new Date(start.getTime() + durationMinutes * MINUTE_MS).toISOString(),
|
|
guest_name: options.guestName ?? `Guest ${id.slice(4, 12)}`,
|
|
guest_email: options.guestEmail === undefined ? 'guest@example.test' : options.guestEmail,
|
|
guest_answers: null,
|
|
guest_timezone: 'UTC',
|
|
location: null,
|
|
note: null,
|
|
video_chat: null,
|
|
status: options.status ?? 'pending',
|
|
origin_id: id,
|
|
cancel_token: `token-${randomUUID()}`,
|
|
action_log: createActionLog([
|
|
{ action: 'create', actor: 'guest', at: new Date().toISOString() }
|
|
]),
|
|
external_event_id: null,
|
|
external_calendar_id: null,
|
|
// Only read when the meeting is gone from config.
|
|
meeting_snapshot: null
|
|
})
|
|
.returningAll()
|
|
.executeTakeFirstOrThrow();
|
|
return appointment;
|
|
} finally {
|
|
await db.destroy();
|
|
}
|
|
}
|