dev #46

Merged
root merged 13 commits from dev into main 2026-05-25 04:49:05 +03:00
Showing only changes of commit 08aa3ac88f - Show all commits

View File

@@ -3,13 +3,13 @@ import { CategoryGrid } from "@/components/categories/category-grid";
import { CategoryTree } from "@/components/categories/category-tree";
import { CategoryViewToggle } from "@/components/categories/category-view-toggle";
import { CarBrandLogo } from "@/components/ui/car-brand-logo";
import { api } from "@/lib/api-client";
import { ApiError, api } from "@/lib/api-client";
import { getUserSettings, setUserSetting } from "@/lib/user-settings";
import { Card, CardContent, CardHeader, CardTitle } from "@sase/ui";
import { Skeleton } from "@sase/ui";
import { Button } from "@sase/ui";
import { useQuery } from "@tanstack/react-query";
import { createFileRoute } from "@tanstack/react-router";
import { createFileRoute, useCanGoBack, useNavigate, useRouter } from "@tanstack/react-router";
import { ArrowLeft } from "lucide-react";
import { useState } from "react";
@@ -29,10 +29,31 @@ function VehicleDetailPage() {
setUserSetting("categoryViewMode", mode);
};
const { data: vehicle, isLoading: vehicleLoading } = useQuery({
const router = useRouter();
const canGoBack = useCanGoBack();
const navigate = useNavigate();
// Go back within the app; if the page was opened from a deep link (no app
// history), fall back to search instead of leaving the site.
const handleBack = () => {
if (canGoBack) router.history.back();
else navigate({ to: "/dashboard/search" });
};
const {
data: vehicle,
isLoading: vehicleLoading,
isError: vehicleError,
error: vehicleErrorObj,
refetch: refetchVehicle,
isFetching: vehicleFetching,
} = useQuery({
queryKey: ["vehicle", id],
queryFn: () => api.get<any>(`/vehicles/${id}`),
enabled: !!id,
// A missing vehicle (404) is final — don't burn retries before showing the
// not-found state. Transient errors still retry.
retry: (count, err) => !(err instanceof ApiError && err.status === 404) && count < 2,
});
const { data: categoryTree, isLoading: categoriesLoading } = useQuery({
@@ -78,6 +99,60 @@ function VehicleDetailPage() {
);
}
if (vehicleError) {
const is404 = vehicleErrorObj instanceof ApiError && vehicleErrorObj.status === 404;
return (
<div className="space-y-6">
<div className="flex items-center gap-3">
<Button
variant="ghost"
size="icon"
onClick={handleBack}
title="Geri dön"
data-faro-user-action-name="vehicle-back"
>
<ArrowLeft className="h-4 w-4" />
</Button>
<h2 className="text-xl font-bold">{is404 ? "Araç bulunamadı" : "Araç yüklenemedi"}</h2>
</div>
<div
role="alert"
className="flex flex-col items-start gap-3 rounded-lg border border-destructive/40 bg-destructive/5 p-5 text-sm"
>
<div>
<p className="font-medium text-destructive">
{is404 ? "Bu araç kaydı bulunamadı" : "Araç bilgileri yüklenemedi"}
</p>
<p className="mt-1 text-muted-foreground">
{is404
? "Bağlantı geçersiz olabilir ya da kayıt kaldırılmış olabilir."
: vehicleErrorObj instanceof Error
? vehicleErrorObj.message
: "Veriler yüklenirken bir hata oluştu."}
</p>
</div>
<div className="flex flex-wrap gap-2">
{!is404 && (
<Button
type="button"
size="sm"
variant="outline"
onClick={() => refetchVehicle()}
disabled={vehicleFetching}
data-faro-user-action-name="vehicle-retry"
>
{vehicleFetching ? "Yükleniyor…" : "Tekrar dene"}
</Button>
)}
<Button type="button" size="sm" variant="ghost" onClick={handleBack}>
Geri dön
</Button>
</div>
</div>
</div>
);
}
return (
<div className="space-y-6">
{/* Header */}
@@ -85,7 +160,7 @@ function VehicleDetailPage() {
<Button
variant="ghost"
size="icon"
onClick={() => window.history.back()}
onClick={handleBack}
title="Geri dön"
data-faro-user-action-name="vehicle-back"
>