refactor(bookings): simplify capacity tracking to use seats

Replace 'pax' booking mode with 'seat'
Consolidate inventory summary to track only seat counts
Update database schema and UI for seat-centric capacity
This commit is contained in:
2026-04-13 08:49:54 +08:00
parent c47d0d287e
commit faa998c7e1
12 changed files with 136 additions and 139 deletions

View File

@@ -1,4 +1,4 @@
export type BookingMode = 'table' | 'pax'
export type BookingMode = 'table' | 'seat'
export type TicketType = 'vip' | 'supporter'
export type BookingStatus = 'pending' | 'confirmed'
@@ -7,14 +7,16 @@ export const DINNER_EVENT_DATE_LABEL = 'Saturday, 30 May 2026'
export const DINNER_EVENT_TIME_LABEL = '6:30 PM'
export const DINNER_EVENT_VENUE = "Yong Peng's Chee Ann Kor"
export const TABLE_SEAT_COUNT = 10
export const BOOKING_MODE_OPTIONS = [
{
value: 'table',
label: 'Table (10 pax)'
label: `Table (${TABLE_SEAT_COUNT} seats)`
},
{
value: 'pax',
label: 'Person'
value: 'seat',
label: 'Seat'
}
] satisfies Array<{ value: BookingMode, label: string }>
@@ -22,13 +24,13 @@ export const BOOKING_TICKET_CATALOG = [
{
value: 'vip',
label: 'VIP',
description: 'RM150 / pax',
description: 'RM150 / seat',
price: 150
},
{
value: 'supporter',
label: 'Supporter',
description: 'RM60 / pax',
description: 'RM60 / seat',
price: 60
}
] satisfies Array<{ value: TicketType, label: string, description: string, price: number }>
@@ -97,22 +99,15 @@ export interface PublicSeatReceipt {
}
export interface BookingCapacitySettings {
totalTables: number | null
totalSeats: number | null
updatedAt: string | null
}
export interface BookingInventorySummary {
totalTables: number | null
totalCapacitySeats: number | null
soldTables: number
pendingTables: number
totalSeats: number | null
soldSeats: number
pendingSeats: number
soldCapacitySeats: number
pendingCapacitySeats: number
leftTables: number | null
leftSeats: number | null
leftCapacitySeats: number | null
}
export interface CreateBookingResponse {
@@ -122,7 +117,7 @@ export interface CreateBookingResponse {
}
export function isBookingMode(value: string | null | undefined): value is BookingMode {
return value === 'table' || value === 'pax'
return value === 'table' || value === 'seat'
}
export function isTicketType(value: string | null | undefined): value is TicketType {
@@ -134,7 +129,7 @@ export function isBookingStatus(value: string | null | undefined): value is Book
}
export function getBookingModeLabel(value: BookingMode) {
return value === 'table' ? 'Table (10 pax each)' : 'Per person'
return value === 'table' ? `Table (${TABLE_SEAT_COUNT} seats each)` : 'Per seat'
}
export function getBookingStatusLabel(value: BookingStatus) {
@@ -142,7 +137,7 @@ export function getBookingStatusLabel(value: BookingStatus) {
}
export function getSeatCount(bookingMode: BookingMode, quantity: number) {
return bookingMode === 'table' ? quantity * 10 : quantity
return bookingMode === 'table' ? quantity * TABLE_SEAT_COUNT : quantity
}
export function getTicketCatalogItem(ticketType: TicketType) {
@@ -163,41 +158,23 @@ export function getSeatLabel(seatNumber: number) {
}
export function calculateBookingInventorySummary(
bookings: Pick<PublicBooking, 'bookingMode' | 'quantity' | 'seatCount' | 'status'>[],
bookings: Pick<PublicBooking, 'seatCount' | 'status'>[],
settings: BookingCapacitySettings
): BookingInventorySummary {
const soldTables = bookings
.filter((booking) => booking.status === 'confirmed' && booking.bookingMode === 'table')
.reduce((total, booking) => total + booking.quantity, 0)
const pendingTables = bookings
.filter((booking) => booking.status === 'pending' && booking.bookingMode === 'table')
.reduce((total, booking) => total + booking.quantity, 0)
const soldSeats = bookings
.filter((booking) => booking.status === 'confirmed' && booking.bookingMode === 'pax')
.filter((booking) => booking.status === 'confirmed')
.reduce((total, booking) => total + booking.seatCount, 0)
const pendingSeats = bookings
.filter((booking) => booking.status === 'pending' && booking.bookingMode === 'pax')
.filter((booking) => booking.status === 'pending')
.reduce((total, booking) => total + booking.seatCount, 0)
const totalCapacitySeats = settings.totalTables === null ? null : settings.totalTables * 10
const soldCapacitySeats = (soldTables * 10) + soldSeats
const pendingCapacitySeats = (pendingTables * 10) + pendingSeats
const leftCapacitySeats = totalCapacitySeats === null ? null : Math.max(totalCapacitySeats - soldCapacitySeats, 0)
const leftSeats = settings.totalSeats === null ? null : Math.max(settings.totalSeats - soldSeats, 0)
return {
totalTables: settings.totalTables,
totalCapacitySeats,
soldTables,
pendingTables,
totalSeats: settings.totalSeats,
soldSeats,
pendingSeats,
soldCapacitySeats,
pendingCapacitySeats,
leftTables: leftCapacitySeats === null ? null : Math.floor(leftCapacitySeats / 10),
leftSeats: leftCapacitySeats === null ? null : leftCapacitySeats % 10,
leftCapacitySeats
leftSeats
}
}