feat(pos): selector de vehiculo con dropdowns — Ano > Marca > Modelo > Motor

Barra de 4 dropdowns arriba del catalogo que se habilitan en cascada.
Al completar los 4, muestra categorias y partes para ese vehiculo.
Boton de limpiar para resetear. Endpoint /years-all para cargar anos.
Estilos con design system tokens (ambos temas).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-02 07:59:50 +00:00
parent 1a770999f5
commit 10d5b62e00
3 changed files with 243 additions and 0 deletions

View File

@@ -816,6 +816,138 @@
}
});
// ─── VEHICLE SELECTOR (dropdown bar) ───
var vsYear = document.getElementById('vsYear');
var vsBrand = document.getElementById('vsBrand');
var vsModel = document.getElementById('vsModel');
var vsEngine = document.getElementById('vsEngine');
var vsClear = document.getElementById('vsClear');
// Load years on init
function vsLoadYears() {
apiFetch(API + '/years-all').then(function (data) {
if (!data) return;
var years = data.data || data;
// If endpoint doesn't exist, generate from 1990-2026
if (!years || !years.length) {
years = [];
for (var y = 2026; y >= 1990; y--) years.push({ id_year: y, year_car: y });
}
vsYear.innerHTML = '<option value="">Año...</option>';
years.forEach(function (y) {
vsYear.innerHTML += '<option value="' + y.id_year + '">' + y.year_car + '</option>';
});
}).catch(function () {
// Fallback: generate years statically
vsYear.innerHTML = '<option value="">Año...</option>';
for (var y = 2026; y >= 1990; y--) {
vsYear.innerHTML += '<option value="' + y + '">' + y + '</option>';
}
});
}
function vsYearChanged() {
var yearId = vsYear.value;
vsBrand.innerHTML = '<option value="">Marca...</option>';
vsModel.innerHTML = '<option value="">Modelo...</option>';
vsEngine.innerHTML = '<option value="">Motor...</option>';
vsBrand.disabled = true;
vsModel.disabled = true;
vsEngine.disabled = true;
vsClear.style.display = yearId ? '' : 'none';
if (!yearId) return;
// Load brands (reuse existing endpoint)
vsBrand.disabled = false;
apiFetch(API + '/brands').then(function (data) {
var brands = data.data || data;
if (!brands) return;
vsBrand.innerHTML = '<option value="">Marca...</option>';
brands.forEach(function (b) {
vsBrand.innerHTML += '<option value="' + b.id_brand + '">' + esc(b.name_brand) + '</option>';
});
});
}
function vsBrandChanged() {
var brandId = vsBrand.value;
vsModel.innerHTML = '<option value="">Modelo...</option>';
vsEngine.innerHTML = '<option value="">Motor...</option>';
vsModel.disabled = true;
vsEngine.disabled = true;
if (!brandId) return;
vsModel.disabled = false;
apiFetch(API + '/models?brand_id=' + brandId).then(function (data) {
var models = data.data || data;
if (!models) return;
vsModel.innerHTML = '<option value="">Modelo...</option>';
models.forEach(function (m) {
vsModel.innerHTML += '<option value="' + m.id_model + '">' + esc(m.name_model) + '</option>';
});
});
}
function vsModelChanged() {
var modelId = vsModel.value;
var yearVal = vsYear.value;
vsEngine.innerHTML = '<option value="">Motor...</option>';
vsEngine.disabled = true;
if (!modelId || !yearVal) return;
vsEngine.disabled = false;
apiFetch(API + '/engines?model_id=' + modelId + '&year_id=' + yearVal).then(function (data) {
var engines = data.data || data;
if (!engines) return;
vsEngine.innerHTML = '<option value="">Motor...</option>';
engines.forEach(function (e) {
var label = e.name_engine + (e.trim_level ? ' (' + e.trim_level + ')' : '');
vsEngine.innerHTML += '<option value="' + e.id_mye + '">' + esc(label) + '</option>';
});
// If only 1 engine, auto-select
if (engines.length === 1) {
vsEngine.value = engines[0].id_mye;
vsEngineChanged();
}
});
}
function vsEngineChanged() {
var myeId = vsEngine.value;
if (!myeId) return;
// Update state and load categories
var yearText = vsYear.options[vsYear.selectedIndex].text;
var brandText = vsBrand.options[vsBrand.selectedIndex].text;
var modelText = vsModel.options[vsModel.selectedIndex].text;
var engineText = vsEngine.options[vsEngine.selectedIndex].text;
state.brand = { id: parseInt(vsBrand.value), name: brandText };
state.model = { id: parseInt(vsModel.value), name: modelText };
state.year = { id: parseInt(vsYear.value), value: yearText };
state.engine = { id_mye: parseInt(myeId), name: engineText };
state.level = 'categories';
loadCategories();
}
function vsClearAll() {
vsYear.value = '';
vsBrand.innerHTML = '<option value="">Marca...</option>';
vsModel.innerHTML = '<option value="">Modelo...</option>';
vsEngine.innerHTML = '<option value="">Motor...</option>';
vsBrand.disabled = true;
vsModel.disabled = true;
vsEngine.disabled = true;
vsClear.style.display = 'none';
state = { level: 'brands', brand: null, model: null, year: null, engine: null, category: null, group: null, page: 1, totalPages: 1 };
loadBrands();
}
// ─── EXPOSE GLOBALS (for backward compat) ───
window.CatalogApp = {
toggleCart: toggleCart,
@@ -825,10 +957,16 @@
updateQty: updateQuantity,
clearCart: clearCart,
loadPage: function (p) { loadParts(p); },
vsYearChanged: vsYearChanged,
vsBrandChanged: vsBrandChanged,
vsModelChanged: vsModelChanged,
vsEngineChanged: vsEngineChanged,
vsClear: vsClearAll,
};
// ─── INIT ───
renderCart();
vsLoadYears();
loadBrands();
})();