@zeniai/client-epic-state 5.1.53 → 5.1.54-betaRD1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,7 +5,7 @@ import { getTransactionWithCOT, getTransactionWithCOTFromRecommendations, } from
5
5
  import { createZeniAPIStatus, isSuccessResponse } from '../../responsePayload';
6
6
  import { getUncategorizedAccounts } from '../accountList/accountListSelector';
7
7
  import { markCategoryClassRecommendationsCompletedForCategorization, markCategoryClassRecommendationsFailureForCategorization, markCategoryClassRecommendationsInProgressForCategorization, setEntityRecommendationForLineIdsForCategorization, } from '../expenseAutomationView/reducers/transactionsViewReducer';
8
- import { markCategoryClassRecommendationsCompletedForTransactionDetail, markCategoryClassRecommendationsFailureForTransactionDetail, markCategoryClassRecommendationsInProgressForTransactionDetail, setEntityRecommendationForLineIdsForTransactionDetail, } from '../transactionDetail/transactionDetailReducer';
8
+ import { markCategoryClassRecommendationsCompletedForTransactionDetail, markCategoryClassRecommendationsFailureForTransactionDetail, markCategoryClassRecommendationsInProgressForTransactionDetail, setEntityRecommendationForLineIdsForTransactionDetail, updateVendorBulkRecommendationsFetchStatus, } from '../transactionDetail/transactionDetailReducer';
9
9
  import { buildRecommendationUrl, getRecommendationByLineIdWithCOTFromRecommendationPayloadWithCOT, } from './recommendationHelper';
10
10
  import { fetchEntityRecommendationsForLineUpdate } from './recommendationReducer';
11
11
  // Close the per-target groupBy bucket after this much idle time so inactive
@@ -38,6 +38,16 @@ export const fetchEntityRecommendationsForLineUpdateEpic = (actions$, state$, ze
38
38
  const payload = action.payload;
39
39
  const { transactionId, transaction, lineIds } = payload.transactionDetails;
40
40
  const { entity, amount, isFetchCOT, isUncategorizedExpenseCategoryEnabled, } = payload;
41
+ // The vendor "Update all lines" popup on the detail page watches
42
+ // its own transaction-level fetch status, separate from the
43
+ // per-line statuses below — surface completion/failure there too
44
+ // when this fetch was triggered by that bulk action, or the popup
45
+ // hangs until its own 60s timeout regardless of how this request
46
+ // resolves.
47
+ const isBulkDetailFetch = payload.flowType === 'detail' && payload.isBulkFetch === true;
48
+ const emitWithBulkStatus = (primaryAction, bulkAction) => isBulkDetailFetch && bulkAction != null
49
+ ? of(primaryAction, bulkAction)
50
+ : of(primaryAction);
41
51
  // Synchronously emit the start arm so the per-line skeleton +
42
52
  // row uncheck happen before the HTTP request begins. The
43
53
  // discriminated-union payload narrows `payload.selectedTab` to
@@ -51,9 +61,9 @@ export const fetchEntityRecommendationsForLineUpdateEpic = (actions$, state$, ze
51
61
  .getJSON(url)
52
62
  .pipe(mergeMap((response) => {
53
63
  if (!isSuccessResponse(response) || response.data == null) {
54
- return of(payload.flowType === 'categorization'
64
+ return emitWithBulkStatus(payload.flowType === 'categorization'
55
65
  ? markCategoryClassRecommendationsFailureForCategorization(payload.selectedTab, transactionId, lineIds, response.status)
56
- : markCategoryClassRecommendationsFailureForTransactionDetail(transactionId, lineIds, response.status));
66
+ : markCategoryClassRecommendationsFailureForTransactionDetail(transactionId, lineIds, response.status), updateVendorBulkRecommendationsFetchStatus(transactionId, 'Error', response.status));
57
67
  }
58
68
  const recommendationWithCOTByLineId = getRecommendationByLineIdWithCOTFromRecommendationPayloadWithCOT(response.data.recommendations, lineIds);
59
69
  // HTTP 200 with no per-line recommendations: NOT an error.
@@ -61,9 +71,9 @@ export const fetchEntityRecommendationsForLineUpdateEpic = (actions$, state$, ze
61
71
  // downstream UI can treat this as "we tried, nothing to
62
72
  // apply".
63
73
  if (recommendationWithCOTByLineId == null) {
64
- return of(payload.flowType === 'categorization'
74
+ return emitWithBulkStatus(payload.flowType === 'categorization'
65
75
  ? markCategoryClassRecommendationsCompletedForCategorization(payload.selectedTab, transactionId, lineIds)
66
- : markCategoryClassRecommendationsCompletedForTransactionDetail(transactionId, lineIds));
76
+ : markCategoryClassRecommendationsCompletedForTransactionDetail(transactionId, lineIds), updateVendorBulkRecommendationsFetchStatus(transactionId, 'Completed'));
67
77
  }
68
78
  const transactionWithCOT = isFetchCOT === true
69
79
  ? getTransactionWithCOTFromRecommendations(transaction, recommendationWithCOTByLineId)
@@ -72,16 +82,16 @@ export const fetchEntityRecommendationsForLineUpdateEpic = (actions$, state$, ze
72
82
  if (payload.flowType === 'categorization') {
73
83
  return of(setEntityRecommendationForLineIdsForCategorization(payload.selectedTab, transactionId, transactionWithCOT, lineIds, entity, amount, recommendationWithCOTByLineId, uncategorizedIncomeExpense, isUncategorizedExpenseCategoryEnabled, getIsAccountingClassesEnabled(state$.value)));
74
84
  }
75
- return of(setEntityRecommendationForLineIdsForTransactionDetail(transactionId, transactionWithCOT, lineIds, entity, amount, recommendationWithCOTByLineId, uncategorizedIncomeExpense));
85
+ return emitWithBulkStatus(setEntityRecommendationForLineIdsForTransactionDetail(transactionId, transactionWithCOT, lineIds, entity, amount, recommendationWithCOTByLineId, uncategorizedIncomeExpense), updateVendorBulkRecommendationsFetchStatus(transactionId, 'Completed'));
76
86
  }), catchError((error) => {
77
87
  const errorMessage = 'fetchEntityRecommendationsForLineUpdate failed: ' +
78
88
  (error instanceof Error
79
89
  ? error.message
80
90
  : JSON.stringify(error));
81
91
  const status = createZeniAPIStatus('Unexpected Error', errorMessage);
82
- return of(payload.flowType === 'categorization'
92
+ return emitWithBulkStatus(payload.flowType === 'categorization'
83
93
  ? markCategoryClassRecommendationsFailureForCategorization(payload.selectedTab, transactionId, lineIds, status)
84
- : markCategoryClassRecommendationsFailureForTransactionDetail(transactionId, lineIds, status));
94
+ : markCategoryClassRecommendationsFailureForTransactionDetail(transactionId, lineIds, status), updateVendorBulkRecommendationsFetchStatus(transactionId, 'Error', status));
85
95
  }));
86
96
  return concat(of(startAction), httpStream$);
87
97
  }))));
@@ -3,7 +3,7 @@ import { Observable } from 'rxjs';
3
3
  import { RootState } from '../../reducer';
4
4
  import { ZeniAPI } from '../../zeniAPI';
5
5
  import { markCategoryClassRecommendationsCompletedForCategorization, markCategoryClassRecommendationsFailureForCategorization, markCategoryClassRecommendationsInProgressForCategorization, setEntityRecommendationForLineIdsForCategorization } from '../expenseAutomationView/reducers/transactionsViewReducer';
6
- import { markCategoryClassRecommendationsCompletedForTransactionDetail, markCategoryClassRecommendationsFailureForTransactionDetail, markCategoryClassRecommendationsInProgressForTransactionDetail, setEntityRecommendationForLineIdsForTransactionDetail } from '../transactionDetail/transactionDetailReducer';
6
+ import { markCategoryClassRecommendationsCompletedForTransactionDetail, markCategoryClassRecommendationsFailureForTransactionDetail, markCategoryClassRecommendationsInProgressForTransactionDetail, setEntityRecommendationForLineIdsForTransactionDetail, updateVendorBulkRecommendationsFetchStatus } from '../transactionDetail/transactionDetailReducer';
7
7
  import { fetchEntityRecommendationsForLineUpdate } from './recommendationReducer';
8
- export type ActionType = ReturnType<typeof fetchEntityRecommendationsForLineUpdate> | ReturnType<typeof markCategoryClassRecommendationsInProgressForCategorization> | ReturnType<typeof markCategoryClassRecommendationsCompletedForCategorization> | ReturnType<typeof markCategoryClassRecommendationsFailureForCategorization> | ReturnType<typeof markCategoryClassRecommendationsInProgressForTransactionDetail> | ReturnType<typeof markCategoryClassRecommendationsCompletedForTransactionDetail> | ReturnType<typeof markCategoryClassRecommendationsFailureForTransactionDetail> | ReturnType<typeof setEntityRecommendationForLineIdsForCategorization> | ReturnType<typeof setEntityRecommendationForLineIdsForTransactionDetail>;
8
+ export type ActionType = ReturnType<typeof fetchEntityRecommendationsForLineUpdate> | ReturnType<typeof markCategoryClassRecommendationsInProgressForCategorization> | ReturnType<typeof markCategoryClassRecommendationsCompletedForCategorization> | ReturnType<typeof markCategoryClassRecommendationsFailureForCategorization> | ReturnType<typeof markCategoryClassRecommendationsInProgressForTransactionDetail> | ReturnType<typeof markCategoryClassRecommendationsCompletedForTransactionDetail> | ReturnType<typeof markCategoryClassRecommendationsFailureForTransactionDetail> | ReturnType<typeof setEntityRecommendationForLineIdsForCategorization> | ReturnType<typeof setEntityRecommendationForLineIdsForTransactionDetail> | ReturnType<typeof updateVendorBulkRecommendationsFetchStatus>;
9
9
  export declare const fetchEntityRecommendationsForLineUpdateEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<ActionType>;
@@ -41,6 +41,16 @@ const fetchEntityRecommendationsForLineUpdateEpic = (actions$, state$, zeniAPI)
41
41
  const payload = action.payload;
42
42
  const { transactionId, transaction, lineIds } = payload.transactionDetails;
43
43
  const { entity, amount, isFetchCOT, isUncategorizedExpenseCategoryEnabled, } = payload;
44
+ // The vendor "Update all lines" popup on the detail page watches
45
+ // its own transaction-level fetch status, separate from the
46
+ // per-line statuses below — surface completion/failure there too
47
+ // when this fetch was triggered by that bulk action, or the popup
48
+ // hangs until its own 60s timeout regardless of how this request
49
+ // resolves.
50
+ const isBulkDetailFetch = payload.flowType === 'detail' && payload.isBulkFetch === true;
51
+ const emitWithBulkStatus = (primaryAction, bulkAction) => isBulkDetailFetch && bulkAction != null
52
+ ? (0, rxjs_1.of)(primaryAction, bulkAction)
53
+ : (0, rxjs_1.of)(primaryAction);
44
54
  // Synchronously emit the start arm so the per-line skeleton +
45
55
  // row uncheck happen before the HTTP request begins. The
46
56
  // discriminated-union payload narrows `payload.selectedTab` to
@@ -54,9 +64,9 @@ const fetchEntityRecommendationsForLineUpdateEpic = (actions$, state$, zeniAPI)
54
64
  .getJSON(url)
55
65
  .pipe((0, operators_1.mergeMap)((response) => {
56
66
  if (!(0, responsePayload_1.isSuccessResponse)(response) || response.data == null) {
57
- return (0, rxjs_1.of)(payload.flowType === 'categorization'
67
+ return emitWithBulkStatus(payload.flowType === 'categorization'
58
68
  ? (0, transactionsViewReducer_1.markCategoryClassRecommendationsFailureForCategorization)(payload.selectedTab, transactionId, lineIds, response.status)
59
- : (0, transactionDetailReducer_1.markCategoryClassRecommendationsFailureForTransactionDetail)(transactionId, lineIds, response.status));
69
+ : (0, transactionDetailReducer_1.markCategoryClassRecommendationsFailureForTransactionDetail)(transactionId, lineIds, response.status), (0, transactionDetailReducer_1.updateVendorBulkRecommendationsFetchStatus)(transactionId, 'Error', response.status));
60
70
  }
61
71
  const recommendationWithCOTByLineId = (0, recommendationHelper_1.getRecommendationByLineIdWithCOTFromRecommendationPayloadWithCOT)(response.data.recommendations, lineIds);
62
72
  // HTTP 200 with no per-line recommendations: NOT an error.
@@ -64,9 +74,9 @@ const fetchEntityRecommendationsForLineUpdateEpic = (actions$, state$, zeniAPI)
64
74
  // downstream UI can treat this as "we tried, nothing to
65
75
  // apply".
66
76
  if (recommendationWithCOTByLineId == null) {
67
- return (0, rxjs_1.of)(payload.flowType === 'categorization'
77
+ return emitWithBulkStatus(payload.flowType === 'categorization'
68
78
  ? (0, transactionsViewReducer_1.markCategoryClassRecommendationsCompletedForCategorization)(payload.selectedTab, transactionId, lineIds)
69
- : (0, transactionDetailReducer_1.markCategoryClassRecommendationsCompletedForTransactionDetail)(transactionId, lineIds));
79
+ : (0, transactionDetailReducer_1.markCategoryClassRecommendationsCompletedForTransactionDetail)(transactionId, lineIds), (0, transactionDetailReducer_1.updateVendorBulkRecommendationsFetchStatus)(transactionId, 'Completed'));
70
80
  }
71
81
  const transactionWithCOT = isFetchCOT === true
72
82
  ? (0, transactionHelper_1.getTransactionWithCOTFromRecommendations)(transaction, recommendationWithCOTByLineId)
@@ -75,16 +85,16 @@ const fetchEntityRecommendationsForLineUpdateEpic = (actions$, state$, zeniAPI)
75
85
  if (payload.flowType === 'categorization') {
76
86
  return (0, rxjs_1.of)((0, transactionsViewReducer_1.setEntityRecommendationForLineIdsForCategorization)(payload.selectedTab, transactionId, transactionWithCOT, lineIds, entity, amount, recommendationWithCOTByLineId, uncategorizedIncomeExpense, isUncategorizedExpenseCategoryEnabled, (0, tenantSelector_1.getIsAccountingClassesEnabled)(state$.value)));
77
87
  }
78
- return (0, rxjs_1.of)((0, transactionDetailReducer_1.setEntityRecommendationForLineIdsForTransactionDetail)(transactionId, transactionWithCOT, lineIds, entity, amount, recommendationWithCOTByLineId, uncategorizedIncomeExpense));
88
+ return emitWithBulkStatus((0, transactionDetailReducer_1.setEntityRecommendationForLineIdsForTransactionDetail)(transactionId, transactionWithCOT, lineIds, entity, amount, recommendationWithCOTByLineId, uncategorizedIncomeExpense), (0, transactionDetailReducer_1.updateVendorBulkRecommendationsFetchStatus)(transactionId, 'Completed'));
79
89
  }), (0, operators_1.catchError)((error) => {
80
90
  const errorMessage = 'fetchEntityRecommendationsForLineUpdate failed: ' +
81
91
  (error instanceof Error
82
92
  ? error.message
83
93
  : JSON.stringify(error));
84
94
  const status = (0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', errorMessage);
85
- return (0, rxjs_1.of)(payload.flowType === 'categorization'
95
+ return emitWithBulkStatus(payload.flowType === 'categorization'
86
96
  ? (0, transactionsViewReducer_1.markCategoryClassRecommendationsFailureForCategorization)(payload.selectedTab, transactionId, lineIds, status)
87
- : (0, transactionDetailReducer_1.markCategoryClassRecommendationsFailureForTransactionDetail)(transactionId, lineIds, status));
97
+ : (0, transactionDetailReducer_1.markCategoryClassRecommendationsFailureForTransactionDetail)(transactionId, lineIds, status), (0, transactionDetailReducer_1.updateVendorBulkRecommendationsFetchStatus)(transactionId, 'Error', status));
88
98
  }));
89
99
  return (0, rxjs_1.concat)((0, rxjs_1.of)(startAction), httpStream$);
90
100
  }))));
@@ -15,6 +15,7 @@ type FetchEntityRecommendationsForLineUpdateCommonPayload = {
15
15
  transaction: SupportedTransaction;
16
16
  transactionId: TransactionID;
17
17
  };
18
+ isBulkFetch?: boolean;
18
19
  isFetchCOT?: boolean;
19
20
  isUncategorizedExpenseCategoryEnabled?: boolean;
20
21
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeniai/client-epic-state",
3
- "version": "5.1.53",
3
+ "version": "5.1.54-betaRD1",
4
4
  "description": "Shared module between Web & Mobile containing required abstractions for state management, async network communication. ",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/esm/index.js",