feat: add reschedule functionality for admin bookings

- Implemented rescheduleAdminBooking service to allow users to change court and time for confirmed bookings.
- Added validation for court availability, maintenance status, and overlapping bookings.
- Created reschedule-admin-booking handler to process rescheduling requests and send confirmation emails.
- Updated booking email service to include rescheduling notifications.
- Enhanced frontend components to support booking rescheduling, including a new dialog for selecting new court and time.
- Added tests for rescheduling logic, covering various scenarios including validation errors and successful reschedules.
- Updated Prisma schema to log previous court and time for audit purposes.
This commit is contained in:
Jose Selesan
2026-06-24 08:38:10 -03:00
parent fd4d8b7abd
commit dce312d426
23 changed files with 1231 additions and 17 deletions

View File

@@ -90,6 +90,19 @@ export const recurringBookingGroupSchema = z.object({
updatedAt: z.string().datetime(),
});
export const rescheduleAdminBookingSchema = z
.object({
courtId: z.string().uuid('El courtId debe ser un UUID válido.').optional(),
startTime: z
.string()
.regex(TIME_REGEX, 'La hora debe tener formato HH:mm.')
.optional(),
})
.refine(
(data) => data.courtId !== undefined || data.startTime !== undefined,
{ message: 'Debe proporcionar al menos una cancha o un horario diferente.' }
);
export const updateRecurringGroupSchema = z.object({
courtId: z.uuid('El courtId debe ser un UUID valido.').optional(),
dayOfWeek: z
@@ -125,5 +138,6 @@ export type CreateAdminBookingInput = z.infer<typeof createAdminBookingSchema>;
export type CreateRecurringBookingInput = z.infer<typeof createRecurringBookingSchema>;
export type RecurringBookingGroup = z.infer<typeof recurringBookingGroupSchema>;
export type UpdateAdminBookingStatusInput = z.infer<typeof updateAdminBookingStatusSchema>;
export type RescheduleAdminBookingInput = z.infer<typeof rescheduleAdminBookingSchema>;
export type UpdateRecurringGroupInput = z.infer<typeof updateRecurringGroupSchema>;
export type ListRecurringGroupsResponse = z.infer<typeof listRecurringGroupsResponseSchema>;

View File

@@ -115,6 +115,7 @@ export const courtSchema = z.object({
id: z.uuid(),
complexId: z.uuid(),
name: z.string(),
isUnderMaintenance: z.boolean(),
sportId: z.uuid(),
sport: courtSportSchema,
slotDurationMinutes: z.int().positive(),

View File

@@ -82,6 +82,7 @@ export {
listRecurringGroupsResponseSchema,
recurringBookingGroupSchema,
recurringGroupStatusSchema,
rescheduleAdminBookingSchema,
updateAdminBookingStatusSchema,
updateRecurringGroupSchema,
} from './admin-booking';
@@ -96,6 +97,7 @@ export type {
ListRecurringGroupsResponse,
RecurringBookingGroup,
RecurringGroupStatus,
RescheduleAdminBookingInput,
UpdateAdminBookingStatusInput,
UpdateRecurringGroupInput,
} from './admin-booking';