feat: Unbekannte und nicht erlaubte Seiten leiten zum Dashboard um
- src/app/not-found.tsx: jede nicht existierende Route landet auf /dashboard statt der Next.js-Standard-404-Seite (der bestehende Auth-Guard in (app)/layout.tsx schickt nicht angemeldete User von dort automatisch weiter zu /login). - settings/layout.tsx: fehlt die Berechtigung fuer den Einstellungen-Bereich, wird jetzt zu /dashboard umgeleitet statt nur einen Hinweistext anzuzeigen (gleiches Redirect-Muster wie der bestehende Login-Guard). Login-nach-Anmeldung-Redirect zu /dashboard und der Auth-Gate in (app)/layout.tsx bestanden bereits.
This commit is contained in:
1 parent
9de123ab32
commit
b3157484c4
3 files changed
+61
-8
No files matched your search
@@ -0,0 +1,46 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import SettingsLayout from "./layout";
|
||||
|
||||
const replaceMock = vi.fn();
|
||||
vi.mock("next/navigation", () => ({
|
||||
useRouter: () => ({ replace: replaceMock }),
|
||||
}));
|
||||
|
||||
let mockUser: { permissions: string[] } | null = null;
|
||||
vi.mock("@/lib/auth/auth-context", () => ({
|
||||
useAuth: () => ({ user: mockUser }),
|
||||
}));
|
||||
|
||||
describe("SettingsLayout", () => {
|
||||
beforeEach(() => {
|
||||
replaceMock.mockReset();
|
||||
mockUser = null;
|
||||
});
|
||||
|
||||
it("renders children when the user has a settings-area permission", () => {
|
||||
mockUser = { permissions: ["users:read"] };
|
||||
|
||||
render(
|
||||
<SettingsLayout>
|
||||
<p>Einstellungen-Inhalt</p>
|
||||
</SettingsLayout>,
|
||||
);
|
||||
|
||||
expect(screen.getByText("Einstellungen-Inhalt")).toBeInTheDocument();
|
||||
expect(replaceMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("redirects to the dashboard when the user lacks every settings-area permission", () => {
|
||||
mockUser = { permissions: ["colonies:read"] };
|
||||
|
||||
render(
|
||||
<SettingsLayout>
|
||||
<p>Einstellungen-Inhalt</p>
|
||||
</SettingsLayout>,
|
||||
);
|
||||
|
||||
expect(screen.queryByText("Einstellungen-Inhalt")).not.toBeInTheDocument();
|
||||
expect(replaceMock).toHaveBeenCalledWith("/dashboard");
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { ReactNode } from "react";
|
||||
import { ReactNode, useEffect } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useAuth } from "@/lib/auth/auth-context";
|
||||
|
||||
const SETTINGS_AREA_PERMISSIONS = [
|
||||
@@ -14,19 +15,20 @@ const SETTINGS_AREA_PERMISSIONS = [
|
||||
];
|
||||
|
||||
export default function SettingsLayout({ children }: { children: ReactNode }) {
|
||||
const router = useRouter();
|
||||
const { user } = useAuth();
|
||||
const hasSettingsAccess = SETTINGS_AREA_PERMISSIONS.some((permission) =>
|
||||
user?.permissions.includes(permission),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasSettingsAccess) {
|
||||
return (
|
||||
<main className="p-6">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Diese Seite ist nur für Administratoren verfügbar.
|
||||
</p>
|
||||
</main>
|
||||
);
|
||||
router.replace("/dashboard");
|
||||
}
|
||||
}, [hasSettingsAccess, router]);
|
||||
|
||||
if (!hasSettingsAccess) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <>{children}</>;
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export default function NotFound() {
|
||||
redirect("/dashboard");
|
||||
}
|
||||
Reference in new issue
Block a user