/* ========================================================================= Nexus Autoparts — Public Catalog (catalog-public.js) Vehicle hierarchy navigation: Brand > Model > Year > Engine > Category > Group > Parts No auth, no cart, no prices — public browsing only. ========================================================================= */ (function () { 'use strict'; // ── State ── var state = { level: 'brands', // brands | models | years | engines | categories | groups | parts | search brand: null, // {id, name} model: null, // {id, name} year: null, // {id, value} engine: null, // {id_mye, name, trim} category: null, // {id, name} group: null, // {id, name} region: 'north-america', page: 1, totalPages: 1, }; // ── Region selector (global) ── window.setRegion = function (region) { state.region = region; document.querySelectorAll('.region-btn').forEach(function (b) { b.classList.toggle('is-active', b.dataset.region === region); }); // Reload brands with new region state.brand = state.model = state.year = state.engine = state.category = state.group = null; loadBrands(); }; var API = '/api/catalog'; var content = document.getElementById('content'); var breadcrumbEl = document.getElementById('breadcrumb'); var searchInput = document.getElementById('searchInput'); // Check URL for brand param var urlParams = new URLSearchParams(window.location.search); var initBrandId = urlParams.get('brand'); // ── Init ── if (initBrandId) { // Load brands, find the one matching, then navigate fetch(API + '/brands') .then(function (r) { return r.json(); }) .then(function (brands) { var found = brands.find(function (b) { return b.id_brand == initBrandId; }); if (found) { state.brand = { id: found.id_brand, name: found.name_brand }; state.level = 'models'; loadModels(); } else { loadBrands(); } }) .catch(function () { loadBrands(); }); } else { loadBrands(); } // Enter on search searchInput.addEventListener('keydown', function (e) { if (e.key === 'Enter') doSearch(); }); // ── Theme toggle (global) ── window.toggleTheme = function () { var html = document.documentElement; var cur = html.getAttribute('data-theme'); var next = cur === 'industrial' ? 'modern' : 'industrial'; html.setAttribute('data-theme', next); localStorage.setItem('nexus-theme', next); }; // ── Search (global) ── window.doSearch = function () { var q = searchInput.value.trim(); if (!q || q.length < 2) return; state.level = 'search'; renderBreadcrumb(); content.innerHTML = '
Buscando...
'; fetch(API + '/search?q=' + encodeURIComponent(q)) .then(function (r) { return r.json(); }) .then(function (data) { renderSearchResults(data); }) .catch(function () { content.innerHTML = '
Error en la busqueda.
'; }); }; // ── Detail modal (global) ── window.openDetail = function (partId) { var modal = document.getElementById('detailModal'); var body = document.getElementById('detailBody'); body.innerHTML = '
Cargando detalle...
'; modal.classList.add('open'); fetch(API + '/part/' + partId) .then(function (r) { return r.json(); }) .then(function (d) { renderDetail(d, body); }) .catch(function () { body.innerHTML = '
Error cargando detalle.
'; }); }; window.closeDetail = function () { document.getElementById('detailModal').classList.remove('open'); }; // Close modal on backdrop click document.getElementById('detailModal').addEventListener('click', function (e) { if (e.target === this) closeDetail(); }); // ── Breadcrumb ── function renderBreadcrumb() { var parts = []; parts.push('Catalogo'); if (state.brand) { parts.push('/'); parts.push('' + esc(state.brand.name) + ''); } if (state.model) { parts.push('/'); parts.push('' + esc(state.model.name) + ''); } if (state.year) { parts.push('/'); parts.push('' + esc(String(state.year.value)) + ''); } if (state.engine) { parts.push('/'); var engineLabel = state.engine.name + (state.engine.trim ? ' (' + state.engine.trim + ')' : ''); parts.push('' + esc(engineLabel) + ''); } if (state.category) { parts.push('/'); parts.push('' + esc(state.category.name) + ''); } if (state.group) { parts.push('/'); parts.push('' + esc(state.group.name) + ''); } if (state.level === 'search') { parts.push('/'); parts.push('Busqueda'); } breadcrumbEl.innerHTML = parts.join(''); } // Global nav window.catalogNav = function (level) { if (level === 'brands') { state.brand = state.model = state.year = state.engine = state.category = state.group = null; state.level = 'brands'; loadBrands(); } else if (level === 'models') { state.model = state.year = state.engine = state.category = state.group = null; state.level = 'models'; loadModels(); } else if (level === 'years') { state.year = state.engine = state.category = state.group = null; state.level = 'years'; loadYears(); } else if (level === 'engines') { state.engine = state.category = state.group = null; state.level = 'engines'; loadEngines(); } else if (level === 'categories') { state.category = state.group = null; state.level = 'categories'; loadCategories(); } else if (level === 'groups') { state.group = null; state.level = 'groups'; loadGroups(); } }; // ── Data loaders ── function loadBrands() { state.level = 'brands'; renderBreadcrumb(); content.innerHTML = '
Cargando marcas...
'; fetch(API + '/brands?region=' + (state.region || 'north-america')) .then(function (r) { return r.json(); }) .then(function (brands) { var html = '

Selecciona una Marca

'; content.innerHTML = html; }) .catch(function () { content.innerHTML = '
Error cargando marcas.
'; }); } window.selectBrand = function (id, name) { state.brand = { id: id, name: name }; state.level = 'models'; loadModels(); }; function loadModels() { renderBreadcrumb(); content.innerHTML = '
Cargando modelos...
'; fetch(API + '/models?brand_id=' + state.brand.id) .then(function (r) { return r.json(); }) .then(function (models) { var html = '

' + esc(state.brand.name) + ' — Modelos

'; content.innerHTML = html; }) .catch(function () { content.innerHTML = '
Error cargando modelos.
'; }); } window.selectModel = function (id, name) { state.model = { id: id, name: name }; state.level = 'years'; loadYears(); }; function loadYears() { renderBreadcrumb(); content.innerHTML = '
Cargando anos...
'; fetch(API + '/years?model_id=' + state.model.id) .then(function (r) { return r.json(); }) .then(function (years) { var html = '

' + esc(state.brand.name) + ' ' + esc(state.model.name) + ' — Anos

'; content.innerHTML = html; }) .catch(function () { content.innerHTML = '
Error cargando anos.
'; }); } window.selectYear = function (id, value) { state.year = { id: id, value: value }; state.level = 'engines'; loadEngines(); }; function loadEngines() { renderBreadcrumb(); content.innerHTML = '
Cargando motores...
'; fetch(API + '/engines?model_id=' + state.model.id + '&year_id=' + state.year.id) .then(function (r) { return r.json(); }) .then(function (engines) { var html = '

' + esc(state.brand.name) + ' ' + esc(state.model.name) + ' ' + state.year.value + ' — Motor

'; html += ''; content.innerHTML = html; }) .catch(function () { content.innerHTML = '
Error cargando motores.
'; }); } window.selectEngine = function (id_mye, name, trim) { state.engine = { id_mye: id_mye, name: name, trim: trim }; state.level = 'categories'; loadCategories(); }; function loadCategories() { renderBreadcrumb(); content.innerHTML = '
Cargando categorias...
'; fetch(API + '/categories?mye_id=' + state.engine.id_mye) .then(function (r) { return r.json(); }) .then(function (cats) { if (!cats.length) { content.innerHTML = '

Categorias

No se encontraron categorias con partes para este vehiculo.
'; return; } var html = '

Categorias

'; content.innerHTML = html; }) .catch(function () { content.innerHTML = '
Error cargando categorias.
'; }); } window.selectCategory = function (id, name) { state.category = { id: id, name: name }; state.level = 'groups'; loadGroups(); }; function loadGroups() { renderBreadcrumb(); content.innerHTML = '
Cargando grupos...
'; fetch(API + '/groups?mye_id=' + state.engine.id_mye + '&category_id=' + state.category.id) .then(function (r) { return r.json(); }) .then(function (groups) { if (!groups.length) { content.innerHTML = '

' + esc(state.category.name) + '

No se encontraron sub-grupos.
'; return; } var html = '

' + esc(state.category.name) + '

'; content.innerHTML = html; }) .catch(function () { content.innerHTML = '
Error cargando grupos.
'; }); } window.selectGroup = function (id, name) { state.group = { id: id, name: name }; state.level = 'parts'; state.page = 1; loadParts(); }; function loadParts() { renderBreadcrumb(); content.innerHTML = '
Cargando partes...
'; var url = API + '/parts?mye_id=' + state.engine.id_mye + '&group_id=' + state.group.id + '&page=' + state.page; fetch(url) .then(function (r) { return r.json(); }) .then(function (resp) { var parts = resp.data; var pag = resp.pagination; state.totalPages = pag.total_pages; if (!parts.length) { content.innerHTML = '

' + esc(state.group.name) + '

No se encontraron partes.
'; return; } var html = '

' + esc(state.group.name) + ' (' + pag.total + ' partes)

'; html += '
'; parts.forEach(function (p) { html += '
'; html += '
'; html += '
' + esc(p.oem_part_number) + '
'; html += '
' + esc(p.name || '') + '
'; if (p.description) html += '
' + esc(p.description) + '
'; html += ''; html += '
'; if (p.image_url) { html += ''; } html += '
'; }); html += '
'; // Pagination if (pag.total_pages > 1) { html += ''; } content.innerHTML = html; }) .catch(function () { content.innerHTML = '
Error cargando partes.
'; }); } window.partsPage = function (p) { state.page = p; loadParts(); window.scrollTo({ top: 0, behavior: 'smooth' }); }; // ── Search results ── function renderSearchResults(results) { renderBreadcrumb(); if (!results.length) { content.innerHTML = '

Busqueda

No se encontraron resultados.
'; return; } var html = '

Resultados (' + results.length + ')

'; results.forEach(function (p) { html += '
'; html += '
'; html += '
' + esc(p.oem_part_number) + '
'; html += '
' + esc(p.name || '') + '
'; if (p.vehicle_info) html += '
' + esc(p.vehicle_info) + '
'; html += ''; html += '
'; if (p.image_url) { html += ''; } html += '
'; }); html += '
'; content.innerHTML = html; } // ── Part detail ── function renderDetail(d, body) { if (!d || !d.part) { body.innerHTML = '
Parte no encontrada.
'; return; } var p = d.part; var html = ''; html += '
' + esc(p.oem_part_number) + '
'; html += '
' + esc(p.name || '') + '
'; if (p.category_name) html += '
' + esc(p.category_name) + (p.group_name ? ' / ' + esc(p.group_name) : '') + '
'; if (p.description) html += '
' + esc(p.description) + '
'; if (p.image_url) { html += '
'; html += ''; html += '
'; } // Alternatives if (d.alternatives && d.alternatives.length) { html += '
'; html += '

Alternativas y Cross-References (' + d.alternatives.length + ')

'; html += ''; d.alternatives.forEach(function (a) { html += ''; html += ''; html += ''; html += ''; html += ''; html += ''; }); html += '
NumeroFabricanteNombreTipo
' + esc(a.part_number || '') + '' + esc(a.manufacturer || '') + '' + esc(a.name || '-') + '' + esc(a.type === 'aftermarket' ? 'Aftermarket' : 'Cross-Ref') + '
'; } // Bodegas if (d.bodegas && d.bodegas.length) { html += '
'; html += '

Disponibilidad en Bodegas (' + d.bodegas.length + ')

'; html += ''; d.bodegas.forEach(function (b) { html += ''; html += ''; html += ''; html += ''; html += ''; }); html += '
BodegaStockUbicacion
' + esc(b.business_name || '') + '' + b.stock + '' + esc(b.location || '-') + '
'; } body.innerHTML = html; } // ── Helpers ── function esc(s) { if (!s) return ''; var d = document.createElement('div'); d.textContent = s; return d.innerHTML; } function escAttr(s) { return esc(s).replace(/'/g, "\\'").replace(/"/g, '"'); } })();