{label}
++ {detail} +
+diff --git a/AGENTS.md b/AGENTS.md index c8ebca3..d0e1082 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -251,6 +251,9 @@ Do not bypass type errors using assertions simply to make the compiler pass. Prefer inference when the resulting type remains clear. +In object type and interface declarations, list required properties before +optional properties. + Avoid duplicating types that can safely be inferred from Zod schemas or other authoritative definitions. diff --git a/apps/web/src/features/auth/current-user.query.ts b/apps/web/src/features/auth/current-user.query.ts index 62aab22..1516bed 100644 --- a/apps/web/src/features/auth/current-user.query.ts +++ b/apps/web/src/features/auth/current-user.query.ts @@ -11,24 +11,36 @@ export const currentUserQueryOptions = queryOptions({ retry: false, }); -export type AuthenticationStatus = - 'loading' | 'anonymous' | 'authenticated' | 'error'; - export function useCurrentUser() { const query = useQuery(currentUserQueryOptions); - let authenticationStatus: AuthenticationStatus = 'anonymous'; if (query.isPending) { - authenticationStatus = 'loading'; - } else if (query.isError) { - authenticationStatus = 'error'; - } else if (query.data.user) { - authenticationStatus = 'authenticated'; + return { + ...query, + authenticationStatus: 'loading' as const, + user: null, + }; + } + + if (query.isError) { + return { + ...query, + authenticationStatus: 'error' as const, + user: null, + }; + } + + if (!query.data.user) { + return { + ...query, + authenticationStatus: 'anonymous' as const, + user: null, + }; } return { ...query, - authenticationStatus, - user: query.data?.user ?? null, + authenticationStatus: 'authenticated' as const, + user: query.data.user, }; } diff --git a/apps/web/src/features/dashboard/application-shell.test.tsx b/apps/web/src/features/dashboard/application-shell.test.tsx index 3395336..6247f80 100644 --- a/apps/web/src/features/dashboard/application-shell.test.tsx +++ b/apps/web/src/features/dashboard/application-shell.test.tsx @@ -24,6 +24,8 @@ describe('application shell', () => { ); expect(screen.getByRole('heading', { name: 'Dashboard' })).toBeVisible(); + expect(screen.getAllByText('Guest')).toHaveLength(2); + expect(screen.getAllByText('Progress is temporary')).toHaveLength(2); const navigationRegions = screen.getAllByRole('navigation', { name: /primary navigation/i, diff --git a/apps/web/src/features/dashboard/application-shell.tsx b/apps/web/src/features/dashboard/application-shell.tsx index bcb5d02..b3f476a 100644 --- a/apps/web/src/features/dashboard/application-shell.tsx +++ b/apps/web/src/features/dashboard/application-shell.tsx @@ -4,6 +4,7 @@ import { History, LayoutDashboard, Settings, + UserRound, type LucideIcon, } from 'lucide-react'; import { Link } from '@tanstack/react-router'; @@ -11,6 +12,7 @@ import type { ReactNode } from 'react'; import wordmarkUrl from '../../assets/goforlift-wordmark.png'; import { cn } from '../../lib/utils'; +import type { ApplicationIdentity } from './dashboard-access-boundary'; const navigationItems = [ { href: '/dashboard', icon: LayoutDashboard, label: 'Dashboard' }, @@ -21,9 +23,13 @@ const navigationItems = [ type ApplicationShellProps = { children: ReactNode; + identity: ApplicationIdentity; }; -export function ApplicationShell({ children }: ApplicationShellProps) { +export function ApplicationShell({ + children, + identity, +}: ApplicationShellProps) { return (
{label}
++ {detail} +
+