@zeniai/client-epic-state 5.0.72 → 5.0.74

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 (163) hide show
  1. package/lib/commonStateTypes/cacheOverrideFetchReducer.d.ts +17 -0
  2. package/lib/commonStateTypes/cacheOverrideFetchReducer.js +20 -0
  3. package/lib/commonStateTypes/filterPrimitives.d.ts +23 -0
  4. package/lib/commonStateTypes/filterPrimitives.js +21 -0
  5. package/lib/commonStateTypes/pusherActions.d.ts +11 -0
  6. package/lib/commonStateTypes/pusherActions.js +6 -0
  7. package/lib/coreEpics.js +1 -1
  8. package/lib/entity/account/accountSelector.d.ts +27 -1
  9. package/lib/entity/account/accountSelector.js +47 -1
  10. package/lib/entity/account/accountState.d.ts +6 -1
  11. package/lib/entity/account/accountState.js +11 -4
  12. package/lib/entity/account/subAccountSelector.d.ts +1 -1
  13. package/lib/entity/aiAccountantCustomer/aiAccountantCustomerPayload.js +1 -3
  14. package/lib/entity/aiAccountantCustomer/aiAccountantCustomerReducer.js +1 -2
  15. package/lib/entity/aiAccountantCustomer/aiAccountantCustomerSelector.d.ts +1 -1
  16. package/lib/entity/chargeCard/chargeCardReducer.d.ts +19 -2
  17. package/lib/entity/chargeCard/chargeCardReducer.js +35 -2
  18. package/lib/entity/chargeCardTransaction/chargeCardTransactionReducer.d.ts +14 -1
  19. package/lib/entity/chargeCardTransaction/chargeCardTransactionReducer.js +36 -2
  20. package/lib/entity/class/classSelector.d.ts +35 -0
  21. package/lib/entity/class/classSelector.js +50 -0
  22. package/lib/entity/monthEndCloseChecks/monthEndCloseChecksPayload.d.ts +2 -0
  23. package/lib/entity/monthEndCloseChecks/monthEndCloseChecksPayload.js +2 -0
  24. package/lib/entity/monthEndCloseChecks/monthEndCloseChecksState.d.ts +2 -0
  25. package/lib/entity/sectionProjectView/sectionProjectViewReducer.d.ts +1 -1
  26. package/lib/entity/sectionProjectView/sectionProjectViewSelector.js +1 -1
  27. package/lib/entity/tenant/SessionManager.js +6 -3
  28. package/lib/entity/tenant/clearAllEpic.d.ts +2 -2
  29. package/lib/entity/tenant/clearAllEpic.js +2 -2
  30. package/lib/entity/tenant/epic/saveAPIKeyConnectionEpic.js +6 -2
  31. package/lib/entity/tenant/epic/saveOAuthConnectionEpic.js +6 -2
  32. package/lib/entity/tenant/tenantReducer.js +6 -1
  33. package/lib/entity/transaction/payloadTypes/transactionLinePayload.js +3 -1
  34. package/lib/epic.d.ts +9 -9
  35. package/lib/epic.js +10 -10
  36. package/lib/esm/commonStateTypes/cacheOverrideFetchReducer.js +16 -0
  37. package/lib/esm/commonStateTypes/filterPrimitives.js +20 -0
  38. package/lib/esm/commonStateTypes/pusherActions.js +3 -0
  39. package/lib/esm/coreEpics.js +1 -1
  40. package/lib/esm/entity/account/accountSelector.js +46 -1
  41. package/lib/esm/entity/account/accountState.js +7 -1
  42. package/lib/esm/entity/aiAccountantCustomer/aiAccountantCustomerPayload.js +1 -3
  43. package/lib/esm/entity/aiAccountantCustomer/aiAccountantCustomerReducer.js +1 -2
  44. package/lib/esm/entity/chargeCard/chargeCardReducer.js +34 -1
  45. package/lib/esm/entity/chargeCardTransaction/chargeCardTransactionReducer.js +35 -1
  46. package/lib/esm/entity/class/classSelector.js +48 -0
  47. package/lib/esm/entity/monthEndCloseChecks/monthEndCloseChecksPayload.js +2 -0
  48. package/lib/esm/entity/sectionProjectView/sectionProjectViewSelector.js +1 -1
  49. package/lib/esm/entity/tenant/SessionManager.js +4 -1
  50. package/lib/esm/entity/tenant/clearAllEpic.js +2 -2
  51. package/lib/esm/entity/tenant/epic/saveAPIKeyConnectionEpic.js +6 -2
  52. package/lib/esm/entity/tenant/epic/saveOAuthConnectionEpic.js +6 -2
  53. package/lib/esm/entity/tenant/tenantReducer.js +6 -1
  54. package/lib/esm/entity/transaction/payloadTypes/transactionLinePayload.js +3 -1
  55. package/lib/esm/epic.js +10 -10
  56. package/lib/esm/index.js +26 -16
  57. package/lib/esm/reducer.js +2 -2
  58. package/lib/esm/view/aiAccountantView/epics/fetchAiAccountantCustomersEpic.js +2 -5
  59. package/lib/esm/view/aiAccountantView/epics/fetchAiAccountantJobsEpic.js +2 -5
  60. package/lib/esm/view/aiAccountantView/epics/triggerAiAccountantJobEpic.js +4 -1
  61. package/lib/esm/view/companyHealthMetricView/companyHealthMetricViewSelector.js +1 -1
  62. package/lib/esm/view/companyTaskManagerView/companyTaskManagerViewSelector.js +1 -1
  63. package/lib/esm/view/companyTaskManagerView/epics/fetchTaskManagerMetricsEpic.js +1 -1
  64. package/lib/esm/view/companyView/helpers/cockpitHelpers.js +1 -1
  65. package/lib/esm/view/companyView/selector/companyManagementViewSelector.js +1 -1
  66. package/lib/esm/view/companyView/selector/companyPortfolioViewSelector.js +1 -1
  67. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchesEpic.js +2 -2
  68. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchCompletedTransactionsEpic.js +2 -1
  69. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/restoreBulkUploadAutomatchingOnMountEpic.js +8 -6
  70. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.js +7 -1
  71. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +11 -1
  72. package/lib/esm/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +2 -1
  73. package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +137 -1
  74. package/lib/esm/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +89 -13
  75. package/lib/esm/view/expenseAutomationView/transactionFilterHelpers.js +258 -0
  76. package/lib/esm/view/expenseAutomationView/types/completedSubTab.js +17 -0
  77. package/lib/esm/view/expenseAutomationView/types/missingReceiptsViewState.js +0 -2
  78. package/lib/esm/view/financeStatement/financeStatementSelector.js +1 -1
  79. package/lib/esm/view/spendManagement/chargeCards/cashbackDetail/cashbackDetailReducer.js +3 -2
  80. package/lib/esm/view/spendManagement/chargeCards/chargeCardConfig/chargeCardConfigReducer.js +3 -2
  81. package/lib/esm/view/spendManagement/chargeCards/chargeCardDetail/chargeCardDetailReducer.js +55 -18
  82. package/lib/esm/view/spendManagement/chargeCards/chargeCardDetail/fetchChargeCardDetailEpic.js +16 -2
  83. package/lib/esm/view/spendManagement/chargeCards/chargeCardDetail/fetchChargeCardDetailPageEpic.js +5 -4
  84. package/lib/esm/view/spendManagement/chargeCards/chargeCardList/chargeCardListReducer.js +26 -9
  85. package/lib/esm/view/spendManagement/chargeCards/chargeCardList/fetchChargeCardListPageEpic.js +9 -6
  86. package/lib/esm/view/spendManagement/chargeCards/chargeCardPaymentHistory/chargeCardPaymentHistoryReducer.js +3 -2
  87. package/lib/esm/view/spendManagement/chargeCards/chargeCardPaymentHistory/fetchChargeCardPaymentPageEpic.js +1 -1
  88. package/lib/esm/view/spendManagement/chargeCards/chargeCardRepaymentDetail/chargeCardRepaymentDetailReducer.js +7 -3
  89. package/lib/esm/view/spendManagement/spendManagementFilterHelpers.js +4 -2
  90. package/lib/esm/view/subscriptionView/subscriptionViewSelector.js +1 -1
  91. package/lib/esm/view/taskManager/cannedResponsesView/epics/fetchCannedResponsesEpic.js +1 -1
  92. package/lib/esm/view/taskManager/cannedResponsesView/epics/saveCannedResponseEpic.js +1 -1
  93. package/lib/esm/view/taskManager/taskDetailView/epics/unsnoozeTaskEpic.js +1 -1
  94. package/lib/esm/view/taskManager/taskListView/taskListReducer.js +1 -1
  95. package/lib/esm/view/transactionDetail/transactionDetailSelector.js +7 -1
  96. package/lib/index.d.ts +25 -19
  97. package/lib/index.js +81 -58
  98. package/lib/reducer.d.ts +2 -2
  99. package/lib/reducer.js +2 -2
  100. package/lib/view/aiAccountantView/aiAccountantViewPayload.d.ts +2 -2
  101. package/lib/view/aiAccountantView/aiAccountantViewReducer.d.ts +1 -1
  102. package/lib/view/aiAccountantView/epics/fetchAiAccountantCustomersEpic.js +2 -5
  103. package/lib/view/aiAccountantView/epics/fetchAiAccountantJobsEpic.js +2 -5
  104. package/lib/view/aiAccountantView/epics/triggerAiAccountantJobEpic.js +4 -1
  105. package/lib/view/companyHealthMetricView/companyHealthMetricViewSelector.js +1 -1
  106. package/lib/view/companyTaskManagerView/companyTaskManagerViewSelector.d.ts +1 -1
  107. package/lib/view/companyTaskManagerView/companyTaskManagerViewSelector.js +1 -1
  108. package/lib/view/companyView/helpers/cockpitHelpers.js +1 -1
  109. package/lib/view/companyView/selector/companyManagementViewSelector.js +1 -1
  110. package/lib/view/companyView/selector/companyPortfolioViewSelector.js +1 -1
  111. package/lib/view/companyView/types/cockpitTypes.d.ts +1 -1
  112. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchesEpic.js +2 -2
  113. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchCompletedTransactionsEpic.js +2 -1
  114. package/lib/view/expenseAutomationView/epics/missingReceipts/restoreBulkUploadAutomatchingOnMountEpic.js +8 -6
  115. package/lib/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.js +7 -1
  116. package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.d.ts +2 -2
  117. package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +10 -0
  118. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
  119. package/lib/view/expenseAutomationView/payload/transactionCategorizationPayload.d.ts +21 -0
  120. package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.d.ts +2 -1
  121. package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +2 -1
  122. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.d.ts +14 -4
  123. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +138 -2
  124. package/lib/view/expenseAutomationView/selectorTypes/missingReceiptsSelectorTypes.d.ts +2 -1
  125. package/lib/view/expenseAutomationView/selectorTypes/transactionsViewSelectorTypes.d.ts +14 -0
  126. package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.d.ts +4 -1
  127. package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +91 -13
  128. package/lib/view/expenseAutomationView/transactionFilterHelpers.d.ts +66 -0
  129. package/lib/view/expenseAutomationView/transactionFilterHelpers.js +262 -0
  130. package/lib/view/expenseAutomationView/types/completedSubTab.d.ts +10 -0
  131. package/lib/view/expenseAutomationView/types/completedSubTab.js +21 -0
  132. package/lib/view/expenseAutomationView/types/missingReceiptsViewState.d.ts +1 -2
  133. package/lib/view/expenseAutomationView/types/missingReceiptsViewState.js +1 -4
  134. package/lib/view/expenseAutomationView/types/transactionsViewState.d.ts +43 -2
  135. package/lib/view/financeStatement/financeStatementSelector.js +1 -1
  136. package/lib/view/profitAndLossProjectView/profitAndLossProjectViewSelectorTypes.d.ts +1 -1
  137. package/lib/view/spendManagement/billPay/billList/billListState.d.ts +1 -1
  138. package/lib/view/spendManagement/chargeCards/cashbackDetail/cashbackDetailReducer.d.ts +3 -1
  139. package/lib/view/spendManagement/chargeCards/cashbackDetail/cashbackDetailReducer.js +3 -2
  140. package/lib/view/spendManagement/chargeCards/chargeCardConfig/chargeCardConfigReducer.d.ts +3 -1
  141. package/lib/view/spendManagement/chargeCards/chargeCardConfig/chargeCardConfigReducer.js +3 -2
  142. package/lib/view/spendManagement/chargeCards/chargeCardDetail/chargeCardDetailReducer.js +55 -18
  143. package/lib/view/spendManagement/chargeCards/chargeCardDetail/fetchChargeCardDetailEpic.js +16 -2
  144. package/lib/view/spendManagement/chargeCards/chargeCardDetail/fetchChargeCardDetailPageEpic.js +5 -4
  145. package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardListReducer.d.ts +18 -3
  146. package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardListReducer.js +27 -10
  147. package/lib/view/spendManagement/chargeCards/chargeCardList/fetchChargeCardListPageEpic.js +9 -6
  148. package/lib/view/spendManagement/chargeCards/chargeCardPaymentHistory/chargeCardPaymentHistory.d.ts +1 -1
  149. package/lib/view/spendManagement/chargeCards/chargeCardPaymentHistory/chargeCardPaymentHistoryReducer.d.ts +3 -1
  150. package/lib/view/spendManagement/chargeCards/chargeCardPaymentHistory/chargeCardPaymentHistoryReducer.js +3 -2
  151. package/lib/view/spendManagement/chargeCards/chargeCardPaymentHistory/fetchChargeCardPaymentPageEpic.js +1 -1
  152. package/lib/view/spendManagement/chargeCards/chargeCardRepaymentDetail/chargeCardRepaymentDetailReducer.d.ts +3 -1
  153. package/lib/view/spendManagement/chargeCards/chargeCardRepaymentDetail/chargeCardRepaymentDetailReducer.js +7 -3
  154. package/lib/view/spendManagement/reimbursement/remiListView/remiListState.d.ts +1 -1
  155. package/lib/view/spendManagement/spendManagementFilterHelpers.d.ts +12 -3
  156. package/lib/view/spendManagement/spendManagementFilterHelpers.js +4 -2
  157. package/lib/view/subscriptionView/subscriptionViewSelector.js +1 -1
  158. package/lib/view/taskManager/taskListView/taskList.d.ts +1 -1
  159. package/lib/view/taskManager/taskListView/taskListReducer.js +1 -1
  160. package/lib/view/transactionDetail/transactionDetailSelector.js +7 -1
  161. package/lib/view/zeniOAuthView/zeniOAuthSelector.d.ts +1 -1
  162. package/package.json +9 -4
  163. package/lib/tsconfig.typecheck.tsbuildinfo +0 -1
@@ -4,13 +4,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  var _a;
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.uploadTransactionCategorizationReceiptSuccess = exports.updateTransactionCategorizationUploadReceiptState = exports.backgroundRefetchReviewTab = exports.syncTransactionCategorizationFromDetailSave = exports.updateSelectedTransactionId = exports.setEntityRecommendationForLineIdsForCategorization = exports.clearExpenseAutomationTransactionsView = exports.clearExpenseAutomationTransactionsViewPerTabView = exports.updateSelectedCheckboxTransactionIds = exports.fetchTransactionCategorizationView = exports.resetOtherTabsFetchState = exports.fetchTransactionCategorizationSuccess = exports.updateTotalCountForTransactionCategorization = exports.setAllItemsToCategoryClassInLocalDataForCategorization = exports.updateSelectedCustomerForTransaction = exports.updateSelectedVendorForTransaction = exports.updateStatusForTransactionNotMiscategorizedUpdateForCategorization = exports.markTransactionAsNotMiscategorized = exports.updateTransactionCategorizationSaveStatus = exports.updateCurrentSelectedTransactionCategorizationTab = exports.updateTransactionCategorization = exports.saveTransactionCategorization = exports.fetchTransactionCategorizationFailure = exports.saveTransactionCategorizationLocalData = exports.initializeTransactionCategorizationViewLocalData = exports.updateTransactionCategorizationUIState = exports.fetchTransactionCategorization = exports.initialState = exports.initialTransactionTabViewState = void 0;
7
+ exports.uploadTransactionCategorizationReceiptSuccess = exports.updateTransactionCategorizationUploadReceiptState = exports.backgroundRefetchReviewTab = exports.syncTransactionCategorizationFromDetailSave = exports.updateSelectedTransactionId = exports.setEntityRecommendationForLineIdsForCategorization = exports.clearExpenseAutomationTransactionsView = exports.clearExpenseAutomationTransactionsViewPerTabView = exports.updateSelectedCheckboxTransactionIds = exports.fetchTransactionCategorizationView = exports.resetOtherTabsFetchState = exports.fetchTransactionCategorizationSuccess = exports.updateParentTotalCountForTab = exports.updateTotalCountForTransactionCategorization = exports.setAllItemsToCategoryClassInLocalDataForCategorization = exports.updateSelectedCustomerForTransaction = exports.updateSelectedVendorForTransaction = exports.updateStatusForTransactionNotMiscategorizedUpdateForCategorization = exports.markTransactionAsNotMiscategorized = exports.updateTransactionCategorizationSaveStatus = exports.updateTransactionCategorizationCompletedSubTab = exports.updateCurrentSelectedTransactionCategorizationTab = exports.updateTransactionCategorization = exports.saveTransactionCategorization = exports.fetchTransactionCategorizationFailure = exports.saveTransactionCategorizationLocalData = exports.initializeTransactionCategorizationViewLocalData = exports.updateTransactionFilters = exports.updateTransactionCategorizationUIState = exports.fetchTransactionCategorization = exports.initialState = exports.initialTransactionTabViewState = void 0;
8
8
  const toolkit_1 = require("@reduxjs/toolkit");
9
9
  const get_1 = __importDefault(require("lodash/get"));
10
10
  const uniq_1 = __importDefault(require("lodash/uniq"));
11
11
  const timePeriod_1 = require("../../../commonStateTypes/timePeriod");
12
12
  const vendorTransaction_1 = require("../../../entity/transaction/stateTypes/vendorTransaction");
13
13
  const transactionCategorizationLocalDataHelper_1 = require("../helpers/transactionCategorizationLocalDataHelper");
14
+ const completedSubTab_1 = require("../types/completedSubTab");
14
15
  exports.initialTransactionTabViewState = {
15
16
  saveStatus: {
16
17
  fetchState: 'Not-Started',
@@ -34,6 +35,10 @@ exports.initialTransactionTabViewState = {
34
35
  totalCount: {},
35
36
  limit: 10,
36
37
  },
38
+ filters: {
39
+ categoryCombinationOperator: 'AND',
40
+ categories: [],
41
+ },
37
42
  fetchState: 'Not-Started',
38
43
  error: undefined,
39
44
  hasValidState() {
@@ -48,12 +53,74 @@ exports.initialTransactionTabViewState = {
48
53
  selectedTransactionLineId: undefined,
49
54
  };
50
55
  exports.initialState = {
56
+ autoCategorizedSubTabCache: {},
57
+ parentTotalCountByTab: {
58
+ review: {},
59
+ autoCategorized: {},
60
+ },
51
61
  selectedTransactionCategorizationTab: 'review',
62
+ selectedTransactionCategorizationCompletedSubTab: completedSubTab_1.DEFAULT_COMPLETED_SUB_TAB,
52
63
  transactionCategorizationView: {
53
64
  review: { ...exports.initialTransactionTabViewState },
54
65
  autoCategorized: { ...exports.initialTransactionTabViewState },
55
66
  },
56
67
  };
68
+ /**
69
+ * Capture the autoCategorized tab's current paginated dataset for a sub-tab.
70
+ * The mid-flight `'In-Progress'` state is normalised to `'Completed'` because
71
+ * the in-flight request is cancelled by `switchMap` in the fetch epic when the
72
+ * sub-tab changes — restoring `'In-Progress'` later would leave the UI stuck
73
+ * showing a phantom loading state with no fetch actually running. Length-zero
74
+ * datasets degrade to `'Not-Started'` so the next visit triggers a fresh
75
+ * fetch from page 1 instead of short-circuiting on stale empty caches.
76
+ *
77
+ * Snapshot scope (deliberately narrow):
78
+ * - Captured: `pageToken`, `totalCount`, `transactionIdsBySelectedPeriod`,
79
+ * `fetchState`, `error`, `scrollPosition`. The first five are the keys the
80
+ * fetch epic's cache check reads to decide whether to short-circuit a
81
+ * sub-tab revisit; `scrollPosition` is captured per sub-tab so revisiting
82
+ * restores the user's last offset and switching to a never-visited sub-tab
83
+ * starts at the top instead of inheriting the outgoing sub-tab's offset
84
+ * (which would land the user at a meaningless row index against a
85
+ * completely different list).
86
+ * - Intentionally NOT captured (left in place on `autoCat` and inherited by
87
+ * the incoming sub-tab):
88
+ * - `uiState.searchString`, `uiState.sortKey`, `uiState.sortOrder`,
89
+ * `uiState.nodeCollapseState`, `uiState.limit` — search and sort are
90
+ * user-applied preferences that persist across sub-tabs by design (a
91
+ * search query stays active when the user toggles between Manual / AI
92
+ * Accountant).
93
+ * - `selectedCheckBoxTransactionIds` — selection state is intentionally
94
+ * cleared at the action source (the fetch epic / save flow), not
95
+ * by the snapshot path. Carrying selection across sub-tabs is safe
96
+ * because every sub-tab change goes through a fetch round-trip that
97
+ * reconciles selection against the new row IDs.
98
+ * - `transactionReviewLocalDataById`, `transactionIdsWithUnsavedData`,
99
+ * `uploadReceiptStatusById`, `saveStatus`, `refreshStatus`,
100
+ * `markAsNotMiscategorizedStatus` — these are per-row / per-flight
101
+ * caches that are write-through global state, not sub-tab-scoped.
102
+ *
103
+ * If the contract changes (e.g. selection should reset on every sub-tab
104
+ * switch), update both this comment and the snapshot return shape together.
105
+ */
106
+ function snapshotAutoCategorizedTab(autoCat) {
107
+ const transactionIdsBySelectedPeriod = {
108
+ ...autoCat.transactionIdsBySelectedPeriod,
109
+ };
110
+ const hasAnyLoadedRows = Object.values(transactionIdsBySelectedPeriod).some((ids) => ids.length > 0);
111
+ let normalisedFetchState = autoCat.fetchState;
112
+ if (normalisedFetchState === 'In-Progress') {
113
+ normalisedFetchState = hasAnyLoadedRows ? 'Completed' : 'Not-Started';
114
+ }
115
+ return {
116
+ error: autoCat.error,
117
+ fetchState: normalisedFetchState,
118
+ pageToken: autoCat.uiState.pageToken,
119
+ scrollPosition: autoCat.uiState.scrollPosition,
120
+ totalCount: { ...autoCat.uiState.totalCount },
121
+ transactionIdsBySelectedPeriod,
122
+ };
123
+ }
57
124
  const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
58
125
  name: 'expenseAutomationTransactionsView',
59
126
  initialState: exports.initialState,
@@ -243,6 +310,12 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
243
310
  uiState.totalCount;
244
311
  }
245
312
  },
313
+ updateTransactionFilters(draft, action) {
314
+ const { selectedTab, filters } = action.payload;
315
+ // `filters` is non-nullable per the payload type, so no runtime
316
+ // null-check is needed — dropping it removes a dead defensive branch.
317
+ draft.transactionCategorizationView[selectedTab].filters = filters;
318
+ },
246
319
  saveTransactionCategorization: {
247
320
  prepare(selectedTab, transactionIds, cotTrackingByTransactionId, isUncategorizedExpenseCategoryEnabled) {
248
321
  return {
@@ -267,6 +340,55 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
267
340
  return { payload: { newSelectedTab } };
268
341
  },
269
342
  },
343
+ updateTransactionCategorizationCompletedSubTab: {
344
+ reducer(draft, action) {
345
+ const { newSubTab } = action.payload;
346
+ const previousSubTab = draft.selectedTransactionCategorizationCompletedSubTab;
347
+ if (previousSubTab === newSubTab) {
348
+ return;
349
+ }
350
+ const autoCat = draft.transactionCategorizationView.autoCategorized;
351
+ // Snapshot the outgoing sub-tab so a future revisit can short-circuit
352
+ // the fetch epic (mirrors the parent-tab "don't refetch what's
353
+ // already cached" behaviour). Period-scoped data is preserved as-is
354
+ // because the snapshot itself is keyed only by sub-tab; the active
355
+ // tab's per-period maps remain the source of truth while live.
356
+ draft.autoCategorizedSubTabCache[previousSubTab] =
357
+ snapshotAutoCategorizedTab(autoCat);
358
+ const cached = draft.autoCategorizedSubTabCache[newSubTab];
359
+ if (cached != null) {
360
+ autoCat.uiState.pageToken = cached.pageToken;
361
+ autoCat.uiState.totalCount = { ...cached.totalCount };
362
+ autoCat.uiState.scrollPosition = cached.scrollPosition;
363
+ autoCat.transactionIdsBySelectedPeriod = {
364
+ ...cached.transactionIdsBySelectedPeriod,
365
+ };
366
+ autoCat.fetchState = cached.fetchState;
367
+ autoCat.error = cached.error;
368
+ }
369
+ else {
370
+ // Sub-tab has never been visited — clear the active slot so the
371
+ // view-epic's `fetchState === 'Not-Started' || transactionIds.length
372
+ // === 0` cache check falls through and triggers a fresh page-1
373
+ // fetch for the new dataset. `scrollPosition` is reset to the top
374
+ // so the incoming list isn't anchored to the outgoing sub-tab's
375
+ // offset (different rows → previous offset is meaningless).
376
+ autoCat.uiState.pageToken = null;
377
+ autoCat.uiState.totalCount = {};
378
+ autoCat.uiState.scrollPosition = {
379
+ scrollTop: 0,
380
+ scrollLeft: undefined,
381
+ };
382
+ autoCat.transactionIdsBySelectedPeriod = {};
383
+ autoCat.fetchState = 'Not-Started';
384
+ autoCat.error = undefined;
385
+ }
386
+ draft.selectedTransactionCategorizationCompletedSubTab = newSubTab;
387
+ },
388
+ prepare(newSubTab) {
389
+ return { payload: { newSubTab } };
390
+ },
391
+ },
270
392
  updateTransactionCategorization: {
271
393
  reducer(draft, action) {
272
394
  const selectedTab = action.payload.selectedTab;
@@ -704,6 +826,10 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
704
826
  const { selectedTab, selectedPeriod, totalCount } = action.payload;
705
827
  draft.transactionCategorizationView[selectedTab].uiState.totalCount[(0, timePeriod_1.toMonthYearPeriodId)(selectedPeriod)] = totalCount;
706
828
  },
829
+ updateParentTotalCountForTab(draft, action) {
830
+ const { selectedTab, selectedPeriod, parentTotalCount } = action.payload;
831
+ draft.parentTotalCountByTab[selectedTab][(0, timePeriod_1.toMonthYearPeriodId)(selectedPeriod)] = parentTotalCount;
832
+ },
707
833
  updateSelectedCheckboxTransactionIds(draft, action) {
708
834
  const selectedTab = action.payload.selectedTab;
709
835
  const transactionIds = action.payload.transactionIds;
@@ -714,6 +840,16 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
714
840
  draft.transactionCategorizationView[selectedTab] = {
715
841
  ...exports.initialTransactionTabViewState,
716
842
  };
843
+ draft.parentTotalCountByTab[selectedTab] = {};
844
+ // The per-sub-tab snapshot cache lives at the slice root and is
845
+ // exclusively populated by the autoCategorized tab's sub-tab switching
846
+ // (see updateTransactionCategorizationCompletedSubTab). When that tab
847
+ // is reset, leaving stale snapshots behind would short-circuit the
848
+ // next sub-tab visit with phantom row IDs / page tokens that no longer
849
+ // correspond to anything in state — drop them in lockstep.
850
+ if (selectedTab === 'autoCategorized') {
851
+ draft.autoCategorizedSubTabCache = {};
852
+ }
717
853
  },
718
854
  clearExpenseAutomationTransactionsView(draft) {
719
855
  Object.assign(draft, exports.initialState);
@@ -810,5 +946,5 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
810
946
  },
811
947
  },
812
948
  });
813
- _a = expenseAutomationTransactionsView.actions, exports.fetchTransactionCategorization = _a.fetchTransactionCategorization, exports.updateTransactionCategorizationUIState = _a.updateTransactionCategorizationUIState, exports.initializeTransactionCategorizationViewLocalData = _a.initializeTransactionCategorizationViewLocalData, exports.saveTransactionCategorizationLocalData = _a.saveTransactionCategorizationLocalData, exports.fetchTransactionCategorizationFailure = _a.fetchTransactionCategorizationFailure, exports.saveTransactionCategorization = _a.saveTransactionCategorization, exports.updateTransactionCategorization = _a.updateTransactionCategorization, exports.updateCurrentSelectedTransactionCategorizationTab = _a.updateCurrentSelectedTransactionCategorizationTab, exports.updateTransactionCategorizationSaveStatus = _a.updateTransactionCategorizationSaveStatus, exports.markTransactionAsNotMiscategorized = _a.markTransactionAsNotMiscategorized, exports.updateStatusForTransactionNotMiscategorizedUpdateForCategorization = _a.updateStatusForTransactionNotMiscategorizedUpdateForCategorization, exports.updateSelectedVendorForTransaction = _a.updateSelectedVendorForTransaction, exports.updateSelectedCustomerForTransaction = _a.updateSelectedCustomerForTransaction, exports.setAllItemsToCategoryClassInLocalDataForCategorization = _a.setAllItemsToCategoryClassInLocalDataForCategorization, exports.updateTotalCountForTransactionCategorization = _a.updateTotalCountForTransactionCategorization, exports.fetchTransactionCategorizationSuccess = _a.fetchTransactionCategorizationSuccess, exports.resetOtherTabsFetchState = _a.resetOtherTabsFetchState, exports.fetchTransactionCategorizationView = _a.fetchTransactionCategorizationView, exports.updateSelectedCheckboxTransactionIds = _a.updateSelectedCheckboxTransactionIds, exports.clearExpenseAutomationTransactionsViewPerTabView = _a.clearExpenseAutomationTransactionsViewPerTabView, exports.clearExpenseAutomationTransactionsView = _a.clearExpenseAutomationTransactionsView, exports.setEntityRecommendationForLineIdsForCategorization = _a.setEntityRecommendationForLineIdsForCategorization, exports.updateSelectedTransactionId = _a.updateSelectedTransactionId, exports.syncTransactionCategorizationFromDetailSave = _a.syncTransactionCategorizationFromDetailSave, exports.backgroundRefetchReviewTab = _a.backgroundRefetchReviewTab, exports.updateTransactionCategorizationUploadReceiptState = _a.updateTransactionCategorizationUploadReceiptState, exports.uploadTransactionCategorizationReceiptSuccess = _a.uploadTransactionCategorizationReceiptSuccess;
949
+ _a = expenseAutomationTransactionsView.actions, exports.fetchTransactionCategorization = _a.fetchTransactionCategorization, exports.updateTransactionCategorizationUIState = _a.updateTransactionCategorizationUIState, exports.updateTransactionFilters = _a.updateTransactionFilters, exports.initializeTransactionCategorizationViewLocalData = _a.initializeTransactionCategorizationViewLocalData, exports.saveTransactionCategorizationLocalData = _a.saveTransactionCategorizationLocalData, exports.fetchTransactionCategorizationFailure = _a.fetchTransactionCategorizationFailure, exports.saveTransactionCategorization = _a.saveTransactionCategorization, exports.updateTransactionCategorization = _a.updateTransactionCategorization, exports.updateCurrentSelectedTransactionCategorizationTab = _a.updateCurrentSelectedTransactionCategorizationTab, exports.updateTransactionCategorizationCompletedSubTab = _a.updateTransactionCategorizationCompletedSubTab, exports.updateTransactionCategorizationSaveStatus = _a.updateTransactionCategorizationSaveStatus, exports.markTransactionAsNotMiscategorized = _a.markTransactionAsNotMiscategorized, exports.updateStatusForTransactionNotMiscategorizedUpdateForCategorization = _a.updateStatusForTransactionNotMiscategorizedUpdateForCategorization, exports.updateSelectedVendorForTransaction = _a.updateSelectedVendorForTransaction, exports.updateSelectedCustomerForTransaction = _a.updateSelectedCustomerForTransaction, exports.setAllItemsToCategoryClassInLocalDataForCategorization = _a.setAllItemsToCategoryClassInLocalDataForCategorization, exports.updateTotalCountForTransactionCategorization = _a.updateTotalCountForTransactionCategorization, exports.updateParentTotalCountForTab = _a.updateParentTotalCountForTab, exports.fetchTransactionCategorizationSuccess = _a.fetchTransactionCategorizationSuccess, exports.resetOtherTabsFetchState = _a.resetOtherTabsFetchState, exports.fetchTransactionCategorizationView = _a.fetchTransactionCategorizationView, exports.updateSelectedCheckboxTransactionIds = _a.updateSelectedCheckboxTransactionIds, exports.clearExpenseAutomationTransactionsViewPerTabView = _a.clearExpenseAutomationTransactionsViewPerTabView, exports.clearExpenseAutomationTransactionsView = _a.clearExpenseAutomationTransactionsView, exports.setEntityRecommendationForLineIdsForCategorization = _a.setEntityRecommendationForLineIdsForCategorization, exports.updateSelectedTransactionId = _a.updateSelectedTransactionId, exports.syncTransactionCategorizationFromDetailSave = _a.syncTransactionCategorizationFromDetailSave, exports.backgroundRefetchReviewTab = _a.backgroundRefetchReviewTab, exports.updateTransactionCategorizationUploadReceiptState = _a.updateTransactionCategorizationUploadReceiptState, exports.uploadTransactionCategorizationReceiptSuccess = _a.uploadTransactionCategorizationReceiptSuccess;
814
950
  exports.default = expenseAutomationTransactionsView.reducer;
@@ -2,7 +2,8 @@ import { CompletionStatusType, FetchStateAndError, ID } from '../../../commonSta
2
2
  import { SortOrder } from '../../../commonStateTypes/selectorTypes/sortOrderTypes';
3
3
  import { SelectorView } from '../../../commonStateTypes/viewAndReport/viewAndReport';
4
4
  import { SupportedTransaction } from '../../../entity/transaction/transactionState';
5
- import type { BatchFileStatus, BatchListItem, BatchStatus, BulkUploadPhase, BulkUploadResultsTab, BulkUploadSortKey, CompletedSubTab, ManualSearchState, MatchSource, MissingReceiptsViewUIState } from '../types/missingReceiptsViewState';
5
+ import type { CompletedSubTab } from '../types/completedSubTab';
6
+ import type { BatchFileStatus, BatchListItem, BatchStatus, BulkUploadPhase, BulkUploadResultsTab, BulkUploadSortKey, ManualSearchState, MatchSource, MissingReceiptsViewUIState } from '../types/missingReceiptsViewState';
6
7
  export interface CompletedTransactionsSelectorData {
7
8
  fetchState: FetchStateAndError;
8
9
  nextPageToken: string | null;
@@ -7,6 +7,7 @@ import { ClassBase } from '../../../entity/class/classState';
7
7
  import { SupportedTransactionWithCOT } from '../../../entity/transaction/transactionState';
8
8
  import { UncategorizedAccounts } from '../../accountList/accountListSelector';
9
9
  import { ProjectListSelectorView } from '../../projectList/projectListSelector';
10
+ import { CompletedSubTab } from '../types/completedSubTab';
10
11
  import { TransactionReviewLocalData, TransactionsTab, TransactionsViewUIState } from '../types/transactionsViewState';
11
12
  export interface TransactionReviewLocalDataSelectorView {
12
13
  transactionId: ID;
@@ -21,10 +22,23 @@ export interface ExpenseAutomationTransactionViewSelector extends SelectorView {
21
22
  fetchStateByTransactionTabs: Record<TransactionsTab, FetchStateAndError>;
22
23
  isAccountingProjectsEnabled: boolean;
23
24
  markAsNotMiscategorizedStatus: FetchStateAndError;
25
+ /**
26
+ * Parent tab badge counts, sourced from the listing response's
27
+ * `parent_tab_total_count`. Used exclusively to drive the navbar / tab
28
+ * strip badge labels — every other count consumer (pagination, in-list
29
+ * "showing X of Y", save flows) keeps reading {@link totalCountByTab}.
30
+ */
31
+ parentTabTotalCountByTab: Record<TransactionsTab, number>;
24
32
  projectList: ProjectListSelectorView;
25
33
  refreshStatus: FetchStateAndError;
26
34
  saveStatus: FetchStateAndError;
27
35
  selectedCheckBoxTransactionIds: ID[];
36
+ selectedTransactionCategorizationCompletedSubTab: CompletedSubTab;
37
+ /**
38
+ * Per-(sub-)tab counts mirroring `total_count` from the listing response.
39
+ * Powers pagination via `InfiniteLoader.itemCount`, in-list count copy,
40
+ * and the `resetTransactionCategorizationLocalData` round-trip.
41
+ */
28
42
  totalCountByTab: Record<TransactionsTab, number>;
29
43
  transactionIdsWithUnsavedData: ID[];
30
44
  transactionLocalData: TransactionReviewLocalDataSelectorView[];
@@ -1,3 +1,6 @@
1
+ import { TransactionWithCOT } from '../../../entity/transaction/stateTypes/transaction';
1
2
  import { RootState } from '../../../reducer';
2
- import { ExpenseAutomationTransactionViewSelector } from '../selectorTypes/transactionsViewSelectorTypes';
3
+ import { TransactionView } from '../transactionFilterHelpers';
4
+ import { ExpenseAutomationTransactionViewSelector, TransactionReviewLocalDataSelectorView } from '../selectorTypes/transactionsViewSelectorTypes';
5
+ export declare const toTransactionView: (transaction: TransactionWithCOT, transactionLocalData?: TransactionReviewLocalDataSelectorView) => TransactionView;
3
6
  export declare function getExpenseAutomationTransactionView(state: RootState): ExpenseAutomationTransactionViewSelector;
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.toTransactionView = void 0;
6
7
  exports.getExpenseAutomationTransactionView = getExpenseAutomationTransactionView;
7
8
  const omit_1 = __importDefault(require("lodash/omit"));
8
9
  const reduceFetchState_1 = require("../../../commonStateTypes/reduceFetchState");
@@ -10,14 +11,34 @@ const timePeriod_1 = require("../../../commonStateTypes/timePeriod");
10
11
  const tenantSelector_1 = require("../../../entity/tenant/tenantSelector");
11
12
  const transactionHelper_1 = require("../../../entity/transaction/transactionHelper");
12
13
  const transactionSelector_1 = require("../../../entity/transaction/transactionSelector");
14
+ const transactionFilterHelpers_1 = require("../transactionFilterHelpers");
13
15
  const accountListSelector_1 = require("../../accountList/accountListSelector");
14
16
  const classListSelector_1 = require("../../classList/classListSelector");
15
17
  const projectListSelector_1 = require("../../projectList/projectListSelector");
16
18
  const expenseAutomationViewSelectorTypes_1 = require("../selectorTypes/expenseAutomationViewSelectorTypes");
19
+ const toTransactionView = (transaction, transactionLocalData) => {
20
+ return {
21
+ id: transaction.id,
22
+ date: transaction.date,
23
+ amount: transaction.amount,
24
+ vendorName: transaction.vendorName,
25
+ customerName: transaction.customerName,
26
+ vendorId: transaction.vendorId,
27
+ customerId: transaction.customerId,
28
+ description: transaction.description,
29
+ memo: transaction.memo,
30
+ type: transaction.type,
31
+ typeName: transaction.typeName,
32
+ createTime: transaction.createTime,
33
+ transaction: transaction,
34
+ transactionLocalData,
35
+ };
36
+ };
37
+ exports.toTransactionView = toTransactionView;
17
38
  function getExpenseAutomationTransactionView(state) {
18
39
  const { accountState, classState, classListState, accountListState, expenseAutomationTransactionsViewState, expenseAutomationViewState, projectState, projectListState, transactionState, monthEndCloseChecksState, monthEndCloseChecksViewState, } = state;
19
- const { selectedTransactionCategorizationTab } = expenseAutomationTransactionsViewState;
20
- const { uiState, refreshStatus, saveStatus, markAsNotMiscategorizedStatus, transactionIdsBySelectedPeriod, transactionReviewLocalDataById, selectedCheckBoxTransactionIds, transactionIdsWithUnsavedData, uploadReceiptStatusById, selectedTransactionId, selectedTransactionLineId, } = expenseAutomationTransactionsViewState.transactionCategorizationView[selectedTransactionCategorizationTab];
40
+ const { selectedTransactionCategorizationCompletedSubTab, selectedTransactionCategorizationTab, } = expenseAutomationTransactionsViewState;
41
+ const { uiState, refreshStatus, saveStatus, markAsNotMiscategorizedStatus, transactionIdsBySelectedPeriod, transactionReviewLocalDataById, selectedCheckBoxTransactionIds, transactionIdsWithUnsavedData, uploadReceiptStatusById, selectedTransactionId, selectedTransactionLineId, filters, } = expenseAutomationTransactionsViewState.transactionCategorizationView[selectedTransactionCategorizationTab];
21
42
  const uncategorizedIncomeExpense = (0, accountListSelector_1.getUncategorizedAccounts)(accountState, accountListState, 'accountList');
22
43
  const accountList = (0, accountListSelector_1.getAccountList)(accountState, accountListState, 'accountList');
23
44
  const classList = (0, classListSelector_1.getClassList)(classState, classListState);
@@ -36,20 +57,58 @@ function getExpenseAutomationTransactionView(state) {
36
57
  ? transactionIdsBySelectedPeriod[monthYearPeriodId]
37
58
  : null;
38
59
  const transactionIds = transactionIdsForSelectedPeriod ?? [];
39
- const transactionLocalData = transactionIds
40
- .map((transactionId) => {
60
+ const transactions = (0, transactionSelector_1.getSupportedTransactionsByIds)(transactionState, transactionIds);
61
+ const transactionsWithCOT = transactions.map((transaction) => (0, transactionHelper_1.getTransactionWithCOT)(transaction));
62
+ const transactionLocalDataMap = new Map();
63
+ transactionIds.forEach((transactionId) => {
41
64
  const transactionData = transactionReviewLocalDataById[transactionId];
42
65
  if (transactionData != null) {
43
- return {
66
+ transactionLocalDataMap.set(transactionId, {
44
67
  transactionId,
45
68
  transactionReviewLocalData: transactionData.transactionReviewLocalData,
46
- };
69
+ });
47
70
  }
48
- return null;
49
- })
50
- .filter((transaction) => transaction != null);
51
- const transactions = (0, transactionSelector_1.getSupportedTransactionsByIds)(transactionState, transactionIds);
52
- const transactionsWithCOT = transactions.map((transaction) => (0, transactionHelper_1.getTransactionWithCOT)(transaction));
71
+ });
72
+ // Step 2: Convert to TransactionView and apply advanced filters
73
+ const transactionViews = transactionsWithCOT.map((transaction) => {
74
+ const localData = transactionLocalDataMap.get(transaction.id);
75
+ return (0, exports.toTransactionView)(transaction, localData);
76
+ });
77
+ // Apply TC-specific filters (lives under expenseAutomationView, independent
78
+ // of the Spend Management filter pipeline).
79
+ const filteredTransactionViews = (0, transactionFilterHelpers_1.applyTransactionFilters)(transactionViews, filters);
80
+ // Convert back to TransactionWithCOT for return
81
+ const filteredTransactionsWithCOT = filteredTransactionViews.map((view) => view.transaction);
82
+ // Get transactionLocalData for filtered transactions
83
+ // Also include transactionLocalData for transactions that don't exist in transactionState
84
+ // but have local data (to match original behavior)
85
+ const filteredTransactionIds = new Set(filteredTransactionViews.map((view) => view.id));
86
+ // Pre-compute the membership set once. The previous implementation called
87
+ // `transactions.some(t => t.id === transactionId)` inside the per-id loop,
88
+ // turning the pipeline into O(n × m) — measurable on tenants with large
89
+ // transaction lists since this selector runs on every Redux dispatch.
90
+ const transactionExistsById = new Set(transactions.map((t) => t.id));
91
+ // `.flatMap` returns `X[]` directly when the callback returns `[]` for the
92
+ // skip case, so we don't need the trailing `.filter((d): d is X => …)` type
93
+ // predicate that the previous `map → filter` pipeline required.
94
+ const filteredTransactionLocalData = transactionIds.flatMap((transactionId) => {
95
+ const transactionData = transactionReviewLocalDataById[transactionId];
96
+ if (transactionData == null) {
97
+ return [];
98
+ }
99
+ // Include if transaction is in filtered results, or if transaction doesn't exist in state
100
+ // (to maintain backward compatibility with tests)
101
+ const transactionExists = transactionExistsById.has(transactionId);
102
+ if (filteredTransactionIds.has(transactionId) || !transactionExists) {
103
+ return [
104
+ {
105
+ transactionId,
106
+ transactionReviewLocalData: transactionData.transactionReviewLocalData,
107
+ },
108
+ ];
109
+ }
110
+ return [];
111
+ });
53
112
  const monthEndFetchState = monthYearPeriodId != null
54
113
  ? (monthEndCloseChecksViewState.monthEndCloseChecksViewByTenantId[currentTenant.tenantId]?.[monthYearPeriodId] ?? { fetchState: 'Not-Started', error: undefined })
55
114
  : { fetchState: 'Not-Started', error: undefined };
@@ -69,10 +128,27 @@ function getExpenseAutomationTransactionView(state) {
69
128
  .uiState.totalCount;
70
129
  const totalCountByAutoCat = expenseAutomationTransactionsViewState.transactionCategorizationView
71
130
  .autoCategorized.uiState.totalCount;
131
+ // Per-(sub-)tab counts powering pagination, in-list "showing X of Y", and
132
+ // any save/refresh round-trips. Sourced from `uiState.totalCount` which
133
+ // mirrors the response's `total_count` for whatever tab/sub-tab the user is
134
+ // viewing (e.g. only the Manual sub-tab rows for Completed → Manual).
72
135
  const totalCountByTab = {
73
136
  review: monthYearPeriodId != null ? totalCountByReview[monthYearPeriodId] : 0,
74
137
  autoCategorized: monthYearPeriodId != null ? totalCountByAutoCat[monthYearPeriodId] : 0,
75
138
  };
139
+ // Parent-tab badge counts. Sourced from `parent_tab_total_count` in the
140
+ // listing response and used exclusively by the navbar / tab strip badges.
141
+ // Independent of which Completed sub-tab is active so the badge stays
142
+ // stable across sub-tab switches.
143
+ const parentTotalCountByTab = expenseAutomationTransactionsViewState.parentTotalCountByTab;
144
+ const parentTabTotalCountByTab = {
145
+ review: monthYearPeriodId != null
146
+ ? (parentTotalCountByTab.review[monthYearPeriodId] ?? 0)
147
+ : 0,
148
+ autoCategorized: monthYearPeriodId != null
149
+ ? (parentTotalCountByTab.autoCategorized[monthYearPeriodId] ?? 0)
150
+ : 0,
151
+ };
76
152
  const fetchStateByTab = {
77
153
  review: {
78
154
  fetchState: expenseAutomationTransactionsViewState.transactionCategorizationView
@@ -96,7 +172,7 @@ function getExpenseAutomationTransactionView(state) {
96
172
  version: 0,
97
173
  fetchState: fetchStatus.fetchState,
98
174
  error: fetchStatus.error,
99
- transactions: transactionsWithCOT,
175
+ transactions: filteredTransactionsWithCOT,
100
176
  selectedCheckBoxTransactionIds,
101
177
  transactionIdsWithUnsavedData,
102
178
  uncategorizedAccounts: uncategorizedIncomeExpense,
@@ -107,16 +183,18 @@ function getExpenseAutomationTransactionView(state) {
107
183
  classHierarchyList,
108
184
  isAccountingProjectsEnabled,
109
185
  projectList,
110
- transactionLocalData,
186
+ transactionLocalData: filteredTransactionLocalData,
111
187
  uiState,
112
188
  refreshStatus,
113
189
  saveStatus,
114
190
  markAsNotMiscategorizedStatus,
115
191
  completionStatus,
116
192
  totalCountByTab,
193
+ parentTabTotalCountByTab,
117
194
  fetchStateByTransactionTabs: fetchStateByTab,
118
195
  uploadReceiptStatusById,
119
196
  selectedTransactionId,
120
197
  selectedTransactionLineId,
198
+ selectedTransactionCategorizationCompletedSubTab,
121
199
  };
122
200
  }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Filter machinery for the Transaction Categorization feature inside
3
+ * Expense Automation. Intentionally self-contained — does NOT import anything
4
+ * from `view/spendManagement/*`, because Transaction Categorization is not a
5
+ * Spend Management product. Shared primitives
6
+ * (`CategoryCombinationOperator`, `FilterCategoryType`) come from
7
+ * `commonStateTypes/filterPrimitives`, which both feature groups consume.
8
+ */
9
+ import { Amount } from '../../commonStateTypes/amount';
10
+ import { ID } from '../../commonStateTypes/common';
11
+ import { CategoryCombinationOperator, FilterCategoryType } from '../../commonStateTypes/filterPrimitives';
12
+ import { TransactionType } from '../../entity/transaction/stateTypes/transactionType';
13
+ import { SupportedTransactionWithCOT } from '../../entity/transaction/transactionState';
14
+ import { ZeniDate } from '../../zeniDayJS';
15
+ import { TransactionReviewLocalDataSelectorView } from './selectorTypes/transactionsViewSelectorTypes';
16
+ /**
17
+ * Re-exported here so the CES barrel can pull TC's primitives from the
18
+ * Expense Automation surface without reaching into `commonStateTypes`
19
+ * directly — keeps the barrel's existing import topology stable.
20
+ */
21
+ export type { CategoryCombinationOperator, FilterCategoryType };
22
+ export type TransactionFilterEntityType = 'transaction_categorization' | 'customer' | 'vendor' | 'merchant';
23
+ export type TransactionFilterCategoryField = 'payment_account_name' | 'payment_account_type' | 'payee' | 'category' | 'class' | 'amount';
24
+ export interface TransactionFilterCategoryDropdownOption {
25
+ value: TransactionFilterCategoryField;
26
+ multiple?: boolean;
27
+ type?: FilterCategoryType;
28
+ }
29
+ export declare const TRANSACTION_FILTER_CATEGORIES: TransactionFilterCategoryDropdownOption[];
30
+ /** Amount filter operators for transaction_categorization. */
31
+ export type TransactionFilterAmountMatchingOperator = 'equal' | 'not_equal' | 'less_than' | 'greater_than' | 'in_between';
32
+ export interface TransactionFilterCategory {
33
+ field: TransactionFilterCategoryField;
34
+ matchingOperator: TransactionFilterAmountMatchingOperator;
35
+ values: (string | number)[];
36
+ valuesCombinationOperator: 'ANY';
37
+ }
38
+ export interface TransactionFilters {
39
+ categories: TransactionFilterCategory[];
40
+ categoryCombinationOperator: CategoryCombinationOperator;
41
+ }
42
+ export interface TransactionView {
43
+ amount: Amount;
44
+ createTime: ZeniDate;
45
+ date: ZeniDate;
46
+ description: string;
47
+ id: ID;
48
+ memo: string;
49
+ transaction: SupportedTransactionWithCOT;
50
+ type: TransactionType;
51
+ customerId?: ID;
52
+ customerName?: string;
53
+ transactionLocalData?: TransactionReviewLocalDataSelectorView;
54
+ typeName?: string;
55
+ vendorId?: ID;
56
+ vendorName?: string;
57
+ }
58
+ /**
59
+ * TC-only equivalent of `applyAdvancedFiltersOnList`. Filters a list of
60
+ * `TransactionView` items against a `TransactionFilters` object using the
61
+ * AND/OR combination semantics from `categoryCombinationOperator`.
62
+ *
63
+ * Independent of `view/spendManagement` — keeps the TC filter pipeline cleanly
64
+ * inside the Expense Automation feature group.
65
+ */
66
+ export declare const applyTransactionFilters: (transactions: TransactionView[], filters?: TransactionFilters) => TransactionView[];