@zeniai/client-epic-state 5.0.65-betaML2 → 5.0.65-betaRR1

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 (115) hide show
  1. package/lib/entity/aiCfo/aiCfoPayload.d.ts +135 -1
  2. package/lib/entity/aiCfo/aiCfoReducer.js +111 -2
  3. package/lib/entity/aiCfo/aiCfoState.d.ts +141 -4
  4. package/lib/entity/aiCfo/aiCfoState.js +10 -1
  5. package/lib/entity/cardPolicy/cardPolicyPayload.d.ts +171 -0
  6. package/lib/entity/cardPolicy/cardPolicyPayload.js +112 -0
  7. package/lib/entity/cardPolicy/cardPolicyReducer.d.ts +13 -0
  8. package/lib/entity/cardPolicy/cardPolicyReducer.js +184 -0
  9. package/lib/entity/cardPolicy/cardPolicySelector.d.ts +28 -0
  10. package/lib/entity/cardPolicy/cardPolicySelector.js +86 -0
  11. package/lib/entity/cardPolicy/cardPolicyState.d.ts +162 -0
  12. package/lib/entity/cardPolicy/cardPolicyState.js +14 -0
  13. package/lib/entity/cardPolicy/extractPolicyDocumentEpic.d.ts +18 -0
  14. package/lib/entity/cardPolicy/extractPolicyDocumentEpic.js +54 -0
  15. package/lib/entity/cardPolicy/fetchCardPolicyVendorOptionsEpic.d.ts +26 -0
  16. package/lib/entity/cardPolicy/fetchCardPolicyVendorOptionsEpic.js +47 -0
  17. package/lib/entity/tenant/clearAllEpic.d.ts +6 -2
  18. package/lib/entity/tenant/clearAllEpic.js +8 -0
  19. package/lib/epic.d.ts +9 -2
  20. package/lib/epic.js +9 -2
  21. package/lib/esm/entity/aiCfo/aiCfoReducer.js +112 -3
  22. package/lib/esm/entity/aiCfo/aiCfoState.js +7 -0
  23. package/lib/esm/entity/cardPolicy/cardPolicyPayload.js +101 -0
  24. package/lib/esm/entity/cardPolicy/cardPolicyReducer.js +180 -0
  25. package/lib/esm/entity/cardPolicy/cardPolicySelector.js +66 -0
  26. package/lib/esm/entity/cardPolicy/cardPolicyState.js +9 -0
  27. package/lib/esm/entity/cardPolicy/extractPolicyDocumentEpic.js +50 -0
  28. package/lib/esm/entity/cardPolicy/fetchCardPolicyVendorOptionsEpic.js +43 -0
  29. package/lib/esm/entity/tenant/clearAllEpic.js +8 -0
  30. package/lib/esm/epic.js +9 -2
  31. package/lib/esm/index.js +21 -7
  32. package/lib/esm/reducer.js +12 -0
  33. package/lib/esm/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js +1 -21
  34. package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +14 -117
  35. package/lib/esm/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +0 -28
  36. package/lib/esm/view/recommendation/recommendationHelper.js +0 -29
  37. package/lib/esm/view/recommendation/recommendationReducer.js +1 -36
  38. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailReducer.js +70 -0
  39. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailSelector.js +22 -0
  40. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailState.js +1 -0
  41. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/fetchCardPolicyDetailEpic.js +44 -0
  42. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/updateCardPolicyEpic.js +49 -0
  43. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/archiveCardPolicyEpic.js +42 -0
  44. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListReducer.js +72 -0
  45. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListSelector.js +21 -0
  46. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListState.js +1 -0
  47. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/fetchCardPolicyListEpic.js +46 -0
  48. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyReducer.js +50 -0
  49. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicySelector.js +6 -0
  50. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyState.js +1 -0
  51. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyTemplateEpic.js +34 -0
  52. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/fetchCardPolicyMccCategoriesEpic.js +17 -0
  53. package/lib/esm/view/transactionDetail/transactionDetailReducer.js +1 -110
  54. package/lib/esm/view/transactionDetail/transactionDetailSelector.js +0 -22
  55. package/lib/index.d.ts +20 -8
  56. package/lib/index.js +119 -35
  57. package/lib/reducer.d.ts +12 -0
  58. package/lib/reducer.js +12 -0
  59. package/lib/view/companyHealthMetricView/companyHealthMetricViewSelector.d.ts +1 -1
  60. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +0 -1
  61. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js +2 -23
  62. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.d.ts +1 -14
  63. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +14 -117
  64. package/lib/view/expenseAutomationView/selectorTypes/transactionsViewSelectorTypes.d.ts +0 -2
  65. package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.d.ts +0 -3
  66. package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +0 -29
  67. package/lib/view/expenseAutomationView/types/transactionsViewState.d.ts +0 -1
  68. package/lib/view/onboardingView/cockpitView/types/onboardingCockpitViewTypes.d.ts +1 -1
  69. package/lib/view/people/peopleTypes.d.ts +1 -1
  70. package/lib/view/recommendation/recommendationHelper.d.ts +0 -9
  71. package/lib/view/recommendation/recommendationHelper.js +1 -31
  72. package/lib/view/recommendation/recommendationReducer.d.ts +1 -18
  73. package/lib/view/recommendation/recommendationReducer.js +2 -37
  74. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailReducer.d.ts +14 -0
  75. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailReducer.js +74 -0
  76. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailSelector.d.ts +21 -0
  77. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailSelector.js +28 -0
  78. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailState.d.ts +25 -0
  79. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailState.js +2 -0
  80. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/fetchCardPolicyDetailEpic.d.ts +19 -0
  81. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/fetchCardPolicyDetailEpic.js +48 -0
  82. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/updateCardPolicyEpic.d.ts +18 -0
  83. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/updateCardPolicyEpic.js +53 -0
  84. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/archiveCardPolicyEpic.d.ts +16 -0
  85. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/archiveCardPolicyEpic.js +46 -0
  86. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListReducer.d.ts +15 -0
  87. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListReducer.js +76 -0
  88. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListSelector.d.ts +21 -0
  89. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListSelector.js +27 -0
  90. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListState.d.ts +19 -0
  91. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListState.js +2 -0
  92. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/fetchCardPolicyListEpic.d.ts +19 -0
  93. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/fetchCardPolicyListEpic.js +50 -0
  94. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyReducer.d.ts +12 -0
  95. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyReducer.js +54 -0
  96. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicySelector.d.ts +4 -0
  97. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicySelector.js +10 -0
  98. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyState.d.ts +15 -0
  99. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyState.js +2 -0
  100. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyTemplateEpic.d.ts +8 -0
  101. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyTemplateEpic.js +38 -0
  102. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/fetchCardPolicyMccCategoriesEpic.d.ts +15 -0
  103. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/fetchCardPolicyMccCategoriesEpic.js +21 -0
  104. package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardList.d.ts +1 -1
  105. package/lib/view/taskManager/taskListView/taskListReducer.d.ts +1 -1
  106. package/lib/view/transactionDetail/transactionDetailReducer.d.ts +1 -11
  107. package/lib/view/transactionDetail/transactionDetailReducer.js +2 -111
  108. package/lib/view/transactionDetail/transactionDetailSelector.d.ts +0 -2
  109. package/lib/view/transactionDetail/transactionDetailSelector.js +1 -24
  110. package/lib/view/transactionDetail/transactionDetailTypes.d.ts +0 -1
  111. package/package.json +1 -1
  112. package/lib/esm/view/recommendation/fetchEntityRecommendationsForLineUpdateEpic.js +0 -88
  113. package/lib/tsconfig.typecheck.tsbuildinfo +0 -1
  114. package/lib/view/recommendation/fetchEntityRecommendationsForLineUpdateEpic.d.ts +0 -9
  115. package/lib/view/recommendation/fetchEntityRecommendationsForLineUpdateEpic.js +0 -92
@@ -1,5 +1,4 @@
1
1
  import { transformRecommendation, transformRecommendationWithCOT, } from '../../entity/transaction/payloadTypes/transactionPayload';
2
- import { getActualTransactionID } from '../transactionDetail/transactionDetailState';
3
2
  export const getRecommendationFromRecommendationPayload = (payload) => {
4
3
  if (payload == null || payload.length === 0) {
5
4
  return undefined;
@@ -38,34 +37,6 @@ export const getRecommendationWithCOTFromRecommendationPayloadWithCOT = (payload
38
37
  });
39
38
  return recommendations;
40
39
  };
41
- // Pluralized URL segment for entity types. Mirrors the legacy
42
- // fetchEntityRecommendationsByTransactionIdEpic.toEntityTypeURL.
43
- const toEntityTypeUrlSegment = (entityType) => `${entityType}s`;
44
- // Build the recommendations URL for a single entity + transaction target.
45
- // Centralizes the URL shape so the legacy
46
- // fetchEntityRecommendationsByTransactionIdEpic and the new
47
- // fetchEntityRecommendationsForLineUpdateEpic stay in lockstep.
48
- export const buildRecommendationUrl = (accountMicroServiceBaseUrl, entity, amount, transactionDetails, isFetchCOT) => {
49
- const entityQuery = {
50
- entity_name: entity.name,
51
- entity_type: entity.type,
52
- };
53
- // Entity-id-null case: server expects entity_name / entity_type query
54
- // instead of the {entityType}/{qboId}/recommendations path.
55
- if (entity.qboId === entity.name) {
56
- return `${accountMicroServiceBaseUrl}/1.0/recommendations?query=${encodeURIComponent(JSON.stringify(entityQuery))}`;
57
- }
58
- const query = {
59
- amount,
60
- transaction_id: getActualTransactionID(transactionDetails.transactionId.id),
61
- transaction_type: transactionDetails.transaction.type,
62
- line_ids: transactionDetails.lineIds,
63
- };
64
- if (isFetchCOT === true) {
65
- query.include_cot = true;
66
- }
67
- return `${accountMicroServiceBaseUrl}/1.0/${toEntityTypeUrlSegment(entity.type)}/${entity.qboId}/recommendations?query=${encodeURIComponent(JSON.stringify(query))}`;
68
- };
69
40
  export const getRecommendationByLineIdWithCOTFromRecommendationPayloadWithCOT = (recommendationPayload, lineIds) => {
70
41
  if (recommendationPayload.length === 0) {
71
42
  return undefined;
@@ -33,41 +33,6 @@ const recommendation = createSlice({
33
33
  };
34
34
  },
35
35
  },
36
- // Targeted recommendations fetch fired when the user changes the
37
- // payee/customer on a single transaction line (or the JE sibling set
38
- // for that change). Routed by `fetchEntityRecommendationsForLineUpdateEpic`
39
- // which uses groupBy + switchMap to keep fetches for distinct targets
40
- // running in parallel while same-target re-fetches still cancel each
41
- // other. The flowType discriminator selects the categorization vs
42
- // detail slice for the per-line In-Progress / Completed / Error state.
43
- fetchEntityRecommendationsForLineUpdate: {
44
- reducer(draft, action) {
45
- const { entity } = action.payload;
46
- const key = getEntityRecommendationKey(entity.type, entity.id);
47
- // Unconditional flip to In-Progress; the previous variant only
48
- // seeded when missing, which left stale fetchStates when a prior
49
- // fetch had already populated the entity entry.
50
- draft.recommendationByEntity[key] = {
51
- ...(draft.recommendationByEntity[key] ??
52
- initialEntityRecommendationState),
53
- fetchState: 'In-Progress',
54
- error: undefined,
55
- };
56
- },
57
- prepare(entity, amount, transactionDetails, flowType, selectedTab, isFetchCOT = false, isUncategorizedExpenseCategoryEnabled) {
58
- return {
59
- payload: {
60
- entity,
61
- amount,
62
- transactionDetails,
63
- flowType,
64
- selectedTab,
65
- isFetchCOT,
66
- isUncategorizedExpenseCategoryEnabled,
67
- },
68
- };
69
- },
70
- },
71
36
  fetchRecommendationByEntityName: {
72
37
  reducer(draft, action) {
73
38
  const { entityName, entityType } = action.payload;
@@ -146,7 +111,7 @@ const recommendation = createSlice({
146
111
  },
147
112
  },
148
113
  });
149
- export const { fetchEntityRecommendationsByTransactionId, fetchEntityRecommendationsForLineUpdate, fetchRecommendationByEntityName, fetchRecommendationByEntityId, updateRecommendationForEntity, updateRecommendationForEntityFailure, indicateReadyToInitializeRecommendation, clearRecommendation, } = recommendation.actions;
114
+ export const { fetchEntityRecommendationsByTransactionId, fetchRecommendationByEntityName, fetchRecommendationByEntityId, updateRecommendationForEntity, updateRecommendationForEntityFailure, indicateReadyToInitializeRecommendation, clearRecommendation, } = recommendation.actions;
150
115
  export default recommendation.reducer;
151
116
  const doUpdateRecommendationForEntity = (draft, entityId, entityType, payload) => {
152
117
  const key = getEntityRecommendationKey(entityType, entityId);
@@ -0,0 +1,70 @@
1
+ import { createSlice } from '@reduxjs/toolkit';
2
+ export const initialState = {
3
+ detailTemplateId: undefined,
4
+ detailFetchState: { fetchState: 'Not-Started', error: undefined },
5
+ updateFetchState: { fetchState: 'Not-Started', error: undefined },
6
+ formDraft: undefined,
7
+ };
8
+ const cardPolicyDetail = createSlice({
9
+ name: 'cardPolicyDetail',
10
+ initialState,
11
+ reducers: {
12
+ /**
13
+ * Kick off the `GET /cards/1.0/policy-templates/{id}` request. The
14
+ * accompanying epic dispatches `updateCreatedCardPolicyTemplate` on
15
+ * the entity slice + `updateCardPolicyFormDraft` (seeded from the
16
+ * template) + `updateCardPolicyDetailFetchStatus` here.
17
+ */
18
+ fetchCardPolicyDetail: {
19
+ reducer(draft, action) {
20
+ draft.detailTemplateId = action.payload;
21
+ draft.detailFetchState.fetchState = 'In-Progress';
22
+ draft.detailFetchState.error = undefined;
23
+ // Reset the draft so a stale form from a previous template
24
+ // doesn't leak into the new edit session.
25
+ draft.formDraft = undefined;
26
+ },
27
+ prepare(templateId) {
28
+ return { payload: templateId };
29
+ },
30
+ },
31
+ updateCardPolicyDetailFetchStatus(draft, action) {
32
+ draft.detailFetchState.fetchState = action.payload.fetchState;
33
+ draft.detailFetchState.error = action.payload.error;
34
+ },
35
+ /**
36
+ * Replace (or seed) the local edit-form draft. Dispatched by the
37
+ * detail-fetch epic with the camelCased values pulled from the
38
+ * fetched template, and by the edit page itself as the user types.
39
+ */
40
+ updateCardPolicyFormDraft(draft, action) {
41
+ draft.formDraft = action.payload;
42
+ },
43
+ /**
44
+ * Kick off the `PUT /cards/1.0/policy-templates/{id}` save. The
45
+ * epic reads the current `formDraft` from state, posts the wire
46
+ * body, then dispatches `updateCreatedCardPolicyTemplate` (entity)
47
+ * + `updateCardPolicyFetchStatus({fetchState: 'Completed'})` here.
48
+ */
49
+ updateCardPolicy: {
50
+ reducer(draft,
51
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
52
+ _action) {
53
+ draft.updateFetchState.fetchState = 'In-Progress';
54
+ draft.updateFetchState.error = undefined;
55
+ },
56
+ prepare(templateId) {
57
+ return { payload: templateId };
58
+ },
59
+ },
60
+ updateCardPolicyFetchStatus(draft, action) {
61
+ draft.updateFetchState.fetchState = action.payload.fetchState;
62
+ draft.updateFetchState.error = action.payload.error;
63
+ },
64
+ clearCardPolicyDetail(draft) {
65
+ Object.assign(draft, initialState);
66
+ },
67
+ },
68
+ });
69
+ export const { fetchCardPolicyDetail, updateCardPolicyDetailFetchStatus, updateCardPolicyFormDraft, updateCardPolicy, updateCardPolicyFetchStatus, clearCardPolicyDetail, } = cardPolicyDetail.actions;
70
+ export default cardPolicyDetail.reducer;
@@ -0,0 +1,22 @@
1
+ import { getCardPolicyTemplateById } from '../../../../../entity/cardPolicy/cardPolicySelector';
2
+ export function getCardPolicyDetailView(state) {
3
+ const { cardPolicyDetailState, cardPolicyState } = state;
4
+ return {
5
+ templateId: cardPolicyDetailState.detailTemplateId,
6
+ template: cardPolicyDetailState.detailTemplateId != null
7
+ ? getCardPolicyTemplateById(cardPolicyState, cardPolicyDetailState.detailTemplateId)
8
+ : undefined,
9
+ formDraft: cardPolicyDetailState.formDraft,
10
+ detailFetchState: cardPolicyDetailState.detailFetchState,
11
+ updateFetchState: cardPolicyDetailState.updateFetchState,
12
+ };
13
+ }
14
+ export function getCardPolicyFormDraft(state) {
15
+ return state.cardPolicyDetailState.formDraft;
16
+ }
17
+ export function getCardPolicyDetailFetchState(state) {
18
+ return state.cardPolicyDetailState.detailFetchState;
19
+ }
20
+ export function getUpdateCardPolicyFetchState(state) {
21
+ return state.cardPolicyDetailState.updateFetchState;
22
+ }
@@ -0,0 +1,44 @@
1
+ import { from, of } from 'rxjs';
2
+ import { catchError, filter, mergeMap } from 'rxjs/operators';
3
+ import { toCardPolicyEditFormDraft, toCardPolicyTemplate, } from '../../../../../entity/cardPolicy/cardPolicyPayload';
4
+ import { updateCreatedCardPolicyTemplate } from '../../../../../entity/cardPolicy/cardPolicyReducer';
5
+ import { createZeniAPIStatus, isSuccessStatus } from '../../../../../responsePayload';
6
+ import { fetchCardPolicyDetail, updateCardPolicyDetailFetchStatus, updateCardPolicyFormDraft, } from './cardPolicyDetailReducer';
7
+ /**
8
+ * `GET /cards/1.0/policy-templates/{id}`. Response is the same
9
+ * `{cards_applied, template}` envelope the create endpoint returns.
10
+ * We:
11
+ *
12
+ * 1. Cache the template on the entity slice (so the list page picks
13
+ * up any drift from the server).
14
+ * 2. Seed the local edit-form draft from the camelCased template so
15
+ * the page can render with the existing values pre-populated.
16
+ * 3. Flip the view lifecycle to `Completed` / `Error`.
17
+ */
18
+ export const fetchCardPolicyDetailEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(fetchCardPolicyDetail.match), mergeMap((action) => {
19
+ const templateId = action.payload;
20
+ return zeniAPI
21
+ .getJSON(`${zeniAPI.apiEndPoints.cardMicroServiceBaseUrl}/1.0/policy-templates/${templateId}`)
22
+ .pipe(mergeMap((response) => {
23
+ if (isSuccessStatus(response) && response.data != null) {
24
+ const { template } = response.data;
25
+ const formDraft = toCardPolicyEditFormDraft(toCardPolicyTemplate(template));
26
+ const actions = [
27
+ updateCreatedCardPolicyTemplate(template),
28
+ updateCardPolicyFormDraft(formDraft),
29
+ updateCardPolicyDetailFetchStatus({ fetchState: 'Completed' }),
30
+ ];
31
+ return from(actions);
32
+ }
33
+ else {
34
+ return of(updateCardPolicyDetailFetchStatus({
35
+ fetchState: 'Error',
36
+ error: response.status,
37
+ }));
38
+ }
39
+ }), catchError((error) => of(updateCardPolicyDetailFetchStatus({
40
+ fetchState: 'Error',
41
+ error: createZeniAPIStatus('Unexpected Error', 'Fetch card-policy detail REST API call errored out' +
42
+ JSON.stringify(error)),
43
+ }))));
44
+ }));
@@ -0,0 +1,49 @@
1
+ import { from, of } from 'rxjs';
2
+ import { catchError, filter, mergeMap } from 'rxjs/operators';
3
+ import { toUpdateCardPolicyTemplateRequestBody, } from '../../../../../entity/cardPolicy/cardPolicyPayload';
4
+ import { updateCreatedCardPolicyTemplate } from '../../../../../entity/cardPolicy/cardPolicyReducer';
5
+ import { createZeniAPIStatus, isSuccessStatus } from '../../../../../responsePayload';
6
+ import { updateCardPolicy, updateCardPolicyFetchStatus, } from './cardPolicyDetailReducer';
7
+ /**
8
+ * `PUT /cards/1.0/policy-templates/{id}`. Reads the current `formDraft`
9
+ * off the `cardPolicyDetail` slice, converts it to the snake_case wire
10
+ * body (same shape as create), and submits. On success the entity
11
+ * slice picks up the refreshed template and the view lifecycle flips
12
+ * to `Completed`.
13
+ *
14
+ * If the action fires before a draft is seeded (e.g. user clicks save
15
+ * before the detail fetch lands), we short-circuit with an Error.
16
+ */
17
+ export const updateCardPolicyEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(updateCardPolicy.match), mergeMap((action) => {
18
+ const templateId = action.payload;
19
+ const formDraft = state$.value.cardPolicyDetailState.formDraft;
20
+ if (formDraft == null) {
21
+ return of(updateCardPolicyFetchStatus({
22
+ fetchState: 'Error',
23
+ error: createZeniAPIStatus('Missing form draft', `Cannot update card-policy ${templateId} — no formDraft is loaded.`),
24
+ }));
25
+ }
26
+ const body = toUpdateCardPolicyTemplateRequestBody(formDraft);
27
+ return zeniAPI
28
+ .putAndGetJSON(`${zeniAPI.apiEndPoints.cardMicroServiceBaseUrl}/1.0/policy-templates/${templateId}`, body)
29
+ .pipe(mergeMap((response) => {
30
+ if (isSuccessStatus(response) && response.data != null) {
31
+ const { template } = response.data;
32
+ const actions = [
33
+ updateCreatedCardPolicyTemplate(template),
34
+ updateCardPolicyFetchStatus({ fetchState: 'Completed' }),
35
+ ];
36
+ return from(actions);
37
+ }
38
+ else {
39
+ return of(updateCardPolicyFetchStatus({
40
+ fetchState: 'Error',
41
+ error: response.status,
42
+ }));
43
+ }
44
+ }), catchError((error) => of(updateCardPolicyFetchStatus({
45
+ fetchState: 'Error',
46
+ error: createZeniAPIStatus('Unexpected Error', 'Update card-policy REST API call errored out' +
47
+ JSON.stringify(error)),
48
+ }))));
49
+ }));
@@ -0,0 +1,42 @@
1
+ import { from, of } from 'rxjs';
2
+ import { catchError, filter, mergeMap } from 'rxjs/operators';
3
+ import { removeCardPolicyTemplate } from '../../../../../entity/cardPolicy/cardPolicyReducer';
4
+ import { createZeniAPIStatus, isSuccessStatus, } from '../../../../../responsePayload';
5
+ import { archiveCardPolicy, updateArchiveCardPolicyFetchStatus, } from './cardPolicyListReducer';
6
+ /**
7
+ * `DELETE /cards/1.0/policy-templates/{id}`. Modeled like
8
+ * `deleteBillEpic`: typed as bare `ZeniAPIResponse` (no `data` body
9
+ * expected) with `isSuccessStatus` driving the success branch. On
10
+ * success the entity slice drops the template via
11
+ * `removeCardPolicyTemplate(templateId)` and the view slice records
12
+ * `Completed` (also pruning the ID from `templateIds`).
13
+ */
14
+ export const archiveCardPolicyEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(archiveCardPolicy.match), mergeMap((action) => {
15
+ const templateId = action.payload;
16
+ return zeniAPI
17
+ .deleteAndGetJSON(`${zeniAPI.apiEndPoints.cardMicroServiceBaseUrl}/1.0/policy-templates/${templateId}`)
18
+ .pipe(mergeMap((response) => {
19
+ if (isSuccessStatus(response)) {
20
+ const actions = [
21
+ removeCardPolicyTemplate(templateId),
22
+ updateArchiveCardPolicyFetchStatus({
23
+ fetchState: 'Completed',
24
+ templateId,
25
+ }),
26
+ ];
27
+ return from(actions);
28
+ }
29
+ else {
30
+ return of(updateArchiveCardPolicyFetchStatus({
31
+ fetchState: 'Error',
32
+ error: response.status,
33
+ templateId,
34
+ }));
35
+ }
36
+ }), catchError((error) => of(updateArchiveCardPolicyFetchStatus({
37
+ fetchState: 'Error',
38
+ error: createZeniAPIStatus('Unexpected Error', 'Archive card-policy REST API call errored out' +
39
+ JSON.stringify(error)),
40
+ templateId,
41
+ }))));
42
+ }));
@@ -0,0 +1,72 @@
1
+ import { createSlice } from '@reduxjs/toolkit';
2
+ export const initialState = {
3
+ templateIds: [],
4
+ fetchState: {
5
+ fetchState: 'Not-Started',
6
+ error: undefined,
7
+ },
8
+ archiveFetchState: {
9
+ fetchState: 'Not-Started',
10
+ error: undefined,
11
+ },
12
+ archiveTargetTemplateId: undefined,
13
+ };
14
+ const cardPolicyList = createSlice({
15
+ name: 'cardPolicyList',
16
+ initialState,
17
+ reducers: {
18
+ /**
19
+ * Kick off the `GET /cards/1.0/policy-templates` request. The
20
+ * accompanying epic dispatches `updateCardPolicyTemplates(templates)`
21
+ * + `updateCardPolicyStats(stats)` on the entity slice and
22
+ * `updateCardPolicyListFetchStatus` here (also supplying the ordered
23
+ * `templateIds` on success).
24
+ */
25
+ fetchCardPolicyList(draft) {
26
+ draft.fetchState.fetchState = 'In-Progress';
27
+ draft.fetchState.error = undefined;
28
+ },
29
+ updateCardPolicyListFetchStatus(draft, action) {
30
+ draft.fetchState.fetchState = action.payload.fetchState;
31
+ draft.fetchState.error = action.payload.error;
32
+ if (action.payload.templateIds != null) {
33
+ draft.templateIds = action.payload.templateIds;
34
+ }
35
+ },
36
+ /**
37
+ * Kick off the `DELETE /cards/1.0/policy-templates/{id}` request.
38
+ * The accompanying epic dispatches `removeCardPolicyTemplate(id)` on
39
+ * the entity slice on success + `updateArchiveCardPolicyFetchStatus`
40
+ * here. The view layer also drops the ID from `templateIds` so the
41
+ * list stays in sync without re-fetching.
42
+ */
43
+ archiveCardPolicy: {
44
+ reducer(draft, action) {
45
+ draft.archiveFetchState.fetchState = 'In-Progress';
46
+ draft.archiveFetchState.error = undefined;
47
+ draft.archiveTargetTemplateId = action.payload;
48
+ },
49
+ prepare(templateId) {
50
+ return { payload: templateId };
51
+ },
52
+ },
53
+ updateArchiveCardPolicyFetchStatus(draft, action) {
54
+ draft.archiveFetchState.fetchState = action.payload.fetchState;
55
+ draft.archiveFetchState.error = action.payload.error;
56
+ if (action.payload.fetchState === 'Completed') {
57
+ if (action.payload.templateId != null) {
58
+ draft.templateIds = draft.templateIds.filter((id) => id !== action.payload.templateId);
59
+ }
60
+ draft.archiveTargetTemplateId = undefined;
61
+ }
62
+ else if (action.payload.fetchState === 'Error') {
63
+ draft.archiveTargetTemplateId = undefined;
64
+ }
65
+ },
66
+ clearCardPolicyList(draft) {
67
+ Object.assign(draft, initialState);
68
+ },
69
+ },
70
+ });
71
+ export const { fetchCardPolicyList, updateCardPolicyListFetchStatus, archiveCardPolicy, updateArchiveCardPolicyFetchStatus, clearCardPolicyList, } = cardPolicyList.actions;
72
+ export default cardPolicyList.reducer;
@@ -0,0 +1,21 @@
1
+ import { getCardPolicyStats, getCardPolicyTemplatesByIds, } from '../../../../../entity/cardPolicy/cardPolicySelector';
2
+ export function getCardPolicyListView(state) {
3
+ const { cardPolicyListState, cardPolicyState } = state;
4
+ return {
5
+ templates: getCardPolicyTemplatesByIds(cardPolicyState, cardPolicyListState.templateIds),
6
+ templateIds: cardPolicyListState.templateIds,
7
+ fetchState: cardPolicyListState.fetchState,
8
+ archiveFetchState: cardPolicyListState.archiveFetchState,
9
+ archiveTargetTemplateId: cardPolicyListState.archiveTargetTemplateId,
10
+ stats: getCardPolicyStats(cardPolicyState),
11
+ };
12
+ }
13
+ export function getCardPolicyListFetchState(state) {
14
+ return state.cardPolicyListState.fetchState;
15
+ }
16
+ export function getArchiveCardPolicyFetchState(state) {
17
+ return state.cardPolicyListState.archiveFetchState;
18
+ }
19
+ export function getCardPolicyTemplateIds(state) {
20
+ return state.cardPolicyListState.templateIds;
21
+ }
@@ -0,0 +1,46 @@
1
+ import { from, of } from 'rxjs';
2
+ import { catchError, filter, mergeMap } from 'rxjs/operators';
3
+ import { toCardPolicyStats, toCardPolicyTemplateList, } from '../../../../../entity/cardPolicy/cardPolicyPayload';
4
+ import { updateCardPolicyStats, updateCardPolicyTemplates, } from '../../../../../entity/cardPolicy/cardPolicyReducer';
5
+ import { createZeniAPIStatus, isSuccessStatus } from '../../../../../responsePayload';
6
+ import { fetchCardPolicyList, updateCardPolicyListFetchStatus, } from './cardPolicyListReducer';
7
+ /**
8
+ * `GET /cards/1.0/policy-templates`. On success the response carries
9
+ * both the tenant-wide `stats` block and a `templates[]` array whose
10
+ * rows are wrapped in `{data: {cards_applied, template}}` (the same
11
+ * envelope the create endpoint returns). We split the result into
12
+ * three actions:
13
+ *
14
+ * 1. `updateCardPolicyTemplates` — full replace of the entity map.
15
+ * 2. `updateCardPolicyStats` — entity-level cached stats.
16
+ * 3. `updateCardPolicyListFetchStatus` — view lifecycle + ordered IDs.
17
+ */
18
+ export const fetchCardPolicyListEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(fetchCardPolicyList.match), mergeMap(() => {
19
+ return zeniAPI
20
+ .getJSON(`${zeniAPI.apiEndPoints.cardMicroServiceBaseUrl}/1.0/policy-templates`)
21
+ .pipe(mergeMap((response) => {
22
+ if (isSuccessStatus(response) && response.data != null) {
23
+ const templates = toCardPolicyTemplateList(response.data);
24
+ const stats = toCardPolicyStats(response.data.stats);
25
+ const actions = [
26
+ updateCardPolicyTemplates(templates),
27
+ updateCardPolicyStats(stats),
28
+ updateCardPolicyListFetchStatus({
29
+ fetchState: 'Completed',
30
+ templateIds: templates.map((t) => t.templateId),
31
+ }),
32
+ ];
33
+ return from(actions);
34
+ }
35
+ else {
36
+ return of(updateCardPolicyListFetchStatus({
37
+ fetchState: 'Error',
38
+ error: response.status,
39
+ }));
40
+ }
41
+ }), catchError((error) => of(updateCardPolicyListFetchStatus({
42
+ fetchState: 'Error',
43
+ error: createZeniAPIStatus('Unexpected Error', 'Fetch card-policy list REST API call errored out' +
44
+ JSON.stringify(error)),
45
+ }))));
46
+ }));
@@ -0,0 +1,50 @@
1
+ import { createSlice } from '@reduxjs/toolkit';
2
+ export const initialState = {
3
+ createCardPolicyTemplateRequestState: {
4
+ fetchState: 'Not-Started',
5
+ error: undefined,
6
+ },
7
+ lastCreatedCardPolicyTemplateId: undefined,
8
+ };
9
+ const createCardPolicy = createSlice({
10
+ name: 'createCardPolicy',
11
+ initialState,
12
+ reducers: {
13
+ /**
14
+ * Kick off the `POST /cards/1.0/policy-templates` request. Setting
15
+ * the request state to `In-Progress` synchronously here matches how
16
+ * every other "create" slice in this repo wires its kickoff
17
+ * (see `issueChargeCards`, `fetchChargeCardConfig`, etc.).
18
+ *
19
+ * The accompanying epic listens for this action, performs the POST,
20
+ * dispatches `updateCreatedCardPolicyTemplate` on the entity slice,
21
+ * and dispatches `updateCreateCardPolicyTemplateRequestState` here to
22
+ * flip the lifecycle to `Completed` or `Error`.
23
+ */
24
+ createCardPolicyTemplate: {
25
+ reducer(draft,
26
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
27
+ _action) {
28
+ draft.createCardPolicyTemplateRequestState.fetchState = 'In-Progress';
29
+ draft.createCardPolicyTemplateRequestState.error = undefined;
30
+ draft.lastCreatedCardPolicyTemplateId = undefined;
31
+ },
32
+ prepare(request) {
33
+ return { payload: request };
34
+ },
35
+ },
36
+ updateCreateCardPolicyTemplateRequestState(draft, action) {
37
+ draft.createCardPolicyTemplateRequestState.fetchState =
38
+ action.payload.fetchState;
39
+ draft.createCardPolicyTemplateRequestState.error = action.payload.error;
40
+ if (action.payload.templateId != null) {
41
+ draft.lastCreatedCardPolicyTemplateId = action.payload.templateId;
42
+ }
43
+ },
44
+ clearCreateCardPolicy(draft) {
45
+ Object.assign(draft, initialState);
46
+ },
47
+ },
48
+ });
49
+ export const { createCardPolicyTemplate, updateCreateCardPolicyTemplateRequestState, clearCreateCardPolicy, } = createCardPolicy.actions;
50
+ export default createCardPolicy.reducer;
@@ -0,0 +1,6 @@
1
+ export function getCreateCardPolicyTemplateRequestState(state) {
2
+ return state.createCardPolicyTemplateRequestState;
3
+ }
4
+ export function getLastCreatedCardPolicyTemplateId(state) {
5
+ return state.lastCreatedCardPolicyTemplateId;
6
+ }
@@ -0,0 +1,34 @@
1
+ import { from, of } from 'rxjs';
2
+ import { catchError, filter, mergeMap } from 'rxjs/operators';
3
+ import { updateCreatedCardPolicyTemplate } from '../../../../../entity/cardPolicy/cardPolicyReducer';
4
+ import { toCreateCardPolicyTemplateRequestBody, } from '../../../../../entity/cardPolicy/cardPolicyPayload';
5
+ import { createZeniAPIStatus, isSuccessStatus } from '../../../../../responsePayload';
6
+ import { createCardPolicyTemplate, updateCreateCardPolicyTemplateRequestState, } from './createCardPolicyReducer';
7
+ export const createCardPolicyTemplateEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(createCardPolicyTemplate.match), mergeMap((action) => {
8
+ const body = toCreateCardPolicyTemplateRequestBody(action.payload);
9
+ return zeniAPI
10
+ .postAndGetJSON(`${zeniAPI.apiEndPoints.cardMicroServiceBaseUrl}/1.0/policy-templates`, body)
11
+ .pipe(mergeMap((response) => {
12
+ if (isSuccessStatus(response) && response.data != null) {
13
+ const { template } = response.data;
14
+ const actions = [
15
+ updateCreatedCardPolicyTemplate(template),
16
+ updateCreateCardPolicyTemplateRequestState({
17
+ fetchState: 'Completed',
18
+ templateId: template.template_id,
19
+ }),
20
+ ];
21
+ return from(actions);
22
+ }
23
+ else {
24
+ return of(updateCreateCardPolicyTemplateRequestState({
25
+ fetchState: 'Error',
26
+ error: response.status,
27
+ }));
28
+ }
29
+ }), catchError((error) => of(updateCreateCardPolicyTemplateRequestState({
30
+ fetchState: 'Error',
31
+ error: createZeniAPIStatus('Unexpected Error', 'Create card-policy template REST API call errored out' +
32
+ JSON.stringify(error)),
33
+ }))));
34
+ }));
@@ -0,0 +1,17 @@
1
+ import { from, of } from 'rxjs';
2
+ import { catchError, filter, mergeMap } from 'rxjs/operators';
3
+ import { fetchCardPolicyMccCategories, updateCardPolicyMccCategories, updateCardPolicyMccCategoriesFailure, } from '../../../../../entity/cardPolicy/cardPolicyReducer';
4
+ import { createZeniAPIStatus, isSuccessStatus } from '../../../../../responsePayload';
5
+ export const fetchCardPolicyMccCategoriesEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(fetchCardPolicyMccCategories.match), mergeMap(() => {
6
+ return zeniAPI
7
+ .getJSON(`${zeniAPI.apiEndPoints.cardMicroServiceBaseUrl}/1.0/cards/mcc-codes`)
8
+ .pipe(mergeMap((response) => {
9
+ if (isSuccessStatus(response) && response.data != null) {
10
+ return from([updateCardPolicyMccCategories(response.data)]);
11
+ }
12
+ else {
13
+ return of(updateCardPolicyMccCategoriesFailure(response.status));
14
+ }
15
+ }), catchError((error) => of(updateCardPolicyMccCategoriesFailure(createZeniAPIStatus('Unexpected Error', 'Fetch card policy MCC categories REST API call errored out' +
16
+ JSON.stringify(error))))));
17
+ }));