From 4c5c243acdf1e4ba1d702127a07a647e145278b2 Mon Sep 17 00:00:00 2001
From: aken-you
Date: Thu, 9 Oct 2025 15:32:15 +0900
Subject: [PATCH 1/8] =?UTF-8?q?feat:=20=EA=B4=80=EB=A6=AC=EC=9E=90=20?=
=?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=EC=97=90=EC=84=9C=20=EC=82=AC?=
=?UTF-8?q?=EC=9A=A9=EC=9E=90=20=EC=A0=95=EB=B3=B4=20=EB=B3=80=EA=B2=BD=20?=
=?UTF-8?q?UI=20=EC=83=9D=EC=84=B1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/features/admin/ui/member-list-table.tsx | 25 ++++++++++++++++++++-
1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/src/features/admin/ui/member-list-table.tsx b/src/features/admin/ui/member-list-table.tsx
index d244a28f..764622ba 100644
--- a/src/features/admin/ui/member-list-table.tsx
+++ b/src/features/admin/ui/member-list-table.tsx
@@ -102,7 +102,30 @@ export default function MemberListTable() {
onChange={setSearchKeyword}
/>
-
+
+
+
+ {someSelected && (
+
+
+
+ {selectedIds.size}
+
+ 명 선택
+
+
+
+
+
+
+
+ )}
+
+
Date: Thu, 9 Oct 2025 15:42:12 +0900
Subject: [PATCH 2/8] =?UTF-8?q?refactor:=20=EA=B6=8C=ED=95=9C=EA=B3=BC=20?=
=?UTF-8?q?=EC=83=81=ED=83=9C=EB=A5=BC=20const=20=ED=8F=B4=EB=8D=94?=
=?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=EB=8F=99?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/features/admin/const/member.ts | 12 ++++++++++++
src/features/admin/ui/member-list-table.tsx | 17 +++--------------
2 files changed, 15 insertions(+), 14 deletions(-)
create mode 100644 src/features/admin/const/member.ts
diff --git a/src/features/admin/const/member.ts b/src/features/admin/const/member.ts
new file mode 100644
index 00000000..4008a566
--- /dev/null
+++ b/src/features/admin/const/member.ts
@@ -0,0 +1,12 @@
+export const ROLE_MAP = {
+ ROLE_MEMBER: '일반',
+ ROLE_MENTOR: '멘토',
+ ROLE_ADMIN: '관리자',
+};
+
+export const MEMBER_STATUS_MAP = {
+ ACTIVE: '활성',
+ PERM_BAN: '일시정지',
+ PAUSED: '영구정지',
+ DORMANT: '휴면',
+};
diff --git a/src/features/admin/ui/member-list-table.tsx b/src/features/admin/ui/member-list-table.tsx
index 764622ba..d026c86d 100644
--- a/src/features/admin/ui/member-list-table.tsx
+++ b/src/features/admin/ui/member-list-table.tsx
@@ -9,25 +9,16 @@ import { SingleDropdown } from '@/shared/ui/dropdown';
import Pagination from '@/shared/ui/pagination';
import FilledX from 'public/icons/filled-x.svg';
import SearchIcon from 'public/icons/search.svg';
+import ChangeStatusModal from './chage-status-modal';
import { MemberStatus, RoleId } from '../api/types';
+import { MEMBER_STATUS_MAP, ROLE_MAP } from '../const/member';
import { useGetMemberListQuery } from '../model/use-member-list-query';
-const ROLE_MAP = {
- ROLE_MEMBER: '일반',
- ROLE_MENTOR: '멘토',
- ROLE_ADMIN: '관리자',
-};
const ROLE_OPTIONS = Object.entries(ROLE_MAP).map(([key, label]) => ({
value: key,
label,
}));
-const MEMBER_STATUS_MAP = {
- ACTIVE: '활성',
- PERM_BAN: '일시정지',
- PAUSED: '영구정지',
- DORMANT: '휴면',
-};
const MEMBER_STATUS_OPTIONS = Object.entries(MEMBER_STATUS_MAP).map(
([key, label]) => ({
value: key,
@@ -118,9 +109,7 @@ export default function MemberListTable() {
-
+
)}
From dac20b04e67dda85ee667ff9da64a5b2ed24f1da Mon Sep 17 00:00:00 2001
From: aken-you
Date: Thu, 9 Oct 2025 15:54:27 +0900
Subject: [PATCH 3/8] =?UTF-8?q?style:=20MemberListFilter=20=EC=BB=B4?=
=?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=EC=9D=98=20=EC=B5=9C=EC=83=81?=
=?UTF-8?q?=EC=9C=84=20=EC=9A=94=EC=86=8C=EB=A1=9C=20div=20=EC=B6=94?=
=?UTF-8?q?=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/features/admin/ui/member-list-table.tsx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/features/admin/ui/member-list-table.tsx b/src/features/admin/ui/member-list-table.tsx
index d026c86d..9aeb2880 100644
--- a/src/features/admin/ui/member-list-table.tsx
+++ b/src/features/admin/ui/member-list-table.tsx
@@ -219,7 +219,7 @@ function MemberListFilter({
onSelectMemberStatus: (memberStatus: MemberStatus | null) => void;
}) {
return (
- <>
+
{(roleId || memberStatus) && (
- >
+
);
}
From d7b5293571c5959906d5097cc876c8803c047942 Mon Sep 17 00:00:00 2001
From: aken-you
Date: Thu, 9 Oct 2025 18:01:16 +0900
Subject: [PATCH 4/8] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?=
=?UTF-8?q?=EA=B3=84=EC=A0=95=20=EC=83=81=ED=83=9C=20=EB=B3=80=EA=B2=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/features/admin/api/member-list.ts | 19 +++-
src/features/admin/api/types.ts | 5 +
.../admin/model/use-member-list-query.ts | 59 +++++++++-
src/features/admin/ui/chage-status-modal.tsx | 105 ++++++++++++++++++
src/features/admin/ui/member-list-table.tsx | 8 +-
5 files changed, 190 insertions(+), 6 deletions(-)
create mode 100644 src/features/admin/ui/chage-status-modal.tsx
diff --git a/src/features/admin/api/member-list.ts b/src/features/admin/api/member-list.ts
index 064ffedd..f6a16992 100644
--- a/src/features/admin/api/member-list.ts
+++ b/src/features/admin/api/member-list.ts
@@ -1,6 +1,11 @@
import { axiosInstance } from '@/shared/tanstack-query/axios';
-import { GetMemberListRequest, GetMemberListResponse } from './types';
+import {
+ ChangeMemberStatusRequest,
+ GetMemberListRequest,
+ GetMemberListResponse,
+} from './types';
+// 사용자 목록 조회
export const getMemberList = async ({
roleId,
memberStatus,
@@ -24,3 +29,15 @@ export const getMemberList = async ({
return res.data.content;
};
+
+// 사용자 계정 상태 변경
+export const changeMemberStatus = async ({
+ memberId,
+ to,
+}: ChangeMemberStatusRequest) => {
+ const res = await axiosInstance.patch(
+ `/admin/members/${memberId}/status?to=${to}`,
+ );
+
+ return res.data;
+};
diff --git a/src/features/admin/api/types.ts b/src/features/admin/api/types.ts
index 9f4d17a9..46c13a7b 100644
--- a/src/features/admin/api/types.ts
+++ b/src/features/admin/api/types.ts
@@ -28,3 +28,8 @@ export interface GetMemberListResponse {
};
}[];
}
+
+export interface ChangeMemberStatusRequest {
+ memberId: number;
+ to: MemberStatus;
+}
diff --git a/src/features/admin/model/use-member-list-query.ts b/src/features/admin/model/use-member-list-query.ts
index 762ce211..4c835a01 100644
--- a/src/features/admin/model/use-member-list-query.ts
+++ b/src/features/admin/model/use-member-list-query.ts
@@ -1,7 +1,12 @@
-import { useQuery } from '@tanstack/react-query';
-import { getMemberList } from '../api/member-list';
-import { GetMemberListRequest } from '../api/types';
+import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
+import { changeMemberStatus, getMemberList } from '../api/member-list';
+import {
+ ChangeMemberStatusRequest,
+ GetMemberListRequest,
+ GetMemberListResponse,
+} from '../api/types';
+// 사용자 목록 조회
export const useGetMemberListQuery = ({
roleId,
memberStatus,
@@ -19,3 +24,51 @@ export const useGetMemberListQuery = ({
}),
});
};
+
+// 사용자 계정 상태 변경
+export const useChangeMemberStatusMutation = () => {
+ const queryClient = useQueryClient();
+
+ return useMutation({
+ mutationFn: async (data: {
+ members: GetMemberListResponse['content'];
+ to: ChangeMemberStatusRequest['to'];
+ }) => {
+ // 병렬로 선택한 모든 사용자의 상태 변경 요청을 보냄
+ // 성공: {status: "fulfilled", value: {memberId, success: true}}
+ // 실패: {status: "fulfilled", value: {memberId, success: false}} (개별 요청 실패는 catch에서 처리했기 때문에 status가 rejected가 되지 않음)
+ const results: PromiseSettledResult<{
+ memberId: number;
+ success: boolean;
+ }>[] = await Promise.allSettled(
+ data.members.map((member) =>
+ changeMemberStatus({ memberId: member.memberId, to: data.to })
+ .then(() => ({ memberId: member.memberId, success: true }))
+ .catch(() => ({ memberId: member.memberId, success: false })),
+ ),
+ );
+
+ const failedMemberIds = results
+ .filter(
+ (result) => result.status === 'fulfilled' && !result.value.success,
+ )
+ .map((result) =>
+ result.status === 'fulfilled' ? result.value.memberId : null,
+ )
+ .filter(Boolean);
+
+ if (failedMemberIds.length > 0) {
+ const failedMemberNames = data.members
+ .filter((member) => failedMemberIds.includes(member.memberId))
+ .map((member) => member.memberName);
+
+ alert(
+ `다음 회원들의 상태 변경에 실패했습니다: ${failedMemberNames.join(', ')}`,
+ );
+ }
+ },
+ onSuccess: async () => {
+ await queryClient.invalidateQueries({ queryKey: ['memberList'] });
+ },
+ });
+};
diff --git a/src/features/admin/ui/chage-status-modal.tsx b/src/features/admin/ui/chage-status-modal.tsx
new file mode 100644
index 00000000..c78bb755
--- /dev/null
+++ b/src/features/admin/ui/chage-status-modal.tsx
@@ -0,0 +1,105 @@
+'use client';
+
+import { XIcon } from 'lucide-react';
+import { useState } from 'react';
+import Button from '@/shared/ui/button';
+import { Modal } from '@/shared/ui/modal';
+import { RadioGroup, RadioGroupItem } from '@/shared/ui/radio';
+import { GetMemberListResponse, MemberStatus } from '../api/types';
+import { MEMBER_STATUS_MAP } from '../const/member';
+import { useChangeMemberStatusMutation } from '../model/use-member-list-query';
+
+const MEMBER_STATUS_OPTIONS = Object.entries(MEMBER_STATUS_MAP).map(
+ ([key, label]) => ({
+ value: key,
+ label,
+ }),
+);
+
+interface ChangeStatusModalProps {
+ members: GetMemberListResponse['content'];
+}
+
+export default function ChangeStatusModal({ members }: ChangeStatusModalProps) {
+ const [open, setOpen] = useState(false);
+
+ return (
+
+
+
+
+
+
+
+
+
+
+ 계정 상태 변경
+
+ setOpen(false)}>
+
+
+
+
+ setOpen(false)} />
+
+
+
+ );
+}
+
+function ChangeStatusForm({
+ members,
+ onClose,
+}: {
+ members: GetMemberListResponse['content'];
+ onClose: () => void;
+}) {
+ const INIT_STATUS: MemberStatus = 'ACTIVE';
+ const [status, setStatus] = useState(INIT_STATUS);
+
+ const { mutate: changeStatus } = useChangeMemberStatusMutation();
+
+ const handleChangeStatus = () => {
+ changeStatus(
+ { members, to: status },
+ {
+ onSuccess: () => {
+ onClose();
+ },
+ },
+ );
+ };
+
+ return (
+ <>
+
+ setStatus(status)}
+ >
+ {MEMBER_STATUS_OPTIONS.map(({ value, label }) => (
+
+
+
+
+ ))}
+
+
+
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/src/features/admin/ui/member-list-table.tsx b/src/features/admin/ui/member-list-table.tsx
index 9aeb2880..d24f6208 100644
--- a/src/features/admin/ui/member-list-table.tsx
+++ b/src/features/admin/ui/member-list-table.tsx
@@ -41,7 +41,7 @@ export default function MemberListTable() {
const memberList = data?.content || [];
- const [selectedIds, setSelectedIds] = useState(() => new Set());
+ const [selectedIds, setSelectedIds] = useState>(() => new Set());
const headerCheckboxRef = useRef(null);
const allSelected =
@@ -109,7 +109,11 @@ export default function MemberListTable() {
-
+
+ selectedIds.has(member.memberId),
+ )}
+ />
)}
From 1c9b2907a5517c0674d8a8a8f79e591c5d25ce4d Mon Sep 17 00:00:00 2001
From: aken-you
Date: Thu, 9 Oct 2025 18:26:03 +0900
Subject: [PATCH 5/8] =?UTF-8?q?feat:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20?=
=?UTF-8?q?=EA=B6=8C=ED=95=9C=20=EB=B3=80=EA=B2=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/features/admin/api/member-list.ts | 13 +++
src/features/admin/api/types.ts | 5 +
.../admin/model/use-member-list-query.ts | 55 +++++++++-
src/features/admin/ui/change-role-modal.tsx | 103 ++++++++++++++++++
src/features/admin/ui/member-list-table.tsx | 9 +-
5 files changed, 181 insertions(+), 4 deletions(-)
create mode 100644 src/features/admin/ui/change-role-modal.tsx
diff --git a/src/features/admin/api/member-list.ts b/src/features/admin/api/member-list.ts
index f6a16992..6c5251ac 100644
--- a/src/features/admin/api/member-list.ts
+++ b/src/features/admin/api/member-list.ts
@@ -1,5 +1,6 @@
import { axiosInstance } from '@/shared/tanstack-query/axios';
import {
+ ChangeMemberRoleRequest,
ChangeMemberStatusRequest,
GetMemberListRequest,
GetMemberListResponse,
@@ -41,3 +42,15 @@ export const changeMemberStatus = async ({
return res.data;
};
+
+// 사용자 권한 변경
+export const changeMemberRole = async ({
+ memberId,
+ roleId,
+}: ChangeMemberRoleRequest) => {
+ const res = await axiosInstance.patch(
+ `/admin/members/${memberId}/role?role-id=${roleId}`,
+ );
+
+ return res.data;
+};
diff --git a/src/features/admin/api/types.ts b/src/features/admin/api/types.ts
index 46c13a7b..071def3c 100644
--- a/src/features/admin/api/types.ts
+++ b/src/features/admin/api/types.ts
@@ -33,3 +33,8 @@ export interface ChangeMemberStatusRequest {
memberId: number;
to: MemberStatus;
}
+
+export interface ChangeMemberRoleRequest {
+ memberId: number;
+ roleId: RoleId;
+}
diff --git a/src/features/admin/model/use-member-list-query.ts b/src/features/admin/model/use-member-list-query.ts
index 4c835a01..38422eb3 100644
--- a/src/features/admin/model/use-member-list-query.ts
+++ b/src/features/admin/model/use-member-list-query.ts
@@ -1,6 +1,11 @@
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
-import { changeMemberStatus, getMemberList } from '../api/member-list';
import {
+ changeMemberRole,
+ changeMemberStatus,
+ getMemberList,
+} from '../api/member-list';
+import {
+ ChangeMemberRoleRequest,
ChangeMemberStatusRequest,
GetMemberListRequest,
GetMemberListResponse,
@@ -72,3 +77,51 @@ export const useChangeMemberStatusMutation = () => {
},
});
};
+
+// 사용자 권한 변경
+export const useChangeMemberRoleMutation = () => {
+ const queryClient = useQueryClient();
+
+ return useMutation({
+ mutationFn: async (data: {
+ members: GetMemberListResponse['content'];
+ roleId: ChangeMemberRoleRequest['roleId'];
+ }) => {
+ // 병렬로 선택한 모든 사용자의 상태 변경 요청을 보냄
+ // 성공: {status: "fulfilled", value: {memberId, success: true}}
+ // 실패: {status: "fulfilled", value: {memberId, success: false}} (개별 요청 실패는 catch에서 처리했기 때문에 status가 rejected가 되지 않음)
+ const results: PromiseSettledResult<{
+ memberId: number;
+ success: boolean;
+ }>[] = await Promise.allSettled(
+ data.members.map((member) =>
+ changeMemberRole({ memberId: member.memberId, roleId: data.roleId })
+ .then(() => ({ memberId: member.memberId, success: true }))
+ .catch(() => ({ memberId: member.memberId, success: false })),
+ ),
+ );
+
+ const failedMemberIds = results
+ .filter(
+ (result) => result.status === 'fulfilled' && !result.value.success,
+ )
+ .map((result) =>
+ result.status === 'fulfilled' ? result.value.memberId : null,
+ )
+ .filter(Boolean);
+
+ if (failedMemberIds.length > 0) {
+ const failedMemberNames = data.members
+ .filter((member) => failedMemberIds.includes(member.memberId))
+ .map((member) => member.memberName);
+
+ alert(
+ `다음 회원들의 권한 변경에 실패했습니다: ${failedMemberNames.join(', ')}`,
+ );
+ }
+ },
+ onSuccess: async () => {
+ await queryClient.invalidateQueries({ queryKey: ['memberList'] });
+ },
+ });
+};
diff --git a/src/features/admin/ui/change-role-modal.tsx b/src/features/admin/ui/change-role-modal.tsx
new file mode 100644
index 00000000..beebf1fe
--- /dev/null
+++ b/src/features/admin/ui/change-role-modal.tsx
@@ -0,0 +1,103 @@
+'use client';
+
+import { XIcon } from 'lucide-react';
+import { useState } from 'react';
+import Button from '@/shared/ui/button';
+import { Modal } from '@/shared/ui/modal';
+import { RadioGroup, RadioGroupItem } from '@/shared/ui/radio';
+import { GetMemberListResponse, RoleId } from '../api/types';
+import { ROLE_MAP } from '../const/member';
+import { useChangeMemberRoleMutation } from '../model/use-member-list-query';
+
+const ROLE_OPTIONS = Object.entries(ROLE_MAP).map(([key, label]) => ({
+ value: key,
+ label,
+}));
+
+interface ChangeRoleModalProps {
+ members: GetMemberListResponse['content'];
+}
+
+export default function ChangeRoleModal({ members }: ChangeRoleModalProps) {
+ const [open, setOpen] = useState(false);
+
+ return (
+
+
+
+
+
+
+
+
+
+
+ 권한 변경
+
+ setOpen(false)}>
+
+
+
+
+ setOpen(false)} />
+
+
+
+ );
+}
+
+function ChangeRoleForm({
+ members,
+ onClose,
+}: {
+ members: GetMemberListResponse['content'];
+ onClose: () => void;
+}) {
+ const INIT_ROLE: RoleId = 'ROLE_MEMBER';
+ const [role, setRole] = useState(INIT_ROLE);
+
+ const { mutate: changeStatus } = useChangeMemberRoleMutation();
+
+ const handleChangeStatus = () => {
+ changeStatus(
+ { members, roleId: role },
+ {
+ onSuccess: () => {
+ onClose();
+ },
+ },
+ );
+ };
+
+ return (
+ <>
+
+ setRole(roleId)}
+ >
+ {ROLE_OPTIONS.map(({ value, label }) => (
+
+
+
+
+ ))}
+
+
+
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/src/features/admin/ui/member-list-table.tsx b/src/features/admin/ui/member-list-table.tsx
index d24f6208..2542e8f7 100644
--- a/src/features/admin/ui/member-list-table.tsx
+++ b/src/features/admin/ui/member-list-table.tsx
@@ -10,6 +10,7 @@ import Pagination from '@/shared/ui/pagination';
import FilledX from 'public/icons/filled-x.svg';
import SearchIcon from 'public/icons/search.svg';
import ChangeStatusModal from './chage-status-modal';
+import ChangeRoleModal from './change-role-modal';
import { MemberStatus, RoleId } from '../api/types';
import { MEMBER_STATUS_MAP, ROLE_MAP } from '../const/member';
import { useGetMemberListQuery } from '../model/use-member-list-query';
@@ -106,9 +107,11 @@ export default function MemberListTable() {
-
+
+ selectedIds.has(member.memberId),
+ )}
+ />
selectedIds.has(member.memberId),
From aff7e96c2a2ef82b518071f4ee104cef5d358fa6 Mon Sep 17 00:00:00 2001
From: aken-you
Date: Thu, 9 Oct 2025 18:44:03 +0900
Subject: [PATCH 6/8] =?UTF-8?q?refactor:=20=EC=84=A0=ED=83=9D=ED=95=9C=20?=
=?UTF-8?q?=ED=96=89=20=EB=B0=B0=EA=B2=BD=EC=83=89=20=EB=B3=80=EA=B2=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/features/admin/ui/member-list-table.tsx | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/features/admin/ui/member-list-table.tsx b/src/features/admin/ui/member-list-table.tsx
index 2542e8f7..37fe3c5e 100644
--- a/src/features/admin/ui/member-list-table.tsx
+++ b/src/features/admin/ui/member-list-table.tsx
@@ -163,11 +163,15 @@ export default function MemberListTable() {
{memberList.map((user, idx) => (
Date: Thu, 9 Oct 2025 18:45:51 +0900
Subject: [PATCH 7/8] =?UTF-8?q?refactor:=20=EA=B6=8C=ED=95=9C=EA=B3=BC=20?=
=?UTF-8?q?=EC=83=81=ED=83=9C=20=EB=B0=B0=EC=97=B4=20=EC=83=81=EC=88=98?=
=?UTF-8?q?=EB=A1=9C=20=EA=B4=80=EB=A6=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/features/admin/const/member.ts | 12 ++++++++++++
src/features/admin/ui/chage-status-modal.tsx | 9 +--------
src/features/admin/ui/change-role-modal.tsx | 7 +------
src/features/admin/ui/member-list-table.tsx | 19 ++++++-------------
4 files changed, 20 insertions(+), 27 deletions(-)
diff --git a/src/features/admin/const/member.ts b/src/features/admin/const/member.ts
index 4008a566..9c269162 100644
--- a/src/features/admin/const/member.ts
+++ b/src/features/admin/const/member.ts
@@ -4,9 +4,21 @@ export const ROLE_MAP = {
ROLE_ADMIN: '관리자',
};
+export const ROLE_OPTIONS = Object.entries(ROLE_MAP).map(([key, label]) => ({
+ value: key,
+ label,
+}));
+
export const MEMBER_STATUS_MAP = {
ACTIVE: '활성',
PERM_BAN: '일시정지',
PAUSED: '영구정지',
DORMANT: '휴면',
};
+
+export const MEMBER_STATUS_OPTIONS = Object.entries(MEMBER_STATUS_MAP).map(
+ ([key, label]) => ({
+ value: key,
+ label,
+ }),
+);
diff --git a/src/features/admin/ui/chage-status-modal.tsx b/src/features/admin/ui/chage-status-modal.tsx
index c78bb755..18d2cb13 100644
--- a/src/features/admin/ui/chage-status-modal.tsx
+++ b/src/features/admin/ui/chage-status-modal.tsx
@@ -6,16 +6,9 @@ import Button from '@/shared/ui/button';
import { Modal } from '@/shared/ui/modal';
import { RadioGroup, RadioGroupItem } from '@/shared/ui/radio';
import { GetMemberListResponse, MemberStatus } from '../api/types';
-import { MEMBER_STATUS_MAP } from '../const/member';
+import { MEMBER_STATUS_OPTIONS } from '../const/member';
import { useChangeMemberStatusMutation } from '../model/use-member-list-query';
-const MEMBER_STATUS_OPTIONS = Object.entries(MEMBER_STATUS_MAP).map(
- ([key, label]) => ({
- value: key,
- label,
- }),
-);
-
interface ChangeStatusModalProps {
members: GetMemberListResponse['content'];
}
diff --git a/src/features/admin/ui/change-role-modal.tsx b/src/features/admin/ui/change-role-modal.tsx
index beebf1fe..b7751d8a 100644
--- a/src/features/admin/ui/change-role-modal.tsx
+++ b/src/features/admin/ui/change-role-modal.tsx
@@ -6,14 +6,9 @@ import Button from '@/shared/ui/button';
import { Modal } from '@/shared/ui/modal';
import { RadioGroup, RadioGroupItem } from '@/shared/ui/radio';
import { GetMemberListResponse, RoleId } from '../api/types';
-import { ROLE_MAP } from '../const/member';
+import { ROLE_OPTIONS } from '../const/member';
import { useChangeMemberRoleMutation } from '../model/use-member-list-query';
-const ROLE_OPTIONS = Object.entries(ROLE_MAP).map(([key, label]) => ({
- value: key,
- label,
-}));
-
interface ChangeRoleModalProps {
members: GetMemberListResponse['content'];
}
diff --git a/src/features/admin/ui/member-list-table.tsx b/src/features/admin/ui/member-list-table.tsx
index 37fe3c5e..d410c360 100644
--- a/src/features/admin/ui/member-list-table.tsx
+++ b/src/features/admin/ui/member-list-table.tsx
@@ -12,21 +12,14 @@ import SearchIcon from 'public/icons/search.svg';
import ChangeStatusModal from './chage-status-modal';
import ChangeRoleModal from './change-role-modal';
import { MemberStatus, RoleId } from '../api/types';
-import { MEMBER_STATUS_MAP, ROLE_MAP } from '../const/member';
+import {
+ MEMBER_STATUS_MAP,
+ MEMBER_STATUS_OPTIONS,
+ ROLE_MAP,
+ ROLE_OPTIONS,
+} from '../const/member';
import { useGetMemberListQuery } from '../model/use-member-list-query';
-const ROLE_OPTIONS = Object.entries(ROLE_MAP).map(([key, label]) => ({
- value: key,
- label,
-}));
-
-const MEMBER_STATUS_OPTIONS = Object.entries(MEMBER_STATUS_MAP).map(
- ([key, label]) => ({
- value: key,
- label,
- }),
-);
-
export default function MemberListTable() {
const [roleId, setRoleId] = useState(null);
const [memberStatus, setMemberStatus] = useState(null);
From f45182776d555eb0e240171ae4482c999a47aef5 Mon Sep 17 00:00:00 2001
From: aken-you
Date: Thu, 9 Oct 2025 18:49:40 +0900
Subject: [PATCH 8/8] =?UTF-8?q?refactor:=20=EB=A9=98=ED=86=A0=EC=9D=BC=20?=
=?UTF-8?q?=EA=B2=BD=EC=9A=B0=20=EC=98=86=EC=97=90=20check=20=EC=95=84?=
=?UTF-8?q?=EC=9D=B4=EC=BD=98=EC=9C=BC=EB=A1=9C=20=ED=91=9C=EC=8B=9C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
public/icons/seal-check.svg | 10 ++++++++++
src/features/admin/ui/member-list-table.tsx | 4 +++-
2 files changed, 13 insertions(+), 1 deletion(-)
create mode 100644 public/icons/seal-check.svg
diff --git a/public/icons/seal-check.svg b/public/icons/seal-check.svg
new file mode 100644
index 00000000..57512572
--- /dev/null
+++ b/public/icons/seal-check.svg
@@ -0,0 +1,10 @@
+
diff --git a/src/features/admin/ui/member-list-table.tsx b/src/features/admin/ui/member-list-table.tsx
index d410c360..f6b135c3 100644
--- a/src/features/admin/ui/member-list-table.tsx
+++ b/src/features/admin/ui/member-list-table.tsx
@@ -8,6 +8,7 @@ import Checkbox from '@/shared/ui/checkbox';
import { SingleDropdown } from '@/shared/ui/dropdown';
import Pagination from '@/shared/ui/pagination';
import FilledX from 'public/icons/filled-x.svg';
+import SealCheckIcon from 'public/icons/seal-check.svg';
import SearchIcon from 'public/icons/search.svg';
import ChangeStatusModal from './chage-status-modal';
import ChangeRoleModal from './change-role-modal';
@@ -182,7 +183,8 @@ export default function MemberListTable() {
|
{formatYYYYMMDD(user.loginMostRecentlyAt)}
|
-
+ |
+ {user.role.roleId === 'ROLE_MENTOR' && }
{ROLE_MAP[user.role.roleId]}
|
| |