@zeniai/client-epic-state 5.2.48 → 5.2.49-betaAK0
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/esm/view/expenseAutomationView/reducers/reconciliationViewReducer.js +80 -53
- package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewReducer.js +19 -11
- package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.js +4 -1
- package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/saveInvoicingCatalogItemEpic.js +3 -2
- package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/seedInvoicingCatalogItemFormDraftEpic.js +18 -9
- package/lib/esm/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewReducer.js +19 -11
- package/lib/esm/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewSelector.js +3 -1
- package/lib/esm/view/invoicing/editInvoicingCouponDetailView/saveInvoicingCouponEpic.js +1 -1
- package/lib/esm/view/invoicing/editInvoicingCouponDetailView/seedInvoicingCouponFormDraftEpic.js +16 -7
- package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer.js +19 -11
- package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewSelector.js +4 -2
- package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/saveInvoicingCustomerEpic.js +1 -1
- package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewReducer.js +21 -13
- package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector.js +3 -2
- package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/fetchInvoicingSubscriptionFormPageEpic.js +4 -1
- package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/saveInvoicingSubscriptionEpic.js +1 -1
- package/lib/esm/view/invoicing/editInvoicingSubscriptionDetailView/seedInvoicingSubscriptionFormDraftEpic.js +18 -9
- package/lib/esm/view/invoicing/invoicingFormDraft.js +56 -0
- package/lib/view/expenseAutomationView/reducers/reconciliationViewReducer.js +80 -53
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewReducer.d.ts +3 -1
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewReducer.js +19 -11
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.d.ts +10 -0
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.js +4 -1
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewState.d.ts +2 -1
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/saveInvoicingCatalogItemEpic.js +3 -2
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/seedInvoicingCatalogItemFormDraftEpic.d.ts +10 -6
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/seedInvoicingCatalogItemFormDraftEpic.js +17 -8
- package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewReducer.d.ts +3 -1
- package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewReducer.js +19 -11
- package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewSelector.d.ts +13 -0
- package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewSelector.js +3 -1
- package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewState.d.ts +2 -1
- package/lib/view/invoicing/editInvoicingCouponDetailView/saveInvoicingCouponEpic.js +1 -1
- package/lib/view/invoicing/editInvoicingCouponDetailView/seedInvoicingCouponFormDraftEpic.d.ts +10 -6
- package/lib/view/invoicing/editInvoicingCouponDetailView/seedInvoicingCouponFormDraftEpic.js +15 -6
- package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer.d.ts +3 -1
- package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer.js +19 -11
- package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewSelector.d.ts +9 -0
- package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewSelector.js +4 -2
- package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewState.d.ts +2 -1
- package/lib/view/invoicing/editInvoicingCustomerDetailView/saveInvoicingCustomerEpic.js +1 -1
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewReducer.d.ts +3 -1
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewReducer.js +21 -13
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector.d.ts +9 -0
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewSelector.js +3 -2
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/editInvoicingSubscriptionDetailViewState.d.ts +2 -1
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/fetchInvoicingSubscriptionFormPageEpic.js +4 -1
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/saveInvoicingSubscriptionEpic.js +1 -1
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/seedInvoicingSubscriptionFormDraftEpic.d.ts +10 -6
- package/lib/view/invoicing/editInvoicingSubscriptionDetailView/seedInvoicingSubscriptionFormDraftEpic.js +17 -8
- package/lib/view/invoicing/invoicingFormDraft.d.ts +50 -0
- package/lib/view/invoicing/invoicingFormDraft.js +63 -0
- package/package.json +1 -1
|
@@ -102,32 +102,27 @@ const expenseAutomationReconciliationView = createSlice({
|
|
|
102
102
|
draft.selectedTab = 'review';
|
|
103
103
|
draft.selectedAccountId = action.payload.accountId;
|
|
104
104
|
}
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(action.payload.selectedPeriod)]?.reconciliationByAccountID[action.payload.accountId];
|
|
106
|
+
if (accountRecon == null) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (accountRecon.transactionFetchState.fetchState !== 'Completed' ||
|
|
108
110
|
action.payload.cacheOverride === true) {
|
|
109
|
-
const data = accountReconciliationRecords.reconciliationByAccountID[action.payload.accountId];
|
|
110
111
|
if (action.payload.refreshViewInBackground === true) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
fetchState: 'In-Progress',
|
|
115
|
-
error: undefined,
|
|
116
|
-
},
|
|
117
|
-
accountId: action.payload.accountId,
|
|
118
|
-
reconciliationId: undefined,
|
|
112
|
+
accountRecon.refreshStatus = {
|
|
113
|
+
fetchState: 'In-Progress',
|
|
114
|
+
error: undefined,
|
|
119
115
|
};
|
|
116
|
+
accountRecon.accountId = action.payload.accountId;
|
|
117
|
+
accountRecon.reconciliationId = undefined;
|
|
120
118
|
}
|
|
121
119
|
else {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
fetchState: 'In-Progress',
|
|
126
|
-
error: undefined,
|
|
127
|
-
},
|
|
128
|
-
accountId: action.payload.accountId,
|
|
129
|
-
reconciliationId: undefined,
|
|
120
|
+
accountRecon.transactionFetchState = {
|
|
121
|
+
fetchState: 'In-Progress',
|
|
122
|
+
error: undefined,
|
|
130
123
|
};
|
|
124
|
+
accountRecon.accountId = action.payload.accountId;
|
|
125
|
+
accountRecon.reconciliationId = undefined;
|
|
131
126
|
}
|
|
132
127
|
}
|
|
133
128
|
}
|
|
@@ -179,14 +174,17 @@ const expenseAutomationReconciliationView = createSlice({
|
|
|
179
174
|
}
|
|
180
175
|
}
|
|
181
176
|
else {
|
|
182
|
-
const
|
|
177
|
+
const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(action.payload.selectedPeriod)]?.reconciliationByAccountID[action.payload.accountId];
|
|
178
|
+
if (accountRecon == null) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
183
181
|
if (action.payload.refreshViewInBackground === true) {
|
|
184
|
-
|
|
185
|
-
|
|
182
|
+
accountRecon.refreshStatus.error = action.payload.error;
|
|
183
|
+
accountRecon.refreshStatus.fetchState = 'Error';
|
|
186
184
|
}
|
|
187
185
|
else {
|
|
188
|
-
|
|
189
|
-
|
|
186
|
+
accountRecon.transactionFetchState.error = action.payload.error;
|
|
187
|
+
accountRecon.transactionFetchState.fetchState = 'Error';
|
|
190
188
|
}
|
|
191
189
|
}
|
|
192
190
|
},
|
|
@@ -391,8 +389,11 @@ const expenseAutomationReconciliationView = createSlice({
|
|
|
391
389
|
},
|
|
392
390
|
setStatementParseInProgress: (draft, action) => {
|
|
393
391
|
const { accountId, selectedPeriod, statementParseInProgress } = action.payload;
|
|
394
|
-
draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]
|
|
395
|
-
|
|
392
|
+
const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
|
|
393
|
+
if (accountRecon == null) {
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
accountRecon.statementParseInProgress = statementParseInProgress;
|
|
396
397
|
},
|
|
397
398
|
setStatementProcessingDismissedToBackground: (draft, action) => {
|
|
398
399
|
const { accountId, selectedPeriod, dismissedToBackground } = action.payload;
|
|
@@ -476,15 +477,23 @@ const expenseAutomationReconciliationView = createSlice({
|
|
|
476
477
|
},
|
|
477
478
|
uploadAccountStatementSuccess: (draft, action) => {
|
|
478
479
|
const { accountId, selectedPeriod } = action.payload;
|
|
479
|
-
draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]
|
|
480
|
+
const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
|
|
481
|
+
if (accountRecon == null) {
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
accountRecon.statementUploadStatus = {
|
|
480
485
|
fetchState: 'Completed',
|
|
481
486
|
error: undefined,
|
|
482
487
|
};
|
|
483
|
-
|
|
488
|
+
accountRecon.statementParseInProgress = true;
|
|
484
489
|
},
|
|
485
490
|
uploadAccountStatementFailure: (draft, action) => {
|
|
486
491
|
const { accountId, selectedPeriod } = action.payload;
|
|
487
|
-
draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]
|
|
492
|
+
const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
|
|
493
|
+
if (accountRecon == null) {
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
accountRecon.statementUploadStatus = {
|
|
488
497
|
fetchState: 'Error',
|
|
489
498
|
error: action.payload.error,
|
|
490
499
|
};
|
|
@@ -677,23 +686,34 @@ const expenseAutomationReconciliationView = createSlice({
|
|
|
677
686
|
},
|
|
678
687
|
reparseStatementFailure: (draft, action) => {
|
|
679
688
|
const { accountId, selectedPeriod } = action.payload;
|
|
680
|
-
draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]
|
|
689
|
+
const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
|
|
690
|
+
if (accountRecon == null) {
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
accountRecon.reparseStatementStatus = {
|
|
681
694
|
fetchState: 'Error',
|
|
682
695
|
error: action.payload.error,
|
|
683
696
|
};
|
|
684
|
-
|
|
697
|
+
accountRecon.statementProcessingFailed = true;
|
|
685
698
|
},
|
|
686
699
|
resetReparseStatementStatus: (draft, action) => {
|
|
687
700
|
const { accountId, selectedPeriod } = action.payload;
|
|
688
|
-
draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]
|
|
701
|
+
const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
|
|
702
|
+
if (accountRecon == null) {
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
accountRecon.reparseStatementStatus = {
|
|
689
706
|
fetchState: 'Not-Started',
|
|
690
707
|
error: undefined,
|
|
691
708
|
};
|
|
692
709
|
},
|
|
693
710
|
updateParsedStatementData: (draft, action) => {
|
|
694
711
|
const { accountId, selectedPeriod, parsedStatementData } = action.payload;
|
|
695
|
-
draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]
|
|
696
|
-
|
|
712
|
+
const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
|
|
713
|
+
if (accountRecon == null) {
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
accountRecon.parsedStatementData = parsedStatementData;
|
|
697
717
|
},
|
|
698
718
|
updateStatementUpdateLocalData: (draft, action) => {
|
|
699
719
|
const { accountId, selectedPeriod, statementUpdateLocalData, statementUploadId, } = action.payload;
|
|
@@ -819,17 +839,21 @@ const expenseAutomationReconciliationView = createSlice({
|
|
|
819
839
|
},
|
|
820
840
|
updateAccountReconciliationLocalData: (draft, action) => {
|
|
821
841
|
const { accountId, selectedPeriod, localData } = action.payload;
|
|
822
|
-
const
|
|
842
|
+
const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
|
|
843
|
+
if (accountRecon == null) {
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
const oldLocalData = accountRecon.localData;
|
|
823
847
|
if (oldLocalData == null) {
|
|
824
|
-
|
|
848
|
+
accountRecon.localData = localData;
|
|
825
849
|
}
|
|
826
850
|
else {
|
|
827
|
-
|
|
851
|
+
accountRecon.localData = {
|
|
828
852
|
...oldLocalData,
|
|
829
853
|
...localData,
|
|
830
854
|
};
|
|
831
855
|
}
|
|
832
|
-
|
|
856
|
+
accountRecon.localData = {
|
|
833
857
|
...oldLocalData,
|
|
834
858
|
...localData,
|
|
835
859
|
};
|
|
@@ -1119,7 +1143,10 @@ function updateAllReconciliation(draft, accounts, selectedPeriod, reconciliation
|
|
|
1119
1143
|
}
|
|
1120
1144
|
}
|
|
1121
1145
|
function updateReconciliationByAccountID(draft, accounts, selectedPeriod, accountId, reconciliationData, refreshViewInBackground) {
|
|
1122
|
-
const
|
|
1146
|
+
const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
|
|
1147
|
+
if (accountRecon == null) {
|
|
1148
|
+
return;
|
|
1149
|
+
}
|
|
1123
1150
|
const oldConnectionStatus = draft.accountConnectionStatusByAccountID[accountId];
|
|
1124
1151
|
draft.accountConnectionStatusByAccountID[accountId] = {
|
|
1125
1152
|
status: toBankStatusCodeType(reconciliationData.bank_status.code),
|
|
@@ -1129,21 +1156,17 @@ function updateReconciliationByAccountID(draft, accounts, selectedPeriod, accoun
|
|
|
1129
1156
|
: false,
|
|
1130
1157
|
paymentAccountId: accounts.payment_account_id ?? undefined,
|
|
1131
1158
|
};
|
|
1132
|
-
const statementParseInProgress = resolveStatementParseInProgressAfterFetch(
|
|
1159
|
+
const statementParseInProgress = resolveStatementParseInProgressAfterFetch(accountRecon, reconciliationData);
|
|
1160
|
+
accountRecon.reconciliationId =
|
|
1161
|
+
reconciliationData.reconciliation_id ?? undefined;
|
|
1162
|
+
accountRecon.statementParseInProgress = statementParseInProgress;
|
|
1133
1163
|
if (refreshViewInBackground === true) {
|
|
1134
|
-
|
|
1135
|
-
...oldRecord,
|
|
1136
|
-
reconciliationId: reconciliationData.reconciliation_id ?? undefined,
|
|
1137
|
-
refreshStatus: { fetchState: 'Completed', error: undefined },
|
|
1138
|
-
statementParseInProgress,
|
|
1139
|
-
};
|
|
1164
|
+
accountRecon.refreshStatus = { fetchState: 'Completed', error: undefined };
|
|
1140
1165
|
}
|
|
1141
1166
|
else {
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
reconciliationId: reconciliationData.reconciliation_id ?? undefined,
|
|
1146
|
-
transactionFetchState: { fetchState: 'Completed', error: undefined },
|
|
1167
|
+
accountRecon.transactionFetchState = {
|
|
1168
|
+
fetchState: 'Completed',
|
|
1169
|
+
error: undefined,
|
|
1147
1170
|
};
|
|
1148
1171
|
}
|
|
1149
1172
|
}
|
|
@@ -1173,7 +1196,11 @@ const updateExcludedAccountExclusionInfo = (draft, account) => {
|
|
|
1173
1196
|
};
|
|
1174
1197
|
};
|
|
1175
1198
|
const updateReconciliationByAccountIDOnIncludeAccount = (draft, accountId, reconciliation, monthYearPeriodId) => {
|
|
1176
|
-
draft.accountReconciliationRecordsBySelectedPeriod[monthYearPeriodId]
|
|
1199
|
+
const accountReconciliationRecords = draft.accountReconciliationRecordsBySelectedPeriod[monthYearPeriodId];
|
|
1200
|
+
if (accountReconciliationRecords == null) {
|
|
1201
|
+
return;
|
|
1202
|
+
}
|
|
1203
|
+
accountReconciliationRecords.reconciliationByAccountID[accountId] = {
|
|
1177
1204
|
accountId,
|
|
1178
1205
|
reconciliationId: reconciliation.reconciliation_id ?? undefined,
|
|
1179
1206
|
transactionFetchState: { fetchState: 'Not-Started', error: undefined },
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createSlice } from '@reduxjs/toolkit';
|
|
2
2
|
import { clearAll } from '../../../rootActions';
|
|
3
|
+
import { applyInvoicingFormDraftEdit, applyInvoicingFormDraftFailure, applyInvoicingFormDraftSeed, } from '../invoicingFormDraft';
|
|
3
4
|
import { initialInvoicingCatalogItemFormLocalData } from './invoicingCatalogItemFormHelper';
|
|
4
5
|
export const initialState = {
|
|
5
6
|
fetchState: 'Not-Started',
|
|
@@ -21,7 +22,7 @@ const editInvoicingCatalogItemDetailView = createSlice({
|
|
|
21
22
|
updateInvoicingCatalogItemFormDraft(draft, action) {
|
|
22
23
|
const { id, localData } = action.payload;
|
|
23
24
|
if (id != null) {
|
|
24
|
-
draft.editDraftById
|
|
25
|
+
applyInvoicingFormDraftEdit(draft.editDraftById, id, localData);
|
|
25
26
|
}
|
|
26
27
|
else {
|
|
27
28
|
draft.newItemDraft = localData;
|
|
@@ -64,6 +65,7 @@ const editInvoicingCatalogItemDetailView = createSlice({
|
|
|
64
65
|
fetchState: 'Error',
|
|
65
66
|
error: action.payload.error,
|
|
66
67
|
};
|
|
68
|
+
applyInvoicingFormDraftFailure(draft.editDraftById, action.payload.id, initialInvoicingCatalogItemFormLocalData);
|
|
67
69
|
},
|
|
68
70
|
fetchInvoicingCatalogItemDetailPage: {
|
|
69
71
|
reducer() {
|
|
@@ -79,14 +81,10 @@ const editInvoicingCatalogItemDetailView = createSlice({
|
|
|
79
81
|
};
|
|
80
82
|
},
|
|
81
83
|
},
|
|
82
|
-
/**
|
|
83
|
-
* Seed the draft from the loaded record, once. Skipped when a draft already
|
|
84
|
-
* exists so a late-arriving refetch cannot overwrite in-progress edits.
|
|
85
|
-
*/
|
|
84
|
+
/** Fill the draft from the loaded record — see `applyInvoicingFormDraftSeed`. */
|
|
86
85
|
seedInvoicingCatalogItemFormDraft(draft, action) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
86
|
+
const { id, localData } = action.payload;
|
|
87
|
+
applyInvoicingFormDraftSeed(draft.editDraftById, id, localData);
|
|
90
88
|
},
|
|
91
89
|
runInvoicingCatalogPlanAction(draft, action) {
|
|
92
90
|
draft.actionStateById[action.payload.id] = {
|
|
@@ -125,13 +123,23 @@ const editInvoicingCatalogItemDetailView = createSlice({
|
|
|
125
123
|
error: action.payload.error,
|
|
126
124
|
};
|
|
127
125
|
},
|
|
128
|
-
|
|
126
|
+
/**
|
|
127
|
+
* Discard a form's draft — the catalog item's own when `id` is given,
|
|
128
|
+
* the create draft otherwise. Scoped to the one form on purpose: another
|
|
129
|
+
* catalog item's half-finished edit is not this form's to throw away.
|
|
130
|
+
* Clearing every draft at once is what `clearAll` is for.
|
|
131
|
+
*/
|
|
132
|
+
resetEditInvoicingCatalogItemDetailView(draft, action) {
|
|
129
133
|
draft.fetchState = 'Not-Started';
|
|
130
134
|
draft.error = undefined;
|
|
131
135
|
draft.savedItemId = undefined;
|
|
132
136
|
draft.savedKind = undefined;
|
|
133
|
-
|
|
134
|
-
|
|
137
|
+
const id = action.payload?.id;
|
|
138
|
+
if (id == null) {
|
|
139
|
+
draft.newItemDraft = { ...initialInvoicingCatalogItemFormLocalData };
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
delete draft.editDraftById[id];
|
|
135
143
|
},
|
|
136
144
|
},
|
|
137
145
|
extraReducers: (builder) => {
|
|
@@ -2,6 +2,7 @@ import { createSelector } from '@reduxjs/toolkit';
|
|
|
2
2
|
import { reduceAllFetchState } from '../../../commonStateTypes/reduceFetchState';
|
|
3
3
|
import { getInvoicingPlanById, getInvoicingPlansByIds, } from '../../../entity/invoicing/plan/planSelector';
|
|
4
4
|
import { getInvoicingConfigView, invoicingFieldHelpForGroup, } from '../invoicingConfigView/invoicingConfigViewSelector';
|
|
5
|
+
import { getInvoicingFormDraftLocalData, isInvoicingFormDraftPending, } from '../invoicingFormDraft';
|
|
5
6
|
import { getInvoicingQboView, isInvoicingAccountingPickerDataLoading, isInvoicingQboConnected, } from '../invoicingQboView/invoicingQboViewSelector';
|
|
6
7
|
import { INVOICING_CATALOG_APPLICABILITY_VALUES, INVOICING_CATALOG_PRICING_MODEL_VALUES, INVOICING_CATALOG_PRORATION_VALUES, INVOICING_CATALOG_TIER_TYPE_VALUES, initialInvoicingCatalogItemFormLocalData, } from './invoicingCatalogItemFormHelper';
|
|
7
8
|
export const getEditInvoicingCatalogItemDetailViewState = (state) => ({
|
|
@@ -52,7 +53,7 @@ export const getInvoicingCatalogItemFormView = (state, id) => {
|
|
|
52
53
|
// lands. Until then the page is showing its skeleton, so the blank shape here
|
|
53
54
|
// is never rendered.
|
|
54
55
|
const localData = id != null
|
|
55
|
-
? (editDraftById
|
|
56
|
+
? getInvoicingFormDraftLocalData(editDraftById, id, initialInvoicingCatalogItemFormLocalData)
|
|
56
57
|
: newItemDraft;
|
|
57
58
|
const allApplicableItemOptions = getInvoicingApplicableCatalogItemOptions(state);
|
|
58
59
|
const applicableItemOptions = id != null
|
|
@@ -90,6 +91,8 @@ export const getInvoicingCatalogItemFormView = (state, id) => {
|
|
|
90
91
|
catalogProductLifecycleActionOptions,
|
|
91
92
|
recordState,
|
|
92
93
|
fieldHelp: invoicingFieldHelpForGroup(state, 'catalog'),
|
|
94
|
+
isFormLoading: isInvoicingAccountingPickerDataLoading(state) ||
|
|
95
|
+
isInvoicingFormDraftPending(editDraftById, id),
|
|
93
96
|
isQboPickerDataLoading: isInvoicingAccountingPickerDataLoading(state),
|
|
94
97
|
qboAccountHierarchy: qboView?.nestedAccountHierarchy ?? [],
|
|
95
98
|
qboClassHierarchy: qboView?.nestedClassHierarchy ?? [],
|
package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/saveInvoicingCatalogItemEpic.js
CHANGED
|
@@ -17,8 +17,9 @@ export const saveInvoicingCatalogItemEpic = (actions$, state$, zeniAPI) => actio
|
|
|
17
17
|
// class become the records the service stores. Price points ride along
|
|
18
18
|
// nested, so the detail page and the create/edit form share one request.
|
|
19
19
|
const viewState = state.editInvoicingCatalogItemDetailViewState;
|
|
20
|
-
const localData = (id != null
|
|
21
|
-
viewState.
|
|
20
|
+
const localData = (id != null
|
|
21
|
+
? viewState.editDraftById[id]?.localData
|
|
22
|
+
: viewState.newItemDraft) ?? viewState.newItemDraft;
|
|
22
23
|
const data = localDataToSaveInvoicingCatalogItemPayload(localData, id == null, accountingLookup);
|
|
23
24
|
const baseUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0`;
|
|
24
25
|
const path = id != null
|
|
@@ -1,18 +1,27 @@
|
|
|
1
1
|
import { EMPTY, of } from 'rxjs';
|
|
2
2
|
import { filter, mergeMap, withLatestFrom } from 'rxjs/operators';
|
|
3
3
|
import { getInvoicingPlanById } from '../../../entity/invoicing/plan/planSelector';
|
|
4
|
-
import { seedInvoicingCatalogItemFormDraft, updateInvoicingCatalogItemDetail, } from './editInvoicingCatalogItemDetailViewReducer';
|
|
4
|
+
import { fetchInvoicingCatalogItemDetailPage, seedInvoicingCatalogItemFormDraft, updateInvoicingCatalogItemDetail, } from './editInvoicingCatalogItemDetailViewReducer';
|
|
5
5
|
import { entityToInvoicingCatalogItemFormLocalData } from './invoicingCatalogItemFormHelper';
|
|
6
6
|
/**
|
|
7
|
-
* Seeds the edit draft from the record the
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* Seeds the edit draft from the record, so the form has its values before it
|
|
8
|
+
* mounts. The reducer ignores a seed once the draft holds the record, which is
|
|
9
|
+
* what stops a background refetch from overwriting edits in progress.
|
|
10
|
+
*
|
|
11
|
+
* Opening the page counts as a trigger, not just the detail response: the page
|
|
12
|
+
* fetch is cache-guarded, so re-opening a form for a record already loaded this
|
|
13
|
+
* session issues no request at all — and a draft cleared in between (by a save
|
|
14
|
+
* or a cancel) would have nothing left to seed it.
|
|
11
15
|
*/
|
|
12
|
-
export const seedInvoicingCatalogItemFormDraftEpic = (actions$, state$) => actions$.pipe(filter(updateInvoicingCatalogItemDetail.match
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
+
export const seedInvoicingCatalogItemFormDraftEpic = (actions$, state$) => actions$.pipe(filter((action) => updateInvoicingCatalogItemDetail.match(action) ||
|
|
17
|
+
fetchInvoicingCatalogItemDetailPage.match(action)), withLatestFrom(state$), mergeMap(([action, state]) => {
|
|
18
|
+
const id = action.payload.id;
|
|
19
|
+
// Nothing to seed from on a cold open; the detail response triggers this
|
|
20
|
+
// again once it lands.
|
|
21
|
+
const plan = id != null
|
|
22
|
+
? getInvoicingPlanById(state.invoicingPlanState, id)
|
|
23
|
+
: undefined;
|
|
24
|
+
if (id == null || plan == null) {
|
|
16
25
|
return EMPTY;
|
|
17
26
|
}
|
|
18
27
|
return of(seedInvoicingCatalogItemFormDraft({
|
package/lib/esm/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewReducer.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createSlice } from '@reduxjs/toolkit';
|
|
2
2
|
import { clearAll } from '../../../rootActions';
|
|
3
|
+
import { applyInvoicingFormDraftEdit, applyInvoicingFormDraftFailure, applyInvoicingFormDraftSeed, } from '../invoicingFormDraft';
|
|
3
4
|
import { initialInvoicingCouponFormLocalData, } from './editInvoicingCouponDetailViewState';
|
|
4
5
|
export const initialState = {
|
|
5
6
|
fetchState: 'Not-Started',
|
|
@@ -20,7 +21,7 @@ const editInvoicingCouponDetailView = createSlice({
|
|
|
20
21
|
updateInvoicingCouponFormDraft(draft, action) {
|
|
21
22
|
const { id, localData } = action.payload;
|
|
22
23
|
if (id != null) {
|
|
23
|
-
draft.editDraftById
|
|
24
|
+
applyInvoicingFormDraftEdit(draft.editDraftById, id, localData);
|
|
24
25
|
}
|
|
25
26
|
else {
|
|
26
27
|
draft.newCouponDraft = localData;
|
|
@@ -85,15 +86,12 @@ const editInvoicingCouponDetailView = createSlice({
|
|
|
85
86
|
fetchState: 'Error',
|
|
86
87
|
error: action.payload.status,
|
|
87
88
|
};
|
|
89
|
+
applyInvoicingFormDraftFailure(draft.editDraftById, action.payload.id, initialInvoicingCouponFormLocalData);
|
|
88
90
|
},
|
|
89
|
-
/**
|
|
90
|
-
* Seed the draft from the loaded record, once. Skipped when a draft already
|
|
91
|
-
* exists so a late refetch cannot overwrite in-progress edits.
|
|
92
|
-
*/
|
|
91
|
+
/** Fill the draft from the loaded record — see `applyInvoicingFormDraftSeed`. */
|
|
93
92
|
seedInvoicingCouponFormDraft(draft, action) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
93
|
+
const { id, localData } = action.payload;
|
|
94
|
+
applyInvoicingFormDraftSeed(draft.editDraftById, id, localData);
|
|
97
95
|
},
|
|
98
96
|
runInvoicingDiscountAction(draft, action) {
|
|
99
97
|
draft.actionStateById[action.payload.id] = {
|
|
@@ -113,12 +111,22 @@ const editInvoicingCouponDetailView = createSlice({
|
|
|
113
111
|
error: action.payload.error,
|
|
114
112
|
};
|
|
115
113
|
},
|
|
116
|
-
|
|
114
|
+
/**
|
|
115
|
+
* Discard a form's draft — the coupon's own when `id` is given,
|
|
116
|
+
* the create draft otherwise. Scoped to the one form on purpose: another
|
|
117
|
+
* coupon's half-finished edit is not this form's to throw away.
|
|
118
|
+
* Clearing every draft at once is what `clearAll` is for.
|
|
119
|
+
*/
|
|
120
|
+
resetEditInvoicingCouponDetailView(draft, action) {
|
|
117
121
|
draft.fetchState = 'Not-Started';
|
|
118
122
|
draft.error = undefined;
|
|
119
123
|
draft.savedCouponId = undefined;
|
|
120
|
-
|
|
121
|
-
|
|
124
|
+
const id = action.payload?.id;
|
|
125
|
+
if (id == null) {
|
|
126
|
+
draft.newCouponDraft = { ...initialInvoicingCouponFormLocalData };
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
delete draft.editDraftById[id];
|
|
122
130
|
},
|
|
123
131
|
},
|
|
124
132
|
extraReducers: (builder) => {
|
|
@@ -2,6 +2,7 @@ import { reduceAllFetchState } from '../../../commonStateTypes/reduceFetchState'
|
|
|
2
2
|
import { getInvoicingCouponById } from '../../../entity/invoicing/coupon/couponSelector';
|
|
3
3
|
import { toInvoicingFormOption, toInvoicingQboAccountMappingSlot, } from '../../../entity/invoicing/invoicingCommonPayload';
|
|
4
4
|
import { getInvoicingConfigView, invoicingFieldHelpForGroup, } from '../invoicingConfigView/invoicingConfigViewSelector';
|
|
5
|
+
import { getInvoicingFormDraftLocalData, isInvoicingFormDraftPending, } from '../invoicingFormDraft';
|
|
5
6
|
import { getInvoicingQboView, invoicingAccountsForQboAccountTypes, invoicingQboAccountByQboId, isInvoicingAccountingPickerDataLoading, isInvoicingQboConnected, } from '../invoicingQboView/invoicingQboViewSelector';
|
|
6
7
|
import { getInvoicingSettings, getInvoicingSettingsFetchState, } from '../settingsView/settingsViewSelector';
|
|
7
8
|
import { initialInvoicingCouponFormLocalData, invoicingCouponDiscountsAccountIdForCreate, } from './editInvoicingCouponDetailViewState';
|
|
@@ -41,6 +42,7 @@ export const getEditInvoicingCouponDetailViewState = (state, couponId) => {
|
|
|
41
42
|
{ error: undefined, fetchState: configFetchState },
|
|
42
43
|
]),
|
|
43
44
|
recordState,
|
|
45
|
+
isFormLoading: isInvoicingFormDraftPending(state.editInvoicingCouponDetailViewState.editDraftById, couponId),
|
|
44
46
|
coupon,
|
|
45
47
|
discountsAccountName: invoicingQboAccountByQboId(state, coupon?.discountsAccountId)?.accountName,
|
|
46
48
|
savedCouponId,
|
|
@@ -70,7 +72,7 @@ export const getInvoicingCouponFormView = (state, couponId) => {
|
|
|
70
72
|
// `seedInvoicingCouponFormDraftEpic` when the detail load lands. Until then
|
|
71
73
|
// the page is showing its skeleton.
|
|
72
74
|
const localData = couponId != null
|
|
73
|
-
? (editDraftById
|
|
75
|
+
? getInvoicingFormDraftLocalData(editDraftById, couponId, initialInvoicingCouponFormLocalData)
|
|
74
76
|
: newCouponDraft;
|
|
75
77
|
const { billingPeriodUnitOptions, discountApplyOnOptions, discountDurationTypeOptions, discountTypeOptions, qboAccountMappingKindOptions, } = getInvoicingConfigView(state);
|
|
76
78
|
const isQboConnected = isInvoicingQboConnected(state);
|
|
@@ -20,7 +20,7 @@ export const saveInvoicingCouponEpic = (actions$, state$, zeniAPI) => actions$.p
|
|
|
20
20
|
const state = state$.value;
|
|
21
21
|
const viewState = state.editInvoicingCouponDetailViewState;
|
|
22
22
|
const draft = (id != null
|
|
23
|
-
? viewState.editDraftById[id]
|
|
23
|
+
? viewState.editDraftById[id]?.localData
|
|
24
24
|
: viewState.newCouponDraft) ?? viewState.newCouponDraft;
|
|
25
25
|
// The create default is resolved here as well as in the form view,
|
|
26
26
|
// so a create that never touched the picker still persists the
|
package/lib/esm/view/invoicing/editInvoicingCouponDetailView/seedInvoicingCouponFormDraftEpic.js
CHANGED
|
@@ -1,17 +1,26 @@
|
|
|
1
1
|
import { EMPTY, of } from 'rxjs';
|
|
2
2
|
import { filter, mergeMap, withLatestFrom } from 'rxjs/operators';
|
|
3
3
|
import { getInvoicingCouponById } from '../../../entity/invoicing/coupon/couponSelector';
|
|
4
|
-
import { seedInvoicingCouponFormDraft, updateInvoicingCouponDetail, } from './editInvoicingCouponDetailViewReducer';
|
|
4
|
+
import { fetchInvoicingCouponDetailPage, seedInvoicingCouponFormDraft, updateInvoicingCouponDetail, } from './editInvoicingCouponDetailViewReducer';
|
|
5
5
|
import { entityToInvoicingCouponFormLocalData } from './editInvoicingCouponDetailViewState';
|
|
6
6
|
/**
|
|
7
|
-
* Seeds the edit draft from the record the
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* Seeds the edit draft from the record, so the form has its values before it
|
|
8
|
+
* mounts. The reducer ignores a seed once the draft holds the record, which is
|
|
9
|
+
* what stops a background refetch from overwriting edits in progress.
|
|
10
|
+
*
|
|
11
|
+
* Opening the page counts as a trigger, not just the detail response: the page
|
|
12
|
+
* fetch is cache-guarded, so re-opening a form for a record already loaded this
|
|
13
|
+
* session issues no request at all — and a draft cleared in between (by a save
|
|
14
|
+
* or a cancel) would have nothing left to seed it.
|
|
11
15
|
*/
|
|
12
|
-
export const seedInvoicingCouponFormDraftEpic = (actions$, state$) => actions$.pipe(filter(updateInvoicingCouponDetail.match
|
|
16
|
+
export const seedInvoicingCouponFormDraftEpic = (actions$, state$) => actions$.pipe(filter((action) => updateInvoicingCouponDetail.match(action) ||
|
|
17
|
+
fetchInvoicingCouponDetailPage.match(action)), withLatestFrom(state$), mergeMap(([action, state]) => {
|
|
13
18
|
const { id } = action.payload;
|
|
14
|
-
|
|
19
|
+
// Nothing to seed from on a cold open; the detail response triggers this
|
|
20
|
+
// again once it lands.
|
|
21
|
+
const coupon = id != null
|
|
22
|
+
? getInvoicingCouponById(state.invoicingCouponState, id)
|
|
23
|
+
: undefined;
|
|
15
24
|
if (coupon == null) {
|
|
16
25
|
return EMPTY;
|
|
17
26
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createSlice } from '@reduxjs/toolkit';
|
|
2
2
|
import { clearAll } from '../../../rootActions';
|
|
3
|
+
import { applyInvoicingFormDraftEdit, applyInvoicingFormDraftFailure, applyInvoicingFormDraftSeed, } from '../invoicingFormDraft';
|
|
3
4
|
import { initialInvoicingCustomerFormLocalData } from './invoicingCustomerFormConfig';
|
|
4
5
|
export const initialState = {
|
|
5
6
|
emailPreviewFetchState: { fetchState: 'Not-Started', error: undefined },
|
|
@@ -123,20 +124,17 @@ const editInvoicingCustomerDetailView = createSlice({
|
|
|
123
124
|
fetchState: 'Error',
|
|
124
125
|
error: action.payload.status,
|
|
125
126
|
};
|
|
127
|
+
applyInvoicingFormDraftFailure(draft.editDraftById, action.payload.id, initialInvoicingCustomerFormLocalData);
|
|
126
128
|
},
|
|
127
|
-
/**
|
|
128
|
-
* Seed the draft from the loaded record, once. Skipped when a draft already
|
|
129
|
-
* exists so a late refetch cannot overwrite in-progress edits.
|
|
130
|
-
*/
|
|
129
|
+
/** Fill the draft from the loaded record — see `applyInvoicingFormDraftSeed`. */
|
|
131
130
|
seedInvoicingCustomerFormDraft(draft, action) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
131
|
+
const { id, localData } = action.payload;
|
|
132
|
+
applyInvoicingFormDraftSeed(draft.editDraftById, id, localData);
|
|
135
133
|
},
|
|
136
134
|
updateInvoicingCustomerFormDraft(draft, action) {
|
|
137
135
|
const { id, localData } = action.payload;
|
|
138
136
|
if (id != null) {
|
|
139
|
-
draft.editDraftById
|
|
137
|
+
applyInvoicingFormDraftEdit(draft.editDraftById, id, localData);
|
|
140
138
|
}
|
|
141
139
|
else {
|
|
142
140
|
draft.newCustomerDraft = localData;
|
|
@@ -161,12 +159,22 @@ const editInvoicingCustomerDetailView = createSlice({
|
|
|
161
159
|
draft.fetchState = 'Error';
|
|
162
160
|
draft.error = action.payload;
|
|
163
161
|
},
|
|
164
|
-
|
|
162
|
+
/**
|
|
163
|
+
* Discard a form's draft — the customer's own when `id` is given,
|
|
164
|
+
* the create draft otherwise. Scoped to the one form on purpose: another
|
|
165
|
+
* customer's half-finished edit is not this form's to throw away.
|
|
166
|
+
* Clearing every draft at once is what `clearAll` is for.
|
|
167
|
+
*/
|
|
168
|
+
resetEditInvoicingCustomerDetailView(draft, action) {
|
|
165
169
|
draft.fetchState = 'Not-Started';
|
|
166
170
|
draft.error = undefined;
|
|
167
171
|
draft.savedCustomerId = undefined;
|
|
168
|
-
|
|
169
|
-
|
|
172
|
+
const id = action.payload?.id;
|
|
173
|
+
if (id == null) {
|
|
174
|
+
draft.newCustomerDraft = { ...initialInvoicingCustomerFormLocalData };
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
delete draft.editDraftById[id];
|
|
170
178
|
},
|
|
171
179
|
// Trigger only — handled by initializeInvoicingCustomerAddressEpic.
|
|
172
180
|
initializeInvoicingCustomerAddress: {
|
|
@@ -5,6 +5,7 @@ import { invoicingCustomerPaymentMethods } from '../../../entity/invoicing/invoi
|
|
|
5
5
|
import { getFormattedAddress } from '../../addressView/addressViewSelector';
|
|
6
6
|
import { getInvoicingPaymentLinkSendState, getInvoicingPaymentMethodSaveState, getInvoicingPlaidLinkToken, getInvoicingPlaidLinkTokenFetchState, getInvoicingSentPaymentLinkEmail, getInvoicingSentPaymentLinkMagicUrl, getInvoicingSetupIntent, getInvoicingSetupIntentFetchState, } from '../customerPaymentMethod/customerPaymentMethodSelector';
|
|
7
7
|
import { getInvoicingConfigView, invoicingFieldHelpForGroup, } from '../invoicingConfigView/invoicingConfigViewSelector';
|
|
8
|
+
import { getInvoicingFormDraftLocalData, isInvoicingFormDraftPending, } from '../invoicingFormDraft';
|
|
8
9
|
import { isStripeConnectedFromSettings } from '../settingsView/invoicingSettingsHelpers';
|
|
9
10
|
import { getInvoicingSettings } from '../settingsView/settingsViewSelector';
|
|
10
11
|
import { INVOICING_CUSTOMER_BILLING_ADDRESS_TYPE, initialInvoicingCustomerFormLocalData, } from './invoicingCustomerFormConfig';
|
|
@@ -59,8 +60,7 @@ export const getInvoicingCustomerFormView = (state, invoicingCustomerID) => {
|
|
|
59
60
|
// `seedInvoicingCustomerFormDraftEpic` when the detail load lands. Until then
|
|
60
61
|
// the page is showing its skeleton.
|
|
61
62
|
const localData = invoicingCustomerID != null
|
|
62
|
-
? (editDraftById
|
|
63
|
-
initialInvoicingCustomerFormLocalData)
|
|
63
|
+
? getInvoicingFormDraftLocalData(editDraftById, invoicingCustomerID, initialInvoicingCustomerFormLocalData)
|
|
64
64
|
: newCustomerDraft;
|
|
65
65
|
// Billing address is captured via the shared Address screen and seeded there
|
|
66
66
|
// (from the address entity) on detail load, so the formatted label comes from
|
|
@@ -78,6 +78,7 @@ export const getInvoicingCustomerFormView = (state, invoicingCustomerID) => {
|
|
|
78
78
|
? { error: undefined, fetchState: 'Completed' }
|
|
79
79
|
: (state.editInvoicingCustomerDetailViewState.recordStateById[invoicingCustomerID] ?? { error: undefined, fetchState: 'Not-Started' });
|
|
80
80
|
const { emailPreview, emailPreviewCustomerId, emailPreviewFetchState } = state.editInvoicingCustomerDetailViewState;
|
|
81
|
+
const isFormLoading = isInvoicingFormDraftPending(editDraftById, invoicingCustomerID);
|
|
81
82
|
return {
|
|
82
83
|
// A preview cached for another customer is not this screen's.
|
|
83
84
|
emailPreview: emailPreviewCustomerId === invoicingCustomerID ? emailPreview : undefined,
|
|
@@ -92,6 +93,7 @@ export const getInvoicingCustomerFormView = (state, invoicingCustomerID) => {
|
|
|
92
93
|
promotionalCreditSubmitState: state.editInvoicingCustomerDetailViewState.promotionalCreditSubmitState,
|
|
93
94
|
record: getInvoicingCustomerRecord(state, invoicingCustomerID),
|
|
94
95
|
fieldHelp: invoicingFieldHelpForGroup(state, 'customer'),
|
|
96
|
+
isFormLoading,
|
|
95
97
|
customerTypeOptions,
|
|
96
98
|
localData,
|
|
97
99
|
mode,
|
|
@@ -16,7 +16,7 @@ export const saveInvoicingCustomerEpic = (actions$, state$, zeniAPI) => actions$
|
|
|
16
16
|
const rootState = state$.value;
|
|
17
17
|
const viewState = rootState.editInvoicingCustomerDetailViewState;
|
|
18
18
|
const localData = (id != null
|
|
19
|
-
? viewState.editDraftById[id]
|
|
19
|
+
? viewState.editDraftById[id]?.localData
|
|
20
20
|
: viewState.newCustomerDraft) ?? viewState.newCustomerDraft;
|
|
21
21
|
// Billing address captured via the shared Address screen is sent as an
|
|
22
22
|
// object in the payload; the backend creates it and returns its id
|