Files
orion/static/admin/js/vendor-theme.js

278 lines
8.4 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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');