import React, { useEffect, useState } from 'react'; import { useParams, Link as RouterLink } from 'react-router-dom'; import { Box, Container, Heading, Text, SimpleGrid, Image, Spinner, VStack, HStack, Button, Breadcrumb, BreadcrumbItem, BreadcrumbLink, useDisclosure, Badge, useColorModeValue, } from '@chakra-ui/react'; import { ChevronRight, ExternalLink, Calendar, Image as ImageIcon } from 'lucide-react'; import MainLayout from '../components/layout/MainLayout'; import PhotoModal from '../components/gallery/PhotoModal'; interface Photo { id: string; page_url: string; image_1500: string; } interface Album { id: string; title: string; url: string; date: string; photos_count: number; views_count?: number; photos: Photo[]; fetched_at?: string; } const resolveBackendUrl = (path: string) => { try { if (/^https?:\/\//i.test(path)) return path; if (path.startsWith('/cache') || path.startsWith('/uploads') || path.startsWith('/api/')) { const base = (process.env.REACT_APP_API_BASE_URL || process.env.REACT_APP_API_URL || 'http://localhost:8080/api/v1'); const b = new URL(base); const abs = new URL(path, `${b.protocol}//${b.host}`); return abs.toString(); } return path; } catch { return path; } }; const AlbumDetailPage: React.FC = () => { const { id } = useParams<{ id: string }>(); const [album, setAlbum] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); const [selectedPhoto, setSelectedPhoto] = useState(null); const { isOpen, onOpen, onClose } = useDisclosure(); // Dark mode colors const bgColor = useColorModeValue('#f8f9fb', '#0f1115'); const cardBg = useColorModeValue('white', '#1a1d29'); const borderColor = useColorModeValue('#e5e7eb', '#2a2e3a'); const headingColor = useColorModeValue('gray.800', 'gray.100'); const textSecondary = useColorModeValue('gray.600', 'gray.300'); const infoBg = useColorModeValue('blue.50', 'blue.900'); const infoBorder = useColorModeValue('blue.200', 'blue.700'); const infoText = useColorModeValue('blue.800', 'blue.200'); useEffect(() => { const fetchAlbum = async () => { if (!id) return; setLoading(true); setError(''); try { // Check both sources for the album const [profileRes, albumsRes] = await Promise.allSettled([ fetch(resolveBackendUrl('/cache/prefetch/zonerama_profile.json'), { cache: 'no-cache' }), fetch(resolveBackendUrl('/cache/prefetch/zonerama_albums.json'), { cache: 'no-cache' }) ]); let foundAlbum: Album | null = null; // Try profile albums first (newest/main source) if (profileRes.status === 'fulfilled' && profileRes.value.ok) { const profileData = await profileRes.value.json(); const albums = profileData.albums || []; foundAlbum = albums.find((a: Album) => a.id === id); } // If not found, try blog-related albums if (!foundAlbum && albumsRes.status === 'fulfilled' && albumsRes.value.ok) { const albumsData = await albumsRes.value.json(); const blogAlbums = Array.isArray(albumsData) ? albumsData : []; foundAlbum = blogAlbums.find((a: Album) => a.id === id); } if (!foundAlbum) { throw new Error('Album nenalezen'); } setAlbum(foundAlbum); } catch (err: any) { setError(err.message || 'Chyba při načítání alba'); } finally { setLoading(false); } }; fetchAlbum(); }, [id]); const handlePhotoClick = (photo: Photo) => { setSelectedPhoto(photo); onOpen(); }; const handleCloseModal = () => { onClose(); setSelectedPhoto(null); }; if (loading) { return ( Načítám album... ); } if (error || !album) { return ( {error || 'Album nenalezeno'} ); } return ( {/* Breadcrumbs */} } mb={6} fontSize="sm" > Domů Galerie {album.title} {/* Album Header */} {album.title} {album.date && ( {album.date} )} {album.photos_count} fotografií {album.views_count !== undefined && album.views_count > 0 && ( {album.views_count} zhlédnutí )} {/* Zonerama Attribution */} 📸 Všechny fotografie jsou z platformy{' '} Zonerama {/* Photo Grid */} {album.photos && album.photos.length > 0 ? ( {album.photos.map((photo) => ( handlePhotoClick(photo)} borderRadius="lg" overflow="hidden" boxShadow="md" borderWidth="1px" borderColor={borderColor} transition="all 0.2s" _hover={{ transform: 'translateY(-4px)', boxShadow: 'xl', borderColor: useColorModeValue('gray.300', 'gray.600') }} bg={cardBg} > {`Fotka ))} ) : ( V tomto albu nejsou žádné fotografie. )} {/* Photo Modal */} {selectedPhoto && ( )} ); }; export default AlbumDetailPage;