@zeniai/client-epic-state 5.0.37 → 5.0.38-betaNB1

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 (162) hide show
  1. package/lib/commonStateTypes/fiscalYearHelpers/formatZeniDateFY.d.ts +1 -0
  2. package/lib/commonStateTypes/fiscalYearHelpers/formatZeniDateFY.js +2 -1
  3. package/lib/commonStateTypes/viewAndReport/agingReportStateTypes.d.ts +1 -1
  4. package/lib/entity/accountRecon/accountReconPayload.d.ts +19 -1
  5. package/lib/entity/accountRecon/accountReconPayload.js +21 -0
  6. package/lib/entity/accountRecon/accountReconSelector.d.ts +5 -1
  7. package/lib/entity/accountRecon/accountReconSelector.js +4 -0
  8. package/lib/entity/accountRecon/accountReconState.d.ts +18 -0
  9. package/lib/entity/file/fileState.d.ts +4 -4
  10. package/lib/entity/file/fileState.js +4 -0
  11. package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
  12. package/lib/entity/snackbar/snackbarTypes.js +4 -0
  13. package/lib/entity/task/taskPayload.d.ts +3 -0
  14. package/lib/entity/task/taskPayload.js +5 -0
  15. package/lib/entity/task/taskState.d.ts +3 -0
  16. package/lib/entity/tenant/clearAllEpic.d.ts +5 -2
  17. package/lib/entity/tenant/clearAllEpic.js +6 -0
  18. package/lib/entity/tenant/epic/deleteConnectionEpic.d.ts +19 -0
  19. package/lib/entity/tenant/epic/deleteConnectionEpic.js +29 -0
  20. package/lib/entity/tenant/epic/saveAPIKeyConnectionEpic.d.ts +19 -0
  21. package/lib/entity/tenant/epic/saveAPIKeyConnectionEpic.js +31 -0
  22. package/lib/entity/tenant/epic/saveOAuthConnectionEpic.d.ts +19 -0
  23. package/lib/entity/tenant/epic/saveOAuthConnectionEpic.js +33 -0
  24. package/lib/entity/tenant/tenantPayload.d.ts +1 -0
  25. package/lib/entity/tenant/tenantReducer.d.ts +59 -1
  26. package/lib/entity/tenant/tenantReducer.js +139 -4
  27. package/lib/entity/tenant/tenantState.d.ts +7 -0
  28. package/lib/entity/transaction/stateTypes/attachment.d.ts +2 -2
  29. package/lib/epic.d.ts +9 -1
  30. package/lib/epic.js +12 -1
  31. package/lib/esm/commonStateTypes/fiscalYearHelpers/formatZeniDateFY.js +1 -0
  32. package/lib/esm/entity/accountRecon/accountReconPayload.js +21 -0
  33. package/lib/esm/entity/accountRecon/accountReconSelector.js +4 -0
  34. package/lib/esm/entity/file/fileState.js +4 -0
  35. package/lib/esm/entity/snackbar/snackbarTypes.js +4 -0
  36. package/lib/esm/entity/task/taskPayload.js +5 -0
  37. package/lib/esm/entity/tenant/clearAllEpic.js +6 -0
  38. package/lib/esm/entity/tenant/epic/deleteConnectionEpic.js +25 -0
  39. package/lib/esm/entity/tenant/epic/saveAPIKeyConnectionEpic.js +27 -0
  40. package/lib/esm/entity/tenant/epic/saveOAuthConnectionEpic.js +29 -0
  41. package/lib/esm/entity/tenant/tenantReducer.js +135 -2
  42. package/lib/esm/epic.js +12 -1
  43. package/lib/esm/index.js +15 -6
  44. package/lib/esm/init.js +71 -16
  45. package/lib/esm/reducer.js +9 -0
  46. package/lib/esm/view/expenseAutomationView/reducers/reconciliationViewReducer.js +7 -2
  47. package/lib/esm/view/expenseAutomationView/selectors/reconciliationViewSelector.js +2 -0
  48. package/lib/esm/view/expenseAutomationView/types/reconciliationViewState.js +20 -0
  49. package/lib/esm/view/featureNotificationView/epics/fetchRegisteredInterestsEpic.js +23 -0
  50. package/lib/esm/view/featureNotificationView/epics/notifyMeForFeatureEpic.js +25 -0
  51. package/lib/esm/view/featureNotificationView/featureNotificationViewPayload.js +11 -0
  52. package/lib/esm/view/featureNotificationView/featureNotificationViewReducer.js +106 -0
  53. package/lib/esm/view/featureNotificationView/featureNotificationViewSelector.js +4 -0
  54. package/lib/esm/view/featureNotificationView/featureNotificationViewState.js +1 -0
  55. package/lib/esm/view/taskManager/cannedResponsesView/cannedResponses.js +1 -0
  56. package/lib/esm/view/taskManager/cannedResponsesView/cannedResponsesPayload.js +12 -0
  57. package/lib/esm/view/taskManager/cannedResponsesView/cannedResponsesReducer.js +64 -0
  58. package/lib/esm/view/taskManager/cannedResponsesView/cannedResponsesSelector.js +3 -0
  59. package/lib/esm/view/taskManager/cannedResponsesView/epics/deleteCannedResponseEpic.js +17 -0
  60. package/lib/esm/view/taskManager/cannedResponsesView/epics/fetchCannedResponsesEpic.js +21 -0
  61. package/lib/esm/view/taskManager/cannedResponsesView/epics/saveCannedResponseEpic.js +29 -0
  62. package/lib/esm/view/taskManager/taskDetailView/epics/archiveTaskEpic.js +3 -0
  63. package/lib/esm/view/taskManager/taskDetailView/epics/deleteTaskEpic.js +5 -0
  64. package/lib/esm/view/taskManager/taskDetailView/epics/initializeTaskToLocalStoreEpic.js +1 -0
  65. package/lib/esm/view/taskManager/taskDetailView/epics/saveTaskDetailEpic.js +1 -0
  66. package/lib/esm/view/taskManager/taskDetailView/epics/snoozeTaskEpic.js +66 -0
  67. package/lib/esm/view/taskManager/taskDetailView/epics/unsnoozeTaskEpic.js +57 -0
  68. package/lib/esm/view/taskManager/taskDetailView/taskDetail.js +4 -0
  69. package/lib/esm/view/taskManager/taskDetailView/taskDetailReducer.js +60 -7
  70. package/lib/esm/view/taskManager/taskDetailView/taskDetailSelector.js +12 -0
  71. package/lib/esm/view/taskManager/taskListView/epics/bulkUpdateTaskListEpic.js +56 -21
  72. package/lib/esm/view/taskManager/taskListView/epics/dragNDropTasksEpic.js +1 -0
  73. package/lib/esm/view/taskManager/taskListView/epics/fetchTaskListEpic.js +13 -4
  74. package/lib/esm/view/taskManager/taskListView/epics/updateTaskFromListViewEpic.js +3 -2
  75. package/lib/esm/view/taskManager/taskListView/taskList.js +7 -0
  76. package/lib/esm/view/taskManager/taskListView/taskListReducer.js +106 -12
  77. package/lib/esm/view/taskManager/taskListView/taskListSelector.js +48 -39
  78. package/lib/esm/view/zeniOAuthView/epics/approveOAuthConsentEpic.js +65 -0
  79. package/lib/esm/view/zeniOAuthView/zeniOAuthParamsParser.js +41 -0
  80. package/lib/esm/view/zeniOAuthView/zeniOAuthReducer.js +49 -0
  81. package/lib/esm/view/zeniOAuthView/zeniOAuthSelector.js +3 -0
  82. package/lib/esm/view/zeniOAuthView/zeniOAuthState.js +1 -0
  83. package/lib/index.d.ts +18 -6
  84. package/lib/index.js +67 -30
  85. package/lib/init.d.ts +5 -3
  86. package/lib/init.js +71 -16
  87. package/lib/reducer.d.ts +9 -0
  88. package/lib/reducer.js +9 -0
  89. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
  90. package/lib/view/expenseAutomationView/payload/reconciliationPayload.d.ts +19 -0
  91. package/lib/view/expenseAutomationView/reducers/reconciliationViewReducer.js +7 -2
  92. package/lib/view/expenseAutomationView/selectorTypes/reconciliationViewSelectorTypes.d.ts +2 -1
  93. package/lib/view/expenseAutomationView/selectors/reconciliationViewSelector.js +2 -0
  94. package/lib/view/expenseAutomationView/types/reconciliationViewState.d.ts +24 -0
  95. package/lib/view/expenseAutomationView/types/reconciliationViewState.js +21 -0
  96. package/lib/view/featureNotificationView/epics/fetchRegisteredInterestsEpic.d.ts +16 -0
  97. package/lib/view/featureNotificationView/epics/fetchRegisteredInterestsEpic.js +27 -0
  98. package/lib/view/featureNotificationView/epics/notifyMeForFeatureEpic.d.ts +14 -0
  99. package/lib/view/featureNotificationView/epics/notifyMeForFeatureEpic.js +29 -0
  100. package/lib/view/featureNotificationView/featureNotificationViewPayload.d.ts +23 -0
  101. package/lib/view/featureNotificationView/featureNotificationViewPayload.js +15 -0
  102. package/lib/view/featureNotificationView/featureNotificationViewReducer.d.ts +19 -0
  103. package/lib/view/featureNotificationView/featureNotificationViewReducer.js +110 -0
  104. package/lib/view/featureNotificationView/featureNotificationViewSelector.d.ts +6 -0
  105. package/lib/view/featureNotificationView/featureNotificationViewSelector.js +11 -0
  106. package/lib/view/featureNotificationView/featureNotificationViewState.d.ts +26 -0
  107. package/lib/view/featureNotificationView/featureNotificationViewState.js +2 -0
  108. package/lib/view/taskManager/cannedResponsesView/cannedResponses.d.ts +19 -0
  109. package/lib/view/taskManager/cannedResponsesView/cannedResponses.js +2 -0
  110. package/lib/view/taskManager/cannedResponsesView/cannedResponsesPayload.d.ts +21 -0
  111. package/lib/view/taskManager/cannedResponsesView/cannedResponsesPayload.js +15 -0
  112. package/lib/view/taskManager/cannedResponsesView/cannedResponsesReducer.d.ts +30 -0
  113. package/lib/view/taskManager/cannedResponsesView/cannedResponsesReducer.js +68 -0
  114. package/lib/view/taskManager/cannedResponsesView/cannedResponsesSelector.d.ts +3 -0
  115. package/lib/view/taskManager/cannedResponsesView/cannedResponsesSelector.js +6 -0
  116. package/lib/view/taskManager/cannedResponsesView/epics/deleteCannedResponseEpic.d.ts +7 -0
  117. package/lib/view/taskManager/cannedResponsesView/epics/deleteCannedResponseEpic.js +21 -0
  118. package/lib/view/taskManager/cannedResponsesView/epics/fetchCannedResponsesEpic.d.ts +7 -0
  119. package/lib/view/taskManager/cannedResponsesView/epics/fetchCannedResponsesEpic.js +25 -0
  120. package/lib/view/taskManager/cannedResponsesView/epics/saveCannedResponseEpic.d.ts +7 -0
  121. package/lib/view/taskManager/cannedResponsesView/epics/saveCannedResponseEpic.js +33 -0
  122. package/lib/view/taskManager/taskDetailView/epics/archiveTaskEpic.d.ts +2 -1
  123. package/lib/view/taskManager/taskDetailView/epics/archiveTaskEpic.js +3 -0
  124. package/lib/view/taskManager/taskDetailView/epics/deleteTaskEpic.d.ts +2 -1
  125. package/lib/view/taskManager/taskDetailView/epics/deleteTaskEpic.js +5 -0
  126. package/lib/view/taskManager/taskDetailView/epics/initializeTaskToLocalStoreEpic.js +1 -0
  127. package/lib/view/taskManager/taskDetailView/epics/saveTaskDetailEpic.js +1 -0
  128. package/lib/view/taskManager/taskDetailView/epics/snoozeTaskEpic.d.ts +9 -0
  129. package/lib/view/taskManager/taskDetailView/epics/snoozeTaskEpic.js +70 -0
  130. package/lib/view/taskManager/taskDetailView/epics/unsnoozeTaskEpic.d.ts +9 -0
  131. package/lib/view/taskManager/taskDetailView/epics/unsnoozeTaskEpic.js +61 -0
  132. package/lib/view/taskManager/taskDetailView/taskDetail.d.ts +2 -0
  133. package/lib/view/taskManager/taskDetailView/taskDetail.js +4 -0
  134. package/lib/view/taskManager/taskDetailView/taskDetailReducer.d.ts +10 -1
  135. package/lib/view/taskManager/taskDetailView/taskDetailReducer.js +61 -8
  136. package/lib/view/taskManager/taskDetailView/taskDetailSelector.d.ts +5 -0
  137. package/lib/view/taskManager/taskDetailView/taskDetailSelector.js +12 -0
  138. package/lib/view/taskManager/taskListView/epics/bulkUpdateTaskListEpic.d.ts +6 -7
  139. package/lib/view/taskManager/taskListView/epics/bulkUpdateTaskListEpic.js +56 -22
  140. package/lib/view/taskManager/taskListView/epics/dragNDropTasksEpic.js +1 -0
  141. package/lib/view/taskManager/taskListView/epics/fetchTaskListEpic.js +13 -4
  142. package/lib/view/taskManager/taskListView/epics/updateTaskFromListViewEpic.js +3 -2
  143. package/lib/view/taskManager/taskListView/taskList.d.ts +14 -1
  144. package/lib/view/taskManager/taskListView/taskList.js +8 -1
  145. package/lib/view/taskManager/taskListView/taskListPayload.d.ts +3 -0
  146. package/lib/view/taskManager/taskListView/taskListReducer.d.ts +9 -6
  147. package/lib/view/taskManager/taskListView/taskListReducer.js +107 -13
  148. package/lib/view/taskManager/taskListView/taskListSelector.d.ts +9 -3
  149. package/lib/view/taskManager/taskListView/taskListSelector.js +48 -39
  150. package/lib/view/vendorFiling1099/vendorFiling1099List/vendorFiling1099ListState.d.ts +1 -1
  151. package/lib/view/zeniOAuthView/epics/approveOAuthConsentEpic.d.ts +27 -0
  152. package/lib/view/zeniOAuthView/epics/approveOAuthConsentEpic.js +69 -0
  153. package/lib/view/zeniOAuthView/zeniOAuthParamsParser.d.ts +16 -0
  154. package/lib/view/zeniOAuthView/zeniOAuthParamsParser.js +44 -0
  155. package/lib/view/zeniOAuthView/zeniOAuthReducer.d.ts +29 -0
  156. package/lib/view/zeniOAuthView/zeniOAuthReducer.js +53 -0
  157. package/lib/view/zeniOAuthView/zeniOAuthSelector.d.ts +5 -0
  158. package/lib/view/zeniOAuthView/zeniOAuthSelector.js +9 -0
  159. package/lib/view/zeniOAuthView/zeniOAuthState.d.ts +4 -0
  160. package/lib/view/zeniOAuthView/zeniOAuthState.js +2 -0
  161. package/package.json +1 -1
  162. package/lib/tsconfig.typecheck.tsbuildinfo +0 -1
@@ -2,6 +2,7 @@ import { createSlice } from '@reduxjs/toolkit';
2
2
  import { toMonthYearPeriodId, } from '../../../commonStateTypes/timePeriod';
3
3
  import { toReconciliationAccountSource } from '../../../entity/account/accountState';
4
4
  import { toBankStatusCodeType } from '../../../entity/accountRecon/accountReconState';
5
+ import { toReconciliationViewSummary, } from '../types/reconciliationViewState';
5
6
  // Initial state
6
7
  export const initialReconciliationTabsState = {
7
8
  balances: {
@@ -75,6 +76,7 @@ export const initialState = {
75
76
  },
76
77
  },
77
78
  excludedAccountIDs: [],
79
+ summary: undefined,
78
80
  };
79
81
  // Create slice with reducers
80
82
  const expenseAutomationReconciliationView = createSlice({
@@ -143,7 +145,7 @@ const expenseAutomationReconciliationView = createSlice({
143
145
  fetchReconciliationSuccess: {
144
146
  reducer(draft, action) {
145
147
  if (action.payload.accountId == null) {
146
- updateAllReconciliation(draft, action.payload.reconciliation.accounts, action.payload.selectedPeriod, action.payload.reconciliation.reconciliation, action.payload.refreshViewInBackground, action.payload.reconciliation.excluded_accounts ?? []);
148
+ updateAllReconciliation(draft, action.payload.reconciliation.accounts, action.payload.selectedPeriod, action.payload.reconciliation.reconciliation, action.payload.refreshViewInBackground, action.payload.reconciliation.excluded_accounts ?? [], action.payload.reconciliation.summary);
147
149
  }
148
150
  else if (action.payload.reconciliation.reconciliation.length > 0 &&
149
151
  action.payload.reconciliation.accounts.length > 0) {
@@ -527,7 +529,7 @@ const expenseAutomationReconciliationView = createSlice({
527
529
  export const { fetchReconciliation, fetchReconciliationFailure, fetchReconciliationSuccess, saveReconciliationDetail, saveReconciliationDetailFailure, updateSelectedAccountId, setConnectionInProgressForAccount, setStatementParseInProgress, updateReconcileTabLocalData, updateReconcileTabListSortState, updateReconcileTabListScrollState, saveReconciliationDetailSuccess, updateSelectedTab, updateBalancesLocalData, initialiseLocalDataForSelectedAccountId, clearExpenseAutomationReconciliationView, updateSelectedDrawerAccountId, updateReviewTabSortState, initializeReconciliationReviewTabLocalData, updateReviewTabLocalData, saveReconciliationReview, updateSaveReconciliationReviewFetchStatus, updateReconListScrollPosition, updateAccountReconciliationLocalData, deleteAccountStatement, deleteAccountStatementSuccess, deleteAccountStatementFailure, excludeAccountFromReconciliation, excludeAccountFromReconciliationSuccess, excludeAccountFromReconciliationFailure, includeAccountInReconciliation, includeAccountInReconciliationSuccess, includeAccountInReconciliationFailure, uploadAccountStatement, uploadAccountStatementSuccess, uploadAccountStatementFailure, updateStatementUploadChosen, updateNodeCollapseState, } = expenseAutomationReconciliationView.actions;
528
530
  // Export reducer
529
531
  export default expenseAutomationReconciliationView.reducer;
530
- function updateAllReconciliation(draft, accounts, selectedPeriod, reconciliationData, refreshViewInBackground, excludedAccounts) {
532
+ function updateAllReconciliation(draft, accounts, selectedPeriod, reconciliationData, refreshViewInBackground, excludedAccounts, summary) {
531
533
  draft.excludedAccountIDs = excludedAccounts.map((ea) => ea.account_id);
532
534
  draft.excludedAccountExclusionInfo = {};
533
535
  excludedAccounts.forEach((ea) => {
@@ -609,6 +611,9 @@ function updateAllReconciliation(draft, accounts, selectedPeriod, reconciliation
609
611
  draft.fetchState = 'Completed';
610
612
  draft.error = undefined;
611
613
  }
614
+ if (summary !== undefined) {
615
+ draft.summary = toReconciliationViewSummary(summary);
616
+ }
612
617
  }
613
618
  function updateReconciliationByAccountID(draft, accounts, selectedPeriod, accountId, reconciliationData, refreshViewInBackground) {
614
619
  const oldRecord = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)].reconciliationByAccountID[accountId];
@@ -115,6 +115,7 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
115
115
  excludeAccountFetchState: reconciliationViewState.actionFetchState.excludeAccountFetch,
116
116
  includeAccountFetchState: reconciliationViewState.actionFetchState.includeAccountFetch,
117
117
  excludedAccountIDs: reconciliationViewState.excludedAccountIDs,
118
+ summary: reconciliationViewState.summary,
118
119
  };
119
120
  }
120
121
  const allAccountIDs = accountReconForMonthYearPeriod.accountIDs;
@@ -423,6 +424,7 @@ export const getExpenseAutomationReconciliationView = createSelector((state) =>
423
424
  excludeAccountFetchState: reconciliationViewState.actionFetchState.excludeAccountFetch,
424
425
  includeAccountFetchState: reconciliationViewState.actionFetchState.includeAccountFetch,
425
426
  excludedAccountIDs: reconciliationViewState.excludedAccountIDs,
427
+ summary: reconciliationViewState.summary,
426
428
  };
427
429
  });
428
430
  export const isAccountReconReport = (reportId) => {
@@ -1,4 +1,24 @@
1
1
  import { stringToUnion } from '../../../commonStateTypes/stringToUnion';
2
+ export function toReconciliationViewSummary(payload) {
3
+ return {
4
+ accounts: {
5
+ done: payload.accounts.done,
6
+ failed: payload.accounts.failed,
7
+ inProgress: payload.accounts.in_progress,
8
+ total: payload.accounts.total,
9
+ },
10
+ accountsToConnectCount: payload.accounts_to_connect_count,
11
+ autoMatched: {
12
+ matchedTxns: payload.auto_matched.matched_txns,
13
+ totalTxns: payload.auto_matched.total_txns,
14
+ },
15
+ needsReview: {
16
+ accountCount: payload.needs_review.account_count,
17
+ txnCount: payload.needs_review.txn_count,
18
+ },
19
+ timeSavedPercentage: payload.time_saved_percentage,
20
+ };
21
+ }
2
22
  export const RECONCILE_ACTIONS = [
3
23
  'reconcile',
4
24
  'save_reconcile_for_later',
@@ -0,0 +1,23 @@
1
+ import { from } from 'rxjs';
2
+ import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
3
+ import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
4
+ import { toFeatureInterest, } from '../featureNotificationViewPayload';
5
+ import { fetchRegisteredInterests, fetchRegisteredInterestsFailure, fetchRegisteredInterestsSuccess, } from '../featureNotificationViewReducer';
6
+ export const fetchRegisteredInterestsEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(fetchRegisteredInterests.match), switchMap((action) => zeniAPI
7
+ .getJSON(`${zeniAPI.apiEndPoints.notificationMicroServiceBaseUrl}/1.0/feature-interests?feature=${encodeURIComponent(action.payload.feature)}`)
8
+ .pipe(mergeMap((response) => {
9
+ if (isSuccessResponse(response) && response.data != null) {
10
+ const interests = response.data.feature_interests.map(toFeatureInterest);
11
+ return from([fetchRegisteredInterestsSuccess(interests)]);
12
+ }
13
+ const status = response.status ??
14
+ createZeniAPIStatus('Failed to fetch registered interests. Please try again.');
15
+ return from([fetchRegisteredInterestsFailure(status)]);
16
+ }), catchError((error) => {
17
+ const message = error instanceof Error
18
+ ? error.message
19
+ : 'Unexpected error fetching registered interests.';
20
+ return from([
21
+ fetchRegisteredInterestsFailure(createZeniAPIStatus(message)),
22
+ ]);
23
+ }))));
@@ -0,0 +1,25 @@
1
+ import { from } from 'rxjs';
2
+ import { catchError, filter, mergeMap, switchMap } from 'rxjs/operators';
3
+ import { createZeniAPIStatus, isSuccessResponse } from '../../../responsePayload';
4
+ import { notifyMeForFeature, notifyMeForFeatureFailure, notifyMeForFeatureSuccess, } from '../featureNotificationViewReducer';
5
+ export const notifyMeForFeatureEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(notifyMeForFeature.match), switchMap((action) => zeniAPI
6
+ .postAndGetJSON(`${zeniAPI.apiEndPoints.notificationMicroServiceBaseUrl}/1.0/feature-interests`, {
7
+ additional_info: action.payload.additionalInfo,
8
+ email: action.payload.email,
9
+ feature: action.payload.feature,
10
+ })
11
+ .pipe(mergeMap((response) => {
12
+ if (isSuccessResponse(response) && response.data != null) {
13
+ return from([notifyMeForFeatureSuccess(response.data)]);
14
+ }
15
+ const status = response.status ??
16
+ createZeniAPIStatus('Failed to register interest. Please try again.');
17
+ return from([notifyMeForFeatureFailure(status)]);
18
+ }), catchError((error) => {
19
+ const message = error instanceof Error
20
+ ? error.message
21
+ : 'Unexpected error registering interest.';
22
+ return from([
23
+ notifyMeForFeatureFailure(createZeniAPIStatus(message)),
24
+ ]);
25
+ }))));
@@ -0,0 +1,11 @@
1
+ import { date } from '../../zeniDayJS';
2
+ export const toFeatureInterest = (payload) => ({
3
+ interestId: payload.interest_id,
4
+ feature: payload.feature,
5
+ notified: payload.notified,
6
+ createTime: date(payload.create_time),
7
+ updateTime: date(payload.update_time),
8
+ additionalInfo: payload.additional_info ?? undefined,
9
+ email: payload.email ?? undefined,
10
+ notifiedTime: payload.notified_time != null ? date(payload.notified_time) : undefined,
11
+ });
@@ -0,0 +1,106 @@
1
+ import { createSlice } from '@reduxjs/toolkit';
2
+ import { toFeatureInterest, } from './featureNotificationViewPayload';
3
+ export const initialState = {
4
+ fetchRegisteredInterestsState: {
5
+ fetchState: 'Not-Started',
6
+ error: undefined,
7
+ },
8
+ notifyMeForFeatureState: {
9
+ fetchState: 'Not-Started',
10
+ error: undefined,
11
+ },
12
+ registeredInterests: [],
13
+ };
14
+ const featureNotificationView = createSlice({
15
+ name: 'featureNotificationView',
16
+ initialState,
17
+ reducers: {
18
+ notifyMeForFeature: {
19
+ prepare(feature, additionalInfo, email) {
20
+ return { payload: { feature, additionalInfo, email } };
21
+ },
22
+ reducer(draft,
23
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
24
+ _action) {
25
+ draft.notifyMeForFeatureState = {
26
+ fetchState: 'In-Progress',
27
+ error: undefined,
28
+ };
29
+ },
30
+ },
31
+ notifyMeForFeatureSuccess: {
32
+ prepare(payload) {
33
+ return { payload };
34
+ },
35
+ reducer(draft, action) {
36
+ draft.notifyMeForFeatureState = {
37
+ fetchState: 'Completed',
38
+ error: undefined,
39
+ };
40
+ const interest = toFeatureInterest(action.payload);
41
+ // Idempotent: if a row for this (feature, additional_info) already
42
+ // exists in the slice, replace it; otherwise append.
43
+ const existingIndex = draft.registeredInterests.findIndex((r) => r.feature === interest.feature &&
44
+ r.additionalInfo === interest.additionalInfo);
45
+ if (existingIndex >= 0) {
46
+ draft.registeredInterests[existingIndex] = interest;
47
+ }
48
+ else {
49
+ draft.registeredInterests.push(interest);
50
+ }
51
+ },
52
+ },
53
+ notifyMeForFeatureFailure: {
54
+ prepare(status) {
55
+ return { payload: { status } };
56
+ },
57
+ reducer(draft, action) {
58
+ draft.notifyMeForFeatureState = {
59
+ fetchState: 'Error',
60
+ error: action.payload.status,
61
+ };
62
+ },
63
+ },
64
+ fetchRegisteredInterests: {
65
+ prepare(feature) {
66
+ return { payload: { feature } };
67
+ },
68
+ reducer(draft,
69
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
70
+ _action) {
71
+ draft.fetchRegisteredInterestsState = {
72
+ fetchState: 'In-Progress',
73
+ error: undefined,
74
+ };
75
+ },
76
+ },
77
+ fetchRegisteredInterestsSuccess: {
78
+ prepare(interests) {
79
+ return { payload: { interests } };
80
+ },
81
+ reducer(draft, action) {
82
+ draft.fetchRegisteredInterestsState = {
83
+ fetchState: 'Completed',
84
+ error: undefined,
85
+ };
86
+ draft.registeredInterests = action.payload.interests;
87
+ },
88
+ },
89
+ fetchRegisteredInterestsFailure: {
90
+ prepare(status) {
91
+ return { payload: { status } };
92
+ },
93
+ reducer(draft, action) {
94
+ draft.fetchRegisteredInterestsState = {
95
+ fetchState: 'Error',
96
+ error: action.payload.status,
97
+ };
98
+ },
99
+ },
100
+ clearFeatureNotificationView(draft) {
101
+ Object.assign(draft, initialState);
102
+ },
103
+ },
104
+ });
105
+ export const { clearFeatureNotificationView, fetchRegisteredInterests, fetchRegisteredInterestsFailure, fetchRegisteredInterestsSuccess, notifyMeForFeature, notifyMeForFeatureFailure, notifyMeForFeatureSuccess, } = featureNotificationView.actions;
106
+ export default featureNotificationView.reducer;
@@ -0,0 +1,4 @@
1
+ export const getFeatureNotificationView = (state) => state.featureNotificationViewState;
2
+ export const getRegisteredInterests = (state) => state.featureNotificationViewState.registeredInterests;
3
+ export const getRegisteredInterestsByFeature = (state, feature) => state.featureNotificationViewState.registeredInterests.filter((interest) => interest.feature === feature);
4
+ export const isFeatureInterestRegistered = (state, feature, additionalInfo) => state.featureNotificationViewState.registeredInterests.some((interest) => interest.feature === feature && interest.additionalInfo === additionalInfo);
@@ -0,0 +1,12 @@
1
+ import { date } from '../../../zeniDayJS';
2
+ export function mapCannedResponsePayloadToCannedResponse(payload) {
3
+ return {
4
+ cannedResponseId: payload.canned_response_id,
5
+ content: payload.content,
6
+ createTime: date(payload.create_time),
7
+ createdBy: payload.created_by,
8
+ isDeleted: payload.is_deleted,
9
+ name: payload.name,
10
+ updateTime: date(payload.update_time),
11
+ };
12
+ }
@@ -0,0 +1,64 @@
1
+ import { createSlice } from '@reduxjs/toolkit';
2
+ export const initialState = {
3
+ cannedResponses: [],
4
+ fetchState: 'Not-Started',
5
+ saveFetchState: 'Not-Started',
6
+ deleteFetchState: 'Not-Started',
7
+ error: undefined,
8
+ };
9
+ const cannedResponsesView = createSlice({
10
+ name: 'cannedResponsesView',
11
+ initialState,
12
+ reducers: {
13
+ fetchCannedResponses(draft) {
14
+ draft.fetchState =
15
+ draft.cannedResponses.length > 0 ? 'Completed' : 'In-Progress';
16
+ draft.error = undefined;
17
+ },
18
+ updateCannedResponses(draft, action) {
19
+ draft.cannedResponses = action.payload.cannedResponses;
20
+ draft.fetchState = 'Completed';
21
+ draft.error = undefined;
22
+ },
23
+ updateCannedResponsesFetchStatus(draft, action) {
24
+ draft.fetchState = action.payload.fetchState;
25
+ draft.error = action.payload.error;
26
+ },
27
+ saveCannedResponse: {
28
+ reducer(draft) {
29
+ draft.saveFetchState = 'In-Progress';
30
+ },
31
+ prepare(payload) {
32
+ return { payload };
33
+ },
34
+ },
35
+ saveCannedResponseSuccess(draft) {
36
+ draft.saveFetchState = 'Completed';
37
+ },
38
+ saveCannedResponseFailure(draft, action) {
39
+ draft.saveFetchState = 'Error';
40
+ draft.error = action.payload.error;
41
+ },
42
+ deleteCannedResponse: {
43
+ reducer(draft) {
44
+ draft.deleteFetchState = 'In-Progress';
45
+ },
46
+ prepare(payload) {
47
+ return { payload };
48
+ },
49
+ },
50
+ deleteCannedResponseSuccess(draft, action) {
51
+ draft.deleteFetchState = 'Completed';
52
+ draft.cannedResponses = draft.cannedResponses.filter((r) => r.cannedResponseId !== action.payload.cannedResponseId);
53
+ },
54
+ deleteCannedResponseFailure(draft, action) {
55
+ draft.deleteFetchState = 'Error';
56
+ draft.error = action.payload.error;
57
+ },
58
+ clearCannedResponses() {
59
+ return initialState;
60
+ },
61
+ },
62
+ });
63
+ export const { fetchCannedResponses, updateCannedResponses, updateCannedResponsesFetchStatus, saveCannedResponse, saveCannedResponseSuccess, saveCannedResponseFailure, deleteCannedResponse, deleteCannedResponseSuccess, deleteCannedResponseFailure, clearCannedResponses, } = cannedResponsesView.actions;
64
+ export default cannedResponsesView.reducer;
@@ -0,0 +1,3 @@
1
+ export function getCannedResponsesView(state) {
2
+ return state.cannedResponsesState;
3
+ }
@@ -0,0 +1,17 @@
1
+ import { of } from 'rxjs';
2
+ import { catchError, filter, mergeMap } from 'rxjs/operators';
3
+ import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
4
+ import { deleteCannedResponse, deleteCannedResponseFailure, deleteCannedResponseSuccess, } from '../cannedResponsesReducer';
5
+ export const deleteCannedResponseEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(deleteCannedResponse.match), mergeMap((action) => {
6
+ const { cannedResponseId } = action.payload;
7
+ return zeniAPI
8
+ .deleteAndGetJSON(`${zeniAPI.apiEndPoints.taskMicroServiceBaseUrl}/1.0/task-manager/canned-responses/${cannedResponseId}`)
9
+ .pipe(mergeMap((response) => {
10
+ if (isSuccessResponse(response)) {
11
+ return of(deleteCannedResponseSuccess({ cannedResponseId }));
12
+ }
13
+ return of(deleteCannedResponseFailure({ error: response.status }));
14
+ }), catchError((error) => of(deleteCannedResponseFailure({
15
+ error: createZeniAPIStatus('Unexpected Error', 'Delete Canned Response errored: ' + JSON.stringify(error)),
16
+ }))));
17
+ }));
@@ -0,0 +1,21 @@
1
+ import { of } from 'rxjs';
2
+ import { catchError, filter, switchMap, mergeMap } from 'rxjs/operators';
3
+ import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
4
+ import { mapCannedResponsePayloadToCannedResponse, } from '../cannedResponsesPayload';
5
+ import { fetchCannedResponses, updateCannedResponses, updateCannedResponsesFetchStatus, } from '../cannedResponsesReducer';
6
+ export const fetchCannedResponsesEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(fetchCannedResponses.match), switchMap(() => zeniAPI
7
+ .getJSON(`${zeniAPI.apiEndPoints.taskMicroServiceBaseUrl}/1.0/task-manager/canned-responses`)
8
+ .pipe(mergeMap((response) => {
9
+ if (isSuccessResponse(response) && response.data != null) {
10
+ return of(updateCannedResponses({
11
+ cannedResponses: (response.data.canned_responses ?? []).map(mapCannedResponsePayloadToCannedResponse),
12
+ }));
13
+ }
14
+ return of(updateCannedResponsesFetchStatus({
15
+ fetchState: 'Error',
16
+ error: response.status,
17
+ }));
18
+ }), catchError((error) => of(updateCannedResponsesFetchStatus({
19
+ fetchState: 'Error',
20
+ error: createZeniAPIStatus('Unexpected Error', 'Fetch Canned Responses errored: ' + JSON.stringify(error)),
21
+ }))))));
@@ -0,0 +1,29 @@
1
+ import { of } from 'rxjs';
2
+ import { catchError, filter, switchMap, mergeMap } from 'rxjs/operators';
3
+ import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
4
+ import { fetchCannedResponses, saveCannedResponse, saveCannedResponseFailure, saveCannedResponseSuccess, } from '../cannedResponsesReducer';
5
+ export const saveCannedResponseEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(saveCannedResponse.match), switchMap((action) => {
6
+ const { name, content, cannedResponseId } = action.payload;
7
+ const isUpdate = cannedResponseId != null;
8
+ const url = isUpdate
9
+ ? `${zeniAPI.apiEndPoints.taskMicroServiceBaseUrl}/1.0/task-manager/canned-responses/${cannedResponseId}`
10
+ : `${zeniAPI.apiEndPoints.taskMicroServiceBaseUrl}/1.0/task-manager/canned-responses`;
11
+ const apiCall = isUpdate
12
+ ? zeniAPI.putAndGetJSON(url, {
13
+ name,
14
+ content,
15
+ })
16
+ : zeniAPI.postAndGetJSON(url, {
17
+ name,
18
+ content,
19
+ });
20
+ return apiCall.pipe(mergeMap((response) => {
21
+ if (isSuccessResponse(response)) {
22
+ return of(saveCannedResponseSuccess(), fetchCannedResponses() // Refresh list after save
23
+ );
24
+ }
25
+ return of(saveCannedResponseFailure({ error: response.status }));
26
+ }), catchError((error) => of(saveCannedResponseFailure({
27
+ error: createZeniAPIStatus('Unexpected Error', 'Save Canned Response errored: ' + JSON.stringify(error)),
28
+ }))));
29
+ }));
@@ -4,6 +4,7 @@ import { openSnackbar } from '../../../../entity/snackbar/snackbarReducer';
4
4
  import { updateTasks } from '../../../../entity/task/taskReducer';
5
5
  import { getTaskById } from '../../../../entity/task/taskSelector';
6
6
  import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
7
+ import { fetchTaskList, removeTaskFromList, } from '../../taskListView/taskListReducer';
7
8
  import { archiveTask, archiveTaskSuccessOrFailure } from '../taskDetailReducer';
8
9
  // Epic function to handle archiving of tasks
9
10
  export const archiveTaskEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(archiveTask.match), mergeMap((action) => handleArchiveTask(action.payload.taskId, state$, zeniAPI)));
@@ -25,6 +26,8 @@ const handleApiResponse = (response, taskId) => {
25
26
  response.data.tasks.length > 0) {
26
27
  const fetchActions = [
27
28
  updateTasks(response.data.tasks),
29
+ removeTaskFromList(taskId),
30
+ fetchTaskList(),
28
31
  archiveTaskSuccessOrFailure({
29
32
  fetchState: 'Completed',
30
33
  taskId,
@@ -2,6 +2,7 @@ import { from, of } from 'rxjs';
2
2
  import { catchError, filter, mergeMap } from 'rxjs/operators';
3
3
  import { openSnackbar } from '../../../../entity/snackbar/snackbarReducer';
4
4
  import { createZeniAPIStatus, isSuccessStatus, } from '../../../../responsePayload';
5
+ import { fetchTaskList, removeTaskFromList, } from '../../taskListView/taskListReducer';
5
6
  import { deleteTask, deleteTaskSuccessOrFailure } from '../taskDetailReducer';
6
7
  export const deleteTaskEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(deleteTask.match), mergeMap((action) => {
7
8
  const { taskId } = action.payload;
@@ -10,6 +11,10 @@ export const deleteTaskEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filt
10
11
  .pipe(mergeMap((response) => {
11
12
  if (isSuccessStatus(response)) {
12
13
  const actions = [];
14
+ if (taskId != null) {
15
+ actions.push(removeTaskFromList(taskId));
16
+ }
17
+ actions.push(fetchTaskList());
13
18
  actions.push(deleteTaskSuccessOrFailure({ fetchState: 'Completed', taskId }));
14
19
  return from(actions);
15
20
  }
@@ -25,6 +25,7 @@ export const initializeTaskToLocalStoreEpic = (actions$, state$) => actions$.pip
25
25
  savedRecurringEndDate: task.recurringEndDate,
26
26
  recurringStartDate: task.recurringStartDate,
27
27
  timeSpent: task.timeSpent,
28
+ isPrivate: task.isPrivate,
28
29
  };
29
30
  const actions = [
30
31
  saveTaskUpdatesToLocalStore({ taskDetailLocalData, taskId }),
@@ -94,5 +94,6 @@ const prepareTaskPayload = (state, taskId, taskGroupId) => {
94
94
  sync_token: syncToken,
95
95
  task_group_ids: taskGroupId != null ? [taskGroupId] : [],
96
96
  time_spent: convertHHMMStrToMinutes(localData.timeSpent),
97
+ ...(taskId == null ? { is_private: localData.isPrivate ?? false } : {}),
97
98
  };
98
99
  };
@@ -0,0 +1,66 @@
1
+ import { from, of } from 'rxjs';
2
+ import { catchError, filter, mergeMap } from 'rxjs/operators';
3
+ import { SNOOZED_DISPLAY_FORMAT } from '../../../../commonStateTypes/fiscalYearHelpers/formatZeniDateFY';
4
+ import { openSnackbar } from '../../../../entity/snackbar/snackbarReducer';
5
+ import { updateTasks } from '../../../../entity/task/taskReducer';
6
+ import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
7
+ import { date } from '../../../../zeniDayJS';
8
+ import { fetchTaskList, removeTaskFromList, } from '../../taskListView/taskListReducer';
9
+ import { snoozeTask, snoozeTaskSuccessOrFailure } from '../taskDetailReducer';
10
+ export const snoozeTaskEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(snoozeTask.match), mergeMap((action) => handleSnoozeTask(action.payload.taskId, action.payload.snoozedUntil, zeniAPI)));
11
+ const formatSnoozedUntilForDisplay = (snoozedUntil) => date(snoozedUntil).format(SNOOZED_DISPLAY_FORMAT);
12
+ const handleSnoozeTask = (taskId, snoozedUntil, zeniAPI) => {
13
+ const snoozeTaskApi$ = zeniAPI.postAndGetJSON(`${zeniAPI.apiEndPoints.taskMicroServiceBaseUrl}/1.0/task-manager/tasks/${taskId}/snooze`, { snoozed_until: snoozedUntil });
14
+ return snoozeTaskApi$.pipe(mergeMap((response) => handleApiResponse(response, taskId, snoozedUntil)), catchError((error) => of(snoozeTaskSuccessOrFailure({
15
+ fetchState: 'Error',
16
+ taskId,
17
+ error: createZeniAPIStatus('Unexpected Error', 'Snooze Task REST API call errored out: ' + JSON.stringify(error)),
18
+ }))));
19
+ };
20
+ const handleApiResponse = (response, taskId, snoozedUntil) => {
21
+ if (isSuccessResponse(response) &&
22
+ response.data != null &&
23
+ response.data.tasks.length > 0) {
24
+ const fetchActions = [
25
+ updateTasks(response.data.tasks),
26
+ removeTaskFromList(taskId),
27
+ fetchTaskList(),
28
+ snoozeTaskSuccessOrFailure({
29
+ fetchState: 'Completed',
30
+ taskId,
31
+ }),
32
+ openSnackbar({
33
+ messageSection: 'snooze_task',
34
+ messageText: 'success',
35
+ type: 'success',
36
+ variables: [
37
+ {
38
+ variableName: '_snoozed_until_',
39
+ variableValue: formatSnoozedUntilForDisplay(snoozedUntil),
40
+ },
41
+ ],
42
+ }),
43
+ ];
44
+ return from(fetchActions);
45
+ }
46
+ else {
47
+ return from([
48
+ snoozeTaskSuccessOrFailure({
49
+ fetchState: 'Error',
50
+ taskId,
51
+ error: response.status,
52
+ }),
53
+ openSnackbar({
54
+ messageSection: 'snooze_task',
55
+ messageText: 'failed',
56
+ type: 'error',
57
+ variables: [
58
+ {
59
+ variableName: '_api-error_',
60
+ variableValue: response.status.message,
61
+ },
62
+ ],
63
+ }),
64
+ ]);
65
+ }
66
+ };
@@ -0,0 +1,57 @@
1
+ import { from, of } from 'rxjs';
2
+ import { catchError, filter, mergeMap } from 'rxjs/operators';
3
+ import { openSnackbar } from '../../../../entity/snackbar/snackbarReducer';
4
+ import { updateTasks } from '../../../../entity/task/taskReducer';
5
+ import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
6
+ import { fetchTaskList, removeTaskFromList, } from '../../taskListView/taskListReducer';
7
+ import { snoozeTaskSuccessOrFailure, unsnoozeTask, } from '../taskDetailReducer';
8
+ export const unsnoozeTaskEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(unsnoozeTask.match), mergeMap((action) => handleUnsnoozeTask(action.payload.taskId, zeniAPI)));
9
+ const handleUnsnoozeTask = (taskId, zeniAPI) => {
10
+ const unsnoozeTaskApi$ = zeniAPI.deleteAndGetJSON(`${zeniAPI.apiEndPoints.taskMicroServiceBaseUrl}/1.0/task-manager/tasks/${taskId}/snooze`);
11
+ return unsnoozeTaskApi$.pipe(mergeMap((response) => handleApiResponse(response, taskId)), catchError((error) => of(snoozeTaskSuccessOrFailure({
12
+ fetchState: 'Error',
13
+ taskId,
14
+ error: createZeniAPIStatus('Unexpected Error', 'Unsnooze Task REST API call errored out: ' + JSON.stringify(error)),
15
+ }))));
16
+ };
17
+ const handleApiResponse = (response, taskId) => {
18
+ if (isSuccessResponse(response) &&
19
+ response.data != null &&
20
+ response.data.tasks.length > 0) {
21
+ const fetchActions = [
22
+ updateTasks(response.data.tasks),
23
+ removeTaskFromList(taskId),
24
+ fetchTaskList(),
25
+ snoozeTaskSuccessOrFailure({
26
+ fetchState: 'Completed',
27
+ taskId,
28
+ }),
29
+ openSnackbar({
30
+ messageSection: 'unsnooze_task',
31
+ messageText: 'success',
32
+ type: 'success',
33
+ }),
34
+ ];
35
+ return from(fetchActions);
36
+ }
37
+ else {
38
+ return from([
39
+ snoozeTaskSuccessOrFailure({
40
+ fetchState: 'Error',
41
+ taskId,
42
+ error: response.status,
43
+ }),
44
+ openSnackbar({
45
+ messageSection: 'unsnooze_task',
46
+ messageText: 'failed',
47
+ type: 'error',
48
+ variables: [
49
+ {
50
+ variableName: '_api-error_',
51
+ variableValue: response.status.message,
52
+ },
53
+ ],
54
+ }),
55
+ ]);
56
+ }
57
+ };
@@ -31,5 +31,9 @@ export const initialTaskDetail = {
31
31
  fetchState: 'Not-Started',
32
32
  error: undefined,
33
33
  },
34
+ snoozeStatus: {
35
+ fetchState: 'Not-Started',
36
+ error: undefined,
37
+ },
34
38
  taskDetailLocalData: initialTaskDetailLocalData,
35
39
  };