225 lines
7.6 KiB
JavaScript
225 lines
7.6 KiB
JavaScript
(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();
|
|
});
|
|
})();
|