Главная страница
Создание главной страницы
This commit is contained in:
parent
068794b4a6
commit
8bda3252cd
@ -1,188 +1,138 @@
|
|||||||
import { useEffect } from "react";
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from 'react-router-dom';
|
||||||
import { useMedia } from "../contexts/MediaContext";
|
import { useMedia } from '../contexts/MediaContext';
|
||||||
import { useAuth } from "../contexts/AuthContext";
|
import { useAuth } from '../contexts/AuthContext';
|
||||||
import MediaCarousel from "../components/media/MediaCarousel";
|
import { listMedia } from '../services/supabase';
|
||||||
|
import { mediaTypes } from '../services/mediaService';
|
||||||
import { FiTrendingUp, FiCalendar, FiAward } from "react-icons/fi";
|
import { FiTrendingUp, FiCalendar, FiAward } from "react-icons/fi";
|
||||||
|
import MediaCarousel from "../components/media/MediaCarousel";
|
||||||
import { getImageUrl } from "../services/tmdbApi";
|
import { getImageUrl } from "../services/tmdbApi";
|
||||||
|
|
||||||
function HomePage() {
|
const HomePage = () => {
|
||||||
const { fetchTrendingMedia, trendingMovies, trendingTvShows, loading } =
|
const [media, setMedia] = useState([]);
|
||||||
useMedia();
|
const [loading, setLoading] = useState(true);
|
||||||
const { currentUser } = useAuth();
|
const [error, setError] = useState(null);
|
||||||
|
const { user } = useAuth();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchTrendingMedia();
|
const loadMedia = async () => {
|
||||||
}, [fetchTrendingMedia]);
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
setError(null);
|
||||||
|
const { data, error } = await listMedia();
|
||||||
|
|
||||||
// Get featured media (first trending movie with backdrop)
|
if (error) {
|
||||||
const featuredMedia =
|
throw new Error(error);
|
||||||
trendingMovies.find((movie) => movie.backdrop_path) || trendingMovies[0];
|
}
|
||||||
|
|
||||||
|
setMedia(data || []);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error loading media:', err);
|
||||||
|
setError('Не удалось загрузить контент');
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadMedia();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<div className="pt-20">
|
<div className="min-h-screen bg-campfire-dark pt-20">
|
||||||
{/* Hero Section */}
|
<div className="container-custom py-12">
|
||||||
{featuredMedia && (
|
|
||||||
<div className="relative w-full h-[500px] md:h-[600px] overflow-hidden">
|
|
||||||
<div className="absolute inset-0">
|
|
||||||
<img
|
|
||||||
src={getImageUrl(featuredMedia.backdrop_path, "original")}
|
|
||||||
alt={featuredMedia.title}
|
|
||||||
className="w-full h-full object-cover"
|
|
||||||
/>
|
|
||||||
<div className="absolute inset-0 bg-gradient-to-t from-campfire-dark via-campfire-dark/60 to-transparent"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="container-custom relative h-full flex flex-col justify-end pb-16">
|
|
||||||
<span className="inline-flex items-center px-3 py-1 rounded-full text-xs font-medium bg-campfire-amber text-campfire-dark mb-4">
|
|
||||||
<FiTrendingUp className="mr-1" /> Trending
|
|
||||||
</span>
|
|
||||||
<h1 className="text-4xl md:text-5xl font-bold mb-4 max-w-2xl">
|
|
||||||
{featuredMedia.title}
|
|
||||||
</h1>
|
|
||||||
<p className="text-campfire-ash mb-6 max-w-2xl">
|
|
||||||
{featuredMedia.overview.substring(0, 200)}...
|
|
||||||
</p>
|
|
||||||
<Link
|
|
||||||
to={`/media/${featuredMedia.id}?type=movie`}
|
|
||||||
className="btn-primary inline-flex items-center"
|
|
||||||
>
|
|
||||||
View Details
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Welcome Message for Logged In Users */}
|
|
||||||
{currentUser && (
|
|
||||||
<div className="container-custom my-8">
|
|
||||||
<div className="bg-campfire-charcoal rounded-lg p-6">
|
|
||||||
<h2 className="text-2xl font-bold mb-2">
|
|
||||||
С возвращением, {currentUser.username}!
|
|
||||||
</h2>
|
|
||||||
<p className="text-campfire-ash mb-4">
|
|
||||||
Продолжайте открывать отличный контент и делиться своими мыслями с
|
|
||||||
сообществом.
|
|
||||||
</p>
|
|
||||||
<Link
|
|
||||||
to={`/profile/${currentUser.uid}`}
|
|
||||||
className="text-campfire-amber hover:text-campfire-ember"
|
|
||||||
>
|
|
||||||
Перейти в профиль →
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Main Content */}
|
|
||||||
<div className="container-custom py-8">
|
|
||||||
{loading ? (
|
|
||||||
<div className="flex justify-center items-center h-64">
|
<div className="flex justify-center items-center h-64">
|
||||||
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-campfire-amber"></div>
|
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-campfire-amber"></div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{/* Trending Movies */}
|
|
||||||
<div className="mb-12">
|
|
||||||
<div className="flex items-center mb-2">
|
|
||||||
<FiTrendingUp className="text-campfire-amber mr-2" size={20} />
|
|
||||||
<h2 className="text-2xl font-bold">Фильмы</h2>
|
|
||||||
</div>
|
|
||||||
<MediaCarousel
|
|
||||||
media={trendingMovies}
|
|
||||||
mediaType="movie"
|
|
||||||
seeAllLink="/discover/movies"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Trending TV Shows */}
|
|
||||||
<div className="mb-12">
|
|
||||||
<div className="flex items-center mb-2">
|
|
||||||
<FiTrendingUp className="text-campfire-amber mr-2" size={20} />
|
|
||||||
<h2 className="text-2xl font-bold">Сериалы</h2>
|
|
||||||
</div>
|
|
||||||
<MediaCarousel
|
|
||||||
media={trendingTvShows}
|
|
||||||
mediaType="tv"
|
|
||||||
seeAllLink="/discover/tv"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Latest Reviews */}
|
|
||||||
<div className="mb-12">
|
|
||||||
<div className="flex items-center mb-6">
|
|
||||||
<FiCalendar className="text-campfire-amber mr-2" size={20} />
|
|
||||||
<h2 className="text-2xl font-bold">Последние рецензии</h2>
|
|
||||||
</div>
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
||||||
{/* Placeholder for latest reviews */}
|
|
||||||
<div className="bg-campfire-charcoal rounded-lg p-6 flex flex-col items-center justify-center text-center h-48">
|
|
||||||
<p className="text-campfire-ash mb-4">Рецензий пока нет</p>
|
|
||||||
{!currentUser && (
|
|
||||||
<Link
|
|
||||||
to="/login"
|
|
||||||
className="text-campfire-amber hover:text-campfire-ember"
|
|
||||||
>
|
|
||||||
Войдите, чтобы написать рецензию
|
|
||||||
</Link>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="bg-campfire-charcoal rounded-lg p-6 flex flex-col items-center justify-center text-center h-48">
|
|
||||||
<p className="text-campfire-ash mb-4">Рецензий пока нет</p>
|
|
||||||
{!currentUser && (
|
|
||||||
<Link
|
|
||||||
to="/login"
|
|
||||||
className="text-campfire-amber hover:text-campfire-ember"
|
|
||||||
>
|
|
||||||
Войдите, чтобы написать рецензию
|
|
||||||
</Link>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
);
|
||||||
|
|
||||||
{/* Critic's Choice */}
|
|
||||||
<div className="mb-12">
|
|
||||||
<div className="flex items-center mb-6">
|
|
||||||
<FiAward className="text-campfire-amber mr-2" size={20} />
|
|
||||||
<h2 className="text-2xl font-bold">Выбор Резидентов</h2>
|
|
||||||
</div>
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
||||||
{trendingMovies.slice(0, 3).map((movie) => (
|
|
||||||
<Link
|
|
||||||
key={movie.id}
|
|
||||||
to={`/media/${movie.id}?type=movie`}
|
|
||||||
className="block"
|
|
||||||
>
|
|
||||||
<div className="card h-full">
|
|
||||||
<div className="relative aspect-video">
|
|
||||||
<img
|
|
||||||
src={
|
|
||||||
getImageUrl(movie.backdrop_path, "w780") ||
|
|
||||||
getImageUrl(movie.poster_path, "w342")
|
|
||||||
}
|
}
|
||||||
alt={movie.title}
|
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-campfire-dark pt-20">
|
||||||
|
<div className="container-custom py-12">
|
||||||
|
<div className="bg-status-error/20 text-status-error p-4 rounded-lg text-center">
|
||||||
|
{error}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen bg-campfire-dark pt-20">
|
||||||
|
<div className="container-custom py-12">
|
||||||
|
<div className="flex justify-between items-center mb-8">
|
||||||
|
<h1 className="text-3xl font-bold text-campfire-light">
|
||||||
|
Добро пожаловать в CampFire
|
||||||
|
</h1>
|
||||||
|
{user?.role === 'admin' && (
|
||||||
|
<Link
|
||||||
|
to="/admin/media"
|
||||||
|
className="btn-secondary"
|
||||||
|
>
|
||||||
|
Управление контентом
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{media.length > 0 ? (
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
|
||||||
|
{media.map((item) => (
|
||||||
|
<Link
|
||||||
|
key={`${item.id}-${item.type}`}
|
||||||
|
to={`/media/${item.id}`}
|
||||||
|
className="group"
|
||||||
|
>
|
||||||
|
<div className="bg-campfire-charcoal rounded-lg overflow-hidden shadow-lg border border-campfire-ash/20 transition-all duration-300 hover:shadow-xl hover:border-campfire-amber/30">
|
||||||
|
<div className="aspect-[2/3] relative">
|
||||||
|
<img
|
||||||
|
src={item.poster_url}
|
||||||
|
alt={item.title}
|
||||||
className="w-full h-full object-cover"
|
className="w-full h-full object-cover"
|
||||||
/>
|
/>
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-t from-campfire-charcoal/80 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
<h3 className="font-bold text-lg mb-2">
|
<div className="flex items-center justify-between mb-2">
|
||||||
{movie.title}
|
<span className="text-xs font-medium px-2 py-1 rounded-full bg-campfire-amber/20 text-campfire-amber">
|
||||||
|
{item.type === 'movie' ? 'Фильм' : 'Сериал'}
|
||||||
|
</span>
|
||||||
|
<span className="text-sm text-campfire-ash">
|
||||||
|
{new Date(item.release_date).getFullYear()}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<h3 className="text-lg font-semibold text-campfire-light mb-1 group-hover:text-campfire-amber transition-colors">
|
||||||
|
{item.title}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-campfire-ash text-sm line-clamp-2">
|
<p className="text-sm text-campfire-ash line-clamp-2">
|
||||||
{movie.overview}
|
{item.description}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="text-center py-12">
|
||||||
|
<p className="text-campfire-ash text-lg">
|
||||||
|
Пока нет доступного контента
|
||||||
|
</p>
|
||||||
|
{user?.role === 'admin' && (
|
||||||
|
<Link
|
||||||
|
to="/admin/media"
|
||||||
|
className="inline-block mt-4 btn-primary"
|
||||||
|
>
|
||||||
|
Добавить контент
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default HomePage;
|
export default HomePage;
|
||||||
|
Loading…
Reference in New Issue
Block a user