Skip to content

Commit 4a05293

Browse files
authored
feat(use-events): add new events providers (#2644)
Signed-off-by: protobuf-ci-cd <[email protected]>
1 parent 5762e12 commit 4a05293

30 files changed

+1659
-190
lines changed

.changeset/tiny-beans-appear.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@scaleway/use-analytics": patch
3+
---
4+
5+
Create Analytics providers with rudderstack, add consent management

package.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"@commitlint/cli": "catalog:",
2424
"@commitlint/config-conventional": "catalog:",
2525
"@eslint/eslintrc": "catalog:",
26+
"@rudderstack/analytics-js": "catalog:",
2627
"@scaleway/eslint-config-react": "workspace:*",
2728
"@scaleway/tsconfig": "workspace:*",
2829
"@testing-library/jest-dom": "catalog:",
@@ -72,7 +73,12 @@
7273
"react-dom": "18 || 19",
7374
"@types/react": "18 || 19"
7475
}
75-
}
76+
},
77+
"onlyBuiltDependencies": [
78+
"@biomejs/biome",
79+
"esbuild",
80+
"unrs-resolver"
81+
]
7682
},
7783
"commitlint": {
7884
"extends": [
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
dist/
2+
coverage/
3+
node_modules
4+
.reports/
5+
coverage/
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const { join } = require('path')
2+
3+
module.exports = {
4+
rules: {
5+
'import/no-extraneous-dependencies': [
6+
'error',
7+
{ packageDir: [__dirname, join(__dirname, '../../')] },
8+
],
9+
},
10+
}

packages/use-analytics/.npmignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
**/__tests__/**
2+
examples/
3+
src
4+
.eslintrc.cjs
5+
!.npmignore
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Change Log

packages/use-analytics/README.md

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# `@scaleway/use-analytics`
2+
3+
## A tiny hooks to handle analytics events
4+
5+
## Install
6+
7+
```bash
8+
$ pnpm add @scaleway/use-analytics
9+
```
10+
11+
## Usage
12+
13+
### Event directory
14+
15+
Create an events directory with all you specific events.
16+
17+
```
18+
events
19+
┣ pageTypes
20+
┃ ┗ index.ts
21+
┣ 📂loginEvent
22+
┃ ┗ index.ts
23+
┃ index.ts ( export all you functions )
24+
25+
```
26+
27+
Each event will have a format like this:
28+
29+
```typescript
30+
const pageVisited =
31+
(analytics?: Analytics) =>
32+
async (args: Args): Promise<void> => {
33+
// here do what you have to do with analytics
34+
await analytics?.page(args)
35+
}
36+
37+
export default pageVisited
38+
```
39+
40+
```typescript
41+
import pageTypes from './pageTypes'
42+
import testEvents from './testEvents'
43+
44+
export default {
45+
pageTypes,
46+
testEvents,
47+
}
48+
```
49+
50+
### Context Load
51+
52+
Inside you global app you have to use our Analytics Provider to allow loading of analytics from your settting app.
53+
This will trigger a load and return analitycs function inside you provider.
54+
55+
```javascript
56+
import { AnalyticsProvider } from '@scaleway/use-analytics'
57+
import { captureMessage } from '@sentry/browser'
58+
import events from './events'
59+
60+
const App = () => (
61+
<AnalyticsProvider
62+
settings={{ cdn: 'https://cdn.url', writeKey: 'WRITE_KEY' }}
63+
events={events}
64+
onError={e => captureMessage(`Error on Analytics: ${e.message}`)}
65+
>
66+
<App />
67+
</AnalyticsProvider>
68+
)
69+
```
70+
71+
### Hook utility
72+
73+
Now you maybe want to use your events inside your app .
74+
If you are using typescript, you may
75+
76+
```typescript
77+
import { useAnalytics } from '@scaleway/use-analytics'
78+
import type { Events } from 'types/events'
79+
import { Form, Submit } from '@scaleway/form'
80+
81+
const Login = () => {
82+
const { events } = useAnalytics<Events>()
83+
84+
const onSubmit = async args => {
85+
// make you api calls
86+
await events.login()
87+
}
88+
89+
return (
90+
<Form onSubmit={onSubmit}>
91+
// others fields
92+
<Submit />
93+
</Form>
94+
)
95+
}
96+
```
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{
2+
"name": "@scaleway/use-analytics",
3+
"version": "0.0.0",
4+
"description": "A small hook to handle events analytics",
5+
"engines": {
6+
"node": ">=20.x"
7+
},
8+
"main": "./dist/index.cjs",
9+
"sideEffects": false,
10+
"type": "module",
11+
"module": "./dist/index.js",
12+
"types": "./dist/index.d.ts",
13+
"exports": {
14+
".": {
15+
"types": "./dist/analytics/index.d.ts",
16+
"require": "./dist/analytics/index.cjs",
17+
"default": "./dist/analytics/index.js"
18+
},
19+
"./cookies-consent": {
20+
"types": "./dist/cookies-consent/index.d.ts",
21+
"require": "./dist/cookies-consent/index.cjs",
22+
"default": "./dist/cookies-consent/index.js"
23+
}
24+
},
25+
"publishConfig": {
26+
"access": "public"
27+
},
28+
"files": [
29+
"dist/*"
30+
],
31+
"scripts": {
32+
"prebuild": "shx rm -rf dist",
33+
"typecheck": "tsc --noEmit",
34+
"type:generate": "tsc --declaration -p tsconfig.build.json",
35+
"build": "vite build --config vite.config.ts && pnpm run type:generate",
36+
"build:profile": "npx vite-bundle-visualizer -c vite.config.ts",
37+
"lint": "eslint --report-unused-disable-directives --cache --cache-strategy content --ext ts,tsx ."
38+
},
39+
"repository": {
40+
"type": "git",
41+
"url": "https://github.com/scaleway/scaleway-lib",
42+
"directory": "packages/use-analytics"
43+
},
44+
"license": "MIT",
45+
"keywords": [
46+
"react",
47+
"reactjs",
48+
"hooks",
49+
"segment",
50+
"rudderstack"
51+
],
52+
"dependencies": {
53+
"@rudderstack/analytics-js":"catalog:",
54+
"@segment/analytics-next": "catalog:",
55+
"cookie": "catalog:",
56+
"use-deep-compare-effect": "catalog:"
57+
},
58+
"devDependencies": {
59+
"react": "catalog:"
60+
},
61+
"peerDependencies": {
62+
"react": "18.x || 19.x"
63+
}
64+
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
// import { AnalyticsBrowser } from '@segment/analytics-next'
2+
// import type { Context } from '@segment/analytics-next'
3+
// import { RudderAnalytics } from '@rudderstack/analytics-js'
4+
// import { render, screen, waitFor } from '@testing-library/react'
5+
// import { describe, expect, it, vi } from 'vitest'
6+
// import {AnalyticsProvider} from './'
7+
// import type { Analytics } from './index'
8+
9+
// const TestChildren = () => <div data-testid="test">children</div>
10+
11+
// const defaultAnalytics = {} as Analytics
12+
13+
// describe('AnalyticsProvider', () => {
14+
// it('Provider should render children when shouldRenderOnlyWhenReady is false', async () => {
15+
// const mock = vi
16+
// .spyOn(RudderAnalytics, 'load')
17+
// .mockResolvedValue([defaultAnalytics, {} as Context])
18+
19+
// const settings = { writeKey: 'helloworld', cdnURL: '', timeout: 300 }
20+
21+
// render(
22+
// <AnalyticsProvider
23+
// settings={settings}
24+
// initOptions={{}}
25+
// areOptionsLoaded={false}
26+
// events={{
27+
// event: () => () => Promise.resolve(),
28+
// }}
29+
// >
30+
// <TestChildren />
31+
// </AnalyticsProvider>,
32+
// )
33+
34+
// await waitFor(() => {
35+
// expect(mock).toHaveBeenCalledTimes(0)
36+
// })
37+
38+
// expect(screen.getByTestId('test')).toBeTruthy()
39+
// })
40+
41+
// it('Provider should not render children when options are not loaded ', async () => {
42+
// const mock = vi
43+
// .spyOn(AnalyticsBrowser, 'load')
44+
// .mockResolvedValue([{} as Analytics, {} as Context])
45+
46+
// const settings = { writeKey: 'helloworld' }
47+
48+
// render(
49+
// <AnalyticsProvider
50+
// settings={settings}
51+
// initOptions={{}}
52+
// areOptionsLoaded={false}
53+
// shouldRenderOnlyWhenReady
54+
// events={{
55+
// event: () => () => Promise.resolve(),
56+
// }}
57+
// >
58+
// <TestChildren />
59+
// </AnalyticsProvider>,
60+
// )
61+
62+
// await waitFor(() => {
63+
// expect(mock).toHaveBeenCalledTimes(0)
64+
// })
65+
66+
// expect(screen.queryByTestId('test')).toBe(null)
67+
// })
68+
69+
// it('Provider should not render children when options are not loaded at first render, but load after options changed', async () => {
70+
// const mock = vi
71+
// .spyOn(AnalyticsBrowser, 'load')
72+
// .mockResolvedValue([{} as Analytics, {} as Context])
73+
74+
// const settings = { writeKey: 'helloworld' }
75+
76+
// const { rerender } = render(
77+
// <AnalyticsProvider
78+
// settings={settings}
79+
// initOptions={{}}
80+
// areOptionsLoaded={false}
81+
// shouldRenderOnlyWhenReady
82+
// events={{
83+
// event: () => () => Promise.resolve(),
84+
// }}
85+
// >
86+
// <TestChildren />
87+
// </AnalyticsProvider>,
88+
// )
89+
90+
// await waitFor(() => {
91+
// expect(mock).toHaveBeenCalledTimes(0)
92+
// })
93+
94+
// expect(screen.queryByTestId('test')).toBe(null)
95+
96+
// rerender(
97+
// <AnalyticsProvider
98+
// settings={settings}
99+
// initOptions={{}}
100+
// areOptionsLoaded
101+
// shouldRenderOnlyWhenReady
102+
// events={{
103+
// event: () => () => Promise.resolve(),
104+
// }}
105+
// >
106+
// <TestChildren />
107+
// </AnalyticsProvider>,
108+
// )
109+
110+
// await waitFor(() => {
111+
// expect(mock).toHaveBeenCalledTimes(1)
112+
// })
113+
114+
// expect(screen.queryByTestId('test')).toBeTruthy()
115+
// })
116+
117+
// it('Provider should not render children when options are not loaded at first render, but load after options changed even without settings', async () => {
118+
// const mock = vi
119+
// .spyOn(AnalyticsBrowser, 'load')
120+
// .mockResolvedValue([{} as Analytics, {} as Context])
121+
122+
// const { rerender } = render(
123+
// <AnalyticsProvider
124+
// initOptions={{}}
125+
// areOptionsLoaded={false}
126+
// shouldRenderOnlyWhenReady
127+
// events={{
128+
// event: () => () => Promise.resolve(),
129+
// }}
130+
// >
131+
// <TestChildren />
132+
// </AnalyticsProvider>,
133+
// )
134+
135+
// await waitFor(() => {
136+
// expect(mock).toHaveBeenCalledTimes(0)
137+
// })
138+
139+
// expect(screen.queryByTestId('test')).toBe(null)
140+
141+
// rerender(
142+
// <AnalyticsProvider
143+
// initOptions={{}}
144+
// areOptionsLoaded
145+
// shouldRenderOnlyWhenReady
146+
// events={{
147+
// event: () => () => Promise.resolve(),
148+
// }}
149+
// >
150+
// <TestChildren />
151+
// </AnalyticsProvider>,
152+
// )
153+
154+
// await waitFor(() => {
155+
// expect(mock).toHaveBeenCalledTimes(0)
156+
// })
157+
158+
// expect(screen.queryByTestId('test')).toBeTruthy()
159+
// })
160+
// })

0 commit comments

Comments
 (0)