@@ -3,63 +3,156 @@ import { useRegistryScript } from '#nuxt-scripts/utils'
33import type { RegistryScriptInput } from '#nuxt-scripts/types'
44import { object , string , optional } from '#nuxt-scripts-validator'
55
6- type ConsentOptions = 'default' | 'update'
6+ export type GtagCustomParams = Record < string , any >
77
8+ // Consent mode types
9+ export type ConsentStatus = 'granted' | 'denied'
10+
11+ export interface ConsentOptions {
12+ ad_user_data ?: ConsentStatus
13+ ad_personalization ?: ConsentStatus
14+ ad_storage ?: ConsentStatus
15+ analytics_storage ?: ConsentStatus
16+ functionality_storage ?: ConsentStatus
17+ personalization_storage ?: ConsentStatus
18+ security_storage ?: ConsentStatus
19+ wait_for_update ?: number
20+ region ?: string [ ]
21+ }
22+
23+ // Config parameters type
24+ export interface ConfigParams extends GtagCustomParams {
25+ send_page_view ?: boolean
26+ transport_url ?: string
27+ cookie_domain ?: string
28+ cookie_prefix ?: string
29+ cookie_expires ?: number
30+ cookie_update ?: boolean
31+ cookie_flags ?: string
32+ user_id ?: string
33+ }
34+
35+ // Event parameters with common GA4 event parameters
36+ export interface EventParameters extends GtagCustomParams {
37+ value ?: number
38+ currency ?: string
39+ transaction_id ?: string
40+ items ?: Array < {
41+ item_id ?: string
42+ item_name ?: string
43+ item_category ?: string
44+ item_variant ?: string
45+ price ?: number
46+ quantity ?: number
47+ [ key : string ] : any
48+ } >
49+ [ key : string ] : any
50+ }
51+
52+ // Default events in GA4
53+ export type DefaultEventName =
54+ | 'add_payment_info'
55+ | 'add_shipping_info'
56+ | 'add_to_cart'
57+ | 'add_to_wishlist'
58+ | 'begin_checkout'
59+ | 'purchase'
60+ | 'refund'
61+ | 'remove_from_cart'
62+ | 'select_item'
63+ | 'select_promotion'
64+ | 'view_cart'
65+ | 'view_item'
66+ | 'view_item_list'
67+ | 'view_promotion'
68+ | 'login'
69+ | 'sign_up'
70+ | 'search'
71+ | 'page_view'
72+ | 'screen_view'
73+ | string // Allow custom event names
74+
75+ // Define the GTag function interface with proper overloads
876export interface GTag {
9- ( fn : 'js' , opt : Date ) : void
10- ( fn : 'config' | 'get' , opt : string ) : void
11- ( fn : 'event' , opt : string , opt2 ?: Record < string , any > ) : void
12- ( fn : 'set' , opt : Record < string , string > ) : void
13- ( fn : 'consent' , opt : ConsentOptions , opt2 : Record < string , string | number > ) : void
77+ // Initialize gtag.js with timestamp
78+ ( command : 'js' , value : Date ) : void
79+
80+ // Configure a GA4 property
81+ ( command : 'config' , targetId : string , configParams ?: ConfigParams ) : void
82+
83+ // Get a value from gtag
84+ ( command : 'get' , targetId : string , fieldName : string , callback ?: ( field : any ) => void ) : void
85+
86+ // Send an event to GA4
87+ ( command : 'event' , eventName : DefaultEventName , eventParams ?: EventParameters ) : void
88+
89+ // Set default parameters for all subsequent events
90+ ( command : 'set' , params : GtagCustomParams ) : void
91+
92+ // Update consent state
93+ ( command : 'consent' , consentArg : 'default' | 'update' , consentParams : ConsentOptions ) : void
1494}
15- type DataLayer = Array < Parameters < GTag > | Record < string , unknown > >
1695
17- export const GoogleAnalyticsOptions = object ( {
18- id : string ( ) ,
19- l : optional ( string ( ) ) ,
20- } )
96+ // Define the dataLayer array type
97+ export interface DataLayerObject {
98+ event ?: string
99+ [ key : string ] : any
100+ }
21101
22- export type GoogleAnalyticsInput = RegistryScriptInput < typeof GoogleAnalyticsOptions >
102+ export type DataLayer = Array < DataLayerObject >
23103
104+ // Define the complete Google Analytics API interface
24105export interface GoogleAnalyticsApi {
25106 gtag : GTag
26107 dataLayer : DataLayer
27108}
28109
29- export function useScriptGoogleAnalytics < T extends GoogleAnalyticsApi > ( _options ?: GoogleAnalyticsInput ) {
30- return useRegistryScript < T , typeof GoogleAnalyticsOptions > ( _options ?. key || 'googleAnalytics' , options => ( {
31- scriptInput : {
32- src : withQuery ( 'https://www.googletagmanager.com/gtag/js' , { id : options ?. id , l : options ?. l } ) ,
33- } ,
34- schema : import . meta. dev ? GoogleAnalyticsOptions : undefined ,
35- scriptOptions : {
36- use : ( ) => {
37- const gtag : GTag = function ( ...args : Parameters < GTag > ) {
38- ( ( window as any ) [ 'gtag-' + ( options . l ?? 'dataLayer' ) ] as GTag ) ( ...args )
39- } as GTag
40- return {
41- dataLayer : ( window as any ) [ options . l ?? 'dataLayer' ] as DataLayer ,
42- gtag,
43- }
110+ export const GoogleAnalyticsOptions = object ( {
111+ id : string ( ) , // The GA4 measurement ID (format: G-XXXXXXXX)
112+ l : optional ( string ( ) ) , // Optional global name for dataLayer (defaults to 'dataLayer')
113+ } )
114+
115+ export type GoogleAnalyticsInput = RegistryScriptInput < typeof GoogleAnalyticsOptions >
116+
117+ export function useScriptGoogleAnalytics < T extends GoogleAnalyticsApi > ( _options ?: GoogleAnalyticsInput & { onBeforeGtagStart ?: ( gtag : GTag ) => void } ) {
118+ return useRegistryScript < T , typeof GoogleAnalyticsOptions > ( _options ?. key || 'googleAnalytics' , ( options ) => {
119+ const dataLayerName = options ?. l ?? 'dataLayer'
120+ const w = import . meta. client ? window as any : { }
121+ return {
122+ scriptInput : {
123+ src : withQuery ( 'https://www.googletagmanager.com/gtag/js' , { id : options ?. id , l : options ?. l } ) ,
44124 } ,
45- performanceMarkFeature : 'nuxt-third-parties-ga' ,
46- tagPriority : 1 ,
47- } ,
48- clientInit : import . meta. server
49- ? undefined
50- : ( ) => {
51- const dataLayerName = options ?. l ?? 'dataLayer'
52- const dataLayer = ( window as any ) [ dataLayerName ] || [ ] ;
53-
54- ( window as any ) [ dataLayerName ] = dataLayer
55- // eslint-disable-next-line
56- // @ts -ignore
57- window [ 'gtag-' + ( dataLayerName ) ] = function ( ) {
58- // eslint-disable-next-line
59- ( window as any ) [ dataLayerName ] . push ( arguments )
125+ schema : import . meta. dev ? GoogleAnalyticsOptions : undefined ,
126+ scriptOptions : {
127+ use : ( ) => {
128+ return {
129+ dataLayer : w [ dataLayerName ] as DataLayer ,
130+ gtag : w . gtag as DataLayer ,
60131 }
61- ; ( ( window as any ) [ 'gtag-' + ( dataLayerName ) ] as GTag ) ( 'js' , new Date ( ) )
62- ; ( ( window as any ) [ 'gtag-' + ( dataLayerName ) ] as GTag ) ( 'config' , ( options ?. id ) )
63132 } ,
64- } ) , _options )
133+ performanceMarkFeature : 'nuxt-third-parties-ga' ,
134+ tagPriority : 1 ,
135+ } ,
136+ clientInit : import . meta. server
137+ ? undefined
138+ : ( ) => {
139+ w [ dataLayerName ] = w [ dataLayerName ] || [ ]
140+ w . gtag = function ( ) {
141+ // eslint-disable-next-line
142+ w [ dataLayerName ] . push ( arguments )
143+ }
144+ // eslint-disable-next-line
145+ // @ts -ignore
146+ _options ?. onBeforeGtagStart ?.( w . gtag )
147+ gtag ( 'js' , new Date ( ) )
148+ gtag ( 'config' , ( options ?. id ) )
149+ } ,
150+ }
151+ } , _options )
65152}
153+
154+ useScriptGoogleAnalytics ( {
155+ scriptOptions : {
156+ trigger : 'manual' ,
157+ } ,
158+ } )
0 commit comments