'use client' import { useParams, useRouter } from 'next/navigation' import { useEffect, useState } from 'react' interface PaymentMethod { id: string name: string icon: string } interface Scenario { id: string name: string description: string outcome: string delay?: number } interface TestProviderConfig { enabled: boolean scenarios: Scenario[] methods: PaymentMethod[] testModeIndicators: { showWarningBanners: boolean showTestBadges: boolean consoleWarnings: boolean } defaultDelay: number customUiRoute: string } interface PaymentSession { id: string amount: number currency: string description?: string } export default function TestPaymentPage() { const params = useParams() const router = useRouter() const paymentId = params.id as string const [config, setConfig] = useState(null) const [session, setSession] = useState(null) const [selectedMethod, setSelectedMethod] = useState(null) const [selectedScenario, setSelectedScenario] = useState(null) const [processing, setProcessing] = useState(false) const [status, setStatus] = useState<{ type: 'idle' | 'processing' | 'success' | 'error' message: string }>({ type: 'idle', message: '' }) useEffect(() => { // Load test provider config fetch('/api/payload-billing/test/config') .then((res) => res.json()) .then((data) => { setConfig(data) if (data.testModeIndicators?.consoleWarnings) { console.warn('[Test Provider] ๐Ÿงช TEST MODE: This is a simulated payment interface') } }) .catch((err) => { console.error('Failed to load test provider config:', err) }) // Load payment session (mock data for demo) setSession({ id: paymentId, amount: 2500, currency: 'USD', description: 'Demo payment for testing the billing plugin', }) }, [paymentId]) const handleProcessPayment = async () => { if (!selectedMethod || !selectedScenario) return setProcessing(true) setStatus({ type: 'processing', message: 'Initiating payment...' }) try { const response = await fetch('/api/payload-billing/test/process', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ paymentId, scenarioId: selectedScenario, method: selectedMethod, }), }) const result = await response.json() if (result.success) { const scenario = config?.scenarios.find((s) => s.id === selectedScenario) setStatus({ type: 'processing', message: `Processing payment with ${scenario?.name}...`, }) // Poll for status updates setTimeout(() => pollStatus(), result.delay || 1000) } else { throw new Error(result.error || 'Failed to process payment') } } catch (error) { setStatus({ type: 'error', message: error instanceof Error ? error.message : 'An error occurred', }) setProcessing(false) } } const pollStatus = async () => { try { const response = await fetch(`/api/payload-billing/test/status/${paymentId}`) const result = await response.json() if (result.status === 'paid') { setStatus({ type: 'success', message: 'โœ… Payment successful!' }) setTimeout(() => { const params = new URLSearchParams({ paymentId: paymentId, amount: session.amount.toString(), currency: session.currency, }) router.push(`/payment-success?${params.toString()}`) }, 2000) } else if (['failed', 'cancelled', 'expired'].includes(result.status)) { setStatus({ type: 'error', message: `โŒ Payment ${result.status}` }) setTimeout(() => { const params = new URLSearchParams({ paymentId: paymentId, amount: session.amount.toString(), currency: session.currency, reason: result.status, }) router.push(`/payment-failed?${params.toString()}`) }, 2000) } else if (result.status === 'pending') { setStatus({ type: 'processing', message: 'Payment is still pending...' }) setTimeout(() => pollStatus(), 2000) } } catch (error) { console.error('[Test Provider] Failed to poll status:', error) setStatus({ type: 'error', message: 'Failed to check payment status' }) setProcessing(false) } } if (!config || !session) { return (
Loading...
) } return (
{config.testModeIndicators.showWarningBanners && (
๐Ÿงช TEST MODE - This is a simulated payment for development purposes
)}

Test Payment Checkout

{config.testModeIndicators.showTestBadges && ( Test )}
{session.currency.toUpperCase()} {(session.amount / 100).toFixed(2)}
{session.description && (

{session.description}

)}
{/* Payment Methods */}

๐Ÿ’ณ Select Payment Method

{config.methods.map((method) => ( ))}
{/* Test Scenarios */}

๐ŸŽญ Select Test Scenario

{config.scenarios.map((scenario) => ( ))}
{/* Process Button */} {/* Status Message */} {status.type !== 'idle' && (
{status.type === 'processing' && ( )} {status.message}
)}
{/* Info Card */}

๐Ÿ’ก Demo Information

This is a custom test payment UI for the @xtr-dev/payload-billing plugin. Select a payment method and scenario to simulate different payment outcomes. The payment will be processed according to the selected scenario.

) }