feat(web): make vehicle info card readable instead of raw VIN codes

The Araç Bilgileri card showed only raw PL24 VIN-decoded codes (Satış tipi
1J10E4, Donanım 82, Motor kodu BCB…) and fully suppressed the friendlier DB
fields. Now it leads with the readable engine description + body type, then the
decoded codes; drops the Model/Model-yılı rows that duplicate the h2 header;
maps the known mojibake labels to clean Turkish; drops the uppercase transform
(which corrupted the Turkish dotted/dotless i); and lays out 2 cols on mobile
with long values spanning the full row.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-25 03:07:38 +03:00
parent 1c187847c4
commit 45ac5783b5

View File

@@ -142,7 +142,20 @@ function VehicleDetailPage() {
);
}
/** Extract vinfoBasic records from rawData, filtering out VIN. */
/** Known PL24 raw labels (missing Turkish chars) → clean Turkish. Unknown
* labels pass through unchanged. */
const LABEL_OVERRIDES: Record<string, string> = {
"Satis tipi": "Satış tipi",
Donanim: "Donanım",
"Aks tahrigi tanimi": "Aks tahriki tanımı",
"Dis rengi / Boya numarasi": "Dış renk / boya kodu",
"Model yili": "Model yılı",
};
/** Labels already shown in the page header — dropped to avoid duplication. */
const HEADER_LABELS = new Set(["model", "model yili", "model yılı"]);
/** Extract vinfoBasic records from rawData, dropping VIN and header dupes. */
function getVehicleAttributes(vehicle: any): Array<{ label: string; value: string }> {
const records = vehicle?.rawData?.raw?.segments?.vinfoBasic?.records;
if (!Array.isArray(records)) return [];
@@ -156,12 +169,28 @@ function getVehicleAttributes(vehicle: any): Array<{ label: string; value: strin
}))
.filter(
(attr: { label: string; value: string }) =>
attr.label && attr.value && attr.value.toLowerCase() !== vinLower,
);
attr.label &&
attr.value &&
attr.value.toLowerCase() !== vinLower &&
!HEADER_LABELS.has(attr.label.toLowerCase()),
)
.map((attr: { label: string; value: string }) => ({
label: LABEL_OVERRIDES[attr.label] ?? attr.label,
value: attr.value,
}));
}
function VehicleAttributes({ vehicle }: { vehicle: any }) {
const richAttrs = getVehicleAttributes(vehicle);
// 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: "Kasa", value: vehicle?.bodyType },
].filter((a): a is { label: string; value: string } => Boolean(a.value));
const fallbackAttrs = [
{ label: "Marka", value: vehicle?.brandName },
{ label: "Model", value: vehicle?.model },
@@ -171,26 +200,32 @@ function VehicleAttributes({ vehicle }: { vehicle: any }) {
{ label: "Kasa", value: vehicle?.bodyType },
].filter((a): a is { label: string; value: string } => Boolean(a.value));
// Prefer the rich VIN-decoded attributes when available; otherwise show DB
// fallback fields. Single layout for both — keeps semantics consistent.
const attrs = richAttrs.length > 0 ? richAttrs : fallbackAttrs;
// 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;
if (attrs.length === 0) {
return (
<p className="text-sm text-muted-foreground">
Bu araç için ayrıntı bilgisi bulunamadı.
</p>
<p className="text-sm text-muted-foreground">Bu araç için ayrıntı bilgisi bulunamadı.</p>
);
}
return (
<dl className="grid grid-cols-1 gap-x-6 gap-y-3 text-sm sm:grid-cols-2 md:grid-cols-3">
{attrs.map((attr) => (
<div key={attr.label} className="flex flex-col">
<dt className="text-xs uppercase tracking-wide text-muted-foreground">{attr.label}</dt>
<dd className="font-medium tabular-nums">{attr.value}</dd>
</div>
))}
<dl className="grid grid-cols-2 gap-x-6 gap-y-3 text-sm md:grid-cols-3">
{attrs.map((attr, i) => {
// Long values (e.g. the engine description) get the full row width so
// they stay readable instead of cramping a single grid cell.
const wide = attr.value.length > 40;
return (
<div
key={`${attr.label}-${i}`}
className={`flex flex-col ${wide ? "col-span-2 md:col-span-3" : ""}`}
>
<dt className="text-xs text-muted-foreground">{attr.label}</dt>
<dd className="font-medium tabular-nums">{attr.value}</dd>
</div>
);
})}
</dl>
);
}