fix: #15857 add managed by tooltip (#15861)

* managed by tooltip

* updated for team admin

* updated for typechecks and naming

* for multiple admins

* update to show team link when more than 2 admins

* nit/chore : variable naming

* improvement

---------

Co-authored-by: Anik Dhabal Babu <81948346+anikdhabal@users.noreply.github.com>
Co-authored-by: unknown <adhabal2002@gmail.com>
This commit is contained in:
Vijay
2024-08-06 13:46:24 +02:00
committed by GitHub
co-authored by Anik Dhabal Babu unknown
parent 3c6e9aaa63
commit 100136aae7
4 changed files with 105 additions and 32 deletions
@@ -2528,5 +2528,6 @@
"outlook_connect_atom_already_connected_label": "Connected Outlook Calendar",
"outlook_connect_atom_loading_label": "Checking Outlook Calendar",
"booking_question_response_variables": "Booking question response variables",
"managed_by_teamAdmins": "Managed by {{teamAdmins}}",
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
}
@@ -1,4 +1,5 @@
import type { Prisma } from "@prisma/client";
import Link from "next/link";
import { useMemo } from "react";
import type { z } from "zod";
@@ -10,7 +11,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { baseEventTypeSelect } from "@calcom/prisma";
import { SchedulingType } from "@calcom/prisma/enums";
import type { EventTypeModel } from "@calcom/prisma/zod";
import { Badge } from "@calcom/ui";
import { Badge, Tooltip } from "@calcom/ui";
export type EventTypeDescriptionProps = {
eventType: Pick<
@@ -19,6 +20,7 @@ export type EventTypeDescriptionProps = {
> & {
descriptionAsSafeHTML?: string | null;
recurringEvent: Prisma.JsonValue;
managedBy?: { teamId: number | undefined; admins: string[] };
};
className?: string;
shortenDescription?: boolean;
@@ -40,6 +42,32 @@ export const EventTypeDescription = ({
const paymentAppData = getPaymentAppData(eventType);
const showManagedBadge = eventType.metadata?.managedEventConfig && !isPublic;
const numberOfAdmins = eventType.managedBy?.admins.length || 0;
let managedByToolTipContent;
if (numberOfAdmins > 0) {
managedByToolTipContent = t("managed_by_teamAdmins", {
teamAdmins: eventType.managedBy?.admins?.slice(0, 2).join(", "),
});
if (numberOfAdmins > 2) {
managedByToolTipContent = (
<>
{`${managedByToolTipContent} ${t("and")} `}
{!!eventType.managedBy?.teamId ? (
<Link
href={`/settings/teams/${eventType.managedBy?.teamId}/members`}
className="text-blue-500 underline hover:text-blue-600 focus:outline-none">
{`${numberOfAdmins - 2} ${t("more")}`}
</Link>
) : (
<span>{`${numberOfAdmins - 2} ${t("more")}`}</span>
)}
</>
);
}
}
return (
<>
<div className={classNames("text-subtle", className)}>
@@ -78,11 +106,22 @@ export const EventTypeDescription = ({
</Badge>
</li>
)}
{eventType.metadata?.managedEventConfig && !isPublic && (
<Badge variant="gray" startIcon="lock">
{t("managed")}
</Badge>
)}
{showManagedBadge &&
(numberOfAdmins === 0 ? (
<div>
<Badge variant="gray" startIcon="lock">
{t("managed")}
</Badge>
</div>
) : (
<Tooltip content={managedByToolTipContent}>
<div>
<Badge variant="gray" startIcon="lock">
{t("managed")}
</Badge>
</div>
</Tooltip>
))}
{recurringEvent?.count && recurringEvent.count > 0 && (
<li className="hidden xl:block" data-testid="repeat-eventtype">
<Badge variant="gray" startIcon="refresh-cw">
@@ -105,32 +105,43 @@ export const getEventTypesByViewer = async (user: User, filters?: Filters, forRo
type UserEventTypes = (typeof profileEventTypes)[number];
const mapEventType = async (eventType: UserEventTypes) => ({
...eventType,
safeDescription: eventType?.description ? markdownToSafeHTML(eventType.description) : undefined,
users: await Promise.all(
(!!eventType?.hosts?.length ? eventType?.hosts.map((host) => host.user) : eventType.users).map(
async (u) =>
await UserRepository.enrichUserWithItsProfile({
user: u,
})
)
),
metadata: eventType.metadata ? EventTypeMetaDataSchema.parse(eventType.metadata) : null,
children: await Promise.all(
(eventType.children || []).map(async (c) => ({
...c,
users: await Promise.all(
c.users.map(
async (u) =>
await UserRepository.enrichUserWithItsProfile({
user: u,
})
)
),
}))
),
});
const mapEventType = async (eventType: UserEventTypes) => {
const { parent, ...rest } = eventType;
return {
...rest,
safeDescription: eventType?.description ? markdownToSafeHTML(eventType.description) : undefined,
users: await Promise.all(
(!!eventType?.hosts?.length ? eventType?.hosts.map((host) => host.user) : eventType.users).map(
async (u) =>
await UserRepository.enrichUserWithItsProfile({
user: u,
})
)
),
metadata: eventType.metadata ? EventTypeMetaDataSchema.parse(eventType.metadata) : null,
children: await Promise.all(
(eventType.children || []).map(async (c) => ({
...c,
users: await Promise.all(
c.users.map(
async (u) =>
await UserRepository.enrichUserWithItsProfile({
user: u,
})
)
),
}))
),
managedBy: {
teamId: parent?.team?.id,
admins:
parent?.team?.members
.filter((member) => member.role === MembershipRole.ADMIN && member.accepted === true)
.map((member) => member.user?.name || member.user?.username || member.user?.email)
.filter((name) => !!name) || [],
},
};
};
const userEventTypes = (await Promise.all(profileEventTypes.map(mapEventType))).filter((eventType) => {
const isAChildEvent = eventType.parentId;
+22
View File
@@ -50,4 +50,26 @@ export const eventTypeSelect = Prisma.validator<Prisma.EventTypeSelect>()({
secondaryEmailId: true,
bookingLimits: true,
durationLimits: true,
parent: {
select: {
team: {
select: {
id: true,
members: {
select: {
user: {
select: {
name: true,
username: true,
email: true,
},
},
role: true,
accepted: true,
},
},
},
},
},
},
});