fix: Polish notification UI - mobile, colors, and layout

##  All UI Improvements

### 1. Contextual Header
- Added contextual header to Notifications page
- Consistent with Payments and Shipping pages
- Saves vertical space

### 2. Mobile View Improvements
**Channels Page:**
- Responsive flex-col on mobile, flex-row on desktop
- Full-width buttons on mobile
- Better spacing and alignment
- Push subscription toggle in bordered container on mobile

**Templates Accordion:**
- Better mobile layout
- Badges wrap properly
- Icon and title alignment improved
- Responsive padding

### 3. Active State Colors
- **Green color for active channels** (consistent with Payments)
- `bg-green-500/20 text-green-600` for active
- `bg-muted text-muted-foreground` for inactive
- Applied to:
  - Events page channel icons
  - Channels page channel icons
  - Active badges

### 4. Badge Layout
- Badges moved under title on mobile
- Better visual hierarchy
- Title → Badges → Description flow
- Proper spacing between elements

### 5. Template Variables Card Removed
- Variables already in template editor modal
- Click-to-insert functionality
- No need for separate reference card
- Cleaner page layout

### 6. Accordion Polish
- Better padding and spacing
- Responsive layout
- Icon stays visible
- Badges wrap on small screens

---

**Next: Email toggle and push settings backend** 🎯
This commit is contained in:
dwindown
2025-11-11 14:51:42 +07:00
parent 200245491f
commit 63dbed757a
4 changed files with 53 additions and 85 deletions

View File

@@ -13,6 +13,7 @@ export default function NotificationsSettings() {
<SettingsLayout
title={__('Notifications')}
description={__('Manage notification events, channels, and templates')}
action={<div />} // Empty action to trigger contextual header
>
<Tabs value={activeTab} onValueChange={setActiveTab} className="space-y-6">
<TabsList className="grid w-full grid-cols-3">

View File

@@ -169,20 +169,27 @@ export default function NotificationChannels() {
<SettingsCard title={__('Built-in Channels')} description={__('Channels included with WooNooW')}>
<div className="space-y-4">
{builtinChannels.map((channel: NotificationChannel) => (
<div key={channel.id} className="flex items-center justify-between p-4 rounded-lg border bg-card">
<div className="flex items-center gap-4 flex-1">
<div className="p-3 rounded-lg bg-primary/10">{getChannelIcon(channel.id)}</div>
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<div key={channel.id} className="flex flex-col sm:flex-row sm:items-center gap-4 p-4 rounded-lg border bg-card">
<div className="flex items-start gap-3 flex-1 min-w-0">
<div className={`p-3 rounded-lg shrink-0 ${channel.enabled ? 'bg-green-500/20 text-green-600' : 'bg-muted text-muted-foreground'}`}>
{getChannelIcon(channel.id)}
</div>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 mb-2">
<h3 className="font-medium">{channel.label}</h3>
</div>
<div className="flex flex-wrap items-center gap-2 mb-2">
<Badge variant="secondary" className="text-xs">
{__('Built-in')}
</Badge>
<Badge variant={channel.enabled ? 'default' : 'secondary'} className="text-xs">
<Badge
variant={channel.enabled ? 'default' : 'secondary'}
className={`text-xs ${channel.enabled ? 'bg-green-500 hover:bg-green-600' : ''}`}
>
{channel.enabled ? __('Active') : __('Inactive')}
</Badge>
</div>
<p className="text-sm text-muted-foreground">
<p className="text-sm text-muted-foreground mt-1">
{channel.id === 'email' &&
__('Email notifications powered by WooCommerce. Configure templates and SMTP settings.')}
{channel.id === 'push' &&
@@ -190,7 +197,7 @@ export default function NotificationChannels() {
</p>
</div>
</div>
<div className="flex items-center gap-2">
<div className="flex flex-col sm:flex-row items-stretch sm:items-center gap-2 sm:gap-2">
<Button
variant="outline"
size="sm"
@@ -198,13 +205,13 @@ export default function NotificationChannels() {
setSelectedChannel(channel);
setConfigOpen(true);
}}
className="w-full sm:w-auto"
>
<Settings className="h-4 w-4 mr-2" />
{__('Configure')}
<Settings className="h-4 w-4 sm:mr-2" />
<span className="sm:inline">{__('Configure')}</span>
</Button>
{channel.id === 'push' && pushSupported && (
<div className="flex items-center gap-3">
<div className="flex items-center gap-2">
<div className="flex items-center justify-between sm:justify-start gap-2 p-2 sm:p-0 rounded-lg sm:rounded-none border sm:border-0">
<span className="text-sm text-muted-foreground">
{pushSubscribed ? __('Subscribed') : __('Not subscribed')}
</span>
@@ -220,10 +227,9 @@ export default function NotificationChannels() {
disabled={subscribeToPush.isPending || unsubscribeFromPush.isPending}
/>
</div>
</div>
)}
{channel.id === 'push' && !pushSupported && (
<Badge variant="destructive" className="text-xs">
<Badge variant="destructive" className="text-xs w-full sm:w-auto justify-center">
{__('Not Supported')}
</Badge>
)}

View File

@@ -150,7 +150,7 @@ export default function NotificationEvents() {
className="flex items-center justify-between p-3 rounded-lg border bg-card"
>
<div className="flex items-center gap-3">
<div className={`p-2 rounded-lg ${channelEnabled ? 'bg-primary/10' : 'bg-muted'}`}>
<div className={`p-2 rounded-lg ${channelEnabled ? 'bg-green-500/20 text-green-600' : 'bg-muted text-muted-foreground'}`}>
{getChannelIcon(channel.id)}
</div>
<div>
@@ -212,7 +212,7 @@ export default function NotificationEvents() {
className="flex items-center justify-between p-3 rounded-lg border bg-card"
>
<div className="flex items-center gap-3">
<div className={`p-2 rounded-lg ${channelEnabled ? 'bg-primary/10' : 'bg-muted'}`}>
<div className={`p-2 rounded-lg ${channelEnabled ? 'bg-green-500/20 text-green-600' : 'bg-muted text-muted-foreground'}`}>
{getChannelIcon(channel.id)}
</div>
<div>
@@ -274,7 +274,7 @@ export default function NotificationEvents() {
className="flex items-center justify-between p-3 rounded-lg border bg-card"
>
<div className="flex items-center gap-3">
<div className={`p-2 rounded-lg ${channelEnabled ? 'bg-primary/10' : 'bg-muted'}`}>
<div className={`p-2 rounded-lg ${channelEnabled ? 'bg-green-500/20 text-green-600' : 'bg-muted text-muted-foreground'}`}>
{getChannelIcon(channel.id)}
</div>
<div>

View File

@@ -125,12 +125,13 @@ export default function NotificationTemplates() {
const customCount = channelTemplates.length;
return (
<AccordionItem key={channel.id} value={channel.id}>
<AccordionTrigger className="hover:no-underline">
<div className="flex items-center gap-3 flex-1">
<div className="p-2 rounded-lg bg-primary/10">{getChannelIcon(channel.id)}</div>
<div className="flex items-center gap-2">
<span className="font-medium">{channel.label} {__('Templates')}</span>
<AccordionItem key={channel.id} value={channel.id} className="border-b">
<AccordionTrigger className="hover:no-underline py-4">
<div className="flex items-center gap-3 flex-1 min-w-0">
<div className="p-2 rounded-lg bg-primary/10 shrink-0">{getChannelIcon(channel.id)}</div>
<div className="flex flex-col sm:flex-row sm:items-center gap-2 flex-1 min-w-0">
<span className="font-medium text-left">{channel.label}</span>
<div className="flex items-center gap-2 flex-wrap">
<Badge variant="secondary" className="text-xs">
{allEvents.length} {__('templates')}
</Badge>
@@ -141,6 +142,7 @@ export default function NotificationTemplates() {
)}
</div>
</div>
</div>
</AccordionTrigger>
<AccordionContent>
<div className="space-y-2 pt-2">
@@ -181,47 +183,6 @@ export default function NotificationTemplates() {
</Accordion>
</SettingsCard>
{/* Template Variables Reference */}
<SettingsCard
title={__('Template Variables')}
description={__('Available variables you can use in your templates')}
>
<div className="space-y-4">
<div>
<h4 className="font-medium text-sm mb-2">{__('Order Variables')}</h4>
<div className="grid grid-cols-2 gap-2 text-sm">
<code className="px-2 py-1 rounded bg-muted text-xs">{'{order_number}'}</code>
<code className="px-2 py-1 rounded bg-muted text-xs">{'{order_total}'}</code>
<code className="px-2 py-1 rounded bg-muted text-xs">{'{order_status}'}</code>
<code className="px-2 py-1 rounded bg-muted text-xs">{'{order_date}'}</code>
<code className="px-2 py-1 rounded bg-muted text-xs">{'{payment_method}'}</code>
<code className="px-2 py-1 rounded bg-muted text-xs">{'{shipping_method}'}</code>
</div>
</div>
<div>
<h4 className="font-medium text-sm mb-2">{__('Customer Variables')}</h4>
<div className="grid grid-cols-2 gap-2 text-sm">
<code className="px-2 py-1 rounded bg-muted text-xs">{'{customer_name}'}</code>
<code className="px-2 py-1 rounded bg-muted text-xs">{'{customer_email}'}</code>
<code className="px-2 py-1 rounded bg-muted text-xs">{'{customer_phone}'}</code>
<code className="px-2 py-1 rounded bg-muted text-xs">{'{billing_address}'}</code>
<code className="px-2 py-1 rounded bg-muted text-xs">{'{shipping_address}'}</code>
</div>
</div>
<div>
<h4 className="font-medium text-sm mb-2">{__('Store Variables')}</h4>
<div className="grid grid-cols-2 gap-2 text-sm">
<code className="px-2 py-1 rounded bg-muted text-xs">{'{store_name}'}</code>
<code className="px-2 py-1 rounded bg-muted text-xs">{'{store_url}'}</code>
<code className="px-2 py-1 rounded bg-muted text-xs">{'{store_email}'}</code>
<code className="px-2 py-1 rounded bg-muted text-xs">{'{store_phone}'}</code>
</div>
</div>
</div>
</SettingsCard>
{/* Template Editor Dialog */}
{selectedEvent && selectedChannel && (
<TemplateEditor