diff --git a/dev-output.txt b/dev-output.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/app/[locale]/dashboard/page.tsx b/src/app/[locale]/dashboard/page.tsx index cc07ae5..f8b7e79 100644 --- a/src/app/[locale]/dashboard/page.tsx +++ b/src/app/[locale]/dashboard/page.tsx @@ -1,6 +1,12 @@ +import { connection } from 'next/server'; import { setRequestLocale } from 'next-intl/server'; import type { Metadata } from 'next'; +import { redirect } from 'next/navigation'; import DashboardContent from '@/components/auth/DashboardContent'; +import { createClient } from '@/lib/supabase/server'; + +// Force dynamic rendering to ensure auth checks run on every request +export const dynamic = 'force-dynamic'; type Props = { params: Promise<{ locale: string }>; @@ -29,8 +35,19 @@ export async function generateMetadata({ params }: Props): Promise { } export default async function DashboardPage({ params }: Props) { + // CRITICAL: Use connection() API to guarantee dynamic rendering in Next.js 15 + await connection(); + const { locale } = await params; setRequestLocale(locale); + // Server-side auth check (defense-in-depth) + const supabase = await createClient(); + const { data: { user } } = await supabase.auth.getUser(); + + if (!user) { + redirect(`/${locale}/login`); + } + return ; } diff --git a/src/components/auth/DashboardContent.tsx b/src/components/auth/DashboardContent.tsx index 9f5dc81..98c1387 100644 --- a/src/components/auth/DashboardContent.tsx +++ b/src/components/auth/DashboardContent.tsx @@ -1,11 +1,9 @@ 'use client'; -import { useEffect, useState } from 'react'; import { useRouter } from 'next/navigation'; -import { Loader2, BarChart2, Users, Eye, Clock, TrendingUp, TrendingDown, LogOut } from 'lucide-react'; +import { BarChart2, Users, Eye, Clock, TrendingUp, TrendingDown, LogOut } from 'lucide-react'; import { useTranslations, useLocale } from 'next-intl'; import { createClient } from '@/lib/supabase/client'; -import type { User } from '@supabase/supabase-js'; interface MetricCard { title: string; @@ -20,6 +18,8 @@ export default function DashboardContent() { const t = useTranslations('dashboard'); const locale = useLocale(); const router = useRouter(); +<<<<<<< HEAD +======= const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); @@ -34,6 +34,7 @@ export default function DashboardContent() { fetchUser(); }, []); +>>>>>>> origin/master const handleLogout = async () => { const supabase = createClient(); @@ -41,25 +42,6 @@ export default function DashboardContent() { router.push(`/${locale}`); }; - if (loading) { - return ( -
-
- -

{t('status.loading')}

-
-
- ); - } - - if (!user) { - return ( -
-

{t('status.notAuthenticated')}

-
- ); - } - const metrics: MetricCard[] = [ { title: t('metrics.pageViews.title'), diff --git a/src/lib/supabase/middleware.ts b/src/lib/supabase/middleware.ts index 5fb7f76..1bd5044 100644 --- a/src/lib/supabase/middleware.ts +++ b/src/lib/supabase/middleware.ts @@ -1,6 +1,10 @@ import { createServerClient } from '@supabase/ssr'; import { NextRequest, NextResponse } from 'next/server'; +<<<<<<< HEAD +export function createClient(request: NextRequest, response: NextResponse) { + return createServerClient( +======= export async function createClient(request: NextRequest) { let response = NextResponse.next({ request: { @@ -9,6 +13,7 @@ export async function createClient(request: NextRequest) { }); const supabase = createServerClient( +>>>>>>> origin/master process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, { @@ -17,6 +22,15 @@ export async function createClient(request: NextRequest) { return request.cookies.getAll(); }, setAll(cookiesToSet) { +<<<<<<< HEAD + try { + cookiesToSet.forEach(({ name, value, options }) => { + response.cookies.set(name, value, options); + }); + } catch { + // Handle middleware context + } +======= cookiesToSet.forEach(({ name, value, options }) => request.cookies.set(name, value) ); @@ -28,10 +42,14 @@ export async function createClient(request: NextRequest) { cookiesToSet.forEach(({ name, value, options }) => response.cookies.set(name, value, options) ); +>>>>>>> origin/master }, }, } ); +<<<<<<< HEAD +======= return { supabase, response }; +>>>>>>> origin/master }