╔══════════════════════════════════════════════════════════════════╗ ║ ALPINE.JS PAGE ARCHITECTURE OVERVIEW ║ ╚══════════════════════════════════════════════════════════════════╝ 📂 FILE STRUCTURE ═════════════════════════════════════════════════════════════════ static/admin/js/ ├── init-alpine.js ............. Base Alpine.js data & theme ├── dashboard.js ............... Dashboard page (✅ WORKING) ├── vendors.js ................. Vendor list page (✅ FIXED) └── vendor-edit.js ............. Vendor edit page (✅ FIXED) 🔄 HOW PAGES INHERIT BASE FUNCTIONALITY ═════════════════════════════════════════════════════════════════ ┌─────────────────────────────────────────────────────────────┐ │ init-alpine.js │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ function data() { │ │ │ │ return { │ │ │ │ dark: ..., ← Theme state │ │ │ │ toggleTheme() {...}, ← Theme toggle │ │ │ │ isSideMenuOpen: false, ← Side menu state │ │ │ │ toggleSideMenu() {...}, ← Side menu toggle │ │ │ │ isProfileMenuOpen: false, ← Profile menu state │ │ │ │ toggleProfileMenu() {...}, ← Profile menu toggle │ │ │ │ currentPage: '' ← Page identifier │ │ │ │ }; │ │ │ │ } │ │ │ └─────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ │ │ Uses ...data() spread operator │ ┌─────────────────────┼─────────────────────┐ │ │ │ ▼ ▼ ▼ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ dashboard.js │ │ vendors.js │ │vendor-edit.js │ ├───────────────┤ ├───────────────┤ ├───────────────┤ │function admin │ │function admin │ │function admin │ │Dashboard() { │ │Vendors() { │ │VendorEdit() { │ │ return { │ │ return { │ │ return { │ │ ...data(), │ │ ...data(), │ │ ...data(), │ │ │ │ │ │ │ │ │ │ │ └──────────┼───┼────┘ │ │ │ │ │ Inherits │ │ Inherits │ │ Inherits │ │ all base │ │ all base │ │ all base │ │ functions │ │ functions │ │ functions │ │ │ │ │ │ │ │ // Page │ │ // Page │ │ // Page │ │ specific │ │ specific │ │ specific │ │ state │ │ state │ │ state │ │ }; │ │ }; │ │ }; │ │} │ │} │ │} │ └───────────────┘ └───────────────┘ └───────────────┘ ⚙️ API CLIENT USAGE PATTERN ═════════════════════════════════════════════════════════════════ All pages must use lowercase 'apiClient': ┌─────────────────────────────────────────────────────────────┐ │ ✅ CORRECT ❌ WRONG │ ├─────────────────────────────────────────────────────────────┤ │ apiClient.get(url) │ ApiClient.get(url) │ │ apiClient.post(url, data) │ API_CLIENT.post(url, data) │ │ apiClient.put(url, data) │ Apiclient.put(url, data) │ │ apiClient.delete(url) │ APIClient.delete(url) │ └─────────────────────────────────────────────────────────────┘ 🪵 LOGGING PATTERN ═════════════════════════════════════════════════════════════════ Each page has its own logger object: ┌─────────────────────────────────────────────────────────────┐ │ dashboard.js vendors.js vendor-edit.js │ ├─────────────────────────────────────────────────────────────┤ │ const dashLog = { const vendorsLog = const editLog = { │ │ error: (...) => error: (...) => error: (...) => │ │ warn: (...) => warn: (...) => warn: (...) => │ │ info: (...) => info: (...) => info: (...) => │ │ debug: (...) => debug: (...) => debug: (...) => │ │ }; }; }; │ │ │ │ dashLog.info('...') vendorsLog.info() editLog.info() │ └─────────────────────────────────────────────────────────────┘ 🔒 INITIALIZATION GUARD PATTERN ═════════════════════════════════════════════════════════════════ Prevents multiple Alpine.js initializations: ┌─────────────────────────────────────────────────────────────┐ │ async init() { │ │ // Check if already initialized │ │ if (window._yourPageInitialized) { │ │ log.warn('Already initialized, skipping...'); │ │ return; // Exit early │ │ } │ │ window._yourPageInitialized = true; // Set flag │ │ │ │ // Continue with initialization │ │ await this.loadData(); │ │ } │ └─────────────────────────────────────────────────────────────┘ 📊 STATE MANAGEMENT ═════════════════════════════════════════════════════════════════ Alpine.js reactive state structure: ┌─────────────────────────────────────────────────────────────┐ │ function yourPage() { │ │ return { │ │ ...data(), ← Base UI state (inherited) │ │ currentPage: 'name', ← Page identifier │ │ │ │ // Loading states │ │ loading: false, ← General loading │ │ loadingItem: false, ← Specific item loading │ │ saving: false, ← Save operation state │ │ │ │ // Data │ │ items: [], ← List data │ │ item: null, ← Single item │ │ stats: {}, ← Statistics │ │ │ │ // Error handling │ │ error: null, ← Error message │ │ errors: {}, ← Field-specific errors │ │ │ │ // Methods │ │ async init() {...}, ← Initialization │ │ async loadData() {...}, ← Data loading │ │ async save() {...}, ← Save operation │ │ formatDate(d) {...} ← Helper functions │ │ }; │ │ } │ └─────────────────────────────────────────────────────────────┘ 🎯 TEMPLATE BINDING ═════════════════════════════════════════════════════════════════ HTML template connects to Alpine.js component: ┌─────────────────────────────────────────────────────────────┐ │ vendor-edit.html │ ├─────────────────────────────────────────────────────────────┤ │ {% extends "admin/base.html" %} │ │ │ │ {# This binds to the JavaScript function #} │ │ {% block alpine_data %}adminVendorEdit(){% endblock %} │ │ └──────────────────┐ │ │ {% block content %} │ │ │