From b4f90a7d46d67fe04b68886650695cda0e1c74c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Afra=20=E2=80=8C?= Date: Sun, 28 Jun 2026 16:38:27 +0330 Subject: [PATCH] feat: fail fallback on reservation flow added --- src/components/PaymentFailModal.tsx | 30 ++++++++++ src/pages/PaymentSuccess.tsx | 85 +++++++++++++++-------------- 2 files changed, 73 insertions(+), 42 deletions(-) create mode 100644 src/components/PaymentFailModal.tsx diff --git a/src/components/PaymentFailModal.tsx b/src/components/PaymentFailModal.tsx new file mode 100644 index 0000000..7cbd0bf --- /dev/null +++ b/src/components/PaymentFailModal.tsx @@ -0,0 +1,30 @@ +import { createPortal } from 'react-dom' +import FailIcon from './FailIcon' + +interface PaymentFailModalProps { + onGoHome: () => void +} + +// covers both a gateway-reported payment failure and a payment that succeeded but +// whose reservation couldn't be created — same message, same recovery action either way +export default function PaymentFailModal({ onGoHome }: PaymentFailModalProps) { + return createPortal( + <> +
+
+
+ +

رزرو با خطا مواجه شد. لطفا دوباره تلاش کنید.

+ +
+
+ , + document.body, + ) +} diff --git a/src/pages/PaymentSuccess.tsx b/src/pages/PaymentSuccess.tsx index dd415c9..001ffb5 100644 --- a/src/pages/PaymentSuccess.tsx +++ b/src/pages/PaymentSuccess.tsx @@ -1,7 +1,7 @@ import { useEffect, useState } from 'react' import { useNavigate, useSearchParams } from 'react-router-dom' -import FailIcon from '../components/FailIcon' import InfoIcon from '../components/InfoIcon' +import PaymentFailModal from '../components/PaymentFailModal' import SuccessIcon from '../components/SuccessIcon' import { createReservation, ReservationResult } from '../services/campaignApi' import { formatPersianNumber } from '../utils/formatNumber' @@ -26,62 +26,63 @@ export default function PaymentSuccess() { const [searchParams] = useSearchParams() const isSuccess = searchParams.get('state') === SUCCESS_STATE const [reservation, setReservation] = useState(null) - const [error, setError] = useState('') - // gateway-reported failure, or a successful payment whose reservation couldn't be created - const isFail = !isSuccess || !!error + const [hasError, setHasError] = useState(false) + // gateway-reported failure, or a successful payment whose reservation couldn't be created — + // both land on the same fail modal + const isFail = !isSuccess || hasError useEffect(() => { if (!isSuccess) return const pending = takePendingReservation() if (!pending) { - Promise.resolve().then(() => setError('اطلاعات رزرو یافت نشد.')) + Promise.resolve().then(() => setHasError(true)) return } createReservation(pending) .then(setReservation) - .catch(() => setError('ثبت رزرو با خطا مواجه شد.')) + .catch(() => setHasError(true)) }, [isSuccess]) return ( -
-
- {isFail ? : } +
+ {!isFail && ( +
+
+ - {isSuccess ? ( - reservation ? ( - <> -

جزئیات رزرو

-
- - - - -
+ {reservation ? ( + <> +

جزئیات رزرو

+
+ + + + +
-
- -

- کد رزرو را برای ورود نزد خود نگه دارید. اطلاعات رزرو و کد ورود تا دقایقی دیگر برای شما پیامک می‌شود. -

-
- - ) : error ? ( -

{error}

- ) : ( -

در حال ثبت رزرو...

- ) - ) : ( -

پرداخت ناموفق بود. لطفاً دوباره تلاش کنید.

- )} +
+ +

+ کد رزرو را برای ورود نزد خود نگه دارید. اطلاعات رزرو و کد ورود تا دقایقی دیگر برای شما پیامک می‌شود. +

+
+ + ) : ( +

در حال ثبت رزرو...

+ )} - -
+ +
+
+ )} + + {isFail && navigate('/home')} />}
) }