From cdb02b893b7266e0f163ae372a8bd4f889a3196c Mon Sep 17 00:00:00 2001 From: Arjuna Date: Mon, 2 Feb 2026 23:46:19 +0700 Subject: [PATCH] feat: user role update by admin --- Internal/adapters/repository/userRepo.go | 20 ++ Internal/api/Routes/routev1.go | 2 + Internal/api/handlers/userHandler.go | 53 ++++++ Internal/core/services/userService.go | 21 ++ .../admin-setting/pages/UserManagement.tsx | 179 ++++++++++++++++-- .../services/userManagementService.ts | 23 +++ 6 files changed, 286 insertions(+), 12 deletions(-) diff --git a/Internal/adapters/repository/userRepo.go b/Internal/adapters/repository/userRepo.go index db3fe87..e965fbd 100644 --- a/Internal/adapters/repository/userRepo.go +++ b/Internal/adapters/repository/userRepo.go @@ -28,3 +28,23 @@ func (ur *UserRepository) FindById(id uint) (*domain.User, error) { } return &user, nil } + +func (ur *UserRepository) AllUser() ([]domain.User, error) { + var users []domain.User + err := ur.db.Gorm.Find(&users).Error + if err != nil { + return nil, err + } + return users, nil +} + +func (ur *UserRepository) RoleUpdate(id uint, role string) (*domain.User, error) { + var user domain.User + if err := ur.db.Gorm.First(&user, id).Error; err != nil { + return nil, err + } + if err := ur.db.Gorm.Model(&user).Update("role", role).Error; err != nil { + return nil, err + } + return &user, nil +} diff --git a/Internal/api/Routes/routev1.go b/Internal/api/Routes/routev1.go index 15e0161..2a50cb8 100644 --- a/Internal/api/Routes/routev1.go +++ b/Internal/api/Routes/routev1.go @@ -43,6 +43,8 @@ func SetupRouterV1(r *gin.Engine, deps Deps) { admin := protected.Group("/admin") { admin.POST("/invite", deps.Auth.CreateInviteHandler) + admin.GET("/alluser", deps.User.AllUserHandler) + admin.PUT("/updaterole", deps.User.UpdateRoleHandler) } } } diff --git a/Internal/api/handlers/userHandler.go b/Internal/api/handlers/userHandler.go index 897e371..26fb067 100644 --- a/Internal/api/handlers/userHandler.go +++ b/Internal/api/handlers/userHandler.go @@ -35,3 +35,56 @@ func (uh *UserHandler) GetUserHandler(c *gin.Context) { "data": user, }) } + +func (uh *UserHandler) AllUserHandler(c *gin.Context) { + userRole, _ := c.Get("userRole") + if userRole != "admin" { + c.JSON(400, gin.H{ + "message": "Not allowed to get all users", + "data": false, + }) + return + } + users, err := uh.Service.GetAllUser() + if err != nil { + c.JSON(400, gin.H{ + "message": "Unable to get all users", + "data": false, + }) + } + c.JSON(200, gin.H{ + "message": "Successfully get all users", + "data": users, + }) +} + +func (uh *UserHandler) UpdateRoleHandler(c *gin.Context) { + var input services.RoleInput + //userRole, _ := c.Get("userRole") + //if userRole != "admin" { + // c.JSON(400, gin.H{ + // "message": "Not allowed to update role", + // "data": false, + // }) + // return + //} + if err := c.ShouldBindJSON(&input); err != nil { + c.JSON(400, gin.H{ + "message": "input not valid", + "data": err.Error(), + }) + return + } + user, err := uh.Service.UpdateRole(&input) + if err != nil { + c.JSON(400, gin.H{ + "message": "Unable to update role", + "data": err, + }) + return + } + c.JSON(200, gin.H{ + "message": "Successfully update role", + "data": user, + }) +} diff --git a/Internal/core/services/userService.go b/Internal/core/services/userService.go index 60d7146..c7fef83 100644 --- a/Internal/core/services/userService.go +++ b/Internal/core/services/userService.go @@ -15,6 +15,11 @@ func NewUserService(repo *repository.UserRepository) *UserService { return &UserService{Repo: repo} } +type RoleInput struct { + UserID uint `json:"id"` + Role string `json:"role"` +} + func (us *UserService) GetUser(id uint) (*domain.User, error) { user, err := us.Repo.FindById(id) if err != nil { @@ -22,3 +27,19 @@ func (us *UserService) GetUser(id uint) (*domain.User, error) { } return user, nil } + +func (us *UserService) GetAllUser() ([]domain.User, error) { + users, err := us.Repo.AllUser() + if err != nil { + return nil, errors.New("user not found") + } + return users, nil +} + +func (us *UserService) UpdateRole(input *RoleInput) (*domain.User, error) { + user, err := us.Repo.RoleUpdate(input.UserID, input.Role) + if err != nil { + return nil, errors.New("user not found") + } + return user, nil +} diff --git a/Lb-web/src/features/admin-setting/pages/UserManagement.tsx b/Lb-web/src/features/admin-setting/pages/UserManagement.tsx index f86aed5..ea7e214 100644 --- a/Lb-web/src/features/admin-setting/pages/UserManagement.tsx +++ b/Lb-web/src/features/admin-setting/pages/UserManagement.tsx @@ -1,5 +1,5 @@ import { Button } from "@/components/ui/button"; -import { Plus, Loader2, Copy, Check } from "lucide-react"; +import { Plus, Loader2, Copy, Check, Pencil } from "lucide-react"; import { Dialog, DialogContent, @@ -10,19 +10,47 @@ import { DialogTrigger, } from "@/components/ui/dialog"; import { Input } from "@/components/ui/input"; -import { useState } from "react"; -import { userManagementService } from "../services/userManagementService"; +import { useState, useEffect } from "react"; +import { userManagementService, type User } from "../services/userManagementService"; import { Label } from "@/components/ui/label"; export default function UserManagement() { const [email, setEmail] = useState(""); const [role, setRole] = useState("user"); const [open, setOpen] = useState(false); + + // Add User / Invite loading state const [loading, setLoading] = useState(false); const [inviteLink, setInviteLink] = useState(null); const [copied, setCopied] = useState(false); const [error, setError] = useState(null); + // User list state + const [users, setUsers] = useState([]); + const [fetchingUsers, setFetchingUsers] = useState(true); + + // Edit User state + const [editOpen, setEditOpen] = useState(false); + const [editingUser, setEditingUser] = useState(null); + const [editRole, setEditRole] = useState("user"); + const [updatingRole, setUpdatingRole] = useState(false); + + useEffect(() => { + fetchUsers(); + }, []); + + const fetchUsers = async () => { + setFetchingUsers(true); + try { + const data = await userManagementService.getAllUsers(); + setUsers(data); + } catch (err) { + console.error("Failed to fetch users:", err); + } finally { + setFetchingUsers(false); + } + }; + const handleInvite = async () => { if (!email) return; @@ -55,6 +83,28 @@ export default function UserManagement() { setLoading(false); }; + const openEditModal = (user: User) => { + setEditingUser(user); + setEditRole(user.role); + setEditOpen(true); + }; + + const handleUpdateRole = async () => { + if (!editingUser) return; + setUpdatingRole(true); + try { + await userManagementService.updateUserRole(editingUser.id, editRole); + setEditOpen(false); + setEditingUser(null); + fetchUsers(); // Refresh the list + } catch (err) { + console.error("Failed to update role:", err); + // Optionally show error toast or message + } finally { + setUpdatingRole(false); + } + }; + return (
@@ -62,6 +112,7 @@ export default function UserManagement() {

User Management

Manage system users and their roles.

+ {/* Add User Dialog */} { setOpen(val); if (!val) resetForm(); @@ -161,18 +212,122 @@ export default function UserManagement() { + + {/* Edit Role Dialog */} + + + + Edit User Role + + Change the role for {editingUser?.username} ({editingUser?.email}). + + +
+
+ + +
+
+ + + + +
+
-
-
- + {fetchingUsers ? ( +
+
-

No users found

-

- You haven't added any users yet. Click the button above to create a new user account. -

- {/* This is a placeholder for the actual table */} -
+ ) : users.length === 0 ? ( +
+
+ +
+

No users found

+

+ You haven't added any users yet. Click the button above to create a new user account. +

+
+ ) : ( +
+
+ + + + + + + + + + + + + {users.map((user) => ( + + + + + + + + + ))} + +
IDUsernameEmailRoleCreated AtActions
{user.id}{user.username}{user.email} + + {user.role} + + + {new Date(user.created_at).toLocaleDateString()} + + +
+
+
+ )}
); } diff --git a/Lb-web/src/features/admin-setting/services/userManagementService.ts b/Lb-web/src/features/admin-setting/services/userManagementService.ts index e172518..7e3ffa5 100644 --- a/Lb-web/src/features/admin-setting/services/userManagementService.ts +++ b/Lb-web/src/features/admin-setting/services/userManagementService.ts @@ -10,9 +10,32 @@ export interface InviteUserRequest { role: string; } +export interface User { + id: number; + username: string; + email: string; + role: string; + created_at: string; +} + +export interface GetAllUsersResponse { + message: string; + data: User[]; +} + export const userManagementService = { inviteUser: async (data: InviteUserRequest): Promise => { const response = await api.post('/protected/admin/invite', data); return response.data; }, + + getAllUsers: async (): Promise => { + const response = await api.get('/protected/admin/alluser'); + return response.data.data; + }, + + updateUserRole: async (id: number, role: string): Promise => { + const response = await api.put<{ message: string, data: User }>('/protected/admin/updaterole', { id, role }); + return response.data.data; + } };