diff --git a/public/assets/svg/location.tsx b/public/assets/svg/location.tsx index d11c83a..d873b0b 100644 --- a/public/assets/svg/location.tsx +++ b/public/assets/svg/location.tsx @@ -1,22 +1,24 @@ import React from 'react'; +import { SvgProps } from '@/types/svgType'; -const Location = ({ size = 24, color = '#9fa6b2', ...props }) => ( +const Location = ({ size = 24, color = '#9fa6b2', className }: SvgProps) => ( + /> + /> ); diff --git a/public/assets/svg/star.tsx b/public/assets/svg/star.tsx new file mode 100644 index 0000000..16e3daa --- /dev/null +++ b/public/assets/svg/star.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { SvgProps } from '@/types/svgType'; + +const Star = ({ size = 20, color = '#fff', ...props }:SvgProps) => ( + + + +); + +export default Star; diff --git a/src/app/(with-header)/activities/[activitiesId]/components/ImageGrid.tsx b/src/app/(with-header)/activities/[activitiesId]/components/ImageGrid.tsx index dfbb559..e3a597e 100644 --- a/src/app/(with-header)/activities/[activitiesId]/components/ImageGrid.tsx +++ b/src/app/(with-header)/activities/[activitiesId]/components/ImageGrid.tsx @@ -2,16 +2,12 @@ import Image from 'next/image'; import React, { useState } from 'react'; - -interface ActivityImageProps { - mainImage: string; - subImages: string[]; -} +import { ImageGridProps } from '@/types/activityDetailType'; export default function ImageGrid({ mainImage, subImages, -}: ActivityImageProps) { +}: ImageGridProps) { const images = [mainImage, ...subImages]; const [currentIndex, setCurrentIndex] = useState(0); //캐러셀 구현용 state diff --git a/src/app/(with-header)/activities/[activitiesId]/components/ReviewCard.tsx b/src/app/(with-header)/activities/[activitiesId]/components/ReviewCard.tsx index e44a42c..0e35241 100644 --- a/src/app/(with-header)/activities/[activitiesId]/components/ReviewCard.tsx +++ b/src/app/(with-header)/activities/[activitiesId]/components/ReviewCard.tsx @@ -1,23 +1,17 @@ import Avatar from '@/components/Avatar'; - -interface UserReviewProps { - userName: string; - date: string; - reviewText: string; - avatarSrc: string; -} +import { ReviewCardProps } from '@/types/activityDetailType'; export default function ReviewCard({ userName, date, reviewText, avatarSrc, -}: UserReviewProps) { +}: ReviewCardProps) { return ( -
+
-
+

{userName}

|

{date}

diff --git a/src/app/(with-header)/activities/[activitiesId]/components/ReviewTitle.tsx b/src/app/(with-header)/activities/[activitiesId]/components/ReviewTitle.tsx new file mode 100644 index 0000000..720e2dc --- /dev/null +++ b/src/app/(with-header)/activities/[activitiesId]/components/ReviewTitle.tsx @@ -0,0 +1,20 @@ +import Star from '@assets/svg/star'; + +export default function ReviewTitle() { + return ( +
+

후기

+ +
+

4.2

+
+

매우 만족

+
+ +

1300개 후기

+
+
+
+
+ ); +} diff --git a/src/app/(with-header)/activities/[activitiesId]/components/Title.tsx b/src/app/(with-header)/activities/[activitiesId]/components/Title.tsx index bc4efc8..02091e3 100644 --- a/src/app/(with-header)/activities/[activitiesId]/components/Title.tsx +++ b/src/app/(with-header)/activities/[activitiesId]/components/Title.tsx @@ -1,14 +1,7 @@ import React from 'react'; import IconDropdown from '@assets/svg/dropdown'; - -interface TitleProps { - title: string; - category: string; - rating: number; - reviewCount: number; - address: string; - isDropDown?: boolean; -} +import Star from '@assets/svg/star'; +import { TitleProps } from '@/types/activityDetailType'; export default function Title({ title, @@ -25,9 +18,9 @@ export default function Title({

{title}

-
+
- + {rating.toFixed(1)} ({reviewCount}명) @@ -37,7 +30,7 @@ export default function Title({
{isDropDown && ( -
+
)} diff --git a/src/app/(with-header)/activities/[activitiesId]/page.tsx b/src/app/(with-header)/activities/[activitiesId]/page.tsx index c6bc385..f1e6e7c 100644 --- a/src/app/(with-header)/activities/[activitiesId]/page.tsx +++ b/src/app/(with-header)/activities/[activitiesId]/page.tsx @@ -4,6 +4,9 @@ import { mockActivity } from './mock/mock'; import Title from './components/Title'; import ImageGrid from './components/ImageGrid'; import ReviewCard from './components/ReviewCard'; +import BookingInterface from '@/components/FloatingBox/BookingInterface'; +import LocationMap from '@/components/LocationMap'; +import ReviewTitle from './components/ReviewTitle'; export default function ActivityDetailPage() { const { @@ -31,18 +34,46 @@ export default function ActivityDetailPage() { /> -
+
-

체험 설명

-

{description}

+

체험 설명

+

{description}

+
+
+ +
+ +
+

체험 장소

+ + + + + + +
-
); } diff --git a/src/components/DatePicker/CalendarBody.tsx b/src/components/DatePicker/CalendarBody.tsx index a8ab86f..7fe1e6f 100644 --- a/src/components/DatePicker/CalendarBody.tsx +++ b/src/components/DatePicker/CalendarBody.tsx @@ -2,13 +2,7 @@ import type dayjs from 'dayjs'; -interface CalendarBodyProps { - viewDate: dayjs.Dayjs; - today: dayjs.Dayjs; - selectedDate: dayjs.Dayjs; - onSelectDate: (date: dayjs.Dayjs) => void; - highlightDates?: dayjs.Dayjs[]; -} +import { CalendarBodyProps } from '@/types/datePickerTypes'; export default function CalendarBody({ viewDate, diff --git a/src/components/DatePicker/CalendarHeader.tsx b/src/components/DatePicker/CalendarHeader.tsx index 747e528..d27a6b7 100644 --- a/src/components/DatePicker/CalendarHeader.tsx +++ b/src/components/DatePicker/CalendarHeader.tsx @@ -1,11 +1,6 @@ 'use client'; -import type dayjs from 'dayjs'; - -interface CalendarHeaderProps { - viewDate: dayjs.Dayjs; - onMonthChange: (direction: 'add' | 'subtract') => void; -} +import { CalendarHeaderProps } from '@/types/datePickerTypes'; export default function CalendarHeader({ viewDate, diff --git a/src/components/DatePicker/DatePicker.tsx b/src/components/DatePicker/DatePicker.tsx index e02fbfd..10077e3 100644 --- a/src/components/DatePicker/DatePicker.tsx +++ b/src/components/DatePicker/DatePicker.tsx @@ -54,7 +54,7 @@ export default function DatePicker() { const highlightDates = availableDates.map((item) => dayjs(item.date)); return ( -
+
void; children: React.ReactNode; + disabled?: boolean; } - export default function BookingButton({ onClick, children, + disabled = false, }: BookingButtonProps) { return ( diff --git a/src/components/FloatingBox/BookingInterface.tsx b/src/components/FloatingBox/BookingInterface.tsx index 5468dc0..cefba9e 100644 --- a/src/components/FloatingBox/BookingInterface.tsx +++ b/src/components/FloatingBox/BookingInterface.tsx @@ -7,99 +7,106 @@ import PriceDisplay from './PriceDisplay'; import TimeSelector from './TimeSelector'; import TotalPriceDisplay from './TotalPriceDisplay'; import BookingModal from '@/ui/BookingModal'; -import { useState } from 'react'; -import TabletPopup from './TabletPopup'; import DatePicker from '../DatePicker/DatePicker'; +import Button from '../Button'; export default function BookingInterface() { const handleBooking = () => { alert('예약이 완료되었습니다!'); }; const setIsOpen = useBookingStore((state) => state.setIsOpen); - const { selectedDate, selectedTime, participants } = useBookingStore(); - const [openTablet, setOpenTablet] = useState(false); + const { selectedDate, selectedTime, participants, selectedTimeId } = + useBookingStore(); + + const isBookable = + !!selectedDate && !!selectedTime && !!selectedTimeId && !!participants; return ( -
-
- {/* PC */} -
-
+
+ {/* PC */} +
+
+ +
+ +
+ + + + 예약하기 + + +
+
+ + {/* 태블릿 */} +
+
+
-
- -
- +

날짜

+ +
+
- 예약하기 + + + + 예약하기 +
+
- {/* 태블릿 */} -
-
-
- -

날짜

- + {/* 모바일 */} +
+
+
+
+ ₩ 10,000{' '} + + / 총 {participants}인 +
-
- - - {openTablet && ( -
- -
+
setIsOpen(true)} + className='mb-4 text-sm text-gray-600' + > + {selectedDate && selectedTime ? ( +

+ {selectedDate instanceof Date + ? selectedDate.toLocaleDateString() + : selectedDate} + /{selectedTime} +

+ ) : ( + '날짜 선택하기' )} - 예약하기 - -
-
-
- - {/* 모바일 */} -
-
-
-
- ₩ 10,000{' '} - - / 총 {participants}인 - -
-
setIsOpen(true)} - className='mb-4 text-sm text-gray-600' - > - {selectedDate && selectedTime ? ( -

- {selectedDate instanceof Date - ? selectedDate.toLocaleDateString() - : selectedDate} - /{selectedTime} -

- ) : ( - '날짜 선택하기' - )} -
- - 예약하기
+ +
diff --git a/src/components/FloatingBox/TabletPopup.tsx b/src/components/FloatingBox/TabletPopup.tsx index d6ba379..0bad5de 100644 --- a/src/components/FloatingBox/TabletPopup.tsx +++ b/src/components/FloatingBox/TabletPopup.tsx @@ -1,15 +1,28 @@ +'use client'; + +import useBookingStore from '@/stores/Booking/useBookingStore'; +import IconClose from '@assets/svg/close'; import DatePicker from '../DatePicker/DatePicker'; +import TimeSelector from './TimeSelector'; + +export default function TabletPopup({}) { + const isOpen = useBookingStore((state) => state.isOpen); + const setIsOpen = useBookingStore((state) => state.setIsOpen); + + if (!isOpen) return null; -export default function TabletPopup() { return ( -
-
- +
+
+

날짜

+
+ + + +
); } diff --git a/src/components/FloatingBox/TimeSelector.tsx b/src/components/FloatingBox/TimeSelector.tsx index f74068a..08a815f 100644 --- a/src/components/FloatingBox/TimeSelector.tsx +++ b/src/components/FloatingBox/TimeSelector.tsx @@ -6,6 +6,7 @@ export default function TimeSelector() { const setSelectedTime = useBookingStore((state) => state.setSelectedTime); const selectedDate = useBookingStore((state) => state.selectedDate); const availableDates = useBookingStore((state) => state.availableDates); + const setSelectedTimeId = useBookingStore((state) => state.setSelectedTimeId); const selectedDateStr = selectedDate ? format(selectedDate, 'yyyy-MM-dd') @@ -26,7 +27,10 @@ export default function TimeSelector() { return ( +
+ +
+
+ +
+ +
+

+ 예약 가능한 시간 +

- +
- - - + +
+
); }