ux improvements

This commit is contained in:
2026-01-11 20:32:34 +01:00
parent f24e8fc1e9
commit e7fede576c
10 changed files with 595 additions and 115 deletions
+48 -23
View File
@@ -3,53 +3,78 @@ import { Link, useParams } from "react-router-dom";
import { Person } from "../items";
import { apiFetch } from "./api";
import { GameImage } from "./GameImage";
import { LoadingState, EmptyState } from "./components/EmptyState";
export const PersonDetails = () => {
const { name } = useParams<{ name: string }>();
const [person, setPerson] = useState<Person | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
if (name) {
setLoading(true);
setError(null);
apiFetch(`/api/${name}`)
.then((res) => res.arrayBuffer())
.then((res) => {
if (!res.ok) {
throw new Error("Person not found");
}
return res.arrayBuffer();
})
.then((buffer) => {
try {
setPerson(Person.decode(new Uint8Array(buffer)));
} catch (e) {
console.error("Failed to decode person:", e);
throw new Error("Failed to load person data");
}
})
.catch(console.error);
.catch((err) => {
console.error(err);
setError(err.message || "Failed to load person");
})
.finally(() => setLoading(false));
}
}, [name]);
if (!person) return <div>Loading...</div>;
if (loading) return <LoadingState message="Loading person details..." />;
if (error) return <EmptyState icon="⚠️" title="Error" description={error} />;
if (!person) return <EmptyState icon="👤" title="Person not found" description="This person doesn't exist" />;
return (
<div>
<div style={{ marginBottom: "2rem" }}>
<h2>{person.name}</h2>
<ul className="grid-container">
{person.opinion.map((op, i) => (
<Link
to={`/game/${encodeURIComponent(op.title)}`}
key={i}
className="list-item"
style={{
textDecoration: "none",
color: "inherit",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
borderColor: op.wouldPlay ? "#4caf50" : "#f44336",
}}
>
<strong>{op.title}</strong>
{person.opinion.length === 0 ? (
<EmptyState
icon="🎮"
title="No opinions yet"
description={`${person.name} hasn't shared any game opinions`}
/>
) : (
<ul className="grid-container">
{person.opinion.map((op, i) => (
<Link
to={`/game/${encodeURIComponent(op.title)}`}
key={i}
className="list-item"
style={{
textDecoration: "none",
color: "inherit",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
borderColor: op.wouldPlay ? "#4caf50" : "#f44336",
}}
>
<strong>{op.title}</strong>
<GameImage game={op.title} />
</Link>
))}
</ul>
<GameImage game={op.title} />
</Link>
))}
</ul>
)}
</div>
</div>
);