// static/admin/js/vendor-theme.js /** * Vendor Theme Management Component * Follows the established Alpine.js pattern from FRONTEND_ALPINE_PAGE_TEMPLATE.md */ const THEME_LOG_LEVEL = 3; const themeLog = { error: (...args) => THEME_LOG_LEVEL >= 1 && console.error('❌ [THEME ERROR]', ...args), warn: (...args) => THEME_LOG_LEVEL >= 2 && console.warn('⚠️ [THEME WARN]', ...args), info: (...args) => THEME_LOG_LEVEL >= 3 && console.info('ℹ️ [THEME INFO]', ...args), debug: (...args) => THEME_LOG_LEVEL >= 4 && console.log('🔍 [THEME DEBUG]', ...args) }; // Theme presets const THEME_PRESETS = { modern: { colors: { primary: "#6366f1", secondary: "#8b5cf6", accent: "#ec4899" }, fonts: { heading: "Inter, sans-serif", body: "Inter, sans-serif" }, layout: { style: "grid", header: "fixed" } }, classic: { colors: { primary: "#1e40af", secondary: "#7c3aed", accent: "#dc2626" }, fonts: { heading: "Georgia, serif", body: "Arial, sans-serif" }, layout: { style: "list", header: "static" } }, minimal: { colors: { primary: "#000000", secondary: "#404040", accent: "#666666" }, fonts: { heading: "Helvetica, sans-serif", body: "Helvetica, sans-serif" }, layout: { style: "grid", header: "transparent" } }, vibrant: { colors: { primary: "#f59e0b", secondary: "#ef4444", accent: "#8b5cf6" }, fonts: { heading: "Poppins, sans-serif", body: "Open Sans, sans-serif" }, layout: { style: "masonry", header: "fixed" } } }; function vendorThemeData() { return { // ✅ CRITICAL: Inherit base layout functionality ...data(), // ✅ CRITICAL: Set page identifier currentPage: 'vendor-theme', // Page state loading: false, saving: false, vendor: null, vendorCode: window.location.pathname.split('/')[3], // Extract from /admin/vendors/{code}/theme // Theme data themeData: { colors: { primary: "#6366f1", secondary: "#8b5cf6", accent: "#ec4899" }, fonts: { heading: "Inter, sans-serif", body: "Inter, sans-serif" }, layout: { style: "grid", header: "fixed" }, custom_css: "" }, originalTheme: null, // For detecting changes // ✅ CRITICAL: Proper initialization with guard async init() { themeLog.info('=== VENDOR THEME PAGE INITIALIZING ==='); // Prevent multiple initializations if (window._vendorThemeInitialized) { themeLog.warn('Page already initialized, skipping...'); return; } window._vendorThemeInitialized = true; // Load data await this.loadVendor(); await this.loadTheme(); themeLog.info('=== VENDOR THEME PAGE INITIALIZATION COMPLETE ==='); }, // Load vendor info async loadVendor() { themeLog.info('Loading vendor:', this.vendorCode); try { // ✅ CRITICAL: Use lowercase apiClient const response = await apiClient.get(`/api/v1/admin/vendors/${this.vendorCode}`); this.vendor = response; themeLog.info('Vendor loaded:', this.vendor.name); } catch (error) { themeLog.error('Failed to load vendor:', error); Utils.showToast('Failed to load vendor', 'error'); } }, // Load theme configuration async loadTheme() { themeLog.info('Loading theme...'); this.loading = true; try { const startTime = Date.now(); // Get vendor's theme config from vendor object if (this.vendor && this.vendor.theme_config) { this.themeData = { colors: this.vendor.theme_config.colors || this.themeData.colors, fonts: this.vendor.theme_config.fonts || this.themeData.fonts, layout: this.vendor.theme_config.layout || this.themeData.layout, custom_css: this.vendor.theme_config.custom_css || "" }; } else { themeLog.info('No theme config found, using defaults'); } // Store original for change detection this.originalTheme = JSON.parse(JSON.stringify(this.themeData)); const duration = Date.now() - startTime; themeLog.info(`Theme loaded in ${duration}ms`, this.themeData); } catch (error) { themeLog.error('Failed to load theme:', error); Utils.showToast('Failed to load theme', 'error'); } finally { this.loading = false; } }, // Save theme configuration async saveTheme() { themeLog.info('Saving theme...'); this.saving = true; try { const startTime = Date.now(); // Update vendor with new theme_config const updateData = { theme_config: this.themeData }; const response = await apiClient.put( `/api/v1/admin/vendors/${this.vendorCode}`, updateData ); const duration = Date.now() - startTime; themeLog.info(`Theme saved in ${duration}ms`); // Update vendor data this.vendor = response; this.originalTheme = JSON.parse(JSON.stringify(this.themeData)); Utils.showToast('Theme saved successfully', 'success'); } catch (error) { themeLog.error('Failed to save theme:', error); Utils.showToast('Failed to save theme', 'error'); } finally { this.saving = false; } }, // Apply preset theme applyPreset(presetName) { themeLog.info('Applying preset:', presetName); if (!THEME_PRESETS[presetName]) { themeLog.error('Unknown preset:', presetName); return; } const preset = THEME_PRESETS[presetName]; // Apply preset values this.themeData.colors = { ...preset.colors }; this.themeData.fonts = { ...preset.fonts }; this.themeData.layout = { ...preset.layout }; Utils.showToast(`Applied ${presetName} theme preset`, 'success'); }, // Reset to default theme resetToDefault() { themeLog.info('Resetting to default theme'); // Confirm with user if (!confirm('Are you sure you want to reset to the default theme? This will discard all customizations.')) { return; } this.themeData = { colors: { primary: "#6366f1", secondary: "#8b5cf6", accent: "#ec4899" }, fonts: { heading: "Inter, sans-serif", body: "Inter, sans-serif" }, layout: { style: "grid", header: "fixed" }, custom_css: "" }; Utils.showToast('Theme reset to default', 'info'); }, // Check if theme has unsaved changes hasChanges() { if (!this.originalTheme) return false; return JSON.stringify(this.themeData) !== JSON.stringify(this.originalTheme); }, // Format date helper formatDate(dateString) { if (!dateString) return '-'; return Utils.formatDate(dateString); } }; } themeLog.info('Vendor theme module loaded');