diff --git a/src/components/accessories/admin/users/Users.tsx b/src/components/accessories/admin/users/Users.tsx index dfac8e331..17b9d7980 100644 --- a/src/components/accessories/admin/users/Users.tsx +++ b/src/components/accessories/admin/users/Users.tsx @@ -1,5 +1,5 @@ import { Tab, Tabs } from "@mui/material"; -import React from "react"; +import React, { useCallback } from "react"; import { useTranslation } from "react-i18next"; import { useLocation, useNavigate } from "react-router"; @@ -7,6 +7,8 @@ import Button from "../../button/Button"; import UserGroupsTable from "./userGroupsTable"; import UsersTable from "./usersTable"; +import { useAppDispatch } from "libraries/hooks/redux"; +import { deleteUser } from "state/users"; import { PATHS } from "../../../../consts"; import { UserDTO, UserGroupDTO } from "../../../../generated"; @@ -18,6 +20,7 @@ export enum TabOptions { export const Users = () => { const navigate = useNavigate(); const { t } = useTranslation(); + const dispatch = useAppDispatch(); const { state }: { state: { tab?: TabOptions } } = useLocation(); const setTab = (tab: TabOptions) => @@ -33,6 +36,13 @@ export const Users = () => { state: row, }); + const handleDeleteUser = useCallback( + (row: UserDTO) => { + dispatch(deleteUser(row.userName ?? "")); + }, + [dispatch] + ); + return ( <> { } onEdit={handleEditUser} + onDelete={handleDeleteUser} /> ) : ( void; + onDelete: (row: UserDTO) => void; } -export const UsersTable = ({ headerActions, onEdit }: IOwnProps) => { +export const UsersTable = ({ headerActions, onEdit, onDelete }: IOwnProps) => { const dispatch = useAppDispatch(); const { t } = useTranslation(); + const infoBoxRef = useRef(null); + const canUpdate = usePermission("users.update"); + const canDelete = usePermission("users.update"); + + const deleteUser = useAppSelector((state) => state.users.delete); useEffect(() => { dispatch(getUsers({})); dispatch(getUserGroups()); + + return () => { + dispatch(deleteUserReset()); + }; }, [dispatch]); - const header = ["userName", "userGroupName", "desc"]; + useEffect(() => { + if (deleteUser.status === "FAIL") { + scrollToElement(infoBoxRef.current); + } + + if (deleteUser.hasSucceeded) { + dispatch(getUsers({})); + } + }, [deleteUser.status, dispatch]); + const header = ["userName", "userGroupName", "desc"]; const label = { userName: t("user.username"), userGroupName: t("user.groups"), @@ -65,7 +87,7 @@ export const UsersTable = ({ headerActions, onEdit }: IOwnProps) => { userGroupName: item.userGroupName?.desc ?? item.userGroupName?.code ?? "", desc: item.desc ?? "", - passwd: item.passwd ?? "" + passwd: item.passwd ?? "", }; }); }; @@ -85,23 +107,42 @@ export const UsersTable = ({ headerActions, onEdit }: IOwnProps) => { case "SUCCESS": return ( - ({ - ...user, - userGroupName: user.userGroupName?.code, - }))} - rowKey="userName" - headerActions={headerActions} - onEdit={canUpdate ? onEdit: undefined} - /> + <> + {deleteUser.status === "FAIL" && ( +
+ +
+ )} +
({ + ...user, + userGroupName: user.userGroupName?.code, + }))} + rowKey="userName" + headerActions={headerActions} + onEdit={canUpdate ? onEdit : undefined} + onDelete={canDelete ? onDelete : undefined} + /> + { + dispatch(deleteUserReset()); + }} + handleSecondaryButtonClick={() => ({})} + /> + ); case "SUCCESS_EMPTY": return ; diff --git a/src/mockServer/routes/users.js b/src/mockServer/routes/users.js index 8b8378e7e..94cfcca7b 100644 --- a/src/mockServer/routes/users.js +++ b/src/mockServer/routes/users.js @@ -29,6 +29,16 @@ export const userRoutes = (server) => { server.put("/:username").intercept((_req, res) => { res.status(200).json(_req.jsonBody()); }); + server.delete("/:username").intercept((req, res) => { + const username = req.params.username; + switch (username) { + case "FAIL": + res.status(400).json({ message: "Fail to delete user" }); + break; + default: + res.status(204); + } + }); server.get("/:username/settings/dashboard").intercept((req, res) => { res.status(200).json(dashboardSettingDTO); }); diff --git a/src/mockServer/routes/wards.js b/src/mockServer/routes/wards.js index c692b5d38..3a5a3c570 100644 --- a/src/mockServer/routes/wards.js +++ b/src/mockServer/routes/wards.js @@ -40,10 +40,10 @@ export const wardsRoutes = (server) => { const code = req.params.code; switch (code) { case "FAIL": - res.status(400).json({ message: "Fail to update ward" }); + res.status(400).json({ message: "Fail to delete ward" }); break; default: - res.status(200); + res.status(204); } }); }); diff --git a/src/resources/i18n/en.json b/src/resources/i18n/en.json index 1ca6ac69d..e580cb747 100644 --- a/src/resources/i18n/en.json +++ b/src/resources/i18n/en.json @@ -30,6 +30,7 @@ "editGroup": "Edit group", "description": "Description", "lastlogin": "Last login", + "deleted": "User deleted", "groupCreated": "Group created", "groupDeleted": "Group deleted", "groupUpdated": "Group updated", @@ -41,6 +42,7 @@ "createdSuccessTitle": "User created", "createdSuccessMessage": "User has been created successfully!", "updatedSuccessTitle": "User updated", + "deleteSuccess": "User has been deleted successfully!", "updatedSuccessMessage": "User has been updated successfully!", "validateUserNeedsGroup": "Each user should belong to a group", "validatePasswordNeeded": "No password provided.",