/teams improvements (#6831)

Co-authored-by: Alex van Andel <me@alexvanandel.com>
This commit is contained in:
Peer Richelsen
2023-02-01 20:41:47 +00:00
committed by GitHub
co-authored by Alex van Andel
parent 7ee5967075
commit ef78db7856
5 changed files with 138 additions and 37 deletions
@@ -1557,6 +1557,11 @@
"email_no_user_step_four":"Join {{teamName}}",
"email_no_user_signoff":"Happy Scheduling from the {{appName}} team",
"impersonation_user_tip": "You are about to impersonate a user, which means you can make changes on their behalf. Please be careful.",
"scheduler": "{Scheduler}",
"available_variables": "Available variables",
"scheduler": "{Scheduler}"
"recommended_next_steps": "Recommended next steps",
"create_a_managed_event": "Create a managed event type",
"meetings_are_better_with_the_right": "Meetings are better with the right team members there. Invite them now.",
"collective_or_roundrobin": "Collective or round-robin",
"book_your_team_members": "Book your team members together with collective events or cycle through to get the right person with round-robin."
}
@@ -1,7 +1,9 @@
import { useState } from "react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { RouterOutputs, trpc } from "@calcom/trpc/react";
import { showToast } from "@calcom/ui";
import { Card, showToast } from "@calcom/ui";
import { FiUserPlus, FiUsers, FiUnlock, FiEdit } from "@calcom/ui/components/icon";
import TeamListItem from "./TeamListItem";
@@ -12,6 +14,8 @@ interface Props {
export default function TeamList(props: Props) {
const utils = trpc.useContext();
const { t } = useLocale();
const [hideDropdown, setHideDropdown] = useState(false);
function selectAction(action: string, teamId: number) {
@@ -47,6 +51,72 @@ export default function TeamList(props: Props) {
setHideDropdown={setHideDropdown}
/>
))}
{/* only show recommended steps when there is only one team */}
{props.teams.length === 1 && (
<>
{props.teams.map(
(team, i) =>
i === 0 && (
<div className="bg-gray-100 p-6">
<h3 className="mb-4 text-sm font-semibold text-gray-900">{t("recommended_next_steps")}</h3>
<div className="grid-col-1 grid gap-2 md:grid-cols-3">
<Card
icon={<FiUserPlus className="h-5 w-5 text-green-700" />}
variant="basic"
title={t("invite_team_member")}
description="Meetings are better with the right team members there. Invite them now."
actionButton={{
href: "/settings/teams/" + team.id + "/members",
child: t("invite"),
}}
/>
{/* @TODO: uncomment once managed event types is live
<Card
icon={<FiUnlock className="h-5 w-5 text-blue-700" />}
variant="basic"
title={t("create_a_managed_event")}
description={t("meetings_are_better_with_the_right")}
actionButton={{
href:
"/event-types?dialog=new-eventtype&eventPage=team%2F" +
team.slug +
"&teamId=" +
team.id +
"&managed=true",
child: t("create"),
}}
/> */}
<Card
icon={<FiUsers className="h-5 w-5 text-orange-700" />}
variant="basic"
title={t("collective_or_roundrobin")}
description={t("book_your_team_members")}
actionButton={{
href:
"/event-types?dialog=new-eventtype&eventPage=team%2F" +
team.slug +
"&teamId=" +
team.id,
child: t("create"),
}}
/>
<Card
icon={<FiEdit className="h-5 w-5 text-purple-700" />}
variant="basic"
title={t("appearance")}
description={t("appearance_subtitle")}
actionButton={{
href: "/settings/teams/" + team.id + "/appearance",
child: t("edit"),
}}
/>
</div>
</div>
)
)}
</>
)}
</ul>
);
}
@@ -68,6 +68,8 @@ export function TeamsListing() {
<UpgradeTip
title="calcom_is_better_with_team"
description="add_your_team_members"
emptyTitle="no_teams"
emptyDescription="no_teams_description"
features={features}
background="/team-banner-background.jpg"
buttons={
+13 -2
View File
@@ -1,4 +1,3 @@
import { useMemo } from "react";
import type { ReactNode } from "react";
import { classNames } from "@calcom/lib";
@@ -11,6 +10,8 @@ import { FiUsers } from "@calcom/ui/components/icon";
export function UpgradeTip({
dark,
title,
emptyTitle,
emptyDescription,
description,
background,
features,
@@ -21,6 +22,9 @@ export function UpgradeTip({
dark?: boolean;
title: string;
description: string;
/* overwrite EmptyScreen text */
emptyTitle?: string;
emptyDescription?: string;
background: string;
features: Array<{ icon: JSX.Element; title: string; description: string }>;
buttons?: JSX.Element;
@@ -36,7 +40,14 @@ export function UpgradeTip({
if (isParentLoading || isLoading) return <>{isParentLoading}</>;
if (!isCalcom)
return <EmptyScreen Icon={FiUsers} headline={title} description={description} buttonRaw={buttons} />;
return (
<EmptyScreen
Icon={FiUsers}
headline={emptyTitle ? t(emptyTitle) : t(title)}
description={emptyDescription ? t(emptyDescription) : t(description)}
buttonRaw={buttons}
/>
);
return (
<>
+46 -33
View File
@@ -1,13 +1,16 @@
// @TODO: turn this into a more generic component that has the same Props API as MUI https://mui.com/material-ui/react-card/
import Link from "next/link";
import { ReactNode } from "react";
import React from "react";
import classNames from "@calcom/lib/classNames";
import { FiArrowRight } from "@calcom/ui/components/icon";
import { Button } from "../button";
export type BaseCardProps = {
image?: string;
icon?: ReactNode;
variant: keyof typeof cardTypeByVariant;
imageProps?: JSX.IntrinsicElements["img"];
title: string;
@@ -26,10 +29,12 @@ export type BaseCardProps = {
thumbnailUrl?: string;
};
// @TODO: use CVA
const cardTypeByVariant = {
AppStore: {
basic: {
image: "w-10 h-auto",
card: "p-5 w-64",
card: "p-5",
title: "text-base",
description: "text-sm leading-[18px] text-gray-500 font-normal",
},
@@ -50,6 +55,7 @@ const cardTypeByVariant = {
export function Card({
image,
title,
icon,
description,
variant,
actionButton,
@@ -64,33 +70,36 @@ export function Card({
className={classNames(
containerProps?.className,
cardTypeByVariant[variant].card,
"rounded-md border border-gray-200 bg-white"
"flex flex-col justify-between rounded-md border border-gray-200 bg-white"
)}
{...containerProps}>
{image && (
<img
src={image}
// Stops eslint complaining - not smart enough to realise it comes from ...imageProps
alt={imageProps?.alt}
className={classNames(imageProps?.className, cardTypeByVariant[variant].image, "mb-4")}
{...imageProps}
/>
)}
<h5
title={title}
className={classNames(
cardTypeByVariant[variant].title,
"line-clamp-1 font-bold leading-5 text-gray-900"
)}>
{title}
</h5>
{description && (
<p
title={description.toString()}
className={classNames(cardTypeByVariant[variant].description, "pt-1")}>
{description}
</p>
)}
<div>
{icon && icon}
{image && (
<img
src={image}
// Stops eslint complaining - not smart enough to realise it comes from ...imageProps
alt={imageProps?.alt}
className={classNames(imageProps?.className, cardTypeByVariant[variant].image)}
{...imageProps}
/>
)}
<h5
title={title}
className={classNames(
cardTypeByVariant[variant].title,
"line-clamp-1 mt-4 font-bold leading-5 text-gray-900"
)}>
{title}
</h5>
{description && (
<p
title={description.toString()}
className={classNames(cardTypeByVariant[variant].description, "pt-1")}>
{description}
</p>
)}
</div>
{variant === "SidebarCard" && (
<a
onClick={actionButton?.onClick}
@@ -120,12 +129,16 @@ export function Card({
<img alt="play feature video" src={thumbnailUrl} />
</a>
)}
{variant === "AppStore" && (
<Button color="secondary" href={actionButton?.href} size="lg" className="mt-10 w-full">
{/* Force it to be centered as this usecase of a button is off - doesnt meet normal sizes */}
<div className="mx-auto">{actionButton?.child}</div>
</Button>
)}
{/* TODO: this should be CardActions https://mui.com/material-ui/api/card-actions/ */}
<div>
{variant === "basic" && (
<Button color="secondary" href={actionButton?.href} className="mt-10" EndIcon={FiArrowRight}>
{actionButton?.child}
</Button>
)}
</div>
{variant === "SidebarCard" && (
<div className="mt-2 flex items-center justify-between">
{learnMore && (