This commit is contained in:
Iliyan Angelov
2025-11-21 19:44:42 +02:00
parent 2a105c1170
commit 9842cc3a4a
24 changed files with 2801 additions and 2654 deletions

View File

@@ -33,6 +33,7 @@ import { confirmBankTransfer } from
import Loading from '../../components/common/Loading';
import { useFormatCurrency } from '../../hooks/useFormatCurrency';
import { parseDateLocal } from '../../utils/format';
import DepositPaymentModal from '../../components/payments/DepositPaymentModal';
const BookingSuccessPage: React.FC = () => {
const { id } = useParams<{ id: string }>();
@@ -54,6 +55,7 @@ const BookingSuccessPage: React.FC = () => {
useState<File | null>(null);
const [previewUrl, setPreviewUrl] =
useState<string | null>(null);
const [showDepositModal, setShowDepositModal] = useState(false);
useEffect(() => {
if (id) {
@@ -91,12 +93,13 @@ const BookingSuccessPage: React.FC = () => {
}
// Only auto-open deposit modal if booking is not cancelled
if (
bookingData.requires_deposit &&
!bookingData.deposit_paid
!bookingData.deposit_paid &&
bookingData.status !== 'cancelled'
) {
navigate(`/deposit-payment/${bookingId}`, { replace: true });
return;
setShowDepositModal(true);
}
} else {
throw new Error(
@@ -301,6 +304,51 @@ const BookingSuccessPage: React.FC = () => {
const room = booking.room;
const roomType = room?.room_type;
// Check if payment is completed
const isPaymentCompleted = (() => {
// Check if booking is cancelled
if (booking.status === 'cancelled') {
return false;
}
// Check payment_status
if (booking.payment_status === 'paid') {
return true;
}
// Check payment_balance
if (booking.payment_balance?.is_fully_paid === true) {
return true;
}
// For deposit bookings, check if deposit is paid
if (booking.requires_deposit && booking.deposit_paid === true) {
return true;
}
// Check payments array
if (booking.payments && Array.isArray(booking.payments)) {
const totalPaid = booking.payments
.filter((p: any) => p.payment_status === 'completed')
.reduce((sum: number, p: any) => sum + parseFloat(p.amount?.toString() || '0'), 0);
// For deposit bookings, check if deposit is paid
if (booking.requires_deposit) {
const depositPayment = booking.payments.find((p: any) => p.payment_type === 'deposit' && p.payment_status === 'completed');
if (depositPayment) {
return true;
}
} else {
// For full payment bookings, check if fully paid
return totalPaid >= booking.total_price - 0.01;
}
}
return false;
})();
const isCancelled = booking.status === 'cancelled';
return (
<div className="min-h-screen bg-gray-50 py-8">
<div className="max-w-4xl mx-auto px-4">
@@ -309,24 +357,70 @@ const BookingSuccessPage: React.FC = () => {
className="bg-white rounded-lg shadow-md
p-8 mb-6 text-center"
>
<div
className="w-20 h-20 bg-green-100
rounded-full flex items-center
justify-center mx-auto mb-4"
>
<CheckCircle
className="w-12 h-12 text-green-600"
/>
</div>
<h1
className="text-3xl font-bold text-gray-900
mb-2"
>
Booking Successful!
</h1>
<p className="text-gray-600 mb-4">
Thank you for booking with our hotel
</p>
{isCancelled ? (
<>
<div
className="w-20 h-20 bg-red-100
rounded-full flex items-center
justify-center mx-auto mb-4"
>
<AlertCircle
className="w-12 h-12 text-red-600"
/>
</div>
<h1
className="text-3xl font-bold text-gray-900
mb-2"
>
Booking Cancelled
</h1>
<p className="text-gray-600 mb-4">
This booking has been cancelled
</p>
</>
) : isPaymentCompleted ? (
<>
<div
className="w-20 h-20 bg-green-100
rounded-full flex items-center
justify-center mx-auto mb-4"
>
<CheckCircle
className="w-12 h-12 text-green-600"
/>
</div>
<h1
className="text-3xl font-bold text-gray-900
mb-2"
>
Booking Successful!
</h1>
<p className="text-gray-600 mb-4">
Thank you for booking with our hotel
</p>
</>
) : (
<>
<div
className="w-20 h-20 bg-yellow-100
rounded-full flex items-center
justify-center mx-auto mb-4"
>
<AlertCircle
className="w-12 h-12 text-yellow-600"
/>
</div>
<h1
className="text-3xl font-bold text-gray-900
mb-2"
>
Booking Pending Payment
</h1>
<p className="text-gray-600 mb-4">
Please complete your payment to confirm your booking
</p>
</>
)}
{}
<div
@@ -681,19 +775,25 @@ const BookingSuccessPage: React.FC = () => {
<input
id="receipt-upload"
type="file"
accept="image}
accept="image/*"
onChange={(e) => {
const file = e.target.files?.[0];
if (file) {
setSelectedFile(file);
}
}}
className="hidden"
/>
<span className="text-sm text-gray-600">
Click to upload receipt
</span>
</label>
</div>
{selectedFile && (
<button
onClick={handleUploadReceipt}
disabled={uploadingReceipt}
className="w-full px-4 py-3
bg-blue-600 text-white
rounded-lg hover:bg-blue-700
transition-colors font-semibold
disabled:bg-gray-400
disabled:cursor-not-allowed
flex items-center
justify-center gap-2"
className="w-full px-4 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-semibold disabled:bg-gray-400 disabled:cursor-not-allowed flex items-center justify-center gap-2"
>
{uploadingReceipt ? (
<>
@@ -800,6 +900,21 @@ const BookingSuccessPage: React.FC = () => {
</Link>
</div>
</div>
{/* Deposit Payment Modal */}
{showDepositModal && id && (
<DepositPaymentModal
isOpen={showDepositModal}
bookingId={Number(id)}
onClose={() => setShowDepositModal(false)}
onSuccess={() => {
setShowDepositModal(false);
if (id) {
fetchBookingDetails(Number(id));
}
}}
/>
)}
</div>
);
};