frontend: key history date groups by year when outside it
The grouping label omitted the year, so the same day and month in two different years collapsed into a single section. The key now carries the year only for a card outside the current one, keeping recent headings short, and a test covers both labels. The reference date is an argument so the behaviour stays deterministic under test
Pedro Lucas Porcellis porcellis@eletrotupi.com · 9 days ago
a1a9079e3159130a372ea537b25611ee5d274ef9 Browse filesParents
6974d55Changed files
2
Additions
+24
Deletions
-3
frontend/lib/utils/history.ts
1 1
// TODO: add a barrel import here ffs
2 2
import type { HistoryCard, HistoryCategory } from '@/lib/history/types'
3 3
4 4
export function mergeAndSort(cards: HistoryCard[][]): HistoryCard[] {
5 5
return cards
6 6
.flat()
7 7
.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime())
8 8
}
9 9
10 -
export function groupByDate(cards: HistoryCard[]): Record<string, HistoryCard[]> {
10 +
export function groupByDate(
11 +
cards: HistoryCard[],
12 +
now: Date = new Date(),
13 +
): Record<string, HistoryCard[]> {
11 14
return cards.reduce<Record<string, HistoryCard[]>>((acc, card) => {
12 -
const key = new Date(card.timestamp).toLocaleDateString('pt-BR', {
15 +
const date = new Date(card.timestamp);
16 +
const includeYear = date.getFullYear() !== now.getFullYear();
17 +
const key = date.toLocaleDateString('pt-BR', {
13 18
weekday: 'long',
14 19
day: 'numeric',
15 20
month: 'long',
21 +
...(includeYear ? { year: 'numeric' } : {}),
16 22
});
17 23
18 24
(acc[key] ??= []).push(card)
19 25
20 26
return acc
26 32
active: HistoryCategory | 'all',
27 33
): HistoryCard[] {
28 34
if (active === 'all') return cards
29 35
return cards.filter(c => c.category === active)
30 36
}
frontend/tests/utils/history.unit.test.ts
1 1
import {
2 2
filterByCategory,
3 3
groupByDate,
4 4
mergeAndSort,
5 5
} from "@/lib/utils/history";
39 39
it("groups into fixed, ordered date buckets", () => {
40 40
const morning = card("m1", "mood", new Date(2025, 0, 15, 9, 0));
41 41
const evening = card("s1", "sleep", new Date(2025, 0, 15, 20, 0));
42 42
const previous = card("t1", "trigger", new Date(2025, 0, 14, 12, 0));
43 43
44 -
const grouped = groupByDate([morning, evening, previous]);
44 +
const grouped = groupByDate(
45 +
[morning, evening, previous],
46 +
new Date(2025, 5, 1),
47 +
);
45 48
46 49
expect(Object.keys(grouped)).toEqual([
47 50
"quarta-feira, 15 de janeiro",
48 51
"terça-feira, 14 de janeiro",
49 52
]);
51 54
"m1",
52 55
"s1",
53 56
]);
54 57
expect(grouped["terça-feira, 14 de janeiro"].map((c) => c.id)).toEqual([
55 58
"t1",
59 +
]);
60 +
});
61 +
62 +
it("adds the year only for cards outside the current year", () => {
63 +
const thisYear = card("this", "mood", new Date(2026, 0, 15, 9, 0));
64 +
const lastYear = card("last", "mood", new Date(2025, 0, 15, 9, 0));
65 +
66 +
const grouped = groupByDate([thisYear, lastYear], new Date(2026, 5, 1));
67 +
68 +
expect(Object.keys(grouped)).toEqual([
69 +
"quinta-feira, 15 de janeiro",
70 +
"quarta-feira, 15 de janeiro de 2025",
56 71
]);
57 72
});
58 73
59 74
it("returns no buckets for an empty list", () => {
60 75
expect(groupByDate([])).toEqual({});
85 100
"t",
86 101
"c",
87 102
]);
88 103
});
89 104
});