From f755312ed769d396c6c6ab5024c313b0d10fc761 Mon Sep 17 00:00:00 2001 From: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com> Date: Thu, 6 Jul 2023 15:25:12 +0530 Subject: [PATCH] feat: Make Team Private ## What does this PR do? Fixes https://github.com/calcom/cal.com/issues/8974 1) When user is admin Screenshot 2023-07-03 at 6 45 50 PM 2) When user is not admin and team is private Screenshot 2023-07-03 at 6 47 15 PM 3) Screenshot 2023-07-03 at 6 51 56 PM ## Type of change - New feature (non-breaking change which adds functionality) ## How should this be tested? 1) go to Team members page and turn on switch Make Team Private. Now after making the team private only admin would be able to see all the members list in the settings. There will not be a button to Book a team member instead on the team page like before. ## Mandatory Tasks - [ ] Make sure you have self-reviewed the code. A decent size PR without self-review might be rejected. --- apps/web/pages/team/[slug].tsx | 17 ++++-- apps/web/public/static/locales/en/common.json | 3 + .../components/MakeTeamPrivateSwitch.tsx | 60 +++++++++++++++++++ .../ee/teams/pages/team-members-view.tsx | 19 +++++- packages/lib/server/queries/teams/index.ts | 1 + .../migration.sql | 2 + packages/prisma/schema.prisma | 1 + .../routers/viewer/teams/update.handler.ts | 1 + .../routers/viewer/teams/update.schema.ts | 1 + 9 files changed, 96 insertions(+), 9 deletions(-) create mode 100644 packages/features/ee/teams/components/MakeTeamPrivateSwitch.tsx create mode 100644 packages/prisma/migrations/20230701125542_add_is_private/migration.sql diff --git a/apps/web/pages/team/[slug].tsx b/apps/web/pages/team/[slug].tsx index a168a56c43..5250faf3ed 100644 --- a/apps/web/pages/team/[slug].tsx +++ b/apps/web/pages/team/[slug].tsx @@ -187,7 +187,7 @@ function TeamPage({ team, isUnpublished, markdownStrippedBio, isValidOrgDomain } {!isBioEmpty && ( <>
@@ -197,21 +197,26 @@ function TeamPage({ team, isUnpublished, markdownStrippedBio, isValidOrgDomain } ) : ( <> - {(showMembers.isOn || !team.eventTypes.length) && } + {(showMembers.isOn || !team.eventTypes.length) && + (team.isPrivate ? ( +
+

{t("you_cannot_see_team_members")}

+
+ ) : ( + + ))} {!showMembers.isOn && team.eventTypes.length > 0 && (
- {!team.hideBookATeamMember && ( + {!(team.hideBookATeamMember || team.isPrivate) && (
diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json index 41fcac295c..ece4273076 100644 --- a/apps/web/public/static/locales/en/common.json +++ b/apps/web/public/static/locales/en/common.json @@ -1003,6 +1003,9 @@ "user_impersonation_heading": "User Impersonation", "user_impersonation_description": "Allows our support team to temporarily sign in as you to help us quickly resolve any issues you report to us.", "team_impersonation_description": "Allows your team Owners/Admins to temporarily sign in as you.", + "make_team_private": "Make team private", + "make_team_private_description": "Your team members won't be able to see other team members when this is turned on.", + "you_cannot_see_team_members": "You cannot see all the team members of a private team.", "allow_booker_to_select_duration": "Allow booker to select duration", "impersonate_user_tip": "All uses of this feature is audited.", "impersonating_user_warning": "Impersonating username \"{{user}}\".", diff --git a/packages/features/ee/teams/components/MakeTeamPrivateSwitch.tsx b/packages/features/ee/teams/components/MakeTeamPrivateSwitch.tsx new file mode 100644 index 0000000000..e36a989126 --- /dev/null +++ b/packages/features/ee/teams/components/MakeTeamPrivateSwitch.tsx @@ -0,0 +1,60 @@ +import { classNames } from "@calcom/lib"; +import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { trpc } from "@calcom/trpc/react"; +import { showToast, Switch } from "@calcom/ui"; + +const MakeTeamPrivateSwitch = ({ + teamId, + isPrivate, + disabled, +}: { + teamId: number; + isPrivate: boolean; + disabled: boolean; +}) => { + const { t } = useLocale(); + + const utils = trpc.useContext(); + + const mutation = trpc.viewer.teams.update.useMutation({ + onError: (err) => { + showToast(err.message, "error"); + }, + async onSuccess() { + await utils.viewer.teams.get.invalidate(); + showToast(t("your_team_updated_successfully"), "success"); + }, + }); + + return ( + <> +
+
+
+

+ {t("make_team_private")} +

+
+

+ {t("make_team_private_description")} +

+
+
+ { + mutation.mutate({ id: teamId, isPrivate: isChecked }); + }} + /> +
+
+ + ); +}; + +export default MakeTeamPrivateSwitch; diff --git a/packages/features/ee/teams/pages/team-members-view.tsx b/packages/features/ee/teams/pages/team-members-view.tsx index 24b4095fdd..e938707185 100644 --- a/packages/features/ee/teams/pages/team-members-view.tsx +++ b/packages/features/ee/teams/pages/team-members-view.tsx @@ -12,6 +12,7 @@ import { Plus } from "@calcom/ui/components/icon"; import { getLayout } from "../../../settings/layouts/SettingsLayout"; import DisableTeamImpersonation from "../components/DisableTeamImpersonation"; import InviteLinkSettingsModal from "../components/InviteLinkSettingsModal"; +import MakeTeamPrivateSwitch from "../components/MakeTeamPrivateSwitch"; import MemberInvitationModal from "../components/MemberInvitationModal"; import MemberListItem from "../components/MemberListItem"; import TeamInviteList from "../components/TeamInviteList"; @@ -67,6 +68,7 @@ const MembersView = () => { const router = useRouter(); const session = useSession(); + const utils = trpc.useContext(); const teamId = Number(router.query.id); @@ -132,8 +134,13 @@ const MembersView = () => { )} )} - -
+ + {((team?.isPrivate && isAdmin) || !team?.isPrivate) && ( + <> + +
+ + )} {team && session.data && ( { disabled={isInviteOpen} /> )} -
+ + {team && isAdmin && ( + <> +
+ + + )}
{showMemberInvitationModal && team && ( { logo: input.logo, bio: input.bio, hideBranding: input.hideBranding, + isPrivate: input.isPrivate, hideBookATeamMember: input.hideBookATeamMember, brandColor: input.brandColor, darkBrandColor: input.darkBrandColor, diff --git a/packages/trpc/server/routers/viewer/teams/update.schema.ts b/packages/trpc/server/routers/viewer/teams/update.schema.ts index 3a35131461..7da9261808 100644 --- a/packages/trpc/server/routers/viewer/teams/update.schema.ts +++ b/packages/trpc/server/routers/viewer/teams/update.schema.ts @@ -8,6 +8,7 @@ export const ZUpdateInputSchema = z.object({ slug: z.string().optional(), hideBranding: z.boolean().optional(), hideBookATeamMember: z.boolean().optional(), + isPrivate: z.boolean().optional(), brandColor: z.string().optional(), darkBrandColor: z.string().optional(), theme: z.string().optional().nullable(),