11import Cookies from 'js-cookie' ;
22import { useEffect } from 'react' ;
33import { v4 as uuidv4 } from 'uuid' ;
4- import { useAppContext } from './contexts/appContext' ;
54
5+ import { useAppContext } from './contexts/appContext' ;
66const GA_TRACKING_ID = 'G-72XG3F8LNJ' ; // This is Hashnode's GA tracking ID
77const isProd = process . env . NEXT_PUBLIC_MODE === 'production' ;
88const BASE_PATH = process . env . NEXT_PUBLIC_BASE_URL || '' ;
99
1010export const Analytics = ( ) => {
11- const { publication, post } = useAppContext ( ) ;
12-
13- useEffect ( ( ) => {
14- if ( ! isProd ) return ;
15-
16- _sendPageViewsToHashnodeGoogleAnalytics ( ) ;
17- _sendViewsToHashnodeInternalAnalytics ( ) ;
18- _sendViewsToHashnodeAnalyticsDashboard ( ) ;
19- } , [ ] ) ;
20-
21- if ( ! isProd ) return null ;
11+ const { publication, post, series, page } = useAppContext ( ) ;
2212
2313 const _sendPageViewsToHashnodeGoogleAnalytics = ( ) => {
2414 // @ts -ignore
@@ -107,27 +97,6 @@ export const Analytics = () => {
10797 utm_content,
10898 } ;
10999
110- // send to Umami powered advanced Hashnode analytics
111- if ( publication . integrations ?. umamiWebsiteUUID ) {
112- await fetch ( `${ BASE_PATH } /api/collect` , {
113- method : 'POST' ,
114- headers : {
115- 'Content-Type' : 'application/json' ,
116- } ,
117- body : JSON . stringify ( {
118- payload : {
119- website : publication . integrations . umamiWebsiteUUID ,
120- url : window . location . pathname ,
121- referrer : referrer ,
122- hostname : window . location . hostname ,
123- language : NAVIGATOR . language ,
124- screen : `${ window . screen . width } x${ window . screen . height } ` ,
125- } ,
126- type : 'pageview' ,
127- } ) ,
128- } ) ;
129- }
130-
131100 // For Hashnode Blog Dashboard Analytics
132101 fetch ( `${ BASE_PATH } /ping/view` , {
133102 method : 'POST' ,
@@ -138,5 +107,91 @@ export const Analytics = () => {
138107 } ) ;
139108 } ;
140109
110+ function _sendViewsToAdvancedAnalyticsDashboard ( ) {
111+ const publicationId = publication . id ;
112+ const postId = post && post . id ;
113+ const seriesId = series ?. id || post ?. series ?. id ;
114+ const staticPageId = page && page . id ;
115+
116+ const data = {
117+ publicationId,
118+ postId,
119+ seriesId,
120+ staticPageId,
121+ } ;
122+
123+ if ( ! publicationId ) {
124+ console . warn ( 'Publication ID is missing; could not send analytics.' ) ;
125+ return ;
126+ }
127+
128+ const isBrowser = typeof window !== 'undefined' ;
129+ if ( ! isBrowser ) {
130+ return ;
131+ }
132+
133+ const isLocalhost = window . location . hostname === 'localhost' ;
134+ if ( isLocalhost ) {
135+ console . warn (
136+ 'Analytics API call is skipped because you are running on localhost; data:' ,
137+ data ,
138+ ) ;
139+ return ;
140+ }
141+
142+ const event = {
143+ // timestamp will be added in API
144+ payload : {
145+ publicationId,
146+ postId : postId || null ,
147+ seriesId : seriesId || null ,
148+ pageId : staticPageId || null ,
149+ url : window . location . href ,
150+ referrer : document . referrer || null ,
151+ language : navigator . language || null ,
152+ screen : `${ window . screen . width } x${ window . screen . height } ` ,
153+ } ,
154+ type : 'pageview' ,
155+ } ;
156+
157+ const blob = new Blob (
158+ [
159+ JSON . stringify ( {
160+ events : [ event ] ,
161+ } ) ,
162+ ] ,
163+ {
164+ type : 'application/json; charset=UTF-8' ,
165+ } ,
166+ ) ;
167+
168+ let hasSentBeacon = false ;
169+ try {
170+ if ( navigator . sendBeacon ) {
171+ hasSentBeacon = navigator . sendBeacon ( `${ BASE_PATH } /api/analytics` , blob ) ;
172+ }
173+ } catch ( error ) {
174+ // do nothing; in case there is an error we fall back to fetch
175+ }
176+
177+ if ( ! hasSentBeacon ) {
178+ fetch ( `${ BASE_PATH } /api/analytics` , {
179+ method : 'POST' ,
180+ body : blob ,
181+ credentials : 'omit' ,
182+ keepalive : true ,
183+ } ) ;
184+ }
185+ }
186+
187+ useEffect ( ( ) => {
188+ if ( ! isProd ) return ;
189+
190+ _sendPageViewsToHashnodeGoogleAnalytics ( ) ;
191+ _sendViewsToHashnodeInternalAnalytics ( ) ;
192+ _sendViewsToHashnodeAnalyticsDashboard ( ) ;
193+ _sendViewsToAdvancedAnalyticsDashboard ( ) ;
194+ } , [ ] ) ;
195+
141196 return null ;
142197} ;
0 commit comments