feat(credits): solde IA unique (option M), packs Stripe et polish billing
Un pot de crédits global (BASIC 100 / PRO 1 000 / BUSINESS 4 000) remplace les seaux par fonction côté débit. Packs one-shot S/M/L, admin sans seaux legacy, usage multi-features, hints de coût, anti-flash thème et hydratation admin. Inclut aussi le pipeline slides renforcé et la page publique polishée.
This commit is contained in:
@@ -5,14 +5,17 @@ import { SessionProviderWrapper } from "@/components/session-provider-wrapper";
|
||||
import { getAISettings } from "@/app/actions/ai-settings";
|
||||
import { getUserSettings } from "@/app/actions/user-settings";
|
||||
import { ThemeInitializer } from "@/components/theme-initializer";
|
||||
import { ThemeClassGuard } from "@/components/theme-class-guard";
|
||||
import { DirectionInitializer } from "@/components/direction-initializer";
|
||||
import { ErrorReporter } from "@/components/error-reporter";
|
||||
import { auth } from "@/auth";
|
||||
import { CookieConsentRoot } from "@/components/legal/cookie-consent-root";
|
||||
import { LanguageProvider } from "@/lib/i18n/LanguageProvider";
|
||||
import Script from "next/script";
|
||||
import type { CSSProperties } from "react";
|
||||
import { normalizeThemeId } from "@/lib/apply-document-theme";
|
||||
import { cookies } from "next/headers";
|
||||
import { normalizeThemeId, THEME_COOKIE_NAME } from "@/lib/apply-document-theme";
|
||||
import { THEME_INIT_SCRIPT, DIRECTION_INIT_SCRIPT } from "@/lib/inline-boot-scripts";
|
||||
import { SwCleanup } from "@/components/sw-cleanup";
|
||||
|
||||
import { Inter, Manrope, Playfair_Display, JetBrains_Mono } from "next/font/google";
|
||||
|
||||
@@ -76,14 +79,20 @@ export default async function RootLayout({
|
||||
const session = await auth();
|
||||
const userId = session?.user?.id;
|
||||
|
||||
const [aiSettings, userSettings] = await Promise.all([
|
||||
const [aiSettings, userSettings, cookieStore] = await Promise.all([
|
||||
getAISettings(userId),
|
||||
getUserSettings(userId),
|
||||
cookies(),
|
||||
])
|
||||
|
||||
const htmlTheme = serverHtmlThemeState(userSettings.theme)
|
||||
// Cookie = préférence immédiate (bascule barre latérale) ; base = profil utilisateur.
|
||||
// Sans cookie, un dark seulement en localStorage était écrasé par le serveur → flash clair.
|
||||
const cookieTheme = cookieStore.get(THEME_COOKIE_NAME)?.value
|
||||
const resolvedTheme = normalizeThemeId(cookieTheme || userSettings.theme || 'light')
|
||||
|
||||
const htmlTheme = serverHtmlThemeState(resolvedTheme)
|
||||
const serverAccent = userSettings.accentColor ?? '#A47148'
|
||||
const serverTheme = normalizeThemeId(userSettings.theme || 'light')
|
||||
const serverTheme = resolvedTheme
|
||||
const htmlStyle = {
|
||||
'--color-brand-accent': serverAccent,
|
||||
} as CSSProperties
|
||||
@@ -97,14 +106,18 @@ export default async function RootLayout({
|
||||
data-server-accent={serverAccent}
|
||||
style={htmlStyle}
|
||||
>
|
||||
<body className={`${inter.className} ${inter.variable} ${manrope.variable} ${playfair.variable} ${jetbrainsMono.variable} h-screen overflow-hidden`}>
|
||||
<Script id="theme-init" src="/scripts/theme-init.js" strategy="beforeInteractive" />
|
||||
<Script id="direction-init" src="/scripts/direction-init.js" strategy="beforeInteractive" />
|
||||
<Script id="sw-cleanup" src="/scripts/sw-cleanup.js" strategy="afterInteractive" />
|
||||
<head>
|
||||
{/* Scripts boot inline : anti-flash thème/RTL, sans next/script (React 19). */}
|
||||
<script id="theme-init" dangerouslySetInnerHTML={{ __html: THEME_INIT_SCRIPT }} />
|
||||
<script id="direction-init" dangerouslySetInnerHTML={{ __html: DIRECTION_INIT_SCRIPT }} />
|
||||
</head>
|
||||
<body className={`${inter.className} ${inter.variable} ${manrope.variable} ${playfair.variable} ${jetbrainsMono.variable} h-screen overflow-hidden bg-background text-foreground`}>
|
||||
<SessionProviderWrapper>
|
||||
<SwCleanup />
|
||||
<ErrorReporter />
|
||||
<DirectionInitializer />
|
||||
<ThemeInitializer theme={userSettings.theme} fontSize={aiSettings.fontSize} fontFamily={aiSettings.fontFamily} accentColor={userSettings.accentColor} />
|
||||
<ThemeInitializer theme={resolvedTheme} fontSize={aiSettings.fontSize} fontFamily={aiSettings.fontFamily} accentColor={userSettings.accentColor} />
|
||||
<ThemeClassGuard />
|
||||
{children}
|
||||
<LanguageProvider initialLanguage="en">
|
||||
<CookieConsentRoot />
|
||||
|
||||
Reference in New Issue
Block a user