fix(i18n): wrap CookieConsentRoot with LanguageProvider
The CookieConsentBanner uses useLanguage() hook but was rendered outside of LanguageProvider in RootLayout. Added LanguageProvider wrapper to fix the runtime error.
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import { Download, Upload, Trash2, Loader2, RefreshCw, Sparkles, Database } from 'lucide-react'
|
||||
import { Download, Upload, Trash2, Loader2, RefreshCw, Sparkles, Database, ShieldAlert } from 'lucide-react'
|
||||
import { toast } from 'sonner'
|
||||
import { useLanguage } from '@/lib/i18n'
|
||||
import { useSession } from 'next-auth/react'
|
||||
import { DeleteAccountDialog } from '@/components/legal/delete-account-dialog'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { motion } from 'motion/react'
|
||||
import { cn } from '@/lib/utils'
|
||||
@@ -11,6 +13,8 @@ import { cn } from '@/lib/utils'
|
||||
export default function DataSettingsPage() {
|
||||
const { t } = useLanguage()
|
||||
const router = useRouter()
|
||||
const { data: session } = useSession()
|
||||
const [deleteOpen, setDeleteOpen] = useState(false)
|
||||
const [isExporting, setIsExporting] = useState(false)
|
||||
const [isImporting, setIsImporting] = useState(false)
|
||||
const [isDeleting, setIsDeleting] = useState(false)
|
||||
@@ -246,6 +250,42 @@ export default function DataSettingsPage() {
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-rose-50/50 dark:bg-rose-500/5 rounded-2xl border border-rose-200/50 dark:border-rose-500/20 p-8 mt-6">
|
||||
<div className="flex items-center gap-5 mb-8">
|
||||
<div className="p-3 bg-rose-500/10 rounded-2xl text-rose-600 dark:text-rose-400 border border-rose-500/20">
|
||||
<ShieldAlert size={20} />
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="text-sm font-bold text-rose-600 dark:text-rose-400">{t('account.deleteAccount.sectionTitle')}</h4>
|
||||
<p className="text-[11px] text-concrete mt-0.5">{t('account.deleteAccount.sectionDescription')}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col sm:flex-row items-start sm:items-center justify-between p-6 bg-white/60 dark:bg-black/20 rounded-2xl border border-rose-200/30 dark:border-rose-500/10 gap-4">
|
||||
<div className="space-y-1">
|
||||
<p className="text-[13px] font-bold text-ink">{t('account.deleteAccount.dialogTitle')}</p>
|
||||
<p className="text-[11px] text-concrete">{t('account.deleteAccount.sectionDescription')}</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setDeleteOpen(true)}
|
||||
className="shrink-0 px-6 py-3 rounded-2xl bg-rose-600 text-white text-[10px] font-bold uppercase tracking-[0.2em] shadow-xl shadow-rose-600/20 hover:scale-[1.02] active:scale-95 transition-all duration-300"
|
||||
>
|
||||
<div className="flex items-center justify-center gap-2">
|
||||
<ShieldAlert className="h-4 w-4" />
|
||||
{t('account.deleteAccount.buttonLabel')}
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{session?.user?.email && (
|
||||
<DeleteAccountDialog
|
||||
userEmail={session.user.email}
|
||||
open={deleteOpen}
|
||||
onOpenChange={setDeleteOpen}
|
||||
/>
|
||||
)}
|
||||
</motion.div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,8 +5,9 @@ import { useLanguage } from '@/lib/i18n'
|
||||
import { updateAISettings } from '@/app/actions/ai-settings'
|
||||
import { toast } from 'sonner'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { Globe, Bell } from 'lucide-react'
|
||||
import { Globe, Bell, Shield } from 'lucide-react'
|
||||
import { motion } from 'motion/react'
|
||||
import { openCookiePreferences } from '@/lib/consent/cookie-consent'
|
||||
|
||||
|
||||
interface GeneralSettingsClientProps {
|
||||
@@ -174,6 +175,27 @@ export function GeneralSettingsClient({ initialSettings }: GeneralSettingsClient
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-white/40 dark:bg-white/5 border border-border rounded-xl p-8 space-y-6">
|
||||
<div className="flex items-center gap-5">
|
||||
<div className="p-3 bg-paper dark:bg-white/10 rounded-2xl text-concrete border border-border">
|
||||
<Shield size={18} />
|
||||
</div>
|
||||
<div className="space-y-0.5">
|
||||
<h4 className="text-base font-bold text-ink">{t('consent.preferences.title')}</h4>
|
||||
<p className="text-[11px] text-concrete">{t('consent.preferences.description')}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="pt-2">
|
||||
<button
|
||||
onClick={() => openCookiePreferences()}
|
||||
className="w-full px-5 py-3.5 bg-white dark:bg-white/10 border border-border rounded-xl text-xs font-bold uppercase tracking-[0.25em] text-ink dark:text-paper hover:scale-[1.01] active:scale-95 transition-all duration-300 shadow-sm"
|
||||
>
|
||||
{t('consent.banner.manage')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
)
|
||||
|
||||
@@ -8,6 +8,8 @@ import { ThemeInitializer } from "@/components/theme-initializer";
|
||||
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 { getThemeScript } from "@/lib/theme-script";
|
||||
import { normalizeThemeId } from "@/lib/apply-document-theme";
|
||||
@@ -123,6 +125,9 @@ export default async function RootLayout({
|
||||
<DirectionInitializer />
|
||||
<ThemeInitializer theme={userSettings.theme} fontSize={aiSettings.fontSize} fontFamily={aiSettings.fontFamily} accentColor={userSettings.accentColor} />
|
||||
{children}
|
||||
<LanguageProvider initialLanguage="en">
|
||||
<CookieConsentRoot initialAnonymousAnalytics={aiSettings?.anonymousAnalytics} />
|
||||
</LanguageProvider>
|
||||
<Toaster />
|
||||
</SessionProviderWrapper>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user