diff --git a/src/@types/tours.types.ts b/src/@types/tours.types.ts index 2b722c6d..ccd95671 100644 --- a/src/@types/tours.types.ts +++ b/src/@types/tours.types.ts @@ -37,3 +37,18 @@ export interface TourType { longitude?: string; latitude?: string; } + +export interface LikedListType { + tripLikedItemId: number; + tourItemId: number; + contentTypeId: number; + title: string; + ratingAverage: number; + reviewCount: number; + smallThumbnailUrl: string; + tourAddress: string; + prefer: boolean; + notPrefer: boolean; + preferTotalCount: number; + notPreferTotalCount: number; +} diff --git a/src/api/socket.ts b/src/api/socket.ts index 000830cf..300d9037 100644 --- a/src/api/socket.ts +++ b/src/api/socket.ts @@ -79,6 +79,7 @@ export const pubAddTripItem = ( destination: `/pub/trips/${tripId}/addTripItems`, body: JSON.stringify(pubAddTripItem), }); + console.log(pubAddTripItem); }; // 여행 아이템 예상 가격 업데이트 이벤트 발생시 @@ -101,8 +102,6 @@ export const pubUpdateTripItem = ( destination: `/pub/trips/${tripId}/updateTripItemOrder`, body: JSON.stringify(pubUpdateTripItem), }); - - console.log('데이터', pubUpdateTripItem); }; // 여행 날짜별 교통 수단 변경 이벤트 발생시 (01/16 업데이트) @@ -136,7 +135,6 @@ export const pubDeleteItem = ( destination: `/pub/tripItems/${tripItemId}/deleteItem`, body: JSON.stringify(pubDeleteItem), }); - console.log(pubDeleteItem); }; // 멤버 여정 페이지로 입장 이벤트 발생시 diff --git a/src/api/trips.ts b/src/api/trips.ts index e4d19de4..21547e5a 100644 --- a/src/api/trips.ts +++ b/src/api/trips.ts @@ -10,8 +10,16 @@ export const getTrips = async (tripId: number) => { }; // 여정 기본정보 수정 -export const putTrips = async (tripId: number, tripsData: TripRequest) => { - const res = await client.put(`trips/${tripId}`, tripsData); +export const putTrips = async ( + tripId: number, + tourItemId: number, + visitDate: string, +) => { + const requestBody = { + tourItemId: tourItemId, + visitDate: visitDate, + }; + const res = await authClient.post(`trips/${tripId}`, requestBody); return res; }; @@ -46,7 +54,7 @@ export const getTripsLike = async ( }; // 우리의 관심 목록 등록 -export const postTripsLike = async (tripId: number, tourItemIds: number[]) => { +export const postTripsLike = async (tripId: string, tourItemIds: number[]) => { const requestBody = { tourItemIds: tourItemIds, }; diff --git a/src/assets/images/FifthMarker.png b/src/assets/images/FifthMarker.png deleted file mode 100644 index 617795ce..00000000 Binary files a/src/assets/images/FifthMarker.png and /dev/null differ diff --git a/src/assets/images/FifthSelectedMarker.png b/src/assets/images/FifthSelectedMarker.png deleted file mode 100644 index b931eb7b..00000000 Binary files a/src/assets/images/FifthSelectedMarker.png and /dev/null differ diff --git a/src/assets/images/FirstMarker.png b/src/assets/images/FirstMarker.png deleted file mode 100644 index b317d65c..00000000 Binary files a/src/assets/images/FirstMarker.png and /dev/null differ diff --git a/src/assets/images/FirstSelectedMarker.png b/src/assets/images/FirstSelectedMarker.png deleted file mode 100644 index 632130de..00000000 Binary files a/src/assets/images/FirstSelectedMarker.png and /dev/null differ diff --git a/src/assets/images/FourthMarker.png b/src/assets/images/FourthMarker.png deleted file mode 100644 index f1963795..00000000 Binary files a/src/assets/images/FourthMarker.png and /dev/null differ diff --git a/src/assets/images/FourthSelectedMarker.png b/src/assets/images/FourthSelectedMarker.png deleted file mode 100644 index 16fcbf5b..00000000 Binary files a/src/assets/images/FourthSelectedMarker.png and /dev/null differ diff --git a/src/assets/images/SecondMarker.png b/src/assets/images/SecondMarker.png deleted file mode 100644 index 741e7cdb..00000000 Binary files a/src/assets/images/SecondMarker.png and /dev/null differ diff --git a/src/assets/images/SecondSelectedMarker.png b/src/assets/images/SecondSelectedMarker.png deleted file mode 100644 index d236dc12..00000000 Binary files a/src/assets/images/SecondSelectedMarker.png and /dev/null differ diff --git a/src/assets/images/ThirdMarker.png b/src/assets/images/ThirdMarker.png deleted file mode 100644 index a55fa7fc..00000000 Binary files a/src/assets/images/ThirdMarker.png and /dev/null differ diff --git a/src/assets/images/ThirdSelectedMarker.png b/src/assets/images/ThirdSelectedMarker.png deleted file mode 100644 index bdfe7cb3..00000000 Binary files a/src/assets/images/ThirdSelectedMarker.png and /dev/null differ diff --git a/src/components/Plan/PlanSchedule.tsx b/src/components/Plan/PlanSchedule.tsx new file mode 100644 index 00000000..4e96dc4f --- /dev/null +++ b/src/components/Plan/PlanSchedule.tsx @@ -0,0 +1,29 @@ +import { UserIcon } from '@components/common/icons/Icons'; +import { socketContext } from '@hooks/useSocket'; +import { useContext } from 'react'; + +const PlanSchedule = () => { + const { tripInfo } = useContext(socketContext); + const trip = tripInfo?.data; + + return ( +
+
+
+
{trip?.tripName}
+
+ + + {trip?.numberOfPeople} + +
+
+
+ + {trip?.startDate} ~ {trip?.endDate} + +
+ ); +}; + +export default PlanSchedule; diff --git a/src/components/Plan/PlanSectionTop.tsx b/src/components/Plan/PlanSectionTop.tsx index 99be9d1f..6200827c 100644 --- a/src/components/Plan/PlanSectionTop.tsx +++ b/src/components/Plan/PlanSectionTop.tsx @@ -12,7 +12,7 @@ import { useRecoilValue, useRecoilState } from 'recoil'; import { dayState, dateState } from '@recoil/plan'; import { tripIdState, memberIdState } from '@recoil/socket'; import { calculateDayAndDate } from '@utils/utils'; -import { TripSchedule } from '@components/Trip/TripSchedule'; +import PlanSchedule from './PlanSchedule'; const PlanSectionTop = () => { const navigate = useNavigate(); @@ -60,7 +60,7 @@ const PlanSectionTop = () => { }} /> - + { + const { tripAuthority } = useGetTripsAuthority(); const { tripBudget } = useContext(socketContext); const tripId = useRecoilValue(tripIdState); @@ -71,63 +73,67 @@ const TripBudget = () => {
목표 경비 - handleSetTargetBudget(inputBudget)} - closeOnConfirm={true} - children={ - + } + content={ +
+
+ setInputBudget(e.target.value)} + /> +
setInputBudget('')}> + {showCloseIcon && ( + + )}
- - - -
- )} - - } - content={ -
-
- setInputBudget(e.target.value)} - /> -
setInputBudget('')}> - {showCloseIcon && }
-
- -
- } - /> + +
+ } + /> + )}
{budget?.budget.toLocaleString() ?? '- '} diff --git a/src/components/Plan/TripMap.tsx b/src/components/Plan/TripMap.tsx index 7c167103..94dac763 100644 --- a/src/components/Plan/TripMap.tsx +++ b/src/components/Plan/TripMap.tsx @@ -1,16 +1,7 @@ import { Paths } from '@/@types/service'; import { useEffect, useRef, useState } from 'react'; import { Map, MapMarker, Polyline, useKakaoLoader } from 'react-kakao-maps-sdk'; -import FirstMarker from '@/assets/images/FirstMarker.png'; -import FirstSelectedMarker from '@/assets/images/FirstSelectedMarker.png'; -import SecondMarker from '@/assets/images/SecondMarker.png'; -import ThirdMarker from '@/assets/images/ThirdMarker.png'; -import FourthMarker from '@/assets/images/FourthMarker.png'; -import FifthMarker from '@/assets/images/FifthMarker.png'; -import SecondSelectedMarker from '@/assets/images/SecondSelectedMarker.png'; -import ThirdSelectedMarker from '@/assets/images/ThirdSelectedMarker.png'; -import FourthSelectedMarker from '@/assets/images/FourthSelectedMarker.png'; -import FifthSelectedMarker from '@/assets/images/FifthSelectedMarker.png'; +import { getColor } from '@utils/getColor'; const VITE_KAKAO_MAP_API_KEY = import.meta.env.VITE_KAKAO_MAP_API_KEY; @@ -19,13 +10,15 @@ const TripMap = ({ paths }: { paths: Paths[] }) => { const latitude = firstPath?.fromLatitude; const longitude = firstPath?.fromLongitude; - // Kakao Maps SDK 로드 상태 + const mapRef = useRef(null); + const [selectedMarker, setSelectedMarker] = useState(null); + + const defaultPosition = { lat: Number(latitude), lng: Number(longitude) }; + const [_] = useKakaoLoader({ appkey: VITE_KAKAO_MAP_API_KEY, }); - const defaultPosition = { lat: Number(latitude), lng: Number(longitude) }; - const getCenterPosition = () => { if (paths.length === 0) { return defaultPosition; @@ -68,8 +61,6 @@ const TripMap = ({ paths }: { paths: Paths[] }) => { }); } - const mapRef = useRef(null); - // 지도 범위 재설정 함수 const setBounds = () => { if (mapRef.current) { @@ -96,38 +87,97 @@ const TripMap = ({ paths }: { paths: Paths[] }) => { setBounds(); }, [paths]); - // 선택된 마커의 인덱스를 추적하기 위한 상태 - const [selectedMarker, setSelectedMarker] = useState(null); - // 마커를 클릭할 때 호출되는 함수 const handleMarkerClick = (index: number) => { setSelectedMarker(index); }; - // 각 마커에 대한 이미지를 렌더링하는 함수 - const renderMarkerImage = (index: number, isSelected: boolean) => { - let svgComponent; - switch (index % 5) { - case 0: - svgComponent = isSelected ? FirstSelectedMarker : FirstMarker; - break; - case 1: - svgComponent = isSelected ? SecondSelectedMarker : SecondMarker; - break; - case 2: - svgComponent = isSelected ? ThirdSelectedMarker : ThirdMarker; - break; - case 3: - svgComponent = isSelected ? FourthSelectedMarker : FourthMarker; - break; - case 4: - svgComponent = isSelected ? FifthSelectedMarker : FifthMarker; - break; - default: - // 기본 마커 - return 'default_marker_image_url'; + // SVG 문자열을 Data URI로 변환하는 함수 + const getSequenceIconUrl = (number: number) => { + let svgString; + let width, height; + + if (selectedMarker === number + 1) { + width = 32; + height = 39; + svgString = encodeURIComponent(` + + + + + ${number} + + + + + + + + + + + + + + + `); + } else { + width = 24; + height = 24; + svgString = encodeURIComponent(` + + + ${number} + + `); } - return svgComponent; + + return { + src: `data:image/svg+xml;charset=UTF-8,${svgString}`, + size: { width, height }, + }; }; return ( @@ -136,39 +186,30 @@ const TripMap = ({ paths }: { paths: Paths[] }) => { key={VITE_KAKAO_MAP_API_KEY} center={centerPosition} style={MapStyle} - level={10} + level={4} className="relative object-fill" ref={mapRef}> {paths.map((path, index) => ( -
+
handleMarkerClick(index)} - image={{ - src: renderMarkerImage(index, selectedMarker === index), - size: { - width: 33, - height: 33, - }, - }} - /> - handleMarkerClick(index)} - image={{ - src: renderMarkerImage(index, selectedMarker === index), - size: { - width: 33, - height: 33, - }, - }} + onClick={() => handleMarkerClick(path.toSeqNum)} + image={getSequenceIconUrl(path.toSeqNum - 1)} /> + {/* 마지막 항목인 경우, 목적지 위치에 마커 추가 */} + {index === paths.length - 1 && ( + handleMarkerClick(path.toSeqNum + 1)} + image={getSequenceIconUrl(path.toSeqNum)} + /> + )} { const imageUrl = isImageUrlValid ? thumbnailUrl : null; return ( - -
+ +
{imageUrl ? ( { const [isActive, setIsActive] = useState(false); - const handleClick = () => { + const handleClick = (e: React.MouseEvent) => { setIsActive(!isActive); + e.stopPropagation(); if (onClick) { onClick(); } @@ -36,15 +37,16 @@ interface ListCheckBtnProps { export const ListCheckBtn = ({ onClick }: ListCheckBtnProps) => { const [isActive, setIsActive] = useState(false); - const handleClick = () => { + const handleClick = (e: React.MouseEvent) => { setIsActive(!isActive); + e.stopPropagation(); if (onClick) { onClick(); } }; return ( -
+