feat: Add URL-type input in booking question field (#15481)

* feat: Add URL-type input in booking question field

* fix type error

* Update common.json

* fix requested changes

* small update

---------

Co-authored-by: Rajiv Sahal <sahalrajiv6900@gmail.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
This commit is contained in:
Anik Dhabal Babu
2024-08-05 12:53:53 +05:30
committed by GitHub
co-authored by Rajiv Sahal Keith Williams
parent add59896f5
commit 099d830e7e
7 changed files with 146 additions and 1 deletions
@@ -1128,6 +1128,7 @@
"update_location": "Update Location",
"location_updated": "Location updated",
"email_validation_error": "That doesn't look like an email address",
"url_validation_error": "That doesn't look like a URL",
"place_where_cal_widget_appear": "Place this code in your HTML where you want your {{appName}} widget to appear.",
"create_update_react_component": "Create or update an existing React component as shown below.",
"copy_code": "Copy Code",
@@ -70,7 +70,7 @@ export type TextLikeComponentProps<TVal extends string | string[] | boolean = st
export type TextLikeComponentPropsRAQB<TVal extends string | boolean = string> =
TextLikeComponentProps<TVal> & {
customProps?: object;
type?: "text" | "number" | "email" | "tel";
type?: "text" | "number" | "email" | "tel" | "url";
maxLength?: number;
noLabel?: boolean;
};
@@ -10,6 +10,7 @@ import getBookingResponsesSchema, { getBookingResponsesPartialSchema } from "./g
const CUSTOM_REQUIRED_FIELD_ERROR_MSG = "error_required_field";
const CUSTOM_PHONE_VALIDATION_ERROR_MSG = "invalid_number";
const CUSTOM_EMAIL_VALIDATION_ERROR_MSG = "email_validation_error";
const CUSTOM_URL_VALIDATION_ERROR_MSG = "url_validation_error";
const ZOD_REQUIRED_FIELD_ERROR_MSG = "Required";
describe("getBookingResponsesSchema", () => {
@@ -994,6 +995,120 @@ describe("getBookingResponsesSchema", () => {
test.todo("radio");
test.todo("boolean");
});
describe("validate url type field", () => {
test(`should fail parsing if invalid url provided`, async ({}) => {
const schema = getBookingResponsesSchema({
bookingFields: [
{
name: "name",
type: "name",
required: true,
},
{
name: "email",
type: "email",
required: true,
},
{
name: "url",
type: "url",
required: true,
},
] as z.infer<typeof eventTypeBookingFields> & z.BRAND<"HAS_SYSTEM_FIELDS">,
view: "ALL_VIEWS",
});
const parsedResponses = await schema.safeParseAsync({
email: "test@test.com",
name: "test",
url: "www.example.com",
});
expect(parsedResponses.success).toBe(false);
if (parsedResponses.success) {
throw new Error("Should not reach here");
}
expect(parsedResponses.error.issues[0]).toEqual(
expect.objectContaining({
code: "custom",
message: `{url}${CUSTOM_URL_VALIDATION_ERROR_MSG}`,
})
);
});
test(`should successfully give responses if url type field value is valid`, async ({}) => {
const schema = getBookingResponsesSchema({
bookingFields: [
{
name: "name",
type: "name",
required: true,
},
{
name: "email",
type: "email",
required: true,
},
{
name: "url",
type: "url",
required: true,
},
] as z.infer<typeof eventTypeBookingFields> & z.BRAND<"HAS_SYSTEM_FIELDS">,
view: "ALL_VIEWS",
});
const parsedResponses = await schema.safeParseAsync({
email: "test@test.com",
name: "test",
url: "https://8x8.vc/company",
});
expect(parsedResponses.success).toBe(true);
if (!parsedResponses.success) {
throw new Error("Should not reach here");
}
expect(parsedResponses.data).toEqual({
email: "test@test.com",
name: "test",
url: "https://8x8.vc/company",
});
});
test("should fail parsing if url field value is empty", async ({}) => {
const schema = getBookingResponsesSchema({
bookingFields: [
{
name: "name",
type: "name",
required: true,
},
{
name: "email",
type: "email",
required: true,
},
{
name: "url",
type: "url",
required: true,
},
] as z.infer<typeof eventTypeBookingFields> & z.BRAND<"HAS_SYSTEM_FIELDS">,
view: "ALL_VIEWS",
});
const parsedResponses = await schema.safeParseAsync({
email: "test@test.com",
name: "test",
url: "",
});
expect(parsedResponses.success).toBe(false);
// eslint-disable-next-line playwright/no-conditional-in-test
if (parsedResponses.success) {
throw new Error("Should not reach here");
}
expect(parsedResponses.error.issues[0]).toEqual(
expect.objectContaining({
code: "custom",
message: `{url}${CUSTOM_REQUIRED_FIELD_ERROR_MSG}`,
})
);
});
});
describe("getBookingResponsesPartialSchema - Prefill validation", () => {
test(`should be able to get fields prefilled even when name is empty string`, async ({}) => {
@@ -512,5 +512,11 @@ export const Components: Record<FieldType, Component> = {
);
},
},
url: {
propsType: propsTypes.url,
factory: (props) => {
return <Widgets.TextWidget type="url" noLabel={true} {...props} />;
},
},
} as const;
// Should use `statisfies` to check if the `type` is from supported types. But satisfies doesn't work with Next.js config
@@ -152,6 +152,11 @@ const configMap: Record<FieldType, Omit<z.infer<typeof fieldTypeConfigSchema>, "
value: "boolean",
isTextType: false,
},
url: {
label: "URL",
value: "url",
isTextType: true,
},
};
export const fieldTypesConfigMap = configMap as Record<FieldType, z.infer<typeof fieldTypeConfigSchema>>;
@@ -13,4 +13,5 @@ export const propsTypes = {
checkbox: "multiselect",
radio: "select",
boolean: "boolean",
url: "text",
} as const;
+17
View File
@@ -23,6 +23,7 @@ const fieldTypeEnum = z.enum([
"radio",
"radioInput",
"boolean",
"url",
]);
export type FieldType = z.infer<typeof fieldTypeEnum>;
@@ -368,6 +369,22 @@ export const fieldTypesSchemaMap: Partial<
}
},
},
url: {
preprocess: ({ response }) => {
return response.trim();
},
superRefine: ({ response, ctx, m }) => {
const value = response ?? "";
const urlSchema = z.string().url();
if (!urlSchema.safeParse(value).success) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: m("url_validation_error"),
});
}
},
},
};
/**