web / frontend /src /pages /HomePage.tsx
Chandima Prabhath
Track bun.lockb with Git LFS
cc2caf9
raw
history blame
5.96 kB
import { useEffect, useState } from 'react';
import HeroSection from '../components/HeroSection';
import ContentRow from '../components/ContentRow';
import { getRecentItems, getGenreCategories, getGenresItems, getMovieCard, getTvShowCard } from '../lib/api';
import { useToast } from '@/hooks/use-toast';
// GenreRow component for dynamic loading of a genre row
const GenreRow = ({ genre, type }) => {
const [loading, setLoading] = useState(true);
const [items, setItems] = useState([]);
const { toast } = useToast();
useEffect(() => {
const fetchGenreData = async () => {
try {
// Fetch titles for the given genre and type
const genreItems = await getGenresItems([genre], type, 10, 1);
const titles =
type === "movie"
? (genreItems && Array.isArray(genreItems.movies)
? genreItems.movies.map(item => item.title)
: [])
: (genreItems && Array.isArray(genreItems.series)
? genreItems.series.map(item => item.title)
: []);
if (titles.length === 0) {
setLoading(false);
return;
}
// For each title, fetch the card details
const fetchCard = async (title) => {
try {
if (type === "movie") {
const movieInfo = await getMovieCard(title);
if (movieInfo) {
return {
type: 'movie',
title,
image: movieInfo.image,
description: movieInfo.overview,
genre: movieInfo.genres?.map((g) => g.name) || [],
year: movieInfo.year
};
}
} else {
const showInfo = await getTvShowCard(title);
if (showInfo) {
return {
type: 'tvshow',
title,
image: showInfo.image,
description: showInfo.overview,
genre: showInfo.genres?.map((g) => g.name) || [],
year: showInfo.year
};
}
}
} catch (error) {
console.error(`Error fetching card for ${title}:`, error);
return null;
}
return null;
};
const cardPromises = titles.map((title) => fetchCard(title));
const cards = await Promise.all(cardPromises);
setItems(cards.filter(item => item !== null));
} catch (error) {
console.error(`Error fetching ${type} items for genre ${genre}:`, error);
toast({
title: `Error loading ${type} items`,
description: `Failed to load ${genre} ${type} items`,
variant: "destructive"
});
} finally {
setLoading(false);
}
};
fetchGenreData();
}, [genre, type, toast]);
// While data is being fetched, show a simple loader in place of the row
if (loading) {
return (
<div className="px-4 md:px-8 py-8">
<h2 className="text-xl font-bold mb-4">{genre} {type === "movie" ? "Movies" : "Shows"}</h2>
<div className="flex items-center justify-center h-32">
<div className="animate-spin rounded-full h-8 w-8 border-t-2 border-b-2 border-netflix-red"></div>
</div>
</div>
);
}
// If no items were found, render nothing
if (items.length === 0) return null;
return (
<ContentRow title={`${genre} ${type === "movie" ? "Movies" : "Shows"}`} items={items} />
);
};
const HomePage = () => {
const [loading, setLoading] = useState(true);
const [heroContent, setHeroContent] = useState(null);
const [recentContent, setRecentContent] = useState([]);
const [genres, setGenres] = useState([]);
const { toast } = useToast();
useEffect(() => {
const fetchHomeData = async () => {
try {
setLoading(true);
// Fetch recent items for hero and recent content row
const recentItems = await getRecentItems(10);
if (recentItems && recentItems.length > 0) {
setHeroContent(recentItems[0]);
setRecentContent(recentItems);
}
// Fetch all genre categories (movies and shows together)
const genresRes = await getGenreCategories();
console.log("Fetched genres:", genresRes);
const allGenres = Array.isArray(genresRes)
? genresRes.map((g) => g.name)
: genresRes.genres
? genresRes.genres.map((g) => g.name)
: [];
console.log("All genres:", allGenres);
setGenres(allGenres);
} catch (error) {
console.error("Error fetching home page data:", error);
toast({
title: "Error loading content",
description: "Please try again later",
variant: "destructive"
});
} finally {
setLoading(false);
}
};
fetchHomeData();
}, [toast]);
if (loading) {
return (
<div className="flex items-center justify-center min-h-screen">
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-netflix-red"></div>
</div>
);
}
return (
<div>
{/* Hero Section */}
{heroContent && (
<HeroSection
type={heroContent.type}
title={heroContent.title}
description={heroContent.description}
backdrop={heroContent.image}
genre={heroContent.genre}
year={heroContent.year}
/>
)}
<div className="mt-8">
{/* Recent Content Row */}
<ContentRow title="Recent Additions" items={recentContent} />
{/* Render genre rows dynamically */}
{genres.map((genre) => (
<div key={genre}>
<GenreRow genre={genre} type="movie" />
<GenreRow genre={genre} type="series" />
</div>
))}
</div>
</div>
);
};
export default HomePage;