@zeniai/client-epic-state 5.1.69 → 5.1.70

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 (81) hide show
  1. package/lib/esm/index.js +7 -7
  2. package/lib/esm/view/invoicing/couponView/couponViewEpics.js +0 -3
  3. package/lib/esm/view/invoicing/couponView/couponViewReducer.js +7 -1
  4. package/lib/esm/view/invoicing/couponView/couponViewSelector.js +27 -14
  5. package/lib/esm/view/invoicing/invoiceList/fetchInvoiceListEpic.js +7 -5
  6. package/lib/esm/view/invoicing/invoiceList/fetchInvoiceListPageEpic.js +2 -1
  7. package/lib/esm/view/invoicing/invoiceList/invoiceListReducer.js +62 -36
  8. package/lib/esm/view/invoicing/invoiceList/invoiceListSelector.js +19 -15
  9. package/lib/esm/view/invoicing/invoiceList/invoiceListState.js +10 -0
  10. package/lib/esm/view/invoicing/invoicingCreditNoteListView/epics/fetchInvoicingCreditNoteListEpic.js +0 -3
  11. package/lib/esm/view/invoicing/invoicingCreditNoteListView/invoicingCreditNoteListViewReducer.js +7 -1
  12. package/lib/esm/view/invoicing/invoicingCreditNoteListView/invoicingCreditNoteListViewSelector.js +23 -13
  13. package/lib/esm/view/invoicing/invoicingCustomerDetailView/fetchInvoicingCustomerDetailPageEpic.js +3 -2
  14. package/lib/esm/view/invoicing/invoicingCustomerDetailView/invoicingCustomerDetailViewSelector.js +1 -1
  15. package/lib/esm/view/invoicing/invoicingCustomerListView/epics/fetchInvoicingCustomerListEpic.js +0 -3
  16. package/lib/esm/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewReducer.js +7 -1
  17. package/lib/esm/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewSelector.js +25 -12
  18. package/lib/esm/view/invoicing/invoicingDunningCaseListView/epics/fetchInvoicingDunningCaseListEpic.js +0 -3
  19. package/lib/esm/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewReducer.js +7 -1
  20. package/lib/esm/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewSelector.js +23 -13
  21. package/lib/esm/view/invoicing/invoicingSubscriptionListView/epics/fetchInvoicingSubscriptionListEpic.js +0 -3
  22. package/lib/esm/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewReducer.js +7 -1
  23. package/lib/esm/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewSelector.js +22 -12
  24. package/lib/esm/view/invoicing/invoicingTransactionListView/epics/fetchInvoicingTransactionListEpic.js +7 -5
  25. package/lib/esm/view/invoicing/invoicingTransactionListView/epics/fetchInvoicingTransactionListPageEpic.js +2 -1
  26. package/lib/esm/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewReducer.js +56 -25
  27. package/lib/esm/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewSelector.js +15 -11
  28. package/lib/esm/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewState.js +10 -0
  29. package/lib/index.d.ts +7 -7
  30. package/lib/index.js +15 -8
  31. package/lib/view/invoicing/couponView/couponViewEpics.js +0 -3
  32. package/lib/view/invoicing/couponView/couponViewReducer.d.ts +1 -1
  33. package/lib/view/invoicing/couponView/couponViewReducer.js +8 -2
  34. package/lib/view/invoicing/couponView/couponViewSelector.d.ts +1 -0
  35. package/lib/view/invoicing/couponView/couponViewSelector.js +27 -14
  36. package/lib/view/invoicing/couponView/couponViewState.d.ts +2 -1
  37. package/lib/view/invoicing/invoiceList/fetchInvoiceListEpic.d.ts +1 -1
  38. package/lib/view/invoicing/invoiceList/fetchInvoiceListEpic.js +7 -5
  39. package/lib/view/invoicing/invoiceList/fetchInvoiceListPageEpic.js +2 -1
  40. package/lib/view/invoicing/invoiceList/invoiceListReducer.d.ts +5 -4
  41. package/lib/view/invoicing/invoiceList/invoiceListReducer.js +63 -37
  42. package/lib/view/invoicing/invoiceList/invoiceListSelector.d.ts +1 -0
  43. package/lib/view/invoicing/invoiceList/invoiceListSelector.js +19 -15
  44. package/lib/view/invoicing/invoiceList/invoiceListState.d.ts +20 -7
  45. package/lib/view/invoicing/invoiceList/invoiceListState.js +13 -1
  46. package/lib/view/invoicing/invoicingCreditNoteListView/epics/fetchInvoicingCreditNoteListEpic.js +0 -3
  47. package/lib/view/invoicing/invoicingCreditNoteListView/invoicingCreditNoteListViewReducer.d.ts +1 -1
  48. package/lib/view/invoicing/invoicingCreditNoteListView/invoicingCreditNoteListViewReducer.js +8 -2
  49. package/lib/view/invoicing/invoicingCreditNoteListView/invoicingCreditNoteListViewSelector.d.ts +1 -0
  50. package/lib/view/invoicing/invoicingCreditNoteListView/invoicingCreditNoteListViewSelector.js +23 -13
  51. package/lib/view/invoicing/invoicingCreditNoteListView/invoicingCreditNoteListViewState.d.ts +2 -1
  52. package/lib/view/invoicing/invoicingCustomerDetailView/fetchInvoicingCustomerDetailPageEpic.js +3 -2
  53. package/lib/view/invoicing/invoicingCustomerDetailView/invoicingCustomerDetailViewSelector.js +1 -1
  54. package/lib/view/invoicing/invoicingCustomerListView/epics/fetchInvoicingCustomerListEpic.js +0 -3
  55. package/lib/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewReducer.d.ts +1 -1
  56. package/lib/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewReducer.js +8 -2
  57. package/lib/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewSelector.d.ts +1 -0
  58. package/lib/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewSelector.js +25 -12
  59. package/lib/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewState.d.ts +2 -1
  60. package/lib/view/invoicing/invoicingDunningCaseListView/epics/fetchInvoicingDunningCaseListEpic.js +0 -3
  61. package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewReducer.d.ts +1 -1
  62. package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewReducer.js +8 -2
  63. package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewSelector.d.ts +1 -0
  64. package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewSelector.js +23 -13
  65. package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewState.d.ts +2 -1
  66. package/lib/view/invoicing/invoicingSubscriptionListView/epics/fetchInvoicingSubscriptionListEpic.js +0 -3
  67. package/lib/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewReducer.d.ts +1 -1
  68. package/lib/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewReducer.js +8 -2
  69. package/lib/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewSelector.d.ts +1 -0
  70. package/lib/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewSelector.js +22 -12
  71. package/lib/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewState.d.ts +3 -1
  72. package/lib/view/invoicing/invoicingTransactionListView/epics/fetchInvoicingTransactionListEpic.d.ts +1 -1
  73. package/lib/view/invoicing/invoicingTransactionListView/epics/fetchInvoicingTransactionListEpic.js +7 -5
  74. package/lib/view/invoicing/invoicingTransactionListView/epics/fetchInvoicingTransactionListPageEpic.js +2 -1
  75. package/lib/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewReducer.d.ts +1 -1
  76. package/lib/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewReducer.js +57 -26
  77. package/lib/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewSelector.d.ts +1 -0
  78. package/lib/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewSelector.js +15 -11
  79. package/lib/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewState.d.ts +18 -4
  80. package/lib/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewState.js +13 -1
  81. package/package.json +1 -1
package/lib/esm/index.js CHANGED
@@ -712,7 +712,7 @@ export { INVOICING_DUNNING_ACTIONS, INVOICING_SUBSCRIPTION_LIFECYCLE_ACTIONS, IN
712
712
  export { mapAuditLogEntry } from './view/invoicing/auditView/auditViewPayload';
713
713
  export { clearAllInvoices, removeInvoice, updateInvoices, } from './entity/invoicing/invoice/invoiceReducer';
714
714
  export { getInvoiceById, getInvoicesByIds, } from './entity/invoicing/invoice/invoiceSelector';
715
- export { clearInvoiceList, fetchInvoiceCounts, fetchInvoiceKPIs, fetchInvoiceList, fetchInvoiceListPage, updateInvoiceListFilters, } from './view/invoicing/invoiceList/invoiceListReducer';
715
+ export { clearInvoiceList, fetchInvoiceCounts, fetchInvoiceKPIs, fetchInvoiceList, fetchInvoiceListPage, setInvoiceActiveTab, updateInvoiceListFilters, } from './view/invoicing/invoiceList/invoiceListReducer';
716
716
  export { ALL_INVOICING_INVOICE_TAB_IDS, INVOICING_INVOICE_TABS, } from './view/invoicing/invoiceList/invoiceListState';
717
717
  export { getInvoiceListView } from './view/invoicing/invoiceList/invoiceListSelector';
718
718
  export { clearAllInvoiceDetail, fetchInvoiceDetail, } from './view/invoicing/invoiceDetail/invoiceDetailReducer';
@@ -768,7 +768,7 @@ export { getInvoicingDataImportActionState } from './view/invoicing/dataImportAc
768
768
  export { INVOICING_LIST_PAGE_SIZE } from './view/invoicing/invoicingApiHelper';
769
769
  // ── Invoicing: customers ──────────────────────────────────────────────────────
770
770
  export { clearAllInvoicingCustomers, removeInvoicingCustomer, updateInvoicingCustomers, } from './entity/invoicing/invoicingCustomer/invoicingCustomerReducer';
771
- export { clearInvoicingCustomerListView, fetchInvoicingCustomerCounts, fetchInvoicingCustomerList, fetchInvoicingCustomerListPage, updateInvoicingCustomerFilters, } from './view/invoicing/invoicingCustomerListView/invoicingCustomerListViewReducer';
771
+ export { clearInvoicingCustomerListView, fetchInvoicingCustomerCounts, fetchInvoicingCustomerList, fetchInvoicingCustomerListPage, setInvoicingCustomerActiveTab, updateInvoicingCustomerFilters, } from './view/invoicing/invoicingCustomerListView/invoicingCustomerListViewReducer';
772
772
  export { ALL_INVOICING_CUSTOMER_SORT_KEYS, ALL_INVOICING_CUSTOMER_TAB_IDS, INVOICING_CUSTOMER_COLUMNS, INVOICING_CUSTOMER_TABS, } from './view/invoicing/invoicingCustomerListView/invoicingCustomerListViewState';
773
773
  export { getInvoicingCustomerListView } from './view/invoicing/invoicingCustomerListView/invoicingCustomerListViewSelector';
774
774
  export { clearInvoicingCustomerDetailView, fetchInvoicingCustomerDetail, fetchInvoicingCustomerDetailPage, } from './view/invoicing/invoicingCustomerDetailView/invoicingCustomerDetailViewReducer';
@@ -780,28 +780,28 @@ export { getInvoicingPaymentLinkSendState, getInvoicingPaymentMethodSaveState, g
780
780
  export { submitAddPromotionalCredits, resetPromotionalCreditAction, } from './view/invoicing/promotionalCreditAction/promotionalCreditActionReducer';
781
781
  // ── Invoicing: subscriptions ──────────────────────────────────────────────────
782
782
  export { clearAllInvoicingSubscriptions, removeInvoicingSubscription, updateInvoicingSubscriptions, } from './entity/invoicing/invoicingSubscription/invoicingSubscriptionReducer';
783
- export { clearInvoicingSubscriptionListView, fetchInvoicingSubscriptionCounts, fetchInvoicingSubscriptionList, fetchInvoicingSubscriptionListPage, updateInvoicingSubscriptionFilters, } from './view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewReducer';
783
+ export { clearInvoicingSubscriptionListView, fetchInvoicingSubscriptionCounts, fetchInvoicingSubscriptionList, fetchInvoicingSubscriptionListPage, setInvoicingSubscriptionActiveTab, updateInvoicingSubscriptionFilters, } from './view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewReducer';
784
784
  export { ALL_INVOICING_SUBSCRIPTION_SORT_KEYS, ALL_INVOICING_SUBSCRIPTION_TAB_IDS, INVOICING_SUBSCRIPTION_COLUMNS, INVOICING_SUBSCRIPTION_TABS, } from './view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewState';
785
785
  export { getInvoicingSubscriptionListView } from './view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewSelector';
786
786
  export { clearInvoicingSubscriptionDetailView, fetchInvoicingSubscriptionDetail, } from './view/invoicing/invoicingSubscriptionDetailView/invoicingSubscriptionDetailViewReducer';
787
787
  export { getInvoicingSubscriptionById, getInvoicingSubscriptionDetail, } from './view/invoicing/invoicingSubscriptionDetailView/invoicingSubscriptionDetailViewSelector';
788
788
  // ── Invoicing: payments (transactions) ────────────────────────────────────────
789
789
  export { clearAllInvoicingTransactions, removeInvoicingTransaction, updateInvoicingTransactions, } from './entity/invoicing/invoicingTransaction/invoicingTransactionReducer';
790
- export { clearInvoicingTransactionListView, fetchInvoicingTransactionList, fetchInvoicingTransactionListPage, updateInvoicingTransactionFilters, } from './view/invoicing/invoicingTransactionListView/invoicingTransactionListViewReducer';
790
+ export { clearInvoicingTransactionListView, fetchInvoicingTransactionList, fetchInvoicingTransactionListPage, setInvoicingTransactionActiveTab, updateInvoicingTransactionFilters, } from './view/invoicing/invoicingTransactionListView/invoicingTransactionListViewReducer';
791
791
  export { ALL_INVOICING_TRANSACTION_SORT_KEYS, ALL_INVOICING_TRANSACTION_TAB_IDS, INVOICING_TRANSACTION_COLUMNS, INVOICING_TRANSACTION_TABS, } from './view/invoicing/invoicingTransactionListView/invoicingTransactionListViewState';
792
792
  export { getInvoicingTransactionListView } from './view/invoicing/invoicingTransactionListView/invoicingTransactionListViewSelector';
793
793
  export { clearInvoicingTransactionDetailView, fetchInvoicingTransactionDetail, } from './view/invoicing/invoicingTransactionDetailView/invoicingTransactionDetailViewReducer';
794
794
  export { getInvoicingTransactionById, getInvoicingTransactionDetail, } from './view/invoicing/invoicingTransactionDetailView/invoicingTransactionDetailViewSelector';
795
795
  // ── Invoicing: credit notes ───────────────────────────────────────────────────
796
796
  export { clearAllInvoicingCreditNotes, removeInvoicingCreditNote, updateInvoicingCreditNotes, } from './entity/invoicing/creditNote/creditNoteReducer';
797
- export { clearInvoicingCreditNoteListView, fetchInvoicingCreditNoteCounts, fetchInvoicingCreditNoteList, fetchInvoicingCreditNoteListPage, updateInvoicingCreditNoteFilters, } from './view/invoicing/invoicingCreditNoteListView/invoicingCreditNoteListViewReducer';
797
+ export { clearInvoicingCreditNoteListView, fetchInvoicingCreditNoteCounts, fetchInvoicingCreditNoteList, fetchInvoicingCreditNoteListPage, setInvoicingCreditNoteActiveTab, updateInvoicingCreditNoteFilters, } from './view/invoicing/invoicingCreditNoteListView/invoicingCreditNoteListViewReducer';
798
798
  export { ALL_INVOICING_CREDIT_NOTE_SORT_KEYS, ALL_INVOICING_CREDIT_NOTE_TAB_IDS, INVOICING_CREDIT_NOTE_COLUMNS, INVOICING_CREDIT_NOTE_TABS, } from './view/invoicing/invoicingCreditNoteListView/invoicingCreditNoteListViewState';
799
799
  export { getInvoicingCreditNoteListView } from './view/invoicing/invoicingCreditNoteListView/invoicingCreditNoteListViewSelector';
800
800
  export { clearInvoicingCreditNoteDetailView, fetchInvoicingCreditNoteDetail, } from './view/invoicing/invoicingCreditNoteDetailView/invoicingCreditNoteDetailViewReducer';
801
801
  export { getInvoicingCreditNoteById, getInvoicingCreditNoteDetail, } from './view/invoicing/invoicingCreditNoteDetailView/invoicingCreditNoteDetailViewSelector';
802
802
  // ── Invoicing: discounts (coupons) ────────────────────────────────────────────
803
803
  export { clearAllInvoicingCoupons, removeInvoicingCoupon, updateInvoicingCoupons, } from './entity/invoicing/coupon/couponReducer';
804
- export { clearInvoicingCouponView, fetchInvoicingCouponCounts, fetchInvoicingCouponList, fetchInvoicingCouponListPage, updateInvoicingCouponFilters, } from './view/invoicing/couponView/couponViewReducer';
804
+ export { clearInvoicingCouponView, fetchInvoicingCouponCounts, fetchInvoicingCouponList, fetchInvoicingCouponListPage, setInvoicingCouponActiveTab, updateInvoicingCouponFilters, } from './view/invoicing/couponView/couponViewReducer';
805
805
  export { ALL_INVOICING_COUPON_SORT_KEYS, ALL_INVOICING_COUPON_TAB_IDS, INVOICING_COUPON_COLUMNS, INVOICING_COUPON_TABS, } from './view/invoicing/couponView/couponViewState';
806
806
  export { getInvoicingCouponCounts, getInvoicingCouponListFetchState, getInvoicingCouponListFilters, getInvoicingCouponListHasMore, getInvoicingCouponListItems, getInvoicingCouponListNextCursor, getInvoicingCouponListView, } from './view/invoicing/couponView/couponViewSelector';
807
807
  export { getInvoicingCouponById } from './entity/invoicing/coupon/couponSelector';
@@ -809,7 +809,7 @@ export { clearInvoicingCouponDetailView, fetchInvoicingCouponDetail, } from './v
809
809
  export { getInvoicingCouponDetail } from './view/invoicing/invoicingCouponDetailView/invoicingCouponDetailViewSelector';
810
810
  // ── Invoicing: dunning ────────────────────────────────────────────────────────
811
811
  export { clearAllInvoicingDunningCases, removeInvoicingDunningCase, updateInvoicingDunningCases, } from './entity/invoicing/dunningCase/dunningCaseReducer';
812
- export { clearInvoicingDunningCaseListView, fetchInvoicingDunningCaseCounts, fetchInvoicingDunningCaseList, fetchInvoicingDunningCaseListPage, updateInvoicingDunningCaseFilters, } from './view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewReducer';
812
+ export { clearInvoicingDunningCaseListView, fetchInvoicingDunningCaseCounts, fetchInvoicingDunningCaseList, fetchInvoicingDunningCaseListPage, setInvoicingDunningCaseActiveTab, updateInvoicingDunningCaseFilters, } from './view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewReducer';
813
813
  export { ALL_INVOICING_DUNNING_CASE_SORT_KEYS, ALL_INVOICING_DUNNING_CASE_TAB_IDS, INVOICING_DUNNING_CASE_COLUMNS, INVOICING_DUNNING_CASE_TABS, } from './view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewState';
814
814
  export { getInvoicingDunningCaseListView } from './view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewSelector';
815
815
  export { clearInvoicingDunningCaseDetailView, fetchInvoicingDunningCaseDetail, } from './view/invoicing/invoicingDunningCaseDetailView/invoicingDunningCaseDetailViewReducer';
@@ -13,9 +13,6 @@ const shouldFetch = (fetchStateAndError, cacheOverride) => cacheOverride ||
13
13
  fetchStateAndError.fetchState !== 'In-Progress');
14
14
  const buildQuery = (filters, cursor, sort) => {
15
15
  const params = new URLSearchParams();
16
- if (filters.status != null && filters.status.length > 0) {
17
- params.set('status', filters.status);
18
- }
19
16
  if (filters.search != null && filters.search.length > 0) {
20
17
  params.set('search', filters.search);
21
18
  }
@@ -9,6 +9,7 @@ function couponStatusToTabCountKey(status) {
9
9
  export const initialState = {
10
10
  fetchState: 'Not-Started',
11
11
  error: undefined,
12
+ activeTab: 'all',
12
13
  ids: [],
13
14
  nextCursor: null,
14
15
  filters: {},
@@ -87,6 +88,11 @@ const couponView = createSlice({
87
88
  updateInvoicingCouponFilters(draft, action) {
88
89
  draft.filters = action.payload;
89
90
  },
91
+ // Select a status tab. The list API ignores `status` (returns all statuses),
92
+ // so the selector filters rows to this tab client-side — no refetch needed.
93
+ setInvoicingCouponActiveTab(draft, action) {
94
+ draft.activeTab = action.payload;
95
+ },
90
96
  // Reflect a newly created coupon in the cached discounts list + tab counts
91
97
  // so the list page shows it without refetching from the server. Edits keep
92
98
  // the same id/counts, so only creates dispatch this.
@@ -105,5 +111,5 @@ const couponView = createSlice({
105
111
  },
106
112
  },
107
113
  });
108
- export const { fetchInvoicingCouponList, fetchInvoicingCouponListPage, updateInvoicingCouponList, updateInvoicingCouponListFailure, fetchInvoicingCouponCounts, updateInvoicingCouponCounts, updateInvoicingCouponCountsFailure, updateInvoicingCouponFilters, addInvoicingCouponToList, clearInvoicingCouponView, } = couponView.actions;
114
+ export const { fetchInvoicingCouponList, fetchInvoicingCouponListPage, updateInvoicingCouponList, updateInvoicingCouponListFailure, fetchInvoicingCouponCounts, updateInvoicingCouponCounts, updateInvoicingCouponCountsFailure, updateInvoicingCouponFilters, setInvoicingCouponActiveTab, addInvoicingCouponToList, clearInvoicingCouponView, } = couponView.actions;
109
115
  export default couponView.reducer;
@@ -17,18 +17,31 @@ export const getInvoicingCouponCounts = (state) => state.invoicingCouponViewStat
17
17
  * array (and the wrapping view object) keep referential identity until the
18
18
  * coupon entity slice or the list-view slice actually change.
19
19
  */
20
- export const getInvoicingCouponListView = createSelector((state) => state.invoicingCouponState, (state) => state.invoicingCouponViewState, (couponState, listViewState) => ({
21
- columns: INVOICING_COUPON_COLUMNS,
22
- coupons: listViewState.ids
20
+ export const getInvoicingCouponListView = createSelector((state) => state.invoicingCouponState, (state) => state.invoicingCouponViewState, (couponState, listViewState) => {
21
+ const { activeTab } = listViewState;
22
+ const allCoupons = listViewState.ids
23
23
  .map((id) => couponState.couponByID[id])
24
- .filter((item) => item != null),
25
- count: listViewState.counts,
26
- countsFetchState: listViewState.countsFetchState,
27
- filters: listViewState.filters,
28
- nextCursor: listViewState.nextCursor,
29
- tabIds: INVOICING_COUPON_TABS,
30
- fetchState: listViewState.fetchState,
31
- error: listViewState.error,
32
- sort: listViewState.sort,
33
- version: 1.0,
34
- }));
24
+ .filter((item) => item != null);
25
+ // The list API ignores `status`, so it returns every status; filter to the
26
+ // active tab client-side. 'all' shows everything, 'active' shows only active
27
+ // coupons, and 'inactive' shows every non-active status (undefined included).
28
+ const coupons = activeTab === 'all'
29
+ ? allCoupons
30
+ : allCoupons.filter((coupon) => activeTab === 'active'
31
+ ? coupon.status === 'active'
32
+ : coupon.status !== 'active');
33
+ return {
34
+ activeTab,
35
+ columns: INVOICING_COUPON_COLUMNS,
36
+ coupons,
37
+ count: listViewState.counts,
38
+ countsFetchState: listViewState.countsFetchState,
39
+ filters: listViewState.filters,
40
+ nextCursor: listViewState.nextCursor,
41
+ tabIds: INVOICING_COUPON_TABS,
42
+ fetchState: listViewState.fetchState,
43
+ error: listViewState.error,
44
+ sort: listViewState.sort,
45
+ version: 1.0,
46
+ };
47
+ });
@@ -6,10 +6,10 @@ import { updateInvoices } from '../../../entity/invoicing/invoice/invoiceReducer
6
6
  import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
7
7
  import { INVOICING_LIST_PAGE_SIZE, applyListSortParams, withQuery, } from '../invoicingApiHelper';
8
8
  import { fetchInvoiceList, updateInvoiceList, updateInvoiceListFailure, } from './invoiceListReducer';
9
- const buildInvoiceListQuery = (filters, cursor, sort) => {
9
+ const buildInvoiceListQuery = (filters, status, cursor, sort) => {
10
10
  const params = new URLSearchParams();
11
- if (filters.status != null && filters.status.length > 0) {
12
- params.set('status', filters.status);
11
+ if (status != null && status.length > 0) {
12
+ params.set('status', status);
13
13
  }
14
14
  if (filters.customerId != null) {
15
15
  params.set('customer_id', filters.customerId);
@@ -33,9 +33,11 @@ const buildInvoiceListQuery = (filters, cursor, sort) => {
33
33
  applyListSortParams(params, sort);
34
34
  return params;
35
35
  };
36
- export const fetchInvoiceListEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(fetchInvoiceList.match), switchMap((action) => {
36
+ export const fetchInvoiceListEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchInvoiceList.match), switchMap((action) => {
37
37
  const { filters, cursor, keepExistingListItems, sort } = action.payload;
38
- const apiUrl = withQuery(`${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0/invoices`, buildInvoiceListQuery(filters, cursor, sort));
38
+ const { activeTab } = state$.value.invoicingInvoiceListState;
39
+ const status = activeTab !== 'all' ? activeTab : undefined;
40
+ const apiUrl = withQuery(`${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0/invoices`, buildInvoiceListQuery(filters, status, cursor, sort));
39
41
  return zeniAPI.getJSON(apiUrl).pipe(switchMap((response) => {
40
42
  if (isSuccessResponse(response)) {
41
43
  const items = response.data?.items ?? [];
@@ -16,8 +16,9 @@ const shouldFetch = (fetchStateAndError, cacheOverride) => cacheOverride ||
16
16
  export const fetchInvoiceListPageEpic = (actions$, state$) => actions$.pipe(filter(fetchInvoiceListPage.match), mergeMap((action) => {
17
17
  const { cacheOverride, filters, sort } = action.payload;
18
18
  const state = state$.value.invoicingInvoiceListState;
19
+ const activeTabState = state.invoiceByTab[state.activeTab];
19
20
  const pageActions = [];
20
- if (shouldFetch({ fetchState: state.fetchState, error: state.error }, cacheOverride)) {
21
+ if (shouldFetch({ fetchState: activeTabState.fetchState, error: activeTabState.error }, cacheOverride)) {
21
22
  pageActions.push(fetchInvoiceList({ filters, sort }));
22
23
  }
23
24
  if (shouldFetch(state.countsFetchState, cacheOverride)) {
@@ -1,30 +1,34 @@
1
1
  import { createSlice } from '@reduxjs/toolkit';
2
+ import { ALL_INVOICING_INVOICE_TAB_IDS, makeInvoiceByTab, } from './invoiceListState';
2
3
  /**
3
- * Whether two invoice-list queries (filters + sort) would return the same list.
4
- * Used to invalidate the cached list when a page mounts with a different query
5
- * e.g. the customer detail page after the main Invoices page, or vice versa.
4
+ * Whether two invoice-list queries share the same base (tab-independent) query.
5
+ * The status tab is server-side per-tab, so it is excluded here when the base
6
+ * query changes (search / customer / subscription / dates / sort) every per-tab
7
+ * cache is stale and the reducer resets them all.
6
8
  */
7
9
  export const sameInvoiceListQuery = (a, b) => a.filters.customerId === b.filters.customerId &&
8
10
  a.filters.subscriptionId === b.filters.subscriptionId &&
9
- a.filters.status === b.filters.status &&
10
11
  a.filters.search === b.filters.search &&
11
12
  a.filters.dateFrom === b.filters.dateFrom &&
12
13
  a.filters.dateTo === b.filters.dateTo &&
13
14
  a.sort?.field === b.sort?.field &&
14
15
  a.sort?.dir === b.sort?.dir;
16
+ /**
17
+ * Narrow an invoice status to a status tab id when one exists. Statuses like
18
+ * `draft` / `posted` / `pending` have no dedicated tab, so a newly created
19
+ * invoice in one of those states only lands in the `all` tab.
20
+ */
21
+ const statusToTabId = (status) => ALL_INVOICING_INVOICE_TAB_IDS.includes(status)
22
+ ? status
23
+ : undefined;
15
24
  export const initialState = {
16
- fetchState: 'Not-Started',
17
- error: undefined,
18
- invoiceIds: [],
19
- nextCursor: null,
25
+ activeTab: 'all',
26
+ invoiceByTab: makeInvoiceByTab(),
20
27
  filters: {},
21
28
  counts: { all: 0 },
22
29
  countsFetchState: { fetchState: 'Not-Started', error: undefined },
23
30
  kpis: undefined,
24
31
  kpisFetchState: { fetchState: 'Not-Started', error: undefined },
25
- hasValidState() {
26
- return this.fetchState === 'Completed';
27
- },
28
32
  };
29
33
  const invoiceList = createSlice({
30
34
  name: 'invoicingInvoiceList',
@@ -32,14 +36,15 @@ const invoiceList = createSlice({
32
36
  reducers: {
33
37
  fetchInvoiceList: {
34
38
  reducer(draft, action) {
39
+ const tab = draft.invoiceByTab[draft.activeTab];
35
40
  if (!action.payload.keepExistingListItems) {
36
- draft.invoiceIds = [];
37
- draft.nextCursor = null;
41
+ tab.invoiceIds = [];
42
+ tab.nextCursor = null;
38
43
  }
39
44
  draft.filters = action.payload.filters;
40
45
  draft.sort = action.payload.sort;
41
- draft.fetchState = 'In-Progress';
42
- draft.error = undefined;
46
+ tab.fetchState = 'In-Progress';
47
+ tab.error = undefined;
43
48
  },
44
49
  prepare(payload) {
45
50
  return {
@@ -54,13 +59,11 @@ const invoiceList = createSlice({
54
59
  },
55
60
  fetchInvoiceListPage: {
56
61
  reducer(draft, action) {
57
- // A different query invalidates the cached list — reset so the page
58
- // epic's shouldFetch refetches instead of showing another view's rows
59
- // (e.g. a customer-filtered list left behind by the detail page).
62
+ // A different base query invalidates every tab's cache — reset so the
63
+ // page epic's shouldFetch refetches the active tab instead of showing
64
+ // rows fetched under a stale search/customer/subscription/dates/sort.
60
65
  if (!sameInvoiceListQuery(draft, action.payload)) {
61
- draft.invoiceIds = [];
62
- draft.nextCursor = null;
63
- draft.fetchState = 'Not-Started';
66
+ draft.invoiceByTab = makeInvoiceByTab();
64
67
  }
65
68
  draft.filters = action.payload.filters;
66
69
  draft.sort = action.payload.sort;
@@ -76,17 +79,19 @@ const invoiceList = createSlice({
76
79
  },
77
80
  },
78
81
  updateInvoiceList(draft, action) {
82
+ const tab = draft.invoiceByTab[draft.activeTab];
79
83
  const newIds = action.payload.invoices.map((invoice) => invoice.id);
80
- draft.invoiceIds = action.payload.keepExistingListItems
81
- ? [...new Set([...draft.invoiceIds, ...newIds])]
84
+ tab.invoiceIds = action.payload.keepExistingListItems
85
+ ? [...new Set([...tab.invoiceIds, ...newIds])]
82
86
  : newIds;
83
- draft.nextCursor = action.payload.nextCursor;
84
- draft.fetchState = 'Completed';
85
- draft.error = undefined;
87
+ tab.nextCursor = action.payload.nextCursor;
88
+ tab.fetchState = 'Completed';
89
+ tab.error = undefined;
86
90
  },
87
91
  updateInvoiceListFailure(draft, action) {
88
- draft.fetchState = 'Error';
89
- draft.error = action.payload;
92
+ const tab = draft.invoiceByTab[draft.activeTab];
93
+ tab.fetchState = 'Error';
94
+ tab.error = action.payload;
90
95
  },
91
96
  fetchInvoiceCounts(draft) {
92
97
  draft.countsFetchState.fetchState = 'In-Progress';
@@ -117,24 +122,45 @@ const invoiceList = createSlice({
117
122
  updateInvoiceListFilters(draft, action) {
118
123
  draft.filters = action.payload;
119
124
  },
125
+ // Select a status tab. The view dispatches the follow-up fetchInvoiceListPage
126
+ // so the page epic fetches the tab when its cache is empty and reuses it when
127
+ // already loaded.
128
+ setInvoiceActiveTab(draft, action) {
129
+ draft.activeTab = action.payload;
130
+ },
120
131
  // Reflect a newly created invoice in the cached list + tab counts so the
121
- // invoices page shows it without refetching from the server. Bumps the
122
- // `all` total and the per-status count key the tabs read (a create is
123
- // typically `draft`). KPIs are money aggregates (Amount, not a plain
124
- // increment), so they are left untouched and refetched lazily.
132
+ // invoices page shows it without refetching. Prepends the id to the `all`
133
+ // tab and its status tab (dedup via includes), and bumps the `all` total and
134
+ // the per-status count key the tabs read. KPIs are money aggregates, so they
135
+ // are left untouched and refetched lazily.
125
136
  addInvoiceToList(draft, action) {
126
137
  const { id, status } = action.payload;
127
- if (draft.invoiceIds.includes(id)) {
138
+ const allTab = draft.invoiceByTab['all'];
139
+ if (allTab.invoiceIds.includes(id)) {
128
140
  return;
129
141
  }
130
- draft.invoiceIds = [id, ...draft.invoiceIds];
142
+ allTab.invoiceIds = [id, ...allTab.invoiceIds];
143
+ const statusTab = statusToTabId(status);
144
+ if (statusTab != null) {
145
+ const tab = draft.invoiceByTab[statusTab];
146
+ if (!tab.invoiceIds.includes(id)) {
147
+ tab.invoiceIds = [id, ...tab.invoiceIds];
148
+ }
149
+ }
131
150
  draft.counts.all += 1;
132
151
  draft.counts[status] = (draft.counts[status] ?? 0) + 1;
133
152
  },
134
153
  clearInvoiceList(draft) {
135
- Object.assign(draft, initialState);
154
+ draft.activeTab = 'all';
155
+ draft.invoiceByTab = makeInvoiceByTab();
156
+ draft.filters = {};
157
+ draft.sort = undefined;
158
+ draft.counts = { all: 0 };
159
+ draft.countsFetchState = { fetchState: 'Not-Started', error: undefined };
160
+ draft.kpis = undefined;
161
+ draft.kpisFetchState = { fetchState: 'Not-Started', error: undefined };
136
162
  },
137
163
  },
138
164
  });
139
- export const { fetchInvoiceList, fetchInvoiceListPage, updateInvoiceList, updateInvoiceListFailure, fetchInvoiceCounts, updateInvoiceCounts, updateInvoiceCountsFailure, fetchInvoiceKPIs, updateInvoiceKPIs, updateInvoiceKPIsFailure, updateInvoiceListFilters, addInvoiceToList, clearInvoiceList, } = invoiceList.actions;
165
+ export const { fetchInvoiceList, fetchInvoiceListPage, updateInvoiceList, updateInvoiceListFailure, fetchInvoiceCounts, updateInvoiceCounts, updateInvoiceCountsFailure, fetchInvoiceKPIs, updateInvoiceKPIs, updateInvoiceKPIsFailure, updateInvoiceListFilters, setInvoiceActiveTab, addInvoiceToList, clearInvoiceList, } = invoiceList.actions;
140
166
  export default invoiceList.reducer;
@@ -6,18 +6,22 @@ import { INVOICING_INVOICE_TABS, } from './invoiceListState';
6
6
  * array (and the wrapping view object) keep referential identity until the
7
7
  * invoice entity slice or the list-view slice actually change.
8
8
  */
9
- export const getInvoiceListView = createSelector((state) => state.invoicingInvoiceState, (state) => state.invoicingInvoiceListState, (invoiceState, listViewState) => ({
10
- invoices: listViewState.invoiceIds
11
- .map((id) => invoiceState.invoiceByID[id])
12
- .filter((item) => item != null),
13
- counts: listViewState.counts,
14
- countsFetchState: listViewState.countsFetchState,
15
- filters: listViewState.filters,
16
- kpis: listViewState.kpis,
17
- kpisFetchState: listViewState.kpisFetchState,
18
- nextCursor: listViewState.nextCursor,
19
- tabIds: INVOICING_INVOICE_TABS,
20
- fetchState: listViewState.fetchState,
21
- error: listViewState.error,
22
- version: 1.0,
23
- }));
9
+ export const getInvoiceListView = createSelector((state) => state.invoicingInvoiceState, (state) => state.invoicingInvoiceListState, (invoiceState, listViewState) => {
10
+ const activeTabState = listViewState.invoiceByTab[listViewState.activeTab];
11
+ return {
12
+ activeTab: listViewState.activeTab,
13
+ invoices: activeTabState.invoiceIds
14
+ .map((id) => invoiceState.invoiceByID[id])
15
+ .filter((item) => item != null),
16
+ counts: listViewState.counts,
17
+ countsFetchState: listViewState.countsFetchState,
18
+ filters: listViewState.filters,
19
+ kpis: listViewState.kpis,
20
+ kpisFetchState: listViewState.kpisFetchState,
21
+ nextCursor: activeTabState.nextCursor,
22
+ tabIds: INVOICING_INVOICE_TABS,
23
+ fetchState: activeTabState.fetchState,
24
+ error: activeTabState.error,
25
+ version: 1.0,
26
+ };
27
+ });
@@ -17,3 +17,13 @@ export const toInvoicingInvoiceTabId = (v) => stringToUnion(v, ALL_INVOICING_INV
17
17
  export const INVOICING_INVOICE_TABS = [
18
18
  ...ALL_INVOICING_INVOICE_TAB_IDS,
19
19
  ];
20
+ export const makeInvoiceTabState = () => ({
21
+ invoiceIds: [],
22
+ nextCursor: null,
23
+ fetchState: 'Not-Started',
24
+ error: undefined,
25
+ });
26
+ export const makeInvoiceByTab = () => ALL_INVOICING_INVOICE_TAB_IDS.reduce((acc, tabId) => {
27
+ acc[tabId] = makeInvoiceTabState();
28
+ return acc;
29
+ }, {});
@@ -6,9 +6,6 @@ import { INVOICING_LIST_PAGE_SIZE, applyListSortParams, withQuery, } from '../..
6
6
  import { fetchInvoicingCreditNoteList, updateInvoicingCreditNoteList, updateInvoicingCreditNoteListFailure, } from '../invoicingCreditNoteListViewReducer';
7
7
  const buildQuery = (filters, cursor, sort) => {
8
8
  const params = new URLSearchParams();
9
- if (filters.status != null && filters.status.length > 0) {
10
- params.set('status', filters.status);
11
- }
12
9
  if (filters.customerId != null) {
13
10
  params.set('customer_id', filters.customerId);
14
11
  }
@@ -2,6 +2,7 @@ import { createSlice } from '@reduxjs/toolkit';
2
2
  export const initialState = {
3
3
  fetchState: 'Not-Started',
4
4
  error: undefined,
5
+ activeTab: 'all',
5
6
  ids: [],
6
7
  nextCursor: null,
7
8
  filters: {},
@@ -80,10 +81,15 @@ const invoicingCreditNoteListView = createSlice({
80
81
  updateInvoicingCreditNoteFilters(draft, action) {
81
82
  draft.filters = action.payload;
82
83
  },
84
+ // Select a status tab. The list API ignores `status` (returns all statuses),
85
+ // so the selector filters rows to this tab client-side — no refetch needed.
86
+ setInvoicingCreditNoteActiveTab(draft, action) {
87
+ draft.activeTab = action.payload;
88
+ },
83
89
  clearInvoicingCreditNoteListView(draft) {
84
90
  Object.assign(draft, initialState);
85
91
  },
86
92
  },
87
93
  });
88
- export const { fetchInvoicingCreditNoteList, fetchInvoicingCreditNoteListPage, updateInvoicingCreditNoteList, updateInvoicingCreditNoteListFailure, fetchInvoicingCreditNoteCounts, updateInvoicingCreditNoteCounts, updateInvoicingCreditNoteCountsFailure, updateInvoicingCreditNoteFilters, clearInvoicingCreditNoteListView, } = invoicingCreditNoteListView.actions;
94
+ export const { fetchInvoicingCreditNoteList, fetchInvoicingCreditNoteListPage, updateInvoicingCreditNoteList, updateInvoicingCreditNoteListFailure, fetchInvoicingCreditNoteCounts, updateInvoicingCreditNoteCounts, updateInvoicingCreditNoteCountsFailure, updateInvoicingCreditNoteFilters, setInvoicingCreditNoteActiveTab, clearInvoicingCreditNoteListView, } = invoicingCreditNoteListView.actions;
89
95
  export default invoicingCreditNoteListView.reducer;
@@ -6,16 +6,26 @@ import { INVOICING_CREDIT_NOTE_COLUMNS, INVOICING_CREDIT_NOTE_TABS, } from './in
6
6
  * object) keep referential identity until the credit-note entity slice or the
7
7
  * list-view slice actually change.
8
8
  */
9
- export const getInvoicingCreditNoteListView = createSelector((state) => state.invoicingCreditNoteState, (state) => state.invoicingCreditNoteListViewState, (creditNoteState, listViewState) => ({
10
- columns: INVOICING_CREDIT_NOTE_COLUMNS,
11
- creditNotes: getInvoicingCreditNotesByIds(creditNoteState, listViewState.ids),
12
- count: listViewState.counts,
13
- countsFetchState: listViewState.countsFetchState,
14
- filters: listViewState.filters,
15
- nextCursor: listViewState.nextCursor,
16
- tabIds: INVOICING_CREDIT_NOTE_TABS,
17
- fetchState: listViewState.fetchState,
18
- error: listViewState.error,
19
- sort: listViewState.sort,
20
- version: 1.0,
21
- }));
9
+ export const getInvoicingCreditNoteListView = createSelector((state) => state.invoicingCreditNoteState, (state) => state.invoicingCreditNoteListViewState, (creditNoteState, listViewState) => {
10
+ const { activeTab } = listViewState;
11
+ const allCreditNotes = getInvoicingCreditNotesByIds(creditNoteState, listViewState.ids);
12
+ // The list API ignores `status`, so it returns every status; filter to the
13
+ // active tab client-side ('all' shows everything).
14
+ const creditNotes = activeTab === 'all'
15
+ ? allCreditNotes
16
+ : allCreditNotes.filter((creditNote) => creditNote.status === activeTab);
17
+ return {
18
+ activeTab,
19
+ columns: INVOICING_CREDIT_NOTE_COLUMNS,
20
+ creditNotes,
21
+ count: listViewState.counts,
22
+ countsFetchState: listViewState.countsFetchState,
23
+ filters: listViewState.filters,
24
+ nextCursor: listViewState.nextCursor,
25
+ tabIds: INVOICING_CREDIT_NOTE_TABS,
26
+ fetchState: listViewState.fetchState,
27
+ error: listViewState.error,
28
+ sort: listViewState.sort,
29
+ version: 1.0,
30
+ };
31
+ });
@@ -20,6 +20,7 @@ export const fetchInvoicingCustomerDetailPageEpic = (actions$, state$) => action
20
20
  const { cacheOverride, id } = action.payload;
21
21
  const customerDetail = state$.value.invoicingCustomerDetailViewState.detailById[id];
22
22
  const invoiceListState = state$.value.invoicingInvoiceListState;
23
+ const invoiceListTabState = invoiceListState.invoiceByTab[invoiceListState.activeTab];
23
24
  const settingsState = state$.value.invoicingSettingsViewState;
24
25
  const pageActions = [];
25
26
  if (shouldFetch({
@@ -33,8 +34,8 @@ export const fetchInvoicingCustomerDetailPageEpic = (actions$, state$) => action
33
34
  const invoiceListIsForCustomer = invoiceListState.filters.customerId === id;
34
35
  if (!invoiceListIsForCustomer ||
35
36
  shouldFetch({
36
- fetchState: invoiceListState.fetchState,
37
- error: invoiceListState.error,
37
+ fetchState: invoiceListTabState.fetchState,
38
+ error: invoiceListTabState.error,
38
39
  }, cacheOverride)) {
39
40
  pageActions.push(fetchInvoiceList({ filters: { customerId: id } }));
40
41
  }
@@ -10,7 +10,7 @@ export const getInvoicingCustomerDetail = (state, invoicingCustomerID) => {
10
10
  const settings = getInvoicingSettings(state);
11
11
  return {
12
12
  invoicingCustomer: getInvoicingCustomerById(invoicingCustomerState, invoicingCustomerID),
13
- invoices: getInvoicesByIds(state.invoicingInvoiceState, state.invoicingInvoiceListState.invoiceIds),
13
+ invoices: getInvoicesByIds(state.invoicingInvoiceState, state.invoicingInvoiceListState.invoiceByTab[state.invoicingInvoiceListState.activeTab].invoiceIds),
14
14
  setupIntent: getInvoicingSetupIntent(state),
15
15
  setupIntentFetchState: getInvoicingSetupIntentFetchState(state),
16
16
  plaidLinkToken: getInvoicingPlaidLinkToken(state),
@@ -11,9 +11,6 @@ const buildQuery = (filters, cursor, sort) => {
11
11
  if (filters.search != null && filters.search.length > 0) {
12
12
  params.set('search', filters.search);
13
13
  }
14
- if (filters.status != null && filters.status.length > 0) {
15
- params.set('status', filters.status);
16
- }
17
14
  params.set('limit', String(INVOICING_LIST_PAGE_SIZE));
18
15
  if (cursor != null) {
19
16
  params.set('cursor', cursor);
@@ -2,6 +2,7 @@ import { createSlice } from '@reduxjs/toolkit';
2
2
  export const initialState = {
3
3
  fetchState: 'Not-Started',
4
4
  error: undefined,
5
+ activeTab: 'all',
5
6
  ids: [],
6
7
  nextCursor: null,
7
8
  filters: {},
@@ -80,6 +81,11 @@ const invoicingCustomerListView = createSlice({
80
81
  updateInvoicingCustomerFilters(draft, action) {
81
82
  draft.filters = action.payload;
82
83
  },
84
+ // Select a status tab. The list API ignores `status` (returns all statuses),
85
+ // so the selector filters rows to this tab client-side — no refetch needed.
86
+ setInvoicingCustomerActiveTab(draft, action) {
87
+ draft.activeTab = action.payload;
88
+ },
83
89
  // Reflect a newly created customer in the cached list + tab counts so the
84
90
  // customer page shows the new row without refetching from the server. The
85
91
  // per-status count key mirrors the customer `status` value the counts map
@@ -101,5 +107,5 @@ const invoicingCustomerListView = createSlice({
101
107
  },
102
108
  },
103
109
  });
104
- export const { fetchInvoicingCustomerList, fetchInvoicingCustomerListPage, updateInvoicingCustomerList, updateInvoicingCustomerListFailure, fetchInvoicingCustomerCounts, updateInvoicingCustomerCounts, updateInvoicingCustomerCountsFailure, updateInvoicingCustomerFilters, addInvoicingCustomerToList, clearInvoicingCustomerListView, } = invoicingCustomerListView.actions;
110
+ export const { fetchInvoicingCustomerList, fetchInvoicingCustomerListPage, updateInvoicingCustomerList, updateInvoicingCustomerListFailure, fetchInvoicingCustomerCounts, updateInvoicingCustomerCounts, updateInvoicingCustomerCountsFailure, updateInvoicingCustomerFilters, setInvoicingCustomerActiveTab, addInvoicingCustomerToList, clearInvoicingCustomerListView, } = invoicingCustomerListView.actions;
105
111
  export default invoicingCustomerListView.reducer;
@@ -7,15 +7,28 @@ import { INVOICING_CUSTOMER_COLUMNS, INVOICING_CUSTOMER_TABS, } from './invoicin
7
7
  * slice actually change. Without this, the connected list page re-rendered on
8
8
  * every unrelated redux action because a fresh array was built each call.
9
9
  */
10
- export const getInvoicingCustomerListView = createSelector((state) => state.invoicingCustomerState, (state) => state.invoicingCustomerListViewState, (customerState, listViewState) => ({
11
- columns: INVOICING_CUSTOMER_COLUMNS,
12
- customers: getInvoicingCustomersByIds(customerState, listViewState.ids),
13
- fetchState: listViewState.fetchState,
14
- error: listViewState.error,
15
- nextCursor: listViewState.nextCursor,
16
- filters: listViewState.filters,
17
- count: listViewState.counts,
18
- countsFetchState: listViewState.countsFetchState,
19
- tabIds: INVOICING_CUSTOMER_TABS,
20
- sort: listViewState.sort,
21
- }));
10
+ export const getInvoicingCustomerListView = createSelector((state) => state.invoicingCustomerState, (state) => state.invoicingCustomerListViewState, (customerState, listViewState) => {
11
+ const { activeTab } = listViewState;
12
+ const allCustomers = getInvoicingCustomersByIds(customerState, listViewState.ids);
13
+ // The list API ignores `status`, so it returns every status; filter to the
14
+ // active tab client-side ('all' shows everything, 'at_risk' keys off the
15
+ // `isAtRisk` flag, the rest match the customer `status`).
16
+ const customers = activeTab === 'all'
17
+ ? allCustomers
18
+ : activeTab === 'at_risk'
19
+ ? allCustomers.filter((customer) => customer.isAtRisk === true)
20
+ : allCustomers.filter((customer) => customer.status === activeTab);
21
+ return {
22
+ activeTab,
23
+ columns: INVOICING_CUSTOMER_COLUMNS,
24
+ customers,
25
+ fetchState: listViewState.fetchState,
26
+ error: listViewState.error,
27
+ nextCursor: listViewState.nextCursor,
28
+ filters: listViewState.filters,
29
+ count: listViewState.counts,
30
+ countsFetchState: listViewState.countsFetchState,
31
+ tabIds: INVOICING_CUSTOMER_TABS,
32
+ sort: listViewState.sort,
33
+ };
34
+ });
@@ -6,9 +6,6 @@ import { INVOICING_LIST_PAGE_SIZE, applyListSortParams, withQuery, } from '../..
6
6
  import { fetchInvoicingDunningCaseList, updateInvoicingDunningCaseList, updateInvoicingDunningCaseListFailure, } from '../invoicingDunningCaseListViewReducer';
7
7
  const buildQuery = (filters, cursor, sort) => {
8
8
  const params = new URLSearchParams();
9
- if (filters.status != null && filters.status.length > 0) {
10
- params.set('status', filters.status);
11
- }
12
9
  if (filters.search != null && filters.search.length > 0) {
13
10
  params.set('search', filters.search);
14
11
  }