import React, { useState, useEffect } from 'react'; import { useParams, useNavigate, Link } from 'react-router-dom'; import { CheckCircle, Home, ListOrdered, Calendar, Users, CreditCard, MapPin, Mail, Phone, User, FileText, Building2, AlertCircle, Copy, Check, Loader2, } from 'lucide-react'; import { toast } from 'react-toastify'; import { getBookingById, generateQRCode, type Booking, } from '../../services/api/bookingService'; import { confirmBankTransfer } from '../../services/api/paymentService'; import Loading from '../../components/common/Loading'; import { useFormatCurrency } from '../../hooks/useFormatCurrency'; import { parseDateLocal } from '../../utils/format'; const BookingSuccessPage: React.FC = () => { const { id } = useParams<{ id: string }>(); const navigate = useNavigate(); const { formatCurrency } = useFormatCurrency(); const [booking, setBooking] = useState( null ); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [copiedBookingNumber, setCopiedBookingNumber] = useState(false); const [uploadingReceipt, setUploadingReceipt] = useState(false); const [receiptUploaded, setReceiptUploaded] = useState(false); const [selectedFile, setSelectedFile] = useState(null); const [previewUrl, setPreviewUrl] = useState(null); useEffect(() => { if (id) { fetchBookingDetails(Number(id)); } }, [id]); const fetchBookingDetails = async (bookingId: number) => { try { setLoading(true); setError(null); const response = await getBookingById(bookingId); if ( response.success && response.data?.booking ) { const bookingData = response.data.booking; setBooking(bookingData); if (bookingData.payment_method === 'stripe' && bookingData.payments) { const pendingStripePayment = bookingData.payments.find( (p: any) => p.payment_method === 'stripe' && p.payment_status === 'pending' ); if (pendingStripePayment) { navigate(`/payment/${bookingId}`, { replace: true }); return; } } if ( bookingData.requires_deposit && !bookingData.deposit_paid ) { navigate(`/deposit-payment/${bookingId}`, { replace: true }); return; } } else { throw new Error( 'Unable to load booking information' ); } } catch (err: any) { console.error('Error fetching booking:', err); const message = err.response?.data?.message || 'Unable to load booking information'; setError(message); toast.error(message); } finally { setLoading(false); } }; const formatDate = (dateString: string) => { const date = parseDateLocal(dateString); return date.toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', }); }; const formatPrice = (price: number) => formatCurrency(price); const getStatusColor = (status: string) => { switch (status) { case 'confirmed': return 'bg-green-100 text-green-800'; case 'pending': return 'bg-yellow-100 text-yellow-800'; case 'cancelled': return 'bg-red-100 text-red-800'; case 'checked_in': return 'bg-blue-100 text-blue-800'; case 'checked_out': return 'bg-gray-100 text-gray-800'; default: return 'bg-gray-100 text-gray-800'; } }; const getStatusText = (status: string) => { switch (status) { case 'confirmed': return 'Confirmed'; case 'pending': return 'Pending confirmation'; case 'cancelled': return 'Cancelled'; case 'checked_in': return 'Checked in'; case 'checked_out': return 'Checked out'; default: return status; } }; const copyBookingNumber = async () => { if (!booking?.booking_number) return; try { await navigator.clipboard.writeText( booking.booking_number ); setCopiedBookingNumber(true); toast.success('Booking number copied'); setTimeout(() => setCopiedBookingNumber(false), 2000); } catch (err) { toast.error('Unable to copy'); } }; const handleFileSelect = ( e: React.ChangeEvent ) => { const file = e.target.files?.[0]; if (!file) return; if (!file.type.startsWith('image/')) { toast.error('Please select an image file'); return; } if (file.size > 5 * 1024 * 1024) { toast.error('Image size must not exceed 5MB'); return; } setSelectedFile(file); const reader = new FileReader(); reader.onloadend = () => { setPreviewUrl(reader.result as string); }; reader.readAsDataURL(file); }; const handleUploadReceipt = async () => { if (!selectedFile || !booking) return; try { setUploadingReceipt(true); const transactionId = `TXN-${booking.booking_number}-${Date.now()}`; const response = await confirmBankTransfer( booking.id, transactionId, selectedFile ); if (response.success) { toast.success( '✅ Payment confirmation sent successfully! ' + 'We will confirm as soon as possible.' ); setReceiptUploaded(true); setBooking((prev) => prev ? { ...prev, payment_status: 'paid', status: prev.status === 'pending' ? 'confirmed' : prev.status } : null ); } else { throw new Error( response.message || 'Unable to confirm payment' ); } } catch (err: any) { console.error('Error uploading receipt:', err); const message = err.response?.data?.message || 'Unable to send payment confirmation. ' + 'Please try again.'; toast.error(message); } finally { setUploadingReceipt(false); } }; const qrCodeUrl = booking ? generateQRCode( booking.booking_number, booking.total_price ) : null; if (loading) { return ; } if (error || !booking) { return (

{error || 'Booking not found'}

); } const room = booking.room; const roomType = room?.room_type; return (
{}

Booking Successful!

Thank you for booking with our hotel

{}
Booking Number: {booking.booking_number}
{}
{getStatusText(booking.status)}
{}

Booking Details

{} {roomType && (
{((room?.room_type?.images && room.room_type.images.length > 0) ? room.room_type.images[0] : roomType?.images?.[0]) && ( 0) ? room.room_type.images[0] : (roomType?.images?.[0] || '')} alt={roomType?.name || 'Room'} className="w-24 h-24 object-cover rounded-lg" /> )}

{roomType.name}

{room && (

Room {room.room_number} - Floor {room.floor}

)}

{formatPrice(room?.room_type?.base_price || roomType?.base_price || 0)}/night

)} {}

Check-in Date

{formatDate(booking.check_in_date)}

Check-out Date

{formatDate(booking.check_out_date)}

{}

Number of Guests

{booking.guest_count} guest(s)

{} {booking.notes && (

Notes

{booking.notes}

)} {}

Payment Method

{booking.payment_method === 'cash' ? '💵 Pay at hotel' : '🏦 Bank transfer'}

{}
{booking.original_price && booking.discount_amount && booking.discount_amount > 0 ? ( <>
Subtotal: {formatPrice(booking.original_price)}
Discount{booking.promotion_code ? ` (${booking.promotion_code})` : ''}: -{formatPrice(booking.discount_amount)}
Total Payment {formatPrice(booking.total_price)}
) : (
Total Payment {formatPrice(booking.total_price)}
)}
{} {booking.guest_info && (

Customer Information

Full Name

{booking.guest_info.full_name}

Email

{booking.guest_info.email}

Phone Number

{booking.guest_info.phone}

)} {} {(booking.payment_method === 'cash' || (booking as any).payment_method === 'bank_transfer') && (

Bank Transfer Instructions

Please transfer according to the following information:

{}

Bank: Vietcombank (VCB)

Account Number: 0123456789

Account Holder: KHACH SAN ABC

Amount:{' '} {formatPrice(booking.total_price)}

Content:{' '} {booking.booking_number}

{} {qrCodeUrl && (

Scan QR code to transfer

QR Code

QR code includes all information

)}

💡 Note: Please enter the correct booking number in the transfer content so we can confirm your payment.

{} {!receiptUploaded ? (

📎 Payment Confirmation

After transferring, please upload the receipt image so we can confirm faster.

{}
) : (

Payment confirmation sent

We will confirm your order as soon as possible.

)}
)} {}

⚠️ Important Notice:

  • Please bring your ID card when checking in
  • Check-in time: 14:00 / Check-out time: 12:00
  • If you cancel the booking, 20% of the total order value will be charged
  • {(booking.payment_method === 'cash' || (booking as any).payment_method === 'bank_transfer') && (
  • Please transfer within 24 hours to secure your room
  • )}
{}
View My Bookings Go to Home
); }; export default BookingSuccessPage;