Old teams page in v2 (#4553)

* Old teams page in v2

* Tea nav item fix

* Team creation modal converted to v2

* Updated emptyscreen and shell button

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
pull/4486/head^2
Leo Giovanetti 2022-09-17 14:53:31 -03:00 committed by GitHub
parent 00071bcdf0
commit 1b2707d4f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 100 additions and 38 deletions

View File

@ -3,9 +3,9 @@ import { useRef, useState } from "react";
import { useLocale } from "@calcom/lib/hooks/useLocale"; import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react"; import { trpc } from "@calcom/trpc/react";
import { Button } from "@calcom/ui"; import { Button } from "@calcom/ui";
import { Alert } from "@calcom/ui/Alert";
import { Dialog, DialogContent, DialogFooter } from "@calcom/ui/Dialog";
import { Icon } from "@calcom/ui/Icon"; import { Icon } from "@calcom/ui/Icon";
import { Alert } from "@calcom/ui/v2/core/Alert";
import { Dialog, DialogContent, DialogFooter } from "@calcom/ui/v2/core/Dialog";
interface Props { interface Props {
isOpen: boolean; isOpen: boolean;
@ -28,15 +28,14 @@ export default function TeamCreate(props: Props) {
}, },
}); });
const createTeam = (e: React.FormEvent<HTMLFormElement>) => { const createTeam = () => {
e.preventDefault();
createTeamMutation.mutate({ name: nameRef?.current?.value }); createTeamMutation.mutate({ name: nameRef?.current?.value });
}; };
return ( return (
<> <>
<Dialog open={props.isOpen} onOpenChange={props.onClose}> <Dialog open={props.isOpen} onOpenChange={props.onClose}>
<DialogContent> <DialogContent type="creation" actionText={t("create_new_team")} actionOnClick={createTeam}>
<div className="mb-4 sm:flex sm:items-start"> <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"> <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.FiUsers className="text-brandcontrast h-6 w-6" /> <Icon.FiUsers className="text-brandcontrast h-6 w-6" />
@ -50,7 +49,7 @@ export default function TeamCreate(props: Props) {
</div> </div>
</div> </div>
</div> </div>
<form onSubmit={createTeam}> <form>
<div className="mb-4"> <div className="mb-4">
<label htmlFor="name" className="block text-sm font-medium text-gray-700"> <label htmlFor="name" className="block text-sm font-medium text-gray-700">
{t("name")} {t("name")}
@ -66,18 +65,6 @@ export default function TeamCreate(props: Props) {
/> />
</div> </div>
{errorMessage && <Alert severity="error" title={errorMessage} />} {errorMessage && <Alert severity="error" title={errorMessage} />}
<DialogFooter>
<Button type="button" color="secondary" onClick={props.onClose}>
{t("cancel")}
</Button>
<Button
type="submit"
color="primary"
className="ltr:ml-2 rtl:mr-2"
data-testid="create-new-team-button">
{t("create_team")}
</Button>
</DialogFooter>
</form> </form>
</DialogContent> </DialogContent>
</Dialog> </Dialog>

View File

@ -1,7 +1,7 @@
import { useState } from "react"; import { useState } from "react";
import showToast from "@calcom/lib/notification";
import { inferQueryOutput, trpc } from "@calcom/trpc/react"; import { inferQueryOutput, trpc } from "@calcom/trpc/react";
import showToast from "@calcom/ui/v2/core/notifications";
import TeamListItem from "./TeamListItem"; import TeamListItem from "./TeamListItem";

View File

@ -4,19 +4,19 @@ import Link from "next/link";
import classNames from "@calcom/lib/classNames"; import classNames from "@calcom/lib/classNames";
import { getPlaceholderAvatar } from "@calcom/lib/getPlaceholderAvatar"; import { getPlaceholderAvatar } from "@calcom/lib/getPlaceholderAvatar";
import { useLocale } from "@calcom/lib/hooks/useLocale"; import { useLocale } from "@calcom/lib/hooks/useLocale";
import showToast from "@calcom/lib/notification";
import { inferQueryOutput, trpc } from "@calcom/trpc/react"; import { inferQueryOutput, trpc } from "@calcom/trpc/react";
import Button from "@calcom/ui/Button"; import { Icon } from "@calcom/ui/Icon";
import ConfirmationDialogContent from "@calcom/ui/ConfirmationDialogContent"; import Button from "@calcom/ui/v2/core/Button";
import { Dialog, DialogTrigger } from "@calcom/ui/Dialog"; import ConfirmationDialogContent from "@calcom/ui/v2/core/ConfirmationDialogContent";
import { Dialog, DialogTrigger } from "@calcom/ui/v2/core/Dialog";
import Dropdown, { import Dropdown, {
DropdownMenuContent, DropdownMenuContent,
DropdownMenuItem, DropdownMenuItem,
DropdownMenuSeparator, DropdownMenuSeparator,
DropdownMenuTrigger, DropdownMenuTrigger,
} from "@calcom/ui/Dropdown"; } from "@calcom/ui/v2/core/Dropdown";
import { Icon } from "@calcom/ui/Icon"; import { Tooltip } from "@calcom/ui/v2/core/Tooltip";
import { Tooltip } from "@calcom/ui/Tooltip"; import showToast from "@calcom/ui/v2/core/notifications";
import Avatar from "@components/ui/Avatar"; import Avatar from "@components/ui/Avatar";
@ -84,7 +84,7 @@ export default function TeamListItem(props: Props) {
!isInvitee && "group hover:bg-neutral-50" !isInvitee && "group hover:bg-neutral-50"
)}> )}>
{!isInvitee ? ( {!isInvitee ? (
<Link href={"/settings/teams/" + team.id}> <Link href={"/settings/teams/" + team.id + "/profile"}>
<a className="flex-grow cursor-pointer truncate text-sm" title={`${team.name}`}> <a className="flex-grow cursor-pointer truncate text-sm" title={`${team.name}`}>
{teamInfo} {teamInfo}
</a> </a>
@ -112,7 +112,6 @@ export default function TeamListItem(props: Props) {
<DropdownMenuItem> <DropdownMenuItem>
<Button <Button
color="minimal" color="minimal"
size="sm"
className="w-full rounded-none font-medium" className="w-full rounded-none font-medium"
StartIcon={Icon.FiCheck} StartIcon={Icon.FiCheck}
onClick={acceptInvite}> onClick={acceptInvite}>
@ -121,8 +120,7 @@ export default function TeamListItem(props: Props) {
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem> <DropdownMenuItem>
<Button <Button
color="warn" color="destructive"
size="sm"
className="w-full rounded-none font-medium" className="w-full rounded-none font-medium"
StartIcon={Icon.FiX} StartIcon={Icon.FiX}
onClick={declineInvite}> onClick={declineInvite}>
@ -158,11 +156,10 @@ export default function TeamListItem(props: Props) {
<DropdownMenuContent hidden={hideDropdown}> <DropdownMenuContent hidden={hideDropdown}>
{isAdmin && ( {isAdmin && (
<DropdownMenuItem> <DropdownMenuItem>
<Link href={"/settings/teams/" + team.id}> <Link href={"/settings/teams/" + team.id + "/profile"}>
<a> <a>
<Button <Button
color="minimal" color="minimal"
size="sm"
className="w-full rounded-none font-medium" className="w-full rounded-none font-medium"
StartIcon={Icon.FiEdit2}> StartIcon={Icon.FiEdit2}>
{t("edit_team")} {t("edit_team")}
@ -176,7 +173,6 @@ export default function TeamListItem(props: Props) {
<a target="_blank"> <a target="_blank">
<Button <Button
color="minimal" color="minimal"
size="sm"
className="w-full rounded-none font-medium" className="w-full rounded-none font-medium"
StartIcon={Icon.FiExternalLink}> StartIcon={Icon.FiExternalLink}>
{t("preview_team")} {t("preview_team")}
@ -193,8 +189,7 @@ export default function TeamListItem(props: Props) {
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
}} }}
color="warn" color="destructive"
size="sm"
className="w-full rounded-none font-medium" className="w-full rounded-none font-medium"
StartIcon={Icon.FiTrash}> StartIcon={Icon.FiTrash}>
{t("disband_team")} {t("disband_team")}
@ -220,7 +215,7 @@ export default function TeamListItem(props: Props) {
<DialogTrigger asChild> <DialogTrigger asChild>
<Button <Button
type="button" type="button"
color="warn" color="destructive"
size="lg" size="lg"
StartIcon={Icon.FiLogOut} StartIcon={Icon.FiLogOut}
className="w-full rounded-none" className="w-full rounded-none"

View File

@ -17,6 +17,7 @@ const V2_WHITELIST = [
"/event-types", "/event-types",
"/workflows", "/workflows",
"/apps", "/apps",
"/teams",
"/success", "/success",
"/auth/login", "/auth/login",
]; ];

View File

@ -1,4 +1,3 @@
import UserV2OptInBanner from "@calcom/features/users/components/UserV2OptInBanner";
import { useLocale } from "@calcom/lib/hooks/useLocale"; import { useLocale } from "@calcom/lib/hooks/useLocale";
import { MobileNavigationMoreItems } from "@calcom/ui/Shell"; import { MobileNavigationMoreItems } from "@calcom/ui/Shell";
import { Shell } from "@calcom/ui/v2"; import { Shell } from "@calcom/ui/v2";

View File

@ -0,0 +1,72 @@
import { useState } from "react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import { Icon } from "@calcom/ui/Icon";
import { Shell } from "@calcom/ui/v2";
import { Alert } from "@calcom/ui/v2/core/Alert";
import Button from "@calcom/ui/v2/core/Button";
import EmptyScreen from "@calcom/ui/v2/core/EmptyScreen";
import SkeletonLoaderTeamList from "@components/team/SkeletonloaderTeamList";
import TeamCreateModal from "@components/team/TeamCreateModal";
import TeamList from "@components/team/TeamList";
function Teams() {
const { t } = useLocale();
const [showCreateTeamModal, setShowCreateTeamModal] = useState(false);
const [errorMessage, setErrorMessage] = useState("");
const { data, isLoading } = trpc.useQuery(["viewer.teams.list"], {
onError: (e) => {
setErrorMessage(e.message);
},
});
const teams = data?.filter((m) => m.accepted) || [];
const invites = data?.filter((m) => !m.accepted) || [];
return (
<Shell
heading={t("teams")}
subtitle={t("create_manage_teams_collaborative")}
CTA={
<Button type="button" onClick={() => setShowCreateTeamModal(true)}>
<Icon.FiPlus className="inline-block h-3.5 w-3.5 text-white group-hover:text-black ltr:mr-2 rtl:ml-2" />
{t("new")}
</Button>
}>
<>
{!!errorMessage && <Alert severity="error" title={errorMessage} />}
{showCreateTeamModal && (
<TeamCreateModal isOpen={showCreateTeamModal} onClose={() => setShowCreateTeamModal(false)} />
)}
{invites.length > 0 && (
<div className="mb-4">
<h1 className="mb-2 text-lg font-medium">{t("open_invitations")}</h1>
<TeamList teams={invites} />
</div>
)}
{isLoading && <SkeletonLoaderTeamList />}
{!teams.length && !isLoading && (
<EmptyScreen
Icon={Icon.FiUsers}
headline={t("no_teams")}
description={t("no_teams_description")}
buttonRaw={
<Button color="secondary" onClick={() => setShowCreateTeamModal(true)}>
{t("create_team")}
</Button>
}
buttonOnClick={() => setShowCreateTeamModal(true)}
/>
)}
{teams.length > 0 && <TeamList teams={teams} />}
</>
</Shell>
);
}
Teams.requiresLicense = false;
export default Teams;

View File

@ -382,6 +382,8 @@ export type NavigationItemType = {
icon?: SVGComponent; icon?: SVGComponent;
child?: NavigationItemType[]; child?: NavigationItemType[];
pro?: true; pro?: true;
onlyMobile?: boolean;
onlyDesktop?: boolean;
isCurrent?: ({ isCurrent?: ({
item, item,
isChild, isChild,
@ -411,6 +413,12 @@ const navigation: NavigationItemType[] = [
href: "/availability", href: "/availability",
icon: Icon.FiClock, icon: Icon.FiClock,
}, },
{
name: "teams",
href: "/teams",
icon: Icon.FiUsers,
onlyDesktop: true,
},
{ {
name: "apps", name: "apps",
href: "/apps", href: "/apps",
@ -480,7 +488,7 @@ const { desktopNavigationItems, mobileNavigationBottomItems, mobileNavigationMor
// We filter out the "more" separator in desktop navigation // We filter out the "more" separator in desktop navigation
if (item.name !== MORE_SEPARATOR_NAME) items.desktopNavigationItems.push(item); if (item.name !== MORE_SEPARATOR_NAME) items.desktopNavigationItems.push(item);
// Items for mobile bottom navigation // Items for mobile bottom navigation
if (index < moreSeparatorIndex + 1) items.mobileNavigationBottomItems.push(item); if (index < moreSeparatorIndex + 1 && !item.onlyDesktop) items.mobileNavigationBottomItems.push(item);
// Items for the "more" menu in mobile navigation // Items for the "more" menu in mobile navigation
else items.mobileNavigationMoreItems.push(item); else items.mobileNavigationMoreItems.push(item);
return items; return items;