From 561a3426e0b5a78524ba4a4befc139019808b3f5 Mon Sep 17 00:00:00 2001 From: degradin Date: Wed, 7 May 2025 13:37:25 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A1=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=86?= =?UTF-8?q?=D0=B0=20=D0=BC=D0=B5=D0=B4=D0=B8=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Полная страничка медиа для подробной информации --- src/pages/MediaPage.jsx | 437 ++++++++-------------------------------- 1 file changed, 83 insertions(+), 354 deletions(-) diff --git a/src/pages/MediaPage.jsx b/src/pages/MediaPage.jsx index 5ad8e6b..f3c7fcd 100644 --- a/src/pages/MediaPage.jsx +++ b/src/pages/MediaPage.jsx @@ -1,378 +1,107 @@ -import { useState, useEffect } from 'react'; -import { useParams, useSearchParams } from 'react-router-dom'; -import { useMedia } from '../contexts/MediaContext'; +import React, { useEffect, useState } from 'react'; +import { useParams } from 'react-router-dom'; +import { getMediaById } from '../services/supabase'; import { useAuth } from '../contexts/AuthContext'; -import { FaStar, FaCalendar, FaClock, FaUser } from 'react-icons/fa'; -import { getImageUrl } from '../services/tmdbApi'; -import ReviewForm from '../components/reviews/ReviewForm'; -import ReviewCard from '../components/reviews/ReviewCard'; -import MediaCarousel from '../components/media/MediaCarousel'; -function MediaPage() { +const MediaPage = () => { const { id } = useParams(); - const [searchParams] = useSearchParams(); - const mediaType = searchParams.get('type') || 'movie'; - - const { fetchMediaDetails, currentMedia, loading } = useMedia(); + const [media, setMedia] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); const { currentUser } = useAuth(); - - const [activeTab, setActiveTab] = useState('overview'); - const [reviews, setReviews] = useState([]); - - useEffect(() => { - if (id && mediaType) { - fetchMediaDetails(id, mediaType); - window.scrollTo(0, 0); - } - }, [id, mediaType, fetchMediaDetails]); - // Mock submit review function - const handleSubmitReview = (reviewData) => { - // In a real app, this would send the review to the backend - const newReview = { - id: Date.now().toString(), - user: { - id: currentUser.uid, - username: currentUser.displayName || 'User', - profilePicture: currentUser.photoURL, - isCritic: false - }, - ...reviewData, - likes: 0, - comments: [] + useEffect(() => { + const loadMedia = async () => { + try { + setLoading(true); + setError(null); + const data = await getMediaById(id); + setMedia(data); + } catch (err) { + console.error('Error loading media:', err); + setError('Не удалось загрузить информацию о медиа'); + } finally { + setLoading(false); + } }; - - setReviews(prevReviews => [newReview, ...prevReviews]); - return Promise.resolve(); - }; - + + if (id) { + loadMedia(); + } + }, [id]); + if (loading) { - return ( -
-
-
- ); + return
Загрузка...
; } - - if (!currentMedia) { - return ( -
-

Media Not Found

-

The requested media could not be found.

-
- ); + + if (error) { + return
{error}
; } - - // Extract media details - const { - backdrop_path, - poster_path, - title, - name, - overview, - vote_average, - release_date, - first_air_date, - runtime, - episode_run_time, - genres = [], - credits = { cast: [], crew: [] }, - videos = { results: [] }, - similar = { results: [] }, - recommendations = { results: [] } - } = currentMedia; - - const mediaTitle = title || name; - const releaseDate = release_date || first_air_date; - const duration = runtime || (episode_run_time && episode_run_time[0]); - const backdropUrl = getImageUrl(backdrop_path, 'original'); - const posterUrl = getImageUrl(poster_path, 'w342'); - - // Format release date - const formattedDate = releaseDate ? new Date(releaseDate).toLocaleDateString('en-US', { - year: 'numeric', - month: 'long', - day: 'numeric' - }) : 'Unknown'; - - // Format duration - const formattedDuration = duration ? `${Math.floor(duration / 60)}h ${duration % 60}m` : 'Unknown'; - - // Get trailer - const trailer = videos.results.find(video => video.type === 'Trailer') || videos.results[0]; - + + if (!media) { + return
Медиа не найдено
; + } + return ( -
- {/* Hero Section */} -
- {backdropUrl ? ( - <> -
- {mediaTitle} -
-
- - ) : ( -
- )} - -
-
- {posterUrl && ( -
- {mediaTitle} -
+
+
+ {/* Заголовок и основная информация */} +
+

{media.title}

+
+ Тип: {media.type} + {media.release_date && ( + Дата выхода: {new Date(media.release_date).toLocaleDateString()} + )} + {media.rating && ( + Рейтинг: {media.rating.toFixed(1)} )} - -
-

{mediaTitle}

- -
- {releaseDate && ( -
- - {formattedDate} -
- )} - - {duration && ( -
- - {formattedDuration} -
- )} - - {vote_average > 0 && ( -
- - {(vote_average / 2).toFixed(1)} -
- )} -
- -
- {genres.map(genre => ( - - {genre.name} - - ))} -
- - {trailer && ( - - Watch Trailer - - )} -
+ {media.description && ( +

{media.description}

+ )}
-
- - {/* Content Section */} -
- {/* Tabs Navigation */} -
-
- - - + + {/* Постер и дополнительная информация */} + {media.poster_url && ( +
+ {media.title}
-
- - {/* Tab Content */} -
- {/* Overview Tab */} - {activeTab === 'overview' && ( -
-

Synopsis

-

{overview}

- - {/* Cast Section */} - {credits.cast && credits.cast.length > 0 && ( -
-

Cast

-
- {credits.cast.slice(0, 6).map(person => ( -
-
- {person.profile_path ? ( - {person.name} - ) : ( -
- -
- )} -
-

{person.name}

-

{person.character}

-
- ))} + )} + + {/* Рецензии */} +
+

Рецензии

+ {media.reviews && media.reviews.length > 0 ? ( +
+ {media.reviews.map((review) => ( +
+
+ {review.user.username} + {review.user.is_critic && ( + + Критик + + )} +
+

{review.content}

+
+ {new Date(review.created_at).toLocaleDateString()}
- )} - - {/* Crew Section */} - {credits.crew && credits.crew.length > 0 && ( -
-

Crew

-
- {credits.crew - .filter(person => - ['Director', 'Producer', 'Writer', 'Screenplay'].includes(person.job) - ) - .slice(0, 6) - .map(person => ( -
-
- {person.profile_path ? ( - {person.name} - ) : ( -
- -
- )} -
-
-

{person.name}

-

{person.job}

-
-
- )) - } -
-
- )} -
- )} - - {/* Reviews Tab */} - {activeTab === 'reviews' && ( -
-

Reviews

- - {/* Submit Review Form */} - {currentUser ? ( -
- -
- ) : ( -
-

Sign in to write a review

- - Sign In - -
- )} - - {/* Reviews List */} - {reviews.length > 0 ? ( -
- {reviews.map(review => ( - - ))} -
- ) : ( -
-

No reviews yet. Be the first to review!

-
- )} -
- )} - - {/* Similar Tab */} - {activeTab === 'similar' && ( -
- {/* Similar Titles */} - {similar.results && similar.results.length > 0 && ( -
-

Similar Titles

-
- {similar.results.slice(0, 10).map(item => ( - - ))} -
-
- )} - - {/* Recommendations */} - {recommendations.results && recommendations.results.length > 0 && ( -
-

Recommendations

-
- {recommendations.results.slice(0, 10).map(item => ( - - ))} -
-
- )} - - {(!similar.results || similar.results.length === 0) && - (!recommendations.results || recommendations.results.length === 0) && ( -
-

No similar content available.

-
- )} + ))}
+ ) : ( +

Пока нет рецензий

)}
); -} +}; export default MediaPage; \ No newline at end of file