Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/pages/movie-reservation/Reservation.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useState, useEffect} from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { useQueryClient } from '@tanstack/react-query';
import Modal from '@components/@modal/Modal';
import Header from '@components/header/Header';
import Divider from '@components/divider/Divider';
Expand All @@ -12,6 +13,7 @@ import {
useModalDetail,
useDate,
useShowtimes,
prefetchShowtimes
} from '@pages/movie-reservation/hooks/index';
import { Carousel } from '@pages/movie-reservation/components/index';
import {
Expand All @@ -29,6 +31,8 @@ export default function Reservation() {
const location = useLocation();
const initialSelectedMovie = location.state?.movieId;

const queryClient = useQueryClient()

const [selectedShowtime, setSelectedShowtime] = useState<ShowtimeDetail | null>(null);
const dates = useDate();
const { isTooltipOpen, handleCloseTooltip } = useTooltip();
Expand Down Expand Up @@ -98,13 +102,15 @@ export default function Reservation() {
<Carousel
selectedMovieIds={selectedMovieIds}
initialSelectedMovie={initialSelectedMovie}
handleClick={id => handleClickMovie(id)}
handleClickMovie={id => handleClickMovie(id)}
prefetchConfig={{date: selectedDate.date, timeSlot: selectedTimeSlot, prefetchShowtimes, queryClient}}
/>
<CinemaChips selectedCinemas={selectedCinemas} />
<DateChips
dates={dates}
selectedDate={selectedDate}
handleClickDate={handleClickDate}
prefetchConfig={{movieIds: selectedMovieIds, timeSlot: selectedTimeSlot, prefetchShowtimes, queryClient}}
/>
</div>
<div className='mt-[1.8rem] mb-[1.6rem]'>
Expand All @@ -114,6 +120,7 @@ export default function Reservation() {
<TimeChips
selectedTimeId={selectedTimeId}
handleClickTime={handleClickTime}
prefetchConfig={{movieIds: selectedMovieIds, date: selectedDate.date, prefetchShowtimes, queryClient}}
/>
{isLoading ? (
<Spinner className='w-[15rem]' />
Expand Down
18 changes: 15 additions & 3 deletions src/pages/movie-reservation/components/Carousel.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import { cn } from '@utils/cn';
import { MOVIES } from '@constants/movies';
import type { PrefetchConfig } from '@pages/movie-reservation/types/index';

interface CarouselProps {
selectedMovieIds: number[];
initialSelectedMovie: number;
handleClick: (_id: number) => void;
handleClickMovie: (_id: number) => void;
prefetchConfig: PrefetchConfig;
}

export default function Carousel({
selectedMovieIds,
initialSelectedMovie,
handleClick,
handleClickMovie,
prefetchConfig
}: CarouselProps) {
const moviesWithSelectedFirst = Object.values(MOVIES).sort((a, b) => {
if (a.id === initialSelectedMovie) return -1;
Expand All @@ -29,7 +32,16 @@ export default function Carousel({
? 'border-gray-0 rounded-[0.4rem] border'
: 'rounded-[0.6rem] border border-transparent opacity-30'
)}
onClick={() => handleClick(movie.id)}
onClick={() => handleClickMovie(movie.id)}
onMouseEnter={() =>
prefetchConfig.prefetchShowtimes(prefetchConfig.queryClient, {
movieIds: selectedMovieIds.includes(movie.id)
? selectedMovieIds.filter(id => id !== movie.id)
: [movie.id, ...selectedMovieIds.filter(id => id !== movie.id)],
date: prefetchConfig.date,
timeSlot: prefetchConfig.timeSlot,
})
}
>
<img src={movie.image} className='w-full h-full rounded-[0.4rem] object-cover' />
</button>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/movie-reservation/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ export { useSelection } from '@pages/movie-reservation/hooks/use-selection';
export { useModalDetail } from '@pages/movie-reservation/hooks/use-modal-detail';
export { useDate } from '@pages/movie-reservation/hooks/use-date';
export { useCinemas } from '@pages/movie-reservation/hooks/use-cinemas';
export { useShowtimes } from '@pages/movie-reservation/hooks/use-showtimes';
export { useShowtimes, prefetchShowtimes } from '@pages/movie-reservation/hooks/use-showtimes';
export { useOneShowtime } from '@pages/movie-reservation/hooks/use-one-showtime';
30 changes: 19 additions & 11 deletions src/pages/movie-reservation/hooks/use-showtimes.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';
import { useQuery, type QueryClient } from '@tanstack/react-query';
import { type ShowtimeReadRequest } from 'apis/data-contracts';
import { showtimesKey } from '@pages/movie-reservation/utils/showtimes-key';

async function apiGetShowtimesFixed(params: ShowtimeReadRequest) {
async function getShowtimes(params: ShowtimeReadRequest) {
const { movieIds, date, timeSlot } = params;

const response = await axios.get(
Expand All @@ -29,15 +30,22 @@ async function apiGetShowtimesFixed(params: ShowtimeReadRequest) {
* @param timeSlot 선택된 시간대
* @returns 조건에 해당하는 상영정보 배열
*/
export function useShowtimes({
movieIds,
date,
timeSlot
}: ShowtimeReadRequest) {
export function useShowtimes(params: ShowtimeReadRequest) {
return useQuery({
queryKey: ['showtimes', movieIds, date, timeSlot],
queryFn: () =>
apiGetShowtimesFixed({ movieIds, date, timeSlot }),
enabled: movieIds && movieIds.length > 0,
queryKey: showtimesKey(params),
queryFn: () => getShowtimes(params),
enabled: params.movieIds && params.movieIds.length > 0,
staleTime: 1000 * 60,
});
}

export async function prefetchShowtimes(queryClient: QueryClient, params: ShowtimeReadRequest) {
if (!params.movieIds?.length) return;

await queryClient.prefetchQuery({
queryKey: showtimesKey(params),
queryFn: () => getShowtimes(params),
staleTime: 1000 * 60,
gcTime: 1000 * 60 * 5,
});
};
13 changes: 11 additions & 2 deletions src/pages/movie-reservation/section/DateChips.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import dayjs from 'dayjs';
import { cn } from '@utils/cn';
import { Chip } from '@pages/movie-reservation/components/index';
import { type Date } from '@pages/movie-reservation/types/date';
import type { Date, PrefetchConfig } from '@pages/movie-reservation/types/index';

interface DateChipsProps {
dates: Date[];
selectedDate: Date;
handleClickDate: (_: Date) => void;
prefetchConfig: PrefetchConfig;
}

export default function DateChips({
dates,
selectedDate,
handleClickDate
handleClickDate,
prefetchConfig,
}: DateChipsProps) {
return (
<div className='scrollbar-hide flex w-full gap-[0.7rem] overflow-x-scroll px-[0.5rem]'>
Expand All @@ -29,6 +31,13 @@ export default function DateChips({
variant='date'
isSelected={selectedDate.date === dateInfo.date}
onClick={() => handleClickDate(dateInfo)}
onMouseEnter={() => {
prefetchConfig.prefetchShowtimes(prefetchConfig.queryClient, {
movieIds: prefetchConfig.movieIds,
date: dateInfo.date,
timeSlot: prefetchConfig.timeSlot,
})
}}
>
<span className={cn('font-title3', dayColorClass)}>
{dateString}
Expand Down
14 changes: 12 additions & 2 deletions src/pages/movie-reservation/section/TimeChips.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { TIMES } from '@pages/movie-reservation/constants/index';
import { TIMES, type TimeType } from '@pages/movie-reservation/constants/index';
import { Chip } from '@pages/movie-reservation/components/index';
import type { PrefetchConfig } from '@pages/movie-reservation/types/index';

interface TimeChipsProps {
selectedTimeId: number | null;
handleClickTime: (_: number) => void;
prefetchConfig: PrefetchConfig;
}

export default function TimeChips({
selectedTimeId,
handleClickTime
handleClickTime,
prefetchConfig,
}: TimeChipsProps) {
return (
<div className='scrollbar-hide flex w-full items-start gap-[0.8rem] overflow-x-scroll py-[1rem] opacity-70'>
Expand All @@ -19,6 +22,13 @@ export default function TimeChips({
variant='time'
isSelected={selectedTimeId === idx}
onClick={() => handleClickTime(idx)}
onMouseEnter={() => {
prefetchConfig.prefetchShowtimes(prefetchConfig.queryClient, {
movieIds: prefetchConfig.movieIds,
date: prefetchConfig.date,
timeSlot: TIMES[idx].type as TimeType
})
}}
>
{TIMES[idx].label}
</Chip>
Expand Down
3 changes: 2 additions & 1 deletion src/pages/movie-reservation/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { type Date } from './date';
export { type ShowtimeDetail } from './showtime-detail';
export { type AgeRating } from './age-rating';
export { type AgeRating } from './age-rating';
export { type PrefetchConfig } from './prefetch-config';
10 changes: 10 additions & 0 deletions src/pages/movie-reservation/types/prefetch-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { QueryClient } from '@tanstack/react-query';
import { type ShowtimeReadRequest } from 'apis/data-contracts';

export interface PrefetchConfig {
movieIds?: number[];
date?: string;
timeSlot?: ShowtimeReadRequest['timeSlot'];
queryClient: QueryClient;
prefetchShowtimes: (_: QueryClient, __: ShowtimeReadRequest) => void;
}
8 changes: 8 additions & 0 deletions src/pages/movie-reservation/utils/showtimes-key.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { type ShowtimeReadRequest } from 'apis/data-contracts';

export const showtimesKey = (params: ShowtimeReadRequest) => [
'showtimes',
JSON.stringify([...(params.movieIds ?? [])].sort((a, b) => a - b)),
params.date,
params.timeSlot ?? null,
];