init projectmycelium

This commit is contained in:
mik-tf
2025-09-01 21:37:01 -04:00
commit b41efb0e99
319 changed files with 128160 additions and 0 deletions

View 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();
});
})();