Skip to content

Commit

Permalink
Feature/#271 스터디원api (#291)
Browse files Browse the repository at this point in the history
* feat: study member api with token

- #271

* feat : patch study mandate

- #271

* feat : 스터디원 관리 Menu

- #271

* feat : search by name

* refactor : ParticipantMenu 공통 컴포넌트 적용

- #271

* feat : 실제 스터디 정보와 연결

- #271

* fix : build error

- #271
- omit으로 불필요한 props 제거

* fix : StudyMemeber Type

- #271

* fix : build error

- #271

* fix : import order error

- #271
  • Loading branch information
jasper200207 authored Aug 29, 2024
1 parent 31b34ac commit 6ad77f8
Show file tree
Hide file tree
Showing 10 changed files with 181 additions and 9 deletions.
10 changes: 9 additions & 1 deletion src/app/api/member.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -21,4 +29,4 @@ const useGetSideBarInfoQuery = () => {
});
};

export { getSidebarInfo, useGetSideBarInfoQuery };
export { getSidebarInfo, useGetSideBarInfoQuery, patchStudyMandate };
22 changes: 18 additions & 4 deletions src/app/api/study.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}`);
Expand Down
12 changes: 11 additions & 1 deletion src/app/team/[teamId]/study/[studyId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -102,7 +103,16 @@ const Page = ({ params }: { params: { teamId: number; studyId: number } }) => {
</Flex>
<Flex direction="column" rowGap={{ base: '6', '2xl': '12' }}>
{/* <Feed /> */}
<Participant participantInfos={participantData} />
<Flex align="right" direction="column" rowGap="3">
{studyData && (
<StudyParticipantMenu
studyId={params.studyId}
teamId={studyData?.teamReference.id}
leaderId={studyData?.studyLeaderId}
/>
)}
<Participant participantInfos={participantData} />
</Flex>
</Flex>
</Grid>
</Flex>
Expand Down
2 changes: 1 addition & 1 deletion src/components/StudyCard/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Study } from '@/types';

export interface StudyCardProps extends Study {
export interface StudyCardProps extends Omit<Study, 'studyLeaderId' | 'teamReference'> {
rank: number;
}
79 changes: 79 additions & 0 deletions src/containers/study/StudyParticipantMenu/index.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<ParticipantMenu
gap="3"
w="fit-content"
ml="auto"
isOpen={isOpen}
setIsOpen={setIsOpen}
leader={leader}
includeMembers={includeMembers}
excludeMembers={excludeMembers}
onAdd={handleAddMember}
onRemove={handleDeleteMember}
onMandateLeader={handleMandateLeader}
>
<IconButton
fontSize="16px"
transform={isOpen ? 'rotate(90deg)' : 'rotate(0deg)'}
transition="all 0.2s"
aria-label=""
icon={<MdOutlineArrowForwardIos />}
isRound
size="icon_sm"
variant="icon_orange"
/>
<Text>관리</Text>
</ParticipantMenu>
);
};

export default StudyParticipantMenu;
5 changes: 5 additions & 0 deletions src/containers/study/StudyParticipantMenu/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface StudyParticipantMenuProps {
studyId: number;
teamId: number;
leaderId: number;
}
4 changes: 2 additions & 2 deletions src/hooks/useFetchWithToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ export function useGetFetchWithToken(fetch: (token: string, ...props: any[]) =>
return result;
}

export function useMutateWithToken(fetch: (token: string, ...props: any[]) => Promise<FetchResult>) {
const user = useGetUser();
export function useMutateWithToken(fetch: (token: string, ...props: any[]) => Promise<FetchResult>, originUser?: any) {
const user = originUser !== undefined ? originUser : useGetUser();

return (...props: any[]) => fetch(user?.token || '', ...props);
}
16 changes: 16 additions & 0 deletions src/mocks/participant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
25 changes: 25 additions & 0 deletions src/mocks/studyMember.ts
Original file line number Diff line number Diff line change
@@ -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: '' },
];
15 changes: 15 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -29,6 +36,8 @@ export interface Study {
cropId: number;
status: string;
studyProgressRatio: number;
studyLeaderId: number;
teamReference: TeamReference;
}

export interface Team {
Expand All @@ -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;
Expand Down

0 comments on commit 6ad77f8

Please sign in to comment.