@zeniai/client-epic-state 5.0.37 → 5.0.38

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 (144) hide show
  1. package/lib/commonStateTypes/fiscalYearHelpers/formatZeniDateFY.d.ts +1 -0
  2. package/lib/commonStateTypes/fiscalYearHelpers/formatZeniDateFY.js +2 -1
  3. package/lib/entity/file/fileState.d.ts +4 -4
  4. package/lib/entity/file/fileState.js +4 -0
  5. package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
  6. package/lib/entity/snackbar/snackbarTypes.js +4 -0
  7. package/lib/entity/task/taskPayload.d.ts +3 -0
  8. package/lib/entity/task/taskPayload.js +5 -0
  9. package/lib/entity/task/taskState.d.ts +3 -0
  10. package/lib/entity/tenant/clearAllEpic.d.ts +5 -2
  11. package/lib/entity/tenant/clearAllEpic.js +6 -0
  12. package/lib/entity/tenant/epic/deleteConnectionEpic.d.ts +19 -0
  13. package/lib/entity/tenant/epic/deleteConnectionEpic.js +29 -0
  14. package/lib/entity/tenant/epic/saveAPIKeyConnectionEpic.d.ts +19 -0
  15. package/lib/entity/tenant/epic/saveAPIKeyConnectionEpic.js +31 -0
  16. package/lib/entity/tenant/epic/saveOAuthConnectionEpic.d.ts +19 -0
  17. package/lib/entity/tenant/epic/saveOAuthConnectionEpic.js +33 -0
  18. package/lib/entity/tenant/tenantPayload.d.ts +1 -0
  19. package/lib/entity/tenant/tenantReducer.d.ts +59 -1
  20. package/lib/entity/tenant/tenantReducer.js +139 -4
  21. package/lib/entity/tenant/tenantState.d.ts +7 -0
  22. package/lib/entity/transaction/stateTypes/attachment.d.ts +2 -2
  23. package/lib/epic.d.ts +9 -1
  24. package/lib/epic.js +12 -1
  25. package/lib/esm/commonStateTypes/fiscalYearHelpers/formatZeniDateFY.js +1 -0
  26. package/lib/esm/entity/file/fileState.js +4 -0
  27. package/lib/esm/entity/snackbar/snackbarTypes.js +4 -0
  28. package/lib/esm/entity/task/taskPayload.js +5 -0
  29. package/lib/esm/entity/tenant/clearAllEpic.js +6 -0
  30. package/lib/esm/entity/tenant/epic/deleteConnectionEpic.js +25 -0
  31. package/lib/esm/entity/tenant/epic/saveAPIKeyConnectionEpic.js +27 -0
  32. package/lib/esm/entity/tenant/epic/saveOAuthConnectionEpic.js +29 -0
  33. package/lib/esm/entity/tenant/tenantReducer.js +135 -2
  34. package/lib/esm/epic.js +12 -1
  35. package/lib/esm/index.js +15 -6
  36. package/lib/esm/init.js +71 -16
  37. package/lib/esm/reducer.js +9 -0
  38. package/lib/esm/view/featureNotificationView/epics/fetchRegisteredInterestsEpic.js +23 -0
  39. package/lib/esm/view/featureNotificationView/epics/notifyMeForFeatureEpic.js +25 -0
  40. package/lib/esm/view/featureNotificationView/featureNotificationViewPayload.js +11 -0
  41. package/lib/esm/view/featureNotificationView/featureNotificationViewReducer.js +106 -0
  42. package/lib/esm/view/featureNotificationView/featureNotificationViewSelector.js +4 -0
  43. package/lib/esm/view/featureNotificationView/featureNotificationViewState.js +1 -0
  44. package/lib/esm/view/taskManager/cannedResponsesView/cannedResponses.js +1 -0
  45. package/lib/esm/view/taskManager/cannedResponsesView/cannedResponsesPayload.js +12 -0
  46. package/lib/esm/view/taskManager/cannedResponsesView/cannedResponsesReducer.js +64 -0
  47. package/lib/esm/view/taskManager/cannedResponsesView/cannedResponsesSelector.js +3 -0
  48. package/lib/esm/view/taskManager/cannedResponsesView/epics/deleteCannedResponseEpic.js +17 -0
  49. package/lib/esm/view/taskManager/cannedResponsesView/epics/fetchCannedResponsesEpic.js +21 -0
  50. package/lib/esm/view/taskManager/cannedResponsesView/epics/saveCannedResponseEpic.js +29 -0
  51. package/lib/esm/view/taskManager/taskDetailView/epics/archiveTaskEpic.js +3 -0
  52. package/lib/esm/view/taskManager/taskDetailView/epics/deleteTaskEpic.js +5 -0
  53. package/lib/esm/view/taskManager/taskDetailView/epics/initializeTaskToLocalStoreEpic.js +1 -0
  54. package/lib/esm/view/taskManager/taskDetailView/epics/saveTaskDetailEpic.js +1 -0
  55. package/lib/esm/view/taskManager/taskDetailView/epics/snoozeTaskEpic.js +66 -0
  56. package/lib/esm/view/taskManager/taskDetailView/epics/unsnoozeTaskEpic.js +57 -0
  57. package/lib/esm/view/taskManager/taskDetailView/taskDetail.js +4 -0
  58. package/lib/esm/view/taskManager/taskDetailView/taskDetailReducer.js +60 -7
  59. package/lib/esm/view/taskManager/taskDetailView/taskDetailSelector.js +12 -0
  60. package/lib/esm/view/taskManager/taskListView/epics/bulkUpdateTaskListEpic.js +56 -21
  61. package/lib/esm/view/taskManager/taskListView/epics/dragNDropTasksEpic.js +1 -0
  62. package/lib/esm/view/taskManager/taskListView/epics/fetchTaskListEpic.js +13 -4
  63. package/lib/esm/view/taskManager/taskListView/epics/updateTaskFromListViewEpic.js +3 -2
  64. package/lib/esm/view/taskManager/taskListView/taskList.js +7 -0
  65. package/lib/esm/view/taskManager/taskListView/taskListReducer.js +106 -12
  66. package/lib/esm/view/taskManager/taskListView/taskListSelector.js +48 -39
  67. package/lib/esm/view/zeniOAuthView/epics/approveOAuthConsentEpic.js +65 -0
  68. package/lib/esm/view/zeniOAuthView/zeniOAuthParamsParser.js +41 -0
  69. package/lib/esm/view/zeniOAuthView/zeniOAuthReducer.js +49 -0
  70. package/lib/esm/view/zeniOAuthView/zeniOAuthSelector.js +3 -0
  71. package/lib/esm/view/zeniOAuthView/zeniOAuthState.js +1 -0
  72. package/lib/index.d.ts +18 -6
  73. package/lib/index.js +67 -30
  74. package/lib/init.d.ts +5 -3
  75. package/lib/init.js +71 -16
  76. package/lib/reducer.d.ts +9 -0
  77. package/lib/reducer.js +9 -0
  78. package/lib/tsconfig.typecheck.tsbuildinfo +1 -1
  79. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
  80. package/lib/view/featureNotificationView/epics/fetchRegisteredInterestsEpic.d.ts +16 -0
  81. package/lib/view/featureNotificationView/epics/fetchRegisteredInterestsEpic.js +27 -0
  82. package/lib/view/featureNotificationView/epics/notifyMeForFeatureEpic.d.ts +14 -0
  83. package/lib/view/featureNotificationView/epics/notifyMeForFeatureEpic.js +29 -0
  84. package/lib/view/featureNotificationView/featureNotificationViewPayload.d.ts +23 -0
  85. package/lib/view/featureNotificationView/featureNotificationViewPayload.js +15 -0
  86. package/lib/view/featureNotificationView/featureNotificationViewReducer.d.ts +19 -0
  87. package/lib/view/featureNotificationView/featureNotificationViewReducer.js +110 -0
  88. package/lib/view/featureNotificationView/featureNotificationViewSelector.d.ts +6 -0
  89. package/lib/view/featureNotificationView/featureNotificationViewSelector.js +11 -0
  90. package/lib/view/featureNotificationView/featureNotificationViewState.d.ts +26 -0
  91. package/lib/view/featureNotificationView/featureNotificationViewState.js +2 -0
  92. package/lib/view/taskManager/cannedResponsesView/cannedResponses.d.ts +19 -0
  93. package/lib/view/taskManager/cannedResponsesView/cannedResponses.js +2 -0
  94. package/lib/view/taskManager/cannedResponsesView/cannedResponsesPayload.d.ts +21 -0
  95. package/lib/view/taskManager/cannedResponsesView/cannedResponsesPayload.js +15 -0
  96. package/lib/view/taskManager/cannedResponsesView/cannedResponsesReducer.d.ts +30 -0
  97. package/lib/view/taskManager/cannedResponsesView/cannedResponsesReducer.js +68 -0
  98. package/lib/view/taskManager/cannedResponsesView/cannedResponsesSelector.d.ts +3 -0
  99. package/lib/view/taskManager/cannedResponsesView/cannedResponsesSelector.js +6 -0
  100. package/lib/view/taskManager/cannedResponsesView/epics/deleteCannedResponseEpic.d.ts +7 -0
  101. package/lib/view/taskManager/cannedResponsesView/epics/deleteCannedResponseEpic.js +21 -0
  102. package/lib/view/taskManager/cannedResponsesView/epics/fetchCannedResponsesEpic.d.ts +7 -0
  103. package/lib/view/taskManager/cannedResponsesView/epics/fetchCannedResponsesEpic.js +25 -0
  104. package/lib/view/taskManager/cannedResponsesView/epics/saveCannedResponseEpic.d.ts +7 -0
  105. package/lib/view/taskManager/cannedResponsesView/epics/saveCannedResponseEpic.js +33 -0
  106. package/lib/view/taskManager/taskDetailView/epics/archiveTaskEpic.d.ts +2 -1
  107. package/lib/view/taskManager/taskDetailView/epics/archiveTaskEpic.js +3 -0
  108. package/lib/view/taskManager/taskDetailView/epics/deleteTaskEpic.d.ts +2 -1
  109. package/lib/view/taskManager/taskDetailView/epics/deleteTaskEpic.js +5 -0
  110. package/lib/view/taskManager/taskDetailView/epics/initializeTaskToLocalStoreEpic.js +1 -0
  111. package/lib/view/taskManager/taskDetailView/epics/saveTaskDetailEpic.js +1 -0
  112. package/lib/view/taskManager/taskDetailView/epics/snoozeTaskEpic.d.ts +9 -0
  113. package/lib/view/taskManager/taskDetailView/epics/snoozeTaskEpic.js +70 -0
  114. package/lib/view/taskManager/taskDetailView/epics/unsnoozeTaskEpic.d.ts +9 -0
  115. package/lib/view/taskManager/taskDetailView/epics/unsnoozeTaskEpic.js +61 -0
  116. package/lib/view/taskManager/taskDetailView/taskDetail.d.ts +2 -0
  117. package/lib/view/taskManager/taskDetailView/taskDetail.js +4 -0
  118. package/lib/view/taskManager/taskDetailView/taskDetailReducer.d.ts +10 -1
  119. package/lib/view/taskManager/taskDetailView/taskDetailReducer.js +61 -8
  120. package/lib/view/taskManager/taskDetailView/taskDetailSelector.d.ts +5 -0
  121. package/lib/view/taskManager/taskDetailView/taskDetailSelector.js +12 -0
  122. package/lib/view/taskManager/taskListView/epics/bulkUpdateTaskListEpic.d.ts +6 -7
  123. package/lib/view/taskManager/taskListView/epics/bulkUpdateTaskListEpic.js +56 -22
  124. package/lib/view/taskManager/taskListView/epics/dragNDropTasksEpic.js +1 -0
  125. package/lib/view/taskManager/taskListView/epics/fetchTaskListEpic.js +13 -4
  126. package/lib/view/taskManager/taskListView/epics/updateTaskFromListViewEpic.js +3 -2
  127. package/lib/view/taskManager/taskListView/taskList.d.ts +14 -1
  128. package/lib/view/taskManager/taskListView/taskList.js +8 -1
  129. package/lib/view/taskManager/taskListView/taskListPayload.d.ts +3 -0
  130. package/lib/view/taskManager/taskListView/taskListReducer.d.ts +9 -6
  131. package/lib/view/taskManager/taskListView/taskListReducer.js +107 -13
  132. package/lib/view/taskManager/taskListView/taskListSelector.d.ts +9 -3
  133. package/lib/view/taskManager/taskListView/taskListSelector.js +48 -39
  134. package/lib/view/zeniOAuthView/epics/approveOAuthConsentEpic.d.ts +27 -0
  135. package/lib/view/zeniOAuthView/epics/approveOAuthConsentEpic.js +69 -0
  136. package/lib/view/zeniOAuthView/zeniOAuthParamsParser.d.ts +16 -0
  137. package/lib/view/zeniOAuthView/zeniOAuthParamsParser.js +44 -0
  138. package/lib/view/zeniOAuthView/zeniOAuthReducer.d.ts +29 -0
  139. package/lib/view/zeniOAuthView/zeniOAuthReducer.js +53 -0
  140. package/lib/view/zeniOAuthView/zeniOAuthSelector.d.ts +5 -0
  141. package/lib/view/zeniOAuthView/zeniOAuthSelector.js +9 -0
  142. package/lib/view/zeniOAuthView/zeniOAuthState.d.ts +4 -0
  143. package/lib/view/zeniOAuthView/zeniOAuthState.js +2 -0
  144. package/package.json +1 -1
@@ -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
  };
@@ -149,11 +149,11 @@ const taskDetailView = createSlice({
149
149
  },
150
150
  saveTaskSuccessOrFailure(draft, action) {
151
151
  const { taskId, fetchState, error, newTaskId } = action.payload;
152
- if (taskId != null) {
152
+ if (taskId != null && draft.editTaskStateById[taskId] != null) {
153
153
  draft.editTaskStateById[taskId].saveStatus.fetchState = fetchState;
154
154
  draft.editTaskStateById[taskId].saveStatus.error = error;
155
155
  }
156
- else {
156
+ else if (taskId == null) {
157
157
  if (newTaskId != null) {
158
158
  draft.newTaskState.taskId = newTaskId;
159
159
  }
@@ -182,8 +182,10 @@ const taskDetailView = createSlice({
182
182
  },
183
183
  archiveTaskSuccessOrFailure(draft, action) {
184
184
  const { taskId, fetchState, error } = action.payload;
185
- draft.editTaskStateById[taskId].archiveStatus.fetchState = fetchState;
186
- draft.editTaskStateById[taskId].archiveStatus.error = error;
185
+ if (draft.editTaskStateById[taskId] != null) {
186
+ draft.editTaskStateById[taskId].archiveStatus.fetchState = fetchState;
187
+ draft.editTaskStateById[taskId].archiveStatus.error = error;
188
+ }
187
189
  },
188
190
  deleteTask: {
189
191
  reducer(draft, action) {
@@ -216,19 +218,70 @@ const taskDetailView = createSlice({
216
218
  },
217
219
  },
218
220
  deleteTaskSuccessOrFailure(draft, action) {
219
- if (action.payload.taskId != null) {
221
+ if (action.payload.taskId != null &&
222
+ draft.editTaskStateById[action.payload.taskId] != null) {
220
223
  const { taskId } = action.payload;
221
224
  draft.editTaskStateById[taskId].deleteTaskStatus.fetchState =
222
225
  action.payload.fetchState;
223
226
  draft.editTaskStateById[taskId].deleteTaskStatus.error =
224
227
  action.payload.error;
225
228
  }
226
- else {
229
+ else if (action.payload.taskId == null) {
227
230
  draft.newTaskState.deleteTaskStatus.fetchState =
228
231
  action.payload.fetchState;
229
232
  draft.newTaskState.deleteTaskStatus.error = action.payload.error;
230
233
  }
231
234
  },
235
+ snoozeTask: {
236
+ reducer(draft, action) {
237
+ const { taskId } = action.payload;
238
+ draft.editTaskStateById[taskId] = {
239
+ ...(draft.editTaskStateById[taskId] != null
240
+ ? draft.editTaskStateById[taskId]
241
+ : initialTaskDetail),
242
+ snoozeStatus: {
243
+ fetchState: 'In-Progress',
244
+ error: undefined,
245
+ },
246
+ };
247
+ },
248
+ prepare(taskId, snoozedUntil) {
249
+ return {
250
+ payload: {
251
+ taskId,
252
+ snoozedUntil,
253
+ },
254
+ };
255
+ },
256
+ },
257
+ snoozeTaskSuccessOrFailure(draft, action) {
258
+ const { taskId, fetchState, error } = action.payload;
259
+ if (draft.editTaskStateById[taskId] != null) {
260
+ draft.editTaskStateById[taskId].snoozeStatus.fetchState = fetchState;
261
+ draft.editTaskStateById[taskId].snoozeStatus.error = error;
262
+ }
263
+ },
264
+ unsnoozeTask: {
265
+ reducer(draft, action) {
266
+ const { taskId } = action.payload;
267
+ draft.editTaskStateById[taskId] = {
268
+ ...(draft.editTaskStateById[taskId] != null
269
+ ? draft.editTaskStateById[taskId]
270
+ : initialTaskDetail),
271
+ snoozeStatus: {
272
+ fetchState: 'In-Progress',
273
+ error: undefined,
274
+ },
275
+ };
276
+ },
277
+ prepare(taskId) {
278
+ return {
279
+ payload: {
280
+ taskId,
281
+ },
282
+ };
283
+ },
284
+ },
232
285
  fetchTaskHistory: {
233
286
  reducer(draft, action) {
234
287
  const { taskId, cacheOverride } = action.payload;
@@ -270,5 +323,5 @@ const taskDetailView = createSlice({
270
323
  },
271
324
  },
272
325
  });
273
- export const { fetchTaskDetailPage, fetchTaskDetail, initializeTaskToLocalStore, updateEditTaskFetchStatus, saveTaskUpdatesToLocalStore, discardTaskUpdatesInLocalStore, saveTaskDetail, archiveTask, archiveTaskSuccessOrFailure, saveTaskSuccessOrFailure, deleteTask, removeTaskDetail, deleteTaskSuccessOrFailure, fetchTaskHistory, updateTaskHistory, updateTaskHistoryFetchStatus, clearTaskDetail, updateCreatedTagToLocalStore, updateDeletedTagToLocalStore, } = taskDetailView.actions;
326
+ export const { fetchTaskDetailPage, fetchTaskDetail, initializeTaskToLocalStore, updateEditTaskFetchStatus, saveTaskUpdatesToLocalStore, discardTaskUpdatesInLocalStore, saveTaskDetail, archiveTask, archiveTaskSuccessOrFailure, saveTaskSuccessOrFailure, deleteTask, removeTaskDetail, deleteTaskSuccessOrFailure, snoozeTask, snoozeTaskSuccessOrFailure, unsnoozeTask, fetchTaskHistory, updateTaskHistory, updateTaskHistoryFetchStatus, clearTaskDetail, updateCreatedTagToLocalStore, updateDeletedTagToLocalStore, } = taskDetailView.actions;
274
327
  export default taskDetailView.reducer;
@@ -22,11 +22,19 @@ export const getTaskDetail = (state, taskId) => {
22
22
  };
23
23
  let taskHistory = [];
24
24
  let createdByUser = undefined;
25
+ let isArchived = undefined;
26
+ let isDeleted = undefined;
27
+ let recurringSourceTaskId = undefined;
28
+ let snoozedUntil = undefined;
25
29
  if (taskId != null && sourceTaskDetail != null) {
26
30
  const taskEntity = getTaskById(taskState, taskId);
27
31
  const fileIdsInEntity = taskEntity?.fileIds ?? [];
28
32
  if (taskEntity != null) {
29
33
  createdByUser = getUserAndUserRole(userState, userRoleState, addressState, taskEntity.createdBy);
34
+ isArchived = taskEntity.isArchived;
35
+ isDeleted = taskEntity.isDeleted;
36
+ recurringSourceTaskId = taskEntity.recurringSourceTaskId;
37
+ snoozedUntil = taskEntity.snoozedUntil;
30
38
  }
31
39
  if (fileIdsInEntity.length > 0) {
32
40
  fetchStatus = reduceFetchState([
@@ -74,7 +82,11 @@ export const getTaskDetail = (state, taskId) => {
74
82
  error: fetchStatus.error,
75
83
  version: 0,
76
84
  createdByUser,
85
+ isArchived,
86
+ isDeleted,
87
+ recurringSourceTaskId,
77
88
  showTaskDetailFormFooter,
89
+ snoozedUntil,
78
90
  };
79
91
  };
80
92
  export const allTaskStatus = [
@@ -5,21 +5,26 @@ import { convertHHMMStrToMinutes } from '../../../../commonStateTypes/fiscalYear
5
5
  import { DEFAULT_DATE_FORMAT } from '../../../../commonStateTypes/fiscalYearHelpers/formatZeniDateFY';
6
6
  import { updateTasks } from '../../../../entity/task/taskReducer';
7
7
  import { createZeniAPIStatus, isSuccessResponse, } from '../../../../responsePayload';
8
- import { bulkUpdateTaskList, updateTasksListOnBulkUpdateTasksFailure, updateTasksListOnBulkUpdateTasksSuccess, } from '../taskListReducer';
9
- export const bulkUpdateTaskListEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(bulkUpdateTaskList.match), switchMap((action) => {
10
- const state = state$.value;
8
+ import { bulkUpdateTaskList, fetchTaskList, updateTasksListOnBulkUpdateTasksFailure, updateTasksListOnBulkUpdateTasksSuccess, } from '../taskListReducer';
9
+ export const bulkUpdateTaskListEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(bulkUpdateTaskList.match), switchMap((action) => {
11
10
  const { taskIds, updates, groupId } = action.payload;
12
- const payload = {
13
- tasks: getTasksListPayload(state, taskIds, updates),
14
- };
11
+ const bulkUpdates = toBulkUpdatesPayload(updates);
12
+ if (groupId != null) {
13
+ bulkUpdates.task_group_ids = [groupId];
14
+ }
15
+ const payload = { task_ids: taskIds, updates: bulkUpdates };
15
16
  return zeniAPI
16
- .putAndGetJSON(`${zeniAPI.apiEndPoints.taskMicroServiceBaseUrl}/1.0/task-manager/tasks`, payload)
17
+ .putAndGetJSON(`${zeniAPI.apiEndPoints.taskMicroServiceBaseUrl}/1.0/task-manager/tasks/bulk-update`, payload)
17
18
  .pipe(mergeMap((response) => {
18
19
  if (isSuccessResponse(response) && response.data != null) {
20
+ const removeFromList = updates.isArchived === true ||
21
+ updates.isDeleted === true ||
22
+ ('snoozedUntil' in updates && updates.snoozedUntil == null);
19
23
  return of(updateTasks(response.data.tasks), updateTasksListOnBulkUpdateTasksSuccess({
20
24
  taskIds,
21
25
  groupId,
22
- }));
26
+ removeFromList,
27
+ }), fetchTaskList());
23
28
  }
24
29
  else {
25
30
  return of(updateTasksListOnBulkUpdateTasksFailure({
@@ -33,19 +38,46 @@ export const bulkUpdateTaskListEpic = (actions$, state$, zeniAPI) => actions$.pi
33
38
  }));
34
39
  }));
35
40
  }));
36
- export const getTasksListPayload = (state, taskIds, updates) => {
37
- const { taskState } = state;
38
- const tasksList = taskIds
39
- .map((taskId) => {
40
- const task = get(taskState.taskByID, taskId);
41
- return {
42
- ...task,
43
- ...updates,
44
- };
45
- })
46
- .filter((task) => task != null);
47
- const tasksPayload = tasksList.map((task) => toTaskPayload(state, task));
48
- return tasksPayload;
41
+ /**
42
+ * Helpers
43
+ */
44
+ const toBulkUpdatesPayload = (updates) => {
45
+ const payload = {};
46
+ if (updates.status != null) {
47
+ payload.status = updates.status.code;
48
+ }
49
+ if (updates.priority != null) {
50
+ payload.priority = updates.priority.code;
51
+ }
52
+ if (updates.assignees != null) {
53
+ payload.assignees = updates.assignees;
54
+ }
55
+ if (updates.groupAssignees != null) {
56
+ payload.group_assignees = updates.groupAssignees;
57
+ }
58
+ if (updates.dueDate != null) {
59
+ payload.due_date = updates.dueDate.format(DEFAULT_DATE_FORMAT);
60
+ }
61
+ if (updates.tagIds != null) {
62
+ payload.tags = updates.tagIds;
63
+ }
64
+ if (updates.timeSpent != null) {
65
+ payload.time_spent = convertHHMMStrToMinutes(updates.timeSpent.replace(/\D/g, ''));
66
+ }
67
+ if (updates.isArchived != null) {
68
+ payload.is_archived = updates.isArchived;
69
+ }
70
+ if (updates.isDeleted != null) {
71
+ payload.is_deleted = updates.isDeleted;
72
+ }
73
+ // Bulk snooze is not supported — only bulk unsnooze (clear all snooze fields)
74
+ if ('snoozedUntil' in updates) {
75
+ payload.snoozed_until = null;
76
+ payload.snoozed_by = null;
77
+ payload.snoozed_at = null;
78
+ payload.is_snooze_notification_sent = false;
79
+ }
80
+ return payload;
49
81
  };
50
82
  export const getTaskPayload = (state, taskId, updates) => {
51
83
  const { taskState } = state;
@@ -71,6 +103,9 @@ const toTaskPayload = (state, task) => {
71
103
  assignees: task.assignees,
72
104
  description: task.description,
73
105
  group_assignees: task.groupAssignees,
106
+ is_archived: task.isArchived,
107
+ is_deleted: task.isDeleted,
108
+ snoozed_until: task.snoozedUntil != null ? task.snoozedUntil.toISOString() : null,
74
109
  due_date: task.dueDate != null ? task.dueDate.format(DEFAULT_DATE_FORMAT) : null,
75
110
  priority: task.priority.code,
76
111
  status: task.status.code,
@@ -11,6 +11,7 @@ export const dragNDropTasksEpic = (actions$, state$) => actions$.pipe(filter(dra
11
11
  updateTasksListOnBulkUpdateTasksSuccess({
12
12
  taskIds,
13
13
  groupId,
14
+ removeFromList: false,
14
15
  }),
15
16
  bulkUpdateTaskList(taskIds, groupId, updates),
16
17
  ];
@@ -9,10 +9,19 @@ export const fetchTaskListEpic = (actions$, _state$, zeniAPI) => actions$.pipe(f
9
9
  .getJSON(`${zeniAPI.apiEndPoints.taskMicroServiceBaseUrl}/1.0/task-manager/tasks?query=${encodeURIComponent(`{"task_type": "all"}`)}`)
10
10
  .pipe(mergeMap((response) => {
11
11
  if (isSuccessResponse(response) && response.data != null) {
12
- return of(updateTasks(response.data.tasks), updateTaskList({
13
- data: response.data.tasks,
14
- updateType: 'replace',
15
- }), updateTags(response.data.tasks.map((task) => task.tags).flat()));
12
+ const { tasks, deleted, archived, snoozed } = response.data;
13
+ const allTasks = [
14
+ ...tasks,
15
+ ...(deleted ?? []),
16
+ ...(archived ?? []),
17
+ ...(snoozed ?? []),
18
+ ];
19
+ return of(updateTasks(allTasks), updateTaskList({
20
+ data: tasks,
21
+ deleted: deleted ?? [],
22
+ archived: archived ?? [],
23
+ snoozed: snoozed ?? [],
24
+ }), updateTags(allTasks.map((task) => task.tags).flat()));
16
25
  }
17
26
  else {
18
27
  return of(updateTaskListFetchStatus({
@@ -8,9 +8,10 @@ export const updateTaskFromListViewEpic = (actions$, state$, zeniAPI) => actions
8
8
  const state = state$.value;
9
9
  const { task, updates } = action.payload;
10
10
  const taskId = task.id;
11
- const taskData = getTaskPayload(state, taskId, updates);
11
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
12
+ const { snoozed_until: _snoozedUntil, ...taskData } = getTaskPayload(state, taskId, updates);
12
13
  return zeniAPI
13
- .putAndGetJSON(`${zeniAPI.apiEndPoints.taskMicroServiceBaseUrl}/1.0/task-manager/tasks/${taskId}`, { ...taskData })
14
+ .putAndGetJSON(`${zeniAPI.apiEndPoints.taskMicroServiceBaseUrl}/1.0/task-manager/tasks/${taskId}`, taskData)
14
15
  .pipe(mergeMap((response) => {
15
16
  if (isSuccessResponse(response) && response.data != null) {
16
17
  return from([
@@ -1,4 +1,10 @@
1
1
  import { stringToUnion, stringToUnionStrict, } from '../../../commonStateTypes/stringToUnion';
2
+ export const ALL_TASK_LIST_TABS = [
3
+ 'live',
4
+ 'archived',
5
+ 'deleted',
6
+ 'snoozed',
7
+ ];
2
8
  export const DUE_DATE_GROUP_KEYS = [
3
9
  'overdue',
4
10
  'today',
@@ -26,6 +32,7 @@ const ALL_TASK_LIST_SORT_KEYS = [
26
32
  'status',
27
33
  'priority',
28
34
  'timeSpent',
35
+ 'visibility',
29
36
  ];
30
37
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
31
38
  const toTaskListSortKeyType = (v) => stringToUnion(v, ALL_TASK_LIST_SORT_KEYS);
@@ -29,7 +29,23 @@ const initialTaskIdsByDueDate = {
29
29
  today: [],
30
30
  upcoming: [],
31
31
  };
32
+ const initialTabData = {
33
+ taskIds: [],
34
+ taskIdsByAssignees: {},
35
+ taskIdsByDueDate: { ...initialTaskIdsByDueDate },
36
+ taskIdsByGroupsIds: {},
37
+ taskIdsByPriority: { ...initialTaskIdsByPriority },
38
+ taskIdsByStatus: { ...initialTaskIdsByStatus },
39
+ taskIdsByTags: {},
40
+ };
32
41
  export const initialState = {
42
+ currentTab: 'live',
43
+ byTab: {
44
+ live: { ...initialTabData },
45
+ archived: { ...initialTabData },
46
+ deleted: { ...initialTabData },
47
+ snoozed: { ...initialTabData },
48
+ },
33
49
  taskIds: [],
34
50
  taskIdsByGroupsIds: {},
35
51
  taskIdsByPriority: initialTaskIdsByPriority,
@@ -86,17 +102,30 @@ const taskList = createSlice({
86
102
  draft.error = undefined;
87
103
  },
88
104
  updateTaskList(draft, action) {
89
- const { data } = action.payload;
105
+ const { data, archived, deleted, snoozed } = action.payload;
90
106
  draft.fetchState = 'Completed';
91
107
  draft.error = undefined;
92
- const { taskIds, taskIdsGroupedByPriority, taskIdsByGroupIds, taskIdsGroupedByStatus, taskIdsByAssignees, taskIdsByDueDate, taskIdsByTags, } = getGroupedTaskIds(data);
93
- draft.taskIds = taskIds;
94
- draft.taskIdsByGroupsIds = taskIdsByGroupIds;
95
- draft.taskIdsByPriority = taskIdsGroupedByPriority;
96
- draft.taskIdsByStatus = taskIdsGroupedByStatus;
97
- draft.taskIdsByAssignees = taskIdsByAssignees;
98
- draft.taskIdsByDueDate = taskIdsByDueDate;
99
- draft.taskIdsByTags = taskIdsByTags;
108
+ // Group live tasks
109
+ const liveGrouped = getGroupedTaskIds(data);
110
+ draft.byTab.live = toTabData(liveGrouped);
111
+ // Group other tabs if provided
112
+ if (archived != null) {
113
+ draft.byTab.archived = toTabData(getGroupedTaskIds(archived));
114
+ }
115
+ if (deleted != null) {
116
+ draft.byTab.deleted = toTabData(getGroupedTaskIds(deleted));
117
+ }
118
+ if (snoozed != null) {
119
+ draft.byTab.snoozed = toTabData(getGroupedTaskIds(snoozed));
120
+ }
121
+ // Copy active tab data to top-level fields
122
+ const activeTabData = draft.byTab[draft.currentTab];
123
+ copyTabDataToTopLevel(draft, activeTabData);
124
+ },
125
+ updateTaskListTab(draft, action) {
126
+ draft.currentTab = action.payload;
127
+ const activeTabData = draft.byTab[action.payload];
128
+ copyTabDataToTopLevel(draft, activeTabData);
100
129
  },
101
130
  initiateTaskListLocalData(draft, action) {
102
131
  const { taskGroupById } = action.payload;
@@ -184,10 +213,13 @@ const taskList = createSlice({
184
213
  },
185
214
  },
186
215
  updateTasksListOnBulkUpdateTasksSuccess(draft, action) {
187
- const { taskIds, groupId } = action.payload;
216
+ const { taskIds, groupId, removeFromList } = action.payload;
188
217
  draft.updateTasksFetchState.fetchState = 'Completed';
189
218
  draft.updateTasksFetchState.error = undefined;
190
- if (groupId != null) {
219
+ if (removeFromList) {
220
+ removeTaskIds(draft, taskIds);
221
+ }
222
+ else if (groupId != null) {
191
223
  const { groupByKey } = draft.uiState;
192
224
  if (groupByKey === 'groupName') {
193
225
  Object.keys(draft.taskIdsByGroupsIds).forEach((gId) => {
@@ -279,6 +311,7 @@ const taskList = createSlice({
279
311
  newTaskGroupName: '',
280
312
  selectedTaskIds: [],
281
313
  };
314
+ syncTopLevelToActiveTab(draft);
282
315
  },
283
316
  updateTasksListOnBulkUpdateTasksFailure(draft, action) {
284
317
  draft.updateTasksFetchState.fetchState = 'Error';
@@ -298,6 +331,7 @@ const taskList = createSlice({
298
331
  }
299
332
  delete draft.taskIdsByGroupsIds[taskGroupId];
300
333
  delete draft.localData.existingTaskGroupNamesByGroupId[taskGroupId];
334
+ syncTopLevelToActiveTab(draft);
301
335
  },
302
336
  updateTaskListOnNewTaskCreationSuccess(draft, action) {
303
337
  const { task, taskGroupId, currentTaskState } = action.payload;
@@ -332,6 +366,7 @@ const taskList = createSlice({
332
366
  doUpdateTaskList(draft, task, taskGroupId);
333
367
  }
334
368
  });
369
+ syncTopLevelToActiveTab(draft);
335
370
  },
336
371
  updateTaskListOnTaskGroupNameUpdate(draft, action) {
337
372
  const { taskGroupName, taskGroupId } = action.payload;
@@ -395,6 +430,7 @@ const taskList = createSlice({
395
430
  };
396
431
  }
397
432
  }
433
+ syncTopLevelToActiveTab(draft);
398
434
  },
399
435
  updateTasksListOnUpdateTaskSuccess(draft) {
400
436
  draft.updateTasksFetchState.fetchState = 'Completed';
@@ -404,12 +440,15 @@ const taskList = createSlice({
404
440
  draft.updateTasksFetchState.fetchState = 'Error';
405
441
  draft.updateTasksFetchState.error = action.payload.error;
406
442
  },
443
+ removeTaskFromList(draft, action) {
444
+ removeTaskIds(draft, [action.payload]);
445
+ },
407
446
  clearTaskList(draft) {
408
447
  Object.assign(draft, initialState);
409
448
  },
410
449
  },
411
450
  });
412
- export const { fetchTaskListPage, fetchTaskList, updateTaskList, updateTaskListFetchStatus, updateTaskListSearchText, updateTaskListUIState, updateTaskFilters, updateTaskListOnNewGroupCreationSuccess, bulkUpdateTaskList, updateTasksListOnBulkUpdateTasksSuccess, updateTasksListOnBulkUpdateTasksFailure, initiateTaskListLocalData, updateTaskListLocalData, updateTaskListOnTaskGroupDeletion, dragNDropTasks, updateTaskListOnNewTaskCreationSuccess, updateTaskListOnTaskGroupNameUpdate, updateTaskFromListView, updateTasksListOnUpdateTaskSuccess, updateTasksListOnUpdateTaskFailure, updateTaskListOnCreateTaskFromTemplateSuccess, clearTaskList, } = taskList.actions;
451
+ export const { fetchTaskListPage, fetchTaskList, updateTaskList, updateTaskListTab, updateTaskListFetchStatus, updateTaskListSearchText, updateTaskListUIState, updateTaskFilters, updateTaskListOnNewGroupCreationSuccess, bulkUpdateTaskList, updateTasksListOnBulkUpdateTasksSuccess, updateTasksListOnBulkUpdateTasksFailure, initiateTaskListLocalData, updateTaskListLocalData, updateTaskListOnTaskGroupDeletion, dragNDropTasks, updateTaskListOnNewTaskCreationSuccess, updateTaskListOnTaskGroupNameUpdate, updateTaskFromListView, updateTasksListOnUpdateTaskSuccess, updateTasksListOnUpdateTaskFailure, updateTaskListOnCreateTaskFromTemplateSuccess, removeTaskFromList, clearTaskList, } = taskList.actions;
413
452
  export default taskList.reducer;
414
453
  /**
415
454
  * helpers
@@ -488,6 +527,61 @@ const getTagsGroupKey = (tags) => {
488
527
  tagIds.sort();
489
528
  return tagIds.join(',');
490
529
  };
530
+ const toTabData = (grouped) => ({
531
+ taskIds: grouped.taskIds,
532
+ taskIdsByAssignees: grouped.taskIdsByAssignees,
533
+ taskIdsByDueDate: grouped.taskIdsByDueDate,
534
+ taskIdsByGroupsIds: grouped.taskIdsByGroupIds,
535
+ taskIdsByPriority: grouped.taskIdsGroupedByPriority,
536
+ taskIdsByStatus: grouped.taskIdsGroupedByStatus,
537
+ taskIdsByTags: grouped.taskIdsByTags,
538
+ });
539
+ const syncTopLevelToActiveTab = (draft) => {
540
+ const tabData = draft.byTab[draft.currentTab];
541
+ tabData.taskIds = draft.taskIds;
542
+ tabData.taskIdsByGroupsIds = draft.taskIdsByGroupsIds;
543
+ tabData.taskIdsByPriority = draft.taskIdsByPriority;
544
+ tabData.taskIdsByStatus = draft.taskIdsByStatus;
545
+ tabData.taskIdsByAssignees = draft.taskIdsByAssignees;
546
+ tabData.taskIdsByDueDate = draft.taskIdsByDueDate;
547
+ tabData.taskIdsByTags = draft.taskIdsByTags;
548
+ };
549
+ const copyTabDataToTopLevel = (draft, tabData) => {
550
+ draft.taskIds = tabData.taskIds;
551
+ draft.taskIdsByGroupsIds = tabData.taskIdsByGroupsIds;
552
+ draft.taskIdsByPriority = tabData.taskIdsByPriority;
553
+ draft.taskIdsByStatus = tabData.taskIdsByStatus;
554
+ draft.taskIdsByAssignees = tabData.taskIdsByAssignees;
555
+ draft.taskIdsByDueDate = tabData.taskIdsByDueDate;
556
+ draft.taskIdsByTags = tabData.taskIdsByTags;
557
+ };
558
+ const removeIdsFromTabData = (tabData, taskIds) => {
559
+ const removedSet = new Set(taskIds);
560
+ const isRemoved = (id) => removedSet.has(id);
561
+ tabData.taskIds = tabData.taskIds.filter((id) => !isRemoved(id));
562
+ Object.keys(tabData.taskIdsByGroupsIds).forEach((gId) => {
563
+ tabData.taskIdsByGroupsIds[gId] = tabData.taskIdsByGroupsIds[gId].filter((id) => !isRemoved(id));
564
+ });
565
+ Object.keys(tabData.taskIdsByPriority).forEach((key) => {
566
+ tabData.taskIdsByPriority[key] = tabData.taskIdsByPriority[key].filter((id) => !isRemoved(id));
567
+ });
568
+ Object.keys(tabData.taskIdsByStatus).forEach((key) => {
569
+ tabData.taskIdsByStatus[key] = tabData.taskIdsByStatus[key].filter((id) => !isRemoved(id));
570
+ });
571
+ Object.keys(tabData.taskIdsByDueDate).forEach((key) => {
572
+ tabData.taskIdsByDueDate[key] = tabData.taskIdsByDueDate[key].filter((id) => !isRemoved(id));
573
+ });
574
+ Object.keys(tabData.taskIdsByAssignees).forEach((key) => {
575
+ tabData.taskIdsByAssignees[key] = tabData.taskIdsByAssignees[key].filter((id) => !isRemoved(id));
576
+ });
577
+ Object.keys(tabData.taskIdsByTags).forEach((key) => {
578
+ tabData.taskIdsByTags[key] = tabData.taskIdsByTags[key].filter((id) => !isRemoved(id));
579
+ });
580
+ };
581
+ const removeTaskIds = (draft, taskIds) => {
582
+ removeIdsFromTabData(draft, taskIds);
583
+ removeIdsFromTabData(draft.byTab[draft.currentTab], taskIds);
584
+ };
491
585
  const getGroupedTaskIds = (tasks) => {
492
586
  const taskIds = [];
493
587
  const taskIdsByGroupIds = {};