feat: Mobile improvements + simplify payment categories
Mobile Improvements: 1. Modal footer buttons now stack vertically on mobile - Order: Save Settings (primary) -> View in WooCommerce -> Cancel - Full width buttons on mobile for easier tapping - Responsive padding: px-4 on mobile, px-6 on desktop 2. Refresh button moved inline with title - Added action prop to SettingsLayout - Refresh button now appears next to Payments title - Cleaner, more compact layout Payment Categories Simplified: 3. Removed Payment Providers section - PayPal, Stripe are also 3rd party, not different - Confusing to separate providers from other gateways - All non-manual gateways now in single category 4. Renamed to Online Payment Methods - Was: Manual + Payment Providers + 3rd Party - Now: Manual + Online Payment Methods - Clearer distinction: offline vs online payments 5. Unified styling for all online gateways - Same card style as manual methods - Status badges (Enabled/Disabled) - Requirements alerts - Manage button always visible Mobile UX: - Footer buttons: flex-col on mobile, flex-row on desktop - Proper button ordering with CSS order utilities - Responsive spacing and padding - Touch-friendly button sizes Files Modified: - Payments.tsx: Mobile footer + simplified categories - SettingsLayout.tsx: Added action prop for header actions Result: ✅ Better mobile experience ✅ Clearer payment method organization ✅ Consistent styling across all gateways
This commit is contained in:
@@ -113,8 +113,8 @@ export default function PaymentsPage() {
|
||||
|
||||
// Categorize gateways
|
||||
const manualGateways = gateways.filter((g: PaymentGateway) => g.type === 'manual');
|
||||
const providerGateways = gateways.filter((g: PaymentGateway) => g.type === 'provider');
|
||||
const otherGateways = gateways.filter((g: PaymentGateway) => g.type === 'other');
|
||||
// Combine provider and other into single "3rd party" category
|
||||
const thirdPartyGateways = gateways.filter((g: PaymentGateway) => g.type === 'provider' || g.type === 'other');
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
@@ -128,9 +128,10 @@ export default function PaymentsPage() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingsLayout title="Payments" description="Manage how you get paid">
|
||||
{/* Refresh button */}
|
||||
<div className="flex justify-end mb-4">
|
||||
<SettingsLayout
|
||||
title="Payments"
|
||||
description="Manage how you get paid"
|
||||
action={
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
@@ -140,7 +141,8 @@ export default function PaymentsPage() {
|
||||
<RefreshCw className="h-4 w-4 mr-2" />
|
||||
Refresh
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
|
||||
{/* Manual Payment Methods - First priority */}
|
||||
<SettingsCard
|
||||
@@ -195,27 +197,14 @@ export default function PaymentsPage() {
|
||||
)}
|
||||
</SettingsCard>
|
||||
|
||||
{/* Payment Providers - Second priority */}
|
||||
<SettingsCard
|
||||
title="Payment Providers"
|
||||
description="Accept credit cards and digital wallets"
|
||||
>
|
||||
{providerGateways.length === 0 ? (
|
||||
<p className="text-sm text-muted-foreground">
|
||||
No payment providers installed.{' '}
|
||||
<a
|
||||
href="https://woocommerce.com/product-category/woocommerce-extensions/payment-gateways/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline inline-flex items-center gap-1"
|
||||
>
|
||||
Browse payment gateways
|
||||
<ExternalLink className="h-3 w-3" />
|
||||
</a>
|
||||
</p>
|
||||
) : (
|
||||
{/* 3rd Party Payment Methods - All online payment gateways */}
|
||||
{thirdPartyGateways.length > 0 && (
|
||||
<SettingsCard
|
||||
title="Online Payment Methods"
|
||||
description="Accept credit cards, digital wallets, and other online payments"
|
||||
>
|
||||
<div className="space-y-4">
|
||||
{providerGateways.map((gateway: PaymentGateway) => (
|
||||
{thirdPartyGateways.map((gateway: PaymentGateway) => (
|
||||
<div
|
||||
key={gateway.id}
|
||||
className="border rounded-lg p-4 hover:border-primary/50 transition-colors"
|
||||
@@ -236,9 +225,11 @@ export default function PaymentsPage() {
|
||||
<Badge variant="secondary">○ Disabled</Badge>
|
||||
)}
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground mb-2">
|
||||
{gateway.description}
|
||||
</p>
|
||||
{gateway.method_description && (
|
||||
<p className="text-sm text-muted-foreground mb-2">
|
||||
{gateway.method_description}
|
||||
</p>
|
||||
)}
|
||||
{!gateway.requirements.met && (
|
||||
<Alert variant="destructive" className="mt-2">
|
||||
<AlertTriangle className="h-4 w-4" />
|
||||
@@ -270,57 +261,6 @@ export default function PaymentsPage() {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</SettingsCard>
|
||||
|
||||
{/* 3rd Party Gateways */}
|
||||
{otherGateways.length > 0 && (
|
||||
<SettingsCard
|
||||
title="3rd Party Payment Methods"
|
||||
description="Additional payment gateways from plugins"
|
||||
>
|
||||
<div className="space-y-4">
|
||||
{otherGateways.map((gateway: PaymentGateway) => (
|
||||
<div
|
||||
key={gateway.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">
|
||||
<CreditCard className="h-5 w-5 text-muted-foreground" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-medium">{gateway.method_title || gateway.title}</h3>
|
||||
{gateway.method_description && (
|
||||
<p className="text-sm text-muted-foreground mt-1">
|
||||
{gateway.method_description}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
{gateway.enabled && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => handleManageGateway(gateway)}
|
||||
>
|
||||
<Settings className="h-4 w-4" />
|
||||
</Button>
|
||||
)}
|
||||
<ToggleField
|
||||
id={gateway.id}
|
||||
label=""
|
||||
checked={gateway.enabled}
|
||||
onCheckedChange={(checked) => handleToggle(gateway.id, checked)}
|
||||
disabled={togglingGateway === gateway.id}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</SettingsCard>
|
||||
)}
|
||||
</SettingsLayout>
|
||||
@@ -332,7 +272,7 @@ export default function PaymentsPage() {
|
||||
<DialogHeader className="px-6 pt-6 pb-4 border-b shrink-0">
|
||||
<DialogTitle>{selectedGateway.title} Settings</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="flex-1 overflow-y-auto px-6 py-4 min-h-0">
|
||||
<div className="flex-1 overflow-y-auto p-6 min-h-0">
|
||||
<GenericGatewayForm
|
||||
gateway={selectedGateway}
|
||||
onSave={handleSaveGateway}
|
||||
@@ -341,20 +281,22 @@ export default function PaymentsPage() {
|
||||
/>
|
||||
</div>
|
||||
{/* Footer outside scrollable area */}
|
||||
<div className="border-t px-6 py-4 flex items-center justify-between shrink-0 bg-background">
|
||||
<div className="border-t px-4 sm:px-6 py-3 sm:py-4 flex flex-col sm:flex-row items-stretch sm:items-center gap-2 sm:gap-0 sm:justify-between shrink-0 bg-background sm:rounded-b-lg">
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={() => setIsModalOpen(false)}
|
||||
disabled={saveMutation.isPending}
|
||||
className="order-3 sm:order-1"
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex flex-col sm:flex-row items-stretch sm:items-center gap-2 order-1 sm:order-2">
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
asChild
|
||||
className="justify-center"
|
||||
>
|
||||
<a
|
||||
href={selectedGateway.wc_settings_url}
|
||||
@@ -372,6 +314,7 @@ export default function PaymentsPage() {
|
||||
if (form) form.requestSubmit();
|
||||
}}
|
||||
disabled={saveMutation.isPending}
|
||||
className="order-1 sm:order-2"
|
||||
>
|
||||
{saveMutation.isPending ? 'Saving...' : 'Save Settings'}
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user