Files
orion/docs/__REVAMPING/FRONTEND/FRONTEND_ADMIN_ARCHITECTURE_OVERVIEW.txt

240 lines
16 KiB
Plaintext

╔══════════════════════════════════════════════════════════════════╗
║ 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 %} │ │
│ <div x-show="loading">Loading...</div> │ │
│ <div x-show="!loading"> │ │
│ <p x-text="vendor.name"></p> ← Reactive binding │ │
│ </div> │ │
│ {% endblock %} │ │
│ │ │
│ {% block extra_scripts %} │ │
│ <script src="...vendor-edit.js"></script> ──────────┐ │ │
│ {% endblock %} │ │ │
└───────────────────────────────────────────────────────│──│─┘
│ │
│ │
┌───────────────────────────────────────────────────────│──│─┐
│ vendor-edit.js │ │ │
├───────────────────────────────────────────────────────│──│─┤
│ function adminVendorEdit() { ◄────────────────────────┘ │ │
│ return { │ │
│ ...data(), │ │
│ vendor: null, ← Bound to x-text="vendor.name"│ │
│ loading: false, ← Bound to x-show="loading" │ │
│ async init() {...} │ │
│ }; │ │
│ } │ │
└──────────────────────────────────────────────────────────┘
🔄 PAGE LIFECYCLE
═════════════════════════════════════════════════════════════════
1. Page Load
2. Alpine.js Initialization
3. x-data="yourPageComponent()" called
4. Component function executes
5. ...data() spreads base state
6. Page-specific state added
7. init() method runs
8. Check initialization guard
9. Load data from API
10. Reactive bindings update UI
✅ CHECKLIST FOR NEW PAGES
═════════════════════════════════════════════════════════════════
JavaScript File:
□ Create logger object (pageLog)
□ Define component function
□ Add ...data() at start of return object
□ Set currentPage: 'page-name'
□ Add initialization guard
□ Use lowercase apiClient for API calls
□ Add performance tracking (optional)
□ Use page-specific logger
HTML Template:
□ Extend admin/base.html
□ Set alpine_data block with function name
□ Add x-show for loading states
□ Add x-text for reactive data
□ Load JavaScript file in extra_scripts block
══════════════════════════════════════════════════════════════════
Your dashboard.js is perfect!
Use it as the template for all new pages.
══════════════════════════════════════════════════════════════════