@zeniai/client-epic-state 5.2.32 → 5.2.34-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/commonPayloadTypes/classesView/reportByClassPayloadV2.d.ts +13 -1
- 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/sectionClassesViewV2/sectionClassesViewEpic.js +10 -7
- package/lib/entity/sectionClassesViewV2/sectionClassesViewReducer.d.ts +3 -3
- package/lib/entity/sectionProjectView/sectionProjectViewEpic.js +6 -2
- package/lib/entity/sectionProjectView/sectionProjectViewReducer.d.ts +3 -3
- package/lib/entity/sectionProjectView/sectionProjectViewReducer.js +6 -3
- package/lib/epic.js +12 -0
- package/lib/esm/entity/class/classReducer.js +1 -1
- 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/sectionClassesViewV2/sectionClassesViewEpic.js +10 -7
- package/lib/esm/entity/sectionProjectView/sectionProjectViewEpic.js +6 -2
- package/lib/esm/entity/sectionProjectView/sectionProjectViewReducer.js +7 -4
- package/lib/esm/epic.js +12 -0
- package/lib/esm/index.js +6 -6
- package/lib/esm/view/aiCfoView/aiCfoViewReducer.js +268 -1
- package/lib/esm/view/aiCfoView/aiCfoViewSelector.js +50 -0
- package/lib/esm/view/aiCfoView/epics/deleteRoutineEpic.js +35 -0
- package/lib/esm/view/aiCfoView/epics/fetchRoutineRunsEpic.js +37 -0
- package/lib/esm/view/aiCfoView/epics/fetchRoutinesEpic.js +37 -0
- package/lib/esm/view/aiCfoView/epics/runRoutineEpic.js +34 -0
- package/lib/esm/view/aiCfoView/epics/saveRoutineEpic.js +65 -0
- package/lib/esm/view/aiCfoView/epics/setRoutineEnabledEpic.js +28 -0
- package/lib/esm/view/aiCfoView/epics/toRoutine.js +64 -0
- package/lib/esm/view/aiCfoView/epics/toRoutineRun.js +42 -0
- package/lib/esm/view/expenseAutomationView/selectors/fluxAnalysisViewSelector.js +12 -10
- package/lib/esm/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +3 -11
- package/lib/esm/view/expenseAutomationView/selectors/missingReceiptsSelector.js +10 -11
- package/lib/esm/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewPayload.js +4 -0
- 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 +8 -8
- package/lib/index.js +63 -41
- package/lib/view/aiCfoView/aiCfoViewPayload.d.ts +90 -0
- package/lib/view/aiCfoView/aiCfoViewReducer.d.ts +164 -123
- package/lib/view/aiCfoView/aiCfoViewReducer.js +270 -3
- package/lib/view/aiCfoView/aiCfoViewSelector.d.ts +13 -1
- package/lib/view/aiCfoView/aiCfoViewSelector.js +55 -0
- package/lib/view/aiCfoView/aiCfoViewState.d.ts +157 -0
- package/lib/view/aiCfoView/epics/deleteRoutineEpic.d.ts +18 -0
- package/lib/view/aiCfoView/epics/deleteRoutineEpic.js +39 -0
- package/lib/view/aiCfoView/epics/fetchRoutineRunsEpic.d.ts +13 -0
- package/lib/view/aiCfoView/epics/fetchRoutineRunsEpic.js +41 -0
- package/lib/view/aiCfoView/epics/fetchRoutinesEpic.d.ts +7 -0
- package/lib/view/aiCfoView/epics/fetchRoutinesEpic.js +41 -0
- package/lib/view/aiCfoView/epics/runRoutineEpic.d.ts +14 -0
- package/lib/view/aiCfoView/epics/runRoutineEpic.js +38 -0
- package/lib/view/aiCfoView/epics/saveRoutineEpic.d.ts +13 -0
- package/lib/view/aiCfoView/epics/saveRoutineEpic.js +69 -0
- package/lib/view/aiCfoView/epics/setRoutineEnabledEpic.d.ts +15 -0
- package/lib/view/aiCfoView/epics/setRoutineEnabledEpic.js +32 -0
- package/lib/view/aiCfoView/epics/toRoutine.d.ts +17 -0
- package/lib/view/aiCfoView/epics/toRoutine.js +69 -0
- package/lib/view/aiCfoView/epics/toRoutineRun.d.ts +12 -0
- package/lib/view/aiCfoView/epics/toRoutineRun.js +47 -0
- package/lib/view/cashFlowClassesView/cashFlowClassesViewPayload.d.ts +4 -4
- package/lib/view/cashFlowProjectView/cashFlowProjectViewPayload.d.ts +4 -4
- package/lib/view/expenseAutomationView/selectors/fluxAnalysisViewSelector.js +12 -10
- package/lib/view/expenseAutomationView/selectors/jeSchedulesViewSelector.js +3 -11
- package/lib/view/expenseAutomationView/selectors/missingReceiptsSelector.js +10 -11
- package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewPayload.d.ts +1 -11
- package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewPayload.js +4 -0
- package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer.d.ts +1 -2
- package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewSelector.d.ts +1 -2
- package/lib/view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewState.d.ts +15 -1
- package/lib/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewReducer.d.ts +1 -1
- package/lib/view/invoicing/invoicingCustomerListView/invoicingCustomerListViewState.d.ts +1 -1
- 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/profitAndLossProjectView/profitAndLossProjectViewPayload.d.ts +12 -0
- package/lib/view/settingsView/epic/fetchNotificationSettingsEpic.js +12 -2
- package/lib/view/settingsView/settingsViewPayload.d.ts +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { of } from 'rxjs';
|
|
2
|
+
import { catchError, filter, mergeMap } from 'rxjs/operators';
|
|
3
|
+
import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
|
|
4
|
+
import { fetchRoutines, saveRoutineFailure, saveRoutineSuccess, setRoutineEnabled, } from '../aiCfoViewReducer';
|
|
5
|
+
/**
|
|
6
|
+
* PUT /1.0/routines/{scheduleId} with nothing but `enabled`.
|
|
7
|
+
*
|
|
8
|
+
* Separate from `saveRoutineEpic` because pausing is not editing. A routine
|
|
9
|
+
* whose cadence this client version does not recognise has `recurrence: null`
|
|
10
|
+
* and cannot produce a `RoutineDraft` — and that is precisely the routine
|
|
11
|
+
* someone most needs to be able to stop. Sending only `enabled` also means a
|
|
12
|
+
* pause can never rewrite a schedule as a side effect.
|
|
13
|
+
*/
|
|
14
|
+
export const setRoutineEnabledEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(setRoutineEnabled.match),
|
|
15
|
+
// mergeMap: pausing one routine must not cancel pausing another, and these
|
|
16
|
+
// target different rows so they cannot collide the way two saves of one
|
|
17
|
+
// form would.
|
|
18
|
+
mergeMap((action) => {
|
|
19
|
+
const { enabled, scheduleId } = action.payload;
|
|
20
|
+
return zeniAPI
|
|
21
|
+
.putAndGetJSON(`${zeniAPI.apiEndPoints.aiCfoMicroServiceBaseUrl}/1.0/routines/${encodeURIComponent(scheduleId)}`, { enabled })
|
|
22
|
+
.pipe(mergeMap((response) => isSuccessResponse(response)
|
|
23
|
+
? of(saveRoutineSuccess(), fetchRoutines())
|
|
24
|
+
: // Refetch on failure too: the switch was flipped optimistically,
|
|
25
|
+
// and leaving it showing "paused" for a routine that is still
|
|
26
|
+
// running would be the one lie this list must not tell.
|
|
27
|
+
of(saveRoutineFailure(response.status), fetchRoutines())), catchError((error) => of(saveRoutineFailure(createZeniAPIStatus('Unexpected Error', 'Set routine enabled REST API call failed', error instanceof Error ? { message: error.message } : undefined)), fetchRoutines())));
|
|
28
|
+
}));
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
const RECURRENCES = ['daily', 'weekly', 'monthly'];
|
|
2
|
+
const STATUSES = ['succeeded', 'failed', 'timeout'];
|
|
3
|
+
/**
|
|
4
|
+
* A routine is usable if it has an identity. That is the whole bar.
|
|
5
|
+
*
|
|
6
|
+
* `schedule_id` and `name` are what every consumer dereferences, so those are
|
|
7
|
+
* what this establishes.
|
|
8
|
+
*
|
|
9
|
+
* Deliberately NOT also requiring `macro_id`. A routine whose skill was deleted
|
|
10
|
+
* can come back without one — and it is still an active schedule emailing the
|
|
11
|
+
* user's financials. Dropping it here would make it invisible in the UI while
|
|
12
|
+
* it kept running, with no way for anyone to turn it off. Showing a broken row
|
|
13
|
+
* that can be paused or deleted is strictly better than hiding a live one.
|
|
14
|
+
*/
|
|
15
|
+
export const isRoutinePayload = (value) => {
|
|
16
|
+
const candidate = value;
|
|
17
|
+
return (typeof candidate?.schedule_id === 'string' &&
|
|
18
|
+
candidate.schedule_id !== '' &&
|
|
19
|
+
typeof candidate.name === 'string');
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Narrow a server string to a known recurrence, or null.
|
|
23
|
+
*
|
|
24
|
+
* Null, NOT a fallback to 'daily'. A read-side default becomes a write-side
|
|
25
|
+
* value the moment the user opens that routine and saves it — so guessing here
|
|
26
|
+
* would quietly convert a cadence this client does not understand into a daily
|
|
27
|
+
* one, and the owner would find out from the volume of email. Null says "this
|
|
28
|
+
* client does not know", and the UI shows the row so it can still be paused or
|
|
29
|
+
* deleted while refusing to edit its schedule.
|
|
30
|
+
*/
|
|
31
|
+
const toRecurrence = (value) => RECURRENCES.includes(value)
|
|
32
|
+
? value
|
|
33
|
+
: null;
|
|
34
|
+
const toStatus = (value) => STATUSES.includes(value) ? value : null;
|
|
35
|
+
/** Map one routine off the wire. Every default here is a deliberate reading. */
|
|
36
|
+
export const toRoutine = (payload) => ({
|
|
37
|
+
unreadRuns: payload.unread_runs ?? 0,
|
|
38
|
+
consecutiveFailures: payload.consecutive_failures ?? 0,
|
|
39
|
+
dayOfMonth: payload.day_of_month ?? null,
|
|
40
|
+
// Absent reads as enabled: a routine the server returned without the flag is
|
|
41
|
+
// one it intends to run, and defaulting to false would show every row paused.
|
|
42
|
+
enabled: payload.enabled !== false,
|
|
43
|
+
hour: payload.hour ?? 0,
|
|
44
|
+
isAdHoc: payload.is_ad_hoc === true,
|
|
45
|
+
lastRunAt: payload.last_run_at ?? null,
|
|
46
|
+
lastStatus: toStatus(payload.last_status),
|
|
47
|
+
// '' is the sanctioned "unset ID" (CLAUDE.md), not a papered-over absence:
|
|
48
|
+
// the row still renders, and the UI reads this to show it as broken rather
|
|
49
|
+
// than offering to open a skill that is not there.
|
|
50
|
+
macroId: payload.macro_id ?? '',
|
|
51
|
+
minute: payload.minute ?? 0,
|
|
52
|
+
name: payload.name,
|
|
53
|
+
nextRunAt: payload.next_run_at ?? null,
|
|
54
|
+
pinnedVersion: payload.pinned_version ?? null,
|
|
55
|
+
recurrence: toRecurrence(payload.recurrence),
|
|
56
|
+
scheduleId: payload.schedule_id,
|
|
57
|
+
sessionId: payload.session_id ?? null,
|
|
58
|
+
// Null, not a guessed 'UTC'. Same trap as `recurrence`: a read-side default
|
|
59
|
+
// is written straight back on the next save, silently moving the routine's
|
|
60
|
+
// delivery by however many hours the real zone differed by. The server always
|
|
61
|
+
// sends this, so null means something is wrong and the UI should say so.
|
|
62
|
+
tzName: payload.tz_name ?? null,
|
|
63
|
+
weekday: payload.weekday ?? null,
|
|
64
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const STATUSES = [
|
|
2
|
+
'claimed',
|
|
3
|
+
'running',
|
|
4
|
+
'succeeded',
|
|
5
|
+
'failed',
|
|
6
|
+
'timeout',
|
|
7
|
+
];
|
|
8
|
+
/**
|
|
9
|
+
* A run is usable if it has an identity — the same bar `isRoutinePayload` sets.
|
|
10
|
+
*
|
|
11
|
+
* Nothing else is required. A run that is still in flight has no `finished_at`,
|
|
12
|
+
* a claimed one has no `started_at`, and a failed one may have neither an error
|
|
13
|
+
* nor an answer to link to. Requiring any of those would drop exactly the rows
|
|
14
|
+
* the history exists to show.
|
|
15
|
+
*/
|
|
16
|
+
export const isRoutineRunPayload = (value) => {
|
|
17
|
+
const candidate = value;
|
|
18
|
+
return typeof candidate?.run_id === 'string' && candidate.run_id !== '';
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Narrow a server status to one this client knows, or null.
|
|
22
|
+
*
|
|
23
|
+
* Null rather than a fallback, for the same reason `toRecurrence` returns null:
|
|
24
|
+
* a guess here would badge an unknown state as something specific, and on a run
|
|
25
|
+
* history the difference between "failed" and "we don't know" is the whole
|
|
26
|
+
* message. The UI shows an unknown status as neither succeeded nor failed.
|
|
27
|
+
*/
|
|
28
|
+
const toStatus = (value) => STATUSES.find((status) => status === value) ?? null;
|
|
29
|
+
/** Empty strings become null: the server sends '' for an absent deep link. */
|
|
30
|
+
const toId = (value) => value != null && value !== '' ? value : null;
|
|
31
|
+
export const toRoutineRun = (payload) => ({
|
|
32
|
+
runId: payload.run_id,
|
|
33
|
+
attempt: payload.attempt ?? 1,
|
|
34
|
+
isManual: payload.is_manual === true,
|
|
35
|
+
error: toId(payload.error),
|
|
36
|
+
finishedAt: toId(payload.finished_at),
|
|
37
|
+
questionAnswerId: toId(payload.question_answer_id),
|
|
38
|
+
sessionId: toId(payload.session_id),
|
|
39
|
+
scheduledFor: toId(payload.scheduled_for),
|
|
40
|
+
startedAt: toId(payload.started_at),
|
|
41
|
+
status: toStatus(payload.status),
|
|
42
|
+
});
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { reduceAnyFetchState } from '../../../commonStateTypes/reduceFetchState';
|
|
2
1
|
import { toMonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
|
|
3
2
|
import { getAccountBase } from '../../../entity/account/accountSelector';
|
|
4
3
|
import { getClassById } from '../../../entity/class/classSelector';
|
|
@@ -7,7 +6,7 @@ import { getUserByUserId } from '../../../entity/user/userSelector';
|
|
|
7
6
|
import { getVendorByVendorId } from '../../../entity/vendor/vendorSelector';
|
|
8
7
|
import { getAllSteps } from './getAllStepsHelper';
|
|
9
8
|
export function getExpenseAutomationFluxAnalysisView(state) {
|
|
10
|
-
const { expenseAutomationFluxAnalysisViewState, monthEndCloseChecksState
|
|
9
|
+
const { expenseAutomationFluxAnalysisViewState, monthEndCloseChecksState } = state;
|
|
11
10
|
const { fetchState, error, lastRefreshSuccessTime, refreshStatus, uiState, reviewOperatingExpenseIdsByPeriod, selectedSectionIdsByPeriod, groupsBySelectedPeriod, fluxAnalysisEntities, bulkReviewStatus, currency, totalBalancesAndVariance, } = expenseAutomationFluxAnalysisViewState;
|
|
12
11
|
const fetchStateAndError = {
|
|
13
12
|
fetchState,
|
|
@@ -92,17 +91,20 @@ export function getExpenseAutomationFluxAnalysisView(state) {
|
|
|
92
91
|
},
|
|
93
92
|
};
|
|
94
93
|
const completionStatus = fluxCompletionStatus != null ? fluxCompletionStatus : 'incomplete';
|
|
95
|
-
const
|
|
96
|
-
?
|
|
97
|
-
:
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
94
|
+
const groupsForSelectedPeriod = monthYearPeriodId != null
|
|
95
|
+
? groupsBySelectedPeriod[monthYearPeriodId]
|
|
96
|
+
: undefined;
|
|
97
|
+
// `fetchState` is a flat slice field that survives a period switch. The per-period group is
|
|
98
|
+
// created by the fetch's own request reducer, so its absence means "not requested yet for this
|
|
99
|
+
// period" -- report 'Not-Started' then, so the table keeps its skeleton instead of rendering
|
|
100
|
+
// the previous period's rows during the transition.
|
|
101
|
+
const fetchStatus = fetchState === 'Completed' && groupsForSelectedPeriod == null
|
|
102
|
+
? { fetchState: 'Not-Started', error: undefined }
|
|
103
|
+
: fetchStateAndError;
|
|
102
104
|
return {
|
|
103
105
|
sections,
|
|
104
106
|
totalBalancesAndVariance,
|
|
105
|
-
fetchStatus
|
|
107
|
+
fetchStatus,
|
|
106
108
|
bulkReviewStatus,
|
|
107
109
|
reviewOperatingExpensesIds,
|
|
108
110
|
selectedSectionIds,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import omit from 'lodash/omit';
|
|
2
2
|
import orderBy from 'lodash/orderBy';
|
|
3
|
-
import { reduceAnyFetchState } from '../../../commonStateTypes/reduceFetchState';
|
|
4
3
|
import { LAST_SCHEDULE_DAY_OF_MONTH, toMonthYearPeriodId, } from '../../../commonStateTypes/timePeriod';
|
|
5
4
|
import { getAccountIdsForTypes } from '../../../entity/account/accountSelector';
|
|
6
5
|
import { generateJEOneTimeAccrualKey } from '../../../entity/jeSchedules/jeScheduleHelper';
|
|
@@ -210,7 +209,7 @@ export function getExpenseAutomationJESchedulesView(state) {
|
|
|
210
209
|
const failedJeScheduledTransaction = [];
|
|
211
210
|
const accruedSchedules = [];
|
|
212
211
|
const oneTimeAccruals = [];
|
|
213
|
-
const { accountState, accountListState, classState, classListState, expenseAutomationJESchedulesViewState, expenseAutomationViewState, monthEndCloseChecksState,
|
|
212
|
+
const { accountState, accountListState, classState, classListState, expenseAutomationJESchedulesViewState, expenseAutomationViewState, monthEndCloseChecksState, } = state;
|
|
214
213
|
const { jeScheduleTransactionKeysByPeriodAndTab, jeScheduleAccruedKeysByPeriodAndTab, jeScheduleOneTimeAccrualKeysByPeriodAndTab, failedJeScheduleTransactionKeysByPeriodAndTab, jeScheduleLocalDataById, postStatusById, ignoreStatusById, revertStatusById, oneTimeAccrualActionStatusById, uiState, error, fetchState, refreshStatus, newSchedule, } = expenseAutomationJESchedulesViewState;
|
|
215
214
|
const accountSettingsView = getJEAccountSettingsView(state);
|
|
216
215
|
const newScheduleView = newSchedule.selectedDetailScheduleType === 'fixed_assets' ||
|
|
@@ -401,13 +400,6 @@ export function getExpenseAutomationJESchedulesView(state) {
|
|
|
401
400
|
: [];
|
|
402
401
|
const jeCompletionStatus = allSteps.find((step) => step.step === 'je_schedules')?.completionStatus;
|
|
403
402
|
const completionStatus = jeCompletionStatus != null ? jeCompletionStatus : 'incomplete';
|
|
404
|
-
const monthEndFetchState = monthYearPeriodId != null
|
|
405
|
-
? (monthEndCloseChecksViewState.monthEndCloseChecksViewByTenantId[currentTenant.tenantId]?.[monthYearPeriodId] ?? { fetchState: 'Not-Started', error: undefined })
|
|
406
|
-
: { fetchState: 'Not-Started', error: undefined };
|
|
407
|
-
const reducedFetchStatus = reduceAnyFetchState([
|
|
408
|
-
{ fetchState, error },
|
|
409
|
-
monthEndFetchState,
|
|
410
|
-
]);
|
|
411
403
|
const countByType = (schedules) => {
|
|
412
404
|
const counts = ALL_SCHEDULES_TYPES.reduce((acc, type) => ({ ...acc, [type]: 0 }), {});
|
|
413
405
|
schedules.forEach((schedule) => {
|
|
@@ -445,10 +437,10 @@ export function getExpenseAutomationJESchedulesView(state) {
|
|
|
445
437
|
ignoreStatusById: ignoreStatusById,
|
|
446
438
|
revertStatusById: revertStatusById,
|
|
447
439
|
oneTimeAccrualActionStatusById: oneTimeAccrualActionStatusById,
|
|
448
|
-
fetchState
|
|
440
|
+
fetchState,
|
|
449
441
|
jeScheduleLocalDataById: jeScheduleLocalDataById,
|
|
450
442
|
uiState: uiState,
|
|
451
|
-
error
|
|
443
|
+
error,
|
|
452
444
|
refreshStatus,
|
|
453
445
|
completionStatus,
|
|
454
446
|
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import orderBy from 'lodash/orderBy';
|
|
2
|
-
import { reduceAnyFetchState } from '../../../commonStateTypes/reduceFetchState';
|
|
3
2
|
import { toMonthYearPeriodId } from '../../../commonStateTypes/timePeriod';
|
|
4
3
|
import { getCurrentTenant } from '../../../entity/tenant/tenantSelector';
|
|
5
4
|
import { getSupportedTransactionById, getSupportedTransactionsByIds, } from '../../../entity/transaction/transactionSelector';
|
|
@@ -8,7 +7,7 @@ import { getCompletedTransactionsCacheKey } from '../reducers/missingReceiptsVie
|
|
|
8
7
|
import { isUnmatchedTabFileStatus, } from '../types/missingReceiptsViewState';
|
|
9
8
|
import { getAllSteps } from './getAllStepsHelper';
|
|
10
9
|
export function getExpenseAutomationMissingReceiptsView(state) {
|
|
11
|
-
const { expenseAutomationMissingReceiptsViewState, expenseAutomationViewState, transactionState, monthEndCloseChecksState,
|
|
10
|
+
const { expenseAutomationMissingReceiptsViewState, expenseAutomationViewState, transactionState, monthEndCloseChecksState, } = state;
|
|
12
11
|
const currentTenant = getCurrentTenant(state);
|
|
13
12
|
const { selectedPeriodByTenantId } = expenseAutomationViewState;
|
|
14
13
|
const selectedPeriod = selectedPeriodByTenantId[currentTenant.tenantId];
|
|
@@ -176,16 +175,16 @@ export function getExpenseAutomationMissingReceiptsView(state) {
|
|
|
176
175
|
vendorLogo: result.vendorLogo ?? transaction?.logo?.href,
|
|
177
176
|
};
|
|
178
177
|
});
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
178
|
+
// `fetchState` is a flat slice field that survives a period switch, so it still reads
|
|
179
|
+
// 'Completed' before the newly selected period's ids land. Reporting 'Not-Started' until they
|
|
180
|
+
// do keeps the skeleton up instead of flashing the "all done" empty state over the previous
|
|
181
|
+
// period's rows.
|
|
182
|
+
const fetchStatus = fetchState === 'Completed' && transactionIdsForSelectedPeriod == null
|
|
183
|
+
? { fetchState: 'Not-Started', error: undefined }
|
|
184
|
+
: { fetchState, error };
|
|
186
185
|
return {
|
|
187
|
-
fetchState:
|
|
188
|
-
error:
|
|
186
|
+
fetchState: fetchStatus.fetchState,
|
|
187
|
+
error: fetchStatus.error,
|
|
189
188
|
uploadReceiptStatusById,
|
|
190
189
|
uiState,
|
|
191
190
|
refreshStatus,
|
|
@@ -30,6 +30,10 @@ export const localDataToSaveInvoicingCustomerPayload = (localData, billingAddres
|
|
|
30
30
|
: {}),
|
|
31
31
|
};
|
|
32
32
|
};
|
|
33
|
+
/**
|
|
34
|
+
* The email rendered once with sentinel tokens standing in for the subject and
|
|
35
|
+
* body, so the composer can splice a draft into it without another request.
|
|
36
|
+
*/
|
|
33
37
|
export const toInvoicingPaymentLinkEmailPreview = (payload) => ({
|
|
34
38
|
body: payload.body,
|
|
35
39
|
bodyToken: payload.body_token,
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { EMPTY, of } from 'rxjs';
|
|
2
2
|
import { catchError, filter, finalize, mergeMap, switchMap, takeUntil, withLatestFrom, } from 'rxjs/operators';
|
|
3
|
+
import { NOTIFICATION_DOMAINS } from '../../../entity/notificationRegistry/notificationRegistryState';
|
|
3
4
|
import { openSnackbar } from '../../../entity/snackbar/snackbarReducer';
|
|
4
5
|
import { createZeniAPIStatus, isSuccessResponse, } from '../../../responsePayload';
|
|
5
6
|
import { notificationPreferencesUrl } from '../notificationPreferencesEndpoint';
|
|
6
7
|
import { mapPreferencesToPayload, } from '../notificationPreferencesViewPayload';
|
|
7
8
|
import { clearAllNotificationPreferencesView, clearNotificationPreferencesLocalOverrides, saveNotificationPreferences, saveNotificationPreferencesFailure, saveNotificationPreferencesSuccess, } from '../notificationPreferencesViewReducer';
|
|
8
|
-
import {
|
|
9
|
+
import { getNotificationLocalOverridesForDomain } from '../notificationPreferencesViewSelector';
|
|
9
10
|
export const saveNotificationPreferencesEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter((action) => saveNotificationPreferences.match(action)), withLatestFrom(state$),
|
|
10
11
|
// `switchMap` unsubscribes from any in-flight PUT observable when a newer
|
|
11
12
|
// Save fires. The prior HTTP request has already left the
|
|
@@ -13,9 +14,19 @@ export const saveNotificationPreferencesEpic = (actions$, state$, zeniAPI) => ac
|
|
|
13
14
|
// ignored, so stale success/failure actions cannot clobber the newer
|
|
14
15
|
// batch's state. Server-side ordering is arrival-order LWW.
|
|
15
16
|
switchMap(([, state]) => {
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
17
|
+
// A clean domain is omitted entirely: an empty patch is still a write against it.
|
|
18
|
+
const overridesByDomain = {};
|
|
19
|
+
const body = {};
|
|
20
|
+
NOTIFICATION_DOMAINS.forEach((domain) => {
|
|
21
|
+
const overrides = getNotificationLocalOverridesForDomain(state, domain);
|
|
22
|
+
const preferencesPatch = mapPreferencesToPayload(overrides);
|
|
23
|
+
if (Object.keys(preferencesPatch).length === 0) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
overridesByDomain[domain] = overrides;
|
|
27
|
+
body[`${domain}_preferences`] = preferencesPatch;
|
|
28
|
+
});
|
|
29
|
+
if (Object.keys(body).length === 0) {
|
|
19
30
|
// No diff → do not dispatch a synthetic success (that would wipe
|
|
20
31
|
// stored preferences via the reducer). Simply no-op.
|
|
21
32
|
return EMPTY;
|
|
@@ -28,7 +39,6 @@ switchMap(([, state]) => {
|
|
|
28
39
|
// in-flight save's response (Success/Failure never dispatched, so
|
|
29
40
|
// the counter never drained and future saves got their merge dropped).
|
|
30
41
|
const cancelEpochAtDispatch = state.notificationPreferencesViewState.cancelEpoch;
|
|
31
|
-
const body = { task_checklist_preferences: preferencesPatch };
|
|
32
42
|
// Suppress the error snackbar when the response lands AFTER the user
|
|
33
43
|
// pressed Cancel — the Failure reducer already swallows the state
|
|
34
44
|
// update, so the toast would be a stale error for a save the user
|
|
@@ -57,8 +67,11 @@ switchMap(([, state]) => {
|
|
|
57
67
|
if (isSuccessResponse(response)) {
|
|
58
68
|
return of(saveNotificationPreferencesSuccess({
|
|
59
69
|
cancelEpochAtDispatch,
|
|
60
|
-
|
|
61
|
-
|
|
70
|
+
savedOverridesByDomain: overridesByDomain,
|
|
71
|
+
serverEchoByDomain: {
|
|
72
|
+
task_checklist: response.data?.task_checklist_preferences,
|
|
73
|
+
commenting: response.data?.commenting_preferences,
|
|
74
|
+
},
|
|
62
75
|
}));
|
|
63
76
|
}
|
|
64
77
|
const actions = [
|
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
import { createSlice } from '@reduxjs/toolkit';
|
|
2
|
+
import { DEFAULT_NOTIFICATION_DOMAIN, } from '../../entity/notificationRegistry/notificationRegistryState';
|
|
2
3
|
import { clearAll } from '../../rootActions';
|
|
3
4
|
import { mapPayloadToPreferences, } from './notificationPreferencesViewPayload';
|
|
4
5
|
import { emptyNotificationPreferences, } from './notificationPreferencesViewState';
|
|
5
6
|
export const initialState = {
|
|
6
7
|
cancelEpoch: 0,
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
localOverridesByDomain: {},
|
|
9
|
+
preferencesByDomain: {},
|
|
9
10
|
saveEpoch: 0,
|
|
10
11
|
savePreferencesState: { fetchState: 'Not-Started' },
|
|
11
12
|
};
|
|
13
|
+
// Lazy: a gate-off tenant never receives that domain's key at all.
|
|
14
|
+
const overridesFor = (byDomain, domain) => {
|
|
15
|
+
const existing = byDomain[domain];
|
|
16
|
+
if (existing != null) {
|
|
17
|
+
return existing;
|
|
18
|
+
}
|
|
19
|
+
const created = emptyNotificationPreferences();
|
|
20
|
+
byDomain[domain] = created;
|
|
21
|
+
return created;
|
|
22
|
+
};
|
|
12
23
|
const mergePreferences = (base, patch) => {
|
|
13
24
|
const eventEnabledByChannel = {
|
|
14
25
|
...base.eventEnabledByChannel,
|
|
@@ -146,7 +157,8 @@ const notificationPreferencesView = createSlice({
|
|
|
146
157
|
// Success/Failure never dispatches, subsequent legitimate saves
|
|
147
158
|
// still work because their captured epoch matches the current one.
|
|
148
159
|
draft.cancelEpoch += 1;
|
|
149
|
-
|
|
160
|
+
// One shared Save/Cancel footer, so Cancel discards every domain.
|
|
161
|
+
draft.localOverridesByDomain = {};
|
|
150
162
|
// Also drop `savePreferencesState` back to Not-Started so any
|
|
151
163
|
// "Saving…" affordance bound to `getNotificationPreferencesSaveState`
|
|
152
164
|
// clears on Cancel. Without this, a Cancel-during-save whose stale
|
|
@@ -163,9 +175,6 @@ const notificationPreferencesView = createSlice({
|
|
|
163
175
|
// them; the save-success path is the only clearer.
|
|
164
176
|
// A `null`/`undefined` payload isn't a snapshot at all (e.g. the
|
|
165
177
|
// envelope key was omitted); no-op instead of wiping preferences.
|
|
166
|
-
if (action.payload.preferences == null) {
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
178
|
// Stale-GET guard (Cursor Bugbot 3632510237): if the fetch epic
|
|
170
179
|
// captured a `saveEpoch` lower than the current one, a save has
|
|
171
180
|
// succeeded since this GET dispatched — the response is carrying
|
|
@@ -175,7 +184,13 @@ const notificationPreferencesView = createSlice({
|
|
|
175
184
|
if (action.payload.saveEpochAtDispatch < draft.saveEpoch) {
|
|
176
185
|
return;
|
|
177
186
|
}
|
|
178
|
-
|
|
187
|
+
Object.entries(action.payload.preferencesByDomain).forEach(([domain, payload]) => {
|
|
188
|
+
if (payload == null) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
draft.preferencesByDomain[domain] =
|
|
192
|
+
mapPayloadToPreferences(payload);
|
|
193
|
+
});
|
|
179
194
|
},
|
|
180
195
|
saveNotificationPreferences(draft) {
|
|
181
196
|
draft.savePreferencesState = { fetchState: 'In-Progress' };
|
|
@@ -234,33 +249,44 @@ const notificationPreferencesView = createSlice({
|
|
|
234
249
|
// skip the `preferences` replace. Cursor Bugbot 3632510237.
|
|
235
250
|
draft.saveEpoch += 1;
|
|
236
251
|
draft.savePreferencesState = { fetchState: 'Completed' };
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
252
|
+
Object.entries(action.payload.savedOverridesByDomain).forEach(([rawDomain, savedOverrides]) => {
|
|
253
|
+
if (savedOverrides == null) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
const domain = rawDomain;
|
|
257
|
+
const serverEcho = action.payload.serverEchoByDomain[domain];
|
|
258
|
+
const patch = serverEcho == null
|
|
259
|
+
? savedOverrides
|
|
260
|
+
: mapPayloadToPreferences(serverEcho);
|
|
261
|
+
draft.preferencesByDomain[domain] = mergePreferences(draft.preferencesByDomain[domain] ?? emptyNotificationPreferences(), patch);
|
|
262
|
+
draft.localOverridesByDomain[domain] = subtractSavedOverrides(draft.localOverridesByDomain[domain] ??
|
|
263
|
+
emptyNotificationPreferences(), savedOverrides);
|
|
264
|
+
});
|
|
242
265
|
},
|
|
243
266
|
setGroupChannelMaster(draft, action) {
|
|
244
267
|
// Mirror of `toggleEventChannel` but scoped to the group-channel master
|
|
245
268
|
// held under `groupChannelEnabledByGroupId[groupId][channel]`.
|
|
246
269
|
const { channel, enabled, groupId } = action.payload;
|
|
270
|
+
const overrides = overridesFor(draft.localOverridesByDomain, action.payload.domain ?? DEFAULT_NOTIFICATION_DOMAIN);
|
|
247
271
|
const groupMap = {
|
|
248
|
-
...(
|
|
272
|
+
...(overrides.groupChannelEnabledByGroupId[groupId] ?? {}),
|
|
249
273
|
};
|
|
250
274
|
groupMap[channel] = enabled;
|
|
251
|
-
|
|
275
|
+
overrides.groupChannelEnabledByGroupId[groupId] = groupMap;
|
|
252
276
|
},
|
|
253
277
|
setGroupFrequency(draft, action) {
|
|
254
|
-
draft.
|
|
278
|
+
const overrides = overridesFor(draft.localOverridesByDomain, action.payload.domain ?? DEFAULT_NOTIFICATION_DOMAIN);
|
|
279
|
+
overrides.groupFrequencyByGroupId[action.payload.groupId] =
|
|
255
280
|
action.payload.frequency;
|
|
256
281
|
},
|
|
257
282
|
toggleEventChannel(draft, action) {
|
|
258
283
|
const { channel, enabled, eventId } = action.payload;
|
|
284
|
+
const overrides = overridesFor(draft.localOverridesByDomain, action.payload.domain ?? DEFAULT_NOTIFICATION_DOMAIN);
|
|
259
285
|
const eventMap = {
|
|
260
|
-
...(
|
|
286
|
+
...(overrides.eventEnabledByChannel[eventId] ?? {}),
|
|
261
287
|
};
|
|
262
288
|
eventMap[channel] = enabled;
|
|
263
|
-
|
|
289
|
+
overrides.eventEnabledByChannel[eventId] = eventMap;
|
|
264
290
|
},
|
|
265
291
|
},
|
|
266
292
|
extraReducers: (builder) => {
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import { createSelector } from '@reduxjs/toolkit';
|
|
2
|
+
import { DEFAULT_NOTIFICATION_DOMAIN, } from '../../entity/notificationRegistry/notificationRegistryState';
|
|
3
|
+
import { emptyNotificationPreferences, } from './notificationPreferencesViewState';
|
|
2
4
|
const getView = (state) => state.notificationPreferencesViewState;
|
|
3
5
|
export const getNotificationPreferencesSaveState = (state) => getView(state).savePreferencesState;
|
|
4
6
|
// Memoised on `preferences` + `localOverrides` so the merged shape keeps a
|
|
5
7
|
// stable reference while neither input changes — a plain function would
|
|
6
8
|
// allocate a fresh object on every call and re-render every `useSelector`
|
|
7
9
|
// consumer on any unrelated dispatch.
|
|
8
|
-
|
|
10
|
+
const EMPTY_PREFERENCES = emptyNotificationPreferences();
|
|
11
|
+
// One per domain: a shared createSelector has a cache of one and would thrash across two.
|
|
12
|
+
const effectivePreferencesSelectorByDomain = new Map();
|
|
13
|
+
const createEffectivePreferencesSelector = (domain) => createSelector((state) => getView(state).preferencesByDomain[domain], (state) => getView(state).localOverridesByDomain[domain], (storedPreferences, storedOverrides) => {
|
|
14
|
+
const preferences = storedPreferences ?? EMPTY_PREFERENCES;
|
|
15
|
+
const localOverrides = storedOverrides ?? EMPTY_PREFERENCES;
|
|
9
16
|
const mergedEventEnabledByChannel = { ...preferences.eventEnabledByChannel };
|
|
10
17
|
Object.entries(localOverrides.eventEnabledByChannel).forEach(([eventId, channels]) => {
|
|
11
18
|
mergedEventEnabledByChannel[eventId] = {
|
|
@@ -29,7 +36,20 @@ export const getEffectiveNotificationPreferences = createSelector((state) => get
|
|
|
29
36
|
},
|
|
30
37
|
};
|
|
31
38
|
});
|
|
32
|
-
export const
|
|
33
|
-
|
|
39
|
+
export const getEffectiveNotificationPreferencesForDomain = (state, domain) => {
|
|
40
|
+
let selector = effectivePreferencesSelectorByDomain.get(domain);
|
|
41
|
+
if (selector == null) {
|
|
42
|
+
selector = createEffectivePreferencesSelector(domain);
|
|
43
|
+
effectivePreferencesSelectorByDomain.set(domain, selector);
|
|
44
|
+
}
|
|
45
|
+
return selector(state);
|
|
46
|
+
};
|
|
47
|
+
export const getEffectiveNotificationPreferences = (state) => getEffectiveNotificationPreferencesForDomain(state, DEFAULT_NOTIFICATION_DOMAIN);
|
|
48
|
+
export const getNotificationLocalOverridesForDomain = (state, domain) => getView(state).localOverridesByDomain[domain] ?? EMPTY_PREFERENCES;
|
|
49
|
+
export const getNotificationLocalOverrides = (state) => getNotificationLocalOverridesForDomain(state, DEFAULT_NOTIFICATION_DOMAIN);
|
|
50
|
+
const isDirty = (localOverrides) => Object.keys(localOverrides.eventEnabledByChannel).length > 0 ||
|
|
34
51
|
Object.keys(localOverrides.groupChannelEnabledByGroupId).length > 0 ||
|
|
35
|
-
Object.keys(localOverrides.groupFrequencyByGroupId).length > 0
|
|
52
|
+
Object.keys(localOverrides.groupFrequencyByGroupId).length > 0;
|
|
53
|
+
export const hasUnsavedNotificationPreferencesForDomain = (state, domain) => isDirty(getNotificationLocalOverridesForDomain(state, domain));
|
|
54
|
+
// Drives the shared page-level Save/Cancel footer.
|
|
55
|
+
export const hasUnsavedNotificationPreferences = (state) => Object.values(getView(state).localOverridesByDomain).some((localOverrides) => localOverrides != null && isDirty(localOverrides));
|
|
@@ -38,11 +38,21 @@ export const fetchNotificationSettingsEpic = (actions$, state$, zeniAPI) => acti
|
|
|
38
38
|
// 67d6918e.
|
|
39
39
|
updateActions.push(updateNotificationRegistry({
|
|
40
40
|
registry: response.data.task_checklist_registry ?? undefined,
|
|
41
|
+
// An absent `<domain>_registry` means that domain's gate is off.
|
|
42
|
+
registriesByDomain: {
|
|
43
|
+
task_checklist: response.data.task_checklist_registry ?? undefined,
|
|
44
|
+
commenting: response.data.commenting_registry ?? undefined,
|
|
45
|
+
},
|
|
41
46
|
registryEpochAtDispatch,
|
|
42
47
|
}));
|
|
43
|
-
|
|
48
|
+
// One action so the domains cannot land on different store epochs.
|
|
49
|
+
const preferencesByDomain = {
|
|
50
|
+
task_checklist: response.data.task_checklist_preferences ?? undefined,
|
|
51
|
+
commenting: response.data.commenting_preferences ?? undefined,
|
|
52
|
+
};
|
|
53
|
+
if (Object.values(preferencesByDomain).some((preferences) => preferences != null)) {
|
|
44
54
|
updateActions.push(fetchNotificationPreferencesSuccess({
|
|
45
|
-
|
|
55
|
+
preferencesByDomain,
|
|
46
56
|
saveEpochAtDispatch,
|
|
47
57
|
}));
|
|
48
58
|
}
|
package/lib/index.d.ts
CHANGED
|
@@ -116,8 +116,8 @@ import { updateCommentsNotifications, updateCommentsNotificationsStatuses } from
|
|
|
116
116
|
import { NotificationWithAuthors } from './entity/notification/types/notificationSelectorTypes';
|
|
117
117
|
import { Notification, NotificationActivity, NotificationEventData, NotificationMetaData, NotificationUpdates, NotificationValueFormat } from './entity/notification/types/notificationStateTypes';
|
|
118
118
|
import { ExternalNotificationData, NotificationActivityType, NotificationGroup, NotificationIdentifierType, NotificationMode, NotificationStatus, NotificationUpdateValue, toNotificationModeStrict } from './entity/notification/types/notificationTypes';
|
|
119
|
-
import { getNotificationRegistry } from './entity/notificationRegistry/notificationRegistrySelector';
|
|
120
|
-
import { NotificationChannel, NotificationFrequency, NotificationRegistry, RegistryNotificationEvent, RegistryNotificationGroup, toNotificationChannel, toNotificationFrequency } from './entity/notificationRegistry/notificationRegistryState';
|
|
119
|
+
import { getNotificationRegistry, getNotificationRegistryForDomain } from './entity/notificationRegistry/notificationRegistrySelector';
|
|
120
|
+
import { DEFAULT_NOTIFICATION_DOMAIN, NOTIFICATION_DOMAINS, NotificationChannel, NotificationDomain, NotificationFrequency, NotificationRegistry, RegistryNotificationEvent, RegistryNotificationGroup, toNotificationChannel, toNotificationDomain, toNotificationFrequency } from './entity/notificationRegistry/notificationRegistryState';
|
|
121
121
|
import { getPlaidPaymentAccounts } from './entity/paymentAccount/paymentAccountSelector';
|
|
122
122
|
import { Logo, PaymentAccount, VERIFIED_PAYMENT_ACCOUNT_PROVIDER_VERIFICATION_STATUS } from './entity/paymentAccount/paymentAccountState';
|
|
123
123
|
import { PaymentInstrument } from './entity/paymentInstrument/paymentInstrument';
|
|
@@ -379,7 +379,7 @@ import { getNetBurnOrIncomeStoryCardReport } from './view/netBurnOrIncomeStoryCa
|
|
|
379
379
|
import { AccountingMethod, NetBurnOrIncomeStoryCardReport } from './view/netBurnOrIncomeStoryCard/netBurnOrIncomeStoryCardSelectorTypes';
|
|
380
380
|
import { AverageMonthsCount, NetBurnOrIncomeRunway, NetBurnOrIncomeStoryCardState, TimeSpanIdForAverage } from './view/netBurnOrIncomeStoryCard/netBurnOrIncomeStoryCardState';
|
|
381
381
|
import { clearAllNotificationPreferencesView, clearNotificationPreferencesLocalOverrides, saveNotificationPreferences, setGroupChannelMaster, setGroupFrequency, toggleEventChannel } from './view/notificationPreferencesView/notificationPreferencesViewReducer';
|
|
382
|
-
import { getEffectiveNotificationPreferences, getNotificationLocalOverrides, getNotificationPreferencesSaveState, hasUnsavedNotificationPreferences } from './view/notificationPreferencesView/notificationPreferencesViewSelector';
|
|
382
|
+
import { getEffectiveNotificationPreferences, getEffectiveNotificationPreferencesForDomain, getNotificationLocalOverrides, getNotificationLocalOverridesForDomain, getNotificationPreferencesSaveState, hasUnsavedNotificationPreferences, hasUnsavedNotificationPreferencesForDomain } from './view/notificationPreferencesView/notificationPreferencesViewSelector';
|
|
383
383
|
import { NotificationPreferences } from './view/notificationPreferencesView/notificationPreferencesViewState';
|
|
384
384
|
import { fetchNotificationUnreadCount, fetchNotificationUnreadCountSuccess, fetchNotificationView, updateNotificationViewAllNotificationsStatus, updateNotificationViewCurrentTabAndSubTab, updateNotificationViewNotificationStatus, updateNotificationViewSubTab, updateNotificationViewTabState, updateNotificationViewUIState } from './view/notificationView/notificationViewReducer';
|
|
385
385
|
import { NotificationView, getExternalNotificationsForSelectedSubTab, getNotificationView, getNotificationsForSelectedSubTab } from './view/notificationView/notificationViewSelector';
|
|
@@ -966,7 +966,7 @@ export { ExternalNotificationData, NotificationGroup, NotificationActivityType,
|
|
|
966
966
|
export { NotificationView, NotificationViewUIState, NotificationTabState, NotificationTabType, NotificationSubTabType, toNotificationSubTabTypeStrict, toNotificationTabTypeStrict, fetchNotificationView, fetchNotificationUnreadCount, fetchNotificationUnreadCountSuccess, updateNotificationViewAllNotificationsStatus, updateNotificationViewNotificationStatus, updateNotificationViewTabState, updateNotificationViewCurrentTabAndSubTab, updateNotificationViewSubTab, updateNotificationViewUIState, getNotificationView, getExternalNotificationsForSelectedSubTab, getNotificationsForSelectedSubTab, };
|
|
967
967
|
export { fetchRegisteredInterests, notifyMeForFeature, getFeatureNotificationView, getRegisteredInterests, getRegisteredInterestsByFeature, isFeatureInterestRegistered, FeatureInterest, FeatureNotificationViewState, };
|
|
968
968
|
export { pushToastNotification, ToastNotification, ToastNotificationPayload, getLastNotificationTime, getNotifications, };
|
|
969
|
-
export { getEffectiveNotificationPreferences, getNotificationLocalOverrides, getNotificationPreferencesSaveState, getNotificationRegistry, hasUnsavedNotificationPreferences, NotificationChannel, NotificationFrequency, NotificationPreferences, NotificationRegistry, RegistryNotificationEvent, RegistryNotificationGroup, clearAllNotificationPreferencesView, clearNotificationPreferencesLocalOverrides, saveNotificationPreferences, setGroupChannelMaster, setGroupFrequency, toggleEventChannel, toNotificationChannel, toNotificationFrequency, };
|
|
969
|
+
export { getEffectiveNotificationPreferences, getEffectiveNotificationPreferencesForDomain, getNotificationLocalOverrides, getNotificationLocalOverridesForDomain, getNotificationPreferencesSaveState, getNotificationRegistry, getNotificationRegistryForDomain, hasUnsavedNotificationPreferences, hasUnsavedNotificationPreferencesForDomain, NOTIFICATION_DOMAINS, NotificationChannel, DEFAULT_NOTIFICATION_DOMAIN, NotificationDomain, NotificationFrequency, NotificationPreferences, NotificationRegistry, RegistryNotificationEvent, RegistryNotificationGroup, clearAllNotificationPreferencesView, clearNotificationPreferencesLocalOverrides, saveNotificationPreferences, setGroupChannelMaster, setGroupFrequency, toggleEventChannel, toNotificationChannel, toNotificationDomain, toNotificationFrequency, };
|
|
970
970
|
export { getReferralListView, getInviteFormView, ReferralListSelectorView, ReferralViewState, InviteCompanyLocalData, ReferralInvitation, ReferralListViewSortKey, ReferralViewUIState, toReferralListViewSortKeyType, ReferralStatus, ReferralAmountStatus, StatusTypes, AmountStatusTypes, DEFAULT_REFERRER_AMOUNT, fetchReferrals, sendReferralInvite, clearReferrals, saveReferralFormDataInLocalStore, updateReferralListSortUiState, resendReferralInvite, fetchRewardsPlan, RewardsPlanCardReport, getRewardsPlanCard, updateReferViewed, RewardsPlanData, };
|
|
971
971
|
export { ALL_WEEK_DAYS, DayOfWeek, RecurringDatePickerOptions, RecurringFrequencyType, SEMI_WEEKLY_REQUIRED_DAYS_COUNT, getMinAllowedEndDate, getRecurringEndDateFromCount, toDayOfWeek, toRecurringFrequency, };
|
|
972
972
|
export { fetchCockpitContext, fetchCompanyTaskManagerView, fetchTaskManagerMetrics, CompanyTaskManagerSelectorView, CompanyTaskManagerViewUIState, TaskManagerMetrics, getCompanyTaskManagerView, TaskWithCompanyDetail, createTaskFromTaskGroupTemplate, TaskGroupTemplate, };
|
|
@@ -983,12 +983,12 @@ export { AiAccountantCustomerViewState, AiAccountantSortKey, AiAccountantUIState
|
|
|
983
983
|
export { AiAccountantFilterCategoryField } from './view/companyView/types/cockpitTypes';
|
|
984
984
|
export { cancelAiAccountantOnboarding, fetchAiAccountantCustomers, fetchAiAccountantJobs, setSelectedTenantIdsForJobTrigger, triggerAiAccountantJob, updateAiAccountantUIState, } from './view/aiAccountantView/aiAccountantViewReducer';
|
|
985
985
|
export { AiAccountantCockpitView, getAiAccountantCockpitView, } from './view/aiAccountantView/aiAccountantViewSelector';
|
|
986
|
-
export {
|
|
987
|
-
export { AiCfoViewState, AiCfoViewUIState, Skill, SkillDetail, SkillDetailState, SkillDraft, SkillMutationState, SkillVersion, SkillVersionBodyState, SkillVersionsState, SkillVisibility,
|
|
986
|
+
export { acceptMasterTOS, applyAiCfoSidePanelHostPageTransition, clearAiCfoSidePanelHostPageContext, clearCurrentSessionId, clearDeleteChatSessionStatus, clearLastContextMessage, clearSkillDetail, clearSkillMutation, closeRoutineRuns, closeRoutinesBrowser, closeSkillsBrowser, createSession, createSessionAndSubmit, deleteChatSession, deleteRoutine, deleteSkill, fetchChatHistory, fetchChatSessionsForUser, fetchRoutineRuns, fetchRoutines, fetchSkillDetail, fetchSkills, fetchSkillsFailure, fetchSkillsSuccess, fetchSkillVersionBody, fetchSkillVersions, fetchSuggestedQuestions, fetchSuggestedQuestionsFailure, fetchSuggestedQuestionsSuccess, openRoutinesBrowser, openSkillsBrowser, runRoutine, saveRoutine, saveSkill, setRoutineEnabled, setSession, setSkillVisibility, stopSubmit, stopSubmitQuestion, submitFeedback, submitQuestion, updateAiCfoViewScrollPosition, updateCotCollapsedState, updateCurrentInput, updateResponseState, } from './view/aiCfoView/aiCfoViewReducer';
|
|
987
|
+
export { AiCfoViewState, AiCfoViewUIState, Routine, RoutineDraft, RoutineMutationState, RoutineRecurrence, RoutineRun, RoutineRunsState, RoutineRunStatus, RoutinesState, RoutineStatus, Skill, SkillDetail, SkillDetailState, SkillDraft, SkillMutationState, SkillsState, SkillVersion, SkillVersionBodyState, SkillVersionsState, SkillVisibility, SuggestedQuestionsForPageContext, } from './view/aiCfoView/aiCfoViewState';
|
|
988
988
|
export { FetchSuggestedQuestionsResponse, SuggestedQuestionsDataPayload, FetchSkillsResponse, SkillSummaryPayload, SkillListDataPayload, } from './view/aiCfoView/aiCfoViewPayload';
|
|
989
989
|
export type { FeedbackType, SubmitFeedbackPayload, } from './view/aiCfoView/aiCfoViewPayload';
|
|
990
990
|
export type { AiCfoSuggestedQuestionsPageContext } from './common/aiCfo/aiCfoSuggestedQuestionsPageContext';
|
|
991
|
-
export { AiCfoViewSelector, getAiCfoView,
|
|
991
|
+
export { AiCfoViewSelector, canCreateRoutine, getAiCfoView, getRoutineMutation, getRoutineRuns, getRoutines, getRoutinesEnabled, getSkillDetail, getSkillMutation, getSkills, getSkillsEnabled, getSkillVersionBody, getSkillVersions, getSuggestedQuestionsForPageContext, } from './view/aiCfoView/aiCfoViewSelector';
|
|
992
992
|
export { MessagePayload, ChatSessionPayload, AiCfoAnswerPayload, } from './entity/aiCfo/aiCfoPayload';
|
|
993
993
|
export { setNewSession, setSessions, updateAiCfoAnswerCardPolicyWizardPlan, upsertAnswerPayload, upsertOrAddQuestionAnswerPayload, addQuestionPayload, clearSession, toAiCfoExports, toAiCfoVisualization, appendSyntheticAiCfoAnswer, updateSyntheticAiCfoAnswer, removeSyntheticAiCfoAnswer, } from './entity/aiCfo/aiCfoReducer';
|
|
994
994
|
export { AiCfoSelectorView, getAllQuestionAnswersForChatSession, getQuestionAnswerByIdForChatSession, getAllQuestionsForChatSession, getAiCfoSelectorView, getSyntheticAiCfoAnswersForChatSession, getSyntheticAiCfoAnswerByQuestionAnswerId, ChatSessionWithOrderedQuestionAnswers, } from './entity/aiCfo/aiCfoSelector';
|
|
@@ -1171,7 +1171,7 @@ export type { InvoicingCustomerColumnConfig, InvoicingCustomerFilters, Invoicing
|
|
|
1171
1171
|
export { getInvoicingCustomerListView } from './view/invoicing/invoicingCustomerListView/invoicingCustomerListViewSelector';
|
|
1172
1172
|
export type { InvoicingCustomerListView } from './view/invoicing/invoicingCustomerListView/invoicingCustomerListViewSelector';
|
|
1173
1173
|
export { fetchInvoicingCustomerDetail, fetchInvoicingCustomerDetailPage, fetchInvoicingPaymentLinkEmailPreviewPage, } from './view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewReducer';
|
|
1174
|
-
export type { InvoicingPaymentLinkEmailPreviewData } from './view/invoicing/editInvoicingCustomerDetailView/
|
|
1174
|
+
export type { InvoicingPaymentLinkEmailPreviewData } from './view/invoicing/editInvoicingCustomerDetailView/editInvoicingCustomerDetailViewState';
|
|
1175
1175
|
export { createInvoicingSetupIntent, fetchInvoicingPlaidLinkToken, resetInvoicingCustomerPaymentMethod, saveInvoicingPaymentMethod, sendInvoicingPaymentLink, } from './view/invoicing/customerPaymentMethod/customerPaymentMethodReducer';
|
|
1176
1176
|
export type { InvoicingSetupIntent } from './view/invoicing/customerPaymentMethod/customerPaymentMethodState';
|
|
1177
1177
|
export { getInvoicingPaymentLinkSendState, getInvoicingPaymentMethodSaveState, getInvoicingPlaidLinkToken, getInvoicingSentPaymentLinkEmail, getInvoicingSentPaymentLinkMagicUrl, getInvoicingSetupIntent, getInvoicingSetupIntentFetchState, } from './view/invoicing/customerPaymentMethod/customerPaymentMethodSelector';
|