Additional fields as variables for custom event name (#7454)
* feat: add custom validate name util * refactor: separate custom event type modal into a different component * feat: add validation to zod * chore: add i18n key * feat: add dynamic imports * fix: padding * Omit cache-hit exit 1, assuming it'll fail regardless * allow custom inputs as variables in event name * fix ui for adding custom inputs * show edited event name in modal * code clean up * merge fixes * includes new booking fields logic * fix event name with custom booking fields * code clean up * Update apps/web/public/static/locales/en/common.json Co-authored-by: Alex van Andel <me@alexvanandel.com> * fix type error * remove old reqbody variable --------- Co-authored-by: nafees nazik <nafeesnazik21@gmail.com> Co-authored-by: Alex van Andel <me@alexvanandel.com> Co-authored-by: CarinaWolli <wollencarina@gmail.com>pull/7643/head^2
parent
943142e77f
commit
d9a555d94a
|
@ -52,7 +52,8 @@ const CustomEventTypeModalForm: FC<CustomEventTypeModalFormProps> = (props) => {
|
|||
type="text"
|
||||
placeholder={placeHolder_}
|
||||
{...register("customEventName", {
|
||||
validate: (value) => validateCustomEventName(value, t("invalid_event_name_variables")),
|
||||
validate: (value) =>
|
||||
validateCustomEventName(value, t("invalid_event_name_variables"), event.bookingFields),
|
||||
})}
|
||||
className="mb-0"
|
||||
/>
|
||||
|
|
|
@ -12,6 +12,7 @@ import DestinationCalendarSelector from "@calcom/features/calendars/DestinationC
|
|||
import { FormBuilder } from "@calcom/features/form-builder/FormBuilder";
|
||||
import { APP_NAME, CAL_URL, IS_SELF_HOSTED } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import type { Prisma } from "@calcom/prisma/client";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import { Badge, Button, Checkbox, Label, SettingsToggle, showToast, TextField, Tooltip } from "@calcom/ui";
|
||||
import { FiEdit, FiCopy } from "@calcom/ui/components/icon";
|
||||
|
@ -36,11 +37,19 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
|
|||
const [hashedLinkVisible, setHashedLinkVisible] = useState(!!eventType.hashedLink);
|
||||
const [redirectUrlVisible, setRedirectUrlVisible] = useState(!!eventType.successRedirectUrl);
|
||||
const [hashedUrl, setHashedUrl] = useState(eventType.hashedLink?.link);
|
||||
|
||||
const bookingFields: Prisma.JsonObject = {};
|
||||
|
||||
eventType.bookingFields.forEach(({ name }) => {
|
||||
bookingFields[name] = name + " input";
|
||||
});
|
||||
|
||||
const eventNameObject: EventNameObjectType = {
|
||||
attendeeName: t("scheduler"),
|
||||
eventType: eventType.title,
|
||||
eventName: eventType.eventName,
|
||||
host: eventType.users[0]?.name || "Nameless",
|
||||
bookingFields: bookingFields,
|
||||
t,
|
||||
};
|
||||
|
||||
|
@ -308,7 +317,7 @@ export const EventAdvancedTab = ({ eventType, team }: Pick<EventTypeSetupProps,
|
|||
<CustomEventTypeModal
|
||||
close={closeEventNameTip}
|
||||
setValue={setEventName}
|
||||
defaultValue={eventType.eventName || ""}
|
||||
defaultValue={formMethods.getValues("eventName") || eventType.eventName || ""}
|
||||
placeHolder={eventNamePlaceholder}
|
||||
event={eventNameObject}
|
||||
/>
|
||||
|
|
|
@ -250,6 +250,7 @@ export default function Success(props: SuccessProps) {
|
|||
eventName: (props.dynamicEventName as string) || props.eventType.eventName,
|
||||
host: props.profile.name || "Nameless",
|
||||
location: location,
|
||||
bookingFields: bookingInfo.responses,
|
||||
t,
|
||||
};
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
|
|||
import { useTypedQuery } from "@calcom/lib/hooks/useTypedQuery";
|
||||
import { HttpError } from "@calcom/lib/http-error";
|
||||
import prisma from "@calcom/prisma";
|
||||
import type { Prisma } from "@calcom/prisma/client";
|
||||
import { eventTypeBookingFields } from "@calcom/prisma/zod-utils";
|
||||
import type { customInputSchema, EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||
import type { RouterOutputs } from "@calcom/trpc/react";
|
||||
|
@ -180,6 +181,12 @@ const EventTypePage = (props: EventTypeSetupProps) => {
|
|||
delete metadata.config?.useHostSchedulesForTeamEvent;
|
||||
}
|
||||
|
||||
const bookingFields: Prisma.JsonObject = {};
|
||||
|
||||
eventType.bookingFields.forEach(({ name }) => {
|
||||
bookingFields[name] = name;
|
||||
});
|
||||
|
||||
const defaultValues = {
|
||||
title: eventType.title,
|
||||
locations: eventType.locations || [],
|
||||
|
@ -211,9 +218,13 @@ const EventTypePage = (props: EventTypeSetupProps) => {
|
|||
// Make it optional because it's not submitted from all tabs of the page
|
||||
eventName: z
|
||||
.string()
|
||||
.refine((val) => validateCustomEventName(val, t("invalid_event_name_variables")) === true, {
|
||||
message: t("invalid_event_name_variables"),
|
||||
})
|
||||
.refine(
|
||||
(val) =>
|
||||
validateCustomEventName(val, t("invalid_event_name_variables"), bookingFields) === true,
|
||||
{
|
||||
message: t("invalid_event_name_variables"),
|
||||
}
|
||||
)
|
||||
.optional(),
|
||||
length: z.union([z.string().transform((val) => +val), z.number()]).optional(),
|
||||
bookingFields: eventTypeBookingFields,
|
||||
|
|
|
@ -1642,8 +1642,8 @@
|
|||
"verification_code": "Verification code",
|
||||
"can_you_try_again": "Can you try again with a different time?",
|
||||
"verify": "Verify",
|
||||
"invalid_event_name_variables":"There is an invalid variable in your event name",
|
||||
"select_all": "Select All",
|
||||
"default_conferencing_bulk_title": "Bulk update existing event types",
|
||||
"default_conferencing_bulk_description": "Update the locations for the selected event types",
|
||||
"invalid_event_name_variables": "There is an invalid variable in your event name"
|
||||
"default_conferencing_bulk_description": "Update the locations for the selected event types"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import type { TFunction } from "next-i18next";
|
||||
|
||||
import { guessEventLocationType } from "@calcom/app-store/locations";
|
||||
import type { Prisma } from "@calcom/prisma/client";
|
||||
|
||||
export type EventNameObjectType = {
|
||||
attendeeName: string;
|
||||
|
@ -8,6 +9,7 @@ export type EventNameObjectType = {
|
|||
eventName?: string | null;
|
||||
host: string;
|
||||
location?: string;
|
||||
bookingFields?: Prisma.JsonObject;
|
||||
t: TFunction;
|
||||
};
|
||||
|
||||
|
@ -31,21 +33,56 @@ export function getEventName(eventNameObj: EventNameObjectType, forAttendeeView
|
|||
eventName = eventName.replace("{LOCATION}", locationString);
|
||||
}
|
||||
|
||||
return (
|
||||
eventName
|
||||
// Need this for compatibility with older event names
|
||||
.replace("{Event type title}", eventNameObj.eventType)
|
||||
.replace("{Scheduler}", eventNameObj.attendeeName)
|
||||
.replace("{Organiser}", eventNameObj.host)
|
||||
.replace("{USER}", eventNameObj.attendeeName)
|
||||
.replace("{ATTENDEE}", eventNameObj.attendeeName)
|
||||
.replace("{HOST}", eventNameObj.host)
|
||||
.replace("{HOST/ATTENDEE}", forAttendeeView ? eventNameObj.host : eventNameObj.attendeeName)
|
||||
);
|
||||
let dynamicEventName = eventName
|
||||
// Need this for compatibility with older event names
|
||||
.replaceAll("{Event type title}", eventNameObj.eventType)
|
||||
.replaceAll("{Scheduler}", eventNameObj.attendeeName)
|
||||
.replaceAll("{Organiser}", eventNameObj.host)
|
||||
.replaceAll("{USER}", eventNameObj.attendeeName)
|
||||
.replaceAll("{ATTENDEE}", eventNameObj.attendeeName)
|
||||
.replaceAll("{HOST}", eventNameObj.host)
|
||||
.replaceAll("{HOST/ATTENDEE}", forAttendeeView ? eventNameObj.host : eventNameObj.attendeeName);
|
||||
|
||||
const customInputvariables = dynamicEventName.match(/\{(.+?)}/g)?.map((variable) => {
|
||||
return variable.replace("{", "").replace("}", "");
|
||||
});
|
||||
|
||||
customInputvariables?.forEach((variable) => {
|
||||
if (eventNameObj.bookingFields) {
|
||||
Object.keys(eventNameObj.bookingFields).forEach((bookingField) => {
|
||||
if (variable === bookingField) {
|
||||
let fieldValue;
|
||||
if (eventNameObj.bookingFields) {
|
||||
fieldValue =
|
||||
eventNameObj.bookingFields[bookingField as keyof typeof eventNameObj.bookingFields]?.toString();
|
||||
}
|
||||
dynamicEventName = dynamicEventName.replace(`{${variable}}`, fieldValue || "");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return dynamicEventName;
|
||||
}
|
||||
|
||||
export const validateCustomEventName = (value: string, message: string) => {
|
||||
const validVariables = ["{Event type title}", "{Organiser}", "{Scheduler}", "{Location}"];
|
||||
export const validateCustomEventName = (
|
||||
value: string,
|
||||
message: string,
|
||||
bookingFields?: Prisma.JsonObject
|
||||
) => {
|
||||
let customInputVariables: string[] = [];
|
||||
if (bookingFields) {
|
||||
customInputVariables = Object.keys(bookingFields).map((customInput) => {
|
||||
return `{${customInput}}`;
|
||||
});
|
||||
}
|
||||
|
||||
const validVariables = customInputVariables.concat([
|
||||
"{Event type title}",
|
||||
"{Organiser}",
|
||||
"{Scheduler}",
|
||||
"{Location}",
|
||||
]);
|
||||
const matches = value.match(/\{([^}]+)\}/g);
|
||||
if (matches?.length) {
|
||||
for (const item of matches) {
|
||||
|
|
|
@ -714,6 +714,8 @@ async function handler(
|
|||
|
||||
const attendeesList = [...invitee, ...guests];
|
||||
|
||||
const responses = "responses" in reqBody ? reqBody.responses : null;
|
||||
|
||||
const eventNameObject = {
|
||||
//TODO: Can we have an unnamed attendee? If not, I would really like to throw an error here.
|
||||
attendeeName: bookerName || "Nameless",
|
||||
|
@ -722,6 +724,7 @@ async function handler(
|
|||
// TODO: Can we have an unnamed organizer? If not, I would really like to throw an error here.
|
||||
host: organizerUser.name || "Nameless",
|
||||
location: bookingLocation,
|
||||
bookingFields: { ...responses },
|
||||
t: tOrganizer,
|
||||
};
|
||||
|
||||
|
@ -733,7 +736,6 @@ async function handler(
|
|||
}
|
||||
}
|
||||
|
||||
const responses = "responses" in reqBody ? reqBody.responses : null;
|
||||
const calEventUserFieldsResponses =
|
||||
"calEventUserFieldsResponses" in reqBody ? reqBody.calEventUserFieldsResponses : null;
|
||||
let evt: CalendarEvent = {
|
||||
|
|
Loading…
Reference in New Issue