import React from 'react'; import { Page } from './_util'; import { useParams } from 'react-router-dom'; import { usePollGalleryDelta } from '../polling/usePollGalleryDelta'; import { Card, CardContent } from '@/components/ui/card'; import { Alert, AlertDescription } from '@/components/ui/alert'; import { Button } from '@/components/ui/button'; import FiltersBar, { type GalleryFilter } from '../components/FiltersBar'; import { Link } from 'react-router-dom'; import { Heart } from 'lucide-react'; import { likePhoto } from '../services/photosApi'; export default function GalleryPage() { const { slug } = useParams(); const { photos, loading, newCount, acknowledgeNew } = usePollGalleryDelta(slug!); const [filter, setFilter] = React.useState('latest'); const myPhotoIds = React.useMemo(() => { try { const raw = localStorage.getItem('my-photo-ids'); return new Set(raw ? JSON.parse(raw) : []); } catch { return new Set(); } }, []); const list = React.useMemo(() => { let arr = photos.slice(); if (filter === 'popular') { arr.sort((a: any, b: any) => (b.likes_count ?? 0) - (a.likes_count ?? 0)); } else if (filter === 'mine') { arr = arr.filter((p: any) => myPhotoIds.has(p.id)); } else { arr.sort((a: any, b: any) => new Date(b.created_at ?? 0).getTime() - new Date(a.created_at ?? 0).getTime()); } return arr; }, [photos, filter, myPhotoIds]); const [liked, setLiked] = React.useState>(new Set()); const [counts, setCounts] = React.useState>({}); async function onLike(id: number) { if (liked.has(id)) return; setLiked(new Set(liked).add(id)); try { const c = await likePhoto(id); setCounts((m) => ({ ...m, [id]: c })); // keep a simple record of liked items try { const raw = localStorage.getItem('liked-photo-ids'); const arr: number[] = raw ? JSON.parse(raw) : []; if (!arr.includes(id)) localStorage.setItem('liked-photo-ids', JSON.stringify([...arr, id])); } catch {} } catch { const s = new Set(liked); s.delete(id); setLiked(s); } } return ( {newCount > 0 && ( {newCount} neue Fotos verfügbar.{' '} )} {loading &&

Lade…

}
{list.map((p: any) => { // Debug: Log image URLs const imgSrc = p.thumbnail_path || p.file_path; // Normalize image URL let imageUrl = imgSrc; let cleanPath = ''; if (imageUrl) { // Remove leading/trailing slashes for processing cleanPath = imageUrl.replace(/^\/+|\/+$/g, ''); // Check if path already contains storage prefix if (cleanPath.startsWith('storage/')) { // Already has storage prefix, just ensure it starts with / imageUrl = `/${cleanPath}`; } else { // Add storage prefix imageUrl = `/storage/${cleanPath}`; } // Remove double slashes imageUrl = imageUrl.replace(/\/+/g, '/'); } // Extended debug logging console.log(`Photo ${p.id} URL processing:`, { id: p.id, original: imgSrc, thumbnail_path: p.thumbnail_path, file_path: p.file_path, cleanPath, finalUrl: imageUrl, isHttp: imageUrl?.startsWith('http'), startsWithStorage: imageUrl?.startsWith('/storage/') }); return ( {`Foto { console.error(`❌ Failed to load image ${p.id}:`, imageUrl); console.error('Error details:', e); (e.target as HTMLImageElement).src = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjRjNGNEY2Ii8+PHRleHQgeD0iNTAlIiB5PSI1MCUiIGZvbnQtZmFtaWx5PSJBcmlhbCIgZm9udC1zaXplPSIxNCIgZmlsbD0iIzk5OSIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZHk9Ii4zZW0iPk5vIEltYWdlPC90ZXh0Pjwvc3ZnPg=='; }} onLoad={() => console.log(`✅ Successfully loaded image ${p.id}:`, imageUrl)} loading="lazy" /> {p.task_title && (

{p.task_title}

)}
{counts[p.id] ?? (p.likes_count || 0)}
); })}
); }