aboutsummaryrefslogtreecommitdiffhomepage
path: root/frontend/src/atoms/auth.ts
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-02-14 12:17:23 +0900
committernsfisis <nsfisis@gmail.com>2026-02-14 12:17:23 +0900
commitfffd36268a216044523c3f5227c3d375608c36dc (patch)
treeb289735cb9d478af763775af9b15214b9595e747 /frontend/src/atoms/auth.ts
parent2889b562e64993482bd13fd806af8ed0865bab8b (diff)
downloadfeedaka-fffd36268a216044523c3f5227c3d375608c36dc.tar.gz
feedaka-fffd36268a216044523c3f5227c3d375608c36dc.tar.zst
feedaka-fffd36268a216044523c3f5227c3d375608c36dc.zip
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>
Diffstat (limited to 'frontend/src/atoms/auth.ts')
-rw-r--r--frontend/src/atoms/auth.ts46
1 files changed, 46 insertions, 0 deletions
diff --git a/frontend/src/atoms/auth.ts b/frontend/src/atoms/auth.ts
new file mode 100644
index 0000000..dd6f06c
--- /dev/null
+++ b/frontend/src/atoms/auth.ts
@@ -0,0 +1,46 @@
+import { atom, useSetAtom } from "jotai";
+import { useEffect } from "react";
+import type { components } from "../api/generated";
+import { api } from "../services/api-client";
+
+type User = components["schemas"]["User"];
+
+export const userAtom = atom<User | null>(null);
+export const authLoadingAtom = atom<boolean>(true);
+export const isLoggedInAtom = atom<boolean>((get) => get(userAtom) !== null);
+
+export const loginAtom = atom(
+ null,
+ async (
+ _get,
+ set,
+ { username, password }: { username: string; password: string },
+ ) => {
+ const { data, error } = await api.POST("/api/auth/login", {
+ body: { username, password },
+ });
+ if (error) {
+ throw new Error(error.message);
+ }
+ set(userAtom, data.user);
+ },
+);
+
+export const logoutAtom = atom(null, async (_get, set) => {
+ await api.POST("/api/auth/logout");
+ set(userAtom, null);
+});
+
+export function useAuthInit() {
+ const setUser = useSetAtom(userAtom);
+ const setAuthLoading = useSetAtom(authLoadingAtom);
+
+ useEffect(() => {
+ api.GET("/api/auth/me").then(({ data }) => {
+ if (data) {
+ setUser(data);
+ }
+ setAuthLoading(false);
+ });
+ }, [setUser, setAuthLoading]);
+}