openreader/src/app/(app)/layout.tsx
Richard R 925c995274 refactor(config): centralize provider default resolution and simplify user preference inheritance
Move provider normalization logic into a dedicated module to ensure consistent
handling of provider defaults and user preference inheritance across client and
server. Update layout components to mount ConfigProvider only at the shared
layout level, preventing unnecessary remounts and hydration issues during
navigation. Adjust app config defaults so user provider settings are empty by
default, always inheriting the admin-configured provider unless explicitly set.
Add tests for normalization and sync logic to ensure robust provider resolution.
2026-06-06 15:25:10 -06:00

70 lines
2.1 KiB
TypeScript

import type { Metadata } from 'next';
import type { ReactNode } from 'react';
import { Toaster } from 'react-hot-toast';
import { Providers } from '@/app/providers';
import { ConfigProvider } from '@/contexts/ConfigContext';
import { AppMain, AppShell } from '@/components/layout';
import { getAuthBaseUrl, isAnonymousAuthSessionsEnabled, isGithubAuthEnabled } from '@/lib/server/auth/config';
export const dynamic = 'force-dynamic';
export const metadata: Metadata = {
robots: {
index: false,
follow: false,
googleBot: {
index: false,
follow: false,
noimageindex: true,
'max-snippet': 0,
'max-video-preview': 0,
},
},
};
export default function AppLayout({ children }: { children: ReactNode }) {
const authBaseUrl = getAuthBaseUrl();
const allowAnonymousAuthSessions = isAnonymousAuthSessionsEnabled();
const githubAuthEnabled = isGithubAuthEnabled();
return (
<Providers
authBaseUrl={authBaseUrl}
allowAnonymousAuthSessions={allowAnonymousAuthSessions}
githubAuthEnabled={githubAuthEnabled}
>
{/* ConfigProvider lives here, in the shared (app) layout, so it stays
mounted across library <-> reader navigation. Mounting it per-route
re-ran the Dexie/server hydration race on every navigation, causing
the reader to briefly use the admin-default provider until a full
page refresh. A single shared instance keeps the user's saved
provider hydrated the whole time. */}
<ConfigProvider>
<AppShell>
<AppMain>{children}</AppMain>
</AppShell>
</ConfigProvider>
<Toaster
toastOptions={{
style: {
background: 'var(--offbase)',
color: 'var(--foreground)',
},
success: {
iconTheme: {
primary: 'var(--accent)',
secondary: 'var(--background)',
},
},
error: {
iconTheme: {
primary: 'var(--accent)',
secondary: 'var(--background)',
},
},
}}
/>
</Providers>
);
}