Files
GearBox/src/client/routes/collection/index.tsx
Jean-Luc Makiola 3fc737c872 fix: add tab navigation to collection page and skip 404 retries
Adds Gear/Planning/Setups pill tabs to the collection page so users
can switch tabs without going back to the dashboard. Also skips
React Query retries on 404 responses for immediate error display.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 18:31:57 +02:00

83 lines
2.2 KiB
TypeScript

import { createFileRoute, Link } from "@tanstack/react-router";
import { AnimatePresence, motion } from "framer-motion";
import { useRef } from "react";
import { z } from "zod";
import { CollectionView } from "../../components/CollectionView";
import { PlanningView } from "../../components/PlanningView";
import { SetupsView } from "../../components/SetupsView";
const searchSchema = z.object({
tab: z.enum(["gear", "planning", "setups"]).catch("gear"),
});
export const Route = createFileRoute("/collection/")({
validateSearch: searchSchema,
component: CollectionPage,
});
const TAB_ORDER = ["gear", "planning", "setups"] as const;
const TAB_LABELS: Record<(typeof TAB_ORDER)[number], string> = {
gear: "Gear",
planning: "Planning",
setups: "Setups",
};
const slideVariants = {
enter: (dir: number) => ({ x: `${dir * 15}%`, opacity: 0 }),
center: { x: 0, opacity: 1 },
exit: (dir: number) => ({ x: `${dir * -15}%`, opacity: 0 }),
};
function CollectionPage() {
const { tab } = Route.useSearch();
const prevTab = useRef(tab);
const direction =
TAB_ORDER.indexOf(tab) >= TAB_ORDER.indexOf(prevTab.current) ? 1 : -1;
prevTab.current = tab;
return (
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6 overflow-x-hidden">
{/* Tab navigation */}
<div className="flex justify-center mb-6">
<div className="flex bg-gray-100 rounded-full p-0.5 gap-0.5">
{TAB_ORDER.map((t) => (
<Link
key={t}
to="/collection"
search={{ tab: t }}
className={`px-4 py-1.5 text-sm font-medium rounded-full transition-colors ${
tab === t
? "bg-gray-700 text-white"
: "text-gray-600 hover:bg-gray-200"
}`}
>
{TAB_LABELS[t]}
</Link>
))}
</div>
</div>
<AnimatePresence mode="wait" initial={false} custom={direction}>
<motion.div
key={tab}
custom={direction}
variants={slideVariants}
initial="enter"
animate="center"
exit="exit"
transition={{ duration: 0.12, ease: "easeInOut" }}
>
{tab === "gear" ? (
<CollectionView />
) : tab === "planning" ? (
<PlanningView />
) : (
<SetupsView />
)}
</motion.div>
</AnimatePresence>
</div>
);
}