@zeniai/client-epic-state 5.1.20-betaDI2 → 5.1.20-betaRD2
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/epic.d.ts +1 -2
- package/lib/epic.js +1 -2
- package/lib/esm/epic.js +1 -2
- package/lib/esm/index.js +1 -2
- package/lib/esm/view/companyTaskManagerView/epics/fetchTaskManagerMetricsEpic.js +1 -8
- package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +49 -11
- package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic.js +48 -4
- package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +107 -19
- package/lib/esm/view/spendManagement/commonSetup/setupViewReducer.js +5 -1
- package/lib/esm/view/taskManager/taskDetailView/epics/initializeTaskToLocalStoreEpic.js +0 -1
- package/lib/esm/view/taskManager/taskDetailView/epics/saveTaskDetailEpic.js +1 -9
- package/lib/esm/view/taskManager/taskDetailView/taskDetailSelector.js +1 -2
- package/lib/index.d.ts +1 -2
- package/lib/index.js +8 -10
- package/lib/view/companyTaskManagerView/epics/fetchTaskManagerMetricsEpic.js +1 -8
- package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +47 -9
- package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic.d.ts +2 -2
- package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic.js +47 -3
- package/lib/view/expenseAutomationView/payload/transactionCategorizationPayload.d.ts +7 -0
- package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.d.ts +4 -1
- package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +108 -20
- package/lib/view/expenseAutomationView/types/transactionsViewState.d.ts +16 -0
- package/lib/view/spendManagement/commonSetup/setupViewReducer.js +5 -1
- package/lib/view/taskManager/taskDetailView/epics/initializeTaskToLocalStoreEpic.js +0 -1
- package/lib/view/taskManager/taskDetailView/epics/saveTaskDetailEpic.js +1 -9
- package/lib/view/taskManager/taskDetailView/taskDetail.d.ts +0 -1
- package/lib/view/taskManager/taskDetailView/taskDetailSelector.js +1 -2
- package/package.json +1 -1
- package/lib/esm/view/taskManager/taskDetailView/epics/sendCommentMentionNotificationEpic.js +0 -44
- package/lib/view/taskManager/taskDetailView/epics/sendCommentMentionNotificationEpic.d.ts +0 -20
- package/lib/view/taskManager/taskDetailView/epics/sendCommentMentionNotificationEpic.js +0 -48
|
@@ -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 = [];
|
|
@@ -19,8 +20,14 @@ const fetchTransactionCategorizationViewEpic = (actions$, state$) => actions$.pi
|
|
|
19
20
|
month: period.start.month,
|
|
20
21
|
year: period.start.year,
|
|
21
22
|
};
|
|
22
|
-
const
|
|
23
|
-
|
|
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
|
+
};
|
|
24
31
|
const accountList = state$.value.accountListState.byReportId['accountList'];
|
|
25
32
|
if (accountList.hasValidState() === false &&
|
|
26
33
|
accountList.fetchState === 'Not-Started') {
|
|
@@ -42,11 +49,48 @@ const fetchTransactionCategorizationViewEpic = (actions$, state$) => actions$.pi
|
|
|
42
49
|
vendorOwnerList.fetchState === 'Not-Started') {
|
|
43
50
|
updateActions.push((0, ownerListReducer_1.fetchOwnerList)());
|
|
44
51
|
}
|
|
45
|
-
|
|
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 ||
|
|
46
60
|
fetchState === 'Not-Started' ||
|
|
47
61
|
transactionIds.length === 0) {
|
|
48
62
|
updateActions.push((0, transactionsViewReducer_1.fetchTransactionCategorization)(selectedTab, period, cacheOverride, keepExistingListItems, searchString, pageToken, refreshViewInBackground, resetListItems, isUncategorizedExpenseCategoryEnabled));
|
|
49
63
|
}
|
|
64
|
+
// On the initial load of a tab (searchString undefined = non-search fetch),
|
|
65
|
+
// preload every other tab that hasn't been fetched yet for this period.
|
|
66
|
+
// This makes switching to the other tab instant instead of triggering a
|
|
67
|
+
// fresh fetch on click. refreshViewInBackground=true keeps it silent.
|
|
68
|
+
if (searchString === undefined) {
|
|
69
|
+
transactionsViewState_1.TRANSACTIONS_TABS.filter((tab) => tab !== selectedTab).forEach((otherTab) => {
|
|
70
|
+
const otherTabFetchState = expenseAutomationTransactionsViewState.transactionCategorizationView[otherTab].fetchState;
|
|
71
|
+
if (otherTabFetchState === 'Not-Started') {
|
|
72
|
+
updateActions.push((0, transactionsViewReducer_1.fetchTransactionCategorization)(otherTab, period, false, false, undefined, undefined, true, undefined, isUncategorizedExpenseCategoryEnabled));
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
// When search changes (searchString defined, including empty string to
|
|
77
|
+
// clear), also update every other tab so all tabs always reflect the same
|
|
78
|
+
// search query. Skip if the other tab already has this search string to
|
|
79
|
+
// avoid redundant work on noop updates. On clear, restore from snapshot
|
|
80
|
+
// if available; otherwise issue a background fetch.
|
|
81
|
+
if (searchString !== undefined) {
|
|
82
|
+
transactionsViewState_1.TRANSACTIONS_TABS.filter((tab) => tab !== selectedTab).forEach((otherTab) => {
|
|
83
|
+
const otherTabSearchString = expenseAutomationTransactionsViewState.transactionCategorizationView[otherTab].uiState.searchString;
|
|
84
|
+
if (searchString !== otherTabSearchString) {
|
|
85
|
+
if (searchString === '' && hasUsableSnapshot(otherTab)) {
|
|
86
|
+
updateActions.push((0, transactionsViewReducer_1.restoreFullDatasetSnapshot)({ selectedTab: otherTab, period }));
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
updateActions.push((0, transactionsViewReducer_1.fetchTransactionCategorization)(otherTab, period, true, keepExistingListItems, searchString, undefined, true, true, isUncategorizedExpenseCategoryEnabled));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
50
94
|
return (0, rxjs_1.from)(updateActions);
|
|
51
95
|
}));
|
|
52
96
|
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;
|
|
@@ -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: [],
|
|
@@ -160,27 +161,62 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
160
161
|
draft.transactionCategorizationView[selectedTab].fetchState =
|
|
161
162
|
'In-Progress';
|
|
162
163
|
draft.transactionCategorizationView[selectedTab].error = undefined;
|
|
164
|
+
// A foreground fetch supersedes any in-flight background preload.
|
|
165
|
+
// Reset refreshStatus so a cancelled preload doesn't leave the
|
|
166
|
+
// spinner stuck at In-Progress.
|
|
167
|
+
draft.transactionCategorizationView[selectedTab].refreshStatus = {
|
|
168
|
+
fetchState: 'Not-Started',
|
|
169
|
+
error: undefined,
|
|
170
|
+
};
|
|
163
171
|
}
|
|
164
172
|
draft.transactionCategorizationView[selectedTab].uiState.pageToken =
|
|
165
173
|
pageToken ?? null;
|
|
166
|
-
|
|
167
|
-
|
|
174
|
+
// Only overwrite when explicitly set; undefined means a non-search fetch
|
|
175
|
+
// (tab switch, period change) should preserve the existing search string.
|
|
176
|
+
if (searchString !== undefined) {
|
|
177
|
+
draft.transactionCategorizationView[selectedTab].uiState.searchString =
|
|
178
|
+
searchString;
|
|
179
|
+
}
|
|
168
180
|
draft.transactionCategorizationView[selectedTab].error = undefined;
|
|
181
|
+
const monthYearPeriod = {
|
|
182
|
+
month: period.start.month,
|
|
183
|
+
year: period.start.year,
|
|
184
|
+
};
|
|
185
|
+
const periodId = (0, timePeriod_1.toMonthYearPeriodId)(monthYearPeriod);
|
|
186
|
+
const transactionIdsBySelectedPeriod = draft.transactionCategorizationView[selectedTab]
|
|
187
|
+
.transactionIdsBySelectedPeriod[periodId] ?? [];
|
|
188
|
+
// Snapshot before any list mutation so clearing the search restores
|
|
189
|
+
// instantly without an API round-trip — for BOTH active and synced tabs.
|
|
190
|
+
// Active-tab search dispatches resetListItems=false, so this must live
|
|
191
|
+
// outside the resetListItems block. fullDatasetSnapshot == null prevents
|
|
192
|
+
// overwriting the original snapshot on search refinement ('ama'→'amazon').
|
|
193
|
+
if (searchString !== undefined &&
|
|
194
|
+
searchString !== '' &&
|
|
195
|
+
transactionIdsBySelectedPeriod.length > 0 &&
|
|
196
|
+
draft.transactionCategorizationView[selectedTab].fullDatasetSnapshot ==
|
|
197
|
+
null) {
|
|
198
|
+
draft.transactionCategorizationView[selectedTab].fullDatasetSnapshot =
|
|
199
|
+
{
|
|
200
|
+
parentTotalCount: draft.parentTotalCountByTab[selectedTab][periodId],
|
|
201
|
+
periodId,
|
|
202
|
+
totalCount: draft.transactionCategorizationView[selectedTab].uiState
|
|
203
|
+
.totalCount[periodId],
|
|
204
|
+
transactionIds: [...transactionIdsBySelectedPeriod],
|
|
205
|
+
transactionReviewLocalDataById: {
|
|
206
|
+
...draft.transactionCategorizationView[selectedTab]
|
|
207
|
+
.transactionReviewLocalDataById,
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
}
|
|
169
211
|
// Reset list when we change the sort order and fetch list again
|
|
170
212
|
if (resetListItems === true) {
|
|
171
|
-
const monthYearPeriod = {
|
|
172
|
-
month: period.start.month,
|
|
173
|
-
year: period.start.year,
|
|
174
|
-
};
|
|
175
|
-
const transactionIdsBySelectedPeriod = draft.transactionCategorizationView[selectedTab]
|
|
176
|
-
.transactionIdsBySelectedPeriod[(0, timePeriod_1.toMonthYearPeriodId)(monthYearPeriod)];
|
|
177
213
|
transactionIdsBySelectedPeriod.forEach((transactionId) => {
|
|
178
214
|
delete draft.transactionCategorizationView[selectedTab]
|
|
179
215
|
.transactionReviewLocalDataById[transactionId];
|
|
180
216
|
});
|
|
181
217
|
draft.transactionCategorizationView[selectedTab].selectedCheckBoxTransactionIds =
|
|
182
218
|
draft.transactionCategorizationView[selectedTab].selectedCheckBoxTransactionIds.filter((selectedCheckBoxTransactionId) => transactionIdsBySelectedPeriod.includes(selectedCheckBoxTransactionId));
|
|
183
|
-
draft.transactionCategorizationView[selectedTab].transactionIdsBySelectedPeriod[
|
|
219
|
+
draft.transactionCategorizationView[selectedTab].transactionIdsBySelectedPeriod[periodId] = [];
|
|
184
220
|
draft.transactionCategorizationView[selectedTab].refreshStatus = {
|
|
185
221
|
fetchState: 'Not-Started',
|
|
186
222
|
error: undefined,
|
|
@@ -312,10 +348,12 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
312
348
|
}
|
|
313
349
|
},
|
|
314
350
|
updateTransactionFilters(draft, action) {
|
|
315
|
-
const {
|
|
316
|
-
//
|
|
317
|
-
//
|
|
318
|
-
|
|
351
|
+
const { filters } = action.payload;
|
|
352
|
+
// Filters are tab-agnostic (payee/category/class/amount), so apply to
|
|
353
|
+
// all tabs so switching tabs after filtering shows consistent results.
|
|
354
|
+
transactionsViewState_1.TRANSACTIONS_TABS.forEach((tab) => {
|
|
355
|
+
draft.transactionCategorizationView[tab].filters = filters;
|
|
356
|
+
});
|
|
319
357
|
},
|
|
320
358
|
saveTransactionCategorization: {
|
|
321
359
|
prepare(selectedTab, transactionIds, cotTrackingByTransactionId, isUncategorizedExpenseCategoryEnabled) {
|
|
@@ -667,19 +705,66 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
667
705
|
resetOtherTabsFetchState(draft, action) {
|
|
668
706
|
const { tabs, refreshViewInBackground } = action.payload;
|
|
669
707
|
tabs.forEach((tab) => {
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
708
|
+
const tabFetchState = draft.transactionCategorizationView[tab].fetchState;
|
|
709
|
+
if (refreshViewInBackground !== true) {
|
|
710
|
+
// Foreground fetch completed: mark other tabs as Completed.
|
|
673
711
|
draft.transactionCategorizationView[tab].fetchState = 'Completed';
|
|
674
712
|
draft.transactionCategorizationView[tab].error = undefined;
|
|
675
713
|
}
|
|
676
|
-
else {
|
|
714
|
+
else if (tabFetchState !== 'In-Progress') {
|
|
715
|
+
// Background fetch completed: reset the other tab's refreshStatus,
|
|
716
|
+
// but only when it is not mid-load. During a dual-search the active
|
|
717
|
+
// tab has its own foreground fetch in flight — clobbering its
|
|
718
|
+
// fetchState here would drop the skeleton and show an empty list.
|
|
677
719
|
draft.transactionCategorizationView[tab].refreshStatus = {
|
|
678
720
|
fetchState: 'Not-Started',
|
|
679
721
|
error: undefined,
|
|
680
722
|
};
|
|
681
723
|
}
|
|
724
|
+
// If tabFetchState === 'In-Progress' and refreshViewInBackground === true,
|
|
725
|
+
// leave the other tab's state untouched — it has its own active fetch.
|
|
726
|
+
});
|
|
727
|
+
},
|
|
728
|
+
restoreFullDatasetSnapshot(draft, action) {
|
|
729
|
+
const { selectedTab, period } = action.payload;
|
|
730
|
+
const periodId = (0, timePeriod_1.toMonthYearPeriodId)({
|
|
731
|
+
month: period.start.month,
|
|
732
|
+
year: period.start.year,
|
|
733
|
+
});
|
|
734
|
+
const snapshot = draft.transactionCategorizationView[selectedTab].fullDatasetSnapshot;
|
|
735
|
+
if (snapshot == null || snapshot.periodId !== periodId) {
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
738
|
+
draft.transactionCategorizationView[selectedTab]
|
|
739
|
+
.transactionIdsBySelectedPeriod[periodId] = snapshot.transactionIds;
|
|
740
|
+
// Merge back per-transaction local data; skip entries that were updated
|
|
741
|
+
// during the search (e.g. a save that happened while filtered results
|
|
742
|
+
// were showing) so those saves are not overwritten.
|
|
743
|
+
Object.entries(snapshot.transactionReviewLocalDataById).forEach(([transactionId, localData]) => {
|
|
744
|
+
if (draft.transactionCategorizationView[selectedTab]
|
|
745
|
+
.transactionReviewLocalDataById[transactionId] == null) {
|
|
746
|
+
draft.transactionCategorizationView[selectedTab]
|
|
747
|
+
.transactionReviewLocalDataById[transactionId] = localData;
|
|
748
|
+
}
|
|
682
749
|
});
|
|
750
|
+
if (snapshot.totalCount != null) {
|
|
751
|
+
draft.transactionCategorizationView[selectedTab].uiState.totalCount[periodId] = snapshot.totalCount;
|
|
752
|
+
}
|
|
753
|
+
if (snapshot.parentTotalCount != null) {
|
|
754
|
+
draft.parentTotalCountByTab[selectedTab][periodId] =
|
|
755
|
+
snapshot.parentTotalCount;
|
|
756
|
+
}
|
|
757
|
+
draft.transactionCategorizationView[selectedTab].uiState.searchString =
|
|
758
|
+
'';
|
|
759
|
+
draft.transactionCategorizationView[selectedTab].uiState.pageToken = null;
|
|
760
|
+
draft.transactionCategorizationView[selectedTab].fetchState = 'Completed';
|
|
761
|
+
draft.transactionCategorizationView[selectedTab].refreshStatus = {
|
|
762
|
+
fetchState: 'Not-Started',
|
|
763
|
+
error: undefined,
|
|
764
|
+
};
|
|
765
|
+
draft.transactionCategorizationView[selectedTab].error = undefined;
|
|
766
|
+
draft.transactionCategorizationView[selectedTab].fullDatasetSnapshot =
|
|
767
|
+
undefined;
|
|
683
768
|
},
|
|
684
769
|
fetchTransactionCategorizationFailure(draft, action) {
|
|
685
770
|
const { selectedTab, selectedPeriod } = action.payload;
|
|
@@ -1009,6 +1094,7 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
1009
1094
|
if (allReviewed) {
|
|
1010
1095
|
if (existsInReview) {
|
|
1011
1096
|
(0, transactionCategorizationLocalDataHelper_1.removeTransactionFromTabView)(reviewTabView, txnId);
|
|
1097
|
+
reviewTabView.fullDatasetSnapshot = undefined;
|
|
1012
1098
|
}
|
|
1013
1099
|
return;
|
|
1014
1100
|
}
|
|
@@ -1055,11 +1141,13 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
1055
1141
|
reducer(draft, action) {
|
|
1056
1142
|
const { transactionId } = action.payload;
|
|
1057
1143
|
for (const tab of transactionsViewState_1.TRANSACTIONS_TABS) {
|
|
1058
|
-
|
|
1144
|
+
const tabView = draft.transactionCategorizationView[tab];
|
|
1145
|
+
(0, transactionCategorizationLocalDataHelper_1.removeTransactionFromTabView)(tabView, transactionId);
|
|
1146
|
+
tabView.fullDatasetSnapshot = undefined;
|
|
1059
1147
|
}
|
|
1060
1148
|
},
|
|
1061
1149
|
},
|
|
1062
1150
|
},
|
|
1063
1151
|
});
|
|
1064
|
-
_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;
|
|
1152
|
+
_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;
|
|
1065
1153
|
exports.default = expenseAutomationTransactionsView.reducer;
|
|
@@ -94,8 +94,24 @@ 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
|
+
parentTotalCount: number | undefined;
|
|
107
|
+
periodId: MonthYearPeriodId;
|
|
108
|
+
totalCount: number | undefined;
|
|
109
|
+
transactionIds: ID[];
|
|
110
|
+
transactionReviewLocalDataById: Record<ID | TransactionDetailKey, SupportedTransactionCategorization>;
|
|
111
|
+
}
|
|
97
112
|
export interface TransactionsTabViewState extends FetchedState {
|
|
98
113
|
filters: TransactionFilters;
|
|
114
|
+
fullDatasetSnapshot: FullDatasetSnapshot | undefined;
|
|
99
115
|
markAsNotMiscategorizedStatus: FetchStateAndError;
|
|
100
116
|
refreshStatus: FetchStateAndError;
|
|
101
117
|
saveStatus: FetchStateAndError;
|
|
@@ -115,7 +115,11 @@ const setupView = (0, toolkit_1.createSlice)({
|
|
|
115
115
|
saveSetupViewDataInLocalStore(draft, action) {
|
|
116
116
|
const setupViewLocalData = action.payload;
|
|
117
117
|
if (setupViewLocalData.companyDetails != null) {
|
|
118
|
-
|
|
118
|
+
const syncToken = setupViewLocalData.companyDetails.syncToken ?? draft.companyDetails.localData?.syncToken;
|
|
119
|
+
draft.companyDetails.localData = {
|
|
120
|
+
...setupViewLocalData.companyDetails,
|
|
121
|
+
...(syncToken != null ? { syncToken } : {}),
|
|
122
|
+
};
|
|
119
123
|
}
|
|
120
124
|
if (setupViewLocalData.primaryContactDetails != null) {
|
|
121
125
|
draft.primaryContactDetails.localData =
|
|
@@ -34,7 +34,6 @@ const initializeTaskToLocalStoreEpic = (actions$, state$) => actions$.pipe((0, o
|
|
|
34
34
|
recurringStartDate: task.recurringStartDate,
|
|
35
35
|
timeSpent: task.timeSpent,
|
|
36
36
|
isPrivate: task.isPrivate,
|
|
37
|
-
taskGroupId: task.taskGroupIds[0],
|
|
38
37
|
};
|
|
39
38
|
const actions = [
|
|
40
39
|
(0, taskDetailReducer_1.saveTaskUpdatesToLocalStore)({ taskDetailLocalData, taskId }),
|
|
@@ -15,17 +15,9 @@ const saveTaskDetailEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, oper
|
|
|
15
15
|
const { taskId, taskGroupId } = action.payload;
|
|
16
16
|
const state = state$.value;
|
|
17
17
|
const isTaskListFetched = state.taskListState.fetchState === 'Completed';
|
|
18
|
-
// For an edit, prefer the locally-edited group (Bug 12). If absent,
|
|
19
|
-
// fall back to the entity's current group. For a create, use the
|
|
20
|
-
// taskGroupId from the action payload.
|
|
21
|
-
const localTaskGroupId = taskId != null
|
|
22
|
-
? state.taskDetailState.editTaskStateById[taskId]?.taskDetailLocalData
|
|
23
|
-
.taskGroupId
|
|
24
|
-
: undefined;
|
|
25
18
|
const updatedTaskGroupId = taskId == null
|
|
26
19
|
? taskGroupId
|
|
27
|
-
: (
|
|
28
|
-
(0, taskSelector_1.getTaskById)(state.taskState, taskId)?.taskGroupIds[0]);
|
|
20
|
+
: (0, taskSelector_1.getTaskById)(state.taskState, taskId)?.taskGroupIds[0];
|
|
29
21
|
const payload = prepareTaskPayload(state, taskId, updatedTaskGroupId);
|
|
30
22
|
const saveTaskApi = taskId != null
|
|
31
23
|
? zeniAPI.putAndGetJSON(`${zeniAPI.apiEndPoints.taskMicroServiceBaseUrl}/1.0/task-manager/tasks/${taskId}`, payload)
|
|
@@ -40,7 +40,6 @@ export interface EditTaskLocalData {
|
|
|
40
40
|
recurringStartDate?: ZeniDate;
|
|
41
41
|
savedRecurringEndDate?: ZeniDate;
|
|
42
42
|
savedRecurringTasksCount?: number;
|
|
43
|
-
taskGroupId?: ID;
|
|
44
43
|
}
|
|
45
44
|
export declare const initialTaskDetailLocalData: EditTaskLocalData;
|
|
46
45
|
export declare const initialTaskDetail: EditTaskDetail;
|
|
@@ -158,8 +158,7 @@ const showFormFooter = (taskDetailLocalData, taskDetailInStore) => {
|
|
|
158
158
|
!(0, isEqual_1.default)(taskDetailLocalData.recurringFrequency, taskDetailInStore.recurringFrequency) ||
|
|
159
159
|
!(0, isEqual_1.default)(taskDetailLocalData.recurringDaysOfWeek, taskDetailInStore.recurringDaysOfWeek) ||
|
|
160
160
|
!(0, isEqual_1.default)(taskDetailLocalData.recurringStartDate, taskDetailInStore.recurringStartDate) ||
|
|
161
|
-
!(0, isEqual_1.default)(taskDetailLocalData.timeSpent, taskDetailInStore.timeSpent)
|
|
162
|
-
!(0, isEqual_1.default)(taskDetailLocalData.taskGroupId, taskDetailInStore.taskGroupIds[0])) {
|
|
161
|
+
!(0, isEqual_1.default)(taskDetailLocalData.timeSpent, taskDetailInStore.timeSpent)) {
|
|
163
162
|
return true;
|
|
164
163
|
}
|
|
165
164
|
return false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zeniai/client-epic-state",
|
|
3
|
-
"version": "5.1.20-
|
|
3
|
+
"version": "5.1.20-betaRD2",
|
|
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",
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { createAction } from '@reduxjs/toolkit';
|
|
2
|
-
import { EMPTY, of } from 'rxjs';
|
|
3
|
-
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
4
|
-
import { isSuccessResponse } from '../../../../responsePayload';
|
|
5
|
-
/**
|
|
6
|
-
* Fire-and-forget action — dispatched by the task-comments UI when a comment
|
|
7
|
-
* is created with @-mentions. The epic POSTs to task-manager's
|
|
8
|
-
* `/comment-mention-notification` endpoint which fans out Slack DMs to each
|
|
9
|
-
* mentioned internal user.
|
|
10
|
-
*
|
|
11
|
-
* Result is intentionally not captured in redux state: comment creation
|
|
12
|
-
* itself is owned by Liveblocks, and a network failure on the notification
|
|
13
|
-
* should not surface in the UI (the comment is still persisted in Liveblocks).
|
|
14
|
-
*/
|
|
15
|
-
export const sendCommentMentionNotification = createAction('taskDetailView/sendCommentMentionNotification', (taskId, mentionedUserIds, performedById) => ({
|
|
16
|
-
payload: { taskId, mentionedUserIds, performedById },
|
|
17
|
-
}));
|
|
18
|
-
export const sendCommentMentionNotificationEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(sendCommentMentionNotification.match), mergeMap((action) => handleSendCommentMentionNotification(action.payload, zeniAPI)));
|
|
19
|
-
const handleSendCommentMentionNotification = ({ taskId, mentionedUserIds, performedById, }, zeniAPI) => {
|
|
20
|
-
// Short-circuit when there's nothing to send. Avoids a useless round-trip
|
|
21
|
-
// (server would also short-circuit with a 200/no-op, but we may as well
|
|
22
|
-
// not enqueue the request at all).
|
|
23
|
-
if (mentionedUserIds.length === 0) {
|
|
24
|
-
return EMPTY;
|
|
25
|
-
}
|
|
26
|
-
const url = `${zeniAPI.apiEndPoints.taskMicroServiceBaseUrl}/1.0/task-manager/tasks/${taskId}/comment-mention-notification`;
|
|
27
|
-
const request$ = zeniAPI.postAndGetJSON(url, {
|
|
28
|
-
mentioned_user_ids: mentionedUserIds,
|
|
29
|
-
performed_by_id: performedById,
|
|
30
|
-
});
|
|
31
|
-
return request$.pipe(mergeMap((response) => {
|
|
32
|
-
if (!isSuccessResponse(response)) {
|
|
33
|
-
// Non-success response — log to console but do not propagate to state.
|
|
34
|
-
// Liveblocks still has the comment; Slack fan-out is best-effort.
|
|
35
|
-
// eslint-disable-next-line no-console
|
|
36
|
-
console.warn('sendCommentMentionNotification non-success response', response);
|
|
37
|
-
}
|
|
38
|
-
return EMPTY;
|
|
39
|
-
}), catchError((error) => {
|
|
40
|
-
// eslint-disable-next-line no-console
|
|
41
|
-
console.warn('sendCommentMentionNotification error', error);
|
|
42
|
-
return of();
|
|
43
|
-
}));
|
|
44
|
-
};
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { ActionsObservable, StateObservable } from 'redux-observable';
|
|
2
|
-
import { RootState } from '../../../../reducer';
|
|
3
|
-
import { ZeniAPI } from '../../../../zeniAPI';
|
|
4
|
-
/**
|
|
5
|
-
* Fire-and-forget action — dispatched by the task-comments UI when a comment
|
|
6
|
-
* is created with @-mentions. The epic POSTs to task-manager's
|
|
7
|
-
* `/comment-mention-notification` endpoint which fans out Slack DMs to each
|
|
8
|
-
* mentioned internal user.
|
|
9
|
-
*
|
|
10
|
-
* Result is intentionally not captured in redux state: comment creation
|
|
11
|
-
* itself is owned by Liveblocks, and a network failure on the notification
|
|
12
|
-
* should not surface in the UI (the comment is still persisted in Liveblocks).
|
|
13
|
-
*/
|
|
14
|
-
export declare const sendCommentMentionNotification: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[taskId: string, mentionedUserIds: string[], performedById: string], {
|
|
15
|
-
taskId: string;
|
|
16
|
-
mentionedUserIds: string[];
|
|
17
|
-
performedById: string;
|
|
18
|
-
}, "taskDetailView/sendCommentMentionNotification", never, never>;
|
|
19
|
-
export type ActionType = ReturnType<typeof sendCommentMentionNotification>;
|
|
20
|
-
export declare const sendCommentMentionNotificationEpic: (actions$: ActionsObservable<ActionType>, _state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => import("rxjs").Observable<unknown>;
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.sendCommentMentionNotificationEpic = exports.sendCommentMentionNotification = void 0;
|
|
4
|
-
const toolkit_1 = require("@reduxjs/toolkit");
|
|
5
|
-
const rxjs_1 = require("rxjs");
|
|
6
|
-
const operators_1 = require("rxjs/operators");
|
|
7
|
-
const responsePayload_1 = require("../../../../responsePayload");
|
|
8
|
-
/**
|
|
9
|
-
* Fire-and-forget action — dispatched by the task-comments UI when a comment
|
|
10
|
-
* is created with @-mentions. The epic POSTs to task-manager's
|
|
11
|
-
* `/comment-mention-notification` endpoint which fans out Slack DMs to each
|
|
12
|
-
* mentioned internal user.
|
|
13
|
-
*
|
|
14
|
-
* Result is intentionally not captured in redux state: comment creation
|
|
15
|
-
* itself is owned by Liveblocks, and a network failure on the notification
|
|
16
|
-
* should not surface in the UI (the comment is still persisted in Liveblocks).
|
|
17
|
-
*/
|
|
18
|
-
exports.sendCommentMentionNotification = (0, toolkit_1.createAction)('taskDetailView/sendCommentMentionNotification', (taskId, mentionedUserIds, performedById) => ({
|
|
19
|
-
payload: { taskId, mentionedUserIds, performedById },
|
|
20
|
-
}));
|
|
21
|
-
const sendCommentMentionNotificationEpic = (actions$, _state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(exports.sendCommentMentionNotification.match), (0, operators_1.mergeMap)((action) => handleSendCommentMentionNotification(action.payload, zeniAPI)));
|
|
22
|
-
exports.sendCommentMentionNotificationEpic = sendCommentMentionNotificationEpic;
|
|
23
|
-
const handleSendCommentMentionNotification = ({ taskId, mentionedUserIds, performedById, }, zeniAPI) => {
|
|
24
|
-
// Short-circuit when there's nothing to send. Avoids a useless round-trip
|
|
25
|
-
// (server would also short-circuit with a 200/no-op, but we may as well
|
|
26
|
-
// not enqueue the request at all).
|
|
27
|
-
if (mentionedUserIds.length === 0) {
|
|
28
|
-
return rxjs_1.EMPTY;
|
|
29
|
-
}
|
|
30
|
-
const url = `${zeniAPI.apiEndPoints.taskMicroServiceBaseUrl}/1.0/task-manager/tasks/${taskId}/comment-mention-notification`;
|
|
31
|
-
const request$ = zeniAPI.postAndGetJSON(url, {
|
|
32
|
-
mentioned_user_ids: mentionedUserIds,
|
|
33
|
-
performed_by_id: performedById,
|
|
34
|
-
});
|
|
35
|
-
return request$.pipe((0, operators_1.mergeMap)((response) => {
|
|
36
|
-
if (!(0, responsePayload_1.isSuccessResponse)(response)) {
|
|
37
|
-
// Non-success response — log to console but do not propagate to state.
|
|
38
|
-
// Liveblocks still has the comment; Slack fan-out is best-effort.
|
|
39
|
-
// eslint-disable-next-line no-console
|
|
40
|
-
console.warn('sendCommentMentionNotification non-success response', response);
|
|
41
|
-
}
|
|
42
|
-
return rxjs_1.EMPTY;
|
|
43
|
-
}), (0, operators_1.catchError)((error) => {
|
|
44
|
-
// eslint-disable-next-line no-console
|
|
45
|
-
console.warn('sendCommentMentionNotification error', error);
|
|
46
|
-
return (0, rxjs_1.of)();
|
|
47
|
-
}));
|
|
48
|
-
};
|