@zeniai/client-epic-state 5.2.10-betaAK0 → 5.2.10-betaAK1

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 (34) hide show
  1. package/lib/epic.d.ts +1 -1
  2. package/lib/epic.js +8 -5
  3. package/lib/esm/epic.js +4 -1
  4. package/lib/esm/index.js +3 -3
  5. package/lib/esm/view/invoicing/invoicingQboView/invoicingQboViewSelector.js +18 -4
  6. package/lib/esm/view/invoicing/settingsView/epics/connectInvoicingStripeEpic.js +27 -0
  7. package/lib/esm/view/invoicing/settingsView/epics/disconnectInvoicingStripeEpic.js +24 -0
  8. package/lib/esm/view/invoicing/settingsView/epics/fetchInvoicingSettingsEpic.js +19 -0
  9. package/lib/esm/view/invoicing/settingsView/epics/saveInvoicingSettingsEpic.js +54 -0
  10. package/lib/esm/view/invoicing/settingsView/epics/settingsViewActionType.js +1 -0
  11. package/lib/esm/view/invoicing/settingsView/settingsViewReducer.js +10 -1
  12. package/lib/esm/view/invoicing/settingsView/settingsViewSelector.js +38 -0
  13. package/lib/index.d.ts +4 -4
  14. package/lib/index.js +8 -5
  15. package/lib/view/invoicing/invoicingQboView/invoicingQboViewSelector.js +18 -4
  16. package/lib/view/invoicing/settingsView/epics/connectInvoicingStripeEpic.d.ts +6 -0
  17. package/lib/view/invoicing/settingsView/epics/connectInvoicingStripeEpic.js +31 -0
  18. package/lib/view/invoicing/settingsView/epics/disconnectInvoicingStripeEpic.d.ts +11 -0
  19. package/lib/view/invoicing/settingsView/epics/disconnectInvoicingStripeEpic.js +28 -0
  20. package/lib/view/invoicing/settingsView/epics/fetchInvoicingSettingsEpic.d.ts +6 -0
  21. package/lib/view/invoicing/settingsView/epics/fetchInvoicingSettingsEpic.js +23 -0
  22. package/lib/view/invoicing/settingsView/epics/saveInvoicingSettingsEpic.d.ts +6 -0
  23. package/lib/view/invoicing/settingsView/epics/saveInvoicingSettingsEpic.js +58 -0
  24. package/lib/view/invoicing/settingsView/epics/settingsViewActionType.d.ts +5 -0
  25. package/lib/view/invoicing/settingsView/epics/settingsViewActionType.js +2 -0
  26. package/lib/view/invoicing/settingsView/settingsViewReducer.d.ts +4 -2
  27. package/lib/view/invoicing/settingsView/settingsViewReducer.js +11 -2
  28. package/lib/view/invoicing/settingsView/settingsViewSelector.d.ts +35 -1
  29. package/lib/view/invoicing/settingsView/settingsViewSelector.js +40 -1
  30. package/lib/view/invoicing/settingsView/settingsViewState.d.ts +8 -1
  31. package/package.json +1 -1
  32. package/lib/esm/view/invoicing/settingsView/settingsViewEpics.js +0 -107
  33. package/lib/view/invoicing/settingsView/settingsViewEpics.d.ts +0 -12
  34. package/lib/view/invoicing/settingsView/settingsViewEpics.js +0 -114
package/lib/epic.d.ts CHANGED
@@ -265,7 +265,7 @@ import { ActionType as InvoicingTransactionListViewActionType } from './view/inv
265
265
  import { ActionType as InvoicingPaymentActionActionType } from './view/invoicing/paymentAction/paymentActionEpic';
266
266
  import { ActionType as InvoicingPromotionalCreditActionActionType } from './view/invoicing/promotionalCreditAction/promotionalCreditActionEpic';
267
267
  import { ActionType as RecordPaymentActionType } from './view/invoicing/recordPayment/recordPaymentEpic';
268
- import { ActionType as InvoicingSettingsViewActionType } from './view/invoicing/settingsView/settingsViewEpics';
268
+ import { InvoicingSettingsViewActionType } from './view/invoicing/settingsView/epics/settingsViewActionType';
269
269
  import { ActionType as InvoicingSubscriptionActionActionType } from './view/invoicing/subscriptionAction/subscriptionActionEpic';
270
270
  import { ActionType as FetchMonthClosePerformanceTrendActionType } from './view/monthEndCloseChecksView/epics/fetchMonthClosePerformanceTrendEpic';
271
271
  import { ActionType as FetchMonthEndCloseChecksActionType } from './view/monthEndCloseChecksView/epics/fetchMonthEndCloseChecksEpic';
package/lib/epic.js CHANGED
@@ -313,8 +313,11 @@ const issueCreditNoteEpic_1 = require("./view/invoicing/issueCreditNote/issueCre
313
313
  const paymentActionEpic_1 = require("./view/invoicing/paymentAction/paymentActionEpic");
314
314
  const promotionalCreditActionEpic_1 = require("./view/invoicing/promotionalCreditAction/promotionalCreditActionEpic");
315
315
  const recordPaymentEpic_1 = require("./view/invoicing/recordPayment/recordPaymentEpic");
316
+ const connectInvoicingStripeEpic_1 = require("./view/invoicing/settingsView/epics/connectInvoicingStripeEpic");
317
+ const disconnectInvoicingStripeEpic_1 = require("./view/invoicing/settingsView/epics/disconnectInvoicingStripeEpic");
318
+ const fetchInvoicingSettingsEpic_1 = require("./view/invoicing/settingsView/epics/fetchInvoicingSettingsEpic");
319
+ const saveInvoicingSettingsEpic_1 = require("./view/invoicing/settingsView/epics/saveInvoicingSettingsEpic");
316
320
  const invoicingBrandingFormEpics_1 = require("./view/invoicing/settingsView/invoicingBrandingFormEpics");
317
- const settingsViewEpics_1 = require("./view/invoicing/settingsView/settingsViewEpics");
318
321
  const subscriptionActionEpic_1 = require("./view/invoicing/subscriptionAction/subscriptionActionEpic");
319
322
  const fetchMonthClosePerformanceTrendEpic_1 = require("./view/monthEndCloseChecksView/epics/fetchMonthClosePerformanceTrendEpic");
320
323
  const fetchMonthEndCloseChecksEpic_1 = require("./view/monthEndCloseChecksView/epics/fetchMonthEndCloseChecksEpic");
@@ -762,7 +765,7 @@ const ALL_EPICS = [
762
765
  confirmBulkUploadMatchEpic_1.confirmBulkUploadMatchEpic,
763
766
  confirmCardSetupIntentEpic_1.confirmCardSetupIntentEpic,
764
767
  confirmStatementMappingEpic_1.confirmStatementMappingEpic,
765
- settingsViewEpics_1.connectInvoicingStripeEpic,
768
+ connectInvoicingStripeEpic_1.connectInvoicingStripeEpic,
766
769
  convertAmountToHomeCurrencyEpic_1.convertAmountToHomeCurrencyEpic,
767
770
  createAddressEpic_1.createAddressEpic,
768
771
  createAutoTransferRuleEpic_1.createAutoTransferRuleEpic,
@@ -814,7 +817,7 @@ const ALL_EPICS = [
814
817
  deleteTransactionAttachmentEpic_1.deleteTransactionAttachmentEpic,
815
818
  deleteUserBankAccountEpic_1.deleteUserBankAccountEpic,
816
819
  disableAccountingProjectsEpic_1.disableAccountingProjectsEpic,
817
- settingsViewEpics_1.disconnectInvoicingStripeEpic,
820
+ disconnectInvoicingStripeEpic_1.disconnectInvoicingStripeEpic,
818
821
  dismissCapitalizationOnboardingEpic_1.dismissCapitalizationOnboardingEpic,
819
822
  doMagicLinkSignInEpic_1.doMagicLinkSignInEpic,
820
823
  signInUserEpic_1.doSignInEpic,
@@ -1023,7 +1026,7 @@ const ALL_EPICS = [
1023
1026
  customerPaymentMethodEpic_1.fetchInvoicingPlaidLinkTokenEpic,
1024
1027
  fetchInvoicingQboConnectionEpic_1.fetchInvoicingQboConnectionEpic,
1025
1028
  fetchInvoicingQboSyncHealthEpic_1.fetchInvoicingQboSyncHealthEpic,
1026
- settingsViewEpics_1.fetchInvoicingSettingsEpic,
1029
+ fetchInvoicingSettingsEpic_1.fetchInvoicingSettingsEpic,
1027
1030
  fetchInvoicingSubscriptionCountsEpic_1.fetchInvoicingSubscriptionCountsEpic,
1028
1031
  invoicingSubscriptionDetailViewEpics_1.fetchInvoicingSubscriptionDetailEpic,
1029
1032
  fetchInvoicingSubscriptionFormPageEpic_1.fetchInvoicingSubscriptionFormPageEpic,
@@ -1311,7 +1314,7 @@ const ALL_EPICS = [
1311
1314
  saveInvoicingCouponEpic_1.saveInvoicingCouponEpic,
1312
1315
  saveInvoicingCustomerEpic_1.saveInvoicingCustomerEpic,
1313
1316
  customerPaymentMethodEpic_1.saveInvoicingPaymentMethodEpic,
1314
- settingsViewEpics_1.saveInvoicingSettingsEpic,
1317
+ saveInvoicingSettingsEpic_1.saveInvoicingSettingsEpic,
1315
1318
  saveInvoicingSubscriptionEpic_1.saveInvoicingSubscriptionEpic,
1316
1319
  saveMagicLinkBankAccountEpic_1.saveMagicLinkBankAccountEpic,
1317
1320
  saveNewAddressEpic_1.saveNewAddressEpic,
package/lib/esm/epic.js CHANGED
@@ -310,8 +310,11 @@ import { issueCreditNoteEpic } from './view/invoicing/issueCreditNote/issueCredi
310
310
  import { runInvoicingPaymentActionEpic, } from './view/invoicing/paymentAction/paymentActionEpic';
311
311
  import { addPromotionalCreditsEpic, } from './view/invoicing/promotionalCreditAction/promotionalCreditActionEpic';
312
312
  import { recordPaymentEpic, } from './view/invoicing/recordPayment/recordPaymentEpic';
313
+ import { connectInvoicingStripeEpic } from './view/invoicing/settingsView/epics/connectInvoicingStripeEpic';
314
+ import { disconnectInvoicingStripeEpic } from './view/invoicing/settingsView/epics/disconnectInvoicingStripeEpic';
315
+ import { fetchInvoicingSettingsEpic } from './view/invoicing/settingsView/epics/fetchInvoicingSettingsEpic';
316
+ import { saveInvoicingSettingsEpic } from './view/invoicing/settingsView/epics/saveInvoicingSettingsEpic';
313
317
  import { initializeInvoicingBrandingAddressEpic, submitInvoicingBrandingFormEpic, } from './view/invoicing/settingsView/invoicingBrandingFormEpics';
314
- import { connectInvoicingStripeEpic, disconnectInvoicingStripeEpic, fetchInvoicingSettingsEpic, saveInvoicingSettingsEpic, } from './view/invoicing/settingsView/settingsViewEpics';
315
318
  import { runInvoicingSubscriptionActionEpic, } from './view/invoicing/subscriptionAction/subscriptionActionEpic';
316
319
  import { fetchMonthClosePerformanceTrendEpic, } from './view/monthEndCloseChecksView/epics/fetchMonthClosePerformanceTrendEpic';
317
320
  import { fetchMonthEndCloseChecksEpic, } from './view/monthEndCloseChecksView/epics/fetchMonthEndCloseChecksEpic';
package/lib/esm/index.js CHANGED
@@ -194,11 +194,11 @@ import { getExpenseAutomationTransactionView, getLastTransferEntryReplacement, }
194
194
  import { applyTransactionFilters } from './view/expenseAutomationView/transactionFilterHelpers';
195
195
  import { TRANSACTION_FILTER_CATEGORIES, } from './view/expenseAutomationView/transactionFilterTypes';
196
196
  import { DEFAULT_COMPLETED_SUB_TAB, toCompletedSubTab, } from './view/expenseAutomationView/types/completedSubTab';
197
- import { DEFAULT_TRANSACTION_GROUP, TRANSACTION_GROUPS, toTransactionGroup, } from './view/expenseAutomationView/types/transactionGroup';
198
197
  import { toJEScheduleMainTab as toExpenseAutomationJEScheduleMainTab, toJEScheduleSortKey as toExpenseAutomationJEScheduleSortKey, } from './view/expenseAutomationView/types/jeSchedulesViewState';
199
198
  import { BATCH_FILE_STATUSES, isUnmatchedTabFileStatus, toBatchFileStatus, toBatchStatusValue, toBulkUploadPhase, toBulkUploadResultsTab, toBulkUploadSortKey, toMatchSource, toMissingReceiptsTab, } from './view/expenseAutomationView/types/missingReceiptsViewState';
200
199
  import { toMissingReceiptsSortKey as toExpenseAutomationMissingReceiptsSortKey, } from './view/expenseAutomationView/types/missingReceiptsViewState';
201
200
  import { toReconciliationTabsType, } from './view/expenseAutomationView/types/reconciliationViewState';
201
+ import { DEFAULT_TRANSACTION_GROUP, TRANSACTION_GROUPS, toTransactionGroup, } from './view/expenseAutomationView/types/transactionGroup';
202
202
  import { toTransactionsTabKey as toExpenseAutomationTransactionsTabKey, toTransactionsSortKey, } from './view/expenseAutomationView/types/transactionsViewState';
203
203
  import { fetchRegisteredInterests, notifyMeForFeature, } from './view/featureNotificationView/featureNotificationViewReducer';
204
204
  import { getFeatureNotificationView, getRegisteredInterests, getRegisteredInterestsByFeature, isFeatureInterestRegistered, } from './view/featureNotificationView/featureNotificationViewSelector';
@@ -849,8 +849,8 @@ export { getInvoicingCatalogItemDetail } from './view/invoicing/invoicingCatalog
849
849
  export { getInvoicingPlanById } from './entity/invoicing/plan/planSelector';
850
850
  export { getInvoicingProductById } from './entity/invoicing/product/productSelector';
851
851
  // ── Invoicing: settings ───────────────────────────────────────────────────────
852
- export { connectInvoicingStripe, disconnectInvoicingStripe, fetchInvoicingSettings, resetInvoicingBrandingFormDraft, resetSaveInvoicingSettings, saveInvoicingSettings, submitInvoicingBrandingForm, updateInvoicingBrandingFormDraft, updateInvoicingSettings, } from './view/invoicing/settingsView/settingsViewReducer';
853
- export { getInvoicingBrandingFormView, getInvoicingSettings, getInvoicingSettingsFetchState, getInvoicingSettingsHubView, getInvoicingSettingsView, } from './view/invoicing/settingsView/settingsViewSelector';
852
+ export { connectInvoicingStripe, disconnectInvoicingStripe, fetchInvoicingSettings, resetInvoicingBrandingFormDraft, resetInvoicingQboSettingsDraft, resetSaveInvoicingSettings, saveInvoicingSettings, submitInvoicingBrandingForm, updateInvoicingBrandingFormDraft, updateInvoicingQboSettingsDraft, updateInvoicingSettings, } from './view/invoicing/settingsView/settingsViewReducer';
853
+ export { getInvoicingBrandingFormView, getInvoicingQboSettingsFormView, getInvoicingSettings, getInvoicingSettingsFetchState, getInvoicingSettingsHubView, getInvoicingSettingsView, } from './view/invoicing/settingsView/settingsViewSelector';
854
854
  export { INVOICING_BUSINESS_ADDRESS_TYPE, entityToInvoicingBrandingFormLocalData, initialInvoicingBrandingFormLocalData, } from './view/invoicing/settingsView/invoicingBrandingFormConfig';
855
855
  export { isStripeConnectedFromSettings } from './view/invoicing/settingsView/invoicingSettingsHelpers';
856
856
  // ── Invoicing: QBO integration ────────────────────────────────────────────────
@@ -46,16 +46,30 @@ export const invoicingQboAccountByQboId = (state, qboId) => {
46
46
  if (qboId == null || qboId === '') {
47
47
  return undefined;
48
48
  }
49
- const { accounts } = getAccountList(state.accountState, state.accountListState, INVOICING_ACCOUNT_LIST_KEY);
50
- return accounts.find((account) => String(account.qboId) === qboId);
49
+ // `getAccountList` throws when a listed id is missing from the entity slice.
50
+ // That is survivable when looking one account up — the caller falls back to
51
+ // the id it already had — but not when it happens inside an epic, where the
52
+ // throw would take the whole request with it.
53
+ try {
54
+ const { accounts } = getAccountList(state.accountState, state.accountListState, INVOICING_ACCOUNT_LIST_KEY);
55
+ return accounts.find((account) => String(account.qboId) === qboId);
56
+ }
57
+ catch {
58
+ return undefined;
59
+ }
51
60
  };
52
61
  /** The class behind a picker value, for the same reason as the account above. */
53
62
  export const invoicingQboClassByQboId = (state, qboId) => {
54
63
  if (qboId == null || qboId === '') {
55
64
  return undefined;
56
65
  }
57
- const { classes } = getClassList(state.classState, state.classListState);
58
- return classes.find((accountingClass) => String(accountingClass.qboId) === qboId);
66
+ try {
67
+ const { classes } = getClassList(state.classState, state.classListState);
68
+ return classes.find((accountingClass) => String(accountingClass.qboId) === qboId);
69
+ }
70
+ catch {
71
+ return undefined;
72
+ }
59
73
  };
60
74
  /**
61
75
  * Accounts and classes as the invoicing pickers need them. Both come from the
@@ -0,0 +1,27 @@
1
+ import { of } from 'rxjs';
2
+ import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
3
+ import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
4
+ import { connectInvoicingStripe, fetchInvoicingSettings, invoicingStripeConnectionFailure, updateInvoicingStripeConnection, } from '../settingsViewReducer';
5
+ export const connectInvoicingStripeEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(connectInvoicingStripe.match), mergeMap((action) => {
6
+ const apiUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0/settings/stripe-connect/setup`;
7
+ const { api_key, publishable_key, webhook_secret } = action.payload;
8
+ const body = {
9
+ api_key,
10
+ publishable_key,
11
+ ...(webhook_secret != null && webhook_secret !== ''
12
+ ? { webhook_secret }
13
+ : {}),
14
+ };
15
+ return zeniAPI
16
+ .postAndGetJSON(apiUrl, body)
17
+ .pipe(switchMap((response) => {
18
+ if (isSuccessResponse(response) && response.data != null) {
19
+ return of(updateInvoicingStripeConnection({
20
+ stripe_connected: response.data.stripe_connected,
21
+ publishable_key: response.data.publishable_key,
22
+ }), fetchInvoicingSettings());
23
+ }
24
+ return of(invoicingStripeConnectionFailure(response.status));
25
+ }), catchError((error) => of(invoicingStripeConnectionFailure(createZeniAPIStatus('Unexpected Error', 'Stripe connect setup REST API call errored out ' +
26
+ JSON.stringify(error))))));
27
+ }));
@@ -0,0 +1,24 @@
1
+ import { of } from 'rxjs';
2
+ import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
3
+ import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
4
+ import { disconnectInvoicingStripe, fetchInvoicingSettings, invoicingStripeConnectionFailure, updateInvoicingStripeConnection, } from '../settingsViewReducer';
5
+ export const disconnectInvoicingStripeEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(disconnectInvoicingStripe.match), mergeMap(() => {
6
+ const apiUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0/settings/stripe-connect/callback`;
7
+ return zeniAPI
8
+ .deleteAndGetJSON(apiUrl)
9
+ .pipe(switchMap((response) => {
10
+ if (isSuccessResponse(response)) {
11
+ return of(updateInvoicingStripeConnection({
12
+ stripe_connected: false,
13
+ publishable_key: '',
14
+ }), fetchInvoicingSettings());
15
+ }
16
+ return of(invoicingStripeConnectionFailure(response.status));
17
+ }), catchError((error) => of(invoicingStripeConnectionFailure(createZeniAPIStatus('Unexpected Error', 'Stripe disconnect REST API call errored out ' +
18
+ JSON.stringify(error))))));
19
+ }));
20
+ /**
21
+ * Turns the QBO settings draft into a save. The draft lives in the store, so the
22
+ * screen fires one action and this reads what to send — the values do not have
23
+ * to travel back out through the page's props to get here.
24
+ */
@@ -0,0 +1,19 @@
1
+ import { of } from 'rxjs';
2
+ import { catchError, filter, switchMap } from 'rxjs/operators';
3
+ import { updateAddresses } from '../../../../entity/address/addressReducer';
4
+ import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
5
+ import { fetchInvoicingSettings, updateInvoicingSettings, updateInvoicingSettingsFailure, } from '../settingsViewReducer';
6
+ export const fetchInvoicingSettingsEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(fetchInvoicingSettings.match), switchMap(() => {
7
+ const apiUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0/settings`;
8
+ return zeniAPI.getJSON(apiUrl).pipe(switchMap((response) => {
9
+ if (isSuccessResponse(response) && response.data != null) {
10
+ const address = response.data.address;
11
+ return [
12
+ ...(address != null ? [updateAddresses([address])] : []),
13
+ updateInvoicingSettings(response.data),
14
+ ];
15
+ }
16
+ return of(updateInvoicingSettingsFailure(response.status));
17
+ }), catchError((error) => of(updateInvoicingSettingsFailure(createZeniAPIStatus('Unexpected Error', 'Fetch settings REST API call errored out ' +
18
+ JSON.stringify(error))))));
19
+ }));
@@ -0,0 +1,54 @@
1
+ import { from } from 'rxjs';
2
+ import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
3
+ import { withInvoicingQboMappedAccounts, } from '../../../../entity/invoicing/invoicingCommonPayload';
4
+ import { apiErrorSnackbarVariables } from '../../../../entity/snackbar/snackbarApiError';
5
+ import { openSnackbar } from '../../../../entity/snackbar/snackbarReducer';
6
+ import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
7
+ import { invoicingQboAccountByQboId } from '../../invoicingQboView/invoicingQboViewSelector';
8
+ import { saveInvoicingSettings, saveInvoicingSettingsFailure, saveInvoicingSettingsSuccess, } from '../settingsViewReducer';
9
+ export const saveInvoicingSettingsEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(saveInvoicingSettings.match), mergeMap((action) => {
10
+ const apiUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0/settings`;
11
+ const { settings, snackbarSection } = action.payload;
12
+ // The QBO page edits mappings as picker ids; the service stores whole
13
+ // accounts. Expanded here, at the request boundary, so the page does not
14
+ // have to hold entities it only needs in order to save.
15
+ const qboSettings = settings.qbo;
16
+ const body = qboSettings?.account_mappings != null
17
+ ? {
18
+ ...settings,
19
+ qbo: {
20
+ ...qboSettings,
21
+ account_mappings: withInvoicingQboMappedAccounts(qboSettings.account_mappings, (qboId) => invoicingQboAccountByQboId(state$.value, qboId)),
22
+ },
23
+ }
24
+ : settings;
25
+ /** `status` surfaces the platform's error text; omit it to keep the generic copy. */
26
+ const snackbar = (messageText, status) => snackbarSection == null
27
+ ? []
28
+ : [
29
+ openSnackbar({
30
+ messageSection: snackbarSection,
31
+ messageText,
32
+ type: messageText === 'success' ? 'success' : 'error',
33
+ variables: apiErrorSnackbarVariables(status),
34
+ }),
35
+ ];
36
+ return zeniAPI
37
+ .putAndGetJSON(apiUrl, { ...body })
38
+ .pipe(switchMap((response) => {
39
+ if (isSuccessResponse(response) && response.data != null) {
40
+ return from([
41
+ saveInvoicingSettingsSuccess(response.data),
42
+ ...snackbar('success'),
43
+ ]);
44
+ }
45
+ return from([
46
+ saveInvoicingSettingsFailure(response.status),
47
+ ...snackbar('failed', response.status),
48
+ ]);
49
+ }), catchError((error) => from([
50
+ saveInvoicingSettingsFailure(createZeniAPIStatus('Unexpected Error', 'Save settings REST API call errored out ' +
51
+ JSON.stringify(error))),
52
+ ...snackbar('failed'),
53
+ ])));
54
+ }));
@@ -36,6 +36,9 @@ const settingsView = createSlice({
36
36
  saveInvoicingSettingsSuccess(draft, action) {
37
37
  draft.settings = action.payload;
38
38
  draft.saveFetchState = { fetchState: 'Completed', error: undefined };
39
+ // The server is authoritative again, so the draft steps aside rather than
40
+ // shadowing what was just persisted.
41
+ draft.qboDraft = undefined;
39
42
  },
40
43
  saveInvoicingSettingsFailure(draft, action) {
41
44
  draft.saveFetchState = { fetchState: 'Error', error: action.payload };
@@ -54,6 +57,12 @@ const settingsView = createSlice({
54
57
  resetInvoicingBrandingFormDraft(draft) {
55
58
  draft.brandingDraft = undefined;
56
59
  },
60
+ updateInvoicingQboSettingsDraft(draft, action) {
61
+ draft.qboDraft = action.payload.localData;
62
+ },
63
+ resetInvoicingQboSettingsDraft(draft) {
64
+ draft.qboDraft = undefined;
65
+ },
57
66
  connectInvoicingStripe: {
58
67
  reducer(draft) {
59
68
  draft.stripeFetchState = { fetchState: 'In-Progress', error: undefined };
@@ -85,5 +94,5 @@ const settingsView = createSlice({
85
94
  });
86
95
  },
87
96
  });
88
- export const { fetchInvoicingSettings, updateInvoicingSettings, updateInvoicingSettingsFailure, saveInvoicingSettings, saveInvoicingSettingsSuccess, saveInvoicingSettingsFailure, resetSaveInvoicingSettings, updateInvoicingBrandingFormDraft, submitInvoicingBrandingForm, resetInvoicingBrandingFormDraft, connectInvoicingStripe, disconnectInvoicingStripe, updateInvoicingStripeConnection, invoicingStripeConnectionFailure, } = settingsView.actions;
97
+ export const { fetchInvoicingSettings, updateInvoicingSettings, updateInvoicingSettingsFailure, saveInvoicingSettings, saveInvoicingSettingsSuccess, saveInvoicingSettingsFailure, resetSaveInvoicingSettings, updateInvoicingBrandingFormDraft, submitInvoicingBrandingForm, resetInvoicingBrandingFormDraft, updateInvoicingQboSettingsDraft, resetInvoicingQboSettingsDraft, connectInvoicingStripe, disconnectInvoicingStripe, updateInvoicingStripeConnection, invoicingStripeConnectionFailure, } = settingsView.actions;
89
98
  export default settingsView.reducer;
@@ -1,6 +1,7 @@
1
1
  import { getInvoicingQboAccountMappingId, } from '../../../entity/invoicing/invoicingCommonPayload';
2
2
  import { getFormattedAddress } from '../../addressView/addressViewSelector';
3
3
  import { getInvoicingConfigView } from '../invoicingConfigView/invoicingConfigViewSelector';
4
+ import { getInvoicingQboView, isInvoicingAccountingPickerDataLoading, } from '../invoicingQboView/invoicingQboViewSelector';
4
5
  import { INVOICING_BUSINESS_ADDRESS_TYPE, entityToInvoicingBrandingFormLocalData, } from './invoicingBrandingFormConfig';
5
6
  /**
6
7
  * Shared primitive: the raw invoicing settings. Consumed internally by other
@@ -92,6 +93,43 @@ export const getInvoicingSettingsHubView = (state) => {
92
93
  status,
93
94
  };
94
95
  };
96
+ /**
97
+ * Bundled view for the QBO configuration page: the draft it edits, the accounts
98
+ * and option lists its dropdowns render, the connection and sync health it
99
+ * reports, and the fetch states that decide between skeleton, form and error.
100
+ *
101
+ * `localData` is the draft once the user has edited, and the settings response
102
+ * before that — so the page has one field to read and CES owns when it becomes
103
+ * available, rather than the page copying settings into local state.
104
+ */
105
+ export const getInvoicingQboSettingsFormView = (state) => {
106
+ const { error, fetchState, qboDraft, saveFetchState, settings } = state.invoicingSettingsViewState;
107
+ const { fetchState: configFetchState, qboAccountMappingKindOptions, qboCustomerMatchingOptions, qboSyncStatusOptions, } = getInvoicingConfigView(state);
108
+ const qboView = getInvoicingQboView(state);
109
+ return {
110
+ accountMappingKindOptions: qboAccountMappingKindOptions,
111
+ accounts: qboView.accounts,
112
+ backfillState: qboView.backfillState,
113
+ connection: qboView.connection,
114
+ configFetchState,
115
+ customerMatchingOptions: qboCustomerMatchingOptions,
116
+ // The dropdowns cannot be built before both the settings and the accounts
117
+ // land, so the page waits on either rather than rendering empty pickers.
118
+ isLoading: fetchState === 'Not-Started' ||
119
+ fetchState === 'In-Progress' ||
120
+ isInvoicingAccountingPickerDataLoading(state),
121
+ isSyncEnabledSaved: settings?.qbo?.enabled === true,
122
+ localData: qboDraft ?? settings?.qbo ?? {},
123
+ nestedAccountHierarchy: qboView.nestedAccountHierarchy,
124
+ retryFetchStateByTaskId: qboView.retryFetchStateByTaskId,
125
+ saveState: saveFetchState.fetchState === 'Not-Started' && error != null
126
+ ? { fetchState, error }
127
+ : saveFetchState,
128
+ settingsFetchState: fetchState,
129
+ syncHealth: qboView.syncHealth,
130
+ syncStatusOptions: qboSyncStatusOptions,
131
+ };
132
+ };
95
133
  /**
96
134
  * Bundled view for the branding settings form: the draft `localData` (seeded
97
135
  * from the existing settings until the user edits), the business-address label
package/lib/index.d.ts CHANGED
@@ -320,12 +320,12 @@ import { getExpenseAutomationTransactionView, getLastTransferEntryReplacement }
320
320
  import { applyTransactionFilters } from './view/expenseAutomationView/transactionFilterHelpers';
321
321
  import { TRANSACTION_FILTER_CATEGORIES, TransactionFilterAmountMatchingOperator, TransactionFilterCategory, TransactionFilterCategoryDropdownOption, TransactionFilterCategoryField, TransactionFilterEntityType, TransactionFilters } from './view/expenseAutomationView/transactionFilterTypes';
322
322
  import { CompletedSubTab, DEFAULT_COMPLETED_SUB_TAB, toCompletedSubTab } from './view/expenseAutomationView/types/completedSubTab';
323
- import { DEFAULT_TRANSACTION_GROUP, TRANSACTION_GROUPS, TransactionGroup, toTransactionGroup } from './view/expenseAutomationView/types/transactionGroup';
324
323
  import { FluxAnalysisActionType, FluxAnalysisReviewStatus, FluxAnalysisSectionType, FluxAnalysisSortKey, FluxAnalysisViewUIState, FluxBalancesByMonth } from './view/expenseAutomationView/types/fluxAnalysisViewState';
325
324
  import { AccountSettingsLocalData, JEScheduleMainTab as ExpenseAutomationJEScheduleMainTab, JEScheduleSortKey as ExpenseAutomationJEScheduleSortKey, JESchedulesViewUIState as ExpenseAutomationJESchedulesViewUIState, JEScheduleLocalData, toJEScheduleMainTab as toExpenseAutomationJEScheduleMainTab, toJEScheduleSortKey as toExpenseAutomationJEScheduleSortKey } from './view/expenseAutomationView/types/jeSchedulesViewState';
326
325
  import { BATCH_FILE_STATUSES, BatchDetails, BatchFile, BatchFileStatus, BatchListItem, BatchStatus, BatchStatusValue, BatchSummary, BulkUploadPhase, BulkUploadResultsTab, BulkUploadSortKey, BulkUploadState, CandidateRef, MatchCandidate, MatchSource, MissingReceiptsTab, isUnmatchedTabFileStatus, toBatchFileStatus, toBatchStatusValue, toBulkUploadPhase, toBulkUploadResultsTab, toBulkUploadSortKey, toMatchSource, toMissingReceiptsTab } from './view/expenseAutomationView/types/missingReceiptsViewState';
327
326
  import { MissingReceiptsSortKey as ExpenseAutomationMissingReceiptsSortKey, MissingReceiptsViewState as ExpenseAutomationMissingReceiptsViewState, MissingReceiptsViewUIState as ExpenseAutomationMissingReceiptsViewUIState, toMissingReceiptsSortKey as toExpenseAutomationMissingReceiptsSortKey } from './view/expenseAutomationView/types/missingReceiptsViewState';
328
327
  import { AccountReconciliationLocalData, CombinedStatementAccount, ExcludeAccountFromReconciliationPayload, ReconciliationViewTabType as ExpenseAutomationReconciliationViewTab, ParsedStatementData, ReconReconcileSortKey, ReconReviewSortKey, ReconciliationReconcileTabLocalData, ReconciliationReviewTabLocalData, SaveReconcileDetailActionPayload as SaveExpenseAutomationReconciliationActionType, StatementAccountScope, StatementDateConflict, StatementMeta, StatementTransaction, StatementTransactionForUpdate, StatementTransactionsUpdate, StatementUpdateLocalData, toReconciliationTabsType } from './view/expenseAutomationView/types/reconciliationViewState';
328
+ import { DEFAULT_TRANSACTION_GROUP, TRANSACTION_GROUPS, TransactionGroup, toTransactionGroup } from './view/expenseAutomationView/types/transactionGroup';
329
329
  import { TransactionsTab as ExpenseAutomationTransactionsTab, TransactionsViewState as ExpenseAutomationTransactionsViewState, TransactionsViewUIState as ExpenseAutomationTransactionsViewUIState, SupportedTransactionCategorization, TransactionCategorizationLineItemData, TransactionReviewLocalData, TransactionsSortKey, TransactionsTab, toTransactionsTabKey as toExpenseAutomationTransactionsTabKey, toTransactionsSortKey } from './view/expenseAutomationView/types/transactionsViewState';
330
330
  import { fetchRegisteredInterests, notifyMeForFeature } from './view/featureNotificationView/featureNotificationViewReducer';
331
331
  import { getFeatureNotificationView, getRegisteredInterests, getRegisteredInterestsByFeature, isFeatureInterestRegistered } from './view/featureNotificationView/featureNotificationViewSelector';
@@ -1235,9 +1235,9 @@ export { getInvoicingCatalogItemDetail } from './view/invoicing/invoicingCatalog
1235
1235
  export { getInvoicingPlanById } from './entity/invoicing/plan/planSelector';
1236
1236
  export { getInvoicingProductById } from './entity/invoicing/product/productSelector';
1237
1237
  export type { InvoicingCatalogItemDetailView } from './view/invoicing/invoicingCatalogItemDetailView/invoicingCatalogItemDetailViewSelector';
1238
- export { connectInvoicingStripe, disconnectInvoicingStripe, fetchInvoicingSettings, resetInvoicingBrandingFormDraft, resetSaveInvoicingSettings, saveInvoicingSettings, submitInvoicingBrandingForm, updateInvoicingBrandingFormDraft, updateInvoicingSettings, } from './view/invoicing/settingsView/settingsViewReducer';
1239
- export { getInvoicingBrandingFormView, getInvoicingSettings, getInvoicingSettingsFetchState, getInvoicingSettingsHubView, getInvoicingSettingsView, } from './view/invoicing/settingsView/settingsViewSelector';
1240
- export type { InvoicingBrandingFormView, InvoicingSettingsHubView, InvoicingSettingsView, } from './view/invoicing/settingsView/settingsViewSelector';
1238
+ export { connectInvoicingStripe, disconnectInvoicingStripe, fetchInvoicingSettings, resetInvoicingBrandingFormDraft, resetInvoicingQboSettingsDraft, resetSaveInvoicingSettings, saveInvoicingSettings, submitInvoicingBrandingForm, updateInvoicingBrandingFormDraft, updateInvoicingQboSettingsDraft, updateInvoicingSettings, } from './view/invoicing/settingsView/settingsViewReducer';
1239
+ export { getInvoicingBrandingFormView, getInvoicingQboSettingsFormView, getInvoicingSettings, getInvoicingSettingsFetchState, getInvoicingSettingsHubView, getInvoicingSettingsView, } from './view/invoicing/settingsView/settingsViewSelector';
1240
+ export type { InvoicingBrandingFormView, InvoicingQboSettingsFormView, InvoicingSettingsHubView, InvoicingSettingsView, } from './view/invoicing/settingsView/settingsViewSelector';
1241
1241
  export type { InvoicingBrandingFormLocalData } from './view/invoicing/settingsView/invoicingBrandingFormConfig';
1242
1242
  export { INVOICING_BUSINESS_ADDRESS_TYPE, entityToInvoicingBrandingFormLocalData, initialInvoicingBrandingFormLocalData, } from './view/invoicing/settingsView/invoicingBrandingFormConfig';
1243
1243
  export { isStripeConnectedFromSettings } from './view/invoicing/settingsView/invoicingSettingsHelpers';
package/lib/index.js CHANGED
@@ -83,7 +83,7 @@ exports.runInvoicingCatalogPlanAction = exports.getInvoicingInvoiceActionState =
83
83
  exports.getInvoicingSetupIntentFetchState = exports.getInvoicingSetupIntent = exports.getInvoicingSentPaymentLinkMagicUrl = exports.getInvoicingSentPaymentLinkEmail = exports.getInvoicingPlaidLinkTokenFetchState = exports.getInvoicingPlaidLinkToken = exports.getInvoicingPaymentMethodSaveState = exports.getInvoicingPaymentLinkSendState = exports.sendInvoicingPaymentLink = exports.saveInvoicingPaymentMethod = exports.resetInvoicingCustomerPaymentMethod = exports.fetchInvoicingPlaidLinkToken = exports.createInvoicingSetupIntent = exports.getInvoicingCustomerDetail = exports.fetchInvoicingCustomerDetailPage = exports.fetchInvoicingCustomerDetail = exports.getInvoicingCustomerListView = exports.INVOICING_CUSTOMER_COLUMNS = exports.ALL_INVOICING_CUSTOMER_TAB_IDS = exports.ALL_INVOICING_CUSTOMER_SORT_KEYS = exports.updateInvoicingCustomerFilters = exports.setInvoicingCustomerActiveTab = exports.fetchInvoicingCustomerListPage = exports.fetchInvoicingCustomerList = exports.fetchInvoicingCustomerCounts = exports.updateInvoicingCustomers = exports.removeInvoicingCustomer = exports.INVOICING_LIST_PAGE_SIZE = exports.getInvoicingDataImportActionState = exports.uploadInvoicingMigrationFiles = exports.startInvoicingMigration = exports.rollbackInvoicingMigration = exports.retryInvoicingMigration = exports.connectInvoicingChargebee = exports.getInvoicingDataImportView = exports.setInvoicingActiveMigrationSessionId = exports.fetchInvoicingMigrationSessions = exports.fetchInvoicingMigrationSession = exports.fetchInvoicingMigrationDiagnostics = exports.fetchInvoicingDataImportStatus = exports.getInvoicingPaymentActionState = exports.runInvoicingPaymentAction = exports.getInvoicingDunningActionState = exports.runInvoicingDunningAction = exports.getInvoicingSubscriptionActionState = exports.runInvoicingSubscriptionAction = exports.getInvoicingDiscountActionState = exports.runInvoicingDiscountAction = exports.getInvoicingCatalogActionState = exports.runInvoicingCatalogProductAction = void 0;
84
84
  exports.updateInvoicingCouponFilters = exports.setInvoicingCouponActiveTab = exports.fetchInvoicingCouponListPage = exports.fetchInvoicingCouponList = exports.fetchInvoicingCouponCounts = exports.updateInvoicingCoupons = exports.removeInvoicingCoupon = exports.getInvoicingCreditNoteDetail = exports.getInvoicingCreditNoteById = exports.fetchInvoicingCreditNoteDetail = exports.getInvoicingCreditNoteListView = exports.INVOICING_CREDIT_NOTE_COLUMNS = exports.ALL_INVOICING_CREDIT_NOTE_TAB_IDS = exports.ALL_INVOICING_CREDIT_NOTE_SORT_KEYS = exports.updateInvoicingCreditNoteFilters = exports.setInvoicingCreditNoteActiveTab = exports.fetchInvoicingCreditNoteListPage = exports.fetchInvoicingCreditNoteList = exports.fetchInvoicingCreditNoteCounts = exports.updateInvoicingCreditNotes = exports.removeInvoicingCreditNote = exports.getInvoicingTransactionDetail = exports.getInvoicingTransactionById = exports.fetchInvoicingTransactionDetail = exports.getInvoicingTransactionListView = exports.INVOICING_TRANSACTION_COLUMNS = exports.ALL_INVOICING_TRANSACTION_TAB_IDS = exports.ALL_INVOICING_TRANSACTION_SORT_KEYS = exports.updateInvoicingTransactionFilters = exports.setInvoicingTransactionActiveTab = exports.fetchInvoicingTransactionListPage = exports.fetchInvoicingTransactionList = exports.updateInvoicingTransactions = exports.removeInvoicingTransaction = exports.getInvoicingSubscriptionDetail = exports.getInvoicingSubscriptionById = exports.fetchInvoicingSubscriptionDetail = exports.getInvoicingSubscriptionListView = exports.INVOICING_SUBSCRIPTION_COLUMNS = exports.ALL_INVOICING_SUBSCRIPTION_TAB_IDS = exports.ALL_INVOICING_SUBSCRIPTION_SORT_KEYS = exports.updateInvoicingSubscriptionFilters = exports.setInvoicingSubscriptionActiveTab = exports.fetchInvoicingSubscriptionListPage = exports.fetchInvoicingSubscriptionList = exports.fetchInvoicingSubscriptionCounts = exports.updateInvoicingSubscriptions = exports.removeInvoicingSubscription = exports.resetPromotionalCreditAction = exports.submitAddPromotionalCredits = void 0;
85
85
  exports.connectInvoicingStripe = exports.getInvoicingProductById = exports.getInvoicingPlanById = exports.getInvoicingCatalogItemDetail = exports.fetchInvoicingCatalogItemDetail = exports.getInvoicingCatalogListView = exports.INVOICING_PRODUCT_COLUMNS = exports.ALL_INVOICING_PRODUCT_SORT_KEYS = exports.updateInvoicingCatalogProductFilters = exports.updateInvoicingCatalogPlanFilters = exports.fetchInvoicingCatalogProductList = exports.fetchInvoicingCatalogPlanList = exports.fetchInvoicingCatalogListPage = exports.fetchInvoicingCatalogCounts = exports.updateInvoicingProducts = exports.removeInvoicingProduct = exports.updateInvoicingPlans = exports.removeInvoicingPlan = exports.mergeInvoicingPlanSubFamily = exports.getInvoicingDunningEmailPreview = exports.getInvoicingDunningCaseDetail = exports.getInvoicingDunningCaseById = exports.invalidateInvoicingDunningEmailPreview = exports.fetchInvoicingDunningEmailPreviewPage = exports.fetchInvoicingDunningCaseDetail = exports.clearInvoicingDunningCaseDetailView = exports.getInvoicingDunningCaseListView = exports.INVOICING_DUNNING_CASE_COLUMNS = exports.ALL_INVOICING_DUNNING_CASE_TAB_IDS = exports.ALL_INVOICING_DUNNING_CASE_SORT_KEYS = exports.updateInvoicingDunningCaseFilters = exports.setInvoicingDunningCaseActiveTab = exports.fetchInvoicingDunningCaseListPage = exports.fetchInvoicingDunningCaseList = exports.fetchInvoicingDunningCaseCounts = exports.updateInvoicingDunningCases = exports.removeInvoicingDunningCase = exports.getInvoicingCouponDetail = exports.fetchInvoicingCouponDetail = exports.getInvoicingCouponById = exports.getInvoicingCouponListView = exports.getInvoicingCouponListNextCursor = exports.getInvoicingCouponListItems = exports.getInvoicingCouponListHasMore = exports.getInvoicingCouponListFilters = exports.getInvoicingCouponListFetchState = exports.getInvoicingCouponCounts = exports.INVOICING_COUPON_COLUMNS = exports.ALL_INVOICING_COUPON_TAB_IDS = exports.ALL_INVOICING_COUPON_SORT_KEYS = void 0;
86
- exports.getInvoicingOnboardingGateView = exports.getInvoicingConfigView = exports.updateInvoicingConfig = exports.resetInvoicingConfigActionStates = exports.fetchInvoicingConfig = exports.enableInvoicing = exports.acceptInvoicingTerms = exports.withInvoicingQboAccountMappingId = exports.toInvoicingQboCustomerMatchingMode = exports.toInvoicingNamedOptionsByKey = exports.getInvoicingQboAccountMappingId = exports.INVOICING_QBO_CUSTOMER_MATCHING_MODES = exports.getInvoicingQboView = exports.invoicingAccountsForQboAccountTypes = exports.INVOICING_INCOME_ACCOUNT_TYPES = exports.startInvoicingQboBackfill = exports.retryInvoicingQboSyncTask = exports.fetchInvoicingQboSyncHealth = exports.fetchInvoicingQboConnection = exports.fetchInvoicingAccountingPickers = exports.isStripeConnectedFromSettings = exports.initialInvoicingBrandingFormLocalData = exports.entityToInvoicingBrandingFormLocalData = exports.INVOICING_BUSINESS_ADDRESS_TYPE = exports.getInvoicingSettingsView = exports.getInvoicingSettingsHubView = exports.getInvoicingSettingsFetchState = exports.getInvoicingSettings = exports.getInvoicingBrandingFormView = exports.updateInvoicingSettings = exports.updateInvoicingBrandingFormDraft = exports.submitInvoicingBrandingForm = exports.saveInvoicingSettings = exports.resetSaveInvoicingSettings = exports.resetInvoicingBrandingFormDraft = exports.fetchInvoicingSettings = exports.disconnectInvoicingStripe = void 0;
86
+ exports.getInvoicingOnboardingGateView = exports.getInvoicingConfigView = exports.updateInvoicingConfig = exports.resetInvoicingConfigActionStates = exports.fetchInvoicingConfig = exports.enableInvoicing = exports.acceptInvoicingTerms = exports.withInvoicingQboAccountMappingId = exports.toInvoicingQboCustomerMatchingMode = exports.toInvoicingNamedOptionsByKey = exports.getInvoicingQboAccountMappingId = exports.INVOICING_QBO_CUSTOMER_MATCHING_MODES = exports.getInvoicingQboView = exports.invoicingAccountsForQboAccountTypes = exports.INVOICING_INCOME_ACCOUNT_TYPES = exports.startInvoicingQboBackfill = exports.retryInvoicingQboSyncTask = exports.fetchInvoicingQboSyncHealth = exports.fetchInvoicingQboConnection = exports.fetchInvoicingAccountingPickers = exports.isStripeConnectedFromSettings = exports.initialInvoicingBrandingFormLocalData = exports.entityToInvoicingBrandingFormLocalData = exports.INVOICING_BUSINESS_ADDRESS_TYPE = exports.getInvoicingSettingsView = exports.getInvoicingSettingsHubView = exports.getInvoicingSettingsFetchState = exports.getInvoicingSettings = exports.getInvoicingQboSettingsFormView = exports.getInvoicingBrandingFormView = exports.updateInvoicingSettings = exports.updateInvoicingQboSettingsDraft = exports.updateInvoicingBrandingFormDraft = exports.submitInvoicingBrandingForm = exports.saveInvoicingSettings = exports.resetSaveInvoicingSettings = exports.resetInvoicingQboSettingsDraft = exports.resetInvoicingBrandingFormDraft = exports.fetchInvoicingSettings = exports.disconnectInvoicingStripe = void 0;
87
87
  const allowedValue_1 = require("./commonStateTypes/allowedValue");
88
88
  Object.defineProperty(exports, "isAllowedValueWithCode", { enumerable: true, get: function () { return allowedValue_1.isAllowedValueWithCode; } });
89
89
  Object.defineProperty(exports, "isAllowedValueWithID", { enumerable: true, get: function () { return allowedValue_1.isAllowedValueWithID; } });
@@ -982,10 +982,6 @@ Object.defineProperty(exports, "TRANSACTION_FILTER_CATEGORIES", { enumerable: tr
982
982
  const completedSubTab_1 = require("./view/expenseAutomationView/types/completedSubTab");
983
983
  Object.defineProperty(exports, "DEFAULT_COMPLETED_SUB_TAB", { enumerable: true, get: function () { return completedSubTab_1.DEFAULT_COMPLETED_SUB_TAB; } });
984
984
  Object.defineProperty(exports, "toCompletedSubTab", { enumerable: true, get: function () { return completedSubTab_1.toCompletedSubTab; } });
985
- const transactionGroup_1 = require("./view/expenseAutomationView/types/transactionGroup");
986
- Object.defineProperty(exports, "DEFAULT_TRANSACTION_GROUP", { enumerable: true, get: function () { return transactionGroup_1.DEFAULT_TRANSACTION_GROUP; } });
987
- Object.defineProperty(exports, "TRANSACTION_GROUPS", { enumerable: true, get: function () { return transactionGroup_1.TRANSACTION_GROUPS; } });
988
- Object.defineProperty(exports, "toTransactionGroup", { enumerable: true, get: function () { return transactionGroup_1.toTransactionGroup; } });
989
985
  const jeSchedulesViewState_1 = require("./view/expenseAutomationView/types/jeSchedulesViewState");
990
986
  Object.defineProperty(exports, "toExpenseAutomationJEScheduleMainTab", { enumerable: true, get: function () { return jeSchedulesViewState_1.toJEScheduleMainTab; } });
991
987
  Object.defineProperty(exports, "toExpenseAutomationJEScheduleSortKey", { enumerable: true, get: function () { return jeSchedulesViewState_1.toJEScheduleSortKey; } });
@@ -1003,6 +999,10 @@ const missingReceiptsViewState_2 = require("./view/expenseAutomationView/types/m
1003
999
  Object.defineProperty(exports, "toExpenseAutomationMissingReceiptsSortKey", { enumerable: true, get: function () { return missingReceiptsViewState_2.toMissingReceiptsSortKey; } });
1004
1000
  const reconciliationViewState_1 = require("./view/expenseAutomationView/types/reconciliationViewState");
1005
1001
  Object.defineProperty(exports, "toReconciliationTabsType", { enumerable: true, get: function () { return reconciliationViewState_1.toReconciliationTabsType; } });
1002
+ const transactionGroup_1 = require("./view/expenseAutomationView/types/transactionGroup");
1003
+ Object.defineProperty(exports, "DEFAULT_TRANSACTION_GROUP", { enumerable: true, get: function () { return transactionGroup_1.DEFAULT_TRANSACTION_GROUP; } });
1004
+ Object.defineProperty(exports, "TRANSACTION_GROUPS", { enumerable: true, get: function () { return transactionGroup_1.TRANSACTION_GROUPS; } });
1005
+ Object.defineProperty(exports, "toTransactionGroup", { enumerable: true, get: function () { return transactionGroup_1.toTransactionGroup; } });
1006
1006
  const transactionsViewState_1 = require("./view/expenseAutomationView/types/transactionsViewState");
1007
1007
  Object.defineProperty(exports, "toExpenseAutomationTransactionsTabKey", { enumerable: true, get: function () { return transactionsViewState_1.toTransactionsTabKey; } });
1008
1008
  Object.defineProperty(exports, "toTransactionsSortKey", { enumerable: true, get: function () { return transactionsViewState_1.toTransactionsSortKey; } });
@@ -3091,13 +3091,16 @@ Object.defineProperty(exports, "connectInvoicingStripe", { enumerable: true, get
3091
3091
  Object.defineProperty(exports, "disconnectInvoicingStripe", { enumerable: true, get: function () { return settingsViewReducer_2.disconnectInvoicingStripe; } });
3092
3092
  Object.defineProperty(exports, "fetchInvoicingSettings", { enumerable: true, get: function () { return settingsViewReducer_2.fetchInvoicingSettings; } });
3093
3093
  Object.defineProperty(exports, "resetInvoicingBrandingFormDraft", { enumerable: true, get: function () { return settingsViewReducer_2.resetInvoicingBrandingFormDraft; } });
3094
+ Object.defineProperty(exports, "resetInvoicingQboSettingsDraft", { enumerable: true, get: function () { return settingsViewReducer_2.resetInvoicingQboSettingsDraft; } });
3094
3095
  Object.defineProperty(exports, "resetSaveInvoicingSettings", { enumerable: true, get: function () { return settingsViewReducer_2.resetSaveInvoicingSettings; } });
3095
3096
  Object.defineProperty(exports, "saveInvoicingSettings", { enumerable: true, get: function () { return settingsViewReducer_2.saveInvoicingSettings; } });
3096
3097
  Object.defineProperty(exports, "submitInvoicingBrandingForm", { enumerable: true, get: function () { return settingsViewReducer_2.submitInvoicingBrandingForm; } });
3097
3098
  Object.defineProperty(exports, "updateInvoicingBrandingFormDraft", { enumerable: true, get: function () { return settingsViewReducer_2.updateInvoicingBrandingFormDraft; } });
3099
+ Object.defineProperty(exports, "updateInvoicingQboSettingsDraft", { enumerable: true, get: function () { return settingsViewReducer_2.updateInvoicingQboSettingsDraft; } });
3098
3100
  Object.defineProperty(exports, "updateInvoicingSettings", { enumerable: true, get: function () { return settingsViewReducer_2.updateInvoicingSettings; } });
3099
3101
  var settingsViewSelector_2 = require("./view/invoicing/settingsView/settingsViewSelector");
3100
3102
  Object.defineProperty(exports, "getInvoicingBrandingFormView", { enumerable: true, get: function () { return settingsViewSelector_2.getInvoicingBrandingFormView; } });
3103
+ Object.defineProperty(exports, "getInvoicingQboSettingsFormView", { enumerable: true, get: function () { return settingsViewSelector_2.getInvoicingQboSettingsFormView; } });
3101
3104
  Object.defineProperty(exports, "getInvoicingSettings", { enumerable: true, get: function () { return settingsViewSelector_2.getInvoicingSettings; } });
3102
3105
  Object.defineProperty(exports, "getInvoicingSettingsFetchState", { enumerable: true, get: function () { return settingsViewSelector_2.getInvoicingSettingsFetchState; } });
3103
3106
  Object.defineProperty(exports, "getInvoicingSettingsHubView", { enumerable: true, get: function () { return settingsViewSelector_2.getInvoicingSettingsHubView; } });
@@ -52,8 +52,17 @@ const invoicingQboAccountByQboId = (state, qboId) => {
52
52
  if (qboId == null || qboId === '') {
53
53
  return undefined;
54
54
  }
55
- const { accounts } = (0, accountListSelector_1.getAccountList)(state.accountState, state.accountListState, exports.INVOICING_ACCOUNT_LIST_KEY);
56
- return accounts.find((account) => String(account.qboId) === qboId);
55
+ // `getAccountList` throws when a listed id is missing from the entity slice.
56
+ // That is survivable when looking one account up — the caller falls back to
57
+ // the id it already had — but not when it happens inside an epic, where the
58
+ // throw would take the whole request with it.
59
+ try {
60
+ const { accounts } = (0, accountListSelector_1.getAccountList)(state.accountState, state.accountListState, exports.INVOICING_ACCOUNT_LIST_KEY);
61
+ return accounts.find((account) => String(account.qboId) === qboId);
62
+ }
63
+ catch {
64
+ return undefined;
65
+ }
57
66
  };
58
67
  exports.invoicingQboAccountByQboId = invoicingQboAccountByQboId;
59
68
  /** The class behind a picker value, for the same reason as the account above. */
@@ -61,8 +70,13 @@ const invoicingQboClassByQboId = (state, qboId) => {
61
70
  if (qboId == null || qboId === '') {
62
71
  return undefined;
63
72
  }
64
- const { classes } = (0, classListSelector_1.getClassList)(state.classState, state.classListState);
65
- return classes.find((accountingClass) => String(accountingClass.qboId) === qboId);
73
+ try {
74
+ const { classes } = (0, classListSelector_1.getClassList)(state.classState, state.classListState);
75
+ return classes.find((accountingClass) => String(accountingClass.qboId) === qboId);
76
+ }
77
+ catch {
78
+ return undefined;
79
+ }
66
80
  };
67
81
  exports.invoicingQboClassByQboId = invoicingQboClassByQboId;
68
82
  /**
@@ -0,0 +1,6 @@
1
+ import { ActionsObservable, StateObservable } from 'redux-observable';
2
+ import { Observable } from 'rxjs';
3
+ import { RootState } from '../../../../rootStateTypes';
4
+ import { ZeniAPI } from '../../../../zeniAPI';
5
+ import { InvoicingSettingsViewActionType } from './settingsViewActionType';
6
+ export declare const connectInvoicingStripeEpic: (actions$: ActionsObservable<InvoicingSettingsViewActionType>, _state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<InvoicingSettingsViewActionType>;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.connectInvoicingStripeEpic = void 0;
4
+ const rxjs_1 = require("rxjs");
5
+ const operators_1 = require("rxjs/operators");
6
+ const responsePayload_1 = require("../../../../responsePayload");
7
+ const settingsViewReducer_1 = require("../settingsViewReducer");
8
+ const connectInvoicingStripeEpic = (actions$, _state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(settingsViewReducer_1.connectInvoicingStripe.match), (0, operators_1.mergeMap)((action) => {
9
+ const apiUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0/settings/stripe-connect/setup`;
10
+ const { api_key, publishable_key, webhook_secret } = action.payload;
11
+ const body = {
12
+ api_key,
13
+ publishable_key,
14
+ ...(webhook_secret != null && webhook_secret !== ''
15
+ ? { webhook_secret }
16
+ : {}),
17
+ };
18
+ return zeniAPI
19
+ .postAndGetJSON(apiUrl, body)
20
+ .pipe((0, operators_1.switchMap)((response) => {
21
+ if ((0, responsePayload_1.isSuccessResponse)(response) && response.data != null) {
22
+ return (0, rxjs_1.of)((0, settingsViewReducer_1.updateInvoicingStripeConnection)({
23
+ stripe_connected: response.data.stripe_connected,
24
+ publishable_key: response.data.publishable_key,
25
+ }), (0, settingsViewReducer_1.fetchInvoicingSettings)());
26
+ }
27
+ return (0, rxjs_1.of)((0, settingsViewReducer_1.invoicingStripeConnectionFailure)(response.status));
28
+ }), (0, operators_1.catchError)((error) => (0, rxjs_1.of)((0, settingsViewReducer_1.invoicingStripeConnectionFailure)((0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', 'Stripe connect setup REST API call errored out ' +
29
+ JSON.stringify(error))))));
30
+ }));
31
+ exports.connectInvoicingStripeEpic = connectInvoicingStripeEpic;
@@ -0,0 +1,11 @@
1
+ import { ActionsObservable, StateObservable } from 'redux-observable';
2
+ import { Observable } from 'rxjs';
3
+ import { RootState } from '../../../../rootStateTypes';
4
+ import { ZeniAPI } from '../../../../zeniAPI';
5
+ import { InvoicingSettingsViewActionType } from './settingsViewActionType';
6
+ export declare const disconnectInvoicingStripeEpic: (actions$: ActionsObservable<InvoicingSettingsViewActionType>, _state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<InvoicingSettingsViewActionType>;
7
+ /**
8
+ * Turns the QBO settings draft into a save. The draft lives in the store, so the
9
+ * screen fires one action and this reads what to send — the values do not have
10
+ * to travel back out through the page's props to get here.
11
+ */
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.disconnectInvoicingStripeEpic = void 0;
4
+ const rxjs_1 = require("rxjs");
5
+ const operators_1 = require("rxjs/operators");
6
+ const responsePayload_1 = require("../../../../responsePayload");
7
+ const settingsViewReducer_1 = require("../settingsViewReducer");
8
+ const disconnectInvoicingStripeEpic = (actions$, _state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(settingsViewReducer_1.disconnectInvoicingStripe.match), (0, operators_1.mergeMap)(() => {
9
+ const apiUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0/settings/stripe-connect/callback`;
10
+ return zeniAPI
11
+ .deleteAndGetJSON(apiUrl)
12
+ .pipe((0, operators_1.switchMap)((response) => {
13
+ if ((0, responsePayload_1.isSuccessResponse)(response)) {
14
+ return (0, rxjs_1.of)((0, settingsViewReducer_1.updateInvoicingStripeConnection)({
15
+ stripe_connected: false,
16
+ publishable_key: '',
17
+ }), (0, settingsViewReducer_1.fetchInvoicingSettings)());
18
+ }
19
+ return (0, rxjs_1.of)((0, settingsViewReducer_1.invoicingStripeConnectionFailure)(response.status));
20
+ }), (0, operators_1.catchError)((error) => (0, rxjs_1.of)((0, settingsViewReducer_1.invoicingStripeConnectionFailure)((0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', 'Stripe disconnect REST API call errored out ' +
21
+ JSON.stringify(error))))));
22
+ }));
23
+ exports.disconnectInvoicingStripeEpic = disconnectInvoicingStripeEpic;
24
+ /**
25
+ * Turns the QBO settings draft into a save. The draft lives in the store, so the
26
+ * screen fires one action and this reads what to send — the values do not have
27
+ * to travel back out through the page's props to get here.
28
+ */
@@ -0,0 +1,6 @@
1
+ import { ActionsObservable, StateObservable } from 'redux-observable';
2
+ import { Observable } from 'rxjs';
3
+ import { RootState } from '../../../../rootStateTypes';
4
+ import { ZeniAPI } from '../../../../zeniAPI';
5
+ import { InvoicingSettingsViewActionType } from './settingsViewActionType';
6
+ export declare const fetchInvoicingSettingsEpic: (actions$: ActionsObservable<InvoicingSettingsViewActionType>, _state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<InvoicingSettingsViewActionType>;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fetchInvoicingSettingsEpic = void 0;
4
+ const rxjs_1 = require("rxjs");
5
+ const operators_1 = require("rxjs/operators");
6
+ const addressReducer_1 = require("../../../../entity/address/addressReducer");
7
+ const responsePayload_1 = require("../../../../responsePayload");
8
+ const settingsViewReducer_1 = require("../settingsViewReducer");
9
+ const fetchInvoicingSettingsEpic = (actions$, _state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(settingsViewReducer_1.fetchInvoicingSettings.match), (0, operators_1.switchMap)(() => {
10
+ const apiUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0/settings`;
11
+ return zeniAPI.getJSON(apiUrl).pipe((0, operators_1.switchMap)((response) => {
12
+ if ((0, responsePayload_1.isSuccessResponse)(response) && response.data != null) {
13
+ const address = response.data.address;
14
+ return [
15
+ ...(address != null ? [(0, addressReducer_1.updateAddresses)([address])] : []),
16
+ (0, settingsViewReducer_1.updateInvoicingSettings)(response.data),
17
+ ];
18
+ }
19
+ return (0, rxjs_1.of)((0, settingsViewReducer_1.updateInvoicingSettingsFailure)(response.status));
20
+ }), (0, operators_1.catchError)((error) => (0, rxjs_1.of)((0, settingsViewReducer_1.updateInvoicingSettingsFailure)((0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', 'Fetch settings REST API call errored out ' +
21
+ JSON.stringify(error))))));
22
+ }));
23
+ exports.fetchInvoicingSettingsEpic = fetchInvoicingSettingsEpic;
@@ -0,0 +1,6 @@
1
+ import { ActionsObservable, StateObservable } from 'redux-observable';
2
+ import { Observable } from 'rxjs';
3
+ import { RootState } from '../../../../rootStateTypes';
4
+ import { ZeniAPI } from '../../../../zeniAPI';
5
+ import { InvoicingSettingsViewActionType } from './settingsViewActionType';
6
+ export declare const saveInvoicingSettingsEpic: (actions$: ActionsObservable<InvoicingSettingsViewActionType>, state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<InvoicingSettingsViewActionType>;
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.saveInvoicingSettingsEpic = void 0;
4
+ const rxjs_1 = require("rxjs");
5
+ const operators_1 = require("rxjs/operators");
6
+ const invoicingCommonPayload_1 = require("../../../../entity/invoicing/invoicingCommonPayload");
7
+ const snackbarApiError_1 = require("../../../../entity/snackbar/snackbarApiError");
8
+ const snackbarReducer_1 = require("../../../../entity/snackbar/snackbarReducer");
9
+ const responsePayload_1 = require("../../../../responsePayload");
10
+ const invoicingQboViewSelector_1 = require("../../invoicingQboView/invoicingQboViewSelector");
11
+ const settingsViewReducer_1 = require("../settingsViewReducer");
12
+ const saveInvoicingSettingsEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(settingsViewReducer_1.saveInvoicingSettings.match), (0, operators_1.mergeMap)((action) => {
13
+ const apiUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0/settings`;
14
+ const { settings, snackbarSection } = action.payload;
15
+ // The QBO page edits mappings as picker ids; the service stores whole
16
+ // accounts. Expanded here, at the request boundary, so the page does not
17
+ // have to hold entities it only needs in order to save.
18
+ const qboSettings = settings.qbo;
19
+ const body = qboSettings?.account_mappings != null
20
+ ? {
21
+ ...settings,
22
+ qbo: {
23
+ ...qboSettings,
24
+ account_mappings: (0, invoicingCommonPayload_1.withInvoicingQboMappedAccounts)(qboSettings.account_mappings, (qboId) => (0, invoicingQboViewSelector_1.invoicingQboAccountByQboId)(state$.value, qboId)),
25
+ },
26
+ }
27
+ : settings;
28
+ /** `status` surfaces the platform's error text; omit it to keep the generic copy. */
29
+ const snackbar = (messageText, status) => snackbarSection == null
30
+ ? []
31
+ : [
32
+ (0, snackbarReducer_1.openSnackbar)({
33
+ messageSection: snackbarSection,
34
+ messageText,
35
+ type: messageText === 'success' ? 'success' : 'error',
36
+ variables: (0, snackbarApiError_1.apiErrorSnackbarVariables)(status),
37
+ }),
38
+ ];
39
+ return zeniAPI
40
+ .putAndGetJSON(apiUrl, { ...body })
41
+ .pipe((0, operators_1.switchMap)((response) => {
42
+ if ((0, responsePayload_1.isSuccessResponse)(response) && response.data != null) {
43
+ return (0, rxjs_1.from)([
44
+ (0, settingsViewReducer_1.saveInvoicingSettingsSuccess)(response.data),
45
+ ...snackbar('success'),
46
+ ]);
47
+ }
48
+ return (0, rxjs_1.from)([
49
+ (0, settingsViewReducer_1.saveInvoicingSettingsFailure)(response.status),
50
+ ...snackbar('failed', response.status),
51
+ ]);
52
+ }), (0, operators_1.catchError)((error) => (0, rxjs_1.from)([
53
+ (0, settingsViewReducer_1.saveInvoicingSettingsFailure)((0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', 'Save settings REST API call errored out ' +
54
+ JSON.stringify(error))),
55
+ ...snackbar('failed'),
56
+ ])));
57
+ }));
58
+ exports.saveInvoicingSettingsEpic = saveInvoicingSettingsEpic;
@@ -0,0 +1,5 @@
1
+ import { updateAddresses } from '../../../../entity/address/addressReducer';
2
+ import { openSnackbar } from '../../../../entity/snackbar/snackbarReducer';
3
+ import { connectInvoicingStripe, disconnectInvoicingStripe, fetchInvoicingSettings, invoicingStripeConnectionFailure, saveInvoicingSettings, saveInvoicingSettingsFailure, saveInvoicingSettingsSuccess, updateInvoicingSettings, updateInvoicingSettingsFailure, updateInvoicingStripeConnection } from '../settingsViewReducer';
4
+ /** Every action the settings epics accept or emit. */
5
+ export type InvoicingSettingsViewActionType = ReturnType<typeof fetchInvoicingSettings> | ReturnType<typeof updateInvoicingSettings> | ReturnType<typeof updateInvoicingSettingsFailure> | ReturnType<typeof saveInvoicingSettings> | ReturnType<typeof saveInvoicingSettingsSuccess> | ReturnType<typeof saveInvoicingSettingsFailure> | ReturnType<typeof connectInvoicingStripe> | ReturnType<typeof disconnectInvoicingStripe> | ReturnType<typeof updateInvoicingStripeConnection> | ReturnType<typeof invoicingStripeConnectionFailure> | ReturnType<typeof updateAddresses> | ReturnType<typeof openSnackbar>;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,4 +1,4 @@
1
- import { InvoicingSettingsPayload } from '../../../entity/invoicing/invoicingCommonPayload';
1
+ import { InvoicingQboSettingsPayload, InvoicingSettingsPayload } from '../../../entity/invoicing/invoicingCommonPayload';
2
2
  import { SnackbarMessageSections } from '../../../entity/snackbar/snackbarTypes';
3
3
  import { ZeniAPIStatus } from '../../../responsePayload';
4
4
  import { InvoicingBrandingFormLocalData } from './invoicingBrandingFormConfig';
@@ -19,6 +19,8 @@ export interface SaveInvoicingSettingsPayload {
19
19
  export declare const initialState: InvoicingSettingsViewState;
20
20
  export declare const fetchInvoicingSettings: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"invoicingSettingsView/fetchInvoicingSettings">, updateInvoicingSettings: import("@reduxjs/toolkit").ActionCreatorWithPayload<InvoicingSettingsPayload, "invoicingSettingsView/updateInvoicingSettings">, updateInvoicingSettingsFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<ZeniAPIStatus<Record<string, unknown>>, "invoicingSettingsView/updateInvoicingSettingsFailure">, saveInvoicingSettings: import("@reduxjs/toolkit").ActionCreatorWithPayload<SaveInvoicingSettingsPayload, "invoicingSettingsView/saveInvoicingSettings">, saveInvoicingSettingsSuccess: import("@reduxjs/toolkit").ActionCreatorWithPayload<InvoicingSettingsPayload, "invoicingSettingsView/saveInvoicingSettingsSuccess">, saveInvoicingSettingsFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<ZeniAPIStatus<Record<string, unknown>>, "invoicingSettingsView/saveInvoicingSettingsFailure">, resetSaveInvoicingSettings: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"invoicingSettingsView/resetSaveInvoicingSettings">, updateInvoicingBrandingFormDraft: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
21
21
  localData: InvoicingBrandingFormLocalData;
22
- }, "invoicingSettingsView/updateInvoicingBrandingFormDraft">, submitInvoicingBrandingForm: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"invoicingSettingsView/submitInvoicingBrandingForm">, resetInvoicingBrandingFormDraft: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"invoicingSettingsView/resetInvoicingBrandingFormDraft">, connectInvoicingStripe: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[credentials: StripeConnectCredentials], StripeConnectCredentials, "invoicingSettingsView/connectInvoicingStripe", never, never>, disconnectInvoicingStripe: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"invoicingSettingsView/disconnectInvoicingStripe">, updateInvoicingStripeConnection: import("@reduxjs/toolkit").ActionCreatorWithPayload<InvoicingStripeConnectionUpdate, "invoicingSettingsView/updateInvoicingStripeConnection">, invoicingStripeConnectionFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<ZeniAPIStatus<Record<string, unknown>>, "invoicingSettingsView/invoicingStripeConnectionFailure">;
22
+ }, "invoicingSettingsView/updateInvoicingBrandingFormDraft">, submitInvoicingBrandingForm: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"invoicingSettingsView/submitInvoicingBrandingForm">, resetInvoicingBrandingFormDraft: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"invoicingSettingsView/resetInvoicingBrandingFormDraft">, updateInvoicingQboSettingsDraft: import("@reduxjs/toolkit").ActionCreatorWithPayload<{
23
+ localData: InvoicingQboSettingsPayload;
24
+ }, "invoicingSettingsView/updateInvoicingQboSettingsDraft">, resetInvoicingQboSettingsDraft: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"invoicingSettingsView/resetInvoicingQboSettingsDraft">, connectInvoicingStripe: import("@reduxjs/toolkit").ActionCreatorWithPreparedPayload<[credentials: StripeConnectCredentials], StripeConnectCredentials, "invoicingSettingsView/connectInvoicingStripe", never, never>, disconnectInvoicingStripe: import("@reduxjs/toolkit").ActionCreatorWithoutPayload<"invoicingSettingsView/disconnectInvoicingStripe">, updateInvoicingStripeConnection: import("@reduxjs/toolkit").ActionCreatorWithPayload<InvoicingStripeConnectionUpdate, "invoicingSettingsView/updateInvoicingStripeConnection">, invoicingStripeConnectionFailure: import("@reduxjs/toolkit").ActionCreatorWithPayload<ZeniAPIStatus<Record<string, unknown>>, "invoicingSettingsView/invoicingStripeConnectionFailure">;
23
25
  declare const _default: import("redux").Reducer<InvoicingSettingsViewState>;
24
26
  export default _default;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  var _a;
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.invoicingStripeConnectionFailure = exports.updateInvoicingStripeConnection = exports.disconnectInvoicingStripe = exports.connectInvoicingStripe = exports.resetInvoicingBrandingFormDraft = exports.submitInvoicingBrandingForm = exports.updateInvoicingBrandingFormDraft = exports.resetSaveInvoicingSettings = exports.saveInvoicingSettingsFailure = exports.saveInvoicingSettingsSuccess = exports.saveInvoicingSettings = exports.updateInvoicingSettingsFailure = exports.updateInvoicingSettings = exports.fetchInvoicingSettings = exports.initialState = void 0;
4
+ exports.invoicingStripeConnectionFailure = exports.updateInvoicingStripeConnection = exports.disconnectInvoicingStripe = exports.connectInvoicingStripe = exports.resetInvoicingQboSettingsDraft = exports.updateInvoicingQboSettingsDraft = exports.resetInvoicingBrandingFormDraft = exports.submitInvoicingBrandingForm = exports.updateInvoicingBrandingFormDraft = exports.resetSaveInvoicingSettings = exports.saveInvoicingSettingsFailure = exports.saveInvoicingSettingsSuccess = exports.saveInvoicingSettings = exports.updateInvoicingSettingsFailure = exports.updateInvoicingSettings = exports.fetchInvoicingSettings = exports.initialState = void 0;
5
5
  const toolkit_1 = require("@reduxjs/toolkit");
6
6
  const rootActions_1 = require("../../../rootActions");
7
7
  exports.initialState = {
@@ -40,6 +40,9 @@ const settingsView = (0, toolkit_1.createSlice)({
40
40
  saveInvoicingSettingsSuccess(draft, action) {
41
41
  draft.settings = action.payload;
42
42
  draft.saveFetchState = { fetchState: 'Completed', error: undefined };
43
+ // The server is authoritative again, so the draft steps aside rather than
44
+ // shadowing what was just persisted.
45
+ draft.qboDraft = undefined;
43
46
  },
44
47
  saveInvoicingSettingsFailure(draft, action) {
45
48
  draft.saveFetchState = { fetchState: 'Error', error: action.payload };
@@ -58,6 +61,12 @@ const settingsView = (0, toolkit_1.createSlice)({
58
61
  resetInvoicingBrandingFormDraft(draft) {
59
62
  draft.brandingDraft = undefined;
60
63
  },
64
+ updateInvoicingQboSettingsDraft(draft, action) {
65
+ draft.qboDraft = action.payload.localData;
66
+ },
67
+ resetInvoicingQboSettingsDraft(draft) {
68
+ draft.qboDraft = undefined;
69
+ },
61
70
  connectInvoicingStripe: {
62
71
  reducer(draft) {
63
72
  draft.stripeFetchState = { fetchState: 'In-Progress', error: undefined };
@@ -89,5 +98,5 @@ const settingsView = (0, toolkit_1.createSlice)({
89
98
  });
90
99
  },
91
100
  });
92
- _a = settingsView.actions, exports.fetchInvoicingSettings = _a.fetchInvoicingSettings, exports.updateInvoicingSettings = _a.updateInvoicingSettings, exports.updateInvoicingSettingsFailure = _a.updateInvoicingSettingsFailure, exports.saveInvoicingSettings = _a.saveInvoicingSettings, exports.saveInvoicingSettingsSuccess = _a.saveInvoicingSettingsSuccess, exports.saveInvoicingSettingsFailure = _a.saveInvoicingSettingsFailure, exports.resetSaveInvoicingSettings = _a.resetSaveInvoicingSettings, exports.updateInvoicingBrandingFormDraft = _a.updateInvoicingBrandingFormDraft, exports.submitInvoicingBrandingForm = _a.submitInvoicingBrandingForm, exports.resetInvoicingBrandingFormDraft = _a.resetInvoicingBrandingFormDraft, exports.connectInvoicingStripe = _a.connectInvoicingStripe, exports.disconnectInvoicingStripe = _a.disconnectInvoicingStripe, exports.updateInvoicingStripeConnection = _a.updateInvoicingStripeConnection, exports.invoicingStripeConnectionFailure = _a.invoicingStripeConnectionFailure;
101
+ _a = settingsView.actions, exports.fetchInvoicingSettings = _a.fetchInvoicingSettings, exports.updateInvoicingSettings = _a.updateInvoicingSettings, exports.updateInvoicingSettingsFailure = _a.updateInvoicingSettingsFailure, exports.saveInvoicingSettings = _a.saveInvoicingSettings, exports.saveInvoicingSettingsSuccess = _a.saveInvoicingSettingsSuccess, exports.saveInvoicingSettingsFailure = _a.saveInvoicingSettingsFailure, exports.resetSaveInvoicingSettings = _a.resetSaveInvoicingSettings, exports.updateInvoicingBrandingFormDraft = _a.updateInvoicingBrandingFormDraft, exports.submitInvoicingBrandingForm = _a.submitInvoicingBrandingForm, exports.resetInvoicingBrandingFormDraft = _a.resetInvoicingBrandingFormDraft, exports.updateInvoicingQboSettingsDraft = _a.updateInvoicingQboSettingsDraft, exports.resetInvoicingQboSettingsDraft = _a.resetInvoicingQboSettingsDraft, exports.connectInvoicingStripe = _a.connectInvoicingStripe, exports.disconnectInvoicingStripe = _a.disconnectInvoicingStripe, exports.updateInvoicingStripeConnection = _a.updateInvoicingStripeConnection, exports.invoicingStripeConnectionFailure = _a.invoicingStripeConnectionFailure;
93
102
  exports.default = settingsView.reducer;
@@ -1,7 +1,10 @@
1
+ import { NestedAccountHierarchyForReport } from '../../../commonStateTypes/accountView/nestedAccountID';
1
2
  import { FetchState, FetchStateAndError } from '../../../commonStateTypes/common';
2
- import { InvoicingDunningActionOption, InvoicingNamedOption, InvoicingQboAccountMappingKindOption, InvoicingSettingsPayload } from '../../../entity/invoicing/invoicingCommonPayload';
3
+ import { InvoicingDunningActionOption, InvoicingNamedOption, InvoicingQboAccountMappingKindOption, InvoicingQboSettingsPayload, InvoicingSettingsPayload } from '../../../entity/invoicing/invoicingCommonPayload';
3
4
  import { ZeniAPIStatus } from '../../../responsePayload';
4
5
  import { RootState } from '../../../rootStateTypes';
6
+ import { InvoicingQboConnection, InvoicingQboSyncHealth } from '../invoicingQboView/invoicingQboViewPayload';
7
+ import { InvoicingAccountingOption } from '../invoicingQboView/invoicingQboViewSelector';
5
8
  import { InvoicingBrandingFormLocalData } from './invoicingBrandingFormConfig';
6
9
  /**
7
10
  * Shared primitive: the raw invoicing settings. Consumed internally by other
@@ -83,6 +86,37 @@ export interface InvoicingSettingsHubView {
83
86
  * and QBO slices read here are only fetched once a settings screen is mounted.
84
87
  */
85
88
  export declare const getInvoicingSettingsHubView: (state: RootState) => InvoicingSettingsHubView;
89
+ export interface InvoicingQboSettingsFormView {
90
+ accountMappingKindOptions: InvoicingQboAccountMappingKindOption[];
91
+ /** Accounts for the mapping dropdowns, narrowed per kind by the page. */
92
+ accounts: InvoicingAccountingOption[];
93
+ backfillState: FetchStateAndError;
94
+ /** So the screen can fetch only what is missing, without reading the slices. */
95
+ configFetchState: FetchState;
96
+ customerMatchingOptions: InvoicingNamedOption[];
97
+ isLoading: boolean;
98
+ /** The persisted sync toggle — the backfill guard checks that, not the draft. */
99
+ isSyncEnabledSaved: boolean;
100
+ /** The draft the page edits, seeded from the settings response. */
101
+ localData: InvoicingQboSettingsPayload;
102
+ nestedAccountHierarchy: NestedAccountHierarchyForReport[];
103
+ retryFetchStateByTaskId: Record<string, FetchStateAndError>;
104
+ saveState: FetchStateAndError;
105
+ settingsFetchState: FetchState;
106
+ syncStatusOptions: InvoicingNamedOption[];
107
+ connection?: InvoicingQboConnection;
108
+ syncHealth?: InvoicingQboSyncHealth;
109
+ }
110
+ /**
111
+ * Bundled view for the QBO configuration page: the draft it edits, the accounts
112
+ * and option lists its dropdowns render, the connection and sync health it
113
+ * reports, and the fetch states that decide between skeleton, form and error.
114
+ *
115
+ * `localData` is the draft once the user has edited, and the settings response
116
+ * before that — so the page has one field to read and CES owns when it becomes
117
+ * available, rather than the page copying settings into local state.
118
+ */
119
+ export declare const getInvoicingQboSettingsFormView: (state: RootState) => InvoicingQboSettingsFormView;
86
120
  export interface InvoicingBrandingFormView {
87
121
  dateFormatOptions: InvoicingNamedOption[];
88
122
  localData: InvoicingBrandingFormLocalData;
@@ -1,10 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getInvoicingBrandingFormView = exports.getInvoicingSettingsHubView = exports.getInvoicingSettingsView = exports.getInvoicingSettingsFetchState = exports.getInvoicingSettings = void 0;
3
+ exports.getInvoicingBrandingFormView = exports.getInvoicingQboSettingsFormView = exports.getInvoicingSettingsHubView = exports.getInvoicingSettingsView = exports.getInvoicingSettingsFetchState = exports.getInvoicingSettings = void 0;
4
4
  exports.deriveInvoicingEnablePrerequisites = deriveInvoicingEnablePrerequisites;
5
5
  const invoicingCommonPayload_1 = require("../../../entity/invoicing/invoicingCommonPayload");
6
6
  const addressViewSelector_1 = require("../../addressView/addressViewSelector");
7
7
  const invoicingConfigViewSelector_1 = require("../invoicingConfigView/invoicingConfigViewSelector");
8
+ const invoicingQboViewSelector_1 = require("../invoicingQboView/invoicingQboViewSelector");
8
9
  const invoicingBrandingFormConfig_1 = require("./invoicingBrandingFormConfig");
9
10
  /**
10
11
  * Shared primitive: the raw invoicing settings. Consumed internally by other
@@ -100,6 +101,44 @@ const getInvoicingSettingsHubView = (state) => {
100
101
  };
101
102
  };
102
103
  exports.getInvoicingSettingsHubView = getInvoicingSettingsHubView;
104
+ /**
105
+ * Bundled view for the QBO configuration page: the draft it edits, the accounts
106
+ * and option lists its dropdowns render, the connection and sync health it
107
+ * reports, and the fetch states that decide between skeleton, form and error.
108
+ *
109
+ * `localData` is the draft once the user has edited, and the settings response
110
+ * before that — so the page has one field to read and CES owns when it becomes
111
+ * available, rather than the page copying settings into local state.
112
+ */
113
+ const getInvoicingQboSettingsFormView = (state) => {
114
+ const { error, fetchState, qboDraft, saveFetchState, settings } = state.invoicingSettingsViewState;
115
+ const { fetchState: configFetchState, qboAccountMappingKindOptions, qboCustomerMatchingOptions, qboSyncStatusOptions, } = (0, invoicingConfigViewSelector_1.getInvoicingConfigView)(state);
116
+ const qboView = (0, invoicingQboViewSelector_1.getInvoicingQboView)(state);
117
+ return {
118
+ accountMappingKindOptions: qboAccountMappingKindOptions,
119
+ accounts: qboView.accounts,
120
+ backfillState: qboView.backfillState,
121
+ connection: qboView.connection,
122
+ configFetchState,
123
+ customerMatchingOptions: qboCustomerMatchingOptions,
124
+ // The dropdowns cannot be built before both the settings and the accounts
125
+ // land, so the page waits on either rather than rendering empty pickers.
126
+ isLoading: fetchState === 'Not-Started' ||
127
+ fetchState === 'In-Progress' ||
128
+ (0, invoicingQboViewSelector_1.isInvoicingAccountingPickerDataLoading)(state),
129
+ isSyncEnabledSaved: settings?.qbo?.enabled === true,
130
+ localData: qboDraft ?? settings?.qbo ?? {},
131
+ nestedAccountHierarchy: qboView.nestedAccountHierarchy,
132
+ retryFetchStateByTaskId: qboView.retryFetchStateByTaskId,
133
+ saveState: saveFetchState.fetchState === 'Not-Started' && error != null
134
+ ? { fetchState, error }
135
+ : saveFetchState,
136
+ settingsFetchState: fetchState,
137
+ syncHealth: qboView.syncHealth,
138
+ syncStatusOptions: qboSyncStatusOptions,
139
+ };
140
+ };
141
+ exports.getInvoicingQboSettingsFormView = getInvoicingQboSettingsFormView;
103
142
  /**
104
143
  * Bundled view for the branding settings form: the draft `localData` (seeded
105
144
  * from the existing settings until the user edits), the business-address label
@@ -1,9 +1,16 @@
1
1
  import { FetchStateAndError, FetchedState } from '../../../commonStateTypes/common';
2
- import { InvoicingSettingsPayload } from '../../../entity/invoicing/invoicingCommonPayload';
2
+ import { InvoicingQboSettingsPayload, InvoicingSettingsPayload } from '../../../entity/invoicing/invoicingCommonPayload';
3
3
  import { InvoicingBrandingFormLocalData } from './invoicingBrandingFormConfig';
4
4
  export interface InvoicingSettingsViewState extends FetchedState {
5
5
  saveFetchState: FetchStateAndError;
6
6
  stripeFetchState: FetchStateAndError;
7
7
  brandingDraft?: InvoicingBrandingFormLocalData;
8
+ /**
9
+ * In-progress QBO settings edits. Held here rather than in the page so a
10
+ * selection cannot be lost between the change and the save, and so a
11
+ * half-finished edit survives navigating away. Undefined until first edited,
12
+ * which is what makes the server's settings the fallback.
13
+ */
14
+ qboDraft?: InvoicingQboSettingsPayload;
8
15
  settings?: InvoicingSettingsPayload;
9
16
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zeniai/client-epic-state",
3
- "version": "5.2.10-betaAK0",
3
+ "version": "5.2.10-betaAK1",
4
4
  "description": "Shared module between Web & Mobile containing required abstractions for state management, async network communication. ",
5
5
  "main": "lib/index.js",
6
6
  "module": "lib/esm/index.js",
@@ -1,107 +0,0 @@
1
- import { from, of } from 'rxjs';
2
- import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
3
- import { updateAddresses } from '../../../entity/address/addressReducer';
4
- import { withInvoicingQboMappedAccounts, } from '../../../entity/invoicing/invoicingCommonPayload';
5
- import { apiErrorSnackbarVariables } from '../../../entity/snackbar/snackbarApiError';
6
- import { openSnackbar } from '../../../entity/snackbar/snackbarReducer';
7
- import { createZeniAPIStatus, isSuccessResponse, } from '../../../responsePayload';
8
- import { invoicingQboAccountByQboId } from '../invoicingQboView/invoicingQboViewSelector';
9
- import { connectInvoicingStripe, disconnectInvoicingStripe, fetchInvoicingSettings, invoicingStripeConnectionFailure, saveInvoicingSettings, saveInvoicingSettingsFailure, saveInvoicingSettingsSuccess, updateInvoicingSettings, updateInvoicingSettingsFailure, updateInvoicingStripeConnection, } from './settingsViewReducer';
10
- export const fetchInvoicingSettingsEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(fetchInvoicingSettings.match), switchMap(() => {
11
- const apiUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0/settings`;
12
- return zeniAPI.getJSON(apiUrl).pipe(switchMap((response) => {
13
- if (isSuccessResponse(response) && response.data != null) {
14
- const address = response.data.address;
15
- return [
16
- ...(address != null ? [updateAddresses([address])] : []),
17
- updateInvoicingSettings(response.data),
18
- ];
19
- }
20
- return of(updateInvoicingSettingsFailure(response.status));
21
- }), catchError((error) => of(updateInvoicingSettingsFailure(createZeniAPIStatus('Unexpected Error', 'Fetch settings REST API call errored out ' +
22
- JSON.stringify(error))))));
23
- }));
24
- export const connectInvoicingStripeEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(connectInvoicingStripe.match), mergeMap((action) => {
25
- const apiUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0/settings/stripe-connect/setup`;
26
- const { api_key, publishable_key, webhook_secret } = action.payload;
27
- const body = {
28
- api_key,
29
- publishable_key,
30
- ...(webhook_secret != null && webhook_secret !== ''
31
- ? { webhook_secret }
32
- : {}),
33
- };
34
- return zeniAPI
35
- .postAndGetJSON(apiUrl, body)
36
- .pipe(switchMap((response) => {
37
- if (isSuccessResponse(response) && response.data != null) {
38
- return of(updateInvoicingStripeConnection({
39
- stripe_connected: response.data.stripe_connected,
40
- publishable_key: response.data.publishable_key,
41
- }), fetchInvoicingSettings());
42
- }
43
- return of(invoicingStripeConnectionFailure(response.status));
44
- }), catchError((error) => of(invoicingStripeConnectionFailure(createZeniAPIStatus('Unexpected Error', 'Stripe connect setup REST API call errored out ' +
45
- JSON.stringify(error))))));
46
- }));
47
- export const disconnectInvoicingStripeEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(disconnectInvoicingStripe.match), mergeMap(() => {
48
- const apiUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0/settings/stripe-connect/callback`;
49
- return zeniAPI
50
- .deleteAndGetJSON(apiUrl)
51
- .pipe(switchMap((response) => {
52
- if (isSuccessResponse(response)) {
53
- return of(updateInvoicingStripeConnection({
54
- stripe_connected: false,
55
- publishable_key: '',
56
- }), fetchInvoicingSettings());
57
- }
58
- return of(invoicingStripeConnectionFailure(response.status));
59
- }), catchError((error) => of(invoicingStripeConnectionFailure(createZeniAPIStatus('Unexpected Error', 'Stripe disconnect REST API call errored out ' +
60
- JSON.stringify(error))))));
61
- }));
62
- export const saveInvoicingSettingsEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(saveInvoicingSettings.match), mergeMap((action) => {
63
- const apiUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0/settings`;
64
- const { settings, snackbarSection } = action.payload;
65
- // The QBO page edits mappings as picker ids; the service stores whole
66
- // accounts. Expanded here, at the request boundary, so the page does not
67
- // have to hold entities it only needs in order to save.
68
- const qboSettings = settings.qbo;
69
- const body = qboSettings?.account_mappings != null
70
- ? {
71
- ...settings,
72
- qbo: {
73
- ...qboSettings,
74
- account_mappings: withInvoicingQboMappedAccounts(qboSettings.account_mappings, (qboId) => invoicingQboAccountByQboId(state$.value, qboId)),
75
- },
76
- }
77
- : settings;
78
- /** `status` surfaces the platform's error text; omit it to keep the generic copy. */
79
- const snackbar = (messageText, status) => snackbarSection == null
80
- ? []
81
- : [
82
- openSnackbar({
83
- messageSection: snackbarSection,
84
- messageText,
85
- type: messageText === 'success' ? 'success' : 'error',
86
- variables: apiErrorSnackbarVariables(status),
87
- }),
88
- ];
89
- return zeniAPI
90
- .putAndGetJSON(apiUrl, { ...body })
91
- .pipe(switchMap((response) => {
92
- if (isSuccessResponse(response) && response.data != null) {
93
- return from([
94
- saveInvoicingSettingsSuccess(response.data),
95
- ...snackbar('success'),
96
- ]);
97
- }
98
- return from([
99
- saveInvoicingSettingsFailure(response.status),
100
- ...snackbar('failed', response.status),
101
- ]);
102
- }), catchError((error) => from([
103
- saveInvoicingSettingsFailure(createZeniAPIStatus('Unexpected Error', 'Save settings REST API call errored out ' +
104
- JSON.stringify(error))),
105
- ...snackbar('failed'),
106
- ])));
107
- }));
@@ -1,12 +0,0 @@
1
- import { ActionsObservable, StateObservable } from 'redux-observable';
2
- import { Observable } from 'rxjs';
3
- import { updateAddresses } from '../../../entity/address/addressReducer';
4
- import { openSnackbar } from '../../../entity/snackbar/snackbarReducer';
5
- import { RootState } from '../../../rootStateTypes';
6
- import { ZeniAPI } from '../../../zeniAPI';
7
- import { connectInvoicingStripe, disconnectInvoicingStripe, fetchInvoicingSettings, invoicingStripeConnectionFailure, saveInvoicingSettings, saveInvoicingSettingsFailure, saveInvoicingSettingsSuccess, updateInvoicingSettings, updateInvoicingSettingsFailure, updateInvoicingStripeConnection } from './settingsViewReducer';
8
- export type ActionType = ReturnType<typeof fetchInvoicingSettings> | ReturnType<typeof updateInvoicingSettings> | ReturnType<typeof updateInvoicingSettingsFailure> | ReturnType<typeof saveInvoicingSettings> | ReturnType<typeof saveInvoicingSettingsSuccess> | ReturnType<typeof saveInvoicingSettingsFailure> | ReturnType<typeof connectInvoicingStripe> | ReturnType<typeof disconnectInvoicingStripe> | ReturnType<typeof updateInvoicingStripeConnection> | ReturnType<typeof invoicingStripeConnectionFailure> | ReturnType<typeof updateAddresses> | ReturnType<typeof openSnackbar>;
9
- export declare const fetchInvoicingSettingsEpic: (actions$: ActionsObservable<ActionType>, _state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<ActionType>;
10
- export declare const connectInvoicingStripeEpic: (actions$: ActionsObservable<ActionType>, _state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<ActionType>;
11
- export declare const disconnectInvoicingStripeEpic: (actions$: ActionsObservable<ActionType>, _state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<ActionType>;
12
- export declare const saveInvoicingSettingsEpic: (actions$: ActionsObservable<ActionType>, state$: StateObservable<RootState>, zeniAPI: ZeniAPI) => Observable<ActionType>;
@@ -1,114 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.saveInvoicingSettingsEpic = exports.disconnectInvoicingStripeEpic = exports.connectInvoicingStripeEpic = exports.fetchInvoicingSettingsEpic = void 0;
4
- const rxjs_1 = require("rxjs");
5
- const operators_1 = require("rxjs/operators");
6
- const addressReducer_1 = require("../../../entity/address/addressReducer");
7
- const invoicingCommonPayload_1 = require("../../../entity/invoicing/invoicingCommonPayload");
8
- const snackbarApiError_1 = require("../../../entity/snackbar/snackbarApiError");
9
- const snackbarReducer_1 = require("../../../entity/snackbar/snackbarReducer");
10
- const responsePayload_1 = require("../../../responsePayload");
11
- const invoicingQboViewSelector_1 = require("../invoicingQboView/invoicingQboViewSelector");
12
- const settingsViewReducer_1 = require("./settingsViewReducer");
13
- const fetchInvoicingSettingsEpic = (actions$, _state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(settingsViewReducer_1.fetchInvoicingSettings.match), (0, operators_1.switchMap)(() => {
14
- const apiUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0/settings`;
15
- return zeniAPI.getJSON(apiUrl).pipe((0, operators_1.switchMap)((response) => {
16
- if ((0, responsePayload_1.isSuccessResponse)(response) && response.data != null) {
17
- const address = response.data.address;
18
- return [
19
- ...(address != null ? [(0, addressReducer_1.updateAddresses)([address])] : []),
20
- (0, settingsViewReducer_1.updateInvoicingSettings)(response.data),
21
- ];
22
- }
23
- return (0, rxjs_1.of)((0, settingsViewReducer_1.updateInvoicingSettingsFailure)(response.status));
24
- }), (0, operators_1.catchError)((error) => (0, rxjs_1.of)((0, settingsViewReducer_1.updateInvoicingSettingsFailure)((0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', 'Fetch settings REST API call errored out ' +
25
- JSON.stringify(error))))));
26
- }));
27
- exports.fetchInvoicingSettingsEpic = fetchInvoicingSettingsEpic;
28
- const connectInvoicingStripeEpic = (actions$, _state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(settingsViewReducer_1.connectInvoicingStripe.match), (0, operators_1.mergeMap)((action) => {
29
- const apiUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0/settings/stripe-connect/setup`;
30
- const { api_key, publishable_key, webhook_secret } = action.payload;
31
- const body = {
32
- api_key,
33
- publishable_key,
34
- ...(webhook_secret != null && webhook_secret !== ''
35
- ? { webhook_secret }
36
- : {}),
37
- };
38
- return zeniAPI
39
- .postAndGetJSON(apiUrl, body)
40
- .pipe((0, operators_1.switchMap)((response) => {
41
- if ((0, responsePayload_1.isSuccessResponse)(response) && response.data != null) {
42
- return (0, rxjs_1.of)((0, settingsViewReducer_1.updateInvoicingStripeConnection)({
43
- stripe_connected: response.data.stripe_connected,
44
- publishable_key: response.data.publishable_key,
45
- }), (0, settingsViewReducer_1.fetchInvoicingSettings)());
46
- }
47
- return (0, rxjs_1.of)((0, settingsViewReducer_1.invoicingStripeConnectionFailure)(response.status));
48
- }), (0, operators_1.catchError)((error) => (0, rxjs_1.of)((0, settingsViewReducer_1.invoicingStripeConnectionFailure)((0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', 'Stripe connect setup REST API call errored out ' +
49
- JSON.stringify(error))))));
50
- }));
51
- exports.connectInvoicingStripeEpic = connectInvoicingStripeEpic;
52
- const disconnectInvoicingStripeEpic = (actions$, _state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(settingsViewReducer_1.disconnectInvoicingStripe.match), (0, operators_1.mergeMap)(() => {
53
- const apiUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0/settings/stripe-connect/callback`;
54
- return zeniAPI
55
- .deleteAndGetJSON(apiUrl)
56
- .pipe((0, operators_1.switchMap)((response) => {
57
- if ((0, responsePayload_1.isSuccessResponse)(response)) {
58
- return (0, rxjs_1.of)((0, settingsViewReducer_1.updateInvoicingStripeConnection)({
59
- stripe_connected: false,
60
- publishable_key: '',
61
- }), (0, settingsViewReducer_1.fetchInvoicingSettings)());
62
- }
63
- return (0, rxjs_1.of)((0, settingsViewReducer_1.invoicingStripeConnectionFailure)(response.status));
64
- }), (0, operators_1.catchError)((error) => (0, rxjs_1.of)((0, settingsViewReducer_1.invoicingStripeConnectionFailure)((0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', 'Stripe disconnect REST API call errored out ' +
65
- JSON.stringify(error))))));
66
- }));
67
- exports.disconnectInvoicingStripeEpic = disconnectInvoicingStripeEpic;
68
- const saveInvoicingSettingsEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(settingsViewReducer_1.saveInvoicingSettings.match), (0, operators_1.mergeMap)((action) => {
69
- const apiUrl = `${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0/settings`;
70
- const { settings, snackbarSection } = action.payload;
71
- // The QBO page edits mappings as picker ids; the service stores whole
72
- // accounts. Expanded here, at the request boundary, so the page does not
73
- // have to hold entities it only needs in order to save.
74
- const qboSettings = settings.qbo;
75
- const body = qboSettings?.account_mappings != null
76
- ? {
77
- ...settings,
78
- qbo: {
79
- ...qboSettings,
80
- account_mappings: (0, invoicingCommonPayload_1.withInvoicingQboMappedAccounts)(qboSettings.account_mappings, (qboId) => (0, invoicingQboViewSelector_1.invoicingQboAccountByQboId)(state$.value, qboId)),
81
- },
82
- }
83
- : settings;
84
- /** `status` surfaces the platform's error text; omit it to keep the generic copy. */
85
- const snackbar = (messageText, status) => snackbarSection == null
86
- ? []
87
- : [
88
- (0, snackbarReducer_1.openSnackbar)({
89
- messageSection: snackbarSection,
90
- messageText,
91
- type: messageText === 'success' ? 'success' : 'error',
92
- variables: (0, snackbarApiError_1.apiErrorSnackbarVariables)(status),
93
- }),
94
- ];
95
- return zeniAPI
96
- .putAndGetJSON(apiUrl, { ...body })
97
- .pipe((0, operators_1.switchMap)((response) => {
98
- if ((0, responsePayload_1.isSuccessResponse)(response) && response.data != null) {
99
- return (0, rxjs_1.from)([
100
- (0, settingsViewReducer_1.saveInvoicingSettingsSuccess)(response.data),
101
- ...snackbar('success'),
102
- ]);
103
- }
104
- return (0, rxjs_1.from)([
105
- (0, settingsViewReducer_1.saveInvoicingSettingsFailure)(response.status),
106
- ...snackbar('failed', response.status),
107
- ]);
108
- }), (0, operators_1.catchError)((error) => (0, rxjs_1.from)([
109
- (0, settingsViewReducer_1.saveInvoicingSettingsFailure)((0, responsePayload_1.createZeniAPIStatus)('Unexpected Error', 'Save settings REST API call errored out ' +
110
- JSON.stringify(error))),
111
- ...snackbar('failed'),
112
- ])));
113
- }));
114
- exports.saveInvoicingSettingsEpic = saveInvoicingSettingsEpic;