Initial Claude Run
This commit is contained in:
232
frontend/src/contexts/AuthContext.js
Normal file
232
frontend/src/contexts/AuthContext.js
Normal file
@@ -0,0 +1,232 @@
|
||||
import React, { createContext, useContext, useReducer, useEffect } from 'react';
|
||||
import { authAPI } from '../services/api';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
// Initial state
|
||||
const initialState = {
|
||||
user: null,
|
||||
token: localStorage.getItem('authToken'),
|
||||
loading: true,
|
||||
error: null,
|
||||
};
|
||||
|
||||
// Action types
|
||||
const actionTypes = {
|
||||
SET_LOADING: 'SET_LOADING',
|
||||
LOGIN_SUCCESS: 'LOGIN_SUCCESS',
|
||||
LOGOUT: 'LOGOUT',
|
||||
SET_ERROR: 'SET_ERROR',
|
||||
CLEAR_ERROR: 'CLEAR_ERROR',
|
||||
UPDATE_USER: 'UPDATE_USER',
|
||||
};
|
||||
|
||||
// Reducer
|
||||
const authReducer = (state, action) => {
|
||||
switch (action.type) {
|
||||
case actionTypes.SET_LOADING:
|
||||
return {
|
||||
...state,
|
||||
loading: action.payload,
|
||||
error: null,
|
||||
};
|
||||
|
||||
case actionTypes.LOGIN_SUCCESS:
|
||||
localStorage.setItem('authToken', action.payload.token);
|
||||
return {
|
||||
...state,
|
||||
user: action.payload.user,
|
||||
token: action.payload.token,
|
||||
loading: false,
|
||||
error: null,
|
||||
};
|
||||
|
||||
case actionTypes.LOGOUT:
|
||||
localStorage.removeItem('authToken');
|
||||
return {
|
||||
...state,
|
||||
user: null,
|
||||
token: null,
|
||||
loading: false,
|
||||
error: null,
|
||||
};
|
||||
|
||||
case actionTypes.SET_ERROR:
|
||||
return {
|
||||
...state,
|
||||
error: action.payload,
|
||||
loading: false,
|
||||
};
|
||||
|
||||
case actionTypes.CLEAR_ERROR:
|
||||
return {
|
||||
...state,
|
||||
error: null,
|
||||
};
|
||||
|
||||
case actionTypes.UPDATE_USER:
|
||||
return {
|
||||
...state,
|
||||
user: { ...state.user, ...action.payload },
|
||||
};
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
// Create context
|
||||
const AuthContext = createContext();
|
||||
|
||||
// Custom hook to use auth context
|
||||
export const useAuth = () => {
|
||||
const context = useContext(AuthContext);
|
||||
if (!context) {
|
||||
throw new Error('useAuth must be used within an AuthProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
// Auth provider component
|
||||
export const AuthProvider = ({ children }) => {
|
||||
const [state, dispatch] = useReducer(authReducer, initialState);
|
||||
|
||||
// Check if user is authenticated on app load
|
||||
useEffect(() => {
|
||||
const checkAuth = async () => {
|
||||
const token = localStorage.getItem('authToken');
|
||||
|
||||
if (!token) {
|
||||
dispatch({ type: actionTypes.SET_LOADING, payload: false });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await authAPI.getCurrentUser();
|
||||
dispatch({
|
||||
type: actionTypes.LOGIN_SUCCESS,
|
||||
payload: {
|
||||
user: response.data.user,
|
||||
token,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Auth check failed:', error);
|
||||
localStorage.removeItem('authToken');
|
||||
dispatch({ type: actionTypes.LOGOUT });
|
||||
}
|
||||
};
|
||||
|
||||
checkAuth();
|
||||
}, []);
|
||||
|
||||
// Login function
|
||||
const login = async (credentials) => {
|
||||
try {
|
||||
dispatch({ type: actionTypes.SET_LOADING, payload: true });
|
||||
dispatch({ type: actionTypes.CLEAR_ERROR });
|
||||
|
||||
const response = await authAPI.login(credentials);
|
||||
|
||||
dispatch({
|
||||
type: actionTypes.LOGIN_SUCCESS,
|
||||
payload: response.data,
|
||||
});
|
||||
|
||||
toast.success('Welcome back!');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
const errorMessage = error.response?.data?.message || 'Login failed. Please try again.';
|
||||
dispatch({ type: actionTypes.SET_ERROR, payload: errorMessage });
|
||||
toast.error(errorMessage);
|
||||
return { success: false, error: errorMessage };
|
||||
}
|
||||
};
|
||||
|
||||
// Register function
|
||||
const register = async (userData) => {
|
||||
try {
|
||||
dispatch({ type: actionTypes.SET_LOADING, payload: true });
|
||||
dispatch({ type: actionTypes.CLEAR_ERROR });
|
||||
|
||||
const response = await authAPI.register(userData);
|
||||
|
||||
dispatch({
|
||||
type: actionTypes.LOGIN_SUCCESS,
|
||||
payload: response.data,
|
||||
});
|
||||
|
||||
toast.success('Account created successfully!');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
const errorMessage = error.response?.data?.message || 'Registration failed. Please try again.';
|
||||
dispatch({ type: actionTypes.SET_ERROR, payload: errorMessage });
|
||||
toast.error(errorMessage);
|
||||
return { success: false, error: errorMessage };
|
||||
}
|
||||
};
|
||||
|
||||
// Logout function
|
||||
const logout = () => {
|
||||
dispatch({ type: actionTypes.LOGOUT });
|
||||
toast.success('Logged out successfully');
|
||||
};
|
||||
|
||||
// Update user profile
|
||||
const updateUser = (userData) => {
|
||||
dispatch({ type: actionTypes.UPDATE_USER, payload: userData });
|
||||
};
|
||||
|
||||
// Change password
|
||||
const changePassword = async (passwordData) => {
|
||||
try {
|
||||
await authAPI.changePassword(passwordData);
|
||||
toast.success('Password changed successfully');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
const errorMessage = error.response?.data?.message || 'Failed to change password';
|
||||
toast.error(errorMessage);
|
||||
return { success: false, error: errorMessage };
|
||||
}
|
||||
};
|
||||
|
||||
// Forgot password
|
||||
const forgotPassword = async (email) => {
|
||||
try {
|
||||
await authAPI.forgotPassword(email);
|
||||
toast.success('Password reset instructions sent to your email');
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
const errorMessage = error.response?.data?.message || 'Failed to send reset email';
|
||||
toast.error(errorMessage);
|
||||
return { success: false, error: errorMessage };
|
||||
}
|
||||
};
|
||||
|
||||
// Clear error
|
||||
const clearError = () => {
|
||||
dispatch({ type: actionTypes.CLEAR_ERROR });
|
||||
};
|
||||
|
||||
// Context value
|
||||
const value = {
|
||||
user: state.user,
|
||||
token: state.token,
|
||||
loading: state.loading,
|
||||
error: state.error,
|
||||
isAuthenticated: !!state.user,
|
||||
isAdmin: state.user?.role === 'admin',
|
||||
login,
|
||||
register,
|
||||
logout,
|
||||
updateUser,
|
||||
changePassword,
|
||||
forgotPassword,
|
||||
clearError,
|
||||
};
|
||||
|
||||
return (
|
||||
<AuthContext.Provider value={value}>
|
||||
{children}
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user