From 6776bdfe73cbcce137eb062b26d114e4df5f7086 Mon Sep 17 00:00:00 2001 From: Nick Szaunig Date: Wed, 26 Aug 2026 23:21:06 +0200 Subject: [PATCH] fix: Root und 404 leiten unangemeldete User direkt zu /login Bisher gingen "/" und unbekannte URLs immer erst zu /dashboard, das dann bei fehlendem Login zu /login weiterleitete - unnoetiger Umweg. Beide pruefen jetzt selbst den Auth-Status (gleiches Muster wie (app)/layout.tsx: waehrend isLoading nichts tun, danach je nach User direkt zu /dashboard oder /login). --- ApiCore-Frontend/src/app/not-found.spec.tsx | 37 +++++++++++++++++++++ ApiCore-Frontend/src/app/not-found.tsx | 18 ++++++++-- ApiCore-Frontend/src/app/page.spec.tsx | 35 +++++++++++++++---- ApiCore-Frontend/src/app/page.tsx | 18 ++++++++-- 4 files changed, 98 insertions(+), 10 deletions(-) create mode 100644 ApiCore-Frontend/src/app/not-found.spec.tsx diff --git a/ApiCore-Frontend/src/app/not-found.spec.tsx b/ApiCore-Frontend/src/app/not-found.spec.tsx new file mode 100644 index 0000000..1a90a06 --- /dev/null +++ b/ApiCore-Frontend/src/app/not-found.spec.tsx @@ -0,0 +1,37 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { render } from "@testing-library/react"; +import NotFound from "./not-found"; + +const replaceMock = vi.fn(); +vi.mock("next/navigation", () => ({ + useRouter: () => ({ replace: replaceMock }), +})); + +let mockAuth: { user: { id: string } | null; isLoading: boolean }; +vi.mock("@/lib/auth/auth-context", () => ({ + useAuth: () => mockAuth, +})); + +describe("NotFound page", () => { + beforeEach(() => { + replaceMock.mockReset(); + }); + + it("does not redirect while the auth check is still loading", () => { + mockAuth = { user: null, isLoading: true }; + render(); + expect(replaceMock).not.toHaveBeenCalled(); + }); + + it("redirects to the dashboard when logged in", () => { + mockAuth = { user: { id: "user-1" }, isLoading: false }; + render(); + expect(replaceMock).toHaveBeenCalledWith("/dashboard"); + }); + + it("redirects to login when not logged in", () => { + mockAuth = { user: null, isLoading: false }; + render(); + expect(replaceMock).toHaveBeenCalledWith("/login"); + }); +}); diff --git a/ApiCore-Frontend/src/app/not-found.tsx b/ApiCore-Frontend/src/app/not-found.tsx index aab4065..04d077f 100644 --- a/ApiCore-Frontend/src/app/not-found.tsx +++ b/ApiCore-Frontend/src/app/not-found.tsx @@ -1,5 +1,19 @@ -import { redirect } from "next/navigation"; +"use client"; + +import { useEffect } from "react"; +import { useRouter } from "next/navigation"; +import { useAuth } from "@/lib/auth/auth-context"; export default function NotFound() { - redirect("/dashboard"); + const router = useRouter(); + const { user, isLoading } = useAuth(); + + useEffect(() => { + if (isLoading) { + return; + } + router.replace(user ? "/dashboard" : "/login"); + }, [isLoading, user, router]); + + return null; } diff --git a/ApiCore-Frontend/src/app/page.spec.tsx b/ApiCore-Frontend/src/app/page.spec.tsx index 123e849..dfdb959 100644 --- a/ApiCore-Frontend/src/app/page.spec.tsx +++ b/ApiCore-Frontend/src/app/page.spec.tsx @@ -1,14 +1,37 @@ -import { describe, expect, it, vi } from "vitest"; -import { redirect } from "next/navigation"; +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { render } from "@testing-library/react"; import Page from "./page"; +const replaceMock = vi.fn(); vi.mock("next/navigation", () => ({ - redirect: vi.fn(), + useRouter: () => ({ replace: replaceMock }), +})); + +let mockAuth: { user: { id: string } | null; isLoading: boolean }; +vi.mock("@/lib/auth/auth-context", () => ({ + useAuth: () => mockAuth, })); describe("Home page", () => { - it("redirects to the dashboard", () => { - Page(); - expect(redirect).toHaveBeenCalledWith("/dashboard"); + beforeEach(() => { + replaceMock.mockReset(); + }); + + it("does not redirect while the auth check is still loading", () => { + mockAuth = { user: null, isLoading: true }; + render(); + expect(replaceMock).not.toHaveBeenCalled(); + }); + + it("redirects to the dashboard when logged in", () => { + mockAuth = { user: { id: "user-1" }, isLoading: false }; + render(); + expect(replaceMock).toHaveBeenCalledWith("/dashboard"); + }); + + it("redirects to login when not logged in", () => { + mockAuth = { user: null, isLoading: false }; + render(); + expect(replaceMock).toHaveBeenCalledWith("/login"); }); }); diff --git a/ApiCore-Frontend/src/app/page.tsx b/ApiCore-Frontend/src/app/page.tsx index a74cb27..0a91e0f 100644 --- a/ApiCore-Frontend/src/app/page.tsx +++ b/ApiCore-Frontend/src/app/page.tsx @@ -1,5 +1,19 @@ -import { redirect } from "next/navigation"; +"use client"; + +import { useEffect } from "react"; +import { useRouter } from "next/navigation"; +import { useAuth } from "@/lib/auth/auth-context"; export default function Home() { - redirect("/dashboard"); + const router = useRouter(); + const { user, isLoading } = useAuth(); + + useEffect(() => { + if (isLoading) { + return; + } + router.replace(user ? "/dashboard" : "/login"); + }, [isLoading, user, router]); + + return null; }