diff --git a/src/components/Homepage/Homepage.tsx b/src/components/Homepage/Homepage.tsx index 7f4f271..3582dea 100644 --- a/src/components/Homepage/Homepage.tsx +++ b/src/components/Homepage/Homepage.tsx @@ -1,12 +1,22 @@ import { Button, Paper } from '@mantine/core'; +import { useEffect } from 'react'; import { BsInstagram, BsTwitterX, BsYoutube } from 'react-icons/bs'; import { ImFacebook2 } from 'react-icons/im'; +import { moviesApiSlice } from '../../features/moviesApiSlice'; import './Homepage.scss'; import LastReviews from './LastReviews/LastReviews'; import NewsFeed from './NewsFeed/NewsFeed'; import PosterCarousel from './PosterCarousel/PosterCarousel'; function Homepage() { + const prefetchMovies = moviesApiSlice.usePrefetch('getMoviesByFilter'); + const prefetchMovieList = moviesApiSlice.usePrefetch('getMoviesByParams'); + + useEffect(() => { + prefetchMovies('nowplaying'); + prefetchMovieList({ page: 1, sort_by: 'popularity.desc', with_genres: '' }); + }, [prefetchMovies, prefetchMovieList]); + return (
diff --git a/src/components/MoviesPage/MoviesPage.tsx b/src/components/MoviesPage/MoviesPage.tsx index fa75a8c..06cb412 100644 --- a/src/components/MoviesPage/MoviesPage.tsx +++ b/src/components/MoviesPage/MoviesPage.tsx @@ -1,11 +1,9 @@ import { Badge, Button, Card, Image, Text } from '@mantine/core'; -import { useEffect, useState } from 'react'; +import { useState } from 'react'; import { Link } from 'react-router-dom'; import { MoviesFilter } from '../../@types/MovieState'; -import MovieType from '../../@types/MovieType'; -import { getMovieById } from '../../apiHandler/api'; import no_poster from '../../assets/no-poster.webp'; -import { useGetMoviesByFilterQuery } from '../../features/moviesApiSlice'; +import { useGetMoviesByFilterQuery, useGetMoviesDetailsQuery } from '../../features/moviesApiSlice'; import { useAppSelector } from '../../store/hooks'; import ButtonAddToPlaylist from '../ui/ButtonAddToPlaylist/ButtonAddToPlaylist'; import Loader from '../ui/Loader/Loader'; @@ -26,50 +24,25 @@ const truncateTextWithSlice = (text: string, maxLength: number) => function MoviesPage({ title, filter }: { title: string; filter: MoviesFilter }) { const { data: movieList } = useGetMoviesByFilterQuery(filter); const logged = useAppSelector((state) => state.settings.user.logged); - const [detailedMovies, setDetailedMovies] = useState([]); const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('desc'); - const [loading, setLoading] = useState(true); - - useEffect(() => { - async function fetchDetails() { - if (!movieList || movieList.length === 0) { - return; - } - setLoading(true); - // impossible to use RTK Query here - const promisesList = movieList.map((movie) => - getMovieById(movie.tmdb_id.toString()) - .then((response) => ({ ...movie, ...response.data.data })) - .catch((error) => { - // eslint-disable-next-line no-console - console.error(`Error fetching details for movie ${movie.tmdb_id}:`, error); - }) - ); - try { - const results = await Promise.all(promisesList); - setDetailedMovies(results); - } catch (error) { - // eslint-disable-next-line no-console - console.error('Error fetching movie details:', error); - } finally { - setLoading(false); - } - } - fetchDetails(); - }, [movieList]); - - const sortedMovieList = detailedMovies.slice().sort((a, b) => { - if (sortOrder === 'asc') { - return new Date(a.release_date).getTime() - new Date(b.release_date).getTime(); - } - return new Date(b.release_date).getTime() - new Date(a.release_date).getTime(); + const { data: detailedMovies, isLoading } = useGetMoviesDetailsQuery(movieList || [], { + skip: !movieList || movieList.length === 0, }); + const sortedMovieList = detailedMovies?.length + ? detailedMovies.slice().sort((a, b) => { + if (sortOrder === 'asc') { + return new Date(a.release_date).getTime() - new Date(b.release_date).getTime(); + } + return new Date(b.release_date).getTime() - new Date(a.release_date).getTime(); + }) + : []; + const toggleSortOrder = () => { setSortOrder((prevSortOrder) => (prevSortOrder === 'asc' ? 'desc' : 'asc')); }; - return loading ? ( + return isLoading ? (
diff --git a/src/features/moviesApiSlice.ts b/src/features/moviesApiSlice.ts index 05f1e7c..ac84ad7 100644 --- a/src/features/moviesApiSlice.ts +++ b/src/features/moviesApiSlice.ts @@ -37,6 +37,24 @@ export const moviesApiSlice = apiSlice.enhanceEndpoints({ addTagTypes: ['MovieUs query: (filter: MoviesFilter) => ({ url: `/movie/${filter}`, }), + async onQueryStarted(_params, { dispatch, queryFulfilled }) { + // Prefetch all movies of the list + const { data: movies } = await queryFulfilled; + movies.forEach((movie: MovieType) => { + dispatch(moviesApiSlice.endpoints.getMovieById.initiate(movie.tmdb_id.toString())); + }); + }, + }), + getMoviesDetails: builder.query({ + // Fetch all movies of the list + async queryFn(movieList: MovieType[], { dispatch }): Promise<{ data: MovieType[] }> { + const detailPromises = movieList.map((movie) => + dispatch(moviesApiSlice.endpoints.getMovieById.initiate(movie.tmdb_id.toString())) + ); + const results = await Promise.all(detailPromises); + const data = results.map((result) => result.data).filter((movie): movie is MovieType => !!movie); + return { data }; + }, }), getGenres: builder.query({ query: () => ({ @@ -195,6 +213,7 @@ export const { useGetUserdataMovieByIdQuery, useGetMoviesByParamsQuery, useGetMoviesByFilterQuery, + useGetMoviesDetailsQuery, useGetGenresQuery, useSearchMoviesQuery, usePostReviewMutation,