Skip to content
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

Fix sendGAEvent function params and type clearly #63226

Open
wants to merge 8 commits into
base: canary
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,11 @@ export function EventButton() {
return (
<div>
<button
onClick={() => sendGAEvent({ event: 'buttonClicked', value: 'xyz' })}
onClick={() =>
sendGAEvent('event-name', {
value: 'xyz',
})
}
>
Send Event
</button>
Expand All @@ -314,7 +318,11 @@ export function EventButton() {
return (
<div>
<button
onClick={() => sendGAEvent({ event: 'buttonClicked', value: 'xyz' })}
onClick={() =>
sendGAEvent('event-name', {
value: 'xyz',
})
}
>
Send Event
</button>
Expand Down
23 changes: 23 additions & 0 deletions packages/third-parties/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,27 @@ export default function Page() {
}
```

### Google Analytics Event

The `sendGAEvent` function can be used to send an event to Google Analytics. This function uses the [gtag.js](https://developers.google.com/analytics/devguides/collection/ga4/events) library under the hood.

```js
import { sendGAEvent } from '@next/third-parties/google'

export default function Page() {
return (
<button
onClick={() => {
// Send an event to Google Analytics
sendGAEvent('event-name', {
value: xyz,
})
}}
>
Click me
</button>
)
}
```

To get a better idea of how these components work, take a look at this [demo](https://test-next-script-housseindjirdeh.vercel.app/). <!--- TODO: Replace with a better demo page -->
19 changes: 16 additions & 3 deletions packages/third-parties/src/google/ga.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
import React, { useEffect } from 'react'
import Script from 'next/script'

import type { GAParams } from '../types/google'
import type {
GAParams,
GARecommendedEventName,
GARecommendedEventParams,
} from '../types/google'

declare global {
interface Window {
Expand Down Expand Up @@ -54,14 +58,23 @@ export function GoogleAnalytics(props: GAParams) {
)
}

export function sendGAEvent(..._args: Object[]) {
export function sendGAEvent<T extends GARecommendedEventName | string>(
eventName: T,
eventParameters: T extends GARecommendedEventName
? GARecommendedEventParams[T]
: { [key: string]: string | number }
) {
if (currDataLayerName === undefined) {
console.warn(`@next/third-parties: GA has not been initialized`)
return
}

if (window[currDataLayerName]) {
window[currDataLayerName].push(arguments)
window[currDataLayerName].push({
0: 'event',
1: eventName,
2: eventParameters,
})
} else {
console.warn(
`@next/third-parties: GA dataLayer ${currDataLayerName} does not exist`
Expand Down
188 changes: 188 additions & 0 deletions packages/third-parties/src/types/google.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,191 @@ export type YouTubeEmbed = {
params?: string
style?: string
}

// https://developers.google.com/tag-platform/gtagjs/reference/events
type GAEventItemParam = {
item_id: string
item_name: string
affiliation?: string
coupon?: string
discount?: number
index?: number
item_brand?: string
item_category?: string
item_category2?: string
item_category3?: string
item_category4?: string
item_category5?: string
item_list_id?: string
item_list_name?: string
item_variant?: string
location_id?: string
price?: number
quantity?: number
[x: string]: any // can add item-scoped custom parameters
}

export type GARecommendedEventParams = {
add_payment_info: {
currency: string
value: number
coupon?: string
payment_type?: string
items: GAEventItemParam[]
}
add_shipping_info: {
currency: string
value: number
coupon?: string
shipping_tier?: string
items: GAEventItemParam[]
}
add_to_cart: {
currency: string
value: number
items: GAEventItemParam[]
}
add_to_wishlist: {
currency: string
value: number
items: GAEventItemParam[]
}
begin_checkout: {
currency: string
value: number
coupon?: string
items: GAEventItemParam[]
}
earn_virtual_currency: {
virtual_currency_name?: string
value?: number
}
exception: {
description?: string
fatal?: boolean
}
generate_lead: {
currency: string
value: number
}
join_group: {
group_id?: string
}
level_end: {
level_name?: string
success?: boolean
}
level_start: {
level_name?: string
}
level_up: {
level?: number
character?: string
}
login: {
method?: string
}
page_view: {
page_location?: string
client_id?: string
language?: string
page_encoding?: string
page_title?: string
user_agent?: string
}
post_score: {
score: number
level?: number
character?: string
}
purchase: {
currency: string
value: number
transaction_id: string
coupon?: string
shipping?: number
tax?: number
items: GAEventItemParam[]
}
refund: {
currency: string
transaction_id: string
value: number
coupon?: string
shipping?: number
tax?: number
items?: GAEventItemParam[]
}
remove_from_cart: {
currency: string
value: number
items: GAEventItemParam[]
}
search: {
search_term: string
}
select_content: {
content_type?: string
content_id?: string
}
select_item: {
item_list_id?: string
item_list_name?: string
// * The items array is expected to have a single element, representing the selected item. If multiple elements are provided, only the first element in items will be used. https://developers.google.com/tag-platform/gtagjs/reference/events#select_item
items: [GAEventItemParam]
}
select_promotion: {
creative_name?: string
creative_slot?: string
promotion_id?: string
promotion_name?: string
items?: GAEventItemParam[]
}
share: {
method?: string
content_type?: string
item_id?: string
}
sign_up: {
method?: string
}
spend_virtual_currency: {
value: number
virtual_currency_name: string
item_name?: string
}
// tutorial begin has no parameters
tutorial_begin: {}
tutorial_complete: {}
unlock_achievement: {
achievement_id: string
}
view_cart: {
currency: string
value: number
items: GAEventItemParam[]
}
view_item: {
currency: string
value: number
items: GAEventItemParam[]
}
view_item_list: {
item_list_id?: string
item_list_name?: string
items: GAEventItemParam[]
}
view_promotion: {
creative_name?: string
creative_slot?: string
promotion_id?: string
promotion_name?: string
// * The items array is expected to have a single element, representing the item associated with the promotion. If multiple elements are provided, only the first element in items will be used. https://developers.google.com/tag-platform/gtagjs/reference/events#view_promotion
items: [GAEventItemParam]
}
view_search_results: {
search_term?: string
}
}

export type GARecommendedEventName = keyof GARecommendedEventParams
Loading