diff --git a/src/client/components/ThreadTabs.tsx b/src/client/components/ThreadTabs.tsx
index 6c8edec..a365f3a 100644
--- a/src/client/components/ThreadTabs.tsx
+++ b/src/client/components/ThreadTabs.tsx
@@ -1,14 +1,17 @@
-interface ThreadTabsProps {
- active: "gear" | "planning";
- onChange: (tab: "gear" | "planning") => void;
+type TabKey = "gear" | "planning" | "setups";
+
+interface CollectionTabsProps {
+ active: TabKey;
+ onChange: (tab: TabKey) => void;
}
const tabs = [
{ key: "gear" as const, label: "My Gear" },
{ key: "planning" as const, label: "Planning" },
+ { key: "setups" as const, label: "Setups" },
];
-export function ThreadTabs({ active, onChange }: ThreadTabsProps) {
+export function CollectionTabs({ active, onChange }: CollectionTabsProps) {
return (
{tabs.map((tab) => (
diff --git a/src/client/routeTree.gen.ts b/src/client/routeTree.gen.ts
index 2cebe4c..4073734 100644
--- a/src/client/routeTree.gen.ts
+++ b/src/client/routeTree.gen.ts
@@ -10,7 +10,6 @@
import { Route as rootRouteImport } from './routes/__root'
import { Route as IndexRouteImport } from './routes/index'
-import { Route as SetupsIndexRouteImport } from './routes/setups/index'
import { Route as CollectionIndexRouteImport } from './routes/collection/index'
import { Route as ThreadsThreadIdRouteImport } from './routes/threads/$threadId'
import { Route as SetupsSetupIdRouteImport } from './routes/setups/$setupId'
@@ -20,11 +19,6 @@ const IndexRoute = IndexRouteImport.update({
path: '/',
getParentRoute: () => rootRouteImport,
} as any)
-const SetupsIndexRoute = SetupsIndexRouteImport.update({
- id: '/setups/',
- path: '/setups/',
- getParentRoute: () => rootRouteImport,
-} as any)
const CollectionIndexRoute = CollectionIndexRouteImport.update({
id: '/collection/',
path: '/collection/',
@@ -46,14 +40,12 @@ export interface FileRoutesByFullPath {
'/setups/$setupId': typeof SetupsSetupIdRoute
'/threads/$threadId': typeof ThreadsThreadIdRoute
'/collection/': typeof CollectionIndexRoute
- '/setups/': typeof SetupsIndexRoute
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
'/setups/$setupId': typeof SetupsSetupIdRoute
'/threads/$threadId': typeof ThreadsThreadIdRoute
'/collection': typeof CollectionIndexRoute
- '/setups': typeof SetupsIndexRoute
}
export interface FileRoutesById {
__root__: typeof rootRouteImport
@@ -61,30 +53,18 @@ export interface FileRoutesById {
'/setups/$setupId': typeof SetupsSetupIdRoute
'/threads/$threadId': typeof ThreadsThreadIdRoute
'/collection/': typeof CollectionIndexRoute
- '/setups/': typeof SetupsIndexRoute
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
- fullPaths:
- | '/'
- | '/setups/$setupId'
- | '/threads/$threadId'
- | '/collection/'
- | '/setups/'
+ fullPaths: '/' | '/setups/$setupId' | '/threads/$threadId' | '/collection/'
fileRoutesByTo: FileRoutesByTo
- to:
- | '/'
- | '/setups/$setupId'
- | '/threads/$threadId'
- | '/collection'
- | '/setups'
+ to: '/' | '/setups/$setupId' | '/threads/$threadId' | '/collection'
id:
| '__root__'
| '/'
| '/setups/$setupId'
| '/threads/$threadId'
| '/collection/'
- | '/setups/'
fileRoutesById: FileRoutesById
}
export interface RootRouteChildren {
@@ -92,7 +72,6 @@ export interface RootRouteChildren {
SetupsSetupIdRoute: typeof SetupsSetupIdRoute
ThreadsThreadIdRoute: typeof ThreadsThreadIdRoute
CollectionIndexRoute: typeof CollectionIndexRoute
- SetupsIndexRoute: typeof SetupsIndexRoute
}
declare module '@tanstack/react-router' {
@@ -104,13 +83,6 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof IndexRouteImport
parentRoute: typeof rootRouteImport
}
- '/setups/': {
- id: '/setups/'
- path: '/setups'
- fullPath: '/setups/'
- preLoaderRoute: typeof SetupsIndexRouteImport
- parentRoute: typeof rootRouteImport
- }
'/collection/': {
id: '/collection/'
path: '/collection'
@@ -140,7 +112,6 @@ const rootRouteChildren: RootRouteChildren = {
SetupsSetupIdRoute: SetupsSetupIdRoute,
ThreadsThreadIdRoute: ThreadsThreadIdRoute,
CollectionIndexRoute: CollectionIndexRoute,
- SetupsIndexRoute: SetupsIndexRoute,
}
export const routeTree = rootRouteImport
._addFileChildren(rootRouteChildren)
diff --git a/src/client/routes/__root.tsx b/src/client/routes/__root.tsx
index e66e8e2..97c0c3d 100644
--- a/src/client/routes/__root.tsx
+++ b/src/client/routes/__root.tsx
@@ -95,7 +95,8 @@ function RootLayout() {
const showFab =
isCollection &&
(!collectionSearch ||
- (collectionSearch as Record
).tab !== "planning");
+ !(collectionSearch as Record).tab ||
+ (collectionSearch as Record).tab === "gear");
// Show a minimal loading state while checking onboarding status
if (onboardingLoading) {
diff --git a/src/client/routes/collection/index.tsx b/src/client/routes/collection/index.tsx
index ac45278..dcd8cae 100644
--- a/src/client/routes/collection/index.tsx
+++ b/src/client/routes/collection/index.tsx
@@ -4,17 +4,19 @@ import { z } from "zod";
import { CategoryHeader } from "../../components/CategoryHeader";
import { CreateThreadModal } from "../../components/CreateThreadModal";
import { ItemCard } from "../../components/ItemCard";
+import { SetupCard } from "../../components/SetupCard";
import { ThreadCard } from "../../components/ThreadCard";
-import { ThreadTabs } from "../../components/ThreadTabs";
+import { CollectionTabs } from "../../components/ThreadTabs";
import { useCategories } from "../../hooks/useCategories";
import { useItems } from "../../hooks/useItems";
+import { useCreateSetup, useSetups } from "../../hooks/useSetups";
import { useThreads } from "../../hooks/useThreads";
import { useTotals } from "../../hooks/useTotals";
import { LucideIcon } from "../../lib/iconData";
import { useUIStore } from "../../stores/uiStore";
const searchSchema = z.object({
- tab: z.enum(["gear", "planning"]).catch("gear"),
+ tab: z.enum(["gear", "planning", "setups"]).catch("gear"),
});
export const Route = createFileRoute("/collection/")({
@@ -26,15 +28,21 @@ function CollectionPage() {
const { tab } = Route.useSearch();
const navigate = useNavigate();
- function handleTabChange(newTab: "gear" | "planning") {
+ function handleTabChange(newTab: "gear" | "planning" | "setups") {
navigate({ to: "/collection", search: { tab: newTab } });
}
return (
-
+
- {tab === "gear" ?
:
}
+ {tab === "gear" ? (
+
+ ) : tab === "planning" ? (
+
+ ) : (
+
+ )}
);
@@ -374,3 +382,87 @@ function PlanningView() {
);
}
+
+function SetupsView() {
+ const [newSetupName, setNewSetupName] = useState("");
+ const { data: setups, isLoading } = useSetups();
+ const createSetup = useCreateSetup();
+
+ function handleCreateSetup(e: React.FormEvent) {
+ e.preventDefault();
+ const name = newSetupName.trim();
+ if (!name) return;
+ createSetup.mutate({ name }, { onSuccess: () => setNewSetupName("") });
+ }
+
+ return (
+
+ {/* Create setup form */}
+
+
+ {/* Loading skeleton */}
+ {isLoading && (
+
+ {[1, 2].map((i) => (
+
+ ))}
+
+ )}
+
+ {/* Empty state */}
+ {!isLoading && (!setups || setups.length === 0) && (
+
+
+
+
+
+
+ No setups yet
+
+
+ Create one to plan your loadout.
+
+
+
+ )}
+
+ {/* Setup grid */}
+ {!isLoading && setups && setups.length > 0 && (
+
+ {setups.map((setup) => (
+
+ ))}
+
+ )}
+
+ );
+}
diff --git a/src/client/routes/index.tsx b/src/client/routes/index.tsx
index d94ebd0..f3ee600 100644
--- a/src/client/routes/index.tsx
+++ b/src/client/routes/index.tsx
@@ -45,7 +45,8 @@ function DashboardPage() {
]}
/>
setNewSetupName("") });
- }
-
- return (
-
- {/* Create setup form */}
-
-
- {/* Loading skeleton */}
- {isLoading && (
-
- {[1, 2].map((i) => (
-
- ))}
-
- )}
-
- {/* Empty state */}
- {!isLoading && (!setups || setups.length === 0) && (
-
-
-
-
-
-
- No setups yet
-
-
- Create one to plan your loadout.
-
-
-
- )}
-
- {/* Setup grid */}
- {!isLoading && setups && setups.length > 0 && (
-
- {setups.map((setup) => (
-
- ))}
-
- )}
-
- );
-}