Files
WooNooW/admin-spa/src/routes/Settings/components/SettingsLayout.tsx
dwindown 1f88120c9d 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
2025-11-06 00:20:38 +07:00

90 lines
2.4 KiB
TypeScript

import React, { useState } from 'react';
import { Button } from '@/components/ui/button';
import { Loader2 } from 'lucide-react';
interface SettingsLayoutProps {
title: string;
description?: string;
children: React.ReactNode;
onSave?: () => Promise<void>;
saveLabel?: string;
isLoading?: boolean;
action?: React.ReactNode;
}
export function SettingsLayout({
title,
description,
children,
onSave,
saveLabel = 'Save changes',
isLoading = false,
action,
}: SettingsLayoutProps) {
const [isSaving, setIsSaving] = useState(false);
const handleSave = async () => {
if (!onSave) return;
setIsSaving(true);
try {
await onSave();
} finally {
setIsSaving(false);
}
};
return (
<div className="min-h-screen bg-background">
{/* Sticky Header with Save Button */}
{onSave && (
<div className="sticky top-0 z-10 border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
<div className="container max-w-5xl mx-auto px-4 py-3 flex items-center justify-between">
<div>
<h1 className="text-lg font-semibold">{title}</h1>
</div>
<Button
onClick={handleSave}
disabled={isSaving || isLoading}
size="sm"
>
{isSaving ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Saving...
</>
) : (
saveLabel
)}
</Button>
</div>
</div>
)}
{/* Content */}
<div className="container max-w-5xl mx-auto px-4 py-8">
{!onSave && (
<div className="mb-8">
<div className="flex items-start justify-between gap-4">
<div>
<h1 className="text-2xl font-bold tracking-tight">{title}</h1>
{description && (
<p className="text-muted-foreground mt-2">{description}</p>
)}
</div>
{action && <div className="shrink-0">{action}</div>}
</div>
</div>
)}
{isLoading ? (
<div className="flex items-center justify-center py-12">
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
</div>
) : (
<div className="space-y-6">{children}</div>
)}
</div>
</div>
);
}