@journium/react 0.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/context.d.ts +15 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/hooks.d.ts +10 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.esm.js +1407 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/index.js +1431 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
- package/readme.md +537 -0
package/readme.md
ADDED
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
# @journium/react
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/js/@journium/react)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://www.typescriptlang.org/)
|
|
6
|
+
|
|
7
|
+
**React integration for Journium - Track events, pageviews, and user interactions in React applications**
|
|
8
|
+
|
|
9
|
+
The official React SDK for Journium providing hooks, providers, and components for seamless analytics integration in React applications.
|
|
10
|
+
|
|
11
|
+
## 🚀 Quick Start
|
|
12
|
+
|
|
13
|
+
### Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @journium/react
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Basic Setup
|
|
20
|
+
|
|
21
|
+
Wrap your app with the `JourniumProvider`:
|
|
22
|
+
|
|
23
|
+
```jsx
|
|
24
|
+
import React from 'react';
|
|
25
|
+
import { JourniumProvider } from '@journium/react';
|
|
26
|
+
import App from './App';
|
|
27
|
+
|
|
28
|
+
function Root() {
|
|
29
|
+
return (
|
|
30
|
+
<JourniumProvider
|
|
31
|
+
token="your-journium-token"
|
|
32
|
+
apiHost="https://your-journium-instance.com"
|
|
33
|
+
autocapture={true}
|
|
34
|
+
>
|
|
35
|
+
<App />
|
|
36
|
+
</JourniumProvider>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export default Root;
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Using the Hook
|
|
44
|
+
|
|
45
|
+
Track events anywhere in your components:
|
|
46
|
+
|
|
47
|
+
```jsx
|
|
48
|
+
import React from 'react';
|
|
49
|
+
import { useJournium } from '@journium/react';
|
|
50
|
+
|
|
51
|
+
function SignupButton() {
|
|
52
|
+
const { track } = useJournium();
|
|
53
|
+
|
|
54
|
+
const handleSignup = () => {
|
|
55
|
+
track('signup_attempted', {
|
|
56
|
+
source: 'homepage',
|
|
57
|
+
plan: 'free'
|
|
58
|
+
});
|
|
59
|
+
// Your signup logic
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return <button onClick={handleSignup}>Sign Up</button>;
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## 📖 API Reference
|
|
67
|
+
|
|
68
|
+
### JourniumProvider
|
|
69
|
+
|
|
70
|
+
The main provider component that initializes Journium for your React app.
|
|
71
|
+
|
|
72
|
+
```jsx
|
|
73
|
+
<JourniumProvider
|
|
74
|
+
token="your-token" // Required: Your project token
|
|
75
|
+
apiHost="https://api.journium.com" // Required: API endpoint
|
|
76
|
+
debug={false} // Optional: Enable debug mode
|
|
77
|
+
flushAt={20} // Optional: Flush after N events
|
|
78
|
+
flushInterval={10000} // Optional: Flush interval (ms)
|
|
79
|
+
autocapture={true} // Optional: Enable auto-capture
|
|
80
|
+
sessionTimeout={1800000} // Optional: Session timeout (30m)
|
|
81
|
+
>
|
|
82
|
+
<YourApp />
|
|
83
|
+
</JourniumProvider>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### useJournium Hook
|
|
87
|
+
|
|
88
|
+
Access Journium functionality throughout your React app:
|
|
89
|
+
|
|
90
|
+
```jsx
|
|
91
|
+
import { useJournium } from '@journium/react';
|
|
92
|
+
|
|
93
|
+
function MyComponent() {
|
|
94
|
+
const { track, capturePageview, startAutoCapture, stopAutoCapture, flush } = useJournium();
|
|
95
|
+
|
|
96
|
+
// Track events
|
|
97
|
+
const handleClick = () => {
|
|
98
|
+
track('button_clicked', {
|
|
99
|
+
button_id: 'cta-primary',
|
|
100
|
+
page: 'pricing'
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// Manual pageview
|
|
105
|
+
const handleNavigate = () => {
|
|
106
|
+
capturePageview({
|
|
107
|
+
previous_page: '/home',
|
|
108
|
+
user_type: 'premium'
|
|
109
|
+
});
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// Control auto-capture
|
|
113
|
+
const toggleTracking = () => {
|
|
114
|
+
if (trackingEnabled) {
|
|
115
|
+
stopAutoCapture();
|
|
116
|
+
} else {
|
|
117
|
+
startAutoCapture();
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
return (
|
|
122
|
+
<div>
|
|
123
|
+
<button onClick={handleClick}>Track Click</button>
|
|
124
|
+
<button onClick={handleNavigate}>Manual Pageview</button>
|
|
125
|
+
<button onClick={toggleTracking}>Toggle Tracking</button>
|
|
126
|
+
</div>
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## 🔧 Advanced Usage
|
|
132
|
+
|
|
133
|
+
### Form Tracking
|
|
134
|
+
|
|
135
|
+
Track form interactions and submissions:
|
|
136
|
+
|
|
137
|
+
```jsx
|
|
138
|
+
import { useJournium } from '@journium/react';
|
|
139
|
+
|
|
140
|
+
function ContactForm() {
|
|
141
|
+
const { track } = useJournium();
|
|
142
|
+
|
|
143
|
+
const handleSubmit = (e) => {
|
|
144
|
+
e.preventDefault();
|
|
145
|
+
|
|
146
|
+
track('form_submitted', {
|
|
147
|
+
form_name: 'contact',
|
|
148
|
+
form_type: 'lead_generation',
|
|
149
|
+
fields_filled: ['name', 'email', 'company']
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// Submit form logic
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const handleFieldChange = (field) => {
|
|
156
|
+
track('form_field_changed', {
|
|
157
|
+
form_name: 'contact',
|
|
158
|
+
field_name: field
|
|
159
|
+
});
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
return (
|
|
163
|
+
<form onSubmit={handleSubmit}>
|
|
164
|
+
<input
|
|
165
|
+
name="email"
|
|
166
|
+
onChange={() => handleFieldChange('email')}
|
|
167
|
+
placeholder="Email"
|
|
168
|
+
/>
|
|
169
|
+
<input
|
|
170
|
+
name="company"
|
|
171
|
+
onChange={() => handleFieldChange('company')}
|
|
172
|
+
placeholder="Company"
|
|
173
|
+
/>
|
|
174
|
+
<button type="submit">Send Message</button>
|
|
175
|
+
</form>
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### E-commerce Tracking
|
|
181
|
+
|
|
182
|
+
Track purchase flows and product interactions:
|
|
183
|
+
|
|
184
|
+
```jsx
|
|
185
|
+
import { useJournium } from '@journium/react';
|
|
186
|
+
|
|
187
|
+
function ProductPage({ product }) {
|
|
188
|
+
const { track } = useJournium();
|
|
189
|
+
|
|
190
|
+
const handleAddToCart = () => {
|
|
191
|
+
track('product_added_to_cart', {
|
|
192
|
+
product_id: product.id,
|
|
193
|
+
product_name: product.name,
|
|
194
|
+
category: product.category,
|
|
195
|
+
price: product.price,
|
|
196
|
+
currency: 'USD'
|
|
197
|
+
});
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const handlePurchase = (orderData) => {
|
|
201
|
+
track('purchase_completed', {
|
|
202
|
+
order_id: orderData.id,
|
|
203
|
+
revenue: orderData.total,
|
|
204
|
+
currency: 'USD',
|
|
205
|
+
products: orderData.items.map(item => ({
|
|
206
|
+
product_id: item.id,
|
|
207
|
+
quantity: item.quantity,
|
|
208
|
+
price: item.price
|
|
209
|
+
}))
|
|
210
|
+
});
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
return (
|
|
214
|
+
<div>
|
|
215
|
+
<h1>{product.name}</h1>
|
|
216
|
+
<p>${product.price}</p>
|
|
217
|
+
<button onClick={handleAddToCart}>Add to Cart</button>
|
|
218
|
+
</div>
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### React Router Integration
|
|
224
|
+
|
|
225
|
+
Track page navigation automatically:
|
|
226
|
+
|
|
227
|
+
```jsx
|
|
228
|
+
import { useEffect } from 'react';
|
|
229
|
+
import { useLocation } from 'react-router-dom';
|
|
230
|
+
import { useJournium } from '@journium/react';
|
|
231
|
+
|
|
232
|
+
function PageTracker() {
|
|
233
|
+
const location = useLocation();
|
|
234
|
+
const { capturePageview } = useJournium();
|
|
235
|
+
|
|
236
|
+
useEffect(() => {
|
|
237
|
+
capturePageview({
|
|
238
|
+
path: location.pathname,
|
|
239
|
+
search: location.search,
|
|
240
|
+
referrer: document.referrer
|
|
241
|
+
});
|
|
242
|
+
}, [location, capturePageview]);
|
|
243
|
+
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Add to your router setup
|
|
248
|
+
function App() {
|
|
249
|
+
return (
|
|
250
|
+
<Router>
|
|
251
|
+
<PageTracker />
|
|
252
|
+
<Routes>
|
|
253
|
+
{/* Your routes */}
|
|
254
|
+
</Routes>
|
|
255
|
+
</Router>
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Conditional Tracking
|
|
261
|
+
|
|
262
|
+
Control tracking based on user preferences or environment:
|
|
263
|
+
|
|
264
|
+
```jsx
|
|
265
|
+
import { useJournium } from '@journium/react';
|
|
266
|
+
|
|
267
|
+
function ConditionalTracker() {
|
|
268
|
+
const { track, startAutoCapture, stopAutoCapture } = useJournium();
|
|
269
|
+
const [hasConsent, setHasConsent] = useState(false);
|
|
270
|
+
|
|
271
|
+
useEffect(() => {
|
|
272
|
+
if (hasConsent) {
|
|
273
|
+
startAutoCapture();
|
|
274
|
+
track('tracking_consent_given');
|
|
275
|
+
} else {
|
|
276
|
+
stopAutoCapture();
|
|
277
|
+
}
|
|
278
|
+
}, [hasConsent, startAutoCapture, stopAutoCapture, track]);
|
|
279
|
+
|
|
280
|
+
return (
|
|
281
|
+
<div>
|
|
282
|
+
<label>
|
|
283
|
+
<input
|
|
284
|
+
type="checkbox"
|
|
285
|
+
checked={hasConsent}
|
|
286
|
+
onChange={(e) => setHasConsent(e.target.checked)}
|
|
287
|
+
/>
|
|
288
|
+
Allow analytics tracking
|
|
289
|
+
</label>
|
|
290
|
+
</div>
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Custom Hook for User Actions
|
|
296
|
+
|
|
297
|
+
Create reusable tracking hooks:
|
|
298
|
+
|
|
299
|
+
```jsx
|
|
300
|
+
import { useJournium } from '@journium/react';
|
|
301
|
+
|
|
302
|
+
function useUserActions() {
|
|
303
|
+
const { track } = useJournium();
|
|
304
|
+
|
|
305
|
+
const trackSignup = (method, plan) => {
|
|
306
|
+
track('user_signup', {
|
|
307
|
+
signup_method: method,
|
|
308
|
+
selected_plan: plan,
|
|
309
|
+
timestamp: new Date().toISOString()
|
|
310
|
+
});
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
const trackLogin = (method) => {
|
|
314
|
+
track('user_login', {
|
|
315
|
+
login_method: method,
|
|
316
|
+
timestamp: new Date().toISOString()
|
|
317
|
+
});
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
const trackFeatureUsed = (feature, context = {}) => {
|
|
321
|
+
track('feature_used', {
|
|
322
|
+
feature_name: feature,
|
|
323
|
+
...context,
|
|
324
|
+
timestamp: new Date().toISOString()
|
|
325
|
+
});
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
return {
|
|
329
|
+
trackSignup,
|
|
330
|
+
trackLogin,
|
|
331
|
+
trackFeatureUsed
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Usage in components
|
|
336
|
+
function LoginForm() {
|
|
337
|
+
const { trackLogin } = useUserActions();
|
|
338
|
+
|
|
339
|
+
const handleLogin = (method) => {
|
|
340
|
+
trackLogin(method);
|
|
341
|
+
// Login logic
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
return (
|
|
345
|
+
<div>
|
|
346
|
+
<button onClick={() => handleLogin('email')}>Login with Email</button>
|
|
347
|
+
<button onClick={() => handleLogin('google')}>Login with Google</button>
|
|
348
|
+
</div>
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
## 🔒 Privacy & GDPR Compliance
|
|
354
|
+
|
|
355
|
+
### User Consent Management
|
|
356
|
+
|
|
357
|
+
```jsx
|
|
358
|
+
import { useState, useEffect } from 'react';
|
|
359
|
+
import { useJournium } from '@journium/react';
|
|
360
|
+
|
|
361
|
+
function PrivacyBanner() {
|
|
362
|
+
const { startAutoCapture, stopAutoCapture, flush } = useJournium();
|
|
363
|
+
const [showBanner, setShowBanner] = useState(true);
|
|
364
|
+
|
|
365
|
+
const handleAccept = () => {
|
|
366
|
+
localStorage.setItem('journium_consent', 'true');
|
|
367
|
+
setShowBanner(false);
|
|
368
|
+
startAutoCapture();
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
const handleDecline = () => {
|
|
372
|
+
localStorage.setItem('journium_consent', 'false');
|
|
373
|
+
setShowBanner(false);
|
|
374
|
+
stopAutoCapture();
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
useEffect(() => {
|
|
378
|
+
const consent = localStorage.getItem('journium_consent');
|
|
379
|
+
if (consent === 'false') {
|
|
380
|
+
stopAutoCapture();
|
|
381
|
+
setShowBanner(false);
|
|
382
|
+
} else if (consent === 'true') {
|
|
383
|
+
startAutoCapture();
|
|
384
|
+
setShowBanner(false);
|
|
385
|
+
}
|
|
386
|
+
}, [startAutoCapture, stopAutoCapture]);
|
|
387
|
+
|
|
388
|
+
if (!showBanner) return null;
|
|
389
|
+
|
|
390
|
+
return (
|
|
391
|
+
<div className="privacy-banner">
|
|
392
|
+
<p>We use analytics to improve your experience.</p>
|
|
393
|
+
<button onClick={handleAccept}>Accept</button>
|
|
394
|
+
<button onClick={handleDecline}>Decline</button>
|
|
395
|
+
</div>
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### Excluding Sensitive Data
|
|
401
|
+
|
|
402
|
+
```jsx
|
|
403
|
+
<JourniumProvider
|
|
404
|
+
token="your-token"
|
|
405
|
+
apiHost="https://api.journium.com"
|
|
406
|
+
autocapture={{
|
|
407
|
+
captureClicks: true,
|
|
408
|
+
captureFormSubmits: true,
|
|
409
|
+
captureFormChanges: false,
|
|
410
|
+
ignoreClasses: ['no-track', 'sensitive', 'pii'],
|
|
411
|
+
ignoreElements: [
|
|
412
|
+
'input[type="password"]',
|
|
413
|
+
'input[type="email"]',
|
|
414
|
+
'.credit-card-input',
|
|
415
|
+
'[data-private]'
|
|
416
|
+
]
|
|
417
|
+
}}
|
|
418
|
+
>
|
|
419
|
+
<App />
|
|
420
|
+
</JourniumProvider>
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
## 📱 TypeScript Support
|
|
424
|
+
|
|
425
|
+
Full TypeScript support with complete type definitions:
|
|
426
|
+
|
|
427
|
+
```typescript
|
|
428
|
+
import { useJournium, JourniumConfig } from '@journium/react';
|
|
429
|
+
|
|
430
|
+
interface CustomEventProperties {
|
|
431
|
+
product_id: string;
|
|
432
|
+
category: string;
|
|
433
|
+
price: number;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
function TypedComponent() {
|
|
437
|
+
const { track } = useJournium();
|
|
438
|
+
|
|
439
|
+
const handlePurchase = () => {
|
|
440
|
+
// Fully typed event tracking
|
|
441
|
+
track('product_purchased', {
|
|
442
|
+
product_id: 'prod_123',
|
|
443
|
+
category: 'electronics',
|
|
444
|
+
price: 299.99
|
|
445
|
+
} as CustomEventProperties);
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
return <button onClick={handlePurchase}>Purchase</button>;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Type-safe provider configuration
|
|
452
|
+
const config: JourniumConfig = {
|
|
453
|
+
token: 'your-token',
|
|
454
|
+
apiHost: 'https://api.journium.com',
|
|
455
|
+
autocapture: {
|
|
456
|
+
captureClicks: true,
|
|
457
|
+
captureFormSubmits: true,
|
|
458
|
+
ignoreClasses: ['no-track']
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
## ⚡ Performance Optimization
|
|
464
|
+
|
|
465
|
+
### Lazy Loading
|
|
466
|
+
|
|
467
|
+
```jsx
|
|
468
|
+
import { lazy, Suspense } from 'react';
|
|
469
|
+
|
|
470
|
+
const JourniumProvider = lazy(() => import('@journium/react').then(module => ({
|
|
471
|
+
default: module.JourniumProvider
|
|
472
|
+
})));
|
|
473
|
+
|
|
474
|
+
function App() {
|
|
475
|
+
return (
|
|
476
|
+
<Suspense fallback={<div>Loading...</div>}>
|
|
477
|
+
<JourniumProvider token="your-token" apiHost="https://api.journium.com">
|
|
478
|
+
<YourApp />
|
|
479
|
+
</JourniumProvider>
|
|
480
|
+
</Suspense>
|
|
481
|
+
);
|
|
482
|
+
}
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
### Event Batching
|
|
486
|
+
|
|
487
|
+
```jsx
|
|
488
|
+
import { useJournium } from '@journium/react';
|
|
489
|
+
|
|
490
|
+
function BatchedTracking() {
|
|
491
|
+
const { track, flush } = useJournium();
|
|
492
|
+
|
|
493
|
+
const handleMultipleActions = async () => {
|
|
494
|
+
// Queue multiple events
|
|
495
|
+
track('action_1', { step: 1 });
|
|
496
|
+
track('action_2', { step: 2 });
|
|
497
|
+
track('action_3', { step: 3 });
|
|
498
|
+
|
|
499
|
+
// Force flush all queued events
|
|
500
|
+
await flush();
|
|
501
|
+
};
|
|
502
|
+
|
|
503
|
+
return <button onClick={handleMultipleActions}>Complete Flow</button>;
|
|
504
|
+
}
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
## 🔗 Related Packages
|
|
508
|
+
|
|
509
|
+
Part of the Journium JavaScript SDK ecosystem:
|
|
510
|
+
|
|
511
|
+
- **[journium-js](https://npmjs.com/package/journium-js)** - Core JavaScript SDK for web browsers
|
|
512
|
+
- **[@journium/nextjs](https://npmjs.com/package/@journium/nextjs)** - Next.js integration with SSR support
|
|
513
|
+
- **[@journium/node](https://npmjs.com/package/@journium/node)** - Node.js server-side tracking
|
|
514
|
+
- **[@journium/core](https://npmjs.com/package/@journium/core)** - Core utilities and types
|
|
515
|
+
|
|
516
|
+
## 📖 Documentation
|
|
517
|
+
|
|
518
|
+
For complete documentation, guides, and examples:
|
|
519
|
+
|
|
520
|
+
- **[Documentation](https://docs.journium.app)** - Complete guides and API reference
|
|
521
|
+
- **[React Guide](https://docs.journium.app/react)** - React-specific documentation
|
|
522
|
+
- **[Examples](https://docs.journium.app/examples/react)** - React code examples and patterns
|
|
523
|
+
|
|
524
|
+
## 🤝 Contributing
|
|
525
|
+
|
|
526
|
+
We welcome contributions! Please see our [Contributing Guide](https://github.com/journium/journium-js/blob/main/CONTRIBUTING.md).
|
|
527
|
+
|
|
528
|
+
## 📄 License
|
|
529
|
+
|
|
530
|
+
MIT License - see [LICENSE](https://github.com/journium/journium-js/blob/main/LICENSE) file for details.
|
|
531
|
+
|
|
532
|
+
## 🆘 Support
|
|
533
|
+
|
|
534
|
+
- **📚 Docs**: [docs.journium.app](https://docs.journium.app)
|
|
535
|
+
- **🐛 Issues**: [GitHub Issues](https://github.com/journium/journium-js/issues)
|
|
536
|
+
- **💬 Discussions**: [GitHub Discussions](https://github.com/journium/journium-js/discussions)
|
|
537
|
+
- **📧 Email**: support@journium.com
|