typescript-typenfehler behoben.. npm run lint läuft nun fehlerfrei durch.
This commit is contained in:
@@ -6,13 +6,28 @@ import FiltersBar, { type GalleryFilter } from '../components/FiltersBar';
|
||||
import { Heart, Image as ImageIcon, Share2 } from 'lucide-react';
|
||||
import { likePhoto } from '../services/photosApi';
|
||||
import PhotoLightbox from './PhotoLightbox';
|
||||
import { fetchEvent, fetchStats, type EventData, type EventStats } from '../services/eventApi';
|
||||
import { fetchEvent, type EventData } from '../services/eventApi';
|
||||
import { useTranslation } from '../i18n/useTranslation';
|
||||
import { sharePhotoLink } from '../lib/sharePhoto';
|
||||
import { useToast } from '../components/ToastHost';
|
||||
import { localizeTaskLabel } from '../lib/localizeTaskLabel';
|
||||
|
||||
const allowedGalleryFilters: GalleryFilter[] = ['latest', 'popular', 'mine', 'photobooth'];
|
||||
type GalleryPhoto = {
|
||||
id: number;
|
||||
likes_count?: number | null;
|
||||
created_at?: string | null;
|
||||
ingest_source?: string | null;
|
||||
session_id?: string | null;
|
||||
task_id?: number | null;
|
||||
task_title?: string | null;
|
||||
emotion_id?: number | null;
|
||||
emotion_name?: string | null;
|
||||
thumbnail_path?: string | null;
|
||||
file_path?: string | null;
|
||||
title?: string | null;
|
||||
uploader_name?: string | null;
|
||||
};
|
||||
|
||||
const parseGalleryFilter = (value: string | null): GalleryFilter =>
|
||||
allowedGalleryFilters.includes(value as GalleryFilter) ? (value as GalleryFilter) : 'latest';
|
||||
@@ -46,7 +61,6 @@ export default function GalleryPage() {
|
||||
const [hasOpenedPhoto, setHasOpenedPhoto] = useState(false);
|
||||
|
||||
const [event, setEvent] = useState<EventData | null>(null);
|
||||
const [stats, setStats] = useState<EventStats | null>(null);
|
||||
const [eventLoading, setEventLoading] = useState(true);
|
||||
const toast = useToast();
|
||||
const [shareTargetId, setShareTargetId] = React.useState<number | null>(null);
|
||||
@@ -62,16 +76,18 @@ export default function GalleryPage() {
|
||||
params.set('mode', next);
|
||||
setSearchParams(params, { replace: true });
|
||||
}, [searchParams, setSearchParams]);
|
||||
const typedPhotos = photos as GalleryPhoto[];
|
||||
|
||||
// Auto-open lightbox if photoId in query params
|
||||
useEffect(() => {
|
||||
if (photoIdParam && photos.length > 0 && currentPhotoIndex === null && !hasOpenedPhoto) {
|
||||
const index = photos.findIndex((photo: any) => photo.id === parseInt(photoIdParam, 10));
|
||||
const index = typedPhotos.findIndex((photo) => photo.id === parseInt(photoIdParam, 10));
|
||||
if (index !== -1) {
|
||||
setCurrentPhotoIndex(index);
|
||||
setHasOpenedPhoto(true);
|
||||
}
|
||||
}
|
||||
}, [photos, photoIdParam, currentPhotoIndex, hasOpenedPhoto]);
|
||||
}, [typedPhotos, photos.length, photoIdParam, currentPhotoIndex, hasOpenedPhoto]);
|
||||
|
||||
// Load event and package info
|
||||
useEffect(() => {
|
||||
@@ -80,12 +96,8 @@ export default function GalleryPage() {
|
||||
const loadEventData = async () => {
|
||||
try {
|
||||
setEventLoading(true);
|
||||
const [eventData, statsData] = await Promise.all([
|
||||
fetchEvent(token),
|
||||
fetchStats(token),
|
||||
]);
|
||||
const eventData = await fetchEvent(token);
|
||||
setEvent(eventData);
|
||||
setStats(statsData);
|
||||
} catch (err) {
|
||||
console.error('Failed to load event data', err);
|
||||
} finally {
|
||||
@@ -104,27 +116,22 @@ export default function GalleryPage() {
|
||||
}, []);
|
||||
|
||||
const list = React.useMemo(() => {
|
||||
let arr = photos.slice();
|
||||
let arr = typedPhotos.slice();
|
||||
if (filter === 'popular') {
|
||||
arr.sort((a: any, b: any) => (b.likes_count ?? 0) - (a.likes_count ?? 0));
|
||||
arr.sort((a, b) => (b.likes_count ?? 0) - (a.likes_count ?? 0));
|
||||
} else if (filter === 'mine') {
|
||||
arr = arr.filter((p: any) => myPhotoIds.has(p.id));
|
||||
arr = arr.filter((p) => myPhotoIds.has(p.id));
|
||||
} else if (filter === 'photobooth') {
|
||||
arr = arr.filter((p: any) => p.ingest_source === 'photobooth');
|
||||
arr.sort((a: any, b: any) => new Date(b.created_at ?? 0).getTime() - new Date(a.created_at ?? 0).getTime());
|
||||
arr = arr.filter((p) => p.ingest_source === 'photobooth');
|
||||
arr.sort((a, b) => new Date(b.created_at ?? 0).getTime() - new Date(a.created_at ?? 0).getTime());
|
||||
} else {
|
||||
arr.sort((a: any, b: any) => new Date(b.created_at ?? 0).getTime() - new Date(a.created_at ?? 0).getTime());
|
||||
arr.sort((a, b) => new Date(b.created_at ?? 0).getTime() - new Date(a.created_at ?? 0).getTime());
|
||||
}
|
||||
return arr;
|
||||
}, [photos, filter, myPhotoIds]);
|
||||
}, [typedPhotos, filter, myPhotoIds]);
|
||||
const [liked, setLiked] = React.useState<Set<number>>(new Set());
|
||||
const [counts, setCounts] = React.useState<Record<number, number>>({});
|
||||
|
||||
const totalLikes = React.useMemo(
|
||||
() => photos.reduce((sum, photo: any) => sum + (photo.likes_count ?? 0), 0),
|
||||
[photos],
|
||||
);
|
||||
|
||||
async function onLike(id: number) {
|
||||
if (liked.has(id)) return;
|
||||
setLiked(new Set(liked).add(id));
|
||||
@@ -136,13 +143,16 @@ export default function GalleryPage() {
|
||||
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 {
|
||||
} catch (error) {
|
||||
console.warn('Failed to persist liked-photo-ids', error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Like failed', error);
|
||||
const s = new Set(liked); s.delete(id); setLiked(s);
|
||||
}
|
||||
}
|
||||
|
||||
async function onShare(photo: any) {
|
||||
async function onShare(photo: GalleryPhoto) {
|
||||
if (!token) return;
|
||||
setShareTargetId(photo.id);
|
||||
try {
|
||||
@@ -223,7 +233,7 @@ export default function GalleryPage() {
|
||||
<FiltersBar value={filter} onChange={setFilter} className="mt-2" />
|
||||
{loading && <p className="px-4">{t('galleryPage.loading', 'Lade…')}</p>}
|
||||
<div className="grid gap-3 px-4 pb-16 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{list.map((p: any) => {
|
||||
{list.map((p: GalleryPhoto) => {
|
||||
const imageUrl = normalizeImageUrl(p.thumbnail_path || p.file_path);
|
||||
const createdLabel = p.created_at
|
||||
? new Date(p.created_at).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
|
||||
@@ -236,7 +246,7 @@ export default function GalleryPage() {
|
||||
const altText = t('galleryPage.photo.alt', { id: p.id, suffix: altSuffix }, `Foto ${p.id}${altSuffix}`);
|
||||
|
||||
const openPhoto = () => {
|
||||
const index = list.findIndex((photo: any) => photo.id === p.id);
|
||||
const index = list.findIndex((photo) => photo.id === p.id);
|
||||
setCurrentPhotoIndex(index >= 0 ? index : null);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user