fix: production login error masking, resolve navbar hydration mismatch, and gracefully handle database render errors
All checks were successful
Staging Build / build (push) Successful in 2m15s

This commit is contained in:
DanielS
2026-06-24 10:54:00 +02:00
parent e1f47ddcd0
commit 5c8c198fc5
4 changed files with 96 additions and 41 deletions

View File

@@ -21,6 +21,11 @@ export function NavbarClient({ user, role = "partner" }: NavbarClientProps) {
const [userRole, setUserRole] = useState<string>(role);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const [open, setOpen] = useState(false);
const [pathname, setPathname] = useState("/");
useEffect(() => {
setPathname(window.location.pathname);
}, []);
// Supabase URL & Anon Key auslesen (für Browser-Client)
const supabaseUrl = process.env.SUPABASE_URL || process.env.NEXT_PUBLIC_SUPABASE_URL;
@@ -186,7 +191,7 @@ export function NavbarClient({ user, role = "partner" }: NavbarClientProps) {
</div>
) : (
<Button asChild className="bg-primary hover:bg-primary/95 text-white dark:text-blue-500">
<Link href={`/auth/login?next=${typeof window !== 'undefined' ? window.location.pathname : '/'}`}>Anmelden</Link>
<Link href={`/auth/login?next=${pathname}`}>Anmelden</Link>
</Button>
)}
</nav>
@@ -269,7 +274,7 @@ export function NavbarClient({ user, role = "partner" }: NavbarClientProps) {
</Button>
) : (
<Button asChild className="w-full bg-primary hover:bg-primary/95 text-white dark:text-blue-500" onClick={() => setIsMobileMenuOpen(false)}>
<Link href={`/auth/login?next=${typeof window !== 'undefined' ? window.location.pathname : '/'}`}>Anmelden</Link>
<Link href={`/auth/login?next=${pathname}`}>Anmelden</Link>
</Button>
)}
</div>

View File

@@ -14,7 +14,7 @@ import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { useState, useEffect } from "react";
export function LoginForm({
className,
@@ -24,8 +24,13 @@ export function LoginForm({
const [password, setPassword] = useState("");
const [error, setError] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(false);
const [messageParam, setMessageParam] = useState<string | null>(null);
const router = useRouter();
useEffect(() => {
setMessageParam(new URLSearchParams(window.location.search).get('message'));
}, []);
const handleLogin = async (e: React.FormEvent) => {
e.preventDefault();
setIsLoading(true);
@@ -35,6 +40,10 @@ export function LoginForm({
try {
const res = await signIn(email, password);
if (!res.success) {
setError(res.error || "An error occurred");
return;
}
if (nextParam) {
router.push(nextParam);
} else if (res.role === "admin") {
@@ -90,17 +99,11 @@ export function LoginForm({
onChange={(e) => setPassword(e.target.value)}
/>
</div>
{(() => {
const messageParam = typeof window !== 'undefined' ? new URLSearchParams(window.location.search).get('message') : null;
if (messageParam === "concurrent") {
return (
<p className="text-sm text-amber-500 bg-amber-500/10 border border-amber-500/20 p-3 rounded-lg text-center font-medium">
Sie wurden abgemeldet, da Sie sich an einem anderen Gerät angemeldet haben.
</p>
);
}
return null;
})()}
{messageParam === "concurrent" && (
<p className="text-sm text-amber-500 bg-amber-500/10 border border-amber-500/20 p-3 rounded-lg text-center font-medium">
Sie wurden abgemeldet, da Sie sich an einem anderen Gerät angemeldet haben.
</p>
)}
{error && <p className="text-sm text-red-500">{error}</p>}
<Button type="submit" className="w-full" disabled={isLoading}>
{isLoading ? "Logging in..." : "Login"}