From 0e41d3ded5634ed0870c69913bfe5ac21d63e0b8 Mon Sep 17 00:00:00 2001 From: dwindown Date: Mon, 10 Nov 2025 23:44:18 +0700 Subject: [PATCH] fix: Login branding, submenu display, favicon standalone, notification strategy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 1. Apply Logo to Standalone Login Screen ✅ **Issue:** Login page shows "WooNooW" text instead of brand logo **Fix:** - Fetch branding from `/store/settings` API - Display logo image if available - Fallback to store name text - Show tagline below logo - Use store name in footer **Result:** ```tsx {branding.logo ? ( {storeName} ) : (

{branding.storeName}

)} {branding.tagline &&

{branding.tagline}

} ``` --- ## 2. Fix Submenu Display Issue ✅ **Issue:** - Click Settings → redirects to Store Details ✓ - Settings submenu shows correctly ✓ - Click other settings pages → Dashboard submenu appears ✗ **Root Cause:** `useActiveSection` hook didn't recognize `/settings` path **Fix:** ```tsx // Special case: /settings should match settings section if (pathname === '/settings' || pathname.startsWith('/settings/')) { const settingsNode = navTree.find(n => n.key === 'settings'); if (settingsNode) return settingsNode; } ``` **Result:** Settings submenu now displays correctly on all settings pages --- ## 3. Apply Favicon in Standalone ✅ **Issue:** Favicon not showing in standalone mode (/admin) **Root Cause:** Standalone doesn't call `wp_head()`, so Branding class hooks don't run **Fix:** Added favicon directly to StandaloneAdmin.php ```php $icon = get_option('woonoow_store_icon', ''); if (!empty($icon)) { echo '' echo '' } ``` **Also:** Changed title to use store name dynamically --- ## 4. Notification Settings Strategy ✅ **Your Concern:** "We should not be optimistic the notification media is only email" **Agreed!** Created comprehensive strategy document: `NOTIFICATION_STRATEGY.md` ### Architecture: **Core (WooNooW):** - Notification events system - Email channel (built-in) - Addon integration framework - Settings UI with addon slots **Addons:** - WhatsApp - Telegram - SMS - Discord - Slack - Push notifications - etc. ### Settings Structure: ``` Notifications ├── Events (What to notify) │ ├── Order Placed │ │ ├── ✓ Email (to admin) │ │ ├── ✓ WhatsApp (to customer) [addon] │ │ └── ✗ Telegram [addon] │ └── Low Stock Alert │ ├── Channels (How to notify) │ ├── Email (Built-in) ✓ │ ├── WhatsApp [Addon] │ ├── Telegram [Addon] │ └── SMS [Addon] │ └── Templates ├── Email Templates └── Channel Templates [per addon] ``` ### Integration Points: ```php // Register channel add_filter('woonoow_notification_channels', function($channels) { $channels['whatsapp'] = [ 'id' => 'whatsapp', 'label' => 'WhatsApp', 'icon' => 'message-circle', ]; return $channels; }); // Send notification add_action('woonoow_notification_send_whatsapp', function($event, $data) { // Send WhatsApp message }, 10, 2); ``` ### Benefits: - ✅ Extensible (any channel via addons) - ✅ Flexible (multiple channels per event) - ✅ No bloat (core = email only) - ✅ Revenue opportunity (premium addons) - ✅ Community friendly (free addons welcome) --- ## Summary ✅ Login screen shows brand logo + tagline ✅ Settings submenu displays correctly ✅ Favicon works in standalone mode ✅ Notification strategy documented (addon-based) **Key Decision:** Notifications = Framework + Email core, everything else via addons **Ready to implement notification system!** --- NOTIFICATION_STRATEGY.md | 294 ++++++++++++++++++++++++ admin-spa/src/hooks/useActiveSection.ts | 6 + admin-spa/src/routes/Login.tsx | 44 +++- includes/Admin/StandaloneAdmin.php | 13 +- 4 files changed, 350 insertions(+), 7 deletions(-) create mode 100644 NOTIFICATION_STRATEGY.md diff --git a/NOTIFICATION_STRATEGY.md b/NOTIFICATION_STRATEGY.md new file mode 100644 index 0000000..e183ff6 --- /dev/null +++ b/NOTIFICATION_STRATEGY.md @@ -0,0 +1,294 @@ +# WooNooW Notification Strategy + +## Philosophy + +**Core Principle:** WooNooW provides the notification framework and email as the default channel. Additional channels (WhatsApp, Telegram, SMS, etc.) are provided by addons. + +--- + +## Architecture + +### Core (WooNooW Plugin) + +**Provides:** +1. **Notification Events System** + - Order placed + - Order status changed + - Low stock alert + - New customer registered + - etc. + +2. **Email Channel (Built-in)** + - Default notification channel + - Always available + - Template system + - Queue system for bulk sending + +3. **Notification Settings UI** + - Enable/disable notifications per event + - Configure which channels to use per event + - Template editor (for email) + - Channel-specific settings (provided by addons) + +4. **Addon Integration Points** + - `woonoow_notification_channels` filter - Register new channels + - `woonoow_notification_send_{channel}` action - Send via channel + - `woonoow_notification_settings_{channel}` filter - Channel settings UI + - `woonoow_notification_template_{channel}` filter - Channel templates + +--- + +## Settings Page Structure + +``` +Notifications +├── Events (What to notify) +│ ├── Orders +│ │ ├── Order Placed +│ │ │ ├── ✓ Email (to admin) +│ │ │ ├── ✓ WhatsApp (to customer) [if addon active] +│ │ │ └── ✗ Telegram +│ │ ├── Order Completed +│ │ ├── Order Cancelled +│ │ └── Order Refunded +│ ├── Products +│ │ ├── Low Stock Alert +│ │ └── Out of Stock Alert +│ └── Customers +│ ├── New Customer +│ └── Customer Note Added +│ +├── Channels (How to notify) +│ ├── Email (Built-in) ✓ +│ │ ├── From Name +│ │ ├── From Email +│ │ ├── SMTP Settings (optional) +│ │ └── Templates +│ ├── WhatsApp [Addon] +│ │ ├── API Key +│ │ ├── Phone Number +│ │ └── Message Templates +│ ├── Telegram [Addon] +│ │ ├── Bot Token +│ │ ├── Chat ID +│ │ └── Message Format +│ └── SMS [Addon] +│ ├── Provider (Twilio, etc.) +│ ├── API Credentials +│ └── Message Templates +│ +└── Templates + ├── Email Templates + ├── WhatsApp Templates [if addon active] + └── Telegram Templates [if addon active] +``` + +--- + +## Implementation + +### 1. Core Notification System + +```php +// includes/Core/Notifications/NotificationManager.php +class NotificationManager { + private $channels = []; + + public function register_channel($id, $label, $callback) { + $this->channels[$id] = [ + 'label' => $label, + 'callback' => $callback, + ]; + } + + public function send($event, $data, $channels = ['email']) { + foreach ($channels as $channel) { + if (isset($this->channels[$channel])) { + call_user_func($this->channels[$channel]['callback'], $event, $data); + } + } + } +} +``` + +### 2. Email Channel (Built-in) + +```php +// includes/Core/Notifications/Channels/EmailChannel.php +class EmailChannel { + public static function init() { + add_filter('woonoow_notification_channels', [__CLASS__, 'register']); + add_action('woonoow_notification_send_email', [__CLASS__, 'send'], 10, 2); + } + + public static function register($channels) { + $channels['email'] = [ + 'id' => 'email', + 'label' => 'Email', + 'icon' => 'mail', + 'builtin' => true, + ]; + return $channels; + } + + public static function send($event, $data) { + // Send email using WooNooW mail queue + } +} +``` + +### 3. Addon Example: WhatsApp Channel + +```php +// woonoow-whatsapp/includes/WhatsAppChannel.php +class WhatsAppChannel { + public static function init() { + add_filter('woonoow_notification_channels', [__CLASS__, 'register']); + add_action('woonoow_notification_send_whatsapp', [__CLASS__, 'send'], 10, 2); + add_filter('woonoow_notification_settings_whatsapp', [__CLASS__, 'settings']); + } + + public static function register($channels) { + $channels['whatsapp'] = [ + 'id' => 'whatsapp', + 'label' => 'WhatsApp', + 'icon' => 'message-circle', + 'addon' => 'woonoow-whatsapp', + ]; + return $channels; + } + + public static function send($event, $data) { + // Send WhatsApp message via API + } + + public static function settings() { + return [ + 'api_key' => get_option('woonoow_whatsapp_api_key'), + 'phone_number' => get_option('woonoow_whatsapp_phone'), + ]; + } +} +``` + +--- + +## Frontend (React SPA) + +### Notifications Settings Page + +```tsx +// admin-spa/src/routes/Settings/Notifications.tsx + +interface NotificationChannel { + id: string; + label: string; + icon: string; + builtin?: boolean; + addon?: string; + enabled: boolean; +} + +interface NotificationEvent { + id: string; + label: string; + description: string; + category: 'orders' | 'products' | 'customers'; + channels: { + [channelId: string]: { + enabled: boolean; + recipient: 'admin' | 'customer' | 'both'; + }; + }; +} + +export default function NotificationsPage() { + // Fetch available channels (core + addons) + const { data: channels } = useQuery({ + queryKey: ['notification-channels'], + queryFn: () => api.get('/notifications/channels'), + }); + + // Fetch notification events configuration + const { data: events } = useQuery({ + queryKey: ['notification-events'], + queryFn: () => api.get('/notifications/events'), + }); + + return ( + + {/* Available Channels */} + + {channels?.map(channel => ( + + ))} + + + {/* Events Configuration */} + + {events?.filter(e => e.category === 'orders').map(event => ( + + ))} + + + {/* More categories... */} + + ); +} +``` + +--- + +## Benefits + +1. **Extensible:** Addons can add any notification channel +2. **Flexible:** Each event can use multiple channels +3. **User-Friendly:** Clear UI showing what's available +4. **No Bloat:** Core only includes email +5. **Addon Revenue:** Premium channels (WhatsApp, SMS) can be paid addons + +--- + +## Example Addons + +### Free Addons +- **WooNooW Telegram** - Send notifications via Telegram bot +- **WooNooW Discord** - Send notifications to Discord channel + +### Premium Addons +- **WooNooW WhatsApp Pro** - WhatsApp Business API integration +- **WooNooW SMS** - SMS notifications via Twilio/Nexmo +- **WooNooW Push** - Browser push notifications +- **WooNooW Slack** - Team notifications via Slack + +--- + +## Migration Path + +**Phase 1 (Current):** +- Build notification framework +- Implement email channel +- Create settings UI with addon slots + +**Phase 2:** +- Build first addon (Telegram) as proof of concept +- Document addon API +- Create addon template + +**Phase 3:** +- Build premium addons (WhatsApp, SMS) +- Marketplace listing +- Community addons + +--- + +## Key Takeaway + +**WooNooW Core = Framework + Email** +**Everything Else = Addons** + +This keeps the core lean while providing unlimited extensibility for notification channels. diff --git a/admin-spa/src/hooks/useActiveSection.ts b/admin-spa/src/hooks/useActiveSection.ts index b98bc4e..5fb6605 100644 --- a/admin-spa/src/hooks/useActiveSection.ts +++ b/admin-spa/src/hooks/useActiveSection.ts @@ -5,6 +5,12 @@ export function useActiveSection(): { main: MainNode; all: MainNode[] } { const { pathname } = useLocation(); function pick(): MainNode { + // Special case: /settings should match settings section + if (pathname === '/settings' || pathname.startsWith('/settings/')) { + const settingsNode = navTree.find(n => n.key === 'settings'); + if (settingsNode) return settingsNode; + } + // Try to find section by matching path prefix for (const node of navTree) { if (node.path === '/') continue; // Skip dashboard for now diff --git a/admin-spa/src/routes/Login.tsx b/admin-spa/src/routes/Login.tsx index 60b46cf..dbf35bd 100644 --- a/admin-spa/src/routes/Login.tsx +++ b/admin-spa/src/routes/Login.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; @@ -12,8 +12,27 @@ export function Login() { const [password, setPassword] = useState(''); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(''); + const [branding, setBranding] = useState<{ logo: string; tagline: string; storeName: string }>({ + logo: '', + tagline: '', + storeName: 'WooNooW' + }); const navigate = useNavigate(); + // Fetch branding + useEffect(() => { + fetch((window.WNW_CONFIG?.restUrl || '') + '/store/settings') + .then(res => res.json()) + .then(data => { + setBranding({ + logo: data.store_logo || '', + tagline: data.store_tagline || '', + storeName: data.store_name || 'WooNooW' + }); + }) + .catch(err => console.error('Failed to load branding:', err)); + }, []); + const handleLogin = async (e: React.FormEvent) => { e.preventDefault(); setIsLoading(true); @@ -52,10 +71,23 @@ export function Login() {
{/* Logo */}
-

- WooNooW -

-

+ {branding.logo ? ( + {branding.storeName} + ) : ( +

+ {branding.storeName} +

+ )} + {branding.tagline && ( +

+ {branding.tagline} +

+ )} +

{__('Sign in to your admin dashboard')}

@@ -138,7 +170,7 @@ export function Login() { {/* Site Info */}
- {window.WNW_CONFIG?.siteName || 'WooNooW'} + {branding.storeName}
diff --git a/includes/Admin/StandaloneAdmin.php b/includes/Admin/StandaloneAdmin.php index 88f3091..6de652e 100644 --- a/includes/Admin/StandaloneAdmin.php +++ b/includes/Admin/StandaloneAdmin.php @@ -92,7 +92,18 @@ class StandaloneAdmin { - WooNooW Admin + <?php echo esc_html( get_option( 'blogname', 'WooNooW' ) ); ?> Admin + + + + +