fix: Prefill issue when name isn't present and add unit tests (#11418)
* Fix yarn.lock * Add tests for getBookingResponsesSchema * Fix prefill failing if name isnt provided * More tests and another fixpull/11529/head^2
parent
a0642598ab
commit
4acfb4b28c
File diff suppressed because it is too large
Load Diff
|
@ -79,7 +79,7 @@ function preprocess<T extends z.ZodType>({
|
||||||
isPartialSchema,
|
isPartialSchema,
|
||||||
field,
|
field,
|
||||||
});
|
});
|
||||||
return newResponses;
|
return;
|
||||||
}
|
}
|
||||||
if (field.type === "boolean") {
|
if (field.type === "boolean") {
|
||||||
// Turn a boolean in string to a real boolean
|
// Turn a boolean in string to a real boolean
|
||||||
|
@ -103,7 +103,11 @@ function preprocess<T extends z.ZodType>({
|
||||||
newResponses[field.name] = value;
|
newResponses[field.name] = value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return newResponses;
|
|
||||||
|
return {
|
||||||
|
...parsedResponses,
|
||||||
|
...newResponses,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
schema.superRefine(async (responses, ctx) => {
|
schema.superRefine(async (responses, ctx) => {
|
||||||
if (!eventType.bookingFields) {
|
if (!eventType.bookingFields) {
|
||||||
|
@ -137,8 +141,10 @@ function preprocess<T extends z.ZodType>({
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isRequired && !isPartialSchema && !value)
|
if (isRequired && !isPartialSchema && !value) {
|
||||||
ctx.addIssue({ code: z.ZodIssueCode.custom, message: m(`error_required_field`) });
|
ctx.addIssue({ code: z.ZodIssueCode.custom, message: m(`error_required_field`) });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (bookingField.type === "email") {
|
if (bookingField.type === "email") {
|
||||||
// Email RegExp to validate if the input is a valid email
|
// Email RegExp to validate if the input is a valid email
|
||||||
|
@ -224,6 +230,7 @@ function preprocess<T extends z.ZodType>({
|
||||||
!optionValue
|
!optionValue
|
||||||
) {
|
) {
|
||||||
ctx.addIssue({ code: z.ZodIssueCode.custom, message: m("error_required_field") });
|
ctx.addIssue({ code: z.ZodIssueCode.custom, message: m("error_required_field") });
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (optionValue) {
|
if (optionValue) {
|
||||||
|
@ -248,14 +255,17 @@ function preprocess<T extends z.ZodType>({
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error(`Can't parse unknown booking field type: ${bookingField.type}`);
|
ctx.addIssue({
|
||||||
|
code: z.ZodIssueCode.custom,
|
||||||
|
message: `Can't parse unknown booking field type: ${bookingField.type}`,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
if (isPartialSchema) {
|
if (isPartialSchema) {
|
||||||
// Query Params can be completely invalid, try to preprocess as much of it in correct format but in worst case simply don't prefill instead of crashing
|
// Query Params can be completely invalid, try to preprocess as much of it in correct format but in worst case simply don't prefill instead of crashing
|
||||||
return preprocessed.catch(() => {
|
return preprocessed.catch(function (res?: { error?: unknown[] }) {
|
||||||
console.error("Failed to preprocess query params, prefilling will be skipped");
|
console.error("Failed to preprocess query params, prefilling will be skipped", res?.error);
|
||||||
return {};
|
return {};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@ import { getValidRhfFieldName } from "@calcom/lib/getValidRhfFieldName";
|
||||||
import { fieldTypesConfigMap } from "./fieldTypes";
|
import { fieldTypesConfigMap } from "./fieldTypes";
|
||||||
import { getVariantsConfig, preprocessNameFieldDataWithVariant } from "./utils";
|
import { getVariantsConfig, preprocessNameFieldDataWithVariant } from "./utils";
|
||||||
|
|
||||||
|
const nonEmptyString = () => z.string().refine((value: string) => value.trim().length > 0);
|
||||||
|
|
||||||
const fieldTypeEnum = z.enum([
|
const fieldTypeEnum = z.enum([
|
||||||
"name",
|
"name",
|
||||||
"text",
|
"text",
|
||||||
|
@ -289,7 +291,7 @@ export const fieldTypesSchemaMap: Partial<
|
||||||
if (fields.length === 1) {
|
if (fields.length === 1) {
|
||||||
const field = fields[0];
|
const field = fields[0];
|
||||||
if (variantSupportedFields.includes(field.type)) {
|
if (variantSupportedFields.includes(field.type)) {
|
||||||
const schema = stringSchema;
|
const schema = field.required && !isPartialSchema ? nonEmptyString() : stringSchema;
|
||||||
if (!schema.safeParse(response).success) {
|
if (!schema.safeParse(response).success) {
|
||||||
ctx.addIssue({ code: z.ZodIssueCode.custom, message: m("Invalid string") });
|
ctx.addIssue({ code: z.ZodIssueCode.custom, message: m("Invalid string") });
|
||||||
}
|
}
|
||||||
|
@ -299,7 +301,7 @@ export const fieldTypesSchemaMap: Partial<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fields.forEach((subField) => {
|
fields.forEach((subField) => {
|
||||||
const schema = stringSchema;
|
const schema = subField.required && !isPartialSchema ? nonEmptyString() : stringSchema;
|
||||||
if (!variantSupportedFields.includes(subField.type)) {
|
if (!variantSupportedFields.includes(subField.type)) {
|
||||||
throw new Error(`Unsupported field.type with variants: ${subField.type}`);
|
throw new Error(`Unsupported field.type with variants: ${subField.type}`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,6 @@ import { isSupportedTimeZone } from "@calcom/lib/date-fns";
|
||||||
import { slugify } from "@calcom/lib/slugify";
|
import { slugify } from "@calcom/lib/slugify";
|
||||||
import { EventTypeCustomInputType } from "@calcom/prisma/enums";
|
import { EventTypeCustomInputType } from "@calcom/prisma/enums";
|
||||||
|
|
||||||
export const nonEmptyString = () => z.string().refine((value: string) => value.trim().length > 0);
|
|
||||||
|
|
||||||
// Let's not import 118kb just to get an enum
|
// Let's not import 118kb just to get an enum
|
||||||
export enum Frequency {
|
export enum Frequency {
|
||||||
YEARLY = 0,
|
YEARLY = 0,
|
||||||
|
@ -115,14 +113,15 @@ export type BookingFieldType = FormBuilderFieldType;
|
||||||
|
|
||||||
// Validation of user added bookingFields' responses happen using `getBookingResponsesSchema` which requires `eventType`.
|
// Validation of user added bookingFields' responses happen using `getBookingResponsesSchema` which requires `eventType`.
|
||||||
// So it is a dynamic validation and thus entire validation can't exist here
|
// So it is a dynamic validation and thus entire validation can't exist here
|
||||||
|
// Note that this validation runs to validate prefill params as well, so it should consider that partial values can be there. e.g. `name` might be empty string
|
||||||
export const bookingResponses = z
|
export const bookingResponses = z
|
||||||
.object({
|
.object({
|
||||||
email: z.string(),
|
email: z.string(),
|
||||||
//TODO: Why don't we move name out of bookingResponses and let it be handled like user fields?
|
//TODO: Why don't we move name out of bookingResponses and let it be handled like user fields?
|
||||||
name: z.union([
|
name: z.union([
|
||||||
nonEmptyString(),
|
z.string(),
|
||||||
z.object({
|
z.object({
|
||||||
firstName: nonEmptyString(),
|
firstName: z.string(),
|
||||||
lastName: z.string().optional(),
|
lastName: z.string().optional(),
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
|
|
Loading…
Reference in New Issue