@jmruthers/pace-core 0.5.74 → 0.5.75
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-2QR5TER5.js → DataTable-HWZQGASI.js} +8 -8
- package/dist/{PublicLoadingSpinner-DLpF5bbs.d.ts → PublicLoadingSpinner-BKNBT6b6.d.ts} +2 -2
- 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-UJMCGBLS.js → chunk-2CHATWBF.js} +5 -7
- package/dist/chunk-2CHATWBF.js.map +1 -0
- package/dist/{chunk-BKVGJVUR.js → chunk-2DFZ432F.js} +496 -30
- package/dist/chunk-2DFZ432F.js.map +1 -0
- package/dist/{chunk-LVQ26TCN.js → chunk-33PHABLB.js} +36 -3
- package/dist/chunk-33PHABLB.js.map +1 -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-IHMMNKNA.js → chunk-CY3AHGO4.js} +6256 -1937
- package/dist/chunk-CY3AHGO4.js.map +1 -0
- package/dist/{chunk-H2TNUICK.js → chunk-DAXLNIDY.js} +47 -49
- package/dist/chunk-DAXLNIDY.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-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-ORSMVXO2.js → chunk-ZTT2AXMX.js} +9 -14
- package/dist/chunk-ZTT2AXMX.js.map +1 -0
- package/dist/components.d.ts +4 -5
- package/dist/components.js +32 -39
- package/dist/components.js.map +1 -1
- package/dist/hooks.d.ts +3 -3
- package/dist/hooks.js +9 -8
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +156 -10
- package/dist/index.js +188 -93
- 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 +61 -5
- package/dist/rbac/index.js +13 -14
- 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/useInactivityTracker-MRUU55XI.js.map +1 -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/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/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 +179 -52
- package/docs/architecture/services.md +30 -32
- package/docs/breaking-changes.md +2 -5
- package/docs/migration/service-architecture.md +121 -260
- package/docs/rbac/README-rbac-rls-integration.md +48 -38
- 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 +650 -9
- package/src/__tests__/helpers/README.md +255 -0
- package/src/__tests__/helpers/index.ts +62 -0
- package/src/__tests__/helpers/supabaseMock.ts +27 -3
- package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -8
- package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +55 -0
- package/src/components/DataTable/core/ColumnManager.ts +10 -0
- package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +254 -0
- package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +193 -0
- 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/Dialog/examples/__tests__/HtmlDialogExample.test.tsx +71 -0
- package/src/components/Dialog/examples/__tests__/SimpleHtmlTest.test.tsx +122 -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/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/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/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 +9 -5
- 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__/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/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/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/styles/core.css +2 -0
- package/src/types/__tests__/guards.test.ts +246 -0
- package/src/types/guards.ts +1 -0
- package/src/types/organisation.ts +3 -2
- 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/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-UJMCGBLS.js.map +0 -1
- package/dist/chunk-V6BHACCH.js +0 -17
- package/dist/chunk-V6BHACCH.js.map +0 -1
- 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/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-HWZQGASI.js.map} +0 -0
- package/dist/{UnifiedAuthProvider-K4NRGXL4.js.map → UnifiedAuthProvider-3NKDOSOK.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
|
@@ -0,0 +1,2468 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AccessLevel,
|
|
3
|
+
init_unified
|
|
4
|
+
} from "./chunk-ULBI5JGB.js";
|
|
5
|
+
import {
|
|
6
|
+
DebugLogger,
|
|
7
|
+
init_debugLogger,
|
|
8
|
+
init_organisationContext,
|
|
9
|
+
setOrganisationContext
|
|
10
|
+
} from "./chunk-XLZ7U46Z.js";
|
|
11
|
+
import {
|
|
12
|
+
__esm
|
|
13
|
+
} from "./chunk-PLDDJCW6.js";
|
|
14
|
+
|
|
15
|
+
// src/services/base/BaseService.ts
|
|
16
|
+
var BaseService;
|
|
17
|
+
var init_BaseService = __esm({
|
|
18
|
+
"src/services/base/BaseService.ts"() {
|
|
19
|
+
"use strict";
|
|
20
|
+
BaseService = class {
|
|
21
|
+
constructor() {
|
|
22
|
+
this.subscribers = [];
|
|
23
|
+
this.isInitialized = false;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Subscribe to state changes
|
|
27
|
+
* @param callback Function to call when state changes
|
|
28
|
+
* @returns Unsubscribe function
|
|
29
|
+
*/
|
|
30
|
+
subscribe(callback) {
|
|
31
|
+
this.subscribers.push(callback);
|
|
32
|
+
return () => {
|
|
33
|
+
const index = this.subscribers.indexOf(callback);
|
|
34
|
+
if (index > -1) {
|
|
35
|
+
this.subscribers.splice(index, 1);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Notify all subscribers of state changes
|
|
41
|
+
* This triggers React re-renders
|
|
42
|
+
*/
|
|
43
|
+
notify() {
|
|
44
|
+
this.subscribers.forEach((callback) => {
|
|
45
|
+
try {
|
|
46
|
+
callback();
|
|
47
|
+
} catch (error) {
|
|
48
|
+
console.error("[BaseService] Error in subscriber callback:", error);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Initialize the service
|
|
54
|
+
* Override in subclasses to implement initialization logic
|
|
55
|
+
*/
|
|
56
|
+
async initialize() {
|
|
57
|
+
if (this.isInitialized) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
await this.doInitialize();
|
|
61
|
+
this.isInitialized = true;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Cleanup the service
|
|
65
|
+
* Override in subclasses to implement cleanup logic
|
|
66
|
+
*/
|
|
67
|
+
cleanup() {
|
|
68
|
+
this.subscribers = [];
|
|
69
|
+
this.doCleanup();
|
|
70
|
+
this.isInitialized = false;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Check if service is initialized
|
|
74
|
+
*/
|
|
75
|
+
getInitialized() {
|
|
76
|
+
return this.isInitialized;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// src/services/AuthService.ts
|
|
83
|
+
import { AuthError } from "@supabase/supabase-js";
|
|
84
|
+
var AuthService;
|
|
85
|
+
var init_AuthService = __esm({
|
|
86
|
+
"src/services/AuthService.ts"() {
|
|
87
|
+
"use strict";
|
|
88
|
+
init_BaseService();
|
|
89
|
+
init_debugLogger();
|
|
90
|
+
AuthService = class extends BaseService {
|
|
91
|
+
constructor(supabaseClient) {
|
|
92
|
+
super();
|
|
93
|
+
this.user = null;
|
|
94
|
+
this.session = null;
|
|
95
|
+
this.authLoading = true;
|
|
96
|
+
this.authError = null;
|
|
97
|
+
this.supabaseClient = null;
|
|
98
|
+
this.authStateSubscription = null;
|
|
99
|
+
this.supabaseClient = supabaseClient;
|
|
100
|
+
}
|
|
101
|
+
// Auth state getters
|
|
102
|
+
getUser() {
|
|
103
|
+
return this.user;
|
|
104
|
+
}
|
|
105
|
+
getSession() {
|
|
106
|
+
return this.session;
|
|
107
|
+
}
|
|
108
|
+
isAuthenticated() {
|
|
109
|
+
return !!(this.user && this.session);
|
|
110
|
+
}
|
|
111
|
+
isLoading() {
|
|
112
|
+
return this.authLoading;
|
|
113
|
+
}
|
|
114
|
+
getError() {
|
|
115
|
+
return this.authError;
|
|
116
|
+
}
|
|
117
|
+
getSupabaseClient() {
|
|
118
|
+
return this.supabaseClient;
|
|
119
|
+
}
|
|
120
|
+
// Auth methods
|
|
121
|
+
async signIn(email, password) {
|
|
122
|
+
if (!this.supabaseClient) {
|
|
123
|
+
const error = new AuthError("Supabase client not available");
|
|
124
|
+
this.authError = error;
|
|
125
|
+
this.notify();
|
|
126
|
+
return { user: null, session: null, error };
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
const { data, error } = await this.supabaseClient.auth.signInWithPassword({
|
|
130
|
+
email,
|
|
131
|
+
password: password || ""
|
|
132
|
+
});
|
|
133
|
+
if (error) {
|
|
134
|
+
this.authError = error;
|
|
135
|
+
this.user = null;
|
|
136
|
+
this.session = null;
|
|
137
|
+
} else {
|
|
138
|
+
this.authError = null;
|
|
139
|
+
this.user = data.user;
|
|
140
|
+
this.session = data.session;
|
|
141
|
+
}
|
|
142
|
+
this.notify();
|
|
143
|
+
return { user: data.user, session: data.session, error };
|
|
144
|
+
} catch (error) {
|
|
145
|
+
const authError = error instanceof AuthError ? error : new AuthError(error instanceof Error ? error.message : "Authentication failed");
|
|
146
|
+
this.authError = authError;
|
|
147
|
+
this.user = null;
|
|
148
|
+
this.session = null;
|
|
149
|
+
this.notify();
|
|
150
|
+
return { user: null, session: null, error: authError };
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
async signUp(email, password) {
|
|
154
|
+
if (!this.supabaseClient) {
|
|
155
|
+
const error = new AuthError("Supabase client not available");
|
|
156
|
+
this.authError = error;
|
|
157
|
+
this.notify();
|
|
158
|
+
return { user: null, session: null, error };
|
|
159
|
+
}
|
|
160
|
+
try {
|
|
161
|
+
const { data, error } = await this.supabaseClient.auth.signUp({
|
|
162
|
+
email,
|
|
163
|
+
password
|
|
164
|
+
});
|
|
165
|
+
if (error) {
|
|
166
|
+
this.authError = error;
|
|
167
|
+
this.user = null;
|
|
168
|
+
this.session = null;
|
|
169
|
+
} else {
|
|
170
|
+
this.authError = null;
|
|
171
|
+
this.user = data.user;
|
|
172
|
+
this.session = data.session;
|
|
173
|
+
}
|
|
174
|
+
this.notify();
|
|
175
|
+
return { user: data.user, session: data.session, error };
|
|
176
|
+
} catch (error) {
|
|
177
|
+
const authError = error instanceof AuthError ? error : new AuthError(error instanceof Error ? error.message : "Authentication failed");
|
|
178
|
+
this.authError = authError;
|
|
179
|
+
this.user = null;
|
|
180
|
+
this.session = null;
|
|
181
|
+
this.notify();
|
|
182
|
+
return { user: null, session: null, error: authError };
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
async signOut() {
|
|
186
|
+
if (!this.supabaseClient) {
|
|
187
|
+
const error = new AuthError("Supabase client not available");
|
|
188
|
+
this.authError = error;
|
|
189
|
+
this.notify();
|
|
190
|
+
return { user: null, session: null, error };
|
|
191
|
+
}
|
|
192
|
+
try {
|
|
193
|
+
const { error } = await this.supabaseClient.auth.signOut();
|
|
194
|
+
if (error) {
|
|
195
|
+
this.authError = error;
|
|
196
|
+
} else {
|
|
197
|
+
this.authError = null;
|
|
198
|
+
this.user = null;
|
|
199
|
+
this.session = null;
|
|
200
|
+
}
|
|
201
|
+
this.notify();
|
|
202
|
+
return { user: null, session: null, error };
|
|
203
|
+
} catch (error) {
|
|
204
|
+
const authError = error instanceof AuthError ? error : new AuthError(error instanceof Error ? error.message : "Authentication failed");
|
|
205
|
+
this.authError = authError;
|
|
206
|
+
this.user = null;
|
|
207
|
+
this.session = null;
|
|
208
|
+
this.notify();
|
|
209
|
+
return { user: null, session: null, error: authError };
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
async resetPassword(email) {
|
|
213
|
+
if (!this.supabaseClient) {
|
|
214
|
+
const error = new AuthError("Supabase client not available");
|
|
215
|
+
this.authError = error;
|
|
216
|
+
this.notify();
|
|
217
|
+
return { user: null, session: null, error };
|
|
218
|
+
}
|
|
219
|
+
try {
|
|
220
|
+
const { error } = await this.supabaseClient.auth.resetPasswordForEmail(email);
|
|
221
|
+
if (error) {
|
|
222
|
+
this.authError = error;
|
|
223
|
+
} else {
|
|
224
|
+
this.authError = null;
|
|
225
|
+
}
|
|
226
|
+
this.notify();
|
|
227
|
+
return { user: null, session: null, error };
|
|
228
|
+
} catch (error) {
|
|
229
|
+
const authError = error instanceof AuthError ? error : new AuthError(error instanceof Error ? error.message : "Authentication failed");
|
|
230
|
+
this.authError = authError;
|
|
231
|
+
this.notify();
|
|
232
|
+
return { user: null, session: null, error: authError };
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
async updatePassword(password) {
|
|
236
|
+
if (!this.supabaseClient) {
|
|
237
|
+
const error = new AuthError("Supabase client not available");
|
|
238
|
+
this.authError = error;
|
|
239
|
+
this.notify();
|
|
240
|
+
return { user: null, session: null, error };
|
|
241
|
+
}
|
|
242
|
+
try {
|
|
243
|
+
const { error } = await this.supabaseClient.auth.updateUser({
|
|
244
|
+
password
|
|
245
|
+
});
|
|
246
|
+
if (error) {
|
|
247
|
+
this.authError = error;
|
|
248
|
+
} else {
|
|
249
|
+
this.authError = null;
|
|
250
|
+
}
|
|
251
|
+
this.notify();
|
|
252
|
+
return { user: null, session: null, error };
|
|
253
|
+
} catch (error) {
|
|
254
|
+
const authError = error;
|
|
255
|
+
this.authError = authError;
|
|
256
|
+
this.notify();
|
|
257
|
+
return { user: null, session: null, error: authError };
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
async refreshSession() {
|
|
261
|
+
if (!this.supabaseClient) {
|
|
262
|
+
const error = new AuthError("Supabase client not available");
|
|
263
|
+
this.authError = error;
|
|
264
|
+
this.notify();
|
|
265
|
+
return { user: null, session: null, error };
|
|
266
|
+
}
|
|
267
|
+
try {
|
|
268
|
+
const { data, error } = await this.supabaseClient.auth.refreshSession();
|
|
269
|
+
if (error) {
|
|
270
|
+
this.authError = error;
|
|
271
|
+
this.user = null;
|
|
272
|
+
this.session = null;
|
|
273
|
+
} else {
|
|
274
|
+
this.authError = null;
|
|
275
|
+
if (data?.user && data?.session) {
|
|
276
|
+
this.user = data.user;
|
|
277
|
+
this.session = data.session;
|
|
278
|
+
} else {
|
|
279
|
+
this.user = null;
|
|
280
|
+
this.session = null;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
this.notify();
|
|
284
|
+
return {
|
|
285
|
+
user: data?.user && data?.session ? data.user : null,
|
|
286
|
+
session: data?.session ?? null,
|
|
287
|
+
error
|
|
288
|
+
};
|
|
289
|
+
} catch (error) {
|
|
290
|
+
const authError = error instanceof AuthError ? error : new AuthError(error instanceof Error ? error.message : "Authentication failed");
|
|
291
|
+
this.authError = authError;
|
|
292
|
+
this.user = null;
|
|
293
|
+
this.session = null;
|
|
294
|
+
this.notify();
|
|
295
|
+
return { user: null, session: null, error: authError };
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
// Lifecycle methods
|
|
299
|
+
async initialize() {
|
|
300
|
+
await super.initialize();
|
|
301
|
+
await this.setupAuthStateListener();
|
|
302
|
+
await this.restoreSession();
|
|
303
|
+
}
|
|
304
|
+
cleanup() {
|
|
305
|
+
if (this.authStateSubscription && typeof this.authStateSubscription.unsubscribe === "function") {
|
|
306
|
+
this.authStateSubscription.unsubscribe();
|
|
307
|
+
this.authStateSubscription = null;
|
|
308
|
+
}
|
|
309
|
+
super.cleanup();
|
|
310
|
+
}
|
|
311
|
+
async doInitialize() {
|
|
312
|
+
this.setupErrorHandlers();
|
|
313
|
+
}
|
|
314
|
+
doCleanup() {
|
|
315
|
+
this.removeErrorHandlers();
|
|
316
|
+
}
|
|
317
|
+
async setupAuthStateListener() {
|
|
318
|
+
if (!this.supabaseClient) {
|
|
319
|
+
this.authLoading = false;
|
|
320
|
+
this.notify();
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
try {
|
|
324
|
+
this.authStateSubscription = this.supabaseClient.auth.onAuthStateChange(
|
|
325
|
+
(event, session) => {
|
|
326
|
+
try {
|
|
327
|
+
DebugLogger.log("AuthService", "Auth state changed:", event, session?.user?.email);
|
|
328
|
+
if (event === "SIGNED_OUT") {
|
|
329
|
+
DebugLogger.log("AuthService", "User signed out, clearing all state");
|
|
330
|
+
this.session = null;
|
|
331
|
+
this.user = null;
|
|
332
|
+
this.authError = null;
|
|
333
|
+
} else if (event === "SIGNED_IN" || event === "TOKEN_REFRESHED") {
|
|
334
|
+
DebugLogger.log("AuthService", "User signed in or token refreshed");
|
|
335
|
+
this.session = session;
|
|
336
|
+
this.user = session?.user ?? null;
|
|
337
|
+
if (session) {
|
|
338
|
+
this.authError = null;
|
|
339
|
+
}
|
|
340
|
+
} else if (event === "INITIAL_SESSION") {
|
|
341
|
+
DebugLogger.log("AuthService", "Initial session event");
|
|
342
|
+
if (session) {
|
|
343
|
+
this.session = session;
|
|
344
|
+
this.user = session.user ?? null;
|
|
345
|
+
this.authError = null;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
this.authLoading = false;
|
|
349
|
+
this.notify();
|
|
350
|
+
} catch (error) {
|
|
351
|
+
console.warn("[AuthService] Error in auth state change handler:", error);
|
|
352
|
+
this.authLoading = false;
|
|
353
|
+
this.notify();
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
);
|
|
357
|
+
} catch (error) {
|
|
358
|
+
console.error("[AuthService] Failed to setup auth state listener:", error);
|
|
359
|
+
throw error;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
async restoreSession() {
|
|
363
|
+
if (!this.supabaseClient) {
|
|
364
|
+
this.authLoading = false;
|
|
365
|
+
this.notify();
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
try {
|
|
369
|
+
DebugLogger.log("AuthService", "Initializing authentication...");
|
|
370
|
+
const { data: { session: currentSession }, error: sessionError } = await this.supabaseClient.auth.getSession();
|
|
371
|
+
if (sessionError) {
|
|
372
|
+
console.warn("[AuthService] Error getting current session:", sessionError);
|
|
373
|
+
}
|
|
374
|
+
if (currentSession) {
|
|
375
|
+
DebugLogger.log("AuthService", "Session restored from storage:", currentSession.user?.email);
|
|
376
|
+
this.session = currentSession;
|
|
377
|
+
this.user = currentSession.user;
|
|
378
|
+
this.authError = null;
|
|
379
|
+
} else {
|
|
380
|
+
DebugLogger.log("AuthService", "No session found in storage");
|
|
381
|
+
const { data: { user: currentUser }, error: userError } = await this.supabaseClient.auth.getUser();
|
|
382
|
+
if (userError) {
|
|
383
|
+
DebugLogger.log("AuthService", "No user found:", userError.message);
|
|
384
|
+
} else if (currentUser) {
|
|
385
|
+
DebugLogger.log("AuthService", "User found without session:", currentUser.email);
|
|
386
|
+
this.user = currentUser;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
this.authLoading = false;
|
|
390
|
+
this.notify();
|
|
391
|
+
} catch (error) {
|
|
392
|
+
console.error("[AuthService] Error during auth initialization:", error);
|
|
393
|
+
this.authLoading = false;
|
|
394
|
+
this.notify();
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
setupErrorHandlers() {
|
|
398
|
+
if (typeof window === "undefined") return;
|
|
399
|
+
const handleError = (event) => {
|
|
400
|
+
if (event.error?.message?.includes("AuthSessionMissingError") || event.error?.message?.includes("Auth session missing")) {
|
|
401
|
+
console.warn("[AuthService] Suppressing AuthSessionMissingError during logout");
|
|
402
|
+
event.preventDefault();
|
|
403
|
+
return false;
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
const handleUnhandledRejection = (event) => {
|
|
407
|
+
if (event.reason?.message?.includes("AuthSessionMissingError") || event.reason?.message?.includes("Auth session missing")) {
|
|
408
|
+
console.warn("[AuthService] Suppressing unhandled AuthSessionMissingError");
|
|
409
|
+
event.preventDefault();
|
|
410
|
+
return false;
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
window.addEventListener("error", handleError);
|
|
414
|
+
window.addEventListener("unhandledrejection", handleUnhandledRejection);
|
|
415
|
+
}
|
|
416
|
+
removeErrorHandlers() {
|
|
417
|
+
if (typeof window === "undefined") return;
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
// src/providers/services/AuthServiceProvider.tsx
|
|
424
|
+
import { createContext, useContext, useMemo, useEffect } from "react";
|
|
425
|
+
import { jsx } from "react/jsx-runtime";
|
|
426
|
+
function AuthServiceProvider({ children, supabaseClient }) {
|
|
427
|
+
const authService = useMemo(
|
|
428
|
+
() => new AuthService(supabaseClient),
|
|
429
|
+
[supabaseClient]
|
|
430
|
+
);
|
|
431
|
+
useEffect(() => {
|
|
432
|
+
authService.initialize().catch((error) => {
|
|
433
|
+
console.error("[AuthServiceProvider] Failed to initialize auth service:", error);
|
|
434
|
+
});
|
|
435
|
+
return () => {
|
|
436
|
+
authService.cleanup();
|
|
437
|
+
};
|
|
438
|
+
}, [authService]);
|
|
439
|
+
const contextValue = useMemo(() => ({
|
|
440
|
+
authService
|
|
441
|
+
}), [authService]);
|
|
442
|
+
return /* @__PURE__ */ jsx(AuthServiceContext.Provider, { value: contextValue, children });
|
|
443
|
+
}
|
|
444
|
+
var AuthServiceContext, useAuthService;
|
|
445
|
+
var init_AuthServiceProvider = __esm({
|
|
446
|
+
"src/providers/services/AuthServiceProvider.tsx"() {
|
|
447
|
+
"use strict";
|
|
448
|
+
init_AuthService();
|
|
449
|
+
AuthServiceContext = createContext(null);
|
|
450
|
+
useAuthService = () => {
|
|
451
|
+
const context = useContext(AuthServiceContext);
|
|
452
|
+
if (!context) {
|
|
453
|
+
throw new Error("useAuthService must be used within AuthServiceProvider");
|
|
454
|
+
}
|
|
455
|
+
return context.authService;
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
// src/services/RBACService.ts
|
|
461
|
+
var RBACService;
|
|
462
|
+
var init_RBACService = __esm({
|
|
463
|
+
"src/services/RBACService.ts"() {
|
|
464
|
+
"use strict";
|
|
465
|
+
init_BaseService();
|
|
466
|
+
init_unified();
|
|
467
|
+
init_debugLogger();
|
|
468
|
+
RBACService = class extends BaseService {
|
|
469
|
+
constructor(supabaseClient, user, session, appName) {
|
|
470
|
+
super();
|
|
471
|
+
this.permissions = {};
|
|
472
|
+
this.roles = [];
|
|
473
|
+
this.accessLevel = "viewer" /* VIEWER */;
|
|
474
|
+
this.rbacLoading = false;
|
|
475
|
+
this.rbacError = null;
|
|
476
|
+
this.selectedEventId = null;
|
|
477
|
+
this.appConfig = null;
|
|
478
|
+
this.userEventAccess = [];
|
|
479
|
+
this.eventAccessLoading = false;
|
|
480
|
+
this.selectedOrganisationId = null;
|
|
481
|
+
// Dependencies
|
|
482
|
+
this.supabaseClient = null;
|
|
483
|
+
this.user = null;
|
|
484
|
+
this.session = null;
|
|
485
|
+
this.appName = "";
|
|
486
|
+
this.supabaseClient = supabaseClient;
|
|
487
|
+
this.user = user;
|
|
488
|
+
this.session = session;
|
|
489
|
+
this.appName = appName;
|
|
490
|
+
}
|
|
491
|
+
// Update dependencies
|
|
492
|
+
updateDependencies(user, session, appName) {
|
|
493
|
+
this.user = user;
|
|
494
|
+
this.session = session;
|
|
495
|
+
this.appName = appName;
|
|
496
|
+
this.notify();
|
|
497
|
+
}
|
|
498
|
+
// RBAC state getters
|
|
499
|
+
getPermissions() {
|
|
500
|
+
return this.permissions;
|
|
501
|
+
}
|
|
502
|
+
getRoles() {
|
|
503
|
+
return this.roles;
|
|
504
|
+
}
|
|
505
|
+
getAccessLevel() {
|
|
506
|
+
return this.accessLevel;
|
|
507
|
+
}
|
|
508
|
+
isLoading() {
|
|
509
|
+
return this.rbacLoading;
|
|
510
|
+
}
|
|
511
|
+
getError() {
|
|
512
|
+
return this.rbacError;
|
|
513
|
+
}
|
|
514
|
+
getSelectedEventId() {
|
|
515
|
+
return this.selectedEventId;
|
|
516
|
+
}
|
|
517
|
+
getAppConfig() {
|
|
518
|
+
return this.appConfig;
|
|
519
|
+
}
|
|
520
|
+
getUserEventAccess() {
|
|
521
|
+
return this.userEventAccess;
|
|
522
|
+
}
|
|
523
|
+
isEventAccessLoading() {
|
|
524
|
+
return this.eventAccessLoading;
|
|
525
|
+
}
|
|
526
|
+
getSelectedOrganisationId() {
|
|
527
|
+
return this.selectedOrganisationId;
|
|
528
|
+
}
|
|
529
|
+
// RBAC methods
|
|
530
|
+
hasPermission(permission, orgId) {
|
|
531
|
+
return !!this.permissions[permission];
|
|
532
|
+
}
|
|
533
|
+
hasAnyPermission(permissions, orgId) {
|
|
534
|
+
return permissions.some((p) => !!this.permissions[p]);
|
|
535
|
+
}
|
|
536
|
+
hasAllPermissions(permissions, orgId) {
|
|
537
|
+
return permissions.every((p) => !!this.permissions[p]);
|
|
538
|
+
}
|
|
539
|
+
hasRole(role) {
|
|
540
|
+
const isSuperAdmin = this.user?.user_metadata?.globalRole === "super_admin";
|
|
541
|
+
if (role.toLowerCase() === "super_admin" || role.toLowerCase() === "super") {
|
|
542
|
+
return isSuperAdmin;
|
|
543
|
+
}
|
|
544
|
+
return this.roles.includes(role);
|
|
545
|
+
}
|
|
546
|
+
hasAccessLevel(level) {
|
|
547
|
+
const levels = Object.values(AccessLevel);
|
|
548
|
+
return levels.indexOf(this.accessLevel) >= levels.indexOf(level);
|
|
549
|
+
}
|
|
550
|
+
canAccess(resource, action, orgId) {
|
|
551
|
+
const permission = `${resource}:${action}`;
|
|
552
|
+
return this.hasPermission(permission, orgId);
|
|
553
|
+
}
|
|
554
|
+
async validatePermission(permission, orgId) {
|
|
555
|
+
return this.hasPermission(permission, orgId);
|
|
556
|
+
}
|
|
557
|
+
async validateAccess(resource, action, orgId) {
|
|
558
|
+
return this.canAccess(resource, action, orgId);
|
|
559
|
+
}
|
|
560
|
+
async refreshPermissions(eventId, orgId) {
|
|
561
|
+
if (!this.supabaseClient || !this.user || !this.appConfig || !this.session) {
|
|
562
|
+
DebugLogger.log("RBACService", "refreshPermissions: Missing required dependencies, clearing permissions");
|
|
563
|
+
this.permissions = {};
|
|
564
|
+
this.roles = [];
|
|
565
|
+
this.accessLevel = "viewer" /* VIEWER */;
|
|
566
|
+
this.notify();
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
const isSuperAdmin = this.user?.user_metadata?.globalRole === "super_admin";
|
|
570
|
+
if (isSuperAdmin) {
|
|
571
|
+
this.permissions = {
|
|
572
|
+
"admin:create": true,
|
|
573
|
+
"admin:read": true,
|
|
574
|
+
"admin:update": true,
|
|
575
|
+
"admin:delete": true,
|
|
576
|
+
"users:create": true,
|
|
577
|
+
"users:read": true,
|
|
578
|
+
"users:update": true,
|
|
579
|
+
"users:delete": true,
|
|
580
|
+
"events:create": true,
|
|
581
|
+
"events:read": true,
|
|
582
|
+
"events:update": true,
|
|
583
|
+
"events:delete": true
|
|
584
|
+
};
|
|
585
|
+
this.roles = ["super_admin"];
|
|
586
|
+
this.accessLevel = "admin" /* ADMIN */;
|
|
587
|
+
this.notify();
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
const shouldLoadDirectPermissions = !eventId && !this.appConfig.requires_event;
|
|
591
|
+
const shouldLoadEventPermissions = eventId;
|
|
592
|
+
const shouldClearPermissions = !eventId && this.appConfig.requires_event;
|
|
593
|
+
if (shouldClearPermissions) {
|
|
594
|
+
this.permissions = {};
|
|
595
|
+
this.roles = [];
|
|
596
|
+
this.accessLevel = "viewer" /* VIEWER */;
|
|
597
|
+
this.notify();
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
if (!shouldLoadDirectPermissions && !shouldLoadEventPermissions) {
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
this.rbacLoading = true;
|
|
604
|
+
this.rbacError = null;
|
|
605
|
+
this.notify();
|
|
606
|
+
try {
|
|
607
|
+
const { getCurrentAppName } = await import("./appNameResolver-UURKN7NF.js");
|
|
608
|
+
const resolvedAppName = getCurrentAppName() || this.appName;
|
|
609
|
+
const { data: appData, error: appError } = await this.supabaseClient.from("rbac_apps").select("id").eq("name", resolvedAppName).eq("is_active", true).single();
|
|
610
|
+
if (appError || !appData) {
|
|
611
|
+
console.warn("App not found or inactive:", resolvedAppName);
|
|
612
|
+
this.rbacLoading = false;
|
|
613
|
+
this.notify();
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
const { data, error } = await this.supabaseClient.rpc("rbac_permissions_get", {
|
|
617
|
+
p_user_id: this.user.id,
|
|
618
|
+
p_app_id: appData.id,
|
|
619
|
+
p_event_id: eventId || null,
|
|
620
|
+
p_organisation_id: orgId || this.selectedOrganisationId || null
|
|
621
|
+
});
|
|
622
|
+
if (error) {
|
|
623
|
+
throw error;
|
|
624
|
+
}
|
|
625
|
+
const { permissions, roles, access_level } = this.transformRBACPermissions(data, this.appName);
|
|
626
|
+
this.permissions = permissions;
|
|
627
|
+
this.roles = roles;
|
|
628
|
+
this.accessLevel = access_level;
|
|
629
|
+
} catch (err) {
|
|
630
|
+
this.rbacError = err;
|
|
631
|
+
} finally {
|
|
632
|
+
this.rbacLoading = false;
|
|
633
|
+
this.notify();
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
setSelectedEventId(eventId) {
|
|
637
|
+
this.selectedEventId = eventId;
|
|
638
|
+
this.notify();
|
|
639
|
+
}
|
|
640
|
+
async loadUserEventAccess(orgId) {
|
|
641
|
+
if (!this.supabaseClient || !this.user || !this.session) {
|
|
642
|
+
DebugLogger.log("RBACService", "loadUserEventAccess: Missing required dependencies, clearing event access");
|
|
643
|
+
this.userEventAccess = [];
|
|
644
|
+
this.notify();
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
this.eventAccessLoading = true;
|
|
648
|
+
this.notify();
|
|
649
|
+
try {
|
|
650
|
+
const { getCurrentAppName } = await import("./appNameResolver-UURKN7NF.js");
|
|
651
|
+
const resolvedAppName = getCurrentAppName() || this.appName;
|
|
652
|
+
const { data: appData, error: appError } = await this.supabaseClient.from("rbac_apps").select("id").eq("name", resolvedAppName).eq("is_active", true).single();
|
|
653
|
+
if (appError || !appData) {
|
|
654
|
+
console.warn("App not found or inactive:", resolvedAppName);
|
|
655
|
+
this.eventAccessLoading = false;
|
|
656
|
+
this.notify();
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
const { data, error } = await this.supabaseClient.from("rbac_event_app_roles").select(`
|
|
660
|
+
event_id,
|
|
661
|
+
role,
|
|
662
|
+
granted_at
|
|
663
|
+
`).eq("user_id", this.user.id).eq("app_id", appData.id);
|
|
664
|
+
if (error) {
|
|
665
|
+
console.error("Failed to load user event access:", error);
|
|
666
|
+
this.userEventAccess = [];
|
|
667
|
+
this.notify();
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
const eventAccess = data?.map((item) => ({
|
|
671
|
+
event_id: item.event_id,
|
|
672
|
+
event_name: item.event_name || "Unknown Event",
|
|
673
|
+
// Event details not available in this query
|
|
674
|
+
event_description: item.event_description || null,
|
|
675
|
+
// Not available in this schema
|
|
676
|
+
start_date: item.start_date || "",
|
|
677
|
+
// Event date not available in this query
|
|
678
|
+
end_date: item.end_date || "",
|
|
679
|
+
// Event date not available in this query
|
|
680
|
+
event_status: item.event_status || "unknown",
|
|
681
|
+
// Not available in this schema
|
|
682
|
+
app_id: item.app_id || appData.id,
|
|
683
|
+
access_level: item.access_level || item.role,
|
|
684
|
+
// Map role to access_level
|
|
685
|
+
granted_at: item.granted_at,
|
|
686
|
+
organisation_id: item.organisation_id || ""
|
|
687
|
+
// Will be populated from event's organisation_id if needed
|
|
688
|
+
})) || [];
|
|
689
|
+
this.userEventAccess = eventAccess;
|
|
690
|
+
} catch (error) {
|
|
691
|
+
console.error("Error loading user event access:", error);
|
|
692
|
+
this.userEventAccess = [];
|
|
693
|
+
} finally {
|
|
694
|
+
this.eventAccessLoading = false;
|
|
695
|
+
this.notify();
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
getUserEventAccessById(eventId) {
|
|
699
|
+
return this.userEventAccess.find((access) => access.event_id === eventId);
|
|
700
|
+
}
|
|
701
|
+
requireOrganisationContext() {
|
|
702
|
+
if (!this.selectedOrganisationId) {
|
|
703
|
+
throw new Error("Organisation context is required but not available");
|
|
704
|
+
}
|
|
705
|
+
return this.selectedOrganisationId;
|
|
706
|
+
}
|
|
707
|
+
// Lifecycle methods
|
|
708
|
+
async initialize() {
|
|
709
|
+
await super.initialize();
|
|
710
|
+
await this.loadAppConfig();
|
|
711
|
+
const isSuperAdmin = this.user?.user_metadata?.globalRole === "super_admin";
|
|
712
|
+
if (!isSuperAdmin && this.appConfig) {
|
|
713
|
+
await this.refreshPermissions(this.selectedEventId || void 0);
|
|
714
|
+
}
|
|
715
|
+
await this.loadPersistedState();
|
|
716
|
+
}
|
|
717
|
+
cleanup() {
|
|
718
|
+
super.cleanup();
|
|
719
|
+
}
|
|
720
|
+
async doInitialize() {
|
|
721
|
+
const isSuperAdmin = this.user?.user_metadata?.globalRole === "super_admin";
|
|
722
|
+
if (isSuperAdmin) {
|
|
723
|
+
this.roles = ["super_admin"];
|
|
724
|
+
this.accessLevel = "admin" /* ADMIN */;
|
|
725
|
+
this.permissions = {
|
|
726
|
+
"admin:create": true,
|
|
727
|
+
"admin:read": true,
|
|
728
|
+
"admin:update": true,
|
|
729
|
+
"admin:delete": true,
|
|
730
|
+
"users:create": true,
|
|
731
|
+
"users:read": true,
|
|
732
|
+
"users:update": true,
|
|
733
|
+
"users:delete": true,
|
|
734
|
+
"events:create": true,
|
|
735
|
+
"events:read": true,
|
|
736
|
+
"events:update": true,
|
|
737
|
+
"events:delete": true
|
|
738
|
+
};
|
|
739
|
+
} else {
|
|
740
|
+
this.roles = [];
|
|
741
|
+
this.accessLevel = "viewer" /* VIEWER */;
|
|
742
|
+
this.permissions = {};
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
doCleanup() {
|
|
746
|
+
}
|
|
747
|
+
async loadAppConfig() {
|
|
748
|
+
if (!this.supabaseClient) return;
|
|
749
|
+
try {
|
|
750
|
+
const { getCurrentAppName } = await import("./appNameResolver-UURKN7NF.js");
|
|
751
|
+
const resolvedAppName = getCurrentAppName() || this.appName;
|
|
752
|
+
const { data: appData, error: appError } = await this.supabaseClient.from("rbac_apps").select("id").eq("name", resolvedAppName).eq("is_active", true).single();
|
|
753
|
+
if (appError || !appData) {
|
|
754
|
+
console.warn("App not found or inactive:", resolvedAppName);
|
|
755
|
+
this.appConfig = {
|
|
756
|
+
supports_direct_access: false,
|
|
757
|
+
requires_event: true
|
|
758
|
+
};
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
const response = await this.supabaseClient.rpc("get_app_config", {
|
|
762
|
+
app_id: appData.id
|
|
763
|
+
});
|
|
764
|
+
const { data } = response || {};
|
|
765
|
+
if (data && data.length > 0) {
|
|
766
|
+
this.appConfig = {
|
|
767
|
+
supports_direct_access: false,
|
|
768
|
+
requires_event: data[0].requires_event
|
|
769
|
+
};
|
|
770
|
+
} else {
|
|
771
|
+
this.appConfig = {
|
|
772
|
+
supports_direct_access: false,
|
|
773
|
+
requires_event: true
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
} catch (error) {
|
|
777
|
+
console.warn("Failed to load app configuration:", error);
|
|
778
|
+
this.appConfig = {
|
|
779
|
+
supports_direct_access: false,
|
|
780
|
+
requires_event: true
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
async loadPersistedState() {
|
|
785
|
+
try {
|
|
786
|
+
const persistedEvent = localStorage.getItem("pace-core-selected-event");
|
|
787
|
+
if (persistedEvent) {
|
|
788
|
+
this.selectedEventId = JSON.parse(persistedEvent);
|
|
789
|
+
}
|
|
790
|
+
} catch (error) {
|
|
791
|
+
console.warn("Clearing corrupted localStorage data");
|
|
792
|
+
localStorage.removeItem("pace-core-selected-event");
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
transformRBACPermissions(rbacData, appName) {
|
|
796
|
+
const permissions = {};
|
|
797
|
+
let roles = [];
|
|
798
|
+
let access_level = "viewer" /* VIEWER */;
|
|
799
|
+
if (!rbacData || !Array.isArray(rbacData)) {
|
|
800
|
+
return { permissions: {}, roles: ["viewer"], access_level: "viewer" /* VIEWER */ };
|
|
801
|
+
}
|
|
802
|
+
const superAdminPerm = rbacData.find((p) => p.permission_type === "all_permissions");
|
|
803
|
+
if (superAdminPerm) {
|
|
804
|
+
return {
|
|
805
|
+
permissions: { "all:all": true },
|
|
806
|
+
roles: ["super"],
|
|
807
|
+
access_level: "super" /* SUPER */
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
const eventAppPerms = rbacData.filter((p) => p.permission_type === "event_app_access");
|
|
811
|
+
if (eventAppPerms.length > 0) {
|
|
812
|
+
const role = eventAppPerms[0].role_name;
|
|
813
|
+
switch (role) {
|
|
814
|
+
case "event_admin":
|
|
815
|
+
access_level = "admin" /* ADMIN */;
|
|
816
|
+
roles = ["admin"];
|
|
817
|
+
break;
|
|
818
|
+
case "planner":
|
|
819
|
+
access_level = "planner" /* PLANNER */;
|
|
820
|
+
roles = ["planner"];
|
|
821
|
+
break;
|
|
822
|
+
case "participant":
|
|
823
|
+
access_level = "participant" /* PARTICIPANT */;
|
|
824
|
+
roles = ["participant"];
|
|
825
|
+
break;
|
|
826
|
+
case "editor":
|
|
827
|
+
access_level = "editor" /* EDITOR */;
|
|
828
|
+
roles = ["editor"];
|
|
829
|
+
break;
|
|
830
|
+
case "viewer":
|
|
831
|
+
default:
|
|
832
|
+
access_level = "viewer" /* VIEWER */;
|
|
833
|
+
roles = ["viewer"];
|
|
834
|
+
break;
|
|
835
|
+
}
|
|
836
|
+
eventAppPerms.forEach((perm) => {
|
|
837
|
+
if (perm.permission) {
|
|
838
|
+
permissions[perm.permission] = true;
|
|
839
|
+
}
|
|
840
|
+
});
|
|
841
|
+
const basePermissions = ["read"];
|
|
842
|
+
if (["event_admin", "planner"].includes(role)) {
|
|
843
|
+
basePermissions.push("create", "update");
|
|
844
|
+
}
|
|
845
|
+
if (role === "event_admin") {
|
|
846
|
+
basePermissions.push("delete");
|
|
847
|
+
}
|
|
848
|
+
basePermissions.forEach((operation) => {
|
|
849
|
+
permissions[`default:${operation}`] = true;
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
const orgPerms = rbacData.filter((p) => p.permission_type === "organisation_access");
|
|
853
|
+
if (orgPerms.length > 0) {
|
|
854
|
+
const role = orgPerms[0].role_name;
|
|
855
|
+
if (role === "org_admin") {
|
|
856
|
+
access_level = "admin" /* ADMIN */;
|
|
857
|
+
roles = ["admin"];
|
|
858
|
+
["create", "read", "update", "delete"].forEach((operation) => {
|
|
859
|
+
permissions[`default:${operation}`] = true;
|
|
860
|
+
});
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
return { permissions, roles, access_level };
|
|
864
|
+
}
|
|
865
|
+
};
|
|
866
|
+
}
|
|
867
|
+
});
|
|
868
|
+
|
|
869
|
+
// src/providers/services/RBACServiceProvider.tsx
|
|
870
|
+
import { createContext as createContext2, useContext as useContext2, useMemo as useMemo2, useEffect as useEffect2 } from "react";
|
|
871
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
872
|
+
function RBACServiceProvider({
|
|
873
|
+
children,
|
|
874
|
+
supabaseClient,
|
|
875
|
+
user,
|
|
876
|
+
session,
|
|
877
|
+
appName
|
|
878
|
+
}) {
|
|
879
|
+
const rbacService = useMemo2(
|
|
880
|
+
() => new RBACService(supabaseClient, user, session, appName),
|
|
881
|
+
[supabaseClient, user, session, appName]
|
|
882
|
+
);
|
|
883
|
+
useEffect2(() => {
|
|
884
|
+
rbacService.updateDependencies(user, session, appName);
|
|
885
|
+
}, [rbacService, user, session, appName]);
|
|
886
|
+
useEffect2(() => {
|
|
887
|
+
rbacService.initialize().catch((error) => {
|
|
888
|
+
console.error("[RBACServiceProvider] Failed to initialize RBAC service:", error);
|
|
889
|
+
});
|
|
890
|
+
return () => {
|
|
891
|
+
rbacService.cleanup();
|
|
892
|
+
};
|
|
893
|
+
}, [rbacService]);
|
|
894
|
+
const contextValue = useMemo2(() => ({
|
|
895
|
+
rbacService
|
|
896
|
+
}), [rbacService]);
|
|
897
|
+
return /* @__PURE__ */ jsx2(RBACServiceContext.Provider, { value: contextValue, children });
|
|
898
|
+
}
|
|
899
|
+
var RBACServiceContext, useRBACService;
|
|
900
|
+
var init_RBACServiceProvider = __esm({
|
|
901
|
+
"src/providers/services/RBACServiceProvider.tsx"() {
|
|
902
|
+
"use strict";
|
|
903
|
+
init_RBACService();
|
|
904
|
+
RBACServiceContext = createContext2(null);
|
|
905
|
+
useRBACService = () => {
|
|
906
|
+
const context = useContext2(RBACServiceContext);
|
|
907
|
+
if (!context) {
|
|
908
|
+
throw new Error("useRBACService must be used within RBACServiceProvider");
|
|
909
|
+
}
|
|
910
|
+
return context.rbacService;
|
|
911
|
+
};
|
|
912
|
+
}
|
|
913
|
+
});
|
|
914
|
+
|
|
915
|
+
// src/services/OrganisationService.ts
|
|
916
|
+
var OrganisationService;
|
|
917
|
+
var init_OrganisationService = __esm({
|
|
918
|
+
"src/services/OrganisationService.ts"() {
|
|
919
|
+
"use strict";
|
|
920
|
+
init_BaseService();
|
|
921
|
+
init_organisationContext();
|
|
922
|
+
init_debugLogger();
|
|
923
|
+
OrganisationService = class extends BaseService {
|
|
924
|
+
constructor(supabaseClient, user, session) {
|
|
925
|
+
super();
|
|
926
|
+
this._selectedOrganisation = null;
|
|
927
|
+
this._organisations = [];
|
|
928
|
+
this._userMemberships = [];
|
|
929
|
+
this._roleMapState = /* @__PURE__ */ new Map();
|
|
930
|
+
this._isLoading = true;
|
|
931
|
+
this._error = null;
|
|
932
|
+
this._isContextReady = false;
|
|
933
|
+
this.retryCount = 0;
|
|
934
|
+
// Dependencies
|
|
935
|
+
this.supabaseClient = null;
|
|
936
|
+
this.user = null;
|
|
937
|
+
this.session = null;
|
|
938
|
+
// Internal state management
|
|
939
|
+
this.isLoadingRef = false;
|
|
940
|
+
this.lastLoadTimeRef = 0;
|
|
941
|
+
this.hasFailedRef = false;
|
|
942
|
+
this.abortControllerRef = null;
|
|
943
|
+
this.supabaseClient = supabaseClient;
|
|
944
|
+
this.user = user;
|
|
945
|
+
this.session = session;
|
|
946
|
+
}
|
|
947
|
+
// Interface implementation
|
|
948
|
+
getSelectedOrganisation() {
|
|
949
|
+
return this._selectedOrganisation;
|
|
950
|
+
}
|
|
951
|
+
getOrganisations() {
|
|
952
|
+
return this._organisations;
|
|
953
|
+
}
|
|
954
|
+
getUserMemberships() {
|
|
955
|
+
return this._userMemberships;
|
|
956
|
+
}
|
|
957
|
+
isLoading() {
|
|
958
|
+
return this._isLoading;
|
|
959
|
+
}
|
|
960
|
+
getError() {
|
|
961
|
+
return this._error;
|
|
962
|
+
}
|
|
963
|
+
hasValidOrganisationContext() {
|
|
964
|
+
return !!(this._selectedOrganisation && !this._isLoading && !this._error && this._isContextReady);
|
|
965
|
+
}
|
|
966
|
+
isContextReady() {
|
|
967
|
+
return this._isContextReady;
|
|
968
|
+
}
|
|
969
|
+
// Additional methods for testing
|
|
970
|
+
setSelectedOrganisation(organisation) {
|
|
971
|
+
this._selectedOrganisation = organisation;
|
|
972
|
+
if (organisation) {
|
|
973
|
+
localStorage.setItem("pace-core-selected-organisation", JSON.stringify(organisation));
|
|
974
|
+
this.setDatabaseOrganisationContext(organisation);
|
|
975
|
+
} else {
|
|
976
|
+
localStorage.removeItem("pace-core-selected-organisation");
|
|
977
|
+
this._isContextReady = false;
|
|
978
|
+
}
|
|
979
|
+
this.notify();
|
|
980
|
+
}
|
|
981
|
+
// For testing: expose dependencies
|
|
982
|
+
getDependencies() {
|
|
983
|
+
return {
|
|
984
|
+
user: this.user,
|
|
985
|
+
session: this.session,
|
|
986
|
+
supabaseClient: this.supabaseClient
|
|
987
|
+
};
|
|
988
|
+
}
|
|
989
|
+
// For testing: manually set state
|
|
990
|
+
setTestState(organisations, memberships, roleMap, selectedOrg = null) {
|
|
991
|
+
this._organisations = organisations;
|
|
992
|
+
this._userMemberships = memberships;
|
|
993
|
+
this._roleMapState = roleMap;
|
|
994
|
+
if (selectedOrg) {
|
|
995
|
+
this._selectedOrganisation = selectedOrg;
|
|
996
|
+
} else if (organisations.length > 0) {
|
|
997
|
+
this._selectedOrganisation = organisations[0];
|
|
998
|
+
}
|
|
999
|
+
this._isLoading = false;
|
|
1000
|
+
this._error = null;
|
|
1001
|
+
this.notify();
|
|
1002
|
+
}
|
|
1003
|
+
// Update dependencies
|
|
1004
|
+
updateDependencies(user, session) {
|
|
1005
|
+
this.user = user;
|
|
1006
|
+
this.session = session;
|
|
1007
|
+
this.notify();
|
|
1008
|
+
}
|
|
1009
|
+
// Organisation methods
|
|
1010
|
+
async switchOrganisation(orgId) {
|
|
1011
|
+
DebugLogger.log("OrganisationService", "Switching to organisation:", orgId);
|
|
1012
|
+
if (!this.validateOrganisationAccess(orgId)) {
|
|
1013
|
+
throw new Error(`User does not have access to organisation ${orgId}`);
|
|
1014
|
+
}
|
|
1015
|
+
const targetOrg = this._organisations.find((org) => org.id === orgId);
|
|
1016
|
+
if (!targetOrg) {
|
|
1017
|
+
throw new Error(`Organisation ${orgId} not found in user's organisations`);
|
|
1018
|
+
}
|
|
1019
|
+
this._selectedOrganisation = targetOrg;
|
|
1020
|
+
localStorage.setItem("pace-core-selected-organisation", JSON.stringify(targetOrg));
|
|
1021
|
+
await this.setDatabaseOrganisationContext(targetOrg);
|
|
1022
|
+
DebugLogger.log("OrganisationService", "Switched to organisation:", targetOrg.display_name);
|
|
1023
|
+
this.notify();
|
|
1024
|
+
}
|
|
1025
|
+
getUserRole(orgId) {
|
|
1026
|
+
const targetOrgId = orgId || this._selectedOrganisation?.id;
|
|
1027
|
+
if (!targetOrgId) return "no_access";
|
|
1028
|
+
return this._roleMapState.get(targetOrgId) || "no_access";
|
|
1029
|
+
}
|
|
1030
|
+
validateOrganisationAccess(orgId) {
|
|
1031
|
+
return this._userMemberships.some(
|
|
1032
|
+
(m) => m.organisation_id === orgId && m.status === "active" && m.revoked_at === null
|
|
1033
|
+
);
|
|
1034
|
+
}
|
|
1035
|
+
async refreshOrganisations() {
|
|
1036
|
+
if (!this.user || !this.session || !this.supabaseClient) return;
|
|
1037
|
+
this._isLoading = true;
|
|
1038
|
+
this.notify();
|
|
1039
|
+
await this.loadUserOrganisations();
|
|
1040
|
+
}
|
|
1041
|
+
ensureOrganisationContext() {
|
|
1042
|
+
if (!this._selectedOrganisation) {
|
|
1043
|
+
throw new Error("Organisation context is required but not available");
|
|
1044
|
+
}
|
|
1045
|
+
return this._selectedOrganisation;
|
|
1046
|
+
}
|
|
1047
|
+
isOrganisationSecure() {
|
|
1048
|
+
return !!(this._selectedOrganisation && this.user);
|
|
1049
|
+
}
|
|
1050
|
+
getPrimaryOrganisation() {
|
|
1051
|
+
const rolePriority = ["org_admin", "leader", "member"];
|
|
1052
|
+
for (const role of rolePriority) {
|
|
1053
|
+
const membership = this._userMemberships.find((m) => m.role === role);
|
|
1054
|
+
if (membership) {
|
|
1055
|
+
return this._organisations.find((org) => org.id === membership.organisation_id) || null;
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
return null;
|
|
1059
|
+
}
|
|
1060
|
+
buildOrganisationHierarchy(orgs) {
|
|
1061
|
+
const orgMap = /* @__PURE__ */ new Map();
|
|
1062
|
+
orgs.forEach((org) => orgMap.set(org.id, org));
|
|
1063
|
+
const roots = [];
|
|
1064
|
+
orgs.forEach((org) => {
|
|
1065
|
+
if (!org.parent_id) {
|
|
1066
|
+
roots.push({
|
|
1067
|
+
organisation: org,
|
|
1068
|
+
children: [],
|
|
1069
|
+
depth: 0
|
|
1070
|
+
});
|
|
1071
|
+
}
|
|
1072
|
+
});
|
|
1073
|
+
return roots;
|
|
1074
|
+
}
|
|
1075
|
+
// Lifecycle methods
|
|
1076
|
+
async initialize() {
|
|
1077
|
+
await super.initialize();
|
|
1078
|
+
await this.loadUserOrganisations();
|
|
1079
|
+
}
|
|
1080
|
+
cleanup() {
|
|
1081
|
+
this.isLoadingRef = false;
|
|
1082
|
+
this.hasFailedRef = false;
|
|
1083
|
+
this.lastLoadTimeRef = 0;
|
|
1084
|
+
if (this.abortControllerRef) {
|
|
1085
|
+
this.abortControllerRef.abort();
|
|
1086
|
+
this.abortControllerRef = null;
|
|
1087
|
+
}
|
|
1088
|
+
this._selectedOrganisation = null;
|
|
1089
|
+
this._organisations = [];
|
|
1090
|
+
this._userMemberships = [];
|
|
1091
|
+
this._roleMapState = /* @__PURE__ */ new Map();
|
|
1092
|
+
this._isLoading = false;
|
|
1093
|
+
this._error = null;
|
|
1094
|
+
this._isContextReady = false;
|
|
1095
|
+
super.cleanup();
|
|
1096
|
+
}
|
|
1097
|
+
async doInitialize() {
|
|
1098
|
+
}
|
|
1099
|
+
doCleanup() {
|
|
1100
|
+
}
|
|
1101
|
+
async setDatabaseOrganisationContext(organisation) {
|
|
1102
|
+
if (!this.supabaseClient || !this.session) {
|
|
1103
|
+
console.warn("[OrganisationService] No Supabase client or session available for setting organisation context");
|
|
1104
|
+
this._isContextReady = false;
|
|
1105
|
+
this.notify();
|
|
1106
|
+
return;
|
|
1107
|
+
}
|
|
1108
|
+
try {
|
|
1109
|
+
await setOrganisationContext(this.supabaseClient, organisation.id);
|
|
1110
|
+
DebugLogger.log("OrganisationService", "Database organisation context set to:", organisation.display_name);
|
|
1111
|
+
this._isContextReady = true;
|
|
1112
|
+
this.notify();
|
|
1113
|
+
} catch (error) {
|
|
1114
|
+
console.error("[OrganisationService] Failed to set database organisation context:", error);
|
|
1115
|
+
this._isContextReady = false;
|
|
1116
|
+
this.notify();
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
async loadUserOrganisations() {
|
|
1120
|
+
const callId = Math.random().toString(36).substr(2, 9);
|
|
1121
|
+
console.log(`[OrganisationService] Starting loadUserOrganisations call ${callId}`);
|
|
1122
|
+
if (!this.user || !this.session || !this.supabaseClient) {
|
|
1123
|
+
DebugLogger.log("OrganisationService", "Clearing organisation state - no user, session, or supabase client");
|
|
1124
|
+
this._selectedOrganisation = null;
|
|
1125
|
+
this._organisations = [];
|
|
1126
|
+
this._userMemberships = [];
|
|
1127
|
+
this._isLoading = false;
|
|
1128
|
+
this._error = null;
|
|
1129
|
+
this.notify();
|
|
1130
|
+
return;
|
|
1131
|
+
}
|
|
1132
|
+
if (this.isLoadingRef) {
|
|
1133
|
+
console.log("OrganisationService", "Already loading, skipping duplicate load");
|
|
1134
|
+
return;
|
|
1135
|
+
}
|
|
1136
|
+
const now = Date.now();
|
|
1137
|
+
if (now - this.lastLoadTimeRef < 2e3) {
|
|
1138
|
+
console.log("OrganisationService", "Too soon since last load, skipping");
|
|
1139
|
+
return;
|
|
1140
|
+
}
|
|
1141
|
+
if (this.abortControllerRef) {
|
|
1142
|
+
this.abortControllerRef.abort();
|
|
1143
|
+
}
|
|
1144
|
+
this.abortControllerRef = new AbortController();
|
|
1145
|
+
const abortSignal = this.abortControllerRef.signal;
|
|
1146
|
+
this.lastLoadTimeRef = now;
|
|
1147
|
+
this.isLoadingRef = true;
|
|
1148
|
+
this._isLoading = true;
|
|
1149
|
+
this._error = null;
|
|
1150
|
+
this.notify();
|
|
1151
|
+
try {
|
|
1152
|
+
DebugLogger.log("OrganisationService", "Loading organisations for user:", this.user.id);
|
|
1153
|
+
console.log("[OrganisationService] Supabase client ready:", {
|
|
1154
|
+
isConnected: !!this.supabaseClient,
|
|
1155
|
+
hasAuth: !!this.supabaseClient.auth,
|
|
1156
|
+
hasRpc: !!this.supabaseClient.rpc
|
|
1157
|
+
});
|
|
1158
|
+
let memberships, membershipError;
|
|
1159
|
+
try {
|
|
1160
|
+
console.log("[OrganisationService] Making RPC call to data_user_organisation_roles_get...");
|
|
1161
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
1162
|
+
const timeoutId = setTimeout(() => reject(new Error("RPC call timeout after 10 seconds")), 1e4);
|
|
1163
|
+
abortSignal.addEventListener("abort", () => {
|
|
1164
|
+
clearTimeout(timeoutId);
|
|
1165
|
+
reject(new Error("Request aborted"));
|
|
1166
|
+
});
|
|
1167
|
+
});
|
|
1168
|
+
const rpcPromise = this.supabaseClient.rpc("data_user_organisation_roles_get", {
|
|
1169
|
+
p_user_id: this.user.id,
|
|
1170
|
+
p_organisation_id: null
|
|
1171
|
+
});
|
|
1172
|
+
if (abortSignal.aborted) {
|
|
1173
|
+
throw new Error("Request aborted");
|
|
1174
|
+
}
|
|
1175
|
+
const result = await Promise.race([rpcPromise, timeoutPromise]);
|
|
1176
|
+
console.log("[OrganisationService] RPC call completed:", {
|
|
1177
|
+
hasData: !!result.data,
|
|
1178
|
+
hasError: !!result.error,
|
|
1179
|
+
dataLength: result.data?.length || 0,
|
|
1180
|
+
errorMessage: result.error?.message || "No error"
|
|
1181
|
+
});
|
|
1182
|
+
memberships = result.data?.filter(
|
|
1183
|
+
(role) => ["org_admin", "leader", "member"].includes(role.role)
|
|
1184
|
+
) || [];
|
|
1185
|
+
membershipError = result.error;
|
|
1186
|
+
} catch (queryError) {
|
|
1187
|
+
membershipError = queryError;
|
|
1188
|
+
}
|
|
1189
|
+
if (membershipError) {
|
|
1190
|
+
console.error("[OrganisationService] Error loading memberships:", membershipError);
|
|
1191
|
+
if (membershipError.message?.includes("timeout")) {
|
|
1192
|
+
console.log("[OrganisationService] RPC timed out, trying direct database query as fallback...");
|
|
1193
|
+
try {
|
|
1194
|
+
if (abortSignal.aborted) {
|
|
1195
|
+
throw new Error("Request aborted");
|
|
1196
|
+
}
|
|
1197
|
+
const { data: fallbackData, error: fallbackError } = await this.supabaseClient.from("rbac_organisation_roles").select(`
|
|
1198
|
+
id,
|
|
1199
|
+
user_id,
|
|
1200
|
+
organisation_id,
|
|
1201
|
+
role,
|
|
1202
|
+
status,
|
|
1203
|
+
granted_at,
|
|
1204
|
+
granted_by,
|
|
1205
|
+
revoked_at,
|
|
1206
|
+
revoked_by,
|
|
1207
|
+
notes,
|
|
1208
|
+
created_at,
|
|
1209
|
+
updated_at,
|
|
1210
|
+
organisations!inner(
|
|
1211
|
+
id,
|
|
1212
|
+
name,
|
|
1213
|
+
display_name,
|
|
1214
|
+
subscription_tier,
|
|
1215
|
+
settings,
|
|
1216
|
+
is_active,
|
|
1217
|
+
parent_id,
|
|
1218
|
+
created_at,
|
|
1219
|
+
updated_at
|
|
1220
|
+
)
|
|
1221
|
+
`).eq("user_id", this.user.id).eq("status", "active").is("revoked_at", null).in("role", ["org_admin", "leader", "member"]);
|
|
1222
|
+
if (fallbackError) {
|
|
1223
|
+
console.error("[OrganisationService] Fallback query also failed:", fallbackError);
|
|
1224
|
+
throw membershipError;
|
|
1225
|
+
}
|
|
1226
|
+
console.log("[OrganisationService] Fallback query successful, got", fallbackData?.length || 0, "memberships");
|
|
1227
|
+
memberships = fallbackData || [];
|
|
1228
|
+
membershipError = null;
|
|
1229
|
+
} catch (fallbackErr) {
|
|
1230
|
+
console.error("[OrganisationService] Fallback query failed:", fallbackErr);
|
|
1231
|
+
throw membershipError;
|
|
1232
|
+
}
|
|
1233
|
+
} else {
|
|
1234
|
+
throw membershipError;
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
DebugLogger.log("OrganisationService", "Raw memberships data:", memberships);
|
|
1238
|
+
if (!memberships || memberships.length === 0) {
|
|
1239
|
+
throw new Error("User has no active organisation memberships");
|
|
1240
|
+
}
|
|
1241
|
+
const organisationIds = memberships.map((m) => m.organisation_id).filter((id) => {
|
|
1242
|
+
if (!id || typeof id !== "string") {
|
|
1243
|
+
console.warn("[OrganisationService] Invalid organisation ID (not string):", id);
|
|
1244
|
+
return false;
|
|
1245
|
+
}
|
|
1246
|
+
const trimmedId = id.trim();
|
|
1247
|
+
if (trimmedId === "") {
|
|
1248
|
+
console.warn("[OrganisationService] Empty organisation ID found");
|
|
1249
|
+
return false;
|
|
1250
|
+
}
|
|
1251
|
+
const isValidUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(trimmedId);
|
|
1252
|
+
if (!isValidUuid) {
|
|
1253
|
+
console.warn("[OrganisationService] Invalid UUID format:", trimmedId);
|
|
1254
|
+
}
|
|
1255
|
+
return isValidUuid;
|
|
1256
|
+
});
|
|
1257
|
+
if (organisationIds.length === 0) {
|
|
1258
|
+
console.warn("[OrganisationService] No valid organisation IDs found in memberships:", memberships);
|
|
1259
|
+
throw new Error("No valid organisation IDs found in memberships");
|
|
1260
|
+
}
|
|
1261
|
+
DebugLogger.log("OrganisationService", "Valid organisation IDs:", organisationIds);
|
|
1262
|
+
if (abortSignal.aborted) {
|
|
1263
|
+
throw new Error("Request aborted");
|
|
1264
|
+
}
|
|
1265
|
+
const { data: allOrganisations, error: orgError } = await this.supabaseClient.from("organisations").select("id, name, display_name, subscription_tier, settings, is_active, parent_id, created_at, updated_at");
|
|
1266
|
+
if (orgError) {
|
|
1267
|
+
console.error("[OrganisationService] Error loading organisations:", orgError);
|
|
1268
|
+
throw orgError;
|
|
1269
|
+
}
|
|
1270
|
+
const organisations = allOrganisations?.filter(
|
|
1271
|
+
(org) => organisationIds.includes(org.id)
|
|
1272
|
+
) || [];
|
|
1273
|
+
const roleMap = /* @__PURE__ */ new Map();
|
|
1274
|
+
memberships?.forEach((membership) => {
|
|
1275
|
+
roleMap.set(membership.organisation_id, membership.role);
|
|
1276
|
+
});
|
|
1277
|
+
const orgs = organisations;
|
|
1278
|
+
const activeOrgs = orgs.filter((org) => org.is_active);
|
|
1279
|
+
if (activeOrgs.length === 0) {
|
|
1280
|
+
throw new Error("User has no access to active organisations");
|
|
1281
|
+
}
|
|
1282
|
+
DebugLogger.log("OrganisationService", "Active organisations:", activeOrgs);
|
|
1283
|
+
this._organisations = activeOrgs;
|
|
1284
|
+
this._userMemberships = memberships;
|
|
1285
|
+
this._roleMapState = roleMap;
|
|
1286
|
+
let initialOrg = null;
|
|
1287
|
+
try {
|
|
1288
|
+
const persistedOrgString = localStorage.getItem("pace-core-selected-organisation");
|
|
1289
|
+
if (persistedOrgString) {
|
|
1290
|
+
const persistedOrg = JSON.parse(persistedOrgString);
|
|
1291
|
+
if (persistedOrg.id && typeof persistedOrg.id === "string" && persistedOrg.id.trim() !== "") {
|
|
1292
|
+
const validPersistedOrg = activeOrgs.find((org) => org.id === persistedOrg.id);
|
|
1293
|
+
if (validPersistedOrg) {
|
|
1294
|
+
initialOrg = validPersistedOrg;
|
|
1295
|
+
DebugLogger.log("OrganisationService", "Restored persisted organisation:", initialOrg.display_name);
|
|
1296
|
+
} else {
|
|
1297
|
+
console.warn("[OrganisationService] Persisted organisation not found in active orgs, clearing cache");
|
|
1298
|
+
localStorage.removeItem("pace-core-selected-organisation");
|
|
1299
|
+
}
|
|
1300
|
+
} else {
|
|
1301
|
+
console.warn("[OrganisationService] Invalid persisted organisation ID, clearing cache");
|
|
1302
|
+
localStorage.removeItem("pace-core-selected-organisation");
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
} catch (storageError) {
|
|
1306
|
+
console.warn("[OrganisationService] Failed to restore persisted organisation:", storageError);
|
|
1307
|
+
localStorage.removeItem("pace-core-selected-organisation");
|
|
1308
|
+
}
|
|
1309
|
+
if (!initialOrg) {
|
|
1310
|
+
const adminMembership = memberships.find((m) => m.role === "org_admin");
|
|
1311
|
+
if (adminMembership) {
|
|
1312
|
+
const foundOrg = organisations.find((org) => org.id === adminMembership.organisation_id);
|
|
1313
|
+
if (foundOrg) {
|
|
1314
|
+
initialOrg = foundOrg;
|
|
1315
|
+
DebugLogger.log("OrganisationService", "Selected org_admin organisation:", initialOrg.display_name);
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
if (!initialOrg) {
|
|
1320
|
+
initialOrg = activeOrgs[0];
|
|
1321
|
+
DebugLogger.log("OrganisationService", "Selected first organisation:", initialOrg.display_name);
|
|
1322
|
+
}
|
|
1323
|
+
if (!initialOrg) {
|
|
1324
|
+
throw new Error("No valid organisation found for user");
|
|
1325
|
+
}
|
|
1326
|
+
this._selectedOrganisation = initialOrg;
|
|
1327
|
+
localStorage.setItem("pace-core-selected-organisation", JSON.stringify(initialOrg));
|
|
1328
|
+
DebugLogger.log("OrganisationService", "Organisation context established:", {
|
|
1329
|
+
selectedOrganisation: initialOrg.display_name,
|
|
1330
|
+
totalOrganisations: activeOrgs.length,
|
|
1331
|
+
userRole: roleMap.get(initialOrg.id)
|
|
1332
|
+
});
|
|
1333
|
+
this.retryCount = 0;
|
|
1334
|
+
this.hasFailedRef = false;
|
|
1335
|
+
} catch (err) {
|
|
1336
|
+
console.error("[OrganisationService] Failed to load organisations:", err);
|
|
1337
|
+
this._error = err;
|
|
1338
|
+
this.retryCount = this.retryCount + 1;
|
|
1339
|
+
this.hasFailedRef = true;
|
|
1340
|
+
this.clearAllCachedData();
|
|
1341
|
+
} finally {
|
|
1342
|
+
this.isLoadingRef = false;
|
|
1343
|
+
this._isLoading = false;
|
|
1344
|
+
this.abortControllerRef = null;
|
|
1345
|
+
this.notify();
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
clearAllCachedData() {
|
|
1349
|
+
localStorage.removeItem("pace-core-selected-organisation");
|
|
1350
|
+
localStorage.removeItem("pace-core-organisation-context");
|
|
1351
|
+
this._selectedOrganisation = null;
|
|
1352
|
+
this._organisations = [];
|
|
1353
|
+
this._userMemberships = [];
|
|
1354
|
+
this._roleMapState = /* @__PURE__ */ new Map();
|
|
1355
|
+
this.retryCount = 0;
|
|
1356
|
+
this._isContextReady = false;
|
|
1357
|
+
}
|
|
1358
|
+
};
|
|
1359
|
+
}
|
|
1360
|
+
});
|
|
1361
|
+
|
|
1362
|
+
// src/providers/services/OrganisationServiceProvider.tsx
|
|
1363
|
+
import { createContext as createContext3, useContext as useContext3, useMemo as useMemo3, useEffect as useEffect3 } from "react";
|
|
1364
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
1365
|
+
function OrganisationServiceProvider({
|
|
1366
|
+
children,
|
|
1367
|
+
supabaseClient,
|
|
1368
|
+
user,
|
|
1369
|
+
session
|
|
1370
|
+
}) {
|
|
1371
|
+
const organisationService = useMemo3(
|
|
1372
|
+
() => new OrganisationService(supabaseClient, user, session),
|
|
1373
|
+
[supabaseClient, user, session]
|
|
1374
|
+
);
|
|
1375
|
+
useEffect3(() => {
|
|
1376
|
+
organisationService.updateDependencies(user, session);
|
|
1377
|
+
}, [organisationService, user, session]);
|
|
1378
|
+
useEffect3(() => {
|
|
1379
|
+
organisationService.initialize().catch((error) => {
|
|
1380
|
+
console.error("[OrganisationServiceProvider] Failed to initialize organisation service:", error);
|
|
1381
|
+
});
|
|
1382
|
+
return () => {
|
|
1383
|
+
organisationService.cleanup();
|
|
1384
|
+
};
|
|
1385
|
+
}, [organisationService]);
|
|
1386
|
+
const contextValue = useMemo3(() => ({
|
|
1387
|
+
organisationService
|
|
1388
|
+
}), [organisationService]);
|
|
1389
|
+
return /* @__PURE__ */ jsx3(OrganisationServiceContext.Provider, { value: contextValue, children });
|
|
1390
|
+
}
|
|
1391
|
+
var OrganisationServiceContext, useOrganisationService;
|
|
1392
|
+
var init_OrganisationServiceProvider = __esm({
|
|
1393
|
+
"src/providers/services/OrganisationServiceProvider.tsx"() {
|
|
1394
|
+
"use strict";
|
|
1395
|
+
init_OrganisationService();
|
|
1396
|
+
OrganisationServiceContext = createContext3(null);
|
|
1397
|
+
useOrganisationService = () => {
|
|
1398
|
+
const context = useContext3(OrganisationServiceContext);
|
|
1399
|
+
if (!context) {
|
|
1400
|
+
throw new Error("useOrganisationService must be used within OrganisationServiceProvider");
|
|
1401
|
+
}
|
|
1402
|
+
return context.organisationService;
|
|
1403
|
+
};
|
|
1404
|
+
}
|
|
1405
|
+
});
|
|
1406
|
+
|
|
1407
|
+
// src/services/EventService.ts
|
|
1408
|
+
var EventService;
|
|
1409
|
+
var init_EventService = __esm({
|
|
1410
|
+
"src/services/EventService.ts"() {
|
|
1411
|
+
"use strict";
|
|
1412
|
+
init_BaseService();
|
|
1413
|
+
init_debugLogger();
|
|
1414
|
+
EventService = class extends BaseService {
|
|
1415
|
+
constructor(supabaseClient, user, session, appName, selectedOrganisation, setSelectedEventId) {
|
|
1416
|
+
super();
|
|
1417
|
+
this.events = [];
|
|
1418
|
+
this.selectedEvent = null;
|
|
1419
|
+
this._isLoading = true;
|
|
1420
|
+
this.error = null;
|
|
1421
|
+
// Dependencies
|
|
1422
|
+
this.supabaseClient = null;
|
|
1423
|
+
this.user = null;
|
|
1424
|
+
this.session = null;
|
|
1425
|
+
this.appName = "";
|
|
1426
|
+
this.selectedOrganisation = null;
|
|
1427
|
+
this.setSelectedEventId = null;
|
|
1428
|
+
// Internal state management
|
|
1429
|
+
this.isInitializedRef = false;
|
|
1430
|
+
this.isFetchingRef = false;
|
|
1431
|
+
this.hasAutoSelectedRef = false;
|
|
1432
|
+
this.userClearedEventRef = false;
|
|
1433
|
+
this.supabaseClient = supabaseClient;
|
|
1434
|
+
this.user = user;
|
|
1435
|
+
this.session = session;
|
|
1436
|
+
this.appName = appName;
|
|
1437
|
+
this.selectedOrganisation = selectedOrganisation;
|
|
1438
|
+
this.setSelectedEventId = setSelectedEventId;
|
|
1439
|
+
}
|
|
1440
|
+
// Update dependencies
|
|
1441
|
+
updateDependencies(supabaseClient, user, session, appName, selectedOrganisation, setSelectedEventId) {
|
|
1442
|
+
this.supabaseClient = supabaseClient;
|
|
1443
|
+
this.user = user;
|
|
1444
|
+
this.session = session;
|
|
1445
|
+
this.appName = appName;
|
|
1446
|
+
this.selectedOrganisation = selectedOrganisation;
|
|
1447
|
+
this.setSelectedEventId = setSelectedEventId;
|
|
1448
|
+
this.notify();
|
|
1449
|
+
}
|
|
1450
|
+
// Event state getters
|
|
1451
|
+
getEvents() {
|
|
1452
|
+
return this.events;
|
|
1453
|
+
}
|
|
1454
|
+
getSelectedEvent() {
|
|
1455
|
+
return this.selectedEvent;
|
|
1456
|
+
}
|
|
1457
|
+
isLoading() {
|
|
1458
|
+
return this._isLoading;
|
|
1459
|
+
}
|
|
1460
|
+
getError() {
|
|
1461
|
+
return this.error;
|
|
1462
|
+
}
|
|
1463
|
+
// Event methods
|
|
1464
|
+
setSelectedEvent(event) {
|
|
1465
|
+
if (event) {
|
|
1466
|
+
try {
|
|
1467
|
+
console.log("[EventService] Event selection validation:", {
|
|
1468
|
+
eventId: event.event_id,
|
|
1469
|
+
eventName: event.event_name,
|
|
1470
|
+
eventOrganisationId: event.organisation_id,
|
|
1471
|
+
selectedOrganisationId: this.selectedOrganisation?.id,
|
|
1472
|
+
selectedOrganisationName: this.selectedOrganisation?.display_name,
|
|
1473
|
+
match: event.organisation_id === this.selectedOrganisation?.id
|
|
1474
|
+
});
|
|
1475
|
+
if (this.selectedOrganisation && event.organisation_id !== this.selectedOrganisation.id) {
|
|
1476
|
+
console.error("[EventService] Event organisation_id does not match selected organisation", {
|
|
1477
|
+
eventOrganisationId: event.organisation_id,
|
|
1478
|
+
selectedOrganisationId: this.selectedOrganisation.id,
|
|
1479
|
+
eventName: event.event_name
|
|
1480
|
+
});
|
|
1481
|
+
return;
|
|
1482
|
+
}
|
|
1483
|
+
} catch (error) {
|
|
1484
|
+
console.error("[EventService] Error during event validation:", error);
|
|
1485
|
+
}
|
|
1486
|
+
this.selectedEvent = event;
|
|
1487
|
+
this.setSelectedEventId?.(event.event_id);
|
|
1488
|
+
this.persistEventSelection(event.event_id);
|
|
1489
|
+
this.userClearedEventRef = false;
|
|
1490
|
+
} else {
|
|
1491
|
+
this.selectedEvent = null;
|
|
1492
|
+
this.setSelectedEventId?.(null);
|
|
1493
|
+
sessionStorage.removeItem("pace-core-selected-event");
|
|
1494
|
+
localStorage.removeItem("pace-core-selected-event");
|
|
1495
|
+
this.hasAutoSelectedRef = false;
|
|
1496
|
+
this.userClearedEventRef = true;
|
|
1497
|
+
}
|
|
1498
|
+
this.notify();
|
|
1499
|
+
}
|
|
1500
|
+
async refreshEvents() {
|
|
1501
|
+
this.isInitializedRef = false;
|
|
1502
|
+
this.isFetchingRef = false;
|
|
1503
|
+
await this.fetchEvents();
|
|
1504
|
+
}
|
|
1505
|
+
async loadPersistedEvent(events) {
|
|
1506
|
+
try {
|
|
1507
|
+
let persistedEventId = sessionStorage.getItem("pace-core-selected-event");
|
|
1508
|
+
if (!persistedEventId) {
|
|
1509
|
+
persistedEventId = localStorage.getItem("pace-core-selected-event");
|
|
1510
|
+
if (persistedEventId) {
|
|
1511
|
+
sessionStorage.setItem("pace-core-selected-event", persistedEventId);
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
if (persistedEventId && events.length > 0) {
|
|
1515
|
+
const persistedEvent = events.find((event) => event.event_id === persistedEventId);
|
|
1516
|
+
if (persistedEvent) {
|
|
1517
|
+
DebugLogger.log("EventService", "Restoring persisted event:", persistedEvent.event_name);
|
|
1518
|
+
this.selectedEvent = persistedEvent;
|
|
1519
|
+
this.setSelectedEventId?.(persistedEventId);
|
|
1520
|
+
return true;
|
|
1521
|
+
} else {
|
|
1522
|
+
DebugLogger.log("EventService", "Persisted event not found in current events, clearing storage");
|
|
1523
|
+
sessionStorage.removeItem("pace-core-selected-event");
|
|
1524
|
+
localStorage.removeItem("pace-core-selected-event");
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
} catch (error) {
|
|
1528
|
+
console.warn("[EventService] Failed to load persisted event:", error);
|
|
1529
|
+
}
|
|
1530
|
+
return false;
|
|
1531
|
+
}
|
|
1532
|
+
persistEventSelection(eventId) {
|
|
1533
|
+
try {
|
|
1534
|
+
sessionStorage.setItem("pace-core-selected-event", eventId);
|
|
1535
|
+
localStorage.setItem("pace-core-selected-event", eventId);
|
|
1536
|
+
} catch (error) {
|
|
1537
|
+
console.warn("[EventService] Failed to persist event selection:", error);
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
clearEventSelection() {
|
|
1541
|
+
try {
|
|
1542
|
+
sessionStorage.removeItem("pace-core-selected-event");
|
|
1543
|
+
localStorage.removeItem("pace-core-selected-event");
|
|
1544
|
+
this.selectedEvent = null;
|
|
1545
|
+
this.setSelectedEventId?.(null);
|
|
1546
|
+
} catch (error) {
|
|
1547
|
+
console.warn("[EventService] Failed to clear event selection:", error);
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
autoSelectNextEvent(events) {
|
|
1551
|
+
const nextEvent = this.getNextEventByDate(events);
|
|
1552
|
+
if (nextEvent) {
|
|
1553
|
+
DebugLogger.log("EventService", "Auto-selecting next event:", nextEvent.event_name);
|
|
1554
|
+
this.selectedEvent = nextEvent;
|
|
1555
|
+
this.setSelectedEventId?.(nextEvent.event_id);
|
|
1556
|
+
this.persistEventSelection(nextEvent.event_id);
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
// Lifecycle methods
|
|
1560
|
+
async initialize() {
|
|
1561
|
+
await super.initialize();
|
|
1562
|
+
await this.fetchEvents();
|
|
1563
|
+
}
|
|
1564
|
+
cleanup() {
|
|
1565
|
+
super.cleanup();
|
|
1566
|
+
}
|
|
1567
|
+
async doInitialize() {
|
|
1568
|
+
await this.fetchEvents();
|
|
1569
|
+
}
|
|
1570
|
+
doCleanup() {
|
|
1571
|
+
}
|
|
1572
|
+
async fetchEvents() {
|
|
1573
|
+
if (!this.user || !this.session || !this.supabaseClient || !this.appName || !this.selectedOrganisation) {
|
|
1574
|
+
DebugLogger.log("EventService", "Missing required dependencies, skipping fetch");
|
|
1575
|
+
this._isLoading = false;
|
|
1576
|
+
this.notify();
|
|
1577
|
+
return;
|
|
1578
|
+
}
|
|
1579
|
+
if (this.isFetchingRef) {
|
|
1580
|
+
DebugLogger.log("EventService", "Already fetching events, skipping");
|
|
1581
|
+
return;
|
|
1582
|
+
}
|
|
1583
|
+
DebugLogger.log("EventService", "User and organisation found, fetching events for:", {
|
|
1584
|
+
userId: this.user.id,
|
|
1585
|
+
appName: this.appName,
|
|
1586
|
+
organisationId: this.selectedOrganisation.id,
|
|
1587
|
+
organisationName: this.selectedOrganisation.display_name
|
|
1588
|
+
});
|
|
1589
|
+
this.isFetchingRef = true;
|
|
1590
|
+
let isMounted = true;
|
|
1591
|
+
try {
|
|
1592
|
+
DebugLogger.log("EventService", "Calling data_user_events_get RPC with:", {
|
|
1593
|
+
user_id: this.user.id,
|
|
1594
|
+
organisation_id: this.selectedOrganisation.id,
|
|
1595
|
+
app_name: this.appName
|
|
1596
|
+
});
|
|
1597
|
+
const { data, error: rpcError } = await this.supabaseClient.rpc("data_user_events_get", {
|
|
1598
|
+
p_user_id: this.user.id,
|
|
1599
|
+
p_organisation_id: this.selectedOrganisation.id,
|
|
1600
|
+
p_app_name: this.appName
|
|
1601
|
+
});
|
|
1602
|
+
DebugLogger.log("EventService", "RPC response:", {
|
|
1603
|
+
data,
|
|
1604
|
+
error: rpcError,
|
|
1605
|
+
dataLength: data?.length || 0,
|
|
1606
|
+
organisationId: this.selectedOrganisation.id
|
|
1607
|
+
});
|
|
1608
|
+
if (rpcError) {
|
|
1609
|
+
throw new Error(rpcError.message || "Failed to fetch events");
|
|
1610
|
+
}
|
|
1611
|
+
if (isMounted) {
|
|
1612
|
+
const eventsData = data || [];
|
|
1613
|
+
console.log("[EventService] Loaded events:", eventsData.map((event) => ({
|
|
1614
|
+
eventId: event.event_id,
|
|
1615
|
+
eventName: event.event_name,
|
|
1616
|
+
organisationId: event.organisation_id,
|
|
1617
|
+
selectedOrganisationId: this.selectedOrganisation?.id
|
|
1618
|
+
})));
|
|
1619
|
+
const transformedEvents = eventsData.map((event) => ({
|
|
1620
|
+
id: event.event_id,
|
|
1621
|
+
// Use event_id as the primary id
|
|
1622
|
+
event_id: event.event_id,
|
|
1623
|
+
event_name: event.event_name,
|
|
1624
|
+
event_date: event.event_date,
|
|
1625
|
+
event_venue: event.event_venue,
|
|
1626
|
+
event_participants: event.event_participants,
|
|
1627
|
+
event_colours: event.event_colours,
|
|
1628
|
+
event_logo: "",
|
|
1629
|
+
// No logo field in event table
|
|
1630
|
+
organisation_id: event.organisation_id,
|
|
1631
|
+
is_visible: event.is_visible,
|
|
1632
|
+
// Legacy compatibility
|
|
1633
|
+
name: event.event_name,
|
|
1634
|
+
start_date: event.event_date
|
|
1635
|
+
}));
|
|
1636
|
+
this.events = transformedEvents;
|
|
1637
|
+
this.error = null;
|
|
1638
|
+
this.hasAutoSelectedRef = false;
|
|
1639
|
+
const persistedEventLoaded = await this.loadPersistedEvent(transformedEvents);
|
|
1640
|
+
if (!persistedEventLoaded && !this.userClearedEventRef) {
|
|
1641
|
+
const nextEvent = this.getNextEventByDate(transformedEvents);
|
|
1642
|
+
if (nextEvent) {
|
|
1643
|
+
DebugLogger.log("EventService", "Auto-selecting next event after no persisted event found:", nextEvent.event_name);
|
|
1644
|
+
this.hasAutoSelectedRef = true;
|
|
1645
|
+
this.selectedEvent = nextEvent;
|
|
1646
|
+
this.setSelectedEventId?.(nextEvent.event_id);
|
|
1647
|
+
this.persistEventSelection(nextEvent.event_id);
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
} catch (err) {
|
|
1652
|
+
console.error("[EventService] Error fetching events:", err);
|
|
1653
|
+
const _error = err instanceof Error ? err : new Error("Unknown error occurred");
|
|
1654
|
+
if (isMounted) {
|
|
1655
|
+
this.error = _error;
|
|
1656
|
+
this.events = [];
|
|
1657
|
+
}
|
|
1658
|
+
} finally {
|
|
1659
|
+
if (isMounted) {
|
|
1660
|
+
this._isLoading = false;
|
|
1661
|
+
}
|
|
1662
|
+
this.isFetchingRef = false;
|
|
1663
|
+
this.notify();
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
getNextEventByDate(events) {
|
|
1667
|
+
const eventsToUse = events || this.events;
|
|
1668
|
+
if (!eventsToUse || eventsToUse.length === 0) {
|
|
1669
|
+
return null;
|
|
1670
|
+
}
|
|
1671
|
+
const now = /* @__PURE__ */ new Date();
|
|
1672
|
+
const futureEvents = eventsToUse.filter((event) => {
|
|
1673
|
+
if (!event.event_date) return false;
|
|
1674
|
+
const eventDate = new Date(event.event_date);
|
|
1675
|
+
return eventDate >= now;
|
|
1676
|
+
});
|
|
1677
|
+
if (futureEvents.length === 0) {
|
|
1678
|
+
return null;
|
|
1679
|
+
}
|
|
1680
|
+
const sortedFutureEvents = futureEvents.sort((a, b) => {
|
|
1681
|
+
const dateA = new Date(a.event_date);
|
|
1682
|
+
const dateB = new Date(b.event_date);
|
|
1683
|
+
return dateA.getTime() - dateB.getTime();
|
|
1684
|
+
});
|
|
1685
|
+
return sortedFutureEvents[0];
|
|
1686
|
+
}
|
|
1687
|
+
};
|
|
1688
|
+
}
|
|
1689
|
+
});
|
|
1690
|
+
|
|
1691
|
+
// src/providers/services/EventServiceProvider.tsx
|
|
1692
|
+
import { createContext as createContext4, useContext as useContext4, useMemo as useMemo4, useEffect as useEffect4 } from "react";
|
|
1693
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
1694
|
+
function EventServiceProvider({
|
|
1695
|
+
children,
|
|
1696
|
+
supabaseClient,
|
|
1697
|
+
user,
|
|
1698
|
+
session,
|
|
1699
|
+
appName,
|
|
1700
|
+
selectedOrganisation,
|
|
1701
|
+
setSelectedEventId
|
|
1702
|
+
}) {
|
|
1703
|
+
const eventService = useMemo4(
|
|
1704
|
+
() => new EventService(supabaseClient, user, session, appName, selectedOrganisation, setSelectedEventId),
|
|
1705
|
+
[supabaseClient, user, session, appName, selectedOrganisation, setSelectedEventId]
|
|
1706
|
+
);
|
|
1707
|
+
useEffect4(() => {
|
|
1708
|
+
eventService.updateDependencies(supabaseClient, user, session, appName, selectedOrganisation, setSelectedEventId);
|
|
1709
|
+
}, [eventService, supabaseClient, user, session, appName, selectedOrganisation, setSelectedEventId]);
|
|
1710
|
+
useEffect4(() => {
|
|
1711
|
+
eventService.initialize().catch((error) => {
|
|
1712
|
+
console.error("[EventServiceProvider] Failed to initialize event service:", error);
|
|
1713
|
+
});
|
|
1714
|
+
return () => {
|
|
1715
|
+
eventService.cleanup();
|
|
1716
|
+
};
|
|
1717
|
+
}, [eventService]);
|
|
1718
|
+
const contextValue = useMemo4(() => ({
|
|
1719
|
+
eventService
|
|
1720
|
+
}), [eventService]);
|
|
1721
|
+
return /* @__PURE__ */ jsx4(EventServiceContext.Provider, { value: contextValue, children });
|
|
1722
|
+
}
|
|
1723
|
+
var EventServiceContext, useEventService;
|
|
1724
|
+
var init_EventServiceProvider = __esm({
|
|
1725
|
+
"src/providers/services/EventServiceProvider.tsx"() {
|
|
1726
|
+
"use strict";
|
|
1727
|
+
init_EventService();
|
|
1728
|
+
EventServiceContext = createContext4(null);
|
|
1729
|
+
useEventService = () => {
|
|
1730
|
+
const context = useContext4(EventServiceContext);
|
|
1731
|
+
if (!context) {
|
|
1732
|
+
throw new Error("useEventService must be used within EventServiceProvider");
|
|
1733
|
+
}
|
|
1734
|
+
return context.eventService;
|
|
1735
|
+
};
|
|
1736
|
+
}
|
|
1737
|
+
});
|
|
1738
|
+
|
|
1739
|
+
// src/services/InactivityService.ts
|
|
1740
|
+
var InactivityService;
|
|
1741
|
+
var init_InactivityService = __esm({
|
|
1742
|
+
"src/services/InactivityService.ts"() {
|
|
1743
|
+
"use strict";
|
|
1744
|
+
init_BaseService();
|
|
1745
|
+
InactivityService = class extends BaseService {
|
|
1746
|
+
constructor(supabaseClient, user, session, idleTimeoutMs = 30 * 60 * 1e3, warnBeforeMs = 60 * 1e3, onIdleLogout) {
|
|
1747
|
+
super();
|
|
1748
|
+
this._showInactivityWarning = false;
|
|
1749
|
+
this._inactivityTimeRemaining = 0;
|
|
1750
|
+
this._isIdle = false;
|
|
1751
|
+
this._timeRemaining = 0;
|
|
1752
|
+
this._showWarning = false;
|
|
1753
|
+
this._isTracking = false;
|
|
1754
|
+
// Dependencies
|
|
1755
|
+
this.supabaseClient = null;
|
|
1756
|
+
this.user = null;
|
|
1757
|
+
this.session = null;
|
|
1758
|
+
this.idleTimeoutMs = 30 * 60 * 1e3;
|
|
1759
|
+
// 30 minutes
|
|
1760
|
+
this.warnBeforeMs = 60 * 1e3;
|
|
1761
|
+
// 60 seconds
|
|
1762
|
+
this.onIdleLogout = null;
|
|
1763
|
+
// Internal state management
|
|
1764
|
+
this.inactivityTracker = null;
|
|
1765
|
+
this.isInactivityEnabled = true;
|
|
1766
|
+
this.supabaseClient = supabaseClient;
|
|
1767
|
+
this.user = user;
|
|
1768
|
+
this.session = session;
|
|
1769
|
+
this.idleTimeoutMs = idleTimeoutMs;
|
|
1770
|
+
this.warnBeforeMs = warnBeforeMs;
|
|
1771
|
+
this.onIdleLogout = onIdleLogout;
|
|
1772
|
+
this._timeRemaining = idleTimeoutMs;
|
|
1773
|
+
}
|
|
1774
|
+
// Interface implementation
|
|
1775
|
+
isIdle() {
|
|
1776
|
+
return this._isIdle;
|
|
1777
|
+
}
|
|
1778
|
+
getTimeRemaining() {
|
|
1779
|
+
return this._timeRemaining;
|
|
1780
|
+
}
|
|
1781
|
+
isWarningShown() {
|
|
1782
|
+
return this._showWarning;
|
|
1783
|
+
}
|
|
1784
|
+
isTracking() {
|
|
1785
|
+
return this._isTracking;
|
|
1786
|
+
}
|
|
1787
|
+
getShowInactivityWarning() {
|
|
1788
|
+
return this._showInactivityWarning;
|
|
1789
|
+
}
|
|
1790
|
+
getInactivityTimeRemaining() {
|
|
1791
|
+
return this._inactivityTimeRemaining;
|
|
1792
|
+
}
|
|
1793
|
+
// Additional getter methods that tests expect
|
|
1794
|
+
getIsIdle() {
|
|
1795
|
+
return this._isIdle;
|
|
1796
|
+
}
|
|
1797
|
+
getIsTracking() {
|
|
1798
|
+
return this._isTracking;
|
|
1799
|
+
}
|
|
1800
|
+
getShowWarning() {
|
|
1801
|
+
return this._showWarning;
|
|
1802
|
+
}
|
|
1803
|
+
// Additional methods for testing
|
|
1804
|
+
setShowInactivityWarning(value) {
|
|
1805
|
+
this._showInactivityWarning = value;
|
|
1806
|
+
this.notify();
|
|
1807
|
+
}
|
|
1808
|
+
setInactivityTimeRemaining(value) {
|
|
1809
|
+
this._inactivityTimeRemaining = value;
|
|
1810
|
+
this.notify();
|
|
1811
|
+
}
|
|
1812
|
+
setIsIdle(value) {
|
|
1813
|
+
this._isIdle = value;
|
|
1814
|
+
this.notify();
|
|
1815
|
+
}
|
|
1816
|
+
setTimeRemaining(value) {
|
|
1817
|
+
this._timeRemaining = value;
|
|
1818
|
+
this.notify();
|
|
1819
|
+
}
|
|
1820
|
+
setShowWarning(value) {
|
|
1821
|
+
this._showWarning = value;
|
|
1822
|
+
this.notify();
|
|
1823
|
+
}
|
|
1824
|
+
setIsTracking(value) {
|
|
1825
|
+
this._isTracking = value;
|
|
1826
|
+
this.notify();
|
|
1827
|
+
}
|
|
1828
|
+
triggerWarning(timeRemaining) {
|
|
1829
|
+
this._showInactivityWarning = true;
|
|
1830
|
+
this._inactivityTimeRemaining = Math.ceil(timeRemaining / 1e3);
|
|
1831
|
+
this._showWarning = true;
|
|
1832
|
+
this.notify();
|
|
1833
|
+
}
|
|
1834
|
+
triggerIdle() {
|
|
1835
|
+
this._isIdle = true;
|
|
1836
|
+
this.handleIdleLogout();
|
|
1837
|
+
this.notify();
|
|
1838
|
+
}
|
|
1839
|
+
// Update dependencies
|
|
1840
|
+
updateDependencies(supabaseClient, user, session, idleTimeoutMs, warnBeforeMs, onIdleLogout) {
|
|
1841
|
+
this.supabaseClient = supabaseClient;
|
|
1842
|
+
this.user = user;
|
|
1843
|
+
this.session = session;
|
|
1844
|
+
if (idleTimeoutMs !== void 0) this.idleTimeoutMs = idleTimeoutMs;
|
|
1845
|
+
if (warnBeforeMs !== void 0) this.warnBeforeMs = warnBeforeMs;
|
|
1846
|
+
if (onIdleLogout !== void 0) this.onIdleLogout = onIdleLogout;
|
|
1847
|
+
this.notify();
|
|
1848
|
+
}
|
|
1849
|
+
// Inactivity methods
|
|
1850
|
+
resetActivity() {
|
|
1851
|
+
if (this.inactivityTracker) {
|
|
1852
|
+
this.inactivityTracker.resetActivity();
|
|
1853
|
+
}
|
|
1854
|
+
this._isIdle = false;
|
|
1855
|
+
this._showWarning = false;
|
|
1856
|
+
this._showInactivityWarning = false;
|
|
1857
|
+
this._inactivityTimeRemaining = 0;
|
|
1858
|
+
this._timeRemaining = this.idleTimeoutMs;
|
|
1859
|
+
this.notify();
|
|
1860
|
+
}
|
|
1861
|
+
startTracking() {
|
|
1862
|
+
if (this.inactivityTracker) {
|
|
1863
|
+
this.inactivityTracker.startTracking();
|
|
1864
|
+
}
|
|
1865
|
+
this._isTracking = true;
|
|
1866
|
+
this.notify();
|
|
1867
|
+
}
|
|
1868
|
+
stopTracking() {
|
|
1869
|
+
if (this.inactivityTracker) {
|
|
1870
|
+
this.inactivityTracker.stopTracking();
|
|
1871
|
+
}
|
|
1872
|
+
this._isTracking = false;
|
|
1873
|
+
this.notify();
|
|
1874
|
+
}
|
|
1875
|
+
async handleIdleLogout() {
|
|
1876
|
+
this._showInactivityWarning = false;
|
|
1877
|
+
this._inactivityTimeRemaining = 0;
|
|
1878
|
+
this.stopTracking();
|
|
1879
|
+
try {
|
|
1880
|
+
if (this.supabaseClient) {
|
|
1881
|
+
await this.supabaseClient.auth.signOut();
|
|
1882
|
+
}
|
|
1883
|
+
} catch (error) {
|
|
1884
|
+
console.error("[InactivityService] Error during idle logout:", error);
|
|
1885
|
+
}
|
|
1886
|
+
this.onIdleLogout?.("inactivity");
|
|
1887
|
+
this.notify();
|
|
1888
|
+
}
|
|
1889
|
+
handleStaySignedIn() {
|
|
1890
|
+
this._showInactivityWarning = false;
|
|
1891
|
+
this._inactivityTimeRemaining = 0;
|
|
1892
|
+
this.resetActivity();
|
|
1893
|
+
this.notify();
|
|
1894
|
+
}
|
|
1895
|
+
async handleSignOutNow() {
|
|
1896
|
+
this._showInactivityWarning = false;
|
|
1897
|
+
this._inactivityTimeRemaining = 0;
|
|
1898
|
+
this.stopTracking();
|
|
1899
|
+
try {
|
|
1900
|
+
if (this.supabaseClient) {
|
|
1901
|
+
await this.supabaseClient.auth.signOut();
|
|
1902
|
+
}
|
|
1903
|
+
} catch (error) {
|
|
1904
|
+
console.error("[InactivityService] Error during manual sign out:", error);
|
|
1905
|
+
}
|
|
1906
|
+
this.onIdleLogout?.("inactivity");
|
|
1907
|
+
this.notify();
|
|
1908
|
+
}
|
|
1909
|
+
// Lifecycle methods
|
|
1910
|
+
async initialize() {
|
|
1911
|
+
await super.initialize();
|
|
1912
|
+
await this.setupInactivityTracker();
|
|
1913
|
+
}
|
|
1914
|
+
cleanup() {
|
|
1915
|
+
if (this.inactivityTracker) {
|
|
1916
|
+
this.inactivityTracker.cleanup?.();
|
|
1917
|
+
this.inactivityTracker = null;
|
|
1918
|
+
}
|
|
1919
|
+
this._isTracking = false;
|
|
1920
|
+
this._isIdle = false;
|
|
1921
|
+
this._showWarning = false;
|
|
1922
|
+
this._showInactivityWarning = false;
|
|
1923
|
+
this._timeRemaining = 0;
|
|
1924
|
+
this._inactivityTimeRemaining = 0;
|
|
1925
|
+
super.cleanup();
|
|
1926
|
+
}
|
|
1927
|
+
async doInitialize() {
|
|
1928
|
+
if (typeof window !== "undefined") {
|
|
1929
|
+
const isProduction = import.meta.env.MODE === "production";
|
|
1930
|
+
if (isProduction) {
|
|
1931
|
+
console.warn("[InactivityService] Inactivity feature enabled in production");
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
doCleanup() {
|
|
1936
|
+
}
|
|
1937
|
+
async setupInactivityTracker() {
|
|
1938
|
+
if (typeof window === "undefined") return;
|
|
1939
|
+
this.isInactivityEnabled = this.user && this.session;
|
|
1940
|
+
if (!this.isInactivityEnabled) {
|
|
1941
|
+
return;
|
|
1942
|
+
}
|
|
1943
|
+
try {
|
|
1944
|
+
const { useInactivityTracker } = await import("./useInactivityTracker-MRUU55XI.js");
|
|
1945
|
+
this.inactivityTracker = {
|
|
1946
|
+
isIdle: false,
|
|
1947
|
+
timeRemaining: 0,
|
|
1948
|
+
showWarning: false,
|
|
1949
|
+
isTracking: false,
|
|
1950
|
+
resetActivity: () => {
|
|
1951
|
+
this._isIdle = false;
|
|
1952
|
+
this._timeRemaining = 0;
|
|
1953
|
+
this._showWarning = false;
|
|
1954
|
+
this.notify();
|
|
1955
|
+
},
|
|
1956
|
+
startTracking: () => {
|
|
1957
|
+
this._isTracking = true;
|
|
1958
|
+
this.notify();
|
|
1959
|
+
},
|
|
1960
|
+
stopTracking: () => {
|
|
1961
|
+
this._isTracking = false;
|
|
1962
|
+
this.notify();
|
|
1963
|
+
},
|
|
1964
|
+
cleanup: () => {
|
|
1965
|
+
this._isTracking = false;
|
|
1966
|
+
this._isIdle = false;
|
|
1967
|
+
this._showWarning = false;
|
|
1968
|
+
this._timeRemaining = 0;
|
|
1969
|
+
}
|
|
1970
|
+
};
|
|
1971
|
+
this.setupEventHandlers();
|
|
1972
|
+
} catch (error) {
|
|
1973
|
+
console.error("[InactivityService] Failed to setup inactivity tracker:", error);
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
setupEventHandlers() {
|
|
1977
|
+
if (typeof window === "undefined") return;
|
|
1978
|
+
let idleTimer = null;
|
|
1979
|
+
let warningTimer = null;
|
|
1980
|
+
let lastActivity = Date.now();
|
|
1981
|
+
const resetTimers = () => {
|
|
1982
|
+
lastActivity = Date.now();
|
|
1983
|
+
if (idleTimer) {
|
|
1984
|
+
clearTimeout(idleTimer);
|
|
1985
|
+
idleTimer = null;
|
|
1986
|
+
}
|
|
1987
|
+
if (warningTimer) {
|
|
1988
|
+
clearTimeout(warningTimer);
|
|
1989
|
+
warningTimer = null;
|
|
1990
|
+
}
|
|
1991
|
+
this._showInactivityWarning = false;
|
|
1992
|
+
this._inactivityTimeRemaining = 0;
|
|
1993
|
+
this._isIdle = false;
|
|
1994
|
+
this._showWarning = false;
|
|
1995
|
+
this.notify();
|
|
1996
|
+
};
|
|
1997
|
+
const startIdleTimer = () => {
|
|
1998
|
+
if (idleTimer) {
|
|
1999
|
+
clearTimeout(idleTimer);
|
|
2000
|
+
}
|
|
2001
|
+
idleTimer = setTimeout(() => {
|
|
2002
|
+
this._isIdle = true;
|
|
2003
|
+
this._showWarning = true;
|
|
2004
|
+
this.notify();
|
|
2005
|
+
warningTimer = setTimeout(() => {
|
|
2006
|
+
this.handleIdleLogout();
|
|
2007
|
+
}, this.warnBeforeMs);
|
|
2008
|
+
}, this.idleTimeoutMs - this.warnBeforeMs);
|
|
2009
|
+
};
|
|
2010
|
+
const startWarningTimer = () => {
|
|
2011
|
+
if (warningTimer) {
|
|
2012
|
+
clearTimeout(warningTimer);
|
|
2013
|
+
}
|
|
2014
|
+
warningTimer = setTimeout(() => {
|
|
2015
|
+
this.handleIdleLogout();
|
|
2016
|
+
}, this.warnBeforeMs);
|
|
2017
|
+
};
|
|
2018
|
+
const activityEvents = ["mousedown", "mousemove", "keypress", "scroll", "touchstart", "click"];
|
|
2019
|
+
const handleActivity = () => {
|
|
2020
|
+
resetTimers();
|
|
2021
|
+
startIdleTimer();
|
|
2022
|
+
};
|
|
2023
|
+
activityEvents.forEach((event) => {
|
|
2024
|
+
document.addEventListener(event, handleActivity, true);
|
|
2025
|
+
});
|
|
2026
|
+
startIdleTimer();
|
|
2027
|
+
this.inactivityTracker.cleanup = () => {
|
|
2028
|
+
if (idleTimer) {
|
|
2029
|
+
clearTimeout(idleTimer);
|
|
2030
|
+
idleTimer = null;
|
|
2031
|
+
}
|
|
2032
|
+
if (warningTimer) {
|
|
2033
|
+
clearTimeout(warningTimer);
|
|
2034
|
+
warningTimer = null;
|
|
2035
|
+
}
|
|
2036
|
+
activityEvents.forEach((event) => {
|
|
2037
|
+
document.removeEventListener(event, handleActivity, true);
|
|
2038
|
+
});
|
|
2039
|
+
this._isTracking = false;
|
|
2040
|
+
this._isIdle = false;
|
|
2041
|
+
this._showWarning = false;
|
|
2042
|
+
this._timeRemaining = 0;
|
|
2043
|
+
this._showInactivityWarning = false;
|
|
2044
|
+
this._inactivityTimeRemaining = 0;
|
|
2045
|
+
};
|
|
2046
|
+
this._isTracking = true;
|
|
2047
|
+
this.notify();
|
|
2048
|
+
}
|
|
2049
|
+
};
|
|
2050
|
+
}
|
|
2051
|
+
});
|
|
2052
|
+
|
|
2053
|
+
// src/providers/services/InactivityServiceProvider.tsx
|
|
2054
|
+
import { createContext as createContext5, useContext as useContext5, useMemo as useMemo5, useEffect as useEffect5 } from "react";
|
|
2055
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
2056
|
+
function InactivityServiceProvider({
|
|
2057
|
+
children,
|
|
2058
|
+
supabaseClient,
|
|
2059
|
+
user,
|
|
2060
|
+
session,
|
|
2061
|
+
idleTimeoutMs = 30 * 60 * 1e3,
|
|
2062
|
+
warnBeforeMs = 60 * 1e3,
|
|
2063
|
+
onIdleLogout
|
|
2064
|
+
}) {
|
|
2065
|
+
const inactivityService = useMemo5(
|
|
2066
|
+
() => new InactivityService(supabaseClient, user, session, idleTimeoutMs, warnBeforeMs, onIdleLogout),
|
|
2067
|
+
[supabaseClient, user, session, idleTimeoutMs, warnBeforeMs, onIdleLogout]
|
|
2068
|
+
);
|
|
2069
|
+
useEffect5(() => {
|
|
2070
|
+
inactivityService.updateDependencies(supabaseClient, user, session, idleTimeoutMs, warnBeforeMs, onIdleLogout);
|
|
2071
|
+
}, [inactivityService, supabaseClient, user, session, idleTimeoutMs, warnBeforeMs, onIdleLogout]);
|
|
2072
|
+
useEffect5(() => {
|
|
2073
|
+
inactivityService.initialize().catch((error) => {
|
|
2074
|
+
console.error("[InactivityServiceProvider] Failed to initialize inactivity service:", error);
|
|
2075
|
+
});
|
|
2076
|
+
return () => {
|
|
2077
|
+
inactivityService.cleanup();
|
|
2078
|
+
};
|
|
2079
|
+
}, [inactivityService]);
|
|
2080
|
+
const contextValue = useMemo5(() => ({
|
|
2081
|
+
inactivityService
|
|
2082
|
+
}), [inactivityService]);
|
|
2083
|
+
return /* @__PURE__ */ jsx5(InactivityServiceContext.Provider, { value: contextValue, children });
|
|
2084
|
+
}
|
|
2085
|
+
var InactivityServiceContext, useInactivityService;
|
|
2086
|
+
var init_InactivityServiceProvider = __esm({
|
|
2087
|
+
"src/providers/services/InactivityServiceProvider.tsx"() {
|
|
2088
|
+
"use strict";
|
|
2089
|
+
init_InactivityService();
|
|
2090
|
+
InactivityServiceContext = createContext5(null);
|
|
2091
|
+
useInactivityService = () => {
|
|
2092
|
+
const context = useContext5(InactivityServiceContext);
|
|
2093
|
+
if (!context) {
|
|
2094
|
+
throw new Error("useInactivityService must be used within InactivityServiceProvider");
|
|
2095
|
+
}
|
|
2096
|
+
return context.inactivityService;
|
|
2097
|
+
};
|
|
2098
|
+
}
|
|
2099
|
+
});
|
|
2100
|
+
|
|
2101
|
+
// src/hooks/services/useAuthService.ts
|
|
2102
|
+
import { useContext as useContext6, useReducer, useEffect as useEffect6 } from "react";
|
|
2103
|
+
function useAuthService2() {
|
|
2104
|
+
const context = useContext6(AuthServiceContext);
|
|
2105
|
+
if (!context) {
|
|
2106
|
+
throw new Error("useAuthService must be used within AuthServiceProvider");
|
|
2107
|
+
}
|
|
2108
|
+
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
|
2109
|
+
useEffect6(() => {
|
|
2110
|
+
return context.authService.subscribe(() => forceUpdate());
|
|
2111
|
+
}, [context.authService]);
|
|
2112
|
+
return context.authService;
|
|
2113
|
+
}
|
|
2114
|
+
var init_useAuthService = __esm({
|
|
2115
|
+
"src/hooks/services/useAuthService.ts"() {
|
|
2116
|
+
"use strict";
|
|
2117
|
+
init_AuthServiceProvider();
|
|
2118
|
+
}
|
|
2119
|
+
});
|
|
2120
|
+
|
|
2121
|
+
// src/hooks/services/useRBACService.ts
|
|
2122
|
+
import { useContext as useContext7, useReducer as useReducer2, useEffect as useEffect7 } from "react";
|
|
2123
|
+
function useRBACService2() {
|
|
2124
|
+
const context = useContext7(RBACServiceContext);
|
|
2125
|
+
if (!context) {
|
|
2126
|
+
throw new Error("useRBACService must be used within RBACServiceProvider");
|
|
2127
|
+
}
|
|
2128
|
+
const [, forceUpdate] = useReducer2((x) => x + 1, 0);
|
|
2129
|
+
useEffect7(() => {
|
|
2130
|
+
return context.rbacService.subscribe(() => forceUpdate());
|
|
2131
|
+
}, [context.rbacService]);
|
|
2132
|
+
return context.rbacService;
|
|
2133
|
+
}
|
|
2134
|
+
var init_useRBACService = __esm({
|
|
2135
|
+
"src/hooks/services/useRBACService.ts"() {
|
|
2136
|
+
"use strict";
|
|
2137
|
+
init_RBACServiceProvider();
|
|
2138
|
+
}
|
|
2139
|
+
});
|
|
2140
|
+
|
|
2141
|
+
// src/hooks/services/useOrganisationService.ts
|
|
2142
|
+
import { useContext as useContext8, useReducer as useReducer3, useEffect as useEffect8 } from "react";
|
|
2143
|
+
function useOrganisationService2() {
|
|
2144
|
+
const context = useContext8(OrganisationServiceContext);
|
|
2145
|
+
if (!context) {
|
|
2146
|
+
throw new Error("useOrganisationService must be used within OrganisationServiceProvider");
|
|
2147
|
+
}
|
|
2148
|
+
const [, forceUpdate] = useReducer3((x) => x + 1, 0);
|
|
2149
|
+
useEffect8(() => {
|
|
2150
|
+
return context.organisationService.subscribe(() => forceUpdate());
|
|
2151
|
+
}, [context.organisationService]);
|
|
2152
|
+
return context.organisationService;
|
|
2153
|
+
}
|
|
2154
|
+
var init_useOrganisationService = __esm({
|
|
2155
|
+
"src/hooks/services/useOrganisationService.ts"() {
|
|
2156
|
+
"use strict";
|
|
2157
|
+
init_OrganisationServiceProvider();
|
|
2158
|
+
}
|
|
2159
|
+
});
|
|
2160
|
+
|
|
2161
|
+
// src/hooks/services/useEventService.ts
|
|
2162
|
+
import { useContext as useContext9, useReducer as useReducer4, useEffect as useEffect9 } from "react";
|
|
2163
|
+
function useEventService2() {
|
|
2164
|
+
const context = useContext9(EventServiceContext);
|
|
2165
|
+
if (!context) {
|
|
2166
|
+
throw new Error("useEventService must be used within EventServiceProvider");
|
|
2167
|
+
}
|
|
2168
|
+
const [, forceUpdate] = useReducer4((x) => x + 1, 0);
|
|
2169
|
+
useEffect9(() => {
|
|
2170
|
+
return context.eventService.subscribe(() => forceUpdate());
|
|
2171
|
+
}, [context.eventService]);
|
|
2172
|
+
return context.eventService;
|
|
2173
|
+
}
|
|
2174
|
+
var init_useEventService = __esm({
|
|
2175
|
+
"src/hooks/services/useEventService.ts"() {
|
|
2176
|
+
"use strict";
|
|
2177
|
+
init_EventServiceProvider();
|
|
2178
|
+
}
|
|
2179
|
+
});
|
|
2180
|
+
|
|
2181
|
+
// src/hooks/services/useInactivityService.ts
|
|
2182
|
+
import { useContext as useContext10, useReducer as useReducer5, useEffect as useEffect10 } from "react";
|
|
2183
|
+
function useInactivityService2() {
|
|
2184
|
+
const context = useContext10(InactivityServiceContext);
|
|
2185
|
+
if (!context) {
|
|
2186
|
+
throw new Error("useInactivityService must be used within InactivityServiceProvider");
|
|
2187
|
+
}
|
|
2188
|
+
const [, forceUpdate] = useReducer5((x) => x + 1, 0);
|
|
2189
|
+
useEffect10(() => {
|
|
2190
|
+
return context.inactivityService.subscribe(() => forceUpdate());
|
|
2191
|
+
}, [context.inactivityService]);
|
|
2192
|
+
return context.inactivityService;
|
|
2193
|
+
}
|
|
2194
|
+
var init_useInactivityService = __esm({
|
|
2195
|
+
"src/hooks/services/useInactivityService.ts"() {
|
|
2196
|
+
"use strict";
|
|
2197
|
+
init_InactivityServiceProvider();
|
|
2198
|
+
}
|
|
2199
|
+
});
|
|
2200
|
+
|
|
2201
|
+
// src/providers/services/UnifiedAuthProvider.tsx
|
|
2202
|
+
import { createContext as createContext6, useContext as useContext11, useMemo as useMemo6 } from "react";
|
|
2203
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
2204
|
+
function UnifiedAuthContextProvider({
|
|
2205
|
+
children,
|
|
2206
|
+
appName,
|
|
2207
|
+
...props
|
|
2208
|
+
}) {
|
|
2209
|
+
const authService = useAuthService2();
|
|
2210
|
+
const rbacService = useRBACService2();
|
|
2211
|
+
const organisationService = useOrganisationService2();
|
|
2212
|
+
const eventService = useEventService2();
|
|
2213
|
+
const inactivityService = useInactivityService2();
|
|
2214
|
+
const contextValue = useMemo6(() => ({
|
|
2215
|
+
// Auth state
|
|
2216
|
+
user: authService.getUser(),
|
|
2217
|
+
session: authService.getSession(),
|
|
2218
|
+
isAuthenticated: authService.isAuthenticated(),
|
|
2219
|
+
authLoading: authService.isLoading(),
|
|
2220
|
+
authError: authService.getError(),
|
|
2221
|
+
error: authService.getError(),
|
|
2222
|
+
// Alias for backward compatibility
|
|
2223
|
+
supabase: authService.getSupabaseClient(),
|
|
2224
|
+
// Auth methods
|
|
2225
|
+
signIn: authService.signIn.bind(authService),
|
|
2226
|
+
signUp: authService.signUp.bind(authService),
|
|
2227
|
+
signOut: authService.signOut.bind(authService),
|
|
2228
|
+
resetPassword: authService.resetPassword.bind(authService),
|
|
2229
|
+
updatePassword: authService.updatePassword.bind(authService),
|
|
2230
|
+
refreshSession: authService.refreshSession.bind(authService),
|
|
2231
|
+
// RBAC state
|
|
2232
|
+
permissions: rbacService.getPermissions(),
|
|
2233
|
+
roles: rbacService.getRoles(),
|
|
2234
|
+
accessLevel: rbacService.getAccessLevel(),
|
|
2235
|
+
rbacLoading: rbacService.isLoading(),
|
|
2236
|
+
rbacError: rbacService.getError(),
|
|
2237
|
+
selectedEventId: rbacService.getSelectedEventId(),
|
|
2238
|
+
appConfig: rbacService.getAppConfig(),
|
|
2239
|
+
userEventAccess: rbacService.getUserEventAccess(),
|
|
2240
|
+
eventAccessLoading: rbacService.isEventAccessLoading(),
|
|
2241
|
+
selectedOrganisationId: rbacService.getSelectedOrganisationId(),
|
|
2242
|
+
// RBAC methods
|
|
2243
|
+
hasPermission: rbacService.hasPermission.bind(rbacService),
|
|
2244
|
+
hasAnyPermission: rbacService.hasAnyPermission.bind(rbacService),
|
|
2245
|
+
hasAllPermissions: rbacService.hasAllPermissions.bind(rbacService),
|
|
2246
|
+
hasRole: rbacService.hasRole.bind(rbacService),
|
|
2247
|
+
hasAccessLevel: rbacService.hasAccessLevel.bind(rbacService),
|
|
2248
|
+
canAccess: rbacService.canAccess.bind(rbacService),
|
|
2249
|
+
validatePermission: rbacService.validatePermission.bind(rbacService),
|
|
2250
|
+
validateAccess: rbacService.validateAccess.bind(rbacService),
|
|
2251
|
+
refreshPermissions: rbacService.refreshPermissions.bind(rbacService),
|
|
2252
|
+
setSelectedEventId: rbacService.setSelectedEventId.bind(rbacService),
|
|
2253
|
+
loadUserEventAccess: rbacService.loadUserEventAccess.bind(rbacService),
|
|
2254
|
+
getUserEventAccess: rbacService.getUserEventAccess.bind(rbacService),
|
|
2255
|
+
requireOrganisationContext: rbacService.requireOrganisationContext.bind(rbacService),
|
|
2256
|
+
// Organisation state
|
|
2257
|
+
selectedOrganisation: organisationService.getSelectedOrganisation(),
|
|
2258
|
+
organisations: organisationService.getOrganisations(),
|
|
2259
|
+
userMemberships: organisationService.getUserMemberships(),
|
|
2260
|
+
organisationLoading: organisationService.isLoading(),
|
|
2261
|
+
organisationError: organisationService.getError(),
|
|
2262
|
+
hasValidOrganisationContext: organisationService.hasValidOrganisationContext(),
|
|
2263
|
+
isContextReady: organisationService.isContextReady(),
|
|
2264
|
+
// Organisation methods
|
|
2265
|
+
switchOrganisation: organisationService.switchOrganisation.bind(organisationService),
|
|
2266
|
+
getUserRole: organisationService.getUserRole.bind(organisationService),
|
|
2267
|
+
validateOrganisationAccess: organisationService.validateOrganisationAccess.bind(organisationService),
|
|
2268
|
+
refreshOrganisations: organisationService.refreshOrganisations.bind(organisationService),
|
|
2269
|
+
ensureOrganisationContext: organisationService.ensureOrganisationContext.bind(organisationService),
|
|
2270
|
+
isOrganisationSecure: organisationService.isOrganisationSecure.bind(organisationService),
|
|
2271
|
+
getPrimaryOrganisation: organisationService.getPrimaryOrganisation.bind(organisationService),
|
|
2272
|
+
// Event state
|
|
2273
|
+
events: eventService.getEvents(),
|
|
2274
|
+
selectedEvent: eventService.getSelectedEvent(),
|
|
2275
|
+
eventLoading: eventService.isLoading(),
|
|
2276
|
+
eventError: eventService.getError(),
|
|
2277
|
+
// Event methods
|
|
2278
|
+
setSelectedEvent: eventService.setSelectedEvent.bind(eventService),
|
|
2279
|
+
refreshEvents: eventService.refreshEvents.bind(eventService),
|
|
2280
|
+
// Inactivity state
|
|
2281
|
+
showInactivityWarning: inactivityService.getShowInactivityWarning(),
|
|
2282
|
+
inactivityTimeRemaining: inactivityService.getInactivityTimeRemaining(),
|
|
2283
|
+
isIdle: inactivityService.isIdle(),
|
|
2284
|
+
timeRemaining: inactivityService.getTimeRemaining(),
|
|
2285
|
+
showWarning: inactivityService.isWarningShown(),
|
|
2286
|
+
isTracking: inactivityService.isTracking(),
|
|
2287
|
+
// Inactivity methods
|
|
2288
|
+
resetActivity: inactivityService.resetActivity.bind(inactivityService),
|
|
2289
|
+
startTracking: inactivityService.startTracking.bind(inactivityService),
|
|
2290
|
+
stopTracking: inactivityService.stopTracking.bind(inactivityService),
|
|
2291
|
+
handleIdleLogout: inactivityService.handleIdleLogout.bind(inactivityService),
|
|
2292
|
+
handleStaySignedIn: inactivityService.handleStaySignedIn.bind(inactivityService),
|
|
2293
|
+
handleSignOutNow: inactivityService.handleSignOutNow.bind(inactivityService),
|
|
2294
|
+
// Additional unified properties
|
|
2295
|
+
appName,
|
|
2296
|
+
isLoading: authService.isLoading() || rbacService.isLoading() || organisationService.isLoading() || eventService.isLoading(),
|
|
2297
|
+
hasErrors: !!(authService.getError() || rbacService.getError() || organisationService.getError() || eventService.getError())
|
|
2298
|
+
}), [authService, rbacService, organisationService, eventService, inactivityService, appName]);
|
|
2299
|
+
return /* @__PURE__ */ jsx6(UnifiedAuthContext.Provider, { value: contextValue, children });
|
|
2300
|
+
}
|
|
2301
|
+
function ServiceAwareProviders({
|
|
2302
|
+
children,
|
|
2303
|
+
supabaseClient,
|
|
2304
|
+
appName,
|
|
2305
|
+
persistState,
|
|
2306
|
+
enablePersistence,
|
|
2307
|
+
requireOrganisationContext,
|
|
2308
|
+
enableRBAC,
|
|
2309
|
+
idleTimeoutMs,
|
|
2310
|
+
warnBeforeMs,
|
|
2311
|
+
onIdleLogout,
|
|
2312
|
+
renderInactivityWarning,
|
|
2313
|
+
dangerouslyDisableInactivity
|
|
2314
|
+
}) {
|
|
2315
|
+
const authService = useAuthService2();
|
|
2316
|
+
return /* @__PURE__ */ jsx6(
|
|
2317
|
+
RBACServiceProvider,
|
|
2318
|
+
{
|
|
2319
|
+
supabaseClient,
|
|
2320
|
+
user: authService.getUser(),
|
|
2321
|
+
session: authService.getSession(),
|
|
2322
|
+
appName,
|
|
2323
|
+
children: /* @__PURE__ */ jsx6(
|
|
2324
|
+
OrganisationServiceProvider,
|
|
2325
|
+
{
|
|
2326
|
+
supabaseClient,
|
|
2327
|
+
user: authService.getUser(),
|
|
2328
|
+
session: authService.getSession(),
|
|
2329
|
+
children: /* @__PURE__ */ jsx6(
|
|
2330
|
+
EventServiceProvider,
|
|
2331
|
+
{
|
|
2332
|
+
supabaseClient,
|
|
2333
|
+
user: authService.getUser(),
|
|
2334
|
+
session: authService.getSession(),
|
|
2335
|
+
appName,
|
|
2336
|
+
selectedOrganisation: null,
|
|
2337
|
+
setSelectedEventId: (eventId) => {
|
|
2338
|
+
},
|
|
2339
|
+
children: /* @__PURE__ */ jsx6(
|
|
2340
|
+
InactivityServiceProvider,
|
|
2341
|
+
{
|
|
2342
|
+
supabaseClient,
|
|
2343
|
+
user: authService.getUser(),
|
|
2344
|
+
session: authService.getSession(),
|
|
2345
|
+
idleTimeoutMs,
|
|
2346
|
+
warnBeforeMs,
|
|
2347
|
+
onIdleLogout,
|
|
2348
|
+
children: /* @__PURE__ */ jsx6(
|
|
2349
|
+
UnifiedAuthContextProvider,
|
|
2350
|
+
{
|
|
2351
|
+
appName,
|
|
2352
|
+
supabaseClient,
|
|
2353
|
+
persistState,
|
|
2354
|
+
enablePersistence,
|
|
2355
|
+
requireOrganisationContext,
|
|
2356
|
+
enableRBAC,
|
|
2357
|
+
idleTimeoutMs,
|
|
2358
|
+
warnBeforeMs,
|
|
2359
|
+
onIdleLogout,
|
|
2360
|
+
renderInactivityWarning,
|
|
2361
|
+
dangerouslyDisableInactivity,
|
|
2362
|
+
children
|
|
2363
|
+
}
|
|
2364
|
+
)
|
|
2365
|
+
}
|
|
2366
|
+
)
|
|
2367
|
+
}
|
|
2368
|
+
)
|
|
2369
|
+
}
|
|
2370
|
+
)
|
|
2371
|
+
}
|
|
2372
|
+
);
|
|
2373
|
+
}
|
|
2374
|
+
function UnifiedAuthProvider({
|
|
2375
|
+
children,
|
|
2376
|
+
supabaseClient,
|
|
2377
|
+
appName,
|
|
2378
|
+
persistState = true,
|
|
2379
|
+
enablePersistence,
|
|
2380
|
+
requireOrganisationContext = true,
|
|
2381
|
+
enableRBAC = false,
|
|
2382
|
+
idleTimeoutMs = 30 * 60 * 1e3,
|
|
2383
|
+
// 30 minutes
|
|
2384
|
+
warnBeforeMs = 60 * 1e3,
|
|
2385
|
+
// 60 seconds
|
|
2386
|
+
onIdleLogout,
|
|
2387
|
+
renderInactivityWarning,
|
|
2388
|
+
dangerouslyDisableInactivity = false
|
|
2389
|
+
}) {
|
|
2390
|
+
return /* @__PURE__ */ jsx6(AuthServiceProvider, { supabaseClient, children: /* @__PURE__ */ jsx6(
|
|
2391
|
+
ServiceAwareProviders,
|
|
2392
|
+
{
|
|
2393
|
+
supabaseClient,
|
|
2394
|
+
appName,
|
|
2395
|
+
persistState,
|
|
2396
|
+
enablePersistence,
|
|
2397
|
+
requireOrganisationContext,
|
|
2398
|
+
enableRBAC,
|
|
2399
|
+
idleTimeoutMs,
|
|
2400
|
+
warnBeforeMs,
|
|
2401
|
+
onIdleLogout,
|
|
2402
|
+
renderInactivityWarning,
|
|
2403
|
+
dangerouslyDisableInactivity,
|
|
2404
|
+
children
|
|
2405
|
+
}
|
|
2406
|
+
) });
|
|
2407
|
+
}
|
|
2408
|
+
var UnifiedAuthContext, useUnifiedAuth;
|
|
2409
|
+
var init_UnifiedAuthProvider = __esm({
|
|
2410
|
+
"src/providers/services/UnifiedAuthProvider.tsx"() {
|
|
2411
|
+
"use strict";
|
|
2412
|
+
init_AuthServiceProvider();
|
|
2413
|
+
init_RBACServiceProvider();
|
|
2414
|
+
init_OrganisationServiceProvider();
|
|
2415
|
+
init_EventServiceProvider();
|
|
2416
|
+
init_InactivityServiceProvider();
|
|
2417
|
+
init_useAuthService();
|
|
2418
|
+
init_useRBACService();
|
|
2419
|
+
init_useOrganisationService();
|
|
2420
|
+
init_useEventService();
|
|
2421
|
+
init_useInactivityService();
|
|
2422
|
+
UnifiedAuthContext = createContext6(void 0);
|
|
2423
|
+
useUnifiedAuth = () => {
|
|
2424
|
+
const context = useContext11(UnifiedAuthContext);
|
|
2425
|
+
if (!context) {
|
|
2426
|
+
throw new Error("useUnifiedAuth must be used within a UnifiedAuthProvider");
|
|
2427
|
+
}
|
|
2428
|
+
return context;
|
|
2429
|
+
};
|
|
2430
|
+
}
|
|
2431
|
+
});
|
|
2432
|
+
|
|
2433
|
+
export {
|
|
2434
|
+
AuthServiceContext,
|
|
2435
|
+
AuthServiceProvider,
|
|
2436
|
+
useAuthService,
|
|
2437
|
+
init_AuthServiceProvider,
|
|
2438
|
+
RBACServiceContext,
|
|
2439
|
+
RBACServiceProvider,
|
|
2440
|
+
useRBACService,
|
|
2441
|
+
init_RBACServiceProvider,
|
|
2442
|
+
OrganisationServiceContext,
|
|
2443
|
+
OrganisationServiceProvider,
|
|
2444
|
+
useOrganisationService,
|
|
2445
|
+
init_OrganisationServiceProvider,
|
|
2446
|
+
EventServiceContext,
|
|
2447
|
+
EventServiceProvider,
|
|
2448
|
+
useEventService,
|
|
2449
|
+
init_EventServiceProvider,
|
|
2450
|
+
InactivityServiceContext,
|
|
2451
|
+
InactivityServiceProvider,
|
|
2452
|
+
useInactivityService,
|
|
2453
|
+
init_InactivityServiceProvider,
|
|
2454
|
+
useAuthService2,
|
|
2455
|
+
init_useAuthService,
|
|
2456
|
+
useRBACService2,
|
|
2457
|
+
init_useRBACService,
|
|
2458
|
+
useOrganisationService2,
|
|
2459
|
+
init_useOrganisationService,
|
|
2460
|
+
useEventService2,
|
|
2461
|
+
init_useEventService,
|
|
2462
|
+
useInactivityService2,
|
|
2463
|
+
init_useInactivityService,
|
|
2464
|
+
useUnifiedAuth,
|
|
2465
|
+
UnifiedAuthProvider,
|
|
2466
|
+
init_UnifiedAuthProvider
|
|
2467
|
+
};
|
|
2468
|
+
//# sourceMappingURL=chunk-WN6XJWOS.js.map
|