From 3f2019bc7caf41cb1c0bac4f2147f85d5f0f1366 Mon Sep 17 00:00:00 2001 From: Dwindi Ramadhana Date: Thu, 12 Mar 2026 04:19:25 +0700 Subject: [PATCH] docs: consolidate markdown documentation into master guides and remove obsolete files --- ADDON_BRIDGE_PATTERN.md | 325 -- ADDON_DEVELOPMENT_GUIDE.md | 715 ----- ADDON_MODULE_DESIGN_DECISIONS.md | 616 ---- ADDON_MODULE_INTEGRATION.md | 476 --- ADDON_REACT_INTEGRATION.md | 499 ---- ARCHITECTURE_DECISION_CUSTOMER_SPA.md | 500 ---- CLEANUP_SUMMARY.md | 262 -- CUSTOMER_SPA_MASTER_PLAN.md | 749 ----- DOCS_CLEANUP_AUDIT.md | 191 -- FIXES_COMPLETE.md | 233 -- HASHROUTER_SOLUTION.md | 434 --- IMPLEMENTATION_STATUS.md | 270 -- MODULE_INTEGRATION_SUMMARY.md | 255 -- PHASE_2_3_4_SUMMARY.md | 379 --- PRODUCT_PAGE_COMPLETE.md | 400 --- PRODUCT_PAGE_CRITICAL_FIXES.md | 227 -- PRODUCT_PAGE_DECISION_FRAMEWORK.md | 517 ---- PRODUCT_PAGE_FIXES_IMPLEMENTED.md | 543 ---- PRODUCT_PAGE_IMPLEMENTATION.md | 331 -- PRODUCT_PAGE_IMPLEMENTATION_COMPLETE.md | 545 ---- PRODUCT_PAGE_RESEARCH_FIXES.md | 273 -- PRODUCT_PAGE_SOP.md | 436 --- RAJAONGKIR_INTEGRATION.md | 313 -- REDIRECT_DEBUG.md | 119 - SHIPPING_BRIDGE_PATTERN.md | 219 -- SHIPPING_INTEGRATION.md | 322 -- SHIPPING_METHOD_TYPES.md | 327 -- SPRINT_1-2_COMPLETION_REPORT.md | 415 --- SPRINT_3-4_PLAN.md | 288 -- STORE_UI_UX_GUIDE.md | 634 ---- admin-spa/BUGFIXES.md | 242 -- admin-spa/EMAIL_BUILDER_COMPLETE.md | 329 -- admin-spa/EMAIL_BUILDER_IMPROVEMENTS.md | 388 --- admin-spa/EMAIL_CUSTOMIZATION_COMPLETE.md | 310 -- admin-spa/EMAIL_UX_REFINEMENTS_COMPLETE.md | 532 ---- admin-spa/FINAL_UX_IMPROVEMENTS.md | 414 --- admin-spa/UX_IMPROVEMENTS.md | 424 --- archive/CALCULATION_EFFICIENCY_AUDIT.md | 368 --- archive/CUSTOMER_DATA_FLOW_ANALYSIS.md | 345 --- archive/PHASE_COMPLETE.md | 26 - archive/PRODUCT_FORM_UX_IMPROVEMENTS.md | 373 --- archive/PROGRESS_NOTE.md | 3147 -------------------- archive/TASKS_SUMMARY.md | 130 - docs/ADDONS_GUIDE.md | 185 ++ docs/CUSTOMER_SPA_ARCHITECTURE.md | 141 + docs/PRODUCT_PAGE_ARCHITECTURE.md | 91 + docs/SHIPPING_GUIDE.md | 186 ++ 47 files changed, 603 insertions(+), 18841 deletions(-) delete mode 100644 ADDON_BRIDGE_PATTERN.md delete mode 100644 ADDON_DEVELOPMENT_GUIDE.md delete mode 100644 ADDON_MODULE_DESIGN_DECISIONS.md delete mode 100644 ADDON_MODULE_INTEGRATION.md delete mode 100644 ADDON_REACT_INTEGRATION.md delete mode 100644 ARCHITECTURE_DECISION_CUSTOMER_SPA.md delete mode 100644 CLEANUP_SUMMARY.md delete mode 100644 CUSTOMER_SPA_MASTER_PLAN.md delete mode 100644 DOCS_CLEANUP_AUDIT.md delete mode 100644 FIXES_COMPLETE.md delete mode 100644 HASHROUTER_SOLUTION.md delete mode 100644 IMPLEMENTATION_STATUS.md delete mode 100644 MODULE_INTEGRATION_SUMMARY.md delete mode 100644 PHASE_2_3_4_SUMMARY.md delete mode 100644 PRODUCT_PAGE_COMPLETE.md delete mode 100644 PRODUCT_PAGE_CRITICAL_FIXES.md delete mode 100644 PRODUCT_PAGE_DECISION_FRAMEWORK.md delete mode 100644 PRODUCT_PAGE_FIXES_IMPLEMENTED.md delete mode 100644 PRODUCT_PAGE_IMPLEMENTATION.md delete mode 100644 PRODUCT_PAGE_IMPLEMENTATION_COMPLETE.md delete mode 100644 PRODUCT_PAGE_RESEARCH_FIXES.md delete mode 100644 PRODUCT_PAGE_SOP.md delete mode 100644 RAJAONGKIR_INTEGRATION.md delete mode 100644 REDIRECT_DEBUG.md delete mode 100644 SHIPPING_BRIDGE_PATTERN.md delete mode 100644 SHIPPING_INTEGRATION.md delete mode 100644 SHIPPING_METHOD_TYPES.md delete mode 100644 SPRINT_1-2_COMPLETION_REPORT.md delete mode 100644 SPRINT_3-4_PLAN.md delete mode 100644 STORE_UI_UX_GUIDE.md delete mode 100644 admin-spa/BUGFIXES.md delete mode 100644 admin-spa/EMAIL_BUILDER_COMPLETE.md delete mode 100644 admin-spa/EMAIL_BUILDER_IMPROVEMENTS.md delete mode 100644 admin-spa/EMAIL_CUSTOMIZATION_COMPLETE.md delete mode 100644 admin-spa/EMAIL_UX_REFINEMENTS_COMPLETE.md delete mode 100644 admin-spa/FINAL_UX_IMPROVEMENTS.md delete mode 100644 admin-spa/UX_IMPROVEMENTS.md delete mode 100644 archive/CALCULATION_EFFICIENCY_AUDIT.md delete mode 100644 archive/CUSTOMER_DATA_FLOW_ANALYSIS.md delete mode 100644 archive/PHASE_COMPLETE.md delete mode 100644 archive/PRODUCT_FORM_UX_IMPROVEMENTS.md delete mode 100644 archive/PROGRESS_NOTE.md delete mode 100644 archive/TASKS_SUMMARY.md create mode 100644 docs/ADDONS_GUIDE.md create mode 100644 docs/CUSTOMER_SPA_ARCHITECTURE.md create mode 100644 docs/PRODUCT_PAGE_ARCHITECTURE.md create mode 100644 docs/SHIPPING_GUIDE.md diff --git a/ADDON_BRIDGE_PATTERN.md b/ADDON_BRIDGE_PATTERN.md deleted file mode 100644 index 84f63f1..0000000 --- a/ADDON_BRIDGE_PATTERN.md +++ /dev/null @@ -1,325 +0,0 @@ -# Addon Bridge Pattern - Rajaongkir Example - -## Philosophy - -**WooNooW Core = Zero Addon Dependencies** - -We don't integrate specific addons into WooNooW core. Instead, we provide: -1. **Hook system** for addons to extend functionality -2. **Bridge snippets** for compatibility with existing plugins -3. **Addon development guide** for building proper WooNooW addons - ---- - -## Problem: Rajaongkir Plugin - -Rajaongkir is a WooCommerce plugin that: -- Removes standard address fields (city, state) -- Adds custom destination dropdown -- Stores data in WooCommerce session -- Works on WooCommerce checkout page - -**It doesn't work with WooNooW OrderForm because:** -- OrderForm uses standard WooCommerce fields -- Rajaongkir expects session-based destination -- No destination = No shipping calculation - ---- - -## Solution: Bridge Snippet (Not Core Integration!) - -### Option A: Standalone Bridge Plugin - -Create a tiny bridge plugin that makes Rajaongkir work with WooNooW: - -```php -search_destination_api($shipping_data['city']); - - if (!empty($results[0])) { - // Set Rajaongkir session data - WC()->session->set('selected_destination_id', $results[0]['id']); - WC()->session->set('selected_destination_label', $results[0]['text']); - } - } - - return $shipping_data; -}); - -// Add Rajaongkir destination field to OrderForm via hook system -add_action('wp_enqueue_scripts', function() { - if (!is_admin()) return; - - wp_enqueue_script( - 'woonoow-rajaongkir-bridge', - plugin_dir_url(__FILE__) . 'dist/bridge.js', - ['woonoow-admin'], - '1.0.0', - true - ); -}); -``` - -**Frontend (bridge.js):** - -```typescript -import { addonLoader, addFilter } from '@woonoow/hooks'; - -addonLoader.register({ - id: 'rajaongkir-bridge', - name: 'Rajaongkir Bridge', - version: '1.0.0', - init: () => { - // Add destination search field after shipping address - addFilter('woonoow_order_form_after_shipping', (content, formData, setFormData) => { - // Only for Indonesia - if (formData.shipping?.country !== 'ID') return content; - - return ( - <> - {content} -
-

๐Ÿ“ Shipping Destination

- { - setFormData({ - ...formData, - shipping: { - ...formData.shipping, - destination_id: id, - destination_label: label, - } - }); - }} - /> -
- - ); - }); - } -}); -``` - -### Option B: Code Snippet (No Plugin) - -For users who don't want a separate plugin, provide a code snippet: - -```php -// Add to theme's functions.php or custom plugin - -// Bridge Rajaongkir with WooNooW -add_filter('woonoow_shipping_data', function($data) { - if ($data['country'] === 'ID' && !empty($data['city'])) { - // Auto-search and set destination - $api = Cekongkir_API::get_instance(); - $results = $api->search_destination_api($data['city']); - if (!empty($results[0])) { - WC()->session->set('selected_destination_id', $results[0]['id']); - } - } - return $data; -}); -``` - ---- - -## Proper Solution: Build WooNooW Addon - -Instead of bridging Rajaongkir, build a proper WooNooW addon: - -**WooNooW Indonesia Shipping Addon** - -```php - 'indonesia-shipping', - 'name' => 'Indonesia Shipping', - 'version' => '1.0.0', - 'spa_bundle' => plugin_dir_url(__FILE__) . 'dist/addon.js', - 'dependencies' => ['woocommerce' => '8.0'], - ]; - return $addons; -}); - -// Add API endpoints -add_action('rest_api_init', function() { - register_rest_route('woonoow/v1', '/indonesia/search-destination', [ - 'methods' => 'GET', - 'callback' => function($req) { - $query = $req->get_param('query'); - $api = new RajaongkirAPI(get_option('rajaongkir_api_key')); - return $api->searchDestination($query); - }, - ]); - - register_rest_route('woonoow/v1', '/indonesia/calculate-shipping', [ - 'methods' => 'POST', - 'callback' => function($req) { - $origin = $req->get_param('origin'); - $destination = $req->get_param('destination'); - $weight = $req->get_param('weight'); - - $api = new RajaongkirAPI(get_option('rajaongkir_api_key')); - return $api->calculateShipping($origin, $destination, $weight); - }, - ]); -}); -``` - -**Frontend:** - -```typescript -// dist/addon.ts - -import { addonLoader, addFilter } from '@woonoow/hooks'; -import { DestinationSearch } from './components/DestinationSearch'; - -addonLoader.register({ - id: 'indonesia-shipping', - name: 'Indonesia Shipping', - version: '1.0.0', - init: () => { - // Add destination field - addFilter('woonoow_order_form_after_shipping', (content, formData, setFormData) => { - if (formData.shipping?.country !== 'ID') return content; - - return ( - <> - {content} - { - setFormData({ - ...formData, - shipping: { ...formData.shipping, destination_id: id, destination_label: label } - }); - }} - /> - - ); - }); - - // Add validation - addFilter('woonoow_order_form_validation', (errors, formData) => { - if (formData.shipping?.country === 'ID' && !formData.shipping?.destination_id) { - errors.destination = 'Please select shipping destination'; - } - return errors; - }); - } -}); -``` - ---- - -## Comparison - -### Bridge Snippet (Quick Fix) -โœ… Works immediately -โœ… No new plugin needed -โœ… Minimal code -โŒ Depends on Rajaongkir plugin -โŒ Limited features -โŒ Not ideal UX - -### Proper WooNooW Addon (Best Practice) -โœ… Native WooNooW integration -โœ… Better UX -โœ… More features -โœ… Independent of Rajaongkir plugin -โœ… Can use any shipping API -โŒ More development effort -โŒ Separate plugin to maintain - ---- - -## Recommendation - -**For WooNooW Core:** -- โŒ Don't integrate Rajaongkir -- โœ… Provide hook system -- โœ… Document bridge pattern -- โœ… Provide code snippets - -**For Users:** -- **Quick fix:** Use bridge snippet -- **Best practice:** Build proper addon or use community addon - -**For Community:** -- Build "WooNooW Indonesia Shipping" addon -- Publish on WordPress.org -- Support Rajaongkir, Biteship, and other Indonesian shipping APIs - ---- - -## Hook Points Needed in WooNooW Core - -To support addons like this, WooNooW core should provide: - -```php -// Before shipping calculation -apply_filters('woonoow_before_shipping_calculate', $shipping_data); - -// After shipping calculation -apply_filters('woonoow_after_shipping_calculate', $rates, $shipping_data); - -// Modify shipping data -apply_filters('woonoow_shipping_data', $data); -``` - -```typescript -// Frontend hooks -'woonoow_order_form_after_shipping' -'woonoow_order_form_shipping_fields' -'woonoow_order_form_validation' -'woonoow_order_form_submit' -``` - -**These hooks already exist in our addon system!** - ---- - -## Conclusion - -**WooNooW Core = Zero addon dependencies** - -Instead of integrating Rajaongkir into core: -1. Provide hook system โœ… (Already done) -2. Document bridge pattern โœ… (This document) -3. Encourage community addons โœ… - -This keeps WooNooW core: -- Clean -- Maintainable -- Flexible -- Extensible - -Users can choose: -- Bridge snippet (quick fix) -- Proper addon (best practice) -- Build their own - -**No bloat in core!** diff --git a/ADDON_DEVELOPMENT_GUIDE.md b/ADDON_DEVELOPMENT_GUIDE.md deleted file mode 100644 index 36e67fd..0000000 --- a/ADDON_DEVELOPMENT_GUIDE.md +++ /dev/null @@ -1,715 +0,0 @@ -# WooNooW Addon Development Guide - -**Version:** 2.0.0 -**Last Updated:** November 9, 2025 -**Status:** Production Ready - ---- - -## ๐Ÿ“‹ Table of Contents - -1. [Overview](#overview) -2. [Addon Types](#addon-types) -3. [Quick Start](#quick-start) -4. [SPA Route Injection](#spa-route-injection) -5. [Hook System Integration](#hook-system-integration) -6. [Component Development](#component-development) -7. [Best Practices](#best-practices) -8. [Examples](#examples) -9. [Troubleshooting](#troubleshooting) - ---- - -## Overview - -WooNooW provides **two powerful addon systems**: - -### 1. **SPA Route Injection** (Admin UI) -- โœ… Register custom SPA routes -- โœ… Inject navigation menu items -- โœ… Add submenu items to existing sections -- โœ… Load React components dynamically -- โœ… Full isolation and safety - -### 2. **Hook System** (Functional Extension) -- โœ… Extend OrderForm, ProductForm, etc. -- โœ… Add custom fields and validation -- โœ… Inject components at specific points -- โœ… Zero coupling with core -- โœ… WordPress-style filters and actions - -**Both systems work together seamlessly!** - ---- - -## Addon Types - -### Type A: UI-Only Addon (Route Injection) -**Use when:** Adding new pages/sections to admin - -**Example:** Reports, Analytics, Custom Dashboard - -```php -// Registers routes + navigation -add_filter('woonoow/spa_routes', ...); -add_filter('woonoow/nav_tree', ...); -``` - -### Type B: Functional Addon (Hook System) -**Use when:** Extending existing functionality - -**Example:** Indonesia Shipping, Custom Fields, Validation - -```typescript -// Registers hooks -addFilter('woonoow_order_form_after_shipping', ...); -addAction('woonoow_order_created', ...); -``` - -### Type C: Full-Featured Addon (Both Systems) -**Use when:** Complex integration needed - -**Example:** Subscriptions, Bookings, Memberships - -```php -// Backend: Routes + Hooks -add_filter('woonoow/spa_routes', ...); -add_filter('woonoow/nav_tree', ...); - -// Frontend: Hook registration -addonLoader.register({ - init: () => { - addFilter('woonoow_order_form_custom_sections', ...); - } -}); -``` - ---- - -## Quick Start - -### Step 1: Create Plugin File - -```php - 'my-addon', - 'name' => 'My Addon', - 'version' => '1.0.0', - 'spa_bundle' => plugin_dir_url(__FILE__) . 'dist/addon.js', - 'dependencies' => ['woocommerce' => '8.0'], - ]; - return $addons; -}); - -// 2. Register routes (optional - for UI pages) -add_filter('woonoow/spa_routes', function($routes) { - $routes[] = [ - 'path' => '/my-addon', - 'component_url' => plugin_dir_url(__FILE__) . 'dist/MyPage.js', - 'capability' => 'manage_woocommerce', - 'title' => 'My Addon', - ]; - return $routes; -}); - -// 3. Add navigation (optional - for UI pages) -add_filter('woonoow/nav_tree', function($tree) { - $tree[] = [ - 'key' => 'my-addon', - 'label' => 'My Addon', - 'path' => '/my-addon', - 'icon' => 'puzzle', - ]; - return $tree; -}); -``` - -### Step 2: Create Frontend Integration - -```typescript -// admin-spa/src/index.ts - -import { addonLoader, addFilter } from '@woonoow/hooks'; - -addonLoader.register({ - id: 'my-addon', - name: 'My Addon', - version: '1.0.0', - init: () => { - // Register hooks here - addFilter('woonoow_order_form_custom_sections', (content, formData, setFormData) => { - return ( - <> - {content} - - - ); - }); - } -}); -``` - -### Step 3: Build - -```bash -npm run build -``` - -**Done!** Your addon is now integrated. - ---- - -## SPA Route Injection - -### Register Routes - -```php -add_filter('woonoow/spa_routes', function($routes) { - $base_url = plugin_dir_url(__FILE__) . 'dist/'; - - $routes[] = [ - 'path' => '/subscriptions', - 'component_url' => $base_url . 'SubscriptionsList.js', - 'capability' => 'manage_woocommerce', - 'title' => 'Subscriptions', - ]; - - $routes[] = [ - 'path' => '/subscriptions/:id', - 'component_url' => $base_url . 'SubscriptionDetail.js', - 'capability' => 'manage_woocommerce', - 'title' => 'Subscription Detail', - ]; - - return $routes; -}); -``` - -### Add Navigation - -```php -// Main menu item -add_filter('woonoow/nav_tree', function($tree) { - $tree[] = [ - 'key' => 'subscriptions', - 'label' => __('Subscriptions', 'my-addon'), - 'path' => '/subscriptions', - 'icon' => 'repeat', - 'children' => [ - [ - 'label' => __('All Subscriptions', 'my-addon'), - 'mode' => 'spa', - 'path' => '/subscriptions', - ], - [ - 'label' => __('New', 'my-addon'), - 'mode' => 'spa', - 'path' => '/subscriptions/new', - ], - ], - ]; - return $tree; -}); - -// Or inject into existing section -add_filter('woonoow/nav_tree/products/children', function($children) { - $children[] = [ - 'label' => __('Bundles', 'my-addon'), - 'mode' => 'spa', - 'path' => '/products/bundles', - ]; - return $children; -}); -``` - ---- - -## Hook System Integration - -### Available Hooks - -#### Order Form Hooks -```typescript -// Add fields after billing address -'woonoow_order_form_after_billing' - -// Add fields after shipping address -'woonoow_order_form_after_shipping' - -// Add custom shipping fields -'woonoow_order_form_shipping_fields' - -// Add custom sections -'woonoow_order_form_custom_sections' - -// Add validation rules -'woonoow_order_form_validation' - -// Modify form data before render -'woonoow_order_form_data' -``` - -#### Action Hooks -```typescript -// Before form submission -'woonoow_order_form_submit' - -// After order created -'woonoow_order_created' - -// After order updated -'woonoow_order_updated' -``` - -### Hook Registration Example - -```typescript -import { addonLoader, addFilter, addAction } from '@woonoow/hooks'; - -addonLoader.register({ - id: 'indonesia-shipping', - name: 'Indonesia Shipping', - version: '1.0.0', - init: () => { - // Filter: Add subdistrict selector - addFilter('woonoow_order_form_after_shipping', (content, formData, setFormData) => { - return ( - <> - {content} - setFormData({ - ...formData, - shipping: { ...formData.shipping, subdistrict_id: id } - })} - /> - - ); - }); - - // Filter: Add validation - addFilter('woonoow_order_form_validation', (errors, formData) => { - if (!formData.shipping?.subdistrict_id) { - errors.subdistrict = 'Subdistrict is required'; - } - return errors; - }); - - // Action: Log when order created - addAction('woonoow_order_created', (orderId, orderData) => { - console.log('Order created:', orderId); - }); - } -}); -``` - -### Hook System Benefits - -โœ… **Zero Coupling** -```typescript -// WooNooW Core has no knowledge of your addon -{applyFilters('woonoow_order_form_after_shipping', null, formData, setFormData)} - -// If addon exists: Returns your component -// If addon doesn't exist: Returns null -// No import, no error! -``` - -โœ… **Multiple Addons Can Hook** -```typescript -// Addon A -addFilter('woonoow_order_form_after_shipping', (content) => { - return <>{content}; -}); - -// Addon B -addFilter('woonoow_order_form_after_shipping', (content) => { - return <>{content}; -}); - -// Both render! -``` - -โœ… **Type Safety** -```typescript -addFilter]>( - 'woonoow_order_form_after_shipping', - (content, formData, setFormData) => { - // TypeScript knows the types! - return ; - } -); -``` - ---- - -## Component Development - -### Basic Component - -```typescript -// dist/MyPage.tsx -import React from 'react'; - -export default function MyPage() { - return ( -
-
-

My Addon

-

Welcome!

-
-
- ); -} -``` - -### Access WooNooW APIs - -```typescript -// Access REST API -const api = (window as any).WNW_API; -const response = await fetch(`${api.root}my-addon/endpoint`, { - headers: { 'X-WP-Nonce': api.nonce }, -}); - -// Access store data -const store = (window as any).WNW_STORE; -console.log('Currency:', store.currency); - -// Access site info -const wnw = (window as any).wnw; -console.log('Site Title:', wnw.siteTitle); -``` - -### Use WooNooW Components - -```typescript -import { __ } from '@/lib/i18n'; -import { formatMoney } from '@/lib/currency'; -import { Button } from '@/components/ui/button'; -import { Card } from '@/components/ui/card'; - -export default function MyPage() { - return ( - -

{__('My Addon', 'my-addon')}

-

{formatMoney(1234.56)}

- -
- ); -} -``` - -### Build Configuration - -```javascript -// vite.config.js -import { defineConfig } from 'vite'; -import react from '@vitejs/plugin-react'; - -export default defineConfig({ - plugins: [react()], - build: { - lib: { - entry: 'src/index.ts', - name: 'MyAddon', - fileName: 'addon', - formats: ['es'], - }, - rollupOptions: { - external: ['react', 'react-dom'], - output: { - globals: { - react: 'React', - 'react-dom': 'ReactDOM', - }, - }, - }, - }, -}); -``` - ---- - -## Best Practices - -### โœ… DO: - -1. **Use Hook System for Functional Extensions** - ```typescript - // โœ… Good - No hardcoding - addFilter('woonoow_order_form_after_shipping', ...); - ``` - -2. **Use Route Injection for New Pages** - ```php - // โœ… Good - Separate UI - add_filter('woonoow/spa_routes', ...); - ``` - -3. **Declare Dependencies** - ```php - 'dependencies' => ['woocommerce' => '8.0'] - ``` - -4. **Check Capabilities** - ```php - 'capability' => 'manage_woocommerce' - ``` - -5. **Internationalize Strings** - ```php - 'label' => __('My Addon', 'my-addon') - ``` - -6. **Handle Errors Gracefully** - ```typescript - try { - await api.post(...); - } catch (error) { - toast.error('Failed to save'); - } - ``` - -### โŒ DON'T: - -1. **Don't Hardcode Addon Components in Core** - ```typescript - // โŒ Bad - Breaks if addon not installed - import { SubdistrictSelector } from 'addon'; - - - // โœ… Good - Use hooks - {applyFilters('woonoow_order_form_after_shipping', null)} - ``` - -2. **Don't Skip Capability Checks** - ```php - // โŒ Bad - 'capability' => '' - - // โœ… Good - 'capability' => 'manage_woocommerce' - ``` - -3. **Don't Modify Core Navigation** - ```php - // โŒ Bad - unset($tree[0]); - - // โœ… Good - $tree[] = ['key' => 'my-addon', ...]; - ``` - ---- - -## Examples - -### Example 1: Simple UI Addon (Route Injection Only) - -```php - 'reports', - 'name' => 'Reports', - 'version' => '1.0.0', - ]; - return $addons; -}); - -add_filter('woonoow/spa_routes', function($routes) { - $routes[] = [ - 'path' => '/reports', - 'component_url' => plugin_dir_url(__FILE__) . 'dist/Reports.js', - 'title' => 'Reports', - ]; - return $routes; -}); - -add_filter('woonoow/nav_tree', function($tree) { - $tree[] = [ - 'key' => 'reports', - 'label' => 'Reports', - 'path' => '/reports', - 'icon' => 'bar-chart', - ]; - return $tree; -}); -``` - -### Example 2: Functional Addon (Hook System Only) - -```typescript -// Indonesia Shipping - No UI pages, just extends OrderForm - -import { addonLoader, addFilter } from '@woonoow/hooks'; -import { SubdistrictSelector } from './components/SubdistrictSelector'; - -addonLoader.register({ - id: 'indonesia-shipping', - name: 'Indonesia Shipping', - version: '1.0.0', - init: () => { - addFilter('woonoow_order_form_after_shipping', (content, formData, setFormData) => { - return ( - <> - {content} -
-

๐Ÿ“ Shipping Destination

- setFormData({ - ...formData, - shipping: { ...formData.shipping, subdistrict_id: id } - })} - /> -
- - ); - }); - } -}); -``` - -### Example 3: Full-Featured Addon (Both Systems) - -```php - 'subscriptions', - 'name' => 'Subscriptions', - 'version' => '1.0.0', - 'spa_bundle' => plugin_dir_url(__FILE__) . 'dist/addon.js', - ]; - return $addons; -}); - -add_filter('woonoow/spa_routes', function($routes) { - $routes[] = [ - 'path' => '/subscriptions', - 'component_url' => plugin_dir_url(__FILE__) . 'dist/SubscriptionsList.js', - ]; - return $routes; -}); - -add_filter('woonoow/nav_tree', function($tree) { - $tree[] = [ - 'key' => 'subscriptions', - 'label' => 'Subscriptions', - 'path' => '/subscriptions', - 'icon' => 'repeat', - ]; - return $tree; -}); -``` - -```typescript -// Frontend: Hook integration - -import { addonLoader, addFilter } from '@woonoow/hooks'; - -addonLoader.register({ - id: 'subscriptions', - name: 'Subscriptions', - version: '1.0.0', - init: () => { - // Add subscription fields to order form - addFilter('woonoow_order_form_custom_sections', (content, formData, setFormData) => { - return ( - <> - {content} - - - ); - }); - - // Add subscription fields to product form - addFilter('woonoow_product_form_fields', (content, formData, setFormData) => { - return ( - <> - {content} - - - ); - }); - } -}); -``` - ---- - -## Troubleshooting - -### Addon Not Appearing? -- Check dependencies are met -- Verify capability requirements -- Check browser console for errors -- Flush caches: `?flush_wnw_cache=1` - -### Route Not Loading? -- Verify `component_url` is correct -- Check file exists and is accessible -- Look for JS errors in console -- Ensure component exports `default` - -### Hook Not Firing? -- Check hook name is correct -- Verify addon is registered -- Check `window.WNW_ADDONS` in console -- Ensure `init()` function runs - -### Component Not Rendering? -- Check for React errors in console -- Verify component returns valid JSX -- Check props are passed correctly -- Test component in isolation - ---- - -## Support & Resources - -**Documentation:** -- `ADDON_INJECTION_GUIDE.md` - SPA route injection (legacy) -- `ADDON_HOOK_SYSTEM.md` - Hook system details (legacy) -- `BITESHIP_ADDON_SPEC.md` - Indonesia shipping example -- `SHIPPING_ADDON_RESEARCH.md` - Shipping integration patterns - -**Code References:** -- `includes/Compat/AddonRegistry.php` - Addon registration -- `includes/Compat/RouteRegistry.php` - Route management -- `includes/Compat/NavigationRegistry.php` - Navigation building -- `admin-spa/src/lib/hooks.ts` - Hook system implementation -- `admin-spa/src/App.tsx` - Dynamic route loading - ---- - -**End of Guide** - -**Version:** 2.0.0 -**Last Updated:** November 9, 2025 -**Status:** โœ… Production Ready - -**This is the single source of truth for WooNooW addon development.** diff --git a/ADDON_MODULE_DESIGN_DECISIONS.md b/ADDON_MODULE_DESIGN_DECISIONS.md deleted file mode 100644 index f246cc7..0000000 --- a/ADDON_MODULE_DESIGN_DECISIONS.md +++ /dev/null @@ -1,616 +0,0 @@ -# Addon-Module Integration: Design Decisions - -**Date**: December 26, 2025 -**Status**: ๐ŸŽฏ Decision Document - ---- - -## 1. Dynamic Categories (RECOMMENDED) - -### โŒ Problem with Static Categories -```php -// BAD: Empty categories if no modules use them -public static function get_categories() { - return [ - 'shipping' => 'Shipping & Fulfillment', // Empty if no shipping modules! - 'payments' => 'Payments & Checkout', // Empty if no payment modules! - ]; -} -``` - -### โœ… Solution: Dynamic Category Generation - -```php -class ModuleRegistry { - - /** - * Get categories dynamically from registered modules - */ - public static function get_categories() { - $all_modules = self::get_all_modules(); - $categories = []; - - // Extract unique categories from modules - foreach ($all_modules as $module) { - $cat = $module['category'] ?? 'other'; - if (!isset($categories[$cat])) { - $categories[$cat] = self::get_category_label($cat); - } - } - - // Sort by predefined order (if exists), then alphabetically - $order = ['marketing', 'customers', 'products', 'shipping', 'payments', 'analytics', 'other']; - uksort($categories, function($a, $b) use ($order) { - $pos_a = array_search($a, $order); - $pos_b = array_search($b, $order); - if ($pos_a === false) $pos_a = 999; - if ($pos_b === false) $pos_b = 999; - return $pos_a - $pos_b; - }); - - return $categories; - } - - /** - * Get human-readable label for category - */ - private static function get_category_label($category) { - $labels = [ - 'marketing' => __('Marketing & Sales', 'woonoow'), - 'customers' => __('Customer Experience', 'woonoow'), - 'products' => __('Products & Inventory', 'woonoow'), - 'shipping' => __('Shipping & Fulfillment', 'woonoow'), - 'payments' => __('Payments & Checkout', 'woonoow'), - 'analytics' => __('Analytics & Reports', 'woonoow'), - 'other' => __('Other Extensions', 'woonoow'), - ]; - - return $labels[$category] ?? ucfirst($category); - } - - /** - * Group modules by category - */ - public static function get_grouped_modules() { - $all_modules = self::get_all_modules(); - $grouped = []; - - foreach ($all_modules as $module) { - $cat = $module['category'] ?? 'other'; - if (!isset($grouped[$cat])) { - $grouped[$cat] = []; - } - $grouped[$cat][] = $module; - } - - return $grouped; - } -} -``` - -### Benefits -- โœ… No empty categories -- โœ… Addons can define custom categories -- โœ… Single registration point (module only) -- โœ… Auto-sorted by predefined order - ---- - -## 2. Module Settings URL Pattern (RECOMMENDED) - -### โŒ Problem with Custom URLs -```php -'settings_url' => '/settings/shipping/biteship', // Conflict risk! -'settings_url' => '/marketing/newsletter', // Inconsistent! -``` - -### โœ… Solution: Convention-Based Pattern - -#### Option A: Standardized Pattern (RECOMMENDED) -```php -// Module registration - NO settings_url needed! -$addons['biteship-shipping'] = [ - 'id' => 'biteship-shipping', - 'name' => 'Biteship Shipping', - 'has_settings' => true, // Just a flag! -]; - -// Auto-generated URL pattern: -// /settings/modules/{module_id} -// Example: /settings/modules/biteship-shipping -``` - -#### Backend: Auto Route Registration -```php -class ModuleRegistry { - - /** - * Register module settings routes automatically - */ - public static function register_settings_routes() { - $modules = self::get_all_modules(); - - foreach ($modules as $module) { - if (empty($module['has_settings'])) continue; - - // Auto-register route: /settings/modules/{module_id} - add_filter('woonoow/spa_routes', function($routes) use ($module) { - $routes[] = [ - 'path' => "/settings/modules/{$module['id']}", - 'component_url' => $module['settings_component'] ?? null, - 'title' => sprintf(__('%s Settings', 'woonoow'), $module['label']), - ]; - return $routes; - }); - } - } -} -``` - -#### Frontend: Automatic Navigation -```tsx -// Modules.tsx - Gear icon auto-links -{module.has_settings && module.enabled && ( - -)} -``` - -### Benefits -- โœ… No URL conflicts (enforced pattern) -- โœ… Consistent navigation -- โœ… Simpler addon registration -- โœ… Auto-generated breadcrumbs - ---- - -## 3. Form Builder vs Custom HTML (HYBRID APPROACH) - -### โœ… Recommended: Provide Both Options - -#### Option A: Schema-Based Form Builder (For Simple Settings) -```php -// Addon defines settings schema -add_filter('woonoow/module_settings_schema', function($schemas) { - $schemas['biteship-shipping'] = [ - 'api_key' => [ - 'type' => 'text', - 'label' => 'API Key', - 'description' => 'Your Biteship API key', - 'required' => true, - ], - 'enable_tracking' => [ - 'type' => 'toggle', - 'label' => 'Enable Tracking', - 'default' => true, - ], - 'default_courier' => [ - 'type' => 'select', - 'label' => 'Default Courier', - 'options' => [ - 'jne' => 'JNE', - 'jnt' => 'J&T Express', - 'sicepat' => 'SiCepat', - ], - ], - ]; - return $schemas; -}); -``` - -**Auto-rendered form** - No React needed! - -#### Option B: Custom React Component (For Complex Settings) -```php -// Addon provides custom React component -add_filter('woonoow/addon_registry', function($addons) { - $addons['biteship-shipping'] = [ - 'id' => 'biteship-shipping', - 'has_settings' => true, - 'settings_component' => plugin_dir_url(__FILE__) . 'dist/Settings.js', - ]; - return $addons; -}); -``` - -**Full control** - Custom React UI - -### Implementation - -```php -class ModuleSettingsRenderer { - - /** - * Render settings page - */ - public static function render($module_id) { - $module = ModuleRegistry::get_module($module_id); - - // Option 1: Has custom component - if (!empty($module['settings_component'])) { - return self::render_custom_component($module); - } - - // Option 2: Has schema - auto-generate form - $schema = apply_filters('woonoow/module_settings_schema', []); - if (isset($schema[$module_id])) { - return self::render_schema_form($module_id, $schema[$module_id]); - } - - // Option 3: No settings - return ['error' => 'No settings available']; - } -} -``` - -### Benefits -- โœ… Simple addons use schema (no React needed) -- โœ… Complex addons use custom components -- โœ… Consistent data persistence for both -- โœ… Gradual complexity curve - ---- - -## 4. Settings Data Persistence (STANDARDIZED) - -### โœ… Recommended: Unified Settings API - -#### Backend: Automatic Persistence -```php -class ModuleSettingsController extends WP_REST_Controller { - - /** - * GET /woonoow/v1/modules/{module_id}/settings - */ - public function get_settings($request) { - $module_id = $request['module_id']; - $settings = get_option("woonoow_module_{$module_id}_settings", []); - - // Apply defaults from schema - $schema = apply_filters('woonoow/module_settings_schema', []); - if (isset($schema[$module_id])) { - $settings = wp_parse_args($settings, self::get_defaults($schema[$module_id])); - } - - return rest_ensure_response($settings); - } - - /** - * POST /woonoow/v1/modules/{module_id}/settings - */ - public function update_settings($request) { - $module_id = $request['module_id']; - $new_settings = $request->get_json_params(); - - // Validate against schema - $schema = apply_filters('woonoow/module_settings_schema', []); - if (isset($schema[$module_id])) { - $validated = self::validate_settings($new_settings, $schema[$module_id]); - if (is_wp_error($validated)) { - return $validated; - } - $new_settings = $validated; - } - - // Save - update_option("woonoow_module_{$module_id}_settings", $new_settings); - - // Allow addons to react - do_action("woonoow/module_settings_updated/{$module_id}", $new_settings); - - return rest_ensure_response(['success' => true]); - } -} -``` - -#### Frontend: Unified Hook -```tsx -// useModuleSettings.ts -export function useModuleSettings(moduleId: string) { - const queryClient = useQueryClient(); - - const { data: settings, isLoading } = useQuery({ - queryKey: ['module-settings', moduleId], - queryFn: async () => { - const response = await api.get(`/modules/${moduleId}/settings`); - return response; - }, - }); - - const updateSettings = useMutation({ - mutationFn: async (newSettings: any) => { - return api.post(`/modules/${moduleId}/settings`, newSettings); - }, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['module-settings', moduleId] }); - toast.success('Settings saved'); - }, - }); - - return { settings, isLoading, updateSettings }; -} -``` - -#### Addon Usage -```tsx -// Custom settings component -export default function BiteshipSettings() { - const { settings, updateSettings } = useModuleSettings('biteship-shipping'); - - return ( - - - updateSettings.mutate({ api_key: e.target.value })} - /> - - - ); -} -``` - -### Benefits -- โœ… Consistent storage pattern: `woonoow_module_{id}_settings` -- โœ… Automatic validation (if schema provided) -- โœ… React hook for easy access -- โœ… Action hooks for addon logic - ---- - -## 5. React Extension Pattern (DOCUMENTED) - -### โœ… Solution: Window API + Build Externals - -#### WooNooW Core Exposes React -```typescript -// admin-spa/src/main.tsx -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import { useQuery, useMutation } from '@tanstack/react-query'; - -// Expose for addons -window.WooNooW = { - React, - ReactDOM, - hooks: { - useQuery, - useMutation, - useModuleSettings, // Our custom hook! - }, - components: { - SettingsLayout, - SettingsCard, - Button, - Input, - Select, - Switch, - // ... all shadcn components - }, - utils: { - api, - toast, - }, -}; -``` - -#### Addon Development -```typescript -// addon/src/Settings.tsx -const { React, hooks, components, utils } = window.WooNooW; -const { useModuleSettings } = hooks; -const { SettingsLayout, SettingsCard, Input, Button } = components; -const { toast } = utils; - -export default function BiteshipSettings() { - const { settings, updateSettings } = useModuleSettings('biteship-shipping'); - const [apiKey, setApiKey] = React.useState(settings?.api_key || ''); - - const handleSave = () => { - updateSettings.mutate({ api_key: apiKey }); - }; - - return React.createElement(SettingsLayout, { title: 'Biteship Settings' }, - React.createElement(SettingsCard, null, - React.createElement(Input, { - label: 'API Key', - value: apiKey, - onChange: (e) => setApiKey(e.target.value), - }), - React.createElement(Button, { onClick: handleSave }, 'Save') - ) - ); -} -``` - -#### With JSX (Build Required) -```tsx -// addon/src/Settings.tsx -const { React, hooks, components } = window.WooNooW; -const { useModuleSettings } = hooks; -const { SettingsLayout, SettingsCard, Input, Button } = components; - -export default function BiteshipSettings() { - const { settings, updateSettings } = useModuleSettings('biteship-shipping'); - - return ( - - - updateSettings.mutate({ api_key: e.target.value })} - /> - - - ); -} -``` - -```javascript -// vite.config.js -export default { - build: { - lib: { - entry: 'src/Settings.tsx', - formats: ['es'], - }, - rollupOptions: { - external: ['react', 'react-dom'], - output: { - globals: { - react: 'window.WooNooW.React', - 'react-dom': 'window.WooNooW.ReactDOM', - }, - }, - }, - }, -}; -``` - -### Benefits -- โœ… Addons don't bundle React (use ours) -- โœ… Access to all WooNooW components -- โœ… Consistent UI automatically -- โœ… Type safety with TypeScript - ---- - -## 6. Newsletter as Addon Example (RECOMMENDED) - -### โœ… Yes, Refactor Newsletter as Built-in Addon - -#### Why This is Valuable - -1. **Dogfooding** - We use our own addon system -2. **Example** - Best reference for addon developers -3. **Consistency** - Newsletter follows same pattern as external addons -4. **Testing** - Proves the system works - -#### Proposed Structure - -``` -includes/ - Modules/ - Newsletter/ - NewsletterModule.php # Module registration - NewsletterController.php # API endpoints (moved from Api/) - NewsletterSettings.php # Settings schema - -admin-spa/src/modules/ - Newsletter/ - Settings.tsx # Settings page - Subscribers.tsx # Subscribers page - index.ts # Module exports -``` - -#### Registration Pattern -```php -// includes/Modules/Newsletter/NewsletterModule.php -class NewsletterModule { - - public static function register() { - // Register as module - add_filter('woonoow/builtin_modules', function($modules) { - $modules['newsletter'] = [ - 'id' => 'newsletter', - 'label' => __('Newsletter', 'woonoow'), - 'description' => __('Email newsletter subscriptions', 'woonoow'), - 'category' => 'marketing', - 'icon' => 'mail', - 'default_enabled' => true, - 'has_settings' => true, - 'settings_component' => self::get_settings_url(), - ]; - return $modules; - }); - - // Register routes (only if enabled) - if (ModuleRegistry::is_enabled('newsletter')) { - self::register_routes(); - } - } - - private static function register_routes() { - // Settings route - add_filter('woonoow/spa_routes', function($routes) { - $routes[] = [ - 'path' => '/settings/modules/newsletter', - 'component_url' => plugins_url('admin-spa/dist/modules/Newsletter/Settings.js', WOONOOW_FILE), - ]; - return $routes; - }); - - // Subscribers route - add_filter('woonoow/spa_routes', function($routes) { - $routes[] = [ - 'path' => '/marketing/newsletter', - 'component_url' => plugins_url('admin-spa/dist/modules/Newsletter/Subscribers.js', WOONOOW_FILE), - ]; - return $routes; - }); - } -} -``` - -### Benefits -- โœ… Newsletter becomes reference implementation -- โœ… Proves addon system works for complex modules -- โœ… Shows best practices -- โœ… Easier to maintain (follows pattern) - ---- - -## Summary of Decisions - -| # | Question | Decision | Rationale | -|---|----------|----------|-----------| -| 1 | Categories | **Dynamic from modules** | No empty categories, single registration | -| 2 | Settings URL | **Pattern: `/settings/modules/{id}`** | No conflicts, consistent, auto-generated | -| 3 | Form Builder | **Hybrid: Schema + Custom** | Simple for basic, flexible for complex | -| 4 | Data Persistence | **Unified API + Hook** | Consistent storage, easy access | -| 5 | React Extension | **Window API + Externals** | No bundling, access to components | -| 6 | Newsletter Refactor | **Yes, as example** | Dogfooding, reference implementation | - ---- - -## Implementation Order - -### Phase 1: Foundation -1. โœ… Dynamic category generation -2. โœ… Standardized settings URL pattern -3. โœ… Module settings API endpoints -4. โœ… `useModuleSettings` hook - -### Phase 2: Form System -1. โœ… Schema-based form renderer -2. โœ… Custom component loader -3. โœ… Settings validation - -### Phase 3: UI Enhancement -1. โœ… Search input on Modules page -2. โœ… Category filter pills -3. โœ… Gear icon with auto-routing - -### Phase 4: Example -1. โœ… Refactor Newsletter as built-in addon -2. โœ… Document pattern -3. โœ… Create external addon example (Biteship) - ---- - -## Next Steps - -**Ready to implement?** We have clear decisions on all 6 questions. Should we: - -1. Start with Phase 1 (Foundation)? -2. Create the schema-based form system first? -3. Refactor Newsletter as proof-of-concept? - -**Your call!** All design decisions are documented and justified. diff --git a/ADDON_MODULE_INTEGRATION.md b/ADDON_MODULE_INTEGRATION.md deleted file mode 100644 index c6d1664..0000000 --- a/ADDON_MODULE_INTEGRATION.md +++ /dev/null @@ -1,476 +0,0 @@ -# Addon-Module Integration Strategy - -**Date**: December 26, 2025 -**Status**: ๐ŸŽฏ Proposal - ---- - -## Vision - -**Module Registry as the Single Source of Truth for all extensions** - both built-in modules and external addons. - ---- - -## Current State Analysis - -### What We Have - -#### 1. **Module System** (Just Built) -- `ModuleRegistry.php` - Manages built-in modules -- Enable/disable functionality -- Module metadata (label, description, features, icon) -- Categories (Marketing, Customers, Products) -- Settings page UI with toggles - -#### 2. **Addon System** (Existing) -- `AddonRegistry.php` - Manages external addons -- SPA route injection -- Hook system integration -- Navigation tree injection -- React component loading - -### The Opportunity - -**These two systems should be unified!** An addon is just an external module. - ---- - -## Proposed Integration - -### Concept: Unified Extension Registry - -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ Module Registry (Single Source) โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ โ”‚ -โ”‚ Built-in Modules External Addons โ”‚ -โ”‚ โ”œโ”€ Newsletter โ”œโ”€ Biteship Shipping โ”‚ -โ”‚ โ”œโ”€ Wishlist โ”œโ”€ Subscriptions โ”‚ -โ”‚ โ”œโ”€ Affiliate โ”œโ”€ Bookings โ”‚ -โ”‚ โ”œโ”€ Subscription โ””โ”€ Custom Reports โ”‚ -โ”‚ โ””โ”€ Licensing โ”‚ -โ”‚ โ”‚ -โ”‚ All share same interface: โ”‚ -โ”‚ โ€ข Enable/disable toggle โ”‚ -โ”‚ โ€ข Settings page (optional) โ”‚ -โ”‚ โ€ข Icon & metadata โ”‚ -โ”‚ โ€ข Feature list โ”‚ -โ”‚ โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - ---- - -## Implementation Plan - -### Phase 1: Extend Module Registry for Addons - -#### Backend: ModuleRegistry.php Enhancement - -```php -class ModuleRegistry { - - /** - * Get all modules (built-in + addons) - */ - public static function get_all_modules() { - $builtin = self::get_builtin_modules(); - $addons = self::get_addon_modules(); - - return array_merge($builtin, $addons); - } - - /** - * Get addon modules from AddonRegistry - */ - private static function get_addon_modules() { - $addons = apply_filters('woonoow/addon_registry', []); - $modules = []; - - foreach ($addons as $addon_id => $addon) { - $modules[$addon_id] = [ - 'id' => $addon_id, - 'label' => $addon['name'], - 'description' => $addon['description'] ?? '', - 'category' => $addon['category'] ?? 'addons', - 'icon' => $addon['icon'] ?? 'puzzle', - 'default_enabled' => false, - 'features' => $addon['features'] ?? [], - 'is_addon' => true, - 'version' => $addon['version'] ?? '1.0.0', - 'author' => $addon['author'] ?? '', - 'settings_url' => $addon['settings_url'] ?? '', // NEW! - ]; - } - - return $modules; - } -} -``` - -#### Addon Registration Enhancement - -```php -// Addon developers register with enhanced metadata -add_filter('woonoow/addon_registry', function($addons) { - $addons['biteship-shipping'] = [ - 'id' => 'biteship-shipping', - 'name' => 'Biteship Shipping', - 'description' => 'Indonesia shipping with Biteship API', - 'version' => '1.0.0', - 'author' => 'WooNooW Team', - 'category' => 'shipping', // NEW! - 'icon' => 'truck', // NEW! - 'features' => [ // NEW! - 'Real-time shipping rates', - 'Multiple couriers', - 'Tracking integration', - ], - 'settings_url' => '/settings/shipping/biteship', // NEW! - 'spa_bundle' => plugin_dir_url(__FILE__) . 'dist/addon.js', - ]; - return $addons; -}); -``` - ---- - -### Phase 2: Module Settings Page with Gear Icon - -#### UI Enhancement: Modules.tsx - -```tsx -{modules.map((module) => ( -
- {/* Icon */} -
- {getIcon(module.icon)} -
- - {/* Content */} -
-
-

{module.label}

- {module.enabled && Active} - {module.is_addon && Addon} -
-

{module.description}

- - {/* Features */} -
    - {module.features.map((feature, i) => ( -
  • - โ€ข {feature} -
  • - ))} -
-
- - {/* Actions */} -
- {/* Settings Gear Icon - Only if module has settings */} - {module.settings_url && module.enabled && ( - - )} - - {/* Enable/Disable Toggle */} - toggleModule.mutate({ moduleId: module.id, enabled })} - /> -
-
-))} -``` - ---- - -### Phase 3: Dynamic Categories - -#### Support for Addon Categories - -```php -// ModuleRegistry.php -public static function get_categories() { - return [ - 'marketing' => __('Marketing & Sales', 'woonoow'), - 'customers' => __('Customer Experience', 'woonoow'), - 'products' => __('Products & Inventory', 'woonoow'), - 'shipping' => __('Shipping & Fulfillment', 'woonoow'), // NEW! - 'payments' => __('Payments & Checkout', 'woonoow'), // NEW! - 'analytics' => __('Analytics & Reports', 'woonoow'), // NEW! - 'addons' => __('Other Extensions', 'woonoow'), // Fallback - ]; -} -``` - -#### Frontend: Dynamic Category Rendering - -```tsx -// Modules.tsx -const { data: modulesData } = useQuery({ - queryKey: ['modules'], - queryFn: async () => { - const response = await api.get('/modules'); - return response as ModulesData; - }, -}); - -// Get unique categories from modules -const categories = Object.keys(modulesData?.grouped || {}); - -return ( - - {categories.map((category) => { - const modules = modulesData.grouped[category] || []; - if (modules.length === 0) return null; - - return ( - - {/* Module cards */} - - ); - })} - -); -``` - ---- - -## Benefits - -### 1. **Unified Management** -- โœ… One place to see all extensions (built-in + addons) -- โœ… Consistent enable/disable interface -- โœ… Unified metadata (icon, description, features) - -### 2. **Better UX** -- โœ… Users don't need to distinguish between "modules" and "addons" -- โœ… Settings gear icon for quick access to module configuration -- โœ… Clear visual indication of what's enabled - -### 3. **Developer Experience** -- โœ… Addon developers use familiar pattern -- โœ… Automatic integration with module system -- โœ… No extra work to appear in Modules page - -### 4. **Extensibility** -- โœ… Dynamic categories support any addon type -- โœ… Settings URL allows deep linking to config -- โœ… Version and author info for better management - ---- - -## Example: Biteship Addon Integration - -### Addon Registration (PHP) - -```php - 'biteship-shipping', - 'name' => 'Biteship Shipping', - 'description' => 'Real-time shipping rates from Indonesian couriers', - 'version' => '1.0.0', - 'author' => 'WooNooW Team', - 'category' => 'shipping', - 'icon' => 'truck', - 'features' => [ - 'JNE, J&T, SiCepat, and more', - 'Real-time rate calculation', - 'Shipment tracking', - 'Automatic label printing', - ], - 'settings_url' => '/settings/shipping/biteship', - 'spa_bundle' => plugin_dir_url(__FILE__) . 'dist/addon.js', - ]; - return $addons; -}); - -// Register settings route -add_filter('woonoow/spa_routes', function($routes) { - $routes[] = [ - 'path' => '/settings/shipping/biteship', - 'component_url' => plugin_dir_url(__FILE__) . 'dist/Settings.js', - 'title' => 'Biteship Settings', - ]; - return $routes; -}); -``` - -### Result in Modules Page - -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ Shipping & Fulfillment โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ โ”‚ -โ”‚ ๐Ÿšš Biteship Shipping [โš™๏ธ] [Toggle] โ”‚ -โ”‚ Real-time shipping rates from Indonesian... โ”‚ -โ”‚ โ€ข JNE, J&T, SiCepat, and more โ”‚ -โ”‚ โ€ข Real-time rate calculation โ”‚ -โ”‚ โ€ข Shipment tracking โ”‚ -โ”‚ โ€ข Automatic label printing โ”‚ -โ”‚ โ”‚ -โ”‚ Version: 1.0.0 | By: WooNooW Team | [Addon] โ”‚ -โ”‚ โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - -Clicking โš™๏ธ navigates to `/settings/shipping/biteship` - ---- - -## Migration Path - -### Step 1: Enhance ModuleRegistry (Backward Compatible) -- Add `get_addon_modules()` method -- Merge built-in + addon modules -- No breaking changes - -### Step 2: Update Modules UI -- Add gear icon for settings -- Add "Addon" badge -- Support dynamic categories - -### Step 3: Document for Addon Developers -- Update ADDON_DEVELOPMENT_GUIDE.md -- Add examples with new metadata -- Show settings page pattern - -### Step 4: Update Existing Addons (Optional) -- Addons work without changes -- Enhanced metadata is optional -- Settings URL is optional - ---- - -## API Changes - -### New Module Properties - -```typescript -interface Module { - id: string; - label: string; - description: string; - category: string; - icon: string; - default_enabled: boolean; - features: string[]; - enabled: boolean; - - // NEW for addons - is_addon?: boolean; - version?: string; - author?: string; - settings_url?: string; // Route to settings page -} -``` - -### New API Endpoint (Optional) - -```php -// GET /woonoow/v1/modules/:module_id/settings -// Returns module-specific settings schema -``` - ---- - -## Settings Page Pattern - -### Option 1: Dedicated Route (Recommended) - -```php -// Addon registers its own settings route -add_filter('woonoow/spa_routes', function($routes) { - $routes[] = [ - 'path' => '/settings/my-addon', - 'component_url' => plugin_dir_url(__FILE__) . 'dist/Settings.js', - ]; - return $routes; -}); -``` - -### Option 2: Modal/Drawer (Alternative) - -```tsx -// Modules page opens modal with addon settings - - - - - -``` - ---- - -## Backward Compatibility - -### Existing Addons Continue to Work -- โœ… No breaking changes -- โœ… Enhanced metadata is optional -- โœ… Addons without metadata still function -- โœ… Gradual migration path - -### Existing Modules Unaffected -- โœ… Built-in modules work as before -- โœ… No changes to existing module logic -- โœ… Only UI enhancement - ---- - -## Summary - -### What This Achieves - -1. **Newsletter Footer Integration** โœ… - - Newsletter form respects module status - - Hidden from footer builder when disabled - -2. **Addon-Module Unification** ๐ŸŽฏ - - Addons appear in Module Registry - - Same enable/disable interface - - Settings gear icon for configuration - -3. **Better Developer Experience** ๐ŸŽฏ - - Consistent registration pattern - - Automatic UI integration - - Optional settings page routing - -4. **Better User Experience** ๐ŸŽฏ - - One place to manage all extensions - - Clear visual hierarchy - - Quick access to settings - -### Next Steps - -1. โœ… Newsletter footer integration (DONE) -2. ๐ŸŽฏ Enhance ModuleRegistry for addon support -3. ๐ŸŽฏ Add settings URL support to Modules UI -4. ๐ŸŽฏ Update documentation -5. ๐ŸŽฏ Create example addon with settings - ---- - -**This creates a truly unified extension system where built-in modules and external addons are first-class citizens with the same management interface.** diff --git a/ADDON_REACT_INTEGRATION.md b/ADDON_REACT_INTEGRATION.md deleted file mode 100644 index b57665c..0000000 --- a/ADDON_REACT_INTEGRATION.md +++ /dev/null @@ -1,499 +0,0 @@ -# Addon React Integration - How It Works - -## The Question - -**"How can addon developers use React if we only ship built `app.js`?"** - -You're absolutely right to question this! Let me clarify the architecture. - ---- - -## Current Misunderstanding - -**What I showed in examples:** -```tsx -// This WON'T work for external addons! -import { addonLoader, addFilter } from '@woonoow/hooks'; -import { DestinationSearch } from './components/DestinationSearch'; - -addonLoader.register({ - id: 'rajaongkir-bridge', - init: () => { - addFilter('woonoow_order_form_after_shipping', (content) => { - return ; // โŒ Can't do this! - }); - } -}); -``` - -**Problem:** External addons can't import React components because: -1. They don't have access to our build pipeline -2. They only get the compiled `app.js` -3. React is bundled, not exposed - ---- - -## Solution: Three Integration Levels - -### **Level 1: Vanilla JS/jQuery** (Basic) - -**For simple addons that just need to inject HTML/JS** - -```javascript -// addon-bridge.js (vanilla JS, no build needed) -(function() { - // Wait for WooNooW to load - window.addEventListener('woonoow:loaded', function() { - // Access WooNooW hooks - window.WooNooW.addFilter('woonoow_order_form_after_shipping', function(container, formData) { - // Inject HTML - const div = document.createElement('div'); - div.innerHTML = ` -
- - -
- `; - container.appendChild(div); - - // Add event listeners - document.getElementById('rajaongkir-dest').addEventListener('change', function(e) { - // Update WooNooW state - window.WooNooW.updateFormData({ - shipping: { - ...formData.shipping, - destination_id: e.target.value - } - }); - }); - - return container; - }); - }); -})(); -``` - -**Pros:** -- โœ… No build process needed -- โœ… Works immediately -- โœ… Easy for PHP developers -- โœ… No dependencies - -**Cons:** -- โŒ No React benefits -- โŒ Manual DOM manipulation -- โŒ No type safety - ---- - -### **Level 2: Exposed React Runtime** (Recommended) - -**WooNooW exposes React on window for addons to use** - -#### WooNooW Core Setup: - -```typescript -// admin-spa/src/main.tsx -import React from 'react'; -import ReactDOM from 'react-dom/client'; - -// Expose React for addons -window.WooNooW = { - React: React, - ReactDOM: ReactDOM, - hooks: { - addFilter: addFilter, - addAction: addAction, - // ... other hooks - }, - components: { - // Expose common components - Button: Button, - Input: Input, - Select: Select, - // ... other UI components - } -}; -``` - -#### Addon Development (with build): - -```javascript -// addon-bridge.js (built with Vite/Webpack) -const { React, hooks, components } = window.WooNooW; -const { addFilter } = hooks; -const { Button, Select } = components; - -// Addon can now use React! -function DestinationSearch({ value, onChange }) { - const [destinations, setDestinations] = React.useState([]); - const [loading, setLoading] = React.useState(false); - - React.useEffect(() => { - // Fetch destinations - fetch('/wp-json/rajaongkir/v1/destinations') - .then(res => res.json()) - .then(data => setDestinations(data)); - }, []); - - return React.createElement('div', { className: 'rajaongkir-search' }, - React.createElement('label', null, 'Shipping Destination'), - React.createElement(Select, { - value: value, - onChange: onChange, - options: destinations, - loading: loading - }) - ); -} - -// Register with WooNooW -addFilter('woonoow_order_form_after_shipping', function(container, formData, setFormData) { - const root = ReactDOM.createRoot(container); - root.render( - React.createElement(DestinationSearch, { - value: formData.shipping?.destination_id, - onChange: (value) => setFormData({ - ...formData, - shipping: { ...formData.shipping, destination_id: value } - }) - }) - ); - return container; -}); -``` - -**Addon Build Setup:** - -```javascript -// vite.config.js -export default { - build: { - lib: { - entry: 'src/addon.js', - name: 'RajaongkirBridge', - fileName: 'addon' - }, - rollupOptions: { - external: ['react', 'react-dom'], // Don't bundle React - output: { - globals: { - react: 'window.WooNooW.React', - 'react-dom': 'window.WooNooW.ReactDOM' - } - } - } - } -}; -``` - -**Pros:** -- โœ… Can use React -- โœ… Access to WooNooW components -- โœ… Better DX -- โœ… Type safety (with TypeScript) - -**Cons:** -- โŒ Requires build process -- โŒ More complex setup - ---- - -### **Level 3: Slot-Based Rendering** (Advanced) - -**WooNooW renders addon components via slots** - -#### WooNooW Core: - -```typescript -// OrderForm.tsx -function OrderForm() { - // ... form logic - - return ( -
- {/* ... shipping fields ... */} - - {/* Slot for addons to inject */} - -
- ); -} - -// AddonSlot.tsx -function AddonSlot({ name, props }) { - const slots = useAddonSlots(name); - - return ( - <> - {slots.map((slot, index) => ( -
- {slot.component(props)} -
- ))} - - ); -} -``` - -#### Addon Registration (PHP): - -```php -// rajaongkir-bridge.php -add_filter('woonoow/addon_slots', function($slots) { - $slots['order_form_after_shipping'][] = [ - 'id' => 'rajaongkir-destination', - 'component' => 'RajaongkirDestination', // Component name - 'script' => plugin_dir_url(__FILE__) . 'dist/addon.js', - 'priority' => 10, - ]; - return $slots; -}); -``` - -#### Addon Component (React with build): - -```typescript -// addon/src/DestinationSearch.tsx -import React, { useState, useEffect } from 'react'; - -export function RajaongkirDestination({ formData, setFormData }) { - const [destinations, setDestinations] = useState([]); - - useEffect(() => { - fetch('/wp-json/rajaongkir/v1/destinations') - .then(res => res.json()) - .then(setDestinations); - }, []); - - return ( -
- - -
- ); -} - -// Export for WooNooW to load -window.WooNooWAddons = window.WooNooWAddons || {}; -window.WooNooWAddons.RajaongkirDestination = RajaongkirDestination; -``` - -**Pros:** -- โœ… Full React support -- โœ… Type safety -- โœ… Modern DX -- โœ… Proper component lifecycle - -**Cons:** -- โŒ Most complex -- โŒ Requires build process -- โŒ More WooNooW core complexity - ---- - -## Recommended Approach: Level 2 (Exposed React) - -### Implementation in WooNooW Core: - -```typescript -// admin-spa/src/main.tsx -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import { QueryClient } from '@tanstack/react-query'; - -// UI Components -import { Button } from '@/components/ui/button'; -import { Input } from '@/components/ui/input'; -import { Select } from '@/components/ui/select'; -import { Label } from '@/components/ui/label'; -// ... other components - -// Hooks -import { addFilter, addAction, applyFilters, doAction } from '@/lib/hooks'; - -// Expose WooNooW API -window.WooNooW = { - // React runtime - React: React, - ReactDOM: ReactDOM, - - // Hooks system - hooks: { - addFilter, - addAction, - applyFilters, - doAction, - }, - - // UI Components (shadcn/ui) - components: { - Button, - Input, - Select, - Label, - // ... expose commonly used components - }, - - // Utilities - utils: { - api: api, // API client - toast: toast, // Toast notifications - }, - - // Version - version: '1.0.0', -}; - -// Emit loaded event -window.dispatchEvent(new CustomEvent('woonoow:loaded')); -``` - -### Addon Developer Experience: - -#### Option 1: Vanilla JS (No Build) - -```javascript -// addon.js -(function() { - const { React, hooks, components } = window.WooNooW; - const { addFilter } = hooks; - const { Select } = components; - - addFilter('woonoow_order_form_after_shipping', function(container, props) { - // Use React.createElement (no JSX) - const element = React.createElement(Select, { - label: 'Destination', - options: [...], - value: props.formData.shipping?.destination_id, - onChange: (value) => props.setFormData({...}) - }); - - const root = ReactDOM.createRoot(container); - root.render(element); - - return container; - }); -})(); -``` - -#### Option 2: With Build (JSX Support) - -```typescript -// addon/src/index.tsx -const { React, hooks, components } = window.WooNooW; -const { addFilter } = hooks; -const { Select } = components; - -function DestinationSearch({ formData, setFormData }) { - return ( - - - - {/* Large gap here */} - - - -// AFTER: -
-
- Quantity: -
- - - -
-
- -
-``` - -**Result:** -- โœ… Tighter spacing (space-y-3 instead of space-y-4) -- โœ… Label added for clarity -- โœ… Smaller padding (p-2.5 instead of p-3) -- โœ… Narrower input (w-14 instead of w-16) -- โœ… Visual grouping improved - ---- - -## ๐Ÿ”„ PENDING FIXES (Next Phase) - -### Fix #6: Reviews Hierarchy (HIGH PRIORITY) - -**Current:** Reviews collapsed in accordion at bottom -**Required:** Reviews prominent, auto-expanded, BEFORE description - -**Implementation Plan:** -```tsx -// Reorder sections -
- {/* 1. Product Info (above fold) */} - - - {/* 2. Reviews FIRST (auto-expanded) - Issue #6 */} -
-
-

Customer Reviews

-
- - 4.8 - (127 reviews) -
-
- - {/* Show 3-5 recent reviews */} - - -
- - {/* 3. Description (auto-expanded) */} -
-

Product Description

-
-
- - {/* 4. Specifications (collapsed) */} - - - -
-``` - -**Research Support:** -- Spiegel Research: 270% conversion boost -- Reviews are #1 factor in purchase decisions -- Tokopedia shows reviews BEFORE description -- Shopify shows reviews auto-expanded - ---- - -### Fix #7: Admin Appearance Menu (MEDIUM PRIORITY) - -**Current:** No appearance settings -**Required:** Admin menu for store customization - -**Implementation Plan:** - -#### 1. Add to NavigationRegistry.php: -```php -private static function get_base_tree(): array { - return [ - // ... existing sections ... - - [ - 'key' => 'appearance', - 'label' => __('Appearance', 'woonoow'), - 'path' => '/appearance', - 'icon' => 'palette', - 'children' => [ - ['label' => __('Store Style', 'woonoow'), 'mode' => 'spa', 'path' => '/appearance/store-style'], - ['label' => __('Trust Badges', 'woonoow'), 'mode' => 'spa', 'path' => '/appearance/trust-badges'], - ['label' => __('Product Alerts', 'woonoow'), 'mode' => 'spa', 'path' => '/appearance/product-alerts'], - ], - ], - - // Settings comes after Appearance - [ - 'key' => 'settings', - // ... - ], - ]; -} -``` - -#### 2. Create REST API Endpoints: -```php -// includes/Admin/Rest/AppearanceController.php -class AppearanceController { - public static function register() { - register_rest_route('wnw/v1', '/appearance/settings', [ - 'methods' => 'GET', - 'callback' => [__CLASS__, 'get_settings'], - ]); - - register_rest_route('wnw/v1', '/appearance/settings', [ - 'methods' => 'POST', - 'callback' => [__CLASS__, 'update_settings'], - ]); - } - - public static function get_settings() { - return [ - 'layout_style' => get_option('wnw_layout_style', 'boxed'), - 'container_width' => get_option('wnw_container_width', '1200'), - 'trust_badges' => get_option('wnw_trust_badges', self::get_default_badges()), - 'show_coupon_alert' => get_option('wnw_show_coupon_alert', true), - 'show_stock_alert' => get_option('wnw_show_stock_alert', true), - ]; - } - - private static function get_default_badges() { - return [ - [ - 'icon' => 'truck', - 'icon_color' => '#10B981', - 'title' => 'Free Shipping', - 'description' => 'On orders over $50', - ], - [ - 'icon' => 'rotate-ccw', - 'icon_color' => '#3B82F6', - 'title' => '30-Day Returns', - 'description' => 'Money-back guarantee', - ], - [ - 'icon' => 'shield-check', - 'icon_color' => '#374151', - 'title' => 'Secure Checkout', - 'description' => 'SSL encrypted payment', - ], - ]; - } -} -``` - -#### 3. Create Admin SPA Pages: -```tsx -// admin-spa/src/pages/Appearance/StoreStyle.tsx -export default function StoreStyle() { - const [settings, setSettings] = useState({ - layout_style: 'boxed', - container_width: '1200', - }); - - return ( -
-

Store Style

- -
-
- - -
- -
- - -
-
-
- ); -} - -// admin-spa/src/pages/Appearance/TrustBadges.tsx -export default function TrustBadges() { - const [badges, setBadges] = useState([]); - - return ( -
-

Trust Badges

- -
- {badges.map((badge, index) => ( -
-
-
- - -
-
- - -
-
- - -
-
- - -
-
- -
- ))} - - -
-
- ); -} -``` - -#### 4. Update Customer SPA: -```tsx -// customer-spa/src/pages/Product/index.tsx -const { data: appearanceSettings } = useQuery({ - queryKey: ['appearance-settings'], - queryFn: async () => { - const response = await fetch('/wp-json/wnw/v1/appearance/settings'); - return response.json(); - } -}); - -// Use settings - - {/* Trust Badges from settings */} -
- {appearanceSettings?.trust_badges?.map(badge => ( -
- -

{badge.title}

-

{badge.description}

-
- ))} -
-
-``` - ---- - -## ๐Ÿ“Š Implementation Status - -### โœ… COMPLETED (Phase 1): -1. โœ… Above-the-fold optimization -2. โœ… Auto-select first variation -3. โœ… Variation image switching -4. โœ… Variation price updating -5. โœ… Quantity box spacing - -### ๐Ÿ”„ IN PROGRESS (Phase 2): -6. โณ Reviews hierarchy reorder -7. โณ Admin Appearance menu -8. โณ Trust badges repeater -9. โณ Product alerts system - -### ๐Ÿ“‹ PLANNED (Phase 3): -10. โณ Full-width layout option -11. โณ Fullscreen image lightbox -12. โณ Sticky bottom bar (mobile) -13. โณ Social proof enhancements - ---- - -## ๐Ÿงช Testing Results - -### Manual Testing: -- โœ… Variable product loads with first variation selected -- โœ… Price updates when variation changed -- โœ… Image switches when variation changed -- โœ… All elements fit above fold on 1366x768 -- โœ… Quantity selector has proper spacing -- โœ… Trust badges are compact and visible -- โœ… Responsive behavior works correctly - -### Browser Testing: -- โœ… Chrome (desktop) - Working -- โœ… Firefox (desktop) - Working -- โœ… Safari (desktop) - Working -- โณ Mobile Safari (iOS) - Pending -- โณ Mobile Chrome (Android) - Pending - ---- - -## ๐Ÿ“ˆ Expected Impact - -### User Experience: -- โœ… No scroll required for CTA (1366x768) -- โœ… Immediate product state (auto-select) -- โœ… Accurate price/image (variation sync) -- โœ… Cleaner UI (spacing fixes) -- โณ Prominent social proof (reviews - pending) - -### Conversion Rate: -- Current: Baseline -- Expected after Phase 1: +5-10% -- Expected after Phase 2 (reviews): +15-30% -- Expected after Phase 3 (full implementation): +20-35% - ---- - -## ๐ŸŽฏ Next Steps - -### Immediate (This Session): -1. โœ… Implement critical product page fixes -2. โณ Create Appearance navigation section -3. โณ Create REST API endpoints -4. โณ Create Admin SPA pages -5. โณ Update Customer SPA to read settings - -### Short Term (Next Session): -6. Reorder reviews hierarchy -7. Test on real devices -8. Performance optimization -9. Accessibility audit - -### Medium Term (Future): -10. Fullscreen lightbox -11. Sticky bottom bar -12. Related products -13. Customer photo gallery - ---- - -**Status:** โœ… Phase 1 Complete (5/5 critical fixes) -**Quality:** โญโญโญโญโญ -**Ready for:** Phase 2 Implementation -**Confidence:** HIGH (Research-backed + Tested) diff --git a/PRODUCT_PAGE_IMPLEMENTATION.md b/PRODUCT_PAGE_IMPLEMENTATION.md deleted file mode 100644 index 9292376..0000000 --- a/PRODUCT_PAGE_IMPLEMENTATION.md +++ /dev/null @@ -1,331 +0,0 @@ -# Product Page Implementation Plan - -## ๐ŸŽฏ What We Have (Current State) - -### Backend (API): -โœ… Product data with variations -โœ… Product attributes -โœ… Images array (featured + gallery) -โœ… Variation images -โœ… Price, stock status, SKU -โœ… Description, short description -โœ… Categories, tags -โœ… Related products - -### Frontend (Existing): -โœ… Basic product page structure -โœ… Image gallery with thumbnails (implemented but needs enhancement) -โœ… Add to cart functionality -โœ… Cart store (Zustand) -โœ… Toast notifications -โœ… Responsive layout - -### Missing: -โŒ Horizontal scrollable thumbnail slider -โŒ Variation selector dropdowns -โŒ Variation image auto-switching -โŒ Reviews section -โŒ Specifications table -โŒ Shipping/Returns info -โŒ Wishlist/Save feature -โŒ Related products display -โŒ Social proof elements -โŒ Trust badges - ---- - -## ๐Ÿ“‹ Implementation Priority (What Makes Sense Now) - -### **Phase 1: Core Product Page (Implement Now)** โญ - -#### 1.1 Image Gallery Enhancement -- โœ… Horizontal scrollable thumbnail slider -- โœ… Arrow navigation for >4 images -- โœ… Active thumbnail highlight -- โœ… Click thumbnail to change main image -- โœ… Responsive (swipeable on mobile) - -**Why:** Critical for user experience, especially for products with multiple images - -#### 1.2 Variation Selector -- โœ… Dropdown for each attribute -- โœ… Auto-switch image when variation selected -- โœ… Update price based on variation -- โœ… Update stock status -- โœ… Disable Add to Cart if no variation selected - -**Why:** Essential for variable products, directly impacts conversion - -#### 1.3 Enhanced Buy Section -- โœ… Price display (regular + sale) -- โœ… Stock status with color coding -- โœ… Quantity selector (plus/minus buttons) -- โœ… Add to Cart button (with loading state) -- โœ… Product meta (SKU, categories) - -**Why:** Core e-commerce functionality - -#### 1.4 Product Information Sections -- โœ… Tabs for Description, Additional Info, Reviews -- โœ… Vertical layout (avoid horizontal tabs) -- โœ… Specifications table (from attributes) -- โœ… Expandable sections on mobile - -**Why:** Users need detailed product info, research shows vertical > horizontal - ---- - -### **Phase 2: Trust & Conversion (Next Sprint)** ๐ŸŽฏ - -#### 2.1 Reviews Section -- โณ Display existing WooCommerce reviews -- โณ Star rating display -- โณ Review count -- โณ Link to write review (WooCommerce native) - -**Why:** Reviews are #2 most important content after images - -#### 2.2 Trust Elements -- โณ Payment method icons -- โณ Secure checkout badge -- โณ Free shipping threshold -- โณ Return policy link - -**Why:** Builds trust, reduces cart abandonment - -#### 2.3 Related Products -- โณ Display related products (from API) -- โณ Horizontal carousel -- โณ Product cards - -**Why:** Increases average order value - ---- - -### **Phase 3: Advanced Features (Future)** ๐Ÿš€ - -#### 3.1 Wishlist/Save for Later -- ๐Ÿ“… Add to wishlist button -- ๐Ÿ“… Wishlist page -- ๐Ÿ“… Persist across sessions - -#### 3.2 Social Proof -- ๐Ÿ“… "X people viewing" -- ๐Ÿ“… "X sold today" -- ๐Ÿ“… Customer photos - -#### 3.3 Enhanced Media -- ๐Ÿ“… Image zoom/lightbox -- ๐Ÿ“… Video support -- ๐Ÿ“… 360ยฐ view - ---- - -## ๐Ÿ› ๏ธ Phase 1 Implementation Details - -### Component Structure: -``` -Product/ -โ”œโ”€โ”€ index.tsx (main component) -โ”œโ”€โ”€ components/ -โ”‚ โ”œโ”€โ”€ ImageGallery.tsx -โ”‚ โ”œโ”€โ”€ ThumbnailSlider.tsx -โ”‚ โ”œโ”€โ”€ VariationSelector.tsx -โ”‚ โ”œโ”€โ”€ BuySection.tsx -โ”‚ โ”œโ”€โ”€ ProductTabs.tsx -โ”‚ โ”œโ”€โ”€ SpecificationTable.tsx -โ”‚ โ””โ”€โ”€ ProductMeta.tsx -``` - -### State Management: -```typescript -// Product page state -const [product, setProduct] = useState(null); -const [selectedImage, setSelectedImage] = useState(''); -const [selectedVariation, setSelectedVariation] = useState(null); -const [selectedAttributes, setSelectedAttributes] = useState>({}); -const [quantity, setQuantity] = useState(1); -const [activeTab, setActiveTab] = useState('description'); -``` - -### Key Features: - -#### 1. Thumbnail Slider -```tsx -
- {/* Prev Arrow */} - - - {/* Scrollable Container */} -
- {images.map((img, i) => ( - - ))} -
- - {/* Next Arrow */} - -
-``` - -#### 2. Variation Selector -```tsx -{product.attributes?.map(attr => ( -
- - -
-))} -``` - -#### 3. Auto-Switch Variation Image -```typescript -useEffect(() => { - if (selectedVariation && selectedVariation.image) { - setSelectedImage(selectedVariation.image); - } -}, [selectedVariation]); - -// Find matching variation -useEffect(() => { - if (product?.variations && Object.keys(selectedAttributes).length > 0) { - const variation = product.variations.find(v => { - return Object.entries(selectedAttributes).every(([key, value]) => { - return v.attributes[key] === value; - }); - }); - setSelectedVariation(variation || null); - } -}, [selectedAttributes, product]); -``` - ---- - -## ๐Ÿ“ Layout Design - -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ Breadcrumb: Home > Shop > Category > Product Name โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ โ”‚ Product Name (H1) โ”‚ -โ”‚ Main Image โ”‚ โญโญโญโญโญ (24 reviews) โ”‚ -โ”‚ (Large) โ”‚ โ”‚ -โ”‚ โ”‚ $99.00 $79.00 (Save 20%) โ”‚ -โ”‚ โ”‚ โœ… In Stock โ”‚ -โ”‚ โ”‚ โ”‚ -โ”‚ [Thumbnail Slider] โ”‚ Short description text... โ”‚ -โ”‚ โ—€ [img][img][img] โ–ถโ”‚ โ”‚ -โ”‚ โ”‚ Color: [Dropdown โ–ผ] โ”‚ -โ”‚ โ”‚ Size: [Dropdown โ–ผ] โ”‚ -โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ Quantity: [-] 1 [+] โ”‚ -โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ [๐Ÿ›’ Add to Cart] โ”‚ -โ”‚ โ”‚ [โ™ก Add to Wishlist] โ”‚ -โ”‚ โ”‚ โ”‚ -โ”‚ โ”‚ ๐Ÿ”’ Secure Checkout โ”‚ -โ”‚ โ”‚ ๐Ÿšš Free Shipping over $50 โ”‚ -โ”‚ โ”‚ โ†ฉ๏ธ 30-Day Returns โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ โ”‚ -โ”‚ [Description] [Additional Info] [Reviews (24)] โ”‚ -โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”‚ -โ”‚ โ”‚ -โ”‚ Full product description here... โ”‚ -โ”‚ โ€ข Feature 1 โ”‚ -โ”‚ โ€ข Feature 2 โ”‚ -โ”‚ โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ Related Products โ”‚ -โ”‚ [Product] [Product] [Product] [Product] โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - ---- - -## ๐ŸŽจ Styling Guidelines - -### Colors: -```css ---price-sale: #DC2626 (red) ---stock-in: #10B981 (green) ---stock-low: #F59E0B (orange) ---stock-out: #EF4444 (red) ---primary-cta: var(--primary) ---border-active: var(--primary) -``` - -### Spacing: -```css ---section-gap: 2rem ---element-gap: 1rem ---thumbnail-size: 80px ---thumbnail-gap: 0.5rem -``` - ---- - -## โœ… Acceptance Criteria - -### Image Gallery: -- [ ] Thumbnails scroll horizontally -- [ ] Show 4 thumbnails at a time on desktop -- [ ] Arrow buttons appear when >4 images -- [ ] Active thumbnail has colored border -- [ ] Click thumbnail changes main image -- [ ] Swipeable on mobile -- [ ] Smooth scroll animation - -### Variation Selector: -- [ ] Dropdown for each attribute -- [ ] "Choose an option" placeholder -- [ ] When variation selected, image auto-switches -- [ ] Price updates based on variation -- [ ] Stock status updates -- [ ] Add to Cart disabled until all attributes selected -- [ ] Clear error message if incomplete - -### Buy Section: -- [ ] Sale price shown in red -- [ ] Regular price strikethrough -- [ ] Savings percentage/amount shown -- [ ] Stock status color-coded -- [ ] Quantity buttons work correctly -- [ ] Add to Cart shows loading state -- [ ] Success toast with cart preview -- [ ] Cart count updates in header - -### Product Info: -- [ ] Tabs work correctly -- [ ] Description renders HTML -- [ ] Specifications show as table -- [ ] Mobile: sections collapsible -- [ ] Smooth scroll to reviews - ---- - -## ๐Ÿš€ Ready to Implement - -**Estimated Time:** 4-6 hours -**Priority:** HIGH -**Dependencies:** None (all APIs ready) - -Let's build Phase 1 now! ๐ŸŽฏ diff --git a/PRODUCT_PAGE_IMPLEMENTATION_COMPLETE.md b/PRODUCT_PAGE_IMPLEMENTATION_COMPLETE.md deleted file mode 100644 index 19a6876..0000000 --- a/PRODUCT_PAGE_IMPLEMENTATION_COMPLETE.md +++ /dev/null @@ -1,545 +0,0 @@ -# Product Page Implementation - COMPLETE โœ… - -**Date:** November 26, 2025 -**Reference:** STORE_UI_UX_GUIDE.md -**Status:** Implemented & Ready for Testing - ---- - -## ๐Ÿ“‹ Implementation Summary - -Successfully rebuilt the product page following the **STORE_UI_UX_GUIDE.md** standards, incorporating lessons from Tokopedia, Shopify, Amazon, and UX research. - ---- - -## โœ… What Was Implemented - -### 1. Typography Hierarchy (FIXED) - -**Before:** -``` -Price: 48-60px (TOO BIG) -Title: 24-32px -``` - -**After (per UI/UX Guide):** -``` -Title: 28-32px (PRIMARY) -Price: 24px (SECONDARY) -``` - -**Rationale:** We're not a marketplace (like Tokopedia). Title should be primary hierarchy. - ---- - -### 2. Image Gallery - -#### Desktop: -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ [Main Image] โ”‚ -โ”‚ (object-contain, padding) โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -[โ–ญ] [โ–ญ] [โ–ญ] [โ–ญ] [โ–ญ] โ† Thumbnails (96-112px) -``` - -**Features:** -- โœ… Thumbnails: 96-112px (w-24 md:w-28) -- โœ… Horizontal scrollable -- โœ… Arrow navigation if >4 images -- โœ… Active thumbnail: Primary border + ring-4 -- โœ… Click thumbnail โ†’ change main image - -#### Mobile: -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ [Main Image] โ”‚ -โ”‚ โ— โ—‹ โ—‹ โ—‹ โ—‹ โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - -**Features:** -- โœ… Dots only (NO thumbnails) -- โœ… Active dot: Primary color, elongated (w-6) -- โœ… Inactive dots: Gray (w-2) -- โœ… Click dot โ†’ change image -- โœ… Swipe gesture supported (native) - -**Rationale:** Convention (Amazon, Tokopedia, Shopify all use dots only on mobile) - ---- - -### 3. Variation Selectors (PILLS) - -**Before:** -```html - -``` - -**After:** -```html -
- - -
-``` - -**Features:** -- โœ… All options visible at once -- โœ… Pills: min 44x44px (touch target) -- โœ… Active state: Primary background + white text -- โœ… Hover state: Border color change -- โœ… No dropdowns (better UX) - -**Rationale:** Convention + Research align (Nielsen Norman Group) - ---- - -### 4. Product Information Sections - -**Pattern:** Vertical Accordions (NOT Horizontal Tabs) - -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ โ–ผ Product Description โ”‚ โ† Auto-expanded -โ”‚ Full description text... โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ โ–ถ Specifications โ”‚ โ† Collapsed -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ โ–ถ Customer Reviews โ”‚ โ† Collapsed -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - -**Features:** -- โœ… Description: Auto-expanded on load -- โœ… Other sections: Collapsed by default -- โœ… Arrow icon: Rotates on expand/collapse -- โœ… Smooth animation -- โœ… Full-width clickable header - -**Rationale:** Research (Baymard: 27% overlook horizontal tabs, only 8% overlook vertical) - ---- - -### 5. Specifications Table - -**Pattern:** Scannable Two-Column Table - -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ Material โ”‚ 100% Cotton โ”‚ -โ”‚ Weight โ”‚ 250g โ”‚ -โ”‚ Color โ”‚ Black, White, Gray โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - -**Features:** -- โœ… Label column: Bold, gray background -- โœ… Value column: Regular weight -- โœ… Padding: py-4 px-6 -- โœ… Border: Bottom border on each row - -**Rationale:** Research (scannable > plain table) - ---- - -### 6. Buy Section - -**Structure:** -1. Product Title (H1) - PRIMARY -2. Price - SECONDARY (not overwhelming) -3. Stock Status (badge with icon) -4. Short Description -5. Variation Selectors (pills) -6. Quantity Selector -7. Add to Cart (prominent CTA) -8. Wishlist Button -9. Trust Badges -10. Product Meta - -**Features:** -- โœ… Title: text-2xl md:text-3xl -- โœ… Price: text-2xl (balanced) -- โœ… Stock badge: Inline-flex with icon -- โœ… Pills: 44x44px minimum -- โœ… Add to Cart: h-14, full width -- โœ… Trust badges: 3 items (shipping, returns, secure) - ---- - -## ๐Ÿ“ฑ Responsive Behavior - -### Breakpoints: -```css -Mobile: < 768px -Desktop: >= 768px -``` - -### Image Gallery: -- **Mobile:** Dots only, swipe gesture -- **Desktop:** Thumbnails + arrows - -### Layout: -- **Mobile:** Single column (grid-cols-1) -- **Desktop:** Two columns (grid-cols-2) - -### Typography: -- **Title:** text-2xl md:text-3xl -- **Price:** text-2xl (same on both) - ---- - -## ๐ŸŽจ Design Tokens Used - -### Colors: -```css -Primary: #222222 -Sale Price: #DC2626 (red-600) -Success: #10B981 (green-600) -Error: #EF4444 (red-500) -Gray Scale: 50-900 -``` - -### Spacing: -```css -Gap: gap-8 lg:gap-12 -Padding: p-4, px-6, py-4 -Margin: mb-4, mb-6 -``` - -### Typography: -```css -Title: text-2xl md:text-3xl font-bold -Price: text-2xl font-bold -Body: text-base -Small: text-sm -``` - -### Touch Targets: -```css -Minimum: 44x44px (min-w-[44px] min-h-[44px]) -Buttons: h-14 (Add to Cart) -Pills: 44x44px minimum -``` - ---- - -## โœ… Checklist (Per UI/UX Guide) - -### Above the Fold: -- [x] Breadcrumb navigation -- [x] Product title (H1) -- [x] Price display (with sale if applicable) -- [x] Stock status badge -- [x] Main product image -- [x] Image navigation (thumbnails/dots) -- [x] Variation selectors (pills) -- [x] Quantity selector -- [x] Add to Cart button -- [x] Trust badges - -### Below the Fold: -- [x] Product description (auto-expanded) -- [x] Specifications table (collapsed) -- [x] Reviews section (collapsed) -- [x] Product meta (SKU, categories) -- [ ] Related products (future) - -### Mobile Specific: -- [x] Dots for image navigation -- [x] Large touch targets (44x44px) -- [x] Responsive text sizes -- [x] Collapsible sections -- [ ] Sticky bottom bar (future) - -### Desktop Specific: -- [x] Thumbnails for image navigation -- [x] Hover states -- [x] Larger layout (2-column grid) -- [x] Arrow navigation for thumbnails - ---- - -## ๐Ÿ”ง Technical Implementation - -### Key Components: -```tsx -// State management -const [selectedImage, setSelectedImage] = useState(); -const [selectedVariation, setSelectedVariation] = useState(null); -const [selectedAttributes, setSelectedAttributes] = useState>({}); -const [quantity, setQuantity] = useState(1); -const [activeTab, setActiveTab] = useState<'description' | 'additional' | 'reviews' | ''>('description'); - -// Image navigation -const thumbnailsRef = useRef(null); -const scrollThumbnails = (direction: 'left' | 'right') => { ... }; - -// Variation handling -const handleAttributeChange = (attributeName: string, value: string) => { ... }; - -// Auto-switch variation image -useEffect(() => { - if (selectedVariation && selectedVariation.image) { - setSelectedImage(selectedVariation.image); - } -}, [selectedVariation]); -``` - -### CSS Utilities: -```css -/* Hide scrollbar */ -.scrollbar-hide::-webkit-scrollbar { display: none; } -.scrollbar-hide { -ms-overflow-style: none; scrollbar-width: none; } - -/* Responsive visibility */ -.hidden.md\\:block { display: none; } -@media (min-width: 768px) { .hidden.md\\:block { display: block; } } - -/* Image override */ -.\\!h-full { height: 100% !important; } -``` - ---- - -## ๐ŸŽฏ Key Decisions Made - -### 1. Dots vs Thumbnails on Mobile -- **Decision:** Dots only (no thumbnails) -- **Rationale:** Convention (Amazon, Tokopedia, Shopify) -- **Evidence:** User screenshot of Amazon confirmed this - -### 2. Pills vs Dropdowns -- **Decision:** Pills/buttons -- **Rationale:** Convention + Research align -- **Evidence:** Nielsen Norman Group guidelines - -### 3. Title vs Price Hierarchy -- **Decision:** Title > Price -- **Rationale:** Context (we're not a marketplace) -- **Evidence:** Shopify (our closer analog) does this - -### 4. Tabs vs Accordions -- **Decision:** Vertical accordions -- **Rationale:** Research (27% overlook tabs) -- **Evidence:** Baymard Institute study - -### 5. Description Auto-Expand -- **Decision:** Auto-expanded on load -- **Rationale:** Don't hide primary content -- **Evidence:** Shopify does this - ---- - -## ๐Ÿ“Š Before vs After - -### Typography: -``` -BEFORE: -Title: 24-32px -Price: 48-60px (TOO BIG) - -AFTER: -Title: 28-32px (PRIMARY) -Price: 24px (SECONDARY) -``` - -### Variations: -``` -BEFORE: - - - -``` - -3. **Stores in Session:** -```php -WC()->session->set('selected_destination_id', $destination_id); -WC()->session->set('selected_destination_label', $destination_label); -``` - -4. **Triggers Shipping Calculation:** -```php -WC()->cart->calculate_shipping(); -WC()->cart->calculate_totals(); -``` - -#### Why Standard Implementation Fails: - -- WooNooW OrderForm uses standard fields: `city`, `state`, `postcode` -- RajaOngkir ignores these fields -- RajaOngkir only reads from session: `selected_destination_id` - -#### Solution: - -Use **Biteship** instead (see below) or create custom RajaOngkir addon that: -- Hooks into WooNooW OrderForm -- Adds Indonesian address selector -- Syncs with RajaOngkir session - ---- - -## Biteship Integration Addon - -### Plugin Specification - -**Plugin Name:** WooNooW Indonesia Shipping -**Description:** Indonesian shipping integration using Biteship Rate API -**Version:** 1.0.0 -**Requires:** WooNooW 1.0.0+, WooCommerce 8.0+ - -### Features - -- โœ… Indonesian address fields (Province, City, District, Subdistrict) -- โœ… Real-time shipping rate calculation -- โœ… Multiple courier support (JNE, SiCepat, J&T, AnterAja, etc.) -- โœ… Works in frontend checkout AND admin order form -- โœ… No subscription required (uses free Biteship Rate API) - -### Implementation Phases - -#### Phase 1: Core Functionality -- WooCommerce Shipping Method integration -- Biteship Rate API integration -- Indonesian address database (Province โ†’ Subdistrict) -- Frontend checkout integration -- Admin settings page - -#### Phase 2: SPA Integration -- REST API endpoints for address data -- REST API for rate calculation -- React components (SubdistrictSelector, CourierSelector) -- Hook integration with WooNooW OrderForm -- Admin order form support - -#### Phase 3: Advanced Features -- Rate caching (reduce API calls) -- Custom rate markup -- Free shipping threshold -- Multi-origin support -- Shipping label generation (optional, requires paid Biteship plan) - -### Plugin Structure - -``` -woonoow-indonesia-shipping/ -โ”œโ”€โ”€ woonoow-indonesia-shipping.php -โ”œโ”€โ”€ includes/ -โ”‚ โ”œโ”€โ”€ class-shipping-method.php -โ”‚ โ”œโ”€โ”€ class-biteship-api.php -โ”‚ โ”œโ”€โ”€ class-address-database.php -โ”‚ โ””โ”€โ”€ class-rest-controller.php -โ”œโ”€โ”€ admin/ -โ”‚ โ”œโ”€โ”€ class-settings.php -โ”‚ โ””โ”€โ”€ views/ -โ”œโ”€โ”€ assets/ -โ”‚ โ”œโ”€โ”€ js/ -โ”‚ โ”‚ โ”œโ”€โ”€ checkout.js -โ”‚ โ”‚ โ””โ”€โ”€ admin-order.js -โ”‚ โ””โ”€โ”€ css/ -โ””โ”€โ”€ data/ - โ””โ”€โ”€ indonesia-addresses.json -``` - -### API Integration - -#### Biteship Rate API Endpoint -``` -POST https://api.biteship.com/v1/rates/couriers -``` - -**Request:** -```json -{ - "origin_area_id": "IDNP6IDNC148IDND1820IDZ16094", - "destination_area_id": "IDNP9IDNC235IDND3256IDZ41551", - "couriers": "jne,sicepat,jnt", - "items": [ - { - "name": "Product Name", - "value": 100000, - "weight": 1000, - "quantity": 1 - } - ] -} -``` - -**Response:** -```json -{ - "success": true, - "object": "courier_pricing", - "pricing": [ - { - "courier_name": "JNE", - "courier_service_name": "REG", - "price": 15000, - "duration": "2-3 days" - } - ] -} -``` - -### React Components - -#### SubdistrictSelector Component -```tsx -interface SubdistrictSelectorProps { - value: { - province_id: string; - city_id: string; - district_id: string; - subdistrict_id: string; - }; - onChange: (value: any) => void; -} - -export function SubdistrictSelector({ value, onChange }: SubdistrictSelectorProps) { - // Cascading dropdowns: Province โ†’ City โ†’ District โ†’ Subdistrict - // Uses WooNooW API: /woonoow/v1/shipping/indonesia/provinces -} -``` - -#### CourierSelector Component -```tsx -interface CourierSelectorProps { - origin: string; - destination: string; - items: CartItem[]; - onSelect: (courier: ShippingRate) => void; -} - -export function CourierSelector({ origin, destination, items, onSelect }: CourierSelectorProps) { - // Fetches rates from Biteship - // Displays courier options with prices - // Uses WooNooW API: /woonoow/v1/shipping/indonesia/rates -} -``` - -### Hook Integration - -```php -// Register shipping addon -add_filter('woonoow/shipping/address_fields', function($fields) { - if (get_option('woonoow_indonesia_shipping_enabled')) { - return [ - 'province' => [ - 'type' => 'select', - 'label' => 'Province', - 'required' => true, - ], - 'city' => [ - 'type' => 'select', - 'label' => 'City', - 'required' => true, - ], - 'district' => [ - 'type' => 'select', - 'label' => 'District', - 'required' => true, - ], - 'subdistrict' => [ - 'type' => 'select', - 'label' => 'Subdistrict', - 'required' => true, - ], - ]; - } - return $fields; -}); - -// Register React component -add_filter('woonoow/checkout/shipping_selector', function($component) { - if (get_option('woonoow_indonesia_shipping_enabled')) { - return 'IndonesiaShippingSelector'; - } - return $component; -}); -``` - ---- - -## General Shipping Integration - -### Standard WooCommerce Shipping - -WooNooW automatically supports any WooCommerce shipping plugin that uses standard shipping methods: - -- WooCommerce Flat Rate -- WooCommerce Free Shipping -- WooCommerce Local Pickup -- Table Rate Shipping -- Distance Rate Shipping -- Any third-party shipping plugin - -### Custom Shipping Addons - -To create a custom shipping addon: - -1. **Create WooCommerce Shipping Method** -```php -class Custom_Shipping_Method extends WC_Shipping_Method { - public function calculate_shipping($package = []) { - // Your shipping calculation logic - $this->add_rate([ - 'id' => $this->id, - 'label' => $this->title, - 'cost' => $cost, - ]); - } -} -``` - -2. **Register with WooCommerce** -```php -add_filter('woocommerce_shipping_methods', function($methods) { - $methods['custom_shipping'] = 'Custom_Shipping_Method'; - return $methods; -}); -``` - -3. **Add SPA Integration (Optional)** -```php -// REST API for frontend -register_rest_route('woonoow/v1', '/shipping/custom/rates', [ - 'methods' => 'POST', - 'callback' => 'get_custom_shipping_rates', -]); - -// React component hook -add_filter('woonoow/checkout/shipping_fields', function($fields) { - // Add custom fields if needed - return $fields; -}); -``` - ---- - -## Best Practices - -1. **Use Standard WC Fields** - Whenever possible, use standard WooCommerce address fields -2. **Cache Rates** - Cache shipping rates to reduce API calls -3. **Error Handling** - Always provide fallback rates if API fails -4. **Mobile Friendly** - Ensure shipping selectors work well on mobile -5. **Admin Support** - Make sure shipping works in admin order form too - ---- - -## Resources - -- [WooCommerce Shipping Method Tutorial](https://woocommerce.com/document/shipping-method-api/) -- [Biteship API Documentation](https://biteship.com/docs) -- [WooNooW Addon Development Guide](ADDON_DEVELOPMENT_GUIDE.md) -- [WooNooW Hooks Registry](HOOKS_REGISTRY.md) diff --git a/SHIPPING_METHOD_TYPES.md b/SHIPPING_METHOD_TYPES.md deleted file mode 100644 index 6da6d28..0000000 --- a/SHIPPING_METHOD_TYPES.md +++ /dev/null @@ -1,327 +0,0 @@ -# Shipping Method Types - WooCommerce Core Structure - -## The Two Types of Shipping Methods - -WooCommerce has TWO fundamentally different shipping method types: - ---- - -## Type 1: Static Methods (WooCommerce Core) - -**Characteristics:** -- No API calls -- Fixed rates or free -- Configured once in settings -- Available immediately - -**Examples:** -- Free Shipping -- Flat Rate -- Local Pickup - -**Structure:** -``` -Method: Free Shipping -โ”œโ”€โ”€ Conditions: Order total > $50 -โ””โ”€โ”€ Cost: $0 -``` - -**In Create Order:** -``` -User fills address -โ†’ Static methods appear immediately -โ†’ User selects one -โ†’ Done! -``` - ---- - -## Type 2: Live Rate Methods (API-based) - -**Characteristics:** -- Requires API call -- Dynamic rates based on address + weight -- Returns multiple service options -- Needs "Calculate" button - -**Examples:** -- UPS (International) -- FedEx, DHL -- Indonesian Shipping Addons (J&T, JNE, SiCepat) - -**Structure:** -``` -Method: UPS Live Rates -โ”œโ”€โ”€ API Credentials configured -โ””โ”€โ”€ On calculate: - โ”œโ”€โ”€ Service: UPS Ground - $15.00 - โ”œโ”€โ”€ Service: UPS 2nd Day - $25.00 - โ””โ”€โ”€ Service: UPS Next Day - $45.00 -``` - -**In Create Order:** -``` -User fills address -โ†’ Click "Calculate Shipping" -โ†’ API returns service options -โ†’ User selects one -โ†’ Done! -``` - ---- - -## The Real Hierarchy - -### Static Method (Simple): -``` -Method -โ””โ”€โ”€ (No sub-levels) -``` - -### Live Rate Method (Complex): -``` -Method -โ”œโ”€โ”€ Courier (if applicable) -โ”‚ โ”œโ”€โ”€ Service Option 1 -โ”‚ โ”œโ”€โ”€ Service Option 2 -โ”‚ โ””โ”€โ”€ Service Option 3 -โ””โ”€โ”€ Or directly: - โ”œโ”€โ”€ Service Option 1 - โ””โ”€โ”€ Service Option 2 -``` - ---- - -## Indonesian Shipping Example - -**Method:** Indonesian Shipping (API-based) -**API:** Biteship / RajaOngkir / Custom - -**After Calculate:** -``` -J&T Express -โ”œโ”€โ”€ Regular Service: Rp15,000 (2-3 days) -โ””โ”€โ”€ Express Service: Rp25,000 (1 day) - -JNE -โ”œโ”€โ”€ REG: Rp18,000 (2-4 days) -โ”œโ”€โ”€ YES: Rp28,000 (1-2 days) -โ””โ”€โ”€ OKE: Rp12,000 (3-5 days) - -SiCepat -โ”œโ”€โ”€ Regular: Rp16,000 (2-3 days) -โ””โ”€โ”€ BEST: Rp20,000 (1-2 days) -``` - -**User sees:** Courier name + Service name + Price + Estimate - ---- - -## UPS Example (International) - -**Method:** UPS Live Rates -**API:** UPS API - -**After Calculate:** -``` -UPS Ground: $15.00 (5-7 business days) -UPS 2nd Day Air: $25.00 (2 business days) -UPS Next Day Air: $45.00 (1 business day) -``` - -**User sees:** Service name + Price + Estimate - ---- - -## Address Field Requirements - -### Static Methods: -- Country -- State/Province -- City -- Postal Code -- Address Line 1 -- Address Line 2 (optional) - -### Live Rate Methods: - -**International (UPS, FedEx, DHL):** -- Country -- State/Province -- City -- **Postal Code** (REQUIRED - used for rate calculation) -- Address Line 1 -- Address Line 2 (optional) - -**Indonesian (J&T, JNE, SiCepat):** -- Country: Indonesia -- Province -- City/Regency -- **Subdistrict** (REQUIRED - used for rate calculation) -- Postal Code -- Address Line 1 -- Address Line 2 (optional) - ---- - -## The Pattern - -| Method Type | Address Requirement | Rate Calculation | -|-------------|---------------------|------------------| -| Static | Basic address | Fixed/Free | -| Live Rate (International) | **Postal Code** required | API call with postal code | -| Live Rate (Indonesian) | **Subdistrict** required | API call with subdistrict ID | - ---- - -## Implementation in Create Order - -### Current Problem: -- We probably require subdistrict for ALL methods -- This breaks international live rate methods - -### Solution: - -**Step 1: Detect Available Methods** -```javascript -const availableMethods = getShippingMethods(address.country); - -const needsSubdistrict = availableMethods.some(method => - method.type === 'live_rate' && method.country === 'ID' -); - -const needsPostalCode = availableMethods.some(method => - method.type === 'live_rate' && method.country !== 'ID' -); -``` - -**Step 2: Show Conditional Fields** -```javascript -// Always show -- Country -- State/Province -- City -- Address Line 1 - -// Conditional -if (needsSubdistrict) { - - Subdistrict (required) -} - -if (needsPostalCode || needsSubdistrict) { - - Postal Code (required) -} - -// Always optional -- Address Line 2 -``` - -**Step 3: Calculate Shipping** -```javascript -// Static methods -if (method.type === 'static') { - return method.cost; // Immediate -} - -// Live rate methods -if (method.type === 'live_rate') { - const rates = await fetchLiveRates({ - method: method.id, - address: { - country: address.country, - state: address.state, - city: address.city, - subdistrict: address.subdistrict, // If Indonesian - postal_code: address.postal_code, // If international - // ... other fields - } - }); - - return rates; // Array of service options -} -``` - ---- - -## UI Flow - -### Scenario 1: Static Method Only -``` -1. User fills basic address -2. Shipping options appear immediately: - - Free Shipping: $0 - - Flat Rate: $10 -3. User selects one -4. Done! -``` - -### Scenario 2: Indonesian Live Rate -``` -1. User fills address including subdistrict -2. Click "Calculate Shipping" -3. API returns: - - J&T Regular: Rp15,000 - - JNE REG: Rp18,000 - - SiCepat BEST: Rp20,000 -4. User selects one -5. Done! -``` - -### Scenario 3: International Live Rate -``` -1. User fills address including postal code -2. Click "Calculate Shipping" -3. API returns: - - UPS Ground: $15.00 - - UPS 2nd Day: $25.00 -4. User selects one -5. Done! -``` - -### Scenario 4: Mixed (Static + Live Rate) -``` -1. User fills address -2. Static methods appear immediately: - - Free Shipping: $0 -3. Click "Calculate Shipping" for live rates -4. Live rates appear: - - UPS Ground: $15.00 -5. User selects from all options -6. Done! -``` - ---- - -## WooCommerce Core Behavior - -**Yes, this is all in WooCommerce core!** - -- Static methods: `WC_Shipping_Method` class -- Live rate methods: Extend `WC_Shipping_Method` with API logic -- Service options: Stored as shipping rates with method_id + instance_id - -**WooCommerce handles:** -- Method registration -- Rate calculation -- Service option display -- Selection and storage - -**We need to handle:** -- Conditional address fields -- "Calculate" button for live rates -- Service option display in Create Order -- Proper address validation - ---- - -## Next Steps - -1. Investigate Create Order address field logic -2. Add conditional field display based on available methods -3. Add "Calculate Shipping" button for live rates -4. Display service options properly -5. Test with: - - Static methods only - - Indonesian live rates - - International live rates - - Mixed scenarios diff --git a/SPRINT_1-2_COMPLETION_REPORT.md b/SPRINT_1-2_COMPLETION_REPORT.md deleted file mode 100644 index 7da8337..0000000 --- a/SPRINT_1-2_COMPLETION_REPORT.md +++ /dev/null @@ -1,415 +0,0 @@ -# Sprint 1-2 Completion Report โœ… COMPLETE - -**Status:** โœ… All objectives achieved and tested -**Date Completed:** November 22, 2025 -## Customer SPA Foundation - -**Date:** November 22, 2025 -**Status:** โœ… Foundation Complete - Ready for Build & Testing - ---- - -## Executive Summary - -Sprint 1-2 objectives have been **successfully completed**. The customer-spa foundation is now in place with: -- โœ… Backend API controllers (Shop, Cart, Account) -- โœ… Frontend base layout components (Header, Footer, Container) -- โœ… WordPress integration (Shortcodes, Asset loading) -- โœ… Authentication flow (using WordPress user session) -- โœ… Routing structure -- โœ… State management (Zustand for cart) -- โœ… API client with endpoints - ---- - -## What Was Built - -### 1. Backend API Controllers โœ… - -Created three new customer-facing API controllers in `includes/Frontend/`: - -#### **ShopController.php** -``` -GET /woonoow/v1/shop/products # List products with filters -GET /woonoow/v1/shop/products/{id} # Get single product (with variations) -GET /woonoow/v1/shop/categories # List categories -GET /woonoow/v1/shop/search # Search products -``` - -**Features:** -- Product listing with pagination, category filter, search -- Single product with detailed info (variations, gallery, related products) -- Category listing with images -- Product search - -#### **CartController.php** -``` -GET /woonoow/v1/cart # Get cart contents -POST /woonoow/v1/cart/add # Add item to cart -POST /woonoow/v1/cart/update # Update cart item quantity -POST /woonoow/v1/cart/remove # Remove item from cart -POST /woonoow/v1/cart/apply-coupon # Apply coupon -POST /woonoow/v1/cart/remove-coupon # Remove coupon -``` - -**Features:** -- Full cart CRUD operations -- Coupon management -- Cart totals calculation (subtotal, tax, shipping, discount) -- WooCommerce session integration - -#### **AccountController.php** -``` -GET /woonoow/v1/account/orders # Get customer orders -GET /woonoow/v1/account/orders/{id} # Get single order -GET /woonoow/v1/account/profile # Get customer profile -POST /woonoow/v1/account/profile # Update profile -POST /woonoow/v1/account/password # Update password -GET /woonoow/v1/account/addresses # Get addresses -POST /woonoow/v1/account/addresses # Update addresses -GET /woonoow/v1/account/downloads # Get digital downloads -``` - -**Features:** -- Order history with pagination -- Order details with items, addresses, totals -- Profile management -- Password update -- Billing/shipping address management -- Digital downloads support -- Permission checks (logged-in users only) - -**Files Created:** -- `includes/Frontend/ShopController.php` -- `includes/Frontend/CartController.php` -- `includes/Frontend/AccountController.php` - -**Integration:** -- Updated `includes/Api/Routes.php` to register frontend controllers -- All routes registered under `woonoow/v1` namespace - ---- - -### 2. WordPress Integration โœ… - -#### **Assets Manager** (`includes/Frontend/Assets.php`) -- Enqueues customer-spa JS/CSS on pages with shortcodes -- Adds inline config with API URL, nonce, user info -- Supports both production build and dev mode -- Smart loading (only loads when needed) - -#### **Shortcodes Manager** (`includes/Frontend/Shortcodes.php`) -Created four shortcodes: -- `[woonoow_shop]` - Product listing page -- `[woonoow_cart]` - Shopping cart page -- `[woonoow_checkout]` - Checkout page (requires login) -- `[woonoow_account]` - My account page (requires login) - -**Features:** -- Renders mount point for React app -- Passes data attributes for page-specific config -- Login requirement for protected pages -- Loading state placeholder - -**Integration:** -- Updated `includes/Core/Bootstrap.php` to initialize frontend classes -- Assets and shortcodes auto-load on `plugins_loaded` hook - ---- - -### 3. Frontend Components โœ… - -#### **Base Layout Components** -Created in `customer-spa/src/components/Layout/`: - -**Header.tsx** -- Logo and navigation -- Cart icon with item count badge -- User account link (if logged in) -- Search button -- Mobile menu button -- Sticky header with backdrop blur - -**Footer.tsx** -- Multi-column footer (About, Shop, Account, Support) -- Links to main pages -- Copyright notice -- Responsive grid layout - -**Container.tsx** -- Responsive container wrapper -- Uses `container-safe` utility class -- Consistent padding and max-width - -**Layout.tsx** -- Main layout wrapper -- Header + Content + Footer structure -- Flex layout with sticky footer - -#### **UI Components** -- `components/ui/button.tsx` - Button component with variants (shadcn/ui pattern) - -#### **Utilities** -- `lib/utils.ts` - Helper functions: - - `cn()` - Tailwind class merging - - `formatPrice()` - Currency formatting - - `formatDate()` - Date formatting - - `debounce()` - Debounce function - -**Integration:** -- Updated `App.tsx` to use Layout wrapper -- All pages now render inside consistent layout - ---- - -### 4. Authentication Flow โœ… - -**Implementation:** -- Uses WordPress session (no separate auth needed) -- User info passed via `window.woonoowCustomer.user` -- Nonce-based API authentication -- Login requirement enforced at shortcode level - -**User Data Available:** -```typescript -window.woonoowCustomer = { - apiUrl: '/wp-json/woonoow/v1', - nonce: 'wp_rest_nonce', - siteUrl: 'https://site.local', - user: { - isLoggedIn: true, - id: 123 - } -} -``` - -**Protected Routes:** -- Checkout page requires login -- Account pages require login -- API endpoints check `is_user_logged_in()` - ---- - -## File Structure - -``` -woonoow/ -โ”œโ”€โ”€ includes/ -โ”‚ โ”œโ”€โ”€ Frontend/ # NEW - Customer-facing backend -โ”‚ โ”‚ โ”œโ”€โ”€ ShopController.php # Product catalog API -โ”‚ โ”‚ โ”œโ”€โ”€ CartController.php # Cart operations API -โ”‚ โ”‚ โ”œโ”€โ”€ AccountController.php # Customer account API -โ”‚ โ”‚ โ”œโ”€โ”€ Assets.php # Asset loading -โ”‚ โ”‚ โ””โ”€โ”€ Shortcodes.php # Shortcode handlers -โ”‚ โ”œโ”€โ”€ Api/ -โ”‚ โ”‚ โ””โ”€โ”€ Routes.php # UPDATED - Register frontend routes -โ”‚ โ””โ”€โ”€ Core/ -โ”‚ โ””โ”€โ”€ Bootstrap.php # UPDATED - Initialize frontend -โ”‚ -โ””โ”€โ”€ customer-spa/ - โ”œโ”€โ”€ src/ - โ”‚ โ”œโ”€โ”€ components/ - โ”‚ โ”‚ โ”œโ”€โ”€ Layout/ # NEW - Layout components - โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ Header.tsx - โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ Footer.tsx - โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ Container.tsx - โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ Layout.tsx - โ”‚ โ”‚ โ””โ”€โ”€ ui/ # NEW - UI components - โ”‚ โ”‚ โ””โ”€โ”€ button.tsx - โ”‚ โ”œโ”€โ”€ lib/ - โ”‚ โ”‚ โ”œโ”€โ”€ api/ - โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ client.ts # EXISTING - API client - โ”‚ โ”‚ โ”œโ”€โ”€ cart/ - โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ store.ts # EXISTING - Cart state - โ”‚ โ”‚ โ””โ”€โ”€ utils.ts # NEW - Utility functions - โ”‚ โ”œโ”€โ”€ pages/ # EXISTING - Page placeholders - โ”‚ โ”œโ”€โ”€ App.tsx # UPDATED - Add Layout wrapper - โ”‚ โ””โ”€โ”€ index.css # EXISTING - Global styles - โ””โ”€โ”€ package.json # EXISTING - Dependencies -``` - ---- - -## Sprint 1-2 Checklist - -According to `CUSTOMER_SPA_MASTER_PLAN.md`, Sprint 1-2 tasks: - -- [x] **Setup customer-spa build system** - โœ… Vite + React + TypeScript configured -- [x] **Create base layout components** - โœ… Header, Footer, Container, Layout -- [x] **Implement routing** - โœ… React Router with routes for all pages -- [x] **Setup API client** - โœ… Client exists with all endpoints defined -- [x] **Cart state management** - โœ… Zustand store with persistence -- [x] **Authentication flow** - โœ… WordPress session integration - -**All Sprint 1-2 objectives completed!** โœ… - ---- - -## Next Steps (Sprint 3-4) - -### Immediate: Build & Test -1. **Build customer-spa:** - ```bash - cd customer-spa - npm install - npm run build - ``` - -2. **Create test pages in WordPress:** - - Create page "Shop" with `[woonoow_shop]` - - Create page "Cart" with `[woonoow_cart]` - - Create page "Checkout" with `[woonoow_checkout]` - - Create page "My Account" with `[woonoow_account]` - -3. **Test API endpoints:** - ```bash - # Test shop API - curl "https://woonoow.local/wp-json/woonoow/v1/shop/products" - - # Test cart API - curl "https://woonoow.local/wp-json/woonoow/v1/cart" - ``` - -### Sprint 3-4: Product Catalog -According to the master plan: -- [ ] Product listing page (with real data) -- [ ] Product filters (category, price, search) -- [ ] Product search functionality -- [ ] Product detail page (with variations) -- [ ] Product variations selector -- [ ] Image gallery with zoom -- [ ] Related products section - ---- - -## Technical Notes - -### API Design -- All customer-facing routes use `/woonoow/v1` namespace -- Public routes (shop) use `'permission_callback' => '__return_true'` -- Protected routes (account) check `is_user_logged_in()` -- Consistent response format with proper HTTP status codes - -### Frontend Architecture -- **Hybrid approach:** Works with any theme via shortcodes -- **Progressive enhancement:** Theme provides layout, WooNooW provides interactivity -- **Mobile-first:** Responsive design with Tailwind utilities -- **Performance:** Code splitting, lazy loading, optimized builds - -### WordPress Integration -- **Safe activation:** No database changes, reversible -- **Theme compatibility:** Works with any theme -- **SEO-friendly:** Server-rendered product pages (future) -- **Tracking-ready:** WooCommerce event triggers for pixels (future) - ---- - -## Known Limitations - -### Current Sprint (1-2) -1. **Pages are placeholders** - Need real implementations in Sprint 3-4 -2. **No product data rendering** - API works, but UI needs to consume it -3. **No checkout flow** - CheckoutController not created yet (Sprint 5-6) -4. **No cart drawer** - Cart page exists, but no slide-out drawer yet - -### Future Sprints -- Sprint 3-4: Product catalog implementation -- Sprint 5-6: Cart drawer + Checkout flow -- Sprint 7-8: My Account pages implementation -- Sprint 9-10: Polish, testing, performance optimization - ---- - -## Testing Checklist - -### Backend API Testing -- [ ] Test `/shop/products` - Returns product list -- [ ] Test `/shop/products/{id}` - Returns single product -- [ ] Test `/shop/categories` - Returns categories -- [ ] Test `/cart` - Returns empty cart -- [ ] Test `/cart/add` - Adds product to cart -- [ ] Test `/account/orders` - Requires login, returns orders - -### Frontend Testing -- [ ] Build customer-spa successfully -- [ ] Create test pages with shortcodes -- [ ] Verify assets load on shortcode pages -- [ ] Check `window.woonoowCustomer` config exists -- [ ] Verify Header renders with cart count -- [ ] Verify Footer renders with links -- [ ] Test navigation between pages - -### Integration Testing -- [ ] Shortcodes render mount point -- [ ] React app mounts on shortcode pages -- [ ] API calls work from frontend -- [ ] Cart state persists in localStorage -- [ ] User login state detected correctly - ---- - -## Success Criteria - -โœ… **Sprint 1-2 is complete when:** -- [x] Backend API controllers created and registered -- [x] Frontend layout components created -- [x] WordPress integration (shortcodes, assets) working -- [x] Authentication flow implemented -- [x] Build system configured -- [ ] **Build succeeds** (pending: run `npm run build`) -- [ ] **Test pages work** (pending: create WordPress pages) - -**Status:** 5/7 complete - Ready for build & testing phase - ---- - -## Commands Reference - -### Build Customer SPA -```bash -cd /Users/dwindown/Local\ Sites/woonoow/app/public/wp-content/plugins/woonoow/customer-spa -npm install -npm run build -``` - -### Dev Mode (Hot Reload) -```bash -cd customer-spa -npm run dev -# Runs at https://woonoow.local:5174 -``` - -### Test API Endpoints -```bash -# Shop API -curl "https://woonoow.local/wp-json/woonoow/v1/shop/products" - -# Cart API -curl "https://woonoow.local/wp-json/woonoow/v1/cart" \ - -H "X-WP-Nonce: YOUR_NONCE" - -# Account API (requires auth) -curl "https://woonoow.local/wp-json/woonoow/v1/account/orders" \ - -H "X-WP-Nonce: YOUR_NONCE" \ - -H "Cookie: wordpress_logged_in_..." -``` - ---- - -## Conclusion - -**Sprint 1-2 foundation is complete!** ๐ŸŽ‰ - -The customer-spa now has: -- โœ… Solid backend API foundation -- โœ… Clean frontend architecture -- โœ… WordPress integration layer -- โœ… Authentication flow -- โœ… Base layout components - -**Ready for:** -- Building the customer-spa -- Creating test pages -- Moving to Sprint 3-4 (Product Catalog implementation) - -**Next session:** Build, test, and start implementing real product listing page. diff --git a/SPRINT_3-4_PLAN.md b/SPRINT_3-4_PLAN.md deleted file mode 100644 index 716c0f0..0000000 --- a/SPRINT_3-4_PLAN.md +++ /dev/null @@ -1,288 +0,0 @@ -# Sprint 3-4: Product Catalog & Cart - -**Duration:** Sprint 3-4 (2 weeks) -**Status:** ๐Ÿš€ Ready to Start -**Prerequisites:** โœ… Sprint 1-2 Complete - ---- - -## Objectives - -Build out the complete product catalog experience and shopping cart functionality. - -### Sprint 3: Product Catalog Enhancement -1. **Product Detail Page** - Full product view with variations -2. **Product Filters** - Category, price, attributes -3. **Product Search** - Real-time search with debouncing -4. **Product Sorting** - Price, popularity, rating, date - -### Sprint 4: Shopping Cart -1. **Cart Page** - View and manage cart items -2. **Cart Sidebar** - Quick cart preview -3. **Cart API Integration** - Sync with WooCommerce cart -4. **Coupon Application** - Apply and remove coupons - ---- - -## Sprint 3: Product Catalog Enhancement - -### 1. Product Detail Page (`/product/:id`) - -**File:** `customer-spa/src/pages/Product/index.tsx` - -**Features:** -- Product images gallery with zoom -- Product title, price, description -- Variation selector (size, color, etc.) -- Quantity selector -- Add to cart button -- Related products -- Product reviews (if enabled) - -**API Endpoints:** -- `GET /shop/products/:id` - Get product details -- `GET /shop/products/:id/related` - Get related products (optional) - -**Components to Create:** -- `ProductGallery.tsx` - Image gallery with thumbnails -- `VariationSelector.tsx` - Select product variations -- `QuantityInput.tsx` - Quantity selector -- `ProductMeta.tsx` - SKU, categories, tags -- `RelatedProducts.tsx` - Related products carousel - ---- - -### 2. Product Filters - -**File:** `customer-spa/src/components/Shop/Filters.tsx` - -**Features:** -- Category filter (tree structure) -- Price range slider -- Attribute filters (color, size, brand, etc.) -- Stock status filter -- On sale filter -- Clear all filters button - -**State Management:** -- Use URL query parameters for filters -- Persist filters in URL for sharing - -**Components:** -- `CategoryFilter.tsx` - Hierarchical category tree -- `PriceRangeFilter.tsx` - Price slider -- `AttributeFilter.tsx` - Checkbox list for attributes -- `ActiveFilters.tsx` - Show active filters with remove buttons - ---- - -### 3. Product Search Enhancement - -**Current:** Basic search input -**Enhancement:** Real-time search with suggestions - -**Features:** -- Search as you type -- Search suggestions dropdown -- Recent searches -- Popular searches -- Product thumbnails in results -- Keyboard navigation (arrow keys, enter, escape) - -**File:** `customer-spa/src/components/Shop/SearchBar.tsx` - ---- - -### 4. Product Sorting - -**Features:** -- Sort by: Default, Popularity, Rating, Price (low to high), Price (high to low), Latest -- Dropdown selector -- Persist in URL - -**File:** `customer-spa/src/components/Shop/SortDropdown.tsx` - ---- - -## Sprint 4: Shopping Cart - -### 1. Cart Page (`/cart`) - -**File:** `customer-spa/src/pages/Cart/index.tsx` - -**Features:** -- Cart items list with thumbnails -- Quantity adjustment (+ / -) -- Remove item button -- Update cart button -- Cart totals (subtotal, tax, shipping, total) -- Coupon code input -- Proceed to checkout button -- Continue shopping link -- Empty cart state - -**Components:** -- `CartItem.tsx` - Single cart item row -- `CartTotals.tsx` - Cart totals summary -- `CouponForm.tsx` - Apply coupon code -- `EmptyCart.tsx` - Empty cart message - ---- - -### 2. Cart Sidebar/Drawer - -**File:** `customer-spa/src/components/Cart/CartDrawer.tsx` - -**Features:** -- Slide-in from right -- Mini cart items (max 5, then scroll) -- Cart totals -- View cart button -- Checkout button -- Close button -- Backdrop overlay - -**Trigger:** -- Click cart icon in header -- Auto-open when item added (optional) - ---- - -### 3. Cart API Integration - -**Endpoints:** -- `GET /cart` - Get current cart -- `POST /cart/add` - Add item to cart -- `PUT /cart/update` - Update item quantity -- `DELETE /cart/remove` - Remove item -- `POST /cart/apply-coupon` - Apply coupon -- `DELETE /cart/remove-coupon` - Remove coupon - -**State Management:** -- Zustand store already created (`customer-spa/src/lib/cart/store.ts`) -- Sync with WooCommerce session -- Persist cart in localStorage -- Handle cart conflicts (server vs local) - ---- - -### 4. Coupon System - -**Features:** -- Apply coupon code -- Show discount amount -- Show coupon description -- Remove coupon button -- Error handling (invalid, expired, usage limit) - -**Backend:** -- Already implemented in `CartController.php` -- `POST /cart/apply-coupon` -- `DELETE /cart/remove-coupon` - ---- - -## Technical Considerations - -### Performance -- Lazy load product images -- Implement infinite scroll for product grid (optional) -- Cache product data with TanStack Query -- Debounce search and filter inputs - -### UX Enhancements -- Loading skeletons for all states -- Optimistic updates for cart actions -- Toast notifications for user feedback -- Smooth transitions and animations -- Mobile-first responsive design - -### Error Handling -- Network errors -- Out of stock products -- Invalid variations -- Cart conflicts -- API timeouts - -### Accessibility -- Keyboard navigation -- Screen reader support -- Focus management -- ARIA labels -- Color contrast - ---- - -## Implementation Order - -### Week 1 (Sprint 3) -1. **Day 1-2:** Product Detail Page - - Basic layout and product info - - Image gallery - - Add to cart functionality - -2. **Day 3:** Variation Selector - - Handle simple and variable products - - Update price based on variation - - Validation - -3. **Day 4-5:** Filters & Search - - Category filter - - Price range filter - - Search enhancement - - Sort dropdown - -### Week 2 (Sprint 4) -1. **Day 1-2:** Cart Page - - Cart items list - - Quantity adjustment - - Cart totals - - Coupon application - -2. **Day 3:** Cart Drawer - - Slide-in sidebar - - Mini cart items - - Quick actions - -3. **Day 4:** Cart API Integration - - Sync with backend - - Handle conflicts - - Error handling - -4. **Day 5:** Polish & Testing - - Responsive design - - Loading states - - Error states - - Cross-browser testing - ---- - -## Success Criteria - -### Sprint 3 -- โœ… Product detail page displays all product info -- โœ… Variations can be selected and price updates -- โœ… Filters work and update product list -- โœ… Search returns relevant results -- โœ… Sorting works correctly - -### Sprint 4 -- โœ… Cart page displays all cart items -- โœ… Quantity can be adjusted -- โœ… Items can be removed -- โœ… Coupons can be applied and removed -- โœ… Cart drawer opens and closes smoothly -- โœ… Cart syncs with WooCommerce backend -- โœ… Cart persists across page reloads - ---- - -## Next Steps - -1. Review this plan -2. Confirm priorities -3. Start with Product Detail Page -4. Implement features incrementally -5. Test each feature before moving to next - -**Ready to start Sprint 3?** ๐Ÿš€ diff --git a/STORE_UI_UX_GUIDE.md b/STORE_UI_UX_GUIDE.md deleted file mode 100644 index 98cab01..0000000 --- a/STORE_UI_UX_GUIDE.md +++ /dev/null @@ -1,634 +0,0 @@ -# WooNooW Store UI/UX Guide -## Official Design System & Standards - -**Version:** 1.0 -**Last Updated:** November 26, 2025 -**Status:** Living Document (Updated by conversation) - ---- - -## ๐Ÿ“‹ Purpose - -This document serves as the single source of truth for all UI/UX decisions in WooNooW Customer SPA. All design and implementation decisions should reference this guide. - -**Philosophy:** Pragmatic, not dogmatic. Follow convention when strong, follow research when clear, use hybrid when beneficial. - ---- - -## ๐ŸŽฏ Core Principles - -1. **Convention Over Innovation** - Users expect familiar patterns -2. **Research-Backed Decisions** - When convention is weak or wrong -3. **Mobile-First Approach** - Design for mobile, enhance for desktop -4. **Performance Matters** - Fast > Feature-rich -5. **Accessibility Always** - WCAG 2.1 AA minimum - ---- - -## ๐Ÿ“ Layout Standards - -### Container Widths - -```css -Mobile: 100% (with padding) -Tablet: 768px max-width -Desktop: 1200px max-width -Wide: 1400px max-width -``` - -### Spacing Scale - -```css -xs: 0.25rem (4px) -sm: 0.5rem (8px) -md: 1rem (16px) -lg: 1.5rem (24px) -xl: 2rem (32px) -2xl: 3rem (48px) -``` - -### Breakpoints - -```css -sm: 640px -md: 768px -lg: 1024px -xl: 1280px -2xl: 1536px -``` - ---- - -## ๐ŸŽจ Typography - -### Hierarchy - -``` -H1 (Product Title): 28-32px, bold -H2 (Section Title): 24-28px, bold -H3 (Subsection): 20-24px, semibold -Price (Primary): 24-28px, bold -Price (Sale): 24-28px, bold, red -Price (Regular): 18-20px, line-through, gray -Body: 16px, regular -Small: 14px, regular -Tiny: 12px, regular -``` - -### Font Stack - -```css -font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', - Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; -``` - -### Rules - -- โœ… Title > Price in hierarchy (we're not a marketplace) -- โœ… Use weight and color for emphasis, not just size -- โœ… Line height: 1.5 for body, 1.2 for headings -- โŒ Don't use more than 3 font sizes per section - ---- - -## ๐Ÿ–ผ๏ธ Product Page Standards - -### Image Gallery - -#### Desktop: -``` -Layout: -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ [Main Image] โ”‚ -โ”‚ (Large, square) โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -[โ–ญ] [โ–ญ] [โ–ญ] [โ–ญ] [โ–ญ] โ† Thumbnails (96-112px) -``` - -**Rules:** -- โœ… Thumbnails: 96-112px (24-28 in Tailwind) -- โœ… Horizontal scrollable if >4 images -- โœ… Active thumbnail: Primary border + ring -- โœ… Main image: object-contain with padding -- โœ… Click thumbnail โ†’ change main image -- โœ… Click main image โ†’ fullscreen lightbox - -#### Mobile: -``` -Layout: -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ [Main Image] โ”‚ -โ”‚ (Full width, square) โ”‚ -โ”‚ โ— โ—‹ โ—‹ โ—‹ โ—‹ โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - -**Rules:** -- โœ… Dots only (NO thumbnails) -- โœ… Swipe gesture for navigation -- โœ… Dots: 8-10px, centered below image -- โœ… Active dot: Primary color, larger -- โœ… Image counter optional (e.g., "1/5") -- โŒ NO thumbnails (redundant with dots) - -**Rationale:** Convention (Amazon, Tokopedia, Shopify all use dots only on mobile) - ---- - -### Variation Selectors - -#### Pattern: Pills/Buttons (NOT Dropdowns) - -**Color Variations:** -```html -[โฌœ White] [โฌ› Black] [๐Ÿ”ด Red] [๐Ÿ”ต Blue] -``` - -**Size/Text Variations:** -```html -[36] [37] [38] [39] [40] [41] -``` - -**Rules:** -- โœ… All options visible at once -- โœ… Pills: min 44x44px (touch target) -- โœ… Active state: Primary background + white text -- โœ… Hover state: Border color change -- โœ… Disabled state: Gray + opacity 50% -- โŒ NO dropdowns (hides options, poor UX) - -**Rationale:** Convention + Research align (Nielsen Norman Group) - ---- - -### Product Information Sections - -#### Pattern: Vertical Accordions - -**Desktop & Mobile:** -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ โ–ผ Product Description โ”‚ โ† Auto-expanded -โ”‚ Full description text... โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ โ–ถ Specifications โ”‚ โ† Collapsed -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ โ–ถ Customer Reviews โ”‚ โ† Collapsed -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - -**Rules:** -- โœ… Description: Auto-expanded on load -- โœ… Other sections: Collapsed by default -- โœ… Arrow icon: Rotates on expand/collapse -- โœ… Smooth animation: 200-300ms -- โœ… Full-width clickable header -- โŒ NO horizontal tabs (27% overlook rate) - -**Rationale:** Research (Baymard: vertical > horizontal) - ---- - -### Specifications Table - -**Pattern: Scannable Two-Column Table** - -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ Material โ”‚ 100% Cotton โ”‚ -โ”‚ Weight โ”‚ 250g โ”‚ -โ”‚ Color โ”‚ Black, White, Gray โ”‚ -โ”‚ Size โ”‚ S, M, L, XL โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - -**Rules:** -- โœ… Label column: 33% width, bold, gray background -- โœ… Value column: 67% width, regular weight -- โœ… Padding: py-4 px-6 -- โœ… Border: Bottom border on each row -- โœ… Last row: No border -- โŒ NO plain table (hard to scan) - -**Rationale:** Research (scannable > plain) - ---- - -### Buy Section - -#### Desktop & Mobile: - -**Structure:** -``` -1. Product Title (H1) -2. Price (prominent, but not overwhelming) -3. Stock Status (badge with icon) -4. Short Description (if exists) -5. Variation Selectors (pills) -6. Quantity Selector (large buttons) -7. Add to Cart (prominent CTA) -8. Wishlist Button (secondary) -9. Trust Badges (shipping, returns, secure) -10. Product Meta (SKU, categories) -``` - -**Price Display:** -```html - -
- $79.00 - $99.00 - SAVE 20% -
- - -$99.00 -``` - -**Stock Status:** -```html - -
- โœ“ - In Stock - Ships Today -
- - -
- โœ— - Out of Stock -
-``` - -**Add to Cart Button:** -```html - - -``` - -**Trust Badges:** -```html -
- -
- ๐Ÿšš -
-

Free Shipping

-

On orders over $50

-
-
- - -
- โ†ฉ -
-

30-Day Returns

-

Money-back guarantee

-
-
- - -
- ๐Ÿ”’ -
-

Secure Checkout

-

SSL encrypted payment

-
-
-
-``` - ---- - -### Mobile-Specific Patterns - -#### Sticky Bottom Bar (Optional - Future Enhancement) - -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ $79.00 [Add to Cart] โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - -**Rules:** -- โœ… Fixed at bottom on scroll -- โœ… Shows price + CTA -- โœ… Appears after scrolling past buy section -- โœ… z-index: 50 (above content) -- โœ… Shadow for depth - -**Rationale:** Convention (Tokopedia does this) - ---- - -## ๐ŸŽจ Color System - -### Primary Colors - -```css -Primary: #222222 (dark gray/black) -Primary Hover: #000000 -Primary Light: #F5F5F5 -``` - -### Semantic Colors - -```css -Success: #10B981 (green) -Error: #EF4444 (red) -Warning: #F59E0B (orange) -Info: #3B82F6 (blue) -``` - -### Sale/Discount - -```css -Sale Price: #DC2626 (red-600) -Sale Badge: #DC2626 bg, white text -Savings: #DC2626 text -``` - -### Stock Status - -```css -In Stock: #10B981 (green-600) -Low Stock: #F59E0B (orange-500) -Out of Stock: #EF4444 (red-500) -``` - -### Neutral Scale - -```css -Gray 50: #F9FAFB -Gray 100: #F3F4F6 -Gray 200: #E5E7EB -Gray 300: #D1D5DB -Gray 400: #9CA3AF -Gray 500: #6B7280 -Gray 600: #4B5563 -Gray 700: #374151 -Gray 800: #1F2937 -Gray 900: #111827 -``` - ---- - -## ๐Ÿ”˜ Interactive Elements - -### Buttons - -**Primary CTA:** -```css -Height: h-14 (56px) -Padding: px-6 -Font: text-lg font-bold -Border Radius: rounded-lg -Shadow: shadow-lg hover:shadow-xl -``` - -**Secondary:** -```css -Height: h-12 (48px) -Padding: px-4 -Font: text-base font-semibold -Border: border-2 -``` - -**Quantity Buttons:** -```css -Size: 44x44px minimum (touch target) -Border: border-2 -Icon: Plus/Minus (20px) -``` - -### Touch Targets - -**Minimum Sizes:** -```css -Mobile: 44x44px (WCAG AAA) -Desktop: 40x40px (acceptable) -``` - -**Rules:** -- โœ… All interactive elements: min 44x44px on mobile -- โœ… Adequate spacing between targets (8px min) -- โœ… Visual feedback on tap/click -- โœ… Disabled state clearly indicated - ---- - -## ๐Ÿ–ผ๏ธ Images - -### Product Images - -**Main Image:** -```css -Aspect Ratio: 1:1 (square) -Object Fit: object-contain (shows full product) -Padding: p-4 (breathing room) -Background: white or light gray -Border: border-2 border-gray-200 -Shadow: shadow-lg -``` - -**Thumbnails:** -```css -Desktop: 96-112px (w-24 md:w-28) -Mobile: N/A (use dots) -Aspect Ratio: 1:1 -Object Fit: object-cover -Border: border-2 -Active: border-primary ring-4 ring-primary -``` - -**Rules:** -- โœ… Always use `!h-full` to override WooCommerce styles -- โœ… Lazy loading for performance -- โœ… Alt text for accessibility -- โœ… WebP format when possible -- โŒ Never use object-cover for main image (crops product) - ---- - -## ๐Ÿ“ฑ Responsive Behavior - -### Grid Layout - -**Product Page:** -```css -Mobile: grid-cols-1 (single column) -Desktop: grid-cols-2 (image | info) -Gap: gap-8 lg:gap-12 -``` - -### Image Gallery - -**Desktop:** -- Thumbnails: Horizontal scroll if >4 images -- Arrows: Show when >4 images -- Layout: Main image + thumbnail strip below - -**Mobile:** -- Dots: Always visible -- Swipe: Primary interaction -- Counter: Optional (e.g., "1/5") - -### Typography - -**Responsive Sizes:** -```css -Title: text-2xl md:text-3xl -Price: text-2xl md:text-2xl (same) -Body: text-base (16px, no change) -Small: text-sm md:text-sm (same) -``` - ---- - -## โ™ฟ Accessibility - -### WCAG 2.1 AA Requirements - -**Color Contrast:** -- Text: 4.5:1 minimum -- Large text (18px+): 3:1 minimum -- Interactive elements: 3:1 minimum - -**Keyboard Navigation:** -- โœ… All interactive elements focusable -- โœ… Visible focus indicators -- โœ… Logical tab order -- โœ… Skip links for main content - -**Screen Readers:** -- โœ… Semantic HTML (h1, h2, nav, main, etc.) -- โœ… Alt text for images -- โœ… ARIA labels for icons -- โœ… Live regions for dynamic content - -**Touch Targets:** -- โœ… Minimum 44x44px on mobile -- โœ… Adequate spacing (8px min) - ---- - -## ๐Ÿš€ Performance - -### Loading Strategy - -**Critical:** -- Hero image (main product image) -- Product title, price, CTA -- Variation selectors - -**Deferred:** -- Thumbnails (lazy load) -- Description content -- Reviews section -- Related products - -**Rules:** -- โœ… Lazy load images below fold -- โœ… Skeleton loading states -- โœ… Optimize images (WebP, compression) -- โœ… Code splitting for routes -- โŒ No layout shift (reserve space) - ---- - -## ๐Ÿ“‹ Component Checklist - -### Product Page Must-Haves - -**Above the Fold:** -- [ ] Breadcrumb navigation -- [ ] Product title (H1) -- [ ] Price display (with sale if applicable) -- [ ] Stock status badge -- [ ] Main product image -- [ ] Image navigation (thumbnails/dots) -- [ ] Variation selectors (pills) -- [ ] Quantity selector -- [ ] Add to Cart button -- [ ] Trust badges - -**Below the Fold:** -- [ ] Product description (auto-expanded) -- [ ] Specifications table (collapsed) -- [ ] Reviews section (collapsed) -- [ ] Product meta (SKU, categories) -- [ ] Related products (future) - -**Mobile Specific:** -- [ ] Dots for image navigation -- [ ] Large touch targets (44x44px) -- [ ] Responsive text sizes -- [ ] Collapsible sections -- [ ] Optional: Sticky bottom bar - -**Desktop Specific:** -- [ ] Thumbnails for image navigation -- [ ] Hover states -- [ ] Larger layout (2-column grid) - ---- - -## ๐ŸŽฏ Decision Log - -### Image Gallery -- **Decision:** Dots only on mobile, thumbnails on desktop -- **Rationale:** Convention (Amazon, Tokopedia, Shopify) -- **Date:** Nov 26, 2025 - -### Variation Selectors -- **Decision:** Pills/buttons, not dropdowns -- **Rationale:** Convention + Research align (NN/g) -- **Date:** Nov 26, 2025 - -### Typography Hierarchy -- **Decision:** Title > Price (28-32px > 24-28px) -- **Rationale:** Context (we're not a marketplace) -- **Date:** Nov 26, 2025 - -### Description Pattern -- **Decision:** Auto-expanded accordion -- **Rationale:** Research (don't hide primary content) -- **Date:** Nov 26, 2025 - -### Tabs vs Accordions -- **Decision:** Vertical accordions, not horizontal tabs -- **Rationale:** Research (27% overlook tabs) -- **Date:** Nov 26, 2025 - ---- - -## ๐Ÿ“š References - -### Research Sources -- Baymard Institute UX Research -- Nielsen Norman Group Guidelines -- WCAG 2.1 Accessibility Standards - -### Convention Sources -- Amazon (marketplace reference) -- Tokopedia (marketplace reference) -- Shopify (e-commerce reference) - ---- - -## ๐Ÿ”„ Version History - -**v1.0 - Nov 26, 2025** -- Initial guide created -- Product page standards defined -- Decision framework established - ---- - -**Status:** โœ… Active -**Maintenance:** Updated by conversation -**Owner:** WooNooW Development Team diff --git a/admin-spa/BUGFIXES.md b/admin-spa/BUGFIXES.md deleted file mode 100644 index eac5cd4..0000000 --- a/admin-spa/BUGFIXES.md +++ /dev/null @@ -1,242 +0,0 @@ -# Bug Fixes & User Feedback Resolution - -## All 7 Issues Resolved โœ… - ---- - -### 1. WordPress Media Library Not Loading - -**Issue:** -- Error: "WordPress media library is not loaded. Please refresh the page." -- Blocking users from inserting images - -**Root Cause:** -- WordPress Media API (`window.wp.media`) not available in some contexts -- No fallback mechanism - -**Solution:** -```typescript -// Added fallback to URL prompt -if (typeof window.wp === 'undefined' || typeof window.wp.media === 'undefined') { - const url = window.prompt('WordPress Media library is not loaded. Please enter image URL:'); - if (url) { - onSelect({ url, id: 0, title: 'External Image', filename: url.split('/').pop() || 'image' }); - } - return; -} -``` - -**Result:** -- Users can still insert images via URL if WP Media fails -- Better error handling -- No blocking errors - ---- - -### 2. Button Variables - Too Many Options - -**Issue:** -- All variables shown in button link field -- Confusing for users (why show customer_name for a link?) - -**Solution:** -```typescript -// Filter to only show URL variables -{variables.filter(v => v.includes('_url')).map((variable) => ( - setButtonHref(buttonHref + `{${variable}}`)}>{`{${variable}}`} -))} -``` - -**Before:** -``` -{order_number} {order_total} {customer_name} {customer_email} ... -``` - -**After:** -``` -{order_url} {store_url} -``` - -**Files Modified:** -- `components/ui/rich-text-editor.tsx` -- `components/EmailBuilder/EmailBuilder.tsx` - ---- - -### 3. Color Customization - Future Feature - -**Issue:** -- Colors are hardcoded: - - Hero card gradient: `#667eea` to `#764ba2` - - Button primary: `#7f54b3` - - Button secondary border: `#7f54b3` - -**Plan:** -- Will be added to email customization form -- Allow users to set brand colors -- Apply to all email templates -- Store in settings - -**Note:** -Confirmed for future implementation. Not blocking current release. - ---- - -### 4 & 5. Headings Not Visible in Editor & Builder - -**Issue:** -- Headings (H1-H4) looked like paragraphs -- No visual distinction -- Confusing for users - -**Root Cause:** -- No CSS styles applied to heading elements -- Default browser styles insufficient - -**Solution:** -Added Tailwind utility classes for heading styles: - -```typescript -// RichTextEditor -className="prose prose-sm max-w-none [&_h1]:text-3xl [&_h1]:font-bold [&_h1]:mt-4 [&_h1]:mb-2 [&_h2]:text-2xl [&_h2]:font-bold [&_h2]:mt-3 [&_h2]:mb-2 [&_h3]:text-xl [&_h3]:font-bold [&_h3]:mt-2 [&_h3]:mb-1 [&_h4]:text-lg [&_h4]:font-bold [&_h4]:mt-2 [&_h4]:mb-1" - -// BlockRenderer (builder preview) -className="prose prose-sm max-w-none [&_h1]:text-3xl [&_h1]:font-bold [&_h1]:mt-0 [&_h1]:mb-4 [&_h2]:text-2xl [&_h2]:font-bold [&_h2]:mt-0 [&_h2]:mb-3 [&_h3]:text-xl [&_h3]:font-bold [&_h3]:mt-0 [&_h3]:mb-2 [&_h4]:text-lg [&_h4]:font-bold [&_h4]:mt-0 [&_h4]:mb-2" -``` - -**Heading Sizes:** -- **H1**: 3xl (1.875rem / 30px), bold -- **H2**: 2xl (1.5rem / 24px), bold -- **H3**: xl (1.25rem / 20px), bold -- **H4**: lg (1.125rem / 18px), bold - -**Result:** -- Headings now visually distinct -- Clear hierarchy -- Matches email preview - -**Files Modified:** -- `components/ui/rich-text-editor.tsx` -- `components/EmailBuilder/BlockRenderer.tsx` - ---- - -### 6. Missing Order Items Variable - -**Issue:** -- No variable for product list/table -- Users can't show ordered products in emails - -**Solution:** -Added `order_items` variable to order variables: - -```php -'order_items' => __('Order Items (formatted table)', 'woonoow'), -``` - -**Usage:** -```html -[card] -

Order Summary

-{order_items} -[/card] -``` - -**Will Render:** -```html - - - - - - - -
Product NameQuantityPrice
-``` - -**File Modified:** -- `includes/Core/Notifications/TemplateProvider.php` - ---- - -### 7. Edit Icon on Spacer & Divider - -**Issue:** -- Edit button (โœŽ) shown for spacer and divider -- No options to edit (they have no configurable properties) -- Clicking does nothing - -**Solution:** -Conditional rendering of edit button: - -```typescript -{/* Only show edit button for card and button blocks */} -{(block.type === 'card' || block.type === 'button') && ( - -)} -``` - -**Controls Now:** -- **Card**: โ†‘ โ†“ โœŽ ร— (all controls) -- **Button**: โ†‘ โ†“ โœŽ ร— (all controls) -- **Spacer**: โ†‘ โ†“ ร— (no edit) -- **Divider**: โ†‘ โ†“ ร— (no edit) - -**File Modified:** -- `components/EmailBuilder/BlockRenderer.tsx` - ---- - -## Testing Checklist - -### Issue 1: WP Media Fallback -- [ ] Try inserting image when WP Media is loaded -- [ ] Try inserting image when WP Media is not loaded -- [ ] Verify fallback prompt appears -- [ ] Verify image inserts correctly - -### Issue 2: Button Variables -- [ ] Open button dialog in RichTextEditor -- [ ] Verify only URL variables shown -- [ ] Open button dialog in EmailBuilder -- [ ] Verify only URL variables shown - -### Issue 3: Color Customization -- [ ] Note documented for future implementation -- [ ] Colors currently hardcoded (expected) - -### Issue 4 & 5: Heading Display -- [ ] Create card with H1 heading -- [ ] Verify H1 is large and bold in editor -- [ ] Verify H1 is large and bold in builder -- [ ] Test H2, H3, H4 similarly -- [ ] Verify preview matches - -### Issue 6: Order Items Variable -- [ ] Check variable list includes `order_items` -- [ ] Insert `{order_items}` in template -- [ ] Verify description shows "formatted table" - -### Issue 7: Edit Icon Removal -- [ ] Hover over spacer block -- [ ] Verify no edit button (only โ†‘ โ†“ ร—) -- [ ] Hover over divider block -- [ ] Verify no edit button (only โ†‘ โ†“ ร—) -- [ ] Hover over card block -- [ ] Verify edit button present (โ†‘ โ†“ โœŽ ร—) - ---- - -## Summary - -All 7 user-reported issues have been resolved: - -1. โœ… **WP Media Fallback** - No more blocking errors -2. โœ… **Button Variables Filtered** - Only relevant variables shown -3. โœ… **Color Customization Noted** - Future feature documented -4. โœ… **Headings Visible in Editor** - Proper styling applied -5. โœ… **Headings Visible in Builder** - Consistent with editor -6. โœ… **Order Items Variable** - Product list support added -7. โœ… **Edit Icon Removed** - Only on editable blocks - -**Status: Ready for Testing** ๐Ÿš€ diff --git a/admin-spa/EMAIL_BUILDER_COMPLETE.md b/admin-spa/EMAIL_BUILDER_COMPLETE.md deleted file mode 100644 index 195ee28..0000000 --- a/admin-spa/EMAIL_BUILDER_COMPLETE.md +++ /dev/null @@ -1,329 +0,0 @@ -# Email Template & Builder System - Complete โœ… - -## Overview -The WooNooW email template and builder system is now production-ready with improved templates, enhanced markdown support, and a fully functional visual builder. - ---- - -## ๐ŸŽ‰ What's Complete - -### 1. **Default Email Templates** โœ… -**File:** `includes/Email/DefaultTemplates.php` - -**Features:** -- โœ… 16 production-ready email templates (9 customer + 7 staff) -- โœ… Modern, clean markdown format (easy to read and edit) -- โœ… Professional, friendly tone -- โœ… Complete variable support -- โœ… Ready to use without any customization - -**Templates Included:** - -**Customer Templates:** -1. Order Placed - Initial order confirmation -2. Order Confirmed - Payment confirmed, ready to ship -3. Order Shipped - Tracking information -4. Order Completed - Delivery confirmation with review request -5. Order Cancelled - Cancellation notice with refund info -6. Payment Received - Payment confirmation -7. Payment Failed - Payment issue with resolution steps -8. Customer Registered - Welcome email with account benefits -9. Customer VIP Upgraded - VIP status announcement - -**Staff Templates:** -1. Order Placed - New order notification -2. Order Confirmed - Order ready to process -3. Order Shipped - Shipment confirmation -4. Order Completed - Order lifecycle complete -5. Order Cancelled - Cancellation with action items -6. Payment Received - Payment notification -7. Payment Failed - Payment failure alert - -**Template Syntax:** -``` -[card type="hero"] -Welcome message here -[/card] - -[card] -**Order Number:** #{order_number} -**Order Total:** {order_total} -[/card] - -[button url="{order_url}"]View Order Details[/button] - ---- - -ยฉ {current_year} {site_name} -``` - ---- - -### 2. **Enhanced Markdown Parser** โœ… -**File:** `admin-spa/src/lib/markdown-parser.ts` - -**New Features:** -- โœ… Button shortcode: `[button url="..."]Text[/button]` -- โœ… Horizontal rules: `---` -- โœ… Checkmarks and bullet points: `โœ“` `โ€ข` `-` `*` -- โœ… Card blocks with types: `[card type="success"]...[/card]` -- โœ… Bold, italic, headings, lists, links -- โœ… Variable support: `{variable_name}` - -**Supported Markdown:** -```markdown -# Heading 1 -## Heading 2 -### Heading 3 - -**Bold text** -*Italic text* - -- List item -โ€ข Bullet point -โœ“ Checkmark item - -[Link text](url) - ---- - -[card type="hero"] -Card content -[/card] - -[button url="#"]Button Text[/button] -``` - ---- - -### 3. **Visual Email Builder** โœ… -**File:** `admin-spa/src/components/EmailBuilder/EmailBuilder.tsx` - -**Features:** -- โœ… Drag-and-drop block editor -- โœ… Card blocks (default, success, info, warning, hero) -- โœ… Button blocks (solid/outline, width/alignment controls) -- โœ… Image blocks with WordPress media library integration -- โœ… Divider and spacer blocks -- โœ… Rich text editor with variable insertion -- โœ… Mobile fallback UI (desktop-only message) -- โœ… WordPress media modal integration (z-index and pointer-events fixed) -- โœ… Dialog outside-click prevention with WP media exception - -**Block Types:** -1. **Card** - Content container with type variants -2. **Button** - CTA button with style and layout options -3. **Image** - Image with alignment and width controls -4. **Divider** - Horizontal line separator -5. **Spacer** - Vertical spacing control - ---- - -### 4. **Preview System** โœ… -**File:** `admin-spa/src/routes/Settings/Notifications/EditTemplate.tsx` - -**Features:** -- โœ… Live preview with actual branding colors -- โœ… Sample data for all variables -- โœ… Mobile-responsive preview (reduced padding on small screens) -- โœ… Button shortcode parsing -- โœ… Card parsing with type support -- โœ… Variable replacement with sample data - -**Mobile Responsive:** -```css -@media only screen and (max-width: 600px) { - body { padding: 8px; } - .card-gutter { padding: 0 8px; } - .card { padding: 20px 16px; } -} -``` - ---- - -### 5. **Variable System** โœ… - -**Complete Variable Support:** - -**Order Variables:** -- `{order_number}` - Order number/ID -- `{order_date}` - Order creation date -- `{order_total}` - Total order amount -- `{order_url}` - Link to view order -- `{order_item_table}` - Formatted order items table -- `{completion_date}` - Order completion date - -**Customer Variables:** -- `{customer_name}` - Customer's full name -- `{customer_email}` - Customer's email -- `{customer_phone}` - Customer's phone - -**Payment Variables:** -- `{payment_method}` - Payment method used -- `{payment_status}` - Payment status -- `{payment_date}` - Payment date -- `{transaction_id}` - Transaction ID -- `{payment_retry_url}` - URL to retry payment - -**Shipping Variables:** -- `{tracking_number}` - Tracking number -- `{tracking_url}` - Tracking URL -- `{shipping_carrier}` - Carrier name -- `{shipping_address}` - Full shipping address -- `{billing_address}` - Full billing address - -**URL Variables:** -- `{order_url}` - Order details page -- `{review_url}` - Leave review page -- `{shop_url}` - Shop homepage -- `{my_account_url}` - Customer account page -- `{vip_dashboard_url}` - VIP dashboard - -**Store Variables:** -- `{site_name}` - Store name -- `{store_url}` - Store URL -- `{support_email}` - Support email -- `{current_year}` - Current year - -**VIP Variables:** -- `{vip_free_shipping_threshold}` - Free shipping threshold - ---- - -### 6. **Bug Fixes** โœ… - -**WordPress Media Modal Integration:** -- โœ… Fixed z-index conflict (WP media now appears above Radix components) -- โœ… Fixed pointer-events blocking (WP media is now fully clickable) -- โœ… Fixed dialog closing when selecting image (dialog stays open) -- โœ… Added exception for WP media in outside-click prevention - -**CSS Fixes:** -```css -/* WordPress Media Modal z-index fix */ -.media-modal { - z-index: 999999 !important; - pointer-events: auto !important; -} - -.media-modal-content { - z-index: 1000000 !important; - pointer-events: auto !important; -} -``` - -**Dialog Fix:** -```typescript -onInteractOutside={(e) => { - const wpMediaOpen = document.querySelector('.media-modal'); - if (wpMediaOpen) { - e.preventDefault(); // Keep dialog open when WP media is active - return; - } - e.preventDefault(); // Prevent closing for other outside clicks -}} -``` - ---- - -## ๐Ÿ“ฑ Mobile Strategy - -**Current Implementation (Optimal):** -- โœ… **Preview Tab** - Works on mobile (read-only viewing) -- โœ… **Code Tab** - Works on mobile (advanced users can edit) -- โŒ **Builder Tab** - Desktop-only with clear message - -**Why This Works:** -- Users can view email previews on any device -- Power users can make quick code edits on mobile -- Visual builder requires desktop for optimal UX - ---- - -## ๐ŸŽจ Email Customization Features - -**Available in Settings:** -1. **Brand Colors** - - Primary color - - Secondary color - - Hero gradient (start/end) - - Hero text color - - Button text color - -2. **Layout** - - Body background color - - Logo upload - - Header text - - Footer text - -3. **Social Links** - - Facebook, Twitter, Instagram, LinkedIn, YouTube, Website - - Custom icon color (white/color) - ---- - -## ๐Ÿš€ Ready for Production - -**What Store Owners Get:** -1. โœ… Professional email templates out-of-the-box -2. โœ… Easy customization with visual builder -3. โœ… Code mode for advanced users -4. โœ… Live preview with branding -5. โœ… Mobile-friendly emails -6. โœ… Complete variable system -7. โœ… WordPress media library integration - -**No Setup Required:** -- Templates are ready to use immediately -- Store owners can start selling without editing emails -- Customization is optional but easy -- However, backend integration is still required for full functionality - ---- - -## Next Steps (REQUIRED) - -**IMPORTANT: Backend Integration Still Needed** - -The new `DefaultTemplates.php` is ready but NOT YET WIRED to the backend! - -**Current State:** -- New templates created: `includes/Email/DefaultTemplates.php` -- Backend still using old: `includes/Core/Notifications/DefaultEmailTemplates.php` - -**To Complete Integration:** -1. Update `includes/Core/Notifications/DefaultEmailTemplates.php` to use new `DefaultTemplates` class -2. Or replace old class entirely with new one -3. Update API controller to return correct event counts per recipient -4. Wire up to database on plugin activation -5. Hook into WooCommerce order status changes -6. Test email sending - -**Example:** -```php -use WooNooW\Email\DefaultTemplates; - -// On plugin activation -$templates = DefaultTemplates::get_all_templates(); -foreach ($templates['customer'] as $event => $body) { - $subject = DefaultTemplates::get_default_subject('customer', $event); - // Save to database -} -``` - ---- - -## โœ… Phase Complete - -The email template and builder system is now **production-ready** and can be shipped to users! - -**Key Achievements:** -- โœ… 16 professional email templates -- โœ… Visual builder with drag-and-drop -- โœ… WordPress media library integration -- โœ… Mobile-responsive preview -- โœ… Complete variable system -- โœ… All bugs fixed -- โœ… Ready for general store owners - -**Time to move on to the next phase!** ๐ŸŽ‰ diff --git a/admin-spa/EMAIL_BUILDER_IMPROVEMENTS.md b/admin-spa/EMAIL_BUILDER_IMPROVEMENTS.md deleted file mode 100644 index d93e081..0000000 --- a/admin-spa/EMAIL_BUILDER_IMPROVEMENTS.md +++ /dev/null @@ -1,388 +0,0 @@ -# Email Builder - All Improvements Complete! ๐ŸŽ‰ - -## Overview - -All 5 user-requested improvements have been successfully implemented, creating a professional, user-friendly email template builder that respects WordPress conventions. - ---- - -## โœ… 1. Heading Selector in RichTextEditor - -### Problem -Users couldn't control heading levels without typing HTML manually. - -### Solution -Added a dropdown selector in the RichTextEditor toolbar. - -**Features:** -- Dropdown with options: Paragraph, H1, H2, H3, H4 -- Visual feedback (shows active heading level) -- One-click heading changes -- User controls document structure - -**UI Location:** -``` -[Paragraph โ–ผ] [B] [I] [List] [Link] ... - โ†‘ - First item in toolbar -``` - -**Files Modified:** -- `components/ui/rich-text-editor.tsx` - ---- - -## โœ… 2. Styled Buttons in Cards - -### Problem -- Buttons in TipTap cards looked raw (unstyled) -- Different appearance from standalone buttons -- Not editable (couldn't change text/URL by clicking) - -### Solution -Created a custom TipTap extension for buttons with proper styling. - -**Features:** -- Same inline styles as standalone buttons -- Solid & Outline styles available -- Fully editable via dialog -- Non-editable in editor (atomic node) -- Click button icon โ†’ dialog opens - -**Button Styles:** -```css -Solid (Primary): - background: #7f54b3 - color: white - padding: 14px 28px - -Outline (Secondary): - background: transparent - color: #7f54b3 - border: 2px solid #7f54b3 -``` - -**Files Created:** -- `components/ui/tiptap-button-extension.ts` - -**Files Modified:** -- `components/ui/rich-text-editor.tsx` - ---- - -## โœ… 3. Variable Pills for Button Links - -### Problem -- Users had to type `{variable_name}` manually -- Easy to make typos -- No suggestions or discovery - -### Solution -Added clickable variable pills under Button Link inputs. - -**Features:** -- Visual display of available variables -- One-click insertion -- No typing errors -- Works in both: - - RichTextEditor button dialog - - EmailBuilder button dialog - -**UI:** -``` -Button Link -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ {order_url} โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - -{order_number} {order_total} {customer_name} ... - โ†‘ Click any pill to insert -``` - -**Files Modified:** -- `components/ui/rich-text-editor.tsx` -- `components/EmailBuilder/EmailBuilder.tsx` - ---- - -## โœ… 4. WordPress Media Modal for TipTap Images - -### Problem -- Prompt dialog for image URL -- Manual URL entry required -- No access to media library - -### Solution -Integrated WordPress native Media Modal for image selection. - -**Features:** -- Native WordPress Media Modal -- Browse existing uploads -- Upload new images -- Full media library features -- Auto-sets: src, alt, title - -**User Flow:** -1. Click image icon in RichTextEditor toolbar -2. WordPress Media Modal opens -3. Select from library OR upload new -4. Image inserted with proper attributes - -**Files Created:** -- `lib/wp-media.ts` (WordPress Media helper) - -**Files Modified:** -- `components/ui/rich-text-editor.tsx` - ---- - -## โœ… 5. WordPress Media Modal for Store Logos/Favicon - -### Problem -- Only drag-and-drop or file picker available -- No access to existing media library -- Couldn't reuse uploaded assets - -### Solution -Added "Choose from Media Library" button to ImageUpload component. - -**Features:** -- WordPress Media Modal integration -- Filtered by media type: - - **Logo**: PNG, JPEG, SVG, WebP - - **Favicon**: PNG, ICO -- Browse and reuse existing assets -- Drag-and-drop still works - -**UI:** -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ [Upload Icon] โ”‚ -โ”‚ โ”‚ -โ”‚ Drop image here or click โ”‚ -โ”‚ Max size: 2MB โ”‚ -โ”‚ โ”‚ -โ”‚ [Choose from Media Library] โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - -**Files Modified:** -- `components/ui/image-upload.tsx` -- `routes/Settings/Store.tsx` - ---- - -## ๐Ÿ“ฆ New Files Created - -### 1. `lib/wp-media.ts` -WordPress Media Modal integration helper. - -**Functions:** -- `openWPMedia()` - Core function with options -- `openWPMediaImage()` - For general images -- `openWPMediaLogo()` - For logos (filtered) -- `openWPMediaFavicon()` - For favicons (filtered) - -**Interface:** -```typescript -interface WPMediaFile { - url: string; - id: number; - title: string; - filename: string; - alt?: string; - width?: number; - height?: number; -} -``` - -### 2. `components/ui/tiptap-button-extension.ts` -Custom TipTap node for styled buttons. - -**Features:** -- Renders with inline styles -- Atomic node (non-editable) -- Data attributes for editing -- Matches email rendering exactly - ---- - -## ๐ŸŽจ User Experience Improvements - -### For Non-Technical Users -- **Heading Control**: No HTML knowledge needed -- **Visual Buttons**: Professional styling automatically -- **Variable Discovery**: See all available variables -- **Media Library**: Familiar WordPress interface - -### For Tech-Savvy Users -- **Code Mode**: Still available with CodeMirror -- **Full Control**: Can edit raw HTML -- **Professional Tools**: Syntax highlighting, auto-completion - -### For Everyone -- **Consistent UX**: Matches WordPress conventions -- **No Learning Curve**: Familiar interfaces -- **Professional Results**: Beautiful emails every time - ---- - -## ๐Ÿ™ Respecting WordPress - -### Why This Matters - -**1. Familiar Interface** -Users already know WordPress Media Modal from Posts/Pages. - -**2. Existing Assets** -Access to all uploaded media, no re-uploading. - -**3. Better UX** -No manual URL entry, visual selection. - -**4. Professional** -Native WordPress integration, not a custom solution. - -**5. Consistent** -Same experience across WordPress admin. - -### WordPress Integration Details - -**Uses:** -- `window.wp.media` API -- WordPress REST API for uploads -- Proper nonce handling -- User permissions respected - -**Compatible with:** -- WordPress Media Library -- Custom upload handlers -- Media organization plugins -- CDN integrations - ---- - -## ๐Ÿ“‹ Complete Feature List - -### Email Builder Features -โœ… Visual block-based editor -โœ… Drag-and-drop reordering -โœ… Card blocks with rich content -โœ… Standalone buttons (outside cards) -โœ… Dividers and spacers -โœ… Code mode with CodeMirror -โœ… Variable insertion -โœ… Preview mode -โœ… Responsive design - -### RichTextEditor Features -โœ… Heading selector (H1-H4, Paragraph) -โœ… Bold, Italic formatting -โœ… Bullet and numbered lists -โœ… Links -โœ… Text alignment (left, center, right) -โœ… Image insertion (WordPress Media) -โœ… Button insertion (styled) -โœ… Variable insertion (pills) -โœ… Undo/Redo - -### Store Settings Features -โœ… Logo upload (light mode) -โœ… Logo upload (dark mode) -โœ… Favicon upload -โœ… WordPress Media Modal integration -โœ… Drag-and-drop upload -โœ… File type filtering -โœ… Preview display - ---- - -## ๐Ÿš€ Installation & Testing - -### Install Dependencies - -```bash -cd admin-spa - -# TipTap Extensions -npm install @tiptap/extension-text-align @tiptap/extension-image - -# CodeMirror -npm install codemirror @codemirror/lang-html @codemirror/theme-one-dark - -# Radix UI -npm install @radix-ui/react-radio-group -``` - -### Or Install All at Once -```bash -npm install @tiptap/extension-text-align @tiptap/extension-image codemirror @codemirror/lang-html @codemirror/theme-one-dark @radix-ui/react-radio-group -``` - -### Start Development Server -```bash -npm run dev -``` - -### Test Checklist - -**Email Builder:** -- [ ] Add card with rich content -- [ ] Use heading selector (H1-H4) -- [ ] Insert styled button in card -- [ ] Add standalone button -- [ ] Click variable pills to insert -- [ ] Insert image via WordPress Media -- [ ] Test text alignment -- [ ] Preview email -- [ ] Switch to code mode -- [ ] Save template - -**Store Settings:** -- [ ] Upload logo (light) via drag-and-drop -- [ ] Upload logo (dark) via Media Library -- [ ] Upload favicon via Media Library -- [ ] Remove and re-upload -- [ ] Verify preview display - ---- - -## ๐Ÿ“ Summary - -### What We Built - -A **professional, user-friendly email template builder** that: -- Respects WordPress conventions -- Provides visual editing for beginners -- Offers code mode for experts -- Integrates seamlessly with WordPress Media -- Produces beautiful, responsive emails - -### Key Achievements - -1. **No HTML Knowledge Required** - Visual builder handles everything -2. **Professional Styling** - Buttons and content look great -3. **WordPress Integration** - Native Media Modal support -4. **Variable System** - Easy dynamic content insertion -5. **Flexible** - Visual builder OR code mode - -### Production Ready - -All features tested and working: -- โœ… Block structure optimized -- โœ… Rich content editing -- โœ… WordPress Media integration -- โœ… Variable insertion -- โœ… Professional styling -- โœ… Code mode available -- โœ… Responsive design - ---- - -## ๐ŸŽ‰ Result - -**The PERFECT email template builder for WooCommerce!** - -Combines the simplicity of a visual builder with the power of code editing, all while respecting WordPress conventions and providing a familiar user experience. - -**Best of all worlds!** ๐Ÿš€ diff --git a/admin-spa/EMAIL_CUSTOMIZATION_COMPLETE.md b/admin-spa/EMAIL_CUSTOMIZATION_COMPLETE.md deleted file mode 100644 index c446eaf..0000000 --- a/admin-spa/EMAIL_CUSTOMIZATION_COMPLETE.md +++ /dev/null @@ -1,310 +0,0 @@ -# Email Customization - Complete Implementation! ๐ŸŽ‰ - -## โœ… All 5 Tasks Completed - -### 1. Logo URL with WP Media Library -**Status:** โœ… Complete - -**Features:** -- "Select" button opens WordPress Media Library -- Logo preview below input field -- Can paste URL or select from media -- Proper image sizing (200x60px recommended) - -**Implementation:** -- Uses `openWPMediaLogo()` from wp-media.ts -- Preview shows selected logo -- Applied to email header in EmailRenderer - ---- - -### 2. Footer Text with {current_year} Variable -**Status:** โœ… Complete - -**Features:** -- Placeholder shows `ยฉ {current_year} Your Store` -- Help text explains dynamic year variable -- Backend replaces {current_year} with actual year - -**Implementation:** -```php -$footer_text = str_replace('{current_year}', date('Y'), $footer_text); -``` - -**Example:** -``` -Input: ยฉ {current_year} My Store. All rights reserved. -Output: ยฉ 2024 My Store. All rights reserved. -``` - ---- - -### 3. Social Links in Footer -**Status:** โœ… Complete - -**Supported Platforms:** -- Facebook -- Twitter -- Instagram -- LinkedIn -- YouTube -- Website - -**Features:** -- Add/remove social links -- Platform dropdown with icons -- URL input for each -- Rendered as icons in email footer -- Centered alignment - -**UI:** -``` -[Facebook โ–ผ] [https://facebook.com/yourpage] [๐Ÿ—‘๏ธ] -[Twitter โ–ผ] [https://twitter.com/yourhandle] [๐Ÿ—‘๏ธ] -``` - -**Email Output:** -```html - -``` - ---- - -### 4. Backend API & Integration -**Status:** โœ… Complete - -**API Endpoints:** -``` -GET /woonoow/v1/notifications/email-settings -POST /woonoow/v1/notifications/email-settings -DELETE /woonoow/v1/notifications/email-settings -``` - -**Database:** -- Stored in wp_options as `woonoow_email_settings` -- JSON structure with all settings -- Defaults provided if not set - -**Security:** -- Permission checks (manage_woocommerce) -- Input sanitization (sanitize_hex_color, esc_url_raw) -- Platform whitelist for social links -- URL validation - -**Email Rendering:** -- EmailRenderer.php applies settings -- Logo/header text -- Footer with {current_year} -- Social icons -- Hero card colors -- Button colors (ready) - ---- - -### 5. Hero Card Text Color -**Status:** โœ… Complete - -**Features:** -- Separate color picker for hero text -- Applied to headings and paragraphs -- Live preview in settings -- Usually white for dark gradients - -**Implementation:** -```php -if ($type === 'hero' || $type === 'success') { - $style .= sprintf( - ' background: linear-gradient(135deg, %s 0%%, %s 100%%);', - $hero_gradient_start, - $hero_gradient_end - ); - $content_style .= sprintf(' color: %s;', $hero_text_color); -} -``` - -**Preview:** -``` -[#667eea] โ†’ [#764ba2] [#ffffff] -Gradient Start End Text Color - -Preview: -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ Preview (white text) โ”‚ -โ”‚ This is how your hero โ”‚ -โ”‚ cards will look โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - ---- - -## Complete Settings Structure - -```typescript -interface EmailSettings { - // Brand Colors - primary_color: string; // #7f54b3 - secondary_color: string; // #7f54b3 - - // Hero Card - hero_gradient_start: string; // #667eea - hero_gradient_end: string; // #764ba2 - hero_text_color: string; // #ffffff - - // Buttons - button_text_color: string; // #ffffff - - // Branding - logo_url: string; // https://... - header_text: string; // Store Name - footer_text: string; // ยฉ {current_year} ... - - // Social - social_links: SocialLink[]; // [{platform, url}] -} -``` - ---- - -## How It Works - -### Frontend โ†’ Backend -1. User customizes settings in UI -2. Clicks "Save Settings" -3. POST to `/notifications/email-settings` -4. Backend sanitizes and stores in wp_options - -### Backend โ†’ Email -1. Email triggered (order placed, etc.) -2. EmailRenderer loads settings -3. Applies colors, logo, footer -4. Renders with custom branding -5. Sends to customer - -### Preview -1. EditTemplate loads settings -2. Applies to preview iframe -3. User sees real-time preview -4. Colors, logo, footer all visible - ---- - -## Files Modified - -### Frontend -- `routes/Settings/Notifications.tsx` - Added card -- `routes/Settings/Notifications/EmailCustomization.tsx` - NEW -- `App.tsx` - Added route - -### Backend -- `includes/Api/NotificationsController.php` - API endpoints -- `includes/Core/Notifications/EmailRenderer.php` - Apply settings - ---- - -## Testing Checklist - -### Settings Page -- [ ] Navigate to Settings โ†’ Notifications โ†’ Email Customization -- [ ] Change primary color โ†’ See button preview update -- [ ] Change hero gradient โ†’ See preview update -- [ ] Change hero text color โ†’ See preview text color change -- [ ] Click "Select" for logo โ†’ Media library opens -- [ ] Select logo โ†’ Preview shows below -- [ ] Add footer text with {current_year} -- [ ] Add social links (Facebook, Twitter, etc.) -- [ ] Click "Save Settings" โ†’ Success message -- [ ] Refresh page โ†’ Settings persist -- [ ] Click "Reset to Defaults" โ†’ Confirm โ†’ Settings reset - -### Email Rendering -- [ ] Trigger test email (place order) -- [ ] Check email has custom logo (if set) -- [ ] Check email has custom header text (if set) -- [ ] Check hero cards have custom gradient -- [ ] Check hero cards have custom text color -- [ ] Check footer has {current_year} replaced with actual year -- [ ] Check footer has social icons -- [ ] Click social icons โ†’ Go to correct URLs - -### Preview -- [ ] Edit email template -- [ ] Switch to Preview tab -- [ ] See custom colors applied -- [ ] See logo/header -- [ ] See footer with social icons - ---- - -## Next Steps (Optional Enhancements) - -### Button Color Application -Currently ready but needs template update: -```php -$primary_color = $email_settings['primary_color'] ?? '#7f54b3'; -$button_text_color = $email_settings['button_text_color'] ?? '#ffffff'; - -// Apply to .button class in template -``` - -### Social Icon Assets -Need to create/host social icon images: -- facebook.png -- twitter.png -- instagram.png -- linkedin.png -- youtube.png -- website.png - -Or use Font Awesome / inline SVG. - -### Preview Integration -Update EditTemplate preview to fetch and apply email settings: -```typescript -const { data: emailSettings } = useQuery({ - queryKey: ['email-settings'], - queryFn: () => api.get('/notifications/email-settings'), -}); - -// Apply to preview styles -``` - ---- - -## Success Metrics - -โœ… **User Experience:** -- Easy logo selection (WP Media Library) -- Visual color pickers -- Live previews -- One-click save -- One-click reset - -โœ… **Functionality:** -- All settings saved to database -- All settings applied to emails -- Dynamic {current_year} variable -- Social links rendered -- Colors applied to cards - -โœ… **Code Quality:** -- Proper sanitization -- Security checks -- Type safety (TypeScript) -- Validation (platform whitelist) -- Fallback defaults - ---- - -## ๐ŸŽ‰ Complete! - -All 5 tasks implemented and tested: -1. โœ… Logo with WP Media Library -2. โœ… Footer {current_year} variable -3. โœ… Social links -4. โœ… Backend API & email rendering -5. โœ… Hero text color - -**Ready for production!** ๐Ÿš€ diff --git a/admin-spa/EMAIL_UX_REFINEMENTS_COMPLETE.md b/admin-spa/EMAIL_UX_REFINEMENTS_COMPLETE.md deleted file mode 100644 index ab7d46e..0000000 --- a/admin-spa/EMAIL_UX_REFINEMENTS_COMPLETE.md +++ /dev/null @@ -1,532 +0,0 @@ -# Email Builder UX Refinements - Complete! ๐ŸŽ‰ - -**Date:** November 13, 2025 -**Status:** โœ… ALL TASKS COMPLETE - ---- - -## Overview - -Successfully implemented all 7 major refinements to the email builder UX, including expanded social media integration, color customization, and comprehensive default email templates for all notification events. - ---- - -## โœ… Task 1: Expanded Social Media Platforms - -### Platforms Added -- **Original:** Facebook, Twitter, Instagram, LinkedIn, YouTube, Website -- **New Additions:** - - X (Twitter rebrand) - - Discord - - Spotify - - Telegram - - WhatsApp - - Threads - - Website (Earth icon) - -### Implementation -- **Frontend:** `EmailCustomization.tsx` - - Updated `getSocialIcon()` with all Lucide icons - - Expanded select dropdown with all platforms - - Each platform has appropriate icon and label - -- **Backend:** `NotificationsController.php` - - Updated `allowed_platforms` array - - Validation for all new platforms - - Sanitization maintained - -### Files Modified -- `admin-spa/src/routes/Settings/Notifications/EmailCustomization.tsx` -- `includes/Api/NotificationsController.php` - ---- - -## โœ… Task 2: PNG Icons Instead of Emoji - -### Icon Assets -- **Location:** `/assets/icons/` -- **Format:** `mage--{platform}-{color}.png` -- **Platforms:** All 11 social platforms -- **Colors:** Black and White variants (22 total files) - -### Implementation -- **Email Rendering:** `EmailRenderer.php` - - Updated `get_social_icon_url()` to return PNG URLs - - Uses plugin URL + assets path - - Dynamic color selection - -- **Preview:** `EditTemplate.tsx` - - PNG icons in preview HTML - - Uses `pluginUrl` from window object - - Matches actual email rendering - -### Benefits -- More accurate than emoji -- Consistent across email clients -- Professional appearance -- Better control over styling - -### Files Modified -- `includes/Core/Notifications/EmailRenderer.php` -- `admin-spa/src/routes/Settings/Notifications/EditTemplate.tsx` - ---- - -## โœ… Task 3: Icon Color Selection (Black/White) - -### New Setting -- **Field:** `social_icon_color` -- **Type:** Select dropdown -- **Options:** - - White Icons (for dark backgrounds) - - Black Icons (for light backgrounds) -- **Default:** White - -### Implementation -- **Frontend:** `EmailCustomization.tsx` - - Select component with two options - - Clear labeling and description - - Saved with other settings - -- **Backend:** - - `NotificationsController.php`: Validation (white/black only) - - `EmailRenderer.php`: Applied to icon URLs - - Default value in settings - -### Usage -```php -// Backend -$icon_color = $email_settings['social_icon_color'] ?? 'white'; -$icon_url = $this->get_social_icon_url($platform, $icon_color); - -// Frontend -const socialIconColor = settings.social_icon_color || 'white'; -``` - -### Files Modified -- `admin-spa/src/routes/Settings/Notifications/EmailCustomization.tsx` -- `includes/Api/NotificationsController.php` -- `includes/Core/Notifications/EmailRenderer.php` -- `admin-spa/src/routes/Settings/Notifications/EditTemplate.tsx` - ---- - -## โœ… Task 4: Body Background Color Setting - -### New Setting -- **Field:** `body_bg_color` -- **Type:** Color picker + hex input -- **Default:** `#f8f8f8` (light gray) - -### Implementation -- **UI Component:** - - Color picker for visual selection - - Text input for hex code entry - - Live preview in customization form - - Descriptive help text - -- **Application:** - - Email body background in actual emails - - Preview iframe background - - Consistent across all email templates - -### Usage -```typescript -// Frontend -const bodyBgColor = settings.body_bg_color || '#f8f8f8'; - -// Applied to preview -body { background: ${bodyBgColor}; } -``` - -### Files Modified -- `admin-spa/src/routes/Settings/Notifications/EmailCustomization.tsx` -- `includes/Api/NotificationsController.php` -- `admin-spa/src/routes/Settings/Notifications/EditTemplate.tsx` - ---- - -## โœ… Task 5: Editor Mode Preview Styling - -### Current Behavior -- **Editor Mode:** Shows content structure (blocks, HTML) -- **Preview Mode:** Shows final styled result with all customizations - -### Design Decision -This is **intentional and follows standard email builder UX patterns**: -- Editor mode = content editing focus -- Preview mode = visual result preview -- Separation of concerns improves usability - -### Rationale -- Users edit content in editor mode without distraction -- Preview mode shows exact final appearance -- Standard pattern in tools like Mailchimp, SendGrid, etc. -- Prevents confusion between editing and viewing - -### Status -โœ… **Working as designed** - No changes needed - ---- - -## โœ… Task 6: Hero Preview Text Color Fix - -### Issue -Hero card preview in customization form wasn't using selected `hero_text_color`. - -### Solution -Applied color directly to child elements instead of parent: - -```tsx -// Before (color inheritance not working) -
-

Preview

-

Text

-
- -// After (explicit color on each element) -
-

Preview

-

Text

-
-``` - -### Result -- Hero preview now correctly shows selected text color -- Live updates as user changes color -- Matches actual email rendering - -### Files Modified -- `admin-spa/src/routes/Settings/Notifications/EmailCustomization.tsx` - ---- - -## โœ… Task 7: Complete Default Email Content - -### New File Created -**`includes/Core/Notifications/DefaultEmailTemplates.php`** - -Comprehensive default templates for all notification events with professional, card-based HTML. - -### Templates Included - -#### Order Events - -**1. Order Placed (Staff)** -``` -[card type="hero"] - New Order Received! - Order from {customer_name} -[/card] -[card] Order Details [/card] -[card] Customer Details [/card] -[card] Order Items [/card] -[button] View Order Details [/button] -``` - -**2. Order Processing (Customer)** -``` -[card type="success"] - Order Confirmed! - Thank you message -[/card] -[card] Order Summary [/card] -[card] What's Next [/card] -[card] Order Items [/card] -[button] Track Your Order [/button] -``` - -**3. Order Completed (Customer)** -``` -[card type="success"] - Order Completed! - Enjoy your purchase -[/card] -[card] Order Details [/card] -[card] Thank You Message [/card] -[button] View Order [/button] -[button outline] Continue Shopping [/button] -``` - -**4. Order Cancelled (Staff)** -``` -[card type="warning"] - Order Cancelled -[/card] -[card] Order Details [/card] -[button] View Order Details [/button] -``` - -**5. Order Refunded (Customer)** -``` -[card type="info"] - Refund Processed -[/card] -[card] Refund Details [/card] -[card] What Happens Next [/card] -[button] View Order [/button] -``` - -#### Product Events - -**6. Low Stock Alert (Staff)** -``` -[card type="warning"] - Low Stock Alert -[/card] -[card] Product Details [/card] -[card] Action Required [/card] -[button] View Product [/button] -``` - -**7. Out of Stock Alert (Staff)** -``` -[card type="warning"] - Out of Stock Alert -[/card] -[card] Product Details [/card] -[card] Immediate Action Required [/card] -[button] Manage Product [/button] -``` - -#### Customer Events - -**8. New Customer (Customer)** -``` -[card type="hero"] - Welcome! - Thank you for creating an account -[/card] -[card] Your Account Details [/card] -[card] Get Started (feature list) [/card] -[button] Go to My Account [/button] -[button outline] Start Shopping [/button] -``` - -**9. Customer Note (Customer)** -``` -[card type="info"] - Order Note Added -[/card] -[card] Order Details [/card] -[card] Note from Store [/card] -[button] View Order [/button] -``` - -### Integration - -**Updated `TemplateProvider.php`:** -```php -public static function get_default_templates() { - // Generate email templates from DefaultEmailTemplates - foreach ($events as $event_id => $recipient_type) { - $default = DefaultEmailTemplates::get_template($event_id, $recipient_type); - $templates["{$event_id}_email"] = [ - 'event_id' => $event_id, - 'channel_id' => 'email', - 'subject' => $default['subject'], - 'body' => $default['body'], - 'variables' => self::get_variables_for_event($event_id), - ]; - } - // ... push templates -} -``` - -### Features -- โœ… All 9 events covered -- โœ… Separate staff/customer templates -- โœ… Professional copy and structure -- โœ… Card-based modern design -- โœ… Multiple card types (hero, success, warning, info) -- โœ… Multiple buttons with styles -- โœ… Proper variable placeholders -- โœ… Consistent branding -- โœ… Push notification templates included - -### Files Created/Modified -- `includes/Core/Notifications/DefaultEmailTemplates.php` (NEW) -- `includes/Core/Notifications/TemplateProvider.php` (UPDATED) - ---- - -## Technical Summary - -### Settings Schema - -```typescript -interface EmailSettings { - // Colors - primary_color: string; // #7f54b3 - secondary_color: string; // #7f54b3 - hero_gradient_start: string; // #667eea - hero_gradient_end: string; // #764ba2 - hero_text_color: string; // #ffffff - button_text_color: string; // #ffffff - body_bg_color: string; // #f8f8f8 (NEW) - social_icon_color: 'white' | 'black'; // (NEW) - - // Branding - logo_url: string; - header_text: string; - footer_text: string; - - // Social Links - social_links: Array<{ - platform: string; // 11 platforms supported - url: string; - }>; -} -``` - -### API Endpoints - -``` -GET /woonoow/v1/notifications/email-settings -POST /woonoow/v1/notifications/email-settings -DELETE /woonoow/v1/notifications/email-settings -``` - -### Storage -- **Option Key:** `woonoow_email_settings` -- **Sanitization:** All inputs sanitized -- **Validation:** Colors, URLs, platforms validated -- **Defaults:** Comprehensive defaults provided - ---- - -## Testing Checklist - -### Social Media Integration -- [x] All 11 platforms appear in dropdown -- [x] Icons display correctly in customization UI -- [x] PNG icons render in email preview -- [x] PNG icons render in actual emails -- [x] Black/white icon selection works -- [x] Social links save and load correctly - -### Color Settings -- [x] Body background color picker works -- [x] Body background applies to preview -- [x] Body background applies to emails -- [x] Icon color selection works -- [x] Hero text color preview fixed -- [x] All colors save and persist - -### Default Templates -- [x] All 9 email events have templates -- [x] Staff templates appropriate for admins -- [x] Customer templates appropriate for customers -- [x] Card syntax correct -- [x] Variables properly placed -- [x] Buttons included where needed -- [x] Push templates complete - -### Integration -- [x] Settings API working -- [x] Frontend loads settings -- [x] Preview reflects settings -- [x] Emails use settings -- [x] Reset functionality works -- [x] Save functionality works - ---- - -## Files Changed - -### Frontend (React/TypeScript) -``` -admin-spa/src/routes/Settings/Notifications/ -โ”œโ”€โ”€ EmailCustomization.tsx (Updated - UI for all settings) -โ””โ”€โ”€ EditTemplate.tsx (Updated - Preview with PNG icons) -``` - -### Backend (PHP) -``` -includes/ -โ”œโ”€โ”€ Api/ -โ”‚ โ””โ”€โ”€ NotificationsController.php (Updated - API endpoints) -โ””โ”€โ”€ Core/Notifications/ - โ”œโ”€โ”€ EmailRenderer.php (Updated - PNG icons, colors) - โ”œโ”€โ”€ TemplateProvider.php (Updated - Integration) - โ””โ”€โ”€ DefaultEmailTemplates.php (NEW - All default content) -``` - -### Assets -``` -assets/icons/ -โ”œโ”€โ”€ mage--discord-black.png -โ”œโ”€โ”€ mage--discord-white.png -โ”œโ”€โ”€ mage--earth-black.png -โ”œโ”€โ”€ mage--earth-white.png -โ”œโ”€โ”€ mage--facebook-black.png -โ”œโ”€โ”€ mage--facebook-white.png -โ”œโ”€โ”€ mage--instagram-black.png -โ”œโ”€โ”€ mage--instagram-white.png -โ”œโ”€โ”€ mage--linkedin-black.png -โ”œโ”€โ”€ mage--linkedin-white.png -โ”œโ”€โ”€ mage--spotify-black.png -โ”œโ”€โ”€ mage--spotify-white.png -โ”œโ”€โ”€ mage--telegram-black.png -โ”œโ”€โ”€ mage--telegram-white.png -โ”œโ”€โ”€ mage--threads-black.png -โ”œโ”€โ”€ mage--threads-white.png -โ”œโ”€โ”€ mage--whatsapp-black.png -โ”œโ”€โ”€ mage--whatsapp-white.png -โ”œโ”€โ”€ mage--x-black.png -โ”œโ”€โ”€ mage--x-white.png -โ”œโ”€โ”€ mage--youtube-black.png -โ””โ”€โ”€ mage--youtube-white.png -``` - ---- - -## Next Steps (Optional Enhancements) - -### Future Improvements -1. **Email Template Variables** - - Add more dynamic variables - - Variable preview in editor - - Variable documentation - -2. **Template Library** - - Pre-built template variations - - Industry-specific templates - - Seasonal templates - -3. **A/B Testing** - - Test different subject lines - - Test different layouts - - Analytics integration - -4. **Advanced Customization** - - Font family selection - - Font size controls - - Spacing/padding controls - - Border radius controls - -5. **Conditional Content** - - Show/hide based on order value - - Show/hide based on customer type - - Dynamic product recommendations - ---- - -## Conclusion - -All 7 tasks successfully completed! The email builder now has: -- โœ… Expanded social media platform support (11 platforms) -- โœ… Professional PNG icons with color selection -- โœ… Body background color customization -- โœ… Fixed hero preview text color -- โœ… Complete default templates for all events -- โœ… Comprehensive documentation - -The email system is now production-ready with professional defaults and extensive customization options. - -**Total Commits:** 2 -**Total Files Modified:** 6 -**Total Files Created:** 23 (22 icons + 1 template class) -**Lines of Code:** ~1,500+ - -๐ŸŽ‰ **Project Status: COMPLETE** diff --git a/admin-spa/FINAL_UX_IMPROVEMENTS.md b/admin-spa/FINAL_UX_IMPROVEMENTS.md deleted file mode 100644 index 3df216e..0000000 --- a/admin-spa/FINAL_UX_IMPROVEMENTS.md +++ /dev/null @@ -1,414 +0,0 @@ -# Final UX Improvements - Session Complete! ๐ŸŽ‰ - -## All 6 Improvements Implemented - ---- - -## 1. โœ… Dialog Scrollable Body with Fixed Header/Footer - -### Problem -Long content made header (with close button) and footer (with action buttons) disappear. Users couldn't close dialog or take action. - -### Solution -- Changed dialog to flexbox layout (`flex flex-col`) -- Added `DialogBody` component with `overflow-y-auto` -- Header and footer fixed with borders -- Max height `90vh` for viewport fit - -### Structure -```tsx - (flex flex-col max-h-[90vh]) - (px-6 pt-6 pb-4 border-b) - FIXED - (flex-1 overflow-y-auto px-6 py-4) - SCROLLABLE - (px-6 py-4 border-t mt-auto) - FIXED - -``` - -### Files -- `components/ui/dialog.tsx` -- `components/ui/rich-text-editor.tsx` - ---- - -## 2. โœ… Dialog Close-Proof (No Outside Click) - -### Problem -Accidental outside clicks closed dialog, losing user input and causing confusion. - -### Solution -```tsx - e.preventDefault()} - onInteractOutside={(e) => e.preventDefault()} -> -``` - -### Result -- Must click X button or Cancel to close -- No accidental dismissal -- No lost UI control -- Better user confidence - -### Files -- `components/ui/dialog.tsx` - ---- - -## 3. โœ… Code Mode Button Moved to Left - -### Problem -Inconsistent layout - Code Mode button was grouped with Editor/Preview tabs on the right. - -### Solution -Moved Code Mode button next to "Message Body" label on the left. - -### Before -``` -Message Body [Editor|Preview] [Code Mode] -``` - -### After -``` -Message Body [Code Mode] [Editor|Preview] -``` - -### Result -- Logical grouping -- Editor/Preview tabs stay together on right -- Code Mode is a mode toggle, not a tab -- Consistent, professional layout - -### Files -- `routes/Settings/Notifications/EditTemplate.tsx` - ---- - -## 4. โœ… Markdown Support in Code Mode! ๐ŸŽ‰ - -### Problem -HTML is verbose and not user-friendly for tech-savvy users who prefer Markdown. - -### Solution -Full Markdown support with custom syntax for email-specific features. - -### Markdown Syntax - -**Standard Markdown:** -```markdown -# Heading 1 -## Heading 2 -### Heading 3 - -**Bold text** -*Italic text* - -- List item 1 -- List item 2 - -[Link text](https://example.com) -``` - -**Card Blocks:** -```markdown -:::card -# Your heading -Your content here -::: - -:::card[success] -โœ… Success message -::: - -:::card[warning] -โš ๏ธ Warning message -::: -``` - -**Button Blocks:** -```markdown -[button](https://example.com){Click Here} - -[button style="outline"](https://example.com){Secondary Button} -``` - -**Variables:** -```markdown -Hi {customer_name}, - -Your order #{order_number} totaling {order_total} is ready! -``` - -### Features -- Bidirectional conversion (HTML โ†” Markdown) -- Toggle button: "๐Ÿ“ Switch to Markdown" / "๐Ÿ”ง Switch to HTML" -- Syntax highlighting for both modes -- Preserves all email features -- Easier for non-HTML users - -### Files -- `lib/markdown-parser.ts` - Parser implementation -- `components/ui/code-editor.tsx` - Mode toggle -- `routes/Settings/Notifications/EditTemplate.tsx` - Enable support - -### Dependencies -```bash -npm install @codemirror/lang-markdown -``` - ---- - -## 5. โœ… Realistic Variable Simulations in Preview - -### Problem -Variables showed as raw text like `{order_items_list}` in preview, making it hard to judge layout. - -### Solution -Added realistic HTML simulations for better preview experience. - -### order_items_list Simulation -```html -
    -
  • - Premium T-Shirt ร— 2
    - Size: L, Color: Blue
    - $49.98 -
  • -
  • - Classic Jeans ร— 1
    - Size: 32, Color: Dark Blue
    - $79.99 -
  • -
-``` - -### order_items_table Simulation -```html - - - - - - - - - - - - - - - -
ProductQtyPrice
- Premium T-Shirt
- Size: L, Color: Blue -
2$49.98
-``` - -### Result -- Users see realistic email preview -- Can judge layout and design accurately -- No guessing what variables will look like -- Professional presentation -- Better design decisions - -### Files -- `routes/Settings/Notifications/EditTemplate.tsx` - ---- - -## 6. โœ… Smart Back Navigation to Accordion - -### Problem -- Back button used `navigate(-1)` -- Returned to parent page but wrong tab -- Required 2-3 clicks to get back to Email accordion -- Lost context, poor UX - -### Solution -Navigate with query params to preserve context. - -### Implementation - -**EditTemplate.tsx:** -```tsx - -``` - -**Templates.tsx:** -```tsx -const [openAccordion, setOpenAccordion] = useState(); - -useEffect(() => { - const eventParam = searchParams.get('event'); - if (eventParam) { - setOpenAccordion(eventParam); - } -}, [searchParams]); - - - {/* ... */} - -``` - -### User Flow -1. User in Email accordion, editing "Order Placed" template -2. Clicks Back button -3. Returns to Notifications page with `?tab=email&event=order_placed` -4. Email accordion auto-opens -5. "Order Placed" template visible -6. Perfect context preservation! - -### Result -- One-click return to context -- No confusion -- No extra clicks -- Professional navigation -- Context always preserved - -### Files -- `routes/Settings/Notifications/EditTemplate.tsx` -- `routes/Settings/Notifications/Templates.tsx` - ---- - -## Summary - -### What We Built -Six critical UX improvements that transform the email builder from good to **perfect**. - -### Key Achievements - -1. **Healthy Dialogs** - Scrollable body, fixed header/footer, no accidental closing -2. **Logical Layout** - Code Mode button in correct position -3. **Markdown Support** - Easier editing for tech-savvy users -4. **Realistic Previews** - See exactly what emails will look like -5. **Smart Navigation** - Context-aware back button - -### Impact - -**For Users:** -- No frustration -- Faster workflow -- Better previews -- Professional tools -- Intuitive navigation - -**For Business:** -- Happy users -- Fewer support tickets -- Better email designs -- Professional product -- Competitive advantage - ---- - -## Testing Checklist - -### 1. Dialog Improvements -- [ ] Paste long content in dialog -- [ ] Verify header stays visible -- [ ] Verify footer stays visible -- [ ] Body scrolls independently -- [ ] Click outside dialog - should NOT close -- [ ] Click X button - closes -- [ ] Click Cancel - closes - -### 2. Code Mode Button -- [ ] Verify button is left of label -- [ ] Verify Editor/Preview tabs on right -- [ ] Toggle Code Mode -- [ ] Layout looks professional - -### 3. Markdown Support -- [ ] Toggle to Markdown mode -- [ ] Write Markdown syntax -- [ ] Use :::card blocks -- [ ] Use [button] syntax -- [ ] Toggle back to HTML -- [ ] Verify conversion works both ways - -### 4. Variable Simulations -- [ ] Use {order_items_list} in template -- [ ] Preview shows realistic list -- [ ] Use {order_items_table} in template -- [ ] Preview shows realistic table -- [ ] Verify styling looks good - -### 5. Back Navigation -- [ ] Open Email accordion -- [ ] Edit a template -- [ ] Click Back -- [ ] Verify returns to Email accordion -- [ ] Verify accordion is open -- [ ] Verify correct template visible - ---- - -## Dependencies - -### New Package Required -```bash -npm install @codemirror/lang-markdown -``` - -### Complete Install Command -```bash -cd admin-spa -npm install @tiptap/extension-text-align @tiptap/extension-image codemirror @codemirror/lang-html @codemirror/lang-markdown @codemirror/theme-one-dark @radix-ui/react-radio-group -``` - ---- - -## Files Modified - -### Components -1. `components/ui/dialog.tsx` - Scrollable body, close-proof -2. `components/ui/code-editor.tsx` - Markdown support -3. `components/ui/rich-text-editor.tsx` - Use DialogBody - -### Routes -4. `routes/Settings/Notifications/EditTemplate.tsx` - Layout, simulations, navigation -5. `routes/Settings/Notifications/Templates.tsx` - Accordion state management - -### Libraries -6. `lib/markdown-parser.ts` - NEW - Markdown โ†” HTML conversion - -### Documentation -7. `DEPENDENCIES.md` - Updated with markdown package - ---- - -## ๐ŸŽ‰ Result - -**The PERFECT email builder experience!** - -All user feedback addressed: -- โœ… Healthy dialogs -- โœ… Logical layout -- โœ… Markdown support -- โœ… Realistic previews -- โœ… Smart navigation -- โœ… Professional UX - -**Ready for production!** ๐Ÿš€ - ---- - -## Notes - -### Lint Warnings -The following lint warnings are expected and can be ignored: -- `mso-table-lspace` and `mso-table-rspace` in `templates/emails/modern.html` - These are Microsoft Outlook-specific CSS properties - -### Future Enhancements -- Variable categorization (order vs account vs product) -- Color customization UI -- More default templates -- Template preview mode -- A/B testing support - ---- - -**Session Complete! All 6 improvements implemented successfully!** โœจ diff --git a/admin-spa/UX_IMPROVEMENTS.md b/admin-spa/UX_IMPROVEMENTS.md deleted file mode 100644 index d289a2e..0000000 --- a/admin-spa/UX_IMPROVEMENTS.md +++ /dev/null @@ -1,424 +0,0 @@ -# UX Improvements - Perfect Builder Experience! ๐ŸŽฏ - -## Overview - -Six major UX improvements implemented to create the perfect email builder experience. These changes address real user pain points and make the builder intuitive and professional. - ---- - -## 1. Prevent Link/Button Navigation in Builder โœ… - -### Problem -- Clicking links or buttons in the builder redirected users -- Users couldn't edit button text (clicking opened the link) -- Frustrating experience, broke editing workflow - -### Solution -**BlockRenderer (Email Builder):** -```typescript -const handleClick = (e: React.MouseEvent) => { - const target = e.target as HTMLElement; - if (target.tagName === 'A' || target.tagName === 'BUTTON' || - target.closest('a') || target.closest('button')) { - e.preventDefault(); - e.stopPropagation(); - } -}; - -return ( -
- {/* Block content */} -
-); -``` - -**RichTextEditor (TipTap):** -```typescript -editorProps: { - handleClick: (view, pos, event) => { - const target = event.target as HTMLElement; - if (target.tagName === 'A' || target.closest('a')) { - event.preventDefault(); - return true; - } - return false; - }, -} -``` - -### Result -- Links and buttons are now **editable only** -- No accidental navigation -- Click to edit, not to follow -- Perfect editing experience - ---- - -## 2. Default Templates Use Raw Buttons โœ… - -### Problem -- Default templates had buttons wrapped in cards: - ```html - [card] -

- View Order -

- [/card] - ``` -- Didn't match current block structure -- Confusing for users - -### Solution -Changed to raw button blocks: -```html -[button link="{order_url}" style="solid"]View Order Details[/button] -``` - -### Before & After - -**Before:** -``` -[card] -

Track Order

-

Questions? Contact us.

-[/card] -``` - -**After:** -``` -[button link="{order_url}" style="solid"]Track Your Order[/button] - -[card] -

Questions? Contact us.

-[/card] -``` - -### Result -- Matches block structure -- Buttons are standalone blocks -- Easier to edit and rearrange -- Consistent with builder UI - ---- - -## 3. Split Order Items: List & Table โœ… - -### Problem -- Only one `{order_items}` variable -- No control over presentation format -- Users want different styles for different emails - -### Solution -Split into two variables: - -**`{order_items_list}`** - Formatted List -```html -
    -
  • Product Name ร— 2 - $50.00
  • -
  • Another Product ร— 1 - $25.00
  • -
-``` - -**`{order_items_table}`** - Formatted Table -```html - - - - - - - - - - - - - - - -
ProductQtyPrice
Product Name2$50.00
-``` - -### Use Cases -- **List format**: Simple, compact, mobile-friendly -- **Table format**: Detailed, professional, desktop-optimized - -### Result -- Better control over presentation -- Choose format based on email type -- Professional-looking order summaries - ---- - -## 4. Payment URL Variable Added โœ… - -### Problem -- No way to link to payment page -- Users couldn't send payment reminders -- Missing critical functionality - -### Solution -Added `{payment_url}` variable with smart strategy: - -**Strategy:** -```php -if (manual_payment) { - // Use order details URL or thank you page - // Contains payment instructions - $payment_url = get_order_url(); -} else if (api_payment) { - // Use payment gateway URL - // From order payment_meta - $payment_url = get_payment_gateway_url(); -} -``` - -**Implementation:** -```php -'payment_url' => __('Payment URL (for pending payments)', 'woonoow'), -``` - -### Use Cases -- **Pending payment emails**: "Complete your payment" -- **Failed payment emails**: "Retry payment" -- **Payment reminder emails**: "Your payment is waiting" - -### Example -```html -[card type="warning"] -

โณ Payment Pending

-

Your order is waiting for payment.

-[/card] - -[button link="{payment_url}" style="solid"]Complete Payment[/button] -``` - -### Result -- Complete payment workflow -- Better conversion rates -- Professional payment reminders - ---- - -## 5. Variable Categorization Strategy ๐Ÿ“ - -### Problem -- All variables shown for all events -- Confusing (why show `order_items` for account emails?) -- Poor UX - -### Strategy (For Future Implementation) - -**Order-Related Events:** -```javascript -{ - order_number, order_total, order_status, - order_items_list, order_items_table, - payment_url, tracking_number, - customer_name, customer_email, - shipping_address, billing_address -} -``` - -**Account-Related Events:** -```javascript -{ - customer_name, customer_email, - login_url, account_url, - reset_password_url -} -``` - -**Product-Related Events:** -```javascript -{ - product_name, product_url, - product_price, product_image, - stock_quantity -} -``` - -### Implementation Plan -1. Add event categories to event definitions -2. Filter variables by event category -3. Show only relevant variables in UI -4. Better UX, less confusion - -### Result (When Implemented) -- Contextual variables only -- Cleaner UI -- Faster template creation -- Less user confusion - ---- - -## 6. WordPress Media Library Fixed โœ… - -### Problem -- WordPress Media library not loaded -- Error: "WordPress media library is not loaded" -- Browser prompt fallback (poor UX) -- Store logos/favicon upload broken - -### Root Cause -```php -// Missing in Assets.php -wp_enqueue_media(); // โ† Not called! -``` - -### Solution - -**Assets.php:** -```php -public static function enqueue($hook) { - if ($hook !== 'toplevel_page_woonoow') { - return; - } - - // Enqueue WordPress Media library for image uploads - wp_enqueue_media(); // โ† Added! - - // ... rest of code -} -``` - -**wp-media.ts (Better Error Handling):** -```typescript -if (typeof window.wp === 'undefined' || typeof window.wp.media === 'undefined') { - console.error('WordPress media library is not available'); - console.error('window.wp:', typeof window.wp); - console.error('window.wp.media:', typeof (window as any).wp?.media); - - alert('WordPress Media library is not loaded.\n\n' + - 'Please ensure you are in WordPress admin and the page has fully loaded.\n\n' + - 'If the problem persists, try refreshing the page.'); - return; -} -``` - -### Result -- WordPress Media Modal loads properly -- No more errors -- Professional image selection -- Store logos/favicon upload works -- Better error messages with debugging info - ---- - -## Testing Checklist - -### 1. Link/Button Navigation -- [ ] Click link in card content โ†’ no navigation -- [ ] Click button in builder โ†’ no navigation -- [ ] Click button in RichTextEditor โ†’ no navigation -- [ ] Edit button text by clicking โ†’ works -- [ ] Links/buttons work in email preview - -### 2. Default Templates -- [ ] Create new template from default -- [ ] Verify buttons are standalone blocks -- [ ] Verify buttons not wrapped in cards -- [ ] Edit button easily -- [ ] Rearrange blocks easily - -### 3. Order Items Variables -- [ ] Insert `{order_items_list}` โ†’ shows list format -- [ ] Insert `{order_items_table}` โ†’ shows table format -- [ ] Preview both formats -- [ ] Verify formatting in email - -### 4. Payment URL -- [ ] Insert `{payment_url}` in button -- [ ] Verify variable appears in list -- [ ] Test with pending payment order -- [ ] Test with manual payment -- [ ] Test with API payment gateway - -### 5. WordPress Media -- [ ] Click image icon in RichTextEditor -- [ ] Verify WP Media Modal opens -- [ ] Select image from library -- [ ] Upload new image -- [ ] Click "Choose from Media Library" in Store settings -- [ ] Upload logo (light mode) -- [ ] Upload logo (dark mode) -- [ ] Upload favicon - ---- - -## Summary - -### What We Built -A **perfect email builder experience** with: -- No accidental navigation -- Intuitive block structure -- Flexible content formatting -- Complete payment workflow -- Professional image management - -### Key Achievements - -1. **โœ… No Navigation in Builder** - Links/buttons editable only -2. **โœ… Raw Button Blocks** - Matches current structure -3. **โœ… List & Table Formats** - Better control -4. **โœ… Payment URL** - Complete workflow -5. **๐Ÿ“ Variable Strategy** - Future improvement -6. **โœ… WP Media Fixed** - Professional uploads - -### Impact - -**For Users:** -- Faster template creation -- No frustration -- Professional results -- Intuitive workflow - -**For Business:** -- Better conversion (payment URLs) -- Professional emails -- Happy users -- Fewer support tickets - ---- - -## Files Modified - -### Frontend (TypeScript/React) -1. `components/EmailBuilder/BlockRenderer.tsx` - Prevent navigation -2. `components/ui/rich-text-editor.tsx` - Prevent navigation -3. `lib/wp-media.ts` - Better error handling - -### Backend (PHP) -4. `includes/Admin/Assets.php` - Enqueue WP Media -5. `includes/Core/Notifications/TemplateProvider.php` - Variables & defaults - ---- - -## Next Steps - -### Immediate -1. Test all features -2. Verify WP Media loads -3. Test payment URL generation -4. Verify order items formatting - -### Future -1. Implement variable categorization -2. Add color customization UI -3. Create more default templates -4. Add template preview mode - ---- - -## ๐ŸŽ‰ Result - -**The PERFECT email builder experience!** - -All pain points addressed: -- โœ… No accidental navigation -- โœ… Intuitive editing -- โœ… Professional features -- โœ… WordPress integration -- โœ… Complete workflow - -**Ready for production!** ๐Ÿš€ diff --git a/archive/CALCULATION_EFFICIENCY_AUDIT.md b/archive/CALCULATION_EFFICIENCY_AUDIT.md deleted file mode 100644 index 8345cdd..0000000 --- a/archive/CALCULATION_EFFICIENCY_AUDIT.md +++ /dev/null @@ -1,368 +0,0 @@ -# Calculation Efficiency Audit - -## ๐Ÿšจ CRITICAL ISSUE FOUND - -### Current Implementation (BLOATED): - -**Frontend makes 2 separate API calls:** - -```tsx -// Call 1: Get shipping rates -const shippingRates = useQuery({ - queryFn: () => api.post('/shipping/calculate', { items, shipping }) -}); - -// Call 2: Get order preview with taxes -const orderPreview = useQuery({ - queryFn: () => api.post('/orders/preview', { items, billing, shipping, shipping_method, coupons }) -}); -``` - -**Backend processes cart TWICE:** - -```php -// Endpoint 1: /shipping/calculate -WC()->cart->empty_cart(); -WC()->cart->add_to_cart(...); // Add items -WC()->cart->calculate_shipping(); // Calculate -WC()->cart->calculate_totals(); // Calculate -WC()->cart->empty_cart(); // Clean up - -// Endpoint 2: /orders/preview (AGAIN!) -WC()->cart->empty_cart(); -WC()->cart->add_to_cart(...); // Add items AGAIN -WC()->cart->calculate_shipping(); // Calculate AGAIN -WC()->cart->calculate_totals(); // Calculate AGAIN -WC()->cart->empty_cart(); // Clean up AGAIN -``` - -### Problems: - -โŒ **2 HTTP requests** instead of 1 -โŒ **Cart initialized twice** (expensive) -โŒ **Items added twice** (database queries) -โŒ **Shipping calculated twice** (API calls to UPS, Rajaongkir, etc.) -โŒ **Taxes calculated twice** (database queries) -โŒ **Network latency doubled** -โŒ **Server load doubled** - ---- - -## โœ… SOLUTION: Single Unified Endpoint - -### New Endpoint: `/woonoow/v1/orders/calculate` - -**Single request with all data:** - -```typescript -// Frontend: ONE API call -const calculation = useQuery({ - queryFn: () => api.post('/orders/calculate', { - items: [{ product_id: 1, qty: 2 }], - billing: { country: 'ID', state: 'JB', city: 'Bandung' }, - shipping: { country: 'ID', state: 'JB', city: 'Bandung' }, - coupons: ['SAVE10'], - // Optional: If user already selected shipping method - shipping_method: 'flat_rate:1', - }) -}); -``` - -**Single response with everything:** - -```json -{ - "subtotal": 100000, - "shipping": { - "methods": [ - { - "id": "cekongkir:jne:reg", - "label": "JNE REG", - "cost": 31000, - "selected": false - }, - { - "id": "cekongkir:jne:yes", - "label": "JNE YES", - "cost": 42000, - "selected": false - } - ], - "selected_method": null, - "selected_cost": 0 - }, - "coupons": [ - { - "code": "SAVE10", - "discount": 10000, - "valid": true - } - ], - "taxes": [ - { - "label": "PPN 11%", - "amount": 13310 - } - ], - "total_tax": 13310, - "total": 134310, - "breakdown": { - "subtotal": 100000, - "shipping": 31000, - "discount": -10000, - "tax": 13310, - "total": 134310 - } -} -``` - -### Backend: ONE cart initialization - -```php -public static function calculate_order( WP_REST_Request $req ) { - $items = $req->get_param('items'); - $billing = $req->get_param('billing'); - $shipping = $req->get_param('shipping'); - $coupons = $req->get_param('coupons') ?? []; - $selected_method = $req->get_param('shipping_method'); - - // Initialize cart ONCE - WC()->cart->empty_cart(); - WC()->session->init(); - - // Add items ONCE - foreach ($items as $item) { - WC()->cart->add_to_cart($item['product_id'], $item['qty']); - } - - // Set addresses ONCE - WC()->customer->set_billing_country($billing['country']); - WC()->customer->set_shipping_country($shipping['country']); - // ... set other fields - - // Apply coupons ONCE - foreach ($coupons as $code) { - WC()->cart->apply_coupon($code); - } - - // Calculate shipping ONCE - WC()->cart->calculate_shipping(); - - // Get all available shipping methods - $packages = WC()->shipping()->get_packages(); - $shipping_methods = []; - foreach ($packages[0]['rates'] as $rate) { - $shipping_methods[] = [ - 'id' => $rate->get_id(), - 'label' => $rate->get_label(), - 'cost' => $rate->get_cost(), - 'selected' => $rate->get_id() === $selected_method, - ]; - } - - // If user selected a method, set it - if ($selected_method) { - WC()->session->set('chosen_shipping_methods', [$selected_method]); - } - - // Calculate totals ONCE (includes tax) - WC()->cart->calculate_totals(); - - // Build response - return new WP_REST_Response([ - 'subtotal' => WC()->cart->get_subtotal(), - 'shipping' => [ - 'methods' => $shipping_methods, - 'selected_method' => $selected_method, - 'selected_cost' => WC()->cart->get_shipping_total(), - ], - 'coupons' => WC()->cart->get_applied_coupons(), - 'taxes' => WC()->cart->get_tax_totals(), - 'total_tax' => WC()->cart->get_total_tax(), - 'total' => WC()->cart->get_total('edit'), - ]); -} -``` - ---- - -## Performance Comparison - -### Before (Current - BLOATED): - -``` -User fills address - โ†“ -Frontend: POST /shipping/calculate (500ms) - โ†“ Backend: Init cart, add items, calculate shipping - โ†“ Response: { methods: [...] } - โ†“ -User sees shipping options - โ†“ -User selects shipping method - โ†“ -Frontend: POST /orders/preview (500ms) - โ†“ Backend: Init cart AGAIN, add items AGAIN, calculate AGAIN - โ†“ Response: { total, tax, ... } - โ†“ -User sees total - -TOTAL TIME: ~1000ms -TOTAL REQUESTS: 2 -CART INITIALIZED: 2 times -SHIPPING CALCULATED: 2 times -``` - -### After (Optimized - LIGHTNING): - -``` -User fills address - โ†“ -Frontend: POST /orders/calculate (300ms) - โ†“ Backend: Init cart ONCE, add items ONCE, calculate ONCE - โ†“ Response: { shipping: { methods: [...] }, total, tax, ... } - โ†“ -User sees shipping options AND total - -TOTAL TIME: ~300ms (70% faster!) -TOTAL REQUESTS: 1 (50% reduction) -CART INITIALIZED: 1 time (50% reduction) -SHIPPING CALCULATED: 1 time (50% reduction) -``` - -### When User Changes Shipping Method: - -**Before:** -``` -User selects different shipping - โ†“ -Frontend: POST /orders/preview (500ms) - โ†“ Backend: Init cart, add items, calculate - โ†“ Response: { total, tax } -``` - -**After:** -``` -User selects different shipping - โ†“ -Frontend: POST /orders/calculate with shipping_method (300ms) - โ†“ Backend: Init cart ONCE, calculate with selected method - โ†“ Response: { shipping: { selected_cost }, total, tax } -``` - ---- - -## Implementation Plan - -### Step 1: Create Unified Endpoint - -```php -// includes/Api/OrdersController.php - -public function register() { - register_rest_route( self::NS, '/orders/calculate', [ - 'methods' => 'POST', - 'callback' => [ __CLASS__, 'calculate_order' ], - 'permission_callback' => [ __CLASS__, 'check_permission' ], - ]); -} -``` - -### Step 2: Update Frontend - -```tsx -// OrderForm.tsx - -// REMOVE these two separate queries: -// const shippingRates = useQuery(...); -// const orderPreview = useQuery(...); - -// REPLACE with single unified query: -const { data: calculation, isLoading } = useQuery({ - queryKey: [ - 'order-calculation', - items, - bCountry, bState, bCity, bPost, - effectiveShippingAddress, - shippingMethod, - validatedCoupons - ], - queryFn: async () => { - return api.post('/orders/calculate', { - items: items.map(i => ({ product_id: i.product_id, qty: i.qty })), - billing: { country: bCountry, state: bState, city: bCity, postcode: bPost }, - shipping: effectiveShippingAddress, - shipping_method: shippingMethod, - coupons: validatedCoupons.map(c => c.code), - }); - }, - enabled: items.length > 0 && isShippingAddressComplete, - staleTime: 0, -}); - -// Use the data: -const shippingMethods = calculation?.shipping?.methods || []; -const orderTotal = calculation?.total || 0; -const orderTax = calculation?.total_tax || 0; -``` - -### Step 3: Deprecate Old Endpoints - -```php -// Mark as deprecated, remove in next major version -// /shipping/calculate - DEPRECATED -// /orders/preview - DEPRECATED -``` - ---- - -## Benefits - -โœ… **50% fewer HTTP requests** -โœ… **70% faster response time** -โœ… **50% less server load** -โœ… **50% less database queries** -โœ… **50% fewer external API calls** (UPS, Rajaongkir) -โœ… **Better user experience** (instant feedback) -โœ… **Lower hosting costs** -โœ… **More scalable** - ---- - -## Migration Path - -### Phase 1: Add New Endpoint (Non-breaking) -- Add `/orders/calculate` endpoint -- Keep old endpoints working -- Update frontend to use new endpoint - -### Phase 2: Deprecation Notice -- Add deprecation warnings to old endpoints -- Update documentation - -### Phase 3: Remove Old Endpoints (Next major version) -- Remove `/shipping/calculate` -- Remove `/orders/preview` - ---- - -## Conclusion - -**Current implementation is bloated like WooCommerce.** - -We're making the same mistake WooCommerce makes - separate requests for shipping and totals, causing: -- Double cart initialization -- Double calculation -- Double API calls -- Slow performance - -**Solution: Single unified `/orders/calculate` endpoint that returns everything in one request.** - -This is what we discussed at the beginning - **efficient, lightning-fast, no bloat**. - ---- - -**Status:** โŒ NOT IMPLEMENTED YET -**Priority:** ๐Ÿšจ CRITICAL -**Impact:** ๐Ÿ”ฅ HIGH - Performance bottleneck -**Effort:** โšก MEDIUM - ~2 hours to implement diff --git a/archive/CUSTOMER_DATA_FLOW_ANALYSIS.md b/archive/CUSTOMER_DATA_FLOW_ANALYSIS.md deleted file mode 100644 index d038e53..0000000 --- a/archive/CUSTOMER_DATA_FLOW_ANALYSIS.md +++ /dev/null @@ -1,345 +0,0 @@ -# Customer Data Flow Analysis - -## Issue Report -**Problem:** Customer `billing_phone` shows "Indonesia" instead of phone number -**Source:** Customer created via Order module -**Impact:** Incorrect customer data stored in database - -## Data Flow Investigation - -### A. Customer as Guest (Not Site Member) - -#### 1. Order Creation Flow -**File:** `OrdersController.php` โ†’ `create_order()` method - -**Steps:** -1. Order form submits billing data including `phone` -2. Data flows through `$billing['phone']` parameter -3. Order billing is set via `$order->set_billing_phone($billing['phone'])` -4. **No WC_Customer object created** - guest orders only store data in order meta - -**Code Location:** Lines 780-1120 - -```php -// Guest customer - data only in order -$order->set_billing_first_name($billing['first_name'] ?? ''); -$order->set_billing_last_name($billing['last_name'] ?? ''); -$order->set_billing_email($billing['email'] ?? ''); -$order->set_billing_phone($billing['phone'] ?? ''); // โ† Data here -// ... more fields -``` - -**Issue:** Guest customers don't have WC_Customer records, so viewing them in Customer module will fail or show incorrect data. - ---- - -### B. Customer as Site Member - -#### 1. Existing Member - Order Creation -**File:** `OrdersController.php` โ†’ Lines 1020-1064 - -**Flow:** -1. User exists, found by email -2. **Upgrade subscriber to customer role** (if needed) -3. Create `WC_Customer` object -4. **Update customer data** from order billing/shipping -5. Save customer -6. Link order to customer - -**Code:** -```php -if ($user) { - // Upgrade role if needed - if (in_array('subscriber', (array) $user->roles, true)) { - $user->set_role('customer'); - } - - // Update customer billing & shipping data - $customer = new \WC_Customer($user->ID); - - // Update billing address - if (! empty($billing['first_name'])) $customer->set_billing_first_name($billing['first_name']); - if (! empty($billing['last_name'])) $customer->set_billing_last_name($billing['last_name']); - if (! empty($billing['email'])) $customer->set_billing_email($billing['email']); - if (! empty($billing['phone'])) $customer->set_billing_phone($billing['phone']); // โ† HERE - // ... more fields - - $customer->save(); -} -``` - -**Validation:** Uses `! empty()` check -**Problem:** If `$billing['phone']` contains "Indonesia" (non-empty string), it will be saved! - ---- - -#### 2. New Member - Auto-Registration -**File:** `OrdersController.php` โ†’ Lines 1065-1118 - -**Flow:** -1. User doesn't exist -2. Auto-register setting is ON -3. Create WordPress user -4. Create `WC_Customer` object -5. Set billing/shipping from order data -6. Save customer -7. Send welcome email - -**Code:** -```php -elseif ($register_member) { - // Create user - $user_id = wp_insert_user($userdata); - - if (!is_wp_error($user_id)) { - $customer = new \WC_Customer($user_id); - - // Billing address - if (! empty($billing['first_name'])) $customer->set_billing_first_name($billing['first_name']); - // ... - if (! empty($billing['phone'])) $customer->set_billing_phone($billing['phone']); // โ† HERE - // ... - - $customer->save(); - } -} -``` - -**Same Issue:** `! empty()` check allows "Indonesia" to be saved. - ---- - -### C. Customer Module Direct Edit - -**File:** `CustomersController.php` โ†’ `update_customer()` method (Lines 232-310) - -**Flow:** -1. Receive customer data via PUT request -2. Update WordPress user meta -3. Update `WC_Customer` billing/shipping -4. Save customer - -**Code:** -```php -$customer = new WC_Customer($id); - -// Billing address -if (!empty($data['billing'])) { - $billing = $data['billing']; - if (isset($billing['first_name'])) $customer->set_billing_first_name(...); - // ... - if (isset($billing['phone'])) $customer->set_billing_phone(sanitize_text_field($billing['phone'])); - // ... -} - -$customer->save(); -``` - -**Validation:** Uses `isset()` check (better than `! empty()`) -**Sanitization:** Uses `sanitize_text_field()` โœ… - ---- - -## Root Cause Analysis - -### Possible Sources of "Indonesia" Value - -1. **Frontend Default Value** - - Check `OrderForm.tsx` for default country/phone values - - Check if "Indonesia" is being set as placeholder or default - -2. **Backend Fallback** - - Check if WooCommerce has default country settings - - Check if there's a fallback to country name instead of phone - -3. **Data Validation Issue** - - `! empty()` check allows ANY non-empty string - - No validation that phone is actually a phone number - - No sanitization before saving - -4. **Virtual Products Case** - - When cart has only virtual products, address fields are hidden - - Phone field might still be submitted with wrong value - ---- - -## Issues Found - -### 1. โŒ Weak Validation in OrdersController - -**Problem:** -```php -if (! empty($billing['phone'])) $customer->set_billing_phone($billing['phone']); -``` - -- `! empty()` allows "Indonesia", "test", "abc", etc. -- No phone number format validation -- No sanitization - -**Should Be:** -```php -if (isset($billing['phone']) && $billing['phone'] !== '') { - $customer->set_billing_phone(sanitize_text_field($billing['phone'])); -} -``` - ---- - -### 2. โŒ No Data Sanitization in Order Creation - -**Problem:** -- Direct assignment without sanitization -- Allows any string value -- No format validation - -**Should Add:** -- `sanitize_text_field()` for all text fields -- Phone number format validation -- Empty string handling - ---- - -### 3. โŒ Inconsistent Validation Between Controllers - -**OrdersController:** -- Uses `! empty()` check -- No sanitization - -**CustomersController:** -- Uses `isset()` check โœ… -- Has `sanitize_text_field()` โœ… - -**Should:** Use same validation pattern everywhere - ---- - -### 4. โŒ Virtual Products Address Handling - -**Current Behavior:** -- Frontend hides address fields for virtual products -- But phone field is ALWAYS shown -- Backend might receive wrong data - -**Check:** -- OrderForm.tsx line 1023: `setBPhone(data.billing.phone || '');` -- Does this fallback to something else? - ---- - -## Action Items - -### 1. Fix OrdersController Validation - -**File:** `OrdersController.php` -**Lines:** 1039-1047, 1088-1096 - -**Change:** -```php -// OLD (Lines 1042) -if (! empty($billing['phone'])) $customer->set_billing_phone($billing['phone']); - -// NEW -if (isset($billing['phone']) && trim($billing['phone']) !== '') { - $customer->set_billing_phone(sanitize_text_field($billing['phone'])); -} -``` - -Apply to: -- Existing member update (lines 1039-1047) -- New member creation (lines 1088-1096) - ---- - -### 2. Add Phone Number Validation - -**Create Helper Function:** -```php -private static function sanitize_phone($phone) { - if (empty($phone)) { - return ''; - } - - // Remove non-numeric characters except + and spaces - $phone = preg_replace('/[^0-9+\s-]/', '', $phone); - - // Trim whitespace - $phone = trim($phone); - - // If result is empty or just symbols, return empty - if (empty($phone) || preg_match('/^[+\s-]+$/', $phone)) { - return ''; - } - - return $phone; -} -``` - ---- - -### 3. Check Frontend Data Source - -**File:** `OrderForm.tsx` -**Line:** ~1023 - -**Check:** -- Where does `data.billing.phone` come from? -- Is there a default value being set? -- Is "Indonesia" coming from country field? - ---- - -### 4. Test Cases - -**A. Guest Customer:** -1. Create order with phone = "08123456789" -2. Check order billing_phone -3. Verify no WC_Customer created - -**B. Existing Member:** -1. Create order with existing customer -2. Phone = "08123456789" -3. Check WC_Customer billing_phone updated -4. Create another order with same customer -5. Phone = "08198765432" -6. Verify WC_Customer phone updated to new value - -**C. New Member (Auto-register):** -1. Create order with new email -2. Auto-register ON -3. Phone = "08123456789" -4. Verify WC_Customer created with correct phone - -**D. Virtual Products:** -1. Create order with only virtual products -2. Verify phone field behavior -3. Check what value is submitted - ---- - -## Expected Behavior - -### Order Creation with Existing Member -1. Order billing data should update WC_Customer data -2. Phone should be validated and sanitized -3. Empty phone should clear WC_Customer phone (not set to country name) - -### Order Creation with New Member -1. WC_Customer should be created with correct data -2. Phone should be validated and sanitized -3. No fallback to country name - -### Virtual Products -1. Phone field should still work correctly -2. No address fields needed -3. Phone should not default to country name - ---- - -## Next Steps - -1. โœ… Update PROJECT_SOP.md with mobile UX patterns -2. ๐Ÿ”„ Find source of "Indonesia" value -3. โณ Fix validation in OrdersController -4. โณ Add phone sanitization helper -5. โณ Test all scenarios -6. โณ Document fix in commit message diff --git a/archive/PHASE_COMPLETE.md b/archive/PHASE_COMPLETE.md deleted file mode 100644 index c893d61..0000000 --- a/archive/PHASE_COMPLETE.md +++ /dev/null @@ -1,26 +0,0 @@ -# Phase Complete โœ… - -**Date:** November 15, 2025 - -## Completed - -### 1. Email Queue โœ… -- Already implemented via MailQueue + WooEmailOverride -- Prevents 30s timeout - -### 2. Documentation โœ… -- Reduced 56 โ†’ 27 files (52% reduction) -- Created NOTIFICATION_SYSTEM.md (consolidated) -- Deleted 30 obsolete docs - -### 3. Git Push โœ… -- 3 commits pushed to main -- Remote: git.backoffice.biz.id - -### 4. Plugin Zip โœ… -- File: woonoow.zip -- Size: 1.4MB -- Location: /wp-content/plugins/woonoow.zip -- Guide: PLUGIN_ZIP_GUIDE.md - -## Ready for Distribution! ๐Ÿš€ diff --git a/archive/PRODUCT_FORM_UX_IMPROVEMENTS.md b/archive/PRODUCT_FORM_UX_IMPROVEMENTS.md deleted file mode 100644 index 5f48017..0000000 --- a/archive/PRODUCT_FORM_UX_IMPROVEMENTS.md +++ /dev/null @@ -1,373 +0,0 @@ -# Product Form UX Improvements - -## Problem Statement - -The original product form (`ProductForm.tsx`) had **600+ lines in a single file** with all fields visible at once, creating an overwhelming and exhausting experience for users adding/editing products. - -### Issues with Old Form: -โŒ **Cognitive Overload** - Too many fields visible simultaneously -โŒ **Poor Mobile UX** - Long scrolling, hard to navigate -โŒ **Difficult Maintenance** - Single 600-line file -โŒ **Confusing Variations** - Comma-separated input (requires shift key) -โŒ **No Visual Hierarchy** - Everything at same level -โŒ **No Contextual Help** - Users unsure what fields mean - ---- - -## Solution: Modern Tabbed Interface - -Redesigned with **5 modular tabs** inspired by industry leaders (Shopify, Shopee, Wix, Magento). - -### Architecture - -``` -ProductFormTabbed.tsx (250 lines) -โ”œโ”€โ”€ GeneralTab.tsx (180 lines) -โ”œโ”€โ”€ PricingTab.tsx (100 lines) -โ”œโ”€โ”€ InventoryTab.tsx (90 lines) -โ”œโ”€โ”€ VariationsTab.tsx (200 lines) -โ””โ”€โ”€ OrganizationTab.tsx (120 lines) - -Total: ~950 lines across 6 files (vs 600 lines in 1 file) -``` - ---- - -## Tab Breakdown - -### 1๏ธโƒฃ General Tab -**Focus:** Basic product information - -**Fields:** -- Product name * -- Product type (simple/variable/grouped/external) -- Status (publish/draft/pending/private) -- Long description -- Short description -- Virtual product checkbox -- Downloadable product checkbox -- Featured product checkbox - -**UX Features:** -- Clear labels with asterisks for required fields -- Inline help text below each field -- Type-specific descriptions (e.g., "A standalone product" for simple) -- Logical grouping with separators - ---- - -### 2๏ธโƒฃ Pricing Tab -**Focus:** Product pricing - -**Fields:** -- SKU (optional) -- Regular price * (for simple products) -- Sale price (optional) - -**UX Features:** -- Dollar sign icons for price inputs -- Savings calculator (shows "Customers save X%") -- Green success banner when sale price is set -- Contextual help for each field -- Pre-filled for variations (base price) - -**Example:** -``` -Regular Price: $100 -Sale Price: $80 -โ†’ Shows: "๐Ÿ’ฐ Customers save 20%" -``` - ---- - -### 3๏ธโƒฃ Inventory Tab -**Focus:** Stock management - -**Fields:** -- Manage stock toggle -- Stock quantity (when enabled) -- Stock status (in stock/out of stock/on backorder) - -**UX Features:** -- Progressive disclosure (quantity only shown when enabled) -- Color-coded status badges: - - ๐ŸŸข In Stock (green) - - ๐Ÿ”ด Out of Stock (red) - - ๐ŸŸก On Backorder (amber) -- Visual border for nested fields -- Clear explanations - ---- - -### 4๏ธโƒฃ Variations Tab -**Focus:** Product variations (variable products only) - -**Features:** -- **Add Attribute** button -- Attribute cards with: - - Attribute name (e.g., Color, Size) - - Options input with **pipe separator** (`|`) - - "Use for variations" checkbox -- **Generate Variations** button -- Variation list with badges -- Per-variation inputs (SKU, price, sale, stock) - -**Key Improvement: Pipe Separator** -``` -โŒ Old: Red, Blue, Green (comma = shift key) -โœ… New: Red | Blue | Green (pipe = no shift!) -``` - -**Variation Generation:** -``` -Attributes: -- Color: Red | Blue -- Size: S | M | L - -Generated Variations (6): -1. Color: Red, Size: S -2. Color: Red, Size: M -3. Color: Red, Size: L -4. Color: Blue, Size: S -5. Color: Blue, Size: M -6. Color: Blue, Size: L -``` - -**UX Features:** -- Empty state with icon and message -- Numbered attribute badges -- Visual attribute cards -- Pre-filled prices (inherit base price) -- Compact variation display -- Success toast with count - ---- - -### 5๏ธโƒฃ Organization Tab -**Focus:** Categories and tags - -**Features:** -- Categories (checkboxes) -- Tags (pill buttons) - -**UX Features:** -- Clear visual separation -- Interactive pill buttons for tags (toggle on/off) -- Active state styling -- Empty states - ---- - -## UX Principles Applied - -### โœ… Progressive Disclosure -Only show relevant fields: -- Variations tab **disabled** for non-variable products -- Stock quantity **hidden** unless "Manage stock" enabled -- Variation-specific pricing only for variable products - -### โœ… Visual Hierarchy -- Card-based layout -- Clear section titles and descriptions -- Separators between logical groups -- Badges for status and counts - -### โœ… Inline Help -Every field has contextual help text: -``` -SKU -[Input field] -"Stock Keeping Unit (optional)" -``` - -### โœ… Smart Defaults -- Product type: Simple -- Status: Published -- Stock status: In Stock -- Variation prices: Pre-filled with base price - -### โœ… Visual Feedback -- Savings percentage calculator -- Color-coded badges -- Success/error toasts -- Loading states -- Disabled states - -### โœ… Validation Routing -Form automatically switches to tab with errors: -```typescript -if (!name.trim()) { - toast.error('Product name is required'); - setActiveTab('general'); // Auto-switch! - return; -} -``` - -### โœ… Mobile Optimized -- Responsive tab layout (icons only on mobile) -- Touch-friendly buttons -- Stacked inputs on small screens -- Pull-to-refresh support - ---- - -## Comparison: Old vs New - -| Aspect | Old Form | New Tabbed Form | -|--------|----------|-----------------| -| **Lines of Code** | 600 in 1 file | ~950 in 6 files | -| **Maintainability** | โŒ Hard | โœ… Easy (modular) | -| **Cognitive Load** | โŒ High | โœ… Low (progressive) | -| **Mobile UX** | โŒ Poor | โœ… Excellent | -| **Visual Hierarchy** | โŒ Flat | โœ… Clear | -| **Contextual Help** | โŒ None | โœ… Everywhere | -| **Variation Input** | โŒ Comma (shift) | โœ… Pipe (no shift) | -| **Validation** | โŒ Generic | โœ… Tab-specific | -| **Extensibility** | โŒ Hard | โœ… Easy (add tabs) | - ---- - -## Industry Benchmarking - -### Shopify -- โœ… Tabbed interface -- โœ… Progressive disclosure -- โœ… Inline help text -- โœ… Visual status badges - -### Shopee (Seller Center) -- โœ… Step-by-step wizard -- โœ… Smart defaults -- โœ… Visual feedback -- โœ… Mobile-first design - -### WooCommerce (Default) -- โŒ Single long form (like our old one) -- โŒ Overwhelming for new users -- โŒ Poor mobile experience - -### Magento -- โœ… Accordion sections -- โœ… Advanced/basic toggle -- โœ… Contextual help - -**Our Approach:** Best of Shopify + Shopee with WooCommerce compatibility. - ---- - -## User Flow Comparison - -### Old Flow (Single Form) -``` -1. Open form -2. See 50+ fields at once ๐Ÿ˜ฐ -3. Scroll... scroll... scroll... -4. Forget what you filled -5. Submit (maybe) -``` - -### New Flow (Tabbed) -``` -1. Open form -2. Start with General (5-8 fields) โœ… -3. Move to Pricing (3 fields) โœ… -4. Configure Inventory (2-3 fields) โœ… -5. Add Variations if needed (focused) โœ… -6. Set Categories/Tags โœ… -7. Submit with confidence! ๐ŸŽ‰ -``` - ---- - -## Technical Benefits - -### Modular Architecture -Each tab is self-contained: -- Easy to test -- Easy to modify -- Easy to extend -- Clear responsibilities - -### Type Safety -Full TypeScript support: -```typescript -type GeneralTabProps = { - name: string; - setName: (value: string) => void; - type: 'simple' | 'variable' | 'grouped' | 'external'; - // ... etc -}; -``` - -### Reusability -Same form for create and edit: -```tsx - - - -``` - ---- - -## Future Enhancements - -### Phase 2 -- [ ] Image upload with drag-and-drop -- [ ] Rich text editor for descriptions -- [ ] Bulk variation editing -- [ ] Variation templates - -### Phase 3 -- [ ] SEO tab (meta title, description, keywords) -- [ ] Shipping tab (weight, dimensions) -- [ ] Advanced tab (custom fields) -- [ ] Related products selector - -### Phase 4 -- [ ] AI-powered descriptions -- [ ] Smart pricing suggestions -- [ ] Inventory forecasting -- [ ] Multi-language support - ---- - -## Metrics to Track - -### User Experience -- โฑ๏ธ Time to create product (expect 30% reduction) -- ๐Ÿ“Š Form completion rate (expect increase) -- ๐Ÿ”„ Form abandonment rate (expect decrease) -- ๐Ÿ˜Š User satisfaction score - -### Technical -- ๐Ÿ› Bug reports (expect decrease) -- ๐Ÿ”ง Maintenance time (expect decrease) -- ๐Ÿ“ˆ Code coverage (easier to test) -- ๐Ÿš€ Performance (no impact, same bundle size) - ---- - -## Conclusion - -The new tabbed product form provides a **significantly better user experience** while maintaining **technical excellence**. By following industry best practices and focusing on progressive disclosure, we've created a form that is: - -โœ… **Less Overwhelming** - Focused, step-by-step approach -โœ… **More Intuitive** - Clear labels, inline help, visual feedback -โœ… **Better Organized** - Logical grouping, modular architecture -โœ… **Mobile-Friendly** - Responsive, touch-optimized -โœ… **Easier to Maintain** - Modular, type-safe, well-documented - -**Result:** Admins can add/edit products faster and with more confidence! ๐ŸŽ‰ - ---- - -**Implemented:** November 19, 2025 -**Team:** WooNooW Development -**Status:** โœ… Production Ready diff --git a/archive/PROGRESS_NOTE.md b/archive/PROGRESS_NOTE.md deleted file mode 100644 index 0ae3fdb..0000000 --- a/archive/PROGRESS_NOTE.md +++ /dev/null @@ -1,3147 +0,0 @@ -# WooNooW Project Progress Note - -**Last Updated:** November 19, 2025, 7:15 PM (GMT+7) - -## Overview -WooNooW is a hybrid WordPress + React SPA replacement for WooCommerce Admin. It focuses on performance, UX consistency, and extensibility with SSR-safe endpoints and REST-first design. The plugin integrates deeply with WooCommerceโ€™s data store (HPOS ready) and provides a modern React-based dashboard and order management system. - -## Current Structure -``` -woonoow/ -โ”œโ”€โ”€ admin-spa/ -โ”‚ โ”œโ”€โ”€ src/ -โ”‚ โ”‚ โ”œโ”€โ”€ components/ -โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ filters/ -โ”‚ โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ DateRange.tsx -โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ OrderBy.tsx -โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ CommandPalette.tsx -โ”‚ โ”‚ โ”œโ”€โ”€ hooks/ -โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ useShortcuts.tsx -โ”‚ โ”‚ โ”œโ”€โ”€ lib/ -โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ api.ts -โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ currency.ts -โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ dates.ts -โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ query-params.ts -โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ useCommandStore.ts -โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ utils.ts -โ”‚ โ”‚ โ”œโ”€โ”€ pages/ -โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ orders/ -โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ partials -โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ OrderForm.tsx -โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ Orders.tsx -โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€ OrdersNew.tsx -โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ OrderShow.tsx -โ”‚ โ”‚ โ”œโ”€โ”€ routes/ -โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ Dashboard.tsx -โ”‚ โ”‚ โ”œโ”€โ”€ types/ -โ”‚ โ”‚ โ”‚ โ””โ”€โ”€ qrcode.d.ts -โ”‚ โ”‚ โ”œโ”€โ”€ App.tsx -โ”‚ โ”‚ โ”œโ”€โ”€ index.css -โ”‚ โ”‚ โ””โ”€โ”€ main.tsx -โ”‚ โ””โ”€โ”€ vite.config.ts -โ”œโ”€โ”€ includes/ -โ”‚ โ”œโ”€โ”€ Admin/ -โ”‚ โ”‚ โ”œโ”€โ”€ Assets.php -โ”‚ โ”‚ โ””โ”€โ”€ Menu.php -โ”‚ โ”œโ”€โ”€ Api/ -โ”‚ โ”‚ โ”œโ”€โ”€ CheckoutController.php -โ”‚ โ”‚ โ”œโ”€โ”€ OrdersController.php -โ”‚ โ”‚ โ”œโ”€โ”€ Permissions.php -โ”‚ โ”‚ โ””โ”€โ”€ Routes.php -โ”‚ โ”œโ”€โ”€ Compat/ -โ”‚ โ”‚ โ”œโ”€โ”€ HideWooMenus.php -โ”‚ โ”‚ โ””โ”€โ”€ HooksShim.php -โ”‚ โ””โ”€โ”€ Core/ -โ”‚ โ”œโ”€โ”€ DataStores/ -โ”‚ โ”‚ โ”œโ”€โ”€ OrderStore_HPOS.php -โ”‚ โ”‚ โ””โ”€โ”€ OrderStore.php -โ”‚ โ”œโ”€โ”€ Mail/ -โ”‚ โ”‚ โ”œโ”€โ”€ MailQueue.php -โ”‚ โ”‚ โ””โ”€โ”€ WooEmailOverride.php -โ”‚ โ”œโ”€โ”€ Bootstrap.php -โ”‚ โ””โ”€โ”€ Features.php -โ”œโ”€โ”€ woonoow.php -โ””โ”€โ”€ docs (project notes, SOP, etc.) -``` - -## Major Implementations - -### โœ… Backend (PHP) -- **Routes.php** registers `/orders`, `/checkout`, `/countries`, `/payments`, `/shippings` endpoints. -- **OrdersController.php** - - `index()` โ€“ Paginated, filterable orders list with date range, orderby, order. - - `show()` โ€“ Detailed order view with items, billing, totals, and formatted addresses. - - `create()` โ€“ Create order via admin (supports multi-item, no customer registration required). - - `countries()`, `payments()`, `shippings()` added for dynamic form data. - - Permissions handled via helper `permission_callback_admin()`. -- **CheckoutController.php** โ€“ Placeholder for frontend (anonymous) checkout path. -- **Assets.php** โ€“ Injects localized nonce & REST base URL for SPA. - -### โœ… Frontend (React) -- SPA with sticky sidebar and topbar. -- CommandPalette + keyboard shortcuts (D, R, O). -- Orders module fully functional: - - `Orders.tsx`: Paginated list, filters (status/date/orderby), and SPA navigation. - - `OrderShow.tsx`: Detailed view with print, label mode (QR/barcode ready), responsive layout. - - `OrdersNew.tsx`: Full order creation form (billing/shipping, items, payments, shippings, coupons). -- Filters (`DateRange`, `OrderBy`) use Shadcn `Select`. -- Sticky nav and fullscreen mode implemented. -- Responsive and print-optimized layouts (with dedicated CSS rules in `index.css`). - -### ๐Ÿง  Data Flow -- All requests handled via `OrdersApi` (in `lib/api.ts`) using unified `api.get/post` wrapper with nonce. -- React Query handles caching, pagination, and mutations. -- URL query sync via `query-params.ts` for persistent filters. - -### ๐Ÿงฉ UI / UX -- Shadcn UI components standardized across input/select. -- Print and label modes render order as invoice/shipping label. -- Label includes QR (via `qrcode` npm package) โ€” tracking or order ID encoded. - -## Known Issues / TODO -1. **Fullscreen scroll issue** โ€“ body scroll locked improperly; needs fix in layout wrapper. -2. **Select z-index in fullscreen** โ€“ dropdowns render under content; requires portal layering fix. -3. **State/Province handling** โ€“ add conditional Select for country states. -4. **Invoice / Label layout** โ€“ needs standalone print-friendly component (A5/A6 sizing option). -5. **Permission helper expansion** โ€“ support `editor` and `shop_manager` roles. -6. **Coupons logic** โ€“ confirm multiple coupon support (WooCommerce natively supports multiple coupons per order). -7. **Upcoming:** Dashboard metrics (revenue, orders, customers) via new `/stats` endpoint. - -## Notes for Next Session -- Start by finishing **OrdersNew.tsx** responsive layout & totals preview card. -- Add **states endpoint** in `OrdersController`. -- Move Shadcn dropdowns to portals for fullscreen mode. -- Prepare print-friendly components (`InvoicePrint`, `LabelPrint`). -- Ensure `index.css` global variables handle light/dark theme for WooNooW. - ---- - -**Last synced:** 2025โ€‘10โ€‘25 20:00 GMT+7 -**Next milestone:** Order creation polish + Dashboard overview. - - -## ๐Ÿ”„ Recent Progress โ€” October 27, 2025 - -### ๐Ÿงฉ Core Architecture -- Added dynamic WooCommerce **menu collector** in `includes/Admin/Menu.php`: - - Scrapes `$menu` and `$submenu` after all plugins register menus. - - Filters Woo-related slugs and localizes `WNM_WC_MENUS` to SPA. - - Guarantees future add-ons automatically appear in the SPA nav. -- Updated `Assets.php` handle targeting to ensure localization attaches to correct dev/prod handles. - -### ๐Ÿงญ Frontend Navigation -- **Dynamic Quick Nav** implemented in `App.tsx`: - - Reads `window.WNM_WC_MENUS.items` (provided by backend collector). - - Renders scrollable top navigation bar. - - Maps known WooCommerce admin URLs โ†’ SPA routes. - - Falls back to legacy bridge for unmapped items. -- Added hovercard filters for mobile in `Orders.tsx`. -- Integrated Shadcn components and unified styling for consistent look across SPA. - -### ๐Ÿ“š Documentation & Planning -- Created **SPA_ADMIN_MENU_PLAN.md** โ€” authoritative mapping of WooCommerce default menus to SPA routes. - - Includes regex route map for legacy โ†’ SPA translation. - - Added visual menu tree (default WooCommerce sidebar hierarchy). - - Defined **Proposed SPA Main Menu (Authoritative)** structure: - 1. Dashboard โ†’ all analytics/reports (merged with Marketing) - 2. Orders โ†’ CRUD - 3. Products โ†’ CRUD - 4. Coupons โ†’ CRUD - 5. Customers โ†’ derived from orders/users - 6. Settings โ†’ all Woo tabs + Status + Extensions -- Clarified that โ€œMarketing / Hubโ€ is part of WooCommerce Admin (extension recommendations) and will be folded into Dashboard metrics. - -### ๐Ÿงฑ Next Steps -1. Update SPA quick-nav to render based on **Proposed SPA Main Menu**, not `wp-admin` structure. -2. Extend `/lib/routes` or `App.tsx` to handle `/dashboard/*` routes for reports. -3. Implement `/dashboard` overview and `/customers` list (buyerโ€‘only dataset). -4. Add settings router structure for tabbed `/settings/*` pages. -5. Migrate Status + Extensions into Settings as planned. -6. Maintain compatibility for add-on menus using `WNM_WC_MENUS` dynamic injection. - ---- - - -**Last synced:** 2025โ€‘10โ€‘28 06:06 GMT+7 -**Next milestone:** Enhance order management features and implement advanced filtering. - - -## ๐Ÿ—‘๏ธ Bulk Delete Operations โ€” October 28, 2025 (Morning) - -### โœ… Complete Bulk Delete Feature Implemented -- **Frontend (Orders/index.tsx):** Multi-select checkboxes with "Select All" functionality -- **Backend (OrdersController.php):** DELETE endpoint with HPOS support -- **Confirmation Dialog:** Shadcn Dialog with clear warning and action buttons -- **Smart Deletion:** Parallel deletion with graceful error handling -- **User Feedback:** Toast notifications for success/partial/failure states -- **Logging:** WooCommerce logger integration for audit trail - -### ๐ŸŽฏ Features -- Checkbox column as first column in orders table -- Delete button appears when items selected (shows count) -- Confirmation dialog prevents accidental deletion -- HPOS-aware deletion (soft delete to trash) -- Handles both HPOS and legacy post-based orders -- Parallel API calls with `Promise.allSettled` -- Automatic list refresh after deletion -- Full i18n support for all UI strings - ---- - - -## ๐ŸŒ Internationalization (i18n) โ€” October 28, 2025 (Morning) - -### โœ… Complete Translation Coverage Implemented -- **Frontend (18 files):** All user-facing strings in Orders, Dashboard, Coupons, Customers, Settings, Navigation, Filters, and Command Palette now use `__()` wrapper -- **Backend (5 files):** All error messages in API controllers translated using WordPress `__()` function -- **Documentation:** Created comprehensive `I18N_IMPLEMENTATION_GUIDE.md` and updated `PROJECT_SOP.md` with sprintf examples -- **Total strings translated:** ~330+ strings across 27 files -- **Pattern established:** Consistent use of `@/lib/i18n` wrapper for frontend, `__('string', 'woonoow')` for backend -- **Ready for:** POT file generation and multilingual deployment - -### ๐Ÿ“ Translation Infrastructure -- Custom `i18n.ts` wrapper leveraging WordPress `wp.i18n` for frontend consistency -- Centralized error handling with translatable messages in `errorHandling.ts` -- All validation messages, UI labels, navigation items, and error states fully translatable -- Both simple strings and sprintf-formatted strings supported - ---- - - -## ๐Ÿ”ง Recent Fixes โ€” October 27, 2025 (Evening) - -### ๐Ÿงฉ Navigation / Menu Synchronization -- Hardened `tree.ts` as immutable single source of truth (deep frozen) for SPA menus. -- Verified `orders.children` = [] so Orders has no submenu; ensured SubmenuBar reads strictly from props. -- Replaced `SubmenuBar.tsx` with minimal version rendering only prop items โ€” no fallbacks. -- Cleaned Orders route files (`index.tsx`, `New.tsx`, `Edit.tsx`, `Detail.tsx`) to remove local static tabs (โ€œOrders / New Orderโ€). -- Confirmed final architecture: tree.ts โ†’ useActiveSection โ†’ SubmenuBar pipeline. -- Added runtime debug logs (`[SubmenuMount]`) in `App.tsx` to trace submenu rendering. -- Discovered root cause: legacy SPA bundle still enqueued; restored and verified `Assets.php` to ensure only one SPA entry script runs. - -### ๐Ÿ“ฑ Responsive / Mobile -- Added global `tokens.css` for interactive element sizing (`.ui-ctrl` h-11 md:h-9) improving mobile UX. -- Applied global sizing to input, select, and button components via `index.css` and tokens import. - -### ๐Ÿงญ Layout & Fullscreen -- Fixed duplicate scrollbars in fullscreen mode by adjusting container overflow. -- Sidebar limited to desktop + fullscreen; mobile uses topbar version for consistency. - -### โš™๏ธ System Checks -- Updated `Assets.php` to expose `window.wnw` global with `isDev`, `devServer`, and `adminUrl` for SPA environment bridging. -- Updated `useActiveSection.ts` to rely solely on `window.wnw.isDev`. - -### โœ… Next Steps -1. Verify only one SPA script enqueued (`woonoow-admin-spa`); remove legacy duplicates. -2. Confirm menu tree auto-sync with Woo add-ons (via `MenuProvider`). -3. Add `/dashboard` and `/customers` routes with consistent layout + submenu. -4. Standardize toast notifications across modules using Sonner. -5. Prepare print-friendly `InvoicePrint` and `LabelPrint` components for order detail. - -**Last synced:** 2025โ€‘10โ€‘27 23:59 GMT+7 -**Next milestone:** Dashboard overview + unified Settings SPA. - ---- - -## ๐Ÿ”Œ Addon Injection System โ€” October 28, 2025 (Complete) - -### โœ… PRODUCTION READY - Full Implementation Complete - -**Status:** 10/10 Readiness Score -**Implementation Time:** 2-3 days -**Total Changes:** 15 files, ~3050 net lines - -### ๐ŸŽฏ What Was Built - -#### **Backend (PHP) - 100% Complete** -1. **AddonRegistry.php** (200+ lines) - - Central addon metadata registry - - Dependency validation (WooCommerce, WordPress, plugins) - - Version checking and enable/disable control - - Filter: `woonoow/addon_registry` - -2. **RouteRegistry.php** (170+ lines) - - SPA route registration for addons - - Capability-based filtering - - Route validation and sanitization - - Filter: `woonoow/spa_routes` - -3. **NavigationRegistry.php** (180+ lines) - - Dynamic navigation tree building - - Main menu injection - - Per-section submenu injection - - Filters: `woonoow/nav_tree`, `woonoow/nav_tree/{key}/children` - -4. **Bootstrap.php** - Integrated all registries -5. **Assets.php** - Exposed data to frontend via window globals - -#### **Frontend (React/TypeScript) - 100% Complete** -1. **nav/tree.ts** - Dynamic navigation tree (reads from `window.WNW_NAV_TREE`) -2. **hooks/useActiveSection.ts** - Dynamic path matching -3. **App.tsx** - AddonRoute component with lazy loading, error handling, loading states -4. **Removed Bridge/iframe** - Cleaned ~150 lines of legacy code - -#### **Documentation - 100% Complete** -1. **ADDON_INJECTION_GUIDE.md** (900+ lines) - - Quick start (5-minute integration) - - Complete API reference - - Component development guide - - Best practices and examples - -2. **HOOKS_REGISTRY.md** (500+ lines) - - Complete hook tree structure - - All active hooks documented - - Priority guidelines - - Usage examples - -3. **PROJECT_SOP.md** - Section 6 added (320+ lines) - - Hook naming convention - - Filter template pattern - - **Non-React addon development (3 approaches)** - - Development checklist - -4. **IMPLEMENTATION_SUMMARY.md** (400+ lines) - - Complete implementation summary - - Questions answered - - Quick reference guide - -### ๐Ÿš€ Key Features - -**For Addon Developers:** -- โœ… 5-minute integration with simple filters -- โœ… **Three development approaches:** - 1. **Traditional PHP** - No React, uses WordPress admin pages - 2. **Vanilla JS** - SPA integration without React - 3. **React** - Full SPA with React (optional) -- โœ… Zero configuration - automatic discovery -- โœ… Dependency validation -- โœ… Error handling and loading states -- โœ… Full i18n support - -**For End Users:** -- โœ… Seamless integration (no iframes!) -- โœ… Fast loading with lazy loading -- โœ… Consistent UI -- โœ… Mobile responsive - -### ๐Ÿ“š Hook Structure - -``` -woonoow/ -โ”œโ”€โ”€ addon_registry โœ… ACTIVE (Priority: 20) -โ”œโ”€โ”€ spa_routes โœ… ACTIVE (Priority: 25) -โ”œโ”€โ”€ nav_tree โœ… ACTIVE (Priority: 30) -โ”‚ โ””โ”€โ”€ {section_key}/children โœ… ACTIVE (Priority: 30) -โ”œโ”€โ”€ dashboard/widgets ๐Ÿ“‹ PLANNED -โ”œโ”€โ”€ order/detail/panels ๐Ÿ“‹ PLANNED -โ””โ”€โ”€ admin_is_dev โœ… ACTIVE -``` - -### ๐ŸŽ“ Orders Module as Reference - -Orders module serves as the model for all future implementations: -- Clean route structure (`/orders`, `/orders/new`, `/orders/:id`) -- No submenu (by design) -- Full CRUD operations -- Type-safe components -- Proper error handling -- Mobile responsive -- i18n complete - -### ๐Ÿ“ฆ Example Addon Created - -**Location:** `examples/example-addon.php` -- Complete working example -- Addon registration -- Route registration -- Navigation injection -- REST API endpoint -- React component - -### โœ… Success Criteria - ALL MET -- [x] Remove Bridge/iframe system -- [x] Implement AddonRegistry -- [x] Implement RouteRegistry -- [x] Implement NavigationRegistry -- [x] Dynamic route loading -- [x] Dynamic navigation -- [x] Component lazy loading -- [x] Error handling -- [x] Comprehensive documentation -- [x] Hook registry with tree structure -- [x] Non-React support documented -- [x] Production ready - -### ๐ŸŽฏ What This Enables - -Addons can now: -- Register with metadata & dependencies -- Add custom SPA routes -- Inject main menu items -- Inject submenu items -- Load React components dynamically -- Use vanilla JavaScript (no React) -- Use traditional PHP/HTML/CSS -- Access WooNooW APIs -- Declare capabilities -- Handle errors gracefully - -**Use Cases:** -- WooCommerce Subscriptions -- Bookings & Appointments -- Memberships -- Custom Reports -- Third-party integrations -- Custom product types -- Marketing automation -- **ANY custom functionality!** - -### ๐Ÿ“ Documentation Files - -- `ADDON_INJECTION_GUIDE.md` - Developer guide (900+ lines) -- `HOOKS_REGISTRY.md` - Hook reference (500+ lines) -- `PROJECT_SOP.md` - Section 6 (320+ lines) -- `IMPLEMENTATION_SUMMARY.md` - Summary (400+ lines) -- `ADDONS_ADMIN_UI_REQUIREMENTS.md` - Updated status -- `ADDON_INJECTION_READINESS_REPORT.md` - Technical analysis -- `examples/example-addon.php` - Working example - -**Total Documentation:** 2400+ lines - ---- - -**Last synced:** 2025โ€‘10โ€‘28 09:35 GMT+7 -**Next milestone:** Test addon system, then proceed with Dashboard module development. - ---- - -## ๐Ÿ’ณ Payment Gateway Integration โ€” October 28, 2025 (Afternoon) - -### โœ… Phase 1: Core Integration - COMPLETE - -**Problem:** Payment gateways (Tripay, Duitku, Xendit) not receiving transactions when orders created via WooNooW Admin. - -**Root Cause:** WooCommerce payment gateways expect `process_payment()` to be called during checkout, but admin-created orders bypass this flow. - -### ๐ŸŽฏ Solution Implemented - -#### **Backend Changes** - -**File:** `includes/Api/OrdersController.php` - -1. **Auto-trigger payment processing** (lines 913-915) - ```php - if ( $payment_method && $status === 'pending' ) { - self::process_payment_gateway( $order, $payment_method ); - } - ``` - -2. **New method: `process_payment_gateway()`** (lines 1509-1602) - - Initializes WooCommerce cart (prevents `empty_cart()` errors) - - Initializes WooCommerce session (prevents `set()` errors) - - Gets payment gateway instance - - Handles channel-based IDs (e.g., `tripay_bniva`, `bacs_account_0`) - - Calls `$gateway->process_payment($order_id)` - - Stores result metadata (`_woonoow_payment_redirect`) - - Adds order notes - - Logs success/failure - - Graceful error handling (doesn't fail order creation) - -### ๐Ÿ”ง Technical Details - -**Session Initialization:** -```php -// Initialize cart -if ( ! WC()->cart ) { - WC()->initialize_cart(); -} - -// Initialize session -if ( ! WC()->session || ! WC()->session instanceof \WC_Session ) { - WC()->initialize_session(); -} -``` - -**Why needed:** -- Payment gateways call `WC()->cart->empty_cart()` after successful payment -- Payment gateways call `WC()->session->set()` to store payment data -- Admin-created orders don't have active cart/session -- Without initialization: `Call to a member function on null` errors - -### ๐Ÿ“Š Features - -- โœ… Universal solution (works with all WooCommerce payment gateways) -- โœ… Handles Tripay, Duitku, Xendit, PayPal, and custom gateways -- โœ… Stores payment metadata for display -- โœ… Adds order notes for audit trail -- โœ… Error logging for debugging -- โœ… Non-blocking (order creation succeeds even if payment fails) -- โœ… Channel support (e.g., Tripay BNI VA, Mandiri VA, etc.) - -### ๐Ÿ“š Documentation - -- `PAYMENT_GATEWAY_INTEGRATION.md` - Complete implementation guide -- `PAYMENT_GATEWAY_PATTERNS.md` - Analysis of 4 major gateways - ---- - -## ๐Ÿ’ฐ Order Totals Calculation โ€” October 28, 2025 (Afternoon) - -### โœ… COMPLETE - Shipping & Coupon Fixes - -**Problem:** Orders created via WooNooW showed incorrect totals: -- Shipping cost always Rp0 (hardcoded) -- Coupon discounts not calculated -- Total = products only (missing shipping) - -### ๐ŸŽฏ Solutions Implemented - -#### **1. Shipping Cost Calculation** - -**File:** `includes/Api/OrdersController.php` (lines 830-858) - -**Before:** -```php -$ship_item->set_total( 0 ); // โŒ Always 0 -``` - -**After:** -```php -// Get shipping method cost from settings -$shipping_cost = 0; -if ( $instance_id ) { - $zones = \WC_Shipping_Zones::get_zones(); - foreach ( $zones as $zone ) { - foreach ( $zone['shipping_methods'] as $method ) { - if ( $method->id === $method_id && $method->instance_id == $instance_id ) { - $shipping_cost = $method->get_option( 'cost', 0 ); // โœ… Actual cost! - break 2; - } - } - } -} -$ship_item->set_total( $shipping_cost ); -``` - -#### **2. Coupon Discount Calculation** - -**File:** `includes/Api/OrdersController.php` (lines 876-886) - -**Before:** -```php -$citem = new \WC_Order_Item_Coupon(); -$citem->set_code( $coupon->get_code() ); -$order->add_item( $citem ); // โŒ No discount calculated -``` - -**After:** -```php -$order->apply_coupon( $coupon ); // โœ… Calculates discount! -``` - -### ๐Ÿ“Š Results - -**Order Calculation Flow:** -``` -1. Add products โ†’ Subtotal: Rp112.000 -2. Add shipping โ†’ Get cost from settings โ†’ Rp25.000 โœ… -3. Apply coupons โ†’ Calculate discount โ†’ -RpX โœ… -4. Calculate totals โ†’ Products + Shipping - Discount + Tax โœ… -5. Payment gateway โ†’ Receives correct total โœ… -``` - -**Example:** -- Products: Rp112.000 -- Shipping: Rp25.000 -- **Total: Rp137.000** โœ… (was Rp112.000 โŒ) - -### ๐Ÿ“š Documentation - -- `ORDER_TOTALS_FIX.md` - Complete fix documentation with test cases - ---- - -## ๐ŸŽจ Order Totals Display โ€” October 28, 2025 (Afternoon) - -### โœ… COMPLETE - Frontend Breakdown Display - -**Problem:** Order form only showed items count and subtotal. No shipping, discount, or total visible. - -### ๐ŸŽฏ Solution Implemented - -#### **Backend: Add Shipping Cost to API** - -**File:** `includes/Api/OrdersController.php` (lines 1149-1159) - -**Added `cost` field to shipping methods API:** -```php -$rows[] = [ - 'id' => $instance ? "{$id}:{$instance}" : $id, - 'method' => $id, - 'title' => (string) ( $m->title ?? $m->get_method_title() ?? $id ), - 'cost' => (float) $cost, // โœ… New! -]; -``` - -#### **Frontend: Complete Order Breakdown** - -**File:** `admin-spa/src/routes/Orders/partials/OrderForm.tsx` - -**Added calculations:** -```typescript -// Calculate shipping cost -const shippingCost = React.useMemo(() => { - if (!shippingMethod) return 0; - const method = shippings.find(s => s.id === shippingMethod); - return method ? Number(method.cost) || 0 : 0; -}, [shippingMethod, shippings]); - -// Calculate order total -const orderTotal = React.useMemo(() => { - return itemsTotal + shippingCost; -}, [itemsTotal, shippingCost]); -``` - -**Display:** -```tsx -
-
Items: 2
-
Subtotal: Rp112.000
-
Shipping: Rp25.000
-
Discount: (calculated on save)
-
- Total (est.): Rp137.000 -
-
-``` - -### ๐Ÿ“Š Features - -- โœ… Real-time shipping cost display -- โœ… Subtotal + Shipping = Total -- โœ… Discount note (calculated server-side) -- โœ… Professional breakdown layout -- โœ… Responsive design - -### ๐Ÿ’ก Coupon Calculation - Best Practice - -**Decision:** Show "(calculated on save)" instead of frontend calculation - -**Why:** -- โœ… Accurate - Backend has all coupon rules -- โœ… Secure - Can't bypass restrictions -- โœ… Simple - No complex frontend logic -- โœ… Reliable - Always matches final total - -**Industry Standard:** Shopify, WooCommerce, Amazon all calculate discounts server-side. - -### ๐Ÿ“š Documentation - -- `ORDER_TOTALS_DISPLAY.md` - Complete display documentation - ---- - -## ๐ŸŽซ Phase 2: Payment Display โ€” October 28, 2025 (Evening) - -### โœ… COMPLETE - Payment Instructions Card - -**Goal:** Display payment gateway metadata (VA numbers, QR codes, expiry, etc.) in Order Detail view. - -### ๐ŸŽฏ Solution Implemented - -#### **Backend: Payment Metadata API** - -**File:** `includes/Api/OrdersController.php` - -**New method: `get_payment_metadata()`** (lines 1604-1662) -```php -private static function get_payment_metadata( $order ): array { - $meta_keys = apply_filters( 'woonoow/payment_meta_keys', [ - // Tripay - '_tripay_payment_pay_code' => __( 'Payment Code', 'woonoow' ), - '_tripay_payment_reference' => __( 'Reference', 'woonoow' ), - '_tripay_payment_expired_time' => __( 'Expires At', 'woonoow' ), - '_tripay_payment_amount' => __( 'Amount', 'woonoow' ), - - // Duitku - '_duitku_va_number' => __( 'VA Number', 'woonoow' ), - '_duitku_payment_url' => __( 'Payment URL', 'woonoow' ), - - // Xendit - '_xendit_invoice_id' => __( 'Invoice ID', 'woonoow' ), - '_xendit_invoice_url' => __( 'Invoice URL', 'woonoow' ), - - // WooNooW - '_woonoow_payment_redirect' => __( 'Payment URL', 'woonoow' ), - ], $order ); - - // Extract, format timestamps, amounts, booleans - // Return structured array -} -``` - -**Features:** -- โœ… Auto-formats timestamps โ†’ readable dates -- โœ… Auto-formats amounts โ†’ currency (Rp70.000) -- โœ… Auto-formats booleans โ†’ Yes/No -- โœ… Extensible via `woonoow/payment_meta_keys` filter -- โœ… Supports Tripay, Duitku, Xendit, custom gateways - -**Added to order API response** (line 442): -```php -'payment_meta' => self::get_payment_metadata($order), -``` - -#### **Frontend: Payment Instructions Card** - -**File:** `admin-spa/src/routes/Orders/Detail.tsx` (lines 212-242) - -```tsx -{order.payment_meta && order.payment_meta.length > 0 && ( -
-
- - {__('Payment Instructions')} -
-
- {order.payment_meta.map((meta: any) => ( -
-
{meta.label}
-
- {meta.key.includes('url') ? ( - - {meta.value} - - ) : meta.key.includes('amount') ? ( - - ) : ( - meta.value - )} -
-
- ))} -
-
-)} -``` - -### ๐Ÿ“Š Example Display - -**Tripay BNI VA Order:** -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ ๐ŸŽซ Payment Instructions โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ Payment Code 8808123456789012 โ”‚ -โ”‚ Reference T1234567890 โ”‚ -โ”‚ Expires At Oct 28, 2025 11:59 PM โ”‚ -โ”‚ Amount Rp137.000 โ”‚ โ† Currency formatted! -โ”‚ Payment Type BNIVA โ”‚ -โ”‚ Payment URL https://tripay.co/... ๐Ÿ”—โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - -### ๐Ÿ“Š Features - -- โœ… Only shows if payment metadata exists -- โœ… Ticket icon for visual clarity -- โœ… Grid layout: Label | Value -- โœ… Auto-detects URLs โ†’ clickable with external icon -- โœ… Currency formatting for amounts -- โœ… Timestamp formatting -- โœ… Responsive design -- โœ… Extensible for custom gateways - -### ๐Ÿ“š Documentation - -- `PHASE2_PAYMENT_DISPLAY.md` - Complete Phase 2 documentation - ---- - -## ๐Ÿ“‹ Summary of October 28, 2025 Progress - -### โœ… Completed Features - -1. **Payment Gateway Integration (Phase 1)** - - Auto-trigger `process_payment()` for admin orders - - Session initialization (cart + session) - - Universal gateway support - - Error handling and logging - -2. **Order Totals Calculation** - - Shipping cost from method settings - - Coupon discount calculation - - Correct totals sent to payment gateway - -3. **Order Totals Display** - - Complete breakdown in order form - - Real-time shipping cost - - Professional UI - -4. **Payment Display (Phase 2)** - - Payment metadata extraction API - - Payment Instructions card - - Auto-formatting (timestamps, currency, URLs) - - Multi-gateway support - -### ๐Ÿ“Š Files Changed - -**Backend:** -- `includes/Api/OrdersController.php` - 7 major changes - -**Frontend:** -- `admin-spa/src/routes/Orders/partials/OrderForm.tsx` - Totals display -- `admin-spa/src/routes/Orders/Detail.tsx` - Payment Instructions card - -**Documentation:** -- `PAYMENT_GATEWAY_INTEGRATION.md` -- `PAYMENT_GATEWAY_PATTERNS.md` -- `ORDER_TOTALS_FIX.md` -- `ORDER_TOTALS_DISPLAY.md` -- `PHASE2_PAYMENT_DISPLAY.md` - -### ๐ŸŽฏ Next Phase: Actions - -**Phase 3 Features (Planned):** -- [ ] "Retry Payment" button -- [ ] "Cancel Payment" button -- [ ] Manual payment status sync -- [ ] Payment status webhooks -- [ ] Real-time payment updates - ---- - -**Last synced:** 2025โ€‘10โ€‘28 22:00 GMT+7 -**Next milestone:** Phase 3 Payment Actions OR Dashboard module development. - ---- - -## ๐Ÿ”„ Phase 3: Payment Actions โ€” October 28, 2025 (Night) - -### โœ… Retry Payment Feature - COMPLETE - -**Goal:** Allow admins to manually retry payment processing for orders with payment issues. - -### ๐ŸŽฏ Solution Implemented - -#### **Backend: Retry Payment Endpoint** - -**File:** `includes/Api/OrdersController.php` - -**New endpoint** (lines 100-105): -```php -register_rest_route('woonoow/v1', '/orders/(?P\d+)/retry-payment', [ - 'methods' => 'POST', - 'callback' => [__CLASS__, 'retry_payment'], - 'permission_callback' => function () { return current_user_can('manage_woocommerce'); }, -]); -``` - -**New method: `retry_payment()`** (lines 1676-1726): -```php -public static function retry_payment( WP_REST_Request $req ): WP_REST_Response { - // Validate permissions - if ( ! current_user_can( 'manage_woocommerce' ) ) { - return new WP_REST_Response( [ 'error' => 'forbidden' ], 403 ); - } - - // Get order - $order = wc_get_order( $id ); - if ( ! $order ) { - return new WP_REST_Response( [ 'error' => 'not_found' ], 404 ); - } - - // Validate payment method exists - $payment_method = $order->get_payment_method(); - if ( empty( $payment_method ) ) { - return new WP_REST_Response( [ - 'error' => 'no_payment_method', - 'message' => __( 'Order has no payment method', 'woonoow' ) - ], 400 ); - } - - // Only allow retry for pending/on-hold/failed orders - $status = $order->get_status(); - if ( ! in_array( $status, [ 'pending', 'on-hold', 'failed' ] ) ) { - return new WP_REST_Response( [ - 'error' => 'invalid_status', - 'message' => sprintf( - __( 'Cannot retry payment for order with status: %s', 'woonoow' ), - $status - ) - ], 400 ); - } - - // Add order note - $order->add_order_note( __( 'Payment retry requested via WooNooW Admin', 'woonoow' ) ); - $order->save(); - - // Trigger payment processing - self::process_payment_gateway( $order, $payment_method ); - - return new WP_REST_Response( [ - 'success' => true, - 'message' => __( 'Payment processing retried', 'woonoow' ) - ], 200 ); -} -``` - -**Features:** -- โœ… Permission check (manage_woocommerce) -- โœ… Order validation -- โœ… Payment method validation -- โœ… Status validation (only pending/on-hold/failed) -- โœ… Order note for audit trail -- โœ… Reuses existing `process_payment_gateway()` method -- โœ… Error handling with i18n messages - ---- - -#### **Frontend: Retry Payment Button** - -**File:** `admin-spa/src/routes/Orders/Detail.tsx` - -**Added mutation** (lines 113-130): -```typescript -// Mutation for retry payment -const retryPaymentMutation = useMutation({ - mutationFn: () => api.post(`/orders/${id}/retry-payment`, {}), - onSuccess: () => { - showSuccessToast(__('Payment processing retried')); - q.refetch(); - }, - onError: (err: any) => { - showErrorToast(err, __('Failed to retry payment')); - }, -}); - -function handleRetryPayment() { - if (!id) return; - if (confirm(__('Retry payment processing for this order?'))) { - retryPaymentMutation.mutate(); - } -} -``` - -**Added button in Payment Instructions card** (lines 234-253): -```tsx -
-
- - {__('Payment Instructions')} -
- {['pending', 'on-hold', 'failed'].includes(order.status) && ( - - )} -
-``` - -**Features:** -- โœ… Only shows for pending/on-hold/failed orders -- โœ… Confirmation dialog before retry -- โœ… Loading state with spinner -- โœ… Disabled during processing -- โœ… Success/error toast notifications -- โœ… Auto-refresh order data after retry -- โœ… Full i18n support - ---- - -### ๐Ÿ“Š How It Works - -**Flow:** -``` -1. Admin views order with pending payment - โ†“ -2. Payment Instructions card shows "Retry Payment" button - โ†“ -3. Admin clicks button โ†’ Confirmation dialog - โ†“ -4. Frontend calls POST /orders/{id}/retry-payment - โ†“ -5. Backend validates order status & payment method - โ†“ -6. Backend adds order note - โ†“ -7. Backend calls process_payment_gateway() - โ†“ -8. Gateway creates new transaction/payment - โ†“ -9. Frontend shows success toast - โ†“ -10. Order data refreshes with new payment metadata -``` - ---- - -### ๐ŸŽฏ Use Cases - -**When to use Retry Payment:** - -1. **Payment Gateway Timeout** - - Initial payment failed due to network issue - - Gateway API was temporarily down - - Retry creates new transaction - -2. **Expired Payment** - - VA number expired - - QR code expired - - Retry generates new payment code - -3. **Failed Transaction** - - Customer payment failed - - Need to generate new payment link - - Retry creates fresh transaction - -4. **Admin Error** - - Wrong payment method selected initially - - Need to regenerate payment instructions - - Retry with correct gateway - ---- - -### ๐Ÿ“Š Example Display - -**Order Detail - Pending Payment:** -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ ๐ŸŽซ Payment Instructions [๐Ÿ”„ Retry Payment] โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ Payment Code 8808123456789012 (expired) โ”‚ -โ”‚ Reference T1234567890 โ”‚ -โ”‚ Expires At Oct 28, 2025 3:47 PM (past) โ”‚ -โ”‚ Amount Rp137.000 โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - -**After clicking Retry Payment:** -``` -โœ… Payment processing retried - -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ ๐ŸŽซ Payment Instructions [๐Ÿ”„ Retry Payment] โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ Payment Code 8808987654321098 (new!) โ”‚ -โ”‚ Reference T9876543210 โ”‚ -โ”‚ Expires At Oct 29, 2025 11:59 PM โ”‚ -โ”‚ Amount Rp137.000 โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - ---- - -### ๐Ÿ“Š Features Summary - -**Backend:** -- โœ… New `/orders/{id}/retry-payment` endpoint -- โœ… Status validation (pending/on-hold/failed only) -- โœ… Payment method validation -- โœ… Order note for audit trail -- โœ… Reuses existing payment gateway logic -- โœ… Full error handling - -**Frontend:** -- โœ… Retry Payment button in Payment Instructions card -- โœ… Conditional display (only for eligible statuses) -- โœ… Confirmation dialog -- โœ… Loading states -- โœ… Toast notifications -- โœ… Auto-refresh after retry - -**UX:** -- โœ… Clear button placement -- โœ… Icon + text label -- โœ… Hover states -- โœ… Disabled state during processing -- โœ… Responsive design - ---- - -### ๐Ÿ“š Files Changed - -**Backend:** -- `includes/Api/OrdersController.php` (lines 100-105, 1676-1726) - -**Frontend:** -- `admin-spa/src/routes/Orders/Detail.tsx` (lines 7, 113-130, 234-253) - ---- - -### ๐ŸŽฏ Next Steps - -**Phase 3 Remaining Features:** -- [ ] "Cancel Payment" button -- [ ] Manual payment status sync -- [ ] Payment status webhooks -- [ ] Real-time payment updates - ---- - -**Last synced:** 2025โ€‘10โ€‘28 23:20 GMT+7 -**Next milestone:** Complete Phase 3 (Cancel Payment + Status Sync) OR Dashboard module. - ---- - -## ๐Ÿ”ง Phase 3: Fixes & Polish โ€” October 28, 2025 (Night) - -### โœ… Retry Payment Improvements - COMPLETE - -**Issues Found During Testing:** - -1. **โŒ Native confirm() dialog** - Not consistent with app design -2. **โŒ 20-30 second delay** when retrying payment (Test 2 & 3) -3. **โŒ Success toast on error** - Shows green even when payment fails (Test 6) - ---- - -### ๐ŸŽฏ Fixes Implemented - -#### **1. Replace confirm() with Shadcn Dialog** - -**File:** `admin-spa/src/routes/Orders/Detail.tsx` - -**Added Dialog component** (lines 9-10, 60, 124-132, 257-283): -```tsx -// Import Dialog components -import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'; -import { Button } from '@/components/ui/button'; - -// State -const [showRetryDialog, setShowRetryDialog] = useState(false); - -// Handlers -function handleRetryPayment() { - if (!id) return; - setShowRetryDialog(true); // Show dialog instead of confirm() -} - -function confirmRetryPayment() { - setShowRetryDialog(false); - retryPaymentMutation.mutate(); -} - -// Dialog UI - - - - {__('Retry Payment')} - - {__('Are you sure you want to retry payment processing for this order?')} -
- - {__('This will create a new payment transaction.')} - -
-
- - - - -
-
-``` - -**Result:** -- โœ… Professional dialog matching Delete Orders design -- โœ… Warning message about creating new transaction -- โœ… Loading state in dialog button -- โœ… Full i18n support - ---- - -#### **2. Fix 20-30 Second Delay** - -**Problem:** WooCommerce analytics tracking to `pixel.wp.com` during `$order->save()` - -**File:** `includes/Api/OrdersController.php` (lines 1718-1728) - -**Solution:** -```php -// Block WooCommerce analytics tracking during save (prevents 30s delay) -add_filter('pre_http_request', function($preempt, $args, $url) { - if (strpos($url, 'pixel.wp.com') !== false || strpos($url, 'stats.wp.com') !== false) { - return new \WP_Error('http_request_blocked', 'WooCommerce analytics blocked'); - } - return $preempt; -}, PHP_INT_MAX, 3); - -$order->save(); // Now completes in ~0.02s instead of 30s! - -remove_all_filters('pre_http_request'); -``` - -**Result:** -- โœ… Retry payment now completes in <1 second -- โœ… 1500x faster (30s โ†’ 0.02s) -- โœ… Same fix used in order status updates - ---- - -#### **3. Fix Error Handling** - -**Problem:** Always shows success toast, even when payment gateway fails - -**File:** `includes/Api/OrdersController.php` (lines 1730-1739) - -**Before:** -```php -self::process_payment_gateway( $order, $payment_method ); - -return new WP_REST_Response( [ - 'success' => true, - 'message' => __( 'Payment processing retried', 'woonoow' ) -], 200 ); -``` - -**After:** -```php -// Trigger payment processing and capture result -$result = self::process_payment_gateway( $order, $payment_method ); - -// Check if payment processing failed -if ( is_wp_error( $result ) ) { - return new WP_REST_Response( [ - 'error' => 'payment_failed', - 'message' => $result->get_error_message() - ], 400 ); -} - -return new WP_REST_Response( [ - 'success' => true, - 'message' => __( 'Payment processing retried', 'woonoow' ) -], 200 ); -``` - -**Result:** -- โœ… Returns 400 error when payment fails -- โœ… Shows red error toast with actual error message -- โœ… Frontend properly handles errors - ---- - -### ๐Ÿ“Š Test Results - -**Before Fixes:** -- โฑ๏ธ Retry payment: 20-30 seconds -- โŒ Error shows green success toast -- ๐Ÿ”ฒ Native browser confirm() dialog - -**After Fixes:** -- โšก Retry payment: <1 second (1500x faster!) -- โœ… Error shows red error toast with message -- โœจ Professional Shadcn dialog - ---- - -### ๐Ÿ“š Files Changed - -**Frontend:** -- `admin-spa/src/routes/Orders/Detail.tsx` (lines 9-10, 60, 124-132, 257-283) - -**Backend:** -- `includes/Api/OrdersController.php` (lines 1718-1739) - ---- - -### ๐ŸŽฏ Cancel Payment Analysis - -**Question:** Should we implement "Cancel Payment" feature? - -**Research:** Analyzed Tripay, Duitku, Xendit, PayPal gateways - -**Findings:** -- โŒ Most Indonesian gateways **do NOT support** canceling pending payments via API -- โŒ VA numbers and QR codes expire automatically -- โŒ No explicit "cancel transaction" endpoint -- โš ๏ธ Changing order status to "Cancelled" doesn't cancel gateway transaction -- โš ๏ธ Customer can still pay after order cancelled (until expiry) -- โœ… Gateways handle expired payments automatically - -**Decision:** **Skip "Cancel Payment" feature** - -**Reasons:** -1. Not supported by major Indonesian gateways -2. Would require gateway-specific implementations -3. Limited value (payments auto-expire) -4. Order status "Cancelled" is sufficient for store management -5. Webhooks handle late payments - -**Alternative:** Use order status changes + webhook handling - ---- - -## ๐Ÿ“Š Dashboard Module Implementation -**Date:** 2025-10-29 14:45 GMT+7 - -### โœ… Complete Dashboard with Dummy Data - -**Objective:** Create a fully functional Dashboard SPA module with dummy data for visualization before connecting to real data sources. - -### ๐ŸŽฏ Key Features Implemented - -#### 1. **Unified Date Range Control** -- Single source of truth for period selection (7/14/30 days) -- Positioned inline with Dashboard title (desktop) / below title (mobile) -- Affects all date-based metrics and charts: - - Revenue, Orders, Avg Order Value stat cards - - Sales Overview chart - - Top Products list - - Top Customers list - - Order Status Distribution - -#### 2. **Metric Cards with Period Comparison** -- **Revenue** - Total for selected period with comparison -- **Orders** - Count for selected period with comparison -- **Avg Order Value** - Calculated from period data -- **Conversion Rate** - Percentage with change indicator -- Period comparison text: "vs previous 7/14/30 days" -- Color-coded trend indicators (green โ†‘ / red โ†“) - -#### 3. **Low Stock Alert Banner** -- Edge-to-edge amber warning banner -- Positioned between stat cards and chart -- Shows count of products needing attention -- Direct link to Products page -- Fully responsive (stacks on mobile) -- Dark mode support - -#### 4. **Interactive Sales Overview Chart** -- Toggle between Revenue / Orders / Both -- Dual-axis chart (Revenue left, Orders right) -- Proper currency formatting with store settings -- Thousand separator support (e.g., Rp10.200.000) -- Y-axis shows M/K format (millions/thousands) -- Translatable axis labels -- Custom tooltip with formatted values -- Filtered by selected period - -#### 5. **Interactive Order Status Pie Chart** -- Dropdown selector for order statuses -- Thick donut chart with double-ring expansion -- Active state shows selected status -- Hover state with visual feedback -- Center label displays count and status name -- Color-coded status indicators in dropdown -- Smooth transitions - -#### 6. **Top Products & Customers Tabs** -- Single card with tab switcher -- Products tab: Shows top 5 with revenue -- Customers tab: Shows top 5 with total spent -- Product icons/emojis for visual appeal -- "View all" link to respective pages - -### ๐Ÿ”ง Technical Implementation - -**Files Created/Modified:** -- `admin-spa/src/routes/Dashboard/index.tsx` - Main Dashboard component -- `admin-spa/src/components/ui/tabs.tsx` - Tabs component for Shadcn UI - -**Key Technologies:** -- **Recharts 3.3.0** - Chart library -- **React hooks** - useState, useMemo for performance -- **TanStack Query** - Ready for real data integration -- **Shadcn UI** - Select, Tabs components -- **Tailwind CSS** - Responsive styling - -**State Management:** -```typescript -const [period, setPeriod] = useState('30'); -const [chartMetric, setChartMetric] = useState('both'); -const [activeStatus, setActiveStatus] = useState('Completed'); -const [hoverIndex, setHoverIndex] = useState(); -``` - -**Computed Metrics:** -```typescript -const periodMetrics = useMemo(() => { - // Calculate revenue, orders, avgOrderValue - // Compare with previous period - return { revenue, orders, avgOrderValue }; -}, [chartData, period]); -``` - -### ๐ŸŽจ UX Improvements - -#### Currency Formatting -- Uses `formatMoney()` with store currency settings -- Proper thousand separator (dot for IDR, comma for USD) -- Decimal separator support -- Symbol positioning (left/right/space) -- Example: `Rp344.750.000` (Indonesian Rupiah) - -#### Responsive Design -- **Desktop:** 4-column metric grid, inline controls -- **Tablet:** 2-column metric grid -- **Mobile:** Single column, stacked layout -- Low Stock banner adapts to screen size -- Chart maintains aspect ratio - -#### Interactive Elements -- Pie chart responds to dropdown selection -- Hover states on all interactive elements -- Smooth transitions and animations -- Keyboard navigation support - -### ๐Ÿ“Š Dummy Data Structure - -```typescript -DUMMY_DATA = { - metrics: { revenue, orders, averageOrderValue, conversionRate }, - salesChart: [{ date, revenue, orders }, ...], // 30 days - topProducts: [{ id, name, image, quantity, revenue }, ...], - topCustomers: [{ id, name, orders, totalSpent }, ...], - orderStatusDistribution: [{ name, value, color }, ...], - lowStock: [{ id, name, stock, threshold, status }, ...] -} -``` - -### ๐Ÿ› Issues Fixed - -1. **TypeScript activeIndex error** - Used spread operator with `as any` to bypass type checking -2. **Currency thousand separator** - Added `preferSymbol: true` to force store settings -3. **Pie chart not expanding** - Removed key-based re-render, used hover state instead -4. **Mobile responsiveness** - Fixed Low Stock banner layout for mobile -5. **CSS class conflicts** - Removed duplicate `self-*` classes, fixed `flex-shrink-1` to `shrink` - -### ๐ŸŽฏ Next Steps - -**Ready for Real Data Integration:** -1. Replace dummy data with API calls -2. Connect to WooCommerce analytics -3. Implement date range picker (custom dates) -4. Add loading states -5. Add error handling -6. Add data refresh functionality - -**Future Enhancements:** -- Export data functionality -- More chart types (bar, line, scatter) -- Comparison mode (year-over-year) -- Custom metric cards -- Dashboard customization - ---- - -## ๐Ÿ“Š Dashboard Submenus Implementation -**Date:** 2025-11-03 21:05 GMT+7 - -### โœ… All Dashboard Report Pages Complete - -**Objective:** Implement all 6 dashboard submenu pages with dummy data, shared components, and full functionality. - -### ๐ŸŽฏ Pages Implemented - -#### 1. **Revenue Report** (`/dashboard/revenue`) -**File:** `admin-spa/src/routes/Dashboard/Revenue.tsx` - -**Features:** -- 4 metric cards (Gross Revenue, Net Revenue, Tax Collected, Refunds) -- Area chart showing revenue over time with gradient fills -- Period selector (7/14/30 days) -- Granularity selector (Daily/Weekly/Monthly) -- 4 tabbed breakdown tables: - - By Product (with refunds and net revenue) - - By Category (with percentage of total) - - By Payment Method (BCA VA, Mandiri VA, GoPay, OVO) - - By Shipping Method (JNE, J&T, SiCepat, Pickup) -- Sortable columns with custom rendering -- Proper currency formatting with store settings - -#### 2. **Orders Analytics** (`/dashboard/orders`) -**File:** `admin-spa/src/routes/Dashboard/Orders.tsx` - -**Features:** -- 4 metric cards (Total Orders, Avg Order Value, Fulfillment Rate, Cancellation Rate) -- Line chart showing orders timeline with status breakdown -- Pie chart for order status distribution (Completed, Processing, Pending, etc.) -- Bar chart for orders by day of week -- Bar chart for orders by hour (24-hour heatmap showing peak times) -- Additional metrics cards (Avg Processing Time, Performance Summary) -- Color-coded status indicators - -#### 3. **Products Performance** (`/dashboard/products`) -**File:** `admin-spa/src/routes/Dashboard/Products.tsx` - -**Features:** -- 4 metric cards (Items Sold, Revenue, Low Stock Items, Out of Stock) -- Top products table with emoji icons (๐ŸŽง, โŒš, ๐Ÿ”Œ, etc.) -- Product details: SKU, items sold, revenue, stock, conversion rate -- Category performance table with percentage breakdown -- Stock analysis with 3 tabs: - - Low Stock (products below threshold) - - Out of Stock (unavailable products) - - Slow Movers (no recent sales) -- Highlighted low stock items in amber color -- Last sale date and days since sale tracking - -#### 4. **Customers Analytics** (`/dashboard/customers`) -**File:** `admin-spa/src/routes/Dashboard/Customers.tsx` - -**Features:** -- 4 metric cards (Total Customers, Avg LTV, Retention Rate, Avg Orders/Customer) -- 4 customer segment cards with percentages: - - New Customers (green) - - Returning Customers (blue) - - VIP Customers (purple) - - At Risk (red) -- Customer acquisition line chart (New vs Returning over time) -- Top customers table with segment badges -- Customer details: name, email, orders, total spent, avg order value -- LTV distribution bar chart (5 spending ranges) -- Angled x-axis labels for better readability - -#### 5. **Coupons Report** (`/dashboard/coupons`) -**File:** `admin-spa/src/routes/Dashboard/Coupons.tsx` - -**Features:** -- 4 metric cards (Total Discount, Coupons Used, Revenue with Coupons, Avg Discount/Order) -- Line chart showing coupon usage and discount amount over time -- Coupon performance table with: - - Coupon code (WELCOME10, FLASH50K, etc.) - - Type (Percentage, Fixed Cart, Fixed Product) - - Amount (10%, Rp50.000, etc.) - - Uses count - - Total discount amount - - Revenue generated - - ROI calculation (e.g., 6.1x) -- Sortable by any metric - -#### 6. **Taxes Report** (`/dashboard/taxes`) -**File:** `admin-spa/src/routes/Dashboard/Taxes.tsx` - -**Features:** -- 3 metric cards (Total Tax Collected, Avg Tax per Order, Orders with Tax) -- Line chart showing tax collection over time -- Tax by rate table (PPN 11%) -- Tax by location table: - - Indonesian provinces (DKI Jakarta, Jawa Barat, etc.) - - Orders count per location - - Tax amount per location - - Percentage of total -- Two-column layout for rate and location breakdowns - -### ๐Ÿ”ง Shared Components Created - -**Files:** `admin-spa/src/routes/Dashboard/components/` - -#### StatCard.tsx -**Purpose:** Reusable metric card with trend indicators - -**Features:** -- Supports 3 formats: money, number, percent -- Trend indicators (โ†‘ green / โ†“ red) -- Period comparison text -- Loading skeleton state -- Icon support (lucide-react) -- Responsive design - -**Usage:** -```typescript - -``` - -#### ChartCard.tsx -**Purpose:** Consistent chart container with title and actions - -**Features:** -- Title and description -- Action buttons slot (for selectors) -- Loading skeleton state -- Configurable height -- Responsive padding - -**Usage:** -```typescript -...} -> - ... - -``` - -#### DataTable.tsx -**Purpose:** Sortable, searchable data table - -**Features:** -- Sortable columns (asc/desc/none) -- Custom cell rendering -- Column alignment (left/center/right) -- Loading skeleton (5 rows) -- Empty state message -- Responsive overflow -- Hover states - -**Usage:** -```typescript - -``` - -### ๐Ÿ“Š Dummy Data Files - -**Files:** `admin-spa/src/routes/Dashboard/data/` - -All dummy data structures match the planned REST API responses: - -#### dummyRevenue.ts -- 30 days of chart data -- 8 top products -- 4 categories -- 4 payment methods -- 4 shipping methods -- Overview metrics with comparison - -#### dummyOrders.ts -- 30 days of chart data -- 6 order statuses with colors -- 24-hour breakdown -- 7-day breakdown -- Processing time metrics - -#### dummyProducts.ts -- 8 top products with emojis -- 4 categories -- Stock analysis (4 low, 2 out, 3 slow) -- Conversion rates -- Last sale tracking - -#### dummyCustomers.ts -- 10 top customers -- 30 days acquisition data -- 4 customer segments -- 5 LTV ranges -- Indonesian names and emails - -#### dummyCoupons.ts -- 7 active coupons -- 30 days usage data -- ROI calculations -- Multiple coupon types - -#### dummyTaxes.ts -- 30 days tax data -- PPN 11% rate -- 6 Indonesian provinces -- Location-based breakdown - -### ๐ŸŽจ Technical Highlights - -**Recharts Integration:** -- Area charts with gradient fills -- Line charts with multiple series -- Bar charts with rounded corners -- Pie charts with custom labels -- Custom tooltips with proper formatting -- Responsive containers -- Legend support - -**Currency Formatting:** -- Uses `formatMoney()` with store settings -- Proper thousand separator (dot for IDR) -- Decimal separator support -- Symbol positioning -- M/K abbreviations for large numbers -- Example: `Rp344.750.000` - -**Responsive Design:** -- Desktop: 4-column grids, side-by-side layouts -- Tablet: 2-column grids -- Mobile: Single column, stacked layouts -- Charts maintain aspect ratio -- Tables scroll horizontally -- Period selectors adapt to screen size - -**TypeScript:** -- Full type safety for all data structures -- Exported interfaces for each data type -- Generic DataTable component -- Type-safe column definitions -- Proper Recharts type handling (with `as any` workaround) - -### ๐Ÿ—บ๏ธ Navigation Integration - -**File:** `admin-spa/src/nav/tree.ts` - -**Added dashboard submenus:** -```typescript -{ - key: 'dashboard', - label: 'Dashboard', - path: '/', - children: [ - { label: 'Overview', mode: 'spa', path: '/', exact: true }, - { label: 'Revenue', mode: 'spa', path: '/dashboard/revenue' }, - { label: 'Orders', mode: 'spa', path: '/dashboard/orders' }, - { label: 'Products', mode: 'spa', path: '/dashboard/products' }, - { label: 'Customers', mode: 'spa', path: '/dashboard/customers' }, - { label: 'Coupons', mode: 'spa', path: '/dashboard/coupons' }, - { label: 'Taxes', mode: 'spa', path: '/dashboard/taxes' }, - ], -} -``` - -**Routing:** `admin-spa/src/App.tsx` - -All routes already added: -```typescript -} /> -} /> -} /> -} /> -} /> -} /> -} /> -``` - -### ๐ŸŽฏ Dummy Data Toggle System - -**Files:** -- `admin-spa/src/lib/useDummyData.ts` - Zustand store -- `admin-spa/src/components/DummyDataToggle.tsx` - Toggle button - -**Features:** -- Global state with LocalStorage persistence -- Toggle button on all dashboard pages -- Visual indicator (Database vs DatabaseZap icon) -- Works across page navigation -- Ready for real API integration - -**Usage in pages:** -```typescript -const useDummy = useDummyData(); -const data = useDummy ? DUMMY_DATA : realApiData; -``` - -### ๐Ÿ“ˆ Statistics - -**Files Created:** 19 -- 7 page components -- 3 shared components -- 6 dummy data files -- 1 dummy data store -- 1 toggle component -- 1 tooltip component - -**Lines of Code:** ~4,000+ -**Chart Types:** Area, Line, Bar, Pie -**Tables:** 15+ with sortable columns -**Metric Cards:** 25+ across all pages - -### ๐ŸŽฏ Next Steps - -**Immediate:** -1. โœ… Add dashboard submenus to navigation tree -2. โœ… Verify all routes work -3. โœ… Test dummy data toggle -4. โณ Update DASHBOARD_PLAN.md - -**Short Term:** -1. Wire to real API endpoints -2. Add loading states -3. Add error handling -4. Add data refresh functionality -5. Add export functionality (CSV/PDF) - -**Long Term:** -1. Custom date range picker -2. Comparison mode (year-over-year) -3. Dashboard customization -4. Real-time updates -5. Advanced filters - ---- - -**Last synced:** 2025โ€‘11โ€‘03 21:05 GMT+7 -**Next milestone:** Wire Dashboard to real data OR Products module.# ๐Ÿ“Š Dashboard Analytics Implementation โ€” November 4, 2025 - -## โœ… COMPLETE - All 7 Analytics Pages with Real Data - -**Status:** Production Ready -**Implementation:** Full HPOS integration with 5-minute caching -**Total Lines:** ~1200 lines (AnalyticsController.php) - -### ๐ŸŽฏ Implemented Pages - -#### **1. Overview** (`/analytics/overview`) -- โœ… Sales chart (revenue + orders over time) with **filled dates** -- โœ… Top 5 products by revenue -- โœ… Top 5 customers by spending -- โœ… Order status distribution (pie chart with sorting) -- โœ… Key metrics: Revenue, Orders, Avg Order Value, **Conversion Rate** - -#### **2. Revenue** (`/analytics/revenue`) -- โœ… Revenue chart (gross, net, tax, refunds, shipping) -- โœ… Top 10 products by revenue -- ๐Ÿ“‹ Revenue by category (TODO) -- ๐Ÿ“‹ Revenue by payment method (TODO) -- ๐Ÿ“‹ Revenue by shipping method (TODO) - -#### **3. Orders** (`/analytics/orders`) -- โœ… Orders over time (total + by status) -- โœ… Orders by status (sorted by importance) -- โœ… Orders by hour of day (24h breakdown) -- โœ… Orders by day of week -- โœ… Average processing time (human-readable) -- โœ… Fulfillment rate & Cancellation rate - -#### **4. Products** (`/analytics/products`) -- โœ… Top 20 products by revenue -- โœ… Stock analysis (low stock, out of stock counts) -- โœ… Average price calculation -- ๐Ÿ“‹ Conversion rate placeholder (0.00) - -#### **5. Customers** (`/analytics/customers`) -- โœ… Top 20 customers by spending -- โœ… New vs Returning customers -- โœ… Customer segments -- โœ… Average LTV (Lifetime Value) -- โœ… Average orders per customer - -#### **6. Coupons** (`/analytics/coupons`) -- โœ… Coupon usage chart over time -- โœ… Top coupons by discount amount -- โœ… **ROI calculation** (Revenue Generated / Discount Given) -- โœ… Coupon performance metrics - -#### **7. Taxes** (`/analytics/taxes`) -- โœ… Tax chart over time -- โœ… Total tax collected -- โœ… Average tax per order -- โœ… Orders with tax count - ---- - -## ๐Ÿ”ง Key Features Implemented - -### **1. Conversion Rate Calculation** -**Formula:** `(Completed Orders / Total Orders) ร— 100` - -**Example:** -- 10 orders total -- 3 completed -- Conversion Rate = 30.00% - -**Location:** `AnalyticsController.php` lines 383-406 - -```php -$total_all_orders = 0; -$completed_orders = 0; - -foreach ($orderStatusDistribution as $status) { - $total_all_orders += $count; - if ($status->status === 'wc-completed') { - $completed_orders = $count; - } -} - -$conversion_rate = $total_all_orders > 0 - ? round(($completed_orders / $total_all_orders) * 100, 2) - : 0.00; -``` - ---- - -### **2. Fill All Dates in Charts** -**Best Practice:** Show all dates in range, even with no data - -**Implementation:** `AnalyticsController.php` lines 324-358 - -```php -// Create a map of existing data -$data_map = []; -foreach ($salesChart as $row) { - $data_map[$row->date] = [ - 'revenue' => round(floatval($row->revenue), 2), - 'orders' => intval($row->orders), - ]; -} - -// Fill in ALL dates in the range -for ($i = $days - 1; $i >= 0; $i--) { - $date = date('Y-m-d', strtotime("-{$i} days")); - - if (isset($data_map[$date])) { - $revenue = $data_map[$date]['revenue']; - $orders = $data_map[$date]['orders']; - } else { - // No data for this date, fill with zeros - $revenue = 0.00; - $orders = 0; - } - - $formatted_sales[] = [ - 'date' => $date, - 'revenue' => $revenue, - 'orders' => $orders, - ]; -} -``` - -**Benefits:** -- โœ… Shows complete timeline (no gaps) -- โœ… Weekends/holidays with no orders are visible -- โœ… Accurate trend visualization -- โœ… Matches Google Analytics, Shopify standards - ---- - -### **3. Frontend Improvements** - -#### **Conversion Rate Display** -- โœ… Uses real API data (no dummy fallback) -- โœ… Formatted as percentage with 2 decimals -- โœ… Shows comparison for non-"all time" periods - -#### **Low Stock Alert** -- โœ… Hides when count is zero -- โœ… Shows actual count from API -- โœ… No dummy data fallback - -**Location:** `admin-spa/src/routes/Dashboard/index.tsx` - -```typescript -// Conversion rate from real data -const currentConversionRate = data?.metrics?.conversionRate?.today ?? 0; - -// Low stock alert - hide if zero -{(data?.lowStock?.length ?? 0) > 0 && ( -
- {data?.lowStock?.length ?? 0} products need attention -
-)} -``` - ---- - -### **4. Chart Visualization** - -**Sales Overview Chart:** -- โœ… Area chart for revenue (gradient fill) -- โœ… Line chart with dots for orders -- โœ… Balanced visual hierarchy -- โœ… Professional appearance - -**Order Status Pie Chart:** -- โœ… Sorted by importance (completed first) -- โœ… Auto-selection of first status -- โœ… Interactive hover states -- โœ… Color-coded by status - ---- - -## ๐Ÿ“Š API Endpoints - -All endpoints support caching (5 minutes): - -1. `GET /woonoow/v1/analytics/overview?period=30` -2. `GET /woonoow/v1/analytics/revenue?period=30&granularity=day` -3. `GET /woonoow/v1/analytics/orders?period=30` -4. `GET /woonoow/v1/analytics/products?period=30` -5. `GET /woonoow/v1/analytics/customers?period=30` -6. `GET /woonoow/v1/analytics/coupons?period=30` -7. `GET /woonoow/v1/analytics/taxes?period=30` - -**Period Options:** `7`, `14`, `30`, `all` - ---- - -## ๐ŸŽจ UI/UX Features - -- โœ… Period selector (Last 7/14/30 days, All time) -- โœ… Real Data toggle (switches between real and dummy data) -- โœ… Responsive design (mobile-first) -- โœ… Dark mode support -- โœ… Loading states -- โœ… Error handling -- โœ… Empty states -- โœ… Metric cards with comparison -- โœ… Professional charts (Recharts) -- โœ… Consistent styling (Shadcn UI) - ---- - -## ๐Ÿ“š Files Changed - -### Backend (PHP) -- `includes/Api/AnalyticsController.php` - Complete implementation (~1200 lines) -- `includes/Api/Routes.php` - 7 new endpoints - -### Frontend (React/TypeScript) -- `admin-spa/src/routes/Dashboard/index.tsx` - Overview page -- `admin-spa/src/routes/Dashboard/Revenue.tsx` - Revenue page -- `admin-spa/src/routes/Dashboard/Orders.tsx` - Orders analytics -- `admin-spa/src/routes/Dashboard/Products.tsx` - Products analytics -- `admin-spa/src/routes/Dashboard/Customers.tsx` - Customers analytics -- `admin-spa/src/routes/Dashboard/Coupons.tsx` - Coupons analytics -- `admin-spa/src/routes/Dashboard/Taxes.tsx` - Taxes analytics -- `admin-spa/src/hooks/useAnalytics.ts` - Shared analytics hook - ---- - -## ๐Ÿ› Fixes Applied - -1. โœ… **Recharts prop warning** - Changed from function to string-based `dataKey`/`nameKey` -2. โœ… **Conversion rate dummy data** - Now uses real API data -3. โœ… **Low stock alert** - Hides when zero -4. โœ… **Date gaps in charts** - All dates filled with zeros -5. โœ… **"All time" comparison** - Suppressed for all time period -6. โœ… **Percentage formatting** - Consistent 2 decimal places - ---- - -## ๐ŸŽฏ Next Steps (Optional Enhancements) - -1. **Revenue by Category** - Group products by category -2. **Revenue by Payment Method** - Breakdown by gateway -3. **Revenue by Shipping Method** - Breakdown by shipping -4. **Product Conversion Rate** - Track views โ†’ purchases -5. **Customer Retention Rate** - Calculate repeat purchase rate -6. **Previous Period Comparison** - Calculate "yesterday" metrics -7. **Export to CSV** - Download analytics data -8. **Date Range Picker** - Custom date selection -9. **Real-time Updates** - WebSocket or polling -10. **Dashboard Widgets** - Customizable widget system - ---- - -## โœ… Success Criteria - ALL MET - -- [x] 7 analytics pages implemented -- [x] Real HPOS data integration -- [x] Caching (5 minutes) -- [x] Conversion rate calculation -- [x] Fill all dates in charts -- [x] ROI calculation for coupons -- [x] Responsive design -- [x] Dark mode support -- [x] Error handling -- [x] Loading states -- [x] No dummy data fallbacks in Real Data mode -- [x] Professional UI/UX - ---- - -**Implementation Date:** November 4, 2025 -**Total Development Time:** ~6 hours -**Status:** โœ… Production Ready -**Next Milestone:** Products module OR Settings module - ---- - -## ๐Ÿš€ Standalone Admin Mode โ€” November 5, 2025 - -### โœ… COMPLETE - Three Admin Modes Implemented - -**Goal:** Provide flexible admin interface access with three distinct modes: normal (wp-admin), fullscreen, and standalone. - -### ๐ŸŽฏ Three Admin Modes - -#### **1. Normal Mode (wp-admin)** -- **URL:** `/wp-admin/admin.php?page=woonoow` -- **Layout:** WordPress admin sidebar + WooNooW SPA -- **Use Case:** Traditional WordPress admin workflow -- **Features:** - - WordPress admin bar visible - - WordPress sidebar navigation - - WooNooW SPA in main content area - - Settings submenu hidden (use WooCommerce settings) - -#### **2. Fullscreen Mode** -- **Toggle:** Fullscreen button in header -- **Layout:** WooNooW SPA only (no WordPress chrome) -- **Use Case:** Focus mode for order processing -- **Features:** - - Maximized workspace - - Distraction-free interface - - All WooNooW features accessible - - Settings submenu hidden - -#### **3. Standalone Mode** โœจ NEW -- **URL:** `https://yoursite.com/admin` -- **Layout:** Complete standalone application -- **Use Case:** Quick daily access, mobile-friendly -- **Features:** - - Custom login page (`/admin#/login`) - - WordPress authentication integration - - Settings submenu visible (SPA settings pages) - - "WordPress" button to access wp-admin - - "Logout" button in header - - Admin bar link in wp-admin to standalone - -### ๐Ÿ”ง Implementation Details - -#### **Backend Changes** - -**File:** `includes/Admin/StandaloneAdmin.php` -- Handles `/admin` and `/admin/` requests -- Renders standalone HTML template -- Localizes `WNW_CONFIG` with `standaloneMode: true` -- Provides authentication state -- Includes store settings (currency, formatting) - -**File:** `includes/Admin/Menu.php` -- Added admin bar link to standalone mode -- Icon: `dashicons-store` -- Only visible to users with `manage_woocommerce` capability - -**File:** `includes/Api/AuthController.php` -- Login endpoint using native WordPress authentication -- Sequence: `wp_authenticate()` โ†’ `wp_clear_auth_cookie()` โ†’ `wp_set_current_user()` โ†’ `wp_set_auth_cookie()` โ†’ `do_action('wp_login')` -- Ensures session persistence between standalone and wp-admin - -#### **Frontend Changes** - -**File:** `admin-spa/src/App.tsx` -- `AuthWrapper` component handles authentication -- Login/logout flow with page reload -- "WordPress" button in header (standalone only) -- "Logout" button in header (standalone only) - -**File:** `admin-spa/src/routes/Login.tsx` -- Custom login form -- Username/password authentication -- Redirects to dashboard after login -- Page reload to pick up fresh cookies/nonces - -**File:** `admin-spa/src/nav/tree.ts` -- Dynamic settings submenu using getter -- Only shows in standalone mode: `get children() { return isStandalone ? [...] : [] }` -- Dashboard path: `/dashboard` (with redirect from `/`) - -### ๐Ÿ“Š Navigation Structure - -**Standalone Mode Settings:** -``` -Settings -โ”œโ”€โ”€ WooNooW (main settings) -โ”œโ”€โ”€ General (store settings) -โ”œโ”€โ”€ Payments (gateways) -โ”œโ”€โ”€ Shipping (zones, methods) -โ”œโ”€โ”€ Products (inventory) -โ”œโ”€โ”€ Tax (rates) -โ”œโ”€โ”€ Accounts & Privacy -โ”œโ”€โ”€ Emails (templates) -โ”œโ”€โ”€ Advanced (bridge to wp-admin) -โ”œโ”€โ”€ Integration (bridge to wp-admin) -โ”œโ”€โ”€ Status (bridge to wp-admin) -โ””โ”€โ”€ Extensions (bridge to wp-admin) -``` - -**Strategy:** Option A - Everyday Use Dashboard -- Focus on most-used settings -- Bridge to wp-admin for advanced settings -- Extensible for 3rd party plugins -- Coexist with WooCommerce - -### ๐Ÿ” Authentication Flow - -**Standalone Login:** -1. User visits `/admin` -2. Not authenticated โ†’ redirect to `/admin#/login` -3. Submit credentials โ†’ `POST /wp-json/woonoow/v1/auth/login` -4. Backend sets WordPress auth cookies -5. Page reload โ†’ authenticated state -6. Access all WooNooW features - -**Session Persistence:** -- Login in standalone โ†’ logged in wp-admin โœ… -- Login in wp-admin โ†’ logged in standalone โœ… -- Logout in standalone โ†’ logged out wp-admin โœ… -- Logout in wp-admin โ†’ logged out standalone โœ… - -### ๐Ÿ“ฑ Cross-Navigation - -**From Standalone to wp-admin:** -- Click "WordPress" button in header -- Opens `/wp-admin` in same tab -- Session persists - -**From wp-admin to Standalone:** -- Click "WooNooW" in admin bar -- Opens `/admin` in same tab -- Session persists - -### โœ… Features Completed - -- [x] Standalone mode routing (`/admin`) -- [x] Custom login page -- [x] WordPress authentication integration -- [x] Session persistence -- [x] Settings submenu (standalone only) -- [x] WordPress button in header -- [x] Logout button in header -- [x] Admin bar link to standalone -- [x] Dashboard path consistency (`/dashboard`) -- [x] Dynamic navigation tree -- [x] Settings placeholder pages -- [x] Documentation updates - -### ๐Ÿ“š Documentation - -- `STANDALONE_ADMIN_SETUP.md` - Setup guide -- `PROJECT_BRIEF.md` - Updated Phase 4 -- `PROJECT_SOP.md` - Section 7 (modes explanation) -- `PROGRESS_NOTE.md` - This section - ---- - -**Implementation Date:** November 5, 2025 -**Status:** โœ… Production Ready -**Next Milestone:** Implement General/Payments/Shipping settings pages - ---- - -## ๐Ÿ“ฑ Mobile Orders UI Enhancement & Contextual Headers - -**Date:** November 8, 2025 -**Status:** โœ… Completed & Documented - -### Overview - -Enhanced the Orders module with a complete mobile-first redesign, implementing industry-standard patterns for card layouts, filtering, and contextual headers across all CRUD pages. - -### Features Implemented - -#### 1. Mobile Orders List Redesign โœ… -- **Card-based layout** for mobile (replaces table) -- **OrderCard component** with status-colored badges -- **SearchBar component** with integrated filter button -- **FilterBottomSheet** for mobile-friendly filtering -- **Pull-to-refresh** functionality -- **Infinite scroll** support -- **Responsive design** (cards on mobile, table on desktop) - -**Files:** -- `admin-spa/src/routes/Orders/index.tsx` - Complete mobile redesign -- `admin-spa/src/routes/Orders/components/OrderCard.tsx` - Card component -- `admin-spa/src/routes/Orders/components/SearchBar.tsx` - Search with filter button -- `admin-spa/src/routes/Orders/components/FilterBottomSheet.tsx` - Mobile filter UI - -#### 2. OrderCard Design Evolution โœ… - -**Final Design:** -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ โ˜ [#337] Nov 04, 2025, 11:44 PMโ”‚ โ† Order ID badge (status color) -โ”‚ Dwindi Ramadhana โ†’โ”‚ โ† Customer (bold) -โ”‚ 1 item ยท Test Digital โ”‚ โ† Items -โ”‚ Rp64.500 โ”‚ โ† Total (large, primary) -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - -**Features:** -- Order ID as colored badge (replaces icon) -- Status colors: Green (completed), Blue (processing), Amber (pending), etc. -- Compact layout with efficient space usage -- Touch-optimized tap targets -- Inspired by Uber, DoorDash, Airbnb patterns - -#### 3. Filter Bottom Sheet โœ… - -**Features:** -- Z-index layering: Above FAB and bottom nav -- Instant filtering (no Apply button) -- Clear all filters button (when filters active) -- Proper padding for bottom navigation -- Scrollable content area - -**UX Pattern:** -- Filters apply immediately on change -- "Clear all filters" button only when filters active -- Follows industry standards (Gmail, Amazon, Airbnb) - -#### 4. DateRange Component Fixes โœ… - -**Issues Fixed:** -- Horizontal overflow in bottom sheet -- WP forms.css overriding styles -- Redundant Apply button - -**Solution:** -- Vertical layout (`flex-col`) -- Full shadcn/ui styling with `!important` overrides -- Instant filtering on date change - -#### 5. Mobile Contextual Header Pattern โœ… - -**Concept: Dual Header System** - -1. **Contextual Header** (Mobile + Desktop) - - Format: `[Back] Page Title [Action]` - - Common actions (Back, Edit, Save, Create) - - Always visible (sticky) - -2. **Page Header** (Desktop Only) - - Extra actions (Print, Invoice, Label) - - Hidden on mobile (`hidden md:flex`) - -**Implementation:** - -| Page | Contextual Header | Page Header | -|------|-------------------|-------------| -| **Orders List** | None | Filters, Search | -| **Order Detail** | [Back] Order #337 [Edit] | Print, Invoice, Label | -| **New Order** | [Back] New Order [Create] | None | -| **Edit Order** | [Back] Edit Order #337 [Save] | None | - -**Files:** -- `admin-spa/src/routes/Orders/Detail.tsx` - Contextual header with Back + Edit -- `admin-spa/src/routes/Orders/New.tsx` - Contextual header with Back + Create -- `admin-spa/src/routes/Orders/Edit.tsx` - Contextual header with Back + Save -- `admin-spa/src/routes/Orders/partials/OrderForm.tsx` - formRef + hideSubmitButton props - -**Form Submit Pattern:** -```typescript -// Trigger form submit from header button -const formRef = useRef(null); - -const actions = ( - -); - - -``` - -#### 6. Code Quality โœ… - -**ESLint Fixes:** -- Fixed React hooks rule violations -- Fixed TypeScript type mismatches -- Fixed React Compiler memoization warnings -- Zero errors, zero warnings in modified files - -**Files Fixed:** -- `admin-spa/src/routes/Orders/components/OrderCard.tsx` - Type fixes -- `admin-spa/src/routes/Orders/Edit.tsx` - Hooks order fix -- `admin-spa/src/routes/Orders/index.tsx` - Memoization fix - -### Technical Implementation - -**Key Patterns:** - -1. **usePageHeader Hook** - ```typescript - const { setPageHeader, clearPageHeader } = usePageHeader(); - - useEffect(() => { - setPageHeader('Page Title', ); - return () => clearPageHeader(); - }, [dependencies]); - ``` - -2. **Form Ref Pattern** - ```typescript - const formRef = useRef(null); -
- ``` - -3. **Instant Filtering** - ```typescript - // No Apply button - filters apply on change - useEffect(() => { - applyFilters(); - }, [filterValue]); - ``` - -4. **Responsive Actions** - ```typescript - {/* Desktop only */} -
- - -
- ``` - -### Benefits - -โœ… **Mobile-First UX** -- Card-based layouts for better mobile experience -- Touch-optimized controls and spacing -- Instant filtering without Apply buttons - -โœ… **Consistent Patterns** -- All CRUD pages follow same header structure -- Predictable navigation (Back button always visible) -- Loading states in action buttons - -โœ… **Industry Standards** -- Follows patterns from Gmail, Amazon, Airbnb -- Modern mobile app-like experience -- Professional, polished UI - -โœ… **Code Quality** -- Zero eslint errors/warnings -- Type-safe implementations -- Follows React best practices - -### Documentation Updates - -- โœ… `PROJECT_SOP.md` - Added section 5.8 (Mobile Contextual Header Pattern) -- โœ… `PROGRESS_NOTE.md` - This entry -- โœ… Code comments and examples in implementation - -### Git Commits - -1. `refine: Polish mobile Orders UI based on feedback` - OrderCard improvements -2. `feat: OrderCard redesign and CRUD header improvements` - Order ID badge pattern -3. `feat: Move action buttons to contextual headers for CRUD pages` - Contextual headers -4. `fix: Correct Order Detail contextual header implementation` - Detail page fix -5. `fix: Resolve eslint errors in Orders components` - Code quality - -### Testing Checklist - -- [x] OrderCard displays correctly on mobile -- [x] Filter bottom sheet works without overlap -- [x] DateRange component doesn't overflow -- [x] Contextual headers show on all CRUD pages -- [x] Back buttons navigate correctly -- [x] Save/Create buttons trigger form submit -- [x] Loading states display properly -- [x] Desktop extra actions hidden on mobile -- [x] ESLint passes with zero errors/warnings - -### Next Steps - -- [ ] Apply contextual header pattern to Products module -- [ ] Apply contextual header pattern to Customers module -- [ ] Apply contextual header pattern to Coupons module -- [ ] Create reusable CRUD page template -- [ ] Document pattern in developer guide - ---- - -**Implementation Date:** November 8, 2025 -**Status:** โœ… Production Ready -**Next Milestone:** Apply mobile patterns to other modules - ---- - -## ๐Ÿ”” Notification System Refinement โ€” November 11, 2025 - -### โœ… COMPLETE - UI/UX Improvements & Toggle Logic Fixes - -**Goal:** Simplify notification settings UI and fix critical toggle bugs. - -### ๐ŸŽฏ Phase 1: UI/UX Refinements - -#### **Channels Page Improvements** - -**Changes Made:** -1. โœ… Removed redundant "Active/Inactive" badge (color indicates state) -2. โœ… Renamed "Built-in Channels" โ†’ "Channels" (unified card) -3. โœ… Moved "Built-in" badge inline with channel title -4. โœ… Removed redundant "Subscribe" toggle for push notifications -5. โœ… Unified enable/disable toggle for all channels -6. โœ… Auto-subscribe when enabling push channel -7. โœ… Green icon when enabled, gray when disabled - -**Layout:** -``` -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ Channels โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ ๐Ÿ“ง Email [Built-in] โ”‚ -โ”‚ Email notifications powered by... โ”‚ -โ”‚ [Enabled โ—] [Configure] โ”‚ -โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค -โ”‚ ๐Ÿ”” Push Notifications [Built-in] โ”‚ -โ”‚ Browser push notifications... โ”‚ -โ”‚ [Disabled โ—‹] [Configure] โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ -``` - -#### **Events Page Improvements** - -**Changes Made:** -1. โœ… Removed event-level toggle (reduced visual density) -2. โœ… Cleaner header layout -3. โœ… Focus on per-channel toggles only - -**Before:** -``` -Order Placed [Toggle] -โ”œโ”€ Email [Toggle] Admin -โ””โ”€ Push [Toggle] Admin -``` - -**After:** -``` -Order Placed -โ”œโ”€ Email [Toggle] Admin -โ””โ”€ Push [Toggle] Admin -``` - -### ๐Ÿ› Phase 2: Critical Bug Fixes - -#### **Issue 1: Toggle Not Saving** - -**Problem:** Channel toggle always returned `enabled: true`, changes weren't saved - -**Root Cause:** Backend using `get_param()` instead of `get_json_params()` - -**Fix:** -```php -// Before -$channel_id = $request->get_param('channelId'); -$enabled = $request->get_param('enabled'); - -// After -$params = $request->get_json_params(); -$channel_id = isset($params['channelId']) ? $params['channelId'] : null; -$enabled = isset($params['enabled']) ? $params['enabled'] : null; -``` - -**Result:** Toggle state now persists correctly โœ… - ---- - -#### **Issue 2: Multiple API Calls** - -**Problem:** Single toggle triggered 3 network requests - -**Root Cause:** Optimistic update + `onSettled` refetch caused race condition - -**Fix:** -```typescript -// Removed optimistic update -// Now uses server response directly -onSuccess: (data, variables) => { - queryClient.setQueryData(['notification-channels'], (old) => - old.map(channel => - channel.id === variables.channelId - ? { ...channel, enabled: data.enabled } - : channel - ) - ); -} -``` - -**Result:** Only 1 request per toggle โœ… - ---- - -#### **Issue 3: Wrong Event Channel Defaults** - -**Problem:** -- Email showing as enabled by default (should be disabled) -- Push showing as disabled (inconsistent) -- Backend path was wrong - -**Root Cause:** -1. Wrong path: `$settings['event_id']` instead of `$settings['event_id']['channels']` -2. Defaults set to `true` instead of `false` - -**Fix:** -```php -// Before -'channels' => $settings['order_placed'] ?? ['email' => ['enabled' => true, ...]] - -// After -'channels' => $settings['order_placed']['channels'] ?? [ - 'email' => ['enabled' => false, 'recipient' => 'admin'], - 'push' => ['enabled' => false, 'recipient' => 'admin'] -] -``` - -**Result:** Events page shows correct defaults โœ… - ---- - -#### **Issue 4: Events Cannot Be Enabled** - -**Problem:** All event channels disabled and cannot be enabled - -**Root Cause:** Wrong data structure in `update_event()` - -**Fix:** -```php -// Before -$settings[$event_id][$channel_id] = [...]; -// Saved as: { "order_placed": { "email": {...} } } - -// After -$settings[$event_id]['channels'][$channel_id] = [...]; -// Saves as: { "order_placed": { "channels": { "email": {...} } } } -``` - -**Result:** Event toggles save correctly โœ… - -### ๐Ÿ“Š Data Structure - -**Correct Structure:** -```php -[ - 'order_placed' => [ - 'channels' => [ - 'email' => ['enabled' => true, 'recipient' => 'admin'], - 'push' => ['enabled' => false, 'recipient' => 'admin'] - ] - ] -] -``` - -### ๐ŸŽฏ Phase 3: Push Notification URL Strategy - -**Question:** Should push notification URL be static or dynamic? - -**Answer:** **Dynamic based on context** for better UX - -**Recommended Approach:** - -```php -// Event-specific URLs -$notification_urls = [ - 'order_placed' => '/wp-admin/admin.php?page=woonoow#/orders/{order_id}', - 'order_completed' => '/wp-admin/admin.php?page=woonoow#/orders/{order_id}', - 'low_stock' => '/wp-admin/admin.php?page=woonoow#/products/{product_id}', - 'out_of_stock' => '/wp-admin/admin.php?page=woonoow#/products/{product_id}', - 'new_customer' => '/wp-admin/admin.php?page=woonoow#/customers/{customer_id}', -]; -``` - -**Benefits:** -- โœ… Better UX - Direct navigation to relevant page -- โœ… Context-aware - Order notification โ†’ Order detail -- โœ… Actionable - User can immediately take action -- โœ… Professional - Industry standard (Gmail, Slack, etc.) - -**Implementation Plan:** -1. Add `notification_url` field to push settings -2. Support template variables: `{order_id}`, `{product_id}`, `{customer_id}` -3. Per-event URL configuration in Templates page -4. Default fallback: `/wp-admin/admin.php?page=woonoow#/orders` - -**Current State:** -- Global URL in push configuration: `/wp-admin/admin.php?page=woonoow#/orders` -- **Recommendation:** Keep as default, add per-event override in Templates - -### ๐Ÿ“š Documentation Created - -1. **NOTIFICATION_LOGIC.md** - Complete logic explanation - - Toggle hierarchy - - Decision logic with examples - - Implementation details - - Usage examples - - Testing checklist - -2. **NotificationManager.php** - Backend validation class - - `is_channel_enabled()` - Global state - - `is_event_channel_enabled()` - Event state - - `should_send_notification()` - Combined validation - - `send()` - Notification sending - -### โœ… Testing Results - -**Channels Page:** -- [x] Toggle email off โ†’ Stays off โœ… -- [x] Toggle email on โ†’ Stays on โœ… -- [x] Toggle push off โ†’ Does NOT affect email โœ… -- [x] Toggle push on โ†’ Does NOT affect email โœ… -- [x] Reload page โ†’ States persist โœ… - -**Events Page:** -- [x] Enable email for "Order Placed" โ†’ Saves โœ… -- [x] Enable push for "Order Placed" โ†’ Saves โœ… -- [x] Disable email โ†’ Does NOT affect push โœ… -- [x] Reload page โ†’ States persist โœ… -- [x] Enable multiple events โ†’ All save independently โœ… - -**Network Tab:** -- [x] Each toggle = 1 request only โœ… -- [x] Response includes correct `enabled` value โœ… -- [x] No race conditions โœ… - -### ๐Ÿ“Š Files Changed - -**Backend:** -- `includes/Api/NotificationsController.php` - 3 methods fixed -- `includes/Core/Notifications/NotificationManager.php` - New class - -**Frontend:** -- `admin-spa/src/routes/Settings/Notifications/Channels.tsx` - UI simplified, mutation fixed -- `admin-spa/src/routes/Settings/Notifications/Events.tsx` - Event-level toggle removed - -**Documentation:** -- `NOTIFICATION_LOGIC.md` - Complete logic documentation - -### ๐ŸŽฏ Next Steps - -**Immediate:** -- [ ] Implement dynamic push notification URLs per event -- [ ] Add URL template variables support -- [ ] Add per-event URL configuration in Templates page - -**Future:** -- [ ] Push notification icon per event type -- [ ] Push notification image per event (product image, customer avatar) -- [ ] Rich notification content (order items, product details) -- [ ] Notification actions (Mark as read, Quick reply) - ---- - -**Implementation Date:** November 11, 2025 -**Status:** โœ… Production Ready -**Next Milestone:** Dynamic push notification URLs - ---- - -## ๐Ÿ“ง Email Notification System Enhancements โ€” November 19, 2025 - -### โœ… Variable Dropdown in TipTap Editor - COMPLETE - -**Problem:** Users had to manually type `{variable_name}` placeholders in email templates. - -**Solution:** Added comprehensive variable dropdown with 40+ available variables. - -#### **Frontend Changes** - -**File:** `admin-spa/src/routes/Settings/Notifications/EditTemplate.tsx` - -**Added variables list** (lines 42-87): -```typescript -const availableVariables = [ - // Order variables (14) - 'order_number', 'order_id', 'order_date', 'order_total', - 'order_subtotal', 'order_tax', 'order_shipping', 'order_discount', - 'order_status', 'order_url', 'order_items_table', - 'completion_date', 'estimated_delivery', - - // Customer variables (7) - 'customer_name', 'customer_first_name', 'customer_last_name', - 'customer_email', 'customer_phone', - 'billing_address', 'shipping_address', - - // Payment variables (5) - 'payment_method', 'payment_status', 'payment_date', - 'transaction_id', 'payment_retry_url', - - // Shipping/Tracking variables (4) - 'tracking_number', 'tracking_url', - 'shipping_carrier', 'shipping_method', - - // URL variables (3) - 'review_url', 'shop_url', 'my_account_url', - - // Store variables (6) - 'site_name', 'site_title', 'store_name', - 'store_url', 'support_email', 'current_year', -]; -``` - -**Features:** -- โœ… Dropdown appears below TipTap editor -- โœ… Shows all 40+ available variables -- โœ… Click to insert at cursor position -- โœ… Formatted as `{variable_name}` -- โœ… Categorized by type (Order, Customer, Payment, etc.) - ---- - -### โœ… Notification Page Reorganization - COMPLETE - -**Problem:** Flat card layout made it hard to scale for future recipient types (Affiliate, Merchant). - -**Solution:** Categorized cards into "Recipients" and "Channels" sections. - -#### **Frontend Changes** - -**File:** `admin-spa/src/routes/Settings/Notifications.tsx` - -**New Structure:** -``` -๐Ÿ“ง Notifications -โ”œโ”€โ”€ ๐Ÿ‘ฅ Recipients -โ”‚ โ”œโ”€โ”€ Staff (Orders, Products, Customers) -โ”‚ โ””โ”€โ”€ Customer (Orders, Shipping, Account) -โ”‚ -โ””โ”€โ”€ ๐Ÿ“ก Channels - โ”œโ”€โ”€ Channel Configuration (Email, Push, WhatsApp, Telegram) - โ””โ”€โ”€ Activity Log (Coming soon) -``` - -**Benefits:** -- โœ… Clear separation of concerns -- โœ… Easy to add new recipients (Affiliate, Merchant) -- โœ… Scalable structure -- โœ… Better UX with section headers -- โœ… Professional organization - ---- - -### โœ… Email Card Styling Fixes - COMPLETE - -**Problem:** -1. `[card type="success"]` rendered with hero gradient (purple) instead of green -2. List support verification needed - -**Solution:** Fixed card rendering in EmailRenderer. - -#### **Backend Changes** - -**File:** `includes/Core/Notifications/EmailRenderer.php` (lines 348-380) - -**Before:** -```php -if ($type === 'hero' || $type === 'success') { - // Both used same gradient โŒ - $style .= ' background: linear-gradient(...)'; -} -``` - -**After:** -```php -if ($type === 'hero') { - // Hero: gradient background - $style .= ' background: linear-gradient(...)'; -} -elseif ($type === 'success') { - // Success: green theme โœ… - $style .= ' background-color: #f0fdf4; border-left: 4px solid #22c55e;'; -} -elseif ($type === 'info') { - // Info: blue theme - $style .= ' background-color: #f0f7ff; border-left: 4px solid #0071e3;'; -} -elseif ($type === 'warning') { - // Warning: orange theme - $style .= ' background-color: #fff8e1; border-left: 4px solid #ff9800;'; -} -``` - -**Card Types Now:** -- `default`: white background -- `hero`: gradient background (purple) -- `success`: green background with left border โœ… -- `info`: blue background with left border -- `warning`: orange background with left border - -**List Support:** -- โœ… Already working in MarkdownParser (lines 132-141) -- โœ… Supports: `*`, `-`, `โ€ข`, `โœ“`, `โœ”` as list markers -- โœ… Properly converts to `
  • ` HTML - ---- - -### ๐Ÿ“Š Files Changed - -**Frontend:** -- `admin-spa/src/routes/Settings/Notifications.tsx` - Card reorganization -- `admin-spa/src/routes/Settings/Notifications/EditTemplate.tsx` - Variable dropdown - -**Backend:** -- `includes/Core/Notifications/EmailRenderer.php` - Card styling fixes - -**Documentation:** -- `includes/Email/TEMPLATE_USAGE_GUIDE.md` - Updated with variable list - ---- - -## ๐Ÿ›๏ธ Product CRUD Module โ€” November 19, 2025 (In Progress) - -### โœ… Backend API - COMPLETE - -**Goal:** Comprehensive REST API for WooCommerce product management following Orders module pattern. - -#### **Backend Implementation** - -**File:** `includes/Api/ProductsController.php` (600+ lines) - -**Endpoints:** -```php -GET /products // List with filters -GET /products/{id} // Single product details -POST /products // Create product -PUT /products/{id} // Update product -DELETE /products/{id} // Delete product -GET /products/categories // Categories list -GET /products/tags // Tags list -GET /products/attributes // Attributes list -``` - -**Features:** - -**1. List Products** (`get_products`) -- โœ… Pagination (page, per_page) -- โœ… Search by name/SKU -- โœ… Filter by status (publish, draft, pending, private) -- โœ… Filter by category -- โœ… Filter by type (simple, variable) -- โœ… Filter by stock status (instock, outofstock, onbackorder) -- โœ… Sort by date, ID, modified, title -- โœ… Returns: id, name, SKU, type, status, price, stock, image - -**2. Get Single Product** (`get_product`) -- โœ… Full product details -- โœ… Description & short description -- โœ… Dimensions (weight, length, width, height) -- โœ… Categories & tags -- โœ… Images & gallery -- โœ… For variable products: attributes & variations - -**3. Create Product** (`create_product`) -- โœ… Simple & Variable product support -- โœ… Basic data (name, slug, status, description, SKU, prices) -- โœ… Stock management (manage_stock, stock_quantity, stock_status) -- โœ… Dimensions & weight -- โœ… Categories & tags -- โœ… Images & gallery -- โœ… Attributes (for variable products) -- โœ… Variations (for variable products) - -**4. Update Product** (`update_product`) -- โœ… Update all product fields -- โœ… Update variations -- โœ… Update attributes -- โœ… Partial updates supported - -**5. Delete Product** (`delete_product`) -- โœ… Soft delete (to trash) -- โœ… Force delete option -- โœ… Deletes variations automatically - -**6. Helper Methods** -- `get_categories()` - All product categories -- `get_tags()` - All product tags -- `get_attributes()` - All product attributes -- `format_product_list_item()` - Format for list view -- `format_product_full()` - Format with full details -- `save_product_attributes()` - Save attributes for variable products -- `save_product_variations()` - Save variations - -**Variation Support:** -```php -// Attributes -[ - { - "name": "Size", - "options": ["S", "M", "L"], - "variation": true, - "visible": true - }, - { - "name": "Color", - "options": ["Red", "Blue"], - "variation": true, - "visible": true - } -] - -// Variations -[ - { - "sku": "TSHIRT-S-RED", - "regular_price": "25.00", - "stock_quantity": 10, - "attributes": { - "Size": "S", - "Color": "Red" - } - } -] -``` - -#### **Routes Registration** - -**File:** `includes/Api/Routes.php` - -**Added:** -```php -use WooNooW\Api\ProductsController; - -// In rest_api_init: -ProductsController::register_routes(); -``` - ---- - -### ๐ŸŽฏ Next Steps (Frontend) - -**Pending:** -1. Create Products index page (table + cards like Orders) -2. Create Product New/Create form with variants support -3. Create Product Edit page -4. Add bulk delete functionality -5. Test complete CRUD flow - -**Pattern to Follow:** -- Study `admin-spa/src/routes/Orders/` structure -- Replicate for Products module -- Use same components (filters, search, pagination) -- Follow same UX patterns - ---- - -## ๐ŸŽ‰ November 19, 2025 - Evening Session: Product CRUD Frontend Complete! - -### โœ… Product CRUD Frontend Implementation (Complete) - -**Products Index Page** (`admin-spa/src/routes/Products/index.tsx` - 475 lines) -- โœ… Desktop table view with product images, SKU, stock, price, type -- โœ… Mobile card view with responsive ProductCard component -- โœ… Multi-select checkboxes with bulk delete functionality -- โœ… Advanced filters: status, type, stock status, category -- โœ… Client-side search by name, SKU, or ID -- โœ… Pagination (20 items per page) -- โœ… Pull to refresh functionality -- โœ… Loading skeletons and error states -- โœ… Stock status badges with quantity display -- โœ… Price display with HTML formatting -- โœ… Product type indicators -- โœ… Quick edit links -- โœ… URL query param synchronization -- โœ… Full i18n support - -**Product New Page** (`admin-spa/src/routes/Products/New.tsx` - 77 lines) -- โœ… Create new products with comprehensive form -- โœ… Page header with back/create buttons -- โœ… React Query mutation for API calls -- โœ… Success toast and navigation to created product -- โœ… Error handling with user-friendly messages -- โœ… Form ref for external submit (page header button) - -**Product Edit Page** (`admin-spa/src/routes/Products/Edit.tsx` - 107 lines) -- โœ… Load existing product data with React Query -- โœ… Update product with PUT request -- โœ… Loading skeleton while fetching -- โœ… Error card with retry functionality -- โœ… Page header with back/save buttons -- โœ… Query invalidation on successful update -- โœ… Navigation back to product after save - -**ProductForm Component** (`admin-spa/src/routes/Products/partials/ProductForm.tsx` - 600+ lines) -- โœ… **Basic Information:** - - Product name (required) - - Product type: Simple, Variable, Grouped, External - - Status: Published, Draft, Pending, Private - - Description (long) - - Short description -- โœ… **Pricing (Simple Products):** - - SKU - - Regular price (required for simple) - - Sale price -- โœ… **Inventory Management:** - - Manage stock toggle - - Stock quantity input - - Stock status: In Stock, Out of Stock, On Backorder -- โœ… **Categories & Tags:** - - Multi-select categories with checkboxes - - Multi-select tags with pill buttons - - Dynamic fetching from API -- โœ… **Attributes & Variations (Variable Products):** - - Add/remove attributes dynamically - - Define attribute options (comma-separated) - - Mark attributes as "used for variations" - - **Generate variations** button (creates all combinations) - - Per-variation inputs: SKU, regular price, sale price, stock - - Variation display with attribute combinations -- โœ… **Additional Options:** - - Virtual product checkbox - - Downloadable product checkbox - - Featured product checkbox -- โœ… **Form Features:** - - Comprehensive validation - - Toast notifications - - Reusable for create/edit modes - - Form ref support - - Hide submit button option - - Type-safe with TypeScript - -**Supporting Components:** -- โœ… `ProductCard.tsx` - Mobile card with image, name, SKU, type, price, stock badge -- โœ… `SearchBar.tsx` - Search input with filter button and active filter count -- โœ… `FilterBottomSheet.tsx` - Mobile filter sheet with status, type, stock, category, sort - -**Navigation & FAB:** -- โœ… Products already in navigation tree (`includes/Compat/NavigationRegistry.php`) - - All products - - New - - Categories - - Tags - - Attributes -- โœ… FAB already configured (`admin-spa/src/hooks/useFABConfig.tsx`) - - "Add Product" button on Products index - - Navigates to `/products/new` - -### ๐Ÿ“Š Summary - -**Completed Today (November 19, 2025):** -1. โœ… Variable dropdown in email template editor (40+ variables) -2. โœ… Notification page reorganization (Recipients + Channels) -3. โœ… Email card styling fixes (success = green, not purple) -4. โœ… List support verification (already working) -5. โœ… Product CRUD backend API (complete with variants) -6. โœ… Routes registration for Products API -7. โœ… **Product CRUD Frontend - Complete!** - - Products index with table/cards - - Product New page with form - - Product Edit page with form - - ProductForm component (600+ lines) - - All supporting components - - Navigation & FAB integration - -**Files Created:** -- `includes/Api/ProductsController.php` (600+ lines) -- `admin-spa/src/routes/Products/index.tsx` (475 lines) -- `admin-spa/src/routes/Products/New.tsx` (77 lines) -- `admin-spa/src/routes/Products/Edit.tsx` (107 lines) -- `admin-spa/src/routes/Products/partials/ProductForm.tsx` (600+ lines) -- `admin-spa/src/routes/Products/components/ProductCard.tsx` -- `admin-spa/src/routes/Products/components/SearchBar.tsx` -- `admin-spa/src/routes/Products/components/FilterBottomSheet.tsx` - -**Files Modified:** -- `admin-spa/src/routes/Settings/Notifications.tsx` -- `admin-spa/src/routes/Settings/Notifications/EditTemplate.tsx` -- `includes/Core/Notifications/EmailRenderer.php` -- `includes/Api/Routes.php` - -**Total Lines Added:** ~2,500+ lines of production-ready code - -**Next Session:** -- Test Product CRUD flow end-to-end -- Add product image upload functionality -- Implement product categories/tags/attributes pages -- Add product detail/view page - ---- - -**Last synced:** 2025-11-19 19:15 GMT+7 -**Next milestone:** Test and refine Product CRUD, add image upload diff --git a/archive/TASKS_SUMMARY.md b/archive/TASKS_SUMMARY.md deleted file mode 100644 index 25f8b51..0000000 --- a/archive/TASKS_SUMMARY.md +++ /dev/null @@ -1,130 +0,0 @@ -# Tasks Summary - November 11, 2025 - -## โœ… Task 1: Translation Support Audit - -### Status: COMPLETED โœ“ - -**Findings:** -- Most settings pages already have `__` translation function imported -- **Missing translation support:** - - `Store.tsx` - Needs `__` import and string wrapping - - `Payments.tsx` - Needs `__` import and string wrapping - - `Developer.tsx` - Needs `__` import and string wrapping - -**Action Required:** -Add translation support to these 3 files (can be done during next iteration) - ---- - -## โœ… Task 2: Documentation Audit - -### Status: COMPLETED โœ“ - -**Actions Taken:** -1. โœ… Created `DOCS_AUDIT_REPORT.md` - Comprehensive audit of all 36 MD files -2. โœ… Deleted 12 obsolete documents: - - CUSTOMER_SETTINGS_404_FIX.md - - MENU_FIX_SUMMARY.md - - DASHBOARD_TWEAKS_TODO.md - - DASHBOARD_PLAN.md - - SPA_ADMIN_MENU_PLAN.md - - STANDALONE_ADMIN_SETUP.md - - STANDALONE_MODE_SUMMARY.md - - SETTINGS_PAGES_PLAN.md - - SETTINGS_PAGES_PLAN_V2.md - - SETTINGS_TREE_PLAN.md - - SETTINGS_PLACEMENT_STRATEGY.md - - TAX_NOTIFICATIONS_PLAN.md - -**Result:** -- Reduced from 36 to 24 documents (33% reduction) -- Clearer focus on active development -- Easier navigation for developers - -**Remaining Documents:** -- 15 essential docs (keep as-is) -- 9 docs to consolidate later (low priority) - ---- - -## ๐Ÿšง Task 3: Notification Settings Implementation - -### Status: IN PROGRESS - -**Plan:** Follow NOTIFICATION_STRATEGY.md - -### Phase 1: Core Framework (Current) -1. **Backend (PHP)** - - [ ] Create `NotificationManager` class - - [ ] Create `EmailChannel` class (built-in) - - [ ] Create notification events registry - - [ ] Create REST API endpoints - - [ ] Add hooks for addon integration - -2. **Frontend (React)** - - [ ] Update `Notifications.tsx` settings page - - [ ] Create channel cards UI - - [ ] Create event configuration UI - - [ ] Add channel toggle/enable functionality - - [ ] Add template editor (email) - -3. **Database** - - [ ] Notification events table (optional) - - [ ] Use wp_options for settings - - [ ] Channel configurations - -### Implementation Steps - -#### Step 1: Backend Core -``` -includes/Core/Notifications/ -โ”œโ”€โ”€ NotificationManager.php # Main manager -โ”œโ”€โ”€ NotificationEvent.php # Event class -โ”œโ”€โ”€ Channels/ -โ”‚ โ””โ”€โ”€ EmailChannel.php # Built-in email -โ””โ”€โ”€ NotificationSettingsProvider.php # Settings CRUD -``` - -#### Step 2: REST API -``` -includes/Api/NotificationsController.php -- GET /notifications/channels # List available channels -- GET /notifications/events # List notification events -- GET /notifications/settings # Get all settings -- POST /notifications/settings # Save settings -``` - -#### Step 3: Frontend UI -``` -admin-spa/src/routes/Settings/Notifications.tsx -- Channel cards (email + addon channels) -- Event configuration per category -- Toggle channels per event -- Recipient selection (admin/customer/both) -``` - -### Key Features -- โœ… Email channel built-in -- โœ… Addon integration via hooks -- โœ… Per-event channel selection -- โœ… Recipient targeting -- โœ… Template system ready - ---- - -## Next Actions - -### Immediate -1. โœ… Commit documentation cleanup -2. ๐Ÿšง Start notification system implementation -3. โณ Add translation to Store/Payments/Developer pages - -### This Session -- Implement notification core framework -- Create REST API endpoints -- Build basic UI for notification settings - -### Future -- Build Telegram addon as proof of concept -- Create addon development template -- Document notification addon API diff --git a/docs/ADDONS_GUIDE.md b/docs/ADDONS_GUIDE.md new file mode 100644 index 0000000..e5677c0 --- /dev/null +++ b/docs/ADDONS_GUIDE.md @@ -0,0 +1,185 @@ +# WooNooW Addon & Module Development Guide + +**Version:** 2.0.0 +**Status:** Production Ready + +This document is the single source of truth for extending WooNooW. It covers everything from basic code snippets (Bridge Patterns) to full-featured React SPAs (Addon Modules). + +--- + +## ๐Ÿ“‹ Table of Contents + +1. [Philosophy & Architecture](#philosophy--architecture) +2. [Addon Types & Integration Levels](#addon-types--integration-levels) + - Level 1: Vanilla JS / Bridge Patterns + - Level 2: React Runtime Expansion (Recommended) + - Level 3: Slot-Based Components +3. [Developing a Full Addon](#developing-a-full-addon) + - Registration + - Settings & Options + - The Hook System +4. [Addon & Built-in Module Unification](#addon--built-in-module-unification) +5. [Examples](#examples) + +--- + +## 1. Philosophy & Architecture + +**WooNooW Core = Zero Addon Dependencies** + +We don't integrate specific addons (like shipping or payment plugins) directly into WooNooW core. Instead, we provide: +1. **Hook system** for external addons to extend functionality. +2. **Exposed React Runtime** so addons don't have to bundle heavy libraries. +3. **Unified Module Registry** where built-in features (like Affiliates, Newsletters) and external addons share the same UI and enablement toggles. + +--- + +## 2. Addon Types & Integration Levels + +### Level 1: Vanilla JS / Bridge Patterns (Basic) +Use this for simple snippets to make existing WooCommerce plugins (e.g. Rajaongkir) work with WooNooW. + +```javascript +// Wait for WooNooW to load +window.addEventListener('woonoow:loaded', function() { + window.WooNooW.hooks.addFilter('woonoow_order_form_after_shipping', function(container, formData) { + const div = document.createElement('div'); + div.innerHTML = ``; + container.appendChild(div); + return container; + }); +}); +``` + +### Level 2: Exposed React Runtime (Recommended) +WooNooW exposes `React`, `ReactDOM`, its `hooks`, and its `components` on `window.WooNooW`. This allows addons to build rich UIs without bundling React. + +**Webpack/Vite Setup (Externals):** +```javascript +// vite.config.js +export default { + build: { + rollupOptions: { + external: ['react', 'react-dom'], + output: { + globals: { + react: 'window.WooNooW.React', + 'react-dom': 'window.WooNooW.ReactDOM' + } + } + } + } +}; +``` + +**Usage:** +```typescript +const { React, hooks, components } = window.WooNooW; +const { addFilter } = hooks; +const { Select } = components; + +function CustomField({ formData, setFormData }) { + return