64 lines
2.3 KiB
TypeScript
64 lines
2.3 KiB
TypeScript
import { useState, useEffect } from "react";
|
|
import { apiFetch, getStoredKey, onUnauthorized, logout } from "./api";
|
|
import { getSpeechMuted, setSpeechMuted } from "./speech";
|
|
import Login from "./components/Login";
|
|
import Chat from "./components/Chat";
|
|
import Dashboard from "./components/Dashboard";
|
|
import Settings from "./components/Settings";
|
|
import WeatherWidget from "./components/WeatherWidget";
|
|
|
|
type View = "chat" | "dashboard" | "settings";
|
|
|
|
export default function App() {
|
|
const [authenticated, setAuthenticated] = useState<boolean>(() => getStoredKey() !== null);
|
|
const [view, setView] = useState<View>("chat");
|
|
const [muted, setMuted] = useState<boolean>(() => getSpeechMuted());
|
|
const [assistantName, setAssistantName] = useState<string>("JARVIS");
|
|
|
|
useEffect(() => onUnauthorized(() => setAuthenticated(false)), []);
|
|
|
|
useEffect(() => {
|
|
if (!authenticated) return;
|
|
async function loadAssistantName() {
|
|
try {
|
|
const response = await apiFetch("/api/v1/settings");
|
|
if (!response.ok) return;
|
|
const data = await response.json();
|
|
setAssistantName(data.assistant_name);
|
|
document.title = data.assistant_name;
|
|
} catch {
|
|
// Default "JARVIS" bleibt bei Fehlern erhalten.
|
|
}
|
|
}
|
|
loadAssistantName();
|
|
}, [authenticated]);
|
|
|
|
function toggleMuted() {
|
|
const next = !muted;
|
|
setSpeechMuted(next);
|
|
setMuted(next);
|
|
}
|
|
|
|
if (!authenticated) {
|
|
return <Login onSuccess={() => setAuthenticated(true)} />;
|
|
}
|
|
|
|
return (
|
|
<div className="app">
|
|
<nav className="nav">
|
|
<button onClick={() => setView("chat")} disabled={view === "chat"}>Chat</button>
|
|
<button onClick={() => setView("dashboard")} disabled={view === "dashboard"}>Dashboard</button>
|
|
<button onClick={() => setView("settings")} disabled={view === "settings"}>Einstellungen</button>
|
|
<button onClick={toggleMuted} title={muted ? "Sprachausgabe einschalten" : "Sprachausgabe stummschalten"}>
|
|
{muted ? "🔇" : "🔊"}
|
|
</button>
|
|
<button onClick={() => logout()}>Logout</button>
|
|
<WeatherWidget />
|
|
</nav>
|
|
{view === "chat" && <Chat assistantName={assistantName} />}
|
|
{view === "dashboard" && <Dashboard />}
|
|
{view === "settings" && <Settings />}
|
|
</div>
|
|
);
|
|
}
|