@zeniai/client-epic-state 5.0.2-betaRR01 → 5.0.2-betaRR02

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 (54) hide show
  1. package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
  2. package/lib/entity/snackbar/snackbarTypes.js +2 -0
  3. package/lib/entity/task/taskPayload.d.ts +3 -0
  4. package/lib/entity/task/taskPayload.js +5 -0
  5. package/lib/entity/task/taskState.d.ts +3 -0
  6. package/lib/epic.d.ts +3 -1
  7. package/lib/epic.js +3 -1
  8. package/lib/esm/entity/snackbar/snackbarTypes.js +2 -0
  9. package/lib/esm/entity/task/taskPayload.js +5 -0
  10. package/lib/esm/epic.js +3 -1
  11. package/lib/esm/index.js +4 -4
  12. package/lib/esm/view/taskManager/taskDetailView/epics/archiveTaskEpic.js +3 -0
  13. package/lib/esm/view/taskManager/taskDetailView/epics/deleteTaskEpic.js +5 -0
  14. package/lib/esm/view/taskManager/taskDetailView/epics/snoozeTaskEpic.js +65 -0
  15. package/lib/esm/view/taskManager/taskDetailView/epics/unsnoozeTaskEpic.js +56 -0
  16. package/lib/esm/view/taskManager/taskDetailView/taskDetail.js +4 -0
  17. package/lib/esm/view/taskManager/taskDetailView/taskDetailReducer.js +49 -1
  18. package/lib/esm/view/taskManager/taskDetailView/taskDetailSelector.js +9 -0
  19. package/lib/esm/view/taskManager/taskListView/epics/bulkUpdateTaskListEpic.js +56 -21
  20. package/lib/esm/view/taskManager/taskListView/epics/dragNDropTasksEpic.js +1 -0
  21. package/lib/esm/view/taskManager/taskListView/epics/fetchTaskListEpic.js +13 -3
  22. package/lib/esm/view/taskManager/taskListView/taskList.js +7 -0
  23. package/lib/esm/view/taskManager/taskListView/taskListReducer.js +91 -12
  24. package/lib/esm/view/taskManager/taskListView/taskListSelector.js +22 -6
  25. package/lib/index.d.ts +4 -4
  26. package/lib/index.js +9 -4
  27. package/lib/tsconfig.typecheck.tsbuildinfo +1 -1
  28. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
  29. package/lib/view/taskManager/taskDetailView/epics/archiveTaskEpic.d.ts +2 -1
  30. package/lib/view/taskManager/taskDetailView/epics/archiveTaskEpic.js +3 -0
  31. package/lib/view/taskManager/taskDetailView/epics/deleteTaskEpic.d.ts +2 -1
  32. package/lib/view/taskManager/taskDetailView/epics/deleteTaskEpic.js +5 -0
  33. package/lib/view/taskManager/taskDetailView/epics/snoozeTaskEpic.d.ts +9 -0
  34. package/lib/view/taskManager/taskDetailView/epics/snoozeTaskEpic.js +69 -0
  35. package/lib/view/taskManager/taskDetailView/epics/unsnoozeTaskEpic.d.ts +9 -0
  36. package/lib/view/taskManager/taskDetailView/epics/unsnoozeTaskEpic.js +60 -0
  37. package/lib/view/taskManager/taskDetailView/taskDetail.d.ts +1 -0
  38. package/lib/view/taskManager/taskDetailView/taskDetail.js +4 -0
  39. package/lib/view/taskManager/taskDetailView/taskDetailReducer.d.ts +10 -1
  40. package/lib/view/taskManager/taskDetailView/taskDetailReducer.js +50 -2
  41. package/lib/view/taskManager/taskDetailView/taskDetailSelector.d.ts +4 -0
  42. package/lib/view/taskManager/taskDetailView/taskDetailSelector.js +9 -0
  43. package/lib/view/taskManager/taskListView/epics/bulkUpdateTaskListEpic.d.ts +6 -7
  44. package/lib/view/taskManager/taskListView/epics/bulkUpdateTaskListEpic.js +56 -22
  45. package/lib/view/taskManager/taskListView/epics/dragNDropTasksEpic.js +1 -0
  46. package/lib/view/taskManager/taskListView/epics/fetchTaskListEpic.js +13 -3
  47. package/lib/view/taskManager/taskListView/taskList.d.ts +14 -1
  48. package/lib/view/taskManager/taskListView/taskList.js +8 -1
  49. package/lib/view/taskManager/taskListView/taskListPayload.d.ts +3 -0
  50. package/lib/view/taskManager/taskListView/taskListReducer.d.ts +6 -2
  51. package/lib/view/taskManager/taskListView/taskListReducer.js +92 -13
  52. package/lib/view/taskManager/taskListView/taskListSelector.d.ts +3 -1
  53. package/lib/view/taskManager/taskListView/taskListSelector.js +22 -6
  54. package/package.json +1 -1
@@ -0,0 +1,65 @@
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 { date } from '../../../../zeniDayJS';
7
+ import { fetchTaskList, removeTaskFromList, } from '../../taskListView/taskListReducer';
8
+ import { snoozeTask, snoozeTaskSuccessOrFailure } from '../taskDetailReducer';
9
+ export const snoozeTaskEpic = (actions$, _state$, zeniAPI) => actions$.pipe(filter(snoozeTask.match), mergeMap((action) => handleSnoozeTask(action.payload.taskId, action.payload.snoozedUntil, zeniAPI)));
10
+ const formatSnoozedUntilForDisplay = (snoozedUntil) => date(snoozedUntil).format('MMM D, h:mm A');
11
+ const handleSnoozeTask = (taskId, snoozedUntil, zeniAPI) => {
12
+ const snoozeTaskApi$ = zeniAPI.postAndGetJSON(`${zeniAPI.apiEndPoints.taskMicroServiceBaseUrl}/1.0/task-manager/tasks/${taskId}/snooze`, { snoozed_until: snoozedUntil });
13
+ return snoozeTaskApi$.pipe(mergeMap((response) => handleApiResponse(response, taskId, snoozedUntil)), catchError((error) => of(snoozeTaskSuccessOrFailure({
14
+ fetchState: 'Error',
15
+ taskId,
16
+ error: createZeniAPIStatus('Unexpected Error', 'Snooze Task REST API call errored out: ' + JSON.stringify(error)),
17
+ }))));
18
+ };
19
+ const handleApiResponse = (response, taskId, snoozedUntil) => {
20
+ if (isSuccessResponse(response) &&
21
+ response.data != null &&
22
+ response.data.tasks.length > 0) {
23
+ const fetchActions = [
24
+ updateTasks(response.data.tasks),
25
+ removeTaskFromList(taskId),
26
+ fetchTaskList(),
27
+ snoozeTaskSuccessOrFailure({
28
+ fetchState: 'Completed',
29
+ taskId,
30
+ }),
31
+ openSnackbar({
32
+ messageSection: 'snooze_task',
33
+ messageText: 'success',
34
+ type: 'success',
35
+ variables: [
36
+ {
37
+ variableName: '_snoozed_until_',
38
+ variableValue: formatSnoozedUntilForDisplay(snoozedUntil),
39
+ },
40
+ ],
41
+ }),
42
+ ];
43
+ return from(fetchActions);
44
+ }
45
+ else {
46
+ return from([
47
+ snoozeTaskSuccessOrFailure({
48
+ fetchState: 'Error',
49
+ taskId,
50
+ error: response.status,
51
+ }),
52
+ openSnackbar({
53
+ messageSection: 'snooze_task',
54
+ messageText: 'failed',
55
+ type: 'error',
56
+ variables: [
57
+ {
58
+ variableName: '_api-error_',
59
+ variableValue: response.status.message,
60
+ },
61
+ ],
62
+ }),
63
+ ]);
64
+ }
65
+ };
@@ -0,0 +1,56 @@
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 } 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
+ fetchTaskList(),
24
+ snoozeTaskSuccessOrFailure({
25
+ fetchState: 'Completed',
26
+ taskId,
27
+ }),
28
+ openSnackbar({
29
+ messageSection: 'unsnooze_task',
30
+ messageText: 'success',
31
+ type: 'success',
32
+ }),
33
+ ];
34
+ return from(fetchActions);
35
+ }
36
+ else {
37
+ return from([
38
+ snoozeTaskSuccessOrFailure({
39
+ fetchState: 'Error',
40
+ taskId,
41
+ error: response.status,
42
+ }),
43
+ openSnackbar({
44
+ messageSection: 'unsnooze_task',
45
+ messageText: 'failed',
46
+ type: 'error',
47
+ variables: [
48
+ {
49
+ variableName: '_api-error_',
50
+ variableValue: response.status.message,
51
+ },
52
+ ],
53
+ }),
54
+ ]);
55
+ }
56
+ };
@@ -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
  };
@@ -229,6 +229,54 @@ const taskDetailView = createSlice({
229
229
  draft.newTaskState.deleteTaskStatus.error = action.payload.error;
230
230
  }
231
231
  },
232
+ snoozeTask: {
233
+ reducer(draft, action) {
234
+ const { taskId } = action.payload;
235
+ draft.editTaskStateById[taskId] = {
236
+ ...(draft.editTaskStateById[taskId] != null
237
+ ? draft.editTaskStateById[taskId]
238
+ : initialTaskDetail),
239
+ snoozeStatus: {
240
+ fetchState: 'In-Progress',
241
+ error: undefined,
242
+ },
243
+ };
244
+ },
245
+ prepare(taskId, snoozedUntil) {
246
+ return {
247
+ payload: {
248
+ taskId,
249
+ snoozedUntil,
250
+ },
251
+ };
252
+ },
253
+ },
254
+ snoozeTaskSuccessOrFailure(draft, action) {
255
+ const { taskId, fetchState, error } = action.payload;
256
+ draft.editTaskStateById[taskId].snoozeStatus.fetchState = fetchState;
257
+ draft.editTaskStateById[taskId].snoozeStatus.error = error;
258
+ },
259
+ unsnoozeTask: {
260
+ reducer(draft, action) {
261
+ const { taskId } = action.payload;
262
+ draft.editTaskStateById[taskId] = {
263
+ ...(draft.editTaskStateById[taskId] != null
264
+ ? draft.editTaskStateById[taskId]
265
+ : initialTaskDetail),
266
+ snoozeStatus: {
267
+ fetchState: 'In-Progress',
268
+ error: undefined,
269
+ },
270
+ };
271
+ },
272
+ prepare(taskId) {
273
+ return {
274
+ payload: {
275
+ taskId,
276
+ },
277
+ };
278
+ },
279
+ },
232
280
  fetchTaskHistory: {
233
281
  reducer(draft, action) {
234
282
  const { taskId, cacheOverride } = action.payload;
@@ -270,5 +318,5 @@ const taskDetailView = createSlice({
270
318
  },
271
319
  },
272
320
  });
273
- export const { fetchTaskDetailPage, fetchTaskDetail, initializeTaskToLocalStore, updateEditTaskFetchStatus, saveTaskUpdatesToLocalStore, discardTaskUpdatesInLocalStore, saveTaskDetail, archiveTask, archiveTaskSuccessOrFailure, saveTaskSuccessOrFailure, deleteTask, removeTaskDetail, deleteTaskSuccessOrFailure, fetchTaskHistory, updateTaskHistory, updateTaskHistoryFetchStatus, clearTaskDetail, updateCreatedTagToLocalStore, updateDeletedTagToLocalStore, } = taskDetailView.actions;
321
+ 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
322
  export default taskDetailView.reducer;
@@ -21,11 +21,17 @@ export const getTaskDetail = (state, taskId) => {
21
21
  };
22
22
  let taskHistory = [];
23
23
  let createdByUser = undefined;
24
+ let isArchived = undefined;
25
+ let isDeleted = undefined;
26
+ let snoozedUntil = undefined;
24
27
  if (taskId != null && sourceTaskDetail != null) {
25
28
  const taskEntity = getTaskById(taskState, taskId);
26
29
  const fileIdsInEntity = taskEntity?.fileIds ?? [];
27
30
  if (taskEntity != null) {
28
31
  createdByUser = getUserAndUserRole(userState, userRoleState, addressState, taskEntity.createdBy);
32
+ isArchived = taskEntity.isArchived;
33
+ isDeleted = taskEntity.isDeleted;
34
+ snoozedUntil = taskEntity.snoozedUntil;
29
35
  }
30
36
  if (fileIdsInEntity.length > 0) {
31
37
  fetchStatus = reduceFetchState([
@@ -73,7 +79,10 @@ export const getTaskDetail = (state, taskId) => {
73
79
  error: fetchStatus.error,
74
80
  version: 0,
75
81
  createdByUser,
82
+ isArchived,
83
+ isDeleted,
76
84
  showTaskDetailFormFooter,
85
+ snoozedUntil,
77
86
  };
78
87
  };
79
88
  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 != null ||
21
+ updates.isDeleted != null ||
22
+ 'snoozedUntil' in updates;
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,20 @@ 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,
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 ?? [],
14
24
  updateType: 'replace',
15
- }), updateTags(response.data.tasks.map((task) => task.tags).flat()));
25
+ }), updateTags(allTasks.map((task) => task.tags).flat()));
16
26
  }
17
27
  else {
18
28
  return of(updateTaskListFetchStatus({
@@ -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) => {
@@ -404,12 +436,15 @@ const taskList = createSlice({
404
436
  draft.updateTasksFetchState.fetchState = 'Error';
405
437
  draft.updateTasksFetchState.error = action.payload.error;
406
438
  },
439
+ removeTaskFromList(draft, action) {
440
+ removeTaskIds(draft, [action.payload]);
441
+ },
407
442
  clearTaskList(draft) {
408
443
  Object.assign(draft, initialState);
409
444
  },
410
445
  },
411
446
  });
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;
447
+ 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
448
  export default taskList.reducer;
414
449
  /**
415
450
  * helpers
@@ -488,6 +523,50 @@ const getTagsGroupKey = (tags) => {
488
523
  tagIds.sort();
489
524
  return tagIds.join(',');
490
525
  };
526
+ const toTabData = (grouped) => ({
527
+ taskIds: grouped.taskIds,
528
+ taskIdsByAssignees: grouped.taskIdsByAssignees,
529
+ taskIdsByDueDate: grouped.taskIdsByDueDate,
530
+ taskIdsByGroupsIds: grouped.taskIdsByGroupIds,
531
+ taskIdsByPriority: grouped.taskIdsGroupedByPriority,
532
+ taskIdsByStatus: grouped.taskIdsGroupedByStatus,
533
+ taskIdsByTags: grouped.taskIdsByTags,
534
+ });
535
+ const copyTabDataToTopLevel = (draft, tabData) => {
536
+ draft.taskIds = tabData.taskIds;
537
+ draft.taskIdsByGroupsIds = tabData.taskIdsByGroupsIds;
538
+ draft.taskIdsByPriority = tabData.taskIdsByPriority;
539
+ draft.taskIdsByStatus = tabData.taskIdsByStatus;
540
+ draft.taskIdsByAssignees = tabData.taskIdsByAssignees;
541
+ draft.taskIdsByDueDate = tabData.taskIdsByDueDate;
542
+ draft.taskIdsByTags = tabData.taskIdsByTags;
543
+ };
544
+ const removeIdsFromTabData = (tabData, taskIds) => {
545
+ const isRemoved = (id) => taskIds.includes(id);
546
+ tabData.taskIds = tabData.taskIds.filter((id) => !isRemoved(id));
547
+ Object.keys(tabData.taskIdsByGroupsIds).forEach((gId) => {
548
+ tabData.taskIdsByGroupsIds[gId] = tabData.taskIdsByGroupsIds[gId].filter((id) => !isRemoved(id));
549
+ });
550
+ Object.keys(tabData.taskIdsByPriority).forEach((key) => {
551
+ tabData.taskIdsByPriority[key] = tabData.taskIdsByPriority[key].filter((id) => !isRemoved(id));
552
+ });
553
+ Object.keys(tabData.taskIdsByStatus).forEach((key) => {
554
+ tabData.taskIdsByStatus[key] = tabData.taskIdsByStatus[key].filter((id) => !isRemoved(id));
555
+ });
556
+ Object.keys(tabData.taskIdsByDueDate).forEach((key) => {
557
+ tabData.taskIdsByDueDate[key] = tabData.taskIdsByDueDate[key].filter((id) => !isRemoved(id));
558
+ });
559
+ Object.keys(tabData.taskIdsByAssignees).forEach((key) => {
560
+ tabData.taskIdsByAssignees[key] = tabData.taskIdsByAssignees[key].filter((id) => !isRemoved(id));
561
+ });
562
+ Object.keys(tabData.taskIdsByTags).forEach((key) => {
563
+ tabData.taskIdsByTags[key] = tabData.taskIdsByTags[key].filter((id) => !isRemoved(id));
564
+ });
565
+ };
566
+ const removeTaskIds = (draft, taskIds) => {
567
+ removeIdsFromTabData(draft, taskIds);
568
+ removeIdsFromTabData(draft.byTab[draft.currentTab], taskIds);
569
+ };
491
570
  const getGroupedTaskIds = (tasks) => {
492
571
  const taskIds = [];
493
572
  const taskIdsByGroupIds = {};
@@ -36,6 +36,8 @@ const sortTasksList = (tagState, tasksList, sortKey, sortOrder) => {
36
36
  return ALL_PRIORITY_CODE.indexOf(task.priority.code);
37
37
  case 'timeSpent':
38
38
  return task.timeSpent;
39
+ case 'visibility':
40
+ return task.isPrivate ? 1 : 0;
39
41
  case 'name':
40
42
  default:
41
43
  return task.name.toLowerCase();
@@ -104,7 +106,8 @@ const getTaskListGroupedByGroupName = ({ taskListState, taskState, taskGroupStat
104
106
  if (defaultTaskGroup != null) {
105
107
  sortedTaskGroupsWithTasksList.push(defaultTaskGroup);
106
108
  }
107
- if (isDefaultFilters(taskListState) === false) {
109
+ if (taskListState.currentTab !== 'live' ||
110
+ isDefaultFilters(taskListState) === false) {
108
111
  return sortedTaskGroupsWithTasksList.filter((group) => group.tasks.length > 0);
109
112
  }
110
113
  return sortedTaskGroupsWithTasksList;
@@ -136,7 +139,8 @@ export const getTaskListGroupedByAssignees = ({ taskListState, taskState, userSt
136
139
  tasks: tasksWithUserDetails,
137
140
  };
138
141
  });
139
- if (isDefaultFilters(taskListState) === false) {
142
+ if (taskListState.currentTab !== 'live' ||
143
+ isDefaultFilters(taskListState) === false) {
140
144
  return taskGroupsWithTasksList.filter((group) => group.tasks.length > 0);
141
145
  }
142
146
  return taskGroupsWithTasksList;
@@ -161,7 +165,8 @@ export const getTaskListGroupedByPriority = ({ taskListState, taskState, userSta
161
165
  tasks: tasksWithUserDetails,
162
166
  };
163
167
  });
164
- if (isDefaultFilters(taskListState) === false) {
168
+ if (taskListState.currentTab !== 'live' ||
169
+ isDefaultFilters(taskListState) === false) {
165
170
  return taskGroupsWithTasksList.filter((group) => group.tasks.length > 0);
166
171
  }
167
172
  return taskGroupsWithTasksList;
@@ -186,7 +191,8 @@ const getTaskListGroupedByStatus = ({ taskListState, taskState, userState, userR
186
191
  tasks: tasksWithUserDetails,
187
192
  };
188
193
  });
189
- if (isDefaultFilters(taskListState) === false) {
194
+ if (taskListState.currentTab !== 'live' ||
195
+ isDefaultFilters(taskListState) === false) {
190
196
  return taskGroupsWithTasksList.filter((group) => group.tasks.length > 0);
191
197
  }
192
198
  return taskGroupsWithTasksList;
@@ -217,7 +223,8 @@ const getTaskListGroupedByTags = ({ taskListState, taskState, userState, userRol
217
223
  tasks: tasksWithUserDetails,
218
224
  };
219
225
  });
220
- if (isDefaultFilters(taskListState) === false) {
226
+ if (taskListState.currentTab !== 'live' ||
227
+ isDefaultFilters(taskListState) === false) {
221
228
  return taskGroupsWithTasksList.filter((group) => group.tasks.length > 0);
222
229
  }
223
230
  return taskGroupsWithTasksList;
@@ -241,7 +248,8 @@ const getTaskListGroupedByDueDate = ({ taskListState, taskState, userState, user
241
248
  tasks: tasksWithUserDetails,
242
249
  };
243
250
  });
244
- if (isDefaultFilters(taskListState) === false) {
251
+ if (taskListState.currentTab !== 'live' ||
252
+ isDefaultFilters(taskListState) === false) {
245
253
  return taskGroupsWithTasksList.filter((group) => group.tasks.length > 0);
246
254
  }
247
255
  return taskGroupsWithTasksList;
@@ -331,7 +339,15 @@ export const getAllTasks = createSelector((state) => state.taskListState, (state
331
339
  }
332
340
  const { fetchState, error } = reduceAnyFetchState(fetchStateVariables);
333
341
  const taskGroupTemplates = getTaskGroupTemplateByIds(taskGroupTemplateState, taskGroupTemplateViewState.taskGroupTemplateIds);
342
+ const tabCounts = {
343
+ live: taskListState.byTab.live.taskIds.length,
344
+ archived: taskListState.byTab.archived.taskIds.length,
345
+ deleted: taskListState.byTab.deleted.taskIds.length,
346
+ snoozed: taskListState.byTab.snoozed.taskIds.length,
347
+ };
334
348
  return {
349
+ currentTab: taskListState.currentTab,
350
+ tabCounts,
335
351
  uiState: taskListState.uiState,
336
352
  filters: taskListState.filters,
337
353
  taskGroupTemplates,
package/lib/index.d.ts CHANGED
@@ -537,12 +537,12 @@ import { createTag, deleteTag, fetchTagList } from './view/tagView/tagViewReduce
537
537
  import { TagViewSelectorView, getAllTags } from './view/tagView/tagViewSelector';
538
538
  import { TagViewState } from './view/tagView/tagViewState';
539
539
  import { EditTaskLocalData, initialTaskDetail, initialTaskDetailLocalData } from './view/taskManager/taskDetailView/taskDetail';
540
- import { archiveTask, deleteTask, discardTaskUpdatesInLocalStore, fetchTaskDetailPage, saveTaskDetail, saveTaskUpdatesToLocalStore } from './view/taskManager/taskDetailView/taskDetailReducer';
540
+ import { archiveTask, deleteTask, discardTaskUpdatesInLocalStore, fetchTaskDetailPage, saveTaskDetail, saveTaskUpdatesToLocalStore, snoozeTask, unsnoozeTask } from './view/taskManager/taskDetailView/taskDetailReducer';
541
541
  import { TaskDetailSelectorView, allTaskPriority, allTaskStatus, getTaskDetail } from './view/taskManager/taskDetailView/taskDetailSelector';
542
542
  import { createTaskFromTaskGroupTemplate } from './view/taskManager/taskGroupTemplateView/taskGroupTemplateViewReducer';
543
543
  import { createNewTaskGroup, deleteTaskGroup, fetchAllTaskGroups, updateTaskGroupName } from './view/taskManager/taskGroupView/taskGroupViewReducer';
544
- import { DueDateGroupKey, TASK_LIST_FILTER_CATEGORIES, TASK_LIST_GROUP_BY_CATEGORIES, TaskFilterCategory, TaskGroupKey, TaskListFilterCategoryField, TaskListFilters, TaskListLocalData, TaskListUIState, TaskListViewSortKey, toDueDateGroupKeyType, toTaskListGroupByKeyType, toTaskListGroupByKeyTypeStrict } from './view/taskManager/taskListView/taskList';
545
- import { bulkUpdateTaskList, dragNDropTasks, fetchTaskListPage, initiateTaskListLocalData, updateTaskFilters, updateTaskFromListView, updateTaskListLocalData, updateTaskListSearchText, updateTaskListUIState } from './view/taskManager/taskListView/taskListReducer';
544
+ import { DueDateGroupKey, TASK_LIST_FILTER_CATEGORIES, TASK_LIST_GROUP_BY_CATEGORIES, TaskFilterCategory, TaskGroupKey, TaskListFilterCategoryField, TaskListFilters, TaskListLocalData, TaskListUIState, TaskListViewSortKey, toDueDateGroupKeyType, toTaskListGroupByKeyType, toTaskListGroupByKeyTypeStrict, ALL_TASK_LIST_TABS, TaskListTab } from './view/taskManager/taskListView/taskList';
545
+ import { bulkUpdateTaskList, dragNDropTasks, fetchTaskListPage, initiateTaskListLocalData, removeTaskFromList, updateTaskFilters, updateTaskFromListView, updateTaskListLocalData, updateTaskListSearchText, updateTaskListTab, updateTaskListUIState } from './view/taskManager/taskListView/taskListReducer';
546
546
  import { TaskGroupWithTasksList, TaskListSelectorView, TaskWithUserDetails, getAllTasks } from './view/taskManager/taskListView/taskListSelector';
547
547
  import { getDueDateValueFromDueDateGroupId, getTaskUpdates } from './view/taskManager/taskListView/taskListViewHelpers';
548
548
  import { fetchTasksCard } from './view/tasksCard/tasksCardReducer';
@@ -847,7 +847,7 @@ export { fetchGlobalMerchantRecommendation, createGlobalMerchant, updateCreateGl
847
847
  export { approveVendorGlobalReview, rejectVendorGlobalReview, fetchVendorGlobalReviewView, updateSelectedGlobalMerchant, updateVendorGlobalReviewViewUIState, getVendorGlobalReviewView, getTenantMerchantByMerchantId, toVendorGlobalReviewColumnSortKeyType, VendorGlobalReview, VendorGlobalReviewViewUIState, VendorGlobalReviewViewColumnSortKey, VendorGlobalReviewViewSelectorView, VendorGlobalReviewViewState, VendorGlobalReviewViewLocalData, updateVendorGlobalReviewViewLocalData, GlobalReviewPageCurrentSelectionByColumn, GlobalRecommendationFetchSource, };
848
848
  export { fetchArAging, updateArAgingUIState, fetchArAgingDetail, updateArAgingDetailUIState, ArAgingReport, ArAgingDetail, NestedAgingBalancesByCustomer, getArAgingReport, getArAgingDetailForCustomer, updateArAgingNodeCollapseState, };
849
849
  export { toRecurringBillFrequency, toRecurringBillFrequencyStrict, RecurringBillFrequency, RecurringBillDetail, RecurringBillConfig, RecurringBillStatus, RecurringBillPaymentStatus, };
850
- export { Task, TaskListSelectorView, TaskWithUserDetails, TaskListViewSortKey, TaskListUIState, TaskDetailSelectorView, EditTaskLocalData, TaskStatusCodeType, PriorityCodeType, getTaskGroupById, TaskStatus, TaskPriority, TaskCodeType, getAllTasks, fetchTaskListPage, getTaskDetail, fetchTaskDetailPage, saveTaskUpdatesToLocalStore, saveTaskDetail, archiveTask, updateTaskListSearchText, updateTaskListUIState, allTaskStatus, allTaskPriority, TaskListFilters, updateTaskFilters, TASK_LIST_FILTER_CATEGORIES, TASK_LIST_GROUP_BY_CATEGORIES, TaskListFilterCategoryField, deleteTask, discardTaskUpdatesInLocalStore, TaskFilterCategory, TaskType, TaskGroupWithTasksList, TaskListLocalData, bulkUpdateTaskList, createNewTaskGroup, initiateTaskListLocalData, deleteTaskGroup, updateTaskListLocalData, dragNDropTasks, updateTaskGroupName, TaskGroupState, TaskGroupKey, toTaskListGroupByKeyType, toTaskListGroupByKeyTypeStrict, getTaskUpdates, fetchAllTaskGroups, initialTaskDetail, getDueDateValueFromDueDateGroupId, toPriorityCodeType, toTaskStatusCodeType, DueDateGroupKey, toDueDateGroupKeyType, updateTaskFromListView, convertHHMMStrToMinutes, initialTaskDetailLocalData, };
850
+ export { Task, TaskListSelectorView, TaskWithUserDetails, TaskListViewSortKey, TaskListUIState, TaskDetailSelectorView, EditTaskLocalData, TaskStatusCodeType, PriorityCodeType, getTaskGroupById, TaskStatus, TaskPriority, TaskCodeType, getAllTasks, fetchTaskListPage, getTaskDetail, fetchTaskDetailPage, saveTaskUpdatesToLocalStore, saveTaskDetail, archiveTask, updateTaskListSearchText, updateTaskListUIState, allTaskStatus, allTaskPriority, TaskListFilters, updateTaskFilters, TASK_LIST_FILTER_CATEGORIES, TASK_LIST_GROUP_BY_CATEGORIES, TaskListFilterCategoryField, deleteTask, discardTaskUpdatesInLocalStore, TaskFilterCategory, TaskType, TaskGroupWithTasksList, TaskListLocalData, bulkUpdateTaskList, createNewTaskGroup, initiateTaskListLocalData, deleteTaskGroup, updateTaskListLocalData, dragNDropTasks, updateTaskGroupName, TaskGroupState, TaskGroupKey, toTaskListGroupByKeyType, toTaskListGroupByKeyTypeStrict, getTaskUpdates, fetchAllTaskGroups, initialTaskDetail, getDueDateValueFromDueDateGroupId, toPriorityCodeType, toTaskStatusCodeType, DueDateGroupKey, toDueDateGroupKeyType, updateTaskFromListView, updateTaskListTab, removeTaskFromList, snoozeTask, unsnoozeTask, convertHHMMStrToMinutes, initialTaskDetailLocalData, TaskListTab, ALL_TASK_LIST_TABS, };
851
851
  export { Tag, TagState, TagViewState, getAllTags, TagViewSelectorView, fetchTagList, createTag, deleteTag, };
852
852
  export { CardPayment, CardPaymentViewState, SetupIntentData, CardPaymentSelectorView, getAllCardsAndBankPaymentMethods, createCardSetupIntent, confirmCardSetupIntent, addCardPaymentSource, fetchPaymentSources, resetCardPaymentErrorStatuses, clearCardPaymentView, AddCardPaymentSourceType, };
853
853
  export { getAuditReportGroupViewSelectorView, getAuditRuleGroupViewSelectorView, getUserFromAllUsers, AuditReportGroupSelectorView, AuditReportGroupViewSelectorView, AuditRuleGroupViewSelectorView, fetchAuditRuleGroupView, fetchAuditReportGroupView, saveReasonForAuditRule, AuditRuleGroup, AuditRuleGroupReport, AuditReportRule, AuditRuleEntityType, AuditRuleEntityIdType, AuditRuleBypassReason, clearAuditReportGroupViewByCompanyId, };