# Function 6: Forgot Password - Completed โœ… ## ๐Ÿ“ฆ Files Created/Updated ### Frontend 1. **`client/src/pages/auth/ForgotPasswordPage.tsx`** - Forgot password form component 2. **`client/src/pages/auth/index.ts`** - Export ForgotPasswordPage 3. **`client/src/App.tsx`** - Route `/forgot-password` ### Backend 4. **`server/src/controllers/authController.js`** - forgotPassword() & resetPassword() 5. **`server/src/routes/authRoutes.js`** - Routes for forgot/reset password ## โœจ Main Features ### 1. Form State (Initial) ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ ๐Ÿจ Hotel Icon (Blue) โ”‚ โ”‚ Forgot password? โ”‚ โ”‚ Enter email to receive link... โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ Email โ”‚ โ”‚ โ”‚ โ”‚ [๐Ÿ“ง email@example.com ] โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ โ”‚ โ”‚ [๐Ÿ“ค Send reset link] โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ โ”‚ โ”‚ โ† Back to login โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ Don't have an account? Sign up now โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ``` ### 2. Success State (After Submit) ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โœ… Success Icon โ”‚ โ”‚ โ”‚ โ”‚ Email has been sent! โ”‚ โ”‚ We have sent a link to โ”‚ โ”‚ user@example.com โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ โ„น๏ธ Note: โ”‚ โ”‚ โ€ข Link is valid for 1 hour โ”‚ โ”‚ โ€ข Check Spam/Junk folder โ”‚ โ”‚ โ€ข If not received, try again โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ [๐Ÿ“ง Resend email] โ”‚ โ”‚ [โ† Back to login] โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ``` ### 3. Two-State Design Pattern โœ… **Form State** - Enter email โœ… **Success State** - Display confirmation & instructions State management: ```typescript const [isSuccess, setIsSuccess] = useState(false); const [submittedEmail, setSubmittedEmail] = useState(''); ``` ## ๐Ÿ”ง Detailed Features ### 1. Validation (Yup Schema) ```typescript email: - Required: "Email is required" - Valid format: "Invalid email format" - Trim whitespace ``` ### 2. Form Field - **Email input** with Mail icon - Auto-focus when page loads - Validation real-time - Error message inline ### 3. Submit Button States ```tsx {isLoading ? ( <> Processing... ) : ( <> Send reset link )} ``` ### 4. Success Features โœ… **Visual Confirmation** - Green checkmark icon - Success message - Display submitted email โœ… **User Instructions** - Link expires in 1 hour - Check spam folder - Can resend email โœ… **Action Buttons** - "Resend email" - Reset to form state - "Back to login" - Navigate to /login ### 5. Help Section ```tsx

Need help?

Contact: support@hotel.com or 1900-xxxx

``` ## ๐Ÿ”— Backend Integration ### API Endpoint: Forgot Password ``` POST /api/auth/forgot-password ``` **Request Body:** ```json { "email": "user@example.com" } ``` **Response (Success):** ```json { "status": "success", "message": "Password reset link has been sent to your email" } ``` **Implementation:** ```javascript const forgotPassword = async (req, res, next) => { // 1. Find user by email // 2. Generate crypto reset token (32 bytes) // 3. Hash token with SHA256 // 4. Save to password_reset_tokens table // 5. Expires in 1 hour // 6. TODO: Send email with reset link // 7. Return success (prevent email enumeration) }; ``` ### API Endpoint: Reset Password ``` POST /api/auth/reset-password ``` **Request Body:** ```json { "token": "reset_token_from_email", "password": "NewPassword123@" } ``` **Response (Success):** ```json { "status": "success", "message": "Password has been reset successfully" } ``` **Implementation:** ```javascript const resetPassword = async (req, res, next) => { // 1. Hash incoming token // 2. Find valid token in DB (not expired) // 3. Find user by user_id // 4. Hash new password with bcrypt // 5. Update user password // 6. Delete used token // 7. TODO: Send confirmation email // 8. Return success }; ``` ## ๐Ÿ” Security Features ### 1. Token Generation ```javascript // Generate random 32-byte token const resetToken = crypto.randomBytes(32).toString('hex'); // Hash with SHA256 before storing const hashedToken = crypto .createHash('sha256') .update(resetToken) .digest('hex'); ``` ### 2. Token Storage - Stored in `password_reset_tokens` table - Hashed (SHA256) - Expires in 1 hour - One token per user (old tokens deleted) ### 3. Email Enumeration Prevention ```javascript // Always return success, even if email not found if (!user) { return res.status(200).json({ status: 'success', message: 'If email exists, reset link has been sent' }); } ``` ### 4. Token Validation ```javascript // Check token exists and not expired const resetToken = await PasswordResetToken.findOne({ where: { token: hashedToken, expires_at: { [Op.gt]: new Date() } } }); ``` ## ๐Ÿ“Š Database Schema ### password_reset_tokens Table ```sql CREATE TABLE password_reset_tokens ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, token VARCHAR(255) NOT NULL, expires_at DATETIME NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id) ); ``` ## ๐ŸŽจ Design & Styling **Color Scheme:** - Primary: blue-600, blue-700 - Background: gradient from-blue-50 to-indigo-100 - Success: green-100, green-600 - Info: blue-50, blue-200 - Text: gray-600, gray-700, gray-900 **Icons:** - ๐Ÿจ Hotel - Main logo - ๐Ÿ“ง Mail - Email input - ๐Ÿ“ค Send - Submit button - โณ Loader2 - Loading spinner - โœ… CheckCircle - Success state - โ† ArrowLeft - Back navigation ## ๐Ÿ”„ User Flow ``` 1. User visits /forgot-password โ†“ 2. Enter email address โ†“ 3. Click "Send reset link" โ†“ 4. Frontend validation (Yup) โ†“ 5. Call useAuthStore.forgotPassword() โ†“ 6. API POST /api/auth/forgot-password โ†“ 7. Backend: - Generate token - Save to DB - TODO: Send email โ†“ 8. Frontend shows success state โ†“ 9. User receives email (TODO) โ†“ 10. Click link โ†’ /reset-password/:token โ†“ 11. Enter new password (Function 7) ``` ## ๐Ÿงช Test Scenarios ### Test Case 1: Valid email ``` Input: email = "user@example.com" Expected: - API called successfully - Success state shown - Email displayed correctly - Instructions visible ``` ### Test Case 2: Invalid email format ``` Input: email = "notanemail" Expected: - Validation error: "Invalid email format" - Form not submitted ``` ### Test Case 3: Empty email ``` Input: email = "" Expected: - Validation error: "Email is required" - Form not submitted ``` ### Test Case 4: Loading state ``` Action: Submit form Expected: - Button disabled - Spinner shows - Text: "Processing..." ``` ### Test Case 5: Resend email ``` Action: Click "Resend email" in success state Expected: - Return to form state - Email field cleared - Error cleared ``` ### Test Case 6: Back to login ``` Action: Click "Back to login" Expected: - Navigate to /login ``` ### Test Case 7: Email not found (Backend) ``` Input: email = "nonexistent@example.com" Expected: - Still return success (security) - No error shown to user ``` ### Test Case 8: Token expiry (Backend) ``` Scenario: Token created 2 hours ago Expected: - Reset fails - Error: "Invalid or expired reset token" ``` ## ๐Ÿ“ Code Quality โœ… **TypeScript**: Full type safety โœ… **React Hook Form**: Optimized performance โœ… **Yup Validation**: Schema-based validation โœ… **State Management**: Local state for success toggle โœ… **Error Handling**: Try-catch blocks โœ… **Security**: Token hashing, email enumeration prevention โœ… **UX**: Clear instructions, help section โœ… **Accessibility**: Labels, autocomplete, focus management โœ… **Responsive**: Mobile-friendly โœ… **80 chars/line**: Code formatting ## ๐Ÿ”— Integration Points ### useAuthStore.forgotPassword() ```typescript const { forgotPassword, isLoading, error, clearError } = useAuthStore(); await forgotPassword({ email: data.email }); ``` ### Success Handling ```typescript await forgotPassword({ email: data.email }); setIsSuccess(true); // Show success state ``` ### Error Handling ```typescript try { await forgotPassword({ email }); } catch (error) { // Error displayed via store.error console.error('Forgot password error:', error); } ``` ## ๐Ÿš€ Usage ### Test Frontend ```bash URL: http://localhost:5173/forgot-password Test Data: Email: admin@hotel.com (from seed data) ``` ### Test Backend API ```bash curl -X POST http://localhost:3000/api/auth/forgot-password \ -H "Content-Type: application/json" \ -d '{"email":"admin@hotel.com"}' ``` Expected response: ```json { "status": "success", "message": "Password reset link has been sent to your email" } ``` Ensure SMTP is configured in `server/.env` and that the server is able to send emails. The application must never log raw reset tokens or reset URLs in production. ## โš ๏ธ TODO: Email Service The project must send real emails via SMTP in production and must never expose raw reset tokens in logs. To enable email sending: 1. Install `nodemailer` in the `server` package and configure SMTP credentials in `server/.env` (`MAIL_HOST`, `MAIL_PORT`, `MAIL_USER`, `MAIL_PASS`, `MAIL_FROM`). Do not commit these credentials to source control. 2. Implement a mail helper (e.g. `server/src/utils/mailer.js`) that uses the SMTP settings. Ensure it throws or fails when SMTP credentials are missing so that emails are not silently dropped. 3. Use the mail helper to send the reset email with a link built as `${process.env.CLIENT_URL}/reset-password/${resetToken}`. 4. Important: never log the raw `resetToken` or the reset URL. If email sending fails, log a generic error and surface a safe message to the user. ## โœ… Checklist - [x] โœ… Create ForgotPasswordPage.tsx - [x] โœ… Implement React Hook Form - [x] โœ… Add Yup validation - [x] โœ… Two-state design (form + success) - [x] โœ… Loading state - [x] โœ… Error display - [x] โœ… Success state with instructions - [x] โœ… Resend email button - [x] โœ… Back to login navigation - [x] โœ… Help section - [x] โœ… Integration with useAuthStore - [x] โœ… Add route to App.tsx - [x] โœ… Backend: forgotPassword() method - [x] โœ… Backend: resetPassword() method - [x] โœ… Backend: Routes added - [x] โœ… Token generation & hashing - [x] โœ… Token expiry (1 hour) - [x] โœ… Security: Email enumeration prevention - [ ] โณ TODO: Send actual email (nodemailer) - [ ] โณ TODO: Email templates ## ๐Ÿ“š Related Files - `client/src/pages/auth/LoginPage.tsx` - Login form - `client/src/pages/auth/RegisterPage.tsx` - Register form - `client/src/utils/validationSchemas.ts` - Validation schemas - `client/src/store/useAuthStore.ts` - Auth state - `server/src/controllers/authController.js` - Auth logic - `server/src/routes/authRoutes.js` - Auth routes - `server/src/databases/models/PasswordResetToken.js` - Token model --- **Status:** โœ… Function 6 completed **Next:** Function 7 - Reset Password (form to change password with token) **Test URL:** http://localhost:5173/forgot-password **API:** POST /api/auth/forgot-password