diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json index 514edf42cf..aae8d922dc 100644 --- a/apps/web/public/static/locales/en/common.json +++ b/apps/web/public/static/locales/en/common.json @@ -3038,6 +3038,8 @@ "tip_username_plus": "Tip: You can a '+' between usernames: cal.com/anna+brian to make a dynamic group meeting", "user_has_no_team_yet": "You don't have a team yet", "no_team_members": "You don't have team members yet", + "hide_team_profile_link": "Hide Team Profile Link", + "hide_team_profile_link_description": "Hide the team profile link on booking pages", "display": "Display", "could_not_find_slug_to_publish_org": "Could not find slug to publish the organization", "picklist": "Picklist", diff --git a/packages/features/bookings/components/event-meta/Members.tsx b/packages/features/bookings/components/event-meta/Members.tsx index e9dbc6a947..e71260af50 100644 --- a/packages/features/bookings/components/event-meta/Members.tsx +++ b/packages/features/bookings/components/event-meta/Members.tsx @@ -47,7 +47,7 @@ export const EventMembers = ({ { // We don't want booker to be able to see the list of other users or teams inside the embed href: - isEmbed || isPlatform || isPrivateLink + isEmbed || isPlatform || isPrivateLink || entity.hideProfileLink ? null : entity.teamSlug ? getTeamUrlSync({ orgSlug: entity.orgSlug, teamSlug: entity.teamSlug }) @@ -67,7 +67,7 @@ export const EventMembers = ({ ...orgOrTeamAvatarItem, ...shownUsers.map((user) => ({ href: - isPlatform || isPrivateLink + isPlatform || isPrivateLink || entity.hideProfileLink ? null : `${getBookerBaseUrlSync(user.profile?.organization?.slug ?? null)}/${ user.profile?.username diff --git a/packages/features/ee/teams/pages/team-appearance-view.tsx b/packages/features/ee/teams/pages/team-appearance-view.tsx index 423d2178e1..e6581483ec 100644 --- a/packages/features/ee/teams/pages/team-appearance-view.tsx +++ b/packages/features/ee/teams/pages/team-appearance-view.tsx @@ -14,9 +14,9 @@ import { useParamsWithFallback } from "@calcom/lib/hooks/useParamsWithFallback"; import { MembershipRole } from "@calcom/prisma/enums"; import { trpc } from "@calcom/trpc/react"; import type { RouterOutputs } from "@calcom/trpc/react"; +import { Button } from "@calcom/ui/components/button"; import { Form } from "@calcom/ui/components/form"; import { SettingsToggle } from "@calcom/ui/components/form"; -import { Button } from "@calcom/ui/components/button"; import { showToast } from "@calcom/ui/components/toast"; import ThemeLabel from "../../../settings/ThemeLabel"; @@ -34,6 +34,7 @@ const ProfileView = ({ team }: ProfileViewProps) => { const [hideBrandingValue, setHideBrandingValue] = useState(team?.hideBranding ?? false); const [hideBookATeamMember, setHideBookATeamMember] = useState(team?.hideBookATeamMember ?? false); + const [hideTeamProfileLink, setHideTeamProfileLink] = useState(team?.hideTeamProfileLink ?? false); const themeForm = useForm<{ theme: string | null | undefined }>({ defaultValues: { @@ -168,6 +169,18 @@ const ProfileView = ({ team }: ProfileViewProps) => { mutation.mutate({ id: team.id, hideBookATeamMember: checked }); }} /> + + { + setHideTeamProfileLink(checked); + mutation.mutate({ id: team.id, hideTeamProfileLink: checked }); + }} + /> ) : ( diff --git a/packages/features/eventtypes/lib/getPublicEvent.ts b/packages/features/eventtypes/lib/getPublicEvent.ts index 9e1fd36f97..a8342b1746 100644 --- a/packages/features/eventtypes/lib/getPublicEvent.ts +++ b/packages/features/eventtypes/lib/getPublicEvent.ts @@ -94,6 +94,7 @@ const getPublicEventSelect = (fetchAllUsers: boolean) => { name: true, logoUrl: true, theme: true, + hideTeamProfileLink: true, parent: { select: { slug: true, @@ -309,6 +310,7 @@ export const getPublicEvent = async ( name: unPublishedOrgUser?.profile?.organization?.name ?? null, teamSlug: null, logoUrl: null, + hideProfileLink: false, }, isInstantEvent: false, instantMeetingParameters: [], @@ -470,6 +472,7 @@ export const getPublicEvent = async ( if (event.team?.isPrivate && !isTeamAdminOrOwner && !isOrgAdminOrOwner) { users = []; } + return { ...eventWithUserProfiles, bookerLayouts: bookerLayoutsSchema.parse(eventMetaData?.bookerLayouts || null), @@ -499,6 +502,7 @@ export const getPublicEvent = async ( eventWithUserProfiles.team?.parent?.name || eventWithUserProfiles.team?.name) ?? null, + hideProfileLink: eventWithUserProfiles.team?.hideTeamProfileLink ?? false, ...(orgDetails ? { logoUrl: getPlaceholderAvatar(orgDetails?.logoUrl, orgDetails?.name), diff --git a/packages/lib/server/queries/teams/index.ts b/packages/lib/server/queries/teams/index.ts index 928878f170..1d34c0f108 100644 --- a/packages/lib/server/queries/teams/index.ts +++ b/packages/lib/server/queries/teams/index.ts @@ -310,6 +310,7 @@ export async function getTeamWithoutMembers(args: { bio: true, hideBranding: true, hideBookATeamMember: true, + hideTeamProfileLink: true, isPrivate: true, metadata: true, bookingLimits: true, diff --git a/packages/prisma/migrations/20250324051542_add_hide_team_profile_link_in_team/migration.sql b/packages/prisma/migrations/20250324051542_add_hide_team_profile_link_in_team/migration.sql new file mode 100644 index 0000000000..7cc8b16310 --- /dev/null +++ b/packages/prisma/migrations/20250324051542_add_hide_team_profile_link_in_team/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Team" ADD COLUMN "hideTeamProfileLink" BOOLEAN NOT NULL DEFAULT false; diff --git a/packages/prisma/schema.prisma b/packages/prisma/schema.prisma index 716d68ed5b..819766aa21 100644 --- a/packages/prisma/schema.prisma +++ b/packages/prisma/schema.prisma @@ -440,6 +440,7 @@ model Team { appIconLogo String? bio String? hideBranding Boolean @default(false) + hideTeamProfileLink Boolean @default(false) isPrivate Boolean @default(false) hideBookATeamMember Boolean @default(false) members Membership[] diff --git a/packages/trpc/server/routers/viewer/teams/update.handler.ts b/packages/trpc/server/routers/viewer/teams/update.handler.ts index d3cf2f7650..8e24e5130d 100644 --- a/packages/trpc/server/routers/viewer/teams/update.handler.ts +++ b/packages/trpc/server/routers/viewer/teams/update.handler.ts @@ -60,6 +60,7 @@ export const updateHandler = async ({ ctx, input }: UpdateOptions) => { hideBranding: input.hideBranding, isPrivate: input.isPrivate, hideBookATeamMember: input.hideBookATeamMember, + hideTeamProfileLink: input.hideTeamProfileLink, brandColor: input.brandColor, darkBrandColor: input.darkBrandColor, theme: input.theme, diff --git a/packages/trpc/server/routers/viewer/teams/update.schema.ts b/packages/trpc/server/routers/viewer/teams/update.schema.ts index 8825991180..582c2a13ff 100644 --- a/packages/trpc/server/routers/viewer/teams/update.schema.ts +++ b/packages/trpc/server/routers/viewer/teams/update.schema.ts @@ -13,6 +13,7 @@ export type TUpdateInputSchema = { slug?: string; hideBranding?: boolean; hideBookATeamMember?: boolean; + hideTeamProfileLink?: boolean; isPrivate?: boolean; brandColor?: string; darkBrandColor?: string; @@ -37,6 +38,7 @@ export const ZUpdateInputSchema: z.Schema = z.object({ .optional(), hideBranding: z.boolean().optional(), hideBookATeamMember: z.boolean().optional(), + hideTeamProfileLink: z.boolean().optional(), isPrivate: z.boolean().optional(), brandColor: z.string().optional(), darkBrandColor: z.string().optional(),