- 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.
61 lines
1.8 KiB
TypeScript
61 lines
1.8 KiB
TypeScript
import { db } from '@/lib/prisma';
|
|
import { sseManager } from '@/lib/sse';
|
|
import {
|
|
AdminBookingServiceError,
|
|
rescheduleAdminBooking,
|
|
} from '@/modules/admin-booking/services/admin-booking.service';
|
|
import { sendBookingRescheduled } from '@/services/booking-email.service';
|
|
import type { AppContext } from '@/types/hono';
|
|
import type { RescheduleAdminBookingInput } from '@repo/api-contract';
|
|
|
|
type BookingIdParams = { id: string };
|
|
|
|
export async function rescheduleAdminBookingHandler(c: AppContext) {
|
|
const { id } = c.req.valid('param' as never) as BookingIdParams;
|
|
const payload = c.req.valid('json' as never) as RescheduleAdminBookingInput;
|
|
const user = c.get('user');
|
|
|
|
const previous = await db.courtBooking.findUnique({
|
|
where: { id },
|
|
select: {
|
|
court: { select: { name: true } },
|
|
startTime: true,
|
|
endTime: true,
|
|
customerEmail: true,
|
|
},
|
|
});
|
|
|
|
try {
|
|
const booking = await rescheduleAdminBooking(user.id, id, payload);
|
|
|
|
if (previous) {
|
|
void sendBookingRescheduled({
|
|
bookingCode: booking.bookingCode,
|
|
complexName: booking.complexName,
|
|
date: booking.date,
|
|
startTime: booking.startTime,
|
|
endTime: booking.endTime,
|
|
courtName: booking.courtName,
|
|
sportName: booking.sport.name,
|
|
customerName: booking.customerName,
|
|
customerEmail: previous.customerEmail,
|
|
previousCourtName: previous.court.name,
|
|
previousStartTime: previous.startTime,
|
|
previousEndTime: previous.endTime,
|
|
});
|
|
}
|
|
|
|
sseManager.emit(
|
|
`complex:${booking.complexId}`,
|
|
JSON.stringify({ type: 'reschedule', booking })
|
|
);
|
|
|
|
return c.json(booking);
|
|
} catch (error) {
|
|
if (error instanceof AdminBookingServiceError) {
|
|
return c.json({ message: error.message }, error.status);
|
|
}
|
|
throw error;
|
|
}
|
|
}
|