feat: complete session — catalog, marketplace, WhatsApp, peer-to-peer, install scripts

Major features:
- Pixel-Perfect glassmorphism design (landing + POS + public catalog)
- OEM/Local catalog toggle with Nexpart taxonomy (14 groups, 108 subgroups, 558 part types)
- Marketplace B2B Phase 1 (bodegas, POs, status machine, WA+email notifications)
- Peer-to-peer inventory (multi-instance, LAN discovery)
- WhatsApp: photo→Vision AI, voice→Whisper, conversational quotations
- Smart unified search (VIN/plate/part_number/keyword auto-detect)
- Shop Supplies tab (vehicle-independent parts)
- Chatbot AI fallback chain (5 models) + response cache
- CSV inventory import tool + setup_instance.sh installer
- Tablet-responsive CSS + sidebar toggle
- Filters, export CSV, employee edit, business data save
- Quotation system (WA→POS) with auto-print on confirmation
- Live stats on landing page

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-18 05:35:53 +00:00
parent 6b097614a0
commit e95f7cf684
54 changed files with 11226 additions and 1422 deletions

View File

@@ -6,6 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Catalogo — Nexus Autoparts POS</title>
<link rel="stylesheet" href="/pos/static/css/tokens.css" />
<link rel="stylesheet" href="/pos/static/css/pos-glass.css" />
<link rel="stylesheet" href="/pos/static/css/chat.css" />
<link rel="stylesheet" href="/pos/static/css/onboarding.css" />
<link rel="manifest" href="/pos/static/pwa/manifest.json" />
@@ -106,6 +107,41 @@
.header-actions { display: flex; align-items: center; gap: var(--space-3); }
/* ── Catalog mode toggle (OEM / Local) ── */
.mode-toggle {
display: inline-flex;
padding: 3px;
background: var(--glass-bg);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
border: 1px dashed var(--glass-border);
border-radius: var(--radius-md);
gap: 2px;
flex-shrink: 0;
}
.mode-toggle button {
background: transparent;
border: none;
color: var(--color-text-muted);
padding: 4px 12px;
border-radius: calc(var(--radius-md) - 3px);
font-family: var(--font-mono);
font-size: var(--text-caption);
font-weight: var(--font-weight-semibold);
text-transform: uppercase;
letter-spacing: var(--tracking-wider);
cursor: pointer;
transition: all 0.2s var(--ease-out);
}
.mode-toggle button:hover {
color: var(--color-text-accent);
}
.mode-toggle button.is-active {
background: var(--color-primary-muted);
color: var(--color-text-accent);
box-shadow: 0 0 12px var(--glow-color-soft);
}
/* Search bar */
.search-bar {
display: flex; align-items: center; gap: var(--space-2);
@@ -233,8 +269,39 @@
.part-card__body { padding: var(--space-3) var(--space-4); flex: 1; }
.part-card__oem { font-family: var(--font-mono, monospace); font-size: var(--text-caption); color: var(--color-primary); font-weight: var(--font-weight-semibold); margin-bottom: var(--space-1); }
.part-card__oem-sub { font-family: var(--font-mono, monospace); font-size: 10px; color: var(--color-text-muted); font-weight: var(--font-weight-regular); }
.part-card__name { font-size: var(--text-body-sm); font-weight: var(--font-weight-semibold); color: var(--color-text-primary); line-height: 1.3; }
/* Local mode — manufacturer badge + priority tier */
.part-card__manu {
display: inline-flex; align-items: center; gap: 4px;
padding: 2px 8px; margin-bottom: var(--space-1);
background: var(--glass-bg);
border: 1px solid var(--glass-border);
border-radius: var(--radius-sm);
font-size: 10px;
font-weight: var(--font-weight-bold);
text-transform: uppercase;
letter-spacing: var(--tracking-wider);
color: var(--color-text-secondary);
}
.part-card__manu .manu-tier {
color: var(--color-primary);
font-size: 11px;
}
.part-card--tier1 {
border-color: var(--color-border-accent);
box-shadow: 0 0 12px var(--glow-color-soft);
}
.part-card--tier1 .part-card__manu {
background: var(--color-primary-muted);
border-color: var(--color-border-accent);
color: var(--color-text-accent);
}
.part-card--tier2 .part-card__manu {
border-color: var(--color-border-strong);
}
.part-card__footer {
padding: var(--space-3) var(--space-4);
border-top: 1px solid var(--color-border);
@@ -592,6 +659,11 @@
<span class="breadcrumb__current">Catalogo</span>
</nav>
<div class="header-actions" style="position:relative;">
<div class="mode-toggle" id="modeToggle" title="Cambiar entre catalogo OEM (TecDoc), marcas locales y consumibles">
<button data-mode="oem" onclick="CatalogApp.setMode('oem')">OEM</button>
<button data-mode="local" onclick="CatalogApp.setMode('local')">Local</button>
<button data-mode="supplies" onclick="CatalogApp.setMode('supplies')" title="Aceites, quimicos, herramientas — sin vehiculo">Supplies</button>
</div>
<div class="search-bar" id="searchBar">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="M21 21l-4.35-4.35"/></svg>
<input type="text" id="searchInput" placeholder="Buscar por numero de parte o nombre... (F1)" autocomplete="off" />
@@ -751,6 +823,7 @@
<script src="/pos/static/js/i18n.js"></script>
<script src="/pos/static/js/kiosk.js"></script>
<script src="/pos/static/js/app-init.js"></script>
<script src="/pos/static/js/pos-utils.js"></script>
<script src="/pos/static/js/sidebar.js"></script>
<script src="/pos/static/js/catalog.js"></script>
<script src="/pos/static/js/offline-banner.js"></script>