@zeniai/client-epic-state 5.1.68-betaDI2 → 5.1.69-betaAK0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/esm/index.js +9 -9
- package/lib/esm/view/invoicing/couponView/couponViewEpics.js +0 -3
- package/lib/esm/view/invoicing/couponView/couponViewReducer.js +7 -1
- package/lib/esm/view/invoicing/couponView/couponViewSelector.js +27 -14
- package/lib/esm/view/invoicing/invoiceList/fetchInvoiceListEpic.js +7 -5
- package/lib/esm/view/invoicing/invoiceList/fetchInvoiceListPageEpic.js +2 -1
- package/lib/esm/view/invoicing/invoiceList/invoiceListReducer.js +62 -36
- package/lib/esm/view/invoicing/invoiceList/invoiceListSelector.js +19 -15
- package/lib/esm/view/invoicing/invoiceList/invoiceListState.js +10 -0
- package/lib/esm/view/invoicing/invoicingCreditNoteListView/epics/fetchInvoicingCreditNoteListEpic.js +0 -3
- package/lib/esm/view/invoicing/invoicingCreditNoteListView/invoicingCreditNoteListViewReducer.js +7 -1
- package/lib/esm/view/invoicing/invoicingCreditNoteListView/invoicingCreditNoteListViewSelector.js +23 -13
- package/lib/esm/view/invoicing/invoicingCustomerDetailView/fetchInvoicingCustomerDetailPageEpic.js +3 -2
- package/lib/esm/view/invoicing/invoicingCustomerDetailView/invoicingCustomerDetailViewSelector.js +1 -1
- package/lib/esm/view/invoicing/invoicingCustomerListView/epics/fetchInvoicingCustomerListEpic.js +0 -3
- package/lib/esm/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewReducer.js +7 -1
- package/lib/esm/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewSelector.js +25 -12
- package/lib/esm/view/invoicing/invoicingDunningCaseListView/epics/fetchInvoicingDunningCaseListEpic.js +0 -3
- package/lib/esm/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewReducer.js +7 -1
- package/lib/esm/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewSelector.js +23 -13
- package/lib/esm/view/invoicing/invoicingSubscriptionListView/epics/fetchInvoicingSubscriptionListEpic.js +0 -3
- package/lib/esm/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewReducer.js +7 -1
- package/lib/esm/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewSelector.js +22 -12
- package/lib/esm/view/invoicing/invoicingTransactionListView/epics/fetchInvoicingTransactionListEpic.js +7 -5
- package/lib/esm/view/invoicing/invoicingTransactionListView/epics/fetchInvoicingTransactionListPageEpic.js +2 -1
- package/lib/esm/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewReducer.js +56 -25
- package/lib/esm/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewSelector.js +15 -11
- package/lib/esm/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewState.js +10 -0
- package/lib/esm/view/notificationPreferencesView/epics/saveNotificationPreferencesEpic.js +12 -9
- package/lib/esm/view/notificationPreferencesView/notificationPreferencesViewPayload.js +2 -7
- package/lib/esm/view/notificationPreferencesView/notificationPreferencesViewReducer.js +2 -47
- package/lib/esm/view/notificationPreferencesView/notificationPreferencesViewSelector.js +0 -9
- package/lib/esm/view/notificationPreferencesView/notificationPreferencesViewState.js +0 -1
- package/lib/esm/view/spendManagement/billPay/billDetailView/billDetailViewSelector.js +8 -2
- package/lib/esm/view/spendManagement/helpers.js +12 -0
- package/lib/esm/view/spendManagement/reimbursement/editRemiView/epics/fetchEditRemiDetailPageEpic.js +0 -12
- package/lib/esm/view/spendManagement/reimbursement/remiDetailView/remiDetailViewSelector.js +4 -2
- package/lib/index.d.ts +9 -9
- package/lib/index.js +21 -16
- package/lib/view/invoicing/couponView/couponViewEpics.js +0 -3
- package/lib/view/invoicing/couponView/couponViewReducer.d.ts +1 -1
- package/lib/view/invoicing/couponView/couponViewReducer.js +8 -2
- package/lib/view/invoicing/couponView/couponViewSelector.d.ts +1 -0
- package/lib/view/invoicing/couponView/couponViewSelector.js +27 -14
- package/lib/view/invoicing/couponView/couponViewState.d.ts +2 -1
- package/lib/view/invoicing/invoiceList/fetchInvoiceListEpic.d.ts +1 -1
- package/lib/view/invoicing/invoiceList/fetchInvoiceListEpic.js +7 -5
- package/lib/view/invoicing/invoiceList/fetchInvoiceListPageEpic.js +2 -1
- package/lib/view/invoicing/invoiceList/invoiceListReducer.d.ts +5 -4
- package/lib/view/invoicing/invoiceList/invoiceListReducer.js +63 -37
- package/lib/view/invoicing/invoiceList/invoiceListSelector.d.ts +1 -0
- package/lib/view/invoicing/invoiceList/invoiceListSelector.js +19 -15
- package/lib/view/invoicing/invoiceList/invoiceListState.d.ts +21 -7
- package/lib/view/invoicing/invoiceList/invoiceListState.js +13 -1
- package/lib/view/invoicing/invoicingCreditNoteListView/epics/fetchInvoicingCreditNoteListEpic.js +0 -3
- package/lib/view/invoicing/invoicingCreditNoteListView/invoicingCreditNoteListViewReducer.d.ts +1 -1
- package/lib/view/invoicing/invoicingCreditNoteListView/invoicingCreditNoteListViewReducer.js +8 -2
- package/lib/view/invoicing/invoicingCreditNoteListView/invoicingCreditNoteListViewSelector.d.ts +1 -0
- package/lib/view/invoicing/invoicingCreditNoteListView/invoicingCreditNoteListViewSelector.js +23 -13
- package/lib/view/invoicing/invoicingCreditNoteListView/invoicingCreditNoteListViewState.d.ts +2 -1
- package/lib/view/invoicing/invoicingCustomerDetailView/fetchInvoicingCustomerDetailPageEpic.js +3 -2
- package/lib/view/invoicing/invoicingCustomerDetailView/invoicingCustomerDetailViewSelector.js +1 -1
- package/lib/view/invoicing/invoicingCustomerListView/epics/fetchInvoicingCustomerListEpic.js +0 -3
- package/lib/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewReducer.d.ts +1 -1
- package/lib/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewReducer.js +8 -2
- package/lib/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewSelector.d.ts +1 -0
- package/lib/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewSelector.js +25 -12
- package/lib/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewState.d.ts +2 -1
- package/lib/view/invoicing/invoicingDunningCaseListView/epics/fetchInvoicingDunningCaseListEpic.js +0 -3
- package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewReducer.d.ts +1 -1
- package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewReducer.js +8 -2
- package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewSelector.d.ts +1 -0
- package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewSelector.js +23 -13
- package/lib/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewState.d.ts +2 -1
- package/lib/view/invoicing/invoicingSubscriptionListView/epics/fetchInvoicingSubscriptionListEpic.js +0 -3
- package/lib/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewReducer.d.ts +1 -1
- package/lib/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewReducer.js +8 -2
- package/lib/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewSelector.d.ts +1 -0
- package/lib/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewSelector.js +22 -12
- package/lib/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewState.d.ts +3 -1
- package/lib/view/invoicing/invoicingTransactionListView/epics/fetchInvoicingTransactionListEpic.d.ts +1 -1
- package/lib/view/invoicing/invoicingTransactionListView/epics/fetchInvoicingTransactionListEpic.js +7 -5
- package/lib/view/invoicing/invoicingTransactionListView/epics/fetchInvoicingTransactionListPageEpic.js +2 -1
- package/lib/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewReducer.d.ts +1 -1
- package/lib/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewReducer.js +57 -26
- package/lib/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewSelector.d.ts +1 -0
- package/lib/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewSelector.js +15 -11
- package/lib/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewState.d.ts +18 -4
- package/lib/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewState.js +13 -1
- package/lib/view/notificationPreferencesView/epics/saveNotificationPreferencesEpic.d.ts +8 -2
- package/lib/view/notificationPreferencesView/epics/saveNotificationPreferencesEpic.js +9 -6
- package/lib/view/notificationPreferencesView/notificationPreferencesViewPayload.d.ts +0 -1
- package/lib/view/notificationPreferencesView/notificationPreferencesViewPayload.js +2 -7
- package/lib/view/notificationPreferencesView/notificationPreferencesViewReducer.d.ts +1 -6
- package/lib/view/notificationPreferencesView/notificationPreferencesViewReducer.js +3 -48
- package/lib/view/notificationPreferencesView/notificationPreferencesViewSelector.js +0 -9
- package/lib/view/notificationPreferencesView/notificationPreferencesViewState.d.ts +0 -1
- package/lib/view/notificationPreferencesView/notificationPreferencesViewState.js +0 -1
- package/lib/view/spendManagement/billPay/billDetailView/billDetailViewSelector.d.ts +1 -0
- package/lib/view/spendManagement/billPay/billDetailView/billDetailViewSelector.js +7 -1
- package/lib/view/spendManagement/helpers.d.ts +1 -0
- package/lib/view/spendManagement/helpers.js +14 -1
- package/lib/view/spendManagement/reimbursement/editRemiView/epics/fetchEditRemiDetailPageEpic.d.ts +1 -2
- package/lib/view/spendManagement/reimbursement/editRemiView/epics/fetchEditRemiDetailPageEpic.js +0 -12
- package/lib/view/spendManagement/reimbursement/remiDetailView/remiDetailViewSelector.d.ts +1 -0
- package/lib/view/spendManagement/reimbursement/remiDetailView/remiDetailViewSelector.js +3 -1
- package/package.json +1 -1
package/lib/esm/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewSelector.js
CHANGED
|
@@ -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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
}
|
package/lib/esm/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewReducer.js
CHANGED
|
@@ -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;
|
package/lib/esm/view/invoicing/invoicingDunningCaseListView/invoicingDunningCaseListViewSelector.js
CHANGED
|
@@ -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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
}
|
package/lib/esm/view/invoicing/invoicingSubscriptionListView/invoicingSubscriptionListViewReducer.js
CHANGED
|
@@ -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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
+
});
|
|
@@ -4,13 +4,13 @@ import { updateInvoicingTransactions } from '../../../../entity/invoicing/invoic
|
|
|
4
4
|
import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
|
|
5
5
|
import { INVOICING_LIST_PAGE_SIZE, applyListSortParams, withQuery, } from '../../invoicingApiHelper';
|
|
6
6
|
import { fetchInvoicingTransactionList, updateInvoicingTransactionList, updateInvoicingTransactionListFailure, } from '../invoicingTransactionListViewReducer';
|
|
7
|
-
const buildQuery = (filters, cursor, sort) => {
|
|
7
|
+
const buildQuery = (filters, type, cursor, sort) => {
|
|
8
8
|
const params = new URLSearchParams();
|
|
9
9
|
if (filters.status != null && filters.status.length > 0) {
|
|
10
10
|
params.set('status', filters.status);
|
|
11
11
|
}
|
|
12
|
-
if (
|
|
13
|
-
params.set('type',
|
|
12
|
+
if (type != null && type.length > 0) {
|
|
13
|
+
params.set('type', type);
|
|
14
14
|
}
|
|
15
15
|
if (filters.customerId != null) {
|
|
16
16
|
params.set('customer_id', filters.customerId);
|
|
@@ -25,9 +25,11 @@ const buildQuery = (filters, cursor, sort) => {
|
|
|
25
25
|
applyListSortParams(params, sort);
|
|
26
26
|
return params;
|
|
27
27
|
};
|
|
28
|
-
export const fetchInvoicingTransactionListEpic = (actions$,
|
|
28
|
+
export const fetchInvoicingTransactionListEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchInvoicingTransactionList.match), switchMap((action) => {
|
|
29
29
|
const { filters, cursor, keepExistingListItems, sort } = action.payload;
|
|
30
|
-
const
|
|
30
|
+
const { activeTab } = state$.value.invoicingTransactionListViewState;
|
|
31
|
+
const type = activeTab !== 'all' ? activeTab : undefined;
|
|
32
|
+
const apiUrl = withQuery(`${zeniAPI.apiEndPoints.invoicingMicroServiceBaseUrl}/1.0/payments`, buildQuery(filters, type, cursor, sort));
|
|
31
33
|
return zeniAPI.getJSON(apiUrl).pipe(switchMap((response) => {
|
|
32
34
|
if (isSuccessResponse(response)) {
|
|
33
35
|
const items = response.data?.items ?? [];
|
|
@@ -16,8 +16,9 @@ const shouldFetch = (fetchStateAndError, cacheOverride) => cacheOverride ||
|
|
|
16
16
|
export const fetchInvoicingTransactionListPageEpic = (actions$, state$) => actions$.pipe(filter(fetchInvoicingTransactionListPage.match), mergeMap((action) => {
|
|
17
17
|
const { cacheOverride, filters, sort } = action.payload;
|
|
18
18
|
const state = state$.value.invoicingTransactionListViewState;
|
|
19
|
+
const activeTabState = state.byTab[state.activeTab];
|
|
19
20
|
const pageActions = [];
|
|
20
|
-
if (shouldFetch({ fetchState:
|
|
21
|
+
if (shouldFetch({ fetchState: activeTabState.fetchState, error: activeTabState.error }, cacheOverride)) {
|
|
21
22
|
pageActions.push(fetchInvoicingTransactionList({ filters, sort }));
|
|
22
23
|
}
|
|
23
24
|
return concat(from(pageActions));
|
package/lib/esm/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewReducer.js
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { createSlice } from '@reduxjs/toolkit';
|
|
2
|
+
import { makeInvoicingTransactionIdsByTab, } from './invoicingTransactionListViewState';
|
|
3
|
+
/**
|
|
4
|
+
* Whether two transaction-list queries share the same base (tab-independent)
|
|
5
|
+
* query. When the base query changes (search / customer / status / sort) every
|
|
6
|
+
* per-tab cache is stale, so the reducer resets them all.
|
|
7
|
+
*/
|
|
8
|
+
const sameTransactionBaseQuery = (a, b) => a.filters.customerId === b.filters.customerId &&
|
|
9
|
+
a.filters.status === b.filters.status &&
|
|
10
|
+
a.filters.search === b.filters.search &&
|
|
11
|
+
a.sort?.field === b.sort?.field &&
|
|
12
|
+
a.sort?.dir === b.sort?.dir;
|
|
2
13
|
export const initialState = {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
ids: [],
|
|
6
|
-
nextCursor: null,
|
|
14
|
+
activeTab: 'all',
|
|
15
|
+
byTab: makeInvoicingTransactionIdsByTab(),
|
|
7
16
|
filters: {},
|
|
8
|
-
hasValidState() {
|
|
9
|
-
return this.fetchState === 'Completed';
|
|
10
|
-
},
|
|
11
17
|
};
|
|
12
18
|
const invoicingTransactionListView = createSlice({
|
|
13
19
|
name: 'invoicingTransactionListView',
|
|
@@ -15,14 +21,15 @@ const invoicingTransactionListView = createSlice({
|
|
|
15
21
|
reducers: {
|
|
16
22
|
fetchInvoicingTransactionList: {
|
|
17
23
|
reducer(draft, action) {
|
|
24
|
+
const tab = draft.byTab[draft.activeTab];
|
|
18
25
|
if (!action.payload.keepExistingListItems) {
|
|
19
|
-
|
|
20
|
-
|
|
26
|
+
tab.ids = [];
|
|
27
|
+
tab.nextCursor = null;
|
|
21
28
|
}
|
|
22
29
|
draft.filters = action.payload.filters;
|
|
23
30
|
draft.sort = action.payload.sort;
|
|
24
|
-
|
|
25
|
-
|
|
31
|
+
tab.fetchState = 'In-Progress';
|
|
32
|
+
tab.error = undefined;
|
|
26
33
|
},
|
|
27
34
|
prepare(payload) {
|
|
28
35
|
return {
|
|
@@ -37,6 +44,12 @@ const invoicingTransactionListView = createSlice({
|
|
|
37
44
|
},
|
|
38
45
|
fetchInvoicingTransactionListPage: {
|
|
39
46
|
reducer(draft, action) {
|
|
47
|
+
// A different base query invalidates every tab's cache — reset so the
|
|
48
|
+
// page epic's shouldFetch refetches the active tab instead of showing
|
|
49
|
+
// rows fetched under a stale search/customer/status/sort.
|
|
50
|
+
if (!sameTransactionBaseQuery(draft, action.payload)) {
|
|
51
|
+
draft.byTab = makeInvoicingTransactionIdsByTab();
|
|
52
|
+
}
|
|
40
53
|
draft.filters = action.payload.filters;
|
|
41
54
|
draft.sort = action.payload.sort;
|
|
42
55
|
},
|
|
@@ -51,34 +64,52 @@ const invoicingTransactionListView = createSlice({
|
|
|
51
64
|
},
|
|
52
65
|
},
|
|
53
66
|
updateInvoicingTransactionList(draft, action) {
|
|
54
|
-
|
|
55
|
-
|
|
67
|
+
const tab = draft.byTab[draft.activeTab];
|
|
68
|
+
tab.ids = action.payload.keepExistingListItems
|
|
69
|
+
? [...new Set([...tab.ids, ...action.payload.ids])]
|
|
56
70
|
: action.payload.ids;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
71
|
+
tab.nextCursor = action.payload.nextCursor;
|
|
72
|
+
tab.fetchState = 'Completed';
|
|
73
|
+
tab.error = undefined;
|
|
60
74
|
},
|
|
61
75
|
updateInvoicingTransactionListFailure(draft, action) {
|
|
62
|
-
|
|
63
|
-
|
|
76
|
+
const tab = draft.byTab[draft.activeTab];
|
|
77
|
+
tab.fetchState = 'Error';
|
|
78
|
+
tab.error = action.payload;
|
|
64
79
|
},
|
|
65
80
|
updateInvoicingTransactionFilters(draft, action) {
|
|
66
81
|
draft.filters = action.payload;
|
|
67
82
|
},
|
|
83
|
+
// Select a type tab. The view dispatches the follow-up
|
|
84
|
+
// fetchInvoicingTransactionListPage so the page epic fetches the tab when
|
|
85
|
+
// its cache is empty and reuses it when already loaded.
|
|
86
|
+
setInvoicingTransactionActiveTab(draft, action) {
|
|
87
|
+
draft.activeTab = action.payload;
|
|
88
|
+
},
|
|
68
89
|
// Reflect a newly recorded payment's transaction in the cached list so the
|
|
69
|
-
// payments page shows it without refetching. The
|
|
70
|
-
//
|
|
90
|
+
// payments page shows it without refetching. The payload carries no type,
|
|
91
|
+
// so prepend to the 'all' tab and the tab currently in view (dedup/no-op if
|
|
92
|
+
// already present); other tabs refetch fresh on their next visit.
|
|
71
93
|
addInvoicingTransactionToList(draft, action) {
|
|
72
94
|
const id = action.payload;
|
|
73
|
-
|
|
74
|
-
|
|
95
|
+
const prependTo = (tabId) => {
|
|
96
|
+
const tab = draft.byTab[tabId];
|
|
97
|
+
if (!tab.ids.includes(id)) {
|
|
98
|
+
tab.ids = [id, ...tab.ids];
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
prependTo('all');
|
|
102
|
+
if (draft.activeTab !== 'all') {
|
|
103
|
+
prependTo(draft.activeTab);
|
|
75
104
|
}
|
|
76
|
-
draft.ids = [id, ...draft.ids];
|
|
77
105
|
},
|
|
78
106
|
clearInvoicingTransactionListView(draft) {
|
|
79
|
-
|
|
107
|
+
draft.activeTab = 'all';
|
|
108
|
+
draft.byTab = makeInvoicingTransactionIdsByTab();
|
|
109
|
+
draft.filters = {};
|
|
110
|
+
draft.sort = undefined;
|
|
80
111
|
},
|
|
81
112
|
},
|
|
82
113
|
});
|
|
83
|
-
export const { fetchInvoicingTransactionList, fetchInvoicingTransactionListPage, updateInvoicingTransactionList, updateInvoicingTransactionListFailure, updateInvoicingTransactionFilters, addInvoicingTransactionToList, clearInvoicingTransactionListView, } = invoicingTransactionListView.actions;
|
|
114
|
+
export const { fetchInvoicingTransactionList, fetchInvoicingTransactionListPage, updateInvoicingTransactionList, updateInvoicingTransactionListFailure, updateInvoicingTransactionFilters, setInvoicingTransactionActiveTab, addInvoicingTransactionToList, clearInvoicingTransactionListView, } = invoicingTransactionListView.actions;
|
|
84
115
|
export default invoicingTransactionListView.reducer;
|
package/lib/esm/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewSelector.js
CHANGED
|
@@ -6,14 +6,18 @@ import { INVOICING_TRANSACTION_COLUMNS, INVOICING_TRANSACTION_TABS, } from './in
|
|
|
6
6
|
* object) keep referential identity until the transaction entity slice or the
|
|
7
7
|
* list-view slice actually change.
|
|
8
8
|
*/
|
|
9
|
-
export const getInvoicingTransactionListView = createSelector((state) => state.invoicingTransactionState, (state) => state.invoicingTransactionListViewState, (transactionState, listViewState) =>
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
9
|
+
export const getInvoicingTransactionListView = createSelector((state) => state.invoicingTransactionState, (state) => state.invoicingTransactionListViewState, (transactionState, listViewState) => {
|
|
10
|
+
const activeTabState = listViewState.byTab[listViewState.activeTab];
|
|
11
|
+
return {
|
|
12
|
+
activeTab: listViewState.activeTab,
|
|
13
|
+
columns: INVOICING_TRANSACTION_COLUMNS,
|
|
14
|
+
transactions: getInvoicingTransactionsByIds(transactionState, activeTabState.ids),
|
|
15
|
+
filters: listViewState.filters,
|
|
16
|
+
nextCursor: activeTabState.nextCursor,
|
|
17
|
+
fetchState: activeTabState.fetchState,
|
|
18
|
+
error: activeTabState.error,
|
|
19
|
+
tabIds: INVOICING_TRANSACTION_TABS,
|
|
20
|
+
sort: listViewState.sort,
|
|
21
|
+
version: 1.0,
|
|
22
|
+
};
|
|
23
|
+
});
|
package/lib/esm/view/invoicing/invoicingTransactionListView/invoicingTransactionListViewState.js
CHANGED
|
@@ -37,3 +37,13 @@ export const toInvoicingTransactionTabId = (v) => stringToUnion(v, ALL_INVOICING
|
|
|
37
37
|
export const INVOICING_TRANSACTION_TABS = [
|
|
38
38
|
...ALL_INVOICING_TRANSACTION_TAB_IDS,
|
|
39
39
|
];
|
|
40
|
+
export const makeInvoicingTransactionTabState = () => ({
|
|
41
|
+
ids: [],
|
|
42
|
+
nextCursor: null,
|
|
43
|
+
fetchState: 'Not-Started',
|
|
44
|
+
error: undefined,
|
|
45
|
+
});
|
|
46
|
+
export const makeInvoicingTransactionIdsByTab = () => ALL_INVOICING_TRANSACTION_TAB_IDS.reduce((acc, tabId) => {
|
|
47
|
+
acc[tabId] = makeInvoicingTransactionTabState();
|
|
48
|
+
return acc;
|
|
49
|
+
}, {});
|
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
import { EMPTY, of } from 'rxjs';
|
|
2
|
-
import { catchError, filter, finalize, mergeMap, switchMap, takeUntil, withLatestFrom, } from 'rxjs/operators';
|
|
1
|
+
import { EMPTY, concat, of } from 'rxjs';
|
|
2
|
+
import { catchError, debounceTime, filter, finalize, mergeMap, switchMap, takeUntil, withLatestFrom, } from 'rxjs/operators';
|
|
3
3
|
import { openSnackbar } from '../../../entity/snackbar/snackbarReducer';
|
|
4
4
|
import { createZeniAPIStatus, isSuccessResponse, } from '../../../responsePayload';
|
|
5
5
|
import { notificationPreferencesUrl } from '../notificationPreferencesEndpoint';
|
|
6
6
|
import { mapPreferencesToPayload, } from '../notificationPreferencesViewPayload';
|
|
7
|
-
import { clearAllNotificationPreferencesView, clearNotificationPreferencesLocalOverrides, saveNotificationPreferences, saveNotificationPreferencesFailure, saveNotificationPreferencesSuccess, } from '../notificationPreferencesViewReducer';
|
|
7
|
+
import { clearAllNotificationPreferencesView, clearNotificationPreferencesLocalOverrides, saveNotificationPreferences, saveNotificationPreferencesFailure, saveNotificationPreferencesSuccess, setGroupFrequency, toggleEventChannel, } from '../notificationPreferencesViewReducer';
|
|
8
8
|
import { getNotificationLocalOverrides } from '../notificationPreferencesViewSelector';
|
|
9
|
-
|
|
9
|
+
const DEBOUNCE_MS = 300;
|
|
10
|
+
export const saveNotificationPreferencesEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter((action) => toggleEventChannel.match(action) || setGroupFrequency.match(action)),
|
|
11
|
+
// Coalesce bursts of toggles into a single PUT. Trade-off: rapid clickers
|
|
12
|
+
// defer saves until they pause. Consider a max-wait wrapper if this
|
|
13
|
+
// becomes a UX problem.
|
|
14
|
+
debounceTime(DEBOUNCE_MS), withLatestFrom(state$),
|
|
10
15
|
// `switchMap` unsubscribes from any in-flight PUT observable when a new
|
|
11
16
|
// debounced batch fires. The prior HTTP request has already left the
|
|
12
17
|
// client — the network call is NOT cancelled — but its response is
|
|
@@ -105,9 +110,7 @@ switchMap(([, state]) => {
|
|
|
105
110
|
// under patch-semantic LWW. Cursor Bugbot 3637969823 + 3641372002.
|
|
106
111
|
takeUntil(actions$.pipe(filter((action) => clearNotificationPreferencesLocalOverrides.match(action) ||
|
|
107
112
|
clearAllNotificationPreferencesView.match(action)))));
|
|
108
|
-
//
|
|
109
|
-
//
|
|
110
|
-
|
|
111
|
-
// loop the epic on itself.
|
|
112
|
-
return request$;
|
|
113
|
+
// Flip savePreferencesState to In-Progress BEFORE the network call so
|
|
114
|
+
// any "saving…" UI can render.
|
|
115
|
+
return concat(of(saveNotificationPreferences()), request$);
|
|
113
116
|
}));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { toNotificationChannel, toNotificationFrequency, } from '../../entity/notificationRegistry/notificationRegistryState';
|
|
2
|
-
const
|
|
2
|
+
const mapEventEnabledByChannel = (raw) => {
|
|
3
3
|
if (raw == null) {
|
|
4
4
|
return {};
|
|
5
5
|
}
|
|
@@ -20,8 +20,7 @@ export const mapPayloadToPreferences = (payload) => {
|
|
|
20
20
|
toNotificationFrequency(frequency),
|
|
21
21
|
]));
|
|
22
22
|
return {
|
|
23
|
-
eventEnabledByChannel:
|
|
24
|
-
groupChannelEnabledByGroupId: mapChannelEnabledMap(payload?.group_channel_enabled_by_group_id),
|
|
23
|
+
eventEnabledByChannel: mapEventEnabledByChannel(payload?.event_enabled_by_channel),
|
|
25
24
|
groupFrequencyByGroupId,
|
|
26
25
|
};
|
|
27
26
|
};
|
|
@@ -30,10 +29,6 @@ export const mapPreferencesToPayload = (preferences) => {
|
|
|
30
29
|
if (Object.keys(preferences.eventEnabledByChannel).length > 0) {
|
|
31
30
|
payload.event_enabled_by_channel = preferences.eventEnabledByChannel;
|
|
32
31
|
}
|
|
33
|
-
if (Object.keys(preferences.groupChannelEnabledByGroupId).length > 0) {
|
|
34
|
-
payload.group_channel_enabled_by_group_id =
|
|
35
|
-
preferences.groupChannelEnabledByGroupId;
|
|
36
|
-
}
|
|
37
32
|
if (Object.keys(preferences.groupFrequencyByGroupId).length > 0) {
|
|
38
33
|
payload.group_frequency_by_group_id = preferences.groupFrequencyByGroupId;
|
|
39
34
|
}
|
|
@@ -18,18 +18,8 @@ const mergePreferences = (base, patch) => {
|
|
|
18
18
|
...channels,
|
|
19
19
|
};
|
|
20
20
|
});
|
|
21
|
-
const groupChannelEnabledByGroupId = {
|
|
22
|
-
...base.groupChannelEnabledByGroupId,
|
|
23
|
-
};
|
|
24
|
-
Object.entries(patch.groupChannelEnabledByGroupId).forEach(([groupId, channels]) => {
|
|
25
|
-
groupChannelEnabledByGroupId[groupId] = {
|
|
26
|
-
...(base.groupChannelEnabledByGroupId[groupId] ?? {}),
|
|
27
|
-
...channels,
|
|
28
|
-
};
|
|
29
|
-
});
|
|
30
21
|
return {
|
|
31
22
|
eventEnabledByChannel,
|
|
32
|
-
groupChannelEnabledByGroupId,
|
|
33
23
|
groupFrequencyByGroupId: {
|
|
34
24
|
...base.groupFrequencyByGroupId,
|
|
35
25
|
...patch.groupFrequencyByGroupId,
|
|
@@ -71,38 +61,13 @@ const subtractSavedOverrides = (current, saved) => {
|
|
|
71
61
|
eventEnabledByChannel[eventId] = remainingChannels;
|
|
72
62
|
}
|
|
73
63
|
});
|
|
74
|
-
// Same value-equality subtraction as eventEnabledByChannel above — a
|
|
75
|
-
// group-channel master the user re-flipped while a PUT was in flight must
|
|
76
|
-
// survive so the next debounce cycle re-sends it.
|
|
77
|
-
const groupChannelEnabledByGroupId = {};
|
|
78
|
-
Object.entries(current.groupChannelEnabledByGroupId).forEach(([groupId, channels]) => {
|
|
79
|
-
const savedChannels = saved.groupChannelEnabledByGroupId[groupId];
|
|
80
|
-
if (savedChannels == null) {
|
|
81
|
-
groupChannelEnabledByGroupId[groupId] = channels;
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
const remainingChannels = {};
|
|
85
|
-
Object.keys(channels).forEach((channel) => {
|
|
86
|
-
if (!(channel in savedChannels) ||
|
|
87
|
-
channels[channel] !== savedChannels[channel]) {
|
|
88
|
-
remainingChannels[channel] = channels[channel];
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
if (Object.keys(remainingChannels).length > 0) {
|
|
92
|
-
groupChannelEnabledByGroupId[groupId] = remainingChannels;
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
64
|
const groupFrequencyByGroupId = {};
|
|
96
65
|
Object.entries(current.groupFrequencyByGroupId).forEach(([groupId, frequency]) => {
|
|
97
66
|
if (saved.groupFrequencyByGroupId[groupId] !== frequency) {
|
|
98
67
|
groupFrequencyByGroupId[groupId] = frequency;
|
|
99
68
|
}
|
|
100
69
|
});
|
|
101
|
-
return {
|
|
102
|
-
eventEnabledByChannel,
|
|
103
|
-
groupChannelEnabledByGroupId,
|
|
104
|
-
groupFrequencyByGroupId,
|
|
105
|
-
};
|
|
70
|
+
return { eventEnabledByChannel, groupFrequencyByGroupId };
|
|
106
71
|
};
|
|
107
72
|
const notificationPreferencesView = createSlice({
|
|
108
73
|
name: 'notificationPreferencesView',
|
|
@@ -239,16 +204,6 @@ const notificationPreferencesView = createSlice({
|
|
|
239
204
|
draft.preferences = mergePreferences(draft.preferences, patch);
|
|
240
205
|
draft.localOverrides = subtractSavedOverrides(draft.localOverrides, action.payload.savedOverrides);
|
|
241
206
|
},
|
|
242
|
-
setGroupChannelMaster(draft, action) {
|
|
243
|
-
// Mirror of `toggleEventChannel` but scoped to the group-channel master
|
|
244
|
-
// held under `groupChannelEnabledByGroupId[groupId][channel]`.
|
|
245
|
-
const { channel, enabled, groupId } = action.payload;
|
|
246
|
-
const groupMap = {
|
|
247
|
-
...(draft.localOverrides.groupChannelEnabledByGroupId[groupId] ?? {}),
|
|
248
|
-
};
|
|
249
|
-
groupMap[channel] = enabled;
|
|
250
|
-
draft.localOverrides.groupChannelEnabledByGroupId[groupId] = groupMap;
|
|
251
|
-
},
|
|
252
207
|
setGroupFrequency(draft, action) {
|
|
253
208
|
draft.localOverrides.groupFrequencyByGroupId[action.payload.groupId] =
|
|
254
209
|
action.payload.frequency;
|
|
@@ -263,5 +218,5 @@ const notificationPreferencesView = createSlice({
|
|
|
263
218
|
},
|
|
264
219
|
},
|
|
265
220
|
});
|
|
266
|
-
export const { clearAllNotificationPreferencesView, clearNotificationPreferencesLocalOverrides, fetchNotificationPreferencesSuccess, saveNotificationPreferences, saveNotificationPreferencesFailure, saveNotificationPreferencesSuccess,
|
|
221
|
+
export const { clearAllNotificationPreferencesView, clearNotificationPreferencesLocalOverrides, fetchNotificationPreferencesSuccess, saveNotificationPreferences, saveNotificationPreferencesFailure, saveNotificationPreferencesSuccess, setGroupFrequency, toggleEventChannel, } = notificationPreferencesView.actions;
|
|
267
222
|
export default notificationPreferencesView.reducer;
|
|
@@ -9,16 +9,8 @@ export const getEffectiveNotificationPreferences = (state) => {
|
|
|
9
9
|
...channels,
|
|
10
10
|
};
|
|
11
11
|
});
|
|
12
|
-
const mergedGroupChannelEnabledByGroupId = { ...view.preferences.groupChannelEnabledByGroupId };
|
|
13
|
-
Object.entries(view.localOverrides.groupChannelEnabledByGroupId).forEach(([groupId, channels]) => {
|
|
14
|
-
mergedGroupChannelEnabledByGroupId[groupId] = {
|
|
15
|
-
...(view.preferences.groupChannelEnabledByGroupId[groupId] ?? {}),
|
|
16
|
-
...channels,
|
|
17
|
-
};
|
|
18
|
-
});
|
|
19
12
|
return {
|
|
20
13
|
eventEnabledByChannel: mergedEventEnabledByChannel,
|
|
21
|
-
groupChannelEnabledByGroupId: mergedGroupChannelEnabledByGroupId,
|
|
22
14
|
groupFrequencyByGroupId: {
|
|
23
15
|
...view.preferences.groupFrequencyByGroupId,
|
|
24
16
|
...view.localOverrides.groupFrequencyByGroupId,
|
|
@@ -29,6 +21,5 @@ export const getNotificationLocalOverrides = (state) => getView(state).localOver
|
|
|
29
21
|
export const hasUnsavedNotificationPreferences = (state) => {
|
|
30
22
|
const overrides = getView(state).localOverrides;
|
|
31
23
|
return (Object.keys(overrides.eventEnabledByChannel).length > 0 ||
|
|
32
|
-
Object.keys(overrides.groupChannelEnabledByGroupId).length > 0 ||
|
|
33
24
|
Object.keys(overrides.groupFrequencyByGroupId).length > 0);
|
|
34
25
|
};
|
|
@@ -13,7 +13,7 @@ import { getUserByUserId } from '../../../../entity/user/userSelector';
|
|
|
13
13
|
import { getUserRoleByUserId } from '../../../../entity/userRole/userRoleSelector';
|
|
14
14
|
import { getActivityHistory, } from '../../commonHistoryView/commonHistorySelector';
|
|
15
15
|
import { getAllFundingAccounts, } from '../../commonSetup/setupViewSelector';
|
|
16
|
-
import { getLatestApprovalDate, isAwaitingMarkAsPaid, isSodAdminFallbackEligibleForStep, isSodExcludedViewerBlocked, } from '../../helpers';
|
|
16
|
+
import { getLatestApprovalDate, isAwaitingMarkAsPaid, isSodAdminFallbackEligibleForStep, isSodExcludedViewerBlocked, shouldShowSodAdminLabel, } from '../../helpers';
|
|
17
17
|
import { getActivityRealTimeApproval, } from '../../realTimeApprovalView/realTimeApprovalSelector';
|
|
18
18
|
import { getEntityRealTimeApprovalDetailKey } from '../../realTimeApprovalView/realTimeApprovalState';
|
|
19
19
|
import { getBillPaymentSubConfigCodeKey, getInternationalSubConfigCodeKey, getInternationalWireMethodCodeKey, } from '../billPayConfig/billPayConfigPayload';
|
|
@@ -22,7 +22,12 @@ import { getBillPayConfigMethodKey, toBillPaymentSubConfigCodeKeyType, } from '.
|
|
|
22
22
|
import { getPreviousBills, } from '../previousBills/previousBillsSelector';
|
|
23
23
|
import { getBillTransactionDetailKey, initialBillDetailView, } from './billDetailViewState';
|
|
24
24
|
export const getBillActivities = (state, billId, billStageCode) => {
|
|
25
|
-
const { billDetailViewState, approvalRuleState, entityApprovalStatusState, userState, } = state;
|
|
25
|
+
const { billDetailViewState, approvalRuleState, entityApprovalStatusState, userState, billTransactionState, } = state;
|
|
26
|
+
// Note: createdBy is undefined until billTransactionState is populated.
|
|
27
|
+
// getBillActivities is called from getBillDetailView which runs after the
|
|
28
|
+
// bill entity epic completes — this assumption must hold for showSodAdminLabel
|
|
29
|
+
// to render on first paint.
|
|
30
|
+
const createdBy = billTransactionState.transactionById[billId]?.createdBy;
|
|
26
31
|
const key = getBillTransactionDetailKey(billId);
|
|
27
32
|
const billDetail = recordGet(billDetailViewState.billDetailById, key, undefined);
|
|
28
33
|
let billActivities = [];
|
|
@@ -85,6 +90,7 @@ export const getBillActivities = (state, billId, billStageCode) => {
|
|
|
85
90
|
actorsActivity,
|
|
86
91
|
isOriginalApprovalStep: step.isOriginalApprovalStep,
|
|
87
92
|
displayPendingApproverAsAdmin: isSodAdminFallbackEligibleForStep(sodExcludedApproverUserId, isAdminFallbackApprover, actorsActivity),
|
|
93
|
+
showSodAdminLabel: shouldShowSodAdminLabel(sodExcludedApproverUserId, actorsActivity, createdBy),
|
|
88
94
|
};
|
|
89
95
|
}),
|
|
90
96
|
};
|