🎨 Layout Changes: - Changed settings from boxed (max-w-5xl) to full-width - Consistent with Orders/Dashboard pages - Better use of space for complex forms 📝 Payments Page Reorder: - Manual payment methods first (Bank Transfer, COD) - Payment providers second (Stripe, PayPal) - Payment settings third (test mode, capture) - Test mode banner moved inside Payment Settings card 📚 Documentation: - Created SETUP_WIZARD_DESIGN.md - 5-step wizard flow (Store, Payments, Shipping, Taxes, Product) - Smart defaults and skip logic - Complete addon integration architecture 🔌 Addon Integration Design: - PaymentProviderRegistry with filter hooks - ShippingMethodRegistry with filter hooks - REST API endpoints for dynamic loading - Example addon implementations - Support for custom React components ✨ Key Features: - woonoow_payment_providers filter hook - woonoow_shipping_zones filter hook - Dynamic component loading from addons - OAuth flow support for payment gateways - Backward compatible with WooCommerce
238 lines
8.3 KiB
TypeScript
238 lines
8.3 KiB
TypeScript
import React, { useState } from 'react';
|
||
import { SettingsLayout } from './components/SettingsLayout';
|
||
import { SettingsCard } from './components/SettingsCard';
|
||
import { ToggleField } from './components/ToggleField';
|
||
import { Button } from '@/components/ui/button';
|
||
import { Badge } from '@/components/ui/badge';
|
||
import { CreditCard, DollarSign, Banknote, Settings } from 'lucide-react';
|
||
import { toast } from 'sonner';
|
||
|
||
interface PaymentProvider {
|
||
id: string;
|
||
name: string;
|
||
description: string;
|
||
icon: React.ReactNode;
|
||
enabled: boolean;
|
||
connected: boolean;
|
||
fees?: string;
|
||
testMode?: boolean;
|
||
}
|
||
|
||
export default function PaymentsPage() {
|
||
const [testMode, setTestMode] = useState(false);
|
||
const [providers] = useState<PaymentProvider[]>([
|
||
{
|
||
id: 'stripe',
|
||
name: 'Stripe Payments',
|
||
description: 'Accept Visa, Mastercard, Amex, and more',
|
||
icon: <CreditCard className="h-6 w-6" />,
|
||
enabled: false,
|
||
connected: false,
|
||
fees: '2.9% + $0.30 per transaction',
|
||
},
|
||
{
|
||
id: 'paypal',
|
||
name: 'PayPal',
|
||
description: 'Accept PayPal payments worldwide',
|
||
icon: <DollarSign className="h-6 w-6" />,
|
||
enabled: true,
|
||
connected: true,
|
||
fees: '3.49% + fixed fee per transaction',
|
||
},
|
||
]);
|
||
|
||
const [manualMethods, setManualMethods] = useState([
|
||
{ id: 'bacs', name: 'Bank Transfer (BACS)', enabled: true },
|
||
{ id: 'cod', name: 'Cash on Delivery', enabled: true },
|
||
{ id: 'cheque', name: 'Check Payments', enabled: false },
|
||
]);
|
||
|
||
const handleSave = async () => {
|
||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||
toast.success('Payment settings have been updated successfully.');
|
||
};
|
||
|
||
|
||
const toggleManualMethod = (id: string) => {
|
||
setManualMethods((prev) =>
|
||
prev.map((m) => (m.id === id ? { ...m, enabled: !m.enabled } : m))
|
||
);
|
||
};
|
||
|
||
return (
|
||
<SettingsLayout
|
||
title="Payments"
|
||
description="Manage how you get paid"
|
||
onSave={handleSave}
|
||
>
|
||
{/* Manual Payment Methods - First priority */}
|
||
<SettingsCard
|
||
title="Manual Payment Methods"
|
||
description="Accept payments outside your online store"
|
||
>
|
||
<div className="space-y-4">
|
||
{manualMethods.map((method) => (
|
||
<div
|
||
key={method.id}
|
||
className="border rounded-lg p-4"
|
||
>
|
||
<div className="flex items-center justify-between">
|
||
<div className="flex items-center gap-4">
|
||
<div className="p-2 bg-muted rounded-lg">
|
||
<Banknote className="h-5 w-5 text-muted-foreground" />
|
||
</div>
|
||
<div>
|
||
<h3 className="font-medium">{method.name}</h3>
|
||
{method.enabled && (
|
||
<p className="text-sm text-muted-foreground mt-1">
|
||
Customers can choose this at checkout
|
||
</p>
|
||
)}
|
||
</div>
|
||
</div>
|
||
<div className="flex items-center gap-2">
|
||
{method.enabled && (
|
||
<Button variant="ghost" size="sm">
|
||
<Settings className="h-4 w-4" />
|
||
</Button>
|
||
)}
|
||
<ToggleField
|
||
id={method.id}
|
||
label=""
|
||
checked={method.enabled}
|
||
onCheckedChange={() => toggleManualMethod(method.id)}
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</SettingsCard>
|
||
|
||
{/* Payment Providers - Second priority */}
|
||
<SettingsCard
|
||
title="Payment Providers"
|
||
description="Accept credit cards and digital wallets"
|
||
>
|
||
<div className="space-y-4">
|
||
{providers.map((provider) => (
|
||
<div
|
||
key={provider.id}
|
||
className="border rounded-lg p-4 hover:border-primary/50 transition-colors"
|
||
>
|
||
<div className="flex items-start justify-between">
|
||
<div className="flex items-start gap-4 flex-1">
|
||
<div className="p-2 bg-primary/10 rounded-lg text-primary">
|
||
{provider.icon}
|
||
</div>
|
||
<div className="flex-1">
|
||
<div className="flex items-center gap-2 mb-1">
|
||
<h3 className="font-semibold">{provider.name}</h3>
|
||
{provider.connected ? (
|
||
<Badge variant="default" className="bg-green-500">
|
||
● Connected
|
||
</Badge>
|
||
) : (
|
||
<Badge variant="secondary">○ Not connected</Badge>
|
||
)}
|
||
</div>
|
||
<p className="text-sm text-muted-foreground mb-2">
|
||
{provider.description}
|
||
</p>
|
||
{provider.fees && (
|
||
<p className="text-xs text-muted-foreground">
|
||
{provider.fees}
|
||
</p>
|
||
)}
|
||
</div>
|
||
</div>
|
||
<div className="flex items-center gap-2">
|
||
{provider.connected ? (
|
||
<>
|
||
<Button variant="outline" size="sm">
|
||
<Settings className="h-4 w-4 mr-2" />
|
||
Manage
|
||
</Button>
|
||
<Button variant="ghost" size="sm">
|
||
Disconnect
|
||
</Button>
|
||
</>
|
||
) : (
|
||
<Button size="sm">Set up {provider.name}</Button>
|
||
)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
))}
|
||
|
||
<Button variant="outline" className="w-full">
|
||
+ Add payment provider
|
||
</Button>
|
||
</div>
|
||
</SettingsCard>
|
||
|
||
{/* Payment Settings - Third priority (test mode, capture, etc) */}
|
||
<SettingsCard
|
||
title="Payment Settings"
|
||
description="General payment options"
|
||
>
|
||
{/* Test Mode Banner */}
|
||
{testMode && (
|
||
<div className="bg-yellow-50 dark:bg-yellow-900/20 border border-yellow-200 dark:border-yellow-800 rounded-lg p-4 mb-4">
|
||
<div className="flex items-center gap-2">
|
||
<span className="text-yellow-600 dark:text-yellow-400 font-semibold">
|
||
⚠️ Test Mode Active
|
||
</span>
|
||
<span className="text-sm text-yellow-700 dark:text-yellow-300">
|
||
No real charges will be processed
|
||
</span>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
<ToggleField
|
||
id="testMode"
|
||
label="Test mode"
|
||
description="Process test transactions without real charges"
|
||
checked={testMode}
|
||
onCheckedChange={setTestMode}
|
||
/>
|
||
|
||
<div className="pt-4 border-t">
|
||
<div className="space-y-2">
|
||
<label className="text-sm font-medium">Payment capture</label>
|
||
<p className="text-sm text-muted-foreground">
|
||
Choose when to capture payment from customers
|
||
</p>
|
||
<div className="space-y-2 mt-2">
|
||
<label className="flex items-center gap-2 cursor-pointer">
|
||
<input type="radio" name="capture" value="automatic" defaultChecked />
|
||
<span className="text-sm">
|
||
<strong>Authorize and capture</strong> - Charge immediately when order is placed
|
||
</span>
|
||
</label>
|
||
<label className="flex items-center gap-2 cursor-pointer">
|
||
<input type="radio" name="capture" value="manual" />
|
||
<span className="text-sm">
|
||
<strong>Authorize only</strong> - Manually capture payment later
|
||
</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</SettingsCard>
|
||
|
||
{/* Help Card */}
|
||
<div className="bg-muted/50 border rounded-lg p-4">
|
||
<p className="text-sm font-medium mb-2">💡 Need help setting up payments?</p>
|
||
<p className="text-sm text-muted-foreground">
|
||
Our setup wizard can help you connect Stripe or PayPal in minutes.
|
||
</p>
|
||
<Button variant="link" className="px-0 mt-2">
|
||
Start setup wizard →
|
||
</Button>
|
||
</div>
|
||
</SettingsLayout>
|
||
);
|
||
}
|