import { Alert } from '../components/alert/Alert' import { Button } from '../components/ui/button' import { Env } from '../lib/env' import { PaymentSheet } from '../features/payments/components/PaymentSheet' import { PaymentMethodList } from '../features/payments/components/PaymentMethodList' import type { PaymentMethod } from '../features/payments/components/PaymentMethodList' import { BankTransferPanel } from '../features/payments/components/BankTransferPanel' import { CardPanel } from '../features/payments/components/CardPanel' import { GoPayPanel } from '../features/payments/components/GoPayPanel' import { CStorePanel } from '../features/payments/components/CStorePanel' import { BankLogo, type BankKey, LogoAlfamart, LogoIndomaret } from '../features/payments/components/PaymentLogos' import { usePaymentConfig } from '../features/payments/lib/usePaymentConfig' import { Logger } from '../lib/logger' import React from 'react' export function CheckoutPage() { const apiBase = Env.API_BASE_URL const clientKey = Env.MIDTRANS_CLIENT_KEY const { data: runtimeCfg } = usePaymentConfig() // Generate unique order id per checkout session to avoid Midtrans 406 conflicts const orderIdRef = React.useRef('') if (!orderIdRef.current) { const ts = Date.now() const rand = Math.floor(Math.random() * 100000).toString().padStart(5, '0') orderIdRef.current = `order-${ts}-${rand}` } const orderId = orderIdRef.current const amount = 3500000 const expireAt = Date.now() + 59 * 60 * 1000 + 32 * 1000 // 00:59:32 const [selected, setSelected] = React.useState(null) const [locked, setLocked] = React.useState(false) const [currentStep, setCurrentStep] = React.useState<1 | 2 | 3>(1) const [isBusy, setIsBusy] = React.useState(false) const [selectedBank, setSelectedBank] = React.useState<'bca' | 'bni' | 'bri' | 'cimb' | 'mandiri' | 'permata' | null>(null) const [selectedStore, setSelectedStore] = React.useState<'alfamart' | 'indomaret' | null>(null) const [form, setForm] = React.useState<{ name: string; contact: string; address: string; notes: string }>({ name: 'Demo User', contact: 'demo@example.com', address: 'Jl. Contoh No. 1', notes: '', }) const configMissing = !clientKey || !apiBase React.useEffect(() => { Logger.info('checkout.init', { apiBase, hasClientKey: !!clientKey }) }, []) React.useEffect(() => { if (runtimeCfg) { Logger.info('runtime.config.applied', runtimeCfg.paymentToggles) } }, [runtimeCfg]) React.useEffect(() => { if (selected) Logger.info('checkout.method.selected', { method: selected }) }, [selected]) const prevStep = React.useRef(currentStep) React.useEffect(() => { if (prevStep.current !== currentStep) { Logger.info('checkout.step', { from: prevStep.current, to: currentStep }) prevStep.current = currentStep } }, [currentStep]) return (
{configMissing && ( Set VITE_MIDTRANS_CLIENT_KEY untuk tokenisasi kartu dan VITE_API_BASE_URL ke server backend (contoh: http://localhost:8000). Tanpa API base, pembayaran tidak dapat diproses. )} {/* Wizard 3 langkah: Step 1 (Form Dummy) → Step 2 (Pilih Metode) → Step 3 (Panel Metode) */} {currentStep === 1 && (
Konfirmasi data checkout