diff --git a/app/Http/Controllers/CheckoutController.php b/app/Http/Controllers/CheckoutController.php index 9c3372f..16d6123 100644 --- a/app/Http/Controllers/CheckoutController.php +++ b/app/Http/Controllers/CheckoutController.php @@ -449,6 +449,7 @@ class CheckoutController extends Controller 'transaction_id' => $transactionId, 'status' => $exception->status(), 'message' => $exception->getMessage(), + 'context' => $exception->context(), ]); return; diff --git a/resources/js/pages/marketing/checkout/steps/PaymentStep.tsx b/resources/js/pages/marketing/checkout/steps/PaymentStep.tsx index e1b9c88..c77f1e5 100644 --- a/resources/js/pages/marketing/checkout/steps/PaymentStep.tsx +++ b/resources/js/pages/marketing/checkout/steps/PaymentStep.tsx @@ -200,9 +200,12 @@ export const PaymentStep: React.FC = () => { const [freeActivationBusy, setFreeActivationBusy] = useState(false); const [awaitingConfirmation, setAwaitingConfirmation] = useState(false); const [confirmationElapsedMs, setConfirmationElapsedMs] = useState(0); + const [pendingConfirmation, setPendingConfirmation] = useState<{ + transactionId: string | null; + checkoutId: string | null; + } | null>(null); const confirmationTimerRef = useRef(null); const statusCheckRef = useRef<(() => void) | null>(null); - const confirmRequestRef = useRef(false); const paddleLocale = useMemo(() => { const sourceLocale = i18n.language || (typeof document !== 'undefined' ? document.documentElement.lang : null); @@ -211,15 +214,12 @@ export const PaymentStep: React.FC = () => { const isFree = useMemo(() => (selectedPackage ? Number(selectedPackage.price) <= 0 : false), [selectedPackage]); - const confirmCheckoutSession = useCallback(async (payload: Record) => { + const confirmCheckoutSession = useCallback(async (payload: { transactionId: string | null; checkoutId: string | null }) => { if (!checkoutSessionId) { return; } - const transactionId = typeof payload?.transaction_id === 'string' ? payload.transaction_id : null; - const checkoutId = typeof payload?.id === 'string' ? payload.id : null; - - if (!transactionId && !checkoutId) { + if (!payload.transactionId && !payload.checkoutId) { return; } @@ -229,8 +229,8 @@ export const PaymentStep: React.FC = () => { headers: buildCheckoutHeaders(), credentials: 'same-origin', body: JSON.stringify({ - transaction_id: transactionId, - checkout_id: checkoutId, + transaction_id: payload.transactionId, + checkout_id: payload.checkoutId, }), }); } catch (error) { @@ -544,15 +544,14 @@ export const PaymentStep: React.FC = () => { } if (event.name === 'checkout.completed') { + const transactionId = typeof event?.data?.transaction_id === 'string' ? event.data.transaction_id : null; + const checkoutId = typeof event?.data?.id === 'string' ? event.data.id : null; setStatus('processing'); setMessage(t('checkout.payment_step.processing_confirmation')); setInlineActive(false); setAwaitingConfirmation(true); setPaymentCompleted(false); - if (!confirmRequestRef.current) { - confirmRequestRef.current = true; - void confirmCheckoutSession(event.data as Record); - } + setPendingConfirmation({ transactionId, checkoutId }); toast.success(t('checkout.payment_step.toast_success')); } @@ -628,9 +627,18 @@ export const PaymentStep: React.FC = () => { setInlineActive(false); setAwaitingConfirmation(false); setConfirmationElapsedMs(0); - confirmRequestRef.current = false; + setPendingConfirmation(null); }, [selectedPackage?.id, setPaymentCompleted]); + useEffect(() => { + if (!pendingConfirmation || !checkoutSessionId) { + return; + } + + void confirmCheckoutSession(pendingConfirmation); + setPendingConfirmation(null); + }, [checkoutSessionId, confirmCheckoutSession, pendingConfirmation]); + useEffect(() => { if (!awaitingConfirmation || typeof window === 'undefined') { if (confirmationTimerRef.current) {