From 1210854c22f648b21463ca40ff03bc976aa47597 Mon Sep 17 00:00:00 2001 From: Jose Selesan Date: Thu, 4 Jun 2026 16:39:45 -0300 Subject: [PATCH] feat(booking-ui): add confirmation dialog for cancelling bookings and improve mobile UI --- .../components/booking-tools-dialog.tsx | 312 +++++++++++------- 1 file changed, 187 insertions(+), 125 deletions(-) diff --git a/apps/frontend/src/features/booking/components/booking-tools-dialog.tsx b/apps/frontend/src/features/booking/components/booking-tools-dialog.tsx index 14650c9..587bdf8 100644 --- a/apps/frontend/src/features/booking/components/booking-tools-dialog.tsx +++ b/apps/frontend/src/features/booking/components/booking-tools-dialog.tsx @@ -24,6 +24,7 @@ import { Wrench, XCircle, } from 'lucide-react'; +import { useState } from 'react'; import { useBooking } from '../booking-provider'; function formatDate(date: string | undefined) { @@ -70,6 +71,7 @@ export function BookingToolsDialog() { useBooking(); const isMobile = useIsMobile(); const booking = selectedSegment?.booking; + const [confirmCancelOpen, setConfirmCancelOpen] = useState(false); const status = statusConfig[booking?.status ?? 'CONFIRMED'] ?? { label: booking?.status, @@ -93,151 +95,211 @@ export function BookingToolsDialog() { closeBookingTools(); }; + const cancelConfirmDialog = ( + !open && setConfirmCancelOpen(false)} + > + + + ¿Cancelar reserva? + + Esta acción no se puede deshacer. Se eliminará la reserva y la cancha volverá a estar + disponible. + + + +
+
+ Cliente + {booking?.customerName ?? '-'} +
+
+ Cancha + {booking?.courtName ?? '-'} +
+
+ Fecha + {formatDate(booking?.date) || '-'} +
+
+ Horario + + {booking?.startTime ?? '--:--'} a {booking?.endTime ?? '--:--'} + +
+
+ + + + + + + +
+
+ ); + if (isMobile) { return ( + <> + !open && closeBookingTools()} + > + event.preventDefault()} + > + updateStatus('COMPLETED')} + onCancel={() => setConfirmCancelOpen(true)} + onReminder={sendWhatsappReminder} + onNoShow={() => updateStatus('NOSHOW')} + /> + + + {cancelConfirmDialog} + + ); + } + + return ( + <> !open && closeBookingTools()} > event.preventDefault()} > - updateStatus('COMPLETED')} - onCancel={() => updateStatus('CANCELLED')} - onReminder={sendWhatsappReminder} - onNoShow={() => updateStatus('NOSHOW')} - /> - - - ); - } + + Detalles de la reserva + + Administra la reserva y su estado. + + - return ( - !open && closeBookingTools()}> - event.preventDefault()} - > - - Detalles de la reserva - - Administra la reserva y su estado. - - - -
-
- } - label="Cancha" - value={selectedSegment?.booking?.courtName ?? '-'} - helper={selectedSegment?.booking?.sport?.name} - withDivider - /> - - } - label="Estado actual" - value={status.label} - valueClassName="text-emerald-400 uppercase dark:text-emerald-500" - withDivider - /> - - } - label="Cliente" - value={selectedSegment?.booking?.customerName ?? '-'} - /> - - } - label="Fecha" - value={`${formatDate(selectedSegment?.booking?.date)}`} - withDivider - className="sm:pt-10" - /> - - } - label="Hora" - value={`${selectedSegment?.booking?.startTime} a ${selectedSegment?.booking?.endTime}`} - withDivider - className="sm:pt-10" - /> - - } - label="Teléfono" - value={selectedSegment?.booking?.customerPhone ?? '-'} - className="sm:pt-10" - /> -
-
- - - - {booking?.status !== 'COMPLETED' && ( -
-
-

Acciones disponibles

-

- Elegí qué hacer según lo que ocurrió con el cliente. -

-
-
- } - title="Completar reserva" - description="El cliente se presentó para usar la cancha." - className="border-emerald-500/40 bg-emerald-500/10 text-lg text-emerald-600 hover:bg-emerald-500/15 hover:text-emerald-800" - onClick={() => { - updateStatus('COMPLETED'); - }} +
+
+ } + label="Cancha" + value={selectedSegment?.booking?.courtName ?? '-'} + helper={selectedSegment?.booking?.sport?.name} + withDivider /> - } - title="Cancelar reserva" - description="El cliente avisó que no va a venir. La cancha vuelve a estar disponible." - className="border-red-500/40 bg-red-500/10 text-lg text-red-600 hover:bg-red-500/15 hover:text-red-800" - onClick={() => { - updateStatus('CANCELLED'); - }} + } + label="Estado actual" + value={status.label} + valueClassName="text-emerald-400 uppercase dark:text-emerald-500" + withDivider /> - } - title="Enviar recordatorio" - description="Enviar un mensaje por WhatsApp al cliente." - className="border-sky-500/40 bg-sky-500/10 text-lg text-sky-600 hover:bg-sky-500/15 hover:text-sky-800" - onClick={sendWhatsappReminder} + } + label="Cliente" + value={selectedSegment?.booking?.customerName ?? '-'} /> - } - title="Marcar como No Show" - description="El cliente no vino y no canceló." - className="border-amber-500/40 bg-amber-500/10 text-lg text-amber-600 hover:bg-amber-500/15 hover:text-amber-800" - onClick={() => { - updateStatus('NOSHOW'); - }} + } + label="Fecha" + value={`${formatDate(selectedSegment?.booking?.date)}`} + withDivider + className="sm:pt-10" + /> + + } + label="Hora" + value={`${selectedSegment?.booking?.startTime} a ${selectedSegment?.booking?.endTime}`} + withDivider + className="sm:pt-10" + /> + + } + label="Teléfono" + value={selectedSegment?.booking?.customerPhone ?? '-'} + className="sm:pt-10" />
- )} - - - - - - - + + + {booking?.status !== 'COMPLETED' && ( +
+
+

Acciones disponibles

+

+ Elegí qué hacer según lo que ocurrió con el cliente. +

+
+
+ } + title="Completar reserva" + description="El cliente se presentó para usar la cancha." + className="border-emerald-500/40 bg-emerald-500/10 text-lg text-emerald-600 hover:bg-emerald-500/15 hover:text-emerald-800" + onClick={() => { + updateStatus('COMPLETED'); + }} + /> + + } + title="Cancelar reserva" + description="El cliente avisó que no va a venir. La cancha vuelve a estar disponible." + className="border-red-500/40 bg-red-500/10 text-lg text-red-600 hover:bg-red-500/15 hover:text-red-800" + onClick={() => setConfirmCancelOpen(true)} + /> + + } + title="Enviar recordatorio" + description="Enviar un mensaje por WhatsApp al cliente." + className="border-sky-500/40 bg-sky-500/10 text-lg text-sky-600 hover:bg-sky-500/15 hover:text-sky-800" + onClick={sendWhatsappReminder} + /> + + } + title="Marcar como No Show" + description="El cliente no vino y no canceló." + className="border-amber-500/40 bg-amber-500/10 text-lg text-amber-600 hover:bg-amber-500/15 hover:text-amber-800" + onClick={() => { + updateStatus('NOSHOW'); + }} + /> +
+
+ )} + + + + + + + + + {cancelConfirmDialog} + ); }