From fffd36268a216044523c3f5227c3d375608c36dc Mon Sep 17 00:00:00 2001
From: nsfisis <nsfisis@gmail.com>
Date: Sat, 14 Feb 2026 12:17:23 +0900
Subject: refactor(frontend): migrate state management to jotai and
 jotai-tanstack-query

Replace React Context + manual useEffect data fetching with jotai atoms
for state management and jotai-tanstack-query for server state caching.

- Add jotai, jotai-tanstack-query, @tanstack/query-core dependencies
- Create atoms for auth (primitive + action), feeds (suspense query),
  and articles (infinite query with cursor-based pagination)
- Wire up Provider, HydrateQueryClient, and StoreInitializer in main.tsx
- Migrate all components from useAuth() context to jotai atoms
- Replace manual fetch logic in FeedSidebar/FeedList with feedsAtom
- Replace usePaginatedArticles hook with articlesInfiniteAtom
- Add queryClient.invalidateQueries() after mutations for automatic
  cache refresh
- Add ErrorBoundary and LoadingSpinner components for Suspense support
- Remove callback prop chains (onFeedAdded, onFeedChanged, etc.)
  in favor of query invalidation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---
 frontend/src/contexts/AuthContext.tsx | 74 -----------------------------------
 1 file changed, 74 deletions(-)

(limited to 'frontend/src/contexts/AuthContext.tsx')

diff --git a/frontend/src/contexts/AuthContext.tsx b/frontend/src/contexts/AuthContext.tsx
index 9b157cb..e69de29 100644
--- a/frontend/src/contexts/AuthContext.tsx
+++ b/frontend/src/contexts/AuthContext.tsx
@@ -1,74 +0,0 @@
-import {
-	createContext,
-	type ReactNode,
-	useCallback,
-	useContext,
-	useEffect,
-	useState,
-} from "react";
-import { api } from "../services/api-client";
-
-type LoginResult = { success: true } | { success: false; error: string };
-
-interface AuthContextType {
-	isLoggedIn: boolean;
-	isLoading: boolean;
-	login: (username: string, password: string) => Promise<LoginResult>;
-	logout: () => Promise<void>;
-}
-
-const AuthContext = createContext<AuthContextType | undefined>(undefined);
-
-export function AuthProvider({ children }: { children: ReactNode }) {
-	const [isLoggedIn, setIsLoggedIn] = useState(false);
-	const [isLoading, setIsLoading] = useState(true);
-
-	const checkAuth = useCallback(async () => {
-		const { data } = await api.GET("/api/auth/me");
-		setIsLoggedIn(!!data);
-		setIsLoading(false);
-	}, []);
-
-	useEffect(() => {
-		checkAuth();
-	}, [checkAuth]);
-
-	const login = async (
-		username: string,
-		password: string,
-	): Promise<LoginResult> => {
-		const { data, error } = await api.POST("/api/auth/login", {
-			body: { username, password },
-		});
-
-		if (error) {
-			return { success: false, error: error.message };
-		}
-
-		if (data?.user) {
-			setIsLoggedIn(true);
-			return { success: true };
-		}
-
-		return { success: false, error: "Invalid username or password" };
-	};
-
-	const logout = async () => {
-		await api.POST("/api/auth/logout");
-		setIsLoggedIn(false);
-	};
-
-	return (
-		<AuthContext.Provider value={{ isLoggedIn, isLoading, login, logout }}>
-			{children}
-		</AuthContext.Provider>
-	);
-}
-
-export function useAuth() {
-	const context = useContext(AuthContext);
-	if (context === undefined) {
-		throw new Error("useAuth must be used within an AuthProvider");
-	}
-	return context;
-}
-- 
cgit v1.3-1-g0d28

