@zeniai/client-epic-state 5.1.43 → 5.1.45-betaDI1
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.
- package/lib/entity/task/taskPayload.d.ts +1 -0
- package/lib/entity/task/taskPayload.js +8 -0
- package/lib/entity/task/taskState.d.ts +1 -0
- package/lib/esm/entity/task/taskPayload.js +8 -0
- package/lib/esm/view/expenseAutomationView/reducers/reconciliationViewReducer.js +21 -9
- package/lib/esm/view/taskManager/taskDetailView/epics/initializeTaskToLocalStoreEpic.js +1 -0
- package/lib/esm/view/taskManager/taskListView/taskListReducer.js +28 -1
- package/lib/view/expenseAutomationView/reducers/reconciliationViewReducer.js +21 -9
- package/lib/view/taskManager/taskDetailView/epics/initializeTaskToLocalStoreEpic.js +1 -0
- package/lib/view/taskManager/taskDetailView/taskDetail.d.ts +1 -0
- package/lib/view/taskManager/taskListView/taskListReducer.js +28 -1
- package/package.json +1 -1
|
@@ -45,6 +45,14 @@ const mapTaskPayloadToTask = (payload, previousTask) => ({
|
|
|
45
45
|
updateTime: payload.update_time != null ? (0, zeniDayJS_1.date)(payload.update_time) : undefined,
|
|
46
46
|
companyId: payload.company_id,
|
|
47
47
|
companyName: payload.company_name,
|
|
48
|
+
// `depth` may be absent on partial updates (e.g. pusher-driven task
|
|
49
|
+
// refreshes that don't include it). Preserve the previously-known depth
|
|
50
|
+
// there — otherwise the Redux store's depth flips to undefined and any
|
|
51
|
+
// WC depth-cap gate ("hide Create Subtask at depth 3") re-opens
|
|
52
|
+
// incorrectly. Explicit `null` from the BE still clears it via `??`.
|
|
53
|
+
depth: payload.depth !== undefined
|
|
54
|
+
? (payload.depth ?? undefined)
|
|
55
|
+
: previousTask?.depth,
|
|
48
56
|
parentTaskId: payload.parent_task_id ?? undefined,
|
|
49
57
|
recurringSourceTaskId: payload.recurring_source_task_id != null
|
|
50
58
|
? payload.recurring_source_task_id
|
|
@@ -42,6 +42,14 @@ export const mapTaskPayloadToTask = (payload, previousTask) => ({
|
|
|
42
42
|
updateTime: payload.update_time != null ? date(payload.update_time) : undefined,
|
|
43
43
|
companyId: payload.company_id,
|
|
44
44
|
companyName: payload.company_name,
|
|
45
|
+
// `depth` may be absent on partial updates (e.g. pusher-driven task
|
|
46
|
+
// refreshes that don't include it). Preserve the previously-known depth
|
|
47
|
+
// there — otherwise the Redux store's depth flips to undefined and any
|
|
48
|
+
// WC depth-cap gate ("hide Create Subtask at depth 3") re-opens
|
|
49
|
+
// incorrectly. Explicit `null` from the BE still clears it via `??`.
|
|
50
|
+
depth: payload.depth !== undefined
|
|
51
|
+
? (payload.depth ?? undefined)
|
|
52
|
+
: previousTask?.depth,
|
|
45
53
|
parentTaskId: payload.parent_task_id ?? undefined,
|
|
46
54
|
recurringSourceTaskId: payload.recurring_source_task_id != null
|
|
47
55
|
? payload.recurring_source_task_id
|
|
@@ -95,12 +95,12 @@ const expenseAutomationReconciliationView = createSlice({
|
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
else {
|
|
98
|
-
//
|
|
98
|
+
// Visiting an account detail page selects it and opens review; background
|
|
99
|
+
// refresh (e.g. statement Pusher) must not change navigation selection.
|
|
99
100
|
if (action.payload.refreshViewInBackground !== true) {
|
|
100
101
|
draft.selectedTab = 'review';
|
|
102
|
+
draft.selectedAccountId = action.payload.accountId;
|
|
101
103
|
}
|
|
102
|
-
// select the account for which we are fetching
|
|
103
|
-
draft.selectedAccountId = action.payload.accountId;
|
|
104
104
|
const accountReconciliationRecords = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(action.payload.selectedPeriod)];
|
|
105
105
|
const { transactionFetchState } = accountReconciliationRecords.reconciliationByAccountID[action.payload.accountId];
|
|
106
106
|
if (transactionFetchState.fetchState !== 'Completed' ||
|
|
@@ -517,21 +517,33 @@ const expenseAutomationReconciliationView = createSlice({
|
|
|
517
517
|
},
|
|
518
518
|
parseStatementSuccess: (draft, action) => {
|
|
519
519
|
const { accountId, selectedPeriod } = action.payload;
|
|
520
|
-
draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]
|
|
520
|
+
const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
|
|
521
|
+
if (accountRecon == null) {
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
accountRecon.statementParseStatus = {
|
|
521
525
|
fetchState: 'Completed',
|
|
522
526
|
error: undefined,
|
|
523
527
|
};
|
|
524
|
-
|
|
525
|
-
|
|
528
|
+
accountRecon.statementParseInProgress = false;
|
|
529
|
+
accountRecon.statementProcessingFailed = false;
|
|
530
|
+
// Stop elapsed-time step simulation; keep dismissed flag so the
|
|
531
|
+
// app-level completion snackbar can still fire.
|
|
532
|
+
accountRecon.statementProcessingStartedAtMs = undefined;
|
|
533
|
+
accountRecon.statementProcessingTotalDurationSeconds = undefined;
|
|
526
534
|
},
|
|
527
535
|
parseStatementFailure: (draft, action) => {
|
|
528
536
|
const { accountId, selectedPeriod } = action.payload;
|
|
529
|
-
draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]
|
|
537
|
+
const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[toMonthYearPeriodId(selectedPeriod)]?.reconciliationByAccountID[accountId];
|
|
538
|
+
if (accountRecon == null) {
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
accountRecon.statementParseStatus = {
|
|
530
542
|
fetchState: 'Error',
|
|
531
543
|
error: action.payload.error,
|
|
532
544
|
};
|
|
533
|
-
|
|
534
|
-
|
|
545
|
+
accountRecon.statementParseInProgress = false;
|
|
546
|
+
accountRecon.statementProcessingFailed = true;
|
|
535
547
|
},
|
|
536
548
|
reparseStatement: (draft, action) => {
|
|
537
549
|
const { accountId, selectedPeriod } = action.payload;
|
|
@@ -29,6 +29,7 @@ export const initializeTaskToLocalStoreEpic = (actions$, state$) => actions$.pip
|
|
|
29
29
|
timeSpent: task.timeSpent,
|
|
30
30
|
isPrivate: task.isPrivate,
|
|
31
31
|
taskGroupId: task.taskGroupIds[0],
|
|
32
|
+
depth: task.depth,
|
|
32
33
|
};
|
|
33
34
|
const actions = [
|
|
34
35
|
saveTaskUpdatesToLocalStore({ taskDetailLocalData, taskId }),
|
|
@@ -824,13 +824,40 @@ const getGroupedTaskIds = (tasks) => {
|
|
|
824
824
|
...initialTaskIdsByDueDate,
|
|
825
825
|
};
|
|
826
826
|
const taskIdsByTags = {};
|
|
827
|
+
// Which parents are actually present in this payload. A subtask is
|
|
828
|
+
// only treated as "nested" (and dropped from the count / groupings)
|
|
829
|
+
// if its parent is in the visible set — otherwise it renders as an
|
|
830
|
+
// orphan top-level row in the UI (SubtaskDetailTable has no parent to
|
|
831
|
+
// attach under) and MUST count. Customer callers routinely see this:
|
|
832
|
+
// the parent is Zeni-internal / private and filtered server-side, but
|
|
833
|
+
// the subtask itself is public and lands in the payload.
|
|
834
|
+
const visibleTaskIds = new Set(tasks.map((t) => t.task_id));
|
|
827
835
|
tasks.forEach((task) => {
|
|
828
|
-
|
|
836
|
+
// A task is a "nested subtask" only when its parent is in the
|
|
837
|
+
// visible payload — otherwise it's an orphan and renders as a
|
|
838
|
+
// top-level row in the UI (customer callers routinely see this:
|
|
839
|
+
// the parent is Zeni-internal / private and filtered server-side,
|
|
840
|
+
// but the subtask itself is public and lands in the payload).
|
|
841
|
+
// Datastore string properties default to '' when unset, so treat
|
|
842
|
+
// empty string as null. Matches the sibling `updateTasks` guard
|
|
843
|
+
// at L719-722.
|
|
844
|
+
const isNestedSubtask = task.parent_task_id != null &&
|
|
845
|
+
task.parent_task_id !== '' &&
|
|
846
|
+
visibleTaskIds.has(task.parent_task_id);
|
|
847
|
+
// Subtasks stay in every groupBy array so the UI can render them
|
|
848
|
+
// nested under their parent (WC's TaskManagementPage builds
|
|
849
|
+
// `subtasksByParentId` from `group.tasks` and then filters them
|
|
850
|
+
// out of top-level rows via `filterOutSubtasks`). Only the flat
|
|
851
|
+
// top-level `taskIds` array — which drives the Active/Completed/…
|
|
852
|
+
// tab counts — must exclude nested subtasks.
|
|
829
853
|
const priorityKey = toPriorityCodeType(task.priority.code);
|
|
830
854
|
const statusKey = toTaskStatusCodeType(task.status.code);
|
|
831
855
|
const assigneeKey = getAssigneesGroupKey(task.assignees);
|
|
832
856
|
const dueDateKey = getDueDateGroupKey(task.due_date);
|
|
833
857
|
const tagsKey = getTagsGroupKey(task.tags);
|
|
858
|
+
if (!isNestedSubtask) {
|
|
859
|
+
taskIds.push(task.task_id);
|
|
860
|
+
}
|
|
834
861
|
taskIdsGroupedByPriority[priorityKey] = [
|
|
835
862
|
...taskIdsGroupedByPriority[priorityKey],
|
|
836
863
|
task.task_id,
|
|
@@ -100,12 +100,12 @@ const expenseAutomationReconciliationView = (0, toolkit_1.createSlice)({
|
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
else {
|
|
103
|
-
//
|
|
103
|
+
// Visiting an account detail page selects it and opens review; background
|
|
104
|
+
// refresh (e.g. statement Pusher) must not change navigation selection.
|
|
104
105
|
if (action.payload.refreshViewInBackground !== true) {
|
|
105
106
|
draft.selectedTab = 'review';
|
|
107
|
+
draft.selectedAccountId = action.payload.accountId;
|
|
106
108
|
}
|
|
107
|
-
// select the account for which we are fetching
|
|
108
|
-
draft.selectedAccountId = action.payload.accountId;
|
|
109
109
|
const accountReconciliationRecords = draft.accountReconciliationRecordsBySelectedPeriod[(0, timePeriod_1.toMonthYearPeriodId)(action.payload.selectedPeriod)];
|
|
110
110
|
const { transactionFetchState } = accountReconciliationRecords.reconciliationByAccountID[action.payload.accountId];
|
|
111
111
|
if (transactionFetchState.fetchState !== 'Completed' ||
|
|
@@ -522,21 +522,33 @@ const expenseAutomationReconciliationView = (0, toolkit_1.createSlice)({
|
|
|
522
522
|
},
|
|
523
523
|
parseStatementSuccess: (draft, action) => {
|
|
524
524
|
const { accountId, selectedPeriod } = action.payload;
|
|
525
|
-
draft.accountReconciliationRecordsBySelectedPeriod[(0, timePeriod_1.toMonthYearPeriodId)(selectedPeriod)]
|
|
525
|
+
const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[(0, timePeriod_1.toMonthYearPeriodId)(selectedPeriod)]?.reconciliationByAccountID[accountId];
|
|
526
|
+
if (accountRecon == null) {
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
accountRecon.statementParseStatus = {
|
|
526
530
|
fetchState: 'Completed',
|
|
527
531
|
error: undefined,
|
|
528
532
|
};
|
|
529
|
-
|
|
530
|
-
|
|
533
|
+
accountRecon.statementParseInProgress = false;
|
|
534
|
+
accountRecon.statementProcessingFailed = false;
|
|
535
|
+
// Stop elapsed-time step simulation; keep dismissed flag so the
|
|
536
|
+
// app-level completion snackbar can still fire.
|
|
537
|
+
accountRecon.statementProcessingStartedAtMs = undefined;
|
|
538
|
+
accountRecon.statementProcessingTotalDurationSeconds = undefined;
|
|
531
539
|
},
|
|
532
540
|
parseStatementFailure: (draft, action) => {
|
|
533
541
|
const { accountId, selectedPeriod } = action.payload;
|
|
534
|
-
draft.accountReconciliationRecordsBySelectedPeriod[(0, timePeriod_1.toMonthYearPeriodId)(selectedPeriod)]
|
|
542
|
+
const accountRecon = draft.accountReconciliationRecordsBySelectedPeriod[(0, timePeriod_1.toMonthYearPeriodId)(selectedPeriod)]?.reconciliationByAccountID[accountId];
|
|
543
|
+
if (accountRecon == null) {
|
|
544
|
+
return;
|
|
545
|
+
}
|
|
546
|
+
accountRecon.statementParseStatus = {
|
|
535
547
|
fetchState: 'Error',
|
|
536
548
|
error: action.payload.error,
|
|
537
549
|
};
|
|
538
|
-
|
|
539
|
-
|
|
550
|
+
accountRecon.statementParseInProgress = false;
|
|
551
|
+
accountRecon.statementProcessingFailed = true;
|
|
540
552
|
},
|
|
541
553
|
reparseStatement: (draft, action) => {
|
|
542
554
|
const { accountId, selectedPeriod } = action.payload;
|
|
@@ -35,6 +35,7 @@ const initializeTaskToLocalStoreEpic = (actions$, state$) => actions$.pipe((0, o
|
|
|
35
35
|
timeSpent: task.timeSpent,
|
|
36
36
|
isPrivate: task.isPrivate,
|
|
37
37
|
taskGroupId: task.taskGroupIds[0],
|
|
38
|
+
depth: task.depth,
|
|
38
39
|
};
|
|
39
40
|
const actions = [
|
|
40
41
|
(0, taskDetailReducer_1.saveTaskUpdatesToLocalStore)({ taskDetailLocalData, taskId }),
|
|
@@ -828,13 +828,40 @@ const getGroupedTaskIds = (tasks) => {
|
|
|
828
828
|
...initialTaskIdsByDueDate,
|
|
829
829
|
};
|
|
830
830
|
const taskIdsByTags = {};
|
|
831
|
+
// Which parents are actually present in this payload. A subtask is
|
|
832
|
+
// only treated as "nested" (and dropped from the count / groupings)
|
|
833
|
+
// if its parent is in the visible set — otherwise it renders as an
|
|
834
|
+
// orphan top-level row in the UI (SubtaskDetailTable has no parent to
|
|
835
|
+
// attach under) and MUST count. Customer callers routinely see this:
|
|
836
|
+
// the parent is Zeni-internal / private and filtered server-side, but
|
|
837
|
+
// the subtask itself is public and lands in the payload.
|
|
838
|
+
const visibleTaskIds = new Set(tasks.map((t) => t.task_id));
|
|
831
839
|
tasks.forEach((task) => {
|
|
832
|
-
|
|
840
|
+
// A task is a "nested subtask" only when its parent is in the
|
|
841
|
+
// visible payload — otherwise it's an orphan and renders as a
|
|
842
|
+
// top-level row in the UI (customer callers routinely see this:
|
|
843
|
+
// the parent is Zeni-internal / private and filtered server-side,
|
|
844
|
+
// but the subtask itself is public and lands in the payload).
|
|
845
|
+
// Datastore string properties default to '' when unset, so treat
|
|
846
|
+
// empty string as null. Matches the sibling `updateTasks` guard
|
|
847
|
+
// at L719-722.
|
|
848
|
+
const isNestedSubtask = task.parent_task_id != null &&
|
|
849
|
+
task.parent_task_id !== '' &&
|
|
850
|
+
visibleTaskIds.has(task.parent_task_id);
|
|
851
|
+
// Subtasks stay in every groupBy array so the UI can render them
|
|
852
|
+
// nested under their parent (WC's TaskManagementPage builds
|
|
853
|
+
// `subtasksByParentId` from `group.tasks` and then filters them
|
|
854
|
+
// out of top-level rows via `filterOutSubtasks`). Only the flat
|
|
855
|
+
// top-level `taskIds` array — which drives the Active/Completed/…
|
|
856
|
+
// tab counts — must exclude nested subtasks.
|
|
833
857
|
const priorityKey = (0, taskState_1.toPriorityCodeType)(task.priority.code);
|
|
834
858
|
const statusKey = (0, taskState_1.toTaskStatusCodeType)(task.status.code);
|
|
835
859
|
const assigneeKey = getAssigneesGroupKey(task.assignees);
|
|
836
860
|
const dueDateKey = getDueDateGroupKey(task.due_date);
|
|
837
861
|
const tagsKey = getTagsGroupKey(task.tags);
|
|
862
|
+
if (!isNestedSubtask) {
|
|
863
|
+
taskIds.push(task.task_id);
|
|
864
|
+
}
|
|
838
865
|
taskIdsGroupedByPriority[priorityKey] = [
|
|
839
866
|
...taskIdsGroupedByPriority[priorityKey],
|
|
840
867
|
task.task_id,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zeniai/client-epic-state",
|
|
3
|
-
"version": "5.1.
|
|
3
|
+
"version": "5.1.45-betaDI1",
|
|
4
4
|
"description": "Shared module between Web & Mobile containing required abstractions for state management, async network communication. ",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "lib/esm/index.js",
|