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

122 lines
3.8 KiB
TypeScript

import { TRPCError } from "@trpc/server";
import {
buildTimelineProjectAssignmentConflicts,
} from "./timeline-project-conflict-support.js";
import {
formatHolidayOverlays,
loadTimelineHolidayOverlays,
} from "./timeline-holiday-read.js";
import {
createTimelineDateRange,
fmtDate,
toDate,
} from "./timeline-read-shared.js";
export interface ResolveTimelineProjectContextPeriodInput {
requestedStartDate?: string | undefined;
requestedEndDate?: string | undefined;
durationDays?: number | undefined;
projectStartDate?: Date | null | undefined;
projectEndDate?: Date | null | undefined;
firstAssignmentStartDate?: Date | string | null | undefined;
firstDemandStartDate?: Date | string | null | undefined;
}
export function resolveTimelineProjectContextPeriod(
input: ResolveTimelineProjectContextPeriodInput,
) {
const startDate = input.requestedStartDate
? createTimelineDateRange({
startDate: input.requestedStartDate,
durationDays: 1,
}).startDate
: input.projectStartDate
?? (input.firstAssignmentStartDate ? toDate(input.firstAssignmentStartDate) : null)
?? (input.firstDemandStartDate ? toDate(input.firstDemandStartDate) : null)
?? createTimelineDateRange({ durationDays: 1 }).startDate;
const endDate = input.requestedEndDate
? createTimelineDateRange({
startDate: fmtDate(startDate) ?? undefined,
endDate: input.requestedEndDate,
}).endDate
: input.projectEndDate
?? createTimelineDateRange({
startDate: fmtDate(startDate) ?? undefined,
durationDays: input.durationDays ?? 21,
}).endDate;
if (endDate < startDate) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "endDate must be on or after startDate.",
});
}
return { startDate, endDate };
}
export async function loadTimelineProjectContextDetailArtifacts(
db: Parameters<typeof loadTimelineHolidayOverlays>[0],
input: {
projectId: string;
requestedStartDate?: string | undefined;
requestedEndDate?: string | undefined;
durationDays?: number | undefined;
projectStartDate?: Date | null | undefined;
projectEndDate?: Date | null | undefined;
firstAssignmentStartDate?: Date | string | null | undefined;
firstDemandStartDate?: Date | string | null | undefined;
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;
}>;
resourceIds: string[];
},
) {
const period = resolveTimelineProjectContextPeriod({
requestedStartDate: input.requestedStartDate,
requestedEndDate: input.requestedEndDate,
durationDays: input.durationDays,
projectStartDate: input.projectStartDate,
projectEndDate: input.projectEndDate,
firstAssignmentStartDate: input.firstAssignmentStartDate,
firstDemandStartDate: input.firstDemandStartDate,
});
const holidayOverlays = input.resourceIds.length > 0
? formatHolidayOverlays(await loadTimelineHolidayOverlays(db, {
startDate: period.startDate,
endDate: period.endDate,
resourceIds: input.resourceIds,
projectIds: [input.projectId],
}))
: [];
const assignmentConflicts = buildTimelineProjectAssignmentConflicts({
projectId: input.projectId,
assignments: input.assignments,
allResourceAllocations: input.allResourceAllocations,
});
return {
period,
holidayOverlays,
assignmentConflicts,
};
}