fix(catalog/ford): disambiguate identical catCode buttons + relabel "Model Yılı" → "Varyant"

Two visible defects when a user picks a Ford model (variant selector step):

1. **N identical buttons.** Ford's `modelFamilyToModelList` gives every sub-catCode
   the same caption — just the family name. parseFordCatCodesForFamily returned
   `[{code:CBV,name:Kuga},{code:CBS,name:Kuga},{code:CTD,name:Kuga}]` for Kuga
   2012-2020. The UI rendered three indistinguishable "Kuga" pills with no way
   for the user to tell them apart. Same on Galaxy ("Galaxy"/"Galaxy"), every
   multi-catCode family.

   Fix: detect duplicate baseNames per family and graft a disambiguator —
   year first (friendliest), catCode as a last resort. Result:
   "Kuga (2013-2016)" / "Kuga (2016-2020)" / "Kuga (CTD)" — or, when year is
   present even for unique entries, always include it for a uniform look.

2. **Section title was lying.** UI label was `catalog.fordVariant.modelYear`
   = "Model Yılı" ("Model Year") but for Ford LEGACY these are catCodes
   (generation identifiers), not years. Rename the key value to "Varyant" /
   "Variant" — semantically correct for both Ford catCodes and Volvo years
   (Volvo flows through the same selector and its codes ARE years; "Varyant"
   covers both).

Cleared the affected Redis cache (`pl24:ford:config:*`) on dev so the next
hit fetches fresh disambiguated data; prod cache will roll over on its own
TTL after promote.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-06 03:12:20 +03:00
parent 37aa4dfd02
commit 9ccf0863f0
3 changed files with 28 additions and 14 deletions

View File

@@ -1712,25 +1712,39 @@ export class PL24FordLegacyService {
const models = familyKey ? familyMap[familyKey] : undefined;
if (!Array.isArray(models) || models.length === 0) return [];
const results: { code: string; name: string }[] = [];
// First pass: collect (catCode, baseCaption, year). Ford's modelFamilyToModelList
// typically gives every sub-catCode the SAME caption (just the family name like
// "Kuga" / "Galaxy"). Without disambiguation the UI shows N identical buttons.
const raw: Array<{ code: string; baseName: string; year: string }> = [];
for (const m2 of models) {
if (m2.gray === true) continue; // Skip unavailable sub-models
// catCode may be in identifier OR embedded in the URL
const catCode =
m2.identifier?.trim() || "" || m2.url?.match(/[?&]catCode=([^&"]+)/)?.[1] || "";
const catCode = m2.identifier?.trim() || m2.url?.match(/[?&]catCode=([^&"]+)/)?.[1] || "";
if (!catCode) continue;
// Build display name: caption if available, else family+year range
const caption = m2.caption?.trim();
const yearStr = m2.year?.replace(/[()]/g, "").trim();
const yearDisplay = yearStr ? ` (${yearStr.replace(",", "-")})` : "";
const name = caption || `${familyId}${yearDisplay}`;
results.push({ code: catCode, name });
const caption = m2.caption?.trim() || "";
const yearStr = m2.year?.replace(/[()]/g, "").trim() || "";
raw.push({ code: catCode, baseName: caption || familyId, year: yearStr });
}
return results;
// Count how many entries share each baseName — if the upstream uses the same
// caption for multiple sub-codes, we have to graft a disambiguator on.
const baseCounts = new Map<string, number>();
for (const r of raw) baseCounts.set(r.baseName, (baseCounts.get(r.baseName) ?? 0) + 1);
return raw.map(({ code, baseName, year }) => {
const isDup = (baseCounts.get(baseName) ?? 0) > 1;
const yearDisplay = year ? year.replace(",", "-") : "";
// Year is the friendliest disambiguator. catCode is the last-resort fallback
// since it's an internal identifier ("CBV") — better than two identical buttons.
if (isDup) {
return {
code,
name: yearDisplay ? `${baseName} (${yearDisplay})` : `${baseName} (${code})`,
};
}
return { code, name: yearDisplay ? `${baseName} (${yearDisplay})` : baseName };
});
}
/**

View File

@@ -213,7 +213,7 @@
"fordVariant": {
"title": "Select Model",
"subtitle": "Optional — use Show All to browse all variants",
"modelYear": "Model Year",
"modelYear": "Variant",
"engine": "Engine",
"gearbox": "Gearbox",
"showAll": "Show All",

View File

@@ -213,7 +213,7 @@
"fordVariant": {
"title": "Model Seçin",
"subtitle": "İsteğe bağlı — tüm varyantlar için Tümü seçeneğini kullanın",
"modelYear": "Model Yılı",
"modelYear": "Varyant",
"engine": "Motor",
"gearbox": "Şanzıman",
"showAll": "Tümü",