8000 web-ui: add analytics · enggaraziz/threads-api@2b3f986 · GitHub
[go: up one dir, main page]

Skip to content

Commit 2b3f986

Browse files
committed
web-ui: add analytics
1 parent 369c200 commit 2b3f986

File tree

7 files changed

+207
-3
lines changed

7 files changed

+207
-3
lines changed

threads-web-ui/app/apps/page.tsx

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
import { AnalyticsTrackerLogView } from '@/components/AnalyticsTracker';
2+
13
export default async function AppDirectory() {
2-
return <></>;
4+
return (
5+
<>
6+
<AnalyticsTrackerLogView event={['view_app_directory', undefined]} />
7+
</>
8+
);
39
}

threads-web-ui/app/layout.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Inter } from 'next/font/google';
44
import './globals.css';
55
import { NavigationBar } from '@/components/NavigationBar';
66
import { Footer } from '@/components/Footer';
7+
import { AnalyticsTrackerInit } from '@/components/AnalyticsTracker';
78

89
const inter = Inter({ subsets: ['latin'] });
910

@@ -16,6 +17,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
1617
return (
1718
<html lang="en">
1819
<body className={inter.className}>
20+
<AnalyticsTrackerInit />
1921
<NavigationBar />
2022

2123
{children}

threads-web-ui/app/page.tsx

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import { BookOpen, Star, Zap } from 'lucide-react';
33
import { Globe } from '@/components/Globe';
44

55
import { UnaffiliatedBrands } from '@/components/UnaffiliatedBrands';
6+
import { AmplitudeClient } from 'amplitude-js';
7+
import { Analytics } from '@/lib/analytics';
8+
import { AnalyticsTrackerLogView } from '@/components/AnalyticsTracker';
69

710
const getStargazersCount = async (): Promise<number> => {
811
try {
@@ -21,6 +24,7 @@ export default async function Home() {
2124

2225
return (
2326
<>
27+
<AnalyticsTrackerLogView event={['view_landing', undefined]} />
2428
<div className="z-0 flex flex-col items-center">
2529
<div className="z-20 flex flex-col items-center">
2630
<header className="flex flex-col gap-5 pt-[120px] pb-12 px-4 items-center rounded-3xl">
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
'use client';
2+
3+
import { Analytics, AnalyticsEvent } from '@/lib/analytics';
4+
import { useEffect, useRef } from 'react';
5+
6+
export const AnalyticsTrackerInit: React.FC = () => {
7+
Analytics.initialize();
8+
return <></>;
9+
};
10+
11+
export const AnalyticsTrackerLogView = <TName extends keyof AnalyticsEvent>(props: {
12+
event: [name: TName, properties: AnalyticsEvent[TName]];
13+
}) => {
14+
const isLoggedRef = useRef<boolean>(false);
15+
16+
useEffect(() => {
17+
if (isLoggedRef.current) {
18+
return;
19+
}
20+
isLoggedRef.current = true;
21+
Analytics.logEvent(...props.event);
22+
}, []);
23+
return <></>;
24+
};

threads-web-ui/lib/analytics.ts

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
const isBrowser = typeof window !== 'undefined';
2+
3+
export type AnalyticsEvent = {
4+
view_landing: undefined;
5+
view_app_directory: undefined;
6+
click_social_link: {
7+
title: string;
8+
url: string;
9+
medium?: 'home_header' | string;
10+
};
11+
};
12+
13+
const AMPLITUDE_API_KEY = '322828ad7d1ac7b6e46bde1db17063b4';
14+
const getEnvironment = () => {
15+
if (!isBrowser) {
16+
return '';
17+
}
18+
return window.location.host.includes('localhost')
19+
? 'debug'
20+
: window.location.host.includes('junho.io')
21+
? 'production'
22+
: 'development';
23+
};
24+
25+
async function getAmplitude() {
26+
if (isBrowser) {
27+
const amplitude = await import('amplitude-js');
28+
return amplitude.default.getInstance();
29+
}
30+
return undefined;
31+
}
32+
33+
declare global {
34+
interface Window {
35+
initialized: boolean;
36+
}
37+
}
38+
39+
async function initialize() {
40+
if (window.initialized) {
41+
return;
42+
}
43+
window.initialized = true;
44+
const amplitude = await getAmplitude();
45+
amplitude?.init(AMPLITUDE_API_KEY);
46+
const ENVIRONMENT = getEnvironment();
47+
amplitude?.setUserProperties({
48+
is_debug: ENVIRONMENT !== 'production',
49+
});
50+
console.log(`[Analytics] Initialized (${ENVIRONMENT})`);
51+
}
52+
53+
async function logEvent<TName extends keyof AnalyticsEvent>(name: TName, properties: AnalyticsEvent[TName]) {
54+
if (!window.initialized) {
55+
await initialize();
56+
}
57+
const eventProperties = {
58+
referrer: document.referrer || undefined,
59+
...(properties as unknown as object),
60+
};
61+
const ENVIRONMENT = getEnvironment();
62+
if (ENVIRONMENT !== 'production') {
63+
console.log('[Analytics]', name, eventProperties);
64+
}
65+
const amplitude = await getAmplitude();
66+
amplitude?.logEvent(name, eventProperties);
67+
}
68+
69+
export const Analytics = {
70+
getAmplitude,
71+
initialize,
72+
logEvent,
73+
};

threads-web-ui/package.json

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"format": "prettier --write \"**/*.js\" \"**/*.ts\" \"**/*.tsx\" \"**/*.css\" \"./app/**/*.js\" \"./app/**/*.ts\" \"./app/**/*.tsx\" \"./app/**/*.css\""
1212
},
1313
"dependencies": {
14+
"amplitude-js": "^8.21.9",
1415
"class-variance-authority": "^0.6.1",
1516
"clsx": "^1.2.1",
1617
"cobe": "^0.6.3",
@@ -27,6 +28,7 @@
2728
},
2829
"devDependencies": {
2930
"@next/bundle-analyzer": "^13.4.8",
31+
"@types/amplitude-js": "^8.16.2",
3032
"@types/node": "^20.4.0",
3133
"@types/react": "^18.2.14",
3234
"@types/react-dom": "^18.2.6",

yarn.lock

+95-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,37 @@ __metadata:
1212
languageName: node
1313
linkType: hard
1414

15+
"@amplitude/analytics-connector@npm:^1.4.6":
16+
version: 1.4.8
17+
resolution: "@amplitude/analytics-connector@npm:1.4.8"
18+
checksum: 72b94cc2018af4d7bec48acf2129a933bee8268fee53d737408a058eef98ac84e7239265d53885f0d8fc73774657a6620db401a44674137486ebc550b320d6e4
19+
languageName: node
20+
linkType: hard
21+
22+
"@amplitude/types@npm:^1.10.2":
23+
version: 1.10.2
24+
resolution: "@amplitude/types@npm:1.10.2"
25+
checksum: 206ef520979c76a69baa145679a60c96249c165ff8354c0b58d183b917ae3abb35569cb0e9587ecf6c7b8636b2cc69d05ea9ecbd1cc9cade503256860bd80afe
26+
languageName: node
27+
linkType: hard
28+
29+
"@amplitude/ua-parser-js@npm:0.7.33":
30+
version: 0.7.33
31+
resolution: "@amplitude/ua-parser-js@npm:0.7.33"
32+
checksum: b08ce4cd4e96fed9eebffadb4060d24751cea80caf4265e6b829b7cfdb6561431386015674b3ac330a8987b990e2ca70725d4298eb1438beccb85264848b0b34
33+
languageName: node
34+
linkType: hard
35+
36+
"@amplitude/utils@npm:^1.10.2":
37+
version: 1.10.2
38+
resolution: "@amplitude/utils@npm:1.10.2"
39+
dependencies:
40+
"@amplitude/types": ^1.10.2
41+
tslib: ^2.0.0
42+
checksum: 9b5d3652725e30add1e42a1f221a3954c844d9aeb9d73b197c5ea2a0b91a86ccdedd4878e829cdae0eca287e68d37016347b97860069fa233d8d9ec78821d1c9
43+
languageName: node
44+
linkType: hard
45+
1546
"@ampproject/remapping@npm:^2.2.0":
1647
version: 2.2.1
1748
resolution: "@ampproject/remapping@npm:2.2.1"
@@ -1328,7 +1359,7 @@ __metadata:
13281359
languageName: node
13291360
linkType: hard
13301361

1331-
"@babel/runtime@npm:^7.8.4":
1362+
"@babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.8.4":
13321363
version: 7.22.6
13331364
resolution: "@babel/runtime@npm:7.22.6"
13341365
dependencies:
@@ -2119,6 +2150,13 @@ __metadata:
21192150
languageName: node
21202151
linkType: hard
21212152

2153+
"@types/amplitude-js@npm:^8.16.2":
2154+
version: 8.16.2
2155+
resolution: "@types/amplitude-js@npm:8.16.2"
2156+
checksum: 4b6763098af5f0a5b06030cd094bd834ba11eeed7625f2ac040ecaf8f1a951b1420ece0f1ed7a086ebbcd29f1ae959715c3b70e21b42e5dda4ef38a4f07d7391
2157+
languageName: node
2158+
linkType: hard
2159+
21222160
"@types/babel__core@npm:^7.1.14":
21232161
version: 7.20.1
21242162
resolution: "@types/babel__core@npm:7.20.1"
@@ -2372,6 +2410,20 @@ __metadata:
23722410
languageName: node
23732411
linkType: hard
23742412

2413+
"amplitude-js@npm:^8.21.9":
2414+
version: 8.21.9
2415+
resolution: "amplitude-js@npm:8.21.9"
2416+
dependencies:
2417+
"@amplitude/analytics-connector": ^1.4.6
2418+
"@amplitude/ua-parser-js": 0.7.33
2419+
"@amplitude/utils": ^1.10.2
2420+
"@babel/runtime": ^7.21.0
2421+
blueimp-md5: ^2.19.0
2422+
query-string: 8.1.0
2423+
checksum: 01409772abf904fecac26e81c453c884a8d3f1dd6b8a01a75288c8f1c8dccb022fdf2257fa66641d480241c3f4c0adbc643c9cfa89673642d9587180bb679c48
2424+
languageName: node
2425+
linkType: hard
2426+
23752427
"ansi-escapes@npm:^4.2.1":
23762428
version: 4.3.2
23772429
resolution: "ansi-escapes@npm:4.3.2"
@@ -2677,6 +2729,13 @@ __metadata:
26772729
languageName: node
26782730
linkType: hard
26792731

2732+
"blueimp-md5@npm:^2.19.0":
2733+
version: 2.19.0
2734+
resolution: "blueimp-md5@npm:2.19.0"
2735+
checksum: 28095dcbd2c67152a2938006e8d7c74c3406ba6556071298f872505432feb2c13241b0476644160ee0a5220383ba94cb8ccdac0053b51f68d168728f9c382530
2736+
languageName: node
2737+
linkType: hard
2738+
26802739
"brace-expansion@npm:^1.1.7":
26812740
version: 1.1.11
26822741
resolution: "brace-expansion@npm:1.1.11"
@@ -3138,6 +3197,13 @@ __metadata:
31383197
languageName: node
31393198
linkType: hard
31403199

3200+
"decode-uri-component@npm:^0.4.1":
3201+
version: 0.4.1
3202+
resolution: "decode-uri-component@npm:0.4.1"
3203+
checksum: 0473924860986fb6ca19ee65a2af13e08801b4f3660475b058500ea8479ed715c919884a026b6bf4296dbb640d3cea74fadf45490b2439152fc548271d0201ec
3204+
languageName: node
3205+
linkType: hard
3206+
31413207
"decompress-response@npm:^6.0.0":
31423208
version: 6.0.0
31433209
resolution: "decompress-response@npm:6.0.0"
@@ -3516,6 +3582,13 @@ __metadata:
35163582
languageName: node
35173583
linkType: hard
35183584

3585+
"filter-obj@npm:^5.1.0":
3586+
version: 5.1.0
3587+
resolution: "filter-obj@npm:5.1.0"
3588+
checksum: ba7c24d9b2c0552ee87d268e07eca74483af61fb740545ffa809f7e9e5294de38cf163ecc55af0e8a40020af9a49512c32f4022de2a858b110420fc8bffa7c9c
3589+
languageName: node
3590+
linkType: hard
3591+
35193592
"find-up@npm:^4.0.0, find-up@npm:^4.1.0":
35203593
version: 4.1.0
35213594
resolution: "find-up@npm:4.1.0"
@@ -5631,6 +5704,17 @@ __metadata:
56315704
languageName: node
56325705
linkType: hard
56335706

5707+
"query-string@npm:8.1.0":
5708+
version: 8.1.0
5709+
resolution: "query-string@npm:8.1.0"
5710+
dependencies:
5711+
decode-uri-component: ^0.4.1
5712+
filter-obj: ^5.1.0
5713+
split-on-first: ^3.0.0
5714+
checksum: 16fe49ab714f2b802bd31bc417876a38a82cd49bea01c0d6c37ca3439604c774752c8c66f9eda5ee33c268de2fc2a65e0e0e27aa97d8d98159af5c1fc838a017
5715+
languageName: node
5716+
linkType: hard
5717+
56345718
"queue-microtask@npm:^1.2.2":
56355719
version: 1.2.3
56365720
resolution: "queue-microtask@npm:1.2.3"
@@ -6155,6 +6239,13 @@ __metadata:
61556239
languageName: node
61566240
linkType: hard
61576241

6242+
"split-on-first@npm:^3.0.0":
6243+
version: 3.0.0
6244+
resolution: "split-on-first@npm:3.0.0"
6245+
checksum: 75dc27ecbac65cfbeab9a3b90cf046307220192d3d7a30e46aa0f19571cc9b4802aac813f3de2cc9b16f2e46aae72f275659b5d2614bb5369c77724d739e5f73
6246+
languageName: node
6247+
linkType: hard
6248+
61586249
"sprintf-js@npm:~1.0.2":
61596250
version: 1.0.3
61606251
resolution: "sprintf-js@npm:1.0.3"
@@ -6493,9 +6584,11 @@ __metadata:
64936584
resolution: "threads-web-ui@workspace:threads-web-ui"
64946585
dependencies:
64956586
"@next/bundle-analyzer": ^13.4.8
6587+
"@types/amplitude-js": ^8.16.2
64966588
"@types/node": ^20.4.0
64976589
"@types/react": ^18.2.14
64986590
"@types/react-dom": ^18.2.6
6591+
amplitude-js: ^8.21.9
64996592
autoprefixer: ^10.4.14
65006593
class-variance-authority: ^0.6.1
65016594
clsx: ^1.2.1
@@ -6615,7 +6708,7 @@ __metadata:
66156708
languageName: node
66166709
linkType: hard
66176710

6618-
"tslib@npm:^2.4.0, tslib@npm:^2.6.0":
6711+
"tslib@npm:^2.0.0, tslib@npm:^2.4.0, tslib@npm:^2.6.0":
66196712
version: 2.6.0
66206713
resolution: "tslib@npm:2.6.0"
66216714
checksum: c01066038f950016a18106ddeca4649b4d76caa76ec5a31e2a26e10586a59fceb4ee45e96719bf6c715648e7c14085a81fee5c62f7e9ebee68e77a5396e5538f

0 commit comments

Comments
 (0)
0