mirror of https://git.sr.ht/~ashkeel/strimertul
283 lines
8.0 KiB
TypeScript
283 lines
8.0 KiB
TypeScript
import {
|
|
ChatBubbleIcon,
|
|
CodeIcon,
|
|
DashboardIcon,
|
|
FrameIcon,
|
|
MixerHorizontalIcon,
|
|
MixIcon,
|
|
StarIcon,
|
|
TableIcon,
|
|
TimerIcon,
|
|
} from "@radix-ui/react-icons";
|
|
import { EventsOff, EventsOn } from "@wailsapp/runtime/runtime";
|
|
import { useTranslation } from "react-i18next";
|
|
import { useEffect, useState } from "react";
|
|
import { Route, Routes, useLocation, useNavigate } from "react-router-dom";
|
|
|
|
import { GetKilovoltBind, GetLastLogs, IsServerReady } from "@wailsapp/go/main/App";
|
|
import type { main } from "@wailsapp/go/models";
|
|
|
|
import { useAppDispatch, useAppSelector } from "~/store";
|
|
import { createWSClient, useAuthBypass } from "~/store/api/reducer";
|
|
import { ConnectionStatus } from "~/store/api/types";
|
|
import loggingReducer from "~/store/logging/reducer";
|
|
import { initializeExtensions } from "~/store/extensions/reducer";
|
|
import { initializeServerInfo } from "~/store/server/reducer";
|
|
|
|
import LogViewer from "./components/LogViewer";
|
|
import Sidebar, { type RouteSection } from "./components/Sidebar";
|
|
import Scrollbar from "./components/utils/Scrollbar";
|
|
import TwitchChatCommandsPage from "./pages/twitch/ChatCommands";
|
|
import TwitchChatTimersPage from "./pages/twitch/ChatTimers";
|
|
import ChatAlertsPage from "./pages/twitch/ChatAlerts";
|
|
import Dashboard from "./pages/Dashboard";
|
|
import DebugPage from "./pages/system/Debug";
|
|
import LoyaltyConfigPage from "./pages/loyalty/LoyaltyConfig";
|
|
import LoyaltyQueuePage from "./pages/loyalty/LoyaltyQueue";
|
|
import LoyaltyRewardsPage from "./pages/loyalty/Rewards/Page";
|
|
import OnboardingPage from "./pages/Onboarding";
|
|
import ServerSettingsPage from "./pages/system/ServerSettings";
|
|
import StrimertulPage from "./pages/system/Strimertul";
|
|
import TwitchSettingsPage from "./pages/twitch/TwitchSettings/Page";
|
|
import UISettingsPage from "./pages/system/UISettingsPage";
|
|
import ExtensionsPage from "./pages/system/Extensions";
|
|
import { getTheme, styled } from "./theme";
|
|
import Loading from "./components/Loading";
|
|
import InteractiveAuthDialog from "./components/InteractiveAuthDialog";
|
|
import { useKilovoltClient } from "~/lib/react";
|
|
|
|
const sections: RouteSection[] = [
|
|
{
|
|
title: "menu.sections.monitor",
|
|
short: "menu.sections.monitor-short",
|
|
links: [
|
|
{
|
|
title: "menu.pages.monitor.dashboard",
|
|
url: "/",
|
|
icon: <DashboardIcon />,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
title: "menu.sections.strimertul",
|
|
short: "menu.sections.strimertul-short",
|
|
links: [
|
|
{
|
|
title: "menu.pages.strimertul.settings",
|
|
url: "/http",
|
|
icon: <MixerHorizontalIcon />,
|
|
},
|
|
{
|
|
title: "menu.pages.strimertul.ui-config",
|
|
url: "/ui-config",
|
|
icon: <MixIcon />,
|
|
},
|
|
{
|
|
title: "menu.pages.strimertul.extensions",
|
|
url: "/extensions",
|
|
icon: <CodeIcon />,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
title: "menu.sections.twitch",
|
|
short: "menu.sections.twitch-short",
|
|
links: [
|
|
{
|
|
title: "menu.pages.twitch.configuration",
|
|
url: "/twitch/settings",
|
|
icon: <MixerHorizontalIcon />,
|
|
},
|
|
{
|
|
title: "menu.pages.twitch.chat-commands",
|
|
url: "/twitch/chat/commands",
|
|
icon: <ChatBubbleIcon />,
|
|
},
|
|
{
|
|
title: "menu.pages.twitch.chat-timers",
|
|
url: "/twitch/chat/timers",
|
|
icon: <TimerIcon />,
|
|
},
|
|
{
|
|
title: "menu.pages.twitch.chat-alerts",
|
|
url: "/twitch/chat/alerts",
|
|
icon: <FrameIcon />,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
title: "menu.sections.loyalty",
|
|
short: "menu.sections.loyalty-short",
|
|
links: [
|
|
{
|
|
title: "menu.pages.loyalty.configuration",
|
|
url: "/loyalty/settings",
|
|
icon: <MixerHorizontalIcon />,
|
|
},
|
|
{
|
|
title: "menu.pages.loyalty.points",
|
|
url: "/loyalty/users",
|
|
icon: <TableIcon />,
|
|
},
|
|
{
|
|
title: "menu.pages.loyalty.rewards",
|
|
url: "/loyalty/rewards",
|
|
icon: <StarIcon />,
|
|
},
|
|
],
|
|
},
|
|
];
|
|
|
|
const Container = styled("div", {
|
|
position: "relative",
|
|
display: "flex",
|
|
flexDirection: "row",
|
|
overflow: "hidden",
|
|
height: "100vh",
|
|
backgroundColor: "$gray1",
|
|
color: "$gray12",
|
|
});
|
|
|
|
const PageContent = styled("main", {
|
|
flex: 1,
|
|
overflow: "auto",
|
|
});
|
|
|
|
const PageWrapper = styled("div", {
|
|
display: "flex",
|
|
flexDirection: "row",
|
|
flex: 1,
|
|
overflow: "hidden",
|
|
});
|
|
|
|
export default function App(): JSX.Element {
|
|
const [ready, setReady] = useState(false);
|
|
const client = useKilovoltClient();
|
|
const uiConfig = useAppSelector((state) => state.api.uiConfig);
|
|
const connected = useAppSelector((state) => state.api.connectionStatus);
|
|
const dispatch = useAppDispatch();
|
|
const location = useLocation();
|
|
const navigate = useNavigate();
|
|
const [t, i18n] = useTranslation();
|
|
|
|
// Fill application info
|
|
// biome-ignore lint/correctness/useExhaustiveDependencies: False positive
|
|
useEffect(() => {
|
|
void dispatch(initializeServerInfo());
|
|
// Load language from local storage until db is ready
|
|
const lang = localStorage.getItem("language");
|
|
if (lang) {
|
|
void i18n.changeLanguage(lang);
|
|
}
|
|
}, []);
|
|
|
|
// Get application logs
|
|
useEffect(() => {
|
|
void GetLastLogs().then((logs) => {
|
|
dispatch(loggingReducer.actions.loadedLogData(logs));
|
|
});
|
|
EventsOn("log-event", (event: main.LogEntry) => {
|
|
dispatch(loggingReducer.actions.receivedEvent(event));
|
|
});
|
|
return () => {
|
|
EventsOff("log-event");
|
|
};
|
|
}, []);
|
|
|
|
// Wait for main process to give us the OK to hit kilovolt
|
|
useEffect(() => {
|
|
void IsServerReady().then(setReady);
|
|
EventsOn("ready", (newValue: boolean) => {
|
|
setReady(newValue);
|
|
});
|
|
return () => {
|
|
EventsOff("ready");
|
|
};
|
|
}, []);
|
|
|
|
// Connect to kilovolt as soon as it's available
|
|
useEffect(() => {
|
|
const connectToKV = async () => {
|
|
const address = await GetKilovoltBind();
|
|
await dispatch(
|
|
createWSClient({
|
|
address: `ws://${address}/ws`,
|
|
}),
|
|
);
|
|
};
|
|
|
|
if (!ready) {
|
|
return;
|
|
}
|
|
if (!client) {
|
|
void connectToKV();
|
|
return;
|
|
}
|
|
if (connected === ConnectionStatus.AuthenticationNeeded) {
|
|
// If Kilovolt is protected by password (pretty much always) use the bypass
|
|
void dispatch(useAuthBypass());
|
|
return;
|
|
}
|
|
if (connected === ConnectionStatus.Connected) {
|
|
// Once connected, initialize UI subsystems
|
|
void dispatch(initializeExtensions());
|
|
}
|
|
}, [ready, connected]);
|
|
|
|
// Sync UI changes on key change
|
|
// biome-ignore lint/correctness/useExhaustiveDependencies: False positive
|
|
useEffect(() => {
|
|
if (uiConfig?.language) {
|
|
void i18n.changeLanguage(uiConfig.language ?? "en");
|
|
localStorage.setItem("language", uiConfig.language);
|
|
}
|
|
if (uiConfig?.theme) {
|
|
localStorage.setItem("theme", uiConfig.theme);
|
|
}
|
|
if (!uiConfig?.onboardingDone) {
|
|
navigate("/setup");
|
|
}
|
|
}, [uiConfig]);
|
|
|
|
const theme = getTheme(uiConfig?.theme ?? localStorage.getItem("theme") ?? "dark");
|
|
|
|
if (
|
|
connected === ConnectionStatus.NotConnected ||
|
|
connected === ConnectionStatus.AuthenticationNeeded
|
|
) {
|
|
return <Loading theme={theme} size="fullscreen" message={t("special.loading")} />;
|
|
}
|
|
|
|
const showSidebar = location.pathname !== "/setup";
|
|
|
|
return (
|
|
<Container id="app-container" className={theme}>
|
|
<InteractiveAuthDialog />
|
|
<LogViewer />
|
|
{showSidebar ? <Sidebar sections={sections} /> : null}
|
|
<Scrollbar vertical={true} root={{ flex: 1 }} viewport={{ height: "100vh", flex: "1" }}>
|
|
<PageContent>
|
|
<PageWrapper role="main">
|
|
<Routes>
|
|
<Route path="/" element={<Dashboard />} />
|
|
<Route path="/setup" element={<OnboardingPage />} />
|
|
<Route path="/about" element={<StrimertulPage />} />
|
|
<Route path="/debug" element={<DebugPage />} />
|
|
<Route path="/http" element={<ServerSettingsPage />} />
|
|
<Route path="/ui-config" element={<UISettingsPage />} />
|
|
<Route path="/extensions" element={<ExtensionsPage />} />
|
|
<Route path="/twitch/settings" element={<TwitchSettingsPage />} />
|
|
<Route path="/twitch/chat/commands" element={<TwitchChatCommandsPage />} />
|
|
<Route path="/twitch/chat/timers" element={<TwitchChatTimersPage />} />
|
|
<Route path="/twitch/chat/alerts" element={<ChatAlertsPage />} />
|
|
<Route path="/loyalty/settings" element={<LoyaltyConfigPage />} />
|
|
<Route path="/loyalty/users" element={<LoyaltyQueuePage />} />
|
|
<Route path="/loyalty/rewards" element={<LoyaltyRewardsPage />} />
|
|
</Routes>
|
|
</PageWrapper>
|
|
</PageContent>
|
|
</Scrollbar>
|
|
</Container>
|
|
);
|
|
}
|