Create New Team (#4450)
* Add link to new teams * Create new team * Invite team members * Bug fix * Tidy up settings calendars (#4430) * feat: 4232 - new theme toggle design. (#4371) Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com> * fix: Select dropdown styling (#4358) * fix: select dropdown styling * change check icon * Revert select component, update v2 select * Updates the background color to match figma design Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com> * Fix input height 36px (#4425) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> * Fix crash due to some props being undefined (#4427) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> * Improve event type item description visibility (#4404) * Make event type description more visible * Delete unneeded import Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> * Updating language in settings needs a reload to be translated (#4431) Co-authored-by: gitstart <gitstart@users.noreply.github.com> Co-authored-by: Nitesh Singh <nitesh.singh@gitstart.dev> Co-authored-by: Thiago Nascimbeni <tnascimbeni@gmail.com> Co-authored-by: Grace Nshokano <grace.devolop@gmail.com> Co-authored-by: Matheus Muniz <87545749+matheusmuniz03@users.noreply.github.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> * fix: remove i18n from title and description (#4354) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> Co-authored-by: Hariom Balhara <hariombalhara@gmail.com> * Fix styles and remove temporarily elements (#4448) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> * Fix deletion of route (#4466) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> * feat: make toggle button default (#4437) * feat: make switch default * fix: refetch invalidated query * React-query caching the previous isDefault state. * fix: switch label color Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> * Refactor skeleton loader files to v2 folders (#4447) * create v2 skeleton loaders * add depreciation notice to old skeleton loader files Co-authored-by: CarinaWolli <wollencarina@gmail.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> * Adds rescheduling dropdown to past unconfirmed bookings (#3726) Co-authored-by: Omar López <zomars@me.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> * fix: add a consistent key to the day ranges list (#4401) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> * remove "Weve changed billing for teams" banner in teams (#4432) Co-authored-by: gitstart <gitstart@users.noreply.github.com> Co-authored-by: gitstart <gitstart@gitstart.com> Co-authored-by: Grace Nshokano <grace.devolop@gmail.com> Co-authored-by: Nitesh Singh <nitesh.singh@gitstart.dev> Co-authored-by: Matheus Muniz <87545749+matheusmuniz03@users.noreply.github.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> * fix: remove name prop from NumberWidget (#4346) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> * Fix bug * Fix bug * Squashed commit of the following: commitc3cb839027Author: Bailey Pumfleet <pumfleet@hey.com> Date: Wed Sep 14 17:13:13 2022 +0100 Remove outline from user dropdown trigger (#4470) commit91c39a0306Author: Sascha Schworm <1959209+saschaschworm@users.noreply.github.com> Date: Wed Sep 14 18:09:00 2022 +0200 feat: Exchange with NTLM support (#4127) * add exchange package * fix conflicts * add setup page for v2 * refactor setup page for v1 * return exchange error messages to user if applicable Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com> commitf1c15f4e8aAuthor: alannnc <alannnc@gmail.com> Date: Wed Sep 14 10:57:20 2022 -0500 4382 onboarding fix the disabled state of the username in step 1 (#4451) * Convert username availability premium to v2 * Update Username Availability to v2 design Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> commit3f29df16adAuthor: Alex van Andel <me@alexvanandel.com> Date: Wed Sep 14 16:40:56 2022 +0100 KBar included @calcom/ui/v2/core -> Shell -> KBar -> Shell -> ... (#4469) commit3a06947c8aAuthor: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Wed Sep 14 19:14:42 2022 +0530 fixes active state of select options (#4456) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> commitf486b0242fAuthor: Nafees Nazik <84864519+G3root@users.noreply.github.com> Date: Wed Sep 14 17:28:59 2022 +0530 fix: remove name prop from NumberWidget (#4346) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> commit9bc2676822Author: GitStart <1501599+gitstart@users.noreply.github.com> Date: Wed Sep 14 12:41:47 2022 +0100 remove "Weve changed billing for teams" banner in teams (#4432) Co-authored-by: gitstart <gitstart@users.noreply.github.com> Co-authored-by: gitstart <gitstart@gitstart.com> Co-authored-by: Grace Nshokano <grace.devolop@gmail.com> Co-authored-by: Nitesh Singh <nitesh.singh@gitstart.dev> Co-authored-by: Matheus Muniz <87545749+matheusmuniz03@users.noreply.github.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> commit5c72aa3497Author: Nafees Nazik <84864519+G3root@users.noreply.github.com> Date: Wed Sep 14 17:00:25 2022 +0530 fix: add a consistent key to the day ranges list (#4401) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> commit09da911bf9Author: Dallen Pyrah <dallenpyrah@gmail.com> Date: Wed Sep 14 05:02:26 2022 -0600 Adds rescheduling dropdown to past unconfirmed bookings (#3726) Co-authored-by: Omar López <zomars@me.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> commit2fbaec41c9Author: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com> Date: Wed Sep 14 06:35:40 2022 -0400 Refactor skeleton loader files to v2 folders (#4447) * create v2 skeleton loaders * add depreciation notice to old skeleton loader files Co-authored-by: CarinaWolli <wollencarina@gmail.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> commit3bada22900Author: Nafees Nazik <84864519+G3root@users.noreply.github.com> Date: Wed Sep 14 15:54:41 2022 +0530 feat: make toggle button default (#4437) * feat: make switch default * fix: refetch invalidated query * React-query caching the previous isDefault state. * fix: switch label color Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> commit45059554b6Author: Hariom Balhara <hariombalhara@gmail.com> Date: Wed Sep 14 15:40:52 2022 +0530 Fix deletion of route (#4466) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> commit8b69359ccbAuthor: alannnc <alannnc@gmail.com> Date: Wed Sep 14 04:55:49 2022 -0500 Fix styles and remove temporarily elements (#4448) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> commitb457125915Author: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com> Date: Wed Sep 14 15:12:48 2022 +0530 fix: remove i18n from title and description (#4354) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> Co-authored-by: Hariom Balhara <hariombalhara@gmail.com> commit01e0fed3c5Author: GitStart <1501599+gitstart@users.noreply.github.com> Date: Wed Sep 14 10:28:23 2022 +0100 Updating language in settings needs a reload to be translated (#4431) Co-authored-by: gitstart <gitstart@users.noreply.github.com> Co-authored-by: Nitesh Singh <nitesh.singh@gitstart.dev> Co-authored-by: Thiago Nascimbeni <tnascimbeni@gmail.com> Co-authored-by: Grace Nshokano <grace.devolop@gmail.com> Co-authored-by: Matheus Muniz <87545749+matheusmuniz03@users.noreply.github.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> commitc09107cec8Author: Noah <hi@noahflk.com> Date: Wed Sep 14 11:08:50 2022 +0200 Improve event type item description visibility (#4404) * Make event type description more visible * Delete unneeded import Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> commit2f9905e548Author: Hariom Balhara <hariombalhara@gmail.com> Date: Wed Sep 14 14:16:42 2022 +0530 Fix crash due to some props being undefined (#4427) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> commitab4d910564Author: sean-brydon <55134778+sean-brydon@users.noreply.github.com> Date: Wed Sep 14 09:18:40 2022 +0100 Fix input height 36px (#4425) Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> commit34bca4984fAuthor: John Afolabi <johnafolabi.da@gmail.com> Date: Wed Sep 14 08:27:00 2022 +0100 fix: Select dropdown styling (#4358) * fix: select dropdown styling * change check icon * Revert select component, update v2 select * Updates the background color to match figma design Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com> commit0907d154c7Author: Jeroen Reumkens <hello@jeroenreumkens.nl> Date: Wed Sep 14 09:15:13 2022 +0200 feat: 4232 - new theme toggle design. (#4371) Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com> commit6f807930f6Author: sean-brydon <55134778+sean-brydon@users.noreply.github.com> Date: Tue Sep 13 21:13:24 2022 +0100 Tidy up settings calendars (#4430) * Fix types * Cleanup Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com> Co-authored-by: Jeroen Reumkens <hello@jeroenreumkens.nl> Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: John Afolabi <johnafolabi.da@gmail.com> Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> Co-authored-by: Hariom Balhara <hariombalhara@gmail.com> Co-authored-by: Noah <hi@noahflk.com> Co-authored-by: GitStart <1501599+gitstart@users.noreply.github.com> Co-authored-by: gitstart <gitstart@users.noreply.github.com> Co-authored-by: Nitesh Singh <nitesh.singh@gitstart.dev> Co-authored-by: Thiago Nascimbeni <tnascimbeni@gmail.com> Co-authored-by: Grace Nshokano <grace.devolop@gmail.com> Co-authored-by: Matheus Muniz <87545749+matheusmuniz03@users.noreply.github.com> Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com> Co-authored-by: alannnc <alannnc@gmail.com> Co-authored-by: Nafees Nazik <84864519+G3root@users.noreply.github.com> Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com> Co-authored-by: CarinaWolli <wollencarina@gmail.com> Co-authored-by: Dallen Pyrah <dallenpyrah@gmail.com> Co-authored-by: Omar López <zomars@me.com> Co-authored-by: gitstart <gitstart@gitstart.com> Co-authored-by: Alex van Andel <me@alexvanandel.com> Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
This commit is contained in:
+15




![kodiakhq[bot]](/avatar/78f03f45def735066748285e1c83c542df49e7b0562b0a8da815d5b24845d135?size=40)




Joe Au-Yeung
Peer Richelsen
Syed Ali Shahbaz
sean-brydon
kodiakhq[bot]
gitstart
Nitesh Singh
Thiago Nascimbeni
Grace Nshokano
Matheus Muniz
Hariom Balhara
CarinaWolli
Omar López
gitstart
Jeroen Reumkens
John Afolabi
Noah
GitStart
Udit Takkar
alannnc
Nafees Nazik
Carina Wollendorfer
Dallen Pyrah
Alex van Andel
Bailey Pumfleet authored and
GitHub committed 2022-09-15 09:47:59 +00:00
1 parent
7a95e714c2
commit
0c78dbea27
9 files changed
+445
-101
No files matched your search
@@ -0,0 +1,114 @@
|
||||
import Head from "next/head";
|
||||
import { useRouter } from "next/router";
|
||||
import { useState } from "react";
|
||||
import { z } from "zod";
|
||||
|
||||
// import TeamGeneralSettings from "@calcom/features/teams/createNewTeam/TeamGeneralSettings";
|
||||
import AddNewTeamMembers from "@calcom/features/ee/teams/components/v2/AddNewTeamMembers";
|
||||
import CreateNewTeam from "@calcom/features/ee/teams/components/v2/CreateNewTeam";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
|
||||
import { StepCard } from "@components/getting-started/components/StepCard";
|
||||
import { Steps } from "@components/getting-started/components/Steps";
|
||||
|
||||
const INITIAL_STEP = "create-a-new-team";
|
||||
// TODO: Add teams general settings "general-settings"
|
||||
const steps = ["create-a-new-team", "add-team-members"] as const;
|
||||
|
||||
const stepTransform = (step: typeof steps[number]) => {
|
||||
const stepIndex = steps.indexOf(step);
|
||||
if (stepIndex > -1) {
|
||||
return steps[stepIndex];
|
||||
}
|
||||
return INITIAL_STEP;
|
||||
};
|
||||
|
||||
const stepRouteSchema = z.object({
|
||||
step: z.array(z.enum(steps)).default([INITIAL_STEP]),
|
||||
});
|
||||
|
||||
const CreateNewTeamPage = () => {
|
||||
const router = useRouter();
|
||||
|
||||
const { t } = useLocale();
|
||||
const [teamId, setTeamId] = useState<number>();
|
||||
|
||||
const result = stepRouteSchema.safeParse(router.query);
|
||||
const currentStep = result.success ? result.data.step[0] : INITIAL_STEP;
|
||||
|
||||
const headers = [
|
||||
{
|
||||
title: `${t("create_a_new_team")}`,
|
||||
subtitle: [`${t("create_a_new_team_description")}`],
|
||||
},
|
||||
// {
|
||||
// title: `${t("general_settings")}`,
|
||||
// subtitle: [`${t("general_settings_description")}`],
|
||||
// },
|
||||
{
|
||||
title: `${t("add_team_members")}`,
|
||||
subtitle: [`${t("add_team_members_description")}`],
|
||||
},
|
||||
];
|
||||
|
||||
const goToIndex = (index: number) => {
|
||||
const newStep = steps[index];
|
||||
router.push(
|
||||
{
|
||||
pathname: `/settings/teams/new/${stepTransform(newStep)}`,
|
||||
},
|
||||
undefined
|
||||
);
|
||||
};
|
||||
|
||||
const currentStepIndex = steps.indexOf(currentStep);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="dark:bg-brand dark:text-brand-contrast min-h-screen text-black"
|
||||
data-testid="onboarding"
|
||||
key={router.asPath}>
|
||||
<Head>
|
||||
<title>{t("create_a_new_team")}</title>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
|
||||
<div className="mx-auto px-4 py-24">
|
||||
<div className="relative">
|
||||
<div className="sm:mx-auto sm:w-full sm:max-w-[600px]">
|
||||
<div className="mx-auto sm:max-w-[520px]">
|
||||
<header>
|
||||
<p className="font-cal mb-3 text-[28px] font-medium leading-7">
|
||||
{headers[currentStepIndex]?.title || "Undefined title"}
|
||||
</p>
|
||||
|
||||
<p className="font-sans text-sm font-normal text-gray-500">
|
||||
{headers[currentStepIndex]?.subtitle}
|
||||
</p>
|
||||
</header>
|
||||
<Steps maxSteps={steps.length} currentStep={currentStepIndex} navigateToStep={goToIndex} />
|
||||
</div>
|
||||
<StepCard>
|
||||
{currentStep === "create-a-new-team" && (
|
||||
<CreateNewTeam
|
||||
nextStep={() => {
|
||||
goToIndex(1);
|
||||
}}
|
||||
setTeamId={(teamId: number) => setTeamId(teamId)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* {currentStep === "general-settings" && (
|
||||
<TeamGeneralSettings teamId={teamId} nextStep={() => goToIndex(2)} />
|
||||
)} */}
|
||||
|
||||
{currentStep === "add-team-members" && teamId && <AddNewTeamMembers teamId={teamId} />}
|
||||
</StepCard>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CreateNewTeamPage;
|
||||
@@ -498,7 +498,7 @@
|
||||
"lets_create_first_administrator_user": "Let's create the first administrator user.",
|
||||
"new_member": "New Member",
|
||||
"invite": "Invite",
|
||||
"invite_new_member": "Invite a new member",
|
||||
"invite_new_member": "Invite a new team member",
|
||||
"invite_new_team_member": "Invite someone to your team.",
|
||||
"change_member_role": "Change team member role",
|
||||
"disable_cal_branding": "Disable Cal branding",
|
||||
@@ -1240,6 +1240,7 @@
|
||||
"password_updated":"Password updated!",
|
||||
"pending_payment": "Pending payment",
|
||||
"confirmation_page_rainbow": "Token gate your event with tokens or NFTs on Ethereum, Polygon, and more.",
|
||||
"not_on_cal": "Not on Cal.com",
|
||||
"no_calendar_installed": "No calendar installed",
|
||||
"no_calendar_installed_description": "You have not yet connected any of your calendars",
|
||||
"add_a_calendar": "Add a calendar"
|
||||
|
||||
@@ -66,20 +66,19 @@ export default function MemberInvitationModal(props: MemberInvitationModalProps)
|
||||
|
||||
return (
|
||||
<Dialog open={props.isOpen} onOpenChange={props.onExit}>
|
||||
<DialogContent type="creation" useOwnActionButtons>
|
||||
<div className="mb-4 sm:flex sm:items-start">
|
||||
<div className="bg-brand text-brandcontrast dark:bg-darkmodebrand dark:text-darkmodebrandcontrast mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-opacity-5 sm:mx-0 sm:h-10 sm:w-10">
|
||||
<Icon.FiUser className="text-brandcontrast h-6 w-6" />
|
||||
</div>
|
||||
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
||||
<h3 className="text-lg font-medium leading-6 text-gray-900" id="modal-title">
|
||||
{t("invite_new_member")}
|
||||
</h3>
|
||||
<div>
|
||||
<p className="text-sm text-gray-400">{t("invite_new_team_member")}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<DialogContent
|
||||
type="creation"
|
||||
useOwnActionButtons
|
||||
title={t("invite_new_member")}
|
||||
description={
|
||||
<span className=" text-sm leading-tight text-gray-500">
|
||||
Note: This will <span className="font-medium text-gray-900">cost an extra seat ($12/m)</span> on
|
||||
your subscription if this invitee does not have a pro account.{" "}
|
||||
<a href="#" className="underline">
|
||||
Learn More
|
||||
</a>
|
||||
</span>
|
||||
}>
|
||||
<form onSubmit={inviteMember}>
|
||||
<div className="space-y-4">
|
||||
<TextField
|
||||
@@ -117,16 +116,6 @@ export default function MemberInvitationModal(props: MemberInvitationModalProps)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row rounded-md bg-gray-50 px-3 py-2">
|
||||
<Icon.FiInfo className="h-5 w-5 flex-shrink-0 fill-gray-400" aria-hidden="true" />
|
||||
<span className="ml-2 text-sm leading-tight text-gray-500">
|
||||
Note: This will cost an extra seat ($12/m) on your subscription if this invitee does not have
|
||||
a pro account.{" "}
|
||||
{/* <a href="#" className="underline">
|
||||
Learn More
|
||||
</a> */}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{errorMessage && (
|
||||
<p className="text-sm text-red-700">
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
import { Suspense, useState } from "react";
|
||||
|
||||
import MemberInvitationModal from "@calcom/features/ee/teams/components/MemberInvitationModal";
|
||||
import { classNames } from "@calcom/lib";
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import { Icon } from "@calcom/ui";
|
||||
import { Button, Avatar, Badge } from "@calcom/ui/v2";
|
||||
import { SkeletonContainer, SkeletonText } from "@calcom/ui/v2";
|
||||
|
||||
const AddNewTeamMemberSkeleton = () => {
|
||||
return (
|
||||
<SkeletonContainer className="rounded-md border">
|
||||
<div className="flex w-full justify-between p-4">
|
||||
<div>
|
||||
<p className="text-sm font-medium text-gray-900">
|
||||
<SkeletonText className="h-4 w-56" />
|
||||
</p>
|
||||
<div className="mt-2.5 w-max">
|
||||
<SkeletonText className="h-5 w-28" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</SkeletonContainer>
|
||||
);
|
||||
};
|
||||
|
||||
const AddNewTeamMembers = (props: { teamId: number }) => {
|
||||
const { t } = useLocale();
|
||||
const utils = trpc.useContext();
|
||||
|
||||
const { data: team, isLoading } = trpc.useQuery(["viewer.teams.get", { teamId: props.teamId }]);
|
||||
const removeMemberMutation = trpc.useMutation("viewer.teams.removeMember", {
|
||||
onSuccess() {
|
||||
utils.invalidateQueries(["viewer.teams.get", { teamId: props.teamId }]);
|
||||
utils.invalidateQueries(["viewer.teams.list"]);
|
||||
},
|
||||
});
|
||||
|
||||
const [memberInviteModal, setMemberInviteModal] = useState(false);
|
||||
|
||||
if (isLoading) return <AddNewTeamMemberSkeleton />;
|
||||
|
||||
return (
|
||||
<Suspense fallback={<AddNewTeamMemberSkeleton />}>
|
||||
<>
|
||||
<>
|
||||
<ul className="rounded-md border">
|
||||
{team?.members.map((member, index) => (
|
||||
<li
|
||||
key={member.id}
|
||||
className={classNames(
|
||||
"flex items-center justify-between p-6 text-sm",
|
||||
index !== 0 && "border-t"
|
||||
)}>
|
||||
<div className="flex space-x-2">
|
||||
<Avatar
|
||||
gravatarFallbackMd5="teamMember"
|
||||
size="mdLg"
|
||||
imageSrc={member?.avatar}
|
||||
alt="owner-avatar"
|
||||
/>
|
||||
<div>
|
||||
<div className="flex space-x-1">
|
||||
<p>{member?.name || t("team_member")}</p>
|
||||
{/* Assume that the first member of the team is the creator */}
|
||||
{index === 0 && <Badge variant="green">{t("you")}</Badge>}
|
||||
{!member.accepted && <Badge variant="orange">{t("pending")}</Badge>}
|
||||
{member.role === "MEMBER" && <Badge variant="gray">{t("member")}</Badge>}
|
||||
{member.role === "ADMIN" && <Badge variant="default">{t("admin")}</Badge>}
|
||||
</div>
|
||||
{member.username ? (
|
||||
<p className="text-gray-600">{`${WEBAPP_URL}/${member?.username}`}</p>
|
||||
) : (
|
||||
<p className="text-gray-600">{t("not_on_cal")}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{member.role !== "OWNER" && (
|
||||
<Button
|
||||
StartIcon={Icon.FiTrash2}
|
||||
size="icon"
|
||||
color="secondary"
|
||||
className="h-[36px] w-[36px]"
|
||||
onClick={() => removeMemberMutation.mutate({ teamId: props.teamId, memberId: member.id })}
|
||||
/>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
color="secondary"
|
||||
StartIcon={Icon.FiPlus}
|
||||
onClick={() => setMemberInviteModal(true)}
|
||||
className="mt-6 w-full justify-center">
|
||||
{t("add_team_member")}
|
||||
</Button>
|
||||
</>
|
||||
|
||||
{team && (
|
||||
<MemberInvitationModal
|
||||
isOpen={memberInviteModal}
|
||||
onExit={() => setMemberInviteModal(false)}
|
||||
team={team}
|
||||
currentMember={team?.membership.role}
|
||||
/>
|
||||
)}
|
||||
|
||||
<hr className="my-6 border-neutral-200" />
|
||||
|
||||
<Button
|
||||
EndIcon={Icon.FiArrowRight}
|
||||
className="mt-6 w-full justify-center"
|
||||
href={`${WEBAPP_URL}/settings/teams/${props.teamId}/profile`}>
|
||||
{t("finish")}
|
||||
</Button>
|
||||
</>
|
||||
</Suspense>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddNewTeamMembers;
|
||||
@@ -0,0 +1,102 @@
|
||||
import { useForm, Controller } from "react-hook-form";
|
||||
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
||||
import { trpc } from "@calcom/trpc/react";
|
||||
import { Icon } from "@calcom/ui";
|
||||
import { Button, Avatar } from "@calcom/ui/v2";
|
||||
import ImageUploader from "@calcom/ui/v2/core/ImageUploader";
|
||||
import { Form, TextField } from "@calcom/ui/v2/core/form/fields";
|
||||
|
||||
const CreateANewTeamForm = (props: { nextStep: () => void; setTeamId: (teamId: number) => void }) => {
|
||||
const { t } = useLocale();
|
||||
const utils = trpc.useContext();
|
||||
|
||||
const createTeamMutation = trpc.useMutation("viewer.teams.create", {
|
||||
onSuccess(data) {
|
||||
utils.invalidateQueries(["viewer.teams.list"]);
|
||||
props.setTeamId(data.id);
|
||||
props.nextStep();
|
||||
},
|
||||
});
|
||||
|
||||
const formMethods = useForm();
|
||||
|
||||
return (
|
||||
<Form
|
||||
form={formMethods}
|
||||
handleSubmit={(values) => {
|
||||
createTeamMutation.mutate({
|
||||
name: values.name,
|
||||
slug: values.slug || null,
|
||||
logo: values.logo || null,
|
||||
});
|
||||
}}>
|
||||
<div className="mb-8">
|
||||
<Controller
|
||||
name="name"
|
||||
control={formMethods.control}
|
||||
rules={{ required: { value: true, message: t("team_name_required") } }}
|
||||
render={({ field: { value } }) => (
|
||||
<TextField
|
||||
className="mt-2"
|
||||
name="name"
|
||||
label={t("team_name")}
|
||||
value={value}
|
||||
onChange={(e) => {
|
||||
formMethods.setValue("name", e?.target.value);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mb-8">
|
||||
<Controller
|
||||
name="slug"
|
||||
control={formMethods.control}
|
||||
render={({ field: { value } }) => (
|
||||
<TextField
|
||||
className="mt-2"
|
||||
name="slug"
|
||||
label={t("team_url")}
|
||||
addOnLeading={`${WEBAPP_URL}/`}
|
||||
value={value}
|
||||
onChange={(e) => {
|
||||
formMethods.setValue("slug", e?.target.value);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-8">
|
||||
<Controller
|
||||
control={formMethods.control}
|
||||
name="avatar"
|
||||
render={({ field: { value } }) => (
|
||||
<div className="flex items-center">
|
||||
<Avatar alt="" imageSrc={value || null} gravatarFallbackMd5="newTeam" size="lg" />
|
||||
<div className="ml-4">
|
||||
<ImageUploader
|
||||
target="avatar"
|
||||
id="avatar-upload"
|
||||
buttonMsg={t("update")}
|
||||
handleAvatarChange={(newAvatar: string) => {
|
||||
formMethods.setValue("avatar", newAvatar);
|
||||
}}
|
||||
imageSrc={value}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<Button type="submit" EndIcon={Icon.FiArrowRight} className="w-full justify-center">
|
||||
{t("continue")}
|
||||
</Button>
|
||||
{createTeamMutation.isError && <p className="mt-4 text-red-700">{createTeamMutation.error.message}</p>}
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default CreateANewTeamForm;
|
||||
@@ -12,6 +12,7 @@ export async function getTeamWithMembers(id?: number, slug?: string) {
|
||||
id: true,
|
||||
plan: true,
|
||||
bio: true,
|
||||
avatar: true,
|
||||
});
|
||||
|
||||
const teamSelect = Prisma.validator<Prisma.TeamSelect>()({
|
||||
|
||||
@@ -79,13 +79,15 @@ export const viewerTeamsRouter = createProtectedRouter()
|
||||
.mutation("create", {
|
||||
input: z.object({
|
||||
name: z.string(),
|
||||
slug: z.string().optional().nullable(),
|
||||
logo: z.string().optional().nullable(),
|
||||
}),
|
||||
async resolve({ ctx, input }) {
|
||||
if (ctx.user.plan === "FREE") {
|
||||
throw new TRPCError({ code: "UNAUTHORIZED", message: "You need a team plan." });
|
||||
}
|
||||
|
||||
const slug = slugify(input.name);
|
||||
const slug = input.slug || slugify(input.name);
|
||||
|
||||
const nameCollisions = await ctx.prisma.team.count({
|
||||
where: {
|
||||
@@ -100,6 +102,7 @@ export const viewerTeamsRouter = createProtectedRouter()
|
||||
data: {
|
||||
name: input.name,
|
||||
slug: slug,
|
||||
logo: input.logo || null,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -114,6 +117,8 @@ export const viewerTeamsRouter = createProtectedRouter()
|
||||
|
||||
// Sync Services: Close.com
|
||||
closeComUpsertTeamUser(createTeam, ctx.user, MembershipRole.OWNER);
|
||||
|
||||
return createTeam;
|
||||
},
|
||||
})
|
||||
// Allows team owner to update team metadata
|
||||
|
||||
@@ -64,7 +64,7 @@ type DialogContentProps = React.ComponentProps<typeof DialogPrimitive["Content"]
|
||||
size?: "xl" | "lg" | "md";
|
||||
type: "creation" | "confirmation";
|
||||
title?: string;
|
||||
description?: string | undefined;
|
||||
description?: string | JSX.Element | undefined;
|
||||
closeText?: string;
|
||||
actionDisabled?: boolean;
|
||||
actionText?: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { UserPermissionRole, MembershipRole } from "@prisma/client";
|
||||
import { MembershipRole, UserPermissionRole } from "@prisma/client";
|
||||
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@radix-ui/react-collapsible";
|
||||
import { useSession } from "next-auth/react";
|
||||
import React, { ComponentProps, useEffect, useState } from "react";
|
||||
@@ -101,6 +101,7 @@ const SettingsSidebarContainer = ({ className = "" }) => {
|
||||
const tabsWithPermissions = useTabs();
|
||||
const [teamMenuState, setTeamMenuState] =
|
||||
useState<{ teamId: number | undefined; teamMenuOpen: boolean }[]>();
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
const { data: teams } = trpc.useQuery(["viewer.teams.list"]);
|
||||
|
||||
@@ -159,23 +160,13 @@ const SettingsSidebarContainer = ({ className = "" }) => {
|
||||
</div>
|
||||
{teams &&
|
||||
teamMenuState &&
|
||||
teams.map((team, index: number) => (
|
||||
<Collapsible
|
||||
key={team.id}
|
||||
open={teamMenuState[index].teamMenuOpen}
|
||||
onOpenChange={() =>
|
||||
setTeamMenuState([
|
||||
...teamMenuState,
|
||||
(teamMenuState[index] = {
|
||||
...teamMenuState[index],
|
||||
teamMenuOpen: !teamMenuState[index].teamMenuOpen,
|
||||
}),
|
||||
])
|
||||
}>
|
||||
<CollapsibleTrigger>
|
||||
<div
|
||||
className="flex h-9 w-64 flex-row items-center rounded-md px-3 py-[10px] text-sm font-medium leading-none hover:bg-gray-100 group-hover:text-gray-700 [&[aria-current='page']]:bg-gray-200 [&[aria-current='page']]:text-gray-900"
|
||||
onClick={() =>
|
||||
teams.map((team, index: number) => {
|
||||
if (teamMenuState.some((teamState) => teamState.teamId === team.id))
|
||||
return (
|
||||
<Collapsible
|
||||
key={team.id}
|
||||
open={teamMenuState[index].teamMenuOpen}
|
||||
onOpenChange={() =>
|
||||
setTeamMenuState([
|
||||
...teamMenuState,
|
||||
(teamMenuState[index] = {
|
||||
@@ -184,74 +175,90 @@ const SettingsSidebarContainer = ({ className = "" }) => {
|
||||
}),
|
||||
])
|
||||
}>
|
||||
<div className="mr-[13px]">
|
||||
{teamMenuState[index].teamMenuOpen ? (
|
||||
<Icon.FiChevronDown />
|
||||
) : (
|
||||
<Icon.FiChevronRight />
|
||||
<CollapsibleTrigger>
|
||||
<div
|
||||
className="flex h-9 w-64 flex-row items-center rounded-md px-3 py-[10px] text-sm font-medium leading-none hover:bg-gray-100 group-hover:text-gray-700 [&[aria-current='page']]:bg-gray-200 [&[aria-current='page']]:text-gray-900"
|
||||
onClick={() =>
|
||||
setTeamMenuState([
|
||||
...teamMenuState,
|
||||
(teamMenuState[index] = {
|
||||
...teamMenuState[index],
|
||||
teamMenuOpen: !teamMenuState[index].teamMenuOpen,
|
||||
}),
|
||||
])
|
||||
}>
|
||||
<div className="mr-[13px]">
|
||||
{teamMenuState[index].teamMenuOpen ? (
|
||||
<Icon.FiChevronDown />
|
||||
) : (
|
||||
<Icon.FiChevronRight />
|
||||
)}
|
||||
</div>
|
||||
{team.logo && (
|
||||
<img
|
||||
src={team.logo}
|
||||
className="mt-2 ml-[12px] mr-[8px] h-[16px] w-[16px] self-start stroke-[2px] md:mt-0"
|
||||
alt={team.name || "Team logo"}
|
||||
/>
|
||||
)}
|
||||
<p>{team.name}</p>
|
||||
{!team.accepted && (
|
||||
<Badge className="ml-3" variant="orange">
|
||||
Inv.
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent>
|
||||
{team.accepted && (
|
||||
<VerticalTabItem
|
||||
name={t("profile")}
|
||||
href={`${WEBAPP_URL}/settings/teams/${team.id}/profile`}
|
||||
textClassNames="px-3 text-gray-900 font-medium text-sm"
|
||||
disableChevron
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{team.logo && (
|
||||
<img
|
||||
src={team.logo}
|
||||
className="mt-2 ml-[12px] mr-[8px] h-[16px] w-[16px] self-start stroke-[2px] md:mt-0"
|
||||
alt={team.name || "Team logo"}
|
||||
<VerticalTabItem
|
||||
name={t("members")}
|
||||
href={`${WEBAPP_URL}/settings/teams/${team.id}/members`}
|
||||
textClassNames="px-3 text-gray-900 font-medium text-sm"
|
||||
disableChevron
|
||||
/>
|
||||
)}
|
||||
<p>{team.name}</p>
|
||||
{!team.accepted && (
|
||||
<Badge className="ml-3" variant="orange">
|
||||
Inv.
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent>
|
||||
{team.accepted && (
|
||||
<VerticalTabItem
|
||||
name={t("profile")}
|
||||
href={`${WEBAPP_URL}/settings/teams/${team.id}/profile`}
|
||||
textClassNames="px-3 text-gray-900 font-medium text-sm"
|
||||
disableChevron
|
||||
/>
|
||||
)}
|
||||
<VerticalTabItem
|
||||
name={t("members")}
|
||||
href={`${WEBAPP_URL}/settings/teams/${team.id}/members`}
|
||||
textClassNames="px-3 text-gray-900 font-medium text-sm"
|
||||
disableChevron
|
||||
/>
|
||||
{(team.role === MembershipRole.OWNER || team.role === MembershipRole.ADMIN) && (
|
||||
<>
|
||||
{/* TODO */}
|
||||
{/* <VerticalTabItem
|
||||
{(team.role === MembershipRole.OWNER || team.role === MembershipRole.ADMIN) && (
|
||||
<>
|
||||
{/* TODO */}
|
||||
{/* <VerticalTabItem
|
||||
name={t("general")}
|
||||
href={`${WEBAPP_URL}/settings/my-account/appearance`}
|
||||
textClassNames="px-3 text-gray-900 font-medium text-sm"
|
||||
disableChevron
|
||||
/> */}
|
||||
<VerticalTabItem
|
||||
name={t("appearance")}
|
||||
href={`${WEBAPP_URL}/settings/teams/${team.id}/appearance`}
|
||||
textClassNames="px-3 text-gray-900 font-medium text-sm"
|
||||
disableChevron
|
||||
/>
|
||||
{/* TODO: Implement saml configuration page */}
|
||||
{/* <VerticalTabItem
|
||||
<VerticalTabItem
|
||||
name={t("appearance")}
|
||||
href={`${WEBAPP_URL}/settings/teams/${team.id}/appearance`}
|
||||
textClassNames="px-3 text-gray-900 font-medium text-sm"
|
||||
disableChevron
|
||||
/>
|
||||
{/* TODO: Implement saml configuration page */}
|
||||
{/* <VerticalTabItem
|
||||
name={t("saml_config")}
|
||||
href={`${WEBAPP_URL}/settings/teams/${team.id}/samlConfig`}
|
||||
textClassNames="px-3 text-gray-900 font-medium text-sm"
|
||||
disableChevron
|
||||
/> */}
|
||||
</>
|
||||
)}
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
))}
|
||||
<div className="group flex h-9 w-64 flex-row items-center rounded-md px-3 py-[10px] text-sm font-medium leading-none hover:bg-gray-100 group-hover:text-gray-700 [&[aria-current='page']]:bg-gray-200 [&[aria-current='page']]:text-gray-900">
|
||||
<Icon.FiPlus className="mt-2 mr-[10px] h-[16px] w-[16px] self-start stroke-[2px] md:mt-0" />
|
||||
<p>{t("add_a_team")}</p>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
);
|
||||
})}
|
||||
<VerticalTabItem
|
||||
name={t("add_a_team")}
|
||||
href={`${WEBAPP_URL}/settings/teams/new`}
|
||||
textClassNames="px-3 text-gray-900 font-medium text-sm"
|
||||
icon={Icon.FiPlus}
|
||||
disableChevron
|
||||
/>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user