@jmruthers/pace-core 0.5.87 → 0.5.88

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 (242) hide show
  1. package/dist/{AuthService-Df3IozMG.d.ts → AuthService-DcTI5Ov4.d.ts} +9 -0
  2. package/dist/{DataTable-FA6EUX5M.js → DataTable-PWBMKMOG.js} +7 -7
  3. package/dist/{PublicLoadingSpinner-DecuJBX0.d.ts → PublicLoadingSpinner-BQXD1fbO.d.ts} +160 -130
  4. package/dist/{UnifiedAuthProvider-K2IZAY5F.js → UnifiedAuthProvider-5D3HEQND.js} +4 -4
  5. package/dist/{UnifiedAuthProvider-B391Aqum.d.ts → UnifiedAuthProvider-BVKmQd9u.d.ts} +4 -0
  6. package/dist/auth-DReDSLq9.d.ts +16 -0
  7. package/dist/{chunk-CBSD3BZ3.js → chunk-3RZBKQ5Y.js} +2 -6
  8. package/dist/{chunk-CBSD3BZ3.js.map → chunk-3RZBKQ5Y.js.map} +1 -1
  9. package/dist/{chunk-NTW3KGS4.js → chunk-6UHXQH7P.js} +5 -5
  10. package/dist/{chunk-YVUZWLQG.js → chunk-AQGF5OG7.js} +3 -3
  11. package/dist/{chunk-CVMVPYAL.js → chunk-BDZUMRBD.js} +3 -5
  12. package/dist/chunk-BDZUMRBD.js.map +1 -0
  13. package/dist/{chunk-KAY3K5TP.js → chunk-BNXBJOGL.js} +4 -4
  14. package/dist/{chunk-I7O3RSMN.js → chunk-CJIZS3UE.js} +1298 -769
  15. package/dist/chunk-CJIZS3UE.js.map +1 -0
  16. package/dist/{chunk-S3JKDMD5.js → chunk-CXKMRKRF.js} +4 -4
  17. package/dist/{chunk-5BN3YGNK.js → chunk-DP5X5ORK.js} +217 -27
  18. package/dist/chunk-DP5X5ORK.js.map +1 -0
  19. package/dist/{chunk-ZFLOV3OM.js → chunk-H3P2RGKZ.js} +352 -16
  20. package/dist/chunk-H3P2RGKZ.js.map +1 -0
  21. package/dist/{chunk-RIXPZJUB.js → chunk-KTPG5VCH.js} +2 -2
  22. package/dist/{chunk-WUXCWRL6.js → chunk-XJ2HZOBU.js} +6 -1
  23. package/dist/chunk-XJ2HZOBU.js.map +1 -0
  24. package/dist/{chunk-2FQEQUJT.js → chunk-XXVM53P4.js} +4 -4
  25. package/dist/{chunk-I2VVV5PQ.js → chunk-YY4YYM3E.js} +2 -2
  26. package/dist/components.d.ts +6 -55
  27. package/dist/components.js +24 -205
  28. package/dist/components.js.map +1 -1
  29. package/dist/{file-reference-9xUOnwyt.d.ts → file-reference-C9isKNPn.d.ts} +67 -2
  30. package/dist/hooks.js +9 -8
  31. package/dist/hooks.js.map +1 -1
  32. package/dist/index.d.ts +152 -26
  33. package/dist/index.js +64 -194
  34. package/dist/index.js.map +1 -1
  35. package/dist/providers.d.ts +5 -3
  36. package/dist/providers.js +3 -3
  37. package/dist/rbac/index.js +8 -8
  38. package/dist/types.d.ts +2 -1
  39. package/dist/types.js +3 -3
  40. package/dist/utils.js +2 -2
  41. package/docs/DOCUMENTATION_AUDIT.md +6 -6
  42. package/docs/DOCUMENTATION_STANDARD.md +137 -0
  43. package/docs/README.md +1 -1
  44. package/docs/api/classes/ColumnFactory.md +1 -1
  45. package/docs/api/classes/ErrorBoundary.md +1 -1
  46. package/docs/api/classes/InvalidScopeError.md +1 -1
  47. package/docs/api/classes/MissingUserContextError.md +1 -1
  48. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  49. package/docs/api/classes/PermissionDeniedError.md +1 -1
  50. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  51. package/docs/api/classes/RBACAuditManager.md +1 -1
  52. package/docs/api/classes/RBACCache.md +1 -1
  53. package/docs/api/classes/RBACEngine.md +1 -1
  54. package/docs/api/classes/RBACError.md +1 -1
  55. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  56. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  57. package/docs/api/classes/StorageUtils.md +83 -40
  58. package/docs/api/enums/FileCategory.md +56 -1
  59. package/docs/api/interfaces/AggregateConfig.md +1 -1
  60. package/docs/api/interfaces/ButtonProps.md +1 -1
  61. package/docs/api/interfaces/CardProps.md +1 -1
  62. package/docs/api/interfaces/ColorPalette.md +1 -1
  63. package/docs/api/interfaces/ColorShade.md +1 -1
  64. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  65. package/docs/api/interfaces/DataRecord.md +1 -1
  66. package/docs/api/interfaces/DataTableAction.md +1 -1
  67. package/docs/api/interfaces/DataTableColumn.md +1 -1
  68. package/docs/api/interfaces/DataTableProps.md +1 -1
  69. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  70. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  71. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  72. package/docs/api/interfaces/EventLogoProps.md +11 -11
  73. package/docs/api/interfaces/FileDisplayProps.md +10 -10
  74. package/docs/api/interfaces/FileMetadata.md +1 -1
  75. package/docs/api/interfaces/FileReference.md +1 -1
  76. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  77. package/docs/api/interfaces/FileUploadOptions.md +8 -8
  78. package/docs/api/interfaces/FileUploadProps.md +137 -42
  79. package/docs/api/interfaces/FooterProps.md +1 -1
  80. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  81. package/docs/api/interfaces/InputProps.md +1 -1
  82. package/docs/api/interfaces/LabelProps.md +1 -1
  83. package/docs/api/interfaces/LoginFormProps.md +1 -1
  84. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  85. package/docs/api/interfaces/NavigationContextType.md +1 -1
  86. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  87. package/docs/api/interfaces/NavigationItem.md +1 -1
  88. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  89. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  90. package/docs/api/interfaces/Organisation.md +1 -1
  91. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  92. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  93. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  94. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  95. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  96. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  97. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  98. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  99. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  100. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  101. package/docs/api/interfaces/PaletteData.md +1 -1
  102. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  103. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  104. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  105. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  106. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  107. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  108. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  109. package/docs/api/interfaces/RBACConfig.md +1 -1
  110. package/docs/api/interfaces/RBACLogger.md +1 -1
  111. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  112. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  113. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  114. package/docs/api/interfaces/RouteConfig.md +1 -1
  115. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  116. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  117. package/docs/api/interfaces/StorageConfig.md +1 -1
  118. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  119. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  120. package/docs/api/interfaces/StorageListOptions.md +1 -1
  121. package/docs/api/interfaces/StorageListResult.md +1 -1
  122. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  123. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  124. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  125. package/docs/api/interfaces/StyleImport.md +1 -1
  126. package/docs/api/interfaces/SwitchProps.md +1 -1
  127. package/docs/api/interfaces/ToastActionElement.md +1 -1
  128. package/docs/api/interfaces/ToastProps.md +1 -1
  129. package/docs/api/interfaces/UnifiedAuthContextType.md +83 -50
  130. package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
  131. package/docs/api/interfaces/UseEventLogoOptions.md +74 -0
  132. package/docs/api/interfaces/UseEventLogoReturn.md +81 -0
  133. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  134. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  135. package/docs/api/interfaces/UsePublicEventLogoOptions.md +6 -6
  136. package/docs/api/interfaces/UsePublicEventLogoReturn.md +6 -6
  137. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  138. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  139. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  140. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  141. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  142. package/docs/api/interfaces/UserEventAccess.md +11 -11
  143. package/docs/api/interfaces/UserMenuProps.md +1 -1
  144. package/docs/api/interfaces/UserProfile.md +1 -1
  145. package/docs/api/modules.md +290 -95
  146. package/docs/api-reference/components.md +1 -18
  147. package/docs/api-reference/hooks.md +1 -4
  148. package/docs/best-practices/testing.md +2 -0
  149. package/docs/documentation-index.md +1 -1
  150. package/docs/getting-started/faq.md +1 -1
  151. package/docs/implementation-guides/file-reference-system.md +592 -58
  152. package/docs/implementation-guides/file-upload-storage.md +137 -73
  153. package/docs/rbac/super-admin-guide.md +18 -70
  154. package/docs/testing/README.md +2 -0
  155. package/package.json +1 -1
  156. package/src/__tests__/TEST_STANDARD.md +674 -0
  157. package/src/__tests__/helpers/test-utils.tsx +3 -2
  158. package/src/components/DataTable/__tests__/{DataTable.comprehensive.test.tsx.skip → DataTable.comprehensive.test.tsx} +17 -18
  159. package/src/components/DataTable/__tests__/{DataTable.test.tsx.skip → DataTable.test.tsx} +14 -22
  160. package/src/components/DataTable/__tests__/{ssr.strict-mode.test.tsx.skip → ssr.strict-mode.test.tsx} +42 -47
  161. package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +1 -1
  162. package/src/components/DataTable/examples/__tests__/PerformanceExample.test.tsx +13 -4
  163. package/src/components/DataTable/utils/__tests__/COVERAGE_NOTE.md +1 -1
  164. package/src/components/DataTable/utils/__tests__/performanceUtils.test.ts +10 -6
  165. package/src/components/FileDisplay/FileDisplay.test.tsx +257 -0
  166. package/src/components/{FileDisplay.tsx → FileDisplay/FileDisplay.tsx} +111 -10
  167. package/src/components/FileDisplay/index.tsx +4 -0
  168. package/src/components/FileUpload/FileUpload.test.tsx +171 -621
  169. package/src/components/FileUpload/FileUpload.tsx +512 -168
  170. package/src/components/FileUpload/index.tsx +4 -0
  171. package/src/components/Progress/Progress.test.tsx +38 -0
  172. package/src/components/PublicLayout/EventLogo.tsx +6 -4
  173. package/src/components/Select/Select.test.tsx +1 -1
  174. package/src/components/SessionRestorationLoader.tsx +48 -0
  175. package/src/components/Toast/Toast.tsx +13 -8
  176. package/src/components/index.ts +16 -16
  177. package/src/hooks/__tests__/ServiceHooks.test.tsx +615 -0
  178. package/src/hooks/public/usePublicEventLogo.ts +16 -20
  179. package/src/hooks/useEventLogo.ts +316 -0
  180. package/src/hooks/useEvents.ts +0 -5
  181. package/src/hooks/useFileReference.test.ts +659 -0
  182. package/src/hooks/useFileReference.ts +207 -3
  183. package/src/hooks/useSessionRestoration.ts +64 -0
  184. package/src/index.ts +17 -5
  185. package/src/providers/{UnifiedAuthProvider.test.simple.tsx → UnifiedAuthProvider.smoke.test.tsx} +81 -60
  186. package/src/providers/services/AuthServiceProvider.tsx +27 -3
  187. package/src/providers/services/UnifiedAuthProvider.tsx +34 -5
  188. package/src/rbac/{engine.test.simple.ts → RBACEngine.smoke.test.ts} +17 -12
  189. package/src/services/AuthService.ts +142 -20
  190. package/src/services/EventService.ts +0 -4
  191. package/src/types/auth.ts +15 -0
  192. package/src/types/file-reference.ts +73 -1
  193. package/src/types/index.ts +1 -0
  194. package/src/utils/__tests__/organisationContext.unit.test.ts +2 -4
  195. package/src/utils/appNameResolver.simple.test.ts +99 -29
  196. package/src/utils/file-reference.test.ts +535 -0
  197. package/src/utils/file-reference.ts +200 -30
  198. package/src/utils/organisationContext.test.ts +5 -19
  199. package/src/utils/organisationContext.ts +3 -5
  200. package/src/utils/storage/README.md +269 -262
  201. package/src/utils/storage/config.ts +9 -0
  202. package/src/utils/storage/helpers.test.ts +631 -0
  203. package/src/utils/storage/helpers.ts +112 -14
  204. package/src/utils/storage/index.ts +3 -0
  205. package/src/validation/__tests__/sanitization.unit.test.ts +1 -1
  206. package/src/validation/__tests__/schemaUtils.unit.test.ts +1 -1
  207. package/src/validation/__tests__/user.unit.test.ts +1 -1
  208. package/dist/chunk-5BN3YGNK.js.map +0 -1
  209. package/dist/chunk-CVMVPYAL.js.map +0 -1
  210. package/dist/chunk-I7O3RSMN.js.map +0 -1
  211. package/dist/chunk-WUXCWRL6.js.map +0 -1
  212. package/dist/chunk-ZFLOV3OM.js.map +0 -1
  213. package/docs/CONTENT_AUDIT_REPORT.md +0 -253
  214. package/docs/STYLE_GUIDE.md +0 -37
  215. package/examples/RBAC/__tests__/PermissionExample.test.tsx +0 -150
  216. package/examples/public-pages/__tests__/PublicPageUsageExample.test.tsx +0 -159
  217. package/src/__tests__/TEST_GUIDE_CURSOR.md +0 -1605
  218. package/src/__tests__/TEST_GUIDE_HUMAN.md +0 -103
  219. package/src/components/FileUpload/FileUpload.example.tsx +0 -218
  220. package/src/components/FileUpload/index.ts +0 -6
  221. package/src/components/FileUpload.tsx +0 -176
  222. package/src/components/Progress/index.ts +0 -3
  223. package/src/components/PublicLayout/__tests__/EventLogo.test.tsx +0 -666
  224. package/src/components/SuperAdminGuard.tsx +0 -116
  225. package/src/components/__tests__/FileDisplay.test.tsx +0 -575
  226. package/src/components/__tests__/FileUpload.test.tsx +0 -446
  227. package/src/components/__tests__/SuperAdminGuard.test.tsx +0 -627
  228. package/src/components/examples/PermissionExample.tsx +0 -173
  229. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +0 -583
  230. package/src/hooks/__tests__/usePublicEventLogo.unit.test.ts +0 -640
  231. package/src/types/__tests__/file-reference.test.ts +0 -447
  232. package/src/utils/__tests__/file-reference.test.ts +0 -383
  233. /package/dist/{DataTable-FA6EUX5M.js.map → DataTable-PWBMKMOG.js.map} +0 -0
  234. /package/dist/{UnifiedAuthProvider-K2IZAY5F.js.map → UnifiedAuthProvider-5D3HEQND.js.map} +0 -0
  235. /package/dist/{chunk-NTW3KGS4.js.map → chunk-6UHXQH7P.js.map} +0 -0
  236. /package/dist/{chunk-YVUZWLQG.js.map → chunk-AQGF5OG7.js.map} +0 -0
  237. /package/dist/{chunk-KAY3K5TP.js.map → chunk-BNXBJOGL.js.map} +0 -0
  238. /package/dist/{chunk-S3JKDMD5.js.map → chunk-CXKMRKRF.js.map} +0 -0
  239. /package/dist/{chunk-RIXPZJUB.js.map → chunk-KTPG5VCH.js.map} +0 -0
  240. /package/dist/{chunk-2FQEQUJT.js.map → chunk-XXVM53P4.js.map} +0 -0
  241. /package/dist/{chunk-I2VVV5PQ.js.map → chunk-YY4YYM3E.js.map} +0 -0
  242. /package/src/providers/{OrganisationProvider.test.simple.tsx → OrganisationProvider.context.test.tsx} +0 -0
@@ -38,31 +38,27 @@ graph TD
38
38
 
39
39
  ```tsx
40
40
  import { FileUpload, FileCategory } from '@jmruthers/pace-core';
41
- import { useFileReference } from '@jmruthers/pace-core';
42
41
 
43
42
  function MyFileUpload() {
44
- const { uploadFile, getFileUrl, deleteFile, isLoading, error } = useFileReference(supabase);
45
-
46
- const handleUpload = async (file: File) => {
47
- try {
48
- const fileRef = await uploadFile({
49
- file,
50
- category: FileCategory.DOCUMENT,
51
- description: 'User uploaded document'
52
- });
53
- console.log('File uploaded:', fileRef);
54
- } catch (err) {
55
- console.error('Upload failed:', err);
56
- }
57
- };
58
-
59
43
  return (
60
44
  <FileUpload
61
45
  supabase={supabase}
62
- orgId="org-123"
63
- onUploadComplete={handleUpload}
46
+ table_name="person"
47
+ record_id="person-123"
48
+ organisation_id="org-123"
49
+ // app_id auto-resolved from app name
50
+ category={FileCategory.GENERAL_DOCUMENTS}
64
51
  accept=".pdf,.doc,.docx"
65
52
  maxSize={5 * 1024 * 1024} // 5MB
53
+ showProgress={true}
54
+ showPreview={false}
55
+ onUploadSuccess={(result) => {
56
+ console.log('File uploaded:', result.file_reference);
57
+ console.log('Available at:', result.file_url);
58
+ }}
59
+ onUploadError={(error, file) => {
60
+ console.error(`Upload failed for ${file?.name}:`, error);
61
+ }}
66
62
  >
67
63
  <div className="border-2 border-dashed border-main-300 rounded-lg p-8 text-center">
68
64
  <p>Drag and drop files here or click to browse</p>
@@ -79,7 +75,7 @@ import { FileDisplay, FileCategory } from '@jmruthers/pace-core';
79
75
  import { useFileReferenceForRecord } from '@jmruthers/pace-core';
80
76
 
81
77
  function UserProfile({ userId }: { userId: string }) {
82
- const { fileUrl, uploadFile, deleteFile, isLoading } = useFileReferenceForRecord(
78
+ const { fileUrl, fileReference, isLoading, error } = useFileReferenceForRecord(
83
79
  supabase,
84
80
  'pace_person',
85
81
  userId,
@@ -91,15 +87,25 @@ function UserProfile({ userId }: { userId: string }) {
91
87
  <h2>Profile Documents</h2>
92
88
  <FileDisplay
93
89
  supabase={supabase}
94
- orgId="org-123"
95
- recordType="pace_person"
96
- recordId={userId}
97
- category={FileCategory.DOCUMENT}
98
- onUpload={uploadFile}
99
- onDelete={deleteFile}
90
+ table_name="pace_person"
91
+ record_id={userId}
92
+ organisation_id="org-123"
93
+ category={FileCategory.GENERAL_DOCUMENTS}
100
94
  showUpload={true}
101
95
  showDelete={true}
102
- />
96
+ className="space-y-4"
97
+ >
98
+ {/* Optional: Add custom upload component */}
99
+ <FileUpload
100
+ supabase={supabase}
101
+ table_name="pace_person"
102
+ record_id={userId}
103
+ organisation_id="org-123"
104
+ category={FileCategory.GENERAL_DOCUMENTS}
105
+ accept=".pdf,.doc,.docx"
106
+ maxSize={10 * 1024 * 1024}
107
+ />
108
+ </FileDisplay>
103
109
  </div>
104
110
  );
105
111
  }
@@ -116,15 +122,22 @@ A comprehensive file upload component with drag-and-drop support, validation, an
116
122
  ```typescript
117
123
  interface FileUploadProps {
118
124
  supabase: SupabaseClient;
119
- appName: string;
120
- orgId: string;
121
- onUploadComplete?: (fileRef: FileReference) => void;
122
- onUploadStart?: (file: File) => void;
125
+ table_name: string;
126
+ record_id: string;
127
+ organisation_id: string;
128
+ app_id?: string; // Optional - will be resolved from app name if not provided
129
+ category: FileCategory;
123
130
  accept?: string;
124
131
  maxSize?: number;
125
132
  multiple?: boolean;
126
133
  disabled?: boolean;
134
+ isPublic?: boolean; // Whether files should be uploaded to public-files bucket
127
135
  className?: string;
136
+ showPreview?: boolean; // Show image preview for accepted files
137
+ showProgress?: boolean; // Show upload progress bar
138
+ onUploadSuccess?: (result: FileUploadResult) => void;
139
+ onUploadError?: (error: string, file?: File) => void;
140
+ onProgress?: (progress: UploadProgress) => void;
128
141
  children?: React.ReactNode;
129
142
  }
130
143
  ```
@@ -135,11 +148,13 @@ interface FileUploadProps {
135
148
  ```tsx
136
149
  <FileUpload
137
150
  supabase={supabase}
138
- appName="my-app"
139
- orgId={organisationId}
140
- onUploadComplete={(fileRef) => console.log('Uploaded:', fileRef)}
151
+ table_name="person"
152
+ record_id="person-123"
153
+ organisation_id={organisationId}
154
+ category={FileCategory.PROFILE_PHOTOS}
141
155
  accept="image/*"
142
156
  maxSize={2 * 1024 * 1024} // 2MB
157
+ onUploadSuccess={(result) => console.log('Uploaded:', result.file_reference)}
143
158
  >
144
159
  <Button>Upload Image</Button>
145
160
  </FileUpload>
@@ -149,11 +164,14 @@ interface FileUploadProps {
149
164
  ```tsx
150
165
  <FileUpload
151
166
  supabase={supabase}
152
- appName="my-app"
153
- orgId={organisationId}
167
+ table_name="person"
168
+ record_id="person-123"
169
+ organisation_id={organisationId}
170
+ category={FileCategory.GENERAL_DOCUMENTS}
154
171
  multiple={true}
155
172
  accept=".pdf,.doc,.docx"
156
- onUploadComplete={(fileRef) => addToFileList(fileRef)}
173
+ showProgress={true}
174
+ onUploadSuccess={(result) => addToFileList(result.file_reference)}
157
175
  >
158
176
  <div className="upload-area">
159
177
  <UploadIcon className="w-8 h-8" />
@@ -188,17 +206,14 @@ A component for displaying and managing files associated with database records.
188
206
  ```typescript
189
207
  interface FileDisplayProps {
190
208
  supabase: SupabaseClient;
191
- appName: string;
192
- orgId: string;
193
- recordType: string;
194
- recordId: string;
209
+ table_name: string;
210
+ record_id: string;
211
+ organisation_id: string;
195
212
  category?: FileCategory;
196
- onUpload?: (file: File) => Promise<FileReference>;
197
- onDelete?: (fileRef: FileReference) => Promise<void>;
198
213
  showUpload?: boolean;
199
214
  showDelete?: boolean;
200
- showPreview?: boolean;
201
215
  className?: string;
216
+ children?: React.ReactNode;
202
217
  }
203
218
  ```
204
219
 
@@ -208,11 +223,10 @@ interface FileDisplayProps {
208
223
  ```tsx
209
224
  <FileDisplay
210
225
  supabase={supabase}
211
- appName="my-app"
212
- orgId={organisationId}
213
- recordType="pace_person"
214
- recordId={personId}
215
- category={FileCategory.DOCUMENT}
226
+ table_name="pace_person"
227
+ record_id={personId}
228
+ organisation_id={organisationId}
229
+ category={FileCategory.GENERAL_DOCUMENTS}
216
230
  showUpload={false}
217
231
  showDelete={false}
218
232
  />
@@ -222,17 +236,25 @@ interface FileDisplayProps {
222
236
  ```tsx
223
237
  <FileDisplay
224
238
  supabase={supabase}
225
- appName="my-app"
226
- orgId={organisationId}
227
- recordType="pace_person"
228
- recordId={personId}
229
- category={FileCategory.IMAGE}
230
- onUpload={handleUpload}
231
- onDelete={handleDelete}
239
+ table_name="pace_person"
240
+ record_id={personId}
241
+ organisation_id={organisationId}
242
+ category={FileCategory.IMAGES}
232
243
  showUpload={true}
233
244
  showDelete={true}
234
- showPreview={true}
235
- />
245
+ className="space-y-4"
246
+ >
247
+ {/* Optional: Custom upload component */}
248
+ <FileUpload
249
+ supabase={supabase}
250
+ table_name="pace_person"
251
+ record_id={personId}
252
+ organisation_id={organisationId}
253
+ category={FileCategory.IMAGES}
254
+ accept="image/*"
255
+ showPreview={true}
256
+ />
257
+ </FileDisplay>
236
258
  ```
237
259
 
238
260
  ## Hooks
@@ -359,14 +381,24 @@ PACE Core supports predefined file categories for better organization:
359
381
 
360
382
  ```typescript
361
383
  enum FileCategory {
362
- DOCUMENT = 'document',
363
- IMAGE = 'image',
384
+ PROFILE_PHOTOS = 'profile_photos',
385
+ ID_DOCUMENTS = 'id_documents',
386
+ QUALIFICATIONS = 'qualifications',
387
+ MEDICAL_DOCUMENTS = 'medical_documents',
388
+ DISH_IMAGES = 'dish_images',
389
+ EVENT_LOGOS = 'event_logos',
390
+ GENERAL_DOCUMENTS = 'general_documents',
391
+ IMAGES = 'images',
364
392
  AUDIO = 'audio',
365
393
  VIDEO = 'video',
366
- ARCHIVE = 'archive',
367
- SPREADSHEET = 'spreadsheet',
368
- PRESENTATION = 'presentation',
369
- OTHER = 'other'
394
+ ARCHIVES = 'archives',
395
+ // CAKE-specific categories
396
+ CAKE_DISH = 'cake_dish',
397
+ // TRAC-specific categories
398
+ TRAC_ACCOMMODATION = 'trac_accommodation',
399
+ TRAC_ACTIVITY = 'trac_activity',
400
+ TRAC_JOURNAL = 'trac_journal',
401
+ TRAC_TRANSPORT = 'trac_transport'
370
402
  }
371
403
  ```
372
404
 
@@ -377,17 +409,23 @@ import { FileCategory } from '@jmruthers/pace-core';
377
409
 
378
410
  // Upload a document
379
411
  await uploadFile({
380
- file: pdfFile,
381
- category: FileCategory.DOCUMENT,
382
- description: 'Contract document'
383
- });
384
-
385
- // Upload an image
412
+ table_name: 'person',
413
+ record_id: 'person-123',
414
+ organisation_id: 'org-123',
415
+ app_id: 'app-123',
416
+ category: FileCategory.GENERAL_DOCUMENTS,
417
+ is_public: false
418
+ }, pdfFile);
419
+
420
+ // Upload a profile photo
386
421
  await uploadFile({
387
- file: imageFile,
388
- category: FileCategory.IMAGE,
389
- description: 'Profile photo'
390
- });
422
+ table_name: 'person',
423
+ record_id: 'person-123',
424
+ organisation_id: 'org-123',
425
+ app_id: 'app-123',
426
+ category: FileCategory.PROFILE_PHOTOS,
427
+ is_public: false
428
+ }, imageFile);
391
429
  ```
392
430
 
393
431
  ## Database Schema
@@ -536,6 +574,32 @@ function FileUpload() {
536
574
  }
537
575
  ```
538
576
 
577
+ ## Recent Improvements
578
+
579
+ ### Performance & Memory Management
580
+ - **Fixed infinite logging loops**: Removed debug logging that was causing performance issues in event services
581
+ - **Memory leak prevention**: Added automatic cleanup in hooks and components to prevent memory accumulation
582
+ - **Cache management**: Implemented cache size limits and TTL for event logos with automatic cleanup
583
+ - **Optimized re-renders**: Fixed infinite re-render loops in FileDisplay component using refs for state tracking
584
+
585
+ ### Enhanced User Experience
586
+ - **App ID auto-resolution**: FileUpload component now automatically resolves app_id from app name configuration
587
+ - **Better error handling**: More descriptive error messages and graceful failure handling with user-friendly toasts
588
+ - **Progress tracking**: Enhanced upload progress with visual feedback and file previews
589
+ - **Event context integration**: Event logos now automatically sync with selected events from the event selector
590
+
591
+ ### Security & Reliability
592
+ - **RLS policy fixes**: Resolved permission issues for file uploads with proper organisation context setting
593
+ - **Organisation context**: Proper database session context setting via `app.current_organisation_id`
594
+ - **Super admin support**: Enhanced permissions for administrative users with dedicated RLS policies
595
+ - **Bucket validation**: Improved bucket selection and validation logic for public vs private files
596
+
597
+ ### Developer Experience
598
+ - **Comprehensive documentation**: Updated all documentation to reflect current API and best practices
599
+ - **Better TypeScript support**: Improved type definitions and interfaces
600
+ - **Enhanced debugging**: Better error messages and debugging tools for troubleshooting
601
+ - **Legacy system removal**: Completely removed legacy file upload system to eliminate tech debt
602
+
539
603
  ## Migration from Old File Columns
540
604
 
541
605
  If you're migrating from direct file columns to the file reference system:
@@ -396,33 +396,9 @@ function MyComponent() {
396
396
  }
397
397
  ```
398
398
 
399
- ### Using SuperAdminGuard Component
399
+ ### Super Admin UI Considerations
400
400
 
401
- ```tsx
402
- import { SuperAdminGuard, SuperAdminBadge } from '@jmruthers/pace-core/components';
403
-
404
- function AdminDashboard() {
405
- return (
406
- <div>
407
- <header>
408
- <h1>Admin Dashboard</h1>
409
- <SuperAdminBadge />
410
- </header>
411
-
412
- <SuperAdminGuard
413
- fallback={<div>You need super admin access to view this content</div>}
414
- >
415
- <div className="super-admin-content">
416
- <h2>Super Admin Tools</h2>
417
- <button>Manage All Organisations</button>
418
- <button>View System Logs</button>
419
- <button>Access All User Data</button>
420
- </div>
421
- </SuperAdminGuard>
422
- </div>
423
- );
424
- }
425
- ```
401
+ Prefer enforcing super-admin-only behavior using RBAC hooks (e.g., `useRBAC`) and server-side policies. Avoid bespoke guard components.
426
402
 
427
403
  ### Data Table with Super Admin Access
428
404
 
@@ -493,11 +469,7 @@ import {
493
469
  PermissionEnforcer,
494
470
  PagePermissionGuard
495
471
  } from '@jmruthers/pace-core/rbac';
496
- import {
497
- SuperAdminGuard,
498
- SuperAdminBadge,
499
- SuperAdminDebugPanel
500
- } from '@jmruthers/pace-core/components';
472
+ // (Super admin UI helpers previously documented have been removed.)
501
473
 
502
474
  function AdminLayout({ children }) {
503
475
  const { isSuperAdmin } = useRBAC();
@@ -515,11 +487,14 @@ function AdminLayout({ children }) {
515
487
  <li><Link to="/admin/users">Users</Link></li>
516
488
  <li><Link to="/admin/events">Events</Link></li>
517
489
 
518
- <SuperAdminGuard>
519
- <li><Link to="/admin/super-admin">Super Admin</Link></li>
520
- <li><Link to="/admin/system-logs">System Logs</Link></li>
521
- <li><Link to="/admin/all-organisations">All Organisations</Link></li>
522
- </SuperAdminGuard>
490
+ {/* Gate links using app logic based on isSuperAdmin instead of a guard component */}
491
+ {isSuperAdmin && (
492
+ <>
493
+ <li><Link to="/admin/super-admin">Super Admin</Link></li>
494
+ <li><Link to="/admin/system-logs">System Logs</Link></li>
495
+ <li><Link to="/admin/all-organisations">All Organisations</Link></li>
496
+ </>
497
+ )}
523
498
  </ul>
524
499
  </nav>
525
500
 
@@ -528,8 +503,9 @@ function AdminLayout({ children }) {
528
503
  </main>
529
504
 
530
505
  <footer className="admin-footer">
506
+ {/* Optional: inline debug in development */}
531
507
  {process.env.NODE_ENV === 'development' && (
532
- <SuperAdminDebugPanel />
508
+ <div>Debug: {String(isSuperAdmin)}</div>
533
509
  )}
534
510
  </footer>
535
511
  </div>
@@ -542,46 +518,18 @@ function AdminLayout({ children }) {
542
518
  ```tsx
543
519
  import { render, screen } from '@testing-library/react';
544
520
  import { useRBAC } from '@jmruthers/pace-core';
545
- import { SuperAdminGuard } from '@jmruthers/pace-core/components';
521
+ // SuperAdminGuard removed; use conditional rendering in tests
546
522
 
547
523
  // Mock the hook
548
524
  jest.mock('@jmruthers/pace-core/rbac', () => ({
549
525
  useRBAC: jest.fn()
550
526
  }));
551
527
 
552
- describe('SuperAdminGuard', () => {
553
- test('renders children for super admin users', () => {
554
- (useRBAC as jest.Mock).mockReturnValue({
555
- isSuperAdmin: true,
556
- hasGlobalPermission: jest.fn().mockReturnValue(true),
557
- isLoading: false
558
- });
559
-
560
- render(
561
- <SuperAdminGuard fallback={<div>Access Denied</div>}>
562
- <div>Super Admin Content</div>
563
- </SuperAdminGuard>
564
- );
565
-
528
+ describe('Super Admin conditional rendering', () => {
529
+ test('renders content for super admin users', () => {
530
+ (useRBAC as jest.Mock).mockReturnValue({ isSuperAdmin: true });
531
+ render(<div>{true && <div>Super Admin Content</div>}</div>);
566
532
  expect(screen.getByText('Super Admin Content')).toBeInTheDocument();
567
- expect(screen.queryByText('Access Denied')).not.toBeInTheDocument();
568
- });
569
-
570
- test('renders fallback for non-super admin users', () => {
571
- (useRBAC as jest.Mock).mockReturnValue({
572
- isSuperAdmin: false,
573
- hasGlobalPermission: jest.fn().mockReturnValue(false),
574
- isLoading: false
575
- });
576
-
577
- render(
578
- <SuperAdminGuard fallback={<div>Access Denied</div>}>
579
- <div>Super Admin Content</div>
580
- </SuperAdminGuard>
581
- );
582
-
583
- expect(screen.getByText('Access Denied')).toBeInTheDocument();
584
- expect(screen.queryByText('Super Admin Content')).not.toBeInTheDocument();
585
533
  });
586
534
  });
587
535
  ```
@@ -8,6 +8,8 @@ reviewedBy: content-audit
8
8
 
9
9
  This guide covers testing strategies, patterns, and best practices for applications built with PACE Core.
10
10
 
11
+ > 📖 **For comprehensive testing standards and patterns**, see the [Testing Standard](../../src/__tests__/TEST_STANDARD.md) - the authoritative guide for writing world-class tests in pace-core.
12
+
11
13
  ## Overview
12
14
 
13
15
  PACE Core provides comprehensive testing support with:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jmruthers/pace-core",
3
- "version": "0.5.87",
3
+ "version": "0.5.88",
4
4
  "description": "Clean, modern React component library with Tailwind v4 styling and native utilities",
5
5
  "private": false,
6
6
  "publishConfig": {