-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #25 from jakala-na/feat/analytic-implementation
Feat(analytic): Analytics implementation outline.
- Loading branch information
Showing
11 changed files
with
335 additions
and
72 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# Analytics | ||
|
||
Analytics solution is based on the [getanalytics.io](https://getanalytics.io/) library. | ||
The library provides three base API interfaces to sent tracking information: | ||
- `page()` - trigger page view. This will trigger page calls in any installed plugins | ||
- `identify()` - this will trigger identify calls in any installed plugins and will set user data in localStorage | ||
- `track()` - Track an analytics event. This will trigger track calls in any installed plugins | ||
|
||
## NextJS Integration | ||
|
||
We will provide integration with NextJS for three different cases: page view, | ||
component in view, click on target. See the `components/analytics/analytics.tsx` | ||
file where we convey the global Analytics context and define a hook to track | ||
page view. Then go to the `app/layout.tsx` where we wrap all children components | ||
inside the analytics context. | ||
|
||
### Page view tracking | ||
|
||
Page view will automatically triggered after the page will be loaded depending | ||
on the NextJS router `pathname` changes. | ||
|
||
### Component InView tracking | ||
|
||
We introduced the wrapper component `TrackInView` that can be used to wrap any | ||
client component and send analytics tracking event when the component is fully viewed. | ||
|
||
### On Click analytics | ||
|
||
Here's the place where we should communicate with the UI component and current | ||
implementation suppose just passing the click tracking event callback to the UI | ||
component and then the passed callback can be attached to any of the elements | ||
inside UI components on demand. | ||
|
||
## Type Safe Events | ||
|
||
We provide interfaces for each event in the `components/analytics/tracking-events.ts`. | ||
Each event should be registered in the `EventsMap` interface and for each event | ||
data should be provided own interface that describes the event data modal and | ||
will be the value of type the registered event in the `EventsMap` | ||
Also that file provides a helper function `createAnalyticsEvent()` that should be | ||
used to create any analytics event on the client level. This function will accept | ||
the event name string as the first argument and the event data object as the | ||
second argument and map given event name to the corresponding event data type. | ||
It will guarantee that all events will have correct data. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
'use client'; | ||
|
||
import { PropsWithChildren, useEffect } from 'react'; | ||
import { usePathname } from 'next/navigation'; | ||
|
||
import Analytics from 'analytics'; | ||
import { AnalyticsProvider } from 'use-analytics'; | ||
|
||
const analyticsInstance = Analytics({ | ||
app: 'starterkit', | ||
debug: true, | ||
}); | ||
|
||
export function AnalyticsComponent({ children }: PropsWithChildren) { | ||
const pathname = usePathname(); | ||
|
||
useEffect(() => { | ||
analyticsInstance.page(); | ||
}, [pathname]); | ||
|
||
return <AnalyticsProvider instance={analyticsInstance}>{children}</AnalyticsProvider>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './analytics'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
'use client'; | ||
|
||
import { InView } from 'react-intersection-observer'; | ||
import { useAnalytics } from 'use-analytics'; | ||
|
||
import { EventData, EventName } from './tracking-events'; | ||
|
||
interface TrackInViewProps { | ||
eventName: EventName; | ||
eventData: EventData<EventName>; | ||
children: React.ReactNode; | ||
} | ||
|
||
export const TrackInView = ({ eventName, eventData, children }: TrackInViewProps) => { | ||
const { track } = useAnalytics(); | ||
const onComponentIntersection = (inView: boolean) => { | ||
if (inView) { | ||
track(eventName, eventData); | ||
} | ||
}; | ||
return ( | ||
<InView triggerOnce threshold={1} onChange={(inView) => onComponentIntersection(inView)}> | ||
{children} | ||
</InView> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
interface EventsMap { | ||
heroBannerViewed: heroBannerViewedProps; | ||
duplexViewed: duplexViewedProps; | ||
duplexClicked: duplexClickedProps; | ||
} | ||
|
||
interface heroBannerViewedProps { | ||
category: string; | ||
} | ||
|
||
interface duplexViewedProps { | ||
category: string; | ||
type: string; | ||
} | ||
|
||
interface duplexClickedProps extends duplexViewedProps {} | ||
|
||
export type EventName = keyof EventsMap; | ||
export type EventData<T extends keyof EventsMap> = EventsMap[T]; | ||
|
||
export function createAnalyticsEvent<T extends EventName>(eventName: T, eventData: EventData<T>) { | ||
return { | ||
eventName, | ||
eventData, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.