diff --git a/apps/fabro-web/app/router.tsx b/apps/fabro-web/app/router.tsx
index e9382e032..e29d7b432 100644
--- a/apps/fabro-web/app/router.tsx
+++ b/apps/fabro-web/app/router.tsx
@@ -31,6 +31,8 @@ import * as Settings from "./routes/settings";
import * as SettingsOverview from "./routes/settings-overview";
import * as SettingsLiveEvents from "./routes/settings-live-events";
import * as Profile from "./routes/profile";
+import * as ProfileOverview from "./routes/profile-overview";
+import * as ProfileSessions from "./routes/profile-sessions";
import AppShellModule from "./layouts/app-shell";
type RouteModule = {
@@ -121,7 +123,12 @@ export const routes: RouteObject[] = [
route("live-events", SettingsLiveEvents),
],
}),
- route("profile", Profile),
+ route("profile", Profile, {
+ children: [
+ indexRoute(ProfileOverview),
+ route("sessions", ProfileSessions),
+ ],
+ }),
],
},
],
diff --git a/apps/fabro-web/app/routes/profile-overview.tsx b/apps/fabro-web/app/routes/profile-overview.tsx
new file mode 100644
index 000000000..9b6a27ff8
--- /dev/null
+++ b/apps/fabro-web/app/routes/profile-overview.tsx
@@ -0,0 +1,69 @@
+import type { AuthSessionUser } from "@qltysh/fabro-api-client";
+import { useAuthMe } from "../lib/queries";
+import {
+ Mono,
+ Muted,
+ Panel,
+ PanelSkeleton,
+ Row,
+ UrlValue,
+} from "../components/settings-panel";
+
+export default function ProfileOverview() {
+ const { data: auth } = useAuthMe();
+
+ if (!auth) {
+ return (
+
+ );
+ }
+
+ const { user } = auth;
+
+ return (
+
+
+
+
+ );
+}
+
+function BasicsPanel({ user }: { user: AuthSessionUser }) {
+ return (
+
+
+
+

+
{user.name}
+
+
+
+ {user.login}
+
+ {user.email}
+
+ );
+}
+
+function IdentityPanel({ user }: { user: AuthSessionUser }) {
+ return (
+
+
+ {user.idpIssuer ? {user.idpIssuer} : —}
+
+
+ {user.idpSubject ? {user.idpSubject} : —}
+
+
+
+
+
+ );
+}
diff --git a/apps/fabro-web/app/routes/profile-sessions.tsx b/apps/fabro-web/app/routes/profile-sessions.tsx
new file mode 100644
index 000000000..9227b5c5b
--- /dev/null
+++ b/apps/fabro-web/app/routes/profile-sessions.tsx
@@ -0,0 +1,3 @@
+export default function ProfileSessions() {
+ return ;
+}
diff --git a/apps/fabro-web/app/routes/profile.tsx b/apps/fabro-web/app/routes/profile.tsx
index e9bbe2f78..27ca149ba 100644
--- a/apps/fabro-web/app/routes/profile.tsx
+++ b/apps/fabro-web/app/routes/profile.tsx
@@ -1,73 +1,77 @@
-import type { AuthSessionUser } from "@qltysh/fabro-api-client";
-import { useAuthMe } from "../lib/queries";
-import {
- Mono,
- Muted,
- Panel,
- PanelSkeleton,
- Row,
- UrlValue,
-} from "../components/settings-panel";
+import { ComputerDesktopIcon, UserCircleIcon } from "@heroicons/react/24/outline";
+import { Link, Outlet, useLocation } from "react-router";
export function meta({}: any) {
return [{ title: "Profile — Fabro" }];
}
-export default function Profile() {
- const { data: auth } = useAuthMe();
+export const handle = { hideHeader: true };
- if (!auth) {
- return (
-
- );
- }
+type NavItem = {
+ name: string;
+ href: string;
+ icon: typeof UserCircleIcon;
+ match: (pathname: string) => boolean;
+};
- const { user } = auth;
+const navItems: NavItem[] = [
+ {
+ name: "Profile",
+ href: "/profile",
+ icon: UserCircleIcon,
+ match: (p) => p === "/profile",
+ },
+ {
+ name: "Sessions",
+ href: "/profile/sessions",
+ icon: ComputerDesktopIcon,
+ match: (p) => p.startsWith("/profile/sessions"),
+ },
+];
+
+function classNames(...classes: Array) {
+ return classes.filter(Boolean).join(" ");
+}
+
+export default function ProfileLayout() {
+ const { pathname } = useLocation();
+ const currentName = navItems.find((item) => item.match(pathname))?.name ?? "Profile";
return (
-
-
-
+
+
+
+
+
+ {currentName}
+
+
+
);
}
-
-function BasicsPanel({ user }: { user: AuthSessionUser }) {
- return (
-
-
-
-

-
{user.name}
-
-
-
- {user.login}
-
- {user.email}
-
- );
-}
-
-function IdentityPanel({ user }: { user: AuthSessionUser }) {
- return (
-
-
- {user.idpIssuer ? {user.idpIssuer} : —}
-
-
- {user.idpSubject ? {user.idpSubject} : —}
-
-
-
-
-
- );
-}