Updates
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
import { featureFlags } from '$lib/features';
|
||||
import { hasModuleAccess, hasPermission, type AppSession } from '$lib/session';
|
||||
|
||||
export type WorkspaceRole = 'admin' | 'operations' | 'full' | 'client' | 'unknown';
|
||||
|
||||
type RouteAccessRule = {
|
||||
path: string;
|
||||
roles: WorkspaceRole[];
|
||||
matches: (pathname: string) => boolean;
|
||||
};
|
||||
|
||||
function hasPathPrefix(pathname: string, prefix: string) {
|
||||
return pathname === prefix || pathname.startsWith(`${prefix}/`);
|
||||
}
|
||||
|
||||
function canAccessWorkspaceArea(
|
||||
session: AppSession | null | undefined,
|
||||
moduleKey: string,
|
||||
permissionKeys: string[],
|
||||
minimumLevel: 'view' | 'edit' | 'manage' = 'view'
|
||||
) {
|
||||
if (!session) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (session.role === 'internal') {
|
||||
return permissionKeys.some((permissionKey) => hasPermission(session, permissionKey));
|
||||
}
|
||||
|
||||
return hasModuleAccess(session, moduleKey, minimumLevel);
|
||||
}
|
||||
|
||||
export function getWorkspaceRole(session: AppSession | null | undefined): WorkspaceRole {
|
||||
if (!session) {
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
if (session.role === 'admin') {
|
||||
return 'admin';
|
||||
}
|
||||
|
||||
if (session.role !== 'internal') {
|
||||
return 'client';
|
||||
}
|
||||
|
||||
if (session.role_name === 'Admin') {
|
||||
return 'admin';
|
||||
}
|
||||
|
||||
if (session.role_name === 'Operations') {
|
||||
return 'operations';
|
||||
}
|
||||
|
||||
if (session.role_name === 'Full Access') {
|
||||
return 'full';
|
||||
}
|
||||
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
export function canOpenDashboard(session: AppSession | null | undefined) {
|
||||
return canAccessWorkspaceArea(session, 'dashboard', ['view_dashboard']);
|
||||
}
|
||||
|
||||
export function canOpenRawMaterials(session: AppSession | null | undefined) {
|
||||
return canAccessWorkspaceArea(session, 'raw_materials', ['view_raw_materials', 'edit_raw_materials']);
|
||||
}
|
||||
|
||||
export function canOpenMixMaster(session: AppSession | null | undefined) {
|
||||
return canAccessWorkspaceArea(session, 'mix_master', ['view_mixes', 'edit_mixes']);
|
||||
}
|
||||
|
||||
export function canCreateMixWorksheet(session: AppSession | null | undefined) {
|
||||
return canAccessWorkspaceArea(session, 'mix_master', ['edit_mixes'], 'edit');
|
||||
}
|
||||
|
||||
export function canOpenMixCalculator(session: AppSession | null | undefined) {
|
||||
return canAccessWorkspaceArea(session, 'mix_calculator', ['view_mix_calculator', 'use_mix_calculator']);
|
||||
}
|
||||
|
||||
export function canCreateMixSession(session: AppSession | null | undefined) {
|
||||
return canAccessWorkspaceArea(session, 'mix_calculator', ['use_mix_calculator', 'save_mix_calculator_session'], 'edit');
|
||||
}
|
||||
|
||||
export function canOpenProducts(session: AppSession | null | undefined) {
|
||||
return canAccessWorkspaceArea(session, 'products', ['view_products', 'edit_products']);
|
||||
}
|
||||
|
||||
export function canOpenScenarios(session: AppSession | null | undefined) {
|
||||
return !!session && hasModuleAccess(session, 'scenarios');
|
||||
}
|
||||
|
||||
export function canOpenReporting(session: AppSession | null | undefined) {
|
||||
return canOpenProducts(session);
|
||||
}
|
||||
|
||||
export function canOpenSettings(session: AppSession | null | undefined) {
|
||||
if (!session) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return session.role === 'internal'
|
||||
? hasPermission(session, 'view_settings') || hasPermission(session, 'edit_settings')
|
||||
: true;
|
||||
}
|
||||
|
||||
export function canOpenClientAccess(session: AppSession | null | undefined) {
|
||||
return !!session && hasModuleAccess(session, 'client_access', 'manage');
|
||||
}
|
||||
|
||||
export const routeAccessRules: RouteAccessRule[] = [
|
||||
{ path: '/', roles: ['admin', 'full', 'client'], matches: (pathname) => pathname === '/' },
|
||||
{
|
||||
path: '/mix-calculator',
|
||||
roles: ['admin', 'operations', 'full', 'client'],
|
||||
matches: (pathname) => hasPathPrefix(pathname, '/mix-calculator')
|
||||
},
|
||||
{
|
||||
path: '/raw-materials',
|
||||
roles: ['admin', 'full', 'client'],
|
||||
matches: (pathname) => hasPathPrefix(pathname, '/raw-materials')
|
||||
},
|
||||
{ path: '/mixes', roles: ['admin', 'full', 'client'], matches: (pathname) => hasPathPrefix(pathname, '/mixes') },
|
||||
{ path: '/products', roles: ['admin', 'full', 'client'], matches: (pathname) => hasPathPrefix(pathname, '/products') },
|
||||
{ path: '/reporting', roles: ['admin', 'full', 'client'], matches: (pathname) => hasPathPrefix(pathname, '/reporting') },
|
||||
{ path: '/scenarios', roles: ['admin', 'full', 'client'], matches: (pathname) => hasPathPrefix(pathname, '/scenarios') },
|
||||
{
|
||||
path: '/settings',
|
||||
roles: ['admin', 'full', 'operations', 'client'],
|
||||
matches: (pathname) => hasPathPrefix(pathname, '/settings')
|
||||
},
|
||||
{
|
||||
path: '/client-access',
|
||||
roles: ['admin', 'client'],
|
||||
matches: (pathname) => hasPathPrefix(pathname, '/client-access')
|
||||
}
|
||||
];
|
||||
|
||||
export function getDefaultRouteForRole(session: AppSession | null | undefined) {
|
||||
const role = getWorkspaceRole(session);
|
||||
|
||||
if (role === 'operations') {
|
||||
return featureFlags.mixCalculatorSessionHistory ? '/mix-calculator' : '/mix-calculator/new';
|
||||
}
|
||||
|
||||
if (role === 'admin' || role === 'full' || role === 'client') {
|
||||
if (canOpenDashboard(session)) return '/';
|
||||
if (canOpenMixCalculator(session)) return featureFlags.mixCalculatorSessionHistory ? '/mix-calculator' : '/mix-calculator/new';
|
||||
if (canOpenRawMaterials(session)) return '/raw-materials';
|
||||
if (canOpenMixMaster(session)) return '/mixes';
|
||||
if (canOpenProducts(session)) return '/products';
|
||||
if (canOpenScenarios(session)) return '/scenarios';
|
||||
if (canOpenSettings(session)) return '/settings';
|
||||
}
|
||||
|
||||
return '/';
|
||||
}
|
||||
|
||||
export function canAccessRoute(session: AppSession | null | undefined, pathname: string) {
|
||||
const rule = routeAccessRules.find((candidate) => candidate.matches(pathname));
|
||||
if (!rule) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const role = getWorkspaceRole(session);
|
||||
if (!rule.roles.includes(role)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pathname === '/') return canOpenDashboard(session);
|
||||
if (pathname.startsWith('/mix-calculator')) return canOpenMixCalculator(session);
|
||||
if (pathname.startsWith('/raw-materials')) return canOpenRawMaterials(session);
|
||||
if (pathname.startsWith('/mixes')) return canOpenMixMaster(session);
|
||||
if (pathname.startsWith('/products')) return canOpenProducts(session);
|
||||
if (pathname.startsWith('/scenarios')) return canOpenScenarios(session);
|
||||
if (pathname.startsWith('/reporting')) return canOpenReporting(session);
|
||||
if (pathname.startsWith('/settings')) return canOpenSettings(session);
|
||||
if (pathname.startsWith('/client-access')) return canOpenClientAccess(session);
|
||||
return true;
|
||||
}
|
||||
|
||||
export function canUseWorkspaceSearch(session: AppSession | null | undefined) {
|
||||
return (
|
||||
canOpenDashboard(session) ||
|
||||
canOpenRawMaterials(session) ||
|
||||
canOpenMixMaster(session) ||
|
||||
canOpenMixCalculator(session) ||
|
||||
canOpenProducts(session) ||
|
||||
canOpenScenarios(session)
|
||||
);
|
||||
}
|
||||
|
||||
export const getWorkspaceHomeHref = getDefaultRouteForRole;
|
||||
export const isWorkspaceRouteAllowed = canAccessRoute;
|
||||
Reference in New Issue
Block a user