85 lines
2.7 KiB
TypeScript
85 lines
2.7 KiB
TypeScript
import { fmtDate, rangesOverlap, toDate } from "./timeline-read-shared.js";
|
|
|
|
export interface TimelineProjectAssignmentConflict {
|
|
assignmentId: string;
|
|
resourceId: string;
|
|
resourceName: string | null;
|
|
startDate: string | null;
|
|
endDate: string | null;
|
|
hoursPerDay: number;
|
|
overlapCount: number;
|
|
crossProjectOverlapCount: number;
|
|
overlaps: Array<{
|
|
id: string;
|
|
projectId: string | null;
|
|
projectName: string | null;
|
|
projectShortCode: string | null;
|
|
startDate: string | null;
|
|
endDate: string | null;
|
|
hoursPerDay: number;
|
|
status: string;
|
|
sameProject: boolean;
|
|
}>;
|
|
}
|
|
|
|
export function buildTimelineProjectAssignmentConflicts(input: {
|
|
projectId: string;
|
|
assignments: Array<{
|
|
id: string;
|
|
resourceId: string | null;
|
|
resource?: { displayName?: string | null } | null;
|
|
startDate: Date | string;
|
|
endDate: Date | string;
|
|
hoursPerDay: number;
|
|
}>;
|
|
allResourceAllocations: Array<{
|
|
id: string;
|
|
resourceId: string | null;
|
|
projectId: string | null;
|
|
project?: { name?: string | null; shortCode?: string | null } | null;
|
|
startDate: Date | string;
|
|
endDate: Date | string;
|
|
hoursPerDay: number;
|
|
status: string;
|
|
}>;
|
|
}): TimelineProjectAssignmentConflict[] {
|
|
return input.assignments
|
|
.filter((assignment) => assignment.resourceId && assignment.resource)
|
|
.map((assignment) => {
|
|
const overlaps = input.allResourceAllocations
|
|
.filter((booking) => (
|
|
booking.resourceId === assignment.resourceId
|
|
&& booking.id !== assignment.id
|
|
&& rangesOverlap(
|
|
toDate(booking.startDate),
|
|
toDate(booking.endDate),
|
|
toDate(assignment.startDate),
|
|
toDate(assignment.endDate),
|
|
)
|
|
))
|
|
.map((booking) => ({
|
|
id: booking.id,
|
|
projectId: booking.projectId,
|
|
projectName: booking.project?.name ?? null,
|
|
projectShortCode: booking.project?.shortCode ?? null,
|
|
startDate: fmtDate(toDate(booking.startDate)),
|
|
endDate: fmtDate(toDate(booking.endDate)),
|
|
hoursPerDay: booking.hoursPerDay,
|
|
status: booking.status,
|
|
sameProject: booking.projectId === input.projectId,
|
|
}));
|
|
|
|
return {
|
|
assignmentId: assignment.id,
|
|
resourceId: assignment.resourceId!,
|
|
resourceName: assignment.resource?.displayName ?? null,
|
|
startDate: fmtDate(toDate(assignment.startDate)),
|
|
endDate: fmtDate(toDate(assignment.endDate)),
|
|
hoursPerDay: assignment.hoursPerDay,
|
|
overlapCount: overlaps.length,
|
|
crossProjectOverlapCount: overlaps.filter((booking) => !booking.sameProject).length,
|
|
overlaps,
|
|
};
|
|
});
|
|
}
|