* feat: add Recent No-Show Guests chart to insights page - Add RecentNoShowGuestsChart component with ChartCard wrapper - Add tRPC handler for recentNoShowGuests query - Add getRecentNoShowGuests method to InsightsBookingBaseService - Display guest name, booking time, event type, and copy email button - Filter for bookings where ALL attendees are no-shows - Add translation strings for new UI elements - Integrate chart into insights view grid layout Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * re-order charts * clean up * feat: add optional tooltip functionality to PanelCard - Add titleTooltip prop to PanelCard component with InfoBadge - Pass through titleTooltip prop in ChartCard - Add tooltip to RecentNoShowGuestsChart explaining complete no-show filtering - Add translation string for tooltip explanation Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * style adjustment * update style * address feedback --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
129 lines
4.2 KiB
TypeScript
129 lines
4.2 KiB
TypeScript
"use client";
|
|
|
|
import {
|
|
DataTableProvider,
|
|
DataTableFilters,
|
|
DateRangeFilter,
|
|
ColumnFilterType,
|
|
type FilterableColumn,
|
|
} from "@calcom/features/data-table";
|
|
import { useSegments } from "@calcom/features/data-table/hooks/useSegments";
|
|
import {
|
|
AverageEventDurationChart,
|
|
BookingKPICards,
|
|
BookingsByHourChart,
|
|
EventTrendsChart,
|
|
HighestNoShowHostTable,
|
|
HighestRatedMembersTable,
|
|
LeastBookedTeamMembersTable,
|
|
LowestRatedMembersTable,
|
|
MostBookedTeamMembersTable,
|
|
MostCancelledBookingsTables,
|
|
MostCompletedTeamMembersTable,
|
|
LeastCompletedTeamMembersTable,
|
|
PopularEventsTable,
|
|
RecentNoShowGuestsChart,
|
|
RecentFeedbackTable,
|
|
TimezoneBadge,
|
|
} from "@calcom/features/insights/components/booking";
|
|
import { InsightsOrgTeamsProvider } from "@calcom/features/insights/context/InsightsOrgTeamsProvider";
|
|
import { Download } from "@calcom/features/insights/filters/Download";
|
|
import { OrgTeamsFilter } from "@calcom/features/insights/filters/OrgTeamsFilter";
|
|
import { useInsightsBookings } from "@calcom/features/insights/hooks/useInsightsBookings";
|
|
import { useInsightsOrgTeams } from "@calcom/features/insights/hooks/useInsightsOrgTeams";
|
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
|
|
|
export default function InsightsPage({ timeZone }: { timeZone: string }) {
|
|
return (
|
|
<DataTableProvider useSegments={useSegments} timeZone={timeZone}>
|
|
<InsightsOrgTeamsProvider>
|
|
<InsightsPageContent />
|
|
</InsightsOrgTeamsProvider>
|
|
</DataTableProvider>
|
|
);
|
|
}
|
|
|
|
const createdAtColumn: Extract<FilterableColumn, { type: ColumnFilterType.DATE_RANGE }> = {
|
|
id: "createdAt",
|
|
title: "createdAt",
|
|
type: ColumnFilterType.DATE_RANGE,
|
|
};
|
|
|
|
function InsightsPageContent() {
|
|
const { t } = useLocale();
|
|
const { table } = useInsightsBookings();
|
|
const { isAll, teamId, userId } = useInsightsOrgTeams();
|
|
|
|
return (
|
|
<>
|
|
<div
|
|
className="flex flex-wrap items-center gap-2"
|
|
data-testid={`insights-filters-${isAll}-${teamId}-${userId}`}>
|
|
<OrgTeamsFilter />
|
|
<DataTableFilters.AddFilterButton table={table} hideWhenFilterApplied />
|
|
<DataTableFilters.ActiveFilters table={table} />
|
|
<DataTableFilters.AddFilterButton table={table} variant="sm" showWhenFilterApplied />
|
|
<DataTableFilters.ClearFiltersButton exclude={["createdAt"]} />
|
|
<div className="grow" />
|
|
<Download />
|
|
<DateRangeFilter column={createdAtColumn} />
|
|
<TimezoneBadge />
|
|
</div>
|
|
|
|
<div className="my-4 space-y-4">
|
|
<BookingKPICards />
|
|
|
|
<EventTrendsChart />
|
|
|
|
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-4">
|
|
<div className="sm:col-span-2">
|
|
<BookingsByHourChart />
|
|
</div>
|
|
<div className="sm:col-span-2">
|
|
<AverageEventDurationChart />
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-4">
|
|
<MostBookedTeamMembersTable />
|
|
<LeastBookedTeamMembersTable />
|
|
<MostCompletedTeamMembersTable />
|
|
<LeastCompletedTeamMembersTable />
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-4">
|
|
<MostCancelledBookingsTables />
|
|
<HighestNoShowHostTable />
|
|
<div className="sm:col-span-2">
|
|
<RecentNoShowGuestsChart />
|
|
</div>
|
|
</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>
|
|
|
|
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-4">
|
|
<div className="sm:col-span-2">
|
|
<PopularEventsTable />
|
|
</div>
|
|
</div>
|
|
|
|
<small className="text-default block text-center">
|
|
{t("looking_for_more_insights")}{" "}
|
|
<a
|
|
className="text-blue-500 hover:underline"
|
|
href="mailto:updates@cal.com?subject=Feature%20Request%3A%20More%20Analytics&body=Hey%20Cal.com%20Team%2C%20I%20love%20the%20analytics%20page%20but%20I%20am%20looking%20for%20...">
|
|
{" "}
|
|
{t("contact_support")}
|
|
</a>
|
|
</small>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|