import type { TimelineAssignmentEntry } from "./TimelineContext.js"; import type { ResourceCapacitySeries } from "./timelineCapacity.js"; export type ProjectDayMetric = { projH: number; totalH: number; capacityH: number; }; type ProjectMetricRow = { resource: { id: string }; allocs: TimelineAssignmentEntry[]; }; type ProjectMetricGroup = { id: string; resourceRows: ProjectMetricRow[]; }; export function getProjectRowMetricsKey(projectId: string, resourceId: string): string { return `${projectId}:${resourceId}`; } export function buildProjectRowMetrics( dates: Date[], projectGroups: ProjectMetricGroup[], resourceTotalHoursById: Map, resourceCapacityById: Map, ): Map { const dateIndexByTime = new Map(); dates.forEach((date, index) => { const normalized = new Date(date); normalized.setHours(0, 0, 0, 0); dateIndexByTime.set(normalized.getTime(), index); }); const nextMetrics = new Map(); for (const project of projectGroups) { for (const { resource, allocs } of project.resourceRows) { const projectHours = new Array(dates.length).fill(0); const capacity = resourceCapacityById.get(resource.id); for (const alloc of allocs) { const current = new Date(alloc.startDate); current.setHours(0, 0, 0, 0); const end = new Date(alloc.endDate); end.setHours(0, 0, 0, 0); while (current.getTime() <= end.getTime()) { const dayIndex = dateIndexByTime.get(current.getTime()); if (dayIndex !== undefined) { projectHours[dayIndex] = (projectHours[dayIndex] ?? 0) + alloc.hoursPerDay * (capacity?.bookingFactorsByDay[dayIndex] ?? 1); } current.setDate(current.getDate() + 1); } } const totalHours = resourceTotalHoursById.get(resource.id); nextMetrics.set( getProjectRowMetricsKey(project.id, resource.id), projectHours.map((projH, dayIndex) => ({ projH, totalH: totalHours?.[dayIndex] ?? 0, capacityH: capacity?.capacityHoursByDay[dayIndex] ?? 8, })), ); } } return nextMetrics; }