diff --git a/api/v2/user_service.go b/api/v2/user_service.go
index 527ecf8..c413921 100644
--- a/api/v2/user_service.go
+++ b/api/v2/user_service.go
@@ -89,7 +89,7 @@ func (s *UserService) CreateUser(ctx context.Context, request *apiv2pb.CreateUse
func (s *UserService) DeleteUser(ctx context.Context, request *apiv2pb.DeleteUserRequest) (*apiv2pb.DeleteUserResponse, error) {
userID := ctx.Value(UserIDContextKey).(int32)
if userID == request.Id {
- return nil, status.Errorf(codes.InvalidArgument, "cannot delete self")
+ return nil, status.Errorf(codes.InvalidArgument, "cannot delete yourself")
}
err := s.Store.DeleteUser(ctx, &store.DeleteUser{
diff --git a/web/src/components/setting/AccessTokenSection.tsx b/web/src/components/setting/AccessTokenSection.tsx
index 61578d4..b18422b 100644
--- a/web/src/components/setting/AccessTokenSection.tsx
+++ b/web/src/components/setting/AccessTokenSection.tsx
@@ -1,4 +1,4 @@
-import { Button } from "@mui/joy";
+import { Button, IconButton } from "@mui/joy";
import axios from "axios";
import copy from "copy-to-clipboard";
import { useEffect, useState } from "react";
@@ -110,7 +110,7 @@ const AccessTokenSection = () => {
{String(userAccessToken.expiresAt ?? "Never")}
-
+
|
))}
diff --git a/web/src/components/setting/MemberSection.tsx b/web/src/components/setting/MemberSection.tsx
index 527f570..1032cda 100644
--- a/web/src/components/setting/MemberSection.tsx
+++ b/web/src/components/setting/MemberSection.tsx
@@ -1,7 +1,10 @@
-import { Button } from "@mui/joy";
+import { Button, IconButton } from "@mui/joy";
import { useEffect, useState } from "react";
+import toast from "react-hot-toast";
import useUserStore from "../../stores/v1/user";
+import { showCommonDialog } from "../Alert";
import CreateUserDialog from "../CreateUserDialog";
+import Icon from "../Icon";
const MemberSection = () => {
const userStore = useUserStore();
@@ -18,6 +21,22 @@ const MemberSection = () => {
setCurrentEditingUser(undefined);
};
+ const handleDeleteUser = async (user: User) => {
+ showCommonDialog({
+ title: "Delete User",
+ content: `Are you sure to delete user \`${user.nickname}\`? You cannot undo this action.`,
+ style: "danger",
+ onConfirm: async () => {
+ try {
+ await userStore.deleteUser(user.id);
+ toast.success(`User \`${user.nickname}\` deleted successfully`);
+ } catch (error: any) {
+ toast.error(`Failed to delete user \`${user.nickname}\`: ${error.response.data.message}`);
+ }
+ },
+ });
+ };
+
return (
<>
@@ -68,16 +87,20 @@ const MemberSection = () => {
{user.nickname} |
{user.email} |
{user.role} |
-
-
+
+
+ handleDeleteUser(user)}>
+
+
|
))}
diff --git a/web/src/helpers/api.ts b/web/src/helpers/api.ts
index db5fae9..a25b4d7 100644
--- a/web/src/helpers/api.ts
+++ b/web/src/helpers/api.ts
@@ -43,8 +43,8 @@ export function patchUser(userPatch: UserPatch) {
return axios.patch(`/api/v1/user/${userPatch.id}`, userPatch);
}
-export function deleteUser(userDelete: UserDelete) {
- return axios.delete(`/api/v1/user/${userDelete.id}`);
+export function deleteUser(userId: UserId) {
+ return axios.delete(`/api/v2/users/${userId}`);
}
export function getShortcutList(shortcutFind?: ShortcutFind) {
diff --git a/web/src/stores/v1/user.ts b/web/src/stores/v1/user.ts
index 7f17abd..2fbc2b6 100644
--- a/web/src/stores/v1/user.ts
+++ b/web/src/stores/v1/user.ts
@@ -19,6 +19,7 @@ interface UserState {
getCurrentUser: () => User;
createUser: (userCreate: UserCreate) => Promise;
patchUser: (userPatch: UserPatch) => Promise;
+ deleteUser: (id: UserId) => Promise;
}
const useUserStore = create()((set, get) => ({
@@ -67,6 +68,12 @@ const useUserStore = create()((set, get) => ({
userMap[user.id] = user;
set(userMap);
},
+ deleteUser: async (userId: UserId) => {
+ await api.deleteUser(userId);
+ const userMap = get().userMapById;
+ delete userMap[userId];
+ set(userMap);
+ },
getUserById: (id: UserId) => {
const userMap = get().userMapById;
return userMap[id] as User;