.md-filene er oppdatert: sesjons-bugen er markert ✅ fikset, og ADR-021 (passord/2FA) er notert som naturlig neste steg i den tråden når du vil sette i gang — jeg venter på ditt klarsignal før jeg begynner å bygge det.
59 lines
2.4 KiB
TypeScript
59 lines
2.4 KiB
TypeScript
import { cookies } from "next/headers"
|
|
import { redirect } from "next/navigation"
|
|
import { LoginForm } from "@/components/login-form"
|
|
import { Wordmark } from "@/components/wordmark"
|
|
|
|
// Server-side, IKKE nettleser-fetch -- går derfor IKKE gjennom
|
|
// next.config.mjs sin rewrites() (samme mønster som generateMetadata i
|
|
// app/t/[id]/page.tsx). Peker direkte på API-et.
|
|
const API_ORIGIN = process.env.TEECUP_API_ORIGIN || "http://localhost:8000"
|
|
// Må matche SESSION_COOKIE_NAME i app/auth.py -- ingen delt konstant på
|
|
// tvers av Python/TypeScript, samme mønster som andre API-kontrakt-felt
|
|
// som dupliseres bevisst i frontend-koden.
|
|
const SESSION_COOKIE_NAME = "teecup_session"
|
|
|
|
export default async function Page() {
|
|
// Reell bug funnet 2026-07-19: denne siden viste ALLTID innloggingsskjemaet,
|
|
// uansett om brukeren allerede hadde en helt gyldig sesjonscookie (30 dager,
|
|
// bekreftet riktig satt) -- Dashboard sjekker /auth/me og sender deg HIT ved
|
|
// manglende sesjon, men ingenting gjorde det motsatte. En bruker som besøkte
|
|
// teecup.teeoff.no direkte (i stedet for å navigere til /dashboard) så derfor
|
|
// alltid innloggingsskjemaet og ba unødvendig om en ny magic-link hver gang.
|
|
const cookieStore = await cookies()
|
|
const session = cookieStore.get(SESSION_COOKIE_NAME)
|
|
let authenticated = false
|
|
if (session) {
|
|
try {
|
|
const res = await fetch(`${API_ORIGIN}/auth/me`, {
|
|
headers: { Cookie: `${SESSION_COOKIE_NAME}=${session.value}` },
|
|
cache: "no-store",
|
|
})
|
|
authenticated = res.ok
|
|
} catch {
|
|
// API utilgjengelig -- vis innloggingsskjemaet i stedet for å henge.
|
|
authenticated = false
|
|
}
|
|
}
|
|
if (authenticated) {
|
|
redirect("/dashboard")
|
|
}
|
|
|
|
return (
|
|
<main className="flex min-h-[100dvh] flex-col items-center justify-center bg-background px-5 py-10">
|
|
<div className="flex w-full max-w-sm flex-col gap-8">
|
|
<header className="flex flex-col items-center gap-3 text-center">
|
|
<Wordmark />
|
|
<p className="text-balance text-base leading-relaxed text-muted-foreground">
|
|
Logg inn for å følge turneringen din live.
|
|
</p>
|
|
</header>
|
|
|
|
<LoginForm />
|
|
|
|
<p className="text-center text-xs leading-relaxed text-muted-foreground text-pretty">
|
|
Ved å logge inn godtar du våre vilkår og personvernregler.
|
|
</p>
|
|
</div>
|
|
</main>
|
|
)
|
|
}
|