fix: update styles of charts on /insights (#22557)

* fix: update styles of charts on /insights

* clean up

* clean up

* share the same styles with ChartCardItem

* margin for event trends

* fix type error
This commit is contained in:
Eunjae Lee
2025-07-17 14:42:35 +00:00
committed by GitHub
parent 9cfc74a74f
commit 1878802213
18 changed files with 271 additions and 251 deletions
+7 -7
View File
@@ -71,22 +71,22 @@ function InsightsPageContent() {
<BookingStatusLineChart />
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
<PopularEventsTable />
<AverageEventDurationChart />
</div>
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-4">
<MostBookedTeamMembersTable />
<LeastBookedTeamMembersTable />
</div>
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<MostCancelledBookingsTables />
</div>
<RecentFeedbackTable />
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<HighestNoShowHostTable />
</div>
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-4">
<HighestRatedMembersTable />
<LowestRatedMembersTable />
<div className="sm:col-span-2">
<RecentFeedbackTable />
</div>
</div>
<small className="text-default block text-center">
{t("looking_for_more_insights")}{" "}
@@ -2167,12 +2167,14 @@
"popular_events": "Popular Events",
"no_event_types_found": "No event types found",
"average_event_duration": "Average Event Duration",
"most_booked_members": "Most Booked Members",
"least_booked_members": "Least Booked Members",
"most_booked_members": "Most Booked",
"least_booked_members": "Least Booked",
"events_created": "Events Created",
"events_completed": "Events Completed",
"events_cancelled": "Events Cancelled",
"events_rescheduled": "Events Rescheduled",
"events": "Events",
"performance": "Performance",
"from_last_period": "from last period",
"from_to_date_period": "From: {{startDate}} To: {{endDate}}",
"redirect_url_warning": "Adding a redirect will disable the success page. Make sure to mention \"Booking Confirmed\" on your custom success page.",
@@ -2720,10 +2722,12 @@
"event_ratings": "Average Ratings",
"event_no_show": "No-Show (Host)",
"event_no_show_guest": "No-Show (Guest)",
"recent_ratings": "Recent ratings",
"recent_ratings": "Recent Ratings",
"no_ratings": "No ratings submitted",
"no_ratings_description": "Add a workflow with 'Rating' to collect ratings after meetings",
"most_no_show_host": "Most No Show Members",
"most_no_show_host": "Most No-Show",
"highest_rated": "Highest Rated",
"lowest_rated": "Lowest Rated",
"highest_rated_members": "Members with highest rated meetings",
"lowest_rated_members": "Members with lowest rated meetings",
"csat_score": "CSAT Score",
@@ -3143,7 +3147,7 @@
"display": "Display",
"could_not_find_slug_to_publish_org": "Could not find slug to publish the organization",
"picklist": "Picklist",
"most_cancelled_bookings": "Most Cancelled Bookings",
"most_cancelled_bookings": "Most Cancelled",
"interface_language": "Interface Language",
"visitors_browser_language": "Visitor's browser language",
"name_or_email": "Name or Email",
@@ -1,11 +1,9 @@
import { Title } from "@tremor/react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc";
import { useInsightsParameters } from "../hooks/useInsightsParameters";
import { valueFormatter } from "../lib/valueFormatter";
import { CardInsights } from "./Card";
import { ChartCard } from "./ChartCard";
import { LineChart } from "./LineChart";
import { LoadingInsight } from "./LoadingInsights";
@@ -36,8 +34,7 @@ export const AverageEventDurationChart = () => {
if (!isSuccess || !data) return null;
const isNoData = data.every((item) => item["Average"] === 0);
return (
<CardInsights>
<Title className="text-emphasis">{t("average_event_duration")}</Title>
<ChartCard title={t("average_event_duration")}>
{isNoData && (
<div className="text-default flex h-60 text-center">
<p className="m-auto text-sm font-light">{t("insights_no_data_found_for_filter")}</p>
@@ -53,6 +50,6 @@ export const AverageEventDurationChart = () => {
valueFormatter={valueFormatter}
/>
)}
</CardInsights>
</ChartCard>
);
};
@@ -1,11 +1,10 @@
import { Grid } from "@tremor/react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc";
import { SkeletonText, SkeletonContainer } from "@calcom/ui/components/skeleton";
import classNames from "@calcom/ui/classNames";
import { SkeletonText } from "@calcom/ui/components/skeleton";
import { useInsightsParameters } from "../hooks/useInsightsParameters";
import { CardInsights } from "./Card";
import { ChartCard } from "./ChartCard";
import { KPICard } from "./KPICard";
export const BookingKPICards = () => {
@@ -30,17 +29,9 @@ export const BookingKPICards = () => {
}
);
const categories: {
const eventCategories: {
title: string;
index:
| "created"
| "completed"
| "rescheduled"
| "cancelled"
| "no_show"
| "rating"
| "csat"
| "no_show_guest";
index: "created" | "completed" | "rescheduled" | "cancelled";
}[] = [
{
title: t("events_created"),
@@ -58,6 +49,12 @@ export const BookingKPICards = () => {
title: t("events_cancelled"),
index: "cancelled",
},
];
const performanceCategories: {
title: string;
index: "rating" | "no_show" | "no_show_guest" | "csat";
}[] = [
{
title: t("event_ratings"),
index: "rating",
@@ -77,41 +74,112 @@ export const BookingKPICards = () => {
];
if (isPending) {
return <LoadingKPICards categories={categories} />;
return (
<LoadingKPICards eventCategories={eventCategories} performanceCategories={performanceCategories} />
);
}
if (!isSuccess || !data) return null;
return (
<>
<Grid numColsSm={2} numColsLg={4} className="gap-x-4 gap-y-4">
{categories.map((item) => (
<KPICard
key={item.title}
title={item.title}
value={data[item.index].count}
previousMetricData={data[item.index]}
previousDateRange={data.previousRange}
/>
))}
</Grid>
</>
<div className="space-y-4">
<ChartCard title={t("events")}>
<StatContainer>
{eventCategories.map((item, index) => (
<StatItem key={item.title} index={index}>
<KPICard
title={item.title}
value={data[item.index].count}
previousMetricData={data[item.index]}
previousDateRange={data.previousRange}
/>
</StatItem>
))}
</StatContainer>
</ChartCard>
<ChartCard title={t("performance")}>
<StatContainer>
{performanceCategories.map((item, index) => (
<StatItem key={item.title} index={index}>
<KPICard
title={item.title}
value={data[item.index].count}
previousMetricData={data[item.index]}
previousDateRange={data.previousRange}
/>
</StatItem>
))}
</StatContainer>
</ChartCard>
</div>
);
};
const LoadingKPICards = (props: { categories: { title: string; index: string }[] }) => {
const { categories } = props;
const LoadingKPICards = (props: {
eventCategories: { title: string; index: string }[];
performanceCategories: { title: string; index: string }[];
}) => {
const { eventCategories, performanceCategories } = props;
const { t } = useLocale();
return (
<Grid numColsSm={2} numColsLg={4} className="gap-x-4 gap-y-4">
{categories.map((item) => (
<CardInsights key={item.title}>
<SkeletonContainer className="flex w-full flex-col">
<SkeletonText className="mt-2 h-4 w-32" />
<SkeletonText className="mt-2 h-6 w-16" />
<SkeletonText className="mt-4 h-6 w-44" />
</SkeletonContainer>
</CardInsights>
))}
</Grid>
<div className="space-y-4">
<ChartCard title={t("events")}>
<StatContainer>
{eventCategories.map((item, index) => (
<StatItem key={item.title} index={index}>
<div>
<SkeletonText className="mb-2 h-4 w-24" />
<div className="items-baseline justify-start space-x-3 truncate">
<SkeletonText className="h-8 w-16" />
</div>
<div className="mt-4 justify-start space-x-2">
<SkeletonText className="h-4 w-20" />
</div>
</div>
</StatItem>
))}
</StatContainer>
</ChartCard>
<ChartCard title={t("performance")}>
<StatContainer>
{performanceCategories.map((item, index) => (
<StatItem key={item.title} index={index}>
<div>
<SkeletonText className="mb-2 h-4 w-24" />
<div className="items-baseline justify-start space-x-3 truncate">
<SkeletonText className="h-8 w-16" />
</div>
<div className="mt-4 justify-start space-x-2">
<SkeletonText className="h-4 w-20" />
</div>
</div>
</StatItem>
))}
</StatContainer>
</ChartCard>
</div>
);
};
// StatContainer: wraps the grid
function StatContainer({ children }: { children: React.ReactNode }) {
return <div className="group grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4">{children}</div>;
}
// StatItem: handles border logic
function StatItem({ index, children }: { index: number; children: React.ReactNode }) {
return (
<div
className={classNames(
"border-muted flex-1 p-4",
index === 0 && "border-b sm:border-r md:border-b-0 md:border-r",
index === 1 && "border-b sm:border-r-0 md:border-b-0 md:border-r",
index === 2 && "border-b sm:border-b-0 sm:border-r md:border-b-0"
)}>
{children}
</div>
);
}
@@ -1,11 +1,9 @@
import { Title } from "@tremor/react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc";
import { useInsightsParameters } from "../hooks/useInsightsParameters";
import { valueFormatter } from "../lib/valueFormatter";
import { CardInsights } from "./Card";
import { ChartCard } from "./ChartCard";
import { LineChart } from "./LineChart";
import { LoadingInsight } from "./LoadingInsights";
@@ -39,16 +37,15 @@ export const BookingStatusLineChart = () => {
if (!isSuccess) return null;
return (
<CardInsights>
<Title className="text-emphasis">{t("event_trends")}</Title>
<ChartCard title={t("event_trends")}>
<LineChart
className="linechart mt-4 h-80"
className="linechart ml-4 mt-4 h-80 sm:ml-0"
data={eventsTimeLine ?? []}
categories={["Created", "Completed", "Rescheduled", "Cancelled", "No-Show (Host)", "No-Show (Guest)"]}
index="Month"
colors={["purple", "green", "blue", "red", "slate", "orange"]}
valueFormatter={valueFormatter}
/>
</CardInsights>
</ChartCard>
);
};
@@ -1,4 +1,4 @@
import { Fragment } from "react";
import { Fragment, type ReactNode } from "react";
import classNames from "@calcom/ui/classNames";
import { Button } from "@calcom/ui/components/button";
@@ -51,6 +51,15 @@ export function ChartCard({
);
}
export function ChartCardItem({ count, children }: { count?: number | string; children: ReactNode }) {
return (
<div className="text-default border-muted flex items-center justify-between border-b px-3 py-3.5 last:border-b-0">
<div className="text-sm font-medium">{children}</div>
{count !== undefined && <div className="text-sm font-medium">{count}</div>}
</div>
);
}
function Legend({ items, size = "default" }: { items: LegendItem[]; size?: LegendSize }) {
return (
<div className="bg-default flex items-center gap-2 rounded-lg px-1.5 py-1">
@@ -1,11 +1,10 @@
import { Table, TableBody, TableCell, TableRow, Text } from "@tremor/react";
import { getUserAvatarUrl } from "@calcom/lib/getAvatarUrl";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { User } from "@calcom/prisma/client";
import { EmptyScreen } from "@calcom/ui/components/empty-screen";
import { Avatar } from "@calcom/ui/components/avatar";
import { Button } from "@calcom/ui/components/button";
import { EmptyScreen } from "@calcom/ui/components/empty-screen";
import { Tooltip } from "@calcom/ui/components/tooltip";
export const FeedbackTable = ({
data,
@@ -23,50 +22,44 @@ export const FeedbackTable = ({
}) => {
const { t } = useLocale();
return (
<Table>
<TableBody>
<>
{data && data?.length > 0 ? (
data?.map((item) => (
<TableRow key={item.userId}>
<TableCell className="flex flex-row">
<Avatar
alt={item.user.name || ""}
size="sm"
imageSrc={getUserAvatarUrl({ avatarUrl: item.user.avatarUrl })}
title={item.user.name || ""}
className="m-2"
/>
<p className="text-default mx-0 my-auto">
<strong>{item.user.name}</strong>
</p>
</TableCell>
<TableCell className="text-right">
<Text>
<strong className="text-default">{item.rating}</strong>
</Text>
</TableCell>
<TableCell className="text-left">
<Text>
<strong className="text-default">{item.feedback}</strong>
</Text>
</TableCell>
</TableRow>
))
) : (
<EmptyScreen
Icon="zap"
headline={t("no_ratings")}
description={t("no_ratings_description")}
buttonRaw={
<Button target="_blank" color="secondary" href="/workflows">
{t("workflows")}
</Button>
}
/>
)}
</>
</TableBody>
</Table>
<div className="overflow-hidden rounded-md">
{data && data?.length > 0 ? (
data?.map((item) => (
<div
key={item.userId}
className="border-subtle flex items-center justify-between border-b px-4 py-3 last:border-b-0">
<div className="flex items-center">
<Avatar
alt={item.user.name || ""}
size="sm"
imageSrc={getUserAvatarUrl({ avatarUrl: item.user.avatarUrl })}
title={item.user.name || ""}
className="mr-3"
/>
<div className="text-default text-sm font-medium">{item.user.name}</div>
</div>
<div className="flex items-center space-x-4">
<div className="text-default text-sm font-medium">{item.rating}</div>
<Tooltip content={item.feedback}>
<div className="text-default max-w-32 md:max-w-52 truncate text-sm font-medium">
{item.feedback}
</div>
</Tooltip>
</div>
</div>
))
) : (
<EmptyScreen
Icon="zap"
headline={t("no_ratings")}
description={t("no_ratings_description")}
buttonRaw={
<Button target="_blank" color="secondary" href="/workflows">
{t("workflows")}
</Button>
}
/>
)}
</div>
);
};
@@ -1,10 +1,8 @@
import { Title } from "@tremor/react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc";
import { useInsightsParameters } from "../hooks/useInsightsParameters";
import { CardInsights } from "./Card";
import { ChartCard } from "./ChartCard";
import { LoadingInsight } from "./LoadingInsights";
import { TotalUserFeedbackTable } from "./TotalUserFeedbackTable";
@@ -33,10 +31,9 @@ export const HighestNoShowHostTable = () => {
if (!isSuccess || !data) return null;
return data && data.length > 0 ? (
<CardInsights className="shadow-none">
<Title className="text-emphasis">{t("most_no_show_host")}</Title>
<ChartCard title={t("most_no_show_host")}>
<TotalUserFeedbackTable data={data} />
</CardInsights>
</ChartCard>
) : (
<></>
);
@@ -1,10 +1,8 @@
import { Title } from "@tremor/react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc";
import { useInsightsParameters } from "../hooks/useInsightsParameters";
import { CardInsights } from "./Card";
import { ChartCard } from "./ChartCard";
import { LoadingInsight } from "./LoadingInsights";
import { TotalUserFeedbackTable } from "./TotalUserFeedbackTable";
@@ -33,10 +31,9 @@ export const HighestRatedMembersTable = () => {
if (!isSuccess || !data) return null;
return data && data.length > 0 ? (
<CardInsights className="shadow-none">
<Title className="text-emphasis">{t("highest_rated_members")}</Title>
<ChartCard title={t("highest_rated")}>
<TotalUserFeedbackTable data={data} />
</CardInsights>
</ChartCard>
) : (
<></>
);
@@ -4,7 +4,6 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import { Tooltip } from "@calcom/ui/components/tooltip";
import { calculateDeltaType, colors, valueFormatter } from "../lib";
import { CardInsights } from "./Card";
export const KPICard = ({
title,
@@ -21,7 +20,7 @@ export const KPICard = ({
}) => {
const { t } = useLocale();
return (
<CardInsights key={title}>
<div>
<Text className="text-default">{title}</Text>
<Flex className="items-baseline justify-start space-x-3 truncate">
<Metric className="text-emphasis">{valueFormatter(previousMetricData.count)}</Metric>
@@ -47,6 +46,6 @@ export const KPICard = ({
</Tooltip>
</Flex>
</Flex>
</CardInsights>
</div>
);
};
@@ -1,10 +1,8 @@
import { Title } from "@tremor/react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc";
import { useInsightsParameters } from "../hooks/useInsightsParameters";
import { CardInsights } from "./Card";
import { ChartCard } from "./ChartCard";
import { LoadingInsight } from "./LoadingInsights";
import { TotalBookingUsersTable } from "./TotalBookingUsersTable";
@@ -33,9 +31,8 @@ export const LeastBookedTeamMembersTable = () => {
if (!isSuccess || !data) return null;
return (
<CardInsights>
<Title className="text-emphasis">{t("least_booked_members")}</Title>
<ChartCard title={t("least_booked_members")}>
<TotalBookingUsersTable data={data} />
</CardInsights>
</ChartCard>
);
};
@@ -1,10 +1,8 @@
import { Title } from "@tremor/react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc";
import { useInsightsParameters } from "../hooks/useInsightsParameters";
import { CardInsights } from "./Card";
import { ChartCard } from "./ChartCard";
import { LoadingInsight } from "./LoadingInsights";
import { TotalUserFeedbackTable } from "./TotalUserFeedbackTable";
@@ -33,10 +31,9 @@ export const LowestRatedMembersTable = () => {
if (!isSuccess || !data) return null;
return data && data.length > 0 ? (
<CardInsights className="shadow-none">
<Title className="text-emphasis">{t("lowest_rated_members")}</Title>
<ChartCard title={t("lowest_rated")}>
<TotalUserFeedbackTable data={data} />
</CardInsights>
</ChartCard>
) : (
<></>
);
@@ -1,10 +1,8 @@
import { Title } from "@tremor/react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc";
import { useInsightsParameters } from "../hooks/useInsightsParameters";
import { CardInsights } from "./Card";
import { ChartCard } from "./ChartCard";
import { LoadingInsight } from "./LoadingInsights";
import { TotalBookingUsersTable } from "./TotalBookingUsersTable";
@@ -33,9 +31,8 @@ export const MostBookedTeamMembersTable = () => {
if (!isSuccess || !data) return null;
return (
<CardInsights className="shadow-none">
<Title className="text-emphasis">{t("most_booked_members")}</Title>
<ChartCard title={t("most_booked_members")}>
<TotalBookingUsersTable data={data} />
</CardInsights>
</ChartCard>
);
};
@@ -1,10 +1,8 @@
import { Title } from "@tremor/react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc";
import { useInsightsParameters } from "../hooks/useInsightsParameters";
import { CardInsights } from "./Card";
import { ChartCard } from "./ChartCard";
import { LoadingInsight } from "./LoadingInsights";
import { TotalBookingUsersTable } from "./TotalBookingUsersTable";
@@ -31,9 +29,8 @@ export const MostCancelledBookingsTables = () => {
if (isPending) return <LoadingInsight />;
return (
<CardInsights className="shadow-none">
<Title className="text-emphasis">{t("most_cancelled_bookings")}</Title>
<ChartCard title={t("most_cancelled_bookings")}>
{!isSuccess || !startDate || !endDate || !teamId ? null : <TotalBookingUsersTable data={data} />}
</CardInsights>
</ChartCard>
);
};
@@ -1,10 +1,8 @@
import { Table, TableBody, TableCell, TableRow, Text, Title } from "@tremor/react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc";
import { useInsightsParameters } from "../hooks/useInsightsParameters";
import { CardInsights } from "./Card";
import { ChartCard, ChartCardItem } from "./ChartCard";
import { LoadingInsight } from "./LoadingInsights";
export const PopularEventsTable = () => {
@@ -34,30 +32,24 @@ export const PopularEventsTable = () => {
if (!isSuccess || !data) return null;
return (
<CardInsights>
<Title className="text-emphasis">{t("popular_events")}</Title>
<Table className="mt-5">
<TableBody>
{data.map(
(item) =>
item.eventTypeId && (
<TableRow key={item.eventTypeId}>
<TableCell className="text-default">{item.eventTypeName}</TableCell>
<TableCell>
<Text className="text-default text-right">
<strong>{item.count}</strong>
</Text>
</TableCell>
</TableRow>
)
)}
</TableBody>
</Table>
<ChartCard title={t("popular_events")}>
<div>
{data
.filter((item) => item.eventTypeId)
.map((item) => (
<ChartCardItem key={item.eventTypeId} count={item.count}>
<div className="flex">
<div className="bg-subtle mr-1.5 h-5 w-[2px] shrink-0 rounded-sm" />
<p>{item.eventTypeName}</p>
</div>
</ChartCardItem>
))}
</div>
{data.length === 0 && (
<div className="flex h-60 text-center">
<p className="m-auto text-sm font-light">{t("insights_no_data_found_for_filter")}</p>
</div>
)}
</CardInsights>
</ChartCard>
);
};
@@ -1,10 +1,8 @@
import { Title } from "@tremor/react";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc";
import { useInsightsParameters } from "../hooks/useInsightsParameters";
import { CardInsights } from "./Card";
import { ChartCard } from "./ChartCard";
import { FeedbackTable } from "./FeedbackTable";
import { LoadingInsight } from "./LoadingInsights";
@@ -33,9 +31,8 @@ export const RecentFeedbackTable = () => {
if (!isSuccess || !data) return null;
return (
<CardInsights>
<Title className="text-emphasis">{t("recent_ratings")}</Title>
<ChartCard title={t("recent_ratings")}>
<FeedbackTable data={data} />
</CardInsights>
</ChartCard>
);
};
@@ -1,9 +1,9 @@
import { Table, TableBody, TableCell, TableRow, Text } from "@tremor/react";
import { getUserAvatarUrl } from "@calcom/lib/getAvatarUrl";
import type { User } from "@calcom/prisma/client";
import { Avatar } from "@calcom/ui/components/avatar";
import { ChartCardItem } from "./ChartCard";
export const TotalBookingUsersTable = ({
data,
}: {
@@ -19,38 +19,27 @@ export const TotalBookingUsersTable = ({
}) => {
const filteredData = data && data?.length > 0 ? data?.filter((item) => !!item.user) : [];
return (
<Table>
<TableBody>
<>
{filteredData.length > 0 ? (
filteredData.map((item) => (
<TableRow key={item.userId}>
<TableCell className="flex flex-row">
<Avatar
alt={item.user.name || ""}
size="sm"
imageSrc={getUserAvatarUrl({ avatarUrl: item.user.avatarUrl })}
title={item.user.name || ""}
className="m-2"
/>
<p className="text-default mx-0 my-auto">
<strong>{item.user.name}</strong>
</p>
</TableCell>
<TableCell className="text-right">
<Text>
<strong className="text-default">{item.count}</strong>
</Text>
</TableCell>
</TableRow>
))
) : (
<TableRow>
<TableCell>No members found</TableCell>
</TableRow>
)}
</>
</TableBody>
</Table>
<div className="overflow-hidden rounded-md">
{filteredData.length > 0 ? (
filteredData.map((item) => (
<ChartCardItem key={item.userId} count={item.count}>
<div className="flex items-center">
<Avatar
alt={item.user.name || ""}
size="sm"
imageSrc={getUserAvatarUrl({ avatarUrl: item.user.avatarUrl })}
title={item.user.name || ""}
className="mr-3"
/>
<div>{item.user.name}</div>
</div>
</ChartCardItem>
))
) : (
<div className="flex h-60 text-center">
<p className="m-auto text-sm font-light">No members found</p>
</div>
)}
</div>
);
};
@@ -1,9 +1,9 @@
import { Table, TableBody, TableCell, TableRow, Text } from "@tremor/react";
import { getUserAvatarUrl } from "@calcom/lib/getAvatarUrl";
import type { User } from "@calcom/prisma/client";
import { Avatar } from "@calcom/ui/components/avatar";
import { ChartCardItem } from "./ChartCard";
export const TotalUserFeedbackTable = ({
data,
}: {
@@ -19,36 +19,29 @@ export const TotalUserFeedbackTable = ({
| undefined;
}) => {
return (
<Table>
<TableBody>
<>
{data &&
data?.length > 0 &&
data?.map((item) => (
<TableRow key={item.userId}>
<TableCell className="flex flex-row">
<Avatar
alt={item.user.name || ""}
size="sm"
imageSrc={getUserAvatarUrl({ avatarUrl: item.user.avatarUrl })}
title={item.user.name || ""}
className="m-2"
/>
<p className="text-default mx-0 my-auto">
<strong>{item.user.name}</strong>
</p>
</TableCell>
<TableCell className="text-right">
<Text>
<strong className="text-default">
{item.averageRating ? item.averageRating.toFixed(1) : item.count}
</strong>
</Text>
</TableCell>
</TableRow>
))}
</>
</TableBody>
</Table>
<div className="overflow-hidden rounded-md">
{data && data?.length > 0 ? (
data?.map((item) => (
<ChartCardItem
key={item.userId}
count={item.averageRating ? item.averageRating.toFixed(1) : item.count}>
<div className="flex items-center">
<Avatar
alt={item.user.name || ""}
size="sm"
imageSrc={getUserAvatarUrl({ avatarUrl: item.user.avatarUrl })}
title={item.user.name || ""}
className="mr-3"
/>
<div className="text-default text-sm font-medium">{item.user.name}</div>
</div>
</ChartCardItem>
))
) : (
<div className="flex h-60 text-center">
<p className="m-auto text-sm font-light">No data found</p>
</div>
)}
</div>
);
};