diff --git a/src/features/payments/components/CStorePanel.tsx b/src/features/payments/components/CStorePanel.tsx
index e7d1b82..6cf254d 100644
--- a/src/features/payments/components/CStorePanel.tsx
+++ b/src/features/payments/components/CStorePanel.tsx
@@ -5,6 +5,8 @@ import React from 'react'
import { PaymentInstructions } from './PaymentInstructions'
import { postCharge } from '../../../services/api'
import { InlinePaymentStatus } from './InlinePaymentStatus'
+import { LoadingOverlay } from '../../../components/LoadingOverlay'
+import { mapErrorToUserMessage } from '../../../lib/errorMessages'
type StoreKey = 'alfamart' | 'indomaret'
@@ -36,7 +38,7 @@ export function CStorePanel({ orderId, amount, locked, onChargeInitiated, defaul
if (typeof res?.store === 'string') setStoreFromRes(res.store)
}
} catch (e) {
- if (!cancelled) toast.error(`Gagal membuat kode pembayaran: ${(e as Error).message}`)
+ if (!cancelled) toast.error(mapErrorToUserMessage(e))
} finally {
if (!cancelled) setBusy(false)
cstoreTasks.delete(chargeKey)
@@ -60,7 +62,7 @@ export function CStorePanel({ orderId, amount, locked, onChargeInitiated, defaul
if (typeof res?.store === 'string') setStoreFromRes(res.store)
}
} catch (e) {
- if (!cancelled) toast.error(`Gagal membuat kode pembayaran: ${(e as Error).message}`)
+ if (!cancelled) toast.error(mapErrorToUserMessage(e))
attemptedCStoreKeys.delete(chargeKey)
} finally {
if (!cancelled) setBusy(false)
@@ -78,53 +80,56 @@ export function CStorePanel({ orderId, amount, locked, onChargeInitiated, defaul
}
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}
- >
- )}
-
-
-
+ >
)
}
\ No newline at end of file
diff --git a/src/features/payments/components/GoPayPanel.tsx b/src/features/payments/components/GoPayPanel.tsx
index 680b572..55341ee 100644
--- a/src/features/payments/components/GoPayPanel.tsx
+++ b/src/features/payments/components/GoPayPanel.tsx
@@ -6,6 +6,8 @@ import { GoPayLogosRow } from './PaymentLogos'
import { postCharge } from '../../../services/api'
import { InlinePaymentStatus } from './InlinePaymentStatus'
import { toast } from '../../../components/ui/toast'
+import { LoadingOverlay } from '../../../components/LoadingOverlay'
+import { mapErrorToUserMessage } from '../../../lib/errorMessages'
// Global guards/tasks to stabilize QR generation across StrictMode remounts
const attemptedChargeKeys = new Set
()
@@ -52,101 +54,104 @@ export function GoPayPanel({ orderId, amount, locked, onChargeInitiated }: { ord
}
}
return (
-
-
-
GoPay / QRIS
-
-
-
Mode:
-
- setMode('gopay')}
- aria-pressed={mode === 'gopay'}
- className={`px-2 py-1 focus:outline-none focus-visible:ring-2 focus-visible:ring-[#2563EB] focus-visible:ring-offset-2 focus-visible:ring-offset-white transition ${mode === 'gopay' ? 'bg-black text-white' : 'bg-white text-black hover:bg-black/10'}`}
- >
- GoPay
-
- setMode('qris')}
- aria-pressed={mode === 'qris'}
- className={`px-2 py-1 focus:outline-none focus-visible:ring-2 focus-visible:ring-[#2563EB] focus-visible:ring-offset-2 focus-visible:ring-offset-white transition ${mode === 'qris' ? 'bg-black text-white' : 'bg-white text-black hover:bg-black/10'}`}
- >
- QRIS
-
-
-
-
-
Scan QR berikut menggunakan aplikasi {mode === 'gopay' ? 'GoPay' : 'QRIS'}
-
- {mode === 'qris' && (!qrUrl || busy) ? (
-
-
- Membuat QR…
-
- ) : qrUrl ? (
-

- ) : null}
-
-
Mode: {mode.toUpperCase()}
-
-
- Download QR
- Buka GoPay
-
-
-
+
+
+
-
- {locked && (
- Metode terkunci. Gunakan QR/deeplink untuk menyelesaikan pembayaran.
- )}
-
-
-
-
{ setBusy(true); onChargeInitiated?.(); setTimeout(() => { nav.toStatus(orderId, mode); setBusy(false) }, 250) }}
- >
- {busy ? (
-
+ GoPay / QRIS
+
+
+
Mode:
+
+ setMode('gopay')}
+ aria-pressed={mode === 'gopay'}
+ className={`px-2 py-1 focus:outline-none focus-visible:ring-2 focus-visible:ring-[#2563EB] focus-visible:ring-offset-2 focus-visible:ring-offset-white transition ${mode === 'gopay' ? 'bg-black text-white' : 'bg-white text-black hover:bg-black/10'}`}
+ >
+ GoPay
+
+ setMode('qris')}
+ aria-pressed={mode === 'qris'}
+ className={`px-2 py-1 focus:outline-none focus-visible:ring-2 focus-visible:ring-[#2563EB] focus-visible:ring-offset-2 focus-visible:ring-offset-white transition ${mode === 'qris' ? 'bg-black text-white' : 'bg-white text-black hover:bg-black/10'}`}
+ >
+ QRIS
+
+
+
+
+
Scan QR berikut menggunakan aplikasi {mode === 'gopay' ? 'GoPay' : 'QRIS'}
+
+ {mode === 'qris' && (!qrUrl || busy) ? (
+
- Menuju status…
+ Membuat QR…
- ) : 'Buka halaman status'}
-
+ ) : qrUrl ? (
+

+ ) : null}
+
+
Mode: {mode.toUpperCase()}
+
+
+ Download QR
+ Buka GoPay
+
+
+ {locked && (
+ Metode terkunci. Gunakan QR/deeplink untuk menyelesaikan pembayaran.
+ )}
+
+
+
+ { setBusy(true); onChargeInitiated?.(); setTimeout(() => { nav.toStatus(orderId, mode); setBusy(false) }, 250) }}
+ >
+ {busy ? (
+
+
+ Menuju status…
+
+ ) : 'Buka halaman status'}
+
+
-
+ >
)
}
@@ -175,7 +180,7 @@ export function GoPayPanel_AutoEffect({ orderId, amount, locked, mode, setBusy,
onChargeInitiated?.()
}
} catch (e) {
- if (!cancelled) toast.error(`Gagal membuat QR: ${(e as Error).message}`)
+ if (!cancelled) toast.error(mapErrorToUserMessage(e))
} finally {
if (!cancelled) {
setBusy(false)
@@ -204,7 +209,7 @@ export function GoPayPanel_AutoEffect({ orderId, amount, locked, mode, setBusy,
onChargeInitiated?.()
}
} catch (e) {
- if (!cancelled) toast.error(`Gagal membuat QR: ${(e as Error).message}`)
+ if (!cancelled) toast.error(mapErrorToUserMessage(e))
attemptedChargeKeys.delete(chargeKey)
} finally {
if (!cancelled) {