mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-07 22:25:42 +00:00
feat: better navigation in backoffice
This commit is contained in:
57
apps/edr-freight-web/backoffice/src/lib/landing.test.ts
Normal file
57
apps/edr-freight-web/backoffice/src/lib/landing.test.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import type { AuthUser } from "@/auth/types";
|
||||
import { FREIGHT_PERMS } from "./permissions";
|
||||
import { NO_ACCESS_PATH, resolveLandingPath } from "./landing";
|
||||
|
||||
const withPermissions = (...keys: string[]): AuthUser => ({
|
||||
permissionKeys: keys,
|
||||
});
|
||||
|
||||
const withRole = (roleKey: string): AuthUser => ({ roles: [{ key: roleKey }] });
|
||||
|
||||
describe("resolveLandingPath", () => {
|
||||
it("keeps normal staff on the overview", () => {
|
||||
expect(resolveLandingPath(withPermissions(FREIGHT_PERMS.overview.view))).toBe(
|
||||
"/dashboard/overview",
|
||||
);
|
||||
});
|
||||
|
||||
it("sends super admins to the overview (they pass every check)", () => {
|
||||
expect(resolveLandingPath(withRole("super_admin"))).toBe(
|
||||
"/dashboard/overview",
|
||||
);
|
||||
});
|
||||
|
||||
it("sends IAM-only admins to the user-management dashboard", () => {
|
||||
// A pure unit_admin holds `can:*` IAM keys and no edr_freight_app:* key, so
|
||||
// the freight sidebar filters down to nothing. Landing them on the overview
|
||||
// is what produced the blank page.
|
||||
for (const role of ["unit_admin", "admin", "organization_admin"]) {
|
||||
expect(resolveLandingPath(withRole(role))).toBe(
|
||||
"/user-management/user_management-dashboard",
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("lands staff without overview:view on a page they can see", () => {
|
||||
const target = resolveLandingPath(
|
||||
withPermissions(FREIGHT_PERMS.warehouses.view),
|
||||
);
|
||||
expect(target).not.toBe("/dashboard/overview");
|
||||
expect(target.startsWith("/dashboard/")).toBe(true);
|
||||
});
|
||||
|
||||
it("never returns /user-management for a freight-only staff key", () => {
|
||||
// The Staff sidebar item points at /user-management, which redirects by
|
||||
// ROLE — returning it here would ping-pong for a user with no IAM role.
|
||||
expect(resolveLandingPath(withPermissions(FREIGHT_PERMS.staff.roles.view))).toBe(
|
||||
NO_ACCESS_PATH,
|
||||
);
|
||||
});
|
||||
|
||||
it("falls back to the no-access page when nothing is granted", () => {
|
||||
expect(resolveLandingPath({})).toBe(NO_ACCESS_PATH);
|
||||
expect(resolveLandingPath(null)).toBe(NO_ACCESS_PATH);
|
||||
});
|
||||
});
|
||||
51
apps/edr-freight-web/backoffice/src/lib/landing.ts
Normal file
51
apps/edr-freight-web/backoffice/src/lib/landing.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import {
|
||||
buildSidebarSections,
|
||||
filterSidebarByPermission,
|
||||
flattenSidebarItems,
|
||||
} from "@/components/layout/sidebar-sections";
|
||||
|
||||
import type { AuthUser } from "@/auth/types";
|
||||
|
||||
import { isSuperAdmin } from "./permissions";
|
||||
|
||||
/**
|
||||
* IAM roles that grant the user-management subtree but no freight permissions.
|
||||
* Mirrors the `allowedRoles` on the org-admin route group in
|
||||
* `user-management/route.tsx` — a role outside this list is bounced by its
|
||||
* PrivateRoute, so landing anyone else there would just bounce again.
|
||||
*/
|
||||
const IAM_ADMIN_ROLES = ["admin", "organization_admin", "unit_admin"];
|
||||
|
||||
/** Terminal page for accounts with nothing granted. Never permission-gated. */
|
||||
export const NO_ACCESS_PATH = "/no-access";
|
||||
|
||||
/**
|
||||
* The first route a user can actually reach.
|
||||
*
|
||||
* Every redirect in the app funnels through here instead of hardcoding
|
||||
* `/dashboard/overview`: that page is itself gated on `overview:view`, so
|
||||
* sending a user who lacks the key there redirects them to the page that just
|
||||
* rejected them — React Router renders nothing and the user sees a blank frame.
|
||||
* A pure `unit_admin` holds only `can:*` IAM keys and no `edr_freight_app:*`
|
||||
* key at all, so this hit them on every login.
|
||||
*/
|
||||
export function resolveLandingPath(user: AuthUser | null | undefined): string {
|
||||
const visible = filterSidebarByPermission(buildSidebarSections([]), user);
|
||||
|
||||
// Only /dashboard/* items are safe landings. The "Staff" item points at
|
||||
// /user-management, which re-redirects by ROLE — a freight user holding
|
||||
// staff:* keys but no IAM role would ping-pong between the two.
|
||||
const firstFreightPage = flattenSidebarItems(visible).find((item) =>
|
||||
item.href.startsWith("/dashboard/"),
|
||||
)?.href;
|
||||
if (firstFreightPage) return firstFreightPage;
|
||||
|
||||
if (isSuperAdmin(user)) return "/user-management/dashboard";
|
||||
|
||||
const roleKeys = (user?.roles ?? []).map((role) => role.key ?? "");
|
||||
if (roleKeys.some((key) => IAM_ADMIN_ROLES.includes(key))) {
|
||||
return "/user-management/user_management-dashboard";
|
||||
}
|
||||
|
||||
return NO_ACCESS_PATH;
|
||||
}
|
||||
Reference in New Issue
Block a user