// static/admin/js/components.js // ✅ Use centralized logger - ONE LINE! // Create custom logger for components page const componentsLog = window.LogConfig.createLogger('COMPONENTS'); /** * Components Library Alpine.js Component * UI components reference with live examples */ function adminComponents() { return { // ✅ CRITICAL: Inherit base layout functionality ...data(), // ✅ CRITICAL: Set page identifier currentPage: 'components', // Active section for navigation activeSection: 'forms', // Component sections sections: [ { id: 'ecommerce', name: 'E-commerce', icon: 'shopping-cart' }, { id: 'macros', name: 'Macros', icon: 'template' }, { id: 'pagination', name: 'Pagination', icon: 'dots-horizontal' }, { id: 'tabs', name: 'Tabs', icon: 'view-boards' }, { id: 'forms', name: 'Forms', icon: 'clipboard-list' }, { id: 'buttons', name: 'Buttons', icon: 'cursor-click' }, { id: 'cards', name: 'Cards', icon: 'collection' }, { id: 'badges', name: 'Badges', icon: 'tag' }, { id: 'tables', name: 'Tables', icon: 'table' }, { id: 'modals', name: 'Modals', icon: 'view-grid-add' }, { id: 'alerts', name: 'Alerts', icon: 'exclamation' }, { id: 'charts', name: 'Charts', icon: 'chart-pie' } ], // Tab demo state demoActiveTab: 'tab1', // Number stepper demo state demoQuantitySm: 3, demoQuantityMd: 5, demoQuantityLg: 500, // E-commerce demo state demoProducts: [ { id: 1, name: 'Premium Wireless Headphones', url: '#', image_url: 'https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=300&h=300&fit=crop', price: 149.99, sale_price: 119.99, rating: 4.5, review_count: 127, stock: 15, is_new: false, in_wishlist: false }, { id: 2, name: 'Smart Watch Pro', url: '#', image_url: 'https://images.unsplash.com/photo-1523275335684-37898b6baf30?w=300&h=300&fit=crop', price: 299.99, sale_price: null, rating: 4.8, review_count: 89, stock: 8, is_new: true, in_wishlist: true }, { id: 3, name: 'Portable Bluetooth Speaker', url: '#', image_url: 'https://images.unsplash.com/photo-1608043152269-423dbba4e7e1?w=300&h=300&fit=crop', price: 79.99, sale_price: null, rating: 4.2, review_count: 45, stock: 0, is_new: false, in_wishlist: false } ], demoCart: { items: [ { id: 1, product_id: 1, name: 'Premium Wireless Headphones', url: '#', image_url: 'https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=300&h=300&fit=crop', price: 119.99, quantity: 1, variant_name: 'Black', max_quantity: 15 }, { id: 2, product_id: 2, name: 'Smart Watch Pro', url: '#', image_url: 'https://images.unsplash.com/photo-1523275335684-37898b6baf30?w=300&h=300&fit=crop', price: 299.99, quantity: 2, variant_name: 'Silver', max_quantity: 8 } ], item_count: 3, subtotal: 719.97, discount: 0, shipping: 0, tax: 0, total: 719.97, promo_code: null }, showDemoCart: false, demoQuantity: 1, addingToCart: false, addedToCart: false, // E-commerce demo methods demoAddToCart(product) { this.addingToCart = true; setTimeout(() => { this.addingToCart = false; this.addedToCart = true; setTimeout(() => { this.addedToCart = false; }, 2000); if (typeof Utils !== 'undefined' && Utils.showToast) { Utils.showToast('Added to cart!', 'success'); } }, 800); }, demoToggleWishlist(product) { product.in_wishlist = !product.in_wishlist; const action = product.in_wishlist ? 'Added to' : 'Removed from'; if (typeof Utils !== 'undefined' && Utils.showToast) { Utils.showToast(`${action} wishlist`, 'success'); } }, demoRemoveFromCart(itemId) { this.demoCart.items = this.demoCart.items.filter(i => i.id !== itemId); this.demoCart.item_count = this.demoCart.items.reduce((sum, i) => sum + i.quantity, 0); this.demoCart.subtotal = this.demoCart.items.reduce((sum, i) => sum + (i.price * i.quantity), 0); this.demoCart.total = this.demoCart.subtotal; }, // Product Detail Demo (Priority 3) demoProductDetail: { id: 1, name: 'Premium Wireless Headphones', sku: 'WH-1000XM5', price: 349.99, sale_price: 279.99, rating: 4.7, review_count: 1247, stock: 23, is_new: true, short_description: 'Industry-leading noise cancellation with exceptional sound quality. 30-hour battery life.', description: '

Experience the next level of silence with our Premium Wireless Headphones. Industry-leading noise cancellation technology lets you focus on what matters most.

With up to 30 hours of battery life, you can enjoy your favorite music all day long. The soft, pressure-relieving ear pads provide all-day comfort.

', features: [ 'Industry-leading noise cancellation', '30-hour battery life', 'Hi-Res Audio certified', 'Multipoint connection', 'Speak-to-chat technology' ], specifications: [ { name: 'Driver Size', value: '40mm' }, { name: 'Frequency Response', value: '4Hz - 40,000Hz' }, { name: 'Battery Life', value: '30 hours' }, { name: 'Charging Time', value: '3 hours' }, { name: 'Weight', value: '250g' }, { name: 'Connectivity', value: 'Bluetooth 5.2, 3.5mm' } ], images: [ { id: 1, url: 'https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=800&h=800&fit=crop', alt: 'Headphones front view' }, { id: 2, url: 'https://images.unsplash.com/photo-1484704849700-f032a568e944?w=800&h=800&fit=crop', alt: 'Headphones side view' }, { id: 3, url: 'https://images.unsplash.com/photo-1583394838336-acd977736f90?w=800&h=800&fit=crop', alt: 'Headphones with case' }, { id: 4, url: 'https://images.unsplash.com/photo-1546435770-a3e426bf472b?w=800&h=800&fit=crop', alt: 'Person wearing headphones' } ], sizes: [ { id: 1, name: 'Standard', value: 'standard', stock: 23 }, { id: 2, name: 'Compact', value: 'compact', stock: 8 } ], colors: [ { id: 1, name: 'Black', value: 'black', color_hex: '#1a1a1a', stock: 15 }, { id: 2, name: 'Silver', value: 'silver', color_hex: '#C0C0C0', stock: 8 }, { id: 3, name: 'Midnight Blue', value: 'blue', color_hex: '#191970', stock: 0 } ], reviews: [ { id: 1, author_name: 'John D.', rating: 5, title: 'Best headphones I\'ve ever owned', content: 'The noise cancellation is incredible. I use these for work calls and they block out everything. Battery life is amazing too.', verified: true, created_at: '2025-01-15', helpful_count: 42 }, { id: 2, author_name: 'Sarah M.', rating: 4, title: 'Great sound, slightly tight fit', content: 'Sound quality is phenomenal. My only complaint is they feel a bit tight after a few hours. Otherwise perfect.', verified: true, created_at: '2025-01-10', helpful_count: 18 } ], rating_distribution: { 5: 68, 4: 22, 3: 6, 2: 3, 1: 1 }, category: { name: 'Headphones', slug: 'headphones', url: '/category/headphones' }, vendor: { name: 'AudioTech', slug: 'audiotech', url: '/vendor/audiotech' } }, selectedImage: 0, selectedSize: null, selectedColor: null, activeProductTab: 'description', // Sample form data for examples exampleForm: { textInput: 'Sample text', email: 'user@example.com', textarea: 'Sample description text...', select: 'option1', checkbox: true, radio: 'option1', disabled: 'Read-only value' }, // Sample errors for validation examples exampleErrors: { email: 'Please enter a valid email address', required: 'This field is required' }, // Modal state variables for examples showExampleModal: false, showFormModal: false, // ✅ CRITICAL: Proper initialization with guard async init() { componentsLog.info('=== COMPONENTS PAGE INITIALIZING ==='); // Prevent multiple initializations if (window._componentsInitialized) { componentsLog.warn('Components page already initialized, skipping...'); return; } window._componentsInitialized = true; // Set active section from URL hash if present this.setActiveSectionFromHash(); // Listen for hash changes window.addEventListener('hashchange', () => { this.setActiveSectionFromHash(); }); // Initialize charts after DOM is ready this.$nextTick(() => { this.initializeCharts(); }); componentsLog.info('=== COMPONENTS PAGE INITIALIZATION COMPLETE ==='); }, /** * Set active section from URL hash */ setActiveSectionFromHash() { const hash = window.location.hash.replace('#', ''); if (hash && this.sections.find(s => s.id === hash)) { this.activeSection = hash; componentsLog.debug('Set active section from hash:', hash); } }, /** * Navigate to section */ goToSection(sectionId) { componentsLog.info('Navigating to section:', sectionId); this.activeSection = sectionId; window.location.hash = sectionId; // Smooth scroll to section const element = document.getElementById(sectionId); if (element) { element.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }, /** * Check if section is active */ isSectionActive(sectionId) { return this.activeSection === sectionId; }, /** * Copy code to clipboard */ async copyCode(code) { try { await navigator.clipboard.writeText(code); // Use the global Utils.showToast function if (typeof Utils !== 'undefined' && Utils.showToast) { Utils.showToast('Code copied to clipboard!', 'success'); } else { componentsLog.warn('Utils.showToast not available'); } componentsLog.debug('Code copied to clipboard'); } catch (error) { window.LogConfig.logError(error, 'Copy Code'); if (typeof Utils !== 'undefined' && Utils.showToast) { Utils.showToast('Failed to copy code', 'error'); } } }, /** * Show toast example */ showToastExample(type) { const messages = { success: 'Operation completed successfully!', error: 'An error occurred!', warning: 'Please review your input.', info: 'Here is some information.' }; componentsLog.info('Showing toast example:', type); if (typeof Utils !== 'undefined' && Utils.showToast) { Utils.showToast(messages[type] || messages.info, type); } else { componentsLog.error('Utils.showToast not available'); alert(messages[type] || messages.info); // Fallback to alert } }, /** * Initialize Chart.js charts */ initializeCharts() { try { // Check if Chart.js is loaded if (typeof Chart === 'undefined') { componentsLog.warn('Chart.js not loaded, skipping chart initialization'); return; } componentsLog.info('Initializing charts...'); componentsLog.time('Chart Initialization'); // Pie Chart const pieCanvas = document.getElementById('examplePieChart'); if (pieCanvas) { const pieConfig = { type: 'doughnut', data: { datasets: [{ data: [33, 33, 33], backgroundColor: ['#0694a2', '#7e3af2', '#1c64f2'], label: 'Dataset 1', }], labels: ['Shoes', 'Shirts', 'Bags'], }, options: { responsive: true, cutoutPercentage: 80, legend: { display: false, }, }, }; new Chart(pieCanvas, pieConfig); componentsLog.debug('Pie chart initialized'); } // Line Chart const lineCanvas = document.getElementById('exampleLineChart'); if (lineCanvas) { const lineConfig = { type: 'line', data: { labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'], datasets: [{ label: 'Organic', backgroundColor: '#0694a2', borderColor: '#0694a2', data: [43, 48, 40, 54, 67, 73, 70], fill: false, }, { label: 'Paid', fill: false, backgroundColor: '#7e3af2', borderColor: '#7e3af2', data: [24, 50, 64, 74, 52, 51, 65], }], }, options: { responsive: true, legend: { display: false, }, tooltips: { mode: 'index', intersect: false, }, hover: { mode: 'nearest', intersect: true, }, scales: { x: { display: true, scaleLabel: { display: true, labelString: 'Month', }, }, y: { display: true, scaleLabel: { display: true, labelString: 'Value', }, }, }, }, }; new Chart(lineCanvas, lineConfig); componentsLog.debug('Line chart initialized'); } // Bar Chart const barCanvas = document.getElementById('exampleBarChart'); if (barCanvas) { const barConfig = { type: 'bar', data: { labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'], datasets: [{ label: 'Shoes', backgroundColor: '#0694a2', borderColor: '#0694a2', borderWidth: 1, data: [43, 48, 40, 54, 67, 73, 70], }, { label: 'Bags', backgroundColor: '#7e3af2', borderColor: '#7e3af2', borderWidth: 1, data: [24, 50, 64, 74, 52, 51, 65], }], }, options: { responsive: true, legend: { display: false, }, }, }; new Chart(barCanvas, barConfig); componentsLog.debug('Bar chart initialized'); } componentsLog.timeEnd('Chart Initialization'); componentsLog.info('All charts initialized successfully'); } catch (error) { window.LogConfig.logError(error, 'Initialize Charts'); } } }; } componentsLog.info('Components module loaded');