fix(brand-catalog): separate search input from content grid

- Add #brandCatalogSearch container in HTML for search inputs
- Move brand search input out of renderBrandList so it persists while typing
- Move parts search input out of renderPartsList so it persists while typing
- Reset now clears search container
- Bump JS cache bust to v=3
This commit is contained in:
2026-05-14 22:24:09 +00:00
parent 24db5eff43
commit 521455f156
2 changed files with 28 additions and 18 deletions

View File

@@ -9,6 +9,8 @@
_limit: 50, _limit: 50,
_total: 0, _total: 0,
el: function(id) { return document.getElementById(id); },
_getToken: function() { _getToken: function() {
return localStorage.getItem('pos_token'); return localStorage.getItem('pos_token');
}, },
@@ -30,8 +32,6 @@
return true; return true;
}, },
el: function(id) { return document.getElementById(id); },
show: function() { show: function() {
if (!this._getToken()) { if (!this._getToken()) {
window.location.href = '/pos/login'; window.location.href = '/pos/login';
@@ -56,6 +56,7 @@
this._allBrands = []; this._allBrands = [];
this._offset = 0; this._offset = 0;
this._total = 0; this._total = 0;
this.el('brandCatalogSearch').innerHTML = '';
}, },
loading: function(on) { loading: function(on) {
@@ -66,6 +67,10 @@
this.el('brandCatalogContent').innerHTML = html; this.el('brandCatalogContent').innerHTML = html;
}, },
setSearch: function(html) {
this.el('brandCatalogSearch').innerHTML = html;
},
setBreadcrumb: function(html) { setBreadcrumb: function(html) {
this.el('brandCatalogBreadcrumb').innerHTML = html; this.el('brandCatalogBreadcrumb').innerHTML = html;
}, },
@@ -75,6 +80,12 @@
this.loading(true); this.loading(true);
this.state = 'brands'; this.state = 'brands';
this.setBreadcrumb('<strong>Marcas de vehiculo</strong>'); this.setBreadcrumb('<strong>Marcas de vehiculo</strong>');
this.setSearch(
'<input type="text" id="brandSearchInput" placeholder="Buscar marca..." ' +
'style="width:100%;padding:10px 14px;border:1px solid var(--color-border);border-radius:var(--radius-md);' +
'font-size:var(--text-body);background:var(--color-surface);color:var(--color-text-primary);' +
'outline:none;" oninput="BrandCatalog.filterBrands(this.value)">'
);
var self = this; var self = this;
fetch('/pos/api/catalog/vehicle-brands', { headers: this._headers() }) fetch('/pos/api/catalog/vehicle-brands', { headers: this._headers() })
.then(function(r) { .then(function(r) {
@@ -98,12 +109,7 @@
}, },
renderBrandList: function(brands) { renderBrandList: function(brands) {
var html = '<div style="grid-column:1/-1;margin-bottom:var(--space-3);">' + var html = '';
'<input type="text" id="brandSearchInput" placeholder="Buscar marca..." ' +
'style="width:100%;padding:10px 14px;border:1px solid var(--color-border);border-radius:var(--radius-md);' +
'font-size:var(--text-body);background:var(--color-surface);color:var(--color-text-primary);' +
'outline:none;" oninput="BrandCatalog.filterBrands(this.value)">' +
'</div>';
brands.forEach(function(b) { brands.forEach(function(b) {
html += '<div class="catalog-category-card" onclick="BrandCatalog.selectBrand(' + JSON.stringify(b.name) + ')">' + html += '<div class="catalog-category-card" onclick="BrandCatalog.selectBrand(' + JSON.stringify(b.name) + ')">' +
'<div style="font-size:var(--text-h4);font-family:var(--font-heading);margin-bottom:4px;">' + escapeHtml(b.name) + '</div>' + '<div style="font-size:var(--text-h4);font-family:var(--font-heading);margin-bottom:4px;">' + escapeHtml(b.name) + '</div>' +
@@ -134,6 +140,7 @@
loadCategories: function(brandName) { loadCategories: function(brandName) {
this.loading(true); this.loading(true);
this.state = 'categories'; this.state = 'categories';
this.setSearch('');
this.setBreadcrumb( this.setBreadcrumb(
'<a href="javascript:void(0)" onclick="BrandCatalog.loadBrands()" style="color:var(--color-primary);text-decoration:none;">Marcas</a> &rsaquo; <strong>' + escapeHtml(brandName) + '</strong>' '<a href="javascript:void(0)" onclick="BrandCatalog.loadBrands()" style="color:var(--color-primary);text-decoration:none;">Marcas</a> &rsaquo; <strong>' + escapeHtml(brandName) + '</strong>'
); );
@@ -185,6 +192,16 @@
'<a href="javascript:void(0)" onclick="BrandCatalog.selectBrand(' + JSON.stringify(brandName) + ')" style="color:var(--color-primary);text-decoration:none;">' + escapeHtml(brandName) + '</a> &rsaquo; ' + '<a href="javascript:void(0)" onclick="BrandCatalog.selectBrand(' + JSON.stringify(brandName) + ')" style="color:var(--color-primary);text-decoration:none;">' + escapeHtml(brandName) + '</a> &rsaquo; ' +
'<strong>' + escapeHtml(this.currentCategory.name) + '</strong>' '<strong>' + escapeHtml(this.currentCategory.name) + '</strong>'
); );
this.setSearch(
'<div style="display:flex;gap:var(--space-2);flex-wrap:wrap;align-items:center;">' +
'<input type="text" id="partsSearchInput" placeholder="Buscar refaccion..." value="' + escapeHtml(searchTerm || '') + '" ' +
'style="flex:1;min-width:200px;padding:10px 14px;border:1px solid var(--color-border);border-radius:var(--radius-md);' +
'font-size:var(--text-body);background:var(--color-surface);color:var(--color-text-primary);outline:none;" ' +
'onkeydown="if(event.key===\'Enter\')BrandCatalog.searchParts(this.value)">' +
'<button class="btn btn--primary btn--sm" onclick="BrandCatalog.searchParts(document.getElementById(\'partsSearchInput\').value)">Buscar</button>' +
'<button class="btn btn--secondary btn--sm" onclick="BrandCatalog.clearPartsSearch()">Limpiar</button>' +
'</div>'
);
var url = '/pos/api/catalog/brand-parts?brand=' + encodeURIComponent(brandName) + '&category_id=' + encodeURIComponent(categoryId) + var url = '/pos/api/catalog/brand-parts?brand=' + encodeURIComponent(brandName) + '&category_id=' + encodeURIComponent(categoryId) +
'&limit=' + this._limit + '&offset=' + this._offset; '&limit=' + this._limit + '&offset=' + this._offset;
if (searchTerm) { if (searchTerm) {
@@ -215,15 +232,7 @@
}, },
renderPartsList: function(items, searchTerm) { renderPartsList: function(items, searchTerm) {
var html = '<div style="grid-column:1/-1;margin-bottom:var(--space-3);display:flex;gap:var(--space-2);flex-wrap:wrap;align-items:center;">' + var html = '';
'<input type="text" id="partsSearchInput" placeholder="Buscar refaccion..." value="' + escapeHtml(searchTerm || '') + '" ' +
'style="flex:1;min-width:200px;padding:10px 14px;border:1px solid var(--color-border);border-radius:var(--radius-md);' +
'font-size:var(--text-body);background:var(--color-surface);color:var(--color-text-primary);outline:none;" ' +
'onkeydown="if(event.key===\'Enter\')BrandCatalog.searchParts(this.value)">' +
'<button class="btn btn--primary btn--sm" onclick="BrandCatalog.searchParts(document.getElementById(\'partsSearchInput\').value)">Buscar</button>' +
'<button class="btn btn--secondary btn--sm" onclick="BrandCatalog.clearPartsSearch()">Limpiar</button>' +
'</div>';
if (!items.length) { if (!items.length) {
html += '<div style="grid-column:1/-1;text-align:center;padding:var(--space-8);">' + html += '<div style="grid-column:1/-1;text-align:center;padding:var(--space-8);">' +
'<p style="color:var(--color-text-muted);font-size:var(--text-body-lg);">No se encontraron refacciones.</p>' + '<p style="color:var(--color-text-muted);font-size:var(--text-body-lg);">No se encontraron refacciones.</p>' +

View File

@@ -277,6 +277,7 @@
<button onclick="BrandCatalog.hide()" class="btn btn--sm" style="background:none;border:1px solid var(--color-border);color:var(--color-text-primary);padding:8px 16px;border-radius:var(--radius-md);cursor:pointer;">&#10005; Cerrar</button> <button onclick="BrandCatalog.hide()" class="btn btn--sm" style="background:none;border:1px solid var(--color-border);color:var(--color-text-primary);padding:8px 16px;border-radius:var(--radius-md);cursor:pointer;">&#10005; Cerrar</button>
</div> </div>
<div id="brandCatalogBreadcrumb" style="margin-bottom:var(--space-3);color:var(--color-text-muted);font-size:var(--text-body-sm);"></div> <div id="brandCatalogBreadcrumb" style="margin-bottom:var(--space-3);color:var(--color-text-muted);font-size:var(--text-body-sm);"></div>
<div id="brandCatalogSearch" style="margin-bottom:var(--space-3);"></div>
<div id="brandCatalogLoading" style="display:none;text-align:center;padding:var(--space-8);"><div class="spinner"></div></div> <div id="brandCatalogLoading" style="display:none;text-align:center;padding:var(--space-8);"><div class="spinner"></div></div>
<div id="brandCatalogContent" style="display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:var(--space-3);"></div> <div id="brandCatalogContent" style="display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:var(--space-3);"></div>
</div> </div>
@@ -294,6 +295,6 @@
<script src="/pos/static/js/onboarding.js" defer></script> <script src="/pos/static/js/onboarding.js" defer></script>
<script>if('serviceWorker' in navigator){navigator.serviceWorker.register('/pos/sw.js',{scope:'/pos/'});}</script> <script>if('serviceWorker' in navigator){navigator.serviceWorker.register('/pos/sw.js',{scope:'/pos/'});}</script>
<script src="/pos/static/js/pwa-install.js" defer></script> <script src="/pos/static/js/pwa-install.js" defer></script>
<script src="/pos/static/js/brand-catalog.js?v=2" defer></script> <script src="/pos/static/js/brand-catalog.js?v=3" defer></script>
</body> </body>
</html> </html>