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:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user