From e9016d507d4c69bfa323edc8334c61d0e727fb4e Mon Sep 17 00:00:00 2001 From: CIFO Dev Date: Thu, 4 Dec 2025 16:47:31 +0700 Subject: [PATCH] UX FIX --- .../payments/components/PaymentSheet.tsx | 30 ++-- src/features/payments/lib/midtrans.ts | 1 + src/pages/CheckoutPage.tsx | 21 +++ src/pages/PayPage.tsx | 11 ++ src/pages/PaymentStatusPage.tsx | 165 ++++++++++++------ tmp-createtransaksi.json | 10 +- 6 files changed, 160 insertions(+), 78 deletions(-) diff --git a/src/features/payments/components/PaymentSheet.tsx b/src/features/payments/components/PaymentSheet.tsx index e7eec97..c560201 100644 --- a/src/features/payments/components/PaymentSheet.tsx +++ b/src/features/payments/components/PaymentSheet.tsx @@ -44,26 +44,16 @@ export function PaymentSheet({ merchantName = 'Simaya', orderId, amount, expireA
{merchantName}
-
-
- Kedaluwarsa dalam {countdown} -
- -
+ {expanded && ( diff --git a/src/features/payments/lib/midtrans.ts b/src/features/payments/lib/midtrans.ts index 246f69a..391835f 100644 --- a/src/features/payments/lib/midtrans.ts +++ b/src/features/payments/lib/midtrans.ts @@ -68,6 +68,7 @@ export interface PaymentStatusResponse { // Common transactionTime?: string grossAmount?: string + customerName?: string // From localStorage, not from Midtrans API // Bank transfer vaNumber?: string bank?: string diff --git a/src/pages/CheckoutPage.tsx b/src/pages/CheckoutPage.tsx index cb55340..ae67b46 100644 --- a/src/pages/CheckoutPage.tsx +++ b/src/pages/CheckoutPage.tsx @@ -72,6 +72,17 @@ function AutoSnapPayment({ orderId, amount, customer, onSuccess, onError, onModa Logger.paymentInfo('checkout.auto.snap.token.received', { orderId, token: token.substring(0, 10) + '...' }) console.log('Token berhasil dibuat:', token) + // Store customer name in localStorage for status page + if (customer?.name) { + try { + const customerCache = JSON.parse(localStorage.getItem('customerCache') || '{}') + customerCache[orderId] = { name: customer.name, timestamp: Date.now() } + localStorage.setItem('customerCache', JSON.stringify(customerCache)) + } catch (e) { + console.warn('Failed to cache customer name:', e) + } + } + // Verify Snap.js is loaded console.log('window.snap:', window.snap) console.log('window.snap.pay:', window.snap?.pay) @@ -105,6 +116,7 @@ function AutoSnapPayment({ orderId, amount, customer, onSuccess, onError, onModa }, onClose: () => { Logger.paymentInfo('checkout.auto.snap.popup.closed', { orderId }) + console.log('🔵 Snap modal closed - calling onModalClosed') setLoading(false) onModalClosed?.() // Enable status button when modal closed } @@ -128,6 +140,7 @@ function AutoSnapPayment({ orderId, amount, customer, onSuccess, onError, onModa } onError?.(e) + onModalClosed?.() // Enable status button on error setLoading(false) } } @@ -315,6 +328,13 @@ export function CheckoutPage() { {(() => { console.log('Rendering step 2 - AutoSnapPayment', { orderId, amount, currentStep }) Logger.info('checkout.step2.render', { orderId, amount }) + // Fallback: Force show status button after 3 seconds if callback not called + setTimeout(() => { + if (!modalClosed) { + console.log('⚠️ Fallback timer: Forcing status button to show') + setModalClosed(true) + } + }, 3000) return null })()} { + console.log('🟢 onModalClosed callback fired - setting modalClosed to TRUE') setModalClosed(true) // Enable status button when modal closed }} /> diff --git a/src/pages/PayPage.tsx b/src/pages/PayPage.tsx index 9989a39..ff175a3 100644 --- a/src/pages/PayPage.tsx +++ b/src/pages/PayPage.tsx @@ -73,6 +73,17 @@ function AutoSnapPayment({ orderId, amount, customer, onSuccess, onError }: Auto Logger.paymentInfo('paypage.auto.snap.token.received', { orderId, token: token.substring(0, 10) + '...' }) console.log('[PayPage] Token received:', token) + // Store customer name in localStorage for status page + if (customer?.name) { + try { + const customerCache = JSON.parse(localStorage.getItem('customerCache') || '{}') + customerCache[orderId] = { name: customer.name, timestamp: Date.now() } + localStorage.setItem('customerCache', JSON.stringify(customerCache)) + } catch (e) { + console.warn('Failed to cache customer name:', e) + } + } + if (!window.snap || typeof window.snap.pay !== 'function') { throw new Error(`Snap.js not loaded: hasSnap=${!!window.snap}`) } diff --git a/src/pages/PaymentStatusPage.tsx b/src/pages/PaymentStatusPage.tsx index c36d467..0aa146b 100644 --- a/src/pages/PaymentStatusPage.tsx +++ b/src/pages/PaymentStatusPage.tsx @@ -1,14 +1,11 @@ import React from 'react' import { useParams, useSearchParams } from 'react-router-dom' -import { usePaymentNavigation } from '../features/payments/lib/navigation' import { usePaymentStatus } from '../features/payments/lib/usePaymentStatus' import type { PaymentStatusResponse } from '../features/payments/lib/midtrans' import { Logger } from '../lib/logger' -import { CountdownRedirect } from '../components/CountdownRedirect' export function PaymentStatusPage() { const { orderId } = useParams() - const nav = usePaymentNavigation() const [search] = useSearchParams() const method = (search.get('m') ?? undefined) as ('bank_transfer' | 'gopay' | 'qris' | 'cstore' | 'credit_card' | undefined) const { data, isLoading, error } = usePaymentStatus(orderId) @@ -63,9 +60,15 @@ export function PaymentStatusPage() { const [qrSrc, setQrSrc] = React.useState('') React.useEffect(() => { setQrSrc(qrCandidates[0] || '') }, [statusText, method, orderId, data, qrCandidates]) - function handleRedirect() { - nav.toHistory() - } + // Get customer name from localStorage + const customerName = React.useMemo(() => { + try { + const customerCache = JSON.parse(localStorage.getItem('customerCache') || '{}') + return customerCache[orderId || '']?.name + } catch { + return undefined + } + }, [orderId]) // Logs for debugging status lifecycle React.useEffect(() => { @@ -155,6 +158,13 @@ export function PaymentStatusPage() { )} + {customerName ? ( +
+
Nama Pelanggan
+
{customerName}
+
+ ) : null} + {method || data?.method ? (
Metode Pembayaran
@@ -164,18 +174,6 @@ export function PaymentStatusPage() {
- {isSuccess ? ( -
-
-
🎉
-
-
Transaksi Selesai!
-
Anda akan diarahkan ke halaman utama dalam beberapa detik
- -
-
-
- ) : null} {/* Payment Instructions - Only show for pending status */} {!isLoading && !error && data && statusText === 'pending' ? (
@@ -183,43 +181,85 @@ export function PaymentStatusPage() {
📝 Cara Pembayaran
- {(!method || method === 'bank_transfer') && data.vaNumber ? ( + {/* Bank Transfer OR Mandiri E-Channel */} + {(!method || method === 'bank_transfer' || data.method === 'bank_transfer' || data.method === 'echannel') && (data.vaNumber || (data.billKey && data.billerCode)) ? ( <> -
-
Nomor Virtual Account
-
-
{data.vaNumber}
- -
- {data.bank ? ( -
-
Bank
-
{data.bank}
+ {data.vaNumber ? ( +
+
Nomor Virtual Account
+
+
{data.vaNumber}
+
- ) : null} -
-
-

Langkah pembayaran:

-
    -
  1. Buka aplikasi mobile banking atau ATM
  2. -
  3. Pilih menu Transfer / Bayar
  4. -
  5. Masukkan nomor Virtual Account di atas
  6. -
  7. Konfirmasi pembayaran
  8. -
  9. Simpan bukti transaksi
  10. -
-
- {data.billKey && data.billerCode ? ( -
-
Khusus Mandiri E-Channel:
-
Kode Biller: {data.billerCode}
-
Kode Bayar: {data.billKey}
+ {data.bank ? ( +
+
Bank
+
{data.bank}
+
+ ) : null}
) : null} + + {/* Mandiri E-Channel specific */} + {data.billKey && data.billerCode ? ( +
+
💳 Mandiri E-Channel
+
+
+
Kode Perusahaan (Biller Code)
+
+
{data.billerCode}
+ +
+
+
+
Kode Bayar (Bill Key)
+
+
{data.billKey}
+ +
+
+
+
+ ) : null} + +
+

Langkah pembayaran:

+ {data.billKey && data.billerCode ? ( +
    +
  1. Buka aplikasi Livin' by Mandiri atau ATM Mandiri
  2. +
  3. Pilih menu Bayar / Multi Payment
  4. +
  5. Pilih penyedia jasa: Midtrans (atau cari dengan Biller Code)
  6. +
  7. Masukkan Kode Perusahaan: {data.billerCode}
  8. +
  9. Masukkan Kode Bayar: {data.billKey}
  10. +
  11. Periksa detail tagihan dan konfirmasi pembayaran
  12. +
  13. Simpan bukti transaksi
  14. +
+ ) : ( +
    +
  1. Buka aplikasi mobile banking atau ATM
  2. +
  3. Pilih menu Transfer / Bayar
  4. +
  5. Masukkan nomor Virtual Account di atas
  6. +
  7. Konfirmasi pembayaran
  8. +
  9. Simpan bukti transaksi
  10. +
+ )} +
) : null} {(!method || method === 'cstore') && (data.store || data.paymentCode) ? ( @@ -257,7 +297,7 @@ export function PaymentStatusPage() {
) : null} - {(!method || method === 'gopay' || method === 'qris') && (qrSrc || (Array.isArray(data?.actions) && data.actions.length > 0)) ? ( + {(!method || method === 'gopay' || method === 'qris' || data.method === 'qris' || data.method === 'gopay') && (qrSrc || (Array.isArray(data?.actions) && data.actions.length > 0)) ? ( <> {qrSrc ? (
@@ -273,7 +313,7 @@ export function PaymentStatusPage() {

Langkah pembayaran:

    -
  1. Buka aplikasi {method === 'gopay' ? 'GoPay/Gojek' : 'e-wallet atau m-banking'}
  2. +
  3. Buka aplikasi {method === 'gopay' || data.method === 'gopay' ? 'GoPay/Gojek' : 'e-wallet atau m-banking yang mendukung QRIS'}
  4. Pilih menu Scan QR atau QRIS
  5. Arahkan kamera ke QR code di atas
  6. Konfirmasi pembayaran
  7. @@ -295,6 +335,25 @@ export function PaymentStatusPage() {
) : null} + ) : (data.method === 'qris' || data.method === 'gopay') ? ( +
+
+
📱
+
+
QR Code Pembayaran
+
+

QR code untuk pembayaran ini ditampilkan di jendela pembayaran Snap.

+

Jika Anda menutup jendela tersebut, silakan:

+
    +
  1. Kembali ke halaman checkout
  2. +
  3. Buat pembayaran baru dengan order ID yang sama
  4. +
  5. QR code akan muncul kembali di jendela Snap
  6. +
+

Atau tunggu hingga pembayaran kedaluwarsa dan buat transaksi baru.

+
+
+
+
) : null} {(!method || method === 'credit_card') && data.maskedCard ? (
diff --git a/tmp-createtransaksi.json b/tmp-createtransaksi.json index cde8748..09f1567 100644 --- a/tmp-createtransaksi.json +++ b/tmp-createtransaksi.json @@ -1,12 +1,12 @@ { - "mercant_id": "REFNO-003", + "mercant_id": "REFNO-004", "timestamp": 1733331600000, "deskripsi": "Bayar Internet", "nominal": 250000, - "nama": "Test User 3", - "no_telepon": "081234567891", - "email": "test3@example.com", + "nama": "Test User 4", + "no_telepon": "081234567892", + "email": "test4@example.com", "item": [ - { "item_id": "TKG-2512042", "nama": "Internet Desember Premium", "harga": 250000, "qty": 1 } + { "item_id": "TKG-2512043", "nama": "Internet Desember Premium", "harga": 250000, "qty": 1 } ] }