@elevasis/ui 1.0.0
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/api/index.d.ts +87 -0
- package/dist/api/index.js +3 -0
- package/dist/auth/context.d.ts +19 -0
- package/dist/auth/context.js +1 -0
- package/dist/auth/index.d.ts +85 -0
- package/dist/auth/index.js +3 -0
- package/dist/chunk-3KMDHCAR.js +52 -0
- package/dist/chunk-5UWFGBFM.js +129 -0
- package/dist/chunk-6BJOYF6E.js +8 -0
- package/dist/chunk-6M6OLGQY.js +36 -0
- package/dist/chunk-7AI5ZYJ4.js +202 -0
- package/dist/chunk-7PLEQFHO.js +18 -0
- package/dist/chunk-GDV44UWF.js +138 -0
- package/dist/chunk-GEFB5YIR.js +338 -0
- package/dist/chunk-HBRMWW6V.js +43 -0
- package/dist/chunk-HUWJXLLF.js +681 -0
- package/dist/chunk-J3FALDQE.js +176 -0
- package/dist/chunk-JKERRYVS.js +109 -0
- package/dist/chunk-KA7LO7U5.js +28 -0
- package/dist/chunk-LHQTTUL2.js +27 -0
- package/dist/chunk-MAAS6CGR.js +1299 -0
- package/dist/chunk-NE36BUGQ.js +146 -0
- package/dist/chunk-NGXCFBCS.js +398 -0
- package/dist/chunk-OEYU5O27.js +235 -0
- package/dist/chunk-OUHGHTE7.js +748 -0
- package/dist/chunk-OXVOHOP3.js +661 -0
- package/dist/chunk-PSLKGOBZ.js +58 -0
- package/dist/chunk-PYL4XW6H.js +107 -0
- package/dist/chunk-Q47SPRY7.js +1 -0
- package/dist/chunk-Q7DJKLEN.js +18 -0
- package/dist/chunk-RJCA5672.js +1664 -0
- package/dist/chunk-S66I2PYB.js +748 -0
- package/dist/chunk-W7ZBF5AA.js +1 -0
- package/dist/chunk-WNWKOCGJ.js +1067 -0
- package/dist/chunk-XCYKC6OZ.js +1 -0
- package/dist/chunk-YULUKCS6.js +56 -0
- package/dist/chunk-YZ6GTZXL.js +48 -0
- package/dist/chunk-ZGHDPDTF.js +379 -0
- package/dist/components/command-queue/index.css +53 -0
- package/dist/components/command-queue/index.d.ts +204 -0
- package/dist/components/command-queue/index.js +10 -0
- package/dist/components/forms/index.d.ts +56 -0
- package/dist/components/forms/index.js +2 -0
- package/dist/components/index.css +443 -0
- package/dist/components/index.d.ts +1354 -0
- package/dist/components/index.js +18 -0
- package/dist/components/monitoring/index.d.ts +66 -0
- package/dist/components/monitoring/index.js +2 -0
- package/dist/components/navigation/index.d.ts +54 -0
- package/dist/components/navigation/index.js +91 -0
- package/dist/components/notifications/index.d.ts +52 -0
- package/dist/components/notifications/index.js +4 -0
- package/dist/components/resource-definition/index.css +388 -0
- package/dist/components/resource-definition/index.d.ts +301 -0
- package/dist/components/resource-definition/index.js +3 -0
- package/dist/display/index.css +53 -0
- package/dist/display/index.d.ts +606 -0
- package/dist/display/index.js +6 -0
- package/dist/execution/index.css +388 -0
- package/dist/execution/index.d.ts +1090 -0
- package/dist/execution/index.js +4 -0
- package/dist/graph/index.css +388 -0
- package/dist/graph/index.d.ts +429 -0
- package/dist/graph/index.js +1 -0
- package/dist/hooks/index.d.ts +1927 -0
- package/dist/hooks/index.js +6 -0
- package/dist/hooks/published.d.ts +1653 -0
- package/dist/hooks/published.js +4 -0
- package/dist/index.css +505 -0
- package/dist/index.d.ts +7284 -0
- package/dist/index.js +31 -0
- package/dist/initialization/index.d.ts +2325 -0
- package/dist/initialization/index.js +4 -0
- package/dist/organization/index.d.ts +225 -0
- package/dist/organization/index.js +4 -0
- package/dist/profile/index.d.ts +2265 -0
- package/dist/profile/index.js +3 -0
- package/dist/provider/index.css +61 -0
- package/dist/provider/index.d.ts +291 -0
- package/dist/provider/index.js +7 -0
- package/dist/provider/published.d.ts +198 -0
- package/dist/provider/published.js +6 -0
- package/dist/router/context.d.ts +19 -0
- package/dist/router/context.js +1 -0
- package/dist/router/index.d.ts +31 -0
- package/dist/router/index.js +2 -0
- package/dist/sse/index.d.ts +83 -0
- package/dist/sse/index.js +185 -0
- package/dist/supabase/index.d.ts +4289 -0
- package/dist/supabase/index.js +47 -0
- package/dist/typeform/index.d.ts +458 -0
- package/dist/typeform/index.js +1976 -0
- package/dist/typeform/schemas.d.ts +67 -0
- package/dist/typeform/schemas.js +1 -0
- package/dist/utils/index.d.ts +177 -0
- package/dist/utils/index.js +1 -0
- package/package.json +88 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { APIClientError } from './chunk-7AI5ZYJ4.js';
|
|
2
|
+
import { createContext, useContext, useMemo, useCallback } from 'react';
|
|
3
|
+
import { jsx } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
var ApiClientContext = createContext(null);
|
|
6
|
+
function useApiClientContext() {
|
|
7
|
+
const context = useContext(ApiClientContext);
|
|
8
|
+
if (!context) {
|
|
9
|
+
throw new Error("useApiClient must be used within ApiClientProvider");
|
|
10
|
+
}
|
|
11
|
+
return context;
|
|
12
|
+
}
|
|
13
|
+
function ApiClientProvider({
|
|
14
|
+
children,
|
|
15
|
+
getAccessToken,
|
|
16
|
+
organizationId,
|
|
17
|
+
isOrganizationReady,
|
|
18
|
+
onError
|
|
19
|
+
}) {
|
|
20
|
+
const value = useMemo(
|
|
21
|
+
() => ({
|
|
22
|
+
getAccessToken,
|
|
23
|
+
organizationId,
|
|
24
|
+
isOrganizationReady,
|
|
25
|
+
onError
|
|
26
|
+
}),
|
|
27
|
+
[getAccessToken, organizationId, isOrganizationReady, onError]
|
|
28
|
+
);
|
|
29
|
+
return /* @__PURE__ */ jsx(ApiClientContext.Provider, { value, children });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ../core/src/platform/constants/http.ts
|
|
33
|
+
var HTTP_HEADERS = {
|
|
34
|
+
/**
|
|
35
|
+
* Organization context header
|
|
36
|
+
* Note: Node.js normalizes all headers to lowercase, so we use lowercase consistently
|
|
37
|
+
*/
|
|
38
|
+
WORKOS_ORGANIZATION_ID: "workos-organization-id",
|
|
39
|
+
AGENT_ORGANIZATION: "x-agent-organization",
|
|
40
|
+
AGENT_MODE: "x-agent-mode"
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// src/api/hooks/useApiClient.ts
|
|
44
|
+
var DEFAULT_TIMEOUT_MS = 6e4;
|
|
45
|
+
function createUseApiClient(useOrganizations, apiUrl) {
|
|
46
|
+
return function useApiClient() {
|
|
47
|
+
const { getAccessToken, organizationId, isOrganizationReady, onError } = useApiClientContext();
|
|
48
|
+
const { isInitializing, isOrgRefreshing } = useOrganizations();
|
|
49
|
+
const handleResponseError = useCallback(
|
|
50
|
+
async (endpoint, response, options) => {
|
|
51
|
+
const errorData = await response.json().catch(() => ({
|
|
52
|
+
error: `HTTP ${response.status}`,
|
|
53
|
+
code: "INTERNAL_SERVER_ERROR"
|
|
54
|
+
}));
|
|
55
|
+
if (response.status >= 500 && onError) {
|
|
56
|
+
onError(endpoint, new Error(errorData.error), {
|
|
57
|
+
method: options.method || "GET",
|
|
58
|
+
statusCode: response.status,
|
|
59
|
+
requestId: errorData.requestId
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
throw new APIClientError(errorData.error, errorData.code, response.status, errorData.requestId, errorData.fields, errorData.retryAfter);
|
|
63
|
+
},
|
|
64
|
+
[onError]
|
|
65
|
+
);
|
|
66
|
+
const apiRequest = useCallback(
|
|
67
|
+
async (endpoint, options = {}) => {
|
|
68
|
+
try {
|
|
69
|
+
const token = await getAccessToken();
|
|
70
|
+
const headers = {
|
|
71
|
+
...options.body ? { "Content-Type": "application/json" } : {},
|
|
72
|
+
...token ? { Authorization: `Bearer ${token}` } : {},
|
|
73
|
+
...organizationId && { [HTTP_HEADERS.WORKOS_ORGANIZATION_ID]: organizationId },
|
|
74
|
+
...options.headers
|
|
75
|
+
};
|
|
76
|
+
const timeoutSignal = AbortSignal.timeout(DEFAULT_TIMEOUT_MS);
|
|
77
|
+
const signal = options.signal ? AbortSignal.any([options.signal, timeoutSignal]) : timeoutSignal;
|
|
78
|
+
const response = await fetch(`${apiUrl}/api${endpoint}`, {
|
|
79
|
+
...options,
|
|
80
|
+
headers,
|
|
81
|
+
signal
|
|
82
|
+
});
|
|
83
|
+
if (!response.ok) {
|
|
84
|
+
await handleResponseError(endpoint, response, options);
|
|
85
|
+
}
|
|
86
|
+
if (response.status === 204) {
|
|
87
|
+
return void 0;
|
|
88
|
+
}
|
|
89
|
+
const responseData = await response.json();
|
|
90
|
+
return responseData;
|
|
91
|
+
} catch (error) {
|
|
92
|
+
if (error instanceof Error && error.message.includes("No access token")) {
|
|
93
|
+
const headers = {
|
|
94
|
+
...options.body ? { "Content-Type": "application/json" } : {},
|
|
95
|
+
...options.headers
|
|
96
|
+
};
|
|
97
|
+
const fallbackTimeoutSignal = AbortSignal.timeout(DEFAULT_TIMEOUT_MS);
|
|
98
|
+
const fallbackSignal = options.signal ? AbortSignal.any([options.signal, fallbackTimeoutSignal]) : fallbackTimeoutSignal;
|
|
99
|
+
const response = await fetch(`${apiUrl}/api${endpoint}`, {
|
|
100
|
+
...options,
|
|
101
|
+
headers,
|
|
102
|
+
signal: fallbackSignal
|
|
103
|
+
});
|
|
104
|
+
if (!response.ok) {
|
|
105
|
+
await handleResponseError(endpoint, response, options);
|
|
106
|
+
}
|
|
107
|
+
if (response.status === 204) {
|
|
108
|
+
return void 0;
|
|
109
|
+
}
|
|
110
|
+
return response.json();
|
|
111
|
+
}
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
[getAccessToken, organizationId, handleResponseError, apiUrl]
|
|
116
|
+
);
|
|
117
|
+
const deferredApiRequest = useCallback(
|
|
118
|
+
async (endpoint, options = {}) => {
|
|
119
|
+
if (isInitializing || isOrgRefreshing) {
|
|
120
|
+
throw new Error("Organization context is still initializing. Please wait.");
|
|
121
|
+
}
|
|
122
|
+
if (!isOrganizationReady) {
|
|
123
|
+
throw new Error("No organization selected. Please select an organization.");
|
|
124
|
+
}
|
|
125
|
+
return apiRequest(endpoint, options);
|
|
126
|
+
},
|
|
127
|
+
[apiRequest, isInitializing, isOrgRefreshing, isOrganizationReady]
|
|
128
|
+
);
|
|
129
|
+
return {
|
|
130
|
+
apiRequest,
|
|
131
|
+
deferredApiRequest,
|
|
132
|
+
isOrganizationReady,
|
|
133
|
+
isInitializing: isInitializing || isOrgRefreshing
|
|
134
|
+
};
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export { ApiClientProvider, createUseApiClient, useApiClientContext };
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import { useUserProfile } from './chunk-5UWFGBFM.js';
|
|
2
|
+
import { useAuthContext } from './chunk-7PLEQFHO.js';
|
|
3
|
+
import { useState, useRef, useEffect, useCallback } from 'react';
|
|
4
|
+
import { Button, Loader, Menu, Text, Badge } from '@mantine/core';
|
|
5
|
+
import { IconChevronDown, IconBuilding, IconCheck } from '@tabler/icons-react';
|
|
6
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
7
|
+
|
|
8
|
+
// src/organization/store/organizationsSlice.ts
|
|
9
|
+
var initialOrganizationsState = {
|
|
10
|
+
currentWorkOSOrganizationId: null,
|
|
11
|
+
currentSupabaseOrganizationId: null,
|
|
12
|
+
currentMembership: null,
|
|
13
|
+
isInitializing: true,
|
|
14
|
+
// Start as initializing
|
|
15
|
+
isOrgRefreshing: false,
|
|
16
|
+
error: null
|
|
17
|
+
};
|
|
18
|
+
var createOrganizationsSlice = (set, _get, _store) => ({
|
|
19
|
+
// Organizations state
|
|
20
|
+
organizations: initialOrganizationsState,
|
|
21
|
+
// Organization actions
|
|
22
|
+
setCurrentWorkOSOrganizationId: (workOSorgId) => {
|
|
23
|
+
set(
|
|
24
|
+
(state) => {
|
|
25
|
+
state.organizations.currentWorkOSOrganizationId = workOSorgId;
|
|
26
|
+
},
|
|
27
|
+
void 0,
|
|
28
|
+
"organizations/setCurrentWorkOSOrganizationId"
|
|
29
|
+
);
|
|
30
|
+
},
|
|
31
|
+
setCurrentMembership: (membership) => {
|
|
32
|
+
set(
|
|
33
|
+
(state) => {
|
|
34
|
+
state.organizations.currentMembership = membership;
|
|
35
|
+
state.organizations.currentSupabaseOrganizationId = membership?.organization?.id || null;
|
|
36
|
+
},
|
|
37
|
+
void 0,
|
|
38
|
+
"organizations/setCurrentMembership"
|
|
39
|
+
);
|
|
40
|
+
},
|
|
41
|
+
setOrganizationsInitializing: (initializing) => set(
|
|
42
|
+
(state) => {
|
|
43
|
+
state.organizations.isInitializing = initializing;
|
|
44
|
+
},
|
|
45
|
+
void 0,
|
|
46
|
+
"organizations/setInitializing"
|
|
47
|
+
),
|
|
48
|
+
setOrganizationsLoading: (loading) => set(
|
|
49
|
+
(state) => {
|
|
50
|
+
state.organizations.isOrgRefreshing = loading;
|
|
51
|
+
},
|
|
52
|
+
void 0,
|
|
53
|
+
"organizations/setLoading"
|
|
54
|
+
),
|
|
55
|
+
setOrganizationsError: (error) => set(
|
|
56
|
+
(state) => {
|
|
57
|
+
state.organizations.error = error;
|
|
58
|
+
},
|
|
59
|
+
void 0,
|
|
60
|
+
"organizations/setError"
|
|
61
|
+
)
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// src/organization/hooks/useOrganizations.ts
|
|
65
|
+
function createUseOrganizations(useStore) {
|
|
66
|
+
return () => {
|
|
67
|
+
const organizations = useStore((state) => state.organizations);
|
|
68
|
+
const setCurrentWorkOSOrganizationId = useStore((state) => state.setCurrentWorkOSOrganizationId);
|
|
69
|
+
const setCurrentMembership = useStore((state) => state.setCurrentMembership);
|
|
70
|
+
const setOrganizationsInitializing = useStore((state) => state.setOrganizationsInitializing);
|
|
71
|
+
const setOrganizationsLoading = useStore((state) => state.setOrganizationsLoading);
|
|
72
|
+
const setOrganizationsError = useStore((state) => state.setOrganizationsError);
|
|
73
|
+
return {
|
|
74
|
+
...organizations,
|
|
75
|
+
setCurrentWorkOSOrganizationId,
|
|
76
|
+
setCurrentMembership,
|
|
77
|
+
setOrganizationsInitializing,
|
|
78
|
+
setOrganizationsLoading,
|
|
79
|
+
setOrganizationsError,
|
|
80
|
+
organizations
|
|
81
|
+
// Also return the full organizations object for easy access
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function createUseOrgInitialization(useOrganizations, useApiClient) {
|
|
86
|
+
return function useOrgInitialization() {
|
|
87
|
+
const { user, organizationId: workosOrgId } = useAuthContext();
|
|
88
|
+
const { apiRequest } = useApiClient();
|
|
89
|
+
const { profile } = useUserProfile();
|
|
90
|
+
const {
|
|
91
|
+
currentWorkOSOrganizationId,
|
|
92
|
+
currentMembership,
|
|
93
|
+
setCurrentWorkOSOrganizationId,
|
|
94
|
+
setCurrentMembership,
|
|
95
|
+
setOrganizationsInitializing,
|
|
96
|
+
setOrganizationsLoading,
|
|
97
|
+
setOrganizationsError,
|
|
98
|
+
organizations
|
|
99
|
+
} = useOrganizations();
|
|
100
|
+
const [memberships, setMemberships] = useState([]);
|
|
101
|
+
const [profileLoaded, setProfileLoaded] = useState(false);
|
|
102
|
+
const hasInitializedRef = useRef(false);
|
|
103
|
+
const currentMembershipIdRef = useRef(null);
|
|
104
|
+
currentMembershipIdRef.current = currentMembership?.id ?? null;
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
if (profile !== void 0 && profile !== null) {
|
|
107
|
+
setProfileLoaded(true);
|
|
108
|
+
}
|
|
109
|
+
}, [profile]);
|
|
110
|
+
const selectOrganization = useCallback(
|
|
111
|
+
async (data) => {
|
|
112
|
+
let selectedMembership = null;
|
|
113
|
+
if (profile?.last_visited_org) {
|
|
114
|
+
const supabaseLastVisitedOrgId = profile.last_visited_org;
|
|
115
|
+
selectedMembership = data.find((m) => m.organizationId === supabaseLastVisitedOrgId) || null;
|
|
116
|
+
}
|
|
117
|
+
if (!selectedMembership && workosOrgId) {
|
|
118
|
+
selectedMembership = data.find((m) => m.organization?.workos_org_id === workosOrgId) || null;
|
|
119
|
+
}
|
|
120
|
+
if (!selectedMembership && data.length > 0) {
|
|
121
|
+
selectedMembership = data[0];
|
|
122
|
+
}
|
|
123
|
+
if (selectedMembership) {
|
|
124
|
+
const workosSelectedOrgId = selectedMembership.organization?.workos_org_id;
|
|
125
|
+
if (workosSelectedOrgId) {
|
|
126
|
+
setCurrentWorkOSOrganizationId(workosSelectedOrgId);
|
|
127
|
+
setCurrentMembership(selectedMembership);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
[profile?.last_visited_org, workosOrgId, setCurrentWorkOSOrganizationId, setCurrentMembership]
|
|
132
|
+
);
|
|
133
|
+
const validateCurrentOrganization = useCallback(
|
|
134
|
+
(data) => {
|
|
135
|
+
const workosCurrentOrgId = currentWorkOSOrganizationId;
|
|
136
|
+
const currentOrg = data.find((m) => m.organization?.workos_org_id === workosCurrentOrgId);
|
|
137
|
+
if (!currentOrg) {
|
|
138
|
+
setCurrentWorkOSOrganizationId(null);
|
|
139
|
+
setCurrentMembership(null);
|
|
140
|
+
if (data.length > 0) {
|
|
141
|
+
const fallbackOrg = data[0];
|
|
142
|
+
const workosFallbackOrgId = fallbackOrg.organization?.workos_org_id;
|
|
143
|
+
if (workosFallbackOrgId) {
|
|
144
|
+
setCurrentWorkOSOrganizationId(workosFallbackOrgId);
|
|
145
|
+
setCurrentMembership(fallbackOrg);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
} else {
|
|
149
|
+
if (currentOrg.id !== currentMembershipIdRef.current) {
|
|
150
|
+
setCurrentMembership(currentOrg);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
[currentWorkOSOrganizationId, setCurrentWorkOSOrganizationId, setCurrentMembership]
|
|
155
|
+
);
|
|
156
|
+
useEffect(() => {
|
|
157
|
+
const initializeOrganizations = async () => {
|
|
158
|
+
if (!user?.id || !profileLoaded) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (hasInitializedRef.current) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (memberships.length === 0) {
|
|
165
|
+
setOrganizationsInitializing(true);
|
|
166
|
+
} else {
|
|
167
|
+
setOrganizationsLoading(true);
|
|
168
|
+
}
|
|
169
|
+
setOrganizationsError(null);
|
|
170
|
+
try {
|
|
171
|
+
const data = await apiRequest("/memberships/my-memberships");
|
|
172
|
+
if (!Array.isArray(data)) {
|
|
173
|
+
throw new Error("Invalid memberships response");
|
|
174
|
+
}
|
|
175
|
+
setMemberships(data);
|
|
176
|
+
if (data.length === 0) {
|
|
177
|
+
setOrganizationsError("No organization memberships found. Please contact your administrator or try refreshing the page.");
|
|
178
|
+
hasInitializedRef.current = true;
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (!currentWorkOSOrganizationId && data.length > 0) {
|
|
182
|
+
await selectOrganization(data);
|
|
183
|
+
} else if (currentWorkOSOrganizationId) {
|
|
184
|
+
validateCurrentOrganization(data);
|
|
185
|
+
}
|
|
186
|
+
hasInitializedRef.current = true;
|
|
187
|
+
} catch (error) {
|
|
188
|
+
setOrganizationsError(error instanceof Error ? error.message : "Failed to load organizations");
|
|
189
|
+
} finally {
|
|
190
|
+
setOrganizationsInitializing(false);
|
|
191
|
+
setOrganizationsLoading(false);
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
initializeOrganizations();
|
|
195
|
+
}, [
|
|
196
|
+
user?.id,
|
|
197
|
+
profileLoaded,
|
|
198
|
+
profile?.last_visited_org,
|
|
199
|
+
currentWorkOSOrganizationId,
|
|
200
|
+
apiRequest,
|
|
201
|
+
setOrganizationsInitializing,
|
|
202
|
+
setOrganizationsLoading,
|
|
203
|
+
setOrganizationsError,
|
|
204
|
+
selectOrganization,
|
|
205
|
+
validateCurrentOrganization
|
|
206
|
+
// REMOVED: memberships.length - causes feedback loop (memberships change as RESULT of effect, not INPUT)
|
|
207
|
+
]);
|
|
208
|
+
const retryInitialization = useCallback(async () => {
|
|
209
|
+
hasInitializedRef.current = false;
|
|
210
|
+
setOrganizationsError(null);
|
|
211
|
+
setOrganizationsInitializing(true);
|
|
212
|
+
try {
|
|
213
|
+
const data = await apiRequest("/memberships/my-memberships");
|
|
214
|
+
if (!Array.isArray(data)) {
|
|
215
|
+
throw new Error("Invalid memberships response");
|
|
216
|
+
}
|
|
217
|
+
setMemberships(data);
|
|
218
|
+
if (!currentWorkOSOrganizationId && data.length > 0) {
|
|
219
|
+
await selectOrganization(data);
|
|
220
|
+
} else if (currentWorkOSOrganizationId) {
|
|
221
|
+
validateCurrentOrganization(data);
|
|
222
|
+
}
|
|
223
|
+
hasInitializedRef.current = true;
|
|
224
|
+
} catch (error) {
|
|
225
|
+
setOrganizationsError(error instanceof Error ? error.message : "Failed to load organizations");
|
|
226
|
+
} finally {
|
|
227
|
+
setOrganizationsInitializing(false);
|
|
228
|
+
}
|
|
229
|
+
}, [
|
|
230
|
+
apiRequest,
|
|
231
|
+
currentWorkOSOrganizationId,
|
|
232
|
+
setOrganizationsError,
|
|
233
|
+
setOrganizationsInitializing,
|
|
234
|
+
selectOrganization,
|
|
235
|
+
validateCurrentOrganization
|
|
236
|
+
]);
|
|
237
|
+
return {
|
|
238
|
+
memberships,
|
|
239
|
+
isInitializing: organizations.isInitializing,
|
|
240
|
+
isLoading: organizations.isOrgRefreshing,
|
|
241
|
+
isInitialized: hasInitializedRef.current && !organizations.isInitializing && !organizations.isOrgRefreshing,
|
|
242
|
+
error: organizations.error,
|
|
243
|
+
currentOrganization: currentMembership?.organization || null,
|
|
244
|
+
retry: retryInitialization
|
|
245
|
+
};
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
function OrganizationSwitcher({
|
|
249
|
+
currentOrganization,
|
|
250
|
+
memberships,
|
|
251
|
+
isLoading,
|
|
252
|
+
onSwitch
|
|
253
|
+
}) {
|
|
254
|
+
const [opened, setOpened] = useState(false);
|
|
255
|
+
const [switching, setSwitching] = useState(false);
|
|
256
|
+
const otherMemberships = memberships.filter((m) => m.organizationId !== currentOrganization?.id);
|
|
257
|
+
const handleSwitch = async (workosOrgId) => {
|
|
258
|
+
setSwitching(true);
|
|
259
|
+
try {
|
|
260
|
+
await onSwitch(workosOrgId);
|
|
261
|
+
setOpened(false);
|
|
262
|
+
} catch (error) {
|
|
263
|
+
console.error("Failed to switch organization:", error);
|
|
264
|
+
} finally {
|
|
265
|
+
setSwitching(false);
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
if (isLoading) {
|
|
269
|
+
return /* @__PURE__ */ jsx(Button, { variant: "light", size: "xs", disabled: true, children: /* @__PURE__ */ jsx(Loader, { size: 14 }) });
|
|
270
|
+
}
|
|
271
|
+
if (memberships.length === 0) {
|
|
272
|
+
return /* @__PURE__ */ jsx(Button, { variant: "light", size: "xs", disabled: true, children: "None" });
|
|
273
|
+
}
|
|
274
|
+
return /* @__PURE__ */ jsxs(Menu, { opened, onChange: setOpened, position: "bottom-start", withinPortal: true, children: [
|
|
275
|
+
/* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(
|
|
276
|
+
Button,
|
|
277
|
+
{
|
|
278
|
+
variant: "light",
|
|
279
|
+
size: "xs",
|
|
280
|
+
leftSection: /* @__PURE__ */ jsx(IconBuilding, { size: 16 }),
|
|
281
|
+
rightSection: /* @__PURE__ */ jsx(IconChevronDown, { size: 14 }),
|
|
282
|
+
loading: switching,
|
|
283
|
+
children: /* @__PURE__ */ jsx(Text, { truncate: true, style: { maxWidth: 200 }, size: "xs", children: currentOrganization?.name || "Select Organization" })
|
|
284
|
+
}
|
|
285
|
+
) }),
|
|
286
|
+
/* @__PURE__ */ jsxs(Menu.Dropdown, { children: [
|
|
287
|
+
currentOrganization && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
288
|
+
/* @__PURE__ */ jsx(Menu.Label, { children: "Current Organization" }),
|
|
289
|
+
/* @__PURE__ */ jsx(Menu.Item, { disabled: true, rightSection: /* @__PURE__ */ jsx(IconCheck, { size: 14 }), leftSection: /* @__PURE__ */ jsx(IconBuilding, { size: 14 }), children: currentOrganization.name }),
|
|
290
|
+
otherMemberships.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
291
|
+
/* @__PURE__ */ jsx(Menu.Divider, {}),
|
|
292
|
+
/* @__PURE__ */ jsx(Menu.Label, { children: "Switch Organization" })
|
|
293
|
+
] })
|
|
294
|
+
] }),
|
|
295
|
+
otherMemberships.length > 0 && /* @__PURE__ */ jsx("div", { children: otherMemberships.map((membership, index) => /* @__PURE__ */ jsx(
|
|
296
|
+
Menu.Item,
|
|
297
|
+
{
|
|
298
|
+
leftSection: /* @__PURE__ */ jsx(IconBuilding, { size: 14 }),
|
|
299
|
+
rightSection: /* @__PURE__ */ jsx(Badge, { size: "xs", variant: "light", children: membership.role.slug }),
|
|
300
|
+
onClick: () => {
|
|
301
|
+
const workosOrgId = membership.organization?.workos_org_id;
|
|
302
|
+
if (!workosOrgId) {
|
|
303
|
+
console.error("Organization missing WorkOS ID:", membership.organization?.name);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
handleSwitch(workosOrgId);
|
|
307
|
+
},
|
|
308
|
+
disabled: switching,
|
|
309
|
+
children: membership.organization?.name || "Unknown Organization"
|
|
310
|
+
},
|
|
311
|
+
`${membership.organizationId}-${index}`
|
|
312
|
+
)) }, "other-memberships"),
|
|
313
|
+
!currentOrganization && memberships.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
314
|
+
/* @__PURE__ */ jsx(Menu.Label, { children: "Select Organization" }),
|
|
315
|
+
memberships.map((membership) => /* @__PURE__ */ jsx(
|
|
316
|
+
Menu.Item,
|
|
317
|
+
{
|
|
318
|
+
leftSection: /* @__PURE__ */ jsx(IconBuilding, { size: 14 }),
|
|
319
|
+
rightSection: /* @__PURE__ */ jsx(Badge, { size: "xs", variant: "light", children: membership.role.slug }),
|
|
320
|
+
onClick: () => {
|
|
321
|
+
const workosOrgId = membership.organization?.workos_org_id;
|
|
322
|
+
if (!workosOrgId) {
|
|
323
|
+
console.error("Organization missing WorkOS ID:", membership.organization?.name);
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
handleSwitch(workosOrgId);
|
|
327
|
+
},
|
|
328
|
+
disabled: switching,
|
|
329
|
+
children: membership.organization?.name || "Unknown Organization"
|
|
330
|
+
},
|
|
331
|
+
membership.organizationId
|
|
332
|
+
))
|
|
333
|
+
] })
|
|
334
|
+
] })
|
|
335
|
+
] });
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
export { OrganizationSwitcher, createOrganizationsSlice, createUseOrgInitialization, createUseOrganizations };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { useAuthContext } from './chunk-7PLEQFHO.js';
|
|
2
|
+
import { useRef, useCallback, useEffect } from 'react';
|
|
3
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
4
|
+
|
|
5
|
+
function useStableAccessToken() {
|
|
6
|
+
const { getAccessToken } = useAuthContext();
|
|
7
|
+
const getAccessTokenRef = useRef(getAccessToken);
|
|
8
|
+
getAccessTokenRef.current = getAccessToken;
|
|
9
|
+
return useCallback(() => {
|
|
10
|
+
return getAccessTokenRef.current();
|
|
11
|
+
}, []);
|
|
12
|
+
}
|
|
13
|
+
function useSessionCheck() {
|
|
14
|
+
const { user } = useAuthContext();
|
|
15
|
+
const queryClient = useQueryClient();
|
|
16
|
+
const isCheckingRef = useRef(false);
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
const handleVisibilityChange = async () => {
|
|
19
|
+
if (isCheckingRef.current || document.visibilityState !== "visible") {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
isCheckingRef.current = true;
|
|
23
|
+
try {
|
|
24
|
+
if (!user) {
|
|
25
|
+
window.location.replace("/login");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
await queryClient.cancelQueries();
|
|
29
|
+
queryClient.invalidateQueries();
|
|
30
|
+
} finally {
|
|
31
|
+
isCheckingRef.current = false;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
35
|
+
window.addEventListener("focus", handleVisibilityChange);
|
|
36
|
+
return () => {
|
|
37
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
38
|
+
window.removeEventListener("focus", handleVisibilityChange);
|
|
39
|
+
};
|
|
40
|
+
}, [user, queryClient]);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export { useSessionCheck, useStableAccessToken };
|