diff --git a/apps/web/modules/insights/insights-view.tsx b/apps/web/modules/insights/insights-view.tsx index 9f3e939ce7..379400f08c 100644 --- a/apps/web/modules/insights/insights-view.tsx +++ b/apps/web/modules/insights/insights-view.tsx @@ -71,22 +71,22 @@ function InsightsPageContent() { -
+
-
+
-
-
-
- -
+
+
+
+ +
{t("looking_for_more_insights")}{" "} diff --git a/apps/web/public/static/locales/en/common.json b/apps/web/public/static/locales/en/common.json index 16fe6157b7..7d99dc6e12 100644 --- a/apps/web/public/static/locales/en/common.json +++ b/apps/web/public/static/locales/en/common.json @@ -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", diff --git a/packages/features/insights/components/AverageEventDurationChart.tsx b/packages/features/insights/components/AverageEventDurationChart.tsx index df73d56210..145c1e461e 100644 --- a/packages/features/insights/components/AverageEventDurationChart.tsx +++ b/packages/features/insights/components/AverageEventDurationChart.tsx @@ -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 ( - - {t("average_event_duration")} + {isNoData && (

{t("insights_no_data_found_for_filter")}

@@ -53,6 +50,6 @@ export const AverageEventDurationChart = () => { valueFormatter={valueFormatter} /> )} - + ); }; diff --git a/packages/features/insights/components/BookingKPICards.tsx b/packages/features/insights/components/BookingKPICards.tsx index fa111acdf7..7d5030a1f3 100644 --- a/packages/features/insights/components/BookingKPICards.tsx +++ b/packages/features/insights/components/BookingKPICards.tsx @@ -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 ; + return ( + + ); } if (!isSuccess || !data) return null; return ( - <> - - {categories.map((item) => ( - - ))} - - +
+ + + {eventCategories.map((item, index) => ( + + + + ))} + + + + + + {performanceCategories.map((item, index) => ( + + + + ))} + + +
); }; -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 ( - - {categories.map((item) => ( - - - - - - - - ))} - +
+ + + {eventCategories.map((item, index) => ( + +
+ +
+ +
+
+ +
+
+
+ ))} +
+
+ + + + {performanceCategories.map((item, index) => ( + +
+ +
+ +
+
+ +
+
+
+ ))} +
+
+
); }; + +// StatContainer: wraps the grid +function StatContainer({ children }: { children: React.ReactNode }) { + return
{children}
; +} + +// StatItem: handles border logic +function StatItem({ index, children }: { index: number; children: React.ReactNode }) { + return ( +
+ {children} +
+ ); +} diff --git a/packages/features/insights/components/BookingStatusLineChart.tsx b/packages/features/insights/components/BookingStatusLineChart.tsx index bcc4524c17..c4cd9ec2b8 100644 --- a/packages/features/insights/components/BookingStatusLineChart.tsx +++ b/packages/features/insights/components/BookingStatusLineChart.tsx @@ -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 ( - - {t("event_trends")} + - + ); }; diff --git a/packages/features/insights/components/ChartCard.tsx b/packages/features/insights/components/ChartCard.tsx index dcdc965792..af50d4be3d 100644 --- a/packages/features/insights/components/ChartCard.tsx +++ b/packages/features/insights/components/ChartCard.tsx @@ -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 ( +
+
{children}
+ {count !== undefined &&
{count}
} +
+ ); +} + function Legend({ items, size = "default" }: { items: LegendItem[]; size?: LegendSize }) { return (
diff --git a/packages/features/insights/components/FeedbackTable.tsx b/packages/features/insights/components/FeedbackTable.tsx index 3d325f55ea..ea2675f250 100644 --- a/packages/features/insights/components/FeedbackTable.tsx +++ b/packages/features/insights/components/FeedbackTable.tsx @@ -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 ( - - - <> - {data && data?.length > 0 ? ( - data?.map((item) => ( - - - -

- {item.user.name} -

-
- - - {item.rating} - - - - - {item.feedback} - - -
- )) - ) : ( - - {t("workflows")} - - } - /> - )} - -
-
+
+ {data && data?.length > 0 ? ( + data?.map((item) => ( +
+
+ +
{item.user.name}
+
+
+
{item.rating}
+ +
+ {item.feedback} +
+
+
+
+ )) + ) : ( + + {t("workflows")} + + } + /> + )} +
); }; diff --git a/packages/features/insights/components/HighestNoShowHostTable.tsx b/packages/features/insights/components/HighestNoShowHostTable.tsx index 23774c52de..7b939dc578 100644 --- a/packages/features/insights/components/HighestNoShowHostTable.tsx +++ b/packages/features/insights/components/HighestNoShowHostTable.tsx @@ -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 ? ( - - {t("most_no_show_host")} + - + ) : ( <> ); diff --git a/packages/features/insights/components/HighestRatedMembersTable.tsx b/packages/features/insights/components/HighestRatedMembersTable.tsx index 926910eb53..3655c13cfe 100644 --- a/packages/features/insights/components/HighestRatedMembersTable.tsx +++ b/packages/features/insights/components/HighestRatedMembersTable.tsx @@ -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 ? ( - - {t("highest_rated_members")} + - + ) : ( <> ); diff --git a/packages/features/insights/components/KPICard.tsx b/packages/features/insights/components/KPICard.tsx index 246b351257..c7ef294d45 100644 --- a/packages/features/insights/components/KPICard.tsx +++ b/packages/features/insights/components/KPICard.tsx @@ -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 ( - +
{title} {valueFormatter(previousMetricData.count)} @@ -47,6 +46,6 @@ export const KPICard = ({ - +
); }; diff --git a/packages/features/insights/components/LeastBookedTeamMembersTable.tsx b/packages/features/insights/components/LeastBookedTeamMembersTable.tsx index af1a20cee9..f7c47d0d13 100644 --- a/packages/features/insights/components/LeastBookedTeamMembersTable.tsx +++ b/packages/features/insights/components/LeastBookedTeamMembersTable.tsx @@ -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 ( - - {t("least_booked_members")} + - + ); }; diff --git a/packages/features/insights/components/LowestRatedMembersTable.tsx b/packages/features/insights/components/LowestRatedMembersTable.tsx index 615f24523b..1708150b1b 100644 --- a/packages/features/insights/components/LowestRatedMembersTable.tsx +++ b/packages/features/insights/components/LowestRatedMembersTable.tsx @@ -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 ? ( - - {t("lowest_rated_members")} + - + ) : ( <> ); diff --git a/packages/features/insights/components/MostBookedTeamMembersTable.tsx b/packages/features/insights/components/MostBookedTeamMembersTable.tsx index 5e7d99eb07..e7fb459e75 100644 --- a/packages/features/insights/components/MostBookedTeamMembersTable.tsx +++ b/packages/features/insights/components/MostBookedTeamMembersTable.tsx @@ -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 ( - - {t("most_booked_members")} + - + ); }; diff --git a/packages/features/insights/components/MostCancelledBookingsTables.tsx b/packages/features/insights/components/MostCancelledBookingsTables.tsx index e452f79fbd..da5ca0d768 100644 --- a/packages/features/insights/components/MostCancelledBookingsTables.tsx +++ b/packages/features/insights/components/MostCancelledBookingsTables.tsx @@ -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 ; return ( - - {t("most_cancelled_bookings")} + {!isSuccess || !startDate || !endDate || !teamId ? null : } - + ); }; diff --git a/packages/features/insights/components/PopularEventsTable.tsx b/packages/features/insights/components/PopularEventsTable.tsx index 1e4e3b3546..6c23dbf041 100644 --- a/packages/features/insights/components/PopularEventsTable.tsx +++ b/packages/features/insights/components/PopularEventsTable.tsx @@ -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 ( - - {t("popular_events")} - - - {data.map( - (item) => - item.eventTypeId && ( - - {item.eventTypeName} - - - {item.count} - - - - ) - )} - -
+ +
+ {data + .filter((item) => item.eventTypeId) + .map((item) => ( + +
+
+

{item.eventTypeName}

+
+ + ))} +
{data.length === 0 && (

{t("insights_no_data_found_for_filter")}

)} - + ); }; diff --git a/packages/features/insights/components/RecentFeedbackTable.tsx b/packages/features/insights/components/RecentFeedbackTable.tsx index 0c5c0c1282..e72b49eaa8 100644 --- a/packages/features/insights/components/RecentFeedbackTable.tsx +++ b/packages/features/insights/components/RecentFeedbackTable.tsx @@ -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 ( - - {t("recent_ratings")} + - + ); }; diff --git a/packages/features/insights/components/TotalBookingUsersTable.tsx b/packages/features/insights/components/TotalBookingUsersTable.tsx index cae9ceeb81..0f9d1f9db1 100644 --- a/packages/features/insights/components/TotalBookingUsersTable.tsx +++ b/packages/features/insights/components/TotalBookingUsersTable.tsx @@ -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 ( - - - <> - {filteredData.length > 0 ? ( - filteredData.map((item) => ( - - - -

- {item.user.name} -

-
- - - {item.count} - - -
- )) - ) : ( - - No members found - - )} - -
-
+
+ {filteredData.length > 0 ? ( + filteredData.map((item) => ( + +
+ +
{item.user.name}
+
+
+ )) + ) : ( +
+

No members found

+
+ )} +
); }; diff --git a/packages/features/insights/components/TotalUserFeedbackTable.tsx b/packages/features/insights/components/TotalUserFeedbackTable.tsx index 91cebecceb..4559e3982c 100644 --- a/packages/features/insights/components/TotalUserFeedbackTable.tsx +++ b/packages/features/insights/components/TotalUserFeedbackTable.tsx @@ -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 ( - - - <> - {data && - data?.length > 0 && - data?.map((item) => ( - - - -

- {item.user.name} -

-
- - - - {item.averageRating ? item.averageRating.toFixed(1) : item.count} - - - -
- ))} - -
-
+
+ {data && data?.length > 0 ? ( + data?.map((item) => ( + +
+ +
{item.user.name}
+
+
+ )) + ) : ( +
+

No data found

+
+ )} +
); };