Files
Hotel-Booking/client/ZUSTAND_AUTH_GUIDE.md
Iliyan Angelov 93d4c1df80 update
2025-11-16 15:12:43 +02:00

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