306 lines
6.3 KiB
Markdown
306 lines
6.3 KiB
Markdown
# useAuthStore - Zustand Authentication Store
|
|
|
|
## ✅ Function 3 Completed
|
|
|
|
### 📦 Files Created:
|
|
|
|
1. **`src/store/useAuthStore.ts`** - Zustand store managing auth
|
|
2. **`src/services/api/apiClient.ts`** - Axios client with interceptors
|
|
3. **`src/services/api/authService.ts`** - Auth API service
|
|
4. **`.env.example`** - Template for environment variables
|
|
|
|
### 🎯 Features Implemented:
|
|
|
|
#### State Management:
|
|
```typescript
|
|
interface AuthState {
|
|
token: string | null;
|
|
refreshToken: string | null;
|
|
userInfo: UserInfo | null;
|
|
isAuthenticated: boolean;
|
|
isLoading: boolean;
|
|
error: string | null;
|
|
}
|
|
```
|
|
|
|
#### Actions:
|
|
- ✅ `login(credentials)` - Login
|
|
- ✅ `register(data)` - Register new account
|
|
- ✅ `logout()` - Logout
|
|
- ✅ `setUser(user)` - Update user information
|
|
- ✅ `refreshAuthToken()` - Refresh token
|
|
- ✅ `forgotPassword(data)` - Forgot password
|
|
- ✅ `resetPassword(data)` - Reset password
|
|
- ✅ `initializeAuth()` - Initialize auth from localStorage
|
|
- ✅ `clearError()` - Clear error message
|
|
|
|
### 📝 Usage:
|
|
|
|
#### 1. Initialize in App.tsx:
|
|
```typescript
|
|
import useAuthStore from './store/useAuthStore';
|
|
|
|
function App() {
|
|
const {
|
|
isAuthenticated,
|
|
userInfo,
|
|
logout,
|
|
initializeAuth
|
|
} = useAuthStore();
|
|
|
|
useEffect(() => {
|
|
initializeAuth();
|
|
}, [initializeAuth]);
|
|
|
|
// ...
|
|
}
|
|
```
|
|
|
|
#### 2. Use in Login Form:
|
|
```typescript
|
|
import useAuthStore from '../store/useAuthStore';
|
|
|
|
const LoginPage = () => {
|
|
const { login, isLoading, error } = useAuthStore();
|
|
const navigate = useNavigate();
|
|
|
|
const handleSubmit = async (data) => {
|
|
try {
|
|
await login(data);
|
|
navigate('/dashboard'); // Redirect after login
|
|
} catch (error) {
|
|
// Error has been handled by store
|
|
}
|
|
};
|
|
|
|
return (
|
|
<form onSubmit={handleSubmit}>
|
|
{/* Form fields */}
|
|
{error && <div>{error}</div>}
|
|
<button disabled={isLoading}>
|
|
{isLoading ? 'Processing...' : 'Login'}
|
|
</button>
|
|
</form>
|
|
);
|
|
};
|
|
```
|
|
|
|
#### 3. Use in Register Form:
|
|
```typescript
|
|
const RegisterPage = () => {
|
|
const { register, isLoading } = useAuthStore();
|
|
const navigate = useNavigate();
|
|
|
|
const handleSubmit = async (data) => {
|
|
try {
|
|
await register(data);
|
|
navigate('/login'); // Redirect to login
|
|
} catch (error) {
|
|
// Error displayed via toast
|
|
}
|
|
};
|
|
|
|
// ...
|
|
};
|
|
```
|
|
|
|
#### 4. Logout:
|
|
```typescript
|
|
const Header = () => {
|
|
const { logout } = useAuthStore();
|
|
|
|
const handleLogout = async () => {
|
|
await logout();
|
|
// Auto redirect to login if needed
|
|
};
|
|
|
|
return <button onClick={handleLogout}>Logout</button>;
|
|
};
|
|
```
|
|
|
|
#### 5. Display user information:
|
|
```typescript
|
|
const Profile = () => {
|
|
const { userInfo } = useAuthStore();
|
|
|
|
return (
|
|
<div>
|
|
<h1>Hello, {userInfo?.name}</h1>
|
|
<p>Email: {userInfo?.email}</p>
|
|
<p>Role: {userInfo?.role}</p>
|
|
</div>
|
|
);
|
|
};
|
|
```
|
|
|
|
### 🔐 LocalStorage Persistence:
|
|
|
|
Store automatically saves and reads from localStorage:
|
|
- `token` - JWT access token
|
|
- `refreshToken` - JWT refresh token
|
|
- `userInfo` - User information
|
|
|
|
When page reloads, auth state is automatically restored via `initializeAuth()`.
|
|
|
|
### 🌐 API Integration:
|
|
|
|
#### Base URL Configuration:
|
|
Create `.env` file in `client/` directory:
|
|
```env
|
|
VITE_API_URL=http://localhost:3000
|
|
VITE_ENV=development
|
|
```
|
|
|
|
#### API Endpoints Used:
|
|
- `POST /api/auth/login` - Login
|
|
- `POST /api/auth/register` - Register
|
|
- `POST /api/auth/logout` - Logout
|
|
- `GET /api/auth/profile` - Get profile
|
|
- `POST /api/auth/refresh-token` - Refresh token
|
|
- `POST /api/auth/forgot-password` - Forgot password
|
|
- `POST /api/auth/reset-password` - Reset password
|
|
|
|
### 🛡️ Security Features:
|
|
|
|
1. **Auto Token Injection**:
|
|
- Axios interceptor automatically adds token to headers
|
|
```typescript
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
2. **Auto Logout on 401**:
|
|
- When token expires (401), automatically logout and redirect to login
|
|
|
|
3. **Token Refresh**:
|
|
- Can refresh token when about to expire
|
|
|
|
4. **Password Hashing**:
|
|
- Backend handles bcrypt hashing
|
|
|
|
### 📱 Toast Notifications:
|
|
|
|
Store automatically displays toast for events:
|
|
- ✅ Login successful
|
|
- ✅ Registration successful
|
|
- ✅ Logout
|
|
- ❌ Login failed
|
|
- ❌ Registration failed
|
|
- ❌ API errors
|
|
|
|
### 🔄 Component Updates:
|
|
|
|
#### ProtectedRoute:
|
|
```typescript
|
|
// BEFORE (with props)
|
|
<ProtectedRoute isAuthenticated={isAuthenticated}>
|
|
<Dashboard />
|
|
</ProtectedRoute>
|
|
|
|
// AFTER (automatically gets from store)
|
|
<ProtectedRoute>
|
|
<Dashboard />
|
|
</ProtectedRoute>
|
|
```
|
|
|
|
#### AdminRoute:
|
|
```typescript
|
|
// BEFORE (with props)
|
|
<AdminRoute userInfo={userInfo}>
|
|
<AdminPanel />
|
|
</AdminRoute>
|
|
|
|
// AFTER (automatically gets from store)
|
|
<AdminRoute>
|
|
<AdminPanel />
|
|
</AdminRoute>
|
|
```
|
|
|
|
#### LayoutMain:
|
|
Still receives props from App.tsx to display Header/Navbar:
|
|
```typescript
|
|
<LayoutMain
|
|
isAuthenticated={isAuthenticated}
|
|
userInfo={userInfo}
|
|
onLogout={handleLogout}
|
|
/>
|
|
```
|
|
|
|
### 🧪 Testing:
|
|
|
|
To test authentication flow:
|
|
|
|
1. **Create `.env` file**:
|
|
```bash
|
|
cp .env.example .env
|
|
```
|
|
|
|
2. **Ensure backend is running**:
|
|
```bash
|
|
cd server
|
|
npm run dev
|
|
```
|
|
|
|
3. **Run frontend**:
|
|
```bash
|
|
cd client
|
|
npm run dev
|
|
```
|
|
|
|
4. **Test flow**:
|
|
- Access `/register` → Register account
|
|
- Access `/login` → Login
|
|
- Access `/dashboard` → View dashboard (protected)
|
|
- Click logout → Clear session
|
|
- Reload page → Auth state restored
|
|
|
|
### 🚀 Next Steps:
|
|
|
|
**Function 4: Login Form**
|
|
- Create LoginPage with React Hook Form + Yup
|
|
- Integrate with useAuthStore
|
|
- UX enhancements (loading, show/hide password, remember me)
|
|
|
|
**Function 5: Register Form**
|
|
- Create RegisterPage with validation
|
|
- Integrate with useAuthStore
|
|
|
|
**Function 6-7: Password Reset Flow**
|
|
- ForgotPasswordPage
|
|
- ResetPasswordPage
|
|
|
|
### 📚 TypeScript Types:
|
|
|
|
```typescript
|
|
interface LoginCredentials {
|
|
email: string;
|
|
password: string;
|
|
rememberMe?: boolean;
|
|
}
|
|
|
|
interface RegisterData {
|
|
name: string;
|
|
email: string;
|
|
password: string;
|
|
phone?: string;
|
|
}
|
|
|
|
interface UserInfo {
|
|
id: number;
|
|
name: string;
|
|
email: string;
|
|
phone?: string;
|
|
avatar?: string;
|
|
role: string;
|
|
createdAt?: string;
|
|
}
|
|
```
|
|
|
|
### ✅ Results Achieved:
|
|
|
|
1. ✅ All user information managed centrally
|
|
2. ✅ Maintain login after page reload
|
|
3. ✅ Easy access to userInfo in any component
|
|
4. ✅ Auto token management
|
|
5. ✅ Type-safe with TypeScript
|
|
6. ✅ Clean code, easy to maintain
|