update
This commit is contained in:
@@ -1,89 +1,89 @@
|
||||
# Chức năng 5: Form Đăng Ký - Hoàn Thành ✅
|
||||
# Function 5: Register Form - Completed ✅
|
||||
|
||||
## 📦 Files Đã Tạo/Cập Nhật
|
||||
## 📦 Files Created/Updated
|
||||
|
||||
### 1. **RegisterPage.tsx** - Component form đăng ký
|
||||
**Đường dẫn:** `client/src/pages/auth/RegisterPage.tsx`
|
||||
### 1. **RegisterPage.tsx** - Register form component
|
||||
**Path:** `client/src/pages/auth/RegisterPage.tsx`
|
||||
|
||||
### 2. **index.ts** - Export module
|
||||
**Đường dẫn:** `client/src/pages/auth/index.ts`
|
||||
- Đã thêm export RegisterPage
|
||||
**Path:** `client/src/pages/auth/index.ts`
|
||||
- Added export RegisterPage
|
||||
|
||||
### 3. **App.tsx** - Cập nhật routing
|
||||
**Đường dẫn:** `client/src/App.tsx`
|
||||
- Đã thêm route `/register`
|
||||
### 3. **App.tsx** - Routing updated
|
||||
**Path:** `client/src/App.tsx`
|
||||
- Added route `/register`
|
||||
|
||||
## ✨ Tính Năng Chính
|
||||
## ✨ Main Features
|
||||
|
||||
### 1. Form Fields (5 fields)
|
||||
✅ **Họ và tên** (name)
|
||||
- Required, 2-50 ký tự
|
||||
✅ **Full Name** (name)
|
||||
- Required, 2-50 characters
|
||||
- Icon: User
|
||||
- Placeholder: "Nguyễn Văn A"
|
||||
- Placeholder: "John Doe"
|
||||
|
||||
✅ **Email**
|
||||
- Required, valid email format
|
||||
- Icon: Mail
|
||||
- Placeholder: "email@example.com"
|
||||
|
||||
✅ **Số điện thoại** (phone) - Optional
|
||||
- 10-11 chữ số
|
||||
✅ **Phone Number** (phone) - Optional
|
||||
- 10-11 digits
|
||||
- Icon: Phone
|
||||
- Placeholder: "0123456789"
|
||||
|
||||
✅ **Mật khẩu** (password)
|
||||
✅ **Password** (password)
|
||||
- Required, min 8 chars
|
||||
- Must contain: uppercase, lowercase, number, special char
|
||||
- Show/hide toggle với Eye icon
|
||||
- Show/hide toggle with Eye icon
|
||||
- Icon: Lock
|
||||
|
||||
✅ **Xác nhận mật khẩu** (confirmPassword)
|
||||
✅ **Confirm Password** (confirmPassword)
|
||||
- Must match password
|
||||
- Show/hide toggle với Eye icon
|
||||
- Show/hide toggle with 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)
|
||||
✅ **Visual Progress Bar** with 5 levels:
|
||||
1. 🔴 Very weak (0/5)
|
||||
2. 🟠 Weak (1/5)
|
||||
3. 🟡 Medium (2/5)
|
||||
4. 🔵 Strong (3/5)
|
||||
5. 🟢 Very strong (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 (@$!%*?&)
|
||||
- ✅/❌ At least 8 characters
|
||||
- ✅/❌ Lowercase (a-z)
|
||||
- ✅/❌ Uppercase (A-Z)
|
||||
- ✅/❌ Number (0-9)
|
||||
- ✅/❌ Special character (@$!%*?&)
|
||||
|
||||
### 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ự"
|
||||
- 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 là bắt buộc"
|
||||
- Valid format: "Email không hợp lệ"
|
||||
- Required: "Email is required"
|
||||
- Valid format: "Invalid email format"
|
||||
- Trim whitespace
|
||||
|
||||
phone (optional):
|
||||
- Pattern /^[0-9]{10,11}$/
|
||||
- Error: "Số điện thoại không hợp lệ"
|
||||
- Error: "Invalid phone number"
|
||||
|
||||
password:
|
||||
- Required: "Mật khẩu là bắt buộc"
|
||||
- Required: "Password is required"
|
||||
- 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"
|
||||
- Error: "Password must contain uppercase, lowercase, number and special characters"
|
||||
|
||||
confirmPassword:
|
||||
- Required: "Vui lòng xác nhận mật khẩu"
|
||||
- Must match password: "Mật khẩu không khớp"
|
||||
- Required: "Please confirm password"
|
||||
- Must match password: "Passwords do not match"
|
||||
```
|
||||
|
||||
### 4. UX Features
|
||||
@@ -93,32 +93,32 @@ confirmPassword:
|
||||
{isLoading ? (
|
||||
<>
|
||||
<Loader2 className="animate-spin" />
|
||||
Đang xử lý...
|
||||
Processing...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<UserPlus />
|
||||
Đăng ký
|
||||
Register
|
||||
</>
|
||||
)}
|
||||
```
|
||||
|
||||
✅ **Show/Hide Password** (2 toggles)
|
||||
- Eye/EyeOff icons
|
||||
- Separate toggle cho password và confirmPassword
|
||||
- Visual feedback khi hover
|
||||
- Separate toggle for password and confirmPassword
|
||||
- Visual feedback on 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
|
||||
- Inline validation errors under each field
|
||||
- Global error message at top of form
|
||||
- Red border for fields with errors
|
||||
|
||||
✅ **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."
|
||||
4. Show toast: "Registration successful! Please login."
|
||||
5. Navigate to /login
|
||||
```
|
||||
|
||||
@@ -135,38 +135,38 @@ confirmPassword:
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ 🏨 Hotel Icon (Purple) │
|
||||
│ Đăng ký tài khoản │
|
||||
│ Tạo tài khoản mới để đặt phòng... │
|
||||
│ Register Account │
|
||||
│ Create a new account to book... │
|
||||
├─────────────────────────────────────┤
|
||||
│ ┌───────────────────────────────┐ │
|
||||
│ │ [Error message if any] │ │
|
||||
│ ├───────────────────────────────┤ │
|
||||
│ │ Họ và tên │ │
|
||||
│ │ [👤 Nguyễn Văn A ] │ │
|
||||
│ │ Full Name │ │
|
||||
│ │ [👤 John Doe ] │ │
|
||||
│ ├───────────────────────────────┤ │
|
||||
│ │ Email │ │
|
||||
│ │ [📧 email@example.com ] │ │
|
||||
│ ├───────────────────────────────┤ │
|
||||
│ │ Số điện thoại (Tùy chọn) │ │
|
||||
│ │ Phone Number (Optional) │ │
|
||||
│ │ [📱 0123456789 ] │ │
|
||||
│ ├───────────────────────────────┤ │
|
||||
│ │ Mật khẩu │ │
|
||||
│ │ Password │ │
|
||||
│ │ [🔒 •••••••• 👁️] │ │
|
||||
│ │ ▓▓▓▓▓░░░░░ 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 │ │
|
||||
│ │ ▓▓▓▓▓░░░░░ Very strong │ │
|
||||
│ │ ✅ At least 8 characters │ │
|
||||
│ │ ✅ Lowercase (a-z) │ │
|
||||
│ │ ✅ Uppercase (A-Z) │ │
|
||||
│ │ ✅ Number (0-9) │ │
|
||||
│ │ ✅ Special character │ │
|
||||
│ ├───────────────────────────────┤ │
|
||||
│ │ Xác nhận mật khẩu │ │
|
||||
│ │ Confirm Password │ │
|
||||
│ │ [🔒 •••••••• 👁️] │ │
|
||||
│ ├───────────────────────────────┤ │
|
||||
│ │ [👤 Đăng ký] │ │
|
||||
│ │ [👤 Register] │ │
|
||||
│ └───────────────────────────────┘ │
|
||||
│ Đã có tài khoản? Đăng nhập ngay │
|
||||
│ Already have an account? Login now │
|
||||
│ │
|
||||
│ Điều khoản & Chính sách bảo mật │
|
||||
│ Terms & Privacy Policy │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
@@ -180,7 +180,7 @@ POST /api/auth/register
|
||||
### Request Body
|
||||
```typescript
|
||||
{
|
||||
name: string; // "Nguyễn Văn A"
|
||||
name: string; // "John Doe"
|
||||
email: string; // "user@example.com"
|
||||
password: string; // "Password123@"
|
||||
phone?: string; // "0123456789" (optional)
|
||||
@@ -195,7 +195,7 @@ POST /api/auth/register
|
||||
"data": {
|
||||
"user": {
|
||||
"id": 1,
|
||||
"name": "Nguyễn Văn A",
|
||||
"name": "John Doe",
|
||||
"email": "user@example.com",
|
||||
"phone": "0123456789",
|
||||
"role": "customer"
|
||||
@@ -235,20 +235,20 @@ Expected: Show validation errors for name, email, password
|
||||
**Test Case 2: Invalid email**
|
||||
```
|
||||
Input: email = "notanemail"
|
||||
Expected: "Email không hợp lệ"
|
||||
Expected: "Invalid email format"
|
||||
```
|
||||
|
||||
**Test Case 3: Short name**
|
||||
```
|
||||
Input: name = "A"
|
||||
Expected: "Họ tên phải có ít nhất 2 ký tự"
|
||||
Expected: "Full name must be at least 2 characters"
|
||||
```
|
||||
|
||||
**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
|
||||
Expected: "Password must contain uppercase, lowercase, number and special characters"
|
||||
Password strength: Weak/Medium
|
||||
```
|
||||
|
||||
**Test Case 5: Password mismatch**
|
||||
@@ -256,13 +256,13 @@ Password strength: Yếu/Trung bình
|
||||
Input:
|
||||
password = "Password123@"
|
||||
confirmPassword = "Password456@"
|
||||
Expected: "Mật khẩu không khớp"
|
||||
Expected: "Passwords do not match"
|
||||
```
|
||||
|
||||
**Test Case 6: Invalid phone**
|
||||
```
|
||||
Input: phone = "123"
|
||||
Expected: "Số điện thoại không hợp lệ"
|
||||
Expected: "Invalid phone number"
|
||||
```
|
||||
|
||||
### 2. UX Tests
|
||||
@@ -290,7 +290,7 @@ Action: Submit valid form
|
||||
Expected:
|
||||
- Button disabled
|
||||
- Spinner shows
|
||||
- Text changes to "Đang xử lý..."
|
||||
- Text changes to "Processing..."
|
||||
```
|
||||
|
||||
### 3. Integration Tests
|
||||
@@ -300,7 +300,7 @@ Expected:
|
||||
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."
|
||||
2. Toast: "Registration successful! Please login."
|
||||
3. Redirect to /login
|
||||
```
|
||||
|
||||
@@ -317,7 +317,7 @@ Expected:
|
||||
```
|
||||
Scenario: Server offline
|
||||
Expected:
|
||||
- Error message: "Đăng ký thất bại. Vui lòng thử lại."
|
||||
- Error message: "Registration failed. Please try again."
|
||||
- Toast error displayed
|
||||
```
|
||||
|
||||
@@ -335,7 +335,7 @@ function getPasswordStrength(pwd: string) {
|
||||
|
||||
return {
|
||||
strength: 0-5,
|
||||
label: ['Rất yếu', 'Yếu', 'Trung bình', 'Mạnh', 'Rất mạnh'][strength],
|
||||
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]
|
||||
};
|
||||
}
|
||||
@@ -347,7 +347,7 @@ function getPasswordStrength(pwd: string) {
|
||||
RegisterPage/
|
||||
├── Header Section
|
||||
│ ├── Hotel Icon (purple)
|
||||
│ ├── Title: "Đăng ký tài khoản"
|
||||
│ ├── Title: "Register Account"
|
||||
│ └── Subtitle
|
||||
│
|
||||
├── Form Container (white card)
|
||||
@@ -364,7 +364,7 @@ RegisterPage/
|
||||
│ └── Submit Button (with loading)
|
||||
│
|
||||
├── Login Link
|
||||
│ └── "Đã có tài khoản? Đăng nhập ngay"
|
||||
│ └── "Already have an account? Login now"
|
||||
│
|
||||
└── Footer Links
|
||||
├── Terms of Service
|
||||
@@ -413,7 +413,7 @@ http://localhost:5173/register
|
||||
|
||||
### Example Registration
|
||||
```typescript
|
||||
Name: "Nguyễn Văn A"
|
||||
Name: "John Doe"
|
||||
Email: "nguyenvana@example.com"
|
||||
Phone: "0123456789"
|
||||
Password: "Password123@"
|
||||
@@ -481,6 +481,6 @@ to /login Show errors
|
||||
|
||||
---
|
||||
|
||||
**Status:** ✅ Chức năng 5 hoàn thành
|
||||
**Next:** Chức năng 6 - Forgot Password
|
||||
**Status:** ✅ Function 5 completed
|
||||
**Next:** Function 6 - Forgot Password
|
||||
**Test URL:** http://localhost:5173/register
|
||||
|
||||
Reference in New Issue
Block a user