From f8e4be9b36a16969ac53bd9ce12ce8064be10196 Mon Sep 17 00:00:00 2001
From: nsfisis <nsfisis@gmail.com>
Date: Sun, 4 Jan 2026 17:43:59 +0900
Subject: refactor(client): migrate state management from React Context to
 Jotai
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

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>
---
 src/client/stores/auth.tsx | 92 ----------------------------------------------
 1 file changed, 92 deletions(-)
 delete mode 100644 src/client/stores/auth.tsx

(limited to 'src/client/stores/auth.tsx')

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 };
-- 
cgit v1.2.3-70-g09d2

