diff --git a/apps/web/components/team/screens/Team.tsx b/apps/web/components/team/screens/Team.tsx
index 644124b7dd..cfe2748a15 100644
--- a/apps/web/components/team/screens/Team.tsx
+++ b/apps/web/components/team/screens/Team.tsx
@@ -18,8 +18,8 @@ const Member = ({ member, teamName }: { member: MemberType; teamName: string | n
const router = useRouter();
const isBioEmpty = !member.bio || !member.bio.replace("
", "").length;
- // slug is a route parameter, we don't want to forward it to the next route
- const { slug: _slug, ...queryParamsToForward } = router.query;
+ // We don't want to forward orgSlug and user which are route params to the next route
+ const { slug: _slug, orgSlug: _orgSlug, user: _user, ...queryParamsToForward } = router.query;
return (
diff --git a/apps/web/pages/[user]/[type].tsx b/apps/web/pages/[user]/[type].tsx
index 509ec9a83c..77c3468737 100644
--- a/apps/web/pages/[user]/[type].tsx
+++ b/apps/web/pages/[user]/[type].tsx
@@ -17,7 +17,7 @@ import PageWrapper from "@components/PageWrapper";
export type PageProps = inferSSRProps;
-export default function Type({ slug, user, booking, away, isBrandingHidden, rescheduleUid }: PageProps) {
+export default function Type({ slug, user, booking, away, isBrandingHidden, rescheduleUid, org }: PageProps) {
const isEmbed = typeof window !== "undefined" && window?.isEmbed?.();
return (
@@ -26,6 +26,7 @@ export default function Type({ slug, user, booking, away, isBrandingHidden, resc
eventSlug={slug}
rescheduleUid={rescheduleUid ?? undefined}
hideBranding={isBrandingHidden}
+ org={org}
/>
);
@@ -46,12 +48,18 @@ async function getDynamicGroupPageProps(context: GetServerSidePropsContext) {
const { ssrInit } = await import("@server/lib/ssr");
const ssr = await ssrInit(context);
+ const { currentOrgDomain, isValidOrgDomain } = orgDomainConfig(context.req.headers.host ?? "");
const users = await prisma.user.findMany({
where: {
username: {
in: usernames,
},
+ organization: isValidOrgDomain
+ ? {
+ slug: currentOrgDomain,
+ }
+ : null,
},
select: {
allowDynamicBooking: true,
@@ -63,6 +71,7 @@ async function getDynamicGroupPageProps(context: GetServerSidePropsContext) {
notFound: true,
};
}
+ const org = isValidOrgDomain ? currentOrgDomain : null;
let booking: GetBookingType | null = null;
if (rescheduleUid) {
@@ -73,7 +82,11 @@ 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: usernames.join("+"), eventSlug: slug });
+ const eventData = await ssr.viewer.public.event.fetch({
+ username: usernames.join("+"),
+ eventSlug: slug,
+ org,
+ });
if (!eventData) {
return {
@@ -83,6 +96,7 @@ async function getDynamicGroupPageProps(context: GetServerSidePropsContext) {
return {
props: {
+ org,
booking,
user: usernames.join("+"),
slug,
@@ -132,9 +146,14 @@ async function getUserPageProps(context: GetServerSidePropsContext) {
booking = await getBookingForSeatedEvent(`${bookingUid}`);
}
+ const org = isValidOrgDomain ? currentOrgDomain : null;
// 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, eventSlug: slug });
+ const eventData = await ssr.viewer.public.event.fetch({
+ username,
+ eventSlug: slug,
+ org,
+ });
if (!eventData) {
return {
@@ -148,6 +167,7 @@ async function getUserPageProps(context: GetServerSidePropsContext) {
away: user?.away,
user: username,
slug,
+ org,
trpcState: ssr.dehydrate(),
isBrandingHidden: user?.hideBranding,
themeBasis: username,
diff --git a/apps/web/pages/api/user/avatar.ts b/apps/web/pages/api/user/avatar.ts
index 321264ffaf..4059f87900 100644
--- a/apps/web/pages/api/user/avatar.ts
+++ b/apps/web/pages/api/user/avatar.ts
@@ -18,7 +18,7 @@ const querySchema = z
async function getIdentityData(req: NextApiRequest) {
const { username, teamname } = querySchema.parse(req.query);
const { currentOrgDomain, isValidOrgDomain } = orgDomainConfig(req.headers.host ?? "");
-
+ const org = isValidOrgDomain ? currentOrgDomain : null;
if (username) {
const user = await prisma.user.findFirst({
where: {
@@ -35,6 +35,7 @@ async function getIdentityData(req: NextApiRequest) {
name: username,
email: user?.email,
avatar: user?.avatar,
+ org,
};
}
if (teamname) {
@@ -50,6 +51,7 @@ async function getIdentityData(req: NextApiRequest) {
select: { logo: true },
});
return {
+ org,
name: teamname,
email: null,
avatar: team?.logo || getPlaceholderAvatar(null, teamname),
@@ -62,6 +64,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const img = identity?.avatar;
// If image isn't set or links to this route itself, use default avatar
if (!img) {
+ if (identity?.org) {
+ res.setHeader("x-cal-org", identity.org);
+ }
res.writeHead(302, {
Location: defaultAvatarSrc({
md5: crypto
@@ -70,16 +75,23 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
.digest("hex"),
}),
});
+
return res.end();
}
if (!img.includes("data:image")) {
+ if (identity.org) {
+ res.setHeader("x-cal-org", identity.org);
+ }
res.writeHead(302, { Location: img });
return res.end();
}
const decoded = img.toString().replace("data:image/png;base64,", "").replace("data:image/jpeg;base64,", "");
const imageResp = Buffer.from(decoded, "base64");
+ if (identity.org) {
+ res.setHeader("x-cal-org", identity.org);
+ }
res.writeHead(200, {
"Content-Type": "image/png",
"Content-Length": imageResp.length,
diff --git a/apps/web/pages/d/[link]/[slug].tsx b/apps/web/pages/d/[link]/[slug].tsx
index 707f94d907..6c7dd1bd53 100644
--- a/apps/web/pages/d/[link]/[slug].tsx
+++ b/apps/web/pages/d/[link]/[slug].tsx
@@ -15,7 +15,7 @@ import PageWrapper from "@components/PageWrapper";
type PageProps = inferSSRProps;
-export default function Type({ slug, user, booking, away, isBrandingHidden, isTeamEvent }: PageProps) {
+export default function Type({ slug, user, booking, away, isBrandingHidden, isTeamEvent, org }: PageProps) {
return (
);
@@ -42,6 +44,7 @@ async function getUserPageProps(context: GetServerSidePropsContext) {
const { link, slug } = paramsSchema.parse(context.params);
const { rescheduleUid } = context.query;
const { currentOrgDomain, isValidOrgDomain } = orgDomainConfig(context.req.headers.host ?? "");
+ const org = isValidOrgDomain ? currentOrgDomain : null;
const { ssrInit } = await import("@server/lib/ssr");
const ssr = await ssrInit(context);
@@ -107,7 +110,7 @@ async function getUserPageProps(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, eventSlug: slug, isTeamEvent });
+ const eventData = await ssr.viewer.public.event.fetch({ username, eventSlug: slug, isTeamEvent, org });
if (!eventData) {
return {
@@ -117,6 +120,7 @@ async function getUserPageProps(context: GetServerSidePropsContext) {
return {
props: {
+ org,
booking,
away: user?.away,
user: username,
diff --git a/apps/web/pages/org/[orgSlug]/[user]/[type].ts b/apps/web/pages/org/[orgSlug]/[user]/[type].tsx
similarity index 89%
rename from apps/web/pages/org/[orgSlug]/[user]/[type].ts
rename to apps/web/pages/org/[orgSlug]/[user]/[type].tsx
index 3d98769121..134dc764a3 100644
--- a/apps/web/pages/org/[orgSlug]/[user]/[type].ts
+++ b/apps/web/pages/org/[orgSlug]/[user]/[type].tsx
@@ -55,8 +55,8 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
type Props = UserTypePageProps | TeamTypePageProps;
export default function Page(props: Props) {
- if ((props as TeamTypePageProps)?.teamId) return TeamTypePage(props as TeamTypePageProps);
- return UserTypePage(props as UserTypePageProps);
+ if ((props as TeamTypePageProps)?.teamId) return ;
+ return ;
}
Page.PageWrapper = PageWrapper;
diff --git a/apps/web/pages/org/[orgSlug]/[user]/index.tsx b/apps/web/pages/org/[orgSlug]/[user]/index.tsx
index 67a68e5012..ca3ef3e56e 100644
--- a/apps/web/pages/org/[orgSlug]/[user]/index.tsx
+++ b/apps/web/pages/org/[orgSlug]/[user]/index.tsx
@@ -33,8 +33,8 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
type Props = UserPageProps | TeamPageProps;
export default function Page(props: Props) {
- if ((props as TeamPageProps)?.team) return TeamPage(props as TeamPageProps);
- return UserPage(props as UserPageProps);
+ if ((props as TeamPageProps)?.team) return ;
+ return ;
}
Page.PageWrapper = PageWrapper;
diff --git a/apps/web/pages/team/[slug].tsx b/apps/web/pages/team/[slug].tsx
index 8b18720fe7..abc92bcad7 100644
--- a/apps/web/pages/team/[slug].tsx
+++ b/apps/web/pages/team/[slug].tsx
@@ -64,7 +64,7 @@ function TeamPage({ team, isUnpublished, markdownStrippedBio, isValidOrgDomain }
}
// slug is a route parameter, we don't want to forward it to the next route
- const { slug: _slug, ...queryParamsToForward } = router.query;
+ const { slug: _slug, orgSlug: _orgSlug, user: _user, ...queryParamsToForward } = router.query;
const EventTypes = () => (
diff --git a/apps/web/pages/team/[slug]/[type].tsx b/apps/web/pages/team/[slug]/[type].tsx
index d9b6590e98..a0faa0cc34 100644
--- a/apps/web/pages/team/[slug]/[type].tsx
+++ b/apps/web/pages/team/[slug]/[type].tsx
@@ -5,6 +5,7 @@ import { Booker } from "@calcom/atoms";
import { BookerSeo } from "@calcom/features/bookings/components/BookerSeo";
import { getBookingForReschedule } 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 { classNames } from "@calcom/lib";
import slugify from "@calcom/lib/slugify";
import prisma from "@calcom/prisma";
@@ -15,7 +16,7 @@ import PageWrapper from "@components/PageWrapper";
export type PageProps = inferSSRProps;
-export default function Type({ slug, user, booking, away, isBrandingHidden }: PageProps) {
+export default function Type({ slug, user, booking, away, isBrandingHidden, org }: PageProps) {
const isEmbed = typeof window !== "undefined" && window?.isEmbed?.();
return (
@@ -25,6 +26,7 @@ export default function Type({ slug, user, booking, away, isBrandingHidden }: Pa
rescheduleUid={booking?.uid}
hideBranding={isBrandingHidden}
isTeamEvent
+ org={org}
/>
);
@@ -53,10 +56,16 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
const { rescheduleUid } = context.query;
const { ssrInit } = await import("@server/lib/ssr");
const ssr = await ssrInit(context);
+ const { currentOrgDomain, isValidOrgDomain } = orgDomainConfig(context.req.headers.host ?? "");
const team = await prisma.team.findFirst({
where: {
slug: teamSlug,
+ parent: isValidOrgDomain
+ ? {
+ slug: currentOrgDomain,
+ }
+ : null,
},
select: {
id: true,
@@ -67,7 +76,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
if (!team) {
return {
notFound: true,
- };
+ } as const;
}
let booking: GetBookingType | null = null;
@@ -75,22 +84,25 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
booking = await getBookingForReschedule(`${rescheduleUid}`);
}
+ const org = isValidOrgDomain ? currentOrgDomain : null;
// 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: teamSlug,
eventSlug: meetingSlug,
isTeamEvent: true,
+ org,
});
if (!eventData) {
return {
notFound: true,
- };
+ } as const;
}
return {
props: {
+ org,
booking,
away: false,
user: teamSlug,
diff --git a/apps/web/pages/team/[slug]/[type]/embed.tsx b/apps/web/pages/team/[slug]/[type]/embed.tsx
index d9b6590e98..5cfd1726ca 100644
--- a/apps/web/pages/team/[slug]/[type]/embed.tsx
+++ b/apps/web/pages/team/[slug]/[type]/embed.tsx
@@ -1,104 +1,7 @@
-import type { GetServerSidePropsContext } from "next";
-import { z } from "zod";
+import withEmbedSsr from "@lib/withEmbedSsr";
-import { Booker } from "@calcom/atoms";
-import { BookerSeo } from "@calcom/features/bookings/components/BookerSeo";
-import { getBookingForReschedule } 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 { getServerSideProps as _getServerSideProps } from "../[type]";
-import type { inferSSRProps } from "@lib/types/inferSSRProps";
+export { default } from "../[type]";
-import PageWrapper from "@components/PageWrapper";
-
-export type PageProps = inferSSRProps;
-
-export default function Type({ slug, user, booking, away, isBrandingHidden }: PageProps) {
- const isEmbed = typeof window !== "undefined" && window?.isEmbed?.();
- return (
-
-
-
-
- );
-}
-
-Type.PageWrapper = PageWrapper;
-
-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
-// 2. If rescheduling, get the booking details
-export const getServerSideProps = async (context: GetServerSidePropsContext) => {
- const { slug: teamSlug, type: meetingSlug } = paramsSchema.parse(context.params);
- const { rescheduleUid } = context.query;
- const { ssrInit } = await import("@server/lib/ssr");
- const ssr = await ssrInit(context);
-
- const team = await prisma.team.findFirst({
- where: {
- slug: teamSlug,
- },
- select: {
- id: true,
- hideBranding: true,
- },
- });
-
- if (!team) {
- return {
- notFound: true,
- };
- }
-
- let booking: GetBookingType | null = null;
- if (rescheduleUid) {
- booking = await getBookingForReschedule(`${rescheduleUid}`);
- }
-
- // 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: teamSlug,
- eventSlug: meetingSlug,
- isTeamEvent: true,
- });
-
- if (!eventData) {
- return {
- notFound: true,
- };
- }
-
- return {
- props: {
- booking,
- away: false,
- user: teamSlug,
- teamId: team.id,
- slug: meetingSlug,
- trpcState: ssr.dehydrate(),
- isBrandingHidden: team?.hideBranding,
- themeBasis: null,
- },
- };
-};
+export const getServerSideProps = withEmbedSsr(_getServerSideProps);
diff --git a/packages/features/bookings/Booker/Booker.tsx b/packages/features/bookings/Booker/Booker.tsx
index cec7296583..e0138e62a9 100644
--- a/packages/features/bookings/Booker/Booker.tsx
+++ b/packages/features/bookings/Booker/Booker.tsx
@@ -37,6 +37,7 @@ const BookerComponent = ({
bookingData,
hideBranding = false,
isTeamEvent,
+ org,
}: BookerProps) => {
const isMobile = useMediaQuery("(max-width: 768px)");
const isTablet = useMediaQuery("(max-width: 1024px)");
@@ -96,6 +97,7 @@ const BookerComponent = ({
bookingData,
layout: defaultLayout,
isTeamEvent,
+ org,
});
useEffect(() => {
diff --git a/packages/features/bookings/Booker/store.ts b/packages/features/bookings/Booker/store.ts
index 0fdeba4e34..605b9a20a6 100644
--- a/packages/features/bookings/Booker/store.ts
+++ b/packages/features/bookings/Booker/store.ts
@@ -25,6 +25,7 @@ type StoreInitializeType = {
bookingData?: GetBookingType | null | undefined;
rescheduleUid?: string | null;
seatReferenceUid?: string;
+ org?: string | null;
};
type SeatedEventData = {
@@ -105,6 +106,7 @@ export type BookerStore = {
* both the slug and the event slug.
*/
isTeamEvent: boolean;
+ org?: string | null;
seatedEventData: SeatedEventData;
setSeatedEventData: (seatedEventData: SeatedEventData) => void;
};
@@ -183,6 +185,7 @@ export const useBookerStore = create((set, get) => ({
bookingData = null,
layout,
isTeamEvent,
+ org,
}: StoreInitializeType) => {
const selectedDateInStore = get().selectedDate;
@@ -201,6 +204,7 @@ export const useBookerStore = create((set, get) => ({
username,
eventSlug,
eventId,
+ org,
rescheduleUid,
bookingUid,
bookingData,
@@ -250,6 +254,7 @@ export const useInitializeBookerStore = ({
bookingData = null,
layout,
isTeamEvent,
+ org,
}: StoreInitializeType) => {
const initializeStore = useBookerStore((state) => state.initialize);
useEffect(() => {
@@ -262,6 +267,18 @@ export const useInitializeBookerStore = ({
bookingData,
layout,
isTeamEvent,
+ org,
});
- }, [initializeStore, username, eventSlug, month, eventId, rescheduleUid, bookingData, layout, isTeamEvent]);
+ }, [
+ initializeStore,
+ org,
+ username,
+ eventSlug,
+ month,
+ eventId,
+ rescheduleUid,
+ bookingData,
+ layout,
+ isTeamEvent,
+ ]);
};
diff --git a/packages/features/bookings/Booker/types.ts b/packages/features/bookings/Booker/types.ts
index 7f0ff27516..14e3ec3043 100644
--- a/packages/features/bookings/Booker/types.ts
+++ b/packages/features/bookings/Booker/types.ts
@@ -5,6 +5,8 @@ import type { GetBookingType } from "../lib/get-booking";
export interface BookerProps {
eventSlug: string;
username: string;
+ // Make it optional later, once we figure out where we can possibly need to set org
+ org: string | null;
/**
* If month is NOT set as a prop on the component, we expect a query parameter
diff --git a/packages/features/bookings/Booker/utils/event.ts b/packages/features/bookings/Booker/utils/event.ts
index 0cdb6f9b79..df8532aa3e 100644
--- a/packages/features/bookings/Booker/utils/event.ts
+++ b/packages/features/bookings/Booker/utils/event.ts
@@ -17,9 +17,10 @@ import { useBookerStore } from "../store";
export const useEvent = () => {
const [username, eventSlug] = useBookerStore((state) => [state.username, state.eventSlug], shallow);
const isTeamEvent = useBookerStore((state) => state.isTeamEvent);
+ const org = useBookerStore((state) => state.org);
return trpc.viewer.public.event.useQuery(
- { username: username ?? "", eventSlug: eventSlug ?? "", isTeamEvent },
+ { username: username ?? "", eventSlug: eventSlug ?? "", isTeamEvent, org: org ?? null },
{ refetchOnWindowFocus: false, enabled: Boolean(username) && Boolean(eventSlug) }
);
};
diff --git a/packages/features/bookings/components/BookerSeo.tsx b/packages/features/bookings/components/BookerSeo.tsx
index 0143b050ec..215527a171 100644
--- a/packages/features/bookings/components/BookerSeo.tsx
+++ b/packages/features/bookings/components/BookerSeo.tsx
@@ -8,13 +8,14 @@ interface BookerSeoProps {
rescheduleUid: string | undefined;
hideBranding?: boolean;
isTeamEvent?: boolean;
+ org: string | null;
}
export const BookerSeo = (props: BookerSeoProps) => {
- const { eventSlug, username, rescheduleUid, hideBranding, isTeamEvent } = props;
+ const { eventSlug, username, rescheduleUid, hideBranding, isTeamEvent, org } = props;
const { t } = useLocale();
const { data: event } = trpc.viewer.public.event.useQuery(
- { username, eventSlug, isTeamEvent },
+ { username, eventSlug, isTeamEvent, org },
{ refetchOnWindowFocus: false }
);
diff --git a/packages/features/eventtypes/lib/getPublicEvent.ts b/packages/features/eventtypes/lib/getPublicEvent.ts
index da88f674a7..c601c619de 100644
--- a/packages/features/eventtypes/lib/getPublicEvent.ts
+++ b/packages/features/eventtypes/lib/getPublicEvent.ts
@@ -81,10 +81,15 @@ export const getPublicEvent = async (
username: string,
eventSlug: string,
isTeamEvent: boolean | undefined,
+ org: string | null,
prisma: PrismaClient
) => {
const usernameList = getUsernameList(username);
-
+ const orgQuery = org
+ ? {
+ slug: org ?? null,
+ }
+ : null;
// In case of dynamic group event, we fetch user's data and use the default event.
if (usernameList.length > 1) {
const users = await prisma.user.findMany({
@@ -92,6 +97,7 @@ export const getPublicEvent = async (
username: {
in: usernameList,
},
+ organization: orgQuery,
},
select: {
username: true,
@@ -151,12 +157,14 @@ export const getPublicEvent = async (
? {
team: {
slug: username,
+ parent: orgQuery,
},
}
: {
users: {
some: {
username,
+ organization: orgQuery,
},
},
team: null,
@@ -192,6 +200,7 @@ export const getPublicEvent = async (
// Sets user data on profile object for easier access
profile: getProfileFromEvent(event),
users,
+ orgDomain: org,
};
};
diff --git a/packages/trpc/server/routers/publicViewer/event.handler.ts b/packages/trpc/server/routers/publicViewer/event.handler.ts
index 6daee0a968..c1a20e5a77 100644
--- a/packages/trpc/server/routers/publicViewer/event.handler.ts
+++ b/packages/trpc/server/routers/publicViewer/event.handler.ts
@@ -10,6 +10,12 @@ interface EventHandlerOptions {
}
export const eventHandler = async ({ ctx, input }: EventHandlerOptions) => {
- const event = await getPublicEvent(input.username, input.eventSlug, input.isTeamEvent, ctx.prisma);
+ const event = await getPublicEvent(
+ input.username,
+ input.eventSlug,
+ input.isTeamEvent,
+ input.org,
+ ctx.prisma
+ );
return event;
};
diff --git a/packages/trpc/server/routers/publicViewer/event.schema.ts b/packages/trpc/server/routers/publicViewer/event.schema.ts
index d5c01b9248..6436d1642a 100644
--- a/packages/trpc/server/routers/publicViewer/event.schema.ts
+++ b/packages/trpc/server/routers/publicViewer/event.schema.ts
@@ -4,6 +4,7 @@ export const ZEventInputSchema = z.object({
username: z.string(),
eventSlug: z.string(),
isTeamEvent: z.boolean().optional(),
+ org: z.string().nullable(),
});
export type TEventInputSchema = z.infer;