feat(web): source-aware vehicle attributes — surface pcat parameters
Vehicle info only ever read PL24's vinfoBasic segment, so emex/pcat/vin-api vehicles fell back to 3-4 sparse DB columns. Introduce a getDisplayAttributes dispatcher keyed on the decode source. First source added: parts-catalogs, which ships a structured pcatCar.parameters list (Year, Region, Steering, Transmission type/code, Engine, Type, Configuration…) — sorted by sortOrder with English names mapped to Turkish. A shared header-dedup drops the brand/model/year rows that already live in the h2 and the collapsed summary. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -266,30 +266,91 @@ function getVehicleAttributes(vehicle: any): Array<{ label: string; value: strin
|
||||
}));
|
||||
}
|
||||
|
||||
function VehicleAttributes({ vehicle }: { vehicle: any }) {
|
||||
const richAttrs = getVehicleAttributes(vehicle);
|
||||
type Attr = { label: string; value: string };
|
||||
|
||||
// Human-readable fields the VIN-code records don't carry (a decoded engine
|
||||
// description, body type). Prepended so the legible info leads and the raw
|
||||
// decoded codes follow — instead of the codes hiding the readable data.
|
||||
const readableExtras = [
|
||||
{ label: "Motor", value: vehicle?.engine },
|
||||
{ label: "Çekiş", value: vehicle?.rawData?.driveType },
|
||||
{ label: "Kasa", value: vehicle?.bodyType },
|
||||
].filter((a): a is { label: string; value: string } => Boolean(a.value));
|
||||
const isAttr = (a: { label: string; value: unknown }): a is Attr =>
|
||||
a.value != null && String(a.value).trim() !== "";
|
||||
|
||||
const fallbackAttrs = [
|
||||
/** Labels already conveyed by the page header (brand/model/year) or the
|
||||
* collapsed summary — dropped from the detail grid to avoid repetition. */
|
||||
const HEADER_DUPE = new Set([
|
||||
"marka",
|
||||
"model",
|
||||
"yıl",
|
||||
"yil",
|
||||
"year",
|
||||
"model yılı",
|
||||
"model yili",
|
||||
"car name",
|
||||
]);
|
||||
|
||||
const dropHeaderDupes = (attrs: Attr[]): Attr[] =>
|
||||
attrs.filter((a) => !HEADER_DUPE.has(a.label.toLowerCase()));
|
||||
|
||||
/** parts-catalogs (pcat) ships a structured parameter list with English names. */
|
||||
const PCAT_LABELS: Record<string, string> = {
|
||||
Year: "Yıl",
|
||||
Region: "Bölge",
|
||||
Steering: "Direksiyon",
|
||||
"Transmission type": "Şanzıman tipi",
|
||||
"Transmission code": "Şanzıman kodu",
|
||||
Engine: "Motor kodu",
|
||||
"Engine index": "Motor indeksi",
|
||||
Type: "Tip",
|
||||
Modification: "Tip",
|
||||
Configuration: "Donanım",
|
||||
"Car name": "Model",
|
||||
};
|
||||
|
||||
function fromPcat(vehicle: any): Attr[] {
|
||||
const params = vehicle?.rawData?.pcatCar?.parameters;
|
||||
if (!Array.isArray(params)) return [];
|
||||
return [...params]
|
||||
.sort((a: any, b: any) => (a?.sortOrder ?? 999) - (b?.sortOrder ?? 999))
|
||||
.map((p: any) => ({
|
||||
label: PCAT_LABELS[p?.name] ?? String(p?.name ?? "").trim(),
|
||||
value: String(p?.value ?? "").trim(),
|
||||
}))
|
||||
.filter((a: Attr) => Boolean(a.label && a.value));
|
||||
}
|
||||
|
||||
/** Plain DB columns — last resort when no source payload is recognised. */
|
||||
function getFallbackAttributes(vehicle: any): Attr[] {
|
||||
return [
|
||||
{ label: "Marka", value: vehicle?.brandName },
|
||||
{ label: "Model", value: vehicle?.model },
|
||||
{ label: "Yıl", value: vehicle?.year },
|
||||
{ label: "Motor", value: vehicle?.engine },
|
||||
{ label: "Vites", value: vehicle?.transmission },
|
||||
{ label: "Kasa", value: vehicle?.bodyType },
|
||||
].filter((a): a is { label: string; value: string } => Boolean(a.value));
|
||||
].filter(isAttr);
|
||||
}
|
||||
|
||||
// With VIN-decoded detail: lead with readable fields, then the decoded codes.
|
||||
// Without it: plain DB fields.
|
||||
const attrs = richAttrs.length > 0 ? [...readableExtras, ...richAttrs] : fallbackAttrs;
|
||||
/** Resolve the attribute list for the vehicle's decode source. Each catalog
|
||||
* ships its detail in a different shape; surface the richest one available. */
|
||||
function getDisplayAttributes(vehicle: any): Attr[] {
|
||||
// PL24 — readable extras lead, then the decoded VIN codes.
|
||||
const vinfo = getVehicleAttributes(vehicle);
|
||||
if (vinfo.length > 0) {
|
||||
const extras = [
|
||||
{ label: "Motor", value: vehicle?.engine },
|
||||
{ label: "Çekiş", value: vehicle?.rawData?.driveType },
|
||||
{ label: "Kasa", value: vehicle?.bodyType },
|
||||
].filter(isAttr);
|
||||
return [...extras, ...vinfo];
|
||||
}
|
||||
|
||||
// parts-catalogs — structured parameter list.
|
||||
if (vehicle?.source === "parts-catalogs") {
|
||||
const a = dropHeaderDupes(fromPcat(vehicle));
|
||||
if (a.length > 0) return a;
|
||||
}
|
||||
|
||||
return dropHeaderDupes(getFallbackAttributes(vehicle));
|
||||
}
|
||||
|
||||
function VehicleAttributes({ vehicle }: { vehicle: any }) {
|
||||
const attrs = getDisplayAttributes(vehicle);
|
||||
|
||||
if (attrs.length === 0) {
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user