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,105 @@
import { renderToBuffer } from "@react-pdf/renderer";
import { createElement } from "react";
import { NextResponse } from "next/server";
import * as XLSX from "xlsx";
import { buildSplitAllocationReadModel } from "@planarchy/application";
import { prisma } from "@planarchy/db";
import type { AllocationLike } from "@planarchy/shared";
import { auth } from "~/server/auth.js";
import { AllocationReport } from "~/components/reports/AllocationReport.js";
export async function GET(request: Request) {
const session = await auth();
if (!session?.user) {
return new NextResponse("Unauthorized", { status: 401 });
}
const { searchParams } = new URL(request.url);
const startDate = searchParams.get("startDate") ? new Date(searchParams.get("startDate")!) : new Date();
const endDate = searchParams.get("endDate") ? new Date(searchParams.get("endDate")!) : new Date(Date.now() + 90 * 24 * 60 * 60 * 1000);
const format = searchParams.get("format") ?? "pdf";
const [demandRequirements, assignments] = await Promise.all([
prisma.demandRequirement.findMany({
where: {
status: { not: "CANCELLED" },
startDate: { lte: endDate },
endDate: { gte: startDate },
},
include: {
project: { select: { id: true, name: true, shortCode: true } },
},
orderBy: [{ project: { name: "asc" } }, { startDate: "asc" }],
take: 1000,
}),
prisma.assignment.findMany({
where: {
status: { not: "CANCELLED" },
startDate: { lte: endDate },
endDate: { gte: startDate },
},
include: {
resource: { select: { id: true, displayName: true, eid: true, lcrCents: true } },
project: { select: { id: true, name: true, shortCode: true } },
},
orderBy: [{ project: { name: "asc" } }, { startDate: "asc" }],
take: 1000,
}),
]);
const allocationView = buildSplitAllocationReadModel({
demandRequirements,
assignments,
});
const assignmentRows = allocationView.assignments.slice(0, 500);
const rows = assignmentRows.map((a: AllocationLike & {
resource?: { displayName?: string | null } | null;
project?: { shortCode: string; name: string } | null;
}) => ({
resourceName: a.resource?.displayName ?? "Unknown",
projectName: a.project ? `${a.project.shortCode}${a.project.name}` : "Unknown project",
role: a.role ?? "",
startDate: new Date(a.startDate).toLocaleDateString("en-GB"),
endDate: new Date(a.endDate).toLocaleDateString("en-GB"),
hoursPerDay: a.hoursPerDay,
dailyCostCents: a.dailyCostCents,
}));
const ts = Date.now();
if (format === "xlsx") {
const sheetData = rows.map((r: typeof rows[number]) => ({
Resource: r.resourceName,
Project: r.projectName,
Role: r.role,
"Start Date": r.startDate,
"End Date": r.endDate,
"Hours/Day": r.hoursPerDay,
"Daily Cost (ct)": r.dailyCostCents,
}));
const ws = XLSX.utils.json_to_sheet(sheetData);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "Allocations");
const buffer = XLSX.write(wb, { type: "buffer", bookType: "xlsx" }) as Buffer;
return new NextResponse(buffer as unknown as BodyInit, {
headers: {
"Content-Type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"Content-Disposition": `attachment; filename="allocations-${ts}.xlsx"`,
},
});
}
const title = `Allocation Report ${startDate.toLocaleDateString("en-GB")} ${endDate.toLocaleDateString("en-GB")}`;
const generatedAt = new Date().toLocaleString("en-GB");
const doc = createElement(AllocationReport, { title, generatedAt, rows });
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const buffer = await renderToBuffer(doc as any);
return new NextResponse(buffer as unknown as BodyInit, {
headers: {
"Content-Type": "application/pdf",
"Content-Disposition": `attachment; filename="allocations-${ts}.pdf"`,
},
});
}