Implements Task 18: App Layout + Club-Switcher + Auth Guard New components: - TenantContext: Manages activeClubId state with TanStack Query - QueryProvider: TanStack Query client wrapper (60s stale time) - AuthGuard: Auth + tenant redirect logic (unauthenticated → /login) - ClubSwitcher: shadcn DropdownMenu for switching clubs - SignOutButton: Simple sign out button - Protected layout: Sidebar navigation + top bar with ClubSwitcher Key features: - Fetches clubs from /api/clubs/me - Auto-loads activeClubId from localStorage - Sets X-Tenant-Id cookie on club switch - Invalidates all queries on club switch - Redirect logic: unauthenticated → /login, 0 clubs → message, 1 club → auto-select, >1 clubs + no active → /select-club TDD: - 6 AuthGuard tests (loading, unauthenticated, 0 clubs, 1 club, multiple clubs, authenticated) - 3 ClubSwitcher tests (renders current club, lists all clubs, calls setActiveClub on selection) Dependencies: - Added @tanstack/react-query All tests pass (25/25). Build succeeds.
22 lines
502 B
TypeScript
22 lines
502 B
TypeScript
'use client';
|
|
|
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
import { ReactNode, useState } from 'react';
|
|
|
|
export function QueryProvider({ children }: { children: ReactNode }) {
|
|
const [queryClient] = useState(() => new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
staleTime: 60 * 1000,
|
|
refetchOnWindowFocus: false,
|
|
},
|
|
},
|
|
}));
|
|
|
|
return (
|
|
<QueryClientProvider client={queryClient}>
|
|
{children}
|
|
</QueryClientProvider>
|
|
);
|
|
}
|