diff --git a/src/assets/icons/chevron_down.svg b/src/assets/icons/chevron_down.svg index 910d318..14ee399 100644 --- a/src/assets/icons/chevron_down.svg +++ b/src/assets/icons/chevron_down.svg @@ -1,3 +1,3 @@ - + diff --git a/src/assets/icons/chevron_up.svg b/src/assets/icons/chevron_up.svg index d68cfc3..30be611 100644 --- a/src/assets/icons/chevron_up.svg +++ b/src/assets/icons/chevron_up.svg @@ -1,3 +1,3 @@ - + diff --git a/src/assets/icons/smile.svg b/src/assets/icons/smile.svg new file mode 100644 index 0000000..153492f --- /dev/null +++ b/src/assets/icons/smile.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/index.tsx b/src/assets/index.tsx index 8265aa2..e9133a1 100644 --- a/src/assets/index.tsx +++ b/src/assets/index.tsx @@ -39,6 +39,7 @@ import NaverIcon from '@/assets/icons/naver_icon.svg?react'; import SoundIcon from '@/assets/icons/sound.svg?react'; import EnvironmentIcon from '@/assets/icons/environment.svg?react'; import CompanionIcon from '@/assets/icons/companion.svg?react'; +import SmileIcon from '@/assets/icons/smile.svg?react'; import GalleryProfileIcon from '@/assets/icons/file_select.svg?react'; import TicketAlt from '@/assets/gif/ticket_alt.gif'; @@ -86,5 +87,6 @@ export { EnvironmentIcon, CompanionIcon, TicketAlt, + SmileIcon, GalleryProfileIcon, }; diff --git a/src/components/common/TagReviewNumber/TagCardList.tsx b/src/components/common/TagReviewNumber/TagCardList.tsx new file mode 100644 index 0000000..6e01331 --- /dev/null +++ b/src/components/common/TagReviewNumber/TagCardList.tsx @@ -0,0 +1,57 @@ +import { useState } from 'react'; +import { ChevronDownIcon, ChevronUpIcon } from '@/assets'; +import { TagReviewNumber } from '@/components'; + +interface TagReview { + iconType: 'sound' | 'environment' | 'companion'; + title: string; + count: number; +} + +interface TagCardListProps { + tags: TagReview[]; + maxVisible?: number; +} + +const TagCardList = ({ tags, maxVisible = 4 }: TagCardListProps) => { + const [expanded, setExpanded] = useState(false); + const visibleTags = expanded ? tags : tags.slice(0, maxVisible); + const hasOverflow = tags.length > maxVisible; + + return ( +
+
+ {visibleTags.map((tag, index) => ( + + ))} +
+ {!expanded && hasOverflow && ( +
+ )} + {hasOverflow && ( +
+
+ +
+
+ )} +
+ ); +}; + +export default TagCardList; diff --git a/src/components/common/TagReviewNumber/TagReviewNumber.tsx b/src/components/common/TagReviewNumber/TagReviewNumber.tsx index 6207e6f..05cd244 100644 --- a/src/components/common/TagReviewNumber/TagReviewNumber.tsx +++ b/src/components/common/TagReviewNumber/TagReviewNumber.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import {SoundIcon, CompanionIcon, EnvironmentIcon} from '@/assets'; +import { SoundIcon, CompanionIcon, EnvironmentIcon } from '@/assets'; const iconComponents = { sound: SoundIcon, @@ -15,31 +15,21 @@ interface TagReviewNumberProps { className?: string; } - -const TagReviewNumber: React.FC = ({ - iconType, - title, - count, - className, -}) => { +const TagReviewNumber: React.FC = ({ iconType, title, count, className }) => { const IconComponent = iconComponents[iconType]; return (
-
+
-

{title}

+

{title}

{count}

); }; -export default TagReviewNumber; \ No newline at end of file +export default TagReviewNumber; diff --git a/src/components/index.tsx b/src/components/index.tsx index d89f33e..0baced7 100644 --- a/src/components/index.tsx +++ b/src/components/index.tsx @@ -27,6 +27,8 @@ import ConfirmModal from '@/components/common/Modal/ConfirmModal'; import SeatFocusModal from '@/components/common/Modal/SeatModal/SeatFocusModal'; import SeatWriteModal from '@/components/common/Modal/SeatModal/SeatWriteModal'; import ProgressBar from '@/components/common/ProgressBar/ProgressBar'; +import TagReviewNumber from './common/TagReviewNumber/TagReviewNumber'; +import TagCardList from './common/TagReviewNumber/TagCardList'; import TheaterList from './common/Theater/TheaterList'; export { default as FilterCheckbox } from '@/components/common/ReviewFilter/FilterCheckbox'; export { default as MyLevelCard } from './common/LevelCard/MyLevelCard'; @@ -61,5 +63,7 @@ export { SeatFocusModal, SeatWriteModal, ProgressBar, + TagReviewNumber, + TagCardList, TheaterList, }; diff --git a/src/constants/taglist.ts b/src/constants/taglist.ts new file mode 100644 index 0000000..bfb6e69 --- /dev/null +++ b/src/constants/taglist.ts @@ -0,0 +1,15 @@ +interface TagReview { + iconType: 'sound' | 'environment' | 'companion'; + title: string; + count: number; +} + +const tagList: TagReview[] = [ + { iconType: 'sound', title: '음향이 최고예요', count: 132 }, + { iconType: 'sound', title: '서라운드가 좋아요', count: 132 }, + { iconType: 'environment', title: '입출입이 편리해요', count: 132 }, + { iconType: 'companion', title: '혼자서도 좋아요', count: 132 }, + { iconType: 'companion', title: '친구랑 재밌었어요', count: 62 }, + { iconType: 'environment', title: '분위기가 좋아요', count: 55 }, +] as const; +export default tagList; diff --git a/src/pages/home/TheaterDetail.tsx b/src/pages/home/TheaterDetail.tsx index 677afdb..427c7c1 100644 --- a/src/pages/home/TheaterDetail.tsx +++ b/src/pages/home/TheaterDetail.tsx @@ -1,8 +1,9 @@ import { useNavigate, useParams } from 'react-router-dom'; -import { Header, Image, Badge, ReviewCard } from '@/components'; -import { StarSmall, ArrowRight } from '@/assets'; +import { Header, Image, ReviewCard, TagCardList } from '@/components'; +import { StarSmall, ArrowRight, SmileIcon } from '@/assets'; import { getRandomImage, reviewSummaryMock } from '@/__mocks'; import { cinemaData } from '@/constants'; +import tagList from '@/constants/taglist'; const CinemaDetailPage = () => { const { auditoriumId } = useParams<{ auditoriumId: string }>(); @@ -19,12 +20,6 @@ const CinemaDetailPage = () => { : cinema.theaterName : '영화관 정보 없음'; - const infoList = [ - { label: '스크린', value: cinema?.screenSize }, - { label: '영사 포맷', value: '정보 없음' }, //스웨거에 없는 것 같습니다... - { label: '음향', value: cinema?.soundType }, - ]; - const reviews = reviewSummaryMock.filter( (review) => review.movieSeatInfo.theaterName === cinema?.theaterName && @@ -58,18 +53,18 @@ const CinemaDetailPage = () => {
- {/*상세 정보*/} -
- {infoList.map(({ label, value }) => ( -
- - {label} - - {value || '정보 없음'} -
- ))} + {/*AI 후기 요약*/} +
+
+ + AI 후기 요약 +
+
어쩌고저쩌고 후기 내용
+ {/*많이 사용된 태그*/} + + {/*후기*/}
diff --git a/src/pages/home/TheatersList.tsx b/src/pages/home/TheatersList.tsx index 3182732..be5560c 100644 --- a/src/pages/home/TheatersList.tsx +++ b/src/pages/home/TheatersList.tsx @@ -1,21 +1,25 @@ import { useState } from 'react'; -import { ToggleTab, Button, Header } from '@/components'; -import { groupCinemasByTheater } from '@/utils/groupCinemasByTheater'; +import { ToggleTab, Header, TheaterList } from '@/components'; import { useLocation, useNavigate } from 'react-router-dom'; +import type { CinemaFormat } from '@/types/onboarding'; +import { useTheatersQuery } from '@/hooks/queries/useTheatersQuery'; export default function TheaterListPage() { const navigate = useNavigate(); const location = useLocation(); const queryTab = new URLSearchParams(location.search).get('tab'); - const defaultTab: 'IMAX' | 'Dolby Cinema' = - queryTab?.toLowerCase() === 'dolby' ? 'Dolby Cinema' : 'IMAX'; + const initialTab: CinemaFormat = queryTab === 'dolby' ? 'Dolby' : 'IMAX'; - const [selectedTab, setSelectedTab] = useState<'IMAX' | 'Dolby Cinema'>(defaultTab); - const [selectedCinema, setSelectedCinema] = useState(null); - const [selectedHall, setSelectedHall] = useState(null); + const [selectedTab, setSelectedTab] = useState(initialTab); + const [selectedAuditorium, setSelectedAuditorium] = useState(null); - const cinemas = groupCinemasByTheater(selectedTab); + const { data: theaters } = useTheatersQuery({ type: selectedTab, page: 1, size: 10 }); + + const handleTabChange = (tab: string) => { + setSelectedTab(tab as CinemaFormat); + setSelectedAuditorium(null); + }; return (
@@ -28,68 +32,24 @@ export default function TheaterListPage() { { - setSelectedTab(option as 'IMAX' | 'Dolby Cinema'); - setSelectedCinema(null); - setSelectedHall(null); - }} + onSelect={handleTabChange} />
+
+ {/* 리스트 */} - {/* 리스트 */} -
-
- {Object.entries(cinemas).map(([theaterName, halls]) => { - const isSelected = selectedCinema === theaterName; - const isMulti = halls.length > 1; - return ( -
- - - {isSelected && isMulti && ( -
- {halls.map((hall) => ( - - ))} -
- )} -
- ); - })} -
+ setSelectedAuditorium(id)} + onAuditoriumClick={(auditoriumId) => { + navigate(`/theaters/${auditoriumId}`); + }} + />
);