|
1 | 1 | import "server-only"; |
2 | 2 |
|
3 | 3 | import { NextRequest, NextResponse } from "next/server"; |
4 | | -import { BetaAnalyticsDataClient } from "@google-analytics/data"; |
| 4 | +import { BetaAnalyticsDataClient, protos } from "@google-analytics/data"; |
| 5 | + |
| 6 | +type IFilterExpression = protos.google.analytics.data.v1beta.IFilterExpression; |
| 7 | +type IRunReportResponse = protos.google.analytics.data.v1beta.IRunReportResponse; |
5 | 8 | // import serviceAccount from "../../../../utils/service-account"; |
6 | 9 | interface ServiceAccountConfig { |
7 | 10 | type?: string; |
@@ -160,13 +163,6 @@ export async function GET(request: NextRequest) { |
160 | 163 | const startDateParam = searchParams.get("startDate"); |
161 | 164 | const endDateParam = searchParams.get("endDate"); |
162 | 165 |
|
163 | | - if (!pagePath) { |
164 | | - return NextResponse.json( |
165 | | - { error: "Query parameter 'path' is required" }, |
166 | | - { status: 400 } |
167 | | - ); |
168 | | - } |
169 | | - |
170 | 166 | const dateRegex = /^\d{4}-\d{2}-\d{2}$/; |
171 | 167 | let startDate: string; |
172 | 168 | let endDate: string; |
@@ -196,48 +192,60 @@ export async function GET(request: NextRequest) { |
196 | 192 | endDate = end; |
197 | 193 | } |
198 | 194 |
|
| 195 | + // Build dimension filter: |
| 196 | + // - If pagePath is provided: filter by BOTH pagePath AND eventName=page_view |
| 197 | + // - If no pagePath: filter only by eventName=page_view (returns total across all pages) |
| 198 | + const dimensionFilter: IFilterExpression = pagePath |
| 199 | + ? { |
| 200 | + andGroup: { |
| 201 | + expressions: [ |
| 202 | + { |
| 203 | + filter: { |
| 204 | + fieldName: "pagePath", |
| 205 | + stringFilter: { matchType: "EXACT" as const, value: pagePath }, |
| 206 | + }, |
| 207 | + }, |
| 208 | + { |
| 209 | + filter: { |
| 210 | + fieldName: "eventName", |
| 211 | + stringFilter: { matchType: "EXACT" as const, value: "page_view" }, |
| 212 | + }, |
| 213 | + }, |
| 214 | + ], |
| 215 | + }, |
| 216 | + } |
| 217 | + : { |
| 218 | + filter: { |
| 219 | + fieldName: "eventName", |
| 220 | + stringFilter: { matchType: "EXACT" as const, value: "page_view" }, |
| 221 | + }, |
| 222 | + }; |
| 223 | + |
199 | 224 | const analyticsDataClient = getAnalyticsClient(); |
200 | | - const [report] = await analyticsDataClient.runReport({ |
| 225 | + const reportResponse = await analyticsDataClient.runReport({ |
201 | 226 | property: `properties/${PROPERTY_ID}`, |
202 | | - //dimensions: [{ name: "pagePath" }], |
203 | | - dimensions: [ |
204 | | - { name: "pagePath" }, |
205 | | - { name: "eventName" }, |
206 | | - ], |
207 | | - // metrics: [{ name: "screenPageViews" }], |
208 | | - metrics: [{ name: "eventCount" }], |
209 | | - |
210 | | -dimensionFilter: { |
211 | | - andGroup: { |
212 | | - expressions: [ |
213 | | - { |
214 | | - filter: { |
215 | | - fieldName: "pagePath", |
216 | | - stringFilter: { matchType: "EXACT", value: pagePath }, |
217 | | - }, |
218 | | - }, |
219 | | - { |
220 | | - filter: { |
221 | | - fieldName: "eventName", |
222 | | - stringFilter: { matchType: "EXACT", value: "page_view" }, |
223 | | - }, |
224 | | - }, |
225 | | - ], |
226 | | - }, |
227 | | -}, |
228 | | - |
229 | | - // dimensionFilter: { |
230 | | - // filter: { |
231 | | - // fieldName: "pagePath", |
232 | | - // stringFilter: { matchType: "EXACT", value: pagePath }, |
233 | | - // }, |
234 | | - // }, |
| 227 | + dimensions: pagePath |
| 228 | + ? [{ name: "pagePath" }, { name: "eventName" }] |
| 229 | + : [{ name: "eventName" }], |
| 230 | + metrics: [{ name: "eventCount" }], |
| 231 | + dimensionFilter, |
235 | 232 | dateRanges: [{ startDate, endDate }], |
236 | | - limit: 1, |
| 233 | + limit: pagePath ? 1 : undefined, |
237 | 234 | }); |
| 235 | + const report = (reportResponse as unknown as [IRunReportResponse])[0]; |
238 | 236 |
|
239 | | - const rawValue = report.rows?.[0]?.metricValues?.[0]?.value ?? "0"; |
240 | | - const pageViews = Number.parseInt(rawValue, 10) || 0; |
| 237 | + // When pagePath is provided, take the single matched row. |
| 238 | + // When no pagePath, sum all rows to get the total page_view count across all pages. |
| 239 | + let pageViews: number; |
| 240 | + if (pagePath) { |
| 241 | + const rawValue = report.rows?.[0]?.metricValues?.[0]?.value ?? "0"; |
| 242 | + pageViews = Number.parseInt(rawValue, 10) || 0; |
| 243 | + } else { |
| 244 | + pageViews = (report.rows ?? []).reduce((sum: number, row: protos.google.analytics.data.v1beta.IRow) => { |
| 245 | + const val = Number.parseInt(row.metricValues?.[0]?.value ?? "0", 10) || 0; |
| 246 | + return sum + val; |
| 247 | + }, 0); |
| 248 | + } |
241 | 249 |
|
242 | 250 | return NextResponse.json({ pageViews }); |
243 | 251 | } catch (error) { |
|
0 commit comments