@jmruthers/pace-core 0.5.54 → 0.5.55

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-4T627QFJ.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-MZBUOP4P.js → chunk-5BSLGBYI.js} +4 -3
  9. package/dist/chunk-5BSLGBYI.js.map +1 -0
  10. package/dist/{chunk-I5Z3QH5X.js → chunk-66C4BSAY.js} +2 -2
  11. package/dist/{chunk-I5Z3QH5X.js.map → chunk-66C4BSAY.js.map} +1 -1
  12. package/dist/{chunk-MYP2EGHX.js → chunk-AJ2KMES7.js} +21 -14
  13. package/dist/chunk-AJ2KMES7.js.map +1 -0
  14. package/dist/{chunk-EL2O4IUX.js → chunk-AQFRLC7K.js} +16 -24
  15. package/dist/{chunk-EL2O4IUX.js.map → chunk-AQFRLC7K.js.map} +1 -1
  16. package/dist/{chunk-7BNPOCLL.js → chunk-B2WTCLCV.js} +6 -2
  17. package/dist/chunk-B2WTCLCV.js.map +1 -0
  18. package/dist/{chunk-WJARTBCT.js → chunk-D7ARGIA3.js} +16 -7
  19. package/dist/chunk-D7ARGIA3.js.map +1 -0
  20. package/dist/{chunk-NRK4AIHQ.js → chunk-KBRACSJI.js} +3 -3
  21. package/dist/{chunk-NYUJ4FJR.js → chunk-KJDPSM64.js} +7 -7
  22. package/dist/chunk-KJDPSM64.js.map +1 -0
  23. package/dist/{chunk-GWSBHC4J.js → chunk-KLPVOPRI.js} +261 -38
  24. package/dist/chunk-KLPVOPRI.js.map +1 -0
  25. package/dist/{chunk-TRIZ7IB7.js → chunk-MPQDF75X.js} +148 -288
  26. package/dist/chunk-MPQDF75X.js.map +1 -0
  27. package/dist/{chunk-MSFACPQQ.js → chunk-PAEM3OWN.js} +11 -11
  28. package/dist/{chunk-MSFACPQQ.js.map → chunk-PAEM3OWN.js.map} +1 -1
  29. package/dist/{chunk-GIO7BFE7.js → chunk-RQD3D2CO.js} +66 -169
  30. package/dist/{chunk-GIO7BFE7.js.map → chunk-RQD3D2CO.js.map} +1 -1
  31. package/dist/{chunk-YDJW5XTN.js → chunk-STT7INZR.js} +25 -1
  32. package/dist/chunk-STT7INZR.js.map +1 -0
  33. package/dist/{chunk-6MTY77WU.js → chunk-TNMXZLDR.js} +3 -3
  34. package/dist/{chunk-BC3S53OZ.js → chunk-UQE2Y64H.js} +30 -14
  35. package/dist/chunk-UQE2Y64H.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-SS3E6QLB.js → chunk-YNUBMSMV.js} +2 -2
  39. package/dist/chunk-YNUBMSMV.js.map +1 -0
  40. package/dist/{chunk-NZ655MWE.js → chunk-ZOD2ZY6X.js} +5 -4
  41. package/dist/chunk-ZOD2ZY6X.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 +18 -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-4T627QFJ.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-KBRACSJI.js.map} +0 -0
  396. /package/dist/{chunk-6MTY77WU.js.map → chunk-TNMXZLDR.js.map} +0 -0
@@ -0,0 +1,733 @@
1
+ # File Upload & Storage System
2
+
3
+ > **📁 Complete File Management** | [← Back to Documentation](../README.md) | [↑ Table of Contents](#table-of-contents)
4
+
5
+ Comprehensive guide to implementing file upload, storage, and management using PACE Core's file reference system.
6
+
7
+ ## Overview
8
+
9
+ PACE Core provides a complete file management system with:
10
+ - **File Upload Component** - Drag-and-drop file upload with validation
11
+ - **File Display Component** - Secure file viewing and management
12
+ - **File Reference System** - Database-backed file tracking with RLS
13
+ - **Storage Hooks** - React hooks for file operations
14
+ - **Security Integration** - Organisation-scoped access control
15
+
16
+ ## Architecture
17
+
18
+ ```mermaid
19
+ graph TD
20
+ A[FileUpload Component] --> B[useFileReference Hook]
21
+ B --> C[File Reference Database]
22
+ C --> D[Storage Bucket]
23
+ E[FileDisplay Component] --> F[useFileReferenceForRecord Hook]
24
+ F --> C
25
+ G[RLS Policies] --> C
26
+ H[Organisation Context] --> G
27
+ ```
28
+
29
+ ## Quick Start
30
+
31
+ ### 1. Basic File Upload
32
+
33
+ ```tsx
34
+ import { FileUpload, FileCategory } from '@jmruthers/pace-core';
35
+ import { useFileReference } from '@jmruthers/pace-core';
36
+
37
+ function MyFileUpload() {
38
+ const { uploadFile, getFileUrl, deleteFile, isLoading, error } = useFileReference(supabase);
39
+
40
+ const handleUpload = async (file: File) => {
41
+ try {
42
+ const fileRef = await uploadFile({
43
+ file,
44
+ category: FileCategory.DOCUMENT,
45
+ description: 'User uploaded document'
46
+ });
47
+ console.log('File uploaded:', fileRef);
48
+ } catch (err) {
49
+ console.error('Upload failed:', err);
50
+ }
51
+ };
52
+
53
+ return (
54
+ <FileUpload
55
+ supabase={supabase}
56
+ orgId="org-123"
57
+ onUploadComplete={handleUpload}
58
+ accept=".pdf,.doc,.docx"
59
+ maxSize={5 * 1024 * 1024} // 5MB
60
+ >
61
+ <div className="border-2 border-dashed border-main-300 rounded-lg p-8 text-center">
62
+ <p>Drag and drop files here or click to browse</p>
63
+ </div>
64
+ </FileUpload>
65
+ );
66
+ }
67
+ ```
68
+
69
+ ### 2. File Display with Management
70
+
71
+ ```tsx
72
+ import { FileDisplay, FileCategory } from '@jmruthers/pace-core';
73
+ import { useFileReferenceForRecord } from '@jmruthers/pace-core';
74
+
75
+ function UserProfile({ userId }: { userId: string }) {
76
+ const { fileUrl, uploadFile, deleteFile, isLoading } = useFileReferenceForRecord(
77
+ supabase,
78
+ 'pace_person',
79
+ userId,
80
+ 'org-123'
81
+ );
82
+
83
+ return (
84
+ <div>
85
+ <h2>Profile Documents</h2>
86
+ <FileDisplay
87
+ supabase={supabase}
88
+ orgId="org-123"
89
+ recordType="pace_person"
90
+ recordId={userId}
91
+ category={FileCategory.DOCUMENT}
92
+ onUpload={uploadFile}
93
+ onDelete={deleteFile}
94
+ showUpload={true}
95
+ showDelete={true}
96
+ />
97
+ </div>
98
+ );
99
+ }
100
+ ```
101
+
102
+ ## Components
103
+
104
+ ### FileUpload
105
+
106
+ A comprehensive file upload component with drag-and-drop support, validation, and progress tracking.
107
+
108
+ #### Props
109
+
110
+ ```typescript
111
+ interface FileUploadProps {
112
+ supabase: SupabaseClient;
113
+ appName: string;
114
+ orgId: string;
115
+ onUploadComplete?: (fileRef: FileReference) => void;
116
+ onUploadStart?: (file: File) => void;
117
+ accept?: string;
118
+ maxSize?: number;
119
+ multiple?: boolean;
120
+ disabled?: boolean;
121
+ className?: string;
122
+ children?: React.ReactNode;
123
+ }
124
+ ```
125
+
126
+ #### Usage Examples
127
+
128
+ **Basic Upload:**
129
+ ```tsx
130
+ <FileUpload
131
+ supabase={supabase}
132
+ appName="my-app"
133
+ orgId={organisationId}
134
+ onUploadComplete={(fileRef) => console.log('Uploaded:', fileRef)}
135
+ accept="image/*"
136
+ maxSize={2 * 1024 * 1024} // 2MB
137
+ >
138
+ <Button>Upload Image</Button>
139
+ </FileUpload>
140
+ ```
141
+
142
+ **Multiple Files:**
143
+ ```tsx
144
+ <FileUpload
145
+ supabase={supabase}
146
+ appName="my-app"
147
+ orgId={organisationId}
148
+ multiple={true}
149
+ accept=".pdf,.doc,.docx"
150
+ onUploadComplete={(fileRef) => addToFileList(fileRef)}
151
+ >
152
+ <div className="upload-area">
153
+ <UploadIcon className="w-8 h-8" />
154
+ <p>Upload Documents</p>
155
+ </div>
156
+ </FileUpload>
157
+ ```
158
+
159
+ **Custom Validation:**
160
+ ```tsx
161
+ <FileUpload
162
+ supabase={supabase}
163
+ appName="my-app"
164
+ orgId={organisationId}
165
+ onUploadStart={(file) => {
166
+ if (file.size > 10 * 1024 * 1024) {
167
+ throw new Error('File too large');
168
+ }
169
+ }}
170
+ onUploadComplete={(fileRef) => handleUpload(fileRef)}
171
+ >
172
+ <CustomUploadArea />
173
+ </FileUpload>
174
+ ```
175
+
176
+ ### FileDisplay
177
+
178
+ A component for displaying and managing files associated with database records.
179
+
180
+ #### Props
181
+
182
+ ```typescript
183
+ interface FileDisplayProps {
184
+ supabase: SupabaseClient;
185
+ appName: string;
186
+ orgId: string;
187
+ recordType: string;
188
+ recordId: string;
189
+ category?: FileCategory;
190
+ onUpload?: (file: File) => Promise<FileReference>;
191
+ onDelete?: (fileRef: FileReference) => Promise<void>;
192
+ showUpload?: boolean;
193
+ showDelete?: boolean;
194
+ showPreview?: boolean;
195
+ className?: string;
196
+ }
197
+ ```
198
+
199
+ #### Usage Examples
200
+
201
+ **Read-Only Display:**
202
+ ```tsx
203
+ <FileDisplay
204
+ supabase={supabase}
205
+ appName="my-app"
206
+ orgId={organisationId}
207
+ recordType="pace_person"
208
+ recordId={personId}
209
+ category={FileCategory.DOCUMENT}
210
+ showUpload={false}
211
+ showDelete={false}
212
+ />
213
+ ```
214
+
215
+ **Full Management:**
216
+ ```tsx
217
+ <FileDisplay
218
+ supabase={supabase}
219
+ appName="my-app"
220
+ orgId={organisationId}
221
+ recordType="pace_person"
222
+ recordId={personId}
223
+ category={FileCategory.IMAGE}
224
+ onUpload={handleUpload}
225
+ onDelete={handleDelete}
226
+ showUpload={true}
227
+ showDelete={true}
228
+ showPreview={true}
229
+ />
230
+ ```
231
+
232
+ ## Hooks
233
+
234
+ ### useFileReference
235
+
236
+ Primary hook for file operations with a Supabase client.
237
+
238
+ ```typescript
239
+ interface UseFileReferenceReturn {
240
+ uploadFile: (options: UploadFileOptions) => Promise<FileReference>;
241
+ getFileUrl: (fileRef: FileReference) => Promise<string>;
242
+ deleteFile: (fileRef: FileReference) => Promise<void>;
243
+ isLoading: boolean;
244
+ error: Error | null;
245
+ }
246
+
247
+ interface UploadFileOptions {
248
+ file: File;
249
+ category: FileCategory;
250
+ description?: string;
251
+ metadata?: Record<string, any>;
252
+ }
253
+ ```
254
+
255
+ #### Usage
256
+
257
+ ```tsx
258
+ import { useFileReference } from '@jmruthers/pace-core';
259
+
260
+ function FileManager() {
261
+ const { uploadFile, getFileUrl, deleteFile, isLoading, error } = useFileReference(supabase);
262
+
263
+ const handleUpload = async (file: File) => {
264
+ try {
265
+ const fileRef = await uploadFile({
266
+ file,
267
+ category: FileCategory.DOCUMENT,
268
+ description: 'User document',
269
+ metadata: { uploadedBy: user.id }
270
+ });
271
+
272
+ // Get the public URL
273
+ const url = await getFileUrl(fileRef);
274
+ console.log('File available at:', url);
275
+ } catch (err) {
276
+ console.error('Upload failed:', err);
277
+ }
278
+ };
279
+
280
+ const handleDelete = async (fileRef: FileReference) => {
281
+ try {
282
+ await deleteFile(fileRef);
283
+ console.log('File deleted');
284
+ } catch (err) {
285
+ console.error('Delete failed:', err);
286
+ }
287
+ };
288
+
289
+ return (
290
+ <div>
291
+ {/* Upload UI */}
292
+ {isLoading && <div>Uploading...</div>}
293
+ {error && <div>Error: {error.message}</div>}
294
+ </div>
295
+ );
296
+ }
297
+ ```
298
+
299
+ ### useFileReferenceForRecord
300
+
301
+ Hook for managing files associated with specific database records.
302
+
303
+ ```typescript
304
+ interface UseFileReferenceForRecordReturn {
305
+ fileUrl: string | null;
306
+ uploadFile: (file: File) => Promise<FileReference>;
307
+ deleteFile: (fileRef: FileReference) => Promise<void>;
308
+ isLoading: boolean;
309
+ error: Error | null;
310
+ }
311
+ ```
312
+
313
+ #### Usage
314
+
315
+ ```tsx
316
+ import { useFileReferenceForRecord } from '@jmruthers/pace-core';
317
+
318
+ function PersonProfile({ personId }: { personId: string }) {
319
+ const { fileUrl, uploadFile, deleteFile, isLoading } = useFileReferenceForRecord(
320
+ supabase,
321
+ 'pace_person',
322
+ personId,
323
+ organisationId
324
+ );
325
+
326
+ return (
327
+ <div>
328
+ {fileUrl && (
329
+ <img
330
+ src={fileUrl}
331
+ alt="Profile"
332
+ className="w-32 h-32 rounded-full"
333
+ />
334
+ )}
335
+
336
+ <FileUpload onUploadComplete={uploadFile}>
337
+ <Button>Change Photo</Button>
338
+ </FileUpload>
339
+
340
+ {fileUrl && (
341
+ <Button onClick={() => deleteFile(fileRef)} variant="destructive">
342
+ Remove Photo
343
+ </Button>
344
+ )}
345
+ </div>
346
+ );
347
+ }
348
+ ```
349
+
350
+ ## File Categories
351
+
352
+ PACE Core supports predefined file categories for better organization:
353
+
354
+ ```typescript
355
+ enum FileCategory {
356
+ DOCUMENT = 'document',
357
+ IMAGE = 'image',
358
+ AUDIO = 'audio',
359
+ VIDEO = 'video',
360
+ ARCHIVE = 'archive',
361
+ SPREADSHEET = 'spreadsheet',
362
+ PRESENTATION = 'presentation',
363
+ OTHER = 'other'
364
+ }
365
+ ```
366
+
367
+ ### Usage
368
+
369
+ ```tsx
370
+ import { FileCategory } from '@jmruthers/pace-core';
371
+
372
+ // Upload a document
373
+ await uploadFile({
374
+ file: pdfFile,
375
+ category: FileCategory.DOCUMENT,
376
+ description: 'Contract document'
377
+ });
378
+
379
+ // Upload an image
380
+ await uploadFile({
381
+ file: imageFile,
382
+ category: FileCategory.IMAGE,
383
+ description: 'Profile photo'
384
+ });
385
+ ```
386
+
387
+ ## Database Schema
388
+
389
+ The file reference system uses the following database structure:
390
+
391
+ ### file_references Table
392
+
393
+ ```sql
394
+ CREATE TABLE file_references (
395
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
396
+ organisation_id UUID NOT NULL REFERENCES organisations(id),
397
+ record_type TEXT NOT NULL,
398
+ record_id UUID NOT NULL,
399
+ file_name TEXT NOT NULL,
400
+ file_size BIGINT NOT NULL,
401
+ file_type TEXT NOT NULL,
402
+ file_category TEXT NOT NULL,
403
+ storage_path TEXT NOT NULL,
404
+ description TEXT,
405
+ metadata JSONB,
406
+ created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
407
+ created_by UUID REFERENCES auth.users(id),
408
+ updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
409
+ );
410
+
411
+ -- RLS Policies
412
+ ALTER TABLE file_references ENABLE ROW LEVEL SECURITY;
413
+
414
+ CREATE POLICY "Users can view files in their organisation" ON file_references
415
+ FOR SELECT USING (
416
+ organisation_id IN (
417
+ SELECT organisation_id FROM user_organisation_memberships
418
+ WHERE user_id = auth.uid()
419
+ )
420
+ );
421
+
422
+ CREATE POLICY "Users can insert files in their organisation" ON file_references
423
+ FOR INSERT WITH CHECK (
424
+ organisation_id IN (
425
+ SELECT organisation_id FROM user_organisation_memberships
426
+ WHERE user_id = auth.uid()
427
+ )
428
+ );
429
+
430
+ CREATE POLICY "Users can update files in their organisation" ON file_references
431
+ FOR UPDATE USING (
432
+ organisation_id IN (
433
+ SELECT organisation_id FROM user_organisation_memberships
434
+ WHERE user_id = auth.uid()
435
+ )
436
+ );
437
+
438
+ CREATE POLICY "Users can delete files in their organisation" ON file_references
439
+ FOR DELETE USING (
440
+ organisation_id IN (
441
+ SELECT organisation_id FROM user_organisation_memberships
442
+ WHERE user_id = auth.uid()
443
+ )
444
+ );
445
+ ```
446
+
447
+ ## Storage Configuration
448
+
449
+ ### Supabase Storage Setup
450
+
451
+ 1. **Create Storage Bucket:**
452
+ ```sql
453
+ INSERT INTO storage.buckets (id, name, public)
454
+ VALUES ('pace-files', 'pace-files', false);
455
+ ```
456
+
457
+ 2. **Set Bucket Policies:**
458
+ ```sql
459
+ -- Allow authenticated users to upload
460
+ CREATE POLICY "Authenticated users can upload files" ON storage.objects
461
+ FOR INSERT WITH CHECK (bucket_id = 'pace-files' AND auth.role() = 'authenticated');
462
+
463
+ -- Allow users to view files in their organisation
464
+ CREATE POLICY "Users can view files in their organisation" ON storage.objects
465
+ FOR SELECT USING (
466
+ bucket_id = 'pace-files' AND
467
+ (storage.foldername(name))[1] IN (
468
+ SELECT id::text FROM organisations
469
+ WHERE id IN (
470
+ SELECT organisation_id FROM user_organisation_memberships
471
+ WHERE user_id = auth.uid()
472
+ )
473
+ )
474
+ );
475
+
476
+ -- Allow users to delete files in their organisation
477
+ CREATE POLICY "Users can delete files in their organisation" ON storage.objects
478
+ FOR DELETE USING (
479
+ bucket_id = 'pace-files' AND
480
+ (storage.foldername(name))[1] IN (
481
+ SELECT id::text FROM organisations
482
+ WHERE id IN (
483
+ SELECT organisation_id FROM user_organisation_memberships
484
+ WHERE user_id = auth.uid()
485
+ )
486
+ )
487
+ );
488
+ ```
489
+
490
+ ## Security Considerations
491
+
492
+ ### Row Level Security (RLS)
493
+
494
+ All file operations are protected by RLS policies that ensure:
495
+ - Users can only access files within their organisation
496
+ - File metadata is properly scoped
497
+ - Storage paths are organisation-isolated
498
+
499
+ ### File Validation
500
+
501
+ ```tsx
502
+ import { validateFileUpload } from '@jmruthers/pace-core';
503
+
504
+ const fileUploadConfig = {
505
+ maxSize: 5 * 1024 * 1024, // 5MB
506
+ allowedTypes: ['image/jpeg', 'image/png', 'application/pdf'],
507
+ allowedExtensions: ['.jpg', '.jpeg', '.png', '.pdf']
508
+ };
509
+
510
+ function FileUpload() {
511
+ const handleFileUpload = async (file: File) => {
512
+ try {
513
+ const validation = await validateFileUpload(file, fileUploadConfig);
514
+ if (!validation.isValid) {
515
+ throw new Error(validation.errors.join(', '));
516
+ }
517
+
518
+ // Proceed with upload
519
+ await uploadFile({ file, category: FileCategory.DOCUMENT });
520
+ } catch (error) {
521
+ console.error('File validation failed:', error);
522
+ }
523
+ };
524
+
525
+ return (
526
+ <FileUpload onUploadComplete={handleFileUpload}>
527
+ <UploadArea />
528
+ </FileUpload>
529
+ );
530
+ }
531
+ ```
532
+
533
+ ## Migration from Old File Columns
534
+
535
+ If you're migrating from direct file columns to the file reference system:
536
+
537
+ ### 1. Create Migration Script
538
+
539
+ ```sql
540
+ -- Example migration for pace_person table
541
+ INSERT INTO file_references (
542
+ organisation_id,
543
+ record_type,
544
+ record_id,
545
+ file_name,
546
+ file_size,
547
+ file_type,
548
+ file_category,
549
+ storage_path,
550
+ created_at,
551
+ created_by
552
+ )
553
+ SELECT
554
+ organisation_id,
555
+ 'pace_person',
556
+ id,
557
+ COALESCE(avatar_filename, 'unknown'),
558
+ COALESCE(avatar_size, 0),
559
+ COALESCE(avatar_type, 'application/octet-stream'),
560
+ 'image',
561
+ COALESCE(avatar_path, ''),
562
+ created_at,
563
+ created_by
564
+ FROM pace_person
565
+ WHERE avatar_filename IS NOT NULL;
566
+ ```
567
+
568
+ ### 2. Update Application Code
569
+
570
+ ```tsx
571
+ // Before: Direct file column access
572
+ const avatarUrl = person.avatar_url;
573
+
574
+ // After: File reference system
575
+ const { fileUrl } = useFileReferenceForRecord(
576
+ supabase,
577
+ 'pace_person',
578
+ person.id,
579
+ organisationId
580
+ );
581
+ ```
582
+
583
+ ## Complete Examples
584
+
585
+ ### Profile Photo Management
586
+
587
+ ```tsx
588
+ import {
589
+ FileUpload,
590
+ FileDisplay,
591
+ useFileReferenceForRecord,
592
+ FileCategory
593
+ } from '@jmruthers/pace-core';
594
+
595
+ function ProfilePhotoManager({ personId }: { personId: string }) {
596
+ const { fileUrl, uploadFile, deleteFile, isLoading } = useFileReferenceForRecord(
597
+ supabase,
598
+ 'pace_person',
599
+ personId,
600
+ organisationId
601
+ );
602
+
603
+ const handleUpload = async (file: File) => {
604
+ try {
605
+ await uploadFile(file);
606
+ toast.success('Photo updated successfully');
607
+ } catch (error) {
608
+ toast.error('Failed to update photo');
609
+ }
610
+ };
611
+
612
+ const handleDelete = async () => {
613
+ try {
614
+ await deleteFile(fileRef);
615
+ toast.success('Photo removed');
616
+ } catch (error) {
617
+ toast.error('Failed to remove photo');
618
+ }
619
+ };
620
+
621
+ return (
622
+ <div className="space-y-4">
623
+ <div className="flex items-center space-x-4">
624
+ {fileUrl ? (
625
+ <img
626
+ src={fileUrl}
627
+ alt="Profile"
628
+ className="w-24 h-24 rounded-full object-cover"
629
+ />
630
+ ) : (
631
+ <div className="w-24 h-24 rounded-full bg-sec-200 flex items-center justify-center">
632
+ <UserIcon className="w-8 h-8 text-sec-500" />
633
+ </div>
634
+ )}
635
+
636
+ <div className="space-y-2">
637
+ <FileUpload
638
+ supabase={supabase}
639
+ appName="my-app"
640
+ orgId={organisationId}
641
+ onUploadComplete={handleUpload}
642
+ accept="image/*"
643
+ maxSize={2 * 1024 * 1024}
644
+ >
645
+ <Button size="sm">Change Photo</Button>
646
+ </FileUpload>
647
+
648
+ {fileUrl && (
649
+ <Button
650
+ size="sm"
651
+ variant="destructive"
652
+ onClick={handleDelete}
653
+ >
654
+ Remove Photo
655
+ </Button>
656
+ )}
657
+ </div>
658
+ </div>
659
+
660
+ {isLoading && <div>Processing...</div>}
661
+ </div>
662
+ );
663
+ }
664
+ ```
665
+
666
+ ### Document Management
667
+
668
+ ```tsx
669
+ import { FileDisplay, FileCategory } from '@jmruthers/pace-core';
670
+
671
+ function DocumentManager({ recordId, recordType }: {
672
+ recordId: string;
673
+ recordType: string;
674
+ }) {
675
+ return (
676
+ <div className="space-y-4">
677
+ <h3>Documents</h3>
678
+
679
+ <FileDisplay
680
+ supabase={supabase}
681
+ appName="my-app"
682
+ orgId={organisationId}
683
+ recordType={recordType}
684
+ recordId={recordId}
685
+ category={FileCategory.DOCUMENT}
686
+ showUpload={true}
687
+ showDelete={true}
688
+ showPreview={true}
689
+ />
690
+ </div>
691
+ );
692
+ }
693
+ ```
694
+
695
+ ## Troubleshooting
696
+
697
+ ### Common Issues
698
+
699
+ **Issue: Files not uploading**
700
+ - Check Supabase storage bucket configuration
701
+ - Verify RLS policies are correctly set
702
+ - Ensure organisation context is available
703
+
704
+ **Issue: Files not displaying**
705
+ - Check file reference database records
706
+ - Verify storage path is correct
707
+ - Ensure user has organisation access
708
+
709
+ **Issue: Permission denied errors**
710
+ - Verify RLS policies allow user access
711
+ - Check organisation membership
712
+ - Ensure file belongs to user's organisation
713
+
714
+ ### Debug Mode
715
+
716
+ Enable debug logging to troubleshoot file operations:
717
+
718
+ ```tsx
719
+ import { setRBACConfig } from '@jmruthers/pace-core/rbac';
720
+
721
+ // Enable debug mode
722
+ setRBACConfig({
723
+ logLevel: 'debug',
724
+ enableAuditLogging: true
725
+ });
726
+ ```
727
+
728
+ ## Next Steps
729
+
730
+ - **[Storage Utilities](../api-reference/utilities.md#storage)** - Additional storage utilities
731
+ - **[Security Best Practices](../best-practices/security.md)** - Security guidelines
732
+ - **[RBAC Integration](./permission-enforcement.md)** - Permission-based file access
733
+ - **[Performance Optimization](./performance.md)** - Large file handling