@zeniai/client-epic-state 5.3.18 → 5.3.20

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.
Files changed (78) hide show
  1. package/lib/commonStateTypes/coaBalance/coaBalance.d.ts +9 -0
  2. package/lib/commonStateTypes/coaBalance/coaBalance.js +11 -0
  3. package/lib/entity/tenant/epic/fetchAllTenantsEpic.d.ts +2 -4
  4. package/lib/entity/tenant/epic/fetchAllTenantsEpic.js +50 -42
  5. package/lib/entity/tenant/tenantPayload.d.ts +17 -1
  6. package/lib/entity/tenant/tenantReducer.d.ts +7 -2
  7. package/lib/entity/tenant/tenantReducer.js +48 -19
  8. package/lib/entity/tenant/tenantSelector.d.ts +26 -6
  9. package/lib/entity/tenant/tenantSelector.js +116 -93
  10. package/lib/entity/tenant/tenantState.d.ts +10 -0
  11. package/lib/epic.d.ts +2 -1
  12. package/lib/epic.js +3 -0
  13. package/lib/esm/commonStateTypes/coaBalance/coaBalance.js +10 -0
  14. package/lib/esm/entity/tenant/epic/fetchAllTenantsEpic.js +53 -45
  15. package/lib/esm/entity/tenant/tenantReducer.js +46 -17
  16. package/lib/esm/entity/tenant/tenantSelector.js +112 -92
  17. package/lib/esm/epic.js +4 -1
  18. package/lib/esm/index.js +7 -7
  19. package/lib/esm/view/aiCfoView/aiCfoViewReducer.js +65 -3
  20. package/lib/esm/view/aiCfoView/aiCfoViewSelector.js +25 -0
  21. package/lib/esm/view/aiCfoView/epics/transcribeAudioEpic.js +60 -0
  22. package/lib/esm/view/balanceSheet/balanceSheetForTimeframeEpic.js +9 -4
  23. package/lib/esm/view/balanceSheet/balanceSheetReducer.js +2 -0
  24. package/lib/esm/view/cashFlow/cashFlowForTimeframeEpic.js +11 -5
  25. package/lib/esm/view/cashFlow/cashFlowReducer.js +2 -0
  26. package/lib/esm/view/dashboard/dashboardEpic.js +0 -4
  27. package/lib/esm/view/dashboard/dashboardSelector.js +2 -3
  28. package/lib/esm/view/financeStatement/financeStatementEpic.js +1 -5
  29. package/lib/esm/view/financeStatement/financeStatementSelector.js +18 -0
  30. package/lib/esm/view/people/peoplePageEpic.js +0 -4
  31. package/lib/esm/view/profitAndLoss/profitAndLossForTimeframeEpic.js +9 -4
  32. package/lib/esm/view/profitAndLoss/profitAndLossReducer.js +5 -1
  33. package/lib/esm/view/spendManagement/reimbursement/editRemiView/editRemiViewReducer.js +23 -3
  34. package/lib/esm/view/spendManagement/reimbursement/editRemiView/epics/fetchRemiAndInitializeLocalStoreEpic.js +17 -4
  35. package/lib/esm/view/spendManagement/reimbursement/remiDetailView/epics/fetchRemiDetailEpic.js +1 -1
  36. package/lib/esm/view/transactionList/filterTransactionsByTimePeriod.js +18 -0
  37. package/lib/esm/view/transactionList/transactionListByAccountSelector.js +2 -1
  38. package/lib/esm/view/transactionList/transactionListByCategoryTypeSelector.js +2 -1
  39. package/lib/esm/view/transactionList/transactionListByClassSelector.js +2 -1
  40. package/lib/esm/view/transactionList/transactionListByProjectSelector.js +2 -1
  41. package/lib/index.d.ts +8 -8
  42. package/lib/index.js +56 -46
  43. package/lib/view/aiCfoView/aiCfoViewPayload.d.ts +20 -0
  44. package/lib/view/aiCfoView/aiCfoViewReducer.d.ts +2 -2
  45. package/lib/view/aiCfoView/aiCfoViewReducer.js +66 -4
  46. package/lib/view/aiCfoView/aiCfoViewSelector.d.ts +8 -1
  47. package/lib/view/aiCfoView/aiCfoViewSelector.js +27 -0
  48. package/lib/view/aiCfoView/aiCfoViewState.d.ts +9 -0
  49. package/lib/view/aiCfoView/epics/transcribeAudioEpic.d.ts +19 -0
  50. package/lib/view/aiCfoView/epics/transcribeAudioEpic.js +64 -0
  51. package/lib/view/balanceSheet/balanceSheetForTimeframeEpic.js +8 -3
  52. package/lib/view/balanceSheet/balanceSheetReducer.js +2 -0
  53. package/lib/view/balanceSheet/balanceSheetState.d.ts +2 -0
  54. package/lib/view/cashFlow/cashFlowForTimeframeEpic.js +10 -4
  55. package/lib/view/cashFlow/cashFlowReducer.js +2 -0
  56. package/lib/view/cashFlow/cashFlowState.d.ts +2 -0
  57. package/lib/view/dashboard/dashboardEpic.js +0 -4
  58. package/lib/view/dashboard/dashboardSelector.d.ts +0 -2
  59. package/lib/view/dashboard/dashboardSelector.js +1 -2
  60. package/lib/view/financeStatement/financeStatementEpic.js +1 -5
  61. package/lib/view/financeStatement/financeStatementSelector.d.ts +8 -0
  62. package/lib/view/financeStatement/financeStatementSelector.js +18 -0
  63. package/lib/view/people/peoplePageEpic.js +0 -4
  64. package/lib/view/profitAndLoss/profitAndLossForTimeframeEpic.js +8 -3
  65. package/lib/view/profitAndLoss/profitAndLossReducer.js +5 -1
  66. package/lib/view/profitAndLoss/profitAndLossState.d.ts +2 -1
  67. package/lib/view/spendManagement/reimbursement/editRemiView/editRemiViewReducer.d.ts +7 -2
  68. package/lib/view/spendManagement/reimbursement/editRemiView/editRemiViewReducer.js +24 -4
  69. package/lib/view/spendManagement/reimbursement/editRemiView/epics/fetchRemiAndInitializeLocalStoreEpic.d.ts +7 -4
  70. package/lib/view/spendManagement/reimbursement/editRemiView/epics/fetchRemiAndInitializeLocalStoreEpic.js +15 -1
  71. package/lib/view/spendManagement/reimbursement/remiDetailView/epics/fetchRemiDetailEpic.js +1 -1
  72. package/lib/view/transactionList/filterTransactionsByTimePeriod.d.ts +15 -0
  73. package/lib/view/transactionList/filterTransactionsByTimePeriod.js +22 -0
  74. package/lib/view/transactionList/transactionListByAccountSelector.js +2 -1
  75. package/lib/view/transactionList/transactionListByCategoryTypeSelector.js +2 -1
  76. package/lib/view/transactionList/transactionListByClassSelector.js +2 -1
  77. package/lib/view/transactionList/transactionListByProjectSelector.js +2 -1
  78. package/package.json +1 -1
@@ -133,3 +133,28 @@ 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
+ }
@@ -0,0 +1,60 @@
1
+ import { of } from 'rxjs';
2
+ import { catchError, filter, finalize, map, switchMap, takeUntil, timeout, } from 'rxjs/operators';
3
+ import { createZeniAPIStatus, isSuccessResponse, } from '../../../responsePayload';
4
+ import { clearAll } from '../../../rootActions';
5
+ import { transcribeAudio, transcribeAudioFailure, transcribeAudioSuccess, } from '../aiCfoViewReducer';
6
+ const AUDIO_FIELD = 'audio';
7
+ const LANGUAGE_FIELD = 'language';
8
+ /** Extension only has to match the recorded format; the server reads the part's MIME type. */
9
+ const AUDIO_FILE_NAME = 'dictation.wav';
10
+ /**
11
+ * A hung request would otherwise pin `isTranscribing` true forever, and the composer
12
+ * gates both submit and the mic on it — leaving the user unable to send even typed
13
+ * text until something else resolved it.
14
+ */
15
+ const TRANSCRIPTION_TIMEOUT_MS = 30000;
16
+ /**
17
+ * Voice dictation for the AI CFO composer. Dispatch `transcribeAudio(blob, language)` with a
18
+ * finished recording to POST it to the AI CFO micro-service `/1.0/transcriptions` endpoint;
19
+ * on success the transcript is appended to the composer input for the user to edit and send.
20
+ *
21
+ * `switchMap` (not `mergeMap`): a newer recording supersedes an older in-flight one, so a
22
+ * slow response can never append a stale transcript after a fresh one has already landed.
23
+ * The AbortController makes that cancellation real — `fetch` wrapped in a promise ignores
24
+ * an RxJS unsubscribe, so without the signal the superseded request would run to completion
25
+ * and still bill a transcription call whose result nothing wants.
26
+ */
27
+ export const transcribeAudioEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(transcribeAudio.match), switchMap((action) => {
28
+ const { audio, chatSessionId, language } = action.payload;
29
+ const abortController = new AbortController();
30
+ const formData = new FormData();
31
+ formData.append(AUDIO_FIELD, audio, AUDIO_FILE_NAME);
32
+ if (language != null && language !== '') {
33
+ formData.append(LANGUAGE_FIELD, language);
34
+ }
35
+ return zeniAPI
36
+ .postFormData(`${zeniAPI.apiEndPoints.aiCfoMicroServiceBaseUrl}/1.0/transcriptions`, formData, abortController.signal)
37
+ .pipe(timeout(TRANSCRIPTION_TIMEOUT_MS),
38
+ // A tenant switch clears the store; a transcript still in flight must not
39
+ // land in the next tenant's composer (both sessions can be `undefined`, so
40
+ // the reducer's session guard would let it through).
41
+ takeUntil(actions$.pipe(filter(clearAll.match))), map((response) => {
42
+ if (!isSuccessResponse(response)) {
43
+ return transcribeAudioFailure(response.status);
44
+ }
45
+ // An EMPTY transcript is a success (the mic caught silence) and the
46
+ // reducer leaves the composer alone. A MISSING one breaks the response
47
+ // contract, so it surfaces as an error rather than being coerced to
48
+ // silence the user cannot distinguish from a quiet room.
49
+ if (response.data?.transcript == null) {
50
+ return transcribeAudioFailure(createZeniAPIStatus('Transcription succeeded but the response carried no transcript', 'Unexpected Error'));
51
+ }
52
+ // The session id rides along so a transcript that lands after the user
53
+ // switched sessions is dropped rather than misfiled.
54
+ return transcribeAudioSuccess(response.data.transcript, chatSessionId);
55
+ }), finalize(() => abortController.abort()), catchError((error) => of(transcribeAudioFailure(createZeniAPIStatus(
56
+ // message (detailed) first, then the short title — per createZeniAPIStatus(message, title).
57
+ // JSON.stringify(Error) drops the (non-enumerable) message — extract it explicitly.
58
+ 'Transcription REST API call errored out: ' +
59
+ (error instanceof Error ? error.message : String(error)), 'Unexpected Error')))));
60
+ }));
@@ -1,11 +1,15 @@
1
1
  import { from, of } from 'rxjs';
2
- import { catchError, filter, mergeMap } from 'rxjs/operators';
2
+ import { catchError, filter, groupBy, mergeMap, switchMap } from 'rxjs/operators';
3
3
  import { updateCalculatedSectionAccountsView, updateSectionAccountsView, } from '../../entity/sectionAccountsView/sectionAccountsViewReducer';
4
4
  import { createZeniAPIStatus, isSuccessResponse } from '../../responsePayload';
5
5
  import { ALL_ASSETS_SECTIONS, ALL_CURRENT_ASSETS_SECTIONS, ALL_CURRENT_LIABILITIES_SECTIONS, ALL_LIABILITIES_SECTIONS, toSectionId, } from './balanceSheetPayload';
6
6
  import { fetchBalanceSheetForTimeframe, updateBalanceSheetForTimeframe, updateBalanceSheetForTimeframeFailure, } from './balanceSheetReducer';
7
7
  export const reportIdUniqueKey = () => 'balance_sheet';
8
- export const fetchBalanceSheetForTimeframeEpic = (actions$, _, zeniAPI) => actions$.pipe(filter(fetchBalanceSheetForTimeframe.match), mergeMap((action) => {
8
+ export const fetchBalanceSheetForTimeframeEpic = (actions$, _, zeniAPI) => actions$.pipe(filter(fetchBalanceSheetForTimeframe.match),
9
+ // One stream per timeframe: a newer request for the same timeframe (e.g. a
10
+ // custom-date-range change, or a dated fetch right after a default one)
11
+ // cancels the older in-flight request so a stale response can't land last.
12
+ groupBy((action) => action.payload.timeframe), mergeMap((group$) => group$.pipe(switchMap((action) => {
9
13
  const getTimeSeriesGroup = (timeframe) => {
10
14
  switch (timeframe) {
11
15
  case 'month':
@@ -20,7 +24,8 @@ export const fetchBalanceSheetForTimeframeEpic = (actions$, _, zeniAPI) => actio
20
24
  is_full_response: action.payload.fetchFullReport,
21
25
  time_series_groups: [getTimeSeriesGroup(action.payload.timeframe)],
22
26
  };
23
- if (action.payload.startDate != null && action.payload.endDate != null) {
27
+ if (action.payload.startDate != null &&
28
+ action.payload.endDate != null) {
24
29
  queryValue.custom_start_date = action.payload.startDate;
25
30
  queryValue.custom_end_date = action.payload.endDate;
26
31
  }
@@ -73,4 +78,4 @@ export const fetchBalanceSheetForTimeframeEpic = (actions$, _, zeniAPI) => actio
73
78
  }
74
79
  }), catchError((error) => of(updateBalanceSheetForTimeframeFailure(createZeniAPIStatus('Unexpected Error', 'Balance Sheet REST API call errored out' +
75
80
  JSON.stringify(error)), action.payload.timeframe))));
76
- }));
81
+ }))));
@@ -1,5 +1,6 @@
1
1
  import { createSlice } from '@reduxjs/toolkit';
2
2
  import { mapReportPayloadV2ToReportV2 } from '../../commonPayloadTypes/v2/viewAndReportPayloadv2';
3
+ import { withFetchedCustomDateRange } from '../../commonStateTypes/coaBalance/coaBalance';
3
4
  import { clearAll } from '../../rootActions';
4
5
  export const initialState = {
5
6
  bookCloseDate: undefined,
@@ -62,6 +63,7 @@ const balanceSheet = createSlice({
62
63
  fetchState: 'In-Progress',
63
64
  error: undefined,
64
65
  };
66
+ draft.customDateRangeByTimeframe = withFetchedCustomDateRange(draft.customDateRangeByTimeframe, timeframe, action.payload.startDate, action.payload.endDate);
65
67
  },
66
68
  },
67
69
  updateBalanceSheetForTimeframe(draft, action) {
@@ -1,11 +1,15 @@
1
1
  import { from, of } from 'rxjs';
2
- import { catchError, filter, mergeMap } from 'rxjs/operators';
2
+ import { catchError, filter, groupBy, mergeMap, switchMap } from 'rxjs/operators';
3
3
  import { updateCalculatedSectionAccountsView, updateSectionAccountsView, } from '../../entity/sectionAccountsView/sectionAccountsViewReducer';
4
4
  import { createZeniAPIStatus, isSuccessResponse } from '../../responsePayload';
5
5
  import { toCashFlowReportViewID, } from './cashFlowPayload';
6
6
  import { fetchCashFlowForTimeframe, updateCashFlowForTimeframe, updateCashFlowForTimeframeFailure, } from './cashFlowReducer';
7
7
  export const reportIdUniqueKey = () => 'cash_flow';
8
- export const fetchCashFlowForTimeframeEpic = (actions$, _, zeniAPI) => actions$.pipe(filter(fetchCashFlowForTimeframe.match), mergeMap((action) => {
8
+ export const fetchCashFlowForTimeframeEpic = (actions$, _, zeniAPI) => actions$.pipe(filter(fetchCashFlowForTimeframe.match),
9
+ // One stream per timeframe: a newer request for the same timeframe (e.g. a
10
+ // custom-date-range change, or a dated fetch right after a default one)
11
+ // cancels the older in-flight request so a stale response can't land last.
12
+ groupBy((action) => action.payload.timeframe), mergeMap((group$) => group$.pipe(switchMap((action) => {
9
13
  const getTimeSeriesGroup = (timeframe) => {
10
14
  switch (timeframe) {
11
15
  case 'month':
@@ -20,7 +24,8 @@ export const fetchCashFlowForTimeframeEpic = (actions$, _, zeniAPI) => actions$.
20
24
  is_full_response: action.payload.fetchFullReport,
21
25
  time_series_groups: [getTimeSeriesGroup(action.payload.timeframe)],
22
26
  };
23
- if (action.payload.startDate != null && action.payload.endDate != null) {
27
+ if (action.payload.startDate != null &&
28
+ action.payload.endDate != null) {
24
29
  queryValue.custom_start_date = action.payload.startDate;
25
30
  queryValue.custom_end_date = action.payload.endDate;
26
31
  }
@@ -48,5 +53,6 @@ export const fetchCashFlowForTimeframeEpic = (actions$, _, zeniAPI) => actions$.
48
53
  else {
49
54
  return of(updateCashFlowForTimeframeFailure(response.status, action.payload.timeframe));
50
55
  }
51
- }), catchError((error) => of(updateCashFlowForTimeframeFailure(createZeniAPIStatus('Unexpected Error', 'Cash Flow REST API call errored out' + JSON.stringify(error)), action.payload.timeframe))));
52
- }));
56
+ }), catchError((error) => of(updateCashFlowForTimeframeFailure(createZeniAPIStatus('Unexpected Error', 'Cash Flow REST API call errored out' +
57
+ JSON.stringify(error)), action.payload.timeframe))));
58
+ }))));
@@ -1,5 +1,6 @@
1
1
  import { createSlice } from '@reduxjs/toolkit';
2
2
  import { mapReportPayloadV2ToReportV2 } from '../../commonPayloadTypes/v2/viewAndReportPayloadv2';
3
+ import { withFetchedCustomDateRange } from '../../commonStateTypes/coaBalance/coaBalance';
3
4
  import { clearAll } from '../../rootActions';
4
5
  export const initialState = {
5
6
  fetchState: {
@@ -54,6 +55,7 @@ const cashFlow = createSlice({
54
55
  fetchState: 'In-Progress',
55
56
  error: undefined,
56
57
  };
58
+ draft.customDateRangeByTimeframe = withFetchedCustomDateRange(draft.customDateRangeByTimeframe, timeframe, action.payload.startDate, action.payload.endDate);
57
59
  },
58
60
  },
59
61
  updateCashFlowForTimeframe(draft, action) {
@@ -88,10 +88,6 @@ 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
- }
95
91
  if (state.cardBalanceState.fetchState !== 'In-Progress' &&
96
92
  !state.cardBalanceState.hasValidState()) {
97
93
  fetchActions.push(fetchCardBalance());
@@ -1,7 +1,7 @@
1
1
  import { createSelector } from '@reduxjs/toolkit';
2
2
  import { newBalancesFilter } from '../../commonStateTypes/coaBalance/coaBalancesFilter';
3
3
  import { reduceFetchState } from '../../commonStateTypes/reduceFetchState';
4
- import { getCurrentTenant, getTenantsByCheckInDateSelector, } from '../../entity/tenant/tenantSelector';
4
+ import { getCurrentTenant } from '../../entity/tenant/tenantSelector';
5
5
  import { hasAdminLevelAccess, hasInvestorBankerLevelAccess, } from '../../entity/userRole/userRoleType';
6
6
  import { getApAgingReport } from '../apAgingView/apAgingReport/apAgingSelector';
7
7
  import { getArAgingReport } from '../arAgingView/arAgingReport/arAgingSelector';
@@ -34,8 +34,7 @@ const getCashInCashOutLast4Periods = (state) => getCashInCashOut(state.accountSt
34
34
  const getNetBurnOrIncomeStoryCard = (state) => getNetBurnOrIncomeStoryCardReport(state);
35
35
  const apAgingSelector = (state) => getApAgingReport(state);
36
36
  const arAgingSelector = (state) => getArAgingReport(state);
37
- const tenantSelector = createSelector(getTenantsByCheckInDateSelector, getCurrentTenant, (tenantsOrdered, currentTenant) => ({
38
- tenantsOrdered,
37
+ const tenantSelector = createSelector(getCurrentTenant, (currentTenant) => ({
39
38
  currentTenant,
40
39
  }));
41
40
  export const getDashboard = createSelector(tenantSelector, getCardBalance, getCashBalance, getOperatingExpensesForLast5Periods, getRevenueForLast4Periods, getTop6Expenses, getNetBurnOrIncomeForLast4Periods, getNetBurnOrIncomeStoryCard, getCashPositionLast5Periods, getCashInCashOutLast4Periods, getInsights, getCompanyPassportView, getTasksCardReport, getBillPayCardReport, getReimbursementCardReport, apAgingSelector, arAgingSelector, getRewardsPlanCard, getDashboardCardsOrdered, (state) => {
@@ -15,12 +15,8 @@ export const fetchFinanceStatementEpic = (actions$, state$) => actions$.pipe(fil
15
15
  return of(fetchAllTenants(userId), fetchProfitAndLoss(), fetchBalanceSheet(), fetchCashFlow());
16
16
  }
17
17
  else {
18
- const { tenantState, financeStatementState } = state;
18
+ const { financeStatementState } = state;
19
19
  const fetchActions = [];
20
- if (tenantState.fetchState !== 'In-Progress' &&
21
- !tenantState.hasValidState()) {
22
- fetchActions.push(fetchAllTenants(userId));
23
- }
24
20
  const pandLFetchState = getPandLReportFetchState(undefined, state.profitAndLossState);
25
21
  const balanceSheetFetchState = getBalanceSheetFetchState(state.balanceSheetState);
26
22
  const cashFlowFetchState = getCashFlowReportFetchState(state.cashFlowState);
@@ -161,6 +161,23 @@ export const getFinanceStatement = createSelector((state) => state.accountState,
161
161
  default:
162
162
  break;
163
163
  }
164
+ let customDateRangeByTimeframe;
165
+ switch (financeStatementState.selectedReportId) {
166
+ case 'profit_and_loss':
167
+ customDateRangeByTimeframe =
168
+ profitAndLossState.pandL.customDateRangeByTimeframe;
169
+ break;
170
+ case 'balance_sheet':
171
+ customDateRangeByTimeframe =
172
+ balanceSheetState.customDateRangeByTimeframe;
173
+ break;
174
+ case 'cash_flow':
175
+ customDateRangeByTimeframe = cashFlowState.customDateRangeByTimeframe;
176
+ break;
177
+ default:
178
+ break;
179
+ }
180
+ const selectedReportCustomDateRange = customDateRangeByTimeframe?.[financeStatementState.timeframe];
164
181
  return {
165
182
  reportId: 'finance_statement',
166
183
  reportTitle: '',
@@ -170,6 +187,7 @@ export const getFinanceStatement = createSelector((state) => state.accountState,
170
187
  allTimeframeTicks,
171
188
  balancesInTimeframe,
172
189
  selectedReportAndTimeframeFetchState,
190
+ selectedReportCustomDateRange,
173
191
  displayOrder: financeStatementState.displayOrder,
174
192
  reportFormat: financeStatementState.reportFormat,
175
193
  firstMonthOfFY,
@@ -10,10 +10,6 @@ export const fetchPeoplePageEpic = (actions$, state$) => actions$.pipe(filter(fe
10
10
  else {
11
11
  const state = state$.value;
12
12
  const fetchActions = [];
13
- if (state.tenantState.fetchState !== 'In-Progress' &&
14
- !state.tenantState.hasValidState()) {
15
- fetchActions.push(fetchAllTenants(userId));
16
- }
17
13
  if (state.peopleState.fetchState != 'In-Progress' &&
18
14
  !state.peopleState.hasValidState()) {
19
15
  fetchActions.push(fetchPeople());
@@ -1,12 +1,16 @@
1
1
  import { from, of } from 'rxjs';
2
- import { catchError, filter, mergeMap } from 'rxjs/operators';
2
+ import { catchError, filter, groupBy, mergeMap, switchMap } from 'rxjs/operators';
3
3
  import { updateCalculatedSectionAccountsView, updateSectionAccountsView, } from '../../entity/sectionAccountsView/sectionAccountsViewReducer';
4
4
  import { createZeniAPIStatus, isSuccessResponse } from '../../responsePayload';
5
5
  import { fetchProfitAndLossForTimeframe, updateProfitAndLossForTimeframe, updateProfitAndLossForTimeframeFailure, } from './profitAndLossReducer';
6
6
  export const reportIdUniqueKey = (forecastId) => forecastId != null
7
7
  ? `profit_and_loss+${forecastId}`
8
8
  : 'profit_and_loss';
9
- export const fetchProfitAndLossForTimeframeEpic = (actions$, _, zeniAPI) => actions$.pipe(filter(fetchProfitAndLossForTimeframe.match), mergeMap((action) => {
9
+ export const fetchProfitAndLossForTimeframeEpic = (actions$, _, zeniAPI) => actions$.pipe(filter(fetchProfitAndLossForTimeframe.match),
10
+ // One stream per timeframe: a newer request for the same timeframe (e.g. a
11
+ // custom-date-range change, or a dated fetch right after a default one)
12
+ // cancels the older in-flight request so a stale response can't land last.
13
+ groupBy((action) => `${action.payload.forecastId ?? ''}_${action.payload.timeframe}`), mergeMap((group$) => group$.pipe(switchMap((action) => {
10
14
  const getTimeSeriesGroup = (timeframe) => {
11
15
  switch (timeframe) {
12
16
  case 'month':
@@ -25,7 +29,8 @@ export const fetchProfitAndLossForTimeframeEpic = (actions$, _, zeniAPI) => acti
25
29
  queryValue.forecast_id = action.payload.forecastId;
26
30
  queryValue.is_forecast_vs_actual = true;
27
31
  }
28
- if (action.payload.startDate != null && action.payload.endDate != null) {
32
+ if (action.payload.startDate != null &&
33
+ action.payload.endDate != null) {
29
34
  queryValue.custom_start_date = action.payload.startDate;
30
35
  queryValue.custom_end_date = action.payload.endDate;
31
36
  }
@@ -55,4 +60,4 @@ export const fetchProfitAndLossForTimeframeEpic = (actions$, _, zeniAPI) => acti
55
60
  return of(updateProfitAndLossForTimeframeFailure(response.status, action.payload.forecastId, action.payload.timeframe));
56
61
  }
57
62
  }), catchError((error) => of(updateProfitAndLossForTimeframeFailure(createZeniAPIStatus('Unexpected Error', 'P&L REST API call errored out' + JSON.stringify(error)), action.payload.forecastId, action.payload.timeframe))));
58
- }));
63
+ }))));
@@ -1,5 +1,6 @@
1
1
  import { createSlice } from '@reduxjs/toolkit';
2
2
  import { mapReportPayloadV2ToReportV2 } from '../../commonPayloadTypes/v2/viewAndReportPayloadv2';
3
+ import { withFetchedCustomDateRange } from '../../commonStateTypes/coaBalance/coaBalance';
3
4
  import { clearAll } from '../../rootActions';
4
5
  export const initialPandLState = {
5
6
  bookCloseDate: undefined,
@@ -71,7 +72,10 @@ const profitAndLoss = createSlice({
71
72
  fetchState: 'In-Progress',
72
73
  error: undefined,
73
74
  };
74
- updateState(draft, action.payload.forecastId, { fetchState });
75
+ updateState(draft, action.payload.forecastId, {
76
+ fetchState,
77
+ customDateRangeByTimeframe: withFetchedCustomDateRange(pAndLState.customDateRangeByTimeframe, timeframe, action.payload.startDate, action.payload.endDate),
78
+ });
75
79
  },
76
80
  },
77
81
  updateProfitAndLossForTimeframe(draft, action) {
@@ -30,8 +30,13 @@ const editRemiView = createSlice({
30
30
  };
31
31
  },
32
32
  },
33
- indicateReadyToInitializeRemiLocalStore() {
34
- // do nothing
33
+ indicateReadyToInitializeRemiLocalStore: {
34
+ reducer() {
35
+ // do nothing
36
+ },
37
+ prepare(reimbursementId) {
38
+ return { payload: { reimbursementId } };
39
+ },
35
40
  },
36
41
  fetchRecommendationsAndUpdateMerchantRecommendations: {
37
42
  reducer() {
@@ -137,6 +142,21 @@ const editRemiView = createSlice({
137
142
  return { payload: { reimbursementId } };
138
143
  },
139
144
  },
145
+ initializeRemiToLocalStoreFailure: {
146
+ reducer(draft, action) {
147
+ const { reimbursementId, error } = action.payload;
148
+ draft.editRemiStateById[reimbursementId] = {
149
+ ...draft.editRemiStateById[reimbursementId],
150
+ fetchStatus: {
151
+ fetchState: 'Error',
152
+ error,
153
+ },
154
+ };
155
+ },
156
+ prepare(reimbursementId, error) {
157
+ return { payload: { reimbursementId, error } };
158
+ },
159
+ },
140
160
  saveRemiUpdatesToLocalStore(draft, action) {
141
161
  if (action.payload.reimbursementId != null) {
142
162
  const reimbursementId = action.payload.reimbursementId;
@@ -387,7 +407,7 @@ const editRemiView = createSlice({
387
407
  });
388
408
  },
389
409
  });
390
- export const { fetchEditRemiDetailPage, fetchRemiAndInitializeLocalStore, initializeRemiToLocalStore, fetchRecommendationsAndUpdateMerchantRecommendations, saveRemiUpdatesToLocalStore, updatesPaymentToInLocalStore, discardRemiUpdatesInLocalStore, removeFileFromRemiUpdatesInLocalStore, saveRemiDetail, saveRemiSuccessOrFailure, parseReceiptsToRemi, fetchCurrencyConversionValue, updateReimbursementType, updateHomeCurrencyConversion, currencyConversionValueSuccessOrFailure, waitForRemiDetailThenInitializeLocalStore, waitForMerchantRecommendationFetchThenUpdateRecommendationInMerchant, updateAddRemiAutoFields, indicateReadyToInitializeRemiLocalStore, updateUploadFetchState, updateRecommendationInMerchant, updateTentativeMerchantNames, clearTentativeMerchantName, clearAddRemiAutoFields, } = editRemiView.actions;
410
+ export const { fetchEditRemiDetailPage, fetchRemiAndInitializeLocalStore, initializeRemiToLocalStore, fetchRecommendationsAndUpdateMerchantRecommendations, saveRemiUpdatesToLocalStore, updatesPaymentToInLocalStore, discardRemiUpdatesInLocalStore, removeFileFromRemiUpdatesInLocalStore, saveRemiDetail, saveRemiSuccessOrFailure, parseReceiptsToRemi, fetchCurrencyConversionValue, updateReimbursementType, updateHomeCurrencyConversion, currencyConversionValueSuccessOrFailure, waitForRemiDetailThenInitializeLocalStore, initializeRemiToLocalStoreFailure, waitForMerchantRecommendationFetchThenUpdateRecommendationInMerchant, updateAddRemiAutoFields, indicateReadyToInitializeRemiLocalStore, updateUploadFetchState, updateRecommendationInMerchant, updateTentativeMerchantNames, clearTentativeMerchantName, clearAddRemiAutoFields, } = editRemiView.actions;
391
411
  export default editRemiView.reducer;
392
412
  const doUpdateRecommendationForEntity = (draft, lineId, recommendations, shouldAutofill, reimbursementId, reimbursementStageCode) => {
393
413
  if (reimbursementId != null) {
@@ -1,8 +1,9 @@
1
1
  import recordGet from 'lodash/get';
2
- import { from } from 'rxjs';
3
- import { filter, mergeMap } from 'rxjs/operators';
4
- import { fetchRemiDetail, } from '../../remiDetailView/remiDetailViewReducer';
5
- import { fetchRemiAndInitializeLocalStore, initializeRemiToLocalStore, waitForRemiDetailThenInitializeLocalStore, } from '../editRemiViewReducer';
2
+ import { from, merge } from 'rxjs';
3
+ import { filter, map, mergeMap, take, takeUntil, takeWhile, } from 'rxjs/operators';
4
+ import { clearAll } from '../../../../../rootActions';
5
+ import { fetchRemiDetail, updateRemiDetailFetchState, } from '../../remiDetailView/remiDetailViewReducer';
6
+ import { fetchRemiAndInitializeLocalStore, indicateReadyToInitializeRemiLocalStore, initializeRemiToLocalStore, initializeRemiToLocalStoreFailure, waitForRemiDetailThenInitializeLocalStore, } from '../editRemiViewReducer';
6
7
  export const fetchRemiAndInitializeLocalStoreEpic = (actions$, state$) => actions$.pipe(filter(fetchRemiAndInitializeLocalStore.match), mergeMap((action) => {
7
8
  const { reimbursementId, cacheOverride, isShowDeletedReimbursementEnabled, } = action.payload;
8
9
  const state = state$.value;
@@ -35,3 +36,15 @@ export const fetchRemiAndInitializeLocalStoreEpic = (actions$, state$) => action
35
36
  }
36
37
  return from(remiDetailActions);
37
38
  }));
39
+ export const waitForRemiDetailThenInitializeLocalStoreEpic = (actions$) => actions$.pipe(filter(waitForRemiDetailThenInitializeLocalStore.match), mergeMap((action) => {
40
+ const { reimbursementId } = action.payload;
41
+ const ready$ = actions$.pipe(filter(indicateReadyToInitializeRemiLocalStore.match), filter((readyAction) => readyAction.payload.reimbursementId === reimbursementId), take(1), map(() => initializeRemiToLocalStore(reimbursementId)));
42
+ const failed$ = actions$.pipe(filter(updateRemiDetailFetchState.match), filter((fetchStateAction) => fetchStateAction.payload.reimbursementId === reimbursementId &&
43
+ fetchStateAction.payload.fetchState === 'Error'), map((fetchStateAction) => initializeRemiToLocalStoreFailure(reimbursementId, fetchStateAction.payload.error)));
44
+ const supersededOrCleared$ = actions$.pipe(filter((nextAction) => clearAll.match(nextAction) ||
45
+ (waitForRemiDetailThenInitializeLocalStore.match(nextAction) &&
46
+ nextAction.payload.reimbursementId === reimbursementId)));
47
+ // An Error does not end the wait: a newer request for the same id may still succeed.
48
+ // After an Error, supersededOrCleared$ is what ends it.
49
+ return merge(ready$, failed$).pipe(takeWhile((resultAction) => !initializeRemiToLocalStore.match(resultAction), true), takeUntil(supersededOrCleared$));
50
+ }));
@@ -75,7 +75,7 @@ export const fetchRemiDetailEpic = (actions$, state$, zeniAPI) => actions$.pipe(
75
75
  }));
76
76
  }
77
77
  });
78
- actions.push(indicateReadyToInitializeRemiLocalStore()); // add dummy action
78
+ actions.push(indicateReadyToInitializeRemiLocalStore(reimbursementId));
79
79
  if (response.data.transaction?.lines != null &&
80
80
  response.data.transaction.lines.length > 0) {
81
81
  actions.push(fetchDuplicateReimbursement(response.data.transaction.created_by_user_id, false, response.data.transaction.transaction_id));
@@ -0,0 +1,18 @@
1
+ import { DEFAULT_DATE_FORMAT, toString, } from '../../commonStateTypes/timePeriod';
2
+ /**
3
+ * Transaction lists are fetched and cached in month buckets: `splitPeriod`
4
+ * snaps the first bucket back to the 1st of the month, while the last bucket
5
+ * is fetched with the real end date. So a period that starts mid-month (e.g. a
6
+ * drill-down from the custom-date-range column "Jun 17-30 2026") pulls in the
7
+ * days before its start. Drop those so the list reconciles to the clicked
8
+ * figure. Periods starting on the 1st (every pre-existing caller) are returned
9
+ * untouched. Compares calendar days as `YYYY-MM-DD` strings so the viewer's
10
+ * timezone can't shift the boundary.
11
+ */
12
+ export const filterTransactionsByTimePeriod = (transactions, period) => {
13
+ if (period.start.day === 1) {
14
+ return transactions;
15
+ }
16
+ const start = toString(period.start);
17
+ return transactions.filter((transaction) => transaction.date.format(DEFAULT_DATE_FORMAT) >= start);
18
+ };
@@ -2,6 +2,7 @@ import flatMap from 'lodash/flatMap';
2
2
  import recordGet from 'lodash/get';
3
3
  import orderBy from 'lodash/orderBy';
4
4
  import { getSupportedTransactionById } from '../../entity/transaction/transactionSelector';
5
+ import { filterTransactionsByTimePeriod } from './filterTransactionsByTimePeriod';
5
6
  import { splitPeriod } from './parallelFetchAccountTransactionListEpic';
6
7
  import { isAnyFetchCompleted, reduceFetchState, } from './reduceTransactionListFetchState';
7
8
  import { getAcKey, getAcTranKey, } from './transactionListState';
@@ -29,7 +30,7 @@ export const getTransactionListByAccount = (transactionState, transactionListSta
29
30
  }
30
31
  return value != null;
31
32
  });
32
- transactions = orderBy(transactionsUnsorted, (value) => value.date.valueOf(), 'desc');
33
+ transactions = orderBy(filterTransactionsByTimePeriod(transactionsUnsorted, filterByTimePeriod), (value) => value.date.valueOf(), 'desc');
33
34
  }
34
35
  const key = getAcKey(accountId, accountType);
35
36
  const uiState = recordGet(transactionListState.byAccount.transactionListUIStateByAccountKey, key, {});
@@ -2,6 +2,7 @@ import flatMap from 'lodash/flatMap';
2
2
  import recordGet from 'lodash/get';
3
3
  import orderBy from 'lodash/orderBy';
4
4
  import { getSupportedTransactionById } from '../../entity/transaction/transactionSelector';
5
+ import { filterTransactionsByTimePeriod } from './filterTransactionsByTimePeriod';
5
6
  import { splitPeriod } from './parallelFetchAccountTransactionListEpic';
6
7
  import { isAnyFetchCompleted, reduceFetchState, } from './reduceTransactionListFetchState';
7
8
  import { getCategoryTypeTranKey, } from './transactionListState';
@@ -26,7 +27,7 @@ export const getTransactionsListByCategoryType = (transactionState, transactionL
26
27
  }
27
28
  return value != null;
28
29
  });
29
- transactions = orderBy(transactionsUnsorted, (value) => value.date.valueOf(), 'desc');
30
+ transactions = orderBy(filterTransactionsByTimePeriod(transactionsUnsorted, filterByTimePeriod), (value) => value.date.valueOf(), 'desc');
30
31
  }
31
32
  const uiState = transactionListState.byType[transactionCategoryType].transactionListUIState;
32
33
  return {
@@ -2,6 +2,7 @@ import flatMap from 'lodash/flatMap';
2
2
  import recordGet from 'lodash/get';
3
3
  import orderBy from 'lodash/orderBy';
4
4
  import { getSupportedTransactionById } from '../../entity/transaction/transactionSelector';
5
+ import { filterTransactionsByTimePeriod } from './filterTransactionsByTimePeriod';
5
6
  import { splitPeriod } from './parallelFetchAccountTransactionListEpic';
6
7
  import { isAnyFetchCompleted, reduceFetchState, } from './reduceTransactionListFetchState';
7
8
  import { getClassAcKey, getClassAcTranKey, } from './transactionListState';
@@ -29,7 +30,7 @@ export const getTransactionListByClass = (transactionState, transactionListState
29
30
  }
30
31
  return value != null;
31
32
  });
32
- transactions = orderBy(transactionsUnsorted, (value) => value.date.valueOf(), 'desc');
33
+ transactions = orderBy(filterTransactionsByTimePeriod(transactionsUnsorted, filterByTimePeriod), (value) => value.date.valueOf(), 'desc');
33
34
  }
34
35
  const key = getClassAcKey(accountId, accountType, classId);
35
36
  const uiState = recordGet(transactionListState.byClass.transactionListUIStateByClassKey, key, {});
@@ -2,6 +2,7 @@ import flatMap from 'lodash/flatMap';
2
2
  import recordGet from 'lodash/get';
3
3
  import orderBy from 'lodash/orderBy';
4
4
  import { getSupportedTransactionById } from '../../entity/transaction/transactionSelector';
5
+ import { filterTransactionsByTimePeriod } from './filterTransactionsByTimePeriod';
5
6
  import { splitPeriod } from './parallelFetchAccountTransactionListEpic';
6
7
  import { isAnyFetchCompleted, reduceFetchState, } from './reduceTransactionListFetchState';
7
8
  import { getProjectAcKey, getProjectAcTranKey, } from './transactionListState';
@@ -29,7 +30,7 @@ export const getTransactionListByProject = (transactionState, transactionListSta
29
30
  }
30
31
  return value != null;
31
32
  });
32
- transactions = orderBy(transactionsUnsorted, (value) => value.date.valueOf(), 'desc');
33
+ transactions = orderBy(filterTransactionsByTimePeriod(transactionsUnsorted, filterByTimePeriod), (value) => value.date.valueOf(), 'desc');
33
34
  }
34
35
  const key = getProjectAcKey(accountId, accountType, projectId);
35
36
  const uiState = recordGet(transactionListState.byProject.transactionListUIStateByProjectKey, key, {});
package/lib/index.d.ts CHANGED
@@ -146,8 +146,8 @@ import { ALL_WEEK_DAYS, DayOfWeek, PriorityCodeType, Task, TaskCodeType, TaskPri
146
146
  import { getTaskGroupById } from './entity/taskGroup/taskGroupSelector';
147
147
  import { TaskGroupState } from './entity/taskGroup/taskGroupState';
148
148
  import { TaskGroupTemplate } from './entity/taskGroupTemplate/taskGroupTemplateState';
149
- import { DoSignInPayload, 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';
150
- import { CurrentTenant, DEFAULT_RECEIPTS_EMAIL, TenantBaseView, TenantCoreDetailsView, TenantView, TenantsBaseOrdered, TenantsOrdered, getCurrentTenant, getIsAccountingClassesEnabled, getIsAccountingProjectsEnabled, getIsAutoReviewIncomeWithoutCustomerEnabled, getReceiptsEmail, getTenantBaseById, getTenantBaseViewForTenantId, getTenantBaseViewForTenantView, getTenantsBaseByCheckInDateSelector, getTenantsByCheckInDateSelector, getTenantsCoreDetailsByCheckInDateSelector, isOtherProductsEnabledForTenant, isTenantBankingOnly, isTenantBookkeepingEnabled, isTenantCardsOnly, isTenantUsingZeniCOA, isZeniDomainTenant, toTenantCoreDetailsView } from './entity/tenant/tenantSelector';
149
+ import { DoSignInPayload, deleteConnection, doMagicLinkSignIn, doSignIn, doSignOut, fetchActiveTenant, fetchAllTenants, fetchExcludedResources as fetchExcludedResourcesForTenant, fetchExternalConnections as fetchExternalConnectionsForTenant, fetchSubscriptionSummaryForTenant, initEmailConnectOAuth, resendVerifyDeviceOTP, resetSignInState, saveAPIKeyConnection, saveConnectorCredentials, saveExternalConnection as saveExternalConnectionForTenant, saveOAuthConnection, seedTenantSummary, sendEmailMagicLinkToUser, sendSessionHeartbeat, toExternalIntegrationType, updateCurrentTenant, updateSignInState, verifyDeviceWithTwoFA } from './entity/tenant/tenantReducer';
150
+ import { CurrentTenant, CurrentTenantIds, DEFAULT_RECEIPTS_EMAIL, TenantBaseView, TenantCoreDetailsView, TenantView, TenantsBaseOrdered, getCurrentTenant, getCurrentTenantId, getCurrentTenantIds, getIsAccountingClassesEnabled, getIsAccountingProjectsEnabled, getIsAutoReviewIncomeWithoutCustomerEnabled, getReceiptsEmail, getTenantBaseById, getTenantBaseViewForTenantId, getTenantBaseViewForTenantView, getTenantsBaseByCheckInDateSelector, getTenantsCoreDetailsByCheckInDateSelector, isCurrentTenantLoaded, isOtherProductsEnabledForTenant, isTenantBankingOnly, isTenantBookkeepingEnabled, isTenantCardsOnly, isTenantLoaded, isTenantUsingZeniCOA, isZeniDomainTenant, toTenantCoreDetailsView } from './entity/tenant/tenantSelector';
151
151
  import { CapitalizableAccount, CapitalizableAccounts, CapitalizableClassificationType, CapitalizableMatchPattern, Connection, LoggedInUser, RoleResource, Tenant, TenantProductSettings } from './entity/tenant/tenantState';
152
152
  import { toExternalSupportedTool } from './entity/tenant/tenantTypes';
153
153
  import { ToastNotificationPayload } from './entity/toastNotification/toastNotificationPayload';
@@ -512,7 +512,7 @@ import { InternationalWireSelectorView, getInternationalWireView } from './view/
512
512
  import { fetchInternationalVerificationForm, submitInternationalVerificationForm, updateVerificationFormLocalData } from './view/spendManagement/billPay/internationalWireVerification/internationalWireVerificationReducer';
513
513
  import { InternationalWireVerificationView, getIntlWireVerificationView } from './view/spendManagement/billPay/internationalWireVerification/internationalWireVerificationSelector';
514
514
  import { FieldValueType, InternationalWireVerificationState, VerificationFormField, VerificationFormLocalData } from './view/spendManagement/billPay/internationalWireVerification/internationalWireVerificationState';
515
- import { fetchBillAttachment, fetchMagicLinkBankNameByRouting, fetchMagicLinkBankNameBySwift, fetchMagicLinkTenant, saveBankAccount, saveMagicLinkAddressInLocalStore, updateMagicLinkBankAccountLocalStoreData, updateMagicLinkInternationalBankAccountLocalStoreData } from './view/spendManagement/billPay/magicLinkView/magicLinkViewReducer';
515
+ import { fetchBillAttachment, fetchMagicLinkBankNameByRouting, fetchMagicLinkBankNameBySwift, fetchMagicLinkTenant, saveBankAccount, saveMagicLinkAddressInLocalStore, updateMagicLinkBankAccountLocalStoreData, updateMagicLinkInternationalBankAccountLocalStoreData, updateMagicLinkTenantFailure, updateMagicLinkTenantSuccess } from './view/spendManagement/billPay/magicLinkView/magicLinkViewReducer';
516
516
  import { MagicLinkView, getMagicLinkBankAccountView, getMagicLinkCurrentAddressState, getMagicLinkView } from './view/spendManagement/billPay/magicLinkView/magicLinkViewSelector';
517
517
  import { PreviousBillsSelectorView } from './view/spendManagement/billPay/previousBills/previousBillsSelector';
518
518
  import { fetchWiseRedirectStatus } from './view/spendManagement/billPay/wiseRedirectView/wiseRedirectReducer';
@@ -754,7 +754,7 @@ export { TimeframeTick, TimeframeTickWithMetaData, toTimeframeTick, mapTimePerio
754
754
  export { VendorSpendTrendFilterTabType, toVendorSpendTrendFilterTabsTypeStrict, } from './entity/vendorExpense/vendorSpendTrendFilterTabType';
755
755
  export { getNumberOfPeriods };
756
756
  export { SCHEDULE_DAYS_OF_MONTH, ScheduleDaysOfMonth, toScheduleDaysOfMonth, Day, Month, toMonth, toMonthStrict, Quarter, toQuarter, toQuarterStrict, AbsoluteDay, TimePeriod, };
757
- export { CapitalizableAccount, CapitalizableAccounts, CapitalizableClassificationType, CapitalizableMatchPattern, Tenant, TenantView, LoggedInUser, TenantBaseView, CurrentTenant, TenantProductSettings, getTenantBaseById, getCurrentTenant, getIsAccountingClassesEnabled, getIsAccountingProjectsEnabled, getIsAutoReviewIncomeWithoutCustomerEnabled, getTenantsByCheckInDateSelector, getTenantsBaseByCheckInDateSelector, getTenantsCoreDetailsByCheckInDateSelector, toTenantCoreDetailsView, getTenantBaseViewForTenantView, getTenantBaseViewForTenantId, isZeniDomainTenant, isTenantUsingZeniCOA, TenantsBaseOrdered, TenantsOrdered, TenantCoreDetailsView, fetchActiveTenant, fetchAllTenants, updateCurrentTenant, clearAll, doMagicLinkSignIn, verifyDeviceWithTwoFA, resendVerifyDeviceOTP, sendEmailMagicLinkToUser, doSignIn, updateSignInState, DoSignInPayload, doSignOut, sendSessionHeartbeat, resetSignInState, RoleResource, Connection, fetchExcludedResourcesForTenant, fetchExternalConnectionsForTenant, saveExternalConnectionForTenant, deleteConnection, saveAPIKeyConnection, saveConnectorCredentials, saveOAuthConnection, initEmailConnectOAuth, toExternalIntegrationType, toExternalSupportedTool, fetchSubscriptionSummaryForTenant, isTenantBankingOnly, isTenantCardsOnly, isTenantBookkeepingEnabled, isOtherProductsEnabledForTenant, DEFAULT_RECEIPTS_EMAIL, getReceiptsEmail, };
757
+ export { CapitalizableAccount, CapitalizableAccounts, CapitalizableClassificationType, CapitalizableMatchPattern, Tenant, TenantView, LoggedInUser, TenantBaseView, CurrentTenant, CurrentTenantIds, TenantProductSettings, getTenantBaseById, getCurrentTenant, getCurrentTenantId, getCurrentTenantIds, isCurrentTenantLoaded, isTenantLoaded, getIsAccountingClassesEnabled, getIsAccountingProjectsEnabled, getIsAutoReviewIncomeWithoutCustomerEnabled, getTenantsBaseByCheckInDateSelector, getTenantsCoreDetailsByCheckInDateSelector, toTenantCoreDetailsView, getTenantBaseViewForTenantView, getTenantBaseViewForTenantId, isZeniDomainTenant, isTenantUsingZeniCOA, TenantsBaseOrdered, TenantCoreDetailsView, fetchActiveTenant, fetchAllTenants, seedTenantSummary, updateCurrentTenant, clearAll, doMagicLinkSignIn, verifyDeviceWithTwoFA, resendVerifyDeviceOTP, sendEmailMagicLinkToUser, doSignIn, updateSignInState, DoSignInPayload, doSignOut, sendSessionHeartbeat, resetSignInState, RoleResource, Connection, fetchExcludedResourcesForTenant, fetchExternalConnectionsForTenant, saveExternalConnectionForTenant, deleteConnection, saveAPIKeyConnection, saveConnectorCredentials, saveOAuthConnection, initEmailConnectOAuth, toExternalIntegrationType, toExternalSupportedTool, fetchSubscriptionSummaryForTenant, isTenantBankingOnly, isTenantCardsOnly, isTenantBookkeepingEnabled, isOtherProductsEnabledForTenant, DEFAULT_RECEIPTS_EMAIL, getReceiptsEmail, };
758
758
  export { Account, AccountType, AccountBase, StatementCloseDay, toAccountType, AccountReport, NestedAccountReport, AccountWithBalanceReport, AccountGroup, AccountGroupReportV2, AccountGroupType, toAccountGroupType, AccountGroupReport, getAccountGroupKey, AccountGroupKey, RecommendedAccountBase, AccountFilterOption, getAllAccounts, getTransactionFilterAccountOptions, };
759
759
  export { Class, ClassBase, RecommendedClassBase, } from './entity/class/classState';
760
760
  export { ClassFilterOption, getAllClasses, getClassById, getClassFilterOptions, } from './entity/class/classSelector';
@@ -952,7 +952,7 @@ export { isZeniClearingAccountReport, ZENI_CLEARING_ACCOUNT, isZeniClearingAccou
952
952
  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, OnboardingCustomerView, OnboardingStep, OnboardingSubStep, ALL_ONBOARDING_STEPS, ALL_ONBOARDING_SUB_STEPS, toOnboardingStepType, toOnboardingSubStepType, OnboardingCustomerViewUIState, OnboardingCustomerViewLocalData, OnboardingBusinessProfileUpdate, AiAgentsActivationCounts, AiAgentsActivationPhase, AiAgentsActivationPhaseStatus, AiAgentsActivationSubview, };
953
953
  export { saveAccountMapping, saveAccountMappingLocalData, clearAccountMappingLocalData, AccountMappingLocalData, AccountMappingView, VendorAccountMappingView, getAccountMappingView, initializeAccountMappingView, ExpenseCategory1099Filing, };
954
954
  export { MagicLinkView, getMagicLinkView, getMagicLinkBankAccountView, getMagicLinkCurrentAddressState, };
955
- export { fetchMagicLinkTenant, fetchBillAttachment, saveBankAccount, updateMagicLinkBankAccountLocalStoreData, updateMagicLinkInternationalBankAccountLocalStoreData, fetchMagicLinkBankNameByRouting, fetchMagicLinkBankNameBySwift, saveMagicLinkAddressInLocalStore, };
955
+ export { fetchMagicLinkTenant, updateMagicLinkTenantSuccess, updateMagicLinkTenantFailure, fetchBillAttachment, saveBankAccount, updateMagicLinkBankAccountLocalStoreData, updateMagicLinkInternationalBankAccountLocalStoreData, fetchMagicLinkBankNameByRouting, fetchMagicLinkBankNameBySwift, saveMagicLinkAddressInLocalStore, };
956
956
  export { getWiseRedirect, fetchWiseRedirectStatus };
957
957
  export { getInternationalWireView, InternationalWireSelectorView, DynamicFormField, CreateInternationalWireDetailsLocalData, SupportedAccountType, VendorCurrency, initializeInternationalWireLocalData, updateInternationalWireLocalStoreData, initializeDynamicForm, fetchInternationalWireDynamicForm, createPaymentInstrument, createPaymentInstrumentUpdateStatus, deletePaymentInstrument, clearInternationalWire, };
958
958
  export { fetchUserRoleConfig, getUserRoleConfig };
@@ -1002,12 +1002,12 @@ export { AiAccountantCustomerViewState, AiAccountantSortKey, AiAccountantUIState
1002
1002
  export { AiAccountantFilterCategoryField } from './view/companyView/types/cockpitTypes';
1003
1003
  export { cancelAiAccountantOnboarding, fetchAiAccountantCustomers, fetchAiAccountantJobs, setSelectedTenantIdsForJobTrigger, triggerAiAccountantJob, updateAiAccountantUIState, } from './view/aiAccountantView/aiAccountantViewReducer';
1004
1004
  export { AiAccountantCockpitView, getAiAccountantCockpitView, } from './view/aiAccountantView/aiAccountantViewSelector';
1005
- 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';
1005
+ 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, transcribeAudio, updateAiCfoViewScrollPosition, updateCotCollapsedState, updateCurrentInput, updateResponseState, } from './view/aiCfoView/aiCfoViewReducer';
1006
1006
  export { AiCfoViewState, AiCfoViewUIState, Routine, RoutineDraft, RoutineMutationState, RoutineRecurrence, RoutineRun, RoutineRunsState, RoutineRunStatus, RoutinesState, RoutineStatus, Skill, SkillDetail, SkillDetailState, SkillDraft, SkillMutationState, SkillsState, SkillVersion, SkillVersionBodyState, SkillVersionsState, SkillVisibility, SuggestedQuestionsForPageContext, } from './view/aiCfoView/aiCfoViewState';
1007
1007
  export { FetchSuggestedQuestionsResponse, SuggestedQuestionsDataPayload, FetchSkillsResponse, SkillSummaryPayload, SkillListDataPayload, } from './view/aiCfoView/aiCfoViewPayload';
1008
- export type { FeedbackType, SubmitFeedbackPayload, } from './view/aiCfoView/aiCfoViewPayload';
1008
+ export type { FeedbackType, SubmitFeedbackPayload, TranscribeAudioPayload, TranscriptionResponseData, } from './view/aiCfoView/aiCfoViewPayload';
1009
1009
  export type { AiCfoSuggestedQuestionsPageContext } from './common/aiCfo/aiCfoSuggestedQuestionsPageContext';
1010
- export { AiCfoViewSelector, canCreateRoutine, getAiCfoView, getRoutineMutation, getRoutineRuns, getRoutines, getRoutinesEnabled, getSkillDetail, getSkillMutation, getSkills, getSkillsEnabled, getSkillVersionBody, getSkillVersions, getSuggestedQuestionsForPageContext, } from './view/aiCfoView/aiCfoViewSelector';
1010
+ export { AiCfoViewSelector, canCreateRoutine, getAiCfoView, getIsTranscribing, getRoutineMutation, getRoutineRuns, getRoutines, getRoutinesEnabled, getSkillDetail, getSkillMutation, getSkills, getSkillsEnabled, getSkillVersionBody, getSkillVersions, getSuggestedQuestionsForPageContext, getTranscriptionFailed, } from './view/aiCfoView/aiCfoViewSelector';
1011
1011
  export { MessagePayload, ChatSessionPayload, AiCfoAnswerPayload, } from './entity/aiCfo/aiCfoPayload';
1012
1012
  export { setNewSession, setSessions, updateAiCfoAnswerCardPolicyWizardPlan, upsertAnswerPayload, upsertOrAddQuestionAnswerPayload, addQuestionPayload, clearSession, toAiCfoExports, toAiCfoVisualization, appendSyntheticAiCfoAnswer, updateSyntheticAiCfoAnswer, removeSyntheticAiCfoAnswer, } from './entity/aiCfo/aiCfoReducer';
1013
1013
  export { AiCfoSelectorView, getAllQuestionAnswersForChatSession, getQuestionAnswerByIdForChatSession, getAllQuestionsForChatSession, getAiCfoSelectorView, getSyntheticAiCfoAnswersForChatSession, getSyntheticAiCfoAnswerByQuestionAnswerId, ChatSessionWithOrderedQuestionAnswers, } from './entity/aiCfo/aiCfoSelector';