@@ -20,26 +20,26 @@ UI Component → tRPC Handler → Insights Service → Database Query → Respon
2020 ``` typescript
2121 // packages/features/insights/components/booking/MyNewChart.tsx
2222 import { LineChart , XAxis , YAxis , CartesianGrid , Tooltip , Line , ResponsiveContainer } from " recharts" ;
23-
23+
2424 import { useLocale } from " @calcom/lib/hooks/useLocale" ;
2525 import { trpc } from " @calcom/trpc" ;
26-
26+
2727 import { useInsightsBookingParameters } from " ../../hooks/useInsightsBookingParameters" ;
2828 import { ChartCard } from " ../ChartCard" ;
2929 import { LoadingInsight } from " ../LoadingInsights" ;
30-
30+
3131 export const MyNewChart = () => {
3232 const { t } = useLocale ();
3333 const insightsBookingParams = useInsightsBookingParameters ();
34-
34+
3535 const { data, isSuccess, isPending } = trpc .viewer .insights .myNewChartData .useQuery (insightsBookingParams , {
3636 staleTime: 180000 , // 3 minutes
3737 refetchOnWindowFocus: false ,
3838 trpc: { context: { skipBatch: true } },
3939 });
40-
40+
4141 if (isPending ) return <LoadingInsight />;
42-
42+
4343 return (
4444 < ChartCard title = {t(" my_new_chart_title" )}>
4545 {isSuccess && data ?.length > 0 ? (
@@ -66,7 +66,7 @@ UI Component → tRPC Handler → Insights Service → Database Query → Respon
6666
6767 <Step title = " Add Component to Barrel Export" >
6868 Update the booking components index file:
69-
69+
7070 ``` typescript
7171 // packages/features/insights/components/booking/index.ts
7272 export { AverageEventDurationChart } from " ./AverageEventDurationChart" ;
@@ -76,55 +76,55 @@ UI Component → tRPC Handler → Insights Service → Database Query → Respon
7676 ```
7777 </Step >
7878 <Step title = " Add Component to Insights View" >
79-
79+
8080 Add your component to the main insights page:
81-
81+
8282 ``` typescript
8383 // apps/web/modules/insights/insights-view.tsx
8484 import {
8585 AverageEventDurationChart ,
8686 BookingKPICards , // ... existing imports
8787 MyNewChart , // Add this import
8888 } from " @calcom/features/insights/components/booking" ;
89-
89+
9090 export default function InsightsPage() {
9191 // ... existing code
92-
92+
9393 return (
9494 < div className = " space-y-6" >
9595 {/* Existing components */ }
9696 < BookingKPICards / >
9797 < EventTrendsChart / >
98-
98+
9999 {/* Add your new chart */ }
100100 < MyNewChart / >
101-
101+
102102 {/* Other existing components */ }
103103 < / div >
104104 );
105105 }
106106 ```
107- </Step >
107+ </Step >
108108 <Step title = " Create tRPC Handler" >
109109
110110 Add the tRPC endpoint in the insights router using the ` getInsightsBookingService() ` DI container function:
111-
111+
112112 ``` typescript
113113 // packages/features/insights/server/trpc-router.ts
114114 import { bookingRepositoryBaseInputSchema } from " @calcom/features/insights/server/raw-data.schema" ;
115115 import { userBelongsToTeamProcedure } from " @calcom/trpc/server/procedures/authedProcedure" ;
116-
116+
117117 import { TRPCError } from " @trpc/server" ;
118-
118+
119119 export const insightsRouter = router ({
120120 // ... existing procedures
121-
121+
122122 myNewChartData: userBelongsToTeamProcedure
123123 .input (bookingRepositoryBaseInputSchema )
124124 .query (async ({ ctx , input }) => {
125125 // `createInsightsBookingService` is defined at the root level in this file
126126 const insightsBookingService = createInsightsBookingService (ctx , input );
127-
127+
128128 try {
129129 return await insightsBookingService .getMyNewChartData ();
130130 } catch (e ) {
@@ -134,24 +134,21 @@ UI Component → tRPC Handler → Insights Service → Database Query → Respon
134134 });
135135 ```
136136 </Step >
137- <Step title = " Add Service Method to InsightsBookingBaseService" >
137+ <Step title = " Add Service Method to InsightsBookingBaseService" >
138138 Add your new method to the ` InsightsBookingBaseService ` class:
139-
139+
140140 ``` typescript
141141 // packages/lib/server/service/InsightsBookingBaseService.ts
142142 export class InsightsBookingBaseService {
143143 // ... existing methods
144-
144+
145145 async getMyNewChartData() {
146146 const baseConditions = await this .getBaseConditions ();
147-
147+
148148 // Example: Get booking counts by day using raw SQL for performance
149- const data = await this .prisma .$queryRaw <
150- Array<{
151- date : Date ;
152- bookingsCount : number ;
153- }>
154- >`
149+ // Note: Use Prisma.sql for the entire query (Prisma v6 requirement)
150+ // Prisma v6 no longer allows mixing template literals with Prisma.sql fragments
151+ const query = Prisma .sql `
155152 SELECT
156153 DATE("createdAt") as date,
157154 COUNT(*)::int as "bookingsCount"
@@ -160,7 +157,14 @@ UI Component → tRPC Handler → Insights Service → Database Query → Respon
160157 GROUP BY DATE("createdAt")
161158 ORDER BY date ASC
162159 ` ;
163-
160+
161+ const data = await this .prisma .$queryRaw <
162+ Array <{
163+ date: Date ;
164+ bookingsCount: number ;
165+ }>
166+ > (query );
167+
164168 // Transform the data for the chart
165169 return data .map ((item ) => ({
166170 date: item .date .toISOString ().split (" T" )[0 ], // Format as YYYY-MM-DD
@@ -170,6 +174,7 @@ UI Component → tRPC Handler → Insights Service → Database Query → Respon
170174 }
171175 ```
172176 </Step >
177+
173178</Steps >
174179
175180## Best Practices
@@ -179,5 +184,6 @@ UI Component → tRPC Handler → Insights Service → Database Query → Respon
1791843 . ** Base Conditions** : Always use ` await this.getBaseConditions() ` for proper filtering and permissions
1801854 . ** Error Handling** : Wrap service calls in try-catch blocks with ` TRPCError `
1811865 . ** Loading States** : Always show loading indicators with ` LoadingInsight `
182- 6 . ** Consistent Styling** : Use ` recharts ` for new charts.
187+ 6 . ** Consistent Styling** : Use ` recharts ` for new charts
1831887 . ** Date Handling** : Use ` getDateRanges() ` and ` getTimeView() ` for time-based charts
189+ 8 . ** Prisma v6 Compatibility** : Use ` Prisma.sql ` for the entire query instead of mixing template literals with SQL fragments
0 commit comments