@zeniai/client-epic-state 5.1.15 → 5.1.16-betaRD1

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.
@@ -42,7 +42,7 @@ const tenantSelector = createSelector(getTenantsByCheckInDateSelector, getCurren
42
42
  export const getDashboard = createSelector(tenantSelector, getCardBalance, getCashBalance, getOperatingExpensesForLast5Periods, getRevenueForLast4Periods, getTop6Expenses, getNetBurnOrIncomeForLast4Periods, getNetBurnOrIncomeStoryCard, getCashPositionLast5Periods, getCashInCashOutLast4Periods, getInsights, getCompanyPassportView, getTasksCardReport, getBillPayCardReport, getReimbursementCardReport, apAgingSelector, arAgingSelector, getZeniAccountsPromoCard, getRewardsPlanCard, getDashboardCardsOrdered, (state) => {
43
43
  const currentTenant = getCurrentTenant(state);
44
44
  return getMonthEndCloseChecksViewByTenantId(state, currentTenant.tenantId);
45
- }, (state) => state.tenantState, (_state, additionalExcludedReports) => additionalExcludedReports, (_state, _additionalExcludedReports, signedInUser) => signedInUser, (_state, _excluded, _signedInUser, isExpenseAutomationFeatureEnabledV2) => isExpenseAutomationFeatureEnabledV2, (_state, _excluded, _signedInUser, _enabledV2, isExpenseAutomationFeatureEnabled) => isExpenseAutomationFeatureEnabled, (_state, _excluded, _signedInUser, _enabledV2, _enabled, isTreasuryFeatureEnabled) => isTreasuryFeatureEnabled, (state) => state.dashboardState.isTreasuryVideoClosed, (tenants, cardBalance, cashBalance, opEx, revenue, topEx, netBurnOrIncome, netBurnOrIncomeStoryCard, cashPosition, cashInCashOut, insightsView, companyPassportView, tasksCard, billPayCard, reimbursementCard, apAgingReport, arAgingReport, zeniAccountsPromoCard, rewardsPlanCard, cards, monthEndCloseChecksView, tenantState, additionalExcludedReports, signedInUser, isExpenseAutomationFeatureEnabledV2, isExpenseAutomationFeatureEnabled, isTreasuryFeatureEnabled, isTreasuryVideoClosed) => {
45
+ }, (state) => state.tenantState, (_state, additionalExcludedReports) => additionalExcludedReports, (_state, _additionalExcludedReports, signedInUser) => signedInUser, (_state, _excluded, _signedInUser, isExpenseAutomationFeatureEnabledV2) => isExpenseAutomationFeatureEnabledV2, (_state, _excluded, _signedInUser, _enabledV2, isExpenseAutomationFeatureEnabled) => isExpenseAutomationFeatureEnabled, (state) => state.dashboardState.isTreasuryVideoClosed, (tenants, cardBalance, cashBalance, opEx, revenue, topEx, netBurnOrIncome, netBurnOrIncomeStoryCard, cashPosition, cashInCashOut, insightsView, companyPassportView, tasksCard, billPayCard, reimbursementCard, apAgingReport, arAgingReport, zeniAccountsPromoCard, rewardsPlanCard, cards, monthEndCloseChecksView, tenantState, additionalExcludedReports, signedInUser, isExpenseAutomationFeatureEnabledV2, isExpenseAutomationFeatureEnabled, isTreasuryVideoClosed) => {
46
46
  const isReimbursementFeatureEnabled = tenants.currentTenant.company?.featuresActivationInfo
47
47
  .isReimbursementFeatureEnabled;
48
48
  const isBillPayFeatureEnabled = tenants.currentTenant.company?.featuresActivationInfo
@@ -153,23 +153,10 @@ export const getDashboard = createSelector(tenantSelector, getCardBalance, getCa
153
153
  cardsToRemove.add('bill_pay_card');
154
154
  cardsToRemove.add('reimbursement_card');
155
155
  }
156
- const showZeniAccountsPromoCard = zeniAccountsPromoCard.isShowDepositAccountsPromo === true;
157
- if (showZeniAccountsPromoCard) {
158
- cardsToRemove.add('bill_pay_promo_card');
159
- cardsToRemove.add('reimbursement_promo_card');
160
- }
161
- else {
162
- cardsToRemove.add('zeni_accounts_promo_card');
163
- }
164
- // remove treasury promo card if its already enabled
165
- const isTreasuryTOSAccepted = tenants.currentTenant.companyTreasuryInfo?.info?.isTreasuryTOSAccepted;
166
- if (isTreasuryTOSAccepted === true || isTreasuryFeatureEnabled === false) {
167
- cardsToRemove.add('treasury_promo_card');
168
- }
169
- // More than one promo card can't be shown on the dashboard (priority: Treasury > Accounts > Bill > Remi).
156
+ cardsToRemove.add('zeni_accounts_promo_card');
157
+ cardsToRemove.add('treasury_promo_card');
158
+ // More than one promo card can't be shown on the dashboard (priority: Bill > Remi).
170
159
  const PROMO_CARD_PRIORITY_ORDER = [
171
- 'treasury_promo_card',
172
- 'zeni_accounts_promo_card',
173
160
  'bill_pay_promo_card',
174
161
  'reimbursement_promo_card',
175
162
  ];
@@ -1,5 +1,5 @@
1
1
  import { from, of } from 'rxjs';
2
- import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
2
+ import { catchError, filter, groupBy, mergeMap, switchMap } from 'rxjs/operators';
3
3
  import { toString } from '../../../../commonStateTypes/timePeriod';
4
4
  import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
5
5
  import { updateTransactions } from '../../../../entity/transaction/transactionReducer';
@@ -8,7 +8,10 @@ import { getLineItemsByTransactionsIdsFromResponse } from '../../helpers/transac
8
8
  import { fetchTransactionCategorization, fetchTransactionCategorizationFailure, fetchTransactionCategorizationSuccess, initializeTransactionCategorizationViewLocalData, resetOtherTabsFetchState, updateParentTotalCountForTab, updateTotalCountForTransactionCategorization, updateTransactionCategorizationUIState, } from '../../reducers/transactionsViewReducer';
9
9
  import { DEFAULT_COMPLETED_SUB_TAB } from '../../types/completedSubTab';
10
10
  import { TRANSACTIONS_TABS, toTransactionsSortKey, } from '../../types/transactionsViewState';
11
- export const fetchTransactionCategorizationEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchTransactionCategorization.match), switchMap((action) => {
11
+ export const fetchTransactionCategorizationEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchTransactionCategorization.match),
12
+ // Per-tab switchMap: cancels in-flight requests for the same tab on a new
13
+ // request, but allows both tabs to fetch concurrently (e.g. dual search).
14
+ groupBy((action) => action.payload.selectedTab), mergeMap((group$) => group$.pipe(switchMap((action) => {
12
15
  const { expenseAutomationViewState: { selectedPeriodByTenantId }, expenseAutomationTransactionsViewState, } = state$.value;
13
16
  const { period, keepExistingListItems, selectedTab, refreshViewInBackground, } = action.payload;
14
17
  const uiState = expenseAutomationTransactionsViewState.transactionCategorizationView[selectedTab].uiState;
@@ -24,6 +27,10 @@ export const fetchTransactionCategorizationEpic = (actions$, state$, zeniAPI) =>
24
27
  page_token: pageToken,
25
28
  page_size: 25,
26
29
  search_text: uiState.searchString,
30
+ // Always scope to the active tab's auto_categorized status;
31
+ // cross-status search (omit or true) is reserved for Receipts
32
+ // manual-match.
33
+ search_all_statuses: false,
27
34
  sub_tab: selectedTab === 'autoCategorized'
28
35
  ? expenseAutomationTransactionsViewState.selectedTransactionCategorizationCompletedSubTab
29
36
  : DEFAULT_COMPLETED_SUB_TAB,
@@ -79,4 +86,4 @@ export const fetchTransactionCategorizationEpic = (actions$, state$, zeniAPI) =>
79
86
  status: createZeniAPIStatus('Unexpected Error', 'fetch Transaction Categorization REST API call errored out' +
80
87
  JSON.stringify(error)),
81
88
  }))));
82
- }));
89
+ }))));
@@ -7,6 +7,7 @@ import { fetchClassList } from '../../../classList/classListReducer';
7
7
  import { fetchOwnerList } from '../../../ownerList/ownerListReducer';
8
8
  import { fetchProjectList } from '../../../projectList/projectListReducer';
9
9
  import { fetchTransactionCategorization, fetchTransactionCategorizationView, } from '../../reducers/transactionsViewReducer';
10
+ import { TRANSACTIONS_TABS } from '../../types/transactionsViewState';
10
11
  export const fetchTransactionCategorizationViewEpic = (actions$, state$) => actions$.pipe(filter(fetchTransactionCategorizationView.match), mergeMap((action) => {
11
12
  const { selectedTab, cacheOverride, keepExistingListItems, pageToken, period, refreshViewInBackground, searchString, resetListItems, isUncategorizedExpenseCategoryEnabled, } = action.payload;
12
13
  const updateActions = [];
@@ -44,5 +45,20 @@ export const fetchTransactionCategorizationViewEpic = (actions$, state$) => acti
44
45
  transactionIds.length === 0) {
45
46
  updateActions.push(fetchTransactionCategorization(selectedTab, period, cacheOverride, keepExistingListItems, searchString, pageToken, refreshViewInBackground, resetListItems, isUncategorizedExpenseCategoryEnabled));
46
47
  }
48
+ // When search changes (searchString defined, including empty string to
49
+ // clear), also fetch every other tab so all tabs always reflect the same
50
+ // search query. Skip if the other tab already has this search string to
51
+ // avoid redundant requests on noop updates. cacheOverride=true bypasses
52
+ // the cache check; pageToken reset to undefined so the other tab starts
53
+ // from page 1; refreshViewInBackground=true because the user isn't
54
+ // looking at the other tab, so a silent background fetch is correct.
55
+ if (searchString !== undefined) {
56
+ TRANSACTIONS_TABS.filter((tab) => tab !== selectedTab).forEach((otherTab) => {
57
+ const otherTabSearchString = expenseAutomationTransactionsViewState.transactionCategorizationView[otherTab].uiState.searchString;
58
+ if (searchString !== otherTabSearchString) {
59
+ updateActions.push(fetchTransactionCategorization(otherTab, period, true, keepExistingListItems, searchString, undefined, true, true, isUncategorizedExpenseCategoryEnabled));
60
+ }
61
+ });
62
+ }
47
63
  return from(updateActions);
48
64
  }));
@@ -156,8 +156,12 @@ const expenseAutomationTransactionsView = createSlice({
156
156
  }
157
157
  draft.transactionCategorizationView[selectedTab].uiState.pageToken =
158
158
  pageToken ?? null;
159
- draft.transactionCategorizationView[selectedTab].uiState.searchString =
160
- searchString ?? '';
159
+ // Only overwrite when explicitly set; undefined means a non-search fetch
160
+ // (tab switch, period change) should preserve the existing search string.
161
+ if (searchString !== undefined) {
162
+ draft.transactionCategorizationView[selectedTab].uiState.searchString =
163
+ searchString;
164
+ }
161
165
  draft.transactionCategorizationView[selectedTab].error = undefined;
162
166
  // Reset list when we change the sort order and fetch list again
163
167
  if (resetListItems === true) {
@@ -305,10 +309,12 @@ const expenseAutomationTransactionsView = createSlice({
305
309
  }
306
310
  },
307
311
  updateTransactionFilters(draft, action) {
308
- const { selectedTab, filters } = action.payload;
309
- // `filters` is non-nullable per the payload type, so no runtime
310
- // null-check is needed dropping it removes a dead defensive branch.
311
- draft.transactionCategorizationView[selectedTab].filters = filters;
312
+ const { filters } = action.payload;
313
+ // Filters are tab-agnostic (payee/category/class/amount), so apply to
314
+ // all tabs so switching tabs after filtering shows consistent results.
315
+ TRANSACTIONS_TABS.forEach((tab) => {
316
+ draft.transactionCategorizationView[tab].filters = filters;
317
+ });
312
318
  },
313
319
  saveTransactionCategorization: {
314
320
  prepare(selectedTab, transactionIds, cotTrackingByTransactionId, isUncategorizedExpenseCategoryEnabled) {
@@ -12,4 +12,4 @@ export interface DashboardReport extends SelectorReport {
12
12
  currentTenant?: Tenant;
13
13
  }
14
14
  export declare const getDashboard: (state: RootState, additionalExcludedReports: ReportID[], // used when reports are excluded through statsig
15
- signedInUser: LoggedInUser | undefined, isExpenseAutomationFeatureEnabledV2: boolean, isExpenseAutomationFeatureEnabled: boolean, isTreasuryFeatureEnabled: boolean) => DashboardReport;
15
+ signedInUser: LoggedInUser | undefined, isExpenseAutomationFeatureEnabledV2: boolean, isExpenseAutomationFeatureEnabled: boolean) => DashboardReport;
@@ -45,7 +45,7 @@ const tenantSelector = (0, toolkit_1.createSelector)(tenantSelector_1.getTenants
45
45
  exports.getDashboard = (0, toolkit_1.createSelector)(tenantSelector, cardBalanceSelector_1.getCardBalance, cashBalanceSelector_1.getCashBalance, getOperatingExpensesForLast5Periods, getRevenueForLast4Periods, topExSelector_1.getTop6Expenses, getNetBurnOrIncomeForLast4Periods, getNetBurnOrIncomeStoryCard, getCashPositionLast5Periods, getCashInCashOutLast4Periods, insightsCardSelector_1.getInsights, companyPassportViewSelector_1.getCompanyPassportView, tasksCardSelector_1.getTasksCardReport, billPayCardSelector_1.getBillPayCardReport, reimbursementCardSelector_1.getReimbursementCardReport, apAgingSelector, arAgingSelector, zeniAccountsPromoCardSelector_1.getZeniAccountsPromoCard, referralSelector_1.getRewardsPlanCard, dashboardLayoutSelector_1.getDashboardCardsOrdered, (state) => {
46
46
  const currentTenant = (0, tenantSelector_1.getCurrentTenant)(state);
47
47
  return (0, monthEndCloseChecksViewSelector_1.getMonthEndCloseChecksViewByTenantId)(state, currentTenant.tenantId);
48
- }, (state) => state.tenantState, (_state, additionalExcludedReports) => additionalExcludedReports, (_state, _additionalExcludedReports, signedInUser) => signedInUser, (_state, _excluded, _signedInUser, isExpenseAutomationFeatureEnabledV2) => isExpenseAutomationFeatureEnabledV2, (_state, _excluded, _signedInUser, _enabledV2, isExpenseAutomationFeatureEnabled) => isExpenseAutomationFeatureEnabled, (_state, _excluded, _signedInUser, _enabledV2, _enabled, isTreasuryFeatureEnabled) => isTreasuryFeatureEnabled, (state) => state.dashboardState.isTreasuryVideoClosed, (tenants, cardBalance, cashBalance, opEx, revenue, topEx, netBurnOrIncome, netBurnOrIncomeStoryCard, cashPosition, cashInCashOut, insightsView, companyPassportView, tasksCard, billPayCard, reimbursementCard, apAgingReport, arAgingReport, zeniAccountsPromoCard, rewardsPlanCard, cards, monthEndCloseChecksView, tenantState, additionalExcludedReports, signedInUser, isExpenseAutomationFeatureEnabledV2, isExpenseAutomationFeatureEnabled, isTreasuryFeatureEnabled, isTreasuryVideoClosed) => {
48
+ }, (state) => state.tenantState, (_state, additionalExcludedReports) => additionalExcludedReports, (_state, _additionalExcludedReports, signedInUser) => signedInUser, (_state, _excluded, _signedInUser, isExpenseAutomationFeatureEnabledV2) => isExpenseAutomationFeatureEnabledV2, (_state, _excluded, _signedInUser, _enabledV2, isExpenseAutomationFeatureEnabled) => isExpenseAutomationFeatureEnabled, (state) => state.dashboardState.isTreasuryVideoClosed, (tenants, cardBalance, cashBalance, opEx, revenue, topEx, netBurnOrIncome, netBurnOrIncomeStoryCard, cashPosition, cashInCashOut, insightsView, companyPassportView, tasksCard, billPayCard, reimbursementCard, apAgingReport, arAgingReport, zeniAccountsPromoCard, rewardsPlanCard, cards, monthEndCloseChecksView, tenantState, additionalExcludedReports, signedInUser, isExpenseAutomationFeatureEnabledV2, isExpenseAutomationFeatureEnabled, isTreasuryVideoClosed) => {
49
49
  const isReimbursementFeatureEnabled = tenants.currentTenant.company?.featuresActivationInfo
50
50
  .isReimbursementFeatureEnabled;
51
51
  const isBillPayFeatureEnabled = tenants.currentTenant.company?.featuresActivationInfo
@@ -156,23 +156,10 @@ exports.getDashboard = (0, toolkit_1.createSelector)(tenantSelector, cardBalance
156
156
  cardsToRemove.add('bill_pay_card');
157
157
  cardsToRemove.add('reimbursement_card');
158
158
  }
159
- const showZeniAccountsPromoCard = zeniAccountsPromoCard.isShowDepositAccountsPromo === true;
160
- if (showZeniAccountsPromoCard) {
161
- cardsToRemove.add('bill_pay_promo_card');
162
- cardsToRemove.add('reimbursement_promo_card');
163
- }
164
- else {
165
- cardsToRemove.add('zeni_accounts_promo_card');
166
- }
167
- // remove treasury promo card if its already enabled
168
- const isTreasuryTOSAccepted = tenants.currentTenant.companyTreasuryInfo?.info?.isTreasuryTOSAccepted;
169
- if (isTreasuryTOSAccepted === true || isTreasuryFeatureEnabled === false) {
170
- cardsToRemove.add('treasury_promo_card');
171
- }
172
- // More than one promo card can't be shown on the dashboard (priority: Treasury > Accounts > Bill > Remi).
159
+ cardsToRemove.add('zeni_accounts_promo_card');
160
+ cardsToRemove.add('treasury_promo_card');
161
+ // More than one promo card can't be shown on the dashboard (priority: Bill > Remi).
173
162
  const PROMO_CARD_PRIORITY_ORDER = [
174
- 'treasury_promo_card',
175
- 'zeni_accounts_promo_card',
176
163
  'bill_pay_promo_card',
177
164
  'reimbursement_promo_card',
178
165
  ];
@@ -11,7 +11,10 @@ const transactionCategorizationLocalDataHelper_1 = require("../../helpers/transa
11
11
  const transactionsViewReducer_1 = require("../../reducers/transactionsViewReducer");
12
12
  const completedSubTab_1 = require("../../types/completedSubTab");
13
13
  const transactionsViewState_1 = require("../../types/transactionsViewState");
14
- const fetchTransactionCategorizationEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(transactionsViewReducer_1.fetchTransactionCategorization.match), (0, operators_1.switchMap)((action) => {
14
+ const fetchTransactionCategorizationEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(transactionsViewReducer_1.fetchTransactionCategorization.match),
15
+ // Per-tab switchMap: cancels in-flight requests for the same tab on a new
16
+ // request, but allows both tabs to fetch concurrently (e.g. dual search).
17
+ (0, operators_1.groupBy)((action) => action.payload.selectedTab), (0, operators_1.mergeMap)((group$) => group$.pipe((0, operators_1.switchMap)((action) => {
15
18
  const { expenseAutomationViewState: { selectedPeriodByTenantId }, expenseAutomationTransactionsViewState, } = state$.value;
16
19
  const { period, keepExistingListItems, selectedTab, refreshViewInBackground, } = action.payload;
17
20
  const uiState = expenseAutomationTransactionsViewState.transactionCategorizationView[selectedTab].uiState;
@@ -27,6 +30,10 @@ const fetchTransactionCategorizationEpic = (actions$, state$, zeniAPI) => action
27
30
  page_token: pageToken,
28
31
  page_size: 25,
29
32
  search_text: uiState.searchString,
33
+ // Always scope to the active tab's auto_categorized status;
34
+ // cross-status search (omit or true) is reserved for Receipts
35
+ // manual-match.
36
+ search_all_statuses: false,
30
37
  sub_tab: selectedTab === 'autoCategorized'
31
38
  ? expenseAutomationTransactionsViewState.selectedTransactionCategorizationCompletedSubTab
32
39
  : completedSubTab_1.DEFAULT_COMPLETED_SUB_TAB,
@@ -82,5 +89,5 @@ const fetchTransactionCategorizationEpic = (actions$, state$, zeniAPI) => action
82
89
  status: (0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', 'fetch Transaction Categorization REST API call errored out' +
83
90
  JSON.stringify(error)),
84
91
  }))));
85
- }));
92
+ }))));
86
93
  exports.fetchTransactionCategorizationEpic = fetchTransactionCategorizationEpic;
@@ -10,6 +10,7 @@ const classListReducer_1 = require("../../../classList/classListReducer");
10
10
  const ownerListReducer_1 = require("../../../ownerList/ownerListReducer");
11
11
  const projectListReducer_1 = require("../../../projectList/projectListReducer");
12
12
  const transactionsViewReducer_1 = require("../../reducers/transactionsViewReducer");
13
+ const transactionsViewState_1 = require("../../types/transactionsViewState");
13
14
  const fetchTransactionCategorizationViewEpic = (actions$, state$) => actions$.pipe((0, operators_1.filter)(transactionsViewReducer_1.fetchTransactionCategorizationView.match), (0, operators_1.mergeMap)((action) => {
14
15
  const { selectedTab, cacheOverride, keepExistingListItems, pageToken, period, refreshViewInBackground, searchString, resetListItems, isUncategorizedExpenseCategoryEnabled, } = action.payload;
15
16
  const updateActions = [];
@@ -47,6 +48,21 @@ const fetchTransactionCategorizationViewEpic = (actions$, state$) => actions$.pi
47
48
  transactionIds.length === 0) {
48
49
  updateActions.push((0, transactionsViewReducer_1.fetchTransactionCategorization)(selectedTab, period, cacheOverride, keepExistingListItems, searchString, pageToken, refreshViewInBackground, resetListItems, isUncategorizedExpenseCategoryEnabled));
49
50
  }
51
+ // When search changes (searchString defined, including empty string to
52
+ // clear), also fetch every other tab so all tabs always reflect the same
53
+ // search query. Skip if the other tab already has this search string to
54
+ // avoid redundant requests on noop updates. cacheOverride=true bypasses
55
+ // the cache check; pageToken reset to undefined so the other tab starts
56
+ // from page 1; refreshViewInBackground=true because the user isn't
57
+ // looking at the other tab, so a silent background fetch is correct.
58
+ if (searchString !== undefined) {
59
+ transactionsViewState_1.TRANSACTIONS_TABS.filter((tab) => tab !== selectedTab).forEach((otherTab) => {
60
+ const otherTabSearchString = expenseAutomationTransactionsViewState.transactionCategorizationView[otherTab].uiState.searchString;
61
+ if (searchString !== otherTabSearchString) {
62
+ updateActions.push((0, transactionsViewReducer_1.fetchTransactionCategorization)(otherTab, period, true, keepExistingListItems, searchString, undefined, true, true, isUncategorizedExpenseCategoryEnabled));
63
+ }
64
+ });
65
+ }
50
66
  return (0, rxjs_1.from)(updateActions);
51
67
  }));
52
68
  exports.fetchTransactionCategorizationViewEpic = fetchTransactionCategorizationViewEpic;
@@ -19,6 +19,13 @@ export interface TransactionCategorizationQueryPayload {
19
19
  * on the backend.
20
20
  */
21
21
  sub_tab: CompletedSubTab;
22
+ /**
23
+ * When `false`, the backend scopes the search to the active tab's
24
+ * categorization status (respects `auto_categorized`). When `true` or
25
+ * omitted, the backend searches across all statuses — the legacy behaviour
26
+ * that the Receipts manual-match flow relies on.
27
+ */
28
+ search_all_statuses?: boolean;
22
29
  }
23
30
  export interface TransactionCategorizationPayload {
24
31
  next_page_token: string | null;
@@ -163,8 +163,12 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
163
163
  }
164
164
  draft.transactionCategorizationView[selectedTab].uiState.pageToken =
165
165
  pageToken ?? null;
166
- draft.transactionCategorizationView[selectedTab].uiState.searchString =
167
- searchString ?? '';
166
+ // Only overwrite when explicitly set; undefined means a non-search fetch
167
+ // (tab switch, period change) should preserve the existing search string.
168
+ if (searchString !== undefined) {
169
+ draft.transactionCategorizationView[selectedTab].uiState.searchString =
170
+ searchString;
171
+ }
168
172
  draft.transactionCategorizationView[selectedTab].error = undefined;
169
173
  // Reset list when we change the sort order and fetch list again
170
174
  if (resetListItems === true) {
@@ -312,10 +316,12 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
312
316
  }
313
317
  },
314
318
  updateTransactionFilters(draft, action) {
315
- const { selectedTab, filters } = action.payload;
316
- // `filters` is non-nullable per the payload type, so no runtime
317
- // null-check is needed dropping it removes a dead defensive branch.
318
- draft.transactionCategorizationView[selectedTab].filters = filters;
319
+ const { filters } = action.payload;
320
+ // Filters are tab-agnostic (payee/category/class/amount), so apply to
321
+ // all tabs so switching tabs after filtering shows consistent results.
322
+ transactionsViewState_1.TRANSACTIONS_TABS.forEach((tab) => {
323
+ draft.transactionCategorizationView[tab].filters = filters;
324
+ });
319
325
  },
320
326
  saveTransactionCategorization: {
321
327
  prepare(selectedTab, transactionIds, cotTrackingByTransactionId, isUncategorizedExpenseCategoryEnabled) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeniai/client-epic-state",
3
- "version": "5.1.15",
3
+ "version": "5.1.16-betaRD1",
4
4
  "description": "Shared module between Web & Mobile containing required abstractions for state management, async network communication. ",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/esm/index.js",