feat: send ticket receipts via WhatsApp and normalize phone numbers

Add WhatsApp API integration for automated receipt delivery
Enforce country codes for all phone number inputs (defaults to +60)
This commit is contained in:
2026-04-27 13:12:25 +08:00
parent faa998c7e1
commit c214d643dd
18 changed files with 208 additions and 28 deletions

View File

@@ -3,6 +3,7 @@ export const MIN_PASSWORD_LENGTH = 8
export const MIN_FULL_NAME_LENGTH = 2
export const USERNAME_PATTERN = /^[a-z0-9._-]{3,32}$/
export const PHONE_NUMBER_PATTERN = /^\+?\d{8,15}$/
export const DEFAULT_PHONE_COUNTRY_CODE = '+60'
export type UserRole = 'super_admin' | 'staff'
@@ -24,7 +25,21 @@ export function normalizePhoneNumber(value: string) {
const hasPlusPrefix = trimmed.startsWith('+')
const digitsOnly = trimmed.replace(/\D/g, '')
return hasPlusPrefix ? `+${digitsOnly}` : digitsOnly
if (!digitsOnly) {
return ''
}
if (hasPlusPrefix) {
return `+${digitsOnly}`
}
const defaultCountryDigits = DEFAULT_PHONE_COUNTRY_CODE.replace(/\D/g, '')
if (digitsOnly.startsWith(defaultCountryDigits)) {
return `+${digitsOnly}`
}
return `+${defaultCountryDigits}${digitsOnly.replace(/^0+/, '')}`
}
export function isValidPhoneNumber(value: string) {

View File

@@ -116,6 +116,21 @@ export interface CreateBookingResponse {
whatsappUrl: string
}
export interface WhatsAppDeliveryResult {
sent: boolean
skipped: boolean
recipientPhone: string
apiRecipientPhone: string
messageId?: string
error?: string
}
export interface ConfirmBookingResponse {
booking: PublicBooking
alreadyConfirmed: boolean
ticketReceiptWhatsApp: WhatsAppDeliveryResult
}
export function isBookingMode(value: string | null | undefined): value is BookingMode {
return value === 'table' || value === 'seat'
}