feat: selector de region en catalogo publico (MX/USA/CA, Europa, Asia, Todos)
Filtra marcas por mercado regional. 4 opciones: - Mexico/USA/Canada (36 marcas) - Europa (27 marcas) - Asia (15 marcas) - Todos (546 marcas) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -87,6 +87,34 @@
|
|||||||
}
|
}
|
||||||
.search-wrapper button:hover { background: var(--btn-primary-bg-hover); }
|
.search-wrapper button:hover { background: var(--btn-primary-bg-hover); }
|
||||||
|
|
||||||
|
/* ── Region bar ── */
|
||||||
|
.region-bar {
|
||||||
|
background: var(--color-bg-elevated);
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
padding: var(--space-2) 0;
|
||||||
|
}
|
||||||
|
.region-inner {
|
||||||
|
max-width: var(--content-xl); margin: 0 auto;
|
||||||
|
padding: 0 var(--space-6);
|
||||||
|
display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.region-label {
|
||||||
|
font-size: var(--text-caption); font-weight: var(--font-weight-semibold);
|
||||||
|
color: var(--color-text-muted); text-transform: uppercase;
|
||||||
|
letter-spacing: var(--tracking-wider); margin-right: var(--space-2);
|
||||||
|
}
|
||||||
|
.region-btn {
|
||||||
|
background: var(--btn-ghost-bg); border: 1px solid var(--btn-ghost-border);
|
||||||
|
color: var(--btn-ghost-text); padding: var(--space-1) var(--space-3);
|
||||||
|
border-radius: var(--radius-md); cursor: pointer; font-size: var(--text-caption);
|
||||||
|
font-family: var(--font-body); transition: var(--transition-fast);
|
||||||
|
}
|
||||||
|
.region-btn:hover { background: var(--color-surface-2); color: var(--color-text-primary); }
|
||||||
|
.region-btn.is-active {
|
||||||
|
background: var(--color-primary-muted); color: var(--color-primary);
|
||||||
|
border-color: var(--color-primary); font-weight: var(--font-weight-semibold);
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Breadcrumb ── */
|
/* ── Breadcrumb ── */
|
||||||
.breadcrumb {
|
.breadcrumb {
|
||||||
max-width: var(--content-xl); margin: 0 auto;
|
max-width: var(--content-xl); margin: 0 auto;
|
||||||
@@ -309,6 +337,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
<!-- Country / Region selector -->
|
||||||
|
<div class="region-bar">
|
||||||
|
<div class="region-inner">
|
||||||
|
<span class="region-label">Región:</span>
|
||||||
|
<button class="region-btn is-active" data-region="north-america" onclick="setRegion('north-america')">🇲🇽 México, 🇺🇸 USA, 🇨🇦 Canadá</button>
|
||||||
|
<button class="region-btn" data-region="europe" onclick="setRegion('europe')">🇪🇺 Europa</button>
|
||||||
|
<button class="region-btn" data-region="asia" onclick="setRegion('asia')">🇯🇵 Asia</button>
|
||||||
|
<button class="region-btn" data-region="all" onclick="setRegion('all')">🌐 Todos</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="search-bar">
|
<div class="search-bar">
|
||||||
<div class="search-wrapper">
|
<div class="search-wrapper">
|
||||||
<input type="text" id="searchInput" placeholder="Buscar por numero de parte o nombre..." autocomplete="off">
|
<input type="text" id="searchInput" placeholder="Buscar por numero de parte o nombre..." autocomplete="off">
|
||||||
|
|||||||
@@ -16,10 +16,22 @@
|
|||||||
engine: null, // {id_mye, name, trim}
|
engine: null, // {id_mye, name, trim}
|
||||||
category: null, // {id, name}
|
category: null, // {id, name}
|
||||||
group: null, // {id, name}
|
group: null, // {id, name}
|
||||||
|
region: 'north-america',
|
||||||
page: 1,
|
page: 1,
|
||||||
totalPages: 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 API = '/api/catalog';
|
||||||
var content = document.getElementById('content');
|
var content = document.getElementById('content');
|
||||||
var breadcrumbEl = document.getElementById('breadcrumb');
|
var breadcrumbEl = document.getElementById('breadcrumb');
|
||||||
@@ -170,7 +182,7 @@
|
|||||||
state.level = 'brands';
|
state.level = 'brands';
|
||||||
renderBreadcrumb();
|
renderBreadcrumb();
|
||||||
content.innerHTML = '<div class="loading">Cargando marcas...</div>';
|
content.innerHTML = '<div class="loading">Cargando marcas...</div>';
|
||||||
fetch(API + '/brands')
|
fetch(API + '/brands?region=' + (state.region || 'north-america'))
|
||||||
.then(function (r) { return r.json(); })
|
.then(function (r) { return r.json(); })
|
||||||
.then(function (brands) {
|
.then(function (brands) {
|
||||||
var html = '<h2>Selecciona una Marca</h2><div class="nav-grid">';
|
var html = '<h2>Selecciona una Marca</h2><div class="nav-grid">';
|
||||||
|
|||||||
@@ -220,28 +220,54 @@ def enhanced_search_js():
|
|||||||
# Public Catalog API — No auth required
|
# Public Catalog API — No auth required
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
NORTH_AMERICA_BRANDS = (
|
REGION_BRANDS = {
|
||||||
'ACURA', 'AUDI', 'BMW', 'BUICK', 'CADILLAC', 'CHEVROLET', 'CHRYSLER',
|
'north-america': (
|
||||||
'DODGE', 'FIAT', 'FORD', 'GMC', 'HONDA', 'HYUNDAI', 'INFINITI',
|
'ACURA', 'AUDI', 'BMW', 'BUICK', 'CADILLAC', 'CHEVROLET', 'CHRYSLER',
|
||||||
'JAGUAR', 'JEEP', 'KIA', 'LAND ROVER', 'LEXUS', 'LINCOLN', 'MAZDA',
|
'DODGE', 'FIAT', 'FORD', 'GMC', 'HONDA', 'HYUNDAI', 'INFINITI',
|
||||||
'MERCEDES-BENZ', 'MINI', 'MITSUBISHI', 'NISSAN', 'PEUGEOT', 'PORSCHE',
|
'JAGUAR', 'JEEP', 'KIA', 'LAND ROVER', 'LEXUS', 'LINCOLN', 'MAZDA',
|
||||||
'RAM', 'RENAULT', 'SEAT', 'SUBARU', 'SUZUKI', 'TESLA', 'TOYOTA',
|
'MERCEDES-BENZ', 'MINI', 'MITSUBISHI', 'NISSAN', 'PEUGEOT', 'PORSCHE',
|
||||||
'VOLVO', 'VW',
|
'RAM', 'RENAULT', 'SEAT', 'SUBARU', 'SUZUKI', 'TESLA', 'TOYOTA',
|
||||||
)
|
'VOLVO', 'VW',
|
||||||
|
),
|
||||||
|
'europe': (
|
||||||
|
'ALFA ROMEO', 'ASTON MARTIN', 'AUDI', 'BENTLEY', 'BMW', 'CITROEN',
|
||||||
|
'DACIA', 'DS', 'FERRARI', 'FIAT', 'JAGUAR', 'LAMBORGHINI', 'LAND ROVER',
|
||||||
|
'MASERATI', 'MERCEDES-BENZ', 'MINI', 'OPEL', 'PEUGEOT', 'PORSCHE',
|
||||||
|
'RENAULT', 'ROLLS-ROYCE', 'SAAB', 'SEAT', 'SKODA', 'SMART',
|
||||||
|
'VAUXHALL', 'VOLVO', 'VW',
|
||||||
|
),
|
||||||
|
'asia': (
|
||||||
|
'ACURA', 'DAIHATSU', 'HONDA', 'HYUNDAI', 'INFINITI', 'ISUZU', 'KIA',
|
||||||
|
'LEXUS', 'MAZDA', 'MITSUBISHI', 'NISSAN', 'SSANGYONG', 'SUBARU',
|
||||||
|
'SUZUKI', 'TOYOTA',
|
||||||
|
),
|
||||||
|
}
|
||||||
|
NORTH_AMERICA_BRANDS = REGION_BRANDS['north-america']
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/catalog/brands')
|
@app.route('/api/catalog/brands')
|
||||||
def api_catalog_brands():
|
def api_catalog_brands():
|
||||||
|
region = request.args.get('region', 'north-america')
|
||||||
session = Session()
|
session = Session()
|
||||||
try:
|
try:
|
||||||
rows = session.execute(text("""
|
if region == 'all':
|
||||||
SELECT DISTINCT b.id_brand, b.name_brand
|
rows = session.execute(text("""
|
||||||
FROM brands b
|
SELECT DISTINCT b.id_brand, b.name_brand
|
||||||
JOIN models m ON m.brand_id = b.id_brand
|
FROM brands b
|
||||||
JOIN model_year_engine mye ON mye.model_id = m.id_model
|
JOIN models m ON m.brand_id = b.id_brand
|
||||||
WHERE b.name_brand = ANY(:brands)
|
JOIN model_year_engine mye ON mye.model_id = m.id_model
|
||||||
ORDER BY b.name_brand
|
ORDER BY b.name_brand
|
||||||
"""), {'brands': list(NORTH_AMERICA_BRANDS)}).mappings().all()
|
""")).mappings().all()
|
||||||
|
else:
|
||||||
|
brand_list = list(REGION_BRANDS.get(region, NORTH_AMERICA_BRANDS))
|
||||||
|
rows = session.execute(text("""
|
||||||
|
SELECT DISTINCT b.id_brand, b.name_brand
|
||||||
|
FROM brands b
|
||||||
|
JOIN models m ON m.brand_id = b.id_brand
|
||||||
|
JOIN model_year_engine mye ON mye.model_id = m.id_model
|
||||||
|
WHERE b.name_brand = ANY(:brands)
|
||||||
|
ORDER BY b.name_brand
|
||||||
|
"""), {'brands': brand_list}).mappings().all()
|
||||||
return jsonify([{'id_brand': r['id_brand'], 'name_brand': r['name_brand']} for r in rows])
|
return jsonify([{'id_brand': r['id_brand'], 'name_brand': r['name_brand']} for r in rows])
|
||||||
finally:
|
finally:
|
||||||
session.close()
|
session.close()
|
||||||
|
|||||||
Reference in New Issue
Block a user