fix(catalog): auto-advance variant selectors instead of forcing an extra "Kataloga Git" click

After the user picks the last meaningful dimension, the next step is determined
— there is no decision left to make. Yet the Ford and PSA selectors stopped at
that point and waited for a "Kataloga Git" / "Proceed" button click. For Ford
specifically this was the worst case: LEGACY_FORD's upstream returns no engines
or gearboxes, so picking a year/catCode IS the whole flow — the user had to
click twice for one decision.

Auto-fire onSelect when the last available dimension is filled in:

- **Ford**: when year picked and (!hasEngines && !hasGearboxes); when engine
  picked and !hasGearboxes; when gearbox picked. Also: when config returns
  empty (no variants at all), fire onSelect("_nor_", "_nor_", "_nor_") via a
  one-shot useEffect so the selector skips itself rather than dead-ending on
  a "no config" notice with no actionable button.
- **PSA**: when gearbox is picked. Body→engine→gearbox is always 3 steps,
  picking gearbox is unambiguous intent. "Show All" buttons already auto-
  advanced — this just removes the asymmetry on the explicit-pick path.

Drop the now-dead Proceed button + handleProceed handler in both. P5
restriction selector already auto-advances on `isFinal` and stays untouched.

i18n keys catalog.fordVariant.proceed / catalog.psaVariant.proceed are kept
in case we ever re-introduce a confirmation button.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-06 03:39:13 +03:00
parent 9ccf0863f0
commit 88aa9271a3
2 changed files with 31 additions and 37 deletions

View File

@@ -1,9 +1,9 @@
import { api } from "@/lib/api-client";
import { useTranslation } from "@/lib/i18n";
import { Button, Card, CardContent, CardHeader, CardTitle } from "@sase/ui";
import { Card, CardContent, CardHeader, CardTitle } from "@sase/ui";
import { useQuery } from "@tanstack/react-query";
import { Loader2 } from "lucide-react";
import { useState } from "react";
import { useEffect, useRef, useState } from "react";
interface VariantItem {
code: string;
@@ -42,33 +42,42 @@ export function FordVariantSelector({ vehicleId, onSelect }: FordVariantSelector
const hasEngines = engines.length > 0;
const hasGearboxes = gearboxes.length > 0;
// Auto-advance: if a selection makes all required dimensions filled in, fire
// onSelect immediately instead of asking the user to click an extra button.
// For LEGACY_FORD this is almost always after the very first pick because the
// upstream returns no engines/gearboxes — one click should go to categories.
const handleYearSelect = (code: string) => {
setSelectedYear(code);
setSelectedEngine(null);
setSelectedGearbox(null);
if (!hasEngines && !hasGearboxes) {
onSelect(code, "_nor_", "_nor_");
}
};
const handleEngineSelect = (code: string) => {
setSelectedEngine(code);
setSelectedGearbox(null);
if (!hasGearboxes) {
onSelect(selectedYear ?? "_nor_", code, "_nor_");
}
};
const handleGearboxSelect = (code: string) => {
setSelectedGearbox(code);
onSelect(selectedYear ?? "_nor_", selectedEngine ?? "_nor_", code);
};
// No variants at all (config came back empty) — skip the selector outright
// instead of forcing the user to click a button that does nothing meaningful.
const hasAny = hasYears || hasEngines || hasGearboxes;
const canProceed =
!hasAny || // No variants available — can always proceed
((!hasYears || !!selectedYear) &&
(!hasEngines || !!selectedEngine) &&
(!hasGearboxes || !!selectedGearbox));
const handleProceed = () => {
if (!canProceed) return;
// When no variants, use "_nor_" so hasVariant=true and variant selector is skipped
onSelect(selectedYear ?? "_nor_", selectedEngine ?? "_nor_", selectedGearbox ?? "_nor_");
};
const autoSkipFired = useRef(false);
useEffect(() => {
if (!isLoading && config && !hasAny && !autoSkipFired.current) {
autoSkipFired.current = true;
onSelect("_nor_", "_nor_", "_nor_");
}
}, [isLoading, config, hasAny, onSelect]);
return (
<Card>
@@ -152,17 +161,11 @@ export function FordVariantSelector({ vehicleId, onSelect }: FordVariantSelector
</div>
)}
{/* No config available — allow skipping */}
{!hasYears && !hasEngines && !hasGearboxes && (
{/* No config available — autoSkip useEffect above will fire
onSelect("_nor_",…) shortly; show a brief notice meanwhile. */}
{!hasAny && (
<p className="text-sm text-muted-foreground">{t("catalog.fordVariant.noConfig")}</p>
)}
{/* Proceed button — only enabled when all required dimensions are selected */}
<div className="flex gap-2">
<Button onClick={handleProceed} disabled={!canProceed} className="w-full sm:w-auto">
{t("catalog.fordVariant.proceed")}
</Button>
</div>
</>
)}
</CardContent>

View File

@@ -1,6 +1,6 @@
import { api } from "@/lib/api-client";
import { useTranslation } from "@/lib/i18n";
import { Button, Card, CardContent, CardHeader, CardTitle } from "@sase/ui";
import { Card, CardContent, CardHeader, CardTitle } from "@sase/ui";
import { useQuery } from "@tanstack/react-query";
import { Loader2 } from "lucide-react";
import { useState } from "react";
@@ -66,6 +66,9 @@ export function PsaVariantSelector({ vehicleId, onSelect }: PsaVariantSelectorPr
setSelectedGearbox(null);
};
// Auto-advance on the final dimension — gearbox is always the last step in
// PSA's body→engine→gearbox flow, so picking one is unambiguous intent to
// proceed. No reason to make the user click an extra button.
const handleGearboxSelect = (code: string | "_all_") => {
if (code === "_all_") {
if (!selectedBody || !selectedEngine) return;
@@ -73,16 +76,11 @@ export function PsaVariantSelector({ vehicleId, onSelect }: PsaVariantSelectorPr
return;
}
setSelectedGearbox(code);
};
const handleProceed = () => {
if (selectedBody && selectedEngine && selectedGearbox) {
onSelect(selectedBody, selectedEngine, selectedGearbox);
if (selectedBody && selectedEngine) {
onSelect(selectedBody, selectedEngine, code);
}
};
const canProceed = selectedBody && selectedEngine && selectedGearbox;
return (
<Card>
<CardHeader>
@@ -198,13 +196,6 @@ export function PsaVariantSelector({ vehicleId, onSelect }: PsaVariantSelectorPr
)}
</div>
)}
{/* Proceed button */}
{canProceed && (
<Button onClick={handleProceed} className="w-full sm:w-auto">
{t("catalog.psaVariant.proceed")}
</Button>
)}
</CardContent>
</Card>
);