77 lines
2.6 KiB
TypeScript
77 lines
2.6 KiB
TypeScript
|
|
"use client";
|
||
|
|
|
||
|
|
import { type ReactNode, useEffect, useState } from "react";
|
||
|
|
import { CapabilitiesProvider } from "@/lib/capabilities/context";
|
||
|
|
import { JobsProvider } from "@/components/layout/jobs-provider";
|
||
|
|
import { LatestToast } from "@/components/layout/latest-toast";
|
||
|
|
import { ActiveJobsPanel } from "@/components/layout/active-jobs-panel";
|
||
|
|
import { ThreadsOAuthToast } from "@/components/layout/threads-oauth-toast";
|
||
|
|
import {
|
||
|
|
MobileBottomNav,
|
||
|
|
MobileNavDrawer,
|
||
|
|
useMobileLogout,
|
||
|
|
} from "@/components/layout/mobile-nav";
|
||
|
|
import { KonamiRegisterGate } from "@/components/auth/konami-register-gate";
|
||
|
|
import { RefineSessionHost } from "@/components/refine-session-host";
|
||
|
|
import { Sidebar } from "@/components/layout/sidebar";
|
||
|
|
import { useJobs } from "@/components/layout/jobs-provider";
|
||
|
|
import { useNotifications } from "@/lib/notifications/use-notifications";
|
||
|
|
import { setNotificationScope } from "@/lib/notifications/store";
|
||
|
|
|
||
|
|
function DashboardChrome({ children }: { children: ReactNode }) {
|
||
|
|
const [menuOpen, setMenuOpen] = useState(false);
|
||
|
|
const [userEmail, setUserEmail] = useState<string | null>(null);
|
||
|
|
const { unreadCount } = useNotifications();
|
||
|
|
const { activeJobs } = useJobs();
|
||
|
|
const badgeCount = unreadCount + activeJobs.length;
|
||
|
|
const logout = useMobileLogout();
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
fetch("/api/auth/me")
|
||
|
|
.then((res) => (res.ok ? res.json() : null))
|
||
|
|
.then((data) => {
|
||
|
|
if (data?.user?.id) setNotificationScope(data.user.id);
|
||
|
|
setUserEmail(data?.user?.email ?? null);
|
||
|
|
})
|
||
|
|
.catch(() => undefined);
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
return (
|
||
|
|
<>
|
||
|
|
<RefineSessionHost />
|
||
|
|
<KonamiRegisterGate />
|
||
|
|
<div className="app-bg-dashboard flex min-h-dvh flex-col lg:h-dvh lg:flex-row lg:overflow-hidden">
|
||
|
|
<Sidebar />
|
||
|
|
<MobileNavDrawer
|
||
|
|
open={menuOpen}
|
||
|
|
onClose={() => setMenuOpen(false)}
|
||
|
|
badgeCount={badgeCount}
|
||
|
|
userEmail={userEmail}
|
||
|
|
onLogout={logout}
|
||
|
|
/>
|
||
|
|
|
||
|
|
<main className="flex-1 overflow-y-auto">
|
||
|
|
<div className="app-main-content mx-auto w-full max-w-6xl px-4 py-7 sm:px-7 lg:px-10 lg:py-10">
|
||
|
|
<ThreadsOAuthToast />
|
||
|
|
<LatestToast />
|
||
|
|
{children}
|
||
|
|
</div>
|
||
|
|
</main>
|
||
|
|
|
||
|
|
<ActiveJobsPanel floating />
|
||
|
|
<MobileBottomNav badgeCount={badgeCount} onOpenMenu={() => setMenuOpen(true)} />
|
||
|
|
</div>
|
||
|
|
</>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
export function DashboardShell({ children }: { children: ReactNode }) {
|
||
|
|
return (
|
||
|
|
<CapabilitiesProvider>
|
||
|
|
<JobsProvider>
|
||
|
|
<DashboardChrome>{children}</DashboardChrome>
|
||
|
|
</JobsProvider>
|
||
|
|
</CapabilitiesProvider>
|
||
|
|
);
|
||
|
|
}
|