@jmruthers/pace-core 0.6.9 → 0.6.11

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 (1182) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/audit-tool/00-dependencies.cjs +46 -13
  3. package/audit-tool/audits/01-pace-core-compliance.cjs +96 -21
  4. package/audit-tool/audits/02-project-structure.cjs +74 -2
  5. package/audit-tool/audits/03-architecture.cjs +220 -20
  6. package/audit-tool/audits/04-code-quality.cjs +95 -3
  7. package/audit-tool/audits/05-styling.cjs +19 -7
  8. package/audit-tool/audits/06-security-rbac.cjs +214 -25
  9. package/audit-tool/audits/07-api-tech-stack.cjs +31 -15
  10. package/audit-tool/audits/08-testing-documentation.cjs +11 -3
  11. package/audit-tool/audits/09-operations.cjs +19 -7
  12. package/audit-tool/index.cjs +22 -11
  13. package/audit-tool/utils/report-utils.cjs +4 -0
  14. package/cursor-rules/01-pace-core-compliance.mdc +1 -0
  15. package/cursor-rules/02-project-structure.mdc +3 -26
  16. package/cursor-rules/03-architecture.mdc +3 -1
  17. package/cursor-rules/04-code-quality.mdc +1 -0
  18. package/cursor-rules/05-styling.mdc +120 -8
  19. package/cursor-rules/06-security-rbac.mdc +126 -2
  20. package/cursor-rules/07-api-tech-stack.mdc +1 -0
  21. package/cursor-rules/08-testing-documentation.mdc +1 -0
  22. package/cursor-rules/09-operations.mdc +1 -0
  23. package/dist/DataTable-EFYP2QLE.js +16 -0
  24. package/dist/InactivityServiceProvider-BbxwwDz1.d.ts +308 -0
  25. package/dist/UnifiedAuthProvider-Bkt_tzdS.d.ts +183 -0
  26. package/dist/api-BZR2CYXL.js +5 -0
  27. package/dist/api-result-USV1Czr-.d.ts +51 -0
  28. package/dist/assets/app-icons/admin_favicon.svg +462 -0
  29. package/dist/assets/app-icons/base_favicon.svg +85 -0
  30. package/dist/assets/app-icons/cake_favicon.svg +68 -0
  31. package/dist/assets/app-icons/core_favicon.svg +256 -0
  32. package/dist/assets/app-icons/gear_favicon.svg +91 -0
  33. package/dist/assets/app-icons/medi_favicon.svg +92 -0
  34. package/dist/assets/app-icons/mint_favicon.svg +83 -0
  35. package/dist/assets/app-icons/pace_favicon.svg +49 -0
  36. package/dist/assets/app-icons/pump_favicon.svg +68 -0
  37. package/dist/assets/app-icons/seed_favicon.svg +91 -0
  38. package/dist/assets/app-icons/team_favicon.svg +67 -0
  39. package/dist/assets/app-icons/trac_favicon.svg +112 -0
  40. package/dist/assets/app-icons/trip_favicon.svg +102 -0
  41. package/dist/audit-HI2DHUVU.js +4 -0
  42. package/dist/auth-JvdRVaud.d.ts +49 -0
  43. package/dist/chunk-2DL2WSOE.js +327 -0
  44. package/dist/chunk-2OEVOGGR.js +9598 -0
  45. package/dist/chunk-44CNXN4P.js +15 -0
  46. package/dist/chunk-4R3T5ENU.js +2943 -0
  47. package/dist/chunk-7A6IMHH2.js +2321 -0
  48. package/dist/chunk-BTHN5MKC.js +121 -0
  49. package/dist/chunk-CU2BU2MQ.js +2 -0
  50. package/dist/chunk-D6BMFMQZ.js +200 -0
  51. package/dist/chunk-DDMPHZ3D.js +58 -0
  52. package/dist/chunk-ENLXB7GP.js +721 -0
  53. package/dist/chunk-J2KQK6DG.js +2159 -0
  54. package/dist/chunk-KJXRL3XE.js +6434 -0
  55. package/dist/chunk-L5LFKKLJ.js +61 -0
  56. package/dist/chunk-PCSHBLPB.js +811 -0
  57. package/dist/chunk-QRYSEPHB.js +429 -0
  58. package/dist/chunk-RMLY6KB5.js +187 -0
  59. package/dist/chunk-SACF5YSM.js +31 -0
  60. package/dist/chunk-UZNAFKGW.js +125 -0
  61. package/dist/chunk-V7FTM2LU.js +1080 -0
  62. package/dist/chunk-WY6Y7KC3.js +264 -0
  63. package/dist/chunk-XOJME5T7.js +407 -0
  64. package/dist/chunk-XPFVT3GN.js +492 -0
  65. package/dist/chunk-YFTFFJIV.js +529 -0
  66. package/dist/chunk-YYTWKVHO.js +1334 -0
  67. package/dist/components.d.ts +12 -89
  68. package/dist/components.js +23 -55
  69. package/dist/database.generated-qkdoiVrJ.d.ts +9441 -0
  70. package/dist/eslint-rules/index.cjs +3 -0
  71. package/dist/eslint-rules/rules/03-architecture.cjs +74 -0
  72. package/dist/eslint-rules/rules/05-styling.cjs +507 -0
  73. package/dist/eslint-rules/rules/06-security-rbac.cjs +84 -0
  74. package/dist/event-BfCox3N2.d.ts +265 -0
  75. package/dist/file-reference-DU1hcawx.d.ts +164 -0
  76. package/dist/functions-DH45k8ec.d.ts +208 -0
  77. package/dist/hooks.d.ts +28 -14
  78. package/dist/hooks.js +90 -56
  79. package/dist/icons/index.d.ts +1 -0
  80. package/dist/icons/index.js +1 -0
  81. package/dist/index.d.ts +392 -155
  82. package/dist/index.js +337 -347
  83. package/dist/pagination-BW1mqywp.d.ts +201 -0
  84. package/dist/papaparseLoader-WG2UXQ22.js +7 -0
  85. package/dist/providers.d.ts +29 -14
  86. package/dist/providers.js +7 -5
  87. package/dist/rbac/eslint-rules.js +2 -2
  88. package/dist/rbac/index.d.ts +180 -351
  89. package/dist/rbac/index.js +13 -11
  90. package/dist/theming/runtime.d.ts +28 -5
  91. package/dist/theming/runtime.js +2 -2
  92. package/dist/timezone-BTWWXKVY.d.ts +696 -0
  93. package/dist/types-BE2sEHKd.d.ts +55 -0
  94. package/dist/types-CvOPXWWZ.d.ts +111 -0
  95. package/dist/types-Dr8sNhER.d.ts +50 -0
  96. package/dist/types.d.ts +20 -13
  97. package/dist/types.js +1 -0
  98. package/dist/usePublicPageContext-B91dGYW1.d.ts +4367 -0
  99. package/dist/usePublicRouteParams-BgV6VhMi.d.ts +946 -0
  100. package/dist/utils.d.ts +338 -156
  101. package/dist/utils.js +78 -60
  102. package/dist/validation-g5n0hDkh.d.ts +177 -0
  103. package/docs/api/modules.md +1226 -1094
  104. package/docs/api-reference/components.md +5 -5
  105. package/docs/api-reference/rpc-functions.md +12 -3
  106. package/docs/core-concepts/rbac-system.md +8 -0
  107. package/docs/getting-started/cursor-rules.md +17 -20
  108. package/docs/getting-started/dependencies.md +1 -1
  109. package/docs/getting-started/setup.md +235 -0
  110. package/docs/implementation-guides/authentication.md +27 -0
  111. package/docs/implementation-guides/data-tables.md +365 -10
  112. package/docs/migration/ApiResult-migration.md +25 -0
  113. package/docs/rbac/RBAC_CONTRACT.md +0 -12
  114. package/docs/rbac/api-reference.md +33 -31
  115. package/docs/standards/0-standards-overview.md +50 -15
  116. package/docs/standards/1-pace-core-compliance-standards.md +62 -57
  117. package/docs/standards/2-project-structure-standards.md +45 -90
  118. package/docs/standards/3-architecture-standards.md +41 -1
  119. package/docs/standards/4-code-quality-standards.md +26 -6
  120. package/docs/standards/5-styling-standards.md +35 -1
  121. package/docs/standards/6-security-rbac-standards.md +288 -7
  122. package/docs/standards/7-api-tech-stack-standards.md +116 -17
  123. package/docs/standards/8-testing-documentation-standards.md +31 -0
  124. package/docs/standards/9-operations-standards.md +19 -0
  125. package/docs/standards/README.md +20 -201
  126. package/docs/testing/README.md +10 -0
  127. package/docs/testing/test-setup-for-consumers.md +916 -0
  128. package/docs/troubleshooting/common-issues.md +17 -1
  129. package/docs/troubleshooting/organisation-context-setup.md +8 -0
  130. package/docs/troubleshooting/print-event-name-css-variable-analysis.md +217 -0
  131. package/eslint-config-pace-core.cjs +24 -0
  132. package/package.json +14 -20
  133. package/scripts/build-docs.js +180 -0
  134. package/scripts/setup.cjs +536 -0
  135. package/scripts/validate.cjs +480 -0
  136. package/src/__mocks__/lucide-react.ts +0 -2
  137. package/src/__tests__/helpers/component-test-utils.test.tsx +260 -0
  138. package/src/__tests__/helpers/optimized-test-setup.test.ts +224 -0
  139. package/src/__tests__/helpers/supabaseMock.test.ts +273 -0
  140. package/src/__tests__/helpers/test-providers.test.tsx +99 -0
  141. package/src/__tests__/helpers/test-providers.tsx +37 -39
  142. package/src/__tests__/helpers/test-utils.test.tsx +447 -0
  143. package/src/__tests__/helpers/timer-utils.test.ts +371 -0
  144. package/src/assets/app-icons/admin_favicon.svg +462 -0
  145. package/src/assets/app-icons/base_favicon.svg +85 -0
  146. package/src/assets/app-icons/cake_favicon.svg +68 -0
  147. package/src/assets/app-icons/core_favicon.svg +256 -0
  148. package/src/assets/app-icons/gear_favicon.svg +91 -0
  149. package/src/assets/app-icons/index.test.ts +304 -0
  150. package/src/assets/app-icons/index.ts +83 -0
  151. package/src/assets/app-icons/medi_favicon.svg +92 -0
  152. package/src/assets/app-icons/mint_favicon.svg +83 -0
  153. package/src/assets/app-icons/pace_favicon.svg +49 -0
  154. package/src/assets/app-icons/pump_favicon.svg +68 -0
  155. package/src/assets/app-icons/seed_favicon.svg +91 -0
  156. package/src/assets/app-icons/team_favicon.svg +67 -0
  157. package/src/assets/app-icons/trac_favicon.svg +112 -0
  158. package/src/assets/app-icons/trip_favicon.svg +102 -0
  159. package/src/components/AddressField/AddressField.test.tsx +379 -4
  160. package/src/components/AddressField/AddressField.tsx +239 -213
  161. package/src/components/AddressField/types.ts +2 -2
  162. package/src/components/Alert/Alert.test.tsx +35 -25
  163. package/src/components/Alert/Alert.tsx +8 -8
  164. package/src/components/AppSwitcher/AppSwitcher.test.tsx +1250 -0
  165. package/src/components/AppSwitcher/AppSwitcher.tsx +315 -0
  166. package/src/components/Avatar/Avatar.test.tsx +11 -1
  167. package/src/components/Avatar/Avatar.tsx +3 -2
  168. package/src/components/Badge/Badge.test.tsx +11 -1
  169. package/src/components/Button/Button.test.tsx +13 -3
  170. package/src/components/Button/Button.tsx +1 -1
  171. package/src/components/Calendar/Calendar.test.tsx +523 -131
  172. package/src/components/Calendar/Calendar.tsx +107 -488
  173. package/src/components/Card/Card.test.tsx +384 -258
  174. package/src/components/Card/Card.tsx +19 -10
  175. package/src/components/Checkbox/Checkbox.test.tsx +58 -174
  176. package/src/components/ContextSelector/ContextSelector.internals.tsx +204 -0
  177. package/src/components/ContextSelector/ContextSelector.test.tsx +360 -0
  178. package/src/components/ContextSelector/ContextSelector.tsx +66 -280
  179. package/src/components/ContextSelector/ContextSelector.types.ts +35 -0
  180. package/src/components/ContextSelector/useContextSelectorState.tsx +195 -0
  181. package/src/components/DataTable/AUDIT_REPORT.md +59 -44
  182. package/src/components/DataTable/DataTable.comprehensive.test.tsx +759 -0
  183. package/src/components/DataTable/DataTable.default-state.test.tsx +524 -0
  184. package/src/components/DataTable/DataTable.export.test.tsx +705 -0
  185. package/src/components/DataTable/DataTable.grouping-aggregation.test.tsx +658 -0
  186. package/src/components/DataTable/DataTable.hooks.test.tsx +192 -0
  187. package/src/components/DataTable/DataTable.select-label-display.test.tsx +485 -0
  188. package/src/components/DataTable/DataTable.test.tsx +787 -416
  189. package/src/components/DataTable/DataTable.tsx +14 -14
  190. package/src/components/DataTable/DataTableCore.integration.test.tsx +458 -0
  191. package/src/components/DataTable/DataTableCore.test-setup.ts +221 -0
  192. package/src/components/DataTable/DataTableCore.test.tsx +970 -0
  193. package/src/components/DataTable/README.md +155 -0
  194. package/src/components/DataTable/TESTING.md +101 -0
  195. package/src/components/DataTable/a11y.basic.test.tsx +788 -0
  196. package/src/components/DataTable/components/DataTableCore.tsx +126 -894
  197. package/src/components/DataTable/components/GroupingDropdown.test.tsx +621 -0
  198. package/src/components/DataTable/components/GroupingDropdown.tsx +2 -3
  199. package/src/components/DataTable/components/ImportModal.tsx +82 -408
  200. package/src/components/DataTable/components/ImportModalFileSection.tsx +148 -0
  201. package/src/components/DataTable/context/DataTableContext.test.tsx +328 -0
  202. package/src/components/DataTable/context/DataTableContext.tsx +13 -13
  203. package/src/components/DataTable/core/ColumnFactory.test.ts +403 -0
  204. package/src/components/DataTable/core/ColumnFactory.ts +3 -3
  205. package/src/components/DataTable/hooks/useColumnOrderPersistence.test.ts +516 -0
  206. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +12 -9
  207. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.test.ts +256 -0
  208. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +12 -9
  209. package/src/components/DataTable/hooks/useDataTableConfiguration.test.ts +297 -0
  210. package/src/components/DataTable/hooks/useDataTableConfiguration.ts +15 -3
  211. package/src/components/DataTable/hooks/useDataTableDataPipeline.test.ts +270 -0
  212. package/src/components/DataTable/hooks/useDataTableDeletionBatching.test.ts +127 -0
  213. package/src/components/DataTable/hooks/useDataTableDeletionBatching.ts +106 -0
  214. package/src/components/DataTable/hooks/useDataTableEffectiveActions.test.ts +461 -0
  215. package/src/components/DataTable/hooks/useDataTableEffectiveActions.ts +238 -0
  216. package/src/components/DataTable/hooks/useDataTableLayoutHandlers.test.ts +296 -0
  217. package/src/components/DataTable/hooks/useDataTableLayoutHandlers.ts +175 -0
  218. package/src/components/DataTable/hooks/useDataTablePaginationSync.test.ts +203 -0
  219. package/src/components/DataTable/hooks/useDataTablePaginationSync.ts +109 -0
  220. package/src/components/DataTable/hooks/useDataTablePermissions.test.ts +280 -0
  221. package/src/components/DataTable/hooks/useDataTablePermissions.ts +81 -260
  222. package/src/components/DataTable/hooks/useDataTablePipeline.test.tsx +219 -0
  223. package/src/components/DataTable/hooks/useDataTablePipeline.tsx +239 -0
  224. package/src/components/DataTable/hooks/useDataTableRenderGuard.test.tsx +316 -0
  225. package/src/components/DataTable/hooks/useDataTableRenderGuard.tsx +195 -0
  226. package/src/components/DataTable/hooks/useDataTableScope.test.ts +110 -0
  227. package/src/components/DataTable/hooks/useDataTableScope.ts +123 -0
  228. package/src/components/DataTable/hooks/useDataTableState.test.ts +733 -0
  229. package/src/components/DataTable/hooks/useDataTableState.ts +161 -114
  230. package/src/components/DataTable/hooks/useDataTableStateAndPersistence.test.ts +277 -0
  231. package/src/components/DataTable/hooks/useDataTableStateAndPersistence.ts +222 -0
  232. package/src/components/DataTable/hooks/useDataTableSuperAdmin.test.ts +93 -0
  233. package/src/components/DataTable/hooks/useDataTableSuperAdmin.ts +86 -0
  234. package/src/components/DataTable/hooks/useDataTableTableInstance.test.ts +185 -0
  235. package/src/components/DataTable/hooks/useDataTableTableInstance.ts +178 -0
  236. package/src/components/DataTable/hooks/useEffectiveColumnOrder.test.ts +183 -0
  237. package/src/components/DataTable/hooks/useHierarchicalState.test.ts +294 -0
  238. package/src/components/DataTable/hooks/useImportModalFocus.test.ts +184 -0
  239. package/src/components/DataTable/hooks/useImportModalFocus.ts +53 -0
  240. package/src/components/DataTable/hooks/useImportModalState.test.ts +390 -0
  241. package/src/components/DataTable/hooks/useImportModalState.ts +345 -0
  242. package/src/components/DataTable/hooks/useKeyboardNavigation.test.ts +787 -0
  243. package/src/components/DataTable/hooks/useKeyboardNavigation.ts +311 -271
  244. package/src/components/DataTable/hooks/usePermissionTracking.test.ts +381 -0
  245. package/src/components/DataTable/hooks/usePermissionTracking.ts +122 -0
  246. package/src/components/DataTable/hooks/useServerSideDataEffect.test.ts +258 -0
  247. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +27 -4
  248. package/src/components/DataTable/hooks/useTableColumns.test.ts +499 -0
  249. package/src/components/DataTable/hooks/useTableColumns.ts +15 -39
  250. package/src/components/DataTable/hooks/useTableHandlers.test.ts +461 -0
  251. package/src/components/DataTable/hooks/useTableHandlers.ts +13 -22
  252. package/src/components/DataTable/index.ts +28 -5
  253. package/src/components/DataTable/keyboard.test.tsx +734 -0
  254. package/src/components/DataTable/mocks/MockRBACProvider.tsx +66 -0
  255. package/src/components/DataTable/pagination.modes.test.tsx +728 -0
  256. package/src/components/DataTable/ssr.strict-mode.test.tsx +319 -0
  257. package/src/components/DataTable/styles.test.ts +379 -0
  258. package/src/components/DataTable/styles.ts +0 -1
  259. package/src/components/DataTable/test-utils/MockDataTableComponents.tsx +55 -0
  260. package/src/components/DataTable/test-utils/dataFactories.ts +103 -0
  261. package/src/components/DataTable/test-utils/featureConfig.ts +10 -0
  262. package/src/components/DataTable/test-utils/sharedTestUtils.ts +419 -0
  263. package/src/components/DataTable/test-utils.ts +94 -0
  264. package/src/components/DataTable/types/actions.ts +71 -0
  265. package/src/components/DataTable/types/base.ts +39 -0
  266. package/src/components/DataTable/types/columns.ts +125 -0
  267. package/src/components/DataTable/types/export.ts +32 -0
  268. package/src/components/DataTable/types/features.ts +81 -0
  269. package/src/components/DataTable/types/hierarchical.ts +44 -0
  270. package/src/components/DataTable/types/index.ts +43 -0
  271. package/src/components/DataTable/types/pagination.ts +85 -0
  272. package/src/components/DataTable/types/performance.ts +47 -0
  273. package/src/components/DataTable/types/props.ts +62 -0
  274. package/src/components/DataTable/types/rbac.ts +45 -0
  275. package/src/components/DataTable/ui/layout/DataTableCore.test.tsx +1194 -0
  276. package/src/components/DataTable/ui/layout/DataTableCore.tsx +345 -0
  277. package/src/components/DataTable/ui/layout/DataTableErrorBoundary.test.tsx +438 -0
  278. package/src/components/DataTable/ui/layout/DataTableErrorBoundary.tsx +225 -0
  279. package/src/components/DataTable/ui/layout/DataTableLayout.test.tsx +1352 -0
  280. package/src/components/DataTable/ui/layout/DataTableLayout.tsx +661 -0
  281. package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.test.tsx +91 -0
  282. package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.tsx +43 -0
  283. package/src/components/DataTable/ui/modals/DataTableModals.test.tsx +749 -0
  284. package/src/components/DataTable/ui/modals/DataTableModals.tsx +341 -0
  285. package/src/components/DataTable/ui/modals/ImportModal.test.tsx +1834 -0
  286. package/src/components/DataTable/ui/modals/ImportModal.tsx +197 -0
  287. package/src/components/DataTable/ui/modals/ImportModalFailedRowsSection.tsx +60 -0
  288. package/src/components/DataTable/ui/modals/ImportModalFileSection.tsx +148 -0
  289. package/src/components/DataTable/ui/modals/ImportModalPreviewSection.tsx +60 -0
  290. package/src/components/DataTable/ui/modals/ImportModalSummarySection.tsx +59 -0
  291. package/src/components/DataTable/ui/modals/importModalPersistence.ts +73 -0
  292. package/src/components/DataTable/ui/shared/AccessDeniedPage.test.tsx +245 -0
  293. package/src/components/DataTable/ui/shared/AccessDeniedPage.tsx +159 -0
  294. package/src/components/DataTable/ui/shared/ActionButtons.test.tsx +921 -0
  295. package/src/components/DataTable/ui/shared/ActionButtons.tsx +195 -0
  296. package/src/components/DataTable/ui/shared/ColumnFilter.test.tsx +497 -0
  297. package/src/components/DataTable/ui/shared/ColumnFilter.tsx +113 -0
  298. package/src/components/DataTable/ui/shared/PaginationControls.test.tsx +451 -0
  299. package/src/components/DataTable/ui/shared/PaginationControls.tsx +291 -0
  300. package/src/components/DataTable/ui/shared/SortIndicator.test.tsx +135 -0
  301. package/src/components/DataTable/ui/shared/SortIndicator.tsx +50 -0
  302. package/src/components/DataTable/ui/table/EditFields.test.tsx +526 -0
  303. package/src/components/DataTable/ui/table/EditFields.tsx +355 -0
  304. package/src/components/DataTable/ui/table/EditableRow.test.tsx +1003 -0
  305. package/src/components/DataTable/ui/table/EditableRow.tsx +444 -0
  306. package/src/components/DataTable/ui/table/EmptyState.test.tsx +360 -0
  307. package/src/components/DataTable/ui/table/EmptyState.tsx +74 -0
  308. package/src/components/DataTable/ui/table/FilterRow.test.tsx +416 -0
  309. package/src/components/DataTable/ui/table/FilterRow.tsx +148 -0
  310. package/src/components/DataTable/ui/table/LoadingState.test.tsx +77 -0
  311. package/src/components/DataTable/ui/table/LoadingState.tsx +17 -0
  312. package/src/components/DataTable/ui/table/RowComponent.test.tsx +1024 -0
  313. package/src/components/DataTable/ui/table/RowComponent.tsx +429 -0
  314. package/src/components/DataTable/ui/table/UnifiedTableBody.test.tsx +1273 -0
  315. package/src/components/DataTable/ui/table/UnifiedTableBody.tsx +440 -0
  316. package/src/components/DataTable/ui/table/cellValueUtils.test.ts +453 -0
  317. package/src/components/DataTable/ui/table/cellValueUtils.ts +40 -0
  318. package/src/components/DataTable/ui/toolbar/BulkOperationsDropdown.test.tsx +551 -0
  319. package/src/components/DataTable/ui/toolbar/BulkOperationsDropdown.tsx +160 -0
  320. package/src/components/DataTable/ui/toolbar/ColumnVisibilityDropdown.test.tsx +751 -0
  321. package/src/components/DataTable/ui/toolbar/ColumnVisibilityDropdown.tsx +114 -0
  322. package/src/components/DataTable/ui/toolbar/DataTableToolbar.test.tsx +629 -0
  323. package/src/components/DataTable/ui/toolbar/DataTableToolbar.tsx +271 -0
  324. package/src/components/DataTable/ui/toolbar/GroupingDropdown.test.tsx +621 -0
  325. package/src/components/DataTable/ui/toolbar/GroupingDropdown.tsx +107 -0
  326. package/src/components/DataTable/utils/a11yUtils.test.ts +548 -0
  327. package/src/components/DataTable/utils/a11yUtils.ts +1 -1
  328. package/src/components/DataTable/utils/aggregationUtils.test.ts +288 -0
  329. package/src/components/DataTable/utils/aggregationUtils.ts +5 -5
  330. package/src/components/DataTable/utils/columnUtils.test.ts +94 -0
  331. package/src/components/DataTable/utils/csvParse.test.ts +74 -0
  332. package/src/components/DataTable/utils/csvParse.ts +65 -0
  333. package/src/components/DataTable/utils/errorHandling.test.ts +209 -0
  334. package/src/components/DataTable/utils/errorHandling.ts +3 -1
  335. package/src/components/DataTable/utils/exportUtils.test.ts +954 -0
  336. package/src/components/DataTable/utils/exportUtils.ts +1 -1
  337. package/src/components/DataTable/utils/flexibleImport.test.ts +573 -0
  338. package/src/components/DataTable/utils/flexibleImport.ts +3 -186
  339. package/src/components/DataTable/utils/hierarchicalSorting.test.ts +235 -0
  340. package/src/components/DataTable/utils/hierarchicalSorting.ts +3 -3
  341. package/src/components/DataTable/utils/hierarchicalUtils.test.ts +586 -0
  342. package/src/components/DataTable/utils/importDateParser.test.ts +162 -0
  343. package/src/components/DataTable/utils/importDateParser.ts +114 -0
  344. package/src/components/DataTable/utils/importValueParser.test.ts +138 -0
  345. package/src/components/DataTable/utils/importValueParser.ts +91 -0
  346. package/src/components/DataTable/utils/paginationUtils.test.ts +593 -0
  347. package/src/components/DataTable/utils/paginationUtils.ts +7 -4
  348. package/src/components/DataTable/utils/performanceUtils.test.ts +470 -0
  349. package/src/components/DataTable/utils/performanceUtils.ts +1 -1
  350. package/src/components/DataTable/utils/rowUtils.test.ts +235 -0
  351. package/src/components/DataTable/utils/selectFieldUtils.test.ts +271 -0
  352. package/src/components/DataTable/utils/selectFieldUtils.ts +97 -67
  353. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +18 -25
  354. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +1 -1
  355. package/src/components/DateTimeField/DateTimeField.test.tsx +3 -16
  356. package/src/components/DateTimeField/DateTimeField.tsx +1 -1
  357. package/src/components/Dialog/Dialog.test-utils.ts +49 -0
  358. package/src/components/Dialog/Dialog.test.tsx +2865 -458
  359. package/src/components/Dialog/Dialog.tsx +183 -986
  360. package/src/components/Dialog/dialogLock.test.ts +238 -0
  361. package/src/components/Dialog/dialogLock.ts +98 -0
  362. package/src/components/Dialog/index.ts +2 -0
  363. package/src/components/Dialog/useDialogDimensions.test.ts +163 -0
  364. package/src/components/Dialog/useDialogDimensions.ts +140 -0
  365. package/src/components/Dialog/useDialogLifecycle.test.ts +358 -0
  366. package/src/components/Dialog/useDialogLifecycle.ts +135 -0
  367. package/src/components/Dialog/useDialogPersistence.test.ts +381 -0
  368. package/src/components/Dialog/useDialogPersistence.ts +357 -0
  369. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +2 -62
  370. package/src/components/ErrorBoundary/ErrorBoundaryContext.context.ts +17 -0
  371. package/src/components/ErrorBoundary/ErrorBoundaryContext.tsx +2 -45
  372. package/src/components/ErrorBoundary/ErrorBoundaryContext.types.ts +41 -0
  373. package/src/components/ErrorBoundary/index.ts +3 -4
  374. package/src/components/ErrorBoundary/useErrorBoundaryContext.ts +20 -0
  375. package/src/components/FileDisplay/FileDisplay.test.tsx +479 -247
  376. package/src/components/FileDisplay/FileDisplay.tsx +29 -659
  377. package/src/components/FileDisplay/FileDisplayContent.test.tsx +395 -0
  378. package/src/components/FileDisplay/FileDisplayContent.tsx +242 -0
  379. package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.test.tsx +74 -0
  380. package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.tsx +38 -0
  381. package/src/components/FileDisplay/FileDisplayEmptyView.test.tsx +33 -0
  382. package/src/components/FileDisplay/FileDisplayEmptyView.tsx +33 -0
  383. package/src/components/FileDisplay/FileDisplayErrorView.test.tsx +71 -0
  384. package/src/components/FileDisplay/FileDisplayErrorView.tsx +50 -0
  385. package/src/components/FileDisplay/FileDisplayLoadingFallbackView.test.tsx +22 -0
  386. package/src/components/FileDisplay/FileDisplayLoadingFallbackView.tsx +22 -0
  387. package/src/components/FileDisplay/FileDisplayLoadingView.test.tsx +21 -0
  388. package/src/components/FileDisplay/FileDisplayLoadingView.tsx +23 -0
  389. package/src/components/FileDisplay/FileDisplayMultipleFilesView.test.tsx +101 -0
  390. package/src/components/FileDisplay/FileDisplayMultipleFilesView.tsx +109 -0
  391. package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.test.tsx +58 -0
  392. package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.tsx +48 -0
  393. package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.test.tsx +111 -0
  394. package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.tsx +270 -0
  395. package/src/components/FileDisplay/FileDisplaySingleImageView.test.tsx +78 -0
  396. package/src/components/FileDisplay/FileDisplaySingleImageView.tsx +67 -0
  397. package/src/components/FileDisplay/fallbackUtils.test.ts +50 -0
  398. package/src/components/FileDisplay/fallbackUtils.ts +44 -0
  399. package/src/components/FileDisplay/fetchFileDisplayData.ts +24 -0
  400. package/src/components/FileDisplay/fetchFileDisplayData.unit.test.ts +183 -0
  401. package/src/components/FileDisplay/fileDisplayUtils.test.ts +58 -0
  402. package/src/components/FileDisplay/fileDisplayUtils.ts +24 -0
  403. package/src/components/FileDisplay/index.tsx +1 -1
  404. package/src/components/FileDisplay/useFileDisplay.test.ts +538 -0
  405. package/src/components/FileDisplay/useFileDisplay.ts +515 -0
  406. package/src/components/FileDisplay/useFileDisplay.unit.test.ts +1438 -0
  407. package/src/components/FileDisplay/useFileDisplayData.ts +126 -0
  408. package/src/components/FileDisplay/usePublicFileDisplay.test.ts +729 -0
  409. package/src/components/FileDisplay/usePublicFileDisplay.ts +579 -0
  410. package/src/components/FileUpload/FileUpload.test.tsx +69 -27
  411. package/src/components/FileUpload/FileUpload.tsx +112 -527
  412. package/src/components/FileUpload/FileUploadDropZone.tsx +112 -0
  413. package/src/components/FileUpload/FileUploadProgressItem.tsx +86 -0
  414. package/src/components/FileUpload/FileUploadProgressList.tsx +40 -0
  415. package/src/components/FileUpload/index.tsx +1 -1
  416. package/src/components/FileUpload/useFileUploadManager.test.ts +308 -0
  417. package/src/components/FileUpload/useFileUploadManager.ts +454 -0
  418. package/src/components/FileUpload/useResolvedAppId.test.ts +102 -0
  419. package/src/components/FileUpload/useResolvedAppId.ts +77 -0
  420. package/src/components/Footer/Footer.test.tsx +15 -382
  421. package/src/components/Footer/Footer.tsx +8 -125
  422. package/src/components/Form/Form.test.tsx +425 -88
  423. package/src/components/Form/Form.tsx +91 -299
  424. package/src/components/Form/useFormPersistence.ts +257 -0
  425. package/src/components/Header/Header.test.tsx +653 -163
  426. package/src/components/Header/Header.tsx +62 -44
  427. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +35 -76
  428. package/src/components/Input/Input.test.tsx +34 -120
  429. package/src/components/Input/Input.tsx +1 -1
  430. package/src/components/Label/Label.test.tsx +46 -45
  431. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +8 -11
  432. package/src/components/LoginForm/LoginForm.test.tsx +0 -1
  433. package/src/components/NavigationMenu/HierarchicalNavItem.tsx +104 -0
  434. package/src/components/NavigationMenu/NavigationMenu.test.tsx +2422 -102
  435. package/src/components/NavigationMenu/NavigationMenu.tsx +62 -362
  436. package/src/components/NavigationMenu/index.ts +6 -1
  437. package/src/components/NavigationMenu/navigationPermissionHelper.ts +188 -0
  438. package/src/components/NavigationMenu/useNavigationFiltering.test.ts +1949 -0
  439. package/src/components/NavigationMenu/useNavigationFiltering.ts +199 -308
  440. package/src/components/NavigationMenu/useNavigationScope.ts +125 -0
  441. package/src/components/PaceAppLayout/PaceAppLayout.edge-cases.test.tsx +1322 -0
  442. package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +50 -49
  443. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +81 -38
  444. package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +103 -85
  445. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +774 -44
  446. package/src/components/PaceAppLayout/PaceAppLayout.tsx +282 -764
  447. package/src/components/PaceAppLayout/README.md +0 -9
  448. package/src/components/PaceAppLayout/test-setup.tsx +15 -9
  449. package/src/components/PaceAppLayout/useFilteredNavItems.ts +304 -0
  450. package/src/components/PaceAppLayout/usePaceAppLayoutConfig.ts +142 -0
  451. package/src/components/PaceAppLayout/usePaceAppLayoutGate.tsx +150 -0
  452. package/src/components/PaceAppLayout/usePaceAppLayoutPermissions.ts +162 -0
  453. package/src/components/PaceAppLayout/usePaceAppLayoutScope.ts +79 -0
  454. package/src/components/PaceAppLayout/useRoleBasedRouteAccess.ts +157 -0
  455. package/src/components/PaceAppLayout/useSuperAdminFallback.ts +58 -0
  456. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +782 -20
  457. package/src/components/PaceLoginPage/PaceLoginPage.tsx +33 -125
  458. package/src/components/PaceLoginPage/useLoginAppAccess.ts +153 -0
  459. package/src/components/PasswordChange/PasswordChangeForm.test.tsx +1 -1
  460. package/src/components/Progress/Progress.test.tsx +127 -1
  461. package/src/components/Progress/Progress.tsx +1 -2
  462. package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +1196 -4
  463. package/src/components/ProtectedRoute/ProtectedRoute.tsx +29 -217
  464. package/src/components/ProtectedRoute/useProtectedRouteState.ts +128 -0
  465. package/src/components/ProtectedRoute/useVisibilityRedirectGrace.ts +89 -0
  466. package/src/components/PublicLayout/PublicLayout.test.tsx +1640 -38
  467. package/src/components/PublicLayout/PublicPageContext.ts +28 -0
  468. package/src/components/PublicLayout/PublicPageLayout.tsx +134 -75
  469. package/src/components/PublicLayout/PublicPageProvider.tsx +7 -42
  470. package/src/components/PublicLayout/usePublicPageContext.ts +36 -0
  471. package/src/components/Select/Select.test.tsx +45 -8
  472. package/src/components/Select/Select.tsx +57 -40
  473. package/src/components/Select/context.test.tsx +56 -0
  474. package/src/components/Select/text.test.tsx +104 -0
  475. package/src/components/Select/text.ts +26 -0
  476. package/src/components/Select/types.ts +3 -0
  477. package/src/components/Select/useSelectEvents.test.ts +279 -0
  478. package/src/components/Select/useSelectEvents.ts +87 -0
  479. package/src/components/Select/useSelectSearch.test.tsx +295 -0
  480. package/src/components/Select/useSelectSearch.ts +91 -0
  481. package/src/components/Select/useSelectState.test.ts +268 -0
  482. package/src/components/Select/useSelectState.ts +104 -0
  483. package/src/components/SessionRestorationLoader/SessionRestorationLoader.test.tsx +28 -112
  484. package/src/components/Switch/Switch.test.tsx +57 -153
  485. package/src/components/Table/Table.test.tsx +395 -317
  486. package/src/components/Tabs/Tabs.test.tsx +270 -0
  487. package/src/components/Tabs/Tabs.tsx +4 -4
  488. package/src/components/Textarea/Textarea.test.tsx +11 -38
  489. package/src/components/Toast/Toast.test.tsx +425 -496
  490. package/src/components/Tooltip/Tooltip.test.tsx +4 -21
  491. package/src/components/UserMenu/UserMenu.test.tsx +1 -21
  492. package/src/components/UserMenu/UserMenu.tsx +0 -1
  493. package/src/components/index.test.ts +346 -0
  494. package/src/components/index.ts +12 -1
  495. package/src/constants/performance.test.ts +91 -0
  496. package/src/hooks/ServiceHooks.test.tsx +725 -0
  497. package/src/hooks/hooks.integration.test.tsx +608 -0
  498. package/src/hooks/index.ts +18 -3
  499. package/src/hooks/index.unit.test.ts +220 -0
  500. package/src/hooks/public/usePublicEvent.test.ts +304 -0
  501. package/src/hooks/public/usePublicEvent.ts +11 -11
  502. package/src/hooks/public/usePublicEventLogo.test.ts +655 -120
  503. package/src/hooks/public/usePublicEventLogo.ts +2 -2
  504. package/src/hooks/public/usePublicRouteParams.test.ts +595 -0
  505. package/src/hooks/public/usePublicRouteParams.ts +2 -2
  506. package/src/hooks/services/useAuth.ts +9 -7
  507. package/src/hooks/services/useAuthService.ts +1 -1
  508. package/src/hooks/services/useEventService.ts +1 -1
  509. package/src/hooks/useAccessibleApps.test.ts +400 -0
  510. package/src/hooks/useAccessibleApps.ts +264 -0
  511. package/src/hooks/useAddressAutocomplete.test.ts +170 -47
  512. package/src/hooks/useAddressAutocomplete.ts +109 -81
  513. package/src/hooks/useApiFetch.unit.test.ts +111 -0
  514. package/src/hooks/useAppConfig.ts +13 -3
  515. package/src/hooks/useAppConfig.unit.test.ts +712 -0
  516. package/src/hooks/useComponentPerformance.unit.test.tsx +314 -0
  517. package/src/hooks/useDataTablePerformance.ts +111 -130
  518. package/src/hooks/useDataTablePerformance.unit.test.ts +720 -0
  519. package/src/hooks/useDataTableState.test.ts +170 -0
  520. package/src/hooks/useDataTableState.ts +5 -5
  521. package/src/hooks/useDebounce.unit.test.ts +157 -0
  522. package/src/hooks/useEventTheme.test.ts +70 -18
  523. package/src/hooks/useEventTheme.ts +50 -22
  524. package/src/hooks/useEvents.ts +49 -2
  525. package/src/hooks/useEvents.unit.test.ts +227 -0
  526. package/src/hooks/useFileReference.test.ts +388 -107
  527. package/src/hooks/useFileReference.ts +184 -179
  528. package/src/hooks/useFileUrl.ts +1 -1
  529. package/src/hooks/useFileUrl.unit.test.ts +686 -0
  530. package/src/hooks/useFileUrlCache.test.ts +319 -0
  531. package/src/hooks/useFileUrlCache.ts +5 -2
  532. package/src/hooks/useFocusManagement.unit.test.ts +604 -0
  533. package/src/hooks/useFocusTrap.unit.test.tsx +613 -0
  534. package/src/hooks/useFormDialog.test.ts +307 -0
  535. package/src/hooks/useFormDialog.ts +2 -2
  536. package/src/hooks/useInactivityTracker.ts +141 -134
  537. package/src/hooks/useInactivityTracker.unit.test.ts +446 -0
  538. package/src/hooks/useIsMobile.unit.test.ts +317 -0
  539. package/src/hooks/useIsPrint.ts +62 -0
  540. package/src/hooks/useIsPrint.unit.test.ts +545 -0
  541. package/src/hooks/useKeyboardShortcuts.unit.test.ts +907 -0
  542. package/src/hooks/useOrganisationPermissions.test.ts +1 -2
  543. package/src/hooks/useOrganisationPermissions.ts +1 -4
  544. package/src/hooks/useOrganisationPermissions.unit.test.tsx +293 -0
  545. package/src/hooks/useOrganisationSecurity.test.ts +4 -33
  546. package/src/hooks/useOrganisationSecurity.ts +192 -203
  547. package/src/hooks/useOrganisationSecurity.unit.test.tsx +959 -0
  548. package/src/hooks/useOrganisations.ts +1 -1
  549. package/src/hooks/useOrganisations.unit.test.ts +369 -0
  550. package/src/hooks/usePerformanceMonitor.ts +1 -1
  551. package/src/hooks/usePerformanceMonitor.unit.test.ts +693 -0
  552. package/src/hooks/usePermissionCache.test.ts +298 -329
  553. package/src/hooks/usePermissionCache.ts +277 -276
  554. package/src/hooks/usePreventTabReload.test.ts +307 -0
  555. package/src/hooks/usePublicEvent.simple.test.ts +794 -0
  556. package/src/hooks/usePublicEvent.test.ts +670 -0
  557. package/src/hooks/usePublicEvent.unit.test.ts +638 -0
  558. package/src/hooks/usePublicFileDisplay.test.ts +948 -0
  559. package/src/hooks/usePublicRouteParams.unit.test.ts +442 -0
  560. package/src/hooks/useQueryCache.test.ts +391 -0
  561. package/src/hooks/useQueryCache.ts +7 -9
  562. package/src/hooks/useRBAC.unit.test.ts +253 -0
  563. package/src/hooks/useSessionDraft.test.ts +556 -0
  564. package/src/hooks/useSessionDraft.ts +14 -11
  565. package/src/hooks/useSessionRestoration.ts +1 -1
  566. package/src/hooks/useSessionRestoration.unit.test.tsx +381 -0
  567. package/src/hooks/useStorage.ts +94 -54
  568. package/src/hooks/useStorage.unit.test.ts +684 -0
  569. package/src/hooks/useToast.test.ts +413 -0
  570. package/src/hooks/useToast.ts +2 -2
  571. package/src/hooks/useToast.unit.test.tsx +481 -0
  572. package/src/hooks/useZodForm.ts +3 -3
  573. package/src/hooks/useZodForm.unit.test.tsx +191 -0
  574. package/src/icons/index.test.ts +133 -0
  575. package/src/icons/index.ts +3 -1
  576. package/src/index.test.ts +528 -0
  577. package/src/index.ts +56 -9
  578. package/src/providers/AuthProvider.test.tsx +218 -0
  579. package/src/providers/EventProvider.test.tsx +487 -0
  580. package/src/providers/InactivityProvider.test-helper.tsx +40 -0
  581. package/src/providers/InactivityProvider.test.tsx +421 -0
  582. package/src/providers/ProviderLifecycle.test.tsx +308 -0
  583. package/src/providers/UnifiedAuthProvider.smoke.test.tsx +7 -12
  584. package/src/providers/UnifiedAuthProvider.test.tsx +503 -0
  585. package/src/providers/index.test.ts +138 -0
  586. package/src/providers/services/AuthServiceContext.ts +27 -0
  587. package/src/providers/services/AuthServiceProvider.integration.test.tsx +229 -0
  588. package/src/providers/services/AuthServiceProvider.test.tsx +638 -0
  589. package/src/providers/services/AuthServiceProvider.tsx +81 -20
  590. package/src/providers/services/EventServiceContext.ts +25 -0
  591. package/src/providers/services/EventServiceProvider.test.tsx +839 -0
  592. package/src/providers/services/EventServiceProvider.tsx +11 -20
  593. package/src/providers/services/InactivityServiceContext.ts +25 -0
  594. package/src/providers/services/InactivityServiceProvider.test.tsx +662 -0
  595. package/src/providers/services/InactivityServiceProvider.tsx +7 -17
  596. package/src/providers/services/OrganisationServiceContext.ts +25 -0
  597. package/src/providers/services/OrganisationServiceProvider.test.tsx +440 -0
  598. package/src/providers/services/OrganisationServiceProvider.tsx +7 -17
  599. package/src/providers/services/UnifiedAuthContext.ts +102 -0
  600. package/src/providers/services/UnifiedAuthProvider.advanced.test.tsx +434 -0
  601. package/src/providers/services/UnifiedAuthProvider.appId.test.tsx +408 -0
  602. package/src/providers/services/UnifiedAuthProvider.integration.test.tsx +304 -0
  603. package/src/providers/services/UnifiedAuthProvider.test.tsx +212 -0
  604. package/src/providers/services/UnifiedAuthProvider.tsx +147 -497
  605. package/src/providers/services/contexts.test.tsx +281 -0
  606. package/src/providers/services/useUnifiedAuth.test.tsx +251 -0
  607. package/src/providers/services/useUnifiedAuth.ts +29 -0
  608. package/src/providers/services/useUnifiedAuthContextValue.ts +279 -0
  609. package/src/providers/useInactivity.test-helper.ts +27 -0
  610. package/src/rbac/README.md +5 -5
  611. package/src/rbac/adapters.comprehensive.test.tsx +429 -0
  612. package/src/rbac/adapters.test.tsx +654 -0
  613. package/src/rbac/adapters.tsx +53 -38
  614. package/src/rbac/api.test.ts +986 -259
  615. package/src/rbac/api.ts +260 -216
  616. package/src/rbac/audit-batched.test.ts +550 -0
  617. package/src/rbac/audit-batched.ts +5 -4
  618. package/src/rbac/audit.test.ts +225 -28
  619. package/src/rbac/audit.ts +26 -18
  620. package/src/rbac/auth-rbac-security.integration.test.tsx +300 -0
  621. package/src/rbac/auth-rbac.e2e.test.tsx +510 -0
  622. package/src/rbac/cache-invalidation.test.ts +715 -0
  623. package/src/rbac/cache-invalidation.ts +18 -15
  624. package/src/rbac/cache.test.ts +123 -63
  625. package/src/rbac/cache.ts +3 -4
  626. package/src/rbac/components/AccessDenied.test.tsx +324 -0
  627. package/src/rbac/components/AccessDenied.tsx +20 -18
  628. package/src/rbac/components/NavigationGuard.test.tsx +1148 -0
  629. package/src/rbac/components/NavigationGuard.tsx +10 -8
  630. package/src/rbac/components/PagePermissionGuard.guard.test.tsx +236 -0
  631. package/src/rbac/components/PagePermissionGuard.performance.test.tsx +252 -0
  632. package/src/rbac/components/PagePermissionGuard.race-condition.test.tsx +243 -0
  633. package/src/rbac/components/PagePermissionGuard.test.tsx +1430 -0
  634. package/src/rbac/components/PagePermissionGuard.tsx +188 -381
  635. package/src/rbac/components/PagePermissionGuard.verification.test.tsx +185 -0
  636. package/src/rbac/config.test.ts +131 -48
  637. package/src/rbac/config.ts +69 -26
  638. package/src/rbac/docs/event-based-apps.md +26 -13
  639. package/src/rbac/engine.comprehensive.test.ts +808 -0
  640. package/src/rbac/engine.test.ts +974 -130
  641. package/src/rbac/engine.ts +53 -13
  642. package/src/rbac/errors.test.ts +99 -87
  643. package/src/rbac/errors.ts +89 -55
  644. package/src/rbac/eslint-rules.js +2 -2
  645. package/src/rbac/hooks/permissions/runPermissionCheck.ts +77 -0
  646. package/src/rbac/hooks/permissions/useAccessLevel.test.ts +622 -0
  647. package/src/rbac/hooks/permissions/useAccessLevel.ts +23 -14
  648. package/src/rbac/hooks/permissions/useCan.test.ts +798 -0
  649. package/src/rbac/hooks/permissions/useCan.ts +173 -253
  650. package/src/rbac/hooks/permissions/useMultiplePermissions.test.ts +843 -0
  651. package/src/rbac/hooks/permissions/useMultiplePermissions.ts +63 -10
  652. package/src/rbac/hooks/permissions/usePermissions.test.ts +543 -0
  653. package/src/rbac/hooks/permissions/usePermissions.ts +50 -78
  654. package/src/rbac/hooks/useCan.test.ts +348 -32
  655. package/src/rbac/hooks/usePageAccessLogging.ts +160 -0
  656. package/src/rbac/hooks/usePageGuardScope.ts +117 -0
  657. package/src/rbac/hooks/usePagePermissionCheck.ts +67 -0
  658. package/src/rbac/hooks/usePermissions.integration.test.ts +427 -0
  659. package/src/rbac/hooks/usePermissions.stability.test.ts +268 -0
  660. package/src/rbac/hooks/usePermissions.test.ts +459 -33
  661. package/src/rbac/hooks/usePermissions.ts +5 -7
  662. package/src/rbac/hooks/useRBAC.test.ts +1784 -21
  663. package/src/rbac/hooks/useRBAC.ts +148 -88
  664. package/src/rbac/hooks/useResolvedScope.test.ts +442 -5
  665. package/src/rbac/hooks/useResolvedScope.ts +4 -1
  666. package/src/rbac/hooks/useResourcePermissions.test.ts +561 -24
  667. package/src/rbac/hooks/useResourcePermissions.ts +76 -140
  668. package/src/rbac/hooks/useResourcePermissionsSuperAdmin.ts +67 -0
  669. package/src/rbac/hooks/useRoleManagement.test.ts +634 -61
  670. package/src/rbac/hooks/useRoleManagement.ts +158 -586
  671. package/src/rbac/hooks/useSecureSupabase.test.ts +1179 -0
  672. package/src/rbac/hooks/useSecureSupabase.ts +21 -14
  673. package/src/rbac/hooks/useSuperAdminCheck.ts +80 -0
  674. package/src/rbac/index.test.ts +107 -0
  675. package/src/rbac/index.ts +32 -32
  676. package/src/rbac/performance.test.ts +451 -0
  677. package/src/rbac/permissions.test.ts +149 -68
  678. package/src/rbac/permissions.ts +0 -3
  679. package/src/rbac/rbac-core.test.tsx +276 -0
  680. package/src/rbac/rbac-engine-core-logic.test.ts +387 -0
  681. package/src/rbac/rbac-engine-simplified.test.ts +252 -0
  682. package/src/rbac/rbac-functions.test.ts +703 -0
  683. package/src/rbac/rbac-integration.test.ts +523 -0
  684. package/src/rbac/rbac-role-isolation.test.ts +456 -0
  685. package/src/rbac/request-deduplication.test.ts +352 -0
  686. package/src/rbac/request-deduplication.ts +5 -4
  687. package/src/rbac/scenarios.user-role.test.tsx +271 -0
  688. package/src/rbac/secureClient.test.ts +499 -115
  689. package/src/rbac/secureClient.ts +54 -28
  690. package/src/rbac/security.test.ts +448 -44
  691. package/src/rbac/security.ts +7 -6
  692. package/src/rbac/types/roleManagement.ts +66 -0
  693. package/src/rbac/types.test.ts +236 -0
  694. package/src/rbac/types.ts +7 -5
  695. package/src/rbac/utils/clientSecurity.test.ts +192 -0
  696. package/src/rbac/utils/clientSecurity.ts +6 -4
  697. package/src/rbac/utils/contextValidator.test.ts +126 -0
  698. package/src/rbac/utils/contextValidator.ts +6 -3
  699. package/src/rbac/utils/deep-equal.test.ts +76 -0
  700. package/src/rbac/utils/eventContext.test.ts +401 -0
  701. package/src/rbac/utils/eventContext.ts +38 -34
  702. package/src/rbac/utils/fetchPermissionMap.ts +13 -0
  703. package/src/rbac/utils/permissionMapHelpers.ts +34 -0
  704. package/src/rbac/utils/roleManagementRpc.ts +303 -0
  705. package/src/services/AuthService.edge-cases.test.ts +746 -0
  706. package/src/services/AuthService.restoreSession.test.ts +59 -0
  707. package/src/services/AuthService.test.ts +1362 -0
  708. package/src/services/AuthService.ts +197 -216
  709. package/src/services/BaseService.edge-cases.test.ts +506 -0
  710. package/src/services/BaseService.test.ts +363 -0
  711. package/src/services/EventService.edge-cases.test.ts +636 -0
  712. package/src/services/EventService.eventColours.test.ts +64 -0
  713. package/src/services/EventService.test.ts +1250 -0
  714. package/src/services/EventService.ts +244 -315
  715. package/src/services/InactivityService.edge-cases.test.ts +492 -0
  716. package/src/services/InactivityService.lifecycle.test.ts +406 -0
  717. package/src/services/InactivityService.test.ts +829 -0
  718. package/src/services/InactivityService.ts +172 -213
  719. package/src/services/OrganisationService.edge-cases.test.ts +633 -0
  720. package/src/services/OrganisationService.pagination.test.ts +409 -0
  721. package/src/services/OrganisationService.test.ts +1579 -0
  722. package/src/services/OrganisationService.ts +186 -257
  723. package/src/services/base/BaseService.test.ts +214 -0
  724. package/src/services/interfaces/IAuthService.test.ts +184 -0
  725. package/src/services/interfaces/IAuthService.ts +10 -9
  726. package/src/services/interfaces/IEventService.test.ts +176 -0
  727. package/src/services/interfaces/IInactivityService.test.ts +183 -0
  728. package/src/services/interfaces/IOrganisationService.test.ts +207 -0
  729. package/src/services/interfaces/IOrganisationService.ts +0 -1
  730. package/src/styles/core.css +244 -12
  731. package/src/theming/parseEventColours.test.ts +321 -0
  732. package/src/theming/parseEventColours.ts +18 -9
  733. package/src/theming/runtime.test.ts +495 -0
  734. package/src/theming/runtime.ts +72 -7
  735. package/src/types/api-result.ts +53 -0
  736. package/src/types/auth.ts +0 -1
  737. package/src/types/core.test.ts +397 -0
  738. package/src/types/database-generated.test.ts +78 -0
  739. package/src/types/database.generated.ts +45 -10
  740. package/src/types/event.ts +39 -19
  741. package/src/types/file-reference.test.ts +351 -0
  742. package/src/types/file-reference.ts +37 -12
  743. package/src/types/guards.test.ts +246 -0
  744. package/src/types/index.test.ts +265 -0
  745. package/src/types/index.ts +3 -0
  746. package/src/types/organisation.roles.test.ts +55 -0
  747. package/src/types/organisation.test.ts +1105 -0
  748. package/src/types/organisation.ts +15 -15
  749. package/src/types/rpc-responses.ts +33 -0
  750. package/src/types/supabase.ts +14 -6
  751. package/src/types/theme.test.ts +830 -0
  752. package/src/types/type-validation.test.ts +526 -0
  753. package/src/types/validation.test.ts +729 -0
  754. package/src/types/vitest-globals.d.ts +1 -1
  755. package/src/utils/app/appConfig.test.ts +235 -0
  756. package/src/utils/app/appIdResolver.test.ts +252 -57
  757. package/src/utils/app/appIdResolver.ts +31 -20
  758. package/src/utils/app/appNameResolver.test.ts +18 -10
  759. package/src/utils/app/appNameResolver.ts +11 -9
  760. package/src/utils/app/appPortMap.test.ts +125 -0
  761. package/src/utils/app/appPortMap.ts +51 -0
  762. package/src/utils/app/buildAppUrl.test.ts +273 -0
  763. package/src/utils/app/buildAppUrl.ts +114 -0
  764. package/src/utils/appConfig.unit.test.ts +55 -0
  765. package/src/utils/audit/audit.test.ts +354 -39
  766. package/src/utils/audit.unit.test.ts +69 -0
  767. package/src/utils/auth-utils.unit.test.ts +69 -0
  768. package/src/utils/bundleAnalysis.unit.test.ts +326 -0
  769. package/src/utils/cn.unit.test.ts +34 -0
  770. package/src/utils/context/organisationContext.test.ts +115 -95
  771. package/src/utils/context/organisationContext.ts +32 -43
  772. package/src/utils/context/sessionTracking.test.ts +354 -0
  773. package/src/utils/core/cn.test.ts +66 -0
  774. package/src/utils/core/debugLogger.test.ts +113 -0
  775. package/src/utils/core/debugLogger.ts +15 -8
  776. package/src/utils/core/logger.test.ts +217 -0
  777. package/src/utils/core/logger.ts +20 -16
  778. package/src/utils/core/mergeRefs.ts +24 -0
  779. package/src/utils/debugLogger.test.ts +417 -0
  780. package/src/utils/device/deviceFingerprint.test.ts +8 -5
  781. package/src/utils/device/deviceFingerprint.ts +3 -3
  782. package/src/utils/deviceFingerprint.unit.test.ts +818 -0
  783. package/src/utils/dynamic/createLazyComponent.tsx +46 -0
  784. package/src/utils/dynamic/dynamicUtils.test.ts +185 -0
  785. package/src/utils/dynamic/dynamicUtils.ts +6 -6
  786. package/src/utils/dynamic/lazyLoad.test.tsx +156 -0
  787. package/src/utils/dynamic/lazyLoad.tsx +8 -36
  788. package/src/utils/dynamic/papaparseLoader.ts +7 -0
  789. package/src/utils/dynamicUtils.unit.test.ts +331 -0
  790. package/src/utils/file-reference/file-reference.test.ts +1238 -0
  791. package/src/utils/file-reference/index.ts +330 -348
  792. package/src/utils/formatDate.unit.test.ts +109 -0
  793. package/src/utils/formatting/formatDate.test.ts +22 -148
  794. package/src/utils/formatting/formatDateTime.test.ts +41 -119
  795. package/src/utils/formatting/formatDateTimeTimezone.test.ts +41 -85
  796. package/src/utils/formatting/formatNumber.test.ts +259 -0
  797. package/src/utils/formatting/formatTime.test.ts +36 -128
  798. package/src/utils/formatting/formatting.ts +1 -1
  799. package/src/utils/formatting.unit.test.ts +99 -0
  800. package/src/utils/google-places/googlePlacesUtils.test.ts +127 -36
  801. package/src/utils/google-places/googlePlacesUtils.ts +67 -86
  802. package/src/utils/google-places/loadGoogleMapsScript.test.ts +68 -8
  803. package/src/utils/google-places/loadGoogleMapsScript.ts +140 -118
  804. package/src/utils/index.ts +52 -11
  805. package/src/utils/index.unit.test.ts +251 -0
  806. package/src/utils/lazyLoad.unit.test.tsx +319 -0
  807. package/src/utils/location/location.test.ts +19 -116
  808. package/src/utils/logger.unit.test.ts +398 -0
  809. package/src/utils/organisationContext.unit.test.ts +180 -0
  810. package/src/utils/performance/bundleAnalysis.test.ts +148 -0
  811. package/src/utils/performance/bundleAnalysis.ts +16 -22
  812. package/src/utils/performance/performanceBenchmark.test.ts +251 -0
  813. package/src/utils/performance/performanceBenchmark.ts +12 -4
  814. package/src/utils/performance/performanceBudgets.test.ts +241 -0
  815. package/src/utils/performance/performanceBudgets.ts +9 -6
  816. package/src/utils/performanceBenchmark.test.ts +174 -0
  817. package/src/utils/performanceBudgets.unit.test.ts +288 -0
  818. package/src/utils/permissionTypes.unit.test.ts +250 -0
  819. package/src/utils/permissionUtils.unit.test.ts +362 -0
  820. package/src/utils/permissions/permissionTypes.test.ts +149 -0
  821. package/src/utils/permissions/permissionUtils.test.ts +20 -42
  822. package/src/utils/persistence/keyDerivation.test.ts +306 -0
  823. package/src/utils/persistence/sensitiveFieldDetection.test.ts +271 -0
  824. package/src/utils/persistence/sensitiveFieldDetection.ts +2 -2
  825. package/src/utils/request-deduplication.test.ts +349 -0
  826. package/src/utils/request-deduplication.ts +6 -4
  827. package/src/utils/sanitization.unit.test.ts +346 -0
  828. package/src/utils/schemaUtils.unit.test.ts +441 -0
  829. package/src/utils/secureDataAccess.unit.test.ts +334 -0
  830. package/src/utils/secureErrors.unit.test.ts +390 -0
  831. package/src/utils/secureStorage.unit.test.ts +289 -0
  832. package/src/utils/security/auth-utils.ts +38 -27
  833. package/src/utils/security/secureDataAccess.test.ts +22 -191
  834. package/src/utils/security/secureDataAccess.ts +241 -281
  835. package/src/utils/security/secureErrors.test.ts +163 -0
  836. package/src/utils/security/secureStorage.test.ts +156 -0
  837. package/src/utils/security/secureStorage.ts +1 -1
  838. package/src/utils/security/security.test.ts +212 -0
  839. package/src/utils/security/security.ts +15 -18
  840. package/src/utils/security/securityMonitor.test.ts +90 -0
  841. package/src/utils/security/securityMonitor.ts +1 -1
  842. package/src/utils/security.unit.test.ts +155 -0
  843. package/src/utils/securityMonitor.unit.test.ts +276 -0
  844. package/src/utils/sessionTracking.unit.test.ts +218 -0
  845. package/src/utils/storage/config.unit.test.ts +239 -0
  846. package/src/utils/storage/helpers.test.ts +769 -456
  847. package/src/utils/storage/helpers.ts +174 -253
  848. package/src/utils/storage/index.unit.test.ts +68 -0
  849. package/src/utils/storage/storageUtils.ts +32 -0
  850. package/src/utils/storage/types.ts +9 -2
  851. package/src/utils/supabase/createBaseClient.test.ts +201 -0
  852. package/src/utils/supabase/createBaseClient.ts +2 -1
  853. package/src/utils/timezone/timezone.test.ts +26 -44
  854. package/src/utils/timezone.test.ts +345 -0
  855. package/src/utils/validation/common.test.ts +115 -0
  856. package/src/utils/validation/csrf.test.ts +198 -0
  857. package/src/utils/validation/csrf.ts +42 -41
  858. package/src/utils/validation/htmlSanitization.ts +27 -31
  859. package/src/utils/validation/htmlSanitization.unit.test.ts +618 -0
  860. package/src/utils/validation/passwordSchema.test.ts +164 -0
  861. package/src/utils/validation/schema.test.ts +127 -0
  862. package/src/utils/validation/schema.ts +6 -3
  863. package/src/utils/validation/sqlInjectionProtection.test.ts +165 -0
  864. package/src/utils/validation/sqlInjectionProtection.ts +2 -2
  865. package/src/utils/validation/user.test.ts +173 -0
  866. package/src/utils/validation/validation.test.ts +197 -0
  867. package/src/utils/validation/validationUtils.test.ts +294 -0
  868. package/src/utils/validation.unit.test.ts +307 -0
  869. package/src/utils/validationUtils.unit.test.ts +558 -0
  870. package/src/vite-env.d.ts +6 -0
  871. package/dist/AuthService-DmfO5rGS.d.ts +0 -524
  872. package/dist/DataTable-DRUIgtUH.d.ts +0 -166
  873. package/dist/DataTable-SOAFXIWY.js +0 -15
  874. package/dist/PublicPageProvider-CIGSujI2.d.ts +0 -4147
  875. package/dist/UnifiedAuthProvider-7SNDOWYD.js +0 -7
  876. package/dist/UnifiedAuthProvider-CKvHP1MK.d.ts +0 -139
  877. package/dist/api-7P7DI652.js +0 -4
  878. package/dist/audit-MYQXYZFU.js +0 -3
  879. package/dist/auth-BZOJqrdd.d.ts +0 -49
  880. package/dist/chunk-4DDCYDQ3.js +0 -544
  881. package/dist/chunk-5HNSDQWH.js +0 -5046
  882. package/dist/chunk-5W2A3DRC.js +0 -164
  883. package/dist/chunk-6GLLNA6U.js +0 -31
  884. package/dist/chunk-7ILTDCL2.js +0 -80
  885. package/dist/chunk-A3W6LW53.js +0 -70
  886. package/dist/chunk-AHU7G2R5.js +0 -423
  887. package/dist/chunk-C7ZQ5O4C.js +0 -481
  888. package/dist/chunk-EF2UGZWY.js +0 -611
  889. package/dist/chunk-FEJLJNWA.js +0 -181
  890. package/dist/chunk-FYHN4DD5.js +0 -415
  891. package/dist/chunk-GS5672WG.js +0 -2003
  892. package/dist/chunk-HF6O3O37.js +0 -187
  893. package/dist/chunk-J2U36LHD.js +0 -8517
  894. package/dist/chunk-LX6U42O3.js +0 -2177
  895. package/dist/chunk-MPBLMWVR.js +0 -2161
  896. package/dist/chunk-OJ4SKRSV.js +0 -105
  897. package/dist/chunk-S6ZQKDY6.js +0 -62
  898. package/dist/chunk-S7DKJPLT.js +0 -699
  899. package/dist/chunk-T5CVK4R3.js +0 -2816
  900. package/dist/chunk-TTRFSOKR.js +0 -121
  901. package/dist/chunk-Z2FNRKF3.js +0 -994
  902. package/dist/database.generated-DT8JTZiP.d.ts +0 -9406
  903. package/dist/event-CW5YB_2p.d.ts +0 -239
  904. package/dist/file-reference-BavO2eQj.d.ts +0 -148
  905. package/dist/functions-lBy5L2ry.d.ts +0 -208
  906. package/dist/timezone-0AyangqX.d.ts +0 -697
  907. package/dist/types-BeoeWV5I.d.ts +0 -110
  908. package/dist/types-DXstZpNI.d.ts +0 -614
  909. package/dist/types-t9H8qKRw.d.ts +0 -55
  910. package/dist/usePublicRouteParams-DQLrDqDb.d.ts +0 -876
  911. package/dist/useToast-AyaT-x7p.d.ts +0 -68
  912. package/dist/validation-643vUDZW.d.ts +0 -177
  913. package/scripts/build-docs-incremental.js +0 -179
  914. package/scripts/eslint-audit.cjs +0 -123
  915. package/scripts/generate-docs.js +0 -157
  916. package/scripts/install-cursor-rules.cjs +0 -255
  917. package/scripts/install-eslint-config.cjs +0 -349
  918. package/scripts/setup-build-cache.js +0 -73
  919. package/scripts/validate-pre-publish.js +0 -145
  920. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +0 -260
  921. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +0 -224
  922. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +0 -273
  923. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +0 -99
  924. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +0 -448
  925. package/src/__tests__/helpers/__tests__/timer-utils.test.ts +0 -371
  926. package/src/__tests__/hooks/usePermissions.test.ts +0 -268
  927. package/src/__tests__/integration/UserProfile.test.tsx +0 -124
  928. package/src/__tests__/public-recipe-view.test.ts +0 -228
  929. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +0 -220
  930. package/src/__tests__/rls-policies.test.ts +0 -471
  931. package/src/components/DataTable/__tests__/DataTable.comprehensive.test.tsx +0 -759
  932. package/src/components/DataTable/__tests__/DataTable.default-state.test.tsx +0 -524
  933. package/src/components/DataTable/__tests__/DataTable.export.test.tsx +0 -705
  934. package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +0 -658
  935. package/src/components/DataTable/__tests__/DataTable.hooks.test.tsx +0 -192
  936. package/src/components/DataTable/__tests__/DataTable.select-label-display.test.tsx +0 -483
  937. package/src/components/DataTable/__tests__/DataTable.test.tsx +0 -876
  938. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +0 -220
  939. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +0 -1474
  940. package/src/components/DataTable/__tests__/README.md +0 -145
  941. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +0 -788
  942. package/src/components/DataTable/__tests__/keyboard.test.tsx +0 -756
  943. package/src/components/DataTable/__tests__/mocks/MockRBACProvider.tsx +0 -66
  944. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +0 -730
  945. package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx +0 -325
  946. package/src/components/DataTable/__tests__/styles.test.ts +0 -382
  947. package/src/components/DataTable/__tests__/test-utils/dataFactories.ts +0 -103
  948. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +0 -380
  949. package/src/components/DataTable/__tests__/test-utils.ts +0 -94
  950. package/src/components/DataTable/components/AccessDeniedPage.tsx +0 -159
  951. package/src/components/DataTable/components/ActionButtons.tsx +0 -190
  952. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +0 -160
  953. package/src/components/DataTable/components/ColumnFilter.tsx +0 -118
  954. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +0 -114
  955. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +0 -225
  956. package/src/components/DataTable/components/DataTableLayout.tsx +0 -573
  957. package/src/components/DataTable/components/DataTableModals.tsx +0 -245
  958. package/src/components/DataTable/components/DataTableToolbar.tsx +0 -271
  959. package/src/components/DataTable/components/EditFields.tsx +0 -327
  960. package/src/components/DataTable/components/EditableRow.tsx +0 -462
  961. package/src/components/DataTable/components/EmptyState.tsx +0 -79
  962. package/src/components/DataTable/components/FilterRow.tsx +0 -141
  963. package/src/components/DataTable/components/LoadingState.tsx +0 -17
  964. package/src/components/DataTable/components/PaginationControls.tsx +0 -289
  965. package/src/components/DataTable/components/RowComponent.tsx +0 -403
  966. package/src/components/DataTable/components/SortIndicator.tsx +0 -50
  967. package/src/components/DataTable/components/UnifiedTableBody.tsx +0 -355
  968. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +0 -657
  969. package/src/components/DataTable/components/__tests__/ActionButtons.test.tsx +0 -913
  970. package/src/components/DataTable/components/__tests__/BulkOperationsDropdown.test.tsx +0 -572
  971. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +0 -612
  972. package/src/components/DataTable/components/__tests__/ColumnVisibilityDropdown.test.tsx +0 -708
  973. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +0 -479
  974. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +0 -475
  975. package/src/components/DataTable/components/__tests__/DataTableToolbar.test.tsx +0 -157
  976. package/src/components/DataTable/components/__tests__/EditableRow.test.tsx +0 -1061
  977. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +0 -437
  978. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +0 -474
  979. package/src/components/DataTable/components/__tests__/GroupingDropdown.test.tsx +0 -617
  980. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +0 -1093
  981. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +0 -139
  982. package/src/components/DataTable/components/__tests__/PaginationControls.test.tsx +0 -519
  983. package/src/components/DataTable/components/__tests__/UnifiedTableBody.test.tsx +0 -1004
  984. package/src/components/DataTable/components/cellValueUtils.ts +0 -40
  985. package/src/components/DataTable/components/hooks/useImportModalFocus.ts +0 -53
  986. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -122
  987. package/src/components/DataTable/components/index.ts +0 -16
  988. package/src/components/DataTable/context/__tests__/DataTableContext.test.tsx +0 -342
  989. package/src/components/DataTable/core/ActionManager.ts +0 -235
  990. package/src/components/DataTable/core/ColumnManager.ts +0 -205
  991. package/src/components/DataTable/core/DataManager.ts +0 -188
  992. package/src/components/DataTable/core/LocalDataAdapter.ts +0 -274
  993. package/src/components/DataTable/core/PluginRegistry.ts +0 -229
  994. package/src/components/DataTable/core/StateManager.ts +0 -312
  995. package/src/components/DataTable/core/__tests__/ActionManager.test.ts +0 -123
  996. package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +0 -305
  997. package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +0 -84
  998. package/src/components/DataTable/core/__tests__/DataManager.test.ts +0 -115
  999. package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +0 -100
  1000. package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +0 -120
  1001. package/src/components/DataTable/core/__tests__/StateManager.test.ts +0 -104
  1002. package/src/components/DataTable/core/index.ts +0 -1
  1003. package/src/components/DataTable/core/interfaces.ts +0 -338
  1004. package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.test.ts +0 -521
  1005. package/src/components/DataTable/hooks/__tests__/useColumnVisibilityPersistence.test.ts +0 -167
  1006. package/src/components/DataTable/hooks/__tests__/useDataTableConfiguration.test.ts +0 -124
  1007. package/src/components/DataTable/hooks/__tests__/useDataTableDataPipeline.test.ts +0 -117
  1008. package/src/components/DataTable/hooks/__tests__/useDataTablePermissions.test.ts +0 -102
  1009. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +0 -596
  1010. package/src/components/DataTable/hooks/__tests__/useEffectiveColumnOrder.test.ts +0 -53
  1011. package/src/components/DataTable/hooks/__tests__/useHierarchicalState.test.ts +0 -214
  1012. package/src/components/DataTable/hooks/__tests__/useTableColumns.test.ts +0 -448
  1013. package/src/components/DataTable/hooks/index.ts +0 -13
  1014. package/src/components/DataTable/types.ts +0 -761
  1015. package/src/components/DataTable/utils/__tests__/a11yUtils.test.ts +0 -612
  1016. package/src/components/DataTable/utils/__tests__/columnUtils.test.ts +0 -94
  1017. package/src/components/DataTable/utils/__tests__/errorHandling.test.ts +0 -266
  1018. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +0 -954
  1019. package/src/components/DataTable/utils/__tests__/flexibleImport.test.ts +0 -573
  1020. package/src/components/DataTable/utils/__tests__/hierarchicalSorting.test.ts +0 -247
  1021. package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +0 -570
  1022. package/src/components/DataTable/utils/__tests__/performanceUtils.test.ts +0 -470
  1023. package/src/components/DataTable/utils/__tests__/rowUtils.test.ts +0 -251
  1024. package/src/components/DataTable/utils/__tests__/selectFieldUtils.test.ts +0 -207
  1025. package/src/components/DataTable/utils/index.ts +0 -10
  1026. package/src/components/PublicLayout/index.ts +0 -32
  1027. package/src/components/Select/hooks/useSelectEvents.ts +0 -87
  1028. package/src/components/Select/hooks/useSelectSearch.ts +0 -91
  1029. package/src/components/Select/hooks/useSelectState.ts +0 -104
  1030. package/src/components/Select/utils/text.ts +0 -26
  1031. package/src/hooks/__tests__/ServiceHooks.test.tsx +0 -615
  1032. package/src/hooks/__tests__/hooks.integration.test.tsx +0 -607
  1033. package/src/hooks/__tests__/index.unit.test.ts +0 -220
  1034. package/src/hooks/__tests__/useApiFetch.unit.test.ts +0 -111
  1035. package/src/hooks/__tests__/useAppConfig.unit.test.ts +0 -347
  1036. package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +0 -144
  1037. package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +0 -776
  1038. package/src/hooks/__tests__/useDataTableState.test.ts +0 -76
  1039. package/src/hooks/__tests__/useDebounce.unit.test.ts +0 -82
  1040. package/src/hooks/__tests__/useEvents.unit.test.ts +0 -252
  1041. package/src/hooks/__tests__/useFileDisplay.unit.test.ts +0 -1112
  1042. package/src/hooks/__tests__/useFileUrl.unit.test.ts +0 -916
  1043. package/src/hooks/__tests__/useFileUrlCache.test.ts +0 -129
  1044. package/src/hooks/__tests__/useFocusManagement.unit.test.ts +0 -230
  1045. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +0 -828
  1046. package/src/hooks/__tests__/useFormDialog.test.ts +0 -478
  1047. package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +0 -446
  1048. package/src/hooks/__tests__/useIsMobile.unit.test.ts +0 -317
  1049. package/src/hooks/__tests__/useKeyboardShortcuts.unit.test.ts +0 -910
  1050. package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +0 -294
  1051. package/src/hooks/__tests__/useOrganisationSecurity.unit.test.tsx +0 -961
  1052. package/src/hooks/__tests__/useOrganisations.unit.test.ts +0 -369
  1053. package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +0 -694
  1054. package/src/hooks/__tests__/usePermissionCache.simple.test.ts +0 -192
  1055. package/src/hooks/__tests__/usePermissionCache.unit.test.ts +0 -741
  1056. package/src/hooks/__tests__/usePreventTabReload.test.ts +0 -88
  1057. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +0 -785
  1058. package/src/hooks/__tests__/usePublicEvent.test.ts +0 -678
  1059. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +0 -630
  1060. package/src/hooks/__tests__/usePublicFileDisplay.test.ts +0 -951
  1061. package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +0 -443
  1062. package/src/hooks/__tests__/useQueryCache.test.ts +0 -144
  1063. package/src/hooks/__tests__/useRBAC.unit.test.ts +0 -236
  1064. package/src/hooks/__tests__/useSessionDraft.test.ts +0 -163
  1065. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +0 -390
  1066. package/src/hooks/__tests__/useStorage.unit.test.ts +0 -751
  1067. package/src/hooks/__tests__/useToast.unit.test.tsx +0 -481
  1068. package/src/hooks/__tests__/useZodForm.unit.test.tsx +0 -37
  1069. package/src/hooks/public/index.ts +0 -36
  1070. package/src/hooks/public/usePublicFileDisplay.ts +0 -504
  1071. package/src/hooks/useFileDisplay.ts +0 -715
  1072. package/src/providers/OrganisationProvider.tsx +0 -92
  1073. package/src/providers/__tests__/AuthProvider.test.tsx +0 -287
  1074. package/src/providers/__tests__/EventProvider.test.tsx +0 -551
  1075. package/src/providers/__tests__/InactivityProvider.test-helper.tsx +0 -65
  1076. package/src/providers/__tests__/InactivityProvider.test.tsx +0 -572
  1077. package/src/providers/__tests__/OrganisationProvider.test.tsx +0 -617
  1078. package/src/providers/__tests__/ProviderLifecycle.test.tsx +0 -424
  1079. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +0 -596
  1080. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +0 -263
  1081. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +0 -294
  1082. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +0 -434
  1083. package/src/rbac/__tests__/auth-rbac-security.integration.test.tsx +0 -313
  1084. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +0 -486
  1085. package/src/rbac/__tests__/cache-invalidation.test.ts +0 -399
  1086. package/src/rbac/__tests__/engine.comprehensive.test.ts +0 -813
  1087. package/src/rbac/__tests__/isSuperAdmin.real.test.ts +0 -82
  1088. package/src/rbac/__tests__/rbac-core.test.tsx +0 -276
  1089. package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +0 -392
  1090. package/src/rbac/__tests__/rbac-engine-simplified.test.ts +0 -258
  1091. package/src/rbac/__tests__/rbac-functions.test.ts +0 -647
  1092. package/src/rbac/__tests__/rbac-integration.test.ts +0 -524
  1093. package/src/rbac/__tests__/rbac-role-isolation.test.ts +0 -456
  1094. package/src/rbac/__tests__/scenarios.user-role.test.tsx +0 -282
  1095. package/src/rbac/audit-enhanced.ts +0 -384
  1096. package/src/rbac/compliance/database-validator.ts +0 -165
  1097. package/src/rbac/compliance/index.ts +0 -48
  1098. package/src/rbac/compliance/pattern-detector.ts +0 -553
  1099. package/src/rbac/compliance/quick-fix-suggestions.ts +0 -209
  1100. package/src/rbac/compliance/runtime-compliance.ts +0 -99
  1101. package/src/rbac/compliance/setup-validator.ts +0 -131
  1102. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +0 -975
  1103. package/src/rbac/components/__tests__/PagePermissionGuard.performance.test.tsx +0 -248
  1104. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +0 -242
  1105. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +0 -1107
  1106. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +0 -184
  1107. package/src/rbac/components/index.ts +0 -26
  1108. package/src/rbac/hooks/__tests__/usePermissions.integration.test.ts +0 -432
  1109. package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +0 -579
  1110. package/src/rbac/hooks/index.ts +0 -34
  1111. package/src/rbac/hooks/permissions/index.ts +0 -4
  1112. package/src/rbac/hooks/useRBAC.simple.test.ts +0 -95
  1113. package/src/rbac/utils/__tests__/contextValidator.test.ts +0 -128
  1114. package/src/rbac/utils/__tests__/deep-equal.test.ts +0 -53
  1115. package/src/rbac/utils/__tests__/eventContext.test.ts +0 -433
  1116. package/src/rbac/utils/__tests__/eventContext.unit.test.ts +0 -490
  1117. package/src/services/__tests__/AuthService.restoreSession.test.ts +0 -39
  1118. package/src/services/__tests__/AuthService.test.ts +0 -1332
  1119. package/src/services/__tests__/BaseService.test.ts +0 -314
  1120. package/src/services/__tests__/EventService.eventColours.test.ts +0 -76
  1121. package/src/services/__tests__/EventService.test.ts +0 -1025
  1122. package/src/services/__tests__/InactivityService.lifecycle.test.ts +0 -411
  1123. package/src/services/__tests__/InactivityService.test.ts +0 -654
  1124. package/src/services/__tests__/OrganisationService.pagination.test.ts +0 -409
  1125. package/src/services/__tests__/OrganisationService.test.ts +0 -1176
  1126. package/src/theming/__tests__/parseEventColours.test.ts +0 -321
  1127. package/src/theming/__tests__/runtime.test.ts +0 -569
  1128. package/src/types/__tests__/file-reference.test.ts +0 -447
  1129. package/src/types/__tests__/guards.test.ts +0 -246
  1130. package/src/types/__tests__/organisation.roles.test.ts +0 -55
  1131. package/src/types/__tests__/organisation.test.ts +0 -1133
  1132. package/src/types/__tests__/theme.test.ts +0 -830
  1133. package/src/types/__tests__/type-validation.test.ts +0 -526
  1134. package/src/types/__tests__/validation.test.ts +0 -731
  1135. package/src/utils/__tests__/appConfig.unit.test.ts +0 -55
  1136. package/src/utils/__tests__/audit.unit.test.ts +0 -69
  1137. package/src/utils/__tests__/auth-utils.unit.test.ts +0 -70
  1138. package/src/utils/__tests__/bundleAnalysis.unit.test.ts +0 -339
  1139. package/src/utils/__tests__/cn.unit.test.ts +0 -34
  1140. package/src/utils/__tests__/debugLogger.test.ts +0 -417
  1141. package/src/utils/__tests__/deviceFingerprint.unit.test.ts +0 -818
  1142. package/src/utils/__tests__/dynamicUtils.unit.test.ts +0 -318
  1143. package/src/utils/__tests__/formatDate.unit.test.ts +0 -109
  1144. package/src/utils/__tests__/formatting.unit.test.ts +0 -99
  1145. package/src/utils/__tests__/index.unit.test.ts +0 -251
  1146. package/src/utils/__tests__/lazyLoad.unit.test.tsx +0 -321
  1147. package/src/utils/__tests__/logger.unit.test.ts +0 -398
  1148. package/src/utils/__tests__/organisationContext.unit.test.ts +0 -191
  1149. package/src/utils/__tests__/performanceBenchmark.test.ts +0 -175
  1150. package/src/utils/__tests__/performanceBudgets.unit.test.ts +0 -253
  1151. package/src/utils/__tests__/permissionTypes.unit.test.ts +0 -250
  1152. package/src/utils/__tests__/permissionUtils.unit.test.ts +0 -362
  1153. package/src/utils/__tests__/sanitization.unit.test.ts +0 -346
  1154. package/src/utils/__tests__/schemaUtils.unit.test.ts +0 -441
  1155. package/src/utils/__tests__/secureDataAccess.unit.test.ts +0 -335
  1156. package/src/utils/__tests__/secureErrors.unit.test.ts +0 -390
  1157. package/src/utils/__tests__/secureStorage.unit.test.ts +0 -289
  1158. package/src/utils/__tests__/security.unit.test.ts +0 -149
  1159. package/src/utils/__tests__/securityMonitor.unit.test.ts +0 -276
  1160. package/src/utils/__tests__/sessionTracking.unit.test.ts +0 -218
  1161. package/src/utils/__tests__/timezone.test.ts +0 -345
  1162. package/src/utils/__tests__/validation.unit.test.ts +0 -308
  1163. package/src/utils/__tests__/validationUtils.unit.test.ts +0 -555
  1164. package/src/utils/app/appNameResolver.simple.test.ts +0 -212
  1165. package/src/utils/file-reference/__tests__/file-reference.test.ts +0 -875
  1166. package/src/utils/google-places/index.ts +0 -26
  1167. package/src/utils/location/index.ts +0 -16
  1168. package/src/utils/persistence/__tests__/keyDerivation.test.ts +0 -135
  1169. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +0 -123
  1170. package/src/utils/storage/__tests__/helpers.unit.test.ts +0 -332
  1171. package/src/utils/storage/__tests__/index.unit.test.ts +0 -16
  1172. package/src/utils/storage/index.ts +0 -67
  1173. package/src/utils/timezone/index.ts +0 -17
  1174. package/src/utils/validation/__tests__/csrf.test.ts +0 -105
  1175. package/src/utils/validation/__tests__/htmlSanitization.unit.test.ts +0 -598
  1176. package/src/utils/validation/__tests__/sqlInjectionProtection.test.ts +0 -92
  1177. package/src/utils/validation/__tests__/validationUtils.test.ts +0 -72
  1178. package/src/utils/validation/index.ts +0 -73
  1179. /package/src/components/DataTable/{components/__tests__ → ui}/COVERAGE_NOTE.md +0 -0
  1180. /package/src/components/DataTable/utils/{__tests__/COVERAGE_NOTE.md → COVERAGE_NOTE.md} +0 -0
  1181. /package/src/providers/{__tests__/README.md → README.md} +0 -0
  1182. /package/src/types/{__tests__/README.md → README.md} +0 -0
@@ -0,0 +1,1250 @@
1
+ /**
2
+ * @file EventService Unit Tests
3
+ * @package @jmruthers/pace-core
4
+ * @module Services
5
+ * @since 0.1.0
6
+ *
7
+ * Unit tests for EventService class.
8
+ * Tests event management, selection, and persistence operations.
9
+ */
10
+
11
+ import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
12
+ import { EventService } from './EventService';
13
+ import { Event } from '../types/event';
14
+ import { assertOrganisationId } from '../types/core';
15
+
16
+ // Don't mock the logger - it now works in test mode
17
+ // We'll spy on the Logger class methods in beforeEach to verify calls
18
+ import { Logger } from '../utils/core/logger';
19
+
20
+ let mockLoggerFunctions: {
21
+ debug: ReturnType<typeof vi.spyOn>;
22
+ error: ReturnType<typeof vi.spyOn>;
23
+ warn: ReturnType<typeof vi.spyOn>;
24
+ info: ReturnType<typeof vi.spyOn>;
25
+ };
26
+
27
+ // Mock secureStorage - use vi.hoisted so methods are proper spies (same path as EventService imports)
28
+ const mockSetItem = vi.hoisted(() => vi.fn().mockResolvedValue(undefined));
29
+ const mockGetItem = vi.hoisted(() => vi.fn().mockResolvedValue(null));
30
+ const mockRemoveItem = vi.hoisted(() => vi.fn().mockResolvedValue(undefined));
31
+ vi.mock('../utils/security/secureStorage', () => ({
32
+ secureStorage: {
33
+ setItem: mockSetItem,
34
+ getItem: mockGetItem,
35
+ removeItem: mockRemoveItem,
36
+ },
37
+ }));
38
+
39
+ // Reference to mocked secureStorage for test assertions (matches vi.mock above)
40
+ const mockSecureStorage = {
41
+ setItem: mockSetItem,
42
+ getItem: mockGetItem,
43
+ removeItem: mockRemoveItem,
44
+ };
45
+
46
+ // Mock RBAC API (same path as EventService imports)
47
+ vi.mock('../rbac/api', async () => {
48
+ const actual = await vi.importActual('../rbac/api');
49
+ return {
50
+ ...actual,
51
+ isSuperAdmin: vi.fn().mockResolvedValue({ ok: true, data: false }),
52
+ };
53
+ });
54
+
55
+ // Mock Supabase client
56
+ const createMockSupabaseClient = () => ({
57
+ rpc: vi.fn(),
58
+ });
59
+
60
+ // Mock user and session
61
+ const mockUser = {
62
+ id: 'user-1',
63
+ email: 'test@example.com'
64
+ };
65
+
66
+ const mockSession = {
67
+ access_token: 'token',
68
+ user: mockUser
69
+ };
70
+
71
+ const mockOrganisation = {
72
+ id: 'org-1',
73
+ display_name: 'Test Organisation'
74
+ };
75
+
76
+ const mockSetSelectedEventId = vi.fn();
77
+
78
+ // Raw RPC response data (what comes from database)
79
+ const mockEventRpcData = {
80
+ event_id: 'event-1',
81
+ event_name: 'Test Event',
82
+ event_code: 'test-event',
83
+ event_date: '2025-01-01T00:00:00Z',
84
+ event_venue: 'Test Venue',
85
+ event_participants: 100,
86
+ event_colours: '#FF0000',
87
+ organisation_id: 'org-1',
88
+ is_visible: true
89
+ };
90
+
91
+ const mockEvent2RpcData = {
92
+ event_id: 'event-2',
93
+ event_name: 'Future Event',
94
+ event_code: 'future-event',
95
+ event_date: '2025-12-31T00:00:00Z',
96
+ event_venue: 'Future Venue',
97
+ event_participants: 200,
98
+ event_colours: '#00FF00',
99
+ organisation_id: 'org-1',
100
+ is_visible: true
101
+ };
102
+
103
+ // Transformed Event objects (what EventService returns after transformation)
104
+ const mockEvent: Event = {
105
+ id: 'event-1',
106
+ event_id: 'event-1',
107
+ event_name: 'Test Event',
108
+ event_code: 'test-event',
109
+ event_date: '2025-01-01T00:00:00Z',
110
+ event_venue: 'Test Venue',
111
+ event_participants: 100,
112
+ event_colours: '#FF0000',
113
+ event_logo: '',
114
+ organisation_id: assertOrganisationId('org-1'),
115
+ is_visible: true,
116
+ created_at: expect.any(String),
117
+ updated_at: expect.any(String)
118
+ };
119
+
120
+ const mockEvent2: Event = {
121
+ id: 'event-2',
122
+ event_id: 'event-2',
123
+ event_name: 'Future Event',
124
+ event_code: 'future-event',
125
+ event_date: '2025-12-31T00:00:00Z',
126
+ event_venue: 'Future Venue',
127
+ event_participants: 200,
128
+ event_colours: '#00FF00',
129
+ event_logo: '',
130
+ organisation_id: assertOrganisationId('org-1'),
131
+ is_visible: true,
132
+ created_at: expect.any(String),
133
+ updated_at: expect.any(String)
134
+ };
135
+
136
+ describe('EventService', () => {
137
+ let mockSupabase: ReturnType<typeof createMockSupabaseClient>;
138
+ let eventService: EventService;
139
+
140
+ beforeEach(() => {
141
+ // Spy on Logger methods to verify calls (logger now works in test mode)
142
+ mockLoggerFunctions = {
143
+ debug: vi.spyOn(Logger, 'debug'),
144
+ error: vi.spyOn(Logger, 'error'),
145
+ warn: vi.spyOn(Logger, 'warn'),
146
+ info: vi.spyOn(Logger, 'info'),
147
+ };
148
+
149
+ vi.clearAllMocks();
150
+ mockSupabase = createMockSupabaseClient();
151
+ eventService = new EventService(
152
+ mockSupabase as any,
153
+ mockUser,
154
+ mockSession,
155
+ 'test-app',
156
+ mockOrganisation,
157
+ mockSetSelectedEventId
158
+ );
159
+ });
160
+
161
+ afterEach(() => {
162
+ eventService.cleanup();
163
+ // Restore spies
164
+ mockLoggerFunctions.debug.mockRestore();
165
+ mockLoggerFunctions.error.mockRestore();
166
+ mockLoggerFunctions.warn.mockRestore();
167
+ mockLoggerFunctions.info.mockRestore();
168
+ vi.clearAllMocks();
169
+ // Clear localStorage
170
+ localStorage.clear();
171
+ sessionStorage.clear();
172
+ });
173
+
174
+ describe('Initialization', () => {
175
+ it('should initialize with default state', () => {
176
+ expect(eventService.getEvents()).toEqual([]);
177
+ expect(eventService.getSelectedEvent()).toBeNull();
178
+ expect(eventService.isLoading()).toBe(false);
179
+ expect(eventService.getError()).toBeNull();
180
+ });
181
+
182
+ it('should fetch events on initialization', async () => {
183
+ mockSupabase.rpc.mockResolvedValue({
184
+ data: [mockEventRpcData, mockEvent2RpcData],
185
+ error: null
186
+ });
187
+
188
+ await eventService.initialize();
189
+
190
+ // For org-required apps: uses selectedOrganisation.id
191
+ // For event-required apps: uses selectedEvent.organisation_id or null for super admins
192
+ expect(mockSupabase.rpc).toHaveBeenCalledWith('data_user_events_get', {
193
+ p_user_id: mockUser.id,
194
+ p_organisation_id: mockOrganisation.id, // Org-required app uses selectedOrganisation
195
+ p_app_name: 'test-app'
196
+ });
197
+
198
+ expect(eventService.getEvents()).toHaveLength(2);
199
+ expect(eventService.isLoading()).toBe(false);
200
+ });
201
+
202
+ it('should fetch events with null organisation for super admin', async () => {
203
+ // Skip this test if RBAC API is not properly mocked
204
+ // The RBAC API mock is set up at the module level, so we can't easily override it here
205
+ // This test verifies the super admin path exists, but the actual behavior depends on the mock setup
206
+ mockSupabase.rpc.mockResolvedValue({
207
+ data: [mockEventRpcData, mockEvent2RpcData],
208
+ error: null
209
+ });
210
+
211
+ await eventService.initialize();
212
+
213
+ // Verify RPC was called (super admin logic is tested in edge-cases file)
214
+ expect(mockSupabase.rpc).toHaveBeenCalled();
215
+ });
216
+
217
+ it('should use selectedEvent organisation_id when event is already selected', async () => {
218
+ mockSupabase.rpc.mockResolvedValue({
219
+ data: [mockEventRpcData],
220
+ error: null
221
+ });
222
+
223
+ // Set event first
224
+ eventService.setSelectedEvent(mockEvent);
225
+
226
+ // Now initialize (should use event's organisation)
227
+ await eventService.initialize();
228
+
229
+ expect(mockSupabase.rpc).toHaveBeenCalledWith('data_user_events_get', {
230
+ p_user_id: mockUser.id,
231
+ p_organisation_id: mockEvent.organisation_id,
232
+ p_app_name: 'test-app'
233
+ });
234
+ });
235
+
236
+ it('should sort events by date descending', async () => {
237
+ const oldEvent = {
238
+ ...mockEventRpcData,
239
+ event_id: 'event-old',
240
+ event_date: '2020-01-01T00:00:00Z'
241
+ };
242
+ const newEvent = {
243
+ ...mockEventRpcData,
244
+ event_id: 'event-new',
245
+ event_date: '2025-12-31T00:00:00Z'
246
+ };
247
+
248
+ mockSupabase.rpc.mockResolvedValue({
249
+ data: [oldEvent, newEvent],
250
+ error: null
251
+ });
252
+
253
+ await eventService.initialize();
254
+
255
+ const events = eventService.getEvents();
256
+ expect(events[0].event_id).toBe('event-new'); // Newest first
257
+ expect(events[1].event_id).toBe('event-old');
258
+ });
259
+
260
+ it('should handle events with null dates in sorting', async () => {
261
+ const eventWithDate = {
262
+ ...mockEventRpcData,
263
+ event_id: 'event-with-date',
264
+ event_date: '2025-01-01T00:00:00Z'
265
+ };
266
+ const eventWithoutDate = {
267
+ ...mockEventRpcData,
268
+ event_id: 'event-no-date',
269
+ event_date: null
270
+ };
271
+
272
+ mockSupabase.rpc.mockResolvedValue({
273
+ data: [eventWithoutDate, eventWithDate],
274
+ error: null
275
+ });
276
+
277
+ await eventService.initialize();
278
+
279
+ const events = eventService.getEvents();
280
+ // Events with dates should come first
281
+ expect(events[0].event_id).toBe('event-with-date');
282
+ expect(events[1].event_id).toBe('event-no-date');
283
+ });
284
+
285
+ it('should clear selected event if it no longer exists in events list', async () => {
286
+ mockSupabase.rpc.mockResolvedValue({
287
+ data: [mockEventRpcData],
288
+ error: null
289
+ });
290
+
291
+ await eventService.initialize();
292
+ eventService.setSelectedEvent(mockEvent);
293
+ expect(eventService.getSelectedEvent()?.event_id).toBe('event-1');
294
+
295
+ // Clear auto-selection flag to prevent auto-selection
296
+ (eventService as any).userClearedEventRef = true;
297
+ (eventService as any).hasAutoSelectedRef = false;
298
+
299
+ // Now fetch events without the selected event
300
+ mockSupabase.rpc.mockResolvedValue({
301
+ data: [mockEvent2RpcData], // Different event
302
+ error: null
303
+ });
304
+
305
+ await eventService.refreshEvents();
306
+
307
+ // Selected event should be cleared since it's not in the new list
308
+ // (unless auto-selection happens, which we prevented)
309
+ const selectedEvent = eventService.getSelectedEvent();
310
+ if (selectedEvent) {
311
+ // If auto-selection happened, it should be the new event
312
+ expect(selectedEvent.event_id).toBe('event-2');
313
+ } else {
314
+ // Otherwise, it should be null
315
+ expect(selectedEvent).toBeNull();
316
+ }
317
+ });
318
+
319
+ it('should handle missing dependencies gracefully', async () => {
320
+ const serviceWithoutUser = new EventService(
321
+ mockSupabase as any,
322
+ null,
323
+ null,
324
+ 'test-app',
325
+ null,
326
+ mockSetSelectedEventId
327
+ );
328
+
329
+ await serviceWithoutUser.initialize();
330
+
331
+ expect(serviceWithoutUser.getEvents()).toEqual([]);
332
+ expect(serviceWithoutUser.isLoading()).toBe(false);
333
+ });
334
+ });
335
+
336
+ describe('Event Operations', () => {
337
+ beforeEach(async () => {
338
+ mockSupabase.rpc.mockResolvedValue({
339
+ data: [mockEventRpcData, mockEvent2RpcData],
340
+ error: null
341
+ });
342
+
343
+ await eventService.initialize();
344
+ });
345
+
346
+ it('should set selected event', () => {
347
+ eventService.setSelectedEvent(mockEvent);
348
+
349
+ expect(eventService.getSelectedEvent()).toEqual(mockEvent);
350
+ expect(mockSetSelectedEventId).toHaveBeenCalledWith('event-1');
351
+ });
352
+
353
+ it('should clear selected event', () => {
354
+ eventService.setSelectedEvent(mockEvent);
355
+ expect(eventService.getSelectedEvent()).toEqual(mockEvent);
356
+
357
+ eventService.setSelectedEvent(null);
358
+
359
+ expect(eventService.getSelectedEvent()).toBeNull();
360
+ expect(mockSetSelectedEventId).toHaveBeenCalledWith(null);
361
+ });
362
+
363
+ it('should allow selecting event from any organisation (no validation)', () => {
364
+ // Clear any auto-selected event first
365
+ eventService.setSelectedEvent(null);
366
+
367
+ const eventFromDifferentOrg: Event = {
368
+ ...mockEvent,
369
+ organisation_id: 'org-2'
370
+ };
371
+
372
+ eventService.setSelectedEvent(eventFromDifferentOrg);
373
+
374
+ // Should allow selection - org validation removed (org derived from event for event-required apps)
375
+ expect(eventService.getSelectedEvent()).toEqual(eventFromDifferentOrg);
376
+ });
377
+
378
+ it('should refresh events', async () => {
379
+ // Clear the mock call count from the beforeEach initialization
380
+ vi.clearAllMocks();
381
+
382
+ const newEventRpcData = {
383
+ ...mockEventRpcData,
384
+ event_id: 'event-3',
385
+ event_name: 'New Event'
386
+ };
387
+ mockSupabase.rpc.mockResolvedValue({
388
+ data: [mockEventRpcData, mockEvent2RpcData, newEventRpcData],
389
+ error: null
390
+ });
391
+
392
+ await eventService.refreshEvents();
393
+
394
+ expect(eventService.getEvents()).toHaveLength(3);
395
+ expect(mockSupabase.rpc).toHaveBeenCalledTimes(1); // Only the refresh call
396
+ });
397
+ });
398
+
399
+ describe('Event Selection Helpers', () => {
400
+ beforeEach(async () => {
401
+ // Set up mock data before creating service
402
+ mockSupabase.rpc.mockResolvedValue({
403
+ data: [mockEventRpcData, mockEvent2RpcData],
404
+ error: null
405
+ });
406
+
407
+ // Create a fresh service instance with the mock data
408
+ const testEventService = new EventService(
409
+ mockSupabase as any,
410
+ mockUser,
411
+ mockSession,
412
+ 'test-app',
413
+ mockOrganisation,
414
+ mockSetSelectedEventId
415
+ );
416
+
417
+ await testEventService.initialize();
418
+
419
+ // Replace the main eventService with our test instance
420
+ eventService = testEventService;
421
+ });
422
+
423
+ it('should get next event by date', () => {
424
+ const nextEvent = eventService.getNextEventByDate();
425
+ expect(nextEvent).toEqual(mockEvent2); // Future event should be selected
426
+ });
427
+
428
+ it('should return most recent past event when no future events', async () => {
429
+ const pastEvent1RpcData = {
430
+ ...mockEventRpcData,
431
+ event_id: 'event-past-1',
432
+ event_date: '2020-01-01T00:00:00Z'
433
+ };
434
+ const pastEvent2RpcData = {
435
+ ...mockEventRpcData,
436
+ event_id: 'event-past-2',
437
+ event_date: '2021-06-15T00:00:00Z' // More recent past event
438
+ };
439
+
440
+ mockSupabase.rpc.mockResolvedValue({
441
+ data: [pastEvent1RpcData, pastEvent2RpcData],
442
+ error: null
443
+ });
444
+
445
+ const service = new EventService(
446
+ mockSupabase as any,
447
+ mockUser,
448
+ mockSession,
449
+ 'test-app',
450
+ mockOrganisation,
451
+ mockSetSelectedEventId
452
+ );
453
+
454
+ await service.initialize();
455
+
456
+ const nextEvent = service.getNextEventByDate();
457
+ // Should return the most recent past event (pastEvent2)
458
+ expect(nextEvent).not.toBeNull();
459
+ expect(nextEvent?.event_id).toBe('event-past-2');
460
+ });
461
+
462
+ it('should persist event selection', async () => {
463
+ await eventService.persistEventSelection('event-1');
464
+
465
+ expect(mockSecureStorage.setItem).toHaveBeenCalledWith(
466
+ expect.stringContaining('pace-core-selected-event'),
467
+ 'event-1',
468
+ { encrypt: true }
469
+ );
470
+ });
471
+
472
+ it('should clear event selection', async () => {
473
+ eventService.setSelectedEvent(mockEvent);
474
+ await eventService.clearEventSelection();
475
+
476
+ expect(mockSecureStorage.removeItem).toHaveBeenCalledWith(
477
+ expect.stringContaining('pace-core-selected-event')
478
+ );
479
+ expect(eventService.getSelectedEvent()).toBeNull();
480
+ });
481
+
482
+ it('should load persisted event', async () => {
483
+ // Set up persisted event in secureStorage
484
+ mockSecureStorage.getItem.mockResolvedValueOnce('event-1');
485
+
486
+ const service = new EventService(
487
+ mockSupabase as any,
488
+ mockUser,
489
+ mockSession,
490
+ 'test-app',
491
+ mockOrganisation,
492
+ mockSetSelectedEventId
493
+ );
494
+
495
+ mockSupabase.rpc.mockResolvedValue({
496
+ data: [mockEventRpcData, mockEvent2RpcData],
497
+ error: null
498
+ });
499
+
500
+ // Initialize will auto-select an event (mockEvent2), but loadPersistedEvent should override it
501
+ await service.initialize();
502
+
503
+ // Restore the persisted event ID in secureStorage before calling loadPersistedEvent
504
+ mockSecureStorage.getItem.mockResolvedValueOnce('event-1');
505
+
506
+ // Now loadPersistedEvent should find and load the persisted event
507
+ const loaded = await service.loadPersistedEvent(service.getEvents());
508
+
509
+ expect(loaded).toBe(true);
510
+ expect(service.getSelectedEvent()).toEqual(mockEvent);
511
+ expect(service.getSelectedEvent()?.event_id).toBe('event-1');
512
+ });
513
+
514
+ it('should handle invalid persisted event', async () => {
515
+ // Set up invalid persisted event in secureStorage
516
+ mockSecureStorage.getItem.mockResolvedValueOnce('invalid-event');
517
+
518
+ const service = new EventService(
519
+ mockSupabase as any,
520
+ mockUser,
521
+ mockSession,
522
+ 'test-app',
523
+ mockOrganisation,
524
+ mockSetSelectedEventId
525
+ );
526
+
527
+ mockSupabase.rpc.mockResolvedValue({
528
+ data: [mockEventRpcData, mockEvent2RpcData],
529
+ error: null
530
+ });
531
+
532
+ await service.initialize();
533
+
534
+ // The service should have auto-selected an event despite the invalid persisted event
535
+ // because the persisted event was invalid and userClearedEventRef is false
536
+ expect(service.getSelectedEvent()).not.toBeNull();
537
+
538
+ // The auto-selected event should be persisted (replacing the invalid one)
539
+ expect(mockSecureStorage.setItem).toHaveBeenCalledWith(
540
+ expect.stringContaining('pace-core-selected-event'),
541
+ 'event-2',
542
+ { encrypt: true }
543
+ );
544
+ });
545
+ });
546
+
547
+ describe('State Management', () => {
548
+ it('should notify subscribers when state changes', async () => {
549
+ mockSupabase.rpc.mockResolvedValue({
550
+ data: [mockEventRpcData],
551
+ error: null
552
+ });
553
+
554
+ const subscriber = vi.fn();
555
+ const unsubscribe = eventService.subscribe(subscriber);
556
+
557
+ await eventService.initialize();
558
+
559
+ expect(subscriber).toHaveBeenCalled();
560
+
561
+ unsubscribe();
562
+ });
563
+
564
+ it('should cleanup subscriptions on cleanup', () => {
565
+ const subscriber = vi.fn();
566
+ eventService.subscribe(subscriber);
567
+
568
+ eventService.cleanup();
569
+
570
+ // After cleanup, new state changes shouldn't notify subscribers
571
+ eventService.setSelectedEvent(mockEvent);
572
+
573
+ expect(subscriber).not.toHaveBeenCalled();
574
+ });
575
+ });
576
+
577
+ describe('Error Handling', () => {
578
+ it('should handle RPC errors gracefully', async () => {
579
+ mockSupabase.rpc.mockResolvedValue({
580
+ data: null,
581
+ error: { message: 'RPC error' }
582
+ });
583
+
584
+ await eventService.initialize();
585
+
586
+ expect(eventService.getError()).toBeDefined();
587
+ expect(eventService.getError()?.message).toBe('RPC error');
588
+ expect(eventService.getEvents()).toEqual([]);
589
+ });
590
+
591
+ it('should handle network errors', async () => {
592
+ mockSupabase.rpc.mockRejectedValue(new Error('Network error'));
593
+
594
+ await eventService.initialize();
595
+
596
+ expect(eventService.getError()).toBeDefined();
597
+ expect(eventService.getError()?.message).toBe('Network error');
598
+ });
599
+
600
+ it('should handle missing event data gracefully', async () => {
601
+ mockSupabase.rpc.mockResolvedValue({
602
+ data: null,
603
+ error: null
604
+ });
605
+
606
+ await eventService.initialize();
607
+
608
+ expect(eventService.getEvents()).toEqual([]);
609
+ expect(eventService.getError()).toBeNull();
610
+ });
611
+ });
612
+
613
+ describe('Auto-selection', () => {
614
+ it('should auto-select next event when no event is selected', async () => {
615
+ // Set up mock data before creating service
616
+ mockSupabase.rpc.mockResolvedValue({
617
+ data: [mockEventRpcData, mockEvent2RpcData],
618
+ error: null
619
+ });
620
+
621
+ // Create a fresh service instance with the mock data
622
+ const testEventService = new EventService(
623
+ mockSupabase as any,
624
+ mockUser,
625
+ mockSession,
626
+ 'test-app',
627
+ mockOrganisation,
628
+ mockSetSelectedEventId
629
+ );
630
+
631
+ await testEventService.initialize();
632
+
633
+ // Should auto-select the future event
634
+ expect(testEventService.getSelectedEvent()).toEqual(mockEvent2);
635
+ expect(mockSetSelectedEventId).toHaveBeenCalledWith('event-2');
636
+ });
637
+
638
+ it('should not auto-select when user has cleared event', async () => {
639
+ // Set up mock data before calling initialize
640
+ mockSupabase.rpc.mockResolvedValue({
641
+ data: [mockEventRpcData, mockEvent2RpcData],
642
+ error: null
643
+ });
644
+
645
+ await eventService.initialize();
646
+
647
+ // Clear the event
648
+ eventService.setSelectedEvent(null);
649
+
650
+ // Refresh events
651
+ mockSupabase.rpc.mockResolvedValue({
652
+ data: [mockEventRpcData, mockEvent2RpcData],
653
+ error: null
654
+ });
655
+
656
+ await eventService.refreshEvents();
657
+
658
+ // Should not auto-select after user cleared
659
+ expect(eventService.getSelectedEvent()).toBeNull();
660
+ });
661
+ });
662
+
663
+ describe('Persistence', () => {
664
+ it('should persist event selection across sessions', async () => {
665
+ mockSupabase.rpc.mockResolvedValue({
666
+ data: [mockEventRpcData, mockEvent2RpcData],
667
+ error: null
668
+ });
669
+
670
+ await eventService.initialize();
671
+
672
+ eventService.setSelectedEvent(mockEvent);
673
+
674
+ // Check persistence - wait for async persistEventSelection call
675
+ await new Promise(resolve => setTimeout(resolve, 10));
676
+ expect(mockSecureStorage.setItem).toHaveBeenCalledWith(
677
+ expect.stringContaining('pace-core-selected-event'),
678
+ 'event-1',
679
+ { encrypt: true }
680
+ );
681
+ });
682
+
683
+ it('should restore persisted event on initialization', async () => {
684
+ // Set up persisted event in secureStorage
685
+ mockSecureStorage.getItem.mockResolvedValue('event-1');
686
+
687
+ mockSupabase.rpc.mockResolvedValue({
688
+ data: [mockEventRpcData, mockEvent2RpcData],
689
+ error: null
690
+ });
691
+
692
+ const service = new EventService(
693
+ mockSupabase as any,
694
+ mockUser,
695
+ mockSession,
696
+ 'test-app',
697
+ mockOrganisation,
698
+ mockSetSelectedEventId
699
+ );
700
+
701
+ await service.initialize();
702
+
703
+ // After initialize(), fetchEvents(true) is called which skips loading persisted events
704
+ // but still auto-selects, which may have overwritten the storage
705
+ // Restore the persisted event ID in secureStorage and then load it
706
+ mockSecureStorage.getItem.mockResolvedValueOnce('event-1');
707
+
708
+ const loaded = await service.loadPersistedEvent(service.getEvents());
709
+
710
+ expect(loaded).toBe(true);
711
+ expect(service.getSelectedEvent()).toEqual(mockEvent);
712
+ expect(service.getSelectedEvent()?.event_id).toBe('event-1');
713
+ });
714
+ });
715
+
716
+ describe('Dependency Updates', () => {
717
+ it('should update dependencies when organisation changes', async () => {
718
+ const newOrganisation = { id: 'org-2', display_name: 'New Organisation' };
719
+
720
+ await eventService.updateDependencies(
721
+ mockSupabase as any,
722
+ mockUser,
723
+ mockSession,
724
+ 'test-app',
725
+ newOrganisation,
726
+ mockSetSelectedEventId
727
+ );
728
+
729
+ // Should reset initialization when organisation changes
730
+ expect(eventService.getEvents()).toBeDefined();
731
+ });
732
+
733
+ it('should preserve event when organisation first becomes available', async () => {
734
+ mockSupabase.rpc.mockResolvedValue({
735
+ data: [mockEventRpcData],
736
+ error: null
737
+ });
738
+
739
+ // Start without organisation
740
+ const serviceWithoutOrg = new EventService(
741
+ mockSupabase as any,
742
+ mockUser,
743
+ mockSession,
744
+ 'test-app',
745
+ null,
746
+ mockSetSelectedEventId
747
+ );
748
+
749
+ await serviceWithoutOrg.initialize();
750
+ serviceWithoutOrg.setSelectedEvent(mockEvent);
751
+
752
+ // Now set organisation (first time)
753
+ await serviceWithoutOrg.updateDependencies(
754
+ mockSupabase as any,
755
+ mockUser,
756
+ mockSession,
757
+ 'test-app',
758
+ mockOrganisation,
759
+ mockSetSelectedEventId
760
+ );
761
+
762
+ // Event should be preserved when org is first set
763
+ expect(serviceWithoutOrg.getSelectedEvent()).toEqual(mockEvent);
764
+
765
+ serviceWithoutOrg.cleanup();
766
+ });
767
+
768
+ it('should clear events when switching between different organisations', async () => {
769
+ mockSupabase.rpc.mockResolvedValue({
770
+ data: [mockEventRpcData],
771
+ error: null
772
+ });
773
+
774
+ await eventService.initialize();
775
+ eventService.setSelectedEvent(mockEvent);
776
+
777
+ const newOrganisation = { id: 'org-2', display_name: 'New Organisation' };
778
+
779
+ await eventService.updateDependencies(
780
+ mockSupabase as any,
781
+ mockUser,
782
+ mockSession,
783
+ 'test-app',
784
+ newOrganisation,
785
+ mockSetSelectedEventId
786
+ );
787
+
788
+ // Events should be cleared when switching organisations
789
+ expect(eventService.getEvents()).toEqual([]);
790
+ expect(eventService.getSelectedEvent()).toBeNull();
791
+ });
792
+
793
+ it('should clear events when switching to different organisation', async () => {
794
+ mockSupabase.rpc.mockResolvedValue({
795
+ data: [mockEventRpcData],
796
+ error: null
797
+ });
798
+
799
+ await eventService.initialize();
800
+ eventService.setSelectedEvent(mockEvent);
801
+
802
+ const newOrganisation = { id: 'org-2', display_name: 'New Organisation' };
803
+
804
+ await eventService.updateDependencies(
805
+ mockSupabase as any,
806
+ mockUser,
807
+ mockSession,
808
+ 'test-app',
809
+ newOrganisation,
810
+ mockSetSelectedEventId
811
+ );
812
+
813
+ // Events should be cleared when switching organisations
814
+ expect(eventService.getEvents()).toEqual([]);
815
+ expect(eventService.getSelectedEvent()).toBeNull();
816
+ });
817
+
818
+ it('should clear event selection when user changes', async () => {
819
+ mockSupabase.rpc.mockResolvedValue({
820
+ data: [mockEventRpcData],
821
+ error: null
822
+ });
823
+
824
+ await eventService.initialize();
825
+ eventService.setSelectedEvent(mockEvent);
826
+
827
+ const newUser = { id: 'user-2', email: 'new@example.com' };
828
+ const newSession = { access_token: 'new-token', user: newUser };
829
+
830
+ await eventService.updateDependencies(
831
+ mockSupabase as any,
832
+ newUser,
833
+ newSession,
834
+ 'test-app',
835
+ mockOrganisation,
836
+ mockSetSelectedEventId
837
+ );
838
+
839
+ // Event selection should be cleared for previous user
840
+ expect(mockSecureStorage.removeItem).toHaveBeenCalled();
841
+ });
842
+
843
+ it('should clear event selection when user logs out', async () => {
844
+ mockSupabase.rpc.mockResolvedValue({
845
+ data: [mockEventRpcData],
846
+ error: null
847
+ });
848
+
849
+ await eventService.initialize();
850
+ eventService.setSelectedEvent(mockEvent);
851
+
852
+ await eventService.updateDependencies(
853
+ mockSupabase as any,
854
+ null,
855
+ null,
856
+ 'test-app',
857
+ mockOrganisation,
858
+ mockSetSelectedEventId
859
+ );
860
+
861
+ // Event should be cleared on logout
862
+ expect(eventService.getSelectedEvent()).toBeNull();
863
+ expect(mockSetSelectedEventId).toHaveBeenCalledWith(null);
864
+ });
865
+
866
+ it('should reset initialization flags when user changes', async () => {
867
+ mockSupabase.rpc.mockResolvedValue({
868
+ data: [mockEventRpcData],
869
+ error: null
870
+ });
871
+
872
+ await eventService.initialize();
873
+
874
+ const newUser = { id: 'user-2', email: 'new@example.com' };
875
+ const newSession = { access_token: 'new-token', user: newUser };
876
+
877
+ await eventService.updateDependencies(
878
+ mockSupabase as any,
879
+ newUser,
880
+ newSession,
881
+ 'test-app',
882
+ mockOrganisation,
883
+ mockSetSelectedEventId
884
+ );
885
+
886
+ // Should allow re-initialization
887
+ expect((eventService as any).isInitializedRef).toBe(false);
888
+ expect((eventService as any).isFetchingRef).toBe(false);
889
+ });
890
+
891
+ it('should reset userClearedEventRef when new user logs in', async () => {
892
+ mockSupabase.rpc.mockResolvedValue({
893
+ data: [mockEventRpcData],
894
+ error: null
895
+ });
896
+
897
+ await eventService.initialize();
898
+ eventService.setSelectedEvent(null); // User clears event
899
+
900
+ expect((eventService as any).userClearedEventRef).toBe(true);
901
+
902
+ const newUser = { id: 'user-2', email: 'new@example.com' };
903
+ const newSession = { access_token: 'new-token', user: newUser };
904
+
905
+ await eventService.updateDependencies(
906
+ mockSupabase as any,
907
+ newUser,
908
+ newSession,
909
+ 'test-app',
910
+ mockOrganisation,
911
+ mockSetSelectedEventId
912
+ );
913
+
914
+ // Should reset flag for new user
915
+ expect((eventService as any).userClearedEventRef).toBe(false);
916
+ });
917
+ });
918
+
919
+ describe('Event Persistence', () => {
920
+ it('should restore persisted event', async () => {
921
+ mockSecureStorage.getItem.mockResolvedValue('event-1');
922
+
923
+ mockSupabase.rpc.mockResolvedValue({
924
+ data: [mockEventRpcData, mockEvent2RpcData],
925
+ error: null
926
+ });
927
+
928
+ const service = new EventService(
929
+ mockSupabase as any,
930
+ mockUser,
931
+ mockSession,
932
+ 'test-app',
933
+ mockOrganisation,
934
+ mockSetSelectedEventId
935
+ );
936
+
937
+ await service.initialize();
938
+
939
+ const restored = await service.restorePersistedEvent();
940
+
941
+ expect(restored).toBe(true);
942
+ expect(service.getSelectedEvent()).toEqual(mockEvent);
943
+ });
944
+
945
+ it('should return false when restoring persisted event if events not loaded', async () => {
946
+ const service = new EventService(
947
+ mockSupabase as any,
948
+ mockUser,
949
+ mockSession,
950
+ 'test-app',
951
+ mockOrganisation,
952
+ mockSetSelectedEventId
953
+ );
954
+
955
+ // Don't initialize, so events are empty
956
+ const restored = await service.restorePersistedEvent();
957
+
958
+ expect(restored).toBe(false);
959
+ });
960
+
961
+ it('should clear event selection for specific user', async () => {
962
+ await eventService.clearEventSelectionForUser('user-1');
963
+
964
+ expect(mockSecureStorage.removeItem).toHaveBeenCalledWith(
965
+ expect.stringContaining('pace-core-selected-event-user-1')
966
+ );
967
+ });
968
+
969
+ it('should handle clearing event selection for null user', async () => {
970
+ await eventService.clearEventSelectionForUser(null);
971
+
972
+ // Should not throw error
973
+ expect(mockSecureStorage.removeItem).not.toHaveBeenCalled();
974
+ });
975
+ });
976
+
977
+ describe('Event Colours Parsing', () => {
978
+ it('should parse event colours from string JSON', () => {
979
+ const eventWithStringColours: Event = {
980
+ ...mockEvent,
981
+ event_colours: JSON.stringify({
982
+ main: { '500': '#FF0000' },
983
+ sec: { '500': '#00FF00' },
984
+ acc: { '500': '#0000FF' }
985
+ })
986
+ };
987
+
988
+ // The parseAndNormalizeEventColours is private, but we can test it indirectly
989
+ // by checking if setSelectedEvent handles it correctly
990
+ eventService.setSelectedEvent(eventWithStringColours);
991
+
992
+ expect(eventService.getSelectedEvent()).toEqual(eventWithStringColours);
993
+ });
994
+
995
+ it('should parse event colours with ev-* keys', () => {
996
+ const eventWithEvKeys: Event = {
997
+ ...mockEvent,
998
+ event_colours: {
999
+ 'ev-main': { '500': '#FF0000' },
1000
+ 'ev-sec': { '500': '#00FF00' },
1001
+ 'ev-acc': { '500': '#0000FF' }
1002
+ }
1003
+ };
1004
+
1005
+ eventService.setSelectedEvent(eventWithEvKeys);
1006
+
1007
+ expect(eventService.getSelectedEvent()).toEqual(eventWithEvKeys);
1008
+ });
1009
+
1010
+ it('should handle invalid event colours gracefully', () => {
1011
+ const eventWithInvalidColours: Event = {
1012
+ ...mockEvent,
1013
+ event_colours: 'invalid-json'
1014
+ };
1015
+
1016
+ // Should not throw error
1017
+ eventService.setSelectedEvent(eventWithInvalidColours);
1018
+
1019
+ expect(eventService.getSelectedEvent()).toEqual(eventWithInvalidColours);
1020
+ });
1021
+
1022
+ it('should handle null event colours', () => {
1023
+ const eventWithNullColours: Event = {
1024
+ ...mockEvent,
1025
+ event_colours: null as any
1026
+ };
1027
+
1028
+ eventService.setSelectedEvent(eventWithNullColours);
1029
+
1030
+ expect(eventService.getSelectedEvent()).toEqual(eventWithNullColours);
1031
+ });
1032
+ });
1033
+
1034
+ describe('Next Event Selection', () => {
1035
+ it('should return null when no events provided', () => {
1036
+ const nextEvent = eventService.getNextEventByDate([]);
1037
+
1038
+ expect(nextEvent).toBeNull();
1039
+ });
1040
+
1041
+ it('should return most recent past event when all events are in the past', () => {
1042
+ const pastEvent1: Event = {
1043
+ ...mockEvent,
1044
+ event_id: 'event-past-1',
1045
+ event_date: '2020-01-01T00:00:00Z'
1046
+ };
1047
+ const pastEvent2: Event = {
1048
+ ...mockEvent,
1049
+ event_id: 'event-past-2',
1050
+ event_date: '2022-03-20T00:00:00Z' // More recent past event
1051
+ };
1052
+
1053
+ const nextEvent = eventService.getNextEventByDate([pastEvent1, pastEvent2]);
1054
+
1055
+ // Should return the most recent past event (pastEvent2)
1056
+ expect(nextEvent).not.toBeNull();
1057
+ expect(nextEvent?.event_id).toBe('event-past-2');
1058
+ });
1059
+
1060
+ it('should select event on today\'s date', () => {
1061
+ const today = new Date();
1062
+ const todayEvent: Event = {
1063
+ ...mockEvent,
1064
+ event_date: today.toISOString()
1065
+ };
1066
+
1067
+ const nextEvent = eventService.getNextEventByDate([todayEvent]);
1068
+
1069
+ expect(nextEvent).toEqual(todayEvent);
1070
+ });
1071
+
1072
+ it('should select earliest future event when multiple future events exist', () => {
1073
+ // Create events with dates far in the future to ensure they're both considered future events
1074
+ const today = new Date();
1075
+ const futureDate1 = new Date(today.getTime() + 200 * 24 * 60 * 60 * 1000); // 200 days from now
1076
+ const futureDate2 = new Date(today.getTime() + 100 * 24 * 60 * 60 * 1000); // 100 days from now (earlier)
1077
+
1078
+ const futureEvent1: Event = {
1079
+ id: 'event-1',
1080
+ event_id: 'event-1',
1081
+ event_name: 'Later Event',
1082
+ event_date: futureDate1.toISOString(),
1083
+ event_venue: 'Venue',
1084
+ event_participants: 100,
1085
+ event_colours: '#FF0000',
1086
+ event_logo: '',
1087
+ organisation_id: assertOrganisationId('org-1'),
1088
+ is_visible: true,
1089
+ name: 'Later Event',
1090
+ start_date: futureDate1.toISOString()
1091
+ };
1092
+
1093
+ const futureEvent2: Event = {
1094
+ id: 'event-2',
1095
+ event_id: 'event-2',
1096
+ event_name: 'Earlier Event',
1097
+ event_date: futureDate2.toISOString(),
1098
+ event_venue: 'Venue',
1099
+ event_participants: 100,
1100
+ event_colours: '#00FF00',
1101
+ event_logo: '',
1102
+ organisation_id: assertOrganisationId('org-1'),
1103
+ is_visible: true,
1104
+ name: 'Earlier Event',
1105
+ start_date: futureDate2.toISOString()
1106
+ };
1107
+
1108
+ const nextEvent = eventService.getNextEventByDate([futureEvent1, futureEvent2]);
1109
+
1110
+ // Should select the earlier event (event-2, 100 days from now)
1111
+ expect(nextEvent?.event_id).toBe('event-2');
1112
+ expect(nextEvent?.event_date).toBe(futureDate2.toISOString());
1113
+ });
1114
+
1115
+ it('should prefer future events over past events when both exist', () => {
1116
+ const today = new Date();
1117
+ const pastDate = new Date(today.getTime() - 30 * 24 * 60 * 60 * 1000); // 30 days ago
1118
+ const futureDate = new Date(today.getTime() + 30 * 24 * 60 * 60 * 1000); // 30 days from now
1119
+
1120
+ const pastEvent: Event = {
1121
+ ...mockEvent,
1122
+ event_id: 'event-past',
1123
+ event_date: pastDate.toISOString()
1124
+ };
1125
+
1126
+ const futureEvent: Event = {
1127
+ ...mockEvent,
1128
+ event_id: 'event-future',
1129
+ event_date: futureDate.toISOString()
1130
+ };
1131
+
1132
+ const nextEvent = eventService.getNextEventByDate([pastEvent, futureEvent]);
1133
+
1134
+ // Should prefer future event even if past event is more recent
1135
+ expect(nextEvent).not.toBeNull();
1136
+ expect(nextEvent?.event_id).toBe('event-future');
1137
+ });
1138
+
1139
+ it('should filter out events without dates', () => {
1140
+ const eventWithoutDate: Event = {
1141
+ ...mockEvent,
1142
+ event_date: null as any
1143
+ };
1144
+
1145
+ const nextEvent = eventService.getNextEventByDate([eventWithoutDate]);
1146
+
1147
+ expect(nextEvent).toBeNull();
1148
+ });
1149
+ });
1150
+
1151
+ describe('Auto-selection Logic', () => {
1152
+ it('should auto-select next event when no persisted event exists', async () => {
1153
+ mockSecureStorage.getItem.mockResolvedValue(null);
1154
+
1155
+ mockSupabase.rpc.mockResolvedValue({
1156
+ data: [mockEventRpcData, mockEvent2RpcData],
1157
+ error: null
1158
+ });
1159
+
1160
+ const service = new EventService(
1161
+ mockSupabase as any,
1162
+ mockUser,
1163
+ mockSession,
1164
+ 'test-app',
1165
+ mockOrganisation,
1166
+ mockSetSelectedEventId
1167
+ );
1168
+
1169
+ await service.initialize();
1170
+
1171
+ // Should auto-select the future event
1172
+ expect(service.getSelectedEvent()).not.toBeNull();
1173
+ });
1174
+
1175
+ it('should not auto-select when user has explicitly cleared event', async () => {
1176
+ mockSupabase.rpc.mockResolvedValue({
1177
+ data: [mockEventRpcData, mockEvent2RpcData],
1178
+ error: null
1179
+ });
1180
+
1181
+ await eventService.initialize();
1182
+
1183
+ // Clear the event (this sets userClearedEventRef)
1184
+ eventService.setSelectedEvent(null);
1185
+
1186
+ // Refresh events
1187
+ await eventService.refreshEvents();
1188
+
1189
+ // Should not auto-select after user cleared
1190
+ expect(eventService.getSelectedEvent()).toBeNull();
1191
+ });
1192
+ });
1193
+
1194
+ describe('Storage Cleanup', () => {
1195
+ it('should clean up old storage keys on initialization', async () => {
1196
+ // Set old storage keys
1197
+ sessionStorage.setItem('pace-core-selected-event', 'old-event');
1198
+ localStorage.setItem('pace-core-selected-event', 'old-event');
1199
+ localStorage.setItem('_sec_pace-core-selected-event', 'old-encrypted');
1200
+
1201
+ mockSupabase.rpc.mockResolvedValue({
1202
+ data: [mockEventRpcData],
1203
+ error: null
1204
+ });
1205
+
1206
+ await eventService.initialize();
1207
+
1208
+ // Old keys should be removed
1209
+ expect(sessionStorage.getItem('pace-core-selected-event')).toBeNull();
1210
+ expect(localStorage.getItem('pace-core-selected-event')).toBeNull();
1211
+ expect(localStorage.getItem('_sec_pace-core-selected-event')).toBeNull();
1212
+ });
1213
+ });
1214
+
1215
+ describe('Event Selection', () => {
1216
+ it('should allow selecting event without organisation validation', () => {
1217
+ vi.clearAllMocks();
1218
+
1219
+ const eventFromDifferentOrg: Event = {
1220
+ ...mockEvent,
1221
+ organisation_id: 'org-2'
1222
+ };
1223
+
1224
+ // Should not throw error - validation removed (org derived from event for event-required apps)
1225
+ eventService.setSelectedEvent(eventFromDifferentOrg);
1226
+
1227
+ // Event should be selected successfully
1228
+ expect(eventService.getSelectedEvent()).toEqual(eventFromDifferentOrg);
1229
+ // No error should be logged
1230
+ expect(mockLoggerFunctions.error).not.toHaveBeenCalled();
1231
+ });
1232
+
1233
+ it('should allow selecting event when organisation is null (event-required apps)', () => {
1234
+ const serviceWithoutOrg = new EventService(
1235
+ mockSupabase as any,
1236
+ mockUser,
1237
+ mockSession,
1238
+ 'test-app',
1239
+ null,
1240
+ mockSetSelectedEventId
1241
+ );
1242
+
1243
+ // Should not throw error - org is derived from event for event-required apps
1244
+ serviceWithoutOrg.setSelectedEvent(mockEvent);
1245
+
1246
+ // Event should be selected successfully
1247
+ expect(serviceWithoutOrg.getSelectedEvent()).toEqual(mockEvent);
1248
+ });
1249
+ });
1250
+ });