@jmruthers/pace-core 0.5.135 → 0.5.136

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 (522) hide show
  1. package/dist/{DataTable-C7GaRZye.d.ts → DataTable-CWAZZcXC.d.ts} +1 -1
  2. package/dist/{DataTable-A36PJG6N.js → DataTable-CYOHOX3O.js} +25 -13
  3. package/dist/{PublicLoadingSpinner-CUAnTvcg.d.ts → EventLogo-801uofbR.d.ts} +51 -135
  4. package/dist/UnifiedAuthProvider-5E5TUNMS.js +17 -0
  5. package/dist/{UnifiedAuthProvider-BVKmQd9u.d.ts → UnifiedAuthProvider-DJxGTftH.d.ts} +1 -1
  6. package/dist/{api-TNIBJWLM.js → api-45XYYO2A.js} +4 -3
  7. package/dist/{audit-T36HM7IM.js → audit-64X3VJXB.js} +3 -2
  8. package/dist/{chunk-CTJRBUX2.js → chunk-2TWNJ46Y.js} +2 -2
  9. package/dist/{chunk-UJI6WSMD.js → chunk-444EZN6N.js} +3 -3
  10. package/dist/chunk-444EZN6N.js.map +1 -0
  11. package/dist/{chunk-3CG5L6RN.js → chunk-4MT5BGGL.js} +90 -73
  12. package/dist/chunk-4MT5BGGL.js.map +1 -0
  13. package/dist/{chunk-PYUXFQJ3.js → chunk-56XJ3TU6.js} +2 -2
  14. package/dist/chunk-56XJ3TU6.js.map +1 -0
  15. package/dist/chunk-5DPZ5EAT.js +60 -0
  16. package/dist/chunk-5DPZ5EAT.js.map +1 -0
  17. package/dist/{chunk-66C4BSAY.js → chunk-ANBQRTPX.js} +9 -2
  18. package/dist/chunk-ANBQRTPX.js.map +1 -0
  19. package/dist/chunk-APIBCTL2.js +670 -0
  20. package/dist/chunk-APIBCTL2.js.map +1 -0
  21. package/dist/{chunk-GKHF54DI.js → chunk-BESYRHQM.js} +10 -4
  22. package/dist/chunk-BESYRHQM.js.map +1 -0
  23. package/dist/{chunk-WP5I5GLN.js → chunk-BVYWGZVV.js} +112 -97
  24. package/dist/chunk-BVYWGZVV.js.map +1 -0
  25. package/dist/{chunk-GEVIB2UB.js → chunk-ERISIBYU.js} +14 -5
  26. package/dist/chunk-ERISIBYU.js.map +1 -0
  27. package/dist/{chunk-CQZU6TFE.js → chunk-FHWWBIHA.js} +100 -62
  28. package/dist/chunk-FHWWBIHA.js.map +1 -0
  29. package/dist/{chunk-O3NWNXDY.js → chunk-FMUCXFII.js} +2 -2
  30. package/dist/chunk-FMUCXFII.js.map +1 -0
  31. package/dist/{chunk-GVDR7WNV.js → chunk-HJGGOMQ6.js} +194 -518
  32. package/dist/chunk-HJGGOMQ6.js.map +1 -0
  33. package/dist/{chunk-BDZUMRBD.js → chunk-K2WWTH7O.js} +13 -6
  34. package/dist/chunk-K2WWTH7O.js.map +1 -0
  35. package/dist/{chunk-BYXRHAIF.js → chunk-L6PGMCMD.js} +23 -14
  36. package/dist/chunk-L6PGMCMD.js.map +1 -0
  37. package/dist/chunk-LMC26NLJ.js +84 -0
  38. package/dist/chunk-LMC26NLJ.js.map +1 -0
  39. package/dist/{chunk-M6DDYFUD.js → chunk-LS353YLY.js} +19 -16
  40. package/dist/chunk-LS353YLY.js.map +1 -0
  41. package/dist/{chunk-ZYZCRSBD.js → chunk-LTV3XIJJ.js} +16 -11
  42. package/dist/chunk-LTV3XIJJ.js.map +1 -0
  43. package/dist/{chunk-HMNOSGVA.js → chunk-NOHEVYVX.js} +377 -666
  44. package/dist/chunk-NOHEVYVX.js.map +1 -0
  45. package/dist/{chunk-JCQZ6LA7.js → chunk-Q5QRDWKI.js} +9 -3
  46. package/dist/chunk-Q5QRDWKI.js.map +1 -0
  47. package/dist/chunk-S5OFRT4M.js +94 -0
  48. package/dist/chunk-S5OFRT4M.js.map +1 -0
  49. package/dist/{chunk-3DBFLLLU.js → chunk-SBVILCCA.js} +14 -9
  50. package/dist/chunk-SBVILCCA.js.map +1 -0
  51. package/dist/{chunk-TGIY2AR2.js → chunk-SL2YQDR6.js} +4 -3
  52. package/dist/{chunk-TGIY2AR2.js.map → chunk-SL2YQDR6.js.map} +1 -1
  53. package/dist/{chunk-VZ5OR6HD.js → chunk-TVYPTYOY.js} +55 -179
  54. package/dist/chunk-TVYPTYOY.js.map +1 -0
  55. package/dist/{chunk-ZV77RZMU.js → chunk-XARJS7CD.js} +2 -2
  56. package/dist/chunk-XDNLUEXI.js +138 -0
  57. package/dist/chunk-XDNLUEXI.js.map +1 -0
  58. package/dist/{chunk-F64FFPOZ.js → chunk-YLKIDTUK.js} +26 -20
  59. package/dist/chunk-YLKIDTUK.js.map +1 -0
  60. package/dist/{chunk-5F3NDPJV.js → chunk-ZZ2SS7NI.js} +10 -5
  61. package/dist/chunk-ZZ2SS7NI.js.map +1 -0
  62. package/dist/components.d.ts +7 -287
  63. package/dist/components.js +26 -157
  64. package/dist/components.js.map +1 -1
  65. package/dist/{file-reference-C9isKNPn.d.ts → file-reference-C6Gkn77H.d.ts} +1 -1
  66. package/dist/{formatting-DFcCxUEk.d.ts → formatting-CvUXy2mF.d.ts} +1 -1
  67. package/dist/hooks.d.ts +3 -3
  68. package/dist/hooks.js +22 -16
  69. package/dist/hooks.js.map +1 -1
  70. package/dist/index.d.ts +101 -9
  71. package/dist/index.js +43 -31
  72. package/dist/index.js.map +1 -1
  73. package/dist/providers.d.ts +1 -1
  74. package/dist/providers.js +5 -4
  75. package/dist/rbac/index.js +13 -12
  76. package/dist/styles/index.js +2 -1
  77. package/dist/theming/runtime.d.ts +2 -19
  78. package/dist/theming/runtime.js +2 -1
  79. package/dist/{types-D5rqZQXk.d.ts → types-Dfz9dmVH.d.ts} +12 -1
  80. package/dist/types.d.ts +2 -2
  81. package/dist/types.js +1 -1
  82. package/dist/{useInactivityTracker-MRUU55XI.js → useInactivityTracker-TO6ZOF35.js} +3 -2
  83. package/dist/{usePublicRouteParams-Dyt1tzI9.d.ts → usePublicRouteParams-B7PabvuH.d.ts} +1 -1
  84. package/dist/utils.d.ts +195 -232
  85. package/dist/utils.js +173 -331
  86. package/dist/utils.js.map +1 -1
  87. package/dist/{validation-DnhrNMju.d.ts → validation-8npbysjg.d.ts} +26 -8
  88. package/dist/validation.d.ts +261 -10
  89. package/dist/validation.js +82 -440
  90. package/dist/validation.js.map +1 -1
  91. package/docs/api/classes/ColumnFactory.md +1 -1
  92. package/docs/api/classes/ErrorBoundary.md +6 -6
  93. package/docs/api/classes/InvalidScopeError.md +1 -1
  94. package/docs/api/classes/MissingUserContextError.md +1 -1
  95. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  96. package/docs/api/classes/PermissionDeniedError.md +1 -1
  97. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  98. package/docs/api/classes/RBACAuditManager.md +6 -6
  99. package/docs/api/classes/RBACCache.md +1 -1
  100. package/docs/api/classes/RBACEngine.md +7 -7
  101. package/docs/api/classes/RBACError.md +1 -1
  102. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  103. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  104. package/docs/api/classes/StorageUtils.md +1 -1
  105. package/docs/api/enums/FileCategory.md +1 -1
  106. package/docs/api/interfaces/AggregateConfig.md +4 -4
  107. package/docs/api/interfaces/ButtonProps.md +1 -1
  108. package/docs/api/interfaces/CardProps.md +1 -1
  109. package/docs/api/interfaces/ColorPalette.md +1 -1
  110. package/docs/api/interfaces/ColorShade.md +29 -4
  111. package/docs/api/interfaces/DataAccessRecord.md +9 -9
  112. package/docs/api/interfaces/DataRecord.md +1 -1
  113. package/docs/api/interfaces/DataTableAction.md +18 -18
  114. package/docs/api/interfaces/DataTableColumn.md +61 -1
  115. package/docs/api/interfaces/DataTableProps.md +1 -1
  116. package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
  117. package/docs/api/interfaces/EmptyStateConfig.md +5 -5
  118. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +14 -14
  119. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  120. package/docs/api/interfaces/EventLogoProps.md +152 -0
  121. package/docs/api/interfaces/ExportColumn.md +1 -1
  122. package/docs/api/interfaces/ExportOptions.md +8 -8
  123. package/docs/api/interfaces/FileDisplayProps.md +15 -15
  124. package/docs/api/interfaces/FileMetadata.md +1 -1
  125. package/docs/api/interfaces/FileReference.md +1 -1
  126. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  127. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  128. package/docs/api/interfaces/FileUploadProps.md +1 -1
  129. package/docs/api/interfaces/FooterProps.md +1 -1
  130. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  131. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  132. package/docs/api/interfaces/InputProps.md +1 -1
  133. package/docs/api/interfaces/LabelProps.md +1 -1
  134. package/docs/api/interfaces/LoginFormProps.md +1 -1
  135. package/docs/api/interfaces/NavigationAccessRecord.md +10 -10
  136. package/docs/api/interfaces/NavigationContextType.md +9 -9
  137. package/docs/api/interfaces/NavigationGuardProps.md +10 -10
  138. package/docs/api/interfaces/NavigationItem.md +1 -1
  139. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  140. package/docs/api/interfaces/NavigationProviderProps.md +7 -7
  141. package/docs/api/interfaces/Organisation.md +1 -1
  142. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  143. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  144. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  145. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  146. package/docs/api/interfaces/PaceAppLayoutProps.md +27 -27
  147. package/docs/api/interfaces/PaceLoginPageProps.md +4 -4
  148. package/docs/api/interfaces/PageAccessRecord.md +8 -8
  149. package/docs/api/interfaces/PagePermissionContextType.md +8 -8
  150. package/docs/api/interfaces/PagePermissionGuardProps.md +11 -11
  151. package/docs/api/interfaces/PagePermissionProviderProps.md +7 -7
  152. package/docs/api/interfaces/PaletteData.md +4 -4
  153. package/docs/api/interfaces/PermissionEnforcerProps.md +11 -11
  154. package/docs/api/interfaces/ProtectedRouteProps.md +6 -6
  155. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  156. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  157. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  158. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  159. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  160. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  161. package/docs/api/interfaces/RBACConfig.md +1 -1
  162. package/docs/api/interfaces/RBACLogger.md +1 -1
  163. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  164. package/docs/api/interfaces/RoleBasedRouterContextType.md +8 -8
  165. package/docs/api/interfaces/RoleBasedRouterProps.md +10 -10
  166. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  167. package/docs/api/interfaces/RouteAccessRecord.md +10 -10
  168. package/docs/api/interfaces/RouteConfig.md +10 -10
  169. package/docs/api/interfaces/SecureDataContextType.md +9 -9
  170. package/docs/api/interfaces/SecureDataProviderProps.md +8 -8
  171. package/docs/api/interfaces/SessionRestorationLoaderProps.md +21 -0
  172. package/docs/api/interfaces/StorageConfig.md +1 -1
  173. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  174. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  175. package/docs/api/interfaces/StorageListOptions.md +1 -1
  176. package/docs/api/interfaces/StorageListResult.md +1 -1
  177. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  178. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  179. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  180. package/docs/api/interfaces/StyleImport.md +1 -1
  181. package/docs/api/interfaces/SwitchProps.md +1 -1
  182. package/docs/api/interfaces/ToastActionElement.md +1 -1
  183. package/docs/api/interfaces/ToastProps.md +1 -1
  184. package/docs/api/interfaces/UnifiedAuthContextType.md +53 -53
  185. package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
  186. package/docs/api/interfaces/UseInactivityTrackerOptions.md +9 -9
  187. package/docs/api/interfaces/UseInactivityTrackerReturn.md +8 -8
  188. package/docs/api/interfaces/UsePublicEventOptions.md +3 -3
  189. package/docs/api/interfaces/UsePublicEventReturn.md +5 -5
  190. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +4 -4
  191. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +9 -9
  192. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  193. package/docs/api/interfaces/UseResolvedScopeOptions.md +4 -4
  194. package/docs/api/interfaces/UseResolvedScopeReturn.md +4 -4
  195. package/docs/api/interfaces/UserEventAccess.md +11 -11
  196. package/docs/api/interfaces/UserMenuProps.md +1 -1
  197. package/docs/api/interfaces/UserProfile.md +1 -1
  198. package/docs/api/modules.md +514 -212
  199. package/docs/api-reference/components.md +106 -26
  200. package/docs/architecture/README.md +0 -2
  201. package/docs/implementation-guides/data-tables.md +277 -13
  202. package/docs/implementation-guides/forms.md +1 -16
  203. package/docs/implementation-guides/permission-enforcement.md +8 -2
  204. package/examples/README.md +30 -14
  205. package/examples/STRUCTURE.md +125 -0
  206. package/examples/components/DataTable/HierarchicalActionsExample.tsx +421 -0
  207. package/examples/components/DataTable/HierarchicalExample.tsx +475 -0
  208. package/examples/components/DataTable/InitialPageSizeExample.tsx +177 -0
  209. package/examples/components/DataTable/PerformanceExample.tsx +506 -0
  210. package/examples/components/DataTable/index.ts +13 -0
  211. package/examples/components/Dialog/BasicHtmlTest.tsx +55 -0
  212. package/examples/components/Dialog/DebugHtmlExample.tsx +68 -0
  213. package/examples/components/Dialog/HtmlDialogExample.tsx +202 -0
  214. package/examples/components/Dialog/ScrollableDialogExample.tsx +290 -0
  215. package/examples/components/Dialog/SimpleHtmlTest.tsx +61 -0
  216. package/examples/components/Dialog/SmartDialogExample.tsx +322 -0
  217. package/examples/components/Dialog/index.ts +15 -0
  218. package/examples/components/index.ts +11 -0
  219. package/examples/features/index.ts +12 -0
  220. package/examples/{public-pages → features/public-pages}/CorrectPublicPageImplementation.tsx +1 -1
  221. package/examples/{public-pages → features/public-pages}/PublicEventPage.tsx +1 -1
  222. package/examples/{public-pages → features/public-pages}/PublicPageApp.tsx +1 -1
  223. package/examples/{public-pages → features/public-pages}/PublicPageUsageExample.tsx +1 -1
  224. package/examples/index.ts +11 -3
  225. package/package.json +30 -10
  226. package/src/components/Alert/Alert.tsx +1 -1
  227. package/src/components/Avatar/Avatar.tsx +1 -1
  228. package/src/components/Button/Button.tsx +1 -1
  229. package/src/components/Card/Card.tsx +1 -1
  230. package/src/components/Checkbox/Checkbox.tsx +1 -1
  231. package/src/components/DataTable/DataTable.test.tsx +1 -1
  232. package/src/components/DataTable/DataTable.tsx +1 -30
  233. package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +562 -0
  234. package/src/components/DataTable/__tests__/styles.test.ts +2 -2
  235. package/src/components/DataTable/components/ActionButtons.tsx +0 -15
  236. package/src/components/DataTable/components/DataTableCore.tsx +4 -185
  237. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +1 -1
  238. package/src/components/DataTable/components/DataTableModals.tsx +1 -27
  239. package/src/components/DataTable/components/EditableRow.tsx +1 -1
  240. package/src/components/DataTable/components/ImportModal.tsx +2 -14
  241. package/src/components/DataTable/components/PaginationControls.tsx +1 -1
  242. package/src/components/DataTable/components/UnifiedTableBody.tsx +109 -82
  243. package/src/components/DataTable/components/__tests__/ActionButtons.test.tsx +1 -1
  244. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +1 -1
  245. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +1 -1
  246. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +1 -1
  247. package/src/components/DataTable/examples/GroupingAggregationExample.tsx +273 -0
  248. package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +1 -1
  249. package/src/components/DataTable/examples/__tests__/HierarchicalActionsExample.test.tsx +1 -1
  250. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +1 -1
  251. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +1 -1
  252. package/src/components/DataTable/hooks/useDataTablePermissions.ts +2 -23
  253. package/src/components/DataTable/index.ts +4 -0
  254. package/src/components/DataTable/styles.ts +1 -1
  255. package/src/components/DataTable/types.ts +13 -0
  256. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +1 -1
  257. package/src/components/DataTable/utils/aggregationUtils.ts +161 -0
  258. package/src/components/DataTable/utils/exportUtils.ts +1 -1
  259. package/src/components/DataTable/utils/flexibleImport.ts +1 -11
  260. package/src/components/DataTable/utils/index.ts +1 -0
  261. package/src/components/DataTable/utils/paginationUtils.ts +1 -1
  262. package/src/components/Dialog/Dialog.tsx +2 -2
  263. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +35 -7
  264. package/src/components/ErrorBoundary/ErrorBoundary.tsx +5 -4
  265. package/src/components/EventSelector/EventSelector.tsx +3 -2
  266. package/src/components/FileDisplay/FileDisplay.tsx +2 -36
  267. package/src/components/FileUpload/FileUpload.test.tsx +2 -2
  268. package/src/components/FileUpload/FileUpload.tsx +2 -2
  269. package/src/components/Footer/Footer.tsx +1 -1
  270. package/src/components/Form/Form.test.tsx +4 -509
  271. package/src/components/Form/Form.tsx +1 -1
  272. package/src/components/Form/FormField.tsx +1 -1
  273. package/src/components/Form/index.ts +0 -12
  274. package/src/components/Header/Header.tsx +1 -1
  275. package/src/components/Input/Input.tsx +1 -1
  276. package/src/components/Label/Label.tsx +1 -1
  277. package/src/components/LoginForm/LoginForm.tsx +1 -1
  278. package/src/components/NavigationMenu/NavigationMenu.test.tsx +19 -3
  279. package/src/components/NavigationMenu/NavigationMenu.tsx +9 -8
  280. package/src/components/OrganisationSelector/OrganisationSelector.tsx +4 -3
  281. package/src/components/PaceAppLayout/PaceAppLayout.tsx +14 -12
  282. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.integration.test.tsx +0 -16
  283. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +0 -1
  284. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.unit.test.tsx +0 -9
  285. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +35 -3
  286. package/src/components/PaceLoginPage/PaceLoginPage.tsx +13 -12
  287. package/src/components/PasswordReset/PasswordChangeForm.tsx +1 -1
  288. package/src/components/PasswordReset/index.ts +0 -2
  289. package/src/components/Progress/Progress.tsx +1 -1
  290. package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +35 -8
  291. package/src/components/ProtectedRoute/ProtectedRoute.tsx +3 -2
  292. package/src/components/PublicLayout/PublicErrorBoundary.tsx +1 -1
  293. package/src/components/PublicLayout/PublicLoadingSpinner.tsx +1 -1
  294. package/src/components/PublicLayout/PublicPageContextChecker.tsx +44 -43
  295. package/src/components/PublicLayout/PublicPageFooter.tsx +1 -1
  296. package/src/components/PublicLayout/PublicPageHeader.tsx +1 -15
  297. package/src/components/PublicLayout/PublicPageProvider.tsx +3 -2
  298. package/src/components/PublicLayout/__tests__/PublicPageContextChecker.test.tsx +2 -0
  299. package/src/components/PublicLayout/index.ts +4 -2
  300. package/src/components/Select/Select.tsx +1 -1
  301. package/src/components/{SessionRestorationLoader.tsx → SessionRestorationLoader/SessionRestorationLoader.tsx} +3 -2
  302. package/src/components/SessionRestorationLoader/index.ts +3 -0
  303. package/src/components/Switch/Switch.tsx +1 -1
  304. package/src/components/Table/Table.tsx +1 -1
  305. package/src/components/Toast/Toast.tsx +1 -1
  306. package/src/components/Tooltip/Tooltip.tsx +1 -1
  307. package/src/components/index.ts +4 -10
  308. package/src/hooks/__tests__/hooks.integration.test.tsx +37 -22
  309. package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +33 -17
  310. package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +28 -3
  311. package/src/hooks/__tests__/useFileDisplay.unit.test.ts +36 -9
  312. package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +26 -2
  313. package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +19 -6
  314. package/src/hooks/__tests__/usePermissionCache.simple.test.ts +17 -4
  315. package/src/hooks/__tests__/usePermissionCache.unit.test.ts +17 -4
  316. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +26 -6
  317. package/src/hooks/__tests__/usePublicFileDisplay.test.ts +16 -6
  318. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +3 -3
  319. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +17 -3
  320. package/src/hooks/public/usePublicEvent.ts +7 -6
  321. package/src/hooks/public/usePublicEventLogo.ts +7 -4
  322. package/src/hooks/public/usePublicFileDisplay.ts +6 -150
  323. package/src/hooks/useComponentPerformance.ts +4 -1
  324. package/src/hooks/useDataTablePerformance.ts +4 -3
  325. package/src/hooks/useEventTheme.test.ts +18 -5
  326. package/src/hooks/useEventTheme.ts +4 -1
  327. package/src/hooks/useEvents.ts +2 -0
  328. package/src/hooks/useFileDisplay.ts +9 -8
  329. package/src/hooks/useFileReference.ts +4 -1
  330. package/src/hooks/useFileUrl.ts +4 -1
  331. package/src/hooks/useInactivityTracker.ts +5 -4
  332. package/src/hooks/useOrganisationSecurity.test.ts +33 -12
  333. package/src/hooks/useOrganisationSecurity.ts +8 -7
  334. package/src/hooks/usePerformanceMonitor.ts +6 -3
  335. package/src/hooks/usePermissionCache.ts +13 -6
  336. package/src/hooks/useSecureDataAccess.test.ts +2 -2
  337. package/src/hooks/useSecureDataAccess.ts +9 -8
  338. package/src/hooks/useSessionRestoration.ts +4 -1
  339. package/src/hooks/useStorage.ts +4 -1
  340. package/src/index.ts +16 -7
  341. package/src/providers/services/AuthServiceProvider.tsx +3 -2
  342. package/src/providers/services/EventServiceProvider.tsx +2 -1
  343. package/src/providers/services/InactivityServiceProvider.tsx +2 -1
  344. package/src/providers/services/OrganisationServiceProvider.tsx +2 -1
  345. package/src/providers/services/UnifiedAuthProvider.tsx +4 -3
  346. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +22 -2
  347. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +24 -2
  348. package/src/rbac/__tests__/cache-invalidation.test.ts +20 -6
  349. package/src/rbac/api.ts +5 -2
  350. package/src/rbac/audit-enhanced.ts +6 -6
  351. package/src/rbac/audit.test.ts +60 -38
  352. package/src/rbac/audit.ts +8 -8
  353. package/src/rbac/cache-invalidation.ts +7 -4
  354. package/src/rbac/components/EnhancedNavigationMenu.tsx +11 -5
  355. package/src/rbac/components/NavigationGuard.tsx +7 -3
  356. package/src/rbac/components/NavigationProvider.tsx +6 -3
  357. package/src/rbac/components/PagePermissionGuard.tsx +28 -16
  358. package/src/rbac/components/PagePermissionProvider.tsx +4 -1
  359. package/src/rbac/components/PermissionEnforcer.tsx +9 -3
  360. package/src/rbac/components/RoleBasedRouter.tsx +3 -1
  361. package/src/rbac/components/SecureDataProvider.tsx +7 -3
  362. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +87 -61
  363. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +83 -33
  364. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +36 -13
  365. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +2 -2
  366. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +22 -8
  367. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +19 -6
  368. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +43 -17
  369. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +42 -17
  370. package/src/rbac/engine.ts +15 -7
  371. package/src/rbac/hooks/usePermissions.ts +7 -3
  372. package/src/rbac/hooks/useResolvedScope.test.ts +2 -2
  373. package/src/rbac/hooks/useResolvedScope.ts +10 -7
  374. package/src/rbac/permissions.ts +5 -2
  375. package/src/rbac/security.test.ts +27 -16
  376. package/src/rbac/security.ts +5 -4
  377. package/src/services/AuthService.ts +22 -21
  378. package/src/services/EventService.ts +12 -12
  379. package/src/services/InactivityService.ts +5 -4
  380. package/src/services/OrganisationService.ts +26 -25
  381. package/src/services/__tests__/AuthService.test.ts +51 -19
  382. package/src/services/__tests__/EventService.test.ts +37 -5
  383. package/src/services/__tests__/InactivityService.test.ts +38 -4
  384. package/src/services/__tests__/OrganisationService.test.ts +3 -8
  385. package/src/services/base/BaseService.ts +3 -1
  386. package/src/theming/__tests__/runtime.test.ts +21 -12
  387. package/src/theming/parseEventColours.ts +5 -19
  388. package/src/theming/runtime.ts +8 -4
  389. package/src/types/validation.ts +2 -29
  390. package/src/utils/__tests__/appConfig.unit.test.ts +1 -1
  391. package/src/utils/__tests__/audit.unit.test.ts +1 -1
  392. package/src/utils/__tests__/auth-utils.unit.test.ts +1 -1
  393. package/src/utils/__tests__/bundleAnalysis.unit.test.ts +19 -19
  394. package/src/utils/__tests__/cn.unit.test.ts +1 -1
  395. package/src/utils/__tests__/debugLogger.test.ts +1 -1
  396. package/src/utils/__tests__/deviceFingerprint.unit.test.ts +1 -1
  397. package/src/utils/__tests__/dynamicUtils.unit.test.ts +1 -1
  398. package/src/utils/__tests__/formatting.unit.test.ts +1 -1
  399. package/src/utils/__tests__/lazyLoad.unit.test.tsx +1 -1
  400. package/src/utils/__tests__/logger.unit.test.ts +1 -1
  401. package/src/utils/__tests__/organisationContext.unit.test.ts +1 -1
  402. package/src/utils/__tests__/performanceBenchmark.test.ts +1 -1
  403. package/src/utils/__tests__/performanceBudgets.unit.test.ts +1 -1
  404. package/src/utils/__tests__/permissionTypes.unit.test.ts +1 -1
  405. package/src/utils/__tests__/permissionUtils.unit.test.ts +1 -1
  406. package/src/utils/__tests__/sanitization.unit.test.ts +1 -1
  407. package/src/utils/__tests__/schemaUtils.unit.test.ts +1 -1
  408. package/src/utils/__tests__/secureDataAccess.unit.test.ts +1 -1
  409. package/src/utils/__tests__/secureErrors.unit.test.ts +33 -15
  410. package/src/utils/__tests__/secureStorage.unit.test.ts +1 -1
  411. package/src/utils/__tests__/security.unit.test.ts +40 -18
  412. package/src/utils/__tests__/securityMonitor.unit.test.ts +1 -1
  413. package/src/utils/__tests__/sessionTracking.unit.test.ts +40 -29
  414. package/src/utils/__tests__/validationUtils.unit.test.ts +19 -6
  415. package/src/utils/{appIdResolver.test.ts → app/appIdResolver.test.ts} +28 -30
  416. package/src/utils/{appIdResolver.ts → app/appIdResolver.ts} +8 -5
  417. package/src/utils/{appNameResolver.test.ts → app/appNameResolver.test.ts} +1 -1
  418. package/src/utils/{appNameResolver.ts → app/appNameResolver.ts} +5 -1
  419. package/src/utils/{organisationContext.ts → context/organisationContext.ts} +6 -3
  420. package/src/utils/{sessionTracking.ts → context/sessionTracking.ts} +11 -12
  421. package/src/utils/{logger.ts → core/logger.ts} +4 -2
  422. package/src/utils/{deviceFingerprint.ts → device/deviceFingerprint.ts} +1 -1
  423. package/src/utils/{lazyLoad.tsx → dynamic/lazyLoad.tsx} +2 -2
  424. package/src/utils/{file-reference.test.ts → file-reference/__tests__/file-reference.test.ts} +5 -5
  425. package/src/utils/{file-reference.ts → file-reference/index.ts} +20 -38
  426. package/src/utils/index.ts +32 -54
  427. package/src/utils/{secureErrors.ts → security/secureErrors.ts} +6 -3
  428. package/src/utils/{security.ts → security/security.ts} +5 -2
  429. package/src/utils/storage/__tests__/helpers.unit.test.ts +1 -4
  430. package/src/utils/storage/helpers.ts +15 -8
  431. package/src/{components/Dialog/utils/__tests__/safeHtml.unit.test.ts → utils/validation/__tests__/htmlSanitization.unit.test.ts} +9 -15
  432. package/src/{validation → utils/validation}/csrf.ts +1 -1
  433. package/src/{components/Dialog/utils/safeHtml.ts → utils/validation/htmlSanitization.ts} +9 -10
  434. package/src/utils/validation/index.ts +79 -0
  435. package/src/utils/{sanitization.ts → validation/sanitization.ts} +71 -2
  436. package/src/{validation/schemaUtils.ts → utils/validation/schema.ts} +11 -6
  437. package/src/{validation → utils/validation}/sqlInjectionProtection.ts +2 -0
  438. package/src/utils/{validationUtils.ts → validation/validationUtils.ts} +4 -1
  439. package/src/validation/index.ts +3 -34
  440. package/dist/UnifiedAuthProvider-CQDZRJIS.js +0 -16
  441. package/dist/chunk-24MKLB7U.js +0 -81
  442. package/dist/chunk-24MKLB7U.js.map +0 -1
  443. package/dist/chunk-3CG5L6RN.js.map +0 -1
  444. package/dist/chunk-3DBFLLLU.js.map +0 -1
  445. package/dist/chunk-5F3NDPJV.js.map +0 -1
  446. package/dist/chunk-66C4BSAY.js.map +0 -1
  447. package/dist/chunk-BDZUMRBD.js.map +0 -1
  448. package/dist/chunk-BYXRHAIF.js.map +0 -1
  449. package/dist/chunk-CDQ3PX7L.js +0 -18
  450. package/dist/chunk-CDQ3PX7L.js.map +0 -1
  451. package/dist/chunk-CQZU6TFE.js.map +0 -1
  452. package/dist/chunk-F64FFPOZ.js.map +0 -1
  453. package/dist/chunk-GEVIB2UB.js.map +0 -1
  454. package/dist/chunk-GKHF54DI.js.map +0 -1
  455. package/dist/chunk-GVDR7WNV.js.map +0 -1
  456. package/dist/chunk-HMNOSGVA.js.map +0 -1
  457. package/dist/chunk-JCQZ6LA7.js.map +0 -1
  458. package/dist/chunk-M6DDYFUD.js.map +0 -1
  459. package/dist/chunk-O3NWNXDY.js.map +0 -1
  460. package/dist/chunk-PYUXFQJ3.js.map +0 -1
  461. package/dist/chunk-UJI6WSMD.js.map +0 -1
  462. package/dist/chunk-VZ5OR6HD.js.map +0 -1
  463. package/dist/chunk-WP5I5GLN.js.map +0 -1
  464. package/dist/chunk-ZYZCRSBD.js.map +0 -1
  465. package/src/components/Dialog/README.md +0 -804
  466. package/src/components/Form/FormErrorSummary.tsx +0 -113
  467. package/src/components/Form/FormFieldset.tsx +0 -127
  468. package/src/components/Form/FormLiveRegion.tsx +0 -198
  469. package/src/components/PasswordReset/PasswordResetForm.test.tsx +0 -597
  470. package/src/components/PasswordReset/PasswordResetForm.tsx +0 -201
  471. package/src/components/PublicLayout/PublicPageDebugger.tsx +0 -104
  472. package/src/components/PublicLayout/PublicPageDiagnostic.tsx +0 -162
  473. package/src/components/PublicLayout/__tests__/PublicPageDebugger.test.tsx +0 -185
  474. package/src/examples/CorrectPublicPageImplementation.tsx +0 -304
  475. package/src/examples/PublicEventPage.tsx +0 -287
  476. package/src/examples/PublicPageApp.tsx +0 -321
  477. package/src/examples/PublicPageUsageExample.tsx +0 -218
  478. package/src/utils/schemaUtils.ts +0 -37
  479. package/src/validation/__tests__/common.unit.test.ts +0 -101
  480. package/src/validation/__tests__/csrf.unit.test.ts +0 -365
  481. package/src/validation/__tests__/passwordSchema.unit.test.ts +0 -203
  482. package/src/validation/__tests__/sanitization.unit.test.ts +0 -250
  483. package/src/validation/__tests__/schemaUtils.unit.test.ts +0 -451
  484. package/src/validation/__tests__/sqlInjectionProtection.unit.test.ts +0 -462
  485. package/src/validation/__tests__/user.unit.test.ts +0 -440
  486. package/src/validation/sanitization.ts +0 -96
  487. /package/dist/{DataTable-A36PJG6N.js.map → DataTable-CYOHOX3O.js.map} +0 -0
  488. /package/dist/{UnifiedAuthProvider-CQDZRJIS.js.map → UnifiedAuthProvider-5E5TUNMS.js.map} +0 -0
  489. /package/dist/{api-TNIBJWLM.js.map → api-45XYYO2A.js.map} +0 -0
  490. /package/dist/{audit-T36HM7IM.js.map → audit-64X3VJXB.js.map} +0 -0
  491. /package/dist/{chunk-CTJRBUX2.js.map → chunk-2TWNJ46Y.js.map} +0 -0
  492. /package/dist/{chunk-ZV77RZMU.js.map → chunk-XARJS7CD.js.map} +0 -0
  493. /package/dist/{useInactivityTracker-MRUU55XI.js.map → useInactivityTracker-TO6ZOF35.js.map} +0 -0
  494. /package/examples/{public-pages → features/public-pages}/index.ts +0 -0
  495. /package/examples/{RBAC → features/rbac}/CompleteRBACExample.tsx +0 -0
  496. /package/examples/{RBAC → features/rbac}/EventBasedApp.tsx +0 -0
  497. /package/examples/{RBAC → features/rbac}/PermissionExample.tsx +0 -0
  498. /package/examples/{RBAC → features/rbac}/index.ts +0 -0
  499. /package/src/utils/{appConfig.ts → app/appConfig.ts} +0 -0
  500. /package/src/utils/{appNameResolver.simple.test.ts → app/appNameResolver.simple.test.ts} +0 -0
  501. /package/src/utils/{audit.ts → audit/audit.ts} +0 -0
  502. /package/src/utils/{organisationContext.test.ts → context/organisationContext.test.ts} +0 -0
  503. /package/src/utils/{cn.ts → core/cn.ts} +0 -0
  504. /package/src/utils/{debugLogger.ts → core/debugLogger.ts} +0 -0
  505. /package/src/utils/{dynamicUtils.ts → dynamic/dynamicUtils.ts} +0 -0
  506. /package/src/utils/{formatDate.test.ts → formatting/formatDate.test.ts} +0 -0
  507. /package/src/utils/{formatting.ts → formatting/formatting.ts} +0 -0
  508. /package/src/utils/{bundleAnalysis.ts → performance/bundleAnalysis.ts} +0 -0
  509. /package/src/utils/{performanceBenchmark.ts → performance/performanceBenchmark.ts} +0 -0
  510. /package/src/utils/{performanceBudgets.ts → performance/performanceBudgets.ts} +0 -0
  511. /package/src/utils/{permissionTypes.ts → permissions/permissionTypes.ts} +0 -0
  512. /package/src/utils/{permissionUtils.test.ts → permissions/permissionUtils.test.ts} +0 -0
  513. /package/src/utils/{permissionUtils.ts → permissions/permissionUtils.ts} +0 -0
  514. /package/src/utils/{auth-utils.ts → security/auth-utils.ts} +0 -0
  515. /package/src/utils/{secureDataAccess.test.ts → security/secureDataAccess.test.ts} +0 -0
  516. /package/src/utils/{secureDataAccess.ts → security/secureDataAccess.ts} +0 -0
  517. /package/src/utils/{secureStorage.ts → security/secureStorage.ts} +0 -0
  518. /package/src/utils/{securityMonitor.ts → security/securityMonitor.ts} +0 -0
  519. /package/src/{validation → utils/validation}/common.ts +0 -0
  520. /package/src/{validation → utils/validation}/passwordSchema.ts +0 -0
  521. /package/src/{validation → utils/validation}/user.ts +0 -0
  522. /package/src/utils/{validation.ts → validation/validation.ts} +0 -0
@@ -193,7 +193,7 @@
193
193
 
194
194
  import * as React from "react";
195
195
  import { Menu, ChevronDown } from "lucide-react";
196
- import { cn } from "../../utils/cn";
196
+ import { cn } from "../../utils/core/cn";
197
197
  import { NavigationMenuProps, NavigationItem } from "./types";
198
198
  import { Button } from "../Button";
199
199
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../Select";
@@ -202,6 +202,7 @@ import { useRBAC } from "../../rbac/hooks/useRBAC";
202
202
  import { useResolvedScope } from "../../rbac/hooks";
203
203
  import { usePermissions } from "../../rbac/hooks/usePermissions";
204
204
  import type { Permission, AccessLevel as RBACAccessLevel } from "../../rbac/types";
205
+ import { logger } from "../../utils/core/logger";
205
206
 
206
207
  /**
207
208
  * Unified NavigationMenu component that supports both dropdown and hierarchical navigation modes.
@@ -424,7 +425,7 @@ export const NavigationMenu = React.forwardRef<
424
425
  authContext = useUnifiedAuth();
425
426
  } catch (error) {
426
427
  // NavigationMenu is being used outside of UnifiedAuthProvider
427
- console.warn('[NavigationMenu] useUnifiedAuth not available, running in unauthenticated mode');
428
+ logger.warn('NavigationMenu', 'useUnifiedAuth not available, running in unauthenticated mode');
428
429
  }
429
430
 
430
431
  // Get RBAC context for permission and role checks
@@ -433,7 +434,7 @@ export const NavigationMenu = React.forwardRef<
433
434
  rbacContext = useRBAC();
434
435
  } catch (error) {
435
436
  // RBAC not available - permission filtering will be disabled
436
- console.warn('[NavigationMenu] useRBAC not available, permission filtering disabled');
437
+ logger.warn('NavigationMenu', 'useRBAC not available, permission filtering disabled');
437
438
  }
438
439
 
439
440
  // Get resolved scope for permission checks
@@ -524,7 +525,7 @@ export const NavigationMenu = React.forwardRef<
524
525
  // If there's an error or empty permission map after loading, show nothing
525
526
  // Security: Better to show nothing than risk showing unauthorized items
526
527
  if (permissionsError || !permissionMap || Object.keys(permissionMap).length === 0) {
527
- console.warn('[NavigationMenu] Permission map is empty or has error - showing no items for security', {
528
+ logger.warn('NavigationMenu', 'Permission map is empty or has error - showing no items for security', {
528
529
  permissionsError: permissionsError?.message,
529
530
  permissionMapSize: permissionMap ? Object.keys(permissionMap).length : 0
530
531
  });
@@ -643,7 +644,7 @@ export const NavigationMenu = React.forwardRef<
643
644
 
644
645
  if (!finalHasPermission) {
645
646
  if (auditLog) {
646
- console.log(`[NavigationMenu] Filtering out navigation item "${item.label}" - no page permission:`, {
647
+ logger.debug('NavigationMenu', `Filtering out navigation item "${item.label}" - no page permission:`, {
647
648
  itemId: item.id,
648
649
  href: item.href,
649
650
  pageId,
@@ -716,7 +717,7 @@ export const NavigationMenu = React.forwardRef<
716
717
  // Log navigation access attempts for debugging
717
718
  React.useEffect(() => {
718
719
  if (auditLog && authContext) {
719
- console.log('[NavigationMenu] Navigation access attempt:', {
720
+ logger.debug('NavigationMenu', 'Navigation access attempt:', {
720
721
  itemId: 'navigation-menu',
721
722
  label: 'Navigation Menu',
722
723
  href: currentPath,
@@ -766,7 +767,7 @@ export const NavigationMenu = React.forwardRef<
766
767
  // NEW: Phase 2 - Enhanced Security Features
767
768
  // Log navigation access attempt for audit
768
769
  if (auditLog) {
769
- console.log(`[NavigationMenu] Navigation access attempt:`, {
770
+ logger.debug('NavigationMenu', 'Navigation access attempt:', {
770
771
  itemId: item.id,
771
772
  label: item.label,
772
773
  href: item.href,
@@ -842,7 +843,7 @@ export const NavigationMenu = React.forwardRef<
842
843
  }
843
844
 
844
845
  if (strictMode) {
845
- console.error(`[NavigationMenu] STRICT MODE VIOLATION: User attempted to access protected navigation item without permission`, {
846
+ logger.error('NavigationMenu', 'STRICT MODE VIOLATION: User attempted to access protected navigation item without permission', {
846
847
  itemId: item.id,
847
848
  label: item.label,
848
849
  href: item.href,
@@ -61,6 +61,7 @@ import { LoadingSpinner } from '../LoadingSpinner/LoadingSpinner';
61
61
  import { RefreshCw, AlertCircle, Building2, Shield } from 'lucide-react';
62
62
  import { useOrganisations } from '../../providers/OrganisationProvider';
63
63
  import type { Organisation } from '../../types/organisation';
64
+ import { logger } from '../../utils/core/logger';
64
65
 
65
66
  export interface OrganisationSelectorProps {
66
67
  /** Placeholder text for the dropdown */
@@ -137,9 +138,9 @@ export function OrganisationSelector({
137
138
  onOrganisationChange(newOrganisation);
138
139
  }
139
140
 
140
- console.log("[OrganisationSelector] Successfully switched to organisation:", orgId);
141
+ logger.debug('OrganisationSelector', 'Successfully switched to organisation:', orgId);
141
142
  } catch (error) {
142
- console.error("[OrganisationSelector] Failed to switch organisation:", error);
143
+ logger.error('OrganisationSelector', 'Failed to switch organisation:', error);
143
144
  setSwitchError(error instanceof Error ? error.message : 'Failed to switch organisation');
144
145
  } finally {
145
146
  setIsLoading(false);
@@ -159,7 +160,7 @@ export function OrganisationSelector({
159
160
  try {
160
161
  await refreshOrganisations();
161
162
  } catch (error) {
162
- console.error("[OrganisationSelector] Failed to refresh organisations:", error);
163
+ logger.error('OrganisationSelector', 'Failed to refresh organisations:', error);
163
164
  setSwitchError('Failed to refresh organisations');
164
165
  } finally {
165
166
  setIsLoading(false);
@@ -105,8 +105,9 @@ import { useEvents } from '../../hooks/useEvents';
105
105
  import { useEventTheme } from '../../hooks/useEventTheme';
106
106
  import { useCan, useResolvedScope } from '../../rbac/hooks';
107
107
  import { createScopeFromEvent } from '../../rbac/utils/eventContext';
108
- import { getCurrentAppName } from '../../utils/appNameResolver';
108
+ import { getCurrentAppName } from '../../utils/app/appNameResolver';
109
109
  import { isSuperAdmin } from '../../rbac/api';
110
+ import { logger } from '../../utils/core/logger';
110
111
  import type { Permission, Scope } from '../../rbac/types';
111
112
 
112
113
  // Stable empty objects to prevent infinite loops
@@ -465,7 +466,7 @@ export function PaceAppLayout({
465
466
  const superAdminStatus = await isSuperAdmin(user.id);
466
467
  setIsSuperAdminUser(superAdminStatus);
467
468
  } catch (error) {
468
- console.error('[PaceAppLayout] Error checking super admin status:', error);
469
+ logger.error('PaceAppLayout', 'Error checking super admin status', { userId: user?.id, error });
469
470
  setIsSuperAdminUser(false);
470
471
  } finally {
471
472
  setIsCheckingSuperAdmin(false);
@@ -506,7 +507,7 @@ export function PaceAppLayout({
506
507
  // NEW: Phase 1 - Enhanced Security Features
507
508
  // Handle strict mode violations - skip for super admins
508
509
  if (strictMode && !isSuperAdminUser && !can) {
509
- console.error(`[PaceAppLayout] STRICT MODE VIOLATION: User attempted to access protected page without permission`, {
510
+ logger.error('PaceAppLayout', 'STRICT MODE VIOLATION: User attempted to access protected page without permission', {
510
511
  pageName: currentPageId,
511
512
  operation: currentRoutePermission,
512
513
  userId: user?.id,
@@ -626,7 +627,7 @@ export function PaceAppLayout({
626
627
  } catch (error) {
627
628
  // On error, fall back to showing all items (graceful degradation)
628
629
  // This prevents navigation from being empty if permission checks fail
629
- console.error('[PaceAppLayout] Failed to load permission map for navigation filtering:', error);
630
+ logger.error('PaceAppLayout', 'Failed to load permission map for navigation filtering', { userId: user?.id, error });
630
631
  if (isMounted) {
631
632
  setFilteredMenuItems(baseMenuItems);
632
633
  }
@@ -654,7 +655,7 @@ export function PaceAppLayout({
654
655
  if (!currentRoute) {
655
656
  // Route not found in configuration
656
657
  if (strictMode) {
657
- console.error(`[PaceAppLayout] STRICT MODE VIOLATION: Route not found in configuration`, {
658
+ logger.error('PaceAppLayout', 'STRICT MODE VIOLATION: Route not found in configuration', {
658
659
  route: currentPath,
659
660
  userId: user?.id,
660
661
  timestamp: new Date().toISOString()
@@ -685,7 +686,7 @@ export function PaceAppLayout({
685
686
  if (!isMounted) return;
686
687
  hasAccess = hasPagePermission;
687
688
  } catch (error) {
688
- console.error('[PaceAppLayout] Failed to check page permission:', error);
689
+ logger.error('PaceAppLayout', 'Failed to check page permission', { route: currentPath, pageId: currentRoute.pageId, error });
689
690
  if (!isMounted) return;
690
691
  hasAccess = false;
691
692
  }
@@ -709,7 +710,7 @@ export function PaceAppLayout({
709
710
  }
710
711
 
711
712
  if (strictMode) {
712
- console.error(`[PaceAppLayout] STRICT MODE VIOLATION: User attempted to access protected route without permission`, {
713
+ logger.error('PaceAppLayout', 'STRICT MODE VIOLATION: User attempted to access protected route without permission', {
713
714
  route: currentPath,
714
715
  userId: user?.id,
715
716
  permissions: currentRoute.permissions,
@@ -745,15 +746,16 @@ export function PaceAppLayout({
745
746
  const result = await updatePassword(newPassword);
746
747
  if (result?.error) {
747
748
  // The form will display the error message
748
- console.error('Failed to change password:', result.error.message);
749
+ logger.error('PaceAppLayout', 'Failed to change password', { error: result.error.message });
749
750
  }
750
751
  // The form will handle closing the modal on success
751
752
  return result || { error: null };
752
753
  };
753
754
 
754
755
  // Show loading state while checking permissions or super admin status
755
- // But don't show loading if we already have a permission error (prioritize error display)
756
- if (enforcePermissions && (isCheckingSuperAdmin || isCheckingPermission) && !permissionError) {
756
+ // Keep loading active until BOTH checks complete to prevent exposing protected content
757
+ // This ensures we don't render the main layout when permission check failed but super admin check is pending
758
+ if (enforcePermissions && (isCheckingSuperAdmin || isCheckingPermission)) {
757
759
  return (
758
760
  <div className="flex items-center justify-center min-h-screen">
759
761
  <div className="text-center">
@@ -764,9 +766,9 @@ export function PaceAppLayout({
764
766
  );
765
767
  }
766
768
 
767
- // Show permission error (check this after loading state, but only if super admin check is complete)
769
+ // Show permission error (only after BOTH checks are complete)
768
770
  // Super admins bypass all permission checks, so don't show errors for them
769
- if (enforcePermissions && permissionError && !isCheckingSuperAdmin && !isSuperAdminUser) {
771
+ if (enforcePermissions && permissionError && !isSuperAdminUser) {
770
772
  return (
771
773
  <div className="flex items-center justify-center min-h-screen">
772
774
  <div className="text-center">
@@ -102,14 +102,6 @@ const mockIsSuperAdmin = vi.fn().mockResolvedValue(false);
102
102
 
103
103
  vi.mock('../../../rbac/api', () => ({
104
104
  isPermitted: vi.fn().mockImplementation((input) => {
105
- console.log('[PaceAppLayout] Page access attempt:', {
106
- pageName: input.pageId || 'unknown',
107
- operation: input.permission,
108
- userId: input.userId,
109
- allowed: true,
110
- strictMode: true,
111
- timestamp: new Date().toISOString()
112
- });
113
105
  return Promise.resolve(true);
114
106
  }),
115
107
  getPermissionMap: vi.fn().mockResolvedValue({}),
@@ -288,14 +280,6 @@ describe('PaceAppLayout Integration', () => {
288
280
 
289
281
  // Reset mockIsPermitted to default implementation
290
282
  mockIsPermitted.mockImplementation((input) => {
291
- console.log('[PaceAppLayout] Page access attempt:', {
292
- pageName: input.pageId || 'unknown',
293
- operation: input.permission,
294
- userId: input.userId,
295
- allowed: true,
296
- strictMode: true,
297
- timestamp: new Date().toISOString()
298
- });
299
283
  return Promise.resolve(true);
300
284
  });
301
285
 
@@ -655,7 +655,6 @@ describe('PaceAppLayout Security', () => {
655
655
  // Simulate a component that might try to execute malicious code
656
656
  React.useEffect(() => {
657
657
  // This would be dangerous in a real scenario
658
- console.log('Component mounted');
659
658
  }, []);
660
659
 
661
660
  return <div data-testid="malicious-component">Malicious Component</div>;
@@ -99,14 +99,6 @@ vi.mock('../../../hooks/useEventTheme', () => ({
99
99
 
100
100
  // Mock the new RBAC system
101
101
  const mockIsPermitted = vi.fn().mockImplementation((input) => {
102
- console.log('[PaceAppLayout] Page access attempt:', {
103
- pageName: input.pageId || 'unknown',
104
- operation: input.permission,
105
- userId: input.userId,
106
- allowed: true,
107
- strictMode: true,
108
- timestamp: new Date().toISOString()
109
- });
110
102
  return Promise.resolve(true);
111
103
  });
112
104
 
@@ -902,7 +894,6 @@ describe('PaceAppLayout Component', () => {
902
894
  it('filters navigation when filterNavigationByPermissions is true', async () => {
903
895
  // Mock checkPermission to return false for some items
904
896
  mockIsPermitted.mockImplementation((input) => {
905
- console.log('[TEST] mockIsPermitted called with:', input);
906
897
  if (input.pageId === 'dashboard') return Promise.resolve(false);
907
898
  return Promise.resolve(true);
908
899
  });
@@ -9,6 +9,7 @@ import userEvent from '@testing-library/user-event';
9
9
  import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
10
10
  import { PaceLoginPage } from './PaceLoginPage';
11
11
  import { renderWithProviders } from '../../__tests__/helpers/test-utils';
12
+ import { Logger, LogLevel } from '../../utils/core/logger';
12
13
 
13
14
  // Mock React Router
14
15
  const mockNavigate = vi.fn();
@@ -83,9 +84,29 @@ import { isSuperAdmin } from '../../rbac/api';
83
84
  const originalConsoleError = console.error;
84
85
 
85
86
  describe('PaceLoginPage Component', () => {
86
- afterEach(() => {
87
+ let originalMode: string | undefined;
88
+
89
+ beforeEach(() => {
90
+ // Ensure logger is enabled by setting MODE to development
91
+ originalMode = import.meta.env.MODE;
92
+ (import.meta.env as any).MODE = 'development';
93
+
94
+ // Configure logger to ensure it logs in test environment
95
+ Logger.configure({
96
+ level: LogLevel.DEBUG,
97
+ includeTimestamp: false,
98
+ includeComponent: true,
99
+ });
100
+ });
101
+
102
+ afterEach(() => {
87
103
  // Restore console methods
88
104
  console.error = originalConsoleError;
105
+
106
+ // Restore original mode
107
+ if (originalMode !== undefined) {
108
+ (import.meta.env as any).MODE = originalMode;
109
+ }
89
110
  });
90
111
 
91
112
  // Basic rendering tests
@@ -330,7 +351,11 @@ describe('PaceLoginPage Component', () => {
330
351
  await user.click(submitButton);
331
352
 
332
353
  await waitFor(() => {
333
- expect(console.error).toHaveBeenCalledWith('Navigation error after sign-in:', expect.any(Error));
354
+ // Logger.error formats the message with component name and log level
355
+ expect(console.error).toHaveBeenCalledWith(
356
+ expect.stringContaining('[PaceLoginPage] Navigation error after sign-in:'),
357
+ expect.any(Error)
358
+ );
334
359
  });
335
360
  });
336
361
 
@@ -387,6 +412,9 @@ describe('PaceLoginPage Component', () => {
387
412
  const user = userEvent.setup();
388
413
  mockAuthContext.signIn.mockRejectedValue(new Error('Network error'));
389
414
 
415
+ // Mock console.error to catch the error
416
+ console.error = vi.fn();
417
+
390
418
  renderWithProviders(<PaceLoginPage appName="Test App" />);
391
419
 
392
420
  const emailInput = screen.getByLabelText('Email');
@@ -398,7 +426,11 @@ describe('PaceLoginPage Component', () => {
398
426
  await user.click(submitButton);
399
427
 
400
428
  await waitFor(() => {
401
- expect(console.error).toHaveBeenCalledWith('Login error:', expect.any(Error));
429
+ // Logger.error formats the message with component name and log level
430
+ expect(console.error).toHaveBeenCalledWith(
431
+ expect.stringContaining('[PaceLoginPage] Login error:'),
432
+ expect.any(Error)
433
+ );
402
434
  });
403
435
  });
404
436
  });
@@ -129,6 +129,7 @@ import { LoginForm } from '../LoginForm';
129
129
  import { Button, Input, Label } from '..';
130
130
  import { clearPalette } from '../../theming/runtime';
131
131
  import { EventServiceContext } from '../../providers/services/EventServiceProvider';
132
+ import { logger } from '../../utils/core/logger';
132
133
 
133
134
  export interface PaceLoginPageProps {
134
135
  /** The name of the application to be displayed on the login form. */
@@ -207,7 +208,7 @@ export const PaceLoginPage: React.FC<PaceLoginPageProps> = ({
207
208
  }
208
209
  } catch (error) {
209
210
  // Service may not be available yet or events not loaded - that's okay
210
- console.debug('[PaceLoginPage] Could not restore persisted event (service may not be ready):', error);
211
+ logger.debug('PaceLoginPage', 'Could not restore persisted event (service may not be ready):', error);
211
212
  }
212
213
  };
213
214
 
@@ -231,13 +232,13 @@ export const PaceLoginPage: React.FC<PaceLoginPageProps> = ({
231
232
 
232
233
  try {
233
234
  const userId = user.id;
234
- console.log('[PaceLoginPage] Checking app access using RBAC:', { appName, userId });
235
+ logger.debug('PaceLoginPage', 'Checking app access using RBAC:', { appName, userId });
235
236
 
236
237
  // Step 1: Check if user is super admin (they have unrestricted access)
237
238
  const superAdminCheck = await isSuperAdmin(userId);
238
239
 
239
240
  if (superAdminCheck) {
240
- console.log('[PaceLoginPage] User is super admin, granting access');
241
+ logger.debug('PaceLoginPage', 'User is super admin, granting access');
241
242
  setIsCheckingAccess(false);
242
243
  navigate(onSuccessRedirectPath, { replace: true });
243
244
  return;
@@ -252,7 +253,7 @@ export const PaceLoginPage: React.FC<PaceLoginPageProps> = ({
252
253
  .single();
253
254
 
254
255
  if (appError || !appData) {
255
- console.error('[PaceLoginPage] App not found:', appName, appError);
256
+ logger.error('PaceLoginPage', 'App not found:', { appName, error: appError });
256
257
  setAccessError(`Application "${appName}" is not configured. Please contact your administrator.`);
257
258
  setIsCheckingAccess(false);
258
259
  return;
@@ -265,7 +266,7 @@ export const PaceLoginPage: React.FC<PaceLoginPageProps> = ({
265
266
  .eq('app_id', appData.id);
266
267
 
267
268
  if (pagesError || !pagesData || pagesData.length === 0) {
268
- console.log('[PaceLoginPage] No pages configured for app:', appName);
269
+ logger.debug('PaceLoginPage', 'No pages configured for app:', appName);
269
270
  setAccessError(`You do not have permission to access ${appName}. This application is currently unavailable. Please contact your administrator if you believe you should have access.`);
270
271
  setIsCheckingAccess(false);
271
272
  return;
@@ -282,7 +283,7 @@ export const PaceLoginPage: React.FC<PaceLoginPageProps> = ({
282
283
  .single();
283
284
 
284
285
  if (!orgData) {
285
- console.log('[PaceLoginPage] User has no organisation access');
286
+ logger.debug('PaceLoginPage', 'User has no organisation access');
286
287
  setAccessError(`You do not have permission to access ${appName}. You are not assigned to any organisation. Please contact your administrator.`);
287
288
  setIsCheckingAccess(false);
288
289
  return;
@@ -302,7 +303,7 @@ export const PaceLoginPage: React.FC<PaceLoginPageProps> = ({
302
303
  p_page_id: page.page_name // Page name to resolve to UUID
303
304
  });
304
305
 
305
- console.log('[PaceLoginPage] Permission check for page:', page.page_name, { hasPermission, error: permError });
306
+ logger.debug('PaceLoginPage', 'Permission check for page:', { pageName: page.page_name, hasPermission, error: permError });
306
307
 
307
308
  if (!permError && hasPermission === true) {
308
309
  hasAnyAccess = true;
@@ -311,18 +312,18 @@ export const PaceLoginPage: React.FC<PaceLoginPageProps> = ({
311
312
  }
312
313
 
313
314
  if (hasAnyAccess) {
314
- console.log('[PaceLoginPage] User has access to app');
315
+ logger.debug('PaceLoginPage', 'User has access to app');
315
316
  setIsCheckingAccess(false);
316
317
  navigate(onSuccessRedirectPath, { replace: true });
317
318
  return;
318
319
  }
319
320
 
320
321
  // No access - deny
321
- console.log('[PaceLoginPage] Access denied - no permissions');
322
+ logger.debug('PaceLoginPage', 'Access denied - no permissions');
322
323
  setAccessError(`You do not have permission to access ${appName}. This application is restricted to authorized users only. Please contact your administrator if you believe you should have access.`);
323
324
  setIsCheckingAccess(false);
324
325
  } catch (error) {
325
- console.error('[PaceLoginPage] Error checking app access:', error);
326
+ logger.error('PaceLoginPage', 'Error checking app access:', error);
326
327
  setAccessError('An error occurred while checking your permissions. Please try again or contact support.');
327
328
  setIsCheckingAccess(false);
328
329
  }
@@ -349,7 +350,7 @@ export const PaceLoginPage: React.FC<PaceLoginPageProps> = ({
349
350
  try {
350
351
  navigate(onSuccessRedirectPath, { replace: true });
351
352
  } catch (navError) {
352
- console.error('Navigation error after sign-in:', navError);
353
+ logger.error('PaceLoginPage', 'Navigation error after sign-in:', navError);
353
354
  }
354
355
  }
355
356
  } finally {
@@ -371,7 +372,7 @@ export const PaceLoginPage: React.FC<PaceLoginPageProps> = ({
371
372
  isLoading={isSigningIn}
372
373
  onError={(error) => {
373
374
  // LoginForm will handle display of the error
374
- console.error('Login error:', error);
375
+ logger.error('PaceLoginPage', 'Login error:', error);
375
376
  }}
376
377
  />
377
378
  {(() => {
@@ -101,7 +101,7 @@ import React, { useState } from 'react';
101
101
  import { Button } from '../Button/Button';
102
102
  import { Input } from '../Input/Input';
103
103
  import { Label } from '../Label';
104
- import { cn } from '../../utils/cn';
104
+ import { cn } from '../../utils/core/cn';
105
105
 
106
106
  export interface PasswordChangeFormValues {
107
107
  newPassword: string;
@@ -1,4 +1,2 @@
1
- export { PasswordResetForm } from './PasswordResetForm';
2
- export type { PasswordResetFormProps } from './PasswordResetForm';
3
1
  export { PasswordChangeForm } from './PasswordChangeForm';
4
2
  export type { PasswordChangeFormProps, PasswordChangeFormValues } from './PasswordChangeForm';
@@ -62,7 +62,7 @@
62
62
 
63
63
  import * as React from 'react';
64
64
  import * as ProgressPrimitive from '@radix-ui/react-progress';
65
- import { cn } from '../../utils/cn';
65
+ import { cn } from '../../utils/core/cn';
66
66
 
67
67
  /**
68
68
  * Props for the Progress component
@@ -98,7 +98,21 @@ describe('ProtectedRoute Component', () => {
98
98
  isLoading: false,
99
99
  };
100
100
 
101
+ let originalMode: string | undefined;
102
+
101
103
  beforeEach(() => {
104
+ // Ensure logger is enabled by setting MODE to development
105
+ originalMode = import.meta.env.MODE;
106
+ (import.meta.env as any).MODE = 'development';
107
+
108
+ import('../../utils/core/logger').then(({ Logger, LogLevel }) => {
109
+ Logger.configure({
110
+ level: LogLevel.DEBUG,
111
+ includeTimestamp: false,
112
+ includeComponent: true,
113
+ });
114
+ });
115
+
102
116
  vi.clearAllMocks();
103
117
  console.debug = vi.fn();
104
118
  console.warn = vi.fn();
@@ -112,6 +126,11 @@ describe('ProtectedRoute Component', () => {
112
126
  afterEach(() => {
113
127
  console.debug = originalConsoleDebug;
114
128
  console.warn = originalConsoleWarn;
129
+
130
+ // Restore original mode
131
+ if (originalMode !== undefined) {
132
+ (import.meta.env as any).MODE = originalMode;
133
+ }
115
134
  });
116
135
 
117
136
  describe('Rendering', () => {
@@ -124,6 +143,8 @@ describe('ProtectedRoute Component', () => {
124
143
  });
125
144
 
126
145
  it('renders outlet when events exist but none selected (allows event selector visibility)', () => {
146
+ const consoleDebugSpy = vi.spyOn(console, 'debug').mockImplementation(() => {});
147
+
127
148
  mockUseEvents.mockReturnValue({
128
149
  selectedEvent: null,
129
150
  events: [{ id: 'event-1', name: 'Test Event' }],
@@ -133,8 +154,8 @@ describe('ProtectedRoute Component', () => {
133
154
  renderWithProviders(<ProtectedRoute />);
134
155
 
135
156
  expect(screen.getByTestId('outlet')).toBeInTheDocument();
136
- expect(console.debug).toHaveBeenCalledWith(
137
- '[ProtectedRoute] Events available but none selected - allowing render so selector is visible'
157
+ expect(consoleDebugSpy).toHaveBeenCalledWith(
158
+ expect.stringContaining('[DEBUG] [ProtectedRoute] Events available but none selected - allowing render so selector is visible')
138
159
  );
139
160
  });
140
161
 
@@ -222,6 +243,8 @@ describe('ProtectedRoute Component', () => {
222
243
  });
223
244
 
224
245
  it('warns when redirecting due to session restoration timeout', () => {
246
+ const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
247
+
225
248
  mockUseUnifiedAuth.mockReturnValue({
226
249
  isAuthenticated: false,
227
250
  authLoading: false,
@@ -236,8 +259,8 @@ describe('ProtectedRoute Component', () => {
236
259
 
237
260
  renderWithProviders(<ProtectedRoute />);
238
261
 
239
- expect(console.warn).toHaveBeenCalledWith(
240
- '[ProtectedRoute] Session restoration failed, redirecting to login',
262
+ expect(consoleWarnSpy).toHaveBeenCalledWith(
263
+ expect.stringContaining('[WARN] [ProtectedRoute] Session restoration failed, redirecting to login'),
241
264
  expect.objectContaining({
242
265
  timedOut: true,
243
266
  })
@@ -259,10 +282,12 @@ describe('ProtectedRoute Component', () => {
259
282
  hasTimedOut: false,
260
283
  });
261
284
 
285
+ const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
286
+
262
287
  renderWithProviders(<ProtectedRoute />);
263
288
 
264
- expect(console.warn).toHaveBeenCalledWith(
265
- '[ProtectedRoute] Session restoration failed, redirecting to login',
289
+ expect(consoleWarnSpy).toHaveBeenCalledWith(
290
+ expect.stringContaining('[WARN] [ProtectedRoute] Session restoration failed, redirecting to login'),
266
291
  expect.objectContaining({
267
292
  error: 'Session restoration failed',
268
293
  timedOut: false,
@@ -408,11 +433,13 @@ describe('ProtectedRoute Component', () => {
408
433
  isLoading: false,
409
434
  });
410
435
 
436
+ const consoleDebugSpy = vi.spyOn(console, 'debug').mockImplementation(() => {});
437
+
411
438
  renderWithProviders(<ProtectedRoute requireEvent={true} />);
412
439
 
413
440
  expect(screen.getByTestId('outlet')).toBeInTheDocument();
414
- expect(console.debug).toHaveBeenCalledWith(
415
- '[ProtectedRoute] Events available but none selected - allowing render so selector is visible'
441
+ expect(consoleDebugSpy).toHaveBeenCalledWith(
442
+ expect.stringContaining('[DEBUG] [ProtectedRoute] Events available but none selected - allowing render so selector is visible')
416
443
  );
417
444
  });
418
445
 
@@ -76,6 +76,7 @@ import { useEvents } from '../../hooks/useEvents';
76
76
  import { LoadingSpinner } from '../LoadingSpinner/LoadingSpinner';
77
77
  import { SessionRestorationLoader } from '../SessionRestorationLoader';
78
78
  import { Alert, AlertDescription, AlertTitle } from '../Alert/Alert';
79
+ import { logger } from '../../utils/core/logger';
79
80
 
80
81
  export interface ProtectedRouteProps {
81
82
  /**
@@ -175,7 +176,7 @@ export function ProtectedRoute({
175
176
  // Redirect to login if not authenticated
176
177
  if (!isAuthenticated) {
177
178
  if (sessionRestoration.hasTimedOut || sessionRestoration.restorationError) {
178
- console.warn('[ProtectedRoute] Session restoration failed, redirecting to login', {
179
+ logger.warn('ProtectedRoute', 'Session restoration failed, redirecting to login', {
179
180
  timedOut: sessionRestoration.hasTimedOut,
180
181
  error: sessionRestoration.restorationError?.message
181
182
  });
@@ -217,7 +218,7 @@ export function ProtectedRoute({
217
218
  // The event selector will be visible and user can select, or auto-selection will kick in
218
219
  if (!selectedEvent) {
219
220
  // Log for debugging - this is expected behavior, not an error
220
- console.debug('[ProtectedRoute] Events available but none selected - allowing render so selector is visible');
221
+ logger.debug('ProtectedRoute', 'Events available but none selected - allowing render so selector is visible');
221
222
  return <Outlet />;
222
223
  }
223
224
 
@@ -40,7 +40,7 @@
40
40
  */
41
41
 
42
42
  import React, { Component, ErrorInfo, ReactNode } from 'react';
43
- import { cn } from '../../utils/cn';
43
+ import { cn } from '../../utils/core/cn';
44
44
 
45
45
  export interface PublicErrorBoundaryProps {
46
46
  /** Child components to wrap */
@@ -37,7 +37,7 @@
37
37
  */
38
38
 
39
39
  import React from 'react';
40
- import { cn } from '../../utils/cn';
40
+ import { cn } from '../../utils/core/cn';
41
41
 
42
42
  export interface PublicLoadingSpinnerProps {
43
43
  /** Loading message to display */