1import { z } from './schema';
2import { db } from './db';
3
4
5export const HOURS = {
6 1: ['08:00', '18:00'],
7 2: ['08:00', '18:00'],
8 3: ['08:00', '18:00'],
9 4: ['08:00', '21:00'],
10 5: ['08:00', '22:00'],
11 6: ['09:00', '22:00'],
12 0: ['10:00', '17:00'],
13} as const;
14
15export interface Booking {
16 id: string;
17 name: string;
18 guests: number;
19 starts: Date;
20 table?: number;
21}
22
23const BookingInput = z.object({
24 name: z.string().min(2),
25 guests: z.number().int().min(1).max(12),
26 starts: z.coerce.date(),
27});
28
29
30export function isOpen(starts: Date, minutes = 90) {
31 const day = HOURS[starts.getDay() as keyof typeof HOURS];
32 const [from, to] = day.map((t) => Number(t.replace(':', '')));
33 const begin = starts.getHours() * 100 + starts.getMinutes();
34 const end = begin + Math.floor(minutes / 60) * 100 + (minutes % 60);
35 return begin >= from && end <= to;
36}
37
38export async function findTable(guests: number, starts: Date) {
39 const taken = await db.bookings.tablesAt(starts);
40 const tables = await db.tables.withSeats(guests);
41 return tables.find((t) => !taken.includes(t.id)) ?? null;
42}
43
44export async function createBooking(input: unknown): Promise<Booking> {
45 const data = BookingInput.parse(input);
46 if (!isOpen(data.starts)) throw new Error('closed');
47 const table = await findTable(data.guests, data.starts);
48
49 if (!table || data.guests > 8) return db.bookings.request(data);
50 return db.bookings.insert({ ...data, table: table.id });
51}
52
53export async function cancelBooking(id: string) {
54 await db.bookings.update(id, { cancelled: true });
55 return { ok: true };
56}