@zeniai/client-epic-state 5.1.16-betaRD4 → 5.1.16-betaRD5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +0 -5
- package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic.js +27 -31
- package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +57 -2
- package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +0 -5
- package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic.d.ts +2 -2
- package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic.js +25 -29
- package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.d.ts +4 -1
- package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +58 -3
- package/lib/view/expenseAutomationView/types/transactionsViewState.d.ts +15 -0
- package/package.json +1 -1
|
@@ -18,11 +18,6 @@ groupBy((action) => action.payload.selectedTab), mergeMap((group$) => group$.pip
|
|
|
18
18
|
const { pageToken, sortOrder, sortKey } = uiState;
|
|
19
19
|
const currentTenant = getCurrentTenant(state$.value);
|
|
20
20
|
const selectedPeriod = selectedPeriodByTenantId[currentTenant.tenantId];
|
|
21
|
-
console.log('[EA-SEARCH] fetchTransactionCategorizationEpic HTTP call', {
|
|
22
|
-
selectedTab,
|
|
23
|
-
refreshViewInBackground,
|
|
24
|
-
search_text: uiState.searchString,
|
|
25
|
-
});
|
|
26
21
|
const queryParam = {
|
|
27
22
|
start_date: toString(period.start),
|
|
28
23
|
end_date: toString(period.end),
|
|
@@ -6,25 +6,25 @@ import { fetchAccountList } from '../../../accountList/accountListReducer';
|
|
|
6
6
|
import { fetchClassList } from '../../../classList/classListReducer';
|
|
7
7
|
import { fetchOwnerList } from '../../../ownerList/ownerListReducer';
|
|
8
8
|
import { fetchProjectList } from '../../../projectList/projectListReducer';
|
|
9
|
-
import { fetchTransactionCategorization, fetchTransactionCategorizationView, } from '../../reducers/transactionsViewReducer';
|
|
10
|
-
import { TRANSACTIONS_TABS } from '../../types/transactionsViewState';
|
|
9
|
+
import { fetchTransactionCategorization, fetchTransactionCategorizationView, restoreFullDatasetSnapshot, } from '../../reducers/transactionsViewReducer';
|
|
10
|
+
import { TRANSACTIONS_TABS, } from '../../types/transactionsViewState';
|
|
11
11
|
export const fetchTransactionCategorizationViewEpic = (actions$, state$) => actions$.pipe(filter(fetchTransactionCategorizationView.match), mergeMap((action) => {
|
|
12
12
|
const { selectedTab, cacheOverride, keepExistingListItems, pageToken, period, refreshViewInBackground, searchString, resetListItems, isUncategorizedExpenseCategoryEnabled, } = action.payload;
|
|
13
13
|
const updateActions = [];
|
|
14
14
|
const { expenseAutomationTransactionsViewState } = state$.value;
|
|
15
15
|
const { fetchState, transactionIdsBySelectedPeriod } = expenseAutomationTransactionsViewState.transactionCategorizationView[selectedTab];
|
|
16
|
-
console.log('[EA-SEARCH] fetchTransactionCategorizationViewEpic received', {
|
|
17
|
-
selectedTab,
|
|
18
|
-
cacheOverride,
|
|
19
|
-
searchString,
|
|
20
|
-
fetchState,
|
|
21
|
-
});
|
|
22
16
|
const monthYearPeriod = {
|
|
23
17
|
month: period.start.month,
|
|
24
18
|
year: period.start.year,
|
|
25
19
|
};
|
|
26
|
-
const
|
|
27
|
-
|
|
20
|
+
const periodId = toMonthYearPeriodId(monthYearPeriod);
|
|
21
|
+
const transactionIds = transactionIdsBySelectedPeriod[periodId] ?? [];
|
|
22
|
+
const hasUsableSnapshot = (tabKey) => {
|
|
23
|
+
const snapshot = expenseAutomationTransactionsViewState.transactionCategorizationView[tabKey].fullDatasetSnapshot;
|
|
24
|
+
return (snapshot != null &&
|
|
25
|
+
snapshot.periodId === periodId &&
|
|
26
|
+
snapshot.transactionIds.length > 0);
|
|
27
|
+
};
|
|
28
28
|
const accountList = state$.value.accountListState.byReportId['accountList'];
|
|
29
29
|
if (accountList.hasValidState() === false &&
|
|
30
30
|
accountList.fetchState === 'Not-Started') {
|
|
@@ -46,37 +46,33 @@ export const fetchTransactionCategorizationViewEpic = (actions$, state$) => acti
|
|
|
46
46
|
vendorOwnerList.fetchState === 'Not-Started') {
|
|
47
47
|
updateActions.push(fetchOwnerList());
|
|
48
48
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
49
|
+
// When clearing search (searchString === ''), restore from the pre-search
|
|
50
|
+
// snapshot if one exists — avoids a round-trip since all data is already
|
|
51
|
+
// in the entity store. Fall back to a normal fetch if no snapshot (the
|
|
52
|
+
// tab was never loaded before the search was applied).
|
|
53
|
+
if (searchString === '' && hasUsableSnapshot(selectedTab)) {
|
|
54
|
+
updateActions.push(restoreFullDatasetSnapshot({ selectedTab, period }));
|
|
55
|
+
}
|
|
56
|
+
else if (cacheOverride === true ||
|
|
56
57
|
fetchState === 'Not-Started' ||
|
|
57
58
|
transactionIds.length === 0) {
|
|
58
|
-
console.log('[EA-SEARCH] dispatching fetchTransactionCategorization for active tab', { selectedTab, searchString });
|
|
59
59
|
updateActions.push(fetchTransactionCategorization(selectedTab, period, cacheOverride, keepExistingListItems, searchString, pageToken, refreshViewInBackground, resetListItems, isUncategorizedExpenseCategoryEnabled));
|
|
60
60
|
}
|
|
61
61
|
// When search changes (searchString defined, including empty string to
|
|
62
|
-
// clear), also
|
|
62
|
+
// clear), also update every other tab so all tabs always reflect the same
|
|
63
63
|
// search query. Skip if the other tab already has this search string to
|
|
64
|
-
// avoid redundant
|
|
65
|
-
//
|
|
66
|
-
// from page 1; refreshViewInBackground=true because the user isn't
|
|
67
|
-
// looking at the other tab, so a silent background fetch is correct.
|
|
64
|
+
// avoid redundant work on noop updates. On clear, restore from snapshot
|
|
65
|
+
// if available; otherwise issue a background fetch.
|
|
68
66
|
if (searchString !== undefined) {
|
|
69
67
|
TRANSACTIONS_TABS.filter((tab) => tab !== selectedTab).forEach((otherTab) => {
|
|
70
68
|
const otherTabSearchString = expenseAutomationTransactionsViewState.transactionCategorizationView[otherTab].uiState.searchString;
|
|
71
|
-
console.log('[EA-SEARCH] dual-fetch check for other tab', {
|
|
72
|
-
otherTab,
|
|
73
|
-
searchString,
|
|
74
|
-
otherTabSearchString,
|
|
75
|
-
willDispatch: searchString !== otherTabSearchString,
|
|
76
|
-
});
|
|
77
69
|
if (searchString !== otherTabSearchString) {
|
|
78
|
-
|
|
79
|
-
|
|
70
|
+
if (searchString === '' && hasUsableSnapshot(otherTab)) {
|
|
71
|
+
updateActions.push(restoreFullDatasetSnapshot({ selectedTab: otherTab, period }));
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
updateActions.push(fetchTransactionCategorization(otherTab, period, true, keepExistingListItems, searchString, undefined, true, true, isUncategorizedExpenseCategoryEnabled));
|
|
75
|
+
}
|
|
80
76
|
}
|
|
81
77
|
});
|
|
82
78
|
}
|
|
@@ -38,6 +38,7 @@ export const initialTransactionTabViewState = {
|
|
|
38
38
|
hasValidState() {
|
|
39
39
|
return this.fetchState == 'Completed';
|
|
40
40
|
},
|
|
41
|
+
fullDatasetSnapshot: undefined,
|
|
41
42
|
transactionReviewLocalDataById: {},
|
|
42
43
|
transactionIdsBySelectedPeriod: {},
|
|
43
44
|
selectedCheckBoxTransactionIds: [],
|
|
@@ -169,8 +170,29 @@ const expenseAutomationTransactionsView = createSlice({
|
|
|
169
170
|
month: period.start.month,
|
|
170
171
|
year: period.start.year,
|
|
171
172
|
};
|
|
173
|
+
const periodId = toMonthYearPeriodId(monthYearPeriod);
|
|
172
174
|
const transactionIdsBySelectedPeriod = draft.transactionCategorizationView[selectedTab]
|
|
173
|
-
.transactionIdsBySelectedPeriod[
|
|
175
|
+
.transactionIdsBySelectedPeriod[periodId] ?? [];
|
|
176
|
+
// When starting a non-empty search, snapshot the current full dataset
|
|
177
|
+
// so clearing the search can restore instantly without an API round-trip.
|
|
178
|
+
// Only save the snapshot when there are rows to restore; skip for tabs
|
|
179
|
+
// that have never been loaded (empty list → no useful snapshot).
|
|
180
|
+
if (searchString !== undefined &&
|
|
181
|
+
searchString !== '' &&
|
|
182
|
+
transactionIdsBySelectedPeriod.length > 0) {
|
|
183
|
+
const snapshot = {
|
|
184
|
+
periodId,
|
|
185
|
+
totalCount: draft.transactionCategorizationView[selectedTab].uiState
|
|
186
|
+
.totalCount[periodId],
|
|
187
|
+
transactionIds: [...transactionIdsBySelectedPeriod],
|
|
188
|
+
transactionReviewLocalDataById: {
|
|
189
|
+
...draft.transactionCategorizationView[selectedTab]
|
|
190
|
+
.transactionReviewLocalDataById,
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
draft.transactionCategorizationView[selectedTab].fullDatasetSnapshot =
|
|
194
|
+
snapshot;
|
|
195
|
+
}
|
|
174
196
|
transactionIdsBySelectedPeriod.forEach((transactionId) => {
|
|
175
197
|
delete draft.transactionCategorizationView[selectedTab]
|
|
176
198
|
.transactionReviewLocalDataById[transactionId];
|
|
@@ -686,6 +708,39 @@ const expenseAutomationTransactionsView = createSlice({
|
|
|
686
708
|
// leave the other tab's state untouched — it has its own active fetch.
|
|
687
709
|
});
|
|
688
710
|
},
|
|
711
|
+
restoreFullDatasetSnapshot(draft, action) {
|
|
712
|
+
const { selectedTab, period } = action.payload;
|
|
713
|
+
const periodId = toMonthYearPeriodId({
|
|
714
|
+
month: period.start.month,
|
|
715
|
+
year: period.start.year,
|
|
716
|
+
});
|
|
717
|
+
const snapshot = draft.transactionCategorizationView[selectedTab].fullDatasetSnapshot;
|
|
718
|
+
if (snapshot == null || snapshot.periodId !== periodId) {
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
draft.transactionCategorizationView[selectedTab]
|
|
722
|
+
.transactionIdsBySelectedPeriod[periodId] = snapshot.transactionIds;
|
|
723
|
+
// Merge back per-transaction local data; skip entries that were updated
|
|
724
|
+
// during the search (e.g. a save that happened while filtered results
|
|
725
|
+
// were showing) so those saves are not overwritten.
|
|
726
|
+
Object.entries(snapshot.transactionReviewLocalDataById).forEach(([transactionId, localData]) => {
|
|
727
|
+
if (draft.transactionCategorizationView[selectedTab]
|
|
728
|
+
.transactionReviewLocalDataById[transactionId] == null) {
|
|
729
|
+
draft.transactionCategorizationView[selectedTab]
|
|
730
|
+
.transactionReviewLocalDataById[transactionId] = localData;
|
|
731
|
+
}
|
|
732
|
+
});
|
|
733
|
+
if (snapshot.totalCount != null) {
|
|
734
|
+
draft.transactionCategorizationView[selectedTab].uiState.totalCount[periodId] = snapshot.totalCount;
|
|
735
|
+
}
|
|
736
|
+
draft.transactionCategorizationView[selectedTab].uiState.searchString =
|
|
737
|
+
'';
|
|
738
|
+
draft.transactionCategorizationView[selectedTab].uiState.pageToken = null;
|
|
739
|
+
draft.transactionCategorizationView[selectedTab].fetchState = 'Completed';
|
|
740
|
+
draft.transactionCategorizationView[selectedTab].error = undefined;
|
|
741
|
+
draft.transactionCategorizationView[selectedTab].fullDatasetSnapshot =
|
|
742
|
+
undefined;
|
|
743
|
+
},
|
|
689
744
|
fetchTransactionCategorizationFailure(draft, action) {
|
|
690
745
|
const { selectedTab, selectedPeriod } = action.payload;
|
|
691
746
|
draft.transactionCategorizationView[selectedTab].transactionIdsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)] =
|
|
@@ -1066,5 +1121,5 @@ const expenseAutomationTransactionsView = createSlice({
|
|
|
1066
1121
|
},
|
|
1067
1122
|
},
|
|
1068
1123
|
});
|
|
1069
|
-
export const { fetchTransactionCategorization, updateTransactionCategorizationUIState, updateTransactionFilters, initializeTransactionCategorizationViewLocalData, saveTransactionCategorizationLocalData, fetchTransactionCategorizationFailure, saveTransactionCategorization, updateTransactionCategorization, updateCurrentSelectedTransactionCategorizationTab, updateTransactionCategorizationCompletedSubTab, updateTransactionCategorizationSaveStatus, markTransactionAsNotMiscategorized, updateStatusForTransactionNotMiscategorizedUpdateForCategorization, updateSelectedVendorForTransaction, updateSelectedCustomerForTransaction, setAllItemsToCategoryClassInLocalDataForCategorization, updateTotalCountForTransactionCategorization, updateParentTotalCountForTab, fetchTransactionCategorizationSuccess, resetOtherTabsFetchState, fetchTransactionCategorizationView, updateSelectedCheckboxTransactionIds, clearExpenseAutomationTransactionsViewPerTabView, clearExpenseAutomationTransactionsView, setEntityRecommendationForLineIdsForCategorization, markCategoryClassRecommendationsInProgressForCategorization, markCategoryClassRecommendationsCompletedForCategorization, markCategoryClassRecommendationsFailureForCategorization, updateSelectedTransactionId, syncTransactionCategorizationFromDetailSave, backgroundRefetchReviewTab, removeTransactionFromAllTabs, updateTransactionCategorizationUploadReceiptState, uploadTransactionCategorizationReceiptSuccess, } = expenseAutomationTransactionsView.actions;
|
|
1124
|
+
export const { fetchTransactionCategorization, updateTransactionCategorizationUIState, updateTransactionFilters, initializeTransactionCategorizationViewLocalData, saveTransactionCategorizationLocalData, fetchTransactionCategorizationFailure, saveTransactionCategorization, updateTransactionCategorization, updateCurrentSelectedTransactionCategorizationTab, updateTransactionCategorizationCompletedSubTab, updateTransactionCategorizationSaveStatus, markTransactionAsNotMiscategorized, updateStatusForTransactionNotMiscategorizedUpdateForCategorization, updateSelectedVendorForTransaction, updateSelectedCustomerForTransaction, setAllItemsToCategoryClassInLocalDataForCategorization, updateTotalCountForTransactionCategorization, updateParentTotalCountForTab, fetchTransactionCategorizationSuccess, resetOtherTabsFetchState, restoreFullDatasetSnapshot, fetchTransactionCategorizationView, updateSelectedCheckboxTransactionIds, clearExpenseAutomationTransactionsViewPerTabView, clearExpenseAutomationTransactionsView, setEntityRecommendationForLineIdsForCategorization, markCategoryClassRecommendationsInProgressForCategorization, markCategoryClassRecommendationsCompletedForCategorization, markCategoryClassRecommendationsFailureForCategorization, updateSelectedTransactionId, syncTransactionCategorizationFromDetailSave, backgroundRefetchReviewTab, removeTransactionFromAllTabs, updateTransactionCategorizationUploadReceiptState, uploadTransactionCategorizationReceiptSuccess, } = expenseAutomationTransactionsView.actions;
|
|
1070
1125
|
export default expenseAutomationTransactionsView.reducer;
|
|
@@ -21,11 +21,6 @@ const fetchTransactionCategorizationEpic = (actions$, state$, zeniAPI) => action
|
|
|
21
21
|
const { pageToken, sortOrder, sortKey } = uiState;
|
|
22
22
|
const currentTenant = (0, tenantSelector_1.getCurrentTenant)(state$.value);
|
|
23
23
|
const selectedPeriod = selectedPeriodByTenantId[currentTenant.tenantId];
|
|
24
|
-
console.log('[EA-SEARCH] fetchTransactionCategorizationEpic HTTP call', {
|
|
25
|
-
selectedTab,
|
|
26
|
-
refreshViewInBackground,
|
|
27
|
-
search_text: uiState.searchString,
|
|
28
|
-
});
|
|
29
24
|
const queryParam = {
|
|
30
25
|
start_date: (0, timePeriod_1.toString)(period.start),
|
|
31
26
|
end_date: (0, timePeriod_1.toString)(period.end),
|
|
@@ -5,6 +5,6 @@ import { fetchAccountList } from '../../../accountList/accountListReducer';
|
|
|
5
5
|
import { fetchClassList } from '../../../classList/classListReducer';
|
|
6
6
|
import { fetchOwnerList } from '../../../ownerList/ownerListReducer';
|
|
7
7
|
import { fetchProjectList } from '../../../projectList/projectListReducer';
|
|
8
|
-
import { fetchTransactionCategorization, fetchTransactionCategorizationView } from '../../reducers/transactionsViewReducer';
|
|
9
|
-
export type ActionType = ReturnType<typeof fetchTransactionCategorizationView> | ReturnType<typeof fetchTransactionCategorization> | ReturnType<typeof fetchAccountList> | ReturnType<typeof fetchClassList> | ReturnType<typeof fetchOwnerList> | ReturnType<typeof fetchProjectList>;
|
|
8
|
+
import { fetchTransactionCategorization, fetchTransactionCategorizationView, restoreFullDatasetSnapshot } from '../../reducers/transactionsViewReducer';
|
|
9
|
+
export type ActionType = ReturnType<typeof fetchTransactionCategorizationView> | ReturnType<typeof fetchTransactionCategorization> | ReturnType<typeof restoreFullDatasetSnapshot> | ReturnType<typeof fetchAccountList> | ReturnType<typeof fetchClassList> | ReturnType<typeof fetchOwnerList> | ReturnType<typeof fetchProjectList>;
|
|
10
10
|
export declare const fetchTransactionCategorizationViewEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>) => Observable<ActionType>;
|
|
@@ -16,18 +16,18 @@ const fetchTransactionCategorizationViewEpic = (actions$, state$) => actions$.pi
|
|
|
16
16
|
const updateActions = [];
|
|
17
17
|
const { expenseAutomationTransactionsViewState } = state$.value;
|
|
18
18
|
const { fetchState, transactionIdsBySelectedPeriod } = expenseAutomationTransactionsViewState.transactionCategorizationView[selectedTab];
|
|
19
|
-
console.log('[EA-SEARCH] fetchTransactionCategorizationViewEpic received', {
|
|
20
|
-
selectedTab,
|
|
21
|
-
cacheOverride,
|
|
22
|
-
searchString,
|
|
23
|
-
fetchState,
|
|
24
|
-
});
|
|
25
19
|
const monthYearPeriod = {
|
|
26
20
|
month: period.start.month,
|
|
27
21
|
year: period.start.year,
|
|
28
22
|
};
|
|
29
|
-
const
|
|
30
|
-
|
|
23
|
+
const periodId = (0, timePeriod_1.toMonthYearPeriodId)(monthYearPeriod);
|
|
24
|
+
const transactionIds = transactionIdsBySelectedPeriod[periodId] ?? [];
|
|
25
|
+
const hasUsableSnapshot = (tabKey) => {
|
|
26
|
+
const snapshot = expenseAutomationTransactionsViewState.transactionCategorizationView[tabKey].fullDatasetSnapshot;
|
|
27
|
+
return (snapshot != null &&
|
|
28
|
+
snapshot.periodId === periodId &&
|
|
29
|
+
snapshot.transactionIds.length > 0);
|
|
30
|
+
};
|
|
31
31
|
const accountList = state$.value.accountListState.byReportId['accountList'];
|
|
32
32
|
if (accountList.hasValidState() === false &&
|
|
33
33
|
accountList.fetchState === 'Not-Started') {
|
|
@@ -49,37 +49,33 @@ const fetchTransactionCategorizationViewEpic = (actions$, state$) => actions$.pi
|
|
|
49
49
|
vendorOwnerList.fetchState === 'Not-Started') {
|
|
50
50
|
updateActions.push((0, ownerListReducer_1.fetchOwnerList)());
|
|
51
51
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
// When clearing search (searchString === ''), restore from the pre-search
|
|
53
|
+
// snapshot if one exists — avoids a round-trip since all data is already
|
|
54
|
+
// in the entity store. Fall back to a normal fetch if no snapshot (the
|
|
55
|
+
// tab was never loaded before the search was applied).
|
|
56
|
+
if (searchString === '' && hasUsableSnapshot(selectedTab)) {
|
|
57
|
+
updateActions.push((0, transactionsViewReducer_1.restoreFullDatasetSnapshot)({ selectedTab, period }));
|
|
58
|
+
}
|
|
59
|
+
else if (cacheOverride === true ||
|
|
59
60
|
fetchState === 'Not-Started' ||
|
|
60
61
|
transactionIds.length === 0) {
|
|
61
|
-
console.log('[EA-SEARCH] dispatching fetchTransactionCategorization for active tab', { selectedTab, searchString });
|
|
62
62
|
updateActions.push((0, transactionsViewReducer_1.fetchTransactionCategorization)(selectedTab, period, cacheOverride, keepExistingListItems, searchString, pageToken, refreshViewInBackground, resetListItems, isUncategorizedExpenseCategoryEnabled));
|
|
63
63
|
}
|
|
64
64
|
// When search changes (searchString defined, including empty string to
|
|
65
|
-
// clear), also
|
|
65
|
+
// clear), also update every other tab so all tabs always reflect the same
|
|
66
66
|
// search query. Skip if the other tab already has this search string to
|
|
67
|
-
// avoid redundant
|
|
68
|
-
//
|
|
69
|
-
// from page 1; refreshViewInBackground=true because the user isn't
|
|
70
|
-
// looking at the other tab, so a silent background fetch is correct.
|
|
67
|
+
// avoid redundant work on noop updates. On clear, restore from snapshot
|
|
68
|
+
// if available; otherwise issue a background fetch.
|
|
71
69
|
if (searchString !== undefined) {
|
|
72
70
|
transactionsViewState_1.TRANSACTIONS_TABS.filter((tab) => tab !== selectedTab).forEach((otherTab) => {
|
|
73
71
|
const otherTabSearchString = expenseAutomationTransactionsViewState.transactionCategorizationView[otherTab].uiState.searchString;
|
|
74
|
-
console.log('[EA-SEARCH] dual-fetch check for other tab', {
|
|
75
|
-
otherTab,
|
|
76
|
-
searchString,
|
|
77
|
-
otherTabSearchString,
|
|
78
|
-
willDispatch: searchString !== otherTabSearchString,
|
|
79
|
-
});
|
|
80
72
|
if (searchString !== otherTabSearchString) {
|
|
81
|
-
|
|
82
|
-
|
|
73
|
+
if (searchString === '' && hasUsableSnapshot(otherTab)) {
|
|
74
|
+
updateActions.push((0, transactionsViewReducer_1.restoreFullDatasetSnapshot)({ selectedTab: otherTab, period }));
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
updateActions.push((0, transactionsViewReducer_1.fetchTransactionCategorization)(otherTab, period, true, keepExistingListItems, searchString, undefined, true, true, isUncategorizedExpenseCategoryEnabled));
|
|
78
|
+
}
|
|
83
79
|
}
|
|
84
80
|
});
|
|
85
81
|
}
|
|
@@ -137,7 +137,10 @@ export declare const fetchTransactionCategorization: import("@reduxjs/toolkit").
|
|
|
137
137
|
}, "expenseAutomationTransactionsView/fetchTransactionCategorizationSuccess">, resetOtherTabsFetchState: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
138
138
|
tabs: TransactionsTab[];
|
|
139
139
|
refreshViewInBackground?: boolean;
|
|
140
|
-
}, "expenseAutomationTransactionsView/resetOtherTabsFetchState">,
|
|
140
|
+
}, "expenseAutomationTransactionsView/resetOtherTabsFetchState">, restoreFullDatasetSnapshot: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
|
|
141
|
+
period: TimePeriod;
|
|
142
|
+
selectedTab: TransactionsTab;
|
|
143
|
+
}, "expenseAutomationTransactionsView/restoreFullDatasetSnapshot">, fetchTransactionCategorizationView: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[selectedTab: "review" | "autoCategorized", period: TimePeriod, cacheOverride?: any, keepExistingListItems?: any, searchString?: string | undefined, pageToken?: PageToken | undefined, refreshViewInBackground?: any, resetListItems?: any, isUncategorizedExpenseCategoryEnabled?: boolean | undefined], {
|
|
141
144
|
selectedTab: "review" | "autoCategorized";
|
|
142
145
|
period: TimePeriod;
|
|
143
146
|
searchString: string | undefined;
|
|
@@ -4,7 +4,7 @@ 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.removeTransactionFromAllTabs = exports.backgroundRefetchReviewTab = exports.syncTransactionCategorizationFromDetailSave = exports.updateSelectedTransactionId = exports.markCategoryClassRecommendationsFailureForCategorization = exports.markCategoryClassRecommendationsCompletedForCategorization = exports.markCategoryClassRecommendationsInProgressForCategorization = 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;
|
|
7
|
+
exports.uploadTransactionCategorizationReceiptSuccess = exports.updateTransactionCategorizationUploadReceiptState = exports.removeTransactionFromAllTabs = exports.backgroundRefetchReviewTab = exports.syncTransactionCategorizationFromDetailSave = exports.updateSelectedTransactionId = exports.markCategoryClassRecommendationsFailureForCategorization = exports.markCategoryClassRecommendationsCompletedForCategorization = exports.markCategoryClassRecommendationsInProgressForCategorization = exports.setEntityRecommendationForLineIdsForCategorization = exports.clearExpenseAutomationTransactionsView = exports.clearExpenseAutomationTransactionsViewPerTabView = exports.updateSelectedCheckboxTransactionIds = exports.fetchTransactionCategorizationView = exports.restoreFullDatasetSnapshot = 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"));
|
|
@@ -45,6 +45,7 @@ exports.initialTransactionTabViewState = {
|
|
|
45
45
|
hasValidState() {
|
|
46
46
|
return this.fetchState == 'Completed';
|
|
47
47
|
},
|
|
48
|
+
fullDatasetSnapshot: undefined,
|
|
48
49
|
transactionReviewLocalDataById: {},
|
|
49
50
|
transactionIdsBySelectedPeriod: {},
|
|
50
51
|
selectedCheckBoxTransactionIds: [],
|
|
@@ -176,8 +177,29 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
176
177
|
month: period.start.month,
|
|
177
178
|
year: period.start.year,
|
|
178
179
|
};
|
|
180
|
+
const periodId = (0, timePeriod_1.toMonthYearPeriodId)(monthYearPeriod);
|
|
179
181
|
const transactionIdsBySelectedPeriod = draft.transactionCategorizationView[selectedTab]
|
|
180
|
-
.transactionIdsBySelectedPeriod[
|
|
182
|
+
.transactionIdsBySelectedPeriod[periodId] ?? [];
|
|
183
|
+
// When starting a non-empty search, snapshot the current full dataset
|
|
184
|
+
// so clearing the search can restore instantly without an API round-trip.
|
|
185
|
+
// Only save the snapshot when there are rows to restore; skip for tabs
|
|
186
|
+
// that have never been loaded (empty list → no useful snapshot).
|
|
187
|
+
if (searchString !== undefined &&
|
|
188
|
+
searchString !== '' &&
|
|
189
|
+
transactionIdsBySelectedPeriod.length > 0) {
|
|
190
|
+
const snapshot = {
|
|
191
|
+
periodId,
|
|
192
|
+
totalCount: draft.transactionCategorizationView[selectedTab].uiState
|
|
193
|
+
.totalCount[periodId],
|
|
194
|
+
transactionIds: [...transactionIdsBySelectedPeriod],
|
|
195
|
+
transactionReviewLocalDataById: {
|
|
196
|
+
...draft.transactionCategorizationView[selectedTab]
|
|
197
|
+
.transactionReviewLocalDataById,
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
draft.transactionCategorizationView[selectedTab].fullDatasetSnapshot =
|
|
201
|
+
snapshot;
|
|
202
|
+
}
|
|
181
203
|
transactionIdsBySelectedPeriod.forEach((transactionId) => {
|
|
182
204
|
delete draft.transactionCategorizationView[selectedTab]
|
|
183
205
|
.transactionReviewLocalDataById[transactionId];
|
|
@@ -693,6 +715,39 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
693
715
|
// leave the other tab's state untouched — it has its own active fetch.
|
|
694
716
|
});
|
|
695
717
|
},
|
|
718
|
+
restoreFullDatasetSnapshot(draft, action) {
|
|
719
|
+
const { selectedTab, period } = action.payload;
|
|
720
|
+
const periodId = (0, timePeriod_1.toMonthYearPeriodId)({
|
|
721
|
+
month: period.start.month,
|
|
722
|
+
year: period.start.year,
|
|
723
|
+
});
|
|
724
|
+
const snapshot = draft.transactionCategorizationView[selectedTab].fullDatasetSnapshot;
|
|
725
|
+
if (snapshot == null || snapshot.periodId !== periodId) {
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
draft.transactionCategorizationView[selectedTab]
|
|
729
|
+
.transactionIdsBySelectedPeriod[periodId] = snapshot.transactionIds;
|
|
730
|
+
// Merge back per-transaction local data; skip entries that were updated
|
|
731
|
+
// during the search (e.g. a save that happened while filtered results
|
|
732
|
+
// were showing) so those saves are not overwritten.
|
|
733
|
+
Object.entries(snapshot.transactionReviewLocalDataById).forEach(([transactionId, localData]) => {
|
|
734
|
+
if (draft.transactionCategorizationView[selectedTab]
|
|
735
|
+
.transactionReviewLocalDataById[transactionId] == null) {
|
|
736
|
+
draft.transactionCategorizationView[selectedTab]
|
|
737
|
+
.transactionReviewLocalDataById[transactionId] = localData;
|
|
738
|
+
}
|
|
739
|
+
});
|
|
740
|
+
if (snapshot.totalCount != null) {
|
|
741
|
+
draft.transactionCategorizationView[selectedTab].uiState.totalCount[periodId] = snapshot.totalCount;
|
|
742
|
+
}
|
|
743
|
+
draft.transactionCategorizationView[selectedTab].uiState.searchString =
|
|
744
|
+
'';
|
|
745
|
+
draft.transactionCategorizationView[selectedTab].uiState.pageToken = null;
|
|
746
|
+
draft.transactionCategorizationView[selectedTab].fetchState = 'Completed';
|
|
747
|
+
draft.transactionCategorizationView[selectedTab].error = undefined;
|
|
748
|
+
draft.transactionCategorizationView[selectedTab].fullDatasetSnapshot =
|
|
749
|
+
undefined;
|
|
750
|
+
},
|
|
696
751
|
fetchTransactionCategorizationFailure(draft, action) {
|
|
697
752
|
const { selectedTab, selectedPeriod } = action.payload;
|
|
698
753
|
draft.transactionCategorizationView[selectedTab].transactionIdsBySelectedPeriod[(0, timePeriod_1.toMonthYearPeriodId)(selectedPeriod)] =
|
|
@@ -1073,5 +1128,5 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
1073
1128
|
},
|
|
1074
1129
|
},
|
|
1075
1130
|
});
|
|
1076
|
-
_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.markCategoryClassRecommendationsInProgressForCategorization = _a.markCategoryClassRecommendationsInProgressForCategorization, exports.markCategoryClassRecommendationsCompletedForCategorization = _a.markCategoryClassRecommendationsCompletedForCategorization, exports.markCategoryClassRecommendationsFailureForCategorization = _a.markCategoryClassRecommendationsFailureForCategorization, exports.updateSelectedTransactionId = _a.updateSelectedTransactionId, exports.syncTransactionCategorizationFromDetailSave = _a.syncTransactionCategorizationFromDetailSave, exports.backgroundRefetchReviewTab = _a.backgroundRefetchReviewTab, exports.removeTransactionFromAllTabs = _a.removeTransactionFromAllTabs, exports.updateTransactionCategorizationUploadReceiptState = _a.updateTransactionCategorizationUploadReceiptState, exports.uploadTransactionCategorizationReceiptSuccess = _a.uploadTransactionCategorizationReceiptSuccess;
|
|
1131
|
+
_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.restoreFullDatasetSnapshot = _a.restoreFullDatasetSnapshot, exports.fetchTransactionCategorizationView = _a.fetchTransactionCategorizationView, exports.updateSelectedCheckboxTransactionIds = _a.updateSelectedCheckboxTransactionIds, exports.clearExpenseAutomationTransactionsViewPerTabView = _a.clearExpenseAutomationTransactionsViewPerTabView, exports.clearExpenseAutomationTransactionsView = _a.clearExpenseAutomationTransactionsView, exports.setEntityRecommendationForLineIdsForCategorization = _a.setEntityRecommendationForLineIdsForCategorization, exports.markCategoryClassRecommendationsInProgressForCategorization = _a.markCategoryClassRecommendationsInProgressForCategorization, exports.markCategoryClassRecommendationsCompletedForCategorization = _a.markCategoryClassRecommendationsCompletedForCategorization, exports.markCategoryClassRecommendationsFailureForCategorization = _a.markCategoryClassRecommendationsFailureForCategorization, exports.updateSelectedTransactionId = _a.updateSelectedTransactionId, exports.syncTransactionCategorizationFromDetailSave = _a.syncTransactionCategorizationFromDetailSave, exports.backgroundRefetchReviewTab = _a.backgroundRefetchReviewTab, exports.removeTransactionFromAllTabs = _a.removeTransactionFromAllTabs, exports.updateTransactionCategorizationUploadReceiptState = _a.updateTransactionCategorizationUploadReceiptState, exports.uploadTransactionCategorizationReceiptSuccess = _a.uploadTransactionCategorizationReceiptSuccess;
|
|
1077
1132
|
exports.default = expenseAutomationTransactionsView.reducer;
|
|
@@ -94,8 +94,23 @@ export interface SupportedTransactionCategorization {
|
|
|
94
94
|
transactionId?: ID;
|
|
95
95
|
}
|
|
96
96
|
export declare const initialSupportedTransactionCategorization: SupportedTransactionCategorization;
|
|
97
|
+
/**
|
|
98
|
+
* Snapshot of a tab's full (pre-search) dataset taken the moment the user
|
|
99
|
+
* first applies a non-empty search string. When the search is cleared the
|
|
100
|
+
* view epic restores from here instead of issuing a new API request.
|
|
101
|
+
*
|
|
102
|
+
* Only saved when there are actual rows to restore (`transactionIds` is
|
|
103
|
+
* non-empty); cleared once consumed or replaced by a fresh search.
|
|
104
|
+
*/
|
|
105
|
+
export interface FullDatasetSnapshot {
|
|
106
|
+
periodId: MonthYearPeriodId;
|
|
107
|
+
totalCount: number | undefined;
|
|
108
|
+
transactionIds: ID[];
|
|
109
|
+
transactionReviewLocalDataById: Record<ID | TransactionDetailKey, SupportedTransactionCategorization>;
|
|
110
|
+
}
|
|
97
111
|
export interface TransactionsTabViewState extends FetchedState {
|
|
98
112
|
filters: TransactionFilters;
|
|
113
|
+
fullDatasetSnapshot: FullDatasetSnapshot | undefined;
|
|
99
114
|
markAsNotMiscategorizedStatus: FetchStateAndError;
|
|
100
115
|
refreshStatus: FetchStateAndError;
|
|
101
116
|
saveStatus: FetchStateAndError;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zeniai/client-epic-state",
|
|
3
|
-
"version": "5.1.16-
|
|
3
|
+
"version": "5.1.16-betaRD5",
|
|
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",
|