import { Button } from '../../../components/ui/button' import { usePaymentNavigation } from '../lib/navigation' import React from 'react' import { PaymentInstructions } from './PaymentInstructions' import { TrustStrip } from './TrustStrip' import { postCharge } from '../../../services/api' import { InlinePaymentStatus } from './InlinePaymentStatus' type StoreKey = 'alfamart' | 'indomaret' // Shared guards/tasks to prevent duplicate charges under StrictMode/HMR and double clicks const attemptedCStoreKeys = new Set() const cstoreTasks = new Map>() export function CStorePanel({ orderId, amount, locked, onChargeInitiated, defaultStore }: { orderId: string; amount: number; locked?: boolean; onChargeInitiated?: () => void; defaultStore?: StoreKey }) { const nav = usePaymentNavigation() const [selected] = React.useState(defaultStore ?? null) const [showGuide, setShowGuide] = React.useState(false) const [busy, setBusy] = React.useState(false) const [paymentCode, setPaymentCode] = React.useState('') const [storeFromRes, setStoreFromRes] = React.useState('') React.useEffect(() => { let cancelled = false async function run() { // Only auto-charge when a store is selected, not locked, and code not yet generated if (!selected || locked || paymentCode) return const chargeKey = `${orderId}:${selected}` // If there's already an in-flight task, await it if (attemptedCStoreKeys.has(chargeKey) && cstoreTasks.has(chargeKey)) { setBusy(true) try { const res = await cstoreTasks.get(chargeKey)! if (!cancelled) { if (typeof res?.payment_code === 'string') setPaymentCode(res.payment_code) if (typeof res?.store === 'string') setStoreFromRes(res.store) } } catch (e) { if (!cancelled) alert(`Gagal membuat kode pembayaran: ${(e as Error).message}`) } finally { if (!cancelled) setBusy(false) cstoreTasks.delete(chargeKey) } return } setBusy(true) onChargeInitiated?.() try { const payload: Record = { payment_type: 'cstore', transaction_details: { order_id: orderId, gross_amount: amount }, cstore: { store: selected, message: `Pembayaran untuk order ${orderId}` }, } attemptedCStoreKeys.add(chargeKey) const task = postCharge(payload) cstoreTasks.set(chargeKey, task) const res = await task if (!cancelled) { if (typeof res?.payment_code === 'string') setPaymentCode(res.payment_code) if (typeof res?.store === 'string') setStoreFromRes(res.store) } } catch (e) { if (!cancelled) alert(`Gagal membuat kode pembayaran: ${(e as Error).message}`) attemptedCStoreKeys.delete(chargeKey) } finally { if (!cancelled) setBusy(false) cstoreTasks.delete(chargeKey) } } run() return () => { cancelled = true } }, [selected, orderId, amount]) function copy(text: string, label: string) { if (!text) return navigator.clipboard?.writeText(text) alert(`${label} disalin: ${text}`) } return (
Convenience Store
{selected && (
Toko dipilih: {selected.toUpperCase()}
)} {showGuide && } {locked && (
Metode terkunci. Gunakan kode pembayaran di kasir {selected?.toUpperCase()}.
)}
Kode Pembayaran
{!selected && (
Pilih toko terlebih dahulu di langkah sebelumnya.
)} {selected && busy && (
Membuat kode…
)} {selected && !busy && (storeFromRes || paymentCode) && ( <> {storeFromRes ?
Toko: {storeFromRes.toUpperCase()}
: null} {paymentCode ?
Kode: {paymentCode}
: null} )}
) }