aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/client/atoms/auth.ts
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-01-04 17:43:59 +0900
committernsfisis <nsfisis@gmail.com>2026-01-04 19:09:58 +0900
commitf8e4be9b36a16969ac53bd9ce12ce8064be10196 (patch)
treeb2cf350d2e2e52803ff809311effb40da767d859 /src/client/atoms/auth.ts
parente1c9e5e89bb91bca2586470c786510c3e1c03826 (diff)
downloadkioku-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/atoms/auth.ts')
-rw-r--r--src/client/atoms/auth.ts57
1 files changed, 57 insertions, 0 deletions
diff --git a/src/client/atoms/auth.ts b/src/client/atoms/auth.ts
new file mode 100644
index 0000000..f618ccf
--- /dev/null
+++ b/src/client/atoms/auth.ts
@@ -0,0 +1,57 @@
+import { atom, useSetAtom } from "jotai";
+import { useEffect } from "react";
+import { apiClient, type User } from "../api/client";
+
+// Primitive atoms
+export const userAtom = atom<User | null>(null);
+export const authLoadingAtom = atom<boolean>(true);
+
+// Derived atom - checks if user is authenticated via apiClient
+export const isAuthenticatedAtom = atom<boolean>((get) => {
+ // We need to trigger re-evaluation when user changes
+ get(userAtom);
+ return apiClient.isAuthenticated();
+});
+
+// Action atom - login
+export const loginAtom = atom(
+ null,
+ async (
+ _get,
+ set,
+ { username, password }: { username: string; password: string },
+ ) => {
+ const response = await apiClient.login(username, password);
+ set(userAtom, response.user);
+ },
+);
+
+// Action atom - logout
+export const logoutAtom = atom(null, (_get, set) => {
+ apiClient.logout();
+ set(userAtom, null);
+});
+
+// Hook to initialize auth state and subscribe to session expiration
+export function useAuthInit() {
+ const setAuthLoading = useSetAtom(authLoadingAtom);
+ const setUser = useSetAtom(userAtom);
+
+ useEffect(() => {
+ // Check for existing auth on mount
+ 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.
+ }
+ setAuthLoading(false);
+
+ // Subscribe to session expired events from the API client
+ const unsubscribe = apiClient.onSessionExpired(() => {
+ apiClient.logout();
+ setUser(null);
+ });
+
+ return unsubscribe;
+ }, [setAuthLoading, setUser]);
+}