(function () { 'use strict'; function onReady(fn) { if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', fn); else fn(); } function setupSidebar() { const sidebarToggleBtn = document.getElementById('sidebarToggleBtn'); const sidebar = document.getElementById('sidebar'); const sidebarBackdrop = document.getElementById('sidebarBackdrop'); if (!sidebarToggleBtn || !sidebar || !sidebarBackdrop) return; // Ensure clean state on page load sidebar.classList.remove('show'); sidebarBackdrop.classList.remove('show'); sidebarToggleBtn.setAttribute('aria-expanded', 'false'); // Toggle sidebar visibility sidebarToggleBtn.addEventListener('click', function (event) { event.stopPropagation(); event.preventDefault(); // Toggle visibility sidebar.classList.toggle('show'); sidebarBackdrop.classList.toggle('show'); // Set aria-expanded for accessibility const isExpanded = sidebar.classList.contains('show'); sidebarToggleBtn.setAttribute('aria-expanded', String(isExpanded)); }); // Close sidebar when clicking on backdrop sidebarBackdrop.addEventListener('click', function (event) { event.stopPropagation(); sidebar.classList.remove('show'); sidebarBackdrop.classList.remove('show'); sidebarToggleBtn.setAttribute('aria-expanded', 'false'); }); // Close sidebar when clicking on any link inside it const sidebarLinks = sidebar.querySelectorAll('a.nav-link'); sidebarLinks.forEach(link => { link.addEventListener('click', function () { // Let the link work, then close setTimeout(function () { sidebar.classList.remove('show'); sidebarBackdrop.classList.remove('show'); sidebarToggleBtn.setAttribute('aria-expanded', 'false'); }, 100); }); }); // Ensure links are clickable sidebar.addEventListener('click', function (event) { event.stopPropagation(); }); } function initializeCartIntegration() { if (typeof window.updateCartCount !== 'function') { // define if missing window.updateCartCount = updateCartCount; } // initial updateCartCount(); // Update cart count every 30 seconds setInterval(updateCartCount, 30000); // Listen for cart updates from other tabs/windows window.addEventListener('storage', function (e) { if (e.key === 'cart_items') { updateCartCount(); } }); // Listen for custom cart update events window.addEventListener('cartUpdated', function () { updateCartCount(); }); } async function updateCartCount() { try { const cartData = await window.apiJson('/api/cart', { cache: 'no-store' }) || {}; const cartCount = parseInt(cartData.item_count) || 0; // Update sidebar cart counter const cartBadge = document.getElementById('cartItemCount'); if (cartBadge) { if (cartCount > 0) { cartBadge.textContent = String(cartCount); cartBadge.style.display = 'flex'; } else { cartBadge.style.display = 'none'; } } // Update main navbar cart counter (from base.html) const navbarCartCount = document.querySelector('.cart-count'); const navbarCartItem = document.getElementById('cartNavItem'); if (navbarCartCount && navbarCartItem) { if (cartCount > 0) { navbarCartCount.textContent = String(cartCount); navbarCartCount.style.display = 'inline'; navbarCartItem.style.display = 'block'; } else { navbarCartCount.style.display = 'none'; navbarCartItem.style.display = 'none'; } } } catch (error) { // Hide counts on error const navbarCartCount = document.querySelector('.cart-count'); const navbarCartItem = document.getElementById('cartNavItem'); if (navbarCartCount && navbarCartItem) { navbarCartCount.style.display = 'none'; navbarCartItem.style.display = 'none'; } // Keep console error minimal // console.error('Error updating dashboard cart count:', error); } } // Expose minimal cart helpers used across dashboard (legacy localStorage-based) window.addToCart = function (serviceId, serviceName, price, specs) { try { const cartItems = JSON.parse(localStorage.getItem('cart_items') || '[]'); const existingItem = cartItems.find(item => item.service_id === serviceId); if (existingItem) { window.showToast('Item already in cart', 'info'); return false; } const newItem = { id: 'cart_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9), service_id: serviceId, service_name: serviceName, price_tfc: price, specs: specs, added_at: new Date().toISOString() }; cartItems.push(newItem); localStorage.setItem('cart_items', JSON.stringify(cartItems)); updateCartCount(); if (typeof window.emitCartUpdated === 'function') { window.emitCartUpdated(); } window.showToast('Added to cart successfully', 'success'); return true; } catch (error) { window.showToast('Failed to add to cart', 'error'); return false; } }; window.removeFromCart = function (itemId) { try { const cartItems = JSON.parse(localStorage.getItem('cart_items') || '[]'); const updatedItems = cartItems.filter(item => item.id !== itemId); localStorage.setItem('cart_items', JSON.stringify(updatedItems)); updateCartCount(); if (typeof window.emitCartUpdated === 'function') { window.emitCartUpdated(); } window.showToast('Removed from cart', 'success'); return true; } catch (error) { window.showToast('Failed to remove from cart', 'error'); return false; } }; window.getCartItems = function () { try { return JSON.parse(localStorage.getItem('cart_items') || '[]'); } catch (error) { return []; } }; window.clearCart = function () { try { localStorage.removeItem('cart_items'); updateCartCount(); if (typeof window.emitCartUpdated === 'function') { window.emitCartUpdated(); } window.showToast('Cart cleared', 'success'); return true; } catch (error) { window.showToast('Failed to clear cart', 'error'); return false; } }; // Toast helper window.showToast = function (message, type = 'info') { let toastContainer = document.getElementById('toastContainer'); if (!toastContainer) { toastContainer = document.createElement('div'); toastContainer.id = 'toastContainer'; toastContainer.style.cssText = 'position: fixed; top: 20px; right: 20px; z-index: 9999; max-width: 300px;'; document.body.appendChild(toastContainer); } const toast = document.createElement('div'); const bgColor = type === 'success' ? '#28a745' : type === 'error' ? '#dc3545' : '#007bff'; toast.style.cssText = 'background-color: ' + bgColor + '; color: white; padding: 12px 16px; border-radius: 6px; margin-bottom: 10px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); opacity: 0; transform: translateX(100%); transition: all 0.3s ease;'; toast.textContent = message; toastContainer.appendChild(toast); setTimeout(function () { toast.style.opacity = '1'; toast.style.transform = 'translateX(0)'; }, 100); setTimeout(function () { toast.style.opacity = '0'; toast.style.transform = 'translateX(100%)'; setTimeout(function () { if (toast.parentNode) toast.parentNode.removeChild(toast); }, 300); }, 3000); }; onReady(function () { setupSidebar(); initializeCartIntegration(); }); })();