feat: better navigation in backoffice

This commit is contained in:
Nathnael
2026-08-07 12:24:30 +00:00
parent d5d7c91e24
commit 1e9149ce00
12 changed files with 861 additions and 676 deletions

View File

@@ -1,30 +1,42 @@
import type { ReactNode } from "react";
import { Navigate } from "react-router-dom";
import { Navigate, useLocation } from "react-router-dom";
import { useAuth } from "@/auth/useAuth";
import { resolveLandingPath } from "@/lib/landing";
import { hasPermission } from "@/lib/permissions";
import NoAccessPage from "@/pages/NoAccessPage";
interface RequirePermissionProps {
/** Permission key(s); access is granted if the user has ANY of them. */
permission: string | string[];
/** Where to send users who lack the permission. */
/** Where to send users who lack the permission. Defaults to their landing page. */
redirectTo?: string;
children: ReactNode;
}
/**
* Page-level guard: renders children only when the current user holds one of
* the given permissions, otherwise redirects (default: overview).
* the given permissions, otherwise redirects to a page they can actually reach.
*
* The fallback must not be a fixed path. It used to be `/dashboard/overview`,
* which is itself gated on `overview:view` — a user without that key was sent
* to the page that had just rejected them, and React Router rendered a blank
* frame instead of navigating.
*/
export function RequirePermission({
permission,
redirectTo = "/dashboard/overview",
redirectTo,
children,
}: RequirePermissionProps) {
const { user } = useAuth();
const location = useLocation();
const keys = Array.isArray(permission) ? permission : [permission];
const allowed = keys.some((key) => hasPermission(user, key));
if (!allowed) return <Navigate to={redirectTo} replace />;
return <>{children}</>;
if (allowed) return <>{children}</>;
const target = redirectTo ?? resolveLandingPath(user);
// Belt and braces: never navigate to the page we are already on.
if (target === location.pathname) return <NoAccessPage />;
return <Navigate to={target} replace />;
}