@zeniai/client-epic-state 4.19.98 → 4.19.99-beta15ND

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/lib/commonStateTypes/coaBalance/coaBalanceType.d.ts +2 -0
  2. package/lib/commonStateTypes/coaBalance/coaBalanceType.js +6 -0
  3. package/lib/commonStateTypes/currencyHelper.d.ts +3 -0
  4. package/lib/commonStateTypes/currencyHelper.js +6 -1
  5. package/lib/commonStateTypes/reduceFetchState.d.ts +9 -0
  6. package/lib/commonStateTypes/reduceFetchState.js +26 -0
  7. package/lib/entity/account/accountPayload.d.ts +2 -0
  8. package/lib/entity/account/accountPayload.js +2 -0
  9. package/lib/entity/account/accountState.d.ts +2 -0
  10. package/lib/entity/customer/customerState.d.ts +0 -2
  11. package/lib/entity/customer/customerState.js +0 -5
  12. package/lib/entity/depositAccount/depositAccount.d.ts +1 -1
  13. package/lib/entity/depositAccount/depositAccount.js +8 -1
  14. package/lib/entity/reimbursement/reimbursementPayload.d.ts +2 -0
  15. package/lib/entity/reimbursement/reimbursementPayload.js +7 -0
  16. package/lib/entity/reimbursement/reimbursementState.d.ts +2 -0
  17. package/lib/entity/snackbar/snackbarTypes.d.ts +1 -1
  18. package/lib/entity/snackbar/snackbarTypes.js +1 -0
  19. package/lib/entity/task/taskPayload.d.ts +1 -0
  20. package/lib/entity/task/taskPayload.js +1 -0
  21. package/lib/entity/task/taskState.d.ts +1 -0
  22. package/lib/entity/userGroups/userGroupsPayload.d.ts +7 -0
  23. package/lib/entity/userGroups/userGroupsPayload.js +10 -0
  24. package/lib/entity/userGroups/userGroupsReducer.d.ts +8 -0
  25. package/lib/entity/userGroups/userGroupsReducer.js +29 -0
  26. package/lib/entity/userGroups/userGroupsSelector.d.ts +4 -0
  27. package/lib/entity/userGroups/userGroupsSelector.js +12 -0
  28. package/lib/entity/userGroups/userGroupsState.d.ts +9 -0
  29. package/lib/entity/userGroups/userGroupsState.js +2 -0
  30. package/lib/epic.d.ts +12 -1
  31. package/lib/epic.js +12 -1
  32. package/lib/esm/commonStateTypes/coaBalance/coaBalanceType.js +5 -0
  33. package/lib/esm/commonStateTypes/currencyHelper.js +5 -0
  34. package/lib/esm/commonStateTypes/reduceFetchState.js +25 -0
  35. package/lib/esm/entity/account/accountPayload.js +2 -0
  36. package/lib/esm/entity/customer/customerState.js +1 -4
  37. package/lib/esm/entity/depositAccount/depositAccount.js +8 -1
  38. package/lib/esm/entity/reimbursement/reimbursementPayload.js +7 -0
  39. package/lib/esm/entity/snackbar/snackbarTypes.js +1 -0
  40. package/lib/esm/entity/task/taskPayload.js +1 -0
  41. package/lib/esm/entity/userGroups/userGroupsPayload.js +7 -0
  42. package/lib/esm/entity/userGroups/userGroupsReducer.js +25 -0
  43. package/lib/esm/entity/userGroups/userGroupsSelector.js +8 -0
  44. package/lib/esm/entity/userGroups/userGroupsState.js +1 -0
  45. package/lib/esm/epic.js +12 -1
  46. package/lib/esm/index.js +18 -10
  47. package/lib/esm/reducer.js +6 -0
  48. package/lib/esm/view/arAgingView/arAgingReport/arAgingReducer.js +1 -1
  49. package/lib/esm/view/arAgingView/arAgingReport/arAgingSelector.js +1 -1
  50. package/lib/esm/view/expenseAutomationView/bulkUploadTiming.js +10 -0
  51. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.js +29 -0
  52. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/confirmBulkUploadMatchEpic.js +49 -0
  53. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchDetailsEpic.js +40 -0
  54. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchesEpic.js +47 -0
  55. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchCompletedTransactionsEpic.js +61 -0
  56. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic.js +33 -0
  57. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic.js +56 -0
  58. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.js +77 -0
  59. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/uploadMissingReceiptSuccessEpic.js +7 -5
  60. package/lib/esm/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +79 -0
  61. package/lib/esm/view/expenseAutomationView/epics/transactionCategorization/uploadTransactionReceiptSuccessEpic.js +24 -0
  62. package/lib/esm/view/expenseAutomationView/payload/missingReceiptsPayload.js +189 -1
  63. package/lib/esm/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +433 -2
  64. package/lib/esm/view/expenseAutomationView/reducers/transactionsViewReducer.js +23 -1
  65. package/lib/esm/view/expenseAutomationView/selectors/missingReceiptsSelector.js +244 -1
  66. package/lib/esm/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +2 -1
  67. package/lib/esm/view/expenseAutomationView/types/missingReceiptsViewState.js +44 -0
  68. package/lib/esm/view/expenseAutomationView/types/transactionsViewState.js +2 -1
  69. package/lib/esm/view/financeStatement/financeStatementReducer.js +11 -8
  70. package/lib/esm/view/financeStatement/financeStatementSelector.js +24 -9
  71. package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.js +317 -0
  72. package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelectorTypes.js +9 -0
  73. package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesViewReducer.js +6 -1
  74. package/lib/esm/view/profitAndLossClassesView/profitAndLossClassesViewSelector.js +2 -29
  75. package/lib/esm/view/profitAndLossClassesView/profitAndLossForTimeframeClassesViewEpic.js +7 -5
  76. package/lib/esm/view/profitAndLossClassesView/profitAndLossHorizontalEnrichment.js +280 -0
  77. package/lib/esm/view/reportUIOptions/updateReportUIOptionCOABalancesRangeEpic.js +9 -7
  78. package/lib/esm/view/taskManager/taskDetailView/taskDetailSelector.js +1 -1
  79. package/lib/esm/view/taskManager/taskListView/epics/bulkUpdateTaskListEpic.js +1 -0
  80. package/lib/esm/view/taskManager/taskListView/taskListSelector.js +3 -1
  81. package/lib/esm/view/userGroupListView/userGroupListViewReducer.js +65 -0
  82. package/lib/esm/view/userGroupListView/userGroupListViewSelector.js +16 -0
  83. package/lib/esm/view/userGroupListView/userGroupListViewState.js +1 -0
  84. package/lib/esm/view/userListView/fetchUserListByTypeEpic.js +11 -0
  85. package/lib/esm/zeniAPI.js +0 -2
  86. package/lib/index.d.ts +19 -12
  87. package/lib/index.js +81 -23
  88. package/lib/reducer.d.ts +6 -0
  89. package/lib/reducer.js +6 -0
  90. package/lib/tsconfig.typecheck.tsbuildinfo +1 -1
  91. package/lib/view/arAgingView/arAgingReport/arAgingReducer.js +2 -2
  92. package/lib/view/arAgingView/arAgingReport/arAgingSelector.js +5 -5
  93. package/lib/view/expenseAutomationView/bulkUploadTiming.d.ts +10 -0
  94. package/lib/view/expenseAutomationView/bulkUploadTiming.js +13 -0
  95. package/lib/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.d.ts +18 -0
  96. package/lib/view/expenseAutomationView/epics/missingReceipts/bulkUploadReceiptsEpic.js +33 -0
  97. package/lib/view/expenseAutomationView/epics/missingReceipts/confirmBulkUploadMatchEpic.d.ts +7 -0
  98. package/lib/view/expenseAutomationView/epics/missingReceipts/confirmBulkUploadMatchEpic.js +53 -0
  99. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchDetailsEpic.d.ts +8 -0
  100. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchDetailsEpic.js +44 -0
  101. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchesEpic.d.ts +7 -0
  102. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchBulkUploadBatchesEpic.js +51 -0
  103. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchCompletedTransactionsEpic.d.ts +8 -0
  104. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchCompletedTransactionsEpic.js +65 -0
  105. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic.d.ts +8 -0
  106. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchMoreBatchDetailsEpic.js +37 -0
  107. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic.d.ts +9 -0
  108. package/lib/view/expenseAutomationView/epics/missingReceipts/fetchMultipleBatchDetailsEpic.js +61 -0
  109. package/lib/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.d.ts +14 -0
  110. package/lib/view/expenseAutomationView/epics/missingReceipts/searchTransactionsForManualMatchEpic.js +81 -0
  111. package/lib/view/expenseAutomationView/epics/missingReceipts/uploadMissingReceiptSuccessEpic.js +7 -5
  112. package/lib/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.d.ts +25 -0
  113. package/lib/view/expenseAutomationView/epics/missingReceipts/watchBulkUploadBatchStatusEpic.js +85 -0
  114. package/lib/view/expenseAutomationView/epics/transactionCategorization/uploadTransactionReceiptSuccessEpic.d.ts +7 -0
  115. package/lib/view/expenseAutomationView/epics/transactionCategorization/uploadTransactionReceiptSuccessEpic.js +28 -0
  116. package/lib/view/expenseAutomationView/helpers/transactionCategorizationLocalDataHelper.d.ts +1 -1
  117. package/lib/view/expenseAutomationView/payload/missingReceiptsPayload.d.ts +118 -0
  118. package/lib/view/expenseAutomationView/payload/missingReceiptsPayload.js +201 -0
  119. package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.d.ts +76 -3
  120. package/lib/view/expenseAutomationView/reducers/missingReceiptsViewReducer.js +434 -2
  121. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.d.ts +11 -3
  122. package/lib/view/expenseAutomationView/reducers/transactionsViewReducer.js +24 -2
  123. package/lib/view/expenseAutomationView/selectorTypes/missingReceiptsSelectorTypes.d.ts +69 -1
  124. package/lib/view/expenseAutomationView/selectorTypes/transactionsViewSelectorTypes.d.ts +1 -0
  125. package/lib/view/expenseAutomationView/selectors/missingReceiptsSelector.d.ts +1 -1
  126. package/lib/view/expenseAutomationView/selectors/missingReceiptsSelector.js +243 -0
  127. package/lib/view/expenseAutomationView/selectors/transactionCategorizationSelector.js +2 -1
  128. package/lib/view/expenseAutomationView/types/missingReceiptsViewState.d.ts +142 -0
  129. package/lib/view/expenseAutomationView/types/missingReceiptsViewState.js +54 -1
  130. package/lib/view/expenseAutomationView/types/transactionsViewState.d.ts +2 -1
  131. package/lib/view/expenseAutomationView/types/transactionsViewState.js +2 -1
  132. package/lib/view/financeStatement/financeStatementReducer.js +11 -8
  133. package/lib/view/financeStatement/financeStatementSelector.d.ts +2 -0
  134. package/lib/view/financeStatement/financeStatementSelector.js +24 -9
  135. package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.d.ts +13 -0
  136. package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelector.js +321 -0
  137. package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelectorTypes.d.ts +111 -0
  138. package/lib/view/profitAndLossClassesView/profitAndLossClassesByClassHorizontalSelectorTypes.js +13 -0
  139. package/lib/view/profitAndLossClassesView/profitAndLossClassesViewReducer.d.ts +4 -2
  140. package/lib/view/profitAndLossClassesView/profitAndLossClassesViewReducer.js +7 -2
  141. package/lib/view/profitAndLossClassesView/profitAndLossClassesViewSelector.js +2 -29
  142. package/lib/view/profitAndLossClassesView/profitAndLossClassesViewState.d.ts +4 -0
  143. package/lib/view/profitAndLossClassesView/profitAndLossForTimeframeClassesViewEpic.js +7 -5
  144. package/lib/view/profitAndLossClassesView/profitAndLossHorizontalEnrichment.d.ts +6 -0
  145. package/lib/view/profitAndLossClassesView/profitAndLossHorizontalEnrichment.js +283 -0
  146. package/lib/view/reportUIOptions/updateReportUIOptionCOABalancesRangeEpic.js +8 -6
  147. package/lib/view/taskManager/taskDetailView/taskDetailSelector.js +1 -1
  148. package/lib/view/taskManager/taskListView/epics/bulkUpdateTaskListEpic.d.ts +1 -0
  149. package/lib/view/taskManager/taskListView/epics/bulkUpdateTaskListEpic.js +1 -0
  150. package/lib/view/taskManager/taskListView/taskListSelector.d.ts +2 -0
  151. package/lib/view/taskManager/taskListView/taskListSelector.js +3 -1
  152. package/lib/view/userGroupListView/userGroupListViewReducer.d.ts +23 -0
  153. package/lib/view/userGroupListView/userGroupListViewReducer.js +69 -0
  154. package/lib/view/userGroupListView/userGroupListViewSelector.d.ts +7 -0
  155. package/lib/view/userGroupListView/userGroupListViewSelector.js +20 -0
  156. package/lib/view/userGroupListView/userGroupListViewState.d.ts +8 -0
  157. package/lib/view/userGroupListView/userGroupListViewState.js +2 -0
  158. package/lib/view/userListView/fetchUserListByTypeEpic.d.ts +3 -1
  159. package/lib/view/userListView/fetchUserListByTypeEpic.js +11 -0
  160. package/lib/view/userListView/userListViewPayload.d.ts +2 -0
  161. package/lib/zeniAPI.js +0 -2
  162. package/package.json +2 -2
@@ -0,0 +1,280 @@
1
+ import { defaultCustomerCurrency } from '../../commonStateTypes/currencyHelper';
2
+ import { HORIZONTAL_CLASS_TOTAL_BALANCE_ID, } from './profitAndLossClassesByClassHorizontalSelectorTypes';
3
+ /**
4
+ * Populates `sectionHeaderBalancesSlice`, and per-account `accountReportData`, so the
5
+ * web layer only maps selector output to tree nodes.
6
+ */
7
+ export function enrichProfitAndLossByClassHorizontalReport(report) {
8
+ if (report.fetchState !== 'Completed' || report.selectedPeriod == null) {
9
+ return;
10
+ }
11
+ for (const section of Object.values(report.sections)) {
12
+ if (section != null) {
13
+ enrichHorizontalSection(report, section);
14
+ }
15
+ }
16
+ for (const calc of Object.values(report.calculatedSections)) {
17
+ if (calc != null) {
18
+ enrichHorizontalCalculatedSection(report, calc);
19
+ }
20
+ }
21
+ }
22
+ function enrichHorizontalSection(report, section) {
23
+ const classAmounts = report.classColumns.map((col) => {
24
+ const total = section.classTotals.find((ct) => ct.classId === col.classId);
25
+ return total?.balance.amount ?? 0;
26
+ });
27
+ section.sectionHeaderBalancesSlice = buildHorizontalClassColumnBalancesSlice(report, classAmounts, section.sectionTotal.amount);
28
+ const parentIndices = computeHorizontalAccountParentIndices(section.accounts);
29
+ const childrenRowIndicesByParent = buildHorizontalAccountChildIndicesByParent(parentIndices);
30
+ const childrenRecord = {};
31
+ childrenRowIndicesByParent.forEach((childIndices, parentIndex) => {
32
+ childrenRecord[parentIndex] = childIndices;
33
+ });
34
+ section.treeLayout = {
35
+ rootAccountRowIndices: section.accounts
36
+ .map((_, i) => (parentIndices[i] === -1 ? i : -1))
37
+ .filter((i) => i >= 0),
38
+ childrenRowIndicesByParent: childrenRecord,
39
+ };
40
+ const siblingsPerRow = buildSiblingIndicesPerRow(section.accounts, parentIndices);
41
+ const hasChildFlags = computeHorizontalHasChildFlags(parentIndices);
42
+ for (let i = 0; i < section.accounts.length; i++) {
43
+ const row = section.accounts[i];
44
+ const classBalanceByClassId = new Map(row.classBalances.map((b) => [b.classId, b.balance.amount]));
45
+ const classRowAmounts = report.classColumns.map((col) => classBalanceByClassId.get(col.classId) ?? 0);
46
+ row.accountReportData = {
47
+ accountId: row.accountId,
48
+ accountName: row.accountName,
49
+ accountType: row.accountType,
50
+ depth: row.depth,
51
+ balancesInTimeframe: buildHorizontalClassColumnBalancesSlice(report, classRowAmounts, row.rowTotal.amount),
52
+ horizontalTreeView: buildHorizontalTreeViewFromPrecomputed(section.accounts, i, parentIndices, siblingsPerRow, hasChildFlags),
53
+ };
54
+ }
55
+ }
56
+ function enrichHorizontalCalculatedSection(report, calcSection) {
57
+ const classAmounts = report.classColumns.map((col) => {
58
+ const total = calcSection.classTotals.find((ct) => ct.classId === col.classId);
59
+ return total?.balance.amount ?? 0;
60
+ });
61
+ calcSection.sectionHeaderBalancesSlice =
62
+ buildHorizontalClassColumnBalancesSlice(report, classAmounts, calcSection.sectionTotal.amount);
63
+ }
64
+ function buildHorizontalClassColumnBalancesSlice(report, classAmounts, totalAmount) {
65
+ const fallback = defaultCustomerCurrency;
66
+ const firstHeader = report.headerBalances[0];
67
+ const currencyCode = firstHeader?.balance.currencyCode ?? fallback.currencyCode;
68
+ const currencySymbol = firstHeader?.balance.currencySymbol ?? fallback.currencySymbol;
69
+ const timeframe = firstHeader?.balanceTimeFrame ?? 'month';
70
+ const emptySlice = {
71
+ balances: [],
72
+ additionalBalances: [],
73
+ filter: {
74
+ firstMonthOfFY: report.firstMonthOfFY,
75
+ timeframe,
76
+ balancesRange: { numberOfPeriods: 0, orderBy: 'ascending_date' },
77
+ additionalBalances: [],
78
+ },
79
+ };
80
+ if (report.selectedPeriod == null) {
81
+ return emptySlice;
82
+ }
83
+ const { startDate, endDate } = report.selectedPeriod;
84
+ const balances = report.classColumns.map((col, i) => ({
85
+ balance: {
86
+ amount: classAmounts[i] ?? 0,
87
+ currencyCode,
88
+ currencySymbol,
89
+ },
90
+ balanceTimeFrame: timeframe,
91
+ startDate,
92
+ endDate,
93
+ type: 'default',
94
+ id: col.classId,
95
+ label: col.className,
96
+ }));
97
+ balances.push({
98
+ balance: {
99
+ amount: totalAmount,
100
+ currencyCode,
101
+ currencySymbol,
102
+ },
103
+ balanceTimeFrame: timeframe,
104
+ startDate,
105
+ endDate,
106
+ type: 'default',
107
+ id: HORIZONTAL_CLASS_TOTAL_BALANCE_ID,
108
+ label: 'Total',
109
+ });
110
+ return {
111
+ balances,
112
+ additionalBalances: [],
113
+ filter: {
114
+ firstMonthOfFY: report.firstMonthOfFY,
115
+ timeframe,
116
+ balancesRange: {
117
+ numberOfPeriods: balances.length,
118
+ orderBy: 'ascending_date',
119
+ },
120
+ additionalBalances: [],
121
+ },
122
+ };
123
+ }
124
+ /**
125
+ * Parent index per DFS row — O(n). Matches the scan in the former
126
+ * `findHorizontalAccountParentIndex` (depth &lt;= 2 rows have no parent).
127
+ */
128
+ function computeHorizontalAccountParentIndices(rows) {
129
+ const n = rows.length;
130
+ const parentIndex = new Array(n).fill(-1);
131
+ const stack = [];
132
+ for (let i = 0; i < n; i++) {
133
+ const row = rows[i];
134
+ if (row === undefined) {
135
+ continue;
136
+ }
137
+ const d = row.depth;
138
+ while (stack.length > 0) {
139
+ const topIdx = stack[stack.length - 1];
140
+ if (topIdx === undefined) {
141
+ break;
142
+ }
143
+ const topRow = rows[topIdx];
144
+ if (topRow === undefined) {
145
+ stack.pop();
146
+ continue;
147
+ }
148
+ if (topRow.depth < d) {
149
+ break;
150
+ }
151
+ stack.pop();
152
+ }
153
+ if (d <= 2) {
154
+ parentIndex[i] = -1;
155
+ }
156
+ else if (stack.length === 0) {
157
+ parentIndex[i] = -1;
158
+ }
159
+ else {
160
+ const peek = stack[stack.length - 1];
161
+ if (peek === undefined) {
162
+ parentIndex[i] = -1;
163
+ }
164
+ else {
165
+ const parentRow = rows[peek];
166
+ parentIndex[i] =
167
+ parentRow !== undefined && parentRow.depth === d - 1 ? peek : -1;
168
+ }
169
+ }
170
+ stack.push(i);
171
+ }
172
+ return parentIndex;
173
+ }
174
+ /** Sibling row indices (same parent + depth), in traversal order — O(n). */
175
+ function buildSiblingIndicesPerRow(rows, parentIndices) {
176
+ const n = rows.length;
177
+ const keyToIndices = new Map();
178
+ for (let j = 0; j < n; j++) {
179
+ const p = parentIndices[j];
180
+ const row = rows[j];
181
+ if (p === undefined || row === undefined) {
182
+ continue;
183
+ }
184
+ const key = `${p}:${row.depth}`;
185
+ let g = keyToIndices.get(key);
186
+ if (g === undefined) {
187
+ g = [];
188
+ keyToIndices.set(key, g);
189
+ }
190
+ g.push(j);
191
+ }
192
+ const siblingsPerRow = new Array(n);
193
+ for (let j = 0; j < n; j++) {
194
+ const p = parentIndices[j];
195
+ const row = rows[j];
196
+ if (p === undefined || row === undefined) {
197
+ siblingsPerRow[j] = [j];
198
+ continue;
199
+ }
200
+ const key = `${p}:${row.depth}`;
201
+ const group = keyToIndices.get(key);
202
+ siblingsPerRow[j] = group !== undefined ? group : [j];
203
+ }
204
+ return siblingsPerRow;
205
+ }
206
+ function computeHorizontalHasChildFlags(parentIndices) {
207
+ const n = parentIndices.length;
208
+ const flags = new Array(n).fill(false);
209
+ for (let j = 0; j < n; j++) {
210
+ const p = parentIndices[j];
211
+ if (p !== undefined && p >= 0 && p < n) {
212
+ flags[p] = true;
213
+ }
214
+ }
215
+ return flags;
216
+ }
217
+ function buildHorizontalSubAccountAncestorMetadataFromPrecomputed(dfsOrderedAccountRows, currentRowIndex, parentIndices, siblingsPerRow, hasChildFlags) {
218
+ const chain = [];
219
+ let w = currentRowIndex;
220
+ while (w >= 0) {
221
+ chain.unshift(w);
222
+ const next = parentIndices[w];
223
+ if (next === undefined) {
224
+ break;
225
+ }
226
+ w = next;
227
+ }
228
+ return chain.map((rowIndex) => {
229
+ const row = dfsOrderedAccountRows[rowIndex];
230
+ const siblingIndices = siblingsPerRow[rowIndex];
231
+ const hasChild = hasChildFlags[rowIndex];
232
+ if (row === undefined || siblingIndices === undefined) {
233
+ return {
234
+ depth: 0,
235
+ hasSibling: false,
236
+ hasChildren: hasChild === true,
237
+ isLastNode: true,
238
+ name: '',
239
+ };
240
+ }
241
+ return {
242
+ depth: row.depth - 2,
243
+ hasSibling: siblingIndices.length > 1,
244
+ hasChildren: hasChild === true,
245
+ isLastNode: rowIndex === siblingIndices[siblingIndices.length - 1],
246
+ name: row.accountName,
247
+ };
248
+ });
249
+ }
250
+ function buildHorizontalTreeViewFromPrecomputed(dfsOrderedAccountRows, currentRowIndex, parentIndices, siblingsPerRow, hasChildFlags) {
251
+ const siblingIndices = siblingsPerRow[currentRowIndex];
252
+ const row = dfsOrderedAccountRows[currentRowIndex];
253
+ const hasChildrenFlag = hasChildFlags[currentRowIndex];
254
+ const treeDepth = row !== undefined ? Math.max(0, row.depth - 2) : 0;
255
+ const hasChildren = hasChildrenFlag === true;
256
+ const sibs = siblingIndices ?? [currentRowIndex];
257
+ return {
258
+ subAccountAncestorMetadata: buildHorizontalSubAccountAncestorMetadataFromPrecomputed(dfsOrderedAccountRows, currentRowIndex, parentIndices, siblingsPerRow, hasChildFlags),
259
+ treeDepth,
260
+ hasChildren,
261
+ hasSiblings: sibs.length > 1,
262
+ isLeaf: !hasChildren,
263
+ isLastNode: currentRowIndex === sibs[sibs.length - 1],
264
+ };
265
+ }
266
+ function buildHorizontalAccountChildIndicesByParent(parentIndices) {
267
+ const childIndicesByParentRowIndex = new Map();
268
+ for (let rowIndex = 0; rowIndex < parentIndices.length; rowIndex++) {
269
+ const parentRowIndex = parentIndices[rowIndex];
270
+ if (parentRowIndex !== undefined && parentRowIndex >= 0) {
271
+ let childRowIndices = childIndicesByParentRowIndex.get(parentRowIndex);
272
+ if (childRowIndices === undefined) {
273
+ childRowIndices = [];
274
+ childIndicesByParentRowIndex.set(parentRowIndex, childRowIndices);
275
+ }
276
+ childRowIndices.push(rowIndex);
277
+ }
278
+ }
279
+ return childIndicesByParentRowIndex;
280
+ }
@@ -2,15 +2,19 @@ import { of } from 'rxjs';
2
2
  import { filter, switchMap } from 'rxjs/operators';
3
3
  import { updateCashInCashOutCOABalancesRange } from '../cashInCashOut/cashInCashOutReducer';
4
4
  import { updateCashPositionCOABalancesRange } from '../cashPosition/cashPositionReducer';
5
- import { initialFinanceStatementState, updateCOABalancesRange, } from '../financeStatement/financeStatementReducer';
5
+ import { updateCOABalancesRange } from '../financeStatement/financeStatementReducer';
6
6
  import { updateNetBurnOrIncomeCOABalancesRange } from '../netBurnOrIncome/netBurnOrIncomeReducer';
7
7
  import { updateOpExCOABalancesRange } from '../opEx/opExReducer';
8
8
  import { updateRevenueCOABalancesRange } from '../revenue/revenueReducer';
9
9
  import { updateReportUIOptionCOABalancesRange } from './reportUIOptionsReducer';
10
10
  export const updateReportUIOptionCOABalancesRangeEpic = (actions$, state$) => actions$.pipe(filter(updateReportUIOptionCOABalancesRange.match), switchMap((action) => {
11
- const thisPeriod = action.payload.selectedCOABalancesRange.thisPeriod;
12
- const orderBy = action.payload.selectedCOABalancesRange.orderBy;
13
- const highlightedNoOfPeriods = state$.value.reportUIOptionsState.isCompareModeOn === true ? 4 : 1;
11
+ const selectedRange = action.payload.selectedCOABalancesRange;
12
+ const thisPeriod = selectedRange.thisPeriod;
13
+ const orderBy = selectedRange.orderBy;
14
+ const numberOfPeriodsFromSelection = selectedRange.numberOfPeriods;
15
+ const highlightedNoOfPeriods = state$.value.reportUIOptionsState.isCompareModeOn === true
16
+ ? numberOfPeriodsFromSelection
17
+ : 1;
14
18
  const highlightedCOABalancesRange = action.payload.highlightedCOABalancesRange == null && thisPeriod != null
15
19
  ? {
16
20
  numberOfPeriods: highlightedNoOfPeriods,
@@ -62,9 +66,7 @@ export const updateReportUIOptionCOABalancesRangeEpic = (actions$, state$) => ac
62
66
  thisPeriod: action.payload.highlightedCOABalancesRange != null
63
67
  ? action.payload.highlightedCOABalancesRange.thisPeriod
64
68
  : thisPeriod,
65
- numberOfPeriods: state$.value.reportUIOptionsState.isCompareModeOn === true
66
- ? 4
67
- : initialFinanceStatementState.maxNumOfPeriodsToHighlight,
69
+ numberOfPeriods: numberOfPeriodsFromSelection,
68
70
  orderBy,
69
71
  }));
70
72
  }));
@@ -109,7 +109,7 @@ export const allTaskPriority = [
109
109
  },
110
110
  {
111
111
  code: 'medium',
112
- name: 'Normal',
112
+ name: 'Medium',
113
113
  },
114
114
  {
115
115
  code: 'low',
@@ -70,6 +70,7 @@ const toTaskPayload = (state, task) => {
70
70
  name: task.name,
71
71
  assignees: task.assignees,
72
72
  description: task.description,
73
+ group_assignees: task.groupAssignees,
73
74
  due_date: task.dueDate != null ? task.dueDate.format(DEFAULT_DATE_FORMAT) : null,
74
75
  priority: task.priority.code,
75
76
  status: task.status.code,
@@ -11,6 +11,7 @@ import { getTaskGroupTemplateByIds } from '../../../entity/taskGroupTemplate/tas
11
11
  import { getUserName, getUsersByUserIds, } from '../../../entity/user/userSelector';
12
12
  import { getUserAndUserRole, } from '../../companyView/types/userAndRole';
13
13
  import { applyAdvancedFiltersOnList } from '../../spendManagement/spendManagementFilterHelpers';
14
+ import { getUserGroupList } from '../../userGroupListView/userGroupListViewSelector';
14
15
  import { getUserList, } from '../../userListView/userListViewSelector';
15
16
  import { allTaskPriority, allTaskStatus, } from '../taskDetailView/taskDetailSelector';
16
17
  import { DUE_DATE_GROUP_KEYS, } from './taskList';
@@ -308,7 +309,7 @@ const getTaskGroupsWithTaskList = ({ taskListState, taskState, userState, userRo
308
309
  tagState,
309
310
  });
310
311
  };
311
- export const getAllTasks = createSelector((state) => state.taskListState, (state) => state.taskState, (state) => state.userState, (state) => state.userRoleState, (state) => state.userListViewState, (state) => state.addressState, (state) => state.taskGroupState, (state) => state.taskGroupViewState, (state) => state.tagViewState, (state) => state.tagState, (state) => state.taskGroupTemplateState, (state) => state.taskGroupTemplateViewState, (_state, isTaskTemplatesEnabled) => isTaskTemplatesEnabled, (taskListState, taskState, userState, userRoleState, userListViewState, addressState, taskGroupState, taskGroupViewState, tagViewState, tagState, taskGroupTemplateState, taskGroupTemplateViewState, isTaskTemplatesEnabled) => {
312
+ export const getAllTasks = createSelector((state) => state.taskListState, (state) => state.taskState, (state) => state.userState, (state) => state.userRoleState, (state) => state.userListViewState, (state) => state.addressState, (state) => state.taskGroupState, (state) => state.taskGroupViewState, (state) => state.tagViewState, (state) => state.tagState, (state) => state.taskGroupTemplateState, (state) => state.taskGroupTemplateViewState, (state) => state.userGroupsState, (state) => state.userGroupListViewState, (_state, isTaskTemplatesEnabled) => isTaskTemplatesEnabled, (taskListState, taskState, userState, userRoleState, userListViewState, addressState, taskGroupState, taskGroupViewState, tagViewState, tagState, taskGroupTemplateState, taskGroupTemplateViewState, userGroupsState, userGroupListViewState, isTaskTemplatesEnabled) => {
312
313
  const { localData } = taskListState;
313
314
  const taskGroupsWithTasksList = getTaskGroupsWithTaskList({
314
315
  taskListState,
@@ -336,6 +337,7 @@ export const getAllTasks = createSelector((state) => state.taskListState, (state
336
337
  taskGroupTemplates,
337
338
  fetchState: fetchState,
338
339
  userList: getUserList(userState, userRoleState, userListViewState, 'taskManagerCandidate'),
340
+ userGroupList: getUserGroupList(userGroupsState, userGroupListViewState, 'taskManagerCandidate'),
339
341
  error: error,
340
342
  version: 0,
341
343
  taskGroupsWithTasksList,
@@ -0,0 +1,65 @@
1
+ import { createSlice } from '@reduxjs/toolkit';
2
+ const initialUserGroupList = {
3
+ ids: [],
4
+ fetchState: 'Not-Started',
5
+ error: undefined,
6
+ hasValidState() {
7
+ return this.fetchState == 'Completed';
8
+ },
9
+ };
10
+ export const initialState = {
11
+ userGroupListByType: {
12
+ taskManagerCandidate: initialUserGroupList,
13
+ },
14
+ };
15
+ const userGroupListView = createSlice({
16
+ name: 'userGroupListView',
17
+ initialState,
18
+ reducers: {
19
+ fetchUserGroupListByType: {
20
+ reducer(draft, action) {
21
+ const { userGroupType } = action.payload;
22
+ draft.userGroupListByType[userGroupType].fetchState = 'In-Progress';
23
+ draft.userGroupListByType[userGroupType].error = undefined;
24
+ },
25
+ prepare(userGroupType, cacheOverride = false) {
26
+ return {
27
+ payload: {
28
+ userGroupType,
29
+ cacheOverride,
30
+ },
31
+ };
32
+ },
33
+ },
34
+ updateUserGroupIds(draft, action) {
35
+ const { userGroupType, userGroupsPayload } = action.payload;
36
+ draft.userGroupListByType[userGroupType].fetchState = 'Completed';
37
+ draft.userGroupListByType[userGroupType].error = undefined;
38
+ draft.userGroupListByType[userGroupType].ids = userGroupsPayload.map((userGroup) => userGroup.id);
39
+ },
40
+ addUserGroupId(draft, action) {
41
+ const { userGroupType, id } = action.payload;
42
+ const index = draft.userGroupListByType[userGroupType].ids.indexOf(id);
43
+ if (index < 0) {
44
+ draft.userGroupListByType[userGroupType].ids.push(id);
45
+ }
46
+ },
47
+ removeUserGroupId(draft, action) {
48
+ const { userGroupType, id } = action.payload;
49
+ const index = draft.userGroupListByType[userGroupType].ids.indexOf(id);
50
+ if (index > -1) {
51
+ draft.userGroupListByType[userGroupType].ids.splice(index, 1);
52
+ }
53
+ },
54
+ updateUserGroupListFetchFailure(draft, action) {
55
+ const { userGroupType, status } = action.payload;
56
+ draft.userGroupListByType[userGroupType].fetchState = 'Error';
57
+ draft.userGroupListByType[userGroupType].error = status;
58
+ },
59
+ clearUserGroupListView(draft) {
60
+ Object.assign(draft, initialState);
61
+ },
62
+ },
63
+ });
64
+ export const { fetchUserGroupListByType, updateUserGroupIds, addUserGroupId, removeUserGroupId, updateUserGroupListFetchFailure, clearUserGroupListView, } = userGroupListView.actions;
65
+ export default userGroupListView.reducer;
@@ -0,0 +1,16 @@
1
+ import { getUserGroupByUserGroupId } from '../../entity/userGroups/userGroupsSelector';
2
+ export const getUserGroupList = (userGroupsState, userGroupListViewState, userGroupType) => {
3
+ const listState = userGroupListViewState.userGroupListByType[userGroupType];
4
+ return {
5
+ userGroups: getUserGroupListByIds(userGroupsState, userGroupListViewState, userGroupType),
6
+ fetchState: listState?.fetchState,
7
+ error: listState?.error,
8
+ version: 0,
9
+ };
10
+ };
11
+ function getUserGroupListByIds(userGroupsState, userGroupListViewState, type) {
12
+ const userGroupIds = userGroupListViewState.userGroupListByType[type].ids;
13
+ return userGroupIds
14
+ .map((id) => getUserGroupByUserGroupId(userGroupsState, id))
15
+ .filter((value) => value != null);
16
+ }
@@ -3,9 +3,11 @@ import { catchError, filter, mergeMap } from 'rxjs/operators';
3
3
  import { updateAddresses } from '../../entity/address/addressReducer';
4
4
  import { getCurrentTenant, isZeniDomainTenant, } from '../../entity/tenant/tenantSelector';
5
5
  import { updateAllUsers } from '../../entity/user/userReducer';
6
+ import { updateAllUserGroups } from '../../entity/userGroups/userGroupsReducer';
6
7
  import { updateUserRoles } from '../../entity/userRole/userRoleReducer';
7
8
  import { createZeniAPIStatus, isSuccessResponse } from '../../responsePayload';
8
9
  import { updateChargeCardCount, updateDebitCardCount, } from '../spendManagement/chargeCards/issueChargeCard/issueChargeCardReducer';
10
+ import { updateUserGroupIds } from '../userGroupListView/userGroupListViewReducer';
9
11
  import { fetchUserListByType, updateUserIds, updateUserListFetchFailure, } from './userListViewReducer';
10
12
  export const fetchUserListByTypeEpic = (actions$, state$, zeniAPI) => actions$.pipe(filter(fetchUserListByType.match), mergeMap((action) => {
11
13
  const { userType, cacheOverride } = action.payload;
@@ -29,6 +31,15 @@ export const fetchUserListByTypeEpic = (actions$, state$, zeniAPI) => actions$.p
29
31
  usersPayload: response.data?.users ?? [],
30
32
  }),
31
33
  ];
34
+ if (response.data?.user_groups != null) {
35
+ userListAction.push(updateAllUserGroups({ userGroups: response.data.user_groups }));
36
+ if (userType === 'taskManagerCandidate') {
37
+ userListAction.push(updateUserGroupIds({
38
+ userGroupType: userType,
39
+ userGroupsPayload: response.data.user_groups,
40
+ }));
41
+ }
42
+ }
32
43
  if (userType === 'cardHolderCandidate') {
33
44
  userListAction.push(updateChargeCardCount(response.data?.cards_count_by_user_id ?? []));
34
45
  userListAction.push(updateDebitCardCount(response.data?.debit_cards_count_by_deposit_account_id ?? {}));
@@ -79,8 +79,6 @@ export class ZeniAPIClient {
79
79
  return from(promise);
80
80
  }
81
81
  postFormData(restEndPoint, formData, signal) {
82
- // Use apiHeaders for auth headers, then remove Content-Type
83
- // so the browser sets multipart/form-data with the correct boundary
84
82
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
85
83
  const { 'Content-Type': _contentType, ...headers } = this.apiHeaders();
86
84
  const promise = fetch(restEndPoint, {