102 lines
3.0 KiB
TypeScript
102 lines
3.0 KiB
TypeScript
import { useState, useEffect } from "react";
|
|
import { Person, PersonList as PersonListProto } from "../items";
|
|
import { Login } from "./Login";
|
|
import { PersonList } from "./PersonList";
|
|
import { PersonDetails } from "./PersonDetails";
|
|
import { GameList } from "./GameList";
|
|
import { GameFilter } from "./GameFilter";
|
|
import { GameDetails } from "./GameDetails";
|
|
import { ShaderBackground } from "./ShaderBackground";
|
|
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
|
|
import "./App.css";
|
|
import { apiFetch } from "./api";
|
|
|
|
function App() {
|
|
const [people, setPeople] = useState<Person[]>([]);
|
|
const [token, setToken] = useState<string>(
|
|
localStorage.getItem("token") || ""
|
|
);
|
|
const [theme, setTheme] = useState<string>("default");
|
|
const [isShaderTheme, setIsShaderTheme] = useState(false);
|
|
|
|
useEffect(() => {
|
|
if (theme !== "default") {
|
|
document.body.classList.add("shader-theme");
|
|
setIsShaderTheme(true);
|
|
} else {
|
|
document.body.classList.remove("shader-theme");
|
|
setIsShaderTheme(false);
|
|
}
|
|
}, [theme]);
|
|
|
|
const fetchPeople = () => {
|
|
if (!token) return;
|
|
|
|
apiFetch("/api")
|
|
.then((res) => res.arrayBuffer())
|
|
.then((buffer) => {
|
|
const list = PersonListProto.decode(new Uint8Array(buffer));
|
|
setPeople(list.person);
|
|
})
|
|
.catch((err) => console.error("Failed to fetch people:", err));
|
|
};
|
|
|
|
useEffect(() => {
|
|
fetchPeople();
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [token]);
|
|
|
|
const handleLogin = (newToken: string) => {
|
|
setToken(newToken);
|
|
localStorage.setItem("token", newToken);
|
|
};
|
|
|
|
const handleLogout = () => {
|
|
setToken("");
|
|
setPeople([]);
|
|
localStorage.removeItem("token");
|
|
};
|
|
|
|
if (!token) {
|
|
return <Login onLogin={handleLogin} />;
|
|
}
|
|
|
|
return (
|
|
<BrowserRouter>
|
|
<div className="card">
|
|
<div className="navbar">
|
|
<div className="nav-links">
|
|
<Link to="/" className="nav-link">
|
|
People List
|
|
</Link>
|
|
<Link to="/games" className="nav-link">
|
|
Games
|
|
</Link>
|
|
<Link to="/filter" className="nav-link">
|
|
Filter
|
|
</Link>
|
|
</div>
|
|
<button onClick={handleLogout} className="btn-secondary">
|
|
Logout
|
|
</button>
|
|
<select value={theme} onChange={(e) => setTheme(e.target.value)}>
|
|
<option value="default">Default Theme</option>
|
|
<option value="blackhole">Blackhole Theme</option>
|
|
<option value="star">Star Theme</option>
|
|
</select>
|
|
</div>
|
|
{isShaderTheme && <ShaderBackground theme= {theme} />}
|
|
<Routes>
|
|
<Route path="/" element={<PersonList people={people} />} />
|
|
<Route path="/games" element={<GameList />} />
|
|
<Route path="/filter" element={<GameFilter />} />
|
|
<Route path="/person/:name" element={<PersonDetails />} />
|
|
<Route path="/game/:title" element={<GameDetails />} />
|
|
</Routes>
|
|
</div>
|
|
</BrowserRouter>
|
|
);
|
|
}
|
|
|
|
export default App;
|