@uxland/primary-shell 5.3.6 → 5.3.7

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.
@@ -0,0 +1,12 @@
1
+ import { IActivityHistoryGroup, IActivityHistoryItemWithComponent, IActivityHistorySubGroup } from '../../domain/model';
2
+
3
+ export type ActivityHistoryEntry = {
4
+ type: "item";
5
+ date: Date;
6
+ item: IActivityHistoryItemWithComponent;
7
+ } | {
8
+ type: "subGroup";
9
+ date: Date;
10
+ subGroup: IActivityHistorySubGroup;
11
+ };
12
+ export declare const mergeHistoryItemsAndSubgroups: (group: IActivityHistoryGroup) => ActivityHistoryEntry[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uxland/primary-shell",
3
- "version": "5.3.6",
3
+ "version": "5.3.7",
4
4
  "description": "Primaria Shell",
5
5
  "author": "UXLand <dev@uxland.es>",
6
6
  "homepage": "https://github.com/uxland/harmonix/tree/app#readme",
@@ -14,6 +14,10 @@ import {
14
14
  import { translate } from "../../../../localization";
15
15
  import { virtualize } from "@lit-labs/virtualizer/virtualize.js";
16
16
  import { hasItemDivider, shouldShowRole } from "../../../domain/business-rules";
17
+ import {
18
+ ActivityHistoryEntry,
19
+ mergeHistoryItemsAndSubgroups,
20
+ } from "../../merge-history-items-and-subgroups/merge-history-items-and-subgroups";
17
21
 
18
22
  export const template = (props: ActivityHistoryTimeline) => {
19
23
  if (!props._hasUpdatedOnce) {
@@ -32,26 +36,41 @@ export const template = (props: ActivityHistoryTimeline) => {
32
36
  ${visitHeaderTemplate(props, itemGroup.items[0] || itemGroup.subGroups[0]?.items[0])}
33
37
  <div class="visit__items">
34
38
  ${repeat(
35
- itemGroup.items,
36
- (item) => item.id,
37
- (item: IActivityHistoryItemWithComponent) =>
38
- html`<div class="item" ?has-divider=${hasItemDivider(item, itemGroup.items as IActivityHistoryItemWithComponent[])}>${item.component}</div> `,
39
- )}
40
- ${repeat(
41
- itemGroup.subGroups,
42
- (subGroup: IActivityHistorySubGroup) => html`
43
- <div class="diagnostics">
44
- ${diagnosticHeaderTemplate(subGroup.items[0])}
45
- <div class="diagnostics__items">
46
- ${repeat(
47
- subGroup.items,
48
- (item) => item.id,
49
- (item: IActivityHistoryItemWithComponent) =>
50
- html`<div class="item" ?has-divider=${hasItemDivider(item, subGroup.items as IActivityHistoryItemWithComponent[])}>${item?.component}</div>`,
51
- )}
52
- </div>
53
- </div>
54
- `,
39
+ mergeHistoryItemsAndSubgroups(itemGroup),
40
+ (entry) => (entry.type === "item" ? entry.item.id : entry.subGroup.id),
41
+ (entry: ActivityHistoryEntry) => {
42
+ if (entry.type === "item") {
43
+ const item = entry.item;
44
+ return html`
45
+ <div
46
+ class="item"
47
+ ?has-divider=${hasItemDivider(item, itemGroup.items as IActivityHistoryItemWithComponent[])}
48
+ >
49
+ ${item.component}
50
+ </div>
51
+ `;
52
+ }
53
+ const subGroup = entry.subGroup;
54
+ return html`
55
+ <div class="diagnostics">
56
+ ${diagnosticHeaderTemplate(subGroup.items[0])}
57
+ <div class="diagnostics__items">
58
+ ${repeat(
59
+ subGroup.items,
60
+ (item) => item.id,
61
+ (item: IActivityHistoryItemWithComponent) => html`
62
+ <div
63
+ class="item"
64
+ ?has-divider=${hasItemDivider(item, subGroup.items as IActivityHistoryItemWithComponent[])}
65
+ >
66
+ ${item.component}
67
+ </div>
68
+ `,
69
+ )}
70
+ </div>
71
+ </div>
72
+ `;
73
+ },
55
74
  )}
56
75
  </div>
57
76
  </div>
@@ -96,7 +115,7 @@ const renderProfessionalValues = (props: ActivityHistoryTimeline, item: IActivit
96
115
  const professionalItems = [
97
116
  props.highlighted(item.professional.name),
98
117
  showRole ? props.highlighted(item.professional.role.description) : null,
99
- props.highlighted(item.center.description),
118
+ props.highlighted(item.up.description) ?? props.highlighted(item.center.description),
100
119
  props.highlighted(item.professional.speciality.description),
101
120
  props.highlighted(item.service.description),
102
121
  ].filter(Boolean);
@@ -0,0 +1,93 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { mergeHistoryItemsAndSubgroups } from "./merge-history-items-and-subgroups";
3
+ import {
4
+ IActivityHistoryGroup,
5
+ IActivityHistoryItemWithComponent,
6
+ IActivityHistorySubGroup,
7
+ } from "../../domain/model";
8
+
9
+ type RenderEntry =
10
+ | { type: "item"; date: Date; item: IActivityHistoryItemWithComponent }
11
+ | { type: "subGroup"; date: Date; subGroup: IActivityHistorySubGroup };
12
+
13
+ describe("mergeHistoryItemsAndSubgroups", () => {
14
+ it("should sort only items by date descending", () => {
15
+ const group: IActivityHistoryGroup = {
16
+ id: "g1",
17
+ items: [
18
+ { id: "i1", date: "2025-05-05T10:00:00Z", component: "<div/>" },
19
+ { id: "i2", date: "2025-05-05T12:00:00Z", component: "<div/>" },
20
+ { id: "i3", date: "2025-05-05T08:00:00Z", component: "<div/>" },
21
+ ],
22
+ subGroups: [],
23
+ };
24
+
25
+ const result = mergeHistoryItemsAndSubgroups(group) as RenderEntry[];
26
+ const ids = result.map((e) => (e.type === "item" ? e.item.id : e.subGroup.id));
27
+
28
+ expect(ids).toEqual(["i2", "i1", "i3"]);
29
+ });
30
+
31
+ it("should sort only subGroups by their most recent item", () => {
32
+ const subGroupA: IActivityHistorySubGroup = {
33
+ id: "sgA",
34
+ items: [{ id: "a1", date: "2025-05-05T09:00:00Z", component: "<div/>" }],
35
+ };
36
+ const subGroupB: IActivityHistorySubGroup = {
37
+ id: "sgB",
38
+ items: [
39
+ { id: "b1", date: "2025-05-05T15:00:00Z", component: "<div/>" },
40
+ { id: "b2", date: "2025-05-05T14:00:00Z", component: "<div/>" },
41
+ ],
42
+ };
43
+ const group: IActivityHistoryGroup = {
44
+ id: "g2",
45
+ items: [],
46
+ subGroups: [subGroupA, subGroupB],
47
+ };
48
+
49
+ const result = mergeHistoryItemsAndSubgroups(group) as RenderEntry[];
50
+ const ids = result.map((e) => (e.type === "item" ? e.item.id : e.subGroup.id));
51
+
52
+ expect(ids).toEqual(["sgB", "sgA"]);
53
+ });
54
+
55
+ it("should interleave items and subGroups by date", () => {
56
+ const group: IActivityHistoryGroup = {
57
+ id: "g3",
58
+ items: [
59
+ { id: "i1", date: "2025-05-05T10:00:00Z", component: "<div/>" },
60
+ { id: "i2", date: "2025-05-05T14:00:00Z", component: "<div/>" },
61
+ ],
62
+ subGroups: [
63
+ {
64
+ id: "sg1",
65
+ items: [{ id: "s1", date: "2025-05-05T12:00:00Z", component: "<div/>" }],
66
+ },
67
+ ],
68
+ };
69
+
70
+ const result = mergeHistoryItemsAndSubgroups(group) as RenderEntry[];
71
+ const ids = result.map((e) => (e.type === "item" ? e.item.id : e.subGroup.id));
72
+
73
+ // Expected order: i2 (14:00), sg1 (12:00), i1 (10:00)
74
+ expect(ids).toEqual(["i2", "sg1", "i1"]);
75
+ });
76
+
77
+ it("should place subGroups without items at the end", () => {
78
+ const emptySubGroup: IActivityHistorySubGroup = {
79
+ id: "sgEmpty",
80
+ items: [],
81
+ };
82
+ const group: IActivityHistoryGroup = {
83
+ id: "g4",
84
+ items: [{ id: "i1", date: "2025-05-05T11:00:00Z", component: "<div/>" }],
85
+ subGroups: [emptySubGroup],
86
+ };
87
+
88
+ const result = mergeHistoryItemsAndSubgroups(group) as RenderEntry[];
89
+ const ids = result.map((e) => (e.type === "item" ? e.item.id : e.subGroup.id));
90
+
91
+ expect(ids).toEqual(["i1", "sgEmpty"]);
92
+ });
93
+ });
@@ -0,0 +1,34 @@
1
+ import {
2
+ IActivityHistoryGroup,
3
+ IActivityHistoryItemWithComponent,
4
+ IActivityHistorySubGroup,
5
+ } from "../../domain/model";
6
+
7
+ export type ActivityHistoryEntry =
8
+ | { type: "item"; date: Date; item: IActivityHistoryItemWithComponent }
9
+ | { type: "subGroup"; date: Date; subGroup: IActivityHistorySubGroup };
10
+
11
+ export const mergeHistoryItemsAndSubgroups = (
12
+ group: IActivityHistoryGroup,
13
+ ): ActivityHistoryEntry[] => {
14
+ // 1. Prepara los items sueltos
15
+ const itemEntries: ActivityHistoryEntry[] = group.items.map((item) => ({
16
+ type: "item",
17
+ date: new Date(item.date),
18
+ item,
19
+ }));
20
+
21
+ // 2. Prepara los subGroups, usando la fecha del ítem más reciente de cada subgrupo
22
+ const subGroupEntries: ActivityHistoryEntry[] = group.subGroups.map((subGroup) => {
23
+ // Asumimos que subGroup.items ya está ordenado de más reciente a más antiguo
24
+ const mostRecent = subGroup.items.length ? new Date(subGroup.items[0].date) : new Date(0);
25
+ return {
26
+ type: "subGroup",
27
+ date: mostRecent,
28
+ subGroup,
29
+ };
30
+ });
31
+
32
+ // 3. Fusiona y ordena
33
+ return [...itemEntries, ...subGroupEntries].sort((a, b) => b.date.getTime() - a.date.getTime());
34
+ };
@@ -1,47 +1,52 @@
1
1
  import { IActivityHistoryGroup } from "../../domain/model";
2
2
 
3
3
  export const sortGroupsByMostRecentDate = (arr: IActivityHistoryGroup[]) => {
4
- // Helper function to get the most recent date from a list of items
5
- const getMostRecentDate = (items) => {
4
+ // Helper: obtener la fecha más reciente de una lista de items
5
+ const getMostRecentDate = (items: { date: string }[]): Date => {
6
6
  return items.reduce((latest, item) => {
7
7
  const itemDate = new Date(item.date);
8
8
  return itemDate > latest ? itemDate : latest;
9
- }, new Date(0)); // Default to an old date
9
+ }, new Date(0));
10
10
  };
11
11
 
12
- // Helper function to sort items within each group or subgroup
13
- const sortItemsByDate = (items) => {
14
- return items.sort((a, b) => new Date(b.date) - new Date(a.date));
12
+ // Ordenar items de más reciente a más antiguo
13
+ const sortItemsByDate = (items: { date: string }[]) => {
14
+ return items.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
15
15
  };
16
16
 
17
- // Function to get the most recent date from a group (considering its items and subgroups)
18
- const getGroupMostRecentDate = (group) => {
19
- let allDates = [];
20
-
21
- // Collect dates from group items
22
- if (group.items.length > 0) {
23
- allDates.push(getMostRecentDate(group.items));
24
- }
25
-
26
- // Collect dates from subgroups items
27
- group.subGroups.forEach((subGroup) => {
28
- if (subGroup.items.length > 0) {
29
- allDates.push(getMostRecentDate(subGroup.items));
30
- }
31
- });
17
+ // Obtener la fecha más reciente de un subgrupo
18
+ const getSubGroupMostRecentDate = (subGroup: { items: { date: string }[] }): Date => {
19
+ return getMostRecentDate(subGroup.items);
20
+ };
32
21
 
33
- // Return the most recent date found in the group and subgroups
34
- return allDates.length > 0 ? new Date(Math.max(...allDates)) : new Date(0);
22
+ // Obtener la fecha más reciente de un grupo (considerando sus items y subgroups)
23
+ const getGroupMostRecentDate = (group: IActivityHistoryGroup): Date => {
24
+ const itemDates = group.items.length > 0 ? [getMostRecentDate(group.items)] : [];
25
+ const subGroupDates = group.subGroups.map(getSubGroupMostRecentDate);
26
+ const allDates = [...itemDates, ...subGroupDates];
27
+ return allDates.length > 0
28
+ ? new Date(Math.max(...allDates.map((d) => d.getTime())))
29
+ : new Date(0);
35
30
  };
36
31
 
37
- // Sort each group's items and subgroups' items by date
32
+ // Procesar cada grupo
38
33
  arr.forEach((group) => {
34
+ // Ordenar items del grupo
39
35
  group.items = sortItemsByDate(group.items);
36
+
37
+ // Ordenar items de cada subgrupo
40
38
  group.subGroups.forEach((subGroup) => {
41
39
  subGroup.items = sortItemsByDate(subGroup.items);
42
40
  });
41
+
42
+ // Ordenar subgrupos según el item más reciente en cada uno
43
+ group.subGroups.sort(
44
+ (a, b) => getSubGroupMostRecentDate(b).getTime() - getSubGroupMostRecentDate(a).getTime(),
45
+ );
43
46
  });
44
47
 
45
- // Sort groups by the most recent date of their items and subgroups
46
- return arr.sort((a, b) => getGroupMostRecentDate(b) - getGroupMostRecentDate(a));
48
+ // Finalmente, ordenar los grupos por su fecha más reciente
49
+ return arr.sort(
50
+ (a, b) => getGroupMostRecentDate(b).getTime() - getGroupMostRecentDate(a).getTime(),
51
+ );
47
52
  };