* refactor: Remove intervalLimits from @calcom/lib and export directly (#19710) * refactor: Remove intervalLimits from @calcom/lib and export directly * Tackle other places that use parseBookingLimit/parseDurationLimit * More type fixups that were hidden by previous fails * Fixed up booking-limits file * Remove server-only ## What does this PR do? <!-- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. --> - Fixes #XXXX (GitHub issue number) - Fixes CAL-XXXX (Linear issue number - should be visible at the bottom of the GitHub issue description) ## Visual Demo (For contributors especially) A visual demonstration is strongly recommended, for both the original and new change **(video / image - any one)**. #### Video Demo (if applicable): - Show screen recordings of the issue or feature. - Demonstrate how to reproduce the issue, the behavior before and after the change. #### Image Demo (if applicable): - Add side-by-side screenshots of the original and updated change. - Highlight any significant change(s). ## Mandatory Tasks (DO NOT REMOVE) - [ ] I have self-reviewed the code (A decent size PR without self-review might be rejected). - [ ] I have updated the developer docs in /docs if this PR makes changes that would require a [documentation change](https://cal.com/docs). If N/A, write N/A here and check the checkbox. - [ ] I confirm automated tests are in place that prove my fix is effective or that my feature works. ## How should this be tested? <!-- Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration. Write details that help to start the tests --> - Are there environment variables that should be set? - What are the minimal test data to have? - What is expected (happy path) to have (input and output)? - Any other important info that could help to test that PR ## Checklist <!-- Remove bullet points below that don't apply to you --> - I haven't read the [contributing guide](https://github.com/calcom/cal.com/blob/main/CONTRIBUTING.md) - My code doesn't follow the style guidelines of this project - I haven't commented my code, particularly in hard-to-understand areas - I haven't checked if my changes generate no new warnings * Add unit tests and e2e * fix ts errors * Add comment * bump platform libs * fix: yarn-lock * fix yarn.lock * doc update * Add isString --------- Co-authored-by: Morgan Vernay <morgan@cal.com>
144 lines
4.7 KiB
TypeScript
144 lines
4.7 KiB
TypeScript
import type { TFunction } from "next-i18next";
|
|
import z from "zod";
|
|
|
|
import { guessEventLocationType } from "@calcom/app-store/locations";
|
|
import type { Prisma } from "@calcom/prisma/client";
|
|
|
|
export const nameObjectSchema = z.object({
|
|
firstName: z.string(),
|
|
lastName: z.string().optional(),
|
|
});
|
|
|
|
function parseName(name: z.infer<typeof nameObjectSchema> | string | undefined) {
|
|
if (typeof name === "string") return name;
|
|
else if (typeof name === "object" && nameObjectSchema.parse(name))
|
|
return `${name.firstName} ${name.lastName}`.trim();
|
|
else return "Nameless";
|
|
}
|
|
|
|
export type EventNameObjectType = {
|
|
attendeeName: z.infer<typeof nameObjectSchema> | string;
|
|
eventType: string;
|
|
eventName?: string | null;
|
|
teamName?: string | null;
|
|
host: string;
|
|
location?: string | null;
|
|
eventDuration: number;
|
|
bookingFields?: Prisma.JsonObject | null;
|
|
t: TFunction;
|
|
};
|
|
|
|
export function getEventName(eventNameObj: EventNameObjectType, forAttendeeView = false) {
|
|
const attendeeName = parseName(eventNameObj.attendeeName);
|
|
|
|
if (!eventNameObj.eventName)
|
|
return eventNameObj.t("event_between_users", {
|
|
eventName: eventNameObj.eventType,
|
|
host: eventNameObj.teamName || eventNameObj.host,
|
|
attendeeName,
|
|
interpolation: {
|
|
escapeValue: false,
|
|
},
|
|
});
|
|
|
|
let eventName = eventNameObj.eventName;
|
|
let locationString = eventNameObj.location || "";
|
|
|
|
if (eventNameObj.eventName.includes("{Location}") || eventNameObj.eventName.includes("{LOCATION}")) {
|
|
const eventLocationType = guessEventLocationType(eventNameObj.location);
|
|
if (eventLocationType) {
|
|
locationString = eventLocationType.label;
|
|
}
|
|
eventName = eventName.replace("{Location}", locationString);
|
|
eventName = eventName.replace("{LOCATION}", locationString);
|
|
}
|
|
|
|
let dynamicEventName = eventName
|
|
// Need this for compatibility with older event names
|
|
.replaceAll("{Event type title}", eventNameObj.eventType)
|
|
.replaceAll("{Scheduler}", attendeeName)
|
|
.replaceAll("{Organiser}", eventNameObj.host)
|
|
.replaceAll("{Organiser first name}", eventNameObj.host.split(" ")[0])
|
|
.replaceAll("{USER}", attendeeName)
|
|
.replaceAll("{ATTENDEE}", attendeeName)
|
|
.replaceAll("{HOST}", eventNameObj.host)
|
|
.replaceAll("{HOST/ATTENDEE}", forAttendeeView ? eventNameObj.host : attendeeName)
|
|
.replaceAll("{Event duration}", `${String(eventNameObj.eventDuration)} mins`)
|
|
.replaceAll(
|
|
"{Scheduler first name}",
|
|
attendeeName === eventNameObj.t("scheduler") ? "{Scheduler first name}" : attendeeName.split(" ")[0]
|
|
);
|
|
|
|
const { bookingFields } = eventNameObj || {};
|
|
const { name } = bookingFields || {};
|
|
|
|
if (name && typeof name === "object" && !Array.isArray(name) && typeof name.lastName === "string") {
|
|
dynamicEventName = dynamicEventName.replaceAll("{Scheduler last name}", name.lastName.toString());
|
|
}
|
|
|
|
const customInputvariables = dynamicEventName.match(/\{(.+?)}/g)?.map((variable) => {
|
|
return variable.replace("{", "").replace("}", "");
|
|
});
|
|
|
|
customInputvariables?.forEach((variable) => {
|
|
if (!eventNameObj.bookingFields) return;
|
|
|
|
const bookingFieldValue = eventNameObj.bookingFields[variable as keyof typeof eventNameObj.bookingFields];
|
|
|
|
if (bookingFieldValue) {
|
|
let fieldValue;
|
|
|
|
if (typeof bookingFieldValue === "object") {
|
|
if ("value" in bookingFieldValue) {
|
|
fieldValue = bookingFieldValue.value?.toString();
|
|
} else if (variable === "name" && "firstName" in bookingFieldValue) {
|
|
const lastName = "lastName" in bookingFieldValue ? bookingFieldValue.lastName : "";
|
|
fieldValue = `${bookingFieldValue.firstName} ${lastName}`.trim();
|
|
}
|
|
} else {
|
|
fieldValue = bookingFieldValue.toString();
|
|
}
|
|
|
|
dynamicEventName = dynamicEventName.replace(`{${variable}}`, fieldValue || "");
|
|
}
|
|
});
|
|
|
|
return dynamicEventName;
|
|
}
|
|
|
|
export const validateCustomEventName = (value: string, bookingFields?: Prisma.JsonObject | null) => {
|
|
let customInputVariables: string[] = [];
|
|
if (bookingFields) {
|
|
customInputVariables = Object.keys(bookingFields).map((customInput) => {
|
|
return `{${customInput}}`;
|
|
});
|
|
}
|
|
|
|
const validVariables = customInputVariables.concat([
|
|
"{Event type title}",
|
|
"{Organiser}",
|
|
"{Scheduler}",
|
|
"{Location}",
|
|
"{Organiser first name}",
|
|
"{Scheduler first name}",
|
|
"{Scheduler last name}",
|
|
"{Event duration}",
|
|
//allowed for fallback reasons
|
|
"{LOCATION}",
|
|
"{HOST/ATTENDEE}",
|
|
"{HOST}",
|
|
"{ATTENDEE}",
|
|
"{USER}",
|
|
]);
|
|
const matches = value.match(/\{([^}]+)\}/g);
|
|
if (matches?.length) {
|
|
for (const item of matches) {
|
|
if (!validVariables.includes(item)) {
|
|
return item;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
};
|