Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
13 commits
Select commit Hold shift + click to select a range
32892cd
feat(DEVING-70): ๋‚ด๊ฐ€ ์ž‘์„ฑํ•œ ๋ฆฌ๋ทฐ API ์—ฐ๋™, ํƒญ ์ปดํฌ๋„ŒํŠธ ์ˆ˜์ •
lee1nna Mar 7, 2025
8895d53
feat(DEVING-70): ๋‚˜์˜ ๋ฆฌ๋ทฐ ๊ฒฝ๋กœ ์ ‘๊ทผ ์‹œ ๋ผ์šฐํ„ฐ์— type ์ฟผ๋ฆฌ ์„ธํŒ… ๋กœ์ง ์ถ”๊ฐ€
lee1nna Mar 7, 2025
5c4932a
Merge branch 'dev' into feat/markup/my-review/DEVING-70
lee1nna Mar 11, 2025
3dc8d46
feat(DEVING-78): ์ž‘์„ฑํ•œ ๋ฆฌ๋ทฐ ReviewItem ์ถ”๊ฐ€
lee1nna Mar 11, 2025
d058a01
Merge branch 'dev' into feat/markup/my-review/DEVING-70
lee1nna Mar 11, 2025
1c0a032
feat(DEVING-78): ๋‚ด๊ฐ€ ์ž‘์„ฑํ•œ ๋ฆฌ๋ทฐ ๋ฌดํ•œ์Šคํฌ๋กค observer ์ถ”๊ฐ€
lee1nna Mar 11, 2025
5595912
feat(DEVING-70): ๋ชจ์ž„ ์กฐํšŒ ํ•„ํ„ฐ๋ง NEW -> CREATED๋กœ ๋ณ€๊ฒฝ
lee1nna Mar 11, 2025
71baaf5
Merge branch 'dev' into feat/markup/my-review/DEVING-70
lee1nna Mar 11, 2025
31ecd31
feat(DEVING-70): ๋ฆฌ๋ทฐ ์ž‘์„ฑ ๊ฐ€๋Šฅํ•œ ๋ชจ์ž„ API ์—ฐ๋™
lee1nna Mar 11, 2025
c32bddd
Merge branch 'dev' into feat/markup/my-review/DEVING-70
lee1nna Mar 13, 2025
90b95d9
feat(DEVING-70): ๋‚˜์˜ ๋ฆฌ๋ทฐ ์นด๋“œ ์ปดํฌ๋„ŒํŠธ์— ์ข‹์•„์š” ๋ฒ„ํŠผ ์ œ๊ฑฐ
lee1nna Mar 13, 2025
0ac2902
Merge branch 'dev' into feat/markup/my-review/DEVING-70
lee1nna Mar 13, 2025
7bd40dc
feat(DEVING-70): ๋ฆฌ๋ทฐ ์—†์„ ๊ฒฝ์šฐ UI ์ถ”๊ฐ€
lee1nna Mar 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions src/app/(user-page)/my-meeting/_features/Tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@
import { Button } from '@/components/ui/Button';
import { useRouter } from 'next/navigation';

const tabList = [
{ label: '๋‚ด๊ฐ€ ๋งŒ๋“  ๋ชจ์ž„', value: 'created' },
{ label: '๋‚ด๊ฐ€ ์ฐธ์—ฌํ•˜๊ณ  ์žˆ๋Š” ๋ชจ์ž„', value: 'joined' },
];
interface TabProps {
type: string;
tabList: {
label: string;
value: string;
url: string;
}[];
}

const Tab = ({ type }: { type: string }) => {
const Tab = ({ type, tabList }: TabProps) => {
const router = useRouter();

return (
Expand All @@ -18,7 +22,7 @@ const Tab = ({ type }: { type: string }) => {
key={item.value}
className="w-fit px-4"
variant={type === item.value ? 'solid' : 'default'}
onClick={() => router.push(`/my-meeting/my?type=${item.value}`)}
onClick={() => router.push(`${item.url}?type=${item.value}`)}
>
{item.label}
</Button>
Expand Down
133 changes: 133 additions & 0 deletions src/app/(user-page)/my-meeting/_features/Writable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
'use client';

import HorizonCard from '@/components/ui/HorizonCard';
import useInfiniteScroll from '@/hooks/common/useInfiniteScroll';
import { useInfiniteWritableMyMeetingsQueries } from '@/hooks/queries/useMyCommentQueries';
import { translateCategoryNameToEng } from '@/util/searchFilter';
import { useRouter } from 'next/navigation';
import { MyComment } from 'types/myComment';

import MeetingListSkeleton from './skeletons/SkeletonMeetingList';

const Writable = () => {
const router = useRouter();
const {
data: meetingData,
fetchNextPage,
hasNextPage,
isFetchingNextPage,
isLoading,
error,
} = useInfiniteWritableMyMeetingsQueries();

const allMeetings: MyComment[] =
meetingData?.pages.flatMap((page) => page.content) || [];

const lastMeetingRef = useInfiniteScroll({
fetchNextPage,
isFetchingNextPage,
hasNextPage,
});

if (error) {
<div className="bg-main text-white">
์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. <hr />
๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.
</div>;
}

if (isLoading) {
return <MeetingListSkeleton />;
}

const handleMoveDetailPage = (meetingId: number, category: string) => {
const categoryEng = translateCategoryNameToEng(category);
router.push(`/meeting/${categoryEng}/${meetingId}`);
};

return (
<div>
{allMeetings.length === 0 && (
<div className="text-gray-500 py-8 text-center text-white">
๋ฆฌ๋ทฐ ์ž‘์„ฑ ๊ฐ€๋Šฅํ•œ ๋ชจ์ž„์ด ์—†์Šต๋‹ˆ๋‹ค. <br />
๋ชจ์ž„์— ์ฐธ์—ฌํ•˜๊ณ  ๋ฆฌ๋ทฐ๋ฅผ ์ž‘์„ฑํ•ด๋ณด์„ธ์š”!
</div>
)}
<div>
{allMeetings.map((meeting) => (
<div key={meeting.meetingId}>
{/* ๋ฐ์Šคํฌํƒ‘ */}
<div className="hidden border-b border-Cgray300 py-[42px] lg:flex">
<HorizonCard
onClick={() =>
handleMoveDetailPage(meeting.meetingId, meeting.categoryTitle)
}
key={meeting.meetingId}
title={meeting.meetingTitle}
thumbnailUrl={meeting.thumbnail}
location={meeting.location}
total={meeting.maxMember}
value={meeting.memberCount}
className="flex-row"
showLikeButton={false}
meetingId={meeting.meetingId}
category={''}
></HorizonCard>
</div>

{/* ํƒœ๋ธ”๋ฆฟ */}
<div className="hidden flex-col border-b border-Cgray300 py-[42px] md:flex lg:hidden">
<HorizonCard
onClick={() =>
handleMoveDetailPage(meeting.meetingId, meeting.categoryTitle)
}
key={meeting.meetingId}
title={meeting.meetingTitle}
thumbnailUrl={meeting.thumbnail}
location={meeting.location}
total={meeting.maxMember}
value={meeting.memberCount}
thumbnailHeight={160}
thumbnailWidth={160}
meetingId={meeting.meetingId}
category={''}
showLikeButton={false}
/>
</div>

{/* ๋ชจ๋ฐ”์ผ */}
<div className="flex flex-col border-b border-Cgray300 py-[42px] md:hidden">
<HorizonCard
onClick={() =>
handleMoveDetailPage(meeting.meetingId, meeting.categoryTitle)
}
key={meeting.meetingId}
title={meeting.meetingTitle}
thumbnailUrl={meeting.thumbnail}
location={meeting.location}
total={meeting.maxMember}
value={meeting.memberCount}
thumbnailHeight={80}
thumbnailWidth={80}
meetingId={meeting.meetingId}
category={''}
showLikeButton={false}
/>
</div>
</div>
))}

{/* ๋ฌดํ•œ ์Šคํฌ๋กค์„ ์œ„ํ•œ ๋ณ„๋„์˜ Observer ์š”์†Œ */}
{hasNextPage && (
<div
ref={lastMeetingRef}
className="h-20 w-full"
id="infinite-scroll-trigger"
/>
)}
</div>
</div>
);
};

export default Writable;
151 changes: 151 additions & 0 deletions src/app/(user-page)/my-meeting/_features/Written.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
'use client';

import ReviewItem from '@/app/meeting/_features/ReviewItem';
import HorizonCard from '@/components/ui/HorizonCard';
import useInfiniteScroll from '@/hooks/common/useInfiniteScroll';
import { useInfiniteWrittenMyCommentQueries } from '@/hooks/queries/useMyCommentQueries';
import { translateCategoryNameToEng } from '@/util/searchFilter';
import { useRouter } from 'next/navigation';
import { MyComment } from 'types/myComment';

import MeetingListSkeleton from './skeletons/SkeletonMeetingList';

const Written = () => {
const router = useRouter();
const {
data: commentData,
fetchNextPage,
hasNextPage,
isFetchingNextPage,
isLoading,
error,
} = useInfiniteWrittenMyCommentQueries();

const allComments: MyComment[] =
commentData?.pages.flatMap((page) => page.content) || [];

const lastMeetingRef = useInfiniteScroll({
fetchNextPage,
isFetchingNextPage,
hasNextPage,
});

if (error) {
<div className="bg-main text-white">
์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. <hr />
๋‹ค์‹œ ์‹œ๋„ํ•ด์ฃผ์„ธ์š”.
</div>;
}

if (isLoading) {
return <MeetingListSkeleton />;
}

const handleMoveDetailPage = (meetingId: number, category: string) => {
const categoryEng = translateCategoryNameToEng(category);
router.push(`/meeting/${categoryEng}/${meetingId}`);
};

return (
<div>
{/* ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ ํ‘œ์‹œ */}
{allComments.length === 0 && (
<div className="text-gray-500 py-8 text-center text-white">
์ž‘์„ฑํ•œ ๋ฆฌ๋ทฐ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. <br />
๋ชจ์ž„์— ์ฐธ์—ฌํ•˜๊ณ  ๋ฆฌ๋ทฐ๋ฅผ ์ž‘์„ฑํ•ด๋ณด์„ธ์š”!
</div>
)}
<div>
{allComments.map((comment) => (
<div key={comment.meetingId}>
{/* ๋ฐ์Šคํฌํƒ‘ */}
<div className="hidden border-b border-Cgray300 py-[42px] lg:flex">
<HorizonCard
onClick={() =>
handleMoveDetailPage(comment.meetingId, comment.categoryTitle)
}
key={comment.meetingId}
title={comment.meetingTitle}
thumbnailUrl={comment.thumbnail}
location={comment.location}
total={comment.maxMember}
value={comment.memberCount}
className="flex-row p-0"
meetingId={comment.meetingId}
showLikeButton={false}
category={''}
></HorizonCard>
<ReviewItem
comment={comment}
isMine={true}
className="px-6"
></ReviewItem>
</div>

{/* ํƒœ๋ธ”๋ฆฟ */}
<div className="hidden flex-col border-b border-Cgray300 py-[42px] md:flex lg:hidden">
<HorizonCard
onClick={() =>
handleMoveDetailPage(comment.meetingId, comment.categoryTitle)
}
key={comment.meetingId}
title={comment.meetingTitle}
thumbnailUrl={comment.thumbnail}
location={comment.location}
total={comment.maxMember}
value={comment.memberCount}
thumbnailHeight={160}
thumbnailWidth={160}
className="p-0"
meetingId={comment.meetingId}
showLikeButton={false}
category={''}
/>
<ReviewItem
comment={comment}
isMine={true}
className="px-6"
></ReviewItem>
</div>

{/* ๋ชจ๋ฐ”์ผ */}
<div className="flex flex-col border-b border-Cgray300 py-[42px] md:hidden">
<HorizonCard
onClick={() =>
handleMoveDetailPage(comment.meetingId, comment.categoryTitle)
}
key={comment.meetingId}
title={comment.meetingTitle}
thumbnailUrl={comment.thumbnail}
location={comment.location}
total={comment.maxMember}
value={comment.memberCount}
thumbnailHeight={80}
thumbnailWidth={80}
className=""
meetingId={comment.meetingId}
category={''}
showLikeButton={false}
/>
<ReviewItem
comment={comment}
isMine={true}
className="px-6"
></ReviewItem>
</div>
</div>
))}

{/* ๋ฌดํ•œ ์Šคํฌ๋กค์„ ์œ„ํ•œ ๋ณ„๋„์˜ Observer ์š”์†Œ */}
{hasNextPage && (
<div
ref={lastMeetingRef}
className="h-20 w-full"
id="infinite-scroll-trigger"
/>
)}
</div>
</div>
);
};
export default Written;
60 changes: 58 additions & 2 deletions src/app/(user-page)/my-meeting/comments/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,61 @@
import NotYet from '@/components/common/NotYet';

Check warning on line 1 in src/app/(user-page)/my-meeting/comments/page.tsx

View workflow job for this annotation

GitHub Actions / check

'NotYet' is defined but never used. Allowed unused vars must match /^_/u
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

์š”๊ณ ๋ˆˆ ์ง€์šฐ์…”๋„ ๋ ๊ฒƒ๊ฐ™์Šด๋‹ˆ๋‹น

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๋„ต ๋‹ค๋ฅธ ๋ธŒ๋žœ์น˜์—์„œ ๋ฐ˜์˜ํ•˜๊ฒ ์Šต๋‹ˆ๋‹น!

import { MY_COMMENT_KEY } from '@/hooks/queries/useMyCommentQueries';
import {
HydrationBoundary,
QueryClient,
dehydrate,
} from '@tanstack/react-query';
import { MY_COMMENT_TAB_LIST } from 'constants/mypage/mypageConstant';
import {
getMyMeetingsWritableComments,
getMyWrittenComments,
} from 'service/api/mycomments';
import { Paginated } from 'types/meeting';
import { MyComment } from 'types/myComment';

export default function CommentsPage() {
return <NotYet />;
import Tab from '../_features/Tab';
import Writable from '../_features/Writable';
import Written from '../_features/Written';

export default async function CommentsPage({
searchParams,
}: {
searchParams: { type: string };
}) {
const type = searchParams?.type;

const queryClient = new QueryClient();

if (type === 'writable') {
// ์ž‘์„ฑ ๊ฐ€๋Šฅํ•œ ๋ฆฌ๋ทฐ prefetch
await queryClient.prefetchInfiniteQuery({
queryKey: MY_COMMENT_KEY.written,
queryFn: ({ pageParam }) => getMyMeetingsWritableComments(pageParam),
initialPageParam: 0,
getNextPageParam: (lastPage: Paginated<MyComment>) => {
return lastPage.nextCursor ?? null;
},
});
} else {
// ์ž‘์„ฑํ•œ ๋ฆฌ๋ทฐ prefetch
await queryClient.prefetchInfiniteQuery({
queryKey: MY_COMMENT_KEY.written,
queryFn: ({ pageParam }) => getMyWrittenComments(pageParam),
initialPageParam: 0,
getNextPageParam: (lastPage: Paginated<MyComment>) => {
return lastPage.nextCursor ?? null;
},
});
}

return (
<div>
<div className="mt-6 flex flex-col gap-[24px]">
<Tab type={type} tabList={MY_COMMENT_TAB_LIST} />
</div>
<HydrationBoundary state={dehydrate(queryClient)}>
{type === 'writable' ? <Writable /> : <Written />}
</HydrationBoundary>
</div>
);
}
3 changes: 2 additions & 1 deletion src/app/(user-page)/my-meeting/my/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import NotYet from '@/components/common/NotYet';

Check warning on line 1 in src/app/(user-page)/my-meeting/my/page.tsx

View workflow job for this annotation

GitHub Actions / check

'NotYet' is defined but never used. Allowed unused vars must match /^_/u
import { myMeetingKeys } from '@/hooks/queries/useMyMeetingQueries';
import { QUERY_KEYS } from '@/hooks/queries/useMyPageQueries';
import {
Expand All @@ -6,6 +6,7 @@
QueryClient,
dehydrate,
} from '@tanstack/react-query';
import { MY_MEETING_TAB_LIST } from 'constants/mypage/mypageConstant';
import {
getMyMeetingManage,
getMyMeetingParticipated,
Expand Down Expand Up @@ -56,7 +57,7 @@
return (
<div>
<div className="mt-6 flex flex-col gap-[24px]">
<Tab type={type} />
<Tab type={type} tabList={MY_MEETING_TAB_LIST} />
</div>
<HydrationBoundary state={dehydrate(queryClient)}>
{type === 'created' ? <Created /> : <Participated />}
Expand Down
Loading
Loading