# Alpine.js Page Template - Quick Reference (WITH CENTRALIZED LOGGING) ## ✅ Correct Page Structure ```javascript // static/admin/js/your-page.js (or vendor/shop) // 1. ✅ Use centralized logger (ONE LINE!) const yourPageLog = window.LogConfig.loggers.yourPage; // OR create custom if not pre-configured // const yourPageLog = window.LogConfig.createLogger('YOUR-PAGE', window.LogConfig.logLevel); // 2. Create your Alpine.js component function yourPageComponent() { return { // ✅ CRITICAL: Inherit base layout functionality ...data(), // ✅ CRITICAL: Set page identifier currentPage: 'your-page', // Your page-specific state items: [], loading: false, error: null, // ✅ CRITICAL: Proper initialization with guard async init() { yourPageLog.info('=== YOUR PAGE INITIALIZING ==='); // Prevent multiple initializations if (window._yourPageInitialized) { yourPageLog.warn('Page already initialized, skipping...'); return; } window._yourPageInitialized = true; // Load your data await this.loadData(); yourPageLog.info('=== YOUR PAGE INITIALIZATION COMPLETE ==='); }, // Your methods async loadData() { yourPageLog.info('Loading data...'); this.loading = true; this.error = null; try { const startTime = performance.now(); // Log API request const url = '/your/endpoint'; window.LogConfig.logApiCall('GET', url, null, 'request'); // ✅ CRITICAL: Use lowercase apiClient const response = await apiClient.get(url); // Log API response window.LogConfig.logApiCall('GET', url, response, 'response'); this.items = response.items || []; // Log performance const duration = performance.now() - startTime; window.LogConfig.logPerformance('Load Data', duration); yourPageLog.info(`Data loaded successfully`, { count: this.items.length, duration: `${duration}ms` }); } catch (error) { // Use centralized error logging window.LogConfig.logError(error, 'Load Data'); this.error = error.message; Utils.showToast('Failed to load data', 'error'); } finally { this.loading = false; } }, // Format date helper (if needed) formatDate(dateString) { if (!dateString) return '-'; return Utils.formatDate(dateString); }, // Your other methods... }; } yourPageLog.info('Your page module loaded'); ``` --- ## 🎯 Checklist for New Pages ### HTML Template ```jinja2 {# app/templates/admin/your-page.html #} {% extends "admin/base.html" %} {% block title %}Your Page{% endblock %} {# ✅ CRITICAL: Link to your Alpine.js component #} {% block alpine_data %}yourPageComponent(){% endblock %} {% block content %} {% endblock %} {% block extra_scripts %} {# ✅ CRITICAL: Load your JavaScript file #} {% endblock %} ``` ### JavaScript File Checklist - [ ] ✅ Use centralized logger (ONE line instead of 15!) - [ ] ✅ Function name matches `alpine_data` in template - [ ] ✅ `...data(),` at start of return object - [ ] ✅ `currentPage: 'your-page'` set - [ ] ✅ Initialization guard in `init()` - [ ] ✅ Use lowercase `apiClient` for API calls - [ ] ✅ Use `window.LogConfig.logApiCall()` for API logging - [ ] ✅ Use `window.LogConfig.logPerformance()` for performance - [ ] ✅ Use `window.LogConfig.logError()` for errors - [ ] ✅ Module loaded log at end --- ## 📦 Pre-configured Loggers by Frontend ### Admin Frontend ```javascript window.LogConfig.loggers.vendors // Vendor management window.LogConfig.loggers.vendorTheme // Theme customization window.LogConfig.loggers.vendorUsers // Vendor users window.LogConfig.loggers.products // Product management window.LogConfig.loggers.inventory // Inventory window.LogConfig.loggers.orders // Order management window.LogConfig.loggers.users // User management window.LogConfig.loggers.audit // Audit logs window.LogConfig.loggers.dashboard // Dashboard window.LogConfig.loggers.imports // Import operations ``` ### Vendor Frontend ```javascript window.LogConfig.loggers.dashboard // Vendor dashboard window.LogConfig.loggers.products // Product management window.LogConfig.loggers.inventory // Inventory window.LogConfig.loggers.orders // Order management window.LogConfig.loggers.theme // Theme customization window.LogConfig.loggers.settings // Settings window.LogConfig.loggers.analytics // Analytics ``` ### Shop Frontend ```javascript window.LogConfig.loggers.catalog // Product browsing window.LogConfig.loggers.product // Product details window.LogConfig.loggers.search // Search window.LogConfig.loggers.cart // Shopping cart window.LogConfig.loggers.checkout // Checkout window.LogConfig.loggers.account // User account window.LogConfig.loggers.orders // Order history window.LogConfig.loggers.wishlist // Wishlist ``` --- ## ❌ Common Mistakes to Avoid ### 1. Old Way vs New Way ```javascript // ❌ OLD WAY - 15 lines of duplicate code const YOUR_PAGE_LOG_LEVEL = 3; const yourPageLog = { error: (...args) => YOUR_PAGE_LOG_LEVEL >= 1 && console.error('❌ [YOUR_PAGE ERROR]', ...args), warn: (...args) => YOUR_PAGE_LOG_LEVEL >= 2 && console.warn('⚠️ [YOUR_PAGE WARN]', ...args), info: (...args) => YOUR_PAGE_LOG_LEVEL >= 3 && console.info('ℹ️ [YOUR_PAGE INFO]', ...args), debug: (...args) => YOUR_PAGE_LOG_LEVEL >= 4 && console.log('🔍 [YOUR_PAGE DEBUG]', ...args) }; // ✅ NEW WAY - 1 line! const yourPageLog = window.LogConfig.loggers.yourPage; ``` ### 2. Missing Base Inheritance ```javascript // ❌ WRONG function myPage() { return { items: [], // Missing ...data() }; } // ✅ CORRECT function myPage() { return { ...data(), // Must be first! items: [], }; } ``` ### 3. Wrong API Client Name ```javascript // ❌ WRONG - Capital letters await ApiClient.get('/endpoint'); await API_CLIENT.get('/endpoint'); // ✅ CORRECT - lowercase await apiClient.get('/endpoint'); ``` ### 4. Missing Init Guard ```javascript // ❌ WRONG async init() { await this.loadData(); } // ✅ CORRECT async init() { if (window._myPageInitialized) return; window._myPageInitialized = true; await this.loadData(); } ``` ### 5. Missing currentPage ```javascript // ❌ WRONG return { ...data(), items: [], // Missing currentPage }; // ✅ CORRECT return { ...data(), currentPage: 'my-page', // Must set this! items: [], }; ``` --- ## 🔧 API Client Pattern ### GET Request ```javascript try { const response = await apiClient.get('/endpoint'); this.data = response; } catch (error) { console.error('Failed:', error); Utils.showToast('Failed to load', 'error'); } ``` ### POST Request ```javascript try { const response = await apiClient.post('/endpoint', { name: 'value', // ... data }); Utils.showToast('Created successfully', 'success'); } catch (error) { console.error('Failed:', error); Utils.showToast('Failed to create', 'error'); } ``` ### PUT Request ```javascript try { const response = await apiClient.put('/endpoint/123', { name: 'updated value' }); Utils.showToast('Updated successfully', 'success'); } catch (error) { console.error('Failed:', error); Utils.showToast('Failed to update', 'error'); } ``` ### DELETE Request ```javascript try { await apiClient.delete('/endpoint/123'); Utils.showToast('Deleted successfully', 'success'); await this.reloadData(); } catch (error) { console.error('Failed:', error); Utils.showToast('Failed to delete', 'error'); } ``` --- ## 🔧 Centralized Logging Patterns ### Basic Logging ```javascript const log = window.LogConfig.loggers.yourPage; log.info('Page loaded'); log.warn('Connection slow'); log.error('Failed to load data', error); log.debug('User data:', userData); ``` ### Grouped Logging ```javascript log.group('Loading Theme Data'); log.info('Fetching vendor...'); log.info('Fetching theme...'); log.info('Fetching presets...'); log.groupEnd(); ``` ### API Call Logging ```javascript const url = '/api/vendors'; // Before request window.LogConfig.logApiCall('GET', url, null, 'request'); // Make request const data = await apiClient.get(url); // After response window.LogConfig.logApiCall('GET', url, data, 'response'); ``` ### Error Logging ```javascript try { await saveTheme(); } catch (error) { window.LogConfig.logError(error, 'Save Theme'); } ``` ### Performance Logging ```javascript const start = performance.now(); await loadThemeData(); const duration = performance.now() - start; window.LogConfig.logPerformance('Load Theme Data', duration); ``` ### Table Logging ```javascript log.table([ { id: 1, name: 'Vendor A', status: 'active' }, { id: 2, name: 'Vendor B', status: 'inactive' } ]); ``` --- ## 📚 Benefits of Centralized Logging | Aspect | Old Way | New Way | |--------|---------|---------| | **Lines of code** | ~15 per file | 1 line per file | | **Consistency** | Varies by file | Unified across all frontends | | **Maintenance** | Update each file | Update one shared file | | **Features** | Basic logging | Advanced (groups, perf, API) | | **Environment** | Manual config | Auto-detected | | **Frontend aware** | No | Yes (admin/vendor/shop) | | **Log levels** | Per file | Per frontend + environment | --- ## 🎨 Common UI Patterns ### Loading State ```javascript async loadData() { this.loading = true; try { const data = await apiClient.get('/endpoint'); this.items = data; } finally { this.loading = false; } } ``` ### Refresh/Reload ```javascript async refresh() { console.info('Refreshing...'); await this.loadData(); Utils.showToast('Refreshed successfully', 'success'); } ``` --- ## 📚 Available Utilities ### From `init-alpine.js` (via `...data()`) - `this.dark` - Dark mode state - `this.toggleTheme()` - Toggle theme - `this.isSideMenuOpen` - Side menu state - `this.toggleSideMenu()` - Toggle side menu - `this.closeSideMenu()` - Close side menu - `this.isNotificationsMenuOpen` - Notifications menu state - `this.toggleNotificationsMenu()` - Toggle notifications - `this.closeNotificationsMenu()` - Close notifications - `this.isProfileMenuOpen` - Profile menu state - `this.toggleProfileMenu()` - Toggle profile menu - `this.closeProfileMenu()` - Close profile menu - `this.isPagesMenuOpen` - Pages menu state - `this.togglePagesMenu()` - Toggle pages menu ### From `Utils` (global) - `Utils.showToast(message, type, duration)` - Show toast notification - `Utils.formatDate(dateString)` - Format date for display - `Utils.confirm(message, title)` - Show confirmation dialog (if available) ### From `apiClient` (global) - `apiClient.get(url)` - GET request - `apiClient.post(url, data)` - POST request - `apiClient.put(url, data)` - PUT request - `apiClient.delete(url)` - DELETE request --- ## 🎨 Complete Example ```javascript // static/admin/js/vendor-theme.js // 1. Use centralized logger const themeLog = window.LogConfig.loggers.vendorTheme; // 2. Create component function adminVendorTheme() { return { ...data(), currentPage: 'vendor-theme', vendor: null, themeData: {}, loading: true, async init() { themeLog.info('Initializing vendor theme editor'); if (window._vendorThemeInitialized) { themeLog.warn('Already initialized, skipping...'); return; } window._vendorThemeInitialized = true; const startTime = performance.now(); try { themeLog.group('Loading theme data'); await Promise.all([ this.loadVendor(), this.loadTheme() ]); themeLog.groupEnd(); const duration = performance.now() - startTime; window.LogConfig.logPerformance('Theme Editor Init', duration); themeLog.info('Theme editor initialized successfully'); } catch (error) { window.LogConfig.logError(error, 'Theme Editor Init'); Utils.showToast('Failed to initialize', 'error'); } finally { this.loading = false; } }, async loadVendor() { const url = `/admin/vendors/${this.vendorCode}`; window.LogConfig.logApiCall('GET', url, null, 'request'); const response = await apiClient.get(url); this.vendor = response; window.LogConfig.logApiCall('GET', url, response, 'response'); themeLog.debug('Vendor loaded:', this.vendor); }, async saveTheme() { themeLog.info('Saving theme changes'); try { const url = `/admin/vendor-themes/${this.vendorCode}`; window.LogConfig.logApiCall('PUT', url, this.themeData, 'request'); const response = await apiClient.put(url, this.themeData); window.LogConfig.logApiCall('PUT', url, response, 'response'); themeLog.info('Theme saved successfully'); Utils.showToast('Theme saved', 'success'); } catch (error) { window.LogConfig.logError(error, 'Save Theme'); Utils.showToast('Failed to save theme', 'error'); } } }; } themeLog.info('Vendor theme editor module loaded'); ``` --- ## 🚀 Quick Start Template Files Copy these to create a new page: 1. **Copy base file:** `dashboard.js` → rename to `your-page.js` 2. **Update logger:** ```javascript // Change from: const dashLog = window.LogConfig.loggers.dashboard; // To: const yourPageLog = window.LogConfig.loggers.yourPage; // Or create custom: const yourPageLog = window.LogConfig.createLogger('YOUR-PAGE'); ``` 3. **Replace function name:** `adminDashboard()` → `yourPageComponent()` 4. **Update init flag:** `_dashboardInitialized` → `_yourPageInitialized` 5. **Update page identifier:** `currentPage: 'dashboard'` → `currentPage: 'your-page'` 6. **Replace data loading logic** with your API endpoints 7. **Update HTML template** to use your function name: ```jinja2 {% block alpine_data %}yourPageComponent(){% endblock %} ``` 8. **Load your script** in the template: ```jinja2 {% block extra_scripts %} {% endblock %} ``` Done! ✅