121 lines
3.1 KiB
TypeScript
121 lines
3.1 KiB
TypeScript
import { useState, useEffect } from "react";
|
|
import { useParams } from "react-router-dom";
|
|
import { Person, AddOpinionRequest, Game, GameList } from "../items";
|
|
import { apiFetch } from "./api";
|
|
|
|
export const PersonDetails = () => {
|
|
const { name } = useParams<{ name: string }>();
|
|
const [person, setPerson] = useState<Person | null>(null);
|
|
const [games, setGames] = useState<Game[]>([]);
|
|
const [gameTitle, setGameTitle] = useState("");
|
|
const [wouldPlay, setWouldPlay] = useState(false);
|
|
|
|
useEffect(() => {
|
|
apiFetch("/api/games")
|
|
.then((res) => res.arrayBuffer())
|
|
.then((buffer) => {
|
|
try {
|
|
const list = GameList.decode(new Uint8Array(buffer));
|
|
setGames(list.games);
|
|
if (list.games.length > 0) {
|
|
setGameTitle(list.games[0].title);
|
|
}
|
|
} catch (e) {
|
|
console.error("Failed to decode games:", e);
|
|
}
|
|
})
|
|
.catch(console.error);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (name) {
|
|
apiFetch(`/api/${name}`)
|
|
.then((res) => res.arrayBuffer())
|
|
.then((buffer) => {
|
|
try {
|
|
setPerson(Person.decode(new Uint8Array(buffer)));
|
|
} catch (e) {
|
|
console.error("Failed to decode person:", e);
|
|
}
|
|
})
|
|
.catch(console.error);
|
|
}
|
|
}, [name]);
|
|
|
|
const handleAddOpinion = async () => {
|
|
if (!person) return;
|
|
|
|
const req = AddOpinionRequest.create({
|
|
gameTitle,
|
|
wouldPlay,
|
|
});
|
|
|
|
const buffer = AddOpinionRequest.encode(req).finish();
|
|
|
|
try {
|
|
const res = await apiFetch("/api/opinion", {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/octet-stream",
|
|
},
|
|
body: buffer,
|
|
});
|
|
|
|
if (res.ok) {
|
|
const resBuffer = await res.arrayBuffer();
|
|
setPerson(Person.decode(new Uint8Array(resBuffer)));
|
|
setGameTitle("");
|
|
setWouldPlay(false);
|
|
}
|
|
} catch (e) {
|
|
console.error(e);
|
|
}
|
|
};
|
|
|
|
if (!person) return <div>Loading...</div>;
|
|
|
|
return (
|
|
<div className="card">
|
|
<h2>{person.name}</h2>
|
|
<ul>
|
|
{person.opinion.map((op, i) => (
|
|
<li key={i}>
|
|
{op.title} - {op.wouldPlay ? "Would Play" : "Would Not Play"}
|
|
</li>
|
|
))}
|
|
</ul>
|
|
|
|
<div
|
|
style={{
|
|
marginTop: "2rem",
|
|
borderTop: "1px solid #ccc",
|
|
paddingTop: "1rem",
|
|
}}
|
|
>
|
|
<h3>Add Opinion</h3>
|
|
<div style={{ display: "flex", gap: "1rem", alignItems: "center" }}>
|
|
<select
|
|
value={gameTitle}
|
|
onChange={(e) => setGameTitle(e.target.value)}
|
|
>
|
|
{games.map((g) => (
|
|
<option key={g.title} value={g.title}>
|
|
{g.title}
|
|
</option>
|
|
))}
|
|
</select>
|
|
<label>
|
|
<input
|
|
type="checkbox"
|
|
checked={wouldPlay}
|
|
onChange={(e) => setWouldPlay(e.target.checked)}
|
|
/>
|
|
Would Play
|
|
</label>
|
|
<button onClick={handleAddOpinion}>Add</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|