@jmruthers/pace-core 0.5.110 → 0.5.112

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 (236) hide show
  1. package/dist/{AuthService-DrHrvXNZ.d.ts → AuthService-CVgsgtaZ.d.ts} +8 -0
  2. package/dist/{DataTable-D3BK2FCN.js → DataTable-3D3BUZDV.js} +8 -8
  3. package/dist/{UnifiedAuthProvider-A7I23UCN.js → UnifiedAuthProvider-KZZUO27W.js} +3 -3
  4. package/dist/{api-PIE4JRFS.js → api-QPMBZZUZ.js} +5 -3
  5. package/dist/{audit-65VNHEV2.js → audit-H4YJJF7R.js} +2 -2
  6. package/dist/{chunk-Q7APDV6H.js → chunk-3OGQLOJM.js} +23 -7
  7. package/dist/chunk-3OGQLOJM.js.map +1 -0
  8. package/dist/{chunk-EYSXQ756.js → chunk-7H75SHXZ.js} +2 -2
  9. package/dist/{chunk-D6MEKC27.js → chunk-BUN7NMV7.js} +2 -2
  10. package/dist/{chunk-AWK2FAUN.js → chunk-C5RN4TE5.js} +7 -7
  11. package/dist/{chunk-3J5N2T2N.js → chunk-EKVVTPIF.js} +183 -127
  12. package/dist/chunk-EKVVTPIF.js.map +1 -0
  13. package/dist/{chunk-2W4WKJVF.js → chunk-F6QB26OS.js} +290 -255
  14. package/dist/chunk-F6QB26OS.js.map +1 -0
  15. package/dist/{chunk-HADXAZT3.js → chunk-I7JC7PTJ.js} +54 -92
  16. package/dist/chunk-I7JC7PTJ.js.map +1 -0
  17. package/dist/{chunk-EZ64QG2I.js → chunk-L36JW4KV.js} +2 -2
  18. package/dist/{chunk-7GBEBJLR.js → chunk-MNSGWRPB.js} +45 -37
  19. package/dist/chunk-MNSGWRPB.js.map +1 -0
  20. package/dist/{chunk-YFMENCR4.js → chunk-NEONKMTU.js} +3 -3
  21. package/dist/{chunk-AUXS7XSO.js → chunk-OO3V7W4H.js} +35 -11
  22. package/dist/chunk-OO3V7W4H.js.map +1 -0
  23. package/dist/{chunk-XRSP3H52.js → chunk-TAJRS6YB.js} +57 -23
  24. package/dist/chunk-TAJRS6YB.js.map +1 -0
  25. package/dist/{chunk-HGZSO43Y.js → chunk-WMPZY26G.js} +8 -4
  26. package/dist/{chunk-HGZSO43Y.js.map → chunk-WMPZY26G.js.map} +1 -1
  27. package/dist/components.js +10 -10
  28. package/dist/hooks.d.ts +11 -1
  29. package/dist/hooks.js +9 -7
  30. package/dist/hooks.js.map +1 -1
  31. package/dist/index.d.ts +2 -2
  32. package/dist/index.js +13 -13
  33. package/dist/providers.d.ts +2 -2
  34. package/dist/providers.js +2 -2
  35. package/dist/rbac/index.d.ts +13 -8
  36. package/dist/rbac/index.js +9 -9
  37. package/dist/utils.js +1 -1
  38. package/docs/api/classes/ColumnFactory.md +1 -1
  39. package/docs/api/classes/ErrorBoundary.md +1 -1
  40. package/docs/api/classes/InvalidScopeError.md +4 -4
  41. package/docs/api/classes/MissingUserContextError.md +4 -4
  42. package/docs/api/classes/OrganisationContextRequiredError.md +4 -4
  43. package/docs/api/classes/PermissionDeniedError.md +4 -4
  44. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  45. package/docs/api/classes/RBACAuditManager.md +8 -8
  46. package/docs/api/classes/RBACCache.md +8 -8
  47. package/docs/api/classes/RBACEngine.md +4 -4
  48. package/docs/api/classes/RBACError.md +4 -4
  49. package/docs/api/classes/RBACNotInitializedError.md +4 -4
  50. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  51. package/docs/api/classes/StorageUtils.md +1 -1
  52. package/docs/api/enums/FileCategory.md +1 -1
  53. package/docs/api/interfaces/AggregateConfig.md +1 -1
  54. package/docs/api/interfaces/ButtonProps.md +1 -1
  55. package/docs/api/interfaces/CardProps.md +1 -1
  56. package/docs/api/interfaces/ColorPalette.md +1 -1
  57. package/docs/api/interfaces/ColorShade.md +1 -1
  58. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  59. package/docs/api/interfaces/DataRecord.md +1 -1
  60. package/docs/api/interfaces/DataTableAction.md +1 -1
  61. package/docs/api/interfaces/DataTableColumn.md +1 -1
  62. package/docs/api/interfaces/DataTableProps.md +1 -1
  63. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  64. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  65. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  66. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  67. package/docs/api/interfaces/FileMetadata.md +1 -1
  68. package/docs/api/interfaces/FileReference.md +1 -1
  69. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  70. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  71. package/docs/api/interfaces/FileUploadProps.md +1 -1
  72. package/docs/api/interfaces/FooterProps.md +1 -1
  73. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  74. package/docs/api/interfaces/InputProps.md +1 -1
  75. package/docs/api/interfaces/LabelProps.md +1 -1
  76. package/docs/api/interfaces/LoginFormProps.md +1 -1
  77. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  78. package/docs/api/interfaces/NavigationContextType.md +1 -1
  79. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  80. package/docs/api/interfaces/NavigationItem.md +1 -1
  81. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  82. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  83. package/docs/api/interfaces/Organisation.md +1 -1
  84. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  85. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  86. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  87. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  88. package/docs/api/interfaces/PaceAppLayoutProps.md +27 -27
  89. package/docs/api/interfaces/PaceLoginPageProps.md +4 -4
  90. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  91. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  92. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  93. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  94. package/docs/api/interfaces/PaletteData.md +1 -1
  95. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  96. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  97. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  98. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  99. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  100. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  101. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  102. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  103. package/docs/api/interfaces/RBACConfig.md +1 -1
  104. package/docs/api/interfaces/RBACLogger.md +1 -1
  105. package/docs/api/interfaces/RoleBasedRouterContextType.md +8 -8
  106. package/docs/api/interfaces/RoleBasedRouterProps.md +10 -10
  107. package/docs/api/interfaces/RouteAccessRecord.md +10 -10
  108. package/docs/api/interfaces/RouteConfig.md +19 -6
  109. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  110. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  111. package/docs/api/interfaces/StorageConfig.md +1 -1
  112. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  113. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  114. package/docs/api/interfaces/StorageListOptions.md +1 -1
  115. package/docs/api/interfaces/StorageListResult.md +1 -1
  116. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  117. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  118. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  119. package/docs/api/interfaces/StyleImport.md +1 -1
  120. package/docs/api/interfaces/SwitchProps.md +1 -1
  121. package/docs/api/interfaces/ToastActionElement.md +1 -1
  122. package/docs/api/interfaces/ToastProps.md +1 -1
  123. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  124. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  125. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  126. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  127. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  128. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  129. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
  130. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  131. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  132. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  133. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  134. package/docs/api/interfaces/UserEventAccess.md +1 -1
  135. package/docs/api/interfaces/UserMenuProps.md +1 -1
  136. package/docs/api/interfaces/UserProfile.md +1 -1
  137. package/docs/api/modules.md +36 -36
  138. package/docs/api-reference/hooks.md +8 -4
  139. package/docs/architecture/rpc-function-standards.md +3 -1
  140. package/docs/best-practices/common-patterns.md +3 -3
  141. package/docs/best-practices/deployment.md +10 -4
  142. package/docs/best-practices/performance.md +11 -3
  143. package/docs/core-concepts/organisations.md +8 -8
  144. package/docs/core-concepts/permissions.md +133 -72
  145. package/docs/migration/rbac-migration.md +65 -66
  146. package/docs/rbac/advanced-patterns.md +15 -22
  147. package/docs/rbac/examples.md +12 -12
  148. package/docs/rbac/getting-started.md +3 -3
  149. package/docs/rbac/troubleshooting.md +2 -1
  150. package/package.json +1 -1
  151. package/src/components/DataTable/DataTable.test.tsx +405 -154
  152. package/src/components/DataTable/components/DataTableCore.tsx +6 -1
  153. package/src/components/DataTable/components/__tests__/ActionButtons.test.tsx +913 -0
  154. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +609 -0
  155. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +434 -0
  156. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +120 -0
  157. package/src/components/DataTable/components/__tests__/PaginationControls.test.tsx +519 -0
  158. package/src/components/DataTable/examples/__tests__/HierarchicalActionsExample.test.tsx +316 -0
  159. package/src/components/DataTable/examples/__tests__/InitialPageSizeExample.test.tsx +211 -0
  160. package/src/components/EventSelector/EventSelector.tsx +32 -2
  161. package/src/components/FileUpload/FileUpload.tsx +2 -8
  162. package/src/components/NavigationMenu/NavigationMenu.test.tsx +56 -8
  163. package/src/components/NavigationMenu/NavigationMenu.tsx +75 -12
  164. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +193 -63
  165. package/src/components/PaceAppLayout/PaceAppLayout.tsx +102 -135
  166. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.accessibility.test.tsx +41 -2
  167. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.integration.test.tsx +61 -6
  168. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.performance.test.tsx +71 -21
  169. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +113 -41
  170. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.unit.test.tsx +155 -45
  171. package/src/components/PaceLoginPage/PaceLoginPage.tsx +30 -1
  172. package/src/hooks/__tests__/usePermissionCache.simple.test.ts +63 -5
  173. package/src/hooks/__tests__/usePermissionCache.unit.test.ts +156 -72
  174. package/src/hooks/__tests__/useRBAC.unit.test.ts +4 -38
  175. package/src/hooks/index.ts +1 -1
  176. package/src/hooks/useFileDisplay.ts +51 -0
  177. package/src/hooks/usePermissionCache.test.ts +112 -68
  178. package/src/hooks/usePermissionCache.ts +55 -15
  179. package/src/rbac/README.md +81 -39
  180. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +3 -3
  181. package/src/rbac/__tests__/engine.comprehensive.test.ts +15 -6
  182. package/src/rbac/__tests__/rbac-core.test.tsx +1 -1
  183. package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +57 -4
  184. package/src/rbac/__tests__/rbac-engine-simplified.test.ts +3 -2
  185. package/src/rbac/adapters.tsx +4 -4
  186. package/src/rbac/api.test.ts +37 -13
  187. package/src/rbac/api.ts +25 -8
  188. package/src/rbac/audit-enhanced.ts +14 -2
  189. package/src/rbac/audit.test.ts +18 -8
  190. package/src/rbac/audit.ts +25 -6
  191. package/src/rbac/cache.test.ts +12 -0
  192. package/src/rbac/cache.ts +29 -9
  193. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +1 -1
  194. package/src/rbac/components/NavigationGuard.tsx +14 -14
  195. package/src/rbac/components/NavigationProvider.test.tsx +1 -1
  196. package/src/rbac/components/PagePermissionGuard.tsx +4 -3
  197. package/src/rbac/components/PagePermissionProvider.test.tsx +1 -1
  198. package/src/rbac/components/PermissionEnforcer.tsx +19 -15
  199. package/src/rbac/components/RoleBasedRouter.tsx +16 -9
  200. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +123 -107
  201. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +1 -1
  202. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +121 -103
  203. package/src/rbac/docs/event-based-apps.md +6 -6
  204. package/src/rbac/engine.ts +12 -2
  205. package/src/rbac/hooks/useCan.test.ts +29 -2
  206. package/src/rbac/hooks/usePermissions.test.ts +25 -25
  207. package/src/rbac/hooks/usePermissions.ts +65 -25
  208. package/src/rbac/hooks/useRBAC.simple.test.ts +1 -8
  209. package/src/rbac/hooks/useRBAC.test.ts +3 -40
  210. package/src/rbac/hooks/useRBAC.ts +0 -55
  211. package/src/rbac/hooks/useResolvedScope.ts +23 -31
  212. package/src/rbac/permissions.test.ts +11 -7
  213. package/src/rbac/security.test.ts +2 -2
  214. package/src/rbac/security.ts +22 -7
  215. package/src/rbac/types.test.ts +2 -2
  216. package/src/rbac/types.ts +1 -2
  217. package/src/services/EventService.ts +42 -13
  218. package/src/services/__tests__/EventService.test.ts +25 -4
  219. package/src/services/interfaces/IEventService.ts +1 -0
  220. package/src/utils/file-reference.ts +9 -0
  221. package/dist/chunk-2W4WKJVF.js.map +0 -1
  222. package/dist/chunk-3J5N2T2N.js.map +0 -1
  223. package/dist/chunk-7GBEBJLR.js.map +0 -1
  224. package/dist/chunk-AUXS7XSO.js.map +0 -1
  225. package/dist/chunk-HADXAZT3.js.map +0 -1
  226. package/dist/chunk-Q7APDV6H.js.map +0 -1
  227. package/dist/chunk-XRSP3H52.js.map +0 -1
  228. /package/dist/{DataTable-D3BK2FCN.js.map → DataTable-3D3BUZDV.js.map} +0 -0
  229. /package/dist/{UnifiedAuthProvider-A7I23UCN.js.map → UnifiedAuthProvider-KZZUO27W.js.map} +0 -0
  230. /package/dist/{api-PIE4JRFS.js.map → api-QPMBZZUZ.js.map} +0 -0
  231. /package/dist/{audit-65VNHEV2.js.map → audit-H4YJJF7R.js.map} +0 -0
  232. /package/dist/{chunk-EYSXQ756.js.map → chunk-7H75SHXZ.js.map} +0 -0
  233. /package/dist/{chunk-D6MEKC27.js.map → chunk-BUN7NMV7.js.map} +0 -0
  234. /package/dist/{chunk-AWK2FAUN.js.map → chunk-C5RN4TE5.js.map} +0 -0
  235. /package/dist/{chunk-EZ64QG2I.js.map → chunk-L36JW4KV.js.map} +0 -0
  236. /package/dist/{chunk-YFMENCR4.js.map → chunk-NEONKMTU.js.map} +0 -0
@@ -25,16 +25,16 @@ import {
25
25
  SelectSeparator,
26
26
  SelectTrigger,
27
27
  SelectValue
28
- } from "./chunk-HGZSO43Y.js";
28
+ } from "./chunk-WMPZY26G.js";
29
29
  import {
30
+ useCan,
30
31
  usePermissions,
31
32
  useRBAC,
32
33
  useResolvedScope
33
- } from "./chunk-HADXAZT3.js";
34
+ } from "./chunk-I7JC7PTJ.js";
34
35
  import {
35
- isPermitted,
36
36
  isSuperAdmin
37
- } from "./chunk-XRSP3H52.js";
37
+ } from "./chunk-TAJRS6YB.js";
38
38
  import {
39
39
  OrganisationProvider_exports,
40
40
  PublicErrorBoundary,
@@ -49,18 +49,19 @@ import {
49
49
  useIsPublicPage,
50
50
  usePublicFileDisplay,
51
51
  usePublicPageContext
52
- } from "./chunk-2W4WKJVF.js";
52
+ } from "./chunk-F6QB26OS.js";
53
53
  import {
54
54
  useToast
55
55
  } from "./chunk-4OX5PXHX.js";
56
56
  import {
57
+ init_useOrganisations,
57
58
  useEvents,
58
59
  useOrganisations
59
- } from "./chunk-EZ64QG2I.js";
60
+ } from "./chunk-L36JW4KV.js";
60
61
  import {
61
62
  UnifiedAuthProvider_exports,
62
63
  init_UnifiedAuthProvider as init_UnifiedAuthProvider2
63
- } from "./chunk-EYSXQ756.js";
64
+ } from "./chunk-7H75SHXZ.js";
64
65
  import {
65
66
  EventServiceContext,
66
67
  EventServiceProvider,
@@ -70,7 +71,7 @@ import {
70
71
  useEventService,
71
72
  useSessionRestoration,
72
73
  useUnifiedAuth
73
- } from "./chunk-AUXS7XSO.js";
74
+ } from "./chunk-OO3V7W4H.js";
74
75
  import {
75
76
  LoadingSpinner
76
77
  } from "./chunk-CDQ3PX7L.js";
@@ -584,7 +585,23 @@ function EventSelector({
584
585
  return [...events].sort((a, b) => getTime(b) - getTime(a));
585
586
  }, [events]);
586
587
  useEffect(() => {
587
- if (!selectedEvent && events.length > 0) {
588
+ if (!selectedEvent && events.length > 0 && !isLoading) {
589
+ const persistedEventId = localStorage.getItem("pace-core-selected-event") || sessionStorage.getItem("pace-core-selected-event");
590
+ if (persistedEventId) {
591
+ const persistedEvent = events.find((e) => e.event_id === persistedEventId);
592
+ if (persistedEvent) {
593
+ console.debug("[EventSelector] Persisted event found in storage but not selected:", persistedEventId);
594
+ return;
595
+ } else {
596
+ localStorage.removeItem("pace-core-selected-event");
597
+ sessionStorage.removeItem("pace-core-selected-event");
598
+ autoSelectEvent();
599
+ }
600
+ } else {
601
+ autoSelectEvent();
602
+ }
603
+ }
604
+ function autoSelectEvent() {
588
605
  const today = /* @__PURE__ */ new Date();
589
606
  const startOfToday = new Date(today.getFullYear(), today.getMonth(), today.getDate()).getTime();
590
607
  const next = [...events].filter((e) => e.event_date && new Date(e.event_date).getTime() >= startOfToday).sort((a, b) => new Date(a.event_date).getTime() - new Date(b.event_date).getTime())[0];
@@ -604,7 +621,7 @@ function EventSelector({
604
621
  }
605
622
  }
606
623
  }
607
- }, [events, selectedEvent, setSelectedEvent, onEventChange]);
624
+ }, [events, selectedEvent, setSelectedEvent, onEventChange, isLoading]);
608
625
  if (isLoading) {
609
626
  return /* @__PURE__ */ jsxs4("div", { className: `flex items-center gap-2 ${className}`, children: [
610
627
  /* @__PURE__ */ jsx8(LoadingSpinner, { size: "sm" }),
@@ -919,14 +936,50 @@ var NavigationMenu = React9.forwardRef(({
919
936
  selectedOrganisationId: selectedOrganisation?.id || null,
920
937
  selectedEventId: selectedEvent?.event_id || null
921
938
  });
939
+ const stableScopeRef = React9.useRef({
940
+ organisationId: "",
941
+ eventId: void 0,
942
+ appId: void 0
943
+ });
944
+ if (resolvedScope?.organisationId) {
945
+ const newOrgId = resolvedScope.organisationId;
946
+ const newEventId = resolvedScope.eventId;
947
+ const newAppId = resolvedScope.appId;
948
+ if (stableScopeRef.current.organisationId !== newOrgId || stableScopeRef.current.eventId !== newEventId || stableScopeRef.current.appId !== newAppId) {
949
+ stableScopeRef.current = {
950
+ organisationId: newOrgId,
951
+ eventId: newEventId,
952
+ appId: newAppId
953
+ };
954
+ }
955
+ } else if (!resolvedScope) {
956
+ if (stableScopeRef.current.organisationId !== "") {
957
+ stableScopeRef.current = {
958
+ organisationId: "",
959
+ eventId: void 0,
960
+ appId: void 0
961
+ };
962
+ }
963
+ }
964
+ const stableScope = stableScopeRef.current;
922
965
  const userId = authContext?.user?.id || "";
923
- const scope = resolvedScope || { organisationId: "", eventId: void 0, appId: void 0 };
924
- const { permissions: permissionMap, hasAnyPermission, isLoading: permissionsLoading } = usePermissions(
966
+ const { permissions: permissionMap, hasAnyPermission, isLoading: permissionsLoading, error: permissionsError } = usePermissions(
925
967
  userId,
926
- scope
968
+ stableScope
927
969
  );
928
970
  const filteredItems = React9.useMemo(() => {
929
- if (!filterByPermissions || !authContext || !rbacContext || scopeLoading || permissionsLoading || !resolvedScope?.organisationId) {
971
+ if (filterByPermissions) {
972
+ if (!authContext || !rbacContext || scopeLoading || permissionsLoading || !resolvedScope?.organisationId) {
973
+ return [];
974
+ }
975
+ if (permissionsError || !permissionMap || Object.keys(permissionMap).length === 0) {
976
+ console.warn("[NavigationMenu] Permission map is empty or has error - showing no items for security", {
977
+ permissionsError: permissionsError?.message,
978
+ permissionMapSize: permissionMap ? Object.keys(permissionMap).length : 0
979
+ });
980
+ return [];
981
+ }
982
+ } else {
930
983
  return (items || []).filter((item) => !item.meta?.hidden);
931
984
  }
932
985
  const getPageIdFromHref = (href) => {
@@ -990,19 +1043,25 @@ var NavigationMenu = React9.forwardRef(({
990
1043
  }
991
1044
  }
992
1045
  }
993
- if (item.href && !item.permissions && !item.roles && !item.accessLevel) {
1046
+ if (item.href) {
994
1047
  const pageId = item.pageId || getPageIdFromHref(item.href);
995
1048
  if (pageId) {
996
1049
  const pagePermission = `read:page.${pageId}`;
997
- const hasPagePermission = permissionMap["*"] === true || permissionMap[pagePermission] === true;
998
- if (!hasPagePermission) {
1050
+ const isSuperAdmin2 = permissionMap["*"] === true;
1051
+ const hasPagePermission = permissionMap[pagePermission] === true;
1052
+ const finalHasPermission = isSuperAdmin2 || hasPagePermission;
1053
+ if (!finalHasPermission) {
999
1054
  if (auditLog) {
1000
1055
  console.log(`[NavigationMenu] Filtering out navigation item "${item.label}" - no page permission:`, {
1001
1056
  itemId: item.id,
1002
1057
  href: item.href,
1003
1058
  pageId,
1004
1059
  permission: pagePermission,
1005
- hasPermission: hasPagePermission
1060
+ hasPermission: finalHasPermission,
1061
+ isSuperAdmin: isSuperAdmin2,
1062
+ permissionMapValue: permissionMap[pagePermission],
1063
+ permissionMapKeys: Object.keys(permissionMap).slice(0, 10)
1064
+ // Show first 10 keys for debugging
1006
1065
  });
1007
1066
  }
1008
1067
  return false;
@@ -1026,7 +1085,8 @@ var NavigationMenu = React9.forwardRef(({
1026
1085
  children: filteredChildren
1027
1086
  };
1028
1087
  };
1029
- return (items || []).map((item) => filterItem(item)).filter((item) => item !== null);
1088
+ const filtered = (items || []).map((item) => filterItem(item)).filter((item) => item !== null);
1089
+ return filtered;
1030
1090
  }, [
1031
1091
  items,
1032
1092
  filterByPermissions,
@@ -1372,7 +1432,8 @@ Footer.displayName = "Footer";
1372
1432
 
1373
1433
  // src/components/PaceAppLayout/PaceAppLayout.tsx
1374
1434
  init_UnifiedAuthProvider2();
1375
- import { useState as useState5, useEffect as useEffect3, useMemo as useMemo5, useCallback as useCallback3 } from "react";
1435
+ init_useOrganisations();
1436
+ import { useState as useState5, useEffect as useEffect3, useMemo as useMemo5 } from "react";
1376
1437
  import { Outlet, useNavigate, useLocation } from "react-router-dom";
1377
1438
  import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
1378
1439
  var EMPTY_PAGE_ID_MAPPING = {};
@@ -1407,48 +1468,31 @@ function PaceAppLayout({
1407
1468
  onRouteAccessDenied,
1408
1469
  onRouteStrictModeViolation
1409
1470
  }) {
1410
- const { user, signOut, updatePassword } = useUnifiedAuth();
1471
+ const { user, signOut, updatePassword, supabase } = useUnifiedAuth();
1472
+ const { selectedOrganisation } = useOrganisations();
1411
1473
  const navigate = useNavigate();
1412
1474
  const location = useLocation();
1413
- const checkPermission = useCallback3(async (permission, pageId) => {
1414
- try {
1415
- if (!user?.id) return false;
1416
- const scope = {
1417
- organisationId: user.user_metadata?.organisationId || user.app_metadata?.organisationId,
1418
- eventId: user.user_metadata?.eventId || user.app_metadata?.eventId,
1419
- appId: user.user_metadata?.appId || user.app_metadata?.appId
1475
+ let selectedEvent = null;
1476
+ try {
1477
+ const eventsContext = useEvents();
1478
+ selectedEvent = eventsContext.selectedEvent;
1479
+ } catch (error) {
1480
+ }
1481
+ const { resolvedScope } = useResolvedScope({
1482
+ supabase: supabase || null,
1483
+ selectedOrganisationId: selectedOrganisation?.id || null,
1484
+ selectedEventId: selectedEvent?.event_id || null
1485
+ });
1486
+ const scope = useMemo5(() => {
1487
+ if (!resolvedScope?.organisationId) {
1488
+ return {
1489
+ organisationId: selectedOrganisation?.id || "",
1490
+ eventId: selectedEvent?.event_id || void 0,
1491
+ appId: void 0
1420
1492
  };
1421
- try {
1422
- const { isSuperAdmin: isSuperAdmin2 } = await import("./api-PIE4JRFS.js");
1423
- const isSuper = await isSuperAdmin2(user.id);
1424
- if (isSuper) {
1425
- return true;
1426
- }
1427
- } catch (error) {
1428
- if (error && typeof error === "object" && "code" in error && error.code === "RBAC_NOT_INITIALIZED") {
1429
- } else {
1430
- throw error;
1431
- }
1432
- }
1433
- if (!scope.organisationId) {
1434
- console.warn("No organisation context available for permission check, denying access");
1435
- return false;
1436
- }
1437
- const fullPermission = permission.includes(":") ? permission : pageId ? `${permission}:page.${pageId}` : permission;
1438
- return await isPermitted({
1439
- userId: user.id,
1440
- scope,
1441
- permission: fullPermission,
1442
- pageId
1443
- });
1444
- } catch (error) {
1445
- console.error("Permission check failed:", error);
1446
- throw error;
1447
1493
  }
1448
- }, [user?.id]);
1449
- const [hasPermission, setHasPermission] = useState5(null);
1450
- const [isCheckingPermission, setIsCheckingPermission] = useState5(false);
1451
- const [permissionError, setPermissionError] = useState5(null);
1494
+ return resolvedScope;
1495
+ }, [resolvedScope, selectedOrganisation?.id, selectedEvent?.event_id]);
1452
1496
  const defaultNavItems = useMemo5(() => [
1453
1497
  { id: "home", label: "Home", href: "/", icon: "Home" },
1454
1498
  { id: "dashboard", label: "Dashboard", href: "/dashboard", icon: "LayoutDashboard" },
@@ -1465,60 +1509,54 @@ function PaceAppLayout({
1465
1509
  const currentPath = location.pathname;
1466
1510
  return pageIdMapping[currentPath] || currentPath.slice(1) || "home";
1467
1511
  }, [location.pathname, pageIdMapping]);
1512
+ const currentPermission = useMemo5(() => {
1513
+ if (!enforcePermissions) {
1514
+ return "read:page.home";
1515
+ }
1516
+ const permissionString = `${currentRoutePermission}:page.${currentPageId}`;
1517
+ return permissionString;
1518
+ }, [enforcePermissions, currentRoutePermission, currentPageId]);
1519
+ const { can, isLoading: isCheckingPermission, error: permissionError } = useCan(
1520
+ user?.id || "",
1521
+ scope,
1522
+ currentPermission,
1523
+ currentPageId,
1524
+ true
1525
+ // useCache
1526
+ );
1527
+ const hasPermission = enforcePermissions ? can : true;
1468
1528
  useEffect3(() => {
1469
1529
  if (!enforcePermissions) {
1470
- setHasPermission(true);
1471
1530
  return;
1472
1531
  }
1473
- let isMounted = true;
1474
- const checkRoutePermission = async () => {
1475
- if (!isMounted) return;
1476
- setIsCheckingPermission(true);
1477
- setPermissionError(null);
1478
- try {
1479
- const hasAccess = await checkPermission(currentRoutePermission, currentPageId);
1480
- if (!isMounted) return;
1481
- setHasPermission(hasAccess);
1482
- if (auditLog) {
1483
- console.log(`[PaceAppLayout] Page access attempt:`, {
1484
- pageName: currentPageId,
1485
- operation: currentRoutePermission,
1486
- userId: user?.id,
1487
- allowed: hasAccess,
1488
- strictMode,
1489
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
1490
- });
1491
- }
1492
- if (strictMode && !hasAccess) {
1493
- console.error(`[PaceAppLayout] STRICT MODE VIOLATION: User attempted to access protected page without permission`, {
1494
- pageName: currentPageId,
1495
- operation: currentRoutePermission,
1496
- userId: user?.id,
1497
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
1498
- });
1499
- if (onStrictModeViolation) {
1500
- onStrictModeViolation(currentPageId, currentRoutePermission);
1501
- }
1502
- }
1503
- if (!hasAccess && onPageAccessDenied) {
1504
- onPageAccessDenied(currentPageId, currentRoutePermission);
1505
- }
1506
- } catch (error) {
1507
- if (!isMounted) return;
1508
- console.error(`[PaceAppLayout] Permission check failed for ${currentPageId}:`, error);
1509
- setPermissionError(error instanceof Error ? error : new Error("Permission check failed"));
1510
- setHasPermission(false);
1511
- } finally {
1512
- if (isMounted) {
1513
- setIsCheckingPermission(false);
1514
- }
1532
+ if (isCheckingPermission) {
1533
+ return;
1534
+ }
1535
+ if (auditLog) {
1536
+ console.log(`[PaceAppLayout] Page access attempt:`, {
1537
+ pageName: currentPageId,
1538
+ operation: currentRoutePermission,
1539
+ userId: user?.id,
1540
+ allowed: can,
1541
+ strictMode,
1542
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1543
+ });
1544
+ }
1545
+ if (strictMode && !can) {
1546
+ console.error(`[PaceAppLayout] STRICT MODE VIOLATION: User attempted to access protected page without permission`, {
1547
+ pageName: currentPageId,
1548
+ operation: currentRoutePermission,
1549
+ userId: user?.id,
1550
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1551
+ });
1552
+ if (onStrictModeViolation) {
1553
+ onStrictModeViolation(currentPageId, currentRoutePermission);
1515
1554
  }
1516
- };
1517
- checkRoutePermission();
1518
- return () => {
1519
- isMounted = false;
1520
- };
1521
- }, [enforcePermissions, currentRoutePermission, currentPageId, strictMode, user?.id]);
1555
+ }
1556
+ if (!can && onPageAccessDenied) {
1557
+ onPageAccessDenied(currentPageId, currentRoutePermission);
1558
+ }
1559
+ }, [enforcePermissions, can, isCheckingPermission, currentPageId, currentRoutePermission, user?.id, strictMode, auditLog, onPageAccessDenied, onStrictModeViolation]);
1522
1560
  const [filteredMenuItems, setFilteredMenuItems] = useState5(baseMenuItems);
1523
1561
  useEffect3(() => {
1524
1562
  if (!filterNavigationByPermissions) {
@@ -1533,13 +1571,13 @@ function PaceAppLayout({
1533
1571
  }
1534
1572
  return;
1535
1573
  }
1536
- const scope = {
1574
+ const scope2 = {
1537
1575
  organisationId: user.user_metadata?.organisationId || user.app_metadata?.organisationId,
1538
1576
  eventId: user.user_metadata?.eventId || user.app_metadata?.eventId,
1539
1577
  appId: user.user_metadata?.appId || user.app_metadata?.appId
1540
1578
  };
1541
1579
  try {
1542
- const { isSuperAdmin: isSuperAdmin2 } = await import("./api-PIE4JRFS.js");
1580
+ const { isSuperAdmin: isSuperAdmin2 } = await import("./api-QPMBZZUZ.js");
1543
1581
  const isSuper = await isSuperAdmin2(user.id);
1544
1582
  if (isSuper) {
1545
1583
  if (isMounted) {
@@ -1553,17 +1591,17 @@ function PaceAppLayout({
1553
1591
  throw error;
1554
1592
  }
1555
1593
  }
1556
- if (!scope.organisationId) {
1594
+ if (!scope2.organisationId) {
1557
1595
  if (isMounted) {
1558
1596
  setFilteredMenuItems(baseMenuItems);
1559
1597
  }
1560
1598
  return;
1561
1599
  }
1562
1600
  try {
1563
- const { getPermissionMap } = await import("./api-PIE4JRFS.js");
1601
+ const { getPermissionMap } = await import("./api-QPMBZZUZ.js");
1564
1602
  const permissionMap = await getPermissionMap({
1565
1603
  userId: user.id,
1566
- scope
1604
+ scope: scope2
1567
1605
  });
1568
1606
  const filtered = baseMenuItems.map((item) => {
1569
1607
  if (!item.href) return { item, hasAccess: true };
@@ -1596,7 +1634,7 @@ function PaceAppLayout({
1596
1634
  return () => {
1597
1635
  isMounted = false;
1598
1636
  };
1599
- }, [baseMenuItems, filterNavigationByPermissions, pageIdMapping, routePermissions, defaultPermission, checkPermission, user?.id, user?.user_metadata, user?.app_metadata]);
1637
+ }, [baseMenuItems, filterNavigationByPermissions, pageIdMapping, routePermissions, defaultPermission, can, user?.id, user?.user_metadata, user?.app_metadata]);
1600
1638
  useEffect3(() => {
1601
1639
  if (!roleBasedRouting || routeConfig.length === 0) return;
1602
1640
  let isMounted = true;
@@ -1619,7 +1657,13 @@ function PaceAppLayout({
1619
1657
  let hasAccess = true;
1620
1658
  if (currentRoute.pageId && currentRoute.permissions && currentRoute.permissions.length > 0) {
1621
1659
  try {
1622
- const hasPagePermission = await checkPermission(currentRoute.permissions[0], currentRoute.pageId);
1660
+ const { isPermittedCached } = await import("./api-QPMBZZUZ.js");
1661
+ const hasPagePermission = await isPermittedCached({
1662
+ userId: user?.id || "",
1663
+ scope,
1664
+ permission: currentRoute.permissions[0],
1665
+ pageId: currentRoute.pageId
1666
+ });
1623
1667
  if (!isMounted) return;
1624
1668
  hasAccess = hasPagePermission;
1625
1669
  } catch (error) {
@@ -1629,7 +1673,7 @@ function PaceAppLayout({
1629
1673
  }
1630
1674
  }
1631
1675
  if (hasAccess && currentRoute.roles && currentRoute.roles.length > 0 && user?.id) {
1632
- const { useUnifiedAuth: useUnifiedAuth2 } = await import("./UnifiedAuthProvider-A7I23UCN.js");
1676
+ const { useUnifiedAuth: useUnifiedAuth2 } = await import("./UnifiedAuthProvider-KZZUO27W.js");
1633
1677
  hasAccess = true;
1634
1678
  }
1635
1679
  if (!isMounted) return;
@@ -1669,7 +1713,7 @@ function PaceAppLayout({
1669
1713
  return () => {
1670
1714
  isMounted = false;
1671
1715
  };
1672
- }, [roleBasedRouting, routeConfig, location.pathname, strictMode, user?.id, fallbackRoute, checkPermission, navigate, auditLog, onRouteAccessDenied, onRouteStrictModeViolation]);
1716
+ }, [roleBasedRouting, routeConfig, location.pathname, strictMode, user?.id, fallbackRoute, scope, navigate, auditLog, onRouteAccessDenied, onRouteStrictModeViolation]);
1673
1717
  const handleSignOut = async () => {
1674
1718
  await signOut();
1675
1719
  };
@@ -1737,9 +1781,10 @@ function PaceAppLayout({
1737
1781
  }
1738
1782
 
1739
1783
  // src/components/PaceLoginPage/PaceLoginPage.tsx
1740
- import { useEffect as useEffect4, useState as useState6 } from "react";
1784
+ import { useEffect as useEffect4, useState as useState6, useContext } from "react";
1741
1785
  import { useNavigate as useNavigate2 } from "react-router-dom";
1742
1786
  init_runtime();
1787
+ init_EventServiceProvider();
1743
1788
  import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
1744
1789
  var PaceLoginPage = ({
1745
1790
  appName = "Pace",
@@ -1751,9 +1796,27 @@ var PaceLoginPage = ({
1751
1796
  const [isSigningIn, setIsSigningIn] = useState6(false);
1752
1797
  const [accessError, setAccessError] = useState6(null);
1753
1798
  const [isCheckingAccess, setIsCheckingAccess] = useState6(false);
1799
+ const eventServiceContext = useContext(EventServiceContext);
1800
+ const eventService = eventServiceContext?.eventService || null;
1754
1801
  useEffect4(() => {
1755
1802
  clearPalette();
1756
1803
  }, []);
1804
+ useEffect4(() => {
1805
+ const restoreEvent = async () => {
1806
+ try {
1807
+ const isOnLoginPage = window.location.pathname === "/login" || window.location.pathname.startsWith("/login");
1808
+ if (isOnLoginPage && eventService) {
1809
+ await eventService.restorePersistedEvent();
1810
+ }
1811
+ } catch (error) {
1812
+ console.debug("[PaceLoginPage] Could not restore persisted event (service may not be ready):", error);
1813
+ }
1814
+ };
1815
+ const timeoutId = setTimeout(() => {
1816
+ restoreEvent();
1817
+ }, 100);
1818
+ return () => clearTimeout(timeoutId);
1819
+ }, [eventService]);
1757
1820
  useEffect4(() => {
1758
1821
  if (!requireAppAccess || !isAuthenticated || isLoading || !user || !supabase) {
1759
1822
  return;
@@ -2990,13 +3053,6 @@ function FileUpload({
2990
3053
  };
2991
3054
  onProgress?.(finalProgress);
2992
3055
  onUploadSuccess?.(result);
2993
- setTimeout(() => {
2994
- setUploadStates((prev) => {
2995
- const updated = new Map(prev);
2996
- updated.delete(fileId);
2997
- return updated;
2998
- });
2999
- }, 3e3);
3000
3056
  } else {
3001
3057
  setUploadStates((prev) => {
3002
3058
  const updated = new Map(prev);
@@ -3191,7 +3247,7 @@ function FileUpload({
3191
3247
  }
3192
3248
 
3193
3249
  // src/components/FileDisplay/FileDisplay.tsx
3194
- import { useState as useState12, useEffect as useEffect8, useRef as useRef5, useContext, useMemo as useMemo9 } from "react";
3250
+ import { useState as useState12, useEffect as useEffect8, useRef as useRef5, useContext as useContext2, useMemo as useMemo9 } from "react";
3195
3251
 
3196
3252
  // src/hooks/useFileUrl.ts
3197
3253
  import { useState as useState11, useEffect as useEffect7, useCallback as useCallback7, useRef as useRef4 } from "react";
@@ -3571,7 +3627,7 @@ function FileDisplayPublic({
3571
3627
  fallbackText,
3572
3628
  fallbackSize
3573
3629
  }) {
3574
- const publicPageContext = useContext(PublicPageContext);
3630
+ const publicPageContext = useContext2(PublicPageContext);
3575
3631
  const supabase = publicPageContext?.supabase ?? null;
3576
3632
  if (!supabase) {
3577
3633
  return /* @__PURE__ */ jsx22("div", { className: `text-sec-500 text-center p-4 ${className}`, children: "Supabase client not available in public context" });
@@ -4453,4 +4509,4 @@ export {
4453
4509
  PublicPageDiagnostic,
4454
4510
  PublicPageContextChecker
4455
4511
  };
4456
- //# sourceMappingURL=chunk-3J5N2T2N.js.map
4512
+ //# sourceMappingURL=chunk-EKVVTPIF.js.map