'use client' import { useEffect, useState, useCallback } from 'react' import type { Game } from '@/types' import GameDetailModal from './GameDetailModal' import FilterPanel from '@/components/FilterPanel' interface Props { libraryId: string } export default function GamesView({ libraryId }: Props) { const [games, setGames] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [selected, setSelected] = useState(null) const [search, setSearch] = useState('') const [selectedTagIds, setSelectedTagIds] = useState>(new Set()) const [assignments, setAssignments] = useState>({}) const [filterRefreshKey, setFilterRefreshKey] = useState(0) const toggleTag = (tagId: string) => setSelectedTagIds((prev) => { const next = new Set(prev) next.has(tagId) ? next.delete(tagId) : next.add(tagId) return next }) useEffect(() => { fetch(`/api/games?libraryId=${encodeURIComponent(libraryId)}`) .then((r) => r.json()) .then((data) => { setGames(data) setLoading(false) }) .catch(() => { setError('Failed to load games') setLoading(false) }) }, [libraryId]) const fetchAssignments = useCallback(() => { fetch(`/api/tags/library-assignments?libraryId=${encodeURIComponent(libraryId)}`) .then((r) => r.json()) .then(setAssignments) .catch(() => {}) }, [libraryId]) useEffect(() => { fetchAssignments() }, [fetchAssignments]) const filtered = games.filter((game) => { if (search && !game.title.toLowerCase().includes(search.toLowerCase())) return false if (selectedTagIds.size > 0) { const gameTags = assignments[`${libraryId}:${game.id}`] ?? [] if (![...selectedTagIds].every((id) => gameTags.includes(id))) return false } return true }) return (
{loading ? ( ) : error ? ( ) : games.length === 0 ? ( ) : (
{filtered.map((game) => ( ))}
)} {selected && ( setSelected(null)} onTagsChanged={() => { setFilterRefreshKey((k) => k + 1); fetchAssignments() }} /> )}
) } function LoadingGrid() { return (
{Array.from({ length: 12 }).map((_, i) => (
))}
) } function ErrorMessage({ message }: { message: string }) { return (
{message}
) } function EmptyState() { return (

No games found

Each game should be a folder containing a .zip file.

) }