diff --git a/apps/web/app/(use-page-wrapper)/apps/routing-forms/[...pages]/FormEdit.tsx b/apps/web/app/(use-page-wrapper)/apps/routing-forms/[...pages]/FormEdit.tsx
index 0a8af241222b3d..f693a2f05df0ab 100644
--- a/apps/web/app/(use-page-wrapper)/apps/routing-forms/[...pages]/FormEdit.tsx
+++ b/apps/web/app/(use-page-wrapper)/apps/routing-forms/[...pages]/FormEdit.tsx
@@ -164,7 +164,9 @@ function Field({
"h-8 w-full justify-between text-left text-sm",
!!router && "bg-subtle cursor-not-allowed"
)}>
- {defaultValue?.label || t("select_field_type")}
+
+ {defaultValue?.label || t("select_field_type")}
+
@@ -201,7 +203,7 @@ function Field({
}}
/>
- {["select", "multiselect"].includes(fieldType) ? (
+ {["select", "multiselect", "checkbox", "radio"].includes(fieldType) ? (
({
@@ -25,6 +24,9 @@ const assertCommonWidgetTypes = (config: any) => {
expect(config.widgets).toHaveProperty("select");
expect(config.widgets).toHaveProperty("phone");
expect(config.widgets).toHaveProperty("email");
+ expect(config.widgets).toHaveProperty("address");
+ expect(config.widgets).toHaveProperty("url");
+ expect(config.widgets).toHaveProperty("multiemail");
};
const assertSelectOperators = (config: any) => {
@@ -95,7 +97,7 @@ describe("Query Builder Config", () => {
);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore
+ // @ts-expect-error
const jsonLogic = AttributesBaseConfig.operators.multiselect_some_in.jsonLogic(
["A"],
"multiselect_some_in",
@@ -122,7 +124,7 @@ describe("Query Builder Config", () => {
it("should provide jsonlogic for between operator", () => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore
+ // @ts-expect-error
const jsonLogic = AttributesBaseConfig.operators.between.jsonLogic(
{ var: "89ee81ae-953c-409b-aacc-700e1ce5ae20" },
"between",
@@ -140,7 +142,7 @@ describe("Query Builder Config", () => {
it("should provide jsonlogic for not_between operator", () => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-ignore
+ // @ts-expect-error
const jsonLogic = AttributesBaseConfig.operators.not_between.jsonLogic(
{ var: "89ee81ae-953c-409b-aacc-700e1ce5ae20" },
"not_between",
diff --git a/packages/app-store/routing-forms/__tests__/uiConfig.test.ts b/packages/app-store/routing-forms/__tests__/uiConfig.test.ts
index 2eac86afc6c1b5..19b0e60abb52d1 100644
--- a/packages/app-store/routing-forms/__tests__/uiConfig.test.ts
+++ b/packages/app-store/routing-forms/__tests__/uiConfig.test.ts
@@ -1,6 +1,5 @@
import type { Settings } from "react-awesome-query-builder";
-import { describe, it, vi, expect } from "vitest";
-
+import { describe, expect, it, vi } from "vitest";
import {
ConfigFor,
withRaqbSettingsAndWidgets,
@@ -14,6 +13,12 @@ vi.mock("../components/react-awesome-query-builder/widgets", () => ({
MultiSelectWidget: vi.fn(),
SelectWidget: vi.fn(),
NumberWidget: vi.fn(),
+ AddressWidget: vi.fn(),
+ URLWidget: vi.fn(),
+ MultiEmailWidget: vi.fn(),
+ CheckboxGroupWidget: vi.fn(),
+ RadioGroupWidget: vi.fn(),
+ BooleanWidget: vi.fn(),
FieldSelect: vi.fn(),
Conjs: vi.fn(),
Button: vi.fn(),
@@ -46,6 +51,24 @@ describe("uiConfig", () => {
email: {
type: "email",
},
+ address: {
+ type: "address",
+ },
+ url: {
+ type: "url",
+ },
+ multiemail: {
+ type: "multiemail",
+ },
+ checkbox: {
+ type: "checkbox",
+ },
+ radio: {
+ type: "radio",
+ },
+ boolean: {
+ type: "boolean",
+ },
},
settings: {} as Settings,
};
@@ -65,6 +88,12 @@ describe("uiConfig", () => {
expect(result.widgets.select).toHaveProperty("factory");
expect(result.widgets.phone).toHaveProperty("factory");
expect(result.widgets.email).toHaveProperty("factory");
+ expect(result.widgets.address).toHaveProperty("factory");
+ expect(result.widgets.url).toHaveProperty("factory");
+ expect(result.widgets.multiemail).toHaveProperty("factory");
+ expect(result.widgets.checkbox).toHaveProperty("factory");
+ expect(result.widgets.radio).toHaveProperty("factory");
+ expect(result.widgets.boolean).toHaveProperty("factory");
});
it("should add render functions to settings", () => {
diff --git a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts
index 21689593f9ecd3..fc832a4004ab73 100644
--- a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts
+++ b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/BasicConfig.ts
@@ -1,10 +1,10 @@
// This is taken from "react-awesome-query-builder/lib/config/basic";
import type {
Conjunction as RAQBConjunction,
- Widget as RAQBWidget,
- Type as RAQBType,
- Settings as RAQBSettings,
Operator as RAQBOperator,
+ Settings as RAQBSettings,
+ Type as RAQBType,
+ Widget as RAQBWidget,
} from "react-awesome-query-builder";
export type Conjunction = RAQBConjunction;
@@ -284,6 +284,30 @@ const widgets: WidgetsWithoutFactory = {
valuePlaceholder: "Select values",
toJS: (val: any) => val,
},
+ checkbox: {
+ type: "multiselect",
+ jsType: "array",
+ valueSrc: "value" as const,
+ valueLabel: "Values",
+ valuePlaceholder: "Select values",
+ toJS: (val: any) => val,
+ },
+ radio: {
+ type: "select",
+ jsType: "string",
+ valueSrc: "value" as const,
+ valueLabel: "Value",
+ valuePlaceholder: "Select value",
+ toJS: (val: any) => val,
+ },
+ boolean: {
+ type: "boolean",
+ jsType: "boolean",
+ valueSrc: "value" as const,
+ valueLabel: "Value",
+ valuePlaceholder: "",
+ toJS: (val: any) => val,
+ },
};
const types: Types = {
@@ -388,6 +412,15 @@ const types: Types = {
},
},
},
+ boolean: {
+ defaultOperator: "equal",
+ mainWidget: "boolean",
+ widgets: {
+ boolean: {
+ operators: ["equal", "not_equal"],
+ },
+ },
+ },
// "!group": {
// defaultOperator: "some",
// mainWidget: "number",
diff --git a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/config.ts b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/config.ts
index a39a10ca483e55..b894fdc7cd5056 100644
--- a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/config.ts
+++ b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/config.ts
@@ -1,10 +1,10 @@
// Figure out why routing-forms/env.d.ts doesn't work
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
-//@ts-ignore
+//@ts-expect-error
import type { Operators, Types } from "./BasicConfig";
import BasicConfig from "./BasicConfig";
-import { ConfigFor } from "./types";
import type { WidgetsWithoutFactory } from "./types";
+import { ConfigFor } from "./types";
function getWidgetsWithoutFactory(_configFor: ConfigFor) {
const widgetsWithoutFactory: WidgetsWithoutFactory = {
@@ -15,6 +15,15 @@ function getWidgetsWithoutFactory(_configFor: ConfigFor) {
email: {
...BasicConfig.widgets.text,
},
+ address: {
+ ...BasicConfig.widgets.text,
+ },
+ url: {
+ ...BasicConfig.widgets.text,
+ },
+ multiemail: {
+ ...BasicConfig.widgets.text,
+ },
};
return widgetsWithoutFactory;
}
@@ -42,6 +51,44 @@ function getTypes(configFor: ConfigFor) {
...BasicConfig.types.text.widgets,
},
},
+ address: {
+ ...BasicConfig.types.text,
+ widgets: {
+ ...BasicConfig.types.text.widgets,
+ },
+ },
+ url: {
+ ...BasicConfig.types.text,
+ widgets: {
+ ...BasicConfig.types.text.widgets,
+ },
+ },
+ multiemail: {
+ ...BasicConfig.types.text,
+ widgets: {
+ ...BasicConfig.types.text.widgets,
+ },
+ },
+ checkbox: {
+ ...BasicConfig.types.multiselect,
+ widgets: {
+ ...BasicConfig.types.multiselect.widgets,
+ // Checkbox uses the checkbox widget for rendering but multiselect type for query logic
+ checkbox: {
+ ...BasicConfig.types.multiselect.widgets.multiselect,
+ operators: [...multiSelectOperators],
+ },
+ },
+ },
+ radio: {
+ ...BasicConfig.types.select,
+ widgets: {
+ ...BasicConfig.types.select.widgets,
+ radio: {
+ ...BasicConfig.types.select.widgets.select,
+ },
+ },
+ },
multiselect: {
...BasicConfig.types.multiselect,
widgets: {
diff --git a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/uiConfig.tsx b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/uiConfig.tsx
index 6f9f77b8f50114..2fa87900b1b661 100644
--- a/packages/app-store/routing-forms/components/react-awesome-query-builder/config/uiConfig.tsx
+++ b/packages/app-store/routing-forms/components/react-awesome-query-builder/config/uiConfig.tsx
@@ -1,20 +1,17 @@
+import { EmailField as EmailWidget } from "@calcom/ui/components/form";
import type { ChangeEvent } from "react";
import type {
- Settings,
SelectWidgetProps,
SelectWidget as SelectWidgetType,
+ Settings,
WidgetProps,
} from "react-awesome-query-builder";
-
-import { EmailField as EmailWidget } from "@calcom/ui/components/form";
-
import widgetsComponents from "../widgets";
-import type { Widgets, WidgetsWithoutFactory } from "./types";
-import type { ConfigFor } from "./types";
+import type { ConfigFor, Widgets, WidgetsWithoutFactory } from "./types";
export { ConfigFor } from "./types";
-const renderComponent = function (props: T1 | undefined, Component: React.FC) {
+const renderComponent = (props: T1 | undefined, Component: React.FC) => {
if (!props) {
return ;
}
@@ -27,6 +24,12 @@ const {
MultiSelectWidget,
SelectWidget,
NumberWidget,
+ AddressWidget,
+ URLWidget,
+ MultiEmailWidget,
+ CheckboxGroupWidget,
+ RadioGroupWidget,
+ BooleanWidget,
FieldSelect,
Conjs,
Button,
@@ -76,6 +79,30 @@ const EmailFactory = (props: WidgetProps | undefined) => {
);
};
+const AddressFactory = (props: WidgetProps | undefined) => renderComponent(props, AddressWidget);
+
+const URLFactory = (props: WidgetProps | undefined) => renderComponent(props, URLWidget);
+
+const MultiEmailFactory = (props: WidgetProps | undefined) => renderComponent(props, MultiEmailWidget);
+
+const CheckboxGroupFactory = (
+ props:
+ | (SelectWidgetProps & {
+ listValues: { title: string; value: string }[];
+ })
+ | undefined
+) => renderComponent(props, CheckboxGroupWidget);
+
+const RadioGroupFactory = (
+ props:
+ | (SelectWidgetProps & {
+ listValues: { title: string; value: string }[];
+ })
+ | undefined
+) => renderComponent(props, RadioGroupWidget);
+
+const BooleanFactory = (props: WidgetProps | undefined) => renderComponent(props, BooleanWidget);
+
// react-query-builder types have missing type property on Widget
//TODO: Reuse FormBuilder Components - FormBuilder components are built considering Cal.com design system and coding guidelines. But when awesome-query-builder renders these components, it passes its own props which are different from what our Components expect.
// So, a mapper should be written here that maps the props provided by awesome-query-builder to the props that our components expect.
@@ -111,6 +138,33 @@ function withFactoryWidgets(widgets: WidgetsWithoutFactory) {
...widgets.text,
factory: EmailFactory,
},
+ address: {
+ ...widgets.text,
+ factory: AddressFactory,
+ valuePlaceholder: "Enter Address",
+ },
+ url: {
+ ...widgets.text,
+ factory: URLFactory,
+ valuePlaceholder: "Enter URL",
+ },
+ multiemail: {
+ ...widgets.text,
+ factory: MultiEmailFactory,
+ valuePlaceholder: "Enter email addresses",
+ },
+ checkbox: {
+ ...widgets.multiselect,
+ factory: CheckboxGroupFactory,
+ } as SelectWidgetType,
+ radio: {
+ ...widgets.select,
+ factory: RadioGroupFactory,
+ } as SelectWidgetType,
+ boolean: {
+ ...(widgets.boolean || widgets.text),
+ factory: BooleanFactory,
+ },
};
return widgetsWithFactory;
}
diff --git a/packages/app-store/routing-forms/components/react-awesome-query-builder/widgets.tsx b/packages/app-store/routing-forms/components/react-awesome-query-builder/widgets.tsx
index be0de821eabf10..93f33162d74f57 100644
--- a/packages/app-store/routing-forms/components/react-awesome-query-builder/widgets.tsx
+++ b/packages/app-store/routing-forms/components/react-awesome-query-builder/widgets.tsx
@@ -1,7 +1,12 @@
"use client";
+import { useLocale } from "@calcom/lib/hooks/useLocale";
+import { Button as CalButton } from "@calcom/ui/components/button";
+import { TextArea, TextField } from "@calcom/ui/components/form";
+import { Icon } from "@calcom/ui/components/icon";
import dynamic from "next/dynamic";
import type { ChangeEvent } from "react";
+import { useCallback } from "react";
import type {
ButtonGroupProps,
ButtonProps,
@@ -10,12 +15,6 @@ import type {
ProviderProps,
} from "react-awesome-query-builder";
-import { useLocale } from "@calcom/lib/hooks/useLocale";
-import { Button as CalButton } from "@calcom/ui/components/button";
-import { TextArea } from "@calcom/ui/components/form";
-import { TextField } from "@calcom/ui/components/form";
-import { Icon } from "@calcom/ui/components/icon";
-
const Select = dynamic(
async () => (await import("@calcom/ui/components/form")).SelectWithValidation
) as unknown as typeof import("@calcom/ui/components/form").SelectWithValidation;
@@ -28,7 +27,7 @@ export type CommonProps<
| {
value: string;
optionValue: string;
- }
+ },
> = {
placeholder?: string;
readOnly?: boolean;
@@ -50,17 +49,17 @@ export type SelectLikeComponentProps<
| {
value: string;
optionValue: string;
- } = string
+ } = string,
> = {
options: {
label: string;
value: TVal extends (infer P)[]
? P
: TVal extends {
- value: string;
- }
- ? TVal["value"]
- : TVal;
+ value: string;
+ }
+ ? TVal["value"]
+ : TVal;
}[];
} & CommonProps;
@@ -233,6 +232,158 @@ function SelectWidget({ listValues, setValue, value, ...remainingProps }: Select
);
}
+function AddressWidget(props: TextLikeComponentPropsRAQB) {
+ const { value, noLabel, setValue, readOnly, placeholder, customProps, ...remainingProps } = props;
+ const onChange = (e: ChangeEvent) => {
+ const val = e.target.value;
+ setValue(val);
+ };
+ const textValue = value || "";
+ return (
+
+ );
+}
+
+function URLWidget(props: TextLikeComponentPropsRAQB) {
+ const { value, noLabel, setValue, readOnly, placeholder, customProps, ...remainingProps } = props;
+ const onChange = (e: ChangeEvent) => {
+ const val = e.target.value;
+ setValue(val);
+ };
+ const textValue = value || "";
+ return (
+
+ );
+}
+
+function MultiEmailWidget(props: TextLikeComponentPropsRAQB) {
+ const { value, noLabel, setValue, readOnly, placeholder, customProps, ...remainingProps } = props;
+ const onChange = (e: ChangeEvent) => {
+ const val = e.target.value;
+ setValue(val);
+ };
+ const textValue = value || "";
+ return (
+
+ );
+}
+
+function CheckboxGroupWidget({
+ listValues,
+ setValue,
+ value,
+ ...remainingProps
+}: SelectLikeComponentPropsRAQB) {
+ if (!listValues) {
+ return null;
+ }
+
+ const currentValues = value || [];
+
+ const handleChange = useCallback(
+ (itemValue: string, checked: boolean) => {
+ const newValues = checked
+ ? [...currentValues, itemValue]
+ : currentValues.filter((v) => v !== itemValue);
+ setValue(newValues);
+ },
+ [currentValues, setValue]
+ );
+
+ return (
+
+ {listValues.map((item) => (
+
+ ))}
+
+ );
+}
+
+function RadioGroupWidget({ listValues, setValue, value, ...remainingProps }: SelectLikeComponentPropsRAQB) {
+ if (!listValues) {
+ return null;
+ }
+
+ return (
+
+ {listValues.map((item) => (
+
+ ))}
+
+ );
+}
+
+function BooleanWidget({ value, setValue, readOnly }: TextLikeComponentPropsRAQB) {
+ // Store as "true"/"false" strings for compatibility with routing logic
+ const isChecked = value === "true";
+
+ return (
+
+
+
+ );
+}
+
function Button({ config, type, label, onClick, readonly }: ButtonProps) {
const { t } = useLocale();
if (type === "delRule" || type == "delGroup") {
@@ -376,6 +527,12 @@ const widgets = {
SelectWidget,
NumberWidget,
MultiSelectWidget,
+ AddressWidget,
+ URLWidget,
+ MultiEmailWidget,
+ CheckboxGroupWidget,
+ RadioGroupWidget,
+ BooleanWidget,
FieldSelect,
Button,
ButtonGroup,
diff --git a/packages/app-store/routing-forms/lib/FieldTypes.ts b/packages/app-store/routing-forms/lib/FieldTypes.ts
index 456f77617cc98e..0acf1cd5b6f14a 100644
--- a/packages/app-store/routing-forms/lib/FieldTypes.ts
+++ b/packages/app-store/routing-forms/lib/FieldTypes.ts
@@ -1,4 +1,4 @@
-export const enum RoutingFormFieldType {
+export enum RoutingFormFieldType {
TEXT = "text",
NUMBER = "number",
TEXTAREA = "textarea",
@@ -6,6 +6,12 @@ export const enum RoutingFormFieldType {
MULTI_SELECT = "multiselect",
PHONE = "phone",
EMAIL = "email",
+ ADDRESS = "address",
+ MULTIEMAIL = "multiemail",
+ CHECKBOX = "checkbox",
+ RADIO = "radio",
+ BOOLEAN = "boolean",
+ URL = "url",
}
export const isValidRoutingFormFieldType = (type: string): type is RoutingFormFieldType => {
@@ -17,6 +23,12 @@ export const isValidRoutingFormFieldType = (type: string): type is RoutingFormFi
RoutingFormFieldType.MULTI_SELECT,
RoutingFormFieldType.PHONE,
RoutingFormFieldType.EMAIL,
+ RoutingFormFieldType.ADDRESS,
+ RoutingFormFieldType.MULTIEMAIL,
+ RoutingFormFieldType.CHECKBOX,
+ RoutingFormFieldType.RADIO,
+ RoutingFormFieldType.BOOLEAN,
+ RoutingFormFieldType.URL,
].includes(type as RoutingFormFieldType);
};
@@ -49,4 +61,28 @@ export const FieldTypes = [
label: "Email",
value: RoutingFormFieldType.EMAIL,
},
+ {
+ label: "Address",
+ value: RoutingFormFieldType.ADDRESS,
+ },
+ {
+ label: "Multiple Emails",
+ value: RoutingFormFieldType.MULTIEMAIL,
+ },
+ {
+ label: "Checkbox Group",
+ value: RoutingFormFieldType.CHECKBOX,
+ },
+ {
+ label: "Radio Group",
+ value: RoutingFormFieldType.RADIO,
+ },
+ {
+ label: "Checkbox",
+ value: RoutingFormFieldType.BOOLEAN,
+ },
+ {
+ label: "URL",
+ value: RoutingFormFieldType.URL,
+ },
] as const;
diff --git a/packages/app-store/routing-forms/lib/__tests__/getQueryBuilderConfig.test.ts b/packages/app-store/routing-forms/lib/__tests__/getQueryBuilderConfig.test.ts
index c14c6e81f84b33..ca4278722e77d9 100644
--- a/packages/app-store/routing-forms/lib/__tests__/getQueryBuilderConfig.test.ts
+++ b/packages/app-store/routing-forms/lib/__tests__/getQueryBuilderConfig.test.ts
@@ -1,9 +1,7 @@
-import { describe, it, expect } from "vitest";
-import { vi } from "vitest";
-
+import { describe, expect, it, vi } from "vitest";
import type { RoutingForm } from "../../types/types";
-import { FormFieldsInitialConfig } from "../InitialConfig";
import { getQueryBuilderConfigForFormFields } from "../getQueryBuilderConfig";
+import { FormFieldsInitialConfig } from "../InitialConfig";
type MockedForm = Pick;
vi.mock("../InitialConfig", () => ({
@@ -12,6 +10,16 @@ vi.mock("../InitialConfig", () => ({
text: { type: "text" },
select: { type: "select" },
multiselect: { type: "multiselect" },
+ phone: { type: "text" },
+ email: { type: "text" },
+ address: { type: "text" },
+ url: { type: "text" },
+ multiemail: { type: "text" },
+ checkbox: { type: "multiselect" },
+ radio: { type: "select" },
+ boolean: { type: "boolean" },
+ textarea: { type: "text" },
+ number: { type: "number" },
},
operators: {
is_empty: {},
diff --git a/packages/app-store/routing-forms/lib/formSubmissionUtils.ts b/packages/app-store/routing-forms/lib/formSubmissionUtils.ts
index 31b8a77de2ed23..2d5f4e12794490 100644
--- a/packages/app-store/routing-forms/lib/formSubmissionUtils.ts
+++ b/packages/app-store/routing-forms/lib/formSubmissionUtils.ts
@@ -9,13 +9,11 @@ import { HttpError } from "@calcom/lib/http-error";
import logger from "@calcom/lib/logger";
import { withReporting } from "@calcom/lib/sentryWrapper";
import { prisma } from "@calcom/prisma";
-import type { Prisma } from "@calcom/prisma/client";
-import type { App_RoutingForms_Form, User } from "@calcom/prisma/client";
+import type { App_RoutingForms_Form, Prisma, User } from "@calcom/prisma/client";
import { WebhookTriggerEvents } from "@calcom/prisma/enums";
import { RoutingFormSettings } from "@calcom/prisma/zod-utils";
import type { Ensure } from "@calcom/types/utils";
-
-import type { FormResponse, SerializableForm, SerializableField, OrderedResponses } from "../types/types";
+import type { FormResponse, OrderedResponses, SerializableField, SerializableForm } from "../types/types";
import getFieldIdentifier from "./getFieldIdentifier";
const moduleLogger = logger.getSubLogger({ prefix: ["routing-forms/lib/formSubmissionUtils"] });
@@ -45,7 +43,13 @@ export type FORM_SUBMITTED_WEBHOOK_RESPONSES = Record<
>;
function isOptionsField(field: Pick) {
- return (field.type === "select" || field.type === "multiselect") && field.options;
+ return (
+ (field.type === "select" ||
+ field.type === "multiselect" ||
+ field.type === "checkbox" ||
+ field.type === "radio") &&
+ field.options
+ );
}
export function getFieldResponse({
@@ -192,11 +196,14 @@ export async function _onFormSubmission(
},
rootData: {
// Send responses unwrapped at root level for backwards compatibility
- ...Object.entries(fieldResponsesByIdentifier).reduce((acc, [key, value]) => {
- const normalizedKey = normalizeIdentifierForHandlebars(key);
- acc[normalizedKey] = value.value;
- return acc;
- }, {} as Record),
+ ...Object.entries(fieldResponsesByIdentifier).reduce(
+ (acc, [key, value]) => {
+ const normalizedKey = normalizeIdentifierForHandlebars(key);
+ acc[normalizedKey] = value.value;
+ return acc;
+ },
+ {} as Record
+ ),
},
}).catch((e) => {
console.error(`Error executing routing form webhook`, webhook, e);
diff --git a/packages/app-store/routing-forms/lib/getQueryBuilderConfig.ts b/packages/app-store/routing-forms/lib/getQueryBuilderConfig.ts
index 000ece889a1d5a..3f8e629f2e723c 100644
--- a/packages/app-store/routing-forms/lib/getQueryBuilderConfig.ts
+++ b/packages/app-store/routing-forms/lib/getQueryBuilderConfig.ts
@@ -1,6 +1,5 @@
import { AttributeType } from "@calcom/prisma/enums";
-
-import type { RoutingForm, Attribute } from "../types/types";
+import type { Attribute, RoutingForm } from "../types/types";
import { FieldTypes, RoutingFormFieldType } from "./FieldTypes";
import { AttributesInitialConfig, FormFieldsInitialConfig } from "./InitialConfig";
import { getUIOptionsForSelect } from "./selectOptions";
@@ -58,13 +57,19 @@ export function getQueryBuilderConfigForFormFields(form: Pick f.fields).flat());
+ const fields = routingFormFieldsSchema.parse(routingForms.flatMap((f) => f.fields));
return fields;
}
@@ -249,7 +248,7 @@ class RoutingEventsInsights {
organizationId,
routingFormId,
}: RoutingFormInsightsTeamFilter) {
- const formsWhereCondition = await this.getWhereForTeamOrAllTeams({
+ const formsWhereCondition = await RoutingEventsInsights.getWhereForTeamOrAllTeams({
userId,
teamId,
isAll,
@@ -266,7 +265,7 @@ class RoutingEventsInsights {
},
});
- const fields = routingFormFieldsSchema.parse(routingForms.map((f) => f.fields).flat());
+ const fields = routingFormFieldsSchema.parse(routingForms.flatMap((f) => f.fields));
const ids = new Set();
const headers = (fields || [])
.filter((f) => !f.deleted)
@@ -284,7 +283,9 @@ class RoutingEventsInsights {
}
if (
field.type === RoutingFormFieldType.SINGLE_SELECT ||
- field.type === RoutingFormFieldType.MULTI_SELECT
+ field.type === RoutingFormFieldType.MULTI_SELECT ||
+ field.type === RoutingFormFieldType.CHECKBOX ||
+ field.type === RoutingFormFieldType.RADIO
) {
return field.options && field.options.length > 0;
}