"use client"; import { useCheckout } from "@/features/checkout/hooks/useCheckout"; import { PageLayout } from "@/components/templates/PageLayout"; import { SubCard } from "@/components/molecules/SubCard/SubCard"; import { Button } from "@/components/atoms/button"; import { AlertBanner } from "@/components/molecules/AlertBanner/AlertBanner"; import { PageAsync } from "@/components/molecules/AsyncBlock/AsyncBlock"; import { InlineToast } from "@/components/atoms/inline-toast"; import { StatusPill } from "@/components/atoms/status-pill"; import { AddressConfirmation } from "@/features/catalog/components/base/AddressConfirmation"; import { isLoading, isError, isSuccess } from "@customer-portal/domain/toolkit"; import { ShieldCheckIcon, CreditCardIcon } from "@heroicons/react/24/outline"; import type { PaymentMethod } from "@customer-portal/domain/payments"; export function CheckoutContainer() { const { checkoutState, submitting, orderType, addressConfirmed, paymentMethods, paymentMethodsLoading, paymentMethodsError, paymentRefresh, confirmAddress, markAddressIncomplete, handleSubmitOrder, navigateBackToConfigure, activeInternetWarning, } = useCheckout(); if (isLoading(checkoutState)) { return ( } > <> ); } if (isError(checkoutState)) { return ( } >
{checkoutState.error.message}
); } if (!isSuccess(checkoutState)) { return ( } >
Checkout data is not available
); } const { items, totals } = checkoutState.data; const paymentMethodList = paymentMethods?.paymentMethods ?? []; const defaultPaymentMethod = paymentMethodList.find(method => method.isDefault) ?? paymentMethodList[0] ?? null; const paymentMethodDisplay = defaultPaymentMethod ? buildPaymentMethodDisplay(defaultPaymentMethod) : null; return ( } >
{activeInternetWarning && ( {activeInternetWarning} )}

Confirm Details

} right={ paymentMethods && paymentMethods.paymentMethods.length > 0 ? ( ) : undefined } > {paymentMethodsLoading ? (
Checking payment methods...
) : paymentMethodsError ? (
) : paymentMethodList.length > 0 ? (
{paymentMethodDisplay ? (

Default payment method

{paymentMethodDisplay.title}

{paymentMethodDisplay.subtitle ? (

{paymentMethodDisplay.subtitle}

) : null}
) : null}

We securely charge your saved payment method after the order is approved. Need to make changes? Visit Billing & Payments.

) : (
)}

Review & Submit

You’re almost done. Confirm your details above, then submit your order. We’ll review and notify you when everything is ready.

What to expect

• Our team reviews your order and schedules setup if needed

• We may contact you to confirm details or availability

• We only charge your card after the order is approved

• You’ll receive confirmation and next steps by email

Estimated Total
¥{totals.monthlyTotal.toLocaleString()}/mo
{totals.oneTimeTotal > 0 && (
+ ¥{totals.oneTimeTotal.toLocaleString()} one-time
)}
); } function buildPaymentMethodDisplay(method: PaymentMethod): { title: string; subtitle?: string } { const descriptor = method.cardType?.trim() || method.bankName?.trim() || method.description?.trim() || method.gatewayName?.trim() || "Saved payment method"; const trimmedLastFour = typeof method.cardLastFour === "string" && method.cardLastFour.trim().length > 0 ? method.cardLastFour.trim().slice(-4) : null; const headline = trimmedLastFour && method.type?.toLowerCase().includes("card") ? `${descriptor} · •••• ${trimmedLastFour}` : descriptor; const details = new Set(); if (method.bankName && !headline.toLowerCase().includes(method.bankName.trim().toLowerCase())) { details.add(method.bankName.trim()); } const expiry = normalizeExpiryLabel(method.expiryDate); if (expiry) { details.add(`Exp ${expiry}`); } if (!trimmedLastFour && method.cardLastFour && method.cardLastFour.trim().length > 0) { details.add(`Ends ${method.cardLastFour.trim().slice(-4)}`); } if (method.type?.toLowerCase().includes("bank") && method.description?.trim()) { details.add(method.description.trim()); } const subtitle = details.size > 0 ? Array.from(details).join(" · ") : undefined; return { title: headline, subtitle }; } function normalizeExpiryLabel(expiry?: string | null): string | null { if (!expiry) return null; const value = expiry.trim(); if (!value) return null; if (/^\d{4}-\d{2}$/.test(value)) { const [year, month] = value.split("-"); return `${month}/${year.slice(-2)}`; } if (/^\d{2}\/\d{4}$/.test(value)) { const [month, year] = value.split("/"); return `${month}/${year.slice(-2)}`; } if (/^\d{2}\/\d{2}$/.test(value)) { return value; } const digits = value.replace(/\D/g, ""); if (digits.length === 6) { const year = digits.slice(2, 4); const month = digits.slice(4, 6); return `${month}/${year}`; } if (digits.length === 4) { const month = digits.slice(0, 2); const year = digits.slice(2, 4); return `${month}/${year}`; } return value; } export default CheckoutContainer;