@jmruthers/pace-core 0.5.76 → 0.5.78

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 (447) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/{RBACService-C4udt_Zp.d.ts → AuthService-Df3IozMG.d.ts} +10 -118
  3. package/dist/{DataTable-ntgmhO2W.d.ts → DataTable-BE0OXZKQ.d.ts} +9 -2
  4. package/dist/{DataTable-4GAVPIEG.js → DataTable-ETGVF4Y5.js} +50 -13
  5. package/dist/{PublicLoadingSpinner-BiNER8F5.d.ts → PublicLoadingSpinner-CnUaz0vG.d.ts} +5 -2
  6. package/dist/{UnifiedAuthProvider-Bj6YCf7c.d.ts → UnifiedAuthProvider-B391Aqum.d.ts} +42 -45
  7. package/dist/{UnifiedAuthProvider-3NKDOSOK.js → UnifiedAuthProvider-P5SOJAQ6.js} +4 -5
  8. package/dist/{api-DDMUKIUD.js → api-KG4A2X7P.js} +9 -3
  9. package/dist/{audit-6TOCAMKO.js → audit-65VNHEV2.js} +2 -2
  10. package/dist/{chunk-K34IM5CT.js → chunk-2OGV6IRV.js} +196 -626
  11. package/dist/chunk-2OGV6IRV.js.map +1 -0
  12. package/dist/{chunk-NTNILOBC.js → chunk-5BO3MI5Y.js} +4 -4
  13. package/dist/{chunk-XLZ7U46Z.js → chunk-CVMVPYAL.js} +9 -60
  14. package/dist/chunk-CVMVPYAL.js.map +1 -0
  15. package/dist/{chunk-URUTVZ7N.js → chunk-FL4ZCQLD.js} +2 -2
  16. package/dist/{chunk-LW7MMEAQ.js → chunk-FT2M4R4F.js} +2 -2
  17. package/dist/{chunk-5BSLGBYI.js → chunk-JCQZ6LA7.js} +2 -8
  18. package/dist/{chunk-5BSLGBYI.js.map → chunk-JCQZ6LA7.js.map} +1 -1
  19. package/dist/{chunk-KHJS6VIA.js → chunk-LRQ6RBJC.js} +157 -112
  20. package/dist/chunk-LRQ6RBJC.js.map +1 -0
  21. package/dist/{chunk-WN6XJWOS.js → chunk-MNJXXD6C.js} +274 -743
  22. package/dist/chunk-MNJXXD6C.js.map +1 -0
  23. package/dist/{chunk-KK73ZB4E.js → chunk-PTR5PMPE.js} +153 -132
  24. package/dist/chunk-PTR5PMPE.js.map +1 -0
  25. package/dist/{chunk-B2WTCLCV.js → chunk-Q7APDV6H.js} +18 -8
  26. package/dist/chunk-Q7APDV6H.js.map +1 -0
  27. package/dist/{chunk-A4FUBC7B.js → chunk-QGVSOUJ2.js} +2 -4
  28. package/dist/{chunk-A4FUBC7B.js.map → chunk-QGVSOUJ2.js.map} +1 -1
  29. package/dist/{chunk-FGMFQSHX.js → chunk-S63MFSY6.js} +500 -551
  30. package/dist/chunk-S63MFSY6.js.map +1 -0
  31. package/dist/{chunk-AFGTSUAD.js → chunk-VSOKOFRF.js} +4 -4
  32. package/dist/chunk-WUXCWRL6.js +20 -0
  33. package/dist/chunk-WUXCWRL6.js.map +1 -0
  34. package/dist/{chunk-Y6TXWPJO.js → chunk-YVVGHRGI.js} +105 -31
  35. package/dist/chunk-YVVGHRGI.js.map +1 -0
  36. package/dist/{chunk-M5IWZRBT.js → chunk-ZMNXIJP4.js} +2187 -981
  37. package/dist/chunk-ZMNXIJP4.js.map +1 -0
  38. package/dist/components.d.ts +6 -6
  39. package/dist/components.js +14 -18
  40. package/dist/components.js.map +1 -1
  41. package/dist/{database-C3Szpi5J.d.ts → database-BXAfr2Y_.d.ts} +18 -0
  42. package/dist/hooks.d.ts +5 -5
  43. package/dist/hooks.js +8 -9
  44. package/dist/hooks.js.map +1 -1
  45. package/dist/index.d.ts +19 -27
  46. package/dist/index.js +21 -29
  47. package/dist/index.js.map +1 -1
  48. package/dist/{organisation-BtshODVF.d.ts → organisation-D6qRDtbF.d.ts} +1 -1
  49. package/dist/providers.d.ts +7 -21
  50. package/dist/providers.js +3 -10
  51. package/dist/rbac/index.d.ts +71 -221
  52. package/dist/rbac/index.js +15 -16
  53. package/dist/{types-CGX9Vyf5.d.ts → types-BDg1mAGG.d.ts} +36 -6
  54. package/dist/types.d.ts +3 -3
  55. package/dist/types.js +61 -18
  56. package/dist/types.js.map +1 -1
  57. package/dist/{unified-CM7T0aTK.d.ts → unified-DQ4VcT7H.d.ts} +1 -1
  58. package/dist/{usePublicRouteParams-B-CumWRc.d.ts → usePublicRouteParams-BlgwXweB.d.ts} +3 -3
  59. package/dist/utils.d.ts +2 -2
  60. package/dist/utils.js +52 -9
  61. package/dist/utils.js.map +1 -1
  62. package/docs/CONTENT_AUDIT_REPORT.md +253 -0
  63. package/docs/DOCUMENTATION_AUDIT.md +172 -0
  64. package/docs/README.md +142 -147
  65. package/docs/STYLE_GUIDE.md +37 -0
  66. package/docs/api/classes/ColumnFactory.md +17 -17
  67. package/docs/api/classes/ErrorBoundary.md +1 -1
  68. package/docs/api/classes/InvalidScopeError.md +4 -4
  69. package/docs/api/classes/MissingUserContextError.md +4 -4
  70. package/docs/api/classes/OrganisationContextRequiredError.md +4 -4
  71. package/docs/api/classes/PermissionDeniedError.md +5 -5
  72. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  73. package/docs/api/classes/RBACAuditManager.md +8 -8
  74. package/docs/api/classes/RBACCache.md +35 -5
  75. package/docs/api/classes/RBACEngine.md +49 -20
  76. package/docs/api/classes/RBACError.md +4 -4
  77. package/docs/api/classes/RBACNotInitializedError.md +4 -4
  78. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  79. package/docs/api/classes/StorageUtils.md +1 -1
  80. package/docs/api/enums/FileCategory.md +1 -1
  81. package/docs/api/interfaces/AggregateConfig.md +4 -4
  82. package/docs/api/interfaces/ButtonProps.md +1 -1
  83. package/docs/api/interfaces/CardProps.md +1 -1
  84. package/docs/api/interfaces/ColorPalette.md +1 -1
  85. package/docs/api/interfaces/ColorShade.md +1 -1
  86. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  87. package/docs/api/interfaces/DataRecord.md +11 -0
  88. package/docs/api/interfaces/DataTableAction.md +65 -29
  89. package/docs/api/interfaces/DataTableColumn.md +36 -23
  90. package/docs/api/interfaces/DataTableProps.md +80 -38
  91. package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
  92. package/docs/api/interfaces/EmptyStateConfig.md +5 -5
  93. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  94. package/docs/api/interfaces/EventLogoProps.md +1 -1
  95. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  96. package/docs/api/interfaces/FileMetadata.md +1 -1
  97. package/docs/api/interfaces/FileReference.md +1 -1
  98. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  99. package/docs/api/interfaces/FileUploadOptions.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 +11 -11
  107. package/docs/api/interfaces/NavigationContextType.md +9 -9
  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 +7 -7
  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 +16 -3
  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 +2 -2
  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/RBACLogger.md +1 -1
  133. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  134. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  135. package/docs/api/interfaces/RouteAccessRecord.md +2 -2
  136. package/docs/api/interfaces/RouteConfig.md +2 -2
  137. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  138. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  139. package/docs/api/interfaces/StorageConfig.md +1 -1
  140. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  141. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  142. package/docs/api/interfaces/StorageListOptions.md +1 -1
  143. package/docs/api/interfaces/StorageListResult.md +1 -1
  144. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  145. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  146. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  147. package/docs/api/interfaces/StyleImport.md +1 -1
  148. package/docs/api/interfaces/SwitchProps.md +1 -1
  149. package/docs/api/interfaces/ToastActionElement.md +1 -1
  150. package/docs/api/interfaces/ToastProps.md +1 -1
  151. package/docs/api/interfaces/UnifiedAuthContextType.md +94 -521
  152. package/docs/api/interfaces/UnifiedAuthProviderProps.md +16 -16
  153. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  154. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  155. package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
  156. package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
  157. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  158. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  159. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  160. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  161. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  162. package/docs/api/interfaces/UserEventAccess.md +11 -11
  163. package/docs/api/interfaces/UserMenuProps.md +1 -1
  164. package/docs/api/interfaces/UserProfile.md +1 -1
  165. package/docs/api/modules.md +251 -269
  166. package/docs/api-reference/components.md +193 -0
  167. package/docs/api-reference/hooks.md +265 -0
  168. package/docs/api-reference/providers.md +6 -0
  169. package/docs/api-reference/types.md +6 -0
  170. package/docs/api-reference/utilities.md +207 -0
  171. package/docs/architecture/README.md +6 -0
  172. package/docs/{database-schema-requirements.md → architecture/database-schema-requirements.md} +6 -0
  173. package/docs/architecture/rbac-security-architecture.md +258 -0
  174. package/docs/architecture/services.md +9 -1
  175. package/docs/best-practices/README.md +6 -0
  176. package/docs/best-practices/accessibility.md +6 -0
  177. package/docs/{common-patterns.md → best-practices/common-patterns.md} +6 -0
  178. package/docs/best-practices/deployment.md +6 -0
  179. package/docs/best-practices/performance.md +475 -2
  180. package/docs/best-practices/security.md +6 -0
  181. package/docs/best-practices/testing.md +6 -0
  182. package/docs/core-concepts/authentication.md +6 -0
  183. package/docs/core-concepts/events.md +6 -0
  184. package/docs/core-concepts/organisations.md +6 -0
  185. package/docs/core-concepts/permissions.md +6 -0
  186. package/docs/core-concepts/rbac-system.md +8 -0
  187. package/docs/documentation-index.md +121 -182
  188. package/docs/{consuming-app-vite-config.md → getting-started/consuming-app-vite-config.md} +6 -0
  189. package/docs/getting-started/documentation-index.md +40 -0
  190. package/docs/getting-started/examples/README.md +878 -35
  191. package/docs/{faq.md → getting-started/faq.md} +7 -1
  192. package/docs/getting-started/installation-guide.md +6 -0
  193. package/docs/{quick-reference.md → getting-started/quick-reference.md} +6 -0
  194. package/docs/implementation-guides/app-layout.md +6 -0
  195. package/docs/implementation-guides/authentication.md +1021 -0
  196. package/docs/implementation-guides/component-styling.md +6 -0
  197. package/docs/implementation-guides/data-tables.md +1264 -2076
  198. package/docs/implementation-guides/dynamic-colors.md +6 -0
  199. package/docs/implementation-guides/event-theming-summary.md +6 -0
  200. package/docs/{file-reference-system.md → implementation-guides/file-reference-system.md} +6 -0
  201. package/docs/implementation-guides/file-upload-storage.md +6 -0
  202. package/docs/implementation-guides/forms.md +6 -0
  203. package/docs/implementation-guides/inactivity-tracking.md +6 -0
  204. package/docs/implementation-guides/navigation.md +6 -0
  205. package/docs/implementation-guides/organisation-security.md +6 -0
  206. package/docs/implementation-guides/permission-enforcement.md +6 -0
  207. package/docs/implementation-guides/public-pages-advanced.md +6 -0
  208. package/docs/implementation-guides/public-pages.md +6 -0
  209. package/docs/migration/MIGRATION_GUIDE.md +827 -351
  210. package/docs/migration/README.md +7 -1
  211. package/docs/migration/organisation-context-timing-fix.md +6 -0
  212. package/docs/migration/rbac-migration.md +44 -1
  213. package/docs/migration/service-architecture.md +6 -0
  214. package/docs/migration/v0.4.15-tailwind-scanning.md +6 -0
  215. package/docs/migration/v0.4.16-css-first-approach.md +6 -0
  216. package/docs/migration/v0.4.17-source-path-fix.md +6 -0
  217. package/docs/rbac/README-rbac-rls-integration.md +6 -0
  218. package/docs/rbac/README.md +6 -0
  219. package/docs/rbac/advanced-patterns.md +6 -0
  220. package/docs/rbac/api-reference.md +7 -1
  221. package/docs/rbac/breaking-changes-v3.md +222 -0
  222. package/docs/rbac/examples/rbac-rls-integration-example.md +6 -0
  223. package/docs/rbac/examples.md +6 -0
  224. package/docs/rbac/getting-started.md +6 -0
  225. package/docs/rbac/migration-guide.md +260 -0
  226. package/docs/rbac/quick-start.md +70 -13
  227. package/docs/rbac/rbac-rls-integration.md +6 -0
  228. package/docs/rbac/super-admin-guide.md +6 -0
  229. package/docs/rbac/troubleshooting.md +6 -0
  230. package/docs/security/README.md +6 -0
  231. package/docs/security/checklist.md +6 -0
  232. package/docs/styles/README.md +7 -1
  233. package/docs/{usage.md → styles/usage.md} +6 -0
  234. package/docs/testing/README.md +6 -0
  235. package/docs/{visual-testing.md → testing/visual-testing.md} +6 -0
  236. package/docs/troubleshooting/README.md +387 -5
  237. package/docs/troubleshooting/cake-page-permission-guard-issue-summary.md +6 -0
  238. package/docs/troubleshooting/common-issues.md +6 -0
  239. package/docs/troubleshooting/database-view-compatibility.md +6 -0
  240. package/docs/troubleshooting/organisation-context-setup.md +6 -0
  241. package/docs/troubleshooting/react-hooks-issue-analysis.md +6 -0
  242. package/docs/troubleshooting/styling-issues.md +6 -0
  243. package/docs/troubleshooting/tailwind-content-scanning.md +6 -0
  244. package/package.json +1 -1
  245. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -1
  246. package/src/__tests__/helpers/test-providers.tsx +3 -53
  247. package/src/components/DataTable/DataTable.test.tsx +319 -0
  248. package/src/components/DataTable/DataTable.tsx +32 -11
  249. package/src/components/DataTable/__tests__/{DataTable.comprehensive.test.tsx → DataTable.comprehensive.test.tsx.skip} +6 -4
  250. package/src/components/DataTable/__tests__/{DataTable.test.tsx → DataTable.test.tsx.skip} +6 -4
  251. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +31 -9
  252. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +601 -0
  253. package/src/components/DataTable/__tests__/keyboard.test.tsx +615 -0
  254. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +639 -0
  255. package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx.skip +330 -0
  256. package/src/components/DataTable/components/AccessDeniedPage.tsx +2 -2
  257. package/src/components/DataTable/components/ActionButtons.tsx +88 -104
  258. package/src/components/DataTable/components/DataTableCore.tsx +309 -337
  259. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +4 -2
  260. package/src/components/DataTable/components/DataTableModals.tsx +22 -1
  261. package/src/components/DataTable/components/EditableRow.tsx +69 -84
  262. package/src/components/DataTable/components/EmptyState.tsx +5 -1
  263. package/src/components/DataTable/components/ImportModal.tsx +65 -36
  264. package/src/components/DataTable/components/PaginationControls.tsx +40 -100
  265. package/src/components/DataTable/components/UnifiedTableBody.tsx +125 -148
  266. package/src/components/DataTable/context/DataTableContext.tsx +1 -1
  267. package/src/components/DataTable/core/ColumnFactory.ts +5 -0
  268. package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +12 -10
  269. package/src/components/DataTable/examples/HierarchicalExample.tsx +1 -1
  270. package/src/components/DataTable/examples/InitialPageSizeExample.tsx +1 -0
  271. package/src/components/DataTable/examples/PerformanceExample.tsx +1 -0
  272. package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.test.ts +1 -5
  273. package/src/components/DataTable/hooks/__tests__/useColumnVisibilityPersistence.test.ts +167 -0
  274. package/src/components/DataTable/hooks/index.ts +7 -0
  275. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +32 -15
  276. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +102 -0
  277. package/src/components/DataTable/hooks/useDataTableConfiguration.ts +89 -0
  278. package/src/components/DataTable/hooks/useDataTableDataPipeline.ts +117 -0
  279. package/src/components/DataTable/hooks/useDataTablePermissions.ts +71 -27
  280. package/src/components/DataTable/hooks/useDataTableState.ts +39 -11
  281. package/src/components/DataTable/hooks/useEffectiveColumnOrder.ts +33 -0
  282. package/src/components/DataTable/hooks/useHierarchicalState.ts +15 -1
  283. package/src/components/DataTable/hooks/useKeyboardNavigation.ts +447 -0
  284. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +94 -0
  285. package/src/components/DataTable/hooks/useTableColumns.ts +10 -7
  286. package/src/components/DataTable/hooks/useTableHandlers.ts +174 -0
  287. package/src/components/DataTable/index.ts +12 -3
  288. package/src/components/DataTable/types.ts +129 -9
  289. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +159 -22
  290. package/src/components/DataTable/utils/__tests__/flexibleImport.test.ts +111 -0
  291. package/src/components/DataTable/utils/__tests__/rowUtils.test.ts +15 -29
  292. package/src/components/DataTable/utils/a11yUtils.ts +244 -0
  293. package/src/components/DataTable/utils/debugTools.ts +609 -0
  294. package/src/components/DataTable/utils/exportUtils.ts +114 -16
  295. package/src/components/DataTable/utils/flexibleImport.ts +202 -32
  296. package/src/components/DataTable/utils/hierarchicalUtils.ts +1 -1
  297. package/src/components/DataTable/utils/index.ts +2 -0
  298. package/src/components/DataTable/utils/paginationUtils.ts +350 -0
  299. package/src/components/DataTable/utils/rowUtils.ts +6 -5
  300. package/src/components/NavigationMenu/NavigationMenu.test.tsx +19 -24
  301. package/src/components/NavigationMenu/NavigationMenu.tsx +19 -8
  302. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +1 -23
  303. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +56 -6
  304. package/src/components/PaceLoginPage/PaceLoginPage.tsx +137 -13
  305. package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +1 -1
  306. package/src/components/Select/Select.tsx +1 -0
  307. package/src/components/examples/PermissionExample.tsx +173 -0
  308. package/src/examples/CorrectPublicPageImplementation.tsx +301 -0
  309. package/src/examples/PublicEventPage.tsx +274 -0
  310. package/src/examples/PublicPageApp.tsx +308 -0
  311. package/src/examples/PublicPageUsageExample.tsx +216 -0
  312. package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +12 -1
  313. package/src/hooks/__tests__/useOrganisationSecurity.unit.test.tsx +129 -17
  314. package/src/hooks/__tests__/useRBAC.unit.test.ts +151 -846
  315. package/src/hooks/useOrganisationPermissions.test.ts +42 -18
  316. package/src/hooks/useOrganisationPermissions.ts +12 -6
  317. package/src/hooks/useOrganisationSecurity.test.ts +138 -85
  318. package/src/hooks/useOrganisationSecurity.ts +41 -10
  319. package/src/index.ts +0 -1
  320. package/src/providers/AuthProvider.simplified.tsx +880 -0
  321. package/src/providers/UnifiedAuthProvider.test.simple.tsx +8 -8
  322. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +29 -19
  323. package/src/providers/index.ts +0 -1
  324. package/src/providers/services/EventServiceProvider.tsx +19 -15
  325. package/src/providers/services/InactivityServiceProvider.tsx +19 -15
  326. package/src/providers/services/OrganisationServiceProvider.tsx +19 -15
  327. package/src/providers/services/UnifiedAuthProvider.tsx +156 -127
  328. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +1 -1
  329. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +3 -3
  330. package/src/rbac/README.md +1 -1
  331. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +25 -27
  332. package/src/rbac/__tests__/auth-rbac-security.integration.test.tsx +313 -0
  333. package/src/rbac/__tests__/engine.comprehensive.test.ts +114 -348
  334. package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +28 -110
  335. package/src/rbac/__tests__/rbac-engine-simplified.test.ts +33 -85
  336. package/src/rbac/__tests__/scenarios.user-role.test.tsx +2 -2
  337. package/src/rbac/adapters.tsx +26 -69
  338. package/src/rbac/api.test.ts +90 -27
  339. package/src/rbac/api.ts +61 -10
  340. package/src/rbac/audit.test.ts +33 -38
  341. package/src/rbac/audit.ts +21 -6
  342. package/src/rbac/cache.ts +33 -1
  343. package/src/rbac/components/NavigationGuard.tsx +11 -11
  344. package/src/rbac/components/NavigationProvider.test.tsx +11 -5
  345. package/src/rbac/components/NavigationProvider.tsx +37 -13
  346. package/src/rbac/components/PagePermissionGuard.tsx +111 -50
  347. package/src/rbac/components/PagePermissionProvider.tsx +5 -5
  348. package/src/rbac/components/PermissionEnforcer.tsx +11 -11
  349. package/src/rbac/components/RoleBasedRouter.tsx +5 -5
  350. package/src/rbac/components/SecureDataProvider.tsx +5 -5
  351. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +8 -8
  352. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +14 -14
  353. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +12 -12
  354. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +6 -6
  355. package/src/rbac/engine.test.simple.ts +19 -13
  356. package/src/rbac/engine.test.ts +1 -0
  357. package/src/rbac/engine.ts +330 -766
  358. package/src/rbac/errors.ts +156 -0
  359. package/src/rbac/hooks/usePermissions.ts +32 -10
  360. package/src/rbac/hooks/useRBAC.test.ts +126 -512
  361. package/src/rbac/hooks/useRBAC.ts +147 -193
  362. package/src/rbac/hooks/useResolvedScope.ts +12 -0
  363. package/src/rbac/index.ts +7 -4
  364. package/src/rbac/security.ts +109 -18
  365. package/src/rbac/types.ts +12 -1
  366. package/src/services/AuthService.ts +2 -15
  367. package/src/services/EventService.ts +43 -46
  368. package/src/services/OrganisationService.ts +51 -31
  369. package/src/services/__tests__/AuthService.test.ts +1 -1
  370. package/src/services/__tests__/EventService.test.ts +1 -1
  371. package/src/services/__tests__/OrganisationService.test.ts +1 -1
  372. package/src/services/base/BaseService.ts +8 -0
  373. package/src/styles/base.css +208 -0
  374. package/src/styles/semantic.css +24 -0
  375. package/src/types/database.generated.ts +7347 -0
  376. package/src/types/database.ts +20 -0
  377. package/src/utils/logger.ts +179 -0
  378. package/src/utils/organisationContext.ts +11 -4
  379. package/src/utils/storage/__tests__/helpers.unit.test.ts +6 -2
  380. package/dist/appNameResolver-UURKN7NF.js +0 -22
  381. package/dist/audit-6TOCAMKO.js.map +0 -1
  382. package/dist/chunk-B2WTCLCV.js.map +0 -1
  383. package/dist/chunk-FGMFQSHX.js.map +0 -1
  384. package/dist/chunk-K34IM5CT.js.map +0 -1
  385. package/dist/chunk-KHJS6VIA.js.map +0 -1
  386. package/dist/chunk-KK73ZB4E.js.map +0 -1
  387. package/dist/chunk-M5IWZRBT.js.map +0 -1
  388. package/dist/chunk-ULBI5JGB.js +0 -109
  389. package/dist/chunk-ULBI5JGB.js.map +0 -1
  390. package/dist/chunk-WN6XJWOS.js.map +0 -1
  391. package/dist/chunk-XLZ7U46Z.js.map +0 -1
  392. package/dist/chunk-Y6TXWPJO.js.map +0 -1
  393. package/docs/DOCUMENTATION_CHECKLIST.md +0 -281
  394. package/docs/TERMINOLOGY.md +0 -231
  395. package/docs/api/interfaces/RBACContextType.md +0 -468
  396. package/docs/api/interfaces/RBACProviderProps.md +0 -107
  397. package/docs/best-practices/performance-expansion.md +0 -473
  398. package/docs/breaking-changes.md +0 -179
  399. package/docs/consuming-app-example.md +0 -290
  400. package/docs/documentation-templates.md +0 -539
  401. package/docs/examples/navigation-menu-auth-fix.md +0 -344
  402. package/docs/getting-started/examples/basic-auth-app.md +0 -520
  403. package/docs/getting-started/examples/full-featured-app.md +0 -616
  404. package/docs/getting-started/quick-start.md +0 -376
  405. package/docs/implementation-guides/datatable-filtering.md +0 -313
  406. package/docs/implementation-guides/datatable-rbac-usage.md +0 -317
  407. package/docs/implementation-guides/hierarchical-datatable.md +0 -850
  408. package/docs/implementation-guides/large-datasets.md +0 -281
  409. package/docs/implementation-guides/performance.md +0 -403
  410. package/docs/migration/quick-migration-guide.md +0 -320
  411. package/docs/migration-guide.md +0 -193
  412. package/docs/migration-guides/unified-auth-provider-mandatory-timeouts.md +0 -226
  413. package/docs/performance/README.md +0 -551
  414. package/docs/style-guide.md +0 -964
  415. package/docs/troubleshooting/authentication-issues.md +0 -334
  416. package/docs/troubleshooting/debugging.md +0 -1117
  417. package/docs/troubleshooting/migration.md +0 -918
  418. package/src/__tests__/hooks/usePermissions.test.ts +0 -261
  419. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.rbac.test.tsx +0 -574
  420. package/src/hooks/__tests__/ServiceHooks.test.tsx +0 -613
  421. package/src/hooks/services/__tests__/useServiceHooks.test.tsx +0 -137
  422. package/src/hooks/services/usePermissions.ts +0 -70
  423. package/src/hooks/services/useRBACService.ts +0 -30
  424. package/src/hooks/usePermissionCheck.ts +0 -150
  425. package/src/providers/__tests__/ServiceProviders.test.tsx +0 -477
  426. package/src/providers/services/RBACServiceProvider.tsx +0 -79
  427. package/src/rbac/__tests__/integration.authflow.test.tsx +0 -119
  428. package/src/rbac/__tests__/integration.navigation.test.tsx +0 -69
  429. package/src/rbac/__tests__/integration.securedata.test.tsx +0 -92
  430. package/src/rbac/__tests__/integration.smoke.test.tsx +0 -73
  431. package/src/rbac/providers/RBACProvider.tsx +0 -645
  432. package/src/rbac/providers/__tests__/RBACProvider.integration.test.tsx +0 -688
  433. package/src/rbac/providers/__tests__/RBACProvider.test.tsx +0 -1186
  434. package/src/rbac/providers/index.ts +0 -11
  435. package/src/services/RBACService.ts +0 -522
  436. package/src/services/__tests__/RBACService.test.ts +0 -492
  437. package/src/services/interfaces/IRBACService.ts +0 -62
  438. package/src/utils/appNameResolver.test 2.ts +0 -494
  439. /package/dist/{DataTable-4GAVPIEG.js.map → DataTable-ETGVF4Y5.js.map} +0 -0
  440. /package/dist/{UnifiedAuthProvider-3NKDOSOK.js.map → UnifiedAuthProvider-P5SOJAQ6.js.map} +0 -0
  441. /package/dist/{api-DDMUKIUD.js.map → api-KG4A2X7P.js.map} +0 -0
  442. /package/dist/{appNameResolver-UURKN7NF.js.map → audit-65VNHEV2.js.map} +0 -0
  443. /package/dist/{chunk-NTNILOBC.js.map → chunk-5BO3MI5Y.js.map} +0 -0
  444. /package/dist/{chunk-URUTVZ7N.js.map → chunk-FL4ZCQLD.js.map} +0 -0
  445. /package/dist/{chunk-LW7MMEAQ.js.map → chunk-FT2M4R4F.js.map} +0 -0
  446. /package/dist/{chunk-AFGTSUAD.js.map → chunk-VSOKOFRF.js.map} +0 -0
  447. /package/docs/{app.css.example → styles/app.css.example} +0 -0
@@ -1,645 +0,0 @@
1
- /**
2
- * @file RBAC Provider
3
- * @package @jmruthers/pace-core
4
- * @module RBAC/Providers
5
- * @since 0.1.0
6
- *
7
- * Handles role-based access control, permissions, and event access management.
8
- * Separated from UnifiedAuthProvider for better maintainability.
9
- */
10
-
11
- import React, { createContext, useContext, useState, useEffect, useCallback, useMemo } from 'react';
12
- import { type SupabaseClient, type User, type Session } from '@supabase/supabase-js';
13
- import { AccessLevel } from '../../types/unified';
14
- import { DebugLogger } from '../../utils/debugLogger';
15
-
16
- // App configuration type
17
- interface AppConfig {
18
- supports_direct_access: boolean;
19
- requires_event: boolean;
20
- }
21
-
22
- // User event access type - now includes organisation context for security
23
- export interface UserEventAccess {
24
- event_id: string;
25
- event_name: string;
26
- event_description?: string | null;
27
- start_date: string;
28
- end_date: string;
29
- event_status: string;
30
- app_id: string;
31
- access_level: string;
32
- granted_at: string;
33
- organisation_id: string; // MANDATORY for security
34
- }
35
-
36
- // RBAC context type
37
- export interface RBACContextType {
38
- // RBAC state
39
- permissions: Record<string, boolean>;
40
- roles: string[];
41
- accessLevel: AccessLevel;
42
- rbacLoading: boolean;
43
- rbacError: Error | null;
44
- selectedEventId: string | null;
45
- appConfig: AppConfig | null;
46
- userEventAccess: UserEventAccess[];
47
- eventAccessLoading: boolean;
48
-
49
- // Organisation context integration
50
- selectedOrganisationId: string | null;
51
- requireOrganisationContext: () => string; // Throws if no organisation context
52
-
53
- // RBAC methods
54
- hasPermission: (permission: string, orgId?: string) => boolean;
55
- hasAnyPermission: (permissions: string[], orgId?: string) => boolean;
56
- hasAllPermissions: (permissions: string[], orgId?: string) => boolean;
57
- hasRole: (role: string) => boolean;
58
- hasAccessLevel: (level: AccessLevel) => boolean;
59
- canAccess: (resource: string, action: string, orgId?: string) => boolean;
60
- validatePermission: (permission: string, orgId?: string) => Promise<boolean>;
61
- validateAccess: (resource: string, action: string, orgId?: string) => Promise<boolean>;
62
- refreshPermissions: (eventId?: string, orgId?: string) => Promise<void>;
63
- setSelectedEventId: (eventId: string | null) => void;
64
- loadUserEventAccess: (orgId?: string) => Promise<void>;
65
- getUserEventAccess: (eventId: string) => UserEventAccess | undefined;
66
-
67
- // New RBAC system support
68
- rbacEnabled: boolean;
69
- rbacContext?: any; // Will be populated by useRBAC hook when enabled
70
- }
71
-
72
- const RBACContext = createContext<RBACContextType | undefined>(undefined);
73
-
74
- export const useRBAC = () => {
75
- const context = useContext(RBACContext);
76
- if (!context) {
77
- throw new Error('useRBAC must be used within an RBACProvider');
78
- }
79
- return context;
80
- };
81
-
82
- export interface RBACProviderProps {
83
- children: React.ReactNode;
84
- supabaseClient?: SupabaseClient;
85
- user: User | null;
86
- session: Session | null;
87
- appName: string;
88
- enableRBAC?: boolean;
89
- persistState?: boolean;
90
- enablePersistence?: boolean;
91
- requireOrganisationContext?: boolean;
92
- }
93
-
94
- // Storage keys for persistence
95
- const STORAGE_KEYS = {
96
- SELECTED_EVENT: 'pace-core-selected-event',
97
- } as const;
98
-
99
- // Helper function to transform RBAC permissions to the format expected by UnifiedAuthProvider
100
- const transformRBACPermissions = (rbacData: any[], _appName: string) => {
101
- const permissions: Record<string, boolean> = {};
102
- let roles: string[] = [];
103
- let access_level: AccessLevel = AccessLevel.VIEWER;
104
-
105
- if (!rbacData || !Array.isArray(rbacData)) {
106
- return { permissions: {}, roles: ['viewer'], access_level: AccessLevel.VIEWER };
107
- }
108
-
109
- // Check for super admin first
110
- const superAdminPerm = rbacData.find((p: any) => p.permission_type === 'all_permissions');
111
- if (superAdminPerm) {
112
- return {
113
- permissions: { 'all:all': true } as Record<string, boolean>,
114
- roles: ['super'],
115
- access_level: AccessLevel.SUPER
116
- };
117
- }
118
-
119
- // Process event-app permissions
120
- const eventAppPerms = rbacData.filter((p: any) => p.permission_type === 'event_app_access');
121
- if (eventAppPerms.length > 0) {
122
- const role = eventAppPerms[0].role_name;
123
-
124
- // Map RBAC roles to AccessLevel
125
- switch (role) {
126
- case 'event_admin':
127
- access_level = AccessLevel.ADMIN;
128
- roles = ['admin'];
129
- break;
130
- case 'planner':
131
- access_level = AccessLevel.PLANNER;
132
- roles = ['planner'];
133
- break;
134
- case 'participant':
135
- access_level = AccessLevel.PARTICIPANT;
136
- roles = ['participant'];
137
- break;
138
- case 'editor':
139
- access_level = AccessLevel.EDITOR;
140
- roles = ['editor'];
141
- break;
142
- case 'viewer':
143
- default:
144
- access_level = AccessLevel.VIEWER;
145
- roles = ['viewer'];
146
- break;
147
- }
148
-
149
- // For now, we'll set basic permissions based on role
150
- // In a full implementation, you'd want to fetch page-specific permissions
151
- const basePermissions = ['read'];
152
- if (['event_admin', 'planner'].includes(role)) {
153
- basePermissions.push('create', 'update');
154
- }
155
- if (role === 'event_admin') {
156
- basePermissions.push('delete');
157
- }
158
-
159
- // Set permissions for all pages (simplified approach)
160
- // In a real implementation, you'd want to get actual page permissions
161
- basePermissions.forEach(operation => {
162
- permissions[`default:${operation}`] = true;
163
- });
164
- }
165
-
166
- // Process organisation permissions
167
- const orgPerms = rbacData.filter((p: any) => p.permission_type === 'organisation_access');
168
- if (orgPerms.length > 0) {
169
- const role = orgPerms[0].role_name;
170
- if (role === 'org_admin') {
171
- access_level = AccessLevel.ADMIN;
172
- roles = ['admin'];
173
- // Org admins get all permissions
174
- ['create', 'read', 'update', 'delete'].forEach(operation => {
175
- permissions[`default:${operation}`] = true;
176
- });
177
- }
178
- }
179
-
180
- return { permissions, roles, access_level };
181
- };
182
-
183
- export function RBACProvider({
184
- children,
185
- supabaseClient,
186
- user,
187
- session,
188
- appName,
189
- enableRBAC = false,
190
- persistState = true,
191
- enablePersistence,
192
- requireOrganisationContext: _requireOrganisationContext = true,
193
- }: RBACProviderProps) {
194
- // Use enablePersistence if provided, otherwise use persistState
195
- const shouldPersist = enablePersistence !== undefined ? enablePersistence : persistState;
196
-
197
- // RBAC state
198
- const [permissions, setPermissions] = useState<Record<string, boolean>>({});
199
- const [roles, setRoles] = useState<string[]>([]);
200
- const [accessLevel, setAccessLevel] = useState<AccessLevel>(AccessLevel.VIEWER);
201
- const [rbacLoading, setRbacLoading] = useState(false);
202
- const [rbacError, setRbacError] = useState<Error | null>(null);
203
- const [selectedEventId, setSelectedEventId] = useState<string | null>(null);
204
- const [appConfig, setAppConfig] = useState<AppConfig | null>(null);
205
- const [userEventAccess, setUserEventAccess] = useState<UserEventAccess[]>([]);
206
- const [eventAccessLoading, setEventAccessLoading] = useState(false);
207
-
208
- // Organisation context state
209
- const [selectedOrganisationId, _setSelectedOrganisationId] = useState<string | null>(null);
210
-
211
- // Load app configuration on mount and when appName changes
212
- useEffect(() => {
213
- if (!supabaseClient) return;
214
-
215
- const loadAppConfig = async () => {
216
- try {
217
- // Use the same app name resolution as PagePermissionGuard
218
- const { getCurrentAppName } = await import('../../utils/appNameResolver');
219
- const resolvedAppName = getCurrentAppName() || appName;
220
-
221
- // First resolve app name to app_id
222
- const { data: appData, error: appError } = await supabaseClient
223
- .from('rbac_apps')
224
- .select('id')
225
- .eq('name', resolvedAppName)
226
- .eq('is_active', true)
227
- .single();
228
-
229
- if (appError || !appData) {
230
- console.warn('App not found or inactive:', resolvedAppName);
231
- setAppConfig({
232
- supports_direct_access: false, // Field removed from rbac_apps table
233
- requires_event: true
234
- });
235
- return;
236
- }
237
-
238
- const response = await supabaseClient.rpc('get_app_config', {
239
- app_id: appData.id
240
- });
241
-
242
- const { data } = response || {};
243
-
244
- if (data && data.length > 0) {
245
- setAppConfig({
246
- supports_direct_access: false, // Field removed from rbac_apps table
247
- requires_event: data[0].requires_event
248
- });
249
- } else {
250
- // Default configuration if app not found
251
- setAppConfig({
252
- supports_direct_access: false,
253
- requires_event: true
254
- });
255
- }
256
- } catch (error) {
257
- console.warn("Clearing corrupted localStorage data");
258
- if (typeof localStorage !== 'undefined') {
259
- localStorage.removeItem(STORAGE_KEYS.SELECTED_EVENT);
260
- }
261
- console.warn('Failed to load app configuration:', error);
262
- // Default configuration on error
263
- setAppConfig({
264
- supports_direct_access: false, // Field removed from rbac_apps table
265
- requires_event: true
266
- });
267
- }
268
- };
269
-
270
- loadAppConfig();
271
- }, [supabaseClient, appName]);
272
-
273
- // Set super admin roles based on user metadata
274
- useEffect(() => {
275
- // Check if user has super admin role in metadata
276
- const isSuperAdmin = user?.user_metadata?.globalRole === 'super_admin';
277
- if (isSuperAdmin) {
278
- setRoles(['super_admin']);
279
- } else {
280
- setRoles([]);
281
- }
282
- }, [user]);
283
-
284
- // Load persisted auth state on mount
285
- useEffect(() => {
286
- if (!shouldPersist) return;
287
-
288
- try {
289
- const persistedEvent = localStorage.getItem(STORAGE_KEYS.SELECTED_EVENT);
290
- if (persistedEvent) {
291
- setSelectedEventId(JSON.parse(persistedEvent));
292
- }
293
- } catch (error) {
294
- console.warn("Clearing corrupted localStorage data");
295
- localStorage.removeItem(STORAGE_KEYS.SELECTED_EVENT);
296
- }
297
- }, [shouldPersist]);
298
-
299
- // Persist auth state changes
300
- useEffect(() => {
301
- if (!shouldPersist) return;
302
-
303
- try {
304
- if (selectedEventId) {
305
- localStorage.setItem(
306
- STORAGE_KEYS.SELECTED_EVENT,
307
- JSON.stringify(selectedEventId),
308
- );
309
- } else {
310
- localStorage.removeItem(STORAGE_KEYS.SELECTED_EVENT);
311
- }
312
- } catch (error) {
313
- console.warn("Clearing corrupted localStorage data");
314
- localStorage.removeItem(STORAGE_KEYS.SELECTED_EVENT);
315
- console.warn('Failed to persist auth state:', error);
316
- }
317
- }, [selectedEventId, shouldPersist]);
318
-
319
- // Load RBAC data when user is authenticated
320
- const refreshPermissions = useCallback(async (eventId?: string) => {
321
- if (!supabaseClient || !user || !appConfig || !session) {
322
- DebugLogger.log('RBACProvider', 'refreshPermissions: Missing required dependencies, clearing permissions');
323
- setPermissions({});
324
- setRoles([]);
325
- setAccessLevel(AccessLevel.VIEWER);
326
- return;
327
- }
328
-
329
- // Check for super admin first by querying the database
330
- // This ensures we check against the rbac_global_roles table, not just user metadata
331
- const { data: globalRoles } = await supabaseClient
332
- .from('rbac_global_roles')
333
- .select('role')
334
- .eq('user_id', user.id)
335
- .eq('role', 'super_admin')
336
- .lte('valid_from', new Date().toISOString())
337
- .or(`valid_to.is.null,valid_to.gte.${new Date().toISOString()}`)
338
- .limit(1);
339
-
340
- const isSuperAdmin = globalRoles && globalRoles.length > 0;
341
-
342
- if (isSuperAdmin) {
343
- setPermissions({
344
- 'admin:create': true,
345
- 'admin:read': true,
346
- 'admin:update': true,
347
- 'admin:delete': true,
348
- 'users:create': true,
349
- 'users:read': true,
350
- 'users:update': true,
351
- 'users:delete': true,
352
- 'events:create': true,
353
- 'events:read': true,
354
- 'events:update': true,
355
- 'events:delete': true
356
- });
357
- setRoles(['super_admin']);
358
- setAccessLevel(AccessLevel.SUPER);
359
- return;
360
- }
361
-
362
- // Determine if we should load permissions without an event
363
- const shouldLoadDirectPermissions = !eventId && !appConfig.requires_event;
364
- const shouldLoadEventPermissions = eventId;
365
- const shouldClearPermissions = !eventId && appConfig.requires_event;
366
-
367
- // If no eventId and app requires events, clear permissions
368
- if (shouldClearPermissions) {
369
- setPermissions({});
370
- setRoles([]);
371
- setAccessLevel(AccessLevel.VIEWER);
372
- return;
373
- }
374
-
375
- // Only proceed if we should load permissions
376
- if (!shouldLoadDirectPermissions && !shouldLoadEventPermissions) {
377
- return;
378
- }
379
-
380
- setRbacLoading(true);
381
- setRbacError(null);
382
-
383
- try {
384
- // Use the same app name resolution as PagePermissionGuard
385
- const { getCurrentAppName } = await import('../../utils/appNameResolver');
386
- const resolvedAppName = getCurrentAppName() || appName;
387
-
388
- // First resolve app name to app_id
389
- const { data: appData, error: appError } = await supabaseClient
390
- .from('rbac_apps')
391
- .select('id')
392
- .eq('name', resolvedAppName)
393
- .eq('is_active', true)
394
- .single();
395
-
396
- if (appError || !appData) {
397
- console.warn('App not found or inactive:', resolvedAppName);
398
- setRbacLoading(false);
399
- return;
400
- }
401
-
402
- const { data, error } = await supabaseClient.rpc('rbac_permissions_get', {
403
- p_user_id: user.id,
404
- p_app_id: appData.id,
405
- p_event_id: eventId || null,
406
- p_organisation_id: selectedOrganisationId || null
407
- });
408
-
409
- if (error) {
410
- throw error;
411
- }
412
-
413
- const { permissions, roles, access_level } = transformRBACPermissions(data, appName);
414
-
415
- setPermissions(permissions);
416
- setRoles(roles);
417
- setAccessLevel(access_level);
418
- } catch (err: any) {
419
- setRbacError(err);
420
- } finally {
421
- setRbacLoading(false);
422
- }
423
- }, [supabaseClient, user, session, appName, appConfig, selectedOrganisationId]);
424
-
425
- // Load user event access data
426
- const loadUserEventAccess = useCallback(async () => {
427
- if (!supabaseClient || !user || !session) {
428
- DebugLogger.log('RBACProvider', 'loadUserEventAccess: Missing required dependencies, clearing event access');
429
- setUserEventAccess([]);
430
- return;
431
- }
432
-
433
- setEventAccessLoading(true);
434
- try {
435
- // Use the same app name resolution as PagePermissionGuard
436
- const { getCurrentAppName } = await import('../../utils/appNameResolver');
437
- const resolvedAppName = getCurrentAppName() || appName;
438
-
439
- // First resolve app name to app_id
440
- const { data: appData, error: appError } = await supabaseClient
441
- .from('rbac_apps')
442
- .select('id')
443
- .eq('name', resolvedAppName)
444
- .eq('is_active', true)
445
- .single();
446
-
447
- if (appError || !appData) {
448
- console.warn('App not found or inactive:', resolvedAppName);
449
- setEventAccessLoading(false);
450
- return;
451
- }
452
-
453
- const { data, error } = await supabaseClient
454
- .from('rbac_event_app_roles')
455
- .select(`
456
- event_id,
457
- role,
458
- granted_at
459
- `)
460
- .eq('user_id', user.id)
461
- .eq('app_id', appData.id);
462
-
463
- if (error) {
464
- console.error('Failed to load user event access:', error);
465
- setUserEventAccess([]);
466
- return;
467
- }
468
-
469
- const eventAccess = data?.map(item => ({
470
- event_id: item.event_id,
471
- event_name: 'Unknown Event', // Event details not available in this query
472
- event_description: null, // Not available in this schema
473
- start_date: '', // Event date not available in this query
474
- end_date: '', // Event date not available in this query
475
- event_status: 'unknown', // Not available in this schema
476
- app_id: appData.id,
477
- access_level: item.role, // Map role to access_level
478
- granted_at: item.granted_at,
479
- organisation_id: '' // Will be populated from event's organisation_id if needed
480
- })) || [];
481
-
482
- setUserEventAccess(eventAccess);
483
- } catch (error) {
484
- console.warn("Clearing corrupted localStorage data");
485
- localStorage.removeItem(STORAGE_KEYS.SELECTED_EVENT);
486
- console.error('Error loading user event access:', error);
487
- setUserEventAccess([]);
488
- } finally {
489
- setEventAccessLoading(false);
490
- }
491
- }, [supabaseClient, user, session, appName]);
492
-
493
- // Helper function to get access for a specific event
494
- const getUserEventAccess = useCallback((eventId: string) => {
495
- return userEventAccess.find(access => access.event_id === eventId);
496
- }, [userEventAccess]);
497
-
498
- // When the selected event ID changes, user logs in, or app config loads, refresh permissions
499
- useEffect(() => {
500
- // Don't run if user is null (signed out) or no app config
501
- if (!user || !appConfig || !session) {
502
- DebugLogger.log('RBACProvider', 'Skipping permission refresh - no user, session, or app config');
503
- return;
504
- }
505
-
506
- // Check for super admin first - admin override should happen regardless of app configuration
507
- const isSuperAdmin = user?.user_metadata?.globalRole === 'super_admin';
508
- if (isSuperAdmin) {
509
- setPermissions({
510
- 'admin:create': true,
511
- 'admin:read': true,
512
- 'admin:update': true,
513
- 'admin:delete': true,
514
- 'users:create': true,
515
- 'users:read': true,
516
- 'users:update': true,
517
- 'users:delete': true,
518
- 'events:create': true,
519
- 'events:read': true,
520
- 'events:update': true,
521
- 'events:delete': true
522
- });
523
- setRoles(['super_admin']);
524
- setAccessLevel(AccessLevel.ADMIN);
525
- return;
526
- }
527
-
528
- if (selectedEventId) {
529
- // Event-based permissions
530
- refreshPermissions(selectedEventId);
531
- } else if (!appConfig.requires_event) {
532
- // Direct app permissions (no event needed)
533
- refreshPermissions();
534
- } else {
535
- // No event and app requires events - clear permissions
536
- setPermissions({});
537
- setRoles([]);
538
- setAccessLevel(AccessLevel.VIEWER);
539
- }
540
- }, [selectedEventId, user, session, appConfig, refreshPermissions]);
541
-
542
- // Load user event access when user changes
543
- useEffect(() => {
544
- let isMounted = true;
545
-
546
- if (user && session) {
547
- DebugLogger.log('RBACProvider', 'Loading user event access for authenticated user');
548
- loadUserEventAccess().catch(error => {
549
- if (isMounted) {
550
- console.error('Error loading user event access:', error);
551
- }
552
- });
553
- } else {
554
- DebugLogger.log('RBACProvider', 'Clearing user event access - no user or session');
555
- if (isMounted) {
556
- setUserEventAccess([]);
557
- }
558
- }
559
-
560
- return () => {
561
- isMounted = false;
562
- };
563
- }, [user, session, loadUserEventAccess]);
564
-
565
- // Permission methods
566
- const hasPermission = useCallback((permission: string) => {
567
- const hasPerm = !!permissions[permission];
568
- return hasPerm;
569
- }, [permissions]);
570
- const hasAnyPermission = useCallback((perms: string[]) => perms.some(p => !!permissions[p]), [permissions]);
571
- const hasAllPermissions = useCallback((perms: string[]) => perms.every(p => !!permissions[p]), [permissions]);
572
- const hasRole = useCallback((role: string) => {
573
- const isSuperAdmin = user?.user_metadata?.globalRole === 'super_admin';
574
- if (role.toLowerCase() === 'super_admin') {
575
- return isSuperAdmin;
576
- }
577
- return roles.includes(role);
578
- }, [roles, user]);
579
- const hasAccessLevel = useCallback((level: AccessLevel) => {
580
- const levels = Object.values(AccessLevel);
581
- return levels.indexOf(accessLevel) >= levels.indexOf(level);
582
- }, [accessLevel]);
583
- const canAccess = useCallback((resource: string, action: string) => {
584
- const permission = `${resource}:${action}`;
585
- const hasAccess = hasPermission(permission);
586
- return hasAccess;
587
- }, [hasPermission]);
588
- const validatePermission = useCallback(async (permission: string) => hasPermission(permission), [hasPermission]);
589
- const validateAccess = useCallback(async (resource: string, action: string) => {
590
- // Placeholder for more complex logic, e.g., re-validating with backend
591
- return Promise.resolve(canAccess(resource, action));
592
- }, [canAccess]);
593
-
594
- // Memoized context value
595
- const contextValue = useMemo<RBACContextType>(() => ({
596
- permissions,
597
- roles,
598
- accessLevel,
599
- rbacLoading,
600
- rbacError,
601
- selectedEventId,
602
- appConfig,
603
- userEventAccess,
604
- eventAccessLoading,
605
-
606
- // Organisation context
607
- selectedOrganisationId,
608
- requireOrganisationContext: () => {
609
- if (!selectedOrganisationId) {
610
- throw new Error('Organisation context is required but not available');
611
- }
612
- return selectedOrganisationId;
613
- },
614
-
615
- hasPermission,
616
- hasAnyPermission,
617
- hasAllPermissions,
618
- hasRole,
619
- hasAccessLevel,
620
- canAccess,
621
- validatePermission,
622
- validateAccess,
623
- refreshPermissions,
624
- setSelectedEventId,
625
-
626
- // New RBAC system support
627
- rbacEnabled: enableRBAC,
628
- rbacContext: undefined, // Will be populated by useRBAC hook when enabled
629
-
630
- loadUserEventAccess,
631
- getUserEventAccess
632
- }), [
633
- permissions, roles, accessLevel, rbacLoading, rbacError, selectedEventId, appConfig,
634
- userEventAccess, eventAccessLoading, selectedOrganisationId,
635
- hasPermission, hasAnyPermission, hasAllPermissions, hasRole, hasAccessLevel, canAccess,
636
- validatePermission, validateAccess, refreshPermissions, setSelectedEventId,
637
- enableRBAC, loadUserEventAccess, getUserEventAccess
638
- ]);
639
-
640
- return (
641
- <RBACContext.Provider value={contextValue}>
642
- {children}
643
- </RBACContext.Provider>
644
- );
645
- }