From 93d4c1df80c14087991e2454a697a5765c21dd20 Mon Sep 17 00:00:00 2001 From: Iliyan Angelov Date: Sun, 16 Nov 2025 15:12:43 +0200 Subject: [PATCH] update --- client/ROUTING_GUIDE.md | 158 ++++++------ client/ZUSTAND_AUTH_GUIDE.md | 150 ++++++------ client/src/App.tsx | 24 +- client/src/components/auth/AdminRoute.tsx | 16 +- client/src/components/auth/ProtectedRoute.tsx | 12 +- .../src/components/common/ErrorBoundary.tsx | 12 +- client/src/components/common/Pagination.tsx | 12 +- client/src/components/layout/SidebarAdmin.tsx | 20 +- .../src/components/rooms/BannerCarousel.tsx | 2 +- .../src/components/rooms/FavoriteButton.tsx | 4 +- client/src/examples/useAuthStoreExamples.tsx | 36 +-- .../src/pages/admin/BookingManagementPage.tsx | 2 +- client/src/pages/admin/CheckInPage.tsx | 4 +- client/src/pages/admin/DashboardPage.tsx | 18 +- .../pages/admin/PromotionManagementPage.tsx | 76 +++--- .../src/pages/admin/ReviewManagementPage.tsx | 6 +- client/src/pages/admin/RoomManagementPage.tsx | 78 +++--- .../src/pages/admin/ServiceManagementPage.tsx | 44 ++-- client/src/pages/auth/ForgotPasswordPage.tsx | 2 +- client/src/pages/auth/LoginPage.tsx | 4 +- client/src/pages/auth/RegisterPage.tsx | 4 +- client/src/pages/auth/ResetPasswordPage.tsx | 62 ++--- .../src/pages/customer/BookingDetailPage.tsx | 107 ++++----- client/src/pages/customer/BookingListPage.tsx | 22 +- client/src/pages/customer/BookingPage.tsx | 2 +- .../src/pages/customer/BookingSuccessPage.tsx | 123 +++++----- client/src/pages/customer/DashboardPage.tsx | 38 +-- .../src/pages/customer/DepositPaymentPage.tsx | 92 +++---- client/src/pages/customer/FavoritesPage.tsx | 24 +- client/src/pages/customer/MyBookingsPage.tsx | 2 +- .../customer/PaymentConfirmationPage.tsx | 2 +- .../src/pages/customer/PaymentResultPage.tsx | 2 +- client/src/pages/customer/RoomDetailPage.tsx | 32 +-- client/src/pages/customer/RoomListPage.tsx | 14 +- client/src/services/api/apiClient.ts | 6 +- client/src/services/api/authService.ts | 16 +- client/src/services/api/bookingService.ts | 2 +- client/src/validators/bookingValidator.ts | 42 ++-- docs/FORGOT_PASSWORD_COMPLETE.md | 80 +++---- docs/LAYOUT_IMPLEMENTATION.md | 150 ++++++------ docs/LOGIN_FORM_GUIDE.md | 192 +++++++-------- docs/REGISTER_FORM_COMPLETE.md | 162 ++++++------- docs/ROUTE_PROTECTION.md | 226 +++++++++--------- docs/SERVER_SETUP_COMPLETE.md | 10 +- docs/TEST_ROUTE_PROTECTION.md | 8 +- docs/tasks-admin.md | 200 ++++++++-------- docs/tasks_1_Authentication.md | 224 ++++++++--------- docs/tasks_2_Home_&_RoomSearch.md | 226 +++++++++--------- docs/tasks_3_Booking_&_Payment.md | 182 +++++++------- docs/tasks_5_Review_System.md | 184 +++++++------- server/QUICK_START.md | 74 +++--- server/src/controllers/authController.js | 2 +- server/src/controllers/favoriteController.js | 10 +- .../20250101000010-seed-service-usages.js | 16 +- 54 files changed, 1606 insertions(+), 1612 deletions(-) diff --git a/client/ROUTING_GUIDE.md b/client/ROUTING_GUIDE.md index 31fd1790..b156e3f3 100644 --- a/client/ROUTING_GUIDE.md +++ b/client/ROUTING_GUIDE.md @@ -1,138 +1,138 @@ -# Routing Configuration - Hướng dẫn Test +# Routing Configuration - Testing Guide -## ✅ Đã hoàn thành Chức năng 2 +## ✅ Function 2 Completed -### Components đã tạo: +### Components Created: 1. **ProtectedRoute** - `src/components/auth/ProtectedRoute.tsx` - - Bảo vệ routes yêu cầu authentication - - Redirect về `/login` nếu chưa đăng nhập - - Lưu location để quay lại sau khi login + - Protects routes requiring authentication + - Redirects to `/login` if not logged in + - Saves location to return after login 2. **AdminRoute** - `src/components/auth/AdminRoute.tsx` - - Bảo vệ routes chỉ dành cho Admin - - Redirect về `/` nếu không phải admin - - Kiểm tra `userInfo.role === 'admin'` + - Protects routes for Admin only + - Redirects to `/` if not admin + - Checks `userInfo.role === 'admin'` 3. **Page Components**: - - `RoomListPage` - Danh sách phòng (public) - - `BookingListPage` - Lịch sử đặt phòng (protected) - - `DashboardPage` - Dashboard cá nhân (protected) + - `RoomListPage` - Room list (public) + - `BookingListPage` - Booking history (protected) + - `DashboardPage` - Personal dashboard (protected) -### Cấu trúc Routes: +### Route Structure: -#### Public Routes (Không cần đăng nhập): +#### Public Routes (No login required): ``` / → HomePage /rooms → RoomListPage /about → About Page -/login → Login Page (chưa có) -/register → Register Page (chưa có) -/forgot-password → Forgot Password Page (chưa có) -/reset-password/:token → Reset Password Page (chưa có) +/login → Login Page (not yet) +/register → Register Page (not yet) +/forgot-password → Forgot Password Page (not yet) +/reset-password/:token → Reset Password Page (not yet) ``` -#### Protected Routes (Cần đăng nhập): +#### Protected Routes (Login required): ``` /dashboard → DashboardPage (ProtectedRoute) /bookings → BookingListPage (ProtectedRoute) /profile → Profile Page (ProtectedRoute) ``` -#### Admin Routes (Chỉ Admin): +#### Admin Routes (Admin only): ``` /admin → AdminLayout (AdminRoute) /admin/dashboard → Admin Dashboard -/admin/users → Quản lý người dùng -/admin/rooms → Quản lý phòng -/admin/bookings → Quản lý đặt phòng -/admin/payments → Quản lý thanh toán -/admin/services → Quản lý dịch vụ -/admin/promotions → Quản lý khuyến mãi -/admin/banners → Quản lý banner -/admin/reports → Báo cáo -/admin/settings → Cài đặt +/admin/users → User Management +/admin/rooms → Room Management +/admin/bookings → Booking Management +/admin/payments → Payment Management +/admin/services → Service Management +/admin/promotions → Promotion Management +/admin/banners → Banner Management +/admin/reports → Reports +/admin/settings → Settings ``` -## 🧪 Cách Test +## 🧪 How to Test -### 1. Khởi động Dev Server: +### 1. Start Dev Server: ```bash cd /d/hotel-booking/client npm run dev ``` -Mở `http://localhost:5173` +Open `http://localhost:5173` ### 2. Test Public Routes: -- Truy cập `/` → Hiển thị HomePage ✅ -- Truy cập `/rooms` → Hiển thị RoomListPage ✅ -- Truy cập `/about` → Hiển thị About Page ✅ +- Access `/` → Display HomePage ✅ +- Access `/rooms` → Display RoomListPage ✅ +- Access `/about` → Display About Page ✅ -### 3. Test Protected Routes (Chưa login): -- Truy cập `/dashboard` → Redirect về `/login` ✅ -- Truy cập `/bookings` → Redirect về `/login` ✅ -- Truy cập `/profile` → Redirect về `/login` ✅ +### 3. Test Protected Routes (Not logged in): +- Access `/dashboard` → Redirect to `/login` ✅ +- Access `/bookings` → Redirect to `/login` ✅ +- Access `/profile` → Redirect to `/login` ✅ -### 4. Test Protected Routes (Đã login): -- Click nút **"🔒 Demo Login"** ở góc dưới phải -- Truy cập `/dashboard` → Hiển thị Dashboard ✅ -- Truy cập `/bookings` → Hiển thị Booking List ✅ -- Truy cập `/profile` → Hiển thị Profile ✅ +### 4. Test Protected Routes (Logged in): +- Click **"🔒 Demo Login"** button at bottom right +- Access `/dashboard` → Display Dashboard ✅ +- Access `/bookings` → Display Booking List ✅ +- Access `/profile` → Display Profile ✅ ### 5. Test Admin Routes (Role = Customer): -- Đảm bảo đã login (role = customer) -- Truy cập `/admin` → Redirect về `/` ✅ -- Truy cập `/admin/dashboard` → Redirect về `/` ✅ +- Ensure logged in (role = customer) +- Access `/admin` → Redirect to `/` ✅ +- Access `/admin/dashboard` → Redirect to `/` ✅ ### 6. Test Admin Routes (Role = Admin): -- Click nút **"👑 Switch to Admin"** -- Truy cập `/admin` → Redirect về `/admin/dashboard` ✅ -- Truy cập `/admin/users` → Hiển thị User Management ✅ -- Truy cập `/admin/rooms` → Hiển thị Room Management ✅ -- Click các menu trong SidebarAdmin → Hoạt động bình thường ✅ +- Click **"👑 Switch to Admin"** button +- Access `/admin` → Redirect to `/admin/dashboard` ✅ +- Access `/admin/users` → Display User Management ✅ +- Access `/admin/rooms` → Display Room Management ✅ +- Click menu items in SidebarAdmin → Works normally ✅ ### 7. Test Logout: -- Click nút **"🔓 Demo Logout"** -- Truy cập `/dashboard` → Redirect về `/login` ✅ -- Truy cập `/admin` → Redirect về `/` ✅ +- Click **"🔓 Demo Logout"** button +- Access `/dashboard` → Redirect to `/login` ✅ +- Access `/admin` → Redirect to `/` ✅ -## 🎯 Kết quả mong đợi +## 🎯 Expected Results ### ✅ ProtectedRoute: -1. User chưa login không thể truy cập protected routes -2. Redirect về `/login` và lưu `state.from` để quay lại sau -3. User đã login có thể truy cập protected routes bình thường +1. Users not logged in cannot access protected routes +2. Redirect to `/login` and save `state.from` to return later +3. Logged in users can access protected routes normally ### ✅ AdminRoute: -1. User không phải admin không thể truy cập `/admin/*` -2. Redirect về `/` nếu không phải admin -3. Admin có thể truy cập tất cả admin routes +1. Non-admin users cannot access `/admin/*` +2. Redirect to `/` if not admin +3. Admin can access all admin routes -### ✅ Không có redirect loop: -1. Redirect chỉ xảy ra 1 lần -2. Không có vòng lặp redirect vô tận -3. Browser history hoạt động đúng (back/forward) +### ✅ No redirect loop: +1. Redirect only happens once +2. No infinite redirect loop +3. Browser history works correctly (back/forward) -## 📝 Demo Buttons (Tạm thời) +## 📝 Demo Buttons (Temporary) ### 🔒 Demo Login/Logout: -- Click để toggle authentication state -- Mô phỏng login/logout -- Sẽ được thay bằng Zustand store ở Chức năng 3 +- Click to toggle authentication state +- Simulates login/logout +- Will be replaced by Zustand store in Function 3 ### 👑 Switch Role: -- Chỉ hiển thị khi đã login -- Toggle giữa `customer` ↔ `admin` -- Test AdminRoute hoạt động đúng +- Only displays when logged in +- Toggle between `customer` ↔ `admin` +- Test AdminRoute works correctly -## 🚀 Bước tiếp theo +## 🚀 Next Steps -Chức năng 3: useAuthStore (Zustand Store) -- Tạo store quản lý auth state toàn cục -- Thay thế demo state bằng Zustand -- Tích hợp với localStorage -- Xóa demo toggle buttons +Function 3: useAuthStore (Zustand Store) +- Create store to manage global auth state +- Replace demo state with Zustand +- Integrate with localStorage +- Remove demo toggle buttons ## 🔧 File Structure diff --git a/client/ZUSTAND_AUTH_GUIDE.md b/client/ZUSTAND_AUTH_GUIDE.md index c834335b..a796bcbc 100644 --- a/client/ZUSTAND_AUTH_GUIDE.md +++ b/client/ZUSTAND_AUTH_GUIDE.md @@ -1,15 +1,15 @@ # useAuthStore - Zustand Authentication Store -## ✅ Hoàn thành Chức năng 3 +## ✅ Function 3 Completed -### 📦 Files đã tạo: +### 📦 Files Created: -1. **`src/store/useAuthStore.ts`** - Zustand store quản lý auth -2. **`src/services/api/apiClient.ts`** - Axios client với interceptors +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 cho environment variables +4. **`.env.example`** - Template for environment variables -### 🎯 Tính năng đã implement: +### 🎯 Features Implemented: #### State Management: ```typescript @@ -24,19 +24,19 @@ interface AuthState { ``` #### Actions: -- ✅ `login(credentials)` - Đăng nhập -- ✅ `register(data)` - Đăng ký tài khoản mới -- ✅ `logout()` - Đăng xuất -- ✅ `setUser(user)` - Cập nhật thông tin user -- ✅ `refreshAuthToken()` - Làm mới token -- ✅ `forgotPassword(data)` - Quên mật khẩu -- ✅ `resetPassword(data)` - Đặt lại mật khẩu -- ✅ `initializeAuth()` - Khởi tạo auth từ localStorage -- ✅ `clearError()` - Xóa error message +- ✅ `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 -### 📝 Cách sử dụng: +### 📝 Usage: -#### 1. Khởi tạo trong App.tsx: +#### 1. Initialize in App.tsx: ```typescript import useAuthStore from './store/useAuthStore'; @@ -56,7 +56,7 @@ function App() { } ``` -#### 2. Sử dụng trong Login Form: +#### 2. Use in Login Form: ```typescript import useAuthStore from '../store/useAuthStore'; @@ -67,9 +67,9 @@ const LoginPage = () => { const handleSubmit = async (data) => { try { await login(data); - navigate('/dashboard'); // Redirect sau khi login + navigate('/dashboard'); // Redirect after login } catch (error) { - // Error đã được xử lý bởi store + // Error has been handled by store } }; @@ -78,14 +78,14 @@ const LoginPage = () => { {/* Form fields */} {error &&
{error}
} ); }; ``` -#### 3. Sử dụng trong Register Form: +#### 3. Use in Register Form: ```typescript const RegisterPage = () => { const { register, isLoading } = useAuthStore(); @@ -94,9 +94,9 @@ const RegisterPage = () => { const handleSubmit = async (data) => { try { await register(data); - navigate('/login'); // Redirect về login + navigate('/login'); // Redirect to login } catch (error) { - // Error được hiển thị qua toast + // Error displayed via toast } }; @@ -111,21 +111,21 @@ const Header = () => { const handleLogout = async () => { await logout(); - // Auto redirect về login nếu cần + // Auto redirect to login if needed }; - return ; + return ; }; ``` -#### 5. Hiển thị thông tin user: +#### 5. Display user information: ```typescript const Profile = () => { const { userInfo } = useAuthStore(); return (
-

Xin chào, {userInfo?.name}

+

Hello, {userInfo?.name}

Email: {userInfo?.email}

Role: {userInfo?.role}

@@ -135,68 +135,68 @@ const Profile = () => { ### 🔐 LocalStorage Persistence: -Store tự động lưu và đọc từ localStorage: +Store automatically saves and reads from localStorage: - `token` - JWT access token - `refreshToken` - JWT refresh token -- `userInfo` - Thông tin user +- `userInfo` - User information -Khi reload page, auth state được khôi phục tự động qua `initializeAuth()`. +When page reloads, auth state is automatically restored via `initializeAuth()`. ### 🌐 API Integration: #### Base URL Configuration: -Tạo file `.env` trong thư mục `client/`: +Create `.env` file in `client/` directory: ```env VITE_API_URL=http://localhost:3000 VITE_ENV=development ``` -#### API Endpoints được sử dụng: -- `POST /api/auth/login` - Đăng nhập -- `POST /api/auth/register` - Đăng ký -- `POST /api/auth/logout` - Đăng xuất -- `GET /api/auth/profile` - Lấy profile +#### 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` - Quên mật khẩu -- `POST /api/auth/reset-password` - Đặt lại mật khẩu +- `POST /api/auth/forgot-password` - Forgot password +- `POST /api/auth/reset-password` - Reset password ### 🛡️ Security Features: 1. **Auto Token Injection**: - - Axios interceptor tự động thêm token vào headers + - Axios interceptor automatically adds token to headers ```typescript Authorization: Bearer ``` 2. **Auto Logout on 401**: - - Khi token hết hạn (401), tự động logout và redirect về login + - When token expires (401), automatically logout and redirect to login 3. **Token Refresh**: - - Có thể refresh token khi sắp hết hạn + - Can refresh token when about to expire 4. **Password Hashing**: - - Backend xử lý bcrypt hashing + - Backend handles bcrypt hashing ### 📱 Toast Notifications: -Store tự động hiển thị toast cho các events: -- ✅ Login thành công -- ✅ Đăng ký thành công +Store automatically displays toast for events: +- ✅ Login successful +- ✅ Registration successful - ✅ Logout -- ❌ Login thất bại -- ❌ Đăng ký thất bại +- ❌ Login failed +- ❌ Registration failed - ❌ API errors ### 🔄 Component Updates: #### ProtectedRoute: ```typescript -// TRƯỚC (với props) +// BEFORE (with props) -// SAU (tự động lấy từ store) +// AFTER (automatically gets from store) @@ -204,19 +204,19 @@ Store tự động hiển thị toast cho các events: #### AdminRoute: ```typescript -// TRƯỚC (với props) +// BEFORE (with props) -// SAU (tự động lấy từ store) +// AFTER (automatically gets from store) ``` #### LayoutMain: -Vẫn nhận props từ App.tsx để hiển thị Header/Navbar: +Still receives props from App.tsx to display Header/Navbar: ```typescript = ({ title }) => (

{title}

- Page này đang được phát triển... + This page is under development...

); function App() { - // Sử dụng Zustand store + // Use Zustand store const { isAuthenticated, userInfo, @@ -96,7 +96,7 @@ function App() { loadGuestFavorites, } = useFavoritesStore(); - // Khởi tạo auth state khi app load + // Initialize auth state when app loads useEffect(() => { initializeAuth(); }, [initializeAuth]); @@ -161,10 +161,10 @@ function App() { /> } + element={} /> - {/* Protected Routes - Yêu cầu đăng nhập */} + {/* Protected Routes - Requires login */} - + } /> @@ -249,7 +249,7 @@ function App() { element={} /> - {/* Admin Routes - Chỉ admin mới truy cập được */} + {/* Admin Routes - Only admin can access */} } + element={} /> } + element={} /> } + element={} /> {/* 404 Route */} } + element={} /> diff --git a/client/src/components/auth/AdminRoute.tsx b/client/src/components/auth/AdminRoute.tsx index c6c253e0..b842b5f5 100644 --- a/client/src/components/auth/AdminRoute.tsx +++ b/client/src/components/auth/AdminRoute.tsx @@ -7,11 +7,11 @@ interface AdminRouteProps { } /** - * AdminRoute - Bảo vệ các route chỉ dành cho Admin + * AdminRoute - Protects routes that are only for Admin * - * Kiểm tra: - * 1. User đã đăng nhập chưa → nếu chưa, redirect /login - * 2. User có role admin không → nếu không, redirect / + * Checks: + * 1. Is user logged in → if not, redirect to /login + * 2. Does user have admin role → if not, redirect to / */ const AdminRoute: React.FC = ({ children @@ -19,7 +19,7 @@ const AdminRoute: React.FC = ({ const location = useLocation(); const { isAuthenticated, userInfo, isLoading } = useAuthStore(); - // Đang loading auth state → hiển thị loading + // Loading auth state → show loading if (isLoading) { return (
= ({ border-b-2 border-indigo-600 mx-auto" />

- Đang xác thực... + Authenticating...

); } - // Chưa đăng nhập → redirect về /login + // Not logged in → redirect to /login if (!isAuthenticated) { return ( = ({ ); } - // Đã đăng nhập nhưng không phải admin → redirect về / + // Logged in but not admin → redirect to / const isAdmin = userInfo?.role === 'admin'; if (!isAdmin) { return ; diff --git a/client/src/components/auth/ProtectedRoute.tsx b/client/src/components/auth/ProtectedRoute.tsx index 3b03ed64..6307ccaa 100644 --- a/client/src/components/auth/ProtectedRoute.tsx +++ b/client/src/components/auth/ProtectedRoute.tsx @@ -7,10 +7,10 @@ interface ProtectedRouteProps { } /** - * ProtectedRoute - Bảo vệ các route yêu cầu authentication + * ProtectedRoute - Protects routes that require authentication * - * Nếu user chưa đăng nhập, redirect về /login - * và lưu location hiện tại để redirect về sau khi login + * If user is not logged in, redirect to /login + * and save current location to redirect back after login */ const ProtectedRoute: React.FC = ({ children @@ -18,7 +18,7 @@ const ProtectedRoute: React.FC = ({ const location = useLocation(); const { isAuthenticated, isLoading } = useAuthStore(); - // Đang loading auth state → hiển thị loading + // Loading auth state → show loading if (isLoading) { return (
= ({ border-b-2 border-indigo-600 mx-auto" />

- Đang tải... + Loading...

); } - // Chưa đăng nhập → redirect về /login + // Not logged in → redirect to /login if (!isAuthenticated) { return ( {

- Đã xảy ra lỗi + An Error Occurred

- Xin lỗi, đã có lỗi xảy ra. Vui lòng thử lại - hoặc liên hệ hỗ trợ nếu vấn đề vẫn tiếp diễn. + Sorry, an error has occurred. Please try again + or contact support if the problem persists.

{process.env.NODE_ENV === 'development' && @@ -96,7 +96,7 @@ class ErrorBoundary extends Component { text-red-700 cursor-pointer hover:text-red-800" > - Chi tiết lỗi + Error Details
                 
-                Tải lại trang
+                Reload Page
               
               
             
           
diff --git a/client/src/components/common/Pagination.tsx b/client/src/components/common/Pagination.tsx
index 7c94547d..e9d5bba0 100644
--- a/client/src/components/common/Pagination.tsx
+++ b/client/src/components/common/Pagination.tsx
@@ -69,7 +69,7 @@ const Pagination: React.FC = ({
               : 'text-gray-700 hover:bg-gray-50'
           }`}
         >
-          Trước
+          Previous
         
         
       
 
@@ -88,10 +88,10 @@ const Pagination: React.FC = ({
       

- Hiển thị{' '} - {startItem} đến{' '} - {endItem} trong tổng số{' '} - {totalItems || 0} kết quả + Showing{' '} + {startItem} to{' '} + {endItem} of{' '} + {totalItems || 0} results

diff --git a/client/src/components/layout/SidebarAdmin.tsx b/client/src/components/layout/SidebarAdmin.tsx index 1bdb4254..e3784be2 100644 --- a/client/src/components/layout/SidebarAdmin.tsx +++ b/client/src/components/layout/SidebarAdmin.tsx @@ -53,32 +53,32 @@ const SidebarAdmin: React.FC = ({ { path: '/admin/users', icon: Users, - label: 'Người dùng' + label: 'Users' }, { path: '/admin/rooms', icon: Hotel, - label: 'Phòng' + label: 'Rooms' }, { path: '/admin/bookings', icon: Calendar, - label: 'Đặt phòng' + label: 'Bookings' }, { path: '/admin/payments', icon: CreditCard, - label: 'Thanh toán' + label: 'Payments' }, { path: '/admin/services', icon: Settings, - label: 'Dịch vụ' + label: 'Services' }, { path: '/admin/promotions', icon: Tag, - label: 'Khuyến mãi' + label: 'Promotions' }, { path: '/admin/check-in', @@ -93,22 +93,22 @@ const SidebarAdmin: React.FC = ({ { path: '/admin/reviews', icon: Star, - label: 'Đánh giá' + label: 'Reviews' }, { path: '/admin/banners', icon: Image, - label: 'Banner' + label: 'Banners' }, { path: '/admin/reports', icon: BarChart3, - label: 'Báo cáo' + label: 'Reports' }, { path: '/admin/settings', icon: FileText, - label: 'Cài đặt' + label: 'Settings' }, ]; diff --git a/client/src/components/rooms/BannerCarousel.tsx b/client/src/components/rooms/BannerCarousel.tsx index 41f40198..34a4e26b 100644 --- a/client/src/components/rooms/BannerCarousel.tsx +++ b/client/src/components/rooms/BannerCarousel.tsx @@ -43,7 +43,7 @@ const BannerCarousel: React.FC = ({ // Default fallback banner if no banners provided const defaultBanner = { id: 0, - title: 'Chào mừng đến với Hotel Booking', + title: 'Welcome to Hotel Booking', image_url: '/images/default-banner.jpg', position: 'home', display_order: 0, diff --git a/client/src/components/rooms/FavoriteButton.tsx b/client/src/components/rooms/FavoriteButton.tsx index 2eb0a9b2..599e26e4 100644 --- a/client/src/components/rooms/FavoriteButton.tsx +++ b/client/src/components/rooms/FavoriteButton.tsx @@ -61,8 +61,8 @@ const FavoriteButton: React.FC = ({ }; const tooltipText = favorited - ? 'Bỏ yêu thích' - : 'Thêm vào yêu thích'; + ? 'Remove from favorites' + : 'Add to favorites'; return (
diff --git a/client/src/examples/useAuthStoreExamples.tsx b/client/src/examples/useAuthStoreExamples.tsx index 5864e545..bdab79c0 100644 --- a/client/src/examples/useAuthStoreExamples.tsx +++ b/client/src/examples/useAuthStoreExamples.tsx @@ -1,8 +1,8 @@ /** - * Example: Cách sử dụng useAuthStore trong components + * Example: How to use useAuthStore in components * - * File này chỉ để tham khảo, không được sử dụng - * trong production + * This file is for reference only, should not be used + * in production */ import { useNavigate } from 'react-router-dom'; @@ -23,7 +23,7 @@ export const LoginExample = () => { await login({ email, password }); navigate('/dashboard'); } catch (error) { - // Error đã được xử lý trong store + // Error has been handled in store console.error('Login failed:', error); } }; @@ -38,7 +38,7 @@ export const LoginExample = () => { )} disabled={isLoading} > - {isLoading ? 'Đang xử lý...' : 'Đăng nhập'} + {isLoading ? 'Processing...' : 'Login'}
); @@ -70,7 +70,7 @@ export const RegisterExample = () => { onClick={handleRegister} disabled={isLoading} > - {isLoading ? 'Đang xử lý...' : 'Đăng ký'} + {isLoading ? 'Processing...' : 'Register'} ); }; @@ -82,13 +82,13 @@ export const UserProfileExample = () => { const { userInfo, isAuthenticated } = useAuthStore(); if (!isAuthenticated) { - return

Vui lòng đăng nhập

; + return

Please login

; } return (
-

Thông tin người dùng

-

Tên: {userInfo?.name}

+

User Information

+

Name: {userInfo?.name}

Email: {userInfo?.email}

Role: {userInfo?.role}

{userInfo?.avatar && ( @@ -118,7 +118,7 @@ export const LogoutButtonExample = () => { onClick={handleLogout} disabled={isLoading} > - {isLoading ? 'Đang xử lý...' : 'Đăng xuất'} + {isLoading ? 'Processing...' : 'Logout'} ); }; @@ -134,7 +134,7 @@ export const ForgotPasswordExample = () => { ) => { try { await forgotPassword({ email }); - // Toast sẽ hiển thị thông báo thành công + // Toast will display success message } catch (error) { console.error('Forgot password failed:', error); } @@ -147,7 +147,7 @@ export const ForgotPasswordExample = () => { } disabled={isLoading} > - Gửi email đặt lại mật khẩu + Send password reset email ); }; @@ -185,7 +185,7 @@ export const ResetPasswordExample = () => { } disabled={isLoading} > - Đặt lại mật khẩu + Reset Password ); }; @@ -222,14 +222,14 @@ export const AuthStateCheckExample = () => { } = useAuthStore(); if (isLoading) { - return

Đang tải...

; + return

Loading...

; } if (!isAuthenticated || !token) { - return

Bạn chưa đăng nhập

; + return

You are not logged in

; } - return

Bạn đã đăng nhập

; + return

You are logged in

; }; // ============================================ @@ -250,7 +250,7 @@ export const UpdateUserInfoExample = () => { return ( ); }; @@ -270,7 +270,7 @@ export const ErrorHandlingExample = () => { onClick={clearError} className="mt-2 text-sm text-red-600" > - Đóng + Close
); diff --git a/client/src/pages/admin/BookingManagementPage.tsx b/client/src/pages/admin/BookingManagementPage.tsx index d13b5a34..275c49aa 100644 --- a/client/src/pages/admin/BookingManagementPage.tsx +++ b/client/src/pages/admin/BookingManagementPage.tsx @@ -301,7 +301,7 @@ const BookingManagementPage: React.FC = () => { onClick={() => setShowDetailModal(false)} className="px-4 py-2 bg-gray-200 text-gray-700 rounded-lg hover:bg-gray-300" > - Đóng + Close
diff --git a/client/src/pages/admin/CheckInPage.tsx b/client/src/pages/admin/CheckInPage.tsx index 95a7babf..1210ee30 100644 --- a/client/src/pages/admin/CheckInPage.tsx +++ b/client/src/pages/admin/CheckInPage.tsx @@ -229,7 +229,7 @@ const CheckInPage: React.FC = () => { type="text" value={actualRoomNumber} onChange={(e) => setActualRoomNumber(e.target.value)} - placeholder="VD: 101, 202, 305" + placeholder="e.g: 101, 202, 305" className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500" />

@@ -271,7 +271,7 @@ const CheckInPage: React.FC = () => { value={guest.name} onChange={(e) => handleGuestChange(index, 'name', e.target.value)} className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500" - placeholder="Nguyễn Văn A" + placeholder="John Doe" />

diff --git a/client/src/pages/admin/DashboardPage.tsx b/client/src/pages/admin/DashboardPage.tsx index e5fdb892..61eecccc 100644 --- a/client/src/pages/admin/DashboardPage.tsx +++ b/client/src/pages/admin/DashboardPage.tsx @@ -191,7 +191,7 @@ const DashboardPage: React.FC = () => { ))}
) : ( -

Không có dữ liệu

+

No data available

)} @@ -227,7 +227,7 @@ const DashboardPage: React.FC = () => { })} ) : ( -

Không có dữ liệu

+

No data available

)} @@ -236,7 +236,7 @@ const DashboardPage: React.FC = () => {
{/* Top Rooms */}
-

Top phòng được đặt

+

Top Booked Rooms

{stats?.top_rooms && stats.top_rooms.length > 0 ? (
{stats.top_rooms.map((room, index) => ( @@ -246,8 +246,8 @@ const DashboardPage: React.FC = () => { {index + 1}
-

Phòng {room.room_number}

-

{room.bookings} lượt đặt

+

Room {room.room_number}

+

{room.bookings} bookings

@@ -257,20 +257,20 @@ const DashboardPage: React.FC = () => { ))}
) : ( -

Không có dữ liệu

+

No data available

)}
{/* Service Usage */}
-

Dịch vụ được sử dụng

+

Services Used

{stats?.service_usage && stats.service_usage.length > 0 ? (
{stats.service_usage.map((service) => (

{service.service_name}

-

{service.usage_count} lần sử dụng

+

{service.usage_count} times used

{formatCurrency(service.total_revenue)} @@ -279,7 +279,7 @@ const DashboardPage: React.FC = () => { ))}
) : ( -

Không có dữ liệu

+

No data available

)}
diff --git a/client/src/pages/admin/PromotionManagementPage.tsx b/client/src/pages/admin/PromotionManagementPage.tsx index c93e0817..0d81cd31 100644 --- a/client/src/pages/admin/PromotionManagementPage.tsx +++ b/client/src/pages/admin/PromotionManagementPage.tsx @@ -152,8 +152,8 @@ const PromotionManagementPage: React.FC = () => {
-

Quản lý khuyến mãi

-

Quản lý mã giảm giá và chương trình khuyến mãi

+

Promotion Management

+

Manage discount codes and promotion programs

@@ -175,7 +175,7 @@ const PromotionManagementPage: React.FC = () => { setFilters({ ...filters, search: e.target.value })} className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500" @@ -187,18 +187,18 @@ const PromotionManagementPage: React.FC = () => { onChange={(e) => setFilters({ ...filters, type: e.target.value })} className="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500" > - - - + + +
@@ -209,25 +209,25 @@ const PromotionManagementPage: React.FC = () => { - Mã code + Code - Tên chương trình + Program Name - Giá trị + Value - Thời gian + Period - Đã dùng + Used - Trạng thái + Status - Thao tác + Actions @@ -301,7 +301,7 @@ const PromotionManagementPage: React.FC = () => {

- {editingPromotion ? 'Cập nhật khuyến mãi' : 'Thêm khuyến mãi mới'} + {editingPromotion ? 'Update Promotion' : 'Add New Promotion'}