@zeniai/client-epic-state 5.0.32 → 5.0.33-betaRR0

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 (112) 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 +4 -2
  11. package/lib/entity/tenant/clearAllEpic.js +4 -0
  12. package/lib/entity/transaction/stateTypes/attachment.d.ts +2 -2
  13. package/lib/epic.d.ts +7 -1
  14. package/lib/epic.js +7 -1
  15. package/lib/esm/commonStateTypes/fiscalYearHelpers/formatZeniDateFY.js +1 -0
  16. package/lib/esm/entity/file/fileState.js +4 -0
  17. package/lib/esm/entity/snackbar/snackbarTypes.js +4 -0
  18. package/lib/esm/entity/task/taskPayload.js +5 -0
  19. package/lib/esm/entity/tenant/clearAllEpic.js +4 -0
  20. package/lib/esm/epic.js +7 -1
  21. package/lib/esm/index.js +10 -4
  22. package/lib/esm/init.js +24 -4
  23. package/lib/esm/reducer.js +6 -0
  24. package/lib/esm/view/taskManager/cannedResponsesView/cannedResponses.js +1 -0
  25. package/lib/esm/view/taskManager/cannedResponsesView/cannedResponsesPayload.js +12 -0
  26. package/lib/esm/view/taskManager/cannedResponsesView/cannedResponsesReducer.js +64 -0
  27. package/lib/esm/view/taskManager/cannedResponsesView/cannedResponsesSelector.js +3 -0
  28. package/lib/esm/view/taskManager/cannedResponsesView/epics/deleteCannedResponseEpic.js +17 -0
  29. package/lib/esm/view/taskManager/cannedResponsesView/epics/fetchCannedResponsesEpic.js +21 -0
  30. package/lib/esm/view/taskManager/cannedResponsesView/epics/saveCannedResponseEpic.js +29 -0
  31. package/lib/esm/view/taskManager/taskDetailView/epics/archiveTaskEpic.js +3 -0
  32. package/lib/esm/view/taskManager/taskDetailView/epics/deleteTaskEpic.js +5 -0
  33. package/lib/esm/view/taskManager/taskDetailView/epics/initializeTaskToLocalStoreEpic.js +1 -0
  34. package/lib/esm/view/taskManager/taskDetailView/epics/saveTaskDetailEpic.js +1 -0
  35. package/lib/esm/view/taskManager/taskDetailView/epics/snoozeTaskEpic.js +66 -0
  36. package/lib/esm/view/taskManager/taskDetailView/epics/unsnoozeTaskEpic.js +57 -0
  37. package/lib/esm/view/taskManager/taskDetailView/taskDetail.js +4 -0
  38. package/lib/esm/view/taskManager/taskDetailView/taskDetailReducer.js +60 -7
  39. package/lib/esm/view/taskManager/taskDetailView/taskDetailSelector.js +12 -0
  40. package/lib/esm/view/taskManager/taskListView/epics/bulkUpdateTaskListEpic.js +56 -21
  41. package/lib/esm/view/taskManager/taskListView/epics/dragNDropTasksEpic.js +1 -0
  42. package/lib/esm/view/taskManager/taskListView/epics/fetchTaskListEpic.js +13 -4
  43. package/lib/esm/view/taskManager/taskListView/epics/updateTaskFromListViewEpic.js +3 -2
  44. package/lib/esm/view/taskManager/taskListView/taskList.js +7 -0
  45. package/lib/esm/view/taskManager/taskListView/taskListReducer.js +106 -12
  46. package/lib/esm/view/taskManager/taskListView/taskListSelector.js +48 -39
  47. package/lib/esm/view/zeniOAuthView/epics/approveOAuthConsentEpic.js +64 -0
  48. package/lib/esm/view/zeniOAuthView/zeniOAuthParamsParser.js +41 -0
  49. package/lib/esm/view/zeniOAuthView/zeniOAuthReducer.js +49 -0
  50. package/lib/esm/view/zeniOAuthView/zeniOAuthSelector.js +3 -0
  51. package/lib/esm/view/zeniOAuthView/zeniOAuthState.js +1 -0
  52. package/lib/index.d.ts +12 -4
  53. package/lib/index.js +28 -5
  54. package/lib/init.d.ts +5 -3
  55. package/lib/init.js +24 -4
  56. package/lib/reducer.d.ts +6 -0
  57. package/lib/reducer.js +6 -0
  58. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
  59. package/lib/view/taskManager/cannedResponsesView/cannedResponses.d.ts +19 -0
  60. package/lib/view/taskManager/cannedResponsesView/cannedResponses.js +2 -0
  61. package/lib/view/taskManager/cannedResponsesView/cannedResponsesPayload.d.ts +21 -0
  62. package/lib/view/taskManager/cannedResponsesView/cannedResponsesPayload.js +15 -0
  63. package/lib/view/taskManager/cannedResponsesView/cannedResponsesReducer.d.ts +30 -0
  64. package/lib/view/taskManager/cannedResponsesView/cannedResponsesReducer.js +68 -0
  65. package/lib/view/taskManager/cannedResponsesView/cannedResponsesSelector.d.ts +3 -0
  66. package/lib/view/taskManager/cannedResponsesView/cannedResponsesSelector.js +6 -0
  67. package/lib/view/taskManager/cannedResponsesView/epics/deleteCannedResponseEpic.d.ts +7 -0
  68. package/lib/view/taskManager/cannedResponsesView/epics/deleteCannedResponseEpic.js +21 -0
  69. package/lib/view/taskManager/cannedResponsesView/epics/fetchCannedResponsesEpic.d.ts +7 -0
  70. package/lib/view/taskManager/cannedResponsesView/epics/fetchCannedResponsesEpic.js +25 -0
  71. package/lib/view/taskManager/cannedResponsesView/epics/saveCannedResponseEpic.d.ts +7 -0
  72. package/lib/view/taskManager/cannedResponsesView/epics/saveCannedResponseEpic.js +33 -0
  73. package/lib/view/taskManager/taskDetailView/epics/archiveTaskEpic.d.ts +2 -1
  74. package/lib/view/taskManager/taskDetailView/epics/archiveTaskEpic.js +3 -0
  75. package/lib/view/taskManager/taskDetailView/epics/deleteTaskEpic.d.ts +2 -1
  76. package/lib/view/taskManager/taskDetailView/epics/deleteTaskEpic.js +5 -0
  77. package/lib/view/taskManager/taskDetailView/epics/initializeTaskToLocalStoreEpic.js +1 -0
  78. package/lib/view/taskManager/taskDetailView/epics/saveTaskDetailEpic.js +1 -0
  79. package/lib/view/taskManager/taskDetailView/epics/snoozeTaskEpic.d.ts +9 -0
  80. package/lib/view/taskManager/taskDetailView/epics/snoozeTaskEpic.js +70 -0
  81. package/lib/view/taskManager/taskDetailView/epics/unsnoozeTaskEpic.d.ts +9 -0
  82. package/lib/view/taskManager/taskDetailView/epics/unsnoozeTaskEpic.js +61 -0
  83. package/lib/view/taskManager/taskDetailView/taskDetail.d.ts +2 -0
  84. package/lib/view/taskManager/taskDetailView/taskDetail.js +4 -0
  85. package/lib/view/taskManager/taskDetailView/taskDetailReducer.d.ts +10 -1
  86. package/lib/view/taskManager/taskDetailView/taskDetailReducer.js +61 -8
  87. package/lib/view/taskManager/taskDetailView/taskDetailSelector.d.ts +5 -0
  88. package/lib/view/taskManager/taskDetailView/taskDetailSelector.js +12 -0
  89. package/lib/view/taskManager/taskListView/epics/bulkUpdateTaskListEpic.d.ts +6 -7
  90. package/lib/view/taskManager/taskListView/epics/bulkUpdateTaskListEpic.js +56 -22
  91. package/lib/view/taskManager/taskListView/epics/dragNDropTasksEpic.js +1 -0
  92. package/lib/view/taskManager/taskListView/epics/fetchTaskListEpic.js +13 -4
  93. package/lib/view/taskManager/taskListView/epics/updateTaskFromListViewEpic.js +3 -2
  94. package/lib/view/taskManager/taskListView/taskList.d.ts +14 -1
  95. package/lib/view/taskManager/taskListView/taskList.js +8 -1
  96. package/lib/view/taskManager/taskListView/taskListPayload.d.ts +3 -0
  97. package/lib/view/taskManager/taskListView/taskListReducer.d.ts +9 -6
  98. package/lib/view/taskManager/taskListView/taskListReducer.js +107 -13
  99. package/lib/view/taskManager/taskListView/taskListSelector.d.ts +9 -3
  100. package/lib/view/taskManager/taskListView/taskListSelector.js +48 -39
  101. package/lib/view/zeniOAuthView/epics/approveOAuthConsentEpic.d.ts +27 -0
  102. package/lib/view/zeniOAuthView/epics/approveOAuthConsentEpic.js +68 -0
  103. package/lib/view/zeniOAuthView/zeniOAuthParamsParser.d.ts +16 -0
  104. package/lib/view/zeniOAuthView/zeniOAuthParamsParser.js +44 -0
  105. package/lib/view/zeniOAuthView/zeniOAuthReducer.d.ts +29 -0
  106. package/lib/view/zeniOAuthView/zeniOAuthReducer.js +53 -0
  107. package/lib/view/zeniOAuthView/zeniOAuthSelector.d.ts +5 -0
  108. package/lib/view/zeniOAuthView/zeniOAuthSelector.js +9 -0
  109. package/lib/view/zeniOAuthView/zeniOAuthState.d.ts +4 -0
  110. package/lib/view/zeniOAuthView/zeniOAuthState.js +2 -0
  111. package/package.json +1 -1
  112. package/lib/tsconfig.typecheck.tsbuildinfo +0 -1
@@ -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
  };
@@ -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);