diff --git a/apps/what-today/src/components/activities/ActivitiesDescription.tsx b/apps/what-today/src/components/activities/ActivitiesDescription.tsx index 12ae50e2..f0a0d53c 100644 --- a/apps/what-today/src/components/activities/ActivitiesDescription.tsx +++ b/apps/what-today/src/components/activities/ActivitiesDescription.tsx @@ -11,8 +11,8 @@ interface ActivitiesDescriptionProps { export default function ActivitiesDescription({ description, className }: ActivitiesDescriptionProps) { return (
-
체험 설명
-

{description}

+
체험 설명
+

{description}

); } diff --git a/apps/what-today/src/components/activities/ActivitiesInformation.tsx b/apps/what-today/src/components/activities/ActivitiesInformation.tsx index 2b4ca381..c054f51e 100644 --- a/apps/what-today/src/components/activities/ActivitiesInformation.tsx +++ b/apps/what-today/src/components/activities/ActivitiesInformation.tsx @@ -14,6 +14,7 @@ interface ActivitiesInformationProps { className?: string; id?: string; isAuthor: boolean; + price: number; } /** @@ -28,6 +29,7 @@ export default function ActivitiesInformation({ address, className, isAuthor, + price, }: ActivitiesInformationProps) { const navigate = useNavigate(); const { toast } = useToast(); @@ -60,36 +62,46 @@ export default function ActivitiesInformation({ return ( <> -
+
-

{category}

+

{category}

{isAuthor && ( - + navigate(`/experiences/create/${id}`)}>수정하기 setIsDeleteOpen(true)}>삭제하기 )}
-

{title}

-
+

{title}

+
{rating.toFixed(1)} ({reviewCount})
-
+
{address}
+
+

+ ₩ {price.toLocaleString()} / 인 +

+
setIsDeleteOpen(false)}>
-

체험을 삭제하시겠습니까?

+

체험을 삭제하시겠습니까?

아니요 diff --git a/apps/what-today/src/components/activities/ActivitiesMap.tsx b/apps/what-today/src/components/activities/ActivitiesMap.tsx index 0ce903b0..f43d709e 100644 --- a/apps/what-today/src/components/activities/ActivitiesMap.tsx +++ b/apps/what-today/src/components/activities/ActivitiesMap.tsx @@ -13,9 +13,9 @@ interface ActivitiesMapProps { */ export default function ActivitiesMap({ address, className }: ActivitiesMapProps) { return ( -
-
오시는 길
-
{address}
+
+
오시는 길
+
{address}
diff --git a/apps/what-today/src/components/activities/ActivitiesReview.tsx b/apps/what-today/src/components/activities/ActivitiesReview.tsx index 68c55f5b..99b613dc 100644 --- a/apps/what-today/src/components/activities/ActivitiesReview.tsx +++ b/apps/what-today/src/components/activities/ActivitiesReview.tsx @@ -20,15 +20,15 @@ export default function ActivitiesReview({ review }: ActivitiesReviewProps) { }); return ( -
+
-
{user.nickname}
-
{formattedDate}
+
{user.nickname}
+
{formattedDate}
-

{content}

+

{content}

); } diff --git a/apps/what-today/src/components/activities/ActivityImages.tsx b/apps/what-today/src/components/activities/ActivityImages.tsx index 73e0ed08..88af0ee6 100644 --- a/apps/what-today/src/components/activities/ActivityImages.tsx +++ b/apps/what-today/src/components/activities/ActivityImages.tsx @@ -12,7 +12,7 @@ export default function ActivityImages({ bannerImageUrl, subImages }: ActivityIm return (
{/* 왼쪽 메인이미지 */} -
+
배너 이미지
@@ -21,7 +21,7 @@ export default function ActivityImages({ bannerImageUrl, subImages }: ActivityIm
{/* 1개일 때: 전체 영역 사용 */} {subImageCount === 1 && ( -
+
서브 이미지
-
+
서브 이미지 1
-
+
서브 이미지 2
{/* 이미지 1 */} -
+
서브 이미지 1 {/* 이미지 2 */} -
+
서브 이미지 2 {/* 이미지 3 - col-span-2 */} -
+
서브 이미지 3
{subImages.slice(0, 4).map((img, index) => ( -
+
{`서브; + return
; } diff --git a/apps/what-today/src/components/activities/ReservationBottomBar.tsx b/apps/what-today/src/components/activities/ReservationBottomBar.tsx index b7d7a1d7..d8b0a6bf 100644 --- a/apps/what-today/src/components/activities/ReservationBottomBar.tsx +++ b/apps/what-today/src/components/activities/ReservationBottomBar.tsx @@ -25,18 +25,19 @@ export default function ReservationBottomBar({ else buttonText = '예약하기'; return ( -
+
-

+

₩ {totalPrice.toLocaleString()} - / {reservation?.headCount ?? 1}명 + / {reservation?.headCount ?? 1}명

- {reservation &&

{formattedDateTime}

} + {reservation &&

{formattedDateTime}

}
-
- )} - {isFetchingNextPage && ( -
-

후기를 더 불러오는 중...

+
+ +
)}
diff --git a/apps/what-today/src/components/activities/reservation/HeadCountSelector.tsx b/apps/what-today/src/components/activities/reservation/HeadCountSelector.tsx index 7b075ef6..2b8fd998 100644 --- a/apps/what-today/src/components/activities/reservation/HeadCountSelector.tsx +++ b/apps/what-today/src/components/activities/reservation/HeadCountSelector.tsx @@ -10,15 +10,15 @@ interface HeadCountSelectorProps { export default function HeadCountSelector({ headCount, onIncrease, onDecrease }: HeadCountSelectorProps) { return (
-

참여 인원 수

+

참여 인원 수

-
- - {headCount} -
diff --git a/apps/what-today/src/components/activities/reservation/MobileReservationSheet.tsx b/apps/what-today/src/components/activities/reservation/MobileReservationSheet.tsx index 7d060aed..ab6c9cfb 100644 --- a/apps/what-today/src/components/activities/reservation/MobileReservationSheet.tsx +++ b/apps/what-today/src/components/activities/reservation/MobileReservationSheet.tsx @@ -1,4 +1,4 @@ -import { BottomSheet, Button } from '@what-today/design-system'; +import { BottomSheet, Button, ClockIcon } from '@what-today/design-system'; import { ArrowIcon } from '@what-today/design-system'; import { useState } from 'react'; @@ -81,10 +81,8 @@ export default function MobileReservationSheet({ {/* 1단계: 날짜/시간 선택 */} {currentStep === 'dateTime' && ( -
-
-

날짜 및 시간 선택

-
+
+

날짜 및 시간 선택

{/* 캘린더 */} @@ -100,28 +98,28 @@ export default function MobileReservationSheet({ {/* 시간 선택 */} {selectedDate && (
-

예약 가능한 시간

- +

예약 가능한 시간

+
+ +
+ + {/* 확인 버튼*/} +
)}
- - {/* 확인 버튼 */} -
- -
)} @@ -129,13 +127,13 @@ export default function MobileReservationSheet({ {/* 2단계: 인원 선택 */} {currentStep === 'headCount' && ( -
+
-

참여 인원 선택

+

참여 인원 선택

@@ -143,8 +141,11 @@ export default function MobileReservationSheet({ {/* 선택된 날짜/시간 요약 */} {selectedDate && selectedScheduleId && (
-

선택된 날짜/시간

-

+

+ + 선택된 날짜/시간 +

+

{selectedDate.replace(/-/g, '/')}{' '} {availableTimes.find((t) => t.id === selectedScheduleId)?.startTime} ~{' '} {availableTimes.find((t) => t.id === selectedScheduleId)?.endTime} @@ -156,11 +157,10 @@ export default function MobileReservationSheet({ {/* 총 금액 */} -

-
- 총 금액 - ₩ {totalPrice.toLocaleString()} -
+ +
+ 총 금액 + ₩ {totalPrice.toLocaleString()}
diff --git a/apps/what-today/src/components/activities/reservation/ReservationForm.tsx b/apps/what-today/src/components/activities/reservation/ReservationForm.tsx index 8e6d9714..ff86765c 100644 --- a/apps/what-today/src/components/activities/reservation/ReservationForm.tsx +++ b/apps/what-today/src/components/activities/reservation/ReservationForm.tsx @@ -1,6 +1,8 @@ import { useQueryClient } from '@tanstack/react-query'; import { Button, useToast } from '@what-today/design-system'; +import Divider from '@/components/activities/Divider'; + import CalendarSelector from './CalendarSelector'; import HeadCountSelector from './HeadCountSelector'; import { useReservation } from './hooks/useReservation'; @@ -88,9 +90,9 @@ export default function ReservationForm({ const content = (
{/* 가격 표시 */} -

+ {/*

₩ {price.toLocaleString()} / 인 -

+

*/} {/* 캘린더 */} @@ -98,22 +100,24 @@ export default function ReservationForm({ {/* 시간 선택 */} {selectedDate && ( <> -

예약 가능한 시간

- +

예약 가능한 시간

+
+ +
)} {/* 인원 선택 */} - + {/* 총 합계 */}
-

- 총 합계 ₩ {totalPrice.toLocaleString()} +

+ 총 합계 ₩ {totalPrice.toLocaleString()}

{showSubmitButton && ( @@ -130,9 +134,5 @@ export default function ReservationForm({
); - return ( -
- {content} -
- ); + return
{content}
; } diff --git a/apps/what-today/src/components/activities/reservation/TabletReservationSheet.tsx b/apps/what-today/src/components/activities/reservation/TabletReservationSheet.tsx index 5047baca..8f7f36c5 100644 --- a/apps/what-today/src/components/activities/reservation/TabletReservationSheet.tsx +++ b/apps/what-today/src/components/activities/reservation/TabletReservationSheet.tsx @@ -38,41 +38,43 @@ export default function TabletReservationSheet({ return ( -
+
{/* 좌측: 캘린더 */} { setSelectedDate(date); - setSelectedScheduleId(null); // 날짜 바뀌면 시간 초기화 + setSelectedScheduleId(null); }} /> {/* 우측: 시간 & 인원 */}
-

예약 가능한 시간

+

예약 가능한 시간

{selectedDate ? ( - +
+ +
) : ( -
날짜를 선택해주세요.
+
날짜를 선택해주세요.
)} -

- 총 합계 ₩ {totalPrice.toLocaleString()} +

+ 총 합계 ₩ {totalPrice.toLocaleString()}

-
+
+ ); +} diff --git a/apps/what-today/src/components/skeletons/activities/ActivitiesInformationSkeleton.tsx b/apps/what-today/src/components/skeletons/activities/ActivitiesInformationSkeleton.tsx new file mode 100644 index 00000000..75aaf0cb --- /dev/null +++ b/apps/what-today/src/components/skeletons/activities/ActivitiesInformationSkeleton.tsx @@ -0,0 +1,28 @@ +export default function ActivitiesInformationSkeleton() { + return ( +
+ {/* 카테고리 */} +
+ + {/* 제목 */} +
+ + {/* 평점 */} +
+
+
+
+ + {/* 주소 */} +
+
+
+
+ + {/* 가격 */} +
+
+
+
+ ); +} diff --git a/apps/what-today/src/components/skeletons/activities/ActivitiesMapSkeleton.tsx b/apps/what-today/src/components/skeletons/activities/ActivitiesMapSkeleton.tsx new file mode 100644 index 00000000..179b5bff --- /dev/null +++ b/apps/what-today/src/components/skeletons/activities/ActivitiesMapSkeleton.tsx @@ -0,0 +1,16 @@ +export default function ActivitiesMapSkeleton() { + return ( +
+ {/* 섹션 제목 */} +
+ + {/* 주소 */} +
+ + {/* 지도 영역 */} +
+
+
+
+ ); +} diff --git a/apps/what-today/src/components/skeletons/activities/ActivityDetailPageSkeleton.tsx b/apps/what-today/src/components/skeletons/activities/ActivityDetailPageSkeleton.tsx new file mode 100644 index 00000000..bbbeeb2c --- /dev/null +++ b/apps/what-today/src/components/skeletons/activities/ActivityDetailPageSkeleton.tsx @@ -0,0 +1,64 @@ +import { useResponsive } from '@/hooks/useResponsive'; + +import ActivitiesDescriptionSkeleton from './ActivitiesDescriptionSkeleton'; +import ActivitiesInformationSkeleton from './ActivitiesInformationSkeleton'; +import ActivitiesMapSkeleton from './ActivitiesMapSkeleton'; +import ActivityImagesSkeleton from './ActivityImagesSkeleton'; +import DividerSkeleton from './DividerSkeleton'; +import ReservationFormSkeleton from './ReservationFormSkeleton'; +import ReviewSectionSkeleton from './ReviewSectionSkeleton'; + +export default function ActivityDetailPageSkeleton() { + const { isDesktop } = useResponsive(); + + return ( + <> +
+ {isDesktop ? ( +
+ {/* 왼쪽 컬럼 */} +
+ + + + + + +
+ + {/* 오른쪽 사이드바 */} +
+ + +
+
+ ) : ( +
+ + + + + + + + + +
+ )} +
+ + {/* 모바일/태블릿 하단바 스켈레톤 */} + {!isDesktop && ( +
+
+
+
+
+
+
+
+
+ )} + + ); +} diff --git a/apps/what-today/src/components/skeletons/activities/ActivityImagesSkeleton.tsx b/apps/what-today/src/components/skeletons/activities/ActivityImagesSkeleton.tsx new file mode 100644 index 00000000..d6b915fa --- /dev/null +++ b/apps/what-today/src/components/skeletons/activities/ActivityImagesSkeleton.tsx @@ -0,0 +1,30 @@ +export default function ActivityImagesSkeleton() { + return ( +
+ {/* 왼쪽 메인 이미지 스켈레톤 */} +
+
+
+ + {/* 오른쪽 서브 이미지들 스켈레톤 */} +
+
+ {/* 서브 이미지 1 */} +
+
+
+ + {/* 서브 이미지 2 */} +
+
+
+ + {/* 서브 이미지 3 - col-span-2 */} +
+
+
+
+
+
+ ); +} diff --git a/apps/what-today/src/components/skeletons/activities/DividerSkeleton.tsx b/apps/what-today/src/components/skeletons/activities/DividerSkeleton.tsx new file mode 100644 index 00000000..188a2410 --- /dev/null +++ b/apps/what-today/src/components/skeletons/activities/DividerSkeleton.tsx @@ -0,0 +1,3 @@ +export default function DividerSkeleton() { + return
; +} diff --git a/apps/what-today/src/components/skeletons/activities/ReservationFormSkeleton.tsx b/apps/what-today/src/components/skeletons/activities/ReservationFormSkeleton.tsx new file mode 100644 index 00000000..f2cb601d --- /dev/null +++ b/apps/what-today/src/components/skeletons/activities/ReservationFormSkeleton.tsx @@ -0,0 +1,46 @@ +export default function ReservationFormSkeleton() { + return ( +
+
+ {/* 캘린더 스켈레톤 */} +
+ {/* 캘린더 헤더 */} +
+
+
+
+
+ + {/* 캘린더 그리드 */} +
+ {Array.from({ length: 35 }).map((_, index) => ( +
+ ))} +
+
+ + {/* 인원 선택 스켈레톤 */} +
+
+
+
+
+
+
+
+ + {/* 구분선 */} +
+ + {/* 총 합계 */} +
+
+
+
+
+
+
+
+
+ ); +} diff --git a/apps/what-today/src/components/skeletons/activities/ReviewCardSkeleton.tsx b/apps/what-today/src/components/skeletons/activities/ReviewCardSkeleton.tsx new file mode 100644 index 00000000..2e7333d9 --- /dev/null +++ b/apps/what-today/src/components/skeletons/activities/ReviewCardSkeleton.tsx @@ -0,0 +1,27 @@ +export default function ReviewCardSkeleton() { + return ( +
+ {/* 리뷰 헤더 */} +
+
+
+
+
+
+ {Array.from({ length: 5 }).map((_, starIndex) => ( +
+ ))} +
+
+
+
+
+ + {/* 리뷰 내용 */} +
+
+
+
+
+ ); +} diff --git a/apps/what-today/src/components/skeletons/activities/ReviewSectionSkeleton.tsx b/apps/what-today/src/components/skeletons/activities/ReviewSectionSkeleton.tsx new file mode 100644 index 00000000..d1df232c --- /dev/null +++ b/apps/what-today/src/components/skeletons/activities/ReviewSectionSkeleton.tsx @@ -0,0 +1,30 @@ +import ReviewCardSkeleton from './ReviewCardSkeleton'; + +export default function ReviewSectionSkeleton() { + return ( +
+ {/* 섹션 헤더 */} +
+
+
+
+ + {/* 평점 통계 */} +
+
+
+
+
+
+
+
+ + {/* 리뷰 카드들 */} +
+ {Array.from({ length: 3 }).map((_, index) => ( + + ))} +
+
+ ); +} diff --git a/apps/what-today/src/components/skeletons/activities/index.ts b/apps/what-today/src/components/skeletons/activities/index.ts new file mode 100644 index 00000000..bafbd27d --- /dev/null +++ b/apps/what-today/src/components/skeletons/activities/index.ts @@ -0,0 +1,9 @@ +export { default as ActivitiesDescriptionSkeleton } from './ActivitiesDescriptionSkeleton'; +export { default as ActivitiesInformationSkeleton } from './ActivitiesInformationSkeleton'; +export { default as ActivitiesMapSkeleton } from './ActivitiesMapSkeleton'; +export { default as ActivityDetailPageSkeleton } from './ActivityDetailPageSkeleton'; +export { default as ActivityImagesSkeleton } from './ActivityImagesSkeleton'; +export { default as DividerSkeleton } from './DividerSkeleton'; +export { default as ReservationFormSkeleton } from './ReservationFormSkeleton'; +export { default as ReviewCardSkeleton } from './ReviewCardSkeleton'; +export { default as ReviewSectionSkeleton } from './ReviewSectionSkeleton'; diff --git a/apps/what-today/src/pages/activities/index.tsx b/apps/what-today/src/pages/activities/index.tsx index 31144763..c8ac07be 100644 --- a/apps/what-today/src/pages/activities/index.tsx +++ b/apps/what-today/src/pages/activities/index.tsx @@ -1,5 +1,5 @@ import { useQueryClient } from '@tanstack/react-query'; -import { SpinIcon, useToast } from '@what-today/design-system'; +import { useToast } from '@what-today/design-system'; import { useState } from 'react'; import { useParams } from 'react-router-dom'; @@ -15,6 +15,7 @@ import TabletReservationSheet from '@/components/activities/reservation/TabletRe import type { ReservationSummary } from '@/components/activities/reservation/types'; import ReservationBottomBar from '@/components/activities/ReservationBottomBar'; import ReviewSection from '@/components/activities/ReviewSection'; +import { ActivityDetailPageSkeleton } from '@/components/skeletons/activities'; import { useActivityDetail } from '@/hooks/activityDetail'; import { useResponsive } from '@/hooks/useResponsive'; import NotFoundPage from '@/pages/not-found-page'; @@ -36,12 +37,7 @@ export default function ActivityDetailPage() { const { data: activity, isLoading: loading, error } = useActivityDetail(id); - if (loading) - return ( -
- -
- ); + if (loading) return ; if (error) return ; if (!activity) return ; @@ -96,7 +92,7 @@ export default function ActivityDetailPage() { <>
{isDesktop ? ( -
+
@@ -111,6 +107,7 @@ export default function ActivityDetailPage() { category={activity.category} id={id} isAuthor={user?.id ? activity?.userId === user.id : false} + price={activity.price} rating={activity.rating} reviewCount={activity.reviewCount} title={activity.title} @@ -133,15 +130,16 @@ export default function ActivityDetailPage() { category={activity.category} id={id} isAuthor={user?.id ? activity?.userId === user.id : false} + price={activity.price} rating={activity.rating} reviewCount={activity.reviewCount} title={activity.title} /> - + - + - +
)}