feat(catalog): brand search, parts pagination, and parts search

Backend:
- Add 'search' param to /brand-parts endpoint (filters oem_part_number and name via ILIKE)
- Keep count query accurate with search filter

Frontend (brand-catalog.js):
- Brand search input: filters 619 brands locally while typing
- Parts pagination: Previous/Next buttons with page counter (50 per page)
- Parts search within category: search input + Enter key triggers backend search
- Visual polish: stock badges, empty-state messages, responsive layout
- Loading states and breadcrumbs improved
This commit is contained in:
2026-05-14 21:23:02 +00:00
parent e61063bdd7
commit 9da14e40da
2 changed files with 155 additions and 35 deletions

View File

@@ -663,9 +663,10 @@ def brand_categories():
@catalog_bp.route('/brand-parts', methods=['GET'])
@require_auth('catalog.view')
def brand_parts():
"""Return parts for a given vehicle brand + category."""
"""Return parts for a given vehicle brand + category, optionally filtered by search term."""
brand = request.args.get('brand', '')
category_id = request.args.get('category_id', type=int)
search = request.args.get('search', '').strip()
limit = request.args.get('limit', 50, type=int)
offset = request.args.get('offset', 0, type=int)
@@ -675,13 +676,22 @@ def brand_parts():
def _query(master, tenant, branch_id):
cur = master.cursor()
try:
# Get parts from the brand catalog
# Build dynamic filters
params = [brand]
cat_filter = ""
search_filter = ""
if category_id:
cat_filter = "AND pc.id_part_category = %s"
params.append(category_id)
if search:
search_filter = "AND (p.oem_part_number ILIKE %s OR COALESCE(NULLIF(p.name_es, ''), p.name_part) ILIKE %s)"
like_term = f"%{search}%"
params.extend([like_term, like_term])
# Get parts from the brand catalog
query_params = list(params)
cur.execute(f"""
SELECT DISTINCT p.id_part, p.oem_part_number,
COALESCE(NULLIF(p.name_es, ''), p.name_part) as name,
@@ -693,9 +703,10 @@ def brand_parts():
JOIN part_categories pc ON pc.id_part_category = pg.category_id
WHERE pvp.name_brand = %s
{cat_filter}
{search_filter}
ORDER BY p.id_part
LIMIT %s OFFSET %s
""", params + [limit, offset])
""", query_params + [limit, offset])
part_rows = cur.fetchall()
part_ids = [r[0] for r in part_rows]
@@ -709,6 +720,7 @@ def brand_parts():
JOIN part_categories pc ON pc.id_part_category = pg.category_id
WHERE pvp.name_brand = %s
{cat_filter}
{search_filter}
""", params)
total = cur.fetchone()[0]
@@ -738,6 +750,7 @@ def brand_parts():
return jsonify({
'brand': brand,
'category_id': category_id,
'search': search,
'items': items,
'total': total,
'limit': limit,