diff --git a/.env.example b/.env.example index 60d1df2..5c1ed4b 100644 --- a/.env.example +++ b/.env.example @@ -20,3 +20,11 @@ NEXTAUTH_SECRET= # Redirect URI instellen op: https://slaap.jouwdomein.be/api/auth/callback/discord DISCORD_CLIENT_ID= DISCORD_CLIENT_SECRET= + +# --- Discord server restrictie (optioneel) --- +# Vul in om login te beperken tot leden van jouw Discord server. +# Leeg laten = iedereen met een Discord account kan inloggen. +# +# Server ID vinden: Discord → rechtsklik op je server → "Server-ID kopiëren" +# (Zet Ontwikkelaarsmodus aan via Instellingen → Geavanceerd) +DISCORD_GUILD_ID= diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 5bbc62a..c0eac89 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -54,6 +54,9 @@ model User { email String? @unique emailVerified DateTime? image String? + // Credentials login (optioneel — Discord users hebben dit niet) + username String? @unique + password String? accounts Account[] sessions Session[] sleepEntries SleepEntry[] diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx index 9a513db..ea08ca9 100644 --- a/src/app/login/page.tsx +++ b/src/app/login/page.tsx @@ -1,20 +1,31 @@ "use client"; import { signIn, useSession } from "next-auth/react"; -import { useRouter } from "next/navigation"; -import { useState, useEffect } from "react"; +import { useRouter, useSearchParams } from "next/navigation"; +import { useState, useEffect, Suspense } from "react"; import Link from "next/link"; -export default function LoginPage() { - const { data: session, status } = useSession(); +const DISCORD_ERRORS: Record = { + not_in_server: "Je moet lid zijn van onze Discord server om in te loggen.", + OAuthAccountNotLinked: "Dit e-mailadres is al gekoppeld aan een ander account.", + default: "Inloggen mislukt, probeer opnieuw.", +}; + +function LoginForm() { + const { status } = useSession(); const router = useRouter(); + const params = useSearchParams(); const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); const [error, setError] = useState(""); const [loading, setLoading] = useState(false); - // Al ingelogd → meteen door naar klassement + // Foutmelding uit URL (bv. ?error=not_in_server) + const urlError = params.get("error"); + const oauthError = urlError ? (DISCORD_ERRORS[urlError] ?? DISCORD_ERRORS.default) : null; + + // Al ingelogd → meteen door useEffect(() => { if (status === "authenticated") router.replace("/"); }, [status, router]); @@ -30,11 +41,7 @@ export default function LoginPage() { async function handleCredentials() { setError(""); setLoading(true); - const res = await signIn("credentials", { - username, - password, - redirect: false, - }); + const res = await signIn("credentials", { username, password, redirect: false }); setLoading(false); if (res?.error) { setError("Gebruikersnaam of wachtwoord klopt niet."); @@ -54,12 +61,19 @@ export default function LoginPage() {

Log je slaap, win het klassement.

+ {/* OAuth fout (bv. niet lid van server) */} + {oauthError && ( +
+ ⚠️ {oauthError} +
+ )} + {/* Discord */}