feat: Add API to retrieve authentication status and display user game opinions with colored borders in the game list.

This commit is contained in:
code002lover 2025-12-04 20:30:21 +01:00
parent defcb0e0bc
commit 03de073692
3 changed files with 83 additions and 53 deletions

View File

@ -1,7 +1,13 @@
import { useState, useEffect } from "react";
import { Game, Source, GameList as GameListProto } from "../items";
import {
Game,
Source,
GameList as GameListProto,
Person as PersonProto,
Opinion,
} from "../items";
import { Link } from "react-router-dom";
import { apiFetch } from "./api";
import { apiFetch, get_auth_status } from "./api";
import { GameImage } from "./GameImage";
export function GameList() {
@ -14,6 +20,7 @@ export function GameList() {
const [remoteId, setRemoteId] = useState(0);
const [message, setMessage] = useState("");
const [isSubmitting, setIsSubmitting] = useState(false);
const [opinions, setOpinions] = useState<Opinion[]>([]);
const fetchGames = () => {
apiFetch("/api/games")
@ -29,6 +36,22 @@ export function GameList() {
.catch(console.error);
};
useEffect(() => {
get_auth_status().then((user) => {
apiFetch(`/api/${user?.username}`)
.then((res) => res.arrayBuffer())
.then((buffer) => {
try {
const person = PersonProto.decode(new Uint8Array(buffer));
const opinions = person.opinion;
setOpinions(opinions);
} catch (e) {
console.error("Failed to decode games:", e);
}
});
});
}, []);
useEffect(() => {
fetchGames();
}, []);
@ -365,7 +388,7 @@ export function GameList() {
<div style={gridStyles}>
<div style={inputGroupStyles}>
<label style={labelStyles}>Price ($)</label>
<label style={labelStyles}>Price ()</label>
<input
type="number"
value={price}
@ -432,23 +455,31 @@ export function GameList() {
<div style={{ marginTop: "3rem" }}>
<h3>Existing Games</h3>
<ul className="grid-container">
{games.map((game) => (
<Link
to={`/game/${encodeURIComponent(game.title)}`}
key={game.title}
className="list-item"
style={{
textDecoration: "none",
color: "inherit",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<strong>{game.title}</strong>
<GameImage game={game.title} />
</Link>
))}
{games.map((game) => {
const opinion = opinions.find((op) => op.title === game.title);
return (
<Link
to={`/game/${encodeURIComponent(game.title)}`}
key={game.title}
className="list-item"
style={{
textDecoration: "none",
color: "inherit",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
borderColor: opinion
? opinion.wouldPlay
? "#4caf50" // would play (green)
: "#f44336" // would not play (red)
: "#191f2e", // no opinion (bg-2)
}}
>
<strong>{game.title}</strong>
<GameImage game={game.title} />
</Link>
);
})}
</ul>
</div>
</div>

View File

@ -1,14 +1,7 @@
import { useState, useEffect } from "react";
import { Link, useParams } from "react-router-dom";
import {
Person,
AddOpinionRequest,
Game,
GameList,
AuthStatusRequest,
AuthStatusResponse,
} from "../items";
import { apiFetch } from "./api";
import { Person, AddOpinionRequest, Game, GameList } from "../items";
import { apiFetch, get_auth_status } from "./api";
import { GameImage } from "./GameImage";
export const PersonDetails = () => {
@ -20,31 +13,14 @@ export const PersonDetails = () => {
const [currentUser, setCurrentUser] = useState<string>("");
useEffect(() => {
const token = localStorage.getItem("token");
if (token) {
const req = AuthStatusRequest.create({ token });
const buffer = AuthStatusRequest.encode(req).finish();
apiFetch("/auth/get_auth_status", {
method: "POST",
headers: {
"Content-Type": "application/octet-stream",
},
body: buffer,
})
.then((res) => res.arrayBuffer())
.then((buffer) => {
try {
const response = AuthStatusResponse.decode(new Uint8Array(buffer));
if (response.authenticated) {
setCurrentUser(response.username);
}
} catch (e) {
console.error("Failed to decode auth status:", e);
}
})
.catch(console.error);
async function fetchUser() {
const token = localStorage.getItem("token");
if (token) {
const authStatus = await get_auth_status();
setCurrentUser(authStatus?.username || "");
}
}
fetchUser();
}, []);
useEffect(() => {

View File

@ -1,3 +1,5 @@
import { AuthStatusRequest, AuthStatusResponse } from "../items";
export const apiFetch = async (
url: string,
options: RequestInit = {}
@ -26,3 +28,24 @@ export const apiFetch = async (
return response;
};
export const get_auth_status = async (): Promise<AuthStatusResponse | null> => {
const token = localStorage.getItem("token") as string;
const req = AuthStatusRequest.create({ token });
const req_buffer = AuthStatusRequest.encode(req).finish();
const response = await apiFetch("/auth/get_auth_status", {
method: "POST",
headers: {
"Content-Type": "application/octet-stream",
},
body: req_buffer,
});
const buffer = await response.arrayBuffer();
try {
const response = AuthStatusResponse.decode(new Uint8Array(buffer));
return response;
} catch (e) {
console.error("Failed to decode auth status:", e);
return null;
}
};