@jmruthers/pace-core 0.6.1 → 0.6.3
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.
- package/CHANGELOG.md +88 -10
- package/cursor-rules/00-pace-core-compliance.mdc +46 -87
- package/cursor-rules/01-standards-compliance.mdc +16 -47
- package/cursor-rules/02-project-structure.mdc +4 -4
- package/cursor-rules/03-solid-principles.mdc +45 -164
- package/cursor-rules/04-testing-standards.mdc +22 -69
- package/cursor-rules/05-bug-reports-and-features.mdc +2 -2
- package/cursor-rules/06-code-quality.mdc +42 -125
- package/cursor-rules/07-tech-stack-compliance.mdc +33 -128
- package/cursor-rules/08-markup-quality.mdc +452 -0
- package/cursor-rules/CHANGELOG.md +18 -0
- package/cursor-rules/README.md +2 -1
- package/dist/{AuthService-DjnJHDtC.d.ts → AuthService-Cb34EQs3.d.ts} +63 -1
- package/dist/{DataTable-CH1U5Tpy.d.ts → DataTable-BMRU8a1j.d.ts} +33 -1
- package/dist/{DataTable-DQ7RSOHE.js → DataTable-THFPBKTP.js} +12 -10
- package/dist/{PublicPageProvider-ce4xlHYA.d.ts → PublicPageProvider-DEMpysFR.d.ts} +394 -171
- package/dist/{UnifiedAuthProvider-185Ih4dj.d.ts → UnifiedAuthProvider-CKvHP1MK.d.ts} +30 -8
- package/dist/{UnifiedAuthProvider-ATAP5UTR.js → UnifiedAuthProvider-KAGUYQ4J.js} +5 -4
- package/dist/{api-N774RPUA.js → api-IAGWF3ZG.js} +10 -10
- package/dist/{audit-B5P6FFIR.js → audit-V53FV5AG.js} +2 -2
- package/dist/{chunk-JBKQ3SAO.js → chunk-2T2IG7T7.js} +107 -57
- package/dist/chunk-2T2IG7T7.js.map +1 -0
- package/dist/{chunk-3QRJFVBR.js → chunk-6SOIHG6Z.js} +1 -1
- package/dist/chunk-6SOIHG6Z.js.map +1 -0
- package/dist/{chunk-3XTALGJF.js → chunk-6Z7LTB3D.js} +69 -240
- package/dist/chunk-6Z7LTB3D.js.map +1 -0
- package/dist/{chunk-4ZC4GX36.js → chunk-CNCQDFLN.js} +199 -46
- package/dist/chunk-CNCQDFLN.js.map +1 -0
- package/dist/chunk-DGUM43GV.js +11 -0
- package/dist/{chunk-BYFSK72L.js → chunk-DWUBLJJM.js} +361 -187
- package/dist/chunk-DWUBLJJM.js.map +1 -0
- package/dist/{chunk-LXQLPRQ2.js → chunk-FFQEQTNW.js} +6 -8
- package/dist/chunk-FFQEQTNW.js.map +1 -0
- package/dist/chunk-FMUCXFII.js +76 -0
- package/dist/chunk-FMUCXFII.js.map +1 -0
- package/dist/{chunk-4N5C5XZU.js → chunk-HFZBI76P.js} +4 -4
- package/dist/chunk-HFZBI76P.js.map +1 -0
- package/dist/{chunk-SQGMNID3.js → chunk-L4OXEN46.js} +4 -5
- package/dist/chunk-L4OXEN46.js.map +1 -0
- package/dist/{chunk-R77UEZ4E.js → chunk-M43Y4SSO.js} +1 -1
- package/dist/chunk-M43Y4SSO.js.map +1 -0
- package/dist/{chunk-I7PSE6JW.js → chunk-M7MPQISP.js} +3 -76
- package/dist/chunk-M7MPQISP.js.map +1 -0
- package/dist/chunk-PQBSKX33.js +7793 -0
- package/dist/chunk-PQBSKX33.js.map +1 -0
- package/dist/chunk-QRPVRXYT.js +226 -0
- package/dist/chunk-QRPVRXYT.js.map +1 -0
- package/dist/{chunk-KNC55RTG.js → chunk-RWEBCB47.js} +194 -416
- package/dist/chunk-RWEBCB47.js.map +1 -0
- package/dist/{chunk-XM25TVIE.js → chunk-YDQHOZNA.js} +843 -388
- package/dist/chunk-YDQHOZNA.js.map +1 -0
- package/dist/{chunk-GLK6VM3F.js → chunk-ZNIWI3UC.js} +739 -737
- package/dist/chunk-ZNIWI3UC.js.map +1 -0
- package/dist/components.d.ts +5 -5
- package/dist/components.js +18 -16
- package/dist/components.js.map +1 -1
- package/dist/contextValidator-3JNZKUTX.js +9 -0
- package/dist/contextValidator-3JNZKUTX.js.map +1 -0
- package/dist/eslint-rules/pace-core-compliance.cjs +106 -0
- package/dist/{functions-D_kgHktt.d.ts → functions-DHebl8-F.d.ts} +1 -1
- package/dist/hooks.d.ts +55 -122
- package/dist/hooks.js +10 -13
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +60 -13
- package/dist/index.js +30 -25
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +21 -3
- package/dist/providers.js +4 -3
- package/dist/rbac/index.d.ts +210 -139
- package/dist/rbac/index.js +17 -13
- package/dist/styles/index.js +1 -1
- package/dist/theming/runtime.d.ts +1 -13
- package/dist/theming/runtime.js +2 -2
- package/dist/{timezone-_pgH8qrY.d.ts → timezone-CHhWg6b4.d.ts} +3 -10
- package/dist/{types-UU913iLA.d.ts → types-BeoeWV5I.d.ts} +8 -0
- package/dist/{types-CEpcvwwF.d.ts → types-CkbwOr4Y.d.ts} +6 -0
- package/dist/types.d.ts +2 -2
- package/dist/types.js +1 -1
- package/dist/{usePublicRouteParams-BJAlWfuJ.d.ts → usePublicRouteParams-i3qtoBgg.d.ts} +38 -17
- package/dist/utils.d.ts +4 -5
- package/dist/utils.js +17 -19
- package/dist/utils.js.map +1 -1
- package/docs/api/README.md +21 -17
- package/docs/api/modules.md +4191 -2967
- package/docs/architecture/database-schema-requirements.md +161 -0
- package/docs/components/context-selector.md +126 -0
- package/docs/core-concepts/rbac-system.md +3 -3
- package/docs/documentation-index.md +2 -4
- package/docs/getting-started/cursor-rules.md +2 -1
- package/docs/migration/DOCUMENTATION_STRUCTURE.md +441 -0
- package/docs/migration/MIGRATION_GUIDE.md +2 -24
- package/docs/migration/RBAC_SCOPE_MIGRATION.md +385 -0
- package/docs/migration/README.md +52 -6
- package/docs/migration/V0.5.190_TO_V0.6.1_MIGRATION.md +1153 -0
- package/docs/migration/database-changes-december-2025.md +3 -3
- package/docs/pace-mint-fix-auto-selection.md +218 -0
- package/docs/pace-mint-rbac-setup.md +391 -0
- package/docs/rbac/event-based-apps.md +1 -1
- package/docs/rbac/getting-started.md +1 -1
- package/docs/rbac/quick-start.md +1 -1
- package/docs/rbac/secure-client-protection.md +330 -0
- package/docs/standards/README.md +1 -0
- package/package.json +4 -3
- package/scripts/audit/core/checks/accessibility.cjs +197 -0
- package/scripts/audit/core/checks/api-usage.cjs +191 -0
- package/scripts/audit/core/checks/bundle.cjs +142 -0
- package/scripts/{check-pace-core-compliance.cjs → audit/core/checks/compliance.cjs} +784 -685
- package/scripts/audit/core/checks/config.cjs +54 -0
- package/scripts/audit/core/checks/coverage.cjs +84 -0
- package/scripts/audit/core/checks/dependencies.cjs +985 -0
- package/scripts/audit/core/checks/documentation.cjs +268 -0
- package/scripts/audit/core/checks/environment.cjs +116 -0
- package/scripts/audit/core/checks/error-handling.cjs +340 -0
- package/scripts/audit/core/checks/forms.cjs +172 -0
- package/scripts/audit/core/checks/heuristics.cjs +68 -0
- package/scripts/audit/core/checks/hooks.cjs +334 -0
- package/scripts/audit/core/checks/imports.cjs +244 -0
- package/scripts/audit/core/checks/performance.cjs +325 -0
- package/scripts/audit/core/checks/routes.cjs +117 -0
- package/scripts/audit/core/checks/state.cjs +130 -0
- package/scripts/audit/core/checks/structure.cjs +65 -0
- package/scripts/audit/core/checks/style.cjs +584 -0
- package/scripts/audit/core/checks/testing.cjs +122 -0
- package/scripts/audit/core/checks/typescript.cjs +61 -0
- package/scripts/audit/core/scanner.cjs +199 -0
- package/scripts/audit/core/utils.cjs +137 -0
- package/scripts/audit/index.cjs +223 -0
- package/scripts/audit/reporters/console.cjs +151 -0
- package/scripts/audit/reporters/json.cjs +54 -0
- package/scripts/audit/reporters/markdown.cjs +124 -0
- package/scripts/audit-consuming-app.cjs +61 -936
- package/scripts/build-docs/build-decision.js +240 -0
- package/scripts/build-docs/cache-utils.js +105 -0
- package/scripts/build-docs/content-normalization.js +150 -0
- package/scripts/build-docs/file-utils.js +105 -0
- package/scripts/build-docs/git-utils.js +86 -0
- package/scripts/build-docs/hash-utils.js +116 -0
- package/scripts/build-docs/typedoc-runner.js +220 -0
- package/scripts/build-docs-incremental.js +77 -913
- package/scripts/utils/command-runner.js +16 -11
- package/scripts/validate-formats.js +61 -56
- package/scripts/validate-master.js +74 -69
- package/scripts/validate-pre-publish.js +70 -65
- package/src/__tests__/hooks/usePermissions.test.ts +2 -2
- package/src/components/Alert/Alert.test.tsx +12 -18
- package/src/components/Alert/Alert.tsx +5 -7
- package/src/components/Avatar/Avatar.test.tsx +4 -4
- package/src/components/Badge/Badge.tsx +14 -0
- package/src/components/Button/Button.tsx +22 -0
- package/src/components/Calendar/Calendar.tsx +8 -2
- package/src/components/Card/Card.tsx +4 -0
- package/src/components/Checkbox/Checkbox.test.tsx +12 -12
- package/src/components/Checkbox/Checkbox.tsx +2 -2
- package/src/components/ContextSelector/ContextSelector.tsx +384 -0
- package/src/components/ContextSelector/index.ts +3 -0
- package/src/components/DataTable/DataTable.tsx +38 -4
- package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +5 -6
- package/src/components/DataTable/__tests__/pagination.modes.test.tsx +18 -4
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +2 -3
- package/src/components/DataTable/components/AccessDeniedPage.tsx +16 -25
- package/src/components/DataTable/components/ActionButtons.tsx +10 -7
- package/src/components/DataTable/components/BulkOperationsDropdown.tsx +1 -1
- package/src/components/DataTable/components/ColumnFilter.tsx +10 -0
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +12 -0
- package/src/components/DataTable/components/DataTableBody.tsx +8 -0
- package/src/components/DataTable/components/DataTableCore.tsx +196 -554
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +11 -0
- package/src/components/DataTable/components/DataTableLayout.tsx +559 -0
- package/src/components/DataTable/components/DataTableModals.tsx +8 -0
- package/src/components/DataTable/components/DataTableToolbar.tsx +8 -0
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +12 -0
- package/src/components/DataTable/components/EditFields.tsx +307 -0
- package/src/components/DataTable/components/EditableRow.tsx +8 -0
- package/src/components/DataTable/components/EmptyState.tsx +10 -0
- package/src/components/DataTable/components/FilterRow.tsx +12 -0
- package/src/components/DataTable/components/GroupHeader.tsx +12 -0
- package/src/components/DataTable/components/GroupingDropdown.tsx +12 -0
- package/src/components/DataTable/components/ImportModal.tsx +7 -0
- package/src/components/DataTable/components/LoadingState.tsx +6 -0
- package/src/components/DataTable/components/PaginationControls.tsx +16 -1
- package/src/components/DataTable/components/RowComponent.tsx +391 -0
- package/src/components/DataTable/components/UnifiedTableBody.tsx +63 -851
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +16 -4
- package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +4 -2
- package/src/components/DataTable/components/cellValueUtils.ts +40 -0
- package/src/components/DataTable/components/hooks/useImportModalFocus.ts +53 -0
- package/src/components/DataTable/components/hooks/usePermissionTracking.ts +126 -0
- package/src/components/DataTable/context/DataTableContext.tsx +50 -0
- package/src/components/DataTable/core/ColumnFactory.ts +31 -0
- package/src/components/DataTable/core/DataTableContext.tsx +32 -1
- package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +10 -0
- package/src/components/DataTable/hooks/useColumnReordering.ts +12 -0
- package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +10 -0
- package/src/components/DataTable/hooks/useDataTableDataPipeline.ts +16 -0
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +127 -33
- package/src/components/DataTable/hooks/useDataTableState.ts +35 -1
- package/src/components/DataTable/hooks/useEffectiveColumnOrder.ts +12 -0
- package/src/components/DataTable/hooks/useServerSideDataEffect.ts +11 -0
- package/src/components/DataTable/hooks/useTableColumns.ts +8 -0
- package/src/components/DataTable/hooks/useTableHandlers.ts +14 -0
- package/src/components/DataTable/styles.ts +6 -6
- package/src/components/DataTable/types.ts +6 -10
- package/src/components/DataTable/utils/a11yUtils.ts +7 -0
- package/src/components/DataTable/utils/debugTools.ts +18 -113
- package/src/components/DataTable/utils/errorHandling.ts +12 -0
- package/src/components/DataTable/utils/exportUtils.ts +9 -0
- package/src/components/DataTable/utils/flexibleImport.ts +12 -48
- package/src/components/DataTable/utils/paginationUtils.ts +8 -0
- package/src/components/DataTable/utils/performanceUtils.ts +5 -1
- package/src/components/Dialog/Dialog.tsx +31 -3
- package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +180 -1
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +45 -5
- package/src/components/ErrorBoundary/ErrorBoundaryContext.tsx +129 -0
- package/src/components/ErrorBoundary/index.ts +27 -2
- package/src/components/FileDisplay/FileDisplay.tsx +74 -28
- package/src/components/FileUpload/FileUpload.tsx +22 -2
- package/src/components/Footer/Footer.test.tsx +16 -16
- package/src/components/Footer/Footer.tsx +14 -11
- package/src/components/Form/Form.tsx +1 -0
- package/src/components/Header/Header.test.tsx +43 -73
- package/src/components/Header/Header.tsx +59 -49
- package/src/components/Input/Input.test.tsx +2 -2
- package/src/components/Input/Input.tsx +8 -4
- package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +4 -4
- package/src/components/LoginForm/LoginForm.tsx +4 -0
- package/src/components/NavigationMenu/NavigationMenu.tsx +14 -513
- package/src/components/NavigationMenu/types.ts +56 -0
- package/src/components/NavigationMenu/useNavigationFiltering.ts +390 -0
- package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +10 -19
- package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +2 -2
- package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +5 -5
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +13 -11
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +167 -44
- package/src/components/PaceAppLayout/README.md +14 -17
- package/src/components/PaceAppLayout/test-setup.tsx +3 -4
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +3 -0
- package/src/components/PasswordChange/PasswordChangeForm.tsx +9 -0
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +3 -9
- package/src/components/PublicLayout/PublicPageLayout.tsx +2 -5
- package/src/components/PublicLayout/PublicPageProvider.tsx +4 -0
- package/src/components/Select/Select.tsx +80 -434
- package/src/components/Select/context.ts +23 -0
- package/src/components/Select/hooks/useSelectEvents.ts +87 -0
- package/src/components/Select/hooks/useSelectSearch.ts +91 -0
- package/src/components/Select/hooks/useSelectState.ts +104 -0
- package/src/components/Select/index.ts +9 -1
- package/src/components/Select/types.ts +123 -0
- package/src/components/Select/utils/text.ts +26 -0
- package/src/components/SessionRestorationLoader/SessionRestorationLoader.tsx +4 -5
- package/src/components/Switch/Switch.tsx +4 -4
- package/src/components/Tabs/Tabs.tsx +1 -1
- package/src/components/Toast/Toast.tsx +4 -0
- package/src/components/Tooltip/Tooltip.tsx +2 -2
- package/src/components/UserMenu/UserMenu.test.tsx +24 -11
- package/src/components/UserMenu/UserMenu.tsx +21 -18
- package/src/components/index.ts +7 -7
- package/src/eslint-rules/pace-core-compliance.cjs +106 -0
- package/src/hooks/__tests__/index.unit.test.ts +2 -5
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +4 -98
- package/src/hooks/index.ts +1 -2
- package/src/hooks/public/usePublicEvent.ts +4 -0
- package/src/hooks/public/usePublicEventLogo.ts +4 -0
- package/src/hooks/public/usePublicFileDisplay.ts +4 -0
- package/src/hooks/public/usePublicRouteParams.ts +4 -0
- package/src/hooks/services/useAuth.ts +32 -0
- package/src/hooks/services/useCurrentEvent.ts +6 -0
- package/src/hooks/services/useCurrentOrganisation.ts +6 -0
- package/src/hooks/useAppConfig.ts +15 -30
- package/src/hooks/useDebounce.ts +9 -0
- package/src/hooks/useEventTheme.ts +6 -0
- package/src/hooks/useFileDisplay.ts +81 -50
- package/src/hooks/useFileReference.ts +25 -7
- package/src/hooks/useFileUrl.ts +11 -1
- package/src/hooks/useFocusManagement.ts +14 -0
- package/src/hooks/useFocusTrap.ts +3 -0
- package/src/hooks/useInactivityTracker.ts +3 -0
- package/src/hooks/useKeyboardShortcuts.ts +4 -0
- package/src/hooks/useOrganisationPermissions.ts +4 -0
- package/src/hooks/useOrganisationSecurity.ts +4 -0
- package/src/hooks/usePerformanceMonitor.ts +4 -0
- package/src/hooks/usePermissionCache.ts +7 -0
- package/src/hooks/useQueryCache.ts +12 -1
- package/src/hooks/useSessionRestoration.ts +4 -0
- package/src/hooks/useStorage.ts +4 -0
- package/src/hooks/useToast.ts +1 -1
- package/src/index.ts +6 -6
- package/src/providers/__tests__/OrganisationProvider.test.tsx +92 -70
- package/src/providers/services/AuthServiceProvider.tsx +35 -7
- package/src/providers/services/EventServiceProvider.tsx +51 -5
- package/src/providers/services/InactivityServiceProvider.tsx +18 -0
- package/src/providers/services/OrganisationServiceProvider.tsx +18 -0
- package/src/providers/services/UnifiedAuthProvider.tsx +126 -134
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +29 -13
- package/src/rbac/README.md +1 -1
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +1 -1
- package/src/rbac/__tests__/scenarios.user-role.test.tsx +4 -5
- package/src/rbac/adapters.tsx +12 -3
- package/src/rbac/api.test.ts +59 -51
- package/src/rbac/api.ts +246 -167
- package/src/rbac/components/NavigationProvider.tsx +4 -1
- package/src/rbac/components/PagePermissionGuard.tsx +185 -17
- package/src/rbac/components/RoleBasedRouter.tsx +5 -1
- package/src/rbac/components/SecureDataProvider.test.tsx +84 -49
- package/src/rbac/components/SecureDataProvider.tsx +20 -5
- package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +24 -14
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +7 -0
- package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +14 -6
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +15 -4
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +148 -24
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +81 -15
- package/src/rbac/engine.ts +38 -14
- package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +32 -21
- package/src/rbac/hooks/permissions/index.ts +7 -0
- package/src/rbac/hooks/permissions/useAccessLevel.ts +105 -0
- package/src/rbac/hooks/permissions/useCachedPermissions.ts +79 -0
- package/src/rbac/hooks/permissions/useCan.ts +377 -0
- package/src/rbac/hooks/permissions/useHasAllPermissions.ts +90 -0
- package/src/rbac/hooks/permissions/useHasAnyPermission.ts +90 -0
- package/src/rbac/hooks/permissions/useMultiplePermissions.ts +93 -0
- package/src/rbac/hooks/permissions/usePermissions.ts +253 -0
- package/src/rbac/hooks/useCan.test.ts +64 -66
- package/src/rbac/hooks/usePermissions.ts +14 -995
- package/src/rbac/hooks/useRBAC.test.ts +1 -5
- package/src/rbac/hooks/useRBAC.ts +36 -37
- package/src/rbac/hooks/useResolvedScope.test.ts +120 -35
- package/src/rbac/hooks/useResolvedScope.ts +35 -40
- package/src/rbac/hooks/useResourcePermissions.test.ts +54 -18
- package/src/rbac/hooks/useResourcePermissions.ts +14 -4
- package/src/rbac/hooks/useSecureSupabase.ts +27 -7
- package/src/rbac/index.ts +7 -0
- package/src/rbac/permissions.ts +0 -30
- package/src/rbac/secureClient.test.ts +22 -18
- package/src/rbac/secureClient.ts +294 -68
- package/src/rbac/security.ts +0 -17
- package/src/rbac/types.ts +9 -0
- package/src/rbac/utils/__tests__/contextValidator.test.ts +64 -86
- package/src/rbac/utils/clientSecurity.ts +93 -0
- package/src/rbac/utils/contextValidator.ts +77 -168
- package/src/services/AuthService.ts +39 -7
- package/src/services/EventService.ts +186 -54
- package/src/services/OrganisationService.ts +81 -14
- package/src/services/__tests__/EventService.test.ts +1 -2
- package/src/services/base/BaseService.ts +3 -0
- package/src/theming/__tests__/parseEventColours.test.ts +6 -9
- package/src/theming/parseEventColours.ts +5 -19
- package/src/types/vitest-globals.d.ts +51 -26
- package/src/utils/__mocks__/supabaseMock.ts +1 -3
- package/src/utils/__tests__/formatting.unit.test.ts +4 -4
- package/src/utils/__tests__/index.unit.test.ts +2 -2
- package/src/utils/audit/audit.ts +0 -3
- package/src/utils/core/cn.ts +1 -1
- package/src/utils/dynamic/dynamicUtils.ts +7 -4
- package/src/utils/file-reference/index.ts +53 -1
- package/src/utils/formatting/formatting.ts +8 -18
- package/src/utils/index.ts +0 -1
- package/dist/chunk-3QRJFVBR.js.map +0 -1
- package/dist/chunk-3XTALGJF.js.map +0 -1
- package/dist/chunk-4N5C5XZU.js.map +0 -1
- package/dist/chunk-4ZC4GX36.js.map +0 -1
- package/dist/chunk-7D4SUZUM.js +0 -38
- package/dist/chunk-BYFSK72L.js.map +0 -1
- package/dist/chunk-EXUD6RNJ.js +0 -451
- package/dist/chunk-EXUD6RNJ.js.map +0 -1
- package/dist/chunk-GLK6VM3F.js.map +0 -1
- package/dist/chunk-I7PSE6JW.js.map +0 -1
- package/dist/chunk-JBKQ3SAO.js.map +0 -1
- package/dist/chunk-KNC55RTG.js.map +0 -1
- package/dist/chunk-LXQLPRQ2.js.map +0 -1
- package/dist/chunk-R77UEZ4E.js.map +0 -1
- package/dist/chunk-SQGMNID3.js.map +0 -1
- package/dist/chunk-T33XF5ZC.js +0 -12922
- package/dist/chunk-T33XF5ZC.js.map +0 -1
- package/dist/chunk-XM25TVIE.js.map +0 -1
- package/docs/api/classes/ColumnFactory.md +0 -243
- package/docs/api/classes/ErrorBoundary.md +0 -144
- package/docs/api/classes/InvalidScopeError.md +0 -73
- package/docs/api/classes/Logger.md +0 -178
- package/docs/api/classes/MissingUserContextError.md +0 -66
- package/docs/api/classes/OrganisationContextRequiredError.md +0 -66
- package/docs/api/classes/PermissionDeniedError.md +0 -73
- package/docs/api/classes/RBACAuditManager.md +0 -297
- package/docs/api/classes/RBACCache.md +0 -322
- package/docs/api/classes/RBACEngine.md +0 -171
- package/docs/api/classes/RBACError.md +0 -76
- package/docs/api/classes/RBACNotInitializedError.md +0 -66
- package/docs/api/classes/SecureSupabaseClient.md +0 -160
- package/docs/api/classes/StorageUtils.md +0 -328
- package/docs/api/enums/FileCategory.md +0 -184
- package/docs/api/enums/LogLevel.md +0 -54
- package/docs/api/enums/RBACErrorCode.md +0 -228
- package/docs/api/enums/RPCFunction.md +0 -118
- package/docs/api/interfaces/AddressFieldProps.md +0 -241
- package/docs/api/interfaces/AddressFieldRef.md +0 -94
- package/docs/api/interfaces/AggregateConfig.md +0 -43
- package/docs/api/interfaces/AutocompleteOptions.md +0 -75
- package/docs/api/interfaces/AvatarProps.md +0 -128
- package/docs/api/interfaces/BadgeProps.md +0 -27
- package/docs/api/interfaces/ButtonProps.md +0 -53
- package/docs/api/interfaces/CalendarProps.md +0 -70
- package/docs/api/interfaces/CardProps.md +0 -66
- package/docs/api/interfaces/ColorPalette.md +0 -7
- package/docs/api/interfaces/ColorShade.md +0 -66
- package/docs/api/interfaces/ComplianceResult.md +0 -30
- package/docs/api/interfaces/DataAccessRecord.md +0 -96
- package/docs/api/interfaces/DataRecord.md +0 -11
- package/docs/api/interfaces/DataTableAction.md +0 -249
- package/docs/api/interfaces/DataTableColumn.md +0 -504
- package/docs/api/interfaces/DataTableProps.md +0 -625
- package/docs/api/interfaces/DataTableToolbarButton.md +0 -96
- package/docs/api/interfaces/DatabaseComplianceResult.md +0 -85
- package/docs/api/interfaces/DatabaseIssue.md +0 -41
- package/docs/api/interfaces/EmptyStateConfig.md +0 -61
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +0 -235
- package/docs/api/interfaces/EventAppRoleData.md +0 -71
- package/docs/api/interfaces/ExportColumn.md +0 -90
- package/docs/api/interfaces/ExportOptions.md +0 -126
- package/docs/api/interfaces/FileDisplayProps.md +0 -249
- package/docs/api/interfaces/FileMetadata.md +0 -129
- package/docs/api/interfaces/FileReference.md +0 -118
- package/docs/api/interfaces/FileSizeLimits.md +0 -7
- package/docs/api/interfaces/FileUploadOptions.md +0 -139
- package/docs/api/interfaces/FileUploadProps.md +0 -293
- package/docs/api/interfaces/FooterProps.md +0 -105
- package/docs/api/interfaces/FormFieldProps.md +0 -166
- package/docs/api/interfaces/FormProps.md +0 -113
- package/docs/api/interfaces/GrantEventAppRoleParams.md +0 -122
- package/docs/api/interfaces/InactivityWarningModalProps.md +0 -115
- package/docs/api/interfaces/InputProps.md +0 -53
- package/docs/api/interfaces/LabelProps.md +0 -107
- package/docs/api/interfaces/LoggerConfig.md +0 -62
- package/docs/api/interfaces/LoginFormProps.md +0 -184
- package/docs/api/interfaces/NavigationAccessRecord.md +0 -107
- package/docs/api/interfaces/NavigationContextType.md +0 -164
- package/docs/api/interfaces/NavigationGuardProps.md +0 -139
- package/docs/api/interfaces/NavigationItem.md +0 -120
- package/docs/api/interfaces/NavigationMenuProps.md +0 -221
- package/docs/api/interfaces/NavigationProviderProps.md +0 -117
- package/docs/api/interfaces/Organisation.md +0 -140
- package/docs/api/interfaces/OrganisationContextType.md +0 -388
- package/docs/api/interfaces/OrganisationMembership.md +0 -140
- package/docs/api/interfaces/OrganisationProviderProps.md +0 -76
- package/docs/api/interfaces/OrganisationSecurityError.md +0 -62
- package/docs/api/interfaces/PaceAppLayoutProps.md +0 -406
- package/docs/api/interfaces/PaceLoginPageProps.md +0 -47
- package/docs/api/interfaces/PageAccessRecord.md +0 -85
- package/docs/api/interfaces/PagePermissionContextType.md +0 -140
- package/docs/api/interfaces/PagePermissionGuardProps.md +0 -153
- package/docs/api/interfaces/PagePermissionProviderProps.md +0 -119
- package/docs/api/interfaces/PaletteData.md +0 -41
- package/docs/api/interfaces/ParsedAddress.md +0 -120
- package/docs/api/interfaces/PermissionEnforcerProps.md +0 -153
- package/docs/api/interfaces/ProgressProps.md +0 -42
- package/docs/api/interfaces/ProtectedRouteProps.md +0 -97
- package/docs/api/interfaces/PublicPageFooterProps.md +0 -112
- package/docs/api/interfaces/PublicPageHeaderProps.md +0 -125
- package/docs/api/interfaces/PublicPageLayoutProps.md +0 -198
- package/docs/api/interfaces/QuickFix.md +0 -52
- package/docs/api/interfaces/RBACAccessValidateParams.md +0 -52
- package/docs/api/interfaces/RBACAccessValidateResult.md +0 -41
- package/docs/api/interfaces/RBACAuditLogParams.md +0 -85
- package/docs/api/interfaces/RBACAuditLogResult.md +0 -52
- package/docs/api/interfaces/RBACConfig.md +0 -133
- package/docs/api/interfaces/RBACContext.md +0 -52
- package/docs/api/interfaces/RBACLogger.md +0 -112
- package/docs/api/interfaces/RBACPageAccessCheckParams.md +0 -74
- package/docs/api/interfaces/RBACPerformanceMetrics.md +0 -138
- package/docs/api/interfaces/RBACPermissionCheckParams.md +0 -74
- package/docs/api/interfaces/RBACPermissionCheckResult.md +0 -52
- package/docs/api/interfaces/RBACPermissionsGetParams.md +0 -63
- package/docs/api/interfaces/RBACPermissionsGetResult.md +0 -63
- package/docs/api/interfaces/RBACResult.md +0 -58
- package/docs/api/interfaces/RBACRoleGrantParams.md +0 -63
- package/docs/api/interfaces/RBACRoleGrantResult.md +0 -52
- package/docs/api/interfaces/RBACRoleRevokeParams.md +0 -63
- package/docs/api/interfaces/RBACRoleRevokeResult.md +0 -52
- package/docs/api/interfaces/RBACRoleValidateParams.md +0 -52
- package/docs/api/interfaces/RBACRoleValidateResult.md +0 -63
- package/docs/api/interfaces/RBACRolesListParams.md +0 -52
- package/docs/api/interfaces/RBACRolesListResult.md +0 -74
- package/docs/api/interfaces/RBACSessionTrackParams.md +0 -74
- package/docs/api/interfaces/RBACSessionTrackResult.md +0 -52
- package/docs/api/interfaces/ResourcePermissions.md +0 -155
- package/docs/api/interfaces/RevokeEventAppRoleParams.md +0 -100
- package/docs/api/interfaces/RoleBasedRouterContextType.md +0 -151
- package/docs/api/interfaces/RoleBasedRouterProps.md +0 -156
- package/docs/api/interfaces/RoleManagementResult.md +0 -52
- package/docs/api/interfaces/RouteAccessRecord.md +0 -107
- package/docs/api/interfaces/RouteConfig.md +0 -134
- package/docs/api/interfaces/RuntimeComplianceResult.md +0 -55
- package/docs/api/interfaces/SecureDataContextType.md +0 -168
- package/docs/api/interfaces/SecureDataProviderProps.md +0 -132
- package/docs/api/interfaces/SessionRestorationLoaderProps.md +0 -34
- package/docs/api/interfaces/SetupIssue.md +0 -41
- package/docs/api/interfaces/StorageConfig.md +0 -41
- package/docs/api/interfaces/StorageFileInfo.md +0 -74
- package/docs/api/interfaces/StorageFileMetadata.md +0 -151
- package/docs/api/interfaces/StorageListOptions.md +0 -99
- package/docs/api/interfaces/StorageListResult.md +0 -41
- package/docs/api/interfaces/StorageUploadOptions.md +0 -101
- package/docs/api/interfaces/StorageUploadResult.md +0 -63
- package/docs/api/interfaces/StorageUrlOptions.md +0 -60
- package/docs/api/interfaces/StyleImport.md +0 -19
- package/docs/api/interfaces/SwitchProps.md +0 -34
- package/docs/api/interfaces/TabsContentProps.md +0 -9
- package/docs/api/interfaces/TabsListProps.md +0 -9
- package/docs/api/interfaces/TabsProps.md +0 -9
- package/docs/api/interfaces/TabsTriggerProps.md +0 -50
- package/docs/api/interfaces/TextareaProps.md +0 -53
- package/docs/api/interfaces/ToastActionElement.md +0 -9
- package/docs/api/interfaces/ToastProps.md +0 -9
- package/docs/api/interfaces/UnifiedAuthContextType.md +0 -820
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +0 -171
- package/docs/api/interfaces/UseFormDialogOptions.md +0 -62
- package/docs/api/interfaces/UseFormDialogReturn.md +0 -117
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +0 -136
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +0 -123
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +0 -87
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +0 -81
- package/docs/api/interfaces/UsePublicEventOptions.md +0 -34
- package/docs/api/interfaces/UsePublicEventReturn.md +0 -68
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +0 -47
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +0 -120
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +0 -94
- package/docs/api/interfaces/UseResolvedScopeOptions.md +0 -47
- package/docs/api/interfaces/UseResolvedScopeReturn.md +0 -47
- package/docs/api/interfaces/UseResourcePermissionsOptions.md +0 -34
- package/docs/api/interfaces/UserEventAccess.md +0 -118
- package/docs/api/interfaces/UserMenuProps.md +0 -86
- package/docs/api/interfaces/UserProfile.md +0 -63
- package/docs/migration/quick-migration-guide.md +0 -356
- package/docs/migration/service-architecture.md +0 -281
- package/src/components/EventSelector/EventSelector.test.tsx +0 -720
- package/src/components/EventSelector/EventSelector.tsx +0 -420
- package/src/components/EventSelector/index.ts +0 -3
- package/src/components/OrganisationSelector/OrganisationSelector.test.tsx +0 -784
- package/src/components/OrganisationSelector/OrganisationSelector.tsx +0 -324
- package/src/components/OrganisationSelector/index.ts +0 -9
- package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +0 -680
- package/src/hooks/useSecureDataAccess.test.ts +0 -559
- package/src/hooks/useSecureDataAccess.ts +0 -681
- /package/dist/{DataTable-DQ7RSOHE.js.map → DataTable-THFPBKTP.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-ATAP5UTR.js.map → UnifiedAuthProvider-KAGUYQ4J.js.map} +0 -0
- /package/dist/{api-N774RPUA.js.map → api-IAGWF3ZG.js.map} +0 -0
- /package/dist/{audit-B5P6FFIR.js.map → audit-V53FV5AG.js.map} +0 -0
- /package/dist/{chunk-7D4SUZUM.js.map → chunk-DGUM43GV.js.map} +0 -0
- /package/docs/migration/{organisation-context-timing-fix.md → V0.3.44_organisation-context-timing-fix.md} +0 -0
- /package/docs/migration/{rbac-migration.md → V0.4.0_rbac-migration.md} +0 -0
- /package/docs/migration/{person-scoped-profiles-migration-guide.md → V0.5.190_person-scoped-profiles-migration-guide.md} +0 -0
- /package/docs/migration/{REACT_19_MIGRATION.md → V0.6.0_REACT_19_MIGRATION.md} +0 -0
|
@@ -20,17 +20,19 @@ import {
|
|
|
20
20
|
Input,
|
|
21
21
|
Select,
|
|
22
22
|
SelectContent,
|
|
23
|
+
SelectGroup,
|
|
23
24
|
SelectItem,
|
|
24
25
|
SelectLabel,
|
|
25
26
|
SelectSeparator,
|
|
26
27
|
SelectTrigger,
|
|
27
28
|
SelectValue
|
|
28
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-PQBSKX33.js";
|
|
29
30
|
import {
|
|
30
31
|
useCan,
|
|
31
32
|
usePermissions,
|
|
32
|
-
useRBAC
|
|
33
|
-
|
|
33
|
+
useRBAC,
|
|
34
|
+
useResolvedScope
|
|
35
|
+
} from "./chunk-YDQHOZNA.js";
|
|
34
36
|
import {
|
|
35
37
|
createFileReferenceService,
|
|
36
38
|
generateFileUrlsBatch,
|
|
@@ -42,27 +44,26 @@ import {
|
|
|
42
44
|
useFileDisplay,
|
|
43
45
|
usePreventTabReload,
|
|
44
46
|
usePublicFileDisplay
|
|
45
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-2T2IG7T7.js";
|
|
46
48
|
import {
|
|
47
49
|
useToast
|
|
48
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-6SOIHG6Z.js";
|
|
49
51
|
import {
|
|
50
52
|
ErrorBoundary,
|
|
51
53
|
PublicPageContext,
|
|
52
54
|
useAppConfig,
|
|
53
55
|
useEvents,
|
|
54
|
-
useIsPublicPage
|
|
55
|
-
|
|
56
|
-
} from "./chunk-3XTALGJF.js";
|
|
56
|
+
useIsPublicPage
|
|
57
|
+
} from "./chunk-6Z7LTB3D.js";
|
|
57
58
|
import {
|
|
58
59
|
EventServiceContext,
|
|
59
60
|
useOrganisations,
|
|
60
61
|
useSessionRestoration,
|
|
61
62
|
useUnifiedAuth
|
|
62
|
-
} from "./chunk-
|
|
63
|
+
} from "./chunk-DWUBLJJM.js";
|
|
63
64
|
import {
|
|
64
65
|
isSuperAdmin
|
|
65
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-RWEBCB47.js";
|
|
66
67
|
import {
|
|
67
68
|
assertAppId
|
|
68
69
|
} from "./chunk-QXHPKYJV.js";
|
|
@@ -72,13 +73,13 @@ import {
|
|
|
72
73
|
} from "./chunk-J36DSWQK.js";
|
|
73
74
|
import {
|
|
74
75
|
cn
|
|
75
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-M43Y4SSO.js";
|
|
76
77
|
import {
|
|
77
78
|
getCurrentAppName
|
|
78
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-M7MPQISP.js";
|
|
79
80
|
import {
|
|
80
81
|
clearPalette
|
|
81
|
-
} from "./chunk-
|
|
82
|
+
} from "./chunk-L4OXEN46.js";
|
|
82
83
|
import {
|
|
83
84
|
createLogger,
|
|
84
85
|
logger
|
|
@@ -404,7 +405,7 @@ function Textarea({ className, variant = "default", size = "md", error, ref, ...
|
|
|
404
405
|
Textarea.displayName = "Textarea";
|
|
405
406
|
|
|
406
407
|
// src/components/FileDisplay/FileDisplay.tsx
|
|
407
|
-
import { useState as useState3, useEffect as useEffect3, useRef as useRef3, useContext, useMemo } from "react";
|
|
408
|
+
import React3, { useState as useState3, useEffect as useEffect3, useCallback as useCallback3, useRef as useRef3, useContext, useMemo } from "react";
|
|
408
409
|
import { FileText, ExternalLink } from "lucide-react";
|
|
409
410
|
|
|
410
411
|
// src/hooks/useFileUrl.ts
|
|
@@ -423,6 +424,12 @@ function useFileUrl(fileReference, options) {
|
|
|
423
424
|
setError(null);
|
|
424
425
|
return;
|
|
425
426
|
}
|
|
427
|
+
if (!supabase) {
|
|
428
|
+
setUrl(null);
|
|
429
|
+
setIsLoading(false);
|
|
430
|
+
setError(new Error("Supabase client is required for URL generation"));
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
426
433
|
if (isLoading || url && fileReferenceIdRef.current === fileReference.id) {
|
|
427
434
|
return;
|
|
428
435
|
}
|
|
@@ -500,7 +507,7 @@ function defaultGenerateFallbackText(fileName) {
|
|
|
500
507
|
if (words.length === 0) return "FL";
|
|
501
508
|
return words.map((word) => word.charAt(0).toUpperCase()).join("").substring(0, 3);
|
|
502
509
|
}
|
|
503
|
-
|
|
510
|
+
var FileDisplayContent = React3.memo(function FileDisplayContent2({
|
|
504
511
|
isLoading,
|
|
505
512
|
error,
|
|
506
513
|
fileUrl,
|
|
@@ -531,6 +538,22 @@ function FileDisplayContent({
|
|
|
531
538
|
const [internalFileUrls, setInternalFileUrls] = useState3(new Map(fileUrls));
|
|
532
539
|
const [deleteDialogOpen, setDeleteDialogOpen] = useState3(false);
|
|
533
540
|
const fileReferencesRef = useRef3([]);
|
|
541
|
+
const imgRef = useRef3(null);
|
|
542
|
+
const currentSrcRef = useRef3(null);
|
|
543
|
+
const isImageLoadingRef = useRef3(false);
|
|
544
|
+
const stableFileUrl = useMemo(() => fileUrl, [fileUrl]);
|
|
545
|
+
const handleImageLoadStart = useCallback3(() => {
|
|
546
|
+
isImageLoadingRef.current = true;
|
|
547
|
+
if (stableFileUrl) {
|
|
548
|
+
currentSrcRef.current = stableFileUrl;
|
|
549
|
+
}
|
|
550
|
+
}, [stableFileUrl]);
|
|
551
|
+
const handleImageLoad = useCallback3(() => {
|
|
552
|
+
isImageLoadingRef.current = false;
|
|
553
|
+
if (stableFileUrl) {
|
|
554
|
+
currentSrcRef.current = stableFileUrl;
|
|
555
|
+
}
|
|
556
|
+
}, [stableFileUrl]);
|
|
534
557
|
const computedFallbackText = useMemo(() => {
|
|
535
558
|
if (fallbackText) return fallbackText;
|
|
536
559
|
const sourceText = fallbackSourceText ?? fileReference?.file_metadata?.fileName;
|
|
@@ -554,10 +577,14 @@ function FileDisplayContent({
|
|
|
554
577
|
};
|
|
555
578
|
const handleDeleteConfirm = async () => {
|
|
556
579
|
setDeleteDialogOpen(false);
|
|
557
|
-
|
|
558
|
-
|
|
580
|
+
try {
|
|
581
|
+
if (onDelete) {
|
|
582
|
+
await onDelete();
|
|
583
|
+
}
|
|
584
|
+
setImageError(false);
|
|
585
|
+
} catch (error2) {
|
|
586
|
+
setImageError(false);
|
|
559
587
|
}
|
|
560
|
-
setImageError(false);
|
|
561
588
|
};
|
|
562
589
|
const handleImageError = () => {
|
|
563
590
|
setImageError(true);
|
|
@@ -632,27 +659,32 @@ function FileDisplayContent({
|
|
|
632
659
|
if (imageError && showFallback) {
|
|
633
660
|
return /* @__PURE__ */ jsx4("figure", { className, title: fileReference.file_metadata.fileName || "File", children: /* @__PURE__ */ jsx4("p", { className: fallbackClasses, children: computedFallbackText }) });
|
|
634
661
|
}
|
|
635
|
-
if (!
|
|
662
|
+
if (!stableFileUrl) {
|
|
636
663
|
return /* @__PURE__ */ jsx4("figure", { className: className || "max-w-full h-48", title: "Loading", children: /* @__PURE__ */ jsx4("p", { className: fallbackClasses, children: /* @__PURE__ */ jsx4(LoadingSpinner, {}) }) });
|
|
637
664
|
}
|
|
638
665
|
return /* @__PURE__ */ jsx4("figure", { className: className || "", children: /* @__PURE__ */ jsx4(
|
|
639
666
|
"img",
|
|
640
667
|
{
|
|
641
|
-
|
|
668
|
+
ref: imgRef,
|
|
669
|
+
src: stableFileUrl || void 0,
|
|
642
670
|
alt: fileReference.file_metadata.fileName || "File",
|
|
643
671
|
className: imgClassName || "object-cover size-full",
|
|
644
|
-
onError: handleImageError
|
|
645
|
-
|
|
672
|
+
onError: handleImageError,
|
|
673
|
+
onLoadStart: handleImageLoadStart,
|
|
674
|
+
onLoad: handleImageLoad,
|
|
675
|
+
loading: "lazy"
|
|
676
|
+
},
|
|
677
|
+
fileReference.id
|
|
646
678
|
) });
|
|
647
679
|
}
|
|
648
|
-
if (displayOnly && !isImage &&
|
|
680
|
+
if (displayOnly && !isImage && stableFileUrl && fileReference && !showDelete) {
|
|
649
681
|
const fileName = fileReference.file_metadata?.fileName || "Document";
|
|
650
682
|
const ariaLabel = `Open ${fileName} in new tab`;
|
|
651
683
|
return /* @__PURE__ */ jsxs3("figure", { className, children: [
|
|
652
684
|
/* @__PURE__ */ jsxs3(
|
|
653
685
|
"a",
|
|
654
686
|
{
|
|
655
|
-
href:
|
|
687
|
+
href: stableFileUrl || void 0,
|
|
656
688
|
target: "_blank",
|
|
657
689
|
rel: "noopener noreferrer",
|
|
658
690
|
"aria-label": ariaLabel,
|
|
@@ -674,18 +706,20 @@ function FileDisplayContent({
|
|
|
674
706
|
] })
|
|
675
707
|
] });
|
|
676
708
|
}
|
|
677
|
-
if (displayOnly && showFallback && (!
|
|
709
|
+
if (displayOnly && showFallback && (!stableFileUrl || imageError || !isImage)) {
|
|
678
710
|
return /* @__PURE__ */ jsx4("figure", { className, title: fileReference.file_metadata.fileName || "File", children: /* @__PURE__ */ jsx4("p", { className: fallbackClasses, children: computedFallbackText }) });
|
|
679
711
|
}
|
|
680
|
-
return /* @__PURE__ */ jsx4("figure", { className: `relative ${className}`, children: isImage &&
|
|
712
|
+
return /* @__PURE__ */ jsx4("figure", { className: `relative ${className}`, children: isImage && stableFileUrl && !imageError ? /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
681
713
|
/* @__PURE__ */ jsx4(
|
|
682
714
|
"img",
|
|
683
715
|
{
|
|
684
|
-
src:
|
|
716
|
+
src: stableFileUrl,
|
|
685
717
|
alt: fileReference.file_metadata.fileName || "File",
|
|
686
718
|
className: imgClassName || "object-cover size-full",
|
|
687
|
-
onError: handleImageError
|
|
688
|
-
|
|
719
|
+
onError: handleImageError,
|
|
720
|
+
loading: "lazy"
|
|
721
|
+
},
|
|
722
|
+
fileReference.id
|
|
689
723
|
),
|
|
690
724
|
showDelete && /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
691
725
|
/* @__PURE__ */ jsx4(
|
|
@@ -778,11 +812,13 @@ function FileDisplayContent({
|
|
|
778
812
|
isImage && fileUrl2 ? /* @__PURE__ */ jsx4(
|
|
779
813
|
"img",
|
|
780
814
|
{
|
|
781
|
-
src: fileUrl2,
|
|
815
|
+
src: fileUrl2 || void 0,
|
|
782
816
|
alt: fileRef.file_metadata.fileName || "File",
|
|
783
817
|
className: imgClassName || "object-cover size-full",
|
|
784
|
-
onError: handleImageError
|
|
785
|
-
|
|
818
|
+
onError: handleImageError,
|
|
819
|
+
loading: "lazy"
|
|
820
|
+
},
|
|
821
|
+
fileRef.id
|
|
786
822
|
) : /* @__PURE__ */ jsx4("span", { className: "text-2xl", children: getFileIcon(fileRef.file_metadata.fileType || "") }),
|
|
787
823
|
showMetadata && /* @__PURE__ */ jsxs3("figcaption", { className: "flex-1 min-w-0", children: [
|
|
788
824
|
/* @__PURE__ */ jsx4("p", { className: "font-medium text-sec-900 truncate", children: fileRef.file_metadata.fileName || "Unknown file" }),
|
|
@@ -821,7 +857,7 @@ function FileDisplayContent({
|
|
|
821
857
|
}),
|
|
822
858
|
children
|
|
823
859
|
] });
|
|
824
|
-
}
|
|
860
|
+
});
|
|
825
861
|
function FileDisplayPublic({
|
|
826
862
|
table_name,
|
|
827
863
|
record_id,
|
|
@@ -971,9 +1007,7 @@ function FileDisplayAuthenticated({
|
|
|
971
1007
|
showMetadata
|
|
972
1008
|
}) {
|
|
973
1009
|
const { supabase } = useUnifiedAuth();
|
|
974
|
-
|
|
975
|
-
return /* @__PURE__ */ jsx4("figure", { className, title: "Error", children: /* @__PURE__ */ jsx4("p", { className: getFallbackClasses(fallbackSize || "md"), children: "Supabase client not available in authenticated context" }) });
|
|
976
|
-
}
|
|
1010
|
+
const [displayOnlyFileReference, setDisplayOnlyFileReference] = useState3(null);
|
|
977
1011
|
const {
|
|
978
1012
|
fileUrl,
|
|
979
1013
|
fileReference,
|
|
@@ -988,16 +1022,15 @@ function FileDisplayAuthenticated({
|
|
|
988
1022
|
record_id,
|
|
989
1023
|
organisation_id,
|
|
990
1024
|
category,
|
|
991
|
-
{ supabase }
|
|
1025
|
+
{ supabase: supabase || null }
|
|
992
1026
|
);
|
|
993
|
-
const [displayOnlyFileReference, setDisplayOnlyFileReference] = useState3(null);
|
|
994
1027
|
const displayOnlyFileUrlFromMap = displayOnlyFileReference ? fileUrls.get(displayOnlyFileReference.id) : null;
|
|
995
1028
|
const displayOnlyFileUrlHook = useFileUrl(
|
|
996
1029
|
displayOnlyFileReference && !displayOnlyFileUrlFromMap ? displayOnlyFileReference : null,
|
|
997
1030
|
{
|
|
998
|
-
supabase,
|
|
1031
|
+
supabase: supabase || null,
|
|
999
1032
|
organisation_id,
|
|
1000
|
-
autoLoad: !displayOnlyFileUrlFromMap && !!displayOnlyFileReference
|
|
1033
|
+
autoLoad: !displayOnlyFileUrlFromMap && !!displayOnlyFileReference && !!supabase
|
|
1001
1034
|
}
|
|
1002
1035
|
);
|
|
1003
1036
|
const displayOnlyFileUrl = displayOnlyFileUrlFromMap || displayOnlyFileUrlHook.url;
|
|
@@ -1012,6 +1045,9 @@ function FileDisplayAuthenticated({
|
|
|
1012
1045
|
setDisplayOnlyFileReference(null);
|
|
1013
1046
|
}
|
|
1014
1047
|
}, [displayOnly, category, fileReferences, fileUrls]);
|
|
1048
|
+
if (!supabase) {
|
|
1049
|
+
return /* @__PURE__ */ jsx4("figure", { className, title: "Error", children: /* @__PURE__ */ jsx4("p", { className: getFallbackClasses(fallbackSize || "md"), children: "Supabase client not available in authenticated context" }) });
|
|
1050
|
+
}
|
|
1015
1051
|
const handleDelete = async () => {
|
|
1016
1052
|
};
|
|
1017
1053
|
let finalFileReference = fileReference;
|
|
@@ -1428,13 +1464,17 @@ function useFileReferenceById(supabase, fileReferenceId, organisationId) {
|
|
|
1428
1464
|
return;
|
|
1429
1465
|
}
|
|
1430
1466
|
const loadUrl = async () => {
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1467
|
+
try {
|
|
1468
|
+
const service = createFileReferenceService(supabase);
|
|
1469
|
+
const url = await service.getFileUrl(
|
|
1470
|
+
fileReference.table_name,
|
|
1471
|
+
fileReference.record_id,
|
|
1472
|
+
organisationId
|
|
1473
|
+
);
|
|
1474
|
+
setFileUrl(url);
|
|
1475
|
+
} catch (error2) {
|
|
1476
|
+
setFileUrl(null);
|
|
1477
|
+
}
|
|
1438
1478
|
};
|
|
1439
1479
|
loadUrl();
|
|
1440
1480
|
}, [fileReference, fileReferenceId, organisationId, supabase]);
|
|
@@ -1982,7 +2022,7 @@ var Calendar = React7.forwardRef(
|
|
|
1982
2022
|
] })
|
|
1983
2023
|
);
|
|
1984
2024
|
}
|
|
1985
|
-
return child;
|
|
2025
|
+
return React7.isValidElement(child) ? React7.cloneElement(child, { key: child.key ?? `calendar-child-${index}` }) : child;
|
|
1986
2026
|
}) });
|
|
1987
2027
|
});
|
|
1988
2028
|
CustomMonth.displayName = "CustomMonth";
|
|
@@ -2236,6 +2276,7 @@ function FormField({
|
|
|
2236
2276
|
type,
|
|
2237
2277
|
placeholder,
|
|
2238
2278
|
"data-testid": testId,
|
|
2279
|
+
"aria-label": label || placeholder || name,
|
|
2239
2280
|
className: cn(
|
|
2240
2281
|
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
|
2241
2282
|
fieldError && "border-destructive focus-visible:ring-destructive"
|
|
@@ -2356,297 +2397,98 @@ var LoginForm = React9.memo(({
|
|
|
2356
2397
|
] }) });
|
|
2357
2398
|
});
|
|
2358
2399
|
|
|
2359
|
-
// src/components/
|
|
2360
|
-
import {
|
|
2361
|
-
import {
|
|
2362
|
-
import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2363
|
-
function
|
|
2364
|
-
placeholder = "Select
|
|
2400
|
+
// src/components/ContextSelector/ContextSelector.tsx
|
|
2401
|
+
import { useMemo as useMemo5 } from "react";
|
|
2402
|
+
import { RefreshCw, AlertCircle, Building2, Calendar as Calendar2 } from "lucide-react";
|
|
2403
|
+
import { Fragment as Fragment6, jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2404
|
+
function ContextSelector({
|
|
2405
|
+
placeholder = "Select organisation or event",
|
|
2365
2406
|
className,
|
|
2366
|
-
|
|
2367
|
-
|
|
2407
|
+
onOrganisationSelect,
|
|
2408
|
+
onEventSelect,
|
|
2409
|
+
showNoItemsMessage = true,
|
|
2368
2410
|
showRetryButton = true,
|
|
2369
|
-
|
|
2370
|
-
|
|
2411
|
+
compact = false,
|
|
2412
|
+
disabled = false,
|
|
2413
|
+
showOrganisations = true,
|
|
2414
|
+
showEvents = true
|
|
2371
2415
|
}) {
|
|
2416
|
+
const {
|
|
2417
|
+
organisations,
|
|
2418
|
+
selectedOrganisation,
|
|
2419
|
+
isLoading: orgLoading,
|
|
2420
|
+
error: orgError,
|
|
2421
|
+
refreshOrganisations
|
|
2422
|
+
} = useOrganisations();
|
|
2372
2423
|
const {
|
|
2373
2424
|
events,
|
|
2374
2425
|
selectedEvent,
|
|
2375
|
-
isLoading,
|
|
2376
|
-
error,
|
|
2377
|
-
setSelectedEvent,
|
|
2426
|
+
isLoading: eventLoading,
|
|
2427
|
+
error: eventError,
|
|
2378
2428
|
refreshEvents
|
|
2379
2429
|
} = useEvents();
|
|
2380
|
-
const
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
}
|
|
2430
|
+
const { isSuperAdmin: isSuperAdmin2 } = useRBAC();
|
|
2431
|
+
const isLoading = showOrganisations && orgLoading || showEvents && eventLoading;
|
|
2432
|
+
const hasError = showOrganisations && orgError || showEvents && eventError;
|
|
2433
|
+
const hasItems = showOrganisations && (organisations?.length || 0) > 0 || showEvents && (events?.length || 0) > 0;
|
|
2434
|
+
const currentValue = useMemo5(() => {
|
|
2435
|
+
if (showEvents && selectedEvent) {
|
|
2436
|
+
return `event:${selectedEvent.event_id || selectedEvent.id}`;
|
|
2387
2437
|
}
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
refreshEvents();
|
|
2391
|
-
};
|
|
2392
|
-
const isNextEvent = (event) => {
|
|
2393
|
-
if (!event.event_date) return false;
|
|
2394
|
-
const now = /* @__PURE__ */ new Date();
|
|
2395
|
-
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
2396
|
-
const eventDate = new Date(event.event_date);
|
|
2397
|
-
return eventDate >= today;
|
|
2398
|
-
};
|
|
2399
|
-
const formatEventDate = (dateString) => {
|
|
2400
|
-
const date = new Date(dateString);
|
|
2401
|
-
const today = /* @__PURE__ */ new Date();
|
|
2402
|
-
const tomorrow = new Date(today);
|
|
2403
|
-
tomorrow.setDate(tomorrow.getDate() + 1);
|
|
2404
|
-
const normalizeDate = (d) => {
|
|
2405
|
-
const normalized = new Date(d);
|
|
2406
|
-
normalized.setHours(0, 0, 0, 0);
|
|
2407
|
-
return normalized;
|
|
2408
|
-
};
|
|
2409
|
-
const normalizedDate = normalizeDate(date);
|
|
2410
|
-
const normalizedToday = normalizeDate(today);
|
|
2411
|
-
const normalizedTomorrow = normalizeDate(tomorrow);
|
|
2412
|
-
if (normalizedDate.getTime() === normalizedToday.getTime()) {
|
|
2413
|
-
return "Today";
|
|
2414
|
-
} else if (normalizedDate.getTime() === normalizedTomorrow.getTime()) {
|
|
2415
|
-
return "Tomorrow";
|
|
2416
|
-
} else {
|
|
2417
|
-
return date.toLocaleDateString();
|
|
2438
|
+
if (showOrganisations && selectedOrganisation) {
|
|
2439
|
+
return `org:${selectedOrganisation.id}`;
|
|
2418
2440
|
}
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
const eventsLengthChanged = events.length !== prevEventsLengthRef.current;
|
|
2429
|
-
const selectedEventChanged = selectedEvent?.event_id !== prevSelectedEventIdRef.current;
|
|
2430
|
-
if (eventsLengthChanged) {
|
|
2431
|
-
prevEventsLengthRef.current = events.length;
|
|
2432
|
-
if (events.length > 0) {
|
|
2433
|
-
hasAutoSelectedRef.current = false;
|
|
2441
|
+
return "";
|
|
2442
|
+
}, [showOrganisations, showEvents, selectedOrganisation?.id, selectedEvent]);
|
|
2443
|
+
const handleValueChange = (value) => {
|
|
2444
|
+
if (disabled || isLoading) return;
|
|
2445
|
+
if (value.startsWith("org:") && showOrganisations) {
|
|
2446
|
+
const orgId = value.replace("org:", "");
|
|
2447
|
+
const org = organisations?.find((o) => o.id === orgId);
|
|
2448
|
+
if (org && onOrganisationSelect) {
|
|
2449
|
+
onOrganisationSelect(org);
|
|
2434
2450
|
}
|
|
2435
|
-
}
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
if (
|
|
2439
|
-
|
|
2451
|
+
} else if (value.startsWith("event:") && showEvents) {
|
|
2452
|
+
const eventId = value.replace("event:", "");
|
|
2453
|
+
const event = events?.find((e) => (e.event_id || e.id) === eventId);
|
|
2454
|
+
if (event && onEventSelect) {
|
|
2455
|
+
onEventSelect(event);
|
|
2440
2456
|
}
|
|
2441
2457
|
}
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
if (next) {
|
|
2451
|
-
setSelectedEvent(next);
|
|
2452
|
-
if (onEventChange) onEventChange(next);
|
|
2453
|
-
} else {
|
|
2454
|
-
const mostRecentPast = [...events].filter((e) => {
|
|
2455
|
-
if (!e.event_date) return false;
|
|
2456
|
-
const eventDate = new Date(e.event_date);
|
|
2457
|
-
const startOfEventDate = new Date(eventDate.getFullYear(), eventDate.getMonth(), eventDate.getDate()).getTime();
|
|
2458
|
-
return startOfEventDate < startOfToday;
|
|
2459
|
-
}).sort((a, b) => new Date(b.event_date).getTime() - new Date(a.event_date).getTime())[0];
|
|
2460
|
-
if (mostRecentPast) {
|
|
2461
|
-
setSelectedEvent(mostRecentPast);
|
|
2462
|
-
if (onEventChange) onEventChange(mostRecentPast);
|
|
2463
|
-
}
|
|
2458
|
+
};
|
|
2459
|
+
const handleRetry = async () => {
|
|
2460
|
+
try {
|
|
2461
|
+
if (showOrganisations && orgError) {
|
|
2462
|
+
await refreshOrganisations();
|
|
2463
|
+
}
|
|
2464
|
+
if (showEvents && eventError) {
|
|
2465
|
+
await refreshEvents();
|
|
2464
2466
|
}
|
|
2467
|
+
} catch (error) {
|
|
2468
|
+
logger.error("ContextSelector", "Failed to refresh:", error);
|
|
2465
2469
|
}
|
|
2466
|
-
}
|
|
2467
|
-
if (isLoading) {
|
|
2470
|
+
};
|
|
2471
|
+
if (isLoading && !hasItems) {
|
|
2472
|
+
const loadingText = compact ? "Loading..." : showOrganisations && showEvents ? "Loading organisations and events..." : showOrganisations ? "Loading organisations..." : "Loading events...";
|
|
2468
2473
|
return /* @__PURE__ */ jsxs8("div", { className: `flex items-center gap-2 ${className}`, children: [
|
|
2469
2474
|
/* @__PURE__ */ jsx13(LoadingSpinner, { size: "sm" }),
|
|
2470
|
-
/* @__PURE__ */ jsx13("span", { className: "text-sm text-muted-foreground", children:
|
|
2475
|
+
/* @__PURE__ */ jsx13("span", { className: "text-sm text-muted-foreground", children: loadingText })
|
|
2471
2476
|
] });
|
|
2472
2477
|
}
|
|
2473
|
-
if (
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
/* @__PURE__ */ jsx13("span", { children: error.message }),
|
|
2478
|
-
showRetryButton && /* @__PURE__ */ jsxs8(
|
|
2479
|
-
Button,
|
|
2480
|
-
{
|
|
2481
|
-
variant: "outline",
|
|
2482
|
-
size: "sm",
|
|
2483
|
-
onClick: handleRetry,
|
|
2484
|
-
className: "ml-2",
|
|
2485
|
-
children: [
|
|
2486
|
-
/* @__PURE__ */ jsx13(RefreshCw, { className: "size-3 mr-1" }),
|
|
2487
|
-
"Retry"
|
|
2488
|
-
]
|
|
2489
|
-
}
|
|
2490
|
-
)
|
|
2491
|
-
] })
|
|
2492
|
-
] }) });
|
|
2493
|
-
}
|
|
2494
|
-
if (events.length === 0) {
|
|
2495
|
-
if (showNoEventsMessage) {
|
|
2496
|
-
return /* @__PURE__ */ jsx13("div", { className, children: /* @__PURE__ */ jsxs8(Alert, { variant: "inline", children: [
|
|
2497
|
-
/* @__PURE__ */ jsx13(AlertCircle, { className: "size-4 text-acc-700" }),
|
|
2498
|
-
/* @__PURE__ */ jsxs8(AlertDescription, { className: "flex items-center justify-between", children: [
|
|
2499
|
-
/* @__PURE__ */ jsx13("span", { children: "No events available." }),
|
|
2500
|
-
showRetryButton && /* @__PURE__ */ jsxs8(
|
|
2501
|
-
Button,
|
|
2502
|
-
{
|
|
2503
|
-
variant: "outline",
|
|
2504
|
-
size: "sm",
|
|
2505
|
-
onClick: handleRetry,
|
|
2506
|
-
className: "ml-2",
|
|
2507
|
-
children: [
|
|
2508
|
-
/* @__PURE__ */ jsx13(RefreshCw, { className: "size-3 mr-1" }),
|
|
2509
|
-
"Refresh"
|
|
2510
|
-
]
|
|
2511
|
-
}
|
|
2512
|
-
)
|
|
2513
|
-
] })
|
|
2514
|
-
] }) });
|
|
2515
|
-
}
|
|
2516
|
-
return null;
|
|
2517
|
-
}
|
|
2518
|
-
return /* @__PURE__ */ jsxs8(
|
|
2519
|
-
Select,
|
|
2520
|
-
{
|
|
2521
|
-
value: selectedEvent ? selectedEvent.event_id || selectedEvent.id : "",
|
|
2522
|
-
onValueChange: handleValueChange,
|
|
2523
|
-
className,
|
|
2524
|
-
children: [
|
|
2525
|
-
/* @__PURE__ */ jsx13(SelectTrigger, { className: "text-left", variant: "outline", children: /* @__PURE__ */ jsx13(SelectValue, { placeholder, children: selectedEvent && /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
|
|
2526
|
-
/* @__PURE__ */ jsx13(Calendar2, { className: "size-4 flex-shrink-0" }),
|
|
2527
|
-
/* @__PURE__ */ jsx13("span", { className: "truncate", children: selectedEvent.event_name }),
|
|
2528
|
-
selectedEvent.event_date && /* @__PURE__ */ jsxs8("span", { className: "text-xs text-muted-foreground flex-shrink-0", children: [
|
|
2529
|
-
"(",
|
|
2530
|
-
formatEventDate(selectedEvent.event_date),
|
|
2531
|
-
")"
|
|
2532
|
-
] })
|
|
2533
|
-
] }) }) }),
|
|
2534
|
-
/* @__PURE__ */ jsx13(SelectContent, { children: sortedEvents.map((event) => {
|
|
2535
|
-
const isNext = isNextEvent(event);
|
|
2536
|
-
const isSelected = selectedEvent && (selectedEvent.event_id === event.event_id || selectedEvent.id === event.id);
|
|
2537
|
-
return /* @__PURE__ */ jsx13(
|
|
2538
|
-
SelectItem,
|
|
2539
|
-
{
|
|
2540
|
-
value: event.event_id || event.id,
|
|
2541
|
-
className: "flex items-center justify-between",
|
|
2542
|
-
children: /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2 w-full", children: [
|
|
2543
|
-
showNextEventIndicator && isNext && /* @__PURE__ */ jsx13(Star, { className: "size-3 text-acc-500" }),
|
|
2544
|
-
/* @__PURE__ */ jsxs8("div", { className: "flex-1", children: [
|
|
2545
|
-
/* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
|
|
2546
|
-
/* @__PURE__ */ jsx13("span", { className: isSelected ? "font-semibold" : "", children: event.event_name }),
|
|
2547
|
-
isSelected && /* @__PURE__ */ jsx13("span", { className: "text-xs bg-primary text-primary-foreground px-1 rounded", children: "Current" })
|
|
2548
|
-
] }),
|
|
2549
|
-
showEventDetails && event.event_date && /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
|
|
2550
|
-
/* @__PURE__ */ jsx13(Calendar2, { className: "size-3" }),
|
|
2551
|
-
/* @__PURE__ */ jsx13("span", { children: formatEventDate(event.event_date) }),
|
|
2552
|
-
showNextEventIndicator && isNext && /* @__PURE__ */ jsx13("span", { className: "text-acc-600 font-medium", children: "(Next)" })
|
|
2553
|
-
] }),
|
|
2554
|
-
showEventDetails && event.event_venue && /* @__PURE__ */ jsxs8("div", { className: "text-xs text-muted-foreground", children: [
|
|
2555
|
-
"\u{1F4CD} ",
|
|
2556
|
-
event.event_venue
|
|
2557
|
-
] })
|
|
2558
|
-
] })
|
|
2559
|
-
] })
|
|
2560
|
-
},
|
|
2561
|
-
event.event_id || event.id
|
|
2562
|
-
);
|
|
2563
|
-
}) })
|
|
2564
|
-
]
|
|
2478
|
+
if (hasError) {
|
|
2479
|
+
const errorMessages = [];
|
|
2480
|
+
if (showOrganisations && orgError) {
|
|
2481
|
+
errorMessages.push(`Failed to load organisations: ${orgError.message}`);
|
|
2565
2482
|
}
|
|
2566
|
-
|
|
2567
|
-
}
|
|
2568
|
-
|
|
2569
|
-
// src/components/OrganisationSelector/OrganisationSelector.tsx
|
|
2570
|
-
import { useState as useState8, useCallback as useCallback8, useMemo as useMemo6 } from "react";
|
|
2571
|
-
import { RefreshCw as RefreshCw2, AlertCircle as AlertCircle2, Building2, Shield } from "lucide-react";
|
|
2572
|
-
import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2573
|
-
function OrganisationSelector({
|
|
2574
|
-
placeholder = "Select organisation",
|
|
2575
|
-
className,
|
|
2576
|
-
onOrganisationChange,
|
|
2577
|
-
showNoOrganisationsMessage = true,
|
|
2578
|
-
showRetryButton = true,
|
|
2579
|
-
showRole = false,
|
|
2580
|
-
compact = false,
|
|
2581
|
-
disabled = false
|
|
2582
|
-
}) {
|
|
2583
|
-
const [isLoading, setIsLoading] = useState8(false);
|
|
2584
|
-
const [switchError, setSwitchError] = useState8(null);
|
|
2585
|
-
const {
|
|
2586
|
-
organisations,
|
|
2587
|
-
selectedOrganisation,
|
|
2588
|
-
isLoading: orgLoading,
|
|
2589
|
-
error: orgError,
|
|
2590
|
-
switchOrganisation,
|
|
2591
|
-
getUserRole,
|
|
2592
|
-
validateOrganisationAccess,
|
|
2593
|
-
refreshOrganisations
|
|
2594
|
-
} = useOrganisations();
|
|
2595
|
-
const handleOrganisationChange = useCallback8(async (orgId) => {
|
|
2596
|
-
if (disabled || isLoading) return;
|
|
2597
|
-
setSwitchError(null);
|
|
2598
|
-
setIsLoading(true);
|
|
2599
|
-
try {
|
|
2600
|
-
if (!validateOrganisationAccess(orgId)) {
|
|
2601
|
-
throw new Error("You do not have access to this organisation");
|
|
2602
|
-
}
|
|
2603
|
-
await switchOrganisation(orgId);
|
|
2604
|
-
const newOrganisation = organisations.find((org) => org.id === orgId);
|
|
2605
|
-
if (newOrganisation && onOrganisationChange) {
|
|
2606
|
-
onOrganisationChange(newOrganisation);
|
|
2607
|
-
}
|
|
2608
|
-
} catch (error) {
|
|
2609
|
-
logger.error("OrganisationSelector", "Failed to switch organisation:", error);
|
|
2610
|
-
setSwitchError(error instanceof Error ? error.message : "Failed to switch organisation");
|
|
2611
|
-
} finally {
|
|
2612
|
-
setIsLoading(false);
|
|
2613
|
-
}
|
|
2614
|
-
}, [
|
|
2615
|
-
disabled,
|
|
2616
|
-
isLoading,
|
|
2617
|
-
validateOrganisationAccess,
|
|
2618
|
-
switchOrganisation,
|
|
2619
|
-
organisations,
|
|
2620
|
-
onOrganisationChange
|
|
2621
|
-
]);
|
|
2622
|
-
const handleRetry = useCallback8(async () => {
|
|
2623
|
-
setIsLoading(true);
|
|
2624
|
-
setSwitchError(null);
|
|
2625
|
-
try {
|
|
2626
|
-
await refreshOrganisations();
|
|
2627
|
-
} catch (error) {
|
|
2628
|
-
logger.error("OrganisationSelector", "Failed to refresh organisations:", error);
|
|
2629
|
-
setSwitchError("Failed to refresh organisations");
|
|
2630
|
-
} finally {
|
|
2631
|
-
setIsLoading(false);
|
|
2483
|
+
if (showEvents && eventError) {
|
|
2484
|
+
errorMessages.push(`Failed to load events: ${eventError.message}`);
|
|
2632
2485
|
}
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
/* @__PURE__ */ jsx14("span", { className: "text-sm text-muted-foreground", children: compact ? "Loading..." : "Loading organisations..." })
|
|
2638
|
-
] });
|
|
2639
|
-
}
|
|
2640
|
-
if (orgError) {
|
|
2641
|
-
return /* @__PURE__ */ jsxs9("div", { className: `space-y-2 ${className}`, children: [
|
|
2642
|
-
/* @__PURE__ */ jsxs9(Alert, { variant: "destructive", children: [
|
|
2643
|
-
/* @__PURE__ */ jsx14(AlertCircle2, { className: "size-4" }),
|
|
2644
|
-
/* @__PURE__ */ jsxs9(AlertDescription, { children: [
|
|
2645
|
-
"Failed to load organisations: ",
|
|
2646
|
-
orgError.message
|
|
2647
|
-
] })
|
|
2486
|
+
return /* @__PURE__ */ jsxs8("div", { className: `space-y-2 ${className}`, children: [
|
|
2487
|
+
/* @__PURE__ */ jsxs8(Alert, { variant: "destructive", children: [
|
|
2488
|
+
/* @__PURE__ */ jsx13(AlertCircle, { className: "size-4" }),
|
|
2489
|
+
/* @__PURE__ */ jsx13(AlertDescription, { children: errorMessages.join(" ") })
|
|
2648
2490
|
] }),
|
|
2649
|
-
showRetryButton && /* @__PURE__ */
|
|
2491
|
+
showRetryButton && /* @__PURE__ */ jsxs8(
|
|
2650
2492
|
Button,
|
|
2651
2493
|
{
|
|
2652
2494
|
variant: "outline",
|
|
@@ -2655,21 +2497,22 @@ function OrganisationSelector({
|
|
|
2655
2497
|
disabled: isLoading,
|
|
2656
2498
|
className: "w-full",
|
|
2657
2499
|
children: [
|
|
2658
|
-
/* @__PURE__ */
|
|
2500
|
+
/* @__PURE__ */ jsx13(RefreshCw, { className: `size-4 mr-2 ${isLoading ? "animate-spin" : ""}` }),
|
|
2659
2501
|
"Retry"
|
|
2660
2502
|
]
|
|
2661
2503
|
}
|
|
2662
2504
|
)
|
|
2663
2505
|
] });
|
|
2664
2506
|
}
|
|
2665
|
-
if (
|
|
2666
|
-
if (
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
/* @__PURE__ */
|
|
2507
|
+
if (!hasItems) {
|
|
2508
|
+
if (showNoItemsMessage) {
|
|
2509
|
+
const noItemsText = showOrganisations && showEvents ? "No organisations or events available. Please contact your administrator." : showOrganisations ? "No organisations available. Please contact your administrator." : "No events available. Please contact your administrator.";
|
|
2510
|
+
return /* @__PURE__ */ jsxs8("div", { className: `space-y-2 ${className}`, children: [
|
|
2511
|
+
/* @__PURE__ */ jsxs8(Alert, { children: [
|
|
2512
|
+
/* @__PURE__ */ jsx13(AlertCircle, { className: "size-4" }),
|
|
2513
|
+
/* @__PURE__ */ jsx13(AlertDescription, { children: noItemsText })
|
|
2671
2514
|
] }),
|
|
2672
|
-
showRetryButton && /* @__PURE__ */
|
|
2515
|
+
showRetryButton && /* @__PURE__ */ jsxs8(
|
|
2673
2516
|
Button,
|
|
2674
2517
|
{
|
|
2675
2518
|
variant: "outline",
|
|
@@ -2678,7 +2521,7 @@ function OrganisationSelector({
|
|
|
2678
2521
|
disabled: isLoading,
|
|
2679
2522
|
className: "w-full",
|
|
2680
2523
|
children: [
|
|
2681
|
-
/* @__PURE__ */
|
|
2524
|
+
/* @__PURE__ */ jsx13(RefreshCw, { className: `size-4 mr-2 ${isLoading ? "animate-spin" : ""}` }),
|
|
2682
2525
|
"Check Again"
|
|
2683
2526
|
]
|
|
2684
2527
|
}
|
|
@@ -2687,74 +2530,103 @@ function OrganisationSelector({
|
|
|
2687
2530
|
}
|
|
2688
2531
|
return null;
|
|
2689
2532
|
}
|
|
2690
|
-
const
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2533
|
+
const displayValue = useMemo5(() => {
|
|
2534
|
+
if (showEvents && selectedEvent) {
|
|
2535
|
+
return /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
|
|
2536
|
+
/* @__PURE__ */ jsx13(Calendar2, { className: "size-4 flex-shrink-0" }),
|
|
2537
|
+
/* @__PURE__ */ jsx13("span", { className: "truncate", children: selectedEvent.event_name })
|
|
2538
|
+
] });
|
|
2539
|
+
}
|
|
2540
|
+
if (showOrganisations && selectedOrganisation) {
|
|
2541
|
+
return /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
|
|
2542
|
+
/* @__PURE__ */ jsx13(Building2, { className: "size-4 flex-shrink-0" }),
|
|
2543
|
+
/* @__PURE__ */ jsx13("span", { className: "truncate", children: selectedOrganisation.display_name })
|
|
2544
|
+
] });
|
|
2545
|
+
}
|
|
2546
|
+
return null;
|
|
2547
|
+
}, [showOrganisations, showEvents, selectedOrganisation, selectedEvent]);
|
|
2548
|
+
const effectivePlaceholder = useMemo5(() => {
|
|
2549
|
+
if (placeholder !== "Select organisation or event") {
|
|
2550
|
+
return placeholder;
|
|
2551
|
+
}
|
|
2552
|
+
if (showOrganisations && showEvents) {
|
|
2553
|
+
return "Select organisation or event";
|
|
2554
|
+
}
|
|
2555
|
+
if (showOrganisations) {
|
|
2556
|
+
return "Select organisation";
|
|
2557
|
+
}
|
|
2558
|
+
if (showEvents) {
|
|
2559
|
+
return "Select event";
|
|
2560
|
+
}
|
|
2561
|
+
return placeholder;
|
|
2562
|
+
}, [placeholder, showOrganisations, showEvents]);
|
|
2563
|
+
return /* @__PURE__ */ jsx13("div", { className, "data-testid": "context-selector", children: /* @__PURE__ */ jsxs8(
|
|
2564
|
+
Select,
|
|
2565
|
+
{
|
|
2566
|
+
value: currentValue,
|
|
2567
|
+
onValueChange: handleValueChange,
|
|
2568
|
+
disabled: disabled || isLoading,
|
|
2569
|
+
children: [
|
|
2570
|
+
/* @__PURE__ */ jsx13(
|
|
2571
|
+
SelectTrigger,
|
|
2572
|
+
{
|
|
2573
|
+
className: "text-left",
|
|
2574
|
+
variant: "outline",
|
|
2575
|
+
children: /* @__PURE__ */ jsx13(SelectValue, { placeholder: effectivePlaceholder, children: displayValue })
|
|
2576
|
+
}
|
|
2577
|
+
),
|
|
2578
|
+
/* @__PURE__ */ jsxs8(SelectContent, { children: [
|
|
2579
|
+
showOrganisations && organisations && organisations.length > 0 && /* @__PURE__ */ jsxs8(Fragment6, { children: [
|
|
2580
|
+
/* @__PURE__ */ jsxs8(SelectGroup, { children: [
|
|
2581
|
+
/* @__PURE__ */ jsx13(SelectLabel, { children: "Organisations" }),
|
|
2582
|
+
organisations.map((org) => /* @__PURE__ */ jsx13(
|
|
2583
|
+
SelectItem,
|
|
2584
|
+
{
|
|
2585
|
+
value: `org:${org.id}`,
|
|
2586
|
+
children: /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
|
|
2587
|
+
/* @__PURE__ */ jsx13(Building2, { className: "size-4" }),
|
|
2588
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex flex-col", children: [
|
|
2589
|
+
/* @__PURE__ */ jsx13("span", { className: "font-medium", children: org.display_name }),
|
|
2590
|
+
!compact && org.description && /* @__PURE__ */ jsx13("span", { className: "text-xs text-muted-foreground truncate max-w-40", children: org.description })
|
|
2591
|
+
] })
|
|
2592
|
+
] })
|
|
2593
|
+
},
|
|
2594
|
+
org.id
|
|
2595
|
+
))
|
|
2596
|
+
] }),
|
|
2597
|
+
showEvents && events && events.length > 0 && /* @__PURE__ */ jsx13(SelectSeparator, {})
|
|
2598
|
+
] }),
|
|
2599
|
+
showEvents && events && events.length > 0 && /* @__PURE__ */ jsxs8(SelectGroup, { children: [
|
|
2600
|
+
/* @__PURE__ */ jsx13(SelectLabel, { children: "Events" }),
|
|
2601
|
+
events.map((event) => /* @__PURE__ */ jsx13(
|
|
2721
2602
|
SelectItem,
|
|
2722
2603
|
{
|
|
2723
|
-
value:
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
/* @__PURE__ */
|
|
2729
|
-
/* @__PURE__ */ jsxs9("div", { className: "flex flex-col", children: [
|
|
2730
|
-
/* @__PURE__ */ jsx14("span", { className: "font-medium", children: org.display_name }),
|
|
2731
|
-
!compact && org.description && /* @__PURE__ */ jsx14("span", { className: "text-xs text-muted-foreground truncate max-w-40", children: org.description })
|
|
2732
|
-
] })
|
|
2733
|
-
] }),
|
|
2734
|
-
showRole && /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-1 ml-4", children: [
|
|
2735
|
-
/* @__PURE__ */ jsx14(Shield, { className: "size-3 text-muted-foreground" }),
|
|
2736
|
-
/* @__PURE__ */ jsx14("span", { className: "text-xs text-muted-foreground capitalize", children: userRole?.replace("_", " ") || "No Role" })
|
|
2604
|
+
value: `event:${event.event_id || event.id}`,
|
|
2605
|
+
children: /* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
|
|
2606
|
+
/* @__PURE__ */ jsx13(Calendar2, { className: "size-4" }),
|
|
2607
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex flex-col", children: [
|
|
2608
|
+
/* @__PURE__ */ jsx13("span", { className: "font-medium", children: event.event_name }),
|
|
2609
|
+
!compact && event.event_date && /* @__PURE__ */ jsx13("span", { className: "text-xs text-muted-foreground", children: new Date(event.event_date).toLocaleDateString() })
|
|
2737
2610
|
] })
|
|
2738
2611
|
] })
|
|
2739
2612
|
},
|
|
2740
|
-
|
|
2741
|
-
)
|
|
2742
|
-
|
|
2743
|
-
]
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
] });
|
|
2613
|
+
event.event_id || event.id
|
|
2614
|
+
))
|
|
2615
|
+
] })
|
|
2616
|
+
] })
|
|
2617
|
+
]
|
|
2618
|
+
}
|
|
2619
|
+
) });
|
|
2748
2620
|
}
|
|
2749
2621
|
|
|
2750
2622
|
// src/components/PasswordChange/PasswordChangeForm.tsx
|
|
2751
|
-
import { useState as
|
|
2752
|
-
import { jsx as
|
|
2623
|
+
import { useState as useState8 } from "react";
|
|
2624
|
+
import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2753
2625
|
function PasswordChangeForm({ onSubmit, className }) {
|
|
2754
|
-
const [newPassword, setNewPassword] =
|
|
2755
|
-
const [confirmPassword, setConfirmPassword] =
|
|
2756
|
-
const [error, setError] =
|
|
2757
|
-
const [isSubmitting, setIsSubmitting] =
|
|
2626
|
+
const [newPassword, setNewPassword] = useState8("");
|
|
2627
|
+
const [confirmPassword, setConfirmPassword] = useState8("");
|
|
2628
|
+
const [error, setError] = useState8(null);
|
|
2629
|
+
const [isSubmitting, setIsSubmitting] = useState8(false);
|
|
2758
2630
|
const handleSubmit = async (e) => {
|
|
2759
2631
|
e.preventDefault();
|
|
2760
2632
|
setError(null);
|
|
@@ -2779,11 +2651,11 @@ function PasswordChangeForm({ onSubmit, className }) {
|
|
|
2779
2651
|
setIsSubmitting(false);
|
|
2780
2652
|
}
|
|
2781
2653
|
};
|
|
2782
|
-
return /* @__PURE__ */
|
|
2783
|
-
error && /* @__PURE__ */
|
|
2784
|
-
/* @__PURE__ */
|
|
2785
|
-
/* @__PURE__ */
|
|
2786
|
-
/* @__PURE__ */
|
|
2654
|
+
return /* @__PURE__ */ jsxs9("form", { onSubmit: handleSubmit, className: cn("space-y-4", className), children: [
|
|
2655
|
+
error && /* @__PURE__ */ jsx14("div", { role: "alert", children: error }),
|
|
2656
|
+
/* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
|
|
2657
|
+
/* @__PURE__ */ jsx14(Label, { htmlFor: "new-password", children: "New Password" }),
|
|
2658
|
+
/* @__PURE__ */ jsx14(
|
|
2787
2659
|
Input,
|
|
2788
2660
|
{
|
|
2789
2661
|
id: "new-password",
|
|
@@ -2795,9 +2667,9 @@ function PasswordChangeForm({ onSubmit, className }) {
|
|
|
2795
2667
|
}
|
|
2796
2668
|
)
|
|
2797
2669
|
] }),
|
|
2798
|
-
/* @__PURE__ */
|
|
2799
|
-
/* @__PURE__ */
|
|
2800
|
-
/* @__PURE__ */
|
|
2670
|
+
/* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
|
|
2671
|
+
/* @__PURE__ */ jsx14(Label, { htmlFor: "confirm-password", children: "Confirm Password" }),
|
|
2672
|
+
/* @__PURE__ */ jsx14(
|
|
2801
2673
|
Input,
|
|
2802
2674
|
{
|
|
2803
2675
|
id: "confirm-password",
|
|
@@ -2809,7 +2681,7 @@ function PasswordChangeForm({ onSubmit, className }) {
|
|
|
2809
2681
|
}
|
|
2810
2682
|
)
|
|
2811
2683
|
] }),
|
|
2812
|
-
/* @__PURE__ */
|
|
2684
|
+
/* @__PURE__ */ jsx14(
|
|
2813
2685
|
Button,
|
|
2814
2686
|
{
|
|
2815
2687
|
type: "submit",
|
|
@@ -2822,9 +2694,9 @@ function PasswordChangeForm({ onSubmit, className }) {
|
|
|
2822
2694
|
}
|
|
2823
2695
|
|
|
2824
2696
|
// src/components/UserMenu/UserMenu.tsx
|
|
2825
|
-
import React12, { useCallback as
|
|
2697
|
+
import React12, { useCallback as useCallback8, useMemo as useMemo6, useState as useState9 } from "react";
|
|
2826
2698
|
import { ChevronDown, LogOut, KeyRound } from "lucide-react";
|
|
2827
|
-
import { jsx as
|
|
2699
|
+
import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2828
2700
|
var UserMenu = React12.memo(function UserMenu2({
|
|
2829
2701
|
user,
|
|
2830
2702
|
onSignOut,
|
|
@@ -2832,8 +2704,8 @@ var UserMenu = React12.memo(function UserMenu2({
|
|
|
2832
2704
|
className,
|
|
2833
2705
|
showAvatar = true
|
|
2834
2706
|
}) {
|
|
2835
|
-
const [isPasswordDialogOpen, setPasswordDialogOpen] =
|
|
2836
|
-
const userInfo =
|
|
2707
|
+
const [isPasswordDialogOpen, setPasswordDialogOpen] = useState9(false);
|
|
2708
|
+
const userInfo = useMemo6(() => {
|
|
2837
2709
|
if (!user) return null;
|
|
2838
2710
|
return {
|
|
2839
2711
|
email: user.email,
|
|
@@ -2842,16 +2714,16 @@ var UserMenu = React12.memo(function UserMenu2({
|
|
|
2842
2714
|
initial: (user.user_metadata?.display_name || user.user_metadata?.full_name || user.email || "U").charAt(0).toUpperCase()
|
|
2843
2715
|
};
|
|
2844
2716
|
}, [user]);
|
|
2845
|
-
const handleSignOut =
|
|
2717
|
+
const handleSignOut = useCallback8(async () => {
|
|
2846
2718
|
if (onSignOut) await onSignOut();
|
|
2847
2719
|
}, [onSignOut]);
|
|
2848
2720
|
if (!user || !userInfo) {
|
|
2849
2721
|
return null;
|
|
2850
2722
|
}
|
|
2851
|
-
return /* @__PURE__ */
|
|
2852
|
-
/* @__PURE__ */
|
|
2853
|
-
/* @__PURE__ */
|
|
2854
|
-
showAvatar && /* @__PURE__ */
|
|
2723
|
+
return /* @__PURE__ */ jsxs10(Dialog, { open: isPasswordDialogOpen, onOpenChange: setPasswordDialogOpen, children: [
|
|
2724
|
+
/* @__PURE__ */ jsxs10(Select, { className, children: [
|
|
2725
|
+
/* @__PURE__ */ jsx15(SelectTrigger, { asChild: true, children: /* @__PURE__ */ jsxs10(Button, { variant: "outline", className: "flex items-center gap-2", "aria-label": userInfo.displayName, children: [
|
|
2726
|
+
showAvatar && /* @__PURE__ */ jsx15(
|
|
2855
2727
|
Avatar,
|
|
2856
2728
|
{
|
|
2857
2729
|
src: userInfo.avatarUrl,
|
|
@@ -2860,29 +2732,30 @@ var UserMenu = React12.memo(function UserMenu2({
|
|
|
2860
2732
|
className: "size-7"
|
|
2861
2733
|
}
|
|
2862
2734
|
),
|
|
2863
|
-
/* @__PURE__ */
|
|
2864
|
-
/* @__PURE__ */
|
|
2735
|
+
/* @__PURE__ */ jsx15("span", { children: userInfo.displayName }),
|
|
2736
|
+
/* @__PURE__ */ jsx15(ChevronDown, { className: "size-4" })
|
|
2865
2737
|
] }) }),
|
|
2866
|
-
/* @__PURE__ */
|
|
2867
|
-
/* @__PURE__ */
|
|
2868
|
-
|
|
2869
|
-
/* @__PURE__ */
|
|
2738
|
+
/* @__PURE__ */ jsxs10(SelectContent, { children: [
|
|
2739
|
+
/* @__PURE__ */ jsx15(SelectLabel, { className: "font-normal", children: /* @__PURE__ */ jsxs10("li", { className: "pt-2", children: [
|
|
2740
|
+
userInfo.displayName,
|
|
2741
|
+
/* @__PURE__ */ jsx15("br", {}),
|
|
2742
|
+
/* @__PURE__ */ jsx15("span", { className: "text-muted-foreground", children: userInfo.email })
|
|
2870
2743
|
] }) }),
|
|
2871
|
-
/* @__PURE__ */
|
|
2872
|
-
/* @__PURE__ */
|
|
2873
|
-
/* @__PURE__ */
|
|
2874
|
-
/* @__PURE__ */
|
|
2744
|
+
/* @__PURE__ */ jsx15(SelectSeparator, {}),
|
|
2745
|
+
/* @__PURE__ */ jsx15(DialogTrigger, { asChild: true, children: /* @__PURE__ */ jsxs10(SelectItem, { value: "change-password", children: [
|
|
2746
|
+
/* @__PURE__ */ jsx15(KeyRound, { className: "mr-2 size-4" }),
|
|
2747
|
+
/* @__PURE__ */ jsx15("span", { children: "Change Password" })
|
|
2875
2748
|
] }) }),
|
|
2876
|
-
/* @__PURE__ */
|
|
2877
|
-
/* @__PURE__ */
|
|
2878
|
-
/* @__PURE__ */
|
|
2749
|
+
/* @__PURE__ */ jsxs10(SelectItem, { value: "sign-out", onClick: handleSignOut, children: [
|
|
2750
|
+
/* @__PURE__ */ jsx15(LogOut, { className: "mr-2 size-4" }),
|
|
2751
|
+
/* @__PURE__ */ jsx15("span", { children: "Sign out" })
|
|
2879
2752
|
] })
|
|
2880
2753
|
] })
|
|
2881
2754
|
] }),
|
|
2882
|
-
/* @__PURE__ */
|
|
2883
|
-
/* @__PURE__ */
|
|
2884
|
-
/* @__PURE__ */
|
|
2885
|
-
/* @__PURE__ */
|
|
2755
|
+
/* @__PURE__ */ jsx15(DialogOverlay, {}),
|
|
2756
|
+
/* @__PURE__ */ jsxs10(DialogContent, { className, children: [
|
|
2757
|
+
/* @__PURE__ */ jsx15(DialogHeader, { children: /* @__PURE__ */ jsx15(DialogTitle, { children: "Change Password" }) }),
|
|
2758
|
+
/* @__PURE__ */ jsx15(
|
|
2886
2759
|
PasswordChangeForm,
|
|
2887
2760
|
{
|
|
2888
2761
|
onSubmit: async ({ newPassword, confirmPassword }) => {
|
|
@@ -2901,60 +2774,54 @@ var UserMenu = React12.memo(function UserMenu2({
|
|
|
2901
2774
|
] });
|
|
2902
2775
|
});
|
|
2903
2776
|
var UserMenuLoading = React12.memo(function UserMenuLoading2() {
|
|
2904
|
-
return /* @__PURE__ */
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
] });
|
|
2777
|
+
return /* @__PURE__ */ jsxs10(
|
|
2778
|
+
Button,
|
|
2779
|
+
{
|
|
2780
|
+
type: "button",
|
|
2781
|
+
disabled: true,
|
|
2782
|
+
variant: "outline",
|
|
2783
|
+
className: "flex items-center space-x-2",
|
|
2784
|
+
"aria-label": "Loading user menu",
|
|
2785
|
+
children: [
|
|
2786
|
+
/* @__PURE__ */ jsx15(LoadingSpinner, { size: "sm", className: "inline-block mr-2" }),
|
|
2787
|
+
/* @__PURE__ */ jsx15("span", { className: "truncate max-w-[150px]", children: "Loading..." }),
|
|
2788
|
+
/* @__PURE__ */ jsx15(ChevronDown, { className: "w-4 h-4 text-muted-foreground" })
|
|
2789
|
+
]
|
|
2790
|
+
}
|
|
2791
|
+
);
|
|
2920
2792
|
});
|
|
2921
2793
|
UserMenu.Loading = UserMenuLoading;
|
|
2922
2794
|
|
|
2923
2795
|
// src/components/NavigationMenu/NavigationMenu.tsx
|
|
2924
|
-
import * as
|
|
2796
|
+
import * as React14 from "react";
|
|
2925
2797
|
import { ChevronDown as ChevronDown2 } from "lucide-react";
|
|
2926
|
-
|
|
2927
|
-
|
|
2798
|
+
|
|
2799
|
+
// src/components/NavigationMenu/useNavigationFiltering.ts
|
|
2800
|
+
import * as React13 from "react";
|
|
2801
|
+
function useNavigationFiltering({
|
|
2928
2802
|
items,
|
|
2929
|
-
mode = "dropdown",
|
|
2930
|
-
currentPath,
|
|
2931
|
-
onNavigate,
|
|
2932
|
-
className,
|
|
2933
|
-
disabled = false,
|
|
2934
|
-
buttonText = "Menu",
|
|
2935
|
-
showIcons = true,
|
|
2936
|
-
navigationLabel = "Main navigation",
|
|
2937
|
-
// NEW: Phase 2 - Enhanced Security Features
|
|
2938
|
-
strictMode = true,
|
|
2939
|
-
auditLog = true,
|
|
2940
|
-
onNavigationAccessDenied,
|
|
2941
|
-
onStrictModeViolation,
|
|
2942
2803
|
itemsPreFiltered = false,
|
|
2943
|
-
|
|
2944
|
-
}
|
|
2945
|
-
const [
|
|
2946
|
-
const
|
|
2804
|
+
auditLog = true
|
|
2805
|
+
}) {
|
|
2806
|
+
const [resolvedAppId, setResolvedAppId] = React13.useState(void 0);
|
|
2807
|
+
const previousFilteredItemsRef = React13.useRef([]);
|
|
2947
2808
|
let authContext = null;
|
|
2948
2809
|
try {
|
|
2949
2810
|
authContext = useUnifiedAuth();
|
|
2950
2811
|
} catch (error) {
|
|
2951
|
-
logger.warn(
|
|
2812
|
+
logger.warn(
|
|
2813
|
+
"NavigationMenu",
|
|
2814
|
+
"useUnifiedAuth not available, running in unauthenticated mode"
|
|
2815
|
+
);
|
|
2952
2816
|
}
|
|
2953
2817
|
let rbacContext = null;
|
|
2954
2818
|
try {
|
|
2955
2819
|
rbacContext = useRBAC();
|
|
2956
2820
|
} catch (error) {
|
|
2957
|
-
logger.warn(
|
|
2821
|
+
logger.warn(
|
|
2822
|
+
"NavigationMenu",
|
|
2823
|
+
"useRBAC not available, permission filtering disabled"
|
|
2824
|
+
);
|
|
2958
2825
|
}
|
|
2959
2826
|
const eventLoadingRaw = authContext?.eventLoading;
|
|
2960
2827
|
const eventLoading = eventLoadingRaw ?? false;
|
|
@@ -2964,11 +2831,9 @@ var NavigationMenu = React13.forwardRef(({
|
|
|
2964
2831
|
const { selectedOrganisation } = authContext || {};
|
|
2965
2832
|
const { resolvedScope, isLoading: scopeLoading, error: scopeError } = useResolvedScope({
|
|
2966
2833
|
supabase: itemsPreFiltered ? null : supabase || null,
|
|
2967
|
-
// Skip expensive resolution if pre-filtered
|
|
2968
2834
|
selectedOrganisationId: itemsPreFiltered ? null : selectedOrganisation?.id || null,
|
|
2969
2835
|
selectedEventId: itemsPreFiltered ? null : selectedEvent?.event_id || null
|
|
2970
2836
|
});
|
|
2971
|
-
const [resolvedAppId, setResolvedAppId] = React13.useState(void 0);
|
|
2972
2837
|
React13.useEffect(() => {
|
|
2973
2838
|
if (!scopeLoading && !resolvedScope?.appId && selectedOrganisation?.id && authContext?.appName && authContext?.user?.id && !resolvedAppId) {
|
|
2974
2839
|
if (!authContext.user || !authContext.appName) {
|
|
@@ -2976,7 +2841,7 @@ var NavigationMenu = React13.forwardRef(({
|
|
|
2976
2841
|
}
|
|
2977
2842
|
const userId2 = authContext.user.id;
|
|
2978
2843
|
const appName = authContext.appName;
|
|
2979
|
-
import("./api-
|
|
2844
|
+
import("./api-IAGWF3ZG.js").then(({ resolveAppContext }) => {
|
|
2980
2845
|
resolveAppContext({
|
|
2981
2846
|
userId: userId2,
|
|
2982
2847
|
appName
|
|
@@ -2984,11 +2849,19 @@ var NavigationMenu = React13.forwardRef(({
|
|
|
2984
2849
|
if (result?.appId) {
|
|
2985
2850
|
setResolvedAppId(result.appId);
|
|
2986
2851
|
}
|
|
2987
|
-
}).catch((
|
|
2852
|
+
}).catch(() => {
|
|
2988
2853
|
});
|
|
2854
|
+
}).catch(() => {
|
|
2989
2855
|
});
|
|
2990
2856
|
}
|
|
2991
|
-
}, [
|
|
2857
|
+
}, [
|
|
2858
|
+
scopeLoading,
|
|
2859
|
+
resolvedScope?.appId,
|
|
2860
|
+
selectedOrganisation?.id,
|
|
2861
|
+
authContext?.appName,
|
|
2862
|
+
authContext?.user?.id,
|
|
2863
|
+
resolvedAppId
|
|
2864
|
+
]);
|
|
2992
2865
|
const effectiveScope = React13.useMemo(() => {
|
|
2993
2866
|
if (resolvedScope?.organisationId) {
|
|
2994
2867
|
return resolvedScope;
|
|
@@ -3019,17 +2892,17 @@ var NavigationMenu = React13.forwardRef(({
|
|
|
3019
2892
|
};
|
|
3020
2893
|
}, [scopeKey, effectiveScope]);
|
|
3021
2894
|
const userId = authContext?.user?.id || "";
|
|
3022
|
-
const {
|
|
2895
|
+
const {
|
|
2896
|
+
permissions: permissionMap,
|
|
2897
|
+
hasAnyPermission,
|
|
2898
|
+
isLoading: permissionsLoading,
|
|
2899
|
+
error: permissionsError
|
|
2900
|
+
} = usePermissions(
|
|
3023
2901
|
itemsPreFiltered ? null : userId,
|
|
3024
|
-
// Pass null to trigger early return (empty string would wait 3s)
|
|
3025
2902
|
itemsPreFiltered ? void 0 : stableScope.organisationId,
|
|
3026
|
-
// Pass undefined to skip timeout
|
|
3027
2903
|
itemsPreFiltered ? void 0 : stableScope.eventId,
|
|
3028
|
-
// Skip if pre-filtered
|
|
3029
2904
|
itemsPreFiltered ? void 0 : stableScope.appId
|
|
3030
|
-
// Skip if pre-filtered
|
|
3031
2905
|
);
|
|
3032
|
-
const previousFilteredItemsRef = React13.useRef([]);
|
|
3033
2906
|
const filteredItems = React13.useMemo(() => {
|
|
3034
2907
|
if (itemsPreFiltered && items && items.length > 0) {
|
|
3035
2908
|
const visibleItems = (items || []).filter((item) => !item.meta?.hidden);
|
|
@@ -3059,9 +2932,13 @@ var NavigationMenu = React13.forwardRef(({
|
|
|
3059
2932
|
return [];
|
|
3060
2933
|
}
|
|
3061
2934
|
if (permissionsError) {
|
|
3062
|
-
logger.warn(
|
|
3063
|
-
|
|
3064
|
-
|
|
2935
|
+
logger.warn(
|
|
2936
|
+
"NavigationMenu",
|
|
2937
|
+
"Permission check error - showing no items for security",
|
|
2938
|
+
{
|
|
2939
|
+
permissionsError: permissionsError?.message
|
|
2940
|
+
}
|
|
2941
|
+
);
|
|
3065
2942
|
return [];
|
|
3066
2943
|
}
|
|
3067
2944
|
if (!permissionMap || Object.keys(permissionMap).length === 0) {
|
|
@@ -3087,7 +2964,7 @@ var NavigationMenu = React13.forwardRef(({
|
|
|
3087
2964
|
if (item.permissions && item.permissions.length > 0 && !item.href) {
|
|
3088
2965
|
const permissions = item.permissions.filter((p) => typeof p === "string").map((p) => p);
|
|
3089
2966
|
if (permissions.length > 0) {
|
|
3090
|
-
const hasPermission = hasAnyPermission(permissions);
|
|
2967
|
+
const hasPermission = hasAnyPermission?.(permissions);
|
|
3091
2968
|
if (!hasPermission) {
|
|
3092
2969
|
return false;
|
|
3093
2970
|
}
|
|
@@ -3119,13 +2996,12 @@ var NavigationMenu = React13.forwardRef(({
|
|
|
3119
2996
|
if (typeof item.accessLevel === "string") {
|
|
3120
2997
|
const accessLevel = item.accessLevel.toLowerCase();
|
|
3121
2998
|
const userEventRole = rbacContext.eventAppRole;
|
|
3122
|
-
if (rbacContext.isSuperAdmin) {
|
|
3123
|
-
} else {
|
|
2999
|
+
if (!rbacContext.isSuperAdmin) {
|
|
3124
3000
|
const roleToAccessLevel = {
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3001
|
+
viewer: "viewer",
|
|
3002
|
+
participant: "participant",
|
|
3003
|
+
planner: "planner",
|
|
3004
|
+
event_admin: "admin"
|
|
3129
3005
|
};
|
|
3130
3006
|
const userAccessLevel = userEventRole ? roleToAccessLevel[userEventRole] || "viewer" : null;
|
|
3131
3007
|
const levelHierarchy = {
|
|
@@ -3178,7 +3054,6 @@ var NavigationMenu = React13.forwardRef(({
|
|
|
3178
3054
|
}, [
|
|
3179
3055
|
items,
|
|
3180
3056
|
itemsPreFiltered,
|
|
3181
|
-
// Add itemsPreFiltered to dependencies
|
|
3182
3057
|
authContext,
|
|
3183
3058
|
rbacContext,
|
|
3184
3059
|
permissionMap,
|
|
@@ -3189,13 +3064,48 @@ var NavigationMenu = React13.forwardRef(({
|
|
|
3189
3064
|
resolvedScope,
|
|
3190
3065
|
effectiveScope,
|
|
3191
3066
|
auditLog,
|
|
3192
|
-
// Add event context state to dependencies so we re-check permissions when event context becomes available
|
|
3193
3067
|
eventLoadingRaw,
|
|
3194
3068
|
eventLoading,
|
|
3195
3069
|
selectedEvent,
|
|
3196
3070
|
orgContextReady,
|
|
3197
|
-
selectedOrganisation?.id
|
|
3071
|
+
selectedOrganisation?.id,
|
|
3072
|
+
permissionsError,
|
|
3073
|
+
stableScope.organisationId,
|
|
3074
|
+
stableScope.eventId,
|
|
3075
|
+
stableScope.appId
|
|
3198
3076
|
]);
|
|
3077
|
+
return {
|
|
3078
|
+
authContext,
|
|
3079
|
+
rbacContext,
|
|
3080
|
+
filteredItems,
|
|
3081
|
+
permissionMap,
|
|
3082
|
+
hasAnyPermission: hasAnyPermission || null
|
|
3083
|
+
};
|
|
3084
|
+
}
|
|
3085
|
+
|
|
3086
|
+
// src/components/NavigationMenu/NavigationMenu.tsx
|
|
3087
|
+
import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
3088
|
+
var NavigationMenu = React14.forwardRef(({
|
|
3089
|
+
items,
|
|
3090
|
+
mode = "dropdown",
|
|
3091
|
+
currentPath,
|
|
3092
|
+
onNavigate,
|
|
3093
|
+
className,
|
|
3094
|
+
disabled = false,
|
|
3095
|
+
buttonText = "Menu",
|
|
3096
|
+
showIcons = true,
|
|
3097
|
+
navigationLabel = "Main navigation",
|
|
3098
|
+
// NEW: Phase 2 - Enhanced Security Features
|
|
3099
|
+
strictMode = true,
|
|
3100
|
+
auditLog = true,
|
|
3101
|
+
onNavigationAccessDenied,
|
|
3102
|
+
onStrictModeViolation,
|
|
3103
|
+
itemsPreFiltered = false,
|
|
3104
|
+
...props
|
|
3105
|
+
}, ref) => {
|
|
3106
|
+
const [expandedItems, setExpandedItems] = React14.useState(/* @__PURE__ */ new Set());
|
|
3107
|
+
const buttonRef = React14.useRef(null);
|
|
3108
|
+
const { authContext, rbacContext, filteredItems, permissionMap, hasAnyPermission } = useNavigationFiltering({ items, itemsPreFiltered, auditLog });
|
|
3199
3109
|
const handleHierarchicalKeyDown = (event, item) => {
|
|
3200
3110
|
switch (event.key) {
|
|
3201
3111
|
case "Enter":
|
|
@@ -3317,8 +3227,8 @@ var NavigationMenu = React13.forwardRef(({
|
|
|
3317
3227
|
const hasChildren = item.children && item.children.length > 0;
|
|
3318
3228
|
const isExpanded = expandedItems.has(item.id);
|
|
3319
3229
|
const itemIsActive = isActiveItem(item);
|
|
3320
|
-
return /* @__PURE__ */
|
|
3321
|
-
/* @__PURE__ */
|
|
3230
|
+
return /* @__PURE__ */ jsx16("li", { role: "none", children: hasChildren ? /* @__PURE__ */ jsxs11("div", { children: [
|
|
3231
|
+
/* @__PURE__ */ jsxs11(
|
|
3322
3232
|
"button",
|
|
3323
3233
|
{
|
|
3324
3234
|
onClick: () => toggleExpanded(item.id),
|
|
@@ -3327,21 +3237,21 @@ var NavigationMenu = React13.forwardRef(({
|
|
|
3327
3237
|
"aria-controls": `submenu-${item.id}`,
|
|
3328
3238
|
"aria-current": itemIsActive ? "page" : void 0,
|
|
3329
3239
|
children: [
|
|
3330
|
-
/* @__PURE__ */
|
|
3331
|
-
/* @__PURE__ */
|
|
3240
|
+
/* @__PURE__ */ jsx16("span", { children: item.label }),
|
|
3241
|
+
/* @__PURE__ */ jsx16(ChevronDown2, { "aria-hidden": "true" })
|
|
3332
3242
|
]
|
|
3333
3243
|
}
|
|
3334
3244
|
),
|
|
3335
|
-
isExpanded && item.children && /* @__PURE__ */
|
|
3245
|
+
isExpanded && item.children && /* @__PURE__ */ jsx16(
|
|
3336
3246
|
"ul",
|
|
3337
3247
|
{
|
|
3338
3248
|
id: `submenu-${item.id}`,
|
|
3339
3249
|
role: "menu",
|
|
3340
3250
|
"aria-label": `${item.label} submenu`,
|
|
3341
|
-
children: item.children.map((child) => /* @__PURE__ */
|
|
3251
|
+
children: item.children.map((child) => /* @__PURE__ */ jsx16(React14.Fragment, { children: renderHierarchicalItem(child, level + 1) }, child.id))
|
|
3342
3252
|
}
|
|
3343
3253
|
)
|
|
3344
|
-
] }) : /* @__PURE__ */
|
|
3254
|
+
] }) : /* @__PURE__ */ jsx16(
|
|
3345
3255
|
"a",
|
|
3346
3256
|
{
|
|
3347
3257
|
href: item.href || "#",
|
|
@@ -3359,26 +3269,26 @@ var NavigationMenu = React13.forwardRef(({
|
|
|
3359
3269
|
) });
|
|
3360
3270
|
};
|
|
3361
3271
|
if (mode === "dropdown") {
|
|
3362
|
-
return /* @__PURE__ */
|
|
3272
|
+
return /* @__PURE__ */ jsxs11(
|
|
3363
3273
|
Select,
|
|
3364
3274
|
{
|
|
3365
3275
|
onValueChange: handleNavigationSelect,
|
|
3366
3276
|
className,
|
|
3367
3277
|
"data-testid": "navigation-menu-root",
|
|
3368
3278
|
children: [
|
|
3369
|
-
/* @__PURE__ */
|
|
3279
|
+
/* @__PURE__ */ jsx16(
|
|
3370
3280
|
SelectTrigger,
|
|
3371
3281
|
{
|
|
3372
3282
|
ref: buttonRef,
|
|
3373
3283
|
disabled,
|
|
3374
3284
|
"aria-label": buttonText,
|
|
3375
3285
|
"data-testid": "navigation-menu-trigger",
|
|
3376
|
-
children: /* @__PURE__ */
|
|
3286
|
+
children: /* @__PURE__ */ jsx16(SelectValue, { placeholder: buttonText })
|
|
3377
3287
|
}
|
|
3378
3288
|
),
|
|
3379
|
-
/* @__PURE__ */
|
|
3289
|
+
/* @__PURE__ */ jsx16(SelectContent, { children: filteredItems.map((item) => {
|
|
3380
3290
|
const isActive = isActiveItem(item);
|
|
3381
|
-
return /* @__PURE__ */
|
|
3291
|
+
return /* @__PURE__ */ jsx16(
|
|
3382
3292
|
SelectItem,
|
|
3383
3293
|
{
|
|
3384
3294
|
value: item.id,
|
|
@@ -3393,14 +3303,14 @@ var NavigationMenu = React13.forwardRef(({
|
|
|
3393
3303
|
}
|
|
3394
3304
|
);
|
|
3395
3305
|
}
|
|
3396
|
-
return /* @__PURE__ */
|
|
3306
|
+
return /* @__PURE__ */ jsx16(
|
|
3397
3307
|
"nav",
|
|
3398
3308
|
{
|
|
3399
3309
|
ref,
|
|
3400
3310
|
className,
|
|
3401
3311
|
"aria-label": navigationLabel,
|
|
3402
3312
|
...props,
|
|
3403
|
-
children: /* @__PURE__ */
|
|
3313
|
+
children: /* @__PURE__ */ jsx16("ul", { role: "menubar", children: filteredItems.map((item) => /* @__PURE__ */ jsx16(React14.Fragment, { children: renderHierarchicalItem(item, 0) }, item.id)) })
|
|
3404
3314
|
}
|
|
3405
3315
|
);
|
|
3406
3316
|
});
|
|
@@ -3408,7 +3318,7 @@ NavigationMenu.displayName = "NavigationMenu";
|
|
|
3408
3318
|
|
|
3409
3319
|
// src/components/Header/Header.tsx
|
|
3410
3320
|
import { Link } from "react-router-dom";
|
|
3411
|
-
import { jsx as
|
|
3321
|
+
import { jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3412
3322
|
function Header({
|
|
3413
3323
|
logoUrl,
|
|
3414
3324
|
logoAlt = "Logo",
|
|
@@ -3420,54 +3330,43 @@ function Header({
|
|
|
3420
3330
|
actions,
|
|
3421
3331
|
userMenu,
|
|
3422
3332
|
className,
|
|
3423
|
-
|
|
3424
|
-
|
|
3333
|
+
showContextSelector = true,
|
|
3334
|
+
showOrganisations = true,
|
|
3335
|
+
showEvents = true,
|
|
3425
3336
|
showUserMenu = true,
|
|
3426
3337
|
currentPath,
|
|
3427
3338
|
onNavigate,
|
|
3428
3339
|
logoHref
|
|
3429
3340
|
}) {
|
|
3430
|
-
const
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
}
|
|
3435
|
-
return /* @__PURE__ */ jsx18(
|
|
3436
|
-
OrganisationSelector,
|
|
3437
|
-
{
|
|
3438
|
-
placeholder: "Select organisation",
|
|
3439
|
-
className: "w-64",
|
|
3440
|
-
"data-testid": "org-selector",
|
|
3441
|
-
compact: true
|
|
3442
|
-
}
|
|
3443
|
-
);
|
|
3444
|
-
};
|
|
3445
|
-
return /* @__PURE__ */ jsx18("header", { className: cn(
|
|
3341
|
+
const shouldShowContextSelector = showContextSelector !== false;
|
|
3342
|
+
const { switchOrganisation } = useOrganisations();
|
|
3343
|
+
const { events, setSelectedEvent } = useEvents();
|
|
3344
|
+
return /* @__PURE__ */ jsx17("header", { className: cn(
|
|
3446
3345
|
"w-full border-b border-main-200 h-16 shadow-sm bg-main-100 ",
|
|
3447
3346
|
className
|
|
3448
|
-
), role: "banner", children: /* @__PURE__ */
|
|
3449
|
-
logo ? logoHref ? /* @__PURE__ */
|
|
3347
|
+
), role: "banner", children: /* @__PURE__ */ jsxs12("nav", { className: "px-4 w-[min(var(--app-width),100%)] mx-auto grid grid-cols-[auto_1fr_auto_auto_auto_auto] items-center gap-4 h-full", children: [
|
|
3348
|
+
logo ? logoHref ? /* @__PURE__ */ jsx17(Link, { to: logoHref, className: "cursor-pointer hover:opacity-80 transition-opacity", children: logo }) : logo : logoUrl ? logoHref ? /* @__PURE__ */ jsx17(Link, { to: logoHref, className: "cursor-pointer hover:opacity-80 transition-opacity", children: /* @__PURE__ */ jsx17(
|
|
3450
3349
|
"img",
|
|
3451
3350
|
{
|
|
3452
3351
|
src: logoUrl,
|
|
3453
3352
|
alt: logoAlt || "Logo",
|
|
3454
3353
|
className: "h-[2.15rem] w-auto max-w-[200px] object-contain rounded-md shadow-md bg-transparent"
|
|
3455
3354
|
}
|
|
3456
|
-
) }) : /* @__PURE__ */
|
|
3355
|
+
) }) : /* @__PURE__ */ jsx17(
|
|
3457
3356
|
"img",
|
|
3458
3357
|
{
|
|
3459
3358
|
src: logoUrl,
|
|
3460
3359
|
alt: logoAlt || "Logo",
|
|
3461
3360
|
className: "h-[2.15rem] w-auto max-w-[200px] object-contain rounded-md shadow-md bg-transparent"
|
|
3462
3361
|
}
|
|
3463
|
-
) : logoHref ? /* @__PURE__ */
|
|
3362
|
+
) : logoHref ? /* @__PURE__ */ jsx17(Link, { to: logoHref, className: "cursor-pointer hover:opacity-80 transition-opacity", children: /* @__PURE__ */ jsx17(
|
|
3464
3363
|
"img",
|
|
3465
3364
|
{
|
|
3466
3365
|
src: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' fill='%23000'/%3E%3Ctext x='16' y='20' text-anchor='middle' fill='white' font-family='Arial' font-size='14' font-weight='bold'%3EL%3C/text%3E%3C/svg%3E",
|
|
3467
3366
|
alt: logoAlt || "Logo",
|
|
3468
3367
|
className: "size-8 shadow-md"
|
|
3469
3368
|
}
|
|
3470
|
-
) }) : /* @__PURE__ */
|
|
3369
|
+
) }) : /* @__PURE__ */ jsx17(
|
|
3471
3370
|
"img",
|
|
3472
3371
|
{
|
|
3473
3372
|
src: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' fill='%23000'/%3E%3Ctext x='16' y='20' text-anchor='middle' fill='white' font-family='Arial' font-size='14' font-weight='bold'%3EL%3C/text%3E%3C/svg%3E",
|
|
@@ -3475,7 +3374,7 @@ function Header({
|
|
|
3475
3374
|
className: "size-8 shadow-md"
|
|
3476
3375
|
}
|
|
3477
3376
|
),
|
|
3478
|
-
navItems && navItems.length > 0 && /* @__PURE__ */
|
|
3377
|
+
navItems && navItems.length > 0 && /* @__PURE__ */ jsx17(
|
|
3479
3378
|
NavigationMenu,
|
|
3480
3379
|
{
|
|
3481
3380
|
items: navItems,
|
|
@@ -3486,33 +3385,44 @@ function Header({
|
|
|
3486
3385
|
itemsPreFiltered: true
|
|
3487
3386
|
}
|
|
3488
3387
|
),
|
|
3489
|
-
/* @__PURE__ */
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
"
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
}
|
|
3508
|
-
|
|
3509
|
-
|
|
3388
|
+
shouldShowContextSelector ? /* @__PURE__ */ jsx17(
|
|
3389
|
+
ContextSelector,
|
|
3390
|
+
{
|
|
3391
|
+
placeholder: "Select organisation or event",
|
|
3392
|
+
className: cn(
|
|
3393
|
+
"w-96",
|
|
3394
|
+
// Adjust width based on whether actions exist
|
|
3395
|
+
actions ? "col-span-1" : "col-span-2"
|
|
3396
|
+
),
|
|
3397
|
+
showOrganisations,
|
|
3398
|
+
showEvents,
|
|
3399
|
+
onOrganisationSelect: async (org) => {
|
|
3400
|
+
setSelectedEvent(null);
|
|
3401
|
+
await switchOrganisation(org.id);
|
|
3402
|
+
},
|
|
3403
|
+
onEventSelect: (event) => {
|
|
3404
|
+
const fullEvent = events.find((e) => (e.event_id || e.id) === (event.event_id || event.id));
|
|
3405
|
+
setSelectedEvent(fullEvent || event);
|
|
3406
|
+
},
|
|
3407
|
+
compact: true
|
|
3408
|
+
}
|
|
3409
|
+
) : null,
|
|
3410
|
+
actions,
|
|
3411
|
+
showUserMenu && (userMenu ? userMenu : /* @__PURE__ */ jsx17(
|
|
3412
|
+
UserMenu,
|
|
3413
|
+
{
|
|
3414
|
+
user: user || null,
|
|
3415
|
+
onSignOut,
|
|
3416
|
+
onChangePassword,
|
|
3417
|
+
className: "w-70"
|
|
3418
|
+
}
|
|
3419
|
+
))
|
|
3510
3420
|
] }) });
|
|
3511
3421
|
}
|
|
3512
3422
|
|
|
3513
3423
|
// src/components/Footer/Footer.tsx
|
|
3514
|
-
import
|
|
3515
|
-
import { Fragment as
|
|
3424
|
+
import React15 from "react";
|
|
3425
|
+
import { Fragment as Fragment8, jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
3516
3426
|
var FooterComponent = ({
|
|
3517
3427
|
companyName = "Solvera Solutions Pty Ltd",
|
|
3518
3428
|
year = (/* @__PURE__ */ new Date()).getFullYear(),
|
|
@@ -3523,28 +3433,29 @@ var FooterComponent = ({
|
|
|
3523
3433
|
children
|
|
3524
3434
|
}) => {
|
|
3525
3435
|
const copyrightText = copyright || `\xA9 Copyright 2022\u2013${year} all rights reserved, ${companyName}.`;
|
|
3526
|
-
return /* @__PURE__ */
|
|
3527
|
-
logo && /* @__PURE__ */
|
|
3528
|
-
children && /* @__PURE__ */
|
|
3529
|
-
/* @__PURE__ */
|
|
3530
|
-
links && links.length > 0 && /* @__PURE__ */
|
|
3436
|
+
return /* @__PURE__ */ jsx18("footer", { className: cn("mt-8 py-6 flex justify-center border-t border-border bg-main-100", className), children: /* @__PURE__ */ jsxs13("section", { className: "px-4 w-[min(var(--app-width),100%)] mx-auto text-center", children: [
|
|
3437
|
+
logo && /* @__PURE__ */ jsx18("img", { src: logo, alt: "Logo", className: "h-8 w-auto" }),
|
|
3438
|
+
children && /* @__PURE__ */ jsx18(Fragment8, { children }),
|
|
3439
|
+
/* @__PURE__ */ jsx18("span", { className: "text-muted-foreground", children: copyrightText }),
|
|
3440
|
+
links && links.length > 0 && /* @__PURE__ */ jsx18("ul", { className: "flex gap-4 mt-2 md:mt-0", children: links.map((link, index) => /* @__PURE__ */ jsx18("li", { children: /* @__PURE__ */ jsx18("a", { href: link.href, className: "text-muted-foreground hover:text-foreground", children: link.label }) }, index)) })
|
|
3531
3441
|
] }) });
|
|
3532
3442
|
};
|
|
3533
3443
|
FooterComponent.displayName = "Footer";
|
|
3534
|
-
var Footer =
|
|
3444
|
+
var Footer = React15.memo(FooterComponent);
|
|
3535
3445
|
Footer.displayName = "Footer";
|
|
3536
3446
|
|
|
3537
3447
|
// src/components/PaceAppLayout/PaceAppLayout.tsx
|
|
3538
|
-
import { useState as useState12, useEffect as
|
|
3448
|
+
import { useState as useState12, useEffect as useEffect7, useMemo as useMemo8 } from "react";
|
|
3539
3449
|
import { Outlet, useNavigate, useLocation } from "react-router-dom";
|
|
3540
|
-
import { Fragment as
|
|
3450
|
+
import { Fragment as Fragment9, jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
3541
3451
|
var EMPTY_PAGE_ID_MAPPING = {};
|
|
3542
3452
|
var EMPTY_ROUTE_PERMISSIONS = {};
|
|
3543
3453
|
function PaceAppLayout({
|
|
3544
3454
|
appName,
|
|
3545
3455
|
navItems,
|
|
3546
|
-
|
|
3547
|
-
|
|
3456
|
+
showContextSelector = true,
|
|
3457
|
+
showOrganisations = true,
|
|
3458
|
+
showEvents = true,
|
|
3548
3459
|
headerActions,
|
|
3549
3460
|
customLogo,
|
|
3550
3461
|
logoHref = "/dashboard",
|
|
@@ -3581,7 +3492,7 @@ function PaceAppLayout({
|
|
|
3581
3492
|
const { isSuperAdmin: isSuperAdminFromRBAC, isLoading: rbacLoading } = useRBAC();
|
|
3582
3493
|
const [isSuperAdminDirect, setIsSuperAdminDirect] = useState12(false);
|
|
3583
3494
|
const [isCheckingSuperAdminDirect, setIsCheckingSuperAdminDirect] = useState12(false);
|
|
3584
|
-
|
|
3495
|
+
useEffect7(() => {
|
|
3585
3496
|
const checkSuperAdminDirect = async () => {
|
|
3586
3497
|
if (!user?.id) {
|
|
3587
3498
|
setIsSuperAdminDirect(false);
|
|
@@ -3594,8 +3505,8 @@ function PaceAppLayout({
|
|
|
3594
3505
|
}
|
|
3595
3506
|
setIsCheckingSuperAdminDirect(true);
|
|
3596
3507
|
try {
|
|
3597
|
-
const
|
|
3598
|
-
setIsSuperAdminDirect(
|
|
3508
|
+
const superAdminStatus2 = await isSuperAdmin(user.id);
|
|
3509
|
+
setIsSuperAdminDirect(superAdminStatus2);
|
|
3599
3510
|
} catch (error) {
|
|
3600
3511
|
logger.error("PaceAppLayout", "Error checking super admin status directly", { userId: user?.id, error });
|
|
3601
3512
|
setIsSuperAdminDirect(false);
|
|
@@ -3624,7 +3535,7 @@ function PaceAppLayout({
|
|
|
3624
3535
|
const scopeOrgId = resolvedScope?.organisationId || selectedOrganisation?.id || "";
|
|
3625
3536
|
const scopeEventId = resolvedScope?.eventId || selectedEvent?.event_id || void 0;
|
|
3626
3537
|
const scopeAppId = resolvedScope?.appId || resolvedAppId || void 0;
|
|
3627
|
-
const scope =
|
|
3538
|
+
const scope = useMemo8(() => {
|
|
3628
3539
|
const newScope = {};
|
|
3629
3540
|
if (scopeOrgId) {
|
|
3630
3541
|
newScope.organisationId = scopeOrgId;
|
|
@@ -3637,19 +3548,19 @@ function PaceAppLayout({
|
|
|
3637
3548
|
}
|
|
3638
3549
|
return newScope;
|
|
3639
3550
|
}, [scopeOrgId, scopeEventId, scopeAppId]);
|
|
3640
|
-
const defaultNavItems =
|
|
3551
|
+
const defaultNavItems = useMemo8(() => [
|
|
3641
3552
|
{ id: "home", label: "Home", href: "/", icon: "Home" },
|
|
3642
3553
|
{ id: "dashboard", label: "Dashboard", href: "/dashboard", icon: "LayoutDashboard" },
|
|
3643
3554
|
{ id: "settings", label: "Settings", href: "/settings", icon: "Settings" },
|
|
3644
3555
|
{ id: "ui-showcase", label: "UI Showcase", href: "/ui-showcase", icon: "Component" },
|
|
3645
3556
|
{ id: "data-table-showcase", label: "DataTable Showcase", href: "/data-table-showcase", icon: "Table" }
|
|
3646
3557
|
], []);
|
|
3647
|
-
const baseMenuItems =
|
|
3648
|
-
const currentRoutePermission =
|
|
3558
|
+
const baseMenuItems = useMemo8(() => navItems || defaultNavItems, [navItems]);
|
|
3559
|
+
const currentRoutePermission = useMemo8(() => {
|
|
3649
3560
|
const currentPath = location.pathname;
|
|
3650
3561
|
return routePermissions[currentPath] || defaultPermission;
|
|
3651
3562
|
}, [location.pathname, routePermissions, defaultPermission]);
|
|
3652
|
-
const currentPageId =
|
|
3563
|
+
const currentPageId = useMemo8(() => {
|
|
3653
3564
|
const currentPath = location.pathname;
|
|
3654
3565
|
if (pageIdMapping[currentPath]) {
|
|
3655
3566
|
return pageIdMapping[currentPath];
|
|
@@ -3657,7 +3568,7 @@ function PaceAppLayout({
|
|
|
3657
3568
|
const pathSegments = currentPath.slice(1).split("/").filter(Boolean);
|
|
3658
3569
|
return pathSegments[0] || "";
|
|
3659
3570
|
}, [location.pathname, pageIdMapping]);
|
|
3660
|
-
const currentPermission =
|
|
3571
|
+
const currentPermission = useMemo8(() => {
|
|
3661
3572
|
if (!enforcePermissions || !currentPageId) {
|
|
3662
3573
|
return "";
|
|
3663
3574
|
}
|
|
@@ -3665,6 +3576,7 @@ function PaceAppLayout({
|
|
|
3665
3576
|
return permissionString;
|
|
3666
3577
|
}, [enforcePermissions, currentRoutePermission, currentPageId]);
|
|
3667
3578
|
const shouldCheckPermission = enforcePermissions && !!currentPermission && !!currentPageId;
|
|
3579
|
+
const superAdminStatus = isSuperAdminFromRBAC ? true : isCheckingSuperAdminDirect ? null : isSuperAdminDirect;
|
|
3668
3580
|
const { can: canFromHook, isLoading: isCheckingPermission, error: permissionError } = useCan(
|
|
3669
3581
|
user?.id || "",
|
|
3670
3582
|
scope,
|
|
@@ -3672,12 +3584,14 @@ function PaceAppLayout({
|
|
|
3672
3584
|
shouldCheckPermission ? currentPageId : "",
|
|
3673
3585
|
true,
|
|
3674
3586
|
// useCache
|
|
3587
|
+
superAdminStatus,
|
|
3588
|
+
// Pass super admin status to avoid duplicate check
|
|
3675
3589
|
appName
|
|
3676
3590
|
// Pass appName for PORTAL/ADMIN special case
|
|
3677
3591
|
);
|
|
3678
3592
|
const can = isSuperAdmin2 ? true : canFromHook;
|
|
3679
3593
|
const hasPermission = enforcePermissions ? can : true;
|
|
3680
|
-
|
|
3594
|
+
useEffect7(() => {
|
|
3681
3595
|
if (!enforcePermissions) {
|
|
3682
3596
|
return;
|
|
3683
3597
|
}
|
|
@@ -3701,7 +3615,7 @@ function PaceAppLayout({
|
|
|
3701
3615
|
}
|
|
3702
3616
|
}, [enforcePermissions, can, isCheckingPermission, isSuperAdmin2, currentPageId, currentRoutePermission, user?.id, strictMode, auditLog, onPageAccessDenied, onStrictModeViolation]);
|
|
3703
3617
|
const [filteredMenuItems, setFilteredMenuItems] = useState12(baseMenuItems);
|
|
3704
|
-
|
|
3618
|
+
useEffect7(() => {
|
|
3705
3619
|
let isMounted = true;
|
|
3706
3620
|
const filterItems = async () => {
|
|
3707
3621
|
if (!user?.id) {
|
|
@@ -3727,7 +3641,7 @@ function PaceAppLayout({
|
|
|
3727
3641
|
return;
|
|
3728
3642
|
}
|
|
3729
3643
|
try {
|
|
3730
|
-
const { isSuperAdmin: checkSuperAdminDynamic } = await import("./api-
|
|
3644
|
+
const { isSuperAdmin: checkSuperAdminDynamic } = await import("./api-IAGWF3ZG.js");
|
|
3731
3645
|
const isSuper = await checkSuperAdminDynamic(user.id);
|
|
3732
3646
|
if (isSuper) {
|
|
3733
3647
|
if (isMounted) {
|
|
@@ -3742,7 +3656,7 @@ function PaceAppLayout({
|
|
|
3742
3656
|
}
|
|
3743
3657
|
}
|
|
3744
3658
|
try {
|
|
3745
|
-
const { getPermissionMap } = await import("./api-
|
|
3659
|
+
const { getPermissionMap } = await import("./api-IAGWF3ZG.js");
|
|
3746
3660
|
const permissionScope = {
|
|
3747
3661
|
organisationId: currentScope.organisationId,
|
|
3748
3662
|
eventId: currentScope.eventId,
|
|
@@ -3753,16 +3667,80 @@ function PaceAppLayout({
|
|
|
3753
3667
|
userId: user.id,
|
|
3754
3668
|
scope: permissionScope
|
|
3755
3669
|
});
|
|
3756
|
-
const
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3670
|
+
const { getPageScopeType } = await import("./api-IAGWF3ZG.js");
|
|
3671
|
+
const effectiveAppId = currentScope.appId || resolvedAppId;
|
|
3672
|
+
const effectiveAppName = appName;
|
|
3673
|
+
const hasEventContext = !!currentScope.eventId;
|
|
3674
|
+
const hasOrgContext = !!currentScope.organisationId;
|
|
3675
|
+
const filtered = await Promise.all(
|
|
3676
|
+
baseMenuItems.map(async (item) => {
|
|
3677
|
+
if (!item.href) return { item, hasAccess: true, matchesScope: true, scopeCheckError: false };
|
|
3678
|
+
const pageId = pageIdMapping[item.href] || (item.href === "/" ? "dashboard" : item.href.slice(1)) || "dashboard";
|
|
3679
|
+
const permission = routePermissions[item.href] || defaultPermission;
|
|
3680
|
+
const fullPermission = permission.includes(":") ? permission : pageId ? `${permission}:page.${pageId}` : permission;
|
|
3681
|
+
const hasAccess = permissionMap["*"] === true || permissionMap[fullPermission] === true;
|
|
3682
|
+
let matchesScope = true;
|
|
3683
|
+
let scopeCheckError = false;
|
|
3684
|
+
if (effectiveAppId || effectiveAppName) {
|
|
3685
|
+
try {
|
|
3686
|
+
const pageScopeType = await getPageScopeType(
|
|
3687
|
+
pageId,
|
|
3688
|
+
effectiveAppId,
|
|
3689
|
+
effectiveAppName
|
|
3690
|
+
);
|
|
3691
|
+
if (hasEventContext) {
|
|
3692
|
+
matchesScope = pageScopeType === "event" || pageScopeType === "both";
|
|
3693
|
+
} else if (hasOrgContext) {
|
|
3694
|
+
matchesScope = pageScopeType === "organisation" || pageScopeType === "both";
|
|
3695
|
+
} else {
|
|
3696
|
+
matchesScope = true;
|
|
3697
|
+
}
|
|
3698
|
+
} catch (error) {
|
|
3699
|
+
scopeCheckError = true;
|
|
3700
|
+
logger.warn("PaceAppLayout", "Failed to get page scope type for navigation filtering", {
|
|
3701
|
+
pageId,
|
|
3702
|
+
href: item.href,
|
|
3703
|
+
contextType: hasEventContext ? "event" : hasOrgContext ? "organisation" : "none",
|
|
3704
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3705
|
+
note: "Allowing page to prevent navigation from disappearing - this may indicate missing scope_type in database"
|
|
3706
|
+
});
|
|
3707
|
+
matchesScope = true;
|
|
3708
|
+
}
|
|
3709
|
+
} else {
|
|
3710
|
+
matchesScope = true;
|
|
3711
|
+
}
|
|
3712
|
+
return { item, hasAccess, matchesScope, scopeCheckError };
|
|
3713
|
+
})
|
|
3714
|
+
);
|
|
3764
3715
|
if (!isMounted) return;
|
|
3765
|
-
const accessibleItems = filtered.filter(({ hasAccess }) => hasAccess).map(({ item }) => item);
|
|
3716
|
+
const accessibleItems = filtered.filter(({ hasAccess, matchesScope }) => hasAccess && matchesScope).map(({ item }) => item);
|
|
3717
|
+
if (accessibleItems.length === 0 && filtered.length > 0) {
|
|
3718
|
+
const itemsWithPermissions = filtered.filter(({ hasAccess }) => hasAccess);
|
|
3719
|
+
const itemsFilteredByScope = filtered.filter(({ hasAccess, matchesScope }) => hasAccess && !matchesScope);
|
|
3720
|
+
const itemsWithScopeErrors = filtered.filter(({ hasAccess, scopeCheckError }) => hasAccess && scopeCheckError);
|
|
3721
|
+
if (itemsWithPermissions.length > 0 && itemsWithScopeErrors.length === itemsWithPermissions.length) {
|
|
3722
|
+
logger.warn("PaceAppLayout", "Scope checking failed for all items - falling back to permission-only filtering", {
|
|
3723
|
+
contextType: hasEventContext ? "event" : hasOrgContext ? "organisation" : "none",
|
|
3724
|
+
totalItems: baseMenuItems.length,
|
|
3725
|
+
itemsWithPermissions: itemsWithPermissions.length,
|
|
3726
|
+
scopeCheckErrorCount: itemsWithScopeErrors.length,
|
|
3727
|
+
note: "Showing items based on permissions only - scope filtering disabled due to errors. This may indicate database issues or missing scope_type values."
|
|
3728
|
+
});
|
|
3729
|
+
const fallbackItems = filtered.filter(({ hasAccess }) => hasAccess).map(({ item }) => item);
|
|
3730
|
+
if (isMounted && fallbackItems.length > 0) {
|
|
3731
|
+
setFilteredMenuItems(fallbackItems);
|
|
3732
|
+
return;
|
|
3733
|
+
}
|
|
3734
|
+
} else if (itemsWithPermissions.length > 0 && itemsFilteredByScope.length === itemsWithPermissions.length) {
|
|
3735
|
+
logger.info("PaceAppLayout", "All navigation items filtered out by scope type", {
|
|
3736
|
+
contextType: hasEventContext ? "event" : hasOrgContext ? "organisation" : "none",
|
|
3737
|
+
totalItems: baseMenuItems.length,
|
|
3738
|
+
itemsWithPermissions: itemsWithPermissions.length,
|
|
3739
|
+
itemsFilteredByScope: itemsFilteredByScope.length,
|
|
3740
|
+
note: "All pages appear to be scoped for a different context type - this is expected behavior. Navigation will be empty until user selects the appropriate context."
|
|
3741
|
+
});
|
|
3742
|
+
}
|
|
3743
|
+
}
|
|
3766
3744
|
setFilteredMenuItems(accessibleItems);
|
|
3767
3745
|
} catch (error) {
|
|
3768
3746
|
logger.error("PaceAppLayout", "Failed to load permission map for navigation filtering", { userId: user?.id, error });
|
|
@@ -3775,8 +3753,8 @@ function PaceAppLayout({
|
|
|
3775
3753
|
return () => {
|
|
3776
3754
|
isMounted = false;
|
|
3777
3755
|
};
|
|
3778
|
-
}, [baseMenuItems, pageIdMapping, routePermissions, defaultPermission, can, user?.id, scope, scopeLoading, contextAppId, resolvedScope?.appId, selectedOrganisation?.id]);
|
|
3779
|
-
|
|
3756
|
+
}, [baseMenuItems, pageIdMapping, routePermissions, defaultPermission, can, user?.id, scope, scopeLoading, contextAppId, resolvedScope?.appId, selectedOrganisation?.id, selectedEvent?.event_id, appName]);
|
|
3757
|
+
useEffect7(() => {
|
|
3780
3758
|
if (!roleBasedRouting || routeConfig.length === 0) return;
|
|
3781
3759
|
let isMounted = true;
|
|
3782
3760
|
const checkRouteAccess = async () => {
|
|
@@ -3798,7 +3776,7 @@ function PaceAppLayout({
|
|
|
3798
3776
|
let hasAccess = true;
|
|
3799
3777
|
if (currentRoute.pageId && currentRoute.permissions && currentRoute.permissions.length > 0) {
|
|
3800
3778
|
try {
|
|
3801
|
-
const { isPermittedCached } = await import("./api-
|
|
3779
|
+
const { isPermittedCached } = await import("./api-IAGWF3ZG.js");
|
|
3802
3780
|
const hasPagePermission = await isPermittedCached({
|
|
3803
3781
|
userId: user?.id || "",
|
|
3804
3782
|
scope,
|
|
@@ -3814,7 +3792,7 @@ function PaceAppLayout({
|
|
|
3814
3792
|
}
|
|
3815
3793
|
}
|
|
3816
3794
|
if (hasAccess && currentRoute.roles && currentRoute.roles.length > 0 && user?.id) {
|
|
3817
|
-
const { useUnifiedAuth: useUnifiedAuth2 } = await import("./UnifiedAuthProvider-
|
|
3795
|
+
const { useUnifiedAuth: useUnifiedAuth2 } = await import("./UnifiedAuthProvider-KAGUYQ4J.js");
|
|
3818
3796
|
hasAccess = true;
|
|
3819
3797
|
}
|
|
3820
3798
|
if (!isMounted) return;
|
|
@@ -3845,53 +3823,67 @@ function PaceAppLayout({
|
|
|
3845
3823
|
};
|
|
3846
3824
|
}, [roleBasedRouting, routeConfig, location.pathname, strictMode, user?.id, fallbackRoute, scope, navigate, auditLog, onRouteAccessDenied, onRouteStrictModeViolation]);
|
|
3847
3825
|
const handleSignOut = async () => {
|
|
3848
|
-
|
|
3826
|
+
try {
|
|
3827
|
+
await signOut();
|
|
3828
|
+
} catch (error) {
|
|
3829
|
+
logger.error("PaceAppLayout", "Failed to sign out", { error: error instanceof Error ? error.message : String(error) });
|
|
3830
|
+
}
|
|
3849
3831
|
};
|
|
3850
3832
|
const handleChangePassword = async (newPassword, confirmPassword) => {
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3833
|
+
try {
|
|
3834
|
+
const result = await updatePassword(newPassword);
|
|
3835
|
+
if (result?.error) {
|
|
3836
|
+
logger.error("PaceAppLayout", "Failed to change password", { error: result.error.message });
|
|
3837
|
+
return {
|
|
3838
|
+
error: {
|
|
3839
|
+
message: result.error.message,
|
|
3840
|
+
code: result.error.name || "PASSWORD_UPDATE_ERROR"
|
|
3841
|
+
}
|
|
3842
|
+
};
|
|
3843
|
+
}
|
|
3844
|
+
return {};
|
|
3845
|
+
} catch (error) {
|
|
3846
|
+
logger.error("PaceAppLayout", "Failed to change password", { error: error instanceof Error ? error.message : String(error) });
|
|
3854
3847
|
return {
|
|
3855
3848
|
error: {
|
|
3856
|
-
message:
|
|
3857
|
-
code:
|
|
3849
|
+
message: error instanceof Error ? error.message : "An unexpected error occurred",
|
|
3850
|
+
code: "PASSWORD_UPDATE_ERROR"
|
|
3858
3851
|
}
|
|
3859
3852
|
};
|
|
3860
3853
|
}
|
|
3861
|
-
return {};
|
|
3862
3854
|
};
|
|
3863
3855
|
if (user?.id && organisationLoading && !isSuperAdmin2 && !isCheckingSuperAdminDirect && !rbacLoading && !selectedOrganisationId) {
|
|
3864
|
-
return /* @__PURE__ */
|
|
3865
|
-
/* @__PURE__ */
|
|
3866
|
-
/* @__PURE__ */
|
|
3856
|
+
return /* @__PURE__ */ jsx19("div", { className: "flex items-center justify-center min-h-screen", children: /* @__PURE__ */ jsxs14("div", { className: "text-center", children: [
|
|
3857
|
+
/* @__PURE__ */ jsx19("div", { className: "animate-spin rounded-full size-8 border-b-2 border-sec-900 mx-auto mb-4" }),
|
|
3858
|
+
/* @__PURE__ */ jsx19("p", { className: "text-sec-600", children: "Loading organisation context..." })
|
|
3867
3859
|
] }) });
|
|
3868
3860
|
}
|
|
3869
3861
|
if (enforcePermissions && isCheckingPermission) {
|
|
3870
|
-
return /* @__PURE__ */
|
|
3871
|
-
/* @__PURE__ */
|
|
3872
|
-
/* @__PURE__ */
|
|
3862
|
+
return /* @__PURE__ */ jsx19("div", { className: "flex items-center justify-center min-h-screen", children: /* @__PURE__ */ jsxs14("div", { className: "text-center", children: [
|
|
3863
|
+
/* @__PURE__ */ jsx19("div", { className: "animate-spin rounded-full size-8 border-b-2 border-sec-900 mx-auto mb-4" }),
|
|
3864
|
+
/* @__PURE__ */ jsx19("p", { className: "text-sec-600", children: "Checking permissions..." })
|
|
3873
3865
|
] }) });
|
|
3874
3866
|
}
|
|
3875
3867
|
if (enforcePermissions && permissionError && !isSuperAdmin2) {
|
|
3876
|
-
return /* @__PURE__ */
|
|
3877
|
-
/* @__PURE__ */
|
|
3878
|
-
/* @__PURE__ */
|
|
3879
|
-
/* @__PURE__ */
|
|
3868
|
+
return /* @__PURE__ */ jsx19("div", { className: "flex items-center justify-center min-h-screen", children: /* @__PURE__ */ jsxs14("div", { className: "text-center", children: [
|
|
3869
|
+
/* @__PURE__ */ jsx19("h2", { className: "text-xl font-semibold text-acc-600 mb-2", children: "Permission Error" }),
|
|
3870
|
+
/* @__PURE__ */ jsx19("p", { className: "text-sec-600 mb-4", children: permissionError.message }),
|
|
3871
|
+
/* @__PURE__ */ jsx19(Button, { onClick: () => navigate("/"), children: "Go Home" })
|
|
3880
3872
|
] }) });
|
|
3881
3873
|
}
|
|
3882
3874
|
if (enforcePermissions && hasPermission === false && !isCheckingSuperAdminDirect && !isSuperAdmin2) {
|
|
3883
3875
|
if (enforcePagePermissions && pagePermissionFallback) {
|
|
3884
|
-
return /* @__PURE__ */
|
|
3876
|
+
return /* @__PURE__ */ jsx19(Fragment9, { children: pagePermissionFallback });
|
|
3885
3877
|
}
|
|
3886
3878
|
if (permissionFallback) {
|
|
3887
|
-
return /* @__PURE__ */
|
|
3879
|
+
return /* @__PURE__ */ jsx19(Fragment9, { children: permissionFallback });
|
|
3888
3880
|
}
|
|
3889
|
-
return /* @__PURE__ */
|
|
3890
|
-
/* @__PURE__ */
|
|
3891
|
-
/* @__PURE__ */
|
|
3892
|
-
/* @__PURE__ */
|
|
3893
|
-
/* @__PURE__ */
|
|
3894
|
-
/* @__PURE__ */
|
|
3881
|
+
return /* @__PURE__ */ jsx19("div", { className: "flex items-center justify-center min-h-screen", children: /* @__PURE__ */ jsxs14("div", { className: "text-center", children: [
|
|
3882
|
+
/* @__PURE__ */ jsx19("h2", { className: "text-xl font-semibold text-acc-600 mb-2", children: "Access Denied" }),
|
|
3883
|
+
/* @__PURE__ */ jsx19("p", { className: "text-sec-600 mb-4", children: "You don't have permission to access this page." }),
|
|
3884
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex gap-2 justify-center", children: [
|
|
3885
|
+
/* @__PURE__ */ jsx19(Button, { onClick: () => navigate("/"), children: "Go Home" }),
|
|
3886
|
+
/* @__PURE__ */ jsx19(
|
|
3895
3887
|
Button,
|
|
3896
3888
|
{
|
|
3897
3889
|
variant: "outline",
|
|
@@ -3905,8 +3897,8 @@ function PaceAppLayout({
|
|
|
3905
3897
|
] })
|
|
3906
3898
|
] }) });
|
|
3907
3899
|
}
|
|
3908
|
-
return /* @__PURE__ */
|
|
3909
|
-
/* @__PURE__ */
|
|
3900
|
+
return /* @__PURE__ */ jsxs14(Fragment9, { children: [
|
|
3901
|
+
/* @__PURE__ */ jsx19(
|
|
3910
3902
|
Header,
|
|
3911
3903
|
{
|
|
3912
3904
|
logo: customLogo || void 0,
|
|
@@ -3925,21 +3917,22 @@ function PaceAppLayout({
|
|
|
3925
3917
|
navigate(item.href);
|
|
3926
3918
|
}
|
|
3927
3919
|
},
|
|
3928
|
-
|
|
3929
|
-
|
|
3920
|
+
showContextSelector,
|
|
3921
|
+
showOrganisations,
|
|
3922
|
+
showEvents,
|
|
3930
3923
|
showUserMenu,
|
|
3931
3924
|
className: headerClassName || "sticky top-0 z-[40] w-full"
|
|
3932
3925
|
}
|
|
3933
3926
|
),
|
|
3934
|
-
/* @__PURE__ */
|
|
3935
|
-
/* @__PURE__ */
|
|
3927
|
+
/* @__PURE__ */ jsx19("main", { className: "px-4 w-[min(var(--app-width),100%)] mx-auto py-8", children: /* @__PURE__ */ jsx19(Outlet, {}) }),
|
|
3928
|
+
/* @__PURE__ */ jsx19(Footer, {})
|
|
3936
3929
|
] });
|
|
3937
3930
|
}
|
|
3938
3931
|
|
|
3939
3932
|
// src/components/PaceLoginPage/PaceLoginPage.tsx
|
|
3940
|
-
import { useEffect as
|
|
3933
|
+
import { useEffect as useEffect8, useState as useState13, useContext as useContext2 } from "react";
|
|
3941
3934
|
import { useNavigate as useNavigate2, useLocation as useLocation2 } from "react-router-dom";
|
|
3942
|
-
import { jsx as
|
|
3935
|
+
import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
3943
3936
|
var PaceLoginPage = ({
|
|
3944
3937
|
appName = "Pace",
|
|
3945
3938
|
onSuccessRedirectPath = "/",
|
|
@@ -3953,16 +3946,16 @@ var PaceLoginPage = ({
|
|
|
3953
3946
|
const [isCheckingAccess, setIsCheckingAccess] = useState13(false);
|
|
3954
3947
|
const eventServiceContext = useContext2(EventServiceContext);
|
|
3955
3948
|
const eventService = eventServiceContext?.eventService || null;
|
|
3956
|
-
|
|
3949
|
+
useEffect8(() => {
|
|
3957
3950
|
clearPalette();
|
|
3958
3951
|
}, []);
|
|
3959
|
-
|
|
3952
|
+
useEffect8(() => {
|
|
3960
3953
|
const isOnLoginPage = location.pathname === "/login" || location.pathname.startsWith("/login");
|
|
3961
3954
|
if (isOnLoginPage) {
|
|
3962
3955
|
clearPalette();
|
|
3963
3956
|
}
|
|
3964
3957
|
}, [location.pathname]);
|
|
3965
|
-
|
|
3958
|
+
useEffect8(() => {
|
|
3966
3959
|
const restoreEvent = async () => {
|
|
3967
3960
|
try {
|
|
3968
3961
|
const isOnLoginPage = window.location.pathname === "/login" || window.location.pathname.startsWith("/login");
|
|
@@ -3977,7 +3970,7 @@ var PaceLoginPage = ({
|
|
|
3977
3970
|
}, 100);
|
|
3978
3971
|
return () => clearTimeout(timeoutId);
|
|
3979
3972
|
}, [eventService]);
|
|
3980
|
-
|
|
3973
|
+
useEffect8(() => {
|
|
3981
3974
|
if (!requireAppAccess || !isAuthenticated || isLoading || !user || !supabase) {
|
|
3982
3975
|
return;
|
|
3983
3976
|
}
|
|
@@ -4065,8 +4058,8 @@ var PaceLoginPage = ({
|
|
|
4065
4058
|
setIsSigningIn(false);
|
|
4066
4059
|
}
|
|
4067
4060
|
};
|
|
4068
|
-
return /* @__PURE__ */
|
|
4069
|
-
/* @__PURE__ */
|
|
4061
|
+
return /* @__PURE__ */ jsxs15("main", { className: "min-h-screen grid mx-auto w-fit content-center justify-items-center gap-y-8", "aria-label": `${appName} Login Page`, children: [
|
|
4062
|
+
/* @__PURE__ */ jsx20(
|
|
4070
4063
|
"img",
|
|
4071
4064
|
{
|
|
4072
4065
|
src: `/${appName.toLowerCase()}_logo_square.svg`,
|
|
@@ -4074,7 +4067,7 @@ var PaceLoginPage = ({
|
|
|
4074
4067
|
className: "h-48"
|
|
4075
4068
|
}
|
|
4076
4069
|
),
|
|
4077
|
-
/* @__PURE__ */
|
|
4070
|
+
/* @__PURE__ */ jsx20(
|
|
4078
4071
|
LoginForm,
|
|
4079
4072
|
{
|
|
4080
4073
|
className: "w-md",
|
|
@@ -4088,21 +4081,21 @@ var PaceLoginPage = ({
|
|
|
4088
4081
|
),
|
|
4089
4082
|
(() => {
|
|
4090
4083
|
const benign = !!(authError && (authError.name === "AuthSessionMissingError" || /Auth session missing/i.test(authError.message)));
|
|
4091
|
-
return authError && !benign ? /* @__PURE__ */
|
|
4084
|
+
return authError && !benign ? /* @__PURE__ */ jsx20("em", { className: "mt-4 text-destructive text-center", children: authError.message }) : null;
|
|
4092
4085
|
})(),
|
|
4093
|
-
accessError && /* @__PURE__ */
|
|
4094
|
-
isCheckingAccess && /* @__PURE__ */
|
|
4086
|
+
accessError && /* @__PURE__ */ jsx20("em", { className: "mt-4 text-destructive text-center", children: accessError }),
|
|
4087
|
+
isCheckingAccess && /* @__PURE__ */ jsx20("em", { className: "mt-4 text-muted-foreground text-center", children: "Checking permissions..." })
|
|
4095
4088
|
] });
|
|
4096
4089
|
};
|
|
4097
4090
|
|
|
4098
4091
|
// src/components/SessionRestorationLoader/SessionRestorationLoader.tsx
|
|
4099
|
-
import { jsx as
|
|
4092
|
+
import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
4100
4093
|
var SessionRestorationLoader = ({
|
|
4101
4094
|
message = "Restoring session...",
|
|
4102
4095
|
className
|
|
4103
4096
|
}) => {
|
|
4104
|
-
return /* @__PURE__ */
|
|
4105
|
-
|
|
4097
|
+
return /* @__PURE__ */ jsxs16(
|
|
4098
|
+
Alert,
|
|
4106
4099
|
{
|
|
4107
4100
|
className: cn(
|
|
4108
4101
|
"flex flex-col items-center justify-center h-screen w-full gap-4 text-center p-4 bg-background",
|
|
@@ -4112,20 +4105,19 @@ var SessionRestorationLoader = ({
|
|
|
4112
4105
|
"aria-live": "polite",
|
|
4113
4106
|
"aria-label": message,
|
|
4114
4107
|
children: [
|
|
4115
|
-
/* @__PURE__ */
|
|
4116
|
-
/* @__PURE__ */
|
|
4108
|
+
/* @__PURE__ */ jsx21(LoadingSpinner, { size: "lg" }),
|
|
4109
|
+
/* @__PURE__ */ jsx21("span", { className: "text-sm text-sec-600", children: message })
|
|
4117
4110
|
]
|
|
4118
4111
|
}
|
|
4119
4112
|
);
|
|
4120
4113
|
};
|
|
4121
4114
|
|
|
4122
4115
|
// src/components/ProtectedRoute/ProtectedRoute.tsx
|
|
4123
|
-
import { useMemo as
|
|
4116
|
+
import { useMemo as useMemo9, useEffect as useEffect9, useRef as useRef8, useState as useState14 } from "react";
|
|
4124
4117
|
import { Navigate, Outlet as Outlet2 } from "react-router-dom";
|
|
4125
|
-
import { jsx as
|
|
4118
|
+
import { jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
4126
4119
|
function ProtectedRoute({
|
|
4127
4120
|
requireEvent = false,
|
|
4128
|
-
allowSuperAdminBypass = false,
|
|
4129
4121
|
noEventsFallback,
|
|
4130
4122
|
loadingFallback,
|
|
4131
4123
|
loginPath = "/login"
|
|
@@ -4140,14 +4132,14 @@ function ProtectedRoute({
|
|
|
4140
4132
|
const wasAuthenticatedRef = useRef8(false);
|
|
4141
4133
|
const [shouldRedirect, setShouldRedirect] = useState14(false);
|
|
4142
4134
|
const tabJustBecameVisibleRef = useRef8(false);
|
|
4143
|
-
|
|
4135
|
+
useEffect9(() => {
|
|
4144
4136
|
if (isAuthenticated) {
|
|
4145
4137
|
wasAuthenticatedRef.current = true;
|
|
4146
4138
|
setShouldRedirect(false);
|
|
4147
4139
|
tabJustBecameVisibleRef.current = false;
|
|
4148
4140
|
}
|
|
4149
4141
|
}, [isAuthenticated]);
|
|
4150
|
-
|
|
4142
|
+
useEffect9(() => {
|
|
4151
4143
|
if (typeof document === "undefined") return;
|
|
4152
4144
|
let timeoutId = null;
|
|
4153
4145
|
let wasHidden = document.hidden;
|
|
@@ -4191,13 +4183,13 @@ function ProtectedRoute({
|
|
|
4191
4183
|
}
|
|
4192
4184
|
};
|
|
4193
4185
|
}, [isAuthenticated]);
|
|
4194
|
-
|
|
4186
|
+
useEffect9(() => {
|
|
4195
4187
|
if (isAuthenticated) {
|
|
4196
4188
|
setShouldRedirect(false);
|
|
4197
4189
|
tabJustBecameVisibleRef.current = false;
|
|
4198
4190
|
}
|
|
4199
4191
|
}, [isAuthenticated]);
|
|
4200
|
-
const isRestoringSession =
|
|
4192
|
+
const isRestoringSession = useMemo9(() => {
|
|
4201
4193
|
return sessionRestoration.isRestoring && !sessionRestoration.restorationComplete && !sessionRestoration.restorationError && !sessionRestoration.hasTimedOut;
|
|
4202
4194
|
}, [
|
|
4203
4195
|
sessionRestoration.isRestoring,
|
|
@@ -4206,13 +4198,13 @@ function ProtectedRoute({
|
|
|
4206
4198
|
sessionRestoration.hasTimedOut
|
|
4207
4199
|
]);
|
|
4208
4200
|
if (isRestoringSession) {
|
|
4209
|
-
return /* @__PURE__ */
|
|
4201
|
+
return /* @__PURE__ */ jsx22(SessionRestorationLoader, {});
|
|
4210
4202
|
}
|
|
4211
4203
|
if (requireEvent && eventLoading) {
|
|
4212
|
-
return /* @__PURE__ */
|
|
4204
|
+
return /* @__PURE__ */ jsx22(Outlet2, {});
|
|
4213
4205
|
}
|
|
4214
4206
|
if (isLoading && !sessionRestoration.hasTimedOut) {
|
|
4215
|
-
return loadingFallback || /* @__PURE__ */
|
|
4207
|
+
return loadingFallback || /* @__PURE__ */ jsx22("div", { style: { display: "flex", justifyContent: "center", alignItems: "center", height: "100vh" }, children: /* @__PURE__ */ jsx22(LoadingSpinner, {}) });
|
|
4216
4208
|
}
|
|
4217
4209
|
if (!isAuthenticated) {
|
|
4218
4210
|
if (sessionRestoration.hasTimedOut || sessionRestoration.restorationError) {
|
|
@@ -4220,41 +4212,41 @@ function ProtectedRoute({
|
|
|
4220
4212
|
timedOut: sessionRestoration.hasTimedOut,
|
|
4221
4213
|
error: sessionRestoration.restorationError?.message
|
|
4222
4214
|
});
|
|
4223
|
-
return /* @__PURE__ */
|
|
4215
|
+
return /* @__PURE__ */ jsx22(Navigate, { to: loginPath, replace: true });
|
|
4224
4216
|
}
|
|
4225
4217
|
if (!wasAuthenticatedRef.current) {
|
|
4226
|
-
return /* @__PURE__ */
|
|
4218
|
+
return /* @__PURE__ */ jsx22(Navigate, { to: loginPath, replace: true });
|
|
4227
4219
|
}
|
|
4228
4220
|
const isTabVisible = typeof document !== "undefined" && !document.hidden;
|
|
4229
4221
|
if (tabJustBecameVisibleRef.current || isTabVisible && wasAuthenticatedRef.current && isLoading) {
|
|
4230
|
-
return loadingFallback || /* @__PURE__ */
|
|
4222
|
+
return loadingFallback || /* @__PURE__ */ jsx22("div", { style: { display: "flex", justifyContent: "center", alignItems: "center", height: "100vh" }, children: /* @__PURE__ */ jsx22(LoadingSpinner, {}) });
|
|
4231
4223
|
}
|
|
4232
4224
|
if (shouldRedirect) {
|
|
4233
|
-
return /* @__PURE__ */
|
|
4225
|
+
return /* @__PURE__ */ jsx22(Navigate, { to: loginPath, replace: true });
|
|
4234
4226
|
}
|
|
4235
4227
|
if (isLoading) {
|
|
4236
|
-
return loadingFallback || /* @__PURE__ */
|
|
4228
|
+
return loadingFallback || /* @__PURE__ */ jsx22("div", { style: { display: "flex", justifyContent: "center", alignItems: "center", height: "100vh" }, children: /* @__PURE__ */ jsx22(LoadingSpinner, {}) });
|
|
4237
4229
|
}
|
|
4238
|
-
return /* @__PURE__ */
|
|
4230
|
+
return /* @__PURE__ */ jsx22(Navigate, { to: loginPath, replace: true });
|
|
4239
4231
|
}
|
|
4240
4232
|
if (!requireEvent) {
|
|
4241
|
-
return /* @__PURE__ */
|
|
4233
|
+
return /* @__PURE__ */ jsx22(Outlet2, {});
|
|
4242
4234
|
}
|
|
4243
4235
|
if (!events || events.length === 0) {
|
|
4244
|
-
return noEventsFallback || /* @__PURE__ */
|
|
4245
|
-
/* @__PURE__ */
|
|
4246
|
-
/* @__PURE__ */
|
|
4236
|
+
return noEventsFallback || /* @__PURE__ */ jsx22("div", { style: { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "100vh", padding: "2rem" }, children: /* @__PURE__ */ jsxs17(Alert, { variant: "destructive", className: "max-w-md", children: [
|
|
4237
|
+
/* @__PURE__ */ jsx22(AlertTitle, { children: "No Events Available" }),
|
|
4238
|
+
/* @__PURE__ */ jsx22(AlertDescription, { children: "You don't have access to any events. Please contact your administrator if you believe this is an error." })
|
|
4247
4239
|
] }) });
|
|
4248
4240
|
}
|
|
4249
4241
|
if (!selectedEvent) {
|
|
4250
|
-
return /* @__PURE__ */
|
|
4242
|
+
return /* @__PURE__ */ jsx22(Outlet2, {});
|
|
4251
4243
|
}
|
|
4252
|
-
return /* @__PURE__ */
|
|
4244
|
+
return /* @__PURE__ */ jsx22(Outlet2, {});
|
|
4253
4245
|
}
|
|
4254
4246
|
|
|
4255
4247
|
// src/components/FileUpload/FileUpload.tsx
|
|
4256
|
-
import { useState as useState15, useCallback as
|
|
4257
|
-
import { Fragment as
|
|
4248
|
+
import { useState as useState15, useCallback as useCallback10, useRef as useRef9, useEffect as useEffect10, useMemo as useMemo10 } from "react";
|
|
4249
|
+
import { Fragment as Fragment10, jsx as jsx23, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
4258
4250
|
function FileUpload({
|
|
4259
4251
|
supabase,
|
|
4260
4252
|
table_name,
|
|
@@ -4280,6 +4272,13 @@ function FileUpload({
|
|
|
4280
4272
|
onProgress,
|
|
4281
4273
|
children
|
|
4282
4274
|
}) {
|
|
4275
|
+
if (!pageContext) {
|
|
4276
|
+
const errorMsg = "pageContext is required for FileUpload component. This is used for permission checks.";
|
|
4277
|
+
if (import.meta.env.MODE === "development") {
|
|
4278
|
+
console.error("[FileUpload]", errorMsg);
|
|
4279
|
+
}
|
|
4280
|
+
throw new Error(errorMsg);
|
|
4281
|
+
}
|
|
4283
4282
|
const [isDragging, setIsDragging] = useState15(false);
|
|
4284
4283
|
const [uploadStates, setUploadStates] = useState15(/* @__PURE__ */ new Map());
|
|
4285
4284
|
const [resolvedAppId, setResolvedAppId] = useState15(app_id || null);
|
|
@@ -4287,7 +4286,7 @@ function FileUpload({
|
|
|
4287
4286
|
const [appIdError, setAppIdError] = useState15(null);
|
|
4288
4287
|
const fileInputRef = useRef9(null);
|
|
4289
4288
|
const { uploadFile, isLoading, error } = useFileReference(supabase);
|
|
4290
|
-
|
|
4289
|
+
useEffect10(() => {
|
|
4291
4290
|
if (app_id) {
|
|
4292
4291
|
setResolvedAppId(app_id);
|
|
4293
4292
|
setIsResolvingAppId(false);
|
|
@@ -4322,15 +4321,15 @@ function FileUpload({
|
|
|
4322
4321
|
};
|
|
4323
4322
|
resolveAppId();
|
|
4324
4323
|
}, [app_id, supabase]);
|
|
4325
|
-
const isUploading =
|
|
4324
|
+
const isUploading = useMemo10(() => {
|
|
4326
4325
|
return uploadStates.size > 0 && Array.from(uploadStates.values()).some(
|
|
4327
4326
|
(state) => state.progress.status === "uploading" || state.progress.status === "processing"
|
|
4328
4327
|
);
|
|
4329
4328
|
}, [uploadStates]);
|
|
4330
|
-
const isDisabled =
|
|
4329
|
+
const isDisabled = useMemo10(() => {
|
|
4331
4330
|
return disabled || isUploading || isResolvingAppId || !resolvedAppId;
|
|
4332
4331
|
}, [disabled, isUploading, isResolvingAppId, resolvedAppId]);
|
|
4333
|
-
const generatePreview =
|
|
4332
|
+
const generatePreview = useCallback10((file) => {
|
|
4334
4333
|
return new Promise((resolve) => {
|
|
4335
4334
|
if (!file.type.startsWith("image/")) {
|
|
4336
4335
|
resolve(null);
|
|
@@ -4344,7 +4343,7 @@ function FileUpload({
|
|
|
4344
4343
|
reader.readAsDataURL(file);
|
|
4345
4344
|
});
|
|
4346
4345
|
}, []);
|
|
4347
|
-
const validateFile =
|
|
4346
|
+
const validateFile = useCallback10((file) => {
|
|
4348
4347
|
if (file.size > maxSize) {
|
|
4349
4348
|
return `File "${file.name}" exceeds maximum size of ${Math.round(maxSize / 1024 / 1024)}MB`;
|
|
4350
4349
|
}
|
|
@@ -4368,7 +4367,7 @@ function FileUpload({
|
|
|
4368
4367
|
}
|
|
4369
4368
|
return null;
|
|
4370
4369
|
}, [accept, maxSize]);
|
|
4371
|
-
const handleFileSelect =
|
|
4370
|
+
const handleFileSelect = useCallback10(async (files) => {
|
|
4372
4371
|
if (!files || files.length === 0) return;
|
|
4373
4372
|
const fileArray = Array.from(files);
|
|
4374
4373
|
const validationErrors = [];
|
|
@@ -4447,6 +4446,10 @@ function FileUpload({
|
|
|
4447
4446
|
const errorMsg = appIdError || "App ID not available. Please provide app_id prop or set app name.";
|
|
4448
4447
|
throw new Error(errorMsg);
|
|
4449
4448
|
}
|
|
4449
|
+
if (!pageContext) {
|
|
4450
|
+
const errorMsg = "pageContext is required for file upload. This is used for permission checks.";
|
|
4451
|
+
throw new Error(errorMsg);
|
|
4452
|
+
}
|
|
4450
4453
|
const result = await uploadFile({
|
|
4451
4454
|
table_name,
|
|
4452
4455
|
record_id,
|
|
@@ -4544,20 +4547,20 @@ function FileUpload({
|
|
|
4544
4547
|
onUploadError?.(errorMessage, file);
|
|
4545
4548
|
}
|
|
4546
4549
|
}
|
|
4547
|
-
}, [uploadFile, table_name, record_id, organisation_id, resolvedAppId, category, folder, isPublic, maxSize, onUploadSuccess, onUploadError, onProgress, validateFile, generatePreview, showPreview, appIdError]);
|
|
4548
|
-
const handleDragOver =
|
|
4550
|
+
}, [uploadFile, table_name, record_id, organisation_id, resolvedAppId, category, folder, isPublic, maxSize, onUploadSuccess, onUploadError, onProgress, validateFile, generatePreview, showPreview, appIdError, pageContext]);
|
|
4551
|
+
const handleDragOver = useCallback10((e) => {
|
|
4549
4552
|
e.preventDefault();
|
|
4550
4553
|
e.stopPropagation();
|
|
4551
4554
|
if (!isDisabled) {
|
|
4552
4555
|
setIsDragging(true);
|
|
4553
4556
|
}
|
|
4554
4557
|
}, [isDisabled]);
|
|
4555
|
-
const handleDragLeave =
|
|
4558
|
+
const handleDragLeave = useCallback10((e) => {
|
|
4556
4559
|
e.preventDefault();
|
|
4557
4560
|
e.stopPropagation();
|
|
4558
4561
|
setIsDragging(false);
|
|
4559
4562
|
}, []);
|
|
4560
|
-
const handleDrop =
|
|
4563
|
+
const handleDrop = useCallback10((e) => {
|
|
4561
4564
|
e.preventDefault();
|
|
4562
4565
|
e.stopPropagation();
|
|
4563
4566
|
setIsDragging(false);
|
|
@@ -4565,13 +4568,13 @@ function FileUpload({
|
|
|
4565
4568
|
const files = e.dataTransfer.files;
|
|
4566
4569
|
handleFileSelect(files);
|
|
4567
4570
|
}, [isDisabled, handleFileSelect]);
|
|
4568
|
-
const handleFileInputChange =
|
|
4571
|
+
const handleFileInputChange = useCallback10((e) => {
|
|
4569
4572
|
handleFileSelect(e.target.files);
|
|
4570
4573
|
if (e.target) {
|
|
4571
4574
|
e.target.value = "";
|
|
4572
4575
|
}
|
|
4573
4576
|
}, [handleFileSelect]);
|
|
4574
|
-
const handleClick =
|
|
4577
|
+
const handleClick = useCallback10(() => {
|
|
4575
4578
|
if (!isDisabled && fileInputRef.current) {
|
|
4576
4579
|
fileInputRef.current.click();
|
|
4577
4580
|
}
|
|
@@ -4585,8 +4588,8 @@ function FileUpload({
|
|
|
4585
4588
|
};
|
|
4586
4589
|
const dragClasses = isDragging ? "border-main-500 bg-main-50" : "border-sec-300 hover:border-sec-400";
|
|
4587
4590
|
const disabledClasses = isDisabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer hover:bg-sec-50";
|
|
4588
|
-
return /* @__PURE__ */
|
|
4589
|
-
/* @__PURE__ */
|
|
4591
|
+
return /* @__PURE__ */ jsxs18("div", { className: `space-y-4 ${className}`, children: [
|
|
4592
|
+
/* @__PURE__ */ jsxs18(
|
|
4590
4593
|
"div",
|
|
4591
4594
|
{
|
|
4592
4595
|
role: "button",
|
|
@@ -4605,8 +4608,8 @@ function FileUpload({
|
|
|
4605
4608
|
}
|
|
4606
4609
|
} : void 0,
|
|
4607
4610
|
children: [
|
|
4608
|
-
children || /* @__PURE__ */
|
|
4609
|
-
/* @__PURE__ */
|
|
4611
|
+
children || /* @__PURE__ */ jsxs18("div", { className: "space-y-2", children: [
|
|
4612
|
+
/* @__PURE__ */ jsx23(
|
|
4610
4613
|
"input",
|
|
4611
4614
|
{
|
|
4612
4615
|
ref: fileInputRef,
|
|
@@ -4616,67 +4619,68 @@ function FileUpload({
|
|
|
4616
4619
|
onChange: handleFileInputChange,
|
|
4617
4620
|
className: "hidden",
|
|
4618
4621
|
disabled: isDisabled,
|
|
4619
|
-
"data-testid": "file-input"
|
|
4622
|
+
"data-testid": "file-input",
|
|
4623
|
+
"aria-label": accept ? `Upload file${multiple ? "s" : ""} (${accept})` : `Upload file${multiple ? "s" : ""}`
|
|
4620
4624
|
}
|
|
4621
4625
|
),
|
|
4622
|
-
/* @__PURE__ */
|
|
4623
|
-
/* @__PURE__ */
|
|
4626
|
+
/* @__PURE__ */ jsx23("div", { className: "text-sec-600", children: isResolvingAppId ? "Resolving app configuration..." : isDragging ? "Drop files here..." : /* @__PURE__ */ jsxs18(Fragment10, { children: [
|
|
4627
|
+
/* @__PURE__ */ jsx23("span", { className: "font-medium", children: "Click to upload" }),
|
|
4624
4628
|
" ",
|
|
4625
4629
|
"or drag and drop"
|
|
4626
4630
|
] }) }),
|
|
4627
|
-
/* @__PURE__ */
|
|
4631
|
+
/* @__PURE__ */ jsxs18("div", { className: "text-sm text-sec-500", children: [
|
|
4628
4632
|
!isResolvingAppId && accept !== "*/*" && `Accepted formats: ${accept}`,
|
|
4629
4633
|
!isResolvingAppId && maxSize && ` \u2022 Max size: ${Math.round(maxSize / 1024 / 1024)}MB`,
|
|
4630
4634
|
!isResolvingAppId && multiple && " \u2022 Multiple files allowed"
|
|
4631
4635
|
] })
|
|
4632
4636
|
] }),
|
|
4633
|
-
isUploading && !showProgress && /* @__PURE__ */
|
|
4637
|
+
isUploading && !showProgress && /* @__PURE__ */ jsx23(
|
|
4634
4638
|
"div",
|
|
4635
4639
|
{
|
|
4636
4640
|
className: "absolute inset-0 bg-white bg-opacity-75 flex items-center justify-center",
|
|
4637
4641
|
role: "status",
|
|
4638
4642
|
"aria-live": "polite",
|
|
4639
4643
|
"aria-label": "Uploading file",
|
|
4640
|
-
children: /* @__PURE__ */
|
|
4644
|
+
children: /* @__PURE__ */ jsx23("div", { className: "animate-spin rounded-full size-8 border-b-2 border-main-500", "aria-hidden": "true" })
|
|
4641
4645
|
}
|
|
4642
4646
|
)
|
|
4643
4647
|
]
|
|
4644
4648
|
}
|
|
4645
4649
|
),
|
|
4646
|
-
showProgress && uploadStates.size > 0 && /* @__PURE__ */
|
|
4650
|
+
showProgress && uploadStates.size > 0 && /* @__PURE__ */ jsx23("div", { className: "space-y-2", children: Array.from(uploadStates.entries()).map(([fileId, uploadState]) => {
|
|
4647
4651
|
const { file, progress, preview, result } = uploadState;
|
|
4648
4652
|
const isError = progress.status === "error";
|
|
4649
4653
|
const isCompleted = progress.status === "completed";
|
|
4650
4654
|
const isUploading2 = progress.status === "uploading" || progress.status === "processing";
|
|
4651
|
-
return /* @__PURE__ */
|
|
4655
|
+
return /* @__PURE__ */ jsxs18(
|
|
4652
4656
|
"div",
|
|
4653
4657
|
{
|
|
4654
4658
|
className: `flex items-center space-x-3 p-3 rounded-lg border ${isError ? "bg-acc-50 border-acc-200" : isCompleted ? "bg-success-50 border-success-200" : "bg-sec-50 border-sec-200"}`,
|
|
4655
4659
|
children: [
|
|
4656
|
-
/* @__PURE__ */
|
|
4660
|
+
/* @__PURE__ */ jsx23("div", { className: "flex-shrink-0", children: preview ? /* @__PURE__ */ jsx23(
|
|
4657
4661
|
"img",
|
|
4658
4662
|
{
|
|
4659
4663
|
src: preview,
|
|
4660
4664
|
alt: file.name,
|
|
4661
4665
|
className: "w-12 h-12 object-cover rounded"
|
|
4662
4666
|
}
|
|
4663
|
-
) : /* @__PURE__ */
|
|
4664
|
-
/* @__PURE__ */
|
|
4665
|
-
/* @__PURE__ */
|
|
4666
|
-
/* @__PURE__ */
|
|
4667
|
+
) : /* @__PURE__ */ jsx23("div", { className: "w-12 h-12 flex items-center justify-center bg-sec-200 rounded", children: /* @__PURE__ */ jsx23("span", { className: "text-2xl", children: "\u{1F4C4}" }) }) }),
|
|
4668
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex-1 min-w-0", children: [
|
|
4669
|
+
/* @__PURE__ */ jsx23("div", { className: "font-medium text-sec-900 truncate", children: file.name }),
|
|
4670
|
+
/* @__PURE__ */ jsxs18("div", { className: "text-sm text-sec-500", children: [
|
|
4667
4671
|
formatFileSize(file.size),
|
|
4668
4672
|
isCompleted && result && " \u2022 Uploaded",
|
|
4669
4673
|
isError && progress.error && ` \u2022 ${progress.error}`
|
|
4670
4674
|
] }),
|
|
4671
|
-
showProgress && (isUploading2 || isError) && /* @__PURE__ */
|
|
4672
|
-
/* @__PURE__ */
|
|
4675
|
+
showProgress && (isUploading2 || isError) && /* @__PURE__ */ jsxs18("div", { className: "mt-2", children: [
|
|
4676
|
+
/* @__PURE__ */ jsx23("div", { className: "w-full bg-sec-200 rounded-full h-2", children: /* @__PURE__ */ jsx23(
|
|
4673
4677
|
"div",
|
|
4674
4678
|
{
|
|
4675
4679
|
className: `h-2 rounded-full transition-all duration-300 ${isError ? "bg-acc-500" : "bg-main-500"}`,
|
|
4676
4680
|
style: { width: `${progress.percentage}%` }
|
|
4677
4681
|
}
|
|
4678
4682
|
) }),
|
|
4679
|
-
isUploading2 && /* @__PURE__ */
|
|
4683
|
+
isUploading2 && /* @__PURE__ */ jsxs18("div", { className: "text-xs text-sec-500 mt-1", children: [
|
|
4680
4684
|
progress.percentage,
|
|
4681
4685
|
"% \u2022 ",
|
|
4682
4686
|
formatFileSize(progress.loaded),
|
|
@@ -4685,10 +4689,10 @@ function FileUpload({
|
|
|
4685
4689
|
] })
|
|
4686
4690
|
] })
|
|
4687
4691
|
] }),
|
|
4688
|
-
/* @__PURE__ */
|
|
4689
|
-
isCompleted && /* @__PURE__ */
|
|
4690
|
-
isError && /* @__PURE__ */
|
|
4691
|
-
isUploading2 && /* @__PURE__ */
|
|
4692
|
+
/* @__PURE__ */ jsxs18("div", { className: "flex-shrink-0", children: [
|
|
4693
|
+
isCompleted && /* @__PURE__ */ jsx23("span", { className: "text-success-500 text-xl", children: "\u2713" }),
|
|
4694
|
+
isError && /* @__PURE__ */ jsx23("span", { className: "text-acc-500 text-xl", children: "\u2715" }),
|
|
4695
|
+
isUploading2 && /* @__PURE__ */ jsx23(
|
|
4692
4696
|
"div",
|
|
4693
4697
|
{
|
|
4694
4698
|
className: "animate-spin rounded-full size-5 border-b-2 border-main-500",
|
|
@@ -4703,7 +4707,7 @@ function FileUpload({
|
|
|
4703
4707
|
fileId
|
|
4704
4708
|
);
|
|
4705
4709
|
}) }),
|
|
4706
|
-
appIdError && /* @__PURE__ */
|
|
4710
|
+
appIdError && /* @__PURE__ */ jsx23(
|
|
4707
4711
|
"div",
|
|
4708
4712
|
{
|
|
4709
4713
|
className: "p-3 bg-acc-50 border border-acc-200 rounded-lg text-sm text-acc-600",
|
|
@@ -4712,7 +4716,7 @@ function FileUpload({
|
|
|
4712
4716
|
children: appIdError
|
|
4713
4717
|
}
|
|
4714
4718
|
),
|
|
4715
|
-
error && /* @__PURE__ */
|
|
4719
|
+
error && /* @__PURE__ */ jsx23(
|
|
4716
4720
|
"div",
|
|
4717
4721
|
{
|
|
4718
4722
|
className: "p-3 bg-acc-50 border border-acc-200 rounded-lg text-sm text-acc-600",
|
|
@@ -4725,9 +4729,9 @@ function FileUpload({
|
|
|
4725
4729
|
}
|
|
4726
4730
|
|
|
4727
4731
|
// src/components/Table/Table.tsx
|
|
4728
|
-
import * as
|
|
4729
|
-
import { jsx as
|
|
4730
|
-
var Table =
|
|
4732
|
+
import * as React20 from "react";
|
|
4733
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
4734
|
+
var Table = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx24(
|
|
4731
4735
|
"table",
|
|
4732
4736
|
{
|
|
4733
4737
|
ref,
|
|
@@ -4736,9 +4740,9 @@ var Table = React19.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */
|
|
|
4736
4740
|
}
|
|
4737
4741
|
));
|
|
4738
4742
|
Table.displayName = "Table";
|
|
4739
|
-
var TableHeader =
|
|
4743
|
+
var TableHeader = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx24("thead", { ref, className: cn("[&_tr]:border-b", className), ...props }));
|
|
4740
4744
|
TableHeader.displayName = "TableHeader";
|
|
4741
|
-
var TableBody =
|
|
4745
|
+
var TableBody = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx24(
|
|
4742
4746
|
"tbody",
|
|
4743
4747
|
{
|
|
4744
4748
|
ref,
|
|
@@ -4747,7 +4751,7 @@ var TableBody = React19.forwardRef(({ className, ...props }, ref) => /* @__PURE_
|
|
|
4747
4751
|
}
|
|
4748
4752
|
));
|
|
4749
4753
|
TableBody.displayName = "TableBody";
|
|
4750
|
-
var TableFooter =
|
|
4754
|
+
var TableFooter = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx24(
|
|
4751
4755
|
"tfoot",
|
|
4752
4756
|
{
|
|
4753
4757
|
ref,
|
|
@@ -4759,7 +4763,7 @@ var TableFooter = React19.forwardRef(({ className, ...props }, ref) => /* @__PUR
|
|
|
4759
4763
|
}
|
|
4760
4764
|
));
|
|
4761
4765
|
TableFooter.displayName = "TableFooter";
|
|
4762
|
-
var TableRow =
|
|
4766
|
+
var TableRow = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx24(
|
|
4763
4767
|
"tr",
|
|
4764
4768
|
{
|
|
4765
4769
|
ref,
|
|
@@ -4771,7 +4775,7 @@ var TableRow = React19.forwardRef(({ className, ...props }, ref) => /* @__PURE__
|
|
|
4771
4775
|
}
|
|
4772
4776
|
));
|
|
4773
4777
|
TableRow.displayName = "TableRow";
|
|
4774
|
-
var TableHead =
|
|
4778
|
+
var TableHead = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx24(
|
|
4775
4779
|
"th",
|
|
4776
4780
|
{
|
|
4777
4781
|
ref,
|
|
@@ -4783,7 +4787,7 @@ var TableHead = React19.forwardRef(({ className, ...props }, ref) => /* @__PURE_
|
|
|
4783
4787
|
}
|
|
4784
4788
|
));
|
|
4785
4789
|
TableHead.displayName = "TableHead";
|
|
4786
|
-
var TableCell =
|
|
4790
|
+
var TableCell = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx24(
|
|
4787
4791
|
"td",
|
|
4788
4792
|
{
|
|
4789
4793
|
ref,
|
|
@@ -4792,7 +4796,7 @@ var TableCell = React19.forwardRef(({ className, ...props }, ref) => /* @__PURE_
|
|
|
4792
4796
|
}
|
|
4793
4797
|
));
|
|
4794
4798
|
TableCell.displayName = "TableCell";
|
|
4795
|
-
var TableCaption =
|
|
4799
|
+
var TableCaption = React20.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx24(
|
|
4796
4800
|
"caption",
|
|
4797
4801
|
{
|
|
4798
4802
|
ref,
|
|
@@ -4803,7 +4807,7 @@ var TableCaption = React19.forwardRef(({ className, ...props }, ref) => /* @__PU
|
|
|
4803
4807
|
TableCaption.displayName = "TableCaption";
|
|
4804
4808
|
|
|
4805
4809
|
// src/components/PublicLayout/PublicPageLayout.tsx
|
|
4806
|
-
import { Fragment as
|
|
4810
|
+
import { Fragment as Fragment11, jsx as jsx25, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
4807
4811
|
function PublicPageHeader({
|
|
4808
4812
|
event,
|
|
4809
4813
|
eventCode,
|
|
@@ -4816,11 +4820,11 @@ function PublicPageHeader({
|
|
|
4816
4820
|
customEventLogo
|
|
4817
4821
|
}) {
|
|
4818
4822
|
const { appName } = useAppConfig();
|
|
4819
|
-
return /* @__PURE__ */
|
|
4823
|
+
return /* @__PURE__ */ jsxs19("header", { className: cn(
|
|
4820
4824
|
"w-full px-[max(0rem,calc((100vw-var(--app-width))/2-0.5rem))] grid grid-cols-[auto_1fr_auto] place-items-center gap-2",
|
|
4821
4825
|
className
|
|
4822
4826
|
), children: [
|
|
4823
|
-
showAppLogo && appName && /* @__PURE__ */
|
|
4827
|
+
showAppLogo && appName && /* @__PURE__ */ jsx25(
|
|
4824
4828
|
"img",
|
|
4825
4829
|
{
|
|
4826
4830
|
className: "ml-4 max-w-36 object-contain row-span-2",
|
|
@@ -4828,9 +4832,9 @@ function PublicPageHeader({
|
|
|
4828
4832
|
alt: appName
|
|
4829
4833
|
}
|
|
4830
4834
|
),
|
|
4831
|
-
event && /* @__PURE__ */
|
|
4832
|
-
/* @__PURE__ */
|
|
4833
|
-
showEventLogo && event && /* @__PURE__ */
|
|
4835
|
+
event && /* @__PURE__ */ jsxs19(Fragment11, { children: [
|
|
4836
|
+
/* @__PURE__ */ jsx25("h1", { children: event.event_name }),
|
|
4837
|
+
showEventLogo && event && /* @__PURE__ */ jsx25(Fragment11, { children: customEventLogo || /* @__PURE__ */ jsx25(
|
|
4834
4838
|
FileDisplay,
|
|
4835
4839
|
{
|
|
4836
4840
|
table_name: "event",
|
|
@@ -4847,13 +4851,13 @@ function PublicPageHeader({
|
|
|
4847
4851
|
}
|
|
4848
4852
|
}
|
|
4849
4853
|
) }),
|
|
4850
|
-
event.event_venue && /* @__PURE__ */
|
|
4854
|
+
event.event_venue && /* @__PURE__ */ jsx25("h4", { children: event.event_venue })
|
|
4851
4855
|
] }),
|
|
4852
|
-
title && /* @__PURE__ */
|
|
4853
|
-
/* @__PURE__ */
|
|
4854
|
-
description && /* @__PURE__ */
|
|
4856
|
+
title && /* @__PURE__ */ jsxs19(Fragment11, { children: [
|
|
4857
|
+
/* @__PURE__ */ jsx25("h1", { children: title }),
|
|
4858
|
+
description && /* @__PURE__ */ jsx25("p", { className: "text-lg text-sec-600 max-w-3xl mx-auto", children: description })
|
|
4855
4859
|
] }),
|
|
4856
|
-
children && /* @__PURE__ */
|
|
4860
|
+
children && /* @__PURE__ */ jsx25(Fragment11, { children })
|
|
4857
4861
|
] });
|
|
4858
4862
|
}
|
|
4859
4863
|
function PublicPageFooter({
|
|
@@ -4867,11 +4871,11 @@ function PublicPageFooter({
|
|
|
4867
4871
|
children
|
|
4868
4872
|
}) {
|
|
4869
4873
|
const copyrightText = copyright || `\xA9 Copyright 2022\u2013${year} all rights reserved, ${companyName}.`;
|
|
4870
|
-
return /* @__PURE__ */
|
|
4871
|
-
logo && /* @__PURE__ */
|
|
4872
|
-
children && /* @__PURE__ */
|
|
4873
|
-
/* @__PURE__ */
|
|
4874
|
-
links && links.length > 0 && /* @__PURE__ */
|
|
4874
|
+
return /* @__PURE__ */ jsx25("footer", { className: cn("mt-8 py-6 flex justify-center", className), children: /* @__PURE__ */ jsxs19("section", { className: "px-4 w-[min(var(--app-width),100%)] mx-auto text-center", children: [
|
|
4875
|
+
logo && /* @__PURE__ */ jsx25("img", { src: logo, alt: "Logo", className: "h-8 w-auto" }),
|
|
4876
|
+
children && /* @__PURE__ */ jsx25(Fragment11, { children }),
|
|
4877
|
+
/* @__PURE__ */ jsx25("span", { className: "text-muted-foreground", children: copyrightText }),
|
|
4878
|
+
links && links.length > 0 && /* @__PURE__ */ jsx25("ul", { className: "flex gap-4 mt-2 md:mt-0", children: links.map((link, index) => /* @__PURE__ */ jsx25("li", { children: /* @__PURE__ */ jsx25("a", { href: link.href, className: "text-muted-foreground hover:text-foreground", children: link.label }) }, index)) })
|
|
4875
4879
|
] }) });
|
|
4876
4880
|
}
|
|
4877
4881
|
function PublicPageLayout({
|
|
@@ -4882,7 +4886,6 @@ function PublicPageLayout({
|
|
|
4882
4886
|
error = null,
|
|
4883
4887
|
refetch,
|
|
4884
4888
|
showFooter = true,
|
|
4885
|
-
className = "",
|
|
4886
4889
|
errorFallback: ErrorFallback,
|
|
4887
4890
|
loadingFallback: LoadingFallback,
|
|
4888
4891
|
customHeader,
|
|
@@ -4895,44 +4898,44 @@ function PublicPageLayout({
|
|
|
4895
4898
|
});
|
|
4896
4899
|
if (isLoading) {
|
|
4897
4900
|
if (LoadingFallback) {
|
|
4898
|
-
return /* @__PURE__ */
|
|
4901
|
+
return /* @__PURE__ */ jsx25(LoadingFallback, {});
|
|
4899
4902
|
}
|
|
4900
|
-
return /* @__PURE__ */
|
|
4901
|
-
/* @__PURE__ */
|
|
4902
|
-
loadingMessage && /* @__PURE__ */
|
|
4903
|
+
return /* @__PURE__ */ jsx25("div", { className: "min-h-screen bg-background flex items-center justify-center", children: /* @__PURE__ */ jsxs19("div", { className: "max-w-md mx-auto text-center px-4", children: [
|
|
4904
|
+
/* @__PURE__ */ jsx25(LoadingSpinner, { size: "lg", className: "mx-auto mb-4" }),
|
|
4905
|
+
loadingMessage && /* @__PURE__ */ jsx25("p", { className: "text-sec-600", children: loadingMessage })
|
|
4903
4906
|
] }) });
|
|
4904
4907
|
}
|
|
4905
4908
|
if (error && showValidationErrors) {
|
|
4906
4909
|
if (ErrorFallback) {
|
|
4907
|
-
return /* @__PURE__ */
|
|
4910
|
+
return /* @__PURE__ */ jsx25(ErrorFallback, { error, retry: handleRefetch });
|
|
4908
4911
|
}
|
|
4909
|
-
return /* @__PURE__ */
|
|
4910
|
-
/* @__PURE__ */
|
|
4911
|
-
/* @__PURE__ */
|
|
4912
|
+
return /* @__PURE__ */ jsxs19("main", { className: "flex flex-col items-center justify-center px-4 w-[min(var(--app-width),100%)] mx-auto py-8", children: [
|
|
4913
|
+
/* @__PURE__ */ jsx25("h1", { children: "Event Not Found" }),
|
|
4914
|
+
/* @__PURE__ */ jsxs19("p", { children: [
|
|
4912
4915
|
'The event code "',
|
|
4913
4916
|
eventCode,
|
|
4914
4917
|
'" is invalid or the event is not available for public viewing.'
|
|
4915
4918
|
] }),
|
|
4916
|
-
/* @__PURE__ */
|
|
4919
|
+
/* @__PURE__ */ jsx25(Button, { onClick: handleRefetch, children: "Try Again" })
|
|
4917
4920
|
] });
|
|
4918
4921
|
}
|
|
4919
4922
|
if (!event && showValidationErrors) {
|
|
4920
|
-
return /* @__PURE__ */
|
|
4921
|
-
/* @__PURE__ */
|
|
4922
|
-
/* @__PURE__ */
|
|
4923
|
-
handleRefetch && /* @__PURE__ */
|
|
4923
|
+
return /* @__PURE__ */ jsxs19("main", { className: "flex flex-col items-center justify-center px-4 w-[min(var(--app-width),100%)] mx-auto py-8", children: [
|
|
4924
|
+
/* @__PURE__ */ jsx25("h1", { children: "Event Not Available" }),
|
|
4925
|
+
/* @__PURE__ */ jsx25("p", { children: "This event is not available for public viewing." }),
|
|
4926
|
+
handleRefetch && /* @__PURE__ */ jsx25(Button, { onClick: handleRefetch, children: "Try Again" })
|
|
4924
4927
|
] });
|
|
4925
4928
|
}
|
|
4926
|
-
return /* @__PURE__ */
|
|
4927
|
-
customHeader || /* @__PURE__ */
|
|
4929
|
+
return /* @__PURE__ */ jsx25(ErrorBoundary, { componentName: "PublicPageLayout", children: /* @__PURE__ */ jsxs19(Fragment11, { children: [
|
|
4930
|
+
customHeader || /* @__PURE__ */ jsx25(
|
|
4928
4931
|
PublicPageHeader,
|
|
4929
4932
|
{
|
|
4930
4933
|
event: event || void 0,
|
|
4931
4934
|
eventCode
|
|
4932
4935
|
}
|
|
4933
4936
|
),
|
|
4934
|
-
/* @__PURE__ */
|
|
4935
|
-
showFooter && event && (customFooter || /* @__PURE__ */
|
|
4937
|
+
/* @__PURE__ */ jsx25("main", { className: "px-4 w-[min(var(--app-width),100%)] mx-auto py-8", children }),
|
|
4938
|
+
showFooter && event && (customFooter || /* @__PURE__ */ jsx25(PublicPageFooter, { event }))
|
|
4936
4939
|
] }) });
|
|
4937
4940
|
}
|
|
4938
4941
|
|
|
@@ -4964,8 +4967,7 @@ export {
|
|
|
4964
4967
|
Form,
|
|
4965
4968
|
FormField,
|
|
4966
4969
|
LoginForm,
|
|
4967
|
-
|
|
4968
|
-
OrganisationSelector,
|
|
4970
|
+
ContextSelector,
|
|
4969
4971
|
PasswordChangeForm,
|
|
4970
4972
|
UserMenu,
|
|
4971
4973
|
NavigationMenu,
|
|
@@ -4988,4 +4990,4 @@ export {
|
|
|
4988
4990
|
PublicPageFooter,
|
|
4989
4991
|
PublicPageLayout
|
|
4990
4992
|
};
|
|
4991
|
-
//# sourceMappingURL=chunk-
|
|
4993
|
+
//# sourceMappingURL=chunk-ZNIWI3UC.js.map
|