From c1fcc9d5c45f5c327fcd63ed8d6129c7ca0f3920 Mon Sep 17 00:00:00 2001 From: Matt Date: Wed, 13 May 2026 12:02:10 +0200 Subject: [PATCH] fix(audit-wave-9): route-level loading skeletons across dashboard Add a default [portSlug]/loading.tsx that covers all 72 nested routes that previously rendered nothing during the cold-load gap. Uses the existing PageSkeleton (page-header + table-skeleton) so the empty-header flash on direct-URL visits / tab navigations is gone. Add tailored loading.tsx for the four other tab-strip detail surfaces so their initial paint mirrors the real page structure (header strip, pipeline stepper for interests, tab strip, two-column overview): - yachts/[yachtId]/loading.tsx - companies/[companyId]/loading.tsx - interests/[interestId]/loading.tsx - berths/[berthId]/loading.tsx (clients/[clientId]/loading.tsx already existed.) Closes ui/ux M3. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../[portSlug]/berths/[berthId]/loading.tsx | 29 +++++++++++++++++ .../companies/[companyId]/loading.tsx | 29 +++++++++++++++++ .../interests/[interestId]/loading.tsx | 31 +++++++++++++++++++ src/app/(dashboard)/[portSlug]/loading.tsx | 17 ++++++++++ .../[portSlug]/yachts/[yachtId]/loading.tsx | 29 +++++++++++++++++ 5 files changed, 135 insertions(+) create mode 100644 src/app/(dashboard)/[portSlug]/berths/[berthId]/loading.tsx create mode 100644 src/app/(dashboard)/[portSlug]/companies/[companyId]/loading.tsx create mode 100644 src/app/(dashboard)/[portSlug]/interests/[interestId]/loading.tsx create mode 100644 src/app/(dashboard)/[portSlug]/loading.tsx create mode 100644 src/app/(dashboard)/[portSlug]/yachts/[yachtId]/loading.tsx diff --git a/src/app/(dashboard)/[portSlug]/berths/[berthId]/loading.tsx b/src/app/(dashboard)/[portSlug]/berths/[berthId]/loading.tsx new file mode 100644 index 00000000..c5f6df2b --- /dev/null +++ b/src/app/(dashboard)/[portSlug]/berths/[berthId]/loading.tsx @@ -0,0 +1,29 @@ +import { Skeleton } from '@/components/ui/skeleton'; +import { CardSkeleton } from '@/components/shared/loading-skeleton'; + +export default function Loading() { + return ( +
+
+
+ + + +
+
+ + +
+
+
+ {Array.from({ length: 4 }).map((_, i) => ( + + ))} +
+
+ + +
+
+ ); +} diff --git a/src/app/(dashboard)/[portSlug]/companies/[companyId]/loading.tsx b/src/app/(dashboard)/[portSlug]/companies/[companyId]/loading.tsx new file mode 100644 index 00000000..cb6a8929 --- /dev/null +++ b/src/app/(dashboard)/[portSlug]/companies/[companyId]/loading.tsx @@ -0,0 +1,29 @@ +import { Skeleton } from '@/components/ui/skeleton'; +import { CardSkeleton } from '@/components/shared/loading-skeleton'; + +export default function Loading() { + return ( +
+
+
+ + +
+
+ + + +
+
+
+ {Array.from({ length: 6 }).map((_, i) => ( + + ))} +
+
+ + +
+
+ ); +} diff --git a/src/app/(dashboard)/[portSlug]/interests/[interestId]/loading.tsx b/src/app/(dashboard)/[portSlug]/interests/[interestId]/loading.tsx new file mode 100644 index 00000000..ecfff961 --- /dev/null +++ b/src/app/(dashboard)/[portSlug]/interests/[interestId]/loading.tsx @@ -0,0 +1,31 @@ +import { Skeleton } from '@/components/ui/skeleton'; +import { CardSkeleton } from '@/components/shared/loading-skeleton'; + +export default function Loading() { + return ( +
+
+
+ + +
+
+ + + +
+
+ {/* Pipeline-stepper row */} + +
+ {Array.from({ length: 7 }).map((_, i) => ( + + ))} +
+
+ + +
+
+ ); +} diff --git a/src/app/(dashboard)/[portSlug]/loading.tsx b/src/app/(dashboard)/[portSlug]/loading.tsx new file mode 100644 index 00000000..02291422 --- /dev/null +++ b/src/app/(dashboard)/[portSlug]/loading.tsx @@ -0,0 +1,17 @@ +import { PageSkeleton } from '@/components/shared/loading-skeleton'; + +/** + * Default route-level loading UI for every page under `(dashboard)/[portSlug]/...`. + * + * Renders while the server component resolves the session, port config, + * and the client component bootstraps its initial query. Replaces the + * empty-header flash on cold direct-URL visits and tab navigations. + * + * Individual routes can still ship their own `loading.tsx` for a more + * tailored skeleton (see `clients/[clientId]/loading.tsx` which mirrors + * the detail page's tab strip). When that file exists Next.js uses it + * in place of this default. + */ +export default function Loading() { + return ; +} diff --git a/src/app/(dashboard)/[portSlug]/yachts/[yachtId]/loading.tsx b/src/app/(dashboard)/[portSlug]/yachts/[yachtId]/loading.tsx new file mode 100644 index 00000000..4ceb9c65 --- /dev/null +++ b/src/app/(dashboard)/[portSlug]/yachts/[yachtId]/loading.tsx @@ -0,0 +1,29 @@ +import { Skeleton } from '@/components/ui/skeleton'; +import { CardSkeleton } from '@/components/shared/loading-skeleton'; + +export default function Loading() { + return ( +
+
+
+ + +
+
+ + + +
+
+
+ {Array.from({ length: 5 }).map((_, i) => ( + + ))} +
+
+ + +
+
+ ); +}