@axcode/axcloud-sdk 0.1.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/index.js ADDED
@@ -0,0 +1,1282 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var auth0React = require('@auth0/auth0-react');
5
+ var reactQuery = require('@tanstack/react-query');
6
+ var jsxRuntime = require('react/jsx-runtime');
7
+
8
+ // src/core/errors.ts
9
+ var AxCloudError = class _AxCloudError extends Error {
10
+ constructor(message, code, status, details) {
11
+ super(message);
12
+ this.name = "AxCloudError";
13
+ this.code = code;
14
+ this.status = status;
15
+ this.details = details;
16
+ const ErrorWithCapture = Error;
17
+ if (ErrorWithCapture.captureStackTrace) {
18
+ ErrorWithCapture.captureStackTrace(this, _AxCloudError);
19
+ }
20
+ }
21
+ static fromResponse(status, body) {
22
+ const details = typeof body === "object" ? body : void 0;
23
+ const message = details?.message;
24
+ switch (status) {
25
+ case 401:
26
+ return new _AxCloudError(
27
+ message || "Authentication required",
28
+ "UNAUTHORIZED",
29
+ status,
30
+ details
31
+ );
32
+ case 403:
33
+ return new _AxCloudError(
34
+ message || "Access denied",
35
+ "FORBIDDEN",
36
+ status,
37
+ details
38
+ );
39
+ case 404:
40
+ return new _AxCloudError(
41
+ message || "Resource not found",
42
+ "NOT_FOUND",
43
+ status,
44
+ details
45
+ );
46
+ case 422:
47
+ return new _AxCloudError(
48
+ message || "Validation failed",
49
+ "VALIDATION_ERROR",
50
+ status,
51
+ details
52
+ );
53
+ default:
54
+ if (status >= 500) {
55
+ return new _AxCloudError(
56
+ message || "Server error",
57
+ "SERVER_ERROR",
58
+ status,
59
+ details
60
+ );
61
+ }
62
+ return new _AxCloudError(
63
+ message || "An error occurred",
64
+ "UNKNOWN_ERROR",
65
+ status,
66
+ details
67
+ );
68
+ }
69
+ }
70
+ static networkError(originalError) {
71
+ const isDev = typeof process !== "undefined" && process.env?.NODE_ENV === "development";
72
+ const message = isDev && originalError?.message ? originalError.message : "Network request failed";
73
+ return new _AxCloudError(
74
+ message,
75
+ "NETWORK_ERROR",
76
+ 0,
77
+ isDev ? { originalError: originalError?.message } : void 0
78
+ );
79
+ }
80
+ static timeoutError(timeoutMs) {
81
+ return new _AxCloudError(
82
+ `Request timed out after ${timeoutMs}ms`,
83
+ "TIMEOUT_ERROR",
84
+ 0,
85
+ { timeout: timeoutMs }
86
+ );
87
+ }
88
+ };
89
+ function isAxCloudError(error) {
90
+ return error instanceof AxCloudError;
91
+ }
92
+
93
+ // src/core/client.ts
94
+ var AxCloudClient = class {
95
+ constructor(config) {
96
+ this.baseUrl = config.baseUrl.replace(/\/$/, "");
97
+ this.getAccessToken = config.getAccessToken;
98
+ this.apiKey = config.apiKey;
99
+ this.defaultTimeout = config.timeout ?? 3e4;
100
+ }
101
+ /**
102
+ * Update the access token getter (used when auth state changes)
103
+ */
104
+ setAccessTokenGetter(getter) {
105
+ this.getAccessToken = getter;
106
+ }
107
+ /**
108
+ * Build URL with query parameters
109
+ */
110
+ buildUrl(path, params) {
111
+ const url = new URL(`${this.baseUrl}${path}`);
112
+ if (params) {
113
+ Object.entries(params).forEach(([key, value]) => {
114
+ if (value !== void 0) {
115
+ url.searchParams.append(key, String(value));
116
+ }
117
+ });
118
+ }
119
+ return url.toString();
120
+ }
121
+ /**
122
+ * Make an authenticated request
123
+ */
124
+ async request(path, options = {}) {
125
+ const { body, params, headers: customHeaders, timeout, ...restOptions } = options;
126
+ const headers = {
127
+ "Content-Type": "application/json"
128
+ };
129
+ if (customHeaders) {
130
+ const customHeadersRecord = customHeaders;
131
+ Object.assign(headers, customHeadersRecord);
132
+ }
133
+ if (this.apiKey) {
134
+ headers["x-api-key"] = this.apiKey;
135
+ }
136
+ if (this.getAccessToken) {
137
+ try {
138
+ const token = await this.getAccessToken();
139
+ if (token) {
140
+ headers["Authorization"] = `Bearer ${token}`;
141
+ }
142
+ } catch (error) {
143
+ if (typeof process !== "undefined" && process.env?.NODE_ENV === "development") {
144
+ console.warn(
145
+ "[AxCloud SDK] Failed to fetch access token:",
146
+ error instanceof Error ? error.message : error
147
+ );
148
+ }
149
+ }
150
+ }
151
+ const url = this.buildUrl(path, params);
152
+ const controller = new AbortController();
153
+ const requestTimeout = timeout ?? this.defaultTimeout;
154
+ const timeoutId = setTimeout(() => controller.abort(), requestTimeout);
155
+ try {
156
+ const response = await fetch(url, {
157
+ ...restOptions,
158
+ headers,
159
+ body: body ? JSON.stringify(body) : void 0,
160
+ signal: controller.signal
161
+ });
162
+ const contentType = response.headers.get("content-type");
163
+ const isJson = contentType?.includes("application/json");
164
+ if (!response.ok) {
165
+ const errorBody = isJson ? await response.json().catch(() => null) : null;
166
+ throw AxCloudError.fromResponse(response.status, errorBody);
167
+ }
168
+ if (response.status === 204) {
169
+ return {};
170
+ }
171
+ return isJson ? await response.json() : {};
172
+ } catch (error) {
173
+ if (error instanceof AxCloudError) {
174
+ throw error;
175
+ }
176
+ if (error instanceof Error && error.name === "AbortError") {
177
+ throw AxCloudError.timeoutError(requestTimeout);
178
+ }
179
+ throw AxCloudError.networkError(error instanceof Error ? error : void 0);
180
+ } finally {
181
+ clearTimeout(timeoutId);
182
+ }
183
+ }
184
+ /**
185
+ * GET request
186
+ */
187
+ get(path, params) {
188
+ return this.request(path, { method: "GET", params });
189
+ }
190
+ /**
191
+ * POST request
192
+ */
193
+ post(path, body) {
194
+ return this.request(path, { method: "POST", body });
195
+ }
196
+ /**
197
+ * PUT request
198
+ */
199
+ put(path, body) {
200
+ return this.request(path, { method: "PUT", body });
201
+ }
202
+ /**
203
+ * PATCH request
204
+ */
205
+ patch(path, body) {
206
+ return this.request(path, { method: "PATCH", body });
207
+ }
208
+ /**
209
+ * DELETE request
210
+ */
211
+ delete(path) {
212
+ return this.request(path, { method: "DELETE" });
213
+ }
214
+ };
215
+ var clientRegistry = /* @__PURE__ */ new WeakMap();
216
+ function createClient(config, key) {
217
+ const client = new AxCloudClient(config);
218
+ if (key) {
219
+ clientRegistry.set(key, client);
220
+ }
221
+ return client;
222
+ }
223
+ function getClient(key) {
224
+ if (key) {
225
+ const client = clientRegistry.get(key);
226
+ if (client) {
227
+ return client;
228
+ }
229
+ }
230
+ throw new Error("AxCloud client not found. Make sure AxCloudProvider is mounted and use useAxCloudContext() to get the client.");
231
+ }
232
+
233
+ // src/core/types.ts
234
+ function userHasPermission(user, permission) {
235
+ if (user.permissions && user.permissions.length > 0) {
236
+ return user.permissions.includes(permission);
237
+ }
238
+ if (user.customRole?.effectivePermissions) {
239
+ return user.customRole.effectivePermissions.includes(permission);
240
+ }
241
+ return false;
242
+ }
243
+ function userHasAnyPermission(user, permissions) {
244
+ return permissions.some((p) => userHasPermission(user, p));
245
+ }
246
+ function userHasAllPermissions(user, permissions) {
247
+ return permissions.every((p) => userHasPermission(user, p));
248
+ }
249
+
250
+ // src/core/forms.ts
251
+ async function submitForm(apiUrl, submission) {
252
+ const url = `${apiUrl.replace(/\/$/, "")}/public/submit`;
253
+ const response = await fetch(url, {
254
+ method: "POST",
255
+ headers: {
256
+ "Content-Type": "application/json"
257
+ },
258
+ body: JSON.stringify({
259
+ api_key: submission.apiKey,
260
+ site: submission.site,
261
+ form_type: submission.formType,
262
+ email: submission.email,
263
+ data: submission.data || {}
264
+ })
265
+ });
266
+ if (!response.ok) {
267
+ const error = await response.json().catch(() => ({ message: "Form submission failed" }));
268
+ throw new Error(error.message || "Form submission failed");
269
+ }
270
+ const result = await response.json();
271
+ return {
272
+ success: result.success,
273
+ message: result.message,
274
+ submissionId: result.submission_id
275
+ };
276
+ }
277
+ function createFormHelper(config) {
278
+ return {
279
+ /**
280
+ * Submit a waitlist form
281
+ */
282
+ submitWaitlist: (email, data) => submitForm(config.apiUrl, {
283
+ apiKey: config.apiKey,
284
+ site: config.site,
285
+ formType: "waitlist",
286
+ email,
287
+ data
288
+ }),
289
+ /**
290
+ * Submit a contact form
291
+ */
292
+ submitContact: (email, data) => submitForm(config.apiUrl, {
293
+ apiKey: config.apiKey,
294
+ site: config.site,
295
+ formType: "contact",
296
+ email,
297
+ data
298
+ }),
299
+ /**
300
+ * Submit a membership application
301
+ */
302
+ submitMembership: (email, data) => submitForm(config.apiUrl, {
303
+ apiKey: config.apiKey,
304
+ site: config.site,
305
+ formType: "membership",
306
+ email,
307
+ data
308
+ }),
309
+ /**
310
+ * Generic submit function
311
+ */
312
+ submit: (formType, email, data) => submitForm(config.apiUrl, {
313
+ apiKey: config.apiKey,
314
+ site: config.site,
315
+ formType,
316
+ email,
317
+ data
318
+ })
319
+ };
320
+ }
321
+ var AxCloudContext = react.createContext(null);
322
+ function useAxCloudContext() {
323
+ const context = react.useContext(AxCloudContext);
324
+ if (!context) {
325
+ throw new Error("useAxCloudContext must be used within a AxCloudProvider");
326
+ }
327
+ return context;
328
+ }
329
+ var defaultQueryClient = new reactQuery.QueryClient({
330
+ defaultOptions: {
331
+ queries: {
332
+ staleTime: 1e3 * 60 * 5,
333
+ // 5 minutes
334
+ gcTime: 1e3 * 60 * 30,
335
+ // 30 minutes (garbage collection)
336
+ retry: 2,
337
+ refetchOnWindowFocus: false
338
+ }
339
+ }
340
+ });
341
+ function AxCloudInnerProvider({
342
+ children,
343
+ config,
344
+ timeout
345
+ }) {
346
+ const { getAccessTokenSilently, isAuthenticated } = auth0React.useAuth0();
347
+ const tokenGetterRef = react.useRef(async () => void 0);
348
+ tokenGetterRef.current = isAuthenticated ? async () => {
349
+ try {
350
+ return await getAccessTokenSilently();
351
+ } catch {
352
+ return void 0;
353
+ }
354
+ } : async () => void 0;
355
+ const client = react.useMemo(() => {
356
+ return new AxCloudClient({
357
+ baseUrl: config.apiUrl,
358
+ apiKey: config.apiKey,
359
+ timeout,
360
+ // Use a wrapper function that delegates to the ref
361
+ // This ensures the client always uses the current auth state
362
+ getAccessToken: async () => {
363
+ if (tokenGetterRef.current) {
364
+ return tokenGetterRef.current();
365
+ }
366
+ return void 0;
367
+ }
368
+ });
369
+ }, [config.apiUrl, config.apiKey, timeout]);
370
+ const contextValue = react.useMemo(
371
+ () => ({
372
+ config,
373
+ client,
374
+ orgId: config.orgId,
375
+ stage: config.stage,
376
+ isPublicMode: Boolean(config.apiKey) && !isAuthenticated
377
+ }),
378
+ [config, client, isAuthenticated]
379
+ );
380
+ return /* @__PURE__ */ jsxRuntime.jsx(AxCloudContext.Provider, { value: contextValue, children });
381
+ }
382
+ function AxCloudProvider({
383
+ children,
384
+ orgId,
385
+ apiUrl,
386
+ stage = "dev",
387
+ apiKey,
388
+ auth0,
389
+ queryClient = defaultQueryClient,
390
+ timeout
391
+ }) {
392
+ const config = react.useMemo(
393
+ () => ({
394
+ orgId,
395
+ apiUrl,
396
+ stage,
397
+ apiKey,
398
+ auth0
399
+ }),
400
+ [orgId, apiUrl, stage, apiKey, auth0]
401
+ );
402
+ return /* @__PURE__ */ jsxRuntime.jsx(reactQuery.QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsxRuntime.jsx(
403
+ auth0React.Auth0Provider,
404
+ {
405
+ domain: auth0.domain,
406
+ clientId: auth0.clientId,
407
+ authorizationParams: {
408
+ redirect_uri: auth0.redirectUri,
409
+ audience: auth0.audience
410
+ },
411
+ children: /* @__PURE__ */ jsxRuntime.jsx(AxCloudInnerProvider, { config, timeout, children })
412
+ }
413
+ ) });
414
+ }
415
+ function useAuth() {
416
+ const { config } = useAxCloudContext();
417
+ const {
418
+ isAuthenticated,
419
+ isLoading,
420
+ user: auth0User,
421
+ error,
422
+ loginWithRedirect,
423
+ logout: auth0Logout,
424
+ getAccessTokenSilently,
425
+ getIdTokenClaims
426
+ } = auth0React.useAuth0();
427
+ const login = react.useCallback(
428
+ (options) => {
429
+ return loginWithRedirect({
430
+ appState: {
431
+ returnTo: options?.returnTo || window.location.pathname
432
+ }
433
+ });
434
+ },
435
+ [loginWithRedirect]
436
+ );
437
+ const logout = react.useCallback(
438
+ (options) => {
439
+ return auth0Logout({
440
+ logoutParams: {
441
+ returnTo: options?.returnTo || window.location.origin
442
+ }
443
+ });
444
+ },
445
+ [auth0Logout]
446
+ );
447
+ const getAccessToken = react.useCallback(async () => {
448
+ try {
449
+ return await getAccessTokenSilently();
450
+ } catch {
451
+ return void 0;
452
+ }
453
+ }, [getAccessTokenSilently]);
454
+ const getAuth0Client = react.useCallback(() => {
455
+ return {
456
+ loginWithRedirect,
457
+ logout: auth0Logout,
458
+ getAccessTokenSilently,
459
+ getIdTokenClaims,
460
+ user: auth0User,
461
+ isAuthenticated,
462
+ isLoading,
463
+ error
464
+ };
465
+ }, [
466
+ loginWithRedirect,
467
+ auth0Logout,
468
+ getAccessTokenSilently,
469
+ getIdTokenClaims,
470
+ auth0User,
471
+ isAuthenticated,
472
+ isLoading,
473
+ error
474
+ ]);
475
+ const requestPasswordReset = react.useCallback(
476
+ async (email) => {
477
+ const targetEmail = email || auth0User?.email;
478
+ if (!targetEmail) {
479
+ return {
480
+ success: false,
481
+ message: "Email address is required"
482
+ };
483
+ }
484
+ try {
485
+ const auth0Domain = config.auth0.domain;
486
+ const clientId = config.auth0.clientId;
487
+ const connection = config.auth0.connection || "Username-Password-Authentication";
488
+ const response = await fetch(`https://${auth0Domain}/dbconnections/change_password`, {
489
+ method: "POST",
490
+ headers: {
491
+ "Content-Type": "application/json"
492
+ },
493
+ body: JSON.stringify({
494
+ client_id: clientId,
495
+ email: targetEmail.toLowerCase(),
496
+ connection
497
+ })
498
+ });
499
+ if (response.ok) {
500
+ return {
501
+ success: true,
502
+ message: "If an account exists with this email, a password reset link has been sent."
503
+ };
504
+ }
505
+ return {
506
+ success: true,
507
+ message: "If an account exists with this email, a password reset link has been sent."
508
+ };
509
+ } catch {
510
+ return {
511
+ success: false,
512
+ message: "Failed to send password reset email. Please try again."
513
+ };
514
+ }
515
+ },
516
+ [auth0User?.email, config.auth0.domain, config.auth0.clientId]
517
+ );
518
+ return {
519
+ // Simple, abstracted API
520
+ isAuthenticated,
521
+ isLoading,
522
+ error,
523
+ user: auth0User ? {
524
+ id: auth0User.sub || "",
525
+ email: auth0User.email || "",
526
+ name: auth0User.name || "",
527
+ avatar: auth0User.picture
528
+ } : null,
529
+ login,
530
+ logout,
531
+ // Escape hatch for advanced use cases
532
+ getAccessToken,
533
+ getAuth0Client,
534
+ // Password management
535
+ requestPasswordReset
536
+ };
537
+ }
538
+ function useUser() {
539
+ const { isAuthenticated, isLoading: isAuthLoading } = auth0React.useAuth0();
540
+ const { client, stage, orgId } = useAxCloudContext();
541
+ const query = reactQuery.useQuery({
542
+ queryKey: ["axcloud", "user", "me", stage],
543
+ queryFn: async () => {
544
+ return client.get(`/${stage}/api/users/me`);
545
+ },
546
+ enabled: isAuthenticated && !isAuthLoading,
547
+ staleTime: 1e3 * 60 * 5
548
+ // 5 minutes
549
+ });
550
+ const userData = query.data;
551
+ const userOrgIds = userData?.all_org_ids ?? [];
552
+ const isSuperAdmin = userData?.isSuperAdmin === true;
553
+ const hasOrgAccess = isSuperAdmin || userOrgIds.includes(orgId);
554
+ const orgMembership = userData?.organization_memberships?.[orgId];
555
+ const roleInOrg = orgMembership?.role ?? null;
556
+ return {
557
+ user: query.data ?? null,
558
+ isLoading: isAuthLoading || query.isLoading,
559
+ isError: query.isError,
560
+ error: query.error,
561
+ refetch: query.refetch,
562
+ // Organization access
563
+ hasOrgAccess,
564
+ roleInOrg,
565
+ // Convenience properties
566
+ isAuthenticated,
567
+ role: query.data?.role ?? null,
568
+ organizationId: query.data?.organizationId ?? null,
569
+ sectionId: query.data?.sectionId ?? null,
570
+ permissions: query.data?.permissions ?? [],
571
+ isSuperAdmin
572
+ };
573
+ }
574
+ function useOrg() {
575
+ const { client, orgId, stage, config } = useAxCloudContext();
576
+ const usePublicEndpoint = Boolean(config.apiKey);
577
+ const query = reactQuery.useQuery({
578
+ queryKey: ["axcloud", "organization", orgId, stage, usePublicEndpoint],
579
+ queryFn: async () => {
580
+ if (usePublicEndpoint) {
581
+ return client.get(`/content/public/${orgId}/org`);
582
+ } else {
583
+ return client.get(`/${stage}/api/organizations/${orgId}`);
584
+ }
585
+ },
586
+ staleTime: 1e3 * 60 * 10
587
+ // 10 minutes (org data rarely changes)
588
+ });
589
+ const orgData = query.data;
590
+ const normalizedOrg = orgData ? {
591
+ id: orgData.id || orgData.org_id,
592
+ org_id: orgData.org_id || orgData.id,
593
+ name: orgData.name,
594
+ description: orgData.description,
595
+ branding: orgData.branding || orgData.settings?.theme,
596
+ modules: orgData.modules || [],
597
+ contact: orgData.contact,
598
+ social: orgData.social
599
+ } : null;
600
+ const hasModule = react.useCallback(
601
+ (module) => {
602
+ const mods = normalizedOrg?.modules || [];
603
+ return mods.includes(module);
604
+ },
605
+ [normalizedOrg?.modules]
606
+ );
607
+ const modules = normalizedOrg?.modules ?? [];
608
+ return {
609
+ org: normalizedOrg,
610
+ orgId,
611
+ isLoading: query.isLoading,
612
+ isError: query.isError,
613
+ error: query.error,
614
+ refetch: query.refetch,
615
+ // Module helpers
616
+ hasModule,
617
+ modules
618
+ };
619
+ }
620
+ function useNews(options = {}) {
621
+ const { client, orgId, isPublicMode } = useAxCloudContext();
622
+ const {
623
+ page = 1,
624
+ pageSize = 20,
625
+ status = "published",
626
+ visibility,
627
+ sectionId,
628
+ search,
629
+ sortBy = "publishedAt",
630
+ sortOrder = "desc",
631
+ publicOnly = false
632
+ } = options;
633
+ const usePublicEndpoint = isPublicMode || publicOnly;
634
+ const query = reactQuery.useQuery({
635
+ queryKey: ["axcloud", "news", orgId, usePublicEndpoint, options],
636
+ queryFn: async () => {
637
+ const endpoint = usePublicEndpoint ? `/content/public/${orgId}/news` : `/content/members/${orgId}/news`;
638
+ return client.get(endpoint, {
639
+ page,
640
+ pageSize,
641
+ status,
642
+ visibility,
643
+ sectionId,
644
+ search,
645
+ sortBy,
646
+ sortOrder
647
+ });
648
+ },
649
+ staleTime: 1e3 * 60 * 5
650
+ // 5 minutes
651
+ });
652
+ return {
653
+ data: query.data?.items ?? [],
654
+ total: query.data?.total ?? 0,
655
+ hasMore: query.data?.hasMore ?? false,
656
+ isLoading: query.isLoading,
657
+ isError: query.isError,
658
+ error: query.error,
659
+ refetch: query.refetch
660
+ };
661
+ }
662
+ var MEMBER_ENDPOINT_TYPES = ["news", "pages", "events"];
663
+ function useContent(contentType, options = {}) {
664
+ const { client, orgId, isPublicMode } = useAxCloudContext();
665
+ const {
666
+ page = 1,
667
+ pageSize = 20,
668
+ status = "published",
669
+ visibility,
670
+ sectionId,
671
+ search,
672
+ sortBy = "createdAt",
673
+ sortOrder = "desc"
674
+ } = options;
675
+ const query = reactQuery.useQuery({
676
+ queryKey: ["axcloud", "content", orgId, contentType, isPublicMode, options],
677
+ queryFn: async () => {
678
+ const useMemberEndpoint = !isPublicMode && MEMBER_ENDPOINT_TYPES.includes(contentType);
679
+ const endpoint = useMemberEndpoint ? `/content/members/${orgId}/${contentType}` : `/content/public/${orgId}/${contentType}`;
680
+ return client.get(endpoint, {
681
+ page,
682
+ pageSize,
683
+ status,
684
+ visibility,
685
+ sectionId,
686
+ search,
687
+ sortBy,
688
+ sortOrder
689
+ });
690
+ },
691
+ staleTime: 1e3 * 60 * 5
692
+ // 5 minutes
693
+ });
694
+ return {
695
+ data: query.data?.items ?? [],
696
+ total: query.data?.total ?? 0,
697
+ hasMore: query.data?.hasMore ?? false,
698
+ isLoading: query.isLoading,
699
+ isError: query.isError,
700
+ error: query.error,
701
+ refetch: query.refetch
702
+ };
703
+ }
704
+ function useContentItem(contentType, idOrSlug, options = {}) {
705
+ const { client, orgId, isPublicMode } = useAxCloudContext();
706
+ const { publicOnly = false } = options;
707
+ const useMemberEndpoint = !isPublicMode && !publicOnly && MEMBER_ENDPOINT_TYPES.includes(contentType);
708
+ const query = reactQuery.useQuery({
709
+ queryKey: ["axcloud", "content", orgId, contentType, idOrSlug, useMemberEndpoint],
710
+ queryFn: async () => {
711
+ const basePath = useMemberEndpoint ? "members" : "public";
712
+ return client.get(`/content/${basePath}/${orgId}/${contentType}/${idOrSlug}`);
713
+ },
714
+ enabled: !!idOrSlug,
715
+ staleTime: 1e3 * 60 * 5
716
+ // 5 minutes
717
+ });
718
+ return {
719
+ data: query.data ?? null,
720
+ isLoading: query.isLoading,
721
+ isError: query.isError,
722
+ error: query.error,
723
+ refetch: query.refetch
724
+ };
725
+ }
726
+ function useMySection(options = {}) {
727
+ const { includeMembers = true } = options;
728
+ const { isAuthenticated } = auth0React.useAuth0();
729
+ const { client, orgId, stage } = useAxCloudContext();
730
+ const { user, sectionId, isLoading: isUserLoading } = useUser();
731
+ const query = reactQuery.useQuery({
732
+ queryKey: ["axcloud", "mySection", orgId, sectionId, includeMembers, stage],
733
+ queryFn: async () => {
734
+ if (!sectionId) {
735
+ throw new Error("User is not assigned to a section");
736
+ }
737
+ const section = await client.get(
738
+ `/${stage}/api/sections/${sectionId}`,
739
+ { includeMembers: includeMembers ? "true" : void 0 }
740
+ );
741
+ return section;
742
+ },
743
+ enabled: isAuthenticated && !isUserLoading && !!sectionId,
744
+ staleTime: 1e3 * 60 * 5
745
+ // 5 minutes
746
+ });
747
+ return {
748
+ section: query.data ?? null,
749
+ sectionId,
750
+ members: query.data?.members ?? [],
751
+ memberCount: query.data?.memberCount ?? 0,
752
+ isLoading: isUserLoading || query.isLoading,
753
+ isError: query.isError,
754
+ error: query.error,
755
+ refetch: query.refetch,
756
+ // Helper: Does the user have a section?
757
+ hasSection: !!sectionId,
758
+ // The current user in context
759
+ user
760
+ };
761
+ }
762
+ function useSections() {
763
+ const { client, orgId, stage } = useAxCloudContext();
764
+ const query = reactQuery.useQuery({
765
+ queryKey: ["axcloud", "sections", orgId, stage],
766
+ queryFn: async () => {
767
+ return client.get(`/${stage}/api/organizations/${orgId}/sections`);
768
+ },
769
+ staleTime: 1e3 * 60 * 10
770
+ // 10 minutes
771
+ });
772
+ return {
773
+ sections: query.data ?? [],
774
+ isLoading: query.isLoading,
775
+ isError: query.isError,
776
+ error: query.error,
777
+ refetch: query.refetch
778
+ };
779
+ }
780
+ function useForms(options = {}) {
781
+ const { client, stage } = useAxCloudContext();
782
+ const { formType, status, limit = 50, cursor } = options;
783
+ const query = reactQuery.useQuery({
784
+ queryKey: ["axcloud", "forms", "submissions", stage, options],
785
+ queryFn: async () => {
786
+ const params = { limit };
787
+ if (formType) params.form_type = formType;
788
+ if (status) params.status = status;
789
+ if (cursor) params.cursor = cursor;
790
+ return client.get(`/${stage}/api/admin/forms/submissions`, params);
791
+ },
792
+ staleTime: 1e3 * 30
793
+ // 30 seconds
794
+ });
795
+ return {
796
+ data: query.data?.items ?? [],
797
+ total: query.data?.total ?? 0,
798
+ hasMore: query.data?.hasMore ?? false,
799
+ cursor: query.data?.cursor,
800
+ isLoading: query.isLoading,
801
+ isError: query.isError,
802
+ error: query.error,
803
+ refetch: query.refetch
804
+ };
805
+ }
806
+ function useFormStats(options = {}) {
807
+ const { client, stage } = useAxCloudContext();
808
+ const { days = 30 } = options;
809
+ const query = reactQuery.useQuery({
810
+ queryKey: ["axcloud", "forms", "stats", stage, days],
811
+ queryFn: async () => {
812
+ return client.get(`/${stage}/api/admin/forms/stats`, { days });
813
+ },
814
+ staleTime: 1e3 * 60 * 5
815
+ // 5 minutes
816
+ });
817
+ return {
818
+ stats: query.data?.stats,
819
+ summary: query.data?.summary,
820
+ period: query.data?.period,
821
+ isLoading: query.isLoading,
822
+ isError: query.isError,
823
+ error: query.error,
824
+ refetch: query.refetch
825
+ };
826
+ }
827
+ function useUpdateFormSubmission() {
828
+ const { client, stage } = useAxCloudContext();
829
+ const queryClient = reactQuery.useQueryClient();
830
+ return reactQuery.useMutation({
831
+ mutationFn: async ({
832
+ submissionId,
833
+ status,
834
+ notes
835
+ }) => {
836
+ return client.patch(`/${stage}/api/admin/forms/submissions/${submissionId}`, { status, notes });
837
+ },
838
+ onSuccess: () => {
839
+ queryClient.invalidateQueries({ queryKey: ["axcloud", "forms"] });
840
+ }
841
+ });
842
+ }
843
+ var LINKED_ACCOUNTS_QUERY_KEY = ["axcloud", "linked-accounts"];
844
+ function useLinkedAccounts() {
845
+ const { isAuthenticated } = useAuth();
846
+ const queryClient = reactQuery.useQueryClient();
847
+ const query = reactQuery.useQuery({
848
+ queryKey: LINKED_ACCOUNTS_QUERY_KEY,
849
+ queryFn: async () => {
850
+ const client = getClient();
851
+ return client.get("/api/users/me/identities");
852
+ },
853
+ enabled: isAuthenticated,
854
+ staleTime: 1e3 * 60 * 5
855
+ // 5 minutes
856
+ });
857
+ const linkMutation = reactQuery.useMutation({
858
+ mutationFn: async (provider) => {
859
+ const client = getClient();
860
+ const response = await client.post(
861
+ `/api/users/me/identities/${provider}/link`,
862
+ {}
863
+ );
864
+ if (response.authorization_url) {
865
+ window.location.href = response.authorization_url;
866
+ }
867
+ return response;
868
+ },
869
+ onSuccess: () => {
870
+ queryClient.invalidateQueries({ queryKey: LINKED_ACCOUNTS_QUERY_KEY });
871
+ }
872
+ });
873
+ const unlinkMutation = reactQuery.useMutation({
874
+ mutationFn: async (provider) => {
875
+ const client = getClient();
876
+ return client.delete(
877
+ `/api/users/me/identities/${provider}`
878
+ );
879
+ },
880
+ onSuccess: () => {
881
+ queryClient.invalidateQueries({ queryKey: LINKED_ACCOUNTS_QUERY_KEY });
882
+ }
883
+ });
884
+ return {
885
+ identities: query.data?.identities ?? [],
886
+ availableProviders: query.data?.available_providers ?? [],
887
+ canUnlink: query.data?.can_unlink ?? false,
888
+ isLoading: query.isLoading,
889
+ error: query.error,
890
+ linkAccount: linkMutation.mutate,
891
+ unlinkAccount: unlinkMutation.mutate,
892
+ isLinking: linkMutation.isPending,
893
+ isUnlinking: unlinkMutation.isPending,
894
+ refetch: query.refetch
895
+ };
896
+ }
897
+ function useBranding() {
898
+ const { client, orgId } = useAxCloudContext();
899
+ const query = reactQuery.useQuery({
900
+ queryKey: ["axcloud", "media", "branding", orgId],
901
+ queryFn: async () => {
902
+ return client.get(`/media/public/${orgId}/branding`);
903
+ },
904
+ staleTime: 1e3 * 60 * 30,
905
+ // 30 minutes (logo URL valid for 1 hour)
906
+ gcTime: 1e3 * 60 * 55
907
+ // Garbage collect before URL expires
908
+ });
909
+ return {
910
+ branding: query.data?.branding ?? null,
911
+ logoUrl: query.data?.branding?.logoUrl ?? null,
912
+ organizationName: query.data?.name ?? null,
913
+ isLoading: query.isLoading,
914
+ isError: query.isError,
915
+ error: query.error,
916
+ refetch: query.refetch
917
+ };
918
+ }
919
+ function useLogo() {
920
+ const { client, orgId } = useAxCloudContext();
921
+ const query = reactQuery.useQuery({
922
+ queryKey: ["axcloud", "media", "logo", orgId],
923
+ queryFn: async () => {
924
+ return client.get(`/media/public/${orgId}/logo`);
925
+ },
926
+ staleTime: 1e3 * 60 * 30,
927
+ // 30 minutes
928
+ gcTime: 1e3 * 60 * 55
929
+ // Garbage collect before URL expires
930
+ });
931
+ return {
932
+ logoUrl: query.data?.url ?? null,
933
+ expiresIn: query.data?.expiresIn ?? null,
934
+ isLoading: query.isLoading,
935
+ isError: query.isError,
936
+ error: query.error,
937
+ refetch: query.refetch
938
+ };
939
+ }
940
+ function useAvatar(userId) {
941
+ const { client, orgId } = useAxCloudContext();
942
+ const query = reactQuery.useQuery({
943
+ queryKey: ["axcloud", "media", "avatar", orgId, userId],
944
+ queryFn: async () => {
945
+ return client.get(`/media/public/${orgId}/avatar/${userId}`);
946
+ },
947
+ enabled: !!userId,
948
+ staleTime: 1e3 * 60 * 30,
949
+ gcTime: 1e3 * 60 * 55,
950
+ retry: false
951
+ // Don't retry if avatar doesn't exist
952
+ });
953
+ return {
954
+ avatarUrl: query.data?.url ?? null,
955
+ isLoading: query.isLoading,
956
+ isError: query.isError,
957
+ error: query.error,
958
+ refetch: query.refetch
959
+ };
960
+ }
961
+ function useMediaList(type = "media", limit = 50) {
962
+ const { client, orgId } = useAxCloudContext();
963
+ const query = reactQuery.useQuery({
964
+ queryKey: ["axcloud", "media", "list", orgId, type, limit],
965
+ queryFn: async () => {
966
+ return client.get(`/media/public/${orgId}/list`, {
967
+ type,
968
+ limit
969
+ });
970
+ },
971
+ staleTime: 1e3 * 60 * 5
972
+ // 5 minutes
973
+ });
974
+ return {
975
+ items: query.data?.items ?? [],
976
+ count: query.data?.count ?? 0,
977
+ isLoading: query.isLoading,
978
+ isError: query.isError,
979
+ error: query.error,
980
+ refetch: query.refetch
981
+ };
982
+ }
983
+ function useMedia(mediaId) {
984
+ const { client, orgId } = useAxCloudContext();
985
+ const query = reactQuery.useQuery({
986
+ queryKey: ["axcloud", "media", "file", orgId, mediaId],
987
+ queryFn: async () => {
988
+ return client.get(`/media/public/${orgId}/media/${mediaId}`);
989
+ },
990
+ enabled: !!mediaId,
991
+ staleTime: 1e3 * 60 * 30,
992
+ gcTime: 1e3 * 60 * 55
993
+ });
994
+ return {
995
+ mediaUrl: query.data?.url ?? null,
996
+ expiresIn: query.data?.expiresIn ?? null,
997
+ isLoading: query.isLoading,
998
+ isError: query.isError,
999
+ error: query.error,
1000
+ refetch: query.refetch
1001
+ };
1002
+ }
1003
+ function LoginButton({
1004
+ children = "Log in",
1005
+ returnTo,
1006
+ className,
1007
+ style
1008
+ }) {
1009
+ const { login, isLoading } = useAuth();
1010
+ const handleClick = () => {
1011
+ login({ returnTo });
1012
+ };
1013
+ return /* @__PURE__ */ jsxRuntime.jsx(
1014
+ "button",
1015
+ {
1016
+ onClick: handleClick,
1017
+ disabled: isLoading,
1018
+ className,
1019
+ style,
1020
+ type: "button",
1021
+ children: isLoading ? "Loading..." : children
1022
+ }
1023
+ );
1024
+ }
1025
+ function LogoutButton({
1026
+ children = "Log out",
1027
+ returnTo,
1028
+ className,
1029
+ style
1030
+ }) {
1031
+ const { logout } = useAuth();
1032
+ const handleClick = () => {
1033
+ logout({ returnTo });
1034
+ };
1035
+ return /* @__PURE__ */ jsxRuntime.jsx(
1036
+ "button",
1037
+ {
1038
+ onClick: handleClick,
1039
+ className,
1040
+ style,
1041
+ type: "button",
1042
+ children
1043
+ }
1044
+ );
1045
+ }
1046
+ function ProtectedRoute({
1047
+ children,
1048
+ roles,
1049
+ loadingComponent,
1050
+ unauthenticatedComponent,
1051
+ unauthorizedComponent,
1052
+ redirectToLogin = false,
1053
+ returnTo
1054
+ }) {
1055
+ const { isAuthenticated, isLoading: isAuthLoading, login } = useAuth();
1056
+ const { user, role, isLoading: isUserLoading } = useUser();
1057
+ const isLoading = isAuthLoading || isAuthenticated && isUserLoading;
1058
+ if (isLoading) {
1059
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: loadingComponent ?? /* @__PURE__ */ jsxRuntime.jsx(DefaultLoadingComponent, {}) });
1060
+ }
1061
+ if (!isAuthenticated) {
1062
+ if (redirectToLogin) {
1063
+ login({ returnTo: returnTo || window.location.pathname });
1064
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: loadingComponent ?? /* @__PURE__ */ jsxRuntime.jsx(DefaultLoadingComponent, {}) });
1065
+ }
1066
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: unauthenticatedComponent ?? /* @__PURE__ */ jsxRuntime.jsx(DefaultUnauthenticatedComponent, {}) });
1067
+ }
1068
+ if (roles && role) {
1069
+ const requiredRoles = Array.isArray(roles) ? roles : [roles];
1070
+ const hasRequiredRole = requiredRoles.includes(role);
1071
+ if (!hasRequiredRole) {
1072
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: unauthorizedComponent ?? /* @__PURE__ */ jsxRuntime.jsx(DefaultUnauthorizedComponent, {}) });
1073
+ }
1074
+ }
1075
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
1076
+ }
1077
+ function DefaultLoadingComponent() {
1078
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "20px", textAlign: "center" }, children: "Loading..." });
1079
+ }
1080
+ function DefaultUnauthenticatedComponent() {
1081
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "20px", textAlign: "center" }, children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Please log in to view this content." }) });
1082
+ }
1083
+ function DefaultUnauthorizedComponent() {
1084
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "20px", textAlign: "center" }, children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: "You don't have permission to view this content." }) });
1085
+ }
1086
+ function ModuleGate({
1087
+ module,
1088
+ children,
1089
+ fallback = null,
1090
+ requireAll = false
1091
+ }) {
1092
+ const { hasModule, isLoading } = useOrg();
1093
+ if (isLoading) {
1094
+ return null;
1095
+ }
1096
+ const requiredModules = Array.isArray(module) ? module : [module];
1097
+ const hasAccess = requireAll ? requiredModules.every((m) => hasModule(m)) : requiredModules.some((m) => hasModule(m));
1098
+ if (!hasAccess) {
1099
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fallback });
1100
+ }
1101
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
1102
+ }
1103
+ function useModuleAccess() {
1104
+ const { hasModule, modules, isLoading } = useOrg();
1105
+ return {
1106
+ hasModule,
1107
+ modules,
1108
+ isLoading
1109
+ };
1110
+ }
1111
+ var SUPPORTED_OAUTH_PROVIDERS = ["google", "microsoft", "apple"];
1112
+ function isSupportedOAuthProvider(provider) {
1113
+ return SUPPORTED_OAUTH_PROVIDERS.includes(provider);
1114
+ }
1115
+ var ProviderIcons = {
1116
+ google: ({ className }) => /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", className, fill: "currentColor", children: [
1117
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z", fill: "#4285F4" }),
1118
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z", fill: "#34A853" }),
1119
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z", fill: "#FBBC05" }),
1120
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z", fill: "#EA4335" })
1121
+ ] }),
1122
+ microsoft: ({ className }) => /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", className, children: [
1123
+ /* @__PURE__ */ jsxRuntime.jsx("path", { fill: "#F25022", d: "M1 1h10v10H1z" }),
1124
+ /* @__PURE__ */ jsxRuntime.jsx("path", { fill: "#00A4EF", d: "M1 13h10v10H1z" }),
1125
+ /* @__PURE__ */ jsxRuntime.jsx("path", { fill: "#7FBA00", d: "M13 1h10v10H13z" }),
1126
+ /* @__PURE__ */ jsxRuntime.jsx("path", { fill: "#FFB900", d: "M13 13h10v10H13z" })
1127
+ ] }),
1128
+ apple: ({ className }) => /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", className, fill: "currentColor", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.32-3.14-2.53C4.25 17 2.94 12.45 4.7 9.39c.87-1.52 2.43-2.48 4.12-2.51 1.28-.02 2.5.87 3.29.87.78 0 2.26-1.07 3.81-.91.65.03 2.47.26 3.64 1.98-.09.06-2.17 1.28-2.15 3.81.03 3.02 2.65 4.03 2.68 4.04-.03.07-.42 1.44-1.38 2.83M13 3.5c.73-.83 1.94-1.46 2.94-1.5.13 1.17-.34 2.35-1.04 3.19-.69.85-1.83 1.51-2.95 1.42-.15-1.15.41-2.35 1.05-3.11z" }) }),
1129
+ email: ({ className }) => /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", className, fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
1130
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z" }),
1131
+ /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "22,6 12,13 2,6" })
1132
+ ] })
1133
+ };
1134
+ function LinkedAccountsList({
1135
+ providers,
1136
+ showConnectButtons = true,
1137
+ className,
1138
+ onUnlink,
1139
+ onLinkInitiated,
1140
+ renderIdentity,
1141
+ renderAvailableProvider
1142
+ }) {
1143
+ const {
1144
+ identities,
1145
+ availableProviders,
1146
+ canUnlink,
1147
+ isLoading,
1148
+ error,
1149
+ linkAccount,
1150
+ unlinkAccount
1151
+ } = useLinkedAccounts();
1152
+ const filteredIdentities = providers ? identities.filter(
1153
+ (i) => providers.some(
1154
+ (p) => i.provider.toLowerCase().includes(p) || i.provider_icon === p
1155
+ )
1156
+ ) : identities;
1157
+ const filteredAvailableProviders = providers ? availableProviders.filter(
1158
+ (p) => providers.some(
1159
+ (provider) => p.provider.toLowerCase().includes(provider) || p.icon === provider
1160
+ )
1161
+ ) : availableProviders;
1162
+ const handleUnlink = (provider) => {
1163
+ unlinkAccount(provider);
1164
+ onUnlink?.(provider);
1165
+ };
1166
+ const handleLink = (provider) => {
1167
+ onLinkInitiated?.(provider);
1168
+ linkAccount(provider);
1169
+ };
1170
+ if (isLoading) {
1171
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `axcloud-linked-accounts__loading ${className || ""}`, children: "Loading linked accounts..." });
1172
+ }
1173
+ if (error) {
1174
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: `axcloud-linked-accounts__error ${className || ""}`, children: "Failed to load linked accounts. Please try again." });
1175
+ }
1176
+ const getIcon = (iconName, muted = false) => {
1177
+ const IconComponent = ProviderIcons[iconName] || ProviderIcons.email;
1178
+ const iconClass = muted ? "axcloud-linked-accounts__icon axcloud-linked-accounts__icon--muted" : "axcloud-linked-accounts__icon";
1179
+ return /* @__PURE__ */ jsxRuntime.jsx(IconComponent, { className: iconClass });
1180
+ };
1181
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `axcloud-linked-accounts ${className || ""}`, children: [
1182
+ filteredIdentities.map((identity) => {
1183
+ if (renderIdentity) {
1184
+ return renderIdentity(identity, () => handleUnlink(identity.provider));
1185
+ }
1186
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "axcloud-linked-accounts__item", children: [
1187
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "axcloud-linked-accounts__info", children: [
1188
+ getIcon(identity.provider_icon),
1189
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1190
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "axcloud-linked-accounts__name-row", children: [
1191
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "axcloud-linked-accounts__provider-name", children: identity.provider_display_name }),
1192
+ identity.is_primary && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "axcloud-linked-accounts__badge", children: "Primary" })
1193
+ ] }),
1194
+ identity.profile_data?.email && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "axcloud-linked-accounts__email", children: identity.profile_data.email })
1195
+ ] })
1196
+ ] }),
1197
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "axcloud-linked-accounts__actions", children: [
1198
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "axcloud-linked-accounts__connected", children: [
1199
+ /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "20 6 9 17 4 12" }) }),
1200
+ "Connected"
1201
+ ] }),
1202
+ canUnlink && !identity.is_primary && /* @__PURE__ */ jsxRuntime.jsx(
1203
+ "button",
1204
+ {
1205
+ onClick: () => handleUnlink(identity.provider),
1206
+ className: "axcloud-linked-accounts__button axcloud-linked-accounts__button--disconnect",
1207
+ children: "Disconnect"
1208
+ }
1209
+ )
1210
+ ] })
1211
+ ] }, `${identity.provider}-${identity.user_id}`);
1212
+ }),
1213
+ showConnectButtons && filteredAvailableProviders.map((provider) => {
1214
+ if (renderAvailableProvider) {
1215
+ return renderAvailableProvider(provider, () => {
1216
+ if (isSupportedOAuthProvider(provider.provider)) {
1217
+ handleLink(provider.provider);
1218
+ }
1219
+ });
1220
+ }
1221
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "axcloud-linked-accounts__available", children: [
1222
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "axcloud-linked-accounts__info", children: [
1223
+ getIcon(provider.icon, true),
1224
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1225
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "axcloud-linked-accounts__provider-name", children: provider.display_name }),
1226
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "axcloud-linked-accounts__email", children: "Not connected" })
1227
+ ] })
1228
+ ] }),
1229
+ /* @__PURE__ */ jsxRuntime.jsx(
1230
+ "button",
1231
+ {
1232
+ onClick: () => {
1233
+ if (isSupportedOAuthProvider(provider.provider)) {
1234
+ handleLink(provider.provider);
1235
+ }
1236
+ },
1237
+ className: "axcloud-linked-accounts__button axcloud-linked-accounts__button--connect",
1238
+ children: "Connect"
1239
+ }
1240
+ )
1241
+ ] }, provider.provider);
1242
+ })
1243
+ ] });
1244
+ }
1245
+
1246
+ exports.AxCloudClient = AxCloudClient;
1247
+ exports.AxCloudError = AxCloudError;
1248
+ exports.AxCloudProvider = AxCloudProvider;
1249
+ exports.LinkedAccountsList = LinkedAccountsList;
1250
+ exports.LoginButton = LoginButton;
1251
+ exports.LogoutButton = LogoutButton;
1252
+ exports.ModuleGate = ModuleGate;
1253
+ exports.ProtectedRoute = ProtectedRoute;
1254
+ exports.createClient = createClient;
1255
+ exports.createFormHelper = createFormHelper;
1256
+ exports.getClient = getClient;
1257
+ exports.isAxCloudError = isAxCloudError;
1258
+ exports.submitForm = submitForm;
1259
+ exports.useAuth = useAuth;
1260
+ exports.useAvatar = useAvatar;
1261
+ exports.useAxCloudContext = useAxCloudContext;
1262
+ exports.useBranding = useBranding;
1263
+ exports.useContent = useContent;
1264
+ exports.useContentItem = useContentItem;
1265
+ exports.useFormStats = useFormStats;
1266
+ exports.useForms = useForms;
1267
+ exports.useLinkedAccounts = useLinkedAccounts;
1268
+ exports.useLogo = useLogo;
1269
+ exports.useMedia = useMedia;
1270
+ exports.useMediaList = useMediaList;
1271
+ exports.useModuleAccess = useModuleAccess;
1272
+ exports.useMySection = useMySection;
1273
+ exports.useNews = useNews;
1274
+ exports.useOrg = useOrg;
1275
+ exports.useSections = useSections;
1276
+ exports.useUpdateFormSubmission = useUpdateFormSubmission;
1277
+ exports.useUser = useUser;
1278
+ exports.userHasAllPermissions = userHasAllPermissions;
1279
+ exports.userHasAnyPermission = userHasAnyPermission;
1280
+ exports.userHasPermission = userHasPermission;
1281
+ //# sourceMappingURL=index.js.map
1282
+ //# sourceMappingURL=index.js.map