# Chức năng 5: Form Đăng Ký - Hoàn Thành ✅ ## 📦 Files Đã Tạo/Cập Nhật ### 1. **RegisterPage.tsx** - Component form đăng ký **Đường dẫn:** `client/src/pages/auth/RegisterPage.tsx` ### 2. **index.ts** - Export module **Đường dẫn:** `client/src/pages/auth/index.ts` - Đã thêm export RegisterPage ### 3. **App.tsx** - Cập nhật routing **Đường dẫn:** `client/src/App.tsx` - Đã thêm route `/register` ## ✨ Tính Năng Chính ### 1. Form Fields (5 fields) ✅ **Họ và tên** (name) - Required, 2-50 ký tự - Icon: User - Placeholder: "Nguyễn Văn A" ✅ **Email** - Required, valid email format - Icon: Mail - Placeholder: "email@example.com" ✅ **Số điện thoại** (phone) - Optional - 10-11 chữ số - Icon: Phone - Placeholder: "0123456789" ✅ **Mật khẩu** (password) - Required, min 8 chars - Must contain: uppercase, lowercase, number, special char - Show/hide toggle với Eye icon - Icon: Lock ✅ **Xác nhận mật khẩu** (confirmPassword) - Must match password - Show/hide toggle với Eye icon - Icon: Lock ### 2. Password Strength Indicator ✅ **Visual Progress Bar** với 5 levels: 1. 🔴 Rất yếu (0/5) 2. 🟠 Yếu (1/5) 3. 🟡 Trung bình (2/5) 4. 🔵 Mạnh (3/5) 5. 🟢 Rất mạnh (5/5) ✅ **Real-time Requirements Checker:** - ✅/❌ Ít nhất 8 ký tự - ✅/❌ Chữ thường (a-z) - ✅/❌ Chữ hoa (A-Z) - ✅/❌ Số (0-9) - ✅/❌ Ký tự đặc biệt (@$!%*?&) ### 3. Validation Rules (Yup Schema) ```typescript name: - Required: "Họ tên là bắt buộc" - Min 2 chars: "Họ tên phải có ít nhất 2 ký tự" - Max 50 chars: "Họ tên không được quá 50 ký tự" - Trim whitespace email: - Required: "Email là bắt buộc" - Valid format: "Email không hợp lệ" - Trim whitespace phone (optional): - Pattern /^[0-9]{10,11}$/ - Error: "Số điện thoại không hợp lệ" password: - Required: "Mật khẩu là bắt buộc" - Min 8 chars - Pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])/ - Error: "Mật khẩu phải chứa chữ hoa, chữ thường, số và ký tự đặc biệt" confirmPassword: - Required: "Vui lòng xác nhận mật khẩu" - Must match password: "Mật khẩu không khớp" ``` ### 4. UX Features ✅ **Loading State** ```tsx {isLoading ? ( <> Đang xử lý... ) : ( <> Đăng ký )} ``` ✅ **Show/Hide Password** (2 toggles) - Eye/EyeOff icons - Separate toggle cho password và confirmPassword - Visual feedback khi hover ✅ **Error Display** - Inline validation errors dưới mỗi field - Global error message ở top của form - Red border cho fields có lỗi ✅ **Success Flow** ```typescript 1. Submit form 2. Validation passes 3. Call useAuthStore.register() 4. Show toast: "Đăng ký thành công! Vui lòng đăng nhập." 5. Navigate to /login ``` ### 5. Design & Styling **Color Scheme:** - Primary: purple-600, purple-700 - Background: gradient from-purple-50 to-pink-100 - Success: green-500, green-600 - Error: red-50, red-200, red-600 - Text: gray-600, gray-700, gray-900 **Layout:** ``` ┌─────────────────────────────────────┐ │ 🏨 Hotel Icon (Purple) │ │ Đăng ký tài khoản │ │ Tạo tài khoản mới để đặt phòng... │ ├─────────────────────────────────────┤ │ ┌───────────────────────────────┐ │ │ │ [Error message if any] │ │ │ ├───────────────────────────────┤ │ │ │ Họ và tên │ │ │ │ [👤 Nguyễn Văn A ] │ │ │ ├───────────────────────────────┤ │ │ │ Email │ │ │ │ [📧 email@example.com ] │ │ │ ├───────────────────────────────┤ │ │ │ Số điện thoại (Tùy chọn) │ │ │ │ [📱 0123456789 ] │ │ │ ├───────────────────────────────┤ │ │ │ Mật khẩu │ │ │ │ [🔒 •••••••• 👁️] │ │ │ │ ▓▓▓▓▓░░░░░ Rất mạnh │ │ │ │ ✅ Ít nhất 8 ký tự │ │ │ │ ✅ Chữ thường (a-z) │ │ │ │ ✅ Chữ hoa (A-Z) │ │ │ │ ✅ Số (0-9) │ │ │ │ ✅ Ký tự đặc biệt │ │ │ ├───────────────────────────────┤ │ │ │ Xác nhận mật khẩu │ │ │ │ [🔒 •••••••• 👁️] │ │ │ ├───────────────────────────────┤ │ │ │ [👤 Đăng ký] │ │ │ └───────────────────────────────┘ │ │ Đã có tài khoản? Đăng nhập ngay │ │ │ │ Điều khoản & Chính sách bảo mật │ └─────────────────────────────────────┘ ``` ## 🔗 Integration ### API Endpoint ``` POST /api/auth/register ``` ### Request Body ```typescript { name: string; // "Nguyễn Văn A" email: string; // "user@example.com" password: string; // "Password123@" phone?: string; // "0123456789" (optional) } ``` ### Response (Success) ```json { "status": "success", "message": "User registered successfully", "data": { "user": { "id": 1, "name": "Nguyễn Văn A", "email": "user@example.com", "phone": "0123456789", "role": "customer" }, "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." } } ``` ### useAuthStore Integration ```typescript const { register: registerUser, isLoading, error, clearError } = useAuthStore(); await registerUser({ name: data.name, email: data.email, password: data.password, phone: data.phone, }); // After success: navigate('/login', { replace: true }); ``` ## 🧪 Test Scenarios ### 1. Validation Tests **Test Case 1: Empty form** ``` Action: Submit empty form Expected: Show validation errors for name, email, password ``` **Test Case 2: Invalid email** ``` Input: email = "notanemail" Expected: "Email không hợp lệ" ``` **Test Case 3: Short name** ``` Input: name = "A" Expected: "Họ tên phải có ít nhất 2 ký tự" ``` **Test Case 4: Weak password** ``` Input: password = "abc123" Expected: "Mật khẩu phải chứa chữ hoa, chữ thường, số và ký tự đặc biệt" Password strength: Yếu/Trung bình ``` **Test Case 5: Password mismatch** ``` Input: password = "Password123@" confirmPassword = "Password456@" Expected: "Mật khẩu không khớp" ``` **Test Case 6: Invalid phone** ``` Input: phone = "123" Expected: "Số điện thoại không hợp lệ" ``` ### 2. UX Tests **Test Case 7: Password strength indicator** ``` Input: Type password character by character Expected: - Progress bar animates - Color changes: red → orange → yellow → blue → green - Checkmarks appear as requirements met ``` **Test Case 8: Show/hide password** ``` Action: Click eye icon on password field Expected: Password text becomes visible/hidden Action: Click eye icon on confirmPassword field Expected: Confirm password text becomes visible/hidden ``` **Test Case 9: Loading state** ``` Action: Submit valid form Expected: - Button disabled - Spinner shows - Text changes to "Đang xử lý..." ``` ### 3. Integration Tests **Test Case 10: Successful registration** ``` Input: All valid data Expected: 1. API POST /api/auth/register called 2. Toast: "Đăng ký thành công! Vui lòng đăng nhập." 3. Redirect to /login ``` **Test Case 11: Email already exists** ``` Input: email = "existing@example.com" Expected: - Error message: "Email already registered" - Toast error displayed - Form remains on page ``` **Test Case 12: Network error** ``` Scenario: Server offline Expected: - Error message: "Đăng ký thất bại. Vui lòng thử lại." - Toast error displayed ``` ## 📊 Password Strength Algorithm ```typescript function getPasswordStrength(pwd: string) { let strength = 0; if (pwd.length >= 8) strength++; // +1 if (/[a-z]/.test(pwd)) strength++; // +1 if (/[A-Z]/.test(pwd)) strength++; // +1 if (/\d/.test(pwd)) strength++; // +1 if (/[@$!%*?&]/.test(pwd)) strength++; // +1 return { strength: 0-5, label: ['Rất yếu', 'Yếu', 'Trung bình', 'Mạnh', 'Rất mạnh'][strength], color: ['bg-red-500', 'bg-orange-500', 'bg-yellow-500', 'bg-blue-500', 'bg-green-500'][strength] }; } ``` ## 🎨 Component Structure ```tsx RegisterPage/ ├── Header Section │ ├── Hotel Icon (purple) │ ├── Title: "Đăng ký tài khoản" │ └── Subtitle │ ├── Form Container (white card) │ ├── Error Alert (conditional) │ ├── Name Input │ ├── Email Input │ ├── Phone Input (optional) │ ├── Password Input │ │ ├── Show/Hide Toggle │ │ ├── Strength Indicator │ │ └── Requirements Checklist │ ├── Confirm Password Input │ │ └── Show/Hide Toggle │ └── Submit Button (with loading) │ ├── Login Link │ └── "Đã có tài khoản? Đăng nhập ngay" │ └── Footer Links ├── Terms of Service └── Privacy Policy ``` ## 🔐 Security Features ### 1. Password Validation - Min 8 characters - Requires: uppercase, lowercase, number, special char - Visual feedback for strength ### 2. Confirm Password - Must match original password - Prevents typos ### 3. Client-side Validation - Immediate feedback - Prevents invalid API calls - Better UX ### 4. Server-side Validation - Backend also validates all fields - Checks email uniqueness - Password hashed with bcrypt ## 📝 Code Quality ✅ **TypeScript**: Full type safety ✅ **React Hook Form**: Optimized re-renders ✅ **Yup Validation**: Schema-based validation ✅ **Component Composition**: Reusable PasswordRequirement component ✅ **Accessibility**: Proper labels, IDs, autocomplete ✅ **Error Handling**: Try-catch, user-friendly messages ✅ **Loading States**: Visual feedback during async operations ✅ **Responsive Design**: Works on mobile and desktop ✅ **80 chars/line**: Code formatting standard ## 🚀 Usage ### Navigate to Register Page ```bash http://localhost:5173/register ``` ### Example Registration ```typescript Name: "Nguyễn Văn A" Email: "nguyenvana@example.com" Phone: "0123456789" Password: "Password123@" Confirm: "Password123@" Submit → Success → Redirect to /login ``` ## 🔄 Flow Diagram ``` User visits /register ↓ Fill in form fields ↓ Real-time validation (Yup) ↓ Password strength updates live ↓ Submit button clicked ↓ Frontend validation passes ↓ Call useAuthStore.register() ↓ API POST /api/auth/register ↓ ┌───────┴───────┐ ↓ ↓ Success Failure ↓ ↓ Toast success Toast error ↓ ↓ Navigate Stay on page to /login Show errors ``` ## ✅ Checklist - [x] ✅ Create RegisterPage.tsx component - [x] ✅ Implement React Hook Form - [x] ✅ Add Yup validation schema - [x] ✅ Add 5 form fields (name, email, phone, password, confirmPassword) - [x] ✅ Show/hide password toggle (2 fields) - [x] ✅ Password strength indicator - [x] ✅ Real-time requirements checker - [x] ✅ Loading state - [x] ✅ Error display (inline + global) - [x] ✅ Integration with useAuthStore - [x] ✅ Redirect to /login after success - [x] ✅ Toast notifications - [x] ✅ Add route to App.tsx - [x] ✅ Responsive design - [x] ✅ Purple color scheme - [x] ✅ Icons integration (Lucide React) - [x] ✅ Terms & Privacy links ## 📚 Related Files - `client/src/pages/auth/LoginPage.tsx` - Login form (same design pattern) - `client/src/utils/validationSchemas.ts` - Validation schemas - `client/src/store/useAuthStore.ts` - Auth state management - `client/src/services/api/authService.ts` - API calls - `client/src/App.tsx` - Route configuration --- **Status:** ✅ Chức năng 5 hoàn thành **Next:** Chức năng 6 - Forgot Password **Test URL:** http://localhost:5173/register