diff --git a/src/app/api/team.ts b/src/app/api/team.ts
index 135c0811..712183de 100644
--- a/src/app/api/team.ts
+++ b/src/app/api/team.ts
@@ -101,6 +101,14 @@ const deleteTeamMember = (token: string, teamId: number, memberId: number) =>
},
});
+const leaveTeam = (token: string, teamId: number) =>
+ teamFetcher(`/teams/${teamId}/members`, {
+ method: 'DELETE',
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
+ });
+
const mandateTeamLeader = (token: string, teamId: number, memberId: number) =>
teamFetcher(`/teams/${teamId}/mandate/${memberId}`, {
method: 'PATCH',
@@ -124,6 +132,7 @@ export {
getTeams,
getMyTeams,
deleteTeamMember,
+ leaveTeam,
mandateTeamLeader,
getTeamMembers,
};
diff --git a/src/app/team/[teamId]/page.tsx b/src/app/team/[teamId]/page.tsx
index 5c1ef608..69f1ff3f 100644
--- a/src/app/team/[teamId]/page.tsx
+++ b/src/app/team/[teamId]/page.tsx
@@ -199,7 +199,7 @@ const Page = ({ params }: { params: { teamId: number } }) => {
)}
- {isTeamLeader && }
+
diff --git a/src/app/team/[teamId]/study/[studyId]/page.tsx b/src/app/team/[teamId]/study/[studyId]/page.tsx
index 1e7a3b49..7115dac9 100644
--- a/src/app/team/[teamId]/study/[studyId]/page.tsx
+++ b/src/app/team/[teamId]/study/[studyId]/page.tsx
@@ -15,6 +15,7 @@ import CreateDocumentModal from '@/containers/study/CreateDocumentModal';
import { CreateDocument } from '@/containers/study/CreateDocumentModal/type';
import CurriculumCard from '@/containers/study/CurriculumCard';
import DeleteStudyModal from '@/containers/study/Modal/DeleteStudyModal';
+import LeaveStudyModal from '@/containers/study/Modal/LeaveStudyModal';
import StudyModal from '@/containers/study/Modal/StudyModal';
import TerminateStudyModal from '@/containers/study/Modal/TerminateStudyModal';
import Participant from '@/containers/study/Participant';
@@ -31,6 +32,7 @@ const Page = ({ params }: { params: { teamId: number; studyId: number } }) => {
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [isTerminateModalOpen, setIsTerminateModalOpen] = useState(false);
+ const [isLeaveModalOpen, setIsLeaveModalOpen] = useState(false);
const [documentArray, setDocumentArray] = useState([]);
const [isCreateDocumentModalOpen, setIsCreateDocumentModalOpen] = useState(false);
const categoryData: CreateDocument = { groupId: params.studyId, groupType: 'studies' };
@@ -95,11 +97,14 @@ const Page = ({ params }: { params: { teamId: number; studyId: number } }) => {
>
)}
- {studyData && studyData?.status !== 'ENDED' && user && user.memberId === studyData?.studyLeaderId && (
+ {studyData && studyData?.status !== 'ENDED' && user && (
data.memberId === user.memberId)}
editModalOpen={setIsEditModalOpen}
terminateModalOpen={setIsTerminateModalOpen}
deleteModalOpen={setIsDeleteModalOpen}
+ leaveModalOpen={setIsLeaveModalOpen}
/>
)}
@@ -199,7 +204,13 @@ const Page = ({ params }: { params: { teamId: number; studyId: number } }) => {
isOpen={isDeleteModalOpen}
setIsOpen={setIsDeleteModalOpen}
/>
-
+
setIsCreateDocumentModalOpen(false)}
diff --git a/src/components/Sidebar/SidebarContent/index.tsx b/src/components/Sidebar/SidebarContent/index.tsx
index 6ff28eb4..1b8397f7 100644
--- a/src/components/Sidebar/SidebarContent/index.tsx
+++ b/src/components/Sidebar/SidebarContent/index.tsx
@@ -11,7 +11,7 @@ import { MdOutlineLogout } from 'react-icons/md';
import { useGetSideBarInfoQuery } from '@/app/api/member';
import { defaultUserAtom, myTeamAtom, userAtom } from '@/atom';
import GoogleLoginButton from '@/containers/main/GoogleLoginButton';
-import TeamModal from '@/containers/team/TeamModal';
+import TeamModal from '@/containers/team/Modal/TeamModal';
import useGetUser from '@/hooks/useGetUser';
import SidebarIconButton from '../Button/SidebarIconButton';
diff --git a/src/containers/study/Modal/LeaveStudyModal/index.tsx b/src/containers/study/Modal/LeaveStudyModal/index.tsx
new file mode 100644
index 00000000..cbc8c466
--- /dev/null
+++ b/src/containers/study/Modal/LeaveStudyModal/index.tsx
@@ -0,0 +1,43 @@
+import { Text } from '@chakra-ui/react';
+import { useRouter } from 'next/navigation';
+
+import { leaveStudy as leaveStudyApi } from '@/app/api/study';
+import ConfirmModal from '@/components/Modal/ConfirmModal';
+import { useMutateWithToken } from '@/hooks/useFetchWithToken';
+import useRefetchSideBar from '@/hooks/useRefetchSideBar';
+
+import { LeaveStudyModalProps } from '../types';
+
+const LeaveStudyModal = ({ id, name, teamId, isOpen, setIsOpen }: LeaveStudyModalProps) => {
+ const leaveStudy = useMutateWithToken(leaveStudyApi);
+ const refetchSidebar = useRefetchSideBar();
+ const router = useRouter();
+
+ const handleClickLeave = () => {
+ leaveStudy(id).then((res) => {
+ if (res.ok) {
+ refetchSidebar();
+ setIsOpen(false);
+ router.replace(`/team/${teamId}`);
+ }
+ });
+ };
+
+ return (
+ setIsOpen(false)}
+ title="스터디 탈퇴"
+ confirmButtonText="탈퇴"
+ onConfirmButtonClick={handleClickLeave}
+ >
+
+ 스터디에서 탈퇴하면 다시 되돌릴 수 없습니다.
+
+ {`"${name}"에서 탈퇴하시겠습니까?`}
+
+
+ );
+};
+
+export default LeaveStudyModal;
diff --git a/src/containers/study/Modal/types.ts b/src/containers/study/Modal/types.ts
index 26845b08..5fb2ed05 100644
--- a/src/containers/study/Modal/types.ts
+++ b/src/containers/study/Modal/types.ts
@@ -10,3 +10,9 @@ export interface DeleteStudyModalProps extends Pick {
teamId: number;
setIsOpen: React.Dispatch>;
}
+
+export interface LeaveStudyModalProps extends Pick {
+ isOpen: boolean;
+ teamId: number;
+ setIsOpen: React.Dispatch>;
+}
diff --git a/src/containers/study/StudyControlPanel/index.tsx b/src/containers/study/StudyControlPanel/index.tsx
index 259c7a89..84d270df 100644
--- a/src/containers/study/StudyControlPanel/index.tsx
+++ b/src/containers/study/StudyControlPanel/index.tsx
@@ -2,51 +2,78 @@ import { Button, Flex } from '@chakra-ui/react';
import { StudyControlPanelProps } from './types';
-const StudyControlPanel = ({ editModalOpen, terminateModalOpen, deleteModalOpen }: StudyControlPanelProps) => {
+const StudyControlPanel = ({
+ isStudyLeader,
+ isStudyMember,
+ editModalOpen,
+ terminateModalOpen,
+ deleteModalOpen,
+ leaveModalOpen,
+}: StudyControlPanelProps) => {
return (
-
-
-
+ {isStudyLeader && (
+ <>
+
+
+
+ >
+ )}
+ {!isStudyLeader && isStudyMember && (
+
+ )}
);
};
diff --git a/src/containers/study/StudyControlPanel/types.ts b/src/containers/study/StudyControlPanel/types.ts
index d20a1714..f3b6a07f 100644
--- a/src/containers/study/StudyControlPanel/types.ts
+++ b/src/containers/study/StudyControlPanel/types.ts
@@ -1,5 +1,8 @@
export interface StudyControlPanelProps {
+ isStudyLeader: boolean;
+ isStudyMember: boolean;
editModalOpen: React.Dispatch>;
terminateModalOpen: React.Dispatch>;
deleteModalOpen: React.Dispatch>;
+ leaveModalOpen: React.Dispatch>;
}
diff --git a/src/containers/team/DeleteTeamModal/type.ts b/src/containers/team/DeleteTeamModal/type.ts
deleted file mode 100644
index 47cef8fa..00000000
--- a/src/containers/team/DeleteTeamModal/type.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { Team } from '@/types';
-
-export interface DeleteTeamModalProps extends Pick {
- isOpen: boolean;
- onClose: () => void;
-}
diff --git a/src/containers/team/DeleteTeamModal/index.tsx b/src/containers/team/Modal/DeleteTeamModal/index.tsx
similarity index 95%
rename from src/containers/team/DeleteTeamModal/index.tsx
rename to src/containers/team/Modal/DeleteTeamModal/index.tsx
index 046f3116..074e578d 100644
--- a/src/containers/team/DeleteTeamModal/index.tsx
+++ b/src/containers/team/Modal/DeleteTeamModal/index.tsx
@@ -6,7 +6,7 @@ import ConfirmModal from '@/components/Modal/ConfirmModal';
import { useMutateWithToken } from '@/hooks/useFetchWithToken';
import useRefetchSideBar from '@/hooks/useRefetchSideBar';
-import { DeleteTeamModalProps } from './type';
+import { DeleteTeamModalProps } from '../type';
const DeleteTeamModal = ({ id, name, isOpen, onClose }: DeleteTeamModalProps) => {
const deleteTeam = useMutateWithToken(deleteTeamApi);
diff --git a/src/containers/team/Modal/LeaveTeamModal/index.tsx b/src/containers/team/Modal/LeaveTeamModal/index.tsx
new file mode 100644
index 00000000..aad5cc08
--- /dev/null
+++ b/src/containers/team/Modal/LeaveTeamModal/index.tsx
@@ -0,0 +1,41 @@
+import { Text } from '@chakra-ui/react';
+import { useRouter } from 'next/navigation';
+
+import { leaveTeam as leaveTeamApi } from '@/app/api/team';
+import ConfirmModal from '@/components/Modal/ConfirmModal';
+import { useMutateWithToken } from '@/hooks/useFetchWithToken';
+import useRefetchSideBar from '@/hooks/useRefetchSideBar';
+
+import { LeaveTeamModalProps } from '../type';
+
+const LeaveTeamModal = ({ id, name, isOpen, onClose }: LeaveTeamModalProps) => {
+ const leaveTeam = useMutateWithToken(leaveTeamApi);
+ const refetchSidebar = useRefetchSideBar();
+ const router = useRouter();
+
+ const handleLeaveTeamButtonClick = () => {
+ leaveTeam(id).then(() => {
+ refetchSidebar();
+ onClose();
+ router.replace('/');
+ });
+ };
+
+ return (
+ handleLeaveTeamButtonClick()}
+ >
+
+ 팀에서 탈퇴하면 다시 되돌릴 수 없습니다.
+
+ {name} 팀에서 탈퇴하시겠습니까?
+
+
+ );
+};
+
+export default LeaveTeamModal;
diff --git a/src/containers/team/TeamModal/index.tsx b/src/containers/team/Modal/TeamModal/index.tsx
similarity index 99%
rename from src/containers/team/TeamModal/index.tsx
rename to src/containers/team/Modal/TeamModal/index.tsx
index ff48a738..e7a03921 100644
--- a/src/containers/team/TeamModal/index.tsx
+++ b/src/containers/team/Modal/TeamModal/index.tsx
@@ -12,7 +12,7 @@ import { useMutateWithToken } from '@/hooks/useFetchWithToken';
import useRefetchSideBar from '@/hooks/useRefetchSideBar';
import useRefetchTeamInfo from '@/hooks/useRefetchTeamInfo';
-import { TeamModalProps } from './type';
+import { TeamModalProps } from '../type';
const AlertContent = ({ message }: { message: string }) => {
return (
diff --git a/src/containers/team/Modal/type.ts b/src/containers/team/Modal/type.ts
new file mode 100644
index 00000000..94dceb9a
--- /dev/null
+++ b/src/containers/team/Modal/type.ts
@@ -0,0 +1,17 @@
+import { Team } from '@/types';
+
+export interface TeamModalProps {
+ teamInfo?: Team;
+ isOpen: boolean;
+ onClose: () => void;
+}
+
+export interface DeleteTeamModalProps extends Pick {
+ isOpen: boolean;
+ onClose: () => void;
+}
+
+export interface LeaveTeamModalProps extends Pick {
+ isOpen: boolean;
+ onClose: () => void;
+}
diff --git a/src/containers/team/TeamControlPanel/index.tsx b/src/containers/team/TeamControlPanel/index.tsx
index 8cdc4ca5..a48cbcdb 100644
--- a/src/containers/team/TeamControlPanel/index.tsx
+++ b/src/containers/team/TeamControlPanel/index.tsx
@@ -2,43 +2,65 @@ import { Button, Flex } from '@chakra-ui/react';
import { useState } from 'react';
import { TeamControlPanelProps } from './types';
-import DeleteTeamModal from '../DeleteTeamModal';
-import TeamModal from '../TeamModal';
+import DeleteTeamModal from '../Modal/DeleteTeamModal';
+import LeaveTeamModal from '../Modal/LeaveTeamModal';
+import TeamModal from '../Modal/TeamModal';
-const TeamControlPanel = ({ teamInfo }: TeamControlPanelProps) => {
+const TeamControlPanel = ({ isTeamLeader, isMyTeam, teamInfo }: TeamControlPanelProps) => {
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
+ const [isLeaveModalOpen, setIsLeaveModalOpen] = useState(false);
return (
-
-
+ {isTeamLeader && (
+ <>
+
+
+ >
+ )}
+ {!isTeamLeader && isMyTeam && (
+
+ )}
{isEditModalOpen && (
setIsEditModalOpen(false)} />
)}
@@ -50,6 +72,14 @@ const TeamControlPanel = ({ teamInfo }: TeamControlPanelProps) => {
onClose={() => setIsDeleteModalOpen(false)}
/>
)}
+ {isLeaveModalOpen && (
+ setIsLeaveModalOpen(false)}
+ />
+ )}
);
};
diff --git a/src/containers/team/TeamControlPanel/types.ts b/src/containers/team/TeamControlPanel/types.ts
index 13f73659..2bcbdd85 100644
--- a/src/containers/team/TeamControlPanel/types.ts
+++ b/src/containers/team/TeamControlPanel/types.ts
@@ -1,5 +1,7 @@
import { TeamDetail } from '@/types';
export interface TeamControlPanelProps {
+ isTeamLeader: boolean;
+ isMyTeam: boolean;
teamInfo: TeamDetail;
}
diff --git a/src/containers/team/TeamModal/type.ts b/src/containers/team/TeamModal/type.ts
deleted file mode 100644
index 528229eb..00000000
--- a/src/containers/team/TeamModal/type.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { Team } from '@/types';
-
-export interface TeamModalProps {
- teamInfo?: Team;
- isOpen: boolean;
- onClose: () => void;
-}