Files
geniusrun/frontend/src/App.tsx

72 lines
2.4 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useEffect, useState } from "react";
import { api, BASE_URL } from "./api/client";
import "./App.css";
import { Activities } from "./pages/Activities";
import { Analysis } from "./pages/Analysis";
import { Plan } from "./pages/Plan";
import { Profile } from "./pages/Profile";
import type { SessionInfo } from "./types/api";
const TABS = [
{ key: "activities", label: "Activities", icon: "☰", Component: Activities },
{ key: "analysis", label: "Analysis", icon: "🔍", Component: Analysis },
{ key: "plan", label: "Training plan", icon: "✎", Component: Plan },
] as const;
type TabKey = (typeof TABS)[number]["key"];
function App({ session }: { session: SessionInfo }) {
const [tab, setTab] = useState<TabKey>("activities");
// Profile isn't a tab: it's reached via the profile name in the top-right
// corner instead, since (for now, single-profile) it's account settings,
// not a content view alongside Activities/Analysis/Training plan.
const [showProfile, setShowProfile] = useState(false);
const [profileName, setProfileName] = useState<string | null>(null);
useEffect(() => {
api.getProfile().then((p) => setProfileName(p.Name)).catch(() => {});
}, []);
const Active = TABS.find((t) => t.key === tab)!.Component;
return (
<div className="app">
<header className="app-header">
<h1>🧞 geniusrun</h1>
<nav className="tabs">
{TABS.map((t) => (
<button
key={t.key}
className={!showProfile && t.key === tab ? "tab active" : "tab"}
onClick={() => {
setShowProfile(false);
setTab(t.key);
}}
>
<span className="tab-icon">{t.icon}</span>
{t.label}
</button>
))}
</nav>
<div className="header-actions">
<button
type="button"
className={showProfile ? "profile-name active" : "profile-name"}
onClick={() => setShowProfile(true)}
>
{profileName ?? "Profile"}
</button>
<form method="post" action={`${BASE_URL}/api/session/logout`} title={session.email}>
<button type="submit" className="logout-link">
Log out
</button>
</form>
</div>
</header>
<main>{showProfile ? <Profile onSaved={(p) => setProfileName(p.Name)} /> : <Active />}</main>
</div>
);
}
export default App;