/** * Authentication State Slice * Manages user authentication state */ import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit'; export interface User { id: string; email: string; name: string; avatar?: string; verifiedDomain?: string; isPremium: boolean; createdAt: string; } interface AuthState { user: User | null; token: string | null; isAuthenticated: boolean; loading: boolean; error: string | null; } const initialState: AuthState = { user: null, token: null, isAuthenticated: false, loading: false, error: null, }; // Async thunks export const login = createAsyncThunk( 'auth/login', async ({ email, password }: { email: string; password: string }, { rejectWithValue }) => { try { const response = await fetch('/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password }), }); if (!response.ok) { const error = await response.json(); return rejectWithValue(error.message); } const data = await response.json(); return data; } catch (error: any) { return rejectWithValue(error.message); } } ); export const register = createAsyncThunk( 'auth/register', async ({ email, password, name }: { email: string; password: string; name: string }, { rejectWithValue }) => { try { const response = await fetch('/api/auth/register', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, password, name }), }); if (!response.ok) { const error = await response.json(); return rejectWithValue(error.message); } const data = await response.json(); return data; } catch (error: any) { return rejectWithValue(error.message); } } ); export const logout = createAsyncThunk( 'auth/logout', async () => { // Clear token from storage localStorage.removeItem('token'); } ); // Slice const authSlice = createSlice({ name: 'auth', initialState, reducers: { setUser: (state, action: PayloadAction) => { state.user = action.payload; state.isAuthenticated = true; }, setToken: (state, action: PayloadAction) => { state.token = action.payload; localStorage.setItem('token', action.payload); }, clearError: (state) => { state.error = null; }, updateUser: (state, action: PayloadAction>) => { if (state.user) { state.user = { ...state.user, ...action.payload }; } }, }, extraReducers: (builder) => { // Login builder.addCase(login.pending, (state) => { state.loading = true; state.error = null; }); builder.addCase(login.fulfilled, (state, action) => { state.loading = false; state.user = action.payload.user; state.token = action.payload.token; state.isAuthenticated = true; localStorage.setItem('token', action.payload.token); }); builder.addCase(login.rejected, (state, action) => { state.loading = false; state.error = action.payload as string; }); // Register builder.addCase(register.pending, (state) => { state.loading = true; state.error = null; }); builder.addCase(register.fulfilled, (state, action) => { state.loading = false; state.user = action.payload.user; state.token = action.payload.token; state.isAuthenticated = true; localStorage.setItem('token', action.payload.token); }); builder.addCase(register.rejected, (state, action) => { state.loading = false; state.error = action.payload as string; }); // Logout builder.addCase(logout.fulfilled, (state) => { state.user = null; state.token = null; state.isAuthenticated = false; state.error = null; }); }, }); export const { setUser, setToken, clearError, updateUser } = authSlice.actions; export default authSlice.reducer;