feat(ui): infinite scroll, saved filters, product timeline, image comparator, customers bulk toolbar, dark mode refinements

This commit is contained in:
2026-05-26 09:37:35 +00:00
parent 5c815bc2f5
commit c5fc8c5ec6
5 changed files with 159 additions and 1 deletions

View File

@@ -1314,6 +1314,15 @@
html += '<span id="imgUploadStatus" style="display:block;margin-top:4px;font-size:var(--text-caption);color:var(--color-text-muted);"></span>';
html += '</div>';
// Action buttons
html += '<div style="display:flex;gap:8px;justify-content:center;margin-bottom:16px;padding-bottom:16px;border-bottom:1px solid var(--color-border);">';
html += '<button class="btn btn--ghost btn--sm" onclick="showProductTimeline(' + data.id + ')">📅 Timeline</button>';
if (data.image_url) {
html += '<button class="btn btn--ghost btn--sm" onclick="showImageCompare(\'' + esc(data.image_url) + '\')">🖼️ Comparar</button>';
}
html += '<button class="btn btn--ghost btn--sm" onclick="viewHistory(' + data.id + ')">📜 Historial</button>';
html += '</div>';
// Product info header
html += '<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:16px;padding-bottom:16px;border-bottom:1px solid var(--color-border);">';
html += '<div><span style="font-size:var(--text-caption);color:var(--color-text-muted);text-transform:uppercase;display:block;">ID Inventario</span><strong style="font-family:var(--font-mono);">' + data.id + '</strong></div>';
@@ -1535,9 +1544,76 @@
window.autoMatchCompat = autoMatchCompat;
window.removeCompat = removeCompat;
// ─── Product Timeline ──────────────────────────────────────────
window.showProductTimeline = function(itemId) {
var modal = document.getElementById('productTimelineModal');
var body = document.getElementById('productTimelineBody');
body.innerHTML = '<div style="padding:20px;"><div class="skeleton skeleton--text"></div><div class="skeleton skeleton--text-sm"></div></div>';
modal.classList.add('is-open');
apiFetch(API + '/items/' + itemId + '/history').then(function(data) {
var history = (data && data.data) ? data.data : [];
var html = '<div class="timeline">';
html += '<div class="timeline__item"><div class="timeline__dot timeline__dot--green"></div><div class="timeline__content"><div class="timeline__date">Producto creado</div><div class="timeline__title">Registro inicial en inventario</div></div></div>';
history.forEach(function(h) {
var color = h.quantity > 0 ? 'timeline__dot--green' : (h.quantity < 0 ? 'timeline__dot--red' : 'timeline__dot--blue');
var title = (h.type || 'Movimiento') + ' · ' + (h.quantity > 0 ? '+' : '') + h.quantity + ' unidades';
html += '<div class="timeline__item"><div class="timeline__dot ' + color + '"></div><div class="timeline__content">' +
'<div class="timeline__date">' + esc(h.date) + ' · ' + esc(h.employee) + '</div>' +
'<div class="timeline__title">' + esc(title) + '</div>' +
(h.notes ? '<div class="timeline__desc">' + esc(h.notes) + '</div>' : '') +
'</div></div>';
});
html += '</div>';
body.innerHTML = html;
});
};
// ─── Image Comparator ──────────────────────────────────────────
window.showImageCompare = function(imageUrl) {
var modal = document.getElementById('imageCompareModal');
document.getElementById('imgCompareNew').src = imageUrl + '?t=' + Date.now();
document.getElementById('imgCompareOld').src = imageUrl + '?t=' + (Date.now() - 1);
modal.classList.add('is-open');
setTimeout(function() { if (typeof initImageComparator === 'function') initImageComparator('#imgCompareContainer'); }, 100);
};
// ─── Infinite Scroll ───────────────────────────────────────────
var _infiniteScrollInstance = null;
function setupInfiniteScroll() {
if (_infiniteScrollInstance) _infiniteScrollInstance.disconnect();
var sentinel = document.createElement('div');
sentinel.id = 'inventoryScrollSentinel';
sentinel.style.cssText = 'height:1px;';
var wrapper = document.querySelector('.table-wrapper');
if (wrapper) wrapper.appendChild(sentinel);
_infiniteScrollInstance = new InfiniteScroll({
sentinelParent: wrapper,
onLoad: function(done) {
if (!currentSearch && currentPage < (window._inventoryTotalPages || 999)) {
loadItems(currentPage + 1);
}
if (done) done();
}
});
}
// ─── Saved Filters ─────────────────────────────────────────────
function renderSavedFilters() {
var container = document.getElementById('savedFiltersContainer');
if (!container) return;
SavedFilters.renderChips('savedFiltersContainer', function(filters) {
if (filters.search) {
var el = document.getElementById('productSearch');
if (el) { el.value = filters.search; loadItems(1, filters.search); }
}
});
}
// =====================================================================
// INIT — load stock on page load
// =====================================================================
loadItems(1);
renderSavedFilters();
})();