feat: add org-level analytics for cancellation and reschedule reasons#28563
Draft
feat: add org-level analytics for cancellation and reschedule reasons#28563
Conversation
- Add cancellationReason field to BookingDenormalized model - Update BookingTimeStatusDenormalized view to include cancellationReason - Update trigger function to sync cancellationReason from Booking table - Add getCancellationReasonStats() and getRescheduleReasonStats() service methods - Add cancellationReasons and rescheduleReasons tRPC endpoints - Create CancellationReasonsTable and RescheduleReasonsTable UI components - Add components to insights page layout - Add i18n translation strings - Add unit tests for new service methods Closes PRI-423 Co-Authored-By: peer@cal.com <peer@cal.com>
Contributor
🤖 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:
|
PostgreSQL cannot add new columns before existing ones with CREATE OR REPLACE VIEW. Use DROP VIEW + CREATE VIEW instead. Co-Authored-By: peer@cal.com <peer@cal.com>
Contributor
There was a problem hiding this comment.
1 issue found across 10 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/features/insights/services/InsightsBookingBaseService.ts">
<violation number="1" location="packages/features/insights/services/InsightsBookingBaseService.ts:1349">
P2: Whitespace-only cancellation reasons are not filtered out, so analytics can show blank reason rows.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
packages/features/insights/services/InsightsBookingBaseService.ts
Outdated
Show resolved
Hide resolved
Contributor
Devin AI is addressing Cubic AI's review feedbackNew feedback has been sent to the existing Devin session. ✅ Pushed commit |
Use NULLIF(BTRIM(...), '') to exclude whitespace-only reasons from analytics, not just empty strings. Identified by cubic. Co-Authored-By: peer@cal.com <peer@cal.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Adds org-level analytics for cancellation and reschedule reasons to the Insights page, so organization admins can track these metrics across their entire org — not just per-host.
Changes
Database layer:
cancellationReasoncolumn toBookingDenormalizedtableBookingTimeStatusDenormalizedview to expose the new column (PostgreSQL'sCREATE OR REPLACE VIEWcannot add columns before existing ones)Bookingtable and updates the trigger functionService layer:
getCancellationReasonStats()andgetRescheduleReasonStats()toInsightsBookingBaseServicecancellationReasonfrom the denormalized view, distinguished bytimeStatus('cancelled'vs'rescheduled')NULLIF(BTRIM("cancellationReason"), '')to filter out NULL, empty, and whitespace-only reasonsAPI layer:
cancellationReasonsandrescheduleReasonstRPC endpoints behinduserBelongsToTeamProcedureUI layer:
CancellationReasonsTableandRescheduleReasonsTablecomponents using existingChartCard/ChartCardItempatternTests:
Important review notes
Both methods read
cancellationReason— Cal.com stores the reschedule reason in the samecancellationReasonfield on theBookingmodel. ThegetRescheduleReasonStatsmethod distinguishes reschedules by filtering"timeStatus" = 'rescheduled'. Please verify this is the intended data source.Migration drops and recreates the view — The migration uses
DROP VIEW IF EXISTS+CREATE VIEW(notCREATE OR REPLACE VIEW, which can't add columns before existing ones). Please verify the view body matches current production with only thecancellationReasonaddition. Similarly, the trigger function is replaced viaCREATE OR REPLACE FUNCTION— verify its body matches production.bookingDataSchemaupdated — AddedcancellationReason: z.string().nullable()to the strict zod schema. If any existing raw queries return data validated against this schema, they would need to includecancellationReasonin their SELECT or the strict parse will fail.No visual demo — These components were not tested in a running app. They follow the existing
ChartCardpattern used byMostCancelledBookingsTables,HighestNoShowHostTable, etc.Human review checklist
cancellationReasonaddition)cancellationReasonfield onBookingcancellationReasontobookingDataSchema(.strict()) doesn't break existing query consumersVisual Demo (For contributors especially)
N/A — no visual demo available. Components follow the established
ChartCard/ChartCardItempattern.Mandatory Tasks (DO NOT REMOVE)
How should this be tested?
cancellationReasonvaluesTest data needed: Bookings with
cancellationReasonset, some withstatus = 'cancelled'and some that were rescheduled.Checklist
Link to Devin session: https://app.devin.ai/sessions/cca15943320f47ac9ed6b7993910b012
Requested by: @PeerRich