Preserve dashboard page across refreshes

This commit is contained in:
2026-08-01 00:11:17 +02:00
parent ec44905310
commit 7bbf7aa4cc
+25 -6
View File
@@ -47,6 +47,14 @@ const ShellTerminal = lazy(async () => {
}); });
type Screen = "loading" | "setup" | "login" | "dashboard" | "fatal"; type Screen = "loading" | "setup" | "login" | "dashboard" | "fatal";
type DashboardPage = "home" | "car" | "adb" | "network" | "settings";
const dashboardPages = new Set<DashboardPage>(["home", "car", "adb", "network", "settings"]);
function pageFromLocation(): DashboardPage {
const page = window.location.hash.replace(/^#\/?/, "");
return dashboardPages.has(page as DashboardPage) ? (page as DashboardPage) : "home";
}
export function App() { export function App() {
const [screen, setScreen] = useState<Screen>("loading"); const [screen, setScreen] = useState<Screen>("loading");
@@ -171,7 +179,7 @@ function AccountScreen({
} }
function Dashboard({ auth, onLoggedOut }: { auth: AuthState; onLoggedOut: () => Promise<void> }) { function Dashboard({ auth, onLoggedOut }: { auth: AuthState; onLoggedOut: () => Promise<void> }) {
const [page, setPage] = useState<"home" | "car" | "adb" | "network" | "settings">("home"); const [page, setPage] = useState<DashboardPage>(pageFromLocation);
const [status, setStatus] = useState<SystemStatus | null>(null); const [status, setStatus] = useState<SystemStatus | null>(null);
const [error, setError] = useState(""); const [error, setError] = useState("");
const [connection, setConnection] = useState<"connecting" | "live" | "offline">("connecting"); const [connection, setConnection] = useState<"connecting" | "live" | "offline">("connecting");
@@ -202,6 +210,17 @@ function Dashboard({ auth, onLoggedOut }: { auth: AuthState; onLoggedOut: () =>
return () => events.close(); return () => events.close();
}, [refresh]); }, [refresh]);
useEffect(() => {
const syncPageWithLocation = () => setPage(pageFromLocation());
window.addEventListener("hashchange", syncPageWithLocation);
return () => window.removeEventListener("hashchange", syncPageWithLocation);
}, []);
function navigate(nextPage: DashboardPage) {
setPage(nextPage);
window.location.hash = `/${nextPage}`;
}
async function logout() { async function logout() {
await post("/api/auth/logout", {}, auth.csrfToken); await post("/api/auth/logout", {}, auth.csrfToken);
await onLoggedOut(); await onLoggedOut();
@@ -212,11 +231,11 @@ function Dashboard({ auth, onLoggedOut }: { auth: AuthState; onLoggedOut: () =>
<aside className="sidebar"> <aside className="sidebar">
<div className="brand brand-compact"><Gauge size={30} weight="duotone" /><span>Pi Companion</span></div> <div className="brand brand-compact"><Gauge size={30} weight="duotone" /><span>Pi Companion</span></div>
<nav aria-label="Primary navigation"> <nav aria-label="Primary navigation">
<button className={`nav-item ${page === "home" ? "active" : ""}`} onClick={() => setPage("home")}><House size={24} weight={page === "home" ? "fill" : "regular"} /><span>Home</span></button> <button className={`nav-item ${page === "home" ? "active" : ""}`} onClick={() => navigate("home")}><House size={24} weight={page === "home" ? "fill" : "regular"} /><span>Home</span></button>
<button className={`nav-item ${page === "car" ? "active" : ""}`} onClick={() => setPage("car")}><CarProfile size={24} weight={page === "car" ? "fill" : "regular"} /><span>Car</span></button> <button className={`nav-item ${page === "car" ? "active" : ""}`} onClick={() => navigate("car")}><CarProfile size={24} weight={page === "car" ? "fill" : "regular"} /><span>Car</span></button>
<button className={`nav-item ${page === "adb" ? "active" : ""}`} onClick={() => setPage("adb")}><AndroidLogo size={24} weight={page === "adb" ? "fill" : "regular"} /><span>ADB</span></button> <button className={`nav-item ${page === "adb" ? "active" : ""}`} onClick={() => navigate("adb")}><AndroidLogo size={24} weight={page === "adb" ? "fill" : "regular"} /><span>ADB</span></button>
<button className={`nav-item ${page === "network" ? "active" : ""}`} onClick={() => setPage("network")}><WifiHigh size={24} weight={page === "network" ? "fill" : "regular"} /><span>Network</span></button> <button className={`nav-item ${page === "network" ? "active" : ""}`} onClick={() => navigate("network")}><WifiHigh size={24} weight={page === "network" ? "fill" : "regular"} /><span>Network</span></button>
<button className={`nav-item ${page === "settings" ? "active" : ""}`} onClick={() => setPage("settings")}><Gear size={24} weight={page === "settings" ? "fill" : "regular"} /><span>Settings</span></button> <button className={`nav-item ${page === "settings" ? "active" : ""}`} onClick={() => navigate("settings")}><Gear size={24} weight={page === "settings" ? "fill" : "regular"} /><span>Settings</span></button>
</nav> </nav>
<button className="nav-item logout" onClick={() => void logout()}><SignOut size={24} /><span>Sign out</span></button> <button className="nav-item logout" onClick={() => void logout()}><SignOut size={24} /><span>Sign out</span></button>
</aside> </aside>