init projectmycelium
This commit is contained in:
224
src/static/js/dashboard_layout.js
Normal file
224
src/static/js/dashboard_layout.js
Normal file
@@ -0,0 +1,224 @@
|
||||
(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();
|
||||
});
|
||||
})();
|
||||
Reference in New Issue
Block a user