62 lines
2 KiB
TypeScript
62 lines
2 KiB
TypeScript
import type { SleepEntry, SleepEvent } from "../api/sleepDiary";
|
|
import { projectSleepTimeline } from "./sleepVisualProjection";
|
|
|
|
export interface SleepEntryFacts {
|
|
bedTime: string | null;
|
|
finalGetUp: string | null;
|
|
sleepSeconds: number;
|
|
timeInBedSeconds: number | null;
|
|
longAwakeCount: number;
|
|
longAwakeSeconds: number;
|
|
napCount: number;
|
|
napSeconds: number;
|
|
sleepinessCount: number;
|
|
}
|
|
|
|
const durationSeconds = (event: SleepEvent): number => {
|
|
if (event.end_at === null) return 0;
|
|
const start = Date.parse(event.start_at);
|
|
const end = Date.parse(event.end_at);
|
|
return Number.isFinite(start) && Number.isFinite(end) && end > start
|
|
? Math.floor((end - start) / 1000)
|
|
: 0;
|
|
};
|
|
|
|
const clock = (timestamp: string | null): string | null =>
|
|
timestamp === null ? null : timestamp.slice(11, 16);
|
|
|
|
export function sleepEntryFacts(entry: SleepEntry): SleepEntryFacts {
|
|
const projection = projectSleepTimeline(entry);
|
|
const bedtime = entry.events.find((event) => event.type === "bed_time");
|
|
const finalGetUp = [...entry.events]
|
|
.reverse()
|
|
.find((event) => event.type === "final_get_up");
|
|
const interval =
|
|
bedtime !== undefined && finalGetUp !== undefined
|
|
? Date.parse(finalGetUp.start_at) - Date.parse(bedtime.start_at)
|
|
: Number.NaN;
|
|
const events = (type: SleepEvent["type"]) =>
|
|
entry.events.filter((event) => event.type === type);
|
|
const longAwake = events("long_awake");
|
|
const naps = events("nap");
|
|
return {
|
|
bedTime: clock(bedtime?.start_at ?? null),
|
|
finalGetUp: clock(finalGetUp?.start_at ?? null),
|
|
sleepSeconds: projection.sleepSeconds,
|
|
timeInBedSeconds:
|
|
Number.isFinite(interval) && interval > 0
|
|
? Math.floor(interval / 1000)
|
|
: null,
|
|
longAwakeCount: longAwake.length,
|
|
longAwakeSeconds: longAwake.reduce(
|
|
(total, event) => total + durationSeconds(event),
|
|
0,
|
|
),
|
|
napCount: naps.length,
|
|
napSeconds: naps.reduce(
|
|
(total, event) => total + durationSeconds(event),
|
|
0,
|
|
),
|
|
sleepinessCount: events("daytime_sleepiness").length,
|
|
};
|
|
}
|