diff --git a/src/components/DatePicker/Calendar.tsx b/src/components/DatePicker/Calendar.tsx index 5185160e..1db551ab 100644 --- a/src/components/DatePicker/Calendar.tsx +++ b/src/components/DatePicker/Calendar.tsx @@ -98,7 +98,7 @@ const Calendar: React.FC<{ let afterClass = ''; if (isStart) { - dayClass = 'rounded-full w-[40px] bg-main2 text-white z-10'; + dayClass = 'rounded-full size-[40px] bg-main2 text-white z-10'; afterClass = endDate ? 'after:content-[""] after:absolute after:left-[50%] after:top-[4px] after:w-[32px] after:h-[40px] after:bg-[#DAFBFF] after:z-[1]' : ''; @@ -107,7 +107,7 @@ const Calendar: React.FC<{ beforeClass = 'before:content-[""] before:absolute before:right-[50%] before:top-[4px] before:w-[32px] before:h-[40px] before:bg-[#DAFBFF] before:z-[1]'; } else if (isMiddle) { - dayClass = 'bg-[#DAFBFF]'; + dayClass = 'bg-[#DAFBFF] w-full'; } const onClick = () => handleDateClick(date); @@ -118,7 +118,7 @@ const Calendar: React.FC<{ className={`relative flex h-[48px] cursor-pointer items-center justify-center ${beforeClass} ${afterClass}`} onClick={onClick}>
+ className={`flex h-[40px] items-center justify-center ${dayClass}`}> {day}
@@ -145,7 +145,7 @@ const Calendar: React.FC<{ } return ( -
+
{format(monthDate, 'yyyy년 MM월', { locale: ko })}
@@ -159,16 +159,18 @@ const Calendar: React.FC<{ return ( <> -
- {startDate && endDate - ? `${format(startDate, 'MM.dd', { locale: ko })} - ${format( - endDate, - 'MM.dd', - { locale: ko }, - )} (${differenceInDays(endDate, startDate)}박 ${ - differenceInDays(endDate, startDate) + 1 - }일)` - : '날짜를 선택해주세요.'} +
+ {startDate && !endDate + ? `${format(startDate, 'MM.dd', { locale: ko })}` + : startDate && endDate + ? `${format(startDate, 'MM.dd', { locale: ko })} - ${format( + endDate, + 'MM.dd', + { locale: ko }, + )} (${differenceInDays(endDate, startDate)}박 ${ + differenceInDays(endDate, startDate) + 1 + }일)` + : '날짜를 선택해주세요.'}
diff --git a/src/components/Plan/TripBudget.tsx b/src/components/Plan/TripBudget.tsx index 54293bea..8838fb25 100644 --- a/src/components/Plan/TripBudget.tsx +++ b/src/components/Plan/TripBudget.tsx @@ -10,7 +10,13 @@ const TripBudget = () => { const [targetBudget, setTargetBudget] = useState(0); // 예시 목표 경비 const [currentSpending, setCurrentSpending] = useState(0); // 초기 사용 경비 - // 프로그레스 바 값 계산 + useEffect(() => { + if (budget) { + setTargetBudget(budget.budget || 0); + setCurrentSpending(budget.calculatedPrice || 0); + } + }, [budget]); + // 프로그레스 바 값 계산 const progress = Math.min( currentSpending && targetBudget @@ -19,19 +25,6 @@ const TripBudget = () => { 100, ); - useEffect(() => { - // 경비 수정 모달 추가 예정 - const timer = setTimeout(() => setCurrentSpending(3000), 300); - return () => clearTimeout(timer); - }, []); - - useEffect(() => { - if (budget) { - setTargetBudget(budget.budget || 0); - setCurrentSpending(budget.calculatedPrice || 0); - } - }, [budget]); - // 목표 경비 설정 함수 const handleSetTargetBudget = (newTargetBudget: number) => { setTargetBudget(newTargetBudget); @@ -54,8 +47,12 @@ const TripBudget = () => { }} value={progress}> = 100 ? 'bg-sub2' : 'bg-main2' + } transition-transform duration-[660ms]`} + style={{ + transform: `translateX(${progress >= 100 ? 0 : -100 + progress}%)`, + }} /> diff --git a/src/components/Plan/TripMap.tsx b/src/components/Plan/TripMap.tsx index bf06dced..8c430353 100644 --- a/src/components/Plan/TripMap.tsx +++ b/src/components/Plan/TripMap.tsx @@ -1,4 +1,5 @@ import { Paths } from '@/@types/service'; +import { useEffect, useRef } from 'react'; import { Map, MapMarker, Polyline, useKakaoLoader } from 'react-kakao-maps-sdk'; const VITE_KAKAO_MAP_API_KEY = import.meta.env.VITE_KAKAO_MAP_API_KEY; @@ -8,6 +9,11 @@ const TripMap = ({ paths }: { paths: Paths[] }) => { const latitude = firstPath?.fromLatitude; const longitude = firstPath?.fromLongitude; + // Kakao Maps SDK 로드 상태 + const [_] = useKakaoLoader({ + appkey: VITE_KAKAO_MAP_API_KEY, + }); + const defaultPosition = { lat: Number(latitude), lng: Number(longitude) }; const getCenterPosition = () => { @@ -31,10 +37,6 @@ const TripMap = ({ paths }: { paths: Paths[] }) => { const centerPosition = getCenterPosition(); - const [_] = useKakaoLoader({ - appkey: VITE_KAKAO_MAP_API_KEY, - }); - const MapStyle = { width: '100%', height: '180px', @@ -58,14 +60,43 @@ const TripMap = ({ paths }: { paths: Paths[] }) => { }); } + const mapRef = useRef(null); + + // 지도 범위 재설정 함수 + const setBounds = () => { + if (mapRef.current) { + const bounds = new kakao.maps.LatLngBounds(); + paths.forEach((path) => { + bounds.extend( + new kakao.maps.LatLng( + Number(path.fromLatitude), + Number(path.fromLongitude), + ), + ); + bounds.extend( + new kakao.maps.LatLng( + Number(path.toLatitude), + Number(path.toLongitude), + ), + ); + }); + mapRef.current.setBounds(bounds); + } + }; + + useEffect(() => { + setBounds(); + }, [paths]); + return ( -
+
+ className="relative rounded-lg object-fill" + ref={mapRef}> {paths.map((path, index) => (
{ const navigate = useNavigate(); + const [isLogin, setIsLogin] = useState(false); + const [, setShowAlert] = useState(false); + const [checked, setChecked] = useState(false); + useEffect(() => { + const checkLoginStatus = async () => { + try { + const res = await getMember(); + if (res.data.status === 200) { + setIsLogin(true); + } + } catch (err) { + console.error(err); + setIsLogin(false); + } finally { + setChecked(true); + } + }; + + checkLoginStatus(); + }, []); + + const handleCreateTrip = () => { + if (isLogin) { + navigate('/create'); + } else { + setShowAlert(true); + } + }; + + const handleConfirm = () => { + navigate('/login'); + }; return ( -
- -
+ <> + {checked && ( + + 로그인이 필요한 기능입니다. +
+ 로그인 하시겠습니까? + + } + onConfirm={handleConfirm}> + +
+ )} + ); }; diff --git a/src/components/Tours/ToursCategoryItem.tsx b/src/components/Tours/ToursCategoryItem.tsx index 3e48384e..d849da67 100644 --- a/src/components/Tours/ToursCategoryItem.tsx +++ b/src/components/Tours/ToursCategoryItem.tsx @@ -13,7 +13,7 @@ const ToursCategoryItem = ({ ); diff --git a/src/components/Trip/LikedToursList.tsx b/src/components/Trip/LikedToursList.tsx new file mode 100644 index 00000000..67119420 --- /dev/null +++ b/src/components/Trip/LikedToursList.tsx @@ -0,0 +1,3 @@ +export const LikedToursList = () => { + return
LikedToursList
; +}; diff --git a/src/components/Trip/TripSectionTop.tsx b/src/components/Trip/TripSectionTop.tsx index efc0960b..82e03c8e 100644 --- a/src/components/Trip/TripSectionTop.tsx +++ b/src/components/Trip/TripSectionTop.tsx @@ -4,6 +4,7 @@ import TripInfo from './TripInfo'; import { BackBox } from '@components/common'; import { useNavigate } from 'react-router-dom'; import PlanTripButton from './PlanTripButton'; +import { LikedToursList } from './LikedToursList'; const TripSectionTop = () => { const navigate = useNavigate(); @@ -21,7 +22,7 @@ const TripSectionTop = () => { ,
우리의 관심목록
]} + contents={[, ]} />
); diff --git a/src/components/common/icons/Icons.tsx b/src/components/common/icons/Icons.tsx index b9d6a6d4..3d70d69e 100644 --- a/src/components/common/icons/Icons.tsx +++ b/src/components/common/icons/Icons.tsx @@ -483,30 +483,19 @@ export const PlusIcon: React.FC = ({ xmlns="http://www.w3.org/2000/svg" width={size} height={size} - viewBox="0 0 21 21" + viewBox="0 0 14 14" fill={fill}> - ); @@ -1123,7 +1112,7 @@ export const ShareIcon: React.FC = ({ }; export const PlanIcon: React.FC = ({ - size = 20, + size = 24, color = 'black', fill = 'none', }) => { @@ -1261,3 +1250,50 @@ export const CheckboxIcon: React.FC = ({ ); }; + +export const CounterIcon: React.FC< + IconProps & { plus?: boolean; minus?: boolean } +> = ({ size = 12, fill = '#D7D7D7', plus, minus }) => { + return ( + <> + {plus && ( + + + + + )} + {minus && ( + + + + )} + + ); +}; diff --git a/src/components/common/tab/Tab.tsx b/src/components/common/tab/Tab.tsx index 34fe447d..3ae8f972 100644 --- a/src/components/common/tab/Tab.tsx +++ b/src/components/common/tab/Tab.tsx @@ -8,7 +8,7 @@ interface TabProps { const Tab = ({ lists, contents }: TabProps) => ( {lists.map((list, index) => { return ( diff --git a/src/components/createTrip/SelectDate.tsx b/src/components/createTrip/SelectDate.tsx index e5fdaa0b..aadc9696 100644 --- a/src/components/createTrip/SelectDate.tsx +++ b/src/components/createTrip/SelectDate.tsx @@ -11,14 +11,18 @@ export const SelectDate = ({ onClose }: { onClose: () => void }) => { const [selectedEndDate, setSelectedEndDate] = useState(null); const handleComplete = () => { - setTripDate({ startDate: selectedStartDate, endDate: selectedEndDate }); + const endDate = selectedEndDate ? selectedEndDate : selectedStartDate; + setTripDate({ startDate: selectedStartDate, endDate }); onClose(); }; return (
-
- +
+
+ +
+
날짜 선택
{ diff --git a/src/components/createTrip/SelectDestination.tsx b/src/components/createTrip/SelectDestination.tsx deleted file mode 100644 index c4abe304..00000000 --- a/src/components/createTrip/SelectDestination.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { ButtonPrimary } from '@components/common/button/Button'; -import { BackIcon } from '@components/common/icons/Icons'; - -export const SelectDestination = ({ onClose }: { onClose: () => void }) => { - return ( -
-
- -
-
검색
-
- 완료 -
-
- ); -}; diff --git a/src/components/search/SearchResult.tsx b/src/components/search/SearchResult.tsx index 5f1ae0c4..74fbb61f 100644 --- a/src/components/search/SearchResult.tsx +++ b/src/components/search/SearchResult.tsx @@ -85,16 +85,7 @@ export const SearchResult = ({ /> ))}
- {/* {searchResults ? ( - - ) : ( -
검색결과가 없습니다.
- )} */} + {noResults ? (
검색결과가 없습니다.
) : ( diff --git a/src/pages/create/createTrip.page.tsx b/src/pages/create/createTrip.page.tsx index a6640f62..ca568ca8 100644 --- a/src/pages/create/createTrip.page.tsx +++ b/src/pages/create/createTrip.page.tsx @@ -3,11 +3,11 @@ import BackHeader from '@components/common/header/BackHeader'; import { CalendarIcon, CloseIcon, - SearchIcon, + CounterIcon, + PlanIcon, UserIcon, } from '@components/common/icons/Icons'; import { InputField } from '@components/createTrip/InputField'; -import { SelectDestination } from '@components/createTrip/SelectDestination'; import { tripDateState } from '@recoil/tripDate'; import { useState } from 'react'; import { useRecoilValue } from 'recoil'; @@ -18,24 +18,30 @@ import { formatDate } from '@utils/formatDate'; import { useQuery } from '@tanstack/react-query'; import { getMemberTrips } from '@api/member'; import { useNavigate } from 'react-router-dom'; +import { Spinner } from '@components/common/spinner/Spinner'; export const CreateTrip = () => { const navigate = useNavigate(); const [title, setTitle] = useState(''); const [numOfMembers, increaseNumOfMembers, decreaseNumOfMembers] = useCounter( - 2, - 2, - 12, - ); // (기본값, 최솟값, 최댓값) + 1, + 1, + ); const [showSelectDate, setShowSelectDate] = useState(false); - const [showSelectDestination, setShowSelectDestination] = useState(false); + const tripDate = useRecoilValue(tripDateState); - const { data } = useQuery({ + const { data, isLoading, isError } = useQuery({ queryKey: ['myTrips'], queryFn: () => getMemberTrips(), }); - const MY_TRIP_NUMBER = data?.numberOfElements + 1; + if (isLoading) { + return ; + } + if (isError) { + return
데이터를 불러오는 중 오류가 발생했습니다.
; + } + const MY_TRIP_NUMBER = data?.length + 1; const defaultTitle = `나의 여정 ${MY_TRIP_NUMBER}`; const handleSubmit = async () => { @@ -62,14 +68,15 @@ export const CreateTrip = () => { } }; - const tripDate = useRecoilValue(tripDateState); const formattedTripDate = tripDate.startDate && tripDate.endDate - ? `${formatDate(tripDate.startDate, 'MM.dd')} - ${formatDate( - tripDate.endDate, - 'MM.dd', - )}` - : '여행 날짜(선택)'; + ? tripDate.startDate === tripDate.endDate + ? formatDate(tripDate.startDate, 'yyyy. MM. dd') + : `${formatDate(tripDate.startDate, 'yyyy. MM. dd')} - ${formatDate( + tripDate.endDate, + 'MM. dd', + )}` + : '여행 날짜 (선택)'; if (showSelectDate) { return ( @@ -80,21 +87,12 @@ export const CreateTrip = () => { /> ); } - if (showSelectDestination) { - return ( - { - setShowSelectDestination(false); - }} - /> - ); - } return (
여행 생성하기
- + { -
{numOfMembers}명
-
- +
인원
+
+ {numOfMembers !== 1 && ( + + )} +
{numOfMembers}
@@ -141,15 +142,6 @@ export const CreateTrip = () => {
{formattedTripDate}
- { - setShowSelectDestination(true); - }} - isClickable> -
여행지 (선택)
-
-
완료