Connect EventTracker to TB endpoint (#7240)

#7091 
EventTrackers send information of events to the TinyBird instance:

In order to test:

1. Set ANALYTICS_ENABLED= true and TELEMETRY_ENABLED=true in
evironment-variables.ts
2. Set the TINYBIRD_TOKEN in environment variables (go to TiniyBird
Tokens)
3. Log in to twenty's TinyBird and go to datasources/analytics_events in
twenty_analytics workspace
4. Run twenty and navigate it
5. New events will be logged in the datasources, containing their
timestamp, sessionId and payload.

<img width="1189" alt="Screenshot 2024-09-24 at 17 23 01"
src="https://github.com/user-attachments/assets/85375897-504d-4e75-98e4-98e6a9671f98">
Example of payload when user is not logged in

```
{"hostName":"localhost",
"pathname":"/welcome",
"locale":"en-US",
"userAgent":"Mozilla/5.0",
"href":"http://localhost:3001/welcome",
"referrer":"",
"timeZone":"Europe/Barcelona"}
```
Example of payload when user is logged in
```
{"userId":"2020202",
"workspaceId":"202",
"workspaceDisplayName":"Apple",
"workspaceDomainName":"apple.dev",
"hostName":"localhost",
"pathname":"/objects/companies",
"locale":"en-US",
"userAgent":"Mozilla/5.0Chrome/128.0.0.0Safari/537.36",
"href":"http://localhost:3001/objects/companies",
"referrer":"",
"timeZone":"Europe/Paris"}
```

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
Ana Sofia Marin Alexandre
2024-09-26 10:53:10 +02:00
committed by GitHub
parent c9e882f4c0
commit 16bb1f22e4
28 changed files with 273 additions and 187 deletions

View File

@ -1,8 +1,8 @@
import { gql } from '@apollo/client';
export const TRACK = gql`
mutation Track($type: String!, $data: JSON!) {
track(type: $type, data: $data) {
mutation Track($type: String!, $sessionId: String!, $data: JSON!) {
track(type: $type, sessionId: $sessionId, data: $data) {
success
}
}

View File

@ -1,8 +1,8 @@
import { ReactNode } from 'react';
import { gql } from '@apollo/client';
import { MockedProvider, MockedResponse } from '@apollo/client/testing';
import { expect } from '@storybook/test';
import { act, renderHook, waitFor } from '@testing-library/react';
import { ReactNode } from 'react';
import { RecoilRoot } from 'recoil';
import { useEventTracker } from '../useEventTracker';
@ -11,15 +11,23 @@ const mocks: MockedResponse[] = [
{
request: {
query: gql`
mutation Track($type: String!, $data: JSON!) {
track(type: $type, data: $data) {
mutation Track($action: String!, $payload: JSON!) {
track(action: $action, payload: $payload) {
success
}
}
`,
variables: {
type: 'exampleType',
data: { location: { pathname: '/examplePath' } },
action: 'exampleType',
payload: {
sessionId: 'exampleId',
pathname: '',
userAgent: '',
timeZone: '',
locale: '',
href: '',
referrer: '',
},
},
},
result: jest.fn(() => ({
@ -43,7 +51,15 @@ const Wrapper = ({ children }: { children: ReactNode }) => (
describe('useEventTracker', () => {
it('should make the call to track the event', async () => {
const eventType = 'exampleType';
const eventData = { location: { pathname: '/examplePath' } };
const eventData = {
sessionId: 'exampleId',
pathname: '',
userAgent: '',
timeZone: '',
locale: '',
href: '',
referrer: '',
};
const { result } = renderHook(() => useEventTracker(), {
wrapper: Wrapper,
});

View File

@ -1,32 +1,46 @@
import { useCallback } from 'react';
import { useRecoilValue } from 'recoil';
import { telemetryState } from '@/client-config/states/telemetryState';
import { useTrackMutation } from '~/generated/graphql';
interface EventLocation {
pathname: string;
}
export interface EventData {
location: EventLocation;
pathname: string;
userAgent: string;
timeZone: string;
locale: string;
href: string;
referrer: string;
}
export const ANALYTICS_COOKIE_NAME = 'analyticsCookie';
export const getSessionId = (): string => {
const cookie: { [key: string]: string } = {};
document.cookie.split(';').forEach((el) => {
const [key, value] = el.split('=');
cookie[key.trim()] = value;
});
return cookie[ANALYTICS_COOKIE_NAME];
};
export const setSessionId = (domain?: string): void => {
const sessionId = getSessionId() || crypto.randomUUID();
const baseCookie = `${ANALYTICS_COOKIE_NAME}=${sessionId}; Max-Age=1800; path=/; secure`;
const cookie = domain ? baseCookie + `; domain=${domain}` : baseCookie;
document.cookie = cookie;
};
export const useEventTracker = () => {
const telemetry = useRecoilValue(telemetryState);
const [createEventMutation] = useTrackMutation();
return useCallback(
(eventType: string, eventData: EventData) => {
if (telemetry.enabled) {
createEventMutation({
variables: {
type: eventType,
data: eventData,
(eventAction: string, eventPayload: EventData) => {
createEventMutation({
variables: {
action: eventAction,
payload: {
sessionId: getSessionId(),
...eventPayload,
},
});
}
},
});
},
[createEventMutation, telemetry],
[createEventMutation],
);
};