diff --git a/apps/web-client/src/app/layout.tsx b/apps/web-client/src/app/layout.tsx index 1596f0e9..85d3590b 100644 --- a/apps/web-client/src/app/layout.tsx +++ b/apps/web-client/src/app/layout.tsx @@ -1,17 +1,29 @@ import type { Metadata } from 'next'; import './globals.css'; +/** + * EN: Metadata for the application + * VI: Metadata cho ứng dụng + */ export const metadata: Metadata = { title: 'GoodGo Platform', - description: 'Enterprise microservices platform', + description: 'Enterprise microservices platform / Nền tảng microservices doanh nghiệp', }; +/** + * EN: Root layout component for the entire application + * VI: Component layout gốc cho toàn bộ ứng dụng + * + * @param children - Child components to render / Components con để render + */ export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( + // EN: Root HTML structure with English language + // VI: Cấu trúc HTML gốc với ngôn ngữ tiếng Anh {children} diff --git a/apps/web-client/src/app/login/page.tsx b/apps/web-client/src/app/login/page.tsx index 2759230c..4d4d8c68 100644 --- a/apps/web-client/src/app/login/page.tsx +++ b/apps/web-client/src/app/login/page.tsx @@ -4,31 +4,57 @@ import { useState } from 'react'; import { useRouter } from 'next/navigation'; import { useAuthStore } from '@/stores/auth.store'; +/** + * EN: Login page component for user authentication + * VI: Component trang đăng nhập để xác thực người dùng + */ export default function LoginPage() { + // EN: Next.js router for navigation + // VI: Next.js router để điều hướng const router = useRouter(); + + // EN: Auth store hooks for login functionality + // VI: Auth store hooks cho chức năng đăng nhập const { login, isLoading } = useAuthStore(); + + // EN: Form state management + // VI: Quản lý trạng thái form const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [error, setError] = useState(''); + /** + * EN: Handle form submission for login + * VI: Xử lý submit form để đăng nhập + */ const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setError(''); try { + // EN: Attempt login through auth store + // VI: Thử đăng nhập thông qua auth store await login(email, password); + // EN: Redirect to home page on successful login + // VI: Chuyển hướng về trang chủ khi đăng nhập thành công router.push('/'); } catch (err: any) { - setError(err.message || 'Login failed'); + setError(err.message || 'Login failed / Đăng nhập thất bại'); } }; return ( + // EN: Centered login form layout + // VI: Layout form đăng nhập được căn giữa
-

Login

+

Login / Đăng nhập

+ + {/* EN: Error message display / VI: Hiển thị thông báo lỗi */} {error &&
{error}
} + + {/* EN: Email input field / VI: Trường nhập email */}
- +
+ + {/* EN: Password input field / VI: Trường nhập mật khẩu */}
- +
+ + {/* EN: Submit button with loading state / VI: Nút submit với trạng thái loading */}
diff --git a/apps/web-client/src/app/page.tsx b/apps/web-client/src/app/page.tsx index d935839e..0a00b41c 100644 --- a/apps/web-client/src/app/page.tsx +++ b/apps/web-client/src/app/page.tsx @@ -3,30 +3,46 @@ import { useAuthStore } from '@/stores/auth.store'; import { useEffect } from 'react'; +/** + * EN: Home page component - main application entry point + * VI: Component trang chủ - điểm vào chính của ứng dụng + */ export default function Home() { + // EN: Get authentication state from store + // VI: Lấy trạng thái xác thực từ store const { user, isAuthenticated, isLoading, fetchUser } = useAuthStore(); + // EN: Fetch user data on component mount if not authenticated + // VI: Fetch dữ liệu user khi component mount nếu chưa xác thực useEffect(() => { if (!isAuthenticated && !isLoading) { fetchUser(); } }, [isAuthenticated, isLoading, fetchUser]); + // EN: Show loading state while checking authentication + // VI: Hiển thị trạng thái loading trong khi kiểm tra xác thực if (isLoading) { - return
Loading...
; + return
Loading... / Đang tải...
; } return ( + // EN: Main content area with responsive padding + // VI: Khu vực nội dung chính với padding responsive
-

GoodGo Platform

+

GoodGo Platform / Nền tảng GoodGo

+ + {/* EN: Conditional rendering based on authentication status / VI: Render có điều kiện dựa trên trạng thái xác thực */} {isAuthenticated && user ? ( + // EN: Authenticated user welcome message / VI: Thông báo chào mừng người dùng đã xác thực
-

Welcome, {user.email}!

-

Role: {user.role}

+

Welcome, {user.email}! / Chào mừng, {user.email}!

+

Role: {user.role} / Vai trò: {user.role}

) : ( + // EN: Login prompt for unauthenticated users / VI: Nhắc đăng nhập cho người dùng chưa xác thực
-

Please log in to continue.

+

Please log in to continue. / Vui lòng đăng nhập để tiếp tục.

)}
diff --git a/apps/web-client/src/services/api/auth.api.ts b/apps/web-client/src/services/api/auth.api.ts index bdfc446c..c15e2046 100644 --- a/apps/web-client/src/services/api/auth.api.ts +++ b/apps/web-client/src/services/api/auth.api.ts @@ -1,13 +1,27 @@ import { apiClient } from './client'; import { LoginDto, RegisterDto, AuthResponse, ApiResponse, UserResponse } from '@goodgo/types'; +/** + * EN: Authentication API service for frontend + * VI: Service API xác thực cho frontend + */ export const authApi = { + /** + * EN: Register new user account + * VI: Đăng ký tài khoản người dùng mới + */ register: async (data: RegisterDto): Promise> => { return apiClient.post('/auth/register', data); }, + /** + * EN: Login user and store tokens + * VI: Đăng nhập người dùng và lưu tokens + */ login: async (data: LoginDto): Promise> => { const response = await apiClient.post('/auth/login', data); + // EN: Store tokens in client and localStorage on successful login + // VI: Lưu tokens trong client và localStorage khi đăng nhập thành công if (response.success && response.data) { apiClient.setAuthToken(response.data.accessToken); if (typeof window !== 'undefined') { @@ -17,9 +31,17 @@ export const authApi = { return response; }, + /** + * EN: Logout user and clear tokens + * VI: Đăng xuất người dùng và xóa tokens + */ logout: async (): Promise => { + // EN: Get refresh token from localStorage for logout request + // VI: Lấy refresh token từ localStorage cho request logout const refreshToken = typeof window !== 'undefined' ? localStorage.getItem('refreshToken') : null; const response = await apiClient.post('/auth/logout', { refreshToken }); + // EN: Clear tokens from client and localStorage + // VI: Xóa tokens khỏi client và localStorage apiClient.removeAuthToken(); if (typeof window !== 'undefined') { localStorage.removeItem('refreshToken'); @@ -27,18 +49,32 @@ export const authApi = { return response; }, + /** + * EN: Refresh access token using refresh token + * VI: Làm mới access token sử dụng refresh token + */ refreshToken: async (refreshToken: string): Promise> => { const response = await apiClient.post('/auth/refresh', { refreshToken }); + // EN: Update access token in client on successful refresh + // VI: Cập nhật access token trong client khi refresh thành công if (response.success && response.data) { apiClient.setAuthToken(response.data.accessToken); } return response; }, + /** + * EN: Get current authenticated user profile + * VI: Lấy hồ sơ người dùng đã xác thực hiện tại + */ getMe: async (): Promise> => { return apiClient.get('/users/me'); }, + /** + * EN: Change user password + * VI: Thay đổi mật khẩu người dùng + */ changePassword: async (currentPassword: string, newPassword: string): Promise => { return apiClient.put('/auth/password', { currentPassword, newPassword }); }, diff --git a/apps/web-client/src/services/api/client.ts b/apps/web-client/src/services/api/client.ts index 79caf82e..479d55d9 100644 --- a/apps/web-client/src/services/api/client.ts +++ b/apps/web-client/src/services/api/client.ts @@ -1,8 +1,14 @@ import { createHttpClient } from '@goodgo/http-client'; +// EN: Get API base URL from environment or use default +// VI: Lấy API base URL từ environment hoặc sử dụng mặc định const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost/api/v1'; +/** + * EN: HTTP client instance configured for API calls + * VI: Instance HTTP client đã cấu hình cho API calls + */ export const apiClient = createHttpClient({ baseURL: API_URL, - timeout: 30000, + timeout: 30000, // EN: 30 second timeout / VI: Timeout 30 giây }); diff --git a/apps/web-client/src/stores/auth.store.ts b/apps/web-client/src/stores/auth.store.ts index c4b6c931..1fc88ed2 100644 --- a/apps/web-client/src/stores/auth.store.ts +++ b/apps/web-client/src/stores/auth.store.ts @@ -3,16 +3,31 @@ import { persist } from 'zustand/middleware'; import { UserResponse } from '@goodgo/types'; import { authApi } from '../services/api/auth.api'; +/** + * EN: Authentication state interface for Zustand store + * VI: Interface trạng thái xác thực cho Zustand store + */ interface AuthState { + /** EN: Current authenticated user / VI: Người dùng đã xác thực hiện tại */ user: UserResponse | null; + /** EN: Authentication status / VI: Trạng thái xác thực */ isAuthenticated: boolean; + /** EN: Loading state for async operations / VI: Trạng thái loading cho async operations */ isLoading: boolean; + /** EN: Login method / VI: Method đăng nhập */ login: (email: string, password: string) => Promise; + /** EN: Register method / VI: Method đăng ký */ register: (email: string, password: string, confirmPassword: string) => Promise; + /** EN: Logout method / VI: Method đăng xuất */ logout: () => Promise; + /** EN: Fetch current user method / VI: Method lấy thông tin user hiện tại */ fetchUser: () => Promise; } +/** + * EN: Zustand store for authentication state management with persistence + * VI: Zustand store để quản lý trạng thái xác thực với persistence + */ export const useAuthStore = create()( persist( (set) => ({ @@ -20,6 +35,10 @@ export const useAuthStore = create()( isAuthenticated: false, isLoading: false, + /** + * EN: Login user and update store state + * VI: Đăng nhập người dùng và cập nhật trạng thái store + */ login: async (email: string, password: string) => { set({ isLoading: true }); try { @@ -31,7 +50,7 @@ export const useAuthStore = create()( isLoading: false, }); } else { - throw new Error(response.error?.message || 'Login failed'); + throw new Error(response.error?.message || 'Login failed / Đăng nhập thất bại'); } } catch (error) { set({ isLoading: false }); @@ -39,6 +58,10 @@ export const useAuthStore = create()( } }, + /** + * EN: Register new user and update store state + * VI: Đăng ký người dùng mới và cập nhật trạng thái store + */ register: async (email: string, password: string, confirmPassword: string) => { set({ isLoading: true }); try { @@ -50,7 +73,7 @@ export const useAuthStore = create()( isLoading: false, }); } else { - throw new Error(response.error?.message || 'Registration failed'); + throw new Error(response.error?.message || 'Registration failed / Đăng ký thất bại'); } } catch (error) { set({ isLoading: false }); @@ -58,6 +81,10 @@ export const useAuthStore = create()( } }, + /** + * EN: Logout user and clear store state + * VI: Đăng xuất người dùng và xóa trạng thái store + */ logout: async () => { try { await authApi.logout(); @@ -69,6 +96,10 @@ export const useAuthStore = create()( } }, + /** + * EN: Fetch current user profile from API + * VI: Lấy hồ sơ người dùng hiện tại từ API + */ fetchUser: async () => { set({ isLoading: true }); try { @@ -87,6 +118,8 @@ export const useAuthStore = create()( }); } } catch (error) { + // EN: Clear user state on fetch failure + // VI: Xóa trạng thái user khi fetch thất bại set({ user: null, isAuthenticated: false, @@ -96,7 +129,11 @@ export const useAuthStore = create()( }, }), { + // EN: Persist auth state to localStorage + // VI: Persist trạng thái auth vào localStorage name: 'auth-storage', + // EN: Only persist user and isAuthenticated, exclude isLoading + // VI: Chỉ persist user và isAuthenticated, loại trừ isLoading partialize: (state) => ({ user: state.user, isAuthenticated: state.isAuthenticated }), } ) diff --git a/packages/types/src/api.types.ts b/packages/types/src/api.types.ts index f21ca0f9..62397fe2 100644 --- a/packages/types/src/api.types.ts +++ b/packages/types/src/api.types.ts @@ -1,29 +1,62 @@ +/** + * EN: Standardized API response interface + * VI: Interface phản hồi API chuẩn hóa + */ export interface ApiResponse { + /** EN: Operation success status / VI: Trạng thái thành công của thao tác */ success: boolean; + /** EN: Response data payload / VI: Payload dữ liệu phản hồi */ data?: T; + /** EN: Success message / VI: Thông báo thành công */ message?: string; + /** EN: Error details (if failed) / VI: Chi tiết lỗi (nếu thất bại) */ error?: ApiError; + /** EN: Response timestamp / VI: Timestamp phản hồi */ timestamp: string; } +/** + * EN: API error structure + * VI: Cấu trúc lỗi API + */ export interface ApiError { + /** EN: Error code identifier / VI: Mã định danh lỗi */ code: string; + /** EN: Human-readable error message / VI: Thông báo lỗi dễ đọc */ message: string; + /** EN: Additional error details / VI: Chi tiết lỗi bổ sung */ details?: Record; } +/** + * EN: Paginated API response interface + * VI: Interface phản hồi API có phân trang + */ export interface PaginatedResponse extends ApiResponse { + /** EN: Pagination metadata / VI: Metadata phân trang */ pagination: { + /** EN: Current page number / VI: Số trang hiện tại */ page: number; + /** EN: Items per page / VI: Số items mỗi trang */ limit: number; + /** EN: Total number of items / VI: Tổng số items */ total: number; + /** EN: Total number of pages / VI: Tổng số trang */ totalPages: number; }; } +/** + * EN: Query parameters for pagination and sorting + * VI: Tham số query cho phân trang và sắp xếp + */ export interface PaginationQuery { + /** EN: Page number (1-based) / VI: Số trang (bắt đầu từ 1) */ page?: number; + /** EN: Items per page / VI: Số items mỗi trang */ limit?: number; + /** EN: Field to sort by / VI: Trường để sắp xếp */ sortBy?: string; + /** EN: Sort order / VI: Thứ tự sắp xếp */ sortOrder?: 'asc' | 'desc'; } diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 0fe2e7bc..3592a69a 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -1,3 +1,9 @@ +// EN: Re-export all user-related types +// VI: Re-export tất cả types liên quan đến user export * from './user.types'; +// EN: Re-export all authentication-related types +// VI: Re-export tất cả types liên quan đến authentication export * from './auth.types'; +// EN: Re-export all API-related types +// VI: Re-export tất cả types liên quan đến API export * from './api.types'; diff --git a/services/auth-service/src/modules/auth/auth.module.ts b/services/auth-service/src/modules/auth/auth.module.ts index ec0038b4..88235317 100644 --- a/services/auth-service/src/modules/auth/auth.module.ts +++ b/services/auth-service/src/modules/auth/auth.module.ts @@ -2,13 +2,26 @@ import { Router } from 'express'; import { AuthController } from './auth.controller'; import { authenticate } from '../../middlewares/auth.middleware'; +/** + * EN: Create and configure authentication routes + * VI: Tạo và cấu hình routes xác thực + * + * @returns Configured Express router for auth endpoints / Router Express đã cấu hình cho auth endpoints + */ export const createAuthRouter = (): Router => { + // EN: Create router instance + // VI: Tạo instance router const router = Router(); const authController = new AuthController(); + // EN: Public authentication routes (no auth required) + // VI: Routes xác thực công khai (không yêu cầu auth) router.post('/register', authController.register); router.post('/login', authController.login); router.post('/refresh', authController.refresh); + + // EN: Protected routes (authentication required) + // VI: Routes được bảo vệ (yêu cầu authentication) router.post('/logout', authenticate, authController.logout); router.put('/password', authenticate, authController.changePassword); diff --git a/services/auth-service/src/modules/user/user.controller.ts b/services/auth-service/src/modules/user/user.controller.ts index db10fca6..50d4b686 100644 --- a/services/auth-service/src/modules/user/user.controller.ts +++ b/services/auth-service/src/modules/user/user.controller.ts @@ -4,13 +4,29 @@ import { updateUserDtoSchema } from './user.dto'; import { AuthRequest } from '../../middlewares/auth.middleware'; import { ApiResponse, PaginatedResponse, UserResponse } from '@goodgo/types'; +/** + * EN: User management controller handling user-related HTTP requests + * VI: Controller quản lý người dùng xử lý các yêu cầu HTTP liên quan đến người dùng + */ export class UserController { + /** EN: User service instance / VI: Instance user service */ private userService: UserService; + /** + * EN: Initialize user controller with service dependency + * VI: Khởi tạo user controller với dependency service + */ constructor() { this.userService = new UserService(); } + /** + * EN: Get current authenticated user profile + * VI: Lấy hồ sơ người dùng đã xác thực hiện tại + * + * @param req - Authenticated request with user info / Request đã xác thực với thông tin người dùng + * @param res - Express response object / Đối tượng response của Express + */ getMe = async (req: AuthRequest, res: Response): Promise => { try { const user = await this.userService.getCurrentUser(req.user!.userId); @@ -34,8 +50,17 @@ export class UserController { } }; + /** + * EN: Get paginated list of users (admin endpoint) + * VI: Lấy danh sách người dùng có phân trang (endpoint admin) + * + * @param req - Express request with query parameters / Request Express với query parameters + * @param res - Express response object / Đối tượng response của Express + */ getUsers = async (req: Request, res: Response): Promise => { try { + // EN: Parse pagination parameters from query + // VI: Parse tham số phân trang từ query const page = parseInt(req.query.page as string) || 1; const limit = parseInt(req.query.limit as string) || 20; @@ -54,13 +79,20 @@ export class UserController { success: false, error: { code: 'USER_002', - message: error.message || 'Failed to fetch users', + message: error.message || 'Failed to fetch users / Lấy danh sách người dùng thất bại', }, timestamp: new Date().toISOString(), }); } }; + /** + * EN: Get user by ID (admin endpoint) + * VI: Lấy người dùng theo ID (endpoint admin) + * + * @param req - Express request with user ID in params / Request Express với user ID trong params + * @param res - Express response object / Đối tượng response của Express + */ getUserById = async (req: Request, res: Response): Promise => { try { const user = await this.userService.getUserById(req.params.id); @@ -84,15 +116,24 @@ export class UserController { } }; + /** + * EN: Update user information (admin endpoint) + * VI: Cập nhật thông tin người dùng (endpoint admin) + * + * @param req - Express request with user ID in params and update data in body / Request Express với user ID trong params và dữ liệu cập nhật trong body + * @param res - Express response object / Đối tượng response của Express + */ updateUser = async (req: Request, res: Response): Promise => { try { + // EN: Validate update data using Zod schema + // VI: Xác thực dữ liệu cập nhật sử dụng Zod schema const data = updateUserDtoSchema.parse(req.body); const user = await this.userService.updateUser(req.params.id, data); const response: ApiResponse = { success: true, data: user, - message: 'User updated successfully', + message: 'User updated successfully / Người dùng đã cập nhật thành công', timestamp: new Date().toISOString(), }; @@ -102,20 +143,29 @@ export class UserController { success: false, error: { code: 'USER_004', - message: error.message || 'Failed to update user', + message: error.message || 'Failed to update user / Cập nhật người dùng thất bại', }, timestamp: new Date().toISOString(), }); } }; + /** + * EN: Delete user (admin endpoint) + * VI: Xóa người dùng (endpoint admin) + * + * @param req - Express request with user ID in params / Request Express với user ID trong params + * @param res - Express response object / Đối tượng response của Express + */ deleteUser = async (req: Request, res: Response): Promise => { try { + // EN: Delete user through service + // VI: Xóa người dùng thông qua service await this.userService.deleteUser(req.params.id); const response: ApiResponse = { success: true, - message: 'User deleted successfully', + message: 'User deleted successfully / Người dùng đã xóa thành công', timestamp: new Date().toISOString(), }; @@ -125,7 +175,7 @@ export class UserController { success: false, error: { code: 'USER_005', - message: error.message || 'Failed to delete user', + message: error.message || 'Failed to delete user / Xóa người dùng thất bại', }, timestamp: new Date().toISOString(), }); diff --git a/services/auth-service/src/modules/user/user.dto.ts b/services/auth-service/src/modules/user/user.dto.ts index 689f82a5..d21fbd56 100644 --- a/services/auth-service/src/modules/user/user.dto.ts +++ b/services/auth-service/src/modules/user/user.dto.ts @@ -1,9 +1,17 @@ import { z } from 'zod'; +/** + * EN: Zod schema for user update validation + * VI: Schema Zod để xác thực cập nhật người dùng + */ export const updateUserDtoSchema = z.object({ + /** EN: Optional email update / VI: Cập nhật email tùy chọn */ email: z.string().email().optional(), + /** EN: Optional role update / VI: Cập nhật vai trò tùy chọn */ role: z.enum(['USER', 'ADMIN', 'SUPER_ADMIN']).optional(), + /** EN: Optional active status update / VI: Cập nhật trạng thái hoạt động tùy chọn */ isActive: z.boolean().optional(), }); +/** EN: TypeScript type inferred from update user schema / VI: Type TypeScript suy ra từ schema cập nhật người dùng */ export type UpdateUserDto = z.infer; diff --git a/services/auth-service/src/modules/user/user.module.ts b/services/auth-service/src/modules/user/user.module.ts index d57bc0fa..5ae0c3dc 100644 --- a/services/auth-service/src/modules/user/user.module.ts +++ b/services/auth-service/src/modules/user/user.module.ts @@ -2,11 +2,24 @@ import { Router } from 'express'; import { UserController } from './user.controller'; import { authenticate, authorize } from '../../middlewares/auth.middleware'; +/** + * EN: Create and configure user management routes + * VI: Tạo và cấu hình routes quản lý người dùng + * + * @returns Configured Express router for user endpoints / Router Express đã cấu hình cho user endpoints + */ export const createUserRouter = (): Router => { + // EN: Create router instance + // VI: Tạo instance router const router = Router(); const userController = new UserController(); + // EN: Public route for authenticated user profile + // VI: Route công khai cho hồ sơ người dùng đã xác thực router.get('/me', authenticate, userController.getMe); + + // EN: Admin-only routes for user management + // VI: Routes chỉ dành cho admin để quản lý người dùng router.get('/', authenticate, authorize('ADMIN', 'SUPER_ADMIN'), userController.getUsers); router.get('/:id', authenticate, authorize('ADMIN', 'SUPER_ADMIN'), userController.getUserById); router.put('/:id', authenticate, authorize('ADMIN', 'SUPER_ADMIN'), userController.updateUser); diff --git a/services/auth-service/src/modules/user/user.service.ts b/services/auth-service/src/modules/user/user.service.ts index 7a0d91a4..1ab86d2d 100644 --- a/services/auth-service/src/modules/user/user.service.ts +++ b/services/auth-service/src/modules/user/user.service.ts @@ -3,7 +3,19 @@ import { logger } from '@goodgo/logger'; import { UpdateUserDto } from './user.dto'; import { UserResponse, Role as TypeRole } from '@goodgo/types'; +/** + * EN: User management service handling CRUD operations + * VI: Service quản lý người dùng xử lý các thao tác CRUD + */ export class UserService { + /** + * EN: Get current authenticated user information + * VI: Lấy thông tin người dùng đã xác thực hiện tại + * + * @param userId - Unique user identifier / Mã định danh duy nhất người dùng + * @returns User response data / Dữ liệu phản hồi người dùng + * @throws Error if user not found / Lỗi nếu không tìm thấy người dùng + */ async getCurrentUser(userId: string): Promise { const user = await prisma.user.findUnique({ where: { id: userId }, @@ -23,13 +35,23 @@ export class UserService { }; } + /** + * EN: Get user by ID (admin function) + * VI: Lấy người dùng theo ID (hàm admin) + * + * @param id - User identifier / Mã định danh người dùng + * @returns User response data / Dữ liệu phản hồi người dùng + * @throws Error if user not found / Lỗi nếu không tìm thấy người dùng + */ async getUserById(id: string): Promise { + // EN: Find user in database + // VI: Tìm người dùng trong database const user = await prisma.user.findUnique({ where: { id }, }); if (!user) { - throw new Error('User not found'); + throw new Error('User not found / Không tìm thấy người dùng'); } return { @@ -42,6 +64,14 @@ export class UserService { }; } + /** + * EN: Get paginated list of users (admin function) + * VI: Lấy danh sách người dùng có phân trang (hàm admin) + * + * @param page - Page number (default: 1) / Số trang (mặc định: 1) + * @param limit - Items per page (default: 20) / Số items mỗi trang (mặc định: 20) + * @returns Paginated user list / Danh sách người dùng có phân trang + */ async getUsers(page: number = 1, limit: number = 20) { const skip = (page - 1) * limit; @@ -72,7 +102,17 @@ export class UserService { }; } + /** + * EN: Update user information (admin function) + * VI: Cập nhật thông tin người dùng (hàm admin) + * + * @param id - User identifier / Mã định danh người dùng + * @param data - Update data / Dữ liệu cập nhật + * @returns Updated user response / Phản hồi người dùng đã cập nhật + */ async updateUser(id: string, data: UpdateUserDto): Promise { + // EN: Update user in database + // VI: Cập nhật người dùng trong database const user = await prisma.user.update({ where: { id }, data: { @@ -82,7 +122,7 @@ export class UserService { }, }); - logger.info('User updated', { userId: id }); + logger.info('User updated / Người dùng đã cập nhật', { userId: id }); return { id: user.id, @@ -94,11 +134,19 @@ export class UserService { }; } + /** + * EN: Delete user (admin function) + * VI: Xóa người dùng (hàm admin) + * + * @param id - User identifier to delete / Mã định danh người dùng cần xóa + */ async deleteUser(id: string): Promise { + // EN: Delete user from database + // VI: Xóa người dùng khỏi database await prisma.user.delete({ where: { id }, }); - logger.info('User deleted', { userId: id }); + logger.info('User deleted / Người dùng đã xóa', { userId: id }); } }