"use server"; import { redirect } from "next/navigation"; import { auth } from "@/auth"; import { clearDraft, readDraft, writeLastBookingReference } from "@/lib/booking-draft/cookie"; import { prisma } from "@/lib/db/prisma"; import { resolveCustomerForBooking } from "@/services/customer/customer.service"; import { createBooking } from "@/services/scheduling/booking.service"; import { getFirstFriendlyMessage } from "../error-messages"; export interface ConfirmBookingResult { success: boolean; error?: string; } /** * The only action that actually creates an appointment. Resolves *which* * customer this is via CustomerService (never trusts a client-supplied * customerId — see docs/phase-4-summary.md, "Security"), then hands off * entirely to BookingService.createBooking, which re-validates the slot * inside a transaction before committing — this action does not decide * whether the slot is actually available. */ export async function confirmBookingAction(businessId: string): Promise { const draft = await readDraft(businessId); if (draft.serviceIds.length === 0 || !draft.startAt) { return { success: false, error: "Your booking details are incomplete — please start again." }; } if (!draft.policyAcknowledged) { return { success: false, error: "Please acknowledge the cancellation policy to continue." }; } const session = await auth(); let customerId: string; try { if (session?.user?.id) { const resolved = await resolveCustomerForBooking(prisma, { businessId, userId: session.user.id }); customerId = resolved.customerId; } else { if (!draft.guest) { return { success: false, error: "Please provide your contact details first." }; } const resolved = await resolveCustomerForBooking(prisma, { businessId, guest: draft.guest }); customerId = resolved.customerId; } } catch { return { success: false, error: "We couldn't confirm your details. Please try again." }; } const result = await createBooking(prisma, { businessId, customerId, serviceIds: draft.serviceIds, staffId: draft.staffId, startAt: new Date(draft.startAt), notes: draft.notes, }); if (!result.success) { return { success: false, error: getFirstFriendlyMessage(result.validation) }; } await writeLastBookingReference(result.appointment.id); await clearDraft(); redirect("/book/confirmation"); }