@zeniai/client-epic-state 5.0.69-betaML2 → 5.0.69-betaML31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/lib/commonStateTypes/viewAndReport/viewAndReport.d.ts +2 -2
  2. package/lib/commonStateTypes/viewAndReport/viewAndReport.js +0 -2
  3. package/lib/entity/account/accountSelector.d.ts +0 -9
  4. package/lib/entity/account/accountSelector.js +1 -14
  5. package/lib/entity/account/accountState.d.ts +1 -1
  6. package/lib/entity/accountGroup/accountGroupState.d.ts +1 -1
  7. package/lib/entity/class/classReducer.d.ts +4 -4
  8. package/lib/entity/class/classState.d.ts +1 -1
  9. package/lib/entity/forecast/forecastState.d.ts +1 -1
  10. package/lib/entity/sectionAccountsView/sectionAccountsView.d.ts +1 -1
  11. package/lib/entity/sectionClassesViewV2/sectionClassesView.d.ts +1 -1
  12. package/lib/entity/sectionClassesViewV2/sectionClassesViewReducer.d.ts +2 -2
  13. package/lib/entity/sectionProjectView/sectionProjectView.d.ts +1 -1
  14. package/lib/entity/sectionProjectView/sectionProjectViewReducer.d.ts +2 -2
  15. package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
  16. package/lib/entity/snackbar/snackbarTypes.js +0 -2
  17. package/lib/entity/transaction/payloadTypes/transactionPayload.d.ts +0 -4
  18. package/lib/entity/transaction/payloadTypes/transactionPayload.js +0 -10
  19. package/lib/entity/transaction/stateTypes/transaction.d.ts +0 -3
  20. package/lib/epic.d.ts +2 -3
  21. package/lib/epic.js +2 -3
  22. package/lib/esm/commonStateTypes/viewAndReport/viewAndReport.js +0 -2
  23. package/lib/esm/entity/account/accountSelector.js +0 -11
  24. package/lib/esm/entity/snackbar/snackbarTypes.js +0 -2
  25. package/lib/esm/entity/transaction/payloadTypes/transactionPayload.js +0 -10
  26. package/lib/esm/epic.js +2 -3
  27. package/lib/esm/index.js +8 -9
  28. package/lib/esm/reducer.js +0 -3
  29. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic.js +0 -8
  30. package/lib/esm/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js +21 -1
  31. package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +117 -26
  32. package/lib/esm/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +59 -9
  33. package/lib/esm/view/recommendation/fetchEntityRecommendationsForLineUpdateEpic.js +83 -0
  34. package/lib/esm/view/recommendation/recommendationHelper.js +29 -0
  35. package/lib/esm/view/recommendation/recommendationReducer.js +36 -1
  36. package/lib/esm/view/transactionDetail/epics/transactionDetailEpic.js +2 -14
  37. package/lib/esm/view/transactionDetail/transactionDetailReducer.js +122 -8
  38. package/lib/esm/view/transactionDetail/transactionDetailSelector.js +24 -7
  39. package/lib/index.d.ts +9 -9
  40. package/lib/index.js +36 -43
  41. package/lib/reducer.d.ts +0 -3
  42. package/lib/reducer.js +0 -3
  43. package/lib/tsconfig.typecheck.tsbuildinfo +1 -0
  44. package/lib/view/auditReportView/auditReportViewState.d.ts +1 -1
  45. package/lib/view/billPayCard/billPayCardSelector.d.ts +1 -1
  46. package/lib/view/cardBalance/cardBalanceSelector.d.ts +1 -1
  47. package/lib/view/cashBalance/cashBalanceSelector.d.ts +1 -1
  48. package/lib/view/cashInCashOut/cashInCashOutSelector.d.ts +1 -1
  49. package/lib/view/cashPosition/cashPositionSelector.d.ts +1 -1
  50. package/lib/view/dashboard/dashboardReducer.d.ts +2 -2
  51. package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic.d.ts +1 -2
  52. package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationViewEpic.js +0 -8
  53. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +2 -1
  54. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js +23 -2
  55. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.d.ts +15 -4
  56. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +117 -26
  57. package/lib/view/expenseAutomationView/selectorTypes/transactionsViewSelectorTypes.d.ts +3 -4
  58. package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.d.ts +3 -1
  59. package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +61 -11
  60. package/lib/view/expenseAutomationView/types/transactionsViewState.d.ts +1 -0
  61. package/lib/view/financeStatement/financeStatementReducer.d.ts +1 -1
  62. package/lib/view/globalMerchantView/globalMerchantViewReducer.d.ts +2 -2
  63. package/lib/view/recommendation/fetchEntityRecommendationsForLineUpdateEpic.d.ts +9 -0
  64. package/lib/view/recommendation/fetchEntityRecommendationsForLineUpdateEpic.js +87 -0
  65. package/lib/view/recommendation/recommendationHelper.d.ts +9 -0
  66. package/lib/view/recommendation/recommendationHelper.js +31 -1
  67. package/lib/view/recommendation/recommendationReducer.d.ts +18 -1
  68. package/lib/view/recommendation/recommendationReducer.js +37 -2
  69. package/lib/view/reimbursementCard/reimbursementCardSelector.d.ts +1 -1
  70. package/lib/view/reportsResync/reportsResyncReducer.d.ts +2 -2
  71. package/lib/view/tasksCard/tasksCardSelector.d.ts +1 -1
  72. package/lib/view/topEx/topExSelector.d.ts +1 -1
  73. package/lib/view/transactionDetail/epics/transactionDetailEpic.d.ts +1 -2
  74. package/lib/view/transactionDetail/epics/transactionDetailEpic.js +2 -14
  75. package/lib/view/transactionDetail/transactionDetailPayload.d.ts +1 -1
  76. package/lib/view/transactionDetail/transactionDetailReducer.d.ts +12 -3
  77. package/lib/view/transactionDetail/transactionDetailReducer.js +123 -9
  78. package/lib/view/transactionDetail/transactionDetailSelector.d.ts +3 -6
  79. package/lib/view/transactionDetail/transactionDetailSelector.js +25 -7
  80. package/lib/view/transactionDetail/transactionDetailTypes.d.ts +1 -0
  81. package/package.json +1 -1
  82. package/lib/esm/view/createTransferEntry/createTransferEntryReducer.js +0 -56
  83. package/lib/esm/view/createTransferEntry/createTransferEntrySelector.js +0 -63
  84. package/lib/esm/view/createTransferEntry/createTransferEntryState.js +0 -17
  85. package/lib/esm/view/createTransferEntry/epics/createTransferEntryEpic.js +0 -112
  86. package/lib/esm/view/createTransferEntry/epics/fetchTransferAccountsEpic.js +0 -36
  87. package/lib/view/createTransferEntry/createTransferEntryReducer.d.ts +0 -32
  88. package/lib/view/createTransferEntry/createTransferEntryReducer.js +0 -60
  89. package/lib/view/createTransferEntry/createTransferEntrySelector.d.ts +0 -38
  90. package/lib/view/createTransferEntry/createTransferEntrySelector.js +0 -68
  91. package/lib/view/createTransferEntry/createTransferEntryState.d.ts +0 -30
  92. package/lib/view/createTransferEntry/createTransferEntryState.js +0 -20
  93. package/lib/view/createTransferEntry/epics/createTransferEntryEpic.d.ts +0 -11
  94. package/lib/view/createTransferEntry/epics/createTransferEntryEpic.js +0 -116
  95. package/lib/view/createTransferEntry/epics/fetchTransferAccountsEpic.d.ts +0 -14
  96. package/lib/view/createTransferEntry/epics/fetchTransferAccountsEpic.js +0 -40
@@ -15,10 +15,9 @@ export declare const downloadAccountingProviderAttachment: import("@reduxjs/tool
15
15
  }, "transactionDetail/downloadAccountingProviderAttachment", never, never>, downloadAccountingProviderAttachmentSuccess: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
16
16
  attachmentId: ID;
17
17
  data: ArrayBuffer;
18
- }, "transactionDetail/downloadAccountingProviderAttachmentSuccess">, downloadAccountingProviderAttachmentFailure: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"transactionDetail/downloadAccountingProviderAttachmentFailure">, fetchTransactionDetail: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[transactionId: TransactionID, cacheOverride?: any, isCreateTransferEntryFromExpenseEnabled?: any], {
18
+ }, "transactionDetail/downloadAccountingProviderAttachmentSuccess">, downloadAccountingProviderAttachmentFailure: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"transactionDetail/downloadAccountingProviderAttachmentFailure">, fetchTransactionDetail: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[transactionId: TransactionID, cacheOverride?: any], {
19
19
  transactionId: TransactionID;
20
20
  cacheOverride: any;
21
- isCreateTransferEntryFromExpenseEnabled: any;
22
21
  }, "transactionDetail/fetchTransactionDetail", never, never>, updateTransactionDetailFetchState: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[transactionId: TransactionID, fetchState: FetchState, error?: ZeniAPIStatus<Record<string, unknown>> | undefined], {
23
22
  transactionId: TransactionID;
24
23
  fetchState: FetchState;
@@ -116,7 +115,17 @@ export declare const downloadAccountingProviderAttachment: import("@reduxjs/tool
116
115
  amount: number;
117
116
  recommendationWithCOTByLineId: RecommendationWithCOTByLineId;
118
117
  uncategorizedIncomeExpense: UncategorizedAccounts;
119
- }, "transactionDetail/setEntityRecommendationForLineIdsForTransactionDetail", never, never>, removeEntityRecommendationForLineIdForTransactionDetail: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[transactionId: TransactionID, transaction: SupportedTransaction, lineId: string], {
118
+ }, "transactionDetail/setEntityRecommendationForLineIdsForTransactionDetail", never, never>, markCategoryClassRecommendationsInProgressForTransactionDetail: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[transactionId: TransactionID, lineIds: string[]], {
119
+ transactionId: TransactionID;
120
+ lineIds: string[];
121
+ }, "transactionDetail/markCategoryClassRecommendationsInProgressForTransactionDetail", never, never>, markCategoryClassRecommendationsCompletedForTransactionDetail: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[transactionId: TransactionID, lineIds: string[]], {
122
+ transactionId: TransactionID;
123
+ lineIds: string[];
124
+ }, "transactionDetail/markCategoryClassRecommendationsCompletedForTransactionDetail", never, never>, markCategoryClassRecommendationsFailureForTransactionDetail: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[transactionId: TransactionID, lineIds: string[], error: ZeniAPIStatus<Record<string, unknown>>], {
125
+ transactionId: TransactionID;
126
+ lineIds: string[];
127
+ error: ZeniAPIStatus<Record<string, unknown>>;
128
+ }, "transactionDetail/markCategoryClassRecommendationsFailureForTransactionDetail", never, never>, removeEntityRecommendationForLineIdForTransactionDetail: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[transactionId: TransactionID, transaction: SupportedTransaction, lineId: string], {
120
129
  transactionId: TransactionID;
121
130
  transaction: SupportedTransaction;
122
131
  lineId: string;
@@ -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.setIsVendorUpdateAllChecked = exports.updateVendorBulkRecommendationsFetchStatus = exports.updateLatestSelectedEntity = exports.resetAllLineItemsToVendor = exports.updateVendorToAllLineItems = exports.updateLocalDataWithTransactionsUpdateWithVendorCheckbox = exports.resetSelectedCustomer = exports.resetVendor = exports.updateSelectedCustomer = exports.updateSelectedVendor = exports.removeEntityRecommendationForLineIdForTransactionDetail = exports.setEntityRecommendationForLineIdsForTransactionDetail = exports.setAllLineItemsLocalDataIsUpdateAllChecked = exports.setAllLineItemsToCategoryClassInLocalData = exports.resetLineItemsCategoryClassInLocalData = exports.clearTransactionDetailLocalData = exports.saveTransactionDetailLocalData = exports.initializeTransactionDetailLocalData = exports.saveTransactionDetail = exports.updateTransactionStateIfUpdateActionNotAllowed = exports.updateStatusConsolidatedSaveTransactionDetail = exports.updateStatusForTransactionNotMiscategorizedUpdate = exports.deleteTransactionAttachmentSuccess = exports.deleteTransactionAttachmentFailure = exports.deleteTransactionAttachment = exports.markTransactionAsNotMiscategorized = exports.clearTransactionDetailSaveStatus = exports.updateTransactionDetailSaveStatus = exports.updateTransactionDetail = exports.uploadMissingAttachmentSuccess = exports.clearTransactionDetail = exports.removeTransactionDetail = exports.updateTransactionDetailFetchState = exports.fetchTransactionDetail = exports.downloadAccountingProviderAttachmentFailure = exports.downloadAccountingProviderAttachmentSuccess = exports.downloadAccountingProviderAttachment = exports.initialState = void 0;
7
+ exports.setIsVendorUpdateAllChecked = exports.updateVendorBulkRecommendationsFetchStatus = exports.updateLatestSelectedEntity = exports.resetAllLineItemsToVendor = exports.updateVendorToAllLineItems = exports.updateLocalDataWithTransactionsUpdateWithVendorCheckbox = exports.resetSelectedCustomer = exports.resetVendor = exports.updateSelectedCustomer = exports.updateSelectedVendor = exports.removeEntityRecommendationForLineIdForTransactionDetail = exports.markCategoryClassRecommendationsFailureForTransactionDetail = exports.markCategoryClassRecommendationsCompletedForTransactionDetail = exports.markCategoryClassRecommendationsInProgressForTransactionDetail = exports.setEntityRecommendationForLineIdsForTransactionDetail = exports.setAllLineItemsLocalDataIsUpdateAllChecked = exports.setAllLineItemsToCategoryClassInLocalData = exports.resetLineItemsCategoryClassInLocalData = exports.clearTransactionDetailLocalData = exports.saveTransactionDetailLocalData = exports.initializeTransactionDetailLocalData = exports.saveTransactionDetail = exports.updateTransactionStateIfUpdateActionNotAllowed = exports.updateStatusConsolidatedSaveTransactionDetail = exports.updateStatusForTransactionNotMiscategorizedUpdate = exports.deleteTransactionAttachmentSuccess = exports.deleteTransactionAttachmentFailure = exports.deleteTransactionAttachment = exports.markTransactionAsNotMiscategorized = exports.clearTransactionDetailSaveStatus = exports.updateTransactionDetailSaveStatus = exports.updateTransactionDetail = exports.uploadMissingAttachmentSuccess = exports.clearTransactionDetail = exports.removeTransactionDetail = exports.updateTransactionDetailFetchState = exports.fetchTransactionDetail = exports.downloadAccountingProviderAttachmentFailure = exports.downloadAccountingProviderAttachmentSuccess = exports.downloadAccountingProviderAttachment = exports.initialState = void 0;
8
8
  const toolkit_1 = require("@reduxjs/toolkit");
9
9
  const get_1 = __importDefault(require("lodash/get"));
10
10
  const entity_1 = require("../../entity/genericEntity/entity");
@@ -57,12 +57,11 @@ const transactionDetail = (0, toolkit_1.createSlice)({
57
57
  };
58
58
  }
59
59
  },
60
- prepare(transactionId, cacheOverride = false, isCreateTransferEntryFromExpenseEnabled = false) {
60
+ prepare(transactionId, cacheOverride = false) {
61
61
  return {
62
62
  payload: {
63
63
  transactionId,
64
64
  cacheOverride,
65
- isCreateTransferEntryFromExpenseEnabled,
66
65
  },
67
66
  };
68
67
  },
@@ -246,12 +245,34 @@ const transactionDetail = (0, toolkit_1.createSlice)({
246
245
  saveTransactionDetailLocalData(draft, action) {
247
246
  const key = (0, transactionDetailState_1.getTransactionDetailKey)(action.payload.transactionId);
248
247
  const detail = (0, get_1.default)(draft.transactionDetailById, key, undefined);
249
- if (detail != null) {
250
- draft.transactionDetailById[key] = {
251
- ...detail,
252
- transactionDetailLocalData: action.payload.transactionLocalData,
253
- };
248
+ if (detail == null) {
249
+ return;
254
250
  }
251
+ const incoming = action.payload.transactionLocalData;
252
+ const prevById = detail.transactionDetailLocalData.lineItemById;
253
+ // Per-line `categoryClassRecommendationsFetchState` is owned by the
254
+ // recommendation epic/reducers (markInProgress / markCompleted /
255
+ // markFailure / setEntityRecommendationForLineIdsForTransactionDetail).
256
+ // Callers that rebuild `transactionLocalData` from a UI snapshot will
257
+ // typically have an out-of-date copy of this field (e.g. payee-change
258
+ // captures the snapshot before the epic's start arm runs and would
259
+ // otherwise clobber In-Progress back to undefined). Treat the field as
260
+ // sticky: only let the caller override it when they explicitly set it.
261
+ const mergedLineItemById = {};
262
+ Object.entries(incoming.lineItemById ?? {}).forEach(([lineId, line]) => {
263
+ mergedLineItemById[lineId] = {
264
+ ...line,
265
+ categoryClassRecommendationsFetchState: line.categoryClassRecommendationsFetchState ??
266
+ prevById?.[lineId]?.categoryClassRecommendationsFetchState,
267
+ };
268
+ });
269
+ draft.transactionDetailById[key] = {
270
+ ...detail,
271
+ transactionDetailLocalData: {
272
+ ...incoming,
273
+ lineItemById: mergedLineItemById,
274
+ },
275
+ };
255
276
  },
256
277
  saveTransactionDetail(draft, action) {
257
278
  const key = (0, transactionDetailState_1.getTransactionDetailKey)(action.payload.transactionId);
@@ -373,6 +394,21 @@ const transactionDetail = (0, toolkit_1.createSlice)({
373
394
  const detail = (0, get_1.default)(draft.transactionDetailById, key, undefined);
374
395
  if (detail != null) {
375
396
  const newLocalData = (0, transactionDetailLocalDataHelper_1.setEntityRecommendationForLineIdInLocalData)(transaction, detail.transactionDetailLocalData, action.payload.entity, lineIds, uncategorizedIncomeExpense, recommendationWithCOTByLineId);
397
+ // Release the per-line fetch flag for every line this fetch
398
+ // covered so the inline skeleton resolves and the page-level
399
+ // Save button can re-enable.
400
+ lineIds.forEach((lineId) => {
401
+ const lineItem = newLocalData.lineItemById[lineId];
402
+ if (lineItem != null) {
403
+ newLocalData.lineItemById[lineId] = {
404
+ ...lineItem,
405
+ categoryClassRecommendationsFetchState: {
406
+ fetchState: 'Completed',
407
+ error: undefined,
408
+ },
409
+ };
410
+ }
411
+ });
376
412
  draft.transactionDetailById[key] = {
377
413
  ...detail,
378
414
  transactionDetailLocalData: newLocalData,
@@ -393,6 +429,84 @@ const transactionDetail = (0, toolkit_1.createSlice)({
393
429
  };
394
430
  },
395
431
  },
432
+ // Start arm of the line-update recommendations fetch for the detail
433
+ // page. Flips covered lines to In-Progress; detail page has no
434
+ // checkbox, so no auto-uncheck side effect.
435
+ markCategoryClassRecommendationsInProgressForTransactionDetail: {
436
+ reducer(draft, action) {
437
+ const { transactionId, lineIds } = action.payload;
438
+ const key = (0, transactionDetailState_1.getTransactionDetailKey)(transactionId);
439
+ const detail = (0, get_1.default)(draft.transactionDetailById, key, undefined);
440
+ if (detail != null) {
441
+ lineIds.forEach((lineId) => {
442
+ const lineItem = detail.transactionDetailLocalData.lineItemById[lineId];
443
+ if (lineItem != null) {
444
+ detail.transactionDetailLocalData.lineItemById[lineId] = {
445
+ ...lineItem,
446
+ categoryClassRecommendationsFetchState: {
447
+ fetchState: 'In-Progress',
448
+ error: undefined,
449
+ },
450
+ };
451
+ }
452
+ });
453
+ }
454
+ },
455
+ prepare(transactionId, lineIds) {
456
+ return { payload: { transactionId, lineIds } };
457
+ },
458
+ },
459
+ // Completed arm. Used when the HTTP call succeeded but the server
460
+ // returned no per-line recommendations — still need to release the
461
+ // In-Progress flag.
462
+ markCategoryClassRecommendationsCompletedForTransactionDetail: {
463
+ reducer(draft, action) {
464
+ const { transactionId, lineIds } = action.payload;
465
+ const key = (0, transactionDetailState_1.getTransactionDetailKey)(transactionId);
466
+ const detail = (0, get_1.default)(draft.transactionDetailById, key, undefined);
467
+ if (detail != null) {
468
+ lineIds.forEach((lineId) => {
469
+ const lineItem = detail.transactionDetailLocalData.lineItemById[lineId];
470
+ if (lineItem != null) {
471
+ detail.transactionDetailLocalData.lineItemById[lineId] = {
472
+ ...lineItem,
473
+ categoryClassRecommendationsFetchState: {
474
+ fetchState: 'Completed',
475
+ error: undefined,
476
+ },
477
+ };
478
+ }
479
+ });
480
+ }
481
+ },
482
+ prepare(transactionId, lineIds) {
483
+ return { payload: { transactionId, lineIds } };
484
+ },
485
+ },
486
+ markCategoryClassRecommendationsFailureForTransactionDetail: {
487
+ reducer(draft, action) {
488
+ const { transactionId, lineIds, error } = action.payload;
489
+ const key = (0, transactionDetailState_1.getTransactionDetailKey)(transactionId);
490
+ const detail = (0, get_1.default)(draft.transactionDetailById, key, undefined);
491
+ if (detail != null) {
492
+ lineIds.forEach((lineId) => {
493
+ const lineItem = detail.transactionDetailLocalData.lineItemById[lineId];
494
+ if (lineItem != null) {
495
+ detail.transactionDetailLocalData.lineItemById[lineId] = {
496
+ ...lineItem,
497
+ categoryClassRecommendationsFetchState: {
498
+ fetchState: 'Error',
499
+ error,
500
+ },
501
+ };
502
+ }
503
+ });
504
+ }
505
+ },
506
+ prepare(transactionId, lineIds, error) {
507
+ return { payload: { transactionId, lineIds, error } };
508
+ },
509
+ },
396
510
  removeEntityRecommendationForLineIdForTransactionDetail: {
397
511
  reducer(draft, action) {
398
512
  const { transaction, lineId } = action.payload;
@@ -664,7 +778,7 @@ const transactionDetail = (0, toolkit_1.createSlice)({
664
778
  },
665
779
  },
666
780
  });
667
- _a = transactionDetail.actions, exports.downloadAccountingProviderAttachment = _a.downloadAccountingProviderAttachment, exports.downloadAccountingProviderAttachmentSuccess = _a.downloadAccountingProviderAttachmentSuccess, exports.downloadAccountingProviderAttachmentFailure = _a.downloadAccountingProviderAttachmentFailure, exports.fetchTransactionDetail = _a.fetchTransactionDetail, exports.updateTransactionDetailFetchState = _a.updateTransactionDetailFetchState, exports.removeTransactionDetail = _a.removeTransactionDetail, exports.clearTransactionDetail = _a.clearTransactionDetail, exports.uploadMissingAttachmentSuccess = _a.uploadMissingAttachmentSuccess, exports.updateTransactionDetail = _a.updateTransactionDetail, exports.updateTransactionDetailSaveStatus = _a.updateTransactionDetailSaveStatus, exports.clearTransactionDetailSaveStatus = _a.clearTransactionDetailSaveStatus, exports.markTransactionAsNotMiscategorized = _a.markTransactionAsNotMiscategorized, exports.deleteTransactionAttachment = _a.deleteTransactionAttachment, exports.deleteTransactionAttachmentFailure = _a.deleteTransactionAttachmentFailure, exports.deleteTransactionAttachmentSuccess = _a.deleteTransactionAttachmentSuccess, exports.updateStatusForTransactionNotMiscategorizedUpdate = _a.updateStatusForTransactionNotMiscategorizedUpdate, exports.updateStatusConsolidatedSaveTransactionDetail = _a.updateStatusConsolidatedSaveTransactionDetail, exports.updateTransactionStateIfUpdateActionNotAllowed = _a.updateTransactionStateIfUpdateActionNotAllowed, exports.saveTransactionDetail = _a.saveTransactionDetail, exports.initializeTransactionDetailLocalData = _a.initializeTransactionDetailLocalData, exports.saveTransactionDetailLocalData = _a.saveTransactionDetailLocalData, exports.clearTransactionDetailLocalData = _a.clearTransactionDetailLocalData, exports.resetLineItemsCategoryClassInLocalData = _a.resetLineItemsCategoryClassInLocalData, exports.setAllLineItemsToCategoryClassInLocalData = _a.setAllLineItemsToCategoryClassInLocalData, exports.setAllLineItemsLocalDataIsUpdateAllChecked = _a.setAllLineItemsLocalDataIsUpdateAllChecked, exports.setEntityRecommendationForLineIdsForTransactionDetail = _a.setEntityRecommendationForLineIdsForTransactionDetail, exports.removeEntityRecommendationForLineIdForTransactionDetail = _a.removeEntityRecommendationForLineIdForTransactionDetail, exports.updateSelectedVendor = _a.updateSelectedVendor, exports.updateSelectedCustomer = _a.updateSelectedCustomer, exports.resetVendor = _a.resetVendor, exports.resetSelectedCustomer = _a.resetSelectedCustomer, exports.updateLocalDataWithTransactionsUpdateWithVendorCheckbox = _a.updateLocalDataWithTransactionsUpdateWithVendorCheckbox, exports.updateVendorToAllLineItems = _a.updateVendorToAllLineItems, exports.resetAllLineItemsToVendor = _a.resetAllLineItemsToVendor, exports.updateLatestSelectedEntity = _a.updateLatestSelectedEntity, exports.updateVendorBulkRecommendationsFetchStatus = _a.updateVendorBulkRecommendationsFetchStatus, exports.setIsVendorUpdateAllChecked = _a.setIsVendorUpdateAllChecked;
781
+ _a = transactionDetail.actions, exports.downloadAccountingProviderAttachment = _a.downloadAccountingProviderAttachment, exports.downloadAccountingProviderAttachmentSuccess = _a.downloadAccountingProviderAttachmentSuccess, exports.downloadAccountingProviderAttachmentFailure = _a.downloadAccountingProviderAttachmentFailure, exports.fetchTransactionDetail = _a.fetchTransactionDetail, exports.updateTransactionDetailFetchState = _a.updateTransactionDetailFetchState, exports.removeTransactionDetail = _a.removeTransactionDetail, exports.clearTransactionDetail = _a.clearTransactionDetail, exports.uploadMissingAttachmentSuccess = _a.uploadMissingAttachmentSuccess, exports.updateTransactionDetail = _a.updateTransactionDetail, exports.updateTransactionDetailSaveStatus = _a.updateTransactionDetailSaveStatus, exports.clearTransactionDetailSaveStatus = _a.clearTransactionDetailSaveStatus, exports.markTransactionAsNotMiscategorized = _a.markTransactionAsNotMiscategorized, exports.deleteTransactionAttachment = _a.deleteTransactionAttachment, exports.deleteTransactionAttachmentFailure = _a.deleteTransactionAttachmentFailure, exports.deleteTransactionAttachmentSuccess = _a.deleteTransactionAttachmentSuccess, exports.updateStatusForTransactionNotMiscategorizedUpdate = _a.updateStatusForTransactionNotMiscategorizedUpdate, exports.updateStatusConsolidatedSaveTransactionDetail = _a.updateStatusConsolidatedSaveTransactionDetail, exports.updateTransactionStateIfUpdateActionNotAllowed = _a.updateTransactionStateIfUpdateActionNotAllowed, exports.saveTransactionDetail = _a.saveTransactionDetail, exports.initializeTransactionDetailLocalData = _a.initializeTransactionDetailLocalData, exports.saveTransactionDetailLocalData = _a.saveTransactionDetailLocalData, exports.clearTransactionDetailLocalData = _a.clearTransactionDetailLocalData, exports.resetLineItemsCategoryClassInLocalData = _a.resetLineItemsCategoryClassInLocalData, exports.setAllLineItemsToCategoryClassInLocalData = _a.setAllLineItemsToCategoryClassInLocalData, exports.setAllLineItemsLocalDataIsUpdateAllChecked = _a.setAllLineItemsLocalDataIsUpdateAllChecked, exports.setEntityRecommendationForLineIdsForTransactionDetail = _a.setEntityRecommendationForLineIdsForTransactionDetail, exports.markCategoryClassRecommendationsInProgressForTransactionDetail = _a.markCategoryClassRecommendationsInProgressForTransactionDetail, exports.markCategoryClassRecommendationsCompletedForTransactionDetail = _a.markCategoryClassRecommendationsCompletedForTransactionDetail, exports.markCategoryClassRecommendationsFailureForTransactionDetail = _a.markCategoryClassRecommendationsFailureForTransactionDetail, exports.removeEntityRecommendationForLineIdForTransactionDetail = _a.removeEntityRecommendationForLineIdForTransactionDetail, exports.updateSelectedVendor = _a.updateSelectedVendor, exports.updateSelectedCustomer = _a.updateSelectedCustomer, exports.resetVendor = _a.resetVendor, exports.resetSelectedCustomer = _a.resetSelectedCustomer, exports.updateLocalDataWithTransactionsUpdateWithVendorCheckbox = _a.updateLocalDataWithTransactionsUpdateWithVendorCheckbox, exports.updateVendorToAllLineItems = _a.updateVendorToAllLineItems, exports.resetAllLineItemsToVendor = _a.resetAllLineItemsToVendor, exports.updateLatestSelectedEntity = _a.updateLatestSelectedEntity, exports.updateVendorBulkRecommendationsFetchStatus = _a.updateVendorBulkRecommendationsFetchStatus, exports.setIsVendorUpdateAllChecked = _a.setIsVendorUpdateAllChecked;
668
782
  exports.default = transactionDetail.reducer;
669
783
  function getUpdatedEntityLocalData(detail, updates, entity, resetRecommendations, type) {
670
784
  const key = type === 'customer' ? 'customerUpdates' : 'vendorUpdates';
@@ -1,8 +1,7 @@
1
1
  import { NestedAccountHierarchyForReport } from '../../commonStateTypes/accountView/nestedAccountID';
2
2
  import { NestedClassHierarchyForReport } from '../../commonStateTypes/classesView/nestedClassID';
3
- import { FetchState, FetchStateAndError } from '../../commonStateTypes/common';
3
+ import { FetchStateAndError } from '../../commonStateTypes/common';
4
4
  import { SelectorView } from '../../commonStateTypes/viewAndReport/viewAndReport';
5
- import { AccountBase } from '../../entity/account/accountState';
6
5
  import { TransactionID } from '../../entity/transaction/stateTypes/transaction';
7
6
  import { SupportedTransactionWithCOT } from '../../entity/transaction/transactionState';
8
7
  import { Vendor } from '../../entity/vendor/vendorState';
@@ -18,23 +17,21 @@ export interface TransactionDetailReport extends SelectorView {
18
17
  allVendors: Vendor[];
19
18
  classHierarchyList: NestedClassHierarchyForReport[];
20
19
  classList: ClassListSelectorView;
21
- createTransferEntryStatus: FetchState;
22
- /** Resolved credit-card pool for credit_card_payment transfer drawer. */
23
- creditCardAccountsForTransferList: AccountBase[];
24
20
  deleteStatusByAttachmentName: Record<string, FetchStateAndError>;
21
+ hasInFlightCategoryClassRecommendations: boolean;
25
22
  isAccountingClassesEnabled: boolean;
26
23
  isAccountingProjectsEnabled: boolean;
27
24
  linkedTransactions: SupportedTransactionWithCOT[];
28
25
  projectList: ProjectListSelectorView;
29
26
  transactionDetailLocalData: TransactionDetailLocalData;
30
27
  transactionDetailUpdateStatus: FetchStateAndError;
31
- transferAccounts: AccountBase[];
32
28
  isUpdateNotAllowed?: boolean;
33
29
  transaction?: SupportedTransactionWithCOT;
34
30
  }
35
31
  export interface VendorDetailsView extends SelectorView {
36
32
  vendors: Vendor[];
37
33
  }
34
+ export declare const getDetailInFlightRecommendations: (state: RootState, transactionId: TransactionID) => boolean;
38
35
  export declare const getTransactionDetail: (state: RootState, transactionId: TransactionID, fetchLinkedTransactions?: boolean) => TransactionDetailReport;
39
36
  export declare function getTransactionDetailForTransaction(rootState: RootState, transactionId: TransactionID): TransactionDetailReport | undefined;
40
37
  export declare const getInitialUpdatablePeriodsForTransactionRecommendations: (companyIncorporationDate?: ZeniDate, bookCloseDate?: ZeniDate) => {
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getInitialUpdatablePeriodsForTransactionRecommendations = exports.getTransactionDetail = void 0;
6
+ exports.getInitialUpdatablePeriodsForTransactionRecommendations = exports.getTransactionDetail = exports.getDetailInFlightRecommendations = void 0;
7
7
  exports.getTransactionDetailForTransaction = getTransactionDetailForTransaction;
8
8
  const get_1 = __importDefault(require("lodash/get"));
9
9
  const reduceFetchState_1 = require("../../commonStateTypes/reduceFetchState");
@@ -14,12 +14,32 @@ const transactionSelector_1 = require("../../entity/transaction/transactionSelec
14
14
  const vendorSelector_1 = require("../../entity/vendor/vendorSelector");
15
15
  const zeniDayJS_1 = require("../../zeniDayJS");
16
16
  const accountListSelector_1 = require("../accountList/accountListSelector");
17
- const createTransferEntrySelector_1 = require("../createTransferEntry/createTransferEntrySelector");
18
17
  const classListSelector_1 = require("../classList/classListSelector");
19
18
  const projectListSelector_1 = require("../projectList/projectListSelector");
20
19
  const transactionDetailState_1 = require("./transactionDetailState");
20
+ // "Any line on this transaction is fetching category/class recommendations?"
21
+ // Inlined as a plain function because the upstream selector
22
+ // `getTransactionDetail` is also un-memoized and the iteration is O(lines)
23
+ // — typically <10. Exported standalone so consumers that only need the
24
+ // flag (e.g. footer save-disable) can avoid materializing the whole
25
+ // detail report.
26
+ const getDetailInFlightRecommendations = (state, transactionId) => {
27
+ const detailKey = (0, transactionDetailState_1.getTransactionDetailKey)(transactionId);
28
+ const detail = (0, get_1.default)(state.transactionDetailState.transactionDetailById, detailKey, undefined);
29
+ if (detail == null) {
30
+ return false;
31
+ }
32
+ for (const lineItem of Object.values(detail.transactionDetailLocalData.lineItemById)) {
33
+ if (lineItem.categoryClassRecommendationsFetchState?.fetchState ===
34
+ 'In-Progress') {
35
+ return true;
36
+ }
37
+ }
38
+ return false;
39
+ };
40
+ exports.getDetailInFlightRecommendations = getDetailInFlightRecommendations;
21
41
  const getTransactionDetail = (state, transactionId, fetchLinkedTransactions = true) => {
22
- const { transactionDetailState, transactionState, vendorState, vendorListState, accountState, classState, classListState, accountListState, createTransferEntryState, projectState, projectListState, } = state;
42
+ const { transactionDetailState, transactionState, vendorState, vendorListState, accountState, classState, classListState, accountListState, projectState, projectListState, } = state;
23
43
  const detailKey = (0, transactionDetailState_1.getTransactionDetailKey)(transactionId);
24
44
  const transactionDetail = (0, get_1.default)(transactionDetailState.transactionDetailById, detailKey);
25
45
  let fetchState = {
@@ -86,7 +106,7 @@ const getTransactionDetail = (state, transactionId, fetchLinkedTransactions = tr
86
106
  : [];
87
107
  const transactionDetailAnyUpdateStatus = reduceUpdateFetchStates(transactionDetail);
88
108
  const vendors = (0, vendorSelector_1.getVendorsByVendorIds)(vendorState, vendorListState.vendorIds);
89
- const { transferAccountsList, creditCardAccountsForTransferList } = (0, createTransferEntrySelector_1.getResolvedTransferAccounts)(state);
109
+ const hasInFlightCategoryClassRecommendations = (0, exports.getDetailInFlightRecommendations)(state, transactionId);
90
110
  return {
91
111
  reportId: 'transaction_detail',
92
112
  reportTitle: 'Transaction Detail',
@@ -102,10 +122,8 @@ const getTransactionDetail = (state, transactionId, fetchLinkedTransactions = tr
102
122
  classHierarchyList,
103
123
  accountsHierarchyList,
104
124
  classList: classList,
125
+ hasInFlightCategoryClassRecommendations,
105
126
  isAccountingClassesEnabled,
106
- createTransferEntryStatus: createTransferEntryState.createTransferEntryStatus,
107
- creditCardAccountsForTransferList,
108
- transferAccounts: transferAccountsList,
109
127
  isAccountingProjectsEnabled,
110
128
  projectList,
111
129
  isUpdateNotAllowed: transactionDetail?.isUpdateNotAllowed,
@@ -14,6 +14,7 @@ export interface TransactionDetailLineItemData extends TransactionLineBase {
14
14
  isClassMiscategorized: boolean;
15
15
  account?: AccountBase;
16
16
  billable?: BillableStatus;
17
+ categoryClassRecommendationsFetchState?: FetchStateAndError;
17
18
  class?: ClassBase;
18
19
  customer?: CustomerBase;
19
20
  isCategoryUpdateSelected?: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeniai/client-epic-state",
3
- "version": "5.0.69-betaML2",
3
+ "version": "5.0.69-betaML31",
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,56 +0,0 @@
1
- import { createSlice } from '@reduxjs/toolkit';
2
- import { initialCreateTransferEntryState, } from './createTransferEntryState';
3
- export const initialState = initialCreateTransferEntryState;
4
- const createTransferEntrySlice = createSlice({
5
- name: 'createTransferEntry',
6
- initialState,
7
- reducers: {
8
- fetchAccountsForTransferFlow(draft, action) {
9
- draft.transferAccountsByType[action.payload.kind].fetchState =
10
- 'In-Progress';
11
- },
12
- updateAccountsForTransferFlow(draft, action) {
13
- const slice = draft.transferAccountsByType[action.payload.kind];
14
- slice.fetchState = 'Completed';
15
- slice.accountIds = action.payload.accountIds;
16
- },
17
- updateAccountsForTransferFlowFailure(draft, action) {
18
- draft.transferAccountsByType[action.payload.kind].fetchState = 'Error';
19
- },
20
- createTransferEntry: {
21
- prepare(payload) {
22
- return { payload };
23
- },
24
- reducer(draft) {
25
- draft.createTransferEntryStatus = 'In-Progress';
26
- },
27
- },
28
- createTransferEntrySuccess(draft) {
29
- draft.createTransferEntryStatus = 'Completed';
30
- },
31
- createTransferEntryFailure(draft) {
32
- draft.createTransferEntryStatus = 'Error';
33
- },
34
- resetCreateTransferEntryStatus(draft) {
35
- draft.createTransferEntryStatus = 'Not-Started';
36
- },
37
- createTransferEntryReplacedTransaction: {
38
- prepare(previousTransactionId, newTransactionId) {
39
- return { payload: { newTransactionId, previousTransactionId } };
40
- },
41
- reducer(draft, action) {
42
- draft.lastTransferEntryReplacement = action.payload;
43
- },
44
- },
45
- /**
46
- * One-shot acknowledgement: the host has consumed the route-replacement
47
- * signal and navigated to the new transaction url, so we can drop the
48
- * record. Re-dispatching is idempotent.
49
- */
50
- clearTransferEntryRouteReplacement(draft) {
51
- draft.lastTransferEntryReplacement = undefined;
52
- },
53
- },
54
- });
55
- export const { fetchAccountsForTransferFlow, updateAccountsForTransferFlow, updateAccountsForTransferFlowFailure, createTransferEntry, createTransferEntrySuccess, createTransferEntryFailure, resetCreateTransferEntryStatus, createTransferEntryReplacedTransaction, clearTransferEntryRouteReplacement, } = createTransferEntrySlice.actions;
56
- export default createTransferEntrySlice.reducer;
@@ -1,63 +0,0 @@
1
- import { createSelector } from '@reduxjs/toolkit';
2
- import { getAccountBase, getAccountBaseForCreditCardTransferAccounts, getAccountBaseForTransferAccounts, } from '../../entity/account/accountSelector';
3
- import { getAccountList } from '../accountList/accountListSelector';
4
- export function getCreateTransferEntryStatus(state) {
5
- return state.createTransferEntryState.createTransferEntryStatus;
6
- }
7
- export function getLastTransferEntryReplacement(state) {
8
- return state.createTransferEntryState.lastTransferEntryReplacement;
9
- }
10
- /**
11
- * Shared resolver for the credit/debit dropdowns in the transfer drawer.
12
- *
13
- * Resolution policy (intentional):
14
- * 1. Prefer the dedicated API fetch results (`transfer_eligible` for the debit
15
- * pool, `credit_card_only` for the credit-card-payment credit pool).
16
- * 2. If the dedicated fetch returns an empty list while the COA is loaded,
17
- * fall back to the COA: the full account list for `transfer_eligible`, and
18
- * COA accounts filtered to `credit_card` for `credit_card_only`. This keeps
19
- * the dropdown populated for older tenants where the dedicated endpoints
20
- * haven't been backfilled yet.
21
- *
22
- * Intent — what this selector deliberately does NOT do:
23
- * - Does NOT distinguish "fetch in-flight" / "fetch errored" / "fetch returned
24
- * empty" — all three collapse to the COA fallback. The product preference
25
- * is "always show something selectable" over "show a spinner that may never
26
- * resolve". Loading/error UI belongs in the view layer; if you need a
27
- * spinner, observe the `fetchState` on `transferAccountsByType[kind]`
28
- * separately rather than changing the resolution policy here.
29
- * - Does NOT enforce "API result is authoritative even if empty" — a tenant
30
- * whose dedicated endpoint is correctly returning `[]` (e.g. no eligible
31
- * transfer destinations) will still see the COA. That trade-off is
32
- * accepted because the alternative blocks the user from picking anything;
33
- * the backend distinguishes "no result" from "endpoint not implemented" by
34
- * surfacing an error response, which the view layer handles separately.
35
- *
36
- * Memoized with reselect so consuming view-models don't recompute on every
37
- * unrelated state change.
38
- */
39
- export const getResolvedTransferAccounts = createSelector([
40
- (state) => state.accountState,
41
- (state) => state.accountListState,
42
- (state) => state.createTransferEntryState.transferAccountsByType.transfer_eligible
43
- .accountIds,
44
- (state) => state.createTransferEntryState.transferAccountsByType.credit_card_only
45
- .accountIds,
46
- ], (accountState, accountListState, transferEligibleIds, creditCardOnlyIds) => {
47
- const accountList = getAccountList(accountState, accountListState, 'accountList');
48
- const transferEligibleFromApi = transferEligibleIds
49
- .map((id) => getAccountBaseForTransferAccounts(accountState, id))
50
- .filter((account) => account != null);
51
- const coaFallbackAllAccounts = accountList.accounts
52
- .map((a) => getAccountBase(accountState, a.accountId, 'account_list'))
53
- .filter((account) => account != null);
54
- const transferAccountsList = transferEligibleFromApi.length > 0
55
- ? transferEligibleFromApi
56
- : coaFallbackAllAccounts;
57
- const creditCardFromApi = creditCardOnlyIds
58
- .map((id) => getAccountBaseForCreditCardTransferAccounts(accountState, id))
59
- .filter((account) => account != null);
60
- const coaFallbackCreditCards = coaFallbackAllAccounts.filter((a) => a.accountType === 'credit_card');
61
- const creditCardAccountsForTransferList = creditCardFromApi.length > 0 ? creditCardFromApi : coaFallbackCreditCards;
62
- return { creditCardAccountsForTransferList, transferAccountsList };
63
- });
@@ -1,17 +0,0 @@
1
- /** Which pool `fetchAccountsForTransferFlow` / transfer-flow epic should load. */
2
- export const TRANSFER_ACCOUNTS_FETCH_TYPE = [
3
- 'transfer_eligible',
4
- 'credit_card_only',
5
- ];
6
- const initialTransferAccountsState = {
7
- accountIds: [],
8
- fetchState: 'Not-Started',
9
- };
10
- export const initialCreateTransferEntryState = {
11
- createTransferEntryStatus: 'Not-Started',
12
- lastTransferEntryReplacement: undefined,
13
- transferAccountsByType: {
14
- transfer_eligible: initialTransferAccountsState,
15
- credit_card_only: initialTransferAccountsState,
16
- },
17
- };
@@ -1,112 +0,0 @@
1
- import { concat, from, timer } from 'rxjs';
2
- import { catchError, filter, mergeMap } from 'rxjs/operators';
3
- import { openSnackbar } from '../../../entity/snackbar/snackbarReducer';
4
- import { toTransactionID } from '../../../entity/transaction/payloadTypes/transactionIDPayload';
5
- import { removeTransaction, updateTransaction, } from '../../../entity/transaction/transactionReducer';
6
- import { isSuccessResponse } from '../../../responsePayload';
7
- import { removeTransactionFromAllTabs } from '../../expenseAutomationView/reducers/transactionsViewReducer';
8
- import { initializeTransactionDetailLocalData, removeTransactionDetail, } from '../../transactionDetail/transactionDetailReducer';
9
- import { getTransactionDetailKey } from '../../transactionDetail/transactionDetailState';
10
- import { clearTransferEntryRouteReplacement, createTransferEntry, createTransferEntryFailure, createTransferEntryReplacedTransaction, createTransferEntrySuccess, resetCreateTransferEntryStatus, } from '../createTransferEntryReducer';
11
- // ─── Pure helpers ────────────────────────────────────────────────────────────
12
- function transactionIdsAreEqual(a, b) {
13
- return a.id === b.id && a.type === b.type;
14
- }
15
- const successSnackbar = () => openSnackbar({
16
- messageSection: 'create_transfer_entry',
17
- messageText: 'success',
18
- type: 'success',
19
- });
20
- const failureSnackbar = () => openSnackbar({
21
- messageSection: 'create_transfer_entry',
22
- messageText: 'failed',
23
- type: 'error',
24
- });
25
- function buildFailureActions() {
26
- return [createTransferEntryFailure(), failureSnackbar()];
27
- }
28
- function buildSuccessSideEffects(sourceTransactionId) {
29
- return [
30
- createTransferEntrySuccess(),
31
- removeTransactionFromAllTabs(sourceTransactionId),
32
- successSnackbar(),
33
- ];
34
- }
35
- function buildPreviousTransactionCleanupActions(previousTransactionId) {
36
- return [
37
- removeTransaction(getTransactionDetailKey(previousTransactionId)),
38
- removeTransactionDetail(previousTransactionId),
39
- clearTransferEntryRouteReplacement(),
40
- ];
41
- }
42
- /**
43
- * Emits `resetCreateTransferEntryStatus()` (and, on the replacement path, the
44
- * follow-up cleanup actions) one scheduler tick after the success actions.
45
- *
46
- * Why the `timer(0)` (and not synchronous emission):
47
- * On the replacement path the host (web-app-ui) watches
48
- * `lastTransferEntryReplacement`, navigates to the new transaction url, and
49
- * then sees `clearTransferEntryRouteReplacement` clear the signal. If we
50
- * dispatched the cleanup actions in the same tick as
51
- * `createTransferEntryReplacedTransaction`, redux subscribers would observe
52
- * `lastTransferEntryReplacement` flicker on then off in a single render, and
53
- * the old transaction's state (which the still-mounted detail view may be
54
- * reading) would be torn down before the host has had a chance to start
55
- * navigating. Deferring by one microtask gives the host exactly one render
56
- * pass to react before we tear down the previous transaction.
57
- */
58
- function delayedResetAndPreviousCleanup(previousTransactionId) {
59
- return timer(0).pipe(mergeMap(() => {
60
- const actions = [resetCreateTransferEntryStatus()];
61
- if (previousTransactionId != null) {
62
- actions.push(...buildPreviousTransactionCleanupActions(previousTransactionId));
63
- }
64
- return from(actions);
65
- }));
66
- }
67
- // ─── Success-path branches ───────────────────────────────────────────────────
68
- function handleSuccessWithoutTransactionBody(transactionId) {
69
- return concat(from(buildSuccessSideEffects(transactionId)), delayedResetAndPreviousCleanup(undefined));
70
- }
71
- function handleSuccessWithTransactionBody(transactionPayload, vendorPayload, previousTransactionId, sourceTransactionId) {
72
- const newTransactionId = toTransactionID(transactionPayload);
73
- const replaced = !transactionIdsAreEqual(previousTransactionId, newTransactionId);
74
- const immediate = [
75
- updateTransaction(getTransactionDetailKey(newTransactionId), transactionPayload),
76
- initializeTransactionDetailLocalData({
77
- transactionId: newTransactionId,
78
- vendorId: vendorPayload?.[0]?.vendor_id,
79
- }),
80
- ...buildSuccessSideEffects(sourceTransactionId),
81
- ];
82
- if (replaced) {
83
- immediate.push(createTransferEntryReplacedTransaction(previousTransactionId, newTransactionId));
84
- }
85
- return concat(from(immediate), delayedResetAndPreviousCleanup(replaced ? previousTransactionId : undefined));
86
- }
87
- // ─── Top-level epic ──────────────────────────────────────────────────────────
88
- const CREATE_TRANSFER_ENTRY_URL = `https://dev.api.zeni.ai/version/accounting/komal/1.0/transactions/transaction-type-update`;
89
- export const createTransferEntryEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(createTransferEntry.match), mergeMap((action) => {
90
- const { transactionId, creditAccountIntegrationId, debitAccountIntegrationId, memo, transactionType, sourceTransactionType, } = action.payload;
91
- const previousTransactionId = {
92
- id: transactionId,
93
- type: sourceTransactionType,
94
- };
95
- return zeniAPI
96
- .postAndGetJSON(CREATE_TRANSFER_ENTRY_URL, {
97
- transaction_type: transactionType,
98
- transaction_id: transactionId,
99
- to_account_integration_id: creditAccountIntegrationId,
100
- from_account_integration_id: debitAccountIntegrationId,
101
- memo,
102
- })
103
- .pipe(mergeMap((response) => {
104
- if (!isSuccessResponse(response)) {
105
- return from(buildFailureActions());
106
- }
107
- if (response.data?.transaction != null) {
108
- return handleSuccessWithTransactionBody(response.data.transaction, response.data.vendors, previousTransactionId, transactionId);
109
- }
110
- return handleSuccessWithoutTransactionBody(transactionId);
111
- }), catchError(() => from(buildFailureActions())));
112
- }));
@@ -1,36 +0,0 @@
1
- import { of } from 'rxjs';
2
- import { catchError, filter, groupBy, mergeMap, switchMap } from 'rxjs/operators';
3
- import { updateAccounts } from '../../../entity/account/accountReducer';
4
- import { isSuccessResponse } from '../../../responsePayload';
5
- import { fetchAccountsForTransferFlow, updateAccountsForTransferFlow, updateAccountsForTransferFlowFailure, } from '../createTransferEntryReducer';
6
- const REPORT_ID_BY_TYPE = {
7
- transfer_eligible: 'transfer_accounts',
8
- credit_card_only: 'credit_card_transfer_accounts',
9
- };
10
- const QUERY_BY_TYPE = {
11
- transfer_eligible: { is_only_include_transfer_accounts: true },
12
- credit_card_only: { is_include_only_credit_card_accounts: true },
13
- };
14
- /**
15
- * Pools fetched concurrently: `groupBy(kind)` keeps `transfer_eligible` and
16
- * `credit_card_only` in their own streams so a back-to-back dispatch of both
17
- * does not cancel the first. Within a single type, a fresh dispatch supersedes
18
- * any in-flight request (per-group `switchMap`).
19
- */
20
- export const fetchTransferAccountsEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(fetchAccountsForTransferFlow.match), groupBy((action) => action.payload.kind), mergeMap((group$) => group$.pipe(switchMap((action) => {
21
- const { kind } = action.payload;
22
- const queryValue = QUERY_BY_TYPE[kind];
23
- const reportId = REPORT_ID_BY_TYPE[kind];
24
- const url = `https://dev.api.zeni.ai/version/accounting/komal/1.0/accounts?query=${encodeURIComponent(JSON.stringify(queryValue))}`;
25
- return zeniAPI.getJSON(url).pipe(mergeMap((response) => {
26
- if (isSuccessResponse(response) && response.data != null) {
27
- const accountIds = response.data.accounts.map((account) => account.account_id);
28
- const actions = [
29
- updateAccounts(response.data.accounts, reportId),
30
- updateAccountsForTransferFlow({ accountIds, kind }),
31
- ];
32
- return of(...actions);
33
- }
34
- return of(updateAccountsForTransferFlowFailure({ kind }));
35
- }), catchError(() => of(updateAccountsForTransferFlowFailure({ kind }))));
36
- }))));