@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
@@ -13,10 +13,16 @@ const mockUseIsPublicPage = vi.hoisted(() => vi.fn(() => false));
13
13
  const publicPageContextStore = vi.hoisted(() => ({ value: null as React.Context<any> | null }));
14
14
 
15
15
  // Mock useIsPublicPage to return false so FileDisplay uses authenticated version by default
16
- vi.mock('../PublicLayout/PublicPageProvider', () => {
17
- publicPageContextStore.value = React.createContext(null);
16
+ vi.mock('../PublicLayout/usePublicPageContext', () => {
18
17
  return {
19
18
  useIsPublicPage: (...args: unknown[]) => mockUseIsPublicPage(...args),
19
+ };
20
+ });
21
+
22
+ // Mock PublicPageContext
23
+ vi.mock('../PublicLayout/PublicPageContext', () => {
24
+ publicPageContextStore.value = React.createContext(null);
25
+ return {
20
26
  PublicPageContext: publicPageContextStore.value,
21
27
  };
22
28
  });
@@ -31,11 +37,11 @@ vi.mock('../../hooks/useFileReference', () => ({
31
37
  }));
32
38
 
33
39
  // Mock useFileDisplay hook which is used by FileDisplayAuthenticated
34
- vi.mock('../../hooks/useFileDisplay', () => ({
40
+ vi.mock('./useFileDisplay', () => ({
35
41
  useFileDisplay: vi.fn()
36
42
  }));
37
43
 
38
- vi.mock('../../hooks/public/usePublicFileDisplay', () => ({
44
+ vi.mock('./usePublicFileDisplay', () => ({
39
45
  usePublicFileDisplay: vi.fn()
40
46
  }));
41
47
 
@@ -45,7 +51,7 @@ vi.mock('../../hooks/useFileUrl', () => ({
45
51
 
46
52
  vi.mock('../../utils/storage/helpers', () => ({
47
53
  getPublicUrl: vi.fn((_, path: string) => `https://example.com/${path}`),
48
- getSignedUrl: vi.fn(async (_: unknown, path: string) => ({ url: `https://signed.example.com/${path}` })),
54
+ getSignedUrl: vi.fn(async (_: unknown, path: string) => ({ ok: true, data: { url: `https://signed.example.com/${path}`, expiresAt: new Date().toISOString() } })),
49
55
  }));
50
56
 
51
57
  // Helper to render with UnifiedAuthProvider
@@ -96,7 +102,7 @@ describe('[component] FileDisplay', () => {
96
102
  });
97
103
 
98
104
  // Set up default mock for useFileDisplay
99
- const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
105
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
100
106
  useFileDisplay.mockReturnValue({
101
107
  isLoading: false,
102
108
  error: null,
@@ -108,7 +114,7 @@ describe('[component] FileDisplay', () => {
108
114
  refetch: vi.fn(),
109
115
  });
110
116
 
111
- const usePublicFileDisplay = (await import('../../hooks/public/usePublicFileDisplay')).usePublicFileDisplay as unknown as vi.Mock;
117
+ const usePublicFileDisplay = (await import('./usePublicFileDisplay')).usePublicFileDisplay as unknown as vi.Mock;
112
118
  usePublicFileDisplay.mockReturnValue({
113
119
  isLoading: false,
114
120
  error: null,
@@ -132,7 +138,7 @@ describe('[component] FileDisplay', () => {
132
138
 
133
139
  it('renders error state and clears error on retry', async () => {
134
140
  const refetch = vi.fn();
135
- const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
141
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
136
142
  useFileDisplay.mockReturnValue({
137
143
  isLoading: false,
138
144
  error: new Error('boom'),
@@ -153,7 +159,7 @@ describe('[component] FileDisplay', () => {
153
159
  });
154
160
 
155
161
  it('renders empty state when no files are found', async () => {
156
- const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
162
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
157
163
  useFileDisplay.mockReturnValue({
158
164
  isLoading: false,
159
165
  error: null,
@@ -183,7 +189,7 @@ describe('[component] FileDisplay', () => {
183
189
  const fileUrlsMap = new Map<string, string>();
184
190
  fileUrlsMap.set('fr-1', 'https://example.com/file.png');
185
191
 
186
- const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
192
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
187
193
  useFileDisplay.mockReturnValue({
188
194
  isLoading: false,
189
195
  error: null,
@@ -212,7 +218,7 @@ describe('[component] FileDisplay', () => {
212
218
  try {
213
219
  const dialog = screen.getByRole('dialog');
214
220
  expect(dialog).toBeInTheDocument();
215
- } catch (e) {
221
+ } catch (_e) {
216
222
  // Fallback for test environments - just check that dialog exists in DOM
217
223
  const dialog = document.querySelector('dialog[role="dialog"]');
218
224
  if (!dialog) {
@@ -241,7 +247,7 @@ describe('[component] FileDisplay', () => {
241
247
  file_metadata: { fileName: 'report.pdf', fileSize: 4096, fileType: 'application/pdf' },
242
248
  };
243
249
 
244
- const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
250
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
245
251
  useFileDisplay.mockReturnValue({
246
252
  isLoading: false,
247
253
  error: null,
@@ -285,7 +291,7 @@ describe('[component] FileDisplay', () => {
285
291
  fileUrlsMap.set('f1', 'https://example.com/bucket/path/a.png');
286
292
  fileUrlsMap.set('f2', 'https://signed.example.com/bucket/path/b.pdf');
287
293
 
288
- const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
294
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
289
295
  useFileDisplay.mockReturnValue({
290
296
  isLoading: false,
291
297
  error: null,
@@ -338,7 +344,7 @@ describe('[component] FileDisplay', () => {
338
344
  const fileUrlsMap = new Map<string, string>();
339
345
  fileUrlsMap.set('fr-3', 'https://example.com/logo.png');
340
346
 
341
- const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
347
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
342
348
  useFileDisplay.mockReturnValue({
343
349
  isLoading: false,
344
350
  error: null,
@@ -379,7 +385,7 @@ describe('[component] FileDisplay', () => {
379
385
  const fileUrlsMap = new Map<string, string>();
380
386
  fileUrlsMap.set('fr-4', 'https://example.com/logo.png');
381
387
 
382
- const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
388
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
383
389
  useFileDisplay.mockReturnValue({
384
390
  isLoading: false,
385
391
  error: null,
@@ -409,7 +415,7 @@ describe('[component] FileDisplay', () => {
409
415
  try {
410
416
  const dialog = screen.getByRole('dialog');
411
417
  expect(dialog).toBeInTheDocument();
412
- } catch (e) {
418
+ } catch (_e) {
413
419
  // Fallback for test environments - just check that dialog exists in DOM
414
420
  const dialog = document.querySelector('dialog[role="dialog"]');
415
421
  if (!dialog) {
@@ -448,7 +454,7 @@ describe('[component] FileDisplay', () => {
448
454
  const fileUrlsMap = new Map<string, string>();
449
455
  fileUrlsMap.set('fr-img', 'https://example.com/image.png');
450
456
 
451
- const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
457
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
452
458
  useFileDisplay.mockReturnValue({
453
459
  isLoading: false,
454
460
  error: null,
@@ -472,7 +478,7 @@ describe('[component] FileDisplay', () => {
472
478
  });
473
479
 
474
480
  it('renders fallback UI when showFallback is enabled and an error occurs', async () => {
475
- const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
481
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
476
482
  useFileDisplay.mockReturnValue({
477
483
  isLoading: false,
478
484
  error: new Error('explode'),
@@ -503,7 +509,7 @@ describe('[component] FileDisplay', () => {
503
509
  file_metadata: { fileName: 'doc.pdf', fileSize: 1024, fileType: 'application/pdf' },
504
510
  };
505
511
 
506
- const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
512
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
507
513
  useFileDisplay.mockReturnValue({
508
514
  isLoading: false,
509
515
  error: null,
@@ -564,7 +570,7 @@ describe('[component] FileDisplay', () => {
564
570
  };
565
571
 
566
572
  const fileUrlsMap = new Map<string, string>([['pub-1', 'https://public.example.com/hero.png']]);
567
- const usePublicFileDisplay = (await import('../../hooks/public/usePublicFileDisplay')).usePublicFileDisplay as unknown as vi.Mock;
573
+ const usePublicFileDisplay = (await import('./usePublicFileDisplay')).usePublicFileDisplay as unknown as vi.Mock;
568
574
  usePublicFileDisplay.mockReturnValue({
569
575
  isLoading: false,
570
576
  error: null,
@@ -587,18 +593,21 @@ describe('[component] FileDisplay', () => {
587
593
  });
588
594
 
589
595
  describe('Document link rendering in displayOnly mode', () => {
590
- it('renders non-image files as clickable links when displayOnly is true and fileUrl exists', async () => {
591
- const pdfFile = {
592
- id: 'fr-pdf',
593
- table_name: 'person',
594
- record_id: 'rec-1',
595
- organisation_id: 'org-1',
596
- file_path: 'bucket/path/document.pdf',
597
- is_public: false,
598
- file_metadata: { fileName: 'document.pdf', fileSize: 2048, fileType: 'application/pdf' },
599
- };
596
+ const createNonImageFile = (id: string, fileName: string, fileType: string) => ({
597
+ id,
598
+ table_name: 'person',
599
+ record_id: 'rec-1',
600
+ organisation_id: 'org-1',
601
+ file_path: `bucket/path/${fileName}`,
602
+ is_public: false,
603
+ file_metadata: { fileName, fileSize: 2048, fileType },
604
+ });
605
+
606
+ it('renders non-image files as clickable links with correct attributes', async () => {
607
+ const pdfFile = createNonImageFile('fr-pdf', 'document.pdf', 'application/pdf');
608
+ const fileUrlsMap = new Map([['fr-pdf', 'https://signed.example.com/document.pdf']]);
600
609
 
601
- const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
610
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
602
611
  useFileDisplay.mockReturnValue({
603
612
  isLoading: false,
604
613
  error: null,
@@ -606,88 +615,59 @@ describe('[component] FileDisplay', () => {
606
615
  fileReference: pdfFile,
607
616
  fileReferences: [pdfFile],
608
617
  fileCount: 1,
609
- fileUrls: new Map([['fr-pdf', 'https://signed.example.com/document.pdf']]),
618
+ fileUrls: fileUrlsMap,
610
619
  refetch: vi.fn(),
611
620
  });
612
621
 
613
- // Mock useFileUrl to return URL from map (since it's in the map, hook won't be used, but mock it anyway)
614
- const useFileUrl = (await import('../../hooks/useFileUrl')).useFileUrl as unknown as vi.Mock;
615
- useFileUrl.mockReturnValue({
616
- url: null,
617
- isLoading: false,
618
- error: null,
619
- clear: vi.fn(),
620
- });
621
-
622
622
  renderWithUnifiedAuth(<FileDisplay {...baseProps} displayOnly />);
623
623
 
624
624
  const link = await screen.findByRole('link', { name: /Open document\.pdf in new tab/i });
625
- expect(link).toBeInTheDocument();
626
625
  expect(link).toHaveAttribute('href', 'https://signed.example.com/document.pdf');
626
+ expect(link).toHaveAttribute('target', '_blank');
627
+ expect(link).toHaveAttribute('rel', 'noopener noreferrer');
628
+ expect(link).toHaveTextContent('document.pdf');
627
629
  });
628
630
 
629
- it('renders link with target="_blank" for new tab', async () => {
630
- const docFile = {
631
- id: 'fr-doc',
632
- table_name: 'person',
633
- record_id: 'rec-1',
634
- organisation_id: 'org-1',
635
- file_path: 'bucket/path/file.docx',
636
- is_public: false,
637
- file_metadata: { fileName: 'file.docx', fileSize: 4096, fileType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' },
638
- };
631
+ it('renders icons in document links', async () => {
632
+ const pdfFile = createNonImageFile('fr-pdf', 'doc.pdf', 'application/pdf');
633
+ const fileUrlsMap = new Map([['fr-pdf', 'https://signed.example.com/doc.pdf']]);
639
634
 
640
- const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
635
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
641
636
  useFileDisplay.mockReturnValue({
642
637
  isLoading: false,
643
638
  error: null,
644
- fileUrl: 'https://signed.example.com/file.docx',
645
- fileReference: docFile,
646
- fileReferences: [docFile],
639
+ fileUrl: 'https://signed.example.com/doc.pdf',
640
+ fileReference: pdfFile,
641
+ fileReferences: [pdfFile],
647
642
  fileCount: 1,
648
- fileUrls: new Map([['fr-doc', 'https://signed.example.com/file.docx']]),
643
+ fileUrls: fileUrlsMap,
649
644
  refetch: vi.fn(),
650
645
  });
651
646
 
652
- // Mock useFileUrl (won't be used since URL is in map, but mock it anyway)
653
- const useFileUrl = (await import('../../hooks/useFileUrl')).useFileUrl as unknown as vi.Mock;
654
- useFileUrl.mockReturnValue({
655
- url: null,
656
- isLoading: false,
657
- error: null,
658
- clear: vi.fn(),
659
- });
660
-
661
647
  renderWithUnifiedAuth(<FileDisplay {...baseProps} displayOnly />);
662
648
 
663
649
  const link = await screen.findByRole('link');
664
- expect(link).toHaveAttribute('target', '_blank');
650
+ const fileTextIcon = link.querySelector('[data-testid="lucide-filetext"]');
651
+ const externalLinkIcon = link.querySelector('[data-testid="lucide-externallink"]');
652
+ expect(fileTextIcon).toBeInTheDocument();
653
+ expect(externalLinkIcon).toBeInTheDocument();
665
654
  });
666
655
 
667
- it('renders link with rel="noopener noreferrer" for security', async () => {
668
- const excelFile = {
669
- id: 'fr-xls',
670
- table_name: 'person',
671
- record_id: 'rec-1',
672
- organisation_id: 'org-1',
673
- file_path: 'bucket/path/spreadsheet.xlsx',
674
- is_public: false,
675
- file_metadata: { fileName: 'spreadsheet.xlsx', fileSize: 8192, fileType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' },
676
- };
656
+ it('falls back to fallback UI when fileUrl is null', async () => {
657
+ const pdfFile = createNonImageFile('fr-pdf', 'doc.pdf', 'application/pdf');
677
658
 
678
- const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
659
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
679
660
  useFileDisplay.mockReturnValue({
680
661
  isLoading: false,
681
662
  error: null,
682
- fileUrl: 'https://signed.example.com/spreadsheet.xlsx',
683
- fileReference: excelFile,
684
- fileReferences: [excelFile],
663
+ fileUrl: null,
664
+ fileReference: pdfFile,
665
+ fileReferences: [pdfFile],
685
666
  fileCount: 1,
686
- fileUrls: new Map([['fr-xls', 'https://signed.example.com/spreadsheet.xlsx']]),
667
+ fileUrls: new Map(),
687
668
  refetch: vi.fn(),
688
669
  });
689
670
 
690
- // Mock useFileUrl (won't be used since URL is in map, but mock it anyway)
691
671
  const useFileUrl = (await import('../../hooks/useFileUrl')).useFileUrl as unknown as vi.Mock;
692
672
  useFileUrl.mockReturnValue({
693
673
  url: null,
@@ -696,133 +676,269 @@ describe('[component] FileDisplay', () => {
696
676
  clear: vi.fn(),
697
677
  });
698
678
 
699
- renderWithUnifiedAuth(<FileDisplay {...baseProps} displayOnly />);
679
+ renderWithUnifiedAuth(<FileDisplay {...baseProps} displayOnly showFallback fallbackText="View Document" />);
700
680
 
701
- const link = await screen.findByRole('link');
702
- expect(link).toHaveAttribute('rel', 'noopener noreferrer');
681
+ expect(await screen.findByText('View Document')).toBeInTheDocument();
682
+ expect(screen.queryByRole('link')).not.toBeInTheDocument();
703
683
  });
704
684
 
705
- it('displays correct filename in link', async () => {
706
- const pdfFile = {
707
- id: 'fr-pdf',
685
+ it('renders images inline in displayOnly mode (not as links)', async () => {
686
+ const imageFile = {
687
+ id: 'fr-img',
708
688
  table_name: 'person',
709
689
  record_id: 'rec-1',
710
690
  organisation_id: 'org-1',
711
- file_path: 'bucket/path/my-document.pdf',
691
+ file_path: 'bucket/path/image.png',
712
692
  is_public: false,
713
- file_metadata: { fileName: 'my-document.pdf', fileSize: 2048, fileType: 'application/pdf' },
693
+ file_metadata: { fileName: 'image.png', fileSize: 1024, fileType: 'image/png' },
714
694
  };
715
695
 
716
- const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
696
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
717
697
  useFileDisplay.mockReturnValue({
718
698
  isLoading: false,
719
699
  error: null,
720
- fileUrl: 'https://signed.example.com/my-document.pdf',
721
- fileReference: pdfFile,
722
- fileReferences: [pdfFile],
700
+ fileUrl: 'https://signed.example.com/image.png',
701
+ fileReference: imageFile,
702
+ fileReferences: [imageFile],
723
703
  fileCount: 1,
724
- fileUrls: new Map([['fr-pdf', 'https://signed.example.com/my-document.pdf']]),
704
+ fileUrls: new Map([['fr-img', 'https://signed.example.com/image.png']]),
725
705
  refetch: vi.fn(),
726
706
  });
727
707
 
728
- // Mock useFileUrl (won't be used since URL is in map, but mock it anyway)
729
- const useFileUrl = (await import('../../hooks/useFileUrl')).useFileUrl as unknown as vi.Mock;
730
- useFileUrl.mockReturnValue({
731
- url: null,
708
+ renderWithUnifiedAuth(<FileDisplay {...baseProps} displayOnly />);
709
+
710
+ const image = await screen.findByRole('img', { name: /image\.png/i });
711
+ expect(image).toBeInTheDocument();
712
+ expect(screen.queryByRole('link')).not.toBeInTheDocument();
713
+ });
714
+
715
+ it('uses wrapper behavior when showDelete is true', async () => {
716
+ const pdfFile = createNonImageFile('fr-pdf', 'doc.pdf', 'application/pdf');
717
+
718
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
719
+ useFileDisplay.mockReturnValue({
732
720
  isLoading: false,
733
721
  error: null,
734
- clear: vi.fn(),
722
+ fileUrl: 'https://signed.example.com/doc.pdf',
723
+ fileReference: pdfFile,
724
+ fileReferences: [pdfFile],
725
+ fileCount: 1,
726
+ fileUrls: new Map([['fr-pdf', 'https://signed.example.com/doc.pdf']]),
727
+ refetch: vi.fn(),
735
728
  });
736
729
 
737
- renderWithUnifiedAuth(<FileDisplay {...baseProps} displayOnly />);
730
+ renderWithUnifiedAuth(<FileDisplay {...baseProps} displayOnly showDelete />);
738
731
 
739
- const link = await screen.findByRole('link');
740
- expect(link).toHaveTextContent('my-document.pdf');
732
+ expect(screen.getByText('doc.pdf')).toBeInTheDocument();
733
+ expect(screen.getByRole('button', { name: /Delete file/i })).toBeInTheDocument();
734
+ expect(screen.queryByRole('link', { name: /Open.*in new tab/i })).not.toBeInTheDocument();
741
735
  });
742
736
 
743
- it('renders FileText and ExternalLink icons', async () => {
737
+ it('renders document links in public context', async () => {
738
+ mockUseIsPublicPage.mockReturnValueOnce(true);
739
+
744
740
  const pdfFile = {
745
- id: 'fr-pdf',
746
- table_name: 'person',
747
- record_id: 'rec-1',
741
+ id: 'pub-pdf',
742
+ table_name: 'event',
743
+ record_id: 'event-1',
748
744
  organisation_id: 'org-1',
749
- file_path: 'bucket/path/doc.pdf',
750
- is_public: false,
751
- file_metadata: { fileName: 'doc.pdf', fileSize: 2048, fileType: 'application/pdf' },
745
+ file_path: 'bucket/path/public-doc.pdf',
746
+ is_public: true,
747
+ file_metadata: { fileName: 'public-doc.pdf', fileSize: 2048, fileType: 'application/pdf' },
752
748
  };
753
749
 
754
- const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
755
- useFileDisplay.mockReturnValue({
750
+ const fileUrlsMap = new Map<string, string>([['pub-pdf', 'https://public.example.com/public-doc.pdf']]);
751
+ const usePublicFileDisplay = (await import('./usePublicFileDisplay')).usePublicFileDisplay as unknown as vi.Mock;
752
+ usePublicFileDisplay.mockReturnValue({
756
753
  isLoading: false,
757
754
  error: null,
758
- fileUrl: 'https://signed.example.com/doc.pdf',
755
+ fileUrl: 'https://public.example.com/public-doc.pdf',
759
756
  fileReference: pdfFile,
760
757
  fileReferences: [pdfFile],
761
758
  fileCount: 1,
762
- fileUrls: new Map([['fr-pdf', 'https://signed.example.com/doc.pdf']]),
759
+ fileUrls: fileUrlsMap,
763
760
  refetch: vi.fn(),
764
761
  });
765
762
 
766
- // Mock useFileUrl (won't be used since URL is in map, but mock it anyway)
767
- const useFileUrl = (await import('../../hooks/useFileUrl')).useFileUrl as unknown as vi.Mock;
768
- useFileUrl.mockReturnValue({
769
- url: null,
763
+ renderWithPublicContext(
764
+ <FileDisplay {...baseProps} displayOnly />,
765
+ { supabase }
766
+ );
767
+
768
+ const link = await screen.findByRole('link', { name: /Open public-doc\.pdf in new tab/i });
769
+ expect(link).toHaveAttribute('href', 'https://public.example.com/public-doc.pdf');
770
+ expect(link).toHaveAttribute('target', '_blank');
771
+ expect(link).toHaveAttribute('rel', 'noopener noreferrer');
772
+ });
773
+
774
+ it('uses fallback text "Document" when fileName is missing', async () => {
775
+ const pdfFile = createNonImageFile('fr-pdf', '', 'application/pdf');
776
+ pdfFile.file_metadata.fileName = '';
777
+
778
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
779
+ useFileDisplay.mockReturnValue({
770
780
  isLoading: false,
771
781
  error: null,
772
- clear: vi.fn(),
782
+ fileUrl: 'https://signed.example.com/file.pdf',
783
+ fileReference: pdfFile,
784
+ fileReferences: [pdfFile],
785
+ fileCount: 1,
786
+ fileUrls: new Map([['fr-pdf', 'https://signed.example.com/file.pdf']]),
787
+ refetch: vi.fn(),
773
788
  });
774
789
 
775
790
  renderWithUnifiedAuth(<FileDisplay {...baseProps} displayOnly />);
776
791
 
777
- const link = await screen.findByRole('link');
778
- // Icons should be present (they have aria-hidden="true")
779
- // Icons are mocked as divs with data-testid in tests
780
- const fileTextIcon = link.querySelector('[data-testid="lucide-filetext"]');
781
- const externalLinkIcon = link.querySelector('[data-testid="lucide-externallink"]');
782
- expect(fileTextIcon).toBeInTheDocument();
783
- expect(externalLinkIcon).toBeInTheDocument();
792
+ const link = await screen.findByRole('link', { name: /Open Document in new tab/i });
793
+ expect(link).toHaveTextContent('Document');
784
794
  });
795
+ });
785
796
 
786
- it('falls back to existing behavior when fileUrl is null', async () => {
787
- const pdfFile = {
788
- id: 'fr-pdf',
789
- table_name: 'person',
790
- record_id: 'rec-1',
791
- organisation_id: 'org-1',
792
- file_path: 'bucket/path/doc.pdf',
793
- is_public: false,
794
- file_metadata: { fileName: 'doc.pdf', fileSize: 2048, fileType: 'application/pdf' },
795
- };
797
+ describe('Loading States', () => {
798
+ it('renders loading spinner when isLoading is true', async () => {
799
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
800
+ useFileDisplay.mockReturnValue({
801
+ isLoading: true,
802
+ error: null,
803
+ fileUrl: null,
804
+ fileReference: null,
805
+ fileReferences: [],
806
+ fileCount: 0,
807
+ fileUrls: new Map(),
808
+ refetch: vi.fn(),
809
+ });
810
+
811
+ renderWithUnifiedAuth(<FileDisplay {...baseProps} />);
812
+
813
+ // LoadingSpinner should be rendered
814
+ const spinner = screen.getByRole('status', { hidden: true }) || document.querySelector('[data-testid="loading-spinner"]');
815
+ expect(spinner || screen.getByText(/loading/i)).toBeDefined();
816
+ });
817
+
818
+ it('uses custom loading component when provided', async () => {
819
+ const CustomLoader = () => <div data-testid="custom-loader">Custom Loading...</div>;
820
+
821
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
822
+ useFileDisplay.mockReturnValue({
823
+ isLoading: true,
824
+ error: null,
825
+ fileUrl: null,
826
+ fileReference: null,
827
+ fileReferences: [],
828
+ fileCount: 0,
829
+ fileUrls: new Map(),
830
+ refetch: vi.fn(),
831
+ });
832
+
833
+ renderWithUnifiedAuth(<FileDisplay {...baseProps} loadingComponent={CustomLoader} />);
796
834
 
797
- const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
835
+ expect(screen.getByTestId('custom-loader')).toBeInTheDocument();
836
+ expect(screen.getByText('Custom Loading...')).toBeInTheDocument();
837
+ });
838
+
839
+ it('shows fallback during loading when showFallback is enabled and fileCount is 0', async () => {
840
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
841
+ useFileDisplay.mockReturnValue({
842
+ isLoading: true,
843
+ error: null,
844
+ fileUrl: null,
845
+ fileReference: null,
846
+ fileReferences: [],
847
+ fileCount: 0,
848
+ fileUrls: new Map(),
849
+ refetch: vi.fn(),
850
+ });
851
+
852
+ renderWithUnifiedAuth(<FileDisplay {...baseProps} showFallback fallbackText="Loading..." />);
853
+
854
+ expect(screen.getByText('Loading...')).toBeInTheDocument();
855
+ });
856
+ });
857
+
858
+ describe('Fallback UI', () => {
859
+ it('generates fallback text from filename when generateFallbackText is provided', async () => {
860
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
798
861
  useFileDisplay.mockReturnValue({
799
862
  isLoading: false,
800
863
  error: null,
801
864
  fileUrl: null,
802
- fileReference: pdfFile,
803
- fileReferences: [pdfFile],
804
- fileCount: 1,
865
+ fileReference: null,
866
+ fileReferences: [],
867
+ fileCount: 0,
805
868
  fileUrls: new Map(),
806
869
  refetch: vi.fn(),
807
870
  });
808
871
 
809
- // Mock useFileUrl to return null URL so fallback is shown
810
- const useFileUrl = (await import('../../hooks/useFileUrl')).useFileUrl as unknown as vi.Mock;
811
- useFileUrl.mockReturnValue({
812
- url: null,
872
+ const generateFallback = vi.fn((fileName?: string) => fileName ? fileName.toUpperCase() : 'NO FILE');
873
+
874
+ renderWithUnifiedAuth(
875
+ <FileDisplay
876
+ {...baseProps}
877
+ showFallback
878
+ generateFallbackText={generateFallback}
879
+ />
880
+ );
881
+
882
+ expect(generateFallback).toHaveBeenCalled();
883
+ });
884
+
885
+ it('uses fallbackSourceText when provided', async () => {
886
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
887
+ useFileDisplay.mockReturnValue({
813
888
  isLoading: false,
814
889
  error: null,
815
- clear: vi.fn(),
890
+ fileUrl: null,
891
+ fileReference: null,
892
+ fileReferences: [],
893
+ fileCount: 0,
894
+ fileUrls: new Map(),
895
+ refetch: vi.fn(),
816
896
  });
817
897
 
818
- renderWithUnifiedAuth(<FileDisplay {...baseProps} displayOnly showFallback fallbackText="View Document" />);
898
+ const generateFallback = vi.fn((sourceText?: string) => sourceText || 'DEFAULT');
819
899
 
820
- // Should show fallback, not a link
821
- expect(await screen.findByText('View Document')).toBeInTheDocument();
822
- expect(screen.queryByRole('link')).not.toBeInTheDocument();
900
+ renderWithUnifiedAuth(
901
+ <FileDisplay
902
+ {...baseProps}
903
+ showFallback
904
+ fallbackSourceText="Custom Source"
905
+ generateFallbackText={generateFallback}
906
+ />
907
+ );
908
+
909
+ expect(generateFallback).toHaveBeenCalledWith('Custom Source');
910
+ });
911
+
912
+ it('applies correct fallback size classes', async () => {
913
+ const sizes: Array<'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'> = ['xs', 'sm', 'md', 'lg', 'xl', '2xl'];
914
+
915
+ for (const size of sizes) {
916
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
917
+ useFileDisplay.mockReturnValue({
918
+ isLoading: false,
919
+ error: null,
920
+ fileUrl: null,
921
+ fileReference: null,
922
+ fileReferences: [],
923
+ fileCount: 0,
924
+ fileUrls: new Map(),
925
+ refetch: vi.fn(),
926
+ });
927
+
928
+ const { unmount } = renderWithUnifiedAuth(
929
+ <FileDisplay {...baseProps} showFallback fallbackText="Test" fallbackSize={size} />
930
+ );
931
+
932
+ const fallback = screen.getByText('Test');
933
+ expect(fallback).toBeInTheDocument();
934
+ // Check that size class is applied (classes contain size-specific text)
935
+ expect(fallback.className).toContain('grid');
936
+
937
+ unmount();
938
+ }
823
939
  });
824
940
 
825
- it('still renders images inline (no regression)', async () => {
941
+ it('shows fallback when image fails to load and showFallback is enabled', async () => {
826
942
  const imageFile = {
827
943
  id: 'fr-img',
828
944
  table_name: 'person',
@@ -833,188 +949,304 @@ describe('[component] FileDisplay', () => {
833
949
  file_metadata: { fileName: 'image.png', fileSize: 1024, fileType: 'image/png' },
834
950
  };
835
951
 
836
- const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
952
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
837
953
  useFileDisplay.mockReturnValue({
838
954
  isLoading: false,
839
955
  error: null,
840
- fileUrl: 'https://signed.example.com/image.png',
956
+ fileUrl: 'https://example.com/image.png',
841
957
  fileReference: imageFile,
842
958
  fileReferences: [imageFile],
843
959
  fileCount: 1,
844
- fileUrls: new Map([['fr-img', 'https://signed.example.com/image.png']]),
960
+ fileUrls: new Map([['fr-img', 'https://example.com/image.png']]),
845
961
  refetch: vi.fn(),
846
962
  });
847
963
 
848
- // Mock useFileUrl (won't be used since URL is in map, but mock it anyway)
849
- const useFileUrl = (await import('../../hooks/useFileUrl')).useFileUrl as unknown as vi.Mock;
850
- useFileUrl.mockReturnValue({
851
- url: null,
964
+ renderWithUnifiedAuth(
965
+ <FileDisplay {...baseProps} showFallback fallbackText="IMG" category={FileCategory.IMAGES} />
966
+ );
967
+
968
+ const image = await screen.findByRole('img', { name: /image\.png/i });
969
+
970
+ // Simulate image error
971
+ act(() => {
972
+ const errorEvent = new Event('error', { bubbles: true });
973
+ image.dispatchEvent(errorEvent);
974
+ });
975
+
976
+ // Should show fallback after error
977
+ await waitFor(() => {
978
+ expect(screen.getByText('IMG')).toBeInTheDocument();
979
+ }, { timeout: 2000 });
980
+ });
981
+ });
982
+
983
+ describe('Metadata Display', () => {
984
+ it('shows metadata by default', async () => {
985
+ const file = {
986
+ id: 'fr-1',
987
+ table_name: 'person',
988
+ record_id: 'rec-1',
989
+ organisation_id: 'org-1',
990
+ file_path: 'bucket/path/file.pdf',
991
+ is_public: false,
992
+ file_metadata: { fileName: 'file.pdf', fileSize: 2048, fileType: 'application/pdf' },
993
+ };
994
+
995
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
996
+ useFileDisplay.mockReturnValue({
852
997
  isLoading: false,
853
998
  error: null,
854
- clear: vi.fn(),
999
+ fileUrl: null,
1000
+ fileReference: file,
1001
+ fileReferences: [file],
1002
+ fileCount: 1,
1003
+ fileUrls: new Map(),
1004
+ refetch: vi.fn(),
855
1005
  });
856
1006
 
857
- renderWithUnifiedAuth(<FileDisplay {...baseProps} displayOnly />);
1007
+ renderWithUnifiedAuth(<FileDisplay {...baseProps} category={FileCategory.IMAGES} />);
858
1008
 
859
- const image = await screen.findByRole('img', { name: /image\.png/i });
860
- expect(image).toBeInTheDocument();
861
- expect(screen.queryByRole('link')).not.toBeInTheDocument();
1009
+ expect(await screen.findByText('file.pdf')).toBeInTheDocument();
1010
+ expect(screen.getByText(/application\/pdf/i)).toBeInTheDocument();
862
1011
  });
863
1012
 
864
- it('uses wrapper behavior when showDelete is true', async () => {
865
- const pdfFile = {
866
- id: 'fr-pdf',
1013
+ it('hides metadata when showMetadata is false', async () => {
1014
+ const file = {
1015
+ id: 'fr-1',
867
1016
  table_name: 'person',
868
1017
  record_id: 'rec-1',
869
1018
  organisation_id: 'org-1',
870
- file_path: 'bucket/path/doc.pdf',
1019
+ file_path: 'bucket/path/file.pdf',
871
1020
  is_public: false,
872
- file_metadata: { fileName: 'doc.pdf', fileSize: 2048, fileType: 'application/pdf' },
1021
+ file_metadata: { fileName: 'file.pdf', fileSize: 2048, fileType: 'application/pdf' },
873
1022
  };
874
1023
 
875
- const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
1024
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
876
1025
  useFileDisplay.mockReturnValue({
877
1026
  isLoading: false,
878
1027
  error: null,
879
- fileUrl: 'https://signed.example.com/doc.pdf',
880
- fileReference: pdfFile,
881
- fileReferences: [pdfFile],
1028
+ fileUrl: null,
1029
+ fileReference: file,
1030
+ fileReferences: [file],
882
1031
  fileCount: 1,
883
- fileUrls: new Map([['fr-pdf', 'https://signed.example.com/doc.pdf']]),
1032
+ fileUrls: new Map(),
884
1033
  refetch: vi.fn(),
885
1034
  });
886
1035
 
887
- // Mock useFileUrl (won't be used since URL is in map, but mock it anyway)
888
- const useFileUrl = (await import('../../hooks/useFileUrl')).useFileUrl as unknown as vi.Mock;
889
- useFileUrl.mockReturnValue({
890
- url: null,
1036
+ renderWithUnifiedAuth(<FileDisplay {...baseProps} category={FileCategory.IMAGES} showMetadata={false} />);
1037
+
1038
+ // File name might still be in alt text or title, but metadata section should not be visible
1039
+ const figcaption = document.querySelector('figcaption');
1040
+ expect(figcaption).not.toBeInTheDocument();
1041
+ });
1042
+ });
1043
+
1044
+ describe('Children Rendering', () => {
1045
+ it('renders children in empty state', async () => {
1046
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
1047
+ useFileDisplay.mockReturnValue({
891
1048
  isLoading: false,
892
1049
  error: null,
893
- clear: vi.fn(),
1050
+ fileUrl: null,
1051
+ fileReference: null,
1052
+ fileReferences: [],
1053
+ fileCount: 0,
1054
+ fileUrls: new Map(),
1055
+ refetch: vi.fn(),
894
1056
  });
895
1057
 
896
- renderWithUnifiedAuth(<FileDisplay {...baseProps} displayOnly showDelete />);
1058
+ renderWithUnifiedAuth(
1059
+ <FileDisplay {...baseProps}>
1060
+ <button>Custom Action</button>
1061
+ </FileDisplay>
1062
+ );
897
1063
 
898
- // Should show wrapper with delete button, not simplified link
899
- expect(screen.getByText('doc.pdf')).toBeInTheDocument();
900
- expect(screen.getByRole('button', { name: /Delete file/i })).toBeInTheDocument();
901
- // Should not be a simplified link (no link with target="_blank" in simplified form)
902
- const link = screen.queryByRole('link', { name: /Open.*in new tab/i });
903
- expect(link).not.toBeInTheDocument();
1064
+ expect(screen.getByRole('button', { name: 'Custom Action' })).toBeInTheDocument();
904
1065
  });
905
1066
 
906
- it('renders document links in public context', async () => {
907
- mockUseIsPublicPage.mockReturnValueOnce(true);
908
-
909
- const pdfFile = {
910
- id: 'pub-pdf',
911
- table_name: 'event',
912
- record_id: 'event-1',
1067
+ it('renders children in single file display', async () => {
1068
+ const file = {
1069
+ id: 'fr-1',
1070
+ table_name: 'person',
1071
+ record_id: 'rec-1',
913
1072
  organisation_id: 'org-1',
914
- file_path: 'bucket/path/public-doc.pdf',
915
- is_public: true,
916
- file_metadata: { fileName: 'public-doc.pdf', fileSize: 2048, fileType: 'application/pdf' },
1073
+ file_path: 'bucket/path/file.png',
1074
+ is_public: false,
1075
+ file_metadata: { fileName: 'file.png', fileSize: 1024, fileType: 'image/png' },
917
1076
  };
918
1077
 
919
- const fileUrlsMap = new Map<string, string>([['pub-pdf', 'https://public.example.com/public-doc.pdf']]);
920
- const usePublicFileDisplay = (await import('../../hooks/public/usePublicFileDisplay')).usePublicFileDisplay as unknown as vi.Mock;
921
- usePublicFileDisplay.mockReturnValue({
1078
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
1079
+ useFileDisplay.mockReturnValue({
922
1080
  isLoading: false,
923
1081
  error: null,
924
- fileUrl: 'https://public.example.com/public-doc.pdf',
925
- fileReference: pdfFile,
926
- fileReferences: [pdfFile],
1082
+ fileUrl: 'https://example.com/file.png',
1083
+ fileReference: file,
1084
+ fileReferences: [file],
927
1085
  fileCount: 1,
928
- fileUrls: fileUrlsMap,
1086
+ fileUrls: new Map([['fr-1', 'https://example.com/file.png']]),
929
1087
  refetch: vi.fn(),
930
1088
  });
931
1089
 
932
- renderWithPublicContext(
933
- <FileDisplay {...baseProps} displayOnly />,
934
- { supabase }
1090
+ renderWithUnifiedAuth(
1091
+ <FileDisplay {...baseProps} category={FileCategory.IMAGES}>
1092
+ <button>Custom Button</button>
1093
+ </FileDisplay>
935
1094
  );
936
1095
 
937
- const link = await screen.findByRole('link', { name: /Open public-doc\.pdf in new tab/i });
938
- expect(link).toBeInTheDocument();
939
- expect(link).toHaveAttribute('href', 'https://public.example.com/public-doc.pdf');
940
- expect(link).toHaveAttribute('target', '_blank');
941
- expect(link).toHaveAttribute('rel', 'noopener noreferrer');
1096
+ expect(await screen.findByRole('img', { name: /file\.png/i })).toBeInTheDocument();
1097
+ expect(screen.getByRole('button', { name: 'Custom Button' })).toBeInTheDocument();
942
1098
  });
943
1099
 
944
- it('includes proper ARIA label for accessibility', async () => {
945
- const pdfFile = {
946
- id: 'fr-pdf',
1100
+ it('renders children in displayOnly mode when enableChildren is true', async () => {
1101
+ const file = {
1102
+ id: 'fr-1',
947
1103
  table_name: 'person',
948
1104
  record_id: 'rec-1',
949
1105
  organisation_id: 'org-1',
950
- file_path: 'bucket/path/accessible.pdf',
1106
+ file_path: 'bucket/path/file.png',
951
1107
  is_public: false,
952
- file_metadata: { fileName: 'accessible.pdf', fileSize: 2048, fileType: 'application/pdf' },
1108
+ file_metadata: { fileName: 'file.png', fileSize: 1024, fileType: 'image/png' },
953
1109
  };
954
1110
 
955
- const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
1111
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
956
1112
  useFileDisplay.mockReturnValue({
957
1113
  isLoading: false,
958
1114
  error: null,
959
- fileUrl: 'https://signed.example.com/accessible.pdf',
960
- fileReference: pdfFile,
961
- fileReferences: [pdfFile],
1115
+ fileUrl: 'https://example.com/file.png',
1116
+ fileReference: file,
1117
+ fileReferences: [file],
962
1118
  fileCount: 1,
963
- fileUrls: new Map([['fr-pdf', 'https://signed.example.com/accessible.pdf']]),
1119
+ fileUrls: new Map([['fr-1', 'https://example.com/file.png']]),
964
1120
  refetch: vi.fn(),
965
1121
  });
966
1122
 
967
- // Mock useFileUrl (won't be used since URL is in map, but mock it anyway)
968
- const useFileUrl = (await import('../../hooks/useFileUrl')).useFileUrl as unknown as vi.Mock;
969
- useFileUrl.mockReturnValue({
970
- url: null,
1123
+ renderWithUnifiedAuth(
1124
+ <FileDisplay {...baseProps} displayOnly enableChildren>
1125
+ <button>Child Button</button>
1126
+ </FileDisplay>
1127
+ );
1128
+
1129
+ expect(await screen.findByRole('img', { name: /file\.png/i })).toBeInTheDocument();
1130
+ expect(screen.getByRole('button', { name: 'Child Button' })).toBeInTheDocument();
1131
+ });
1132
+ });
1133
+
1134
+ describe('Error Handling', () => {
1135
+ it('uses custom error component when provided', async () => {
1136
+ const CustomError = ({ error, retry }: { error: Error | string | null; retry?: () => void }) => (
1137
+ <div data-testid="custom-error">
1138
+ <p>Custom Error: {error instanceof Error ? error.message : String(error)}</p>
1139
+ {retry && <button onClick={retry}>Retry</button>}
1140
+ </div>
1141
+ );
1142
+
1143
+ const refetch = vi.fn();
1144
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
1145
+ useFileDisplay.mockReturnValue({
971
1146
  isLoading: false,
972
- error: null,
973
- clear: vi.fn(),
1147
+ error: new Error('Test error'),
1148
+ fileUrl: null,
1149
+ fileReference: null,
1150
+ fileReferences: [],
1151
+ fileCount: 0,
1152
+ fileUrls: new Map(),
1153
+ refetch,
974
1154
  });
975
1155
 
976
- renderWithUnifiedAuth(<FileDisplay {...baseProps} displayOnly />);
1156
+ renderWithUnifiedAuth(<FileDisplay {...baseProps} errorComponent={CustomError} />);
977
1157
 
978
- const link = await screen.findByRole('link', { name: /Open accessible\.pdf in new tab/i });
979
- expect(link).toHaveAttribute('aria-label', 'Open accessible.pdf in new tab');
1158
+ expect(screen.getByTestId('custom-error')).toBeInTheDocument();
1159
+ expect(screen.getByText(/Custom Error: Test error/i)).toBeInTheDocument();
1160
+
1161
+ const retryButton = screen.getByRole('button', { name: 'Retry' });
1162
+ await userEvent.click(retryButton);
1163
+ expect(refetch).toHaveBeenCalled();
980
1164
  });
981
1165
 
982
- it('uses fallback text "Document" when fileName is missing', async () => {
983
- const pdfFile = {
984
- id: 'fr-pdf',
1166
+ it('handles string error messages', async () => {
1167
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
1168
+ useFileDisplay.mockReturnValue({
1169
+ isLoading: false,
1170
+ error: 'String error message',
1171
+ fileUrl: null,
1172
+ fileReference: null,
1173
+ fileReferences: [],
1174
+ fileCount: 0,
1175
+ fileUrls: new Map(),
1176
+ refetch: vi.fn(),
1177
+ });
1178
+
1179
+ renderWithUnifiedAuth(<FileDisplay {...baseProps} />);
1180
+
1181
+ expect(screen.getByText(/Error loading file: String error message/i)).toBeInTheDocument();
1182
+ });
1183
+ });
1184
+
1185
+ describe('Category Filtering', () => {
1186
+ it('filters files by category when category is specified', async () => {
1187
+ const imageFile = {
1188
+ id: 'fr-img',
985
1189
  table_name: 'person',
986
1190
  record_id: 'rec-1',
987
1191
  organisation_id: 'org-1',
988
- file_path: 'bucket/path/file.pdf',
1192
+ file_path: 'bucket/path/image.png',
989
1193
  is_public: false,
990
- file_metadata: { fileName: '', fileSize: 2048, fileType: 'application/pdf' },
1194
+ file_metadata: { fileName: 'image.png', fileSize: 1024, fileType: 'image/png', category: FileCategory.IMAGES },
991
1195
  };
992
1196
 
993
- const useFileDisplay = (await import('../../hooks/useFileDisplay')).useFileDisplay as unknown as vi.Mock;
1197
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
994
1198
  useFileDisplay.mockReturnValue({
995
1199
  isLoading: false,
996
1200
  error: null,
997
- fileUrl: 'https://signed.example.com/file.pdf',
998
- fileReference: pdfFile,
999
- fileReferences: [pdfFile],
1201
+ fileUrl: 'https://example.com/image.png',
1202
+ fileReference: imageFile,
1203
+ fileReferences: [imageFile],
1000
1204
  fileCount: 1,
1001
- fileUrls: new Map([['fr-pdf', 'https://signed.example.com/file.pdf']]),
1205
+ fileUrls: new Map([['fr-img', 'https://example.com/image.png']]),
1002
1206
  refetch: vi.fn(),
1003
1207
  });
1004
1208
 
1005
- // Mock useFileUrl (won't be used since URL is in map, but mock it anyway)
1006
- const useFileUrl = (await import('../../hooks/useFileUrl')).useFileUrl as unknown as vi.Mock;
1007
- useFileUrl.mockReturnValue({
1008
- url: null,
1209
+ renderWithUnifiedAuth(<FileDisplay {...baseProps} category={FileCategory.IMAGES} />);
1210
+
1211
+ expect(await screen.findByRole('img', { name: /image\.png/i })).toBeInTheDocument();
1212
+ });
1213
+ });
1214
+
1215
+ describe('Organisation ID Handling', () => {
1216
+ it('handles undefined organisation_id', async () => {
1217
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
1218
+ useFileDisplay.mockReturnValue({
1009
1219
  isLoading: false,
1010
1220
  error: null,
1011
- clear: vi.fn(),
1221
+ fileUrl: null,
1222
+ fileReference: null,
1223
+ fileReferences: [],
1224
+ fileCount: 0,
1225
+ fileUrls: new Map(),
1226
+ refetch: vi.fn(),
1012
1227
  });
1013
1228
 
1014
- renderWithUnifiedAuth(<FileDisplay {...baseProps} displayOnly />);
1229
+ renderWithUnifiedAuth(<FileDisplay table_name="person" record_id="rec-1" />);
1015
1230
 
1016
- const link = await screen.findByRole('link', { name: /Open Document in new tab/i });
1017
- expect(link).toHaveTextContent('Document');
1231
+ expect(screen.getByText(/No files found/i)).toBeInTheDocument();
1232
+ });
1233
+
1234
+ it('handles null organisation_id', async () => {
1235
+ const useFileDisplay = (await import('./useFileDisplay')).useFileDisplay as unknown as vi.Mock;
1236
+ useFileDisplay.mockReturnValue({
1237
+ isLoading: false,
1238
+ error: null,
1239
+ fileUrl: null,
1240
+ fileReference: null,
1241
+ fileReferences: [],
1242
+ fileCount: 0,
1243
+ fileUrls: new Map(),
1244
+ refetch: vi.fn(),
1245
+ });
1246
+
1247
+ renderWithUnifiedAuth(<FileDisplay table_name="person" record_id="rec-1" organisation_id={null} />);
1248
+
1249
+ expect(screen.getByText(/No files found/i)).toBeInTheDocument();
1018
1250
  });
1019
1251
  });
1020
1252
  });