diff --git a/src/@types/socket.types.ts b/src/@types/socket.types.ts index 9434e981..757e3b28 100644 --- a/src/@types/socket.types.ts +++ b/src/@types/socket.types.ts @@ -132,7 +132,7 @@ interface pubDeleteItem { } interface pubMember { - memberId: number; + token: string; } interface pubGetPathAndItems { diff --git a/src/@types/trips.types.ts b/src/@types/trips.types.ts index fb708de8..3197ccfe 100644 --- a/src/@types/trips.types.ts +++ b/src/@types/trips.types.ts @@ -18,3 +18,35 @@ 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; + title: string; +} + +interface ThumbsProps { + tripId: number; + tourId: number; + prefer: boolean; + notPrefer: boolean; +} + +interface AuthorityType { + status: number; + message: string; + data: { + memberId: number; + tripAuthority: string; + TripId: number; + }; +} diff --git a/src/api/socket.ts b/src/api/socket.ts index 2be1d259..000830cf 100644 --- a/src/api/socket.ts +++ b/src/api/socket.ts @@ -102,8 +102,7 @@ export const pubUpdateTripItem = ( body: JSON.stringify(pubUpdateTripItem), }); - console.log(pubUpdateTripItem); - console.log('펍실행'); + console.log('데이터', pubUpdateTripItem); }; // 여행 날짜별 교통 수단 변경 이벤트 발생시 (01/16 업데이트) @@ -157,10 +156,9 @@ export const pubDisconnectMember = (pubMember: pubMember, tripId: string) => { }; // 여정 편집 페이지 입장 이벤트 발생시(모든 sub 다받음) -export const pubEnterMember = (pubMember: pubMember, tripId: string) => { +export const pubEnterMember = (tripId: string) => { socketClient.publish({ destination: `/pub/trips/${tripId}/enterMember`, - body: JSON.stringify(pubMember), }); }; diff --git a/src/api/trips.ts b/src/api/trips.ts index be019a7f..d50faa39 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; }; // 우리의 관심 목록 등록 @@ -62,9 +62,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; }; @@ -84,3 +85,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/DetailSectionTop/DetailTopButton.tsx b/src/components/DetailSectionTop/DetailTopButton.tsx index 225c4fc6..2e5cd923 100644 --- a/src/components/DetailSectionTop/DetailTopButton.tsx +++ b/src/components/DetailSectionTop/DetailTopButton.tsx @@ -1,51 +1,37 @@ -import { useEffect, useRef, useState } from 'react'; +import { useEffect, useState } from 'react'; +import { useRecoilValue } from 'recoil'; +import { reviewCountState } from '@recoil/review'; import { TopIcon } from '@components/common/icons/Icons'; -export default function DetailTopButton({ parentRef }: any) { - const [isVisible, setIsVisible] = useState(false); - const [scrollPosition, setScrollPosition] = useState(0); - const [viewportHeight, setViewportHeight] = useState(0); - - const scrollButtonRef = useRef(null); +export default function DetailTopButton() { + const [visible, setVisible] = useState(false); + const getReviewCount = useRecoilValue(reviewCountState); useEffect(() => { - const handleScroll = () => { - if (scrollButtonRef.current && parentRef.current) { - setViewportHeight(screen.height); - - // 부모 요소의 높이보다 적을 때까지 스크롤 허용 - if (window.scrollY < parentRef.current.clientHeight - 50) { - // 기기 높이의 절반 이상 스크롤 했을 때 - if (window.scrollY >= viewportHeight / 2) { - setIsVisible(true); - setScrollPosition(window.scrollY); - } else { - setIsVisible(false); - } - } - } - }; - - window.addEventListener('scroll', handleScroll); - - return () => { - window.removeEventListener('scroll', handleScroll); - }; - }, [parentRef, scrollPosition, setScrollPosition]); - - const scrollToTop = () => { + if (getReviewCount > 2) { + setVisible(true); + } else { + setVisible(false); + } + }, [getReviewCount]); + + const scrollToTop = (e: React.MouseEvent) => { + e.stopPropagation(); window.scrollTo({ top: 0, behavior: 'smooth' }); }; + if (!visible) { + return null; + } + return (
- + className="sticky bottom-5 + mt-[-50px] flex h-12 w-12 cursor-pointer items-center justify-center rounded-full bg-white shadow-md" + style={{ left: 'calc(100%)' }}> +
); } 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/components/Plan/PlanEditItemBox.tsx b/src/components/Plan/PlanEditItemBox.tsx index ae5f4873..a3987601 100644 --- a/src/components/Plan/PlanEditItemBox.tsx +++ b/src/components/Plan/PlanEditItemBox.tsx @@ -59,8 +59,6 @@ const PlanEditItemBox = ({ visitDate: visitDate, tripItemOrder, }); - - console.log(newData); }; useEffect(() => { diff --git a/src/components/Plan/PlanItem.tsx b/src/components/Plan/PlanItem.tsx index c27cf354..a49109f6 100644 --- a/src/components/Plan/PlanItem.tsx +++ b/src/components/Plan/PlanItem.tsx @@ -6,34 +6,44 @@ import PlanItemBox from './PlanItemBox'; import PlanEditItemBox from './PlanEditItemBox'; import { useContext, useEffect, useState } from 'react'; import { socketContext } from '@hooks/useSocket'; -import { useRecoilState } from 'recoil'; +import { useRecoilState, useRecoilValue } from 'recoil'; import { visitDateState } from '@recoil/socket'; import { pubGetPathAndItems, pubUpdateTransportation } from '@api/socket'; import { tripIdState } from '@recoil/socket'; -import { useRecoilValue } from 'recoil'; +import { tapState } from '@recoil/plan'; type PlanItemProps = { date: string; day: string; + isMount: boolean; }; -const PlanItem: React.FC = ({ date, day }) => { +const PlanItem: React.FC = ({ date, day, isMount }) => { const navigate = useNavigate(); const [isEdit, SetIsEdit] = useState(false); const tripId = useRecoilValue(tripIdState); + const tap = useRecoilValue(tapState); + const [visitDate, setVisitDate] = useRecoilState(visitDateState); const { tripItem, tripPath, callBackPub } = useContext(socketContext); + console.log(visitDate); useEffect(() => { - setVisitDate({ visitDate: date }); - }, [date]); - - useEffect(() => { - if (visitDate && tripId) { - callBackPub(() => pubGetPathAndItems(visitDate, tripId)); + if (isMount) { + setVisitDate({ visitDate: date }); + if (date && tripId) { + callBackPub(() => pubGetPathAndItems({ visitDate: date }, tripId)); + console.log('pubGetPathAndItems', tap); + } } - }, [visitDate]); + }, [tap]); + + // useEffect(() => { + // if (date && tripId) { + // callBackPub(() => pubGetPathAndItems({ visitDate: date }, tripId)); + // } + // }, [tap]); const handleEdit = () => { SetIsEdit((prev) => !prev); @@ -41,14 +51,14 @@ const PlanItem: React.FC = ({ date, day }) => { const handleTranspo = ( transportation: 'CAR' | 'PUBLIC_TRANSPORTATION', - visitDate: string, + date: string, tripId: string, ) => { if (transportation !== transpo) { callBackPub(() => pubUpdateTransportation( { - visitDate: visitDate, + visitDate: date, transportation: transportation, }, tripId, @@ -59,6 +69,7 @@ const PlanItem: React.FC = ({ date, day }) => { const transpo = tripItem?.data?.transportation || ''; + // console.log(tripItem?.data?.tripItems.sort((a, b) => a.seqNum - b.seqNum)); return ( <> {tripPath && } @@ -67,11 +78,9 @@ const PlanItem: React.FC = ({ date, day }) => { {isEdit ? (
) : ( -
+
- handleTranspo('CAR', visitDate?.visitDate || '', tripId || '') - } + onClick={() => handleTranspo('CAR', date || '', tripId || '')} className="flex h-[32px] w-[32px] cursor-pointer items-center justify-center rounded-l-md border border-solid border-gray3"> = ({ date, day }) => {
- handleTranspo( - 'PUBLIC_TRANSPORTATION', - visitDate?.visitDate || '', - tripId || '', - ) + handleTranspo('PUBLIC_TRANSPORTATION', date || '', tripId || '') } className="pointer-cursor -ml-[1px] flex h-[32px] w-[32px] cursor-pointer items-center justify-center rounded-r-md border border-solid border-gray3"> = ({ date, day }) => {
)} -
diff --git a/src/components/Plan/TripBudget.tsx b/src/components/Plan/TripBudget.tsx index bac3e435..07b33ecf 100644 --- a/src/components/Plan/TripBudget.tsx +++ b/src/components/Plan/TripBudget.tsx @@ -1,51 +1,57 @@ +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 ( <> -
+
사용 경비
- {currentSpending.toLocaleString()} + {budget?.calculatedPrice.toLocaleString() ?? '-'}
{ { - console.log('확인'); - }} - onCancel={() => { - console.log('취소'); - }} + onConfirm={() => handleSetTargetBudget(inputBudget)} + closeOnConfirm={true} children={ } content={
- - +
+ setInputBudget(e.target.value)} + /> +
setInputBudget('')}> + {showCloseIcon && } +
+
+ +
} />
- {targetBudget.toLocaleString()} + {budget?.budget.toLocaleString() ?? '- '}
diff --git a/src/components/Plan/TripMap.tsx b/src/components/Plan/TripMap.tsx index 9816403e..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', }; @@ -100,8 +99,6 @@ const TripMap = ({ paths }: { paths: Paths[] }) => { // 선택된 마커의 인덱스를 추적하기 위한 상태 const [selectedMarker, setSelectedMarker] = useState(null); - // ... - // 마커를 클릭할 때 호출되는 함수 const handleMarkerClick = (index: number) => { setSelectedMarker(index); @@ -127,22 +124,20 @@ const TripMap = ({ paths }: { paths: Paths[] }) => { svgComponent = isSelected ? FifthSelectedMarker : FifthMarker; break; default: - // 기본 마커가 필요한 경우 기본 마커 이미지 URL을 제공합니다. + // 기본 마커 return 'default_marker_image_url'; } return svgComponent; }; - // ... TripMap 컴포넌트 및 나머지 코드 - return ( -
+
{paths.map((path, index) => (
diff --git a/src/components/Trip/LikedToursList.tsx b/src/components/Trip/LikedToursList.tsx index 67119420..eab8eeea 100644 --- a/src/components/Trip/LikedToursList.tsx +++ b/src/components/Trip/LikedToursList.tsx @@ -1,3 +1,92 @@ +import { useState } from 'react'; +import { useNavigate, 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 navigate = useNavigate(); + 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; + }, + }); + + if (error) { + return
데이터를 불러오는 중 오류가 발생했습니다.
; + } + + const handleCategoryClick = (contentTypeId: number | null) => { + setSelectedContentTypeId(contentTypeId); + }; + + 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..b0a1092b --- /dev/null +++ b/src/components/Trip/LikedToursLists/LikedToursListItem.tsx @@ -0,0 +1,130 @@ +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, + title, + } = 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}`)}> +
+
+ 여행지 이미지 +
+ +
+
+

+ {title} +

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

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

+
+
+
+ +
+
+ + +
+
+
+
+
+ ); +}; + +export default LikedToursListItem; 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/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
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 ( -
+
{ const navigate = useNavigate(); + const { tripAuthority } = useGetTripsAuthority(); + + console.log(tripAuthority); return (
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}

diff --git a/src/components/common/icons/Icons.tsx b/src/components/common/icons/Icons.tsx index 34987b1f..42385993 100644 --- a/src/components/common/icons/Icons.tsx +++ b/src/components/common/icons/Icons.tsx @@ -1299,6 +1299,93 @@ 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 ( + + + + + ); +}; + export const RedIcon: React.FC = ({ size = 20, className }) => { return ( = ({}) => { ); }; + export const PaperIcon: React.FC = ({}) => { return ( = ({}) => { ); }; + +export const PlanColorIcon = () => { + return ( + + + + + + + ); +}; diff --git a/src/components/common/tab/Tab.tsx b/src/components/common/tab/Tab.tsx index 3ae8f972..dc1918a4 100644 --- a/src/components/common/tab/Tab.tsx +++ b/src/components/common/tab/Tab.tsx @@ -1,37 +1,63 @@ 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); + } + }; + + 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; 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 }; +}; 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/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/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/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, +}); 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 = () => { }> } /> } /> - } /> + } /> );