Files
CapaKraken/packages/api/src/router/timeline-project-context-response-support.ts
T

125 lines
3.9 KiB
TypeScript

import {
fmtDate,
} from "./timeline-read-shared.js";
import {
anonymizeResourceOnEntry,
summarizeTimelineEntries,
} from "./timeline-entry-response-support.js";
import {
summarizeHolidayOverlays,
} from "./timeline-holiday-read.js";
type TimelineAnonymizationDirectory = Parameters<typeof anonymizeResourceOnEntry>[1];
export function buildTimelineProjectContextSummary(input: {
allocations: Array<{ projectId: string | null; resourceId: string | null }>;
demands: Array<{ projectId: string | null }>;
assignments: Array<{ projectId: string | null; resourceId: string | null }>;
resourceIds: string[];
allResourceAllocations: unknown[];
assignmentConflicts: Array<{ crossProjectOverlapCount: number }>;
holidayOverlays: Parameters<typeof summarizeHolidayOverlays>[0];
}) {
return {
...summarizeTimelineEntries({
allocations: input.allocations,
demands: input.demands,
assignments: input.assignments,
}),
resourceIds: input.resourceIds.length,
allResourceAllocationCount: input.allResourceAllocations.length,
conflictedAssignmentCount: input.assignmentConflicts.filter(
(item) => item.crossProjectOverlapCount > 0,
).length,
...summarizeHolidayOverlays(input.holidayOverlays),
};
}
export function buildTimelineProjectContextResponse<
TProject,
TAllocation extends { resource?: { id: string } | null },
TDemand,
TAssignment extends { resource?: { id: string } | null },
TBooking extends { resource?: { id: string } | null },
>(input: {
project: TProject;
allocations: TAllocation[];
demands: TDemand[];
assignments: TAssignment[];
allResourceAllocations: TBooking[];
resourceIds: string[];
directory: TimelineAnonymizationDirectory;
}) {
return {
project: input.project,
allocations: input.allocations.map((allocation) =>
anonymizeResourceOnEntry(allocation, input.directory),
),
demands: input.demands,
assignments: input.assignments.map((assignment) =>
anonymizeResourceOnEntry(assignment, input.directory),
),
allResourceAllocations: input.allResourceAllocations.map((allocation) =>
anonymizeResourceOnEntry(allocation, input.directory),
),
resourceIds: input.resourceIds,
};
}
export function buildTimelineProjectContextDetailResponse<
TProject,
TAllocation extends {
projectId: string | null;
resourceId: string | null;
resource?: { id: string } | null;
},
TDemand extends { projectId: string | null },
TAssignment extends {
projectId: string | null;
resourceId: string | null;
resource?: { id: string } | null;
},
TBooking extends { resource?: { id: string } | null },
TConflict extends { crossProjectOverlapCount: number },
>(input: {
project: TProject;
period: { startDate: Date; endDate: Date };
allocations: TAllocation[];
demands: TDemand[];
assignments: TAssignment[];
allResourceAllocations: TBooking[];
resourceIds: string[];
assignmentConflicts: TConflict[];
holidayOverlays: Parameters<typeof summarizeHolidayOverlays>[0];
directory: TimelineAnonymizationDirectory;
}) {
const base = buildTimelineProjectContextResponse({
project: input.project,
allocations: input.allocations,
demands: input.demands,
assignments: input.assignments,
allResourceAllocations: input.allResourceAllocations,
resourceIds: input.resourceIds,
directory: input.directory,
});
return {
...base,
period: {
startDate: fmtDate(input.period.startDate),
endDate: fmtDate(input.period.endDate),
},
summary: buildTimelineProjectContextSummary({
allocations: input.allocations,
demands: input.demands,
assignments: input.assignments,
resourceIds: input.resourceIds,
allResourceAllocations: input.allResourceAllocations,
assignmentConflicts: input.assignmentConflicts,
holidayOverlays: input.holidayOverlays,
}),
assignmentConflicts: input.assignmentConflicts,
holidayOverlays: input.holidayOverlays,
};
}