106 lines
3.4 KiB
TypeScript
106 lines
3.4 KiB
TypeScript
import { ProjectStatus } from "@capakraken/shared";
|
|
import { TRPCError } from "@trpc/server";
|
|
import { z } from "zod";
|
|
import { controllerProcedure, planningReadProcedure } from "../trpc.js";
|
|
import {
|
|
mapProjectDetail,
|
|
mapProjectSummary,
|
|
mapProjectSummaryDetail,
|
|
readProjectByIdentifierDetailSnapshot,
|
|
readProjectSummariesSnapshot,
|
|
readProjectSummaryDetailsSnapshot,
|
|
resolveProjectIdentifierSnapshot,
|
|
} from "./project-read-shared.js";
|
|
|
|
export const projectIdentifierReadProcedures = {
|
|
resolveByIdentifier: planningReadProcedure
|
|
.input(z.object({ identifier: z.string() }))
|
|
.query(async ({ ctx, input }) => {
|
|
const select = {
|
|
id: true,
|
|
shortCode: true,
|
|
name: true,
|
|
status: true,
|
|
responsiblePerson: true,
|
|
startDate: true,
|
|
endDate: true,
|
|
} as const;
|
|
|
|
let project = await ctx.db.project.findUnique({
|
|
where: { id: input.identifier },
|
|
select,
|
|
});
|
|
if (!project) {
|
|
project = await ctx.db.project.findUnique({
|
|
where: { shortCode: input.identifier },
|
|
select,
|
|
});
|
|
}
|
|
if (!project) {
|
|
project = await ctx.db.project.findFirst({
|
|
where: { name: { equals: input.identifier, mode: "insensitive" } },
|
|
select,
|
|
});
|
|
}
|
|
if (!project) {
|
|
project = await ctx.db.project.findFirst({
|
|
where: { name: { contains: input.identifier, mode: "insensitive" } },
|
|
select,
|
|
});
|
|
}
|
|
|
|
if (!project) {
|
|
throw new TRPCError({ code: "NOT_FOUND", message: "Project not found" });
|
|
}
|
|
|
|
return project;
|
|
}),
|
|
|
|
searchSummaries: planningReadProcedure
|
|
.input(z.object({
|
|
search: z.string().optional(),
|
|
status: z.nativeEnum(ProjectStatus).optional(),
|
|
limit: z.number().int().min(1).max(50).default(20),
|
|
}))
|
|
.query(async ({ ctx, input }) => {
|
|
const { items, exactMatch } = await readProjectSummariesSnapshot(ctx, input);
|
|
const formatted = items.map(mapProjectSummary);
|
|
if (items.length > 0 && input.search && !exactMatch) {
|
|
return {
|
|
suggestions: formatted,
|
|
note: `No exact match for "${input.search}". These projects match some of the search terms:`,
|
|
};
|
|
}
|
|
return formatted;
|
|
}),
|
|
|
|
searchSummariesDetail: controllerProcedure
|
|
.input(z.object({
|
|
search: z.string().optional(),
|
|
status: z.nativeEnum(ProjectStatus).optional(),
|
|
limit: z.number().int().min(1).max(50).default(20),
|
|
}))
|
|
.query(async ({ ctx, input }) => {
|
|
const { items, exactMatch } = await readProjectSummaryDetailsSnapshot(ctx, input);
|
|
const formatted = items.map(mapProjectSummaryDetail);
|
|
if (items.length > 0 && input.search && !exactMatch) {
|
|
return {
|
|
suggestions: formatted,
|
|
note: `No exact match for "${input.search}". These projects match some of the search terms:`,
|
|
};
|
|
}
|
|
return formatted;
|
|
}),
|
|
|
|
getByIdentifier: planningReadProcedure
|
|
.input(z.object({ identifier: z.string() }))
|
|
.query(async ({ ctx, input }) => resolveProjectIdentifierSnapshot(ctx, input.identifier)),
|
|
|
|
getByIdentifierDetail: controllerProcedure
|
|
.input(z.object({ identifier: z.string() }))
|
|
.query(async ({ ctx, input }) => {
|
|
const project = await readProjectByIdentifierDetailSnapshot(ctx, input.identifier);
|
|
return mapProjectDetail(project, project.topAssignments);
|
|
}),
|
|
};
|