diff --git a/apps/edr-freight-api/src/seed/edr-freight.seed.ts b/apps/edr-freight-api/src/seed/edr-freight.seed.ts index e4ab41954..e611011f8 100644 --- a/apps/edr-freight-api/src/seed/edr-freight.seed.ts +++ b/apps/edr-freight-api/src/seed/edr-freight.seed.ts @@ -2,10 +2,15 @@ import { BOOKING_RULE_ENGINE_PERMISSIONS, BOOKING_RULE_ENGINE_PERMISSION_KEYS, deriveReadPermissions, + FREIGHT_PERMS, POSITION_PERMISSION_PRESETS, ROLE_PERMISSION_PRESETS, } from './freight-permissions.registry'; +/** Shorthand for the one overview-layout permission a role/position preset gets. */ +const overviewLayout = (key: Parameters[0]): string => + FREIGHT_PERMS.overview.layout(key); + export type FreightSeedRole = { key: string; name: { en: string }; @@ -248,48 +253,55 @@ export const EDR_FREIGHT_ROLES: FreightSeedRole[] = [ { key: "edr_line_staff", name: { en: "EDR Line Staff" }, - permissionKeys: [...ROLE_PERMISSION_PRESETS.lineStaff], + // OCC: the legacy role form of the control-centre desk (no position preset + // grants this layout — see EDR_FREIGHT_POSITIONS). + permissionKeys: [...ROLE_PERMISSION_PRESETS.lineStaff, overviewLayout("occ")], }, { key: "edr_operations_officer", name: { en: "EDR Operations Officer" }, - permissionKeys: [...ROLE_PERMISSION_PRESETS.operationsOfficer], + permissionKeys: [ + ...ROLE_PERMISSION_PRESETS.operationsOfficer, + overviewLayout("operation"), + ], }, { key: "edr_director", name: { en: "EDR Director" }, - permissionKeys: [...ROLE_PERMISSION_PRESETS.director], + permissionKeys: [...ROLE_PERMISSION_PRESETS.director, overviewLayout("executive")], }, { key: "edr_ceo", name: { en: "EDR CEO" }, - permissionKeys: [...ROLE_PERMISSION_PRESETS.ceo], + permissionKeys: [...ROLE_PERMISSION_PRESETS.ceo, overviewLayout("executive")], }, { key: "edr_finance", name: { en: "EDR Finance" }, - permissionKeys: [...ROLE_PERMISSION_PRESETS.finance], + // No position preset grants this layout — Finance only exists as a Role. + permissionKeys: [...ROLE_PERMISSION_PRESETS.finance, overviewLayout("finance")], }, { key: "edr_marketing", name: { en: "EDR Marketing" }, - permissionKeys: [...ROLE_PERMISSION_PRESETS.marketing], + permissionKeys: [...ROLE_PERMISSION_PRESETS.marketing, overviewLayout("marketer")], }, { key: "edr_gl_ethiopia", name: { en: "EDR Global Logistics — Ethiopia" }, - permissionKeys: [...ROLE_PERMISSION_PRESETS.glEthiopia], + permissionKeys: [...ROLE_PERMISSION_PRESETS.glEthiopia, overviewLayout("clearance")], }, { key: "edr_gl_djibouti", name: { en: "EDR Global Logistics — Djibouti" }, - permissionKeys: [...ROLE_PERMISSION_PRESETS.glDjibouti], + permissionKeys: [...ROLE_PERMISSION_PRESETS.glDjibouti, overviewLayout("clearance")], }, { key: "edr_org_manager", name: { en: "EDR Org Manager" }, permissionKeys: [ ...BOOKING_RULE_ENGINE_PERMISSION_KEYS, + overviewLayout("executive"), ...EMPLOYEE_REGISTRATION_PERMISSIONS.map((p) => p.key), ...ROLE_ASSIGNMENT_PERMISSIONS.map((p) => p.key), ...HIERARCHY_UNIT_PERMISSIONS.map((p) => p.key), @@ -326,15 +338,17 @@ export const EDR_FREIGHT_ROLES: FreightSeedRole[] = [ * PositionPermission rows (NOT Role/RolePermission). Users get their access by * being assigned to a Position via EmployeePosition. */ +// No position preset grants the "occ" or "finance" overview layouts today — +// see the comments on edr_line_staff / edr_finance above. export const EDR_FREIGHT_POSITIONS: FreightSeedPosition[] = [ - { key: "chief", name: { en: "Chief" }, rank: 1, permissionKeys: [...POSITION_PERMISSION_PRESETS.chief] }, - { key: "director", name: { en: "Director" }, rank: 2, permissionKeys: [...POSITION_PERMISSION_PRESETS.director] }, - { key: "ceo", name: { en: "CEO" }, rank: 1, permissionKeys: [...POSITION_PERMISSION_PRESETS.ceo] }, - { key: "ethiopian_gl", name: { en: "Ethiopian GL" }, rank: 3, permissionKeys: [...POSITION_PERMISSION_PRESETS.ethiopianGl] }, - { key: "djibouti_gl", name: { en: "Djibouti GL" }, rank: 3, permissionKeys: [...POSITION_PERMISSION_PRESETS.djiboutiGl] }, - { key: "marketer", name: { en: "Marketer" }, rank: 4, permissionKeys: [...POSITION_PERMISSION_PRESETS.marketer] }, - { key: "operation", name: { en: "Operation" }, rank: 4, permissionKeys: [...POSITION_PERMISSION_PRESETS.operation] }, - { key: "operations_chief", name: { en: "Operations Chief" }, rank: 2, permissionKeys: [...POSITION_PERMISSION_PRESETS.operationsChief] }, - { key: "dispatcher", name: { en: "Dispatcher" }, rank: 4, permissionKeys: [...POSITION_PERMISSION_PRESETS.dispatcher] }, - { key: "truck_machinery_chief", name: { en: "Truck & Machinery Chief" }, rank: 2, permissionKeys: [...POSITION_PERMISSION_PRESETS.truckMachineryChief] }, + { key: "chief", name: { en: "Chief" }, rank: 1, permissionKeys: [...POSITION_PERMISSION_PRESETS.chief, overviewLayout("executive")] }, + { key: "director", name: { en: "Director" }, rank: 2, permissionKeys: [...POSITION_PERMISSION_PRESETS.director, overviewLayout("executive")] }, + { key: "ceo", name: { en: "CEO" }, rank: 1, permissionKeys: [...POSITION_PERMISSION_PRESETS.ceo, overviewLayout("executive")] }, + { key: "ethiopian_gl", name: { en: "Ethiopian GL" }, rank: 3, permissionKeys: [...POSITION_PERMISSION_PRESETS.ethiopianGl, overviewLayout("clearance")] }, + { key: "djibouti_gl", name: { en: "Djibouti GL" }, rank: 3, permissionKeys: [...POSITION_PERMISSION_PRESETS.djiboutiGl, overviewLayout("clearance")] }, + { key: "marketer", name: { en: "Marketer" }, rank: 4, permissionKeys: [...POSITION_PERMISSION_PRESETS.marketer, overviewLayout("marketer")] }, + { key: "operation", name: { en: "Operation" }, rank: 4, permissionKeys: [...POSITION_PERMISSION_PRESETS.operation, overviewLayout("operation")] }, + { key: "operations_chief", name: { en: "Operations Chief" }, rank: 2, permissionKeys: [...POSITION_PERMISSION_PRESETS.operationsChief, overviewLayout("operation")] }, + { key: "dispatcher", name: { en: "Dispatcher" }, rank: 4, permissionKeys: [...POSITION_PERMISSION_PRESETS.dispatcher, overviewLayout("operation")] }, + { key: "truck_machinery_chief", name: { en: "Truck & Machinery Chief" }, rank: 2, permissionKeys: [...POSITION_PERMISSION_PRESETS.truckMachineryChief, overviewLayout("operation")] }, ]; diff --git a/apps/edr-freight-api/src/seed/freight-permissions.registry.ts b/apps/edr-freight-api/src/seed/freight-permissions.registry.ts index 4e4144f7d..5fee67dbc 100644 --- a/apps/edr-freight-api/src/seed/freight-permissions.registry.ts +++ b/apps/edr-freight-api/src/seed/freight-permissions.registry.ts @@ -148,6 +148,52 @@ export const REPORT_PERMISSIONS: FreightPermissionSeed[] = ), ); +/** + * Overview dashboard layouts (see the backoffice's role-dashboards.config.ts, + * where `LAYOUTS` renders one composition per key). Unlike reports, a caller + * lands on exactly ONE layout, so `OVERVIEW_LAYOUT_KEYS` is also the priority + * order: whoever resolves the permission set picks the FIRST key here the + * caller holds — the specific operational view wins over the broad executive + * one, same rule the old role/position-key table encoded. + * + * NEVER reorder — GET /overview/layouts and the frontend both walk this array + * to break ties, so reordering silently changes who gets which dashboard. + */ +export const OVERVIEW_LAYOUT_KEYS = [ + "clearance", + "occ", + "operation", + "marketer", + "finance", + "executive", +] as const; + +export type OverviewLayoutKey = (typeof OVERVIEW_LAYOUT_KEYS)[number]; + +export const OVERVIEW_LAYOUT_LABELS: Record = { + clearance: "Clearance & logistics dashboard", + occ: "Control centre dashboard", + operation: "Operations dashboard", + marketer: "Marketing dashboard", + finance: "Finance dashboard", + executive: "Executive dashboard", +}; + +export const overviewLayoutPermissionKey = (key: string): string => + `edr_freight_app:overview:${key}:view`; + +const overviewLayoutPermId = (index: number): string => + `a4f00003-0001-4000-8000-${(index + 1).toString(16).padStart(12, "0")}`; + +export const OVERVIEW_LAYOUT_PERMISSIONS: FreightPermissionSeed[] = + OVERVIEW_LAYOUT_KEYS.map((key, index) => + perm( + overviewLayoutPermId(index), + overviewLayoutPermissionKey(key), + `Overview layout: ${OVERVIEW_LAYOUT_LABELS[key]}`, + ), + ); + export const BOOKING_PERMISSIONS: FreightPermissionSeed[] = [ perm( "a1000001-0001-4000-8000-000000000001", @@ -1759,6 +1805,7 @@ export const NOTIFICATION_PERMISSIONS: FreightPermissionSeed[] = [ export const ADVANCED_BACKOFFICE_PERMISSIONS: FreightPermissionSeed[] = [ ...REPORT_PERMISSIONS, + ...OVERVIEW_LAYOUT_PERMISSIONS, ...CUSTOMER_PERMISSIONS, ...SHIPPING_LINE_PERMISSIONS, ...CHAT_PERMISSIONS, @@ -2295,6 +2342,7 @@ export const FREIGHT_PERMS = { }, overview: { view: "edr_freight_app:overview:view", + layout: (key: OverviewLayoutKey): string => overviewLayoutPermissionKey(key), }, reports: { view: "edr_freight_app:reports:view",