-
Notifications
You must be signed in to change notification settings - Fork 11.6k
feat: add Recent No-Show Guests chart to insights page #23381
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- 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: [email protected] <[email protected]>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
WalkthroughAdds a new RecentNoShowGuestsChart component (UI + data fetching) and integrates it into the Insights page layout, relocating PopularEventsTable to a separate grid section. Introduces a tRPC endpoint Possibly related PRs
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
Status, Documentation and Community
|
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
- 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: [email protected] <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Nitpick comments (2)
packages/lib/server/service/InsightsBookingBaseService.ts (1)
1125-1175: Indexing advice to keep CTE fast on large datasets.
Ensure indexes exist: Attendee(bookingId), Attendee(bookingId, noShow), BookingTimeStatusDenormalized(id), BookingTimeStatusDenormalized(status), BookingTimeStatusDenormalized(startTime/createdAt). This query groups by booking and double-joins Attendee.packages/features/insights/components/booking/RecentNoShowGuestsChart.tsx (1)
29-32: Prefer explicit error/empty states over returning nullReturning null hides failures. Consider showing a lightweight error placeholder consistent with other insights widgets.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (8)
apps/web/modules/insights/insights-view.tsx(3 hunks)apps/web/public/static/locales/en/common.json(1 hunks)packages/features/insights/components/ChartCard.tsx(2 hunks)packages/features/insights/components/booking/RecentNoShowGuestsChart.tsx(1 hunks)packages/features/insights/components/booking/index.ts(1 hunks)packages/features/insights/server/trpc-router.ts(1 hunks)packages/lib/server/service/InsightsBookingBaseService.ts(1 hunks)packages/ui/components/card/PanelCard.tsx(1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Always use
t()for text localization in frontend code; direct text embedding should trigger a warning
Files:
packages/features/insights/components/booking/RecentNoShowGuestsChart.tsxpackages/ui/components/card/PanelCard.tsxapps/web/modules/insights/insights-view.tsxpackages/features/insights/components/ChartCard.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js
.utc()in hot paths like loops
Files:
packages/features/insights/components/booking/RecentNoShowGuestsChart.tsxpackages/ui/components/card/PanelCard.tsxpackages/features/insights/server/trpc-router.tspackages/features/insights/components/booking/index.tspackages/lib/server/service/InsightsBookingBaseService.tsapps/web/modules/insights/insights-view.tsxpackages/features/insights/components/ChartCard.tsx
**/*.{ts,tsx,js,jsx}
⚙️ CodeRabbit configuration file
Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.
Files:
packages/features/insights/components/booking/RecentNoShowGuestsChart.tsxpackages/ui/components/card/PanelCard.tsxpackages/features/insights/server/trpc-router.tspackages/features/insights/components/booking/index.tspackages/lib/server/service/InsightsBookingBaseService.tsapps/web/modules/insights/insights-view.tsxpackages/features/insights/components/ChartCard.tsx
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
**/*.ts: For Prisma queries, only select data you need; never useinclude, always useselect
Ensure thecredential.keyfield is never returned from tRPC endpoints or APIs
Files:
packages/features/insights/server/trpc-router.tspackages/features/insights/components/booking/index.tspackages/lib/server/service/InsightsBookingBaseService.ts
**/*Service.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Service files must include
Servicesuffix, use PascalCase matching exported class, and avoid generic names (e.g.,MembershipService.ts)
Files:
packages/lib/server/service/InsightsBookingBaseService.ts
🧠 Learnings (4)
📚 Learning: 2025-08-12T08:53:11.848Z
Learnt from: supalarry
PR: calcom/cal.com#22976
File: packages/ui/components/app-list-card/AppListCard.tsx:63-67
Timestamp: 2025-08-12T08:53:11.848Z
Learning: In AppListCard.tsx, the className || classNameObject?.container fallback pattern is intentional to encourage users to migrate from the legacy className prop to the new granular classNameObject styling system, rather than merging both approaches.
Applied to files:
packages/ui/components/card/PanelCard.tsxpackages/features/insights/components/ChartCard.tsx
📚 Learning: 2025-08-26T08:08:23.395Z
Learnt from: SinghaAnirban005
PR: calcom/cal.com#23343
File: packages/features/insights/server/trpc-router.ts:1080-1101
Timestamp: 2025-08-26T08:08:23.395Z
Learning: In packages/features/insights/server/trpc-router.ts, when filtering personal event types (userId provided, no teamId, not isAll), the query correctly uses user.id (authenticated user) instead of the input userId parameter for security reasons. This prevents users from accessing other users' personal event types by passing arbitrary user IDs.
Applied to files:
packages/features/insights/server/trpc-router.ts
📚 Learning: 2025-08-21T13:44:06.805Z
Learnt from: supalarry
PR: calcom/cal.com#23217
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts:93-94
Timestamp: 2025-08-21T13:44:06.805Z
Learning: In apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts, repository functions that use explicit Prisma select clauses (like getEventTypeWithSeats) are used for specific purposes and don't need to include all EventType fields like bookingRequiresAuthentication. These methods don't feed into the general OutputEventTypesService_2024_06_14 flow.
Applied to files:
packages/features/insights/server/trpc-router.ts
📚 Learning: 2025-08-22T16:38:00.225Z
Learnt from: bandhan-majumder
PR: calcom/cal.com#23192
File: packages/lib/server/service/InsightsBookingBaseService.ts:814-816
Timestamp: 2025-08-22T16:38:00.225Z
Learning: In the InsightsBookingBaseService (packages/lib/server/service/InsightsBookingBaseService.ts), when filtering for "accepted" bookings in getMembersStatsWithCount(), using `endTime <= now()` in the SQL condition should be avoided as it conflicts with existing date filtering logic. The components already handle completion filtering by setting `endDate: currentTime` in their query parameters, making additional SQL-level endTime filtering unnecessary and potentially problematic.
Applied to files:
packages/lib/server/service/InsightsBookingBaseService.ts
🧬 Code graph analysis (5)
packages/features/insights/components/booking/RecentNoShowGuestsChart.tsx (3)
packages/features/insights/hooks/useInsightsBookingParameters.ts (1)
useInsightsBookingParameters(14-46)apps/web/app/_trpc/trpc.ts (1)
trpc(7-7)packages/features/insights/components/ChartCard.tsx (2)
ChartCard(16-48)ChartCardItem(50-69)
packages/ui/components/card/PanelCard.tsx (2)
packages/ui/components/card/index.ts (1)
PanelCard(5-5)packages/ui/components/badge/index.ts (1)
InfoBadge(5-5)
packages/features/insights/server/trpc-router.ts (1)
packages/features/insights/server/raw-data.schema.ts (1)
bookingRepositoryBaseInputSchema(92-99)
apps/web/modules/insights/insights-view.tsx (3)
packages/features/insights/components/booking/RecentNoShowGuestsChart.tsx (1)
RecentNoShowGuestsChart(13-75)packages/features/insights/components/booking/index.ts (2)
RecentNoShowGuestsChart(12-12)PopularEventsTable(11-11)packages/features/insights/components/booking/PopularEventsTable.tsx (1)
PopularEventsTable(10-47)
packages/features/insights/components/ChartCard.tsx (1)
packages/ui/components/card/PanelCard.tsx (1)
PanelCard(7-58)
🔇 Additional comments (9)
apps/web/public/static/locales/en/common.json (1)
3276-3277: LGTM: keys and copy read well and follow existing tone.
No issues with punctuation or casing; usage aligns with the new chart.packages/ui/components/card/PanelCard.tsx (1)
3-5: LGTM: prop extensions and tooltip rendering look solid.
- className merged safely via classNames.
- titleTooltip integrates cleanly with InfoBadge.
No accessibility or layout concerns from this change.Also applies to: 12-22, 25-36
packages/features/insights/components/booking/index.ts (1)
12-12: LGTM: export added for RecentNoShowGuestsChart.
Keeps barrel up to date.apps/web/modules/insights/insights-view.tsx (1)
98-99: Layout update reads well; grid balance preserved.
RecentNoShowGuestsChart placement and PopularEventsTable relocation are consistent with the page’s structure.Also applies to: 110-114
packages/features/insights/server/trpc-router.ts (1)
1054-1064: Good: endpoint follows membership-guard patternUsing userBelongsToTeamProcedure with bookingRepositoryBaseInputSchema aligns with the security pattern we learned for insights endpoints.
packages/features/insights/components/ChartCard.tsx (2)
16-33: Prop pass-through (className, titleTooltip) looks correctProps are typed, threaded to PanelCard, and backward-compatible.
Also applies to: 38-45
65-65: Minor layout improvement LGTMAdding grow to the left container helps truncation/alignment in rows.
packages/features/insights/components/booking/RecentNoShowGuestsChart.tsx (2)
40-42: Good i18n usageTitle and tooltip are localized via t() and match the new keys.
18-27: MaintainskipBatch: truefor consistency
skipBatch: trueis applied across all Insights and related queries—dropping it here alone would introduce inconsistency. RemoveskipBatchas part of a coordinated, global change rather than this single query.Likely an incorrect or invalid review comment.
packages/features/insights/components/booking/RecentNoShowGuestsChart.tsx
Outdated
Show resolved
Hide resolved
packages/features/insights/components/booking/RecentNoShowGuestsChart.tsx
Show resolved
Hide resolved
…alcom/cal.com into devin/recent-no-show-guests-1756284064
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (4)
packages/lib/server/service/InsightsBookingBaseService.ts (1)
1146-1149: Good: restricted to accepted bookings.Filtering with b.status = 'accepted' prevents cancelled/rescheduled noise. This matches prior feedback.
packages/features/insights/server/trpc-router.ts (1)
1057-1057: Correct: anchor “recent” to startTime.Passing "startTime" into createInsightsBookingService aligns the date window with meeting time, not creation time.
packages/features/insights/components/booking/RecentNoShowGuestsChart.tsx (2)
55-59: Timezone-aware formatting: ✅Using Intl.DateTimeFormat with the selected timeZone is correct.
13-18: “Copied” state leaks across rows; scope it per booking.Use per-item copied state instead of a single isCopied boolean.
Apply:
"use client"; +import { useState } from "react"; import { useCopy } from "@calcom/lib/hooks/useCopy"; @@ export const RecentNoShowGuestsChart = () => { const { t } = useLocale(); - const { copyToClipboard, isCopied } = useCopy(); + const { copyToClipboard } = useCopy(); + const [copiedBookingId, setCopiedBookingId] = useState<number | null>(null); const insightsBookingParams = useInsightsBookingParameters(); const timeZone = insightsBookingParams.timeZone;And:
- const handleCopyEmail = (email: string) => { - copyToClipboard(email); - showToast(t("email_copied"), "success"); - }; + const handleCopyEmail = (bookingId: number, email: string) => { + copyToClipboard(email); + setCopiedBookingId(bookingId); + showToast(t("email_copied"), "success"); + window.setTimeout(() => setCopiedBookingId(null), 1500); + };And:
- <Button + <Button color="minimal" size="sm" - StartIcon={isCopied ? "clipboard-check" : "clipboard"} - onClick={() => handleCopyEmail(item.guestEmail)}> - {!isCopied ? t("email") : t("copied")} + StartIcon={copiedBookingId === item.bookingId ? "clipboard-check" : "clipboard"} + onClick={() => handleCopyEmail(item.bookingId, item.guestEmail)} + aria-label={t("copy_email")}> + {copiedBookingId === item.bookingId ? t("copied") : t("email")} </Button>
🧹 Nitpick comments (4)
packages/lib/server/service/InsightsBookingBaseService.ts (1)
1137-1149: Consider indexes to keep this CTE fast on large datasets.If not already present, add or verify:
- Attendee: composite index on ("bookingId", "noShow")
- BookingTimeStatusDenormalized: index on ("status"), and on ("startTime") to support date-range + ORDER BY.
packages/features/insights/server/trpc-router.ts (1)
1059-1063: Add minimal error logging for observability.Before throwing TRPCError, log the error with context so failures are traceable.
- try { - return await insightsBookingService.getRecentNoShowGuests(); - } catch (e) { - throw new TRPCError({ code: "INTERNAL_SERVER_ERROR" }); - } + try { + return await insightsBookingService.getRecentNoShowGuests(); + } catch (e) { + ctx.logger?.error?.({ err: e }, "recentNoShowGuests failed"); + throw new TRPCError({ code: "INTERNAL_SERVER_ERROR" }); + }packages/features/insights/components/booking/RecentNoShowGuestsChart.tsx (2)
51-54: Fallback when guestName is empty.Guard against blank names so the UI remains informative.
- <p className="text-sm font-medium">{item.guestName}</p> + <p className="text-sm font-medium">{item.guestName || item.guestEmail}</p>
64-71: Disable copy for missing emails and add accessible label.Avoid showing an enabled copy action when email is absent; improve a11y.
- <Button + <Button color="minimal" size="sm" StartIcon={copiedBookingId === item.bookingId ? "clipboard-check" : "clipboard"} - onClick={() => handleCopyEmail(item.bookingId, item.guestEmail)} - aria-label={t("copy_email")}> + onClick={() => handleCopyEmail(item.bookingId, item.guestEmail)} + aria-label={t("copy_email")} + disabled={!item.guestEmail}> {copiedBookingId === item.bookingId ? t("copied") : t("email")} </Button>
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (4)
packages/features/insights/components/booking/RecentNoShowGuestsChart.tsx(1 hunks)packages/features/insights/server/trpc-router.ts(1 hunks)packages/lib/server/service/InsightsBookingBaseService.ts(1 hunks)packages/ui/components/card/PanelCard.tsx(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/ui/components/card/PanelCard.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.tsx
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Always use
t()for text localization in frontend code; direct text embedding should trigger a warning
Files:
packages/features/insights/components/booking/RecentNoShowGuestsChart.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js
.utc()in hot paths like loops
Files:
packages/features/insights/components/booking/RecentNoShowGuestsChart.tsxpackages/lib/server/service/InsightsBookingBaseService.tspackages/features/insights/server/trpc-router.ts
**/*.{ts,tsx,js,jsx}
⚙️ CodeRabbit configuration file
Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.
Files:
packages/features/insights/components/booking/RecentNoShowGuestsChart.tsxpackages/lib/server/service/InsightsBookingBaseService.tspackages/features/insights/server/trpc-router.ts
**/*Service.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Service files must include
Servicesuffix, use PascalCase matching exported class, and avoid generic names (e.g.,MembershipService.ts)
Files:
packages/lib/server/service/InsightsBookingBaseService.ts
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
**/*.ts: For Prisma queries, only select data you need; never useinclude, always useselect
Ensure thecredential.keyfield is never returned from tRPC endpoints or APIs
Files:
packages/lib/server/service/InsightsBookingBaseService.tspackages/features/insights/server/trpc-router.ts
🧠 Learnings (4)
📚 Learning: 2025-08-22T16:38:00.225Z
Learnt from: bandhan-majumder
PR: calcom/cal.com#23192
File: packages/lib/server/service/InsightsBookingBaseService.ts:814-816
Timestamp: 2025-08-22T16:38:00.225Z
Learning: In the InsightsBookingBaseService (packages/lib/server/service/InsightsBookingBaseService.ts), when filtering for "accepted" bookings in getMembersStatsWithCount(), using `endTime <= now()` in the SQL condition should be avoided as it conflicts with existing date filtering logic. The components already handle completion filtering by setting `endDate: currentTime` in their query parameters, making additional SQL-level endTime filtering unnecessary and potentially problematic.
Applied to files:
packages/features/insights/components/booking/RecentNoShowGuestsChart.tsxpackages/lib/server/service/InsightsBookingBaseService.tspackages/features/insights/server/trpc-router.ts
📚 Learning: 2025-07-28T11:50:23.946Z
Learnt from: CR
PR: calcom/cal.com#0
File: .cursor/rules/review.mdc:0-0
Timestamp: 2025-07-28T11:50:23.946Z
Learning: Applies to **/*.{ts,tsx} : Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js `.utc()` in hot paths like loops
Applied to files:
packages/features/insights/components/booking/RecentNoShowGuestsChart.tsx
📚 Learning: 2025-08-26T08:08:23.395Z
Learnt from: SinghaAnirban005
PR: calcom/cal.com#23343
File: packages/features/insights/server/trpc-router.ts:1080-1101
Timestamp: 2025-08-26T08:08:23.395Z
Learning: In packages/features/insights/server/trpc-router.ts, when filtering personal event types (userId provided, no teamId, not isAll), the query correctly uses user.id (authenticated user) instead of the input userId parameter for security reasons. This prevents users from accessing other users' personal event types by passing arbitrary user IDs.
Applied to files:
packages/features/insights/server/trpc-router.ts
📚 Learning: 2025-08-21T13:44:06.805Z
Learnt from: supalarry
PR: calcom/cal.com#23217
File: apps/api/v2/src/ee/event-types/event-types_2024_06_14/services/output-event-types.service.ts:93-94
Timestamp: 2025-08-21T13:44:06.805Z
Learning: In apps/api/v2/src/ee/event-types/event-types_2024_06_14/event-types.repository.ts, repository functions that use explicit Prisma select clauses (like getEventTypeWithSeats) are used for specific purposes and don't need to include all EventType fields like bookingRequiresAuthentication. These methods don't feed into the general OutputEventTypesService_2024_06_14 flow.
Applied to files:
packages/features/insights/server/trpc-router.ts
🧬 Code graph analysis (2)
packages/features/insights/components/booking/RecentNoShowGuestsChart.tsx (2)
packages/features/insights/hooks/useInsightsBookingParameters.ts (1)
useInsightsBookingParameters(14-46)packages/features/insights/components/ChartCard.tsx (2)
ChartCard(16-48)ChartCardItem(50-69)
packages/features/insights/server/trpc-router.ts (1)
packages/features/insights/server/raw-data.schema.ts (1)
bookingRepositoryBaseInputSchema(92-99)
hbjORbj
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
beautiful code :D
E2E results are ready! |
What does this PR do?
This PR implements a "Recent No-Show Guests" chart on the
/insightspage that displays bookings where all attendees were no-shows (not partial no-shows). The implementation includes:recentNoShowGuestsendpoint in the insights routergetRecentNoShowGuests()inInsightsBookingBaseServicewith complex SQL queryRecentNoShowGuestsChartdisplaying guest name, booking time, event type, and email copy buttonPanelCardcomponent with question mark iconLink to Devin run: https://app.devin.ai/sessions/e066c52cb93b4ba5a57b0ca5601ced65
Requested by: @eunjae-lee
How should this be tested?
/insightspage (requires authentication)Critical Review Areas
getRecentNoShowGuests()method uses a complex CTE with this key filtering logic:Please verify this correctly identifies bookings where ALL attendees were no-shows.
BookingTimeStatusDenormalizedtable and specific column relationships. Verify these exist in production.Mandatory Tasks (DO NOT REMOVE)
Checklist
Note: Local testing was limited due to authentication issues, but code structure and types have been verified.