phase 7 blockers
This commit is contained in:
@@ -778,6 +778,11 @@
|
||||
"total_payable_label": "Total to pay",
|
||||
"secure_gateway_notice": "Secure payment via bank gateway",
|
||||
"cta_pay": "Continue to payment",
|
||||
"gateway_title": "Redirecting to the payment gateway",
|
||||
"gateway_hint": "This is a demo page standing in for the bank gateway.",
|
||||
"gateway_reference_label": "Reference",
|
||||
"gateway_pay_success": "Pay (demo)",
|
||||
"gateway_pay_fail": "Cancel",
|
||||
"bnpl_option": "Or pay in installments",
|
||||
"state_initiating": "Starting payment…",
|
||||
"state_redirecting": "Redirecting to the payment gateway…",
|
||||
|
||||
@@ -778,6 +778,11 @@
|
||||
"total_payable_label": "مبلغ قابل پرداخت",
|
||||
"secure_gateway_notice": "پرداخت امن از طریق درگاه بانکی",
|
||||
"cta_pay": "ادامه پرداخت",
|
||||
"gateway_title": "در حال انتقال به درگاه پرداخت",
|
||||
"gateway_hint": "این صفحه نمایشی جایگزین درگاه بانکی است.",
|
||||
"gateway_reference_label": "کد مرجع",
|
||||
"gateway_pay_success": "پرداخت (نمایشی)",
|
||||
"gateway_pay_fail": "انصراف",
|
||||
"bnpl_option": "یا پرداخت اقساطی",
|
||||
"state_initiating": "در حال آغاز پرداخت…",
|
||||
"state_redirecting": "در حال انتقال به درگاه پرداخت…",
|
||||
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
'use client';
|
||||
import { Suspense } from 'react';
|
||||
import { useLocale, useTranslations } from 'next-intl';
|
||||
import { useRouter, useSearchParams } from 'next/navigation';
|
||||
import { Box, Stack, Typography } from '@mui/material';
|
||||
import { AppButton, AppLoading, PaymentStateCard } from '@/components';
|
||||
import { ROUTES } from '@/constants';
|
||||
import {
|
||||
CHECKOUT_QUERY_OUTCOME,
|
||||
CHECKOUT_QUERY_REQUEST_ID,
|
||||
CHECKOUT_QUERY_TRANSACTION_ID,
|
||||
} from '@/services/payment/constants';
|
||||
import type { GatewayReturnOutcome } from '@/services/payment/types';
|
||||
|
||||
/**
|
||||
* Mock-gateway harness — a **test harness, not a product feature**, mirroring the BNPL provider-handoff
|
||||
* harness (`checkout/bnpl/gateway/page.tsx`). It stands in for the PSP so the initiate → redirect → return
|
||||
* round-trip is exercisable without a real gateway: `MockPaymentProvider.InitPaymentAsync` points its
|
||||
* `redirectUrl` here, and the pay/cancel buttons drive both outcome branches of the return surface (a real
|
||||
* PSP redirects back after the cardholder pays or cancels). Deliberately reachable in every build, including
|
||||
* production — unlike the BNPL harness, this one is NOT env-gated: this deployment is a demo with no real
|
||||
* gateway wired up (`mvp/blockers.md` §B.5), so the mock stays reachable until a real acquirer is switched
|
||||
* on, at which point `redirectUrl` becomes the PSP's absolute URL and this page is never reached.
|
||||
*/
|
||||
export default function MockGatewayPage() {
|
||||
return (
|
||||
<Suspense fallback={<AppLoading />}>
|
||||
<MockGatewayScreen />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
function MockGatewayScreen() {
|
||||
const t = useTranslations('payment');
|
||||
const locale = useLocale();
|
||||
const router = useRouter();
|
||||
const params = useSearchParams();
|
||||
|
||||
const requestId = params.get(CHECKOUT_QUERY_REQUEST_ID) ?? '';
|
||||
const transactionId = params.get(CHECKOUT_QUERY_TRANSACTION_ID) ?? '';
|
||||
|
||||
const returnWith = (outcome: GatewayReturnOutcome) => {
|
||||
const query = new URLSearchParams({
|
||||
[CHECKOUT_QUERY_REQUEST_ID]: requestId,
|
||||
[CHECKOUT_QUERY_TRANSACTION_ID]: transactionId,
|
||||
[CHECKOUT_QUERY_OUTCOME]: outcome,
|
||||
});
|
||||
router.replace(`/${locale}${ROUTES.CHECKOUT_RETURN}?${query.toString()}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<PaymentStateCard icon="payment" tone="var(--bal-secondary)" title={t('gateway_title')} body={t('gateway_hint')}>
|
||||
{transactionId ? (
|
||||
<Typography variant="caption" sx={{ color: 'text.secondary' }}>
|
||||
{t('gateway_reference_label')}:{' '}
|
||||
<Box component="span" dir="ltr">
|
||||
#{transactionId}
|
||||
</Box>
|
||||
</Typography>
|
||||
) : null}
|
||||
<Stack sx={{ gap: 1.5, alignItems: 'center', width: '100%' }}>
|
||||
<AppButton color="secondary" variant="contained" size="large" onClick={() => returnWith('success')}>
|
||||
{t('gateway_pay_success')}
|
||||
</AppButton>
|
||||
<AppButton variant="text" color="error" onClick={() => returnWith('failure')}>
|
||||
{t('gateway_pay_fail')}
|
||||
</AppButton>
|
||||
</Stack>
|
||||
</PaymentStateCard>
|
||||
);
|
||||
}
|
||||
@@ -27,6 +27,8 @@ export const ROUTES = {
|
||||
BOOKING_REQUEST_STATUS: '/bookings/request',
|
||||
// Checkout (f9) — C6 summary & pay; the C5 accept CTA hands off here with `?request_id=`.
|
||||
CHECKOUT: '/bookings/checkout',
|
||||
// Mock-gateway harness (test-only stand-in for the PSP redirect; the mock initiate points here).
|
||||
CHECKOUT_GATEWAY: '/bookings/checkout/gateway',
|
||||
// Return-from-gateway surface — pending-callback poll → succeeded/failed states.
|
||||
CHECKOUT_RETURN: '/bookings/checkout/return',
|
||||
// Post-payment success screen — links to the booking detail + invoice.
|
||||
|
||||
Reference in New Issue
Block a user