@zeniai/client-epic-state 5.0.82 → 5.0.83-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.
- package/lib/common/aiCfo/aiCfoSuggestedQuestionsPageContext.d.ts +1 -1
- package/lib/entity/aiCfo/aiCfoPayload.d.ts +140 -1
- package/lib/entity/aiCfo/aiCfoReducer.d.ts +23 -2
- package/lib/entity/aiCfo/aiCfoReducer.js +328 -5
- package/lib/entity/aiCfo/aiCfoSelector.d.ts +13 -1
- package/lib/entity/aiCfo/aiCfoSelector.js +28 -1
- package/lib/entity/aiCfo/aiCfoState.d.ts +225 -4
- package/lib/entity/aiCfo/aiCfoState.js +30 -1
- package/lib/entity/cardPolicy/cardPolicyPayload.d.ts +277 -0
- package/lib/entity/cardPolicy/cardPolicyPayload.js +143 -0
- package/lib/entity/cardPolicy/cardPolicyReducer.d.ts +19 -0
- package/lib/entity/cardPolicy/cardPolicyReducer.js +175 -0
- package/lib/entity/cardPolicy/cardPolicySelector.d.ts +32 -0
- package/lib/entity/cardPolicy/cardPolicySelector.js +99 -0
- package/lib/entity/cardPolicy/cardPolicyState.d.ts +205 -0
- package/lib/entity/cardPolicy/cardPolicyState.js +14 -0
- package/lib/entity/cardPolicy/extractPolicyDocumentEpic.d.ts +18 -0
- package/lib/entity/cardPolicy/extractPolicyDocumentEpic.js +68 -0
- package/lib/entity/cardPolicy/fetchCardPolicyVendorOptionsEpic.d.ts +26 -0
- package/lib/entity/cardPolicy/fetchCardPolicyVendorOptionsEpic.js +47 -0
- package/lib/entity/cardPolicy/policyDocumentExtractionToRecommendationBridgeEpic.d.ts +25 -0
- package/lib/entity/cardPolicy/policyDocumentExtractionToRecommendationBridgeEpic.js +39 -0
- package/lib/entity/cardPolicy/policyRecommendationFromUploadEpic.d.ts +23 -0
- package/lib/entity/cardPolicy/policyRecommendationFromUploadEpic.js +104 -0
- package/lib/entity/jeSchedules/jeSchedulesTypes.d.ts +1 -1
- package/lib/entity/monthEndCloseChecks/monthEndCloseChecksState.d.ts +1 -1
- package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
- package/lib/entity/snackbar/snackbarTypes.js +3 -0
- package/lib/entity/tenant/clearAllEpic.d.ts +6 -2
- package/lib/entity/tenant/clearAllEpic.js +8 -0
- package/lib/epic.d.ts +11 -1
- package/lib/epic.js +11 -1
- package/lib/esm/entity/aiCfo/aiCfoReducer.js +328 -5
- package/lib/esm/entity/aiCfo/aiCfoSelector.js +26 -1
- package/lib/esm/entity/aiCfo/aiCfoState.js +27 -0
- package/lib/esm/entity/cardPolicy/cardPolicyPayload.js +130 -0
- package/lib/esm/entity/cardPolicy/cardPolicyReducer.js +171 -0
- package/lib/esm/entity/cardPolicy/cardPolicySelector.js +75 -0
- package/lib/esm/entity/cardPolicy/cardPolicyState.js +9 -0
- package/lib/esm/entity/cardPolicy/extractPolicyDocumentEpic.js +64 -0
- package/lib/esm/entity/cardPolicy/fetchCardPolicyVendorOptionsEpic.js +43 -0
- package/lib/esm/entity/cardPolicy/policyDocumentExtractionToRecommendationBridgeEpic.js +35 -0
- package/lib/esm/entity/cardPolicy/policyRecommendationFromUploadEpic.js +100 -0
- package/lib/esm/entity/snackbar/snackbarTypes.js +3 -0
- package/lib/esm/entity/tenant/clearAllEpic.js +8 -0
- package/lib/esm/epic.js +11 -1
- package/lib/esm/index.js +27 -8
- package/lib/esm/reducer.js +12 -0
- package/lib/esm/view/aiCfoView/aiCfoViewReducer.js +6 -3
- package/lib/esm/view/aiCfoView/epics/createSessionAndSubmitEpic.js +5 -2
- package/lib/esm/view/aiCfoView/epics/createSessionEpic.js +2 -1
- package/lib/esm/view/aiCfoView/epics/fetchSuggestedQuestionsEpic.js +12 -2
- package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailReducer.js +70 -0
- package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailSelector.js +22 -0
- package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailState.js +1 -0
- package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/fetchCardPolicyDetailEpic.js +56 -0
- package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/updateCardPolicyEpic.js +49 -0
- package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/archiveCardPolicyEpic.js +42 -0
- package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListReducer.js +72 -0
- package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListSelector.js +21 -0
- package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListState.js +1 -0
- package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/fetchCardPolicyListEpic.js +56 -0
- package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyReducer.js +45 -0
- package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicySelector.js +39 -0
- package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyState.js +1 -0
- package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyTemplateEpic.js +53 -0
- package/lib/esm/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/fetchCardPolicyMccCategoriesEpic.js +25 -0
- package/lib/esm/view/spendManagement/chargeCards/chargeCardList/chargeCardListSelector.js +25 -0
- package/lib/esm/view/spendManagement/chargeCards/issueChargeCard/aiCardCreationFormDraftTypes.js +1 -0
- package/lib/esm/view/spendManagement/chargeCards/issueChargeCard/applyAiCardCreationFormDraftUpdate.js +20 -0
- package/lib/esm/view/spendManagement/chargeCards/issueChargeCard/buildAiCardCreationFormDraftSeed.js +62 -0
- package/lib/esm/view/spendManagement/chargeCards/issueChargeCard/deriveAiCardRowsFromTeams.js +47 -0
- package/lib/esm/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardEpic.js +2 -2
- package/lib/esm/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardReducer.js +48 -4
- package/lib/esm/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardSelector.js +61 -0
- package/lib/esm/view/spendManagement/chargeCards/issueChargeCard/toIssueChargeCardLocalDataFromDraft.js +69 -0
- package/lib/index.d.ts +26 -8
- package/lib/index.js +141 -13
- package/lib/reducer.d.ts +12 -0
- package/lib/reducer.js +12 -0
- package/lib/view/aiCfoView/aiCfoViewReducer.d.ts +11 -2
- package/lib/view/aiCfoView/aiCfoViewReducer.js +6 -3
- package/lib/view/aiCfoView/epics/createSessionAndSubmitEpic.js +5 -2
- package/lib/view/aiCfoView/epics/createSessionEpic.js +2 -1
- package/lib/view/aiCfoView/epics/fetchSuggestedQuestionsEpic.d.ts +8 -1
- package/lib/view/aiCfoView/epics/fetchSuggestedQuestionsEpic.js +12 -2
- package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
- package/lib/view/expenseAutomationView/types/reconciliationViewState.d.ts +1 -1
- package/lib/view/people/peopleTypes.d.ts +1 -1
- package/lib/view/scheduleView/scheduleListView/scheduleListTypes.d.ts +1 -1
- package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailReducer.d.ts +14 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailReducer.js +74 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailSelector.d.ts +21 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailSelector.js +28 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailState.d.ts +25 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/cardPolicyDetailState.js +2 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/fetchCardPolicyDetailEpic.d.ts +19 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/fetchCardPolicyDetailEpic.js +60 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/updateCardPolicyEpic.d.ts +18 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyDetail/updateCardPolicyEpic.js +53 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/archiveCardPolicyEpic.d.ts +16 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/archiveCardPolicyEpic.js +46 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListReducer.d.ts +15 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListReducer.js +76 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListSelector.d.ts +21 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListSelector.js +27 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListState.d.ts +19 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListState.js +2 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/fetchCardPolicyListEpic.d.ts +19 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/fetchCardPolicyListEpic.js +60 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyReducer.d.ts +13 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyReducer.js +49 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicySelector.d.ts +32 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicySelector.js +46 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyState.d.ts +45 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyState.js +2 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyTemplateEpic.d.ts +25 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/createCardPolicyTemplateEpic.js +57 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/fetchCardPolicyMccCategoriesEpic.d.ts +15 -0
- package/lib/view/spendManagement/chargeCards/cardPolicy/createCardPolicy/fetchCardPolicyMccCategoriesEpic.js +29 -0
- package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardList.d.ts +1 -1
- package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardListSelector.d.ts +14 -0
- package/lib/view/spendManagement/chargeCards/chargeCardList/chargeCardListSelector.js +27 -1
- package/lib/view/spendManagement/chargeCards/issueChargeCard/aiCardCreationFormDraftTypes.d.ts +79 -0
- package/lib/view/spendManagement/chargeCards/issueChargeCard/aiCardCreationFormDraftTypes.js +2 -0
- package/lib/view/spendManagement/chargeCards/issueChargeCard/applyAiCardCreationFormDraftUpdate.d.ts +6 -0
- package/lib/view/spendManagement/chargeCards/issueChargeCard/applyAiCardCreationFormDraftUpdate.js +24 -0
- package/lib/view/spendManagement/chargeCards/issueChargeCard/buildAiCardCreationFormDraftSeed.d.ts +25 -0
- package/lib/view/spendManagement/chargeCards/issueChargeCard/buildAiCardCreationFormDraftSeed.js +66 -0
- package/lib/view/spendManagement/chargeCards/issueChargeCard/deriveAiCardRowsFromTeams.d.ts +26 -0
- package/lib/view/spendManagement/chargeCards/issueChargeCard/deriveAiCardRowsFromTeams.js +51 -0
- package/lib/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardEpic.d.ts +2 -2
- package/lib/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardEpic.js +1 -1
- package/lib/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardReducer.d.ts +12 -2
- package/lib/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardReducer.js +49 -5
- package/lib/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardSelector.d.ts +42 -0
- package/lib/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardSelector.js +68 -1
- package/lib/view/spendManagement/chargeCards/issueChargeCard/issueChargeCardState.d.ts +18 -0
- package/lib/view/spendManagement/chargeCards/issueChargeCard/toIssueChargeCardLocalDataFromDraft.d.ts +11 -0
- package/lib/view/spendManagement/chargeCards/issueChargeCard/toIssueChargeCardLocalDataFromDraft.js +73 -0
- package/lib/view/taskManager/taskListView/taskListReducer.d.ts +1 -1
- package/package.json +1 -1
package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/archiveCardPolicyEpic.js
ADDED
|
@@ -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
|
+
}));
|
package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListReducer.js
ADDED
|
@@ -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;
|
package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListSelector.js
ADDED
|
@@ -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
|
+
}
|
package/lib/esm/view/spendManagement/chargeCards/cardPolicy/cardPolicyList/cardPolicyListState.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { from, of } from 'rxjs';
|
|
2
|
+
import { catchError, exhaustMap, 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),
|
|
19
|
+
// `exhaustMap` (rather than `mergeMap`) so a duplicate
|
|
20
|
+
// `fetchCardPolicyList` dispatched while the previous one is still
|
|
21
|
+
// in flight is dropped instead of producing a second HTTP request.
|
|
22
|
+
// This guards against React 18 StrictMode, which mount-cleanup-
|
|
23
|
+
// remounts the screen's mount effect with a stale closure of
|
|
24
|
+
// `listFetchState`, causing the same effect to dispatch this
|
|
25
|
+
// action twice synchronously. Retry-after-error still works
|
|
26
|
+
// because the previous inner observable has completed by the time
|
|
27
|
+
// the user retries.
|
|
28
|
+
exhaustMap(() => {
|
|
29
|
+
return zeniAPI
|
|
30
|
+
.getJSON(`${zeniAPI.apiEndPoints.cardMicroServiceBaseUrl}/1.0/policy-templates`)
|
|
31
|
+
.pipe(mergeMap((response) => {
|
|
32
|
+
if (isSuccessStatus(response) && response.data != null) {
|
|
33
|
+
const templates = toCardPolicyTemplateList(response.data);
|
|
34
|
+
const stats = toCardPolicyStats(response.data.stats);
|
|
35
|
+
const actions = [
|
|
36
|
+
updateCardPolicyTemplates(templates),
|
|
37
|
+
updateCardPolicyStats(stats),
|
|
38
|
+
updateCardPolicyListFetchStatus({
|
|
39
|
+
fetchState: 'Completed',
|
|
40
|
+
templateIds: templates.map((t) => t.templateId),
|
|
41
|
+
}),
|
|
42
|
+
];
|
|
43
|
+
return from(actions);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
return of(updateCardPolicyListFetchStatus({
|
|
47
|
+
fetchState: 'Error',
|
|
48
|
+
error: response.status,
|
|
49
|
+
}));
|
|
50
|
+
}
|
|
51
|
+
}), catchError((error) => of(updateCardPolicyListFetchStatus({
|
|
52
|
+
fetchState: 'Error',
|
|
53
|
+
error: createZeniAPIStatus('Unexpected Error', 'Fetch card-policy list REST API call errored out' +
|
|
54
|
+
JSON.stringify(error)),
|
|
55
|
+
}))));
|
|
56
|
+
}));
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { createSlice } from '@reduxjs/toolkit';
|
|
2
|
+
export const initialState = {
|
|
3
|
+
createCardPolicyTemplateRequestState: {
|
|
4
|
+
fetchState: 'Not-Started',
|
|
5
|
+
error: undefined,
|
|
6
|
+
},
|
|
7
|
+
lastCreatedCardPolicyTemplateIds: [],
|
|
8
|
+
lastCreateCardPolicyTemplateErrors: [],
|
|
9
|
+
};
|
|
10
|
+
const createCardPolicy = createSlice({
|
|
11
|
+
name: 'createCardPolicy',
|
|
12
|
+
initialState,
|
|
13
|
+
reducers: {
|
|
14
|
+
createCardPolicyTemplates: {
|
|
15
|
+
reducer(draft, action) {
|
|
16
|
+
draft.createCardPolicyTemplateRequestState.fetchState = 'In-Progress';
|
|
17
|
+
draft.createCardPolicyTemplateRequestState.error = undefined;
|
|
18
|
+
draft.lastCreatedCardPolicyTemplateIds = [];
|
|
19
|
+
draft.lastCreateCardPolicyTemplateErrors = [];
|
|
20
|
+
// Mirrors `lastIssueSourceChatSessionId` so list/drawer can attribute the in-flight create to its AI CFO session.
|
|
21
|
+
draft.lastCreateCardPolicySourceChatSessionId =
|
|
22
|
+
action.payload.sourceChatSessionId;
|
|
23
|
+
},
|
|
24
|
+
prepare(request) {
|
|
25
|
+
return { payload: request };
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
updateCreateCardPolicyTemplateRequestState(draft, action) {
|
|
29
|
+
draft.createCardPolicyTemplateRequestState.fetchState =
|
|
30
|
+
action.payload.fetchState;
|
|
31
|
+
draft.createCardPolicyTemplateRequestState.error = action.payload.error;
|
|
32
|
+
if (action.payload.templateIds != null) {
|
|
33
|
+
draft.lastCreatedCardPolicyTemplateIds = action.payload.templateIds;
|
|
34
|
+
}
|
|
35
|
+
if (action.payload.perItemErrors != null) {
|
|
36
|
+
draft.lastCreateCardPolicyTemplateErrors = action.payload.perItemErrors;
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
clearCreateCardPolicy(draft) {
|
|
40
|
+
Object.assign(draft, initialState);
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
export const { createCardPolicyTemplates, updateCreateCardPolicyTemplateRequestState, clearCreateCardPolicy, } = createCardPolicy.actions;
|
|
45
|
+
export default createCardPolicy.reducer;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export function getCreateCardPolicyTemplateRequestState(state) {
|
|
2
|
+
return state.createCardPolicyTemplateRequestState;
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* All template ids created by the most recent successful bulk submit
|
|
6
|
+
* (in BE return order). Empty array before any submit or after
|
|
7
|
+
* `clearCreateCardPolicy`. Multi-policy AI CFO submit reads this; the
|
|
8
|
+
* single-policy `getLastCreatedCardPolicyTemplateId` selector below is a
|
|
9
|
+
* convenience for the manual-create routing flow.
|
|
10
|
+
*/
|
|
11
|
+
export function getLastCreatedCardPolicyTemplateIds(state) {
|
|
12
|
+
return state.lastCreatedCardPolicyTemplateIds;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Convenience selector returning the first id of the most recent submit
|
|
16
|
+
* — kept ergonomic for the single-create page's "navigate to detail on
|
|
17
|
+
* success" logic, which only ever creates one template. Returns
|
|
18
|
+
* `undefined` when no submit has succeeded or when the list is empty.
|
|
19
|
+
*/
|
|
20
|
+
export function getLastCreatedCardPolicyTemplateId(state) {
|
|
21
|
+
return state.lastCreatedCardPolicyTemplateIds[0];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Per-item errors returned by the bulk POST when one or more templates
|
|
25
|
+
* failed to persist. Empty on full success; populated on partial success
|
|
26
|
+
* so the UI can render a "N of M created" banner alongside the navigate /
|
|
27
|
+
* close behaviour driven by the lifecycle selector.
|
|
28
|
+
*/
|
|
29
|
+
export function getLastCreateCardPolicyTemplateErrors(state) {
|
|
30
|
+
return state.lastCreateCardPolicyTemplateErrors;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Chat session id that triggered the most recent bulk create — used by the
|
|
34
|
+
* card policy list screen and the AI CFO drawer to scope "creating…" and
|
|
35
|
+
* "created" placeholders to the active conversation.
|
|
36
|
+
*/
|
|
37
|
+
export function getLastCreateCardPolicySourceChatSessionId(state) {
|
|
38
|
+
return state.lastCreateCardPolicySourceChatSessionId;
|
|
39
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { from, of } from 'rxjs';
|
|
2
|
+
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
3
|
+
import { updateCreatedCardPolicyTemplate } from '../../../../../entity/cardPolicy/cardPolicyReducer';
|
|
4
|
+
import { toBulkCreateCardPolicyTemplateError, toCreateCardPolicyTemplatesRequestBody, } from '../../../../../entity/cardPolicy/cardPolicyPayload';
|
|
5
|
+
import { createZeniAPIStatus, isSuccessStatus } from '../../../../../responsePayload';
|
|
6
|
+
import { createCardPolicyTemplates, updateCreateCardPolicyTemplateRequestState, } from './createCardPolicyReducer';
|
|
7
|
+
/**
|
|
8
|
+
* `POST /cards/1.0/policy-templates` (bulk). Builds the bulk wire body
|
|
9
|
+
* from the camelCased action payload, sends one round-trip, and on
|
|
10
|
+
* success fans out:
|
|
11
|
+
* - one `updateCreatedCardPolicyTemplate` on the entity slice per row
|
|
12
|
+
* in `templates_created` (so the entity store is hydrated with every
|
|
13
|
+
* created template), and
|
|
14
|
+
* - one `updateCreateCardPolicyTemplateRequestState` with the ordered
|
|
15
|
+
* id list + per-item errors so the view can render partial-success
|
|
16
|
+
* UX without re-touching the wire types.
|
|
17
|
+
*
|
|
18
|
+
* Partial success (`errors.length > 0` with at least one template
|
|
19
|
+
* created) is still treated as `Completed` — the lifecycle is binary
|
|
20
|
+
* and the per-item errors live on the slice for the UI to inspect.
|
|
21
|
+
* Hard failures (non-success `status` or thrown errors) map to `Error`
|
|
22
|
+
* the same way they did pre-bulk.
|
|
23
|
+
*/
|
|
24
|
+
export const createCardPolicyTemplatesEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(createCardPolicyTemplates.match), mergeMap((action) => {
|
|
25
|
+
const body = toCreateCardPolicyTemplatesRequestBody(action.payload);
|
|
26
|
+
return zeniAPI
|
|
27
|
+
.postAndGetJSON(`${zeniAPI.apiEndPoints.cardMicroServiceBaseUrl}/1.0/policy-templates`, body)
|
|
28
|
+
.pipe(mergeMap((response) => {
|
|
29
|
+
if (isSuccessStatus(response) && response.data != null) {
|
|
30
|
+
const { templates_created, errors } = response.data;
|
|
31
|
+
const createdTemplates = templates_created.map((row) => row.template);
|
|
32
|
+
const actions = [
|
|
33
|
+
...createdTemplates.map((template) => updateCreatedCardPolicyTemplate(template)),
|
|
34
|
+
updateCreateCardPolicyTemplateRequestState({
|
|
35
|
+
fetchState: 'Completed',
|
|
36
|
+
perItemErrors: (errors ?? []).map(toBulkCreateCardPolicyTemplateError),
|
|
37
|
+
templateIds: createdTemplates.map((template) => template.template_id),
|
|
38
|
+
}),
|
|
39
|
+
];
|
|
40
|
+
return from(actions);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
return of(updateCreateCardPolicyTemplateRequestState({
|
|
44
|
+
fetchState: 'Error',
|
|
45
|
+
error: response.status,
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
}), catchError((error) => of(updateCreateCardPolicyTemplateRequestState({
|
|
49
|
+
fetchState: 'Error',
|
|
50
|
+
error: createZeniAPIStatus('Unexpected Error', 'Create card-policy templates REST API call errored out' +
|
|
51
|
+
JSON.stringify(error)),
|
|
52
|
+
}))));
|
|
53
|
+
}));
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { from, of } from 'rxjs';
|
|
2
|
+
import { catchError, exhaustMap, 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),
|
|
6
|
+
// `exhaustMap` (rather than `mergeMap`) so a duplicate
|
|
7
|
+
// `fetchCardPolicyMccCategories` dispatched while the previous one
|
|
8
|
+
// is still in flight is dropped instead of producing a second HTTP
|
|
9
|
+
// request. Both the Create and Edit policy screens dispatch this
|
|
10
|
+
// on mount, and React 18 StrictMode invokes their mount effect
|
|
11
|
+
// twice with a stale `mccCategoriesFetchState` closure — without
|
|
12
|
+
// `exhaustMap` that yields two `/cards/mcc-codes` calls.
|
|
13
|
+
exhaustMap(() => {
|
|
14
|
+
return zeniAPI
|
|
15
|
+
.getJSON(`${zeniAPI.apiEndPoints.cardMicroServiceBaseUrl}/1.0/cards/mcc-codes`)
|
|
16
|
+
.pipe(mergeMap((response) => {
|
|
17
|
+
if (isSuccessStatus(response) && response.data != null) {
|
|
18
|
+
return from([updateCardPolicyMccCategories(response.data)]);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
return of(updateCardPolicyMccCategoriesFailure(response.status));
|
|
22
|
+
}
|
|
23
|
+
}), catchError((error) => of(updateCardPolicyMccCategoriesFailure(createZeniAPIStatus('Unexpected Error', 'Fetch card policy MCC categories REST API call errored out' +
|
|
24
|
+
JSON.stringify(error))))));
|
|
25
|
+
}));
|
|
@@ -87,6 +87,31 @@ export const getChargeCardListView = (state, includeCreditAccountDebitSummaryAnd
|
|
|
87
87
|
hasDebitCard,
|
|
88
88
|
};
|
|
89
89
|
};
|
|
90
|
+
/**
|
|
91
|
+
* Returns every enriched `ChargeCardWithUser` for the tenant, without
|
|
92
|
+
* applying the cards-list screen's `searchText` filter or its column
|
|
93
|
+
* `sortKey/sortOrder`. Used by surfaces that need the raw card universe
|
|
94
|
+
* decoupled from whatever the user has typed/sorted on the cards list
|
|
95
|
+
* (e.g. the Card Policy "Apply to Cards" picker, which owns its own
|
|
96
|
+
* search + sort UI). The list-screen's filter/sort state is intentionally
|
|
97
|
+
* left untouched so revisits to the cards list still restore the user's
|
|
98
|
+
* search.
|
|
99
|
+
*/
|
|
100
|
+
export const getAllChargeCardsWithUser = (state) => {
|
|
101
|
+
const { chargeCardListState, chargeCardState, chargeCardConfigState } = state;
|
|
102
|
+
const cards = getChargeCardsByIds(chargeCardState, chargeCardListState.cardIds);
|
|
103
|
+
const chargeCardsWithUser = getChargeCardsWithUser(cards, state);
|
|
104
|
+
const fetchState = reduceFetchState([
|
|
105
|
+
chargeCardListState,
|
|
106
|
+
chargeCardConfigState,
|
|
107
|
+
]).fetchState;
|
|
108
|
+
return {
|
|
109
|
+
fetchState,
|
|
110
|
+
error: chargeCardListState.error,
|
|
111
|
+
cards: chargeCardsWithUser,
|
|
112
|
+
version: '1.0',
|
|
113
|
+
};
|
|
114
|
+
};
|
|
90
115
|
export const getMyPendingActivationChargeCardListView = (state) => {
|
|
91
116
|
const { tenantState, chargeCardListState, chargeCardState } = state;
|
|
92
117
|
const cards = getChargeCardsByIds(chargeCardState, chargeCardListState.cardIds);
|
package/lib/esm/view/spendManagement/chargeCards/issueChargeCard/aiCardCreationFormDraftTypes.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { deriveAiCardRowsFromTeams } from './deriveAiCardRowsFromTeams';
|
|
2
|
+
// Single source of truth for "what the next form draft should look like
|
|
3
|
+
// after a watchHandler flush". `create` mode + missing context keep the
|
|
4
|
+
// payload as-is; `review` mode re-derives step-2 cardRows from the latest
|
|
5
|
+
// teamRows, preserving in-place edits via prevCardRows.
|
|
6
|
+
export const applyAiCardCreationFormDraftUpdate = ({ next, context, }) => {
|
|
7
|
+
if (context == null || context.mode === 'create') {
|
|
8
|
+
return next;
|
|
9
|
+
}
|
|
10
|
+
return {
|
|
11
|
+
teamRows: next.teamRows,
|
|
12
|
+
cardRows: deriveAiCardRowsFromTeams({
|
|
13
|
+
teamRows: next.teamRows,
|
|
14
|
+
prevCardRows: next.cardRows,
|
|
15
|
+
allUsers: context.allUsers,
|
|
16
|
+
defaultCardOptionId: context.defaultCardOptionId,
|
|
17
|
+
suggestedOwnerUserIdByTeamId: context.suggestedOwnerUserIdByTeamId,
|
|
18
|
+
}),
|
|
19
|
+
};
|
|
20
|
+
};
|
package/lib/esm/view/spendManagement/chargeCards/issueChargeCard/buildAiCardCreationFormDraftSeed.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build the initial `CardsFormDraft` + companion seed context for a
|
|
3
|
+
* fresh AI card-creation session. Used by the `seedAiCardCreationFormDraft`
|
|
4
|
+
* reducer.
|
|
5
|
+
*
|
|
6
|
+
* Branches on `initialData.mode`:
|
|
7
|
+
* - `review`: step-1 team rows start fully checked. Step-2 `cardRows`
|
|
8
|
+
* is left empty — `deriveAiCardRowsFromTeams` materializes it on
|
|
9
|
+
* subsequent `updateAiCardCreationFormDraft` dispatches.
|
|
10
|
+
* - `create`: no step-1 list — seed `cardRows` directly from the AI's
|
|
11
|
+
* suggested cards (resolving owners via `allUsers`) and leave
|
|
12
|
+
* `teamRows` empty.
|
|
13
|
+
*/
|
|
14
|
+
export const buildAiCardCreationFormDraftSeed = ({ initialData, allUsers, }) => {
|
|
15
|
+
const context = {
|
|
16
|
+
allUsers,
|
|
17
|
+
defaultCardOptionId: initialData.cardOptions[0]?.id,
|
|
18
|
+
mode: initialData.mode,
|
|
19
|
+
suggestedOwnerUserIdByTeamId: initialData.suggestedOwnerUserIdByTeamId,
|
|
20
|
+
};
|
|
21
|
+
if (initialData.mode === 'create') {
|
|
22
|
+
return {
|
|
23
|
+
context,
|
|
24
|
+
draft: {
|
|
25
|
+
teamRows: [],
|
|
26
|
+
cardRows: initialData.cardRows.map((seed) => buildCardRowFromSeed(seed, allUsers)),
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const teamRows = initialData.teamRows.map((row) => ({
|
|
31
|
+
cardKind: row.cardKind,
|
|
32
|
+
id: row.id,
|
|
33
|
+
isChecked: true,
|
|
34
|
+
label: row.label,
|
|
35
|
+
value: row.avgMonthlySpend,
|
|
36
|
+
rightLabel: row.recommendedLimit,
|
|
37
|
+
rightSubLabel: row.recommendedLimitCadence,
|
|
38
|
+
}));
|
|
39
|
+
return {
|
|
40
|
+
context,
|
|
41
|
+
draft: {
|
|
42
|
+
teamRows,
|
|
43
|
+
cardRows: [],
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
const buildCardRowFromSeed = (seed, allUsers) => {
|
|
48
|
+
const selectedUser = seed.suggestedOwnerUserId != null
|
|
49
|
+
? allUsers.find((user) => user.userId === seed.suggestedOwnerUserId)
|
|
50
|
+
: undefined;
|
|
51
|
+
return {
|
|
52
|
+
cardKind: seed.cardKind,
|
|
53
|
+
id: seed.id,
|
|
54
|
+
label: seed.label,
|
|
55
|
+
cardOptionId: seed.cardOptionId,
|
|
56
|
+
owner: {
|
|
57
|
+
allUsers,
|
|
58
|
+
selectedUser,
|
|
59
|
+
},
|
|
60
|
+
recommendedLimit: seed.recommendedLimit,
|
|
61
|
+
};
|
|
62
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derive the step-2 `cardRows` from the user's step-1 team selection.
|
|
3
|
+
*
|
|
4
|
+
* Behaviour:
|
|
5
|
+
* - One output row per `teamRow.isChecked === true`, in the same order.
|
|
6
|
+
* - When a team is still checked AND we have a previous row for it, the
|
|
7
|
+
* previous row is preserved verbatim — so user edits made in step 2
|
|
8
|
+
* aren't blown away when an upstream watchHandler re-derives.
|
|
9
|
+
* - Newly-included teams fall back to:
|
|
10
|
+
* - `cardOptionId = defaultCardOptionId`
|
|
11
|
+
* - `selectedUser = the User whose userId === suggestedOwnerUserIdByTeamId[teamId]`
|
|
12
|
+
* - `recommendedLimit = numeric parse of `teamRow.rightLabel` (e.g. "$20,000")`
|
|
13
|
+
*/
|
|
14
|
+
export const deriveAiCardRowsFromTeams = ({ teamRows, prevCardRows = [], allUsers, defaultCardOptionId, suggestedOwnerUserIdByTeamId, }) => {
|
|
15
|
+
const prevById = new Map(prevCardRows.map((row) => [row.id, row]));
|
|
16
|
+
const userById = new Map(allUsers.map((user) => [user.userId, user]));
|
|
17
|
+
return teamRows
|
|
18
|
+
.filter((row) => row.isChecked)
|
|
19
|
+
.map((teamRow) => {
|
|
20
|
+
const previous = prevById.get(teamRow.id);
|
|
21
|
+
if (previous != null) {
|
|
22
|
+
return previous;
|
|
23
|
+
}
|
|
24
|
+
const suggestedUserId = suggestedOwnerUserIdByTeamId[teamRow.id];
|
|
25
|
+
const selectedUser = suggestedUserId != null ? userById.get(suggestedUserId) : undefined;
|
|
26
|
+
return {
|
|
27
|
+
cardKind: teamRow.cardKind,
|
|
28
|
+
id: teamRow.id,
|
|
29
|
+
label: teamRow.label,
|
|
30
|
+
cardOptionId: defaultCardOptionId ?? '',
|
|
31
|
+
owner: {
|
|
32
|
+
allUsers,
|
|
33
|
+
selectedUser,
|
|
34
|
+
},
|
|
35
|
+
recommendedLimit: parseLimitToFloat(teamRow.rightLabel),
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
// Best-effort numeric parse of an AI-provided limit string like "$20,000".
|
|
40
|
+
const parseLimitToFloat = (raw) => {
|
|
41
|
+
const cleaned = raw.replace(/[^0-9.-]/g, '');
|
|
42
|
+
if (cleaned.length === 0) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
const parsed = Number(cleaned);
|
|
46
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
47
|
+
};
|
|
@@ -7,7 +7,7 @@ import { updateAllUsers } from '../../../../entity/user/userReducer';
|
|
|
7
7
|
import { updateUserRoles } from '../../../../entity/userRole/userRoleReducer';
|
|
8
8
|
import { createZeniAPIStatus, isSuccessStatus, } from '../../../../responsePayload';
|
|
9
9
|
import { updateChargeCardList } from '../chargeCardList/chargeCardListReducer';
|
|
10
|
-
import { issueChargeCardSuccessOrFailure, issueChargeCards, updateChargeCardCount, updateDebitCardCount, updateLastSelfIssuedDebitCardId, } from './issueChargeCardReducer';
|
|
10
|
+
import { issueChargeCardSuccessOrFailure, issueChargeCards, updateChargeCardCount, updateDebitCardCount, updateLastIssuedCardIds, updateLastSelfIssuedDebitCardId, } from './issueChargeCardReducer';
|
|
11
11
|
export const issueChargeCardEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(issueChargeCards.match), switchMap(() => {
|
|
12
12
|
const state = state$.value;
|
|
13
13
|
const loggedInUserId = state$.value.tenantState.loggedInUser?.userId;
|
|
@@ -87,7 +87,7 @@ export const issueChargeCardEpic = (actions$, state$, zeniAPI) => actions$.pipe(
|
|
|
87
87
|
actions.push(updateChargeCards(issuedCards), updateAllUsers({ users: response.data.users }), updateUserRoles(response.data.user_roles), updateChargeCardList({
|
|
88
88
|
chargeCardListPayload: response.data,
|
|
89
89
|
keepExistingListItems: true,
|
|
90
|
-
}), updateAddresses(response.data.addresses), updateChargeCardCount(response.data?.cards_count_by_user_id ?? []), updateDebitCardCount(response.data?.debit_cards_count_by_deposit_account_id ?? {}), issueChargeCardSuccessOrFailure({ fetchState: 'Completed' }));
|
|
90
|
+
}), updateAddresses(response.data.addresses), updateChargeCardCount(response.data?.cards_count_by_user_id ?? []), updateDebitCardCount(response.data?.debit_cards_count_by_deposit_account_id ?? {}), updateLastIssuedCardIds(issuedCards.map((card) => card.card_id)), issueChargeCardSuccessOrFailure({ fetchState: 'Completed' }));
|
|
91
91
|
if (issuedCards.length === 1 &&
|
|
92
92
|
(issuedCards[0].card_type.code ===
|
|
93
93
|
'business_virtual_debit_card' ||
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { createSlice } from '@reduxjs/toolkit';
|
|
2
|
+
import { applyAiCardCreationFormDraftUpdate } from './applyAiCardCreationFormDraftUpdate';
|
|
3
|
+
import { buildAiCardCreationFormDraftSeed } from './buildAiCardCreationFormDraftSeed';
|
|
2
4
|
export const initialState = {
|
|
3
5
|
depositAccountIds: [],
|
|
4
6
|
depositAccountsFetchState: { fetchState: 'Not-Started', error: undefined },
|
|
@@ -14,6 +16,7 @@ export const initialState = {
|
|
|
14
16
|
},
|
|
15
17
|
activeChargeCardCount: {},
|
|
16
18
|
activeDebitCardCountByDepositAccountId: {},
|
|
19
|
+
lastIssuedCardIds: [],
|
|
17
20
|
};
|
|
18
21
|
const issueChargeCard = createSlice({
|
|
19
22
|
name: 'issueChargeCard',
|
|
@@ -34,14 +37,19 @@ const issueChargeCard = createSlice({
|
|
|
34
37
|
},
|
|
35
38
|
},
|
|
36
39
|
issueChargeCards: {
|
|
37
|
-
prepare() {
|
|
38
|
-
return { payload: {} };
|
|
40
|
+
prepare(payload) {
|
|
41
|
+
return { payload: payload ?? {} };
|
|
39
42
|
},
|
|
40
|
-
reducer(draft) {
|
|
43
|
+
reducer(draft, action) {
|
|
41
44
|
draft.saveStatus.fetchState = 'In-Progress';
|
|
42
45
|
draft.saveStatus.error = undefined;
|
|
46
|
+
draft.lastIssueSourceChatSessionId = action.payload.sourceChatSessionId;
|
|
47
|
+
draft.lastIssuedCardIds = [];
|
|
43
48
|
},
|
|
44
49
|
},
|
|
50
|
+
updateLastIssuedCardIds(draft, action) {
|
|
51
|
+
draft.lastIssuedCardIds = action.payload;
|
|
52
|
+
},
|
|
45
53
|
updateChargeCardsLocalStore(draft, action) {
|
|
46
54
|
draft.localData = action.payload;
|
|
47
55
|
},
|
|
@@ -49,6 +57,8 @@ const issueChargeCard = createSlice({
|
|
|
49
57
|
draft.localData = [...initialState.localData];
|
|
50
58
|
draft.saveStatus = initialState.saveStatus;
|
|
51
59
|
draft.lastSelfIssuedDebitCardId = undefined;
|
|
60
|
+
draft.lastIssueSourceChatSessionId = undefined;
|
|
61
|
+
draft.lastIssuedCardIds = [];
|
|
52
62
|
},
|
|
53
63
|
updateLastSelfIssuedDebitCardId(draft, action) {
|
|
54
64
|
draft.lastSelfIssuedDebitCardId = action.payload;
|
|
@@ -124,10 +134,44 @@ const issueChargeCard = createSlice({
|
|
|
124
134
|
draft.depositAccountsFetchState.fetchState = action.payload.fetchState;
|
|
125
135
|
draft.depositAccountsFetchState.error = action.payload.error;
|
|
126
136
|
},
|
|
137
|
+
/**
|
|
138
|
+
* Seed the AI card-creation form draft + companion context from the
|
|
139
|
+
* AI's `interactive_form` payload. Dispatched once when the
|
|
140
|
+
* `CardsCreationInteractiveForm` mounts (or the AI payload arrives).
|
|
141
|
+
*/
|
|
142
|
+
seedAiCardCreationFormDraft: {
|
|
143
|
+
reducer(draft, action) {
|
|
144
|
+
const { draft: nextDraft, context } = buildAiCardCreationFormDraftSeed({
|
|
145
|
+
allUsers: action.payload.allUsers,
|
|
146
|
+
initialData: action.payload.initialData,
|
|
147
|
+
});
|
|
148
|
+
draft.aiCardCreationFormDraft = nextDraft;
|
|
149
|
+
draft.aiCardCreationFormDraftContext = context;
|
|
150
|
+
},
|
|
151
|
+
prepare(allUsers, initialData) {
|
|
152
|
+
return { payload: { allUsers, initialData } };
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
/**
|
|
156
|
+
* Replace the form draft from the component's `watchHandler`. Delegates
|
|
157
|
+
* to `applyAiCardCreationFormDraftUpdate` so the same derivation rules
|
|
158
|
+
* (review-mode `cardRows` re-derivation that preserves in-place edits)
|
|
159
|
+
* are shared with the Storybook owner harness.
|
|
160
|
+
*/
|
|
161
|
+
updateAiCardCreationFormDraft(draft, action) {
|
|
162
|
+
draft.aiCardCreationFormDraft = applyAiCardCreationFormDraftUpdate({
|
|
163
|
+
next: action.payload,
|
|
164
|
+
context: draft.aiCardCreationFormDraftContext,
|
|
165
|
+
});
|
|
166
|
+
},
|
|
167
|
+
clearAiCardCreationFormDraft(draft) {
|
|
168
|
+
draft.aiCardCreationFormDraft = undefined;
|
|
169
|
+
draft.aiCardCreationFormDraftContext = undefined;
|
|
170
|
+
},
|
|
127
171
|
clearIssueChargeCard(draft) {
|
|
128
172
|
Object.assign(draft, initialState);
|
|
129
173
|
},
|
|
130
174
|
},
|
|
131
175
|
});
|
|
132
|
-
export const { issueChargeCards, updateChargeCardsLocalStore, updateLastSelfIssuedDebitCardId, issueChargeCardSuccessOrFailure, resetIssueChargeCardForm, updateCustomAddressId, updateChargeCardCount, updateDebitCardCount, fetchIssueCardPage, updateDepositAccountsInCards, fetchDepositAccountListForCards, updateDepositAccountListForCardsFetchStatus, clearIssueChargeCard, } = issueChargeCard.actions;
|
|
176
|
+
export const { issueChargeCards, updateChargeCardsLocalStore, updateLastSelfIssuedDebitCardId, updateLastIssuedCardIds, issueChargeCardSuccessOrFailure, resetIssueChargeCardForm, updateCustomAddressId, updateChargeCardCount, updateDebitCardCount, fetchIssueCardPage, updateDepositAccountsInCards, fetchDepositAccountListForCards, updateDepositAccountListForCardsFetchStatus, seedAiCardCreationFormDraft, updateAiCardCreationFormDraft, clearAiCardCreationFormDraft, clearIssueChargeCard, } = issueChargeCard.actions;
|
|
133
177
|
export default issueChargeCard.reducer;
|