diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-01-04 17:43:59 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-01-04 19:09:58 +0900 |
| commit | f8e4be9b36a16969ac53bd9ce12ce8064be10196 (patch) | |
| tree | b2cf350d2e2e52803ff809311effb40da767d859 /src/client/stores/auth.tsx | |
| parent | e1c9e5e89bb91bca2586470c786510c3e1c03826 (diff) | |
| download | kioku-f8e4be9b36a16969ac53bd9ce12ce8064be10196.tar.gz kioku-f8e4be9b36a16969ac53bd9ce12ce8064be10196.tar.zst kioku-f8e4be9b36a16969ac53bd9ce12ce8064be10196.zip | |
refactor(client): migrate state management from React Context to Jotai
Replace AuthProvider and SyncProvider with Jotai atoms for more granular
state management and better performance. This migration:
- Creates atoms for auth, sync, decks, cards, noteTypes, and study state
- Uses atomFamily for parameterized state (e.g., cards by deckId)
- Introduces StoreInitializer component for subscription initialization
- Updates all components and pages to use useAtomValue/useSetAtom
- Updates all tests to use Jotai Provider with createStore pattern
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat (limited to 'src/client/stores/auth.tsx')
| -rw-r--r-- | src/client/stores/auth.tsx | 92 |
1 files changed, 0 insertions, 92 deletions
diff --git a/src/client/stores/auth.tsx b/src/client/stores/auth.tsx deleted file mode 100644 index 3f2681b..0000000 --- a/src/client/stores/auth.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import { - createContext, - type ReactNode, - useCallback, - useContext, - useEffect, - useMemo, - useState, -} from "react"; -import { ApiClientError, apiClient, type User } from "../api/client"; - -export interface AuthState { - user: User | null; - isAuthenticated: boolean; - isLoading: boolean; -} - -export interface AuthActions { - login: (username: string, password: string) => Promise<void>; - logout: () => void; -} - -export type AuthContextValue = AuthState & AuthActions; - -const AuthContext = createContext<AuthContextValue | null>(null); - -export interface AuthProviderProps { - children: ReactNode; -} - -export function AuthProvider({ children }: AuthProviderProps) { - const [user, setUser] = useState<User | null>(null); - const [isLoading, setIsLoading] = useState(true); - const [isAuthenticated, setIsAuthenticated] = useState( - apiClient.isAuthenticated(), - ); - - const logout = useCallback(() => { - apiClient.logout(); - setUser(null); - setIsAuthenticated(false); - }, []); - - // Check for existing auth on mount - useEffect(() => { - const tokens = apiClient.getTokens(); - if (tokens) { - // We have tokens stored, but we don't have user info cached - // For now, just set authenticated state. User info will be fetched when needed. - // In a full implementation, we'd decode the JWT or call an API endpoint - setIsLoading(false); - } else { - setIsLoading(false); - } - }, []); - - // Subscribe to session expired events from the API client - useEffect(() => { - return apiClient.onSessionExpired(() => { - logout(); - }); - }, [logout]); - - const login = useCallback(async (username: string, password: string) => { - const response = await apiClient.login(username, password); - setUser(response.user); - setIsAuthenticated(true); - }, []); - - const value = useMemo<AuthContextValue>( - () => ({ - user, - isAuthenticated, - isLoading, - login, - logout, - }), - [user, isAuthenticated, isLoading, login, logout], - ); - - return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>; -} - -export function useAuth(): AuthContextValue { - const context = useContext(AuthContext); - if (!context) { - throw new Error("useAuth must be used within an AuthProvider"); - } - return context; -} - -export { ApiClientError }; |
