Reading history data.
Time range to analyze.
Habit pattern data (byDayOfWeek, byTimeOfDay, peakDay, peakHour).
export function computeReadingHabits(
history: ReadingHistory,
timeRange: TimeRange,
): {
byDayOfWeek: Array<{ day: string; chapters: number }>;
byTimeOfDay: Array<{ hour: string; chapters: number }>;
peakDay: string | null;
peakHour: string | null;
} {
const filtered = filterHistoryByTimeRange(history, timeRange);
if (!filtered.length) {
return {
byDayOfWeek: [],
byTimeOfDay: [],
peakDay: null,
peakHour: null,
};
}
// Establish baseline from pre-range history
const now = Date.now();
const ranges = {
"7d": 7 * 24 * 60 * 60 * 1000,
"30d": 30 * 24 * 60 * 60 * 1000,
"90d": 90 * 24 * 60 * 60 * 1000,
};
const cutoff = timeRange === "all" ? 0 : now - ranges[timeRange];
const preRangeBaseline =
timeRange === "all" ? new Map() : getPreRangeBaseline(history, cutoff);
const dayNames = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
];
const dayMap = new Map<number, number>();
const hourMap = new Map<number, number>();
// Calculate deltas and group by day/hour
const sorted = [...filtered].sort((a, b) => a.timestamp - b.timestamp);
const previousChapters = new Map<string | number, number>(preRangeBaseline);
for (const entry of sorted) {
const prev = previousChapters.get(entry.mangaId) ?? 0;
const delta = Math.max(0, entry.chaptersRead - prev);
if (delta > 0) {
const date = new Date(entry.timestamp);
const dayOfWeek = date.getDay();
const hour = date.getHours();
dayMap.set(dayOfWeek, (dayMap.get(dayOfWeek) ?? 0) + delta);
hourMap.set(hour, (hourMap.get(hour) ?? 0) + delta);
}
previousChapters.set(entry.mangaId, entry.chaptersRead);
}
// Convert to arrays
const byDayOfWeek = Array.from({ length: 7 }, (_, i) => ({
day: dayNames[i],
chapters: dayMap.get(i) ?? 0,
}));
const byTimeOfDay = Array.from({ length: 24 }, (_, i) => ({
hour: `${i.toString().padStart(2, "0")}:00`,
chapters: hourMap.get(i) ?? 0,
}));
// Find peaks
const maxDay = Math.max(...byDayOfWeek.map((d) => d.chapters));
const maxHour = Math.max(...byTimeOfDay.map((h) => h.chapters));
const peakDay = byDayOfWeek.find((d) => d.chapters === maxDay)?.day ?? null;
const peakHour =
byTimeOfDay.find((h) => h.chapters === maxHour)?.hour ?? null;
return {
byDayOfWeek,
byTimeOfDay,
peakDay,
peakHour,
};
}
Computes reading habit patterns (day of week, time of day) with per-manga baseline from pre-range history.