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

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 (121) hide show
  1. package/lib/common/aiCfo/aiCfoSuggestedQuestionsPageContext.d.ts +1 -1
  2. package/lib/entity/aiCfo/aiCfoPayload.d.ts +168 -1
  3. package/lib/entity/aiCfo/aiCfoReducer.js +186 -2
  4. package/lib/entity/aiCfo/aiCfoState.d.ts +164 -4
  5. package/lib/entity/aiCfo/aiCfoState.js +10 -1
  6. package/lib/entity/cardPolicy/cardPolicyPayload.d.ts +171 -0
  7. package/lib/entity/cardPolicy/cardPolicyPayload.js +112 -0
  8. package/lib/entity/cardPolicy/cardPolicyReducer.d.ts +13 -0
  9. package/lib/entity/cardPolicy/cardPolicyReducer.js +203 -0
  10. package/lib/entity/cardPolicy/cardPolicySelector.d.ts +28 -0
  11. package/lib/entity/cardPolicy/cardPolicySelector.js +86 -0
  12. package/lib/entity/cardPolicy/cardPolicyState.d.ts +162 -0
  13. package/lib/entity/cardPolicy/cardPolicyState.js +14 -0
  14. package/lib/entity/cardPolicy/extractPolicyDocumentEpic.d.ts +18 -0
  15. package/lib/entity/cardPolicy/extractPolicyDocumentEpic.js +54 -0
  16. package/lib/entity/cardPolicy/fetchCardPolicyVendorOptionsEpic.d.ts +26 -0
  17. package/lib/entity/cardPolicy/fetchCardPolicyVendorOptionsEpic.js +47 -0
  18. package/lib/entity/jeSchedules/jeSchedulesTypes.d.ts +1 -1
  19. package/lib/entity/monthEndCloseChecks/monthEndCloseChecksState.d.ts +1 -1
  20. package/lib/entity/tenant/clearAllEpic.d.ts +6 -2
  21. package/lib/entity/tenant/clearAllEpic.js +8 -0
  22. package/lib/epic.d.ts +9 -2
  23. package/lib/epic.js +9 -2
  24. package/lib/esm/entity/aiCfo/aiCfoReducer.js +187 -3
  25. package/lib/esm/entity/aiCfo/aiCfoState.js +7 -0
  26. package/lib/esm/entity/cardPolicy/cardPolicyPayload.js +101 -0
  27. package/lib/esm/entity/cardPolicy/cardPolicyReducer.js +199 -0
  28. package/lib/esm/entity/cardPolicy/cardPolicySelector.js +66 -0
  29. package/lib/esm/entity/cardPolicy/cardPolicyState.js +9 -0
  30. package/lib/esm/entity/cardPolicy/extractPolicyDocumentEpic.js +50 -0
  31. package/lib/esm/entity/cardPolicy/fetchCardPolicyVendorOptionsEpic.js +43 -0
  32. package/lib/esm/entity/tenant/clearAllEpic.js +8 -0
  33. package/lib/esm/epic.js +9 -2
  34. package/lib/esm/index.js +21 -7
  35. package/lib/esm/reducer.js +12 -0
  36. package/lib/esm/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js +1 -21
  37. package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +14 -117
  38. package/lib/esm/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +0 -28
  39. package/lib/esm/view/recommendation/recommendationHelper.js +0 -29
  40. package/lib/esm/view/recommendation/recommendationReducer.js +1 -36
  41. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailReducer.js +70 -0
  42. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailSelector.js +22 -0
  43. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailState.js +1 -0
  44. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/fetchCardPolicyDetailEpic.js +44 -0
  45. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/updateCardPolicyEpic.js +49 -0
  46. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/archiveCardPolicyEpic.js +42 -0
  47. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListReducer.js +72 -0
  48. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListSelector.js +21 -0
  49. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListState.js +1 -0
  50. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/fetchCardPolicyListEpic.js +46 -0
  51. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyReducer.js +50 -0
  52. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicySelector.js +6 -0
  53. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyState.js +1 -0
  54. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyTemplateEpic.js +34 -0
  55. package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/fetchCardPolicyMccCategoriesEpic.js +17 -0
  56. package/lib/esm/view/transactionDetail/transactionDetailReducer.js +1 -110
  57. package/lib/esm/view/transactionDetail/transactionDetailSelector.js +0 -22
  58. package/lib/index.d.ts +20 -8
  59. package/lib/index.js +119 -35
  60. package/lib/reducer.d.ts +12 -0
  61. package/lib/reducer.js +12 -0
  62. package/lib/view/companyHealthMetricView/companyHealthMetricViewSelector.d.ts +1 -1
  63. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +0 -1
  64. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.js +2 -23
  65. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.d.ts +1 -14
  66. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +14 -117
  67. package/lib/view/expenseAutomationView/selectorTypes/transactionsViewSelectorTypes.d.ts +0 -2
  68. package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.d.ts +0 -3
  69. package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +0 -29
  70. package/lib/view/expenseAutomationView/types/jeSchedulesViewState.d.ts +1 -1
  71. package/lib/view/expenseAutomationView/types/missingReceiptsViewState.d.ts +2 -2
  72. package/lib/view/expenseAutomationView/types/transactionsViewState.d.ts +1 -2
  73. package/lib/view/onboardingView/cockpitView/types/onboardingCockpitViewTypes.d.ts +1 -1
  74. package/lib/view/people/peopleTypes.d.ts +1 -1
  75. package/lib/view/recommendation/recommendationHelper.d.ts +0 -9
  76. package/lib/view/recommendation/recommendationHelper.js +1 -31
  77. package/lib/view/recommendation/recommendationReducer.d.ts +1 -18
  78. package/lib/view/recommendation/recommendationReducer.js +2 -37
  79. package/lib/view/scheduleView/scheduleListView/scheduleListTypes.d.ts +1 -1
  80. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailReducer.d.ts +14 -0
  81. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailReducer.js +74 -0
  82. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailSelector.d.ts +21 -0
  83. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailSelector.js +28 -0
  84. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailState.d.ts +25 -0
  85. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailState.js +2 -0
  86. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/fetchCardPolicyDetailEpic.d.ts +19 -0
  87. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/fetchCardPolicyDetailEpic.js +48 -0
  88. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/updateCardPolicyEpic.d.ts +18 -0
  89. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/updateCardPolicyEpic.js +53 -0
  90. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/archiveCardPolicyEpic.d.ts +16 -0
  91. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/archiveCardPolicyEpic.js +46 -0
  92. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListReducer.d.ts +15 -0
  93. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListReducer.js +76 -0
  94. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListSelector.d.ts +21 -0
  95. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListSelector.js +27 -0
  96. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListState.d.ts +19 -0
  97. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListState.js +2 -0
  98. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/fetchCardPolicyListEpic.d.ts +19 -0
  99. package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/fetchCardPolicyListEpic.js +50 -0
  100. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyReducer.d.ts +12 -0
  101. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyReducer.js +54 -0
  102. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicySelector.d.ts +4 -0
  103. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicySelector.js +10 -0
  104. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyState.d.ts +15 -0
  105. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyState.js +2 -0
  106. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyTemplateEpic.d.ts +8 -0
  107. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyTemplateEpic.js +38 -0
  108. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/fetchCardPolicyMccCategoriesEpic.d.ts +15 -0
  109. package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/fetchCardPolicyMccCategoriesEpic.js +21 -0
  110. package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardList.d.ts +1 -1
  111. package/lib/view/taskManager/taskListView/taskListReducer.d.ts +1 -1
  112. package/lib/view/transactionDetail/transactionDetailReducer.d.ts +1 -11
  113. package/lib/view/transactionDetail/transactionDetailReducer.js +2 -111
  114. package/lib/view/transactionDetail/transactionDetailSelector.d.ts +0 -2
  115. package/lib/view/transactionDetail/transactionDetailSelector.js +1 -24
  116. package/lib/view/transactionDetail/transactionDetailTypes.d.ts +0 -1
  117. package/package.json +1 -1
  118. package/lib/esm/view/recommendation/fetchEntityRecommendationsForLineUpdateEpic.js +0 -88
  119. package/lib/tsconfig.typecheck.tsbuildinfo +0 -1
  120. package/lib/view/recommendation/fetchEntityRecommendationsForLineUpdateEpic.d.ts +0 -9
  121. package/lib/view/recommendation/fetchEntityRecommendationsForLineUpdateEpic.js +0 -92
@@ -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
+ }));
@@ -365,21 +365,6 @@ const transactionDetail = createSlice({
365
365
  const detail = recordGet(draft.transactionDetailById, key, undefined);
366
366
  if (detail != null) {
367
367
  const newLocalData = setEntityRecommendationForLineIdInLocalData(transaction, detail.transactionDetailLocalData, action.payload.entity, lineIds, uncategorizedIncomeExpense, recommendationWithCOTByLineId);
368
- // Release the per-line fetch flag for every line this fetch
369
- // covered so the inline skeleton resolves and the page-level
370
- // Save button can re-enable.
371
- lineIds.forEach((lineId) => {
372
- const lineItem = newLocalData.lineItemById[lineId];
373
- if (lineItem != null) {
374
- newLocalData.lineItemById[lineId] = {
375
- ...lineItem,
376
- categoryClassRecommendationsFetchState: {
377
- fetchState: 'Completed',
378
- error: undefined,
379
- },
380
- };
381
- }
382
- });
383
368
  draft.transactionDetailById[key] = {
384
369
  ...detail,
385
370
  transactionDetailLocalData: newLocalData,
@@ -400,100 +385,6 @@ const transactionDetail = createSlice({
400
385
  };
401
386
  },
402
387
  },
403
- // Start arm of the line-update recommendations fetch for the detail
404
- // page. Flips covered lines to In-Progress; detail page has no
405
- // checkbox, so no auto-uncheck side effect.
406
- markCategoryClassRecommendationsInProgressForTransactionDetail: {
407
- reducer(draft, action) {
408
- const { transactionId, lineIds } = action.payload;
409
- const key = getTransactionDetailKey(transactionId);
410
- const detail = recordGet(draft.transactionDetailById, key, undefined);
411
- // TEMP-LOG[JE-skeleton]: reducer entry — confirms the action reached
412
- // the slice and shows whether incoming lineIds match the redux keys.
413
- // eslint-disable-next-line no-console
414
- console.log('[JE-skeleton][reducer] markInProgress detail', {
415
- transactionId,
416
- incomingLineIds: lineIds,
417
- existingLineItemKeys: detail != null
418
- ? Object.keys(detail.transactionDetailLocalData.lineItemById)
419
- : null,
420
- matched: detail != null
421
- ? lineIds.filter((id) => detail.transactionDetailLocalData.lineItemById[id] != null)
422
- : [],
423
- missed: detail != null
424
- ? lineIds.filter((id) => detail.transactionDetailLocalData.lineItemById[id] == null)
425
- : lineIds,
426
- });
427
- if (detail != null) {
428
- lineIds.forEach((lineId) => {
429
- const lineItem = detail.transactionDetailLocalData.lineItemById[lineId];
430
- if (lineItem != null) {
431
- detail.transactionDetailLocalData.lineItemById[lineId] = {
432
- ...lineItem,
433
- categoryClassRecommendationsFetchState: {
434
- fetchState: 'In-Progress',
435
- error: undefined,
436
- },
437
- };
438
- }
439
- });
440
- }
441
- },
442
- prepare(transactionId, lineIds) {
443
- return { payload: { transactionId, lineIds } };
444
- },
445
- },
446
- // Completed arm. Used when the HTTP call succeeded but the server
447
- // returned no per-line recommendations — still need to release the
448
- // In-Progress flag.
449
- markCategoryClassRecommendationsCompletedForTransactionDetail: {
450
- reducer(draft, action) {
451
- const { transactionId, lineIds } = action.payload;
452
- const key = getTransactionDetailKey(transactionId);
453
- const detail = recordGet(draft.transactionDetailById, key, undefined);
454
- if (detail != null) {
455
- lineIds.forEach((lineId) => {
456
- const lineItem = detail.transactionDetailLocalData.lineItemById[lineId];
457
- if (lineItem != null) {
458
- detail.transactionDetailLocalData.lineItemById[lineId] = {
459
- ...lineItem,
460
- categoryClassRecommendationsFetchState: {
461
- fetchState: 'Completed',
462
- error: undefined,
463
- },
464
- };
465
- }
466
- });
467
- }
468
- },
469
- prepare(transactionId, lineIds) {
470
- return { payload: { transactionId, lineIds } };
471
- },
472
- },
473
- markCategoryClassRecommendationsFailureForTransactionDetail: {
474
- reducer(draft, action) {
475
- const { transactionId, lineIds, error } = action.payload;
476
- const key = getTransactionDetailKey(transactionId);
477
- const detail = recordGet(draft.transactionDetailById, key, undefined);
478
- if (detail != null) {
479
- lineIds.forEach((lineId) => {
480
- const lineItem = detail.transactionDetailLocalData.lineItemById[lineId];
481
- if (lineItem != null) {
482
- detail.transactionDetailLocalData.lineItemById[lineId] = {
483
- ...lineItem,
484
- categoryClassRecommendationsFetchState: {
485
- fetchState: 'Error',
486
- error,
487
- },
488
- };
489
- }
490
- });
491
- }
492
- },
493
- prepare(transactionId, lineIds, error) {
494
- return { payload: { transactionId, lineIds, error } };
495
- },
496
- },
497
388
  removeEntityRecommendationForLineIdForTransactionDetail: {
498
389
  reducer(draft, action) {
499
390
  const { transaction, lineId } = action.payload;
@@ -765,7 +656,7 @@ const transactionDetail = createSlice({
765
656
  },
766
657
  },
767
658
  });
768
- export const { downloadAccountingProviderAttachment, downloadAccountingProviderAttachmentSuccess, downloadAccountingProviderAttachmentFailure, fetchTransactionDetail, updateTransactionDetailFetchState, removeTransactionDetail, clearTransactionDetail, uploadMissingAttachmentSuccess, updateTransactionDetail, updateTransactionDetailSaveStatus, clearTransactionDetailSaveStatus, markTransactionAsNotMiscategorized, deleteTransactionAttachment, deleteTransactionAttachmentFailure, deleteTransactionAttachmentSuccess, updateStatusForTransactionNotMiscategorizedUpdate, updateStatusConsolidatedSaveTransactionDetail, updateTransactionStateIfUpdateActionNotAllowed, saveTransactionDetail, initializeTransactionDetailLocalData, saveTransactionDetailLocalData, clearTransactionDetailLocalData, resetLineItemsCategoryClassInLocalData, setAllLineItemsToCategoryClassInLocalData, setAllLineItemsLocalDataIsUpdateAllChecked, setEntityRecommendationForLineIdsForTransactionDetail, markCategoryClassRecommendationsInProgressForTransactionDetail, markCategoryClassRecommendationsCompletedForTransactionDetail, markCategoryClassRecommendationsFailureForTransactionDetail, removeEntityRecommendationForLineIdForTransactionDetail, updateSelectedVendor, updateSelectedCustomer, resetVendor, resetSelectedCustomer, updateLocalDataWithTransactionsUpdateWithVendorCheckbox, updateVendorToAllLineItems, resetAllLineItemsToVendor, updateLatestSelectedEntity, updateVendorBulkRecommendationsFetchStatus, setIsVendorUpdateAllChecked, } = transactionDetail.actions;
659
+ export const { downloadAccountingProviderAttachment, downloadAccountingProviderAttachmentSuccess, downloadAccountingProviderAttachmentFailure, fetchTransactionDetail, updateTransactionDetailFetchState, removeTransactionDetail, clearTransactionDetail, uploadMissingAttachmentSuccess, updateTransactionDetail, updateTransactionDetailSaveStatus, clearTransactionDetailSaveStatus, markTransactionAsNotMiscategorized, deleteTransactionAttachment, deleteTransactionAttachmentFailure, deleteTransactionAttachmentSuccess, updateStatusForTransactionNotMiscategorizedUpdate, updateStatusConsolidatedSaveTransactionDetail, updateTransactionStateIfUpdateActionNotAllowed, saveTransactionDetail, initializeTransactionDetailLocalData, saveTransactionDetailLocalData, clearTransactionDetailLocalData, resetLineItemsCategoryClassInLocalData, setAllLineItemsToCategoryClassInLocalData, setAllLineItemsLocalDataIsUpdateAllChecked, setEntityRecommendationForLineIdsForTransactionDetail, removeEntityRecommendationForLineIdForTransactionDetail, updateSelectedVendor, updateSelectedCustomer, resetVendor, resetSelectedCustomer, updateLocalDataWithTransactionsUpdateWithVendorCheckbox, updateVendorToAllLineItems, resetAllLineItemsToVendor, updateLatestSelectedEntity, updateVendorBulkRecommendationsFetchStatus, setIsVendorUpdateAllChecked, } = transactionDetail.actions;
769
660
  export default transactionDetail.reducer;
770
661
  function getUpdatedEntityLocalData(detail, updates, entity, resetRecommendations, type) {
771
662
  const key = type === 'customer' ? 'customerUpdates' : 'vendorUpdates';
@@ -10,26 +10,6 @@ import { getAccountList, getNestedAccountListHierarchy, } from '../accountList/a
10
10
  import { getClassList, getNestedClassListHierarchy, } from '../classList/classListSelector';
11
11
  import { getProjectList, } from '../projectList/projectListSelector';
12
12
  import { getAllLinkedTransactions, getTransactionDetailKey, initialSupportedTransactionDetail, } from './transactionDetailState';
13
- // "Any line on this transaction is fetching category/class recommendations?"
14
- // Inlined as a plain function because the upstream selector
15
- // `getTransactionDetail` is also un-memoized and the iteration is O(lines)
16
- // — typically <10. Exported standalone so consumers that only need the
17
- // flag (e.g. footer save-disable) can avoid materializing the whole
18
- // detail report.
19
- export const getDetailInFlightRecommendations = (state, transactionId) => {
20
- const detailKey = getTransactionDetailKey(transactionId);
21
- const detail = recordGet(state.transactionDetailState.transactionDetailById, detailKey, undefined);
22
- if (detail == null) {
23
- return false;
24
- }
25
- for (const lineItem of Object.values(detail.transactionDetailLocalData.lineItemById)) {
26
- if (lineItem.categoryClassRecommendationsFetchState?.fetchState ===
27
- 'In-Progress') {
28
- return true;
29
- }
30
- }
31
- return false;
32
- };
33
13
  export const getTransactionDetail = (state, transactionId, fetchLinkedTransactions = true) => {
34
14
  const { transactionDetailState, transactionState, vendorState, vendorListState, accountState, classState, classListState, accountListState, projectState, projectListState, } = state;
35
15
  const detailKey = getTransactionDetailKey(transactionId);
@@ -92,7 +72,6 @@ export const getTransactionDetail = (state, transactionId, fetchLinkedTransactio
92
72
  : [];
93
73
  const transactionDetailAnyUpdateStatus = reduceUpdateFetchStates(transactionDetail);
94
74
  const vendors = getVendorsByVendorIds(vendorState, vendorListState.vendorIds);
95
- const hasInFlightCategoryClassRecommendations = getDetailInFlightRecommendations(state, transactionId);
96
75
  return {
97
76
  reportId: 'transaction_detail',
98
77
  reportTitle: 'Transaction Detail',
@@ -108,7 +87,6 @@ export const getTransactionDetail = (state, transactionId, fetchLinkedTransactio
108
87
  classHierarchyList,
109
88
  accountsHierarchyList,
110
89
  classList: classList,
111
- hasInFlightCategoryClassRecommendations,
112
90
  isAccountingClassesEnabled,
113
91
  isAccountingProjectsEnabled,
114
92
  projectList,