| 1 | import { prisma } from "@app/lib/prisma";
|
| 2 | import { InsightType, InsightPeriod } from "@prisma/client";
|
| 3 | import { InsightPeriodPayload } from "@app/lib/queue/types";
|
| 4 | // XXX: date-fns?
|
| 5 | import { formatHours, formatDiff } from "@app/utils/calc";
|
| 6 | import { startOfDay, addDays, subDays } from "date-fns";
|
| 7 |
|
| 8 | export async function processDailySleep({
|
| 9 | userId,
|
| 10 | periodStart,
|
| 11 | }: InsightPeriodPayload): Promise<void> {
|
| 12 | const today = startOfDay(new Date(periodStart));
|
| 13 | const tomorrow = addDays(today, 1);
|
| 14 | const yesterday = subDays(today, 1);
|
| 15 |
|
| 16 | const [todayRecords, yesterdayRecords] = await Promise.all([
|
| 17 | prisma.sleepRecord.findMany({
|
| 18 | where: { userId, date: { gte: today, lt: tomorrow } },
|
| 19 | select: { average: true },
|
| 20 | }),
|
| 21 | prisma.sleepRecord.findMany({
|
| 22 | where: { userId, date: { gte: yesterday, lt: today } },
|
| 23 | select: { average: true },
|
| 24 | }),
|
| 25 | ]);
|
| 26 |
|
| 27 | console.log("todayRecords, yesterdayRecords", todayRecords, yesterdayRecords);
|
| 28 |
|
| 29 | if (todayRecords.length === 0) return;
|
| 30 |
|
| 31 | // average is stored in hours
|
| 32 | // sum across all records for the day
|
| 33 | const totalToday = todayRecords.reduce(
|
| 34 | (sum: number, r: { average: number }) => sum + r.average,
|
| 35 | 0,
|
| 36 | );
|
| 37 | const totalYesterday =
|
| 38 | yesterdayRecords.length > 0
|
| 39 | ? yesterdayRecords.reduce(
|
| 40 | (sum: number, r: { average: number }) => sum + r.average,
|
| 41 | 0,
|
| 42 | )
|
| 43 | : null;
|
| 44 |
|
| 45 | const diffMinutes =
|
| 46 | totalYesterday !== null
|
| 47 | ? Math.round((totalToday - totalYesterday) * 60)
|
| 48 | : null;
|
| 49 |
|
| 50 | const sessionCount = todayRecords.length; // 1 = normal night, 2+ = nap(s)
|
| 51 |
|
| 52 | const diffStr =
|
| 53 | diffMinutes !== null && Math.abs(diffMinutes) >= 5
|
| 54 | ? `${formatDiff(diffMinutes)} que ontem`
|
| 55 | : "";
|
| 56 |
|
| 57 | const napStr =
|
| 58 | sessionCount > 1
|
| 59 | ? `incluindo ${sessionCount - 1} cochilo${sessionCount > 2 ? "s" : ""}`
|
| 60 | : "";
|
| 61 |
|
| 62 | await prisma.insight.upsert({
|
| 63 | where: {
|
| 64 | userId_type_periodStart: {
|
| 65 | userId,
|
| 66 | type: InsightType.DAILY_SLEEP,
|
| 67 | periodStart: today,
|
| 68 | },
|
| 69 | },
|
| 70 | update: {
|
| 71 | body: buildBody(totalToday),
|
| 72 | metadata: {
|
| 73 | totalHours: totalToday,
|
| 74 | diffMinutes,
|
| 75 | diffStr,
|
| 76 | sessionCount,
|
| 77 | napStr,
|
| 78 | hadNaps: sessionCount > 1,
|
| 79 | },
|
| 80 | generatedAt: new Date(),
|
| 81 | },
|
| 82 | create: {
|
| 83 | userId,
|
| 84 | type: InsightType.DAILY_SLEEP,
|
| 85 | period: InsightPeriod.DAILY,
|
| 86 | title: "Sono",
|
| 87 | body: buildBody(totalToday),
|
| 88 | metadata: {
|
| 89 | totalHours: totalToday,
|
| 90 | diffMinutes,
|
| 91 | sessionCount,
|
| 92 | diffStr,
|
| 93 | napStr,
|
| 94 | hadNaps: sessionCount > 1,
|
| 95 | },
|
| 96 | periodStart: today,
|
| 97 | periodEnd: tomorrow,
|
| 98 | },
|
| 99 | });
|
| 100 | }
|
| 101 |
|
| 102 | function buildBody(total: number): string {
|
| 103 | const totalStr = formatHours(total);
|
| 104 |
|
| 105 | return `${totalStr} de sono hoje`;
|
| 106 | }
|