@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
@@ -11,7 +11,7 @@
11
11
  import React from 'react';
12
12
  import { screen, waitFor } from '@testing-library/react';
13
13
  import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
14
- import { ProtectedRoute, ProtectedRouteProps } from './ProtectedRoute';
14
+ import { ProtectedRoute } from './ProtectedRoute';
15
15
  import { renderWithProviders } from '../../__tests__/helpers/test-utils';
16
16
 
17
17
  // Mock React Router components
@@ -65,14 +65,20 @@ vi.mock('../Alert/Alert', () => ({
65
65
  ),
66
66
  }));
67
67
 
68
+ vi.mock('../../hooks/usePreventTabReload', () => ({
69
+ usePreventTabReload: vi.fn(),
70
+ }));
71
+
68
72
  import { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';
69
73
  import { useSessionRestoration } from '../../hooks/useSessionRestoration';
70
74
  import { useEvents } from '../../hooks/useEvents';
75
+ import { usePreventTabReload } from '../../hooks/usePreventTabReload';
71
76
 
72
77
  // Type-safe mock implementations
73
78
  const mockUseUnifiedAuth = vi.mocked(useUnifiedAuth);
74
79
  const mockUseSessionRestoration = vi.mocked(useSessionRestoration);
75
80
  const mockUseEvents = vi.mocked(useEvents);
81
+ const mockUsePreventTabReload = vi.mocked(usePreventTabReload);
76
82
 
77
83
  // Suppress console methods in tests
78
84
  const originalConsoleDebug = console.debug;
@@ -122,6 +128,7 @@ describe('ProtectedRoute Component', () => {
122
128
  mockUseUnifiedAuth.mockReturnValue(defaultAuthState);
123
129
  mockUseSessionRestoration.mockReturnValue(defaultSessionState);
124
130
  mockUseEvents.mockReturnValue(defaultEventsState);
131
+ mockUsePreventTabReload.mockImplementation(() => {});
125
132
  });
126
133
 
127
134
  afterEach(() => {
@@ -144,7 +151,6 @@ describe('ProtectedRoute Component', () => {
144
151
  });
145
152
 
146
153
  it('renders outlet when events exist but none selected (allows event selector visibility)', async () => {
147
- const consoleDebugSpy = vi.spyOn(console, 'debug').mockImplementation(() => {});
148
154
 
149
155
  mockUseEvents.mockReturnValue({
150
156
  selectedEvent: null,
@@ -380,6 +386,26 @@ describe('ProtectedRoute Component', () => {
380
386
  expect(screen.queryByTestId('loading-spinner')).not.toBeInTheDocument();
381
387
  expect(screen.getByTestId('navigate')).toHaveAttribute('data-to', '/login');
382
388
  });
389
+
390
+ it('skips restoration loader when a restoration error is present', () => {
391
+ mockUseUnifiedAuth.mockReturnValue({
392
+ isAuthenticated: false,
393
+ authLoading: false,
394
+ isLoading: false,
395
+ });
396
+
397
+ mockUseSessionRestoration.mockReturnValue({
398
+ isRestoring: true,
399
+ restorationComplete: false,
400
+ restorationError: new Error('Restore failed'),
401
+ hasTimedOut: false,
402
+ });
403
+
404
+ renderWithProviders(<ProtectedRoute />);
405
+
406
+ expect(screen.queryByTestId('session-restoration-loader')).not.toBeInTheDocument();
407
+ expect(screen.getByTestId('navigate')).toHaveAttribute('data-to', '/login');
408
+ });
383
409
  });
384
410
 
385
411
  describe('Event Management', () => {
@@ -452,7 +478,6 @@ describe('ProtectedRoute Component', () => {
452
478
  isLoading: false,
453
479
  });
454
480
 
455
- const consoleDebugSpy = vi.spyOn(console, 'debug').mockImplementation(() => {});
456
481
 
457
482
  renderWithProviders(<ProtectedRoute requireEvent={true} />);
458
483
 
@@ -697,5 +722,1172 @@ describe('ProtectedRoute Component', () => {
697
722
  );
698
723
  });
699
724
  });
700
- });
701
725
 
726
+ describe('Tab Visibility and Grace Period', () => {
727
+ beforeEach(() => {
728
+ // Mock document.hidden
729
+ Object.defineProperty(document, 'hidden', {
730
+ writable: true,
731
+ configurable: true,
732
+ value: false,
733
+ });
734
+ });
735
+
736
+ it('calls usePreventTabReload with correct parameters', () => {
737
+ renderWithProviders(<ProtectedRoute />);
738
+
739
+ expect(mockUsePreventTabReload).toHaveBeenCalledWith({
740
+ enabled: true,
741
+ gracePeriodMs: 2000,
742
+ });
743
+ });
744
+
745
+ it('prevents redirect during grace period when tab becomes visible', async () => {
746
+ // Start with authenticated user
747
+ mockUseUnifiedAuth.mockReturnValue({
748
+ isAuthenticated: true,
749
+ authLoading: false,
750
+ isLoading: false,
751
+ });
752
+
753
+ const { rerender } = renderWithProviders(
754
+ <ProtectedRoute />
755
+ );
756
+
757
+ expect(screen.getByTestId('outlet')).toBeInTheDocument();
758
+
759
+ // Simulate tab becoming hidden (user switches away)
760
+ Object.defineProperty(document, 'hidden', {
761
+ writable: true,
762
+ configurable: true,
763
+ value: true,
764
+ });
765
+ document.dispatchEvent(new Event('visibilitychange'));
766
+
767
+ // Simulate user becoming unauthenticated while tab is hidden, but still loading (session refresh)
768
+ mockUseUnifiedAuth.mockReturnValue({
769
+ isAuthenticated: false,
770
+ authLoading: false,
771
+ isLoading: true, // Still loading - session might be refreshing
772
+ });
773
+
774
+ // Simulate tab becoming visible again
775
+ Object.defineProperty(document, 'hidden', {
776
+ writable: true,
777
+ configurable: true,
778
+ value: false,
779
+ });
780
+ document.dispatchEvent(new Event('visibilitychange'));
781
+
782
+ // During grace period with loading state, should show loading instead of redirecting
783
+ rerender(<ProtectedRoute />);
784
+ expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
785
+ expect(screen.queryByTestId('navigate')).not.toBeInTheDocument();
786
+ });
787
+
788
+ it('shows loading during grace period when tab becomes visible and user is unauthenticated', async () => {
789
+ // Start authenticated
790
+ mockUseUnifiedAuth.mockReturnValue({
791
+ isAuthenticated: true,
792
+ authLoading: false,
793
+ isLoading: false,
794
+ });
795
+
796
+ const { rerender } = renderWithProviders(
797
+ <ProtectedRoute />
798
+ );
799
+
800
+ expect(screen.getByTestId('outlet')).toBeInTheDocument();
801
+
802
+ // Tab becomes hidden
803
+ Object.defineProperty(document, 'hidden', {
804
+ writable: true,
805
+ configurable: true,
806
+ value: true,
807
+ });
808
+ document.dispatchEvent(new Event('visibilitychange'));
809
+
810
+ // User becomes unauthenticated but still loading (session refresh in progress)
811
+ mockUseUnifiedAuth.mockReturnValue({
812
+ isAuthenticated: false,
813
+ authLoading: false,
814
+ isLoading: true,
815
+ });
816
+
817
+ // Tab becomes visible
818
+ Object.defineProperty(document, 'hidden', {
819
+ writable: true,
820
+ configurable: true,
821
+ value: false,
822
+ });
823
+ document.dispatchEvent(new Event('visibilitychange'));
824
+
825
+ rerender(<ProtectedRoute />);
826
+
827
+ // Should show loading during grace period when tab becomes visible
828
+ expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
829
+ expect(screen.queryByTestId('navigate')).not.toBeInTheDocument();
830
+ });
831
+
832
+ it('tracks wasAuthenticatedRef to prevent redirects during session refresh', async () => {
833
+ const { rerender } = renderWithProviders(
834
+ <ProtectedRoute />
835
+ );
836
+
837
+ // Start authenticated
838
+ mockUseUnifiedAuth.mockReturnValue({
839
+ isAuthenticated: true,
840
+ authLoading: false,
841
+ isLoading: false,
842
+ });
843
+
844
+ rerender(<ProtectedRoute />);
845
+ expect(screen.getByTestId('outlet')).toBeInTheDocument();
846
+
847
+ // User appears unauthenticated (session refresh in progress)
848
+ mockUseUnifiedAuth.mockReturnValue({
849
+ isAuthenticated: false,
850
+ authLoading: false,
851
+ isLoading: true, // Still loading (session refresh)
852
+ });
853
+
854
+ rerender(<ProtectedRoute />);
855
+
856
+ // Should show loading, not redirect (wasAuthenticatedRef prevents immediate redirect)
857
+ expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
858
+ expect(screen.queryByTestId('navigate')).not.toBeInTheDocument();
859
+ });
860
+
861
+ it('redirects when a previously authenticated user is logged out and no longer loading', () => {
862
+ const { rerender } = renderWithProviders(
863
+ <ProtectedRoute />
864
+ );
865
+
866
+ // Start authenticated to set wasAuthenticatedRef
867
+ mockUseUnifiedAuth.mockReturnValue({
868
+ isAuthenticated: true,
869
+ authLoading: false,
870
+ isLoading: false,
871
+ });
872
+
873
+ rerender(<ProtectedRoute />);
874
+ expect(screen.getByTestId('outlet')).toBeInTheDocument();
875
+
876
+ // User becomes unauthenticated and not loading
877
+ mockUseUnifiedAuth.mockReturnValue({
878
+ isAuthenticated: false,
879
+ authLoading: false,
880
+ isLoading: false,
881
+ });
882
+
883
+ rerender(<ProtectedRoute />);
884
+
885
+ expect(screen.getByTestId('navigate')).toHaveAttribute('data-to', '/login');
886
+ });
887
+
888
+ it('handles multiple visibility changes correctly', async () => {
889
+ const { rerender } = renderWithProviders(
890
+ <ProtectedRoute />
891
+ );
892
+
893
+ // Start authenticated
894
+ mockUseUnifiedAuth.mockReturnValue({
895
+ isAuthenticated: true,
896
+ authLoading: false,
897
+ isLoading: false,
898
+ });
899
+
900
+ rerender(<ProtectedRoute />);
901
+
902
+ // Tab becomes hidden
903
+ Object.defineProperty(document, 'hidden', {
904
+ writable: true,
905
+ configurable: true,
906
+ value: true,
907
+ });
908
+ document.dispatchEvent(new Event('visibilitychange'));
909
+
910
+ // Tab becomes visible
911
+ Object.defineProperty(document, 'hidden', {
912
+ writable: true,
913
+ configurable: true,
914
+ value: false,
915
+ });
916
+ document.dispatchEvent(new Event('visibilitychange'));
917
+
918
+ // Tab becomes hidden again
919
+ Object.defineProperty(document, 'hidden', {
920
+ writable: true,
921
+ configurable: true,
922
+ value: true,
923
+ });
924
+ document.dispatchEvent(new Event('visibilitychange'));
925
+
926
+ // Tab becomes visible again
927
+ Object.defineProperty(document, 'hidden', {
928
+ writable: true,
929
+ configurable: true,
930
+ value: false,
931
+ });
932
+ document.dispatchEvent(new Event('visibilitychange'));
933
+
934
+ // Should still render outlet if authenticated
935
+ rerender(<ProtectedRoute />);
936
+ expect(screen.getByTestId('outlet')).toBeInTheDocument();
937
+ });
938
+
939
+ it('clears visibility flag when user authenticates', async () => {
940
+ const { rerender } = renderWithProviders(
941
+ <ProtectedRoute />
942
+ );
943
+
944
+ // Start authenticated
945
+ mockUseUnifiedAuth.mockReturnValue({
946
+ isAuthenticated: true,
947
+ authLoading: false,
948
+ isLoading: false,
949
+ });
950
+
951
+ rerender(<ProtectedRoute />);
952
+
953
+ // Tab becomes hidden
954
+ Object.defineProperty(document, 'hidden', {
955
+ writable: true,
956
+ configurable: true,
957
+ value: true,
958
+ });
959
+ document.dispatchEvent(new Event('visibilitychange'));
960
+
961
+ // User becomes unauthenticated
962
+ mockUseUnifiedAuth.mockReturnValue({
963
+ isAuthenticated: false,
964
+ authLoading: false,
965
+ isLoading: false,
966
+ });
967
+
968
+ // Tab becomes visible
969
+ Object.defineProperty(document, 'hidden', {
970
+ writable: true,
971
+ configurable: true,
972
+ value: false,
973
+ });
974
+ document.dispatchEvent(new Event('visibilitychange'));
975
+
976
+ // User authenticates again (session refresh completes)
977
+ mockUseUnifiedAuth.mockReturnValue({
978
+ isAuthenticated: true,
979
+ authLoading: false,
980
+ isLoading: false,
981
+ });
982
+
983
+ rerender(<ProtectedRoute />);
984
+
985
+ // Should render outlet, visibility flag should be cleared
986
+ expect(screen.getByTestId('outlet')).toBeInTheDocument();
987
+ expect(screen.queryByTestId('navigate')).not.toBeInTheDocument();
988
+ });
989
+
990
+ it('handles rapid state changes during tab visibility transitions', async () => {
991
+ vi.useFakeTimers();
992
+
993
+ const { rerender } = renderWithProviders(
994
+ <ProtectedRoute />
995
+ );
996
+
997
+ // Start authenticated
998
+ mockUseUnifiedAuth.mockReturnValue({
999
+ isAuthenticated: true,
1000
+ authLoading: false,
1001
+ isLoading: false,
1002
+ });
1003
+
1004
+ rerender(<ProtectedRoute />);
1005
+
1006
+ // Rapid state changes
1007
+ mockUseUnifiedAuth.mockReturnValue({
1008
+ isAuthenticated: false,
1009
+ authLoading: false,
1010
+ isLoading: true,
1011
+ });
1012
+
1013
+ Object.defineProperty(document, 'hidden', {
1014
+ writable: true,
1015
+ configurable: true,
1016
+ value: false,
1017
+ });
1018
+ document.dispatchEvent(new Event('visibilitychange'));
1019
+
1020
+ rerender(<ProtectedRoute />);
1021
+ expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
1022
+
1023
+ // State changes again
1024
+ mockUseUnifiedAuth.mockReturnValue({
1025
+ isAuthenticated: true,
1026
+ authLoading: false,
1027
+ isLoading: false,
1028
+ });
1029
+
1030
+ rerender(<ProtectedRoute />);
1031
+ expect(screen.getByTestId('outlet')).toBeInTheDocument();
1032
+
1033
+ vi.useRealTimers();
1034
+ });
1035
+ });
1036
+
1037
+ describe('Session Restoration Not Complete Logic', () => {
1038
+ it('shows loading when restoration has not completed and user is not authenticated', () => {
1039
+ mockUseUnifiedAuth.mockReturnValue({
1040
+ isAuthenticated: false,
1041
+ authLoading: false,
1042
+ isLoading: false,
1043
+ });
1044
+
1045
+ mockUseSessionRestoration.mockReturnValue({
1046
+ isRestoring: false,
1047
+ restorationComplete: false, // Not complete
1048
+ restorationError: null,
1049
+ hasTimedOut: false,
1050
+ });
1051
+
1052
+ renderWithProviders(<ProtectedRoute />);
1053
+
1054
+ // Should show loading while waiting for restoration to complete
1055
+ expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
1056
+ expect(screen.queryByTestId('navigate')).not.toBeInTheDocument();
1057
+ });
1058
+
1059
+ it('shows session restoration loader when restoration is in progress and user is not authenticated', () => {
1060
+ mockUseUnifiedAuth.mockReturnValue({
1061
+ isAuthenticated: false,
1062
+ authLoading: false,
1063
+ isLoading: false,
1064
+ });
1065
+
1066
+ mockUseSessionRestoration.mockReturnValue({
1067
+ isRestoring: true, // In progress
1068
+ restorationComplete: false,
1069
+ restorationError: null,
1070
+ hasTimedOut: false,
1071
+ });
1072
+
1073
+ renderWithProviders(<ProtectedRoute />);
1074
+
1075
+ // Should show session restoration loader while restoration is in progress
1076
+ expect(screen.getByTestId('session-restoration-loader')).toBeInTheDocument();
1077
+ expect(screen.queryByTestId('navigate')).not.toBeInTheDocument();
1078
+ });
1079
+
1080
+ it('redirects when restoration has timed out even if not complete', () => {
1081
+ mockUseUnifiedAuth.mockReturnValue({
1082
+ isAuthenticated: false,
1083
+ authLoading: false,
1084
+ isLoading: false,
1085
+ });
1086
+
1087
+ mockUseSessionRestoration.mockReturnValue({
1088
+ isRestoring: false,
1089
+ restorationComplete: false,
1090
+ restorationError: null,
1091
+ hasTimedOut: true, // Timed out
1092
+ });
1093
+
1094
+ renderWithProviders(<ProtectedRoute />);
1095
+
1096
+ // Should redirect immediately when timed out
1097
+ expect(screen.getByTestId('navigate')).toHaveAttribute('data-to', '/login');
1098
+ expect(screen.queryByTestId('loading-spinner')).not.toBeInTheDocument();
1099
+ });
1100
+
1101
+ it('redirects when restoration has error even if not complete', () => {
1102
+ const mockError = new Error('Restoration failed');
1103
+
1104
+ mockUseUnifiedAuth.mockReturnValue({
1105
+ isAuthenticated: false,
1106
+ authLoading: false,
1107
+ isLoading: false,
1108
+ });
1109
+
1110
+ mockUseSessionRestoration.mockReturnValue({
1111
+ isRestoring: false,
1112
+ restorationComplete: false,
1113
+ restorationError: mockError, // Has error
1114
+ hasTimedOut: false,
1115
+ });
1116
+
1117
+ renderWithProviders(<ProtectedRoute />);
1118
+
1119
+ // Should redirect immediately when error occurs
1120
+ expect(screen.getByTestId('navigate')).toHaveAttribute('data-to', '/login');
1121
+ expect(screen.queryByTestId('loading-spinner')).not.toBeInTheDocument();
1122
+ });
1123
+
1124
+ it('shows loading when isLoading is true even if restoration not complete', () => {
1125
+ mockUseUnifiedAuth.mockReturnValue({
1126
+ isAuthenticated: false,
1127
+ authLoading: false,
1128
+ isLoading: true, // Still loading
1129
+ });
1130
+
1131
+ mockUseSessionRestoration.mockReturnValue({
1132
+ isRestoring: false,
1133
+ restorationComplete: false,
1134
+ restorationError: null,
1135
+ hasTimedOut: false,
1136
+ });
1137
+
1138
+ renderWithProviders(<ProtectedRoute />);
1139
+
1140
+ // Should show loading when isLoading is true
1141
+ expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
1142
+ expect(screen.queryByTestId('navigate')).not.toBeInTheDocument();
1143
+ });
1144
+
1145
+ it('handles restoration complete but user never authenticated', () => {
1146
+ mockUseUnifiedAuth.mockReturnValue({
1147
+ isAuthenticated: false,
1148
+ authLoading: false,
1149
+ isLoading: false,
1150
+ });
1151
+
1152
+ mockUseSessionRestoration.mockReturnValue({
1153
+ isRestoring: false,
1154
+ restorationComplete: true, // Complete
1155
+ restorationError: null,
1156
+ hasTimedOut: false,
1157
+ });
1158
+
1159
+ renderWithProviders(<ProtectedRoute />);
1160
+
1161
+ // User was never authenticated, should redirect
1162
+ expect(screen.getByTestId('navigate')).toHaveAttribute('data-to', '/login');
1163
+ });
1164
+ });
1165
+
1166
+ describe('Tab Visibility Timeout and Grace Period', () => {
1167
+ beforeEach(() => {
1168
+ vi.useFakeTimers();
1169
+ Object.defineProperty(document, 'hidden', {
1170
+ writable: true,
1171
+ configurable: true,
1172
+ value: false,
1173
+ });
1174
+ });
1175
+
1176
+ afterEach(() => {
1177
+ vi.useRealTimers();
1178
+ });
1179
+
1180
+ it('prevents redirect during 2-second grace period after tab becomes visible', async () => {
1181
+ // Start authenticated
1182
+ mockUseUnifiedAuth.mockReturnValue({
1183
+ isAuthenticated: true,
1184
+ authLoading: false,
1185
+ isLoading: false,
1186
+ });
1187
+
1188
+ mockUseSessionRestoration.mockReturnValue({
1189
+ isRestoring: false,
1190
+ restorationComplete: true,
1191
+ restorationError: null,
1192
+ hasTimedOut: false,
1193
+ });
1194
+
1195
+ const { rerender } = renderWithProviders(<ProtectedRoute />);
1196
+ expect(screen.getByTestId('outlet')).toBeInTheDocument();
1197
+
1198
+ // Tab becomes hidden
1199
+ Object.defineProperty(document, 'hidden', {
1200
+ writable: true,
1201
+ configurable: true,
1202
+ value: true,
1203
+ });
1204
+ document.dispatchEvent(new Event('visibilitychange'));
1205
+
1206
+ // User becomes unauthenticated while tab is hidden, but still loading (session refresh)
1207
+ mockUseUnifiedAuth.mockReturnValue({
1208
+ isAuthenticated: false,
1209
+ authLoading: false,
1210
+ isLoading: true, // Still loading - session refresh in progress
1211
+ });
1212
+
1213
+ // Tab becomes visible
1214
+ Object.defineProperty(document, 'hidden', {
1215
+ writable: true,
1216
+ configurable: true,
1217
+ value: false,
1218
+ });
1219
+ document.dispatchEvent(new Event('visibilitychange'));
1220
+
1221
+ rerender(<ProtectedRoute />);
1222
+
1223
+ // Should show loading during grace period when isLoading is true
1224
+ expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
1225
+ expect(screen.queryByTestId('navigate')).not.toBeInTheDocument();
1226
+
1227
+ // Fast-forward 1 second (still in grace period)
1228
+ vi.advanceTimersByTime(1000);
1229
+ rerender(<ProtectedRoute />);
1230
+ expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
1231
+ expect(screen.queryByTestId('navigate')).not.toBeInTheDocument();
1232
+
1233
+ // Fast-forward past grace period (2 seconds total) and stop loading
1234
+ vi.advanceTimersByTime(1000);
1235
+ mockUseUnifiedAuth.mockReturnValue({
1236
+ isAuthenticated: false,
1237
+ authLoading: false,
1238
+ isLoading: false, // No longer loading
1239
+ });
1240
+ rerender(<ProtectedRoute />);
1241
+
1242
+ // After grace period and not loading, should redirect
1243
+ expect(screen.getByTestId('navigate')).toHaveAttribute('data-to', '/login');
1244
+ });
1245
+
1246
+ it('clears timeout when tab becomes hidden during grace period', () => {
1247
+ // Start authenticated
1248
+ mockUseUnifiedAuth.mockReturnValue({
1249
+ isAuthenticated: true,
1250
+ authLoading: false,
1251
+ isLoading: false,
1252
+ });
1253
+
1254
+ mockUseSessionRestoration.mockReturnValue({
1255
+ isRestoring: false,
1256
+ restorationComplete: true,
1257
+ restorationError: null,
1258
+ hasTimedOut: false,
1259
+ });
1260
+
1261
+ const { rerender } = renderWithProviders(<ProtectedRoute />);
1262
+
1263
+ // Tab becomes hidden
1264
+ Object.defineProperty(document, 'hidden', {
1265
+ writable: true,
1266
+ configurable: true,
1267
+ value: true,
1268
+ });
1269
+ document.dispatchEvent(new Event('visibilitychange'));
1270
+
1271
+ // User becomes unauthenticated but still loading
1272
+ mockUseUnifiedAuth.mockReturnValue({
1273
+ isAuthenticated: false,
1274
+ authLoading: false,
1275
+ isLoading: true,
1276
+ });
1277
+
1278
+ // Tab becomes visible (starts grace period)
1279
+ Object.defineProperty(document, 'hidden', {
1280
+ writable: true,
1281
+ configurable: true,
1282
+ value: false,
1283
+ });
1284
+ document.dispatchEvent(new Event('visibilitychange'));
1285
+
1286
+ rerender(<ProtectedRoute />);
1287
+ expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
1288
+
1289
+ // Tab becomes hidden again (should clear timeout)
1290
+ Object.defineProperty(document, 'hidden', {
1291
+ writable: true,
1292
+ configurable: true,
1293
+ value: true,
1294
+ });
1295
+ document.dispatchEvent(new Event('visibilitychange'));
1296
+
1297
+ rerender(<ProtectedRoute />);
1298
+
1299
+ // Component should still show loading if isLoading is true
1300
+ // The timeout cleanup happens in the effect, but component state is based on current props
1301
+ expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
1302
+ });
1303
+
1304
+ it('handles initial state when tab is visible and user appears logged out', () => {
1305
+ // Start with user that was authenticated (sets wasAuthenticatedRef)
1306
+ mockUseUnifiedAuth.mockReturnValue({
1307
+ isAuthenticated: true,
1308
+ authLoading: false,
1309
+ isLoading: false,
1310
+ });
1311
+
1312
+ mockUseSessionRestoration.mockReturnValue({
1313
+ isRestoring: false,
1314
+ restorationComplete: true,
1315
+ restorationError: null,
1316
+ hasTimedOut: false,
1317
+ });
1318
+
1319
+ const { rerender } = renderWithProviders(<ProtectedRoute />);
1320
+
1321
+ // User becomes unauthenticated but still loading (session refresh)
1322
+ mockUseUnifiedAuth.mockReturnValue({
1323
+ isAuthenticated: false,
1324
+ authLoading: false,
1325
+ isLoading: true, // Still loading
1326
+ });
1327
+
1328
+ // Tab is visible (initial state check)
1329
+ Object.defineProperty(document, 'hidden', {
1330
+ writable: true,
1331
+ configurable: true,
1332
+ value: false,
1333
+ });
1334
+
1335
+ rerender(<ProtectedRoute />);
1336
+
1337
+ // Should show loading during initial grace period when isLoading is true
1338
+ expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
1339
+
1340
+ // Fast-forward past grace period and stop loading
1341
+ vi.advanceTimersByTime(2000);
1342
+ mockUseUnifiedAuth.mockReturnValue({
1343
+ isAuthenticated: false,
1344
+ authLoading: false,
1345
+ isLoading: false, // No longer loading
1346
+ });
1347
+ rerender(<ProtectedRoute />);
1348
+
1349
+ // After grace period and not loading, should redirect if still not authenticated
1350
+ expect(screen.getByTestId('navigate')).toHaveAttribute('data-to', '/login');
1351
+ });
1352
+
1353
+ it('clears visibility flag when user authenticates during grace period', () => {
1354
+ // Start authenticated
1355
+ mockUseUnifiedAuth.mockReturnValue({
1356
+ isAuthenticated: true,
1357
+ authLoading: false,
1358
+ isLoading: false,
1359
+ });
1360
+
1361
+ mockUseSessionRestoration.mockReturnValue({
1362
+ isRestoring: false,
1363
+ restorationComplete: true,
1364
+ restorationError: null,
1365
+ hasTimedOut: false,
1366
+ });
1367
+
1368
+ const { rerender } = renderWithProviders(<ProtectedRoute />);
1369
+
1370
+ // Tab becomes hidden
1371
+ Object.defineProperty(document, 'hidden', {
1372
+ writable: true,
1373
+ configurable: true,
1374
+ value: true,
1375
+ });
1376
+ document.dispatchEvent(new Event('visibilitychange'));
1377
+
1378
+ // User becomes unauthenticated but still loading
1379
+ mockUseUnifiedAuth.mockReturnValue({
1380
+ isAuthenticated: false,
1381
+ authLoading: false,
1382
+ isLoading: true,
1383
+ });
1384
+
1385
+ // Tab becomes visible (starts grace period)
1386
+ Object.defineProperty(document, 'hidden', {
1387
+ writable: true,
1388
+ configurable: true,
1389
+ value: false,
1390
+ });
1391
+ document.dispatchEvent(new Event('visibilitychange'));
1392
+
1393
+ rerender(<ProtectedRoute />);
1394
+ expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
1395
+
1396
+ // User authenticates again (session refresh completes)
1397
+ mockUseUnifiedAuth.mockReturnValue({
1398
+ isAuthenticated: true,
1399
+ authLoading: false,
1400
+ isLoading: false,
1401
+ });
1402
+
1403
+ rerender(<ProtectedRoute />);
1404
+
1405
+ // Should render outlet and clear visibility flag
1406
+ expect(screen.getByTestId('outlet')).toBeInTheDocument();
1407
+ expect(screen.queryByTestId('navigate')).not.toBeInTheDocument();
1408
+ });
1409
+ });
1410
+
1411
+ describe('SSR and Document Handling', () => {
1412
+ it('handles document.hidden being undefined gracefully', () => {
1413
+ const originalHidden = Object.getOwnPropertyDescriptor(document, 'hidden');
1414
+
1415
+ // Remove hidden property to simulate edge case
1416
+ delete (document as any).hidden;
1417
+
1418
+ mockUseUnifiedAuth.mockReturnValue({
1419
+ isAuthenticated: true,
1420
+ authLoading: false,
1421
+ isLoading: false,
1422
+ });
1423
+
1424
+ mockUseSessionRestoration.mockReturnValue({
1425
+ isRestoring: false,
1426
+ restorationComplete: true,
1427
+ restorationError: null,
1428
+ hasTimedOut: false,
1429
+ });
1430
+
1431
+ // Should not throw error - component checks typeof document !== 'undefined'
1432
+ expect(() => {
1433
+ renderWithProviders(<ProtectedRoute />);
1434
+ }).not.toThrow();
1435
+
1436
+ // Component should still render outlet
1437
+ expect(screen.getByTestId('outlet')).toBeInTheDocument();
1438
+
1439
+ // Restore hidden property
1440
+ if (originalHidden) {
1441
+ Object.defineProperty(document, 'hidden', originalHidden);
1442
+ } else {
1443
+ // Restore default if it didn't exist
1444
+ Object.defineProperty(document, 'hidden', {
1445
+ writable: true,
1446
+ configurable: true,
1447
+ value: false,
1448
+ });
1449
+ }
1450
+ });
1451
+ });
1452
+
1453
+ describe('Complex State Transitions', () => {
1454
+ beforeEach(() => {
1455
+ // Ensure document is properly set up
1456
+ Object.defineProperty(document, 'hidden', {
1457
+ writable: true,
1458
+ configurable: true,
1459
+ value: false,
1460
+ });
1461
+ });
1462
+
1463
+ it('handles transition from session restoration to authenticated', () => {
1464
+ // Start with session restoration
1465
+ mockUseSessionRestoration.mockReturnValue({
1466
+ isRestoring: true,
1467
+ restorationComplete: false,
1468
+ restorationError: null,
1469
+ hasTimedOut: false,
1470
+ });
1471
+
1472
+ mockUseUnifiedAuth.mockReturnValue({
1473
+ isAuthenticated: false,
1474
+ authLoading: false,
1475
+ isLoading: false,
1476
+ });
1477
+
1478
+ const { rerender } = renderWithProviders(<ProtectedRoute />);
1479
+ expect(screen.getByTestId('session-restoration-loader')).toBeInTheDocument();
1480
+
1481
+ // Restoration completes and user becomes authenticated
1482
+ mockUseSessionRestoration.mockReturnValue({
1483
+ isRestoring: false,
1484
+ restorationComplete: true,
1485
+ restorationError: null,
1486
+ hasTimedOut: false,
1487
+ });
1488
+
1489
+ mockUseUnifiedAuth.mockReturnValue({
1490
+ isAuthenticated: true,
1491
+ authLoading: false,
1492
+ isLoading: false,
1493
+ });
1494
+
1495
+ rerender(<ProtectedRoute />);
1496
+ expect(screen.getByTestId('outlet')).toBeInTheDocument();
1497
+ expect(screen.queryByTestId('session-restoration-loader')).not.toBeInTheDocument();
1498
+ });
1499
+
1500
+ it('handles transition from loading to authenticated with events', () => {
1501
+ mockUseSessionRestoration.mockReturnValue({
1502
+ isRestoring: false,
1503
+ restorationComplete: true,
1504
+ restorationError: null,
1505
+ hasTimedOut: false,
1506
+ });
1507
+
1508
+ mockUseUnifiedAuth.mockReturnValue({
1509
+ isAuthenticated: false,
1510
+ authLoading: true,
1511
+ isLoading: true,
1512
+ });
1513
+
1514
+ mockUseEvents.mockReturnValue({
1515
+ selectedEvent: null,
1516
+ events: [],
1517
+ isLoading: true,
1518
+ });
1519
+
1520
+ const { rerender } = renderWithProviders(<ProtectedRoute requireEvent={true} />);
1521
+ // Event loading takes priority, should render outlet
1522
+ expect(screen.getByTestId('outlet')).toBeInTheDocument();
1523
+
1524
+ // User becomes authenticated and events load
1525
+ mockUseUnifiedAuth.mockReturnValue({
1526
+ isAuthenticated: true,
1527
+ authLoading: false,
1528
+ isLoading: false,
1529
+ });
1530
+
1531
+ mockUseEvents.mockReturnValue({
1532
+ selectedEvent: { id: 'event-1', name: 'Event 1' },
1533
+ events: [{ id: 'event-1', name: 'Event 1' }],
1534
+ isLoading: false,
1535
+ });
1536
+
1537
+ rerender(<ProtectedRoute requireEvent={true} />);
1538
+ expect(screen.getByTestId('outlet')).toBeInTheDocument();
1539
+ });
1540
+
1541
+ it('handles transition from authenticated to unauthenticated', () => {
1542
+ mockUseSessionRestoration.mockReturnValue({
1543
+ isRestoring: false,
1544
+ restorationComplete: true,
1545
+ restorationError: null,
1546
+ hasTimedOut: false,
1547
+ });
1548
+
1549
+ mockUseUnifiedAuth.mockReturnValue({
1550
+ isAuthenticated: true,
1551
+ authLoading: false,
1552
+ isLoading: false,
1553
+ });
1554
+
1555
+ const { rerender } = renderWithProviders(<ProtectedRoute />);
1556
+ expect(screen.getByTestId('outlet')).toBeInTheDocument();
1557
+
1558
+ // User becomes unauthenticated
1559
+ mockUseUnifiedAuth.mockReturnValue({
1560
+ isAuthenticated: false,
1561
+ authLoading: false,
1562
+ isLoading: false,
1563
+ });
1564
+
1565
+ rerender(<ProtectedRoute />);
1566
+ expect(screen.getByTestId('navigate')).toHaveAttribute('data-to', '/login');
1567
+ });
1568
+
1569
+ it('handles rapid transitions between multiple states', () => {
1570
+ const { rerender } = renderWithProviders(<ProtectedRoute />);
1571
+
1572
+ // State 1: Session restoring
1573
+ mockUseSessionRestoration.mockReturnValue({
1574
+ isRestoring: true,
1575
+ restorationComplete: false,
1576
+ restorationError: null,
1577
+ hasTimedOut: false,
1578
+ });
1579
+ mockUseUnifiedAuth.mockReturnValue({
1580
+ isAuthenticated: false,
1581
+ authLoading: false,
1582
+ isLoading: false,
1583
+ });
1584
+ rerender(<ProtectedRoute />);
1585
+ expect(screen.getByTestId('session-restoration-loader')).toBeInTheDocument();
1586
+
1587
+ // State 2: Loading (restoration complete but auth loading)
1588
+ mockUseSessionRestoration.mockReturnValue({
1589
+ isRestoring: false,
1590
+ restorationComplete: true,
1591
+ restorationError: null,
1592
+ hasTimedOut: false,
1593
+ });
1594
+ mockUseUnifiedAuth.mockReturnValue({
1595
+ isAuthenticated: false,
1596
+ authLoading: true,
1597
+ isLoading: true,
1598
+ });
1599
+ rerender(<ProtectedRoute />);
1600
+ expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
1601
+
1602
+ // State 3: Authenticated
1603
+ mockUseUnifiedAuth.mockReturnValue({
1604
+ isAuthenticated: true,
1605
+ authLoading: false,
1606
+ isLoading: false,
1607
+ });
1608
+ rerender(<ProtectedRoute />);
1609
+ expect(screen.getByTestId('outlet')).toBeInTheDocument();
1610
+ });
1611
+ });
1612
+
1613
+ describe('Event Loading Priority', () => {
1614
+ beforeEach(() => {
1615
+ mockUseSessionRestoration.mockReturnValue({
1616
+ isRestoring: false,
1617
+ restorationComplete: true,
1618
+ restorationError: null,
1619
+ hasTimedOut: false,
1620
+ });
1621
+ });
1622
+
1623
+ it('renders outlet during event loading even when auth is loading', () => {
1624
+ mockUseUnifiedAuth.mockReturnValue({
1625
+ isAuthenticated: true,
1626
+ authLoading: true,
1627
+ isLoading: true, // Auth is loading
1628
+ });
1629
+
1630
+ mockUseEvents.mockReturnValue({
1631
+ selectedEvent: null,
1632
+ events: [],
1633
+ isLoading: true, // Events are loading
1634
+ });
1635
+
1636
+ renderWithProviders(<ProtectedRoute requireEvent={true} />);
1637
+
1638
+ // Event loading check comes before auth loading check
1639
+ // Should render outlet during event loading
1640
+ expect(screen.getByTestId('outlet')).toBeInTheDocument();
1641
+ expect(screen.queryByTestId('loading-spinner')).not.toBeInTheDocument();
1642
+ });
1643
+
1644
+ it('shows auth loading when events are not loading and auth is loading', () => {
1645
+ mockUseUnifiedAuth.mockReturnValue({
1646
+ isAuthenticated: false,
1647
+ authLoading: true,
1648
+ isLoading: true,
1649
+ });
1650
+
1651
+ mockUseEvents.mockReturnValue({
1652
+ selectedEvent: null,
1653
+ events: [],
1654
+ isLoading: false, // Events not loading
1655
+ });
1656
+
1657
+ renderWithProviders(<ProtectedRoute requireEvent={true} />);
1658
+
1659
+ // Should show auth loading spinner
1660
+ expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
1661
+ expect(screen.queryByTestId('outlet')).not.toBeInTheDocument();
1662
+ });
1663
+ });
1664
+
1665
+ describe('wasAuthenticatedRef Tracking', () => {
1666
+ beforeEach(() => {
1667
+ mockUseSessionRestoration.mockReturnValue({
1668
+ isRestoring: false,
1669
+ restorationComplete: true,
1670
+ restorationError: null,
1671
+ hasTimedOut: false,
1672
+ });
1673
+ });
1674
+
1675
+ it('tracks wasAuthenticatedRef when user authenticates', () => {
1676
+ // Start unauthenticated
1677
+ mockUseUnifiedAuth.mockReturnValue({
1678
+ isAuthenticated: false,
1679
+ authLoading: false,
1680
+ isLoading: false,
1681
+ });
1682
+
1683
+ const { rerender } = renderWithProviders(<ProtectedRoute />);
1684
+ expect(screen.getByTestId('navigate')).toBeInTheDocument();
1685
+
1686
+ // User authenticates
1687
+ mockUseUnifiedAuth.mockReturnValue({
1688
+ isAuthenticated: true,
1689
+ authLoading: false,
1690
+ isLoading: false,
1691
+ });
1692
+
1693
+ rerender(<ProtectedRoute />);
1694
+ expect(screen.getByTestId('outlet')).toBeInTheDocument();
1695
+
1696
+ // User becomes unauthenticated again (but wasAuthenticatedRef is true)
1697
+ mockUseUnifiedAuth.mockReturnValue({
1698
+ isAuthenticated: false,
1699
+ authLoading: false,
1700
+ isLoading: true, // Still loading (session refresh)
1701
+ });
1702
+
1703
+ rerender(<ProtectedRoute />);
1704
+
1705
+ // Should show loading (not redirect immediately) because wasAuthenticatedRef is true
1706
+ expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
1707
+ expect(screen.queryByTestId('navigate')).not.toBeInTheDocument();
1708
+ });
1709
+
1710
+ it('redirects immediately when user was never authenticated', () => {
1711
+ mockUseUnifiedAuth.mockReturnValue({
1712
+ isAuthenticated: false,
1713
+ authLoading: false,
1714
+ isLoading: false,
1715
+ });
1716
+
1717
+ renderWithProviders(<ProtectedRoute />);
1718
+
1719
+ // User was never authenticated, should redirect immediately
1720
+ expect(screen.getByTestId('navigate')).toHaveAttribute('data-to', '/login');
1721
+ });
1722
+ });
1723
+
1724
+ describe('shouldRedirect State Management', () => {
1725
+ beforeEach(() => {
1726
+ mockUseSessionRestoration.mockReturnValue({
1727
+ isRestoring: false,
1728
+ restorationComplete: true,
1729
+ restorationError: null,
1730
+ hasTimedOut: false,
1731
+ });
1732
+ });
1733
+
1734
+ it('resets shouldRedirect when user authenticates', () => {
1735
+ // Start authenticated
1736
+ mockUseUnifiedAuth.mockReturnValue({
1737
+ isAuthenticated: true,
1738
+ authLoading: false,
1739
+ isLoading: false,
1740
+ });
1741
+
1742
+ const { rerender } = renderWithProviders(<ProtectedRoute />);
1743
+ expect(screen.getByTestId('outlet')).toBeInTheDocument();
1744
+
1745
+ // User becomes unauthenticated
1746
+ mockUseUnifiedAuth.mockReturnValue({
1747
+ isAuthenticated: false,
1748
+ authLoading: false,
1749
+ isLoading: false,
1750
+ });
1751
+
1752
+ rerender(<ProtectedRoute />);
1753
+ expect(screen.getByTestId('navigate')).toBeInTheDocument();
1754
+
1755
+ // User authenticates again
1756
+ mockUseUnifiedAuth.mockReturnValue({
1757
+ isAuthenticated: true,
1758
+ authLoading: false,
1759
+ isLoading: false,
1760
+ });
1761
+
1762
+ rerender(<ProtectedRoute />);
1763
+
1764
+ // shouldRedirect should be reset, outlet should render
1765
+ expect(screen.getByTestId('outlet')).toBeInTheDocument();
1766
+ expect(screen.queryByTestId('navigate')).not.toBeInTheDocument();
1767
+ });
1768
+ });
1769
+
1770
+ describe('Restoration Error Combinations', () => {
1771
+ it('handles restoration error with timeout', () => {
1772
+ const mockError = new Error('Restoration failed');
1773
+
1774
+ mockUseUnifiedAuth.mockReturnValue({
1775
+ isAuthenticated: false,
1776
+ authLoading: false,
1777
+ isLoading: false,
1778
+ });
1779
+
1780
+ mockUseSessionRestoration.mockReturnValue({
1781
+ isRestoring: false,
1782
+ restorationComplete: false,
1783
+ restorationError: mockError,
1784
+ hasTimedOut: true, // Both error and timeout
1785
+ });
1786
+
1787
+ renderWithProviders(<ProtectedRoute />);
1788
+
1789
+ // Should redirect immediately (error takes precedence or both cause redirect)
1790
+ expect(screen.getByTestId('navigate')).toHaveAttribute('data-to', '/login');
1791
+ });
1792
+
1793
+ it('handles restoration complete with error (edge case)', () => {
1794
+ const mockError = new Error('Restoration failed');
1795
+
1796
+ mockUseUnifiedAuth.mockReturnValue({
1797
+ isAuthenticated: false,
1798
+ authLoading: false,
1799
+ isLoading: false,
1800
+ });
1801
+
1802
+ mockUseSessionRestoration.mockReturnValue({
1803
+ isRestoring: false,
1804
+ restorationComplete: true, // Complete but has error (edge case)
1805
+ restorationError: mockError,
1806
+ hasTimedOut: false,
1807
+ });
1808
+
1809
+ renderWithProviders(<ProtectedRoute />);
1810
+
1811
+ // Error should cause redirect
1812
+ expect(screen.getByTestId('navigate')).toHaveAttribute('data-to', '/login');
1813
+ });
1814
+ });
1815
+
1816
+ describe('Event State Edge Cases', () => {
1817
+ beforeEach(() => {
1818
+ mockUseSessionRestoration.mockReturnValue({
1819
+ isRestoring: false,
1820
+ restorationComplete: true,
1821
+ restorationError: null,
1822
+ hasTimedOut: false,
1823
+ });
1824
+ });
1825
+
1826
+ it('handles events array with null elements', () => {
1827
+ mockUseEvents.mockReturnValue({
1828
+ selectedEvent: null,
1829
+ // @ts-expect-error - Testing runtime edge case
1830
+ events: [null, undefined],
1831
+ isLoading: false,
1832
+ });
1833
+
1834
+ renderWithProviders(<ProtectedRoute requireEvent={true} />);
1835
+
1836
+ // Component checks events.length === 0, so [null, undefined] has length 2
1837
+ // This means it will try to render outlet (events exist but none selected)
1838
+ // The component doesn't validate event object structure, just array length
1839
+ expect(screen.getByTestId('outlet')).toBeInTheDocument();
1840
+ });
1841
+
1842
+ it('handles events array that becomes empty after loading', () => {
1843
+ mockUseEvents.mockReturnValue({
1844
+ selectedEvent: null,
1845
+ events: [],
1846
+ isLoading: true,
1847
+ });
1848
+
1849
+ const { rerender } = renderWithProviders(<ProtectedRoute requireEvent={true} />);
1850
+
1851
+ // Should render outlet during loading
1852
+ expect(screen.getByTestId('outlet')).toBeInTheDocument();
1853
+
1854
+ // Events finish loading but are empty
1855
+ mockUseEvents.mockReturnValue({
1856
+ selectedEvent: null,
1857
+ events: [],
1858
+ isLoading: false,
1859
+ });
1860
+
1861
+ rerender(<ProtectedRoute requireEvent={true} />);
1862
+
1863
+ // Should show no events message
1864
+ expect(screen.getByTestId('alert')).toBeInTheDocument();
1865
+ expect(screen.queryByTestId('outlet')).not.toBeInTheDocument();
1866
+ });
1867
+
1868
+ it('handles events that become available after loading', () => {
1869
+ mockUseEvents.mockReturnValue({
1870
+ selectedEvent: null,
1871
+ events: [],
1872
+ isLoading: true,
1873
+ });
1874
+
1875
+ const { rerender } = renderWithProviders(<ProtectedRoute requireEvent={true} />);
1876
+
1877
+ // Should render outlet during loading
1878
+ expect(screen.getByTestId('outlet')).toBeInTheDocument();
1879
+
1880
+ // Events become available
1881
+ mockUseEvents.mockReturnValue({
1882
+ selectedEvent: null,
1883
+ events: [{ id: 'event-1', name: 'Event 1' }],
1884
+ isLoading: false,
1885
+ });
1886
+
1887
+ rerender(<ProtectedRoute requireEvent={true} />);
1888
+
1889
+ // Should render outlet (events exist, even if none selected)
1890
+ expect(screen.getByTestId('outlet')).toBeInTheDocument();
1891
+ });
1892
+ });
1893
+ });