12 KiB
Function 5: Register Form - Completed ✅
📦 Files Created/Updated
1. RegisterPage.tsx - Register form component
Path: client/src/pages/auth/RegisterPage.tsx
2. index.ts - Export module
Path: client/src/pages/auth/index.ts
- Added export RegisterPage
3. App.tsx - Routing updated
Path: client/src/App.tsx
- Added route
/register
✨ Main Features
1. Form Fields (5 fields)
✅ Full Name (name)
- Required, 2-50 characters
- Icon: User
- Placeholder: "John Doe"
- Required, valid email format
- Icon: Mail
- Placeholder: "email@example.com"
✅ Phone Number (phone) - Optional
- 10-11 digits
- Icon: Phone
- Placeholder: "0123456789"
✅ Password (password)
- Required, min 8 chars
- Must contain: uppercase, lowercase, number, special char
- Show/hide toggle with Eye icon
- Icon: Lock
✅ Confirm Password (confirmPassword)
- Must match password
- Show/hide toggle with Eye icon
- Icon: Lock
2. Password Strength Indicator
✅ Visual Progress Bar with 5 levels:
- 🔴 Very weak (0/5)
- 🟠 Weak (1/5)
- 🟡 Medium (2/5)
- 🔵 Strong (3/5)
- 🟢 Very strong (5/5)
✅ Real-time Requirements Checker:
- ✅/❌ At least 8 characters
- ✅/❌ Lowercase (a-z)
- ✅/❌ Uppercase (A-Z)
- ✅/❌ Number (0-9)
- ✅/❌ Special character (@$!%*?&)
3. Validation Rules (Yup Schema)
name:
- Required: "Full name is required"
- Min 2 chars: "Full name must be at least 2 characters"
- Max 50 chars: "Full name must not exceed 50 characters"
- Trim whitespace
email:
- Required: "Email is required"
- Valid format: "Invalid email format"
- Trim whitespace
phone (optional):
- Pattern /^[0-9]{10,11}$/
- Error: "Invalid phone number"
password:
- Required: "Password is required"
- Min 8 chars
- Pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])/
- Error: "Password must contain uppercase, lowercase, number and special characters"
confirmPassword:
- Required: "Please confirm password"
- Must match password: "Passwords do not match"
4. UX Features
✅ Loading State
{isLoading ? (
<>
<Loader2 className="animate-spin" />
Processing...
</>
) : (
<>
<UserPlus />
Register
</>
)}
✅ Show/Hide Password (2 toggles)
- Eye/EyeOff icons
- Separate toggle for password and confirmPassword
- Visual feedback on hover
✅ Error Display
- Inline validation errors under each field
- Global error message at top of form
- Red border for fields with errors
✅ Success Flow
1. Submit form
2. Validation passes
3. Call useAuthStore.register()
4. Show toast: "Registration successful! Please login."
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) │
│ Register Account │
│ Create a new account to book... │
├─────────────────────────────────────┤
│ ┌───────────────────────────────┐ │
│ │ [Error message if any] │ │
│ ├───────────────────────────────┤ │
│ │ Full Name │ │
│ │ [👤 John Doe ] │ │
│ ├───────────────────────────────┤ │
│ │ Email │ │
│ │ [📧 email@example.com ] │ │
│ ├───────────────────────────────┤ │
│ │ Phone Number (Optional) │ │
│ │ [📱 0123456789 ] │ │
│ ├───────────────────────────────┤ │
│ │ Password │ │
│ │ [🔒 •••••••• 👁️] │ │
│ │ ▓▓▓▓▓░░░░░ Very strong │ │
│ │ ✅ At least 8 characters │ │
│ │ ✅ Lowercase (a-z) │ │
│ │ ✅ Uppercase (A-Z) │ │
│ │ ✅ Number (0-9) │ │
│ │ ✅ Special character │ │
│ ├───────────────────────────────┤ │
│ │ Confirm Password │ │
│ │ [🔒 •••••••• 👁️] │ │
│ ├───────────────────────────────┤ │
│ │ [👤 Register] │ │
│ └───────────────────────────────┘ │
│ Already have an account? Login now │
│ │
│ Terms & Privacy Policy │
└─────────────────────────────────────┘
🔗 Integration
API Endpoint
POST /api/auth/register
Request Body
{
name: string; // "John Doe"
email: string; // "user@example.com"
password: string; // "Password123@"
phone?: string; // "0123456789" (optional)
}
Response (Success)
{
"status": "success",
"message": "User registered successfully",
"data": {
"user": {
"id": 1,
"name": "John Doe",
"email": "user@example.com",
"phone": "0123456789",
"role": "customer"
},
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}
useAuthStore Integration
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: "Invalid email format"
Test Case 3: Short name
Input: name = "A"
Expected: "Full name must be at least 2 characters"
Test Case 4: Weak password
Input: password = "abc123"
Expected: "Password must contain uppercase, lowercase, number and special characters"
Password strength: Weak/Medium
Test Case 5: Password mismatch
Input:
password = "Password123@"
confirmPassword = "Password456@"
Expected: "Passwords do not match"
Test Case 6: Invalid phone
Input: phone = "123"
Expected: "Invalid phone number"
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 "Processing..."
3. Integration Tests
Test Case 10: Successful registration
Input: All valid data
Expected:
1. API POST /api/auth/register called
2. Toast: "Registration successful! Please login."
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: "Registration failed. Please try again."
- Toast error displayed
📊 Password Strength Algorithm
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: ['Very weak', 'Weak', 'Medium', 'Strong', 'Very strong'][strength],
color: ['bg-red-500', 'bg-orange-500', 'bg-yellow-500', 'bg-blue-500', 'bg-green-500'][strength]
};
}
🎨 Component Structure
RegisterPage/
├── Header Section
│ ├── Hotel Icon (purple)
│ ├── Title: "Register Account"
│ └── 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
│ └── "Already have an account? Login now"
│
└── 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
http://localhost:5173/register
Example Registration
Name: "John Doe"
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
- ✅ Create RegisterPage.tsx component
- ✅ Implement React Hook Form
- ✅ Add Yup validation schema
- ✅ Add 5 form fields (name, email, phone, password, confirmPassword)
- ✅ Show/hide password toggle (2 fields)
- ✅ Password strength indicator
- ✅ Real-time requirements checker
- ✅ Loading state
- ✅ Error display (inline + global)
- ✅ Integration with useAuthStore
- ✅ Redirect to /login after success
- ✅ Toast notifications
- ✅ Add route to App.tsx
- ✅ Responsive design
- ✅ Purple color scheme
- ✅ Icons integration (Lucide React)
- ✅ Terms & Privacy links
📚 Related Files
client/src/pages/auth/LoginPage.tsx- Login form (same design pattern)client/src/utils/validationSchemas.ts- Validation schemasclient/src/store/useAuthStore.ts- Auth state managementclient/src/services/api/authService.ts- API callsclient/src/App.tsx- Route configuration
Status: ✅ Function 5 completed Next: Function 6 - Forgot Password Test URL: http://localhost:5173/register