|
|
|
import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit'; |
|
import { authApi, LoginCredentials, SignupCredentials, AuthResponse } from '../../api/authApi'; |
|
|
|
|
|
interface AuthState { |
|
user: AuthResponse['user'] | null; |
|
token: string | null; |
|
isAuthenticated: boolean; |
|
isLoading: boolean; |
|
error: string | null; |
|
} |
|
|
|
|
|
const initialState: AuthState = { |
|
user: null, |
|
token: localStorage.getItem('authToken'), |
|
isAuthenticated: !!localStorage.getItem('authToken'), |
|
isLoading: false, |
|
error: null, |
|
}; |
|
|
|
|
|
export const loginUser = createAsyncThunk( |
|
'auth/login', |
|
async (credentials: LoginCredentials, { rejectWithValue }) => { |
|
try { |
|
const response = await authApi.login(credentials); |
|
|
|
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); |
|
|
|
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'); |
|
} |
|
} |
|
); |
|
|
|
|
|
const authSlice = createSlice({ |
|
name: 'auth', |
|
initialState, |
|
reducers: { |
|
resetAuthErrors: (state) => { |
|
state.error = null; |
|
}, |
|
}, |
|
extraReducers: (builder) => { |
|
|
|
builder |
|
.addCase(loginUser.pending, (state) => { |
|
state.isLoading = true; |
|
state.error = null; |
|
}) |
|
.addCase(loginUser.fulfilled, (state, action: PayloadAction<AuthResponse>) => { |
|
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; |
|
}) |
|
|
|
|
|
.addCase(signupUser.pending, (state) => { |
|
state.isLoading = true; |
|
state.error = null; |
|
}) |
|
.addCase(signupUser.fulfilled, (state, action: PayloadAction<AuthResponse>) => { |
|
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; |
|
}) |
|
|
|
|
|
.addCase(logoutUser.fulfilled, (state) => { |
|
state.isAuthenticated = false; |
|
state.user = null; |
|
state.token = null; |
|
}) |
|
|
|
|
|
.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; |
|
|