Files
playzer/packages/api-contract/src/public-booking.ts
Jose Selesan 85f234b05e feat: add customer email functionality for booking confirmations
- Implemented email confirmation for admin and public bookings.
- Added customerEmail field to booking schemas and services.
- Created email templates for booking confirmation, cancellation, and no-show notifications.
- Updated booking handlers to send emails upon booking creation and status updates.
- Enhanced frontend forms to capture customer email during booking creation.
2026-06-02 19:21:04 -03:00

111 lines
3.9 KiB
TypeScript

import { z } from 'zod'
import { dayOfWeekSchema } from './court'
const TIME_REGEX = /^([01]\d|2[0-3]):([0-5]\d)$/
const ISO_DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/
const BOOKING_CODE_REGEX = /^[A-Z0-9]{6,8}$/
export const publicAvailabilityQuerySchema = z.object({
date: z.string().regex(ISO_DATE_REGEX, 'La fecha debe tener formato YYYY-MM-DD.'),
sportId: z.uuid('El sportId debe ser un UUID valido.').optional(),
})
export const publicBookingSportSchema = z.object({
id: z.uuid(),
name: z.string(),
slug: z.string(),
})
export const publicBookingSlotSchema = z.object({
startTime: z.string().regex(TIME_REGEX),
endTime: z.string().regex(TIME_REGEX),
price: z.number().nonnegative(),
})
export const publicAvailabilityCourtSchema = z.object({
courtId: z.uuid(),
courtName: z.string(),
sport: publicBookingSportSchema,
slotDurationMinutes: z.int().positive(),
availabilityDay: dayOfWeekSchema,
availableSlots: z.array(publicBookingSlotSchema),
})
export const publicAvailabilityResponseSchema = z.object({
complexId: z.uuid(),
complexName: z.string(),
complexAddress: z.string().optional(),
complexSlug: z.string(),
date: z.string().regex(ISO_DATE_REGEX),
sportSelectionRequired: z.boolean(),
sports: z.array(publicBookingSportSchema),
courts: z.array(publicAvailabilityCourtSchema),
})
export const createPublicBookingSchema = z.object({
date: z.string().regex(ISO_DATE_REGEX, 'La fecha debe tener formato YYYY-MM-DD.'),
sportId: z.uuid('El sportId debe ser un UUID valido.').optional(),
courtId: z.uuid('El courtId debe ser un UUID valido.'),
startTime: z.string().regex(TIME_REGEX, 'La hora debe tener formato HH:mm.'),
customerName: z
.string()
.trim()
.min(2, 'El nombre debe tener al menos 2 caracteres.')
.max(120, 'El nombre no puede superar los 120 caracteres.'),
customerPhone: z
.string()
.trim()
.min(6, 'El telefono debe tener al menos 6 caracteres.')
.max(30, 'El telefono no puede superar los 30 caracteres.'),
customerEmail: z
.string()
.email('El email ingresado no es valido.')
.optional()
.or(z.literal('')),
})
export const publicBookingSchema = z.object({
id: z.uuid(),
bookingCode: z.string().regex(BOOKING_CODE_REGEX),
complexId: z.uuid(),
complexName: z.string(),
complexSlug: z.string(),
courtId: z.uuid(),
courtName: z.string(),
sport: publicBookingSportSchema,
date: z.string().regex(ISO_DATE_REGEX),
startTime: z.string().regex(TIME_REGEX),
endTime: z.string().regex(TIME_REGEX),
customerName: z.string(),
customerPhone: z.string(),
customerEmail: z.string().optional(),
status: z.enum(['CONFIRMED', 'CANCELLED', 'COMPLETED']),
price: z.number().nonnegative(),
createdAt: z.string().datetime(),
})
export const publicBookingConfirmationSchema = z.object({
bookingCode: z.string().regex(BOOKING_CODE_REGEX),
complexName: z.string(),
complexAddress: z.string().optional(),
complexSlug: z.string(),
date: z.string().regex(ISO_DATE_REGEX),
startTime: z.string().regex(TIME_REGEX),
endTime: z.string().regex(TIME_REGEX),
price: z.number().nonnegative(),
courtName: z.string(),
sport: publicBookingSportSchema,
status: z.enum(['CONFIRMED', 'CANCELLED', 'COMPLETED']),
customerEmail: z.string().optional(),
createdAt: z.string().datetime(),
})
export type PublicAvailabilityQuery = z.infer<typeof publicAvailabilityQuerySchema>
export type PublicBookingSport = z.infer<typeof publicBookingSportSchema>
export type PublicBookingSlot = z.infer<typeof publicBookingSlotSchema>
export type PublicAvailabilityCourt = z.infer<typeof publicAvailabilityCourtSchema>
export type PublicAvailabilityResponse = z.infer<typeof publicAvailabilityResponseSchema>
export type CreatePublicBookingInput = z.infer<typeof createPublicBookingSchema>
export type PublicBooking = z.infer<typeof publicBookingSchema>
export type PublicBookingConfirmation = z.infer<typeof publicBookingConfirmationSchema>