chore(repo): initialize planarchy workspace

This commit is contained in:
2026-03-14 14:31:09 +01:00
commit dd55d0e78b
769 changed files with 166461 additions and 0 deletions
@@ -0,0 +1,75 @@
import type { PrismaClient } from "@planarchy/db";
import { listAssignmentBookings } from "../allocation/list-assignment-bookings.js";
import { getAverageDailyAvailabilityHours, getMonthBucketKey, getWeekBucketKey } from "./shared.js";
export interface GetDashboardPeakTimesInput {
startDate: Date;
endDate: Date;
granularity: "week" | "month";
groupBy: "project" | "chapter" | "resource";
}
export async function getDashboardPeakTimes(
db: PrismaClient,
input: GetDashboardPeakTimesInput,
) {
const allocations = await listAssignmentBookings(db, {
startDate: input.startDate,
endDate: input.endDate,
});
const buckets = new Map<string, Map<string, number>>();
const getBucketKey = input.granularity === "week" ? getWeekBucketKey : getMonthBucketKey;
for (const allocation of allocations) {
const allocStart = new Date(
Math.max(allocation.startDate.getTime(), input.startDate.getTime()),
);
const allocEnd = new Date(
Math.min(allocation.endDate.getTime(), input.endDate.getTime()),
);
const group =
input.groupBy === "project"
? allocation.project.shortCode
: input.groupBy === "chapter"
? allocation.resource?.chapter ?? "Unassigned"
: allocation.resource?.displayName ?? "Unknown";
const cursor = new Date(allocStart);
while (cursor <= allocEnd) {
const bucketKey = getBucketKey(cursor);
if (!buckets.has(bucketKey)) {
buckets.set(bucketKey, new Map());
}
const bucket = buckets.get(bucketKey)!;
bucket.set(group, (bucket.get(group) ?? 0) + allocation.hoursPerDay);
cursor.setDate(cursor.getDate() + 1);
}
}
const resources = await db.resource.findMany({
where: { isActive: true },
select: { availability: true },
});
const dailyCapacityHours = resources.reduce(
(sum, resource) =>
sum +
getAverageDailyAvailabilityHours(
resource.availability as Record<string, number | null | undefined>,
),
0,
);
return [...buckets.entries()]
.sort(([left], [right]) => left.localeCompare(right))
.map(([period, groups]) => ({
period,
groups: [...groups.entries()].map(([name, hours]) => ({ name, hours })),
totalHours: [...groups.values()].reduce((sum, hours) => sum + hours, 0),
capacityHours:
dailyCapacityHours * (input.granularity === "week" ? 5 : 22),
}));
}