From 457eb550e42576d575fd2ff1d9635cd0980ee240 Mon Sep 17 00:00:00 2001 From: Evan Reichard Date: Fri, 3 Jul 2026 19:46:28 -0400 Subject: [PATCH] cleanup 6 --- frontend/src/auth/AuthContext.tsx | 40 +-- frontend/src/components/HamburgerMenu.tsx | 132 ++++---- frontend/src/hooks/useAuthForm.ts | 3 +- frontend/src/pages/ActivityPage.tsx | 3 +- frontend/src/pages/AdminImportPage.tsx | 3 +- frontend/src/pages/AdminImportResultsPage.tsx | 3 +- frontend/src/pages/AdminLogsPage.tsx | 3 +- frontend/src/pages/AdminUsersPage.tsx | 195 +++++++----- frontend/src/pages/DocumentPage.tsx | 7 +- frontend/src/pages/DocumentsPage.tsx | 84 +++-- frontend/src/pages/HomePage.tsx | 3 +- frontend/src/pages/ProgressPage.tsx | 3 +- frontend/src/pages/ReaderPage.tsx | 7 +- frontend/src/pages/SearchPage.tsx | 3 +- frontend/src/pages/SettingsPage.tsx | 301 ++++++++++-------- frontend/src/utils/apiResponses.ts | 21 ++ 16 files changed, 446 insertions(+), 365 deletions(-) create mode 100644 frontend/src/utils/apiResponses.ts diff --git a/frontend/src/auth/AuthContext.tsx b/frontend/src/auth/AuthContext.tsx index 34d4bce..065b4b2 100644 --- a/frontend/src/auth/AuthContext.tsx +++ b/frontend/src/auth/AuthContext.tsx @@ -1,4 +1,4 @@ -import { createContext, useContext, useState, useEffect, ReactNode, useCallback } from 'react'; +import { createContext, useContext, ReactNode, useCallback, useMemo } from 'react'; import { useQueryClient } from '@tanstack/react-query'; import { useNavigate } from 'react-router-dom'; import { @@ -10,7 +10,6 @@ import { } from '../generated/anthoLumeAPIV1'; import { type AuthState, - getAuthenticatedAuthState, getUnauthenticatedAuthState, resolveAuthStateFromMe, authUserFromMutation, @@ -25,15 +24,9 @@ interface AuthContextType extends AuthState { const AuthContext = createContext(undefined); -const initialAuthState: AuthState = { - isAuthenticated: false, - user: null, - isCheckingAuth: true, -}; +const unauthenticatedState = getUnauthenticatedAuthState(); export function AuthProvider({ children }: { children: ReactNode }) { - const [authState, setAuthState] = useState(initialAuthState); - const loginMutation = useLogin(); const registerMutation = useRegister(); const logoutMutation = useLogout(); @@ -43,16 +36,16 @@ export function AuthProvider({ children }: { children: ReactNode }) { const queryClient = useQueryClient(); const navigate = useNavigate(); - useEffect(() => { - setAuthState(prev => + const authState = useMemo( + () => resolveAuthStateFromMe({ meData, meError, meLoading, - previousState: prev, - }) - ); - }, [meData, meError, meLoading]); + previousState: unauthenticatedState, + }), + [meData, meError, meLoading] + ); const login = useCallback( async (username: string, password: string) => { @@ -66,16 +59,14 @@ export function AuthProvider({ children }: { children: ReactNode }) { const user = authUserFromMutation(response); if (!user) { - setAuthState(getUnauthenticatedAuthState()); throw new Error(getResponseError(response) ?? 'Login failed'); } - setAuthState(getAuthenticatedAuthState(user)); - + queryClient.setQueryData(getGetMeQueryKey(), response); await queryClient.invalidateQueries({ queryKey: getGetMeQueryKey() }); navigate('/'); } catch (error) { - setAuthState(getUnauthenticatedAuthState()); + queryClient.setQueryData(getGetMeQueryKey(), undefined); throw error instanceof Error ? error : new Error('Login failed'); } }, @@ -94,16 +85,14 @@ export function AuthProvider({ children }: { children: ReactNode }) { const user = authUserFromMutation(response); if (!user) { - setAuthState(getUnauthenticatedAuthState()); throw new Error(getResponseError(response) ?? 'Registration failed'); } - setAuthState(getAuthenticatedAuthState(user)); - + queryClient.setQueryData(getGetMeQueryKey(), response); await queryClient.invalidateQueries({ queryKey: getGetMeQueryKey() }); navigate('/'); } catch (error) { - setAuthState(getUnauthenticatedAuthState()); + queryClient.setQueryData(getGetMeQueryKey(), undefined); throw error instanceof Error ? error : new Error('Registration failed'); } }, @@ -112,9 +101,8 @@ export function AuthProvider({ children }: { children: ReactNode }) { const logout = useCallback(() => { logoutMutation.mutate(undefined, { - onSuccess: async () => { - setAuthState(getUnauthenticatedAuthState()); - queryClient.removeQueries({ queryKey: getGetMeQueryKey() }); + onSettled: () => { + queryClient.clear(); navigate('/login'); }, }); diff --git a/frontend/src/components/HamburgerMenu.tsx b/frontend/src/components/HamburgerMenu.tsx index 6c2a12f..6a3c2cd 100644 --- a/frontend/src/components/HamburgerMenu.tsx +++ b/frontend/src/components/HamburgerMenu.tsx @@ -4,11 +4,38 @@ import { SettingsIcon, GitIcon } from '../icons'; import { useAuth } from '../auth/AuthContext'; import { useGetInfo } from '../generated/anthoLumeAPIV1'; import { navItems, adminNavItems } from './navigation'; +import { dataForStatus } from '../utils/apiResponses'; +import { cn } from '../utils/cn'; function hasPrefix(path: string, prefix: string): boolean { return path.startsWith(prefix); } +function NavToggleIcon({ isOpen }: { isOpen: boolean }) { + return ( +