diff --git a/src/pages/CheckoutPage.tsx b/src/pages/CheckoutPage.tsx
index 1b4178f..8788a23 100644
--- a/src/pages/CheckoutPage.tsx
+++ b/src/pages/CheckoutPage.tsx
@@ -9,6 +9,118 @@ import { usePaymentConfig } from '../features/payments/lib/usePaymentConfig'
import { Logger } from '../lib/logger'
import React from 'react'
+interface AutoSnapPaymentProps {
+ orderId: string
+ amount: number
+ customer?: { name?: string; phone?: string; email?: string }
+ onChargeInitiated?: () => void
+ onSuccess?: (result: any) => void
+ onError?: (error: any) => void
+}
+
+function AutoSnapPayment({ orderId, amount, customer, onChargeInitiated, onSuccess, onError }: AutoSnapPaymentProps) {
+ const [loading, setLoading] = React.useState(false)
+ const [error, setError] = React.useState('')
+ const hasTriggered = React.useRef(false)
+
+ React.useEffect(() => {
+ if (hasTriggered.current) return
+ hasTriggered.current = true
+
+ const triggerPayment = async () => {
+ try {
+ setLoading(true)
+ setError('')
+
+ Logger.paymentInfo('checkout.auto.snap.init', { orderId, amount, customer })
+
+ // Import SnapTokenService dynamically to avoid circular deps
+ const { SnapTokenService } = await import('../features/payments/snap/SnapTokenService')
+
+ // Create Snap transaction token
+ const token = await SnapTokenService.createToken({
+ transaction_details: {
+ order_id: orderId,
+ gross_amount: amount
+ },
+ customer_details: customer ? {
+ first_name: customer.name,
+ email: customer.email,
+ phone: customer.phone
+ } : undefined,
+ item_details: [{
+ id: orderId,
+ name: 'Payment',
+ price: amount,
+ quantity: 1
+ }]
+ })
+
+ Logger.paymentInfo('checkout.auto.snap.token.received', { orderId, token: token.substring(0, 10) + '...' })
+
+ // Auto-trigger Snap payment popup
+ if (window.snap && typeof window.snap.pay === 'function') {
+ window.snap.pay(token, {
+ onSuccess: (result: any) => {
+ Logger.paymentInfo('checkout.auto.snap.payment.success', { orderId, transactionId: result.transaction_id })
+ onSuccess?.(result)
+ },
+ onPending: (result: any) => {
+ Logger.paymentInfo('checkout.auto.snap.payment.pending', { orderId, transactionId: result.transaction_id })
+ },
+ onError: (result: any) => {
+ Logger.paymentError('checkout.auto.snap.payment.error', { orderId, error: result })
+ const message = 'Pembayaran gagal. Silakan coba lagi.'
+ setError(message)
+ onError?.(result)
+ },
+ onClose: () => {
+ Logger.paymentInfo('checkout.auto.snap.popup.closed', { orderId })
+ }
+ })
+ } else {
+ throw new Error('Snap.js not loaded')
+ }
+
+ } catch (e: any) {
+ Logger.paymentError('checkout.auto.snap.payment.error', { orderId, error: e.message })
+ const message = 'Gagal memuat pembayaran. Silakan refresh halaman.'
+ setError(message)
+ onError?.(e)
+ } finally {
+ setLoading(false)
+ }
+ }
+
+ // Small delay to ensure UI is rendered
+ const timer = setTimeout(triggerPayment, 500)
+ return () => clearTimeout(timer)
+ }, [orderId, amount, customer, onChargeInitiated, onSuccess, onError])
+
+ return (
+
+ {error && (
+
+ {error}
+
+ )}
+
+
+ {loading ? (
+
+
+
Menyiapkan pembayaran...
+
+ ) : (
+
+ Membuka halaman pembayaran Midtrans...
+
+ )}
+
+
+ )
+}
+
export function CheckoutPage() {
const apiBase = Env.API_BASE_URL
const clientKey = Env.MIDTRANS_CLIENT_KEY
@@ -132,7 +244,7 @@ export function CheckoutPage() {
{currentStep === 2 && (
-
setLocked(true)}
onSuccess={(result) => {
Logger.info('checkout.payment.success', { orderId, result })
diff --git a/src/pages/PayPage.tsx b/src/pages/PayPage.tsx
index ca64f8e..09c6f00 100644
--- a/src/pages/PayPage.tsx
+++ b/src/pages/PayPage.tsx
@@ -2,16 +2,128 @@ import { useEffect, useMemo, useState } from 'react'
import { useParams } from 'react-router-dom'
import { PaymentSheet } from '../features/payments/components/PaymentSheet'
import type { PaymentMethod } from '../features/payments/components/PaymentMethodList'
-import { SnapPaymentTrigger } from '../features/payments/snap/SnapPaymentTrigger'
import { usePaymentConfig } from '../features/payments/lib/usePaymentConfig'
import { Alert } from '../components/alert/Alert'
import { Button } from '../components/ui/button'
import { getPaymentLinkPayload } from '../services/api'
import { isOrderLocked, lockOrder } from '../features/payments/lib/chargeLock'
import { usePaymentNavigation } from '../features/payments/lib/navigation'
+import React from 'react'
type Method = PaymentMethod | null
+interface AutoSnapPaymentProps {
+ orderId: string
+ amount: number
+ customer?: { name?: string; phone?: string; email?: string }
+ onChargeInitiated?: () => void
+ onSuccess?: (result: any) => void
+ onError?: (error: any) => void
+}
+
+function AutoSnapPayment({ orderId, amount, customer, onChargeInitiated, onSuccess, onError }: AutoSnapPaymentProps) {
+ const [loading, setLoading] = React.useState(false)
+ const [error, setError] = React.useState('')
+ const hasTriggered = React.useRef(false)
+
+ React.useEffect(() => {
+ if (hasTriggered.current) return
+ hasTriggered.current = true
+
+ const triggerPayment = async () => {
+ try {
+ setLoading(true)
+ setError('')
+
+ console.log('[PayPage] Auto-triggering Snap payment:', { orderId, amount, customer })
+
+ // Import SnapTokenService dynamically to avoid circular deps
+ const { SnapTokenService } = await import('../features/payments/snap/SnapTokenService')
+
+ // Create Snap transaction token
+ const token = await SnapTokenService.createToken({
+ transaction_details: {
+ order_id: orderId,
+ gross_amount: amount
+ },
+ customer_details: customer ? {
+ first_name: customer.name,
+ email: customer.email,
+ phone: customer.phone
+ } : undefined,
+ item_details: [{
+ id: orderId,
+ name: 'Payment',
+ price: amount,
+ quantity: 1
+ }]
+ })
+
+ console.log('[PayPage] Snap token received:', token.substring(0, 10) + '...')
+
+ // Auto-trigger Snap payment popup
+ if (window.snap && typeof window.snap.pay === 'function') {
+ window.snap.pay(token, {
+ onSuccess: (result: any) => {
+ console.log('[PayPage] Payment success:', result)
+ onSuccess?.(result)
+ },
+ onPending: (result: any) => {
+ console.log('[PayPage] Payment pending:', result)
+ },
+ onError: (result: any) => {
+ console.error('[PayPage] Payment error:', result)
+ const message = 'Pembayaran gagal. Silakan coba lagi.'
+ setError(message)
+ onError?.(result)
+ },
+ onClose: () => {
+ console.log('[PayPage] Snap popup closed')
+ }
+ })
+ } else {
+ throw new Error('Snap.js not loaded')
+ }
+
+ } catch (e: any) {
+ console.error('[PayPage] Auto-payment error:', e.message)
+ const message = 'Gagal memuat pembayaran. Silakan refresh halaman.'
+ setError(message)
+ onError?.(e)
+ } finally {
+ setLoading(false)
+ }
+ }
+
+ // Small delay to ensure UI is rendered
+ const timer = setTimeout(triggerPayment, 500)
+ return () => clearTimeout(timer)
+ }, [orderId, amount, customer, onChargeInitiated, onSuccess, onError])
+
+ return (
+
+ {error && (
+
+ {error}
+
+ )}
+
+
+ {loading ? (
+
+
+
Menyiapkan pembayaran...
+
+ ) : (
+
+ Membuka halaman pembayaran Midtrans...
+
+ )}
+
+
+ )
+}
+
export function PayPage() {
const { token } = useParams()
const nav = usePaymentNavigation()
@@ -108,11 +220,10 @@ export function PayPage() {
)}
{currentStep === 2 && (
- {
lockOrder(orderId)
setLocked(true)