game_list/frontend/src/GameList.tsx

158 lines
3.9 KiB
TypeScript

import { useState, useEffect } from "react";
import { Game, Source, GameList as GameListProto } from "../items";
import { apiFetch } from "./api";
export function GameList() {
const [games, setGames] = useState<Game[]>([]);
const [title, setTitle] = useState("");
const [source, setSource] = useState<Source>(Source.STEAM);
const [multiplayer, setMultiplayer] = useState(false);
const [minPlayers, setMinPlayers] = useState(1);
const [maxPlayers, setMaxPlayers] = useState(1);
const [price, setPrice] = useState(0);
const [remoteId, setRemoteId] = useState(0);
const [message, setMessage] = useState("");
const fetchGames = () => {
apiFetch("/api/games")
.then((res) => res.arrayBuffer())
.then((buffer) => {
try {
const list = GameListProto.decode(new Uint8Array(buffer));
setGames(list.games);
} catch (e) {
console.error("Failed to decode games:", e);
}
})
.catch(console.error);
};
useEffect(() => {
fetchGames();
}, []);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
const game = {
title,
source,
multiplayer,
minPlayers,
maxPlayers,
price,
remoteId,
};
try {
const encoded = Game.encode(game).finish();
const res = await apiFetch("/api/game", {
method: "POST",
headers: {
"Content-Type": "application/octet-stream",
},
body: encoded,
});
if (res.ok) {
setMessage("Game added successfully!");
setTitle("");
fetchGames();
// Reset other fields if needed
} else {
setMessage("Failed to add game.");
}
} catch (err) {
console.error(err);
setMessage("Error adding game.");
}
};
return (
<div>
<h2>Add New Game</h2>
{message && <p>{message}</p>}
<form
onSubmit={handleSubmit}
style={{
display: "flex",
flexDirection: "column",
gap: "1rem",
maxWidth: "400px",
}}
>
<label>
Title:
<input
type="text"
value={title}
onChange={(e) => setTitle(e.target.value)}
required
/>
</label>
<label>
Source:
<select
value={source}
onChange={(e) => setSource(Number(e.target.value))}
>
<option value={Source.STEAM}>Steam</option>
<option value={Source.ROBLOX}>Roblox</option>
</select>
</label>
<label>
Multiplayer:
<input
type="checkbox"
checked={multiplayer}
onChange={(e) => setMultiplayer(e.target.checked)}
/>
</label>
<label>
Min Players:
<input
type="number"
value={minPlayers}
onChange={(e) => setMinPlayers(Number(e.target.value))}
/>
</label>
<label>
Max Players:
<input
type="number"
value={maxPlayers}
onChange={(e) => setMaxPlayers(Number(e.target.value))}
/>
</label>
<label>
Price:
<input
type="number"
value={price}
onChange={(e) => setPrice(Number(e.target.value))}
/>
</label>
<label>
Remote ID:
<input
type="number"
value={remoteId}
onChange={(e) => setRemoteId(Number(e.target.value))}
/>
</label>
<button type="submit">Add Game</button>
</form>
<div style={{ marginTop: "2rem" }}>
<h3>Existing Games</h3>
<ul>
{games.map((game) => (
<li key={game.title}>
{game.title} ({game.source === Source.STEAM ? "Steam" : "Roblox"})
</li>
))}
</ul>
</div>
</div>
);
}