@jmruthers/pace-core 0.5.68 → 0.5.70

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 (394) hide show
  1. package/dist/{DataTable-4IUY7BXB.js → DataTable-OSELOGMA.js} +6 -6
  2. package/dist/{PublicLoadingSpinner-DdKXTkCZ.d.ts → PublicLoadingSpinner-DLpF5bbs.d.ts} +78 -2
  3. package/dist/{chunk-OPCWH3A4.js → chunk-4YMVZ76F.js} +7 -6
  4. package/dist/chunk-4YMVZ76F.js.map +1 -0
  5. package/dist/{chunk-NN45OBIS.js → chunk-5G7JA3L5.js} +3 -5
  6. package/dist/{chunk-NN45OBIS.js.map → chunk-5G7JA3L5.js.map} +1 -1
  7. package/dist/{chunk-U6GPOF6J.js → chunk-5NV76BYF.js} +666 -110
  8. package/dist/chunk-5NV76BYF.js.map +1 -0
  9. package/dist/{chunk-D7ARGIA3.js → chunk-6RBH67W7.js} +23 -6
  10. package/dist/chunk-6RBH67W7.js.map +1 -0
  11. package/dist/{chunk-ZPG4XPV5.js → chunk-BHBMXMLT.js} +5 -7
  12. package/dist/chunk-BHBMXMLT.js.map +1 -0
  13. package/dist/{chunk-ZMS23NS5.js → chunk-FOT3WUV6.js} +3 -5
  14. package/dist/{chunk-ZMS23NS5.js.map → chunk-FOT3WUV6.js.map} +1 -1
  15. package/dist/{chunk-MOJXHWDE.js → chunk-GCUIIBLB.js} +382 -5
  16. package/dist/chunk-GCUIIBLB.js.map +1 -0
  17. package/dist/{chunk-PXWEDX7Y.js → chunk-KWQH4VO3.js} +3 -3
  18. package/dist/{chunk-ZPK5656W.js → chunk-O3NWNXDY.js} +4 -5
  19. package/dist/chunk-O3NWNXDY.js.map +1 -0
  20. package/dist/{chunk-KRCRNXPD.js → chunk-OTJUAYBG.js} +81 -18
  21. package/dist/chunk-OTJUAYBG.js.map +1 -0
  22. package/dist/chunk-SMJZMKYN.js +141 -0
  23. package/dist/chunk-SMJZMKYN.js.map +1 -0
  24. package/dist/{chunk-UYA6U6H7.js → chunk-V2TE7LOF.js} +4 -4
  25. package/dist/{chunk-L3RV2ALE.js → chunk-VKOCWWVY.js} +6 -1
  26. package/dist/{chunk-L3RV2ALE.js.map → chunk-VKOCWWVY.js.map} +1 -1
  27. package/dist/components.d.ts +4 -79
  28. package/dist/components.js +23 -581
  29. package/dist/components.js.map +1 -1
  30. package/dist/hooks.d.ts +1 -1
  31. package/dist/hooks.js +9 -6
  32. package/dist/hooks.js.map +1 -1
  33. package/dist/index.d.ts +4 -3
  34. package/dist/index.js +32 -19
  35. package/dist/index.js.map +1 -1
  36. package/dist/providers.js +6 -7
  37. package/dist/rbac/index.js +6 -6
  38. package/dist/styles/index.js +2 -2
  39. package/dist/theming/runtime.d.ts +4 -3
  40. package/dist/theming/runtime.js +3 -1
  41. package/dist/{usePublicRouteParams-CdoFxnJK.d.ts → usePublicRouteParams-Ua1Vz-HG.d.ts} +35 -1
  42. package/dist/utils.d.ts +4 -1
  43. package/dist/utils.js +3 -3
  44. package/docs/DOCUMENTATION_CHECKLIST.md +281 -0
  45. package/docs/README.md +22 -10
  46. package/docs/api/classes/ColumnFactory.md +1 -1
  47. package/docs/api/classes/ErrorBoundary.md +1 -1
  48. package/docs/api/classes/InvalidScopeError.md +1 -1
  49. package/docs/api/classes/MissingUserContextError.md +1 -1
  50. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  51. package/docs/api/classes/PermissionDeniedError.md +1 -1
  52. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  53. package/docs/api/classes/RBACAuditManager.md +1 -1
  54. package/docs/api/classes/RBACCache.md +1 -1
  55. package/docs/api/classes/RBACEngine.md +1 -1
  56. package/docs/api/classes/RBACError.md +1 -1
  57. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  58. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  59. package/docs/api/classes/StorageUtils.md +1 -1
  60. package/docs/api/enums/FileCategory.md +129 -0
  61. package/docs/api/interfaces/AggregateConfig.md +1 -1
  62. package/docs/api/interfaces/ButtonProps.md +1 -1
  63. package/docs/api/interfaces/CardProps.md +1 -1
  64. package/docs/api/interfaces/ColorPalette.md +1 -1
  65. package/docs/api/interfaces/ColorShade.md +1 -1
  66. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  67. package/docs/api/interfaces/DataTableAction.md +1 -1
  68. package/docs/api/interfaces/DataTableColumn.md +1 -1
  69. package/docs/api/interfaces/DataTableProps.md +1 -1
  70. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  71. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  72. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  73. package/docs/api/interfaces/EventContextType.md +7 -7
  74. package/docs/api/interfaces/EventLogoProps.md +1 -1
  75. package/docs/api/interfaces/EventProviderProps.md +2 -2
  76. package/docs/api/interfaces/FileDisplayProps.md +107 -0
  77. package/docs/api/interfaces/FileMetadata.md +129 -0
  78. package/docs/api/interfaces/FileReference.md +118 -0
  79. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  80. package/docs/api/interfaces/FileUploadOptions.md +85 -0
  81. package/docs/api/interfaces/FileUploadProps.md +1 -1
  82. package/docs/api/interfaces/FooterProps.md +1 -1
  83. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  84. package/docs/api/interfaces/InputProps.md +1 -1
  85. package/docs/api/interfaces/LabelProps.md +1 -1
  86. package/docs/api/interfaces/LoginFormProps.md +1 -1
  87. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  88. package/docs/api/interfaces/NavigationContextType.md +1 -1
  89. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  90. package/docs/api/interfaces/NavigationItem.md +1 -1
  91. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  92. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  93. package/docs/api/interfaces/Organisation.md +1 -1
  94. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  95. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  96. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  97. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  98. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  99. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  100. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  101. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  102. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  103. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  104. package/docs/api/interfaces/PaletteData.md +1 -1
  105. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  106. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  107. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  108. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  109. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  110. package/docs/api/interfaces/PublicPageHeaderProps.md +2 -2
  111. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  112. package/docs/api/interfaces/RBACConfig.md +1 -1
  113. package/docs/api/interfaces/RBACContextType.md +1 -1
  114. package/docs/api/interfaces/RBACLogger.md +1 -1
  115. package/docs/api/interfaces/RBACProviderProps.md +1 -1
  116. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  117. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  118. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  119. package/docs/api/interfaces/RouteConfig.md +1 -1
  120. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  121. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  122. package/docs/api/interfaces/StorageConfig.md +1 -1
  123. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  124. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  125. package/docs/api/interfaces/StorageListOptions.md +1 -1
  126. package/docs/api/interfaces/StorageListResult.md +1 -1
  127. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  128. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  129. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  130. package/docs/api/interfaces/StyleImport.md +1 -1
  131. package/docs/api/interfaces/SwitchProps.md +1 -1
  132. package/docs/api/interfaces/ToastActionElement.md +1 -1
  133. package/docs/api/interfaces/ToastProps.md +1 -1
  134. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  135. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  136. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  137. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  138. package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
  139. package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
  140. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  141. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  142. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  143. package/docs/api/interfaces/UserEventAccess.md +1 -1
  144. package/docs/api/interfaces/UserMenuProps.md +1 -1
  145. package/docs/api/interfaces/UserProfile.md +1 -1
  146. package/docs/api/modules.md +228 -23
  147. package/docs/architecture/services.md +374 -0
  148. package/docs/best-practices/README.md +1 -1
  149. package/docs/best-practices/testing.md +1 -1
  150. package/docs/breaking-changes.md +182 -0
  151. package/docs/common-patterns.md +445 -0
  152. package/docs/core-concepts/authentication.md +26 -11
  153. package/docs/core-concepts/events.md +2 -0
  154. package/docs/core-concepts/organisations.md +2 -0
  155. package/docs/core-concepts/permissions.md +2 -0
  156. package/docs/{INDEX.md → documentation-index.md} +26 -38
  157. package/docs/faq.md +286 -0
  158. package/docs/{FILE_REFERENCE_SYSTEM.md → file-reference-system.md} +1 -1
  159. package/docs/getting-started/installation-guide.md +284 -0
  160. package/docs/getting-started/quick-start.md +8 -1
  161. package/docs/implementation-guides/app-layout.md +3 -1
  162. package/docs/implementation-guides/data-tables.md +2 -0
  163. package/docs/implementation-guides/dynamic-colors.md +47 -2
  164. package/docs/implementation-guides/event-theming-summary.md +220 -0
  165. package/docs/implementation-guides/forms.md +9 -7
  166. package/docs/implementation-guides/navigation.md +2 -0
  167. package/docs/migration/service-architecture.md +351 -0
  168. package/docs/rbac/README-rbac-rls-integration.md +2 -2
  169. package/docs/rbac/README.md +1 -1
  170. package/docs/rbac/examples/rbac-rls-integration-example.md +3 -3
  171. package/docs/rbac/quick-start.md +2 -0
  172. package/docs/rbac/rbac-rls-integration.md +2 -2
  173. package/docs/style-guide.md +136 -1
  174. package/docs/testing/README.md +1 -1
  175. package/docs/troubleshooting/authentication-issues.md +334 -0
  176. package/docs/troubleshooting/common-issues.md +2 -0
  177. package/docs/troubleshooting/styling-issues.md +199 -144
  178. package/docs/usage.md +23 -2
  179. package/package.json +3 -2
  180. package/src/__tests__/{TESTING_GUIDELINES.md → TEST_GUIDE_CURSOR.md} +20 -0
  181. package/src/__tests__/TEST_GUIDE_HUMAN.md +103 -0
  182. package/src/__tests__/fixtures/test-data.ts +90 -0
  183. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +260 -0
  184. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +224 -0
  185. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +273 -0
  186. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +98 -0
  187. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +436 -0
  188. package/src/__tests__/helpers/__tests__/timer-utils.test.ts +371 -0
  189. package/src/__tests__/helpers/component-test-utils.tsx +14 -4
  190. package/src/__tests__/helpers/optimized-test-setup.ts +68 -0
  191. package/src/__tests__/helpers/test-providers.tsx +329 -0
  192. package/src/__tests__/helpers/test-utils.tsx +91 -45
  193. package/src/__tests__/helpers/timer-utils.ts +71 -0
  194. package/src/__tests__/hooks/usePermissions.test.ts +1 -5
  195. package/src/__tests__/integration/UserProfile.test.tsx +1 -5
  196. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +42 -12
  197. package/src/__tests__/setup.ts +34 -28
  198. package/src/components/Alert/Alert.test.tsx +1 -5
  199. package/src/components/Avatar/Avatar.test.tsx +1 -5
  200. package/src/components/Button/Button.test.tsx +4 -20
  201. package/src/components/Card/Card.test.tsx +1 -5
  202. package/src/components/Checkbox/Checkbox.test.tsx +1 -5
  203. package/src/components/DataTable/__tests__/DataTable.comprehensive.test.tsx +1 -5
  204. package/src/components/DataTable/__tests__/DataTable.test.tsx +45 -49
  205. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +1 -5
  206. package/src/components/DataTable/__tests__/styles.test.ts +382 -0
  207. package/src/components/DataTable/context/__tests__/DataTableContext.test.tsx +409 -0
  208. package/src/components/DataTable/core/__tests__/ActionManager.test.ts +634 -0
  209. package/src/components/DataTable/core/__tests__/DataManager.test.ts +519 -0
  210. package/src/components/DataTable/core/__tests__/StateManager.test.ts +714 -0
  211. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +592 -0
  212. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +354 -0
  213. package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +539 -0
  214. package/src/components/Dialog/examples/__tests__/SmartDialogExample.unit.test.tsx +1 -5
  215. package/src/components/Dialog/utils/__tests__/safeHtml.unit.test.ts +1 -8
  216. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +34 -38
  217. package/src/components/Footer/Footer.test.tsx +1 -5
  218. package/src/components/Form/Form.test.tsx +22 -35
  219. package/src/components/Header/Header.test.tsx +1 -9
  220. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +1 -5
  221. package/src/components/Input/Input.test.tsx +2 -10
  222. package/src/components/LoginForm/LoginForm.test.tsx +1 -5
  223. package/src/components/NavigationMenu/NavigationMenu.test.tsx +24 -24
  224. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.accessibility.test.tsx +1 -6
  225. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.integration.test.tsx +6 -16
  226. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.performance.test.tsx +1 -4
  227. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.rbac.test.tsx +1 -5
  228. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +1 -7
  229. package/src/components/PasswordReset/PasswordChangeForm.test.tsx +1 -9
  230. package/src/components/PasswordReset/PasswordResetForm.test.tsx +1 -9
  231. package/src/components/PublicLayout/PublicErrorBoundary.tsx +4 -5
  232. package/src/components/PublicLayout/PublicPageHeader.tsx +13 -9
  233. package/src/components/PublicLayout/__tests__/EventLogo.test.tsx +666 -0
  234. package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +457 -0
  235. package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +393 -0
  236. package/src/components/PublicLayout/__tests__/PublicPageFooter.test.tsx +351 -0
  237. package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +374 -0
  238. package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +388 -0
  239. package/src/components/Select/Select.bug-test.tsx +69 -0
  240. package/src/components/Select/Select.refactored.tsx +497 -0
  241. package/src/components/Select/Select.test.tsx +42 -49
  242. package/src/components/Select/Select.tsx +5 -2
  243. package/src/components/Select/hooks.ts +254 -0
  244. package/src/components/Switch/Switch.test.tsx +1 -5
  245. package/src/components/Table/__tests__/Table.test.tsx +775 -0
  246. package/src/components/Toast/Toast.test.tsx +15 -8
  247. package/src/components/Tooltip/Tooltip.test.tsx +1 -5
  248. package/src/components/UserMenu/UserMenu.test.tsx +3 -15
  249. package/src/components/__tests__/FileDisplay.test.tsx +575 -0
  250. package/src/components/__tests__/FileUpload.test.tsx +446 -0
  251. package/src/components/__tests__/SuperAdminGuard.test.tsx +422 -354
  252. package/src/hooks/__tests__/ServiceHooks.test.tsx +613 -0
  253. package/src/hooks/__tests__/hooks.integration.test.tsx +1 -10
  254. package/src/hooks/__tests__/useApiFetch.unit.test.ts +10 -14
  255. package/src/hooks/__tests__/useAppConfig.unit.test.ts +307 -0
  256. package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +1 -6
  257. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +1 -5
  258. package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +6 -9
  259. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +321 -0
  260. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +583 -0
  261. package/src/hooks/__tests__/usePublicEventLogo.unit.test.ts +640 -0
  262. package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +435 -0
  263. package/src/hooks/__tests__/useRBAC.unit.test.ts +10 -10
  264. package/src/hooks/__tests__/useStorage.unit.test.ts +751 -0
  265. package/src/hooks/index.ts +3 -0
  266. package/src/hooks/public/usePublicEvent.ts +30 -9
  267. package/src/hooks/public/usePublicRouteParams.ts +13 -3
  268. package/src/hooks/services/useAuth.ts +50 -0
  269. package/src/hooks/services/useAuthService.ts +30 -0
  270. package/src/hooks/services/useCurrentEvent.ts +36 -0
  271. package/src/hooks/services/useCurrentOrganisation.ts +52 -0
  272. package/src/hooks/services/useEventService.ts +30 -0
  273. package/src/hooks/services/useInactivityService.ts +30 -0
  274. package/src/hooks/services/useOrganisationService.ts +30 -0
  275. package/src/hooks/services/usePermissions.ts +70 -0
  276. package/src/hooks/services/useRBACService.ts +30 -0
  277. package/src/hooks/useCounter.test.ts +1 -5
  278. package/src/hooks/useEventTheme.ts +86 -0
  279. package/src/hooks/useOrganisationPermissions.test.ts +2 -5
  280. package/src/hooks/useOrganisationSecurity.test.ts +1 -5
  281. package/src/hooks/usePermissionCache.test.ts +1 -5
  282. package/src/hooks/usePermissionCheck.ts +150 -0
  283. package/src/hooks/useSecureDataAccess.test.ts +1 -5
  284. package/src/index.ts +7 -0
  285. package/src/providers/EventProvider.tsx +58 -2
  286. package/src/providers/OrganisationProvider.test.tsx +1 -5
  287. package/src/providers/OrganisationProvider.tsx +56 -4
  288. package/src/providers/UnifiedAuthProvider.test.tsx +1 -5
  289. package/src/providers/__tests__/AuthProvider.test.tsx +105 -439
  290. package/src/providers/__tests__/AuthProvider.test.tsx.backup +771 -0
  291. package/src/providers/__tests__/EventProvider.test.tsx +211 -110
  292. package/src/providers/__tests__/EventProvider.test.tsx.backup +824 -0
  293. package/src/providers/__tests__/InactivityProvider.test.tsx +1 -5
  294. package/src/providers/__tests__/OrganisationProvider.test.tsx +97 -261
  295. package/src/providers/__tests__/OrganisationProvider.test.tsx.backup +820 -0
  296. package/src/providers/__tests__/ServiceProviders.test.tsx +477 -0
  297. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +72 -504
  298. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx.backup +911 -0
  299. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx.backup2 +166 -0
  300. package/src/providers/services/AuthServiceProvider.tsx +65 -0
  301. package/src/providers/services/EventServiceProvider.tsx +83 -0
  302. package/src/providers/services/InactivityServiceProvider.tsx +83 -0
  303. package/src/providers/services/OrganisationServiceProvider.tsx +77 -0
  304. package/src/providers/services/RBACServiceProvider.tsx +79 -0
  305. package/src/providers/services/UnifiedAuthProvider.tsx +368 -0
  306. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +210 -0
  307. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +269 -0
  308. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +892 -0
  309. package/src/rbac/__tests__/engine.comprehensive.test.ts +954 -0
  310. package/src/rbac/__tests__/integration.authflow.test.tsx +1 -5
  311. package/src/rbac/__tests__/integration.navigation.test.tsx +1 -4
  312. package/src/rbac/__tests__/rbac-core.test.tsx +2 -7
  313. package/src/rbac/__tests__/rbac-functions.test.ts +1 -9
  314. package/src/rbac/__tests__/rbac-integration.test.ts +1 -9
  315. package/src/rbac/api.test.ts +1 -9
  316. package/src/rbac/cache.test.ts +10 -8
  317. package/src/rbac/cli/__tests__/policy-manager.test.ts +339 -0
  318. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +1 -5
  319. package/src/rbac/components/NavigationProvider.test.tsx +1 -5
  320. package/src/rbac/components/PagePermissionProvider.test.tsx +1 -5
  321. package/src/rbac/components/SecureDataProvider.test.tsx +1 -5
  322. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +25 -29
  323. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +27 -30
  324. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +23 -27
  325. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +18 -22
  326. package/src/rbac/config.test.ts +1 -5
  327. package/src/rbac/hooks/useCan.test.ts +262 -9
  328. package/src/rbac/hooks/usePermissions.test.ts +246 -6
  329. package/src/rbac/hooks/useRBAC.simple.test.ts +1 -5
  330. package/src/rbac/hooks/useRBAC.test.ts +472 -198
  331. package/src/rbac/providers/__tests__/RBACProvider.test.tsx +1 -9
  332. package/src/services/AuthService.ts +416 -0
  333. package/src/services/EventService.ts +366 -0
  334. package/src/services/InactivityService.ts +388 -0
  335. package/src/services/OrganisationService.ts +592 -0
  336. package/src/services/RBACService.ts +522 -0
  337. package/src/services/__tests__/AuthService.test.ts +356 -0
  338. package/src/services/__tests__/BaseService.test.ts +314 -0
  339. package/src/services/__tests__/EventService.test.ts +489 -0
  340. package/src/services/__tests__/InactivityService.test.ts +403 -0
  341. package/src/services/__tests__/OrganisationService.test.ts +660 -0
  342. package/src/services/__tests__/RBACService.test.ts +492 -0
  343. package/src/services/base/BaseService.ts +87 -0
  344. package/src/services/interfaces/IAuthService.ts +39 -0
  345. package/src/services/interfaces/IEventService.ts +30 -0
  346. package/src/services/interfaces/IInactivityService.ts +31 -0
  347. package/src/services/interfaces/IOrganisationService.ts +41 -0
  348. package/src/services/interfaces/IRBACService.ts +62 -0
  349. package/src/theming/__tests__/runtime.test.ts +560 -0
  350. package/src/theming/runtime.ts +71 -28
  351. package/src/types/__tests__/file-reference.test.ts +447 -0
  352. package/src/types/__tests__/organisation.test.ts +1133 -0
  353. package/src/types/__tests__/theme.test.ts +830 -0
  354. package/src/types/__tests__/type-validation.test.ts +527 -0
  355. package/src/utils/__tests__/bundleAnalysis.unit.test.ts +1 -5
  356. package/src/utils/__tests__/debugLogger.test.ts +417 -0
  357. package/src/utils/__tests__/deviceFingerprint.unit.test.ts +1 -6
  358. package/src/utils/__tests__/dynamicUtils.unit.test.ts +1 -5
  359. package/src/utils/__tests__/lazyLoad.unit.test.tsx +35 -35
  360. package/src/utils/__tests__/organisationContext.unit.test.ts +1 -5
  361. package/src/utils/__tests__/performanceBudgets.unit.test.ts +5 -11
  362. package/src/utils/__tests__/secureErrors.unit.test.ts +1 -6
  363. package/src/utils/__tests__/secureStorage.unit.test.ts +1 -5
  364. package/src/utils/__tests__/securityMonitor.unit.test.ts +1 -5
  365. package/src/utils/__tests__/sessionTracking.unit.test.ts +1 -5
  366. package/src/utils/appIdResolver.test.ts +6 -10
  367. package/src/utils/appNameResolver.simple.test.ts +142 -0
  368. package/src/utils/appNameResolver.test.ts +31 -458
  369. package/src/utils/appNameResolver.test.ts.backup +494 -0
  370. package/src/utils/debugLogger.ts +26 -5
  371. package/src/utils/formatDate.test.ts +1 -5
  372. package/src/utils/organisationContext.test.ts +1 -5
  373. package/src/utils/performanceBudgets.ts +3 -4
  374. package/src/utils/secureDataAccess.test.ts +1 -5
  375. package/src/utils/storage/__tests__/helpers.unit.test.ts +1 -5
  376. package/src/validation/__tests__/sqlInjectionProtection.unit.test.ts +1 -5
  377. package/dist/chunk-D7ARGIA3.js.map +0 -1
  378. package/dist/chunk-IPCH4YPT.js +0 -315
  379. package/dist/chunk-IPCH4YPT.js.map +0 -1
  380. package/dist/chunk-KRCRNXPD.js.map +0 -1
  381. package/dist/chunk-MOJXHWDE.js.map +0 -1
  382. package/dist/chunk-N2EUGZRW.js +0 -98
  383. package/dist/chunk-N2EUGZRW.js.map +0 -1
  384. package/dist/chunk-OPCWH3A4.js.map +0 -1
  385. package/dist/chunk-U6GPOF6J.js.map +0 -1
  386. package/dist/chunk-ZPG4XPV5.js.map +0 -1
  387. package/dist/chunk-ZPK5656W.js.map +0 -1
  388. package/docs/getting-started/installation.md +0 -269
  389. package/src/__tests__/REBUILD_PLAN.md +0 -223
  390. package/src/styles/base.css +0 -208
  391. package/src/styles/semantic.css +0 -24
  392. /package/dist/{DataTable-4IUY7BXB.js.map → DataTable-OSELOGMA.js.map} +0 -0
  393. /package/dist/{chunk-PXWEDX7Y.js.map → chunk-KWQH4VO3.js.map} +0 -0
  394. /package/dist/{chunk-UYA6U6H7.js.map → chunk-V2TE7LOF.js.map} +0 -0
@@ -22,6 +22,9 @@ export { useFocusTrap } from './useFocusTrap';
22
22
  export { useKeyboardShortcuts } from './useKeyboardShortcuts';
23
23
  export { useIsMobile } from './useIsMobile';
24
24
 
25
+ // === EVENT THEMING HOOK ===
26
+ export { useEventTheme } from './useEventTheme';
27
+
25
28
  // === DATA & STATE HOOKS ===
26
29
  export { useDebounce } from './useDebounce';
27
30
  export { useDataTableState } from './useDataTableState';
@@ -172,9 +172,12 @@ export function usePublicEvent(
172
172
 
173
173
  try {
174
174
  // Try to call the public event RPC function first
175
- const { data, error: rpcError } = await (supabase as any).rpc('get_public_event_by_code', {
175
+ const response = await (supabase as any).rpc('get_public_event_by_code', {
176
176
  event_code_param: eventCode
177
177
  });
178
+
179
+ const data = response?.data;
180
+ const rpcError = response?.error;
178
181
 
179
182
  if (rpcError) {
180
183
  // If RPC function doesn't exist or schema cache issue, try refresh first, then fallback
@@ -188,10 +191,13 @@ export function usePublicEvent(
188
191
 
189
192
  // Try RPC call one more time after refresh
190
193
  try {
191
- const { data: retryData, error: retryError } = await (supabase as any).rpc('get_public_event_by_code', {
194
+ const retryResponse = await (supabase as any).rpc('get_public_event_by_code', {
192
195
  event_code_param: eventCode
193
196
  });
194
197
 
198
+ const retryData = retryResponse?.data;
199
+ const retryError = retryResponse?.error;
200
+
195
201
  if (!retryError && retryData && retryData.length > 0) {
196
202
  eventData = retryData[0];
197
203
  } else {
@@ -201,7 +207,7 @@ export function usePublicEvent(
201
207
  console.warn('[usePublicEvent] RPC still failing after cache refresh, falling back to direct table access');
202
208
 
203
209
  // Fallback: Direct table access with public RLS policy
204
- const { data: tableData, error: tableError } = await (supabase as any)
210
+ const tableResponse2 = await (supabase as any)
205
211
  .from('event')
206
212
  .select(`
207
213
  event_id,
@@ -227,8 +233,11 @@ export function usePublicEvent(
227
233
  .limit(1)
228
234
  .single();
229
235
 
236
+ const tableData = tableResponse2?.data;
237
+ const tableError = tableResponse2?.error;
238
+
230
239
  if (tableError) {
231
- throw new Error(tableError.message || 'Failed to fetch event from table');
240
+ throw new Error(tableError?.message || 'Failed to fetch event from table');
232
241
  }
233
242
 
234
243
  if (!tableData) {
@@ -238,7 +247,7 @@ export function usePublicEvent(
238
247
  }
239
248
 
240
249
  // Get event logo from file_references
241
- const { data: logoData } = await (supabase as any)
250
+ const logoResponse = await (supabase as any)
242
251
  .from('file_references')
243
252
  .select('file_path')
244
253
  .eq('table_name', 'event')
@@ -247,6 +256,8 @@ export function usePublicEvent(
247
256
  .eq('file_metadata->>category', 'event_logos')
248
257
  .limit(1)
249
258
  .single();
259
+
260
+ const logoData = logoResponse?.data;
250
261
 
251
262
  eventData = {
252
263
  ...tableData,
@@ -254,7 +265,12 @@ export function usePublicEvent(
254
265
  };
255
266
  }
256
267
  } else {
257
- throw new Error(rpcError.message || 'Failed to fetch event');
268
+ // For RPC errors that aren't schema cache issues, throw immediately without fallback
269
+ const errorMessage = rpcError?.message || rpcError?.toString() || 'Failed to fetch event';
270
+ setEvent(null);
271
+ setError(new Error(errorMessage));
272
+ setIsLoading(false);
273
+ return;
258
274
  }
259
275
  } else {
260
276
  if (!data || data.length === 0 || !data[0]) {
@@ -268,7 +284,7 @@ export function usePublicEvent(
268
284
  // If RPC call fails for any reason (including schema cache issues), try direct table access
269
285
  console.warn('[usePublicEvent] RPC call failed, falling back to direct table access:', rpcError);
270
286
 
271
- const { data: tableData, error: tableError } = await (supabase as any)
287
+ const tableResponse = await (supabase as any)
272
288
  .from('event')
273
289
  .select(`
274
290
  event_id,
@@ -294,8 +310,11 @@ export function usePublicEvent(
294
310
  .limit(1)
295
311
  .single();
296
312
 
313
+ const tableData = tableResponse?.data;
314
+ const tableError = tableResponse?.error;
315
+
297
316
  if (tableError) {
298
- throw new Error(tableError.message || 'Failed to fetch event from table');
317
+ throw new Error(tableError?.message || 'Failed to fetch event from table');
299
318
  }
300
319
 
301
320
  if (!tableData) {
@@ -305,7 +324,7 @@ export function usePublicEvent(
305
324
  }
306
325
 
307
326
  // Get event logo from file_references
308
- const { data: logoData } = await (supabase as any)
327
+ const logoResponse = await (supabase as any)
309
328
  .from('file_references')
310
329
  .select('file_path')
311
330
  .eq('table_name', 'event')
@@ -314,6 +333,8 @@ export function usePublicEvent(
314
333
  .eq('file_metadata->>category', 'event_logos')
315
334
  .limit(1)
316
335
  .single();
336
+
337
+ const logoData = logoResponse?.data;
317
338
 
318
339
  eventData = {
319
340
  ...tableData,
@@ -87,15 +87,25 @@ interface UsePublicRouteParamsOptions {
87
87
 
88
88
  /**
89
89
  * Validate event code format
90
- * Event codes should be alphanumeric with optional hyphens/underscores
90
+ * Event codes should be alphanumeric with optional hyphens/underscores in the middle
91
91
  */
92
92
  function validateEventCodeFormat(eventCode: string): boolean {
93
93
  if (!eventCode || typeof eventCode !== 'string') return false;
94
94
 
95
95
  // Allow alphanumeric characters, hyphens, and underscores
96
96
  // Length between 3 and 50 characters
97
- const eventCodeRegex = /^[a-zA-Z0-9_-]{3,50}$/;
98
- return eventCodeRegex.test(eventCode);
97
+ // Must not start or end with hyphen/underscore
98
+ const eventCodeRegex = /^[a-zA-Z0-9][a-zA-Z0-9_-]{1,48}[a-zA-Z0-9]$/;
99
+ const matchesFormat = eventCodeRegex.test(eventCode);
100
+
101
+ if (!matchesFormat) return false;
102
+
103
+ // Additional check: no consecutive hyphens or underscores
104
+ if (eventCode.includes('--') || eventCode.includes('__') || eventCode.includes('-_') || eventCode.includes('_-')) {
105
+ return false;
106
+ }
107
+
108
+ return true;
99
109
  }
100
110
 
101
111
  /**
@@ -0,0 +1,50 @@
1
+ /**
2
+ * @file Auth Convenience Hook
3
+ * @package @jmruthers/pace-core
4
+ * @module Hooks/Services
5
+ * @since 0.1.0
6
+ *
7
+ * Convenience hook for authentication.
8
+ * Returns just the auth state and methods needed by components.
9
+ */
10
+
11
+ import { useAuthService } from './useAuthService';
12
+ import { type User, type Session, AuthError } from '@supabase/supabase-js';
13
+
14
+ export interface AuthState {
15
+ user: User | null;
16
+ session: Session | null;
17
+ isAuthenticated: boolean;
18
+ authLoading: boolean;
19
+ authError: AuthError | null;
20
+ error: AuthError | null; // Alias for authError for backward compatibility
21
+ supabase: any | null;
22
+
23
+ // Auth methods
24
+ signIn: (email: string, password?: string) => Promise<{ error: AuthError | null }>;
25
+ signUp: (email: string, password: string) => Promise<{ error: AuthError | null }>;
26
+ signOut: () => Promise<{ error: AuthError | null }>;
27
+ resetPassword: (email: string) => Promise<{ error: AuthError | null }>;
28
+ updatePassword: (password: string) => Promise<{ error: AuthError | null }>;
29
+ refreshSession: () => Promise<{ error: AuthError | null }>;
30
+ }
31
+
32
+ export function useAuth(): AuthState {
33
+ const authService = useAuthService();
34
+
35
+ return {
36
+ user: authService.getUser(),
37
+ session: authService.getSession(),
38
+ isAuthenticated: authService.isAuthenticated(),
39
+ authLoading: authService.isLoading(),
40
+ authError: authService.getError(),
41
+ error: authService.getError(), // Alias for backward compatibility
42
+ supabase: authService.getSupabaseClient(),
43
+ signIn: authService.signIn.bind(authService),
44
+ signUp: authService.signUp.bind(authService),
45
+ signOut: authService.signOut.bind(authService),
46
+ resetPassword: authService.resetPassword.bind(authService),
47
+ updatePassword: authService.updatePassword.bind(authService),
48
+ refreshSession: authService.refreshSession.bind(authService),
49
+ };
50
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @file Auth Service Hook
3
+ * @package @jmruthers/pace-core
4
+ * @module Hooks/Services
5
+ * @since 0.1.0
6
+ *
7
+ * React hook for AuthService.
8
+ * Provides authentication service with reactive state updates.
9
+ */
10
+
11
+ import { useContext, useReducer, useEffect } from 'react';
12
+ import { AuthServiceContext } from '../../providers/services/AuthServiceProvider';
13
+ import { AuthService } from '../../services/AuthService';
14
+
15
+ export function useAuthService(): AuthService {
16
+ const context = useContext(AuthServiceContext);
17
+
18
+ if (!context) {
19
+ throw new Error('useAuthService must be used within AuthServiceProvider');
20
+ }
21
+
22
+ // Subscribe to service state changes
23
+ const [, forceUpdate] = useReducer(x => x + 1, 0);
24
+
25
+ useEffect(() => {
26
+ return context.authService.subscribe(() => forceUpdate());
27
+ }, [context.authService]);
28
+
29
+ return context.authService;
30
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @file Current Event Convenience Hook
3
+ * @package @jmruthers/pace-core
4
+ * @module Hooks/Services
5
+ * @since 0.1.0
6
+ *
7
+ * Convenience hook for current event.
8
+ * Returns just the event state and methods needed by components.
9
+ */
10
+
11
+ import { useEventService } from './useEventService';
12
+ import { Event } from '../../types/unified';
13
+
14
+ export interface CurrentEventState {
15
+ events: Event[];
16
+ selectedEvent: Event | null;
17
+ isLoading: boolean;
18
+ error: Error | null;
19
+
20
+ // Event methods
21
+ setSelectedEvent: (event: Event | null) => void;
22
+ refreshEvents: () => Promise<void>;
23
+ }
24
+
25
+ export function useCurrentEvent(): CurrentEventState {
26
+ const eventService = useEventService();
27
+
28
+ return {
29
+ events: eventService.getEvents(),
30
+ selectedEvent: eventService.getSelectedEvent(),
31
+ isLoading: eventService.isLoading(),
32
+ error: eventService.getError(),
33
+ setSelectedEvent: eventService.setSelectedEvent.bind(eventService),
34
+ refreshEvents: eventService.refreshEvents.bind(eventService),
35
+ };
36
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @file Current Organisation Convenience Hook
3
+ * @package @jmruthers/pace-core
4
+ * @module Hooks/Services
5
+ * @since 0.1.0
6
+ *
7
+ * Convenience hook for current organisation.
8
+ * Returns just the organisation state and methods needed by components.
9
+ */
10
+
11
+ import { useOrganisationService } from './useOrganisationService';
12
+ import type { Organisation, OrganisationMembership } from '../../types/organisation';
13
+
14
+ export interface CurrentOrganisationState {
15
+ selectedOrganisation: Organisation | null;
16
+ organisations: Organisation[];
17
+ userMemberships: OrganisationMembership[];
18
+ isLoading: boolean;
19
+ error: Error | null;
20
+ hasValidOrganisationContext: boolean;
21
+ isContextReady: boolean;
22
+
23
+ // Organisation methods
24
+ switchOrganisation: (orgId: string) => Promise<void>;
25
+ getUserRole: (orgId?: string) => string;
26
+ validateOrganisationAccess: (orgId: string) => boolean;
27
+ refreshOrganisations: () => Promise<void>;
28
+ ensureOrganisationContext: () => Organisation;
29
+ isOrganisationSecure: () => boolean;
30
+ getPrimaryOrganisation: () => Organisation | null;
31
+ }
32
+
33
+ export function useCurrentOrganisation(): CurrentOrganisationState {
34
+ const organisationService = useOrganisationService();
35
+
36
+ return {
37
+ selectedOrganisation: organisationService.getSelectedOrganisation(),
38
+ organisations: organisationService.getOrganisations(),
39
+ userMemberships: organisationService.getUserMemberships(),
40
+ isLoading: organisationService.isLoading(),
41
+ error: organisationService.getError(),
42
+ hasValidOrganisationContext: organisationService.hasValidOrganisationContext(),
43
+ isContextReady: organisationService.isContextReady(),
44
+ switchOrganisation: organisationService.switchOrganisation.bind(organisationService),
45
+ getUserRole: organisationService.getUserRole.bind(organisationService),
46
+ validateOrganisationAccess: organisationService.validateOrganisationAccess.bind(organisationService),
47
+ refreshOrganisations: organisationService.refreshOrganisations.bind(organisationService),
48
+ ensureOrganisationContext: organisationService.ensureOrganisationContext.bind(organisationService),
49
+ isOrganisationSecure: organisationService.isOrganisationSecure.bind(organisationService),
50
+ getPrimaryOrganisation: organisationService.getPrimaryOrganisation.bind(organisationService),
51
+ };
52
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @file Event Service Hook
3
+ * @package @jmruthers/pace-core
4
+ * @module Hooks/Services
5
+ * @since 0.1.0
6
+ *
7
+ * React hook for EventService.
8
+ * Provides event service with reactive state updates.
9
+ */
10
+
11
+ import { useContext, useReducer, useEffect } from 'react';
12
+ import { EventServiceContext } from '../../providers/services/EventServiceProvider';
13
+ import { EventService } from '../../services/EventService';
14
+
15
+ export function useEventService(): EventService {
16
+ const context = useContext(EventServiceContext);
17
+
18
+ if (!context) {
19
+ throw new Error('useEventService must be used within EventServiceProvider');
20
+ }
21
+
22
+ // Subscribe to service state changes
23
+ const [, forceUpdate] = useReducer(x => x + 1, 0);
24
+
25
+ useEffect(() => {
26
+ return context.eventService.subscribe(() => forceUpdate());
27
+ }, [context.eventService]);
28
+
29
+ return context.eventService;
30
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @file Inactivity Service Hook
3
+ * @package @jmruthers/pace-core
4
+ * @module Hooks/Services
5
+ * @since 0.1.0
6
+ *
7
+ * React hook for InactivityService.
8
+ * Provides inactivity service with reactive state updates.
9
+ */
10
+
11
+ import { useContext, useReducer, useEffect } from 'react';
12
+ import { InactivityServiceContext } from '../../providers/services/InactivityServiceProvider';
13
+ import { InactivityService } from '../../services/InactivityService';
14
+
15
+ export function useInactivityService(): InactivityService {
16
+ const context = useContext(InactivityServiceContext);
17
+
18
+ if (!context) {
19
+ throw new Error('useInactivityService must be used within InactivityServiceProvider');
20
+ }
21
+
22
+ // Subscribe to service state changes
23
+ const [, forceUpdate] = useReducer(x => x + 1, 0);
24
+
25
+ useEffect(() => {
26
+ return context.inactivityService.subscribe(() => forceUpdate());
27
+ }, [context.inactivityService]);
28
+
29
+ return context.inactivityService;
30
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @file Organisation Service Hook
3
+ * @package @jmruthers/pace-core
4
+ * @module Hooks/Services
5
+ * @since 0.1.0
6
+ *
7
+ * React hook for OrganisationService.
8
+ * Provides organisation service with reactive state updates.
9
+ */
10
+
11
+ import { useContext, useReducer, useEffect } from 'react';
12
+ import { OrganisationServiceContext } from '../../providers/services/OrganisationServiceProvider';
13
+ import { OrganisationService } from '../../services/OrganisationService';
14
+
15
+ export function useOrganisationService(): OrganisationService {
16
+ const context = useContext(OrganisationServiceContext);
17
+
18
+ if (!context) {
19
+ throw new Error('useOrganisationService must be used within OrganisationServiceProvider');
20
+ }
21
+
22
+ // Subscribe to service state changes
23
+ const [, forceUpdate] = useReducer(x => x + 1, 0);
24
+
25
+ useEffect(() => {
26
+ return context.organisationService.subscribe(() => forceUpdate());
27
+ }, [context.organisationService]);
28
+
29
+ return context.organisationService;
30
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @file Permissions Convenience Hook
3
+ * @package @jmruthers/pace-core
4
+ * @module Hooks/Services
5
+ * @since 0.1.0
6
+ *
7
+ * Convenience hook for permissions.
8
+ * Returns just the permission state and methods needed by components.
9
+ */
10
+
11
+ import { useRBACService } from './useRBACService';
12
+ import { AccessLevel } from '../../types/unified';
13
+
14
+ export interface PermissionsState {
15
+ permissions: Record<string, boolean>;
16
+ roles: string[];
17
+ accessLevel: AccessLevel;
18
+ rbacLoading: boolean;
19
+ rbacError: Error | null;
20
+ selectedEventId: string | null;
21
+ appConfig: any | null;
22
+ userEventAccess: any[];
23
+ eventAccessLoading: boolean;
24
+ selectedOrganisationId: string | null;
25
+
26
+ // Permission methods
27
+ hasPermission: (permission: string, orgId?: string) => boolean;
28
+ hasAnyPermission: (permissions: string[], orgId?: string) => boolean;
29
+ hasAllPermissions: (permissions: string[], orgId?: string) => boolean;
30
+ hasRole: (role: string) => boolean;
31
+ hasAccessLevel: (level: AccessLevel) => boolean;
32
+ canAccess: (resource: string, action: string, orgId?: string) => boolean;
33
+ validatePermission: (permission: string, orgId?: string) => Promise<boolean>;
34
+ validateAccess: (resource: string, action: string, orgId?: string) => Promise<boolean>;
35
+ refreshPermissions: (eventId?: string, orgId?: string) => Promise<void>;
36
+ setSelectedEventId: (eventId: string | null) => void;
37
+ loadUserEventAccess: (orgId?: string) => Promise<void>;
38
+ getUserEventAccess: (eventId: string) => any | undefined;
39
+ requireOrganisationContext: () => string;
40
+ }
41
+
42
+ export function usePermissions(): PermissionsState {
43
+ const rbacService = useRBACService();
44
+
45
+ return {
46
+ permissions: rbacService.getPermissions(),
47
+ roles: rbacService.getRoles(),
48
+ accessLevel: rbacService.getAccessLevel(),
49
+ rbacLoading: rbacService.isLoading(),
50
+ rbacError: rbacService.getError(),
51
+ selectedEventId: rbacService.getSelectedEventId(),
52
+ appConfig: rbacService.getAppConfig(),
53
+ userEventAccess: rbacService.getUserEventAccess(),
54
+ eventAccessLoading: rbacService.isEventAccessLoading(),
55
+ selectedOrganisationId: rbacService.getSelectedOrganisationId(),
56
+ hasPermission: rbacService.hasPermission.bind(rbacService),
57
+ hasAnyPermission: rbacService.hasAnyPermission.bind(rbacService),
58
+ hasAllPermissions: rbacService.hasAllPermissions.bind(rbacService),
59
+ hasRole: rbacService.hasRole.bind(rbacService),
60
+ hasAccessLevel: rbacService.hasAccessLevel.bind(rbacService),
61
+ canAccess: rbacService.canAccess.bind(rbacService),
62
+ validatePermission: rbacService.validatePermission.bind(rbacService),
63
+ validateAccess: rbacService.validateAccess.bind(rbacService),
64
+ refreshPermissions: rbacService.refreshPermissions.bind(rbacService),
65
+ setSelectedEventId: rbacService.setSelectedEventId.bind(rbacService),
66
+ loadUserEventAccess: rbacService.loadUserEventAccess.bind(rbacService),
67
+ getUserEventAccess: rbacService.getUserEventAccess.bind(rbacService),
68
+ requireOrganisationContext: rbacService.requireOrganisationContext.bind(rbacService),
69
+ };
70
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @file RBAC Service Hook
3
+ * @package @jmruthers/pace-core
4
+ * @module Hooks/Services
5
+ * @since 0.1.0
6
+ *
7
+ * React hook for RBACService.
8
+ * Provides RBAC service with reactive state updates.
9
+ */
10
+
11
+ import { useContext, useReducer, useEffect } from 'react';
12
+ import { RBACServiceContext } from '../../providers/services/RBACServiceProvider';
13
+ import { RBACService } from '../../services/RBACService';
14
+
15
+ export function useRBACService(): RBACService {
16
+ const context = useContext(RBACServiceContext);
17
+
18
+ if (!context) {
19
+ throw new Error('useRBACService must be used within RBACServiceProvider');
20
+ }
21
+
22
+ // Subscribe to service state changes
23
+ const [, forceUpdate] = useReducer(x => x + 1, 0);
24
+
25
+ useEffect(() => {
26
+ return context.rbacService.subscribe(() => forceUpdate());
27
+ }, [context.rbacService]);
28
+
29
+ return context.rbacService;
30
+ }
@@ -19,11 +19,7 @@ const useCounter = (initialValue = 0) => {
19
19
  };
20
20
 
21
21
  describe('useCounter Hook', () => {
22
- beforeEach(() => {
23
- vi.clearAllMocks();
24
- });
25
-
26
- describe('Initialization', () => {
22
+ describe('Initialization', () => {
27
23
  it('initializes with default value', () => {
28
24
  const { result } = renderHook(() => useCounter());
29
25
  expect(result.current.count).toBe(0);
@@ -0,0 +1,86 @@
1
+ /**
2
+ * @file Event Theme Hook
3
+ * @package @jmruthers/pace-core
4
+ * @module Hooks/EventTheme
5
+ * @since 2.0.0
6
+ *
7
+ * Hook that automatically applies event-specific theming when an event is selected.
8
+ * This ensures consistent UX across all apps in the pace suite.
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * import { useEventTheme } from '@jmruthers/pace-core/hooks';
13
+ *
14
+ * function MyApp() {
15
+ * // Automatically applies event colors when event is selected
16
+ * useEventTheme();
17
+ *
18
+ * return <div>Your app content</div>;
19
+ * }
20
+ * ```
21
+ */
22
+
23
+ import { useEffect } from 'react';
24
+ import { useEvents } from '../providers/EventProvider';
25
+ import { applyPalette, clearPalette } from '../theming/runtime';
26
+ import type { PaletteData, ColorPalette } from '../theming/runtime';
27
+
28
+ /**
29
+ * Hook that automatically applies event-specific theming
30
+ *
31
+ * This hook watches the selected event and applies its colors using the theming system.
32
+ * It will:
33
+ * - Apply event colors when an event with `event_colours` is selected
34
+ * - Clear theming when no event is selected
35
+ * - Handle cleanup when the component unmounts
36
+ *
37
+ * @returns void - This is an effect hook with no return value
38
+ */
39
+ export function useEventTheme(): void {
40
+ const { selectedEvent } = useEvents();
41
+
42
+ useEffect(() => {
43
+ // If there's no selected event, clear any dynamic theming
44
+ if (!selectedEvent) {
45
+ clearPalette();
46
+ return;
47
+ }
48
+
49
+ // Check if the event has theme colors
50
+ const eventColours = selectedEvent.event_colours;
51
+
52
+ if (!eventColours || typeof eventColours !== 'object') {
53
+ clearPalette();
54
+ return;
55
+ }
56
+
57
+ // Validate that event_colours has the expected structure
58
+ const palette = eventColours as Partial<PaletteData>;
59
+
60
+ // Check if we have at least one valid palette (main, sec, or acc)
61
+ if (!palette.main && !palette.sec && !palette.acc) {
62
+ clearPalette();
63
+ return;
64
+ }
65
+
66
+ // Apply the palette
67
+ // The system expects main, sec, and acc, so we ensure all are present (empty if needed)
68
+ const fullPalette: PaletteData = {
69
+ main: (palette.main as ColorPalette) || {},
70
+ sec: (palette.sec as ColorPalette) || {},
71
+ acc: (palette.acc as ColorPalette) || {},
72
+ };
73
+
74
+ try {
75
+ applyPalette(fullPalette);
76
+ } catch (error) {
77
+ console.error('[useEventTheme] Failed to apply event palette:', error);
78
+ }
79
+
80
+ // Cleanup function to clear palette when component unmounts or event changes
81
+ return () => {
82
+ // Don't clear on unmount since we want the theme to persist
83
+ // The next event selection will update it
84
+ };
85
+ }, [selectedEvent]);
86
+ }
@@ -36,16 +36,13 @@ describe('useOrganisationPermissions', () => {
36
36
  ...overrides
37
37
  });
38
38
 
39
+ // Set up default mock for all tests
39
40
  beforeEach(() => {
40
41
  vi.clearAllMocks();
41
42
  mockUseOrganisations.mockReturnValue(createMockOrganisations() as any);
42
43
  });
43
44
 
44
- afterEach(() => {
45
- vi.restoreAllMocks();
46
- });
47
-
48
- describe('Hook Initialization', () => {
45
+ describe('Hook Initialization', () => {
49
46
  it('initializes with default organisation', () => {
50
47
  const { result } = renderHook(() => useOrganisationPermissions());
51
48
 
@@ -122,11 +122,7 @@ describe('useOrganisationSecurity', () => {
122
122
  } as any);
123
123
  });
124
124
 
125
- afterEach(() => {
126
- vi.restoreAllMocks();
127
- });
128
-
129
- describe('Super Admin Context', () => {
125
+ describe('Super Admin Context', () => {
130
126
  it('detects super admin from app_metadata', () => {
131
127
  const superAdminUser = {
132
128
  ...mockUser,
@@ -39,11 +39,7 @@ describe('usePermissionCache', () => {
39
39
  mockUseRBAC.mockReturnValue(stableMockRBAC);
40
40
  });
41
41
 
42
- afterEach(() => {
43
- vi.restoreAllMocks();
44
- });
45
-
46
- describe('Hook Initialization', () => {
42
+ describe('Hook Initialization', () => {
47
43
  it('initializes with default configuration', () => {
48
44
  const { result } = renderHook(() => usePermissionCache());
49
45