refactor(api): align timeline project read routing

This commit is contained in:
2026-03-31 18:49:51 +02:00
parent 850ea864f4
commit 1c5c203a89
5 changed files with 46 additions and 5 deletions
@@ -41,6 +41,7 @@ import {
} from "../router/timeline-project-query-support.js";
import {
readTimelineProjectBudgetStatusResponse,
readTimelineProjectShiftPreview,
readTimelineProjectShiftPreviewDetail,
} from "../router/timeline-project-procedure-support.js";
@@ -89,6 +90,24 @@ describe("timeline project procedure support", () => {
});
});
it("loads plain shift preview responses through procedure support", async () => {
previewTimelineProjectShiftMock.mockResolvedValueOnce({ valid: true } as never);
await expect(
readTimelineProjectShiftPreview({} as never, {
projectId: "project_1",
newStartDate: new Date("2026-04-03T00:00:00.000Z"),
newEndDate: new Date("2026-04-12T00:00:00.000Z"),
}),
).resolves.toEqual({ valid: true });
expect(previewTimelineProjectShiftMock).toHaveBeenCalledWith({}, {
projectId: "project_1",
newStartDate: new Date("2026-04-03T00:00:00.000Z"),
newEndDate: new Date("2026-04-12T00:00:00.000Z"),
});
});
it("builds budget status responses from project bookings", async () => {
findTimelineProjectOrThrowMock.mockResolvedValueOnce({
id: "project_1",
@@ -3,6 +3,7 @@ import {
buildTimelineEntriesDetailInput,
TimelineDetailFiltersSchema,
TimelineProjectContextDetailSchema,
TimelineProjectIdSchema,
} from "../router/timeline-read-shared.js";
describe("timeline read shared", () => {
@@ -68,5 +69,11 @@ describe("timeline read shared", () => {
endDate: "2026-04-20",
durationDays: undefined,
});
expect(TimelineProjectIdSchema.parse({
projectId: "project_1",
})).toEqual({
projectId: "project_1",
});
});
});
@@ -45,6 +45,17 @@ export async function readTimelineProjectShiftPreviewDetail(
});
}
export async function readTimelineProjectShiftPreview(
db: TimelineProjectProcedureDb,
input: {
projectId: string;
newStartDate: Date;
newEndDate: Date;
},
) {
return previewTimelineProjectShift(db, input);
}
export async function readTimelineProjectBudgetStatusResponse(
db: TimelineProjectProcedureDb,
projectId: string,
@@ -1,9 +1,8 @@
import { ShiftProjectSchema } from "@capakraken/shared";
import { z } from "zod";
import { controllerProcedure } from "../trpc.js";
import { previewTimelineProjectShift } from "./timeline-project-load-support.js";
import {
TimelineProjectContextDetailSchema,
TimelineProjectIdSchema,
} from "./timeline-read-shared.js";
import {
readTimelineProjectContextDetailResponse,
@@ -11,12 +10,13 @@ import {
} from "./timeline-project-context-procedure-support.js";
import {
readTimelineProjectBudgetStatusResponse,
readTimelineProjectShiftPreview,
readTimelineProjectShiftPreviewDetail,
} from "./timeline-project-procedure-support.js";
export const timelineProjectReadProcedures = {
getProjectContext: controllerProcedure
.input(z.object({ projectId: z.string() }))
.input(TimelineProjectIdSchema)
.query(async ({ ctx, input }) => readTimelineProjectContextResponse(ctx.db, input.projectId)),
getProjectContextDetail: controllerProcedure
@@ -25,13 +25,13 @@ export const timelineProjectReadProcedures = {
previewShift: controllerProcedure
.input(ShiftProjectSchema)
.query(async ({ ctx, input }) => previewTimelineProjectShift(ctx.db, input)),
.query(async ({ ctx, input }) => readTimelineProjectShiftPreview(ctx.db, input)),
getShiftPreviewDetail: controllerProcedure
.input(ShiftProjectSchema)
.query(async ({ ctx, input }) => readTimelineProjectShiftPreviewDetail(ctx.db, input)),
getBudgetStatus: controllerProcedure
.input(z.object({ projectId: z.string() }))
.input(TimelineProjectIdSchema)
.query(async ({ ctx, input }) => readTimelineProjectBudgetStatusResponse(ctx.db, input.projectId)),
};
@@ -60,6 +60,10 @@ export const TimelineProjectContextDetailSchema = z.object({
durationDays: z.number().int().min(1).max(366).optional(),
});
export const TimelineProjectIdSchema = z.object({
projectId: z.string(),
});
type TimelineWindowFiltersInput = z.infer<typeof TimelineWindowFiltersSchema>;
export function getAssignmentResourceIds(