@zeniai/client-epic-state 5.3.18-betaAK2 → 5.3.18
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/lib/entity/tenant/epic/fetchAllTenantsEpic.d.ts +4 -2
- package/lib/entity/tenant/epic/fetchAllTenantsEpic.js +42 -45
- package/lib/entity/tenant/tenantPayload.d.ts +1 -17
- package/lib/entity/tenant/tenantReducer.d.ts +2 -7
- package/lib/entity/tenant/tenantReducer.js +19 -48
- package/lib/entity/tenant/tenantSelector.d.ts +6 -26
- package/lib/entity/tenant/tenantSelector.js +96 -119
- package/lib/entity/tenant/tenantState.d.ts +0 -10
- package/lib/epic.d.ts +1 -2
- package/lib/epic.js +0 -2
- package/lib/esm/entity/tenant/epic/fetchAllTenantsEpic.js +46 -49
- package/lib/esm/entity/tenant/tenantReducer.js +17 -46
- package/lib/esm/entity/tenant/tenantSelector.js +95 -115
- package/lib/esm/epic.js +0 -2
- package/lib/esm/index.js +7 -7
- package/lib/esm/view/aiCfoView/aiCfoViewReducer.js +3 -65
- package/lib/esm/view/aiCfoView/aiCfoViewSelector.js +0 -25
- package/lib/esm/view/dashboard/dashboardEpic.js +4 -0
- package/lib/esm/view/dashboard/dashboardSelector.js +3 -2
- package/lib/esm/view/financeStatement/financeStatementEpic.js +5 -1
- package/lib/esm/view/people/peoplePageEpic.js +4 -0
- package/lib/index.d.ts +8 -8
- package/lib/index.js +46 -56
- package/lib/view/aiCfoView/aiCfoViewPayload.d.ts +0 -20
- package/lib/view/aiCfoView/aiCfoViewReducer.d.ts +2 -2
- package/lib/view/aiCfoView/aiCfoViewReducer.js +4 -66
- package/lib/view/aiCfoView/aiCfoViewSelector.d.ts +1 -8
- package/lib/view/aiCfoView/aiCfoViewSelector.js +0 -27
- package/lib/view/aiCfoView/aiCfoViewState.d.ts +0 -9
- package/lib/view/dashboard/dashboardEpic.js +4 -0
- package/lib/view/dashboard/dashboardSelector.d.ts +2 -0
- package/lib/view/dashboard/dashboardSelector.js +2 -1
- package/lib/view/financeStatement/financeStatementEpic.js +5 -1
- package/lib/view/people/peoplePageEpic.js +4 -0
- package/package.json +1 -1
- package/lib/esm/view/aiCfoView/epics/transcribeAudioEpic.js +0 -60
- package/lib/view/aiCfoView/epics/transcribeAudioEpic.d.ts +0 -19
- package/lib/view/aiCfoView/epics/transcribeAudioEpic.js +0 -64
|
@@ -17,7 +17,6 @@ export const initialState = {
|
|
|
17
17
|
error: undefined,
|
|
18
18
|
accountLocked: false,
|
|
19
19
|
tenantsById: {},
|
|
20
|
-
tenantSummariesById: {},
|
|
21
20
|
onboardingTenantsById: {},
|
|
22
21
|
tenantIds: [],
|
|
23
22
|
signInState: 'Not-Started',
|
|
@@ -108,24 +107,26 @@ const tenant = createSlice({
|
|
|
108
107
|
});
|
|
109
108
|
},
|
|
110
109
|
},
|
|
111
|
-
|
|
110
|
+
updateTenantsSuccess(draft, action) {
|
|
111
|
+
const { tenants, user } = action.payload;
|
|
112
112
|
draft.fetchState = 'Completed';
|
|
113
113
|
draft.error = undefined;
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
accessibleTenantsById[tenant.tenantId] = tenant;
|
|
114
|
+
const [tenantsbyId, tenantIds, firstUser] = mapTenantsPayloadToState(tenants, user);
|
|
115
|
+
tenantIds.forEach((tenantId) => {
|
|
116
|
+
const existingTenant = draft.tenantsById[tenantId];
|
|
117
|
+
tenantsbyId[tenantId] = applyTreasuryPromoUserFieldsFromPayload(existingTenant, tenantsbyId[tenantId], user);
|
|
118
|
+
if (existingTenant != null) {
|
|
119
|
+
tenantsbyId[tenantId].capitalizableAccountOverrides =
|
|
120
|
+
tenantsbyId[tenantId].capitalizableAccountOverrides ??
|
|
121
|
+
existingTenant.capitalizableAccountOverrides;
|
|
122
|
+
tenantsbyId[tenantId].capitalizationOnboardingDismissedAccounts =
|
|
123
|
+
tenantsbyId[tenantId].capitalizationOnboardingDismissedAccounts ??
|
|
124
|
+
existingTenant.capitalizationOnboardingDismissedAccounts;
|
|
126
125
|
}
|
|
127
126
|
});
|
|
128
|
-
draft.tenantsById =
|
|
127
|
+
draft.tenantsById = tenantsbyId;
|
|
128
|
+
draft.tenantIds = tenantIds;
|
|
129
|
+
draft.loggedInUser = assignWith(draft.loggedInUser ?? {}, firstUser, (objValue, srcValue) => srcValue ?? objValue);
|
|
129
130
|
},
|
|
130
131
|
updateTenantsFailure(draft, action) {
|
|
131
132
|
draft.fetchState = 'Error';
|
|
@@ -133,7 +134,6 @@ const tenant = createSlice({
|
|
|
133
134
|
draft.error = action.payload;
|
|
134
135
|
draft.tenantIds = [];
|
|
135
136
|
draft.tenantsById = {};
|
|
136
|
-
draft.tenantSummariesById = {};
|
|
137
137
|
},
|
|
138
138
|
updateTenantSuccess(draft, action) {
|
|
139
139
|
const { tenants, user } = action.payload;
|
|
@@ -242,7 +242,6 @@ const tenant = createSlice({
|
|
|
242
242
|
draft.signInState = 'Error';
|
|
243
243
|
draft.tenantIds = [];
|
|
244
244
|
draft.tenantsById = {};
|
|
245
|
-
draft.tenantSummariesById = {};
|
|
246
245
|
},
|
|
247
246
|
updateTenantReimbursementInfo(draft, action) {
|
|
248
247
|
const { tenant_id, reimbursement_info } = action.payload;
|
|
@@ -272,24 +271,6 @@ const tenant = createSlice({
|
|
|
272
271
|
updateCurrentTenant(draft, action) {
|
|
273
272
|
draft.currentTenantId = action.payload;
|
|
274
273
|
},
|
|
275
|
-
/**
|
|
276
|
-
* Records a tenant's ids known before the tenants list loads (the app's
|
|
277
|
-
* cached tenant list), so `getCurrentTenantIds` has them from the first
|
|
278
|
-
* render. The list is not changed and its own entries win.
|
|
279
|
-
*/
|
|
280
|
-
seedTenantSummary(draft, action) {
|
|
281
|
-
const { companyId, tenantEmailDomain, tenantId, tenantName } = action.payload;
|
|
282
|
-
if (draft.tenantSummariesById[tenantId] == null) {
|
|
283
|
-
draft.tenantSummariesById[tenantId] = {
|
|
284
|
-
companyId,
|
|
285
|
-
companyName: tenantName ?? '',
|
|
286
|
-
tenantEmailDomain,
|
|
287
|
-
tenantId,
|
|
288
|
-
// Not in `tenantIds`, so it is never ordered or listed.
|
|
289
|
-
userLastCheckInTime: date('1970-01-01'),
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
},
|
|
293
274
|
fetchExcludedResources: {
|
|
294
275
|
prepare(userId, tenantId) {
|
|
295
276
|
return { payload: { userId, tenantId } };
|
|
@@ -953,7 +934,7 @@ const tenant = createSlice({
|
|
|
953
934
|
});
|
|
954
935
|
},
|
|
955
936
|
});
|
|
956
|
-
export const { updateTenants, fetchAllTenants,
|
|
937
|
+
export const { updateTenants, fetchAllTenants, updateTenantsSuccess, updateTenantsFailure, fetchActiveTenant, updateTenantSuccess, updateTenantFailure, updateCurrentTenant, fetchExcludedResources, updateExcludedResourcesSuccess, updateExcludedResourcesFailure, doSignIn, doMagicLinkSignIn, magicLinkSignInSuccess, magicLinkSignInFailure, sendEmailMagicLinkToUser, sendEmailMagicLinkToUserSuccess, sendEmailMagicLinkToUserFailure, updateSignInState, doSignOut, signOutSuccess, sendSessionHeartbeat, sessionHeartbeatSuccess, sessionHeartbeatFailure, updateLoggedInUser, fetchExternalConnections, saveExternalConnection, saveExternalConnectionSuccess, saveExternalConnectionFailure, fetchExternalConnectionsFailure, fetchExternalConnectionsSuccess, saveAPIKeyConnection, saveAPIKeyConnectionSuccess, saveAPIKeyConnectionFailure, saveOAuthConnection, saveOAuthConnectionSuccess, saveOAuthConnectionFailure, saveConnectorCredentials, saveConnectorCredentialsSuccess, saveConnectorCredentialsFailure, initEmailConnectOAuth, initEmailConnectOAuthSuccess, initEmailConnectOAuthFailure, deleteConnection, deleteConnectionSuccess, deleteConnectionFailure, fetchSubscriptionSummaryForTenant, updateSubscriptionSummaryForTenantSuccess, updateSubscriptionSummaryForTenantFailure, updateOnboardingTenants, removeOnboardingTenant, updateTenantReimbursementInfo, updateReferViewedForLoggedInUser, resetSignInState, trigger2FA, updateTenantAccountingClassesEnabled, updateTenantAccountingProjectsEnabled, updateTenantAutoReviewIncomeWithoutCustomer, updateTenantProductSettings, updateTenantCapitalizationOnboardingDismissed, updateTenantCapitalizationAccountOverride, updateTenantMasterTOSInfo, verifyDeviceWithTwoFA, verifyDeviceWithTwoFASuccess, verifyDeviceWithTwoFAFailure, updateTreasuryVideoViewedForLoggedInUser, updateTreasuryPromoRemindMeLaterClickedForLoggedInUser, updateTreasuryPromoIntroClosedByOutsideClickForLoggedInUser, resendVerifyDeviceOTP, resendVerifyDeviceOTPSuccess, resendVerifyDeviceOTPFailure, } = tenant.actions;
|
|
957
938
|
export default tenant.reducer;
|
|
958
939
|
/**
|
|
959
940
|
* Applies treasury promo user fields from the tenants API user block when present.
|
|
@@ -995,16 +976,6 @@ function mapTenantsPayloadToState(tenantsPayload, userTenantPayload) {
|
|
|
995
976
|
const firstUser = mapTenantPayloadToUser(tenantsPayload[0]);
|
|
996
977
|
return [tenantsById, tenantIds, firstUser];
|
|
997
978
|
}
|
|
998
|
-
function mapTenantSummaryPayloadToTenantSummary(payload) {
|
|
999
|
-
return {
|
|
1000
|
-
companyId: payload.company_id,
|
|
1001
|
-
companyName: payload.company_name,
|
|
1002
|
-
tenantEmailDomain: payload.tenant_email_domain,
|
|
1003
|
-
tenantId: payload.tenant_id,
|
|
1004
|
-
// A tenant never opened sorts last, as in `mapTenantPayloadToTenant`.
|
|
1005
|
-
userLastCheckInTime: date(payload.user_last_check_in_time_into_tenant ?? '1970-01-01'),
|
|
1006
|
-
};
|
|
1007
|
-
}
|
|
1008
979
|
function mapTenantPayloadToTenant(payload, userTenantPayload) {
|
|
1009
980
|
const tenant = {
|
|
1010
981
|
accountingClassIDs: payload.accounting_class_ids,
|
|
@@ -16,75 +16,50 @@ export function getTenant(tenantState, companyState, tenantId) {
|
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
export function getTenantIdByCompanyId(tenantState, companyId) {
|
|
19
|
-
return
|
|
20
|
-
Object.values(tenantState.tenantSummariesById).find((tenantSummary) => tenantSummary.companyId === companyId))?.tenantId;
|
|
19
|
+
return Object.values(tenantState.tenantsById).find((tenant) => tenant.companyId === companyId)?.tenantId;
|
|
21
20
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if (tenant != null) {
|
|
32
|
-
return {
|
|
33
|
-
companyId: tenant.companyId,
|
|
34
|
-
companyName: tenant.companyName,
|
|
35
|
-
tenantEmailDomain: tenant.tenantEmailDomain,
|
|
36
|
-
tenantId: tenant.tenantId,
|
|
37
|
-
userLastCheckInTime: tenant.userLastCheckInTime,
|
|
38
|
-
userRole: tenant.userRole,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
return tenantSummary != null
|
|
42
|
-
? { ...tenantSummary, userRole: [] }
|
|
43
|
-
: undefined;
|
|
44
|
-
})
|
|
45
|
-
.filter((entry) => entry != null);
|
|
46
|
-
return orderBy(entries, (entry) => entry.userLastCheckInTime.valueOf(), 'desc');
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* The selected tenant's full record. With no tenant selected, or one the user
|
|
50
|
-
* can no longer open, it is the most recently opened loaded tenant. A selected
|
|
51
|
-
* tenant that is in the list but not loaded yet reads as no tenant until its
|
|
52
|
-
* fetch lands, so nothing renders another tenant's record in its place.
|
|
53
|
-
*/
|
|
54
|
-
function getCurrentTenantView(tenantState, companyState) {
|
|
55
|
-
const { currentTenantId } = tenantState;
|
|
56
|
-
if (currentTenantId != null) {
|
|
57
|
-
const tenant = getTenant(tenantState, companyState, currentTenantId);
|
|
58
|
-
if (tenant != null ||
|
|
59
|
-
tenantState.tenantSummariesById[currentTenantId] != null) {
|
|
60
|
-
return tenant;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
const mostRecentLoadedTenant = getTenantListEntriesByCheckInDate(tenantState).find((entry) => tenantState.tenantsById[entry.tenantId] != null);
|
|
64
|
-
return mostRecentLoadedTenant != null
|
|
65
|
-
? getTenant(tenantState, companyState, mostRecentLoadedTenant.tenantId)
|
|
66
|
-
: undefined;
|
|
21
|
+
function getTenantsByCheckInDate(tenantState, companyState) {
|
|
22
|
+
const tenants = tenantState.tenantIds
|
|
23
|
+
.map((tenantId) => getTenant(tenantState, companyState, tenantId))
|
|
24
|
+
.filter((value) => value != null);
|
|
25
|
+
const tenantsOrdered = orderBy(tenants, (value) => value.userLastCheckInTime.valueOf(), 'desc');
|
|
26
|
+
return {
|
|
27
|
+
order: 'descending_last_check_in',
|
|
28
|
+
tenantsInOrder: tenantsOrdered,
|
|
29
|
+
};
|
|
67
30
|
}
|
|
68
|
-
/** Whether the tenant's full record is loaded, not just its list entry. */
|
|
69
|
-
export const isTenantLoaded = (state, tenantId) => state.tenantState.tenantsById[tenantId] != null;
|
|
70
|
-
/**
|
|
71
|
-
* Whether the selected tenant's full record is loaded. Screens that act on
|
|
72
|
-
* roles or product settings wait for this rather than for either tenant fetch
|
|
73
|
-
* to complete: the tenants list alone carries neither.
|
|
74
|
-
*/
|
|
75
|
-
export const isCurrentTenantLoaded = (state) => {
|
|
76
|
-
const { currentTenantId } = state.tenantState;
|
|
77
|
-
return currentTenantId != null && isTenantLoaded(state, currentTenantId);
|
|
78
|
-
};
|
|
79
31
|
export const getTenantBaseViewForTenantId = createSelector((state) => state.tenantState, (state) => state.companyState, (_state, tenantId) => tenantId, (tenantState, companyState, tenantId) => {
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
32
|
+
const tenant = tenantState.tenantsById[tenantId];
|
|
33
|
+
if (tenant != null) {
|
|
34
|
+
const companyId = tenant.companyId;
|
|
35
|
+
const companyName = companyState.companiesById[companyId]?.companyInfo.name;
|
|
36
|
+
const tenantName = tenant.companyName ?? companyName;
|
|
37
|
+
const tenantEmailDomain = tenant.tenantEmailDomain;
|
|
38
|
+
const userRole = tenant.userRole;
|
|
39
|
+
const companyLocaleInfo = companyState.companiesById[companyId]?.companyLocaleInfo;
|
|
40
|
+
return {
|
|
41
|
+
tenantId,
|
|
42
|
+
tenantName,
|
|
43
|
+
tenantEmailDomain,
|
|
44
|
+
companyId,
|
|
45
|
+
companyName,
|
|
46
|
+
userRole,
|
|
47
|
+
companyLocaleInfo,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return undefined;
|
|
84
51
|
});
|
|
85
52
|
const getCurrentTenantHelper = (tenantState, companyState) => {
|
|
86
|
-
const { currentTenantId, excludedResourcesByTenant, subscriptionSummaryByTenant, } = tenantState;
|
|
87
|
-
|
|
53
|
+
const { tenantIds, currentTenantId, excludedResourcesByTenant, subscriptionSummaryByTenant, } = tenantState;
|
|
54
|
+
let tenant = undefined;
|
|
55
|
+
if (currentTenantId != null) {
|
|
56
|
+
tenant = getTenant(tenantState, companyState, currentTenantId);
|
|
57
|
+
}
|
|
58
|
+
if (tenant == null && tenantIds.length > 0) {
|
|
59
|
+
const tenants = getTenantsByCheckInDate(tenantState, companyState);
|
|
60
|
+
tenant =
|
|
61
|
+
tenants.tenantsInOrder.length > 0 ? tenants.tenantsInOrder[0] : undefined;
|
|
62
|
+
}
|
|
88
63
|
let excludedResources = undefined;
|
|
89
64
|
if (tenant != null) {
|
|
90
65
|
excludedResources = excludedResourcesByTenant[tenant.tenantId];
|
|
@@ -145,34 +120,9 @@ const getCurrentTenantHelper = (tenantState, companyState) => {
|
|
|
145
120
|
export const getCurrentTenant = createSelector((state) => state.tenantState, (state) => state.companyState, (tenantState, companyState) => {
|
|
146
121
|
return getCurrentTenantHelper(tenantState, companyState);
|
|
147
122
|
});
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
* it is set before the tenant fetch lands (boot reads it from the cached
|
|
151
|
-
* tenant list).
|
|
152
|
-
*/
|
|
153
|
-
export const getCurrentTenantId = (state) => state.tenantState.currentTenantId;
|
|
154
|
-
const getCurrentTenantIdValues = createSelector((state) => state.tenantState, (state) => state.companyState, (tenantState, companyState) => {
|
|
155
|
-
const tenant = getCurrentTenantView(tenantState, companyState);
|
|
156
|
-
if (tenant != null) {
|
|
157
|
-
return { tenantId: tenant.tenantId, companyId: tenant.companyId };
|
|
158
|
-
}
|
|
159
|
-
const { currentTenantId } = tenantState;
|
|
160
|
-
const tenantSummary = currentTenantId != null
|
|
161
|
-
? tenantState.tenantSummariesById[currentTenantId]
|
|
162
|
-
: undefined;
|
|
163
|
-
return {
|
|
164
|
-
tenantId: tenantSummary?.tenantId,
|
|
165
|
-
companyId: tenantSummary?.companyId,
|
|
166
|
-
};
|
|
123
|
+
export const getTenantsByCheckInDateSelector = createSelector((state) => state.tenantState, (state) => state.companyState, (tenantState, companyState) => {
|
|
124
|
+
return getTenantsByCheckInDate(tenantState, companyState);
|
|
167
125
|
});
|
|
168
|
-
/**
|
|
169
|
-
* The current tenant's ids before its record loads: from the record when
|
|
170
|
-
* loaded, otherwise from the tenants list or the entry seeded from the app's
|
|
171
|
-
* cache (`seedTenantSummary`). Providers keyed on them (Statsig, collaboration)
|
|
172
|
-
* then mount once with the final ids, on a reload and on a tenant switch.
|
|
173
|
-
* The result keeps its identity while the ids are unchanged.
|
|
174
|
-
*/
|
|
175
|
-
export const getCurrentTenantIds = createSelector((state) => getCurrentTenantIdValues(state).tenantId, (state) => getCurrentTenantIdValues(state).companyId, (tenantId, companyId) => ({ tenantId, companyId }));
|
|
176
126
|
export function getOnboardingTenantByTenantId(tenantState, tenantId) {
|
|
177
127
|
const tenant = tenantState.onboardingTenantsById[tenantId];
|
|
178
128
|
if (tenant != null) {
|
|
@@ -183,7 +133,10 @@ export function getOnboardingTenantByTenantId(tenantState, tenantId) {
|
|
|
183
133
|
}
|
|
184
134
|
}
|
|
185
135
|
export const getTenantBaseById = createSelector((state) => state.tenantState, (state) => state.companyState, (tenantState, companyState) => {
|
|
186
|
-
return
|
|
136
|
+
return tenantState.tenantIds.map((tenantId) => {
|
|
137
|
+
const tenant = tenantState.tenantsById[tenantId];
|
|
138
|
+
return getTenantBaseViewForTenant(tenant, companyState);
|
|
139
|
+
});
|
|
187
140
|
});
|
|
188
141
|
export const getTenantsBaseByCheckInDateSelector = createSelector((state) => state.tenantState, (state) => state.companyState, (tenantState, companyState) => {
|
|
189
142
|
return getTenantsBaseByCheckInDate(tenantState, companyState);
|
|
@@ -212,8 +165,16 @@ export const isTenantUsingZeniCOA = (currentTenant) => {
|
|
|
212
165
|
return currentTenant.company?.companyInfo.isZeniCOAInUse ?? true; // defaulting to true
|
|
213
166
|
};
|
|
214
167
|
export const getCurrentTenantExternalConnections = (tenantState, companyState) => {
|
|
215
|
-
const { externalConnectionsByTenant, currentTenantId } = tenantState;
|
|
216
|
-
|
|
168
|
+
const { externalConnectionsByTenant, tenantIds, currentTenantId } = tenantState;
|
|
169
|
+
let tenant = undefined;
|
|
170
|
+
if (currentTenantId != null) {
|
|
171
|
+
tenant = getTenant(tenantState, companyState, currentTenantId);
|
|
172
|
+
}
|
|
173
|
+
if (tenant == null && tenantIds.length > 0) {
|
|
174
|
+
const tenants = getTenantsByCheckInDate(tenantState, companyState);
|
|
175
|
+
tenant =
|
|
176
|
+
tenants.tenantsInOrder.length > 0 ? tenants.tenantsInOrder[0] : undefined;
|
|
177
|
+
}
|
|
217
178
|
let externalConnections = undefined;
|
|
218
179
|
if (tenant != null) {
|
|
219
180
|
externalConnections = externalConnectionsByTenant[tenant.tenantId];
|
|
@@ -227,39 +188,58 @@ export const getCurrentTenantExternalConnections = (tenantState, companyState) =
|
|
|
227
188
|
* Helpers
|
|
228
189
|
*/
|
|
229
190
|
function getTenantsBaseByCheckInDate(tenantState, companyState) {
|
|
191
|
+
const tenants = tenantState.tenantIds
|
|
192
|
+
.map((tenantId) => getTenant(tenantState, companyState, tenantId))
|
|
193
|
+
.filter((value) => value != null);
|
|
194
|
+
const tenantsOrdered = orderBy(tenants, (value) => value.userLastCheckInTime.valueOf(), 'desc');
|
|
195
|
+
const tenantsBaseOrdered = tenantsOrdered.map((tenant) => getTenantBaseViewForTenant(tenant, companyState));
|
|
230
196
|
return {
|
|
231
197
|
order: 'descending_last_check_in',
|
|
232
|
-
tenantsBaseInOrder:
|
|
198
|
+
tenantsBaseInOrder: tenantsBaseOrdered,
|
|
233
199
|
};
|
|
234
200
|
}
|
|
235
|
-
const
|
|
236
|
-
const
|
|
201
|
+
const getTenantBaseViewForTenant = (tenant, companyState) => {
|
|
202
|
+
const tenantId = tenant.tenantId;
|
|
203
|
+
const companyId = tenant.companyId;
|
|
204
|
+
const companyName = companyState.companiesById[companyId]?.companyInfo.name;
|
|
205
|
+
const tenantName = tenant.companyName ?? companyName ?? tenant.tenantEmailDomain ?? '';
|
|
206
|
+
const tenantEmailDomain = tenant.tenantEmailDomain;
|
|
207
|
+
const userRole = tenant.userRole;
|
|
208
|
+
const companyLocaleInfo = companyState.companiesById[companyId]?.companyLocaleInfo;
|
|
237
209
|
return {
|
|
238
|
-
tenantId
|
|
239
|
-
tenantName
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
// Companies are loaded only for opened tenants; the list carries the name.
|
|
246
|
-
companyName: company?.companyInfo.name ?? entry.companyName,
|
|
247
|
-
userRole: entry.userRole,
|
|
248
|
-
companyLocaleInfo: company?.companyLocaleInfo,
|
|
210
|
+
tenantId,
|
|
211
|
+
tenantName,
|
|
212
|
+
tenantEmailDomain,
|
|
213
|
+
companyId,
|
|
214
|
+
companyName,
|
|
215
|
+
userRole,
|
|
216
|
+
companyLocaleInfo,
|
|
249
217
|
};
|
|
250
218
|
};
|
|
251
219
|
function getTenantCoreDetailsByCheckInDate(tenantState, companyState) {
|
|
220
|
+
const tenants = tenantState.tenantIds
|
|
221
|
+
.map((tenantId) => getTenant(tenantState, companyState, tenantId))
|
|
222
|
+
.filter((value) => value != null);
|
|
223
|
+
const tenantsOrdered = orderBy(tenants, (value) => value.userLastCheckInTime.valueOf(), 'desc');
|
|
224
|
+
const tenantsCoreDetailsOrdered = tenantsOrdered.map((tenant) => getTenantCoreDetailsViewForTenant(tenant, companyState));
|
|
252
225
|
return {
|
|
253
226
|
order: 'descending_last_check_in',
|
|
254
|
-
tenantsCoreDetailsInOrder:
|
|
255
|
-
tenantId: entry.tenantId,
|
|
256
|
-
tenantName: entry.companyName ??
|
|
257
|
-
companyState.companiesById[entry.companyId]?.companyInfo.name,
|
|
258
|
-
tenantEmailDomain: entry.tenantEmailDomain,
|
|
259
|
-
companyId: entry.companyId,
|
|
260
|
-
})),
|
|
227
|
+
tenantsCoreDetailsInOrder: tenantsCoreDetailsOrdered,
|
|
261
228
|
};
|
|
262
229
|
}
|
|
230
|
+
const getTenantCoreDetailsViewForTenant = (tenant, companyState) => {
|
|
231
|
+
const tenantId = tenant.tenantId;
|
|
232
|
+
const companyId = tenant.companyId;
|
|
233
|
+
const companyName = companyState.companiesById[companyId]?.companyInfo.name;
|
|
234
|
+
const tenantName = tenant.companyName ?? companyName;
|
|
235
|
+
const tenantEmailDomain = tenant.tenantEmailDomain;
|
|
236
|
+
return {
|
|
237
|
+
tenantId,
|
|
238
|
+
tenantName,
|
|
239
|
+
tenantEmailDomain,
|
|
240
|
+
companyId,
|
|
241
|
+
};
|
|
242
|
+
};
|
|
263
243
|
export const toTenantCoreDetailsView = (tenantsBaseView) => {
|
|
264
244
|
return tenantsBaseView.map(({ tenantId, tenantName, tenantEmailDomain, companyId }) => {
|
|
265
245
|
return {
|
package/lib/esm/epic.js
CHANGED
|
@@ -70,7 +70,6 @@ import { stopSubmitEpic, } from './view/aiCfoView/epics/stopSubmitEpic';
|
|
|
70
70
|
import { stopSubmitQuestionEpic, } from './view/aiCfoView/epics/stopSubmitQuestionEpic';
|
|
71
71
|
import { submitFeedbackEpic, } from './view/aiCfoView/epics/submitFeedbackEpic';
|
|
72
72
|
import { submitQuestionEpic, } from './view/aiCfoView/epics/submitQuestionEpic';
|
|
73
|
-
import { transcribeAudioEpic, } from './view/aiCfoView/epics/transcribeAudioEpic';
|
|
74
73
|
import { fetchApAgingDetailEpic, } from './view/apAgingView/apAgingDetail/fetchApAgingDetailEpic';
|
|
75
74
|
import { fetchApAgingEpic, } from './view/apAgingView/apAgingReport/fetchApAgingEpic';
|
|
76
75
|
import { fetchArAgingDetailEpic, } from './view/arAgingView/arAgingDetail/fetchArAgingDetailEpic';
|
|
@@ -1485,7 +1484,6 @@ const ALL_EPICS = [
|
|
|
1485
1484
|
syncInvoicingSubscriptionCouponsEpic,
|
|
1486
1485
|
syncTabsAfterAutomatchEpic,
|
|
1487
1486
|
toggleReportUIOptionForecastModeEpic,
|
|
1488
|
-
transcribeAudioEpic,
|
|
1489
1487
|
transferMoneyEpic,
|
|
1490
1488
|
treasuryTransferMoneyEpic,
|
|
1491
1489
|
triggerAiAccountantJobEpic,
|
package/lib/esm/index.js
CHANGED
|
@@ -72,8 +72,8 @@ import { closeSnackbar, openSnackbar } from './entity/snackbar/snackbarReducer';
|
|
|
72
72
|
import { getSnackbar } from './entity/snackbar/snackbarSelector';
|
|
73
73
|
import { ALL_WEEK_DAYS, toDayOfWeek, toPriorityCodeType, toTaskStatusCodeType, } from './entity/task/taskState';
|
|
74
74
|
import { getTaskGroupById } from './entity/taskGroup/taskGroupSelector';
|
|
75
|
-
import { deleteConnection, doMagicLinkSignIn, doSignIn, doSignOut, fetchActiveTenant, fetchAllTenants, fetchExcludedResources as fetchExcludedResourcesForTenant, fetchExternalConnections as fetchExternalConnectionsForTenant, fetchSubscriptionSummaryForTenant, initEmailConnectOAuth, resendVerifyDeviceOTP, resetSignInState, saveAPIKeyConnection, saveConnectorCredentials, saveExternalConnection as saveExternalConnectionForTenant, saveOAuthConnection,
|
|
76
|
-
import { DEFAULT_RECEIPTS_EMAIL, getCurrentTenant,
|
|
75
|
+
import { deleteConnection, doMagicLinkSignIn, doSignIn, doSignOut, fetchActiveTenant, fetchAllTenants, fetchExcludedResources as fetchExcludedResourcesForTenant, fetchExternalConnections as fetchExternalConnectionsForTenant, fetchSubscriptionSummaryForTenant, initEmailConnectOAuth, resendVerifyDeviceOTP, resetSignInState, saveAPIKeyConnection, saveConnectorCredentials, saveExternalConnection as saveExternalConnectionForTenant, saveOAuthConnection, sendEmailMagicLinkToUser, sendSessionHeartbeat, toExternalIntegrationType, updateCurrentTenant, updateSignInState, verifyDeviceWithTwoFA, } from './entity/tenant/tenantReducer';
|
|
76
|
+
import { DEFAULT_RECEIPTS_EMAIL, getCurrentTenant, getIsAccountingClassesEnabled, getIsAccountingProjectsEnabled, getIsAutoReviewIncomeWithoutCustomerEnabled, getReceiptsEmail, getTenantBaseById, getTenantBaseViewForTenantId, getTenantBaseViewForTenantView, getTenantsBaseByCheckInDateSelector, getTenantsByCheckInDateSelector, getTenantsCoreDetailsByCheckInDateSelector, isOtherProductsEnabledForTenant, isTenantBankingOnly, isTenantBookkeepingEnabled, isTenantCardsOnly, isTenantUsingZeniCOA, isZeniDomainTenant, toTenantCoreDetailsView, } from './entity/tenant/tenantSelector';
|
|
77
77
|
import { toExternalSupportedTool } from './entity/tenant/tenantTypes';
|
|
78
78
|
import { pushToastNotification } from './entity/toastNotification/toastNotificationReducer';
|
|
79
79
|
import { getLastNotificationTime, getNotifications, } from './entity/toastNotification/toastNotificationSelector';
|
|
@@ -332,7 +332,7 @@ import { clearInternationalWire, createPaymentInstrument, createPaymentInstrumen
|
|
|
332
332
|
import { getInternationalWireView, } from './view/spendManagement/billPay/internationalWire/internationalWireSelector';
|
|
333
333
|
import { fetchInternationalVerificationForm, submitInternationalVerificationForm, updateVerificationFormLocalData, } from './view/spendManagement/billPay/internationalWireVerification/internationalWireVerificationReducer';
|
|
334
334
|
import { getIntlWireVerificationView, } from './view/spendManagement/billPay/internationalWireVerification/internationalWireVerificationSelector';
|
|
335
|
-
import { fetchBillAttachment, fetchMagicLinkBankNameByRouting, fetchMagicLinkBankNameBySwift, fetchMagicLinkTenant, saveBankAccount, saveMagicLinkAddressInLocalStore, updateMagicLinkBankAccountLocalStoreData, updateMagicLinkInternationalBankAccountLocalStoreData,
|
|
335
|
+
import { fetchBillAttachment, fetchMagicLinkBankNameByRouting, fetchMagicLinkBankNameBySwift, fetchMagicLinkTenant, saveBankAccount, saveMagicLinkAddressInLocalStore, updateMagicLinkBankAccountLocalStoreData, updateMagicLinkInternationalBankAccountLocalStoreData, } from './view/spendManagement/billPay/magicLinkView/magicLinkViewReducer';
|
|
336
336
|
import { getMagicLinkBankAccountView, getMagicLinkCurrentAddressState, getMagicLinkView, } from './view/spendManagement/billPay/magicLinkView/magicLinkViewSelector';
|
|
337
337
|
import { fetchWiseRedirectStatus } from './view/spendManagement/billPay/wiseRedirectView/wiseRedirectReducer';
|
|
338
338
|
import { getWiseRedirect } from './view/spendManagement/billPay/wiseRedirectView/wiseRedirectSelector';
|
|
@@ -509,7 +509,7 @@ export { toTimeframeTick, mapTimePeriodtoTimeframeTick, toTimePeriod, toAbsolute
|
|
|
509
509
|
export { toVendorSpendTrendFilterTabsTypeStrict, } from './entity/vendorExpense/vendorSpendTrendFilterTabType';
|
|
510
510
|
export { getNumberOfPeriods };
|
|
511
511
|
export { SCHEDULE_DAYS_OF_MONTH, toScheduleDaysOfMonth, toMonth, toMonthStrict, toQuarter, toQuarterStrict, };
|
|
512
|
-
export { getTenantBaseById, getCurrentTenant,
|
|
512
|
+
export { getTenantBaseById, getCurrentTenant, getIsAccountingClassesEnabled, getIsAccountingProjectsEnabled, getIsAutoReviewIncomeWithoutCustomerEnabled, getTenantsByCheckInDateSelector, getTenantsBaseByCheckInDateSelector, getTenantsCoreDetailsByCheckInDateSelector, toTenantCoreDetailsView, getTenantBaseViewForTenantView, getTenantBaseViewForTenantId, isZeniDomainTenant, isTenantUsingZeniCOA, fetchActiveTenant, fetchAllTenants, updateCurrentTenant, clearAll, doMagicLinkSignIn, verifyDeviceWithTwoFA, resendVerifyDeviceOTP, sendEmailMagicLinkToUser, doSignIn, updateSignInState, doSignOut, sendSessionHeartbeat, resetSignInState, fetchExcludedResourcesForTenant, fetchExternalConnectionsForTenant, saveExternalConnectionForTenant, deleteConnection, saveAPIKeyConnection, saveConnectorCredentials, saveOAuthConnection, initEmailConnectOAuth, toExternalIntegrationType, toExternalSupportedTool, fetchSubscriptionSummaryForTenant, isTenantBankingOnly, isTenantCardsOnly, isTenantBookkeepingEnabled, isOtherProductsEnabledForTenant, DEFAULT_RECEIPTS_EMAIL, getReceiptsEmail, };
|
|
513
513
|
export { toAccountType, toAccountGroupType, getAccountGroupKey, getAllAccounts, getTransactionFilterAccountOptions, };
|
|
514
514
|
export { getAllClasses, getClassById, getClassFilterOptions, } from './entity/class/classSelector';
|
|
515
515
|
export { getForecast };
|
|
@@ -661,7 +661,7 @@ export { isZeniClearingAccountReport, ZENI_CLEARING_ACCOUNT, isZeniClearingAccou
|
|
|
661
661
|
export { fetchOnboardingCustomerView, fetchOnboardingCustomerSetupView, getOnboardingPlaidLinkToken, establishOnboardingPlaidConnection, updateOnboardingCustomerViewAccountDetails, updateOnboardingCustomerViewCompleteStatus, updateOnboardingCustomerViewDashboardLoaded, updateOnboardingPaymentAccountLoginStatus, updateOnboardingPaymentAccountStatus, updateOnboardingCustomerView, updateOnboardingCustomerViewLocalStoreData, updateCurrentStep, updateCurrentSubStep, updateOnboardingCustomerViewUIState, saveOnboardingCompnayOfficerPhoneInLocalStore, saveOnboardingCustomerViewDataInLocalStore, clearOnboardingCustomerViewDataInLocalStore, applyKycDocumentAutofillForOnboarding, applyKybDocumentAutofillForOnboarding, clearKycKybAutofillForOnboarding, acknowledgeOnboardingAiActivationViewed, acknowledgeOnboardingAiFinanceTeam, fetchAiAgentsActivationStatus, aiAgentsActivationCountsUpdated, aiAgentsActivationPhaseChanged, getAiAgentsActivationCounts, getAiAgentsActivationPhases, getAiAgentsActivationSubview, getOnboardingCustomerView, getProductSettingsString, ALL_ONBOARDING_STEPS, ALL_ONBOARDING_SUB_STEPS, toOnboardingStepType, toOnboardingSubStepType, };
|
|
662
662
|
export { saveAccountMapping, saveAccountMappingLocalData, clearAccountMappingLocalData, getAccountMappingView, initializeAccountMappingView, };
|
|
663
663
|
export { getMagicLinkView, getMagicLinkBankAccountView, getMagicLinkCurrentAddressState, };
|
|
664
|
-
export { fetchMagicLinkTenant,
|
|
664
|
+
export { fetchMagicLinkTenant, fetchBillAttachment, saveBankAccount, updateMagicLinkBankAccountLocalStoreData, updateMagicLinkInternationalBankAccountLocalStoreData, fetchMagicLinkBankNameByRouting, fetchMagicLinkBankNameBySwift, saveMagicLinkAddressInLocalStore, };
|
|
665
665
|
export { getWiseRedirect, fetchWiseRedirectStatus };
|
|
666
666
|
export { getInternationalWireView, initializeInternationalWireLocalData, updateInternationalWireLocalStoreData, initializeDynamicForm, fetchInternationalWireDynamicForm, createPaymentInstrument, createPaymentInstrumentUpdateStatus, deletePaymentInstrument, clearInternationalWire, };
|
|
667
667
|
export { fetchUserRoleConfig, getUserRoleConfig };
|
|
@@ -705,8 +705,8 @@ export { updateAiAccountantCustomers, updateAiAccountantCustomer, updateAiAccoun
|
|
|
705
705
|
export { getAiAccountantCustomers, getAiAccountantJobsByTenantId, } from './entity/aiAccountantCustomer/aiAccountantCustomerSelector';
|
|
706
706
|
export { cancelAiAccountantOnboarding, fetchAiAccountantCustomers, fetchAiAccountantJobs, setSelectedTenantIdsForJobTrigger, triggerAiAccountantJob, updateAiAccountantUIState, } from './view/aiAccountantView/aiAccountantViewReducer';
|
|
707
707
|
export { getAiAccountantCockpitView, } from './view/aiAccountantView/aiAccountantViewSelector';
|
|
708
|
-
export { acceptMasterTOS, applyAiCfoSidePanelHostPageTransition, clearAiCfoSidePanelHostPageContext, clearCurrentSessionId, clearDeleteChatSessionStatus, clearLastContextMessage, clearSkillDetail, clearSkillMutation, closeRoutineRuns, closeRoutinesBrowser, closeSkillsBrowser, createSession, createSessionAndSubmit, deleteChatSession, deleteRoutine, deleteSkill, fetchChatHistory, fetchChatSessionsForUser, fetchRoutineRuns, fetchRoutines, fetchSkillDetail, fetchSkills, fetchSkillsFailure, fetchSkillsSuccess, fetchSkillVersionBody, fetchSkillVersions, fetchSuggestedQuestions, fetchSuggestedQuestionsFailure, fetchSuggestedQuestionsSuccess, openRoutinesBrowser, openSkillsBrowser, runRoutine, saveRoutine, saveSkill, setRoutineEnabled, setSession, setSkillVisibility, stopSubmit, stopSubmitQuestion, submitFeedback, submitQuestion,
|
|
709
|
-
export { canCreateRoutine, getAiCfoView,
|
|
708
|
+
export { acceptMasterTOS, applyAiCfoSidePanelHostPageTransition, clearAiCfoSidePanelHostPageContext, clearCurrentSessionId, clearDeleteChatSessionStatus, clearLastContextMessage, clearSkillDetail, clearSkillMutation, closeRoutineRuns, closeRoutinesBrowser, closeSkillsBrowser, createSession, createSessionAndSubmit, deleteChatSession, deleteRoutine, deleteSkill, fetchChatHistory, fetchChatSessionsForUser, fetchRoutineRuns, fetchRoutines, fetchSkillDetail, fetchSkills, fetchSkillsFailure, fetchSkillsSuccess, fetchSkillVersionBody, fetchSkillVersions, fetchSuggestedQuestions, fetchSuggestedQuestionsFailure, fetchSuggestedQuestionsSuccess, openRoutinesBrowser, openSkillsBrowser, runRoutine, saveRoutine, saveSkill, setRoutineEnabled, setSession, setSkillVisibility, stopSubmit, stopSubmitQuestion, submitFeedback, submitQuestion, updateAiCfoViewScrollPosition, updateCotCollapsedState, updateCurrentInput, updateResponseState, } from './view/aiCfoView/aiCfoViewReducer';
|
|
709
|
+
export { canCreateRoutine, getAiCfoView, getRoutineMutation, getRoutineRuns, getRoutines, getRoutinesEnabled, getSkillDetail, getSkillMutation, getSkills, getSkillsEnabled, getSkillVersionBody, getSkillVersions, getSuggestedQuestionsForPageContext, } from './view/aiCfoView/aiCfoViewSelector';
|
|
710
710
|
export { setNewSession, setSessions, updateAiCfoAnswerCardPolicyWizardPlan, upsertAnswerPayload, upsertOrAddQuestionAnswerPayload, addQuestionPayload, clearSession, toAiCfoExports, toAiCfoVisualization, appendSyntheticAiCfoAnswer, updateSyntheticAiCfoAnswer, removeSyntheticAiCfoAnswer, } from './entity/aiCfo/aiCfoReducer';
|
|
711
711
|
export { getAllQuestionAnswersForChatSession, getQuestionAnswerByIdForChatSession, getAllQuestionsForChatSession, getAiCfoSelectorView, getSyntheticAiCfoAnswersForChatSession, getSyntheticAiCfoAnswerByQuestionAnswerId, } from './entity/aiCfo/aiCfoSelector';
|
|
712
712
|
export { ALL_AI_CFO_CHARTS_TYPES, ALL_AI_CFO_VISUALIZATION_TYPES, ALL_AI_CFO_ANSWER_STATE_TYPES, ALL_AI_CFO_ANSWER_RESPONSE_TYPES, ALL_INTERACTIVE_FORM_TYPES, toAiCfoVisualizationType, toAiCfoVisualizationTypeStrict, toAiCfoChartType, toAiCfoChartTypeStrict, toAiCfoAnswerStateType, toAiCfoAnswerStateTypeStrict, toAiCfoAnswerResponseType, toAiCfoAnswerResponseTypeStrict, toInteractiveFormType, toInteractiveFormTypeStrict, ALL_SYNTHETIC_AI_CFO_ANSWER_KINDS, toMessageSender, toMessageType, } from './entity/aiCfo/aiCfoState';
|
|
@@ -47,8 +47,6 @@ export const initialAiCfoViewState = {
|
|
|
47
47
|
fetchChatSessionHistoryByChatSessionId: {},
|
|
48
48
|
responseStateByChatSessionId: {},
|
|
49
49
|
stopSubmitStateByChatSessionId: {},
|
|
50
|
-
transcriptionState: { fetchState: 'Not-Started', error: undefined },
|
|
51
|
-
transcribingChatSessionId: undefined,
|
|
52
50
|
suggestedQuestionsByPageContext: {},
|
|
53
51
|
skillDetail: {
|
|
54
52
|
fetchState: 'Not-Started',
|
|
@@ -149,19 +147,6 @@ function closeSkillsBrowserState(draft) {
|
|
|
149
147
|
draft.uiState.isSkillsBrowserOpen = false;
|
|
150
148
|
clearOpenSkillState(draft);
|
|
151
149
|
}
|
|
152
|
-
/**
|
|
153
|
-
* Clear a finished dictation attempt when the conversation moves on, so a failed one
|
|
154
|
-
* stops showing "Could not transcribe that recording" in every later chat. A running
|
|
155
|
-
* take keeps its state — the composer is showing a live "Transcribing…" for it.
|
|
156
|
-
*/
|
|
157
|
-
function resetFinishedTranscription(draft) {
|
|
158
|
-
if (draft.transcriptionState.fetchState === 'In-Progress') {
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
draft.transcriptionState.fetchState = 'Not-Started';
|
|
162
|
-
draft.transcriptionState.error = undefined;
|
|
163
|
-
draft.transcribingChatSessionId = undefined;
|
|
164
|
-
}
|
|
165
150
|
const aiCfoView = createSlice({
|
|
166
151
|
name: 'aiCfoView',
|
|
167
152
|
initialState: initialAiCfoViewState,
|
|
@@ -169,7 +154,6 @@ const aiCfoView = createSlice({
|
|
|
169
154
|
submitQuestion: {
|
|
170
155
|
reducer(draft, action) {
|
|
171
156
|
const { sessionId } = action.payload;
|
|
172
|
-
resetFinishedTranscription(draft);
|
|
173
157
|
// A turn is being sent, so the chat body has to be what the user sees. Doing this
|
|
174
158
|
// here rather than at each call site is deliberate: the composer, the sample
|
|
175
159
|
// chips, Run, and the `/` menu all submit, and every one of them was a separate
|
|
@@ -315,7 +299,6 @@ const aiCfoView = createSlice({
|
|
|
315
299
|
setSession(draft, action) {
|
|
316
300
|
draft.uiState.currentChatSessionId = action.payload.sessionId;
|
|
317
301
|
draft.uiState.agentId = action.payload.agentId;
|
|
318
|
-
resetFinishedTranscription(draft);
|
|
319
302
|
// Picking a session means wanting to see that chat, so the browser cannot stay over
|
|
320
303
|
// it. In the reducer because there are six dispatch sites across three separate
|
|
321
304
|
// rails, and covering them one at a time missed half of them.
|
|
@@ -368,7 +351,6 @@ const aiCfoView = createSlice({
|
|
|
368
351
|
createSessionAndSubmit: {
|
|
369
352
|
reducer(draft, action) {
|
|
370
353
|
draft.uiState.agentId = action.payload.agentId;
|
|
371
|
-
resetFinishedTranscription(draft);
|
|
372
354
|
draft.createSessionAndSubmitState.fetchState = 'In-Progress';
|
|
373
355
|
draft.createSessionAndSubmitState.error = undefined;
|
|
374
356
|
},
|
|
@@ -569,49 +551,7 @@ const aiCfoView = createSlice({
|
|
|
569
551
|
return { payload: { chatMessageId, error } };
|
|
570
552
|
},
|
|
571
553
|
},
|
|
572
|
-
transcribeAudio: {
|
|
573
|
-
reducer(draft, action) {
|
|
574
|
-
draft.transcriptionState.fetchState = 'In-Progress';
|
|
575
|
-
draft.transcriptionState.error = undefined;
|
|
576
|
-
draft.transcribingChatSessionId = action.payload.chatSessionId;
|
|
577
|
-
},
|
|
578
|
-
prepare(audio, language, chatSessionId) {
|
|
579
|
-
return { payload: { audio, chatSessionId, language } };
|
|
580
|
-
},
|
|
581
|
-
},
|
|
582
|
-
transcribeAudioSuccess: {
|
|
583
|
-
reducer(draft, action) {
|
|
584
|
-
draft.transcriptionState.fetchState = 'Completed';
|
|
585
|
-
draft.transcriptionState.error = undefined;
|
|
586
|
-
// The user moved to another session while this was in flight — dropping it
|
|
587
|
-
// is the only safe option, since appending would put their words in a
|
|
588
|
-
// conversation they did not dictate into.
|
|
589
|
-
if (action.payload.chatSessionId !== draft.uiState.currentChatSessionId) {
|
|
590
|
-
return;
|
|
591
|
-
}
|
|
592
|
-
const transcript = action.payload.transcript.trim();
|
|
593
|
-
if (transcript === '') {
|
|
594
|
-
// Silence, not a failure: leave the composer untouched so the user can
|
|
595
|
-
// simply speak again rather than hunting for what went wrong.
|
|
596
|
-
return;
|
|
597
|
-
}
|
|
598
|
-
// Append to whatever is in the box now rather than to a snapshot taken when
|
|
599
|
-
// recording began — a take produces exactly one result, so there is nothing
|
|
600
|
-
// to reconcile, and anything typed while transcribing survives.
|
|
601
|
-
const existing = draft.uiState.currentInput.trim();
|
|
602
|
-
draft.uiState.currentInput =
|
|
603
|
-
existing === '' ? transcript : `${existing} ${transcript}`;
|
|
604
|
-
},
|
|
605
|
-
prepare(transcript, chatSessionId) {
|
|
606
|
-
return { payload: { chatSessionId, transcript } };
|
|
607
|
-
},
|
|
608
|
-
},
|
|
609
|
-
transcribeAudioFailure(draft, action) {
|
|
610
|
-
draft.transcriptionState.fetchState = 'Error';
|
|
611
|
-
draft.transcriptionState.error = action.payload;
|
|
612
|
-
},
|
|
613
554
|
clearCurrentSessionId(draft) {
|
|
614
|
-
resetFinishedTranscription(draft);
|
|
615
555
|
// New Chat: the empty composer is the point, so the browser cannot stay over it.
|
|
616
556
|
if (draft.uiState.isSkillsBrowserOpen === true) {
|
|
617
557
|
closeSkillsBrowserState(draft);
|
|
@@ -895,8 +835,7 @@ const aiCfoView = createSlice({
|
|
|
895
835
|
// The server has it. Nothing it sends from here on will contain this row,
|
|
896
836
|
// so the tombstone has done its job and holding it any longer is what
|
|
897
837
|
// makes a routine recreated under the same id invisible forever.
|
|
898
|
-
draft.routines.deletedScheduleIds =
|
|
899
|
-
draft.routines.deletedScheduleIds.filter((id) => id !== action.payload.scheduleId);
|
|
838
|
+
draft.routines.deletedScheduleIds = draft.routines.deletedScheduleIds.filter((id) => id !== action.payload.scheduleId);
|
|
900
839
|
draft.routineMutation = {
|
|
901
840
|
fetchState: 'Completed',
|
|
902
841
|
error: undefined,
|
|
@@ -908,8 +847,7 @@ const aiCfoView = createSlice({
|
|
|
908
847
|
// is what lets the refetch put the row back — leaving it hidden would
|
|
909
848
|
// tell the user they had stopped something they had not, which is the
|
|
910
849
|
// worst outcome this list can produce.
|
|
911
|
-
draft.routines.deletedScheduleIds =
|
|
912
|
-
draft.routines.deletedScheduleIds.filter((id) => id !== action.payload.scheduleId);
|
|
850
|
+
draft.routines.deletedScheduleIds = draft.routines.deletedScheduleIds.filter((id) => id !== action.payload.scheduleId);
|
|
913
851
|
// Its own slice: the refetch that puts the row back would otherwise wipe
|
|
914
852
|
// this error, leaving the row silently reappearing with no explanation.
|
|
915
853
|
draft.routineMutation = {
|
|
@@ -1245,5 +1183,5 @@ const aiCfoView = createSlice({
|
|
|
1245
1183
|
});
|
|
1246
1184
|
},
|
|
1247
1185
|
});
|
|
1248
|
-
export const { acceptMasterTOS, acceptMasterTOSFailure, acceptMasterTOSSuccess, applyAiCfoSidePanelHostPageTransition, clearAiCfoSidePanelHostPageContext, clearCurrentSessionId, clearDeleteChatSessionStatus, clearLastContextMessage, clearSkillDetail, clearSkillMutation, closeRoutineRuns, closeRoutinesBrowser, closeSkillsBrowser, createSession, createSessionAndSubmit, createSessionAndSubmitFailure, createSessionAndSubmitSuccess, createSessionFailure, createSessionSuccess, deleteChatSession, deleteChatSessionFailure, deleteChatSessionSuccess, deleteRoutine, deleteRoutineFailure, deleteRoutineSuccess, deleteSkill, deleteSkillFailure, deleteSkillSuccess, fetchChatHistory, fetchChatHistoryFailure, fetchChatHistorySuccess, fetchChatSessionsForUser, fetchChatSessionsForUserFailure, fetchChatSessionsForUserSuccess, fetchRoutineRuns, fetchRoutineRunsFailure, fetchRoutineRunsSuccess, fetchRoutines, fetchRoutinesFailure, fetchRoutinesSuccess, fetchSkillDetail, fetchSkillDetailFailure, fetchSkillDetailSuccess, fetchSkills, fetchSkillsFailure, fetchSkillsSuccess, fetchSkillVersionBody, fetchSkillVersionBodyFailure, fetchSkillVersionBodySuccess, fetchSkillVersions, fetchSkillVersionsFailure, fetchSkillVersionsSuccess, fetchSuggestedQuestions, fetchSuggestedQuestionsFailure, fetchSuggestedQuestionsSuccess, initializeNewSessionState, openRoutinesBrowser, openSkillsBrowser, runRoutine, runRoutineFailure, runRoutineSuccess, saveRoutine, saveRoutineFailure, saveRoutineSuccess, saveSkill, saveSkillFailure, saveSkillSuccess, setRoutineEnabled, setSession, setSkillVisibility, setSkillVisibilityFailure, setSkillVisibilitySuccess, stopSubmit, stopSubmitFailure, stopSubmitQuestion, stopSubmitQuestionFailure, stopSubmitQuestionSuccess, stopSubmitSuccess, submitFeedback, submitFeedbackFailure, submitFeedbackSuccess, submitQuestion, submitQuestionFailure, submitQuestionSuccess,
|
|
1186
|
+
export const { acceptMasterTOS, acceptMasterTOSFailure, acceptMasterTOSSuccess, applyAiCfoSidePanelHostPageTransition, clearAiCfoSidePanelHostPageContext, clearCurrentSessionId, clearDeleteChatSessionStatus, clearLastContextMessage, clearSkillDetail, clearSkillMutation, closeRoutineRuns, closeRoutinesBrowser, closeSkillsBrowser, createSession, createSessionAndSubmit, createSessionAndSubmitFailure, createSessionAndSubmitSuccess, createSessionFailure, createSessionSuccess, deleteChatSession, deleteChatSessionFailure, deleteChatSessionSuccess, deleteRoutine, deleteRoutineFailure, deleteRoutineSuccess, deleteSkill, deleteSkillFailure, deleteSkillSuccess, fetchChatHistory, fetchChatHistoryFailure, fetchChatHistorySuccess, fetchChatSessionsForUser, fetchChatSessionsForUserFailure, fetchChatSessionsForUserSuccess, fetchRoutineRuns, fetchRoutineRunsFailure, fetchRoutineRunsSuccess, fetchRoutines, fetchRoutinesFailure, fetchRoutinesSuccess, fetchSkillDetail, fetchSkillDetailFailure, fetchSkillDetailSuccess, fetchSkills, fetchSkillsFailure, fetchSkillsSuccess, fetchSkillVersionBody, fetchSkillVersionBodyFailure, fetchSkillVersionBodySuccess, fetchSkillVersions, fetchSkillVersionsFailure, fetchSkillVersionsSuccess, fetchSuggestedQuestions, fetchSuggestedQuestionsFailure, fetchSuggestedQuestionsSuccess, initializeNewSessionState, openRoutinesBrowser, openSkillsBrowser, runRoutine, runRoutineFailure, runRoutineSuccess, saveRoutine, saveRoutineFailure, saveRoutineSuccess, saveSkill, saveSkillFailure, saveSkillSuccess, setRoutineEnabled, setSession, setSkillVisibility, setSkillVisibilityFailure, setSkillVisibilitySuccess, stopSubmit, stopSubmitFailure, stopSubmitQuestion, stopSubmitQuestionFailure, stopSubmitQuestionSuccess, stopSubmitSuccess, submitFeedback, submitFeedbackFailure, submitFeedbackSuccess, submitQuestion, submitQuestionFailure, submitQuestionSuccess, updateAiCfoViewScrollPosition, updateCotCollapsedState, updateCurrentInput, updateResponseState, } = aiCfoView.actions;
|
|
1249
1187
|
export default aiCfoView.reducer;
|
|
@@ -133,28 +133,3 @@ export function getSkillMutation(state) {
|
|
|
133
133
|
export function getSkillsEnabled(state) {
|
|
134
134
|
return getSkills(state).skillsEnabled;
|
|
135
135
|
}
|
|
136
|
-
/** True while a finished voice recording is being transcribed server-side. */
|
|
137
|
-
/**
|
|
138
|
-
* A take belongs to the chat it was dictated into. A new chat has no session id yet on
|
|
139
|
-
* either side, which is a match rather than a mismatch.
|
|
140
|
-
*/
|
|
141
|
-
function isTranscribingCurrentSession(state) {
|
|
142
|
-
if (state.aiCfoViewState == null) {
|
|
143
|
-
return false;
|
|
144
|
-
}
|
|
145
|
-
return (state.aiCfoViewState.transcribingChatSessionId ===
|
|
146
|
-
state.aiCfoViewState.uiState.currentChatSessionId);
|
|
147
|
-
}
|
|
148
|
-
export function getIsTranscribing(state) {
|
|
149
|
-
return (state.aiCfoViewState?.transcriptionState?.fetchState === 'In-Progress' &&
|
|
150
|
-
isTranscribingCurrentSession(state));
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* Set when a transcription request failed. Without surfacing this the composer
|
|
154
|
-
* would just drop the "Transcribing…" label and sit there silently, leaving the
|
|
155
|
-
* user with no sign their recording went nowhere.
|
|
156
|
-
*/
|
|
157
|
-
export function getTranscriptionFailed(state) {
|
|
158
|
-
return (state.aiCfoViewState?.transcriptionState?.fetchState === 'Error' &&
|
|
159
|
-
isTranscribingCurrentSession(state));
|
|
160
|
-
}
|
|
@@ -88,6 +88,10 @@ export const fetchDashboardEpic = (actions$, state$) => actions$.pipe(filter(fet
|
|
|
88
88
|
const revenueState = getRevenueReportFetchState(state.revenueState.uiState.selectedForecast?.id, state.revenueState);
|
|
89
89
|
const opExState = getOperatingExpensesReportFetchState(state.opExState.uiState.selectedForecast?.id, state.opExState);
|
|
90
90
|
const netBurnOrIncomeReportFetchState = getNetBurnOrIncomeReportFetchState(state.netBurnOrIncomeState.uiState.selectedForecast?.id, state.netBurnOrIncomeState);
|
|
91
|
+
if (state.tenantState.fetchState !== 'In-Progress' &&
|
|
92
|
+
!state.tenantState.hasValidState()) {
|
|
93
|
+
fetchActions.push(fetchAllTenants(userId));
|
|
94
|
+
}
|
|
91
95
|
if (state.cardBalanceState.fetchState !== 'In-Progress' &&
|
|
92
96
|
!state.cardBalanceState.hasValidState()) {
|
|
93
97
|
fetchActions.push(fetchCardBalance());
|