Files
Nexus/apps/web/src/components/timeline/timelineProjectMetrics.ts
T

75 lines
2.2 KiB
TypeScript

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<string, number[]>,
resourceCapacityById: Map<string, ResourceCapacitySeries>,
): Map<string, ProjectDayMetric[]> {
const dateIndexByTime = new Map<number, number>();
dates.forEach((date, index) => {
const normalized = new Date(date);
normalized.setHours(0, 0, 0, 0);
dateIndexByTime.set(normalized.getTime(), index);
});
const nextMetrics = new Map<string, ProjectDayMetric[]>();
for (const project of projectGroups) {
for (const { resource, allocs } of project.resourceRows) {
const projectHours = new Array<number>(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;
}