@jmruthers/pace-core 0.5.74 → 0.5.76
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/dist/DataTable-4GAVPIEG.js +120 -0
- package/dist/{PublicLoadingSpinner-DLpF5bbs.d.ts → PublicLoadingSpinner-BiNER8F5.d.ts} +30 -19
- package/dist/RBACService-C4udt_Zp.d.ts +528 -0
- package/dist/{UnifiedAuthProvider-K4NRGXL4.js → UnifiedAuthProvider-3NKDOSOK.js} +6 -4
- package/dist/UnifiedAuthProvider-Bj6YCf7c.d.ts +113 -0
- package/dist/chunk-5F3NDPJV.js +232 -0
- package/dist/chunk-5F3NDPJV.js.map +1 -0
- package/dist/chunk-A4FUBC7B.js +17 -0
- package/dist/chunk-A4FUBC7B.js.map +1 -0
- package/dist/{chunk-SMJZMKYN.js → chunk-A6HBIY5P.js} +2 -11
- package/dist/{chunk-SMJZMKYN.js.map → chunk-A6HBIY5P.js.map} +1 -1
- package/dist/{chunk-LVQ26TCN.js → chunk-AFGTSUAD.js} +43 -127
- package/dist/chunk-AFGTSUAD.js.map +1 -0
- package/dist/{chunk-BKVGJVUR.js → chunk-K34IM5CT.js} +497 -33
- package/dist/chunk-K34IM5CT.js.map +1 -0
- package/dist/{chunk-UJMCGBLS.js → chunk-KHJS6VIA.js} +203 -41
- package/dist/chunk-KHJS6VIA.js.map +1 -0
- package/dist/{chunk-ORSMVXO2.js → chunk-KK73ZB4E.js} +9 -14
- package/dist/chunk-KK73ZB4E.js.map +1 -0
- package/dist/{chunk-VKOCWWVY.js → chunk-L3RV2ALE.js} +1 -6
- package/dist/{chunk-VKOCWWVY.js.map → chunk-L3RV2ALE.js.map} +1 -1
- package/dist/chunk-LW7MMEAQ.js +59 -0
- package/dist/chunk-LW7MMEAQ.js.map +1 -0
- package/dist/{chunk-IHMMNKNA.js → chunk-M5IWZRBT.js} +5118 -1864
- package/dist/chunk-M5IWZRBT.js.map +1 -0
- package/dist/{chunk-DG5Z55HH.js → chunk-NTNILOBC.js} +7 -9
- package/dist/chunk-NTNILOBC.js.map +1 -0
- package/dist/chunk-PYUXFQJ3.js +11 -0
- package/dist/chunk-PYUXFQJ3.js.map +1 -0
- package/dist/chunk-URUTVZ7N.js +27 -0
- package/dist/chunk-URUTVZ7N.js.map +1 -0
- package/dist/chunk-WN6XJWOS.js +2468 -0
- package/dist/chunk-WN6XJWOS.js.map +1 -0
- package/dist/{chunk-3SP4P7NS.js → chunk-XLZ7U46Z.js} +59 -1
- package/dist/chunk-XLZ7U46Z.js.map +1 -0
- package/dist/{chunk-H2TNUICK.js → chunk-Y6TXWPJO.js} +50 -50
- package/dist/chunk-Y6TXWPJO.js.map +1 -0
- package/dist/{chunk-YNUBMSMV.js → chunk-YCKPEMJA.js} +186 -263
- package/dist/chunk-YCKPEMJA.js.map +1 -0
- package/dist/components.d.ts +4 -5
- package/dist/components.js +35 -41
- package/dist/components.js.map +1 -1
- package/dist/hooks.d.ts +20 -43
- package/dist/hooks.js +13 -12
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +156 -10
- package/dist/index.js +193 -96
- package/dist/index.js.map +1 -1
- package/dist/{organisation-t-vvQC3g.d.ts → organisation-BtshODVF.d.ts} +4 -3
- package/dist/providers.d.ts +27 -38
- package/dist/providers.js +33 -23
- package/dist/rbac/index.d.ts +114 -5
- package/dist/rbac/index.js +15 -15
- package/dist/styles/index.js +2 -2
- package/dist/theming/runtime.js +1 -3
- package/dist/types.d.ts +3 -3
- package/dist/types.js +1 -1
- package/dist/types.js.map +1 -1
- package/dist/{unified-CMPjE_fv.d.ts → unified-CM7T0aTK.d.ts} +1 -1
- package/dist/useInactivityTracker-MRUU55XI.js +10 -0
- package/dist/{usePublicRouteParams-Ua1Vz-HG.d.ts → usePublicRouteParams-B-CumWRc.d.ts} +3 -3
- package/dist/utils.js +7 -9
- package/dist/utils.js.map +1 -1
- package/dist/validation.d.ts +1 -1
- package/docs/TERMINOLOGY.md +231 -0
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +1 -1
- package/docs/api/classes/MissingUserContextError.md +1 -1
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +1 -1
- package/docs/api/classes/PublicErrorBoundary.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +1 -1
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +1 -1
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +1 -1
- package/docs/api/classes/SecureSupabaseClient.md +1 -1
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +3 -3
- package/docs/api/interfaces/CardProps.md +2 -2
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +1 -1
- package/docs/api/interfaces/DataAccessRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +1 -1
- package/docs/api/interfaces/DataTableColumn.md +1 -1
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
- package/docs/api/interfaces/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventLogoProps.md +2 -2
- package/docs/api/interfaces/FileDisplayProps.md +1 -1
- package/docs/api/interfaces/FileMetadata.md +1 -1
- package/docs/api/interfaces/FileReference.md +1 -1
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +1 -1
- package/docs/api/interfaces/FileUploadProps.md +1 -1
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
- package/docs/api/interfaces/InputProps.md +2 -2
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
- package/docs/api/interfaces/NavigationContextType.md +1 -1
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +1 -1
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +28 -17
- package/docs/api/interfaces/OrganisationMembership.md +1 -1
- package/docs/api/interfaces/OrganisationProviderProps.md +2 -2
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PageAccessRecord.md +1 -1
- package/docs/api/interfaces/PagePermissionContextType.md +1 -1
- package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
- package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
- package/docs/api/interfaces/PublicLoadingSpinnerProps.md +2 -2
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
- package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
- package/docs/api/interfaces/RBACConfig.md +1 -1
- package/docs/api/interfaces/RBACContextType.md +5 -11
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RBACProviderProps.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +1 -1
- package/docs/api/interfaces/RouteConfig.md +1 -1
- package/docs/api/interfaces/SecureDataContextType.md +1 -1
- package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
- package/docs/api/interfaces/StorageConfig.md +1 -1
- package/docs/api/interfaces/StorageFileInfo.md +1 -1
- package/docs/api/interfaces/StorageFileMetadata.md +1 -1
- package/docs/api/interfaces/StorageListOptions.md +1 -1
- package/docs/api/interfaces/StorageListResult.md +1 -1
- package/docs/api/interfaces/StorageUploadOptions.md +1 -1
- package/docs/api/interfaces/StorageUploadResult.md +1 -1
- package/docs/api/interfaces/StorageUrlOptions.md +1 -1
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/SwitchProps.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +524 -440
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +14 -14
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +47 -0
- package/docs/api/interfaces/UseResolvedScopeReturn.md +47 -0
- package/docs/api/interfaces/UserEventAccess.md +11 -11
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +234 -61
- package/docs/api-reference/providers.md +26 -7
- package/docs/architecture/services.md +30 -32
- package/docs/best-practices/README.md +20 -0
- package/docs/best-practices/accessibility.md +566 -0
- package/docs/best-practices/performance-expansion.md +473 -0
- package/docs/breaking-changes.md +2 -5
- package/docs/core-concepts/authentication.md +15 -7
- package/docs/documentation-index.md +1 -1
- package/docs/documentation-templates.md +539 -0
- package/docs/getting-started/quick-start.md +16 -66
- package/docs/implementation-guides/component-styling.md +410 -0
- package/docs/implementation-guides/data-tables.md +1 -1
- package/docs/migration/service-architecture.md +121 -260
- package/docs/rbac/README-rbac-rls-integration.md +48 -38
- package/docs/style-guide.md +39 -0
- package/{src/rbac/examples → examples/RBAC}/CompleteRBACExample.tsx +3 -2
- package/{src/rbac/examples → examples/RBAC}/EventBasedApp.tsx +5 -4
- package/{src/components/examples → examples/RBAC}/PermissionExample.tsx +7 -6
- package/examples/RBAC/__tests__/PermissionExample.test.tsx +150 -0
- package/examples/RBAC/index.ts +13 -0
- package/examples/README.md +37 -0
- package/examples/index.ts +22 -0
- package/{src/examples → examples/public-pages}/CorrectPublicPageImplementation.tsx +1 -1
- package/{src/examples → examples/public-pages}/PublicEventPage.tsx +1 -1
- package/{src/examples → examples/public-pages}/PublicPageApp.tsx +1 -1
- package/{src/examples → examples/public-pages}/PublicPageUsageExample.tsx +1 -1
- package/examples/public-pages/__tests__/PublicPageUsageExample.test.tsx +159 -0
- package/examples/public-pages/index.ts +14 -0
- package/package.json +22 -18
- package/src/__tests__/TEST_GUIDE_CURSOR.md +940 -9
- package/src/__tests__/helpers/README.md +255 -0
- package/src/__tests__/helpers/index.ts +62 -0
- package/src/__tests__/helpers/supabaseMock.ts +75 -5
- package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -8
- package/src/components/DataTable/__tests__/DataTable.default-state.test.tsx +17 -6
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +73 -9
- package/src/components/DataTable/components/DataTableCore.tsx +280 -475
- package/src/components/DataTable/components/UnifiedTableBody.tsx +120 -153
- package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +55 -0
- package/src/components/DataTable/components/index.ts +1 -2
- package/src/components/DataTable/context/__tests__/DataTableContext.test.tsx +208 -275
- package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +254 -0
- package/src/components/DataTable/core/index.ts +1 -8
- package/src/components/DataTable/examples/__tests__/HierarchicalExample.test.tsx +45 -0
- package/src/components/DataTable/examples/__tests__/PerformanceExample.test.tsx +117 -0
- package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.test.ts +525 -0
- package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +570 -0
- package/src/components/DataTable/hooks/__tests__/useHierarchicalState.test.ts +214 -0
- package/src/components/DataTable/hooks/__tests__/useTableColumns.test.ts +224 -0
- package/src/components/DataTable/hooks/index.ts +6 -0
- package/src/components/DataTable/hooks/useColumnReordering.ts +1 -0
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +149 -0
- package/src/components/DataTable/hooks/useDataTableState.ts +12 -6
- package/src/components/DataTable/hooks/useHierarchicalState.ts +26 -8
- package/src/components/DataTable/hooks/useTableColumns.ts +153 -0
- package/src/components/DataTable/index.ts +1 -9
- package/src/components/DataTable/utils/__tests__/COVERAGE_NOTE.md +89 -0
- package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +3 -6
- package/src/components/DataTable/utils/__tests__/flexibleImport.test.ts +462 -0
- package/src/components/DataTable/utils/__tests__/hierarchicalSorting.test.ts +247 -0
- package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +8 -6
- package/src/components/DataTable/utils/__tests__/performanceUtils.test.ts +466 -0
- package/src/components/DataTable/utils/__tests__/rowUtils.test.ts +265 -0
- package/src/components/DataTable/utils/errorHandling.ts +52 -460
- package/src/components/DataTable/utils/exportUtils.ts +46 -15
- package/src/components/DataTable/utils/hierarchicalSorting.ts +50 -3
- package/src/components/DataTable/utils/hierarchicalUtils.ts +167 -34
- package/src/components/DataTable/utils/index.ts +5 -0
- package/src/components/DataTable/utils/rowUtils.ts +68 -0
- package/src/components/Dialog/examples/__tests__/HtmlDialogExample.test.tsx +71 -0
- package/src/components/Dialog/examples/__tests__/SimpleHtmlTest.test.tsx +122 -0
- package/src/components/EventSelector/EventSelector.test.tsx +672 -0
- package/src/components/EventSelector/EventSelector.tsx +1 -1
- package/src/components/Header/Header.test.tsx +35 -1
- package/src/components/Header/Header.tsx +3 -1
- package/src/components/Label/__tests__/Label.test.tsx +434 -0
- package/src/components/OrganisationSelector/OrganisationSelector.tsx +3 -3
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.rbac.test.tsx +24 -4
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +3 -2
- package/src/components/PublicLayout/__tests__/PublicPageContextChecker.test.tsx +190 -0
- package/src/components/PublicLayout/__tests__/PublicPageDebugger.test.tsx +185 -0
- package/src/components/PublicLayout/__tests__/PublicPageProvider.test.tsx +313 -0
- package/src/components/Select/Select.test.tsx +143 -120
- package/src/components/Select/Select.tsx +47 -212
- package/src/components/Select/hooks.ts +36 -1
- package/src/components/Select/index.ts +2 -1
- package/src/hooks/__tests__/useFocusManagement.unit.test.ts +220 -0
- package/src/hooks/__tests__/useIsMobile.unit.test.ts +117 -0
- package/src/hooks/__tests__/useKeyboardShortcuts.unit.test.ts +295 -0
- package/src/hooks/__tests__/useOrganisationSecurity.unit.test.tsx +29 -19
- package/src/hooks/__tests__/useRBAC.unit.test.ts +7 -3
- package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +115 -19
- package/src/hooks/services/__tests__/useServiceHooks.test.tsx +137 -0
- package/src/hooks/useEventTheme.test.ts +350 -0
- package/src/hooks/useEventTheme.ts +1 -1
- package/src/hooks/useEvents.ts +61 -0
- package/src/hooks/useOrganisationSecurity.test.ts +4 -4
- package/src/hooks/useOrganisationSecurity.ts +2 -2
- package/src/hooks/useOrganisations.ts +64 -0
- package/src/hooks/useSecureDataAccess.test.ts +37 -30
- package/src/hooks/useSecureDataAccess.ts +2 -2
- package/src/index.ts +18 -3
- package/src/providers/AuthProvider.tsx +8 -292
- package/src/providers/EventProvider.tsx +15 -425
- package/src/providers/InactivityProvider.tsx +8 -231
- package/src/providers/OrganisationProvider.test.simple.tsx +3 -2
- package/src/providers/OrganisationProvider.tsx +11 -890
- package/src/providers/UnifiedAuthProvider.tsx +8 -320
- package/src/providers/__tests__/AuthProvider.test.tsx +18 -17
- package/src/providers/__tests__/EventProvider.test.tsx +253 -2
- package/src/providers/__tests__/InactivityProvider.test-helper.tsx +65 -0
- package/src/providers/__tests__/InactivityProvider.test.tsx +46 -114
- package/src/providers/__tests__/OrganisationProvider.test.tsx +313 -3
- package/src/providers/__tests__/ProviderLifecycle.test.tsx +341 -0
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +383 -2
- package/src/providers/index.ts +8 -7
- package/src/providers/services/EventServiceProvider.tsx +3 -0
- package/src/providers/services/UnifiedAuthProvider.tsx +3 -0
- package/src/rbac/hooks/__tests__/usePermissions.integration.test.ts +437 -0
- package/src/rbac/hooks/index.ts +2 -0
- package/src/rbac/hooks/usePermissions.test.ts +296 -0
- package/src/rbac/hooks/useRBAC.test.ts +9 -5
- package/src/rbac/hooks/useRBAC.ts +3 -3
- package/src/rbac/hooks/useResolvedScope.ts +232 -0
- package/src/rbac/providers/__tests__/RBACProvider.integration.test.tsx +688 -0
- package/src/rbac/providers/__tests__/RBACProvider.test.tsx +507 -0
- package/src/services/AuthService.ts +19 -4
- package/src/services/__tests__/AuthService.test.ts +288 -0
- package/src/services/__tests__/InactivityService.lifecycle.test.ts +411 -0
- package/src/services/__tests__/OrganisationService.pagination.test.ts +375 -0
- package/src/styles/core.css +2 -0
- package/src/types/__tests__/README.md +114 -0
- package/src/types/__tests__/guards.test.ts +246 -0
- package/src/types/__tests__/validation.test.ts +731 -0
- package/src/types/guards.ts +1 -0
- package/src/types/organisation.ts +3 -2
- package/src/utils/__tests__/file-reference.test.ts +383 -0
- package/src/utils/__tests__/performanceBenchmark.test.ts +175 -0
- package/src/utils/appNameResolver.test.ts +54 -0
- package/src/validation/__tests__/csrf.unit.test.ts +63 -0
- package/src/validation/__tests__/passwordSchema.unit.test.ts +105 -0
- package/src/validation/__tests__/sanitization.unit.test.ts +250 -0
- package/src/validation/__tests__/schemaUtils.unit.test.ts +451 -0
- package/src/validation/__tests__/user.unit.test.ts +440 -0
- package/dist/DataTable-2QR5TER5.js +0 -102
- package/dist/RBACProvider-BO4ilsQB.d.ts +0 -63
- package/dist/UnifiedAuthProvider-D02AMXgO.d.ts +0 -103
- package/dist/chunk-3SP4P7NS.js.map +0 -1
- package/dist/chunk-B5LK25HV.js +0 -953
- package/dist/chunk-B5LK25HV.js.map +0 -1
- package/dist/chunk-BKVGJVUR.js.map +0 -1
- package/dist/chunk-C5Q5LRU5.js +0 -5691
- package/dist/chunk-C5Q5LRU5.js.map +0 -1
- package/dist/chunk-CDDYJCYU.js +0 -79
- package/dist/chunk-CDDYJCYU.js.map +0 -1
- package/dist/chunk-DG5Z55HH.js.map +0 -1
- package/dist/chunk-H2TNUICK.js.map +0 -1
- package/dist/chunk-IHMMNKNA.js.map +0 -1
- package/dist/chunk-LVQ26TCN.js.map +0 -1
- package/dist/chunk-ORSMVXO2.js.map +0 -1
- package/dist/chunk-TYHR5X4W.js +0 -33
- package/dist/chunk-TYHR5X4W.js.map +0 -1
- package/dist/chunk-UJMCGBLS.js.map +0 -1
- package/dist/chunk-V6BHACCH.js +0 -17
- package/dist/chunk-V6BHACCH.js.map +0 -1
- package/dist/chunk-YNUBMSMV.js.map +0 -1
- package/dist/eventContext-BBA42P6G.js +0 -14
- package/dist/rbac/cli/policy-manager.js +0 -278
- package/dist/rbac/cli/policy-manager.js.map +0 -1
- package/docs/api/interfaces/EventContextType.md +0 -96
- package/docs/api/interfaces/EventProviderProps.md +0 -19
- package/docs/documentation-style-checklist.md +0 -294
- package/src/components/DataTable/components/DataTableBody.tsx +0 -488
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -144
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -515
- package/src/components/DataTable/core/ActionManager.ts +0 -235
- package/src/components/DataTable/core/ColumnManager.ts +0 -205
- package/src/components/DataTable/core/DataManager.ts +0 -188
- package/src/components/DataTable/core/DataTableContext.tsx +0 -181
- package/src/components/DataTable/core/LocalDataAdapter.ts +0 -264
- package/src/components/DataTable/core/PluginRegistry.ts +0 -229
- package/src/components/DataTable/core/StateManager.ts +0 -311
- package/src/components/DataTable/core/__tests__/ActionManager.test.ts +0 -634
- package/src/components/DataTable/core/__tests__/DataManager.test.ts +0 -519
- package/src/components/DataTable/core/__tests__/StateManager.test.ts +0 -714
- package/src/components/DataTable/core/interfaces.ts +0 -338
- package/src/components/DataTable/utils/debugTools.ts +0 -583
- package/src/components/Select/Select.bug-test.tsx +0 -69
- package/src/components/Select/Select.refactored.tsx +0 -497
- package/src/providers/OrganisationProvider.test.tsx +0 -164
- package/src/providers/UnifiedAuthProvider.test.tsx +0 -124
- package/src/providers/__tests__/AuthProvider.test.tsx.backup +0 -771
- package/src/providers/__tests__/EventProvider.test.tsx.backup +0 -824
- package/src/providers/__tests__/OrganisationProvider.test.tsx.backup +0 -820
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx.backup +0 -911
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx.backup2 +0 -166
- package/src/rbac/cli/__tests__/policy-manager.test.ts +0 -339
- package/src/rbac/cli/policy-manager.ts +0 -443
- package/dist/{DataTable-2QR5TER5.js.map → DataTable-4GAVPIEG.js.map} +0 -0
- package/dist/{UnifiedAuthProvider-K4NRGXL4.js.map → UnifiedAuthProvider-3NKDOSOK.js.map} +0 -0
- package/dist/{eventContext-BBA42P6G.js.map → useInactivityTracker-MRUU55XI.js.map} +0 -0
- package/dist/{validation-PM_iOaTI.d.ts → validation-D8VcbTzC.d.ts} +2 -2
- /package/src/utils/{appNameResolver.test.ts.backup → appNameResolver.test 2.ts} +0 -0
|
@@ -1,426 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
} from '
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
import type { PaletteData, ColorPalette } from '../theming/runtime';
|
|
1
|
+
/**
|
|
2
|
+
* @file Re-export for EventProvider
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module Providers
|
|
5
|
+
* @since 0.1.0
|
|
6
|
+
*
|
|
7
|
+
* Re-exports the service-based EventProvider for backward compatibility.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export { EventServiceProvider as EventProvider } from './services/EventServiceProvider';
|
|
11
|
+
export type { EventServiceProviderProps as EventProviderProps } from './services/EventServiceProvider';
|
|
12
|
+
|
|
13
|
+
// Re-export context and hook
|
|
14
|
+
export { EventServiceContext, useEventService } from './services/EventServiceProvider';
|
|
15
|
+
export type { EventServiceContextType, EventContextType } from './services/EventServiceProvider';
|
|
17
16
|
|
|
18
|
-
import { Event } from '../types/unified';
|
|
19
|
-
|
|
20
|
-
export interface EventContextType {
|
|
21
|
-
events: Event[];
|
|
22
|
-
selectedEvent: Event | null;
|
|
23
|
-
isLoading: boolean;
|
|
24
|
-
error: Error | null;
|
|
25
|
-
setSelectedEvent: (event: Event | null) => void;
|
|
26
|
-
refreshEvents: () => Promise<void>;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const EventContext = createContext<EventContextType | undefined>(undefined);
|
|
30
|
-
|
|
31
|
-
export const useEvents = () => {
|
|
32
|
-
const context = useContext(EventContext);
|
|
33
|
-
if (context === undefined) {
|
|
34
|
-
throw new Error('useEvents must be used within an EventProvider');
|
|
35
|
-
}
|
|
36
|
-
return context;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export interface EventProviderProps {
|
|
40
|
-
children: React.ReactNode;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Helper function to get the next event by date
|
|
44
|
-
function getNextEventByDate(events: Event[]): Event | null {
|
|
45
|
-
if (!events || events.length === 0) {
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const now = new Date();
|
|
50
|
-
const futureEvents = events.filter(event => {
|
|
51
|
-
if (!event.event_date) return false;
|
|
52
|
-
const eventDate = new Date(event.event_date);
|
|
53
|
-
return eventDate >= now;
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
if (futureEvents.length === 0) {
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Sort by date (ascending) to get the next event
|
|
61
|
-
const sortedFutureEvents = futureEvents.sort((a, b) => {
|
|
62
|
-
const dateA = new Date(a.event_date!);
|
|
63
|
-
const dateB = new Date(b.event_date!);
|
|
64
|
-
return dateA.getTime() - dateB.getTime();
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
return sortedFutureEvents[0];
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export function EventProvider({ children }: EventProviderProps) {
|
|
71
|
-
const [events, setEvents] = useState<Event[]>([]);
|
|
72
|
-
const [selectedEvent, setSelectedEventState] = useState<Event | null>(null);
|
|
73
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
74
|
-
const [error, setError] = useState<Error | null>(null);
|
|
75
|
-
const { user, session, supabase, appName, setSelectedEventId } = useUnifiedAuth();
|
|
76
|
-
|
|
77
|
-
// Refs to prevent infinite loops
|
|
78
|
-
const isInitializedRef = useRef(false);
|
|
79
|
-
const isFetchingRef = useRef(false);
|
|
80
|
-
const hasAutoSelectedRef = useRef(false);
|
|
81
|
-
const userClearedEventRef = useRef(false);
|
|
82
|
-
const setSelectedEventIdRef = useRef(setSelectedEventId);
|
|
83
|
-
|
|
84
|
-
// Try to get organisation context, but don't fail if not available
|
|
85
|
-
let selectedOrganisation = null;
|
|
86
|
-
let ensureOrganisationContext = null;
|
|
87
|
-
|
|
88
|
-
try {
|
|
89
|
-
const orgContext = useOrganisations();
|
|
90
|
-
selectedOrganisation = orgContext.selectedOrganisation;
|
|
91
|
-
ensureOrganisationContext = orgContext.ensureOrganisationContext;
|
|
92
|
-
} catch (error) {
|
|
93
|
-
console.warn('[EventProvider] Organisation context not available:', error);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Load persisted event selection with tab-scoped storage
|
|
97
|
-
const loadPersistedEvent = useCallback(async (events: Event[]) => {
|
|
98
|
-
try {
|
|
99
|
-
// Try sessionStorage first (tab-specific)
|
|
100
|
-
let persistedEventId = sessionStorage.getItem('pace-core-selected-event');
|
|
101
|
-
|
|
102
|
-
// Fallback to localStorage if no sessionStorage value (for new tabs)
|
|
103
|
-
if (!persistedEventId) {
|
|
104
|
-
persistedEventId = localStorage.getItem('pace-core-selected-event');
|
|
105
|
-
// If we found a value in localStorage, also store it in sessionStorage for this tab
|
|
106
|
-
if (persistedEventId) {
|
|
107
|
-
sessionStorage.setItem('pace-core-selected-event', persistedEventId);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (persistedEventId && events.length > 0) {
|
|
112
|
-
const persistedEvent = events.find(event => event.event_id === persistedEventId);
|
|
113
|
-
if (persistedEvent) {
|
|
114
|
-
DebugLogger.log('EventProvider', 'Restoring persisted event:', persistedEvent.event_name);
|
|
115
|
-
setSelectedEventState(persistedEvent);
|
|
116
|
-
setSelectedEventId(persistedEventId);
|
|
117
|
-
return true;
|
|
118
|
-
} else {
|
|
119
|
-
DebugLogger.log('EventProvider', 'Persisted event not found in current events, clearing storage');
|
|
120
|
-
// Clear invalid persisted event
|
|
121
|
-
sessionStorage.removeItem('pace-core-selected-event');
|
|
122
|
-
localStorage.removeItem('pace-core-selected-event');
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
} catch (error) {
|
|
126
|
-
console.warn('[EventProvider] Failed to load persisted event:', error);
|
|
127
|
-
}
|
|
128
|
-
return false;
|
|
129
|
-
}, [setSelectedEventId]);
|
|
130
|
-
|
|
131
|
-
// Persist event selection with tab-scoped storage
|
|
132
|
-
const persistEventSelection = useCallback((eventId: string) => {
|
|
133
|
-
try {
|
|
134
|
-
// Store in sessionStorage for tab-specific persistence
|
|
135
|
-
sessionStorage.setItem('pace-core-selected-event', eventId);
|
|
136
|
-
// Also store in localStorage as fallback for new tabs
|
|
137
|
-
localStorage.setItem('pace-core-selected-event', eventId);
|
|
138
|
-
} catch (error) {
|
|
139
|
-
console.warn('[EventProvider] Failed to persist event selection:', error);
|
|
140
|
-
}
|
|
141
|
-
}, []);
|
|
142
|
-
|
|
143
|
-
// Auto-select next event
|
|
144
|
-
const autoSelectNextEvent = useCallback((events: Event[]) => {
|
|
145
|
-
const nextEvent = getNextEventByDate(events);
|
|
146
|
-
if (nextEvent) {
|
|
147
|
-
DebugLogger.log('EventProvider', 'Auto-selecting next event:', nextEvent.event_name);
|
|
148
|
-
setSelectedEventState(nextEvent);
|
|
149
|
-
setSelectedEventId(nextEvent.event_id);
|
|
150
|
-
persistEventSelection(nextEvent.event_id);
|
|
151
|
-
}
|
|
152
|
-
}, [setSelectedEventId, persistEventSelection]);
|
|
153
|
-
|
|
154
|
-
// Main fetch function
|
|
155
|
-
const fetchEvents = useCallback(async () => {
|
|
156
|
-
if (!user || !session || !supabase || !appName || !selectedOrganisation) {
|
|
157
|
-
DebugLogger.log('EventProvider', 'Missing required dependencies, skipping fetch');
|
|
158
|
-
setIsLoading(false);
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Prevent multiple simultaneous fetches
|
|
163
|
-
if (isFetchingRef.current) {
|
|
164
|
-
DebugLogger.log('EventProvider', 'Already fetching events, skipping');
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
DebugLogger.log('EventProvider', 'User and organisation found, fetching events for:', {
|
|
169
|
-
userId: user.id,
|
|
170
|
-
appName: appName,
|
|
171
|
-
organisationId: selectedOrganisation.id,
|
|
172
|
-
organisationName: selectedOrganisation.display_name
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
isFetchingRef.current = true;
|
|
176
|
-
let isMounted = true;
|
|
177
|
-
|
|
178
|
-
try {
|
|
179
|
-
// Ensure organisation context is set
|
|
180
|
-
if (ensureOrganisationContext) {
|
|
181
|
-
await ensureOrganisationContext();
|
|
182
|
-
await setOrganisationContext(supabase, selectedOrganisation.id);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// Call the RPC function following the established pattern
|
|
186
|
-
DebugLogger.log('EventProvider', 'Calling data_user_events_get RPC with:', {
|
|
187
|
-
user_id: user.id,
|
|
188
|
-
organisation_id: selectedOrganisation.id,
|
|
189
|
-
app_name: appName
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
const { data, error: rpcError } = await supabase.rpc('data_user_events_get', {
|
|
193
|
-
p_user_id: user.id,
|
|
194
|
-
p_organisation_id: selectedOrganisation.id,
|
|
195
|
-
p_app_name: appName
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
DebugLogger.log('EventProvider', 'RPC response:', {
|
|
199
|
-
data,
|
|
200
|
-
error: rpcError,
|
|
201
|
-
dataLength: data?.length || 0,
|
|
202
|
-
organisationId: selectedOrganisation.id
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
if (rpcError) {
|
|
206
|
-
throw new Error(rpcError.message || 'Failed to fetch events');
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
if (isMounted) {
|
|
210
|
-
const eventsData = data || [];
|
|
211
|
-
console.log('[EventProvider] Loaded events:', eventsData.map((event: any) => ({
|
|
212
|
-
eventId: event.event_id,
|
|
213
|
-
eventName: event.event_name,
|
|
214
|
-
organisationId: event.organisation_id,
|
|
215
|
-
selectedOrganisationId: selectedOrganisation?.id
|
|
216
|
-
})));
|
|
217
|
-
|
|
218
|
-
// Transform the data to match our Event interface
|
|
219
|
-
const transformedEvents: Event[] = eventsData.map((event: any) => ({
|
|
220
|
-
id: event.event_id, // Use event_id as the primary id
|
|
221
|
-
event_id: event.event_id,
|
|
222
|
-
event_name: event.event_name,
|
|
223
|
-
event_date: event.event_date,
|
|
224
|
-
event_venue: event.event_venue,
|
|
225
|
-
event_participants: event.event_participants,
|
|
226
|
-
event_colours: event.event_colours,
|
|
227
|
-
event_logo: '', // No logo field in event table
|
|
228
|
-
organisation_id: event.organisation_id,
|
|
229
|
-
is_visible: event.is_visible,
|
|
230
|
-
// Legacy compatibility
|
|
231
|
-
name: event.event_name,
|
|
232
|
-
start_date: event.event_date
|
|
233
|
-
}));
|
|
234
|
-
|
|
235
|
-
setEvents(transformedEvents);
|
|
236
|
-
setError(null);
|
|
237
|
-
|
|
238
|
-
// Note: Event colors are automatically applied when selectedEvent changes (see useEffect below)
|
|
239
|
-
|
|
240
|
-
// Reset auto-selection ref for new events
|
|
241
|
-
hasAutoSelectedRef.current = false;
|
|
242
|
-
|
|
243
|
-
// Try to restore persisted event first
|
|
244
|
-
const persistedEventLoaded = await loadPersistedEvent(transformedEvents);
|
|
245
|
-
|
|
246
|
-
// If no persisted event was loaded, auto-select the next event
|
|
247
|
-
if (!persistedEventLoaded) {
|
|
248
|
-
const nextEvent = getNextEventByDate(transformedEvents);
|
|
249
|
-
if (nextEvent) {
|
|
250
|
-
DebugLogger.log('EventProvider', 'Auto-selecting next event after no persisted event found:', nextEvent.event_name);
|
|
251
|
-
hasAutoSelectedRef.current = true;
|
|
252
|
-
setSelectedEventState(nextEvent);
|
|
253
|
-
setSelectedEventIdRef.current(nextEvent.event_id);
|
|
254
|
-
persistEventSelection(nextEvent.event_id);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
} catch (err) {
|
|
259
|
-
console.error('[EventProvider] Error fetching events:', err);
|
|
260
|
-
const _error = err instanceof Error ? err : new Error('Unknown error occurred');
|
|
261
|
-
|
|
262
|
-
if (isMounted) {
|
|
263
|
-
setError(_error);
|
|
264
|
-
setEvents([]);
|
|
265
|
-
}
|
|
266
|
-
} finally {
|
|
267
|
-
if (isMounted) {
|
|
268
|
-
setIsLoading(false);
|
|
269
|
-
}
|
|
270
|
-
isFetchingRef.current = false;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
return () => {
|
|
274
|
-
isMounted = false;
|
|
275
|
-
};
|
|
276
|
-
}, [user, session, supabase, appName, selectedOrganisation, ensureOrganisationContext, loadPersistedEvent, autoSelectNextEvent]);
|
|
277
|
-
|
|
278
|
-
// Initialize events only once
|
|
279
|
-
useEffect(() => {
|
|
280
|
-
if (!isInitializedRef.current) {
|
|
281
|
-
isInitializedRef.current = true;
|
|
282
|
-
fetchEvents();
|
|
283
|
-
}
|
|
284
|
-
}, [fetchEvents]);
|
|
285
|
-
|
|
286
|
-
// Update ref when setSelectedEventId changes
|
|
287
|
-
useEffect(() => {
|
|
288
|
-
setSelectedEventIdRef.current = setSelectedEventId;
|
|
289
|
-
}, [setSelectedEventId]);
|
|
290
|
-
|
|
291
|
-
// Auto-select next event when events are loaded and no event is selected
|
|
292
|
-
useLayoutEffect(() => {
|
|
293
|
-
if (events.length > 0 && !selectedEvent && !hasAutoSelectedRef.current && !userClearedEventRef.current) {
|
|
294
|
-
const nextEvent = getNextEventByDate(events);
|
|
295
|
-
if (nextEvent) {
|
|
296
|
-
DebugLogger.log('EventProvider', 'Auto-selecting next event:', nextEvent.event_name);
|
|
297
|
-
hasAutoSelectedRef.current = true;
|
|
298
|
-
setSelectedEventState(nextEvent);
|
|
299
|
-
setSelectedEventIdRef.current(nextEvent.event_id);
|
|
300
|
-
persistEventSelection(nextEvent.event_id);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}, [events, selectedEvent]);
|
|
304
|
-
|
|
305
|
-
// Apply event theming when selected event changes
|
|
306
|
-
useEffect(() => {
|
|
307
|
-
console.log('[EventProvider] Event theming useEffect triggered, selectedEvent:', selectedEvent?.event_name, selectedEvent?.event_colours);
|
|
308
|
-
|
|
309
|
-
if (!selectedEvent) {
|
|
310
|
-
console.log('[EventProvider] No selected event, clearing palette');
|
|
311
|
-
clearPalette();
|
|
312
|
-
return;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
const eventColours = selectedEvent.event_colours;
|
|
316
|
-
console.log('[EventProvider] Event colours:', eventColours);
|
|
317
|
-
console.log('[EventProvider] Event colours keys:', Object.keys(eventColours as object || {}));
|
|
318
|
-
|
|
319
|
-
if (!eventColours || typeof eventColours !== 'object') {
|
|
320
|
-
console.log('[EventProvider] No valid event_colours, clearing palette');
|
|
321
|
-
clearPalette();
|
|
322
|
-
return;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// Map event palette keys (ev-main, ev-sec, ev-acc) to app palette keys (main, sec, acc)
|
|
326
|
-
// This matches the format used in pace-admin's eventColorManager
|
|
327
|
-
const evMainPalette = ((eventColours as any)['ev-main'] as ColorPalette) || ((eventColours as any).main as ColorPalette) || {};
|
|
328
|
-
const evSecPalette = ((eventColours as any)['ev-sec'] as ColorPalette) || ((eventColours as any).sec as ColorPalette) || {};
|
|
329
|
-
const evAccPalette = ((eventColours as any)['ev-acc'] as ColorPalette) || ((eventColours as any).acc as ColorPalette) || {};
|
|
330
|
-
|
|
331
|
-
console.log('[EventProvider] Mapped palettes:', {
|
|
332
|
-
'ev-main': Object.keys(evMainPalette),
|
|
333
|
-
'ev-sec': Object.keys(evSecPalette),
|
|
334
|
-
'ev-acc': Object.keys(evAccPalette),
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
const fullPalette: PaletteData = {
|
|
338
|
-
main: evMainPalette,
|
|
339
|
-
sec: evSecPalette,
|
|
340
|
-
acc: evAccPalette,
|
|
341
|
-
};
|
|
342
|
-
|
|
343
|
-
// Check if we have at least one valid palette
|
|
344
|
-
if (!fullPalette.main && !fullPalette.sec && !fullPalette.acc) {
|
|
345
|
-
console.log('[EventProvider] No valid palettes found in event_colours, clearing palette');
|
|
346
|
-
clearPalette();
|
|
347
|
-
return;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
console.log('[EventProvider] Applying full palette:', fullPalette);
|
|
351
|
-
|
|
352
|
-
try {
|
|
353
|
-
applyPalette(fullPalette);
|
|
354
|
-
console.log('[EventProvider] Palette applied successfully');
|
|
355
|
-
} catch (error) {
|
|
356
|
-
console.error('[EventProvider] Failed to apply event palette:', error);
|
|
357
|
-
}
|
|
358
|
-
}, [selectedEvent]);
|
|
359
|
-
|
|
360
|
-
const setSelectedEvent = useCallback((event: Event | null) => {
|
|
361
|
-
if (event) {
|
|
362
|
-
// SECURITY: Validate event belongs to current organisation
|
|
363
|
-
try {
|
|
364
|
-
console.log('[EventProvider] Event selection validation:', {
|
|
365
|
-
eventId: event.event_id,
|
|
366
|
-
eventName: event.event_name,
|
|
367
|
-
eventOrganisationId: event.organisation_id,
|
|
368
|
-
selectedOrganisationId: selectedOrganisation?.id,
|
|
369
|
-
selectedOrganisationName: selectedOrganisation?.display_name,
|
|
370
|
-
match: event.organisation_id === selectedOrganisation?.id
|
|
371
|
-
});
|
|
372
|
-
|
|
373
|
-
if (selectedOrganisation && event.organisation_id !== selectedOrganisation.id) {
|
|
374
|
-
console.error('[EventProvider] Event organisation_id does not match selected organisation', {
|
|
375
|
-
eventOrganisationId: event.organisation_id,
|
|
376
|
-
selectedOrganisationId: selectedOrganisation.id,
|
|
377
|
-
eventName: event.event_name
|
|
378
|
-
});
|
|
379
|
-
return;
|
|
380
|
-
}
|
|
381
|
-
} catch (error) {
|
|
382
|
-
console.error('[EventProvider] Error during event validation:', error);
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
setSelectedEventState(event);
|
|
386
|
-
setSelectedEventId(event.event_id);
|
|
387
|
-
persistEventSelection(event.event_id);
|
|
388
|
-
// Reset the user cleared flag when selecting an event
|
|
389
|
-
userClearedEventRef.current = false;
|
|
390
|
-
} else {
|
|
391
|
-
setSelectedEventState(null);
|
|
392
|
-
setSelectedEventId(null);
|
|
393
|
-
// Clear both sessionStorage and localStorage
|
|
394
|
-
sessionStorage.removeItem('pace-core-selected-event');
|
|
395
|
-
localStorage.removeItem('pace-core-selected-event');
|
|
396
|
-
// Reset the auto-selection flag when clearing the event
|
|
397
|
-
hasAutoSelectedRef.current = false;
|
|
398
|
-
// Mark that user explicitly cleared the event to prevent auto-selection
|
|
399
|
-
userClearedEventRef.current = true;
|
|
400
|
-
}
|
|
401
|
-
}, [selectedOrganisation, setSelectedEventId, persistEventSelection]);
|
|
402
|
-
|
|
403
|
-
const refreshEvents = useCallback(async () => {
|
|
404
|
-
isInitializedRef.current = false;
|
|
405
|
-
isFetchingRef.current = false;
|
|
406
|
-
// Reset the user cleared flag when refreshing events
|
|
407
|
-
userClearedEventRef.current = false;
|
|
408
|
-
await fetchEvents();
|
|
409
|
-
}, [fetchEvents]);
|
|
410
|
-
|
|
411
|
-
// Memoize the context value to prevent unnecessary re-renders
|
|
412
|
-
const contextValue: EventContextType = useMemo(() => ({
|
|
413
|
-
events,
|
|
414
|
-
selectedEvent,
|
|
415
|
-
isLoading,
|
|
416
|
-
error,
|
|
417
|
-
setSelectedEvent,
|
|
418
|
-
refreshEvents,
|
|
419
|
-
}), [events, selectedEvent, isLoading, error, setSelectedEvent, refreshEvents]);
|
|
420
|
-
|
|
421
|
-
return (
|
|
422
|
-
<EventContext.Provider value={contextValue}>
|
|
423
|
-
{children}
|
|
424
|
-
</EventContext.Provider>
|
|
425
|
-
);
|
|
426
|
-
}
|
|
@@ -1,238 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @file
|
|
2
|
+
* @file Re-export for InactivityProvider
|
|
3
3
|
* @package @jmruthers/pace-core
|
|
4
|
-
* @module Providers
|
|
4
|
+
* @module Providers
|
|
5
5
|
* @since 0.1.0
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* Separated from UnifiedAuthProvider for better maintainability.
|
|
6
|
+
*
|
|
7
|
+
* Re-exports the service-based InactivityProvider for backward compatibility.
|
|
9
8
|
*/
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
import { InactivityWarningModal } from '../components/InactivityWarningModal/InactivityWarningModal';
|
|
10
|
+
export { InactivityServiceProvider as InactivityProvider } from './services/InactivityServiceProvider';
|
|
11
|
+
export type { InactivityServiceProviderProps as InactivityProviderProps, InactivityServiceContextType as InactivityContextType } from './services/InactivityServiceProvider';
|
|
14
12
|
|
|
15
|
-
//
|
|
16
|
-
export
|
|
17
|
-
// Inactivity state
|
|
18
|
-
showInactivityWarning: boolean;
|
|
19
|
-
inactivityTimeRemaining: number;
|
|
20
|
-
isIdle: boolean;
|
|
21
|
-
timeRemaining: number;
|
|
22
|
-
showWarning: boolean;
|
|
23
|
-
isTracking: boolean;
|
|
24
|
-
|
|
25
|
-
// Inactivity methods
|
|
26
|
-
resetActivity: () => void;
|
|
27
|
-
startTracking: () => void;
|
|
28
|
-
stopTracking: () => void;
|
|
29
|
-
handleIdleLogout: () => Promise<void>;
|
|
30
|
-
handleStaySignedIn: () => void;
|
|
31
|
-
handleSignOutNow: () => Promise<void>;
|
|
32
|
-
}
|
|
13
|
+
// Re-export hook
|
|
14
|
+
export { useInactivityService as useInactivity } from '../hooks/services/useInactivityService';
|
|
33
15
|
|
|
34
|
-
const InactivityContext = createContext<InactivityContextType | undefined>(undefined);
|
|
35
|
-
|
|
36
|
-
export const useInactivity = () => {
|
|
37
|
-
const context = useContext(InactivityContext);
|
|
38
|
-
if (!context) {
|
|
39
|
-
throw new Error('useInactivity must be used within an InactivityProvider');
|
|
40
|
-
}
|
|
41
|
-
return context;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
export interface InactivityProviderProps {
|
|
45
|
-
children: React.ReactNode;
|
|
46
|
-
user: any; // User from auth context
|
|
47
|
-
session: any; // Session from auth context
|
|
48
|
-
supabaseClient: any; // Supabase client
|
|
49
|
-
idleTimeoutMs?: number; // Default: 30 minutes
|
|
50
|
-
warnBeforeMs?: number; // Default: 60 seconds
|
|
51
|
-
onIdleLogout?: (reason: 'inactivity') => void; // App handles redirect/navigation
|
|
52
|
-
renderInactivityWarning?: (args: {
|
|
53
|
-
timeRemaining: number;
|
|
54
|
-
onStaySignedIn: () => void;
|
|
55
|
-
onSignOutNow: () => void;
|
|
56
|
-
}) => React.ReactNode; // Optional custom warning UI
|
|
57
|
-
dangerouslyDisableInactivity?: boolean; // Dev-only; must not disable in production
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export function InactivityProvider({
|
|
61
|
-
children,
|
|
62
|
-
user,
|
|
63
|
-
session,
|
|
64
|
-
supabaseClient,
|
|
65
|
-
idleTimeoutMs = 30 * 60 * 1000, // 30 minutes
|
|
66
|
-
warnBeforeMs = 60 * 1000, // 60 seconds
|
|
67
|
-
onIdleLogout,
|
|
68
|
-
renderInactivityWarning,
|
|
69
|
-
dangerouslyDisableInactivity = false
|
|
70
|
-
}: InactivityProviderProps) {
|
|
71
|
-
// Inactivity state
|
|
72
|
-
const [showInactivityWarning, setShowInactivityWarning] = useState(false);
|
|
73
|
-
const [inactivityTimeRemaining, setInactivityTimeRemaining] = useState(0);
|
|
74
|
-
|
|
75
|
-
// Production safety check for inactivity feature
|
|
76
|
-
useEffect(() => {
|
|
77
|
-
if (typeof window !== 'undefined') {
|
|
78
|
-
const isProduction = import.meta.env.MODE === 'production';
|
|
79
|
-
|
|
80
|
-
if (isProduction && dangerouslyDisableInactivity) {
|
|
81
|
-
console.error('[InactivityProvider] CRITICAL: dangerouslyDisableInactivity is not allowed in production! Auto-enabling inactivity feature.');
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (!isProduction && dangerouslyDisableInactivity) {
|
|
85
|
-
console.warn('[InactivityProvider] Inactivity feature disabled for development. This will NOT work in production.');
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}, [dangerouslyDisableInactivity]);
|
|
89
|
-
|
|
90
|
-
// Inactivity tracking
|
|
91
|
-
const isInactivityEnabled = typeof window !== 'undefined' &&
|
|
92
|
-
(import.meta.env.MODE !== 'production' ? !dangerouslyDisableInactivity : true);
|
|
93
|
-
|
|
94
|
-
const {
|
|
95
|
-
isIdle,
|
|
96
|
-
timeRemaining,
|
|
97
|
-
showWarning,
|
|
98
|
-
resetActivity,
|
|
99
|
-
startTracking,
|
|
100
|
-
stopTracking,
|
|
101
|
-
isTracking
|
|
102
|
-
} = useInactivityTracker({
|
|
103
|
-
idleTimeoutMs,
|
|
104
|
-
warnBeforeMs,
|
|
105
|
-
enabled: isInactivityEnabled && !!user && !!session,
|
|
106
|
-
onIdle: useCallback(() => {
|
|
107
|
-
// Handle idle logout inline to avoid circular dependency
|
|
108
|
-
setShowInactivityWarning(false);
|
|
109
|
-
setInactivityTimeRemaining(0);
|
|
110
|
-
|
|
111
|
-
// Sign out via Supabase
|
|
112
|
-
if (supabaseClient) {
|
|
113
|
-
supabaseClient.auth.signOut().catch((error: any) => {
|
|
114
|
-
console.error('[InactivityProvider] Error during idle logout:', error);
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Call app callback for navigation/redirect
|
|
119
|
-
onIdleLogout?.('inactivity');
|
|
120
|
-
}, [supabaseClient, onIdleLogout]),
|
|
121
|
-
onWarning: useCallback(() => {
|
|
122
|
-
setShowInactivityWarning(true);
|
|
123
|
-
setInactivityTimeRemaining(warnBeforeMs);
|
|
124
|
-
}, [warnBeforeMs]),
|
|
125
|
-
onActivity: useCallback(() => {
|
|
126
|
-
setShowInactivityWarning(false);
|
|
127
|
-
setInactivityTimeRemaining(0);
|
|
128
|
-
}, [])
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
// Handle idle logout (for manual calls)
|
|
132
|
-
const handleIdleLogout = useCallback(async () => {
|
|
133
|
-
// Hide warning
|
|
134
|
-
setShowInactivityWarning(false);
|
|
135
|
-
setInactivityTimeRemaining(0);
|
|
136
|
-
|
|
137
|
-
// Stop tracking
|
|
138
|
-
stopTracking();
|
|
139
|
-
|
|
140
|
-
// Sign out via Supabase
|
|
141
|
-
try {
|
|
142
|
-
if (supabaseClient) {
|
|
143
|
-
await supabaseClient.auth.signOut();
|
|
144
|
-
}
|
|
145
|
-
} catch (error: any) {
|
|
146
|
-
console.error('[InactivityProvider] Error during idle logout:', error);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Call app callback for navigation/redirect
|
|
150
|
-
onIdleLogout?.('inactivity');
|
|
151
|
-
}, [supabaseClient, onIdleLogout, stopTracking]);
|
|
152
|
-
|
|
153
|
-
// Handle stay signed in
|
|
154
|
-
const handleStaySignedIn = useCallback(() => {
|
|
155
|
-
setShowInactivityWarning(false);
|
|
156
|
-
setInactivityTimeRemaining(0);
|
|
157
|
-
resetActivity();
|
|
158
|
-
}, [resetActivity]);
|
|
159
|
-
|
|
160
|
-
// Handle sign out now
|
|
161
|
-
const handleSignOutNow = useCallback(async () => {
|
|
162
|
-
setShowInactivityWarning(false);
|
|
163
|
-
setInactivityTimeRemaining(0);
|
|
164
|
-
stopTracking();
|
|
165
|
-
|
|
166
|
-
// Sign out via Supabase
|
|
167
|
-
try {
|
|
168
|
-
if (supabaseClient) {
|
|
169
|
-
await supabaseClient.auth.signOut();
|
|
170
|
-
}
|
|
171
|
-
} catch (error: any) {
|
|
172
|
-
console.error('[InactivityProvider] Error during manual sign out:', error);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Call app callback for navigation/redirect
|
|
176
|
-
onIdleLogout?.('inactivity');
|
|
177
|
-
}, [supabaseClient, onIdleLogout, stopTracking]);
|
|
178
|
-
|
|
179
|
-
// Update inactivity time remaining
|
|
180
|
-
useEffect(() => {
|
|
181
|
-
if (showWarning && timeRemaining > 0) {
|
|
182
|
-
setInactivityTimeRemaining(Math.ceil(timeRemaining / 1000)); // Convert to seconds
|
|
183
|
-
}
|
|
184
|
-
}, [showWarning, timeRemaining]);
|
|
185
|
-
|
|
186
|
-
// Memoized context value
|
|
187
|
-
const contextValue = useMemo<InactivityContextType>(() => ({
|
|
188
|
-
showInactivityWarning,
|
|
189
|
-
inactivityTimeRemaining,
|
|
190
|
-
isIdle,
|
|
191
|
-
timeRemaining,
|
|
192
|
-
showWarning,
|
|
193
|
-
isTracking,
|
|
194
|
-
resetActivity,
|
|
195
|
-
startTracking,
|
|
196
|
-
stopTracking,
|
|
197
|
-
handleIdleLogout,
|
|
198
|
-
handleStaySignedIn,
|
|
199
|
-
handleSignOutNow,
|
|
200
|
-
}), [
|
|
201
|
-
showInactivityWarning,
|
|
202
|
-
inactivityTimeRemaining,
|
|
203
|
-
isIdle,
|
|
204
|
-
timeRemaining,
|
|
205
|
-
showWarning,
|
|
206
|
-
isTracking,
|
|
207
|
-
resetActivity,
|
|
208
|
-
startTracking,
|
|
209
|
-
stopTracking,
|
|
210
|
-
handleIdleLogout,
|
|
211
|
-
handleStaySignedIn,
|
|
212
|
-
handleSignOutNow,
|
|
213
|
-
]);
|
|
214
|
-
|
|
215
|
-
return (
|
|
216
|
-
<InactivityContext.Provider value={contextValue}>
|
|
217
|
-
{children}
|
|
218
|
-
|
|
219
|
-
{/* Inactivity Warning Modal */}
|
|
220
|
-
{showInactivityWarning && (
|
|
221
|
-
renderInactivityWarning ? (
|
|
222
|
-
renderInactivityWarning({
|
|
223
|
-
timeRemaining: inactivityTimeRemaining,
|
|
224
|
-
onStaySignedIn: handleStaySignedIn,
|
|
225
|
-
onSignOutNow: handleSignOutNow
|
|
226
|
-
})
|
|
227
|
-
) : (
|
|
228
|
-
<InactivityWarningModal
|
|
229
|
-
isOpen={showInactivityWarning}
|
|
230
|
-
timeRemaining={inactivityTimeRemaining}
|
|
231
|
-
onStaySignedIn={handleStaySignedIn}
|
|
232
|
-
onSignOutNow={handleSignOutNow}
|
|
233
|
-
/>
|
|
234
|
-
)
|
|
235
|
-
)}
|
|
236
|
-
</InactivityContext.Provider>
|
|
237
|
-
);
|
|
238
|
-
}
|