@uxland/primary-shell 5.3.8 → 5.3.10
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/dist/index.js +1896 -1893
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +26 -26
- package/dist/index.umd.cjs.map +1 -1
- package/dist/primary/shell/src/internal-plugins/activity-history/activity-history-item/domain/validation/is-valid-basic-history-item.d.ts +5 -0
- package/dist/primary/shell/src/internal-plugins/activity-history/activity-history-item/domain/validation/is-valid-full-history-item.d.ts +5 -0
- package/dist/primary/shell/src/internal-plugins/activity-history/activity-history-item/domain/validation/is-valid-full-history-item.test.d.ts +1 -0
- package/dist/primary/shell/src/internal-plugins/activity-history/utils/get-unique-values-by-prop-path.d.ts +1 -1
- package/package.json +1 -1
- package/src/UI/components/primaria-shell/shell-header/styles.css +1 -0
- package/src/UI/internal-views/upper-nav-views.ts +0 -8
- package/src/internal-plugins/activity-history/activity-history-item/add/add-history-item/handler.ts +2 -2
- package/src/internal-plugins/activity-history/activity-history-item/add/add-history-items/handler.ts +2 -2
- package/src/internal-plugins/activity-history/activity-history-item/domain/business-rules.ts +2 -2
- package/src/internal-plugins/activity-history/activity-history-item/domain/validation/is-valid-basic-history-item.test.ts +63 -0
- package/src/internal-plugins/activity-history/activity-history-item/domain/validation/is-valid-basic-history-item.ts +43 -0
- package/src/internal-plugins/activity-history/activity-history-item/domain/{is-valid-history-item/is-valid-history-item.test.ts → validation/is-valid-full-history-item.test.ts} +11 -11
- package/src/internal-plugins/activity-history/activity-history-item/domain/{is-valid-history-item/is-valid-history-item.ts → validation/is-valid-full-history-item.ts} +7 -8
- package/src/internal-plugins/activity-history/activity-history-item/filter/diagnostic-filters/handle-add-diagnostics-options-from-item.ts +1 -0
- package/src/internal-plugins/activity-history/activity-history-item/list/UI/timeline/template.ts +22 -12
- package/src/internal-plugins/activity-history/activity-history-item/list/group-history-items/group-history-items.test.ts +71 -215
- package/src/internal-plugins/activity-history/activity-history-item/list/group-history-items/group-history-items.ts +26 -3
- package/src/internal-plugins/activity-history/activity-history-item/selectors.ts +1 -0
- package/src/internal-plugins/activity-history/activity-history-item/update/handler.ts +2 -2
- package/src/internal-plugins/activity-history/utils/get-unique-values-by-prop-path.test.ts +55 -30
- package/src/internal-plugins/activity-history/utils/get-unique-values-by-prop-path.ts +30 -10
- package/dist/primary/shell/src/internal-plugins/activity-history/activity-history-item/domain/is-valid-history-item/is-valid-history-item.d.ts +0 -5
- /package/dist/primary/shell/src/internal-plugins/activity-history/activity-history-item/domain/{is-valid-history-item/is-valid-history-item.test.d.ts → validation/is-valid-basic-history-item.test.d.ts} +0 -0
|
@@ -1,238 +1,94 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { groupActivityHistoryItems } from "./group-history-items";
|
|
3
2
|
import { IActivityHistoryItem } from "../../domain/model";
|
|
3
|
+
import { groupActivityHistoryItems } from "./group-history-items";
|
|
4
|
+
|
|
5
|
+
const baseItem = (overrides: Partial<IActivityHistoryItem>): IActivityHistoryItem => ({
|
|
6
|
+
id: "1",
|
|
7
|
+
date: new Date().toISOString(),
|
|
8
|
+
professional: { id: "p1", role: { id: "r1" }, speciality: { id: "s1" } },
|
|
9
|
+
ep: { id: "ep1" },
|
|
10
|
+
up: { id: "up1" },
|
|
11
|
+
center: { id: "c1" },
|
|
12
|
+
service: { id: "sv1" },
|
|
13
|
+
diagnostics: [],
|
|
14
|
+
...overrides,
|
|
15
|
+
});
|
|
16
|
+
|
|
4
17
|
describe("groupActivityHistoryItems", () => {
|
|
5
|
-
it("
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
professional: {
|
|
11
|
-
name: "1",
|
|
12
|
-
id: "1",
|
|
13
|
-
role: { id: "1", description: "1" },
|
|
14
|
-
speciality: { id: "1", description: "1" },
|
|
15
|
-
},
|
|
16
|
-
relevant: true,
|
|
17
|
-
diagnostics: [{ id: "d1", description: "d1" }],
|
|
18
|
-
center: { id: "c1", description: "c1" },
|
|
19
|
-
up: { id: "up1", description: "up1" },
|
|
20
|
-
ep: { id: "ep1", description: "ep1" },
|
|
21
|
-
service: { id: "s1", description: "s1" },
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
id: "2",
|
|
25
|
-
date: "2024-07-04T10:00:00Z",
|
|
26
|
-
professional: {
|
|
27
|
-
name: "1",
|
|
28
|
-
id: "1",
|
|
29
|
-
role: { id: "1", description: "1" },
|
|
30
|
-
speciality: { id: "1", description: "1" },
|
|
31
|
-
},
|
|
32
|
-
relevant: true,
|
|
33
|
-
diagnostics: [{ id: "d1", description: "d1" }],
|
|
34
|
-
center: { id: "c1", description: "c1" },
|
|
35
|
-
up: { id: "up1", description: "up1" },
|
|
36
|
-
ep: { id: "ep1", description: "ep1" },
|
|
37
|
-
service: { id: "s1", description: "s1" },
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
id: "3",
|
|
41
|
-
date: "2024-07-04T08:00:00Z",
|
|
42
|
-
professional: {
|
|
43
|
-
name: "1",
|
|
44
|
-
id: "2",
|
|
45
|
-
role: { id: "2", description: "2" },
|
|
46
|
-
speciality: { id: "2", description: "2" },
|
|
47
|
-
},
|
|
48
|
-
relevant: true,
|
|
49
|
-
diagnostics: [{ id: "d2", description: "d2" }],
|
|
50
|
-
center: { id: "c2", description: "c2" },
|
|
51
|
-
up: { id: "up2", description: "up2" },
|
|
52
|
-
ep: { id: "ep2", description: "ep2" },
|
|
53
|
-
service: { id: "s2", description: "s2" },
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
id: "4",
|
|
57
|
-
date: "2024-07-04T08:00:00Z",
|
|
58
|
-
professional: {
|
|
59
|
-
name: "1",
|
|
60
|
-
id: "1",
|
|
61
|
-
role: { id: "1", description: "1" },
|
|
62
|
-
speciality: { id: "1", description: "1" },
|
|
63
|
-
},
|
|
64
|
-
relevant: true,
|
|
65
|
-
diagnostics: [],
|
|
66
|
-
center: { id: "c1", description: "c1" },
|
|
67
|
-
up: { id: "up1", description: "up1" },
|
|
68
|
-
ep: { id: "ep1", description: "ep1" },
|
|
69
|
-
service: { id: "s1", description: "s1" },
|
|
70
|
-
},
|
|
18
|
+
it("agrupa en un solo grupo por misma visita y dentro de 8h", () => {
|
|
19
|
+
const now = new Date();
|
|
20
|
+
const items = [
|
|
21
|
+
baseItem({ id: "1", date: now.toISOString() }),
|
|
22
|
+
baseItem({ id: "2", date: new Date(now.getTime() + 2 * 3600 * 1000).toISOString() }),
|
|
71
23
|
];
|
|
72
24
|
|
|
73
25
|
const result = groupActivityHistoryItems(items);
|
|
74
26
|
|
|
75
|
-
expect(result
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const group2 = result.find((g) =>
|
|
79
|
-
g.subGroups?.some((sg) => sg.items.some((i) => i.id === "3")),
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
expect(group1).toBeDefined();
|
|
83
|
-
expect(group2).toBeDefined();
|
|
84
|
-
|
|
85
|
-
if (group1) {
|
|
86
|
-
expect(group1.items.length).toBe(1); // Only item with no diagnostics should be here
|
|
87
|
-
expect(group1.items[0].id).toBe("4");
|
|
88
|
-
|
|
89
|
-
expect(group1.subGroups?.length).toBe(1);
|
|
90
|
-
const subGroup1 = group1.subGroups?.[0];
|
|
91
|
-
expect(subGroup1?.items.length).toBe(2);
|
|
92
|
-
expect(subGroup1?.items.some((i) => i.id === "1")).toBe(true);
|
|
93
|
-
expect(subGroup1?.items.some((i) => i.id === "2")).toBe(true);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (group2) {
|
|
97
|
-
expect(group2.items.length).toBe(0); // No items should be here
|
|
98
|
-
expect(group2.subGroups?.length).toBe(1);
|
|
99
|
-
const subGroup2 = group2.subGroups?.[0];
|
|
100
|
-
expect(subGroup2?.items.length).toBe(1);
|
|
101
|
-
expect(subGroup2?.items.some((i) => i.id === "3")).toBe(true);
|
|
102
|
-
}
|
|
27
|
+
expect(result).toHaveLength(1);
|
|
28
|
+
expect(result[0].sameVisit).toBe(true);
|
|
29
|
+
expect(result[0].items).toHaveLength(2);
|
|
103
30
|
});
|
|
104
31
|
|
|
105
|
-
it("
|
|
106
|
-
const
|
|
107
|
-
|
|
32
|
+
it("agrupa sin misma visita pero dentro de 8h", () => {
|
|
33
|
+
const now = new Date();
|
|
34
|
+
const items = [
|
|
35
|
+
baseItem({
|
|
108
36
|
id: "1",
|
|
109
|
-
date:
|
|
110
|
-
professional: {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
role: { id: "1", description: "1" },
|
|
114
|
-
speciality: { id: "1", description: "1" },
|
|
115
|
-
},
|
|
116
|
-
relevant: true,
|
|
117
|
-
diagnostics: [{ id: "d1", description: "d1" }],
|
|
118
|
-
center: { id: "c1", description: "c1" },
|
|
119
|
-
up: { id: "up1", description: "up1" },
|
|
120
|
-
ep: { id: "ep1", description: "ep1" },
|
|
121
|
-
service: { id: "s1", description: "s1" },
|
|
122
|
-
},
|
|
123
|
-
{
|
|
37
|
+
date: now.toISOString(),
|
|
38
|
+
professional: { id: "p1", role: { id: "r1" }, speciality: { id: "s1" } },
|
|
39
|
+
}),
|
|
40
|
+
baseItem({
|
|
124
41
|
id: "2",
|
|
125
|
-
date:
|
|
126
|
-
professional: {
|
|
127
|
-
|
|
128
|
-
id: "1",
|
|
129
|
-
role: { id: "1", description: "1" },
|
|
130
|
-
speciality: { id: "1", description: "1" },
|
|
131
|
-
},
|
|
132
|
-
relevant: true,
|
|
133
|
-
diagnostics: [{ id: "d1", description: "d1" }],
|
|
134
|
-
center: { id: "c1", description: "c1" },
|
|
135
|
-
up: { id: "up1", description: "up1" },
|
|
136
|
-
ep: { id: "ep1", description: "ep1" },
|
|
137
|
-
service: { id: "s1", description: "s1" },
|
|
138
|
-
},
|
|
42
|
+
date: new Date(now.getTime() + 2 * 3600 * 1000).toISOString(),
|
|
43
|
+
professional: { id: "p2", role: { id: "r2" }, speciality: { id: "s2" } },
|
|
44
|
+
}),
|
|
139
45
|
];
|
|
140
46
|
|
|
141
47
|
const result = groupActivityHistoryItems(items);
|
|
142
48
|
|
|
143
|
-
expect(result
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
g.subGroups?.some((sg) => sg.items.some((i) => i.id === "1")),
|
|
147
|
-
);
|
|
148
|
-
const group2 = result.find((g) =>
|
|
149
|
-
g.subGroups?.some((sg) => sg.items.some((i) => i.id === "2")),
|
|
150
|
-
);
|
|
151
|
-
|
|
152
|
-
expect(group1).toBeDefined();
|
|
153
|
-
expect(group2).toBeDefined();
|
|
154
|
-
|
|
155
|
-
if (group1) {
|
|
156
|
-
expect(group1.items.length).toBe(0);
|
|
157
|
-
expect(group1.subGroups?.length).toBe(1);
|
|
158
|
-
const subGroup1 = group1.subGroups?.[0];
|
|
159
|
-
expect(subGroup1?.items.length).toBe(1);
|
|
160
|
-
expect(subGroup1?.items.some((i) => i.id === "1")).toBe(true);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if (group2) {
|
|
164
|
-
expect(group2.items.length).toBe(0);
|
|
165
|
-
expect(group2.subGroups?.length).toBe(1);
|
|
166
|
-
const subGroup2 = group2.subGroups?.[0];
|
|
167
|
-
expect(subGroup2?.items.length).toBe(1);
|
|
168
|
-
expect(subGroup2?.items.some((i) => i.id === "2")).toBe(true);
|
|
169
|
-
}
|
|
49
|
+
expect(result).toHaveLength(1);
|
|
50
|
+
expect(result[0].sameVisit).toBe(false);
|
|
51
|
+
expect(result[0].items).toHaveLength(2);
|
|
170
52
|
});
|
|
171
53
|
|
|
172
|
-
it("
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
},
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
service: { id: "s1", description: "s1" },
|
|
205
|
-
},
|
|
54
|
+
it("no agrupa si hay diferencia de más de 8h", () => {
|
|
55
|
+
const now = new Date();
|
|
56
|
+
const items = [
|
|
57
|
+
baseItem({ id: "1", date: now.toISOString() }),
|
|
58
|
+
baseItem({ id: "2", date: new Date(now.getTime() + 9 * 3600 * 1000).toISOString() }),
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
const result = groupActivityHistoryItems(items);
|
|
62
|
+
|
|
63
|
+
expect(result).toHaveLength(2);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("crea subgrupos con mismos diagnósticos", () => {
|
|
67
|
+
const now = new Date();
|
|
68
|
+
const diagnostics = [{ codi: "D1" }];
|
|
69
|
+
const items = [
|
|
70
|
+
baseItem({ id: "1", date: now.toISOString(), diagnostics }),
|
|
71
|
+
baseItem({ id: "2", date: new Date(now.getTime() + 1000).toISOString(), diagnostics }),
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
const result = groupActivityHistoryItems(items);
|
|
75
|
+
|
|
76
|
+
expect(result[0].subGroups).toHaveLength(1);
|
|
77
|
+
expect(result[0].subGroups![0].items).toHaveLength(2);
|
|
78
|
+
expect(result[0].items).toHaveLength(0);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("deja fuera de subgrupos ítems sin diagnóstico", () => {
|
|
82
|
+
const now = new Date();
|
|
83
|
+
const items = [
|
|
84
|
+
baseItem({ id: "1", date: now.toISOString(), diagnostics: [{ codi: "D1" }] }),
|
|
85
|
+
baseItem({ id: "2", date: new Date(now.getTime() + 1000).toISOString() }),
|
|
206
86
|
];
|
|
207
87
|
|
|
208
88
|
const result = groupActivityHistoryItems(items);
|
|
209
89
|
|
|
210
|
-
expect(result.
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
g.subGroups?.some((sg) => sg.items.some((i) => i.id === "1")),
|
|
214
|
-
);
|
|
215
|
-
const group2 = result.find((g) =>
|
|
216
|
-
g.subGroups?.some((sg) => sg.items.some((i) => i.id === "2")),
|
|
217
|
-
);
|
|
218
|
-
|
|
219
|
-
expect(group1).toBeDefined();
|
|
220
|
-
expect(group2).toBeDefined();
|
|
221
|
-
|
|
222
|
-
if (group1) {
|
|
223
|
-
expect(group1.items.length).toBe(0);
|
|
224
|
-
expect(group1.subGroups?.length).toBe(1);
|
|
225
|
-
const subGroup1 = group1.subGroups?.[0];
|
|
226
|
-
expect(subGroup1?.items.length).toBe(1);
|
|
227
|
-
expect(subGroup1?.items.some((i) => i.id === "1")).toBe(true);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
if (group2) {
|
|
231
|
-
expect(group2.items.length).toBe(0);
|
|
232
|
-
expect(group2.subGroups?.length).toBe(1);
|
|
233
|
-
const subGroup2 = group2.subGroups?.[0];
|
|
234
|
-
expect(subGroup2?.items.length).toBe(1);
|
|
235
|
-
expect(subGroup2?.items.some((i) => i.id === "2")).toBe(true);
|
|
236
|
-
}
|
|
90
|
+
expect(result[0].subGroups).toHaveLength(1);
|
|
91
|
+
expect(result[0].subGroups![0].items).toHaveLength(1);
|
|
92
|
+
expect(result[0].items).toHaveLength(1);
|
|
237
93
|
});
|
|
238
94
|
});
|
|
@@ -8,8 +8,8 @@ import {
|
|
|
8
8
|
const isSameVisit = (item1: IActivityHistoryItem, item2: IActivityHistoryItem): boolean => {
|
|
9
9
|
const sameProfessional =
|
|
10
10
|
item1.professional?.id === item2.professional?.id &&
|
|
11
|
-
item1.professional?.role
|
|
12
|
-
item1.professional?.speciality
|
|
11
|
+
item1.professional?.role?.id === item2.professional?.role?.id &&
|
|
12
|
+
item1.professional?.speciality?.id === item2.professional?.speciality?.id;
|
|
13
13
|
const sameLocation =
|
|
14
14
|
item1.ep?.id === item2.ep?.id &&
|
|
15
15
|
item1.up?.id === item2.up?.id &&
|
|
@@ -21,7 +21,7 @@ const isSameVisit = (item1: IActivityHistoryItem, item2: IActivityHistoryItem):
|
|
|
21
21
|
return sameProfessional && sameLocation && sameDay;
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
-
const withinEightHours = (date1:
|
|
24
|
+
const withinEightHours = (date1: string, date2: string): boolean => {
|
|
25
25
|
const timeDifference = Math.abs(new Date(date1).getTime() - new Date(date2).getTime());
|
|
26
26
|
return timeDifference <= 8 * 60 * 60 * 1000; // 8 hours in milliseconds
|
|
27
27
|
};
|
|
@@ -46,6 +46,7 @@ const groupActivityHistoryItems = (items: IActivityHistoryItem[]): IActivityHist
|
|
|
46
46
|
items?.forEach((item) => {
|
|
47
47
|
let added = false;
|
|
48
48
|
|
|
49
|
+
// Primer intento: agrupar por misma visita y dentro de 8 horas
|
|
49
50
|
for (const group of groups) {
|
|
50
51
|
const firstItem = group.items[0];
|
|
51
52
|
const lastItem = group.items[group.items.length - 1];
|
|
@@ -56,15 +57,37 @@ const groupActivityHistoryItems = (items: IActivityHistoryItem[]): IActivityHist
|
|
|
56
57
|
withinEightHours(lastItem.date, item.date)
|
|
57
58
|
) {
|
|
58
59
|
group.items.push(item);
|
|
60
|
+
group.sameVisit = true; // marcamos el grupo como de "misma visita"
|
|
59
61
|
added = true;
|
|
60
62
|
break;
|
|
61
63
|
}
|
|
62
64
|
}
|
|
63
65
|
|
|
66
|
+
// Segundo intento: agrupar solo por 8h, pero solo en grupos que NO son "misma visita"
|
|
67
|
+
if (!added) {
|
|
68
|
+
for (const group of groups) {
|
|
69
|
+
if (group.sameVisit) continue; // evitamos mezclar visitas
|
|
70
|
+
|
|
71
|
+
const firstItem = group.items[0];
|
|
72
|
+
const lastItem = group.items[group.items.length - 1];
|
|
73
|
+
|
|
74
|
+
if (
|
|
75
|
+
withinEightHours(firstItem.date, item.date) &&
|
|
76
|
+
withinEightHours(lastItem.date, item.date)
|
|
77
|
+
) {
|
|
78
|
+
group.items.push(item);
|
|
79
|
+
added = true;
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Si no se pudo agrupar, crear un nuevo grupo
|
|
64
86
|
if (!added) {
|
|
65
87
|
groups.push({
|
|
66
88
|
idGroup: Math.random().toString(36).substr(2, 9),
|
|
67
89
|
items: [item],
|
|
90
|
+
sameVisit: false,
|
|
68
91
|
});
|
|
69
92
|
}
|
|
70
93
|
});
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { StoreBaseHandler } from "../../infrastructure/base-handlers";
|
|
2
|
-
import {
|
|
2
|
+
import { ensureAreValidBasicActivityHistoryItems } from "../domain/validation/is-valid-basic-history-item";
|
|
3
3
|
import { updateActivityHistoryItem } from "./action";
|
|
4
4
|
import { UpdateHistoryItemPayload } from "./request";
|
|
5
5
|
|
|
6
6
|
export class UpdateHistoryItemHandler extends StoreBaseHandler {
|
|
7
7
|
async handle(payload: UpdateHistoryItemPayload) {
|
|
8
8
|
try {
|
|
9
|
-
|
|
9
|
+
ensureAreValidBasicActivityHistoryItems([payload.item]);
|
|
10
10
|
this.store.dispatch(
|
|
11
11
|
updateActivityHistoryItem({
|
|
12
12
|
id: payload.entityId,
|
|
@@ -1,61 +1,86 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
2
|
import { getUniqueObjects } from "./get-unique-values-by-prop-path";
|
|
3
3
|
|
|
4
|
+
|
|
4
5
|
describe("getUniqueObjects", () => {
|
|
5
|
-
|
|
6
|
+
const filterTitle = "Centre";
|
|
7
|
+
|
|
8
|
+
it("should return unique objects with correct id and title", () => {
|
|
6
9
|
const items = [
|
|
7
|
-
{
|
|
8
|
-
{
|
|
9
|
-
{
|
|
10
|
+
{ a: { b: "1" }, c: { d: "Hospital A" } },
|
|
11
|
+
{ a: { b: "2" }, c: { d: "Hospital B" } },
|
|
12
|
+
{ a: { b: "1" }, c: { d: "Hospital A" } }, // duplicated
|
|
10
13
|
];
|
|
11
14
|
|
|
12
|
-
const result = getUniqueObjects(items, ["
|
|
15
|
+
const result = getUniqueObjects(items, ["a", "b"], ["c", "d"], filterTitle);
|
|
13
16
|
|
|
14
17
|
expect(result).toEqual([
|
|
15
|
-
{ id: "1", title: "
|
|
16
|
-
{ id: "2", title: "
|
|
18
|
+
{ id: "1", title: "Hospital A" },
|
|
19
|
+
{ id: "2", title: "Hospital B" },
|
|
17
20
|
]);
|
|
18
21
|
});
|
|
19
22
|
|
|
20
|
-
it("should
|
|
23
|
+
it("should sort the results alphabetically by title", () => {
|
|
21
24
|
const items = [
|
|
22
|
-
{
|
|
23
|
-
{
|
|
24
|
-
{
|
|
25
|
+
{ a: { b: "2" }, c: { d: "Zoo" } },
|
|
26
|
+
{ a: { b: "1" }, c: { d: "Apple" } },
|
|
27
|
+
{ a: { b: "3" }, c: { d: "Library" } },
|
|
25
28
|
];
|
|
26
29
|
|
|
27
|
-
const result = getUniqueObjects(items, ["
|
|
30
|
+
const result = getUniqueObjects(items, ["a", "b"], ["c", "d"], filterTitle);
|
|
28
31
|
|
|
29
|
-
expect(result).toEqual([
|
|
32
|
+
expect(result).toEqual([
|
|
33
|
+
{ id: "1", title: "Apple" },
|
|
34
|
+
{ id: "3", title: "Library" },
|
|
35
|
+
{ id: "2", title: "Zoo" },
|
|
36
|
+
]);
|
|
30
37
|
});
|
|
31
38
|
|
|
32
|
-
it("should
|
|
33
|
-
const
|
|
34
|
-
|
|
39
|
+
it("should add 'Sense centre' for items with missing id or title", () => {
|
|
40
|
+
const items = [
|
|
41
|
+
{ a: { b: "" }, c: { d: "Hospital A" } },
|
|
42
|
+
{ a: { b: "1" }, c: { d: null } },
|
|
43
|
+
{ a: { b: null }, c: { d: "" } },
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
const result = getUniqueObjects(items, ["a", "b"], ["c", "d"], filterTitle);
|
|
47
|
+
|
|
48
|
+
expect(result).toHaveLength(1);
|
|
49
|
+
expect(result[0].title).toBe("Sense centre");
|
|
50
|
+
expect(result[0].id).toBe(""); // depende de implementación, aquí "" está permitido
|
|
35
51
|
});
|
|
36
52
|
|
|
37
|
-
it("should
|
|
53
|
+
it("should put 'Sense centre' entry at the end", () => {
|
|
38
54
|
const items = [
|
|
39
|
-
{ a: { b:
|
|
40
|
-
{ a: { b:
|
|
55
|
+
{ a: { b: "1" }, c: { d: "Beta" } },
|
|
56
|
+
{ a: { b: null }, c: { d: null } },
|
|
57
|
+
{ a: { b: "2" }, c: { d: "Alpha" } },
|
|
41
58
|
];
|
|
42
59
|
|
|
43
|
-
const result = getUniqueObjects(items, ["a", "b", "c", "
|
|
60
|
+
const result = getUniqueObjects(items, ["a", "b"], ["c", "d"], filterTitle);
|
|
44
61
|
|
|
45
|
-
expect(result).
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
]);
|
|
62
|
+
expect(result).toHaveLength(3);
|
|
63
|
+
expect(result[0].title).toBe("Alpha");
|
|
64
|
+
expect(result[1].title).toBe("Beta");
|
|
65
|
+
expect(result[2].title).toBe("Sense centre");
|
|
49
66
|
});
|
|
50
67
|
|
|
51
|
-
it("should handle
|
|
68
|
+
it("should handle deep nested paths", () => {
|
|
52
69
|
const items = [
|
|
53
|
-
{ a: { b: {
|
|
54
|
-
{
|
|
70
|
+
{ a: { b: { c: "10" } }, x: { y: { z: "Foo" } } },
|
|
71
|
+
{ a: { b: { c: "20" } }, x: { y: { z: "Bar" } } },
|
|
55
72
|
];
|
|
56
73
|
|
|
57
|
-
const result = getUniqueObjects(items, ["a", "b", "
|
|
74
|
+
const result = getUniqueObjects(items, ["a", "b", "c"], ["x", "y", "z"], filterTitle);
|
|
75
|
+
|
|
76
|
+
expect(result).toEqual([
|
|
77
|
+
{ id: "20", title: "Bar" },
|
|
78
|
+
{ id: "10", title: "Foo" },
|
|
79
|
+
]);
|
|
80
|
+
});
|
|
58
81
|
|
|
59
|
-
|
|
82
|
+
it("should return empty array for empty input", () => {
|
|
83
|
+
const result = getUniqueObjects([], ["a"], ["b"], filterTitle);
|
|
84
|
+
expect(result).toEqual([]);
|
|
60
85
|
});
|
|
61
|
-
});
|
|
86
|
+
});
|
|
@@ -2,15 +2,35 @@ export function getUniqueObjects<T>(
|
|
|
2
2
|
items: T[],
|
|
3
3
|
propPathId: string[],
|
|
4
4
|
propPathDescription: string[],
|
|
5
|
+
filterTitle: string
|
|
5
6
|
): { id: string; title: string }[] {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
const SENSE_TITLE = `Sense ${filterTitle.toLocaleLowerCase()}`;
|
|
8
|
+
const map = new Map<string, { id: string; title: string }>();
|
|
9
|
+
let hasSenseItem = false;
|
|
10
|
+
|
|
11
|
+
for (const item of items) {
|
|
12
|
+
const id = propPathId.reduce((acc, key) => acc?.[key], item);
|
|
13
|
+
const title = propPathDescription.reduce((acc, key) => acc?.[key], item);
|
|
14
|
+
|
|
15
|
+
const isValidId = typeof id === "string" && id.trim() !== "";
|
|
16
|
+
const isValidTitle = typeof title === "string" && title.trim() !== "";
|
|
17
|
+
|
|
18
|
+
if (isValidId && isValidTitle) {
|
|
19
|
+
if (!map.has(id)) {
|
|
20
|
+
map.set(id, { id, title });
|
|
21
|
+
}
|
|
22
|
+
} else {
|
|
23
|
+
hasSenseItem = true;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const result = Array.from(map.values()).sort((a, b) =>
|
|
28
|
+
a.title.localeCompare(b.title, "ca", { sensitivity: "base" })
|
|
15
29
|
);
|
|
16
|
-
|
|
30
|
+
|
|
31
|
+
if (hasSenseItem) {
|
|
32
|
+
result.push({ id: "", title: SENSE_TITLE });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { IActivityHistoryItem } from '../model';
|
|
2
|
-
|
|
3
|
-
export declare const isValidActivityHistoryItem: (obj: IActivityHistoryItem) => any;
|
|
4
|
-
export declare const ensureAreValidActivityHistoryItems: (items: IActivityHistoryItem[]) => IActivityHistoryItem[];
|
|
5
|
-
export declare const validateAndFilterItems: (items: IActivityHistoryItem[]) => IActivityHistoryItem[];
|