eletrotupi / tcc/ commit / a1a9079

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 files
Parents 6974d55
Changed 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
});