diff --git a/apps/what-today/src/pages/mypage/reservations-list/index.tsx b/apps/what-today/src/pages/mypage/reservations-list/index.tsx index 42179e84..b7898be7 100644 --- a/apps/what-today/src/pages/mypage/reservations-list/index.tsx +++ b/apps/what-today/src/pages/mypage/reservations-list/index.tsx @@ -7,6 +7,7 @@ import { NoResult, RadioGroup, ReservationCard, + SpinIcon, StarRating, } from '@what-today/design-system'; import { WarningLogo } from '@what-today/design-system'; @@ -19,12 +20,25 @@ import { cancelMyReservation, createReview, fetchMyReservations } from '@/apis/m import useIntersectionObserver from '@/hooks/useIntersectionObserver'; import type { MyReservationsResponse, Reservation, ReservationStatus } from '@/schemas/myReservations'; +// 필터링 가능한 상태 타입 (전체 상태 + 빈 문자열) +type FilterStatus = ReservationStatus | ''; + +// 예약 상태별 NoResult 메시지 상수 (컴포넌트 외부에 정의하여 최적화) +const NO_RESULT_MESSAGES: Record = { + '': '예약한 체험이', + pending: '대기 중인 예약이', + confirmed: '승인된 예약이', + declined: '거절된 예약이', + canceled: '취소된 예약이', + completed: '완료된 체험이', +}; + export default function ReservationsListPage() { const navigate = useNavigate(); const { toast } = useToast(); const queryClient = useQueryClient(); - const [selectedStatus, setSelectedStatus] = useState(''); + const [selectedStatus, setSelectedStatus] = useState(''); const [cancelTarget, setCancelTarget] = useState(null); const isDeleteOpen = cancelTarget !== null; @@ -54,6 +68,15 @@ export default function ReservationsListPage() { const reservations = data?.pages.flatMap((page) => page.reservations) ?? []; + const noResultMessage = NO_RESULT_MESSAGES[selectedStatus]; + + // 리뷰 모달 닫기 핸들러 + const handleCloseReviewModal = () => { + setReviewTarget(null); + setReviewContent(''); + setStarRating(0); + }; + const scrollContainerRef = useRef(null); const observerRef = useIntersectionObserver( fetchNextPage, @@ -93,14 +116,12 @@ export default function ReservationsListPage() { type: 'success', }); setReviewTarget(null); - setReviewContent(''); - setStarRating(0); queryClient.invalidateQueries({ queryKey: ['reservations'] }); }, - onError: () => { + onError: (error) => { toast({ title: '후기 작성 실패', - description: '후기 작성 중 문제가 발생했습니다.', + description: error instanceof Error ? error.message : '후기 작성 중 문제가 발생했습니다.', type: 'error', }); }, @@ -128,6 +149,7 @@ export default function ReservationsListPage() { {group.map((res) => { const showCancelButton = res.status === 'pending'; const showReviewButton = res.status === 'completed' && !res.reviewSubmitted; + const showReviewCompletedButton = res.status === 'completed' && res.reviewSubmitted; return (
  • @@ -142,7 +164,7 @@ export default function ReservationsListPage() { onClick={() => navigate(`/activities/${res.activity.id}`)} /> - {(showCancelButton || showReviewButton) && ( + {(showCancelButton || showReviewButton || showReviewCompletedButton) && (
    {showCancelButton && ( + )}
    )}
  • @@ -176,13 +203,17 @@ export default function ReservationsListPage() { let content; if (isLoading) { - content =
    로딩 중...
    ; + content = ( +
    + +
    + ); } else if (reservations.length > 0) { content =
    {renderGroupedReservations(reservations)}
    ; } else { content = (
    - +
    ); } @@ -203,7 +234,7 @@ export default function ReservationsListPage() { setSelectedStatus(String(value))} + onSelect={(value) => setSelectedStatus(value as FilterStatus)} > 예약 대기 예약 승인 @@ -237,12 +268,12 @@ export default function ReservationsListPage() { - setReviewTarget(null)}> + {reviewTarget && (

    {reviewTarget.activity.title}

    -

    +

    {reviewTarget.date}/ {reviewTarget.startTime} ~ {reviewTarget.endTime} ({reviewTarget.headCount}명)

    diff --git a/packages/design-system/src/components/StarRating.tsx b/packages/design-system/src/components/StarRating.tsx index cedee4f0..8249cab6 100644 --- a/packages/design-system/src/components/StarRating.tsx +++ b/packages/design-system/src/components/StarRating.tsx @@ -64,7 +64,7 @@ export default function StarRating({ value, onChange, max = 5, className }: Star onClick={() => onChange(starValue)} onMouseEnter={() => setHoverValue(starValue)} > - + ); })}