/* ============================================================ UI HELPER FUNCTIONS ============================================================ */ // TOAST NOTIFICATIONS function showToast(message, type = 'info', duration = CONFIG.TOAST_TIMEOUT) { let toast = document.getElementById('app-toast'); if (!toast) { toast = document.createElement('div'); toast.id = 'app-toast'; toast.style.cssText = ` position: fixed; bottom: 80px; left: 50%; transform: translateX(-50%); background: var(--color-ink); color: white; padding: 12px 24px; border-radius: 999px; font-size: 13px; font-weight: 700; z-index: 9999; transition: opacity 0.3s ease; white-space: nowrap; border: 2px solid var(--color-brand); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); display: flex; align-items: center; gap: 8px; `; document.body.appendChild(toast); } // Icon mapping const icons = { success: '✓', error: '✗', warning: '⚠', info: 'ⓘ' }; // Color mapping const colors = { success: 'linear-gradient(135deg, #10b981 0%, #059669 100%)', error: 'linear-gradient(135deg, #ef4444 0%, #dc2626 100%)', warning: 'linear-gradient(135deg, #f59e0b 0%, #d97706 100%)', info: 'linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%)' }; const icon = icons[type] || icons.info; const bgColor = colors[type] || colors.info; toast.style.background = bgColor; toast.textContent = icon + ' ' + message; toast.style.opacity = '1'; clearTimeout(toast._timer); toast._timer = setTimeout(() => { toast.style.opacity = '0'; }, duration); } function showActionableToast(message, type = 'info', action = null, duration = CONFIG.TOAST_TIMEOUT) { let toast = document.getElementById('app-toast'); if (!toast) { toast = document.createElement('div'); toast.id = 'app-toast'; document.body.appendChild(toast); } // Icon mapping const icons = { success: '✓', error: '✗', warning: '⚠', info: 'ⓘ' }; // Color mapping const colors = { success: 'linear-gradient(135deg, #10b981 0%, #059669 100%)', error: 'linear-gradient(135deg, #ef4444 0%, #dc2626 100%)', warning: 'linear-gradient(135deg, #f59e0b 0%, #d97706 100%)', info: 'linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%)' }; const icon = icons[type] || icons.info; const bgColor = colors[type] || colors.info; toast.style.cssText = ` position: fixed; bottom: 80px; left: 50%; transform: translateX(-50%); background: ${bgColor}; color: white; padding: 12px 24px; border-radius: 999px; font-size: 13px; font-weight: 700; z-index: 9999; transition: opacity 0.3s ease; white-space: nowrap; border: 2px solid var(--color-brand); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); display: flex; align-items: center; gap: 12px; `; let html = `${icon} ${message}`; if (action && action.label) { html += ``; } toast.innerHTML = html; toast.style.opacity = '1'; if (action && action.label) { const btn = document.getElementById('toast-action-btn'); btn.addEventListener('click', () => { toast.style.opacity = '0'; clearTimeout(toast._timer); if (action.action) action.action(); }); } clearTimeout(toast._timer); toast._timer = setTimeout(() => { toast.style.opacity = '0'; }, duration); } // MODAL CONTROLS function openModal(modalId) { const modal = document.getElementById(modalId); if (!modal) return; modal.classList.remove('hidden'); setTimeout(() => { modal.classList.add('open'); }, 10); } function closeModal(modalId) { const modal = document.getElementById(modalId); if (!modal) return; modal.classList.remove('open'); setTimeout(() => { modal.classList.add('hidden'); }, 250); } function isModalOpen(modalId) { const modal = document.getElementById(modalId); return modal && modal.classList.contains('open'); } // DRAWER CONTROLS function openDrawer(drawerId) { const drawer = document.getElementById(drawerId); const overlay = document.getElementById(drawerId + '-overlay'); if (!drawer) return; drawer.classList.remove('hidden'); if (overlay) overlay.classList.remove('hidden'); setTimeout(() => { drawer.classList.add('open'); if (overlay) overlay.classList.add('open'); }, 10); } function closeDrawer(drawerId) { const drawer = document.getElementById(drawerId); const overlay = document.getElementById(drawerId + '-overlay'); if (!drawer) return; drawer.classList.remove('open'); if (overlay) overlay.classList.remove('open'); setTimeout(() => { drawer.classList.add('hidden'); if (overlay) overlay.classList.add('hidden'); }, 250); } function toggleDrawer(drawerId) { const drawer = document.getElementById(drawerId); if (!drawer) return; if (drawer.classList.contains('open')) { closeDrawer(drawerId); } else { openDrawer(drawerId); } } // TAB CONTROLS function switchTab(tabName, containerSelector = '.tab-section') { const sections = document.querySelectorAll(containerSelector); sections.forEach(section => { section.classList.add('hidden'); }); const activeSection = document.getElementById('tab-' + tabName); if (activeSection) { activeSection.classList.remove('hidden'); } // Update button states const tabButtons = document.querySelectorAll('.tab-btn'); tabButtons.forEach(btn => { btn.classList.remove('active'); if (btn.dataset.tab === tabName) { btn.classList.add('active'); } }); } function switchAdminTab(tabName) { const sections = document.querySelectorAll('.admin-section'); sections.forEach(section => { section.classList.add('hidden'); section.classList.remove('active'); }); const sectionMap = { pos: 'facturacion', facturacion: 'facturacion', pedidos: 'pedidos', stock: 'stock', clientes: 'clientes' }; const normalizedTab = sectionMap[tabName] || tabName; const activeSection = document.getElementById('admin-' + normalizedTab); if (activeSection) { activeSection.classList.remove('hidden'); activeSection.classList.add('active'); } // Update button states const adminTabs = document.querySelectorAll('.admin-tab'); adminTabs.forEach(btn => { btn.classList.remove('active'); if (btn.dataset.tab === tabName) { btn.classList.add('active'); } }); } // Legacy compatibility for inline handlers in index.html function showTab(tabName) { switchTab(tabName); } function showAdminTab(tabName, btn = null) { switchAdminTab(tabName); if (tabName === 'clientes' && typeof initClientsTab === 'function') { initClientsTab(); } if (btn) { document.querySelectorAll('.admin-tab').forEach(tab => tab.classList.remove('active')); btn.classList.add('active'); } } function toggleCart() { const drawer = document.getElementById('cart-drawer'); const overlay = document.getElementById('cart-overlay'); if (!drawer) return; const isOpen = drawer.classList.contains('open'); if (isOpen) { drawer.classList.remove('open'); if (overlay) overlay.classList.remove('open'); setTimeout(() => { drawer.classList.add('hidden'); if (overlay) overlay.classList.add('hidden'); }, 250); return; } drawer.classList.remove('hidden'); if (overlay) overlay.classList.remove('hidden'); setTimeout(() => { drawer.classList.add('open'); if (overlay) overlay.classList.add('open'); }, 10); } // CONFIRM DIALOG function showConfirmDialog(message, onConfirm, onCancel) { const backdrop = document.createElement('div'); backdrop.className = 'overlay open'; backdrop.style.cssText = ` position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.5); z-index: 10000; display: flex; align-items: center; justify-content: center; `; const dialog = document.createElement('div'); dialog.className = 'card'; dialog.style.cssText = ` background: white; border-radius: 12px; padding: 24px; max-width: 400px; width: 90%; box-shadow: 0 20px 25px rgba(0, 0, 0, 0.15); z-index: 10001; `; dialog.innerHTML = `
${escapeHtml(message)}