refactor(api): centralize timeline read detail schemas

This commit is contained in:
2026-03-31 18:22:20 +02:00
parent 4758c96543
commit 66a33a5ad6
4 changed files with 55 additions and 22 deletions
@@ -1,6 +1,8 @@
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { import {
buildTimelineEntriesDetailInput, buildTimelineEntriesDetailInput,
TimelineDetailFiltersSchema,
TimelineProjectContextDetailSchema,
} from "../router/timeline-read-shared.js"; } from "../router/timeline-read-shared.js";
describe("timeline read shared", () => { describe("timeline read shared", () => {
@@ -39,4 +41,32 @@ describe("timeline read shared", () => {
}); });
}); });
it("shares detail filter schemas across timeline read endpoints", () => {
expect(TimelineDetailFiltersSchema.parse({
startDate: "2026-04-01",
durationDays: 14,
resourceIds: ["resource_1"],
countryCodes: ["DE"],
})).toEqual({
startDate: "2026-04-01",
endDate: undefined,
durationDays: 14,
resourceIds: ["resource_1"],
projectIds: undefined,
clientIds: undefined,
chapters: undefined,
eids: undefined,
countryCodes: ["DE"],
});
expect(TimelineProjectContextDetailSchema.parse({
projectId: "project_1",
endDate: "2026-04-20",
})).toEqual({
projectId: "project_1",
startDate: undefined,
endDate: "2026-04-20",
durationDays: undefined,
});
});
}); });
+2 -14
View File
@@ -1,6 +1,6 @@
import { z } from "zod";
import { controllerProcedure, protectedProcedure } from "../trpc.js"; import { controllerProcedure, protectedProcedure } from "../trpc.js";
import { import {
TimelineDetailFiltersSchema,
TimelineWindowFiltersSchema, TimelineWindowFiltersSchema,
} from "./timeline-read-shared.js"; } from "./timeline-read-shared.js";
import { import {
@@ -24,18 +24,6 @@ export const timelineEntryReadProcedures = {
.query(({ ctx, input }) => readMyTimelineEntriesView(ctx, input)), .query(({ ctx, input }) => readMyTimelineEntriesView(ctx, input)),
getEntriesDetail: controllerProcedure getEntriesDetail: controllerProcedure
.input( .input(TimelineDetailFiltersSchema)
z.object({
startDate: z.string().optional(),
endDate: z.string().optional(),
durationDays: z.number().int().min(1).max(366).optional(),
resourceIds: z.array(z.string()).optional(),
projectIds: z.array(z.string()).optional(),
clientIds: z.array(z.string()).optional(),
chapters: z.array(z.string()).optional(),
eids: z.array(z.string()).optional(),
countryCodes: z.array(z.string()).optional(),
}),
)
.query(({ ctx, input }) => readTimelineEntriesDetail(ctx.db, input)), .query(({ ctx, input }) => readTimelineEntriesDetail(ctx.db, input)),
}; };
@@ -2,6 +2,9 @@ import { ShiftProjectSchema } from "@capakraken/shared";
import { z } from "zod"; import { z } from "zod";
import { controllerProcedure } from "../trpc.js"; import { controllerProcedure } from "../trpc.js";
import { previewTimelineProjectShift } from "./timeline-project-load-support.js"; import { previewTimelineProjectShift } from "./timeline-project-load-support.js";
import {
TimelineProjectContextDetailSchema,
} from "./timeline-read-shared.js";
import { import {
readTimelineProjectBudgetStatusResponse, readTimelineProjectBudgetStatusResponse,
readTimelineProjectContextDetailResponse, readTimelineProjectContextDetailResponse,
@@ -15,14 +18,7 @@ export const timelineProjectReadProcedures = {
.query(async ({ ctx, input }) => readTimelineProjectContextResponse(ctx.db, input.projectId)), .query(async ({ ctx, input }) => readTimelineProjectContextResponse(ctx.db, input.projectId)),
getProjectContextDetail: controllerProcedure getProjectContextDetail: controllerProcedure
.input( .input(TimelineProjectContextDetailSchema)
z.object({
projectId: z.string(),
startDate: z.string().optional(),
endDate: z.string().optional(),
durationDays: z.number().int().min(1).max(366).optional(),
}),
)
.query(async ({ ctx, input }) => readTimelineProjectContextDetailResponse(ctx.db, input)), .query(async ({ ctx, input }) => readTimelineProjectContextDetailResponse(ctx.db, input)),
previewShift: controllerProcedure previewShift: controllerProcedure
@@ -41,6 +41,25 @@ export const TimelineWindowFiltersSchema = z.object({
countryCodes: z.array(z.string()).optional(), countryCodes: z.array(z.string()).optional(),
}); });
export const TimelineDetailFiltersSchema = z.object({
startDate: z.string().optional(),
endDate: z.string().optional(),
durationDays: z.number().int().min(1).max(366).optional(),
resourceIds: z.array(z.string()).optional(),
projectIds: z.array(z.string()).optional(),
clientIds: z.array(z.string()).optional(),
chapters: z.array(z.string()).optional(),
eids: z.array(z.string()).optional(),
countryCodes: z.array(z.string()).optional(),
});
export const TimelineProjectContextDetailSchema = z.object({
projectId: z.string(),
startDate: z.string().optional(),
endDate: z.string().optional(),
durationDays: z.number().int().min(1).max(366).optional(),
});
type TimelineWindowFiltersInput = z.infer<typeof TimelineWindowFiltersSchema>; type TimelineWindowFiltersInput = z.infer<typeof TimelineWindowFiltersSchema>;
export function getAssignmentResourceIds( export function getAssignmentResourceIds(