From 51ee0ab5ced0495d164078e3b4f40a0ede22dd45 Mon Sep 17 00:00:00 2001 From: sispo3314 Date: Tue, 5 Aug 2025 20:07:05 +0900 Subject: [PATCH 1/5] =?UTF-8?q?feat:=20AI=20=ED=9B=84=EA=B8=B0=20=EC=9A=94?= =?UTF-8?q?=EC=95=BD=20UI=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icons/smile.svg | 3 +++ src/assets/index.tsx | 5 +++-- src/pages/home/TheaterDetail.tsx | 11 ++++++++++- 3 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 src/assets/icons/smile.svg 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 590db39..6ac8bf7 100644 --- a/src/assets/index.tsx +++ b/src/assets/index.tsx @@ -39,7 +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 TicketAlt from '@/assets/gif/ticket_alt.gif'; export { @@ -85,4 +85,5 @@ export { EnvironmentIcon, CompanionIcon, TicketAlt, -}; \ No newline at end of file + SmileIcon, +}; diff --git a/src/pages/home/TheaterDetail.tsx b/src/pages/home/TheaterDetail.tsx index 677afdb..943baca 100644 --- a/src/pages/home/TheaterDetail.tsx +++ b/src/pages/home/TheaterDetail.tsx @@ -1,6 +1,6 @@ import { useNavigate, useParams } from 'react-router-dom'; import { Header, Image, Badge, ReviewCard } from '@/components'; -import { StarSmall, ArrowRight } from '@/assets'; +import { StarSmall, ArrowRight, SmileIcon } from '@/assets'; import { getRandomImage, reviewSummaryMock } from '@/__mocks'; import { cinemaData } from '@/constants'; @@ -58,6 +58,15 @@ const CinemaDetailPage = () => { + {/*AI 후기 요약*/} +
+
+ + AI 후기 요약 +
+
어쩌고저쩌고 후기 내용
+
+ {/*상세 정보*/}
{infoList.map(({ label, value }) => ( From 02dabfbfb88647d6e36b14f1f6fdfd395806290f Mon Sep 17 00:00:00 2001 From: sispo3314 Date: Tue, 5 Aug 2025 20:51:37 +0900 Subject: [PATCH 2/5] =?UTF-8?q?feat:=20=ED=83=9C=EA=B7=B8=20=EB=A6=AC?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icons/chevron_down.svg | 2 +- src/assets/icons/chevron_up.svg | 2 +- .../common/TagReviewNumber/TagCardList.tsx | 57 +++++++++++++++++++ .../TagReviewNumber/TagReviewNumber.tsx | 22 ++----- src/components/index.tsx | 4 ++ src/constants/taglist.ts | 15 +++++ src/pages/home/TheaterDetail.tsx | 5 +- 7 files changed, 88 insertions(+), 19 deletions(-) create mode 100644 src/components/common/TagReviewNumber/TagCardList.tsx create mode 100644 src/constants/taglist.ts 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/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 2012e01..982c90d 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'; export { default as FilterCheckbox } from '@/components/common/ReviewFilter/FilterCheckbox'; export { default as MyLevelCard } from './common/LevelCard/MyLevelCard'; @@ -61,4 +63,6 @@ export { SeatFocusModal, SeatWriteModal, ProgressBar, + TagReviewNumber, + TagCardList, }; 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 943baca..789d80f 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 { Header, Image, Badge, 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 }>(); @@ -67,6 +68,8 @@ const CinemaDetailPage = () => {
어쩌고저쩌고 후기 내용
+ + {/*상세 정보*/}
{infoList.map(({ label, value }) => ( From dfb324c00b1b4eed2d8ba9105a305d008465f46b Mon Sep 17 00:00:00 2001 From: sispo3314 Date: Tue, 5 Aug 2025 20:54:22 +0900 Subject: [PATCH 3/5] =?UTF-8?q?fix:=20=EC=83=81=EC=84=B8=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EB=9E=80=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/home/TheaterDetail.tsx | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/pages/home/TheaterDetail.tsx b/src/pages/home/TheaterDetail.tsx index 789d80f..1fd75f2 100644 --- a/src/pages/home/TheaterDetail.tsx +++ b/src/pages/home/TheaterDetail.tsx @@ -68,20 +68,9 @@ const CinemaDetailPage = () => {
어쩌고저쩌고 후기 내용
+ {/*많이 사용된 태그*/} - {/*상세 정보*/} -
- {infoList.map(({ label, value }) => ( -
- - {label} - - {value || '정보 없음'} -
- ))} -
- {/*후기*/}
From 31b50feeb04fc296e3b4e610b3005b839aeb439f Mon Sep 17 00:00:00 2001 From: sispo3314 Date: Tue, 5 Aug 2025 20:55:18 +0900 Subject: [PATCH 4/5] =?UTF-8?q?fix:=20=EC=82=AC=EC=9A=A9=ED=95=98=EC=A7=80?= =?UTF-8?q?=20=EC=95=8A=EB=8A=94=20=EC=BD=94=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/home/TheaterDetail.tsx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/pages/home/TheaterDetail.tsx b/src/pages/home/TheaterDetail.tsx index 1fd75f2..427c7c1 100644 --- a/src/pages/home/TheaterDetail.tsx +++ b/src/pages/home/TheaterDetail.tsx @@ -1,5 +1,5 @@ import { useNavigate, useParams } from 'react-router-dom'; -import { Header, Image, Badge, ReviewCard, TagCardList } from '@/components'; +import { Header, Image, ReviewCard, TagCardList } from '@/components'; import { StarSmall, ArrowRight, SmileIcon } from '@/assets'; import { getRandomImage, reviewSummaryMock } from '@/__mocks'; import { cinemaData } from '@/constants'; @@ -20,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 && From ae052a654066ebe2c00484f968d0f7938d919386 Mon Sep 17 00:00:00 2001 From: sispo3314 Date: Tue, 5 Aug 2025 21:24:01 +0900 Subject: [PATCH 5/5] =?UTF-8?q?refactor:=20=ED=99=88=20=EC=98=81=ED=99=94?= =?UTF-8?q?=EA=B4=80=20=EC=84=A0=ED=83=9D=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=EB=A1=9C=20=EB=8C=80=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/index.tsx | 2 + src/pages/home/TheatersList.tsx | 88 +++++++++------------------------ 2 files changed, 26 insertions(+), 64 deletions(-) diff --git a/src/components/index.tsx b/src/components/index.tsx index 982c90d..ba1c5c6 100644 --- a/src/components/index.tsx +++ b/src/components/index.tsx @@ -29,6 +29,7 @@ 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'; @@ -65,4 +66,5 @@ export { ProgressBar, TagReviewNumber, TagCardList, + TheaterList, }; 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}`); + }} + />
);