import { addWeeks } from "date-fns"; import * as R from "remeda"; import { AVAILABILITY } from "../availability-constants"; import type { ScheduleWeekView } from "../availability-types"; import * as Availability from "./Availability"; import * as ScheduleWeek from "./ScheduleWeek"; import * as VisibleSchedules from "./VisibleSchedules.server"; /** * Reportable weeks keyed by user id, free time only (commitments subtracted). Users who reported * neither week, and those not sharing their schedule with the viewer, are left out; the friends * page sorts and shows its calendar icon by the missing key. */ export async function findByUserIds({ userIds, timezone, viewerId, }: { userIds: Array; timezone: string; viewerId: number; }): Promise>> { const now = new Date(); const ranges = R.range(0, AVAILABILITY.WEEK_HORIZON).map((weekOffset) => Availability.weekRange(addWeeks(now, weekOffset), timezone), ); const horizon = { startsAt: ranges[0].startsAt, endsAt: ranges[ranges.length - 1].endsAt, }; const { reportedWeeks, busyByUserId } = await VisibleSchedules.findByUserIds({ userIds, viewerId, ...horizon, }); const weeks = ranges.map((range, index) => ({ range, week: index === 0 ? ("current" as const) : ("next" as const), weekNumber: ScheduleWeek.weekNumber(range, timezone), days: ScheduleWeek.days(range, timezone), })); return new Map( userIds.flatMap((userId) => { const busy = busyByUserId.get(userId) ?? []; const views = weeks.map((week): ScheduleWeekView => { const row = ScheduleWeek.memberRow({ userId, days: week.days, timezone, reportedWeeks, range: week.range, busy, }); return { week: week.week, weekNumber: week.weekNumber, reported: row.reported, days: week.days.map((day, dayIndex) => ({ noonAt: day.noonAt, ranges: row.days[dayIndex].ranges, })), }; }); return views.some((view) => view.reported) ? [[userId, views]] : []; }), ); }