diff --git a/src/hooks/query/useTeamQuery.ts b/src/hooks/query/useTeamQuery.ts index ed212644..910446c0 100644 --- a/src/hooks/query/useTeamQuery.ts +++ b/src/hooks/query/useTeamQuery.ts @@ -2,7 +2,7 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { getTeamList } from '@services/userService'; import { acceptTeamInvitation, declineTeamInvitation, deleteTeam, leaveTeam } from '@services/teamService'; import type { TeamListWithApproval } from '@/types/TeamType'; -import useToast from '../useToast'; +import useToast from '@/hooks/useToast'; export function useReadTeams() { const { @@ -29,7 +29,7 @@ export function useLeaveTeam() { const { toastSuccess, toastError } = useToast(); return useMutation({ - mutationFn: (teamId: string) => leaveTeam(teamId), + mutationFn: (teamId: number) => leaveTeam(teamId), onSuccess: () => { toastSuccess('팀에서 탈퇴했습니다.'); queryClient.invalidateQueries({ queryKey: ['teams'] }); @@ -45,7 +45,7 @@ export function useDeleteTeam() { const { toastSuccess, toastError } = useToast(); return useMutation({ - mutationFn: async (teamId: string) => { + mutationFn: async (teamId: number) => { const response = await deleteTeam(teamId); return response; @@ -65,10 +65,10 @@ export function useApproveTeamInvitation() { const { toastSuccess, toastError } = useToast(); return useMutation({ - mutationFn: (teamId: string) => acceptTeamInvitation(teamId), + mutationFn: (teamId: number) => acceptTeamInvitation(teamId), onSuccess: () => { toastSuccess('초대를 수락했습니다.'); - queryClient.invalidateQueries({ queryKey: ['teams'] }); // 팀 목록을 다시 불러오기 + queryClient.invalidateQueries({ queryKey: ['teams'] }); }, onError: () => { toastError('초대 수락에 실패했습니다. 다시 시도해 주세요.'); @@ -81,7 +81,7 @@ export function useRejectTeamInvitation() { const { toastSuccess, toastError } = useToast(); return useMutation({ - mutationFn: (teamId: string) => declineTeamInvitation(teamId), + mutationFn: (teamId: number) => declineTeamInvitation(teamId), onSuccess: () => { toastSuccess('초대를 거절했습니다.'); queryClient.invalidateQueries({ queryKey: ['teams'] }); diff --git a/src/mocks/services/teamServiceHandler.ts b/src/mocks/services/teamServiceHandler.ts index ef1652d5..9113368c 100644 --- a/src/mocks/services/teamServiceHandler.ts +++ b/src/mocks/services/teamServiceHandler.ts @@ -1,5 +1,12 @@ import { http, HttpResponse } from 'msw'; -import { TEAM_DUMMY, TEAM_USER_DUMMY } from '../mockData'; +import { + PROJECT_DUMMY, + PROJECT_USER_DUMMY, + STATUS_DUMMY, + TASK_DUMMY, + TEAM_DUMMY, + TEAM_USER_DUMMY, +} from '@/mocks/mockData'; const BASE_URL = import.meta.env.VITE_BASE_URL; // TODO: 실제 userId로 넣어주기 @@ -17,8 +24,7 @@ const teamServiceHandler = [ return HttpResponse.json([]); }), - - // 팀 탈퇴하기 + // 팀 탈퇴 API http.post(`${BASE_URL}/team/:teamId/leave`, ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const { teamId } = params; @@ -32,10 +38,29 @@ const teamServiceHandler = [ TEAM_USER_DUMMY.length = 0; TEAM_USER_DUMMY.push(...filteredTeamUsers); - return new HttpResponse(JSON.stringify({ message: `팀 ${teamId}에서 성공적으로 탈퇴했습니다.` }), { status: 200 }); + const projectIds = PROJECT_DUMMY.filter((project) => project.teamId === Number(teamId)).map( + (project) => project.projectId, + ); + + const filteredProjectUsers = PROJECT_USER_DUMMY.filter( + (projectUser) => !projectIds.includes(projectUser.projectId) || projectUser.userId !== Number(userId), + ); + + PROJECT_USER_DUMMY.length = 0; + PROJECT_USER_DUMMY.push(...filteredProjectUsers); + + const filteredTasks = TASK_DUMMY.map((task) => ({ + ...task, + userId: task.userId.filter((id) => id !== Number(userId)), + })); + + TASK_DUMMY.length = 0; + TASK_DUMMY.push(...filteredTasks); + + return new HttpResponse(null, { status: 204 }); }), - // 팀 삭제하기 + // 팀 삭제 API http.delete(`${BASE_URL}/team/:teamId`, ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const { teamId } = params; @@ -50,10 +75,30 @@ const teamServiceHandler = [ TEAM_USER_DUMMY.length = 0; TEAM_USER_DUMMY.push(...filteredTeamUsers); + const projectIdsToDelete = PROJECT_DUMMY.filter((project) => project.teamId === Number(teamId)).map( + (project) => project.projectId, + ); + + const filteredProjects = PROJECT_DUMMY.filter((project) => !projectIdsToDelete.includes(project.projectId)); + PROJECT_DUMMY.length = 0; + PROJECT_DUMMY.push(...filteredProjects); + + const statusIdsToDelete = STATUS_DUMMY.filter((status) => projectIdsToDelete.includes(status.projectId)).map( + (status) => status.statusId, + ); + + const filteredStatuses = STATUS_DUMMY.filter((status) => !statusIdsToDelete.includes(status.statusId)); + STATUS_DUMMY.length = 0; + STATUS_DUMMY.push(...filteredStatuses); + + const filteredTasks = TASK_DUMMY.filter((task) => !statusIdsToDelete.includes(task.statusId)); + TASK_DUMMY.length = 0; + TASK_DUMMY.push(...filteredTasks); + return new HttpResponse(null, { status: 204 }); }), - // 팀 초대 수락하기 + // 팀 초대 수락 API http.post(`${BASE_URL}/team/:teamId/invitation/accept`, ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const { teamId } = params; @@ -67,10 +112,10 @@ const teamServiceHandler = [ if (teamUser) { teamUser.isPendingApproval = true; } - return new HttpResponse(JSON.stringify({ message: `팀 ${teamId}에 성공적으로 가입했습니다.` }), { status: 200 }); + return new HttpResponse(null, { status: 200 }); }), - // 팀 초대 거절하기 + // 팀 초대 거절 API http.post(`${BASE_URL}/team/:teamId/invitation/decline`, ({ request, params }) => { const accessToken = request.headers.get('Authorization'); const { teamId } = params; @@ -84,7 +129,7 @@ const teamServiceHandler = [ TEAM_USER_DUMMY.length = 0; TEAM_USER_DUMMY.push(...filteredTeamUsers); - return new HttpResponse(JSON.stringify({ message: `팀 ${teamId} 초대를 거절했습니다.` }), { status: 200 }); + return new HttpResponse(null, { status: 200 }); }), ]; diff --git a/src/pages/setting/TeamInvitedPage.tsx b/src/pages/setting/TeamInvitedPage.tsx index 5d02885d..c77e1b73 100644 --- a/src/pages/setting/TeamInvitedPage.tsx +++ b/src/pages/setting/TeamInvitedPage.tsx @@ -31,14 +31,14 @@ export default function InvitedTeamPage() { diff --git a/src/pages/setting/TeamJoinedPage.tsx b/src/pages/setting/TeamJoinedPage.tsx index 9ddfca57..dea21241 100644 --- a/src/pages/setting/TeamJoinedPage.tsx +++ b/src/pages/setting/TeamJoinedPage.tsx @@ -1,6 +1,5 @@ import Spinner from '@components/common/Spinner'; import { useDeleteTeam, useLeaveTeam, useReadTeams } from '@hooks/query/useTeamQuery'; -import { deleteTeam } from '@services/teamService'; export default function JoinedTeamPage() { const { joinedTeamList, isLoading } = useReadTeams(); @@ -31,12 +30,11 @@ export default function JoinedTeamPage() {
- {/* TODO: 삭제하기 (creatorId와 로그인한 유저 아이디와 동일시에만 보임) */} {team.creatorId === userId && ( @@ -44,7 +42,7 @@ export default function JoinedTeamPage() { diff --git a/src/services/teamService.ts b/src/services/teamService.ts index 4ff2b0a1..69c50cc6 100644 --- a/src/services/teamService.ts +++ b/src/services/teamService.ts @@ -22,41 +22,41 @@ async function findUserByTeam( } /** - * 팀에서 탈퇴하기 - * @param {string} teamId - 팀 아이디 + * 팀 탈퇴 API + * @param {number} teamId - 팀 아이디 * @param {AxiosRequestConfig} [axiosConfig={}] - axios 요청 옵션 설정 객체 - * @returns {Promise} + * @returns {Promise>} */ -export async function leaveTeam(teamId: string, axiosConfig: AxiosRequestConfig = {}) { +export async function leaveTeam(teamId: number, axiosConfig: AxiosRequestConfig = {}) { return authAxios.post(`/team/${teamId}/leave`, {}, axiosConfig); } /** - * 팀 삭제하기 - * @param {string} teamId - 팀 아이디 + * 팀 삭제 API + * @param {number} teamId - 팀 아이디 * @param {AxiosRequestConfig} [axiosConfig={}] - axios 요청 옵션 설정 객체 - * @returns {Promise} + * @returns {Promise>} */ -export async function deleteTeam(teamId: string, axiosConfig: AxiosRequestConfig = {}) { +export async function deleteTeam(teamId: number, axiosConfig: AxiosRequestConfig = {}) { return authAxios.delete(`/team/${teamId}`, axiosConfig); } /** - * 팀 초대 수락하기 - * @param {string} teamId - 팀 아이디 + * 팀 초대 수락 API + * @param {number} teamId - 팀 아이디 * @param {AxiosRequestConfig} [axiosConfig={}] - axios 요청 옵션 설정 객체 - * @returns {Promise} + * @returns {Promise>} */ -export async function acceptTeamInvitation(teamId: string, axiosConfig: AxiosRequestConfig = {}) { +export async function acceptTeamInvitation(teamId: number, axiosConfig: AxiosRequestConfig = {}) { return authAxios.post(`/team/${teamId}/invitation/accept`, {}, axiosConfig); } /** - * 팀 초대 거절하기 - * @param {string} teamId - 팀 아이디 + * 팀 초대 거절 API + * @param {number} teamId - 팀 아이디 * @param {AxiosRequestConfig} [axiosConfig={}] - axios 요청 옵션 설정 객체 - * @returns {Promise} + * @returns {Promise>} */ -export async function declineTeamInvitation(teamId: string, axiosConfig: AxiosRequestConfig = {}) { +export async function declineTeamInvitation(teamId: number, axiosConfig: AxiosRequestConfig = {}) { return authAxios.post(`/team/${teamId}/invitation/decline`, {}, axiosConfig); } diff --git a/src/types/TeamType.tsx b/src/types/TeamType.tsx index 80f2a8c8..64a5d69c 100644 --- a/src/types/TeamType.tsx +++ b/src/types/TeamType.tsx @@ -12,5 +12,5 @@ export type TeamListWithApproval = Omit & Pick & { isPendingApproval: boolean; creator: string; - creatorId: number; // 추가된 필드 + creatorId: number; };