diff --git a/src/app/api/member.ts b/src/app/api/member.ts
index 2803f02..bc2cf6f 100644
--- a/src/app/api/member.ts
+++ b/src/app/api/member.ts
@@ -13,6 +13,14 @@ const getSidebarInfo = (token: string, memberId: number) =>
},
});
+const patchStudyMandate = (token: string, studyId: number, newStudyLeaderId: number) =>
+ memberFetcher(`/study/${studyId}/mandate/${newStudyLeaderId}`, {
+ method: 'PATCH',
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
+ });
+
const useGetSideBarInfoQuery = () => {
const user = useGetUser();
return useQuery({
@@ -21,4 +29,4 @@ const useGetSideBarInfoQuery = () => {
});
};
-export { getSidebarInfo, useGetSideBarInfoQuery };
+export { getSidebarInfo, useGetSideBarInfoQuery, patchStudyMandate };
diff --git a/src/app/api/study.ts b/src/app/api/study.ts
index 946f86c..41c48b8 100644
--- a/src/app/api/study.ts
+++ b/src/app/api/study.ts
@@ -53,22 +53,36 @@ const patchStudyStatus = (studyId: number, status: string) =>
method: 'PATCH',
});
-const postStudyMember = (studyId: number, userId: number) =>
+const postStudyMember = (token: string, studyId: number, userId: number) =>
studyFetcher(`/studies/${studyId}/members/${userId}`, {
method: 'POST',
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
});
-const deleteStudyMember = (studyId: number, userId: number) =>
+const deleteStudyMember = (token: string, studyId: number, userId: number) =>
studyFetcher(`/studies/${studyId}/members/${userId}`, {
method: 'DELETE',
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
});
-const leaveStudy = (studyId: number) =>
+const leaveStudy = (token: string, studyId: number) =>
studyFetcher(`/studies/${studyId}/members`, {
method: 'DELETE',
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
});
-const getStudyMembers = (studyId: number) => studyFetcher(`/studies/${studyId}/members`);
+const getStudyMembers = (token: string, studyId: number) =>
+ studyFetcher(`/studies/${studyId}/members`, {
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
+ });
const getStudies = (studyId: number, page: number, size: number) =>
studyFetcher(`/teams/${studyId}/studies?page=${page}&size=${size}`);
diff --git a/src/app/team/[teamId]/study/[studyId]/page.tsx b/src/app/team/[teamId]/study/[studyId]/page.tsx
index 4959643..dcfddca 100644
--- a/src/app/team/[teamId]/study/[studyId]/page.tsx
+++ b/src/app/team/[teamId]/study/[studyId]/page.tsx
@@ -17,6 +17,7 @@ import TerminateStudyModal from '@/containers/study/Modal/TerminateStudyModal';
import Participant from '@/containers/study/Participant';
import StudyControlPanel from '@/containers/study/StudyControlPanel';
import StudyInfoCard from '@/containers/study/StudyInfoCard';
+import StudyParticipantMenu from '@/containers/study/StudyParticipantMenu';
import participantData from '@/mocks/participant';
import { DocumentList, Study } from '@/types';
@@ -102,7 +103,16 @@ const Page = ({ params }: { params: { teamId: number; studyId: number } }) => {
{/* */}
-
+
+ {studyData && (
+
+ )}
+
+
diff --git a/src/components/StudyCard/types.ts b/src/components/StudyCard/types.ts
index a8c6b98..99c0096 100644
--- a/src/components/StudyCard/types.ts
+++ b/src/components/StudyCard/types.ts
@@ -1,5 +1,5 @@
import { Study } from '@/types';
-export interface StudyCardProps extends Study {
+export interface StudyCardProps extends Omit {
rank: number;
}
diff --git a/src/containers/study/StudyParticipantMenu/index.tsx b/src/containers/study/StudyParticipantMenu/index.tsx
new file mode 100644
index 0000000..4620032
--- /dev/null
+++ b/src/containers/study/StudyParticipantMenu/index.tsx
@@ -0,0 +1,79 @@
+import { IconButton, Text } from '@chakra-ui/react';
+import { useState } from 'react';
+import { MdOutlineArrowForwardIos } from 'react-icons/md';
+
+import { patchStudyMandate } from '@/app/api/member';
+import { deleteStudyMember, getStudyMembers, postStudyMember } from '@/app/api/study';
+import { getTeamMembers } from '@/app/api/team';
+import ParticipantMenu from '@/components/ParticipantMenu';
+import { StudyParticipantMenuProps } from '@/containers/study/StudyParticipantMenu/types';
+import { useGetFetchWithToken, useMutateWithToken } from '@/hooks/useFetchWithToken';
+import useGetUser from '@/hooks/useGetUser';
+import { Member, StudyMember } from '@/types';
+
+const StudyParticipantMenu = ({ studyId, teamId, leaderId }: StudyParticipantMenuProps) => {
+ const user = useGetUser();
+ const [isOpen, setIsOpen] = useState(false);
+
+ const studyMembers = useGetFetchWithToken(getStudyMembers, [studyId], user)?.map(
+ (data: StudyMember) =>
+ ({
+ id: data.memberId,
+ name: data.name,
+ imageUrl: data.imageUrl,
+ }) as Member,
+ );
+ const teamMembers = useGetFetchWithToken(getTeamMembers, [teamId], user);
+
+ const leader = studyMembers?.find((member: Member) => member.id === leaderId);
+ const includeMembers = studyMembers?.filter((member: Member) => member.id !== leaderId);
+ const excludeMembers = teamMembers?.filter(
+ (member: Member) => !studyMembers?.find((studyData: Member) => studyData.id === member.id),
+ );
+
+ const addMember = useMutateWithToken(postStudyMember, user);
+ const deleteMember = useMutateWithToken(deleteStudyMember, user);
+ const mandateLeader = useMutateWithToken(patchStudyMandate, user);
+
+ const handleAddMember = (member: Member) => {
+ addMember(studyId, member.id);
+ };
+
+ const handleDeleteMember = (member: Member) => {
+ deleteMember(studyId, member.id);
+ };
+
+ const handleMandateLeader = (member: Member) => {
+ mandateLeader(studyId, member.id);
+ };
+
+ return (
+
+ }
+ isRound
+ size="icon_sm"
+ variant="icon_orange"
+ />
+ 관리
+
+ );
+};
+
+export default StudyParticipantMenu;
diff --git a/src/containers/study/StudyParticipantMenu/types.ts b/src/containers/study/StudyParticipantMenu/types.ts
new file mode 100644
index 0000000..13c4de7
--- /dev/null
+++ b/src/containers/study/StudyParticipantMenu/types.ts
@@ -0,0 +1,5 @@
+export interface StudyParticipantMenuProps {
+ studyId: number;
+ teamId: number;
+ leaderId: number;
+}
diff --git a/src/hooks/useFetchWithToken.ts b/src/hooks/useFetchWithToken.ts
index 1024e07..3278fd0 100644
--- a/src/hooks/useFetchWithToken.ts
+++ b/src/hooks/useFetchWithToken.ts
@@ -26,8 +26,8 @@ export function useGetFetchWithToken(fetch: (token: string, ...props: any[]) =>
return result;
}
-export function useMutateWithToken(fetch: (token: string, ...props: any[]) => Promise) {
- const user = useGetUser();
+export function useMutateWithToken(fetch: (token: string, ...props: any[]) => Promise, originUser?: any) {
+ const user = originUser !== undefined ? originUser : useGetUser();
return (...props: any[]) => fetch(user?.token || '', ...props);
}
diff --git a/src/mocks/participant.ts b/src/mocks/participant.ts
index 6f443fe..71568d0 100644
--- a/src/mocks/participant.ts
+++ b/src/mocks/participant.ts
@@ -31,6 +31,22 @@ const participantData: ParticipantType[] = [
{ id: 28, name: '황철수', status: '스터디원', profileImg: 'profile6.png', myPageUrl: '/' },
{ id: 29, name: '진철수', status: '스터디원', profileImg: 'profile5.png', myPageUrl: '/' },
{ id: 30, name: '황철수', status: '스터디장', profileImg: 'profile6.png', myPageUrl: '/' },
+ { id: 31, name: '김철수', status: '', profileImg: 'profile1.png', myPageUrl: '/' },
+ { id: 32, name: '윤철수', status: '', profileImg: 'profile2.png', myPageUrl: '/' },
+ { id: 33, name: '박철수', status: '', profileImg: 'profile3.png', myPageUrl: '/' },
+ { id: 34, name: '이철수', status: '', profileImg: 'profile4.png', myPageUrl: '/' },
+ { id: 35, name: '진철수', status: '', profileImg: 'profile5.png', myPageUrl: '/' },
+ { id: 36, name: '황철수', status: '', profileImg: 'profile6.png', myPageUrl: '/' },
+ { id: 37, name: '진철수', status: '', profileImg: 'profile5.png', myPageUrl: '/' },
+ { id: 38, name: '황철수', status: '', profileImg: 'profile6.png', myPageUrl: '/' },
+ { id: 39, name: '진철수', status: '', profileImg: 'profile5.png', myPageUrl: '/' },
+ { id: 40, name: '황철수', status: '', profileImg: 'profile6.png', myPageUrl: '/' },
+ { id: 41, name: '진철수', status: '', profileImg: 'profile5.png', myPageUrl: '/' },
+ { id: 42, name: '황철수', status: '', profileImg: 'profile6.png', myPageUrl: '/' },
+ { id: 43, name: '진철수', status: '', profileImg: 'profile5.png', myPageUrl: '/' },
+ { id: 44, name: '황철수', status: '', profileImg: 'profile6.png', myPageUrl: '/' },
+ { id: 45, name: '진철수', status: '', profileImg: 'profile5.png', myPageUrl: '/' },
+ { id: 46, name: '황철수', status: '', profileImg: 'profile6.png', myPageUrl: '/' },
];
export default participantData;
diff --git a/src/mocks/studyMember.ts b/src/mocks/studyMember.ts
new file mode 100644
index 0000000..b7d1479
--- /dev/null
+++ b/src/mocks/studyMember.ts
@@ -0,0 +1,25 @@
+/* eslint-disable import/prefer-default-export */
+import { Member } from '@/types';
+
+export const studyMember: Member[] = [
+ { id: 21, name: '김철수21', imageUrl: '' },
+ { id: 22, name: '김철수22', imageUrl: '' },
+ { id: 23, name: '김철수23', imageUrl: '' },
+ { id: 24, name: '김철수24', imageUrl: '' },
+ { id: 25, name: '김철수25', imageUrl: '' },
+ { id: 26, name: '김철수26', imageUrl: '' },
+ { id: 27, name: '김철수27', imageUrl: '' },
+ { id: 28, name: '김철수28', imageUrl: '' },
+ { id: 29, name: '김철수29', imageUrl: '' },
+ { id: 10, name: '김철수10', imageUrl: '' },
+ { id: 11, name: '김철수11', imageUrl: '' },
+ { id: 12, name: '김철수12', imageUrl: '' },
+ { id: 13, name: '김철수13', imageUrl: '' },
+ { id: 14, name: '김철수14', imageUrl: '' },
+ { id: 15, name: '김철수15', imageUrl: '' },
+ { id: 16, name: '김철수16', imageUrl: '' },
+ { id: 17, name: '김철수17', imageUrl: '' },
+ { id: 18, name: '김철수18', imageUrl: '' },
+ { id: 19, name: '김철수19', imageUrl: '' },
+ { id: 20, name: '김철수20', imageUrl: '' },
+];
diff --git a/src/types.ts b/src/types.ts
index 8fe32e8..241a97c 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -20,6 +20,13 @@ export interface CurriculumItemDto {
isDeleted: boolean;
}
+interface TeamReference {
+ readonly id: number;
+ name: string;
+ description: string;
+ imageUrl: string;
+}
+
export interface Study {
readonly id: number;
name: string;
@@ -29,6 +36,8 @@ export interface Study {
cropId: number;
status: string;
studyProgressRatio: number;
+ studyLeaderId: number;
+ teamReference: TeamReference;
}
export interface Team {
@@ -42,6 +51,12 @@ export interface TeamDetail extends Team {
attendanceRatio: number;
}
+export interface StudyMember {
+ readonly memberId: number;
+ name: string;
+ imageUrl: string;
+}
+
export interface Member {
readonly id: number;
name: string;