@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.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var React = require('react');
|
|
4
4
|
var iblaiApi = require('@iblai/iblai-api');
|
|
5
5
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
var axios = require('axios');
|
|
6
7
|
|
|
7
8
|
function _interopNamespaceDefault(e) {
|
|
8
9
|
var n = Object.create(null);
|
|
@@ -3400,7 +3401,7 @@ function updateMutationSubstateIfExists(state, id, update) {
|
|
|
3400
3401
|
update(substate);
|
|
3401
3402
|
}
|
|
3402
3403
|
}
|
|
3403
|
-
var initialState$
|
|
3404
|
+
var initialState$2 = {};
|
|
3404
3405
|
function buildSlice({
|
|
3405
3406
|
reducerPath,
|
|
3406
3407
|
queryThunk,
|
|
@@ -3476,7 +3477,7 @@ function buildSlice({
|
|
|
3476
3477
|
}
|
|
3477
3478
|
const querySlice = createSlice$1({
|
|
3478
3479
|
name: `${reducerPath}/queries`,
|
|
3479
|
-
initialState: initialState$
|
|
3480
|
+
initialState: initialState$2,
|
|
3480
3481
|
reducers: {
|
|
3481
3482
|
removeQueryResult: {
|
|
3482
3483
|
reducer(draft, {
|
|
@@ -3610,7 +3611,7 @@ function buildSlice({
|
|
|
3610
3611
|
});
|
|
3611
3612
|
const mutationSlice = createSlice$1({
|
|
3612
3613
|
name: `${reducerPath}/mutations`,
|
|
3613
|
-
initialState: initialState$
|
|
3614
|
+
initialState: initialState$2,
|
|
3614
3615
|
reducers: {
|
|
3615
3616
|
removeMutationResult: {
|
|
3616
3617
|
reducer(draft, {
|
|
@@ -3779,7 +3780,7 @@ function buildSlice({
|
|
|
3779
3780
|
}
|
|
3780
3781
|
const subscriptionSlice = createSlice$1({
|
|
3781
3782
|
name: `${reducerPath}/subscriptions`,
|
|
3782
|
-
initialState: initialState$
|
|
3783
|
+
initialState: initialState$2,
|
|
3783
3784
|
reducers: {
|
|
3784
3785
|
updateSubscriptionOptions(d, a) {
|
|
3785
3786
|
},
|
|
@@ -3791,7 +3792,7 @@ function buildSlice({
|
|
|
3791
3792
|
});
|
|
3792
3793
|
const internalSubscriptionsSlice = createSlice$1({
|
|
3793
3794
|
name: `${reducerPath}/internalSubscriptions`,
|
|
3794
|
-
initialState: initialState$
|
|
3795
|
+
initialState: initialState$2,
|
|
3795
3796
|
reducers: {
|
|
3796
3797
|
subscriptionsUpdated: {
|
|
3797
3798
|
reducer(state, action) {
|
|
@@ -6461,6 +6462,25 @@ createApi({
|
|
|
6461
6462
|
}),
|
|
6462
6463
|
});
|
|
6463
6464
|
|
|
6465
|
+
createApi({
|
|
6466
|
+
reducerPath: 'chatFilesApiSlice',
|
|
6467
|
+
baseQuery: iblFetchBaseQuery,
|
|
6468
|
+
endpoints: (builder) => ({
|
|
6469
|
+
/**
|
|
6470
|
+
* Get presigned S3 URL for file upload
|
|
6471
|
+
* POST /api/ai-mentor/orgs/{org}/users/{userId}/chat/files/upload-url/
|
|
6472
|
+
*/
|
|
6473
|
+
getFileUploadUrl: builder.mutation({
|
|
6474
|
+
query: ({ org, userId, requestBody, }) => ({
|
|
6475
|
+
url: `/api/ai-mentor/orgs/${org}/users/${userId}/chat/files/upload-url/`,
|
|
6476
|
+
method: 'POST',
|
|
6477
|
+
body: requestBody,
|
|
6478
|
+
service: SERVICES.DM,
|
|
6479
|
+
}),
|
|
6480
|
+
}),
|
|
6481
|
+
}),
|
|
6482
|
+
});
|
|
6483
|
+
|
|
6464
6484
|
createApi({
|
|
6465
6485
|
reducerPath: 'llmsApiSlice',
|
|
6466
6486
|
baseQuery: iblFakeBaseQuery,
|
|
@@ -6481,6 +6501,7 @@ const mentorApiSlice = createApi({
|
|
|
6481
6501
|
'mentorPublicSettings',
|
|
6482
6502
|
'shareableLinks',
|
|
6483
6503
|
'publicMentors',
|
|
6504
|
+
'moderationLogs',
|
|
6484
6505
|
],
|
|
6485
6506
|
endpoints: (builder) => ({
|
|
6486
6507
|
createMentor: builder.mutation({
|
|
@@ -6546,7 +6567,7 @@ const mentorApiSlice = createApi({
|
|
|
6546
6567
|
}));
|
|
6547
6568
|
}
|
|
6548
6569
|
catch (error) {
|
|
6549
|
-
console.error(error);
|
|
6570
|
+
console.error(JSON.stringify(error));
|
|
6550
6571
|
}
|
|
6551
6572
|
},
|
|
6552
6573
|
}),
|
|
@@ -6602,9 +6623,17 @@ const mentorApiSlice = createApi({
|
|
|
6602
6623
|
...buildEndpointFromDmService(iblaiApi.AiMentorService.aiMentorOrgsUsersMentorsForkCreate),
|
|
6603
6624
|
invalidatesTags: ['mentors'],
|
|
6604
6625
|
}),
|
|
6626
|
+
getRecentlyAccessedMentors: builder.query({
|
|
6627
|
+
...buildEndpointFromDmService(iblaiApi.AiMentorService.aiMentorOrgsUsersRecentlyAccessedMentorsList),
|
|
6628
|
+
providesTags: ['mentors'],
|
|
6629
|
+
}),
|
|
6630
|
+
getModerationLogs: builder.query({
|
|
6631
|
+
...buildEndpointFromDmService(iblaiApi.AiMentorService.aiMentorOrgsUsersModerationLogsList),
|
|
6632
|
+
providesTags: ['moderationLogs'],
|
|
6633
|
+
}),
|
|
6605
6634
|
}),
|
|
6606
6635
|
});
|
|
6607
|
-
const { useLazyGetMentorsQuery, useLazySeedMentorsQuery, useGetMentorSettingsQuery, useGetMentorPublicSettingsQuery, useLazyGetMentorPublicSettingsQuery, useLazyGetFreeUsageCountQuery} = mentorApiSlice;
|
|
6636
|
+
const { useLazyGetMentorsQuery, useLazySeedMentorsQuery, useGetMentorSettingsQuery, useGetMentorPublicSettingsQuery, useLazyGetMentorPublicSettingsQuery, useLazyGetFreeUsageCountQuery, useLazyGetRecentlyAccessedMentorsQuery} = mentorApiSlice;
|
|
6608
6637
|
|
|
6609
6638
|
createApi({
|
|
6610
6639
|
reducerPath: 'mentorCategoriesApiSlice',
|
|
@@ -7071,7 +7100,20 @@ const coreApiSlice = createApi({
|
|
|
7071
7100
|
invalidatesTags: ['RbacGroups'],
|
|
7072
7101
|
}),
|
|
7073
7102
|
getRbacGroupDetails: builder.query({
|
|
7074
|
-
...
|
|
7103
|
+
...buildEndpointFromService(SERVICES.DM, async (args) => {
|
|
7104
|
+
const url = `${iblaiApi.OpenAPI.BASE}/api/core/rbac/groups/${args.id}/`;
|
|
7105
|
+
const response = await fetch(url, {
|
|
7106
|
+
method: 'GET',
|
|
7107
|
+
headers: iblaiApi.OpenAPI.HEADERS,
|
|
7108
|
+
});
|
|
7109
|
+
if (!response.ok) {
|
|
7110
|
+
const error = new Error('Failed to fetch RBAC group details');
|
|
7111
|
+
error.status = response.status;
|
|
7112
|
+
error.body = await response.text();
|
|
7113
|
+
throw error;
|
|
7114
|
+
}
|
|
7115
|
+
return response.json();
|
|
7116
|
+
}),
|
|
7075
7117
|
providesTags: ['RbacGroups'],
|
|
7076
7118
|
}),
|
|
7077
7119
|
//RBAC POLICIES
|
|
@@ -7092,7 +7134,22 @@ const coreApiSlice = createApi({
|
|
|
7092
7134
|
invalidatesTags: ['RbacPolicies'],
|
|
7093
7135
|
}),
|
|
7094
7136
|
getRbacPolicyDetails: builder.query({
|
|
7095
|
-
...
|
|
7137
|
+
...buildEndpointFromService(SERVICES.DM, async (args) => {
|
|
7138
|
+
const queryParams = new URLSearchParams({ platform_key: args.platform_key });
|
|
7139
|
+
const queryString = queryParams.toString();
|
|
7140
|
+
const url = `${iblaiApi.OpenAPI.BASE}/api/core/rbac/policies/${args.id}/?${queryString}`;
|
|
7141
|
+
const response = await fetch(url, {
|
|
7142
|
+
method: 'GET',
|
|
7143
|
+
headers: iblaiApi.OpenAPI.HEADERS,
|
|
7144
|
+
});
|
|
7145
|
+
if (!response.ok) {
|
|
7146
|
+
const error = new Error('Failed to fetch RBAC policy details');
|
|
7147
|
+
error.status = response.status;
|
|
7148
|
+
error.body = await response.text();
|
|
7149
|
+
throw error;
|
|
7150
|
+
}
|
|
7151
|
+
return response.json();
|
|
7152
|
+
}),
|
|
7096
7153
|
providesTags: ['RbacPolicies'],
|
|
7097
7154
|
}),
|
|
7098
7155
|
//RBAC ROLES
|
|
@@ -7117,14 +7174,36 @@ const coreApiSlice = createApi({
|
|
|
7117
7174
|
invalidatesTags: ['RbacRoles'],
|
|
7118
7175
|
}),
|
|
7119
7176
|
getRbacRoleDetails: builder.query({
|
|
7120
|
-
...
|
|
7177
|
+
...buildEndpointFromService(SERVICES.DM, async (args) => {
|
|
7178
|
+
const queryParams = new URLSearchParams({ platform_key: args.platform_key });
|
|
7179
|
+
const queryString = queryParams.toString();
|
|
7180
|
+
const url = `${iblaiApi.OpenAPI.BASE}/api/core/rbac/roles/${args.id}/?${queryString}`;
|
|
7181
|
+
const response = await fetch(url, {
|
|
7182
|
+
method: 'GET',
|
|
7183
|
+
headers: iblaiApi.OpenAPI.HEADERS,
|
|
7184
|
+
});
|
|
7185
|
+
if (!response.ok) {
|
|
7186
|
+
const error = new Error('Failed to fetch RBAC role details');
|
|
7187
|
+
error.status = response.status;
|
|
7188
|
+
error.body = await response.text();
|
|
7189
|
+
throw error;
|
|
7190
|
+
}
|
|
7191
|
+
return response.json();
|
|
7192
|
+
}),
|
|
7121
7193
|
providesTags: ['RbacRoles'],
|
|
7122
7194
|
}),
|
|
7195
|
+
getRbacMentorAccessList: builder.query({
|
|
7196
|
+
...buildEndpointFromDmService(iblaiApi.CoreService.coreRbacMentorAccessList),
|
|
7197
|
+
}),
|
|
7198
|
+
updateRbacMentorAccess: builder.mutation({
|
|
7199
|
+
...buildEndpointFromDmService(iblaiApi.CoreService.coreRbacMentorAccessCreate),
|
|
7200
|
+
}),
|
|
7123
7201
|
}),
|
|
7124
7202
|
});
|
|
7125
7203
|
const { useGetRbacPermissionsMutation} = coreApiSlice;
|
|
7126
7204
|
|
|
7127
7205
|
const CORE_CUSTOM_REDUCER_PATH = 'coreCustomApiSlice';
|
|
7206
|
+
const CORE_FAKE_CUSTOM_REDUCER_PATH = 'coreFakeCustomApiSlice';
|
|
7128
7207
|
const PLATFORM_MEMBERSHIP_TAG = 'PlatformMembership';
|
|
7129
7208
|
const CORE_CUSTOM_ENDPOINTS = {
|
|
7130
7209
|
GET_PLATFORM_MEMBERSHIP: {
|
|
@@ -7158,7 +7237,13 @@ const CORE_CUSTOM_ENDPOINTS = {
|
|
|
7158
7237
|
DELETE_PLATFORM_IMAGE_ASSET: {
|
|
7159
7238
|
path: (platform_key, asset_id) => `/api/core/platforms/${platform_key}/public-image-assets/${asset_id}/`,
|
|
7160
7239
|
service: SERVICES.DM,
|
|
7161
|
-
}
|
|
7240
|
+
},
|
|
7241
|
+
GET_PUBLIC_PLATFORM_IMAGE_ASSET_FILE_URL: {
|
|
7242
|
+
path: (platform_key, asset_id) => `/api/core/platforms/${platform_key}/public-image-assets/${asset_id}/file/`,
|
|
7243
|
+
baseUrl: getServiceUrl(SERVICES.DM),
|
|
7244
|
+
service: SERVICES.DM,
|
|
7245
|
+
},
|
|
7246
|
+
};
|
|
7162
7247
|
|
|
7163
7248
|
createApi({
|
|
7164
7249
|
// TODO: replace to catalogSlice
|
|
@@ -7230,7 +7315,13 @@ createApi({
|
|
|
7230
7315
|
...buildEndpointFromDmService(iblaiApi.AiAccountService.aiAccountOrgsIntegrationCredentialPartialUpdate),
|
|
7231
7316
|
}),
|
|
7232
7317
|
getConnectedServiceAuthUrl: builder.query({
|
|
7233
|
-
|
|
7318
|
+
queryFn: async (queryParams, api, extraOptions) => {
|
|
7319
|
+
const url = `/api/ai-account/connected-services/orgs/${queryParams.org}/users/${queryParams.userId}/${queryParams.provider}/${queryParams.service}/`;
|
|
7320
|
+
return iblFetchBaseQuery({
|
|
7321
|
+
url,
|
|
7322
|
+
service: SERVICES.DM,
|
|
7323
|
+
}, api, extraOptions);
|
|
7324
|
+
},
|
|
7234
7325
|
}),
|
|
7235
7326
|
connectedServicesCallback: builder.query({
|
|
7236
7327
|
queryFn: async (queryParams, api, extraOptions) => {
|
|
@@ -7324,10 +7415,11 @@ const stripeApiSlice = createApi({
|
|
|
7324
7415
|
providesTags: ['stripe-context'],
|
|
7325
7416
|
}),
|
|
7326
7417
|
getStripePricingPageSession: builder.query({
|
|
7327
|
-
query: ({ platform_key }) => ({
|
|
7418
|
+
query: ({ platform_key, params }) => ({
|
|
7328
7419
|
url: STRIPE_ENDPOINTS.GET_STRIPE_PRICING_PAGE_SESSION.path(platform_key),
|
|
7329
7420
|
service: STRIPE_ENDPOINTS.GET_STRIPE_PRICING_PAGE_SESSION.service,
|
|
7330
7421
|
method: 'GET',
|
|
7422
|
+
params,
|
|
7331
7423
|
}),
|
|
7332
7424
|
providesTags: ['stripe-context'],
|
|
7333
7425
|
}),
|
|
@@ -7362,7 +7454,7 @@ const sessionApiSlice = createApi({
|
|
|
7362
7454
|
}),
|
|
7363
7455
|
}),
|
|
7364
7456
|
});
|
|
7365
|
-
const { useCreateSessionIdMutation, useEditSessionMutation, } = sessionApiSlice;
|
|
7457
|
+
const { useCreateSessionIdMutation, useLazyGetSessionIdQuery, useEditSessionMutation, } = sessionApiSlice;
|
|
7366
7458
|
|
|
7367
7459
|
createApi({
|
|
7368
7460
|
reducerPath: 'datasetsApiSlice',
|
|
@@ -8299,6 +8391,12 @@ createApi({
|
|
|
8299
8391
|
});
|
|
8300
8392
|
|
|
8301
8393
|
const NOTIFICATIONS_CUSTOM_REDUCER_PATH = 'notificationsCustomApiSlice';
|
|
8394
|
+
const NOTIFICATIONS_CUSTOM_TAGS = {
|
|
8395
|
+
TEMPLATES: 'NOTIFICATIONS_CUSTOM_TEMPLATES',
|
|
8396
|
+
TEMPLATE_DETAILS: 'NOTIFICATIONS_CUSTOM_TEMPLATE_DETAILS',
|
|
8397
|
+
UPDATE_TEMPLATE: 'NOTIFICATIONS_CUSTOM_UPDATE_TEMPLATE',
|
|
8398
|
+
TOGGLE_TEMPLATE: 'NOTIFICATIONS_CUSTOM_TOGGLE_TEMPLATE',
|
|
8399
|
+
};
|
|
8302
8400
|
const NOTIFICATIONS_CUSTOM_ENDPOINTS = {
|
|
8303
8401
|
GET_TEMPLATES: {
|
|
8304
8402
|
service: SERVICES.DM,
|
|
@@ -8320,6 +8418,7 @@ const NOTIFICATIONS_CUSTOM_ENDPOINTS = {
|
|
|
8320
8418
|
|
|
8321
8419
|
createApi({
|
|
8322
8420
|
reducerPath: NOTIFICATIONS_CUSTOM_REDUCER_PATH,
|
|
8421
|
+
tagTypes: [...Object.values(NOTIFICATIONS_CUSTOM_TAGS)],
|
|
8323
8422
|
baseQuery: iblFetchBaseQuery,
|
|
8324
8423
|
endpoints: (builder) => ({
|
|
8325
8424
|
getTemplates: builder.query({
|
|
@@ -8329,6 +8428,7 @@ createApi({
|
|
|
8329
8428
|
service: NOTIFICATIONS_CUSTOM_ENDPOINTS.GET_TEMPLATES.service,
|
|
8330
8429
|
};
|
|
8331
8430
|
},
|
|
8431
|
+
providesTags: [NOTIFICATIONS_CUSTOM_TAGS.TEMPLATES],
|
|
8332
8432
|
}),
|
|
8333
8433
|
getTemplateDetails: builder.query({
|
|
8334
8434
|
query: (args) => {
|
|
@@ -8337,6 +8437,7 @@ createApi({
|
|
|
8337
8437
|
service: NOTIFICATIONS_CUSTOM_ENDPOINTS.GET_TEMPLATE_DETAILS.service,
|
|
8338
8438
|
};
|
|
8339
8439
|
},
|
|
8440
|
+
providesTags: [NOTIFICATIONS_CUSTOM_TAGS.TEMPLATE_DETAILS],
|
|
8340
8441
|
}),
|
|
8341
8442
|
updateTemplate: builder.mutation({
|
|
8342
8443
|
query: (args) => {
|
|
@@ -8347,6 +8448,7 @@ createApi({
|
|
|
8347
8448
|
body: args.template,
|
|
8348
8449
|
};
|
|
8349
8450
|
},
|
|
8451
|
+
invalidatesTags: [NOTIFICATIONS_CUSTOM_TAGS.TEMPLATE_DETAILS],
|
|
8350
8452
|
}),
|
|
8351
8453
|
toggleTemplate: builder.mutation({
|
|
8352
8454
|
query: (args) => {
|
|
@@ -8359,6 +8461,7 @@ createApi({
|
|
|
8359
8461
|
},
|
|
8360
8462
|
};
|
|
8361
8463
|
},
|
|
8464
|
+
invalidatesTags: [NOTIFICATIONS_CUSTOM_TAGS.TEMPLATES],
|
|
8362
8465
|
}),
|
|
8363
8466
|
}),
|
|
8364
8467
|
});
|
|
@@ -8639,7 +8742,7 @@ const CUSTOM_DOMAIN_QUERY_KEYS = {
|
|
|
8639
8742
|
CREATE_CUSTOM_DOMAIN: () => ['CREATE_CUSTOM_DOMAIN'],
|
|
8640
8743
|
};
|
|
8641
8744
|
|
|
8642
|
-
createApi({
|
|
8745
|
+
const customDomainApiSlice = createApi({
|
|
8643
8746
|
reducerPath: CUSTOM_DOMAIN_REDUCER_PATH,
|
|
8644
8747
|
baseQuery: iblFetchBaseQuery,
|
|
8645
8748
|
tagTypes: [...CUSTOM_DOMAIN_QUERY_KEYS.GET_CUSTOM_DOMAINS()],
|
|
@@ -8678,6 +8781,7 @@ createApi({
|
|
|
8678
8781
|
}),
|
|
8679
8782
|
}),
|
|
8680
8783
|
});
|
|
8784
|
+
const { useGetCustomDomainsQuery} = customDomainApiSlice;
|
|
8681
8785
|
|
|
8682
8786
|
const PLATFORM_CUSTOM_REDUCER_PATH = "platformCustomApiSlice";
|
|
8683
8787
|
const PLATFORM_CONFIGURATION_TAG = "PlatformConfiguration";
|
|
@@ -8740,7 +8844,7 @@ createApi({
|
|
|
8740
8844
|
const coreCustomApiSlice = createApi({
|
|
8741
8845
|
reducerPath: CORE_CUSTOM_REDUCER_PATH,
|
|
8742
8846
|
baseQuery: iblFetchBaseQuery,
|
|
8743
|
-
tagTypes: [PLATFORM_MEMBERSHIP_TAG],
|
|
8847
|
+
tagTypes: [PLATFORM_MEMBERSHIP_TAG, 'PlatformImageAssetFileUrl'],
|
|
8744
8848
|
endpoints: (builder) => ({
|
|
8745
8849
|
getPlatformMembership: builder.query({
|
|
8746
8850
|
query: ({ platform_key }) => ({
|
|
@@ -8813,6 +8917,19 @@ const coreCustomApiSlice = createApi({
|
|
|
8813
8917
|
});
|
|
8814
8918
|
const { useJoinTenantMutation} = coreCustomApiSlice;
|
|
8815
8919
|
|
|
8920
|
+
createApi({
|
|
8921
|
+
reducerPath: CORE_FAKE_CUSTOM_REDUCER_PATH,
|
|
8922
|
+
baseQuery: iblFakeBaseQuery,
|
|
8923
|
+
endpoints: (builder) => ({
|
|
8924
|
+
getPublicPlatformImageAssetFileUrl: builder.query({
|
|
8925
|
+
...buildEndpointFromService(SERVICES.DM, async (args) => {
|
|
8926
|
+
const url = `${iblaiApi.OpenAPI.BASE}${CORE_CUSTOM_ENDPOINTS.GET_PUBLIC_PLATFORM_IMAGE_ASSET_FILE_URL.path(args.platform_key, args.asset_id)}`;
|
|
8927
|
+
return url;
|
|
8928
|
+
}),
|
|
8929
|
+
}),
|
|
8930
|
+
}),
|
|
8931
|
+
});
|
|
8932
|
+
|
|
8816
8933
|
const EDX_PROCTORING_ENDPOINTS = {
|
|
8817
8934
|
GET_EXAM_INFO: {
|
|
8818
8935
|
service: SERVICES.LMS,
|
|
@@ -9735,6 +9852,7 @@ const useSubscriptionHandlerV2 = (subscriptionFlow) => {
|
|
|
9735
9852
|
});
|
|
9736
9853
|
}
|
|
9737
9854
|
catch (error) {
|
|
9855
|
+
console.error("Error getting user active app:", JSON.stringify(error));
|
|
9738
9856
|
return null;
|
|
9739
9857
|
}
|
|
9740
9858
|
};
|
|
@@ -9781,6 +9899,7 @@ const useSubscriptionHandlerV2 = (subscriptionFlow) => {
|
|
|
9781
9899
|
return await getUserActiveApp();
|
|
9782
9900
|
}
|
|
9783
9901
|
catch (error) {
|
|
9902
|
+
console.error("Error updating trial status:", JSON.stringify(error));
|
|
9784
9903
|
return null;
|
|
9785
9904
|
}
|
|
9786
9905
|
};
|
|
@@ -9873,6 +9992,7 @@ const useSubscriptionHandlerV2 = (subscriptionFlow) => {
|
|
|
9873
9992
|
return stripeContext.payment_link_url;
|
|
9874
9993
|
}
|
|
9875
9994
|
catch (error) {
|
|
9995
|
+
console.error("Error getting top up URL:", JSON.stringify(error));
|
|
9876
9996
|
return null;
|
|
9877
9997
|
}
|
|
9878
9998
|
};
|
|
@@ -9946,6 +10066,7 @@ const useSubscriptionHandlerV2 = (subscriptionFlow) => {
|
|
|
9946
10066
|
return stripeCustomerPortal === null || stripeCustomerPortal === void 0 ? void 0 : stripeCustomerPortal.url;
|
|
9947
10067
|
}
|
|
9948
10068
|
catch (error) {
|
|
10069
|
+
console.error("Error getting billing URL:", JSON.stringify(error));
|
|
9949
10070
|
return null;
|
|
9950
10071
|
}
|
|
9951
10072
|
};
|
|
@@ -9991,7 +10112,10 @@ const useSubscriptionHandlerV2 = (subscriptionFlow) => {
|
|
|
9991
10112
|
try {
|
|
9992
10113
|
subscriptionFlow.handleBeforePricingPageDisplayFlow();
|
|
9993
10114
|
const { data: stripeContext } = await getStripePricingPageSession({
|
|
9994
|
-
platform_key: subscriptionFlow.
|
|
10115
|
+
platform_key: subscriptionFlow.getMainTenantKey(),
|
|
10116
|
+
params: {
|
|
10117
|
+
source_platform_key: subscriptionFlow.getCurrentTenantKey(),
|
|
10118
|
+
},
|
|
9995
10119
|
}, false);
|
|
9996
10120
|
if (isStripeContextError ||
|
|
9997
10121
|
!stripeContext ||
|
|
@@ -10004,6 +10128,7 @@ const useSubscriptionHandlerV2 = (subscriptionFlow) => {
|
|
|
10004
10128
|
}, !hasCredits);
|
|
10005
10129
|
}
|
|
10006
10130
|
catch (error) {
|
|
10131
|
+
console.error("Error getting stripe pricing page session:", JSON.stringify(error));
|
|
10007
10132
|
subscriptionFlow.handleFailureOnPaymentFlow();
|
|
10008
10133
|
}
|
|
10009
10134
|
};
|
|
@@ -10325,6 +10450,299 @@ const formatRelativeTime = (timestamp) => {
|
|
|
10325
10450
|
return `${diffInYears} year${diffInYears === 1 ? "" : "s"} ago`;
|
|
10326
10451
|
};
|
|
10327
10452
|
|
|
10453
|
+
/**
|
|
10454
|
+
* Authentication and Authorization Utilities
|
|
10455
|
+
*
|
|
10456
|
+
* This module provides utility functions for handling authentication flows,
|
|
10457
|
+
* including redirects to auth SPA, cookie management, and session handling.
|
|
10458
|
+
*/
|
|
10459
|
+
/**
|
|
10460
|
+
* Check if the current window is inside an iframe
|
|
10461
|
+
* @returns {boolean} True if running in an iframe, false otherwise
|
|
10462
|
+
*/
|
|
10463
|
+
function isInIframe() {
|
|
10464
|
+
if (typeof window === "undefined") {
|
|
10465
|
+
return false;
|
|
10466
|
+
}
|
|
10467
|
+
return (window === null || window === void 0 ? void 0 : window.self) !== (window === null || window === void 0 ? void 0 : window.top);
|
|
10468
|
+
}
|
|
10469
|
+
/**
|
|
10470
|
+
* Send a message to the parent website (when in iframe)
|
|
10471
|
+
* @param payload - The data to send to parent window
|
|
10472
|
+
*/
|
|
10473
|
+
function sendMessageToParentWebsite(payload) {
|
|
10474
|
+
window.parent.postMessage(payload, "*");
|
|
10475
|
+
}
|
|
10476
|
+
/**
|
|
10477
|
+
* Delete a cookie with specific name, path, and domain
|
|
10478
|
+
* @param name - Cookie name
|
|
10479
|
+
* @param path - Cookie path
|
|
10480
|
+
* @param domain - Cookie domain
|
|
10481
|
+
*/
|
|
10482
|
+
function deleteCookie(name, path, domain) {
|
|
10483
|
+
const expires = "expires=Thu, 01 Jan 1970 00:00:00 UTC;";
|
|
10484
|
+
const cookieValue = `${name}=;`;
|
|
10485
|
+
const pathValue = path ? `path=${path};` : "";
|
|
10486
|
+
const domainValue = domain ? `domain=${domain};` : "";
|
|
10487
|
+
document.cookie = cookieValue + expires + pathValue + domainValue;
|
|
10488
|
+
}
|
|
10489
|
+
/**
|
|
10490
|
+
* Get all possible domain parts for cookie deletion
|
|
10491
|
+
* @param domain - The domain to split
|
|
10492
|
+
* @returns Array of domain parts
|
|
10493
|
+
* @example
|
|
10494
|
+
* getDomainParts('app.example.com') // returns ['app.example.com', 'example.com', 'com']
|
|
10495
|
+
*/
|
|
10496
|
+
function getDomainParts(domain) {
|
|
10497
|
+
const parts = domain.split(".");
|
|
10498
|
+
const domains = [];
|
|
10499
|
+
for (let i = parts.length - 1; i >= 0; i--) {
|
|
10500
|
+
domains.push(parts.slice(i).join("."));
|
|
10501
|
+
}
|
|
10502
|
+
return domains;
|
|
10503
|
+
}
|
|
10504
|
+
/**
|
|
10505
|
+
* Delete a cookie across all possible domain variations
|
|
10506
|
+
* @param name - Cookie name to delete
|
|
10507
|
+
* @param childDomain - The current domain
|
|
10508
|
+
*/
|
|
10509
|
+
function deleteCookieOnAllDomains(name, childDomain) {
|
|
10510
|
+
getDomainParts(childDomain).forEach((domainPart) => {
|
|
10511
|
+
deleteCookie(name, "/", domainPart);
|
|
10512
|
+
deleteCookie(name, "", domainPart);
|
|
10513
|
+
});
|
|
10514
|
+
}
|
|
10515
|
+
/**
|
|
10516
|
+
* Get the parent domain from a given domain
|
|
10517
|
+
* @param domain - The domain to process
|
|
10518
|
+
* @returns The parent domain (e.g., 'app.example.com' → '.example.com')
|
|
10519
|
+
*/
|
|
10520
|
+
function getParentDomain(domain) {
|
|
10521
|
+
if (!domain) {
|
|
10522
|
+
return "";
|
|
10523
|
+
}
|
|
10524
|
+
const parts = domain.split(".");
|
|
10525
|
+
return parts.length > 1 ? `.${parts.slice(-2).join(".")}` : domain;
|
|
10526
|
+
}
|
|
10527
|
+
/**
|
|
10528
|
+
* Set a cookie for authentication with cross-domain support
|
|
10529
|
+
* @param name - Cookie name
|
|
10530
|
+
* @param value - Cookie value
|
|
10531
|
+
* @param days - Number of days until expiration (default: 365)
|
|
10532
|
+
*/
|
|
10533
|
+
function setCookieForAuth(name, value, days = 365) {
|
|
10534
|
+
const expires = new Date();
|
|
10535
|
+
expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000);
|
|
10536
|
+
const hostname = window.location.hostname;
|
|
10537
|
+
let baseDomain = hostname;
|
|
10538
|
+
// Calculate base domain (skip for localhost and IP addresses)
|
|
10539
|
+
if (hostname !== "localhost" && !/^\d+\.\d+\.\d+\.\d+$/.test(hostname)) {
|
|
10540
|
+
const parts = hostname.split(".");
|
|
10541
|
+
if (parts.length > 2) {
|
|
10542
|
+
baseDomain = `.${parts.slice(-2).join(".")}`;
|
|
10543
|
+
}
|
|
10544
|
+
}
|
|
10545
|
+
const domainAttr = baseDomain ? `;domain=${baseDomain}` : "";
|
|
10546
|
+
document.cookie = `${name}=${encodeURIComponent(value)};expires=${expires.toUTCString()};path=/;SameSite=None;Secure${domainAttr}`;
|
|
10547
|
+
}
|
|
10548
|
+
/**
|
|
10549
|
+
* Clear all cookies for the current domain
|
|
10550
|
+
*/
|
|
10551
|
+
function clearCookies() {
|
|
10552
|
+
const cookies = document.cookie.split(";");
|
|
10553
|
+
for (let i = 0; i < cookies.length; i++) {
|
|
10554
|
+
const cookie = cookies[i];
|
|
10555
|
+
const eqPos = cookie.indexOf("=");
|
|
10556
|
+
const name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie;
|
|
10557
|
+
deleteCookieOnAllDomains(name, window.location.hostname);
|
|
10558
|
+
document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/;Domain=${getParentDomain(window.location.hostname)}`;
|
|
10559
|
+
}
|
|
10560
|
+
}
|
|
10561
|
+
/**
|
|
10562
|
+
* Check if user is currently logged in
|
|
10563
|
+
* @param tokenKey - The localStorage key for the auth token (default: 'axd_token')
|
|
10564
|
+
* @returns True if logged in, false otherwise
|
|
10565
|
+
*/
|
|
10566
|
+
function isLoggedIn(tokenKey = "axd_token") {
|
|
10567
|
+
return !!localStorage.getItem(tokenKey);
|
|
10568
|
+
}
|
|
10569
|
+
/**
|
|
10570
|
+
* Extract platform/tenant key from URL
|
|
10571
|
+
* @param url - The URL to parse
|
|
10572
|
+
* @param pattern - RegExp pattern to match platform key (default matches /platform/[key]/...)
|
|
10573
|
+
* @returns The platform key or null if not found
|
|
10574
|
+
*/
|
|
10575
|
+
function getPlatformKey(url, pattern = /\/platform\/([^/]+)/) {
|
|
10576
|
+
const match = url.match(pattern);
|
|
10577
|
+
return match ? match[1] : null;
|
|
10578
|
+
}
|
|
10579
|
+
/**
|
|
10580
|
+
* Redirect to authentication SPA for login/logout
|
|
10581
|
+
*
|
|
10582
|
+
* This function handles the complete authentication flow:
|
|
10583
|
+
* - Clears localStorage and cookies on logout
|
|
10584
|
+
* - Saves redirect path for post-auth return
|
|
10585
|
+
* - Handles iframe scenarios
|
|
10586
|
+
* - Syncs logout across multiple SPAs via cookies
|
|
10587
|
+
*
|
|
10588
|
+
* @param options - Configuration options for the redirect
|
|
10589
|
+
*
|
|
10590
|
+
* @example
|
|
10591
|
+
* ```tsx
|
|
10592
|
+
* // Basic usage
|
|
10593
|
+
* redirectToAuthSpa({
|
|
10594
|
+
* authUrl: 'https://auth.example.com',
|
|
10595
|
+
* appName: 'mentor',
|
|
10596
|
+
* });
|
|
10597
|
+
*
|
|
10598
|
+
* // With logout
|
|
10599
|
+
* redirectToAuthSpa({
|
|
10600
|
+
* authUrl: 'https://auth.example.com',
|
|
10601
|
+
* appName: 'mentor',
|
|
10602
|
+
* logout: true,
|
|
10603
|
+
* platformKey: 'my-tenant',
|
|
10604
|
+
* });
|
|
10605
|
+
*
|
|
10606
|
+
* // With custom redirect
|
|
10607
|
+
* redirectToAuthSpa({
|
|
10608
|
+
* authUrl: 'https://auth.example.com',
|
|
10609
|
+
* appName: 'mentor',
|
|
10610
|
+
* redirectTo: '/dashboard',
|
|
10611
|
+
* platformKey: 'my-tenant',
|
|
10612
|
+
* });
|
|
10613
|
+
* ```
|
|
10614
|
+
*/
|
|
10615
|
+
async function redirectToAuthSpa(options) {
|
|
10616
|
+
const { redirectTo, platformKey, logout = false, saveRedirect = true, authUrl, appName, queryParams = {
|
|
10617
|
+
app: "app",
|
|
10618
|
+
redirectTo: "redirect-to",
|
|
10619
|
+
tenant: "tenant",
|
|
10620
|
+
}, redirectPathStorageKey = "redirect_to", cookieNames = {
|
|
10621
|
+
currentTenant: "ibl_current_tenant",
|
|
10622
|
+
userData: "ibl_user_data",
|
|
10623
|
+
tenant: "ibl_tenant",
|
|
10624
|
+
logoutTimestamp: "ibl_logout_timestamp",
|
|
10625
|
+
}, } = options;
|
|
10626
|
+
// Clear localStorage
|
|
10627
|
+
localStorage.clear();
|
|
10628
|
+
if (logout) {
|
|
10629
|
+
// Delete authentication cookies for cross-SPA synchronization
|
|
10630
|
+
const currentDomain = window.location.hostname;
|
|
10631
|
+
if (cookieNames.currentTenant) {
|
|
10632
|
+
deleteCookieOnAllDomains(cookieNames.currentTenant, currentDomain);
|
|
10633
|
+
}
|
|
10634
|
+
if (cookieNames.userData) {
|
|
10635
|
+
deleteCookieOnAllDomains(cookieNames.userData, currentDomain);
|
|
10636
|
+
}
|
|
10637
|
+
if (cookieNames.tenant) {
|
|
10638
|
+
deleteCookieOnAllDomains(cookieNames.tenant, currentDomain);
|
|
10639
|
+
}
|
|
10640
|
+
// Set logout timestamp cookie to trigger logout on other SPAs
|
|
10641
|
+
if (cookieNames.logoutTimestamp) {
|
|
10642
|
+
setCookieForAuth(cookieNames.logoutTimestamp, Date.now().toString());
|
|
10643
|
+
}
|
|
10644
|
+
}
|
|
10645
|
+
// Handle iframe scenario
|
|
10646
|
+
if (isInIframe()) {
|
|
10647
|
+
console.log("[redirectToAuthSpa]: sending authExpired to parent");
|
|
10648
|
+
sendMessageToParentWebsite({ authExpired: true });
|
|
10649
|
+
return;
|
|
10650
|
+
}
|
|
10651
|
+
const redirectPath = redirectTo !== null && redirectTo !== void 0 ? redirectTo : `${window.location.pathname}${window.location.search}`;
|
|
10652
|
+
// Never save sso-login routes as redirect paths
|
|
10653
|
+
if (!redirectPath.startsWith("/sso-login") && saveRedirect) {
|
|
10654
|
+
window.localStorage.setItem(redirectPathStorageKey, redirectPath);
|
|
10655
|
+
}
|
|
10656
|
+
const platform = platformKey !== null && platformKey !== void 0 ? platformKey : getPlatformKey(redirectPath);
|
|
10657
|
+
const redirectToUrl = `${window.location.origin}`;
|
|
10658
|
+
let authRedirectUrl = `${authUrl}/login?${queryParams.app}=${appName}`;
|
|
10659
|
+
authRedirectUrl += `&${queryParams.redirectTo}=${redirectToUrl}`;
|
|
10660
|
+
if (platform) {
|
|
10661
|
+
authRedirectUrl += `&${queryParams.tenant}=${platform}`;
|
|
10662
|
+
}
|
|
10663
|
+
if (logout) {
|
|
10664
|
+
authRedirectUrl += "&logout=1";
|
|
10665
|
+
}
|
|
10666
|
+
// Small delay for any pending operations
|
|
10667
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
10668
|
+
// Redirect to auth SPA
|
|
10669
|
+
window.location.href = authRedirectUrl;
|
|
10670
|
+
}
|
|
10671
|
+
/**
|
|
10672
|
+
* Get the URL for joining a tenant (sign up flow)
|
|
10673
|
+
* @param authUrl - Auth SPA base URL
|
|
10674
|
+
* @param tenantKey - Tenant to join
|
|
10675
|
+
* @param redirectUrl - URL to redirect to after joining (defaults to current URL)
|
|
10676
|
+
* @returns The join URL
|
|
10677
|
+
*/
|
|
10678
|
+
function getAuthSpaJoinUrl(authUrl, tenantKey, redirectUrl) {
|
|
10679
|
+
const resolvedTenant = tenantKey || getPlatformKey(window.location.pathname) || "";
|
|
10680
|
+
if (!resolvedTenant) {
|
|
10681
|
+
return "";
|
|
10682
|
+
}
|
|
10683
|
+
const targetUrl = redirectUrl !== null && redirectUrl !== void 0 ? redirectUrl : window.location.href;
|
|
10684
|
+
const joinUrl = `${authUrl}/join?tenant=${encodeURIComponent(resolvedTenant)}&redirect-to=${encodeURIComponent(targetUrl)}`;
|
|
10685
|
+
return joinUrl;
|
|
10686
|
+
}
|
|
10687
|
+
/**
|
|
10688
|
+
* Redirect to auth SPA's join/signup page for a specific tenant
|
|
10689
|
+
* @param authUrl - Auth SPA base URL
|
|
10690
|
+
* @param tenantKey - Tenant to join
|
|
10691
|
+
* @param redirectUrl - URL to redirect to after joining (defaults to current URL)
|
|
10692
|
+
*/
|
|
10693
|
+
function redirectToAuthSpaJoinTenant(authUrl, tenantKey, redirectUrl) {
|
|
10694
|
+
const resolvedTenant = tenantKey || getPlatformKey(window.location.pathname) || "";
|
|
10695
|
+
if (!resolvedTenant) {
|
|
10696
|
+
console.log("[auth-redirect] Missing tenant key for join", {
|
|
10697
|
+
tenantKey,
|
|
10698
|
+
redirectUrl,
|
|
10699
|
+
});
|
|
10700
|
+
redirectToAuthSpa({
|
|
10701
|
+
authUrl,
|
|
10702
|
+
appName: "app", // Will need to be configured
|
|
10703
|
+
redirectTo: redirectUrl,
|
|
10704
|
+
});
|
|
10705
|
+
return;
|
|
10706
|
+
}
|
|
10707
|
+
const targetUrl = redirectUrl !== null && redirectUrl !== void 0 ? redirectUrl : window.location.href;
|
|
10708
|
+
const joinUrl = `${authUrl}/join?tenant=${encodeURIComponent(resolvedTenant)}&redirect-to=${encodeURIComponent(targetUrl)}`;
|
|
10709
|
+
window.location.href = joinUrl;
|
|
10710
|
+
}
|
|
10711
|
+
/**
|
|
10712
|
+
* Handle user logout
|
|
10713
|
+
*
|
|
10714
|
+
* This function:
|
|
10715
|
+
* - Clears localStorage (preserving tenant)
|
|
10716
|
+
* - Sets logout timestamp cookie for cross-SPA sync
|
|
10717
|
+
* - Clears all cookies
|
|
10718
|
+
* - Redirects to auth SPA logout endpoint
|
|
10719
|
+
*
|
|
10720
|
+
* @param options - Logout configuration options
|
|
10721
|
+
*
|
|
10722
|
+
* @example
|
|
10723
|
+
* ```tsx
|
|
10724
|
+
* handleLogout({
|
|
10725
|
+
* authUrl: 'https://auth.example.com',
|
|
10726
|
+
* redirectUrl: 'https://app.example.com',
|
|
10727
|
+
* });
|
|
10728
|
+
* ```
|
|
10729
|
+
*/
|
|
10730
|
+
function handleLogout(options) {
|
|
10731
|
+
const { redirectUrl = window.location.origin, authUrl, tenantStorageKey = "tenant", logoutTimestampCookie = "ibl_logout_timestamp", callback, } = options;
|
|
10732
|
+
const tenant = window.localStorage.getItem(tenantStorageKey);
|
|
10733
|
+
window.localStorage.clear();
|
|
10734
|
+
if (tenant) {
|
|
10735
|
+
window.localStorage.setItem(tenantStorageKey, tenant);
|
|
10736
|
+
}
|
|
10737
|
+
// Set logout timestamp cookie to trigger logout on other SPAs
|
|
10738
|
+
setCookieForAuth(logoutTimestampCookie, Date.now().toString());
|
|
10739
|
+
clearCookies();
|
|
10740
|
+
callback === null || callback === void 0 ? void 0 : callback();
|
|
10741
|
+
if (!isInIframe()) {
|
|
10742
|
+
window.location.href = `${authUrl}/logout?redirect-to=${redirectUrl}${tenant ? "&tenant=" + tenant : ""}`;
|
|
10743
|
+
}
|
|
10744
|
+
}
|
|
10745
|
+
|
|
10328
10746
|
const useExternalPricingPlan = ({ pricingModalData, userEmail, }) => {
|
|
10329
10747
|
const pricingBoxIframeRef = React.useRef(null);
|
|
10330
10748
|
const getIFrameReadyData = async () => {
|
|
@@ -10456,6 +10874,8 @@ function jwtDecode(token, options) {
|
|
|
10456
10874
|
* - Polls for cookie changes every 2 seconds
|
|
10457
10875
|
* - Refreshes the page when cross-SPA changes are detected
|
|
10458
10876
|
* - Listens for storage events to update cookies when localStorage changes
|
|
10877
|
+
* - Monitors logout timestamp cookie to trigger cross-SPA logout
|
|
10878
|
+
* - Automatically logs out when another SPA initiates logout
|
|
10459
10879
|
*
|
|
10460
10880
|
* For React Native:
|
|
10461
10881
|
* - Relies on AsyncStorage only (handled by StorageService)
|
|
@@ -10465,7 +10885,7 @@ function jwtDecode(token, options) {
|
|
|
10465
10885
|
/**
|
|
10466
10886
|
* Check if we're running in a web browser environment
|
|
10467
10887
|
*/
|
|
10468
|
-
const isWeb = () => {
|
|
10888
|
+
const isWeb$1 = () => {
|
|
10469
10889
|
return typeof window !== "undefined" && typeof document !== "undefined";
|
|
10470
10890
|
};
|
|
10471
10891
|
/**
|
|
@@ -10475,6 +10895,7 @@ const COOKIE_KEYS = {
|
|
|
10475
10895
|
CURRENT_TENANT: "ibl_current_tenant",
|
|
10476
10896
|
USER_DATA: "ibl_user_data",
|
|
10477
10897
|
TENANT: "ibl_tenant",
|
|
10898
|
+
LOGOUT_TIMESTAMP: "ibl_logout_timestamp",
|
|
10478
10899
|
};
|
|
10479
10900
|
/**
|
|
10480
10901
|
* Get the base domain for cookie sharing
|
|
@@ -10485,7 +10906,7 @@ const COOKIE_KEYS = {
|
|
|
10485
10906
|
*/
|
|
10486
10907
|
const getBaseDomain = () => {
|
|
10487
10908
|
// Must check for window existence before accessing it
|
|
10488
|
-
if (!isWeb())
|
|
10909
|
+
if (!isWeb$1())
|
|
10489
10910
|
return "";
|
|
10490
10911
|
const hostname = window.location.hostname;
|
|
10491
10912
|
// For localhost or IP addresses, use as-is
|
|
@@ -10514,7 +10935,7 @@ const CookieUtils = {
|
|
|
10514
10935
|
* Uses SameSite=None for cross-subdomain sharing and base domain
|
|
10515
10936
|
*/
|
|
10516
10937
|
set(name, value, days = 365) {
|
|
10517
|
-
if (!isWeb())
|
|
10938
|
+
if (!isWeb$1())
|
|
10518
10939
|
return;
|
|
10519
10940
|
const expires = new Date();
|
|
10520
10941
|
expires.setTime(expires.getTime() + days * 24 * 60 * 60 * 1000);
|
|
@@ -10526,7 +10947,7 @@ const CookieUtils = {
|
|
|
10526
10947
|
* Get a cookie value by name
|
|
10527
10948
|
*/
|
|
10528
10949
|
get(name) {
|
|
10529
|
-
if (!isWeb())
|
|
10950
|
+
if (!isWeb$1())
|
|
10530
10951
|
return null;
|
|
10531
10952
|
const nameEQ = name + "=";
|
|
10532
10953
|
const cookies = document.cookie.split(";");
|
|
@@ -10545,7 +10966,7 @@ const CookieUtils = {
|
|
|
10545
10966
|
* Uses same domain logic as set() to ensure proper deletion
|
|
10546
10967
|
*/
|
|
10547
10968
|
delete(name) {
|
|
10548
|
-
if (!isWeb())
|
|
10969
|
+
if (!isWeb$1())
|
|
10549
10970
|
return;
|
|
10550
10971
|
const baseDomain = getBaseDomain();
|
|
10551
10972
|
const domainAttr = baseDomain ? `;domain=${baseDomain}` : "";
|
|
@@ -10558,8 +10979,7 @@ const CookieUtils = {
|
|
|
10558
10979
|
* On React Native, this is a no-op
|
|
10559
10980
|
*/
|
|
10560
10981
|
async function syncAuthToCookies(storageService) {
|
|
10561
|
-
|
|
10562
|
-
if (!isWeb())
|
|
10982
|
+
if (!isWeb$1())
|
|
10563
10983
|
return;
|
|
10564
10984
|
try {
|
|
10565
10985
|
const currentTenant = await storageService.getItem(LOCAL_STORAGE_KEYS.CURRENT_TENANT);
|
|
@@ -10588,13 +11008,23 @@ async function syncAuthToCookies(storageService) {
|
|
|
10588
11008
|
console.error("[syncAuthToCookies] Error syncing to cookies:", error);
|
|
10589
11009
|
}
|
|
10590
11010
|
}
|
|
11011
|
+
/**
|
|
11012
|
+
* Clear current tenant cookie only (web only)
|
|
11013
|
+
* Should be called before tenant switching
|
|
11014
|
+
* On React Native, this is a no-op
|
|
11015
|
+
*/
|
|
11016
|
+
function clearCurrentTenantCookie() {
|
|
11017
|
+
if (!isWeb$1())
|
|
11018
|
+
return;
|
|
11019
|
+
CookieUtils.delete(COOKIE_KEYS.CURRENT_TENANT);
|
|
11020
|
+
}
|
|
10591
11021
|
/**
|
|
10592
11022
|
* Clear all authentication cookies (web only)
|
|
10593
11023
|
* Should be called on logout
|
|
10594
11024
|
* On React Native, this is a no-op
|
|
10595
11025
|
*/
|
|
10596
11026
|
function clearAuthCookies() {
|
|
10597
|
-
if (!isWeb())
|
|
11027
|
+
if (!isWeb$1())
|
|
10598
11028
|
return;
|
|
10599
11029
|
CookieUtils.delete(COOKIE_KEYS.CURRENT_TENANT);
|
|
10600
11030
|
CookieUtils.delete(COOKIE_KEYS.USER_DATA);
|
|
@@ -10606,14 +11036,30 @@ function clearAuthCookies() {
|
|
|
10606
11036
|
* On React Native, always returns false (no-op)
|
|
10607
11037
|
*/
|
|
10608
11038
|
async function syncCookiesToLocalStorage(storageService) {
|
|
10609
|
-
if (!isWeb())
|
|
11039
|
+
if (!isWeb$1())
|
|
10610
11040
|
return false;
|
|
10611
11041
|
try {
|
|
10612
11042
|
let needsRefresh = false;
|
|
10613
11043
|
// Check current_tenant
|
|
10614
11044
|
const cookieCurrentTenant = CookieUtils.get(COOKIE_KEYS.CURRENT_TENANT);
|
|
11045
|
+
console.log("[syncCookiesToLocalStorage] cookieCurrentTenant", cookieCurrentTenant);
|
|
10615
11046
|
const localCurrentTenant = await storageService.getItem(LOCAL_STORAGE_KEYS.CURRENT_TENANT);
|
|
10616
|
-
|
|
11047
|
+
console.log("[syncCookiesToLocalStorage] localCurrentTenant", localCurrentTenant);
|
|
11048
|
+
// Compare current tenant objects by key field only to avoid false positives from extra fields
|
|
11049
|
+
let currentTenantIsDifferent = false;
|
|
11050
|
+
if (cookieCurrentTenant && localCurrentTenant) {
|
|
11051
|
+
try {
|
|
11052
|
+
const cookieTenant = JSON.parse(cookieCurrentTenant);
|
|
11053
|
+
const localTenant = JSON.parse(localCurrentTenant);
|
|
11054
|
+
// Compare by the tenant key only
|
|
11055
|
+
currentTenantIsDifferent = cookieTenant.key !== localTenant.key;
|
|
11056
|
+
}
|
|
11057
|
+
catch (e) {
|
|
11058
|
+
// If parsing fails, fall back to string comparison
|
|
11059
|
+
currentTenantIsDifferent = cookieCurrentTenant !== localCurrentTenant;
|
|
11060
|
+
}
|
|
11061
|
+
}
|
|
11062
|
+
if (currentTenantIsDifferent) {
|
|
10617
11063
|
if (cookieCurrentTenant) {
|
|
10618
11064
|
await storageService.setItem(LOCAL_STORAGE_KEYS.CURRENT_TENANT, cookieCurrentTenant);
|
|
10619
11065
|
}
|
|
@@ -10625,8 +11071,24 @@ async function syncCookiesToLocalStorage(storageService) {
|
|
|
10625
11071
|
}
|
|
10626
11072
|
// Check userData
|
|
10627
11073
|
const cookieUserData = CookieUtils.get(COOKIE_KEYS.USER_DATA);
|
|
11074
|
+
console.log("[syncCookiesToLocalStorage] cookieUserData", cookieUserData);
|
|
10628
11075
|
const localUserData = await storageService.getItem(LOCAL_STORAGE_KEYS.USER_DATA);
|
|
10629
|
-
|
|
11076
|
+
console.log("[syncCookiesToLocalStorage] localUserData", localUserData);
|
|
11077
|
+
// Compare userData objects by user_id to avoid false positives from extra fields
|
|
11078
|
+
let userDataIsDifferent = false;
|
|
11079
|
+
if (cookieUserData && localUserData) {
|
|
11080
|
+
try {
|
|
11081
|
+
const cookieUser = JSON.parse(cookieUserData);
|
|
11082
|
+
const localUser = JSON.parse(localUserData);
|
|
11083
|
+
// Compare by user_id - the primary identifier
|
|
11084
|
+
userDataIsDifferent = cookieUser.user_id !== localUser.user_id;
|
|
11085
|
+
}
|
|
11086
|
+
catch (e) {
|
|
11087
|
+
// If parsing fails, fall back to string comparison
|
|
11088
|
+
userDataIsDifferent = cookieUserData !== localUserData;
|
|
11089
|
+
}
|
|
11090
|
+
}
|
|
11091
|
+
if (userDataIsDifferent) {
|
|
10630
11092
|
if (cookieUserData) {
|
|
10631
11093
|
await storageService.setItem(LOCAL_STORAGE_KEYS.USER_DATA, cookieUserData);
|
|
10632
11094
|
}
|
|
@@ -10638,8 +11100,37 @@ async function syncCookiesToLocalStorage(storageService) {
|
|
|
10638
11100
|
}
|
|
10639
11101
|
// Check tenant
|
|
10640
11102
|
const cookieTenant = CookieUtils.get(COOKIE_KEYS.TENANT);
|
|
11103
|
+
console.log("[syncCookiesToLocalStorage] cookieTenant", cookieTenant);
|
|
10641
11104
|
const localTenant = await storageService.getItem(LOCAL_STORAGE_KEYS.TENANTS);
|
|
10642
|
-
|
|
11105
|
+
console.log("[syncCookiesToLocalStorage] localTenant", localTenant);
|
|
11106
|
+
// Compare tenant arrays by checking length and tenant keys
|
|
11107
|
+
let tenantsAreDifferent = false;
|
|
11108
|
+
if (cookieTenant &&
|
|
11109
|
+
localTenant &&
|
|
11110
|
+
cookieTenant !== "[]" &&
|
|
11111
|
+
localTenant !== "[]") {
|
|
11112
|
+
try {
|
|
11113
|
+
const cookieTenantsArray = JSON.parse(cookieTenant);
|
|
11114
|
+
const localTenantsArray = JSON.parse(localTenant);
|
|
11115
|
+
// Check if arrays have same length
|
|
11116
|
+
if (cookieTenantsArray.length !== localTenantsArray.length) {
|
|
11117
|
+
tenantsAreDifferent = true;
|
|
11118
|
+
}
|
|
11119
|
+
else {
|
|
11120
|
+
// Check if all tenant keys match
|
|
11121
|
+
const cookieKeys = new Set(cookieTenantsArray.map((t) => t.key));
|
|
11122
|
+
const localKeys = new Set(localTenantsArray.map((t) => t.key));
|
|
11123
|
+
tenantsAreDifferent =
|
|
11124
|
+
cookieKeys.size !== localKeys.size ||
|
|
11125
|
+
[...cookieKeys].some((key) => !localKeys.has(key));
|
|
11126
|
+
}
|
|
11127
|
+
}
|
|
11128
|
+
catch (e) {
|
|
11129
|
+
// If parsing fails, fall back to string comparison
|
|
11130
|
+
tenantsAreDifferent = cookieTenant !== localTenant;
|
|
11131
|
+
}
|
|
11132
|
+
}
|
|
11133
|
+
if (tenantsAreDifferent) {
|
|
10643
11134
|
if (cookieTenant) {
|
|
10644
11135
|
await storageService.setItem(LOCAL_STORAGE_KEYS.TENANTS, cookieTenant);
|
|
10645
11136
|
}
|
|
@@ -10694,6 +11185,7 @@ async function isJwtTokenExpired(storageService) {
|
|
|
10694
11185
|
async function validateJwtToken(storageService) {
|
|
10695
11186
|
try {
|
|
10696
11187
|
const edxJwtToken = await storageService.getItem(LOCAL_STORAGE_KEYS.EDX_TOKEN_KEY);
|
|
11188
|
+
console.log("[AuthProvider] JWT token ", edxJwtToken);
|
|
10697
11189
|
const userData = await storageService.getItem(LOCAL_STORAGE_KEYS.USER_DATA);
|
|
10698
11190
|
if (!edxJwtToken || !userData) {
|
|
10699
11191
|
return false;
|
|
@@ -10716,7 +11208,9 @@ async function validateJwtToken(storageService) {
|
|
|
10716
11208
|
function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure, redirectToAuthSpa, hasNonExpiredAuthToken, username, pathname, storageService, skipAuthCheck, token, }) {
|
|
10717
11209
|
const [isAuthenticating, setIsAuthenticating] = React.useState(true);
|
|
10718
11210
|
const [userIsAccessingPublicRoute, setUserIsAccessingPublicRoute] = React.useState(false);
|
|
11211
|
+
const [initialSyncComplete, setInitialSyncComplete] = React.useState(false);
|
|
10719
11212
|
const cookieCheckIntervalRef = React.useRef(null);
|
|
11213
|
+
const lastLogoutTimestampRef = React.useRef(null);
|
|
10720
11214
|
// RTK Query hook for refreshing JWT token
|
|
10721
11215
|
const [refreshJwtToken] = useLazyRefreshJwtTokenQuery();
|
|
10722
11216
|
/**
|
|
@@ -10725,24 +11219,65 @@ function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure,
|
|
|
10725
11219
|
* On React Native, this is a no-op
|
|
10726
11220
|
*/
|
|
10727
11221
|
React.useEffect(() => {
|
|
10728
|
-
|
|
10729
|
-
|
|
11222
|
+
if (!storageService || !isWeb$1()) {
|
|
11223
|
+
// If no storage service or not web, mark sync as complete immediately
|
|
11224
|
+
setInitialSyncComplete(true);
|
|
10730
11225
|
return;
|
|
11226
|
+
}
|
|
10731
11227
|
// Initial sync on mount
|
|
10732
11228
|
async function initialSync() {
|
|
10733
|
-
|
|
10734
|
-
|
|
10735
|
-
|
|
10736
|
-
|
|
11229
|
+
try {
|
|
11230
|
+
// Initialize last known logout timestamp
|
|
11231
|
+
lastLogoutTimestampRef.current = CookieUtils.get(COOKIE_KEYS.LOGOUT_TIMESTAMP);
|
|
11232
|
+
const needsRefresh = await syncCookiesToLocalStorage(storageService);
|
|
11233
|
+
if (needsRefresh) {
|
|
11234
|
+
console.log("[auth-redirect] Cookie sync detected changes, refreshing page");
|
|
11235
|
+
redirectToAuthSpa(undefined, undefined, false, false);
|
|
11236
|
+
}
|
|
11237
|
+
else {
|
|
11238
|
+
await syncAuthToCookies(storageService);
|
|
11239
|
+
}
|
|
11240
|
+
}
|
|
11241
|
+
finally {
|
|
11242
|
+
// Mark initial sync as complete
|
|
11243
|
+
setInitialSyncComplete(true);
|
|
10737
11244
|
}
|
|
10738
11245
|
}
|
|
10739
11246
|
initialSync();
|
|
10740
11247
|
// Poll for cookie changes every 2 seconds to detect cross-SPA updates
|
|
10741
11248
|
cookieCheckIntervalRef.current = setInterval(async () => {
|
|
11249
|
+
// Skip cookie sync checks if user is completing SSO at /sso-login
|
|
11250
|
+
const completingSso = new RegExp("^\/sso-login").test(pathname);
|
|
11251
|
+
if (completingSso) {
|
|
11252
|
+
console.log("[AuthProvider] Skipping cookie sync check for public route");
|
|
11253
|
+
return;
|
|
11254
|
+
}
|
|
11255
|
+
// Check for logout timestamp changes (cross-SPA logout detection)
|
|
11256
|
+
const currentLogoutTimestamp = CookieUtils.get(COOKIE_KEYS.LOGOUT_TIMESTAMP);
|
|
11257
|
+
if (currentLogoutTimestamp &&
|
|
11258
|
+
lastLogoutTimestampRef.current &&
|
|
11259
|
+
currentLogoutTimestamp !== lastLogoutTimestampRef.current) {
|
|
11260
|
+
console.log("[auth-redirect] Logout detected from another SPA", {
|
|
11261
|
+
previousTimestamp: lastLogoutTimestampRef.current,
|
|
11262
|
+
newTimestamp: currentLogoutTimestamp,
|
|
11263
|
+
});
|
|
11264
|
+
lastLogoutTimestampRef.current = currentLogoutTimestamp;
|
|
11265
|
+
redirectToAuthSpa(undefined, undefined, true);
|
|
11266
|
+
return;
|
|
11267
|
+
}
|
|
10742
11268
|
const needsRefresh = await syncCookiesToLocalStorage(storageService);
|
|
10743
11269
|
if (needsRefresh) {
|
|
10744
|
-
console.log("[
|
|
10745
|
-
|
|
11270
|
+
console.log("[auth-redirect] Cookie sync detected changes from another SPA, refreshing page");
|
|
11271
|
+
let cookieTenantKey;
|
|
11272
|
+
try {
|
|
11273
|
+
const cookieCurrentTenant = JSON.parse(CookieUtils.get(COOKIE_KEYS.CURRENT_TENANT));
|
|
11274
|
+
cookieTenantKey = cookieCurrentTenant.key;
|
|
11275
|
+
}
|
|
11276
|
+
catch (_a) { }
|
|
11277
|
+
redirectToAuthSpa(undefined, cookieTenantKey, false, false);
|
|
11278
|
+
}
|
|
11279
|
+
else {
|
|
11280
|
+
await syncAuthToCookies(storageService);
|
|
10746
11281
|
}
|
|
10747
11282
|
}, 2000);
|
|
10748
11283
|
// Cleanup interval on unmount
|
|
@@ -10751,15 +11286,14 @@ function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure,
|
|
|
10751
11286
|
clearInterval(cookieCheckIntervalRef.current);
|
|
10752
11287
|
}
|
|
10753
11288
|
};
|
|
10754
|
-
}, [storageService]);
|
|
11289
|
+
}, [storageService, middleware, pathname]);
|
|
10755
11290
|
/**
|
|
10756
11291
|
* Listen for storage events from other tabs/windows (web only)
|
|
10757
11292
|
* This catches same-SPA changes in different tabs
|
|
10758
11293
|
* On React Native, this is a no-op
|
|
10759
11294
|
*/
|
|
10760
11295
|
React.useEffect(() => {
|
|
10761
|
-
|
|
10762
|
-
if (!storageService || !isWeb())
|
|
11296
|
+
if (!storageService || !isWeb$1())
|
|
10763
11297
|
return;
|
|
10764
11298
|
const handleStorageChange = async (event) => {
|
|
10765
11299
|
// Only handle changes to our auth-related keys
|
|
@@ -10790,14 +11324,15 @@ function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure,
|
|
|
10790
11324
|
if (!hasNonExpiredAuthToken()) {
|
|
10791
11325
|
const reason = "Auth token expired";
|
|
10792
11326
|
onAuthFailure === null || onAuthFailure === void 0 ? void 0 : onAuthFailure(reason);
|
|
10793
|
-
|
|
11327
|
+
console.log("[auth-redirect] Auth token expired");
|
|
11328
|
+
redirectToAuthSpa(undefined, undefined, true);
|
|
10794
11329
|
return;
|
|
10795
11330
|
}
|
|
10796
11331
|
// Check JWT token expiry and force logout for protected routes
|
|
10797
11332
|
if (isProtectedRoute && storageService) {
|
|
10798
11333
|
const jwtExpired = await isJwtTokenExpired(storageService);
|
|
10799
11334
|
if (jwtExpired) {
|
|
10800
|
-
console.log("[
|
|
11335
|
+
console.log("[auth-redirect] JWT token has expired, forcing logout");
|
|
10801
11336
|
// Clear all auth-related storage keys
|
|
10802
11337
|
clearAuthCookies();
|
|
10803
11338
|
const reason = "JWT token expired";
|
|
@@ -10819,11 +11354,18 @@ function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure,
|
|
|
10819
11354
|
console.log("[AuthProvider] JWT token refreshed successfully");
|
|
10820
11355
|
}
|
|
10821
11356
|
else if (result.error) {
|
|
10822
|
-
console.
|
|
11357
|
+
console.log("[auth-redirect] Failed to refresh JWT token", {
|
|
11358
|
+
error: result.error,
|
|
11359
|
+
});
|
|
11360
|
+
redirectToAuthSpa(undefined, undefined, true);
|
|
11361
|
+
return;
|
|
10823
11362
|
}
|
|
10824
11363
|
}
|
|
10825
11364
|
catch (refreshError) {
|
|
10826
|
-
console.
|
|
11365
|
+
console.log("[auth-redirect] JWT token refresh error", {
|
|
11366
|
+
error: refreshError,
|
|
11367
|
+
});
|
|
11368
|
+
redirectToAuthSpa(undefined, undefined, true);
|
|
10827
11369
|
// Continue with auth check even if JWT refresh fails
|
|
10828
11370
|
}
|
|
10829
11371
|
}
|
|
@@ -10835,12 +11377,18 @@ function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure,
|
|
|
10835
11377
|
setIsAuthenticating(false);
|
|
10836
11378
|
}
|
|
10837
11379
|
catch (error) {
|
|
11380
|
+
console.error("[AuthProvider] Error performing auth check:", error);
|
|
10838
11381
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
10839
11382
|
onAuthFailure === null || onAuthFailure === void 0 ? void 0 : onAuthFailure(`Unexpected error: ${errorMessage}`);
|
|
10840
11383
|
redirectToAuthSpa();
|
|
10841
11384
|
}
|
|
10842
11385
|
}
|
|
10843
11386
|
React.useEffect(() => {
|
|
11387
|
+
// Wait for initial sync to complete before performing auth check
|
|
11388
|
+
if (!initialSyncComplete) {
|
|
11389
|
+
console.log("[useAuthProvider] Waiting for initial sync to complete...");
|
|
11390
|
+
return;
|
|
11391
|
+
}
|
|
10844
11392
|
async function checkAuth() {
|
|
10845
11393
|
setIsAuthenticating(true);
|
|
10846
11394
|
const authRequired = (await determineAuthRequired(middleware, pathname)) && !token;
|
|
@@ -10861,7 +11409,7 @@ function useAuthProvider({ middleware = new Map(), onAuthSuccess, onAuthFailure,
|
|
|
10861
11409
|
}
|
|
10862
11410
|
console.log("[useAuthProvider] performing auth check for ", username);
|
|
10863
11411
|
checkAuth();
|
|
10864
|
-
}, [username]);
|
|
11412
|
+
}, [username, initialSyncComplete]);
|
|
10865
11413
|
return {
|
|
10866
11414
|
isAuthenticating,
|
|
10867
11415
|
userIsAccessingPublicRoute,
|
|
@@ -10929,7 +11477,7 @@ function AuthProvider({ children, fallback, middleware = new Map(), onAuthSucces
|
|
|
10929
11477
|
if (isAuthenticating) {
|
|
10930
11478
|
return fallback;
|
|
10931
11479
|
}
|
|
10932
|
-
return (jsxRuntime.jsx(AuthContextProvider, { value: { userIsAccessingPublicRoute, setUserIsAccessingPublicRoute }, children:
|
|
11480
|
+
return (jsxRuntime.jsx(AuthContextProvider, { value: { userIsAccessingPublicRoute, setUserIsAccessingPublicRoute }, children: children }));
|
|
10933
11481
|
}
|
|
10934
11482
|
|
|
10935
11483
|
/**
|
|
@@ -10942,6 +11490,12 @@ function AuthProvider({ children, fallback, middleware = new Map(), onAuthSucces
|
|
|
10942
11490
|
* - Tenant metadata retrieval
|
|
10943
11491
|
* - User-tenant relationship verification
|
|
10944
11492
|
*/
|
|
11493
|
+
/**
|
|
11494
|
+
* Check if we're running in a web browser environment
|
|
11495
|
+
*/
|
|
11496
|
+
const isWeb = () => {
|
|
11497
|
+
return typeof window !== "undefined" && typeof document !== "undefined";
|
|
11498
|
+
};
|
|
10945
11499
|
const TenantContext = React.createContext(undefined);
|
|
10946
11500
|
/**
|
|
10947
11501
|
* Context Provider component that wraps children with tenant context
|
|
@@ -10962,7 +11516,7 @@ const useTenantContext = () => React.useContext(TenantContext);
|
|
|
10962
11516
|
* 4. Handles tenant-specific domain redirects
|
|
10963
11517
|
* 5. Maintains tenant access state
|
|
10964
11518
|
*/
|
|
10965
|
-
function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, currentTenant, requestedTenant, saveCurrentTenant, saveUserTenants, handleTenantSwitch, saveVisitingTenant, removeVisitingTenant, saveUserTokens, saveTenant, onAutoJoinUserToTenant, }) {
|
|
11519
|
+
function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, currentTenant, requestedTenant, saveCurrentTenant, saveUserTenants, handleTenantSwitch, saveVisitingTenant, removeVisitingTenant, saveUserTokens, saveTenant, onAutoJoinUserToTenant, redirectToAuthSpa, username, }) {
|
|
10966
11520
|
const { userIsAccessingPublicRoute, setUserIsAccessingPublicRoute } = useAuthContext();
|
|
10967
11521
|
const [determineUserPath, setDetermineUserPath] = React.useState(false);
|
|
10968
11522
|
const [isLoading, setIsLoading] = React.useState(true);
|
|
@@ -10973,6 +11527,26 @@ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, curr
|
|
|
10973
11527
|
const [getAppToken] = useGetAppTokensMutation();
|
|
10974
11528
|
const [tenantKey, setTenantKey] = React.useState(currentTenant);
|
|
10975
11529
|
const [metadata, setMetadata] = React.useState({});
|
|
11530
|
+
// Fetch custom domain to get platform_key
|
|
11531
|
+
const currentDomain = typeof window !== "undefined" ? window.location.hostname : "";
|
|
11532
|
+
const { data: customDomainData, isLoading: isLoadingCustomDomain, isError: isCustomDomainError, } = useGetCustomDomainsQuery({ params: { domain: currentDomain } }, { skip: !isWeb() || !currentDomain });
|
|
11533
|
+
// Extract platform_key from custom domain response to use as requestedTenant
|
|
11534
|
+
const customDomainPlatformKey = React.useMemo(() => {
|
|
11535
|
+
if (customDomainData &&
|
|
11536
|
+
typeof customDomainData === "object" &&
|
|
11537
|
+
"custom_domains" in customDomainData) {
|
|
11538
|
+
const domains = customDomainData.custom_domains;
|
|
11539
|
+
if (Array.isArray(domains) &&
|
|
11540
|
+
domains.length > 0 &&
|
|
11541
|
+
domains[0].platform_key) {
|
|
11542
|
+
console.log("[TenantProvider] Using platform_key from custom domain:", domains[0].platform_key);
|
|
11543
|
+
return domains[0].platform_key;
|
|
11544
|
+
}
|
|
11545
|
+
}
|
|
11546
|
+
return undefined;
|
|
11547
|
+
}, [customDomainData]);
|
|
11548
|
+
// Use custom domain platform_key as requested tenant if available, otherwise use provided requestedTenant
|
|
11549
|
+
const effectiveRequestedTenant = customDomainPlatformKey || requestedTenant;
|
|
10976
11550
|
/**
|
|
10977
11551
|
* Helper function to enhance tenants with platform metadata from user apps
|
|
10978
11552
|
*/
|
|
@@ -11032,24 +11606,32 @@ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, curr
|
|
|
11032
11606
|
const otherTenant = tenants.find((t) => t.key !== MAIN_TENANT_KEY);
|
|
11033
11607
|
if (mainTenant &&
|
|
11034
11608
|
otherTenant &&
|
|
11035
|
-
|
|
11036
|
-
|
|
11609
|
+
effectiveRequestedTenant &&
|
|
11610
|
+
effectiveRequestedTenant !== otherTenant.key) {
|
|
11037
11611
|
handleTenantSwitch(otherTenant.key, true);
|
|
11038
11612
|
console.log("TenantProvider: Triggering tenant switch to newly joined tenant:", otherTenant.key);
|
|
11039
11613
|
}
|
|
11040
11614
|
}
|
|
11041
|
-
// Enhance tenants with platform
|
|
11615
|
+
// Enhance tenants with platform metadatax
|
|
11042
11616
|
let enhancedTenants = await enhanceTenants(tenants);
|
|
11617
|
+
// if there is customDomainPlatformKey and user doesn't belong to that tenant, trigger logout
|
|
11618
|
+
if (customDomainPlatformKey) {
|
|
11619
|
+
if (!(enhancedTenants === null || enhancedTenants === void 0 ? void 0 : enhancedTenants.find((tenant) => tenant.key === customDomainPlatformKey))) {
|
|
11620
|
+
redirectToAuthSpa === null || redirectToAuthSpa === void 0 ? void 0 : redirectToAuthSpa(undefined, undefined, true);
|
|
11621
|
+
return;
|
|
11622
|
+
}
|
|
11623
|
+
}
|
|
11043
11624
|
saveUserTenants(enhancedTenants);
|
|
11044
11625
|
// Find requested tenant or fallback to current tenant
|
|
11045
|
-
console.log("checking requested tenant", {
|
|
11046
|
-
|
|
11047
|
-
|
|
11626
|
+
console.log("checking requested tenant", JSON.stringify({
|
|
11627
|
+
requestedTenant: effectiveRequestedTenant,
|
|
11628
|
+
customDomainPlatformKey,
|
|
11629
|
+
}));
|
|
11630
|
+
let tenant = enhancedTenants === null || enhancedTenants === void 0 ? void 0 : enhancedTenants.find((tenant) => tenant.key === effectiveRequestedTenant);
|
|
11631
|
+
console.log("requested tenant", tenant);
|
|
11048
11632
|
if (!tenant && !userIsAccessingPublicRoute) {
|
|
11049
11633
|
setDetermineUserPath(true);
|
|
11050
|
-
console.log("no requested tenant, checking current tenant",
|
|
11051
|
-
currentTenant,
|
|
11052
|
-
});
|
|
11634
|
+
console.log("no requested tenant, checking current tenant", currentTenant);
|
|
11053
11635
|
tenant = enhancedTenants === null || enhancedTenants === void 0 ? void 0 : enhancedTenants.find((tenant) => tenant.key === currentTenant);
|
|
11054
11636
|
console.log("current tenant", { tenant });
|
|
11055
11637
|
}
|
|
@@ -11061,7 +11643,7 @@ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, curr
|
|
|
11061
11643
|
tenant = enhancedTenants[0];
|
|
11062
11644
|
}
|
|
11063
11645
|
// Fetch and validate tenant metadata
|
|
11064
|
-
console.log("fetching tenant metadata",
|
|
11646
|
+
console.log("fetching tenant metadata", JSON.stringify(tenant));
|
|
11065
11647
|
const { data: tenantMetadata } = await fetchTenantMetadata([
|
|
11066
11648
|
{
|
|
11067
11649
|
org: (tenant === null || tenant === void 0 ? void 0 : tenant.key) || currentTenant,
|
|
@@ -11132,6 +11714,11 @@ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, curr
|
|
|
11132
11714
|
platform_name: data.platform_name,
|
|
11133
11715
|
is_advertising: (_a = data.metadata) === null || _a === void 0 ? void 0 : _a.is_advertising,
|
|
11134
11716
|
};
|
|
11717
|
+
if (!username) {
|
|
11718
|
+
saveVisitingTenant === null || saveVisitingTenant === void 0 ? void 0 : saveVisitingTenant(newCurrentTenant);
|
|
11719
|
+
// user is not authenticated so we don't need to do anything that concerns an authenticated user
|
|
11720
|
+
return;
|
|
11721
|
+
}
|
|
11135
11722
|
const { data: tenants } = await fetchUserTenants();
|
|
11136
11723
|
const enhancedTenants = await enhanceTenants(tenants, data);
|
|
11137
11724
|
saveUserTenants(enhancedTenants);
|
|
@@ -11203,28 +11790,44 @@ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, curr
|
|
|
11203
11790
|
}
|
|
11204
11791
|
// Effect to handle tenant determination when auth state changes
|
|
11205
11792
|
React.useEffect(() => {
|
|
11793
|
+
// Wait for custom domain query to complete (unless skipped or error)
|
|
11794
|
+
const customDomainQuerySkipped = !isWeb() || !currentDomain;
|
|
11795
|
+
if (!customDomainQuerySkipped && isLoadingCustomDomain) {
|
|
11796
|
+
console.log("[TenantProvider] Waiting for custom domain query to complete...");
|
|
11797
|
+
return;
|
|
11798
|
+
}
|
|
11799
|
+
if (isCustomDomainError) {
|
|
11800
|
+
console.warn("[TenantProvider] Custom domain query failed, proceeding without custom domain platform_key");
|
|
11801
|
+
}
|
|
11206
11802
|
// NOTE: currentTenant comes from local storage.
|
|
11207
11803
|
// it's the tenant the user is currently signed into.
|
|
11208
11804
|
console.log("determineWhichTenantToUse", {
|
|
11209
11805
|
userIsAccessingPublicRoute,
|
|
11210
11806
|
currentTenant,
|
|
11211
11807
|
requestedTenant,
|
|
11808
|
+
effectiveRequestedTenant,
|
|
11809
|
+
customDomainPlatformKey,
|
|
11212
11810
|
});
|
|
11213
|
-
if (userIsAccessingPublicRoute &&
|
|
11811
|
+
if (userIsAccessingPublicRoute && effectiveRequestedTenant.length === 0) {
|
|
11214
11812
|
setIsLoading(false);
|
|
11215
11813
|
return;
|
|
11216
11814
|
}
|
|
11217
|
-
if (userIsAccessingPublicRoute &&
|
|
11815
|
+
if (userIsAccessingPublicRoute && effectiveRequestedTenant.length > 0) {
|
|
11218
11816
|
setIsLoading(true);
|
|
11219
|
-
setTenantKey(
|
|
11220
|
-
handleLoadTenantMetadata(
|
|
11817
|
+
setTenantKey(effectiveRequestedTenant);
|
|
11818
|
+
handleLoadTenantMetadata(effectiveRequestedTenant);
|
|
11221
11819
|
}
|
|
11222
11820
|
else {
|
|
11223
11821
|
setIsLoading(true);
|
|
11224
11822
|
removeVisitingTenant === null || removeVisitingTenant === void 0 ? void 0 : removeVisitingTenant();
|
|
11225
11823
|
determineWhichTenantToUse();
|
|
11226
11824
|
}
|
|
11227
|
-
}, [
|
|
11825
|
+
}, [
|
|
11826
|
+
userIsAccessingPublicRoute,
|
|
11827
|
+
effectiveRequestedTenant,
|
|
11828
|
+
isLoadingCustomDomain,
|
|
11829
|
+
isCustomDomainError,
|
|
11830
|
+
]);
|
|
11228
11831
|
// Show fallback component during tenant determination
|
|
11229
11832
|
if (isLoading) {
|
|
11230
11833
|
return fallback;
|
|
@@ -11257,24 +11860,17 @@ function TenantProvider({ children, fallback, onAuthSuccess, onAuthFailure, curr
|
|
|
11257
11860
|
* 3. Manages redirection based on mentor availability
|
|
11258
11861
|
* 4. Integrates with tenant context for access control
|
|
11259
11862
|
*/
|
|
11260
|
-
function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redirectToAuthSpa, redirectToMentor, onLoadMentorsPermissions, redirectToNoMentorsPage, redirectToCreateMentor, username, isAdmin, mainTenantKey, requestedMentorId, handleMentorNotFound, forceDetermineMentor = false, }) {
|
|
11863
|
+
function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redirectToAuthSpa, redirectToMentor, onLoadMentorsPermissions, redirectToNoMentorsPage, redirectToCreateMentor, username, isAdmin, mainTenantKey, requestedMentorId, handleMentorNotFound, forceDetermineMentor = false, onComplete, }) {
|
|
11261
11864
|
const [isLoading, setIsLoading] = React.useState(true);
|
|
11262
11865
|
const { userIsAccessingPublicRoute } = useAuthContext();
|
|
11263
|
-
const { determineUserPath, tenantKey } = useTenantContext();
|
|
11866
|
+
const { determineUserPath, tenantKey, metadata } = useTenantContext();
|
|
11264
11867
|
const isMainTenant = tenantKey === mainTenantKey;
|
|
11265
|
-
console.log("MentorProvider initialized",
|
|
11266
|
-
username,
|
|
11267
|
-
isAdmin,
|
|
11268
|
-
tenantKey,
|
|
11269
|
-
mainTenantKey,
|
|
11270
|
-
isMainTenant,
|
|
11271
|
-
requestedMentorId,
|
|
11272
|
-
determineUserPath,
|
|
11273
|
-
});
|
|
11868
|
+
console.log("MentorProvider initialized", username, isAdmin, tenantKey, mainTenantKey, isMainTenant, requestedMentorId, determineUserPath);
|
|
11274
11869
|
const [fetchMentors] = useLazyGetMentorsQuery();
|
|
11275
11870
|
const [fetchSeedMentors] = useLazySeedMentorsQuery();
|
|
11276
11871
|
const [getMentorPublicSettings] = useLazyGetMentorPublicSettingsQuery();
|
|
11277
11872
|
const [getRbacPermissions] = useGetRbacPermissionsMutation();
|
|
11873
|
+
const [getRecentlyAccessedMentors] = useLazyGetRecentlyAccessedMentorsQuery();
|
|
11278
11874
|
const QUERY_LIMIT = 10;
|
|
11279
11875
|
const loadMentorsPermissions = async (mentorDbId) => {
|
|
11280
11876
|
try {
|
|
@@ -11291,6 +11887,33 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11291
11887
|
}
|
|
11292
11888
|
catch (_a) { }
|
|
11293
11889
|
};
|
|
11890
|
+
/**
|
|
11891
|
+
* Gets the mentor database ID from public settings if not available on the mentor object
|
|
11892
|
+
*/
|
|
11893
|
+
const getMentorDbId = async (mentor) => {
|
|
11894
|
+
if (mentor === null || mentor === void 0 ? void 0 : mentor.id) {
|
|
11895
|
+
return mentor.id;
|
|
11896
|
+
}
|
|
11897
|
+
if (mentor === null || mentor === void 0 ? void 0 : mentor.unique_id) {
|
|
11898
|
+
try {
|
|
11899
|
+
const response = await getMentorPublicSettings({
|
|
11900
|
+
// @ts-ignore
|
|
11901
|
+
mentor: mentor.unique_id,
|
|
11902
|
+
org: tenantKey,
|
|
11903
|
+
// @ts-ignore
|
|
11904
|
+
userId: username,
|
|
11905
|
+
}).unwrap();
|
|
11906
|
+
return response === null || response === void 0 ? void 0 : response.mentor_id;
|
|
11907
|
+
}
|
|
11908
|
+
catch (error) {
|
|
11909
|
+
console.log("failed to fetch mentor ID from public settings", {
|
|
11910
|
+
error: error instanceof Error ? error.message : String(error),
|
|
11911
|
+
mentorUniqueId: mentor.unique_id,
|
|
11912
|
+
});
|
|
11913
|
+
}
|
|
11914
|
+
}
|
|
11915
|
+
return undefined;
|
|
11916
|
+
};
|
|
11294
11917
|
/**
|
|
11295
11918
|
* Determines which mentor to redirect the user to by following this priority:
|
|
11296
11919
|
* 1. Recently accessed mentors
|
|
@@ -11298,24 +11921,60 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11298
11921
|
* 3. Non-featured mentors
|
|
11299
11922
|
* 4. Seeded mentors (for admin users)
|
|
11300
11923
|
* 5. Creation flow or no mentors page
|
|
11924
|
+
*
|
|
11925
|
+
* Returns the mentor object if found, undefined otherwise
|
|
11301
11926
|
*/
|
|
11302
11927
|
async function determineMentorToRedirectTo() {
|
|
11303
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o
|
|
11304
|
-
console.log("starting mentor determination process", {
|
|
11928
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
11929
|
+
console.log("starting mentor determination process", JSON.stringify({
|
|
11305
11930
|
tenantKey,
|
|
11306
11931
|
username,
|
|
11307
11932
|
isAdmin,
|
|
11308
11933
|
isMainTenant,
|
|
11309
|
-
});
|
|
11934
|
+
}));
|
|
11935
|
+
console.log("###################### metadata is ", metadata, typeof metadata);
|
|
11310
11936
|
setIsLoading(true);
|
|
11311
11937
|
try {
|
|
11312
11938
|
// Get the user's recent mentors
|
|
11313
|
-
console.log("fetching recent mentors", {
|
|
11939
|
+
console.log("fetching recent mentors", JSON.stringify({
|
|
11314
11940
|
tenantKey,
|
|
11315
11941
|
username,
|
|
11316
11942
|
limit: QUERY_LIMIT,
|
|
11317
11943
|
orderBy: "recently_accessed_at",
|
|
11944
|
+
}));
|
|
11945
|
+
if (typeof metadata === "object" &&
|
|
11946
|
+
metadata.skills_embedded_mentor_name) {
|
|
11947
|
+
const defaultMentor = JSON.parse(metadata.skills_embedded_mentor_name);
|
|
11948
|
+
if (defaultMentor === null || defaultMentor === void 0 ? void 0 : defaultMentor.unique_id) {
|
|
11949
|
+
return defaultMentor;
|
|
11950
|
+
}
|
|
11951
|
+
}
|
|
11952
|
+
// Check for recently accessed mentors (second choice)
|
|
11953
|
+
console.log("checking recently accessed mentors", JSON.stringify({
|
|
11954
|
+
tenantKey,
|
|
11955
|
+
username,
|
|
11956
|
+
}));
|
|
11957
|
+
const recentlyAccessedResult = await getRecentlyAccessedMentors({
|
|
11958
|
+
org: tenantKey,
|
|
11959
|
+
// @ts-ignore
|
|
11960
|
+
userId: username,
|
|
11318
11961
|
});
|
|
11962
|
+
// @ts-ignore
|
|
11963
|
+
const recentlyAccessedMentors = recentlyAccessedResult.data;
|
|
11964
|
+
const starredMentors = recentlyAccessedMentors === null || recentlyAccessedMentors === void 0 ? void 0 : recentlyAccessedMentors.starred_mentors;
|
|
11965
|
+
let recentMentors = recentlyAccessedMentors === null || recentlyAccessedMentors === void 0 ? void 0 : recentlyAccessedMentors.recent_mentors;
|
|
11966
|
+
if (starredMentors.length > 0) {
|
|
11967
|
+
const starredMentor = starredMentors[0];
|
|
11968
|
+
if (starredMentor === null || starredMentor === void 0 ? void 0 : starredMentor.unique_id) {
|
|
11969
|
+
return starredMentor;
|
|
11970
|
+
}
|
|
11971
|
+
}
|
|
11972
|
+
if (recentMentors.length > 0) {
|
|
11973
|
+
const recentMentor = recentMentors[0];
|
|
11974
|
+
if (recentMentor === null || recentMentor === void 0 ? void 0 : recentMentor.unique_id) {
|
|
11975
|
+
return recentMentor;
|
|
11976
|
+
}
|
|
11977
|
+
}
|
|
11319
11978
|
const recentMentorsResult = await fetchMentors({
|
|
11320
11979
|
// @ts-ignore
|
|
11321
11980
|
org: tenantKey,
|
|
@@ -11323,26 +11982,19 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11323
11982
|
limit: QUERY_LIMIT,
|
|
11324
11983
|
orderBy: "recently_accessed_at",
|
|
11325
11984
|
});
|
|
11326
|
-
|
|
11327
|
-
console.log("recent mentors fetched", {
|
|
11985
|
+
recentMentors = ((_a = recentMentorsResult.data) === null || _a === void 0 ? void 0 : _a.results) || [];
|
|
11986
|
+
console.log("recent mentors fetched", JSON.stringify({
|
|
11328
11987
|
count: recentMentors.length,
|
|
11329
11988
|
mentorIds: recentMentors.map((m) => m === null || m === void 0 ? void 0 : m.unique_id),
|
|
11330
|
-
});
|
|
11989
|
+
}));
|
|
11331
11990
|
// Check if we found recent mentors for the tenant
|
|
11332
11991
|
if (recentMentors.length > 0) {
|
|
11333
|
-
|
|
11334
|
-
|
|
11335
|
-
|
|
11336
|
-
selectedMentorId,
|
|
11337
|
-
mentorName: (_d = recentMentors[0]) === null || _d === void 0 ? void 0 : _d.name,
|
|
11992
|
+
console.log("found recent mentor", JSON.stringify({
|
|
11993
|
+
selectedMentorId: (_b = recentMentors[0]) === null || _b === void 0 ? void 0 : _b.unique_id,
|
|
11994
|
+
mentorName: (_c = recentMentors[0]) === null || _c === void 0 ? void 0 : _c.name,
|
|
11338
11995
|
tenantKey,
|
|
11339
|
-
});
|
|
11340
|
-
|
|
11341
|
-
// Select the most recent mentor as current mentor
|
|
11342
|
-
onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
|
|
11343
|
-
redirectToMentor(tenantKey, selectedMentorId);
|
|
11344
|
-
onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
|
|
11345
|
-
return;
|
|
11996
|
+
}));
|
|
11997
|
+
return recentMentors[0];
|
|
11346
11998
|
}
|
|
11347
11999
|
// If no recent mentors, get featured mentors
|
|
11348
12000
|
console.log("no recent mentors found, fetching featured mentors", {
|
|
@@ -11356,7 +12008,7 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11356
12008
|
limit: QUERY_LIMIT,
|
|
11357
12009
|
orderBy: "recently_accessed_at",
|
|
11358
12010
|
});
|
|
11359
|
-
const featuredMentors = ((
|
|
12011
|
+
const featuredMentors = ((_d = featuredMentorsResult.data) === null || _d === void 0 ? void 0 : _d.results) || [];
|
|
11360
12012
|
console.log("featured mentors fetched", {
|
|
11361
12013
|
count: featuredMentors.length,
|
|
11362
12014
|
mentorIds: featuredMentors.map((m) => m === null || m === void 0 ? void 0 : m.unique_id),
|
|
@@ -11376,16 +12028,11 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11376
12028
|
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; });
|
|
11377
12029
|
// Check if found default featured mentor
|
|
11378
12030
|
if (defaultIblMentor) {
|
|
11379
|
-
console.log("
|
|
12031
|
+
console.log("found default IBL mentor", {
|
|
11380
12032
|
mentorId: defaultIblMentor === null || defaultIblMentor === void 0 ? void 0 : defaultIblMentor.unique_id,
|
|
11381
12033
|
mentorName: defaultIblMentor === null || defaultIblMentor === void 0 ? void 0 : defaultIblMentor.name,
|
|
11382
12034
|
});
|
|
11383
|
-
|
|
11384
|
-
const rbacPermissions = await loadMentorsPermissions(defaultIblMentorDbId);
|
|
11385
|
-
onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
|
|
11386
|
-
redirectToMentor === null || redirectToMentor === void 0 ? void 0 : redirectToMentor(tenantKey, (defaultIblMentor === null || defaultIblMentor === void 0 ? void 0 : defaultIblMentor.unique_id) || "");
|
|
11387
|
-
onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
|
|
11388
|
-
return;
|
|
12035
|
+
return defaultIblMentor;
|
|
11389
12036
|
}
|
|
11390
12037
|
}
|
|
11391
12038
|
else {
|
|
@@ -11396,30 +12043,19 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11396
12043
|
// Check if there's a default featured mentor
|
|
11397
12044
|
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; });
|
|
11398
12045
|
if (defaultFeatureMentor) {
|
|
11399
|
-
console.log("
|
|
12046
|
+
console.log("found default featured mentor", {
|
|
11400
12047
|
mentorId: defaultFeatureMentor === null || defaultFeatureMentor === void 0 ? void 0 : defaultFeatureMentor.unique_id,
|
|
11401
12048
|
mentorName: defaultFeatureMentor === null || defaultFeatureMentor === void 0 ? void 0 : defaultFeatureMentor.name,
|
|
11402
12049
|
});
|
|
11403
|
-
|
|
11404
|
-
const rbacPermissions = await loadMentorsPermissions(defaultFeatureMentorDbId);
|
|
11405
|
-
onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
|
|
11406
|
-
redirectToMentor(tenantKey, (defaultFeatureMentor === null || defaultFeatureMentor === void 0 ? void 0 : defaultFeatureMentor.unique_id) || "");
|
|
11407
|
-
onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
|
|
11408
|
-
return;
|
|
12050
|
+
return defaultFeatureMentor;
|
|
11409
12051
|
}
|
|
11410
12052
|
}
|
|
11411
12053
|
// If no default mentor, select the first featured mentor
|
|
11412
|
-
|
|
11413
|
-
|
|
11414
|
-
|
|
11415
|
-
mentorName: (_g = featuredMentors[0]) === null || _g === void 0 ? void 0 : _g.name,
|
|
12054
|
+
console.log("found first featured mentor", {
|
|
12055
|
+
mentorId: (_e = featuredMentors[0]) === null || _e === void 0 ? void 0 : _e.unique_id,
|
|
12056
|
+
mentorName: (_f = featuredMentors[0]) === null || _f === void 0 ? void 0 : _f.name,
|
|
11416
12057
|
});
|
|
11417
|
-
|
|
11418
|
-
const rbacPermissions = await loadMentorsPermissions(firstFeaturedMentorDbId);
|
|
11419
|
-
onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
|
|
11420
|
-
redirectToMentor(tenantKey, firstFeaturedMentorId);
|
|
11421
|
-
onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
|
|
11422
|
-
return;
|
|
12058
|
+
return featuredMentors[0];
|
|
11423
12059
|
}
|
|
11424
12060
|
// If no featured mentors, get non-featured mentors
|
|
11425
12061
|
console.log("no featured mentors found, fetching non-featured mentors", {
|
|
@@ -11433,24 +12069,18 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11433
12069
|
limit: QUERY_LIMIT,
|
|
11434
12070
|
orderBy: "recently_accessed_at",
|
|
11435
12071
|
});
|
|
11436
|
-
const nonFeaturedMentors = ((
|
|
12072
|
+
const nonFeaturedMentors = ((_g = nonFeaturedMentorsResult.data) === null || _g === void 0 ? void 0 : _g.results) || [];
|
|
11437
12073
|
console.log("non-featured mentors fetched", {
|
|
11438
12074
|
count: nonFeaturedMentors.length,
|
|
11439
12075
|
mentorIds: nonFeaturedMentors.map((m) => m === null || m === void 0 ? void 0 : m.unique_id),
|
|
11440
12076
|
});
|
|
11441
12077
|
// Check if we found non-featured mentors
|
|
11442
12078
|
if (nonFeaturedMentors.length > 0) {
|
|
11443
|
-
|
|
11444
|
-
|
|
11445
|
-
|
|
11446
|
-
mentorName: (_l = nonFeaturedMentors[0]) === null || _l === void 0 ? void 0 : _l.name,
|
|
12079
|
+
console.log("found first non-featured mentor", {
|
|
12080
|
+
mentorId: (_h = nonFeaturedMentors[0]) === null || _h === void 0 ? void 0 : _h.unique_id,
|
|
12081
|
+
mentorName: (_j = nonFeaturedMentors[0]) === null || _j === void 0 ? void 0 : _j.name,
|
|
11447
12082
|
});
|
|
11448
|
-
|
|
11449
|
-
const rbacPermissions = await loadMentorsPermissions(firstNonFeaturedMentorDbId);
|
|
11450
|
-
onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
|
|
11451
|
-
redirectToMentor(tenantKey, firstNonFeaturedMentorId);
|
|
11452
|
-
onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
|
|
11453
|
-
return;
|
|
12083
|
+
return nonFeaturedMentors[0];
|
|
11454
12084
|
}
|
|
11455
12085
|
// If no mentors found, check if user is admin
|
|
11456
12086
|
console.log("no mentors found, checking admin status", {
|
|
@@ -11470,7 +12100,7 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11470
12100
|
// @ts-ignore
|
|
11471
12101
|
userId: username,
|
|
11472
12102
|
});
|
|
11473
|
-
const seededMentorsDetails = (
|
|
12103
|
+
const seededMentorsDetails = (_k = seedMentorsResult.data) === null || _k === void 0 ? void 0 : _k.detail;
|
|
11474
12104
|
console.log("mentor seeding completed", {
|
|
11475
12105
|
success: !!seededMentorsDetails,
|
|
11476
12106
|
details: seededMentorsDetails,
|
|
@@ -11485,29 +12115,23 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11485
12115
|
username,
|
|
11486
12116
|
limit: QUERY_LIMIT,
|
|
11487
12117
|
});
|
|
11488
|
-
const featuredMentorsAfterSeed = ((
|
|
12118
|
+
const featuredMentorsAfterSeed = ((_l = featuredMentorsAfterSeedResult.data) === null || _l === void 0 ? void 0 : _l.results) || [];
|
|
11489
12119
|
console.log("featured mentors after seeding", {
|
|
11490
12120
|
count: featuredMentorsAfterSeed.length,
|
|
11491
12121
|
mentorIds: featuredMentorsAfterSeed.map((m) => m === null || m === void 0 ? void 0 : m.unique_id),
|
|
11492
12122
|
});
|
|
11493
12123
|
if (featuredMentorsAfterSeed.length > 0) {
|
|
11494
|
-
|
|
11495
|
-
|
|
11496
|
-
|
|
11497
|
-
mentorName: (_r = featuredMentorsAfterSeed[0]) === null || _r === void 0 ? void 0 : _r.name,
|
|
12124
|
+
console.log("found seeded mentor", {
|
|
12125
|
+
mentorId: (_m = featuredMentorsAfterSeed[0]) === null || _m === void 0 ? void 0 : _m.unique_id,
|
|
12126
|
+
mentorName: (_o = featuredMentorsAfterSeed[0]) === null || _o === void 0 ? void 0 : _o.name,
|
|
11498
12127
|
});
|
|
11499
|
-
|
|
11500
|
-
const rbacPermissions = await loadMentorsPermissions(seededMentorDbId);
|
|
11501
|
-
onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
|
|
11502
|
-
redirectToMentor(tenantKey, seededMentorId);
|
|
11503
|
-
onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
|
|
11504
|
-
return;
|
|
12128
|
+
return featuredMentorsAfterSeed[0];
|
|
11505
12129
|
}
|
|
11506
12130
|
else {
|
|
11507
12131
|
console.log("no seeded mentors found, redirecting to create mentor");
|
|
11508
12132
|
redirectToCreateMentor();
|
|
11509
12133
|
onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
|
|
11510
|
-
return;
|
|
12134
|
+
return undefined;
|
|
11511
12135
|
}
|
|
11512
12136
|
}
|
|
11513
12137
|
else {
|
|
@@ -11515,7 +12139,7 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11515
12139
|
// Prompt the user to create a mentor
|
|
11516
12140
|
redirectToCreateMentor();
|
|
11517
12141
|
onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
|
|
11518
|
-
return;
|
|
12142
|
+
return undefined;
|
|
11519
12143
|
}
|
|
11520
12144
|
}
|
|
11521
12145
|
else {
|
|
@@ -11526,7 +12150,7 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11526
12150
|
// Redirect to no mentors page for non-admin users
|
|
11527
12151
|
redirectToNoMentorsPage();
|
|
11528
12152
|
onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
|
|
11529
|
-
return;
|
|
12153
|
+
return undefined;
|
|
11530
12154
|
}
|
|
11531
12155
|
}
|
|
11532
12156
|
catch (error) {
|
|
@@ -11538,18 +12162,19 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11538
12162
|
isAdmin,
|
|
11539
12163
|
});
|
|
11540
12164
|
onAuthFailure === null || onAuthFailure === void 0 ? void 0 : onAuthFailure(`Unexpected error: ${errorMessage}`);
|
|
12165
|
+
console.log("[auth-redirect] Unexpected error in mentor provider", {
|
|
12166
|
+
error: errorMessage,
|
|
12167
|
+
});
|
|
11541
12168
|
redirectToAuthSpa();
|
|
12169
|
+
return undefined;
|
|
11542
12170
|
}
|
|
11543
12171
|
finally {
|
|
11544
12172
|
setIsLoading(false);
|
|
12173
|
+
onComplete === null || onComplete === void 0 ? void 0 : onComplete();
|
|
11545
12174
|
}
|
|
11546
12175
|
}
|
|
11547
12176
|
async function mentorExistsInTenant(tenantKey, requestedMentorId) {
|
|
11548
|
-
console.log("checking if mentor exists in tenant",
|
|
11549
|
-
tenantKey,
|
|
11550
|
-
requestedMentorId,
|
|
11551
|
-
username,
|
|
11552
|
-
});
|
|
12177
|
+
console.log("checking if mentor exists in tenant", tenantKey, requestedMentorId, username);
|
|
11553
12178
|
try {
|
|
11554
12179
|
const response = await getMentorPublicSettings({
|
|
11555
12180
|
// @ts-ignore
|
|
@@ -11578,13 +12203,10 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11578
12203
|
// Effect to handle mentor determination when tenant path is determined
|
|
11579
12204
|
React.useEffect(() => {
|
|
11580
12205
|
async function checkMentor() {
|
|
11581
|
-
console.log("starting mentor check process",
|
|
11582
|
-
determineUserPath,
|
|
11583
|
-
requestedMentorId,
|
|
11584
|
-
tenantKey,
|
|
11585
|
-
});
|
|
12206
|
+
console.log("starting mentor check process", determineUserPath, requestedMentorId, tenantKey);
|
|
11586
12207
|
if (userIsAccessingPublicRoute && !requestedMentorId) {
|
|
11587
12208
|
setIsLoading(false);
|
|
12209
|
+
onComplete === null || onComplete === void 0 ? void 0 : onComplete();
|
|
11588
12210
|
return;
|
|
11589
12211
|
}
|
|
11590
12212
|
setIsLoading(true);
|
|
@@ -11592,50 +12214,83 @@ function MentorProvider({ children, fallback, onAuthSuccess, onAuthFailure, redi
|
|
|
11592
12214
|
// then this mentor provider will redirect the user to the correct mentor.
|
|
11593
12215
|
if (determineUserPath || forceDetermineMentor) {
|
|
11594
12216
|
console.log("determine user path is true, starting mentor determination");
|
|
11595
|
-
await determineMentorToRedirectTo();
|
|
12217
|
+
const mentor = await determineMentorToRedirectTo();
|
|
12218
|
+
if (mentor === null || mentor === void 0 ? void 0 : mentor.unique_id) {
|
|
12219
|
+
// Get mentor DB ID - use existing ID or fetch from public settings
|
|
12220
|
+
let mentorDbId = mentor === null || mentor === void 0 ? void 0 : mentor.id;
|
|
12221
|
+
if (!mentorDbId) {
|
|
12222
|
+
mentorDbId = await getMentorDbId(mentor);
|
|
12223
|
+
}
|
|
12224
|
+
// Load permissions if we have a mentor DB ID
|
|
12225
|
+
if (mentorDbId) {
|
|
12226
|
+
const rbacPermissions = await loadMentorsPermissions(mentorDbId);
|
|
12227
|
+
onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
|
|
12228
|
+
}
|
|
12229
|
+
// Redirect to the mentor
|
|
12230
|
+
redirectToMentor(tenantKey, mentor.unique_id);
|
|
12231
|
+
onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
|
|
12232
|
+
}
|
|
11596
12233
|
return;
|
|
11597
12234
|
}
|
|
11598
12235
|
else if (requestedMentorId) {
|
|
11599
|
-
console.log(" ", {
|
|
11600
|
-
requestedMentorId,
|
|
11601
|
-
});
|
|
11602
12236
|
const [mentorExists, requestedMentorDbId] = await mentorExistsInTenant(tenantKey, requestedMentorId);
|
|
11603
12237
|
// If the mentor does not exist in the tenant, redirect the user to the correct mentor
|
|
11604
12238
|
if (!mentorExists) {
|
|
11605
|
-
console.log("requested mentor not found in tenant", {
|
|
12239
|
+
console.log("requested mentor not found in tenant", JSON.stringify({
|
|
11606
12240
|
requestedMentorId,
|
|
11607
12241
|
tenantKey,
|
|
11608
12242
|
hasCustomHandler: !!handleMentorNotFound,
|
|
11609
|
-
});
|
|
12243
|
+
}));
|
|
11610
12244
|
if (handleMentorNotFound) {
|
|
11611
12245
|
console.log("calling custom mentor not found handler");
|
|
11612
12246
|
await handleMentorNotFound();
|
|
11613
12247
|
}
|
|
11614
12248
|
else {
|
|
11615
12249
|
console.log("using default mentor determination fallback");
|
|
11616
|
-
await determineMentorToRedirectTo();
|
|
12250
|
+
const mentor = await determineMentorToRedirectTo();
|
|
12251
|
+
if (mentor === null || mentor === void 0 ? void 0 : mentor.unique_id) {
|
|
12252
|
+
// Get mentor DB ID - use existing ID or fetch from public settings
|
|
12253
|
+
let mentorDbId = mentor === null || mentor === void 0 ? void 0 : mentor.id;
|
|
12254
|
+
if (!mentorDbId) {
|
|
12255
|
+
mentorDbId = await getMentorDbId(mentor);
|
|
12256
|
+
}
|
|
12257
|
+
// Load permissions if we have a mentor DB ID
|
|
12258
|
+
if (mentorDbId) {
|
|
12259
|
+
const rbacPermissions = await loadMentorsPermissions(mentorDbId);
|
|
12260
|
+
onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
|
|
12261
|
+
}
|
|
12262
|
+
// Redirect to the mentor
|
|
12263
|
+
redirectToMentor(tenantKey, mentor.unique_id);
|
|
12264
|
+
onAuthSuccess === null || onAuthSuccess === void 0 ? void 0 : onAuthSuccess();
|
|
12265
|
+
}
|
|
11617
12266
|
}
|
|
11618
12267
|
return;
|
|
11619
12268
|
}
|
|
11620
12269
|
else {
|
|
11621
|
-
console.log("requested mentor exists in tenant, proceeding",
|
|
11622
|
-
requestedMentorId,
|
|
11623
|
-
});
|
|
12270
|
+
console.log("requested mentor exists in tenant, proceeding", requestedMentorId);
|
|
11624
12271
|
if (requestedMentorDbId) {
|
|
11625
12272
|
const rbacPermissions = await loadMentorsPermissions(requestedMentorDbId);
|
|
11626
12273
|
onLoadMentorsPermissions === null || onLoadMentorsPermissions === void 0 ? void 0 : onLoadMentorsPermissions(rbacPermissions);
|
|
11627
12274
|
}
|
|
11628
12275
|
setIsLoading(false);
|
|
12276
|
+
onComplete === null || onComplete === void 0 ? void 0 : onComplete();
|
|
11629
12277
|
}
|
|
11630
12278
|
// If the user is navigating to a specific mentor, check if it exists in the tenant
|
|
11631
12279
|
}
|
|
11632
12280
|
else {
|
|
11633
12281
|
console.log("no specific mentor requested, loading complete");
|
|
11634
12282
|
setIsLoading(false);
|
|
12283
|
+
onComplete === null || onComplete === void 0 ? void 0 : onComplete();
|
|
11635
12284
|
}
|
|
11636
12285
|
}
|
|
11637
12286
|
checkMentor();
|
|
11638
|
-
}, [
|
|
12287
|
+
}, [
|
|
12288
|
+
requestedMentorId,
|
|
12289
|
+
determineUserPath,
|
|
12290
|
+
forceDetermineMentor,
|
|
12291
|
+
userIsAccessingPublicRoute,
|
|
12292
|
+
tenantKey,
|
|
12293
|
+
]);
|
|
11639
12294
|
// Show fallback component during mentor determination
|
|
11640
12295
|
if (isLoading) {
|
|
11641
12296
|
console.log("mentor provider showing fallback component");
|
|
@@ -12092,7 +12747,7 @@ function formatProdErrorMessage(code) {
|
|
|
12092
12747
|
|
|
12093
12748
|
const defaultSessionIds = Object.fromEntries(Object.keys(advancedTabsProperties).map((key) => [key, ""]));
|
|
12094
12749
|
const defaultChatState = Object.fromEntries(Object.keys(advancedTabsProperties).map((key) => [key, []]));
|
|
12095
|
-
const initialState = {
|
|
12750
|
+
const initialState$1 = {
|
|
12096
12751
|
chats: defaultChatState,
|
|
12097
12752
|
isTyping: false,
|
|
12098
12753
|
streaming: false,
|
|
@@ -12120,7 +12775,7 @@ const initialState = {
|
|
|
12120
12775
|
};
|
|
12121
12776
|
const chatSlice = createSlice({
|
|
12122
12777
|
name: "chatSliceShared",
|
|
12123
|
-
initialState,
|
|
12778
|
+
initialState: initialState$1,
|
|
12124
12779
|
reducers: {
|
|
12125
12780
|
setChats: (state, action) => {
|
|
12126
12781
|
state.chats = action.payload;
|
|
@@ -12224,6 +12879,25 @@ const chatSlice = createSlice({
|
|
|
12224
12879
|
setShowingSharedChat: (state, action) => {
|
|
12225
12880
|
state.showingSharedChat = action.payload;
|
|
12226
12881
|
},
|
|
12882
|
+
updateFileUrlInMessage: (state, action) => {
|
|
12883
|
+
const { fileId, fileUrl } = action.payload;
|
|
12884
|
+
// Update all tabs' messages that have this file
|
|
12885
|
+
Object.keys(state.chats).forEach((tab) => {
|
|
12886
|
+
state.chats[tab] = state.chats[tab].map((message) => {
|
|
12887
|
+
if (message.fileAttachments && message.fileAttachments.length > 0) {
|
|
12888
|
+
const updatedAttachments = message.fileAttachments.map((attachment) => {
|
|
12889
|
+
// Match by fileId
|
|
12890
|
+
if (attachment.fileId === fileId) {
|
|
12891
|
+
return { ...attachment, uploadUrl: fileUrl };
|
|
12892
|
+
}
|
|
12893
|
+
return attachment;
|
|
12894
|
+
});
|
|
12895
|
+
return { ...message, fileAttachments: updatedAttachments };
|
|
12896
|
+
}
|
|
12897
|
+
return message;
|
|
12898
|
+
});
|
|
12899
|
+
});
|
|
12900
|
+
},
|
|
12227
12901
|
},
|
|
12228
12902
|
});
|
|
12229
12903
|
const chatActions = chatSlice.actions;
|
|
@@ -12507,6 +13181,61 @@ function useTimeTrackerNative(config) {
|
|
|
12507
13181
|
};
|
|
12508
13182
|
}
|
|
12509
13183
|
|
|
13184
|
+
const initialState = {
|
|
13185
|
+
attachedFiles: [],
|
|
13186
|
+
};
|
|
13187
|
+
const filesSlice = createSlice({
|
|
13188
|
+
name: "files",
|
|
13189
|
+
initialState,
|
|
13190
|
+
reducers: {
|
|
13191
|
+
addFiles: (state, action) => {
|
|
13192
|
+
state.attachedFiles = [...state.attachedFiles, ...action.payload];
|
|
13193
|
+
},
|
|
13194
|
+
updateFileProgress: (state, action) => {
|
|
13195
|
+
state.attachedFiles = state.attachedFiles.map((file) => file.id === action.payload.id
|
|
13196
|
+
? { ...file, uploadProgress: action.payload.progress }
|
|
13197
|
+
: file);
|
|
13198
|
+
},
|
|
13199
|
+
updateFileStatus: (state, action) => {
|
|
13200
|
+
state.attachedFiles = state.attachedFiles.map((file) => file.id === action.payload.id
|
|
13201
|
+
? { ...file, uploadStatus: action.payload.status }
|
|
13202
|
+
: file);
|
|
13203
|
+
},
|
|
13204
|
+
updateFileUrl: (state, action) => {
|
|
13205
|
+
state.attachedFiles = state.attachedFiles.map((file) => file.id === action.payload.id
|
|
13206
|
+
? { ...file, uploadUrl: action.payload.uploadUrl }
|
|
13207
|
+
: file);
|
|
13208
|
+
},
|
|
13209
|
+
updateFileMetadata: (state, action) => {
|
|
13210
|
+
state.attachedFiles = state.attachedFiles.map((file) => file.id === action.payload.id
|
|
13211
|
+
? {
|
|
13212
|
+
...file,
|
|
13213
|
+
fileKey: action.payload.fileKey,
|
|
13214
|
+
fileId: action.payload.fileId,
|
|
13215
|
+
}
|
|
13216
|
+
: file);
|
|
13217
|
+
},
|
|
13218
|
+
updateFileRetryCount: (state, action) => {
|
|
13219
|
+
state.attachedFiles = state.attachedFiles.map((file) => file.id === action.payload.id
|
|
13220
|
+
? { ...file, retryCount: action.payload.retryCount }
|
|
13221
|
+
: file);
|
|
13222
|
+
},
|
|
13223
|
+
updateFileUrlFromWebSocket: (state, action) => {
|
|
13224
|
+
state.attachedFiles = state.attachedFiles.map((file) => file.fileId === action.payload.fileId
|
|
13225
|
+
? { ...file, fileUrl: action.payload.fileUrl }
|
|
13226
|
+
: file);
|
|
13227
|
+
},
|
|
13228
|
+
removeFile: (state, action) => {
|
|
13229
|
+
state.attachedFiles = state.attachedFiles.filter((file) => file.id !== action.payload);
|
|
13230
|
+
},
|
|
13231
|
+
clearFiles: (state) => {
|
|
13232
|
+
state.attachedFiles = [];
|
|
13233
|
+
},
|
|
13234
|
+
},
|
|
13235
|
+
});
|
|
13236
|
+
const { addFiles, removeFile, clearFiles, updateFileProgress, updateFileStatus, updateFileUrl, updateFileMetadata, updateFileRetryCount, updateFileUrlFromWebSocket, } = filesSlice.actions;
|
|
13237
|
+
const filesReducer = filesSlice.reducer;
|
|
13238
|
+
|
|
12510
13239
|
const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, enableHaptics = false, hapticFeedback, store, errorHandler, onStatusChange, onStreamingChange, onStreamingMessageUpdate, WebSocketImpl = WebSocket, redirectToAuthSpa, sendMessageToParentWebsite, on402Error, }) => {
|
|
12511
13240
|
const dispatch = useDispatch();
|
|
12512
13241
|
const isWebSocketPaused = React.useRef(false);
|
|
@@ -12530,7 +13259,7 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
|
|
|
12530
13259
|
await hapticFeedback.impactAsync("medium");
|
|
12531
13260
|
}
|
|
12532
13261
|
catch (error) {
|
|
12533
|
-
|
|
13262
|
+
errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler("Haptic feedback failed", error);
|
|
12534
13263
|
}
|
|
12535
13264
|
}
|
|
12536
13265
|
}, [enableHaptics, hapticFeedback]);
|
|
@@ -12542,8 +13271,8 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
|
|
|
12542
13271
|
}
|
|
12543
13272
|
if (!wsToken) {
|
|
12544
13273
|
if (!userIsAccessingPublicRoute) {
|
|
12545
|
-
console.
|
|
12546
|
-
redirectToAuthSpa();
|
|
13274
|
+
console.log("[auth-redirect] WebSocket token is missing for non-anonymous user");
|
|
13275
|
+
redirectToAuthSpa(undefined, undefined, true);
|
|
12547
13276
|
return;
|
|
12548
13277
|
}
|
|
12549
13278
|
}
|
|
@@ -12577,6 +13306,7 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
|
|
|
12577
13306
|
onStreamingChange === null || onStreamingChange === void 0 ? void 0 : onStreamingChange(false);
|
|
12578
13307
|
});
|
|
12579
13308
|
socket.addEventListener("message", (event) => {
|
|
13309
|
+
var _a, _b, _c;
|
|
12580
13310
|
if (isWebSocketPaused.current)
|
|
12581
13311
|
return;
|
|
12582
13312
|
try {
|
|
@@ -12598,6 +13328,16 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
|
|
|
12598
13328
|
onStreamingChange(!!messageData.isTyping);
|
|
12599
13329
|
return;
|
|
12600
13330
|
}
|
|
13331
|
+
// Handle file processing success
|
|
13332
|
+
if (messageData.type === "file_processing_success") {
|
|
13333
|
+
console.log("🟣 File processing success:", messageData);
|
|
13334
|
+
dispatch(chatActions.updateFileUrlInMessage({
|
|
13335
|
+
fileId: messageData.file_id,
|
|
13336
|
+
fileName: messageData.file_name,
|
|
13337
|
+
fileUrl: messageData.file_url,
|
|
13338
|
+
}));
|
|
13339
|
+
return;
|
|
13340
|
+
}
|
|
12601
13341
|
// Handle start of new streaming session
|
|
12602
13342
|
if (messageData.generation_id &&
|
|
12603
13343
|
!messageData.data &&
|
|
@@ -12616,14 +13356,14 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
|
|
|
12616
13356
|
if (messageData.data !== undefined || messageData.eos !== undefined) {
|
|
12617
13357
|
const messageText = messageData.data || "";
|
|
12618
13358
|
// If we have content to add
|
|
12619
|
-
if (messageText) {
|
|
13359
|
+
if (messageText && currentStreamingMessage.current) {
|
|
12620
13360
|
currentStreamingMessage.current = {
|
|
12621
13361
|
...currentStreamingMessage.current,
|
|
12622
13362
|
content: currentStreamingMessage.current.content + messageText,
|
|
12623
13363
|
};
|
|
12624
13364
|
onStreamingMessageUpdate === null || onStreamingMessageUpdate === void 0 ? void 0 : onStreamingMessageUpdate(currentStreamingMessage.current);
|
|
12625
13365
|
// Update or add message in Redux store
|
|
12626
|
-
if (currentStreamingMessage.current.id) {
|
|
13366
|
+
if ((_a = currentStreamingMessage.current) === null || _a === void 0 ? void 0 : _a.id) {
|
|
12627
13367
|
dispatch(chatActions.appendMessageToActiveTab({
|
|
12628
13368
|
id: currentStreamingMessage.current.id,
|
|
12629
13369
|
content: currentStreamingMessage.current.content,
|
|
@@ -12633,8 +13373,8 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
|
|
|
12633
13373
|
// Handle end of stream
|
|
12634
13374
|
if (messageData.eos) {
|
|
12635
13375
|
// Final update to Redux store with complete message
|
|
12636
|
-
if (currentStreamingMessage.current.id &&
|
|
12637
|
-
currentStreamingMessage.current.content) {
|
|
13376
|
+
if (((_b = currentStreamingMessage.current) === null || _b === void 0 ? void 0 : _b.id) &&
|
|
13377
|
+
((_c = currentStreamingMessage.current) === null || _c === void 0 ? void 0 : _c.content)) {
|
|
12638
13378
|
dispatch(chatActions.appendMessageToActiveTab({
|
|
12639
13379
|
id: currentStreamingMessage.current.id,
|
|
12640
13380
|
content: currentStreamingMessage.current.content,
|
|
@@ -12649,13 +13389,13 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
|
|
|
12649
13389
|
}
|
|
12650
13390
|
}
|
|
12651
13391
|
catch (error) {
|
|
12652
|
-
|
|
13392
|
+
errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler("Error processing message", error);
|
|
12653
13393
|
onStreamingChange === null || onStreamingChange === void 0 ? void 0 : onStreamingChange(false);
|
|
12654
13394
|
onStatusChange("error");
|
|
12655
13395
|
}
|
|
12656
13396
|
});
|
|
12657
13397
|
socket.addEventListener("error", (error) => {
|
|
12658
|
-
|
|
13398
|
+
errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler("WebSocket error", error);
|
|
12659
13399
|
onStreamingChange === null || onStreamingChange === void 0 ? void 0 : onStreamingChange(false);
|
|
12660
13400
|
onStatusChange("error");
|
|
12661
13401
|
});
|
|
@@ -12693,19 +13433,31 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
|
|
|
12693
13433
|
};
|
|
12694
13434
|
};
|
|
12695
13435
|
const sendMessage = React.useCallback(async (tab, text, options) => {
|
|
12696
|
-
var _a;
|
|
13436
|
+
var _a, _b;
|
|
12697
13437
|
dispatch(chatActions.setShowingSharedChat(false));
|
|
12698
|
-
if
|
|
13438
|
+
// Allow sending if there's text OR file references
|
|
13439
|
+
if (!text.trim() &&
|
|
13440
|
+
(!(options === null || options === void 0 ? void 0 : options.fileReferences) || options.fileReferences.length === 0)) {
|
|
12699
13441
|
return;
|
|
13442
|
+
}
|
|
12700
13443
|
onStatusChange("pending");
|
|
12701
13444
|
isWebSocketPaused.current = false;
|
|
12702
13445
|
await triggerHapticFeedback();
|
|
13446
|
+
// Create file attachments array from file references if present
|
|
13447
|
+
const fileAttachments = (_a = options === null || options === void 0 ? void 0 : options.fileReferences) === null || _a === void 0 ? void 0 : _a.map((ref) => ({
|
|
13448
|
+
fileName: ref.file_name,
|
|
13449
|
+
fileType: ref.content_type,
|
|
13450
|
+
fileSize: ref.file_size,
|
|
13451
|
+
uploadUrl: ref.upload_url, // Include URL for display
|
|
13452
|
+
fileId: ref.file_id, // Include fileId for matching WebSocket updates
|
|
13453
|
+
}));
|
|
12703
13454
|
const userMessage = {
|
|
12704
13455
|
id: `user-${Date.now()}`,
|
|
12705
13456
|
role: "user",
|
|
12706
13457
|
content: text,
|
|
12707
13458
|
timestamp: new Date().toISOString(),
|
|
12708
|
-
visible: (
|
|
13459
|
+
visible: (_b = options === null || options === void 0 ? void 0 : options.visible) !== null && _b !== void 0 ? _b : true,
|
|
13460
|
+
fileAttachments,
|
|
12709
13461
|
};
|
|
12710
13462
|
// Notify parent to add user message
|
|
12711
13463
|
// onAddUserMessage?.(tab, userMessage);
|
|
@@ -12717,8 +13469,14 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
|
|
|
12717
13469
|
flow: flowConfig,
|
|
12718
13470
|
session_id: sessionId,
|
|
12719
13471
|
token: wsToken,
|
|
12720
|
-
prompt: text,
|
|
13472
|
+
prompt: text || "", // Allow empty prompt when sending files
|
|
12721
13473
|
};
|
|
13474
|
+
if ((options === null || options === void 0 ? void 0 : options.fileReferences) && options.fileReferences.length > 0) {
|
|
13475
|
+
messageData = {
|
|
13476
|
+
...messageData,
|
|
13477
|
+
file_references: options.fileReferences,
|
|
13478
|
+
};
|
|
13479
|
+
}
|
|
12722
13480
|
if (iframeContext.pageContent) {
|
|
12723
13481
|
messageData = {
|
|
12724
13482
|
...messageData,
|
|
@@ -12788,8 +13546,12 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
|
|
|
12788
13546
|
}
|
|
12789
13547
|
};
|
|
12790
13548
|
const _initiateServerStopGeneration = () => {
|
|
12791
|
-
var _a;
|
|
12792
|
-
(_a =
|
|
13549
|
+
var _a, _b;
|
|
13550
|
+
if (!((_a = currentStreamingMessage.current) === null || _a === void 0 ? void 0 : _a.id)) {
|
|
13551
|
+
console.warn("Cannot stop generation: no active generation ID");
|
|
13552
|
+
return;
|
|
13553
|
+
}
|
|
13554
|
+
(_b = stopGenerationSocket === null || stopGenerationSocket === void 0 ? void 0 : stopGenerationSocket.current) === null || _b === void 0 ? void 0 : _b.send(JSON.stringify({
|
|
12793
13555
|
generation_id: currentStreamingMessage.current.id,
|
|
12794
13556
|
name: flowConfig.name,
|
|
12795
13557
|
tenant: flowConfig.tenant,
|
|
@@ -12849,7 +13611,7 @@ const useChat = ({ wsUrl, wsToken, flowConfig, sessionId, stopGenerationWsUrl, e
|
|
|
12849
13611
|
};
|
|
12850
13612
|
};
|
|
12851
13613
|
|
|
12852
|
-
function useMentorSettings({ mentorId, tenantKey, username }) {
|
|
13614
|
+
function useMentorSettings({ mentorId, tenantKey, username, }) {
|
|
12853
13615
|
var _a, _b, _c, _d;
|
|
12854
13616
|
const isLoggedIn = username !== ANONYMOUS_USERNAME;
|
|
12855
13617
|
const { data: mentorSettings } = useGetMentorSettingsQuery({
|
|
@@ -12885,6 +13647,9 @@ function useMentorSettings({ mentorId, tenantKey, username }) {
|
|
|
12885
13647
|
mentorUniqueId: isLoggedIn
|
|
12886
13648
|
? mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.mentor_unique_id
|
|
12887
13649
|
: mentorPublicSettings === null || mentorPublicSettings === void 0 ? void 0 : mentorPublicSettings.mentor_unique_id,
|
|
13650
|
+
mentorVisibility: isLoggedIn
|
|
13651
|
+
? mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.mentor_visibility
|
|
13652
|
+
: mentorPublicSettings === null || mentorPublicSettings === void 0 ? void 0 : mentorPublicSettings.mentor_visibility,
|
|
12888
13653
|
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,
|
|
12889
13654
|
enableGuidedPrompts: isLoggedIn
|
|
12890
13655
|
? mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.enable_guided_prompts
|
|
@@ -12903,8 +13668,8 @@ function useMentorSettings({ mentorId, tenantKey, username }) {
|
|
|
12903
13668
|
};
|
|
12904
13669
|
}
|
|
12905
13670
|
|
|
12906
|
-
function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, token, wsUrl, stopGenerationWsUrl, redirectToAuthSpa, errorHandler, sendMessageToParentWebsite, isPreviewMode, mentorShareableToken, on402Error, }) {
|
|
12907
|
-
var _a, _b, _c, _d;
|
|
13671
|
+
function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, token, wsUrl, stopGenerationWsUrl, redirectToAuthSpa, errorHandler, sendMessageToParentWebsite, isPreviewMode, mentorShareableToken, on402Error, cachedSessionId, onStartNewChat, }) {
|
|
13672
|
+
var _a, _b, _c, _d, _e;
|
|
12908
13673
|
const dispatch = useDispatch();
|
|
12909
13674
|
const [createSessionId, { isLoading: isLoadingSessionIds }] = useCreateSessionIdMutation();
|
|
12910
13675
|
const chats = useSelector(selectChats);
|
|
@@ -12942,7 +13707,7 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
12942
13707
|
username,
|
|
12943
13708
|
pathway: mentorId,
|
|
12944
13709
|
},
|
|
12945
|
-
sessionId: sessionIds[activeTab],
|
|
13710
|
+
sessionId: (_a = cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId]) !== null && _a !== void 0 ? _a : sessionIds[activeTab],
|
|
12946
13711
|
activeTab,
|
|
12947
13712
|
wsToken: token,
|
|
12948
13713
|
errorHandler,
|
|
@@ -12953,6 +13718,56 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
12953
13718
|
onStatusChange,
|
|
12954
13719
|
on402Error,
|
|
12955
13720
|
});
|
|
13721
|
+
const [getSessionChats, { isError: isErrorGettingSessionChats }] = useLazyGetSessionIdQuery();
|
|
13722
|
+
React.useEffect(() => {
|
|
13723
|
+
const getChats = async () => {
|
|
13724
|
+
var _a, _b;
|
|
13725
|
+
try {
|
|
13726
|
+
const { data } = await getSessionChats({
|
|
13727
|
+
sessionId: (_a = cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId]) !== null && _a !== void 0 ? _a : "",
|
|
13728
|
+
org: tenantKey,
|
|
13729
|
+
share: true,
|
|
13730
|
+
});
|
|
13731
|
+
let previousChats = [];
|
|
13732
|
+
try {
|
|
13733
|
+
previousChats =
|
|
13734
|
+
((_b = data === null || data === void 0 ? void 0 : data.results) === null || _b === void 0 ? void 0 : _b.map((result) => {
|
|
13735
|
+
return {
|
|
13736
|
+
...result,
|
|
13737
|
+
role: result.type === "human" ? "user" : "assistant",
|
|
13738
|
+
visible: true,
|
|
13739
|
+
id: new Date().getTime(),
|
|
13740
|
+
content: typeof result.content === "object" &&
|
|
13741
|
+
result.content.length > 0
|
|
13742
|
+
? result.content[0].text
|
|
13743
|
+
: result.content,
|
|
13744
|
+
};
|
|
13745
|
+
}).reverse()) || [];
|
|
13746
|
+
}
|
|
13747
|
+
catch (error) {
|
|
13748
|
+
console.error(JSON.stringify(error));
|
|
13749
|
+
}
|
|
13750
|
+
// Ensures that the first AI response due to a Proactive prompt
|
|
13751
|
+
// doesn't show up as part of the chats
|
|
13752
|
+
if ((data === null || data === void 0 ? void 0 : data.proactive_prompt) &&
|
|
13753
|
+
previousChats.length > 0 &&
|
|
13754
|
+
previousChats[0].type === "ai") {
|
|
13755
|
+
previousChats.splice(0, 1);
|
|
13756
|
+
}
|
|
13757
|
+
dispatch(chatActions.setNewMessages(previousChats));
|
|
13758
|
+
}
|
|
13759
|
+
catch (error) {
|
|
13760
|
+
console.error(JSON.stringify(error));
|
|
13761
|
+
}
|
|
13762
|
+
};
|
|
13763
|
+
if (cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId]) {
|
|
13764
|
+
dispatch(chatActions.updateSessionIds(cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId]));
|
|
13765
|
+
getChats();
|
|
13766
|
+
}
|
|
13767
|
+
}, [cachedSessionId]);
|
|
13768
|
+
React.useEffect(() => {
|
|
13769
|
+
}, [isErrorGettingSessionChats]);
|
|
13770
|
+
React.useEffect(() => { }, []);
|
|
12956
13771
|
const startNewChat = React.useCallback(async () => {
|
|
12957
13772
|
// Reset all chat state
|
|
12958
13773
|
if (!showingSharedChat) {
|
|
@@ -12962,6 +13777,7 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
12962
13777
|
dispatch(chatActions.setStreaming(false));
|
|
12963
13778
|
dispatch(chatActions.resetCurrentStreamingMessage(undefined));
|
|
12964
13779
|
dispatch(chatActions.setTools([]));
|
|
13780
|
+
dispatch(clearFiles(undefined));
|
|
12965
13781
|
if (isPreviewMode) {
|
|
12966
13782
|
return;
|
|
12967
13783
|
}
|
|
@@ -12972,6 +13788,7 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
12972
13788
|
// @ts-ignore
|
|
12973
13789
|
requestBody["shareable_link_token"] = mentorShareableToken;
|
|
12974
13790
|
}
|
|
13791
|
+
console.log("[startNewChat] requestBody", tenantKey, username, JSON.stringify(requestBody));
|
|
12975
13792
|
const response = await createSessionId({
|
|
12976
13793
|
org: tenantKey,
|
|
12977
13794
|
// @ts-ignore
|
|
@@ -12979,10 +13796,15 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
12979
13796
|
requestBody,
|
|
12980
13797
|
}).unwrap();
|
|
12981
13798
|
dispatch(chatActions.updateSessionIds(response.session_id));
|
|
12982
|
-
|
|
13799
|
+
onStartNewChat === null || onStartNewChat === void 0 ? void 0 : onStartNewChat(response.session_id);
|
|
12983
13800
|
}
|
|
12984
13801
|
catch (error) {
|
|
12985
|
-
|
|
13802
|
+
if (mentorSettings.mentorVisibility !==
|
|
13803
|
+
iblaiApi.MentorVisibilityEnum.VIEWABLE_BY_ANYONE) {
|
|
13804
|
+
errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler(`Failed to start new chat: ${JSON.stringify(error)}`);
|
|
13805
|
+
console.log("[auth-redirect] Failed to start new chat", JSON.stringify({ error }));
|
|
13806
|
+
redirectToAuthSpa(undefined, undefined, true);
|
|
13807
|
+
}
|
|
12986
13808
|
}
|
|
12987
13809
|
}, [
|
|
12988
13810
|
isPreviewMode,
|
|
@@ -12996,7 +13818,8 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
12996
13818
|
]);
|
|
12997
13819
|
React.useEffect(() => {
|
|
12998
13820
|
if (!showingSharedChat || mentorSettings.allowAnonymous) {
|
|
12999
|
-
if (mentorSettings.allowAnonymous !== undefined
|
|
13821
|
+
if (mentorSettings.allowAnonymous !== undefined &&
|
|
13822
|
+
!(cachedSessionId === null || cachedSessionId === void 0 ? void 0 : cachedSessionId[mentorId])) {
|
|
13000
13823
|
startNewChat();
|
|
13001
13824
|
}
|
|
13002
13825
|
}
|
|
@@ -13048,7 +13871,7 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
13048
13871
|
}
|
|
13049
13872
|
}
|
|
13050
13873
|
catch (error) {
|
|
13051
|
-
errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler(
|
|
13874
|
+
errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler(`Failed to start new chat: ${error}`);
|
|
13052
13875
|
return;
|
|
13053
13876
|
}
|
|
13054
13877
|
}
|
|
@@ -13068,9 +13891,9 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
13068
13891
|
currentStreamingMessage,
|
|
13069
13892
|
activeTab,
|
|
13070
13893
|
uniqueMentorId: mentorId,
|
|
13071
|
-
mentorName: (
|
|
13072
|
-
profileImage: (
|
|
13073
|
-
enabledGuidedPrompts: (
|
|
13894
|
+
mentorName: (_b = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.mentorName) !== null && _b !== void 0 ? _b : "",
|
|
13895
|
+
profileImage: (_c = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.profileImage) !== null && _c !== void 0 ? _c : "",
|
|
13896
|
+
enabledGuidedPrompts: (_d = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.enableGuidedPrompts) !== null && _d !== void 0 ? _d : true,
|
|
13074
13897
|
sendMessage,
|
|
13075
13898
|
stopGenerating,
|
|
13076
13899
|
setMessage,
|
|
@@ -13082,7 +13905,7 @@ function useAdvancedChat({ tenantKey, mentorId, username = ANONYMOUS_USERNAME, t
|
|
|
13082
13905
|
isConnected,
|
|
13083
13906
|
messageQueue,
|
|
13084
13907
|
sessionIds,
|
|
13085
|
-
enableSafetyDisclaimer: (
|
|
13908
|
+
enableSafetyDisclaimer: (_e = mentorSettings === null || mentorSettings === void 0 ? void 0 : mentorSettings.safetyDisclaimer) !== null && _e !== void 0 ? _e : false,
|
|
13086
13909
|
resetConnection,
|
|
13087
13910
|
};
|
|
13088
13911
|
}
|
|
@@ -17938,11 +18761,130 @@ const tenantSchema = z.object({
|
|
|
17938
18761
|
});
|
|
17939
18762
|
const tenantKeySchema = z.string().min(1);
|
|
17940
18763
|
|
|
18764
|
+
/**
|
|
18765
|
+
* Chat area size constants
|
|
18766
|
+
*/
|
|
18767
|
+
const CHAT_AREA_SIZE = {
|
|
18768
|
+
DEFAULT: 672,
|
|
18769
|
+
MIN: 672,
|
|
18770
|
+
MAX: 1024,
|
|
18771
|
+
};
|
|
18772
|
+
|
|
18773
|
+
/**
|
|
18774
|
+
* Extract file information from File object
|
|
18775
|
+
*/
|
|
18776
|
+
function getFileInfo(file) {
|
|
18777
|
+
const fileName = file.name;
|
|
18778
|
+
const contentType = file.type || "application/octet-stream";
|
|
18779
|
+
const fileSize = file.size;
|
|
18780
|
+
return {
|
|
18781
|
+
fileName,
|
|
18782
|
+
contentType,
|
|
18783
|
+
fileSize,
|
|
18784
|
+
};
|
|
18785
|
+
}
|
|
18786
|
+
/**
|
|
18787
|
+
* Request presigned S3 URL from backend
|
|
18788
|
+
* Note: This function should be called via the RTK Query mutation hook
|
|
18789
|
+
* This is a helper to show the data flow
|
|
18790
|
+
*/
|
|
18791
|
+
async function requestPresignedUrl(sessionId, file, getUploadUrlFn, org, userId) {
|
|
18792
|
+
const { fileName, contentType, fileSize } = getFileInfo(file);
|
|
18793
|
+
return await getUploadUrlFn({
|
|
18794
|
+
org,
|
|
18795
|
+
userId,
|
|
18796
|
+
requestBody: {
|
|
18797
|
+
session_id: sessionId,
|
|
18798
|
+
file_name: fileName,
|
|
18799
|
+
content_type: contentType,
|
|
18800
|
+
file_size: fileSize,
|
|
18801
|
+
},
|
|
18802
|
+
});
|
|
18803
|
+
}
|
|
18804
|
+
/**
|
|
18805
|
+
* Upload file directly to S3 using presigned URL
|
|
18806
|
+
* Uses axios for cross-platform support (web + React Native)
|
|
18807
|
+
*/
|
|
18808
|
+
async function uploadToS3(presignedUrl, file, contentType, onProgress) {
|
|
18809
|
+
await axios.put(presignedUrl, file, {
|
|
18810
|
+
headers: {
|
|
18811
|
+
"Content-Type": contentType,
|
|
18812
|
+
},
|
|
18813
|
+
onUploadProgress: (progressEvent) => {
|
|
18814
|
+
if (onProgress && progressEvent.total) {
|
|
18815
|
+
const progress = Math.round((progressEvent.loaded / progressEvent.total) * 100);
|
|
18816
|
+
onProgress(progress);
|
|
18817
|
+
}
|
|
18818
|
+
},
|
|
18819
|
+
});
|
|
18820
|
+
}
|
|
18821
|
+
/**
|
|
18822
|
+
* Complete file upload flow:
|
|
18823
|
+
* 1. Request presigned URL
|
|
18824
|
+
* 2. Upload to S3
|
|
18825
|
+
* 3. Return file reference
|
|
18826
|
+
*/
|
|
18827
|
+
async function createFileReference(file, sessionId, getUploadUrlFn, org, userId, onProgress) {
|
|
18828
|
+
// Step 1: Get presigned URL
|
|
18829
|
+
const presignedResponse = await requestPresignedUrl(sessionId, file, getUploadUrlFn, org, userId);
|
|
18830
|
+
// Step 2: Upload to S3
|
|
18831
|
+
const { fileName, contentType, fileSize } = getFileInfo(file);
|
|
18832
|
+
await uploadToS3(presignedResponse.upload_url, file, contentType, onProgress);
|
|
18833
|
+
// Step 3: Return file reference
|
|
18834
|
+
return {
|
|
18835
|
+
file_id: presignedResponse.file_id,
|
|
18836
|
+
file_key: presignedResponse.file_key,
|
|
18837
|
+
file_name: fileName,
|
|
18838
|
+
content_type: contentType,
|
|
18839
|
+
file_size: fileSize,
|
|
18840
|
+
};
|
|
18841
|
+
}
|
|
18842
|
+
/**
|
|
18843
|
+
* Upload multiple files and return their references
|
|
18844
|
+
*/
|
|
18845
|
+
async function createMultipleFileReferences(files, sessionId, getUploadUrlFn, org, userId, onFileProgress) {
|
|
18846
|
+
const fileReferences = [];
|
|
18847
|
+
for (let i = 0; i < files.length; i++) {
|
|
18848
|
+
const file = files[i];
|
|
18849
|
+
const onProgress = onFileProgress
|
|
18850
|
+
? (progress) => onFileProgress(i, progress)
|
|
18851
|
+
: undefined;
|
|
18852
|
+
const fileReference = await createFileReference(file, sessionId, getUploadUrlFn, org, userId, onProgress);
|
|
18853
|
+
fileReferences.push(fileReference);
|
|
18854
|
+
}
|
|
18855
|
+
return fileReferences;
|
|
18856
|
+
}
|
|
18857
|
+
/**
|
|
18858
|
+
* Validate file before upload
|
|
18859
|
+
* Returns error message if invalid, null if valid
|
|
18860
|
+
*/
|
|
18861
|
+
function validateFile(file, maxSizeBytes, allowedTypes) {
|
|
18862
|
+
var _a;
|
|
18863
|
+
// Check file size
|
|
18864
|
+
if (maxSizeBytes && file.size > maxSizeBytes) {
|
|
18865
|
+
const maxSizeMB = (maxSizeBytes / (1024 * 1024)).toFixed(2);
|
|
18866
|
+
const fileSizeMB = (file.size / (1024 * 1024)).toFixed(2);
|
|
18867
|
+
return `File size (${fileSizeMB}MB) exceeds maximum allowed size (${maxSizeMB}MB)`;
|
|
18868
|
+
}
|
|
18869
|
+
// Check file type
|
|
18870
|
+
if (allowedTypes && allowedTypes.length > 0) {
|
|
18871
|
+
const fileExtension = (_a = file.name.split(".").pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
18872
|
+
const fileType = file.type.toLowerCase();
|
|
18873
|
+
const isTypeAllowed = allowedTypes.some((allowed) => fileType.includes(allowed.toLowerCase()) ||
|
|
18874
|
+
fileExtension === allowed.toLowerCase().replace(".", ""));
|
|
18875
|
+
if (!isTypeAllowed) {
|
|
18876
|
+
return `File type not allowed. Allowed types: ${allowedTypes.join(", ")}`;
|
|
18877
|
+
}
|
|
18878
|
+
}
|
|
18879
|
+
return null;
|
|
18880
|
+
}
|
|
18881
|
+
|
|
17941
18882
|
exports.ALPHANUMERIC_32_REGEX = ALPHANUMERIC_32_REGEX;
|
|
17942
18883
|
exports.ANONYMOUS_USERNAME = ANONYMOUS_USERNAME;
|
|
17943
18884
|
exports.AuthContext = AuthContext;
|
|
17944
18885
|
exports.AuthContextProvider = AuthContextProvider;
|
|
17945
18886
|
exports.AuthProvider = AuthProvider;
|
|
18887
|
+
exports.CHAT_AREA_SIZE = CHAT_AREA_SIZE;
|
|
17946
18888
|
exports.LOCAL_STORAGE_KEYS = LOCAL_STORAGE_KEYS;
|
|
17947
18889
|
exports.MAX_INITIAL_WEBSOCKET_CONNECTION_ATTEMPTS = MAX_INITIAL_WEBSOCKET_CONNECTION_ATTEMPTS;
|
|
17948
18890
|
exports.MENTOR_CHAT_DOCUMENTS_EXTENSIONS = MENTOR_CHAT_DOCUMENTS_EXTENSIONS;
|
|
@@ -17959,20 +18901,42 @@ exports.TenantContext = TenantContext;
|
|
|
17959
18901
|
exports.TenantContextProvider = TenantContextProvider;
|
|
17960
18902
|
exports.TenantProvider = TenantProvider;
|
|
17961
18903
|
exports.TimeTracker = TimeTracker;
|
|
18904
|
+
exports.addFiles = addFiles;
|
|
17962
18905
|
exports.addProtocolToUrl = addProtocolToUrl;
|
|
17963
18906
|
exports.advancedTabs = advancedTabs;
|
|
17964
18907
|
exports.advancedTabsProperties = advancedTabsProperties;
|
|
17965
18908
|
exports.chatActions = chatActions;
|
|
17966
18909
|
exports.chatSliceReducerShared = chatSliceReducerShared;
|
|
17967
18910
|
exports.clearAuthCookies = clearAuthCookies;
|
|
18911
|
+
exports.clearCookies = clearCookies;
|
|
18912
|
+
exports.clearCurrentTenantCookie = clearCurrentTenantCookie;
|
|
18913
|
+
exports.clearFiles = clearFiles;
|
|
18914
|
+
exports.createFileReference = createFileReference;
|
|
18915
|
+
exports.createMultipleFileReferences = createMultipleFileReferences;
|
|
17968
18916
|
exports.defaultSessionIds = defaultSessionIds;
|
|
18917
|
+
exports.deleteCookie = deleteCookie;
|
|
18918
|
+
exports.deleteCookieOnAllDomains = deleteCookieOnAllDomains;
|
|
18919
|
+
exports.filesReducer = filesReducer;
|
|
18920
|
+
exports.filesSlice = filesSlice;
|
|
17969
18921
|
exports.formatRelativeTime = formatRelativeTime;
|
|
18922
|
+
exports.getAuthSpaJoinUrl = getAuthSpaJoinUrl;
|
|
18923
|
+
exports.getDomainParts = getDomainParts;
|
|
18924
|
+
exports.getFileInfo = getFileInfo;
|
|
17970
18925
|
exports.getInitials = getInitials;
|
|
18926
|
+
exports.getParentDomain = getParentDomain;
|
|
18927
|
+
exports.getPlatformKey = getPlatformKey;
|
|
17971
18928
|
exports.getTimeAgo = getTimeAgo;
|
|
17972
18929
|
exports.getUserName = getUserName;
|
|
18930
|
+
exports.handleLogout = handleLogout;
|
|
17973
18931
|
exports.isAlphaNumeric32 = isAlphaNumeric32;
|
|
18932
|
+
exports.isInIframe = isInIframe;
|
|
17974
18933
|
exports.isJSON = isJSON;
|
|
18934
|
+
exports.isLoggedIn = isLoggedIn;
|
|
17975
18935
|
exports.loadMetadataConfig = loadMetadataConfig;
|
|
18936
|
+
exports.redirectToAuthSpa = redirectToAuthSpa;
|
|
18937
|
+
exports.redirectToAuthSpaJoinTenant = redirectToAuthSpaJoinTenant;
|
|
18938
|
+
exports.removeFile = removeFile;
|
|
18939
|
+
exports.requestPresignedUrl = requestPresignedUrl;
|
|
17976
18940
|
exports.selectActiveChatMessages = selectActiveChatMessages;
|
|
17977
18941
|
exports.selectActiveTab = selectActiveTab;
|
|
17978
18942
|
exports.selectChats = selectChats;
|
|
@@ -17993,10 +18957,19 @@ exports.selectStreaming = selectStreaming;
|
|
|
17993
18957
|
exports.selectToken = selectToken;
|
|
17994
18958
|
exports.selectTokenEnabled = selectTokenEnabled;
|
|
17995
18959
|
exports.selectTools = selectTools;
|
|
18960
|
+
exports.sendMessageToParentWebsite = sendMessageToParentWebsite;
|
|
18961
|
+
exports.setCookieForAuth = setCookieForAuth;
|
|
17996
18962
|
exports.syncAuthToCookies = syncAuthToCookies;
|
|
17997
18963
|
exports.tenantKeySchema = tenantKeySchema;
|
|
17998
18964
|
exports.tenantSchema = tenantSchema;
|
|
17999
18965
|
exports.translatePrompt = translatePrompt;
|
|
18966
|
+
exports.updateFileMetadata = updateFileMetadata;
|
|
18967
|
+
exports.updateFileProgress = updateFileProgress;
|
|
18968
|
+
exports.updateFileRetryCount = updateFileRetryCount;
|
|
18969
|
+
exports.updateFileStatus = updateFileStatus;
|
|
18970
|
+
exports.updateFileUrl = updateFileUrl;
|
|
18971
|
+
exports.updateFileUrlFromWebSocket = updateFileUrlFromWebSocket;
|
|
18972
|
+
exports.uploadToS3 = uploadToS3;
|
|
18000
18973
|
exports.useAdvancedChat = useAdvancedChat;
|
|
18001
18974
|
exports.useAuthContext = useAuthContext;
|
|
18002
18975
|
exports.useAuthProvider = useAuthProvider;
|
|
@@ -18014,4 +18987,5 @@ exports.useTimeTracker = useTimeTracker;
|
|
|
18014
18987
|
exports.useTimeTrackerNative = useTimeTrackerNative;
|
|
18015
18988
|
exports.useUserProfileUpdate = useUserProfileUpdate;
|
|
18016
18989
|
exports.userDataSchema = userDataSchema;
|
|
18990
|
+
exports.validateFile = validateFile;
|
|
18017
18991
|
//# sourceMappingURL=index.js.map
|