@zeniai/client-epic-state 5.1.69 → 5.1.70-betaRD1

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 (129) hide show
  1. package/lib/entity/jeSchedules/jeSchedulesPayload.d.ts +2 -0
  2. package/lib/entity/jeSchedules/jeSchedulesPayload.js +2 -0
  3. package/lib/entity/jeSchedules/jeSchedulesSelector.d.ts +4 -0
  4. package/lib/entity/jeSchedules/jeSchedulesSelector.js +11 -1
  5. package/lib/entity/jeSchedules/jeSchedulesState.d.ts +2 -0
  6. package/lib/entity/transaction/payloadTypes/scheduleTransactionPayload.d.ts +2 -0
  7. package/lib/entity/transaction/payloadTypes/scheduleTransactionPayload.js +2 -0
  8. package/lib/entity/transaction/stateTypes/scheduleTransaction.d.ts +2 -0
  9. package/lib/epic.d.ts +5 -1
  10. package/lib/epic.js +5 -1
  11. package/lib/esm/entity/jeSchedules/jeSchedulesPayload.js +2 -0
  12. package/lib/esm/entity/jeSchedules/jeSchedulesSelector.js +11 -1
  13. package/lib/esm/entity/transaction/payloadTypes/scheduleTransactionPayload.js +2 -0
  14. package/lib/esm/epic.js +5 -1
  15. package/lib/esm/index.js +14 -11
  16. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulesEpic.js +15 -2
  17. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/newSchedule/initializeNewScheduleEpic.js +21 -0
  18. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/newSchedule/saveNewScheduleEpic.js +110 -0
  19. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/newSchedule/searchTransactionsForNewScheduleEpic.js +73 -0
  20. package/lib/esm/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.js +22 -0
  21. package/lib/esm/view/expenseAutomationView/helpers/newScheduleLocalDataHelper.js +140 -0
  22. package/lib/esm/view/expenseAutomationView/reducers/jeSchedulesViewReducer.js +126 -6
  23. package/lib/esm/view/expenseAutomationView/selectorTypes/jeNewScheduleViewSelectorTypes.js +1 -0
  24. package/lib/esm/view/expenseAutomationView/selectors/jeNewScheduleViewSelector.js +70 -0
  25. package/lib/esm/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +78 -11
  26. package/lib/esm/view/expenseAutomationView/types/jeSchedulesViewState.js +3 -6
  27. package/lib/esm/view/invoicing/couponView/couponViewEpics.js +0 -3
  28. package/lib/esm/view/invoicing/couponView/couponViewReducer.js +7 -1
  29. package/lib/esm/view/invoicing/couponView/couponViewSelector.js +27 -14
  30. package/lib/esm/view/invoicing/invoiceList/fetchInvoiceListEpic.js +7 -5
  31. package/lib/esm/view/invoicing/invoiceList/fetchInvoiceListPageEpic.js +2 -1
  32. package/lib/esm/view/invoicing/invoiceList/invoiceListReducer.js +62 -36
  33. package/lib/esm/view/invoicing/invoiceList/invoiceListSelector.js +19 -15
  34. package/lib/esm/view/invoicing/invoiceList/invoiceListState.js +10 -0
  35. package/lib/esm/view/invoicing/invoicingCreditNoteListView/epics/fetchInvoicingCreditNoteListEpic.js +0 -3
  36. package/lib/esm/view/invoicing/invoicingCreditNoteListView/invoicingCreditNoteListViewReducer.js +7 -1
  37. package/lib/esm/view/invoicing/invoicingCreditNoteListView/invoicingCreditNoteListViewSelector.js +23 -13
  38. package/lib/esm/view/invoicing/invoicingCustomerDetailView/fetchInvoicingCustomerDetailPageEpic.js +3 -2
  39. package/lib/esm/view/invoicing/invoicingCustomerDetailView/invoicingCustomerDetailViewSelector.js +1 -1
  40. package/lib/esm/view/invoicing/invoicingCustomerListView/epics/fetchInvoicingCustomerListEpic.js +0 -3
  41. package/lib/esm/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewReducer.js +7 -1
  42. package/lib/esm/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewSelector.js +25 -12
  43. package/lib/esm/view/invoicing/invoicingDunningCaseListView/epics/fetchInvoicingDunningCaseListEpic.js +0 -3
  44. package/lib/esm/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewReducer.js +7 -1
  45. package/lib/esm/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewSelector.js +23 -13
  46. package/lib/esm/view/invoicing/invoicingSubscriptionListView/epics/fetchInvoicingSubscriptionListEpic.js +0 -3
  47. package/lib/esm/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewReducer.js +7 -1
  48. package/lib/esm/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewSelector.js +22 -12
  49. package/lib/esm/view/invoicing/invoicingTransactionListView/epics/fetchInvoicingTransactionListEpic.js +7 -5
  50. package/lib/esm/view/invoicing/invoicingTransactionListView/epics/fetchInvoicingTransactionListPageEpic.js +2 -1
  51. package/lib/esm/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewReducer.js +56 -25
  52. package/lib/esm/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewSelector.js +15 -11
  53. package/lib/esm/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewState.js +10 -0
  54. package/lib/index.d.ts +16 -13
  55. package/lib/index.js +73 -48
  56. package/lib/view/expenseAutomationView/epics/jeSchedule/fetchJeSchedulesEpic.js +14 -1
  57. package/lib/view/expenseAutomationView/epics/jeSchedule/newSchedule/initializeNewScheduleEpic.d.ts +8 -0
  58. package/lib/view/expenseAutomationView/epics/jeSchedule/newSchedule/initializeNewScheduleEpic.js +25 -0
  59. package/lib/view/expenseAutomationView/epics/jeSchedule/newSchedule/saveNewScheduleEpic.d.ts +45 -0
  60. package/lib/view/expenseAutomationView/epics/jeSchedule/newSchedule/saveNewScheduleEpic.js +114 -0
  61. package/lib/view/expenseAutomationView/epics/jeSchedule/newSchedule/searchTransactionsForNewScheduleEpic.d.ts +8 -0
  62. package/lib/view/expenseAutomationView/epics/jeSchedule/newSchedule/searchTransactionsForNewScheduleEpic.js +77 -0
  63. package/lib/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.d.ts +6 -0
  64. package/lib/view/expenseAutomationView/epics/jeSchedule/switchJESchedulesTabEpic.js +26 -0
  65. package/lib/view/expenseAutomationView/helpers/newScheduleLocalDataHelper.d.ts +36 -0
  66. package/lib/view/expenseAutomationView/helpers/newScheduleLocalDataHelper.js +145 -0
  67. package/lib/view/expenseAutomationView/payload/jeSchedulesPayload.d.ts +1 -0
  68. package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.d.ts +38 -8
  69. package/lib/view/expenseAutomationView/reducers/jeSchedulesViewReducer.js +128 -7
  70. package/lib/view/expenseAutomationView/selectorTypes/jeNewScheduleViewSelectorTypes.d.ts +25 -0
  71. package/lib/view/expenseAutomationView/selectorTypes/jeNewScheduleViewSelectorTypes.js +2 -0
  72. package/lib/view/expenseAutomationView/selectorTypes/jeSchedulesSelectorTypes.d.ts +29 -4
  73. package/lib/view/expenseAutomationView/selectors/jeNewScheduleViewSelector.d.ts +10 -0
  74. package/lib/view/expenseAutomationView/selectors/jeNewScheduleViewSelector.js +75 -0
  75. package/lib/view/expenseAutomationView/selectors/jeSchedulesViewSelector.d.ts +1 -0
  76. package/lib/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +80 -11
  77. package/lib/view/expenseAutomationView/types/jeSchedulesViewState.d.ts +52 -6
  78. package/lib/view/expenseAutomationView/types/jeSchedulesViewState.js +5 -8
  79. package/lib/view/invoicing/couponView/couponViewEpics.js +0 -3
  80. package/lib/view/invoicing/couponView/couponViewReducer.d.ts +1 -1
  81. package/lib/view/invoicing/couponView/couponViewReducer.js +8 -2
  82. package/lib/view/invoicing/couponView/couponViewSelector.d.ts +1 -0
  83. package/lib/view/invoicing/couponView/couponViewSelector.js +27 -14
  84. package/lib/view/invoicing/couponView/couponViewState.d.ts +2 -1
  85. package/lib/view/invoicing/invoiceList/fetchInvoiceListEpic.d.ts +1 -1
  86. package/lib/view/invoicing/invoiceList/fetchInvoiceListEpic.js +7 -5
  87. package/lib/view/invoicing/invoiceList/fetchInvoiceListPageEpic.js +2 -1
  88. package/lib/view/invoicing/invoiceList/invoiceListReducer.d.ts +5 -4
  89. package/lib/view/invoicing/invoiceList/invoiceListReducer.js +63 -37
  90. package/lib/view/invoicing/invoiceList/invoiceListSelector.d.ts +1 -0
  91. package/lib/view/invoicing/invoiceList/invoiceListSelector.js +19 -15
  92. package/lib/view/invoicing/invoiceList/invoiceListState.d.ts +20 -7
  93. package/lib/view/invoicing/invoiceList/invoiceListState.js +13 -1
  94. package/lib/view/invoicing/invoicingCreditNoteListView/epics/fetchInvoicingCreditNoteListEpic.js +0 -3
  95. package/lib/view/invoicing/invoicingCreditNoteListView/invoicingCreditNoteListViewReducer.d.ts +1 -1
  96. package/lib/view/invoicing/invoicingCreditNoteListView/invoicingCreditNoteListViewReducer.js +8 -2
  97. package/lib/view/invoicing/invoicingCreditNoteListView/invoicingCreditNoteListViewSelector.d.ts +1 -0
  98. package/lib/view/invoicing/invoicingCreditNoteListView/invoicingCreditNoteListViewSelector.js +23 -13
  99. package/lib/view/invoicing/invoicingCreditNoteListView/invoicingCreditNoteListViewState.d.ts +2 -1
  100. package/lib/view/invoicing/invoicingCustomerDetailView/fetchInvoicingCustomerDetailPageEpic.js +3 -2
  101. package/lib/view/invoicing/invoicingCustomerDetailView/invoicingCustomerDetailViewSelector.js +1 -1
  102. package/lib/view/invoicing/invoicingCustomerListView/epics/fetchInvoicingCustomerListEpic.js +0 -3
  103. package/lib/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewReducer.d.ts +1 -1
  104. package/lib/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewReducer.js +8 -2
  105. package/lib/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewSelector.d.ts +1 -0
  106. package/lib/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewSelector.js +25 -12
  107. package/lib/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewState.d.ts +2 -1
  108. package/lib/view/invoicing/invoicingDunningCaseListView/epics/fetchInvoicingDunningCaseListEpic.js +0 -3
  109. package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewReducer.d.ts +1 -1
  110. package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewReducer.js +8 -2
  111. package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewSelector.d.ts +1 -0
  112. package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewSelector.js +23 -13
  113. package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewState.d.ts +2 -1
  114. package/lib/view/invoicing/invoicingSubscriptionListView/epics/fetchInvoicingSubscriptionListEpic.js +0 -3
  115. package/lib/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewReducer.d.ts +1 -1
  116. package/lib/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewReducer.js +8 -2
  117. package/lib/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewSelector.d.ts +1 -0
  118. package/lib/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewSelector.js +22 -12
  119. package/lib/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewState.d.ts +3 -1
  120. package/lib/view/invoicing/invoicingTransactionListView/epics/fetchInvoicingTransactionListEpic.d.ts +1 -1
  121. package/lib/view/invoicing/invoicingTransactionListView/epics/fetchInvoicingTransactionListEpic.js +7 -5
  122. package/lib/view/invoicing/invoicingTransactionListView/epics/fetchInvoicingTransactionListPageEpic.js +2 -1
  123. package/lib/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewReducer.d.ts +1 -1
  124. package/lib/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewReducer.js +57 -26
  125. package/lib/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewSelector.d.ts +1 -0
  126. package/lib/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewSelector.js +15 -11
  127. package/lib/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewState.d.ts +18 -4
  128. package/lib/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewState.js +13 -1
  129. package/package.json +1 -1
@@ -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
  }
@@ -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 invoicingDunningCaseListView = createSlice({
80
81
  updateInvoicingDunningCaseFilters(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
+ setInvoicingDunningCaseActiveTab(draft, action) {
87
+ draft.activeTab = action.payload;
88
+ },
83
89
  clearInvoicingDunningCaseListView(draft) {
84
90
  Object.assign(draft, initialState);
85
91
  },
86
92
  },
87
93
  });
88
- export const { fetchInvoicingDunningCaseList, fetchInvoicingDunningCaseListPage, updateInvoicingDunningCaseList, updateInvoicingDunningCaseListFailure, fetchInvoicingDunningCaseCounts, updateInvoicingDunningCaseCounts, updateInvoicingDunningCaseCountsFailure, updateInvoicingDunningCaseFilters, clearInvoicingDunningCaseListView, } = invoicingDunningCaseListView.actions;
94
+ export const { fetchInvoicingDunningCaseList, fetchInvoicingDunningCaseListPage, updateInvoicingDunningCaseList, updateInvoicingDunningCaseListFailure, fetchInvoicingDunningCaseCounts, updateInvoicingDunningCaseCounts, updateInvoicingDunningCaseCountsFailure, updateInvoicingDunningCaseFilters, setInvoicingDunningCaseActiveTab, clearInvoicingDunningCaseListView, } = invoicingDunningCaseListView.actions;
89
95
  export default invoicingDunningCaseListView.reducer;
@@ -6,16 +6,26 @@ import { INVOICING_DUNNING_CASE_COLUMNS, INVOICING_DUNNING_CASE_TABS, } from './
6
6
  * object) keep referential identity until the dunning-case entity slice or the
7
7
  * list-view slice actually change.
8
8
  */
9
- export const getInvoicingDunningCaseListView = createSelector((state) => state.invoicingDunningCaseState, (state) => state.invoicingDunningCaseListViewState, (dunningCaseState, listViewState) => ({
10
- columns: INVOICING_DUNNING_CASE_COLUMNS,
11
- dunningCases: getInvoicingDunningCasesByIds(dunningCaseState, listViewState.ids),
12
- count: listViewState.counts,
13
- countsFetchState: listViewState.countsFetchState,
14
- filters: listViewState.filters,
15
- nextCursor: listViewState.nextCursor,
16
- fetchState: listViewState.fetchState,
17
- error: listViewState.error,
18
- tabIds: INVOICING_DUNNING_CASE_TABS,
19
- sort: listViewState.sort,
20
- version: 1.0,
21
- }));
9
+ export const getInvoicingDunningCaseListView = createSelector((state) => state.invoicingDunningCaseState, (state) => state.invoicingDunningCaseListViewState, (dunningCaseState, listViewState) => {
10
+ const { activeTab } = listViewState;
11
+ const allDunningCases = getInvoicingDunningCasesByIds(dunningCaseState, 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 dunningCases = activeTab === 'all'
15
+ ? allDunningCases
16
+ : allDunningCases.filter((dunningCase) => dunningCase.status === activeTab);
17
+ return {
18
+ activeTab,
19
+ columns: INVOICING_DUNNING_CASE_COLUMNS,
20
+ dunningCases,
21
+ count: listViewState.counts,
22
+ countsFetchState: listViewState.countsFetchState,
23
+ filters: listViewState.filters,
24
+ nextCursor: listViewState.nextCursor,
25
+ fetchState: listViewState.fetchState,
26
+ error: listViewState.error,
27
+ tabIds: INVOICING_DUNNING_CASE_TABS,
28
+ sort: listViewState.sort,
29
+ version: 1.0,
30
+ };
31
+ });
@@ -8,9 +8,6 @@ import { INVOICING_LIST_PAGE_SIZE, applyListSortParams, withQuery, } from '../..
8
8
  import { fetchInvoicingSubscriptionList, updateInvoicingSubscriptionList, updateInvoicingSubscriptionListFailure, } from '../invoicingSubscriptionListViewReducer';
9
9
  const buildQuery = (filters, cursor, sort) => {
10
10
  const params = new URLSearchParams();
11
- if (filters.status != null && filters.status.length > 0) {
12
- params.set('status', filters.status);
13
- }
14
11
  if (filters.customerId != null) {
15
12
  params.set('customer_id', filters.customerId);
16
13
  }
@@ -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 invoicingSubscriptionListView = createSlice({
80
81
  updateInvoicingSubscriptionFilters(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
+ setInvoicingSubscriptionActiveTab(draft, action) {
87
+ draft.activeTab = action.payload;
88
+ },
83
89
  // Reflect a newly created subscription in the cached list + tab counts so the
84
90
  // subscription page shows it without refetching from the server. The status
85
91
  // doubles as the per-tab count key (tab ids mirror InvoicingSubscriptionStatus).
@@ -99,5 +105,5 @@ const invoicingSubscriptionListView = createSlice({
99
105
  },
100
106
  },
101
107
  });
102
- export const { fetchInvoicingSubscriptionList, fetchInvoicingSubscriptionListPage, updateInvoicingSubscriptionList, updateInvoicingSubscriptionListFailure, fetchInvoicingSubscriptionCounts, updateInvoicingSubscriptionCounts, updateInvoicingSubscriptionCountsFailure, updateInvoicingSubscriptionFilters, addInvoicingSubscriptionToList, clearInvoicingSubscriptionListView, } = invoicingSubscriptionListView.actions;
108
+ export const { fetchInvoicingSubscriptionList, fetchInvoicingSubscriptionListPage, updateInvoicingSubscriptionList, updateInvoicingSubscriptionListFailure, fetchInvoicingSubscriptionCounts, updateInvoicingSubscriptionCounts, updateInvoicingSubscriptionCountsFailure, updateInvoicingSubscriptionFilters, setInvoicingSubscriptionActiveTab, addInvoicingSubscriptionToList, clearInvoicingSubscriptionListView, } = invoicingSubscriptionListView.actions;
103
109
  export default invoicingSubscriptionListView.reducer;
@@ -8,15 +8,25 @@ import { INVOICING_SUBSCRIPTION_COLUMNS, INVOICING_SUBSCRIPTION_TABS, } from './
8
8
  * re-rendered on every unrelated redux action because a fresh array was built
9
9
  * each call.
10
10
  */
11
- export const getInvoicingSubscriptionListView = createSelector((state) => state.invoicingSubscriptionState, (state) => state.invoicingSubscriptionListViewState, (subscriptionState, listViewState) => ({
12
- columns: INVOICING_SUBSCRIPTION_COLUMNS,
13
- subscriptions: getInvoicingSubscriptionsByIds(subscriptionState, listViewState.ids),
14
- fetchState: listViewState.fetchState,
15
- error: listViewState.error,
16
- nextCursor: listViewState.nextCursor,
17
- filters: listViewState.filters,
18
- count: listViewState.counts,
19
- countsFetchState: listViewState.countsFetchState,
20
- tabIds: INVOICING_SUBSCRIPTION_TABS,
21
- sort: listViewState.sort,
22
- }));
11
+ export const getInvoicingSubscriptionListView = createSelector((state) => state.invoicingSubscriptionState, (state) => state.invoicingSubscriptionListViewState, (subscriptionState, listViewState) => {
12
+ const { activeTab } = listViewState;
13
+ const allSubscriptions = getInvoicingSubscriptionsByIds(subscriptionState, listViewState.ids);
14
+ // The list API ignores `status`, so it returns every status; filter to the
15
+ // active tab client-side ('all' shows everything).
16
+ const subscriptions = activeTab === 'all'
17
+ ? allSubscriptions
18
+ : allSubscriptions.filter((subscription) => subscription.status === activeTab);
19
+ return {
20
+ activeTab,
21
+ columns: INVOICING_SUBSCRIPTION_COLUMNS,
22
+ subscriptions,
23
+ fetchState: listViewState.fetchState,
24
+ error: listViewState.error,
25
+ nextCursor: listViewState.nextCursor,
26
+ filters: listViewState.filters,
27
+ count: listViewState.counts,
28
+ countsFetchState: listViewState.countsFetchState,
29
+ tabIds: INVOICING_SUBSCRIPTION_TABS,
30
+ sort: listViewState.sort,
31
+ };
32
+ });