@zeniai/client-epic-state 5.0.83 → 5.0.84-beta0ND

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 (199) hide show
  1. package/lib/common/aiCfo/aiCfoSuggestedQuestionsPageContext.d.ts +1 -1
  2. package/lib/commonStateTypes/animations.d.ts +1 -1
  3. package/lib/commonStateTypes/animations.js +1 -0
  4. package/lib/entity/aiCfo/aiCfoPayload.d.ts +1 -140
  5. package/lib/entity/aiCfo/aiCfoReducer.d.ts +2 -23
  6. package/lib/entity/aiCfo/aiCfoReducer.js +4 -332
  7. package/lib/entity/aiCfo/aiCfoSelector.d.ts +1 -13
  8. package/lib/entity/aiCfo/aiCfoSelector.js +1 -28
  9. package/lib/entity/aiCfo/aiCfoState.d.ts +4 -225
  10. package/lib/entity/aiCfo/aiCfoState.js +1 -30
  11. package/lib/entity/company/companyPayload.d.ts +2 -0
  12. package/lib/entity/company/companyPayload.js +2 -0
  13. package/lib/entity/company/companyStateTypes.d.ts +2 -0
  14. package/lib/entity/jeSchedules/jeSchedulesTypes.d.ts +1 -1
  15. package/lib/entity/monthEndCloseChecks/monthEndCloseChecksState.d.ts +1 -1
  16. package/lib/entity/paymentAccount/paymentAccountSelector.d.ts +1 -0
  17. package/lib/entity/paymentAccount/paymentAccountSelector.js +4 -0
  18. package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
  19. package/lib/entity/snackbar/snackbarTypes.js +1 -3
  20. package/lib/entity/tenant/clearAllEpic.d.ts +2 -6
  21. package/lib/entity/tenant/clearAllEpic.js +0 -8
  22. package/lib/entity/tenant/epic/deleteConnectionEpic.d.ts +1 -1
  23. package/lib/entity/tenant/epic/initEmailConnectOAuthEpic.d.ts +21 -0
  24. package/lib/entity/tenant/epic/initEmailConnectOAuthEpic.js +54 -0
  25. package/lib/entity/tenant/epic/saveAPIKeyConnectionEpic.d.ts +1 -1
  26. package/lib/entity/tenant/epic/saveConnectorCredentialsEpic.d.ts +3 -3
  27. package/lib/entity/tenant/epic/saveOAuthConnectionEpic.d.ts +1 -1
  28. package/lib/entity/tenant/tenantPayload.d.ts +19 -0
  29. package/lib/entity/tenant/tenantReducer.d.ts +49 -28
  30. package/lib/entity/tenant/tenantReducer.js +111 -5
  31. package/lib/entity/tenant/tenantState.d.ts +21 -0
  32. package/lib/epic.d.ts +6 -11
  33. package/lib/epic.js +7 -11
  34. package/lib/esm/commonStateTypes/animations.js +1 -0
  35. package/lib/esm/entity/aiCfo/aiCfoReducer.js +4 -332
  36. package/lib/esm/entity/aiCfo/aiCfoSelector.js +1 -26
  37. package/lib/esm/entity/aiCfo/aiCfoState.js +0 -27
  38. package/lib/esm/entity/company/companyPayload.js +2 -0
  39. package/lib/esm/entity/paymentAccount/paymentAccountSelector.js +3 -0
  40. package/lib/esm/entity/snackbar/snackbarTypes.js +1 -3
  41. package/lib/esm/entity/tenant/clearAllEpic.js +0 -8
  42. package/lib/esm/entity/tenant/epic/initEmailConnectOAuthEpic.js +50 -0
  43. package/lib/esm/entity/tenant/tenantReducer.js +108 -3
  44. package/lib/esm/epic.js +7 -11
  45. package/lib/esm/index.js +16 -28
  46. package/lib/esm/reducer.js +0 -12
  47. package/lib/esm/view/aiCfoView/aiCfoViewReducer.js +3 -6
  48. package/lib/esm/view/aiCfoView/epics/createSessionAndSubmitEpic.js +2 -5
  49. package/lib/esm/view/aiCfoView/epics/createSessionEpic.js +1 -2
  50. package/lib/esm/view/aiCfoView/epics/fetchSuggestedQuestionsEpic.js +2 -12
  51. package/lib/esm/view/companyView/companyViewReducer.js +45 -1
  52. package/lib/esm/view/companyView/epic/companyPassport/dismissCapitalizationOnboardingEpic.js +25 -0
  53. package/lib/esm/view/companyView/epic/companyPassport/updateCapitalizationThresholdEpic.js +79 -0
  54. package/lib/esm/view/companyView/types/companyPassport/companyPassportViewState.js +4 -0
  55. package/lib/esm/view/onboardingView/customerView/epic/aiAgentsActivation/fetchAiAgentsActivationStatusEpic.js +45 -0
  56. package/lib/esm/view/onboardingView/customerView/epic/customerDetails/acknowledgeOnboardingAiFinanceTeamEpic.js +40 -0
  57. package/lib/esm/view/onboardingView/customerView/onboardingCustomerViewReducer.js +168 -50
  58. package/lib/esm/view/onboardingView/customerView/onboardingCustomerViewSelector.js +14 -0
  59. package/lib/esm/view/onboardingView/customerView/onboardingCustomerViewState.js +13 -0
  60. package/lib/esm/view/spendManagement/chargeCards/chargeCardList/chargeCardListSelector.js +0 -25
  61. package/lib/esm/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardEpic.js +2 -2
  62. package/lib/esm/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardReducer.js +4 -16
  63. package/lib/esm/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardSelector.js +0 -38
  64. package/lib/esm/view/spendManagement/commonSetup/epic/setup/parseUploadedKybDocumentEpic.js +49 -0
  65. package/lib/esm/view/spendManagement/commonSetup/epic/setup/parseUploadedKycDocumentEpic.js +58 -0
  66. package/lib/esm/view/spendManagement/commonSetup/kycKybAutofillActions.js +12 -0
  67. package/lib/esm/view/spendManagement/commonSetup/kycKybParseMapper.js +205 -0
  68. package/lib/esm/view/spendManagement/commonSetup/setupViewReducer.js +71 -52
  69. package/lib/esm/view/spendManagement/commonSetup/setupViewSelector.js +2 -0
  70. package/lib/esm/view/spendManagement/commonSetup/types/kycKybAutofill.js +28 -0
  71. package/lib/index.d.ts +19 -28
  72. package/lib/index.js +36 -136
  73. package/lib/reducer.d.ts +0 -12
  74. package/lib/reducer.js +0 -12
  75. package/lib/view/aiCfoView/aiCfoViewReducer.d.ts +2 -11
  76. package/lib/view/aiCfoView/aiCfoViewReducer.js +3 -6
  77. package/lib/view/aiCfoView/epics/createSessionAndSubmitEpic.js +2 -5
  78. package/lib/view/aiCfoView/epics/createSessionEpic.js +1 -2
  79. package/lib/view/aiCfoView/epics/fetchSuggestedQuestionsEpic.d.ts +1 -8
  80. package/lib/view/aiCfoView/epics/fetchSuggestedQuestionsEpic.js +2 -12
  81. package/lib/view/companyView/companyViewReducer.d.ts +11 -1
  82. package/lib/view/companyView/companyViewReducer.js +47 -3
  83. package/lib/view/companyView/epic/companyPassport/dismissCapitalizationOnboardingEpic.d.ts +9 -0
  84. package/lib/view/companyView/epic/companyPassport/dismissCapitalizationOnboardingEpic.js +29 -0
  85. package/lib/view/companyView/epic/companyPassport/updateCapitalizationThresholdEpic.d.ts +10 -0
  86. package/lib/view/companyView/epic/companyPassport/updateCapitalizationThresholdEpic.js +83 -0
  87. package/lib/view/companyView/types/companyPassport/companyPassportViewState.d.ts +1 -0
  88. package/lib/view/companyView/types/companyPassport/companyPassportViewState.js +4 -0
  89. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
  90. package/lib/view/expenseAutomationView/types/reconciliationViewState.d.ts +1 -1
  91. package/lib/view/onboardingView/customerView/epic/aiAgentsActivation/fetchAiAgentsActivationStatusEpic.d.ts +7 -0
  92. package/lib/view/onboardingView/customerView/epic/aiAgentsActivation/fetchAiAgentsActivationStatusEpic.js +49 -0
  93. package/lib/view/onboardingView/customerView/epic/customerDetails/acknowledgeOnboardingAiFinanceTeamEpic.d.ts +9 -0
  94. package/lib/view/onboardingView/customerView/epic/customerDetails/acknowledgeOnboardingAiFinanceTeamEpic.js +44 -0
  95. package/lib/view/onboardingView/customerView/onboardingCustomerViewPayload.d.ts +3 -0
  96. package/lib/view/onboardingView/customerView/onboardingCustomerViewReducer.d.ts +41 -4
  97. package/lib/view/onboardingView/customerView/onboardingCustomerViewReducer.js +170 -51
  98. package/lib/view/onboardingView/customerView/onboardingCustomerViewSelector.d.ts +7 -1
  99. package/lib/view/onboardingView/customerView/onboardingCustomerViewSelector.js +21 -1
  100. package/lib/view/onboardingView/customerView/onboardingCustomerViewState.d.ts +37 -0
  101. package/lib/view/onboardingView/customerView/onboardingCustomerViewState.js +14 -1
  102. package/lib/view/people/peopleTypes.d.ts +1 -1
  103. package/lib/view/scheduleView/scheduleListView/scheduleListTypes.d.ts +1 -1
  104. package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardList.d.ts +1 -1
  105. package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardListSelector.d.ts +0 -14
  106. package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardListSelector.js +1 -27
  107. package/lib/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardEpic.d.ts +2 -2
  108. package/lib/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardEpic.js +1 -1
  109. package/lib/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardReducer.d.ts +1 -5
  110. package/lib/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardReducer.js +5 -17
  111. package/lib/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardSelector.d.ts +0 -27
  112. package/lib/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardSelector.js +1 -43
  113. package/lib/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardState.d.ts +0 -2
  114. package/lib/view/spendManagement/commonSetup/epic/setup/parseUploadedKybDocumentEpic.d.ts +8 -0
  115. package/lib/view/spendManagement/commonSetup/epic/setup/parseUploadedKybDocumentEpic.js +53 -0
  116. package/lib/view/spendManagement/commonSetup/epic/setup/parseUploadedKycDocumentEpic.d.ts +8 -0
  117. package/lib/view/spendManagement/commonSetup/epic/setup/parseUploadedKycDocumentEpic.js +62 -0
  118. package/lib/view/spendManagement/commonSetup/kycKybAutofillActions.d.ts +27 -0
  119. package/lib/view/spendManagement/commonSetup/kycKybAutofillActions.js +15 -0
  120. package/lib/view/spendManagement/commonSetup/kycKybParseMapper.d.ts +24 -0
  121. package/lib/view/spendManagement/commonSetup/kycKybParseMapper.js +213 -0
  122. package/lib/view/spendManagement/commonSetup/setupViewReducer.d.ts +24 -2
  123. package/lib/view/spendManagement/commonSetup/setupViewReducer.js +72 -53
  124. package/lib/view/spendManagement/commonSetup/setupViewSelector.d.ts +4 -0
  125. package/lib/view/spendManagement/commonSetup/setupViewSelector.js +2 -0
  126. package/lib/view/spendManagement/commonSetup/setupViewState.d.ts +12 -0
  127. package/lib/view/spendManagement/commonSetup/types/kycKybAutofill.d.ts +125 -0
  128. package/lib/view/spendManagement/commonSetup/types/kycKybAutofill.js +32 -0
  129. package/lib/view/taskManager/taskListView/taskListReducer.d.ts +1 -1
  130. package/package.json +1 -1
  131. package/lib/entity/cardPolicy/cardPolicyPayload.d.ts +0 -277
  132. package/lib/entity/cardPolicy/cardPolicyPayload.js +0 -143
  133. package/lib/entity/cardPolicy/cardPolicyReducer.d.ts +0 -19
  134. package/lib/entity/cardPolicy/cardPolicyReducer.js +0 -265
  135. package/lib/entity/cardPolicy/cardPolicySelector.d.ts +0 -32
  136. package/lib/entity/cardPolicy/cardPolicySelector.js +0 -103
  137. package/lib/entity/cardPolicy/cardPolicyState.d.ts +0 -205
  138. package/lib/entity/cardPolicy/cardPolicyState.js +0 -14
  139. package/lib/entity/cardPolicy/extractPolicyDocumentEpic.d.ts +0 -18
  140. package/lib/entity/cardPolicy/extractPolicyDocumentEpic.js +0 -68
  141. package/lib/entity/cardPolicy/fetchCardPolicyVendorOptionsEpic.d.ts +0 -26
  142. package/lib/entity/cardPolicy/fetchCardPolicyVendorOptionsEpic.js +0 -47
  143. package/lib/entity/cardPolicy/policyDocumentExtractionToRecommendationBridgeEpic.d.ts +0 -25
  144. package/lib/entity/cardPolicy/policyDocumentExtractionToRecommendationBridgeEpic.js +0 -39
  145. package/lib/entity/cardPolicy/policyRecommendationFromUploadEpic.d.ts +0 -23
  146. package/lib/entity/cardPolicy/policyRecommendationFromUploadEpic.js +0 -111
  147. package/lib/esm/entity/cardPolicy/cardPolicyPayload.js +0 -130
  148. package/lib/esm/entity/cardPolicy/cardPolicyReducer.js +0 -261
  149. package/lib/esm/entity/cardPolicy/cardPolicySelector.js +0 -79
  150. package/lib/esm/entity/cardPolicy/cardPolicyState.js +0 -9
  151. package/lib/esm/entity/cardPolicy/extractPolicyDocumentEpic.js +0 -64
  152. package/lib/esm/entity/cardPolicy/fetchCardPolicyVendorOptionsEpic.js +0 -43
  153. package/lib/esm/entity/cardPolicy/policyDocumentExtractionToRecommendationBridgeEpic.js +0 -35
  154. package/lib/esm/entity/cardPolicy/policyRecommendationFromUploadEpic.js +0 -107
  155. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailReducer.js +0 -70
  156. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailSelector.js +0 -22
  157. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailState.js +0 -1
  158. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/fetchCardPolicyDetailEpic.js +0 -56
  159. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/updateCardPolicyEpic.js +0 -49
  160. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/archiveCardPolicyEpic.js +0 -42
  161. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListReducer.js +0 -72
  162. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListSelector.js +0 -21
  163. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListState.js +0 -1
  164. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/fetchCardPolicyListEpic.js +0 -56
  165. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyReducer.js +0 -62
  166. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicySelector.js +0 -39
  167. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyState.js +0 -1
  168. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyTemplateEpic.js +0 -53
  169. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/fetchCardPolicyMccCategoriesEpic.js +0 -25
  170. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailReducer.d.ts +0 -14
  171. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailReducer.js +0 -74
  172. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailSelector.d.ts +0 -21
  173. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailSelector.js +0 -28
  174. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailState.d.ts +0 -25
  175. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailState.js +0 -2
  176. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/fetchCardPolicyDetailEpic.d.ts +0 -19
  177. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/fetchCardPolicyDetailEpic.js +0 -60
  178. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/updateCardPolicyEpic.d.ts +0 -18
  179. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/updateCardPolicyEpic.js +0 -53
  180. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/archiveCardPolicyEpic.d.ts +0 -16
  181. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/archiveCardPolicyEpic.js +0 -46
  182. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListReducer.d.ts +0 -15
  183. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListReducer.js +0 -76
  184. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListSelector.d.ts +0 -21
  185. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListSelector.js +0 -27
  186. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListState.d.ts +0 -19
  187. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListState.js +0 -2
  188. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/fetchCardPolicyListEpic.d.ts +0 -19
  189. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/fetchCardPolicyListEpic.js +0 -60
  190. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyReducer.d.ts +0 -13
  191. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyReducer.js +0 -66
  192. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicySelector.d.ts +0 -32
  193. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicySelector.js +0 -46
  194. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyState.d.ts +0 -45
  195. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyState.js +0 -2
  196. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyTemplateEpic.d.ts +0 -25
  197. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyTemplateEpic.js +0 -57
  198. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/fetchCardPolicyMccCategoriesEpic.d.ts +0 -15
  199. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/fetchCardPolicyMccCategoriesEpic.js +0 -29
@@ -1,261 +0,0 @@
1
- import { createSlice } from '@reduxjs/toolkit';
2
- import { toCardPolicyTemplate, toCardPolicyVendorSearchOption, toExtractedCardPolicyRules, toMccCategory, } from './cardPolicyPayload';
3
- /**
4
- * Defensive predicate for vendor / merchant names that flow into
5
- * `buildVendorChipId(name)` (in `@zeniai/web-components`). That helper
6
- * calls `name.trim().toLowerCase()`, so a null / undefined / whitespace-
7
- * only value would throw at render time, and an empty string would
8
- * collapse every nameless row into a single colliding `vendor-` chip-id.
9
- * Used at the redux ingestion boundary for both the vendor-search results
10
- * and the BE-suggested merchant seed arrays.
11
- */
12
- const isUsableMerchantName = (name) => typeof name === 'string' && name.trim() !== '';
13
- const initialPolicyDocumentExtractionState = {
14
- fetchState: 'Not-Started',
15
- error: undefined,
16
- extractedRules: undefined,
17
- uploadedFileName: undefined,
18
- };
19
- const initialPolicyRecommendationFromUploadState = {
20
- fetchState: 'Not-Started',
21
- answerId: undefined,
22
- chatSessionId: undefined,
23
- error: undefined,
24
- };
25
- const initialVendorSearchState = {
26
- fetchState: 'Not-Started',
27
- searchString: '',
28
- vendors: [],
29
- error: undefined,
30
- };
31
- export const initialState = {
32
- cardPolicyTemplateById: {},
33
- mccCategories: [],
34
- mccCategoriesError: undefined,
35
- mccCategoriesFetchState: 'Not-Started',
36
- policyDocumentExtraction: initialPolicyDocumentExtractionState,
37
- policyRecommendationFromUpload: initialPolicyRecommendationFromUploadState,
38
- suggestedAllowCategories: [],
39
- suggestedAllowMerchants: [],
40
- suggestedBlockCategories: [],
41
- suggestedBlockMerchants: [],
42
- vendorSearch: initialVendorSearchState,
43
- cardPolicyStats: undefined,
44
- };
45
- const cardPolicy = createSlice({
46
- name: 'cardPolicy',
47
- initialState,
48
- reducers: {
49
- fetchCardPolicyMccCategories(draft) {
50
- draft.mccCategoriesFetchState = 'In-Progress';
51
- draft.mccCategoriesError = undefined;
52
- },
53
- updateCardPolicyMccCategories(draft, action) {
54
- draft.mccCategories = (action.payload.categories ?? []).map(toMccCategory);
55
- // Persist BE-suggested allow / block seeds alongside the universe.
56
- // Both flows (manual create page + AI CFO interactive form) read
57
- // these to pre-populate the chip cloud body before the user edits.
58
- // Drop empty / nullish merchant names defensively — they feed
59
- // `buildVendorChipId(name)` (in @zeniai/web-components) which calls
60
- // `.trim().toLowerCase()` and would crash the chip-picker render
61
- // path if any entry slipped through as undefined / "".
62
- draft.suggestedAllowMerchants = (action.payload.suggested_allow_merchants ?? []).filter(isUsableMerchantName);
63
- draft.suggestedBlockMerchants = (action.payload.suggested_block_merchants ?? []).filter(isUsableMerchantName);
64
- draft.suggestedAllowCategories = (action.payload.suggested_allow_catagories ?? []).map(toMccCategory);
65
- draft.suggestedBlockCategories = (action.payload.suggested_block_catagories ?? []).map(toMccCategory);
66
- draft.mccCategoriesFetchState = 'Completed';
67
- draft.mccCategoriesError = undefined;
68
- },
69
- updateCardPolicyMccCategoriesFailure(draft, action) {
70
- draft.mccCategoriesFetchState = 'Error';
71
- draft.mccCategoriesError = action.payload;
72
- },
73
- /**
74
- * Store a newly-created (or refreshed) card-policy template keyed by
75
- * `templateId`. Dispatched by the create / list / get epics; consumed
76
- * by both manual and AI-CFO policy flows via `getCardPolicyTemplateById`.
77
- */
78
- updateCreatedCardPolicyTemplate(draft, action) {
79
- const template = toCardPolicyTemplate(action.payload);
80
- draft.cardPolicyTemplateById[template.templateId] = template;
81
- },
82
- /**
83
- * Replace the entity store's `cardPolicyTemplateById` map with the
84
- * full list returned by the templates-list endpoint. Full replace is
85
- * intentional — templates that no longer exist on the server should be
86
- * dropped from local state too. The view slice keeps the server-order
87
- * ID list separately for stable list rendering.
88
- */
89
- updateCardPolicyTemplates(draft, action) {
90
- const byId = {};
91
- for (const template of action.payload) {
92
- byId[template.templateId] = template;
93
- }
94
- draft.cardPolicyTemplateById = byId;
95
- },
96
- /**
97
- * Drop a single template from the entity map. Dispatched by the
98
- * archive (DELETE) epic on success; also usable by any future flow
99
- * that needs to evict a template (e.g. AI-CFO rejection).
100
- */
101
- removeCardPolicyTemplate(draft, action) {
102
- delete draft.cardPolicyTemplateById[action.payload];
103
- },
104
- /**
105
- * Replace the tenant-wide policy stats. Dispatched alongside
106
- * `updateCardPolicyTemplates` from the list epic, but lives on the
107
- * entity slice so any consumer can read it without re-fetching the
108
- * list.
109
- */
110
- updateCardPolicyStats(draft, action) {
111
- draft.cardPolicyStats = action.payload;
112
- },
113
- /**
114
- * Kick off the `POST /cards/1.0/policy-documents/extract` request.
115
- *
116
- * Synchronously flips the sub-slice to `In-Progress` and captures the
117
- * first uploaded file's name (used by the manual `CardPolicyCreatePage`
118
- * to render the "Policy.pdf ×" pill once the request completes) so
119
- * downstream callers don't have to keep their own file refs.
120
- *
121
- * The accompanying `extractPolicyDocumentEpic` listens for this action,
122
- * POSTs multipart form-data to the cards micro-service, and dispatches
123
- * either `updatePolicyDocumentExtractionSuccess` or
124
- * `updatePolicyDocumentExtractionFailure`.
125
- *
126
- * Designed to be dispatched from both the manual create page and a
127
- * future AI CFO composer/upload surface — selectors return a single
128
- * source of truth.
129
- */
130
- extractPolicyDocument: {
131
- reducer(draft, action) {
132
- draft.policyDocumentExtraction.fetchState = 'In-Progress';
133
- draft.policyDocumentExtraction.error = undefined;
134
- draft.policyDocumentExtraction.extractedRules = undefined;
135
- draft.policyDocumentExtraction.uploadedFileName =
136
- action.meta.uploadedFileName;
137
- draft.policyDocumentExtraction.aiCfoAnswerId =
138
- action.payload.aiCfoAnswerId;
139
- draft.policyDocumentExtraction.aiCfoChatSessionId =
140
- action.payload.aiCfoChatSessionId;
141
- // Reset the chained recommendation slice too — without this a
142
- // second upload in the same AI CFO session can read `Completed` or
143
- // `Error` from the prior chain while extraction is still
144
- // `In-Progress`, leaving lifecycle UI/gating wrong until the new
145
- // chain finishes. The two sub-slices model the upload lifecycle
146
- // together (see `clearPolicyDocumentExtraction` below).
147
- draft.policyRecommendationFromUpload = {
148
- ...initialPolicyRecommendationFromUploadState,
149
- };
150
- },
151
- prepare(files, aiCfoAnswerId, aiCfoChatSessionId) {
152
- return {
153
- payload: { files, aiCfoAnswerId, aiCfoChatSessionId },
154
- meta: { uploadedFileName: files[0]?.name },
155
- };
156
- },
157
- },
158
- updatePolicyDocumentExtractionSuccess(draft, action) {
159
- draft.policyDocumentExtraction.fetchState = 'Completed';
160
- draft.policyDocumentExtraction.error = undefined;
161
- draft.policyDocumentExtraction.extractedRules =
162
- toExtractedCardPolicyRules(action.payload);
163
- },
164
- updatePolicyDocumentExtractionFailure(draft, action) {
165
- draft.policyDocumentExtraction.fetchState = 'Error';
166
- draft.policyDocumentExtraction.error = action.payload;
167
- draft.policyDocumentExtraction.extractedRules = undefined;
168
- },
169
- clearPolicyDocumentExtraction(draft) {
170
- draft.policyDocumentExtraction = {
171
- ...initialPolicyDocumentExtractionState,
172
- };
173
- // Clear the chained recommendation slice too — the two together
174
- // model the upload lifecycle and either both reset (× pill,
175
- // unmount) or both advance (drop file → extract → recommend).
176
- draft.policyRecommendationFromUpload = {
177
- ...initialPolicyRecommendationFromUploadState,
178
- };
179
- },
180
- /**
181
- * Kick off `POST /cards/1.0/ai-cfo/policy-recommendation-from-upload`.
182
- *
183
- * Chained after `extractPolicyDocument` succeeds in the AI CFO
184
- * `upload`-mode flow. The accompanying epic forwards the
185
- * just-returned `extracted_rules` to the BE and dispatches success /
186
- * failure into this slice; on success, a sibling action
187
- * (`updateAiCfoAnswerCardPolicyWizardPlan` on the aiCfo slice) is
188
- * dispatched by the epic to merge the returned `wizard_plan` + `source`
189
- * into the in-flight AI CFO answer's `CardPolicyInitialData`.
190
- *
191
- * `answerId` + `chatSessionId` identify which AI CFO answer should
192
- * receive the patch. Both are required so the wizard reads a single
193
- * source of truth for its lifecycle pill (`fetchState`) and the
194
- * bridge epic can correlate against the originating answer.
195
- */
196
- fetchCardPolicyRecommendationFromUpload: {
197
- reducer(draft, action) {
198
- draft.policyRecommendationFromUpload.fetchState = 'In-Progress';
199
- draft.policyRecommendationFromUpload.answerId = action.payload.answerId;
200
- draft.policyRecommendationFromUpload.chatSessionId =
201
- action.payload.chatSessionId;
202
- draft.policyRecommendationFromUpload.error = undefined;
203
- },
204
- prepare(answerId, chatSessionId, extractedRules) {
205
- return { payload: { answerId, chatSessionId, extractedRules } };
206
- },
207
- },
208
- updatePolicyRecommendationFromUploadSuccess(draft) {
209
- draft.policyRecommendationFromUpload.fetchState = 'Completed';
210
- draft.policyRecommendationFromUpload.error = undefined;
211
- },
212
- updatePolicyRecommendationFromUploadFailure(draft, action) {
213
- draft.policyRecommendationFromUpload.fetchState = 'Error';
214
- draft.policyRecommendationFromUpload.error = action.payload;
215
- },
216
- /**
217
- * Kick off `GET /accounting/1.0/vendors` (card-policy mode). When
218
- * `searchString` is empty the BE returns the top vendors sorted by
219
- * year-to-date spend; with a non-empty value it filters server-side.
220
- *
221
- * The accompanying `fetchCardPolicyVendorOptionsEpic` listens for
222
- * this action, builds the `query` JSON (matching `fetchVendorsList`'s
223
- * `view: "vendor_list"` shape) and dispatches success / failure.
224
- *
225
- * Designed to be dispatched from both the manual `CardPolicyCreate /
226
- * EditScreen` (on mount + on every chip-picker keystroke, debounced)
227
- * and the AI CFO interactive form's vendor step.
228
- */
229
- fetchCardPolicyVendorOptions: {
230
- reducer(draft, action) {
231
- draft.vendorSearch.fetchState = 'In-Progress';
232
- draft.vendorSearch.searchString = action.payload.searchString;
233
- draft.vendorSearch.error = undefined;
234
- },
235
- prepare(searchString) {
236
- return { payload: { searchString: searchString ?? '' } };
237
- },
238
- },
239
- updateCardPolicyVendorOptions(draft, action) {
240
- // Drop rows with no usable name. The chip-picker keys vendors by
241
- // `buildVendorChipId(name)` (in @zeniai/web-components), which calls
242
- // `name.trim().toLowerCase()`. A null / undefined / whitespace-only
243
- // name would either throw at render time or collapse every nameless
244
- // row into a single colliding `vendor-` chip-id.
245
- draft.vendorSearch.vendors = (action.payload.vendors ?? [])
246
- .map(toCardPolicyVendorSearchOption)
247
- .filter((vendor) => isUsableMerchantName(vendor.name));
248
- draft.vendorSearch.fetchState = 'Completed';
249
- draft.vendorSearch.error = undefined;
250
- },
251
- updateCardPolicyVendorOptionsFailure(draft, action) {
252
- draft.vendorSearch.fetchState = 'Error';
253
- draft.vendorSearch.error = action.payload;
254
- },
255
- clearCardPolicy(draft) {
256
- Object.assign(draft, initialState);
257
- },
258
- },
259
- });
260
- export const { fetchCardPolicyMccCategories, fetchCardPolicyVendorOptions, updateCardPolicyMccCategories, updateCardPolicyMccCategoriesFailure, updateCardPolicyVendorOptions, updateCardPolicyVendorOptionsFailure, updateCreatedCardPolicyTemplate, updateCardPolicyTemplates, removeCardPolicyTemplate, updateCardPolicyStats, extractPolicyDocument, updatePolicyDocumentExtractionSuccess, updatePolicyDocumentExtractionFailure, clearPolicyDocumentExtraction, fetchCardPolicyRecommendationFromUpload, updatePolicyRecommendationFromUploadSuccess, updatePolicyRecommendationFromUploadFailure, clearCardPolicy, } = cardPolicy.actions;
261
- export default cardPolicy.reducer;
@@ -1,79 +0,0 @@
1
- export function getCardPolicyMccCategories(state) {
2
- return state.mccCategories;
3
- }
4
- export function getCardPolicyMccCategoriesFetchState(state) {
5
- return state.mccCategoriesFetchState;
6
- }
7
- export function getCardPolicyMccCategoriesError(state) {
8
- return state.mccCategoriesError;
9
- }
10
- export function getCardPolicyTemplateById(state, templateId) {
11
- return state.cardPolicyTemplateById[templateId];
12
- }
13
- export function getAllCardPolicyTemplates(state) {
14
- return Object.values(state.cardPolicyTemplateById);
15
- }
16
- /**
17
- * Resolve an ordered list of `templateId`s against the entity store and
18
- * return the corresponding `CardPolicyTemplate[]` in the same order.
19
- * Missing IDs (e.g. stale local state during a refetch) are silently
20
- * dropped. Pair with `getCardPolicyTemplateIds` from the view slice to
21
- * render the Policy List page in server order.
22
- */
23
- export function getCardPolicyTemplatesByIds(state, templateIds) {
24
- return templateIds
25
- .map((id) => state.cardPolicyTemplateById[id])
26
- .filter((template) => template != null);
27
- }
28
- export function getCardPolicyStats(state) {
29
- return state.cardPolicyStats;
30
- }
31
- // ── Policy document extraction ───────────────────────────────────────
32
- export function getPolicyDocumentExtractionFetchState(state) {
33
- return state.policyDocumentExtraction.fetchState;
34
- }
35
- export function getPolicyDocumentExtractionError(state) {
36
- return state.policyDocumentExtraction.error;
37
- }
38
- export function getExtractedCardPolicyRules(state) {
39
- return state.policyDocumentExtraction.extractedRules;
40
- }
41
- export function getUploadedPolicyDocumentFileName(state) {
42
- return state.policyDocumentExtraction.uploadedFileName;
43
- }
44
- // ── Policy recommendation from upload (AI CFO upload mode) ───────────
45
- export function getPolicyRecommendationFromUploadFetchState(state) {
46
- return state.policyRecommendationFromUpload.fetchState;
47
- }
48
- export function getPolicyRecommendationFromUploadError(state) {
49
- return state.policyRecommendationFromUpload.error;
50
- }
51
- export function getPolicyRecommendationFromUploadAnswerId(state) {
52
- return state.policyRecommendationFromUpload.answerId;
53
- }
54
- export function getPolicyRecommendationFromUploadChatSessionId(state) {
55
- return state.policyRecommendationFromUpload.chatSessionId;
56
- }
57
- // ── Suggested allow / block seeds (shipped alongside MCC categories) ─
58
- export function getCardPolicySuggestedAllowMerchants(state) {
59
- return state.suggestedAllowMerchants;
60
- }
61
- export function getCardPolicySuggestedBlockMerchants(state) {
62
- return state.suggestedBlockMerchants;
63
- }
64
- export function getCardPolicySuggestedAllowCategories(state) {
65
- return state.suggestedAllowCategories;
66
- }
67
- export function getCardPolicySuggestedBlockCategories(state) {
68
- return state.suggestedBlockCategories;
69
- }
70
- // ── Vendor search dropdown ───────────────────────────────────────────
71
- export function getCardPolicyVendorSearchOptions(state) {
72
- return state.vendorSearch.vendors;
73
- }
74
- export function getCardPolicyVendorSearchFetchState(state) {
75
- return state.vendorSearch.fetchState;
76
- }
77
- export function getCardPolicyVendorSearchString(state) {
78
- return state.vendorSearch.searchString;
79
- }
@@ -1,9 +0,0 @@
1
- import { stringToUnion } from '../../commonStateTypes/stringToUnion';
2
- export const ALL_CARD_POLICY_TEMPLATE_MODES = ['strict', 'flexible'];
3
- export const toCardPolicyTemplateMode = (v) => stringToUnion(v, ALL_CARD_POLICY_TEMPLATE_MODES);
4
- export const ALL_CARD_POLICY_TEMPLATE_STATUSES = [
5
- 'active',
6
- 'inactive',
7
- 'archived',
8
- ];
9
- export const toCardPolicyTemplateStatus = (v) => stringToUnion(v, ALL_CARD_POLICY_TEMPLATE_STATUSES);
@@ -1,64 +0,0 @@
1
- import { of } from 'rxjs';
2
- import { catchError, filter, mergeMap, switchMap, takeUntil } from 'rxjs/operators';
3
- import { createZeniAPIStatus, isSuccessStatus } from '../../responsePayload';
4
- import { clearPolicyDocumentExtraction, extractPolicyDocument, updatePolicyDocumentExtractionFailure, updatePolicyDocumentExtractionSuccess, } from './cardPolicyReducer';
5
- /**
6
- * Build a multipart `FormData` body for `POST /cards/1.0/policy-documents/extract`.
7
- *
8
- * Uses the same `attachment_file_<i>` / `attachment_json_<i>` field-naming
9
- * convention as the charge-card receipt upload (`uploadReceipts.ts` in
10
- * `web-components`) so backends that already support that wire shape
11
- * accept this endpoint without bespoke parsing.
12
- */
13
- const buildPolicyDocumentFormData = (files) => {
14
- const data = new FormData();
15
- files.forEach((file, index) => {
16
- data.append(`attachment_file_${index}`, file);
17
- const attachmentJson = JSON.stringify({
18
- file_name: file.name,
19
- content_type: file.type,
20
- size: file.size,
21
- });
22
- data.append(`attachment_json_${index}`, attachmentJson);
23
- });
24
- return data;
25
- };
26
- /**
27
- * Listens for `extractPolicyDocument`, POSTs the file(s) as multipart
28
- * form-data to the cards micro-service's policy-document extract endpoint,
29
- * and dispatches success / failure into the entity slice.
30
- *
31
- * Consumed by:
32
- * - Manual `CardPolicyCreatePage` (read result via
33
- * `getExtractedCardPolicyRules` then pre-fill the RHF form via
34
- * `applyExtractedPolicyRulesToFormValues` from `@zeniai/web-components`).
35
- * - (Future) AI CFO upload surface — same action + selector contract.
36
- */
37
- export const extractPolicyDocumentEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(extractPolicyDocument.match),
38
- // `switchMap` (vs `mergeMap`) cancels any in-flight extract whenever a
39
- // new upload is dispatched. With `mergeMap` an older, slower response
40
- // could win the race: `updatePolicyDocumentExtractionSuccess` would
41
- // fire with stale `extractedRules` and the chained bridge epic would
42
- // pair them with whatever `aiCfoAnswerId` / `aiCfoChatSessionId` are
43
- // currently in state — recommending the old file's rules against the
44
- // wrong AI CFO answer.
45
- switchMap((action) => {
46
- const formData = buildPolicyDocumentFormData(action.payload.files);
47
- return zeniAPI
48
- .postFormData(`${zeniAPI.apiEndPoints.cardMicroServiceBaseUrl}/1.0/policy-documents/extract`, formData)
49
- .pipe(mergeMap((response) => {
50
- if (isSuccessStatus(response) &&
51
- response.data != null &&
52
- response.data.extracted_rules != null) {
53
- return of(updatePolicyDocumentExtractionSuccess(response.data.extracted_rules));
54
- }
55
- return of(updatePolicyDocumentExtractionFailure(response.status));
56
- }), catchError((error) => of(updatePolicyDocumentExtractionFailure(createZeniAPIStatus('Unexpected Error', 'Extract card-policy document REST API call errored out' +
57
- JSON.stringify(error))))),
58
- // `clearPolicyDocumentExtraction` (e.g. user clicks the "× Policy.pdf"
59
- // pill) tears down the in-flight extract subscription, so a late
60
- // response can't re-flip `policyDocumentExtraction.fetchState` back
61
- // to `Completed` or repopulate `extractedRules` after the user
62
- // already dismissed the upload.
63
- takeUntil(actions$.pipe(filter(clearPolicyDocumentExtraction.match))));
64
- }));
@@ -1,43 +0,0 @@
1
- import { of } from 'rxjs';
2
- import { catchError, filter, switchMap } from 'rxjs/operators';
3
- import { createZeniAPIStatus, isSuccessStatus } from '../../responsePayload';
4
- import { fetchCardPolicyVendorOptions, updateCardPolicyVendorOptions, updateCardPolicyVendorOptionsFailure, } from './cardPolicyReducer';
5
- const buildQuery = (searchString) => ({
6
- view: 'vendor_list',
7
- page_token: null,
8
- sort_by: 'year_to_date_spend',
9
- sort_order: 'desc',
10
- search_text: searchString,
11
- vendor_name: searchString,
12
- });
13
- /**
14
- * Card-policy vendor search.
15
- *
16
- * Listens for `fetchCardPolicyVendorOptions` and hits the same
17
- * `/accounting/1.0/vendors` endpoint the Vendors-tab uses, but writes
18
- * results onto the dedicated `cardPolicyState.vendorSearch` slice — no
19
- * fan-out to the global `vendor` / `account` / `class` / `vendorList`
20
- * entities. That isolation is important: the user may be configuring a
21
- * card policy in parallel with browsing the Vendors tab, and we don't
22
- * want either flow to clobber the other's list state.
23
- *
24
- * Uses `switchMap` so the latest typed search wins — earlier in-flight
25
- * requests are abandoned, which is the right semantics for a
26
- * search-as-you-type UX.
27
- *
28
- * Consumers:
29
- * - Manual `CardPolicyCreate / EditScreen`
30
- * - AI CFO `CardPolicyInteractiveForm` (vendor step)
31
- */
32
- export const fetchCardPolicyVendorOptionsEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(fetchCardPolicyVendorOptions.match), switchMap((action) => {
33
- const query = buildQuery(action.payload.searchString);
34
- const apiUrl = `${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/vendors` +
35
- `?query=${encodeURIComponent(JSON.stringify(query))}`;
36
- return zeniAPI.getJSON(apiUrl).pipe(switchMap((response) => {
37
- if (isSuccessStatus(response) && response.data != null) {
38
- return of(updateCardPolicyVendorOptions(response.data));
39
- }
40
- return of(updateCardPolicyVendorOptionsFailure(response.status));
41
- }), catchError((error) => of(updateCardPolicyVendorOptionsFailure(createZeniAPIStatus('Unexpected Error', 'Fetch card policy vendor options REST API call errored out' +
42
- JSON.stringify(error))))));
43
- }));
@@ -1,35 +0,0 @@
1
- import { EMPTY, of } from 'rxjs';
2
- import { filter, mergeMap } from 'rxjs/operators';
3
- import { fetchCardPolicyRecommendationFromUpload, updatePolicyDocumentExtractionSuccess, } from './cardPolicyReducer';
4
- /**
5
- * Bridge epic — chains the AI CFO `upload`-mode flow's two API hops.
6
- *
7
- * The first hop (`extractPolicyDocument` → multipart POST to
8
- * `policy-documents/extract`) lives on the cardPolicy slice and is
9
- * shared with the manual `CardPolicyCreatePage`. The second hop
10
- * (`fetchCardPolicyRecommendationFromUpload` → JSON POST to
11
- * `ai-cfo/policy-recommendation-from-upload`) is AI-CFO only.
12
- *
13
- * The chain is gated on `policyDocumentExtraction.aiCfoAnswerId` being
14
- * populated — manual callers leave it undefined, so the bridge is a
15
- * silent no-op there.
16
- *
17
- * Splitting this off from `policyRecommendationFromUploadEpic` keeps
18
- * the wizard component a pure renderer: it dispatches
19
- * `extractPolicyDocument(files, answerId, chatSessionId)` once, then
20
- * subscribes to `cardPolicyState` lifecycle flags to drive its
21
- * "Extracting…" / "Recommending…" pill.
22
- */
23
- export const policyDocumentExtractionToRecommendationBridgeEpic = (actions$, state$) => actions$.pipe(filter(updatePolicyDocumentExtractionSuccess.match), mergeMap((action) => {
24
- const extraction = state$.value.cardPolicyState.policyDocumentExtraction;
25
- const aiCfoAnswerId = extraction.aiCfoAnswerId;
26
- const aiCfoChatSessionId = extraction.aiCfoChatSessionId;
27
- const extractedRules = extraction.extractedRules;
28
- if (aiCfoAnswerId == null ||
29
- aiCfoChatSessionId == null ||
30
- extractedRules == null) {
31
- return EMPTY;
32
- }
33
- void action;
34
- return of(fetchCardPolicyRecommendationFromUpload(aiCfoAnswerId, aiCfoChatSessionId, extractedRules));
35
- }));
@@ -1,107 +0,0 @@
1
- import { of } from 'rxjs';
2
- import { catchError, filter, mergeMap, switchMap, takeUntil } from 'rxjs/operators';
3
- import { updateAiCfoAnswerCardPolicyWizardPlan } from '../aiCfo/aiCfoReducer';
4
- import { createZeniAPIStatus, isSuccessStatus } from '../../responsePayload';
5
- import { clearPolicyDocumentExtraction, fetchCardPolicyRecommendationFromUpload, updatePolicyRecommendationFromUploadFailure, updatePolicyRecommendationFromUploadSuccess, } from './cardPolicyReducer';
6
- /**
7
- * Listens for `fetchCardPolicyRecommendationFromUpload` and POSTs the
8
- * just-extracted policy rules to the AI-CFO recommendation endpoint.
9
- *
10
- * On success — dispatches BOTH:
11
- * - `updatePolicyRecommendationFromUploadSuccess` (flips the
12
- * cardPolicy slice's recommendation lifecycle to `Completed`), and
13
- * - `updateAiCfoAnswerCardPolicyWizardPlan` (patches the in-flight AI
14
- * CFO answer's `CardPolicyInitialData` so the wizard can advance from
15
- * Step 1 → Step 2 in the upload variant).
16
- *
17
- * The reducer payload originally captured at kickoff (`answerId` +
18
- * `chatSessionId`) re-enters via the action so the patch can find the
19
- * right answer to merge into.
20
- */
21
- export const policyRecommendationFromUploadEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(fetchCardPolicyRecommendationFromUpload.match),
22
- // `switchMap` (vs `mergeMap`) cancels any in-flight recommendation
23
- // whenever a new upload kicks off another one. Without this an older,
24
- // slower recommendation response could still resolve after a fresh
25
- // extract has started — that late response would dispatch
26
- // `updateAiCfoAnswerCardPolicyWizardPlan` against the *current*
27
- // `answerId`/`chatSessionId` (the ones captured at its kickoff) and
28
- // overwrite the wizard plan with stale draft policies from the prior
29
- // document. Pairs with the matching `switchMap` in
30
- // `extractPolicyDocumentEpic`.
31
- switchMap((action) => {
32
- const { answerId, chatSessionId, extractedRules } = action.payload;
33
- const body = {
34
- extracted_rules: {
35
- allowed_entity: {
36
- category_codes: extractedRules.allowedEntity.categoryCodes,
37
- merchant_names: extractedRules.allowedEntity.merchantNames,
38
- },
39
- blocked_entity: {
40
- category_codes: extractedRules.blockedEntity.categoryCodes,
41
- merchant_names: extractedRules.blockedEntity.merchantNames,
42
- },
43
- confidence_score: extractedRules.confidenceScore,
44
- policy_name: extractedRules.policyName,
45
- required_receipt_threshold: extractedRules.requiredReceiptThreshold,
46
- transaction_limit: extractedRules.transactionLimit,
47
- },
48
- };
49
- return zeniAPI
50
- .postAndGetJSON(`${zeniAPI.apiEndPoints.cardMicroServiceBaseUrl}/1.0/ai-cfo/policy-recommendation-from-upload`, body)
51
- .pipe(mergeMap((response) => {
52
- if (!isSuccessStatus(response) ||
53
- response.data?.wizard_plan?.step_5_review == null) {
54
- return of(updatePolicyRecommendationFromUploadFailure(response.status));
55
- }
56
- const data = response.data;
57
- const review = data.wizard_plan.step_5_review;
58
- const wizardPlan = {
59
- step5Review: {
60
- draftPolicies: (review.draft_policies ?? []).map((draft, index) => ({
61
- id: `draft-${index}`,
62
- name: draft.name,
63
- description: draft.description ?? '',
64
- mode: draft.mode,
65
- allowedEntity: {
66
- categoryCodes: draft.allowed_entity?.category_codes ?? [],
67
- merchantNames: draft.allowed_entity?.merchant_names ?? [],
68
- },
69
- blockedEntity: {
70
- categoryCodes: draft.blocked_entity?.category_codes ?? [],
71
- merchantNames: draft.blocked_entity?.merchant_names ?? [],
72
- },
73
- applyToCards: draft.apply_to_cards ?? [],
74
- requiredReceiptThreshold: draft.required_receipt_threshold ?? 0,
75
- spendLimits: {
76
- transaction: draft.spend_limits?.transaction ?? 0,
77
- },
78
- })),
79
- groupingSource: review.grouping_source ?? 'none',
80
- prompt: review.prompt ?? '',
81
- },
82
- };
83
- const source = data.source != null
84
- ? {
85
- confidenceScore: data.source.confidence_score,
86
- fileName: data.source.file_name,
87
- lowConfidenceFields: data.source.low_confidence_fields ?? [],
88
- }
89
- : undefined;
90
- return of(updatePolicyRecommendationFromUploadSuccess(), updateAiCfoAnswerCardPolicyWizardPlan({
91
- answerId,
92
- chatSessionId,
93
- wizardPlan,
94
- source,
95
- }));
96
- }), catchError((error) => of(updatePolicyRecommendationFromUploadFailure(createZeniAPIStatus('Unexpected Error', 'Policy recommendation from upload REST API call errored out' +
97
- JSON.stringify(error))))),
98
- // `clearPolicyDocumentExtraction` (× pill) tears down the in-flight
99
- // recommendation subscription so a late response can't dispatch
100
- // `updateAiCfoAnswerCardPolicyWizardPlan` against the captured-at-
101
- // kickoff `answerId`/`chatSessionId` and patch the AI CFO answer
102
- // with a wizard plan the user already dismissed. The outer
103
- // `switchMap` only handles the "another upload kicks off another
104
- // recommendation" race; this guards the orthogonal "user cleared
105
- // mid-flight" case.
106
- takeUntil(actions$.pipe(filter(clearPolicyDocumentExtraction.match))));
107
- }));