feat: implement advanced test provider with interactive UI and multiple scenarios

- Add comprehensive test provider with configurable payment outcomes (paid, failed, cancelled, expired, pending)
- Support multiple payment methods (iDEAL, Credit Card, PayPal, Apple Pay, Bank Transfer)
- Interactive test payment UI with responsive design and real-time processing simulation
- Test mode indicators including warning banners, badges, and console warnings
- React components for admin UI integration (TestModeWarningBanner, TestModeBadge, TestPaymentControls)
- API endpoints for test payment processing and status polling
- Configurable scenarios with custom delays and outcomes
- Production safety mechanisms and clear test mode indicators
- Complete documentation and usage examples

Implements GitHub issue #20 for advanced test provider functionality.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-09-19 10:34:55 +02:00
parent 83251bb404
commit 8e6385caa3
6 changed files with 1025 additions and 3 deletions

View File

@@ -60,9 +60,130 @@ export const PaymentStatusBadge: React.FC<{ status: string }> = ({ status }) =>
)
}
// Test mode indicator components
export const TestModeWarningBanner: React.FC<{ visible?: boolean }> = ({ visible = true }) => {
if (!visible) return null
return (
<div style={{
background: 'linear-gradient(90deg, #ff6b6b, #ffa726)',
color: 'white',
padding: '12px 20px',
textAlign: 'center',
fontWeight: 600,
fontSize: '14px',
marginBottom: '20px',
borderRadius: '4px'
}}>
🧪 TEST MODE - Payment system is running in test mode for development
</div>
)
}
export const TestModeBadge: React.FC<{ visible?: boolean }> = ({ visible = true }) => {
if (!visible) return null
return (
<span style={{
display: 'inline-block',
background: '#6c757d',
color: 'white',
padding: '4px 8px',
borderRadius: '4px',
fontSize: '12px',
fontWeight: 600,
textTransform: 'uppercase',
marginLeft: '8px'
}}>
Test
</span>
)
}
export const TestPaymentControls: React.FC<{
paymentId?: string
onScenarioSelect?: (scenario: string) => void
onMethodSelect?: (method: string) => void
}> = ({ paymentId, onScenarioSelect, onMethodSelect }) => {
const [selectedScenario, setSelectedScenario] = React.useState('')
const [selectedMethod, setSelectedMethod] = React.useState('')
const scenarios = [
{ id: 'instant-success', name: 'Instant Success', description: 'Payment succeeds immediately' },
{ id: 'delayed-success', name: 'Delayed Success', description: 'Payment succeeds after delay' },
{ id: 'cancelled-payment', name: 'Cancelled Payment', description: 'User cancels payment' },
{ id: 'declined-payment', name: 'Declined Payment', description: 'Payment declined' },
{ id: 'expired-payment', name: 'Expired Payment', description: 'Payment expires' },
{ id: 'pending-payment', name: 'Pending Payment', description: 'Payment stays pending' }
]
const methods = [
{ id: 'ideal', name: 'iDEAL', icon: '🏦' },
{ id: 'creditcard', name: 'Credit Card', icon: '💳' },
{ id: 'paypal', name: 'PayPal', icon: '🅿️' },
{ id: 'applepay', name: 'Apple Pay', icon: '🍎' },
{ id: 'banktransfer', name: 'Bank Transfer', icon: '🏛️' }
]
return (
<div style={{ border: '1px solid #e9ecef', borderRadius: '8px', padding: '16px', margin: '16px 0' }}>
<h4 style={{ marginBottom: '12px', color: '#2c3e50' }}>🧪 Test Payment Controls</h4>
<div style={{ marginBottom: '16px' }}>
<label style={{ display: 'block', marginBottom: '8px', fontWeight: '600' }}>Payment Method:</label>
<select
value={selectedMethod}
onChange={(e) => {
setSelectedMethod(e.target.value)
onMethodSelect?.(e.target.value)
}}
style={{ width: '100%', padding: '8px', borderRadius: '4px', border: '1px solid #ccc' }}
>
<option value="">Select payment method...</option>
{methods.map(method => (
<option key={method.id} value={method.id}>
{method.icon} {method.name}
</option>
))}
</select>
</div>
<div style={{ marginBottom: '16px' }}>
<label style={{ display: 'block', marginBottom: '8px', fontWeight: '600' }}>Test Scenario:</label>
<select
value={selectedScenario}
onChange={(e) => {
setSelectedScenario(e.target.value)
onScenarioSelect?.(e.target.value)
}}
style={{ width: '100%', padding: '8px', borderRadius: '4px', border: '1px solid #ccc' }}
>
<option value="">Select test scenario...</option>
{scenarios.map(scenario => (
<option key={scenario.id} value={scenario.id}>
{scenario.name} - {scenario.description}
</option>
))}
</select>
</div>
{paymentId && (
<div style={{ marginTop: '12px', padding: '8px', background: '#f8f9fa', borderRadius: '4px' }}>
<small style={{ color: '#6c757d' }}>
Payment ID: <code>{paymentId}</code>
</small>
</div>
)}
</div>
)
}
export default {
BillingDashboardWidget,
formatCurrency,
getPaymentStatusColor,
PaymentStatusBadge,
TestModeWarningBanner,
TestModeBadge,
TestPaymentControls,
}