/** * tienda.js — Store / Tablet dashboard logic for Nexus Autoparts */ (function () { 'use strict'; var API = ''; // ================================================================ // Utility // ================================================================ function fmt(n) { return '$' + (parseFloat(n) || 0).toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ','); } function esc(s) { if (!s) return ''; var d = document.createElement('div'); d.textContent = s; return d.innerHTML; } // ================================================================ // Clock // ================================================================ function updateClock() { var now = new Date(); var h = now.getHours(); var m = String(now.getMinutes()).padStart(2, '0'); var ampm = h >= 12 ? 'PM' : 'AM'; h = h % 12 || 12; document.getElementById('clock').textContent = h + ':' + m + ' ' + ampm; } updateClock(); setInterval(updateClock, 30000); // ================================================================ // Load Dashboard Stats // ================================================================ function loadStats() { fetch(API + '/api/tienda/stats') .then(function (r) { return r.json(); }) .then(function (d) { var st = d.sales_today || {}; var sm = d.sales_month || {}; var pt = d.payments_today || {}; // KPIs document.getElementById('kpi-sales-today').textContent = fmt(st.total); document.getElementById('kpi-sales-count').textContent = (st.count || 0) + ' facturas'; document.getElementById('kpi-month').textContent = fmt(sm.total); document.getElementById('kpi-month-count').textContent = (sm.count || 0) + ' facturas'; document.getElementById('kpi-customers').textContent = d.total_customers || 0; document.getElementById('kpi-parts-count').textContent = (d.total_parts || 0) + ' partes'; document.getElementById('kpi-pending').textContent = fmt(d.pending_balance || 0); document.getElementById('kpi-pending-count').textContent = (d.pending_invoices || 0) + ' facturas'; // Today's payments document.getElementById('payments-today-amount').textContent = fmt(pt.total); document.getElementById('payments-today-count').textContent = (pt.count || 0) + ' pagos registrados'; // Top debtors renderDebtors(d.top_debtors || []); // Recent invoices renderInvoices(d.recent_invoices || []); }) .catch(function (err) { console.error('Error loading stats:', err); }); } // ================================================================ // Render Debtors // ================================================================ function renderDebtors(debtors) { var el = document.getElementById('debtors-list'); if (debtors.length === 0) { el.innerHTML = '
Sin cuentas pendientes
'; return; } el.innerHTML = debtors.map(function (d) { var limitPct = d.credit_limit > 0 ? Math.round(d.balance / d.credit_limit * 100) : 0; return '' + '
' + '
' + esc(d.name) + '
' + (d.credit_limit > 0 ? '
' + limitPct + '% de l\u00edmite
' : '') + '
' + '' + fmt(d.balance) + '' + '
'; }).join(''); } // ================================================================ // Render Recent Invoices // ================================================================ function renderInvoices(invoices) { var el = document.getElementById('recent-invoices'); if (invoices.length === 0) { el.innerHTML = '
Sin facturas recientes
'; return; } el.innerHTML = invoices.map(function (inv) { var statusClass = inv.status || 'pending'; var statusLabel = { pending: 'Pendiente', paid: 'Pagada', partial: 'Parcial', cancelled: 'Cancelada' }; return '
' + '
' + '' + esc(inv.folio) + '' + '' + esc(inv.customer_name) + '' + '
' + '
' + '' + fmt(inv.total) + '' + '' + (statusLabel[statusClass] || statusClass) + '' + '
' + '
'; }).join(''); } // ================================================================ // Global Search // ================================================================ var searchTimer = null; var searchInput = document.getElementById('global-search'); var searchResults = document.getElementById('global-results'); if (searchInput) { searchInput.addEventListener('input', function () { clearTimeout(searchTimer); var q = this.value.trim(); if (q.length < 2) { searchResults.classList.remove('active'); searchResults.innerHTML = ''; return; } searchTimer = setTimeout(function () { fetch(API + '/api/pos/search-parts?q=' + encodeURIComponent(q)) .then(function (r) { return r.json(); }) .then(function (results) { if (results.length === 0) { searchResults.innerHTML = '
Sin resultados para "' + esc(q) + '"
'; } else { searchResults.innerHTML = results.slice(0, 8).map(function (p) { return '
' + '
' + '' + esc(p.oem_part_number) + '' + '' + esc(p.name_part) + '' + '
' + '
'; }).join(''); } searchResults.classList.add('active'); }); }, 250); }); searchInput.addEventListener('blur', function () { setTimeout(function () { searchResults.classList.remove('active'); }, 200); }); searchInput.addEventListener('focus', function () { if (searchResults.innerHTML.trim()) { searchResults.classList.add('active'); } }); } // ================================================================ // Init // ================================================================ loadStats(); // Auto-refresh every 2 minutes setInterval(loadStats, 120000); })();