# Alpine.js Page Template - Quick Reference ## ✅ Correct Page Structure ```javascript // static/admin/js/your-page.js // 1. Setup logging (optional but recommended) 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) }; // 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 = Date.now(); // ✅ CRITICAL: Use lowercase apiClient const response = await apiClient.get('/your/endpoint'); const duration = Date.now() - startTime; this.items = response.items || []; yourPageLog.info(`Data loaded in ${duration}ms`, { count: this.items.length }); } catch (error) { yourPageLog.error('Failed to load data:', error); 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 - [ ] ✅ Logging setup (optional) - [ ] ✅ 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 your custom logger (not `Logger`) - [ ] ✅ Performance tracking with `Date.now()` (optional) - [ ] ✅ Module loaded log at end --- ## ❌ Common Mistakes to Avoid ### 1. Missing Base Inheritance ```javascript // ❌ WRONG function myPage() { return { items: [], // Missing ...data() }; } // ✅ CORRECT function myPage() { return { ...data(), // Must be first! items: [], }; } ``` ### 2. Wrong API Client Name ```javascript // ❌ WRONG - Capital letters await ApiClient.get('/endpoint'); await API_CLIENT.get('/endpoint'); // ✅ CORRECT - lowercase await apiClient.get('/endpoint'); ``` ### 3. Missing Init Guard ```javascript // ❌ WRONG async init() { await this.loadData(); } // ✅ CORRECT async init() { if (window._myPageInitialized) return; window._myPageInitialized = true; await this.loadData(); } ``` ### 4. 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'); } ``` --- ## 🎨 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; } } ``` ### Error Handling ```javascript async loadData() { this.loading = true; this.error = null; try { const data = await apiClient.get('/endpoint'); this.items = data; } catch (error) { this.error = error.message; Utils.showToast('Failed to load', 'error'); } 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 --- ## 🚀 Quick Start Template Files Copy these to create a new page: 1. Copy `dashboard.js` → rename to `your-page.js` 2. Replace function name: `adminDashboard()` → `yourPageComponent()` 3. Update logging prefix: `dashLog` → `yourPageLog` 4. Update init flag: `_dashboardInitialized` → `_yourPageInitialized` 5. Update `currentPage`: `'dashboard'` → `'your-page'` 6. Replace data loading logic with your endpoints 7. Update HTML template to use your function name Done! ✅