@jmruthers/pace-core 0.6.10 → 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 (726) 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 +13 -3
  5. package/audit-tool/audits/03-architecture.cjs +78 -4
  6. package/audit-tool/audits/04-code-quality.cjs +9 -2
  7. package/audit-tool/audits/05-styling.cjs +19 -7
  8. package/audit-tool/audits/06-security-rbac.cjs +105 -14
  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 +1 -0
  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 +41 -7
  19. package/cursor-rules/06-security-rbac.mdc +2 -1
  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-SAXFG4XI.js → DataTable-EFYP2QLE.js} +10 -7
  24. package/dist/{InactivityServiceProvider-DHryoh6K.d.ts → InactivityServiceProvider-BbxwwDz1.d.ts} +10 -1
  25. package/dist/{UnifiedAuthProvider-CiBAl9-s.d.ts → UnifiedAuthProvider-Bkt_tzdS.d.ts} +56 -24
  26. package/dist/{api-F47QJ7FX.js → api-BZR2CYXL.js} +3 -2
  27. package/dist/api-result-USV1Czr-.d.ts +51 -0
  28. package/dist/{audit-Z6ZZBWLU.js → audit-HI2DHUVU.js} +2 -1
  29. package/dist/{auth-BZOJqrdd.d.ts → auth-JvdRVaud.d.ts} +1 -1
  30. package/dist/{chunk-KSNLMI7N.js → chunk-2DL2WSOE.js} +1 -155
  31. package/dist/{chunk-MPY44PWB.js → chunk-2OEVOGGR.js} +4648 -3560
  32. package/dist/chunk-44CNXN4P.js +15 -0
  33. package/dist/{chunk-Y4PF6HIM.js → chunk-4R3T5ENU.js} +867 -786
  34. package/dist/{chunk-LNHFAF4X.js → chunk-7A6IMHH2.js} +289 -247
  35. package/dist/chunk-CU2BU2MQ.js +2 -0
  36. package/dist/{chunk-JJEYZ3DX.js → chunk-D6BMFMQZ.js} +37 -2
  37. package/dist/{chunk-BCTXBU6U.js → chunk-ENLXB7GP.js} +88 -71
  38. package/dist/{chunk-FBZ7U3ID.js → chunk-J2KQK6DG.js} +937 -987
  39. package/dist/{chunk-TFIPNIPE.js → chunk-KJXRL3XE.js} +3300 -2245
  40. package/dist/{chunk-3GWSPISD.js → chunk-L5LFKKLJ.js} +1 -1
  41. package/dist/{chunk-X5EAU5G7.js → chunk-PCSHBLPB.js} +132 -114
  42. package/dist/{chunk-NIU6DPQV.js → chunk-QRYSEPHB.js} +2 -0
  43. package/dist/{chunk-KYURMOQM.js → chunk-V7FTM2LU.js} +423 -320
  44. package/dist/chunk-WY6Y7KC3.js +264 -0
  45. package/dist/{chunk-FN52B75D.js → chunk-XOJME5T7.js} +176 -15
  46. package/dist/{chunk-7YDC7LMU.js → chunk-XPFVT3GN.js} +71 -66
  47. package/dist/{chunk-66R6RLUZ.js → chunk-YFTFFJIV.js} +3 -3
  48. package/dist/{chunk-W46INAVW.js → chunk-YYTWKVHO.js} +688 -570
  49. package/dist/components.d.ts +8 -7
  50. package/dist/components.js +17 -15
  51. package/dist/{database.generated-DT8JTZiP.d.ts → database.generated-qkdoiVrJ.d.ts} +45 -10
  52. package/dist/eslint-rules/index.cjs +3 -0
  53. package/dist/eslint-rules/rules/03-architecture.cjs +74 -0
  54. package/dist/eslint-rules/rules/06-security-rbac.cjs +74 -0
  55. package/dist/{event-WTAQuGcq.d.ts → event-BfCox3N2.d.ts} +36 -10
  56. package/dist/{file-reference-BavO2eQj.d.ts → file-reference-DU1hcawx.d.ts} +29 -13
  57. package/dist/hooks.d.ts +22 -9
  58. package/dist/hooks.js +34 -25
  59. package/dist/icons/index.d.ts +1 -0
  60. package/dist/icons/index.js +1 -0
  61. package/dist/index.d.ts +66 -177
  62. package/dist/index.js +316 -340
  63. package/dist/pagination-BW1mqywp.d.ts +201 -0
  64. package/dist/providers.d.ts +6 -5
  65. package/dist/providers.js +5 -3
  66. package/dist/rbac/index.d.ts +123 -138
  67. package/dist/rbac/index.js +10 -8
  68. package/dist/theming/runtime.d.ts +19 -2
  69. package/dist/theming/runtime.js +1 -1
  70. package/dist/{timezone-K-ptz3HO.d.ts → timezone-BTWWXKVY.d.ts} +1 -1
  71. package/dist/types.d.ts +17 -10
  72. package/dist/types.js +1 -0
  73. package/dist/{usePublicPageContext-vxBlEHO9.d.ts → usePublicPageContext-B91dGYW1.d.ts} +433 -356
  74. package/dist/{usePublicRouteParams-G3Ks53mk.d.ts → usePublicRouteParams-BgV6VhMi.d.ts} +73 -4
  75. package/dist/utils.d.ts +163 -145
  76. package/dist/utils.js +42 -25
  77. package/docs/api/modules.md +782 -643
  78. package/docs/api-reference/rpc-functions.md +12 -3
  79. package/docs/core-concepts/rbac-system.md +8 -0
  80. package/docs/getting-started/cursor-rules.md +17 -20
  81. package/docs/getting-started/dependencies.md +1 -1
  82. package/docs/getting-started/setup.md +235 -0
  83. package/docs/implementation-guides/authentication.md +27 -0
  84. package/docs/implementation-guides/data-tables.md +176 -3
  85. package/docs/migration/ApiResult-migration.md +25 -0
  86. package/docs/rbac/api-reference.md +33 -31
  87. package/docs/standards/0-standards-overview.md +50 -15
  88. package/docs/standards/1-pace-core-compliance-standards.md +62 -57
  89. package/docs/standards/2-project-structure-standards.md +33 -16
  90. package/docs/standards/3-architecture-standards.md +41 -1
  91. package/docs/standards/4-code-quality-standards.md +26 -6
  92. package/docs/standards/5-styling-standards.md +35 -1
  93. package/docs/standards/6-security-rbac-standards.md +66 -0
  94. package/docs/standards/7-api-tech-stack-standards.md +25 -14
  95. package/docs/standards/8-testing-documentation-standards.md +31 -0
  96. package/docs/standards/9-operations-standards.md +19 -0
  97. package/docs/standards/README.md +20 -201
  98. package/docs/testing/test-setup-for-consumers.md +2 -0
  99. package/docs/troubleshooting/common-issues.md +17 -1
  100. package/docs/troubleshooting/organisation-context-setup.md +8 -0
  101. package/docs/troubleshooting/print-event-name-css-variable-analysis.md +217 -0
  102. package/eslint-config-pace-core.cjs +20 -0
  103. package/package.json +14 -20
  104. package/scripts/{build-docs-incremental.js → build-docs.js} +3 -2
  105. package/scripts/setup.cjs +536 -0
  106. package/scripts/validate.cjs +480 -0
  107. package/src/__tests__/helpers/{__tests__/component-test-utils.test.tsx → component-test-utils.test.tsx} +3 -3
  108. package/src/__tests__/helpers/{__tests__/optimized-test-setup.test.ts → optimized-test-setup.test.ts} +2 -2
  109. package/src/__tests__/helpers/{__tests__/supabaseMock.test.ts → supabaseMock.test.ts} +2 -2
  110. package/src/__tests__/helpers/{__tests__/test-providers.test.tsx → test-providers.test.tsx} +1 -1
  111. package/src/__tests__/helpers/test-providers.tsx +37 -39
  112. package/src/__tests__/helpers/{__tests__/test-utils.test.tsx → test-utils.test.tsx} +4 -3
  113. package/src/__tests__/helpers/{__tests__/timer-utils.test.ts → timer-utils.test.ts} +2 -2
  114. package/src/assets/app-icons/index.test.ts +304 -0
  115. package/src/components/AddressField/AddressField.test.tsx +1 -1
  116. package/src/components/AddressField/AddressField.tsx +238 -212
  117. package/src/components/Button/Button.tsx +1 -1
  118. package/src/components/Card/Card.test.tsx +172 -17
  119. package/src/components/Card/Card.tsx +19 -10
  120. package/src/components/ContextSelector/ContextSelector.internals.tsx +204 -0
  121. package/src/components/ContextSelector/{__tests__/ContextSelector.test.tsx → ContextSelector.test.tsx} +6 -6
  122. package/src/components/ContextSelector/ContextSelector.tsx +66 -280
  123. package/src/components/ContextSelector/ContextSelector.types.ts +35 -0
  124. package/src/components/ContextSelector/useContextSelectorState.tsx +195 -0
  125. package/src/components/DataTable/AUDIT_REPORT.md +59 -44
  126. package/src/components/DataTable/{__tests__/DataTable.comprehensive.test.tsx → DataTable.comprehensive.test.tsx} +6 -6
  127. package/src/components/DataTable/{__tests__/DataTable.default-state.test.tsx → DataTable.default-state.test.tsx} +5 -5
  128. package/src/components/DataTable/{__tests__/DataTable.export.test.tsx → DataTable.export.test.tsx} +10 -10
  129. package/src/components/DataTable/{__tests__/DataTable.grouping-aggregation.test.tsx → DataTable.grouping-aggregation.test.tsx} +6 -6
  130. package/src/components/DataTable/{__tests__/DataTable.hooks.test.tsx → DataTable.hooks.test.tsx} +6 -6
  131. package/src/components/DataTable/{__tests__/DataTable.select-label-display.test.tsx → DataTable.select-label-display.test.tsx} +6 -6
  132. package/src/components/DataTable/DataTable.test.tsx +787 -416
  133. package/src/components/DataTable/DataTable.tsx +12 -12
  134. package/src/components/DataTable/DataTableCore.integration.test.tsx +458 -0
  135. package/src/components/DataTable/{__tests__/DataTableCore.test-setup.ts → DataTableCore.test-setup.ts} +10 -9
  136. package/src/components/DataTable/{__tests__/DataTableCore.test.tsx → DataTableCore.test.tsx} +8 -8
  137. package/src/components/DataTable/{__tests__/README.md → README.md} +17 -7
  138. package/src/components/DataTable/TESTING.md +101 -0
  139. package/src/components/DataTable/{__tests__/a11y.basic.test.tsx → a11y.basic.test.tsx} +34 -34
  140. package/src/components/DataTable/components/DataTableCore.tsx +104 -864
  141. package/src/components/DataTable/components/{__tests__/GroupingDropdown.test.tsx → GroupingDropdown.test.tsx} +17 -8
  142. package/src/components/DataTable/components/GroupingDropdown.tsx +2 -2
  143. package/src/components/DataTable/components/ImportModal.tsx +61 -559
  144. package/src/components/DataTable/components/ImportModalFileSection.tsx +148 -0
  145. package/src/components/DataTable/context/{__tests__/DataTableContext.test.tsx → DataTableContext.test.tsx} +2 -2
  146. package/src/components/DataTable/context/DataTableContext.tsx +7 -6
  147. package/src/components/DataTable/core/{__tests__/ColumnFactory.test.ts → ColumnFactory.test.ts} +2 -2
  148. package/src/components/DataTable/hooks/{__tests__/useColumnOrderPersistence.test.ts → useColumnOrderPersistence.test.ts} +2 -2
  149. package/src/components/DataTable/hooks/{__tests__/useColumnVisibilityPersistence.test.ts → useColumnVisibilityPersistence.test.ts} +2 -2
  150. package/src/components/DataTable/hooks/{__tests__/useDataTableConfiguration.test.ts → useDataTableConfiguration.test.ts} +3 -3
  151. package/src/components/DataTable/hooks/useDataTableConfiguration.ts +14 -2
  152. package/src/components/DataTable/hooks/{__tests__/useDataTableDataPipeline.test.ts → useDataTableDataPipeline.test.ts} +6 -6
  153. package/src/components/DataTable/hooks/useDataTableDeletionBatching.test.ts +127 -0
  154. package/src/components/DataTable/hooks/useDataTableDeletionBatching.ts +106 -0
  155. package/src/components/DataTable/hooks/useDataTableEffectiveActions.test.ts +461 -0
  156. package/src/components/DataTable/hooks/useDataTableEffectiveActions.ts +238 -0
  157. package/src/components/DataTable/hooks/useDataTableLayoutHandlers.test.ts +296 -0
  158. package/src/components/DataTable/hooks/useDataTableLayoutHandlers.ts +175 -0
  159. package/src/components/DataTable/hooks/useDataTablePaginationSync.test.ts +203 -0
  160. package/src/components/DataTable/hooks/useDataTablePaginationSync.ts +109 -0
  161. package/src/components/DataTable/hooks/{__tests__/useDataTablePermissions.test.ts → useDataTablePermissions.test.ts} +11 -11
  162. package/src/components/DataTable/hooks/useDataTablePermissions.ts +79 -247
  163. package/src/components/DataTable/hooks/useDataTablePipeline.test.tsx +219 -0
  164. package/src/components/DataTable/hooks/useDataTablePipeline.tsx +239 -0
  165. package/src/components/DataTable/hooks/useDataTableRenderGuard.test.tsx +316 -0
  166. package/src/components/DataTable/hooks/useDataTableRenderGuard.tsx +195 -0
  167. package/src/components/DataTable/hooks/useDataTableScope.test.ts +110 -0
  168. package/src/components/DataTable/hooks/useDataTableScope.ts +123 -0
  169. package/src/components/DataTable/hooks/{__tests__/useDataTableState.test.ts → useDataTableState.test.ts} +47 -5
  170. package/src/components/DataTable/hooks/useDataTableState.ts +145 -94
  171. package/src/components/DataTable/hooks/useDataTableStateAndPersistence.test.ts +277 -0
  172. package/src/components/DataTable/hooks/useDataTableStateAndPersistence.ts +222 -0
  173. package/src/components/DataTable/hooks/useDataTableSuperAdmin.test.ts +93 -0
  174. package/src/components/DataTable/hooks/useDataTableSuperAdmin.ts +86 -0
  175. package/src/components/DataTable/hooks/useDataTableTableInstance.test.ts +185 -0
  176. package/src/components/DataTable/hooks/useDataTableTableInstance.ts +178 -0
  177. package/src/components/DataTable/hooks/{__tests__/useEffectiveColumnOrder.test.ts → useEffectiveColumnOrder.test.ts} +2 -2
  178. package/src/components/DataTable/hooks/{__tests__/useHierarchicalState.test.ts → useHierarchicalState.test.ts} +2 -2
  179. package/src/components/DataTable/{components/hooks → hooks}/useImportModalFocus.test.ts +3 -3
  180. package/src/components/DataTable/{components/hooks → hooks}/useImportModalFocus.ts +2 -2
  181. package/src/components/DataTable/hooks/useImportModalState.test.ts +390 -0
  182. package/src/components/DataTable/hooks/useImportModalState.ts +345 -0
  183. package/src/components/DataTable/hooks/{__tests__/useKeyboardNavigation.test.ts → useKeyboardNavigation.test.ts} +3 -3
  184. package/src/components/DataTable/hooks/useKeyboardNavigation.ts +309 -269
  185. package/src/components/DataTable/{components/hooks → hooks}/usePermissionTracking.test.ts +3 -3
  186. package/src/components/DataTable/{components/hooks → hooks}/usePermissionTracking.ts +3 -3
  187. package/src/components/DataTable/hooks/{__tests__/useServerSideDataEffect.test.ts → useServerSideDataEffect.test.ts} +2 -2
  188. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +14 -3
  189. package/src/components/DataTable/hooks/{__tests__/useTableColumns.test.ts → useTableColumns.test.ts} +2 -2
  190. package/src/components/DataTable/hooks/{__tests__/useTableHandlers.test.ts → useTableHandlers.test.ts} +25 -4
  191. package/src/components/DataTable/hooks/useTableHandlers.ts +5 -2
  192. package/src/components/DataTable/index.ts +18 -17
  193. package/src/components/DataTable/{__tests__/keyboard.test.tsx → keyboard.test.tsx} +41 -63
  194. package/src/components/DataTable/{__tests__/mocks → mocks}/MockRBACProvider.tsx +1 -1
  195. package/src/components/DataTable/{__tests__/pagination.modes.test.tsx → pagination.modes.test.tsx} +6 -6
  196. package/src/components/DataTable/{__tests__/ssr.strict-mode.test.tsx → ssr.strict-mode.test.tsx} +2 -2
  197. package/src/components/DataTable/{__tests__/styles.test.ts → styles.test.ts} +1 -4
  198. package/src/components/DataTable/styles.ts +0 -1
  199. package/src/components/DataTable/test-utils/MockDataTableComponents.tsx +55 -0
  200. package/src/components/DataTable/{__tests__/test-utils → test-utils}/dataFactories.ts +2 -2
  201. package/src/components/DataTable/test-utils/featureConfig.ts +10 -0
  202. package/src/components/DataTable/{__tests__/test-utils/sharedTestUtils.tsx → test-utils/sharedTestUtils.ts} +97 -66
  203. package/src/components/DataTable/{__tests__/test-utils.ts → test-utils.ts} +1 -1
  204. package/src/components/DataTable/types/actions.ts +71 -0
  205. package/src/components/DataTable/types/base.ts +39 -0
  206. package/src/components/DataTable/types/columns.ts +125 -0
  207. package/src/components/DataTable/types/export.ts +32 -0
  208. package/src/components/DataTable/types/features.ts +81 -0
  209. package/src/components/DataTable/types/hierarchical.ts +44 -0
  210. package/src/components/DataTable/types/index.ts +43 -0
  211. package/src/components/DataTable/types/pagination.ts +85 -0
  212. package/src/components/DataTable/types/performance.ts +47 -0
  213. package/src/components/DataTable/types/props.ts +62 -0
  214. package/src/components/DataTable/types/rbac.ts +45 -0
  215. package/src/components/DataTable/{components/__tests__ → ui/layout}/DataTableCore.test.tsx +430 -28
  216. package/src/components/DataTable/ui/layout/DataTableCore.tsx +345 -0
  217. package/src/components/DataTable/{components/__tests__ → ui/layout}/DataTableErrorBoundary.test.tsx +4 -4
  218. package/src/components/DataTable/{components → ui/layout}/DataTableErrorBoundary.tsx +7 -7
  219. package/src/components/DataTable/ui/layout/DataTableLayout.test.tsx +1352 -0
  220. package/src/components/DataTable/ui/layout/DataTableLayout.tsx +661 -0
  221. package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.test.tsx +91 -0
  222. package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.tsx +43 -0
  223. package/src/components/DataTable/ui/modals/DataTableModals.test.tsx +749 -0
  224. package/src/components/DataTable/{components → ui/modals}/DataTableModals.tsx +36 -28
  225. package/src/components/DataTable/ui/modals/ImportModal.test.tsx +1834 -0
  226. package/src/components/DataTable/ui/modals/ImportModal.tsx +197 -0
  227. package/src/components/DataTable/ui/modals/ImportModalFailedRowsSection.tsx +60 -0
  228. package/src/components/DataTable/ui/modals/ImportModalFileSection.tsx +148 -0
  229. package/src/components/DataTable/ui/modals/ImportModalPreviewSection.tsx +60 -0
  230. package/src/components/DataTable/ui/modals/ImportModalSummarySection.tsx +59 -0
  231. package/src/components/DataTable/ui/modals/importModalPersistence.ts +73 -0
  232. package/src/components/DataTable/{components/__tests__ → ui/shared}/AccessDeniedPage.test.tsx +2 -2
  233. package/src/components/DataTable/{components → ui/shared}/AccessDeniedPage.tsx +2 -2
  234. package/src/components/DataTable/{components/__tests__ → ui/shared}/ActionButtons.test.tsx +6 -4
  235. package/src/components/DataTable/{components → ui/shared}/ActionButtons.tsx +4 -4
  236. package/src/components/DataTable/{components/__tests__ → ui/shared}/ColumnFilter.test.tsx +29 -16
  237. package/src/components/DataTable/{components → ui/shared}/ColumnFilter.tsx +4 -4
  238. package/src/components/DataTable/{components/__tests__ → ui/shared}/PaginationControls.test.tsx +38 -16
  239. package/src/components/DataTable/{components → ui/shared}/PaginationControls.tsx +21 -15
  240. package/src/components/DataTable/{components/__tests__ → ui/shared}/SortIndicator.test.tsx +2 -2
  241. package/src/components/DataTable/{components → ui/shared}/SortIndicator.tsx +1 -1
  242. package/src/components/DataTable/{components/__tests__ → ui/table}/EditFields.test.tsx +3 -3
  243. package/src/components/DataTable/{components → ui/table}/EditFields.tsx +138 -69
  244. package/src/components/DataTable/{components/__tests__ → ui/table}/EditableRow.test.tsx +36 -27
  245. package/src/components/DataTable/{components → ui/table}/EditableRow.tsx +86 -104
  246. package/src/components/DataTable/{components/__tests__ → ui/table}/EmptyState.test.tsx +2 -62
  247. package/src/components/DataTable/{components → ui/table}/EmptyState.tsx +7 -15
  248. package/src/components/DataTable/{components/__tests__ → ui/table}/FilterRow.test.tsx +5 -4
  249. package/src/components/DataTable/{components → ui/table}/FilterRow.tsx +3 -3
  250. package/src/components/DataTable/{components/__tests__ → ui/table}/LoadingState.test.tsx +6 -10
  251. package/src/components/DataTable/{components → ui/table}/LoadingState.tsx +4 -4
  252. package/src/components/DataTable/{components/__tests__ → ui/table}/RowComponent.test.tsx +412 -17
  253. package/src/components/DataTable/{components → ui/table}/RowComponent.tsx +183 -177
  254. package/src/components/DataTable/{components/__tests__ → ui/table}/UnifiedTableBody.test.tsx +425 -16
  255. package/src/components/DataTable/ui/table/UnifiedTableBody.tsx +440 -0
  256. package/src/components/DataTable/{components/__tests__ → ui/table}/cellValueUtils.test.ts +2 -2
  257. package/src/components/DataTable/{components → ui/table}/cellValueUtils.ts +1 -1
  258. package/src/components/DataTable/{components/__tests__ → ui/toolbar}/BulkOperationsDropdown.test.tsx +12 -5
  259. package/src/components/DataTable/{components → ui/toolbar}/BulkOperationsDropdown.tsx +3 -3
  260. package/src/components/DataTable/{components/__tests__ → ui/toolbar}/ColumnVisibilityDropdown.test.tsx +7 -4
  261. package/src/components/DataTable/{components → ui/toolbar}/ColumnVisibilityDropdown.tsx +7 -7
  262. package/src/components/DataTable/{components/__tests__ → ui/toolbar}/DataTableToolbar.test.tsx +4 -4
  263. package/src/components/DataTable/{components → ui/toolbar}/DataTableToolbar.tsx +4 -4
  264. package/src/components/DataTable/ui/toolbar/GroupingDropdown.test.tsx +621 -0
  265. package/src/components/DataTable/ui/toolbar/GroupingDropdown.tsx +107 -0
  266. package/src/components/DataTable/utils/{__tests__/a11yUtils.test.ts → a11yUtils.test.ts} +2 -2
  267. package/src/components/DataTable/utils/{__tests__/aggregationUtils.test.ts → aggregationUtils.test.ts} +3 -3
  268. package/src/components/DataTable/utils/{__tests__/columnUtils.test.ts → columnUtils.test.ts} +2 -2
  269. package/src/components/DataTable/utils/csvParse.test.ts +74 -0
  270. package/src/components/DataTable/utils/csvParse.ts +65 -0
  271. package/src/components/DataTable/utils/{__tests__/errorHandling.test.ts → errorHandling.test.ts} +2 -2
  272. package/src/components/DataTable/utils/{__tests__/exportUtils.test.ts → exportUtils.test.ts} +3 -3
  273. package/src/components/DataTable/utils/{__tests__/flexibleImport.test.ts → flexibleImport.test.ts} +2 -2
  274. package/src/components/DataTable/utils/flexibleImport.ts +3 -186
  275. package/src/components/DataTable/utils/{__tests__/hierarchicalSorting.test.ts → hierarchicalSorting.test.ts} +3 -3
  276. package/src/components/DataTable/utils/{__tests__/hierarchicalUtils.test.ts → hierarchicalUtils.test.ts} +3 -3
  277. package/src/components/DataTable/utils/importDateParser.test.ts +162 -0
  278. package/src/components/DataTable/utils/importDateParser.ts +114 -0
  279. package/src/components/DataTable/utils/importValueParser.test.ts +138 -0
  280. package/src/components/DataTable/utils/importValueParser.ts +91 -0
  281. package/src/components/DataTable/utils/{__tests__/paginationUtils.test.ts → paginationUtils.test.ts} +2 -2
  282. package/src/components/DataTable/utils/paginationUtils.ts +6 -3
  283. package/src/components/DataTable/utils/{__tests__/performanceUtils.test.ts → performanceUtils.test.ts} +3 -3
  284. package/src/components/DataTable/utils/{__tests__/rowUtils.test.ts → rowUtils.test.ts} +3 -3
  285. package/src/components/DataTable/utils/{__tests__/selectFieldUtils.test.ts → selectFieldUtils.test.ts} +66 -3
  286. package/src/components/DataTable/utils/selectFieldUtils.ts +97 -60
  287. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +1 -1
  288. package/src/components/DateTimeField/DateTimeField.test.tsx +1 -1
  289. package/src/components/Dialog/Dialog.test-utils.ts +49 -0
  290. package/src/components/Dialog/Dialog.test.tsx +896 -89
  291. package/src/components/Dialog/Dialog.tsx +174 -882
  292. package/src/components/Dialog/dialogLock.test.ts +238 -0
  293. package/src/components/Dialog/dialogLock.ts +98 -0
  294. package/src/components/Dialog/index.ts +2 -0
  295. package/src/components/Dialog/useDialogDimensions.test.ts +163 -0
  296. package/src/components/Dialog/useDialogDimensions.ts +140 -0
  297. package/src/components/Dialog/useDialogLifecycle.test.ts +358 -0
  298. package/src/components/Dialog/useDialogLifecycle.ts +135 -0
  299. package/src/components/Dialog/useDialogPersistence.test.ts +381 -0
  300. package/src/components/Dialog/useDialogPersistence.ts +357 -0
  301. package/src/components/FileDisplay/FileDisplay.test.tsx +40 -40
  302. package/src/components/FileDisplay/FileDisplay.tsx +24 -656
  303. package/src/components/FileDisplay/FileDisplayContent.test.tsx +395 -0
  304. package/src/components/FileDisplay/FileDisplayContent.tsx +242 -0
  305. package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.test.tsx +74 -0
  306. package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.tsx +38 -0
  307. package/src/components/FileDisplay/FileDisplayEmptyView.test.tsx +33 -0
  308. package/src/components/FileDisplay/FileDisplayEmptyView.tsx +33 -0
  309. package/src/components/FileDisplay/FileDisplayErrorView.test.tsx +71 -0
  310. package/src/components/FileDisplay/FileDisplayErrorView.tsx +50 -0
  311. package/src/components/FileDisplay/FileDisplayLoadingFallbackView.test.tsx +22 -0
  312. package/src/components/FileDisplay/FileDisplayLoadingFallbackView.tsx +22 -0
  313. package/src/components/FileDisplay/FileDisplayLoadingView.test.tsx +21 -0
  314. package/src/components/FileDisplay/FileDisplayLoadingView.tsx +23 -0
  315. package/src/components/FileDisplay/FileDisplayMultipleFilesView.test.tsx +101 -0
  316. package/src/components/FileDisplay/FileDisplayMultipleFilesView.tsx +109 -0
  317. package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.test.tsx +58 -0
  318. package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.tsx +48 -0
  319. package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.test.tsx +111 -0
  320. package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.tsx +270 -0
  321. package/src/components/FileDisplay/FileDisplaySingleImageView.test.tsx +78 -0
  322. package/src/components/FileDisplay/FileDisplaySingleImageView.tsx +67 -0
  323. package/src/components/FileDisplay/fallbackUtils.test.ts +50 -0
  324. package/src/components/FileDisplay/fallbackUtils.ts +44 -0
  325. package/src/components/FileDisplay/fetchFileDisplayData.ts +24 -0
  326. package/src/components/FileDisplay/fetchFileDisplayData.unit.test.ts +183 -0
  327. package/src/components/FileDisplay/fileDisplayUtils.test.ts +58 -0
  328. package/src/components/FileDisplay/fileDisplayUtils.ts +24 -0
  329. package/src/{hooks/__tests__ → components/FileDisplay}/useFileDisplay.test.ts +40 -42
  330. package/src/components/FileDisplay/useFileDisplay.ts +515 -0
  331. package/src/{hooks/__tests__ → components/FileDisplay}/useFileDisplay.unit.test.ts +406 -77
  332. package/src/components/FileDisplay/useFileDisplayData.ts +126 -0
  333. package/src/{hooks/public → components/FileDisplay}/usePublicFileDisplay.test.ts +94 -88
  334. package/src/components/FileDisplay/usePublicFileDisplay.ts +579 -0
  335. package/src/components/FileUpload/FileUpload.test.tsx +16 -10
  336. package/src/components/FileUpload/FileUpload.tsx +107 -525
  337. package/src/components/FileUpload/FileUploadDropZone.tsx +112 -0
  338. package/src/components/FileUpload/FileUploadProgressItem.tsx +86 -0
  339. package/src/components/FileUpload/FileUploadProgressList.tsx +40 -0
  340. package/src/components/FileUpload/useFileUploadManager.test.ts +308 -0
  341. package/src/components/FileUpload/useFileUploadManager.ts +454 -0
  342. package/src/components/FileUpload/useResolvedAppId.test.ts +102 -0
  343. package/src/components/FileUpload/useResolvedAppId.ts +77 -0
  344. package/src/components/Footer/Footer.test.tsx +6 -292
  345. package/src/components/Footer/Footer.tsx +8 -125
  346. package/src/components/Form/Form.test.tsx +44 -27
  347. package/src/components/Form/Form.tsx +64 -287
  348. package/src/components/Form/useFormPersistence.ts +257 -0
  349. package/src/components/Header/Header.test.tsx +17 -18
  350. package/src/components/Header/Header.tsx +10 -1
  351. package/src/components/Input/Input.tsx +1 -1
  352. package/src/components/Label/Label.test.tsx +1 -1
  353. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +1 -1
  354. package/src/components/NavigationMenu/HierarchicalNavItem.tsx +104 -0
  355. package/src/components/NavigationMenu/NavigationMenu.test.tsx +1029 -26
  356. package/src/components/NavigationMenu/NavigationMenu.tsx +61 -361
  357. package/src/components/NavigationMenu/index.ts +6 -1
  358. package/src/components/NavigationMenu/navigationPermissionHelper.ts +188 -0
  359. package/src/components/NavigationMenu/{__tests__/useNavigationFiltering.test.ts → useNavigationFiltering.test.ts} +68 -53
  360. package/src/components/NavigationMenu/useNavigationFiltering.ts +197 -296
  361. package/src/components/NavigationMenu/useNavigationScope.ts +125 -0
  362. package/src/components/PaceAppLayout/PaceAppLayout.edge-cases.test.tsx +77 -62
  363. package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +3 -3
  364. package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +16 -19
  365. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +529 -5
  366. package/src/components/PaceAppLayout/PaceAppLayout.tsx +280 -756
  367. package/src/components/PaceAppLayout/useFilteredNavItems.ts +304 -0
  368. package/src/components/PaceAppLayout/usePaceAppLayoutConfig.ts +142 -0
  369. package/src/components/PaceAppLayout/usePaceAppLayoutGate.tsx +150 -0
  370. package/src/components/PaceAppLayout/usePaceAppLayoutPermissions.ts +162 -0
  371. package/src/components/PaceAppLayout/usePaceAppLayoutScope.ts +79 -0
  372. package/src/components/PaceAppLayout/useRoleBasedRouteAccess.ts +157 -0
  373. package/src/components/PaceAppLayout/useSuperAdminFallback.ts +58 -0
  374. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +31 -25
  375. package/src/components/PaceLoginPage/PaceLoginPage.tsx +31 -122
  376. package/src/components/PaceLoginPage/useLoginAppAccess.ts +153 -0
  377. package/src/components/Progress/Progress.tsx +1 -2
  378. package/src/components/ProtectedRoute/ProtectedRoute.tsx +29 -235
  379. package/src/components/ProtectedRoute/useProtectedRouteState.ts +128 -0
  380. package/src/components/ProtectedRoute/useVisibilityRedirectGrace.ts +89 -0
  381. package/src/components/PublicLayout/PublicLayout.test.tsx +217 -36
  382. package/src/components/PublicLayout/PublicPageLayout.tsx +132 -73
  383. package/src/components/PublicLayout/PublicPageProvider.tsx +5 -1
  384. package/src/components/Select/Select.test.tsx +1 -1
  385. package/src/components/Select/Select.tsx +28 -18
  386. package/src/components/Select/{__tests__/context.test.tsx → context.test.tsx} +3 -3
  387. package/src/components/Select/{utils/__tests__/text.test.tsx → text.test.tsx} +2 -2
  388. package/src/components/Select/{utils/text.ts → text.ts} +1 -1
  389. package/src/components/Select/{hooks/__tests__/useSelectEvents.test.ts → useSelectEvents.test.ts} +5 -5
  390. package/src/components/Select/{hooks/useSelectEvents.ts → useSelectEvents.ts} +2 -2
  391. package/src/components/Select/{hooks/__tests__/useSelectSearch.test.tsx → useSelectSearch.test.tsx} +7 -7
  392. package/src/components/Select/{hooks/useSelectSearch.ts → useSelectSearch.ts} +2 -2
  393. package/src/components/Select/{hooks/__tests__/useSelectState.test.ts → useSelectState.test.ts} +16 -2
  394. package/src/components/Select/{hooks/useSelectState.ts → useSelectState.ts} +3 -3
  395. package/src/components/Table/Table.test.tsx +348 -0
  396. package/src/components/Tabs/Tabs.test.tsx +270 -0
  397. package/src/components/Tabs/Tabs.tsx +1 -1
  398. package/src/components/Toast/Toast.test.tsx +420 -0
  399. package/src/components/{__tests__/index.test.ts → index.test.ts} +2 -2
  400. package/src/constants/{__tests__/performance.test.ts → performance.test.ts} +2 -2
  401. package/src/hooks/{__tests__/ServiceHooks.test.tsx → ServiceHooks.test.tsx} +8 -8
  402. package/src/hooks/{__tests__/hooks.integration.test.tsx → hooks.integration.test.tsx} +11 -11
  403. package/src/hooks/index.ts +7 -4
  404. package/src/hooks/{__tests__/index.unit.test.ts → index.unit.test.ts} +2 -2
  405. package/src/hooks/public/usePublicEvent.test.ts +1 -1
  406. package/src/hooks/public/usePublicEventLogo.test.ts +1 -1
  407. package/src/hooks/public/usePublicRouteParams.test.ts +1 -1
  408. package/src/hooks/services/useAuth.ts +9 -7
  409. package/src/hooks/useAddressAutocomplete.test.ts +22 -22
  410. package/src/hooks/useAddressAutocomplete.ts +90 -75
  411. package/src/hooks/{__tests__/useAppConfig.unit.test.ts → useAppConfig.unit.test.ts} +328 -22
  412. package/src/hooks/{__tests__/useComponentPerformance.unit.test.tsx → useComponentPerformance.unit.test.tsx} +27 -41
  413. package/src/hooks/useDataTablePerformance.ts +100 -120
  414. package/src/hooks/{__tests__/useDataTablePerformance.unit.test.ts → useDataTablePerformance.unit.test.ts} +5 -5
  415. package/src/hooks/{__tests__/useDataTableState.test.ts → useDataTableState.test.ts} +2 -2
  416. package/src/hooks/{__tests__/useDebounce.unit.test.ts → useDebounce.unit.test.ts} +2 -2
  417. package/src/hooks/useEventTheme.test.ts +4 -1
  418. package/src/hooks/useEventTheme.ts +49 -21
  419. package/src/hooks/useEvents.ts +41 -1
  420. package/src/hooks/{__tests__/useEvents.unit.test.ts → useEvents.unit.test.ts} +5 -5
  421. package/src/hooks/useFileReference.test.ts +44 -41
  422. package/src/hooks/useFileReference.ts +182 -173
  423. package/src/hooks/useFileUrl.ts +1 -1
  424. package/src/hooks/{__tests__/useFileUrl.unit.test.ts → useFileUrl.unit.test.ts} +26 -36
  425. package/src/hooks/{__tests__/useFileUrlCache.test.ts → useFileUrlCache.test.ts} +8 -8
  426. package/src/hooks/useFileUrlCache.ts +1 -1
  427. package/src/hooks/{__tests__/useFocusManagement.unit.test.ts → useFocusManagement.unit.test.ts} +2 -2
  428. package/src/hooks/{__tests__/useFocusTrap.unit.test.tsx → useFocusTrap.unit.test.tsx} +2 -2
  429. package/src/hooks/{__tests__/useFormDialog.test.ts → useFormDialog.test.ts} +2 -2
  430. package/src/hooks/useInactivityTracker.ts +138 -131
  431. package/src/hooks/{__tests__/useInactivityTracker.unit.test.ts → useInactivityTracker.unit.test.ts} +3 -3
  432. package/src/hooks/{__tests__/useIsMobile.unit.test.ts → useIsMobile.unit.test.ts} +2 -2
  433. package/src/hooks/useIsPrint.ts +62 -0
  434. package/src/hooks/useIsPrint.unit.test.ts +545 -0
  435. package/src/hooks/{__tests__/useKeyboardShortcuts.unit.test.ts → useKeyboardShortcuts.unit.test.ts} +2 -2
  436. package/src/hooks/{__tests__/useOrganisationPermissions.unit.test.tsx → useOrganisationPermissions.unit.test.tsx} +4 -4
  437. package/src/hooks/useOrganisationSecurity.test.ts +3 -3
  438. package/src/hooks/useOrganisationSecurity.ts +190 -201
  439. package/src/hooks/{__tests__/useOrganisationSecurity.unit.test.tsx → useOrganisationSecurity.unit.test.tsx} +61 -63
  440. package/src/hooks/{__tests__/useOrganisations.unit.test.ts → useOrganisations.unit.test.ts} +5 -5
  441. package/src/hooks/{__tests__/usePerformanceMonitor.unit.test.ts → usePerformanceMonitor.unit.test.ts} +13 -14
  442. package/src/hooks/{__tests__/usePermissionCache.test.ts → usePermissionCache.test.ts} +26 -27
  443. package/src/hooks/usePermissionCache.ts +276 -271
  444. package/src/hooks/{__tests__/usePreventTabReload.test.ts → usePreventTabReload.test.ts} +2 -2
  445. package/src/hooks/{__tests__/usePublicEvent.simple.test.ts → usePublicEvent.simple.test.ts} +4 -4
  446. package/src/hooks/{__tests__/usePublicEvent.test.ts → usePublicEvent.test.ts} +4 -4
  447. package/src/hooks/{__tests__/usePublicEvent.unit.test.ts → usePublicEvent.unit.test.ts} +4 -4
  448. package/src/hooks/{__tests__/usePublicFileDisplay.test.ts → usePublicFileDisplay.test.ts} +12 -12
  449. package/src/hooks/{__tests__/usePublicRouteParams.unit.test.ts → usePublicRouteParams.unit.test.ts} +3 -3
  450. package/src/hooks/{__tests__/useQueryCache.test.ts → useQueryCache.test.ts} +2 -2
  451. package/src/hooks/useQueryCache.ts +0 -2
  452. package/src/hooks/{__tests__/useRBAC.unit.test.ts → useRBAC.unit.test.ts} +55 -38
  453. package/src/hooks/{__tests__/useSessionDraft.test.ts → useSessionDraft.test.ts} +2 -2
  454. package/src/hooks/{__tests__/useSessionRestoration.unit.test.tsx → useSessionRestoration.unit.test.tsx} +10 -19
  455. package/src/hooks/useStorage.ts +21 -16
  456. package/src/hooks/{__tests__/useStorage.unit.test.ts → useStorage.unit.test.ts} +38 -75
  457. package/src/hooks/{__tests__/useToast.test.ts → useToast.test.ts} +2 -2
  458. package/src/hooks/{__tests__/useToast.unit.test.tsx → useToast.unit.test.tsx} +2 -2
  459. package/src/hooks/{__tests__/useZodForm.unit.test.tsx → useZodForm.unit.test.tsx} +2 -2
  460. package/src/icons/{__tests__/index.test.ts → index.test.ts} +2 -2
  461. package/src/icons/index.ts +2 -0
  462. package/src/{__tests__/index.test.ts → index.test.ts} +3 -7
  463. package/src/index.ts +15 -7
  464. package/src/providers/{__tests__/AuthProvider.test.tsx → AuthProvider.test.tsx} +3 -3
  465. package/src/providers/{__tests__/EventProvider.test.tsx → EventProvider.test.tsx} +3 -3
  466. package/src/providers/InactivityProvider.test-helper.tsx +40 -0
  467. package/src/providers/{__tests__/InactivityProvider.test.tsx → InactivityProvider.test.tsx} +14 -21
  468. package/src/providers/{__tests__/ProviderLifecycle.test.tsx → ProviderLifecycle.test.tsx} +4 -4
  469. package/src/providers/{__tests__/UnifiedAuthProvider.test.tsx → UnifiedAuthProvider.test.tsx} +1 -1
  470. package/src/providers/{__tests__/index.test.ts → index.test.ts} +2 -2
  471. package/src/providers/services/{__tests__/AuthServiceProvider.integration.test.tsx → AuthServiceProvider.integration.test.tsx} +4 -4
  472. package/src/providers/services/{__tests__/AuthServiceProvider.test.tsx → AuthServiceProvider.test.tsx} +7 -7
  473. package/src/providers/services/{__tests__/EventServiceProvider.test.tsx → EventServiceProvider.test.tsx} +7 -7
  474. package/src/providers/services/{__tests__/InactivityServiceProvider.test.tsx → InactivityServiceProvider.test.tsx} +5 -5
  475. package/src/providers/services/{__tests__/OrganisationServiceProvider.test.tsx → OrganisationServiceProvider.test.tsx} +6 -6
  476. package/src/providers/services/UnifiedAuthContext.ts +30 -27
  477. package/src/providers/services/{__tests__/UnifiedAuthProvider.advanced.test.tsx → UnifiedAuthProvider.advanced.test.tsx} +8 -9
  478. package/src/providers/services/{__tests__/UnifiedAuthProvider.appId.test.tsx → UnifiedAuthProvider.appId.test.tsx} +25 -25
  479. package/src/providers/services/{__tests__/UnifiedAuthProvider.integration.test.tsx → UnifiedAuthProvider.integration.test.tsx} +14 -11
  480. package/src/providers/services/UnifiedAuthProvider.tsx +115 -360
  481. package/src/providers/services/{__tests__/contexts.test.tsx → contexts.test.tsx} +6 -6
  482. package/src/providers/services/{__tests__/useUnifiedAuth.test.tsx → useUnifiedAuth.test.tsx} +6 -6
  483. package/src/providers/services/useUnifiedAuthContextValue.ts +279 -0
  484. package/src/providers/useInactivity.test-helper.ts +27 -0
  485. package/src/rbac/{__tests__/adapters.comprehensive.test.tsx → adapters.comprehensive.test.tsx} +24 -24
  486. package/src/rbac/adapters.test.tsx +22 -22
  487. package/src/rbac/adapters.tsx +29 -29
  488. package/src/rbac/api.test.ts +973 -42
  489. package/src/rbac/api.ts +228 -253
  490. package/src/rbac/{__tests__/audit-batched.test.ts → audit-batched.test.ts} +6 -6
  491. package/src/rbac/audit.ts +4 -1
  492. package/src/rbac/{__tests__/auth-rbac-security.integration.test.tsx → auth-rbac-security.integration.test.tsx} +1 -1
  493. package/src/rbac/{__tests__/auth-rbac.e2e.test.tsx → auth-rbac.e2e.test.tsx} +27 -34
  494. package/src/rbac/cache-invalidation.test.ts +715 -0
  495. package/src/rbac/components/{__tests__/AccessDenied.test.tsx → AccessDenied.test.tsx} +3 -3
  496. package/src/rbac/components/{__tests__/NavigationGuard.test.tsx → NavigationGuard.test.tsx} +13 -11
  497. package/src/{__tests__/rbac/PagePermissionGuard.test.tsx → rbac/components/PagePermissionGuard.guard.test.tsx} +33 -19
  498. package/src/rbac/components/{__tests__/PagePermissionGuard.performance.test.tsx → PagePermissionGuard.performance.test.tsx} +30 -9
  499. package/src/rbac/components/{__tests__/PagePermissionGuard.race-condition.test.tsx → PagePermissionGuard.race-condition.test.tsx} +7 -7
  500. package/src/rbac/components/{__tests__/PagePermissionGuard.test.tsx → PagePermissionGuard.test.tsx} +10 -10
  501. package/src/rbac/components/PagePermissionGuard.tsx +177 -372
  502. package/src/rbac/components/{__tests__/PagePermissionGuard.verification.test.tsx → PagePermissionGuard.verification.test.tsx} +7 -7
  503. package/src/rbac/config.ts +58 -18
  504. package/src/rbac/{__tests__/engine.comprehensive.test.ts → engine.comprehensive.test.ts} +3 -3
  505. package/src/rbac/engine.test.ts +494 -0
  506. package/src/rbac/errors.ts +89 -55
  507. package/src/rbac/hooks/permissions/runPermissionCheck.ts +77 -0
  508. package/src/rbac/hooks/permissions/{__tests__/useAccessLevel.test.ts → useAccessLevel.test.ts} +40 -40
  509. package/src/rbac/hooks/permissions/useAccessLevel.ts +16 -6
  510. package/src/rbac/hooks/permissions/{__tests__/useCan.test.ts → useCan.test.ts} +41 -41
  511. package/src/rbac/hooks/permissions/useCan.ts +170 -252
  512. package/src/rbac/hooks/permissions/{__tests__/useMultiplePermissions.test.ts → useMultiplePermissions.test.ts} +49 -49
  513. package/src/rbac/hooks/permissions/useMultiplePermissions.ts +6 -2
  514. package/src/rbac/hooks/permissions/{__tests__/usePermissions.test.ts → usePermissions.test.ts} +10 -12
  515. package/src/rbac/hooks/permissions/usePermissions.ts +36 -65
  516. package/src/rbac/hooks/useCan.test.ts +42 -42
  517. package/src/rbac/hooks/usePageAccessLogging.ts +160 -0
  518. package/src/rbac/hooks/usePageGuardScope.ts +117 -0
  519. package/src/rbac/hooks/usePagePermissionCheck.ts +67 -0
  520. package/src/rbac/hooks/{__tests__/usePermissions.integration.test.ts → usePermissions.integration.test.ts} +9 -9
  521. package/src/{__tests__/hooks/usePermissions.test.ts → rbac/hooks/usePermissions.stability.test.ts} +18 -18
  522. package/src/rbac/hooks/usePermissions.test.ts +54 -54
  523. package/src/rbac/hooks/useRBAC.test.ts +313 -217
  524. package/src/rbac/hooks/useRBAC.ts +145 -81
  525. package/src/rbac/hooks/useResourcePermissions.test.ts +25 -25
  526. package/src/rbac/hooks/useResourcePermissions.ts +68 -134
  527. package/src/rbac/hooks/useResourcePermissionsSuperAdmin.ts +67 -0
  528. package/src/rbac/hooks/useRoleManagement.test.ts +27 -112
  529. package/src/rbac/hooks/useRoleManagement.ts +153 -585
  530. package/src/rbac/hooks/{__tests__/useSecureSupabase.test.ts → useSecureSupabase.test.ts} +17 -17
  531. package/src/rbac/hooks/useSecureSupabase.ts +10 -2
  532. package/src/rbac/hooks/useSuperAdminCheck.ts +80 -0
  533. package/src/rbac/{__tests__/performance.test.ts → performance.test.ts} +1 -1
  534. package/src/rbac/{__tests__/rbac-core.test.tsx → rbac-core.test.tsx} +3 -3
  535. package/src/rbac/{__tests__/rbac-engine-core-logic.test.ts → rbac-engine-core-logic.test.ts} +2 -2
  536. package/src/rbac/{__tests__/rbac-engine-simplified.test.ts → rbac-engine-simplified.test.ts} +3 -3
  537. package/src/rbac/{__tests__/rbac-functions.test.ts → rbac-functions.test.ts} +57 -0
  538. package/src/rbac/{__tests__/rbac-role-isolation.test.ts → rbac-role-isolation.test.ts} +2 -2
  539. package/src/rbac/request-deduplication.test.ts +14 -9
  540. package/src/rbac/request-deduplication.ts +5 -4
  541. package/src/rbac/{__tests__/scenarios.user-role.test.tsx → scenarios.user-role.test.tsx} +23 -23
  542. package/src/rbac/secureClient.test.ts +514 -83
  543. package/src/rbac/secureClient.ts +8 -2
  544. package/src/rbac/security.test.ts +323 -0
  545. package/src/rbac/types/roleManagement.ts +66 -0
  546. package/src/rbac/utils/{__tests__/clientSecurity.test.ts → clientSecurity.test.ts} +4 -4
  547. package/src/rbac/utils/{__tests__/contextValidator.test.ts → contextValidator.test.ts} +4 -4
  548. package/src/rbac/utils/contextValidator.ts +5 -1
  549. package/src/rbac/utils/{__tests__/deep-equal.test.ts → deep-equal.test.ts} +1 -1
  550. package/src/rbac/utils/{__tests__/eventContext.test.ts → eventContext.test.ts} +36 -21
  551. package/src/rbac/utils/eventContext.ts +37 -33
  552. package/src/rbac/utils/fetchPermissionMap.ts +13 -0
  553. package/src/rbac/utils/permissionMapHelpers.ts +34 -0
  554. package/src/rbac/utils/roleManagementRpc.ts +303 -0
  555. package/src/services/{__tests__/AuthService.edge-cases.test.ts → AuthService.edge-cases.test.ts} +19 -19
  556. package/src/services/{__tests__/AuthService.restoreSession.test.ts → AuthService.restoreSession.test.ts} +2 -2
  557. package/src/services/{__tests__/AuthService.test.ts → AuthService.test.ts} +89 -55
  558. package/src/services/AuthService.ts +184 -205
  559. package/src/services/{__tests__/BaseService.edge-cases.test.ts → BaseService.edge-cases.test.ts} +3 -3
  560. package/src/services/{__tests__/BaseService.test.ts → BaseService.test.ts} +2 -2
  561. package/src/services/{__tests__/EventService.edge-cases.test.ts → EventService.edge-cases.test.ts} +27 -24
  562. package/src/services/{__tests__/EventService.eventColours.test.ts → EventService.eventColours.test.ts} +1 -1
  563. package/src/services/{__tests__/EventService.test.ts → EventService.test.ts} +256 -24
  564. package/src/services/EventService.ts +242 -312
  565. package/src/services/{__tests__/InactivityService.edge-cases.test.ts → InactivityService.edge-cases.test.ts} +3 -3
  566. package/src/services/{__tests__/InactivityService.lifecycle.test.ts → InactivityService.lifecycle.test.ts} +2 -2
  567. package/src/services/{__tests__/InactivityService.test.ts → InactivityService.test.ts} +179 -4
  568. package/src/services/InactivityService.ts +172 -213
  569. package/src/services/{__tests__/OrganisationService.edge-cases.test.ts → OrganisationService.edge-cases.test.ts} +5 -5
  570. package/src/services/{__tests__/OrganisationService.pagination.test.ts → OrganisationService.pagination.test.ts} +4 -4
  571. package/src/services/{__tests__/OrganisationService.test.ts → OrganisationService.test.ts} +410 -7
  572. package/src/services/OrganisationService.ts +184 -238
  573. package/src/services/base/BaseService.test.ts +1 -1
  574. package/src/services/interfaces/{__tests__/IAuthService.test.ts → IAuthService.test.ts} +21 -27
  575. package/src/services/interfaces/IAuthService.ts +10 -9
  576. package/src/services/interfaces/{__tests__/IEventService.test.ts → IEventService.test.ts} +4 -4
  577. package/src/services/interfaces/{__tests__/IInactivityService.test.ts → IInactivityService.test.ts} +3 -3
  578. package/src/services/interfaces/{__tests__/IOrganisationService.test.ts → IOrganisationService.test.ts} +3 -3
  579. package/src/styles/core.css +243 -12
  580. package/src/theming/{__tests__/parseEventColours.test.ts → parseEventColours.test.ts} +1 -1
  581. package/src/theming/{__tests__/runtime.test.ts → runtime.test.ts} +8 -17
  582. package/src/theming/runtime.ts +71 -2
  583. package/src/types/api-result.ts +53 -0
  584. package/src/types/{__tests__/core.test.ts → core.test.ts} +2 -2
  585. package/src/types/{__tests__/database-generated.test.ts → database-generated.test.ts} +3 -3
  586. package/src/types/database.generated.ts +45 -10
  587. package/src/types/event.ts +38 -18
  588. package/src/types/{__tests__/file-reference.test.ts → file-reference.test.ts} +13 -13
  589. package/src/types/file-reference.ts +37 -12
  590. package/src/types/{__tests__/guards.test.ts → guards.test.ts} +2 -2
  591. package/src/types/{__tests__/index.test.ts → index.test.ts} +2 -2
  592. package/src/types/index.ts +3 -0
  593. package/src/types/{__tests__/organisation.roles.test.ts → organisation.roles.test.ts} +1 -1
  594. package/src/types/{__tests__/organisation.test.ts → organisation.test.ts} +3 -31
  595. package/src/types/organisation.ts +15 -15
  596. package/src/types/supabase.ts +13 -4
  597. package/src/types/{__tests__/theme.test.ts → theme.test.ts} +1 -1
  598. package/src/types/{__tests__/type-validation.test.ts → type-validation.test.ts} +1 -1
  599. package/src/types/{__tests__/validation.test.ts → validation.test.ts} +2 -2
  600. package/src/utils/app/appIdResolver.test.ts +98 -71
  601. package/src/utils/app/appIdResolver.ts +31 -20
  602. package/src/utils/{__tests__/appConfig.unit.test.ts → appConfig.unit.test.ts} +1 -1
  603. package/src/utils/{__tests__/audit.unit.test.ts → audit.unit.test.ts} +1 -1
  604. package/src/utils/{__tests__/auth-utils.unit.test.ts → auth-utils.unit.test.ts} +16 -17
  605. package/src/utils/{__tests__/bundleAnalysis.unit.test.ts → bundleAnalysis.unit.test.ts} +35 -35
  606. package/src/utils/{__tests__/cn.unit.test.ts → cn.unit.test.ts} +1 -1
  607. package/src/utils/context/organisationContext.test.ts +105 -91
  608. package/src/utils/context/organisationContext.ts +29 -40
  609. package/src/utils/core/{__tests__/cn.test.ts → cn.test.ts} +3 -3
  610. package/src/utils/core/{__tests__/debugLogger.test.ts → debugLogger.test.ts} +2 -2
  611. package/src/utils/core/{__tests__/logger.test.ts → logger.test.ts} +2 -2
  612. package/src/utils/core/mergeRefs.ts +24 -0
  613. package/src/utils/{__tests__/debugLogger.test.ts → debugLogger.test.ts} +1 -1
  614. package/src/utils/{__tests__/deviceFingerprint.unit.test.ts → deviceFingerprint.unit.test.ts} +1 -1
  615. package/src/utils/dynamic/createLazyComponent.tsx +9 -1
  616. package/src/utils/dynamic/{__tests__/dynamicUtils.test.ts → dynamicUtils.test.ts} +2 -2
  617. package/src/utils/dynamic/{__tests__/lazyLoad.test.tsx → lazyLoad.test.tsx} +2 -2
  618. package/src/utils/{__tests__/dynamicUtils.unit.test.ts → dynamicUtils.unit.test.ts} +1 -1
  619. package/src/utils/file-reference/{__tests__/file-reference.test.ts → file-reference.test.ts} +214 -289
  620. package/src/utils/file-reference/index.ts +330 -347
  621. package/src/utils/{__tests__/formatDate.unit.test.ts → formatDate.unit.test.ts} +2 -2
  622. package/src/utils/formatting/formatDateTimeTimezone.test.ts +1 -1
  623. package/src/utils/formatting/formatNumber.test.ts +1 -1
  624. package/src/utils/{__tests__/formatting.unit.test.ts → formatting.unit.test.ts} +1 -1
  625. package/src/utils/google-places/googlePlacesUtils.test.ts +70 -48
  626. package/src/utils/google-places/googlePlacesUtils.ts +67 -99
  627. package/src/utils/google-places/loadGoogleMapsScript.test.ts +25 -22
  628. package/src/utils/google-places/loadGoogleMapsScript.ts +138 -117
  629. package/src/utils/{__tests__/index.unit.test.ts → index.unit.test.ts} +1 -1
  630. package/src/utils/{__tests__/lazyLoad.unit.test.tsx → lazyLoad.unit.test.tsx} +13 -14
  631. package/src/utils/location/location.test.ts +1 -1
  632. package/src/utils/{__tests__/logger.unit.test.ts → logger.unit.test.ts} +1 -1
  633. package/src/utils/{__tests__/organisationContext.unit.test.ts → organisationContext.unit.test.ts} +37 -48
  634. package/src/utils/performance/{__tests__/bundleAnalysis.test.ts → bundleAnalysis.test.ts} +2 -2
  635. package/src/utils/performance/{__tests__/performanceBenchmark.test.ts → performanceBenchmark.test.ts} +2 -2
  636. package/src/utils/performance/{__tests__/performanceBudgets.test.ts → performanceBudgets.test.ts} +2 -2
  637. package/src/utils/{__tests__/performanceBenchmark.test.ts → performanceBenchmark.test.ts} +2 -2
  638. package/src/utils/{__tests__/performanceBudgets.unit.test.ts → performanceBudgets.unit.test.ts} +2 -2
  639. package/src/utils/{__tests__/permissionTypes.unit.test.ts → permissionTypes.unit.test.ts} +1 -1
  640. package/src/utils/{__tests__/permissionUtils.unit.test.ts → permissionUtils.unit.test.ts} +1 -1
  641. package/src/utils/permissions/{__tests__/permissionTypes.test.ts → permissionTypes.test.ts} +2 -2
  642. package/src/utils/persistence/{__tests__/keyDerivation.test.ts → keyDerivation.test.ts} +2 -2
  643. package/src/utils/persistence/{__tests__/sensitiveFieldDetection.test.ts → sensitiveFieldDetection.test.ts} +2 -2
  644. package/src/utils/{__tests__/request-deduplication.test.ts → request-deduplication.test.ts} +2 -2
  645. package/src/utils/{__tests__/sanitization.unit.test.ts → sanitization.unit.test.ts} +1 -1
  646. package/src/utils/{__tests__/schemaUtils.unit.test.ts → schemaUtils.unit.test.ts} +1 -1
  647. package/src/utils/{__tests__/secureDataAccess.unit.test.ts → secureDataAccess.unit.test.ts} +2 -2
  648. package/src/utils/{__tests__/secureErrors.unit.test.ts → secureErrors.unit.test.ts} +4 -4
  649. package/src/utils/{__tests__/secureStorage.unit.test.ts → secureStorage.unit.test.ts} +1 -1
  650. package/src/utils/security/auth-utils.ts +34 -23
  651. package/src/utils/security/secureDataAccess.ts +241 -281
  652. package/src/utils/security/secureErrors.test.ts +1 -1
  653. package/src/utils/security/secureStorage.test.ts +1 -1
  654. package/src/utils/security/security.test.ts +25 -17
  655. package/src/utils/security/security.ts +15 -18
  656. package/src/utils/security/securityMonitor.test.ts +1 -1
  657. package/src/utils/{__tests__/security.unit.test.ts → security.unit.test.ts} +21 -15
  658. package/src/utils/{__tests__/securityMonitor.unit.test.ts → securityMonitor.unit.test.ts} +1 -1
  659. package/src/utils/{__tests__/sessionTracking.unit.test.ts → sessionTracking.unit.test.ts} +12 -12
  660. package/src/utils/storage/{__tests__/config.unit.test.ts → config.unit.test.ts} +2 -2
  661. package/src/utils/storage/helpers.test.ts +88 -102
  662. package/src/utils/storage/helpers.ts +173 -251
  663. package/src/utils/storage/{__tests__/index.unit.test.ts → index.unit.test.ts} +3 -3
  664. package/src/utils/storage/types.ts +7 -0
  665. package/src/utils/supabase/createBaseClient.test.ts +1 -1
  666. package/src/utils/timezone/timezone.test.ts +1 -1
  667. package/src/utils/{__tests__/timezone.test.ts → timezone.test.ts} +2 -2
  668. package/src/utils/validation/{__tests__/common.test.ts → common.test.ts} +2 -2
  669. package/src/utils/validation/{__tests__/csrf.test.ts → csrf.test.ts} +56 -28
  670. package/src/utils/validation/csrf.ts +42 -41
  671. package/src/utils/validation/{__tests__/htmlSanitization.unit.test.ts → htmlSanitization.unit.test.ts} +2 -2
  672. package/src/utils/validation/{__tests__/passwordSchema.test.ts → passwordSchema.test.ts} +2 -2
  673. package/src/utils/validation/{__tests__/schema.test.ts → schema.test.ts} +2 -2
  674. package/src/utils/validation/{__tests__/sqlInjectionProtection.test.ts → sqlInjectionProtection.test.ts} +2 -2
  675. package/src/utils/validation/{__tests__/user.test.ts → user.test.ts} +2 -2
  676. package/src/utils/validation/{__tests__/validation.test.ts → validation.test.ts} +2 -2
  677. package/src/utils/validation/{__tests__/validationUtils.test.ts → validationUtils.test.ts} +2 -2
  678. package/src/utils/{__tests__/validation.unit.test.ts → validation.unit.test.ts} +1 -1
  679. package/src/utils/{__tests__/validationUtils.unit.test.ts → validationUtils.unit.test.ts} +5 -2
  680. package/dist/UnifiedAuthProvider-BBD2PS3Q.js +0 -7
  681. package/dist/chunk-KPYQWGFQ.js +0 -183
  682. package/dist/types-D05dCGma.d.ts +0 -521
  683. package/scripts/eslint-audit.cjs +0 -222
  684. package/scripts/generate-docs.js +0 -157
  685. package/scripts/install-cursor-rules.cjs +0 -255
  686. package/scripts/install-eslint-config.cjs +0 -349
  687. package/scripts/setup-build-cache.js +0 -73
  688. package/scripts/validate-pre-publish.js +0 -145
  689. package/src/__tests__/integration/UserProfile.test.tsx +0 -124
  690. package/src/__tests__/public-recipe-view.test.ts +0 -228
  691. package/src/__tests__/rls-policies.test.ts +0 -472
  692. package/src/components/DataTable/__tests__/DataTable.test.tsx +0 -876
  693. package/src/components/DataTable/components/DataTableLayout.tsx +0 -584
  694. package/src/components/DataTable/components/UnifiedTableBody.tsx +0 -395
  695. package/src/components/DataTable/components/__tests__/DataTableLayout.test.tsx +0 -467
  696. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +0 -358
  697. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +0 -957
  698. package/src/components/DataTable/core/ActionManager.ts +0 -235
  699. package/src/components/DataTable/core/ColumnManager.ts +0 -204
  700. package/src/components/DataTable/core/DataManager.ts +0 -190
  701. package/src/components/DataTable/core/LocalDataAdapter.ts +0 -274
  702. package/src/components/DataTable/core/PluginRegistry.ts +0 -229
  703. package/src/components/DataTable/core/StateManager.ts +0 -312
  704. package/src/components/DataTable/core/__tests__/ActionManager.test.ts +0 -235
  705. package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +0 -141
  706. package/src/components/DataTable/core/__tests__/DataManager.test.ts +0 -178
  707. package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +0 -133
  708. package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +0 -142
  709. package/src/components/DataTable/core/__tests__/StateManager.test.ts +0 -158
  710. package/src/components/DataTable/core/interfaces.ts +0 -338
  711. package/src/components/DataTable/types.ts +0 -764
  712. package/src/hooks/public/usePublicFileDisplay.ts +0 -534
  713. package/src/hooks/useFileDisplay.ts +0 -748
  714. package/src/providers/OrganisationProvider.test.tsx +0 -40
  715. package/src/providers/OrganisationProvider.tsx +0 -92
  716. package/src/providers/__tests__/InactivityProvider.test-helper.tsx +0 -65
  717. package/src/providers/__tests__/OrganisationProvider.test.tsx +0 -616
  718. package/src/providers/__tests__/OrganisationProvider.wrapper.test.tsx +0 -591
  719. package/src/rbac/__tests__/cache-invalidation.test.ts +0 -393
  720. /package/src/components/DataTable/{components/__tests__ → ui}/COVERAGE_NOTE.md +0 -0
  721. /package/src/components/DataTable/utils/{__tests__/COVERAGE_NOTE.md → COVERAGE_NOTE.md} +0 -0
  722. /package/src/hooks/{__tests__/useApiFetch.unit.test.ts → useApiFetch.unit.test.ts} +0 -0
  723. /package/src/providers/{__tests__/README.md → README.md} +0 -0
  724. /package/src/rbac/{__tests__/index.test.ts → index.test.ts} +0 -0
  725. /package/src/rbac/{__tests__/rbac-integration.test.ts → rbac-integration.test.ts} +0 -0
  726. /package/src/types/{__tests__/README.md → README.md} +0 -0
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @file useFileDisplay Hook Unit Tests
3
3
  * @package @jmruthers/pace-core
4
- * @module Hooks/__tests__
4
+ * @module Hooks
5
5
  * @since 0.1.0
6
6
  *
7
7
  * Comprehensive tests for the useFileDisplay hook following TEST_STANDARD.md.
@@ -15,16 +15,16 @@ import {
15
15
  clearFileDisplayCache,
16
16
  getFileDisplayCacheStats,
17
17
  invalidateFileDisplayCache
18
- } from '../useFileDisplay';
18
+ } from './useFileDisplay';
19
19
  import { createMockSupabaseClient } from '../../__tests__/helpers/supabaseMock';
20
20
  import type { SupabaseClient } from '@supabase/supabase-js';
21
21
  import type { Database } from '../../types/database';
22
22
  import { FileCategory as FileCategoryEnum } from '../../types/file-reference';
23
23
 
24
- // Mock storage helpers
24
+ // Mock storage helpers - paths relative to src/hooks/
25
25
  vi.mock('../../utils/storage/helpers', () => ({
26
26
  getPublicUrl: vi.fn((supabase: any, path: string) => `https://example.com/${path}`),
27
- getSignedUrl: vi.fn().mockResolvedValue({ url: 'https://example.com/signed-file.jpg', expiresAt: new Date().toISOString() }),
27
+ getSignedUrl: vi.fn().mockResolvedValue({ ok: true, data: { url: 'https://example.com/signed-file.jpg', expiresAt: new Date().toISOString() } }),
28
28
  generateFileUrlsBatch: vi.fn().mockImplementation(async (supabase, files) => {
29
29
  const urlMap = new Map<string, string>();
30
30
  for (const file of files) {
@@ -34,11 +34,11 @@ vi.mock('../../utils/storage/helpers', () => ({
34
34
  urlMap.set(file.id, `https://example.com/signed/${file.file_path}`);
35
35
  }
36
36
  }
37
- return urlMap;
37
+ return { ok: true as const, data: urlMap };
38
38
  })
39
39
  }));
40
40
 
41
- // Mock file reference service
41
+ // Mock file reference service (kept for any legacy references)
42
42
  const mockService = {
43
43
  getFilesByCategory: vi.fn(),
44
44
  listFileReferences: vi.fn()
@@ -48,8 +48,12 @@ vi.mock('../../utils/file-reference', () => ({
48
48
  createFileReferenceService: vi.fn(() => mockService)
49
49
  }));
50
50
 
51
+ const mockFetchFileDisplayData = vi.fn();
52
+ vi.mock('./fetchFileDisplayData', () => ({
53
+ fetchFileDisplayData: (params: unknown) => mockFetchFileDisplayData(params),
54
+ }));
55
+
51
56
  import { getSignedUrl, generateFileUrlsBatch } from '../../utils/storage/helpers';
52
- import { createFileReferenceService } from '../../utils/file-reference';
53
57
 
54
58
  describe('useFileDisplay Hook', () => {
55
59
  let mockSupabase: SupabaseClient<Database>;
@@ -95,8 +99,7 @@ describe('useFileDisplay Hook', () => {
95
99
  vi.clearAllMocks();
96
100
  clearFileDisplayCache();
97
101
  mockSupabase = createMockSupabaseClient() as any;
98
- mockService.getFilesByCategory.mockResolvedValue([]);
99
- mockService.listFileReferences.mockResolvedValue([]);
102
+ mockFetchFileDisplayData.mockResolvedValue([]);
100
103
 
101
104
  // Reset generateFileUrlsBatch mock to ensure it returns a Map
102
105
  vi.mocked(generateFileUrlsBatch).mockImplementation(async (supabase, files) => {
@@ -108,7 +111,7 @@ describe('useFileDisplay Hook', () => {
108
111
  urlMap.set(file.id, `https://example.com/signed/${file.file_path}`);
109
112
  }
110
113
  }
111
- return urlMap;
114
+ return { ok: true, data: urlMap };
112
115
  });
113
116
  });
114
117
 
@@ -122,8 +125,8 @@ describe('useFileDisplay Hook', () => {
122
125
  // Reset getSignedUrl mock to prevent interference with other test files
123
126
  vi.mocked(getSignedUrl).mockReset();
124
127
  vi.mocked(getSignedUrl).mockResolvedValue({
125
- url: 'https://example.com/signed-file.jpg',
126
- expiresAt: new Date().toISOString()
128
+ ok: true,
129
+ data: { url: 'https://example.com/signed-file.jpg', expiresAt: new Date().toISOString() }
127
130
  });
128
131
  });
129
132
 
@@ -145,7 +148,7 @@ describe('useFileDisplay Hook', () => {
145
148
  });
146
149
 
147
150
  it('initializes with loading state when parameters are provided', () => {
148
- mockService.getFilesByCategory.mockImplementation(() => new Promise(() => {})); // Never resolves
151
+ mockFetchFileDisplayData.mockImplementation(() => new Promise(() => {})); // Never resolves
149
152
 
150
153
  const { result } = renderHook(() =>
151
154
  useFileDisplay('event', 'event-123', 'org-123', FileCategoryEnum.EVENT_LOGOS, {
@@ -173,7 +176,7 @@ describe('useFileDisplay Hook', () => {
173
176
 
174
177
  describe('Single File Mode (with category)', () => {
175
178
  it('fetches single file by category successfully with public file', async () => {
176
- mockService.getFilesByCategory.mockResolvedValue([mockFileReference]);
179
+ mockFetchFileDisplayData.mockResolvedValue([mockFileReference]);
177
180
 
178
181
  const { result } = renderHook(() =>
179
182
  useFileDisplay('event', 'event-123', 'org-123', FileCategoryEnum.EVENT_LOGOS, {
@@ -193,16 +196,19 @@ describe('useFileDisplay Hook', () => {
193
196
  expect(result.current.fileUrl).toBe('https://example.com/org-123/logos/logo.png');
194
197
  expect(result.current.fileCount).toBe(1);
195
198
  expect(result.current.error).toBe(null);
196
- expect(mockService.getFilesByCategory).toHaveBeenCalledWith(
197
- 'event',
198
- 'event-123',
199
- FileCategoryEnum.EVENT_LOGOS,
200
- 'org-123'
199
+ expect(mockFetchFileDisplayData).toHaveBeenCalledWith(
200
+ expect.objectContaining({
201
+ table_name: 'event',
202
+ record_id: 'event-123',
203
+ organisation_id: 'org-123',
204
+ category: FileCategoryEnum.EVENT_LOGOS,
205
+ })
201
206
  );
202
207
  });
203
208
 
204
209
  it('fetches single file by category successfully with private file and signed URL', async () => {
205
- mockService.getFilesByCategory.mockResolvedValue([mockPrivateFileReference]);
210
+ mockFetchFileDisplayData.mockResolvedValue([mockPrivateFileReference]);
211
+ vi.mocked(getSignedUrl).mockResolvedValue({ ok: true, data: { url: 'https://example.com/signed-file.jpg', expiresAt: new Date().toISOString() } });
206
212
 
207
213
  const { result } = renderHook(() =>
208
214
  useFileDisplay('event', 'event-123', 'org-123', FileCategoryEnum.EVENT_LOGOS, {
@@ -224,7 +230,7 @@ describe('useFileDisplay Hook', () => {
224
230
  });
225
231
 
226
232
  it('handles no files found for category', async () => {
227
- mockService.getFilesByCategory.mockResolvedValue([]);
233
+ mockFetchFileDisplayData.mockResolvedValue([]);
228
234
 
229
235
  const { result } = renderHook(() =>
230
236
  useFileDisplay('event', 'event-123', 'org-123', FileCategoryEnum.EVENT_LOGOS, {
@@ -247,7 +253,7 @@ describe('useFileDisplay Hook', () => {
247
253
 
248
254
  it('handles errors in single file mode', async () => {
249
255
  const error = new Error('Database error');
250
- mockService.getFilesByCategory.mockRejectedValue(error);
256
+ mockFetchFileDisplayData.mockRejectedValue(error);
251
257
 
252
258
  const { result } = renderHook(() =>
253
259
  useFileDisplay('event', 'event-123', 'org-123', FileCategoryEnum.EVENT_LOGOS, {
@@ -270,7 +276,8 @@ describe('useFileDisplay Hook', () => {
270
276
 
271
277
  it('regenerates signed URL from cache for private files', async () => {
272
278
  // First, fetch and cache a private file
273
- mockService.getFilesByCategory.mockResolvedValue([mockPrivateFileReference]);
279
+ mockFetchFileDisplayData.mockResolvedValue([mockPrivateFileReference]);
280
+ vi.mocked(getSignedUrl).mockResolvedValue({ ok: true, data: { url: 'https://example.com/signed-file.jpg', expiresAt: new Date().toISOString() } });
274
281
 
275
282
  const { result: firstResult } = renderHook(() =>
276
283
  useFileDisplay('event', 'event-123', 'org-123', FileCategoryEnum.EVENT_LOGOS, {
@@ -287,7 +294,7 @@ describe('useFileDisplay Hook', () => {
287
294
  );
288
295
 
289
296
  // Clear the mock to simulate cache hit
290
- mockService.getFilesByCategory.mockClear();
297
+ mockFetchFileDisplayData.mockClear();
291
298
  (getSignedUrl as any).mockClear();
292
299
 
293
300
  // Second render with same parameters - should use cache
@@ -307,7 +314,7 @@ describe('useFileDisplay Hook', () => {
307
314
 
308
315
  // Should regenerate signed URL from cache
309
316
  expect(getSignedUrl).toHaveBeenCalled();
310
- expect(mockService.getFilesByCategory).not.toHaveBeenCalled();
317
+ expect(mockFetchFileDisplayData).not.toHaveBeenCalled();
311
318
  });
312
319
  });
313
320
 
@@ -317,7 +324,7 @@ describe('useFileDisplay Hook', () => {
317
324
  mockFileReference,
318
325
  { ...mockFileReference, id: 'file-789', file_path: 'org-123/logos/logo2.png' }
319
326
  ];
320
- mockService.listFileReferences.mockResolvedValue(files);
327
+ mockFetchFileDisplayData.mockResolvedValue(files);
321
328
 
322
329
  const { result } = renderHook(() =>
323
330
  useFileDisplay('event', 'event-123', 'org-123', undefined, {
@@ -341,7 +348,7 @@ describe('useFileDisplay Hook', () => {
341
348
  });
342
349
 
343
350
  it('handles no files found in multiple file mode', async () => {
344
- mockService.listFileReferences.mockResolvedValue([]);
351
+ mockFetchFileDisplayData.mockResolvedValue([]);
345
352
 
346
353
  const { result } = renderHook(() =>
347
354
  useFileDisplay('event', 'event-123', 'org-123', undefined, {
@@ -364,7 +371,7 @@ describe('useFileDisplay Hook', () => {
364
371
 
365
372
  it('handles errors in multiple file mode', async () => {
366
373
  const error = new Error('Failed to fetch file references');
367
- mockService.listFileReferences.mockRejectedValue(error);
374
+ mockFetchFileDisplayData.mockRejectedValue(error);
368
375
 
369
376
  const { result } = renderHook(() =>
370
377
  useFileDisplay('event', 'event-123', 'org-123', undefined, {
@@ -387,7 +394,7 @@ describe('useFileDisplay Hook', () => {
387
394
 
388
395
  describe('Caching', () => {
389
396
  it('caches file data and returns from cache on subsequent calls', async () => {
390
- mockService.getFilesByCategory.mockResolvedValue([mockFileReference]);
397
+ mockFetchFileDisplayData.mockResolvedValue([mockFileReference]);
391
398
 
392
399
  const { result, rerender } = renderHook(() =>
393
400
  useFileDisplay('event', 'event-123', 'org-123', FileCategoryEnum.EVENT_LOGOS, {
@@ -404,7 +411,7 @@ describe('useFileDisplay Hook', () => {
404
411
  { timeout: 2000 }
405
412
  );
406
413
 
407
- const firstCallCount = mockService.getFilesByCategory.mock.calls.length;
414
+ const firstCallCount = mockFetchFileDisplayData.mock.calls.length;
408
415
 
409
416
  // Rerender with same parameters - should use cache
410
417
  rerender();
@@ -417,11 +424,11 @@ describe('useFileDisplay Hook', () => {
417
424
  );
418
425
 
419
426
  // Should not make another service call
420
- expect(mockService.getFilesByCategory.mock.calls.length).toBe(firstCallCount);
427
+ expect(mockFetchFileDisplayData.mock.calls.length).toBe(firstCallCount);
421
428
  });
422
429
 
423
430
  it('respects cache TTL option', async () => {
424
- mockService.getFilesByCategory.mockResolvedValue([mockFileReference]);
431
+ mockFetchFileDisplayData.mockResolvedValue([mockFileReference]);
425
432
 
426
433
  const { result } = renderHook(() =>
427
434
  useFileDisplay('event', 'event-123', 'org-123', FileCategoryEnum.EVENT_LOGOS, {
@@ -442,7 +449,7 @@ describe('useFileDisplay Hook', () => {
442
449
  });
443
450
 
444
451
  it('disables caching when enableCache is false', async () => {
445
- mockService.getFilesByCategory.mockResolvedValue([mockFileReference]);
452
+ mockFetchFileDisplayData.mockResolvedValue([mockFileReference]);
446
453
 
447
454
  const { result, rerender } = renderHook(() =>
448
455
  useFileDisplay('event', 'event-123', 'org-123', FileCategoryEnum.EVENT_LOGOS, {
@@ -476,7 +483,7 @@ describe('useFileDisplay Hook', () => {
476
483
  it('performs cache cleanup on size limit exceeded', async () => {
477
484
  // Fill cache beyond MAX_CACHE_SIZE (100)
478
485
  for (let i = 0; i < 101; i++) {
479
- mockService.getFilesByCategory.mockResolvedValue([mockFileReference]);
486
+ mockFetchFileDisplayData.mockResolvedValue([mockFileReference]);
480
487
 
481
488
  renderHook(() =>
482
489
  useFileDisplay('event', `event-${i}`, 'org-123', FileCategoryEnum.EVENT_LOGOS, {
@@ -498,7 +505,7 @@ describe('useFileDisplay Hook', () => {
498
505
 
499
506
  describe('Cache Management Utilities', () => {
500
507
  it('clearFileDisplayCache clears all cached data', async () => {
501
- mockService.getFilesByCategory.mockResolvedValue([mockFileReference]);
508
+ mockFetchFileDisplayData.mockResolvedValue([mockFileReference]);
502
509
 
503
510
  const { result } = renderHook(() =>
504
511
  useFileDisplay('event', 'event-123', 'org-123', FileCategoryEnum.EVENT_LOGOS, {
@@ -523,7 +530,7 @@ describe('useFileDisplay Hook', () => {
523
530
  });
524
531
 
525
532
  it('getFileDisplayCacheStats returns correct statistics', async () => {
526
- mockService.getFilesByCategory.mockResolvedValue([mockFileReference]);
533
+ mockFetchFileDisplayData.mockResolvedValue([mockFileReference]);
527
534
 
528
535
  renderHook(() =>
529
536
  useFileDisplay('event', 'event-123', 'org-123', FileCategoryEnum.EVENT_LOGOS, {
@@ -547,7 +554,7 @@ describe('useFileDisplay Hook', () => {
547
554
  });
548
555
 
549
556
  it('invalidateFileDisplayCache invalidates specific entries', async () => {
550
- mockService.getFilesByCategory.mockResolvedValue([mockFileReference]);
557
+ mockFetchFileDisplayData.mockResolvedValue([mockFileReference]);
551
558
 
552
559
  renderHook(() =>
553
560
  useFileDisplay('event', 'event-123', 'org-123', FileCategoryEnum.EVENT_LOGOS, {
@@ -574,8 +581,8 @@ describe('useFileDisplay Hook', () => {
574
581
  });
575
582
 
576
583
  it('invalidateFileDisplayCache also invalidates all category when specific category invalidated', async () => {
577
- mockService.getFilesByCategory.mockResolvedValue([mockFileReference]);
578
- mockService.listFileReferences.mockResolvedValue([mockFileReference]);
584
+ mockFetchFileDisplayData.mockResolvedValue([mockFileReference]);
585
+ mockFetchFileDisplayData.mockResolvedValue([mockFileReference]);
579
586
 
580
587
  // Create cache entries for both category and all
581
588
  renderHook(() =>
@@ -614,7 +621,7 @@ describe('useFileDisplay Hook', () => {
614
621
 
615
622
  describe('Refetch Functionality', () => {
616
623
  it('refetches data when refetch is called', async () => {
617
- mockService.getFilesByCategory.mockResolvedValue([mockFileReference]);
624
+ mockFetchFileDisplayData.mockResolvedValue([mockFileReference]);
618
625
 
619
626
  const { result } = renderHook(() =>
620
627
  useFileDisplay('event', 'event-123', 'org-123', FileCategoryEnum.EVENT_LOGOS, {
@@ -630,11 +637,11 @@ describe('useFileDisplay Hook', () => {
630
637
  { timeout: 2000 }
631
638
  );
632
639
 
633
- const firstCallCount = mockService.getFilesByCategory.mock.calls.length;
640
+ const firstCallCount = mockFetchFileDisplayData.mock.calls.length;
634
641
 
635
642
  // Update mock to return different data
636
643
  const newFile = { ...mockFileReference, id: 'file-999', file_path: 'org-123/logos/new-logo.png' };
637
- mockService.getFilesByCategory.mockResolvedValue([newFile]);
644
+ mockFetchFileDisplayData.mockResolvedValue([newFile]);
638
645
 
639
646
  await result.current.refetch();
640
647
 
@@ -646,11 +653,11 @@ describe('useFileDisplay Hook', () => {
646
653
  );
647
654
 
648
655
  // Should have made another call
649
- expect(mockService.getFilesByCategory.mock.calls.length).toBeGreaterThan(firstCallCount);
656
+ expect(mockFetchFileDisplayData.mock.calls.length).toBeGreaterThan(firstCallCount);
650
657
  });
651
658
 
652
659
  it('clears cache before refetching', async () => {
653
- mockService.getFilesByCategory.mockResolvedValue([mockFileReference]);
660
+ mockFetchFileDisplayData.mockResolvedValue([mockFileReference]);
654
661
 
655
662
  const { result } = renderHook(() =>
656
663
  useFileDisplay('event', 'event-123', 'org-123', FileCategoryEnum.EVENT_LOGOS, {
@@ -682,7 +689,7 @@ describe('useFileDisplay Hook', () => {
682
689
  });
683
690
 
684
691
  it('handles refetch errors gracefully', async () => {
685
- mockService.getFilesByCategory.mockResolvedValue([mockFileReference]);
692
+ mockFetchFileDisplayData.mockResolvedValue([mockFileReference]);
686
693
 
687
694
  const { result } = renderHook(() =>
688
695
  useFileDisplay('event', 'event-123', 'org-123', FileCategoryEnum.EVENT_LOGOS, {
@@ -698,7 +705,7 @@ describe('useFileDisplay Hook', () => {
698
705
  );
699
706
 
700
707
  const error = new Error('Refetch failed');
701
- mockService.getFilesByCategory.mockRejectedValue(error);
708
+ mockFetchFileDisplayData.mockRejectedValue(error);
702
709
 
703
710
  await result.current.refetch();
704
711
 
@@ -716,7 +723,7 @@ describe('useFileDisplay Hook', () => {
716
723
  describe('Error Handling', () => {
717
724
  it('handles exceptions during file fetch', async () => {
718
725
  const error = new Error('Network timeout');
719
- mockService.getFilesByCategory.mockRejectedValue(error);
726
+ mockFetchFileDisplayData.mockRejectedValue(error);
720
727
 
721
728
  const { result } = renderHook(() =>
722
729
  useFileDisplay('event', 'event-123', 'org-123', FileCategoryEnum.EVENT_LOGOS, {
@@ -738,7 +745,7 @@ describe('useFileDisplay Hook', () => {
738
745
  });
739
746
 
740
747
  it('handles non-Error exceptions', async () => {
741
- mockService.getFilesByCategory.mockRejectedValue('String error');
748
+ mockFetchFileDisplayData.mockRejectedValue('String error');
742
749
 
743
750
  const { result } = renderHook(() =>
744
751
  useFileDisplay('event', 'event-123', 'org-123', FileCategoryEnum.EVENT_LOGOS, {
@@ -760,7 +767,7 @@ describe('useFileDisplay Hook', () => {
760
767
  it('validates UUID format for organisation_id', async () => {
761
768
  const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
762
769
 
763
- mockService.getFilesByCategory.mockResolvedValue([]);
770
+ mockFetchFileDisplayData.mockResolvedValue([]);
764
771
 
765
772
  renderHook(() =>
766
773
  useFileDisplay('event', 'event-123', 'invalid-uuid', FileCategoryEnum.EVENT_LOGOS, {
@@ -782,7 +789,7 @@ describe('useFileDisplay Hook', () => {
782
789
  });
783
790
 
784
791
  it('handles signed URL generation failures', async () => {
785
- mockService.getFilesByCategory.mockResolvedValue([mockPrivateFileReference]);
792
+ mockFetchFileDisplayData.mockResolvedValue([mockPrivateFileReference]);
786
793
  (getSignedUrl as any).mockRejectedValue(new Error('Signed URL generation failed'));
787
794
 
788
795
  const { result } = renderHook(() =>
@@ -805,7 +812,7 @@ describe('useFileDisplay Hook', () => {
805
812
 
806
813
  describe('Parameter Changes', () => {
807
814
  it('refetches when table_name changes', async () => {
808
- mockService.getFilesByCategory.mockResolvedValue([]);
815
+ mockFetchFileDisplayData.mockResolvedValue([]);
809
816
 
810
817
  const { result, rerender } = renderHook(
811
818
  ({ tableName }) =>
@@ -824,7 +831,7 @@ describe('useFileDisplay Hook', () => {
824
831
  { timeout: 2000 }
825
832
  );
826
833
 
827
- const firstCallCount = mockService.getFilesByCategory.mock.calls.length;
834
+ const firstCallCount = mockFetchFileDisplayData.mock.calls.length;
828
835
 
829
836
  rerender({ tableName: 'organisation' });
830
837
 
@@ -836,17 +843,19 @@ describe('useFileDisplay Hook', () => {
836
843
  );
837
844
 
838
845
  // Should make another call with new table name
839
- expect(mockService.getFilesByCategory.mock.calls.length).toBeGreaterThan(firstCallCount);
840
- expect(mockService.getFilesByCategory).toHaveBeenCalledWith(
841
- 'organisation',
842
- 'event-123',
843
- FileCategoryEnum.EVENT_LOGOS,
844
- 'org-123'
846
+ expect(mockFetchFileDisplayData.mock.calls.length).toBeGreaterThan(firstCallCount);
847
+ expect(mockFetchFileDisplayData).toHaveBeenCalledWith(
848
+ expect.objectContaining({
849
+ table_name: 'organisation',
850
+ record_id: 'event-123',
851
+ organisation_id: 'org-123',
852
+ category: FileCategoryEnum.EVENT_LOGOS,
853
+ })
845
854
  );
846
855
  });
847
856
 
848
857
  it('refetches when record_id changes', async () => {
849
- mockService.getFilesByCategory.mockResolvedValue([]);
858
+ mockFetchFileDisplayData.mockResolvedValue([]);
850
859
 
851
860
  const { result, rerender } = renderHook(
852
861
  ({ recordId }) =>
@@ -875,11 +884,11 @@ describe('useFileDisplay Hook', () => {
875
884
  );
876
885
 
877
886
  // Should have refetched with new record ID
878
- expect(mockService.getFilesByCategory.mock.calls.length).toBeGreaterThan(1);
887
+ expect(mockFetchFileDisplayData.mock.calls.length).toBeGreaterThan(1);
879
888
  });
880
889
 
881
890
  it('refetches when category changes', async () => {
882
- mockService.getFilesByCategory.mockResolvedValue([]);
891
+ mockFetchFileDisplayData.mockResolvedValue([]);
883
892
 
884
893
  const { result, rerender } = renderHook(
885
894
  ({ category }) =>
@@ -899,7 +908,7 @@ describe('useFileDisplay Hook', () => {
899
908
  { timeout: 2000 }
900
909
  );
901
910
 
902
- const firstCallCount = mockService.getFilesByCategory.mock.calls.length;
911
+ const firstCallCount = mockFetchFileDisplayData.mock.calls.length;
903
912
  expect(firstCallCount).toBeGreaterThan(0); // Ensure initial call happened
904
913
 
905
914
  // Change category - this should trigger a refetch
@@ -914,11 +923,11 @@ describe('useFileDisplay Hook', () => {
914
923
 
915
924
  // Should have refetched with new category
916
925
  // The hook may batch calls or React may optimize, so we check it was called at least once more
917
- expect(mockService.getFilesByCategory.mock.calls.length).toBeGreaterThanOrEqual(firstCallCount);
926
+ expect(mockFetchFileDisplayData.mock.calls.length).toBeGreaterThanOrEqual(firstCallCount);
918
927
  });
919
928
 
920
929
  it('refetches when organisation_id changes', async () => {
921
- mockService.getFilesByCategory.mockResolvedValue([]);
930
+ mockFetchFileDisplayData.mockResolvedValue([]);
922
931
 
923
932
  const { result, rerender } = renderHook(
924
933
  ({ orgId }) =>
@@ -947,11 +956,11 @@ describe('useFileDisplay Hook', () => {
947
956
  );
948
957
 
949
958
  // Should have refetched with new organisation ID
950
- expect(mockService.getFilesByCategory.mock.calls.length).toBeGreaterThan(1);
959
+ expect(mockFetchFileDisplayData.mock.calls.length).toBeGreaterThan(1);
951
960
  });
952
961
 
953
962
  it('handles supabase client changes', async () => {
954
- mockService.getFilesByCategory.mockResolvedValue([mockFileReference]);
963
+ mockFetchFileDisplayData.mockResolvedValue([mockFileReference]);
955
964
 
956
965
  const { result, rerender } = renderHook(
957
966
  ({ supabase }) =>
@@ -980,9 +989,10 @@ describe('useFileDisplay Hook', () => {
980
989
  { timeout: 2000 }
981
990
  );
982
991
 
983
- // Should have refetched with new client
984
- // The service is created when the hook initializes, so it should be called
985
- expect(createFileReferenceService).toHaveBeenCalled();
992
+ // Hook uses fetchFileDisplayData; when supabase prop changes, effect may re-run depending on ref identity.
993
+ // At minimum, fetch was called on initial mount.
994
+ expect(mockFetchFileDisplayData).toHaveBeenCalled();
995
+ expect(result.current.fileReference).not.toBeNull();
986
996
  });
987
997
  });
988
998
 
@@ -992,7 +1002,7 @@ describe('useFileDisplay Hook', () => {
992
1002
  ...mockFileReference,
993
1003
  file_metadata: null
994
1004
  };
995
- mockService.getFilesByCategory.mockResolvedValue([fileWithoutMetadata]);
1005
+ mockFetchFileDisplayData.mockResolvedValue([fileWithoutMetadata]);
996
1006
 
997
1007
  const { result } = renderHook(() =>
998
1008
  useFileDisplay('event', 'event-123', 'org-123', FileCategoryEnum.EVENT_LOGOS, {
@@ -1016,7 +1026,7 @@ describe('useFileDisplay Hook', () => {
1016
1026
  ...mockFileReference,
1017
1027
  file_path: null
1018
1028
  };
1019
- mockService.getFilesByCategory.mockResolvedValue([fileWithoutPath]);
1029
+ mockFetchFileDisplayData.mockResolvedValue([fileWithoutPath]);
1020
1030
 
1021
1031
  const { result } = renderHook(() =>
1022
1032
  useFileDisplay('event', 'event-123', 'org-123', FileCategoryEnum.EVENT_LOGOS, {
@@ -1049,7 +1059,7 @@ describe('useFileDisplay Hook', () => {
1049
1059
  });
1050
1060
 
1051
1061
  it('handles null category parameter for multiple file mode', async () => {
1052
- mockService.listFileReferences.mockResolvedValue([]);
1062
+ mockFetchFileDisplayData.mockResolvedValue([]);
1053
1063
 
1054
1064
  const { result } = renderHook(() =>
1055
1065
  useFileDisplay('event', 'event-123', 'org-123', null, {
@@ -1065,17 +1075,19 @@ describe('useFileDisplay Hook', () => {
1065
1075
  );
1066
1076
 
1067
1077
  // Should use multiple file mode
1068
- expect(mockService.listFileReferences).toHaveBeenCalledWith(
1069
- 'event',
1070
- 'event-123',
1071
- 'org-123'
1078
+ expect(mockFetchFileDisplayData).toHaveBeenCalledWith(
1079
+ expect.objectContaining({
1080
+ table_name: 'event',
1081
+ record_id: 'event-123',
1082
+ organisation_id: 'org-123',
1083
+ })
1072
1084
  );
1073
1085
  });
1074
1086
 
1075
1087
  it('handles invalid organisation ID format gracefully', async () => {
1076
1088
  const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
1077
1089
 
1078
- mockService.getFilesByCategory.mockResolvedValue([]);
1090
+ mockFetchFileDisplayData.mockResolvedValue([]);
1079
1091
 
1080
1092
  const { result } = renderHook(() =>
1081
1093
  useFileDisplay('event', 'event-123', 'not-a-uuid', FileCategoryEnum.EVENT_LOGOS, {
@@ -1105,5 +1117,322 @@ describe('useFileDisplay Hook', () => {
1105
1117
  consoleWarnSpy.mockRestore();
1106
1118
  });
1107
1119
  });
1120
+
1121
+ describe('Dual-Scope Search (organisation_id undefined)', () => {
1122
+ it('searches both user-scoped and organisation-scoped files when organisation_id is undefined', async () => {
1123
+ const userScopedFile = {
1124
+ ...mockFileReference,
1125
+ id: 'user-file-1',
1126
+ organisation_id: null,
1127
+ };
1128
+
1129
+ // Mock user-scoped query
1130
+ mockFetchFileDisplayData.mockResolvedValueOnce([userScopedFile]);
1131
+
1132
+ // Mock getUser to return a user
1133
+ (mockSupabase.auth.getUser as any).mockResolvedValue({
1134
+ data: { user: { id: 'user-123' } },
1135
+ error: null,
1136
+ });
1137
+
1138
+ // Mock organisation memberships query
1139
+ const mockMembershipsQuery = {
1140
+ select: vi.fn().mockReturnThis(),
1141
+ eq: vi.fn().mockResolvedValue({
1142
+ data: [{ organisation_id: 'org-123' }],
1143
+ error: null,
1144
+ }),
1145
+ };
1146
+
1147
+ // Mock organisation-scoped query
1148
+ mockFetchFileDisplayData.mockResolvedValueOnce([mockFileReference]);
1149
+
1150
+ const mockFrom = vi.fn((table: string) => {
1151
+ if (table === 'core_organisation_memberships') {
1152
+ return mockMembershipsQuery;
1153
+ }
1154
+ return {
1155
+ select: vi.fn().mockReturnThis(),
1156
+ eq: vi.fn().mockReturnThis(),
1157
+ order: vi.fn().mockReturnThis(),
1158
+ };
1159
+ });
1160
+ (mockSupabase.from as any) = mockFrom;
1161
+
1162
+ const { result } = renderHook(() =>
1163
+ useFileDisplay('event', 'event-123', undefined, FileCategoryEnum.EVENT_LOGOS, {
1164
+ supabase: mockSupabase
1165
+ })
1166
+ );
1167
+
1168
+ await waitFor(
1169
+ () => {
1170
+ expect(result.current.isLoading).toBe(false);
1171
+ },
1172
+ { timeout: 2000 }
1173
+ );
1174
+
1175
+ // Should have queried both scopes
1176
+ expect(mockFetchFileDisplayData).toHaveBeenCalled();
1177
+ });
1178
+
1179
+ it('handles user with no organisation memberships', async () => {
1180
+ mockFetchFileDisplayData.mockResolvedValueOnce([mockFileReference]);
1181
+
1182
+ (mockSupabase.auth.getUser as any).mockResolvedValue({
1183
+ data: { user: { id: 'user-123' } },
1184
+ error: null,
1185
+ });
1186
+
1187
+ // Mock memberships query to return empty
1188
+ const mockMembershipsQuery = {
1189
+ select: vi.fn().mockReturnThis(),
1190
+ eq: vi.fn().mockResolvedValue({
1191
+ data: [],
1192
+ error: null,
1193
+ }),
1194
+ };
1195
+
1196
+ // Mock the fallback query
1197
+ const mockFallbackQuery = {
1198
+ select: vi.fn().mockReturnThis(),
1199
+ eq: vi.fn().mockReturnThis(),
1200
+ order: vi.fn().mockResolvedValue({
1201
+ data: [],
1202
+ error: null,
1203
+ }),
1204
+ };
1205
+
1206
+ const mockFrom = vi.fn((table: string) => {
1207
+ if (table === 'core_organisation_memberships') {
1208
+ return mockMembershipsQuery;
1209
+ }
1210
+ if (table === 'core_file_references') {
1211
+ return mockFallbackQuery;
1212
+ }
1213
+ return {
1214
+ select: vi.fn().mockReturnThis(),
1215
+ eq: vi.fn().mockReturnThis(),
1216
+ };
1217
+ });
1218
+ (mockSupabase.from as any) = mockFrom;
1219
+
1220
+ const { result } = renderHook(() =>
1221
+ useFileDisplay('event', 'event-123', undefined, FileCategoryEnum.EVENT_LOGOS, {
1222
+ supabase: mockSupabase
1223
+ })
1224
+ );
1225
+
1226
+ await waitFor(
1227
+ () => {
1228
+ expect(result.current.isLoading).toBe(false);
1229
+ },
1230
+ { timeout: 2000 }
1231
+ );
1232
+
1233
+ expect(result.current.error).toBe(null);
1234
+ });
1235
+
1236
+ it('handles errors when querying user-scoped files', async () => {
1237
+ mockFetchFileDisplayData.mockRejectedValueOnce(new Error('User scope error'));
1238
+
1239
+ (mockSupabase.auth.getUser as any).mockResolvedValue({
1240
+ data: { user: { id: 'user-123' } },
1241
+ error: null,
1242
+ });
1243
+
1244
+ const mockFrom = vi.fn().mockReturnValue({
1245
+ select: vi.fn().mockReturnThis(),
1246
+ eq: vi.fn().mockReturnThis(),
1247
+ });
1248
+ (mockSupabase.from as any) = mockFrom;
1249
+
1250
+ const { result } = renderHook(() =>
1251
+ useFileDisplay('event', 'event-123', undefined, FileCategoryEnum.EVENT_LOGOS, {
1252
+ supabase: mockSupabase
1253
+ })
1254
+ );
1255
+
1256
+ await waitFor(
1257
+ () => {
1258
+ expect(result.current.isLoading).toBe(false);
1259
+ },
1260
+ { timeout: 2000 }
1261
+ );
1262
+
1263
+ // Hook sets error when fetchFileDisplayData rejects
1264
+ expect(result.current.error).not.toBe(null);
1265
+ expect(result.current.error?.message).toContain('User scope error');
1266
+ });
1267
+
1268
+ it('handles errors when getting user', async () => {
1269
+ mockFetchFileDisplayData.mockResolvedValueOnce([]);
1270
+
1271
+ (mockSupabase.auth.getUser as any).mockResolvedValue({
1272
+ data: { user: null },
1273
+ error: { message: 'User error' },
1274
+ });
1275
+
1276
+ const mockFrom = vi.fn().mockReturnValue({
1277
+ select: vi.fn().mockReturnThis(),
1278
+ eq: vi.fn().mockReturnThis(),
1279
+ });
1280
+ (mockSupabase.from as any) = mockFrom;
1281
+
1282
+ const { result } = renderHook(() =>
1283
+ useFileDisplay('event', 'event-123', undefined, FileCategoryEnum.EVENT_LOGOS, {
1284
+ supabase: mockSupabase
1285
+ })
1286
+ );
1287
+
1288
+ await waitFor(
1289
+ () => {
1290
+ expect(result.current.isLoading).toBe(false);
1291
+ },
1292
+ { timeout: 2000 }
1293
+ );
1294
+
1295
+ // Hook only calls fetchFileDisplayData; empty result yields no error
1296
+ expect(result.current.error).toBe(null);
1297
+ expect(result.current.fileReferences).toEqual([]);
1298
+ });
1299
+
1300
+ it('handles fallback query when no files found through RPC', async () => {
1301
+ mockFetchFileDisplayData.mockResolvedValueOnce([]);
1302
+
1303
+ (mockSupabase.auth.getUser as any).mockResolvedValue({
1304
+ data: { user: { id: 'user-123' } },
1305
+ error: null,
1306
+ });
1307
+
1308
+ const mockMembershipsQuery = {
1309
+ select: vi.fn().mockReturnThis(),
1310
+ eq: vi.fn().mockResolvedValue({
1311
+ data: [],
1312
+ error: null,
1313
+ }),
1314
+ };
1315
+
1316
+ // Mock fallback query to return files - need to chain properly
1317
+ const _mockFallbackQuery = {
1318
+ select: vi.fn().mockReturnThis(),
1319
+ eq: vi.fn().mockReturnThis(),
1320
+ order: vi.fn().mockResolvedValue({
1321
+ data: [{
1322
+ id: 'fallback-file-1',
1323
+ table_name: 'event',
1324
+ record_id: 'event-123',
1325
+ file_path: 'path/to/file.jpg',
1326
+ file_metadata: { category: FileCategoryEnum.EVENT_LOGOS },
1327
+ organisation_id: 'org-123',
1328
+ app_id: 'app-123',
1329
+ is_public: true,
1330
+ created_at: '2024-01-01T00:00:00Z',
1331
+ updated_at: '2024-01-01T00:00:00Z',
1332
+ }],
1333
+ error: null,
1334
+ }),
1335
+ };
1336
+
1337
+ // Create a proper chain for the fallback query
1338
+ const createFallbackChain = () => {
1339
+ const chain = {
1340
+ select: vi.fn().mockReturnThis(),
1341
+ eq: vi.fn().mockReturnThis(),
1342
+ order: vi.fn().mockResolvedValue({
1343
+ data: [{
1344
+ id: 'fallback-file-1',
1345
+ table_name: 'event',
1346
+ record_id: 'event-123',
1347
+ file_path: 'path/to/file.jpg',
1348
+ file_metadata: { category: FileCategoryEnum.EVENT_LOGOS },
1349
+ organisation_id: 'org-123',
1350
+ app_id: 'app-123',
1351
+ is_public: true,
1352
+ created_at: '2024-01-01T00:00:00Z',
1353
+ updated_at: '2024-01-01T00:00:00Z',
1354
+ }],
1355
+ error: null,
1356
+ }),
1357
+ };
1358
+ return chain;
1359
+ };
1360
+
1361
+ const mockFrom = vi.fn((table: string) => {
1362
+ if (table === 'core_organisation_memberships') {
1363
+ return mockMembershipsQuery;
1364
+ }
1365
+ if (table === 'core_file_references') {
1366
+ return createFallbackChain();
1367
+ }
1368
+ return {
1369
+ select: vi.fn().mockReturnThis(),
1370
+ eq: vi.fn().mockReturnThis(),
1371
+ };
1372
+ });
1373
+ (mockSupabase.from as any) = mockFrom;
1374
+
1375
+ const { result } = renderHook(() =>
1376
+ useFileDisplay('event', 'event-123', undefined, FileCategoryEnum.EVENT_LOGOS, {
1377
+ supabase: mockSupabase
1378
+ })
1379
+ );
1380
+
1381
+ await waitFor(
1382
+ () => {
1383
+ expect(result.current.isLoading).toBe(false);
1384
+ },
1385
+ { timeout: 2000 }
1386
+ );
1387
+
1388
+ // The fallback query may or may not find files depending on RLS
1389
+ // This test verifies the hook handles the fallback path without errors
1390
+ expect(result.current.error).toBe(null);
1391
+ expect(Array.isArray(result.current.fileReferences)).toBe(true);
1392
+ });
1393
+
1394
+ it('handles empty string organisation_id as explicit null', async () => {
1395
+ mockFetchFileDisplayData.mockResolvedValueOnce([]);
1396
+
1397
+ // When organisation_id is empty string, should treat as null (not undefined)
1398
+ const { result } = renderHook(() =>
1399
+ useFileDisplay('event', 'event-123', '', FileCategoryEnum.EVENT_LOGOS, {
1400
+ supabase: mockSupabase
1401
+ })
1402
+ );
1403
+
1404
+ await waitFor(
1405
+ () => {
1406
+ expect(result.current.isLoading).toBe(false);
1407
+ },
1408
+ { timeout: 2000 }
1409
+ );
1410
+
1411
+ expect(result.current.error).toBe(null);
1412
+ });
1413
+ });
1414
+
1415
+ describe('Component Unmount Handling', () => {
1416
+ it('does not update state after component unmounts', async () => {
1417
+ mockFetchFileDisplayData.mockImplementation(() =>
1418
+ new Promise((resolve) => setTimeout(() => resolve([mockFileReference]), 100))
1419
+ );
1420
+
1421
+ const { result, unmount } = renderHook(() =>
1422
+ useFileDisplay('event', 'event-123', 'org-123', FileCategoryEnum.EVENT_LOGOS, {
1423
+ supabase: mockSupabase
1424
+ })
1425
+ );
1426
+
1427
+ // Unmount before promise resolves
1428
+ unmount();
1429
+
1430
+ // Wait for promise to resolve
1431
+ await new Promise(resolve => setTimeout(resolve, 150));
1432
+
1433
+ // State should not have been updated (no errors thrown)
1434
+ expect(result.current.isLoading).toBeDefined();
1435
+ });
1436
+ });
1108
1437
  });
1109
1438