eletrotupi / tcc/ commit / 8d8ddb9

frontend/history: fix weird offset for sleep records and use the created at

Pedro Lucas Porcellis porcellis@eletrotupi.com 1 month ago 8d8ddb91411f9e44160d4b8a44cad4f1738bfc94
Parents: f9e8c48
3 file(s) changed
  • frontend/lib/history/mappers.ts +4 -6
  • frontend/lib/utils/history.ts +0 -13
  • frontend/lib/utils/time.ts +7 -0
frontend/lib/history/mappers.ts
1 1
import type { HistoryCard } from "@/lib/history/types";
2 2
import type { MoodEntry, SleepRecord, Trigger } from "@/lib/api";
3 3
import { getMood } from "@/constants/moods";
4 4
import { parse, setHours } from "date-fns";
5 5

▸ 29 unchanged lines
35 35
    variant: "danger",
36 36
  };
37 37
}
38 38

39 39
export function mapSleepToHistoryCard(record: SleepRecord): HistoryCard {
40 +
  console.log("mapping...", record)
40 41
  const hours = Math.floor(record.average);
41 42
  const minutes = Math.round((record.average - hours) * 60);
42 43
  const duration = `${hours}h ${minutes.toString().padStart(2, "0")}min`;
43 -
  // Force local noon so timezone shifts can't bleed into the previous day
44 -
  const dateStr = typeof record.date === 'string'
45 -
    ? record.date.slice(0, 10)           // "2026-05-24"
46 -
    : record.date.toISOString().slice(0, 10)
47 -

48 -
  const timestamp = `${dateStr}T12:00:00`  // local noon, no UTC funny business
44 +
  const timestamp = typeof record.createdAt === 'string'
45 +
    ? record.createdAt
46 +
    : record.createdAt.toISOString();
49 47

50 48
  return {
51 49
    id: `sleep-${record.id}`,
52 50
    category: "sleep",
53 51
    timestamp,
▸ 13 unchanged lines
67 65
    summary: [record.category, record.comment].filter(Boolean).join(" · "),
68 66
    badge: undefined,
69 67
    raw: record,
70 68
  };
71 69
}
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
▸ 1 unchanged lines
7 7
  .sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime())
8 8
}
9 9

10 10
export function groupByDate(cards: HistoryCard[]): Record<string, HistoryCard[]> {
11 11
  return cards.reduce<Record<string, HistoryCard[]>>((acc, card) => {
12 -
    // If the key for this card is sleep, we have to set the hours to
13 -
    // mid day since sleep records dont have a specific time
14 -
    if (card.category === 'sleep') {
15 -
      const date = new Date(card.timestamp)
16 -
      date.setHours(12)
17 -
      card.timestamp = date.toISOString()
18 -
    }
19 -

20 12
    const key = new Date(card.timestamp).toLocaleDateString('pt-BR', {
21 13
      weekday: 'long',
22 14
      day: 'numeric',
23 15
      month: 'long',
24 16
    });
25 17

26 -
    if (card.category === 'sleep') {
27 -
      console.log("Key for this sleep card", key, card.timestamp)
28 -
    }
29 -

30 -
    // XXX: Hacky as fuck
31 18
    (acc[key] ??= []).push(card)
32 19

33 20
    return acc
34 21
  }, {})
35 22
}
▸ 3 unchanged lines
39 26
  active: HistoryCategory | 'all',
40 27
): HistoryCard[] {
41 28
  if (active === 'all') return cards
42 29
    return cards.filter(c => c.category === active)
43 30
}
frontend/lib/utils/time.ts
1 1
import { format, isToday, isYesterday } from 'date-fns';
2 2
import { ptBR } from 'date-fns/locale';
3 3

4 4
type TimeBadgeVariant = 'morning' | 'afternoon' | 'night' | 'latenight';
5 5

▸ 26 unchanged lines
32 32
  if (isToday(date))     return `Hoje, ${format(date, "dd/MM")}`;
33 33
  if (isYesterday(date)) return `Ontem, ${format(date, "dd/MM")}`;
34 34

35 35
  return format(date, "dd/MM/yyyy", { locale: ptBR });
36 36
}
37 +

38 +
// Parse a date-only string (YYYY-MM-DD or ISO UTC midnight) as local noon
39 +
// to prevent timezone offsets from shifting the calendar day
40 +
export const parseDateOnly = (dateStr: string | Date): Date => {
41 +
  const iso = typeof dateStr === 'string' ? dateStr : dateStr.toISOString();
42 +
  return new Date(`${iso.slice(0, 10)}T12:00:00`);
43 +
};