frontend: draft fix to sleep not having time
Parents:
3f30f225 file(s) changed
- frontend/app/(tabs)/settings.tsx +1 -1
- frontend/hooks/useHistoryFeed.ts +4 -0
- frontend/hooks/useSleepRecord.queries.ts +14 -0
- frontend/lib/history/mappers.ts +8 -2
- frontend/lib/utils/history.ts +12 -0
frontend/app/(tabs)/settings.tsx
1 1
import {
2 2
TouchableOpacity,
3 3
StyleSheet,
4 4
Text,
5 5
SectionList,
▸ 207 unchanged lines
213 213
color: Colors.light.text,
214 214
fontSize: 14,
215 215
fontWeight: "500" as const,
216 216
}}
217 217
>
218 -
Modo Invisível
218 +
Criptografia (EE2E)
219 219
</Text>
220 220
</View>
221 221
222 222
<Ionicons name="chevron-forward" size={24} color={textColor} />
223 223
</TouchableOpacity>
▸ 82 unchanged lines
306 306
height: StyleSheet.hairlineWidth,
307 307
backgroundColor: "#D1D5DB",
308 308
marginVertical: 16,
309 309
},
310 310
});
frontend/hooks/useHistoryFeed.ts
1 1
// hooks/useHistoryFeed.ts
2 2
import { useMemo } from "react";
3 3
import {
4 4
mergeAndSort,
5 5
filterByCategory,
▸ 20 unchanged lines
26 26
const merged = mergeAndSort([
27 27
moods.map(mapMoodToHistoryCard),
28 28
sleepRecords.map(mapSleepToHistoryCard),
29 29
triggers.map(mapTriggerToHistoryCard),
30 30
]);
31 +
32 +
console.log("Sleep records", sleepRecords)
33 +
console.log("Merged data", merged)
34 +
31 35
const filtered = filterByCategory(merged, activeFilter);
32 36
return groupByDate(filtered);
33 37
}, [moods, sleepRecords, triggers, activeFilter]);
34 38
35 39
// TODO: expose the isLoading here
36 40
return grouped;
37 41
}
frontend/hooks/useSleepRecord.queries.ts
1 1
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
2 2
3 3
import { apiClient, SleepRecord, SleepRecordPayload } from "@/lib/api";
4 +
import { insightKeys } from "./useInsights.queries";
4 5
5 6
export const sleepRecordKeys = {
6 7
all: () => ["sleep-records"] as const,
7 8
lists: () => [...sleepRecordKeys.all(), "list"] as const,
8 9
list: (filters?: SleepRecordFilters) =>
▸ 58 unchanged lines
67 68
}
68 69
},
69 70
70 71
onSuccess: () => {
71 72
queryClient.invalidateQueries({ queryKey: sleepRecordKeys.lists() });
73 +
74 +
// Invalidate insights, so we can force refresh
75 +
setTimeout(() => {
76 +
queryClient.invalidateQueries({
77 +
queryKey: insightKeys.byType("DAILY_ENERGY"),
78 +
});
79 +
queryClient.invalidateQueries({
80 +
queryKey: insightKeys.byType("MOOD_TREND"),
81 +
});
82 +
queryClient.invalidateQueries({
83 +
queryKey: insightKeys.byType("ENERGY_SLEEP_CORRELATION"),
84 +
});
85 +
}, 2000);
72 86
},
73 87
});
74 88
};
75 89
76 90
// Delete a sleep record with optimistic removal
▸ 24 unchanged lines
101 115
onSuccess: () => {
102 116
queryClient.invalidateQueries({ queryKey: sleepRecordKeys.lists() });
103 117
},
104 118
});
105 119
};
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 -
import { parse } from "date-fns";
4 +
import { parse, setHours } from "date-fns";
5 5
6 6
export function mapMoodToHistoryCard(mood: MoodEntry): HistoryCard {
7 7
const moodLabel = getMood(mood.selectedMood);
8 8
const components = mood.moodComponents
9 9
.map((c) => c.component.charAt(0) + c.component.slice(1).toLowerCase())
▸ 28 unchanged lines
38 38
39 39
export function mapSleepToHistoryCard(record: SleepRecord): HistoryCard {
40 40
const hours = Math.floor(record.average);
41 41
const minutes = Math.round((record.average - hours) * 60);
42 42
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
43 49
44 50
return {
45 51
id: `sleep-${record.id}`,
46 52
category: "sleep",
47 -
timestamp: record.date.toString(),
53 +
timestamp,
48 54
title: "Sono",
49 55
summary: [duration, record.annotations].filter(Boolean).join(" · "),
50 56
badge: sleepQualityBadge(record.average),
51 57
raw: record,
52 58
};
▸ 8 unchanged lines
61 67
summary: [record.category, record.comment].filter(Boolean).join(" · "),
62 68
badge: undefined,
63 69
raw: record,
64 70
};
65 71
}
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 +
12 20
const key = new Date(card.timestamp).toLocaleDateString('pt-BR', {
13 21
weekday: 'long',
14 22
day: 'numeric',
15 23
month: 'long',
16 24
});
25 +
26 +
if (card.category === 'sleep') {
27 +
console.log("Key for this sleep card", key, card.timestamp)
28 +
}
17 29
18 30
// XXX: Hacky as fuck
19 31
(acc[key] ??= []).push(card)
20 32
21 33
return acc
▸ 5 unchanged lines
27 39
active: HistoryCategory | 'all',
28 40
): HistoryCard[] {
29 41
if (active === 'all') return cards
30 42
return cards.filter(c => c.category === active)
31 43
}