@jmruthers/pace-core 0.5.136 → 0.5.139

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 (292) hide show
  1. package/dist/{DataTable-CYOHOX3O.js → DataTable-JXFCA2BJ.js} +10 -9
  2. package/dist/{EventLogo-801uofbR.d.ts → EventLogo-rFL_kRjk.d.ts} +73 -1
  3. package/dist/{UnifiedAuthProvider-5E5TUNMS.js → UnifiedAuthProvider-XIQQ7LVU.js} +4 -5
  4. package/dist/{chunk-YLKIDTUK.js → chunk-22WKWKRX.js} +4 -4
  5. package/dist/{chunk-TVYPTYOY.js → chunk-4C7EXCAR.js} +60 -24
  6. package/dist/chunk-4C7EXCAR.js.map +1 -0
  7. package/dist/{chunk-NOHEVYVX.js → chunk-5JMOHWDI.js} +417 -319
  8. package/dist/chunk-5JMOHWDI.js.map +1 -0
  9. package/dist/{chunk-FHWWBIHA.js → chunk-6DXZ6V5Q.js} +5 -5
  10. package/dist/{chunk-2TWNJ46Y.js → chunk-6LAAY47Q.js} +2 -2
  11. package/dist/{chunk-444EZN6N.js → chunk-7QCC6MCP.js} +88 -1
  12. package/dist/chunk-7QCC6MCP.js.map +1 -0
  13. package/dist/chunk-BJPBT3CU.js +21 -0
  14. package/dist/chunk-BJPBT3CU.js.map +1 -0
  15. package/dist/{chunk-L6PGMCMD.js → chunk-BOOI7GK2.js} +38 -12
  16. package/dist/chunk-BOOI7GK2.js.map +1 -0
  17. package/dist/{chunk-XARJS7CD.js → chunk-INQLMHPF.js} +2 -2
  18. package/dist/chunk-JISYG63F.js +70 -0
  19. package/dist/chunk-JISYG63F.js.map +1 -0
  20. package/dist/{chunk-SL2YQDR6.js → chunk-MA6EPSGZ.js} +2 -2
  21. package/dist/{chunk-5DPZ5EAT.js → chunk-OWAG3GSU.js} +1 -3
  22. package/dist/{chunk-LTV3XIJJ.js → chunk-T6JN6LH6.js} +4 -4
  23. package/dist/{chunk-HJGGOMQ6.js → chunk-TLT2ZR3L.js} +147 -103
  24. package/dist/chunk-TLT2ZR3L.js.map +1 -0
  25. package/dist/{chunk-4MT5BGGL.js → chunk-YCWDTTUK.js} +4 -6
  26. package/dist/{chunk-4MT5BGGL.js.map → chunk-YCWDTTUK.js.map} +1 -1
  27. package/dist/components.d.ts +1 -1
  28. package/dist/components.js +12 -11
  29. package/dist/components.js.map +1 -1
  30. package/dist/hooks.js +8 -9
  31. package/dist/hooks.js.map +1 -1
  32. package/dist/index.d.ts +2 -2
  33. package/dist/index.js +15 -14
  34. package/dist/index.js.map +1 -1
  35. package/dist/providers.js +3 -4
  36. package/dist/rbac/index.js +8 -9
  37. package/dist/schema-DTDZQe2u.d.ts +28 -0
  38. package/dist/types.d.ts +152 -3
  39. package/dist/types.js +51 -16
  40. package/dist/types.js.map +1 -1
  41. package/dist/utils.d.ts +89 -4
  42. package/dist/utils.js +214 -96
  43. package/dist/utils.js.map +1 -1
  44. package/dist/validation.d.ts +1 -343
  45. package/dist/validation.js +3 -100
  46. package/docs/api/classes/ColumnFactory.md +1 -1
  47. package/docs/api/classes/ErrorBoundary.md +1 -1
  48. package/docs/api/classes/InvalidScopeError.md +1 -1
  49. package/docs/api/classes/MissingUserContextError.md +1 -1
  50. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  51. package/docs/api/classes/PermissionDeniedError.md +1 -1
  52. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  53. package/docs/api/classes/RBACAuditManager.md +1 -1
  54. package/docs/api/classes/RBACCache.md +1 -1
  55. package/docs/api/classes/RBACEngine.md +1 -1
  56. package/docs/api/classes/RBACError.md +1 -1
  57. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  58. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  59. package/docs/api/classes/StorageUtils.md +1 -1
  60. package/docs/api/enums/FileCategory.md +1 -1
  61. package/docs/api/interfaces/AggregateConfig.md +1 -1
  62. package/docs/api/interfaces/BadgeProps.md +27 -0
  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/EventLogoProps.md +1 -1
  77. package/docs/api/interfaces/ExportColumn.md +1 -1
  78. package/docs/api/interfaces/ExportOptions.md +1 -1
  79. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  80. package/docs/api/interfaces/FileMetadata.md +1 -1
  81. package/docs/api/interfaces/FileReference.md +1 -1
  82. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  83. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  84. package/docs/api/interfaces/FileUploadProps.md +1 -1
  85. package/docs/api/interfaces/FooterProps.md +1 -1
  86. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  87. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  88. package/docs/api/interfaces/InputProps.md +1 -1
  89. package/docs/api/interfaces/LabelProps.md +1 -1
  90. package/docs/api/interfaces/LoginFormProps.md +1 -1
  91. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  92. package/docs/api/interfaces/NavigationContextType.md +1 -1
  93. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  94. package/docs/api/interfaces/NavigationItem.md +1 -1
  95. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  96. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  97. package/docs/api/interfaces/Organisation.md +1 -1
  98. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  99. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  100. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  101. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  102. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  103. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  104. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  105. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  106. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  107. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  108. package/docs/api/interfaces/PaletteData.md +1 -1
  109. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  110. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  111. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  112. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  113. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  114. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  115. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  116. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  117. package/docs/api/interfaces/RBACConfig.md +1 -1
  118. package/docs/api/interfaces/RBACLogger.md +1 -1
  119. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  120. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  121. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  122. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  123. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  124. package/docs/api/interfaces/RouteConfig.md +1 -1
  125. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  126. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  127. package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
  128. package/docs/api/interfaces/StorageConfig.md +1 -1
  129. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  130. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  131. package/docs/api/interfaces/StorageListOptions.md +1 -1
  132. package/docs/api/interfaces/StorageListResult.md +1 -1
  133. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  134. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  135. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  136. package/docs/api/interfaces/StyleImport.md +1 -1
  137. package/docs/api/interfaces/SwitchProps.md +1 -1
  138. package/docs/api/interfaces/ToastActionElement.md +1 -1
  139. package/docs/api/interfaces/ToastProps.md +1 -1
  140. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  141. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  142. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  143. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  144. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  145. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  146. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
  147. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  148. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  149. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  150. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  151. package/docs/api/interfaces/UserEventAccess.md +1 -1
  152. package/docs/api/interfaces/UserMenuProps.md +1 -1
  153. package/docs/api/interfaces/UserProfile.md +1 -1
  154. package/docs/api/modules.md +84 -15
  155. package/docs/architecture/README.md +0 -1
  156. package/docs/styles/README.md +0 -2
  157. package/examples/RBAC/CompleteRBACExample.tsx +324 -0
  158. package/examples/RBAC/EventBasedApp.tsx +239 -0
  159. package/examples/RBAC/PermissionExample.tsx +151 -0
  160. package/examples/RBAC/index.ts +13 -0
  161. package/examples/public-pages/CorrectPublicPageImplementation.tsx +301 -0
  162. package/examples/public-pages/PublicEventPage.tsx +274 -0
  163. package/examples/public-pages/PublicPageApp.tsx +308 -0
  164. package/examples/public-pages/PublicPageUsageExample.tsx +216 -0
  165. package/examples/public-pages/index.ts +14 -0
  166. package/package.json +1 -10
  167. package/src/__tests__/TEST_STANDARD.md +92 -0
  168. package/src/components/Badge/Badge.test.tsx +314 -0
  169. package/src/components/Badge/Badge.tsx +304 -0
  170. package/src/components/Badge/index.ts +3 -0
  171. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +217 -0
  172. package/src/components/DataTable/__tests__/styles.test.ts +1 -1
  173. package/src/components/DataTable/components/ColumnFilter.tsx +8 -4
  174. package/src/components/DataTable/components/DataTableBody.tsx +461 -0
  175. package/src/components/DataTable/components/DraggableColumnHeader.tsx +144 -0
  176. package/src/components/DataTable/components/FilterRow.tsx +9 -3
  177. package/src/components/DataTable/components/PaginationControls.tsx +1 -0
  178. package/src/components/DataTable/components/VirtualizedDataTable.tsx +513 -0
  179. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +14 -68
  180. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +62 -0
  181. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +43 -0
  182. package/src/components/DataTable/core/ActionManager.ts +235 -0
  183. package/src/components/DataTable/core/ColumnManager.ts +205 -0
  184. package/src/components/DataTable/core/DataManager.ts +188 -0
  185. package/src/components/DataTable/core/DataTableContext.tsx +181 -0
  186. package/src/components/DataTable/core/LocalDataAdapter.ts +273 -0
  187. package/src/components/DataTable/core/PluginRegistry.ts +229 -0
  188. package/src/components/DataTable/core/StateManager.ts +311 -0
  189. package/src/components/DataTable/core/interfaces.ts +338 -0
  190. package/src/components/DataTable/styles.ts +27 -6
  191. package/src/components/DataTable/utils/__tests__/columnUtils.test.ts +94 -0
  192. package/src/components/DataTable/utils/columnUtils.ts +40 -0
  193. package/src/components/DataTable/utils/debugTools.ts +609 -0
  194. package/src/components/DataTable/utils/index.ts +1 -0
  195. package/src/components/Dialog/README.md +804 -0
  196. package/src/components/Dialog/utils/__tests__/safeHtml.unit.test.ts +611 -0
  197. package/src/components/Dialog/utils/safeHtml.ts +185 -0
  198. package/src/components/Footer/Footer.test.tsx +1 -1
  199. package/src/components/Form/Form.test.tsx +1 -1
  200. package/src/components/Form/FormErrorSummary.tsx +113 -0
  201. package/src/components/Form/FormFieldset.tsx +127 -0
  202. package/src/components/Form/FormLiveRegion.tsx +198 -0
  203. package/src/components/LoginForm/LoginForm.test.tsx +1 -1
  204. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.performance.test.tsx +76 -10
  205. package/src/components/PaceLoginPage/PaceLoginPage.tsx +1 -1
  206. package/src/components/PasswordReset/PasswordResetForm.test.tsx +597 -0
  207. package/src/components/PasswordReset/PasswordResetForm.tsx +201 -0
  208. package/src/components/PublicLayout/PublicPageDebugger.tsx +104 -0
  209. package/src/components/PublicLayout/PublicPageDiagnostic.tsx +162 -0
  210. package/src/components/PublicLayout/__tests__/PublicPageFooter.test.tsx +1 -1
  211. package/src/components/Select/Select.test.tsx +1 -1
  212. package/src/components/Select/Select.tsx +20 -8
  213. package/src/components/Table/__tests__/Table.test.tsx +1 -1
  214. package/src/components/index.ts +3 -0
  215. package/src/hooks/__tests__/useFileUrl.unit.test.ts +83 -85
  216. package/src/index.ts +4 -0
  217. package/src/rbac/hooks/useCan.test.ts +24 -0
  218. package/src/rbac/hooks/usePermissions.ts +49 -12
  219. package/src/styles/core.css +3 -0
  220. package/src/utils/appConfig.ts +47 -0
  221. package/src/utils/appIdResolver.test.ts +499 -0
  222. package/src/utils/appIdResolver.ts +130 -0
  223. package/src/utils/appNameResolver.simple.test.ts +212 -0
  224. package/src/utils/appNameResolver.test.ts +121 -0
  225. package/src/utils/appNameResolver.ts +191 -0
  226. package/src/utils/audit.ts +127 -0
  227. package/src/utils/auth-utils.ts +96 -0
  228. package/src/utils/bundleAnalysis.ts +129 -0
  229. package/src/utils/cn.ts +7 -0
  230. package/src/utils/debugLogger.ts +67 -0
  231. package/src/utils/deviceFingerprint.ts +215 -0
  232. package/src/utils/dynamicUtils.ts +105 -0
  233. package/src/utils/file-reference.test.ts +788 -0
  234. package/src/utils/file-reference.ts +519 -0
  235. package/src/utils/formatDate.test.ts +237 -0
  236. package/src/utils/formatting.ts +133 -0
  237. package/src/utils/index.ts +7 -0
  238. package/src/utils/lazyLoad.tsx +44 -0
  239. package/src/utils/logger.ts +179 -0
  240. package/src/utils/organisationContext.test.ts +322 -0
  241. package/src/utils/organisationContext.ts +153 -0
  242. package/src/utils/performanceBenchmark.ts +64 -0
  243. package/src/utils/performanceBudgets.ts +110 -0
  244. package/src/utils/permissionTypes.ts +37 -0
  245. package/src/utils/permissionUtils.test.ts +393 -0
  246. package/src/utils/permissionUtils.ts +34 -0
  247. package/src/utils/sanitization.ts +264 -0
  248. package/src/utils/schemaUtils.ts +37 -0
  249. package/src/utils/secureDataAccess.test.ts +711 -0
  250. package/src/utils/secureDataAccess.ts +377 -0
  251. package/src/utils/secureErrors.ts +79 -0
  252. package/src/utils/secureStorage.ts +244 -0
  253. package/src/utils/security.ts +156 -0
  254. package/src/utils/securityMonitor.ts +45 -0
  255. package/src/utils/sessionTracking.ts +126 -0
  256. package/src/utils/validation.ts +111 -0
  257. package/src/utils/validationUtils.ts +120 -0
  258. package/src/validation/index.ts +2 -2
  259. package/dist/chunk-444EZN6N.js.map +0 -1
  260. package/dist/chunk-APIBCTL2.js +0 -670
  261. package/dist/chunk-APIBCTL2.js.map +0 -1
  262. package/dist/chunk-HJGGOMQ6.js.map +0 -1
  263. package/dist/chunk-K2WWTH7O.js +0 -94
  264. package/dist/chunk-K2WWTH7O.js.map +0 -1
  265. package/dist/chunk-L6PGMCMD.js.map +0 -1
  266. package/dist/chunk-LMC26NLJ.js +0 -84
  267. package/dist/chunk-LMC26NLJ.js.map +0 -1
  268. package/dist/chunk-NOHEVYVX.js.map +0 -1
  269. package/dist/chunk-TVYPTYOY.js.map +0 -1
  270. package/dist/validation-8npbysjg.d.ts +0 -177
  271. /package/dist/{DataTable-CYOHOX3O.js.map → DataTable-JXFCA2BJ.js.map} +0 -0
  272. /package/dist/{UnifiedAuthProvider-5E5TUNMS.js.map → UnifiedAuthProvider-XIQQ7LVU.js.map} +0 -0
  273. /package/dist/{chunk-YLKIDTUK.js.map → chunk-22WKWKRX.js.map} +0 -0
  274. /package/dist/{chunk-FHWWBIHA.js.map → chunk-6DXZ6V5Q.js.map} +0 -0
  275. /package/dist/{chunk-2TWNJ46Y.js.map → chunk-6LAAY47Q.js.map} +0 -0
  276. /package/dist/{chunk-XARJS7CD.js.map → chunk-INQLMHPF.js.map} +0 -0
  277. /package/dist/{chunk-SL2YQDR6.js.map → chunk-MA6EPSGZ.js.map} +0 -0
  278. /package/dist/{chunk-5DPZ5EAT.js.map → chunk-OWAG3GSU.js.map} +0 -0
  279. /package/dist/{chunk-LTV3XIJJ.js.map → chunk-T6JN6LH6.js.map} +0 -0
  280. /package/examples/{components → components 2}/DataTable/HierarchicalActionsExample.tsx +0 -0
  281. /package/examples/{components → components 2}/DataTable/HierarchicalExample.tsx +0 -0
  282. /package/examples/{components → components 2}/DataTable/InitialPageSizeExample.tsx +0 -0
  283. /package/examples/{components → components 2}/DataTable/PerformanceExample.tsx +0 -0
  284. /package/examples/{components → components 2}/DataTable/index.ts +0 -0
  285. /package/examples/{components → components 2}/Dialog/BasicHtmlTest.tsx +0 -0
  286. /package/examples/{components → components 2}/Dialog/DebugHtmlExample.tsx +0 -0
  287. /package/examples/{components → components 2}/Dialog/HtmlDialogExample.tsx +0 -0
  288. /package/examples/{components → components 2}/Dialog/ScrollableDialogExample.tsx +0 -0
  289. /package/examples/{components → components 2}/Dialog/SimpleHtmlTest.tsx +0 -0
  290. /package/examples/{components → components 2}/Dialog/SmartDialogExample.tsx +0 -0
  291. /package/examples/{components → components 2}/Dialog/index.ts +0 -0
  292. /package/examples/{components → components 2}/index.ts +0 -0
@@ -0,0 +1,151 @@
1
+ /**
2
+ * @file Permission System Example
3
+ * @package @jmruthers/pace-core
4
+ * @module Examples/RBAC/PermissionExample
5
+ * @since 0.4.0
6
+ *
7
+ * Example component demonstrating the hybrid permission system
8
+ * that supports both direct app access and event-based permissions.
9
+ */
10
+
11
+ import React from 'react';
12
+ import { useUnifiedAuth } from '../../src/providers';
13
+ import { useAppConfig } from '../../src/hooks';
14
+ import { AccessLevel } from '../../src/types';
15
+
16
+ export function PermissionExample() {
17
+ const {
18
+ user,
19
+ isAuthenticated,
20
+ hasPermission,
21
+ hasAccessLevel,
22
+ accessLevel,
23
+ selectedEventId,
24
+ setSelectedEventId
25
+ } = useUnifiedAuth();
26
+
27
+ const { supportsDirectAccess, requiresEvent, isLoading, appName } = useAppConfig();
28
+
29
+ if (!isAuthenticated) {
30
+ return <div>Please log in to see permissions</div>;
31
+ }
32
+
33
+ if (isLoading) {
34
+ return <div>Loading app configuration...</div>;
35
+ }
36
+
37
+ return (
38
+ <div className="p-6 max-w-2xl">
39
+ <h2>Permission System Example</h2>
40
+
41
+ {/* App Configuration Info */}
42
+ <div className="mb-6 p-4 bg-sec-100 rounded-lg">
43
+ <h3>App Configuration: {appName}</h3>
44
+ <div className="space-y-1">
45
+ <div>Supports Direct Access: {supportsDirectAccess ? '✅' : '❌'}</div>
46
+ <div>Requires Event: {requiresEvent ? '✅' : '❌'}</div>
47
+ <div>Current Access Level: {accessLevel}</div>
48
+ </div>
49
+ </div>
50
+
51
+ {/* Event Selection */}
52
+ {requiresEvent && (
53
+ <div className="mb-6 p-4 border rounded-lg">
54
+ <h3>Event Context</h3>
55
+ <div className="space-y-2">
56
+ <div>Selected Event: {selectedEventId || 'None'}</div>
57
+ <div className="space-x-2">
58
+ <button
59
+ onClick={() => setSelectedEventId('event-123')}
60
+ className="px-3 py-1 bg-main-500 text-main-50 rounded"
61
+ >
62
+ Select Event 123
63
+ </button>
64
+ <button
65
+ onClick={() => setSelectedEventId(null)}
66
+ className="px-3 py-1 bg-sec-500 text-main-50 rounded"
67
+ >
68
+ Clear Event
69
+ </button>
70
+ </div>
71
+ </div>
72
+ </div>
73
+ )}
74
+
75
+ {/* Permission Examples */}
76
+ <div className="space-y-4">
77
+ <h3>Permission Examples</h3>
78
+
79
+ <div className="grid gap-4 md:grid-cols-2">
80
+ {/* Basic Permissions */}
81
+ <div className="p-4 border rounded-lg">
82
+ <h4>Basic Permissions</h4>
83
+ <div className="space-y-1 text-sm">
84
+ <div>Can Read: {hasPermission('app:read') ? '✅' : '❌'}</div>
85
+ <div>Can Write: {hasPermission('app:write') ? '✅' : '❌'}</div>
86
+ <div>Can Delete: {hasPermission('app:delete') ? '✅' : '❌'}</div>
87
+ </div>
88
+ </div>
89
+
90
+ {/* Access Level Checks */}
91
+ <div className="p-4 border rounded-lg">
92
+ <h4>Access Level Checks</h4>
93
+ <div className="space-y-1 text-sm">
94
+ <div>Is Editor+: {hasAccessLevel(AccessLevel.EDITOR) ? '✅' : '❌'}</div>
95
+ <div>Is Planner+: {hasAccessLevel(AccessLevel.PLANNER) ? '✅' : '❌'}</div>
96
+ <div>Is Admin: {hasAccessLevel(AccessLevel.ADMIN) ? '✅' : '❌'}</div>
97
+ </div>
98
+ </div>
99
+ </div>
100
+
101
+ {/* Conditional Rendering Examples */}
102
+ <div className="p-4 border rounded-lg">
103
+ <h4>Conditional UI Elements</h4>
104
+ <div className="space-y-2">
105
+ {hasPermission('app:read') && (
106
+ <div className="p-2 bg-main-100 text-main-800 rounded">
107
+ ✅ You can see this because you have read permission
108
+ </div>
109
+ )}
110
+
111
+ {hasPermission('app:write') && (
112
+ <button className="px-4 py-2 bg-main-500 text-main-50 rounded">
113
+ Edit (Available with write permission)
114
+ </button>
115
+ )}
116
+
117
+ {hasAccessLevel(AccessLevel.ADMIN) && (
118
+ <div className="p-2 bg-acc-100 text-acc-800 rounded">
119
+ 🔒 Admin-only content visible
120
+ </div>
121
+ )}
122
+
123
+ {!hasPermission('app:delete') && (
124
+ <div className="p-2 bg-acc-100 text-acc-800 rounded">
125
+ ⚠️ Delete functionality not available for your access level
126
+ </div>
127
+ )}
128
+ </div>
129
+ </div>
130
+
131
+ {/* Status Summary */}
132
+ <div className="p-4 bg-main-50 rounded-lg">
133
+ <h4>Current Status</h4>
134
+ <div className="text-sm space-y-1">
135
+ <div>User: {user?.email}</div>
136
+ <div>App: {appName}</div>
137
+ <div>Event: {selectedEventId || 'Direct Access'}</div>
138
+ <div>
139
+ Permission Model: {
140
+ selectedEventId ? 'Event-based' :
141
+ supportsDirectAccess ? 'Direct Access' :
142
+ 'No Access (requires event)'
143
+ }
144
+ </div>
145
+ </div>
146
+ </div>
147
+ </div>
148
+ </div>
149
+ );
150
+ }
151
+
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @file RBAC Examples
3
+ * @package @jmruthers/pace-core
4
+ * @module Examples/RBAC
5
+ * @since 2.0.0
6
+ *
7
+ * RBAC and permission-related examples
8
+ */
9
+
10
+ export { EventBasedApp } from './EventBasedApp';
11
+ export { CompleteRBACExample } from './CompleteRBACExample';
12
+ export { PermissionExample } from './PermissionExample';
13
+
@@ -0,0 +1,301 @@
1
+ /**
2
+ * @file Correct Public Page Implementation
3
+ * @package @jmruthers/pace-core
4
+ * @module Examples/PublicPages
5
+ * @since 1.0.0
6
+ *
7
+ * This example shows the CORRECT way to implement public pages
8
+ * that are completely isolated from the authentication context.
9
+ *
10
+ * CRITICAL: Public pages MUST be completely separate from the main app's
11
+ * authentication context. They cannot be rendered inside the same component
12
+ * tree as UnifiedAuthProvider, OrganisationProvider, or EventProvider.
13
+ */
14
+
15
+ import React from 'react';
16
+ import { BrowserRouter, Routes, Route } from 'react-router-dom';
17
+ import {
18
+ PublicPageProvider,
19
+ PublicPageLayout,
20
+ PublicPageHeader,
21
+ PublicPageFooter,
22
+ EventLogo,
23
+ usePublicEvent,
24
+ usePublicRouteParams,
25
+ PublicLoadingSpinner
26
+ } from '../../src';
27
+
28
+ /**
29
+ * MAIN APPLICATION - This is your main app with authentication
30
+ *
31
+ * This should be completely separate from public pages.
32
+ * All authenticated routes go here.
33
+ */
34
+ function MainApp() {
35
+ return (
36
+ <div>
37
+ <h1>Main Application (Requires Authentication)</h1>
38
+ <p>This is your main app with all the authenticated features.</p>
39
+ {/* Your main app content here */}
40
+ </div>
41
+ );
42
+ }
43
+
44
+ /**
45
+ * PUBLIC PAGE APPLICATION - This is completely separate
46
+ *
47
+ * This handles ALL public pages and is completely isolated
48
+ * from the main application's authentication context.
49
+ */
50
+ function PublicPageApp() {
51
+ return (
52
+ <PublicPageProvider>
53
+ <Routes>
54
+ {/* All public routes go here */}
55
+ <Route path="/events/:eventCode/recipe-grid-report" element={<PublicRecipeGridReportPage />} />
56
+ <Route path="/events/:eventCode" element={<PublicEventPage />} />
57
+ <Route path="/public-info/:pageId" element={<PublicInfoPage />} />
58
+ </Routes>
59
+ </PublicPageProvider>
60
+ );
61
+ }
62
+
63
+ /**
64
+ * ROOT APPLICATION - This decides which app to render
65
+ *
66
+ * This is the key: public pages and authenticated pages
67
+ * are completely separate applications.
68
+ */
69
+ function RootApp() {
70
+ return (
71
+ <BrowserRouter>
72
+ <Routes>
73
+ {/* Public routes - NO authentication context */}
74
+ <Route path="/events/*" element={<PublicPageApp />} />
75
+ <Route path="/public-info/*" element={<PublicPageApp />} />
76
+
77
+ {/* Authenticated routes - WITH authentication context */}
78
+ <Route path="/*" element={<MainApp />} />
79
+ </Routes>
80
+ </BrowserRouter>
81
+ );
82
+ }
83
+
84
+ /**
85
+ * Public Recipe Grid Report Page
86
+ *
87
+ * This demonstrates the correct usage pattern.
88
+ * Notice: NO authentication context is triggered.
89
+ */
90
+ function PublicRecipeGridReportPage() {
91
+ // Step 1: Extract event code from URL
92
+ const { eventCode } = usePublicRouteParams({ fetchEventData: false });
93
+
94
+ // Step 2: Fetch event data
95
+ const { event, isLoading, error, refetch } = usePublicEvent(eventCode || '');
96
+
97
+ // Step 3: Handle loading state
98
+ if (isLoading) {
99
+ return (
100
+ <PublicLoadingSpinner
101
+ message="Loading recipe grid report..."
102
+ />
103
+ );
104
+ }
105
+
106
+ // Step 4: Handle error state
107
+ if (error) {
108
+ return (
109
+ <div className="min-h-screen bg-main-50 flex items-center justify-center">
110
+ <div className="max-w-md mx-auto text-center px-4">
111
+ <div className="mb-6">
112
+ <div className="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-acc-100 mb-4">
113
+ <svg className="h-6 w-6 text-acc-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
114
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z" />
115
+ </svg>
116
+ </div>
117
+ <h1 className="text-2xl font-bold text-sec-900 mb-2">
118
+ Recipe Grid Report Not Found
119
+ </h1>
120
+ <p className="text-sec-600 mb-6">
121
+ The event code "{eventCode}" is invalid or the recipe grid report is not available for public viewing.
122
+ </p>
123
+ <button
124
+ onClick={refetch}
125
+ className="px-4 py-2 bg-main-600 text-main-50 rounded-md hover:bg-main-700 transition-colors"
126
+ >
127
+ Try Again
128
+ </button>
129
+ </div>
130
+ </div>
131
+ </div>
132
+ );
133
+ }
134
+
135
+ // Step 5: Handle missing event
136
+ if (!event) {
137
+ return (
138
+ <div className="min-h-screen bg-main-50 flex items-center justify-center">
139
+ <div className="max-w-md mx-auto text-center px-4">
140
+ <h1 className="text-2xl font-bold text-sec-900 mb-4">
141
+ Recipe Grid Report Not Available
142
+ </h1>
143
+ <p className="text-sec-600 mb-6">
144
+ This recipe grid report is not available for public viewing.
145
+ </p>
146
+ <button
147
+ onClick={refetch}
148
+ className="px-4 py-2 bg-main-600 text-main-50 rounded-md hover:bg-main-700 transition-colors"
149
+ >
150
+ Try Again
151
+ </button>
152
+ </div>
153
+ </div>
154
+ );
155
+ }
156
+
157
+ // Step 6: Render the public page
158
+ return (
159
+ <PublicPageLayout eventCode={eventCode || ''} event={event}>
160
+ <PublicPageHeader
161
+ event={event}
162
+ eventCode={eventCode || ''}
163
+ title="Recipe Grid Report"
164
+ description="Public recipe grid report for this event"
165
+ />
166
+
167
+ <main className="max-w-6xl mx-auto px-4 py-8">
168
+ {/* Recipe Grid Report Content */}
169
+ <div className="mb-12">
170
+ <div className="bg-main-50 border border-main-200 rounded-lg p-6">
171
+ <h3 className="font-semibold text-main-900 mb-2">Recipe Grid Report</h3>
172
+ <p className="text-main-800">
173
+ This is where your recipe grid report content would go.
174
+ The public page is now working correctly without authentication context conflicts.
175
+ </p>
176
+ <div className="mt-4 text-sm text-main-700">
177
+ <p><strong>Event Code:</strong> {eventCode}</p>
178
+ <p><strong>Event ID:</strong> {event.event_id}</p>
179
+ <p><strong>Event Name:</strong> {event.event_name}</p>
180
+ </div>
181
+ </div>
182
+ </div>
183
+
184
+ {/* Event Information */}
185
+ <div className="grid grid-cols-1 lg:grid-cols-3 gap-8 mb-12">
186
+ <div className="lg:col-span-2 space-y-6">
187
+ <div>
188
+ <h2 className="text-2xl font-bold text-sec-900 mb-4">Event Information</h2>
189
+ <div className="bg-sec-50 rounded-lg p-6 space-y-4">
190
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
191
+ <div>
192
+ <h3 className="font-semibold text-sec-700">Date</h3>
193
+ <p className="text-sec-900">
194
+ {event.event_date ? new Date(event.event_date).toLocaleDateString('en-AU', {
195
+ weekday: 'long',
196
+ year: 'numeric',
197
+ month: 'long',
198
+ day: 'numeric'
199
+ }) : 'TBA'}
200
+ </p>
201
+ </div>
202
+ <div>
203
+ <h3 className="font-semibold text-sec-700">Venue</h3>
204
+ <p className="text-sec-900">{event.event_venue || 'TBA'}</p>
205
+ </div>
206
+ <div>
207
+ <h3 className="font-semibold text-sec-700">Participants</h3>
208
+ <p className="text-sec-900">{event.event_participants || 'TBA'}</p>
209
+ </div>
210
+ <div>
211
+ <h3 className="font-semibold text-sec-700">Event Code</h3>
212
+ <p className="text-sec-900 font-mono">{event.event_code}</p>
213
+ </div>
214
+ </div>
215
+ </div>
216
+ </div>
217
+ </div>
218
+
219
+ {/* Event Logo */}
220
+ <div className="flex justify-center lg:justify-start">
221
+ <div className="text-center">
222
+ <EventLogo
223
+ eventId={event.event_id}
224
+ eventName={event.event_name}
225
+ organisationId={event.organisation_id}
226
+ size="2xl"
227
+ className="rounded-lg shadow-lg"
228
+ />
229
+ <p className="mt-4 text-sm text-sec-600">Event Logo</p>
230
+ </div>
231
+ </div>
232
+ </div>
233
+ </main>
234
+
235
+ <PublicPageFooter event={event} />
236
+ </PublicPageLayout>
237
+ );
238
+ }
239
+
240
+ /**
241
+ * Generic public event page
242
+ */
243
+ function PublicEventPage() {
244
+ const { eventCode } = usePublicRouteParams({ fetchEventData: false });
245
+ const { event, isLoading, error, refetch } = usePublicEvent(eventCode || '');
246
+
247
+ if (isLoading) return <PublicLoadingSpinner message="Loading event..." />;
248
+ if (error) return <div>Error: {error.message}</div>;
249
+ if (!event) return <div>Event not found</div>;
250
+
251
+ return (
252
+ <PublicPageLayout eventCode={eventCode || ''} event={event}>
253
+ <PublicPageHeader
254
+ event={event}
255
+ eventCode={eventCode || ''}
256
+ title="Event Details"
257
+ description="Public information about this event"
258
+ />
259
+
260
+ <main className="max-w-4xl mx-auto px-4 py-6">
261
+ <div className="text-center mb-6">
262
+ <EventLogo
263
+ eventId={event.event_id}
264
+ eventName={event.event_name}
265
+ organisationId={event.organisation_id}
266
+ size="xl"
267
+ className="mx-auto mb-4"
268
+ />
269
+ <h1 className="text-2xl font-bold text-sec-900">{event.event_name}</h1>
270
+ {event.event_date && (
271
+ <p className="text-sec-600 mt-2">
272
+ {new Date(event.event_date).toLocaleDateString('en-AU')}
273
+ </p>
274
+ )}
275
+ </div>
276
+ </main>
277
+
278
+ <PublicPageFooter event={event} />
279
+ </PublicPageLayout>
280
+ );
281
+ }
282
+
283
+ /**
284
+ * Generic public info page
285
+ */
286
+ function PublicInfoPage() {
287
+ return (
288
+ <div className="min-h-screen bg-main-50 flex items-center justify-center">
289
+ <div className="max-w-md mx-auto text-center px-4">
290
+ <h1 className="text-2xl font-bold text-sec-900 mb-4">
291
+ Public Information Page
292
+ </h1>
293
+ <p className="text-sec-600">
294
+ This is a public information page that doesn't require authentication.
295
+ </p>
296
+ </div>
297
+ </div>
298
+ );
299
+ }
300
+
301
+ export default RootApp;