eris/ui/AppHeader.tsx

136 lines
3.6 KiB
TypeScript
Raw Normal View History

2023-10-05 09:00:51 +00:00
import React, { ReactNode } from "react";
import { NavLink } from "react-router-dom";
import useSWR from "swr";
2023-10-21 10:40:42 +00:00
import { cx } from "twind/core";
import { API_URL, fetchApi, handleResponse } from "./apiClient.ts";
2023-10-05 09:00:51 +00:00
function NavTab(props: { to: string; children: ReactNode }) {
return (
<NavLink
className={({ isActive }) => cx("tab", isActive && "tab-active")}
to={props.to}
>
{props.children}
</NavLink>
);
}
2023-10-23 00:39:01 +00:00
export function AppHeader(props: {
className?: string;
sessionId: string | null;
onLogOut: () => void;
}) {
2023-10-05 09:00:51 +00:00
const { className, sessionId, onLogOut } = props;
2023-10-23 00:39:01 +00:00
const getSession = useSWR(
sessionId ? ["/sessions/:sessionId", { method: "GET", params: { sessionId } }] as const : null,
2023-10-08 21:23:54 +00:00
(args) => fetchApi(...args).then(handleResponse),
2023-10-05 09:00:51 +00:00
{ onError: () => onLogOut() },
);
2023-10-23 00:39:01 +00:00
const getUser = useSWR(
getSession.data?.userId
? ["/users/:userId", {
method: "GET",
params: { userId: String(getSession.data.userId) },
}] as const
2023-10-05 09:00:51 +00:00
: null,
2023-10-08 21:23:54 +00:00
(args) => fetchApi(...args).then(handleResponse),
2023-10-05 09:00:51 +00:00
);
2023-10-23 00:39:01 +00:00
const getBot = useSWR(
["/bot", { method: "GET" }] as const,
2023-10-19 21:37:03 +00:00
(args) => fetchApi(...args).then(handleResponse),
2023-10-13 19:18:19 +00:00
);
2023-10-23 00:39:01 +00:00
const getUserPhoto = useSWR(
getSession.data?.userId
? ["/users/:userId/photo", {
method: "GET",
2023-10-23 00:39:01 +00:00
params: { userId: String(getSession.data.userId) },
2023-10-10 16:21:25 +00:00
}] as const
: null,
() =>
// elysia fetch can't download file
fetch(`${API_URL}/users/${getSession.data?.userId}/photo`)
.then((response) => {
if (!response.ok) throw new Error(response.statusText);
return response;
})
.then((response) => response.blob())
.then((blob) => blob ? URL.createObjectURL(blob) : null),
2023-10-10 16:21:25 +00:00
);
2023-10-05 09:00:51 +00:00
return (
<header
className={cx(
"bg-zinc-50 dark:bg-zinc-800 shadow-md flex items-center gap-2 px-4 py-1",
className,
)}
>
{/* logo */}
<img className="w-12 h-12" src="/favicon.png" alt="logo" />
{/* tabs */}
<nav className="flex-grow self-stretch flex items-stretch justify-center gap-2">
<NavTab to="/">
Stats
</NavTab>
2023-10-23 00:39:01 +00:00
<NavTab to="/admins">
Admins
</NavTab>
2023-10-13 11:47:57 +00:00
<NavTab to="/workers">
Workers
</NavTab>
2023-10-05 09:00:51 +00:00
<NavTab to="/queue">
Queue
</NavTab>
<NavTab to="/settings">
Settings
</NavTab>
</nav>
{/* loading indicator */}
2023-10-23 00:39:01 +00:00
{getSession.isLoading || getUser.isLoading ? <div className="spinner" /> : null}
2023-10-05 09:00:51 +00:00
{/* user avatar */}
2023-10-23 00:39:01 +00:00
{getUser.data
? getUserPhoto.data
2023-10-05 09:00:51 +00:00
? (
<img
2023-10-23 00:39:01 +00:00
src={getUserPhoto.data}
2023-10-05 09:00:51 +00:00
alt="avatar"
className="w-9 h-9 rounded-full"
/>
)
: (
<div className="w-9 h-9 rounded-full bg-zinc-400 dark:bg-zinc-500 flex items-center justify-center text-white text-2xl font-bold select-none">
2023-10-23 00:39:01 +00:00
{getUser.data.first_name.at(0)?.toUpperCase()}
2023-10-05 09:00:51 +00:00
</div>
)
: null}
{/* login/logout button */}
2023-10-23 00:39:01 +00:00
{!getSession.isLoading && !getUser.isLoading && getBot.data && sessionId
2023-10-05 09:00:51 +00:00
? (
2023-10-23 00:39:01 +00:00
getUser.data
2023-10-05 09:00:51 +00:00
? (
<button className="button-outlined" onClick={() => onLogOut()}>
Logout
</button>
)
: (
<a
className="button-filled"
2023-10-23 00:39:01 +00:00
href={`https://t.me/${getBot.data.username}?start=${sessionId}`}
2023-10-05 09:00:51 +00:00
target="_blank"
>
Login
</a>
)
)
: null}
</header>
);
}