From e1937df2fcdce8206a769635eb4099bd93a71a29 Mon Sep 17 00:00:00 2001 From: NohWookJin Date: Thu, 18 Jan 2024 14:12:43 +0900 Subject: [PATCH 01/17] =?UTF-8?q?feat:=20=EC=B6=94=EA=B0=80,=20=EC=97=84?= =?UTF-8?q?=EC=A7=80=20=EC=95=84=EC=9D=B4=EC=BD=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/icons/Icons.tsx | 87 +++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/src/components/common/icons/Icons.tsx b/src/components/common/icons/Icons.tsx index 493de888..ceca7ad9 100644 --- a/src/components/common/icons/Icons.tsx +++ b/src/components/common/icons/Icons.tsx @@ -1308,3 +1308,90 @@ export const CounterIcon: React.FC< ); }; + +export const ThumbsUp: React.FC = ({ + size = 16, + fill = '#1E1E1E', +}) => { + return ( + + + + + + ); +}; + +export const ThumbsDown: React.FC = ({ + size = 16, + fill = '#1E1E1E', +}) => { + return ( + + + + + ); +}; + +export const NewIcon: React.FC = ({ + size = 11, + fill = '#1E1E1E', +}) => { + return ( + + + + + ); +}; From ee88bcf6e79b5821e3a70d4e37223a9dd6e8a2cd Mon Sep 17 00:00:00 2001 From: NohWookJin Date: Thu, 18 Jan 2024 14:13:13 +0900 Subject: [PATCH 02/17] =?UTF-8?q?feat:=20=EC=9A=B0=EB=A6=AC=EC=9D=98=20?= =?UTF-8?q?=EA=B4=80=EC=8B=AC=EC=97=AC=ED=96=89=EC=A7=80=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/@types/trips.types.ts | 21 +++ src/api/trips.ts | 13 +- src/components/Trip/LikedToursList.tsx | 86 +++++++++++- .../LikedToursLists/LikedToursListBox.tsx | 72 ++++++++++ .../LikedToursListCategory.tsx | 46 +++++++ .../LikedToursListCategoryItem.tsx | 29 ++++ .../LikedToursLists/LikedToursListItem.tsx | 129 ++++++++++++++++++ 7 files changed, 389 insertions(+), 7 deletions(-) create mode 100644 src/components/Trip/LikedToursLists/LikedToursListBox.tsx create mode 100644 src/components/Trip/LikedToursLists/LikedToursListCategory.tsx create mode 100644 src/components/Trip/LikedToursLists/LikedToursListCategoryItem.tsx create mode 100644 src/components/Trip/LikedToursLists/LikedToursListItem.tsx diff --git a/src/@types/trips.types.ts b/src/@types/trips.types.ts index fb708de8..4374a050 100644 --- a/src/@types/trips.types.ts +++ b/src/@types/trips.types.ts @@ -18,3 +18,24 @@ interface MyTripType { area: string; subArea: string; } + +interface ourTripType { + tripLikedItemId: number; + tourItemId: number; + contentTypeId: number; + ratingAverage: number; + reviewCount: number; + smallThumbnailUrl: string; + tourAddress: string; + prefer: boolean; + notPrefer: boolean; + preferTotalCount: number; + notPreferTotalCount: number; +} + +interface ThumbsProps { + tripId: number; + tourId: number; + prefer: boolean; + notPrefer: boolean; +} diff --git a/src/api/trips.ts b/src/api/trips.ts index 3441cb6b..1a395cf4 100644 --- a/src/api/trips.ts +++ b/src/api/trips.ts @@ -35,14 +35,14 @@ export const postTrips = async (tripsData: TripRequest) => { // 우리의 관심목록 조회 export const getTripsLike = async ( tripId: number, - category: number, page: number, size: number, ) => { - const res = await client.get( - `trips/${tripId}/tripLikedTours?category=${category}&page=${page}$size=${size}`, + const res = await authClient.get( + `trips/${tripId}/tripLikedTours?page=${page}&size=${size}`, ); - return res; + + return res.data; }; // 우리의 관심 목록 등록 @@ -56,9 +56,10 @@ export const postTripsLikeHate = async ( tripId: number, tourId: number, prefer: boolean, + notPrefer: boolean, ) => { - const res = await client.post( - `trips/${tripId}/tripLikedTours/${tourId}?prefer=${prefer}`, + const res = await authClient.post( + `trips/${tripId}/tripLikedTours/${tourId}?prefer=${prefer}¬Prefer=${notPrefer}`, ); return res; }; diff --git a/src/components/Trip/LikedToursList.tsx b/src/components/Trip/LikedToursList.tsx index 67119420..de2a69e9 100644 --- a/src/components/Trip/LikedToursList.tsx +++ b/src/components/Trip/LikedToursList.tsx @@ -1,3 +1,87 @@ +import { useState } from 'react'; +import { useParams } from 'react-router-dom'; +import { useInfiniteQuery } from '@tanstack/react-query'; + +import LikedToursListCategory from './LikedToursLists/LikedToursListCategory'; +import LikedToursListBox from './LikedToursLists/LikedToursListBox'; +import NoDataMessage from '@components/common/noData/NoDataMessage'; + +import { getTripsLike } from '@api/trips'; +import { HeartIcon, NewIcon } from '@components/common/icons/Icons'; + export const LikedToursList = () => { - return
LikedToursList
; + const [selectedContentTypeId, setSelectedContentTypeId] = useState< + null | number + >(null); + const params = useParams(); + const [selectedTripId, _] = useState(Number(params.id)); + + const { fetchNextPage, hasNextPage, data, isLoading, error } = + useInfiniteQuery({ + queryKey: ['ourTrips'], + queryFn: ({ pageParam = 0 }) => + getTripsLike(selectedTripId, 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; + }, + }); + + const handleCategoryClick = (contentTypeId: number | null) => { + setSelectedContentTypeId(contentTypeId); + }; + + if (error) { + return
데이터를 불러오는 중 오류가 발생했습니다.
; + } + + return ( +
+ + + {data?.pages[0].data.content.length > 0 ? ( +
+ +
+ ) : ( +
+ } + /> +
+ )} + + {/* 검색 라우터 이동 */} +
+ +
+
+ ); }; diff --git a/src/components/Trip/LikedToursLists/LikedToursListBox.tsx b/src/components/Trip/LikedToursLists/LikedToursListBox.tsx new file mode 100644 index 00000000..56c2db3d --- /dev/null +++ b/src/components/Trip/LikedToursLists/LikedToursListBox.tsx @@ -0,0 +1,72 @@ +import React from 'react'; +import InfiniteScroll from 'react-infinite-scroller'; +import { v4 as uuidv4 } from 'uuid'; +import ToursItemSkeleton from '@components/Tours/ToursItemSkeleton'; +// import { Spinner } from '@components/common/spinner/Spinner'; + +import LikedToursListItem from './LikedToursListItem'; + +interface LikedToursListProps { + toursData: { pages: Array<{ data: { content: ourTripType[] } }> }; + fetchNextPage: () => void; + hasNextPage: boolean; + isLoading: boolean; + selectedContentTypeId: number | null; + selectedTripId: number; +} + +const LikedToursListBox: React.FC = ({ + toursData, + fetchNextPage, + hasNextPage, + isLoading, + selectedContentTypeId, + selectedTripId, +}) => { + if (!toursData || toursData.pages.length === 0) { + return
데이터를 불러오는 중 오류가 발생했습니다.
; + } + + const filteredData = + selectedContentTypeId !== null + ? toursData.pages.map((group) => ({ + data: { + content: group.data.content.filter( + (item) => item.contentTypeId === selectedContentTypeId, + ), + }, + })) + : toursData.pages; + + return ( + fetchNextPage()} + hasMore={hasNextPage} + loader={ +
+ {/* */} +
+ }> +
+ {isLoading + ? Array.from({ length: 10 }, (_, index) => ( + + )) + : filteredData.map((group) => ( + + {group?.data.content.map((ourTripList: ourTripType) => ( + + ))} + + ))} +
+
+ ); +}; + +export default LikedToursListBox; diff --git a/src/components/Trip/LikedToursLists/LikedToursListCategory.tsx b/src/components/Trip/LikedToursLists/LikedToursListCategory.tsx new file mode 100644 index 00000000..8a243c2f --- /dev/null +++ b/src/components/Trip/LikedToursLists/LikedToursListCategory.tsx @@ -0,0 +1,46 @@ +import { useState } from 'react'; +import { LikedToursListCategoryItem } from './LikedToursListCategoryItem'; + +interface LikedToursListCategoryProps { + onCategoryClick: (contentTypeId: number | null) => void; +} + +const LikedToursListCategory: React.FC = ({ + onCategoryClick, +}) => { + const [selectedCategory, setSelectedCategory] = useState('전체'); + + const categories = [ + { code: null, name: '전체' }, + { code: 12, name: '관광지' }, + { code: 32, name: '숙소' }, + { code: 39, name: '식당' }, + ]; + + const handleSelectCategory = (name: string) => { + setSelectedCategory(name); + window.scrollTo({ + top: 0, + left: 0, + behavior: 'smooth', + }); + }; + + return ( +
+ {categories.map((category) => { + return ( + + ); + })} +
+ ); +}; + +export default LikedToursListCategory; diff --git a/src/components/Trip/LikedToursLists/LikedToursListCategoryItem.tsx b/src/components/Trip/LikedToursLists/LikedToursListCategoryItem.tsx new file mode 100644 index 00000000..d795f8f0 --- /dev/null +++ b/src/components/Trip/LikedToursLists/LikedToursListCategoryItem.tsx @@ -0,0 +1,29 @@ +interface LikedToursListCategoryItemProps { + category: { code: number | null; name: string }; + onCategoryClick: (contentTypeId: number | null) => void; + onSelect: (name: string) => void; + isSelected: boolean; +} + +export const LikedToursListCategoryItem: React.FC< + LikedToursListCategoryItemProps +> = ({ category, onCategoryClick, onSelect, isSelected }) => { + const handleCategoryClick = () => { + if (category.code !== undefined) { + onCategoryClick(category.code); + onSelect(category.name); + } + }; + + const buttonStyle = isSelected + ? 'bg-[#28D8FF] text-white font-bold' + : 'bg-[#fff] text-[#888] border-[#ededed]'; + + return ( + + ); +}; diff --git a/src/components/Trip/LikedToursLists/LikedToursListItem.tsx b/src/components/Trip/LikedToursLists/LikedToursListItem.tsx new file mode 100644 index 00000000..4577f448 --- /dev/null +++ b/src/components/Trip/LikedToursLists/LikedToursListItem.tsx @@ -0,0 +1,129 @@ +import { ThumbsUp, ThumbsDown, StarIcon } from '@components/common/icons/Icons'; +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { postTripsLikeHate } from '@api/trips'; +import { useNavigate } from 'react-router-dom'; +import { useState } from 'react'; + +interface LikedToursListItemProps { + ourTripList: ourTripType; + selectedTripId: number; +} + +const LikedToursListItem: React.FC = ({ + ourTripList, + selectedTripId, +}) => { + const { + tourItemId, + ratingAverage, + reviewCount, + prefer, + notPrefer, + preferTotalCount, + notPreferTotalCount, + smallThumbnailUrl, + tourAddress, + } = ourTripList; + const navigate = useNavigate(); + const queryClient = useQueryClient(); + const [thumbsState, setThumbsState] = useState({ + prefer: false, + notPrefer: false, + }); + + const { mutate: thumbsUpMutate } = useMutation({ + mutationFn: () => + postTripsLikeHate( + selectedTripId, + tourItemId, + thumbsState.prefer, + thumbsState.notPrefer, + ), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['ourTrips'] }); + }, + onError: () => console.log('error'), + }); + + const onClickThumbsUpButton = (e: React.MouseEvent) => { + e.stopPropagation(); + setThumbsState({ prefer: true, notPrefer: false }); + thumbsUpMutate(); + }; + + const onClickThumbsDownButton = (e: React.MouseEvent) => { + e.stopPropagation(); + setThumbsState({ prefer: false, notPrefer: true }); + thumbsUpMutate(); + }; + + return ( +
navigate(`/detail/${tourItemId}`)}> +
+
+ 여행지 이미지 +
+ +
+
+

+ 타이틀 +

+ +
+
+
+ +
+ +
+ + {(Math.ceil(ratingAverage * 100) / 100).toFixed(1)} + + + ({reviewCount ? reviewCount.toLocaleString() : reviewCount}) + +
+
+ +
+

+ {tourAddress ? tourAddress : '주소를 제공하지 않고 있어요'} +

+
+
+
+ +
+
+ + +
+
+
+
+
+ ); +}; + +export default LikedToursListItem; From 468b1b812a4171ce4b174775e0de65f62ee58022 Mon Sep 17 00:00:00 2001 From: NohWookJin Date: Thu, 18 Jan 2024 14:21:39 +0900 Subject: [PATCH 03/17] =?UTF-8?q?style:=20truncate=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Trip/LikedToursLists/LikedToursListItem.tsx | 4 ++-- src/components/Wish/WishItem.tsx | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/Trip/LikedToursLists/LikedToursListItem.tsx b/src/components/Trip/LikedToursLists/LikedToursListItem.tsx index 4577f448..765ded43 100644 --- a/src/components/Trip/LikedToursLists/LikedToursListItem.tsx +++ b/src/components/Trip/LikedToursLists/LikedToursListItem.tsx @@ -92,8 +92,8 @@ const LikedToursListItem: React.FC = ({ -
-

+

+

{tourAddress ? tourAddress : '주소를 제공하지 않고 있어요'}

diff --git a/src/components/Wish/WishItem.tsx b/src/components/Wish/WishItem.tsx index 6b30c0b5..e8c12eb9 100644 --- a/src/components/Wish/WishItem.tsx +++ b/src/components/Wish/WishItem.tsx @@ -38,12 +38,12 @@ const WishItem: React.FC = ({ wishList }) => {
-
-

+

+

{title}

-
-

{tourAddress}

+
+

{tourAddress}

From 5083a61582f7df92ef6e02ebc4d3cee680a4b68b Mon Sep 17 00:00:00 2001 From: NohWookJin Date: Thu, 18 Jan 2024 14:29:24 +0900 Subject: [PATCH 04/17] =?UTF-8?q?feat:=20=EC=B6=94=EA=B0=80=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=ED=81=B4=EB=A6=AD=EC=8B=9C=20=EA=B2=80=EC=83=89=20?= =?UTF-8?q?=EB=9D=BC=EC=9A=B0=ED=84=B0=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Trip/LikedToursList.tsx | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/components/Trip/LikedToursList.tsx b/src/components/Trip/LikedToursList.tsx index de2a69e9..b11271da 100644 --- a/src/components/Trip/LikedToursList.tsx +++ b/src/components/Trip/LikedToursList.tsx @@ -1,5 +1,5 @@ import { useState } from 'react'; -import { useParams } from 'react-router-dom'; +import { useNavigate, useParams } from 'react-router-dom'; import { useInfiniteQuery } from '@tanstack/react-query'; import LikedToursListCategory from './LikedToursLists/LikedToursListCategory'; @@ -13,7 +13,10 @@ export const LikedToursList = () => { const [selectedContentTypeId, setSelectedContentTypeId] = useState< null | number >(null); + + const navigate = useNavigate(); const params = useParams(); + const [selectedTripId, _] = useState(Number(params.id)); const { fetchNextPage, hasNextPage, data, isLoading, error } = @@ -40,14 +43,14 @@ export const LikedToursList = () => { }, }); - const handleCategoryClick = (contentTypeId: number | null) => { - setSelectedContentTypeId(contentTypeId); - }; - if (error) { return
데이터를 불러오는 중 오류가 발생했습니다.
; } + const handleCategoryClick = (contentTypeId: number | null) => { + setSelectedContentTypeId(contentTypeId); + }; + return (
@@ -73,9 +76,11 @@ export const LikedToursList = () => {
)} - {/* 검색 라우터 이동 */} + {/* 우리의 관심 여행지 추가 버튼 => 검색 라우터 이동 */}
-
); } diff --git a/src/components/DetailSectionTop/DetailToursRating.tsx b/src/components/DetailSectionTop/DetailToursRating.tsx index 0178f248..2be49e9c 100644 --- a/src/components/DetailSectionTop/DetailToursRating.tsx +++ b/src/components/DetailSectionTop/DetailToursRating.tsx @@ -1,5 +1,8 @@ import { useEffect, useState } from 'react'; import { Link } from 'react-scroll'; +import { useSetRecoilState } from 'recoil'; +import { reviewCountState } from '@recoil/review'; + interface ReviewData { ratingAverage: number; reviewTotalCount: number; @@ -13,6 +16,7 @@ export default function DetailToursRating({ reviewData, }: DetailToursRatingProps) { const { reviewTotalCount, ratingAverage } = reviewData; + const setReviewCount = useSetRecoilState(reviewCountState); const STAR_IDX_ARR = ['1', '2', '3', '4', '5']; const [ratedStarArr, setRatedStarArr] = useState([0, 0, 0, 0, 0]); @@ -32,6 +36,7 @@ export default function DetailToursRating({ useEffect(() => { setRatedStarArr(calculateRates(ratingAverage)); + setReviewCount(reviewTotalCount); }, []); return ( diff --git a/src/pages/detail/detail.page.tsx b/src/pages/detail/detail.page.tsx index bcccedb5..cee1949a 100644 --- a/src/pages/detail/detail.page.tsx +++ b/src/pages/detail/detail.page.tsx @@ -2,20 +2,15 @@ import { DetailHeader } from '@components/common/header'; import DetailSectionTop from '@components/DetailSectionTop/DetailSectionTop'; import DetailSectionBottom from '@components/DetailSectionBottom/DetailSectionBottom'; import { DetailTopButton } from '@components/DetailSectionTop'; -import { useRef } from 'react'; const DetailTours = () => { - const parentRef = useRef(null); - return ( -
+ <> -
- - -
-
+ + + ); }; diff --git a/src/recoil/review.ts b/src/recoil/review.ts index 6bb84cc2..1c9753e1 100644 --- a/src/recoil/review.ts +++ b/src/recoil/review.ts @@ -88,3 +88,8 @@ export const inputFocusState = atom({ key: 'inputFocusState', default: false, }); + +export const reviewCountState = atom({ + key: 'reviewCountState', + default: 0, +}); From e82075bc56d195f22055f23f77ee7634a1b1511c Mon Sep 17 00:00:00 2001 From: NohWookJin Date: Thu, 18 Jan 2024 17:36:55 +0900 Subject: [PATCH 06/17] =?UTF-8?q?refactor:=20API=20=EC=A0=9C=EB=AA=A9=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/@types/trips.types.ts | 1 + src/components/Trip/LikedToursLists/LikedToursListItem.tsx | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/@types/trips.types.ts b/src/@types/trips.types.ts index 4374a050..b265e709 100644 --- a/src/@types/trips.types.ts +++ b/src/@types/trips.types.ts @@ -31,6 +31,7 @@ interface ourTripType { notPrefer: boolean; preferTotalCount: number; notPreferTotalCount: number; + title: string; } interface ThumbsProps { diff --git a/src/components/Trip/LikedToursLists/LikedToursListItem.tsx b/src/components/Trip/LikedToursLists/LikedToursListItem.tsx index 765ded43..70d0c6f2 100644 --- a/src/components/Trip/LikedToursLists/LikedToursListItem.tsx +++ b/src/components/Trip/LikedToursLists/LikedToursListItem.tsx @@ -23,6 +23,7 @@ const LikedToursListItem: React.FC = ({ notPreferTotalCount, smallThumbnailUrl, tourAddress, + title, } = ourTripList; const navigate = useNavigate(); const queryClient = useQueryClient(); @@ -71,9 +72,9 @@ const LikedToursListItem: React.FC = ({
-
-

- 타이틀 +

+

+ {title}

From 0f71e770d24310cd08852f01f275cc0d8c14cfd3 Mon Sep 17 00:00:00 2001 From: WookJin Date: Thu, 18 Jan 2024 18:39:00 +0900 Subject: [PATCH 07/17] Update DetailTopButton.tsx --- src/components/DetailSectionTop/DetailTopButton.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/DetailSectionTop/DetailTopButton.tsx b/src/components/DetailSectionTop/DetailTopButton.tsx index eb557523..2e5cd923 100644 --- a/src/components/DetailSectionTop/DetailTopButton.tsx +++ b/src/components/DetailSectionTop/DetailTopButton.tsx @@ -14,8 +14,9 @@ export default function DetailTopButton() { setVisible(false); } }, [getReviewCount]); - - const scrollToTop = () => { + + const scrollToTop = (e: React.MouseEvent) => { + e.stopPropagation(); window.scrollTo({ top: 0, behavior: 'smooth' }); }; From 52920fbccc91b7884bf35b2d665147fa361e5002 Mon Sep 17 00:00:00 2001 From: WookJin Date: Fri, 19 Jan 2024 13:59:45 +0900 Subject: [PATCH 08/17] Update LikedToursListItem.tsx --- src/components/Trip/LikedToursLists/LikedToursListItem.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Trip/LikedToursLists/LikedToursListItem.tsx b/src/components/Trip/LikedToursLists/LikedToursListItem.tsx index 70d0c6f2..b0a1092b 100644 --- a/src/components/Trip/LikedToursLists/LikedToursListItem.tsx +++ b/src/components/Trip/LikedToursLists/LikedToursListItem.tsx @@ -106,7 +106,7 @@ const LikedToursListItem: React.FC = ({
diff --git a/src/components/common/tab/Tab.tsx b/src/components/common/tab/Tab.tsx index 3ae8f972..de746353 100644 --- a/src/components/common/tab/Tab.tsx +++ b/src/components/common/tab/Tab.tsx @@ -1,37 +1,53 @@ import * as Tabs from '@radix-ui/react-tabs'; +import { useRecoilState } from 'recoil'; +import { tapState } from '@recoil/plan'; interface TabProps { lists: string[]; contents: React.ReactNode[]; } -const Tab = ({ lists, contents }: TabProps) => ( - - - {lists.map((list, index) => { +const Tab = ({ lists, contents }: TabProps) => { + const [, setTapState] = useRecoilState(tapState); + + const handleTabChange = (value: string) => { + const tabIndex = value.replace('tab', ''); + if (tabIndex !== '') { + setTapState(tabIndex); + } + }; + + return ( + + + {lists.map((list, index) => { + return ( + + {list} + + ); + })} + + {contents.map((content, index) => { return ( - - {list} - + {content} + ); })} - - {contents.map((content, index) => { - return ( - - {content} - - ); - })} - -); + + ); +}; export default Tab; diff --git a/src/hooks/useSocket.ts b/src/hooks/useSocket.ts index 50c9e2d6..78928526 100644 --- a/src/hooks/useSocket.ts +++ b/src/hooks/useSocket.ts @@ -83,6 +83,7 @@ export const useSocket = (tripId: string, visitDate: string) => { useEffect(() => { socketConnect(); + console.log('소켓연결'); return () => { socketClient.deactivate(); diff --git a/src/recoil/plan.ts b/src/recoil/plan.ts index c938efaa..42e69971 100644 --- a/src/recoil/plan.ts +++ b/src/recoil/plan.ts @@ -9,3 +9,8 @@ export const dateState = atom({ key: 'dateState', default: [''], }); + +export const tapState = atom({ + key: 'tapState', + default: '', +}); diff --git a/src/recoil/socket.ts b/src/recoil/socket.ts index d722c733..ab7bb76b 100644 --- a/src/recoil/socket.ts +++ b/src/recoil/socket.ts @@ -10,7 +10,7 @@ export const visitDateState = atom<{ visitDate: string } | null>({ default: { visitDate: '2024-01-03' }, }); -export const memberIdState = atom<{ memberId: number } | null>({ +export const memberIdState = atom<{ token: number | null }>({ key: 'memberIdState', - default: { memberId: 1 }, + default: { token: null }, }); diff --git a/src/router/socketRouter.tsx b/src/router/socketRouter.tsx index a48c16dc..e679617b 100644 --- a/src/router/socketRouter.tsx +++ b/src/router/socketRouter.tsx @@ -19,9 +19,9 @@ const SocketRoutes = () => { return ( - } /> - } /> - } /> + } /> + } /> + } /> ); @@ -33,7 +33,7 @@ const SocketRouter = () => { }> } /> } /> - } /> + } /> ); From 1917a2f86a84552087f5ec8eef15ca61afb87599 Mon Sep 17 00:00:00 2001 From: sue Date: Fri, 19 Jan 2024 18:47:05 +0900 Subject: [PATCH 10/17] =?UTF-8?q?Design:=20=EC=97=AC=ED=96=89=20=EA=B3=84?= =?UTF-8?q?=ED=9A=8D=20=EC=95=84=EC=9D=B4=EC=BD=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Trip/PlanTripButton.tsx | 8 +++---- src/components/common/icons/Icons.tsx | 32 ++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/components/Trip/PlanTripButton.tsx b/src/components/Trip/PlanTripButton.tsx index bd5ac6fc..327360e5 100644 --- a/src/components/Trip/PlanTripButton.tsx +++ b/src/components/Trip/PlanTripButton.tsx @@ -1,18 +1,16 @@ -import { PlanIcon, RightIcon } from '@components/common/icons/Icons'; +import { PlanColorIcon, RightIcon } from '@components/common/icons/Icons'; const PlanTripButton = () => { return ( - ); diff --git a/src/components/common/icons/Icons.tsx b/src/components/common/icons/Icons.tsx index 34987b1f..f0097365 100644 --- a/src/components/common/icons/Icons.tsx +++ b/src/components/common/icons/Icons.tsx @@ -1499,3 +1499,35 @@ export const PaperIcon: React.FC = ({}) => { ); }; + +export const PlanColorIcon = () => { + return ( + + + + + + + ); +}; From 6d7425ad0117e9b06f46a91699c66443ecbd0616 Mon Sep 17 00:00:00 2001 From: sue Date: Fri, 19 Jan 2024 18:48:15 +0900 Subject: [PATCH 11/17] =?UTF-8?q?Design:=20=ED=8E=B8=EC=A7=91=20=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/components/Trip/TripInfo.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/components/Trip/TripInfo.tsx b/src/components/Trip/TripInfo.tsx index 5594c89a..902263e6 100644 --- a/src/components/Trip/TripInfo.tsx +++ b/src/components/Trip/TripInfo.tsx @@ -113,9 +113,6 @@ const TripInfo = () => { 5
-
23.12.23 - 23.12.25
From e5e954b76d29b42406103d174771e6d1aaffcd09 Mon Sep 17 00:00:00 2001 From: Hojin Date: Fri, 19 Jan 2024 18:50:39 +0900 Subject: [PATCH 12/17] =?UTF-8?q?Feat:=20=EA=B6=8C=ED=95=9C=ED=99=95?= =?UTF-8?q?=EC=9D=B8=20=EC=BB=A4=EC=8A=A4=ED=85=80=ED=9B=85=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 --- src/@types/trips.types.ts | 10 +++++++ src/api/trips.ts | 6 ++++ src/components/Trip/TripSectionTop.tsx | 2 ++ src/hooks/useGetTripsAuthority.ts | 39 ++++++++++++++++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 src/hooks/useGetTripsAuthority.ts diff --git a/src/@types/trips.types.ts b/src/@types/trips.types.ts index fb708de8..9aa18b2d 100644 --- a/src/@types/trips.types.ts +++ b/src/@types/trips.types.ts @@ -18,3 +18,13 @@ interface MyTripType { area: string; subArea: string; } + +interface AuthorityType { + status: number; + message: string; + data: { + memberId: number; + tripAuthority: string; + TripId: number; + }; +} diff --git a/src/api/trips.ts b/src/api/trips.ts index be019a7f..f327e7a3 100644 --- a/src/api/trips.ts +++ b/src/api/trips.ts @@ -84,3 +84,9 @@ export const getTripsMembers = async (tripId: number) => { const res = await client.get(`trips/${tripId}/members`); return res; }; + +// 편집권한 조회 +export const getTripsAuthority = async (tripId: string) => { + const res = await authClient.get(`trips/${tripId}/authority`); + return res; +}; diff --git a/src/components/Trip/TripSectionTop.tsx b/src/components/Trip/TripSectionTop.tsx index 82e03c8e..4f1062eb 100644 --- a/src/components/Trip/TripSectionTop.tsx +++ b/src/components/Trip/TripSectionTop.tsx @@ -5,9 +5,11 @@ import { BackBox } from '@components/common'; import { useNavigate } from 'react-router-dom'; import PlanTripButton from './PlanTripButton'; import { LikedToursList } from './LikedToursList'; +import { useGetTripsAuthority } from '@hooks/useGetTripsAuthority'; const TripSectionTop = () => { const navigate = useNavigate(); + const { tripAuthority } = useGetTripsAuthority(); return (
diff --git a/src/hooks/useGetTripsAuthority.ts b/src/hooks/useGetTripsAuthority.ts new file mode 100644 index 00000000..efef5695 --- /dev/null +++ b/src/hooks/useGetTripsAuthority.ts @@ -0,0 +1,39 @@ +import { useQuery } from '@tanstack/react-query'; +import { getTripsAuthority } from '@api/trips'; + +import { useParams } from 'react-router-dom'; + +type useGetTripsAuthorityReturn = { + tripAuthority: string | null; + memberId: number | null; + TripId: number | null; +}; + +export const useGetTripsAuthority = (): useGetTripsAuthorityReturn => { + const { id } = useParams(); + + const defaultReturn = { + tripAuthority: null, + memberId: null, + TripId: null, + }; + + if (!id) { + return defaultReturn; + } + const { data, isLoading, isError } = useQuery({ + queryKey: ['getTripsAuthority', id], + queryFn: () => getTripsAuthority(id), + enabled: !!id, + }); + + const tripAuthority = data?.data.data.tripAuthority; + const memberId = data?.data.data.memberId; + const TripId = data?.data.data.TripId; + + if (isLoading || isError) { + return defaultReturn; + } + + return { tripAuthority, memberId, TripId }; +}; From 7235e9a7d914f949d8535839e0f9e9e4dff47803 Mon Sep 17 00:00:00 2001 From: sue Date: Fri, 19 Jan 2024 23:09:00 +0900 Subject: [PATCH 13/17] =?UTF-8?q?Feat:=20=EA=B2=BD=EB=B9=84=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EC=86=8C=EC=BC=93=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Plan/TripBudget.tsx | 82 +++++++++++++++++------------- src/components/Plan/TripMap.tsx | 6 +-- 2 files changed, 48 insertions(+), 40 deletions(-) diff --git a/src/components/Plan/TripBudget.tsx b/src/components/Plan/TripBudget.tsx index bac3e435..9898b7d6 100644 --- a/src/components/Plan/TripBudget.tsx +++ b/src/components/Plan/TripBudget.tsx @@ -1,37 +1,43 @@ +import { pubUpdateBudget } from '@api/socket'; import Alert from '@components/common/alert/Alert'; -import { SettingIcons } from '@components/common/icons/Icons'; +import { CloseIcon, SettingIcons } from '@components/common/icons/Icons'; import { socketContext } from '@hooks/useSocket'; import * as Progress from '@radix-ui/react-progress'; -import { useContext, useEffect, useState } from 'react'; +import { tripIdState } from '@recoil/socket'; +import { useContext, useState } from 'react'; +import { useRecoilValue } from 'recoil'; const TripBudget = () => { const { tripBudget } = useContext(socketContext); - const budget = tripBudget?.data; - - const [targetBudget, setTargetBudget] = useState(0); // 예시 목표 경비 - const [currentSpending, setCurrentSpending] = useState(0); // 초기 사용 경비 + const tripId = useRecoilValue(tripIdState); - useEffect(() => { - if (budget) { - setTargetBudget(budget.budget || 0); - setCurrentSpending( - budget.calculatedPrice >= 0 ? budget.calculatedPrice : 0, - ); - } - }, [budget]); + const budget = tripBudget?.data; // 프로그레스 바 값 계산 const progress = Math.min( - currentSpending && targetBudget - ? (currentSpending / targetBudget) * 100 + budget?.calculatedPrice && budget.budget + ? (budget.calculatedPrice / budget.budget) * 100 : 0, 100, ); - // // 목표 경비 설정 함수 - // const handleSetTargetBudget = (newTargetBudget: number) => { - // setTargetBudget(newTargetBudget); - // }; + const [inputBudget, setInputBudget] = useState(''); + + const showCloseIcon = inputBudget; + + // 목표 경비 설정 함수 + const handleSetTargetBudget = (inputBudget: string) => { + const newTargetBudget = parseInt(inputBudget, 10); // 문자열 숫자로 변환 + if (!isNaN(newTargetBudget) && newTargetBudget !== budget?.budget) { + pubUpdateBudget( + { + budget: newTargetBudget, + }, + tripId || '', + ); + setInputBudget(''); + } + }; return ( <> @@ -39,13 +45,13 @@ const TripBudget = () => {
사용 경비
- {currentSpending.toLocaleString()} + {budget?.calculatedPrice.toLocaleString()}
{ { - console.log('확인'); - }} - onCancel={() => { - console.log('취소'); - }} + onConfirm={() => handleSetTargetBudget(inputBudget)} + closeOnConfirm={true} children={
- {targetBudget.toLocaleString()} + {budget?.budget.toLocaleString()}
diff --git a/src/components/Plan/TripMap.tsx b/src/components/Plan/TripMap.tsx index 9816403e..02c3787a 100644 --- a/src/components/Plan/TripMap.tsx +++ b/src/components/Plan/TripMap.tsx @@ -100,8 +100,6 @@ const TripMap = ({ paths }: { paths: Paths[] }) => { // 선택된 마커의 인덱스를 추적하기 위한 상태 const [selectedMarker, setSelectedMarker] = useState(null); - // ... - // 마커를 클릭할 때 호출되는 함수 const handleMarkerClick = (index: number) => { setSelectedMarker(index); @@ -127,14 +125,12 @@ const TripMap = ({ paths }: { paths: Paths[] }) => { svgComponent = isSelected ? FifthSelectedMarker : FifthMarker; break; default: - // 기본 마커가 필요한 경우 기본 마커 이미지 URL을 제공합니다. + // 기본 마커 return 'default_marker_image_url'; } return svgComponent; }; - // ... TripMap 컴포넌트 및 나머지 코드 - return (
Date: Fri, 19 Jan 2024 23:09:24 +0900 Subject: [PATCH 14/17] =?UTF-8?q?Design:=20Tab=20=EC=A1=B0=EA=B1=B4?= =?UTF-8?q?=EB=B6=80=20css?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/tab/Tab.tsx | 58 +++++++++++++++++++------------ 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/src/components/common/tab/Tab.tsx b/src/components/common/tab/Tab.tsx index 3ae8f972..96effc11 100644 --- a/src/components/common/tab/Tab.tsx +++ b/src/components/common/tab/Tab.tsx @@ -5,33 +5,45 @@ interface TabProps { contents: React.ReactNode[]; } -const Tab = ({ lists, contents }: TabProps) => ( - - - {lists.map((list, index) => { +const Tab = ({ lists, contents }: TabProps) => { + let isDayTab = false; + + lists.forEach((list) => { + if (list.includes('DAY')) { + isDayTab = true; + } + }); + + return ( + + + {lists.map((list, index) => { + return ( + + {list} + + ); + })} + + {contents.map((content, index) => { return ( - - {list} - + {content} + ); })} - - {contents.map((content, index) => { - return ( - - {content} - - ); - })} - -); + + ); +}; export default Tab; From b14d584c898bb217cdfdb4966aca622c22241d3a Mon Sep 17 00:00:00 2001 From: sue Date: Sat, 20 Jan 2024 00:30:58 +0900 Subject: [PATCH 15/17] =?UTF-8?q?Design:=20Tab=20padding=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Plan/TripMap.tsx | 5 ++--- src/components/Trip/LikedToursList.tsx | 2 +- src/components/Trip/TripParticipant.tsx | 2 +- src/components/Trip/TripPreference.tsx | 2 +- src/components/common/tab/Tab.tsx | 2 +- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/components/Plan/TripMap.tsx b/src/components/Plan/TripMap.tsx index 02c3787a..7c167103 100644 --- a/src/components/Plan/TripMap.tsx +++ b/src/components/Plan/TripMap.tsx @@ -50,7 +50,6 @@ const TripMap = ({ paths }: { paths: Paths[] }) => { const MapStyle = { width: '100%', height: '180px', - marginTop: '15px', transition: 'height 0.3s ease-in-out', }; @@ -132,13 +131,13 @@ const TripMap = ({ paths }: { paths: Paths[] }) => { }; return ( -
+
{paths.map((path, index) => (
diff --git a/src/components/Trip/LikedToursList.tsx b/src/components/Trip/LikedToursList.tsx index b11271da..eab8eeea 100644 --- a/src/components/Trip/LikedToursList.tsx +++ b/src/components/Trip/LikedToursList.tsx @@ -52,7 +52,7 @@ export const LikedToursList = () => { }; return ( -
+
{data?.pages[0].data.content.length > 0 ? ( diff --git a/src/components/Trip/TripParticipant.tsx b/src/components/Trip/TripParticipant.tsx index 934aa95e..70e9ab33 100644 --- a/src/components/Trip/TripParticipant.tsx +++ b/src/components/Trip/TripParticipant.tsx @@ -33,7 +33,7 @@ export const ParticipantStatus: React.FC = ({ const participants = useRecoilValue(participantsState); return ( -
+
{status == '참여' ? ( <>{participants?.tripSurveyMemberCount}명 참여 diff --git a/src/components/Trip/TripPreference.tsx b/src/components/Trip/TripPreference.tsx index 02f71976..5535c9db 100644 --- a/src/components/Trip/TripPreference.tsx +++ b/src/components/Trip/TripPreference.tsx @@ -154,7 +154,7 @@ const TripPreference: React.FC = () => { }; return ( -
+
{ return ( {content} From b66f730174010787053085e09e08728e105ca2fc Mon Sep 17 00:00:00 2001 From: sue Date: Sat, 20 Jan 2024 00:31:28 +0900 Subject: [PATCH 16/17] =?UTF-8?q?Design:=20=EA=B2=BD=EB=B9=84=20=EB=A7=90?= =?UTF-8?q?=ED=92=8D=EC=84=A0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Plan/TripBudget.tsx | 32 +++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/src/components/Plan/TripBudget.tsx b/src/components/Plan/TripBudget.tsx index 9898b7d6..07b33ecf 100644 --- a/src/components/Plan/TripBudget.tsx +++ b/src/components/Plan/TripBudget.tsx @@ -41,11 +41,11 @@ const TripBudget = () => { return ( <> -
+
사용 경비
- {budget?.calculatedPrice.toLocaleString()} + {budget?.calculatedPrice.toLocaleString() ?? '-'}
@@ -79,6 +79,32 @@ const TripBudget = () => { children={ } content={ @@ -104,7 +130,7 @@ const TripBudget = () => { />
- {budget?.budget.toLocaleString()} + {budget?.budget.toLocaleString() ?? '- '}
From d4eceb9ebec963ae5463cb83cf8bc5c09238263f Mon Sep 17 00:00:00 2001 From: sue Date: Sat, 20 Jan 2024 00:35:08 +0900 Subject: [PATCH 17/17] =?UTF-8?q?Chore:=20=EB=B9=8C=EB=93=9C=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Plan/PlanItem.tsx | 3 ++- src/components/Trip/TripSectionTop.tsx | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/Plan/PlanItem.tsx b/src/components/Plan/PlanItem.tsx index 49c410f4..a49109f6 100644 --- a/src/components/Plan/PlanItem.tsx +++ b/src/components/Plan/PlanItem.tsx @@ -4,7 +4,7 @@ import { useNavigate } from 'react-router-dom'; import TripMap from './TripMap'; import PlanItemBox from './PlanItemBox'; import PlanEditItemBox from './PlanEditItemBox'; -import { useContext, useEffect, useState, useRef } from 'react'; +import { useContext, useEffect, useState } from 'react'; import { socketContext } from '@hooks/useSocket'; import { useRecoilState, useRecoilValue } from 'recoil'; import { visitDateState } from '@recoil/socket'; @@ -27,6 +27,7 @@ const PlanItem: React.FC = ({ date, day, isMount }) => { const [visitDate, setVisitDate] = useRecoilState(visitDateState); const { tripItem, tripPath, callBackPub } = useContext(socketContext); + console.log(visitDate); useEffect(() => { if (isMount) { diff --git a/src/components/Trip/TripSectionTop.tsx b/src/components/Trip/TripSectionTop.tsx index 4f1062eb..59ef58eb 100644 --- a/src/components/Trip/TripSectionTop.tsx +++ b/src/components/Trip/TripSectionTop.tsx @@ -11,6 +11,8 @@ const TripSectionTop = () => { const navigate = useNavigate(); const { tripAuthority } = useGetTripsAuthority(); + console.log(tripAuthority); + return (