'use client'; import { useState, useEffect } from 'react'; import { useParams, useSearchParams } from 'next/navigation'; import Link from 'next/link'; import { useLanguage } from '@/context/LanguageContext'; import { ticketsApi, paymentOptionsApi, Ticket, PaymentOptionsConfig } from '@/lib/api'; import Card from '@/components/ui/Card'; import Button from '@/components/ui/Button'; import { CheckCircleIcon, ClockIcon, XCircleIcon, TicketIcon, CreditCardIcon, BuildingLibraryIcon, ArrowTopRightOnSquareIcon, CalendarIcon, MapPinIcon, CurrencyDollarIcon, } from '@heroicons/react/24/outline'; import toast from 'react-hot-toast'; type PaymentStep = 'loading' | 'manual_payment' | 'pending_approval' | 'confirmed' | 'error'; export default function BookingPaymentPage() { const params = useParams(); const searchParams = useSearchParams(); const { locale } = useLanguage(); const [ticket, setTicket] = useState(null); const [paymentConfig, setPaymentConfig] = useState(null); const [step, setStep] = useState('loading'); const [markingPaid, setMarkingPaid] = useState(false); const [error, setError] = useState(null); const ticketId = params.ticketId as string; const requestedStep = searchParams.get('step'); // Fetch ticket and payment config useEffect(() => { if (!ticketId) return; const loadBookingData = async () => { try { // Get ticket with event and payment info const { ticket: ticketData } = await ticketsApi.getById(ticketId); if (!ticketData) { setError('Booking not found'); setStep('error'); return; } setTicket(ticketData); // Only proceed for manual payment methods const paymentMethod = ticketData.payment?.provider; if (!['bank_transfer', 'tpago'].includes(paymentMethod || '')) { // Not a manual payment method, redirect to success page or show appropriate state if (ticketData.status === 'confirmed' || ticketData.payment?.status === 'paid') { setStep('confirmed'); } else { setError('This booking does not support manual payment confirmation.'); setStep('error'); } return; } // Get payment config for the event if (ticketData.eventId) { const { paymentOptions } = await paymentOptionsApi.getForEvent(ticketData.eventId); setPaymentConfig(paymentOptions); } // Determine which step to show based on payment status const paymentStatus = ticketData.payment?.status; if (paymentStatus === 'paid' || ticketData.status === 'confirmed') { setStep('confirmed'); } else if (paymentStatus === 'pending_approval') { setStep('pending_approval'); } else if (paymentStatus === 'pending') { setStep('manual_payment'); } else { setError('Unable to determine payment status'); setStep('error'); } } catch (err: any) { console.error('Error loading booking:', err); setError(err.message || 'Failed to load booking'); setStep('error'); } }; loadBookingData(); }, [ticketId]); // Handle "I Have Paid" button click const handleMarkPaymentSent = async () => { if (!ticket) return; // Check if already marked as paid if (ticket.payment?.status === 'pending_approval' || ticket.payment?.status === 'paid') { toast(locale === 'es' ? 'El pago ya fue marcado como enviado.' : 'Payment has already been marked as sent.', { icon: 'ℹ️' } ); return; } setMarkingPaid(true); try { await ticketsApi.markPaymentSent(ticket.id); // Update local state setTicket(prev => prev ? { ...prev, payment: prev.payment ? { ...prev.payment, status: 'pending_approval', userMarkedPaidAt: new Date().toISOString(), } : prev.payment, } : null); setStep('pending_approval'); toast.success(locale === 'es' ? 'Pago marcado como enviado. Esperando aprobación.' : 'Payment marked as sent. Waiting for approval.'); } catch (error: any) { // Handle idempotency - if already processed, show appropriate message if (error.message?.includes('already been processed')) { toast(locale === 'es' ? 'El pago ya fue procesado anteriormente.' : 'Payment has already been processed.', { icon: 'ℹ️' } ); // Refresh ticket data const { ticket: refreshedTicket } = await ticketsApi.getById(ticket.id); setTicket(refreshedTicket); if (refreshedTicket.payment?.status === 'pending_approval') { setStep('pending_approval'); } else if (refreshedTicket.payment?.status === 'paid') { setStep('confirmed'); } } else { toast.error(error.message || 'Failed to mark payment as sent'); } } finally { setMarkingPaid(false); } }; const formatDate = (dateStr: string) => { return new Date(dateStr).toLocaleDateString(locale === 'es' ? 'es-ES' : 'en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', }); }; const formatTime = (dateStr: string) => { return new Date(dateStr).toLocaleTimeString(locale === 'es' ? 'es-ES' : 'en-US', { hour: '2-digit', minute: '2-digit', }); }; // Loading state if (step === 'loading') { return (

{locale === 'es' ? 'Cargando tu reserva...' : 'Loading your booking...'}

); } // Error state if (step === 'error') { return (

{locale === 'es' ? 'Reserva no encontrada' : 'Booking Not Found'}

{error || (locale === 'es' ? 'No pudimos encontrar tu reserva.' : 'We could not find your booking.')}

); } // Confirmed state if (step === 'confirmed' && ticket) { return (

{locale === 'es' ? '¡Reserva Confirmada!' : 'Booking Confirmed!'}

{locale === 'es' ? 'Tu pago ha sido verificado. ¡Te esperamos en el evento!' : 'Your payment has been verified. See you at the event!'}

{ticket.qrCode}
{ticket.event && (

{locale === 'es' ? 'Evento' : 'Event'}: {ticket.event.title}

{locale === 'es' ? 'Fecha' : 'Date'}: {formatDate(ticket.event.startDatetime)}

{locale === 'es' ? 'Hora' : 'Time'}: {formatTime(ticket.event.startDatetime)}

{locale === 'es' ? 'Ubicación' : 'Location'}: {ticket.event.location}

)}
); } // Pending approval state if (step === 'pending_approval' && ticket) { return (

{locale === 'es' ? '¡Pago en Verificación!' : 'Payment Being Verified!'}

{locale === 'es' ? 'Estamos verificando tu pago. Recibirás un email de confirmación una vez aprobado.' : 'We are verifying your payment. You will receive a confirmation email once approved.'}

{ticket.qrCode}
{ticket.event && (

{locale === 'es' ? 'Evento' : 'Event'}: {ticket.event.title}

{locale === 'es' ? 'Fecha' : 'Date'}: {formatDate(ticket.event.startDatetime)}

{locale === 'es' ? 'Hora' : 'Time'}: {formatTime(ticket.event.startDatetime)}

{locale === 'es' ? 'Ubicación' : 'Location'}: {ticket.event.location}

)}

{locale === 'es' ? 'La verificación del pago puede tomar hasta 24 horas hábiles. Por favor revisa tu email regularmente.' : 'Payment verification may take up to 24 business hours. Please check your email regularly.'}

); } // Manual payment step - show payment details and "I have paid" button if (step === 'manual_payment' && ticket && paymentConfig) { const isBankTransfer = ticket.payment?.provider === 'bank_transfer'; const isTpago = ticket.payment?.provider === 'tpago'; return (
{/* Event Summary Card */} {ticket.event && (

{locale === 'es' && ticket.event.titleEs ? ticket.event.titleEs : ticket.event.title}

{formatDate(ticket.event.startDatetime)} - {formatTime(ticket.event.startDatetime)}
{ticket.event.location}
{ticket.event.price?.toLocaleString()} {ticket.event.currency}
)} {/* Payment Details Card */}
{isBankTransfer ? ( ) : ( )}

{locale === 'es' ? 'Completa tu Pago' : 'Complete Your Payment'}

{locale === 'es' ? 'Sigue las instrucciones para completar tu pago' : 'Follow the instructions to complete your payment'}

{/* Amount to pay */}

{locale === 'es' ? 'Monto a pagar' : 'Amount to pay'}

{ticket.event?.price?.toLocaleString()} {ticket.event?.currency}

{/* Bank Transfer Details */} {isBankTransfer && (

{locale === 'es' ? 'Datos Bancarios' : 'Bank Details'}

{paymentConfig.bankName && (
{locale === 'es' ? 'Banco' : 'Bank'}: {paymentConfig.bankName}
)} {paymentConfig.bankAccountHolder && (
{locale === 'es' ? 'Titular' : 'Account Holder'}: {paymentConfig.bankAccountHolder}
)} {paymentConfig.bankAccountNumber && (
{locale === 'es' ? 'Nro. Cuenta' : 'Account Number'}: {paymentConfig.bankAccountNumber}
)} {paymentConfig.bankAlias && (
Alias: {paymentConfig.bankAlias}
)} {paymentConfig.bankPhone && (
{locale === 'es' ? 'Teléfono' : 'Phone'}: {paymentConfig.bankPhone}
)}
{(locale === 'es' ? paymentConfig.bankNotesEs : paymentConfig.bankNotes) && (

{locale === 'es' ? paymentConfig.bankNotesEs : paymentConfig.bankNotes}

)}
)} {/* TPago Link */} {isTpago && (

{locale === 'es' ? 'Pago con Tarjeta' : 'Card Payment'}

{paymentConfig.tpagoLink && ( {locale === 'es' ? 'Abrir TPago para Pagar' : 'Open TPago to Pay'} )} {(locale === 'es' ? paymentConfig.tpagoInstructionsEs : paymentConfig.tpagoInstructions) && (

{locale === 'es' ? paymentConfig.tpagoInstructionsEs : paymentConfig.tpagoInstructions}

)}
)} {/* Reference */}

{locale === 'es' ? 'Referencia de tu reserva' : 'Your booking reference'}

{ticket.qrCode}

{/* I Have Paid Button */}

{locale === 'es' ? 'Tu reserva será confirmada una vez que verifiquemos el pago' : 'Your booking will be confirmed once we verify the payment'}

); } // Fallback return (

{locale === 'es' ? 'Cargando...' : 'Loading...'}

); }