diff --git a/apps/web/pages/new-booker/[user]/[type].tsx b/apps/web/pages/new-booker/[user]/[type].tsx index e075748e8e..7a7c2c4b97 100644 --- a/apps/web/pages/new-booker/[user]/[type].tsx +++ b/apps/web/pages/new-booker/[user]/[type].tsx @@ -8,6 +8,7 @@ import type { GetBookingType } from "@calcom/features/bookings/lib/get-booking"; import { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains"; import { classNames } from "@calcom/lib"; import { getUsernameList } from "@calcom/lib/defaultEvents"; +import slugify from "@calcom/lib/slugify"; import prisma from "@calcom/prisma"; import type { inferSSRProps } from "@lib/types/inferSSRProps"; @@ -40,17 +41,16 @@ export default function Type({ slug, user, booking, away, isBrandingHidden }: Pa Type.PageWrapper = PageWrapper; async function getDynamicGroupPageProps(context: GetServerSidePropsContext) { - const { user, type: slug } = paramsSchema.parse(context.params); + const { user: usernames, type: slug } = paramsSchema.parse(context.params); const { rescheduleUid } = context.query; const { ssrInit } = await import("@server/lib/ssr"); const ssr = await ssrInit(context); - const usernameList = getUsernameList(user); const users = await prisma.user.findMany({ where: { username: { - in: usernameList, + in: usernames, }, }, select: { @@ -71,7 +71,7 @@ async function getDynamicGroupPageProps(context: GetServerSidePropsContext) { // We use this to both prefetch the query on the server, // as well as to check if the event exist, so we c an show a 404 otherwise. - const eventData = await ssr.viewer.public.event.fetch({ username: user, eventSlug: slug }); + const eventData = await ssr.viewer.public.event.fetch({ username: usernames.join("+"), eventSlug: slug }); if (!eventData) { return { @@ -82,7 +82,7 @@ async function getDynamicGroupPageProps(context: GetServerSidePropsContext) { return { props: { booking, - user, + user: usernames.join("+"), slug, away: false, trpcState: ssr.dehydrate(), @@ -93,13 +93,11 @@ async function getDynamicGroupPageProps(context: GetServerSidePropsContext) { } async function getUserPageProps(context: GetServerSidePropsContext) { - const { user: uname, type: slug } = paramsSchema.parse(context.params); + const { user: usernames, type: slug } = paramsSchema.parse(context.params); + const username = usernames[0]; const { rescheduleUid } = context.query; const { currentOrgDomain, isValidOrgDomain } = orgDomainConfig(context.req.headers.host ?? ""); - /** TODO: We should standarize this */ - const username = uname.toLowerCase().replace(/( |%20)/g, "+"); - const { ssrInit } = await import("@server/lib/ssr"); const ssr = await ssrInit(context); const user = await prisma.user.findFirst({ @@ -151,13 +149,16 @@ async function getUserPageProps(context: GetServerSidePropsContext) { }; } -const paramsSchema = z.object({ type: z.string(), user: z.string() }); +const paramsSchema = z.object({ + type: z.string().transform((s) => slugify(s)), + user: z.string().transform((s) => getUsernameList(s)), +}); // Booker page fetches a tiny bit of data server side, to determine early // whether the page should show an away state or dynamic booking not allowed. export const getServerSideProps = async (context: GetServerSidePropsContext) => { const { user } = paramsSchema.parse(context.params); - const isDynamicGroup = getUsernameList(user).length > 1; + const isDynamicGroup = user.length > 1; return isDynamicGroup ? await getDynamicGroupPageProps(context) : await getUserPageProps(context); }; diff --git a/apps/web/pages/new-booker/d/[link]/[slug].tsx b/apps/web/pages/new-booker/d/[link]/[slug].tsx index 21178d8805..1fb184088e 100644 --- a/apps/web/pages/new-booker/d/[link]/[slug].tsx +++ b/apps/web/pages/new-booker/d/[link]/[slug].tsx @@ -6,6 +6,7 @@ import { BookerSeo } from "@calcom/features/bookings/components/BookerSeo"; import { getBookingByUidOrRescheduleUid } from "@calcom/features/bookings/lib/get-booking"; import type { GetBookingType } from "@calcom/features/bookings/lib/get-booking"; import { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains"; +import slugify from "@calcom/lib/slugify"; import prisma from "@calcom/prisma"; import type { inferSSRProps } from "@lib/types/inferSSRProps"; @@ -129,7 +130,7 @@ async function getUserPageProps(context: GetServerSidePropsContext) { }; } -const paramsSchema = z.object({ link: z.string(), slug: z.string() }); +const paramsSchema = z.object({ link: z.string(), slug: z.string().transform((s) => slugify(s)) }); // Booker page fetches a tiny bit of data server side, to determine early // whether the page should show an away state or dynamic booking not allowed. diff --git a/apps/web/pages/new-booker/team/[slug]/[type].tsx b/apps/web/pages/new-booker/team/[slug]/[type].tsx index d56fbc892e..6e9fab27dc 100644 --- a/apps/web/pages/new-booker/team/[slug]/[type].tsx +++ b/apps/web/pages/new-booker/team/[slug]/[type].tsx @@ -6,6 +6,7 @@ import { BookerSeo } from "@calcom/features/bookings/components/BookerSeo"; import { getBookingByUidOrRescheduleUid } from "@calcom/features/bookings/lib/get-booking"; import type { GetBookingType } from "@calcom/features/bookings/lib/get-booking"; import { classNames } from "@calcom/lib"; +import slugify from "@calcom/lib/slugify"; import prisma from "@calcom/prisma"; import type { inferSSRProps } from "@lib/types/inferSSRProps"; @@ -39,7 +40,10 @@ export default function Type({ slug, user, booking, away, isBrandingHidden }: Pa Type.PageWrapper = PageWrapper; -const paramsSchema = z.object({ type: z.string(), slug: z.string() }); +const paramsSchema = z.object({ + type: z.string().transform((s) => slugify(s)), + slug: z.string().transform((s) => slugify(s)), +}); // Booker page fetches a tiny bit of data server side: // 1. Check if team exists, to show 404 diff --git a/packages/lib/defaultEvents.ts b/packages/lib/defaultEvents.ts index 8bce4181c2..b49fc87d68 100644 --- a/packages/lib/defaultEvents.ts +++ b/packages/lib/defaultEvents.ts @@ -2,6 +2,7 @@ import type { Prisma, Credential } from "@prisma/client"; import { DailyLocationType } from "@calcom/app-store/locations"; import { getBookingFieldsWithSystemFields } from "@calcom/features/bookings/lib/getBookingFields"; +import slugify from "@calcom/lib/slugify"; import { PeriodType, SchedulingType } from "@calcom/prisma/enums"; import type { userSelect } from "@calcom/prisma/selects"; import type { CustomInputSchema } from "@calcom/prisma/zod-utils"; @@ -177,14 +178,8 @@ export const getUsernameList = (users: string | string[] | undefined): string[] // So, even though this code handles even if individual user is dynamic link, that isn't a possibility right now. users = arrayCast(users); - const allUsers = users.map((user) => - user - .toLowerCase() - .replace(/( |%20|%2b)/g, "+") - .split("+") - ); - - return Array.prototype.concat(...allUsers); + const allUsers = users.map((user) => user.split("+")).flat(); + return Array.prototype.concat(...allUsers.map((userSlug) => slugify(userSlug))); }; export default defaultEvents;