Skip to content

Commit 10fca86

Browse files
feat: add drop off funnel chart for /insights/routing (calcom#22106)
* feat: add Drop-off funnel chart for /insights/routing * convert insights services to use kysely * WIP * implement drop-off data WIP * updates * revert services back to Prisma * do not expose findMany * WIP * revert usage * fix type errors * updates * clean up * update playground * update styles * support columnFilters * update tooltip * add skeleton * remove dynamic loading * avoid using Prisma.raw * update condition for user scope * Update packages/features/insights/components/RoutingFunnelContent.tsx Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> * playground fix * fix type error * update playground * update styles * implement subtitle to ChartCard * revert insights booking service * update border * update ChartCard style * style updates * convert the playground to a client component * clean up * apply feedback * fix tests * fix unit test * hide scrollbar --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
1 parent c2fc877 commit 10fca86

24 files changed

Lines changed: 2189 additions & 243 deletions

File tree

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
"use client";
2+
3+
import Link from "next/link";
4+
import { usePathname } from "next/navigation";
5+
6+
export default function PlaygroundLayout({ children }: { children: React.ReactNode }) {
7+
const pathname = usePathname();
8+
9+
const isPlaygroundRoot = pathname === "/settings/admin/playground";
10+
11+
return isPlaygroundRoot ? (
12+
children
13+
) : (
14+
<div>
15+
<Link href="/settings/admin/playground" className="text-sm underline">
16+
← Playground
17+
</Link>
18+
<div className="h-8" />
19+
<div>{children}</div>
20+
</div>
21+
);
22+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import Link from "next/link";
2+
3+
const LINKS = [
4+
{
5+
title: "Routing Funnel",
6+
href: "/settings/admin/playground/routing-funnel",
7+
},
8+
];
9+
10+
export default function Page() {
11+
return (
12+
<div>
13+
<h1 className="text-3xl font-bold">Playground</h1>
14+
15+
<ul className="mt-8">
16+
{LINKS.map((link) => (
17+
<li key={link.title}>
18+
<Link href={link.href} className="list-item list-disc font-medium underline">
19+
{link.title}
20+
</Link>
21+
</li>
22+
))}
23+
</ul>
24+
</div>
25+
);
26+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
"use client";
2+
3+
import { ChartCard } from "@calcom/features/insights/components/ChartCard";
4+
import { RoutingFunnelContent, legend } from "@calcom/features/insights/components/RoutingFunnelContent";
5+
import { useLocale } from "@calcom/lib/hooks/useLocale";
6+
7+
// Random sample data for playground testing
8+
const sampleRoutingFunnelData = [
9+
{
10+
name: "Week 1",
11+
formattedDateFull: "Week 1",
12+
totalSubmissions: 150,
13+
successfulRoutings: 120,
14+
acceptedBookings: 95,
15+
},
16+
{
17+
name: "Week 2",
18+
formattedDateFull: "Week 2",
19+
totalSubmissions: 180,
20+
successfulRoutings: 145,
21+
acceptedBookings: 110,
22+
},
23+
{
24+
name: "Week 3",
25+
formattedDateFull: "Week 3",
26+
totalSubmissions: 200,
27+
successfulRoutings: 160,
28+
acceptedBookings: 125,
29+
},
30+
{
31+
name: "Week 4",
32+
formattedDateFull: "Week 4",
33+
totalSubmissions: 170,
34+
successfulRoutings: 135,
35+
acceptedBookings: 105,
36+
},
37+
{
38+
name: "Week 5",
39+
formattedDateFull: "Week 5",
40+
totalSubmissions: 220,
41+
successfulRoutings: 175,
42+
acceptedBookings: 140,
43+
},
44+
{
45+
name: "Week 6",
46+
formattedDateFull: "Week 6",
47+
totalSubmissions: 190,
48+
successfulRoutings: 155,
49+
acceptedBookings: 120,
50+
},
51+
];
52+
53+
export default function RoutingFunnelPlayground() {
54+
const { t } = useLocale();
55+
return (
56+
<div className="space-y-6 p-6">
57+
<div className="mb-6">
58+
<h1 className="text-3xl font-bold">Routing Funnel Playground</h1>
59+
<p className="mt-2 text-gray-600">
60+
This page demonstrates the RoutingFunnelContent component with sample data.
61+
</p>
62+
</div>
63+
64+
<div className="max-w-4xl">
65+
<ChartCard
66+
title={t("routing_funnel")}
67+
subtitle="Hello world!"
68+
legend={legend}
69+
legendSize="sm"
70+
cta={{
71+
label: "Show all",
72+
onClick: () => {
73+
alert("hello!");
74+
},
75+
}}>
76+
<RoutingFunnelContent data={sampleRoutingFunnelData} />
77+
</ChartCard>
78+
</div>
79+
80+
<div className="mt-8 rounded-lg bg-gray-50 p-4">
81+
<h2 className="mb-2 text-lg font-semibold">Sample Data Used:</h2>
82+
<pre className="overflow-auto text-sm text-gray-700">
83+
{JSON.stringify(sampleRoutingFunnelData, null, 2)}
84+
</pre>
85+
</div>
86+
</div>
87+
);
88+
}

apps/web/app/(use-page-wrapper)/settings/(settings-layout)/SettingsLayoutAppDirClient.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ const getTabs = (orgBranding: OrganizationBranding | null) => {
147147
{ name: "lockedSMS", href: "/settings/admin/lockedSMS" },
148148
{ name: "oAuth", href: "/settings/admin/oAuth" },
149149
{ name: "Workspace Platforms", href: "/settings/admin/workspace-platforms" },
150+
{ name: "Playground", href: "/settings/admin/playground" },
150151
],
151152
},
152153
];

apps/web/modules/insights/insights-routing-view.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
RoutingFormResponsesTable,
77
FailedBookingsByField,
88
RoutedToPerPeriod,
9+
RoutingFunnel,
910
} from "@calcom/features/insights/components";
1011
import { InsightsOrgTeamsProvider } from "@calcom/features/insights/context/InsightsOrgTeamsProvider";
1112
import { useLocale } from "@calcom/lib/hooks/useLocale";
@@ -19,9 +20,12 @@ export default function InsightsRoutingFormResponsesPage() {
1920
<div className="mb-4 space-y-4">
2021
<RoutingFormResponsesTable />
2122

22-
<RoutedToPerPeriod />
23+
<RoutingFunnel />
2324

24-
<FailedBookingsByField />
25+
<div className="flex flex-col gap-4 md:flex-row">
26+
<RoutedToPerPeriod />
27+
<FailedBookingsByField />
28+
</div>
2529

2630
<small className="text-default block text-center">
2731
{t("looking_for_more_insights")}{" "}

apps/web/public/static/locales/en/common.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
"you_can_view_booking_details_with_this_url": "You can view the booking details from this url {{url}} and add the event to your calendar",
7777
"no_options_available": "No options available",
7878
"cancellation_reason": "Reason for cancellation (optional)",
79-
"cancelled_by":"Cancelled By",
79+
"cancelled_by": "Cancelled By",
8080
"cancellation_reason_host": "Reason for cancellation",
8181
"cancellation_reason_placeholder": "Why are you cancelling?",
8282
"notify_attendee_cancellation_reason_warning": "Cancellation reason will be shared with guests",
@@ -285,7 +285,7 @@
285285
"guests": "Guests",
286286
"guest": "Guest",
287287
"web_conferencing_details_to_follow": "Web conferencing details to follow in the confirmation email.",
288-
"confirmation":"Confirmation",
288+
"confirmation": "Confirmation",
289289
"what_booker_should_provide": "What your booker should provide to receive confirmations",
290290
"404_the_user": "The username",
291291
"username": "Username",
@@ -3349,6 +3349,10 @@
33493349
"booking_not_allowed_by_restriction_schedule_error": "Booking outside restriction schedule availability.",
33503350
"restriction_schedule_not_found_error": "Restriction schedule not found",
33513351
"converted_image_size_limit_exceed": "Image size limit exceeded, please use a smaller image preferably in JPEG format",
3352+
"routing_funnel": "Routing Funnel",
3353+
"routing_funnel_total_submissions": "Total Submissions",
3354+
"routing_funnel_successful_routings": "Successful Routings",
3355+
"routing_funnel_accepted_bookings": "Accepted Bookings",
33523356
"license_key": "License key",
33533357
"license_selection_title": "Choose your license",
33543358
"license_selection_description": "Select how you want to license your Cal.com deployment",
@@ -3367,6 +3371,7 @@
33673371
"license_validation_failed": "Failed to validate license key",
33683372
"license_key_saved": "License key saved successfully",
33693373
"timezone_mismatch_tooltip": "You are viewing the report based on your profile timezone ({{userTimezone}}), while your browser is set to timezone ({{browserTimezone}})",
3374+
"failed_bookings_by_field": "Failed Bookings By Field",
33703375
"event_type_no_hosts": "No hosts are assigned to event type",
33713376
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
33723377
}

0 commit comments

Comments
 (0)