import { useState } from 'react'; import { useQuery, useQueryClient } from '@tanstack/react-query'; import { api } from '../api'; import type { GalleryImage } from '../api/types'; type GalleryImageWithTarget = GalleryImage & { target_name?: string; target_common_name?: string; }; function fmtDate(ts: number): string { return new Date(ts * 1000).toLocaleDateString('fr-FR', { year: 'numeric', month: 'short', day: 'numeric', }); } export default function Gallery() { const [lightbox, setLightbox] = useState(null); const [filterTarget, setFilterTarget] = useState(''); const qc = useQueryClient(); const { data, isLoading } = useQuery({ queryKey: ['gallery-all'], queryFn: () => api.gallery.listAll(), }); const images = data?.items ?? []; // Unique targets for filter const targets = Array.from( new Map(images.map(img => [img.catalog_id, img.target_common_name ?? img.target_name ?? img.catalog_id])).entries() ).sort((a, b) => a[1].localeCompare(b[1])); const filtered = filterTarget ? images.filter(img => img.catalog_id === filterTarget) : images; // Group by target const grouped: Record = {}; for (const img of filtered) { const key = img.catalog_id; if (!grouped[key]) grouped[key] = []; grouped[key].push(img); } return (

Gallery

{images.length} image{images.length !== 1 ? 's' : ''} {targets.length > 1 && ( )}
{isLoading && (
Loading images…
)} {!isLoading && images.length === 0 && (
No images yet. Upload images from the Targets page → Log & Gallery tab.
)} {Object.entries(grouped).map(([catalogId, imgs]) => { const first = imgs[0]; const targetLabel = first.target_common_name ?? first.target_name ?? catalogId; return (
{targetLabel} {catalogId} {imgs.length} image{imgs.length !== 1 ? 's' : ''}
{imgs.map(img => (
setLightbox(img)} style={{ cursor: 'pointer', borderRadius: 4, overflow: 'hidden', background: 'var(--bg-deep)', border: '1px solid var(--border)', transition: 'border-color 0.15s', }} onMouseEnter={e => (e.currentTarget.style.borderColor = 'var(--border-hi)')} onMouseLeave={e => (e.currentTarget.style.borderColor = 'var(--border)')} >
{img.caption
{img.caption && (
{img.caption}
)}
{fmtDate(img.created_at)}
))}
); })} {/* Lightbox */} {lightbox && (
setLightbox(null)} style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.94)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 1000, }} >
e.stopPropagation()} style={{ position: 'relative', maxWidth: '90vw', maxHeight: '90vh' }} > {lightbox.caption
{lightbox.target_common_name ?? lightbox.target_name ?? lightbox.catalog_id} {lightbox.catalog_id}
{lightbox.caption && (
{lightbox.caption}
)}
{fmtDate(lightbox.created_at)}
)}
); }