@jmruthers/pace-core 0.6.1 → 0.6.3

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 (549) hide show
  1. package/CHANGELOG.md +88 -10
  2. package/cursor-rules/00-pace-core-compliance.mdc +46 -87
  3. package/cursor-rules/01-standards-compliance.mdc +16 -47
  4. package/cursor-rules/02-project-structure.mdc +4 -4
  5. package/cursor-rules/03-solid-principles.mdc +45 -164
  6. package/cursor-rules/04-testing-standards.mdc +22 -69
  7. package/cursor-rules/05-bug-reports-and-features.mdc +2 -2
  8. package/cursor-rules/06-code-quality.mdc +42 -125
  9. package/cursor-rules/07-tech-stack-compliance.mdc +33 -128
  10. package/cursor-rules/08-markup-quality.mdc +452 -0
  11. package/cursor-rules/CHANGELOG.md +18 -0
  12. package/cursor-rules/README.md +2 -1
  13. package/dist/{AuthService-DjnJHDtC.d.ts → AuthService-Cb34EQs3.d.ts} +63 -1
  14. package/dist/{DataTable-CH1U5Tpy.d.ts → DataTable-BMRU8a1j.d.ts} +33 -1
  15. package/dist/{DataTable-DQ7RSOHE.js → DataTable-THFPBKTP.js} +12 -10
  16. package/dist/{PublicPageProvider-ce4xlHYA.d.ts → PublicPageProvider-DEMpysFR.d.ts} +394 -171
  17. package/dist/{UnifiedAuthProvider-185Ih4dj.d.ts → UnifiedAuthProvider-CKvHP1MK.d.ts} +30 -8
  18. package/dist/{UnifiedAuthProvider-ATAP5UTR.js → UnifiedAuthProvider-KAGUYQ4J.js} +5 -4
  19. package/dist/{api-N774RPUA.js → api-IAGWF3ZG.js} +10 -10
  20. package/dist/{audit-B5P6FFIR.js → audit-V53FV5AG.js} +2 -2
  21. package/dist/{chunk-JBKQ3SAO.js → chunk-2T2IG7T7.js} +107 -57
  22. package/dist/chunk-2T2IG7T7.js.map +1 -0
  23. package/dist/{chunk-3QRJFVBR.js → chunk-6SOIHG6Z.js} +1 -1
  24. package/dist/chunk-6SOIHG6Z.js.map +1 -0
  25. package/dist/{chunk-3XTALGJF.js → chunk-6Z7LTB3D.js} +69 -240
  26. package/dist/chunk-6Z7LTB3D.js.map +1 -0
  27. package/dist/{chunk-4ZC4GX36.js → chunk-CNCQDFLN.js} +199 -46
  28. package/dist/chunk-CNCQDFLN.js.map +1 -0
  29. package/dist/chunk-DGUM43GV.js +11 -0
  30. package/dist/{chunk-BYFSK72L.js → chunk-DWUBLJJM.js} +361 -187
  31. package/dist/chunk-DWUBLJJM.js.map +1 -0
  32. package/dist/{chunk-LXQLPRQ2.js → chunk-FFQEQTNW.js} +6 -8
  33. package/dist/chunk-FFQEQTNW.js.map +1 -0
  34. package/dist/chunk-FMUCXFII.js +76 -0
  35. package/dist/chunk-FMUCXFII.js.map +1 -0
  36. package/dist/{chunk-4N5C5XZU.js → chunk-HFZBI76P.js} +4 -4
  37. package/dist/chunk-HFZBI76P.js.map +1 -0
  38. package/dist/{chunk-SQGMNID3.js → chunk-L4OXEN46.js} +4 -5
  39. package/dist/chunk-L4OXEN46.js.map +1 -0
  40. package/dist/{chunk-R77UEZ4E.js → chunk-M43Y4SSO.js} +1 -1
  41. package/dist/chunk-M43Y4SSO.js.map +1 -0
  42. package/dist/{chunk-I7PSE6JW.js → chunk-M7MPQISP.js} +3 -76
  43. package/dist/chunk-M7MPQISP.js.map +1 -0
  44. package/dist/chunk-PQBSKX33.js +7793 -0
  45. package/dist/chunk-PQBSKX33.js.map +1 -0
  46. package/dist/chunk-QRPVRXYT.js +226 -0
  47. package/dist/chunk-QRPVRXYT.js.map +1 -0
  48. package/dist/{chunk-KNC55RTG.js → chunk-RWEBCB47.js} +194 -416
  49. package/dist/chunk-RWEBCB47.js.map +1 -0
  50. package/dist/{chunk-XM25TVIE.js → chunk-YDQHOZNA.js} +843 -388
  51. package/dist/chunk-YDQHOZNA.js.map +1 -0
  52. package/dist/{chunk-GLK6VM3F.js → chunk-ZNIWI3UC.js} +739 -737
  53. package/dist/chunk-ZNIWI3UC.js.map +1 -0
  54. package/dist/components.d.ts +5 -5
  55. package/dist/components.js +18 -16
  56. package/dist/components.js.map +1 -1
  57. package/dist/contextValidator-3JNZKUTX.js +9 -0
  58. package/dist/contextValidator-3JNZKUTX.js.map +1 -0
  59. package/dist/eslint-rules/pace-core-compliance.cjs +106 -0
  60. package/dist/{functions-D_kgHktt.d.ts → functions-DHebl8-F.d.ts} +1 -1
  61. package/dist/hooks.d.ts +55 -122
  62. package/dist/hooks.js +10 -13
  63. package/dist/hooks.js.map +1 -1
  64. package/dist/index.d.ts +60 -13
  65. package/dist/index.js +30 -25
  66. package/dist/index.js.map +1 -1
  67. package/dist/providers.d.ts +21 -3
  68. package/dist/providers.js +4 -3
  69. package/dist/rbac/index.d.ts +210 -139
  70. package/dist/rbac/index.js +17 -13
  71. package/dist/styles/index.js +1 -1
  72. package/dist/theming/runtime.d.ts +1 -13
  73. package/dist/theming/runtime.js +2 -2
  74. package/dist/{timezone-_pgH8qrY.d.ts → timezone-CHhWg6b4.d.ts} +3 -10
  75. package/dist/{types-UU913iLA.d.ts → types-BeoeWV5I.d.ts} +8 -0
  76. package/dist/{types-CEpcvwwF.d.ts → types-CkbwOr4Y.d.ts} +6 -0
  77. package/dist/types.d.ts +2 -2
  78. package/dist/types.js +1 -1
  79. package/dist/{usePublicRouteParams-BJAlWfuJ.d.ts → usePublicRouteParams-i3qtoBgg.d.ts} +38 -17
  80. package/dist/utils.d.ts +4 -5
  81. package/dist/utils.js +17 -19
  82. package/dist/utils.js.map +1 -1
  83. package/docs/api/README.md +21 -17
  84. package/docs/api/modules.md +4191 -2967
  85. package/docs/architecture/database-schema-requirements.md +161 -0
  86. package/docs/components/context-selector.md +126 -0
  87. package/docs/core-concepts/rbac-system.md +3 -3
  88. package/docs/documentation-index.md +2 -4
  89. package/docs/getting-started/cursor-rules.md +2 -1
  90. package/docs/migration/DOCUMENTATION_STRUCTURE.md +441 -0
  91. package/docs/migration/MIGRATION_GUIDE.md +2 -24
  92. package/docs/migration/RBAC_SCOPE_MIGRATION.md +385 -0
  93. package/docs/migration/README.md +52 -6
  94. package/docs/migration/V0.5.190_TO_V0.6.1_MIGRATION.md +1153 -0
  95. package/docs/migration/database-changes-december-2025.md +3 -3
  96. package/docs/pace-mint-fix-auto-selection.md +218 -0
  97. package/docs/pace-mint-rbac-setup.md +391 -0
  98. package/docs/rbac/event-based-apps.md +1 -1
  99. package/docs/rbac/getting-started.md +1 -1
  100. package/docs/rbac/quick-start.md +1 -1
  101. package/docs/rbac/secure-client-protection.md +330 -0
  102. package/docs/standards/README.md +1 -0
  103. package/package.json +4 -3
  104. package/scripts/audit/core/checks/accessibility.cjs +197 -0
  105. package/scripts/audit/core/checks/api-usage.cjs +191 -0
  106. package/scripts/audit/core/checks/bundle.cjs +142 -0
  107. package/scripts/{check-pace-core-compliance.cjs → audit/core/checks/compliance.cjs} +784 -685
  108. package/scripts/audit/core/checks/config.cjs +54 -0
  109. package/scripts/audit/core/checks/coverage.cjs +84 -0
  110. package/scripts/audit/core/checks/dependencies.cjs +985 -0
  111. package/scripts/audit/core/checks/documentation.cjs +268 -0
  112. package/scripts/audit/core/checks/environment.cjs +116 -0
  113. package/scripts/audit/core/checks/error-handling.cjs +340 -0
  114. package/scripts/audit/core/checks/forms.cjs +172 -0
  115. package/scripts/audit/core/checks/heuristics.cjs +68 -0
  116. package/scripts/audit/core/checks/hooks.cjs +334 -0
  117. package/scripts/audit/core/checks/imports.cjs +244 -0
  118. package/scripts/audit/core/checks/performance.cjs +325 -0
  119. package/scripts/audit/core/checks/routes.cjs +117 -0
  120. package/scripts/audit/core/checks/state.cjs +130 -0
  121. package/scripts/audit/core/checks/structure.cjs +65 -0
  122. package/scripts/audit/core/checks/style.cjs +584 -0
  123. package/scripts/audit/core/checks/testing.cjs +122 -0
  124. package/scripts/audit/core/checks/typescript.cjs +61 -0
  125. package/scripts/audit/core/scanner.cjs +199 -0
  126. package/scripts/audit/core/utils.cjs +137 -0
  127. package/scripts/audit/index.cjs +223 -0
  128. package/scripts/audit/reporters/console.cjs +151 -0
  129. package/scripts/audit/reporters/json.cjs +54 -0
  130. package/scripts/audit/reporters/markdown.cjs +124 -0
  131. package/scripts/audit-consuming-app.cjs +61 -936
  132. package/scripts/build-docs/build-decision.js +240 -0
  133. package/scripts/build-docs/cache-utils.js +105 -0
  134. package/scripts/build-docs/content-normalization.js +150 -0
  135. package/scripts/build-docs/file-utils.js +105 -0
  136. package/scripts/build-docs/git-utils.js +86 -0
  137. package/scripts/build-docs/hash-utils.js +116 -0
  138. package/scripts/build-docs/typedoc-runner.js +220 -0
  139. package/scripts/build-docs-incremental.js +77 -913
  140. package/scripts/utils/command-runner.js +16 -11
  141. package/scripts/validate-formats.js +61 -56
  142. package/scripts/validate-master.js +74 -69
  143. package/scripts/validate-pre-publish.js +70 -65
  144. package/src/__tests__/hooks/usePermissions.test.ts +2 -2
  145. package/src/components/Alert/Alert.test.tsx +12 -18
  146. package/src/components/Alert/Alert.tsx +5 -7
  147. package/src/components/Avatar/Avatar.test.tsx +4 -4
  148. package/src/components/Badge/Badge.tsx +14 -0
  149. package/src/components/Button/Button.tsx +22 -0
  150. package/src/components/Calendar/Calendar.tsx +8 -2
  151. package/src/components/Card/Card.tsx +4 -0
  152. package/src/components/Checkbox/Checkbox.test.tsx +12 -12
  153. package/src/components/Checkbox/Checkbox.tsx +2 -2
  154. package/src/components/ContextSelector/ContextSelector.tsx +384 -0
  155. package/src/components/ContextSelector/index.ts +3 -0
  156. package/src/components/DataTable/DataTable.tsx +38 -4
  157. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +5 -6
  158. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +18 -4
  159. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +2 -3
  160. package/src/components/DataTable/components/AccessDeniedPage.tsx +16 -25
  161. package/src/components/DataTable/components/ActionButtons.tsx +10 -7
  162. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +1 -1
  163. package/src/components/DataTable/components/ColumnFilter.tsx +10 -0
  164. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +12 -0
  165. package/src/components/DataTable/components/DataTableBody.tsx +8 -0
  166. package/src/components/DataTable/components/DataTableCore.tsx +196 -554
  167. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +11 -0
  168. package/src/components/DataTable/components/DataTableLayout.tsx +559 -0
  169. package/src/components/DataTable/components/DataTableModals.tsx +8 -0
  170. package/src/components/DataTable/components/DataTableToolbar.tsx +8 -0
  171. package/src/components/DataTable/components/DraggableColumnHeader.tsx +12 -0
  172. package/src/components/DataTable/components/EditFields.tsx +307 -0
  173. package/src/components/DataTable/components/EditableRow.tsx +8 -0
  174. package/src/components/DataTable/components/EmptyState.tsx +10 -0
  175. package/src/components/DataTable/components/FilterRow.tsx +12 -0
  176. package/src/components/DataTable/components/GroupHeader.tsx +12 -0
  177. package/src/components/DataTable/components/GroupingDropdown.tsx +12 -0
  178. package/src/components/DataTable/components/ImportModal.tsx +7 -0
  179. package/src/components/DataTable/components/LoadingState.tsx +6 -0
  180. package/src/components/DataTable/components/PaginationControls.tsx +16 -1
  181. package/src/components/DataTable/components/RowComponent.tsx +391 -0
  182. package/src/components/DataTable/components/UnifiedTableBody.tsx +63 -851
  183. package/src/components/DataTable/components/VirtualizedDataTable.tsx +16 -4
  184. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +4 -2
  185. package/src/components/DataTable/components/cellValueUtils.ts +40 -0
  186. package/src/components/DataTable/components/hooks/useImportModalFocus.ts +53 -0
  187. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +126 -0
  188. package/src/components/DataTable/context/DataTableContext.tsx +50 -0
  189. package/src/components/DataTable/core/ColumnFactory.ts +31 -0
  190. package/src/components/DataTable/core/DataTableContext.tsx +32 -1
  191. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +10 -0
  192. package/src/components/DataTable/hooks/useColumnReordering.ts +12 -0
  193. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +10 -0
  194. package/src/components/DataTable/hooks/useDataTableDataPipeline.ts +16 -0
  195. package/src/components/DataTable/hooks/useDataTablePermissions.ts +127 -33
  196. package/src/components/DataTable/hooks/useDataTableState.ts +35 -1
  197. package/src/components/DataTable/hooks/useEffectiveColumnOrder.ts +12 -0
  198. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +11 -0
  199. package/src/components/DataTable/hooks/useTableColumns.ts +8 -0
  200. package/src/components/DataTable/hooks/useTableHandlers.ts +14 -0
  201. package/src/components/DataTable/styles.ts +6 -6
  202. package/src/components/DataTable/types.ts +6 -10
  203. package/src/components/DataTable/utils/a11yUtils.ts +7 -0
  204. package/src/components/DataTable/utils/debugTools.ts +18 -113
  205. package/src/components/DataTable/utils/errorHandling.ts +12 -0
  206. package/src/components/DataTable/utils/exportUtils.ts +9 -0
  207. package/src/components/DataTable/utils/flexibleImport.ts +12 -48
  208. package/src/components/DataTable/utils/paginationUtils.ts +8 -0
  209. package/src/components/DataTable/utils/performanceUtils.ts +5 -1
  210. package/src/components/Dialog/Dialog.tsx +31 -3
  211. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +180 -1
  212. package/src/components/ErrorBoundary/ErrorBoundary.tsx +45 -5
  213. package/src/components/ErrorBoundary/ErrorBoundaryContext.tsx +129 -0
  214. package/src/components/ErrorBoundary/index.ts +27 -2
  215. package/src/components/FileDisplay/FileDisplay.tsx +74 -28
  216. package/src/components/FileUpload/FileUpload.tsx +22 -2
  217. package/src/components/Footer/Footer.test.tsx +16 -16
  218. package/src/components/Footer/Footer.tsx +14 -11
  219. package/src/components/Form/Form.tsx +1 -0
  220. package/src/components/Header/Header.test.tsx +43 -73
  221. package/src/components/Header/Header.tsx +59 -49
  222. package/src/components/Input/Input.test.tsx +2 -2
  223. package/src/components/Input/Input.tsx +8 -4
  224. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +4 -4
  225. package/src/components/LoginForm/LoginForm.tsx +4 -0
  226. package/src/components/NavigationMenu/NavigationMenu.tsx +14 -513
  227. package/src/components/NavigationMenu/types.ts +56 -0
  228. package/src/components/NavigationMenu/useNavigationFiltering.ts +390 -0
  229. package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +10 -19
  230. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +2 -2
  231. package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +5 -5
  232. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +13 -11
  233. package/src/components/PaceAppLayout/PaceAppLayout.tsx +167 -44
  234. package/src/components/PaceAppLayout/README.md +14 -17
  235. package/src/components/PaceAppLayout/test-setup.tsx +3 -4
  236. package/src/components/PaceLoginPage/PaceLoginPage.tsx +3 -0
  237. package/src/components/PasswordChange/PasswordChangeForm.tsx +9 -0
  238. package/src/components/ProtectedRoute/ProtectedRoute.tsx +3 -9
  239. package/src/components/PublicLayout/PublicPageLayout.tsx +2 -5
  240. package/src/components/PublicLayout/PublicPageProvider.tsx +4 -0
  241. package/src/components/Select/Select.tsx +80 -434
  242. package/src/components/Select/context.ts +23 -0
  243. package/src/components/Select/hooks/useSelectEvents.ts +87 -0
  244. package/src/components/Select/hooks/useSelectSearch.ts +91 -0
  245. package/src/components/Select/hooks/useSelectState.ts +104 -0
  246. package/src/components/Select/index.ts +9 -1
  247. package/src/components/Select/types.ts +123 -0
  248. package/src/components/Select/utils/text.ts +26 -0
  249. package/src/components/SessionRestorationLoader/SessionRestorationLoader.tsx +4 -5
  250. package/src/components/Switch/Switch.tsx +4 -4
  251. package/src/components/Tabs/Tabs.tsx +1 -1
  252. package/src/components/Toast/Toast.tsx +4 -0
  253. package/src/components/Tooltip/Tooltip.tsx +2 -2
  254. package/src/components/UserMenu/UserMenu.test.tsx +24 -11
  255. package/src/components/UserMenu/UserMenu.tsx +21 -18
  256. package/src/components/index.ts +7 -7
  257. package/src/eslint-rules/pace-core-compliance.cjs +106 -0
  258. package/src/hooks/__tests__/index.unit.test.ts +2 -5
  259. package/src/hooks/__tests__/useAppConfig.unit.test.ts +4 -98
  260. package/src/hooks/index.ts +1 -2
  261. package/src/hooks/public/usePublicEvent.ts +4 -0
  262. package/src/hooks/public/usePublicEventLogo.ts +4 -0
  263. package/src/hooks/public/usePublicFileDisplay.ts +4 -0
  264. package/src/hooks/public/usePublicRouteParams.ts +4 -0
  265. package/src/hooks/services/useAuth.ts +32 -0
  266. package/src/hooks/services/useCurrentEvent.ts +6 -0
  267. package/src/hooks/services/useCurrentOrganisation.ts +6 -0
  268. package/src/hooks/useAppConfig.ts +15 -30
  269. package/src/hooks/useDebounce.ts +9 -0
  270. package/src/hooks/useEventTheme.ts +6 -0
  271. package/src/hooks/useFileDisplay.ts +81 -50
  272. package/src/hooks/useFileReference.ts +25 -7
  273. package/src/hooks/useFileUrl.ts +11 -1
  274. package/src/hooks/useFocusManagement.ts +14 -0
  275. package/src/hooks/useFocusTrap.ts +3 -0
  276. package/src/hooks/useInactivityTracker.ts +3 -0
  277. package/src/hooks/useKeyboardShortcuts.ts +4 -0
  278. package/src/hooks/useOrganisationPermissions.ts +4 -0
  279. package/src/hooks/useOrganisationSecurity.ts +4 -0
  280. package/src/hooks/usePerformanceMonitor.ts +4 -0
  281. package/src/hooks/usePermissionCache.ts +7 -0
  282. package/src/hooks/useQueryCache.ts +12 -1
  283. package/src/hooks/useSessionRestoration.ts +4 -0
  284. package/src/hooks/useStorage.ts +4 -0
  285. package/src/hooks/useToast.ts +1 -1
  286. package/src/index.ts +6 -6
  287. package/src/providers/__tests__/OrganisationProvider.test.tsx +92 -70
  288. package/src/providers/services/AuthServiceProvider.tsx +35 -7
  289. package/src/providers/services/EventServiceProvider.tsx +51 -5
  290. package/src/providers/services/InactivityServiceProvider.tsx +18 -0
  291. package/src/providers/services/OrganisationServiceProvider.tsx +18 -0
  292. package/src/providers/services/UnifiedAuthProvider.tsx +126 -134
  293. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +29 -13
  294. package/src/rbac/README.md +1 -1
  295. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +1 -1
  296. package/src/rbac/__tests__/scenarios.user-role.test.tsx +4 -5
  297. package/src/rbac/adapters.tsx +12 -3
  298. package/src/rbac/api.test.ts +59 -51
  299. package/src/rbac/api.ts +246 -167
  300. package/src/rbac/components/NavigationProvider.tsx +4 -1
  301. package/src/rbac/components/PagePermissionGuard.tsx +185 -17
  302. package/src/rbac/components/RoleBasedRouter.tsx +5 -1
  303. package/src/rbac/components/SecureDataProvider.test.tsx +84 -49
  304. package/src/rbac/components/SecureDataProvider.tsx +20 -5
  305. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +24 -14
  306. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +7 -0
  307. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +14 -6
  308. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +15 -4
  309. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +148 -24
  310. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +81 -15
  311. package/src/rbac/engine.ts +38 -14
  312. package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +32 -21
  313. package/src/rbac/hooks/permissions/index.ts +7 -0
  314. package/src/rbac/hooks/permissions/useAccessLevel.ts +105 -0
  315. package/src/rbac/hooks/permissions/useCachedPermissions.ts +79 -0
  316. package/src/rbac/hooks/permissions/useCan.ts +377 -0
  317. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +90 -0
  318. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +90 -0
  319. package/src/rbac/hooks/permissions/useMultiplePermissions.ts +93 -0
  320. package/src/rbac/hooks/permissions/usePermissions.ts +253 -0
  321. package/src/rbac/hooks/useCan.test.ts +64 -66
  322. package/src/rbac/hooks/usePermissions.ts +14 -995
  323. package/src/rbac/hooks/useRBAC.test.ts +1 -5
  324. package/src/rbac/hooks/useRBAC.ts +36 -37
  325. package/src/rbac/hooks/useResolvedScope.test.ts +120 -35
  326. package/src/rbac/hooks/useResolvedScope.ts +35 -40
  327. package/src/rbac/hooks/useResourcePermissions.test.ts +54 -18
  328. package/src/rbac/hooks/useResourcePermissions.ts +14 -4
  329. package/src/rbac/hooks/useSecureSupabase.ts +27 -7
  330. package/src/rbac/index.ts +7 -0
  331. package/src/rbac/permissions.ts +0 -30
  332. package/src/rbac/secureClient.test.ts +22 -18
  333. package/src/rbac/secureClient.ts +294 -68
  334. package/src/rbac/security.ts +0 -17
  335. package/src/rbac/types.ts +9 -0
  336. package/src/rbac/utils/__tests__/contextValidator.test.ts +64 -86
  337. package/src/rbac/utils/clientSecurity.ts +93 -0
  338. package/src/rbac/utils/contextValidator.ts +77 -168
  339. package/src/services/AuthService.ts +39 -7
  340. package/src/services/EventService.ts +186 -54
  341. package/src/services/OrganisationService.ts +81 -14
  342. package/src/services/__tests__/EventService.test.ts +1 -2
  343. package/src/services/base/BaseService.ts +3 -0
  344. package/src/theming/__tests__/parseEventColours.test.ts +6 -9
  345. package/src/theming/parseEventColours.ts +5 -19
  346. package/src/types/vitest-globals.d.ts +51 -26
  347. package/src/utils/__mocks__/supabaseMock.ts +1 -3
  348. package/src/utils/__tests__/formatting.unit.test.ts +4 -4
  349. package/src/utils/__tests__/index.unit.test.ts +2 -2
  350. package/src/utils/audit/audit.ts +0 -3
  351. package/src/utils/core/cn.ts +1 -1
  352. package/src/utils/dynamic/dynamicUtils.ts +7 -4
  353. package/src/utils/file-reference/index.ts +53 -1
  354. package/src/utils/formatting/formatting.ts +8 -18
  355. package/src/utils/index.ts +0 -1
  356. package/dist/chunk-3QRJFVBR.js.map +0 -1
  357. package/dist/chunk-3XTALGJF.js.map +0 -1
  358. package/dist/chunk-4N5C5XZU.js.map +0 -1
  359. package/dist/chunk-4ZC4GX36.js.map +0 -1
  360. package/dist/chunk-7D4SUZUM.js +0 -38
  361. package/dist/chunk-BYFSK72L.js.map +0 -1
  362. package/dist/chunk-EXUD6RNJ.js +0 -451
  363. package/dist/chunk-EXUD6RNJ.js.map +0 -1
  364. package/dist/chunk-GLK6VM3F.js.map +0 -1
  365. package/dist/chunk-I7PSE6JW.js.map +0 -1
  366. package/dist/chunk-JBKQ3SAO.js.map +0 -1
  367. package/dist/chunk-KNC55RTG.js.map +0 -1
  368. package/dist/chunk-LXQLPRQ2.js.map +0 -1
  369. package/dist/chunk-R77UEZ4E.js.map +0 -1
  370. package/dist/chunk-SQGMNID3.js.map +0 -1
  371. package/dist/chunk-T33XF5ZC.js +0 -12922
  372. package/dist/chunk-T33XF5ZC.js.map +0 -1
  373. package/dist/chunk-XM25TVIE.js.map +0 -1
  374. package/docs/api/classes/ColumnFactory.md +0 -243
  375. package/docs/api/classes/ErrorBoundary.md +0 -144
  376. package/docs/api/classes/InvalidScopeError.md +0 -73
  377. package/docs/api/classes/Logger.md +0 -178
  378. package/docs/api/classes/MissingUserContextError.md +0 -66
  379. package/docs/api/classes/OrganisationContextRequiredError.md +0 -66
  380. package/docs/api/classes/PermissionDeniedError.md +0 -73
  381. package/docs/api/classes/RBACAuditManager.md +0 -297
  382. package/docs/api/classes/RBACCache.md +0 -322
  383. package/docs/api/classes/RBACEngine.md +0 -171
  384. package/docs/api/classes/RBACError.md +0 -76
  385. package/docs/api/classes/RBACNotInitializedError.md +0 -66
  386. package/docs/api/classes/SecureSupabaseClient.md +0 -160
  387. package/docs/api/classes/StorageUtils.md +0 -328
  388. package/docs/api/enums/FileCategory.md +0 -184
  389. package/docs/api/enums/LogLevel.md +0 -54
  390. package/docs/api/enums/RBACErrorCode.md +0 -228
  391. package/docs/api/enums/RPCFunction.md +0 -118
  392. package/docs/api/interfaces/AddressFieldProps.md +0 -241
  393. package/docs/api/interfaces/AddressFieldRef.md +0 -94
  394. package/docs/api/interfaces/AggregateConfig.md +0 -43
  395. package/docs/api/interfaces/AutocompleteOptions.md +0 -75
  396. package/docs/api/interfaces/AvatarProps.md +0 -128
  397. package/docs/api/interfaces/BadgeProps.md +0 -27
  398. package/docs/api/interfaces/ButtonProps.md +0 -53
  399. package/docs/api/interfaces/CalendarProps.md +0 -70
  400. package/docs/api/interfaces/CardProps.md +0 -66
  401. package/docs/api/interfaces/ColorPalette.md +0 -7
  402. package/docs/api/interfaces/ColorShade.md +0 -66
  403. package/docs/api/interfaces/ComplianceResult.md +0 -30
  404. package/docs/api/interfaces/DataAccessRecord.md +0 -96
  405. package/docs/api/interfaces/DataRecord.md +0 -11
  406. package/docs/api/interfaces/DataTableAction.md +0 -249
  407. package/docs/api/interfaces/DataTableColumn.md +0 -504
  408. package/docs/api/interfaces/DataTableProps.md +0 -625
  409. package/docs/api/interfaces/DataTableToolbarButton.md +0 -96
  410. package/docs/api/interfaces/DatabaseComplianceResult.md +0 -85
  411. package/docs/api/interfaces/DatabaseIssue.md +0 -41
  412. package/docs/api/interfaces/EmptyStateConfig.md +0 -61
  413. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +0 -235
  414. package/docs/api/interfaces/EventAppRoleData.md +0 -71
  415. package/docs/api/interfaces/ExportColumn.md +0 -90
  416. package/docs/api/interfaces/ExportOptions.md +0 -126
  417. package/docs/api/interfaces/FileDisplayProps.md +0 -249
  418. package/docs/api/interfaces/FileMetadata.md +0 -129
  419. package/docs/api/interfaces/FileReference.md +0 -118
  420. package/docs/api/interfaces/FileSizeLimits.md +0 -7
  421. package/docs/api/interfaces/FileUploadOptions.md +0 -139
  422. package/docs/api/interfaces/FileUploadProps.md +0 -293
  423. package/docs/api/interfaces/FooterProps.md +0 -105
  424. package/docs/api/interfaces/FormFieldProps.md +0 -166
  425. package/docs/api/interfaces/FormProps.md +0 -113
  426. package/docs/api/interfaces/GrantEventAppRoleParams.md +0 -122
  427. package/docs/api/interfaces/InactivityWarningModalProps.md +0 -115
  428. package/docs/api/interfaces/InputProps.md +0 -53
  429. package/docs/api/interfaces/LabelProps.md +0 -107
  430. package/docs/api/interfaces/LoggerConfig.md +0 -62
  431. package/docs/api/interfaces/LoginFormProps.md +0 -184
  432. package/docs/api/interfaces/NavigationAccessRecord.md +0 -107
  433. package/docs/api/interfaces/NavigationContextType.md +0 -164
  434. package/docs/api/interfaces/NavigationGuardProps.md +0 -139
  435. package/docs/api/interfaces/NavigationItem.md +0 -120
  436. package/docs/api/interfaces/NavigationMenuProps.md +0 -221
  437. package/docs/api/interfaces/NavigationProviderProps.md +0 -117
  438. package/docs/api/interfaces/Organisation.md +0 -140
  439. package/docs/api/interfaces/OrganisationContextType.md +0 -388
  440. package/docs/api/interfaces/OrganisationMembership.md +0 -140
  441. package/docs/api/interfaces/OrganisationProviderProps.md +0 -76
  442. package/docs/api/interfaces/OrganisationSecurityError.md +0 -62
  443. package/docs/api/interfaces/PaceAppLayoutProps.md +0 -406
  444. package/docs/api/interfaces/PaceLoginPageProps.md +0 -47
  445. package/docs/api/interfaces/PageAccessRecord.md +0 -85
  446. package/docs/api/interfaces/PagePermissionContextType.md +0 -140
  447. package/docs/api/interfaces/PagePermissionGuardProps.md +0 -153
  448. package/docs/api/interfaces/PagePermissionProviderProps.md +0 -119
  449. package/docs/api/interfaces/PaletteData.md +0 -41
  450. package/docs/api/interfaces/ParsedAddress.md +0 -120
  451. package/docs/api/interfaces/PermissionEnforcerProps.md +0 -153
  452. package/docs/api/interfaces/ProgressProps.md +0 -42
  453. package/docs/api/interfaces/ProtectedRouteProps.md +0 -97
  454. package/docs/api/interfaces/PublicPageFooterProps.md +0 -112
  455. package/docs/api/interfaces/PublicPageHeaderProps.md +0 -125
  456. package/docs/api/interfaces/PublicPageLayoutProps.md +0 -198
  457. package/docs/api/interfaces/QuickFix.md +0 -52
  458. package/docs/api/interfaces/RBACAccessValidateParams.md +0 -52
  459. package/docs/api/interfaces/RBACAccessValidateResult.md +0 -41
  460. package/docs/api/interfaces/RBACAuditLogParams.md +0 -85
  461. package/docs/api/interfaces/RBACAuditLogResult.md +0 -52
  462. package/docs/api/interfaces/RBACConfig.md +0 -133
  463. package/docs/api/interfaces/RBACContext.md +0 -52
  464. package/docs/api/interfaces/RBACLogger.md +0 -112
  465. package/docs/api/interfaces/RBACPageAccessCheckParams.md +0 -74
  466. package/docs/api/interfaces/RBACPerformanceMetrics.md +0 -138
  467. package/docs/api/interfaces/RBACPermissionCheckParams.md +0 -74
  468. package/docs/api/interfaces/RBACPermissionCheckResult.md +0 -52
  469. package/docs/api/interfaces/RBACPermissionsGetParams.md +0 -63
  470. package/docs/api/interfaces/RBACPermissionsGetResult.md +0 -63
  471. package/docs/api/interfaces/RBACResult.md +0 -58
  472. package/docs/api/interfaces/RBACRoleGrantParams.md +0 -63
  473. package/docs/api/interfaces/RBACRoleGrantResult.md +0 -52
  474. package/docs/api/interfaces/RBACRoleRevokeParams.md +0 -63
  475. package/docs/api/interfaces/RBACRoleRevokeResult.md +0 -52
  476. package/docs/api/interfaces/RBACRoleValidateParams.md +0 -52
  477. package/docs/api/interfaces/RBACRoleValidateResult.md +0 -63
  478. package/docs/api/interfaces/RBACRolesListParams.md +0 -52
  479. package/docs/api/interfaces/RBACRolesListResult.md +0 -74
  480. package/docs/api/interfaces/RBACSessionTrackParams.md +0 -74
  481. package/docs/api/interfaces/RBACSessionTrackResult.md +0 -52
  482. package/docs/api/interfaces/ResourcePermissions.md +0 -155
  483. package/docs/api/interfaces/RevokeEventAppRoleParams.md +0 -100
  484. package/docs/api/interfaces/RoleBasedRouterContextType.md +0 -151
  485. package/docs/api/interfaces/RoleBasedRouterProps.md +0 -156
  486. package/docs/api/interfaces/RoleManagementResult.md +0 -52
  487. package/docs/api/interfaces/RouteAccessRecord.md +0 -107
  488. package/docs/api/interfaces/RouteConfig.md +0 -134
  489. package/docs/api/interfaces/RuntimeComplianceResult.md +0 -55
  490. package/docs/api/interfaces/SecureDataContextType.md +0 -168
  491. package/docs/api/interfaces/SecureDataProviderProps.md +0 -132
  492. package/docs/api/interfaces/SessionRestorationLoaderProps.md +0 -34
  493. package/docs/api/interfaces/SetupIssue.md +0 -41
  494. package/docs/api/interfaces/StorageConfig.md +0 -41
  495. package/docs/api/interfaces/StorageFileInfo.md +0 -74
  496. package/docs/api/interfaces/StorageFileMetadata.md +0 -151
  497. package/docs/api/interfaces/StorageListOptions.md +0 -99
  498. package/docs/api/interfaces/StorageListResult.md +0 -41
  499. package/docs/api/interfaces/StorageUploadOptions.md +0 -101
  500. package/docs/api/interfaces/StorageUploadResult.md +0 -63
  501. package/docs/api/interfaces/StorageUrlOptions.md +0 -60
  502. package/docs/api/interfaces/StyleImport.md +0 -19
  503. package/docs/api/interfaces/SwitchProps.md +0 -34
  504. package/docs/api/interfaces/TabsContentProps.md +0 -9
  505. package/docs/api/interfaces/TabsListProps.md +0 -9
  506. package/docs/api/interfaces/TabsProps.md +0 -9
  507. package/docs/api/interfaces/TabsTriggerProps.md +0 -50
  508. package/docs/api/interfaces/TextareaProps.md +0 -53
  509. package/docs/api/interfaces/ToastActionElement.md +0 -9
  510. package/docs/api/interfaces/ToastProps.md +0 -9
  511. package/docs/api/interfaces/UnifiedAuthContextType.md +0 -820
  512. package/docs/api/interfaces/UnifiedAuthProviderProps.md +0 -171
  513. package/docs/api/interfaces/UseFormDialogOptions.md +0 -62
  514. package/docs/api/interfaces/UseFormDialogReturn.md +0 -117
  515. package/docs/api/interfaces/UseInactivityTrackerOptions.md +0 -136
  516. package/docs/api/interfaces/UseInactivityTrackerReturn.md +0 -123
  517. package/docs/api/interfaces/UsePublicEventLogoOptions.md +0 -87
  518. package/docs/api/interfaces/UsePublicEventLogoReturn.md +0 -81
  519. package/docs/api/interfaces/UsePublicEventOptions.md +0 -34
  520. package/docs/api/interfaces/UsePublicEventReturn.md +0 -68
  521. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +0 -47
  522. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +0 -120
  523. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +0 -94
  524. package/docs/api/interfaces/UseResolvedScopeOptions.md +0 -47
  525. package/docs/api/interfaces/UseResolvedScopeReturn.md +0 -47
  526. package/docs/api/interfaces/UseResourcePermissionsOptions.md +0 -34
  527. package/docs/api/interfaces/UserEventAccess.md +0 -118
  528. package/docs/api/interfaces/UserMenuProps.md +0 -86
  529. package/docs/api/interfaces/UserProfile.md +0 -63
  530. package/docs/migration/quick-migration-guide.md +0 -356
  531. package/docs/migration/service-architecture.md +0 -281
  532. package/src/components/EventSelector/EventSelector.test.tsx +0 -720
  533. package/src/components/EventSelector/EventSelector.tsx +0 -420
  534. package/src/components/EventSelector/index.ts +0 -3
  535. package/src/components/OrganisationSelector/OrganisationSelector.test.tsx +0 -784
  536. package/src/components/OrganisationSelector/OrganisationSelector.tsx +0 -324
  537. package/src/components/OrganisationSelector/index.ts +0 -9
  538. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +0 -680
  539. package/src/hooks/useSecureDataAccess.test.ts +0 -559
  540. package/src/hooks/useSecureDataAccess.ts +0 -681
  541. /package/dist/{DataTable-DQ7RSOHE.js.map → DataTable-THFPBKTP.js.map} +0 -0
  542. /package/dist/{UnifiedAuthProvider-ATAP5UTR.js.map → UnifiedAuthProvider-KAGUYQ4J.js.map} +0 -0
  543. /package/dist/{api-N774RPUA.js.map → api-IAGWF3ZG.js.map} +0 -0
  544. /package/dist/{audit-B5P6FFIR.js.map → audit-V53FV5AG.js.map} +0 -0
  545. /package/dist/{chunk-7D4SUZUM.js.map → chunk-DGUM43GV.js.map} +0 -0
  546. /package/docs/migration/{organisation-context-timing-fix.md → V0.3.44_organisation-context-timing-fix.md} +0 -0
  547. /package/docs/migration/{rbac-migration.md → V0.4.0_rbac-migration.md} +0 -0
  548. /package/docs/migration/{person-scoped-profiles-migration-guide.md → V0.5.190_person-scoped-profiles-migration-guide.md} +0 -0
  549. /package/docs/migration/{REACT_19_MIGRATION.md → V0.6.0_REACT_19_MIGRATION.md} +0 -0
@@ -47,28 +47,28 @@
47
47
  *
48
48
  * // Footer with custom content
49
49
  * <Footer companyName="My Company">
50
- * <div className="grid grid-cols-1 md:grid-cols-3 gap-8 mb-8">
51
- * <div>
50
+ * <section className="grid grid-cols-1 md:grid-cols-3 gap-8 mb-8">
51
+ * <section>
52
52
  * <h3 className="font-semibold mb-2">About Us</h3>
53
53
  * <p className="text-sm text-muted-foreground">
54
54
  * We provide innovative solutions for modern businesses.
55
55
  * </p>
56
- * </div>
57
- * <div>
56
+ * </section>
57
+ * <section>
58
58
  * <h3 className="font-semibold mb-2">Contact</h3>
59
59
  * <p className="text-sm text-muted-foreground">
60
60
  * Email: info@mycompany.com<br />
61
61
  * Phone: (555) 123-4567
62
62
  * </p>
63
- * </div>
64
- * <div>
63
+ * </section>
64
+ * <section>
65
65
  * <h3 className="font-semibold mb-2">Follow Us</h3>
66
- * <div className="flex gap-2">
66
+ * <nav className="flex gap-2">
67
67
  * <a href="#" className="text-muted-foreground hover:text-foreground">Twitter</a>
68
68
  * <a href="#" className="text-muted-foreground hover:text-foreground">LinkedIn</a>
69
- * </div>
70
- * </div>
71
- * </div>
69
+ * </nav>
70
+ * </section>
71
+ * </section>
72
72
  * </Footer>
73
73
  * ```
74
74
  *
@@ -87,6 +87,9 @@
87
87
  import React from 'react';
88
88
  import { cn } from '../../utils/core/cn';
89
89
 
90
+ /**
91
+ * Props for the Footer component.
92
+ */
90
93
  export interface FooterProps {
91
94
  /**
92
95
  * Company or organization name
@@ -138,7 +141,7 @@ export interface FooterProps {
138
141
  *
139
142
  * // With children
140
143
  * <Footer>
141
- * <div>Custom footer content</div>
144
+ * <section>Custom footer content</section>
142
145
  * </Footer>
143
146
  *
144
147
  * // With logo and copyright
@@ -359,6 +359,7 @@ export function FormField<
359
359
  type={type}
360
360
  placeholder={placeholder}
361
361
  data-testid={testId}
362
+ aria-label={label || placeholder || name}
362
363
  className={cn(
363
364
  "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
364
365
  fieldError && "border-destructive focus-visible:ring-destructive"
@@ -52,20 +52,24 @@ vi.mock('../UserMenu', () => ({
52
52
  ),
53
53
  }));
54
54
 
55
- vi.mock('../EventSelector', () => ({
56
- EventSelector: ({ placeholder, className, 'data-testid': testId }: any) => (
57
- <div data-testid={testId || 'event-selector'} className={className}>
58
- <button>{placeholder}</button>
55
+ vi.mock('../ContextSelector', () => ({
56
+ ContextSelector: ({ placeholder, className, 'data-testid': testId }: any) => (
57
+ <div data-testid={testId || 'context-selector'} className={className}>
58
+ <button>{placeholder || 'Select organisation or event'}</button>
59
59
  </div>
60
60
  ),
61
61
  }));
62
62
 
63
- vi.mock('../OrganisationSelector', () => ({
64
- OrganisationSelector: ({ placeholder, className, 'data-testid': testId }: any) => (
65
- <div data-testid={testId || 'org-selector'} className={className}>
66
- <button>{placeholder}</button>
67
- </div>
68
- ),
63
+ // Mock useEventService to prevent provider requirement
64
+ vi.mock('../../hooks/services/useEventService', () => ({
65
+ useEventService: vi.fn(() => ({
66
+ getEvents: vi.fn(() => []),
67
+ getSelectedEvent: vi.fn(() => null),
68
+ isLoading: vi.fn(() => false),
69
+ getError: vi.fn(() => null),
70
+ setSelectedEvent: vi.fn(),
71
+ refreshEvents: vi.fn()
72
+ }))
69
73
  }));
70
74
 
71
75
  // Mock useOrganisations hook
@@ -90,7 +94,7 @@ vi.mock('../../hooks/useOrganisations', () => ({
90
94
  isContextReady: true,
91
95
  isLoading: false,
92
96
  error: null,
93
- selectOrganisation: vi.fn(),
97
+ switchOrganisation: vi.fn(),
94
98
  refreshOrganisations: vi.fn(),
95
99
  userMemberships: []
96
100
  }))
@@ -314,44 +318,44 @@ describe('Header Component', () => {
314
318
  });
315
319
  });
316
320
 
317
- // Event selector tests
318
- describe('Event Selector', () => {
319
- it('renders event selector when showEventSelector is true', () => {
320
- renderWithProviders(<Header showEventSelector={true} />);
321
+ // Context selector tests
322
+ describe('Context Selector', () => {
323
+ it('renders context selector by default', () => {
324
+ renderWithProviders(<Header />);
321
325
 
322
- expect(screen.getByTestId('event-selector')).toBeInTheDocument();
326
+ expect(screen.getByTestId('context-selector')).toBeInTheDocument();
323
327
  });
324
328
 
325
- it('does not render event selector when showEventSelector is false', () => {
326
- renderWithProviders(<Header showEventSelector={false} />);
329
+ it('does not render context selector when showContextSelector is false', () => {
330
+ renderWithProviders(<Header showContextSelector={false} />);
327
331
 
328
- expect(screen.queryByTestId('event-selector')).not.toBeInTheDocument();
332
+ expect(screen.queryByTestId('context-selector')).not.toBeInTheDocument();
329
333
  });
330
334
 
331
- it('renders event selector by default', () => {
332
- renderWithProviders(<Header />);
335
+ it('renders context selector when showContextSelector is explicitly true', () => {
336
+ renderWithProviders(<Header showContextSelector={true} />);
333
337
 
334
- expect(screen.getByTestId('event-selector')).toBeInTheDocument();
338
+ expect(screen.getByTestId('context-selector')).toBeInTheDocument();
335
339
  });
336
340
 
337
- it('applies correct className to event selector', () => {
338
- renderWithProviders(<Header showEventSelector={true} />);
341
+ it('applies correct className to context selector', () => {
342
+ renderWithProviders(<Header showContextSelector={true} />);
339
343
 
340
- const eventSelector = screen.getByTestId('event-selector');
341
- expect(eventSelector).toBeInTheDocument();
342
- expect(eventSelector).toBeVisible();
344
+ const contextSelector = screen.getByTestId('context-selector');
345
+ expect(contextSelector).toBeInTheDocument();
346
+ expect(contextSelector).toBeVisible();
343
347
  });
344
348
 
345
349
  it('shows correct placeholder text', () => {
346
- renderWithProviders(<Header showEventSelector={true} />);
350
+ renderWithProviders(<Header showContextSelector={true} />);
347
351
 
348
- expect(screen.getByRole('button', { name: 'Select event' })).toBeInTheDocument();
352
+ expect(screen.getByRole('button', { name: 'Select organisation or event' })).toBeInTheDocument();
349
353
  });
350
354
 
351
- it('preserves layout when event selector is hidden', () => {
355
+ it('preserves layout when context selector is hidden', () => {
352
356
  renderWithProviders(
353
357
  <Header
354
- showEventSelector={false}
358
+ showContextSelector={false}
355
359
  user={mockUser}
356
360
  showUserMenu={true}
357
361
  />
@@ -361,47 +365,14 @@ describe('Header Component', () => {
361
365
  expect(nav).toBeInTheDocument();
362
366
  expect(nav).toBeVisible();
363
367
 
364
- // Event selector should not be rendered
365
- expect(screen.queryByTestId('event-selector')).not.toBeInTheDocument();
368
+ // Context selector should not be rendered
369
+ expect(screen.queryByTestId('context-selector')).not.toBeInTheDocument();
366
370
 
367
371
  // User menu should still be present and positioned correctly
368
372
  expect(screen.getByTestId('user-menu')).toBeInTheDocument();
369
373
  });
370
374
  });
371
375
 
372
- // Organisation Selector tests
373
- describe('Organisation Selector', () => {
374
- it('does not render organisation selector by default', () => {
375
- renderWithProviders(<Header />);
376
-
377
- expect(screen.queryByTestId('org-selector')).not.toBeInTheDocument();
378
- });
379
-
380
- it('renders organisation selector when showOrgSelector is true', () => {
381
- renderWithProviders(<Header showOrgSelector={true} />);
382
-
383
- expect(screen.getByTestId('org-selector')).toBeInTheDocument();
384
- });
385
-
386
- it('does not render organisation selector when showOrgSelector is false', () => {
387
- renderWithProviders(<Header showOrgSelector={false} />);
388
-
389
- expect(screen.queryByTestId('org-selector')).not.toBeInTheDocument();
390
- });
391
-
392
- it('can render both organisation and event selectors together', () => {
393
- renderWithProviders(
394
- <Header
395
- showOrgSelector={true}
396
- showEventSelector={true}
397
- />
398
- );
399
-
400
- expect(screen.getByTestId('org-selector')).toBeInTheDocument();
401
- expect(screen.getByTestId('event-selector')).toBeInTheDocument();
402
- });
403
- });
404
-
405
376
  // Custom actions tests
406
377
  describe('Custom Actions', () => {
407
378
  it('renders custom actions when provided', () => {
@@ -598,7 +569,7 @@ describe('Header Component', () => {
598
569
  navItems={mockNavItems}
599
570
  user={mockUser}
600
571
  actions={customActions}
601
- showEventSelector={true}
572
+ showContextSelector={true}
602
573
  showUserMenu={true}
603
574
  />
604
575
  );
@@ -609,8 +580,8 @@ describe('Header Component', () => {
609
580
  // Navigation
610
581
  expect(screen.getByTestId('navigation-menu')).toBeInTheDocument();
611
582
 
612
- // Event Selector
613
- expect(screen.getByTestId('event-selector')).toBeInTheDocument();
583
+ // Context Selector
584
+ expect(screen.getByTestId('context-selector')).toBeInTheDocument();
614
585
 
615
586
  // Custom Actions
616
587
  expect(screen.getByTestId('custom-actions')).toBeInTheDocument();
@@ -622,7 +593,7 @@ describe('Header Component', () => {
622
593
  it('renders minimal configuration', () => {
623
594
  renderWithProviders(
624
595
  <Header
625
- showEventSelector={false}
596
+ showContextSelector={false}
626
597
  showUserMenu={false}
627
598
  />
628
599
  );
@@ -631,9 +602,8 @@ describe('Header Component', () => {
631
602
  expect(screen.getByRole('banner')).toBeInTheDocument();
632
603
  expect(screen.getByRole('img', { name: 'Logo' })).toBeInTheDocument();
633
604
  expect(screen.queryByTestId('navigation-menu')).not.toBeInTheDocument();
634
- expect(screen.queryByTestId('event-selector')).not.toBeInTheDocument();
605
+ expect(screen.queryByTestId('context-selector')).not.toBeInTheDocument();
635
606
  expect(screen.queryByTestId('user-menu')).not.toBeInTheDocument();
636
- expect(screen.queryByTestId('org-selector')).not.toBeInTheDocument();
637
607
  });
638
608
  });
639
609
 
@@ -649,7 +619,7 @@ describe('Header Component', () => {
649
619
  navItems={mockNavItems}
650
620
  user={mockUser}
651
621
  actions={<div>Actions</div>}
652
- showEventSelector={true}
622
+ showContextSelector={true}
653
623
  showUserMenu={true}
654
624
  />
655
625
  );
@@ -42,20 +42,20 @@
42
42
  * ]}
43
43
  * currentPath="/dashboard"
44
44
  * actions={
45
- * <div className="flex gap-2">
45
+ * <>
46
46
  * <Button variant="outline">Export</Button>
47
47
  * <Button>New Item</Button>
48
- * </div>
48
+ * </>
49
49
  * }
50
50
  * user={currentUser}
51
51
  * onSignOut={handleSignOut}
52
52
  * />
53
53
  *
54
- * // Header without event selector
54
+ * // Header without context selector
55
55
  * <Header
56
56
  * logoUrl="/logo.svg"
57
57
  * logoHref="/dashboard"
58
- * showEventSelector={false}
58
+ * showContextSelector={false}
59
59
  * user={currentUser}
60
60
  * onSignOut={handleSignOut}
61
61
  * />
@@ -83,21 +83,21 @@
83
83
  * - Tailwind CSS - Styling
84
84
  * - NavigationMenu component
85
85
  * - UserMenu component
86
- * - OrganisationSelector component
87
- * - EventSelector component
86
+ * - ContextSelector component (unified org/event selector)
88
87
  */
89
88
 
90
89
  import React from 'react';
91
90
  import { Link } from 'react-router-dom';
92
91
  import { User } from '@supabase/supabase-js';
93
92
  import { cn } from '../../utils/core/cn';
94
- import { EventSelector } from '../EventSelector';
95
- import { OrganisationSelector } from '../OrganisationSelector';
93
+ import { ContextSelector } from '../ContextSelector';
96
94
  import { UserMenu } from '../UserMenu';
97
95
  import { NavigationMenu } from '../NavigationMenu';
98
96
  import type { NavigationItem } from '../NavigationMenu';
99
97
  import type { PasswordChangeFormError } from '../PasswordChange/PasswordChangeForm';
100
98
  import { useOrganisations } from '../../hooks/useOrganisations';
99
+ import { useEvents } from '../../hooks/useEvents';
100
+ import type { Event } from '../../types/event';
101
101
 
102
102
  /**
103
103
  * Props for the Header component
@@ -123,10 +123,12 @@ export interface HeaderProps {
123
123
  userMenu?: React.ReactNode;
124
124
  /** Custom className */
125
125
  className?: string;
126
- /** Show/hide event selector */
127
- showEventSelector?: boolean;
128
- /** Show/hide organisation selector */
129
- showOrgSelector?: boolean;
126
+ /** Show/hide context selector (unified org/event selector) - default: true */
127
+ showContextSelector?: boolean;
128
+ /** Show organisations in context selector - default: true */
129
+ showOrganisations?: boolean;
130
+ /** Show events in context selector - default: true */
131
+ showEvents?: boolean;
130
132
  /** Show/hide user menu */
131
133
  showUserMenu?: boolean;
132
134
  /** Current path for navigation highlighting */
@@ -199,10 +201,10 @@ export interface HeaderProps {
199
201
  *
200
202
  * function HeaderWithActions() {
201
203
  * const customActions = (
202
- * <div className="flex items-center gap-2">
204
+ * <>
203
205
  * <Button variant="outline" size="sm">Export</Button>
204
206
  * <Button size="sm">New Item</Button>
205
- * </div>
207
+ * </>
206
208
  * );
207
209
  *
208
210
  * return (
@@ -225,7 +227,7 @@ export interface HeaderProps {
225
227
  * <Header
226
228
  * logoUrl="/simple-logo.svg"
227
229
  * logoAlt="Simple App"
228
- * showEventSelector={false}
230
+ * showContextSelector={false}
229
231
  * user={currentUser}
230
232
  * onSignOut={handleSignOut}
231
233
  * />
@@ -238,6 +240,13 @@ export interface HeaderProps {
238
240
  *
239
241
  * @since 0.1.0
240
242
  */
243
+ /**
244
+ * Header component for application layouts.
245
+ * Provides navigation, user menu, organisation/event selectors, and customizable branding.
246
+ *
247
+ * @param props - Header configuration
248
+ * @returns The rendered header
249
+ */
241
250
  export function Header({
242
251
  logoUrl,
243
252
  logoAlt = 'Logo',
@@ -249,36 +258,27 @@ export function Header({
249
258
  actions,
250
259
  userMenu,
251
260
  className,
252
- showEventSelector = true,
253
- showOrgSelector = false,
261
+ showContextSelector = true,
262
+ showOrganisations = true,
263
+ showEvents = true,
254
264
  showUserMenu = true,
255
265
  currentPath,
256
266
  onNavigate,
257
267
  logoHref
258
268
  }: HeaderProps) {
259
- // Conditional wrapper for organisation selector - only show if user has organisations
260
- const OrganisationSelectorConditional = () => {
261
- const { organisations, isContextReady } = useOrganisations();
262
- // Only show selector if user has organisations and context is ready
263
- if (!isContextReady || !organisations || organisations.length === 0) {
264
- return null;
265
- }
266
- return (
267
- <OrganisationSelector
268
- placeholder="Select organisation"
269
- className="w-64"
270
- data-testid="org-selector"
271
- compact={true}
272
- />
273
- );
274
- };
269
+ // Determine if context selector should be shown
270
+ const shouldShowContextSelector = showContextSelector !== false;
271
+
272
+ // Get hooks for context selector
273
+ const { switchOrganisation } = useOrganisations();
274
+ const { events, setSelectedEvent } = useEvents();
275
275
 
276
276
  return (
277
277
  <header className={cn(
278
278
  "w-full border-b border-main-200 h-16 shadow-sm bg-main-100 ",
279
279
  className
280
280
  )} role="banner">
281
- <nav className="px-4 w-[min(var(--app-width),100%)] mx-auto flex items-center gap-4 h-full">
281
+ <nav className="px-4 w-[min(var(--app-width),100%)] mx-auto grid grid-cols-[auto_1fr_auto_auto_auto_auto] items-center gap-4 h-full">
282
282
  {/* Logo */}
283
283
  {logo ? (
284
284
  logoHref ? (
@@ -333,21 +333,32 @@ export function Header({
333
333
  itemsPreFiltered={true}
334
334
  />
335
335
  )}
336
-
337
-
338
- {/* Right side: Organisation Selector, Event Selector, Actions, and User Menu */}
339
- <div className="flex items-center gap-4 ml-auto">
340
- {/* Organisation Selector - Only show if user has organisations */}
341
- {showOrgSelector ? (
342
- <OrganisationSelectorConditional />
343
- ) : null}
344
336
 
345
- {/* Event Selector */}
346
- {showEventSelector ? (
347
- <EventSelector
348
- placeholder="Select event"
349
- className="w-96"
350
- data-testid="event-selector"
337
+ {/* Unified Context Selector - Shows all accessible orgs and events */}
338
+ {shouldShowContextSelector ? (
339
+ <ContextSelector
340
+ placeholder="Select organisation or event"
341
+ className={cn(
342
+ "w-96",
343
+ // Adjust width based on whether actions exist
344
+ actions ? "col-span-1" : "col-span-2"
345
+ )}
346
+ showOrganisations={showOrganisations}
347
+ showEvents={showEvents}
348
+ onOrganisationSelect={async (org) => {
349
+ // When switching to an organisation, clear event selection FIRST
350
+ // This ensures the userClearedEventRef flag is set before any event refresh
351
+ // This prevents auto-selection from re-selecting the event
352
+ setSelectedEvent(null);
353
+ // Then switch organisation (this may trigger event refresh, but flag is already set)
354
+ await switchOrganisation(org.id);
355
+ }}
356
+ onEventSelect={(event) => {
357
+ // Find the full event object from the events list
358
+ const fullEvent = events.find((e: Event) => (e.event_id || e.id) === (event.event_id || event.id));
359
+ setSelectedEvent(fullEvent || event);
360
+ }}
361
+ compact={true}
351
362
  />
352
363
  ) : null}
353
364
 
@@ -367,7 +378,6 @@ export function Header({
367
378
  />
368
379
  )
369
380
  )}
370
- </div>
371
381
 
372
382
  </nav>
373
383
  </header>
@@ -420,14 +420,14 @@ describe('InputGroup Component', () => {
420
420
  // Accessibility tests
421
421
  describe('Accessibility', () => {
422
422
  it('forwards ref correctly', () => {
423
- const ref = React.createRef<HTMLDivElement>();
423
+ const ref = React.createRef<HTMLFieldSetElement>();
424
424
  renderWithProviders(
425
425
  <InputGroup ref={ref}>
426
426
  <Input placeholder="Input 1" />
427
427
  </InputGroup>
428
428
  );
429
429
 
430
- expect(ref.current).toBeInstanceOf(HTMLDivElement);
430
+ expect(ref.current).toBeInstanceOf(HTMLFieldSetElement);
431
431
  });
432
432
 
433
433
  it('maintains proper focus order', async () => {
@@ -55,6 +55,10 @@ import { cn } from '../../utils/core/cn';
55
55
  // BASE INPUT COMPONENT
56
56
  // ============================================================================
57
57
 
58
+ /**
59
+ * Props for the Input component.
60
+ * Extends standard input HTML attributes.
61
+ */
58
62
  export interface InputProps
59
63
  extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {
60
64
  /**
@@ -136,7 +140,7 @@ Input.displayName = 'Input';
136
140
  // INPUT GROUP COMPONENT
137
141
  // ============================================================================
138
142
 
139
- export interface InputGroupProps extends React.HTMLAttributes<HTMLDivElement> {
143
+ export interface InputGroupProps extends React.HTMLAttributes<HTMLFieldSetElement> {
140
144
  /** Child elements to be rendered in the group */
141
145
  children: React.ReactNode;
142
146
  /** Layout orientation of the input group */
@@ -165,7 +169,7 @@ export interface InputGroupProps extends React.HTMLAttributes<HTMLDivElement> {
165
169
  * </InputGroup>
166
170
  * ```
167
171
  */
168
- export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>(
172
+ export const InputGroup = React.forwardRef<HTMLFieldSetElement, InputGroupProps>(
169
173
  ({ className, children, orientation = 'vertical', spacing = 'md', ...props }, ref) => {
170
174
  const spacingClasses = {
171
175
  sm: orientation === 'horizontal' ? 'space-x-2' : 'space-y-2',
@@ -174,7 +178,7 @@ export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>(
174
178
  };
175
179
 
176
180
  return (
177
- <div
181
+ <fieldset
178
182
  ref={ref}
179
183
  className={cn(
180
184
  'flex',
@@ -185,7 +189,7 @@ export const InputGroup = React.forwardRef<HTMLDivElement, InputGroupProps>(
185
189
  {...props}
186
190
  >
187
191
  {children}
188
- </div>
192
+ </fieldset>
189
193
  );
190
194
  }
191
195
  );
@@ -382,10 +382,10 @@ describe('LoadingSpinner Component', () => {
382
382
 
383
383
  it('works within a card or container', () => {
384
384
  renderWithProviders(
385
- <div className="card">
385
+ <section className="card">
386
386
  <h2>Loading Content</h2>
387
387
  <LoadingSpinner size="lg" />
388
- </div>
388
+ </section>
389
389
  );
390
390
 
391
391
  const spinner = screen.getByRole('status');
@@ -397,11 +397,11 @@ describe('LoadingSpinner Component', () => {
397
397
 
398
398
  it('works with multiple instances', () => {
399
399
  renderWithProviders(
400
- <div>
400
+ <>
401
401
  <LoadingSpinner size="sm" />
402
402
  <LoadingSpinner size="md" />
403
403
  <LoadingSpinner size="lg" />
404
- </div>
404
+ </>
405
405
  );
406
406
 
407
407
  const spinners = screen.getAllByRole('status');
@@ -106,6 +106,10 @@ import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle }
106
106
  import { Alert, AlertDescription } from '../Alert/Alert';
107
107
  import { cn } from '../../utils/core/cn';
108
108
 
109
+ /**
110
+ * Props for the LoginForm component.
111
+ * Configures login form behavior, validation, and callbacks.
112
+ */
109
113
  export interface LoginFormProps {
110
114
  /** Callback invoked when the form is submitted */
111
115
  onSignIn: (data: { email: string; password: string }) => Promise<void>;