summaryrefslogtreecommitdiff
path: root/frontend/src/store/authStore.ts
diff options
context:
space:
mode:
authorblackhao <13851610112@163.com>2025-12-10 20:12:21 -0600
committerblackhao <13851610112@163.com>2025-12-10 20:12:21 -0600
commit9646da833bc3d94564c10649b62a378d0190471e (patch)
treed0c9c0584b8c4f167c281f5970f713b239a1d7c5 /frontend/src/store/authStore.ts
parent9ba956c7aa601f0e6cd0fe2ede907cbc558fa1b8 (diff)
user data
Diffstat (limited to 'frontend/src/store/authStore.ts')
-rw-r--r--frontend/src/store/authStore.ts157
1 files changed, 157 insertions, 0 deletions
diff --git a/frontend/src/store/authStore.ts b/frontend/src/store/authStore.ts
new file mode 100644
index 0000000..652256c
--- /dev/null
+++ b/frontend/src/store/authStore.ts
@@ -0,0 +1,157 @@
+import { create } from 'zustand';
+import { persist } from 'zustand/middleware';
+
+const API_BASE = 'http://localhost:8000';
+
+interface UserInfo {
+ id: number;
+ username: string;
+ email: string;
+ created_at: string;
+}
+
+interface AuthState {
+ token: string | null;
+ user: UserInfo | null;
+ isAuthenticated: boolean;
+ isLoading: boolean;
+ error: string | null;
+
+ // Actions
+ login: (username: string, password: string) => Promise<void>;
+ register: (username: string, email: string, password: string) => Promise<void>;
+ logout: () => void;
+ checkAuth: () => Promise<boolean>;
+ clearError: () => void;
+ getAuthHeader: () => { Authorization: string } | {};
+}
+
+export const useAuthStore = create<AuthState>()(
+ persist(
+ (set, get) => ({
+ token: null,
+ user: null,
+ isAuthenticated: false,
+ isLoading: false,
+ error: null,
+
+ login: async (username: string, password: string) => {
+ set({ isLoading: true, error: null });
+
+ try {
+ // Use JSON login endpoint
+ const res = await fetch(`${API_BASE}/api/auth/login/json`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ username, password }),
+ });
+
+ if (!res.ok) {
+ const errorData = await res.json().catch(() => ({}));
+ throw new Error(errorData.detail || 'Login failed');
+ }
+
+ const data = await res.json();
+ set({
+ token: data.access_token,
+ isAuthenticated: true,
+ isLoading: false
+ });
+
+ // Fetch user info
+ await get().checkAuth();
+ } catch (err) {
+ set({
+ isLoading: false,
+ error: (err as Error).message,
+ isAuthenticated: false,
+ token: null,
+ user: null
+ });
+ throw err;
+ }
+ },
+
+ register: async (username: string, email: string, password: string) => {
+ set({ isLoading: true, error: null });
+
+ try {
+ const res = await fetch(`${API_BASE}/api/auth/register`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ username, email, password }),
+ });
+
+ if (!res.ok) {
+ const errorData = await res.json().catch(() => ({}));
+ throw new Error(errorData.detail || 'Registration failed');
+ }
+
+ set({ isLoading: false });
+ } catch (err) {
+ set({ isLoading: false, error: (err as Error).message });
+ throw err;
+ }
+ },
+
+ logout: () => {
+ set({
+ token: null,
+ user: null,
+ isAuthenticated: false,
+ error: null
+ });
+ },
+
+ checkAuth: async () => {
+ const token = get().token;
+ if (!token) {
+ set({ isAuthenticated: false, user: null });
+ return false;
+ }
+
+ try {
+ const res = await fetch(`${API_BASE}/api/auth/me`, {
+ headers: { Authorization: `Bearer ${token}` },
+ });
+
+ if (res.ok) {
+ const user = await res.json();
+ set({ user, isAuthenticated: true });
+ return true;
+ } else {
+ // Token is invalid
+ set({ token: null, user: null, isAuthenticated: false });
+ return false;
+ }
+ } catch {
+ set({ token: null, user: null, isAuthenticated: false });
+ return false;
+ }
+ },
+
+ clearError: () => {
+ set({ error: null });
+ },
+
+ getAuthHeader: () => {
+ const token = get().token;
+ if (token) {
+ return { Authorization: `Bearer ${token}` };
+ }
+ return {};
+ },
+ }),
+ {
+ name: 'contextflow-auth',
+ partialize: (state) => ({
+ token: state.token,
+ user: state.user,
+ isAuthenticated: state.isAuthenticated
+ }),
+ }
+ )
+);
+
+export default useAuthStore;
+