@jmruthers/pace-core 0.5.121 → 0.5.124

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 (255) hide show
  1. package/dist/{AuthService-D4646R4b.d.ts → AuthService-DYuQPJj6.d.ts} +0 -9
  2. package/dist/{DataTable-DGZDJUYM.js → DataTable-OKDYRW2S.js} +7 -8
  3. package/dist/{PublicLoadingSpinner-DgDWTFqn.d.ts → PublicLoadingSpinner-CaoRbHvJ.d.ts} +30 -4
  4. package/dist/{UnifiedAuthProvider-UACKFATV.js → UnifiedAuthProvider-6C47WIML.js} +3 -4
  5. package/dist/{chunk-D6BOFXYR.js → chunk-35ZDPMBM.js} +3 -3
  6. package/dist/{chunk-CGURJ27Z.js → chunk-4MXVZVNS.js} +2 -2
  7. package/dist/{chunk-ZYJ6O5CA.js → chunk-C43QIDN3.js} +2 -2
  8. package/dist/{chunk-VKOCWWVY.js → chunk-CX5M4ZAG.js} +1 -6
  9. package/dist/{chunk-VKOCWWVY.js 3.map → chunk-CX5M4ZAG.js.map} +1 -1
  10. package/dist/{chunk-RIEJGKD3.js → chunk-ESJTIADP.js} +15 -6
  11. package/dist/{chunk-RIEJGKD3.js.map → chunk-ESJTIADP.js.map} +1 -1
  12. package/dist/{chunk-HFBOFZ3Z.js → chunk-GBGYYMC6.js} +317 -251
  13. package/dist/chunk-GBGYYMC6.js.map +1 -0
  14. package/dist/{chunk-SMJZMKYN.js → chunk-GEVIB2UB.js} +43 -10
  15. package/dist/chunk-GEVIB2UB.js.map +1 -0
  16. package/dist/{chunk-TDNI6ZWL.js → chunk-IJOZZOGT.js} +7 -7
  17. package/dist/chunk-IJOZZOGT.js.map +1 -0
  18. package/dist/{chunk-GZRXOUBE.js → chunk-M6DDYFUD.js} +2 -2
  19. package/dist/chunk-M6DDYFUD.js.map +1 -0
  20. package/dist/{chunk-B4GZ2BXO.js → chunk-NZGLXZGP.js} +3 -3
  21. package/dist/{chunk-NZ32EONV.js → chunk-QWNJCQXZ.js} +2 -2
  22. package/dist/{chunk-QPI2CCBA.js → chunk-VPUCTHTY.js} +149 -96
  23. package/dist/chunk-VPUCTHTY.js.map +1 -0
  24. package/dist/{chunk-FKFHZUGF.js → chunk-XN6GWKMV.js} +43 -56
  25. package/dist/chunk-XN6GWKMV.js.map +1 -0
  26. package/dist/{chunk-BHWIUEYH.js → chunk-ZBLK676C.js} +1 -61
  27. package/dist/chunk-ZBLK676C.js.map +1 -0
  28. package/dist/components.d.ts +1 -1
  29. package/dist/components.js +11 -11
  30. package/dist/{formatting-B1jSqgl-.d.ts → formatting-DFcCxUEk.d.ts} +1 -1
  31. package/dist/hooks.d.ts +1 -1
  32. package/dist/hooks.js +9 -8
  33. package/dist/hooks.js.map +1 -1
  34. package/dist/index.d.ts +6 -6
  35. package/dist/index.js +19 -17
  36. package/dist/index.js.map +1 -1
  37. package/dist/providers.d.ts +2 -2
  38. package/dist/providers.js +2 -3
  39. package/dist/rbac/index.js +7 -8
  40. package/dist/styles/index.d.ts +1 -1
  41. package/dist/styles/index.js +5 -3
  42. package/dist/theming/runtime.d.ts +73 -1
  43. package/dist/theming/runtime.js +5 -5
  44. package/dist/{usePublicRouteParams-BdF8bZgs.d.ts → usePublicRouteParams-Dyt1tzI9.d.ts} +60 -8
  45. package/dist/utils.d.ts +1 -1
  46. package/dist/utils.js +5 -5
  47. package/docs/api/classes/ColumnFactory.md +1 -1
  48. package/docs/api/classes/ErrorBoundary.md +1 -1
  49. package/docs/api/classes/InvalidScopeError.md +1 -1
  50. package/docs/api/classes/MissingUserContextError.md +1 -1
  51. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  52. package/docs/api/classes/PermissionDeniedError.md +1 -1
  53. package/docs/api/classes/PublicErrorBoundary.md +6 -6
  54. package/docs/api/classes/RBACAuditManager.md +1 -1
  55. package/docs/api/classes/RBACCache.md +1 -1
  56. package/docs/api/classes/RBACEngine.md +1 -1
  57. package/docs/api/classes/RBACError.md +1 -1
  58. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  59. package/docs/api/classes/SecureSupabaseClient.md +6 -6
  60. package/docs/api/classes/StorageUtils.md +1 -1
  61. package/docs/api/enums/FileCategory.md +1 -1
  62. package/docs/api/interfaces/AggregateConfig.md +1 -1
  63. package/docs/api/interfaces/ButtonProps.md +1 -1
  64. package/docs/api/interfaces/CardProps.md +1 -1
  65. package/docs/api/interfaces/ColorPalette.md +1 -1
  66. package/docs/api/interfaces/ColorShade.md +1 -1
  67. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  68. package/docs/api/interfaces/DataRecord.md +1 -1
  69. package/docs/api/interfaces/DataTableAction.md +1 -1
  70. package/docs/api/interfaces/DataTableColumn.md +1 -1
  71. package/docs/api/interfaces/DataTableProps.md +1 -1
  72. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  73. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  74. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  75. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  76. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  77. package/docs/api/interfaces/FileMetadata.md +1 -1
  78. package/docs/api/interfaces/FileReference.md +1 -1
  79. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  80. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  81. package/docs/api/interfaces/FileUploadProps.md +1 -1
  82. package/docs/api/interfaces/FooterProps.md +1 -1
  83. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  84. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  85. package/docs/api/interfaces/InputProps.md +1 -1
  86. package/docs/api/interfaces/LabelProps.md +1 -1
  87. package/docs/api/interfaces/LoginFormProps.md +1 -1
  88. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  89. package/docs/api/interfaces/NavigationContextType.md +1 -1
  90. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  91. package/docs/api/interfaces/NavigationItem.md +1 -1
  92. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  93. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  94. package/docs/api/interfaces/Organisation.md +1 -1
  95. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  96. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  97. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  98. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  99. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  100. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  101. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  102. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  103. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  104. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  105. package/docs/api/interfaces/PaletteData.md +1 -1
  106. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  107. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  108. package/docs/api/interfaces/PublicErrorBoundaryProps.md +7 -7
  109. package/docs/api/interfaces/PublicErrorBoundaryState.md +5 -5
  110. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +7 -7
  111. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  112. package/docs/api/interfaces/PublicPageHeaderProps.md +51 -12
  113. package/docs/api/interfaces/PublicPageLayoutProps.md +72 -12
  114. package/docs/api/interfaces/RBACConfig.md +1 -1
  115. package/docs/api/interfaces/RBACLogger.md +1 -1
  116. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  117. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  118. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  119. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  120. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  121. package/docs/api/interfaces/RouteConfig.md +1 -1
  122. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  123. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  124. package/docs/api/interfaces/StorageConfig.md +1 -1
  125. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  126. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  127. package/docs/api/interfaces/StorageListOptions.md +1 -1
  128. package/docs/api/interfaces/StorageListResult.md +1 -1
  129. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  130. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  131. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  132. package/docs/api/interfaces/StyleImport.md +1 -1
  133. package/docs/api/interfaces/SwitchProps.md +1 -1
  134. package/docs/api/interfaces/ToastActionElement.md +1 -1
  135. package/docs/api/interfaces/ToastProps.md +1 -1
  136. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  137. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  138. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  139. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  140. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  141. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  142. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
  143. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  144. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  145. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  146. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  147. package/docs/api/interfaces/UserEventAccess.md +1 -1
  148. package/docs/api/interfaces/UserMenuProps.md +1 -1
  149. package/docs/api/interfaces/UserProfile.md +1 -1
  150. package/docs/api/modules.md +140 -30
  151. package/docs/best-practices/README.md +1 -1
  152. package/docs/implementation-guides/datatable-filtering.md +313 -0
  153. package/docs/implementation-guides/datatable-rbac-usage.md +317 -0
  154. package/docs/implementation-guides/hierarchical-datatable.md +850 -0
  155. package/docs/implementation-guides/large-datasets.md +281 -0
  156. package/docs/implementation-guides/performance.md +403 -0
  157. package/docs/implementation-guides/public-pages.md +4 -4
  158. package/docs/migration/quick-migration-guide.md +320 -0
  159. package/docs/rbac/quick-start.md +16 -16
  160. package/docs/troubleshooting/README.md +4 -4
  161. package/docs/troubleshooting/cake-page-permission-guard-issue-summary.md +1 -1
  162. package/docs/troubleshooting/debugging.md +1117 -0
  163. package/docs/troubleshooting/migration.md +918 -0
  164. package/examples/public-pages/CorrectPublicPageImplementation.tsx +30 -30
  165. package/examples/public-pages/PublicEventPage.tsx +41 -41
  166. package/examples/public-pages/PublicPageApp.tsx +33 -33
  167. package/examples/public-pages/PublicPageUsageExample.tsx +30 -30
  168. package/package.json +4 -4
  169. package/src/__tests__/hooks/usePermissions.test.ts +265 -0
  170. package/src/components/DataTable/DataTable.test.tsx +9 -38
  171. package/src/components/DataTable/DataTable.tsx +0 -7
  172. package/src/components/DataTable/components/DataTableCore.tsx +125 -144
  173. package/src/components/DataTable/components/DataTableModals.tsx +25 -22
  174. package/src/components/DataTable/components/DataTableToolbar.tsx +14 -1
  175. package/src/components/DataTable/components/EditableRow.tsx +118 -42
  176. package/src/components/DataTable/components/UnifiedTableBody.tsx +129 -76
  177. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +33 -14
  178. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +17 -5
  179. package/src/components/DataTable/utils/exportUtils.ts +3 -2
  180. package/src/components/Dialog/Dialog.tsx +1 -1
  181. package/src/components/Dialog/README.md +24 -24
  182. package/src/components/Dialog/examples/BasicHtmlTest.tsx +2 -2
  183. package/src/components/Dialog/examples/DebugHtmlExample.tsx +6 -6
  184. package/src/components/Dialog/examples/HtmlDialogExample.tsx +2 -2
  185. package/src/components/Dialog/examples/SimpleHtmlTest.tsx +3 -3
  186. package/src/components/Dialog/examples/__tests__/SimpleHtmlTest.test.tsx +4 -4
  187. package/src/components/PaceAppLayout/PaceAppLayout.tsx +12 -1
  188. package/src/components/PublicLayout/EventLogo.tsx +175 -0
  189. package/src/components/PublicLayout/PublicErrorBoundary.tsx +22 -18
  190. package/src/components/PublicLayout/PublicLoadingSpinner.tsx +22 -14
  191. package/src/components/PublicLayout/PublicPageHeader.tsx +133 -40
  192. package/src/components/PublicLayout/PublicPageLayout.tsx +75 -72
  193. package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +1 -1
  194. package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +8 -8
  195. package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +23 -16
  196. package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +86 -14
  197. package/src/examples/CorrectPublicPageImplementation.tsx +30 -30
  198. package/src/examples/PublicEventPage.tsx +41 -41
  199. package/src/examples/PublicPageApp.tsx +33 -33
  200. package/src/examples/PublicPageUsageExample.tsx +30 -30
  201. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +583 -0
  202. package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +10 -3
  203. package/src/hooks/index.ts +1 -1
  204. package/src/hooks/public/usePublicEventLogo.ts +285 -0
  205. package/src/hooks/public/usePublicRouteParams.ts +21 -4
  206. package/src/hooks/useEventTheme.test.ts +119 -43
  207. package/src/hooks/useEventTheme.ts +84 -55
  208. package/src/index.ts +3 -1
  209. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +630 -0
  210. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +667 -0
  211. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +647 -0
  212. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +496 -0
  213. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +496 -0
  214. package/src/rbac/secureClient.ts +4 -2
  215. package/src/services/EventService.ts +0 -66
  216. package/src/services/__tests__/EventService.eventColours.test.ts +44 -40
  217. package/src/styles/index.ts +1 -1
  218. package/src/theming/__tests__/parseEventColours.test.ts +209 -0
  219. package/src/theming/parseEventColours.ts +123 -0
  220. package/src/theming/runtime.ts +3 -0
  221. package/src/types/__tests__/file-reference.test.ts +447 -0
  222. package/src/utils/formatDate.test.ts +11 -11
  223. package/src/utils/formatting.ts +3 -2
  224. package/dist/chunk-BDZUMRBD.js 3.map +0 -1
  225. package/dist/chunk-BHWIUEYH.js.map +0 -1
  226. package/dist/chunk-CGURJ27Z.js.map +0 -1
  227. package/dist/chunk-FKFHZUGF.js.map +0 -1
  228. package/dist/chunk-GKHF54DI 2.js +0 -619
  229. package/dist/chunk-GKHF54DI.js 2.map +0 -1
  230. package/dist/chunk-GZRXOUBE.js.map +0 -1
  231. package/dist/chunk-HFBOFZ3Z.js.map +0 -1
  232. package/dist/chunk-NZ32EONV.js.map +0 -1
  233. package/dist/chunk-O3NWNXDY 2.js +0 -76
  234. package/dist/chunk-QPI2CCBA.js.map +0 -1
  235. package/dist/chunk-SMJZMKYN.js.map +0 -1
  236. package/dist/chunk-TDNI6ZWL.js 2.map +0 -1
  237. package/dist/chunk-TDNI6ZWL.js.map +0 -1
  238. package/dist/chunk-VKOCWWVY.js.map +0 -1
  239. package/dist/chunk-WP5I5GLN 2.js +0 -1564
  240. package/dist/index 3.js +0 -856
  241. package/dist/providers 3.js +0 -38
  242. package/dist/providers.js 3.map +0 -1
  243. package/dist/types 3.js +0 -128
  244. package/dist/types.js 3.map +0 -1
  245. package/dist/useInactivityTracker-MRUU55XI.js 3.map +0 -1
  246. package/dist/utils.js 3.map +0 -1
  247. package/dist/validation 3.js +0 -479
  248. package/src/styles/semantic.css +0 -24
  249. /package/dist/{DataTable-DGZDJUYM.js.map → DataTable-OKDYRW2S.js.map} +0 -0
  250. /package/dist/{UnifiedAuthProvider-UACKFATV.js.map → UnifiedAuthProvider-6C47WIML.js.map} +0 -0
  251. /package/dist/{chunk-D6BOFXYR.js.map → chunk-35ZDPMBM.js.map} +0 -0
  252. /package/dist/{chunk-CGURJ27Z.js 2.map → chunk-4MXVZVNS.js.map} +0 -0
  253. /package/dist/{chunk-ZYJ6O5CA.js.map → chunk-C43QIDN3.js.map} +0 -0
  254. /package/dist/{chunk-B4GZ2BXO.js.map → chunk-NZGLXZGP.js.map} +0 -0
  255. /package/dist/{chunk-NZ32EONV.js 2.map → chunk-QWNJCQXZ.js.map} +0 -0
@@ -660,7 +660,7 @@ const DialogBody = ({
660
660
  ) : (
661
661
  <>
662
662
  {hasHtmlContent && !processedHtmlContent && (
663
- <div className="text-red-500 mb-2">
663
+ <div className="text-acc-500 mb-2">
664
664
  No HTML content processed. Showing children instead.
665
665
  </div>
666
666
  )}
@@ -86,7 +86,7 @@ The Dialog components support rich HTML content rendering with automatic sanitiz
86
86
  allowHtml={true}
87
87
  >
88
88
  {/* Fallback content if HTML rendering fails */}
89
- <div className="text-red-500">
89
+ <div className="text-acc-500">
90
90
  HTML content failed to render. This is fallback content.
91
91
  </div>
92
92
  </DialogBody>
@@ -100,27 +100,27 @@ The Dialog components support rich HTML content rendering with automatic sanitiz
100
100
  <DialogBody
101
101
  htmlContent={`
102
102
  <div class="space-y-4">
103
- <div class="bg-blue-50 p-4 rounded-lg">
104
- <h3 class="font-semibold text-blue-900 mb-2">📋 Required Format</h3>
105
- <p class="text-sm text-blue-800 mb-2">Your CSV file must include these columns:</p>
106
- <ul class="text-sm text-blue-700 list-disc list-inside ml-2">
103
+ <div class="bg-main-50 p-4 rounded-lg">
104
+ <h3 class="font-semibold text-main-900 mb-2">📋 Required Format</h3>
105
+ <p class="text-sm text-main-800 mb-2">Your CSV file must include these columns:</p>
106
+ <ul class="text-sm text-main-700 list-disc list-inside ml-2">
107
107
  <li><code>name</code> - Full name of the person</li>
108
108
  <li><code>email</code> - Valid email address</li>
109
109
  <li><code>phone</code> - Phone number (optional)</li>
110
110
  </ul>
111
111
  </div>
112
112
 
113
- <div class="bg-green-50 p-4 rounded-lg">
114
- <h3 class="font-semibold text-green-900 mb-2">✅ Example Data</h3>
115
- <pre class="text-xs text-green-700 bg-white p-2 rounded border">
113
+ <div class="bg-main-50 p-4 rounded-lg">
114
+ <h3 class="font-semibold text-main-900 mb-2">✅ Example Data</h3>
115
+ <pre class="text-xs text-main-700 bg-main-50 p-2 rounded border">
116
116
  name,email,phone
117
117
  John Doe,john@example.com,555-0123
118
118
  Jane Smith,jane@example.com,
119
119
  </pre>
120
120
  </div>
121
121
 
122
- <div class="bg-yellow-50 p-3 rounded-lg">
123
- <p class="text-sm text-yellow-800">
122
+ <div class="bg-acc-50 p-3 rounded-lg">
123
+ <p class="text-sm text-acc-800">
124
124
  <strong>⚠️ Important:</strong> Make sure your CSV file is properly formatted.
125
125
  </p>
126
126
  </div>
@@ -212,20 +212,20 @@ function ImportInstructionsDialog() {
212
212
 
213
213
  const importInstructions = `
214
214
  <div class="space-y-4">
215
- <p class="text-sm text-gray-600 mb-4">
215
+ <p class="text-sm text-sec-600 mb-4">
216
216
  Upload a CSV file with dish or recipe data. The system will automatically detect the format based on your column headers.
217
217
  </p>
218
218
 
219
- <div class="bg-blue-50 p-4 rounded-lg">
220
- <h3 class="font-semibold text-blue-900 mb-2">🍽️ Dish Format (3 columns)</h3>
221
- <p class="text-sm text-blue-800 mb-2">Perfect for importing basic dish information:</p>
219
+ <div class="bg-main-50 p-4 rounded-lg">
220
+ <h3 class="font-semibold text-main-900 mb-2">🍽️ Dish Format (3 columns)</h3>
221
+ <p class="text-sm text-main-800 mb-2">Perfect for importing basic dish information:</p>
222
222
  <div class="space-y-1">
223
223
  <p class="text-sm"><strong>Required:</strong> <code>dish_code</code>, <code>dish_name</code>, <code>mealtype_name</code></p>
224
224
  <p class="text-sm"><strong>Optional:</strong> <code>dish_description</code></p>
225
225
  </div>
226
226
  <div class="mt-2">
227
- <p class="text-xs text-blue-700"><strong>Examples:</strong></p>
228
- <ul class="text-xs text-blue-700 list-disc list-inside ml-2">
227
+ <p class="text-xs text-main-700"><strong>Examples:</strong></p>
228
+ <ul class="text-xs text-main-700 list-disc list-inside ml-2">
229
229
  <li><code>dish_code</code>: BBQ, PC, CTY</li>
230
230
  <li><code>dish_name</code>: BBQ hamburgers and potato salad</li>
231
231
  <li><code>mealtype_name</code>: Breakfast, Lunch, Dinner</li>
@@ -233,16 +233,16 @@ function ImportInstructionsDialog() {
233
233
  </div>
234
234
  </div>
235
235
 
236
- <div class="bg-green-50 p-4 rounded-lg">
237
- <h3 class="font-semibold text-green-900 mb-2">📋 Recipe Format (8 columns)</h3>
238
- <p class="text-sm text-green-800 mb-2">Perfect for importing detailed recipe ingredients:</p>
236
+ <div class="bg-main-50 p-4 rounded-lg">
237
+ <h3 class="font-semibold text-main-900 mb-2">📋 Recipe Format (8 columns)</h3>
238
+ <p class="text-sm text-main-800 mb-2">Perfect for importing detailed recipe ingredients:</p>
239
239
  <div class="space-y-1">
240
240
  <p class="text-sm"><strong>Required:</strong> <code>dish_code</code>, <code>dish_name</code>, <code>mealtype_name</code>, <code>diettype_name</code>, <code>item_name</code>, <code>recipe_qtypp</code>, <code>recipe_uptake</code></p>
241
241
  <p class="text-sm"><strong>Optional:</strong> <code>item_brand</code></p>
242
242
  </div>
243
243
  <div class="mt-2">
244
- <p class="text-xs text-green-700"><strong>Examples:</strong></p>
245
- <ul class="text-xs text-green-700 list-disc list-inside ml-2">
244
+ <p class="text-xs text-main-700"><strong>Examples:</strong></p>
245
+ <ul class="text-xs text-main-700 list-disc list-inside ml-2">
246
246
  <li><code>dish_code</code>: BBQ</li>
247
247
  <li><code>dish_name</code>: BBQ hamburgers and potato salad</li>
248
248
  <li><code>mealtype_name</code>: Dinner</li>
@@ -255,8 +255,8 @@ function ImportInstructionsDialog() {
255
255
  </div>
256
256
  </div>
257
257
 
258
- <div class="bg-yellow-50 p-3 rounded-lg">
259
- <p class="text-sm text-yellow-800"><strong>⚠️ Important:</strong> Recipe imports will replace all existing recipe data for dishes in the file.</p>
258
+ <div class="bg-acc-50 p-3 rounded-lg">
259
+ <p class="text-sm text-acc-800"><strong>⚠️ Important:</strong> Recipe imports will replace all existing recipe data for dishes in the file.</p>
260
260
  </div>
261
261
  </div>
262
262
  `;
@@ -280,7 +280,7 @@ function ImportInstructionsDialog() {
280
280
  logWarnings={true}
281
281
  >
282
282
  {/* Fallback content if HTML rendering fails */}
283
- <div className="text-red-500">
283
+ <div className="text-acc-500">
284
284
  HTML content failed to render. This is fallback content.
285
285
  </div>
286
286
  </DialogBody>
@@ -20,7 +20,7 @@ export function BasicHtmlTest() {
20
20
  <h3 className="font-semibold mb-2">Test 1: Direct dangerouslySetInnerHTML</h3>
21
21
  <div
22
22
  dangerouslySetInnerHTML={{ __html: '<p>Hello <strong>world</strong>!</p>' }}
23
- className="bg-green-50 p-2 rounded"
23
+ className="bg-main-50 p-2 rounded"
24
24
  />
25
25
  </div>
26
26
 
@@ -38,7 +38,7 @@ export function BasicHtmlTest() {
38
38
  </DialogHeader>
39
39
 
40
40
  <DialogBody htmlContent="<p>Hello <strong>world</strong>!</p>" allowHtml={true}>
41
- <div className="text-red-500">
41
+ <div className="text-acc-500">
42
42
  HTML content failed to render. This is fallback content.
43
43
  </div>
44
44
  </DialogBody>
@@ -13,11 +13,11 @@ export function DebugHtmlExample() {
13
13
  const [isOpen, setIsOpen] = useState(false);
14
14
 
15
15
  const testHtml = `
16
- <p class="text-sm text-gray-600 mb-4">Upload a CSV file with dish or recipe data. The system will automatically detect the format based on your column headers.</p>
16
+ <p class="text-sm text-sec-600 mb-4">Upload a CSV file with dish or recipe data. The system will automatically detect the format based on your column headers.</p>
17
17
 
18
- <div class="bg-blue-50 p-4 rounded-lg">
19
- <h3 class="font-semibold text-blue-900 mb-2">Dish Format (3 columns)</h3>
20
- <p class="text-sm text-blue-800 mb-2">Perfect for importing basic dish information:</p>
18
+ <div class="bg-main-50 p-4 rounded-lg">
19
+ <h3 class="font-semibold text-main-900 mb-2">Dish Format (3 columns)</h3>
20
+ <p class="text-sm text-main-800 mb-2">Perfect for importing basic dish information:</p>
21
21
  <div class="space-y-1">
22
22
  <p class="text-sm"><strong>Required:</strong> <code>dish_code</code>, <code>dish_name</code>, <code>mealtype_name</code></p>
23
23
  <p class="text-sm"><strong>Optional:</strong> <code>dish_description</code></p>
@@ -31,7 +31,7 @@ export function DebugHtmlExample() {
31
31
 
32
32
  <div className="mb-4">
33
33
  <h3 className="font-semibold mb-2">Raw HTML String:</h3>
34
- <pre className="bg-gray-100 p-2 rounded text-xs overflow-auto">
34
+ <pre className="bg-sec-100 p-2 rounded text-xs overflow-auto">
35
35
  {testHtml}
36
36
  </pre>
37
37
  </div>
@@ -48,7 +48,7 @@ export function DebugHtmlExample() {
48
48
 
49
49
  <DialogBody htmlContent={testHtml} allowHtml={true}>
50
50
  {/* Fallback content if HTML rendering fails */}
51
- <div className="text-red-500">
51
+ <div className="text-acc-500">
52
52
  HTML content failed to render. This is fallback content.
53
53
  </div>
54
54
  </DialogBody>
@@ -149,8 +149,8 @@ export function HtmlDialogExample() {
149
149
  <div className="space-y-4">
150
150
  <h3 className="text-lg font-semibold">React Children Content</h3>
151
151
  <p>This content is rendered using React children, not HTML strings.</p>
152
- <div className="bg-blue-50 p-4 rounded-lg">
153
- <p className="text-blue-800">
152
+ <div className="bg-main-50 p-4 rounded-lg">
153
+ <p className="text-main-800">
154
154
  You can mix HTML content (via <code>htmlContent</code> prop)
155
155
  with React children for maximum flexibility.
156
156
  </p>
@@ -21,14 +21,14 @@ export function SimpleHtmlTest() {
21
21
 
22
22
  <div className="mb-4">
23
23
  <h3 className="font-semibold mb-2">Test HTML:</h3>
24
- <pre className="bg-gray-100 p-2 rounded text-xs">
24
+ <pre className="bg-sec-100 p-2 rounded text-xs">
25
25
  {simpleHtml}
26
26
  </pre>
27
27
  </div>
28
28
 
29
29
  <div className="mb-4">
30
30
  <h3 className="font-semibold mb-2">Expected Result:</h3>
31
- <div className="bg-green-50 p-2 rounded">
31
+ <div className="bg-main-50 p-2 rounded">
32
32
  Hello <strong>world</strong>!
33
33
  </div>
34
34
  </div>
@@ -44,7 +44,7 @@ export function SimpleHtmlTest() {
44
44
  </DialogHeader>
45
45
 
46
46
  <DialogBody htmlContent={simpleHtml} allowHtml={true}>
47
- <div className="text-red-500">
47
+ <div className="text-acc-500">
48
48
  HTML content failed to render. This is fallback content.
49
49
  </div>
50
50
  </DialogBody>
@@ -93,7 +93,7 @@ describe('SimpleHtmlTest Component', () => {
93
93
 
94
94
  const codeBlock = screen.getByText(/Hello <strong>world<\/strong>!/).closest('pre');
95
95
  expect(codeBlock).toBeInTheDocument();
96
- expect(codeBlock?.className).toContain('bg-gray-100');
96
+ expect(codeBlock?.className).toContain('bg-sec-100');
97
97
  });
98
98
  });
99
99
 
@@ -102,7 +102,7 @@ describe('SimpleHtmlTest Component', () => {
102
102
  renderWithProviders(<SimpleHtmlTest />);
103
103
 
104
104
  // Should show the expected result container with proper styling
105
- const resultContainers = document.querySelectorAll('.bg-green-50');
105
+ const resultContainers = document.querySelectorAll('.bg-main-50');
106
106
  expect(resultContainers.length).toBeGreaterThan(0);
107
107
  });
108
108
 
@@ -110,11 +110,11 @@ describe('SimpleHtmlTest Component', () => {
110
110
  renderWithProviders(<SimpleHtmlTest />);
111
111
 
112
112
  // The expected result should have "Hello" text
113
- const expectedResult = document.querySelector('.bg-green-50');
113
+ const expectedResult = document.querySelector('.bg-main-50');
114
114
  expect(expectedResult).toBeTruthy();
115
115
 
116
116
  // Should contain a strong element
117
- const strongElements = document.querySelectorAll('.bg-green-50 strong');
117
+ const strongElements = document.querySelectorAll('.bg-main-50 strong');
118
118
  expect(strongElements.length).toBeGreaterThan(0);
119
119
  });
120
120
  });
@@ -772,7 +772,18 @@ export function PaceAppLayout({
772
772
  <p className="text-sec-600 mb-4">
773
773
  You don't have permission to access this page.
774
774
  </p>
775
- <Button onClick={() => navigate('/')}>Go Home</Button>
775
+ <div className="flex gap-2 justify-center">
776
+ <Button onClick={() => navigate('/')}>Go Home</Button>
777
+ <Button
778
+ variant="outline"
779
+ onClick={async () => {
780
+ await handleSignOut();
781
+ navigate('/login');
782
+ }}
783
+ >
784
+ Sign out
785
+ </Button>
786
+ </div>
776
787
  </div>
777
788
  </div>
778
789
  );
@@ -0,0 +1,175 @@
1
+ /**
2
+ * @file Event Logo Component
3
+ * @package @jmruthers/pace-core
4
+ * @module Components/PublicLayout
5
+ * @since 1.0.0
6
+ *
7
+ * A context-aware component for displaying event logos with automatic fallback to event initials.
8
+ * Automatically detects whether it's being used in a public or authenticated context and behaves
9
+ * appropriately without triggering authentication context leakage.
10
+ *
11
+ * Features:
12
+ * - Context-aware (works in both public and authenticated contexts)
13
+ * - Automatic fallback to event initials
14
+ * - Logo validation and error handling
15
+ * - Multiple size options
16
+ * - Responsive design
17
+ * - Accessibility compliant
18
+ * - TypeScript support
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * import { EventLogo } from '@jmruthers/pace-core';
23
+ *
24
+ * function EventHeader() {
25
+ * return (
26
+ * <EventLogo
27
+ * eventId={event.id}
28
+ * eventName={event.event_name}
29
+ * organisationId={event.organisation_id}
30
+ * size="lg"
31
+ * className="rounded-full"
32
+ * />
33
+ * );
34
+ * }
35
+ * ```
36
+ *
37
+ * @accessibility
38
+ * - WCAG 2.1 AA compliant
39
+ * - Proper alt text for images
40
+ * - Screen reader friendly fallbacks
41
+ * - High contrast support
42
+ *
43
+ * @dependencies
44
+ * - React 18+ - Component framework
45
+ * - FileDisplay component - Logo display and fallback handling
46
+ * - Tailwind CSS - Styling
47
+ */
48
+
49
+ import React from 'react';
50
+ import { FileDisplay } from '../FileDisplay/FileDisplay';
51
+ import { FileCategory } from '../../types/file-reference';
52
+
53
+ export interface EventLogoProps {
54
+ /** The event ID to fetch logo for */
55
+ eventId: string;
56
+ /** The event name for fallback text generation */
57
+ eventName: string;
58
+ /** The organisation ID for storage path */
59
+ organisationId: string;
60
+ /** Logo size variant */
61
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
62
+ /** Custom CSS classes */
63
+ className?: string;
64
+ /** Whether to show fallback text when no logo is available */
65
+ showFallback?: boolean;
66
+ /** Custom fallback text generator */
67
+ generateFallbackText?: (eventName: string) => string;
68
+ /** Whether to validate image existence (deprecated - FileDisplay handles this) */
69
+ validateImage?: boolean;
70
+ /** Custom loading component */
71
+ loadingComponent?: React.ComponentType;
72
+ /** Custom error component */
73
+ errorComponent?: React.ComponentType<{ error: Error }>;
74
+ }
75
+
76
+ /**
77
+ * Default fallback text generator
78
+ */
79
+ function defaultGenerateFallbackText(eventName: string): string {
80
+ if (!eventName) return 'EV';
81
+
82
+ return eventName
83
+ .split(' ')
84
+ .map(word => word.charAt(0).toUpperCase())
85
+ .join('')
86
+ .substring(0, 3); // Max 3 characters
87
+ }
88
+
89
+ /**
90
+ * Component for displaying event logos with fallback to initials
91
+ *
92
+ * This component is context-aware and automatically detects whether it's being used
93
+ * in a public or authenticated context. It uses FileDisplay internally to fetch and
94
+ * display event logos from storage, with automatic fallback to event initials if no
95
+ * logo is available.
96
+ *
97
+ * @param props - Logo configuration and styling
98
+ * @returns React element with event logo or fallback
99
+ */
100
+ export function EventLogo({
101
+ eventId,
102
+ eventName,
103
+ organisationId,
104
+ size = 'md',
105
+ className = '',
106
+ showFallback = true,
107
+ generateFallbackText = defaultGenerateFallbackText,
108
+ validateImage = true, // Deprecated but kept for backward compatibility
109
+ loadingComponent: LoadingComponent,
110
+ errorComponent: ErrorComponent
111
+ }: EventLogoProps) {
112
+ // Adapt generateFallbackText to FileDisplay's signature
113
+ // FileDisplay expects (fileName?: string) => string, but we have (eventName: string) => string
114
+ const adaptedGenerateFallbackText = React.useCallback(
115
+ (fileName?: string) => {
116
+ // Use eventName if available, otherwise fall back to fileName
117
+ return generateFallbackText(eventName || fileName || '');
118
+ },
119
+ [eventName, generateFallbackText]
120
+ );
121
+
122
+ // Adapt error component to FileDisplay's signature
123
+ // FileDisplay expects { error: Error | string | null; retry?: () => void }
124
+ const adaptedErrorComponent = ErrorComponent
125
+ ? React.useCallback(
126
+ ({ error }: { error: Error | string | null; retry?: () => void }) => {
127
+ const errorObj = error instanceof Error ? error : new Error(String(error || 'Unknown error'));
128
+ return <ErrorComponent error={errorObj} />;
129
+ },
130
+ [ErrorComponent]
131
+ )
132
+ : undefined;
133
+
134
+ return (
135
+ <FileDisplay
136
+ table_name="event"
137
+ record_id={eventId}
138
+ organisation_id={organisationId}
139
+ category={FileCategory.EVENT_LOGOS}
140
+ displayOnly={true}
141
+ showFallback={showFallback}
142
+ fallbackSize={size}
143
+ className={className}
144
+ generateFallbackText={adaptedGenerateFallbackText}
145
+ loadingComponent={LoadingComponent}
146
+ errorComponent={adaptedErrorComponent}
147
+ />
148
+ );
149
+ }
150
+
151
+ /**
152
+ * Compact event logo for small spaces
153
+ */
154
+ export function EventLogoCompact(props: EventLogoProps) {
155
+ return (
156
+ <EventLogo
157
+ {...props}
158
+ size="sm"
159
+ className={`${props.className || ''} rounded-sm`}
160
+ />
161
+ );
162
+ }
163
+
164
+ /**
165
+ * Large event logo for prominent display
166
+ */
167
+ export function EventLogoLarge(props: EventLogoProps) {
168
+ return (
169
+ <EventLogo
170
+ {...props}
171
+ size="xl"
172
+ className={`${props.className || ''} rounded-lg`}
173
+ />
174
+ );
175
+ }
@@ -40,6 +40,7 @@
40
40
  */
41
41
 
42
42
  import React, { Component, ErrorInfo, ReactNode } from 'react';
43
+ import { cn } from '../../utils/cn';
43
44
 
44
45
  export interface PublicErrorBoundaryProps {
45
46
  /** Child components to wrap */
@@ -128,12 +129,15 @@ export class PublicErrorBoundary extends Component<PublicErrorBoundaryProps, Pub
128
129
 
129
130
  // Default error UI
130
131
  return (
131
- <div className={`min-h-screen bg-white flex items-center justify-center ${this.props.className || ''}`}>
132
+ <div className={cn(
133
+ "min-h-screen bg-background flex items-center justify-center",
134
+ this.props.className
135
+ )}>
132
136
  <div className="max-w-md mx-auto text-center px-4">
133
137
  <div className="mb-6">
134
- <div className="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-red-100 mb-4">
138
+ <div className="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-acc-100 mb-4">
135
139
  <svg
136
- className="h-6 w-6 text-red-600"
140
+ className="h-6 w-6 text-acc-600"
137
141
  fill="none"
138
142
  viewBox="0 0 24 24"
139
143
  stroke="currentColor"
@@ -146,10 +150,10 @@ export class PublicErrorBoundary extends Component<PublicErrorBoundaryProps, Pub
146
150
  />
147
151
  </svg>
148
152
  </div>
149
- <h1 className="text-2xl font-bold text-gray-900 mb-2">
153
+ <h1 className="text-2xl font-bold text-sec-900 mb-2">
150
154
  Something went wrong
151
155
  </h1>
152
- <p className="text-gray-600 mb-6">
156
+ <p className="text-sec-600 mb-6">
153
157
  {this.props.customErrorMessage ||
154
158
  'We encountered an error while loading this page. Please try again.'}
155
159
  </p>
@@ -157,11 +161,11 @@ export class PublicErrorBoundary extends Component<PublicErrorBoundaryProps, Pub
157
161
 
158
162
  {/* Error details in development */}
159
163
  {this.props.showErrorDetails && this.state.error && (
160
- <div className="mb-6 p-4 bg-red-50 border border-red-200 rounded-md text-left">
161
- <h3 className="text-sm font-medium text-red-800 mb-2">
164
+ <div className="mb-6 p-4 bg-acc-50 border border-acc-200 rounded-md text-left">
165
+ <h3 className="text-sm font-medium text-acc-800 mb-2">
162
166
  Error Details (Development Only)
163
167
  </h3>
164
- <pre className="text-xs text-red-700 whitespace-pre-wrap">
168
+ <pre className="text-xs text-acc-700 whitespace-pre-wrap">
165
169
  {this.state.error.toString()}
166
170
  {this.state.errorInfo?.componentStack}
167
171
  </pre>
@@ -172,14 +176,14 @@ export class PublicErrorBoundary extends Component<PublicErrorBoundaryProps, Pub
172
176
  <div className="space-y-3">
173
177
  <button
174
178
  onClick={this.resetError}
175
- className="w-full px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
179
+ className="w-full px-4 py-2 bg-main-600 text-main-50 rounded-md hover:bg-main-700 transition-colors focus:outline-none focus:ring-2 focus:ring-main-500 focus:ring-offset-2"
176
180
  >
177
181
  Try Again
178
182
  </button>
179
183
 
180
184
  <button
181
185
  onClick={() => window.location.reload()}
182
- className="w-full px-4 py-2 bg-gray-600 text-white rounded-md hover:bg-gray-700 transition-colors focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2"
186
+ className="w-full px-4 py-2 bg-sec-600 text-main-50 rounded-md hover:bg-sec-700 transition-colors focus:outline-none focus:ring-2 focus:ring-sec-500 focus:ring-offset-2"
183
187
  >
184
188
  Reload Page
185
189
  </button>
@@ -187,7 +191,7 @@ export class PublicErrorBoundary extends Component<PublicErrorBoundaryProps, Pub
187
191
  {this.props.onRecover && (
188
192
  <button
189
193
  onClick={this.props.onRecover}
190
- className="w-full px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 transition-colors focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2"
194
+ className="w-full px-4 py-2 bg-main-600 text-main-50 rounded-md hover:bg-main-700 transition-colors focus:outline-none focus:ring-2 focus:ring-main-500 focus:ring-offset-2"
191
195
  >
192
196
  Alternative Action
193
197
  </button>
@@ -195,7 +199,7 @@ export class PublicErrorBoundary extends Component<PublicErrorBoundaryProps, Pub
195
199
  </div>
196
200
 
197
201
  {/* Help text */}
198
- <div className="mt-6 text-sm text-gray-500">
202
+ <div className="mt-6 text-sm text-sec-500">
199
203
  <p>
200
204
  If this problem persists, please contact support or try accessing the page later.
201
205
  </p>
@@ -240,12 +244,12 @@ export function DefaultPublicErrorFallback({
240
244
  resetError
241
245
  }: PublicErrorBoundaryState) {
242
246
  return (
243
- <div className="min-h-screen bg-white flex items-center justify-center">
247
+ <div className="min-h-screen bg-background flex items-center justify-center">
244
248
  <div className="max-w-md mx-auto text-center px-4">
245
249
  <div className="mb-6">
246
- <div className="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-red-100 mb-4">
250
+ <div className="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-acc-100 mb-4">
247
251
  <svg
248
- className="h-6 w-6 text-red-600"
252
+ className="h-6 w-6 text-acc-600"
249
253
  fill="none"
250
254
  viewBox="0 0 24 24"
251
255
  stroke="currentColor"
@@ -258,17 +262,17 @@ export function DefaultPublicErrorFallback({
258
262
  />
259
263
  </svg>
260
264
  </div>
261
- <h1 className="text-2xl font-bold text-gray-900 mb-2">
265
+ <h1 className="text-2xl font-bold text-sec-900 mb-2">
262
266
  Page Error
263
267
  </h1>
264
- <p className="text-gray-600 mb-6">
268
+ <p className="text-sec-600 mb-6">
265
269
  We encountered an error while loading this page.
266
270
  </p>
267
271
  </div>
268
272
 
269
273
  <button
270
274
  onClick={resetError}
271
- className="w-full px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
275
+ className="w-full px-4 py-2 bg-main-600 text-main-50 rounded-md hover:bg-main-700 transition-colors focus:outline-none focus:ring-2 focus:ring-main-500 focus:ring-offset-2"
272
276
  >
273
277
  Try Again
274
278
  </button>