refactor(app): scope heavy providers to authenticated route layouts

This commit is contained in:
2026-04-03 19:01:48 +02:00
parent df2a6c1759
commit 234da6f7d7
5 changed files with 125 additions and 56 deletions

31
app/(app)/layout.tsx Normal file
View File

@@ -0,0 +1,31 @@
import * as Sentry from "@sentry/nextjs";
import { InitUser } from "@/components/init-user";
import { AppProviders } from "@/components/providers";
import { getAuthUser, getToken } from "@/lib/auth-server";
export default async function AuthenticatedAppLayout({
children,
}: {
children: React.ReactNode;
}) {
const initialToken = await getToken();
const user = await getAuthUser();
if (user) {
const id = user.userId ?? String(user._id);
Sentry.setUser({
id,
email: user.email ?? undefined,
});
} else {
Sentry.setUser(null);
}
return (
<AppProviders initialToken={initialToken}>
<InitUser />
{children}
</AppProviders>
);
}

View File

@@ -1,6 +1,8 @@
import { AuthView } from "@daveyplate/better-auth-ui";
import { authViewPaths } from "@daveyplate/better-auth-ui/server";
import { AuthViewProviders } from "@/components/providers";
export const dynamicParams = false;
export function generateStaticParams() {
@@ -16,7 +18,9 @@ export default async function AuthPage({
return (
<main className="flex min-h-screen flex-col items-center justify-center p-4">
<AuthViewProviders>
<AuthView path={path} />
</AuthViewProviders>
</main>
);
}

31
app/dashboard/layout.tsx Normal file
View File

@@ -0,0 +1,31 @@
import * as Sentry from "@sentry/nextjs";
import { InitUser } from "@/components/init-user";
import { AppProviders } from "@/components/providers";
import { getAuthUser, getToken } from "@/lib/auth-server";
export default async function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
const initialToken = await getToken();
const user = await getAuthUser();
if (user) {
const id = user.userId ?? String(user._id);
Sentry.setUser({
id,
email: user.email ?? undefined,
});
} else {
Sentry.setUser(null);
}
return (
<AppProviders initialToken={initialToken}>
<InitUser />
{children}
</AppProviders>
);
}

View File

@@ -1,12 +1,9 @@
import type { Metadata } from "next";
import Script from "next/script";
import { Manrope } from "next/font/google";
import * as Sentry from "@sentry/nextjs";
import "./globals.css";
import { cn } from "@/lib/utils";
import { Providers } from "@/components/providers";
import { InitUser } from "@/components/init-user";
import { getAuthUser, getToken } from "@/lib/auth-server";
import { RootProviders } from "@/components/providers";
import { getLocale, getMessages, getTimeZone } from "next-intl/server";
const manrope = Manrope({ subsets: ["latin"], variable: "--font-sans" });
@@ -47,20 +44,9 @@ export default async function RootLayout({
}: Readonly<{
children: React.ReactNode;
}>) {
const initialToken = await getToken();
const locale = await getLocale();
const messages = await getMessages();
const timeZone = await getTimeZone();
const user = await getAuthUser();
if (user) {
const id = user.userId ?? String(user._id);
Sentry.setUser({
id,
email: user.email ?? undefined,
});
} else {
Sentry.setUser(null);
}
return (
<html
@@ -74,15 +60,9 @@ export default async function RootLayout({
data-site-id="bb1ac546eda7"
strategy="afterInteractive"
/>
<Providers
initialToken={initialToken}
locale={locale}
messages={messages}
timeZone={timeZone}
>
<InitUser />
<RootProviders locale={locale} messages={messages} timeZone={timeZone}>
{children}
</Providers>
</RootProviders>
</body>
</html>
);

View File

@@ -34,34 +34,22 @@ function SentryAuthUserSync() {
return null;
}
export function Providers({
children,
initialToken,
locale,
messages,
timeZone,
}: {
type RootProvidersProps = {
children: ReactNode;
initialToken?: string | null;
locale?: string;
messages?: AbstractIntlMessages;
timeZone?: string;
}) {
};
type AppProvidersProps = {
children: ReactNode;
initialToken?: string | null;
};
function AuthUiShell({ children }: { children: ReactNode }) {
const router = useRouter();
return (
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
<NextIntlClientProvider
locale={locale}
messages={messages}
timeZone={timeZone}
>
<ConvexBetterAuthProvider
client={convex}
authClient={authClient}
initialToken={initialToken}
>
<SentryAuthUserSync />
<AuthUIProvider
authClient={authClient}
navigate={router.push}
@@ -70,6 +58,39 @@ export function Providers({
Link={Link}
>
{children}
</AuthUIProvider>
);
}
export function RootProviders({
children,
locale,
messages,
timeZone,
}: RootProvidersProps) {
return (
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
<NextIntlClientProvider
locale={locale}
messages={messages}
timeZone={timeZone}
>
{children}
</NextIntlClientProvider>
</ThemeProvider>
);
}
export function AppProviders({ children, initialToken }: AppProvidersProps) {
return (
<ConvexBetterAuthProvider
client={convex}
authClient={authClient}
initialToken={initialToken}
>
<SentryAuthUserSync />
<AuthUiShell>
{children}
<GooeyToaster
position="bottom-right"
theme="dark"
@@ -77,9 +98,11 @@ export function Providers({
maxQueue={8}
queueOverflow="drop-oldest"
/>
</AuthUIProvider>
</AuthUiShell>
</ConvexBetterAuthProvider>
</NextIntlClientProvider>
</ThemeProvider>
);
}
export function AuthViewProviders({ children }: { children: ReactNode }) {
return <AuthUiShell>{children}</AuthUiShell>;
}