@zeniai/client-epic-state 5.3.5 → 5.3.7-betaRD0

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 (67) hide show
  1. package/lib/entity/customerIncome/customerIncomeTrend.d.ts +18 -2
  2. package/lib/entity/customerIncome/customerIncomeTrend.js +65 -5
  3. package/lib/entity/insights/insightSummary.d.ts +3 -0
  4. package/lib/entity/insights/insightSummaryPayload.js +2 -0
  5. package/lib/entity/invoicing/invoice/invoicePayload.d.ts +1 -0
  6. package/lib/entity/invoicing/invoice/invoicePayload.js +3 -0
  7. package/lib/entity/invoicing/invoice/invoiceState.d.ts +2 -0
  8. package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
  9. package/lib/entity/snackbar/snackbarTypes.js +1 -0
  10. package/lib/entity/tenant/epic/fetchAllTenantsEpic.js +45 -38
  11. package/lib/entity/vendorExpense/vendorSpendTrendFilterTabType.d.ts +2 -2
  12. package/lib/epic.d.ts +4 -1
  13. package/lib/epic.js +6 -0
  14. package/lib/esm/entity/customerIncome/customerIncomeTrend.js +63 -4
  15. package/lib/esm/entity/insights/insightSummaryPayload.js +2 -0
  16. package/lib/esm/entity/invoicing/invoice/invoicePayload.js +3 -0
  17. package/lib/esm/entity/snackbar/snackbarTypes.js +1 -0
  18. package/lib/esm/entity/tenant/epic/fetchAllTenantsEpic.js +46 -39
  19. package/lib/esm/epic.js +6 -0
  20. package/lib/esm/index.js +5 -2
  21. package/lib/esm/init.js +14 -3
  22. package/lib/esm/reducer.js +3 -0
  23. package/lib/esm/sessionEndpointsLoader.js +7 -0
  24. package/lib/esm/view/customerSummaryView/customerSummaryViewPayload.js +1 -0
  25. package/lib/esm/view/customerSummaryView/customerSummaryViewReducer.js +197 -0
  26. package/lib/esm/view/customerSummaryView/customerSummaryViewSelector.js +35 -0
  27. package/lib/esm/view/customerSummaryView/customerSummaryViewState.js +10 -0
  28. package/lib/esm/view/customerSummaryView/epic/fetchCustomerSummaryDetailEpic.js +30 -0
  29. package/lib/esm/view/customerSummaryView/epic/fetchCustomerSummaryListEpic.js +27 -0
  30. package/lib/esm/view/customerSummaryView/epic/saveCustomerSummaryDetailEpic.js +44 -0
  31. package/lib/esm/view/expenseAutomationView/epics/accountRecon/fetchReconciliationViewEpic.js +2 -1
  32. package/lib/esm/view/trend/fetchIncomeTrendEpic.js +29 -6
  33. package/lib/esm/view/trend/trendReducer.js +4 -2
  34. package/lib/index.d.ts +9 -2
  35. package/lib/index.js +73 -51
  36. package/lib/init.d.ts +9 -0
  37. package/lib/init.js +17 -4
  38. package/lib/reducer.d.ts +1 -0
  39. package/lib/reducer.js +3 -0
  40. package/lib/rootStateTypes.d.ts +2 -0
  41. package/lib/sessionEndpointsLoader.d.ts +9 -0
  42. package/lib/sessionEndpointsLoader.js +11 -0
  43. package/lib/tsconfig.mocks.tsbuildinfo +1 -0
  44. package/lib/tsconfig.typecheck.tsbuildinfo +1 -0
  45. package/lib/view/commonVendorView/vendorsTabVendorView/vendorsTabVendorViewReducer.d.ts +2 -2
  46. package/lib/view/customerSummaryView/customerSummaryViewPayload.d.ts +38 -0
  47. package/lib/view/customerSummaryView/customerSummaryViewPayload.js +2 -0
  48. package/lib/view/customerSummaryView/customerSummaryViewReducer.d.ts +32 -0
  49. package/lib/view/customerSummaryView/customerSummaryViewReducer.js +202 -0
  50. package/lib/view/customerSummaryView/customerSummaryViewSelector.d.ts +20 -0
  51. package/lib/view/customerSummaryView/customerSummaryViewSelector.js +43 -0
  52. package/lib/view/customerSummaryView/customerSummaryViewState.d.ts +63 -0
  53. package/lib/view/customerSummaryView/customerSummaryViewState.js +13 -0
  54. package/lib/view/customerSummaryView/epic/fetchCustomerSummaryDetailEpic.d.ts +9 -0
  55. package/lib/view/customerSummaryView/epic/fetchCustomerSummaryDetailEpic.js +34 -0
  56. package/lib/view/customerSummaryView/epic/fetchCustomerSummaryListEpic.d.ts +7 -0
  57. package/lib/view/customerSummaryView/epic/fetchCustomerSummaryListEpic.js +31 -0
  58. package/lib/view/customerSummaryView/epic/saveCustomerSummaryDetailEpic.d.ts +8 -0
  59. package/lib/view/customerSummaryView/epic/saveCustomerSummaryDetailEpic.js +48 -0
  60. package/lib/view/expenseAutomationView/epics/accountRecon/fetchReconciliationViewEpic.js +2 -1
  61. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
  62. package/lib/view/trend/fetchIncomeTrendEpic.d.ts +1 -1
  63. package/lib/view/trend/fetchIncomeTrendEpic.js +28 -5
  64. package/lib/view/trend/trendReducer.d.ts +8 -1
  65. package/lib/view/trend/trendReducer.js +4 -2
  66. package/lib/zeniAPI.d.ts +2 -2
  67. package/package.json +26 -1
@@ -0,0 +1,27 @@
1
+ import { of } from 'rxjs';
2
+ import { catchError, exhaustMap, filter, map, startWith, switchMap, } from 'rxjs/operators';
3
+ import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
4
+ import { fetchCustomerSummaryList, updateCustomerSummaryList, updateCustomerSummaryListFailure, } from '../customerSummaryViewReducer';
5
+ export const fetchCustomerSummaryListEpic = (actions$, state$, zeniAPI) => {
6
+ const fetch$ = actions$.pipe(filter(fetchCustomerSummaryList.match));
7
+ const fetchPage = (action) => {
8
+ const { keepExistingListItems, pageToken, searchString } = action.payload;
9
+ const { uiState } = state$.value.customerSummaryViewState;
10
+ const query = {
11
+ page_token: pageToken,
12
+ sort_by: uiState.sortKey,
13
+ sort_order: uiState.sortOrder === 'ascending' ? 'asc' : 'desc',
14
+ search_text: searchString,
15
+ };
16
+ return zeniAPI
17
+ .getJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/customers/summary?query=${encodeURIComponent(JSON.stringify(query))}`)
18
+ .pipe(map((response) => isSuccessResponse(response)
19
+ ? updateCustomerSummaryList(response, keepExistingListItems)
20
+ : updateCustomerSummaryListFailure(response.status)), catchError((error) => of(updateCustomerSummaryListFailure(createZeniAPIStatus('Unexpected Error', 'Fetch customer summary list REST API call errored out' +
21
+ JSON.stringify(error))))));
22
+ };
23
+ // A new search / sort cancels whatever is in flight; a load-more is dropped while any page is in flight
24
+ // (the reducer ignores it too), so the in-flight page isn't restarted.
25
+ const loadMore$ = fetch$.pipe(filter(({ payload }) => payload.keepExistingListItems));
26
+ return fetch$.pipe(filter(({ payload }) => !payload.keepExistingListItems), map((action) => loadMore$.pipe(startWith(action))), startWith(loadMore$), switchMap((fetches$) => fetches$.pipe(exhaustMap(fetchPage))));
27
+ };
@@ -0,0 +1,44 @@
1
+ import { from } from 'rxjs';
2
+ import { catchError, concatMap, filter, mergeMap } from 'rxjs/operators';
3
+ import { openSnackbar } from '../../../entity/snackbar/snackbarReducer';
4
+ import { isSuccessResponse } from '../../../responsePayload';
5
+ import { saveCustomerSummaryDetail, updateCustomerSummaryDetail, updateCustomerSummarySaveState, } from '../customerSummaryViewReducer';
6
+ // Zeni-only edit of a customer's default category / class from the Customers tab.
7
+ export const saveCustomerSummaryDetailEpic = (actions$, _, zeniAPI) => actions$.pipe(filter(saveCustomerSummaryDetail.match),
8
+ // concatMap: quick successive saves resolve in order, so the latest one wins
9
+ concatMap(({ payload: { customerId, changes } }) => {
10
+ const failure = () => [
11
+ updateCustomerSummarySaveState(customerId, 'Error'),
12
+ openSnackbar({
13
+ messageSection: 'update_customer',
14
+ messageText: 'failed',
15
+ type: 'error',
16
+ }),
17
+ ];
18
+ return zeniAPI
19
+ .putAndGetJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/customers/summary/${encodeURIComponent(customerId)}`,
20
+ // Only the changed fields: an omitted one keeps its (possibly history-based) default
21
+ {
22
+ ...(changes.accountId !== undefined
23
+ ? { account_id: changes.accountId }
24
+ : {}),
25
+ ...(changes.accountingClassId !== undefined
26
+ ? { accounting_class_id: changes.accountingClassId }
27
+ : {}),
28
+ })
29
+ .pipe(mergeMap((response) => {
30
+ const customer = response.data?.customers?.[0];
31
+ if (!isSuccessResponse(response) || customer == null) {
32
+ return from(failure());
33
+ }
34
+ return from([
35
+ updateCustomerSummaryDetail(customerId, customer),
36
+ updateCustomerSummarySaveState(customerId, 'Completed'),
37
+ openSnackbar({
38
+ messageSection: 'update_customer',
39
+ messageText: 'success',
40
+ type: 'success',
41
+ }),
42
+ ]);
43
+ }), catchError(() => from(failure())));
44
+ }));
@@ -26,9 +26,10 @@ export const fetchReconciliationViewEpic = (actions$, state$, zeniAPI) => action
26
26
  }
27
27
  let fetchState;
28
28
  if (accountId != null) {
29
+ // Period bucket can be unhydrated during app-shell load.
29
30
  fetchState =
30
31
  accountReconciliationRecords[toMonthYearPeriodId(selectedPeriod)]
31
- .reconciliationByAccountID[accountId].transactionFetchState
32
+ ?.reconciliationByAccountID[accountId]?.transactionFetchState
32
33
  .fetchState;
33
34
  }
34
35
  else {
@@ -1,16 +1,38 @@
1
1
  import { concat, from, of } from 'rxjs';
2
- import { catchError, filter, mergeMap } from 'rxjs/operators';
2
+ import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
3
+ import { toTimePeriod, } from '../../commonStateTypes/timeframeTick';
4
+ import { getCustomerIncomeTrendKey } from '../../entity/customerIncome/customerIncomeTrendKey';
3
5
  import { updateCustomerIncomeTrend } from '../../entity/customerIncome/customerIncomeTrendReducer';
4
6
  import { createZeniAPIStatus, isSuccessResponse } from '../../responsePayload';
5
7
  import { date as zeniDate } from '../../zeniDayJS';
6
8
  import { fetchIncomeTrend, updateTrendFailure, updateTrendSuccess, } from './trendReducer';
7
- export const fetchIncomeTrendEpic = (actions$, _, zeniAPI) => actions$.pipe(filter(fetchIncomeTrend.match), mergeMap((action) => {
8
- const { customerId, customerName } = action.payload;
9
+ export const fetchIncomeTrendEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchIncomeTrend.match),
10
+ // switchMap: a late response for the previously selected customer must not land on the current one
11
+ switchMap((action) => {
12
+ const { customerId, customerName, dateRange } = action.payload;
13
+ // Customers tab: the trend for this exact range is already loaded (e.g. back from a transaction) ->
14
+ // just re-select it instead of re-running the live QBO report
15
+ const requestedPeriod = dateRange != null
16
+ ? {
17
+ startDate: zeniDate(dateRange.startDate),
18
+ endDate: zeniDate(dateRange.endDate),
19
+ }
20
+ : undefined;
21
+ if (requestedPeriod != null) {
22
+ const key = getCustomerIncomeTrendKey(customerId, toTimePeriod(requestedPeriod));
23
+ if (state$.value.customerIncomeState.customerIncomeTrendByPeriod[key] !=
24
+ null) {
25
+ return of(updateTrendSuccess(requestedPeriod));
26
+ }
27
+ }
9
28
  const query = {
10
29
  entity_id: customerId,
11
30
  entity_type: 'customer',
12
31
  customer_id: customerId,
13
32
  customer_name: customerName,
33
+ ...(dateRange != null
34
+ ? { start_date: dateRange.startDate, end_date: dateRange.endDate }
35
+ : {}),
14
36
  };
15
37
  const getIncomeTrend$ = zeniAPI
16
38
  .getJSON(`${zeniAPI.apiEndPoints.accountMicroServiceBaseUrl}/1.0/reports/income_trend?query=${encodeURIComponent(JSON.stringify(query))}`)
@@ -20,7 +42,7 @@ export const fetchIncomeTrendEpic = (actions$, _, zeniAPI) => actions$.pipe(filt
20
42
  id: customerId,
21
43
  name: customerName,
22
44
  };
23
- return from(updateTrendActions(customer, response));
45
+ return from(updateTrendActions(customer, response, requestedPeriod));
24
46
  }
25
47
  else {
26
48
  return of(updateTrendFailure(action.payload.customerId, response.status));
@@ -33,13 +55,14 @@ export const fetchIncomeTrendEpic = (actions$, _, zeniAPI) => actions$.pipe(filt
33
55
  *
34
56
  * @param customer
35
57
  * @param incomeResponse
58
+ * @param requestedPeriod stored under the requested range (not data_available_*) so the cache lookup hits
36
59
  * @returns actions for updating the trend
37
60
  */
38
- const updateTrendActions = (customer, incomeResponse) => {
61
+ const updateTrendActions = (customer, incomeResponse, requestedPeriod) => {
39
62
  const updateActions = [];
40
63
  /* eslint-disable @typescript-eslint/no-non-null-assertion */
41
64
  /* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */
42
- const trendPeriod = {
65
+ const trendPeriod = requestedPeriod ?? {
43
66
  startDate: zeniDate(incomeResponse.data?.report.data_available_start_date),
44
67
  endDate: zeniDate(incomeResponse.data?.report.data_available_end_date),
45
68
  };
@@ -14,8 +14,10 @@ const trend = createSlice({
14
14
  initialState: initialTrendState,
15
15
  reducers: {
16
16
  fetchIncomeTrend: {
17
- prepare(customerId, customerName) {
18
- return { payload: { customerId, customerName } };
17
+ prepare(customerId, customerName,
18
+ // ISO dates; omitted = the API default (last 8 months)
19
+ dateRange) {
20
+ return { payload: { customerId, customerName, dateRange } };
19
21
  },
20
22
  reducer(draft, action) {
21
23
  draft.selectedEntity = Object.assign({}, {
package/lib/index.d.ts CHANGED
@@ -175,7 +175,7 @@ import { Filing1099TinType } from './entity/vendor/vendorType';
175
175
  import { VendorExpenseState, VendorSpend } from './entity/vendorExpense/vendorExpenseState';
176
176
  import { VendorExpenseTrend } from './entity/vendorExpense/vendorExpenseTrend';
177
177
  import { ExternalAPIEndpoints } from './externalAPI';
178
- import initialize, { ZeniStore, disconnectPusher, initializePusher, initializeWithNewStore, injectFeatureEpics, injectFeatureModules, updateZeniAPIClientConfig, zeniAPIClientConfig } from './init';
178
+ import initialize, { ZeniStore, disconnectPusher, initializePusher, initializeWithNewStore, injectFeatureEpics, injectFeatureModules, setSessionEndpointsLoader, updateZeniAPIClientConfig, updateZeniAPIEndpoints, zeniAPIClientConfig } from './init';
179
179
  import { ZeniAPIStatus, isAccessDeniedError, isInvalidSessionError, isSuccessResponse } from './responsePayload';
180
180
  import { clearAll } from './rootActions';
181
181
  import { RootState } from './rootStateTypes';
@@ -722,7 +722,7 @@ export type { CreditAgentFocusFilter, CreditAgentSortDir, CreditAgentSortKey, Cr
722
722
  export { AccountSettingsLocalData };
723
723
  export { saveJeAccountSettings, saveJeAccountSettingsLocalData };
724
724
  export default initialize;
725
- export { initializePusher, disconnectPusher, Dayjs, ZeniDate, dateInLocal as zeniDateInLocal, date as zeniDate, dateLocal, dateNow, getBusinessDayOfDate, formatZeniDateFY as formatZeniDate, getFYMonths, getFYQuarterAndYear, getStartOfAndEndOfTimeframeForFY, getActualPeriodOfFYQtr, getActualPeriodOfFY, getLocalTimezone, addPeriod, subtractPeriod, setLocalTimezone, updateZeniDateLocaleID, ZeniUrl, toZeniUrl, toZeniUrlWithoutBaseURL, RESTAPIEndpoints, RootState, updateZeniAPIClientConfig, zeniAPIClientConfig, injectFeatureEpics, injectFeatureModules, initializeWithNewStore, ZeniStore, ZeniAPIStatus, getTimeframeTickTag, TimeFrameTickTag, isIncompleteMonthPresentInTimeframeTick, getLastMonthOfFYQuarter, getLastMonthOfFYYear, getMonthIndex, dateFromYearMonthDate, getMinDate, ExternalAPIEndpoints, };
725
+ export { initializePusher, disconnectPusher, Dayjs, ZeniDate, dateInLocal as zeniDateInLocal, date as zeniDate, dateLocal, dateNow, getBusinessDayOfDate, formatZeniDateFY as formatZeniDate, getFYMonths, getFYQuarterAndYear, getStartOfAndEndOfTimeframeForFY, getActualPeriodOfFYQtr, getActualPeriodOfFY, getLocalTimezone, addPeriod, subtractPeriod, setLocalTimezone, updateZeniDateLocaleID, ZeniUrl, toZeniUrl, toZeniUrlWithoutBaseURL, RESTAPIEndpoints, RootState, updateZeniAPIClientConfig, updateZeniAPIEndpoints, setSessionEndpointsLoader, zeniAPIClientConfig, injectFeatureEpics, injectFeatureModules, initializeWithNewStore, ZeniStore, ZeniAPIStatus, getTimeframeTickTag, TimeFrameTickTag, isIncompleteMonthPresentInTimeframeTick, getLastMonthOfFYQuarter, getLastMonthOfFYYear, getMonthIndex, dateFromYearMonthDate, getMinDate, ExternalAPIEndpoints, };
726
726
  export { ID, FetchState, FetchStateAndError, FetchedState, UpdateType, Mode, AccountViewMode, CompletionStatusType, };
727
727
  export { Amount, toAmount, Currency };
728
728
  export { View, SelectorView, Report, ReportID, toReportID, ReportIDPlusForecastID, SelectorReport, ReportFormat, toReportFormatStrict, isCashFlowOrBalanceSheetReport, isBalanceSheetReport, isBalanceSheetClassesViewReport, isBalanceSheetProjectViewReport, isCashFlowClassesViewReport, isCashFlowProjectViewReport, isCashFlowReport, isGroupedCashFlowReport, isGroupedBalanceSheetReport, isDashboardReport, isDashboardClassesViewReport, isDashboardProjectViewReport, isPAndLReport, isPAndLClassesViewReport, isPAndLProjectViewReport, isAgingReport, isOpExByVendorReport, isFluxAnalysisOpExReport, PageToken, };
@@ -831,6 +831,7 @@ export { getTrendWithTransactions, TrendWithTransactionsView, getLatestTimeFrame
831
831
  export { fetchIncomeTrend, fetchExpenseTrend, clearTrendData };
832
832
  export { getTrendForEntity, TrendView, getCurrentFiscalQuarterDateRange };
833
833
  export { CustomerIncomeTrend };
834
+ export type { CustomerIncomeTrendFilter } from './entity/customerIncome/customerIncomeTrend';
834
835
  export { VendorExpenseTrend, VendorExpenseState, VendorSpend };
835
836
  export { Entity, toEntityType, TransactionEntityType };
836
837
  export { fetchEntityAutoCompleteEpic };
@@ -1269,4 +1270,10 @@ export { getActualMatchingAmount, getActualMatchingReversalDate, getActualMatchi
1269
1270
  export type { ExpenseAutomationActualMatchingMatchView } from './view/expenseAutomationView/selectors/actualMatchingViewSelector';
1270
1271
  export type { ActualMatchingMatch, ActualMatchingMatchKind, } from './entity/actualMatching/actualMatchingState';
1271
1272
  export type { ActualMatchingMatchId } from './entity/actualMatching/actualMatchingTypes';
1273
+ export type { SessionEndpointsLoader } from './sessionEndpointsLoader';
1272
1274
  export type { DisplayCurrencyFallback } from './entity/actualMatching/actualMatchingPayload';
1275
+ export { fetchCustomerSummaryDetail, fetchCustomerSummaryList, resetCustomerSummaryDetailUiState, saveCustomerSummaryDetail, updateCustomerAllTransactionsTabData, updateCustomerDetailSelectedTab, updateCustomerSummaryRevenueSelection, updateCustomerSummaryScrollYOffset, updateCustomerSummarySortUiState, updateCustomerTrendFilter, } from './view/customerSummaryView/customerSummaryViewReducer';
1276
+ export { getCustomerSummaryAllTransactionsTabData, getCustomerSummaryDetail, getCustomerSummaryList, getCustomerSummarySelectedTabType, getCustomerSummaryTrendFilter, isCustomersTabVisible, } from './view/customerSummaryView/customerSummaryViewSelector';
1277
+ export type { CustomerSummaryDetailView } from './view/customerSummaryView/customerSummaryViewSelector';
1278
+ export { CUSTOMER_REVENUE_KEYS } from './view/customerSummaryView/customerSummaryViewState';
1279
+ export type { CustomerAllTransactionsTabData, CustomerDetailTabType, CustomerRevenueKey, CustomerSummary, CustomerSummaryDetailChanges, CustomerSummaryDetailState, CustomerSummarySortKey, CustomerSummaryViewState, } from './view/customerSummaryView/customerSummaryViewState';