@jmruthers/pace-core 0.5.54 → 0.5.56

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 (396) hide show
  1. package/README.md +0 -4
  2. package/dist/{DataTable-7FMFXA7A.js → DataTable-DJQTKX33.js} +11 -11
  3. package/dist/{PublicLoadingSpinner-Bq_-BeK-.d.ts → PublicLoadingSpinner-SL8WaQN7.d.ts} +2 -21
  4. package/dist/{api-H5A3H4IR.js → api-LUNF5O6M.js} +3 -3
  5. package/dist/{appConfig-BVGyuvI7.d.ts → appConfig-DjpeG6P-.d.ts} +9 -1
  6. package/dist/{appNameResolver-7GHF5ED2.js → appNameResolver-UURKN7NF.js} +2 -2
  7. package/dist/{audit-BUW3LMJB.js → audit-6TOCAMKO.js} +2 -2
  8. package/dist/{chunk-NRK4AIHQ.js → chunk-2DFCT6D3.js} +3 -3
  9. package/dist/{chunk-GIO7BFE7.js → chunk-3JKVVLD3.js} +66 -169
  10. package/dist/{chunk-GIO7BFE7.js.map → chunk-3JKVVLD3.js.map} +1 -1
  11. package/dist/{chunk-MZBUOP4P.js → chunk-5BSLGBYI.js} +4 -3
  12. package/dist/chunk-5BSLGBYI.js.map +1 -0
  13. package/dist/{chunk-I5Z3QH5X.js → chunk-66C4BSAY.js} +2 -2
  14. package/dist/{chunk-I5Z3QH5X.js.map → chunk-66C4BSAY.js.map} +1 -1
  15. package/dist/{chunk-EL2O4IUX.js → chunk-ASXSJGPW.js} +20 -24
  16. package/dist/{chunk-EL2O4IUX.js.map → chunk-ASXSJGPW.js.map} +1 -1
  17. package/dist/{chunk-7BNPOCLL.js → chunk-B2WTCLCV.js} +6 -2
  18. package/dist/chunk-B2WTCLCV.js.map +1 -0
  19. package/dist/{chunk-WJARTBCT.js → chunk-D7ARGIA3.js} +16 -7
  20. package/dist/chunk-D7ARGIA3.js.map +1 -0
  21. package/dist/{chunk-MYP2EGHX.js → chunk-GIDCWCHF.js} +21 -14
  22. package/dist/chunk-GIDCWCHF.js.map +1 -0
  23. package/dist/{chunk-MSFACPQQ.js → chunk-HYNGIE5T.js} +11 -11
  24. package/dist/{chunk-MSFACPQQ.js.map → chunk-HYNGIE5T.js.map} +1 -1
  25. package/dist/{chunk-TRIZ7IB7.js → chunk-I5GID3EX.js} +148 -288
  26. package/dist/chunk-I5GID3EX.js.map +1 -0
  27. package/dist/{chunk-GWSBHC4J.js → chunk-KLPVOPRI.js} +261 -38
  28. package/dist/chunk-KLPVOPRI.js.map +1 -0
  29. package/dist/{chunk-BC3S53OZ.js → chunk-N6XMGSGD.js} +30 -14
  30. package/dist/chunk-N6XMGSGD.js.map +1 -0
  31. package/dist/{chunk-6MTY77WU.js → chunk-QB4GXDUM.js} +3 -3
  32. package/dist/{chunk-YDJW5XTN.js → chunk-STT7INZR.js} +25 -1
  33. package/dist/chunk-STT7INZR.js.map +1 -0
  34. package/dist/{chunk-NYUJ4FJR.js → chunk-UETTVYKU.js} +7 -7
  35. package/dist/chunk-UETTVYKU.js.map +1 -0
  36. package/dist/{chunk-22KLBHPS.js → chunk-W66AZIOH.js} +2 -2
  37. package/dist/chunk-W66AZIOH.js.map +1 -0
  38. package/dist/{chunk-NZ655MWE.js → chunk-YEHO6FDW.js} +5 -4
  39. package/dist/chunk-YEHO6FDW.js.map +1 -0
  40. package/dist/{chunk-SS3E6QLB.js → chunk-YNUBMSMV.js} +2 -2
  41. package/dist/chunk-YNUBMSMV.js.map +1 -0
  42. package/dist/{chunk-74C6SNEC.js → chunk-ZPK5656W.js} +3 -3
  43. package/dist/{chunk-74C6SNEC.js.map → chunk-ZPK5656W.js.map} +1 -1
  44. package/dist/components.d.ts +22 -899
  45. package/dist/components.js +436 -3118
  46. package/dist/components.js.map +1 -1
  47. package/dist/file-reference-9xUOnwyt.d.ts +70 -0
  48. package/dist/hooks.d.ts +2 -2
  49. package/dist/hooks.js +10 -10
  50. package/dist/hooks.js.map +1 -1
  51. package/dist/index.d.ts +49 -9
  52. package/dist/index.js +190 -25
  53. package/dist/index.js.map +1 -1
  54. package/dist/{organisation-CO3Sh3_D.d.ts → organisation-t-vvQC3g.d.ts} +1 -8
  55. package/dist/providers.d.ts +2 -2
  56. package/dist/providers.js +5 -5
  57. package/dist/rbac/index.d.ts +65 -46
  58. package/dist/rbac/index.js +10 -12
  59. package/dist/styles/core.css +0 -125
  60. package/dist/types.d.ts +2 -1
  61. package/dist/types.js +3 -1
  62. package/dist/types.js.map +1 -1
  63. package/dist/{usePublicRouteParams-B2OcAsur.d.ts → usePublicRouteParams-CdoFxnJK.d.ts} +1 -1
  64. package/dist/utils.d.ts +3 -4
  65. package/dist/utils.js +44 -13
  66. package/dist/utils.js.map +1 -1
  67. package/docs/FILE_REFERENCE_SYSTEM.md +440 -0
  68. package/docs/INDEX.md +7 -5
  69. package/docs/README.md +0 -1
  70. package/docs/api/README.md +0 -4
  71. package/docs/api/classes/ErrorBoundary.md +1 -1
  72. package/docs/api/classes/InvalidScopeError.md +1 -1
  73. package/docs/api/classes/MissingUserContextError.md +1 -1
  74. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  75. package/docs/api/classes/PermissionDeniedError.md +2 -2
  76. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  77. package/docs/api/classes/RBACAuditManager.md +12 -12
  78. package/docs/api/classes/RBACCache.md +1 -1
  79. package/docs/api/classes/RBACEngine.md +6 -6
  80. package/docs/api/classes/RBACError.md +1 -1
  81. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  82. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  83. package/docs/api/classes/StorageUtils.md +281 -0
  84. package/docs/api/interfaces/AggregateConfig.md +1 -1
  85. package/docs/api/interfaces/ButtonProps.md +1 -1
  86. package/docs/api/interfaces/CardProps.md +1 -1
  87. package/docs/api/interfaces/ColorPalette.md +1 -1
  88. package/docs/api/interfaces/ColorShade.md +1 -1
  89. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  90. package/docs/api/interfaces/DataTableAction.md +1 -1
  91. package/docs/api/interfaces/DataTableColumn.md +1 -1
  92. package/docs/api/interfaces/DataTableProps.md +1 -1
  93. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  94. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  95. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  96. package/docs/api/interfaces/EventContextType.md +1 -1
  97. package/docs/api/interfaces/EventLogoProps.md +1 -1
  98. package/docs/api/interfaces/EventProviderProps.md +1 -1
  99. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  100. package/docs/api/interfaces/FileUploadProps.md +1 -1
  101. package/docs/api/interfaces/FooterProps.md +1 -1
  102. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  103. package/docs/api/interfaces/InputProps.md +1 -1
  104. package/docs/api/interfaces/LabelProps.md +1 -1
  105. package/docs/api/interfaces/LoginFormProps.md +1 -1
  106. package/docs/api/interfaces/NavigationAccessRecord.md +2 -2
  107. package/docs/api/interfaces/NavigationContextType.md +1 -1
  108. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  109. package/docs/api/interfaces/NavigationItem.md +1 -1
  110. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  111. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  112. package/docs/api/interfaces/Organisation.md +1 -1
  113. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  114. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  115. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  116. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  117. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  118. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  119. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  120. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  121. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  122. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  123. package/docs/api/interfaces/PaletteData.md +1 -1
  124. package/docs/api/interfaces/PermissionEnforcerProps.md +4 -4
  125. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  126. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  127. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  128. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  129. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  130. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  131. package/docs/api/interfaces/RBACConfig.md +1 -1
  132. package/docs/api/interfaces/RBACContextType.md +1 -1
  133. package/docs/api/interfaces/RBACLogger.md +1 -1
  134. package/docs/api/interfaces/RBACProviderProps.md +1 -1
  135. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  136. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  137. package/docs/api/interfaces/RouteAccessRecord.md +2 -2
  138. package/docs/api/interfaces/RouteConfig.md +2 -2
  139. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  140. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  141. package/docs/api/interfaces/StorageConfig.md +1 -1
  142. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  143. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  144. package/docs/api/interfaces/StorageListOptions.md +1 -1
  145. package/docs/api/interfaces/StorageListResult.md +1 -1
  146. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  147. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  148. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  149. package/docs/api/interfaces/StyleImport.md +1 -1
  150. package/docs/api/interfaces/ToastActionElement.md +1 -1
  151. package/docs/api/interfaces/ToastProps.md +1 -1
  152. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  153. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  154. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  155. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  156. package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
  157. package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
  158. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  159. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  160. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  161. package/docs/api/interfaces/UserEventAccess.md +1 -1
  162. package/docs/api/interfaces/UserMenuProps.md +1 -1
  163. package/docs/api/interfaces/UserProfile.md +1 -1
  164. package/docs/api/modules.md +204 -200
  165. package/docs/api-reference/components.md +141 -163
  166. package/docs/api-reference/hooks.md +347 -0
  167. package/docs/core-concepts/rbac-system.md +69 -16
  168. package/docs/getting-started/examples/basic-auth-app.md +0 -1
  169. package/docs/implementation-guides/datatable-rbac-usage.md +12 -11
  170. package/docs/implementation-guides/file-upload-storage.md +733 -0
  171. package/docs/implementation-guides/inactivity-tracking.md +779 -0
  172. package/docs/implementation-guides/organisation-security.md +748 -0
  173. package/docs/implementation-guides/public-pages-advanced.md +1022 -0
  174. package/docs/migration/MIGRATION_GUIDE.md +684 -0
  175. package/docs/migration/README.md +13 -2
  176. package/docs/migration/rbac-migration.md +73 -0
  177. package/docs/rbac/examples/rbac-rls-integration-example.md +11 -13
  178. package/docs/style-guide.md +269 -1
  179. package/package.json +1 -1
  180. package/src/__tests__/TESTING_GUIDELINES.md +331 -18
  181. package/src/__tests__/helpers/supabaseMock.ts +99 -0
  182. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +10 -7
  183. package/src/__tests__/shared.ts +6 -0
  184. package/src/components/DataTable/components/ActionButtons.tsx +2 -2
  185. package/src/components/DataTable/components/DataTableCore.tsx +2 -2
  186. package/src/components/DataTable/components/UnifiedTableBody.tsx +1 -1
  187. package/src/components/DataTable/utils/debugTools.ts +2 -2
  188. package/src/components/Dialog/Dialog.test.tsx +12 -2
  189. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +6 -6
  190. package/src/components/ErrorBoundary/ErrorBoundary.tsx +2 -2
  191. package/src/components/FileDisplay.tsx +233 -0
  192. package/src/components/FileUpload.tsx +176 -0
  193. package/src/components/Footer/Footer.test.tsx +7 -7
  194. package/src/components/NavigationMenu/NavigationMenu.test.tsx +13 -6
  195. package/src/components/OrganisationSelector/OrganisationSelector.test.tsx +30 -3
  196. package/src/components/OrganisationSelector/OrganisationSelector.tsx +1 -1
  197. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.rbac.test.tsx +558 -0
  198. package/src/components/PublicLayout/PublicErrorBoundary.tsx +1 -1
  199. package/src/components/PublicLayout/PublicPageDebugger.tsx +2 -2
  200. package/src/components/PublicLayout/PublicPageDiagnostic.tsx +2 -2
  201. package/src/components/PublicLayout/PublicPageProvider.tsx +2 -2
  202. package/src/components/Select/Select.test.tsx +50 -15
  203. package/src/components/SuperAdminGuard.tsx +2 -2
  204. package/src/components/__tests__/SuperAdminGuard.test.tsx +559 -0
  205. package/src/components/index.ts +0 -183
  206. package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +2 -2
  207. package/src/hooks/__tests__/usePermissionCache.unit.test.ts +1 -1
  208. package/src/hooks/__tests__/useRBAC.unit.test.ts +191 -138
  209. package/src/hooks/public/usePublicEvent.ts +2 -2
  210. package/src/hooks/useAppConfig.ts +3 -3
  211. package/src/hooks/useComponentPerformance.ts +1 -1
  212. package/src/hooks/useDataTablePerformance.ts +1 -1
  213. package/src/hooks/useFileReference.ts +232 -0
  214. package/src/hooks/useOrganisationPermissions.test.ts +254 -344
  215. package/src/hooks/useOrganisationPermissions.ts +15 -7
  216. package/src/hooks/useOrganisationSecurity.test.ts +390 -402
  217. package/src/hooks/usePerformanceMonitor.ts +1 -1
  218. package/src/hooks/usePermissionCache.test.ts +264 -395
  219. package/src/hooks/usePermissionCache.ts +34 -4
  220. package/src/hooks/useSecureDataAccess.test.ts +486 -0
  221. package/src/hooks/useSecureDataAccess.ts +4 -1
  222. package/src/providers/InactivityProvider.tsx +2 -2
  223. package/src/providers/OrganisationProvider.test.simple.tsx +168 -0
  224. package/src/providers/OrganisationProvider.test.tsx +168 -0
  225. package/src/providers/OrganisationProvider.tsx +25 -31
  226. package/src/providers/UnifiedAuthProvider.test.simple.tsx +205 -0
  227. package/src/providers/UnifiedAuthProvider.test.tsx +128 -0
  228. package/src/providers/__tests__/InactivityProvider.test.tsx +3 -4
  229. package/src/providers/__tests__/OrganisationProvider.test.tsx +19 -14
  230. package/src/rbac/__tests__/integration.authflow.test.tsx +123 -0
  231. package/src/rbac/__tests__/integration.navigation.test.tsx +72 -0
  232. package/src/rbac/__tests__/integration.securedata.test.tsx +92 -0
  233. package/src/rbac/__tests__/integration.smoke.test.tsx +73 -0
  234. package/src/rbac/__tests__/rbac-core.test.tsx +26 -22
  235. package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +411 -0
  236. package/src/rbac/__tests__/rbac-engine-simplified.test.ts +285 -0
  237. package/src/rbac/__tests__/rbac-functions.test.ts +655 -0
  238. package/src/rbac/__tests__/rbac-integration.test.ts +532 -0
  239. package/src/rbac/__tests__/scenarios.user-role.test.tsx +196 -0
  240. package/src/rbac/api.test.ts +6 -6
  241. package/src/rbac/api.ts +2 -2
  242. package/src/rbac/audit.test.ts +485 -0
  243. package/src/rbac/audit.ts +7 -1
  244. package/src/rbac/cache-invalidation.ts +318 -0
  245. package/src/rbac/cache.test.ts +286 -0
  246. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +559 -0
  247. package/src/rbac/components/EnhancedNavigationMenu.tsx +29 -23
  248. package/src/rbac/components/NavigationProvider.test.tsx +449 -0
  249. package/src/rbac/components/PagePermissionGuard.tsx +4 -4
  250. package/src/rbac/components/PagePermissionProvider.test.tsx +479 -0
  251. package/src/rbac/components/SecureDataProvider.test.tsx +511 -0
  252. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +159 -430
  253. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +4 -5
  254. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +112 -118
  255. package/src/rbac/config.test.ts +410 -0
  256. package/src/rbac/engine.test.simple.ts +237 -0
  257. package/src/rbac/engine.test.ts +233 -0
  258. package/src/rbac/engine.ts +37 -41
  259. package/src/rbac/examples/CompleteRBACExample.tsx +3 -3
  260. package/src/rbac/examples/EventBasedApp.tsx +4 -4
  261. package/src/rbac/hooks/useRBAC.simple.test.ts +16 -0
  262. package/src/rbac/hooks/useRBAC.test.ts +207 -455
  263. package/src/rbac/hooks/useRBAC.ts +30 -22
  264. package/src/rbac/permissions.test.ts +128 -0
  265. package/src/rbac/permissions.ts +56 -141
  266. package/src/rbac/providers/RBACProvider.tsx +1 -1
  267. package/src/rbac/secureClient.test.ts +444 -0
  268. package/src/rbac/security.test.ts +390 -0
  269. package/src/rbac/security.ts +1 -1
  270. package/src/rbac/types.test.ts +382 -0
  271. package/src/rbac/types.ts +2 -2
  272. package/src/styles/core.css +0 -125
  273. package/src/types/file-reference.ts +77 -0
  274. package/src/types/rbac-functions.ts +290 -0
  275. package/src/types/supabase.ts +10 -28
  276. package/src/types/unified.ts +4 -1
  277. package/src/utils/__tests__/bundleAnalysis.unit.test.ts +81 -55
  278. package/src/utils/__tests__/lazyLoad.unit.test.tsx +21 -12
  279. package/src/utils/__tests__/organisationContext.unit.test.ts +13 -7
  280. package/src/utils/__tests__/performanceBudgets.unit.test.ts +3 -3
  281. package/src/utils/__tests__/sessionTracking.unit.test.ts +32 -12
  282. package/src/utils/appConfig.ts +1 -1
  283. package/src/utils/appIdResolver.test.ts +503 -0
  284. package/src/utils/appIdResolver.ts +1 -1
  285. package/src/utils/appNameResolver.test.ts +494 -0
  286. package/src/utils/appNameResolver.ts +3 -2
  287. package/src/utils/bundleAnalysis.ts +3 -3
  288. package/src/utils/debugLogger.ts +1 -1
  289. package/src/utils/file-reference.ts +263 -0
  290. package/src/utils/formatDate.test.ts +2 -2
  291. package/src/utils/organisationContext.test.ts +340 -0
  292. package/src/utils/organisationContext.ts +19 -6
  293. package/src/utils/performanceBudgets.ts +2 -2
  294. package/src/utils/permissionUtils.test.ts +393 -0
  295. package/src/utils/permissionUtils.ts +5 -2
  296. package/src/utils/secureDataAccess.test.ts +715 -0
  297. package/src/utils/secureDataAccess.ts +21 -5
  298. package/src/utils/sessionTracking.ts +34 -4
  299. package/src/utils/storage/__tests__/helpers.unit.test.ts +328 -0
  300. package/src/utils/storage/__tests__/index.unit.test.ts +16 -0
  301. package/src/utils/storage/helpers.ts +20 -25
  302. package/src/utils/storage/index.ts +29 -1
  303. package/src/vite-env.d.ts +17 -0
  304. package/dist/chunk-22KLBHPS.js.map +0 -1
  305. package/dist/chunk-7BNPOCLL.js.map +0 -1
  306. package/dist/chunk-BC3S53OZ.js.map +0 -1
  307. package/dist/chunk-GWSBHC4J.js.map +0 -1
  308. package/dist/chunk-MYP2EGHX.js.map +0 -1
  309. package/dist/chunk-MZBUOP4P.js.map +0 -1
  310. package/dist/chunk-NYUJ4FJR.js.map +0 -1
  311. package/dist/chunk-NZ655MWE.js.map +0 -1
  312. package/dist/chunk-SS3E6QLB.js.map +0 -1
  313. package/dist/chunk-TRIZ7IB7.js.map +0 -1
  314. package/dist/chunk-WJARTBCT.js.map +0 -1
  315. package/dist/chunk-YDJW5XTN.js.map +0 -1
  316. package/docs/print-components/README.md +0 -258
  317. package/docs/print-components/api-reference.md +0 -636
  318. package/docs/print-components/examples/README.md +0 -204
  319. package/docs/print-components/examples/basic-report.tsx +0 -92
  320. package/docs/print-components/examples/card-catalog.tsx +0 -149
  321. package/docs/print-components/examples/cover-page-report.tsx +0 -163
  322. package/docs/print-components/quick-start.md +0 -363
  323. package/src/components/PrintButton/PrintButton.tsx +0 -321
  324. package/src/components/PrintButton/PrintButtonGroup.tsx +0 -84
  325. package/src/components/PrintButton/PrintToolbar.tsx +0 -94
  326. package/src/components/PrintButton/__tests__/PrintButton.test.tsx +0 -271
  327. package/src/components/PrintButton/examples/PrintButtonShowcase.tsx +0 -438
  328. package/src/components/PrintButton/index.ts +0 -33
  329. package/src/components/PrintButton/types.ts +0 -173
  330. package/src/components/PrintCard/PrintCard.tsx +0 -154
  331. package/src/components/PrintCard/PrintCardContent.tsx +0 -57
  332. package/src/components/PrintCard/PrintCardFooter.tsx +0 -60
  333. package/src/components/PrintCard/PrintCardGrid.tsx +0 -91
  334. package/src/components/PrintCard/PrintCardHeader.tsx +0 -78
  335. package/src/components/PrintCard/PrintCardImage.tsx +0 -81
  336. package/src/components/PrintCard/examples/PrintCardShowcase.tsx +0 -239
  337. package/src/components/PrintCard/index.ts +0 -34
  338. package/src/components/PrintCard/types.ts +0 -171
  339. package/src/components/PrintDataTable/PrintDataTable.tsx +0 -215
  340. package/src/components/PrintDataTable/PrintTableGroup.tsx +0 -90
  341. package/src/components/PrintDataTable/PrintTableRow.tsx +0 -76
  342. package/src/components/PrintDataTable/index.ts +0 -25
  343. package/src/components/PrintDataTable/types.ts +0 -67
  344. package/src/components/PrintFooter/PrintFooter.tsx +0 -183
  345. package/src/components/PrintFooter/PrintFooterContent.tsx +0 -71
  346. package/src/components/PrintFooter/PrintFooterInfo.tsx +0 -86
  347. package/src/components/PrintFooter/PrintPageNumber.tsx +0 -90
  348. package/src/components/PrintFooter/examples/PrintFooterShowcase.tsx +0 -390
  349. package/src/components/PrintFooter/index.ts +0 -30
  350. package/src/components/PrintFooter/types.ts +0 -149
  351. package/src/components/PrintGrid/PrintGrid.tsx +0 -180
  352. package/src/components/PrintGrid/PrintGridBreakpoint.tsx +0 -109
  353. package/src/components/PrintGrid/PrintGridContainer.tsx +0 -128
  354. package/src/components/PrintGrid/PrintGridItem.tsx +0 -220
  355. package/src/components/PrintGrid/examples/PrintGridShowcase.tsx +0 -359
  356. package/src/components/PrintGrid/index.ts +0 -31
  357. package/src/components/PrintGrid/types.ts +0 -159
  358. package/src/components/PrintHeader/PrintCoverHeader.tsx +0 -230
  359. package/src/components/PrintHeader/PrintHeader.tsx +0 -150
  360. package/src/components/PrintHeader/index.ts +0 -17
  361. package/src/components/PrintHeader/types.ts +0 -42
  362. package/src/components/PrintLayout/PrintLayout.tsx +0 -122
  363. package/src/components/PrintLayout/PrintLayoutContext.tsx +0 -66
  364. package/src/components/PrintLayout/PrintPageBreak.tsx +0 -52
  365. package/src/components/PrintLayout/examples/PrintShowcase.tsx +0 -230
  366. package/src/components/PrintLayout/index.ts +0 -19
  367. package/src/components/PrintLayout/types.ts +0 -37
  368. package/src/components/PrintPageBreak/PrintPageBreak.tsx +0 -120
  369. package/src/components/PrintPageBreak/PrintPageBreakGroup.tsx +0 -90
  370. package/src/components/PrintPageBreak/PrintPageBreakIndicator.tsx +0 -112
  371. package/src/components/PrintPageBreak/examples/PrintPageBreakShowcase.tsx +0 -279
  372. package/src/components/PrintPageBreak/index.ts +0 -23
  373. package/src/components/PrintPageBreak/types.ts +0 -94
  374. package/src/components/PrintSection/PrintColumn.tsx +0 -104
  375. package/src/components/PrintSection/PrintDivider.tsx +0 -101
  376. package/src/components/PrintSection/PrintSection.tsx +0 -129
  377. package/src/components/PrintSection/PrintSectionContent.tsx +0 -75
  378. package/src/components/PrintSection/PrintSectionHeader.tsx +0 -97
  379. package/src/components/PrintSection/examples/PrintSectionShowcase.tsx +0 -258
  380. package/src/components/PrintSection/index.ts +0 -33
  381. package/src/components/PrintSection/types.ts +0 -155
  382. package/src/components/PrintText/PrintText.tsx +0 -116
  383. package/src/components/PrintText/index.ts +0 -16
  384. package/src/components/PrintText/types.ts +0 -24
  385. package/src/rbac/__tests__/integration.test.tsx +0 -218
  386. package/src/utils/print/PrintDataProcessor.ts +0 -390
  387. package/src/utils/print/examples/PrintUtilitiesShowcase.tsx +0 -397
  388. package/src/utils/print/index.ts +0 -29
  389. package/src/utils/print/types.ts +0 -196
  390. package/src/utils/print/usePrintOptimization.ts +0 -272
  391. /package/dist/{DataTable-7FMFXA7A.js.map → DataTable-DJQTKX33.js.map} +0 -0
  392. /package/dist/{api-H5A3H4IR.js.map → api-LUNF5O6M.js.map} +0 -0
  393. /package/dist/{appNameResolver-7GHF5ED2.js.map → appNameResolver-UURKN7NF.js.map} +0 -0
  394. /package/dist/{audit-BUW3LMJB.js.map → audit-6TOCAMKO.js.map} +0 -0
  395. /package/dist/{chunk-NRK4AIHQ.js.map → chunk-2DFCT6D3.js.map} +0 -0
  396. /package/dist/{chunk-6MTY77WU.js.map → chunk-QB4GXDUM.js.map} +0 -0
@@ -0,0 +1,233 @@
1
+ // File Display Component
2
+ // Provides a file display interface using the file reference system
3
+
4
+ import React, { useState, useEffect } from 'react';
5
+ import { SupabaseClient } from '@supabase/supabase-js';
6
+ import { FileReference, FileCategory } from '../types/file-reference';
7
+ import { useFileReferenceForRecord } from '../hooks/useFileReference';
8
+
9
+ export interface FileDisplayProps {
10
+ supabase: SupabaseClient;
11
+ table_name: string;
12
+ record_id: string;
13
+ organisation_id: string;
14
+ category?: FileCategory;
15
+ showUpload?: boolean;
16
+ showDelete?: boolean;
17
+ className?: string;
18
+ children?: React.ReactNode;
19
+ }
20
+
21
+ export function FileDisplay({
22
+ supabase,
23
+ table_name,
24
+ record_id,
25
+ organisation_id,
26
+ category,
27
+ showUpload = false,
28
+ showDelete = false,
29
+ className = '',
30
+ children
31
+ }: FileDisplayProps) {
32
+ const {
33
+ isLoading,
34
+ error,
35
+ fileUrl,
36
+ fileReference,
37
+ fileReferences,
38
+ fileCount,
39
+ loadFileReference,
40
+ loadFileUrl,
41
+ loadFileReferences,
42
+ loadFileCount,
43
+ deleteFile,
44
+ clearError
45
+ } = useFileReferenceForRecord(supabase, table_name, record_id, organisation_id);
46
+
47
+ const [imageError, setImageError] = useState(false);
48
+
49
+ // Load file data on mount
50
+ useEffect(() => {
51
+ loadFileCount();
52
+ if (category) {
53
+ loadFileReference();
54
+ } else {
55
+ loadFileReferences();
56
+ }
57
+ }, [loadFileCount, loadFileReference, loadFileReferences, category]);
58
+
59
+ // Load file URL when file reference is available
60
+ useEffect(() => {
61
+ if (fileReference) {
62
+ loadFileUrl();
63
+ }
64
+ }, [fileReference, loadFileUrl]);
65
+
66
+ const handleDelete = async () => {
67
+ if (window.confirm('Are you sure you want to delete this file?')) {
68
+ const success = await deleteFile(true);
69
+ if (success) {
70
+ setImageError(false);
71
+ }
72
+ }
73
+ };
74
+
75
+ const handleImageError = () => {
76
+ setImageError(true);
77
+ };
78
+
79
+ const getFileIcon = (fileType: string) => {
80
+ if (fileType.startsWith('image/')) return '🖼️';
81
+ if (fileType.startsWith('video/')) return '🎥';
82
+ if (fileType.startsWith('audio/')) return '🎵';
83
+ if (fileType.includes('pdf')) return '📄';
84
+ if (fileType.includes('word')) return '📝';
85
+ if (fileType.includes('excel') || fileType.includes('spreadsheet')) return '📊';
86
+ if (fileType.includes('powerpoint') || fileType.includes('presentation')) return '📊';
87
+ return '📁';
88
+ };
89
+
90
+ const formatFileSize = (bytes: number) => {
91
+ if (bytes === 0) return '0 Bytes';
92
+ const k = 1024;
93
+ const sizes = ['Bytes', 'KB', 'MB', 'GB'];
94
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
95
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
96
+ };
97
+
98
+ if (isLoading) {
99
+ return (
100
+ <div className={`flex items-center justify-center p-4 ${className}`}>
101
+ <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-main-500"></div>
102
+ </div>
103
+ );
104
+ }
105
+
106
+ if (error) {
107
+ return (
108
+ <div className={`p-4 bg-acc-50 border border-acc-200 rounded-lg ${className}`}>
109
+ <div className="text-acc-600">
110
+ Error loading file: {error}
111
+ </div>
112
+ <button
113
+ onClick={clearError}
114
+ className="mt-2 text-sm text-acc-700 hover:text-acc-800 underline"
115
+ >
116
+ Try again
117
+ </button>
118
+ </div>
119
+ );
120
+ }
121
+
122
+ if (fileCount === 0) {
123
+ return (
124
+ <div className={`text-sec-500 text-center p-4 ${className}`}>
125
+ No files found
126
+ {children}
127
+ </div>
128
+ );
129
+ }
130
+
131
+ // Single file display (when category is specified)
132
+ if (category && fileReference) {
133
+ const isImage = fileReference.file_metadata.fileType?.startsWith('image/');
134
+
135
+ return (
136
+ <div className={`space-y-2 ${className}`}>
137
+ {isImage && fileUrl && !imageError ? (
138
+ <div className="relative">
139
+ <img
140
+ src={fileUrl}
141
+ alt={fileReference.file_metadata.fileName || 'File'}
142
+ className="max-w-full h-auto rounded-lg border border-sec-200"
143
+ onError={handleImageError}
144
+ />
145
+ {showDelete && (
146
+ <button
147
+ onClick={handleDelete}
148
+ className="absolute top-2 right-2 bg-acc-500 text-white rounded-full w-6 h-6 flex items-center justify-center text-sm hover:bg-acc-600"
149
+ title="Delete file"
150
+ >
151
+ ×
152
+ </button>
153
+ )}
154
+ </div>
155
+ ) : (
156
+ <div className="flex items-center space-x-3 p-3 bg-sec-50 rounded-lg border border-sec-200">
157
+ <span className="text-2xl">
158
+ {getFileIcon(fileReference.file_metadata.fileType || '')}
159
+ </span>
160
+ <div className="flex-1 min-w-0">
161
+ <div className="font-medium text-sec-900 truncate">
162
+ {fileReference.file_metadata.fileName || 'Unknown file'}
163
+ </div>
164
+ <div className="text-sm text-sec-500">
165
+ {fileReference.file_metadata.fileSize && formatFileSize(fileReference.file_metadata.fileSize)}
166
+ {fileReference.file_metadata.fileType && ` • ${fileReference.file_metadata.fileType}`}
167
+ </div>
168
+ </div>
169
+ {showDelete && (
170
+ <button
171
+ onClick={handleDelete}
172
+ className="text-acc-500 hover:text-acc-700 p-1"
173
+ title="Delete file"
174
+ >
175
+ ×
176
+ </button>
177
+ )}
178
+ </div>
179
+ )}
180
+ {children}
181
+ </div>
182
+ );
183
+ }
184
+
185
+ // Multiple files display
186
+ return (
187
+ <div className={`space-y-2 ${className}`}>
188
+ {fileReferences.map((fileRef) => {
189
+ const isImage = fileRef.file_metadata.fileType?.startsWith('image/');
190
+ const fileUrl = fileRef.is_public
191
+ ? `https://your-supabase-url.supabase.co/storage/v1/object/public/files/${fileRef.file_path}`
192
+ : null; // Would need to get signed URL for private files
193
+
194
+ return (
195
+ <div key={fileRef.id} className="flex items-center space-x-3 p-3 bg-sec-50 rounded-lg border border-sec-200">
196
+ {isImage && fileUrl ? (
197
+ <img
198
+ src={fileUrl}
199
+ alt={fileRef.file_metadata.fileName || 'File'}
200
+ className="w-12 h-12 object-cover rounded"
201
+ onError={handleImageError}
202
+ />
203
+ ) : (
204
+ <span className="text-2xl">
205
+ {getFileIcon(fileRef.file_metadata.fileType || '')}
206
+ </span>
207
+ )}
208
+ <div className="flex-1 min-w-0">
209
+ <div className="font-medium text-sec-900 truncate">
210
+ {fileRef.file_metadata.fileName || 'Unknown file'}
211
+ </div>
212
+ <div className="text-sm text-sec-500">
213
+ {fileRef.file_metadata.fileSize && formatFileSize(fileRef.file_metadata.fileSize)}
214
+ {fileRef.file_metadata.fileType && ` • ${fileRef.file_metadata.fileType}`}
215
+ {fileRef.file_metadata.category && ` • ${fileRef.file_metadata.category}`}
216
+ </div>
217
+ </div>
218
+ {showDelete && (
219
+ <button
220
+ onClick={() => deleteFile(true)}
221
+ className="text-acc-500 hover:text-acc-700 p-1"
222
+ title="Delete file"
223
+ >
224
+ ×
225
+ </button>
226
+ )}
227
+ </div>
228
+ );
229
+ })}
230
+ {children}
231
+ </div>
232
+ );
233
+ }
@@ -0,0 +1,176 @@
1
+ // File Upload Component
2
+ // Provides a file upload interface using the file reference system
3
+
4
+ import React, { useState, useCallback, useRef } from 'react';
5
+ import { SupabaseClient } from '@supabase/supabase-js';
6
+ import { FileCategory } from '../types/file-reference';
7
+ import { useFileReference } from '../hooks/useFileReference';
8
+
9
+ export interface FileUploadProps {
10
+ supabase: SupabaseClient;
11
+ table_name: string;
12
+ record_id: string;
13
+ organisation_id: string;
14
+ app_id: string;
15
+ category: FileCategory;
16
+ accept?: string;
17
+ maxSize?: number;
18
+ multiple?: boolean;
19
+ disabled?: boolean;
20
+ className?: string;
21
+ onUploadSuccess?: (result: any) => void;
22
+ onUploadError?: (error: string) => void;
23
+ children?: React.ReactNode;
24
+ }
25
+
26
+ export function FileUpload({
27
+ supabase,
28
+ table_name,
29
+ record_id,
30
+ organisation_id,
31
+ app_id,
32
+ category,
33
+ accept = '*/*',
34
+ maxSize = 10 * 1024 * 1024, // 10MB default
35
+ multiple = false,
36
+ disabled = false,
37
+ className = '',
38
+ onUploadSuccess,
39
+ onUploadError,
40
+ children
41
+ }: FileUploadProps) {
42
+ const [isDragging, setIsDragging] = useState(false);
43
+ const fileInputRef = useRef<HTMLInputElement>(null);
44
+ const { uploadFile, isLoading, error } = useFileReference(supabase);
45
+
46
+ const handleFileSelect = useCallback(async (files: FileList | null) => {
47
+ if (!files || files.length === 0) return;
48
+
49
+ const fileArray = Array.from(files);
50
+
51
+ // Validate file sizes
52
+ const oversizedFiles = fileArray.filter(file => file.size > maxSize);
53
+ if (oversizedFiles.length > 0) {
54
+ const errorMessage = `Files exceed maximum size of ${Math.round(maxSize / 1024 / 1024)}MB: ${oversizedFiles.map(f => f.name).join(', ')}`;
55
+ onUploadError?.(errorMessage);
56
+ return;
57
+ }
58
+
59
+ // Upload files
60
+ for (const file of fileArray) {
61
+ try {
62
+ const result = await uploadFile({
63
+ table_name,
64
+ record_id,
65
+ organisation_id,
66
+ app_id,
67
+ category,
68
+ is_public: false
69
+ }, file);
70
+
71
+ if (result) {
72
+ onUploadSuccess?.(result);
73
+ } else {
74
+ onUploadError?.('Upload failed');
75
+ }
76
+ } catch (err) {
77
+ const errorMessage = err instanceof Error ? err.message : 'Upload failed';
78
+ onUploadError?.(errorMessage);
79
+ }
80
+ }
81
+ }, [uploadFile, table_name, record_id, organisation_id, app_id, category, maxSize, onUploadSuccess, onUploadError]);
82
+
83
+ const handleDragOver = useCallback((e: React.DragEvent) => {
84
+ e.preventDefault();
85
+ e.stopPropagation();
86
+ if (!disabled) {
87
+ setIsDragging(true);
88
+ }
89
+ }, [disabled]);
90
+
91
+ const handleDragLeave = useCallback((e: React.DragEvent) => {
92
+ e.preventDefault();
93
+ e.stopPropagation();
94
+ setIsDragging(false);
95
+ }, []);
96
+
97
+ const handleDrop = useCallback((e: React.DragEvent) => {
98
+ e.preventDefault();
99
+ e.stopPropagation();
100
+ setIsDragging(false);
101
+
102
+ if (disabled) return;
103
+
104
+ const files = e.dataTransfer.files;
105
+ handleFileSelect(files);
106
+ }, [disabled, handleFileSelect]);
107
+
108
+ const handleFileInputChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
109
+ handleFileSelect(e.target.files);
110
+ // Reset input value to allow re-uploading the same file
111
+ if (e.target) {
112
+ e.target.value = '';
113
+ }
114
+ }, [handleFileSelect]);
115
+
116
+ const handleClick = useCallback(() => {
117
+ if (!disabled && fileInputRef.current) {
118
+ fileInputRef.current.click();
119
+ }
120
+ }, [disabled]);
121
+
122
+ const dragClasses = isDragging ? 'border-main-500 bg-main-50' : 'border-sec-300 hover:border-sec-400';
123
+ const disabledClasses = disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer hover:bg-sec-50';
124
+
125
+ return (
126
+ <div
127
+ className={`relative border-2 border-dashed rounded-lg p-6 text-center transition-colors ${dragClasses} ${disabledClasses} ${className}`}
128
+ onDragOver={handleDragOver}
129
+ onDragLeave={handleDragLeave}
130
+ onDrop={handleDrop}
131
+ onClick={handleClick}
132
+ >
133
+ <input
134
+ ref={fileInputRef}
135
+ type="file"
136
+ accept={accept}
137
+ multiple={multiple}
138
+ onChange={handleFileInputChange}
139
+ className="hidden"
140
+ disabled={disabled}
141
+ />
142
+
143
+ {children || (
144
+ <div className="space-y-2">
145
+ <div className="text-sec-600">
146
+ {isDragging ? (
147
+ 'Drop files here...'
148
+ ) : (
149
+ <>
150
+ <span className="font-medium">Click to upload</span>
151
+ {' '}or drag and drop
152
+ </>
153
+ )}
154
+ </div>
155
+ <div className="text-sm text-sec-500">
156
+ {accept !== '*/*' && `Accepted formats: ${accept}`}
157
+ {maxSize && ` • Max size: ${Math.round(maxSize / 1024 / 1024)}MB`}
158
+ {multiple && ' • Multiple files allowed'}
159
+ </div>
160
+ </div>
161
+ )}
162
+
163
+ {isLoading && (
164
+ <div className="absolute inset-0 bg-white bg-opacity-75 flex items-center justify-center">
165
+ <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-main-500"></div>
166
+ </div>
167
+ )}
168
+
169
+ {error && (
170
+ <div className="mt-2 text-sm text-acc-600">
171
+ {error}
172
+ </div>
173
+ )}
174
+ </div>
175
+ );
176
+ }
@@ -47,13 +47,13 @@ describe('Footer Component', () => {
47
47
  it('renders with default company name and year', () => {
48
48
  renderWithProviders(<Footer />);
49
49
 
50
- expect(screen.getByText(/© Copyright 2022–2024 all rights reserved, Solvera Solutions Pty Ltd\./)).toBeInTheDocument();
50
+ expect(screen.getByText(/© Copyright 2022–2025 all rights reserved, Solvera Solutions Pty Ltd\./)).toBeInTheDocument();
51
51
  });
52
52
 
53
53
  it('renders with custom company name', () => {
54
54
  renderWithProviders(<Footer companyName="Test Company Inc." />);
55
55
 
56
- expect(screen.getByText(/© Copyright 2022–2024 all rights reserved, Test Company Inc\./)).toBeInTheDocument();
56
+ expect(screen.getByText(/© Copyright 2022–2025 all rights reserved, Test Company Inc\./)).toBeInTheDocument();
57
57
  });
58
58
 
59
59
  it('renders with custom year', () => {
@@ -275,7 +275,7 @@ describe('Footer Component', () => {
275
275
  it('handles empty string company name', () => {
276
276
  renderWithProviders(<Footer companyName="" />);
277
277
 
278
- expect(screen.getByText(/© Copyright 2022–2024 all rights reserved, \./)).toBeInTheDocument();
278
+ expect(screen.getByText(/© Copyright 2022–2025 all rights reserved, \./)).toBeInTheDocument();
279
279
  });
280
280
 
281
281
  it('handles zero year', () => {
@@ -300,20 +300,20 @@ describe('Footer Component', () => {
300
300
  renderWithProviders(<Footer copyright="" />);
301
301
 
302
302
  // When copyright is empty string, it falls back to default copyright
303
- expect(screen.getByText(/© Copyright 2022–2024 all rights reserved, Solvera Solutions Pty Ltd\./)).toBeInTheDocument();
303
+ expect(screen.getByText(/© Copyright 2022–2025 all rights reserved, Solvera Solutions Pty Ltd\./)).toBeInTheDocument();
304
304
  });
305
305
 
306
306
  it('handles special characters in company name', () => {
307
307
  renderWithProviders(<Footer companyName="Company & Co. (Ltd.)" />);
308
308
 
309
- expect(screen.getByText(/© Copyright 2022–2024 all rights reserved, Company & Co\. \(Ltd\.\)\./)).toBeInTheDocument();
309
+ expect(screen.getByText(/© Copyright 2022–2025 all rights reserved, Company & Co\. \(Ltd\.\)\./)).toBeInTheDocument();
310
310
  });
311
311
 
312
312
  it('handles very long company name', () => {
313
313
  const longName = 'A'.repeat(100);
314
314
  renderWithProviders(<Footer companyName={longName} />);
315
315
 
316
- expect(screen.getByText(new RegExp(`© Copyright 2022–2024 all rights reserved, ${longName}\\.`))).toBeInTheDocument();
316
+ expect(screen.getByText(new RegExp(`© Copyright 2022–2025 all rights reserved, ${longName}\\.`))).toBeInTheDocument();
317
317
  });
318
318
 
319
319
  it('handles links with special characters', () => {
@@ -348,7 +348,7 @@ describe('Footer Component', () => {
348
348
  renderWithProviders(<Footer />);
349
349
 
350
350
  expect(screen.getByText(/Solvera Solutions Pty Ltd/)).toBeInTheDocument();
351
- expect(screen.getByText(/2024/)).toBeInTheDocument();
351
+ expect(screen.getByText(/2025/)).toBeInTheDocument();
352
352
  });
353
353
 
354
354
  it('overrides default values when props are provided', () => {
@@ -17,12 +17,12 @@ const mockAuthContext = {
17
17
  user: { id: 'test-user', email: 'test@example.com' },
18
18
  isAuthenticated: true,
19
19
  isLoading: false,
20
- hasPermission: vi.fn(),
21
- hasRole: vi.fn(),
22
- hasAccessLevel: vi.fn(),
20
+ hasPermission: vi.fn().mockReturnValue(true), // Allow all permissions
21
+ hasRole: vi.fn().mockReturnValue(true), // Allow all roles
22
+ hasAccessLevel: vi.fn().mockReturnValue(true), // Allow all access levels
23
23
  permissions: ['dashboard:read', 'users:read'],
24
- roles: ['user'],
25
- accessLevel: AccessLevel.VIEWER,
24
+ roles: ['user', 'admin'], // Include admin role
25
+ accessLevel: AccessLevel.ADMIN, // Set to admin level
26
26
  signOut: vi.fn(),
27
27
  refreshSession: vi.fn(),
28
28
  appName: 'Test App',
@@ -43,7 +43,7 @@ const mockAuthContext = {
43
43
 
44
44
  // Mock the useUnifiedAuth hook
45
45
  vi.mock('../../providers/UnifiedAuthProvider', () => ({
46
- useUnifiedAuth: () => mockAuthContext,
46
+ useUnifiedAuth: vi.fn(() => mockAuthContext),
47
47
  }));
48
48
 
49
49
  // Mock console methods to avoid noise in tests
@@ -93,6 +93,12 @@ describe('NavigationMenu Component', () => {
93
93
 
94
94
  beforeEach(() => {
95
95
  vi.clearAllMocks();
96
+
97
+ // Ensure the mock functions are properly set up
98
+ mockAuthContext.hasPermission.mockReturnValue(true);
99
+ mockAuthContext.hasRole.mockReturnValue(true);
100
+ mockAuthContext.hasAccessLevel.mockReturnValue(true);
101
+
96
102
  // Reset console mocks
97
103
  console.log = vi.fn();
98
104
  console.warn = vi.fn();
@@ -512,6 +518,7 @@ describe('NavigationMenu Component', () => {
512
518
 
513
519
  it('handles permission-based navigation', async () => {
514
520
  const user = userEvent.setup();
521
+
515
522
  renderWithProviders(
516
523
  <NavigationMenu
517
524
  items={permissionBasedNavItems}
@@ -143,7 +143,20 @@ const defaultMockContext = {
143
143
  describe('OrganisationSelector Component', () => {
144
144
  beforeEach(() => {
145
145
  vi.clearAllMocks();
146
- mockUseOrganisations.mockReturnValue(defaultMockContext);
146
+
147
+ // Re-setup the default mock context after clearing mocks
148
+ const mockContext = {
149
+ organisations: mockOrganisations,
150
+ selectedOrganisation: mockSelectedOrganisation,
151
+ isLoading: false,
152
+ error: null,
153
+ switchOrganisation: vi.fn().mockResolvedValue(undefined),
154
+ getUserRole: vi.fn().mockReturnValue('admin'),
155
+ validateOrganisationAccess: vi.fn().mockReturnValue(true), // Ensure all orgs are accessible by default
156
+ refreshOrganisations: vi.fn().mockResolvedValue(undefined),
157
+ };
158
+
159
+ mockUseOrganisations.mockReturnValue(mockContext);
147
160
  });
148
161
 
149
162
  afterEach(() => {
@@ -347,10 +360,17 @@ describe('OrganisationSelector Component', () => {
347
360
  const user = userEvent.setup();
348
361
  const onOrganisationChange = vi.fn();
349
362
  const switchOrganisation = vi.fn().mockResolvedValue(undefined);
363
+ const validateOrganisationAccess = vi.fn().mockReturnValue(true);
350
364
 
351
365
  mockUseOrganisations.mockReturnValue({
352
- ...defaultMockContext,
366
+ organisations: mockOrganisations,
367
+ selectedOrganisation: mockSelectedOrganisation,
368
+ isLoading: false,
369
+ error: null,
353
370
  switchOrganisation,
371
+ getUserRole: vi.fn().mockReturnValue('admin'),
372
+ validateOrganisationAccess,
373
+ refreshOrganisations: vi.fn().mockResolvedValue(undefined),
354
374
  });
355
375
 
356
376
  renderWithProviders(
@@ -367,10 +387,17 @@ describe('OrganisationSelector Component', () => {
367
387
  const user = userEvent.setup();
368
388
  const onOrganisationChange = vi.fn();
369
389
  const switchOrganisation = vi.fn().mockResolvedValue(undefined);
390
+ const validateOrganisationAccess = vi.fn().mockReturnValue(true);
370
391
 
371
392
  mockUseOrganisations.mockReturnValue({
372
- ...defaultMockContext,
393
+ organisations: mockOrganisations,
394
+ selectedOrganisation: mockSelectedOrganisation,
395
+ isLoading: false,
396
+ error: null,
373
397
  switchOrganisation,
398
+ getUserRole: vi.fn().mockReturnValue('admin'),
399
+ validateOrganisationAccess,
400
+ refreshOrganisations: vi.fn().mockResolvedValue(undefined),
374
401
  });
375
402
 
376
403
  renderWithProviders(
@@ -287,7 +287,7 @@ export function OrganisationSelector({
287
287
  <div className="flex items-center gap-1 ml-4">
288
288
  <Shield className="h-3 w-3 text-muted-foreground" />
289
289
  <span className="text-xs text-muted-foreground capitalize">
290
- {userRole.replace('_', ' ')}
290
+ {userRole?.replace('_', ' ') || 'No Role'}
291
291
  </span>
292
292
  </div>
293
293
  )}