@zeniai/client-epic-state 5.2.52 → 5.2.53-beta0ND
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/entity/notificationRegistry/notificationRegistryReducer.d.ts +2 -1
- package/lib/entity/notificationRegistry/notificationRegistryReducer.js +20 -9
- package/lib/entity/notificationRegistry/notificationRegistrySelector.d.ts +2 -1
- package/lib/entity/notificationRegistry/notificationRegistrySelector.js +7 -1
- package/lib/entity/notificationRegistry/notificationRegistryState.d.ts +5 -0
- package/lib/entity/notificationRegistry/notificationRegistryState.js +7 -1
- package/lib/entity/sectionProjectView/sectionProjectViewReducer.js +3 -1
- package/lib/epic.js +4 -4
- package/lib/esm/entity/notificationRegistry/notificationRegistryReducer.js +20 -9
- package/lib/esm/entity/notificationRegistry/notificationRegistrySelector.js +5 -0
- package/lib/esm/entity/notificationRegistry/notificationRegistryState.js +5 -0
- package/lib/esm/entity/sectionProjectView/sectionProjectViewReducer.js +3 -1
- package/lib/esm/epic.js +4 -4
- package/lib/esm/index.js +4 -4
- package/lib/esm/view/aiCfoView/aiCfoViewReducer.js +4 -2
- package/lib/esm/view/aiCfoView/epics/fetchRoutineRunsEpic.js +3 -1
- package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +15 -4
- package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +10 -0
- package/lib/esm/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +28 -11
- package/lib/esm/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.js +19 -3
- package/lib/esm/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewSelector.js +21 -21
- package/lib/esm/view/invoicing/invoicingQboView/invoicingQboViewSelector.js +57 -9
- package/lib/esm/view/notificationPreferencesView/epics/saveNotificationPreferencesEpic.js +20 -7
- package/lib/esm/view/notificationPreferencesView/notificationPreferencesViewReducer.js +43 -17
- package/lib/esm/view/notificationPreferencesView/notificationPreferencesViewSelector.js +24 -4
- package/lib/esm/view/settingsView/epic/fetchNotificationSettingsEpic.js +12 -2
- package/lib/index.d.ts +4 -4
- package/lib/index.js +21 -14
- package/lib/view/aiCfoView/aiCfoViewReducer.js +4 -2
- package/lib/view/aiCfoView/aiCfoViewSelector.d.ts +1 -1
- package/lib/view/aiCfoView/epics/fetchRoutineRunsEpic.js +3 -1
- package/lib/view/expenseAutomationView/epics/transactionCategorization/fetchTransactionCategorizationEpic.js +15 -4
- package/lib/view/expenseAutomationView/payload/transactionCategorizationPayload.d.ts +18 -7
- package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +10 -0
- package/lib/view/expenseAutomationView/selectorTypes/transactionsViewSelectorTypes.d.ts +8 -4
- package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +27 -10
- package/lib/view/expenseAutomationView/types/transactionsViewState.d.ts +8 -5
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.d.ts +7 -0
- package/lib/view/invoicing/editInvoicingCatalogItemDetailView/editInvoicingCatalogItemDetailViewSelector.js +18 -2
- package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewSelector.d.ts +3 -2
- package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewSelector.js +19 -19
- package/lib/view/invoicing/invoicingQboView/invoicingQboViewSelector.d.ts +49 -0
- package/lib/view/invoicing/invoicingQboView/invoicingQboViewSelector.js +59 -10
- package/lib/view/notificationPreferencesView/epics/saveNotificationPreferencesEpic.js +19 -6
- package/lib/view/notificationPreferencesView/notificationPreferencesViewReducer.d.ts +8 -5
- package/lib/view/notificationPreferencesView/notificationPreferencesViewReducer.js +43 -17
- package/lib/view/notificationPreferencesView/notificationPreferencesViewSelector.d.ts +4 -0
- package/lib/view/notificationPreferencesView/notificationPreferencesViewSelector.js +30 -5
- package/lib/view/notificationPreferencesView/notificationPreferencesViewState.d.ts +4 -3
- package/lib/view/settingsView/epic/fetchNotificationSettingsEpic.js +12 -2
- package/lib/view/settingsView/settingsViewPayload.d.ts +2 -0
- package/package.json +1 -1
|
@@ -30,7 +30,9 @@ const fetchRoutineRunsEpic = (actions$, _state$, zeniAPI) => actions$.pipe((0, o
|
|
|
30
30
|
// Filtered, not trusted: one malformed row must not take the
|
|
31
31
|
// whole history down, and a run without an id is not addressable
|
|
32
32
|
// by anything the UI does with it.
|
|
33
|
-
runs: (data.runs ?? [])
|
|
33
|
+
runs: (data.runs ?? [])
|
|
34
|
+
.filter(toRoutineRun_1.isRoutineRunPayload)
|
|
35
|
+
.map(toRoutineRun_1.toRoutineRun),
|
|
34
36
|
scheduleId,
|
|
35
37
|
sessionId: data.session_id ?? null,
|
|
36
38
|
});
|
|
@@ -9,7 +9,6 @@ const transactionReducer_1 = require("../../../../entity/transaction/transaction
|
|
|
9
9
|
const responsePayload_1 = require("../../../../responsePayload");
|
|
10
10
|
const transactionCategorizationLocalDataHelper_1 = require("../../helpers/transactionCategorizationLocalDataHelper");
|
|
11
11
|
const transactionsViewReducer_1 = require("../../reducers/transactionsViewReducer");
|
|
12
|
-
const completedSubTab_1 = require("../../types/completedSubTab");
|
|
13
12
|
const transactionsViewState_1 = require("../../types/transactionsViewState");
|
|
14
13
|
const fetchTransactionCategorizationEpic = (actions$, state$, zeniAPI) => actions$.pipe((0, operators_1.filter)(transactionsViewReducer_1.fetchTransactionCategorization.match),
|
|
15
14
|
// Per-tab switchMap: cancels in-flight requests for the same tab on a new
|
|
@@ -36,9 +35,10 @@ const fetchTransactionCategorizationEpic = (actions$, state$, zeniAPI) => action
|
|
|
36
35
|
// cross-status search (omit or true) is reserved for Receipts
|
|
37
36
|
// manual-match.
|
|
38
37
|
search_all_statuses: false,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
// Sent on both tabs: the backend ignores it for Review's own rows but uses
|
|
39
|
+
// it to scope the Completed badge it returns alongside them.
|
|
40
|
+
sub_tab: expenseAutomationTransactionsViewState
|
|
41
|
+
.selectedTransactionCategorizationCompletedSubTab,
|
|
42
42
|
transaction_group: expenseAutomationTransactionsViewState.selectedTransactionGroup,
|
|
43
43
|
};
|
|
44
44
|
return zeniAPI
|
|
@@ -90,6 +90,17 @@ const fetchTransactionCategorizationEpic = (actions$, state$, zeniAPI) => action
|
|
|
90
90
|
parentTotalCount: response.data.parent_tab_total_count ??
|
|
91
91
|
response.data.total_count,
|
|
92
92
|
}));
|
|
93
|
+
// The inactive tab's badge, counted under the same filters. Absent on
|
|
94
|
+
// pages after the first and on the cross-tab search path, where the
|
|
95
|
+
// last known value stays correct.
|
|
96
|
+
const otherTabTotalCount = response.data.other_tab_total_count;
|
|
97
|
+
if (otherTabTotalCount != null) {
|
|
98
|
+
updateActions.push((0, transactionsViewReducer_1.updateParentTotalCountForTab)({
|
|
99
|
+
selectedPeriod,
|
|
100
|
+
selectedTab: selectedTab === 'review' ? 'autoCategorized' : 'review',
|
|
101
|
+
parentTotalCount: otherTabTotalCount,
|
|
102
|
+
}));
|
|
103
|
+
}
|
|
93
104
|
updateActions.push((0, transactionsViewReducer_1.resetOtherTabsFetchState)({
|
|
94
105
|
refreshViewInBackground,
|
|
95
106
|
tabs: transactionsViewState_1.TRANSACTIONS_TABS.filter((tab) => selectedTab !== tab),
|
|
@@ -15,9 +15,9 @@ export interface TransactionCategorizationQueryPayload {
|
|
|
15
15
|
start_date: string | null;
|
|
16
16
|
/**
|
|
17
17
|
* Required. For the Completed (`auto_categorized=true`) listing, scopes the
|
|
18
|
-
* returned page + `total_count` to one of the Completed sub-tabs.
|
|
19
|
-
* Review listing
|
|
20
|
-
*
|
|
18
|
+
* returned page + `total_count` to one of the Completed sub-tabs. It is sent
|
|
19
|
+
* on the Review listing too: the backend ignores it for Review's own status
|
|
20
|
+
* set, but uses it to scope the Completed badge in `other_tab_total_count`.
|
|
21
21
|
*/
|
|
22
22
|
sub_tab: CompletedSubTab;
|
|
23
23
|
/**
|
|
@@ -44,10 +44,21 @@ export interface TransactionCategorizationPayload {
|
|
|
44
44
|
total_count: number;
|
|
45
45
|
transactions: SupportedTransactionPayload[];
|
|
46
46
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
47
|
+
* Badge count for the OTHER tab (Completed when this response is Review, and
|
|
48
|
+
* vice versa) under the same filters, so both badges move together with the
|
|
49
|
+
* Transaction Group dropdown and the Completed sub-tab without having to
|
|
50
|
+
* fetch that tab's rows.
|
|
51
|
+
*
|
|
52
|
+
* `null`/absent when the backend computed no badge — pages after the first
|
|
53
|
+
* (a scroll cannot change either badge) and the cross-tab search path used by
|
|
54
|
+
* Receipts manual-match. Consumers must keep their last known value then.
|
|
55
|
+
*/
|
|
56
|
+
other_tab_total_count?: number | null;
|
|
57
|
+
/**
|
|
58
|
+
* Badge count for the tab this response belongs to, taken under every filter
|
|
59
|
+
* the request carried (`transaction_group`, `sub_tab`, `search_text`) — so it
|
|
60
|
+
* matches the rows rendered below it and equals {@link total_count}. Retained
|
|
61
|
+
* as its own key for wire compatibility.
|
|
51
62
|
*
|
|
52
63
|
* Optional at the wire boundary so that any version-skew scenario
|
|
53
64
|
* (delayed BE rollout, cached SW response, hotfix without the BE change)
|
|
@@ -380,6 +380,16 @@ const expenseAutomationTransactionsView = (0, toolkit_1.createSlice)({
|
|
|
380
380
|
if (cached != null) {
|
|
381
381
|
autoCat.uiState.pageToken = cached.pageToken;
|
|
382
382
|
autoCat.uiState.totalCount = { ...cached.totalCount };
|
|
383
|
+
// Keep the stored badge in step with the restored sub-tab: the selector
|
|
384
|
+
// falls back to it for any period this sub-tab has not loaded. Merged,
|
|
385
|
+
// not replaced -- the snapshot only holds periods this sub-tab actually
|
|
386
|
+
// loaded, while the badge map also carries periods filled from a Review
|
|
387
|
+
// response's `other_tab_total_count`. Overwriting would drop those and
|
|
388
|
+
// leave the badge at 0 for any period this sub-tab never visited.
|
|
389
|
+
draft.parentTotalCountByTab.autoCategorized = {
|
|
390
|
+
...draft.parentTotalCountByTab.autoCategorized,
|
|
391
|
+
...cached.totalCount,
|
|
392
|
+
};
|
|
383
393
|
autoCat.uiState.scrollPosition = cached.scrollPosition;
|
|
384
394
|
autoCat.transactionIdsBySelectedPeriod = {
|
|
385
395
|
...cached.transactionIdsBySelectedPeriod,
|
|
@@ -28,10 +28,14 @@ export interface ExpenseAutomationTransactionViewSelector extends SelectorView {
|
|
|
28
28
|
isAccountingProjectsEnabled: boolean;
|
|
29
29
|
markAsNotMiscategorizedStatus: FetchStateAndError;
|
|
30
30
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
31
|
+
* Tab badge counts under the filters currently applied to the list
|
|
32
|
+
* (transaction group + Completed sub-tab + search), so each badge matches
|
|
33
|
+
* the rows its tab renders. The active tab's entry is {@link totalCountByTab}
|
|
34
|
+
* itself, so it cannot drift when a cache hit skips the fetch; the inactive
|
|
35
|
+
* tab's comes from the listing response's `other_tab_total_count`. Used
|
|
36
|
+
* exclusively to drive the navbar / tab strip badge labels — every other
|
|
37
|
+
* count consumer (pagination, in-list "showing X of Y", save flows) keeps
|
|
38
|
+
* reading {@link totalCountByTab}.
|
|
35
39
|
*/
|
|
36
40
|
parentTabTotalCountByTab: Record<TransactionsTab, number>;
|
|
37
41
|
projectList: ProjectListSelectorView;
|
|
@@ -182,18 +182,35 @@ function getExpenseAutomationTransactionView(state) {
|
|
|
182
182
|
review: monthYearPeriodId != null ? totalCountByReview[monthYearPeriodId] : 0,
|
|
183
183
|
autoCategorized: monthYearPeriodId != null ? totalCountByAutoCat[monthYearPeriodId] : 0,
|
|
184
184
|
};
|
|
185
|
-
//
|
|
186
|
-
//
|
|
187
|
-
//
|
|
188
|
-
//
|
|
185
|
+
// Tab badge counts, used exclusively by the navbar / tab strip badges. Both
|
|
186
|
+
// tabs are counted under the filters applied to the list, so a badge always
|
|
187
|
+
// equals the number of rows that tab shows.
|
|
188
|
+
//
|
|
189
|
+
// The ACTIVE tab prefers its own list count: the two are the same number (the
|
|
190
|
+
// backend's parent_tab_total_count mirrors total_count), but `uiState.totalCount`
|
|
191
|
+
// is restored by every cache path that skips a fetch -- switching back to an
|
|
192
|
+
// already-loaded period, or to a cached Completed sub-tab -- whereas the stored
|
|
193
|
+
// badge is only written when a response lands, so on those paths it would keep
|
|
194
|
+
// showing whatever was fetched last.
|
|
195
|
+
//
|
|
196
|
+
// The `in` check is load-bearing, not defensive: `totalCount` is a per-period
|
|
197
|
+
// map typed as `Record<MonthYearPeriodId, number>`, so indexing it is typed
|
|
198
|
+
// `number` but is `undefined` for any period the active (sub-)tab has not
|
|
199
|
+
// loaded -- the window between switching to a fresh sub-tab and its response
|
|
200
|
+
// landing. Falling back to the stored badge there keeps a real number in the
|
|
201
|
+
// label instead of blanking it.
|
|
189
202
|
const parentTotalCountByTab = expenseAutomationTransactionsViewState.parentTotalCountByTab;
|
|
203
|
+
const storedBadgeByTab = (tab) => monthYearPeriodId != null
|
|
204
|
+
? (parentTotalCountByTab[tab][monthYearPeriodId] ?? 0)
|
|
205
|
+
: 0;
|
|
206
|
+
const badgeForTab = (tab, listCountByPeriod) => selectedTransactionCategorizationTab === tab &&
|
|
207
|
+
monthYearPeriodId != null &&
|
|
208
|
+
monthYearPeriodId in listCountByPeriod
|
|
209
|
+
? listCountByPeriod[monthYearPeriodId]
|
|
210
|
+
: storedBadgeByTab(tab);
|
|
190
211
|
const parentTabTotalCountByTab = {
|
|
191
|
-
review:
|
|
192
|
-
|
|
193
|
-
: 0,
|
|
194
|
-
autoCategorized: monthYearPeriodId != null
|
|
195
|
-
? (parentTotalCountByTab.autoCategorized[monthYearPeriodId] ?? 0)
|
|
196
|
-
: 0,
|
|
212
|
+
review: badgeForTab('review', totalCountByReview),
|
|
213
|
+
autoCategorized: badgeForTab('autoCategorized', totalCountByAutoCat),
|
|
197
214
|
};
|
|
198
215
|
const fetchStateByTab = {
|
|
199
216
|
review: {
|
|
@@ -139,11 +139,14 @@ export type TransactionsViewState = {
|
|
|
139
139
|
*/
|
|
140
140
|
autoCategorizedSubTabCache: Partial<Record<CompletedSubTab, AutoCategorizedSubTabSnapshot>>;
|
|
141
141
|
/**
|
|
142
|
-
* Period-keyed
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
142
|
+
* Period-keyed tab badge counts, scoped per {@link TransactionsTab}. Every
|
|
143
|
+
* count here is taken under the filters currently applied to the list
|
|
144
|
+
* (`transaction_group` + Completed `sub_tab` + search), so a badge always
|
|
145
|
+
* matches the rows that tab renders. The active tab is filled from the
|
|
146
|
+
* listing response's `parent_tab_total_count` and the inactive one from its
|
|
147
|
+
* `other_tab_total_count`. Used exclusively to drive the tab badges — every
|
|
148
|
+
* other count consumer (pagination, in-tab "showing X of Y") keeps reading
|
|
149
|
+
* from {@link TransactionsViewUIState.totalCount}.
|
|
147
150
|
*/
|
|
148
151
|
parentTotalCountByTab: Record<TransactionsTab, Record<MonthYearPeriodId, number>>;
|
|
149
152
|
selectedTransactionCategorizationCompletedSubTab: CompletedSubTab;
|
|
@@ -79,6 +79,13 @@ export interface InvoicingCatalogItemFormView extends SelectorView {
|
|
|
79
79
|
*/
|
|
80
80
|
qboAccountHierarchy: NestedAccountHierarchyForReport[];
|
|
81
81
|
qboClassHierarchy: NestedClassHierarchyForReport[];
|
|
82
|
+
/**
|
|
83
|
+
* The ids within the account tree an income account may be picked from.
|
|
84
|
+
* QuickBooks only accepts an income account on a product, so a price point
|
|
85
|
+
* mapped to anything else — A/R, deferred revenue, a bank account — fails to
|
|
86
|
+
* sync once an invoice carrying it is pushed.
|
|
87
|
+
*/
|
|
88
|
+
qboIncomeAccountIds: string[];
|
|
82
89
|
/**
|
|
83
90
|
* Loading the item, as distinct from this view's own `fetchState`, which
|
|
84
91
|
* tracks the save.
|
|
@@ -50,6 +50,21 @@ const NOT_STARTED = {
|
|
|
50
50
|
error: undefined,
|
|
51
51
|
fetchState: 'Not-Started',
|
|
52
52
|
};
|
|
53
|
+
/**
|
|
54
|
+
* The QuickBooks ids a price point's income account may be picked from.
|
|
55
|
+
*
|
|
56
|
+
* Memoized, and collapsing to one shared empty array while QBO is disconnected:
|
|
57
|
+
* the pages turn this into their picker options and re-seed their form defaults
|
|
58
|
+
* when those change, so a fresh array on every store change would reset the form
|
|
59
|
+
* under the user — including mid-save.
|
|
60
|
+
*/
|
|
61
|
+
const getInvoicingCatalogIncomeAccountIds = (0, toolkit_1.createSelector)([
|
|
62
|
+
invoicingQboViewSelector_1.getInvoicingQboAccountOptions,
|
|
63
|
+
(state) => (0, invoicingConfigViewSelector_1.getInvoicingConfigView)(state).qboAccountMappingKindOptions,
|
|
64
|
+
invoicingQboViewSelector_1.isInvoicingQboConnected,
|
|
65
|
+
], (accounts, qboAccountMappingKindOptions, isQboConnected) => isQboConnected
|
|
66
|
+
? (0, invoicingQboViewSelector_1.invoicingQboAccountIdsForMappingSlot)(accounts, qboAccountMappingKindOptions, invoicingQboViewSelector_1.INVOICING_INCOME_ACCOUNT_MAPPING_SLOT, invoicingQboViewSelector_1.INVOICING_DEFAULT_INCOME_ACCOUNT_TYPES)
|
|
67
|
+
: invoicingQboViewSelector_1.NO_INVOICING_ACCOUNT_IDS);
|
|
53
68
|
const getInvoicingCatalogItemFormView = (state, id) => {
|
|
54
69
|
const { editDraftById, error, fetchState, newItemDraft, savedItemId, savedKind, } = state.editInvoicingCatalogItemDetailViewState;
|
|
55
70
|
const plan = id != null ? (0, planSelector_1.getInvoicingPlanById)(state.invoicingPlanState, id) : undefined;
|
|
@@ -100,8 +115,9 @@ const getInvoicingCatalogItemFormView = (state, id) => {
|
|
|
100
115
|
isFormLoading: (0, invoicingQboViewSelector_1.isInvoicingAccountingPickerDataLoading)(state) ||
|
|
101
116
|
(0, invoicingFormDraft_1.isInvoicingFormDraftPending)(editDraftById, id),
|
|
102
117
|
isQboPickerDataLoading: (0, invoicingQboViewSelector_1.isInvoicingAccountingPickerDataLoading)(state),
|
|
103
|
-
qboAccountHierarchy: qboView?.nestedAccountHierarchy ??
|
|
104
|
-
qboClassHierarchy: qboView?.nestedClassHierarchy ??
|
|
118
|
+
qboAccountHierarchy: qboView?.nestedAccountHierarchy ?? invoicingQboViewSelector_1.NO_INVOICING_ACCOUNT_HIERARCHY,
|
|
119
|
+
qboClassHierarchy: qboView?.nestedClassHierarchy ?? invoicingQboViewSelector_1.NO_INVOICING_CLASS_HIERARCHY,
|
|
120
|
+
qboIncomeAccountIds: getInvoicingCatalogIncomeAccountIds(state),
|
|
105
121
|
applicabilityValues: invoicingCatalogItemFormHelper_1.INVOICING_CATALOG_APPLICABILITY_VALUES,
|
|
106
122
|
applicableItemOptions,
|
|
107
123
|
localData,
|
package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewSelector.d.ts
CHANGED
|
@@ -82,8 +82,9 @@ export interface InvoicingCouponFormView extends EditInvoicingCouponDetailView {
|
|
|
82
82
|
/**
|
|
83
83
|
* The account tree the discounts-account picker renders, and the QuickBooks
|
|
84
84
|
* ids within it the discounts slot accepts. Two values rather than a filtered
|
|
85
|
-
* tree: the picker
|
|
86
|
-
*
|
|
85
|
+
* tree: the picker flattens the tree into options by walking each node's
|
|
86
|
+
* children, so dropping a parent that is not itself an income account would
|
|
87
|
+
* drop its income descendants with it.
|
|
87
88
|
*
|
|
88
89
|
* Empty until QBO is connected — the form must not offer a mapping that
|
|
89
90
|
* cannot be pushed.
|
package/lib/view/invoicing/editInvoicingCouponDetailView/editInvoicingCouponDetailViewSelector.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getInvoicingCouponFormView = exports.getEditInvoicingCouponDetailViewState = void 0;
|
|
4
|
+
const toolkit_1 = require("@reduxjs/toolkit");
|
|
4
5
|
const reduceFetchState_1 = require("../../../commonStateTypes/reduceFetchState");
|
|
5
6
|
const couponSelector_1 = require("../../../entity/invoicing/coupon/couponSelector");
|
|
6
7
|
const invoicingCommonPayload_1 = require("../../../entity/invoicing/invoicingCommonPayload");
|
|
@@ -14,6 +15,21 @@ const editInvoicingCouponDetailViewState_1 = require("./editInvoicingCouponDetai
|
|
|
14
15
|
* the id of the coupon last saved, and — when a `couponId` is passed (edit
|
|
15
16
|
* mode) — the existing coupon entity to prefill the form.
|
|
16
17
|
*/
|
|
18
|
+
/**
|
|
19
|
+
* The QuickBooks ids the discounts account may be picked from.
|
|
20
|
+
*
|
|
21
|
+
* Memoized, and collapsing to one shared empty array while QBO is disconnected:
|
|
22
|
+
* the form turns this into its picker options and re-seeds its defaults when
|
|
23
|
+
* those change, so a fresh array on every store change would reset the form
|
|
24
|
+
* under the user until their first edit.
|
|
25
|
+
*/
|
|
26
|
+
const getInvoicingCouponDiscountsAccountIds = (0, toolkit_1.createSelector)([
|
|
27
|
+
invoicingQboViewSelector_1.getInvoicingQboAccountOptions,
|
|
28
|
+
(state) => (0, invoicingConfigViewSelector_1.getInvoicingConfigView)(state).qboAccountMappingKindOptions,
|
|
29
|
+
invoicingQboViewSelector_1.isInvoicingQboConnected,
|
|
30
|
+
], (accounts, qboAccountMappingKindOptions, isQboConnected) => isQboConnected
|
|
31
|
+
? (0, invoicingQboViewSelector_1.invoicingQboAccountIdsForMappingSlot)(accounts, qboAccountMappingKindOptions, invoicingQboViewSelector_1.INVOICING_DISCOUNTS_ACCOUNT_MAPPING_SLOT, invoicingQboViewSelector_1.INVOICING_DEFAULT_INCOME_ACCOUNT_TYPES)
|
|
32
|
+
: invoicingQboViewSelector_1.NO_INVOICING_ACCOUNT_IDS);
|
|
17
33
|
const NOT_STARTED = {
|
|
18
34
|
error: undefined,
|
|
19
35
|
fetchState: 'Not-Started',
|
|
@@ -55,14 +71,6 @@ const getEditInvoicingCouponDetailViewState = (state, couponId) => {
|
|
|
55
71
|
};
|
|
56
72
|
};
|
|
57
73
|
exports.getEditInvoicingCouponDetailViewState = getEditInvoicingCouponDetailViewState;
|
|
58
|
-
/**
|
|
59
|
-
* The account types the discounts slot falls back to when the config has no
|
|
60
|
-
* `discounts_account` kind. A QuickBooks discount line posts to an income
|
|
61
|
-
* account; offering every account instead would let a save be rejected.
|
|
62
|
-
*/
|
|
63
|
-
const DEFAULT_DISCOUNTS_ACCOUNT_TYPES = 'Income';
|
|
64
|
-
/** The account-mapping slot a coupon's discounts account shares with settings. */
|
|
65
|
-
const DISCOUNTS_ACCOUNT_MAPPING_SLOT = 'discounts_account';
|
|
66
74
|
/**
|
|
67
75
|
* Bundled view for the discount form screen: the edit view (save state + the
|
|
68
76
|
* coupon to prefill in edit mode), the draft `localData` (seeded from the
|
|
@@ -78,7 +86,7 @@ const getInvoicingCouponFormView = (state, couponId) => {
|
|
|
78
86
|
const localData = couponId != null
|
|
79
87
|
? (0, invoicingFormDraft_1.getInvoicingFormDraftLocalData)(editDraftById, couponId, editInvoicingCouponDetailViewState_1.initialInvoicingCouponFormLocalData)
|
|
80
88
|
: newCouponDraft;
|
|
81
|
-
const { billingPeriodUnitOptions, discountApplyOnOptions, discountDurationTypeOptions, discountTypeOptions,
|
|
89
|
+
const { billingPeriodUnitOptions, discountApplyOnOptions, discountDurationTypeOptions, discountTypeOptions, } = (0, invoicingConfigViewSelector_1.getInvoicingConfigView)(state);
|
|
82
90
|
const isQboConnected = (0, invoicingQboViewSelector_1.isInvoicingQboConnected)(state);
|
|
83
91
|
const qboView = isQboConnected ? (0, invoicingQboViewSelector_1.getInvoicingQboView)(state) : undefined;
|
|
84
92
|
const isQboPickerDataLoading = (0, invoicingQboViewSelector_1.isInvoicingAccountingPickerDataLoading)(state);
|
|
@@ -88,14 +96,6 @@ const getInvoicingCouponFormView = (state, couponId) => {
|
|
|
88
96
|
const isCreateSeedPending = couponId == null &&
|
|
89
97
|
(settingsFetchState === 'Not-Started' ||
|
|
90
98
|
settingsFetchState === 'In-Progress');
|
|
91
|
-
// The account types the discounts slot accepts come from the same config the
|
|
92
|
-
// QBO settings page reads, so the two pickers offer the same accounts and
|
|
93
|
-
// widening the slot stays a config change. Matched on the slot rather than
|
|
94
|
-
// the code as written: a config that names the kind `discounts_account_id`
|
|
95
|
-
// is the same slot, and missing it here would quietly fall back to the
|
|
96
|
-
// default and offer a different set than the settings page does.
|
|
97
|
-
const discountsAccountTypes = qboAccountMappingKindOptions.find((kindOption) => (0, invoicingCommonPayload_1.toInvoicingQboAccountMappingSlot)(kindOption.code) ===
|
|
98
|
-
DISCOUNTS_ACCOUNT_MAPPING_SLOT)?.accountTypes ?? DEFAULT_DISCOUNTS_ACCOUNT_TYPES;
|
|
99
99
|
return {
|
|
100
100
|
...base,
|
|
101
101
|
applyOnOptions: discountApplyOnOptions.map(invoicingCommonPayload_1.toInvoicingFormOption),
|
|
@@ -134,8 +134,8 @@ const getInvoicingCouponFormView = (state, couponId) => {
|
|
|
134
134
|
},
|
|
135
135
|
mode: couponId != null ? 'edit' : 'create',
|
|
136
136
|
periodUnitOptions: billingPeriodUnitOptions.map(invoicingCommonPayload_1.toInvoicingFormOption),
|
|
137
|
-
qboAccountHierarchy: qboView?.nestedAccountHierarchy ??
|
|
138
|
-
qboIncomeAccountIds: (
|
|
137
|
+
qboAccountHierarchy: qboView?.nestedAccountHierarchy ?? invoicingQboViewSelector_1.NO_INVOICING_ACCOUNT_HIERARCHY,
|
|
138
|
+
qboIncomeAccountIds: getInvoicingCouponDiscountsAccountIds(state),
|
|
139
139
|
};
|
|
140
140
|
};
|
|
141
141
|
exports.getInvoicingCouponFormView = getInvoicingCouponFormView;
|
|
@@ -3,6 +3,7 @@ import { NestedClassHierarchyForReport } from '../../../commonStateTypes/classes
|
|
|
3
3
|
import { FetchStateAndError } from '../../../commonStateTypes/common';
|
|
4
4
|
import { AccountBase } from '../../../entity/account/accountState';
|
|
5
5
|
import { ClassBase } from '../../../entity/class/classState';
|
|
6
|
+
import { InvoicingQboAccountMappingKindOption } from '../../../entity/invoicing/invoicingCommonPayload';
|
|
6
7
|
import { RootState } from '../../../rootStateTypes';
|
|
7
8
|
import { InvoicingQboConnection, InvoicingQboSyncHealth } from './invoicingQboViewPayload';
|
|
8
9
|
export declare const INVOICING_ACCOUNT_LIST_KEY: "accountList";
|
|
@@ -60,6 +61,17 @@ export interface InvoicingQboView {
|
|
|
60
61
|
connection?: InvoicingQboConnection;
|
|
61
62
|
syncHealth?: InvoicingQboSyncHealth;
|
|
62
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Accounts as the invoicing pickers need them, from the shared
|
|
66
|
+
* accounting-service list, so whatever another screen already loaded is reused.
|
|
67
|
+
* `qboId` is the submitted value because that is what the invoicing API stores;
|
|
68
|
+
* an account without one cannot be posted, so it is dropped rather than offered.
|
|
69
|
+
*
|
|
70
|
+
* Memoized on the two slices it reads: the pickers and the lists derived from
|
|
71
|
+
* them are handed straight to forms, and a fresh array on every store change
|
|
72
|
+
* re-seeds a form the user is editing.
|
|
73
|
+
*/
|
|
74
|
+
export declare const getInvoicingQboAccountOptions: (state: RootState) => InvoicingAccountingOption[];
|
|
63
75
|
/**
|
|
64
76
|
* The accounts valid for one QBO mapping kind, whose `accountTypes` is a
|
|
65
77
|
* comma-separated list of QuickBooks type names. An unrecognised list yields no
|
|
@@ -67,6 +79,43 @@ export interface InvoicingQboView {
|
|
|
67
79
|
* required would post a mapping QuickBooks rejects.
|
|
68
80
|
*/
|
|
69
81
|
export declare const invoicingAccountsForQboAccountTypes: (accounts: InvoicingAccountingOption[], accountTypes: string) => InvoicingAccountingOption[];
|
|
82
|
+
/**
|
|
83
|
+
* The account-mapping slot a catalog price point's income account shares with
|
|
84
|
+
* the settings page, and the one a discount's account shares with it.
|
|
85
|
+
*/
|
|
86
|
+
export declare const INVOICING_INCOME_ACCOUNT_MAPPING_SLOT = "default_income_account";
|
|
87
|
+
export declare const INVOICING_DISCOUNTS_ACCOUNT_MAPPING_SLOT = "discounts_account";
|
|
88
|
+
/**
|
|
89
|
+
* The account types a slot falls back to when the config carries no kind for
|
|
90
|
+
* it. QuickBooks posts a product, a price and a discount line to an income
|
|
91
|
+
* account; offering every account instead would let a save be rejected.
|
|
92
|
+
*/
|
|
93
|
+
export declare const INVOICING_DEFAULT_INCOME_ACCOUNT_TYPES = "Income";
|
|
94
|
+
/**
|
|
95
|
+
* The QuickBooks ids a mapping slot's picker may offer, from the account types
|
|
96
|
+
* the config gives that slot — so every picker filling the same slot offers the
|
|
97
|
+
* same accounts, and widening one stays a config change.
|
|
98
|
+
*
|
|
99
|
+
* Ids rather than a filtered tree: the pickers flatten the tree into options by
|
|
100
|
+
* walking each node's children, so dropping a parent that is not itself of the
|
|
101
|
+
* wanted type would drop its matching descendants with it.
|
|
102
|
+
*
|
|
103
|
+
* Matched on the slot rather than the code as written, since a config naming
|
|
104
|
+
* the kind `discounts_account_id` means the same slot. A slot the config does
|
|
105
|
+
* not carry falls back to `defaultAccountTypes` rather than to every account.
|
|
106
|
+
*/
|
|
107
|
+
export declare const invoicingQboAccountIdsForMappingSlot: (accounts: InvoicingAccountingOption[], accountMappingKindOptions: InvoicingQboAccountMappingKindOption[], mappingSlot: string, defaultAccountTypes: string) => string[];
|
|
108
|
+
/**
|
|
109
|
+
* Stable empties for a tenant with no QBO connection.
|
|
110
|
+
*
|
|
111
|
+
* `?? []` builds a fresh array per call, and the invoicing forms re-seed their
|
|
112
|
+
* fields whenever their option lists change identity — so a form open against a
|
|
113
|
+
* disconnected tenant would reset itself on every unrelated store change, until
|
|
114
|
+
* the first edit disarms the re-seed.
|
|
115
|
+
*/
|
|
116
|
+
export declare const NO_INVOICING_ACCOUNT_HIERARCHY: NestedAccountHierarchyForReport[];
|
|
117
|
+
export declare const NO_INVOICING_CLASS_HIERARCHY: NestedClassHierarchyForReport[];
|
|
118
|
+
export declare const NO_INVOICING_ACCOUNT_IDS: string[];
|
|
70
119
|
/**
|
|
71
120
|
* Single bundled view for the QBO integration settings screen — the
|
|
72
121
|
* connection, the account and class options, sync health, and the fetch/action
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getInvoicingQboView = exports.invoicingAccountsForQboAccountTypes = exports.getInvoicingCatalogAccountingLookup = exports.invoicingQboClassByQboId = exports.invoicingQboAccountByQboId = exports.getInvoicingQboConnectionFetchState = exports.isInvoicingAccountingPickerDataLoading = exports.isInvoicingQboConnected = exports.INVOICING_ACCOUNT_LIST_KEY = void 0;
|
|
3
|
+
exports.getInvoicingQboView = exports.NO_INVOICING_ACCOUNT_IDS = exports.NO_INVOICING_CLASS_HIERARCHY = exports.NO_INVOICING_ACCOUNT_HIERARCHY = exports.invoicingQboAccountIdsForMappingSlot = exports.INVOICING_DEFAULT_INCOME_ACCOUNT_TYPES = exports.INVOICING_DISCOUNTS_ACCOUNT_MAPPING_SLOT = exports.INVOICING_INCOME_ACCOUNT_MAPPING_SLOT = exports.invoicingAccountsForQboAccountTypes = exports.getInvoicingQboAccountOptions = exports.getInvoicingCatalogAccountingLookup = exports.invoicingQboClassByQboId = exports.invoicingQboAccountByQboId = exports.getInvoicingQboConnectionFetchState = exports.isInvoicingAccountingPickerDataLoading = exports.isInvoicingQboConnected = exports.INVOICING_ACCOUNT_LIST_KEY = void 0;
|
|
4
|
+
const toolkit_1 = require("@reduxjs/toolkit");
|
|
5
|
+
const invoicingCommonPayload_1 = require("../../../entity/invoicing/invoicingCommonPayload");
|
|
4
6
|
const accountListSelector_1 = require("../../accountList/accountListSelector");
|
|
5
7
|
const classListSelector_1 = require("../../classList/classListSelector");
|
|
6
8
|
// The shared bucket, fetched with the same arguments as the other consumers so
|
|
@@ -91,14 +93,20 @@ const getInvoicingCatalogAccountingLookup = (state) => ({
|
|
|
91
93
|
});
|
|
92
94
|
exports.getInvoicingCatalogAccountingLookup = getInvoicingCatalogAccountingLookup;
|
|
93
95
|
/**
|
|
94
|
-
* Accounts
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
96
|
+
* Accounts as the invoicing pickers need them, from the shared
|
|
97
|
+
* accounting-service list, so whatever another screen already loaded is reused.
|
|
98
|
+
* `qboId` is the submitted value because that is what the invoicing API stores;
|
|
99
|
+
* an account without one cannot be posted, so it is dropped rather than offered.
|
|
100
|
+
*
|
|
101
|
+
* Memoized on the two slices it reads: the pickers and the lists derived from
|
|
102
|
+
* them are handed straight to forms, and a fresh array on every store change
|
|
103
|
+
* re-seeds a form the user is editing.
|
|
99
104
|
*/
|
|
100
|
-
|
|
101
|
-
|
|
105
|
+
exports.getInvoicingQboAccountOptions = (0, toolkit_1.createSelector)([
|
|
106
|
+
(state) => state.accountState,
|
|
107
|
+
(state) => state.accountListState,
|
|
108
|
+
], (accountState, accountListState) => {
|
|
109
|
+
const { accounts } = (0, accountListSelector_1.getAccountList)(accountState, accountListState, exports.INVOICING_ACCOUNT_LIST_KEY);
|
|
102
110
|
return accounts.flatMap((account) => {
|
|
103
111
|
if (account.qboId == null || account.isDeleted === true) {
|
|
104
112
|
return [];
|
|
@@ -111,7 +119,7 @@ const invoicingAccountingOptions = (state) => {
|
|
|
111
119
|
},
|
|
112
120
|
];
|
|
113
121
|
});
|
|
114
|
-
};
|
|
122
|
+
});
|
|
115
123
|
/**
|
|
116
124
|
* Normalises an account-type name for comparison. The config's mapping kinds
|
|
117
125
|
* name QuickBooks types the way QuickBooks displays them ("Other Current
|
|
@@ -148,6 +156,47 @@ const invoicingAccountsForQboAccountTypes = (accounts, accountTypes) => {
|
|
|
148
156
|
wanted.has(normalizeAccountTypeName(account.accountType)));
|
|
149
157
|
};
|
|
150
158
|
exports.invoicingAccountsForQboAccountTypes = invoicingAccountsForQboAccountTypes;
|
|
159
|
+
/**
|
|
160
|
+
* The account-mapping slot a catalog price point's income account shares with
|
|
161
|
+
* the settings page, and the one a discount's account shares with it.
|
|
162
|
+
*/
|
|
163
|
+
exports.INVOICING_INCOME_ACCOUNT_MAPPING_SLOT = 'default_income_account';
|
|
164
|
+
exports.INVOICING_DISCOUNTS_ACCOUNT_MAPPING_SLOT = 'discounts_account';
|
|
165
|
+
/**
|
|
166
|
+
* The account types a slot falls back to when the config carries no kind for
|
|
167
|
+
* it. QuickBooks posts a product, a price and a discount line to an income
|
|
168
|
+
* account; offering every account instead would let a save be rejected.
|
|
169
|
+
*/
|
|
170
|
+
exports.INVOICING_DEFAULT_INCOME_ACCOUNT_TYPES = 'Income';
|
|
171
|
+
/**
|
|
172
|
+
* The QuickBooks ids a mapping slot's picker may offer, from the account types
|
|
173
|
+
* the config gives that slot — so every picker filling the same slot offers the
|
|
174
|
+
* same accounts, and widening one stays a config change.
|
|
175
|
+
*
|
|
176
|
+
* Ids rather than a filtered tree: the pickers flatten the tree into options by
|
|
177
|
+
* walking each node's children, so dropping a parent that is not itself of the
|
|
178
|
+
* wanted type would drop its matching descendants with it.
|
|
179
|
+
*
|
|
180
|
+
* Matched on the slot rather than the code as written, since a config naming
|
|
181
|
+
* the kind `discounts_account_id` means the same slot. A slot the config does
|
|
182
|
+
* not carry falls back to `defaultAccountTypes` rather than to every account.
|
|
183
|
+
*/
|
|
184
|
+
const invoicingQboAccountIdsForMappingSlot = (accounts, accountMappingKindOptions, mappingSlot, defaultAccountTypes) => {
|
|
185
|
+
const accountTypes = accountMappingKindOptions.find((kindOption) => (0, invoicingCommonPayload_1.toInvoicingQboAccountMappingSlot)(kindOption.code) === mappingSlot)?.accountTypes ?? defaultAccountTypes;
|
|
186
|
+
return (0, exports.invoicingAccountsForQboAccountTypes)(accounts, accountTypes).map((account) => account.id);
|
|
187
|
+
};
|
|
188
|
+
exports.invoicingQboAccountIdsForMappingSlot = invoicingQboAccountIdsForMappingSlot;
|
|
189
|
+
/**
|
|
190
|
+
* Stable empties for a tenant with no QBO connection.
|
|
191
|
+
*
|
|
192
|
+
* `?? []` builds a fresh array per call, and the invoicing forms re-seed their
|
|
193
|
+
* fields whenever their option lists change identity — so a form open against a
|
|
194
|
+
* disconnected tenant would reset itself on every unrelated store change, until
|
|
195
|
+
* the first edit disarms the re-seed.
|
|
196
|
+
*/
|
|
197
|
+
exports.NO_INVOICING_ACCOUNT_HIERARCHY = [];
|
|
198
|
+
exports.NO_INVOICING_CLASS_HIERARCHY = [];
|
|
199
|
+
exports.NO_INVOICING_ACCOUNT_IDS = [];
|
|
151
200
|
/** Classes as the invoicing pickers need them, from the shared class list. */
|
|
152
201
|
const invoicingAccountingClassOptions = (state) => {
|
|
153
202
|
const { classes } = (0, classListSelector_1.getClassList)(state.classState, state.classListState);
|
|
@@ -169,7 +218,7 @@ const getInvoicingQboView = (state) => {
|
|
|
169
218
|
const qboState = state.invoicingQboViewState;
|
|
170
219
|
const accountList = state.accountListState.byReportId[exports.INVOICING_ACCOUNT_LIST_KEY];
|
|
171
220
|
return {
|
|
172
|
-
accounts:
|
|
221
|
+
accounts: (0, exports.getInvoicingQboAccountOptions)(state),
|
|
173
222
|
accountsFetchState: {
|
|
174
223
|
fetchState: accountList.fetchState,
|
|
175
224
|
error: accountList.error,
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.saveNotificationPreferencesEpic = void 0;
|
|
4
4
|
const rxjs_1 = require("rxjs");
|
|
5
5
|
const operators_1 = require("rxjs/operators");
|
|
6
|
+
const notificationRegistryState_1 = require("../../../entity/notificationRegistry/notificationRegistryState");
|
|
6
7
|
const snackbarReducer_1 = require("../../../entity/snackbar/snackbarReducer");
|
|
7
8
|
const responsePayload_1 = require("../../../responsePayload");
|
|
8
9
|
const notificationPreferencesEndpoint_1 = require("../notificationPreferencesEndpoint");
|
|
@@ -16,9 +17,19 @@ const saveNotificationPreferencesEpic = (actions$, state$, zeniAPI) => actions$.
|
|
|
16
17
|
// ignored, so stale success/failure actions cannot clobber the newer
|
|
17
18
|
// batch's state. Server-side ordering is arrival-order LWW.
|
|
18
19
|
(0, operators_1.switchMap)(([, state]) => {
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
20
|
+
// A clean domain is omitted entirely: an empty patch is still a write against it.
|
|
21
|
+
const overridesByDomain = {};
|
|
22
|
+
const body = {};
|
|
23
|
+
notificationRegistryState_1.NOTIFICATION_DOMAINS.forEach((domain) => {
|
|
24
|
+
const overrides = (0, notificationPreferencesViewSelector_1.getNotificationLocalOverridesForDomain)(state, domain);
|
|
25
|
+
const preferencesPatch = (0, notificationPreferencesViewPayload_1.mapPreferencesToPayload)(overrides);
|
|
26
|
+
if (Object.keys(preferencesPatch).length === 0) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
overridesByDomain[domain] = overrides;
|
|
30
|
+
body[`${domain}_preferences`] = preferencesPatch;
|
|
31
|
+
});
|
|
32
|
+
if (Object.keys(body).length === 0) {
|
|
22
33
|
// No diff → do not dispatch a synthetic success (that would wipe
|
|
23
34
|
// stored preferences via the reducer). Simply no-op.
|
|
24
35
|
return rxjs_1.EMPTY;
|
|
@@ -31,7 +42,6 @@ const saveNotificationPreferencesEpic = (actions$, state$, zeniAPI) => actions$.
|
|
|
31
42
|
// in-flight save's response (Success/Failure never dispatched, so
|
|
32
43
|
// the counter never drained and future saves got their merge dropped).
|
|
33
44
|
const cancelEpochAtDispatch = state.notificationPreferencesViewState.cancelEpoch;
|
|
34
|
-
const body = { task_checklist_preferences: preferencesPatch };
|
|
35
45
|
// Suppress the error snackbar when the response lands AFTER the user
|
|
36
46
|
// pressed Cancel — the Failure reducer already swallows the state
|
|
37
47
|
// update, so the toast would be a stale error for a save the user
|
|
@@ -60,8 +70,11 @@ const saveNotificationPreferencesEpic = (actions$, state$, zeniAPI) => actions$.
|
|
|
60
70
|
if ((0, responsePayload_1.isSuccessResponse)(response)) {
|
|
61
71
|
return (0, rxjs_1.of)((0, notificationPreferencesViewReducer_1.saveNotificationPreferencesSuccess)({
|
|
62
72
|
cancelEpochAtDispatch,
|
|
63
|
-
|
|
64
|
-
|
|
73
|
+
savedOverridesByDomain: overridesByDomain,
|
|
74
|
+
serverEchoByDomain: {
|
|
75
|
+
task_checklist: response.data?.task_checklist_preferences,
|
|
76
|
+
commenting: response.data?.commenting_preferences,
|
|
77
|
+
},
|
|
65
78
|
}));
|
|
66
79
|
}
|
|
67
80
|
const actions = [
|
|
@@ -1,30 +1,33 @@
|
|
|
1
|
-
import { NotificationChannel, NotificationFrequency } from '../../entity/notificationRegistry/notificationRegistryState';
|
|
1
|
+
import { NotificationChannel, NotificationDomain, NotificationFrequency } from '../../entity/notificationRegistry/notificationRegistryState';
|
|
2
2
|
import { ZeniAPIStatus } from '../../responsePayload';
|
|
3
3
|
import { NotificationPreferencesPayload } from './notificationPreferencesViewPayload';
|
|
4
|
-
import {
|
|
4
|
+
import { NotificationPreferencesByDomain, NotificationPreferencesViewState } from './notificationPreferencesViewState';
|
|
5
5
|
export declare const initialState: NotificationPreferencesViewState;
|
|
6
6
|
export interface SetFrequencyPayload {
|
|
7
7
|
frequency: NotificationFrequency;
|
|
8
8
|
groupId: string;
|
|
9
|
+
domain?: NotificationDomain;
|
|
9
10
|
}
|
|
10
11
|
export interface TogglePreferencePayload {
|
|
11
12
|
channel: NotificationChannel;
|
|
12
13
|
enabled: boolean;
|
|
13
14
|
eventId: string;
|
|
15
|
+
domain?: NotificationDomain;
|
|
14
16
|
}
|
|
15
17
|
export interface SetGroupChannelMasterPayload {
|
|
16
18
|
channel: NotificationChannel;
|
|
17
19
|
enabled: boolean;
|
|
18
20
|
groupId: string;
|
|
21
|
+
domain?: NotificationDomain;
|
|
19
22
|
}
|
|
20
23
|
export interface FetchNotificationPreferencesSuccessPayload {
|
|
21
|
-
|
|
24
|
+
preferencesByDomain: Partial<Record<NotificationDomain, NotificationPreferencesPayload | undefined>>;
|
|
22
25
|
saveEpochAtDispatch: number;
|
|
23
26
|
}
|
|
24
27
|
export interface SaveNotificationPreferencesSuccessPayload {
|
|
25
28
|
cancelEpochAtDispatch: number;
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
savedOverridesByDomain: NotificationPreferencesByDomain;
|
|
30
|
+
serverEchoByDomain: Partial<Record<NotificationDomain, NotificationPreferencesPayload | undefined>>;
|
|
28
31
|
}
|
|
29
32
|
export interface SaveNotificationPreferencesFailurePayload {
|
|
30
33
|
cancelEpochAtDispatch: number;
|