import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit'; import { authApi, LoginCredentials, SignupCredentials, AuthResponse } from '../../api/authApi'; // Define the auth state interface interface AuthState { user: AuthResponse['user'] | null; token: string | null; isAuthenticated: boolean; isLoading: boolean; error: string | null; } // Initial state const initialState: AuthState = { user: null, token: localStorage.getItem('authToken'), isAuthenticated: !!localStorage.getItem('authToken'), isLoading: false, error: null, }; // Async thunks export const loginUser = createAsyncThunk( 'auth/login', async (credentials: LoginCredentials, { rejectWithValue }) => { try { const response = await authApi.login(credentials); // Store the token in localStorage localStorage.setItem('authToken', response.token); return response; } catch (error: any) { return rejectWithValue(error.response?.data?.message || 'Login failed'); } } ); export const signupUser = createAsyncThunk( 'auth/signup', async (credentials: SignupCredentials, { rejectWithValue }) => { try { const response = await authApi.signup(credentials); // Store the token in localStorage localStorage.setItem('authToken', response.token); return response; } catch (error: any) { return rejectWithValue(error.response?.data?.message || 'Signup failed'); } } ); export const logoutUser = createAsyncThunk( 'auth/logout', async (_, { rejectWithValue }) => { try { await authApi.logout(); localStorage.removeItem('authToken'); return; } catch (error: any) { return rejectWithValue(error.response?.data?.message || 'Logout failed'); } } ); export const getCurrentUser = createAsyncThunk( 'auth/getCurrentUser', async (_, { rejectWithValue }) => { try { const user = await authApi.getCurrentUser(); return user; } catch (error: any) { return rejectWithValue(error.response?.data?.message || 'Failed to fetch user'); } } ); // Auth slice const authSlice = createSlice({ name: 'auth', initialState, reducers: { resetAuthErrors: (state) => { state.error = null; }, }, extraReducers: (builder) => { // Login cases builder .addCase(loginUser.pending, (state) => { state.isLoading = true; state.error = null; }) .addCase(loginUser.fulfilled, (state, action: PayloadAction) => { state.isLoading = false; state.isAuthenticated = true; state.user = action.payload.user; state.token = action.payload.token; }) .addCase(loginUser.rejected, (state, action) => { state.isLoading = false; state.error = action.payload as string; }) // Signup cases .addCase(signupUser.pending, (state) => { state.isLoading = true; state.error = null; }) .addCase(signupUser.fulfilled, (state, action: PayloadAction) => { state.isLoading = false; state.isAuthenticated = true; state.user = action.payload.user; state.token = action.payload.token; }) .addCase(signupUser.rejected, (state, action) => { state.isLoading = false; state.error = action.payload as string; }) // Logout cases .addCase(logoutUser.fulfilled, (state) => { state.isAuthenticated = false; state.user = null; state.token = null; }) // Get current user cases .addCase(getCurrentUser.pending, (state) => { state.isLoading = true; }) .addCase(getCurrentUser.fulfilled, (state, action) => { state.isLoading = false; state.user = action.payload; state.isAuthenticated = true; }) .addCase(getCurrentUser.rejected, (state) => { state.isLoading = false; state.isAuthenticated = false; state.user = null; state.token = null; }); }, }); export const { resetAuthErrors } = authSlice.actions; export default authSlice.reducer;