feat: add more routing forms data (#17229)

Co-authored-by: Omar López <zomars@me.com>
This commit is contained in:
Keith Williams
2024-10-25 02:00:37 +00:00
committed by GitHub
co-authored by Omar López
parent 52e1a58904
commit 1c8cf62582
2 changed files with 81 additions and 15 deletions
@@ -323,11 +323,16 @@ test.describe("Routing Forms", () => {
"Multi Select",
"Legacy Select",
"Select",
// TODO: Find a way to incorporate Routed To and Booked At into the report
// @see https://github.com/calcom/cal.com/pull/17229
"Routed To",
"Booked At",
]);
/* Last two columns are "Routed To" and "Booked At" */
expect(responses).toEqual([
["event-routing", "Option-2", "Option-2", "Option-2", "Option-2"],
["external-redirect", "Option-2", "Option-2", "Option-2", "Option-2"],
["custom-page", "Option-2", "Option-2", "Option-2", "Option-2"],
["event-routing", "Option-2", "Option-2", "Option-2", "Option-2", "", ""],
["external-redirect", "Option-2", "Option-2", "Option-2", "Option-2", "", ""],
["custom-page", "Option-2", "Option-2", "Option-2", "Option-2", "", ""],
]);
await page.goto(`apps/routing-forms/route-builder/${routingForm.id}`);
@@ -4,6 +4,7 @@ import logger from "@calcom/lib/logger";
import type { PrismaClient } from "@calcom/prisma";
import type { App_RoutingForms_FormResponse } from "@calcom/prisma/client";
import { TRPCError } from "@calcom/trpc/server";
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
import { jsonLogicToPrisma } from "../jsonLogicToPrisma";
import { getSerializableForm } from "../lib/getSerializableForm";
@@ -15,11 +16,23 @@ import type { TReportInputSchema } from "./report.schema";
interface ReportHandlerOptions {
ctx: {
prisma: PrismaClient;
user: NonNullable<TrpcSessionUser>;
};
input: TReportInputSchema;
}
export const reportHandler = async ({ ctx: { prisma }, input }: ReportHandlerOptions) => {
const makeFormatDate = (locale: string, timeZone: string) => {
const formatDate = (date: Date): string => {
return new Intl.DateTimeFormat(locale, {
timeZone,
dateStyle: "medium",
timeStyle: "short",
}).format(date);
};
return formatDate;
};
const getRows = async ({ ctx: { prisma }, input }: ReportHandlerOptions) => {
// Can be any prisma `where` clause
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const prismaWhere: Record<string, any> = input.jsonLogicQuery
@@ -32,6 +45,32 @@ export const reportHandler = async ({ ctx: { prisma }, input }: ReportHandlerOpt
input.jsonLogicQuery
)}`
);
const rows = await prisma.app_RoutingForms_FormResponse.findMany({
where: {
formId: input.formId,
...prismaWhere,
},
include: {
routedToBooking: {
select: {
createdAt: true,
user: {
select: { id: true, name: true, email: true },
},
},
},
},
take,
skip,
});
return { skip, take, rows };
};
export const reportHandler = async (options: ReportHandlerOptions) => {
const {
ctx: { prisma },
input,
} = options;
const form = await prisma.app_RoutingForms_Form.findUnique({
where: {
id: input.formId,
@@ -46,15 +85,7 @@ export const reportHandler = async ({ ctx: { prisma }, input }: ReportHandlerOpt
}
// TODO: Second argument is required to return deleted operators.
const serializedForm = await getSerializableForm({ form, withDeletedFields: true });
const rows = await prisma.app_RoutingForms_FormResponse.findMany({
where: {
formId: input.formId,
...prismaWhere,
},
take,
skip,
});
const { rows, skip, take } = await getRows(options);
const fields = serializedForm?.fields || [];
const { responses, headers } = buildResponsesForReporting({
@@ -63,13 +94,43 @@ export const reportHandler = async ({ ctx: { prisma }, input }: ReportHandlerOpt
});
const areThereNoResultsOrLessThanAskedFor = !rows.length || rows.length < take;
return {
return presenter({
rows,
options,
headers,
responses,
nextCursor: areThereNoResultsOrLessThanAskedFor ? null : skip + rows.length,
};
});
};
/**
* This is a temporary solution to make the report work. It should be incorporated into the report data itself.
* Right now we cannot filter by Routed To and Booked At because they are not part of the response data.
*/
function presenter(args: {
rows: Awaited<ReturnType<typeof getRows>>["rows"];
options: ReportHandlerOptions;
headers: string[];
responses: string[][];
nextCursor: number | null;
}) {
const { headers, responses, nextCursor, options, rows } = args;
const { ctx } = options;
const formatDate = makeFormatDate(ctx.user.locale, ctx.user.timeZone);
return {
nextCursor,
headers: [...headers, "Routed To", "Booked At"],
responses: responses.map((r, i) => {
const currentRow = rows[i];
return [
...r,
currentRow.routedToBooking?.user?.email || "",
currentRow.routedToBooking?.createdAt ? formatDate(currentRow.routedToBooking.createdAt) : "",
];
}),
};
}
export default reportHandler;
export function buildResponsesForReporting({