@jmruthers/pace-core 0.5.54 → 0.5.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (396) hide show
  1. package/README.md +0 -4
  2. package/dist/{DataTable-7FMFXA7A.js → DataTable-4T627QFJ.js} +11 -11
  3. package/dist/{PublicLoadingSpinner-Bq_-BeK-.d.ts → PublicLoadingSpinner-SL8WaQN7.d.ts} +2 -21
  4. package/dist/{api-H5A3H4IR.js → api-LUNF5O6M.js} +3 -3
  5. package/dist/{appConfig-BVGyuvI7.d.ts → appConfig-DjpeG6P-.d.ts} +9 -1
  6. package/dist/{appNameResolver-7GHF5ED2.js → appNameResolver-UURKN7NF.js} +2 -2
  7. package/dist/{audit-BUW3LMJB.js → audit-6TOCAMKO.js} +2 -2
  8. package/dist/{chunk-MZBUOP4P.js → chunk-5BSLGBYI.js} +4 -3
  9. package/dist/chunk-5BSLGBYI.js.map +1 -0
  10. package/dist/{chunk-I5Z3QH5X.js → chunk-66C4BSAY.js} +2 -2
  11. package/dist/{chunk-I5Z3QH5X.js.map → chunk-66C4BSAY.js.map} +1 -1
  12. package/dist/{chunk-MYP2EGHX.js → chunk-AJ2KMES7.js} +21 -14
  13. package/dist/chunk-AJ2KMES7.js.map +1 -0
  14. package/dist/{chunk-EL2O4IUX.js → chunk-AQFRLC7K.js} +16 -24
  15. package/dist/{chunk-EL2O4IUX.js.map → chunk-AQFRLC7K.js.map} +1 -1
  16. package/dist/{chunk-7BNPOCLL.js → chunk-B2WTCLCV.js} +6 -2
  17. package/dist/chunk-B2WTCLCV.js.map +1 -0
  18. package/dist/{chunk-WJARTBCT.js → chunk-D7ARGIA3.js} +16 -7
  19. package/dist/chunk-D7ARGIA3.js.map +1 -0
  20. package/dist/{chunk-NRK4AIHQ.js → chunk-KBRACSJI.js} +3 -3
  21. package/dist/{chunk-NYUJ4FJR.js → chunk-KJDPSM64.js} +7 -7
  22. package/dist/chunk-KJDPSM64.js.map +1 -0
  23. package/dist/{chunk-GWSBHC4J.js → chunk-KLPVOPRI.js} +261 -38
  24. package/dist/chunk-KLPVOPRI.js.map +1 -0
  25. package/dist/{chunk-TRIZ7IB7.js → chunk-MPQDF75X.js} +148 -288
  26. package/dist/chunk-MPQDF75X.js.map +1 -0
  27. package/dist/{chunk-MSFACPQQ.js → chunk-PAEM3OWN.js} +11 -11
  28. package/dist/{chunk-MSFACPQQ.js.map → chunk-PAEM3OWN.js.map} +1 -1
  29. package/dist/{chunk-GIO7BFE7.js → chunk-RQD3D2CO.js} +66 -169
  30. package/dist/{chunk-GIO7BFE7.js.map → chunk-RQD3D2CO.js.map} +1 -1
  31. package/dist/{chunk-YDJW5XTN.js → chunk-STT7INZR.js} +25 -1
  32. package/dist/chunk-STT7INZR.js.map +1 -0
  33. package/dist/{chunk-6MTY77WU.js → chunk-TNMXZLDR.js} +3 -3
  34. package/dist/{chunk-BC3S53OZ.js → chunk-UQE2Y64H.js} +30 -14
  35. package/dist/chunk-UQE2Y64H.js.map +1 -0
  36. package/dist/{chunk-22KLBHPS.js → chunk-W66AZIOH.js} +2 -2
  37. package/dist/chunk-W66AZIOH.js.map +1 -0
  38. package/dist/{chunk-SS3E6QLB.js → chunk-YNUBMSMV.js} +2 -2
  39. package/dist/chunk-YNUBMSMV.js.map +1 -0
  40. package/dist/{chunk-NZ655MWE.js → chunk-ZOD2ZY6X.js} +5 -4
  41. package/dist/chunk-ZOD2ZY6X.js.map +1 -0
  42. package/dist/{chunk-74C6SNEC.js → chunk-ZPK5656W.js} +3 -3
  43. package/dist/{chunk-74C6SNEC.js.map → chunk-ZPK5656W.js.map} +1 -1
  44. package/dist/components.d.ts +22 -899
  45. package/dist/components.js +436 -3118
  46. package/dist/components.js.map +1 -1
  47. package/dist/file-reference-9xUOnwyt.d.ts +70 -0
  48. package/dist/hooks.d.ts +2 -2
  49. package/dist/hooks.js +10 -10
  50. package/dist/hooks.js.map +1 -1
  51. package/dist/index.d.ts +49 -9
  52. package/dist/index.js +190 -25
  53. package/dist/index.js.map +1 -1
  54. package/dist/{organisation-CO3Sh3_D.d.ts → organisation-t-vvQC3g.d.ts} +1 -8
  55. package/dist/providers.d.ts +2 -2
  56. package/dist/providers.js +5 -5
  57. package/dist/rbac/index.d.ts +65 -46
  58. package/dist/rbac/index.js +10 -12
  59. package/dist/styles/core.css +0 -125
  60. package/dist/types.d.ts +2 -1
  61. package/dist/types.js +3 -1
  62. package/dist/types.js.map +1 -1
  63. package/dist/{usePublicRouteParams-B2OcAsur.d.ts → usePublicRouteParams-CdoFxnJK.d.ts} +1 -1
  64. package/dist/utils.d.ts +3 -4
  65. package/dist/utils.js +44 -13
  66. package/dist/utils.js.map +1 -1
  67. package/docs/FILE_REFERENCE_SYSTEM.md +440 -0
  68. package/docs/INDEX.md +7 -5
  69. package/docs/README.md +0 -1
  70. package/docs/api/README.md +0 -4
  71. package/docs/api/classes/ErrorBoundary.md +1 -1
  72. package/docs/api/classes/InvalidScopeError.md +1 -1
  73. package/docs/api/classes/MissingUserContextError.md +1 -1
  74. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  75. package/docs/api/classes/PermissionDeniedError.md +2 -2
  76. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  77. package/docs/api/classes/RBACAuditManager.md +12 -12
  78. package/docs/api/classes/RBACCache.md +1 -1
  79. package/docs/api/classes/RBACEngine.md +6 -6
  80. package/docs/api/classes/RBACError.md +1 -1
  81. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  82. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  83. package/docs/api/classes/StorageUtils.md +281 -0
  84. package/docs/api/interfaces/AggregateConfig.md +1 -1
  85. package/docs/api/interfaces/ButtonProps.md +1 -1
  86. package/docs/api/interfaces/CardProps.md +1 -1
  87. package/docs/api/interfaces/ColorPalette.md +1 -1
  88. package/docs/api/interfaces/ColorShade.md +1 -1
  89. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  90. package/docs/api/interfaces/DataTableAction.md +1 -1
  91. package/docs/api/interfaces/DataTableColumn.md +1 -1
  92. package/docs/api/interfaces/DataTableProps.md +1 -1
  93. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  94. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  95. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  96. package/docs/api/interfaces/EventContextType.md +1 -1
  97. package/docs/api/interfaces/EventLogoProps.md +1 -1
  98. package/docs/api/interfaces/EventProviderProps.md +1 -1
  99. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  100. package/docs/api/interfaces/FileUploadProps.md +1 -1
  101. package/docs/api/interfaces/FooterProps.md +1 -1
  102. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  103. package/docs/api/interfaces/InputProps.md +1 -1
  104. package/docs/api/interfaces/LabelProps.md +1 -1
  105. package/docs/api/interfaces/LoginFormProps.md +1 -1
  106. package/docs/api/interfaces/NavigationAccessRecord.md +2 -2
  107. package/docs/api/interfaces/NavigationContextType.md +1 -1
  108. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  109. package/docs/api/interfaces/NavigationItem.md +1 -1
  110. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  111. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  112. package/docs/api/interfaces/Organisation.md +1 -1
  113. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  114. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  115. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  116. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  117. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  118. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  119. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  120. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  121. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  122. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  123. package/docs/api/interfaces/PaletteData.md +1 -1
  124. package/docs/api/interfaces/PermissionEnforcerProps.md +4 -4
  125. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  126. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  127. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  128. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  129. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  130. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  131. package/docs/api/interfaces/RBACConfig.md +1 -1
  132. package/docs/api/interfaces/RBACContextType.md +1 -1
  133. package/docs/api/interfaces/RBACLogger.md +1 -1
  134. package/docs/api/interfaces/RBACProviderProps.md +1 -1
  135. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  136. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  137. package/docs/api/interfaces/RouteAccessRecord.md +2 -2
  138. package/docs/api/interfaces/RouteConfig.md +2 -2
  139. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  140. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  141. package/docs/api/interfaces/StorageConfig.md +1 -1
  142. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  143. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  144. package/docs/api/interfaces/StorageListOptions.md +1 -1
  145. package/docs/api/interfaces/StorageListResult.md +1 -1
  146. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  147. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  148. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  149. package/docs/api/interfaces/StyleImport.md +1 -1
  150. package/docs/api/interfaces/ToastActionElement.md +1 -1
  151. package/docs/api/interfaces/ToastProps.md +1 -1
  152. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  153. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  154. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  155. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  156. package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
  157. package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
  158. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  159. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  160. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  161. package/docs/api/interfaces/UserEventAccess.md +1 -1
  162. package/docs/api/interfaces/UserMenuProps.md +1 -1
  163. package/docs/api/interfaces/UserProfile.md +1 -1
  164. package/docs/api/modules.md +204 -200
  165. package/docs/api-reference/components.md +141 -163
  166. package/docs/api-reference/hooks.md +347 -0
  167. package/docs/core-concepts/rbac-system.md +69 -16
  168. package/docs/getting-started/examples/basic-auth-app.md +0 -1
  169. package/docs/implementation-guides/datatable-rbac-usage.md +12 -11
  170. package/docs/implementation-guides/file-upload-storage.md +733 -0
  171. package/docs/implementation-guides/inactivity-tracking.md +779 -0
  172. package/docs/implementation-guides/organisation-security.md +748 -0
  173. package/docs/implementation-guides/public-pages-advanced.md +1022 -0
  174. package/docs/migration/MIGRATION_GUIDE.md +684 -0
  175. package/docs/migration/README.md +13 -2
  176. package/docs/migration/rbac-migration.md +73 -0
  177. package/docs/rbac/examples/rbac-rls-integration-example.md +11 -13
  178. package/docs/style-guide.md +269 -1
  179. package/package.json +1 -1
  180. package/src/__tests__/TESTING_GUIDELINES.md +331 -18
  181. package/src/__tests__/helpers/supabaseMock.ts +99 -0
  182. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +10 -7
  183. package/src/__tests__/shared.ts +6 -0
  184. package/src/components/DataTable/components/ActionButtons.tsx +2 -2
  185. package/src/components/DataTable/components/DataTableCore.tsx +2 -2
  186. package/src/components/DataTable/components/UnifiedTableBody.tsx +1 -1
  187. package/src/components/DataTable/utils/debugTools.ts +2 -2
  188. package/src/components/Dialog/Dialog.test.tsx +12 -2
  189. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +6 -6
  190. package/src/components/ErrorBoundary/ErrorBoundary.tsx +2 -2
  191. package/src/components/FileDisplay.tsx +233 -0
  192. package/src/components/FileUpload.tsx +176 -0
  193. package/src/components/Footer/Footer.test.tsx +7 -7
  194. package/src/components/NavigationMenu/NavigationMenu.test.tsx +13 -6
  195. package/src/components/OrganisationSelector/OrganisationSelector.test.tsx +30 -3
  196. package/src/components/OrganisationSelector/OrganisationSelector.tsx +1 -1
  197. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.rbac.test.tsx +558 -0
  198. package/src/components/PublicLayout/PublicErrorBoundary.tsx +1 -1
  199. package/src/components/PublicLayout/PublicPageDebugger.tsx +2 -2
  200. package/src/components/PublicLayout/PublicPageDiagnostic.tsx +2 -2
  201. package/src/components/PublicLayout/PublicPageProvider.tsx +2 -2
  202. package/src/components/Select/Select.test.tsx +50 -15
  203. package/src/components/SuperAdminGuard.tsx +2 -2
  204. package/src/components/__tests__/SuperAdminGuard.test.tsx +559 -0
  205. package/src/components/index.ts +0 -183
  206. package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +2 -2
  207. package/src/hooks/__tests__/usePermissionCache.unit.test.ts +1 -1
  208. package/src/hooks/__tests__/useRBAC.unit.test.ts +191 -138
  209. package/src/hooks/public/usePublicEvent.ts +2 -2
  210. package/src/hooks/useAppConfig.ts +3 -3
  211. package/src/hooks/useComponentPerformance.ts +1 -1
  212. package/src/hooks/useDataTablePerformance.ts +1 -1
  213. package/src/hooks/useFileReference.ts +232 -0
  214. package/src/hooks/useOrganisationPermissions.test.ts +254 -344
  215. package/src/hooks/useOrganisationPermissions.ts +15 -7
  216. package/src/hooks/useOrganisationSecurity.test.ts +390 -402
  217. package/src/hooks/usePerformanceMonitor.ts +1 -1
  218. package/src/hooks/usePermissionCache.test.ts +264 -395
  219. package/src/hooks/usePermissionCache.ts +34 -4
  220. package/src/hooks/useSecureDataAccess.test.ts +486 -0
  221. package/src/hooks/useSecureDataAccess.ts +4 -1
  222. package/src/providers/InactivityProvider.tsx +2 -2
  223. package/src/providers/OrganisationProvider.test.simple.tsx +168 -0
  224. package/src/providers/OrganisationProvider.test.tsx +168 -0
  225. package/src/providers/OrganisationProvider.tsx +18 -31
  226. package/src/providers/UnifiedAuthProvider.test.simple.tsx +205 -0
  227. package/src/providers/UnifiedAuthProvider.test.tsx +128 -0
  228. package/src/providers/__tests__/InactivityProvider.test.tsx +3 -4
  229. package/src/providers/__tests__/OrganisationProvider.test.tsx +19 -14
  230. package/src/rbac/__tests__/integration.authflow.test.tsx +123 -0
  231. package/src/rbac/__tests__/integration.navigation.test.tsx +72 -0
  232. package/src/rbac/__tests__/integration.securedata.test.tsx +92 -0
  233. package/src/rbac/__tests__/integration.smoke.test.tsx +73 -0
  234. package/src/rbac/__tests__/rbac-core.test.tsx +26 -22
  235. package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +411 -0
  236. package/src/rbac/__tests__/rbac-engine-simplified.test.ts +285 -0
  237. package/src/rbac/__tests__/rbac-functions.test.ts +655 -0
  238. package/src/rbac/__tests__/rbac-integration.test.ts +532 -0
  239. package/src/rbac/__tests__/scenarios.user-role.test.tsx +196 -0
  240. package/src/rbac/api.test.ts +6 -6
  241. package/src/rbac/api.ts +2 -2
  242. package/src/rbac/audit.test.ts +485 -0
  243. package/src/rbac/audit.ts +7 -1
  244. package/src/rbac/cache-invalidation.ts +318 -0
  245. package/src/rbac/cache.test.ts +286 -0
  246. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +559 -0
  247. package/src/rbac/components/EnhancedNavigationMenu.tsx +29 -23
  248. package/src/rbac/components/NavigationProvider.test.tsx +449 -0
  249. package/src/rbac/components/PagePermissionGuard.tsx +4 -4
  250. package/src/rbac/components/PagePermissionProvider.test.tsx +479 -0
  251. package/src/rbac/components/SecureDataProvider.test.tsx +511 -0
  252. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +159 -430
  253. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +4 -5
  254. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +112 -118
  255. package/src/rbac/config.test.ts +410 -0
  256. package/src/rbac/engine.test.simple.ts +237 -0
  257. package/src/rbac/engine.test.ts +233 -0
  258. package/src/rbac/engine.ts +37 -41
  259. package/src/rbac/examples/CompleteRBACExample.tsx +3 -3
  260. package/src/rbac/examples/EventBasedApp.tsx +4 -4
  261. package/src/rbac/hooks/useRBAC.simple.test.ts +16 -0
  262. package/src/rbac/hooks/useRBAC.test.ts +207 -455
  263. package/src/rbac/hooks/useRBAC.ts +30 -22
  264. package/src/rbac/permissions.test.ts +128 -0
  265. package/src/rbac/permissions.ts +56 -141
  266. package/src/rbac/providers/RBACProvider.tsx +1 -1
  267. package/src/rbac/secureClient.test.ts +444 -0
  268. package/src/rbac/security.test.ts +390 -0
  269. package/src/rbac/security.ts +1 -1
  270. package/src/rbac/types.test.ts +382 -0
  271. package/src/rbac/types.ts +2 -2
  272. package/src/styles/core.css +0 -125
  273. package/src/types/file-reference.ts +77 -0
  274. package/src/types/rbac-functions.ts +290 -0
  275. package/src/types/supabase.ts +10 -28
  276. package/src/types/unified.ts +4 -1
  277. package/src/utils/__tests__/bundleAnalysis.unit.test.ts +81 -55
  278. package/src/utils/__tests__/lazyLoad.unit.test.tsx +21 -12
  279. package/src/utils/__tests__/organisationContext.unit.test.ts +13 -7
  280. package/src/utils/__tests__/performanceBudgets.unit.test.ts +3 -3
  281. package/src/utils/__tests__/sessionTracking.unit.test.ts +32 -12
  282. package/src/utils/appConfig.ts +1 -1
  283. package/src/utils/appIdResolver.test.ts +503 -0
  284. package/src/utils/appIdResolver.ts +1 -1
  285. package/src/utils/appNameResolver.test.ts +494 -0
  286. package/src/utils/appNameResolver.ts +3 -2
  287. package/src/utils/bundleAnalysis.ts +3 -3
  288. package/src/utils/debugLogger.ts +1 -1
  289. package/src/utils/file-reference.ts +263 -0
  290. package/src/utils/formatDate.test.ts +2 -2
  291. package/src/utils/organisationContext.test.ts +340 -0
  292. package/src/utils/organisationContext.ts +19 -6
  293. package/src/utils/performanceBudgets.ts +2 -2
  294. package/src/utils/permissionUtils.test.ts +393 -0
  295. package/src/utils/permissionUtils.ts +5 -2
  296. package/src/utils/secureDataAccess.test.ts +715 -0
  297. package/src/utils/secureDataAccess.ts +21 -5
  298. package/src/utils/sessionTracking.ts +34 -4
  299. package/src/utils/storage/__tests__/helpers.unit.test.ts +328 -0
  300. package/src/utils/storage/__tests__/index.unit.test.ts +16 -0
  301. package/src/utils/storage/helpers.ts +20 -25
  302. package/src/utils/storage/index.ts +29 -1
  303. package/src/vite-env.d.ts +17 -0
  304. package/dist/chunk-22KLBHPS.js.map +0 -1
  305. package/dist/chunk-7BNPOCLL.js.map +0 -1
  306. package/dist/chunk-BC3S53OZ.js.map +0 -1
  307. package/dist/chunk-GWSBHC4J.js.map +0 -1
  308. package/dist/chunk-MYP2EGHX.js.map +0 -1
  309. package/dist/chunk-MZBUOP4P.js.map +0 -1
  310. package/dist/chunk-NYUJ4FJR.js.map +0 -1
  311. package/dist/chunk-NZ655MWE.js.map +0 -1
  312. package/dist/chunk-SS3E6QLB.js.map +0 -1
  313. package/dist/chunk-TRIZ7IB7.js.map +0 -1
  314. package/dist/chunk-WJARTBCT.js.map +0 -1
  315. package/dist/chunk-YDJW5XTN.js.map +0 -1
  316. package/docs/print-components/README.md +0 -258
  317. package/docs/print-components/api-reference.md +0 -636
  318. package/docs/print-components/examples/README.md +0 -204
  319. package/docs/print-components/examples/basic-report.tsx +0 -92
  320. package/docs/print-components/examples/card-catalog.tsx +0 -149
  321. package/docs/print-components/examples/cover-page-report.tsx +0 -163
  322. package/docs/print-components/quick-start.md +0 -363
  323. package/src/components/PrintButton/PrintButton.tsx +0 -321
  324. package/src/components/PrintButton/PrintButtonGroup.tsx +0 -84
  325. package/src/components/PrintButton/PrintToolbar.tsx +0 -94
  326. package/src/components/PrintButton/__tests__/PrintButton.test.tsx +0 -271
  327. package/src/components/PrintButton/examples/PrintButtonShowcase.tsx +0 -438
  328. package/src/components/PrintButton/index.ts +0 -33
  329. package/src/components/PrintButton/types.ts +0 -173
  330. package/src/components/PrintCard/PrintCard.tsx +0 -154
  331. package/src/components/PrintCard/PrintCardContent.tsx +0 -57
  332. package/src/components/PrintCard/PrintCardFooter.tsx +0 -60
  333. package/src/components/PrintCard/PrintCardGrid.tsx +0 -91
  334. package/src/components/PrintCard/PrintCardHeader.tsx +0 -78
  335. package/src/components/PrintCard/PrintCardImage.tsx +0 -81
  336. package/src/components/PrintCard/examples/PrintCardShowcase.tsx +0 -239
  337. package/src/components/PrintCard/index.ts +0 -34
  338. package/src/components/PrintCard/types.ts +0 -171
  339. package/src/components/PrintDataTable/PrintDataTable.tsx +0 -215
  340. package/src/components/PrintDataTable/PrintTableGroup.tsx +0 -90
  341. package/src/components/PrintDataTable/PrintTableRow.tsx +0 -76
  342. package/src/components/PrintDataTable/index.ts +0 -25
  343. package/src/components/PrintDataTable/types.ts +0 -67
  344. package/src/components/PrintFooter/PrintFooter.tsx +0 -183
  345. package/src/components/PrintFooter/PrintFooterContent.tsx +0 -71
  346. package/src/components/PrintFooter/PrintFooterInfo.tsx +0 -86
  347. package/src/components/PrintFooter/PrintPageNumber.tsx +0 -90
  348. package/src/components/PrintFooter/examples/PrintFooterShowcase.tsx +0 -390
  349. package/src/components/PrintFooter/index.ts +0 -30
  350. package/src/components/PrintFooter/types.ts +0 -149
  351. package/src/components/PrintGrid/PrintGrid.tsx +0 -180
  352. package/src/components/PrintGrid/PrintGridBreakpoint.tsx +0 -109
  353. package/src/components/PrintGrid/PrintGridContainer.tsx +0 -128
  354. package/src/components/PrintGrid/PrintGridItem.tsx +0 -220
  355. package/src/components/PrintGrid/examples/PrintGridShowcase.tsx +0 -359
  356. package/src/components/PrintGrid/index.ts +0 -31
  357. package/src/components/PrintGrid/types.ts +0 -159
  358. package/src/components/PrintHeader/PrintCoverHeader.tsx +0 -230
  359. package/src/components/PrintHeader/PrintHeader.tsx +0 -150
  360. package/src/components/PrintHeader/index.ts +0 -17
  361. package/src/components/PrintHeader/types.ts +0 -42
  362. package/src/components/PrintLayout/PrintLayout.tsx +0 -122
  363. package/src/components/PrintLayout/PrintLayoutContext.tsx +0 -66
  364. package/src/components/PrintLayout/PrintPageBreak.tsx +0 -52
  365. package/src/components/PrintLayout/examples/PrintShowcase.tsx +0 -230
  366. package/src/components/PrintLayout/index.ts +0 -19
  367. package/src/components/PrintLayout/types.ts +0 -37
  368. package/src/components/PrintPageBreak/PrintPageBreak.tsx +0 -120
  369. package/src/components/PrintPageBreak/PrintPageBreakGroup.tsx +0 -90
  370. package/src/components/PrintPageBreak/PrintPageBreakIndicator.tsx +0 -112
  371. package/src/components/PrintPageBreak/examples/PrintPageBreakShowcase.tsx +0 -279
  372. package/src/components/PrintPageBreak/index.ts +0 -23
  373. package/src/components/PrintPageBreak/types.ts +0 -94
  374. package/src/components/PrintSection/PrintColumn.tsx +0 -104
  375. package/src/components/PrintSection/PrintDivider.tsx +0 -101
  376. package/src/components/PrintSection/PrintSection.tsx +0 -129
  377. package/src/components/PrintSection/PrintSectionContent.tsx +0 -75
  378. package/src/components/PrintSection/PrintSectionHeader.tsx +0 -97
  379. package/src/components/PrintSection/examples/PrintSectionShowcase.tsx +0 -258
  380. package/src/components/PrintSection/index.ts +0 -33
  381. package/src/components/PrintSection/types.ts +0 -155
  382. package/src/components/PrintText/PrintText.tsx +0 -116
  383. package/src/components/PrintText/index.ts +0 -16
  384. package/src/components/PrintText/types.ts +0 -24
  385. package/src/rbac/__tests__/integration.test.tsx +0 -218
  386. package/src/utils/print/PrintDataProcessor.ts +0 -390
  387. package/src/utils/print/examples/PrintUtilitiesShowcase.tsx +0 -397
  388. package/src/utils/print/index.ts +0 -29
  389. package/src/utils/print/types.ts +0 -196
  390. package/src/utils/print/usePrintOptimization.ts +0 -272
  391. /package/dist/{DataTable-7FMFXA7A.js.map → DataTable-4T627QFJ.js.map} +0 -0
  392. /package/dist/{api-H5A3H4IR.js.map → api-LUNF5O6M.js.map} +0 -0
  393. /package/dist/{appNameResolver-7GHF5ED2.js.map → appNameResolver-UURKN7NF.js.map} +0 -0
  394. /package/dist/{audit-BUW3LMJB.js.map → audit-6TOCAMKO.js.map} +0 -0
  395. /package/dist/{chunk-NRK4AIHQ.js.map → chunk-KBRACSJI.js.map} +0 -0
  396. /package/dist/{chunk-6MTY77WU.js.map → chunk-TNMXZLDR.js.map} +0 -0
@@ -1,528 +1,438 @@
1
1
  /**
2
- * @file useOrganisationPermissions Hook Tests
3
- * @description Comprehensive tests for the useOrganisationPermissions hook
2
+ * @file Organisation Permissions Hook Tests
3
+ * @package @jmruthers/pace-core
4
+ * @module Hooks/useOrganisationPermissions
5
+ * @since 0.4.0
6
+ *
7
+ * Comprehensive tests for the useOrganisationPermissions hook covering all critical functionality.
4
8
  */
5
9
 
6
- import { renderHook, act } from '@testing-library/react';
7
- import { describe, it, expect, vi, beforeEach } from 'vitest';
10
+ import React from 'react';
11
+ import { renderHook, waitFor } from '@testing-library/react';
12
+ import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
8
13
  import { useOrganisationPermissions } from './useOrganisationPermissions';
9
14
  import { useOrganisations } from '../providers/OrganisationProvider';
10
- import type { Organisation, OrganisationRole, OrganisationPermission } from '../types/organisation';
11
15
 
12
- // Mock the OrganisationProvider
16
+ // Mock the organisation provider
13
17
  vi.mock('../providers/OrganisationProvider', () => ({
14
18
  useOrganisations: vi.fn()
15
19
  }));
16
20
 
17
- const mockUseOrganisations = vi.mocked(useOrganisations);
21
+ describe('useOrganisationPermissions', () => {
22
+ const mockUseOrganisations = vi.mocked(useOrganisations);
18
23
 
19
- describe('useOrganisationPermissions Hook', () => {
20
- const mockOrganisation: Organisation = {
24
+ const mockSelectedOrganisation = {
21
25
  id: 'org-123',
22
- name: 'test-org',
23
- display_name: 'Test Organisation',
24
- subscription_tier: 'standard',
25
- settings: {},
26
- is_active: true,
27
- created_at: '2024-01-01T00:00:00Z',
28
- updated_at: '2024-01-01T00:00:00Z'
26
+ name: 'Test Organisation'
29
27
  };
30
28
 
31
- const mockOrganisationContext = {
32
- selectedOrganisation: mockOrganisation,
33
- organisations: [mockOrganisation],
34
- userMemberships: [],
35
- isLoading: false,
36
- error: null,
37
- hasValidOrganisationContext: true,
38
- setSelectedOrganisation: vi.fn(),
39
- switchOrganisation: vi.fn(),
40
- getUserRole: vi.fn(),
41
- validateOrganisationAccess: vi.fn(),
42
- refreshOrganisations: vi.fn(),
43
- ensureOrganisationContext: vi.fn(),
44
- isOrganisationSecure: vi.fn(),
45
- getPrimaryOrganisation: vi.fn()
46
- };
29
+ // Helper function to create consistent mock setup
30
+ const createMockOrganisations = (overrides: any = {}) => ({
31
+ selectedOrganisation: mockSelectedOrganisation,
32
+ getUserRole: vi.fn().mockReturnValue('member'),
33
+ validateOrganisationAccess: vi.fn().mockReturnValue(true),
34
+ ensureOrganisationContext: vi.fn().mockReturnValue(mockSelectedOrganisation),
35
+ // Add other required properties
36
+ ...overrides
37
+ });
47
38
 
48
39
  beforeEach(() => {
49
40
  vi.clearAllMocks();
50
- mockUseOrganisations.mockReturnValue(mockOrganisationContext);
41
+ mockUseOrganisations.mockReturnValue(createMockOrganisations() as any);
51
42
  });
52
43
 
53
- describe('Initialization', () => {
54
- it('initializes with no access when no organisation context', () => {
55
- mockUseOrganisations.mockReturnValue({
56
- ...mockOrganisationContext,
57
- selectedOrganisation: null,
58
- hasValidOrganisationContext: false
59
- });
60
-
61
- const { result } = renderHook(() => useOrganisationPermissions());
62
-
63
- expect(result.current.userRole).toBe('no_access');
64
- expect(result.current.hasOrganisationAccess).toBe(false);
65
- expect(result.current.isOrgAdmin).toBe(false);
66
- expect(result.current.isSuperAdmin).toBe(false);
67
- expect(result.current.canModerate).toBe(false);
68
- expect(result.current.canManageMembers).toBe(false);
69
- expect(result.current.canManageSettings).toBe(false);
70
- expect(result.current.canManageEvents).toBe(false);
71
- expect(result.current.hasAdminPrivileges).toBe(false);
72
- });
73
-
74
- it('initializes with organisation context', () => {
75
- mockUseOrganisations.mockReturnValue({
76
- ...mockOrganisationContext,
77
- getUserRole: vi.fn().mockReturnValue('member'),
78
- validateOrganisationAccess: vi.fn().mockReturnValue(true),
79
- ensureOrganisationContext: vi.fn().mockReturnValue(mockOrganisation)
80
- });
44
+ afterEach(() => {
45
+ vi.restoreAllMocks();
46
+ });
81
47
 
48
+ describe('Hook Initialization', () => {
49
+ it('initializes with default organisation', () => {
82
50
  const { result } = renderHook(() => useOrganisationPermissions());
83
51
 
52
+ expect(result.current).toBeDefined();
53
+ expect(result.current.userRole).toBe('member');
84
54
  expect(result.current.organisationId).toBe('org-123');
85
55
  expect(result.current.hasOrganisationAccess).toBe(true);
86
56
  });
87
57
 
88
- it('initializes with specific organisation ID', () => {
89
- mockUseOrganisations.mockReturnValue({
90
- ...mockOrganisationContext,
91
- getUserRole: vi.fn().mockReturnValue('member'),
92
- validateOrganisationAccess: vi.fn().mockReturnValue(true)
93
- });
94
-
58
+ it('initializes with specific organisation', () => {
95
59
  const { result } = renderHook(() => useOrganisationPermissions('org-456'));
96
60
 
61
+ expect(result.current).toBeDefined();
97
62
  expect(result.current.organisationId).toBe('org-456');
98
63
  });
64
+
65
+ it('depends on useOrganisations hook', () => {
66
+ renderHook(() => useOrganisationPermissions());
67
+ expect(mockUseOrganisations).toHaveBeenCalled();
68
+ });
99
69
  });
100
70
 
101
- describe('Role-based Permissions', () => {
102
- it('handles supporter role correctly', () => {
103
- mockUseOrganisations.mockReturnValue({
104
- ...mockOrganisationContext,
105
- getUserRole: vi.fn().mockReturnValue('supporter'),
106
- validateOrganisationAccess: vi.fn().mockReturnValue(true),
107
- ensureOrganisationContext: vi.fn().mockReturnValue(mockOrganisation)
108
- });
71
+ describe('Role Detection', () => {
72
+ it('detects org admin role', () => {
73
+ mockUseOrganisations.mockReturnValue(createMockOrganisations({
74
+ getUserRole: vi.fn().mockReturnValue('org_admin')
75
+ }) as any);
109
76
 
110
77
  const { result } = renderHook(() => useOrganisationPermissions());
111
78
 
112
- expect(result.current.userRole).toBe('supporter');
113
- expect(result.current.isOrgAdmin).toBe(false);
114
- expect(result.current.isSuperAdmin).toBe(false);
115
- expect(result.current.canModerate).toBe(false);
116
- expect(result.current.canManageMembers).toBe(false);
117
- expect(result.current.canManageSettings).toBe(false);
118
- expect(result.current.canManageEvents).toBe(false);
119
- expect(result.current.hasAdminPrivileges).toBe(false);
79
+ expect(result.current.userRole).toBe('org_admin');
80
+ expect(result.current.isOrgAdmin).toBe(true);
81
+ expect(result.current.hasAdminPrivileges).toBe(true);
120
82
  });
121
83
 
122
- it('handles member role correctly', () => {
123
- mockUseOrganisations.mockReturnValue({
124
- ...mockOrganisationContext,
125
- getUserRole: vi.fn().mockReturnValue('member'),
126
- validateOrganisationAccess: vi.fn().mockReturnValue(true),
127
- ensureOrganisationContext: vi.fn().mockReturnValue(mockOrganisation)
128
- });
84
+ it('detects leader role', () => {
85
+ mockUseOrganisations.mockReturnValue(createMockOrganisations({
86
+ getUserRole: vi.fn().mockReturnValue('leader')
87
+ }) as any);
129
88
 
130
89
  const { result } = renderHook(() => useOrganisationPermissions());
131
90
 
132
- expect(result.current.userRole).toBe('member');
91
+ expect(result.current.userRole).toBe('leader');
133
92
  expect(result.current.isOrgAdmin).toBe(false);
134
- expect(result.current.isSuperAdmin).toBe(false);
135
- expect(result.current.canModerate).toBe(false);
136
- expect(result.current.canManageMembers).toBe(false);
137
- expect(result.current.canManageSettings).toBe(false);
138
- expect(result.current.canManageEvents).toBe(false);
139
- expect(result.current.hasAdminPrivileges).toBe(false);
93
+ expect(result.current.hasAdminPrivileges).toBe(true);
140
94
  });
141
95
 
142
- it('handles leader role correctly', () => {
143
- mockUseOrganisations.mockReturnValue({
144
- ...mockOrganisationContext,
145
- getUserRole: vi.fn().mockReturnValue('leader'),
146
- validateOrganisationAccess: vi.fn().mockReturnValue(true),
147
- ensureOrganisationContext: vi.fn().mockReturnValue(mockOrganisation)
148
- });
96
+ it('detects member role', () => {
97
+ mockUseOrganisations.mockReturnValue(createMockOrganisations({
98
+ getUserRole: vi.fn().mockReturnValue('member')
99
+ }) as any);
149
100
 
150
101
  const { result } = renderHook(() => useOrganisationPermissions());
151
102
 
152
- expect(result.current.userRole).toBe('leader');
103
+ expect(result.current.userRole).toBe('member');
153
104
  expect(result.current.isOrgAdmin).toBe(false);
154
- expect(result.current.isSuperAdmin).toBe(false);
155
- expect(result.current.canModerate).toBe(true);
156
- expect(result.current.canManageMembers).toBe(false);
157
- expect(result.current.canManageSettings).toBe(false);
158
- expect(result.current.canManageEvents).toBe(true);
159
105
  expect(result.current.hasAdminPrivileges).toBe(false);
160
106
  });
161
107
 
162
- it('handles org_admin role correctly', () => {
163
- mockUseOrganisations.mockReturnValue({
164
- ...mockOrganisationContext,
165
- getUserRole: vi.fn().mockReturnValue('org_admin'),
166
- validateOrganisationAccess: vi.fn().mockReturnValue(true),
167
- ensureOrganisationContext: vi.fn().mockReturnValue(mockOrganisation)
168
- });
108
+ it('detects supporter role', () => {
109
+ mockUseOrganisations.mockReturnValue(createMockOrganisations({
110
+ getUserRole: vi.fn().mockReturnValue('supporter')
111
+ }) as any);
169
112
 
170
113
  const { result } = renderHook(() => useOrganisationPermissions());
171
114
 
172
- expect(result.current.userRole).toBe('org_admin');
173
- expect(result.current.isOrgAdmin).toBe(true);
174
- expect(result.current.isSuperAdmin).toBe(true); // org_admin acts as super admin within org
175
- expect(result.current.canModerate).toBe(true);
176
- expect(result.current.canManageMembers).toBe(true);
177
- expect(result.current.canManageSettings).toBe(true);
178
- expect(result.current.canManageEvents).toBe(true);
179
- expect(result.current.hasAdminPrivileges).toBe(true);
115
+ expect(result.current.userRole).toBe('supporter');
116
+ expect(result.current.isOrgAdmin).toBe(false);
117
+ expect(result.current.hasAdminPrivileges).toBe(false);
180
118
  });
181
119
 
182
- it('handles no_access role correctly', () => {
120
+ it('handles no access role', () => {
183
121
  mockUseOrganisations.mockReturnValue({
184
- ...mockOrganisationContext,
122
+ selectedOrganisation: mockSelectedOrganisation,
185
123
  getUserRole: vi.fn().mockReturnValue('no_access'),
186
- validateOrganisationAccess: vi.fn().mockReturnValue(false),
187
- ensureOrganisationContext: vi.fn().mockReturnValue(mockOrganisation)
188
- });
124
+ validateOrganisationAccess: vi.fn().mockResolvedValue(false),
125
+ // Add other required properties
126
+ } as any);
189
127
 
190
128
  const { result } = renderHook(() => useOrganisationPermissions());
191
129
 
192
130
  expect(result.current.userRole).toBe('no_access');
193
- expect(result.current.hasOrganisationAccess).toBe(false);
194
131
  expect(result.current.isOrgAdmin).toBe(false);
195
- expect(result.current.isSuperAdmin).toBe(false);
196
- expect(result.current.canModerate).toBe(false);
197
- expect(result.current.canManageMembers).toBe(false);
198
- expect(result.current.canManageSettings).toBe(false);
199
- expect(result.current.canManageEvents).toBe(false);
200
132
  expect(result.current.hasAdminPrivileges).toBe(false);
133
+ expect(result.current.hasOrganisationAccess).toBe(false);
201
134
  });
202
135
  });
203
136
 
204
- describe('Permission Checking', () => {
205
- it('hasPermission returns false for no access', () => {
206
- mockUseOrganisations.mockReturnValue({
207
- ...mockOrganisationContext,
208
- getUserRole: vi.fn().mockReturnValue('no_access'),
209
- validateOrganisationAccess: vi.fn().mockReturnValue(false)
210
- });
137
+ describe('Super Admin Detection', () => {
138
+ it('detects super admin from user metadata', () => {
139
+ // Mock global user context first
140
+ (globalThis as any).__PACE_USER__ = {
141
+ app_metadata: { globalRole: 'super_admin' }
142
+ };
143
+
144
+ mockUseOrganisations.mockReturnValue(createMockOrganisations({
145
+ getUserRole: vi.fn().mockReturnValue('org_admin')
146
+ }) as any);
211
147
 
212
148
  const { result } = renderHook(() => useOrganisationPermissions());
213
149
 
214
- expect(result.current.hasPermission('view_basic')).toBe(false);
215
- expect(result.current.hasPermission('manage_members')).toBe(false);
150
+ expect(result.current.isSuperAdmin).toBe(true);
151
+ expect(result.current.hasAdminPrivileges).toBe(true);
152
+
153
+ delete (globalThis as any).__PACE_USER__;
216
154
  });
217
155
 
218
- it('hasPermission returns correct permissions for supporter', () => {
219
- mockUseOrganisations.mockReturnValue({
220
- ...mockOrganisationContext,
221
- getUserRole: vi.fn().mockReturnValue('supporter'),
222
- validateOrganisationAccess: vi.fn().mockReturnValue(true),
223
- ensureOrganisationContext: vi.fn().mockReturnValue(mockOrganisation)
224
- });
156
+ it('detects super admin from user metadata fallback', () => {
157
+ // Mock global user context first
158
+ (globalThis as any).__PACE_USER__ = {
159
+ user_metadata: { globalRole: 'super_admin' }
160
+ };
161
+
162
+ mockUseOrganisations.mockReturnValue(createMockOrganisations({
163
+ getUserRole: vi.fn().mockReturnValue('org_admin')
164
+ }) as any);
225
165
 
226
166
  const { result } = renderHook(() => useOrganisationPermissions());
227
167
 
228
- expect(result.current.hasPermission('view_basic')).toBe(true);
229
- expect(result.current.hasPermission('view_details')).toBe(false);
230
- expect(result.current.hasPermission('moderate_content')).toBe(false);
231
- expect(result.current.hasPermission('manage_events')).toBe(false);
232
- expect(result.current.hasPermission('manage_members')).toBe(false);
233
- expect(result.current.hasPermission('manage_settings')).toBe(false);
168
+ expect(result.current.isSuperAdmin).toBe(true);
169
+ expect(result.current.hasAdminPrivileges).toBe(true);
170
+
171
+ delete (globalThis as any).__PACE_USER__;
234
172
  });
235
173
 
236
- it('hasPermission returns correct permissions for member', () => {
174
+ it('returns false for non-super admin users', () => {
237
175
  mockUseOrganisations.mockReturnValue({
238
- ...mockOrganisationContext,
176
+ selectedOrganisation: mockSelectedOrganisation,
239
177
  getUserRole: vi.fn().mockReturnValue('member'),
240
178
  validateOrganisationAccess: vi.fn().mockReturnValue(true),
241
- ensureOrganisationContext: vi.fn().mockReturnValue(mockOrganisation)
242
- });
179
+ // Add other required properties
180
+ } as any);
243
181
 
244
182
  const { result } = renderHook(() => useOrganisationPermissions());
245
183
 
246
- expect(result.current.hasPermission('view_basic')).toBe(true);
247
- expect(result.current.hasPermission('view_details')).toBe(true);
248
- expect(result.current.hasPermission('moderate_content')).toBe(false);
249
- expect(result.current.hasPermission('manage_events')).toBe(false);
250
- expect(result.current.hasPermission('manage_members')).toBe(false);
251
- expect(result.current.hasPermission('manage_settings')).toBe(false);
184
+ expect(result.current.isSuperAdmin).toBe(false);
252
185
  });
186
+ });
253
187
 
254
- it('hasPermission returns correct permissions for leader', () => {
255
- mockUseOrganisations.mockReturnValue({
256
- ...mockOrganisationContext,
257
- getUserRole: vi.fn().mockReturnValue('leader'),
258
- validateOrganisationAccess: vi.fn().mockReturnValue(true),
259
- ensureOrganisationContext: vi.fn().mockReturnValue(mockOrganisation)
260
- });
188
+ describe('Permission Checks', () => {
189
+ it('checks moderation permissions for org admin', () => {
190
+ mockUseOrganisations.mockReturnValue(createMockOrganisations({
191
+ getUserRole: vi.fn().mockReturnValue('org_admin')
192
+ }) as any);
261
193
 
262
194
  const { result } = renderHook(() => useOrganisationPermissions());
263
195
 
264
- expect(result.current.hasPermission('view_basic')).toBe(true);
265
- expect(result.current.hasPermission('view_details')).toBe(true);
266
- expect(result.current.hasPermission('moderate_content')).toBe(true);
267
- expect(result.current.hasPermission('manage_events')).toBe(true);
268
- expect(result.current.hasPermission('manage_members')).toBe(false);
269
- expect(result.current.hasPermission('manage_settings')).toBe(false);
196
+ expect(result.current.canModerate).toBe(true);
197
+ expect(result.current.canManageMembers).toBe(true);
198
+ expect(result.current.canManageSettings).toBe(true);
199
+ expect(result.current.canManageEvents).toBe(true);
270
200
  });
271
201
 
272
- it('hasPermission returns correct permissions for org_admin', () => {
273
- mockUseOrganisations.mockReturnValue({
274
- ...mockOrganisationContext,
275
- getUserRole: vi.fn().mockReturnValue('org_admin'),
276
- validateOrganisationAccess: vi.fn().mockReturnValue(true),
277
- ensureOrganisationContext: vi.fn().mockReturnValue(mockOrganisation)
278
- });
202
+ it('checks moderation permissions for leader', () => {
203
+ mockUseOrganisations.mockReturnValue(createMockOrganisations({
204
+ getUserRole: vi.fn().mockReturnValue('leader')
205
+ }) as any);
279
206
 
280
207
  const { result } = renderHook(() => useOrganisationPermissions());
281
208
 
282
- expect(result.current.hasPermission('view_basic')).toBe(true);
283
- expect(result.current.hasPermission('view_details')).toBe(true);
284
- expect(result.current.hasPermission('moderate_content')).toBe(true);
285
- expect(result.current.hasPermission('manage_events')).toBe(true);
286
- expect(result.current.hasPermission('manage_members')).toBe(true);
287
- expect(result.current.hasPermission('manage_settings')).toBe(true);
209
+ expect(result.current.canModerate).toBe(true);
210
+ expect(result.current.canManageMembers).toBe(true);
211
+ expect(result.current.canManageSettings).toBe(false);
212
+ expect(result.current.canManageEvents).toBe(true);
288
213
  });
289
214
 
290
- it('hasPermission returns true for wildcard permission for org_admin', () => {
215
+ it('checks moderation permissions for member', () => {
291
216
  mockUseOrganisations.mockReturnValue({
292
- ...mockOrganisationContext,
293
- getUserRole: vi.fn().mockReturnValue('org_admin'),
217
+ selectedOrganisation: mockSelectedOrganisation,
218
+ getUserRole: vi.fn().mockReturnValue('member'),
294
219
  validateOrganisationAccess: vi.fn().mockReturnValue(true),
295
- ensureOrganisationContext: vi.fn().mockReturnValue(mockOrganisation)
296
- });
220
+ // Add other required properties
221
+ } as any);
297
222
 
298
223
  const { result } = renderHook(() => useOrganisationPermissions());
299
224
 
300
- expect(result.current.hasPermission('*')).toBe(true);
225
+ expect(result.current.canModerate).toBe(false);
226
+ expect(result.current.canManageMembers).toBe(false);
227
+ expect(result.current.canManageSettings).toBe(false);
228
+ expect(result.current.canManageEvents).toBe(false);
301
229
  });
302
- });
303
230
 
304
- describe('getAllPermissions', () => {
305
- it('returns empty array for no access', () => {
231
+ it('checks moderation permissions for supporter', () => {
306
232
  mockUseOrganisations.mockReturnValue({
307
- ...mockOrganisationContext,
308
- getUserRole: vi.fn().mockReturnValue('no_access'),
309
- validateOrganisationAccess: vi.fn().mockReturnValue(false)
310
- });
233
+ selectedOrganisation: mockSelectedOrganisation,
234
+ getUserRole: vi.fn().mockReturnValue('supporter'),
235
+ validateOrganisationAccess: vi.fn().mockReturnValue(true),
236
+ // Add other required properties
237
+ } as any);
311
238
 
312
239
  const { result } = renderHook(() => useOrganisationPermissions());
313
240
 
314
- expect(result.current.getAllPermissions()).toEqual([]);
241
+ expect(result.current.canModerate).toBe(false);
242
+ expect(result.current.canManageMembers).toBe(false);
243
+ expect(result.current.canManageSettings).toBe(false);
244
+ expect(result.current.canManageEvents).toBe(false);
315
245
  });
246
+ });
316
247
 
317
- it('returns correct permissions for supporter', () => {
318
- mockUseOrganisations.mockReturnValue({
319
- ...mockOrganisationContext,
320
- getUserRole: vi.fn().mockReturnValue('supporter'),
321
- validateOrganisationAccess: vi.fn().mockReturnValue(true),
322
- ensureOrganisationContext: vi.fn().mockReturnValue(mockOrganisation)
323
- });
248
+ describe('Permission Management', () => {
249
+ it('checks specific permissions', () => {
250
+ mockUseOrganisations.mockReturnValue(createMockOrganisations({
251
+ getUserRole: vi.fn().mockReturnValue('org_admin')
252
+ }) as any);
324
253
 
325
254
  const { result } = renderHook(() => useOrganisationPermissions());
326
255
 
327
- expect(result.current.getAllPermissions()).toEqual(['view_basic']);
256
+ expect(result.current.hasPermission('manage_organisation')).toBe(true);
257
+ expect(result.current.hasPermission('manage_members')).toBe(true);
258
+ expect(result.current.hasPermission('manage_events')).toBe(true);
328
259
  });
329
260
 
330
- it('returns correct permissions for member', () => {
261
+ it('returns false for permissions user does not have', () => {
331
262
  mockUseOrganisations.mockReturnValue({
332
- ...mockOrganisationContext,
263
+ selectedOrganisation: mockSelectedOrganisation,
333
264
  getUserRole: vi.fn().mockReturnValue('member'),
334
265
  validateOrganisationAccess: vi.fn().mockReturnValue(true),
335
- ensureOrganisationContext: vi.fn().mockReturnValue(mockOrganisation)
336
- });
266
+ // Add other required properties
267
+ } as any);
337
268
 
338
269
  const { result } = renderHook(() => useOrganisationPermissions());
339
270
 
340
- expect(result.current.getAllPermissions()).toEqual(['view_basic', 'view_details']);
271
+ expect(result.current.hasPermission('manage_organisation')).toBe(false);
272
+ expect(result.current.hasPermission('manage_members')).toBe(false);
273
+ expect(result.current.hasPermission('manage_events')).toBe(false);
341
274
  });
342
275
 
343
- it('returns correct permissions for leader', () => {
344
- mockUseOrganisations.mockReturnValue({
345
- ...mockOrganisationContext,
346
- getUserRole: vi.fn().mockReturnValue('leader'),
347
- validateOrganisationAccess: vi.fn().mockReturnValue(true),
348
- ensureOrganisationContext: vi.fn().mockReturnValue(mockOrganisation)
349
- });
276
+ it('gets all permissions for user', () => {
277
+ mockUseOrganisations.mockReturnValue(createMockOrganisations({
278
+ getUserRole: vi.fn().mockReturnValue('org_admin')
279
+ }) as any);
350
280
 
351
281
  const { result } = renderHook(() => useOrganisationPermissions());
352
282
 
353
- expect(result.current.getAllPermissions()).toEqual([
354
- 'view_basic',
355
- 'view_details',
356
- 'moderate_content',
357
- 'manage_events'
358
- ]);
283
+ const permissions = result.current.getAllPermissions();
284
+ expect(Array.isArray(permissions)).toBe(true);
285
+ expect(permissions.length).toBeGreaterThan(0);
359
286
  });
360
287
 
361
- it('returns correct permissions for org_admin', () => {
288
+ it('returns empty array for users with no permissions', () => {
362
289
  mockUseOrganisations.mockReturnValue({
363
- ...mockOrganisationContext,
364
- getUserRole: vi.fn().mockReturnValue('org_admin'),
290
+ selectedOrganisation: mockSelectedOrganisation,
291
+ getUserRole: vi.fn().mockReturnValue('supporter'),
365
292
  validateOrganisationAccess: vi.fn().mockReturnValue(true),
366
- ensureOrganisationContext: vi.fn().mockReturnValue(mockOrganisation)
367
- });
293
+ // Add other required properties
294
+ } as any);
368
295
 
369
296
  const { result } = renderHook(() => useOrganisationPermissions());
370
297
 
371
- expect(result.current.getAllPermissions()).toEqual([
372
- 'view_basic',
373
- 'view_details',
374
- 'moderate_content',
375
- 'manage_events',
376
- 'manage_members',
377
- 'manage_settings'
378
- ]);
298
+ const permissions = result.current.getAllPermissions();
299
+ expect(Array.isArray(permissions)).toBe(true);
300
+ expect(permissions.length).toBe(0);
379
301
  });
380
302
  });
381
303
 
382
- describe('Organisation Access Validation', () => {
383
- it('returns false when organisation access is invalid', () => {
384
- mockUseOrganisations.mockReturnValue({
385
- ...mockOrganisationContext,
386
- getUserRole: vi.fn().mockReturnValue('member'),
387
- validateOrganisationAccess: vi.fn().mockReturnValue(false)
388
- });
304
+ describe('Organisation Access', () => {
305
+ it('validates organisation access for valid user', () => {
306
+ mockUseOrganisations.mockReturnValue(createMockOrganisations({
307
+ getUserRole: vi.fn().mockReturnValue('member')
308
+ }) as any);
389
309
 
390
310
  const { result } = renderHook(() => useOrganisationPermissions());
391
311
 
392
- expect(result.current.hasOrganisationAccess).toBe(false);
312
+ expect(result.current.hasOrganisationAccess).toBe(true);
393
313
  });
394
314
 
395
- it('returns true when organisation access is valid', () => {
315
+ it('denies access for invalid user', () => {
396
316
  mockUseOrganisations.mockReturnValue({
397
- ...mockOrganisationContext,
398
- getUserRole: vi.fn().mockReturnValue('member'),
399
- validateOrganisationAccess: vi.fn().mockReturnValue(true),
400
- ensureOrganisationContext: vi.fn().mockReturnValue(mockOrganisation)
401
- });
317
+ selectedOrganisation: mockSelectedOrganisation,
318
+ getUserRole: vi.fn().mockReturnValue('no_access'),
319
+ validateOrganisationAccess: vi.fn().mockResolvedValue(false),
320
+ // Add other required properties
321
+ } as any);
402
322
 
403
323
  const { result } = renderHook(() => useOrganisationPermissions());
404
324
 
405
- expect(result.current.hasOrganisationAccess).toBe(true);
325
+ expect(result.current.hasOrganisationAccess).toBe(false);
406
326
  });
407
- });
408
327
 
409
- describe('Edge Cases', () => {
410
- it('handles missing organisation context gracefully', () => {
328
+ it('handles missing organisation context', () => {
411
329
  mockUseOrganisations.mockReturnValue({
412
- ...mockOrganisationContext,
413
330
  selectedOrganisation: null,
414
- hasValidOrganisationContext: false,
415
- ensureOrganisationContext: vi.fn().mockImplementation(() => {
416
- throw new Error('No organisation context');
417
- })
418
- });
331
+ getUserRole: vi.fn().mockReturnValue('no_access'),
332
+ validateOrganisationAccess: vi.fn().mockResolvedValue(false),
333
+ // Add other required properties
334
+ } as any);
419
335
 
420
336
  const { result } = renderHook(() => useOrganisationPermissions());
421
337
 
422
- expect(result.current.organisationId).toBe('');
423
- expect(result.current.userRole).toBe('no_access');
424
338
  expect(result.current.hasOrganisationAccess).toBe(false);
339
+ expect(result.current.organisationId).toBe('');
425
340
  });
341
+ });
426
342
 
427
- it('handles invalid organisation ID', () => {
343
+ describe('Error Handling', () => {
344
+ it('handles missing organisation provider gracefully', () => {
428
345
  mockUseOrganisations.mockReturnValue({
429
- ...mockOrganisationContext,
346
+ selectedOrganisation: null,
430
347
  getUserRole: vi.fn().mockReturnValue('no_access'),
431
- validateOrganisationAccess: vi.fn().mockReturnValue(false)
432
- });
348
+ validateOrganisationAccess: vi.fn().mockResolvedValue(false),
349
+ // Add other required properties
350
+ } as any);
433
351
 
434
- const { result } = renderHook(() => useOrganisationPermissions('invalid-org'));
352
+ const { result } = renderHook(() => useOrganisationPermissions());
435
353
 
436
- expect(result.current.organisationId).toBe('invalid-org');
437
- expect(result.current.userRole).toBe('no_access');
354
+ expect(result.current).toBeDefined();
438
355
  expect(result.current.hasOrganisationAccess).toBe(false);
439
356
  });
440
357
 
441
- it('handles undefined organisation ID parameter', () => {
442
- mockUseOrganisations.mockReturnValue({
443
- ...mockOrganisationContext,
444
- getUserRole: vi.fn().mockReturnValue('member'),
445
- validateOrganisationAccess: vi.fn().mockReturnValue(true),
446
- ensureOrganisationContext: vi.fn().mockReturnValue(mockOrganisation)
447
- });
358
+ it('handles invalid role gracefully', () => {
359
+ mockUseOrganisations.mockReturnValue(createMockOrganisations({
360
+ getUserRole: vi.fn().mockReturnValue('invalid_role')
361
+ }) as any);
448
362
 
449
- const { result } = renderHook(() => useOrganisationPermissions(undefined));
363
+ const { result } = renderHook(() => useOrganisationPermissions());
450
364
 
451
- expect(result.current.organisationId).toBe('org-123');
365
+ expect(result.current.userRole).toBe('no_access');
366
+ expect(result.current.isOrgAdmin).toBe(false);
367
+ expect(result.current.hasAdminPrivileges).toBe(false);
452
368
  });
453
369
  });
454
370
 
455
- describe('Memoization', () => {
456
- it('maintains stable references when dependencies do not change', () => {
457
- mockUseOrganisations.mockReturnValue({
458
- ...mockOrganisationContext,
459
- getUserRole: vi.fn().mockReturnValue('member'),
460
- validateOrganisationAccess: vi.fn().mockReturnValue(true),
461
- ensureOrganisationContext: vi.fn().mockReturnValue(mockOrganisation)
462
- });
463
-
371
+ describe('Performance', () => {
372
+ it('memoizes results to prevent unnecessary re-renders', () => {
464
373
  const { result, rerender } = renderHook(() => useOrganisationPermissions());
465
-
466
- const firstResult = result.current;
374
+
375
+ // Get the initial result
376
+ const initialResult = result.current;
377
+
378
+ // Re-render with same props
467
379
  rerender();
468
- const secondResult = result.current;
469
-
470
- expect(firstResult.hasPermission).toBe(secondResult.hasPermission);
471
- expect(firstResult.getAllPermissions).toBe(secondResult.getAllPermissions);
380
+
381
+ // The result should be the same object due to memoization
382
+ expect(result.current).toBe(initialResult);
472
383
  });
473
384
 
474
- it('updates when organisation context changes', () => {
385
+ it('handles role changes efficiently', () => {
386
+ const mockGetUserRole = vi.fn().mockReturnValue('member');
387
+ mockUseOrganisations.mockReturnValue(createMockOrganisations({
388
+ getUserRole: mockGetUserRole
389
+ }) as any);
390
+
475
391
  const { result, rerender } = renderHook(() => useOrganisationPermissions());
476
392
 
477
- // Initial state
478
- mockUseOrganisations.mockReturnValue({
479
- ...mockOrganisationContext,
480
- getUserRole: vi.fn().mockReturnValue('member'),
481
- validateOrganisationAccess: vi.fn().mockReturnValue(true),
482
- ensureOrganisationContext: vi.fn().mockReturnValue(mockOrganisation)
483
- });
393
+ expect(result.current.userRole).toBe('member');
484
394
 
395
+ // Change role by updating the mock setup
396
+ mockUseOrganisations.mockReturnValue(createMockOrganisations({
397
+ getUserRole: vi.fn().mockReturnValue('org_admin')
398
+ }) as any);
485
399
  rerender();
486
400
 
487
- expect(result.current.userRole).toBe('member');
401
+ expect(result.current.userRole).toBe('org_admin');
402
+ expect(result.current.isOrgAdmin).toBe(true);
403
+ });
404
+ });
488
405
 
489
- // Change role
490
- mockUseOrganisations.mockReturnValue({
491
- ...mockOrganisationContext,
492
- getUserRole: vi.fn().mockReturnValue('leader'),
493
- validateOrganisationAccess: vi.fn().mockReturnValue(true),
494
- ensureOrganisationContext: vi.fn().mockReturnValue(mockOrganisation)
495
- });
406
+ describe('Integration with Organisation Provider', () => {
407
+ it('integrates with useOrganisations hook correctly', () => {
408
+ renderHook(() => useOrganisationPermissions());
409
+ expect(mockUseOrganisations).toHaveBeenCalled();
410
+ });
496
411
 
497
- rerender();
412
+ it('uses selected organisation from provider', () => {
413
+ const { result } = renderHook(() => useOrganisationPermissions());
498
414
 
499
- expect(result.current.userRole).toBe('leader');
415
+ expect(result.current.organisationId).toBe('org-123');
500
416
  });
501
- });
502
417
 
503
- describe('Type Safety', () => {
504
- it('returns correct types for all properties', () => {
505
- mockUseOrganisations.mockReturnValue({
506
- ...mockOrganisationContext,
418
+ it('uses specific organisation when provided', () => {
419
+ const { result } = renderHook(() => useOrganisationPermissions('org-456'));
420
+
421
+ expect(result.current.organisationId).toBe('org-456');
422
+ });
423
+
424
+ it('validates organisation access through provider', () => {
425
+ const mockValidateAccess = vi.fn().mockReturnValue(true);
426
+ mockUseOrganisations.mockReturnValue(createMockOrganisations({
507
427
  getUserRole: vi.fn().mockReturnValue('member'),
508
- validateOrganisationAccess: vi.fn().mockReturnValue(true),
509
- ensureOrganisationContext: vi.fn().mockReturnValue(mockOrganisation)
510
- });
428
+ validateOrganisationAccess: mockValidateAccess
429
+ }) as any);
511
430
 
512
431
  const { result } = renderHook(() => useOrganisationPermissions());
513
432
 
514
- expect(typeof result.current.userRole).toBe('string');
515
- expect(typeof result.current.organisationId).toBe('string');
516
- expect(typeof result.current.hasOrganisationAccess).toBe('boolean');
517
- expect(typeof result.current.isOrgAdmin).toBe('boolean');
518
- expect(typeof result.current.isSuperAdmin).toBe('boolean');
519
- expect(typeof result.current.canModerate).toBe('boolean');
520
- expect(typeof result.current.canManageMembers).toBe('boolean');
521
- expect(typeof result.current.canManageSettings).toBe('boolean');
522
- expect(typeof result.current.canManageEvents).toBe('boolean');
523
- expect(typeof result.current.hasAdminPrivileges).toBe('boolean');
524
- expect(typeof result.current.hasPermission).toBe('function');
525
- expect(typeof result.current.getAllPermissions).toBe('function');
433
+ // The hook should call validateOrganisationAccess when checking hasOrganisationAccess
434
+ expect(result.current.hasOrganisationAccess).toBe(true);
435
+ expect(mockValidateAccess).toHaveBeenCalledWith('org-123');
526
436
  });
527
437
  });
528
- });
438
+ });