From 2281c2a437a09753ac550ea9f25d3c5da0ffc5fd Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Tue, 11 Mar 2025 14:00:56 +0900 Subject: [PATCH 01/30] =?UTF-8?q?chore(DEVING-74):=20meetings.ts=20url=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20packeage.json=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 ++- src/service/api/meeting.ts | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index bd5c20be..9de0826c 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,8 @@ "version": "0.1.0", "private": true, "scripts": { - "dev": "node server.js", + "https:dev": "node server.js", + "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint", diff --git a/src/service/api/meeting.ts b/src/service/api/meeting.ts index 34cff72f..5a9a40b8 100644 --- a/src/service/api/meeting.ts +++ b/src/service/api/meeting.ts @@ -9,12 +9,14 @@ import type { TopMeeting, } from 'types/meeting'; +import { likesURL, meetingURL, memberURL, myMeetingURL } from './endpoints'; + const getTopMeetings = async ( categoryTitle: CategoryTitle, ): Promise => { const token = await getAccessToken(); - const res = await (token ? authAPI : basicAPI).get(`/api/v1/meetings/top`, { + const res = await (token ? authAPI : basicAPI).get(meetingURL.top, { params: { categoryTitle }, }); @@ -30,7 +32,7 @@ const getMeetings = async ( const token = await getAccessToken(); const res = await (token ? authAPI : basicAPI).post( - `/api/v1/meetings/search?categoryTitle=${category}`, + `${meetingURL.search}?categoryTitle=${category}`, newSearchQueryObj, ); @@ -38,13 +40,13 @@ const getMeetings = async ( }; const likeMeeting = async (meetingId: number) => { - const res = await authAPI.post(`/api/v1/meetings/${meetingId}/likes`); + const res = await authAPI.post(likesURL.create(meetingId)); return res.data.data; }; const cancelLikeMeeting = async (meetingId: number) => { - const res = await authAPI.delete(`/api/v1/meetings/${meetingId}/likes`); + const res = await authAPI.delete(likesURL.delete(meetingId)); return res.data.data; }; @@ -74,12 +76,12 @@ export interface MeetingManager { } const getMeetingDetail = async (id: number): Promise => { - const res = await authAPI.get(`/api/v1/meetings/detail/${id}`); + const res = await authAPI.get(meetingURL.detail(id)); return res.data.data; }; const getMeetingDetailManager = async (id: number): Promise => { - const res = await basicAPI.get(`/api/v1/meetings/detail/manager/${id}`); + const res = await basicAPI.get(meetingURL.managerDetail(id)); return res.data.data; }; @@ -91,13 +93,13 @@ const postMeetingRegister = async ({ meetingId: number; message: string; }) => { - const res = await authAPI.post(`/api/v1/members/${meetingId}`, { message }); + const res = await authAPI.post(memberURL.create(meetingId), { message }); return res.data.data; }; // Approve 상태에서 모임 탈퇴 const deleteMeetingQuit = async (meetingId: number) => { - const res = await authAPI.delete(`/api/v1/mymeetings/quit/${meetingId}`); + const res = await authAPI.delete(myMeetingURL.quit(meetingId)); return res.data.data; }; From 7ab51122f1cc66e8fd9030d2015e35aa5c8a9498 Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Tue, 11 Mar 2025 22:04:14 +0900 Subject: [PATCH 02/30] =?UTF-8?q?feat(DEVING-74):=20myMeeting.ts=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/types/myMeeting.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/types/myMeeting.ts b/src/types/myMeeting.ts index 8dece93c..d8271d8a 100644 --- a/src/types/myMeeting.ts +++ b/src/types/myMeeting.ts @@ -1,3 +1,4 @@ +import { CategoryTitle } from './meeting'; import { IContactResponse } from './mypageTypes'; interface Member { @@ -30,6 +31,29 @@ interface IMyMeetingManage { memberList: Member[]; } +interface IMyMeetingAll { + meetingId: number; + title: string; + thumbnail: string; + location: string; + memberCount: number; + maxMember: number; + likesCount: number; + myMemberStatus: 'APPROVED' | 'REJECTED' | 'PENDING' | 'EXPEL'; + memberList: Member[]; +} + +interface IMyMeetingLikes { + meetingId: number; + categoryTitle: CategoryTitle; + title: string; + thumbnail: string; + location: string; + memberCount: number; + maxMember: number; + likesCount: number; +} + interface IUserProfile { userId: number; name: string; @@ -75,4 +99,6 @@ export type { IMemberProfile, IBanner, UserData, + IMyMeetingAll, + IMyMeetingLikes, }; From c05a1c0c5c7fb085521096b49e149cc2ae31020b Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Tue, 11 Mar 2025 22:06:13 +0900 Subject: [PATCH 03/30] =?UTF-8?q?feat(DEVING-74):=20myMeetingLikes=20API?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/service/api/mymeeting.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/service/api/mymeeting.ts b/src/service/api/mymeeting.ts index 3b9e6b90..c00fae0f 100644 --- a/src/service/api/mymeeting.ts +++ b/src/service/api/mymeeting.ts @@ -1,6 +1,7 @@ import { authAPI } from '@/lib/axios/authApi'; import { Paginated } from 'types/meeting'; import type { IMemberProfile, IMyMeetingManage } from 'types/myMeeting'; +import { IMyMeetingLikes } from 'types/myMeeting'; import { myMeetingURL } from './endpoints'; @@ -15,7 +16,7 @@ const getMyMeetingManage = async ( return res.data.data; }; -// 내가 참여하고있는 모임 불러오기기 +// 내가 참여하고있는 모임 불러오기 const getMyMeetingParticipated = async ( lastMeetingId: number, ): Promise> => { @@ -26,6 +27,17 @@ const getMyMeetingParticipated = async ( return res.data.data; }; +// 내가 찜한 모임 불러오기 +const getMyMeetingLikes = async ( + lastMeetingId: number, +): Promise> => { + const res = await authAPI.get( + `${myMeetingURL.likes}?lastMeetingId=${lastMeetingId}&size=${6}`, + ); + + return res.data.data; +}; + // 맴버 프로필 불러오기 const getMyMeetingMemberProfile = async ({ userId, @@ -89,6 +101,7 @@ export { getMyMeetingManage, getMyMeetingMemberProfile, getMyMeetingParticipated, + getMyMeetingLikes, putMemberStatus, putExpel, putIsPublic, From e36cfebc389591d2916075e83da95b089c43555b Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Tue, 11 Mar 2025 22:07:08 +0900 Subject: [PATCH 04/30] =?UTF-8?q?feat(DEVING-74):=20likes=EB=AF=B8?= =?UTF-8?q?=ED=8C=85=20=EC=9D=B8=ED=94=BC=EB=8B=88=ED=8B=B0=EC=BF=BC?= =?UTF-8?q?=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/queries/useMyMeetingQueries.ts | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/hooks/queries/useMyMeetingQueries.ts b/src/hooks/queries/useMyMeetingQueries.ts index 4fed671a..e8fa8fbb 100644 --- a/src/hooks/queries/useMyMeetingQueries.ts +++ b/src/hooks/queries/useMyMeetingQueries.ts @@ -3,14 +3,18 @@ import { getMyMeetingManage, getMyMeetingMemberProfile, } from 'service/api/mymeeting'; -import { getMyMeetingParticipated } from 'service/api/mymeeting'; +import { + getMyMeetingLikes, + getMyMeetingParticipated, +} from 'service/api/mymeeting'; import { Paginated } from 'types/meeting'; -import { IMyMeetingManage } from 'types/myMeeting'; +import { IMyMeetingLikes, IMyMeetingManage } from 'types/myMeeting'; export const myMeetingKeys = { all: ['mymeeting'] as const, manage: () => [...myMeetingKeys.all, 'manage'] as const, participated: () => [...myMeetingKeys.all, 'participated'] as const, + likes: () => [...myMeetingKeys.all, 'likes'] as const, memberProfile: (meetingId: number, userId: number) => [ ...myMeetingKeys.all, 'profile', @@ -18,6 +22,7 @@ export const myMeetingKeys = { ], }; +// 내가 생성한 모임 export const useInfiniteMyMeetingManageQueries = () => { return useInfiniteQuery({ queryKey: myMeetingKeys.manage(), @@ -29,6 +34,7 @@ export const useInfiniteMyMeetingManageQueries = () => { }); }; +// 내가 참여하고 있는 모임 export const useInfiniteMyMeetingParticipatedQueries = () => { return useInfiniteQuery({ queryKey: myMeetingKeys.participated(), @@ -40,6 +46,18 @@ export const useInfiniteMyMeetingParticipatedQueries = () => { }); }; +// 내가 찜한 모임 +export const useInfiniteMyMeetingLikesQueries = () => { + return useInfiniteQuery({ + queryKey: myMeetingKeys.likes(), + queryFn: ({ pageParam }) => getMyMeetingLikes(pageParam), + initialPageParam: 0, + getNextPageParam: (lastPage: Paginated) => { + return lastPage.nextCursor ?? null; + }, + }); +}; + // 특정 유저의 프로필 요청 export const useMyMeetingMemberProfileQuries = ({ meetingId, From 87dfd0a35591c741b70d56831db53eceb47bc0ef Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Tue, 11 Mar 2025 22:28:05 +0900 Subject: [PATCH 05/30] =?UTF-8?q?feat(DEVING-74):=20=EC=9E=84=EC=8B=9C=20N?= =?UTF-8?q?ameToEng=20=EC=9C=A0=ED=8B=B8=ED=95=A8=EC=88=98=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EC=B6=94=ED=9B=84=20=ED=86=B5=ED=95=A9=EC=98=88?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/util/CategoryNameToEng.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/util/CategoryNameToEng.ts diff --git a/src/util/CategoryNameToEng.ts b/src/util/CategoryNameToEng.ts new file mode 100644 index 00000000..7bfae340 --- /dev/null +++ b/src/util/CategoryNameToEng.ts @@ -0,0 +1,14 @@ +export const translateCategoryNameToEng = (category: string) => { + switch (category) { + case '모각코': + return 'mogakco'; + case '취미': + return 'hobby'; + case '스터디': + return 'study'; + case '사이드 프로젝트': + return 'side-project'; + default: + return 'mogakco'; + } +}; From 886c37a36ae4e86f197b6ecb1fbc4cd07140f498 Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Tue, 11 Mar 2025 22:29:35 +0900 Subject: [PATCH 06/30] =?UTF-8?q?feat(DEVING-74):=20=EC=B0=9C=ED=95=9C?= =?UTF-8?q?=EB=AA=A8=EC=9E=84=20=EC=84=9C=EB=B2=84=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(user-page)/my-meeting/likes/page.tsx | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/app/(user-page)/my-meeting/likes/page.tsx b/src/app/(user-page)/my-meeting/likes/page.tsx index 3ae9476e..efbfdbd8 100644 --- a/src/app/(user-page)/my-meeting/likes/page.tsx +++ b/src/app/(user-page)/my-meeting/likes/page.tsx @@ -1,5 +1,30 @@ -import NotYet from '@/components/common/NotYet'; +import { myMeetingKeys } from '@/hooks/queries/useMyMeetingQueries'; +import { + HydrationBoundary, + QueryClient, + dehydrate, +} from '@tanstack/react-query'; +import { getMyMeetingLikes } from 'service/api/mymeeting'; +import { Paginated } from 'types/meeting'; +import { IMyMeetingLikes } from 'types/myMeeting'; -export default function LikesPage() { - return ; +import Likes from '../_features/Likes'; + +export default async function LikesPage() { + const queryClient = new QueryClient(); + + await queryClient.prefetchInfiniteQuery({ + queryKey: myMeetingKeys.likes(), + queryFn: ({ pageParam }) => getMyMeetingLikes(pageParam), + getNextPageParam: (lastPage: Paginated) => + lastPage.nextCursor ?? false, + initialPageParam: 0, + }); + return ( +
+ + + +
+ ); } From e1958eeda926293d0b9b11598009fe0740fe9289 Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Tue, 11 Mar 2025 22:51:46 +0900 Subject: [PATCH 07/30] =?UTF-8?q?feat(DEVING-74):=20=EC=B0=9C=ED=95=9C?= =?UTF-8?q?=EB=AA=A8=EC=9E=84=20=ED=81=B4=EB=9D=BC=EC=9D=B4=EC=96=B8?= =?UTF-8?q?=ED=8A=B8=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../my-meeting/_features/Likes.tsx | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 src/app/(user-page)/my-meeting/_features/Likes.tsx diff --git a/src/app/(user-page)/my-meeting/_features/Likes.tsx b/src/app/(user-page)/my-meeting/_features/Likes.tsx new file mode 100644 index 00000000..6a458203 --- /dev/null +++ b/src/app/(user-page)/my-meeting/_features/Likes.tsx @@ -0,0 +1,148 @@ +'use client'; + +import HorizonCard from '@/components/ui/HorizonCard'; +import useInfiniteScroll from '@/hooks/common/useInfiniteScroll'; +import { useInfiniteMyMeetingLikesQueries } from '@/hooks/queries/useMyMeetingQueries'; +import { translateCategoryNameToEng } from '@/util/CategoryNameToEng'; +import { useRouter } from 'next/navigation'; +import React from 'react'; + +import MeetingListSkeleton from './skeletons/SkeletonMeetingList'; + +const Likes = () => { + const router = useRouter(); + + const { + data: meetingData, + fetchNextPage, + hasNextPage, + isFetchingNextPage, + isLoading, + } = useInfiniteMyMeetingLikesQueries(); + + const lastMeetingRef = useInfiniteScroll({ + fetchNextPage, + isFetchingNextPage, + hasNextPage: !!hasNextPage, + }); + + if (isLoading || !meetingData) { + return ; + } + + return ( +
+ {meetingData.pages.map((page, pageIdx) => ( +
+ {page.content.map((meeting) => ( +
+ {/* 데스크탑 */} +
+ + router.push( + `/meeting/${translateCategoryNameToEng(meeting.categoryTitle)}/${meeting.meetingId}`, + ) + } + key={meeting.meetingId} + title={meeting.title} + thumbnailUrl={meeting.thumbnail} + location={meeting.location} + total={meeting.maxMember} + value={meeting.memberCount} + className="flex-row" + meetingId={meeting.meetingId} + category={translateCategoryNameToEng(meeting.categoryTitle)} + isLike={true} + likesCount={meeting.likesCount} + > +
+ + {/* 태블릿 */} +
+ + router.push( + `/meeting/${translateCategoryNameToEng(meeting.categoryTitle)}/${meeting.meetingId}`, + ) + } + key={meeting.meetingId} + title={meeting.title} + thumbnailUrl={meeting.thumbnail} + location={meeting.location} + total={meeting.maxMember} + value={meeting.memberCount} + thumbnailHeight={160} + thumbnailWidth={160} + className="" + meetingId={meeting.meetingId} + category={translateCategoryNameToEng(meeting.categoryTitle)} + isLike={true} + likesCount={meeting.likesCount} + /> +
+ + {/* 모바일 */} +
+ + router.push( + `/meeting/${translateCategoryNameToEng(meeting.categoryTitle)}/${meeting.meetingId}`, + ) + } + key={meeting.meetingId} + title={meeting.title} + thumbnailUrl={meeting.thumbnail} + location={meeting.location} + total={meeting.maxMember} + value={meeting.memberCount} + thumbnailHeight={80} + thumbnailWidth={80} + className="" + meetingId={meeting.meetingId} + category={translateCategoryNameToEng(meeting.categoryTitle)} + isLike={true} + likesCount={meeting.likesCount} + /> +
+
+ ))} +
+ ))} + + {/* 무한 스크롤을 위한 별도의 Observer 요소 */} + {hasNextPage && ( +
+ )} + + {/* 추가 데이터 로딩 중 표시 */} + {isFetchingNextPage && ( +
+
+ 로딩 중... +
+
+ )} + + {/* 데이터가 없는 경우 표시 */} + {meetingData.pages[0].content.length === 0 && ( +
+ 찜한 모임이 없습니다. +
+ )} + + {/* 더 이상 데이터가 없음을 표시 */} + {!hasNextPage && meetingData.pages[0].content.length > 0 && ( +
+ 모든 모임을 불러왔습니다. +
+ )} +
+ ); +}; + +export default Likes; From 01cf60bb5f0ff65b927a3ff86afcaa380e92e3ef Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Tue, 11 Mar 2025 22:52:57 +0900 Subject: [PATCH 08/30] =?UTF-8?q?chore(DEVING-74):=20server.js=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20commonJS=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/server.js b/server.js index b108c548..2a5c4503 100644 --- a/server.js +++ b/server.js @@ -1,15 +1,15 @@ -import { readFileSync } from 'fs'; -import { createServer } from 'https'; -import next from 'next'; -import { parse } from 'url'; +const { createServer } = require('https'); +const { parse } = require('url'); +const next = require('next'); +const fs = require('fs'); const dev = process.env.NODE_ENV !== 'production'; const app = next({ dev }); const handle = app.getRequestHandler(); const httpsOptions = { - key: readFileSync('./localhost-key.pem'), - cert: readFileSync('./localhost.pem'), + key: fs.readFileSync('./localhost-key.pem'), + cert: fs.readFileSync('./localhost.pem'), }; app.prepare().then(() => { From b466ee2885ed939b004e244c063689175c6fe470 Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Wed, 12 Mar 2025 23:03:27 +0900 Subject: [PATCH 09/30] =?UTF-8?q?chore(DEVING-79):=20=EA=B8=B0=EC=A1=B4=20?= =?UTF-8?q?join=EB=8D=94=EB=AF=B8=20=ED=8C=8C=EC=9D=BC=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../my-meeting/_features/Joined.tsx | 191 ------------------ 1 file changed, 191 deletions(-) delete mode 100644 src/app/(user-page)/my-meeting/_features/Joined.tsx diff --git a/src/app/(user-page)/my-meeting/_features/Joined.tsx b/src/app/(user-page)/my-meeting/_features/Joined.tsx deleted file mode 100644 index dad6ab0c..00000000 --- a/src/app/(user-page)/my-meeting/_features/Joined.tsx +++ /dev/null @@ -1,191 +0,0 @@ -// 'use client'; - -// import Dropdown from '@/components/common/Dropdown'; -// import { Button } from '@/components/ui/Button'; -// import HorizonCard from '@/components/ui/HorizonCard'; -// import { Tag } from '@/components/ui/Tag'; -// import Modal from '@/components/ui/modal/Modal'; -// import Image from 'next/image'; -// import { useState } from 'react'; - -// import { Meeting, Member } from '../my-meeting/my/page'; -// import ModalProfile from './ModalProfile'; -// import ModalUserList from './ModalUserList'; - -// const CardRightSection = ({ -// memberList, -// isPublic, -// className, -// }: { -// memberList: Member[]; -// isPublic: boolean; -// className?: string; -// }) => { -// const [selectedFilter, setSelectedFilter] = useState( -// isPublic ? '공개' : '비공개', -// ); -// const [isUserListModalOpen, setIsUserListModalOpen] = useState(false); -// const handleConfirm = () => { -// setIsUserListModalOpen(false); -// }; -// const filterAreaOptions = [ -// { value: 'true', label: '공개' }, -// { value: 'false', label: '비공개' }, -// ]; - -// const [isUserProfileModalOpen, setIsUserProfileModalOpen] = useState(false); - -// const handleSecondModalConfirm = () => { -// // 가입 확인 api 연동 -// setIsUserProfileModalOpen(false); -// }; - -// const handleSecondModalCancel = () => { -// // 가입 거절 api 연동 -// setIsUserProfileModalOpen(false); -// }; -// return ( -//
-//
-//

참가 중인 멤버

-//
-// {memberList.map((member: Member) => ( -//
-// 맴버 프로필 -//

-// {member.name} -//

-//
-// -// -//
-//
-// ))} -//
-//
-// -//
-// -//
-// -// -// -// setIsUserListModalOpen(false)} -// onConfirm={handleConfirm} -// showOnly -// modalClassName="h-[590px] w-[520px] overflow-y-auto" -// > -// -// -//
-// ); -// }; - -// const Joined = ({ meetings }: { meetings: Meeting[] }) => { -// return ( -//
-// {meetings.map((meeting) => { -// return ( -//
-// {/* 데스크탑 */} -//
-// -// -// -//
- -// {/* 태블릿 */} -//
-// -// -//
- -// {/* 모바일 */} -//
-// -// -//
-//
-// ); -// })} -//
-// ); -// }; -// export default Joined; From 7a39443957fe134447766606fdf62208214eb4ff Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Wed, 12 Mar 2025 23:21:39 +0900 Subject: [PATCH 10/30] =?UTF-8?q?chore(DEVING-79):=20=EB=82=B4=EA=B0=80=20?= =?UTF-8?q?=EC=B0=B8=EC=97=AC=ED=95=98=EA=B3=A0=EC=9E=88=EB=8A=94=20?= =?UTF-8?q?=EB=AA=A8=EC=9E=84=EB=B3=80=EC=88=98=EB=AA=85=20join=20?= =?UTF-8?q?=EB=B0=8F=20all=20=EB=AA=85=EC=B9=AD=20=EC=A0=84=EB=B6=80=20par?= =?UTF-8?q?ticipated=EB=A1=9C=20=EA=B5=90=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../(user-page)/my-meeting/_features/CardRightSection.tsx | 6 +++--- src/app/(user-page)/my-meeting/_features/Tab.tsx | 2 +- src/app/(user-page)/my-meeting/my/page.tsx | 4 ++-- src/hooks/queries/useMyMeetingQueries.ts | 8 ++++++-- src/hooks/useCard.tsx | 4 ++-- src/service/api/mymeeting.ts | 6 +++--- src/types/myMeeting.ts | 4 ++-- 7 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/app/(user-page)/my-meeting/_features/CardRightSection.tsx b/src/app/(user-page)/my-meeting/_features/CardRightSection.tsx index 2efa077b..78f1a14f 100644 --- a/src/app/(user-page)/my-meeting/_features/CardRightSection.tsx +++ b/src/app/(user-page)/my-meeting/_features/CardRightSection.tsx @@ -20,7 +20,7 @@ const CardRightSection = ({ showPublicSelect = false, }: { memberList: Member[]; - isPublic: boolean; + isPublic?: boolean; className?: string; meetingId: number; showPublicSelect?: boolean; @@ -61,7 +61,7 @@ const CardRightSection = ({ memberList, ); router.push( - `/my-meeting/my/user-list?meetingId=${meetingId}&type=${showPublicSelect ? 'created' : 'joined'}`, + `/my-meeting/my/user-list?meetingId=${meetingId}&type=${showPublicSelect ? 'created' : 'participated'}`, ); }; @@ -129,7 +129,7 @@ const CardRightSection = ({ 맴버 명단 보기 {showPublicSelect && ( - + )}
// diff --git a/src/app/(user-page)/my-meeting/_features/Tab.tsx b/src/app/(user-page)/my-meeting/_features/Tab.tsx index 9dcf139e..15b4ad87 100644 --- a/src/app/(user-page)/my-meeting/_features/Tab.tsx +++ b/src/app/(user-page)/my-meeting/_features/Tab.tsx @@ -5,7 +5,7 @@ import { useRouter } from 'next/navigation'; const tabList = [ { label: '내가 만든 모임', value: 'created' }, - { label: '내가 참여하고 있는 모임', value: 'joined' }, + { label: '내가 참여하고 있는 모임', value: 'participated' }, ]; const Tab = ({ type }: { type: string }) => { diff --git a/src/app/(user-page)/my-meeting/my/page.tsx b/src/app/(user-page)/my-meeting/my/page.tsx index f3635150..43a2b611 100644 --- a/src/app/(user-page)/my-meeting/my/page.tsx +++ b/src/app/(user-page)/my-meeting/my/page.tsx @@ -12,7 +12,7 @@ import { } from 'service/api/mymeeting'; import { getBanner } from 'service/api/mypageProfile'; import { Paginated } from 'types/meeting'; -import { IMyMeetingManage } from 'types/myMeeting'; +import { IMyMeetingManage, IMyMeetingParticipated } from 'types/myMeeting'; import Created from '../_features/Created'; import Participated from '../_features/Participated'; @@ -47,7 +47,7 @@ export default async function Page({ await queryClient.prefetchInfiniteQuery({ queryKey: myMeetingKeys.participated(), queryFn: ({ pageParam }) => getMyMeetingParticipated(pageParam), - getNextPageParam: (lastPage: Paginated) => + getNextPageParam: (lastPage: Paginated) => lastPage.nextCursor ?? false, initialPageParam: 0, }); diff --git a/src/hooks/queries/useMyMeetingQueries.ts b/src/hooks/queries/useMyMeetingQueries.ts index e8fa8fbb..f1dabf15 100644 --- a/src/hooks/queries/useMyMeetingQueries.ts +++ b/src/hooks/queries/useMyMeetingQueries.ts @@ -8,7 +8,11 @@ import { getMyMeetingParticipated, } from 'service/api/mymeeting'; import { Paginated } from 'types/meeting'; -import { IMyMeetingLikes, IMyMeetingManage } from 'types/myMeeting'; +import { + IMyMeetingLikes, + IMyMeetingManage, + IMyMeetingParticipated, +} from 'types/myMeeting'; export const myMeetingKeys = { all: ['mymeeting'] as const, @@ -40,7 +44,7 @@ export const useInfiniteMyMeetingParticipatedQueries = () => { queryKey: myMeetingKeys.participated(), queryFn: ({ pageParam }) => getMyMeetingParticipated(pageParam), initialPageParam: 0, - getNextPageParam: (lastPage: Paginated) => { + getNextPageParam: (lastPage: Paginated) => { return lastPage.nextCursor ?? null; }, }); diff --git a/src/hooks/useCard.tsx b/src/hooks/useCard.tsx index 62402248..3bc1506c 100644 --- a/src/hooks/useCard.tsx +++ b/src/hooks/useCard.tsx @@ -121,11 +121,11 @@ const useCard = (meeting: MeetingDetail) => { setMent(''); break; case 'registerWait': - router.push('/my-meeting/my?type=joined'); + router.push('/my-meeting/my?type=participated'); setIsModalOpen(false); break; case 'registerComplete': - router.push('/my-meeting/my?type=joined'); + router.push('/my-meeting/my?type=participated'); setIsModalOpen(false); break; default: diff --git a/src/service/api/mymeeting.ts b/src/service/api/mymeeting.ts index 8a25d391..8ed0bbd3 100644 --- a/src/service/api/mymeeting.ts +++ b/src/service/api/mymeeting.ts @@ -1,7 +1,7 @@ import axiosInstance from '@/lib/axios/axiosInstance'; import { Paginated } from 'types/meeting'; import type { IMemberProfile, IMyMeetingManage } from 'types/myMeeting'; -import { IMyMeetingLikes } from 'types/myMeeting'; +import { IMyMeetingLikes, IMyMeetingParticipated } from 'types/myMeeting'; import { myMeetingURL } from './endpoints'; @@ -19,7 +19,7 @@ const getMyMeetingManage = async ( // 내가 참여하고있는 모임 불러오기 const getMyMeetingParticipated = async ( lastMeetingId: number, -): Promise> => { +): Promise> => { const res = await axiosInstance.get( `${myMeetingURL.all}?lastMeetingId=${lastMeetingId}&size=${6}`, ); @@ -31,7 +31,7 @@ const getMyMeetingParticipated = async ( const getMyMeetingLikes = async ( lastMeetingId: number, ): Promise> => { - const res = await authAPI.get( + const res = await axiosInstance.get( `${myMeetingURL.likes}?lastMeetingId=${lastMeetingId}&size=${6}`, ); diff --git a/src/types/myMeeting.ts b/src/types/myMeeting.ts index d8271d8a..0edf2483 100644 --- a/src/types/myMeeting.ts +++ b/src/types/myMeeting.ts @@ -31,7 +31,7 @@ interface IMyMeetingManage { memberList: Member[]; } -interface IMyMeetingAll { +interface IMyMeetingParticipated { meetingId: number; title: string; thumbnail: string; @@ -99,6 +99,6 @@ export type { IMemberProfile, IBanner, UserData, - IMyMeetingAll, + IMyMeetingParticipated, IMyMeetingLikes, }; From 9ebe7f08ce7a8e691ecc5ef2db23d6e95fe60145 Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Thu, 13 Mar 2025 15:39:15 +0900 Subject: [PATCH 11/30] =?UTF-8?q?chore(DEVING-79):=20=EC=B0=B8=EC=97=AC?= =?UTF-8?q?=EC=A4=91=EC=9D=B8=20=EB=AA=A8=EC=9E=84=EC=97=90=20=EC=B9=B4?= =?UTF-8?q?=ED=85=8C=EA=B3=A0=EB=A6=AC=ED=83=80=EC=9D=B4=ED=8B=80=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/types/myMeeting.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/types/myMeeting.ts b/src/types/myMeeting.ts index 0edf2483..c8721588 100644 --- a/src/types/myMeeting.ts +++ b/src/types/myMeeting.ts @@ -32,6 +32,7 @@ interface IMyMeetingManage { } interface IMyMeetingParticipated { + categoryTitle: CategoryTitle; meetingId: number; title: string; thumbnail: string; From a343f347d7db4e7745d0bbe08dc2064e9cdb3eb4 Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Thu, 13 Mar 2025 15:46:48 +0900 Subject: [PATCH 12/30] =?UTF-8?q?style(DEVING-79):=20=EA=B1=B0=EC=A0=88=20?= =?UTF-8?q?=EB=B0=8F=20=EA=B0=95=ED=87=B4=EC=8B=9C,=20=EC=B9=B4=EB=93=9C?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EB=A0=88=EC=9D=B4=EC=95=84?= =?UTF-8?q?=EC=9B=83=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../my-meeting/_features/Participated.tsx | 124 +++++++++++++----- 1 file changed, 93 insertions(+), 31 deletions(-) diff --git a/src/app/(user-page)/my-meeting/_features/Participated.tsx b/src/app/(user-page)/my-meeting/_features/Participated.tsx index 803b6d0b..116a3bf9 100644 --- a/src/app/(user-page)/my-meeting/_features/Participated.tsx +++ b/src/app/(user-page)/my-meeting/_features/Participated.tsx @@ -3,11 +3,18 @@ import HorizonCard from '@/components/ui/HorizonCard'; import useInfiniteScroll from '@/hooks/common/useInfiniteScroll'; import { useInfiniteMyMeetingParticipatedQueries } from '@/hooks/queries/useMyMeetingQueries'; +import { translateCategoryNameToEng } from '@/util/searchFilter'; +import Link from 'next/link'; import { useRouter } from 'next/navigation'; +import { IMyMeetingParticipated } from 'types/myMeeting'; import CardRightSection from './CardRightSection'; import MeetingListSkeleton from './skeletons/SkeletonMeetingList'; +interface IStatusOverlay { + meeting: IMyMeetingParticipated; +} + const Participated = () => { const router = useRouter(); @@ -32,15 +39,50 @@ const Participated = () => { return ; } - // 상세 페이지로 이동하는 핸들러 - const handleMoveDetailPage = (meetingId: number) => { - /** - * TODO - * 추후 category 수정 - */ - router.push(`/meeting/study/${meetingId}`); + // 클릭 불가능한 상태인지 확인하는 함수 (오버레이 표시 여부만 결정) + + const isDisabledStatus = ( + status: IMyMeetingParticipated['myMemberStatus'], + ): boolean => { + return status === 'REJECTED' || status === 'EXPEL'; + }; + + // 카드 클릭 핸들러 - 모든 상태에서 라우팅 가능하도록 변경 + const handleCardClick = (meeting: IMyMeetingParticipated) => { + router.push( + `/meeting/${translateCategoryNameToEng(meeting.categoryTitle)}/${meeting.meetingId}`, + ); }; + // 모임 상세 페이지 URL 생성 함수 + const getMeetingDetailUrl = (meeting: IMyMeetingParticipated) => + `/meeting/${translateCategoryNameToEng(meeting.categoryTitle)}/${meeting.meetingId}`; + + // 오버레이 컴포넌트 (수정된 버전) + const StatusOverlay = ({ meeting }: IStatusOverlay) => ( +
+
+ {meeting.myMemberStatus === 'REJECTED' ? ( +

+ 죄송합니다. 가입이 거절된 + 모임입니다. +

+ ) : ( +

+ 더 이상 참여가 불가능한 + 모임입니다. +

+ )} + + 상세페이지 보기 + +
+
+ ); + return (
{meetingData.pages.map((page, pageIdx) => ( @@ -49,31 +91,43 @@ const Participated = () => {
{/* 데스크탑 */}
- handleMoveDetailPage(meeting.meetingId)} - key={meeting.meetingId} - title={meeting.title} - thumbnailUrl={meeting.thumbnail} - location={meeting.location} - total={meeting.maxMember} - value={meeting.memberCount} - className="flex-row" - meetingId={meeting.meetingId} - category={''} - > - + handleCardClick(meeting)} + key={meeting.meetingId} + title={meeting.title} + thumbnailUrl={meeting.thumbnail} + location={meeting.location} + total={meeting.maxMember} + value={meeting.memberCount} + className="flex-row" meetingId={meeting.meetingId} - /> - + category={''} + > +
+ + + +
+
+ + {/* 비활성화된 상태일 때 오버레이 */} + {isDisabledStatus(meeting.myMemberStatus) && ( + + )} +
{/* 태블릿 */} -
+
handleMoveDetailPage(meeting.meetingId)} + onClick={() => handleCardClick(meeting)} key={meeting.meetingId} title={meeting.title} thumbnailUrl={meeting.thumbnail} @@ -88,16 +142,20 @@ const Participated = () => { /> + + {/* 비활성화된 상태일 때 오버레이 */} + {isDisabledStatus(meeting.myMemberStatus) && ( + + )}
{/* 모바일 */} -
+
handleMoveDetailPage(meeting.meetingId)} + onClick={() => handleCardClick(meeting)} key={meeting.meetingId} title={meeting.title} thumbnailUrl={meeting.thumbnail} @@ -112,10 +170,14 @@ const Participated = () => { /> + + {/* 비활성화된 상태일 때 오버레이 */} + {isDisabledStatus(meeting.myMemberStatus) && ( + + )}
))} From 32c731c9616a9a8f834cad33557de0704d17976f Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Thu, 13 Mar 2025 22:12:56 +0900 Subject: [PATCH 13/30] =?UTF-8?q?feat(DEVING-79):=20=EC=B0=B8=EA=B0=80?= =?UTF-8?q?=EC=A4=91=EC=9D=B8=20=EB=AA=A8=EC=9E=84=20=ED=83=88=ED=87=B4=20?= =?UTF-8?q?=EB=B0=8F=20=EC=8A=B9=EC=9D=B8=EB=8C=80=EA=B8=B0=20=EC=B7=A8?= =?UTF-8?q?=EC=86=8C=ED=95=98=EA=B8=B0=20api=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/service/api/mymeeting.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/service/api/mymeeting.ts b/src/service/api/mymeeting.ts index 8ed0bbd3..759820fd 100644 --- a/src/service/api/mymeeting.ts +++ b/src/service/api/mymeeting.ts @@ -97,6 +97,18 @@ const putIsPublic = async (meetingId: number) => { return res.data.data; }; +// 참가중인 모임 나가기 +const DeleteQuit = async (meetingId: number) => { + const res = await axiosInstance.delete(`${myMeetingURL.quit(meetingId)}`); + return res.data.data; +}; + +// 승인 대기중인 모임 취소하기 +const DeleteCancel = async (meetingId: number) => { + const res = await axiosInstance.delete(`${myMeetingURL.cancel(meetingId)}`); + return res.data.data; +}; + export { getMyMeetingManage, getMyMeetingMemberProfile, @@ -105,4 +117,6 @@ export { putMemberStatus, putExpel, putIsPublic, + DeleteQuit, + DeleteCancel, }; From f72d7e70576eae13897071b75303b9ba5bbe2d6b Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Fri, 14 Mar 2025 00:04:08 +0900 Subject: [PATCH 14/30] =?UTF-8?q?feat(DEVING-79):=20=EC=8A=B9=EC=9D=B8?= =?UTF-8?q?=EB=8C=80=EA=B8=B0=20=EC=95=A0=EB=8B=88=EB=A9=94=EC=9D=B4?= =?UTF-8?q?=EC=85=98=20=EC=9C=84=ED=95=9C=20=ED=85=8C=EC=9D=BC=EC=9C=88?= =?UTF-8?q?=EB=93=9C=20=20config=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tailwind.config.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tailwind.config.ts b/tailwind.config.ts index 41406062..faf8f9d5 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -10,6 +10,11 @@ export default { ], theme: { extend: { + animation: { + 'delay-100': 'bounce 1s infinite 100ms', + 'delay-200': 'bounce 1s infinite 200ms', + 'delay-300': 'bounce 1s infinite 300ms', + }, screens: { sm: { min: '375px', From e10693a31f9ea58e0f6b37927409e47ecae62099 Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Fri, 14 Mar 2025 00:06:46 +0900 Subject: [PATCH 15/30] =?UTF-8?q?feat(DEVING-79):=20mymeeting=20=EB=AE=A4?= =?UTF-8?q?=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/mutations/useMyMeetingMutation.ts | 81 ++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/src/hooks/mutations/useMyMeetingMutation.ts b/src/hooks/mutations/useMyMeetingMutation.ts index 64c69cba..9e843505 100644 --- a/src/hooks/mutations/useMyMeetingMutation.ts +++ b/src/hooks/mutations/useMyMeetingMutation.ts @@ -1,10 +1,83 @@ import { useToast } from '@/components/common/ToastContext'; +import axiosInstance from '@/lib/axios/axiosInstance'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { AxiosError } from 'axios'; +import { myMeetingURL } from 'service/api/endpoints'; import { putExpel, putIsPublic, putMemberStatus } from 'service/api/mymeeting'; +import { meetingKeys } from '../queries/useMeetingQueries'; import { myMeetingKeys } from '../queries/useMyMeetingQueries'; +// 참가중인 모임 나가기 +const DeleteQuit = async (meetingId: number) => { + const res = await axiosInstance.delete(`${myMeetingURL.quit(meetingId)}`); + return res.data.data; +}; + +// 승인 대기중인 모임 취소하기 +const DeleteCancel = async (meetingId: number) => { + const res = await axiosInstance.delete(`${myMeetingURL.cancel(meetingId)}`); + return res.data.data; +}; + +// 참가중인 모임 나가기 훅 +const useQuitMeetingMutation = () => { + const { showToast } = useToast(); + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (meetingId: number) => DeleteQuit(meetingId), + onSuccess: (_, meetingId) => { + showToast('모임에서 탈퇴했습니다.', 'success'); + queryClient.invalidateQueries({ + queryKey: myMeetingKeys.participated(), + }); + queryClient.invalidateQueries({ + queryKey: meetingKeys.detailInfo(meetingId), + }); + }, + onError: (error: AxiosError) => { + const errorData = error.response?.data as + | { data?: { request?: string } } + | undefined; + const errorMessage = errorData?.data?.request || ''; + + if ( + errorMessage.includes('Meeting manager cannot quit meeting') && + error.response?.status === 400 + ) { + showToast('주최자는 모임을 탈퇴할 수 없습니다.', 'error'); + } else { + showToast('모임 탈퇴에 실패했습니다. 다시 시도해주세요.', 'error'); + } + }, + }); +}; + +// 승인 대기중인 모임 취소 훅 +const useCancelPendingMutation = () => { + const { showToast } = useToast(); + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: (meetingId: number) => DeleteCancel(meetingId), + onSuccess: (_, meetingId) => { + showToast('승인 대기를 취소했습니다.', 'success'); + queryClient.invalidateQueries({ + queryKey: myMeetingKeys.participated(), + }); + queryClient.invalidateQueries({ + queryKey: meetingKeys.detailInfo(meetingId), + }); + }, + onError: (error: AxiosError) => { + if (error.response?.status) { + showToast('승인 대기 취소에 실패했습니다. 다시 시도해주세요.', 'error'); + } + }, + }); +}; + const useMemberStatusMutation = (meetingId: number) => { const { showToast } = useToast(); const queryClient = useQueryClient(); @@ -95,4 +168,10 @@ const useChangePublic = (meetingId: number) => { }); }; -export { useMemberStatusMutation, useExpelMutation, useChangePublic }; +export { + useMemberStatusMutation, + useExpelMutation, + useChangePublic, + useQuitMeetingMutation, + useCancelPendingMutation, +}; From 3047fe879b2211ce72b10fe0c02092e94475a129 Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Fri, 14 Mar 2025 00:32:50 +0900 Subject: [PATCH 16/30] =?UTF-8?q?feat(DEVING-79):=20=EC=8A=B9=EC=9D=B8?= =?UTF-8?q?=EB=8C=80=EA=B8=B0=20=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_features/PendingStatusChip.tsx | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/app/(user-page)/my-meeting/_features/PendingStatusChip.tsx diff --git a/src/app/(user-page)/my-meeting/_features/PendingStatusChip.tsx b/src/app/(user-page)/my-meeting/_features/PendingStatusChip.tsx new file mode 100644 index 00000000..3026de49 --- /dev/null +++ b/src/app/(user-page)/my-meeting/_features/PendingStatusChip.tsx @@ -0,0 +1,50 @@ +'use client'; + +import { useCancelPendingMutation } from '@/hooks/mutations/useMyMeetingMutation'; +import { LogOut } from 'lucide-react'; + +interface PendingStatusChipProps { + meetingId: number; + text?: string; +} + +export const PendingStatusChip = ({ + meetingId, + text, +}: PendingStatusChipProps) => { + const { mutate: cancelPending, isPending: isLoading } = + useCancelPendingMutation(); + + const handleClick = (e: React.MouseEvent) => { + e.stopPropagation(); + cancelPending(meetingId); + }; + + return ( +
+
+ 승인 대기중 + + . + . + . + +
+ + +
+ ); +}; + +export default PendingStatusChip; From 5ae6b664a0bdbf255dc571f5b658f566f75fea1e Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Fri, 14 Mar 2025 00:33:23 +0900 Subject: [PATCH 17/30] =?UTF-8?q?feat(DEVING-79):=20=EB=AA=A8=EC=9E=84?= =?UTF-8?q?=ED=83=88=ED=87=B4=20=EA=B8=B0=EB=8A=A5=20=EB=B0=8F=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_features/LeaveMeetingButton.tsx | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 src/app/(user-page)/my-meeting/_features/LeaveMeetingButton.tsx diff --git a/src/app/(user-page)/my-meeting/_features/LeaveMeetingButton.tsx b/src/app/(user-page)/my-meeting/_features/LeaveMeetingButton.tsx new file mode 100644 index 00000000..f219bd2c --- /dev/null +++ b/src/app/(user-page)/my-meeting/_features/LeaveMeetingButton.tsx @@ -0,0 +1,44 @@ +'use client'; + +import { useQuitMeetingMutation } from '@/hooks/mutations/useMyMeetingMutation'; +import { LogOut } from 'lucide-react'; + +interface LeaveMeetingButtonProps { + meetingId: number; + className?: string; +} + +const LeaveMeetingButton = ({ + meetingId, + className = '', +}: LeaveMeetingButtonProps) => { + const { mutate: quitMeeting, isPending: isLoading } = + useQuitMeetingMutation(); + + const handleClick = (e: React.MouseEvent) => { + e.stopPropagation(); + quitMeeting(meetingId); + }; + + return ( + + ); +}; + +export default LeaveMeetingButton; From 6b9542d3c25cae2bb1be3d77e9c68ae11250e21c Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Fri, 14 Mar 2025 00:34:03 +0900 Subject: [PATCH 18/30] =?UTF-8?q?chore(DEVING-79):=20=EC=B0=B8=EC=97=AC?= =?UTF-8?q?=EC=A4=91=EC=9D=B8=20=EB=AA=A8=EC=9E=84=20=EB=A6=AC=ED=8E=99?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../my-meeting/_features/Participated.tsx | 68 +++++++++++++------ 1 file changed, 47 insertions(+), 21 deletions(-) diff --git a/src/app/(user-page)/my-meeting/_features/Participated.tsx b/src/app/(user-page)/my-meeting/_features/Participated.tsx index 116a3bf9..484edbb0 100644 --- a/src/app/(user-page)/my-meeting/_features/Participated.tsx +++ b/src/app/(user-page)/my-meeting/_features/Participated.tsx @@ -9,6 +9,8 @@ import { useRouter } from 'next/navigation'; import { IMyMeetingParticipated } from 'types/myMeeting'; import CardRightSection from './CardRightSection'; +import LeaveMeetingButton from './LeaveMeetingButton'; +import PendingStatusChip from './PendingStatusChip'; import MeetingListSkeleton from './skeletons/SkeletonMeetingList'; interface IStatusOverlay { @@ -40,7 +42,6 @@ const Participated = () => { } // 클릭 불가능한 상태인지 확인하는 함수 (오버레이 표시 여부만 결정) - const isDisabledStatus = ( status: IMyMeetingParticipated['myMemberStatus'], ): boolean => { @@ -64,12 +65,12 @@ const Participated = () => {
{meeting.myMemberStatus === 'REJECTED' ? (

- 죄송합니다. 가입이 거절된 + 죄송합니다. 가입이 거절된 모임입니다.

) : (

- 더 이상 참여가 불가능한 + 더 이상 참여가 불가능한 모임입니다.

)} @@ -104,19 +105,26 @@ const Participated = () => { meetingId={meeting.meetingId} category={''} > -
- - - -
+ + {/* PENDING 상태일 때 승인 대기중 칩 표시 */} + {meeting.myMemberStatus === 'PENDING' && ( + + )} + + {/* APPROVED 상태일 때 모임 탈퇴하기 버튼 표시 */} + {meeting.myMemberStatus === 'APPROVED' && ( + + )} + {/* 비활성화된 상태일 때 오버레이 */} {isDisabledStatus(meeting.myMemberStatus) && ( @@ -146,7 +154,17 @@ const Participated = () => { meetingId={meeting.meetingId} /> - {/* 비활성화된 상태일 때 오버레이 */} + {meeting.myMemberStatus === 'PENDING' && ( + + )} + + {meeting.myMemberStatus === 'APPROVED' && ( + + )} + {isDisabledStatus(meeting.myMemberStatus) && ( )} @@ -174,7 +192,17 @@ const Participated = () => { meetingId={meeting.meetingId} /> - {/* 비활성화된 상태일 때 오버레이 */} + {meeting.myMemberStatus === 'PENDING' && ( + + )} + + {meeting.myMemberStatus === 'APPROVED' && ( + + )} + {isDisabledStatus(meeting.myMemberStatus) && ( )} @@ -196,22 +224,20 @@ const Participated = () => { {/* 추가 데이터 로딩 중 표시 */} {isFetchingNextPage && (
-
- 로딩 중... -
+
로딩 중...
)} {/* 데이터가 없는 경우 표시 */} {meetingData.pages[0].content.length === 0 && ( -
+
참여한 모임이 없습니다.
)} {/* 더 이상 데이터가 없음을 표시 */} {!hasNextPage && meetingData.pages[0].content.length > 0 && ( -
+
모든 모임을 불러왔습니다.
)} From 4546f4a3f040724844f7770dd4ae682fa041efb9 Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Fri, 14 Mar 2025 23:43:47 +0900 Subject: [PATCH 19/30] =?UTF-8?q?chore(DEVING-79):=20=EB=82=B4=EA=B0=80?= =?UTF-8?q?=EC=B0=B8=EC=97=AC=ED=95=98=EA=B3=A0=EC=9E=88=EB=8A=94=20?= =?UTF-8?q?=EB=AA=A8=EC=9E=84=20=EC=A2=8B=EC=95=84=EC=9A=94=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(user-page)/my-meeting/_features/Participated.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/(user-page)/my-meeting/_features/Participated.tsx b/src/app/(user-page)/my-meeting/_features/Participated.tsx index 484edbb0..bd6e1f95 100644 --- a/src/app/(user-page)/my-meeting/_features/Participated.tsx +++ b/src/app/(user-page)/my-meeting/_features/Participated.tsx @@ -103,6 +103,7 @@ const Participated = () => { value={meeting.memberCount} className="flex-row" meetingId={meeting.meetingId} + showLikeButton={false} category={''} > Date: Fri, 14 Mar 2025 23:50:21 +0900 Subject: [PATCH 20/30] =?UTF-8?q?chore(DEVING-79):=20isPublic=20=EC=97=B0?= =?UTF-8?q?=EC=82=B0=EC=9E=90=20=EA=B9=94=EB=81=94=ED=95=98=EA=B2=8C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(user-page)/my-meeting/_features/CardRightSection.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/(user-page)/my-meeting/_features/CardRightSection.tsx b/src/app/(user-page)/my-meeting/_features/CardRightSection.tsx index 78f1a14f..8836b3a7 100644 --- a/src/app/(user-page)/my-meeting/_features/CardRightSection.tsx +++ b/src/app/(user-page)/my-meeting/_features/CardRightSection.tsx @@ -14,7 +14,7 @@ import PublicSelect from './PublicDropdown'; const CardRightSection = ({ memberList, - isPublic, + isPublic = false, className, meetingId, showPublicSelect = false, @@ -129,7 +129,7 @@ const CardRightSection = ({ 맴버 명단 보기 {showPublicSelect && ( - + )}
//
From fb9c0416c664453f677bd6679a052b65200928cb Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Sat, 15 Mar 2025 00:16:55 +0900 Subject: [PATCH 21/30] =?UTF-8?q?chore(DEVING-79):=20=EC=B0=B8=EC=97=AC?= =?UTF-8?q?=EB=AA=A8=EC=9E=84=20=EC=97=86=EC=9D=84=EC=8B=9C,=20=EB=AC=B8?= =?UTF-8?q?=EA=B5=AC=20=EC=8B=9C=EC=95=88=EB=A7=9E=EA=B2=8C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../my-meeting/_features/Participated.tsx | 24 +++++++------------ 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/app/(user-page)/my-meeting/_features/Participated.tsx b/src/app/(user-page)/my-meeting/_features/Participated.tsx index bd6e1f95..fd9891d8 100644 --- a/src/app/(user-page)/my-meeting/_features/Participated.tsx +++ b/src/app/(user-page)/my-meeting/_features/Participated.tsx @@ -147,6 +147,7 @@ const Participated = () => { thumbnailWidth={160} className="" meetingId={meeting.meetingId} + showLikeButton={false} category={''} /> { thumbnailWidth={80} className="" meetingId={meeting.meetingId} + showLikeButton={false} category={''} /> { ))} {/* 무한 스크롤을 위한 별도의 Observer 요소 */} - {hasNextPage && ( -
- )} + {hasNextPage &&
} {/* 추가 데이터 로딩 중 표시 */} {isFetchingNextPage && ( @@ -231,15 +227,11 @@ const Participated = () => { {/* 데이터가 없는 경우 표시 */} {meetingData.pages[0].content.length === 0 && ( -
- 참여한 모임이 없습니다. -
- )} - - {/* 더 이상 데이터가 없음을 표시 */} - {!hasNextPage && meetingData.pages[0].content.length > 0 && ( -
- 모든 모임을 불러왔습니다. +
+
+

내가 참여하고있는 모임이 없어요.

+

원하는 모임에 참가하세요!

+
)}
From f4c9334ebe5f488bf4ea6e5aec7d6ce05a2f9747 Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Sat, 15 Mar 2025 00:24:04 +0900 Subject: [PATCH 22/30] =?UTF-8?q?chore(DEVING-79):=20url=EC=83=9D=EC=84=B1?= =?UTF-8?q?=20=ED=95=A8=EC=88=98=20=EC=9E=AC=ED=99=9C=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../(user-page)/my-meeting/_features/Participated.tsx | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/app/(user-page)/my-meeting/_features/Participated.tsx b/src/app/(user-page)/my-meeting/_features/Participated.tsx index fd9891d8..c8ec3418 100644 --- a/src/app/(user-page)/my-meeting/_features/Participated.tsx +++ b/src/app/(user-page)/my-meeting/_features/Participated.tsx @@ -48,17 +48,14 @@ const Participated = () => { return status === 'REJECTED' || status === 'EXPEL'; }; - // 카드 클릭 핸들러 - 모든 상태에서 라우팅 가능하도록 변경 - const handleCardClick = (meeting: IMyMeetingParticipated) => { - router.push( - `/meeting/${translateCategoryNameToEng(meeting.categoryTitle)}/${meeting.meetingId}`, - ); - }; - // 모임 상세 페이지 URL 생성 함수 const getMeetingDetailUrl = (meeting: IMyMeetingParticipated) => `/meeting/${translateCategoryNameToEng(meeting.categoryTitle)}/${meeting.meetingId}`; + const handleCardClick = (meeting: IMyMeetingParticipated) => { + router.push(getMeetingDetailUrl(meeting)); + }; + // 오버레이 컴포넌트 (수정된 버전) const StatusOverlay = ({ meeting }: IStatusOverlay) => (
From b6f4df6a1ab7f218d03ff7683b81791d654323ae Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Sat, 15 Mar 2025 00:29:29 +0900 Subject: [PATCH 23/30] =?UTF-8?q?chore(DEVING-79):=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=8A=A4=EC=BC=88=EB=A0=88?= =?UTF-8?q?=ED=86=A4=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(user-page)/my-meeting/_features/Participated.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/app/(user-page)/my-meeting/_features/Participated.tsx b/src/app/(user-page)/my-meeting/_features/Participated.tsx index c8ec3418..26c05d45 100644 --- a/src/app/(user-page)/my-meeting/_features/Participated.tsx +++ b/src/app/(user-page)/my-meeting/_features/Participated.tsx @@ -216,11 +216,7 @@ const Participated = () => { {hasNextPage &&
} {/* 추가 데이터 로딩 중 표시 */} - {isFetchingNextPage && ( -
-
로딩 중...
-
- )} + {isFetchingNextPage && } {/* 데이터가 없는 경우 표시 */} {meetingData.pages[0].content.length === 0 && ( From d4683f074a035ffff755626e3d830f9a758b7fa8 Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Sat, 15 Mar 2025 00:44:30 +0900 Subject: [PATCH 24/30] =?UTF-8?q?chore(DEVING-79):=20=EC=A3=BC=EC=B5=9C?= =?UTF-8?q?=EC=9E=90=20=ED=8C=90=EB=B3=84=ED=95=98=EC=97=AC=20=ED=83=88?= =?UTF-8?q?=ED=87=B4=EB=B2=84=ED=8A=BC=20=EC=84=A0=ED=83=9D=EB=A0=8C?= =?UTF-8?q?=EB=8D=94=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../my-meeting/_features/Participated.tsx | 39 ++++++++++--------- src/types/myMeeting.ts | 1 + 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/app/(user-page)/my-meeting/_features/Participated.tsx b/src/app/(user-page)/my-meeting/_features/Participated.tsx index 26c05d45..c332341f 100644 --- a/src/app/(user-page)/my-meeting/_features/Participated.tsx +++ b/src/app/(user-page)/my-meeting/_features/Participated.tsx @@ -116,12 +116,13 @@ const Participated = () => { )} {/* APPROVED 상태일 때 모임 탈퇴하기 버튼 표시 */} - {meeting.myMemberStatus === 'APPROVED' && ( - - )} + {meeting.myMemberStatus === 'APPROVED' && + !meeting.isMeetingManager && ( + + )} {/* 비활성화된 상태일 때 오버레이 */} {isDisabledStatus(meeting.myMemberStatus) && ( @@ -157,12 +158,13 @@ const Participated = () => { )} - {meeting.myMemberStatus === 'APPROVED' && ( - - )} + {meeting.myMemberStatus === 'APPROVED' && + !meeting.isMeetingManager && ( + + )} {isDisabledStatus(meeting.myMemberStatus) && ( @@ -196,12 +198,13 @@ const Participated = () => { )} - {meeting.myMemberStatus === 'APPROVED' && ( - - )} + {meeting.myMemberStatus === 'APPROVED' && + !meeting.isMeetingManager && ( + + )} {isDisabledStatus(meeting.myMemberStatus) && ( diff --git a/src/types/myMeeting.ts b/src/types/myMeeting.ts index c8721588..07d5e7ec 100644 --- a/src/types/myMeeting.ts +++ b/src/types/myMeeting.ts @@ -42,6 +42,7 @@ interface IMyMeetingParticipated { likesCount: number; myMemberStatus: 'APPROVED' | 'REJECTED' | 'PENDING' | 'EXPEL'; memberList: Member[]; + isMeetingManager: boolean; } interface IMyMeetingLikes { From fffc3a9fa4b35e5976f7e669b71c837fd6c2b0aa Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Sat, 15 Mar 2025 00:52:03 +0900 Subject: [PATCH 25/30] =?UTF-8?q?chore(DEVING-79):=20=EC=B0=9C=ED=95=9C?= =?UTF-8?q?=EB=AA=A8=EC=9E=84=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../my-meeting/_features/Likes.tsx | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/src/app/(user-page)/my-meeting/_features/Likes.tsx b/src/app/(user-page)/my-meeting/_features/Likes.tsx index 6a458203..71a503a9 100644 --- a/src/app/(user-page)/my-meeting/_features/Likes.tsx +++ b/src/app/(user-page)/my-meeting/_features/Likes.tsx @@ -120,25 +120,15 @@ const Likes = () => { )} {/* 추가 데이터 로딩 중 표시 */} - {isFetchingNextPage && ( -
-
- 로딩 중... -
-
- )} + {isFetchingNextPage && } {/* 데이터가 없는 경우 표시 */} {meetingData.pages[0].content.length === 0 && ( -
- 찜한 모임이 없습니다. -
- )} - - {/* 더 이상 데이터가 없음을 표시 */} - {!hasNextPage && meetingData.pages[0].content.length > 0 && ( -
- 모든 모임을 불러왔습니다. +
+
+

찜한 모임이 없어요.

+

원하는 모임을 찜해보세요!

+
)}
From 881c983ee762972709897c2e9bd9db62909d334a Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Sat, 15 Mar 2025 00:57:45 +0900 Subject: [PATCH 26/30] =?UTF-8?q?chore(DEVING-79):=20=EC=A4=91=EB=B3=B5?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0=20=EB=B0=8F=20=EC=BB=A8?= =?UTF-8?q?=EB=B2=A4=EC=85=98=20=EB=A7=9E=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/mutations/useMyMeetingMutation.ts | 18 +++--------------- src/service/api/mymeeting.ts | 8 ++++---- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/hooks/mutations/useMyMeetingMutation.ts b/src/hooks/mutations/useMyMeetingMutation.ts index 9e843505..9c49b118 100644 --- a/src/hooks/mutations/useMyMeetingMutation.ts +++ b/src/hooks/mutations/useMyMeetingMutation.ts @@ -2,31 +2,19 @@ import { useToast } from '@/components/common/ToastContext'; import axiosInstance from '@/lib/axios/axiosInstance'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { AxiosError } from 'axios'; -import { myMeetingURL } from 'service/api/endpoints'; import { putExpel, putIsPublic, putMemberStatus } from 'service/api/mymeeting'; +import { deleteCancel, deleteQuit } from 'service/api/mymeeting'; import { meetingKeys } from '../queries/useMeetingQueries'; import { myMeetingKeys } from '../queries/useMyMeetingQueries'; -// 참가중인 모임 나가기 -const DeleteQuit = async (meetingId: number) => { - const res = await axiosInstance.delete(`${myMeetingURL.quit(meetingId)}`); - return res.data.data; -}; - -// 승인 대기중인 모임 취소하기 -const DeleteCancel = async (meetingId: number) => { - const res = await axiosInstance.delete(`${myMeetingURL.cancel(meetingId)}`); - return res.data.data; -}; - // 참가중인 모임 나가기 훅 const useQuitMeetingMutation = () => { const { showToast } = useToast(); const queryClient = useQueryClient(); return useMutation({ - mutationFn: (meetingId: number) => DeleteQuit(meetingId), + mutationFn: (meetingId: number) => deleteQuit(meetingId), onSuccess: (_, meetingId) => { showToast('모임에서 탈퇴했습니다.', 'success'); queryClient.invalidateQueries({ @@ -60,7 +48,7 @@ const useCancelPendingMutation = () => { const queryClient = useQueryClient(); return useMutation({ - mutationFn: (meetingId: number) => DeleteCancel(meetingId), + mutationFn: (meetingId: number) => deleteCancel(meetingId), onSuccess: (_, meetingId) => { showToast('승인 대기를 취소했습니다.', 'success'); queryClient.invalidateQueries({ diff --git a/src/service/api/mymeeting.ts b/src/service/api/mymeeting.ts index 759820fd..c48b3ba3 100644 --- a/src/service/api/mymeeting.ts +++ b/src/service/api/mymeeting.ts @@ -98,13 +98,13 @@ const putIsPublic = async (meetingId: number) => { }; // 참가중인 모임 나가기 -const DeleteQuit = async (meetingId: number) => { +const deleteQuit = async (meetingId: number) => { const res = await axiosInstance.delete(`${myMeetingURL.quit(meetingId)}`); return res.data.data; }; // 승인 대기중인 모임 취소하기 -const DeleteCancel = async (meetingId: number) => { +const deleteCancel = async (meetingId: number) => { const res = await axiosInstance.delete(`${myMeetingURL.cancel(meetingId)}`); return res.data.data; }; @@ -117,6 +117,6 @@ export { putMemberStatus, putExpel, putIsPublic, - DeleteQuit, - DeleteCancel, + deleteQuit, + deleteCancel, }; From b2eeb444912f23a3debb636f226afc59bba4c236 Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Sat, 15 Mar 2025 01:12:20 +0900 Subject: [PATCH 27/30] =?UTF-8?q?chore(DEVING-79):=20=EC=95=A0=EB=8B=88?= =?UTF-8?q?=EB=A9=94=EC=9D=B4=EC=85=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../(user-page)/my-meeting/_features/PendingStatusChip.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/(user-page)/my-meeting/_features/PendingStatusChip.tsx b/src/app/(user-page)/my-meeting/_features/PendingStatusChip.tsx index 3026de49..a38dff94 100644 --- a/src/app/(user-page)/my-meeting/_features/PendingStatusChip.tsx +++ b/src/app/(user-page)/my-meeting/_features/PendingStatusChip.tsx @@ -25,9 +25,9 @@ export const PendingStatusChip = ({
승인 대기중 - . - . - . + . + . + .
From 838989a5a368c60f32a2eaa9ed4fa6b4870bfa1d Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Sat, 15 Mar 2025 13:26:35 +0900 Subject: [PATCH 28/30] =?UTF-8?q?chore(DEVING-79):=20=EC=A4=91=EB=B3=B5Nam?= =?UTF-8?q?eToEng=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/util/CategoryNameToEng.ts | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 src/util/CategoryNameToEng.ts diff --git a/src/util/CategoryNameToEng.ts b/src/util/CategoryNameToEng.ts deleted file mode 100644 index 7bfae340..00000000 --- a/src/util/CategoryNameToEng.ts +++ /dev/null @@ -1,14 +0,0 @@ -export const translateCategoryNameToEng = (category: string) => { - switch (category) { - case '모각코': - return 'mogakco'; - case '취미': - return 'hobby'; - case '스터디': - return 'study'; - case '사이드 프로젝트': - return 'side-project'; - default: - return 'mogakco'; - } -}; From af329d36015a7a96fc78a1a3d7567f96937187a2 Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Sat, 15 Mar 2025 14:52:40 +0900 Subject: [PATCH 29/30] =?UTF-8?q?chore(DEVING-79):=20=EC=B6=A9=EB=8F=8C?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useCard.tsx | 167 ------------------------------------------ 1 file changed, 167 deletions(-) delete mode 100644 src/hooks/useCard.tsx diff --git a/src/hooks/useCard.tsx b/src/hooks/useCard.tsx deleted file mode 100644 index 3bc1506c..00000000 --- a/src/hooks/useCard.tsx +++ /dev/null @@ -1,167 +0,0 @@ -import ModalBeforeLogin from '@/app/meeting/_features/modal-content/ModalBeforeLogin'; -import ModalCancel from '@/app/meeting/_features/modal-content/ModalCancel'; -import ModalRegisterCheck from '@/app/meeting/_features/modal-content/ModalRegisterCheck'; -import ModalRegisterComplete from '@/app/meeting/_features/modal-content/ModalRegisterComplete'; -import ModalRegisterInput from '@/app/meeting/_features/modal-content/ModalRegisterInput'; -import ModalRegisterWait from '@/app/meeting/_features/modal-content/ModalRegisterWait'; -import { getAccessToken } from '@/lib/serverActions'; -import { useRouter } from 'next/navigation'; -import { useState } from 'react'; -import { MeetingDetail } from 'service/api/meeting'; - -import { - useMeetingMutation, - useMeetingQuitMutation, -} from './mutations/useMeetingMutation'; - -const useCard = (meeting: MeetingDetail) => { - const [isModalOpen, setIsModalOpen] = useState(false); - const [modalValue, setModalValue] = useState<{ - state: string; // 로그인 전, 신청 확인, 신청 입력, 신청 완료 - confirmText: string; - cancelText: string; - modalClassName?: string; - }>({ - state: '', - confirmText: '', - cancelText: '', - }); - const router = useRouter(); - - const [ment, setMent] = useState(''); - - const getToken = async () => { - const token = await getAccessToken(); // 서버에서 데이터 패칭 - return token; - }; - - const handleModalOpen = async (state: string) => { - // 경우의 수를 따져가며 여기서 모달 열기 - const token = await getToken(); - - // 로그인 전인지 확인 - if (!token) { - state = 'beforeLogin'; - } - - switch (state) { - case 'cancel': - setModalValue({ - state, - confirmText: '신청 취소', - cancelText: '돌아가기', - }); - break; - case 'beforeLogin': - setModalValue({ - state, - confirmText: '로그인', - cancelText: '취소', - }); - break; - case 'registerCheck': - setModalValue({ - state, - confirmText: '신청', - cancelText: '취소', - }); - break; - case 'registerInput': - setModalValue({ - state, - confirmText: '보내기', - cancelText: '취소', - modalClassName: 'w-[520px] py-[12px]', - }); - break; - case 'registerWait': - setModalValue({ - state, - confirmText: '내 모임 보러가기', - cancelText: '확인', - }); - break; - case 'registerComplete': - setModalValue({ - state, - confirmText: '내 모임 보러가기', - cancelText: '확인', - }); - break; - } - setIsModalOpen(true); - }; - - const { mutate } = useMeetingMutation({ - onSuccessCallback: handleModalOpen, - onErrorCallback: () => setIsModalOpen(false), - meetingId: meeting.meetingId, - }); - - const { mutate: cancelMutate } = useMeetingQuitMutation({ - meetingId: meeting.meetingId, - }); - - // 모달의 confirm 버튼 동작을 현재 modalType에 따라 동적으로 처리 - const handleModalConfirm = () => { - switch (modalValue.state) { - case 'cancel': - setIsModalOpen(false); - cancelMutate(); - break; - case 'beforeLogin': - setIsModalOpen(false); - router.push('/login'); - break; - case 'registerCheck': - handleModalOpen('registerInput'); - break; - case 'registerInput': - mutate({ message: ment }); - setMent(''); - break; - case 'registerWait': - router.push('/my-meeting/my?type=participated'); - setIsModalOpen(false); - break; - case 'registerComplete': - router.push('/my-meeting/my?type=participated'); - setIsModalOpen(false); - break; - default: - setIsModalOpen(false); - break; - } - }; - - // 모달 내부 콘텐츠를 조건부로 렌더링 - const renderModalContent = () => { - switch (modalValue.state) { - case 'cancel': - return ; - case 'beforeLogin': - return ; - case 'registerCheck': - return ; - case 'registerInput': - return ; - case 'registerWait': - return ; - case 'registerComplete': - return ; - default: - return null; - } - }; - - return { - handleModalOpen, - isModalOpen, - setIsModalOpen, - handleModalConfirm, - modalValue, - renderModalContent, - }; -}; - -export default useCard; From d9f467d0295a5ea8ad7e8ee473465151e326c7b3 Mon Sep 17 00:00:00 2001 From: clyde-yoonjae Date: Sat, 15 Mar 2025 14:57:24 +0900 Subject: [PATCH 30/30] =?UTF-8?q?chore(DEVING-79):=20=EB=B9=8C=EB=93=9C?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/(user-page)/my-meeting/_features/Likes.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/(user-page)/my-meeting/_features/Likes.tsx b/src/app/(user-page)/my-meeting/_features/Likes.tsx index 71a503a9..96f56144 100644 --- a/src/app/(user-page)/my-meeting/_features/Likes.tsx +++ b/src/app/(user-page)/my-meeting/_features/Likes.tsx @@ -3,7 +3,7 @@ import HorizonCard from '@/components/ui/HorizonCard'; import useInfiniteScroll from '@/hooks/common/useInfiniteScroll'; import { useInfiniteMyMeetingLikesQueries } from '@/hooks/queries/useMyMeetingQueries'; -import { translateCategoryNameToEng } from '@/util/CategoryNameToEng'; +import { translateCategoryNameToEng } from '@/util/searchFilter'; import { useRouter } from 'next/navigation'; import React from 'react';