import React, { useEffect, useMemo, useState } from 'react'; import MainLayout from '../components/layout/MainLayout'; import { Box, Container, Heading, Text, SimpleGrid, AspectRatio, useColorModeValue, Spinner, VStack, HStack, Badge, Button, Link, Modal, ModalOverlay, ModalContent, ModalBody, ModalCloseButton, useDisclosure, Icon, } from '@chakra-ui/react'; import { useClubTheme } from '../contexts/ClubThemeContext'; import { usePublicSettings } from '../hooks/usePublicSettings'; import { getCachedYouTube, YouTubeVideo } from '../services/youtube'; import { FaPlay, FaExternalLinkAlt, FaYoutube } from 'react-icons/fa'; import NewsletterCTA from '../components/common/NewsletterCTA'; import CommentsSection from '../components/comments/CommentsSection'; import { Helmet } from 'react-helmet-async'; type RenderItem = { key: string; title: string; embedUrl: string; thumbnail?: string; date?: string; // YYYY-MM-DD videoId?: string; }; const toEmbed = (idOrUrl: string): string => { try { if (idOrUrl.includes('youtube.com') || idOrUrl.includes('youtu.be')) { const u = new URL(idOrUrl); if (u.hostname.includes('youtu.be')) { const id = u.pathname.replace('/', ''); return `https://www.youtube.com/embed/${id}`; } const id = u.searchParams.get('v'); if (id) return `https://www.youtube.com/embed/${id}`; } } catch {} return `https://www.youtube.com/embed/${idOrUrl}`; }; const extractVideoId = (embedUrl: string): string | undefined => { if (embedUrl?.includes('/embed/')) { return embedUrl.split('/embed/')[1]?.split('?')[0]; } return undefined; }; const VideosPage: React.FC = () => { const cardBg = useColorModeValue('white', 'gray.800'); const borderColor = useColorModeValue('gray.200', 'gray.600'); const headingColor = useColorModeValue('gray.800', 'gray.100'); const textSecondary = useColorModeValue('gray.600', 'gray.300'); const textTertiary = useColorModeValue('gray.500', 'gray.400'); const modalBg = useColorModeValue('white', 'gray.800'); const placeholderBg = useColorModeValue('gray.100', 'gray.700'); const placeholderIcon = useColorModeValue('gray.400', 'gray.500'); const videoPrimaryColor = useColorModeValue('brand.primary', 'brand.accent'); const theme = useClubTheme(); const { data: settings, isLoading: settingsLoading } = usePublicSettings(); const [yt, setYt] = useState([]); const [loading, setLoading] = useState(true); const { isOpen, onOpen, onClose } = useDisclosure(); const [selectedVideo, setSelectedVideo] = useState(null); const source = settings?.videos_source || 'auto'; const youtubeUrl = (settings as any)?.youtube_url || (settings as any)?.social_youtube || null; const titleOverrides: Record = (settings as any)?.videos_title_overrides || {}; useEffect(() => { let canceled = false; const run = async () => { if (source !== 'auto') { setLoading(false); return; } try { const payload = await getCachedYouTube(); if (!payload) { setLoading(false); return; } const vids = (payload.videos || []) .slice() .sort((a, b) => (Date.parse(b.published_date || '') || 0) - (Date.parse(a.published_date || '') || 0)); if (!canceled) setYt(vids); } catch (e) { console.error('Failed to load videos:', e); } finally { if (!canceled) setLoading(false); } }; run(); return () => { canceled = true; }; }, [source]); const items: RenderItem[] = useMemo(() => { if (source === 'auto') { return (yt || []).map((v) => ({ key: v.video_id, title: (titleOverrides?.[v.video_id]?.trim()) || v.title, embedUrl: toEmbed(v.video_id), thumbnail: v.thumbnail_url, date: v.published_date, videoId: v.video_id, })); } // Manual fallback from settings const manual = (settings?.videos_items || []).map((it, i) => { const embedUrl = toEmbed(it.url); return { key: `${i}-${it.url}`, title: it.title || `Video ${i + 1}`, embedUrl, thumbnail: it.thumbnail_url, date: it.uploaded_at, videoId: extractVideoId(embedUrl), }; }); const legacy = ((settings as any)?.videos || []).map((url: string, i: number) => { const embedUrl = toEmbed(url); return { key: `${i}-${url}`, title: `Video ${i + 1}`, embedUrl, videoId: extractVideoId(embedUrl), }; }); return manual.length ? manual : legacy; }, [source, yt, settings?.videos_items, settings, titleOverrides]); const openVideo = (item: RenderItem) => { setSelectedVideo(item); onOpen(); }; const VideoCard: React.FC<{ item: RenderItem }> = ({ item }) => { const thumb = item.thumbnail || (item.videoId ? `https://i.ytimg.com/vi/${item.videoId}/hqdefault.jpg` : undefined); return ( openVideo(item)}> {/* Thumbnail */} {thumb ? ( ) : ( )} {/* Play overlay */} Přehrát {item.title} {item.date && ( {new Date(item.date).toLocaleDateString('cs-CZ')} )} {item.videoId && ( e.stopPropagation()}> )} ); }; if (settingsLoading || loading) { return ( Načítám videa... ); } return ( Videa Videa {youtubeUrl && ( )} Sledujte naše nejnovější videa a zápasy Všechna videa jsou z YouTube {items.length === 0 ? ( Zatím nejsou k dispozici žádná videa ) : ( {items.map((item) => ( ))} )} {/* Video Modal */} {selectedVideo && (