haixunMaster/components/layout/dashboard-shell.tsx

77 lines
2.6 KiB
TypeScript
Raw Permalink Normal View History

2026-06-21 12:50:31 +00:00
"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>
);
}