diff --git a/src/@types/trips.types.ts b/src/@types/trips.types.ts index cda8b28b..accc7011 100644 --- a/src/@types/trips.types.ts +++ b/src/@types/trips.types.ts @@ -6,3 +6,13 @@ interface TripRequest { area: string; subarea: string; } + +interface MyTripType { + tripId: number; + tripName: string; + startDate: string; + endDate: string; + numberOfTripMembers: number; + tripStatus: string; + tripThumbnailUrl: string; +} diff --git a/src/api/member.ts b/src/api/member.ts index 1e355324..0a5e6093 100644 --- a/src/api/member.ts +++ b/src/api/member.ts @@ -44,9 +44,13 @@ export const deleteMember = async () => { }; // 나의 여정 조회 -export const getMemberTrips = async () => { - const res = await authClient.get(`member/trips`); - return res; +export const getMemberTrips = async (page?: number, size?: number) => { + try { + const res = await authClient.get(`trips?&page=${page}&size=${size}`); + return res.data; + } catch (e) { + console.error(e); + } }; // 나의 관심 여행지 조회 diff --git a/src/components/MyTrip/CreateMyTripButton.tsx b/src/components/MyTrip/CreateMyTripButton.tsx new file mode 100644 index 00000000..347d70ed --- /dev/null +++ b/src/components/MyTrip/CreateMyTripButton.tsx @@ -0,0 +1,9 @@ +const CreateMyTripButton = () => { + return ( +
+ +
+ ); +}; + +export default CreateMyTripButton; diff --git a/src/components/MyTrip/MyTrip.tsx b/src/components/MyTrip/MyTrip.tsx new file mode 100644 index 00000000..3d7a7813 --- /dev/null +++ b/src/components/MyTrip/MyTrip.tsx @@ -0,0 +1,59 @@ +import { useInfiniteQuery } from '@tanstack/react-query'; +import MyTripList from './MyTripList'; +import NoDataMessage from '@components/common/noData/NoDataMessage'; +import { getMemberTrips } from '@api/member'; +import { PenIcon } from '@components/common/icons/Icons'; + +const MyTrip = () => { + const { fetchNextPage, hasNextPage, data, isLoading, error } = + useInfiniteQuery({ + queryKey: ['wishList'], + queryFn: ({ pageParam = 0 }) => getMemberTrips(pageParam, 10), + initialPageParam: 0, + getNextPageParam: (lastPage) => { + if ( + lastPage && + lastPage.data && + lastPage.data && + lastPage.data.pageable + ) { + const currentPage = lastPage.data.pageable.pageNumber; + const totalPages = lastPage.data.totalPages; + + if (currentPage < totalPages - 1) { + return currentPage + 1; + } + } + return undefined; + }, + }); + + if (error) { + return
데이터를 불러오는 중 오류가 발생했습니다.
; + } + + return ( +
+
+

나의 여정

+
+ + {data?.pages[0].data.content.length > 0 ? ( + + ) : ( + } + /> + )} +
+ ); +}; + +export default MyTrip; diff --git a/src/components/MyTrip/MyTripItem.tsx b/src/components/MyTrip/MyTripItem.tsx new file mode 100644 index 00000000..aff1a8da --- /dev/null +++ b/src/components/MyTrip/MyTripItem.tsx @@ -0,0 +1,72 @@ +import { MoreIcon } from '@components/common/icons/Icons'; + +interface MyTripItemProps { + myTripList: MyTripType; +} + +const MyTripItem: React.FC = ({ myTripList }) => { + const { + tripName, + startDate, + endDate, + numberOfTripMembers, + tripStatus, + tripThumbnailUrl, + } = myTripList; + + const ACTIVE_TRIP = '여행 중'; + const COMPLETED_TRIP = '여행 후'; + + return ( +
+
+
+ 여행지 이미지 +
+ +
+
+
+
+
+ + {tripStatus} + +
+
+ {tripName} +
+
+ {startDate} ~ {endDate} +
+
+
+ {numberOfTripMembers}명과 공유중 +
+
+
+
+
+
+ ); +}; + +export default MyTripItem; diff --git a/src/components/MyTrip/MyTripList.tsx b/src/components/MyTrip/MyTripList.tsx new file mode 100644 index 00000000..bfb6ca22 --- /dev/null +++ b/src/components/MyTrip/MyTripList.tsx @@ -0,0 +1,56 @@ +import React from 'react'; +import InfiniteScroll from 'react-infinite-scroller'; +import { v4 as uuidv4 } from 'uuid'; +import ToursItemSkeleton from '@components/Tours/ToursItemSkeleton'; +import MyTripItem from './MyTripItem'; + +interface MyTripListProps { + myTripsData: { pages: Array<{ data: { content: MyTripType[] } }> }; + fetchNextPage: () => void; + hasNextPage: boolean; + isLoading: boolean; +} + +const MyTripList: React.FC = ({ + myTripsData, + fetchNextPage, + hasNextPage, + isLoading, +}) => { + if (!myTripsData || myTripsData.pages.length === 0) { + return
데이터를 불러오는 중 오류가 발생했습니다.
; + } + + return ( + fetchNextPage()} + hasMore={hasNextPage} + loader={ +
+
+
Loading...
+
+
+ }> +
+ {isLoading + ? Array.from({ length: 10 }, (_, index) => ( + + )) + : myTripsData.pages.map((group) => ( + + {group?.data.content.map((myTripList: MyTripType) => ( + + ))} + + ))} +
+
+ ); +}; + +export default MyTripList; diff --git a/src/components/Mypage/MypageList.tsx b/src/components/Mypage/MypageList.tsx index 266dad60..ed6dbbae 100644 --- a/src/components/Mypage/MypageList.tsx +++ b/src/components/Mypage/MypageList.tsx @@ -3,7 +3,7 @@ import MypageItem from './MypageItem'; const MypageList = () => { return (
- 나의 여정 + 나의 여정 나의 관심 여행지 나의 리뷰 나의 여행 취향 설정 diff --git a/src/components/Wish/Wish.tsx b/src/components/Wish/Wish.tsx index af2d8acb..6a0e219a 100644 --- a/src/components/Wish/Wish.tsx +++ b/src/components/Wish/Wish.tsx @@ -1,9 +1,9 @@ import { useState } from 'react'; import { useInfiniteQuery } from '@tanstack/react-query'; -import { getMemberTours } from '@api/member'; import WishCategory from './WishCategory'; import WishList from './WishList'; import NoDataMessage from '@components/common/noData/NoDataMessage'; +import { getMemberTours } from '@api/member'; import { HeartIcon } from '@components/common/icons/Icons'; const Wish = () => { diff --git a/src/components/Wish/WishItem.tsx b/src/components/Wish/WishItem.tsx index e0cfb679..6b30c0b5 100644 --- a/src/components/Wish/WishItem.tsx +++ b/src/components/Wish/WishItem.tsx @@ -57,7 +57,7 @@ const WishItem: React.FC = ({ wishList }) => { {(Math.ceil(ratingAverage * 100) / 100).toFixed(1)} - ({reviewCount.toLocaleString()}) + ({reviewCount ? reviewCount.toLocaleString() : reviewCount})
@@ -66,7 +66,7 @@ const WishItem: React.FC = ({ wishList }) => { - {likedCount.toLocaleString()} + {likedCount ? likedCount.toLocaleString() : likedCount} diff --git a/src/components/common/icons/Icons.tsx b/src/components/common/icons/Icons.tsx index 3c28aa46..ca6db260 100644 --- a/src/components/common/icons/Icons.tsx +++ b/src/components/common/icons/Icons.tsx @@ -119,6 +119,80 @@ export const CalendarIcon: React.FC = ({ ); }; +export const CalendarIcon2: React.FC = ({ size = 25 }) => { + return ( + + + + + + + + + + + + ); +}; + export const HeartIcon: React.FC = ({ size = 25, color = 'black', diff --git a/src/components/common/nav/Nav.tsx b/src/components/common/nav/Nav.tsx index e99f5789..5fb9d35a 100644 --- a/src/components/common/nav/Nav.tsx +++ b/src/components/common/nav/Nav.tsx @@ -1,5 +1,11 @@ import { useLocation, useNavigate } from 'react-router-dom'; -import { CalendarIcon, HeartIcon, HomeIcon, UserIcon } from '../icons/Icons'; +import { + CalendarIcon, + CalendarIcon2, + HeartIcon, + HomeIcon, + UserIcon, +} from '../icons/Icons'; import { useEffect, useState } from 'react'; import Alert from '../alert/Alert'; @@ -38,12 +44,37 @@ const Nav = () => {

-
navigate('/')} - className="cursor-pointer flex-col items-center justify-center px-2"> - -

일정

-
+ + {isLoggedIn ? ( +
navigate('/mytrip')} + className="cursor-pointer flex-col items-center justify-center px-2"> +
+ {isActive('/mytrip') ? : } +
+

여정

+
+ ) : ( + + 나의 여정 조회를 위해 로그인이 필요합니다. +
+ 로그인 하시겠습니까? + + } + onConfirm={handleConfirm}> +
+
+ +
+

+ 여정 +

+
+
+ )} {isLoggedIn ? (
{ + return ( + <> + + + + ); +}; + +export default MyTripPage; diff --git a/src/router/mainRouter.tsx b/src/router/mainRouter.tsx index c91a2dce..1cbe518c 100644 --- a/src/router/mainRouter.tsx +++ b/src/router/mainRouter.tsx @@ -5,6 +5,7 @@ import Detail from '@pages/detail/detail.page'; import ReviewComment from '@pages/reviewComment/reviewComment.page'; import ReviewPosting from '@pages/reviewPosting/reviewPosting.page'; import WishList from '@pages/wishList/wishList.page'; +import MyTripPage from '@pages/myTrip/myTrip.page'; import MyPageReview from '@pages/myPageReview/myPageReview.page'; import { Signup, SignupSuccess, SignupSurvey, SignupInfo } from '@pages/signup'; import { Login, LoginKakao } from '@pages/login'; @@ -31,6 +32,7 @@ const MainRouter = () => { } /> } /> } /> + } /> } /> } /> } />