feat(p): reverse catalog on OEM detail — your vehicles using this code

New "Bu kod kataloğunuzda" section lists the user's decoded vehicles
whose parts include the queried OEM code, each linking to the schema
page that shows it. Pure sase data (parts.oem_code → vehicles, indexed
exact match) — no TecDoc / vehicle-structure dependency.
GET /parts/oem-vehicles?code=.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-10 15:26:48 +03:00
parent c2dfa5cd2e
commit 8b7dc83bd2
3 changed files with 85 additions and 1 deletions

View File

@@ -7,6 +7,7 @@ import {
AlertCircle,
ArrowLeft,
Check,
ChevronRight,
Copy,
ImageOff,
PackageSearch,
@@ -39,6 +40,17 @@ interface POemResult {
truncated: boolean;
}
/** A decoded vehicle in the user's own catalog whose parts include this OEM
* code (reverse catalog — sase data, independent of the P snapshot). */
interface CatalogVehicle {
vehicleId: string;
brandName: string | null;
model: string | null;
year: number | null;
categoryId: string;
occurrences: number;
}
/** Normalise a code for search: strip non-alphanumerics + uppercase, so a query
* like "1j0 973" matches a stored "1J0 973 702". */
const normCode = (s: string) => s.toUpperCase().replace(/[^A-Z0-9]/g, "");
@@ -113,6 +125,13 @@ function OemDetailPage() {
queryFn: () => api.get<POemResult>(`/p/oem?code=${encodeURIComponent(code)}`),
});
// Reverse catalog: the user's own vehicles that use this OEM code (sase data).
const { data: catalogVehicles } = useQuery({
queryKey: ["oem-vehicles", code],
queryFn: () =>
api.get<CatalogVehicle[]>(`/parts/oem-vehicles?code=${encodeURIComponent(code)}`),
});
useEffect(() => {
if (data) {
capture("oem_detail_viewed", {
@@ -319,6 +338,36 @@ function OemDetailPage() {
)}
</div>
)}
{/* ─── Reverse catalog: your vehicles that use this code ───────────── */}
{catalogVehicles && catalogVehicles.length > 0 && (
<section className="space-y-3">
<div>
<h2 className="text-sm font-semibold">Bu kod kataloğunuzda</h2>
<p className="mt-0.5 text-xs text-muted-foreground">
Bu OEM kodunun geçtiği araçlarınız
</p>
</div>
<div className="grid gap-2 sm:grid-cols-2">
{catalogVehicles.map((v) => (
<Link
key={v.vehicleId}
to="/dashboard/vehicles/$id/categories/$categoryId"
params={{ id: v.vehicleId, categoryId: v.categoryId }}
className="flex items-center justify-between gap-2 rounded-xl border border-border bg-background p-3 transition-colors hover:bg-accent"
>
<span className="min-w-0">
<span className="block truncate text-sm font-medium">
{[v.brandName, v.model].filter(Boolean).join(" ") || "Araç"}
</span>
{v.year && <span className="text-xs text-muted-foreground">{v.year}</span>}
</span>
<ChevronRight className="size-4 shrink-0 text-muted-foreground" />
</Link>
))}
</div>
</section>
)}
</div>
);
}