@iblai/web-utils 0.3.0 → 1.1.1
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/README.md +504 -0
- package/dist/data-layer/src/features/chat-files/api-slice.d.ts +185 -0
- package/dist/data-layer/src/features/chat-files/types.d.ts +32 -0
- package/dist/data-layer/src/features/core/api-slice.d.ts +419 -61
- package/dist/data-layer/src/features/core/constants.d.ts +3 -0
- package/dist/data-layer/src/features/core/custom-api-slice.d.ts +50 -50
- package/dist/data-layer/src/features/core/custom-public-image-asset-api-slice.d.ts +333 -0
- package/dist/data-layer/src/features/core/types.d.ts +33 -0
- package/dist/data-layer/src/features/credentials/api-slice.d.ts +62 -39
- package/dist/data-layer/src/features/mentor/api-slice.d.ts +1028 -188
- package/dist/data-layer/src/features/notifications/constants.d.ts +6 -0
- package/dist/data-layer/src/features/notifications/custom-api-slice.d.ts +43 -43
- package/dist/data-layer/src/features/notifications/types.d.ts +25 -2
- package/dist/data-layer/src/features/stripe/api-slice.d.ts +22 -0
- package/dist/data-layer/src/index.d.ts +3 -0
- package/dist/index.d.ts +447 -83
- package/dist/index.esm.js +1137 -196
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1167 -193
- package/dist/index.js.map +1 -1
- package/dist/package.json +4 -2
- package/dist/web-utils/src/constants/chat.d.ts +8 -0
- package/dist/web-utils/src/features/files/filesSlice.d.ts +20 -0
- package/dist/web-utils/src/features/index.d.ts +1 -0
- package/dist/web-utils/src/hooks/chat/use-advanced-chat.d.ts +6 -4
- package/dist/web-utils/src/hooks/chat/use-chat-v2.d.ts +11 -1
- package/dist/web-utils/src/hooks/use-mentor-settings.d.ts +18 -15
- package/dist/web-utils/src/index.d.ts +2 -0
- package/dist/web-utils/src/index.web.d.ts +14 -12
- package/dist/web-utils/src/providers/auth-provider.d.ts +9 -1
- package/dist/web-utils/src/providers/mentor-provider.d.ts +2 -1
- package/dist/web-utils/src/providers/tenant-provider.d.ts +3 -1
- package/dist/web-utils/src/services/__tests__/file-upload.test.d.ts +1 -0
- package/dist/web-utils/src/services/file-upload.d.ts +60 -0
- package/dist/web-utils/src/services/index.d.ts +1 -0
- package/dist/web-utils/src/types/file-upload.d.ts +62 -0
- package/dist/web-utils/src/types/index.d.ts +1 -0
- package/dist/web-utils/src/utils/auth.d.ts +180 -0
- package/dist/web-utils/src/utils/index.d.ts +1 -0
- package/package.json +12 -13
- package/dist/web-utils/tsconfig.tsbuildinfo +0 -1
package/dist/index.esm.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import React__default, { useCallback, useDebugValue, useMemo, useState, useEffect, useRef, useLayoutEffect, createContext, useContext } from 'react';
|
|
3
|
-
import { OpenAPI, CoreService, ReportsService, AiAnalyticsService, AiMentorService, SearchService, AiPromptService, AiIndexService, CatalogService, SkillsService, AiAccountService, CredentialsService, FeaturesService, CommerceService, NotificationsService } from '@iblai/iblai-api';
|
|
4
|
-
import { jsx
|
|
3
|
+
import { OpenAPI, CoreService, ReportsService, AiAnalyticsService, AiMentorService, SearchService, AiPromptService, AiIndexService, CatalogService, SkillsService, AiAccountService, CredentialsService, FeaturesService, CommerceService, NotificationsService, MentorVisibilityEnum } from '@iblai/iblai-api';
|
|
4
|
+
import { jsx } from 'react/jsx-runtime';
|
|
5
|
+
import axios from 'axios';
|
|
5
6
|
|
|
6
7
|
const SUBSCRIPTION_TRIGGERS = {
|
|
7
8
|
PRICING_MODAL: "TRIGGER_PRICING_MODAL",
|
|
@@ -3380,7 +3381,7 @@ function updateMutationSubstateIfExists(state, id, update) {
|
|
|
3380
3381
|
update(substate);
|
|
3381
3382
|
}
|
|
3382
3383
|
}
|
|
3383
|
-
var initialState$
|
|
3384
|
+
var initialState$2 = {};
|
|
3384
3385
|
function buildSlice({
|
|
3385
3386
|
reducerPath,
|
|
3386
3387
|
queryThunk,
|
|
@@ -3456,7 +3457,7 @@ function buildSlice({
|
|
|
3456
3457
|
}
|
|
3457
3458
|
const querySlice = createSlice$1({
|
|
3458
3459
|
name: `${reducerPath}/queries`,
|
|
3459
|
-
initialState: initialState$
|
|
3460
|
+
initialState: initialState$2,
|
|
3460
3461
|
reducers: {
|
|
3461
3462
|
removeQueryResult: {
|
|
3462
3463
|
reducer(draft, {
|
|
@@ -3590,7 +3591,7 @@ function buildSlice({
|
|
|
3590
3591
|
});
|
|
3591
3592
|
const mutationSlice = createSlice$1({
|
|
3592
3593
|
name: `${reducerPath}/mutations`,
|
|
3593
|
-
initialState: initialState$
|
|
3594
|
+
initialState: initialState$2,
|
|
3594
3595
|
reducers: {
|
|
3595
3596
|
removeMutationResult: {
|
|
3596
3597
|
reducer(draft, {
|
|
@@ -3759,7 +3760,7 @@ function buildSlice({
|
|
|
3759
3760
|
}
|
|
3760
3761
|
const subscriptionSlice = createSlice$1({
|
|
3761
3762
|
name: `${reducerPath}/subscriptions`,
|
|
3762
|
-
initialState: initialState$
|
|
3763
|
+
initialState: initialState$2,
|
|
3763
3764
|
reducers: {
|
|
3764
3765
|
updateSubscriptionOptions(d, a) {
|
|
3765
3766
|
},
|
|
@@ -3771,7 +3772,7 @@ function buildSlice({
|
|
|
3771
3772
|
});
|
|
3772
3773
|
const internalSubscriptionsSlice = createSlice$1({
|
|
3773
3774
|
name: `${reducerPath}/internalSubscriptions`,
|
|
3774
|
-
initialState: initialState$
|
|
3775
|
+
initialState: initialState$2,
|
|
3775
3776
|
reducers: {
|
|
3776
3777
|
subscriptionsUpdated: {
|
|
3777
3778
|
reducer(state, action) {
|
|
@@ -6441,6 +6442,25 @@ createApi({
|
|
|
6441
6442
|
}),
|
|
6442
6443
|
});
|
|
6443
6444
|
|
|
6445
|
+
createApi({
|
|
6446
|
+
reducerPath: 'chatFilesApiSlice',
|
|
6447
|
+
baseQuery: iblFetchBaseQuery,
|
|
6448
|
+
endpoints: (builder) => ({
|
|
6449
|
+
/**
|
|
6450
|
+
* Get presigned S3 URL for file upload
|
|
6451
|
+
* POST /api/ai-mentor/orgs/{org}/users/{userId}/chat/files/upload-url/
|
|
6452
|
+
*/
|
|
6453
|
+
getFileUploadUrl: builder.mutation({
|
|
6454
|
+
query: ({ org, userId, requestBody, }) => ({
|
|
6455
|
+
url: `/api/ai-mentor/orgs/${org}/users/${userId}/chat/files/upload-url/`,
|
|
6456
|
+
method: 'POST',
|
|
6457
|
+
body: requestBody,
|
|
6458
|
+
service: SERVICES.DM,
|
|
6459
|
+
}),
|
|
6460
|
+
}),
|
|
6461
|
+
}),
|
|
6462
|
+
});
|
|
6463
|
+
|
|
6444
6464
|
createApi({
|
|
6445
6465
|
reducerPath: 'llmsApiSlice',
|
|
6446
6466
|
baseQuery: iblFakeBaseQuery,
|
|
@@ -6461,6 +6481,7 @@ const mentorApiSlice = createApi({
|
|
|
6461
6481
|
'mentorPublicSettings',
|
|
6462
6482
|
'shareableLinks',
|
|
6463
6483
|
'publicMentors',
|
|
6484
|
+
'moderationLogs',
|
|
6464
6485
|
],
|
|
6465
6486
|
endpoints: (builder) => ({
|
|
6466
6487
|
createMentor: builder.mutation({
|
|
@@ -6526,7 +6547,7 @@ const mentorApiSlice = createApi({
|
|
|
6526
6547
|
}));
|
|
6527
6548
|
}
|
|
6528
6549
|
catch (error) {
|
|
6529
|
-
console.error(error);
|
|
6550
|
+
console.error(JSON.stringify(error));
|
|
6530
6551
|
}
|
|
6531
6552
|
},
|
|
6532
6553
|
}),
|
|
@@ -6582,9 +6603,17 @@ const mentorApiSlice = createApi({
|
|
|
6582
6603
|
...buildEndpointFromDmService(AiMentorService.aiMentorOrgsUsersMentorsForkCreate),
|
|
6583
6604
|
invalidatesTags: ['mentors'],
|
|
6584
6605
|
}),
|
|
6606
|
+
getRecentlyAccessedMentors: builder.query({
|
|
6607
|
+
...buildEndpointFromDmService(AiMentorService.aiMentorOrgsUsersRecentlyAccessedMentorsList),
|
|
6608
|
+
providesTags: ['mentors'],
|
|
6609
|
+
}),
|
|
6610
|
+
getModerationLogs: builder.query({
|
|
6611
|
+
...buildEndpointFromDmService(AiMentorService.aiMentorOrgsUsersModerationLogsList),
|
|
6612
|
+
providesTags: ['moderationLogs'],
|
|
6613
|
+
}),
|
|
6585
6614
|
}),
|
|
6586
6615
|
});
|
|
6587
|
-
const { useLazyGetMentorsQuery, useLazySeedMentorsQuery, useGetMentorSettingsQuery, useGetMentorPublicSettingsQuery, useLazyGetMentorPublicSettingsQuery, useLazyGetFreeUsageCountQuery} = mentorApiSlice;
|
|
6616
|
+
const { useLazyGetMentorsQuery, useLazySeedMentorsQuery, useGetMentorSettingsQuery, useGetMentorPublicSettingsQuery, useLazyGetMentorPublicSettingsQuery, useLazyGetFreeUsageCountQuery, useLazyGetRecentlyAccessedMentorsQuery} = mentorApiSlice;
|
|
6588
6617
|
|
|
6589
6618
|
createApi({
|
|
6590
6619
|
reducerPath: 'mentorCategoriesApiSlice',
|
|
@@ -7051,7 +7080,20 @@ const coreApiSlice = createApi({
|
|
|
7051
7080
|
invalidatesTags: ['RbacGroups'],
|
|
7052
7081
|
}),
|
|
7053
7082
|
getRbacGroupDetails: builder.query({
|
|
7054
|
-
...
|
|
7083
|
+
...buildEndpointFromService(SERVICES.DM, async (args) => {
|
|
7084
|
+
const url = `${OpenAPI.BASE}/api/core/rbac/groups/${args.id}/`;
|
|
7085
|
+
const response = await fetch(url, {
|
|
7086
|
+
method: 'GET',
|
|
7087
|
+
headers: OpenAPI.HEADERS,
|
|
7088
|
+
});
|
|
7089
|
+
if (!response.ok) {
|
|
7090
|
+
const error = new Error('Failed to fetch RBAC group details');
|
|
7091
|
+
error.status = response.status;
|
|
7092
|
+
error.body = await response.text();
|
|
7093
|
+
throw error;
|
|
7094
|
+
}
|
|
7095
|
+
return response.json();
|
|
7096
|
+
}),
|
|
7055
7097
|
providesTags: ['RbacGroups'],
|
|
7056
7098
|
}),
|
|
7057
7099
|
//RBAC POLICIES
|
|
@@ -7072,7 +7114,22 @@ const coreApiSlice = createApi({
|
|
|
7072
7114
|
invalidatesTags: ['RbacPolicies'],
|
|
7073
7115
|
}),
|
|
7074
7116
|
getRbacPolicyDetails: builder.query({
|
|
7075
|
-
...
|
|
7117
|
+
...buildEndpointFromService(SERVICES.DM, async (args) => {
|
|
7118
|
+
const queryParams = new URLSearchParams({ platform_key: args.platform_key });
|
|
7119
|
+
const queryString = queryParams.toString();
|
|
7120
|
+
const url = `${OpenAPI.BASE}/api/core/rbac/policies/${args.id}/?${queryString}`;
|
|
7121
|
+
const response = await fetch(url, {
|
|
7122
|
+
method: 'GET',
|
|
7123
|
+
headers: OpenAPI.HEADERS,
|
|
7124
|
+
});
|
|
7125
|
+
if (!response.ok) {
|
|
7126
|
+
const error = new Error('Failed to fetch RBAC policy details');
|
|
7127
|
+
error.status = response.status;
|
|
7128
|
+
error.body = await response.text();
|
|
7129
|
+
throw error;
|
|
7130
|
+
}
|
|
7131
|
+
return response.json();
|
|
7132
|
+
}),
|
|
7076
7133
|
providesTags: ['RbacPolicies'],
|
|
7077
7134
|
}),
|
|
7078
7135
|
//RBAC ROLES
|
|
@@ -7097,14 +7154,36 @@ const coreApiSlice = createApi({
|
|
|
7097
7154
|
invalidatesTags: ['RbacRoles'],
|
|
7098
7155
|
}),
|
|
7099
7156
|
getRbacRoleDetails: builder.query({
|
|
7100
|
-
...
|
|
7157
|
+
...buildEndpointFromService(SERVICES.DM, async (args) => {
|
|
7158
|
+
const queryParams = new URLSearchParams({ platform_key: args.platform_key });
|
|
7159
|
+
const queryString = queryParams.toString();
|
|
7160
|
+
const url = `${OpenAPI.BASE}/api/core/rbac/roles/${args.id}/?${queryString}`;
|
|
7161
|
+
const response = await fetch(url, {
|
|
7162
|
+
method: 'GET',
|
|
7163
|
+
headers: OpenAPI.HEADERS,
|
|
7164
|
+
});
|
|
7165
|
+
if (!response.ok) {
|
|
7166
|
+
const error = new Error('Failed to fetch RBAC role details');
|
|
7167
|
+
error.status = response.status;
|
|
7168
|
+
error.body = await response.text();
|
|
7169
|
+
throw error;
|
|
7170
|
+
}
|
|
7171
|
+
return response.json();
|
|
7172
|
+
}),
|
|
7101
7173
|
providesTags: ['RbacRoles'],
|
|
7102
7174
|
}),
|
|
7175
|
+
getRbacMentorAccessList: builder.query({
|
|
7176
|
+
...buildEndpointFromDmService(CoreService.coreRbacMentorAccessList),
|
|
7177
|
+
}),
|
|
7178
|
+
updateRbacMentorAccess: builder.mutation({
|
|
7179
|
+
...buildEndpointFromDmService(CoreService.coreRbacMentorAccessCreate),
|
|
7180
|
+
}),
|
|
7103
7181
|
}),
|
|
7104
7182
|
});
|
|
7105
7183
|
const { useGetRbacPermissionsMutation} = coreApiSlice;
|
|
7106
7184
|
|
|
7107
7185
|
const CORE_CUSTOM_REDUCER_PATH = 'coreCustomApiSlice';
|
|
7186
|
+
const CORE_FAKE_CUSTOM_REDUCER_PATH = 'coreFakeCustomApiSlice';
|
|
7108
7187
|
const PLATFORM_MEMBERSHIP_TAG = 'PlatformMembership';
|
|
7109
7188
|
const CORE_CUSTOM_ENDPOINTS = {
|
|
7110
7189
|
GET_PLATFORM_MEMBERSHIP: {
|
|
@@ -7138,7 +7217,13 @@ const CORE_CUSTOM_ENDPOINTS = {
|
|
|
7138
7217
|
DELETE_PLATFORM_IMAGE_ASSET: {
|
|
7139
7218
|
path: (platform_key, asset_id) => `/api/core/platforms/${platform_key}/public-image-assets/${asset_id}/`,
|
|
7140
7219
|
service: SERVICES.DM,
|
|
7141
|
-
}
|
|
7220
|
+
},
|
|
7221
|
+
GET_PUBLIC_PLATFORM_IMAGE_ASSET_FILE_URL: {
|
|
7222
|
+
path: (platform_key, asset_id) => `/api/core/platforms/${platform_key}/public-image-assets/${asset_id}/file/`,
|
|
7223
|
+
baseUrl: getServiceUrl(SERVICES.DM),
|
|
7224
|
+
service: SERVICES.DM,
|
|
7225
|
+
},
|
|
7226
|
+
};
|
|
7142
7227
|
|
|
7143
7228
|
createApi({
|
|
7144
7229
|
// TODO: replace to catalogSlice
|
|
@@ -7210,7 +7295,13 @@ createApi({
|
|
|
7210
7295
|
...buildEndpointFromDmService(AiAccountService.aiAccountOrgsIntegrationCredentialPartialUpdate),
|
|
7211
7296
|
}),
|
|
7212
7297
|
getConnectedServiceAuthUrl: builder.query({
|
|
7213
|
-
|
|
7298
|
+
queryFn: async (queryParams, api, extraOptions) => {
|
|
7299
|
+
const url = `/api/ai-account/connected-services/orgs/${queryParams.org}/users/${queryParams.userId}/${queryParams.provider}/${queryParams.service}/`;
|
|
7300
|
+
return iblFetchBaseQuery({
|
|
7301
|
+
url,
|
|
7302
|
+
service: SERVICES.DM,
|
|
7303
|
+
}, api, extraOptions);
|
|
7304
|
+
},
|
|
7214
7305
|
}),
|
|
7215
7306
|
connectedServicesCallback: builder.query({
|
|
7216
7307
|
queryFn: async (queryParams, api, extraOptions) => {
|
|
@@ -7304,10 +7395,11 @@ const stripeApiSlice = createApi({
|
|
|
7304
7395
|
providesTags: ['stripe-context'],
|
|
7305
7396
|
}),
|
|
7306
7397
|
getStripePricingPageSession: builder.query({
|
|
7307
|
-
query: ({ platform_key }) => ({
|
|
7398
|
+
query: ({ platform_key, params }) => ({
|
|
7308
7399
|
url: STRIPE_ENDPOINTS.GET_STRIPE_PRICING_PAGE_SESSION.path(platform_key),
|
|
7309
7400
|
service: STRIPE_ENDPOINTS.GET_STRIPE_PRICING_PAGE_SESSION.service,
|
|
7310
7401
|
method: 'GET',
|
|
7402
|
+
params,
|
|
7311
7403
|
}),
|
|
7312
7404
|
providesTags: ['stripe-context'],
|
|
7313
7405
|
}),
|
|
@@ -7342,7 +7434,7 @@ const sessionApiSlice = createApi({
|
|
|
7342
7434
|
}),
|
|
7343
7435
|
}),
|
|
7344
7436
|
});
|
|
7345
|
-
const { useCreateSessionIdMutation, useEditSessionMutation, } = sessionApiSlice;
|
|
7437
|
+
const { useCreateSessionIdMutation, useLazyGetSessionIdQuery, useEditSessionMutation, } = sessionApiSlice;
|
|
7346
7438
|
|
|
7347
7439
|
createApi({
|
|
7348
7440
|
reducerPath: 'datasetsApiSlice',
|
|
@@ -8279,6 +8371,12 @@ createApi({
|
|
|
8279
8371
|
});
|
|
8280
8372
|
|
|
8281
8373
|
const NOTIFICATIONS_CUSTOM_REDUCER_PATH = 'notificationsCustomApiSlice';
|
|
8374
|
+
const NOTIFICATIONS_CUSTOM_TAGS = {
|
|
8375
|
+
TEMPLATES: 'NOTIFICATIONS_CUSTOM_TEMPLATES',
|
|
8376
|
+
TEMPLATE_DETAILS: 'NOTIFICATIONS_CUSTOM_TEMPLATE_DETAILS',
|
|
8377
|
+
UPDATE_TEMPLATE: 'NOTIFICATIONS_CUSTOM_UPDATE_TEMPLATE',
|
|
8378
|
+
TOGGLE_TEMPLATE: 'NOTIFICATIONS_CUSTOM_TOGGLE_TEMPLATE',
|
|
8379
|
+
};
|
|
8282
8380
|
const NOTIFICATIONS_CUSTOM_ENDPOINTS = {
|
|
8283
8381
|
GET_TEMPLATES: {
|
|
8284
8382
|
service: SERVICES.DM,
|
|
@@ -8300,6 +8398,7 @@ const NOTIFICATIONS_CUSTOM_ENDPOINTS = {
|
|
|
8300
8398
|
|
|
8301
8399
|
createApi({
|
|
8302
8400
|
reducerPath: NOTIFICATIONS_CUSTOM_REDUCER_PATH,
|
|
8401
|
+
tagTypes: [...Object.values(NOTIFICATIONS_CUSTOM_TAGS)],
|
|
8303
8402
|
baseQuery: iblFetchBaseQuery,
|
|
8304
8403
|
endpoints: (builder) => ({
|
|
8305
8404
|
getTemplates: builder.query({
|
|
@@ -8309,6 +8408,7 @@ createApi({
|
|
|
8309
8408
|
service: NOTIFICATIONS_CUSTOM_ENDPOINTS.GET_TEMPLATES.service,
|
|
8310
8409
|
};
|
|
8311
8410
|
},
|
|
8411
|
+
providesTags: [NOTIFICATIONS_CUSTOM_TAGS.TEMPLATES],
|
|
8312
8412
|
}),
|
|
8313
8413
|
getTemplateDetails: builder.query({
|
|
8314
8414
|
query: (args) => {
|
|
@@ -8317,6 +8417,7 @@ createApi({
|
|
|
8317
8417
|
service: NOTIFICATIONS_CUSTOM_ENDPOINTS.GET_TEMPLATE_DETAILS.service,
|
|
8318
8418
|
};
|
|
8319
8419
|
},
|
|
8420
|
+
providesTags: [NOTIFICATIONS_CUSTOM_TAGS.TEMPLATE_DETAILS],
|
|
8320
8421
|
}),
|
|
8321
8422
|
updateTemplate: builder.mutation({
|
|
8322
8423
|
query: (args) => {
|
|
@@ -8327,6 +8428,7 @@ createApi({
|
|
|
8327
8428
|
body: args.template,
|
|
8328
8429
|
};
|
|
8329
8430
|
},
|
|
8431
|
+
invalidatesTags: [NOTIFICATIONS_CUSTOM_TAGS.TEMPLATE_DETAILS],
|
|
8330
8432
|
}),
|
|
8331
8433
|
toggleTemplate: builder.mutation({
|
|
8332
8434
|
query: (args) => {
|
|
@@ -8339,6 +8441,7 @@ createApi({
|
|
|
8339
8441
|
},
|
|
8340
8442
|
};
|
|
8341
8443
|
},
|
|
8444
|
+
invalidatesTags: [NOTIFICATIONS_CUSTOM_TAGS.TEMPLATES],
|
|
8342
8445
|
}),
|
|
8343
8446
|
}),
|
|
8344
8447
|
});
|
|
@@ -8619,7 +8722,7 @@ const CUSTOM_DOMAIN_QUERY_KEYS = {
|
|
|
8619
8722
|
CREATE_CUSTOM_DOMAIN: () => ['CREATE_CUSTOM_DOMAIN'],
|
|
8620
8723
|
};
|
|
8621
8724
|
|
|
8622
|
-
createApi({
|
|
8725
|
+
const customDomainApiSlice = createApi({
|
|
8623
8726
|
reducerPath: CUSTOM_DOMAIN_REDUCER_PATH,
|
|
8624
8727
|
baseQuery: iblFetchBaseQuery,
|
|
8625
8728
|
tagTypes: [...CUSTOM_DOMAIN_QUERY_KEYS.GET_CUSTOM_DOMAINS()],
|
|
@@ -8658,6 +8761,7 @@ createApi({
|
|
|
8658
8761
|
}),
|
|
8659
8762
|
}),
|
|
8660
8763
|
});
|
|
8764
|
+
const { useGetCustomDomainsQuery} = customDomainApiSlice;
|
|
8661
8765
|
|
|
8662
8766
|
const PLATFORM_CUSTOM_REDUCER_PATH = "platformCustomApiSlice";
|
|
8663
8767
|
const PLATFORM_CONFIGURATION_TAG = "PlatformConfiguration";
|
|
@@ -8720,7 +8824,7 @@ createApi({
|
|
|
8720
8824
|
const coreCustomApiSlice = createApi({
|
|
8721
8825
|
reducerPath: CORE_CUSTOM_REDUCER_PATH,
|
|
8722
8826
|
baseQuery: iblFetchBaseQuery,
|
|
8723
|
-
tagTypes: [PLATFORM_MEMBERSHIP_TAG],
|
|
8827
|
+
tagTypes: [PLATFORM_MEMBERSHIP_TAG, 'PlatformImageAssetFileUrl'],
|
|
8724
8828
|
endpoints: (builder) => ({
|
|
8725
8829
|
getPlatformMembership: builder.query({
|
|
8726
8830
|
query: ({ platform_key }) => ({
|
|
@@ -8793,6 +8897,19 @@ const coreCustomApiSlice = createApi({
|
|
|
8793
8897
|
});
|
|
8794
8898
|
const { useJoinTenantMutation} = coreCustomApiSlice;
|
|
8795
8899
|
|
|
8900
|
+
createApi({
|
|
8901
|
+
reducerPath: CORE_FAKE_CUSTOM_REDUCER_PATH,
|
|
8902
|
+
baseQuery: iblFakeBaseQuery,
|
|
8903
|
+
endpoints: (builder) => ({
|
|
8904
|
+
getPublicPlatformImageAssetFileUrl: builder.query({
|
|
8905
|
+
...buildEndpointFromService(SERVICES.DM, async (args) => {
|
|
8906
|
+
const url = `${OpenAPI.BASE}${CORE_CUSTOM_ENDPOINTS.GET_PUBLIC_PLATFORM_IMAGE_ASSET_FILE_URL.path(args.platform_key, args.asset_id)}`;
|
|
8907
|
+
return url;
|
|
8908
|
+
}),
|
|
8909
|
+
}),
|
|
8910
|
+
}),
|
|
8911
|
+
});
|
|
8912
|
+
|
|
8796
8913
|
const EDX_PROCTORING_ENDPOINTS = {
|
|
8797
8914
|
GET_EXAM_INFO: {
|
|
8798
8915
|
service: SERVICES.LMS,
|
|
@@ -9715,6 +9832,7 @@ const useSubscriptionHandlerV2 = (subscriptionFlow) => {
|
|
|
9715
9832
|
});
|
|
9716
9833
|
}
|
|
9717
9834
|
catch (error) {
|
|
9835
|
+
console.error("Error getting user active app:", JSON.stringify(error));
|
|
9718
9836
|
return null;
|
|
9719
9837
|
}
|
|
9720
9838
|
};
|
|
@@ -9761,6 +9879,7 @@ const useSubscriptionHandlerV2 = (subscriptionFlow) => {
|
|
|
9761
9879
|
return await getUserActiveApp();
|
|
9762
9880
|
}
|
|
9763
9881
|
catch (error) {
|
|
9882
|
+
console.error("Error updating trial status:", JSON.stringify(error));
|
|
9764
9883
|
return null;
|
|
9765
9884
|
}
|
|
9766
9885
|
};
|
|
@@ -9853,6 +9972,7 @@ const useSubscriptionHandlerV2 = (subscriptionFlow) => {
|
|
|
9853
9972
|
return stripeContext.payment_link_url;
|
|
9854
9973
|
}
|
|
9855
9974
|
catch (error) {
|
|
9975
|
+
console.error("Error getting top up URL:", JSON.stringify(error));
|
|
9856
9976
|
return null;
|
|
9857
9977
|
}
|
|
9858
9978
|
};
|
|
@@ -9926,6 +10046,7 @@ const useSubscriptionHandlerV2 = (subscriptionFlow) => {
|
|
|
9926
10046
|
return stripeCustomerPortal === null || stripeCustomerPortal === void 0 ? void 0 : stripeCustomerPortal.url;
|
|
9927
10047
|
}
|
|
9928
10048
|
catch (error) {
|
|
10049
|
+
console.error("Error getting billing URL:", JSON.stringify(error));
|
|
9929
10050
|
return null;
|
|
9930
10051
|
}
|
|
9931
10052
|
};
|
|
@@ -9971,7 +10092,10 @@ const useSubscriptionHandlerV2 = (subscriptionFlow) => {
|
|
|
9971
10092
|
try {
|
|
9972
10093
|
subscriptionFlow.handleBeforePricingPageDisplayFlow();
|
|
9973
10094
|
const { data: stripeContext } = await getStripePricingPageSession({
|
|
9974
|
-
platform_key: subscriptionFlow.
|
|
10095
|
+
platform_key: subscriptionFlow.getMainTenantKey(),
|
|
10096
|
+
params: {
|
|
10097
|
+
source_platform_key: subscriptionFlow.getCurrentTenantKey(),
|
|
10098
|
+
},
|
|
9975
10099
|
}, false);
|
|
9976
10100
|
if (isStripeContextError ||
|
|
9977
10101
|
!stripeContext ||
|
|
@@ -9984,6 +10108,7 @@ const useSubscriptionHandlerV2 = (subscriptionFlow) => {
|
|
|
9984
10108
|
}, !hasCredits);
|
|
9985
10109
|
}
|
|
9986
10110
|
catch (error) {
|
|
10111
|
+
console.error("Error getting stripe pricing page session:", JSON.stringify(error));
|
|
9987
10112
|
subscriptionFlow.handleFailureOnPaymentFlow();
|
|
9988
10113
|
}
|
|
9989
10114
|
};
|
|
@@ -10305,6 +10430,299 @@ const formatRelativeTime = (timestamp) => {
|
|
|
10305
10430
|
return `${diffInYears} year${diffInYears === 1 ? "" : "s"} ago`;
|
|
10306
10431
|
};
|
|
10307
10432
|
|
|
10433
|
+
/**
|
|
10434
|
+
* Authentication and Authorization Utilities
|
|
10435
|
+
*
|
|
10436
|
+
* This module provides utility functions for handling authentication flows,
|
|
10437
|
+
* including redirects to auth SPA, cookie management, and session handling.
|
|
10438
|
+
*/
|
|
10439
|
+
/**
|
|
10440
|
+
* Check if the current window is inside an iframe
|
|
10441
|
+
* @returns {boolean} True if running in an iframe, false otherwise
|
|
10442
|
+
*/
|
|
10443
|
+
function isInIframe() {
|
|
10444
|
+
if (typeof window === "undefined") {
|
|
10445
|
+
return false;
|
|
10446
|
+
}
|
|
10447
|
+
return (window === null || window === void 0 ? void 0 : window.self) !== (window === null || window === void 0 ? void 0 : window.top);
|
|
10448
|
+
}
|
|
10449
|
+
/**
|
|
10450
|
+
* Send a message to the parent website (when in iframe)
|
|
10451
|
+
* @param payload - The data to send to parent window
|
|
10452
|
+
*/
|
|
10453
|
+
function sendMessageToParentWebsite(payload) {
|
|
10454
|
+
window.parent.postMessage(payload, "*");
|
|
10455
|
+
}
|
|
10456
|
+
/**
|
|
10457
|
+
* Delete a cookie with specific name, path, and domain
|
|
10458
|
+
* @param name - Cookie name
|
|
10459
|
+
* @param path - Cookie path
|
|
10460
|
+
* @param domain - Cookie domain
|
|
10461
|
+
*/
|
|
10462
|
+
function deleteCookie(name, path, domain) {
|
|
10463
|
+
const expires = "expires=Thu, 01 Jan 1970 00:00:00 UTC;";
|
|
10464
|
+
const cookieValue = `${name}=;`;
|
|
10465
|
+
const pathValue = path ? `path=${path};` : "";
|
|
10466
|
+
const domainValue = domain ? `domain=${domain};` : "";
|
|
10467
|
+
document.cookie = cookieValue + expires + pathValue + domainValue;
|
|
10468
|
+
}
|
|
10469
|
+
/**
|
|
10470
|
+
* Get all possible domain parts for cookie deletion
|
|
10471
|
+
* @param domain - The domain to split
|
|
10472
|
+
* @returns Array of domain parts
|
|
10473
|
+
* @example
|
|
10474
|
+
* getDomainParts('app.example.com') // returns ['app.example.com', 'example.com', 'com']
|
|
10475
|
+
*/
|
|
10476
|
+
function getDomainParts(domain) {
|
|
10477
|
+
const parts = domain.split(".");
|
|
10478
|
+
const domains = [];
|
|
10479
|
+
for (let i = parts.length - 1; i >= 0; i--) {
|
|
10480
|
+
domains.push(parts.slice(i).join("."));
|
|
10481
|
+
}
|
|
10482
|
+
return domains;
|
|
10483
|
+
}
|
|
10484
|
+
/**
|
|
10485
|
+
* Delete a cookie across all possible domain variations
|
|
10486
|
+
* @param name - Cookie name to delete
|
|
10487
|
+
* @param childDomain - The current domain
|
|
10488
|
+
*/
|
|
10489
|
+
function deleteCookieOnAllDomains(name, childDomain) {
|
|
10490
|
+
getDomainParts(childDomain).forEach((domainPart) => {
|
|
10491
|
+
deleteCookie(name, "/", domainPart);
|
|
10492
|
+
deleteCookie(name, "", domainPart);
|
|
10493
|
+
});
|
|
10494
|
+
}
|
|
10495
|
+
/**
|
|
10496
|
+
* Get the parent domain from a given domain
|
|
10497
|
+
* @param domain - The domain to process
|
|
10498
|
+
* @returns The parent domain (e.g., 'app.example.com' → '.example.com')
|
|
10499
|
+
*/
|
|
10500
|
+
function getParentDomain(domain) {
|
|
10501
|
+
if (!domain) {
|
|
10502
|
+
return "";
|
|
10503
|
+
}
|
|
10504
|
+
const parts = domain.split(".");
|
|
10505
|
+
return parts.length > 1 ? `.${parts.slice(-2).join(".")}` : domain;
|
|
10506
|
+
}
|
|
10507
|
+
/**
|
|
10508
|
+
* Set a cookie for authentication with cross-domain support
|
|
10509
|
+
* @param name - Cookie name
|
|
10510
|
+
* @param value - Cookie value
|
|
10511
|
+
* @param days - Number of days until expiration (default: 365)
|
|
10512
|
+
*/
|
|
10513
|
+
function setCookieForAuth(name, value, days = 365) {
|
|
10514
|
+
const expires = new Date();
|
|
10515
|
+
expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000);
|
|
10516
|
+
const hostname = window.location.hostname;
|
|
10517
|
+
let baseDomain = hostname;
|
|
10518
|
+
// Calculate base domain (skip for localhost and IP addresses)
|
|
10519
|
+
if (hostname !== "localhost" && !/^\d+\.\d+\.\d+\.\d+$/.test(hostname)) {
|
|
10520
|
+
const parts = hostname.split(".");
|
|
10521
|
+
if (parts.length > 2) {
|
|
10522
|
+
baseDomain = `.${parts.slice(-2).join(".")}`;
|
|
10523
|
+
}
|
|
10524
|
+
}
|
|
10525
|
+
const domainAttr = baseDomain ? `;domain=${baseDomain}` : "";
|
|
10526
|
+
document.cookie = `${name}=${encodeURIComponent(value)};expires=${expires.toUTCString()};path=/;SameSite=None;Secure${domainAttr}`;
|
|
10527
|
+
}
|
|
10528
|
+
/**
|
|
10529
|
+
* Clear all cookies for the current domain
|
|
10530
|
+
*/
|
|
10531
|
+
function clearCookies() {
|
|
10532
|
+
const cookies = document.cookie.split(";");
|
|
10533
|
+
for (let i = 0; i < cookies.length; i++) {
|
|
10534
|
+
const cookie = cookies[i];
|
|
10535
|
+
const eqPos = cookie.indexOf("=");
|
|
10536
|
+
const name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;
|
|
10537
|
+
deleteCookieOnAllDomains(name, window.location.hostname);
|
|
10538
|
+
document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/;Domain=${getParentDomain(window.location.hostname)}`;
|
|
10539
|
+
}
|
|
10540
|
+
}
|
|
10541
|
+
/**
|
|
10542
|
+
* Check if user is currently logged in
|
|
10543
|
+
* @param tokenKey - The localStorage key for the auth token (default: 'axd_token')
|
|
10544
|
+
* @returns True if logged in, false otherwise
|
|
10545
|
+
*/
|
|
10546
|
+
function isLoggedIn(tokenKey = "axd_token") {
|
|
10547
|
+
return !!localStorage.getItem(tokenKey);
|
|
10548
|
+
}
|
|
10549
|
+
/**
|
|
10550
|
+
* Extract platform/tenant key from URL
|
|
10551
|
+
* @param url - The URL to parse
|
|
10552
|
+
* @param pattern - RegExp pattern to match platform key (default matches /platform/[key]/...)
|
|
10553
|
+
* @returns The platform key or null if not found
|
|
10554
|
+
*/
|
|
10555
|
+
function getPlatformKey(url, pattern = /\/platform\/([^/]+)/) {
|
|
10556
|
+
const match = url.match(pattern);
|
|
10557
|
+
return match ? match[1] : null;
|
|
10558
|
+
}
|
|
10559
|
+
/**
|
|
10560
|
+
* Redirect to authentication SPA for login/logout
|
|
10561
|
+
*
|
|
10562
|
+
* This function handles the complete authentication flow:
|
|
10563
|
+
* - Clears localStorage and cookies on logout
|
|
10564
|
+
* - Saves redirect path for post-auth return
|
|
10565
|
+
* - Handles iframe scenarios
|
|
10566
|
+
* - Syncs logout across multiple SPAs via cookies
|
|
10567
|
+
*
|
|
10568
|
+
* @param options - Configuration options for the redirect
|
|
10569
|
+
*
|
|
10570
|
+
* @example
|
|
10571
|
+
* ```tsx
|
|
10572
|
+
* // Basic usage
|
|
10573
|
+
* redirectToAuthSpa({
|
|
10574
|
+
* authUrl: 'https://auth.example.com',
|
|
10575
|
+
* appName: 'mentor',
|
|
10576
|
+
* });
|
|
10577
|
+
*
|
|
10578
|
+
* // With logout
|
|
10579
|
+
* redirectToAuthSpa({
|
|
10580
|
+
* authUrl: 'https://auth.example.com',
|
|
10581
|
+
* appName: 'mentor',
|
|
10582
|
+
* logout: true,
|
|
10583
|
+
* platformKey: 'my-tenant',
|
|
10584
|
+
* });
|
|
10585
|
+
*
|
|
10586
|
+
* // With custom redirect
|
|
10587
|
+
* redirectToAuthSpa({
|
|
10588
|
+
* authUrl: 'https://auth.example.com',
|
|
10589
|
+
* appName: 'mentor',
|
|
10590
|
+
* redirectTo: '/dashboard',
|
|
10591
|
+
* platformKey: 'my-tenant',
|
|
10592
|
+
* });
|
|
10593
|
+
* ```
|
|
10594
|
+
*/
|
|
10595
|
+
async function redirectToAuthSpa(options) {
|
|
10596
|
+
const { redirectTo, platformKey, logout = false, saveRedirect = true, authUrl, appName, queryParams = {
|
|
10597
|
+
app: "app",
|
|
10598
|
+
redirectTo: "redirect-to",
|
|
10599
|
+
tenant: "tenant",
|
|
10600
|
+
}, redirectPathStorageKey = "redirect_to", cookieNames = {
|
|
10601
|
+
currentTenant: "ibl_current_tenant",
|
|
10602
|
+
userData: "ibl_user_data",
|
|
10603
|
+
tenant: "ibl_tenant",
|
|
10604
|
+
logoutTimestamp: "ibl_logout_timestamp",
|
|
10605
|
+
}, } = options;
|
|
10606
|
+
// Clear localStorage
|
|
10607
|
+
localStorage.clear();
|
|
10608
|
+
if (logout) {
|
|
10609
|
+
// Delete authentication cookies for cross-SPA synchronization
|
|
10610
|
+
const currentDomain = window.location.hostname;
|
|
10611
|
+
if (cookieNames.currentTenant) {
|
|
10612
|
+
deleteCookieOnAllDomains(cookieNames.currentTenant, currentDomain);
|
|
10613
|
+
}
|
|
10614
|
+
if (cookieNames.userData) {
|
|
10615
|
+
deleteCookieOnAllDomains(cookieNames.userData, currentDomain);
|
|
10616
|
+
}
|
|
10617
|
+
if (cookieNames.tenant) {
|
|
10618
|
+
deleteCookieOnAllDomains(cookieNames.tenant, currentDomain);
|
|
10619
|
+
}
|
|
10620
|
+
// Set logout timestamp cookie to trigger logout on other SPAs
|
|
10621
|
+
if (cookieNames.logoutTimestamp) {
|
|
10622
|
+
setCookieForAuth(cookieNames.logoutTimestamp, Date.now().toString());
|
|
10623
|
+
}
|
|
10624
|
+
}
|
|
10625
|
+
// Handle iframe scenario
|
|
10626
|
+
if (isInIframe()) {
|
|
10627
|
+
console.log("[redirectToAuthSpa]: sending authExpired to parent");
|
|
10628
|
+
sendMessageToParentWebsite({ authExpired: true });
|
|
10629
|
+
return;
|
|
10630
|
+
}
|
|
10631
|
+
const redirectPath = redirectTo !== null && redirectTo !== void 0 ? redirectTo : `${window.location.pathname}${window.location.search}`;
|
|
10632
|
+
// Never save sso-login routes as redirect paths
|
|
10633
|
+
if (!redirectPath.startsWith("/sso-login") && saveRedirect) {
|
|
10634
|
+
window.localStorage.setItem(redirectPathStorageKey, redirectPath);
|
|
10635
|
+
}
|
|
10636
|
+
const platform = platformKey !== null && platformKey !== void 0 ? platformKey : getPlatformKey(redirectPath);
|
|
10637
|
+
const redirectToUrl = `${window.location.origin}`;
|
|
10638
|
+
let authRedirectUrl = `${authUrl}/login?${queryParams.app}=${appName}`;
|
|
10639
|
+
authRedirectUrl += `&${queryParams.redirectTo}=${redirectToUrl}`;
|
|
10640
|
+
if (platform) {
|
|
10641
|
+
authRedirectUrl += `&${queryParams.tenant}=${platform}`;
|
|
10642
|
+
}
|
|
10643
|
+
if (logout) {
|
|
10644
|
+
authRedirectUrl += "&logout=1";
|
|
10645
|
+
}
|
|
10646
|
+
// Small delay for any pending operations
|
|
10647
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
10648
|
+
// Redirect to auth SPA
|
|
10649
|
+
window.location.href = authRedirectUrl;
|
|
10650
|
+
}
|
|
10651
|
+
/**
|
|
10652
|
+
* Get the URL for joining a tenant (sign up flow)
|
|
10653
|
+
* @param authUrl - Auth SPA base URL
|
|
10654
|
+
* @param tenantKey - Tenant to join
|
|
10655
|
+
* @param redirectUrl - URL to redirect to after joining (defaults to current URL)
|
|
10656
|
+
* @returns The join URL
|
|
10657
|
+
*/
|
|
10658
|
+
function getAuthSpaJoinUrl(authUrl, tenantKey, redirectUrl) {
|
|
10659
|
+
const resolvedTenant = tenantKey || getPlatformKey(window.location.pathname) || "";
|
|
10660
|
+
if (!resolvedTenant) {
|
|
10661
|
+
return "";
|
|
10662
|
+
}
|
|
10663
|
+
const targetUrl = redirectUrl !== null && redirectUrl !== void 0 ? redirectUrl : window.location.href;
|
|
10664
|
+
const joinUrl = `${authUrl}/join?tenant=${encodeURIComponent(resolvedTenant)}&redirect-to=${encodeURIComponent(targetUrl)}`;
|
|
10665
|
+
return joinUrl;
|
|
10666
|
+
}
|
|
10667
|
+
/**
|
|
10668
|
+
* Redirect to auth SPA's join/signup page for a specific tenant
|
|
10669
|
+
* @param authUrl - Auth SPA base URL
|
|
10670
|
+
* @param tenantKey - Tenant to join
|
|
10671
|
+
* @param redirectUrl - URL to redirect to after joining (defaults to current URL)
|
|
10672
|
+
*/
|
|
10673
|
+
function redirectToAuthSpaJoinTenant(authUrl, tenantKey, redirectUrl) {
|
|
10674
|
+
const resolvedTenant = tenantKey || getPlatformKey(window.location.pathname) || "";
|
|
10675
|
+
if (!resolvedTenant) {
|
|
10676
|
+
console.log("[auth-redirect] Missing tenant key for join", {
|
|
10677
|
+
tenantKey,
|
|
10678
|
+
redirectUrl,
|
|
10679
|
+
});
|
|
10680
|
+
redirectToAuthSpa({
|
|
10681
|
+
authUrl,
|
|
10682
|
+
appName: "app", // Will need to be configured
|
|
10683
|
+
redirectTo: redirectUrl,
|
|
10684
|
+
});
|
|
10685
|
+
return;
|
|
10686
|
+
}
|
|
10687
|
+
const targetUrl = redirectUrl !== null && redirectUrl !== void 0 ? redirectUrl : window.location.href;
|
|
10688
|
+
const joinUrl = `${authUrl}/join?tenant=${encodeURIComponent(resolvedTenant)}&redirect-to=${encodeURIComponent(targetUrl)}`;
|
|
10689
|
+
window.location.href = joinUrl;
|
|
10690
|
+
}
|
|
10691
|
+
/**
|
|
10692
|
+
* Handle user logout
|
|
10693
|
+
*
|
|
10694
|
+
* This function:
|
|
10695
|
+
* - Clears localStorage (preserving tenant)
|
|
10696
|
+
* - Sets logout timestamp cookie for cross-SPA sync
|
|
10697
|
+
* - Clears all cookies
|
|
10698
|
+
* - Redirects to auth SPA logout endpoint
|
|
10699
|
+
*
|
|
10700
|
+
* @param options - Logout configuration options
|
|
10701
|
+
*
|
|
10702
|
+
* @example
|
|
10703
|
+
* ```tsx
|
|
10704
|
+
* handleLogout({
|
|
10705
|
+
* authUrl: 'https://auth.example.com',
|
|
10706
|
+
* redirectUrl: 'https://app.example.com',
|
|
10707
|
+
* });
|
|
10708
|
+
* ```
|
|
10709
|
+
*/
|
|
10710
|
+
function handleLogout(options) {
|
|
10711
|
+
const { redirectUrl = window.location.origin, authUrl, tenantStorageKey = "tenant", logoutTimestampCookie = "ibl_logout_timestamp", callback, } = options;
|
|
10712
|
+
const tenant = window.localStorage.getItem(tenantStorageKey);
|
|
10713
|
+
window.localStorage.clear();
|
|
10714
|
+
if (tenant) {
|
|
10715
|
+
window.localStorage.setItem(tenantStorageKey, tenant);
|
|
10716
|
+
}
|
|
10717
|
+
// Set logout timestamp cookie to trigger logout on other SPAs
|
|
10718
|
+
setCookieForAuth(logoutTimestampCookie, Date.now().toString());
|
|
10719
|
+
clearCookies();
|
|
10720
|
+
callback === null || callback === void 0 ? void 0 : callback();
|
|
10721
|
+
if (!isInIframe()) {
|
|
10722
|
+
window.location.href = `${authUrl}/logout?redirect-to=${redirectUrl}${tenant ? "&tenant=" + tenant : ""}`;
|
|
10723
|
+
}
|
|
10724
|
+
}
|
|
10725
|
+
|
|
10308
10726
|
const useExternalPricingPlan = ({ pricingModalData, userEmail, }) => {
|
|
10309
10727
|
const pricingBoxIframeRef = useRef(null);
|
|
10310
10728
|
const getIFrameReadyData = async () => {
|
|
@@ -10436,6 +10854,8 @@ function jwtDecode(token, options) {
|
|
|
10436
10854
|
* - Polls for cookie changes every 2 seconds
|
|
10437
10855
|
* - Refreshes the page when cross-SPA changes are detected
|
|
10438
10856
|
* - Listens for storage events to update cookies when localStorage changes
|
|
10857
|
+
* - Monitors logout timestamp cookie to trigger cross-SPA logout
|
|
10858
|
+
* - Automatically logs out when another SPA initiates logout
|
|
10439
10859
|
*
|
|
10440
10860
|
* For React Native:
|
|
10441
10861
|
* - Relies on AsyncStorage only (handled by StorageService)
|
|
@@ -10445,7 +10865,7 @@ function jwtDecode(token, options) {
|
|
|
10445
10865
|
/**
|
|
10446
10866
|
* Check if we're running in a web browser environment
|
|
10447
10867
|
*/
|
|
10448
|
-
const isWeb = () => {
|
|
10868
|
+
const isWeb$1 = () => {
|
|
10449
10869
|
return typeof window !== "undefined" && typeof document !== "undefined";
|
|
10450
10870
|
};
|
|
10451
10871
|
/**
|
|
@@ -10455,6 +10875,7 @@ const COOKIE_KEYS = {
|
|
|
10455
10875
|
CURRENT_TENANT: "ibl_current_tenant",
|
|
10456
10876
|
USER_DATA: "ibl_user_data",
|
|
10457
10877
|
TENANT: "ibl_tenant",
|
|
10878
|
+
LOGOUT_TIMESTAMP: "ibl_logout_timestamp",
|
|
10458
10879
|
};
|
|
10459
10880
|
/**
|
|
10460
10881
|
* Get the base domain for cookie sharing
|
|
@@ -10465,7 +10886,7 @@ const COOKIE_KEYS = {
|
|
|
10465
10886
|
*/
|
|
10466
10887
|
const getBaseDomain = () => {
|
|
10467
10888
|
// Must check for window existence before accessing it
|
|
10468
|
-
if (!isWeb())
|
|
10889
|
+
if (!isWeb$1())
|
|
10469
10890
|
return "";
|
|
10470
10891
|
const hostname = window.location.hostname;
|
|
10471
10892
|
// For localhost or IP addresses, use as-is
|
|
@@ -10494,7 +10915,7 @@ const CookieUtils = {
|
|
|
10494
10915
|
* Uses SameSite=None for cross-subdomain sharing and base domain
|
|
10495
10916
|
*/
|
|
10496
10917
|
set(name, value, days = 365) {
|
|
10497
|
-
if (!isWeb())
|
|
10918
|
+
if (!isWeb$1())
|
|
10498
10919
|
return;
|
|
10499
10920
|
const expires = new Date();
|
|
10500
10921
|
expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000);
|
|
@@ -10506,7 +10927,7 @@ const CookieUtils = {
|
|
|
10506
10927
|
* Get a cookie value by name
|
|
10507
10928
|
*/
|
|
10508
10929
|
get(name) {
|
|
10509
|
-
if (!isWeb())
|
|
10930
|
+
if (!isWeb$1())
|
|
10510
10931
|
return null;
|
|
10511
10932
|
const nameEQ = name + "=";
|
|
10512
10933
|
const cookies = document.cookie.split(";");
|
|
@@ -10525,7 +10946,7 @@ const CookieUtils = {
|
|
|
10525
10946
|
* Uses same domain logic as set() to ensure proper deletion
|
|
10526
10947
|
*/
|
|
10527
10948
|
delete(name) {
|
|
10528
|
-
if (!isWeb())
|
|
10949
|
+
if (!isWeb$1())
|
|
10529
10950
|
return;
|
|
10530
10951
|
const baseDomain = getBaseDomain();
|
|
10531
10952
|
const domainAttr = baseDomain ? `;domain=${baseDomain}` : "";
|
|
@@ -10538,8 +10959,7 @@ const CookieUtils = {
|
|
|
10538
10959
|
* On React Native, this is a no-op
|
|
10539
10960
|
*/
|
|
10540
10961
|
async function syncAuthToCookies(storageService) {
|
|
10541
|
-
|
|
10542
|
-
if (!isWeb())
|
|
10962
|
+
if (!isWeb$1())
|
|
10543
10963
|
return;
|
|
10544
10964
|
try {
|
|
10545
10965
|
const currentTenant = await storageService.getItem(LOCAL_STORAGE_KEYS.CURRENT_TENANT);
|
|
@@ -10568,13 +10988,23 @@ async function syncAuthToCookies(storageService) {
|
|
|
10568
10988
|
console.error("[syncAuthToCookies] Error syncing to cookies:", error);
|
|
10569
10989
|
}
|
|
10570
10990
|
}
|
|
10991
|
+
/**
|
|
10992
|
+
* Clear current tenant cookie only (web only)
|
|
10993
|
+
* Should be called before tenant switching
|
|
10994
|
+
* On React Native, this is a no-op
|
|
10995
|
+
*/
|
|
10996
|
+
function clearCurrentTenantCookie() {
|
|
10997
|
+
if (!isWeb$1())
|
|
10998
|
+
return;
|
|
10999
|
+
CookieUtils.delete(COOKIE_KEYS.CURRENT_TENANT);
|
|
11000
|
+
}
|
|
10571
11001
|
/**
|
|
10572
11002
|
* Clear all authentication cookies (web only)
|
|
10573
11003
|
* Should be called on logout
|
|
10574
11004
|
* On React Native, this is a no-op
|
|
10575
11005
|
*/
|
|
10576
11006
|
function clearAuthCookies() {
|
|
10577
|
-
if (!isWeb())
|
|
11007
|
+
if (!isWeb$1())
|
|
10578
11008
|
return;
|
|
10579
11009
|
CookieUtils.delete(COOKIE_KEYS.CURRENT_TENANT);
|
|
10580
11010
|
CookieUtils.delete(COOKIE_KEYS.USER_DATA);
|
|
@@ -10586,14 +11016,30 @@ function clearAuthCookies() {
|
|
|
10586
11016
|
* On React Native, always returns false (no-op)
|
|
10587
11017
|
*/
|
|
10588
11018
|
async function syncCookiesToLocalStorage(storageService) {
|
|
10589
|
-
if (!isWeb())
|
|
11019
|
+
if (!isWeb$1())
|
|
10590
11020
|
return false;
|
|
10591
11021
|
try {
|
|
10592
11022
|
let needsRefresh = false;
|
|
10593
11023
|
// Check current_tenant
|
|
10594
11024
|
const cookieCurrentTenant = CookieUtils.get(COOKIE_KEYS.CURRENT_TENANT);
|
|
11025
|
+
console.log("[syncCookiesToLocalStorage] cookieCurrentTenant", cookieCurrentTenant);
|
|
10595
11026
|
const localCurrentTenant = await storageService.getItem(LOCAL_STORAGE_KEYS.CURRENT_TENANT);
|
|
10596
|
-
|
|
11027
|
+
console.log("[syncCookiesToLocalStorage] localCurrentTenant", localCurrentTenant);
|
|
11028
|
+
// Compare current tenant objects by key field only to avoid false positives from extra fields
|
|
11029
|
+
let currentTenantIsDifferent = false;
|
|
11030
|
+
if (cookieCurrentTenant && localCurrentTenant) {
|
|
11031
|
+
try {
|
|
11032
|
+
const cookieTenant = JSON.parse(cookieCurrentTenant);
|
|
11033
|
+
const localTenant = JSON.parse(localCurrentTenant);
|
|
11034
|
+
// Compare by the tenant key only
|
|
11035
|
+
currentTenantIsDifferent = cookieTenant.key !== localTenant.key;
|
|
11036
|
+
}
|
|
11037
|
+
catch (e) {
|
|
11038
|
+
// If parsing fails, fall back to string comparison
|
|
11039
|
+
currentTenantIsDifferent = cookieCurrentTenant !== localCurrentTenant;
|
|
11040
|
+
}
|
|
11041
|
+
}
|
|
11042
|
+
if (currentTenantIsDifferent) {
|
|
10597
11043
|
if (cookieCurrentTenant) {
|
|
10598
11044
|
await storageService.setItem(LOCAL_STORAGE_KEYS.CURRENT_TENANT, cookieCurrentTenant);
|
|
10599
11045
|
}
|
|
@@ -10605,8 +11051,24 @@ async function syncCookiesToLocalStorage(storageService) {
|
|
|
10605
11051
|
}
|
|
10606
11052
|
// Check userData
|
|
10607
11053
|
const cookieUserData = CookieUtils.get(COOKIE_KEYS.USER_DATA);
|
|
11054
|
+
console.log("[syncCookiesToLocalStorage] cookieUserData", cookieUserData);
|
|
10608
11055
|
const localUserData = await storageService.getItem(LOCAL_STORAGE_KEYS.USER_DATA);
|
|
10609
|
-
|
|
11056
|
+
console.log("[syncCookiesToLocalStorage] localUserData", localUserData);
|
|
11057
|
+
// Compare userData objects by user_id to avoid false positives from extra fields
|
|
11058
|
+
let userDataIsDifferent = false;
|
|
11059
|
+
if (cookieUserData && localUserData) {
|
|
11060
|
+
try {
|
|
11061
|
+
const cookieUser = JSON.parse(cookieUserData);
|
|
11062
|
+
const localUser = JSON.parse(localUserData);
|
|
11063
|
+
// Compare by user_id - the primary identifier
|
|
11064
|
+
userDataIsDifferent = cookieUser.user_id !== localUser.user_id;
|
|
11065
|
+
}
|
|
11066
|
+
catch (e) {
|
|
11067
|
+
// If parsing fails, fall back to string comparison
|
|
11068
|
+
userDataIsDifferent = cookieUserData !== localUserData;
|
|
11069
|
+
}
|
|
11070
|
+
}
|
|
11071
|
+
if (userDataIsDifferent) {
|
|
10610
11072
|
if (cookieUserData) {
|
|
10611
11073
|
await storageService.setItem(LOCAL_STORAGE_KEYS.USER_DATA, cookieUserData);
|
|
10612
11074
|
}
|
|
@@ -10618,8 +11080,37 @@ async function syncCookiesToLocalStorage(storageService) {
|
|
|
10618
11080
|
}
|
|
10619
11081
|
// Check tenant
|
|
10620
11082
|
const cookieTenant = CookieUtils.get(COOKIE_KEYS.TENANT);
|
|
11083
|
+
console.log("[syncCookiesToLocalStorage] cookieTenant", cookieTenant);
|
|
10621
11084
|
const localTenant = await storageService.getItem(LOCAL_STORAGE_KEYS.TENANTS);
|
|
10622
|
-
|
|
11085
|
+
console.log("[syncCookiesToLocalStorage] localTenant", localTenant);
|
|
11086
|
+
// Compare tenant arrays by checking length and tenant keys
|
|
11087
|
+
let tenantsAreDifferent = false;
|
|
11088
|
+
if (cookieTenant &&
|
|
11089
|
+
localTenant &&
|
|
11090
|
+
cookieTenant !== "[]" &&
|
|
11091
|
+
localTenant !== "[]") {
|
|
11092
|
+
try {
|
|
11093
|
+
const cookieTenantsArray = JSON.parse(cookieTenant);
|
|
11094
|
+
const localTenantsArray = JSON.parse(localTenant);
|
|
11095
|
+
// Check if arrays have same length
|
|
11096
|
+
if (cookieTenantsArray.length !== localTenantsArray.length) {
|
|
11097
|
+
tenantsAreDifferent = true;
|
|
11098
|
+
}
|
|
11099
|
+
else {
|
|
11100
|
+
// Check if all tenant keys match
|
|
11101
|
+
const cookieKeys = new Set(cookieTenantsArray.map((t) => t.key));
|
|
11102
|
+
const localKeys = new Set(localTenantsArray.map((t) => t.key));
|
|
11103
|
+
tenantsAreDifferent =
|
|
11104
|
+
cookieKeys.size !== localKeys.size ||
|
|
11105
|
+
[...cookieKeys].some((key) => !localKeys.has(key));
|
|
11106
|
+
}
|
|
11107
|
+
}
|
|
11108
|
+
catch (e) {
|
|
11109
|
+
// If parsing fails, fall back to string comparison
|
|
11110
|
+
tenantsAreDifferent = cookieTenant !== localTenant;
|
|
11111
|
+
}
|
|
11112
|
+
}
|
|
11113
|
+
if (tenantsAreDifferent) {
|
|
10623
11114
|
if (cookieTenant) {
|
|
10624
11115
|
await storageService.setItem(LOCAL_STORAGE_KEYS.TENANTS, cookieTenant);
|
|
10625
11116
|
}
|
|
@@ -10674,6 +11165,7 @@ async function isJwtTokenExpired(storageService) {
|
|
|
10674
11165
|
async function validateJwtToken(storageService) {
|
|
10675
11166
|
try {
|
|
10676
11167
|
const edxJwtToken = await storageService.getItem(LOCAL_STORAGE_KEYS.EDX_TOKEN_KEY);
|
|
11168
|
+
console.log("[AuthProvider] JWT token ", edxJwtToken);
|
|
10677
11169
|
const userData = await storageService.getItem(LOCAL_STORAGE_KEYS.USER_DATA);
|
|
10678
11170
|
if (!edxJwtToken || !userData) {
|
|
10679
11171
|
return false;
|
|
@@ -10696,7 +11188,9 @@ async function validateJwtToken(storageService) {
|
|
|
10696
11188
|
function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure, redirectToAuthSpa, hasNonExpiredAuthToken, username, pathname, storageService, skipAuthCheck, token, }) {
|
|
10697
11189
|
const [isAuthenticating, setIsAuthenticating] = useState(true);
|
|
10698
11190
|
const [userIsAccessingPublicRoute, setUserIsAccessingPublicRoute] = useState(false);
|
|
11191
|
+
const [initialSyncComplete, setInitialSyncComplete] = useState(false);
|
|
10699
11192
|
const cookieCheckIntervalRef = useRef(null);
|
|
11193
|
+
const lastLogoutTimestampRef = useRef(null);
|
|
10700
11194
|
// RTK Query hook for refreshing JWT token
|
|
10701
11195
|
const [refreshJwtToken] = useLazyRefreshJwtTokenQuery();
|
|
10702
11196
|
/**
|
|
@@ -10705,24 +11199,65 @@ function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure,
|
|
|
10705
11199
|
* On React Native, this is a no-op
|
|
10706
11200
|
*/
|
|
10707
11201
|
useEffect(() => {
|
|
10708
|
-
|
|
10709
|
-
|
|
11202
|
+
if (!storageService || !isWeb$1()) {
|
|
11203
|
+
// If no storage service or not web, mark sync as complete immediately
|
|
11204
|
+
setInitialSyncComplete(true);
|
|
10710
11205
|
return;
|
|
11206
|
+
}
|
|
10711
11207
|
// Initial sync on mount
|
|
10712
11208
|
async function initialSync() {
|
|
10713
|
-
|
|
10714
|
-
|
|
10715
|
-
|
|
10716
|
-
|
|
11209
|
+
try {
|
|
11210
|
+
// Initialize last known logout timestamp
|
|
11211
|
+
lastLogoutTimestampRef.current = CookieUtils.get(COOKIE_KEYS.LOGOUT_TIMESTAMP);
|
|
11212
|
+
const needsRefresh = await syncCookiesToLocalStorage(storageService);
|
|
11213
|
+
if (needsRefresh) {
|
|
11214
|
+
console.log("[auth-redirect] Cookie sync detected changes, refreshing page");
|
|
11215
|
+
redirectToAuthSpa(undefined, undefined, false, false);
|
|
11216
|
+
}
|
|
11217
|
+
else {
|
|
11218
|
+
await syncAuthToCookies(storageService);
|
|
11219
|
+
}
|
|
11220
|
+
}
|
|
11221
|
+
finally {
|
|
11222
|
+
// Mark initial sync as complete
|
|
11223
|
+
setInitialSyncComplete(true);
|
|
10717
11224
|
}
|
|
10718
11225
|
}
|
|
10719
11226
|
initialSync();
|
|
10720
11227
|
// Poll for cookie changes every 2 seconds to detect cross-SPA updates
|
|
10721
11228
|
cookieCheckIntervalRef.current = setInterval(async () => {
|
|
11229
|
+
// Skip cookie sync checks if user is completing SSO at /sso-login
|
|
11230
|
+
const completingSso = new RegExp("^\/sso-login").test(pathname);
|
|
11231
|
+
if (completingSso) {
|
|
11232
|
+
console.log("[AuthProvider] Skipping cookie sync check for public route");
|
|
11233
|
+
return;
|
|
11234
|
+
}
|
|
11235
|
+
// Check for logout timestamp changes (cross-SPA logout detection)
|
|
11236
|
+
const currentLogoutTimestamp = CookieUtils.get(COOKIE_KEYS.LOGOUT_TIMESTAMP);
|
|
11237
|
+
if (currentLogoutTimestamp &&
|
|
11238
|
+
lastLogoutTimestampRef.current &&
|
|
11239
|
+
currentLogoutTimestamp !== lastLogoutTimestampRef.current) {
|
|
11240
|
+
console.log("[auth-redirect] Logout detected from another SPA", {
|
|
11241
|
+
previousTimestamp: lastLogoutTimestampRef.current,
|
|
11242
|
+
newTimestamp: currentLogoutTimestamp,
|
|
11243
|
+
});
|
|
11244
|
+
lastLogoutTimestampRef.current = currentLogoutTimestamp;
|
|
11245
|
+
redirectToAuthSpa(undefined, undefined, true);
|
|
11246
|
+
return;
|
|
11247
|
+
}
|
|
10722
11248
|
const needsRefresh = await syncCookiesToLocalStorage(storageService);
|
|
10723
11249
|
if (needsRefresh) {
|
|
10724
|
-
console.log("[
|
|
10725
|
-
|
|
11250
|
+
console.log("[auth-redirect] Cookie sync detected changes from another SPA, refreshing page");
|
|
11251
|
+
let cookieTenantKey;
|
|
11252
|
+
try {
|
|
11253
|
+
const cookieCurrentTenant = JSON.parse(CookieUtils.get(COOKIE_KEYS.CURRENT_TENANT));
|
|
11254
|
+
cookieTenantKey = cookieCurrentTenant.key;
|
|
11255
|
+
}
|
|
11256
|
+
catch (_a) { }
|
|
11257
|
+
redirectToAuthSpa(undefined, cookieTenantKey, false, false);
|
|
11258
|
+
}
|
|
11259
|
+
else {
|
|
11260
|
+
await syncAuthToCookies(storageService);
|
|
10726
11261
|
}
|
|
10727
11262
|
}, 2000);
|
|
10728
11263
|
// Cleanup interval on unmount
|
|
@@ -10731,15 +11266,14 @@ function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure,
|
|
|
10731
11266
|
clearInterval(cookieCheckIntervalRef.current);
|
|
10732
11267
|
}
|
|
10733
11268
|
};
|
|
10734
|
-
}, [storageService]);
|
|
11269
|
+
}, [storageService, middleware, pathname]);
|
|
10735
11270
|
/**
|
|
10736
11271
|
* Listen for storage events from other tabs/windows (web only)
|
|
10737
11272
|
* This catches same-SPA changes in different tabs
|
|
10738
11273
|
* On React Native, this is a no-op
|
|
10739
11274
|
*/
|
|
10740
11275
|
useEffect(() => {
|
|
10741
|
-
|
|
10742
|
-
if (!storageService || !isWeb())
|
|
11276
|
+
if (!storageService || !isWeb$1())
|
|
10743
11277
|
return;
|
|
10744
11278
|
const handleStorageChange = async (event) => {
|
|
10745
11279
|
// Only handle changes to our auth-related keys
|
|
@@ -10770,14 +11304,15 @@ function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure,
|
|
|
10770
11304
|
if (!hasNonExpiredAuthToken()) {
|
|
10771
11305
|
const reason = "Auth token expired";
|
|
10772
11306
|
onAuthFailure === null || onAuthFailure === void 0 ? void 0 : onAuthFailure(reason);
|
|
10773
|
-
|
|
11307
|
+
console.log("[auth-redirect] Auth token expired");
|
|
11308
|
+
redirectToAuthSpa(undefined, undefined, true);
|
|
10774
11309
|
return;
|
|
10775
11310
|
}
|
|
10776
11311
|
// Check JWT token expiry and force logout for protected routes
|
|
10777
11312
|
if (isProtectedRoute && storageService) {
|
|
10778
11313
|
const jwtExpired = await isJwtTokenExpired(storageService);
|
|
10779
11314
|
if (jwtExpired) {
|
|
10780
|
-
console.log("[
|
|
11315
|
+
console.log("[auth-redirect] JWT token has expired, forcing logout");
|
|
10781
11316
|
// Clear all auth-related storage keys
|
|
10782
11317
|
clearAuthCookies();
|
|
10783
11318
|
const reason = "JWT token expired";
|
|
@@ -10799,11 +11334,18 @@ function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure,
|
|
|
10799
11334
|
console.log("[AuthProvider] JWT token refreshed successfully");
|
|
10800
11335
|
}
|
|
10801
11336
|
else if (result.error) {
|
|
10802
|
-
console.
|
|
11337
|
+
console.log("[auth-redirect] Failed to refresh JWT token", {
|
|
11338
|
+
error: result.error,
|
|
11339
|
+
});
|
|
11340
|
+
redirectToAuthSpa(undefined, undefined, true);
|
|
11341
|
+
return;
|
|
10803
11342
|
}
|
|
10804
11343
|
}
|
|
10805
11344
|
catch (refreshError) {
|
|
10806
|
-
console.
|
|
11345
|
+
console.log("[auth-redirect] JWT token refresh error", {
|
|
11346
|
+
error: refreshError,
|
|
11347
|
+
});
|
|
11348
|
+
redirectToAuthSpa(undefined, undefined, true);
|
|
10807
11349
|
// Continue with auth check even if JWT refresh fails
|
|
10808
11350
|
}
|
|
10809
11351
|
}
|
|
@@ -10815,12 +11357,18 @@ function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure,
|
|
|
10815
11357
|
setIsAuthenticating(false);
|
|
10816
11358
|
}
|
|
10817
11359
|
catch (error) {
|
|
11360
|
+
console.error("[AuthProvider] Error performing auth check:", error);
|
|
10818
11361
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
10819
11362
|
onAuthFailure === null || onAuthFailure === void 0 ? void 0 : onAuthFailure(`Unexpected error: ${errorMessage}`);
|
|
10820
11363
|
redirectToAuthSpa();
|
|
10821
11364
|
}
|
|
10822
11365
|
}
|
|
10823
11366
|
useEffect(() => {
|
|
11367
|
+
// Wait for initial sync to complete before performing auth check
|
|
11368
|
+
if (!initialSyncComplete) {
|
|
11369
|
+
console.log("[useAuthProvider] Waiting for initial sync to complete...");
|
|
11370
|
+
return;
|
|
11371
|
+
}
|
|
10824
11372
|
async function checkAuth() {
|
|
10825
11373
|
setIsAuthenticating(true);
|
|
10826
11374
|
const authRequired = (await determineAuthRequired(middleware, pathname)) && !token;
|
|
@@ -10841,7 +11389,7 @@ function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure,
|
|
|
10841
11389
|
}
|
|
10842
11390
|
console.log("[useAuthProvider] performing auth check for ", username);
|
|
10843
11391
|
checkAuth();
|
|
10844
|
-
}, [username]);
|
|
11392
|
+
}, [username, initialSyncComplete]);
|
|
10845
11393
|
return {
|
|
10846
11394
|
isAuthenticating,
|
|
10847
11395
|
userIsAccessingPublicRoute,
|
|
@@ -10909,7 +11457,7 @@ function AuthProvider({ children, fallback, middleware = new Map(), onAuthSucces
|
|
|
10909
11457
|
if (isAuthenticating) {
|
|
10910
11458
|
return fallback;
|
|
10911
11459
|
}
|
|
10912
|
-
return (jsx(AuthContextProvider, { value: { userIsAccessingPublicRoute, setUserIsAccessingPublicRoute }, children:
|
|
11460
|
+
return (jsx(AuthContextProvider, { value: { userIsAccessingPublicRoute, setUserIsAccessingPublicRoute }, children: children }));
|
|
10913
11461
|
}
|
|
10914
11462
|
|
|
10915
11463
|
/**
|
|
@@ -10922,6 +11470,12 @@ function AuthProvider({ children, fallback, middleware = new Map(), onAuthSucces
|
|
|
10922
11470
|
* - Tenant metadata retrieval
|
|
10923
11471
|
* - User-tenant relationship verification
|
|
10924
11472
|
*/
|
|
11473
|
+
/**
|
|
11474
|
+
* Check if we're running in a web browser environment
|
|
11475
|
+
*/
|
|
11476
|
+
const isWeb = () => {
|
|
11477
|
+
return typeof window !== "undefined" && typeof document !== "undefined";
|
|
11478
|
+
};
|
|
10925
11479
|
const TenantContext = createContext(undefined);
|
|
10926
11480
|
/**
|
|
10927
11481
|
* Context Provider component that wraps children with tenant context
|
|
@@ -10942,7 +11496,7 @@ const useTenantContext = () => useContext(TenantContext);
|
|
|
10942
11496
|
* 4. Handles tenant-specific domain redirects
|
|
10943
11497
|
* 5. Maintains tenant access state
|
|
10944
11498
|
*/
|
|
10945
|
-
function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, currentTenant, requestedTenant, saveCurrentTenant, saveUserTenants, handleTenantSwitch, saveVisitingTenant, removeVisitingTenant, saveUserTokens, saveTenant, onAutoJoinUserToTenant, }) {
|
|
11499
|
+
function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, currentTenant, requestedTenant, saveCurrentTenant, saveUserTenants, handleTenantSwitch, saveVisitingTenant, removeVisitingTenant, saveUserTokens, saveTenant, onAutoJoinUserToTenant, redirectToAuthSpa, username, }) {
|
|
10946
11500
|
const { userIsAccessingPublicRoute, setUserIsAccessingPublicRoute } = useAuthContext();
|
|
10947
11501
|
const [determineUserPath, setDetermineUserPath] = useState(false);
|
|
10948
11502
|
const [isLoading, setIsLoading] = React__default.useState(true);
|
|
@@ -10953,6 +11507,26 @@ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, curr
|
|
|
10953
11507
|
const [getAppToken] = useGetAppTokensMutation();
|
|
10954
11508
|
const [tenantKey, setTenantKey] = useState(currentTenant);
|
|
10955
11509
|
const [metadata, setMetadata] = useState({});
|
|
11510
|
+
// Fetch custom domain to get platform_key
|
|
11511
|
+
const currentDomain = typeof window !== "undefined" ? window.location.hostname : "";
|
|
11512
|
+
const { data: customDomainData, isLoading: isLoadingCustomDomain, isError: isCustomDomainError, } = useGetCustomDomainsQuery({ params: { domain: currentDomain } }, { skip: !isWeb() || !currentDomain });
|
|
11513
|
+
// Extract platform_key from custom domain response to use as requestedTenant
|
|
11514
|
+
const customDomainPlatformKey = React__default.useMemo(() => {
|
|
11515
|
+
if (customDomainData &&
|
|
11516
|
+
typeof customDomainData === "object" &&
|
|
11517
|
+
"custom_domains" in customDomainData) {
|
|
11518
|
+
const domains = customDomainData.custom_domains;
|
|
11519
|
+
if (Array.isArray(domains) &&
|
|
11520
|
+
domains.length > 0 &&
|
|
11521
|
+
domains[0].platform_key) {
|
|
11522
|
+
console.log("[TenantProvider] Using platform_key from custom domain:", domains[0].platform_key);
|
|
11523
|
+
return domains[0].platform_key;
|
|
11524
|
+
}
|
|
11525
|
+
}
|
|
11526
|
+
return undefined;
|
|
11527
|
+
}, [customDomainData]);
|
|
11528
|
+
// Use custom domain platform_key as requested tenant if available, otherwise use provided requestedTenant
|
|
11529
|
+
const effectiveRequestedTenant = customDomainPlatformKey || requestedTenant;
|
|
10956
11530
|
/**
|
|
10957
11531
|
* Helper function to enhance tenants with platform metadata from user apps
|
|
10958
11532
|
*/
|
|
@@ -11012,24 +11586,32 @@ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, curr
|
|
|
11012
11586
|
const otherTenant = tenants.find((t) => t.key !== MAIN_TENANT_KEY);
|
|
11013
11587
|
if (mainTenant &&
|
|
11014
11588
|
otherTenant &&
|
|
11015
|
-
|
|
11016
|
-
|
|
11589
|
+
effectiveRequestedTenant &&
|
|
11590
|
+
effectiveRequestedTenant !== otherTenant.key) {
|
|
11017
11591
|
handleTenantSwitch(otherTenant.key, true);
|
|
11018
11592
|
console.log("TenantProvider: Triggering tenant switch to newly joined tenant:", otherTenant.key);
|
|
11019
11593
|
}
|
|
11020
11594
|
}
|
|
11021
|
-
// Enhance tenants with platform
|
|
11595
|
+
// Enhance tenants with platform metadatax
|
|
11022
11596
|
let enhancedTenants = await enhanceTenants(tenants);
|
|
11597
|
+
// if there is customDomainPlatformKey and user doesn't belong to that tenant, trigger logout
|
|
11598
|
+
if (customDomainPlatformKey) {
|
|
11599
|
+
if (!(enhancedTenants === null || enhancedTenants === void 0 ? void 0 : enhancedTenants.find((tenant) => tenant.key === customDomainPlatformKey))) {
|
|
11600
|
+
redirectToAuthSpa === null || redirectToAuthSpa === void 0 ? void 0 : redirectToAuthSpa(undefined, undefined, true);
|
|
11601
|
+
return;
|
|
11602
|
+
}
|
|
11603
|
+
}
|
|
11023
11604
|
saveUserTenants(enhancedTenants);
|
|
11024
11605
|
// Find requested tenant or fallback to current tenant
|
|
11025
|
-
console.log("checking requested tenant", {
|
|
11026
|
-
|
|
11027
|
-
|
|
11606
|
+
console.log("checking requested tenant", JSON.stringify({
|
|
11607
|
+
requestedTenant: effectiveRequestedTenant,
|
|
11608
|
+
customDomainPlatformKey,
|
|
11609
|
+
}));
|
|
11610
|
+
let tenant = enhancedTenants === null || enhancedTenants === void 0 ? void 0 : enhancedTenants.find((tenant) => tenant.key === effectiveRequestedTenant);
|
|
11611
|
+
console.log("requested tenant", tenant);
|
|
11028
11612
|
if (!tenant && !userIsAccessingPublicRoute) {
|
|
11029
11613
|
setDetermineUserPath(true);
|
|
11030
|
-
console.log("no requested tenant, checking current tenant",
|
|
11031
|
-
currentTenant,
|
|
11032
|
-
});
|
|
11614
|
+
console.log("no requested tenant, checking current tenant", currentTenant);
|
|
11033
11615
|
tenant = enhancedTenants === null || enhancedTenants === void 0 ? void 0 : enhancedTenants.find((tenant) => tenant.key === currentTenant);
|
|
11034
11616
|
console.log("current tenant", { tenant });
|
|
11035
11617
|
}
|
|
@@ -11041,7 +11623,7 @@ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, curr
|
|
|
11041
11623
|
tenant = enhancedTenants[0];
|
|
11042
11624
|
}
|
|
11043
11625
|
// Fetch and validate tenant metadata
|
|
11044
|
-
console.log("fetching tenant metadata",
|
|
11626
|
+
console.log("fetching tenant metadata", JSON.stringify(tenant));
|
|
11045
11627
|
const { data: tenantMetadata } = await fetchTenantMetadata([
|
|
11046
11628
|
{
|
|
11047
11629
|
org: (tenant === null || tenant === void 0 ? void 0 : tenant.key) || currentTenant,
|
|
@@ -11112,6 +11694,11 @@ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, curr
|
|
|
11112
11694
|
platform_name: data.platform_name,
|
|
11113
11695
|
is_advertising: (_a = data.metadata) === null || _a === void 0 ? void 0 : _a.is_advertising,
|
|
11114
11696
|
};
|
|
11697
|
+
if (!username) {
|
|
11698
|
+
saveVisitingTenant === null || saveVisitingTenant === void 0 ? void 0 : saveVisitingTenant(newCurrentTenant);
|
|
11699
|
+
// user is not authenticated so we don't need to do anything that concerns an authenticated user
|
|
11700
|
+
return;
|
|
11701
|
+
}
|
|
11115
11702
|
const { data: tenants } = await fetchUserTenants();
|
|
11116
11703
|
const enhancedTenants = await enhanceTenants(tenants, data);
|
|
11117
11704
|
saveUserTenants(enhancedTenants);
|
|
@@ -11183,28 +11770,44 @@ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, curr
|
|
|
11183
11770
|
}
|
|
11184
11771
|
// Effect to handle tenant determination when auth state changes
|
|
11185
11772
|
React__default.useEffect(() => {
|
|
11773
|
+
// Wait for custom domain query to complete (unless skipped or error)
|
|
11774
|
+
const customDomainQuerySkipped = !isWeb() || !currentDomain;
|
|
11775
|
+
if (!customDomainQuerySkipped && isLoadingCustomDomain) {
|
|
11776
|
+
console.log("[TenantProvider] Waiting for custom domain query to complete...");
|
|
11777
|
+
return;
|
|
11778
|
+
}
|
|
11779
|
+
if (isCustomDomainError) {
|
|
11780
|
+
console.warn("[TenantProvider] Custom domain query failed, proceeding without custom domain platform_key");
|
|
11781
|
+
}
|
|
11186
11782
|
// NOTE: currentTenant comes from local storage.
|
|
11187
11783
|
// it's the tenant the user is currently signed into.
|
|
11188
11784
|
console.log("determineWhichTenantToUse", {
|
|
11189
11785
|
userIsAccessingPublicRoute,
|
|
11190
11786
|
currentTenant,
|
|
11191
11787
|
requestedTenant,
|
|
11788
|
+
effectiveRequestedTenant,
|
|
11789
|
+
customDomainPlatformKey,
|
|
11192
11790
|
});
|
|
11193
|
-
if (userIsAccessingPublicRoute &&
|
|
11791
|
+
if (userIsAccessingPublicRoute && effectiveRequestedTenant.length === 0) {
|
|
11194
11792
|
setIsLoading(false);
|
|
11195
11793
|
return;
|
|
11196
11794
|
}
|
|
11197
|
-
if (userIsAccessingPublicRoute &&
|
|
11795
|
+
if (userIsAccessingPublicRoute && effectiveRequestedTenant.length > 0) {
|
|
11198
11796
|
setIsLoading(true);
|
|
11199
|
-
setTenantKey(
|
|
11200
|
-
handleLoadTenantMetadata(
|
|
11797
|
+
setTenantKey(effectiveRequestedTenant);
|
|
11798
|
+
handleLoadTenantMetadata(effectiveRequestedTenant);
|
|
11201
11799
|
}
|
|
11202
11800
|
else {
|
|
11203
11801
|
setIsLoading(true);
|
|
11204
11802
|
removeVisitingTenant === null || removeVisitingTenant === void 0 ? void 0 : removeVisitingTenant();
|
|
11205
11803
|
determineWhichTenantToUse();
|
|
11206
11804
|
}
|
|
11207
|
-
}, [
|
|
11805
|
+
}, [
|
|
11806
|
+
userIsAccessingPublicRoute,
|
|
11807
|
+
effectiveRequestedTenant,
|
|
11808
|
+
isLoadingCustomDomain,
|
|
11809
|
+
isCustomDomainError,
|
|
11810
|
+
]);
|
|
11208
11811
|
// Show fallback component during tenant determination
|
|
11209
11812
|
if (isLoading) {
|
|
11210
11813
|
return fallback;
|
|
@@ -11237,24 +11840,17 @@ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, curr
|
|
|
11237
11840
|
* 3. Manages redirection based on mentor availability
|
|
11238
11841
|
* 4. Integrates with tenant context for access control
|
|
11239
11842
|
*/
|
|
11240
|
-
function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redirectToAuthSpa, redirectToMentor, onLoadMentorsPermissions, redirectToNoMentorsPage, redirectToCreateMentor, username, isAdmin, mainTenantKey, requestedMentorId, handleMentorNotFound, forceDetermineMentor = false, }) {
|
|
11843
|
+
function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redirectToAuthSpa, redirectToMentor, onLoadMentorsPermissions, redirectToNoMentorsPage, redirectToCreateMentor, username, isAdmin, mainTenantKey, requestedMentorId, handleMentorNotFound, forceDetermineMentor = false, onComplete, }) {
|
|
11241
11844
|
const [isLoading, setIsLoading] = useState(true);
|
|
11242
11845
|
const { userIsAccessingPublicRoute } = useAuthContext();
|
|
11243
|
-
const { determineUserPath, tenantKey } = useTenantContext();
|
|
11846
|
+
const { determineUserPath, tenantKey, metadata } = useTenantContext();
|
|
11244
11847
|
const isMainTenant = tenantKey === mainTenantKey;
|
|
11245
|
-
console.log("MentorProvider initialized",
|
|
11246
|
-
username,
|
|
11247
|
-
isAdmin,
|
|
11248
|
-
tenantKey,
|
|
11249
|
-
mainTenantKey,
|
|
11250
|
-
isMainTenant,
|
|
11251
|
-
requestedMentorId,
|
|
11252
|
-
determineUserPath,
|
|
11253
|
-
});
|
|
11848
|
+
console.log("MentorProvider initialized", username, isAdmin, tenantKey, mainTenantKey, isMainTenant, requestedMentorId, determineUserPath);
|
|
11254
11849
|
const [fetchMentors] = useLazyGetMentorsQuery();
|
|
11255
11850
|
const [fetchSeedMentors] = useLazySeedMentorsQuery();
|
|
11256
11851
|
const [getMentorPublicSettings] = useLazyGetMentorPublicSettingsQuery();
|
|
11257
11852
|
const [getRbacPermissions] = useGetRbacPermissionsMutation();
|
|
11853
|
+
const [getRecentlyAccessedMentors] = useLazyGetRecentlyAccessedMentorsQuery();
|
|
11258
11854
|
const QUERY_LIMIT = 10;
|
|
11259
11855
|
const loadMentorsPermissions = async (mentorDbId) => {
|
|
11260
11856
|
try {
|
|
@@ -11271,6 +11867,33 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11271
11867
|
}
|
|
11272
11868
|
catch (_a) { }
|
|
11273
11869
|
};
|
|
11870
|
+
/**
|
|
11871
|
+
* Gets the mentor database ID from public settings if not available on the mentor object
|
|
11872
|
+
*/
|
|
11873
|
+
const getMentorDbId = async (mentor) => {
|
|
11874
|
+
if (mentor === null || mentor === void 0 ? void 0 : mentor.id) {
|
|
11875
|
+
return mentor.id;
|
|
11876
|
+
}
|
|
11877
|
+
if (mentor === null || mentor === void 0 ? void 0 : mentor.unique_id) {
|
|
11878
|
+
try {
|
|
11879
|
+
const response = await getMentorPublicSettings({
|
|
11880
|
+
// @ts-ignore
|
|
11881
|
+
mentor: mentor.unique_id,
|
|
11882
|
+
org: tenantKey,
|
|
11883
|
+
// @ts-ignore
|
|
11884
|
+
userId: username,
|
|
11885
|
+
}).unwrap();
|
|
11886
|
+
return response === null || response === void 0 ? void 0 : response.mentor_id;
|
|
11887
|
+
}
|
|
11888
|
+
catch (error) {
|
|
11889
|
+
console.log("failed to fetch mentor ID from public settings", {
|
|
11890
|
+
error: error instanceof Error ? error.message : String(error),
|
|
11891
|
+
mentorUniqueId: mentor.unique_id,
|
|
11892
|
+
});
|
|
11893
|
+
}
|
|
11894
|
+
}
|
|
11895
|
+
return undefined;
|
|
11896
|
+
};
|
|
11274
11897
|
/**
|
|
11275
11898
|
* Determines which mentor to redirect the user to by following this priority:
|
|
11276
11899
|
* 1. Recently accessed mentors
|
|
@@ -11278,24 +11901,60 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11278
11901
|
* 3. Non-featured mentors
|
|
11279
11902
|
* 4. Seeded mentors (for admin users)
|
|
11280
11903
|
* 5. Creation flow or no mentors page
|
|
11904
|
+
*
|
|
11905
|
+
* Returns the mentor object if found, undefined otherwise
|
|
11281
11906
|
*/
|
|
11282
11907
|
async function determineMentorToRedirectTo() {
|
|
11283
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o
|
|
11284
|
-
console.log("starting mentor determination process", {
|
|
11908
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
11909
|
+
console.log("starting mentor determination process", JSON.stringify({
|
|
11285
11910
|
tenantKey,
|
|
11286
11911
|
username,
|
|
11287
11912
|
isAdmin,
|
|
11288
11913
|
isMainTenant,
|
|
11289
|
-
});
|
|
11914
|
+
}));
|
|
11915
|
+
console.log("###################### metadata is ", metadata, typeof metadata);
|
|
11290
11916
|
setIsLoading(true);
|
|
11291
11917
|
try {
|
|
11292
11918
|
// Get the user's recent mentors
|
|
11293
|
-
console.log("fetching recent mentors", {
|
|
11919
|
+
console.log("fetching recent mentors", JSON.stringify({
|
|
11294
11920
|
tenantKey,
|
|
11295
11921
|
username,
|
|
11296
11922
|
limit: QUERY_LIMIT,
|
|
11297
11923
|
orderBy: "recently_accessed_at",
|
|
11924
|
+
}));
|
|
11925
|
+
if (typeof metadata === "object" &&
|
|
11926
|
+
metadata.skills_embedded_mentor_name) {
|
|
11927
|
+
const defaultMentor = JSON.parse(metadata.skills_embedded_mentor_name);
|
|
11928
|
+
if (defaultMentor === null || defaultMentor === void 0 ? void 0 : defaultMentor.unique_id) {
|
|
11929
|
+
return defaultMentor;
|
|
11930
|
+
}
|
|
11931
|
+
}
|
|
11932
|
+
// Check for recently accessed mentors (second choice)
|
|
11933
|
+
console.log("checking recently accessed mentors", JSON.stringify({
|
|
11934
|
+
tenantKey,
|
|
11935
|
+
username,
|
|
11936
|
+
}));
|
|
11937
|
+
const recentlyAccessedResult = await getRecentlyAccessedMentors({
|
|
11938
|
+
org: tenantKey,
|
|
11939
|
+
// @ts-ignore
|
|
11940
|
+
userId: username,
|
|
11298
11941
|
});
|
|
11942
|
+
// @ts-ignore
|
|
11943
|
+
const recentlyAccessedMentors = recentlyAccessedResult.data;
|
|
11944
|
+
const starredMentors = recentlyAccessedMentors === null || recentlyAccessedMentors === void 0 ? void 0 : recentlyAccessedMentors.starred_mentors;
|
|
11945
|
+
let recentMentors = recentlyAccessedMentors === null || recentlyAccessedMentors === void 0 ? void 0 : recentlyAccessedMentors.recent_mentors;
|
|
11946
|
+
if (starredMentors.length > 0) {
|
|
11947
|
+
const starredMentor = starredMentors[0];
|
|
11948
|
+
if (starredMentor === null || starredMentor === void 0 ? void 0 : starredMentor.unique_id) {
|
|
11949
|
+
return starredMentor;
|
|
11950
|
+
}
|
|
11951
|
+
}
|
|
11952
|
+
if (recentMentors.length > 0) {
|
|
11953
|
+
const recentMentor = recentMentors[0];
|
|
11954
|
+
if (recentMentor === null || recentMentor === void 0 ? void 0 : recentMentor.unique_id) {
|
|
11955
|
+
return recentMentor;
|
|
11956
|
+
}
|
|
11957
|
+
}
|
|
11299
11958
|
const recentMentorsResult = await fetchMentors({
|
|
11300
11959
|
// @ts-ignore
|
|
11301
11960
|
org: tenantKey,
|
|
@@ -11303,26 +11962,19 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11303
11962
|
limit: QUERY_LIMIT,
|
|
11304
11963
|
orderBy: "recently_accessed_at",
|
|
11305
11964
|
});
|
|
11306
|
-
|
|
11307
|
-
console.log("recent mentors fetched", {
|
|
11965
|
+
recentMentors = ((_a = recentMentorsResult.data) === null || _a === void 0 ? void 0 : _a.results) || [];
|
|
11966
|
+
console.log("recent mentors fetched", JSON.stringify({
|
|
11308
11967
|
count: recentMentors.length,
|
|
11309
11968
|
mentorIds: recentMentors.map((m) => m === null || m === void 0 ? void 0 : m.unique_id),
|
|
11310
|
-
});
|
|
11969
|
+
}));
|
|
11311
11970
|
// Check if we found recent mentors for the tenant
|
|
11312
11971
|
if (recentMentors.length > 0) {
|
|
11313
|
-
|
|
11314
|
-
|
|
11315
|
-
|
|
11316
|
-
selectedMentorId,
|
|
11317
|
-
mentorName: (_d = recentMentors[0]) === null || _d === void 0 ? void 0 : _d.name,
|
|
11972
|
+
console.log("found recent mentor", JSON.stringify({
|
|
11973
|
+
selectedMentorId: (_b = recentMentors[0]) === null || _b === void 0 ? void 0 : _b.unique_id,
|
|
11974
|
+
mentorName: (_c = recentMentors[0]) === null || _c === void 0 ? void 0 : _c.name,
|
|
11318
11975
|
tenantKey,
|
|
11319
|
-
});
|
|
11320
|
-
|
|
11321
|
-
// Select the most recent mentor as current mentor
|
|
11322
|
-
onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
|
|
11323
|
-
redirectToMentor(tenantKey, selectedMentorId);
|
|
11324
|
-
onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
|
|
11325
|
-
return;
|
|
11976
|
+
}));
|
|
11977
|
+
return recentMentors[0];
|
|
11326
11978
|
}
|
|
11327
11979
|
// If no recent mentors, get featured mentors
|
|
11328
11980
|
console.log("no recent mentors found, fetching featured mentors", {
|
|
@@ -11336,7 +11988,7 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11336
11988
|
limit: QUERY_LIMIT,
|
|
11337
11989
|
orderBy: "recently_accessed_at",
|
|
11338
11990
|
});
|
|
11339
|
-
const featuredMentors = ((
|
|
11991
|
+
const featuredMentors = ((_d = featuredMentorsResult.data) === null || _d === void 0 ? void 0 : _d.results) || [];
|
|
11340
11992
|
console.log("featured mentors fetched", {
|
|
11341
11993
|
count: featuredMentors.length,
|
|
11342
11994
|
mentorIds: featuredMentors.map((m) => m === null || m === void 0 ? void 0 : m.unique_id),
|
|
@@ -11356,16 +12008,11 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11356
12008
|
const defaultIblMentor = featuredMentors.find((mentor) => { var _a; return ((_a = mentor === null || mentor === void 0 ? void 0 : mentor.metadata) === null || _a === void 0 ? void 0 : _a.default) === true; });
|
|
11357
12009
|
// Check if found default featured mentor
|
|
11358
12010
|
if (defaultIblMentor) {
|
|
11359
|
-
console.log("
|
|
12011
|
+
console.log("found default IBL mentor", {
|
|
11360
12012
|
mentorId: defaultIblMentor === null || defaultIblMentor === void 0 ? void 0 : defaultIblMentor.unique_id,
|
|
11361
12013
|
mentorName: defaultIblMentor === null || defaultIblMentor === void 0 ? void 0 : defaultIblMentor.name,
|
|
11362
12014
|
});
|
|
11363
|
-
|
|
11364
|
-
const rbacPermissions = await loadMentorsPermissions(defaultIblMentorDbId);
|
|
11365
|
-
onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
|
|
11366
|
-
redirectToMentor === null || redirectToMentor === void 0 ? void 0 : redirectToMentor(tenantKey, (defaultIblMentor === null || defaultIblMentor === void 0 ? void 0 : defaultIblMentor.unique_id) || "");
|
|
11367
|
-
onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
|
|
11368
|
-
return;
|
|
12015
|
+
return defaultIblMentor;
|
|
11369
12016
|
}
|
|
11370
12017
|
}
|
|
11371
12018
|
else {
|
|
@@ -11376,30 +12023,19 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11376
12023
|
// Check if there's a default featured mentor
|
|
11377
12024
|
const defaultFeatureMentor = featuredMentors.find((mentor) => { var _a; return ((_a = mentor === null || mentor === void 0 ? void 0 : mentor.metadata) === null || _a === void 0 ? void 0 : _a.default) === true; });
|
|
11378
12025
|
if (defaultFeatureMentor) {
|
|
11379
|
-
console.log("
|
|
12026
|
+
console.log("found default featured mentor", {
|
|
11380
12027
|
mentorId: defaultFeatureMentor === null || defaultFeatureMentor === void 0 ? void 0 : defaultFeatureMentor.unique_id,
|
|
11381
12028
|
mentorName: defaultFeatureMentor === null || defaultFeatureMentor === void 0 ? void 0 : defaultFeatureMentor.name,
|
|
11382
12029
|
});
|
|
11383
|
-
|
|
11384
|
-
const rbacPermissions = await loadMentorsPermissions(defaultFeatureMentorDbId);
|
|
11385
|
-
onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
|
|
11386
|
-
redirectToMentor(tenantKey, (defaultFeatureMentor === null || defaultFeatureMentor === void 0 ? void 0 : defaultFeatureMentor.unique_id) || "");
|
|
11387
|
-
onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
|
|
11388
|
-
return;
|
|
12030
|
+
return defaultFeatureMentor;
|
|
11389
12031
|
}
|
|
11390
12032
|
}
|
|
11391
12033
|
// If no default mentor, select the first featured mentor
|
|
11392
|
-
|
|
11393
|
-
|
|
11394
|
-
|
|
11395
|
-
mentorName: (_g = featuredMentors[0]) === null || _g === void 0 ? void 0 : _g.name,
|
|
12034
|
+
console.log("found first featured mentor", {
|
|
12035
|
+
mentorId: (_e = featuredMentors[0]) === null || _e === void 0 ? void 0 : _e.unique_id,
|
|
12036
|
+
mentorName: (_f = featuredMentors[0]) === null || _f === void 0 ? void 0 : _f.name,
|
|
11396
12037
|
});
|
|
11397
|
-
|
|
11398
|
-
const rbacPermissions = await loadMentorsPermissions(firstFeaturedMentorDbId);
|
|
11399
|
-
onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
|
|
11400
|
-
redirectToMentor(tenantKey, firstFeaturedMentorId);
|
|
11401
|
-
onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
|
|
11402
|
-
return;
|
|
12038
|
+
return featuredMentors[0];
|
|
11403
12039
|
}
|
|
11404
12040
|
// If no featured mentors, get non-featured mentors
|
|
11405
12041
|
console.log("no featured mentors found, fetching non-featured mentors", {
|
|
@@ -11413,24 +12049,18 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11413
12049
|
limit: QUERY_LIMIT,
|
|
11414
12050
|
orderBy: "recently_accessed_at",
|
|
11415
12051
|
});
|
|
11416
|
-
const nonFeaturedMentors = ((
|
|
12052
|
+
const nonFeaturedMentors = ((_g = nonFeaturedMentorsResult.data) === null || _g === void 0 ? void 0 : _g.results) || [];
|
|
11417
12053
|
console.log("non-featured mentors fetched", {
|
|
11418
12054
|
count: nonFeaturedMentors.length,
|
|
11419
12055
|
mentorIds: nonFeaturedMentors.map((m) => m === null || m === void 0 ? void 0 : m.unique_id),
|
|
11420
12056
|
});
|
|
11421
12057
|
// Check if we found non-featured mentors
|
|
11422
12058
|
if (nonFeaturedMentors.length > 0) {
|
|
11423
|
-
|
|
11424
|
-
|
|
11425
|
-
|
|
11426
|
-
mentorName: (_l = nonFeaturedMentors[0]) === null || _l === void 0 ? void 0 : _l.name,
|
|
12059
|
+
console.log("found first non-featured mentor", {
|
|
12060
|
+
mentorId: (_h = nonFeaturedMentors[0]) === null || _h === void 0 ? void 0 : _h.unique_id,
|
|
12061
|
+
mentorName: (_j = nonFeaturedMentors[0]) === null || _j === void 0 ? void 0 : _j.name,
|
|
11427
12062
|
});
|
|
11428
|
-
|
|
11429
|
-
const rbacPermissions = await loadMentorsPermissions(firstNonFeaturedMentorDbId);
|
|
11430
|
-
onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
|
|
11431
|
-
redirectToMentor(tenantKey, firstNonFeaturedMentorId);
|
|
11432
|
-
onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
|
|
11433
|
-
return;
|
|
12063
|
+
return nonFeaturedMentors[0];
|
|
11434
12064
|
}
|
|
11435
12065
|
// If no mentors found, check if user is admin
|
|
11436
12066
|
console.log("no mentors found, checking admin status", {
|
|
@@ -11450,7 +12080,7 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11450
12080
|
// @ts-ignore
|
|
11451
12081
|
userId: username,
|
|
11452
12082
|
});
|
|
11453
|
-
const seededMentorsDetails = (
|
|
12083
|
+
const seededMentorsDetails = (_k = seedMentorsResult.data) === null || _k === void 0 ? void 0 : _k.detail;
|
|
11454
12084
|
console.log("mentor seeding completed", {
|
|
11455
12085
|
success: !!seededMentorsDetails,
|
|
11456
12086
|
details: seededMentorsDetails,
|
|
@@ -11465,29 +12095,23 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11465
12095
|
username,
|
|
11466
12096
|
limit: QUERY_LIMIT,
|
|
11467
12097
|
});
|
|
11468
|
-
const featuredMentorsAfterSeed = ((
|
|
12098
|
+
const featuredMentorsAfterSeed = ((_l = featuredMentorsAfterSeedResult.data) === null || _l === void 0 ? void 0 : _l.results) || [];
|
|
11469
12099
|
console.log("featured mentors after seeding", {
|
|
11470
12100
|
count: featuredMentorsAfterSeed.length,
|
|
11471
12101
|
mentorIds: featuredMentorsAfterSeed.map((m) => m === null || m === void 0 ? void 0 : m.unique_id),
|
|
11472
12102
|
});
|
|
11473
12103
|
if (featuredMentorsAfterSeed.length > 0) {
|
|
11474
|
-
|
|
11475
|
-
|
|
11476
|
-
|
|
11477
|
-
mentorName: (_r = featuredMentorsAfterSeed[0]) === null || _r === void 0 ? void 0 : _r.name,
|
|
12104
|
+
console.log("found seeded mentor", {
|
|
12105
|
+
mentorId: (_m = featuredMentorsAfterSeed[0]) === null || _m === void 0 ? void 0 : _m.unique_id,
|
|
12106
|
+
mentorName: (_o = featuredMentorsAfterSeed[0]) === null || _o === void 0 ? void 0 : _o.name,
|
|
11478
12107
|
});
|
|
11479
|
-
|
|
11480
|
-
const rbacPermissions = await loadMentorsPermissions(seededMentorDbId);
|
|
11481
|
-
onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
|
|
11482
|
-
redirectToMentor(tenantKey, seededMentorId);
|
|
11483
|
-
onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
|
|
11484
|
-
return;
|
|
12108
|
+
return featuredMentorsAfterSeed[0];
|
|
11485
12109
|
}
|
|
11486
12110
|
else {
|
|
11487
12111
|
console.log("no seeded mentors found, redirecting to create mentor");
|
|
11488
12112
|
redirectToCreateMentor();
|
|
11489
12113
|
onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
|
|
11490
|
-
return;
|
|
12114
|
+
return undefined;
|
|
11491
12115
|
}
|
|
11492
12116
|
}
|
|
11493
12117
|
else {
|
|
@@ -11495,7 +12119,7 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11495
12119
|
// Prompt the user to create a mentor
|
|
11496
12120
|
redirectToCreateMentor();
|
|
11497
12121
|
onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
|
|
11498
|
-
return;
|
|
12122
|
+
return undefined;
|
|
11499
12123
|
}
|
|
11500
12124
|
}
|
|
11501
12125
|
else {
|
|
@@ -11506,7 +12130,7 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11506
12130
|
// Redirect to no mentors page for non-admin users
|
|
11507
12131
|
redirectToNoMentorsPage();
|
|
11508
12132
|
onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
|
|
11509
|
-
return;
|
|
12133
|
+
return undefined;
|
|
11510
12134
|
}
|
|
11511
12135
|
}
|
|
11512
12136
|
catch (error) {
|
|
@@ -11518,18 +12142,19 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11518
12142
|
isAdmin,
|
|
11519
12143
|
});
|
|
11520
12144
|
onAuthFailure === null || onAuthFailure === void 0 ? void 0 : onAuthFailure(`Unexpected error: ${errorMessage}`);
|
|
12145
|
+
console.log("[auth-redirect] Unexpected error in mentor provider", {
|
|
12146
|
+
error: errorMessage,
|
|
12147
|
+
});
|
|
11521
12148
|
redirectToAuthSpa();
|
|
12149
|
+
return undefined;
|
|
11522
12150
|
}
|
|
11523
12151
|
finally {
|
|
11524
12152
|
setIsLoading(false);
|
|
12153
|
+
onComplete === null || onComplete === void 0 ? void 0 : onComplete();
|
|
11525
12154
|
}
|
|
11526
12155
|
}
|
|
11527
12156
|
async function mentorExistsInTenant(tenantKey, requestedMentorId) {
|
|
11528
|
-
console.log("checking if mentor exists in tenant",
|
|
11529
|
-
tenantKey,
|
|
11530
|
-
requestedMentorId,
|
|
11531
|
-
username,
|
|
11532
|
-
});
|
|
12157
|
+
console.log("checking if mentor exists in tenant", tenantKey, requestedMentorId, username);
|
|
11533
12158
|
try {
|
|
11534
12159
|
const response = await getMentorPublicSettings({
|
|
11535
12160
|
// @ts-ignore
|
|
@@ -11558,13 +12183,10 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11558
12183
|
// Effect to handle mentor determination when tenant path is determined
|
|
11559
12184
|
React__default.useEffect(() => {
|
|
11560
12185
|
async function checkMentor() {
|
|
11561
|
-
console.log("starting mentor check process",
|
|
11562
|
-
determineUserPath,
|
|
11563
|
-
requestedMentorId,
|
|
11564
|
-
tenantKey,
|
|
11565
|
-
});
|
|
12186
|
+
console.log("starting mentor check process", determineUserPath, requestedMentorId, tenantKey);
|
|
11566
12187
|
if (userIsAccessingPublicRoute && !requestedMentorId) {
|
|
11567
12188
|
setIsLoading(false);
|
|
12189
|
+
onComplete === null || onComplete === void 0 ? void 0 : onComplete();
|
|
11568
12190
|
return;
|
|
11569
12191
|
}
|
|
11570
12192
|
setIsLoading(true);
|
|
@@ -11572,50 +12194,83 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11572
12194
|
// then this mentor provider will redirect the user to the correct mentor.
|
|
11573
12195
|
if (determineUserPath || forceDetermineMentor) {
|
|
11574
12196
|
console.log("determine user path is true, starting mentor determination");
|
|
11575
|
-
await determineMentorToRedirectTo();
|
|
12197
|
+
const mentor = await determineMentorToRedirectTo();
|
|
12198
|
+
if (mentor === null || mentor === void 0 ? void 0 : mentor.unique_id) {
|
|
12199
|
+
// Get mentor DB ID - use existing ID or fetch from public settings
|
|
12200
|
+
let mentorDbId = mentor === null || mentor === void 0 ? void 0 : mentor.id;
|
|
12201
|
+
if (!mentorDbId) {
|
|
12202
|
+
mentorDbId = await getMentorDbId(mentor);
|
|
12203
|
+
}
|
|
12204
|
+
// Load permissions if we have a mentor DB ID
|
|
12205
|
+
if (mentorDbId) {
|
|
12206
|
+
const rbacPermissions = await loadMentorsPermissions(mentorDbId);
|
|
12207
|
+
onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
|
|
12208
|
+
}
|
|
12209
|
+
// Redirect to the mentor
|
|
12210
|
+
redirectToMentor(tenantKey, mentor.unique_id);
|
|
12211
|
+
onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
|
|
12212
|
+
}
|
|
11576
12213
|
return;
|
|
11577
12214
|
}
|
|
11578
12215
|
else if (requestedMentorId) {
|
|
11579
|
-
console.log(" ", {
|
|
11580
|
-
requestedMentorId,
|
|
11581
|
-
});
|
|
11582
12216
|
const [mentorExists, requestedMentorDbId] = await mentorExistsInTenant(tenantKey, requestedMentorId);
|
|
11583
12217
|
// If the mentor does not exist in the tenant, redirect the user to the correct mentor
|
|
11584
12218
|
if (!mentorExists) {
|
|
11585
|
-
console.log("requested mentor not found in tenant", {
|
|
12219
|
+
console.log("requested mentor not found in tenant", JSON.stringify({
|
|
11586
12220
|
requestedMentorId,
|
|
11587
12221
|
tenantKey,
|
|
11588
12222
|
hasCustomHandler: !!handleMentorNotFound,
|
|
11589
|
-
});
|
|
12223
|
+
}));
|
|
11590
12224
|
if (handleMentorNotFound) {
|
|
11591
12225
|
console.log("calling custom mentor not found handler");
|
|
11592
12226
|
await handleMentorNotFound();
|
|
11593
12227
|
}
|
|
11594
12228
|
else {
|
|
11595
12229
|
console.log("using default mentor determination fallback");
|
|
11596
|
-
await determineMentorToRedirectTo();
|
|
12230
|
+
const mentor = await determineMentorToRedirectTo();
|
|
12231
|
+
if (mentor === null || mentor === void 0 ? void 0 : mentor.unique_id) {
|
|
12232
|
+
// Get mentor DB ID - use existing ID or fetch from public settings
|
|
12233
|
+
let mentorDbId = mentor === null || mentor === void 0 ? void 0 : mentor.id;
|
|
12234
|
+
if (!mentorDbId) {
|
|
12235
|
+
mentorDbId = await getMentorDbId(mentor);
|
|
12236
|
+
}
|
|
12237
|
+
// Load permissions if we have a mentor DB ID
|
|
12238
|
+
if (mentorDbId) {
|
|
12239
|
+
const rbacPermissions = await loadMentorsPermissions(mentorDbId);
|
|
12240
|
+
onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
|
|
12241
|
+
}
|
|
12242
|
+
// Redirect to the mentor
|
|
12243
|
+
redirectToMentor(tenantKey, mentor.unique_id);
|
|
12244
|
+
onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
|
|
12245
|
+
}
|
|
11597
12246
|
}
|
|
11598
12247
|
return;
|
|
11599
12248
|
}
|
|
11600
12249
|
else {
|
|
11601
|
-
console.log("requested mentor exists in tenant, proceeding",
|
|
11602
|
-
requestedMentorId,
|
|
11603
|
-
});
|
|
12250
|
+
console.log("requested mentor exists in tenant, proceeding", requestedMentorId);
|
|
11604
12251
|
if (requestedMentorDbId) {
|
|
11605
12252
|
const rbacPermissions = await loadMentorsPermissions(requestedMentorDbId);
|
|
11606
12253
|
onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
|
|
11607
12254
|
}
|
|
11608
12255
|
setIsLoading(false);
|
|
12256
|
+
onComplete === null || onComplete === void 0 ? void 0 : onComplete();
|
|
11609
12257
|
}
|
|
11610
12258
|
// If the user is navigating to a specific mentor, check if it exists in the tenant
|
|
11611
12259
|
}
|
|
11612
12260
|
else {
|
|
11613
12261
|
console.log("no specific mentor requested, loading complete");
|
|
11614
12262
|
setIsLoading(false);
|
|
12263
|
+
onComplete === null || onComplete === void 0 ? void 0 : onComplete();
|
|
11615
12264
|
}
|
|
11616
12265
|
}
|
|
11617
12266
|
checkMentor();
|
|
11618
|
-
}, [
|
|
12267
|
+
}, [
|
|
12268
|
+
requestedMentorId,
|
|
12269
|
+
determineUserPath,
|
|
12270
|
+
forceDetermineMentor,
|
|
12271
|
+
userIsAccessingPublicRoute,
|
|
12272
|
+
tenantKey,
|
|
12273
|
+
]);
|
|
11619
12274
|
// Show fallback component during mentor determination
|
|
11620
12275
|
if (isLoading) {
|
|
11621
12276
|
console.log("mentor provider showing fallback component");
|
|
@@ -12072,7 +12727,7 @@ function formatProdErrorMessage(code) {
|
|
|
12072
12727
|
|
|
12073
12728
|
const defaultSessionIds = Object.fromEntries(Object.keys(advancedTabsProperties).map((key) => [key, ""]));
|
|
12074
12729
|
const defaultChatState = Object.fromEntries(Object.keys(advancedTabsProperties).map((key) => [key, []]));
|
|
12075
|
-
const initialState = {
|
|
12730
|
+
const initialState$1 = {
|
|
12076
12731
|
chats: defaultChatState,
|
|
12077
12732
|
isTyping: false,
|
|
12078
12733
|
streaming: false,
|
|
@@ -12100,7 +12755,7 @@ const initialState = {
|
|
|
12100
12755
|
};
|
|
12101
12756
|
const chatSlice = createSlice({
|
|
12102
12757
|
name: "chatSliceShared",
|
|
12103
|
-
initialState,
|
|
12758
|
+
initialState: initialState$1,
|
|
12104
12759
|
reducers: {
|
|
12105
12760
|
setChats: (state, action) => {
|
|
12106
12761
|
state.chats = action.payload;
|
|
@@ -12204,6 +12859,25 @@ const chatSlice = createSlice({
|
|
|
12204
12859
|
setShowingSharedChat: (state, action) => {
|
|
12205
12860
|
state.showingSharedChat = action.payload;
|
|
12206
12861
|
},
|
|
12862
|
+
updateFileUrlInMessage: (state, action) => {
|
|
12863
|
+
const { fileId, fileUrl } = action.payload;
|
|
12864
|
+
// Update all tabs' messages that have this file
|
|
12865
|
+
Object.keys(state.chats).forEach((tab) => {
|
|
12866
|
+
state.chats[tab] = state.chats[tab].map((message) => {
|
|
12867
|
+
if (message.fileAttachments && message.fileAttachments.length > 0) {
|
|
12868
|
+
const updatedAttachments = message.fileAttachments.map((attachment) => {
|
|
12869
|
+
// Match by fileId
|
|
12870
|
+
if (attachment.fileId === fileId) {
|
|
12871
|
+
return { ...attachment, uploadUrl: fileUrl };
|
|
12872
|
+
}
|
|
12873
|
+
return attachment;
|
|
12874
|
+
});
|
|
12875
|
+
return { ...message, fileAttachments: updatedAttachments };
|
|
12876
|
+
}
|
|
12877
|
+
return message;
|
|
12878
|
+
});
|
|
12879
|
+
});
|
|
12880
|
+
},
|
|
12207
12881
|
},
|
|
12208
12882
|
});
|
|
12209
12883
|
const chatActions = chatSlice.actions;
|
|
@@ -12487,6 +13161,61 @@ function useTimeTrackerNative(config) {
|
|
|
12487
13161
|
};
|
|
12488
13162
|
}
|
|
12489
13163
|
|
|
13164
|
+
const initialState = {
|
|
13165
|
+
attachedFiles: [],
|
|
13166
|
+
};
|
|
13167
|
+
const filesSlice = createSlice({
|
|
13168
|
+
name: "files",
|
|
13169
|
+
initialState,
|
|
13170
|
+
reducers: {
|
|
13171
|
+
addFiles: (state, action) => {
|
|
13172
|
+
state.attachedFiles = [...state.attachedFiles, ...action.payload];
|
|
13173
|
+
},
|
|
13174
|
+
updateFileProgress: (state, action) => {
|
|
13175
|
+
state.attachedFiles = state.attachedFiles.map((file) => file.id === action.payload.id
|
|
13176
|
+
? { ...file, uploadProgress: action.payload.progress }
|
|
13177
|
+
: file);
|
|
13178
|
+
},
|
|
13179
|
+
updateFileStatus: (state, action) => {
|
|
13180
|
+
state.attachedFiles = state.attachedFiles.map((file) => file.id === action.payload.id
|
|
13181
|
+
? { ...file, uploadStatus: action.payload.status }
|
|
13182
|
+
: file);
|
|
13183
|
+
},
|
|
13184
|
+
updateFileUrl: (state, action) => {
|
|
13185
|
+
state.attachedFiles = state.attachedFiles.map((file) => file.id === action.payload.id
|
|
13186
|
+
? { ...file, uploadUrl: action.payload.uploadUrl }
|
|
13187
|
+
: file);
|
|
13188
|
+
},
|
|
13189
|
+
updateFileMetadata: (state, action) => {
|
|
13190
|
+
state.attachedFiles = state.attachedFiles.map((file) => file.id === action.payload.id
|
|
13191
|
+
? {
|
|
13192
|
+
...file,
|
|
13193
|
+
fileKey: action.payload.fileKey,
|
|
13194
|
+
fileId: action.payload.fileId,
|
|
13195
|
+
}
|
|
13196
|
+
: file);
|
|
13197
|
+
},
|
|
13198
|
+
updateFileRetryCount: (state, action) => {
|
|
13199
|
+
state.attachedFiles = state.attachedFiles.map((file) => file.id === action.payload.id
|
|
13200
|
+
? { ...file, retryCount: action.payload.retryCount }
|
|
13201
|
+
: file);
|
|
13202
|
+
},
|
|
13203
|
+
updateFileUrlFromWebSocket: (state, action) => {
|
|
13204
|
+
state.attachedFiles = state.attachedFiles.map((file) => file.fileId === action.payload.fileId
|
|
13205
|
+
? { ...file, fileUrl: action.payload.fileUrl }
|
|
13206
|
+
: file);
|
|
13207
|
+
},
|
|
13208
|
+
removeFile: (state, action) => {
|
|
13209
|
+
state.attachedFiles = state.attachedFiles.filter((file) => file.id !== action.payload);
|
|
13210
|
+
},
|
|
13211
|
+
clearFiles: (state) => {
|
|
13212
|
+
state.attachedFiles = [];
|
|
13213
|
+
},
|
|
13214
|
+
},
|
|
13215
|
+
});
|
|
13216
|
+
const { addFiles, removeFile, clearFiles, updateFileProgress, updateFileStatus, updateFileUrl, updateFileMetadata, updateFileRetryCount, updateFileUrlFromWebSocket, } = filesSlice.actions;
|
|
13217
|
+
const filesReducer = filesSlice.reducer;
|
|
13218
|
+
|
|
12490
13219
|
const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, enableHaptics = false, hapticFeedback, store, errorHandler, onStatusChange, onStreamingChange, onStreamingMessageUpdate, WebSocketImpl = WebSocket, redirectToAuthSpa, sendMessageToParentWebsite, on402Error, }) => {
|
|
12491
13220
|
const dispatch = useDispatch();
|
|
12492
13221
|
const isWebSocketPaused = useRef(false);
|
|
@@ -12510,7 +13239,7 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
|
|
|
12510
13239
|
await hapticFeedback.impactAsync("medium");
|
|
12511
13240
|
}
|
|
12512
13241
|
catch (error) {
|
|
12513
|
-
|
|
13242
|
+
errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler("Haptic feedback failed", error);
|
|
12514
13243
|
}
|
|
12515
13244
|
}
|
|
12516
13245
|
}, [enableHaptics, hapticFeedback]);
|
|
@@ -12522,8 +13251,8 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
|
|
|
12522
13251
|
}
|
|
12523
13252
|
if (!wsToken) {
|
|
12524
13253
|
if (!userIsAccessingPublicRoute) {
|
|
12525
|
-
console.
|
|
12526
|
-
redirectToAuthSpa();
|
|
13254
|
+
console.log("[auth-redirect] WebSocket token is missing for non-anonymous user");
|
|
13255
|
+
redirectToAuthSpa(undefined, undefined, true);
|
|
12527
13256
|
return;
|
|
12528
13257
|
}
|
|
12529
13258
|
}
|
|
@@ -12557,6 +13286,7 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
|
|
|
12557
13286
|
onStreamingChange === null || onStreamingChange === void 0 ? void 0 : onStreamingChange(false);
|
|
12558
13287
|
});
|
|
12559
13288
|
socket.addEventListener("message", (event) => {
|
|
13289
|
+
var _a, _b, _c;
|
|
12560
13290
|
if (isWebSocketPaused.current)
|
|
12561
13291
|
return;
|
|
12562
13292
|
try {
|
|
@@ -12578,6 +13308,16 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
|
|
|
12578
13308
|
onStreamingChange(!!messageData.isTyping);
|
|
12579
13309
|
return;
|
|
12580
13310
|
}
|
|
13311
|
+
// Handle file processing success
|
|
13312
|
+
if (messageData.type === "file_processing_success") {
|
|
13313
|
+
console.log("🟣 File processing success:", messageData);
|
|
13314
|
+
dispatch(chatActions.updateFileUrlInMessage({
|
|
13315
|
+
fileId: messageData.file_id,
|
|
13316
|
+
fileName: messageData.file_name,
|
|
13317
|
+
fileUrl: messageData.file_url,
|
|
13318
|
+
}));
|
|
13319
|
+
return;
|
|
13320
|
+
}
|
|
12581
13321
|
// Handle start of new streaming session
|
|
12582
13322
|
if (messageData.generation_id &&
|
|
12583
13323
|
!messageData.data &&
|
|
@@ -12596,14 +13336,14 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
|
|
|
12596
13336
|
if (messageData.data !== undefined || messageData.eos !== undefined) {
|
|
12597
13337
|
const messageText = messageData.data || "";
|
|
12598
13338
|
// If we have content to add
|
|
12599
|
-
if (messageText) {
|
|
13339
|
+
if (messageText && currentStreamingMessage.current) {
|
|
12600
13340
|
currentStreamingMessage.current = {
|
|
12601
13341
|
...currentStreamingMessage.current,
|
|
12602
13342
|
content: currentStreamingMessage.current.content + messageText,
|
|
12603
13343
|
};
|
|
12604
13344
|
onStreamingMessageUpdate === null || onStreamingMessageUpdate === void 0 ? void 0 : onStreamingMessageUpdate(currentStreamingMessage.current);
|
|
12605
13345
|
// Update or add message in Redux store
|
|
12606
|
-
if (currentStreamingMessage.current.id) {
|
|
13346
|
+
if ((_a = currentStreamingMessage.current) === null || _a === void 0 ? void 0 : _a.id) {
|
|
12607
13347
|
dispatch(chatActions.appendMessageToActiveTab({
|
|
12608
13348
|
id: currentStreamingMessage.current.id,
|
|
12609
13349
|
content: currentStreamingMessage.current.content,
|
|
@@ -12613,8 +13353,8 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
|
|
|
12613
13353
|
// Handle end of stream
|
|
12614
13354
|
if (messageData.eos) {
|
|
12615
13355
|
// Final update to Redux store with complete message
|
|
12616
|
-
if (currentStreamingMessage.current.id &&
|
|
12617
|
-
currentStreamingMessage.current.content) {
|
|
13356
|
+
if (((_b = currentStreamingMessage.current) === null || _b === void 0 ? void 0 : _b.id) &&
|
|
13357
|
+
((_c = currentStreamingMessage.current) === null || _c === void 0 ? void 0 : _c.content)) {
|
|
12618
13358
|
dispatch(chatActions.appendMessageToActiveTab({
|
|
12619
13359
|
id: currentStreamingMessage.current.id,
|
|
12620
13360
|
content: currentStreamingMessage.current.content,
|
|
@@ -12629,13 +13369,13 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
|
|
|
12629
13369
|
}
|
|
12630
13370
|
}
|
|
12631
13371
|
catch (error) {
|
|
12632
|
-
|
|
13372
|
+
errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler("Error processing message", error);
|
|
12633
13373
|
onStreamingChange === null || onStreamingChange === void 0 ? void 0 : onStreamingChange(false);
|
|
12634
13374
|
onStatusChange("error");
|
|
12635
13375
|
}
|
|
12636
13376
|
});
|
|
12637
13377
|
socket.addEventListener("error", (error) => {
|
|
12638
|
-
|
|
13378
|
+
errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler("WebSocket error", error);
|
|
12639
13379
|
onStreamingChange === null || onStreamingChange === void 0 ? void 0 : onStreamingChange(false);
|
|
12640
13380
|
onStatusChange("error");
|
|
12641
13381
|
});
|
|
@@ -12673,19 +13413,31 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
|
|
|
12673
13413
|
};
|
|
12674
13414
|
};
|
|
12675
13415
|
const sendMessage = useCallback(async (tab, text, options) => {
|
|
12676
|
-
var _a;
|
|
13416
|
+
var _a, _b;
|
|
12677
13417
|
dispatch(chatActions.setShowingSharedChat(false));
|
|
12678
|
-
if
|
|
13418
|
+
// Allow sending if there's text OR file references
|
|
13419
|
+
if (!text.trim() &&
|
|
13420
|
+
(!(options === null || options === void 0 ? void 0 : options.fileReferences) || options.fileReferences.length === 0)) {
|
|
12679
13421
|
return;
|
|
13422
|
+
}
|
|
12680
13423
|
onStatusChange("pending");
|
|
12681
13424
|
isWebSocketPaused.current = false;
|
|
12682
13425
|
await triggerHapticFeedback();
|
|
13426
|
+
// Create file attachments array from file references if present
|
|
13427
|
+
const fileAttachments = (_a = options === null || options === void 0 ? void 0 : options.fileReferences) === null || _a === void 0 ? void 0 : _a.map((ref) => ({
|
|
13428
|
+
fileName: ref.file_name,
|
|
13429
|
+
fileType: ref.content_type,
|
|
13430
|
+
fileSize: ref.file_size,
|
|
13431
|
+
uploadUrl: ref.upload_url, // Include URL for display
|
|
13432
|
+
fileId: ref.file_id, // Include fileId for matching WebSocket updates
|
|
13433
|
+
}));
|
|
12683
13434
|
const userMessage = {
|
|
12684
13435
|
id: `user-${Date.now()}`,
|
|
12685
13436
|
role: "user",
|
|
12686
13437
|
content: text,
|
|
12687
13438
|
timestamp: new Date().toISOString(),
|
|
12688
|
-
visible: (
|
|
13439
|
+
visible: (_b = options === null || options === void 0 ? void 0 : options.visible) !== null && _b !== void 0 ? _b : true,
|
|
13440
|
+
fileAttachments,
|
|
12689
13441
|
};
|
|
12690
13442
|
// Notify parent to add user message
|
|
12691
13443
|
// onAddUserMessage?.(tab, userMessage);
|
|
@@ -12697,8 +13449,14 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
|
|
|
12697
13449
|
flow: flowConfig,
|
|
12698
13450
|
session_id: sessionId,
|
|
12699
13451
|
token: wsToken,
|
|
12700
|
-
prompt: text,
|
|
13452
|
+
prompt: text || "", // Allow empty prompt when sending files
|
|
12701
13453
|
};
|
|
13454
|
+
if ((options === null || options === void 0 ? void 0 : options.fileReferences) && options.fileReferences.length > 0) {
|
|
13455
|
+
messageData = {
|
|
13456
|
+
...messageData,
|
|
13457
|
+
file_references: options.fileReferences,
|
|
13458
|
+
};
|
|
13459
|
+
}
|
|
12702
13460
|
if (iframeContext.pageContent) {
|
|
12703
13461
|
messageData = {
|
|
12704
13462
|
...messageData,
|
|
@@ -12768,8 +13526,12 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
|
|
|
12768
13526
|
}
|
|
12769
13527
|
};
|
|
12770
13528
|
const _initiateServerStopGeneration = () => {
|
|
12771
|
-
var _a;
|
|
12772
|
-
(_a =
|
|
13529
|
+
var _a, _b;
|
|
13530
|
+
if (!((_a = currentStreamingMessage.current) === null || _a === void 0 ? void 0 : _a.id)) {
|
|
13531
|
+
console.warn("Cannot stop generation: no active generation ID");
|
|
13532
|
+
return;
|
|
13533
|
+
}
|
|
13534
|
+
(_b = stopGenerationSocket === null || stopGenerationSocket === void 0 ? void 0 : stopGenerationSocket.current) === null || _b === void 0 ? void 0 : _b.send(JSON.stringify({
|
|
12773
13535
|
generation_id: currentStreamingMessage.current.id,
|
|
12774
13536
|
name: flowConfig.name,
|
|
12775
13537
|
tenant: flowConfig.tenant,
|
|
@@ -12829,7 +13591,7 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
|
|
|
12829
13591
|
};
|
|
12830
13592
|
};
|
|
12831
13593
|
|
|
12832
|
-
function useMentorSettings({ mentorId, tenantKey, username }) {
|
|
13594
|
+
function useMentorSettings({ mentorId, tenantKey, username, }) {
|
|
12833
13595
|
var _a, _b, _c, _d;
|
|
12834
13596
|
const isLoggedIn = username !== ANONYMOUS_USERNAME;
|
|
12835
13597
|
const { data: mentorSettings } = useGetMentorSettingsQuery({
|
|
@@ -12865,6 +13627,9 @@ function useMentorSettings({ mentorId, tenantKey, username }) {
|
|
|
12865
13627
|
mentorUniqueId: isLoggedIn
|
|
12866
13628
|
? mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.mentor_unique_id
|
|
12867
13629
|
: mentorPublicSettings === null || mentorPublicSettings === void 0 ? void 0 : mentorPublicSettings.mentor_unique_id,
|
|
13630
|
+
mentorVisibility: isLoggedIn
|
|
13631
|
+
? mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.mentor_visibility
|
|
13632
|
+
: mentorPublicSettings === null || mentorPublicSettings === void 0 ? void 0 : mentorPublicSettings.mentor_visibility,
|
|
12868
13633
|
mentorName: (_a = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.mentor) !== null && _a !== void 0 ? _a : mentorPublicSettings === null || mentorPublicSettings === void 0 ? void 0 : mentorPublicSettings.mentor,
|
|
12869
13634
|
enableGuidedPrompts: isLoggedIn
|
|
12870
13635
|
? mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.enable_guided_prompts
|
|
@@ -12883,8 +13648,8 @@ function useMentorSettings({ mentorId, tenantKey, username }) {
|
|
|
12883
13648
|
};
|
|
12884
13649
|
}
|
|
12885
13650
|
|
|
12886
|
-
function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, token, wsUrl, stopGenerationWsUrl, redirectToAuthSpa, errorHandler, sendMessageToParentWebsite, isPreviewMode, mentorShareableToken, on402Error, }) {
|
|
12887
|
-
var _a, _b, _c, _d;
|
|
13651
|
+
function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, token, wsUrl, stopGenerationWsUrl, redirectToAuthSpa, errorHandler, sendMessageToParentWebsite, isPreviewMode, mentorShareableToken, on402Error, cachedSessionId, onStartNewChat, }) {
|
|
13652
|
+
var _a, _b, _c, _d, _e;
|
|
12888
13653
|
const dispatch = useDispatch();
|
|
12889
13654
|
const [createSessionId, { isLoading: isLoadingSessionIds }] = useCreateSessionIdMutation();
|
|
12890
13655
|
const chats = useSelector(selectChats);
|
|
@@ -12922,7 +13687,7 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
12922
13687
|
username,
|
|
12923
13688
|
pathway: mentorId,
|
|
12924
13689
|
},
|
|
12925
|
-
sessionId: sessionIds[activeTab],
|
|
13690
|
+
sessionId: (_a = cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId]) !== null && _a !== void 0 ? _a : sessionIds[activeTab],
|
|
12926
13691
|
activeTab,
|
|
12927
13692
|
wsToken: token,
|
|
12928
13693
|
errorHandler,
|
|
@@ -12933,6 +13698,56 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
12933
13698
|
onStatusChange,
|
|
12934
13699
|
on402Error,
|
|
12935
13700
|
});
|
|
13701
|
+
const [getSessionChats, { isError: isErrorGettingSessionChats }] = useLazyGetSessionIdQuery();
|
|
13702
|
+
useEffect(() => {
|
|
13703
|
+
const getChats = async () => {
|
|
13704
|
+
var _a, _b;
|
|
13705
|
+
try {
|
|
13706
|
+
const { data } = await getSessionChats({
|
|
13707
|
+
sessionId: (_a = cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId]) !== null && _a !== void 0 ? _a : "",
|
|
13708
|
+
org: tenantKey,
|
|
13709
|
+
share: true,
|
|
13710
|
+
});
|
|
13711
|
+
let previousChats = [];
|
|
13712
|
+
try {
|
|
13713
|
+
previousChats =
|
|
13714
|
+
((_b = data === null || data === void 0 ? void 0 : data.results) === null || _b === void 0 ? void 0 : _b.map((result) => {
|
|
13715
|
+
return {
|
|
13716
|
+
...result,
|
|
13717
|
+
role: result.type === "human" ? "user" : "assistant",
|
|
13718
|
+
visible: true,
|
|
13719
|
+
id: new Date().getTime(),
|
|
13720
|
+
content: typeof result.content === "object" &&
|
|
13721
|
+
result.content.length > 0
|
|
13722
|
+
? result.content[0].text
|
|
13723
|
+
: result.content,
|
|
13724
|
+
};
|
|
13725
|
+
}).reverse()) || [];
|
|
13726
|
+
}
|
|
13727
|
+
catch (error) {
|
|
13728
|
+
console.error(JSON.stringify(error));
|
|
13729
|
+
}
|
|
13730
|
+
// Ensures that the first AI response due to a Proactive prompt
|
|
13731
|
+
// doesn't show up as part of the chats
|
|
13732
|
+
if ((data === null || data === void 0 ? void 0 : data.proactive_prompt) &&
|
|
13733
|
+
previousChats.length > 0 &&
|
|
13734
|
+
previousChats[0].type === "ai") {
|
|
13735
|
+
previousChats.splice(0, 1);
|
|
13736
|
+
}
|
|
13737
|
+
dispatch(chatActions.setNewMessages(previousChats));
|
|
13738
|
+
}
|
|
13739
|
+
catch (error) {
|
|
13740
|
+
console.error(JSON.stringify(error));
|
|
13741
|
+
}
|
|
13742
|
+
};
|
|
13743
|
+
if (cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId]) {
|
|
13744
|
+
dispatch(chatActions.updateSessionIds(cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId]));
|
|
13745
|
+
getChats();
|
|
13746
|
+
}
|
|
13747
|
+
}, [cachedSessionId]);
|
|
13748
|
+
useEffect(() => {
|
|
13749
|
+
}, [isErrorGettingSessionChats]);
|
|
13750
|
+
useEffect(() => { }, []);
|
|
12936
13751
|
const startNewChat = React__default.useCallback(async () => {
|
|
12937
13752
|
// Reset all chat state
|
|
12938
13753
|
if (!showingSharedChat) {
|
|
@@ -12942,6 +13757,7 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
12942
13757
|
dispatch(chatActions.setStreaming(false));
|
|
12943
13758
|
dispatch(chatActions.resetCurrentStreamingMessage(undefined));
|
|
12944
13759
|
dispatch(chatActions.setTools([]));
|
|
13760
|
+
dispatch(clearFiles(undefined));
|
|
12945
13761
|
if (isPreviewMode) {
|
|
12946
13762
|
return;
|
|
12947
13763
|
}
|
|
@@ -12952,6 +13768,7 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
12952
13768
|
// @ts-ignore
|
|
12953
13769
|
requestBody["shareable_link_token"] = mentorShareableToken;
|
|
12954
13770
|
}
|
|
13771
|
+
console.log("[startNewChat] requestBody", tenantKey, username, JSON.stringify(requestBody));
|
|
12955
13772
|
const response = await createSessionId({
|
|
12956
13773
|
org: tenantKey,
|
|
12957
13774
|
// @ts-ignore
|
|
@@ -12959,10 +13776,15 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
12959
13776
|
requestBody,
|
|
12960
13777
|
}).unwrap();
|
|
12961
13778
|
dispatch(chatActions.updateSessionIds(response.session_id));
|
|
12962
|
-
|
|
13779
|
+
onStartNewChat === null || onStartNewChat === void 0 ? void 0 : onStartNewChat(response.session_id);
|
|
12963
13780
|
}
|
|
12964
13781
|
catch (error) {
|
|
12965
|
-
|
|
13782
|
+
if (mentorSettings.mentorVisibility !==
|
|
13783
|
+
MentorVisibilityEnum.VIEWABLE_BY_ANYONE) {
|
|
13784
|
+
errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler(`Failed to start new chat: ${JSON.stringify(error)}`);
|
|
13785
|
+
console.log("[auth-redirect] Failed to start new chat", JSON.stringify({ error }));
|
|
13786
|
+
redirectToAuthSpa(undefined, undefined, true);
|
|
13787
|
+
}
|
|
12966
13788
|
}
|
|
12967
13789
|
}, [
|
|
12968
13790
|
isPreviewMode,
|
|
@@ -12976,7 +13798,8 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
12976
13798
|
]);
|
|
12977
13799
|
React__default.useEffect(() => {
|
|
12978
13800
|
if (!showingSharedChat || mentorSettings.allowAnonymous) {
|
|
12979
|
-
if (mentorSettings.allowAnonymous !== undefined
|
|
13801
|
+
if (mentorSettings.allowAnonymous !== undefined &&
|
|
13802
|
+
!(cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId])) {
|
|
12980
13803
|
startNewChat();
|
|
12981
13804
|
}
|
|
12982
13805
|
}
|
|
@@ -13028,7 +13851,7 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
13028
13851
|
}
|
|
13029
13852
|
}
|
|
13030
13853
|
catch (error) {
|
|
13031
|
-
errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler(
|
|
13854
|
+
errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler(`Failed to start new chat: ${error}`);
|
|
13032
13855
|
return;
|
|
13033
13856
|
}
|
|
13034
13857
|
}
|
|
@@ -13048,9 +13871,9 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
13048
13871
|
currentStreamingMessage,
|
|
13049
13872
|
activeTab,
|
|
13050
13873
|
uniqueMentorId: mentorId,
|
|
13051
|
-
mentorName: (
|
|
13052
|
-
profileImage: (
|
|
13053
|
-
enabledGuidedPrompts: (
|
|
13874
|
+
mentorName: (_b = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.mentorName) !== null && _b !== void 0 ? _b : "",
|
|
13875
|
+
profileImage: (_c = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.profileImage) !== null && _c !== void 0 ? _c : "",
|
|
13876
|
+
enabledGuidedPrompts: (_d = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.enableGuidedPrompts) !== null && _d !== void 0 ? _d : true,
|
|
13054
13877
|
sendMessage,
|
|
13055
13878
|
stopGenerating,
|
|
13056
13879
|
setMessage,
|
|
@@ -13062,7 +13885,7 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
13062
13885
|
isConnected,
|
|
13063
13886
|
messageQueue,
|
|
13064
13887
|
sessionIds,
|
|
13065
|
-
enableSafetyDisclaimer: (
|
|
13888
|
+
enableSafetyDisclaimer: (_e = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.safetyDisclaimer) !== null && _e !== void 0 ? _e : false,
|
|
13066
13889
|
resetConnection,
|
|
13067
13890
|
};
|
|
13068
13891
|
}
|
|
@@ -17918,5 +18741,123 @@ const tenantSchema = z.object({
|
|
|
17918
18741
|
});
|
|
17919
18742
|
const tenantKeySchema = z.string().min(1);
|
|
17920
18743
|
|
|
17921
|
-
|
|
18744
|
+
/**
|
|
18745
|
+
* Chat area size constants
|
|
18746
|
+
*/
|
|
18747
|
+
const CHAT_AREA_SIZE = {
|
|
18748
|
+
DEFAULT: 672,
|
|
18749
|
+
MIN: 672,
|
|
18750
|
+
MAX: 1024,
|
|
18751
|
+
};
|
|
18752
|
+
|
|
18753
|
+
/**
|
|
18754
|
+
* Extract file information from File object
|
|
18755
|
+
*/
|
|
18756
|
+
function getFileInfo(file) {
|
|
18757
|
+
const fileName = file.name;
|
|
18758
|
+
const contentType = file.type || "application/octet-stream";
|
|
18759
|
+
const fileSize = file.size;
|
|
18760
|
+
return {
|
|
18761
|
+
fileName,
|
|
18762
|
+
contentType,
|
|
18763
|
+
fileSize,
|
|
18764
|
+
};
|
|
18765
|
+
}
|
|
18766
|
+
/**
|
|
18767
|
+
* Request presigned S3 URL from backend
|
|
18768
|
+
* Note: This function should be called via the RTK Query mutation hook
|
|
18769
|
+
* This is a helper to show the data flow
|
|
18770
|
+
*/
|
|
18771
|
+
async function requestPresignedUrl(sessionId, file, getUploadUrlFn, org, userId) {
|
|
18772
|
+
const { fileName, contentType, fileSize } = getFileInfo(file);
|
|
18773
|
+
return await getUploadUrlFn({
|
|
18774
|
+
org,
|
|
18775
|
+
userId,
|
|
18776
|
+
requestBody: {
|
|
18777
|
+
session_id: sessionId,
|
|
18778
|
+
file_name: fileName,
|
|
18779
|
+
content_type: contentType,
|
|
18780
|
+
file_size: fileSize,
|
|
18781
|
+
},
|
|
18782
|
+
});
|
|
18783
|
+
}
|
|
18784
|
+
/**
|
|
18785
|
+
* Upload file directly to S3 using presigned URL
|
|
18786
|
+
* Uses axios for cross-platform support (web + React Native)
|
|
18787
|
+
*/
|
|
18788
|
+
async function uploadToS3(presignedUrl, file, contentType, onProgress) {
|
|
18789
|
+
await axios.put(presignedUrl, file, {
|
|
18790
|
+
headers: {
|
|
18791
|
+
"Content-Type": contentType,
|
|
18792
|
+
},
|
|
18793
|
+
onUploadProgress: (progressEvent) => {
|
|
18794
|
+
if (onProgress && progressEvent.total) {
|
|
18795
|
+
const progress = Math.round((progressEvent.loaded / progressEvent.total) * 100);
|
|
18796
|
+
onProgress(progress);
|
|
18797
|
+
}
|
|
18798
|
+
},
|
|
18799
|
+
});
|
|
18800
|
+
}
|
|
18801
|
+
/**
|
|
18802
|
+
* Complete file upload flow:
|
|
18803
|
+
* 1. Request presigned URL
|
|
18804
|
+
* 2. Upload to S3
|
|
18805
|
+
* 3. Return file reference
|
|
18806
|
+
*/
|
|
18807
|
+
async function createFileReference(file, sessionId, getUploadUrlFn, org, userId, onProgress) {
|
|
18808
|
+
// Step 1: Get presigned URL
|
|
18809
|
+
const presignedResponse = await requestPresignedUrl(sessionId, file, getUploadUrlFn, org, userId);
|
|
18810
|
+
// Step 2: Upload to S3
|
|
18811
|
+
const { fileName, contentType, fileSize } = getFileInfo(file);
|
|
18812
|
+
await uploadToS3(presignedResponse.upload_url, file, contentType, onProgress);
|
|
18813
|
+
// Step 3: Return file reference
|
|
18814
|
+
return {
|
|
18815
|
+
file_id: presignedResponse.file_id,
|
|
18816
|
+
file_key: presignedResponse.file_key,
|
|
18817
|
+
file_name: fileName,
|
|
18818
|
+
content_type: contentType,
|
|
18819
|
+
file_size: fileSize,
|
|
18820
|
+
};
|
|
18821
|
+
}
|
|
18822
|
+
/**
|
|
18823
|
+
* Upload multiple files and return their references
|
|
18824
|
+
*/
|
|
18825
|
+
async function createMultipleFileReferences(files, sessionId, getUploadUrlFn, org, userId, onFileProgress) {
|
|
18826
|
+
const fileReferences = [];
|
|
18827
|
+
for (let i = 0; i < files.length; i++) {
|
|
18828
|
+
const file = files[i];
|
|
18829
|
+
const onProgress = onFileProgress
|
|
18830
|
+
? (progress) => onFileProgress(i, progress)
|
|
18831
|
+
: undefined;
|
|
18832
|
+
const fileReference = await createFileReference(file, sessionId, getUploadUrlFn, org, userId, onProgress);
|
|
18833
|
+
fileReferences.push(fileReference);
|
|
18834
|
+
}
|
|
18835
|
+
return fileReferences;
|
|
18836
|
+
}
|
|
18837
|
+
/**
|
|
18838
|
+
* Validate file before upload
|
|
18839
|
+
* Returns error message if invalid, null if valid
|
|
18840
|
+
*/
|
|
18841
|
+
function validateFile(file, maxSizeBytes, allowedTypes) {
|
|
18842
|
+
var _a;
|
|
18843
|
+
// Check file size
|
|
18844
|
+
if (maxSizeBytes && file.size > maxSizeBytes) {
|
|
18845
|
+
const maxSizeMB = (maxSizeBytes / (1024 * 1024)).toFixed(2);
|
|
18846
|
+
const fileSizeMB = (file.size / (1024 * 1024)).toFixed(2);
|
|
18847
|
+
return `File size (${fileSizeMB}MB) exceeds maximum allowed size (${maxSizeMB}MB)`;
|
|
18848
|
+
}
|
|
18849
|
+
// Check file type
|
|
18850
|
+
if (allowedTypes && allowedTypes.length > 0) {
|
|
18851
|
+
const fileExtension = (_a = file.name.split(".").pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
18852
|
+
const fileType = file.type.toLowerCase();
|
|
18853
|
+
const isTypeAllowed = allowedTypes.some((allowed) => fileType.includes(allowed.toLowerCase()) ||
|
|
18854
|
+
fileExtension === allowed.toLowerCase().replace(".", ""));
|
|
18855
|
+
if (!isTypeAllowed) {
|
|
18856
|
+
return `File type not allowed. Allowed types: ${allowedTypes.join(", ")}`;
|
|
18857
|
+
}
|
|
18858
|
+
}
|
|
18859
|
+
return null;
|
|
18860
|
+
}
|
|
18861
|
+
|
|
18862
|
+
export { ALPHANUMERIC_32_REGEX, ANONYMOUS_USERNAME, AuthContext, AuthContextProvider, AuthProvider, CHAT_AREA_SIZE, LOCAL_STORAGE_KEYS, MAX_INITIAL_WEBSOCKET_CONNECTION_ATTEMPTS, MENTOR_CHAT_DOCUMENTS_EXTENSIONS, METADATAS, MentorProvider, SUBSCRIPTION_MESSAGES, SUBSCRIPTION_PACKAGES, SUBSCRIPTION_TRIGGERS, SUBSCRIPTION_V2_TRIGGERS, SubscriptionFlow, SubscriptionFlowV2, TOOLS, TenantContext, TenantContextProvider, TenantProvider, TimeTracker, addFiles, addProtocolToUrl, advancedTabs, advancedTabsProperties, chatActions, chatSliceReducerShared, clearAuthCookies, clearCookies, clearCurrentTenantCookie, clearFiles, createFileReference, createMultipleFileReferences, defaultSessionIds, deleteCookie, deleteCookieOnAllDomains, filesReducer, filesSlice, formatRelativeTime, getAuthSpaJoinUrl, getDomainParts, getFileInfo, getInitials, getParentDomain, getPlatformKey, getTimeAgo, getUserName, handleLogout, isAlphaNumeric32, isInIframe, isJSON, isLoggedIn, loadMetadataConfig, redirectToAuthSpa, redirectToAuthSpaJoinTenant, removeFile, requestPresignedUrl, selectActiveChatMessages, selectActiveTab, selectChats, selectCurrentStreamingMessage, selectDocumentFilter, selectIframeContext, selectIsError, selectIsPending, selectIsStopped, selectIsTyping, selectNumberOfActiveChatMessages, selectSessionId, selectSessionIds, selectShouldStartNewChat, selectShowingSharedChat, selectStatus, selectStreaming, selectToken, selectTokenEnabled, selectTools, sendMessageToParentWebsite, setCookieForAuth, syncAuthToCookies, tenantKeySchema, tenantSchema, translatePrompt, updateFileMetadata, updateFileProgress, updateFileRetryCount, updateFileStatus, updateFileUrl, updateFileUrlFromWebSocket, uploadToS3, useAdvancedChat, useAuthContext, useAuthProvider, useChat, useDayJs, useExternalPricingPlan, useMentorSettings, useMentorTools, useProfileImageUpload, useSubscriptionHandler, useSubscriptionHandlerV2, useTenantContext, useTenantMetadata, useTimeTracker, useTimeTrackerNative, useUserProfileUpdate, userDataSchema, validateFile };
|
|
17922
18863
|
//# sourceMappingURL=index.esm.js.map
|