fix(F17 ext): apply DetailNotFound to clients/yachts/companies/berths
Refactored the interest-detail 404 pattern into a reusable `<DetailNotFound>` component and applied it to the four other entity detail pages. Pre-fix, navigating to a wrong-port or stale entity URL silently rendered the layout shell with empty tabs on: - /[portSlug]/clients/[id] - /[portSlug]/yachts/[id] - /[portSlug]/companies/[id] - /[portSlug]/berths/[id] All four now route a 404/403 response into an explicit "<Entity> not found" / "No access" EmptyState with a back-to-list CTA, and the TanStack Query retry policy short-circuits 404/403s so the empty state appears immediately. 1373/1373 vitest pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,8 +2,10 @@
|
||||
|
||||
import { useEffect } from 'react';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useParams } from 'next/navigation';
|
||||
|
||||
import { DetailLayout } from '@/components/shared/detail-layout';
|
||||
import { DetailNotFound } from '@/components/shared/detail-not-found';
|
||||
import { useMobileChrome } from '@/components/layout/mobile/mobile-layout-provider';
|
||||
import { YachtDetailHeader } from '@/components/yachts/yacht-detail-header';
|
||||
import { getYachtTabs } from '@/components/yachts/yacht-tabs';
|
||||
@@ -43,9 +45,17 @@ interface YachtDetailProps {
|
||||
}
|
||||
|
||||
export function YachtDetail({ yachtId, currentUserId }: YachtDetailProps) {
|
||||
const { data, isLoading } = useQuery<YachtData>({
|
||||
const params = useParams<{ portSlug: string }>();
|
||||
const portSlug = params?.portSlug ?? '';
|
||||
|
||||
const { data, isLoading, error } = useQuery<YachtData>({
|
||||
queryKey: ['yachts', yachtId],
|
||||
queryFn: () => apiFetch<{ data: YachtData }>(`/api/v1/yachts/${yachtId}`).then((r) => r.data),
|
||||
retry: (failureCount, err) => {
|
||||
const status = (err as { status?: number } | null | undefined)?.status;
|
||||
if (status === 404 || status === 403) return false;
|
||||
return failureCount < 2;
|
||||
},
|
||||
});
|
||||
|
||||
const { setChrome } = useMobileChrome();
|
||||
@@ -66,6 +76,18 @@ export function YachtDetail({ yachtId, currentUserId }: YachtDetailProps) {
|
||||
],
|
||||
});
|
||||
|
||||
if (error && !isLoading) {
|
||||
const status = (error as { status?: number } | null | undefined)?.status;
|
||||
return (
|
||||
<DetailNotFound
|
||||
entity="yacht"
|
||||
backHref={`/${portSlug}/yachts`}
|
||||
backLabel="Back to yachts"
|
||||
status={status}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const tabs = data ? getYachtTabs({ yachtId, currentUserId, yacht: data }) : [];
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user