diff --git a/dashboard/admin.js b/dashboard/admin.js
index 43da4ef..fcde228 100644
--- a/dashboard/admin.js
+++ b/dashboard/admin.js
@@ -849,9 +849,28 @@ async function openAftermarketModal(id = null) {
openModal('aftermarketModal');
}
-function editAftermarket(id) {
- // TODO: Fetch and populate for edit
- openAftermarketModal(id);
+async function editAftermarket(id) {
+ await openAftermarketModal(id);
+ try {
+ const res = await fetch(`/api/aftermarket?search=&per_page=200`);
+ const data = await res.json();
+ const items = data.data || data;
+ const item = items.find(a => a.id === id);
+ if (item) {
+ document.getElementById('aftermarketId').value = item.id;
+ document.getElementById('aftermarketPartNumber').value = item.part_number || '';
+ document.getElementById('aftermarketName').value = item.name || '';
+ document.getElementById('aftermarketNameEs').value = item.name_es || '';
+ document.getElementById('aftermarketQuality').value = item.quality_tier || 'standard';
+ document.getElementById('aftermarketPrice').value = item.price_usd || '';
+ document.getElementById('aftermarketWarranty').value = item.warranty_months || '';
+ if (item.oem_part_id) document.getElementById('aftermarketOemPart').value = item.oem_part_id;
+ if (item.manufacturer_id) document.getElementById('aftermarketManufacturer').value = item.manufacturer_id;
+ document.getElementById('aftermarketModalTitle').textContent = 'Editar Parte Aftermarket';
+ }
+ } catch (e) {
+ console.error('Error loading aftermarket for edit:', e);
+ }
}
async function saveAftermarket() {
diff --git a/dashboard/customer-landing.html b/dashboard/customer-landing.html
index a0af19f..8e8da05 100644
--- a/dashboard/customer-landing.html
+++ b/dashboard/customer-landing.html
@@ -1277,12 +1277,13 @@
// Load stats
async function loadStats() {
try {
- const [partsRes, brandsRes, categoriesRes, manufacturersRes, aftermarketRes] = await Promise.all([
+ const [partsRes, brandsRes, categoriesRes, manufacturersRes, aftermarketRes, modelsRes] = await Promise.all([
fetch(`${API_BASE}/api/parts?per_page=1`),
fetch(`${API_BASE}/api/brands`),
fetch(`${API_BASE}/api/categories`),
fetch(`${API_BASE}/api/manufacturers`),
- fetch(`${API_BASE}/api/aftermarket?per_page=1`)
+ fetch(`${API_BASE}/api/aftermarket?per_page=1`),
+ fetch(`${API_BASE}/api/models`)
]);
const parts = await partsRes.json();
@@ -1290,11 +1291,13 @@
const categories = await categoriesRes.json();
const manufacturers = await manufacturersRes.json();
const aftermarket = await aftermarketRes.json();
+ const models = await modelsRes.json();
document.getElementById('stat-parts').textContent = (parts.pagination?.total || parts.length || 0) + '+';
document.getElementById('stat-brands').textContent = brands.length || 0;
document.getElementById('stat-categories').textContent = categories.length || 0;
- document.getElementById('stat-models').textContent = '13K+';
+ const modelCount = models.length || 0;
+ document.getElementById('stat-models').textContent = modelCount >= 1000 ? Math.floor(modelCount / 1000) + 'K+' : modelCount;
document.getElementById('stat-manufacturers').textContent = manufacturers.length || 0;
document.getElementById('stat-aftermarket').textContent = (aftermarket.pagination?.total || aftermarket.length || 0) + '+';
} catch (e) {
@@ -1444,13 +1447,15 @@
try {
const res = await fetch(`${API_BASE}/api/vin/decode/${vin}`);
- const data = await res.json();
+ const raw = await res.json();
+ const data = raw.vehicle || raw;
if (data.error) {
resultDiv.innerHTML = `
${data.error}
`;
return;
}
+ const engineInfo = data.engine_info || {};
resultDiv.innerHTML = `
Vehículo Identificado
@@ -1459,7 +1464,7 @@
Año: ${data.year || 'N/A'}
Tipo: ${data.body_class || 'N/A'}
Tracción: ${data.drive_type || 'N/A'}
- ${data.engine_info ? `
Motor: ${data.engine_info.displacement_l || ''}L ${data.engine_info.cylinders || ''} cil.
` : ''}
+ ${engineInfo.raw || engineInfo.displacement_l ? `
Motor: ${engineInfo.raw || (engineInfo.displacement_l + 'L ' + (engineInfo.cylinders || '') + ' cil.')}
` : ''}
Ver partes compatibles
`;
diff --git a/dashboard/dashboard.js b/dashboard/dashboard.js
index 9f1ddd3..ce81f7b 100644
--- a/dashboard/dashboard.js
+++ b/dashboard/dashboard.js
@@ -93,26 +93,26 @@ class VehicleDashboard {
items.push({ label: this.selectedBrand, active: true });
} else if (this.currentView === 'vehicles') {
items.push({ label: ' Marcas', action: 'dashboard.goToBrands()' });
- items.push({ label: this.selectedBrand, action: `dashboard.goToModels('${this.selectedBrand}')` });
+ items.push({ label: this.selectedBrand, action: `dashboard.goToModels('${this.selectedBrand.replace(/'/g, "\\'")}')` });
items.push({ label: this.selectedModel, active: true });
} else if (this.currentView === 'categories') {
items.push({ label: ' Marcas', action: 'dashboard.goToBrands()' });
- items.push({ label: this.selectedBrand, action: `dashboard.goToModels('${this.selectedBrand}')` });
- items.push({ label: this.selectedModel, action: `dashboard.goToVehicles('${this.selectedBrand}', '${this.selectedModel}')` });
+ items.push({ label: this.selectedBrand, action: `dashboard.goToModels('${this.selectedBrand.replace(/'/g, "\\'")}')` });
+ items.push({ label: this.selectedModel, action: `dashboard.goToVehicles('${this.selectedBrand.replace(/'/g, "\\'")}', '${this.selectedModel.replace(/'/g, "\\'")}')` });
if (this.selectedYear) items.push({ label: this.selectedYear });
items.push({ label: 'Categorías', active: true });
} else if (this.currentView === 'groups') {
items.push({ label: ' Marcas', action: 'dashboard.goToBrands()' });
- items.push({ label: this.selectedBrand, action: `dashboard.goToModels('${this.selectedBrand}')` });
- items.push({ label: this.selectedModel, action: `dashboard.goToVehicles('${this.selectedBrand}', '${this.selectedModel}')` });
+ items.push({ label: this.selectedBrand, action: `dashboard.goToModels('${this.selectedBrand.replace(/'/g, "\\'")}')` });
+ items.push({ label: this.selectedModel, action: `dashboard.goToVehicles('${this.selectedBrand.replace(/'/g, "\\'")}', '${this.selectedModel.replace(/'/g, "\\'")}')` });
if (this.selectedYear) items.push({ label: this.selectedYear });
items.push({ label: 'Categorías', action: `dashboard.goToCategories(${this.selectedVehicleId})` });
items.push({ label: this.selectedCategory ? (this.selectedCategory.name_es || this.selectedCategory.name) : 'Grupos', active: true });
} else if (this.currentView === 'parts') {
const groupName = this.selectedGroup ? (this.selectedGroup.name_es || this.selectedGroup.name) : 'Grupo';
items.push({ label: ' Marcas', action: 'dashboard.goToBrands()' });
- items.push({ label: this.selectedBrand, action: `dashboard.goToModels('${this.selectedBrand}')` });
- items.push({ label: this.selectedModel, action: `dashboard.goToVehicles('${this.selectedBrand}', '${this.selectedModel}')` });
+ items.push({ label: this.selectedBrand, action: `dashboard.goToModels('${this.selectedBrand.replace(/'/g, "\\'")}')` });
+ items.push({ label: this.selectedModel, action: `dashboard.goToVehicles('${this.selectedBrand.replace(/'/g, "\\'")}', '${this.selectedModel.replace(/'/g, "\\'")}')` });
if (this.selectedYear) items.push({ label: this.selectedYear });
items.push({ label: 'Categorías', action: `dashboard.goToCategories(${this.selectedVehicleId})` });
items.push({ label: this.selectedCategory ? (this.selectedCategory.name_es || this.selectedCategory.name) : 'Categoría', action: `dashboard.goToGroups(${this.selectedCategory ? this.selectedCategory.id : 0})` });
@@ -980,9 +980,10 @@ class VehicleDashboard {
// FASE 5: Fetch group details for breadcrumb
try {
- const response = await fetch(`/api/groups/${groupId}`);
+ const response = await fetch(`/api/categories/${this.selectedCategory ? this.selectedCategory.id : 0}/groups`);
if (response.ok) {
- this.selectedGroup = await response.json();
+ const groups = await response.json();
+ this.selectedGroup = groups.find(g => g.id === groupId) || { id: groupId, name: 'Grupo' };
}
} catch (error) {
console.error('Error fetching group details:', error);
@@ -1354,9 +1355,9 @@ class VehicleDashboard {
// FASE 2: Show part detail from search results (closes search modal first)
showPartDetailFromSearch(partId) {
// Close search results modal
- const searchModal = bootstrap.Modal.getInstance(document.getElementById('searchResultsModal'));
- if (searchModal) {
- searchModal.hide();
+ const searchModalEl = document.getElementById('searchResultsModal');
+ if (searchModalEl) {
+ searchModalEl.classList.remove('active');
}
// Small delay to allow modal transition, then show part detail
@@ -1453,7 +1454,7 @@ class VehicleDashboard {
async showDiagram(diagramId) {
// FASE 5: Use focus management for modal
const contentContainer = document.getElementById('diagramModalContent');
- const modalTitle = document.getElementById('diagramModalLabel');
+ const modalTitle = document.getElementById('diagramModalTitle');
contentContainer.innerHTML = `
@@ -1567,9 +1568,9 @@ class VehicleDashboard {
onHotspotClick(hotspot) {
if (hotspot.part_id) {
// Close diagram modal first
- const diagramModal = bootstrap.Modal.getInstance(document.getElementById('diagramModal'));
- if (diagramModal) {
- diagramModal.hide();
+ const diagramModalEl = document.getElementById('diagramModal');
+ if (diagramModalEl) {
+ diagramModalEl.classList.remove('active');
}
// Small delay to allow modal transition, then show part detail
@@ -1790,9 +1791,9 @@ class VehicleDashboard {
// FASE 4: View parts for a VIN
async viewVinParts(vin, myeId) {
// Close VIN modal
- const vinModal = bootstrap.Modal.getInstance(document.getElementById('vinDecoderModal'));
- if (vinModal) {
- vinModal.hide();
+ const vinModalEl = document.getElementById('vinDecoderModal');
+ if (vinModalEl) {
+ vinModalEl.classList.remove('active');
}
// FASE 5: Use focus management for modal