feat: add more routing forms data (#17229)
Co-authored-by: Omar López <zomars@me.com>
This commit is contained in:
co-authored by
Omar López
parent
52e1a58904
commit
1c8cf62582
@@ -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({
|
||||
|
||||
Reference in New Issue
Block a user