@zeniai/client-epic-state 5.0.4 → 5.0.7-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.
Files changed (33) hide show
  1. package/lib/coreEpics.js +2 -1
  2. package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
  3. package/lib/entity/snackbar/snackbarTypes.js +2 -0
  4. package/lib/entity/tenant/SessionManager.d.ts +38 -0
  5. package/lib/entity/tenant/SessionManager.js +171 -0
  6. package/lib/entity/tenant/epic/sessionHeartbeatEpic.d.ts +16 -0
  7. package/lib/entity/tenant/epic/sessionHeartbeatEpic.js +16 -0
  8. package/lib/entity/tenant/sessionTypes.d.ts +26 -0
  9. package/lib/entity/tenant/sessionTypes.js +12 -0
  10. package/lib/entity/tenant/tenantReducer.d.ts +5 -1
  11. package/lib/entity/tenant/tenantReducer.js +23 -2
  12. package/lib/entity/tenant/tenantState.d.ts +1 -0
  13. package/lib/entity/transaction/payloadTypes/transactionPayload.d.ts +2 -0
  14. package/lib/entity/transaction/payloadTypes/transactionPayload.js +18 -4
  15. package/lib/esm/coreEpics.js +2 -1
  16. package/lib/esm/entity/snackbar/snackbarTypes.js +2 -0
  17. package/lib/esm/entity/tenant/SessionManager.js +167 -0
  18. package/lib/esm/entity/tenant/epic/sessionHeartbeatEpic.js +12 -0
  19. package/lib/esm/entity/tenant/sessionTypes.js +9 -0
  20. package/lib/esm/entity/tenant/tenantReducer.js +21 -1
  21. package/lib/esm/entity/transaction/payloadTypes/transactionPayload.js +18 -4
  22. package/lib/esm/index.js +5 -2
  23. package/lib/esm/view/expenseAutomationView/epics/accountRecon/excludeAccountFromReconciliationEpic.js +19 -0
  24. package/lib/esm/view/expenseAutomationView/epics/accountRecon/includeAccountInReconciliationEpic.js +21 -0
  25. package/lib/index.d.ts +5 -2
  26. package/lib/index.js +36 -30
  27. package/lib/tsconfig.typecheck.tsbuildinfo +1 -1
  28. package/lib/view/expenseAutomationView/epics/accountRecon/excludeAccountFromReconciliationEpic.d.ts +2 -1
  29. package/lib/view/expenseAutomationView/epics/accountRecon/excludeAccountFromReconciliationEpic.js +19 -0
  30. package/lib/view/expenseAutomationView/epics/accountRecon/includeAccountInReconciliationEpic.d.ts +2 -1
  31. package/lib/view/expenseAutomationView/epics/accountRecon/includeAccountInReconciliationEpic.js +21 -0
  32. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
  33. package/package.json +1 -1
@@ -0,0 +1,167 @@
1
+ /**
2
+ * SessionManager — Central session lifecycle manager.
3
+ *
4
+ * Responsibilities:
5
+ * 1. Track user activity (mousemove, keydown, click, scroll, touch)
6
+ * 2. Send heartbeat at configurable intervals while user is active
7
+ * 3. Show warning popup after idle timeout
8
+ * 4. Auto-logout after warning countdown expires
9
+ */
10
+ import { DEFAULT_SESSION_CONFIG, } from './sessionTypes';
11
+ /** Events that indicate user activity. */
12
+ const ACTIVITY_EVENTS = [
13
+ 'mousemove',
14
+ 'mousedown',
15
+ 'keydown',
16
+ 'scroll',
17
+ 'touchstart',
18
+ 'click',
19
+ ];
20
+ /** Debounce interval for activity events (ms). */
21
+ const ACTIVITY_DEBOUNCE_MS = 1000;
22
+ export class SessionManager {
23
+ constructor() {
24
+ this.config = DEFAULT_SESSION_CONFIG;
25
+ this.callbacks = null;
26
+ /** Timestamps and timers */
27
+ this.lastActivityTime = 0;
28
+ this.idleCheckInterval = null;
29
+ this.heartbeatInterval = null;
30
+ this.countdownInterval = null;
31
+ this.activityDebounceTimer = null;
32
+ /** State */
33
+ this.running = false;
34
+ this.warningActive = false;
35
+ this.secondsRemaining = 0;
36
+ /** Bound handler for event listener cleanup. */
37
+ this.boundOnActivity = this.onActivity.bind(this);
38
+ this.boundOnVisibilityChange = this.onVisibilityChange.bind(this);
39
+ }
40
+ // ─── Public API ────────────────────────────────────────────
41
+ start(config = {}, callbacks) {
42
+ if (this.running) {
43
+ this.stop();
44
+ }
45
+ this.config = { ...DEFAULT_SESSION_CONFIG, ...config };
46
+ this.callbacks = callbacks;
47
+ this.running = true;
48
+ this.warningActive = false;
49
+ this.lastActivityTime = Date.now();
50
+ if (!this.config.isAutoLogoutEnabled) {
51
+ return;
52
+ }
53
+ ACTIVITY_EVENTS.forEach((event) => {
54
+ document.addEventListener(event, this.boundOnActivity, {
55
+ capture: true,
56
+ passive: true,
57
+ });
58
+ });
59
+ document.addEventListener('visibilitychange', this.boundOnVisibilityChange);
60
+ this.startHeartbeat();
61
+ this.callbacks?.onHeartbeat();
62
+ this.idleCheckInterval = setInterval(() => this.checkIdle(), 1000);
63
+ }
64
+ stop() {
65
+ this.running = false;
66
+ this.warningActive = false;
67
+ ACTIVITY_EVENTS.forEach((event) => {
68
+ document.removeEventListener(event, this.boundOnActivity, {
69
+ capture: true,
70
+ });
71
+ });
72
+ document.removeEventListener('visibilitychange', this.boundOnVisibilityChange);
73
+ this.clearTimer('idleCheckInterval');
74
+ this.clearTimer('heartbeatInterval');
75
+ this.clearTimer('countdownInterval');
76
+ this.clearTimer('activityDebounceTimer');
77
+ }
78
+ continueSession() {
79
+ if (!this.running) {
80
+ return;
81
+ }
82
+ this.warningActive = false;
83
+ this.secondsRemaining = 0;
84
+ this.lastActivityTime = Date.now();
85
+ this.clearTimer('countdownInterval');
86
+ this.callbacks?.onHeartbeat();
87
+ this.callbacks?.onSessionExtended();
88
+ this.startHeartbeat();
89
+ }
90
+ isWarningActive() {
91
+ return this.warningActive;
92
+ }
93
+ getSecondsRemaining() {
94
+ return this.secondsRemaining;
95
+ }
96
+ // ─── Private ───────────────────────────────────────────────
97
+ onActivity() {
98
+ if (!this.running || this.warningActive) {
99
+ return;
100
+ }
101
+ if (this.activityDebounceTimer != null) {
102
+ return;
103
+ }
104
+ this.lastActivityTime = Date.now();
105
+ this.activityDebounceTimer = setTimeout(() => {
106
+ this.activityDebounceTimer = null;
107
+ }, ACTIVITY_DEBOUNCE_MS);
108
+ }
109
+ onVisibilityChange() {
110
+ if (!this.running) {
111
+ return;
112
+ }
113
+ if (document.visibilityState === 'visible') {
114
+ this.lastActivityTime = Date.now();
115
+ this.checkIdle();
116
+ }
117
+ }
118
+ checkIdle() {
119
+ if (!this.running || this.warningActive) {
120
+ return;
121
+ }
122
+ const idleMs = Date.now() - this.lastActivityTime;
123
+ const idleTimeoutMs = this.config.idleTimeoutMinutes * 60 * 1000;
124
+ if (idleMs >= idleTimeoutMs) {
125
+ this.startWarning();
126
+ }
127
+ }
128
+ startWarning() {
129
+ this.warningActive = true;
130
+ this.secondsRemaining = this.config.warningDurationSeconds;
131
+ this.clearTimer('heartbeatInterval');
132
+ this.callbacks?.onWarningStart(this.secondsRemaining);
133
+ this.countdownInterval = setInterval(() => {
134
+ this.secondsRemaining -= 1;
135
+ if (this.secondsRemaining <= 0) {
136
+ this.clearTimer('countdownInterval');
137
+ this.warningActive = false;
138
+ this.callbacks?.onAutoLogout();
139
+ }
140
+ else {
141
+ this.callbacks?.onWarningTick(this.secondsRemaining);
142
+ }
143
+ }, 1000);
144
+ }
145
+ startHeartbeat() {
146
+ this.clearTimer('heartbeatInterval');
147
+ const intervalMs = this.config.heartbeatIntervalMinutes * 60 * 1000;
148
+ this.heartbeatInterval = setInterval(() => {
149
+ if (!this.running || this.warningActive) {
150
+ return;
151
+ }
152
+ this.callbacks?.onHeartbeat();
153
+ }, intervalMs);
154
+ }
155
+ clearTimer(name) {
156
+ const timer = this[name];
157
+ if (timer != null) {
158
+ if (name === 'activityDebounceTimer') {
159
+ clearTimeout(timer);
160
+ }
161
+ else {
162
+ clearInterval(timer);
163
+ }
164
+ this[name] = null;
165
+ }
166
+ }
167
+ }
@@ -0,0 +1,12 @@
1
+ import { of } from 'rxjs';
2
+ import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
3
+ import { createZeniAPIStatus, isSuccessResponse, } from '../../../responsePayload';
4
+ import { sendSessionHeartbeat, sessionHeartbeatFailure, sessionHeartbeatSuccess, } from '../tenantReducer';
5
+ export const sessionHeartbeatEpic = (actions$, _, zeniAPI) => actions$.pipe(filter(sendSessionHeartbeat.match), switchMap(() => zeniAPI
6
+ .postAndGetJSON(`${zeniAPI.apiEndPoints.authMicroServiceBaseUrl}/1.0/sessions/heartbeat`)
7
+ .pipe(mergeMap((response) => {
8
+ if (isSuccessResponse(response)) {
9
+ return of(sessionHeartbeatSuccess(response.data?.expiry ?? ''));
10
+ }
11
+ return of(sessionHeartbeatFailure(response.status));
12
+ }), catchError((error) => of(sessionHeartbeatFailure(createZeniAPIStatus('Heartbeat failed', 'Session heartbeat API call errored: ' + JSON.stringify(error))))))));
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Session management types for idle timeout and heartbeat.
3
+ */
4
+ export const DEFAULT_SESSION_CONFIG = {
5
+ heartbeatIntervalMinutes: 10,
6
+ idleTimeoutMinutes: 30,
7
+ isAutoLogoutEnabled: true,
8
+ warningDurationSeconds: 60,
9
+ };
@@ -428,6 +428,26 @@ const tenant = createSlice({
428
428
  signOutSuccess(draft) {
429
429
  draft.loggedInUser = undefined;
430
430
  draft.currentTenantId = undefined;
431
+ draft.sessionExpiresAt = undefined;
432
+ },
433
+ sendSessionHeartbeat() {
434
+ // No state change needed — epic handles the API call
435
+ },
436
+ sessionHeartbeatSuccess: {
437
+ prepare(expiresAt) {
438
+ return { payload: { expiresAt } };
439
+ },
440
+ reducer(draft, action) {
441
+ draft.sessionExpiresAt = action.payload.expiresAt;
442
+ },
443
+ },
444
+ sessionHeartbeatFailure: {
445
+ prepare(error) {
446
+ return { payload: { error } };
447
+ },
448
+ reducer(draft, action) {
449
+ draft.error = action.payload.error;
450
+ },
431
451
  },
432
452
  fetchSubscriptionSummaryForTenant: {
433
453
  prepare(tenantId) {
@@ -535,7 +555,7 @@ const tenant = createSlice({
535
555
  },
536
556
  },
537
557
  });
538
- export const { updateTenants, fetchAllTenants, updateTenantsSuccess, updateTenantsFailure, fetchActiveTenant, updateTenantSuccess, updateTenantFailure, updateCurrentTenant, fetchExcludedResources, updateExcludedResourcesSuccess, updateExcludedResourcesFailure, doSignIn, doMagicLinkSignIn, magicLinkSignInSuccess, magicLinkSignInFailure, sendEmailMagicLinkToUser, sendEmailMagicLinkToUserSuccess, sendEmailMagicLinkToUserFailure, updateSignInState, doSignOut, signOutSuccess, updateLoggedInUser, fetchExternalConnections, saveExternalConnection, saveExternalConnectionSuccess, saveExternalConnectionFailure, fetchExternalConnectionsFailure, fetchExternalConnectionsSuccess, clearAll, fetchSubscriptionSummaryForTenant, updateSubscriptionSummaryForTenantSuccess, updateSubscriptionSummaryForTenantFailure, updateOnboardingTenants, removeOnboardingTenant, updateTenantReimbursementInfo, updateReferViewedForLoggedInUser, updateTreasuryVideoViewedForLoggedInUser, resetSignInState, trigger2FA, updateTenantAccountingClassesEnabled, updateTenantMasterTOSInfo, verifyDeviceWithTwoFA, verifyDeviceWithTwoFASuccess, verifyDeviceWithTwoFAFailure, resendVerifyDeviceOTP, resendVerifyDeviceOTPSuccess, resendVerifyDeviceOTPFailure, } = tenant.actions;
558
+ export const { updateTenants, fetchAllTenants, updateTenantsSuccess, updateTenantsFailure, fetchActiveTenant, updateTenantSuccess, updateTenantFailure, updateCurrentTenant, fetchExcludedResources, updateExcludedResourcesSuccess, updateExcludedResourcesFailure, doSignIn, doMagicLinkSignIn, magicLinkSignInSuccess, magicLinkSignInFailure, sendEmailMagicLinkToUser, sendEmailMagicLinkToUserSuccess, sendEmailMagicLinkToUserFailure, updateSignInState, doSignOut, signOutSuccess, sendSessionHeartbeat, sessionHeartbeatSuccess, sessionHeartbeatFailure, updateLoggedInUser, fetchExternalConnections, saveExternalConnection, saveExternalConnectionSuccess, saveExternalConnectionFailure, fetchExternalConnectionsFailure, fetchExternalConnectionsSuccess, clearAll, fetchSubscriptionSummaryForTenant, updateSubscriptionSummaryForTenantSuccess, updateSubscriptionSummaryForTenantFailure, updateOnboardingTenants, removeOnboardingTenant, updateTenantReimbursementInfo, updateReferViewedForLoggedInUser, updateTreasuryVideoViewedForLoggedInUser, resetSignInState, trigger2FA, updateTenantAccountingClassesEnabled, updateTenantMasterTOSInfo, verifyDeviceWithTwoFA, verifyDeviceWithTwoFASuccess, verifyDeviceWithTwoFAFailure, resendVerifyDeviceOTP, resendVerifyDeviceOTPSuccess, resendVerifyDeviceOTPFailure, } = tenant.actions;
539
559
  export default tenant.reducer;
540
560
  /**
541
561
  * Converts tenants payload to Tenant and User State
@@ -34,8 +34,6 @@ export const toTransaction = (payload) => {
34
34
  const amount = getTransactionPayloadAmount(payload);
35
35
  const recipientAmount = getTransactionPayloadRecipientAmount(payload);
36
36
  const lines = payload?.lines?.map((linePayload) => toLine(linePayload, amount, recipientAmount));
37
- const firstLineWithClass = lines?.find((line) => 'class' in line &&
38
- line.class?.classId != null);
39
37
  return {
40
38
  ...toTransactionID(payload),
41
39
  typeOfTransaction: 'supported',
@@ -93,6 +91,12 @@ export const toTransaction = (payload) => {
93
91
  payload.category_integration_id !== ''
94
92
  ? { categoryIntegrationId: payload.category_integration_id }
95
93
  : {}),
94
+ ...(payload.class_id != null && payload.class_id !== ''
95
+ ? { classId: payload.class_id }
96
+ : {}),
97
+ ...(payload.class_name != null && payload.class_name !== ''
98
+ ? { className: payload.class_name }
99
+ : {}),
96
100
  ...(payload.category_name != null && payload.category_name !== ''
97
101
  ? { categoryName: payload.category_name }
98
102
  : {}),
@@ -101,8 +105,6 @@ export const toTransaction = (payload) => {
101
105
  account: payloadHasAccountInfo(payload)
102
106
  ? mapAccountBasePayloadToAccountBase(payload)
103
107
  : undefined,
104
- classId: firstLineWithClass?.class?.classId,
105
- className: firstLineWithClass?.class?.className,
106
108
  syncToken: payload.sync_token?.toString(),
107
109
  paymentType: payload.payment_type ?? undefined,
108
110
  paymentTypeName: payload.payment_type_name ?? undefined,
@@ -171,6 +173,18 @@ export const toTransactionPayload = (transaction) => {
171
173
  target_account_name: transaction.targetAccountName,
172
174
  };
173
175
  }
176
+ if (transaction.classId != null && transaction.classId !== '') {
177
+ transactionPayload = {
178
+ ...transactionPayload,
179
+ class_id: transaction.classId,
180
+ };
181
+ }
182
+ if (transaction.className != null && transaction.className !== '') {
183
+ transactionPayload = {
184
+ ...transactionPayload,
185
+ class_name: transaction.className,
186
+ };
187
+ }
174
188
  if (transaction.toFromAccountId != null &&
175
189
  transaction.toFromAccountId !== '') {
176
190
  transactionPayload = {
package/lib/esm/index.js CHANGED
@@ -59,7 +59,7 @@ import { closeSnackbar, openSnackbar } from './entity/snackbar/snackbarReducer';
59
59
  import { getSnackbar } from './entity/snackbar/snackbarSelector';
60
60
  import { toPriorityCodeType, toTaskStatusCodeType, } from './entity/task/taskState';
61
61
  import { getTaskGroupById } from './entity/taskGroup/taskGroupSelector';
62
- import { clearAll, doMagicLinkSignIn, doSignIn, doSignOut, fetchActiveTenant, fetchAllTenants, fetchExcludedResources as fetchExcludedResourcesForTenant, fetchExternalConnections as fetchExternalConnectionsForTenant, fetchSubscriptionSummaryForTenant, resendVerifyDeviceOTP, resetSignInState, saveExternalConnection as saveExternalConnectionForTenant, sendEmailMagicLinkToUser, updateCurrentTenant, updateSignInState, verifyDeviceWithTwoFA, } from './entity/tenant/tenantReducer';
62
+ import { clearAll, doMagicLinkSignIn, doSignIn, doSignOut, sendSessionHeartbeat, fetchActiveTenant, fetchAllTenants, fetchExcludedResources as fetchExcludedResourcesForTenant, fetchExternalConnections as fetchExternalConnectionsForTenant, fetchSubscriptionSummaryForTenant, resendVerifyDeviceOTP, resetSignInState, saveExternalConnection as saveExternalConnectionForTenant, sendEmailMagicLinkToUser, updateCurrentTenant, updateSignInState, verifyDeviceWithTwoFA, } from './entity/tenant/tenantReducer';
63
63
  import { getCurrentTenant, getIsAccountingClassesEnabled, getIsAccountingProjectsEnabled, getTenantBaseById, getTenantBaseViewForTenantId, getTenantBaseViewForTenantView, getTenantsBaseByCheckInDateSelector, getTenantsByCheckInDateSelector, getTenantsCoreDetailsByCheckInDateSelector, isOtherProductsEnabledForTenant, isTenantBankingOnly, isTenantBookkeepingEnabled, isTenantCardsOnly, isTenantUsingZeniCOA, isZeniDomainTenant, toTenantCoreDetailsView, } from './entity/tenant/tenantSelector';
64
64
  import { pushToastNotification } from './entity/toastNotification/toastNotificationReducer';
65
65
  import { getLastNotificationTime, getNotifications, } from './entity/toastNotification/toastNotificationSelector';
@@ -433,7 +433,7 @@ export { toTimeframeTick, mapTimePeriodtoTimeframeTick, toTimePeriod, toAbsolute
433
433
  export { toVendorSpendTrendFilterTabsTypeStrict, } from './entity/vendorExpense/vendorExpenseSelector';
434
434
  export { getNumberOfPeriods };
435
435
  export { SCHEDULE_DAYS_OF_MONTH, toScheduleDaysOfMonth, toMonth, toMonthStrict, toQuarter, toQuarterStrict, };
436
- export { getTenantBaseById, getCurrentTenant, getIsAccountingClassesEnabled, getIsAccountingProjectsEnabled, getTenantsByCheckInDateSelector, getTenantsBaseByCheckInDateSelector, getTenantsCoreDetailsByCheckInDateSelector, toTenantCoreDetailsView, getTenantBaseViewForTenantView, getTenantBaseViewForTenantId, isZeniDomainTenant, isTenantUsingZeniCOA, fetchActiveTenant, fetchAllTenants, updateCurrentTenant, clearAll, doMagicLinkSignIn, verifyDeviceWithTwoFA, resendVerifyDeviceOTP, sendEmailMagicLinkToUser, doSignIn, updateSignInState, doSignOut, resetSignInState, fetchExcludedResourcesForTenant, fetchExternalConnectionsForTenant, saveExternalConnectionForTenant, fetchSubscriptionSummaryForTenant, isTenantBankingOnly, isTenantCardsOnly, isTenantBookkeepingEnabled, isOtherProductsEnabledForTenant, };
436
+ export { getTenantBaseById, getCurrentTenant, getIsAccountingClassesEnabled, getIsAccountingProjectsEnabled, getTenantsByCheckInDateSelector, getTenantsBaseByCheckInDateSelector, getTenantsCoreDetailsByCheckInDateSelector, toTenantCoreDetailsView, getTenantBaseViewForTenantView, getTenantBaseViewForTenantId, isZeniDomainTenant, isTenantUsingZeniCOA, fetchActiveTenant, fetchAllTenants, updateCurrentTenant, clearAll, doMagicLinkSignIn, verifyDeviceWithTwoFA, resendVerifyDeviceOTP, sendEmailMagicLinkToUser, doSignIn, updateSignInState, doSignOut, sendSessionHeartbeat, resetSignInState, fetchExcludedResourcesForTenant, fetchExternalConnectionsForTenant, saveExternalConnectionForTenant, fetchSubscriptionSummaryForTenant, isTenantBankingOnly, isTenantCardsOnly, isTenantBookkeepingEnabled, isOtherProductsEnabledForTenant, };
437
437
  export { toAccountType, toAccountGroupType, getAccountGroupKey, };
438
438
  export { getClassById } from './entity/class/classSelector';
439
439
  export { getForecast };
@@ -631,3 +631,6 @@ export { getAutoTransferRules, getAutoTransferRuleById, getAutoTransferRuleHisto
631
631
  export { BULK_UPLOAD_AUTOMATCHING_TIMEOUT_MS, BULK_UPLOAD_BAR_COMPLETE_HOLD_MS, } from './view/expenseAutomationView/helpers/bulkUploadTiming';
632
632
  export { fetchTransactionActivityLog } from './view/transactionActivityLogView/transactionActivityLogViewReducer';
633
633
  export { getTransactionActivityLogView, } from './view/transactionActivityLogView/transactionActivityLogViewSelector';
634
+ // ── Session Management ──────────────────────────────────────────────
635
+ export { SessionManager } from './entity/tenant/SessionManager';
636
+ export { DEFAULT_SESSION_CONFIG } from './entity/tenant/sessionTypes';
@@ -3,6 +3,7 @@ import { catchError, filter, mergeMap } from 'rxjs/operators';
3
3
  import { changeAccountKey } from '../../../../entity/account/accountReducer';
4
4
  import { getAccountKey } from '../../../../entity/account/accountState';
5
5
  import { getAccountReconByAccountIdAndSelectedPeriod } from '../../../../entity/accountRecon/accountReconSelector';
6
+ import { openSnackbar } from '../../../../entity/snackbar/snackbarReducer';
6
7
  import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
7
8
  import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
8
9
  import { excludeAccountFromReconciliation, excludeAccountFromReconciliationFailure, excludeAccountFromReconciliationSuccess, } from '../../reducers/reconciliationViewReducer';
@@ -31,14 +32,32 @@ export const excludeAccountFromReconciliationEpic = (actions$, state$, zeniAPI)
31
32
  }), changeAccountKey({
32
33
  oldKey: oldAccountKey,
33
34
  newKey: newAccountKey,
35
+ }), openSnackbar({
36
+ messageSection: 'account_excluded_from_reconciliation',
37
+ messageText: 'success',
38
+ type: 'success',
39
+ variables: [
40
+ {
41
+ variableName: '_account-name_',
42
+ variableValue: reconciliationData?.account.accountName ?? '',
43
+ },
44
+ ],
34
45
  }));
35
46
  }
36
47
  else {
37
48
  return of(excludeAccountFromReconciliationFailure({
38
49
  error: response.status,
50
+ }), openSnackbar({
51
+ messageSection: 'account_excluded_from_reconciliation',
52
+ messageText: 'failed',
53
+ type: 'error',
39
54
  }));
40
55
  }
41
56
  }), catchError((error) => of(excludeAccountFromReconciliationFailure({
42
57
  error: createZeniAPIStatus('Unexpected Error', `Exclude account from reconciliation REST API call errored out ${JSON.stringify(error)}`),
58
+ }), openSnackbar({
59
+ messageSection: 'account_excluded_from_reconciliation',
60
+ messageText: 'failed',
61
+ type: 'error',
43
62
  }))));
44
63
  }));
@@ -2,8 +2,10 @@ import { of } from 'rxjs';
2
2
  import { catchError, filter, mergeMap } from 'rxjs/operators';
3
3
  import { convertToPeriod } from '../../../../commonStateTypes/timePeriod';
4
4
  import { changeAccountKey } from '../../../../entity/account/accountReducer';
5
+ import { getAccountBase } from '../../../../entity/account/accountSelector';
5
6
  import { getAccountKey } from '../../../../entity/account/accountState';
6
7
  import { updateAccountRecon } from '../../../../entity/accountRecon/accountReconReducer';
8
+ import { openSnackbar } from '../../../../entity/snackbar/snackbarReducer';
7
9
  import { getCurrentTenant } from '../../../../entity/tenant/tenantSelector';
8
10
  import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
9
11
  import { includeAccountInReconciliation, includeAccountInReconciliationFailure, includeAccountInReconciliationSuccess, } from '../../reducers/reconciliationViewReducer';
@@ -12,6 +14,7 @@ export const includeAccountInReconciliationEpic = (actions$, state$, zeniAPI) =>
12
14
  const state = state$.value;
13
15
  const currentTenant = getCurrentTenant(state);
14
16
  const selectedPeriod = state.expenseAutomationViewState.selectedPeriodByTenantId[currentTenant.tenantId];
17
+ const account = getAccountBase(state.accountState, accountId, 'excluded_account_reconciliation');
15
18
  const period = convertToPeriod(selectedPeriod, true);
16
19
  const query = JSON.stringify({
17
20
  start_date: period.start,
@@ -31,14 +34,32 @@ export const includeAccountInReconciliationEpic = (actions$, state$, zeniAPI) =>
31
34
  }), changeAccountKey({
32
35
  oldKey: oldAccountKey,
33
36
  newKey: newAccountKey,
37
+ }), openSnackbar({
38
+ messageSection: 'account_included_in_reconciliation',
39
+ messageText: 'success',
40
+ type: 'success',
41
+ variables: [
42
+ {
43
+ variableName: '_account-name_',
44
+ variableValue: account?.accountName ?? '',
45
+ },
46
+ ],
34
47
  }));
35
48
  }
36
49
  else {
37
50
  return of(includeAccountInReconciliationFailure({
38
51
  error: response.status,
52
+ }), openSnackbar({
53
+ messageSection: 'account_included_in_reconciliation',
54
+ messageText: 'failed',
55
+ type: 'error',
39
56
  }));
40
57
  }
41
58
  }), catchError((error) => of(includeAccountInReconciliationFailure({
42
59
  error: createZeniAPIStatus('Unexpected Error', `Include account in reconciliation REST API call errored out ${JSON.stringify(error)}`),
60
+ }), openSnackbar({
61
+ messageSection: 'account_included_in_reconciliation',
62
+ messageText: 'failed',
63
+ type: 'error',
43
64
  }))));
44
65
  }));
package/lib/index.d.ts CHANGED
@@ -123,7 +123,7 @@ import { PriorityCodeType, Task, TaskCodeType, TaskPriority, TaskStatus, TaskSta
123
123
  import { getTaskGroupById } from './entity/taskGroup/taskGroupSelector';
124
124
  import { TaskGroupState } from './entity/taskGroup/taskGroupState';
125
125
  import { TaskGroupTemplate } from './entity/taskGroupTemplate/taskGroupTemplateState';
126
- import { DoSignInPayload, clearAll, doMagicLinkSignIn, doSignIn, doSignOut, fetchActiveTenant, fetchAllTenants, fetchExcludedResources as fetchExcludedResourcesForTenant, fetchExternalConnections as fetchExternalConnectionsForTenant, fetchSubscriptionSummaryForTenant, resendVerifyDeviceOTP, resetSignInState, saveExternalConnection as saveExternalConnectionForTenant, sendEmailMagicLinkToUser, updateCurrentTenant, updateSignInState, verifyDeviceWithTwoFA } from './entity/tenant/tenantReducer';
126
+ import { DoSignInPayload, clearAll, doMagicLinkSignIn, doSignIn, doSignOut, sendSessionHeartbeat, fetchActiveTenant, fetchAllTenants, fetchExcludedResources as fetchExcludedResourcesForTenant, fetchExternalConnections as fetchExternalConnectionsForTenant, fetchSubscriptionSummaryForTenant, resendVerifyDeviceOTP, resetSignInState, saveExternalConnection as saveExternalConnectionForTenant, sendEmailMagicLinkToUser, updateCurrentTenant, updateSignInState, verifyDeviceWithTwoFA } from './entity/tenant/tenantReducer';
127
127
  import { CurrentTenant, TenantBaseView, TenantCoreDetailsView, TenantView, TenantsBaseOrdered, TenantsOrdered, getCurrentTenant, getIsAccountingClassesEnabled, getIsAccountingProjectsEnabled, getTenantBaseById, getTenantBaseViewForTenantId, getTenantBaseViewForTenantView, getTenantsBaseByCheckInDateSelector, getTenantsByCheckInDateSelector, getTenantsCoreDetailsByCheckInDateSelector, isOtherProductsEnabledForTenant, isTenantBankingOnly, isTenantBookkeepingEnabled, isTenantCardsOnly, isTenantUsingZeniCOA, isZeniDomainTenant, toTenantCoreDetailsView } from './entity/tenant/tenantSelector';
128
128
  import { Connection, LoggedInUser, RoleResource, Tenant, TenantProductSettings } from './entity/tenant/tenantState';
129
129
  import { ToastNotificationPayload } from './entity/toastNotification/toastNotificationPayload';
@@ -643,7 +643,7 @@ export { TimeframeTick, TimeframeTickWithMetaData, toTimeframeTick, mapTimePerio
643
643
  export { VendorSpendTrendFilterTabType, toVendorSpendTrendFilterTabsTypeStrict, } from './entity/vendorExpense/vendorExpenseSelector';
644
644
  export { getNumberOfPeriods };
645
645
  export { SCHEDULE_DAYS_OF_MONTH, ScheduleDaysOfMonth, toScheduleDaysOfMonth, Day, Month, toMonth, toMonthStrict, Quarter, toQuarter, toQuarterStrict, AbsoluteDay, TimePeriod, };
646
- export { Tenant, TenantView, LoggedInUser, TenantBaseView, CurrentTenant, TenantProductSettings, getTenantBaseById, getCurrentTenant, getIsAccountingClassesEnabled, getIsAccountingProjectsEnabled, getTenantsByCheckInDateSelector, getTenantsBaseByCheckInDateSelector, getTenantsCoreDetailsByCheckInDateSelector, toTenantCoreDetailsView, getTenantBaseViewForTenantView, getTenantBaseViewForTenantId, isZeniDomainTenant, isTenantUsingZeniCOA, TenantsBaseOrdered, TenantsOrdered, TenantCoreDetailsView, fetchActiveTenant, fetchAllTenants, updateCurrentTenant, clearAll, doMagicLinkSignIn, verifyDeviceWithTwoFA, resendVerifyDeviceOTP, sendEmailMagicLinkToUser, doSignIn, updateSignInState, DoSignInPayload, doSignOut, resetSignInState, RoleResource, Connection, fetchExcludedResourcesForTenant, fetchExternalConnectionsForTenant, saveExternalConnectionForTenant, fetchSubscriptionSummaryForTenant, isTenantBankingOnly, isTenantCardsOnly, isTenantBookkeepingEnabled, isOtherProductsEnabledForTenant, };
646
+ export { Tenant, TenantView, LoggedInUser, TenantBaseView, CurrentTenant, TenantProductSettings, getTenantBaseById, getCurrentTenant, getIsAccountingClassesEnabled, getIsAccountingProjectsEnabled, getTenantsByCheckInDateSelector, getTenantsBaseByCheckInDateSelector, getTenantsCoreDetailsByCheckInDateSelector, toTenantCoreDetailsView, getTenantBaseViewForTenantView, getTenantBaseViewForTenantId, isZeniDomainTenant, isTenantUsingZeniCOA, TenantsBaseOrdered, TenantsOrdered, TenantCoreDetailsView, fetchActiveTenant, fetchAllTenants, updateCurrentTenant, clearAll, doMagicLinkSignIn, verifyDeviceWithTwoFA, resendVerifyDeviceOTP, sendEmailMagicLinkToUser, doSignIn, updateSignInState, DoSignInPayload, doSignOut, sendSessionHeartbeat, resetSignInState, RoleResource, Connection, fetchExcludedResourcesForTenant, fetchExternalConnectionsForTenant, saveExternalConnectionForTenant, fetchSubscriptionSummaryForTenant, isTenantBankingOnly, isTenantCardsOnly, isTenantBookkeepingEnabled, isOtherProductsEnabledForTenant, };
647
647
  export { Account, AccountType, AccountBase, StatementCloseDay, toAccountType, AccountReport, NestedAccountReport, AccountWithBalanceReport, AccountGroup, AccountGroupReportV2, AccountGroupType, toAccountGroupType, AccountGroupReport, getAccountGroupKey, AccountGroupKey, RecommendedAccountBase, };
648
648
  export { Class, ClassBase, RecommendedClassBase, } from './entity/class/classState';
649
649
  export { getClassById } from './entity/class/classSelector';
@@ -901,3 +901,6 @@ export { BULK_UPLOAD_AUTOMATCHING_TIMEOUT_MS, BULK_UPLOAD_BAR_COMPLETE_HOLD_MS,
901
901
  export { fetchTransactionActivityLog } from './view/transactionActivityLogView/transactionActivityLogViewReducer';
902
902
  export { TransactionActivityLogViewSelectorView, getTransactionActivityLogView, } from './view/transactionActivityLogView/transactionActivityLogViewSelector';
903
903
  export { UserGroup } from './entity/userGroups/userGroupsState';
904
+ export { SessionManager } from './entity/tenant/SessionManager';
905
+ export type { SessionCallbacks, SessionConfig } from './entity/tenant/sessionTypes';
906
+ export { DEFAULT_SESSION_CONFIG } from './entity/tenant/sessionTypes';