feat: Add game thumbnail fetching from external APIs, migrate

This commit is contained in:
2025-12-04 15:15:47 +01:00
parent f49900adad
commit 04e21708b2
7 changed files with 882 additions and 59 deletions
+7 -5
View File
@@ -2,6 +2,7 @@ import { useState, useEffect } from "react";
import { Person, PersonList as PersonListProto } from "../items";
import { apiFetch } from "./api";
import { Link } from "react-router-dom";
import { GameImage } from "./GameImage";
export function GameFilter() {
const [people, setPeople] = useState<Person[]>([]);
@@ -37,10 +38,10 @@ export function GameFilter() {
selectedPersons.forEach((person) => {
person.opinion.forEach((op) => {
if (op.wouldPlay) {
if (!gameToPlayers.has(op.title)) {
gameToPlayers.set(op.title, new Set());
}
if (!gameToPlayers.has(op.title)) {
gameToPlayers.set(op.title, new Set());
}
if (!op.wouldPlay) {
gameToPlayers.get(op.title)!.add(person.name);
}
});
@@ -48,7 +49,7 @@ export function GameFilter() {
// Filter games where ALL selected people would play
const games = Array.from(gameToPlayers.entries())
.filter(([, players]) => players.size === selectedPeople.size)
.filter(([, players]) => players.size === 0)
.map(([game]) => game);
setFilteredGames(games);
@@ -137,6 +138,7 @@ export function GameFilter() {
>
All {selectedPeople.size} selected would play
</div>
<GameImage game={game} />
</Link>
))}
</ul>
+44
View File
@@ -0,0 +1,44 @@
import { useState } from "react";
interface GameImageProps {
game: string;
}
export function GameImage({ game }: GameImageProps) {
const [error, setError] = useState(false);
if (error) {
return (
<div
style={{
width: "100%",
height: "150px",
background: "#ddd",
display: "flex",
alignItems: "center",
justifyContent: "center",
color: "#666",
borderRadius: "8px",
marginTop: "0.5rem",
}}
>
No Image Available
</div>
);
}
return (
<img
src={`/api/game_thumbnail/${encodeURIComponent(game)}`}
alt={`${game} cover`}
onError={() => setError(true)}
style={{
width: "100%",
height: "auto",
borderRadius: "8px",
marginTop: "0.5rem",
objectFit: "cover",
}}
/>
);
}