diff --git a/package-lock.json b/package-lock.json index a9c4068a..2923c63c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1859,6 +1859,351 @@ "yarn": ">=1.22.18" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.0.tgz", + "integrity": "sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.0.tgz", + "integrity": "sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.0.tgz", + "integrity": "sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.0.tgz", + "integrity": "sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.0.tgz", + "integrity": "sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.0.tgz", + "integrity": "sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.0.tgz", + "integrity": "sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.0.tgz", + "integrity": "sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.0.tgz", + "integrity": "sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.0.tgz", + "integrity": "sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.0.tgz", + "integrity": "sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.0.tgz", + "integrity": "sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.0.tgz", + "integrity": "sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.0.tgz", + "integrity": "sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.0.tgz", + "integrity": "sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.0.tgz", + "integrity": "sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.0.tgz", + "integrity": "sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.0.tgz", + "integrity": "sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.0.tgz", + "integrity": "sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.0.tgz", + "integrity": "sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.0.tgz", + "integrity": "sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.0.tgz", + "integrity": "sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.0.tgz", + "integrity": "sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/win32-x64": { "version": "0.24.0", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.0.tgz", @@ -2347,6 +2692,126 @@ "glob": "10.3.10" } }, + "node_modules/@next/swc-darwin-arm64": { + "version": "14.2.18", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.18.tgz", + "integrity": "sha512-tOBlDHCjGdyLf0ube/rDUs6VtwNOajaWV+5FV/ajPgrvHeisllEdymY/oDgv2cx561+gJksfMUtqf8crug7sbA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "14.2.18", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.18.tgz", + "integrity": "sha512-uJCEjutt5VeJ30jjrHV1VIHCsbMYnEqytQgvREx+DjURd/fmKy15NaVK4aR/u98S1LGTnjq35lRTnRyygglxoA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "14.2.18", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.18.tgz", + "integrity": "sha512-IL6rU8vnBB+BAm6YSWZewc+qvdL1EaA+VhLQ6tlUc0xp+kkdxQrVqAnh8Zek1ccKHlTDFRyAft0e60gteYmQ4A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "14.2.18", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.18.tgz", + "integrity": "sha512-RCaENbIZqKKqTlL8KNd+AZV/yAdCsovblOpYFp0OJ7ZxgLNbV5w23CUU1G5On+0fgafrsGcW+GdMKdFjaRwyYA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "14.2.18", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.18.tgz", + "integrity": "sha512-3kmv8DlyhPRCEBM1Vavn8NjyXtMeQ49ID0Olr/Sut7pgzaQTo4h01S7Z8YNE0VtbowyuAL26ibcz0ka6xCTH5g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "14.2.18", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.18.tgz", + "integrity": "sha512-mliTfa8seVSpTbVEcKEXGjC18+TDII8ykW4a36au97spm9XMPqQTpdGPNBJ9RySSFw9/hLuaCMByluQIAnkzlw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "14.2.18", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.18.tgz", + "integrity": "sha512-J5g0UFPbAjKYmqS3Cy7l2fetFmWMY9Oao32eUsBPYohts26BdrMUyfCJnZFQkX9npYaHNDOWqZ6uV9hSDPw9NA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.2.18", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.18.tgz", + "integrity": "sha512-Ynxuk4ZgIpdcN7d16ivJdjsDG1+3hTvK24Pp8DiDmIa2+A4CfhJSEHHVndCHok6rnLUzAZD+/UOKESQgTsAZGg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@next/swc-win32-x64-msvc": { "version": "14.2.18", "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.18.tgz", diff --git a/src/_apis/review/my-review-apis.ts b/src/_apis/review/my-review-apis.ts new file mode 100644 index 00000000..efaa0b79 --- /dev/null +++ b/src/_apis/review/my-review-apis.ts @@ -0,0 +1,26 @@ +import { fetchApi } from '@/src/utils/api'; +import { ApiResponse, MyReviewResponse } from '@/src/types/review'; + +export function getMyReviews(page: number, size: number): Promise { + // 최종 반환 타입 + const url = `/api/review/memberReviews?page=${page}&size=${size}`; + return fetchApi>(url, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }).then((response) => { + return response.data; + }); +} + +// 리뷰 삭제 API +export function deleteReview(reviewId: number): Promise { + const url = `/api/review/${reviewId}`; + return fetchApi(url, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + }, + }); +} diff --git a/src/_queries/review/my-review-queries.ts b/src/_queries/review/my-review-queries.ts new file mode 100644 index 00000000..85d78e5f --- /dev/null +++ b/src/_queries/review/my-review-queries.ts @@ -0,0 +1,12 @@ +import { getMyReviews } from '@/src/_apis/review/my-review-apis'; +import { MyReviewResponse } from '@/src/types/review'; + +export function useGetMyReviewsQuery({ size }: { size: number }) { + return { + queryKey: ['myReviews'], + queryFn: ({ pageParam = 0 }: { pageParam?: number }) => getMyReviews(pageParam, size), + getNextPageParam: (lastPage: MyReviewResponse, allPages: MyReviewResponse[]) => { + return lastPage.hasNext ? allPages.length : undefined; + }, + }; +} diff --git a/src/app/(crew)/crew/detail/[id]/_components/crew-review-list.tsx b/src/app/(crew)/crew/detail/[id]/_components/crew-review-list.tsx index facece23..b1bdbc14 100644 --- a/src/app/(crew)/crew/detail/[id]/_components/crew-review-list.tsx +++ b/src/app/(crew)/crew/detail/[id]/_components/crew-review-list.tsx @@ -21,7 +21,7 @@ export default function CrewReviewList({ return (
- {reviews.map((review) => ( + {/* {reviews.map((review) => ( - ))} + ))} */}
5 * 1024 * 1024) { - alert('5MB 이하의 파일만 업로드 가능합니다.'); + toast.error('5MB 이하의 파일만 업로드 가능합니다.'); return; } diff --git a/src/app/(crew)/my-page/_components/review-tabs.tsx b/src/app/(crew)/my-page/_components/review-tabs.tsx index 211d626b..58c6cf3b 100644 --- a/src/app/(crew)/my-page/_components/review-tabs.tsx +++ b/src/app/(crew)/my-page/_components/review-tabs.tsx @@ -3,14 +3,7 @@ import { useState } from 'react'; import { useRouter } from 'next/navigation'; import { Divider } from '@mantine/core'; -import { getReviewableGatherings } from '@/src/_apis/gathering/reviewable-gathering'; -import { useInfiniteScroll } from '@/src/hooks/use-infinite-scroll'; -import { fetchMyReviewData } from '@/src/app/api/mock-api/review'; -import ReviewCardList from '@/src/components/common/review-list/review-card-list'; import Tabs from '@/src/components/common/tab'; -import ReviewableGatheringCardList from '@/src/components/my-page/reviewable-gatherings/reviewable-gathering-card-list'; -import { ReviewInformResponse } from '@/src/types/review'; -import { ReviewableGatheringCardInformResponse } from '@/src/types/reviewable-gathering-card'; export default function ReviewTabs() { const myPageTabs = [ diff --git a/src/app/(crew)/my-page/layout.tsx b/src/app/(crew)/my-page/layout.tsx index 6cd148f5..913285f7 100644 --- a/src/app/(crew)/my-page/layout.tsx +++ b/src/app/(crew)/my-page/layout.tsx @@ -1,13 +1,14 @@ import ProfileCardContainer from '@/src/app/(crew)/my-page/_components/profile-card/container'; import ReviewTabs from './_components/review-tabs'; -export default function MyPage() { +export default function MyPage({ children }: { children: React.ReactNode }) { return (
+
{children}
); diff --git a/src/app/(crew)/my-page/my-review/page.tsx b/src/app/(crew)/my-page/my-review/page.tsx index 19b61e14..21c8fd3d 100644 --- a/src/app/(crew)/my-page/my-review/page.tsx +++ b/src/app/(crew)/my-page/my-review/page.tsx @@ -1,3 +1,40 @@ +'use client'; + +import { toast } from 'react-toastify'; +import { Loader } from '@mantine/core'; +import { useGetMyReviewsQuery } from '@/src/_queries/review/my-review-queries'; +import { useInfiniteScroll } from '@/src/hooks/use-infinite-scroll'; +import ReviewCardList from '@/src/components/common/review-list/review-card-list'; + export default function MyReviewPage() { - return
my review list component
; + const size = 6; + + const { data, isLoading, error, ref, isFetchingNextPage, refetch } = useInfiniteScroll( + useGetMyReviewsQuery({ size }), + ); + + if (isLoading) { + return ( +
+ +
+ ); + } + + if (error) { + toast.error('리뷰를 불러오는 중 문제가 발생했습니다.'); + return null; + } + + return ( +
+ + {isFetchingNextPage && ( +
+ +
+ )} +
+
+ ); } diff --git a/src/app/(crew)/my-page/page.tsx b/src/app/(crew)/my-page/page.tsx index 57e2baa1..5d127dee 100644 --- a/src/app/(crew)/my-page/page.tsx +++ b/src/app/(crew)/my-page/page.tsx @@ -4,4 +4,5 @@ import { redirect } from 'next/navigation'; export default function MyPage() { redirect('/my-page/reviewable'); + return null; } diff --git a/src/app/api/mock-api/review.ts b/src/app/api/mock-api/review.ts deleted file mode 100644 index ec1fada3..00000000 --- a/src/app/api/mock-api/review.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { CrewReviewInformResponse, ReviewInformResponse } from '@/src/types/review'; -import { CrewReviewData, MyReviewData } from '@/src/mock/review-data'; - -// NOTE : 크루 리뷰 데이터 fetch -export const fetchCrewReviewData = (page: number, limit: number = 6) => { - const startIndex = page * limit; - const endIndex = startIndex + limit; - const data = CrewReviewData.data.slice(startIndex, endIndex); - - return new Promise((resolve) => { - setTimeout(() => { - resolve({ - data, - totalItems: CrewReviewData.data.length, - }); - }); - }); -}; - -// NOTE : 나의 리뷰 데이터 fetch -export const fetchMyReviewData = (page: number, limit: number) => { - const startIndex = page * limit; - const endIndex = startIndex + limit; - const data = MyReviewData.data.slice(startIndex, endIndex); - - return new Promise((resolve) => { - setTimeout(() => { - resolve({ - data, - hasNextPage: endIndex < MyReviewData.data.length, - }); - }); - }); -}; - -// const { data, ref, isFetchingNextPage } = useInfiniteScroll({ -// queryKey: ['review'], -// queryFn: ({ pageParam = 0 }) => fetchMyReviewData(pageParam, 3); -// getNextPageParam: (lastPage, allPages) => -// lastPage.hasNextPage ? allPages.length + 1 : undefined, -// }); diff --git a/src/components/common/review-list/review-card-list.stories.tsx b/src/components/common/review-list/review-card-list.stories.tsx index 48fca2ae..c955166b 100644 --- a/src/components/common/review-list/review-card-list.stories.tsx +++ b/src/components/common/review-list/review-card-list.stories.tsx @@ -1,75 +1,23 @@ import type { Meta, StoryObj } from '@storybook/react'; -import { useInfiniteScroll } from '@/src/hooks/use-infinite-scroll'; -import { fetchMyReviewData } from '@/src/app/api/mock-api/review'; -import { ReviewInformResponse } from '@/src/types/review'; -import ClientProvider from '../../client-provider'; +import { MyReviewData } from '@/src/mock/review-data'; import ReviewCardList from './review-card-list'; const meta: Meta = { title: 'components/ReviewCardList', component: ReviewCardList, parameters: { - layout: 'centered', + layout: 'fullscreen', nextjs: { appDirectory: true, }, }, tags: ['autodocs'], - decorators: [ - (Story) => ( - - - - ), - ], -} satisfies Meta; +}; export default meta; -type Story = StoryObj; - -// function RenderCrewReviewCardList({ isMine = false, clickable = false }) { -// const { data, ref, isFetchingNextPage } = useInfiniteScroll({ -// queryKey: ['review'], -// queryFn: ({ pageParam = 0 }) => fetchCrewReviewData(pageParam, 3), -// getNextPageParam: (lastPage, allPages) => -// lastPage.hasNextPage ? allPages.length + 1 : undefined, -// }); -// return ( -// -// ); -// } -function RenderMyReviewCardList({ isMine = true, clickable = false }) { - const { data, ref, isFetchingNextPage } = useInfiniteScroll({ - queryKey: ['review'], - queryFn: ({ pageParam = 0 }) => fetchMyReviewData(pageParam, 3), - getNextPageParam: (lastPage, allPages) => - lastPage.hasNextPage ? allPages.length + 1 : undefined, - }); - - return ( - - ); -} - -// export const CrewReviewCardList: Story = { -// render: () => , -// args: {}, -// }; +type Story = StoryObj; export const MyReviewCardList: Story = { - render: () => , - args: {}, + render: () => {}} />, }; diff --git a/src/components/common/review-list/review-card-list.tsx b/src/components/common/review-list/review-card-list.tsx index 2ec304b6..a1f3b3e5 100644 --- a/src/components/common/review-list/review-card-list.tsx +++ b/src/components/common/review-list/review-card-list.tsx @@ -1,48 +1,47 @@ -import { forwardRef } from 'react'; import { InfiniteData } from '@tanstack/react-query'; -import { ReviewInformResponse } from '@/src/types/review'; +import { MyReview } from '@/src/types/review'; import ReviewCard from './review-card'; +// ReviewCardListProps 타입 정의 interface ReviewCardListProps { - data: InfiniteData | undefined; - isFetchingNextPage: boolean; - clickable?: boolean; - isMine?: boolean; + data: InfiniteData<{ + content: MyReview[]; + hasNext: boolean; + }>; + refetch: () => void; } -function ReviewCardList( - { data, isFetchingNextPage, clickable = false, isMine = false }: ReviewCardListProps, - ref: React.Ref, -) { - const reviewDataList = data?.pages.flatMap((page) => [...page.data]) ?? []; +export default function ReviewCardList({ data, refetch }: ReviewCardListProps) { + const reviewDataList = data.pages.flatMap((page) => page.content || []); - if (!reviewDataList) return

Loading...

; + // 데이터가 없을 경우 처리 + if (!reviewDataList.length) { + return ( +
+

남긴 리뷰가 없습니다

+

크루에 가입하고 약속을 잡아보세요!

+
+ ); + } return ( - <> -
    - {reviewDataList.map((review, index) => ( -
  • - -
  • - ))} -
- {isFetchingNextPage ?

loading...

:
} - +
    + {reviewDataList.map((review) => ( +
  • + +
  • + ))} +
); } - -export default forwardRef(ReviewCardList); diff --git a/src/components/common/review-list/review-card.tsx b/src/components/common/review-list/review-card.tsx index 50154609..8a2686ab 100644 --- a/src/components/common/review-list/review-card.tsx +++ b/src/components/common/review-list/review-card.tsx @@ -1,14 +1,16 @@ 'use client'; import React, { useState } from 'react'; +import { toast } from 'react-toastify'; import { useRouter } from 'next/navigation'; -import { Button } from '@mantine/core'; import { useDisclosure } from '@mantine/hooks'; +import { deleteReview } from '@/src/_apis/review/my-review-apis'; import { formatDateWithYear } from '@/src/utils/format-date'; +import Button from '@/src/components/common/input/button'; import ConfirmCancelModal from '@/src/components/common/modal/confirm-cancel-modal'; +import { Profile } from '@/src/components/common/profile'; +import ReviewHearts from '@/src/components/common/review-heart/hearts'; import { ReviewerType } from '@/src/types/review'; -import { Profile } from '../profile'; -import ReviewHearts from '../review-heart/hearts'; export interface GatheringInform { id: number; @@ -20,12 +22,13 @@ interface ReviewCardProps { rate: number; comment: string; createdAt: string; - crewId: number; + id: number; clickable?: boolean; isMine?: boolean; + crewId?: number; crewName?: string; - gatheringLocation?: string; gatheringName?: string; + refetch: () => void; reviewer?: ReviewerType; } @@ -33,38 +36,38 @@ interface ReviewCardProps { export default function ReviewCard({ rate, comment, - // eslint-disable-next-line @typescript-eslint/no-unused-vars createdAt, - crewId, + id, clickable = false, isMine = false, + crewId, crewName, gatheringName, - gatheringLocation, + refetch, reviewer, }: ReviewCardProps) { const [ confirmDeleteModalOpened, { open: openConfirmDeleteModal, close: closeConfirmDeleteModal }, ] = useDisclosure(false); - - const [prefetched, setPrefetched] = useState(new Set()); - const CREWPAGE = `crew/detail/${crewId}`; const router = useRouter(); - const handleClick = (e: React.MouseEvent) => { - e.preventDefault(); - if (clickable) router.push(CREWPAGE); + const handleDelete = async () => { + try { + await deleteReview(id); + toast.success('리뷰가 성공적으로 삭제되었습니다.'); + closeConfirmDeleteModal(); + refetch(); + } catch (error) { + toast.error('리뷰 삭제에 실패했습니다.'); + } }; - const handlePrefetch = () => { - if (clickable && !prefetched.has(CREWPAGE)) router.prefetch(CREWPAGE); - setPrefetched(new Set(prefetched).add(CREWPAGE)); - }; - - const handleDelete = () => { - // TODO: 삭제 로직 - closeConfirmDeleteModal(); + const handleClick = (e: React.MouseEvent) => { + e.stopPropagation(); // 이벤트 전파 중지 + if (clickable && crewId) { + router.push(`/crew/detail/${crewId}`); + } }; const { year, month, day } = formatDateWithYear(createdAt); @@ -75,20 +78,23 @@ export default function ReviewCard({ return (
{isMine && ( -
- {gatheringName} | - {gatheringLocation} -
+ )}
{isMine && ( - {crewName} + + {gatheringName} + )}
@@ -108,8 +114,7 @@ export default function ReviewCard({
{isMine && (
-
{`${year}년 ${month}월 ${day}일`}
+
{formatDate}