diff --git a/src/assets/icons/noWine.svg b/src/assets/icons/noWine.svg new file mode 100644 index 00000000..495c991d --- /dev/null +++ b/src/assets/icons/noWine.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/components/my-profile/Empty.tsx b/src/components/my-profile/Empty.tsx new file mode 100644 index 00000000..f3f82ec6 --- /dev/null +++ b/src/components/my-profile/Empty.tsx @@ -0,0 +1,33 @@ +import React from 'react'; + +import Link from 'next/link'; + +import NoReviewIcon from '@/assets/icons/noReview.svg'; +import NoWineIcon from '@/assets/icons/noWine.svg'; +import { Button } from '@/components/ui/button'; + +interface MyPageEmptyProps { + type: 'reviews' | 'wines'; +} + +/** + * 내 프로필 페이지에서 데이터가 없을 때 표시되는 공통 Empty 컴포넌트 + * - type: 'reviews' | 'wines' (내가 쓴 후기 / 내가 등록한 와인) + * - 리뷰는 '와인 보러가기' 링크 + * - 와인은 와인 등록 버튼 + */ +export default function MyPageEmpty({ type }: MyPageEmptyProps) { + const isReview = type === 'reviews'; + + return ( +
+
+ {isReview ? : } +
+ + +
+ ); +} diff --git a/src/components/my-profile/ReviewList.tsx b/src/components/my-profile/ReviewList.tsx index 18e7626d..b1079fea 100644 --- a/src/components/my-profile/ReviewList.tsx +++ b/src/components/my-profile/ReviewList.tsx @@ -12,6 +12,8 @@ import { Badge } from '@/components/ui/badge'; import { useInfiniteScroll } from '@/hooks/useInfiniteScroll'; import { MyReview } from '@/types/MyReviewsTypes'; +import MyPageEmpty from './Empty'; + const PAGE_LIMIT = 10; interface ReviewListProps { @@ -30,13 +32,12 @@ export function ReviewList({ setTotalCount }: ReviewListProps) { const observerRef = useRef(null); // useInfiniteQuery 훅으로 리뷰 데이터를 무한 스크롤 형태로 조회 - const { data, isLoading, isError, fetchNextPage, hasNextPage, isFetchingNextPage } = - useInfiniteQuery({ - queryKey: ['reviews'], - queryFn: ({ pageParam = 0 }) => getMyReviews({ cursor: pageParam, limit: PAGE_LIMIT }), - initialPageParam: 0, - getNextPageParam: (lastPage) => lastPage.nextCursor ?? null, - }); + const { data, isError, fetchNextPage, hasNextPage, isFetchingNextPage } = useInfiniteQuery({ + queryKey: ['reviews'], + queryFn: ({ pageParam = 0 }) => getMyReviews({ cursor: pageParam, limit: PAGE_LIMIT }), + initialPageParam: 0, + getNextPageParam: (lastPage) => lastPage.nextCursor ?? null, + }); // xhx useEffect(() => { if (data?.pages?.[0]?.totalCount != null) { @@ -53,13 +54,15 @@ export function ReviewList({ setTotalCount }: ReviewListProps) { }); // 로딩 및 에러 상태 처리 (임시) - if (isLoading) return

불러오는 중…

; if (isError) return

불러오기 실패

; - if (!data) return

리뷰 데이터가 없습니다.

; - // 리뮤 목록 평탄화 + // 리뷰 목록 평탄화 const reviews: MyReview[] = data?.pages?.flatMap((page) => page.list ?? []) ?? []; + if (!data || data.pages[0].list.length === 0) { + return ; + } + return (
{reviews.map((review) => ( diff --git a/src/components/my-profile/WineList.tsx b/src/components/my-profile/WineList.tsx index 9a7c0d28..fed57f07 100644 --- a/src/components/my-profile/WineList.tsx +++ b/src/components/my-profile/WineList.tsx @@ -9,6 +9,7 @@ import MenuDropdown from '@/components/common/dropdown/MenuDropdown'; import { Badge } from '@/components/ui/badge'; import { useInfiniteScroll } from '@/hooks/useInfiniteScroll'; +import MyPageEmpty from './Empty'; import DeleteModal from '../Modal/DeleteModal/DeleteModal'; import EditWineModal from '../Modal/WineModal/EditWineModal'; @@ -31,13 +32,12 @@ export function WineList({ setTotalCount }: WineListProps) { const [deleteWineId, setDeleteWineId] = useState(null); //useInfiniteQuery 훅으로 와인 데이터를 무한 스크롤 형태로 조회 - const { data, isLoading, isError, fetchNextPage, hasNextPage, isFetchingNextPage } = - useInfiniteQuery({ - queryKey: ['wines'], - queryFn: ({ pageParam = 0 }) => getMyWines({ cursor: pageParam, limit: PAGE_LIMIT }), - initialPageParam: 0, - getNextPageParam: (lastPage: MyWinesResponse | undefined) => lastPage?.nextCursor ?? null, - }); + const { data, isError, fetchNextPage, hasNextPage, isFetchingNextPage } = useInfiniteQuery({ + queryKey: ['wines'], + queryFn: ({ pageParam = 0 }) => getMyWines({ cursor: pageParam, limit: PAGE_LIMIT }), + initialPageParam: 0, + getNextPageParam: (lastPage: MyWinesResponse | undefined) => lastPage?.nextCursor ?? null, + }); useEffect(() => { if (data?.pages?.[0]?.totalCount != null) { @@ -54,12 +54,15 @@ export function WineList({ setTotalCount }: WineListProps) { }); // 로딩 및 에러 상태 처리 (임시) - if (isLoading) return

와인 불러오는 중…

; if (isError || !data) return

와인 불러오기 실패

; // 와인 목록 평탄화 const wines: MyWine[] = data?.pages?.flatMap((page) => page?.list ?? []) ?? []; + if (!data || data.pages[0].list.length === 0) { + return ; + } + return (
{wines.map((wine) => ( diff --git a/src/pages/my-profile/index.tsx b/src/pages/my-profile/index.tsx index e524c4e4..940cb7aa 100644 --- a/src/pages/my-profile/index.tsx +++ b/src/pages/my-profile/index.tsx @@ -29,7 +29,7 @@ export default function MyProfile() { const [winesCount, setWinesCount] = useState(0); return ( -
+
{/* 프로필 섹션 */}