@datalyr/react-native 1.1.1 → 1.2.0
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/CHANGELOG.md +24 -141
- package/LICENSE +21 -0
- package/README.md +405 -217
- package/datalyr-react-native.podspec +31 -0
- package/ios/DatalyrNative.m +70 -0
- package/ios/DatalyrNative.swift +275 -0
- package/ios/DatalyrSKAdNetwork.m +26 -0
- package/lib/datalyr-sdk.d.ts +64 -3
- package/lib/datalyr-sdk.js +322 -3
- package/lib/index.d.ts +1 -0
- package/lib/index.js +4 -2
- package/lib/integrations/index.d.ts +6 -0
- package/lib/integrations/index.js +6 -0
- package/lib/integrations/meta-integration.d.ts +76 -0
- package/lib/integrations/meta-integration.js +218 -0
- package/lib/integrations/tiktok-integration.d.ts +82 -0
- package/lib/integrations/tiktok-integration.js +356 -0
- package/lib/native/DatalyrNativeBridge.d.ts +31 -0
- package/lib/native/DatalyrNativeBridge.js +168 -0
- package/lib/native/index.d.ts +5 -0
- package/lib/native/index.js +5 -0
- package/lib/types.d.ts +29 -0
- package/package.json +10 -5
- package/src/datalyr-sdk-expo.ts +957 -0
- package/src/datalyr-sdk.ts +419 -19
- package/src/expo.ts +38 -18
- package/src/index.ts +5 -2
- package/src/integrations/index.ts +7 -0
- package/src/integrations/meta-integration.ts +238 -0
- package/src/integrations/tiktok-integration.ts +360 -0
- package/src/native/DatalyrNativeBridge.ts +271 -0
- package/src/native/index.ts +11 -0
- package/src/types.ts +39 -0
- package/src/utils-expo.ts +25 -3
- package/src/utils-interface.ts +38 -0
- package/EXPO_INSTALL.md +0 -297
- package/INSTALL.md +0 -402
- package/examples/attribution-example.tsx +0 -377
- package/examples/auto-events-example.tsx +0 -403
- package/examples/example.tsx +0 -250
- package/examples/skadnetwork-example.tsx +0 -380
- package/examples/test-implementation.tsx +0 -163
|
@@ -1,403 +0,0 @@
|
|
|
1
|
-
import React, { useState, useEffect } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
View,
|
|
4
|
-
Text,
|
|
5
|
-
TouchableOpacity,
|
|
6
|
-
ScrollView,
|
|
7
|
-
Alert,
|
|
8
|
-
StyleSheet,
|
|
9
|
-
AppState,
|
|
10
|
-
SafeAreaView,
|
|
11
|
-
} from 'react-native';
|
|
12
|
-
import { datalyr } from '@datalyr/react-native';
|
|
13
|
-
|
|
14
|
-
// This example demonstrates all automatic events (like Mixpanel)
|
|
15
|
-
export default function AutoEventsExample() {
|
|
16
|
-
const [sdkStatus, setSdkStatus] = useState<any>(null);
|
|
17
|
-
const [sessionInfo, setSessionInfo] = useState<any>(null);
|
|
18
|
-
const [autoEvents, setAutoEvents] = useState<string[]>([]);
|
|
19
|
-
|
|
20
|
-
useEffect(() => {
|
|
21
|
-
initializeSDK();
|
|
22
|
-
|
|
23
|
-
// Monitor app state changes
|
|
24
|
-
const subscription = AppState.addEventListener('change', handleAppStateChange);
|
|
25
|
-
|
|
26
|
-
return () => subscription?.remove();
|
|
27
|
-
}, []);
|
|
28
|
-
|
|
29
|
-
const initializeSDK = async () => {
|
|
30
|
-
try {
|
|
31
|
-
console.log('🚀 Initializing Datalyr SDK with auto-events...');
|
|
32
|
-
|
|
33
|
-
await datalyr.initialize({
|
|
34
|
-
workspaceId: 'your-workspace-id',
|
|
35
|
-
apiKey: 'dk_your_api_key', // Required for authentication
|
|
36
|
-
debug: true,
|
|
37
|
-
enableAttribution: true, // ✅ Deep link attribution tracking
|
|
38
|
-
autoEvents: {
|
|
39
|
-
trackSessions: true, // ✅ Automatic session tracking
|
|
40
|
-
trackScreenViews: true, // ✅ Automatic screen tracking
|
|
41
|
-
trackAppUpdates: true, // ✅ App version changes
|
|
42
|
-
trackPerformance: true, // ✅ App launch time, performance
|
|
43
|
-
sessionTimeoutMs: 30 * 60 * 1000, // 30 minutes
|
|
44
|
-
},
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
// Get SDK status
|
|
48
|
-
const status = datalyr.getStatus();
|
|
49
|
-
setSdkStatus(status);
|
|
50
|
-
|
|
51
|
-
// Get session info
|
|
52
|
-
const session = datalyr.getCurrentSession();
|
|
53
|
-
setSessionInfo(session);
|
|
54
|
-
|
|
55
|
-
console.log('✅ SDK initialized with auto-events');
|
|
56
|
-
addAutoEvent('✅ SDK Initialized (automatic)');
|
|
57
|
-
addAutoEvent('📱 App Install Detected (automatic)');
|
|
58
|
-
addAutoEvent('⏱️ Session Started (automatic)');
|
|
59
|
-
addAutoEvent('🚀 App Launch Performance Tracked (automatic)');
|
|
60
|
-
|
|
61
|
-
} catch (error) {
|
|
62
|
-
console.error('❌ Failed to initialize SDK:', error);
|
|
63
|
-
Alert.alert('Error', 'Failed to initialize SDK');
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
const addAutoEvent = (event: string) => {
|
|
68
|
-
setAutoEvents(prev => [...prev, `${new Date().toLocaleTimeString()}: ${event}`]);
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
const handleAppStateChange = (nextAppState: string) => {
|
|
72
|
-
console.log('📱 App state changed to:', nextAppState);
|
|
73
|
-
|
|
74
|
-
if (nextAppState === 'active') {
|
|
75
|
-
addAutoEvent('🔆 App Foreground (automatic)');
|
|
76
|
-
// Session might be resumed or new session started automatically
|
|
77
|
-
updateSessionInfo();
|
|
78
|
-
} else if (nextAppState === 'background') {
|
|
79
|
-
addAutoEvent('🌙 App Background (automatic)');
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
const updateSessionInfo = () => {
|
|
84
|
-
const session = datalyr.getCurrentSession();
|
|
85
|
-
setSessionInfo(session);
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
// Simulate automatic screen tracking
|
|
89
|
-
const navigateToScreen = async (screenName: string) => {
|
|
90
|
-
console.log(`📺 Navigating to ${screenName}`);
|
|
91
|
-
|
|
92
|
-
// This will trigger automatic screen tracking
|
|
93
|
-
await datalyr.screen(screenName, {
|
|
94
|
-
screen_category: 'demo',
|
|
95
|
-
navigation_method: 'button_press',
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
addAutoEvent(`📺 Pageview: ${screenName} (automatic)`);
|
|
99
|
-
updateSessionInfo();
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
// Simulate automatic revenue tracking
|
|
103
|
-
const simulatePurchase = async () => {
|
|
104
|
-
console.log('💰 Simulating purchase...');
|
|
105
|
-
|
|
106
|
-
// This will trigger automatic revenue event tracking
|
|
107
|
-
await datalyr.trackRevenue('purchase', {
|
|
108
|
-
product_id: 'premium_plan',
|
|
109
|
-
price: 9.99,
|
|
110
|
-
currency: 'USD',
|
|
111
|
-
payment_method: 'apple_pay',
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
addAutoEvent('💰 Revenue Event: Purchase (automatic)');
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
// Simulate app update
|
|
118
|
-
const simulateAppUpdate = async () => {
|
|
119
|
-
console.log('📱 Simulating app update...');
|
|
120
|
-
|
|
121
|
-
await datalyr.trackAppUpdate('1.0.0', '1.1.0');
|
|
122
|
-
addAutoEvent('📱 App Update: 1.0.0 → 1.1.0 (automatic)');
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
// Force end session to test session management
|
|
126
|
-
const endCurrentSession = async () => {
|
|
127
|
-
console.log('🔚 Ending current session...');
|
|
128
|
-
|
|
129
|
-
await datalyr.endSession();
|
|
130
|
-
addAutoEvent('🔚 Session Ended (manual)');
|
|
131
|
-
|
|
132
|
-
// Update session info after ending
|
|
133
|
-
setTimeout(updateSessionInfo, 1000);
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
// Custom event (for comparison with automatic events)
|
|
137
|
-
const trackCustomEvent = async () => {
|
|
138
|
-
console.log('🎯 Tracking custom event...');
|
|
139
|
-
|
|
140
|
-
await datalyr.track('button_clicked', {
|
|
141
|
-
button_name: 'custom_event_button',
|
|
142
|
-
screen_name: 'auto_events_demo',
|
|
143
|
-
user_intent: 'testing',
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
addAutoEvent('🎯 Custom Event: button_clicked (manual)');
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
return (
|
|
150
|
-
<SafeAreaView style={styles.container}>
|
|
151
|
-
<ScrollView style={styles.content}>
|
|
152
|
-
<Text style={styles.title}>📊 Datalyr Auto-Events Demo</Text>
|
|
153
|
-
<Text style={styles.subtitle}>Like Mixpanel's Automatic Events</Text>
|
|
154
|
-
|
|
155
|
-
{/* SDK Status */}
|
|
156
|
-
<View style={styles.section}>
|
|
157
|
-
<Text style={styles.sectionTitle}>📱 SDK Status</Text>
|
|
158
|
-
<View style={styles.infoCard}>
|
|
159
|
-
<Text style={styles.infoText}>
|
|
160
|
-
Initialized: {sdkStatus?.initialized ? '✅' : '❌'}
|
|
161
|
-
</Text>
|
|
162
|
-
<Text style={styles.infoText}>
|
|
163
|
-
Visitor ID: {sdkStatus?.visitorId || 'Not set'}
|
|
164
|
-
</Text>
|
|
165
|
-
<Text style={styles.infoText}>
|
|
166
|
-
Workspace: {sdkStatus?.workspaceId || 'Not set'}
|
|
167
|
-
</Text>
|
|
168
|
-
</View>
|
|
169
|
-
</View>
|
|
170
|
-
|
|
171
|
-
{/* Session Info */}
|
|
172
|
-
<View style={styles.section}>
|
|
173
|
-
<Text style={styles.sectionTitle}>⏱️ Current Session</Text>
|
|
174
|
-
<View style={styles.infoCard}>
|
|
175
|
-
{sessionInfo ? (
|
|
176
|
-
<>
|
|
177
|
-
<Text style={styles.infoText}>
|
|
178
|
-
Session ID: {sessionInfo.sessionId}
|
|
179
|
-
</Text>
|
|
180
|
-
<Text style={styles.infoText}>
|
|
181
|
-
Duration: {Math.round((Date.now() - sessionInfo.startTime) / 1000)}s
|
|
182
|
-
</Text>
|
|
183
|
-
<Text style={styles.infoText}>
|
|
184
|
-
Pageviews: {sessionInfo.screenViews}
|
|
185
|
-
</Text>
|
|
186
|
-
<Text style={styles.infoText}>
|
|
187
|
-
Events: {sessionInfo.events}
|
|
188
|
-
</Text>
|
|
189
|
-
</>
|
|
190
|
-
) : (
|
|
191
|
-
<Text style={styles.infoText}>No active session</Text>
|
|
192
|
-
)}
|
|
193
|
-
</View>
|
|
194
|
-
</View>
|
|
195
|
-
|
|
196
|
-
{/* Action Buttons */}
|
|
197
|
-
<View style={styles.section}>
|
|
198
|
-
<Text style={styles.sectionTitle}>🎮 Test Automatic Events</Text>
|
|
199
|
-
|
|
200
|
-
<TouchableOpacity
|
|
201
|
-
style={styles.button}
|
|
202
|
-
onPress={() => navigateToScreen('Home')}
|
|
203
|
-
>
|
|
204
|
-
<Text style={styles.buttonText}>📺 Navigate to Home</Text>
|
|
205
|
-
</TouchableOpacity>
|
|
206
|
-
|
|
207
|
-
<TouchableOpacity
|
|
208
|
-
style={styles.button}
|
|
209
|
-
onPress={() => navigateToScreen('Profile')}
|
|
210
|
-
>
|
|
211
|
-
<Text style={styles.buttonText}>📺 Navigate to Profile</Text>
|
|
212
|
-
</TouchableOpacity>
|
|
213
|
-
|
|
214
|
-
<TouchableOpacity
|
|
215
|
-
style={styles.button}
|
|
216
|
-
onPress={() => navigateToScreen('Settings')}
|
|
217
|
-
>
|
|
218
|
-
<Text style={styles.buttonText}>📺 Navigate to Settings</Text>
|
|
219
|
-
</TouchableOpacity>
|
|
220
|
-
|
|
221
|
-
<TouchableOpacity
|
|
222
|
-
style={[styles.button, styles.revenueButton]}
|
|
223
|
-
onPress={simulatePurchase}
|
|
224
|
-
>
|
|
225
|
-
<Text style={styles.buttonText}>💰 Simulate Purchase</Text>
|
|
226
|
-
</TouchableOpacity>
|
|
227
|
-
|
|
228
|
-
<TouchableOpacity
|
|
229
|
-
style={[styles.button, styles.updateButton]}
|
|
230
|
-
onPress={simulateAppUpdate}
|
|
231
|
-
>
|
|
232
|
-
<Text style={styles.buttonText}>📱 Simulate App Update</Text>
|
|
233
|
-
</TouchableOpacity>
|
|
234
|
-
|
|
235
|
-
<TouchableOpacity
|
|
236
|
-
style={[styles.button, styles.sessionButton]}
|
|
237
|
-
onPress={endCurrentSession}
|
|
238
|
-
>
|
|
239
|
-
<Text style={styles.buttonText}>🔚 End Session</Text>
|
|
240
|
-
</TouchableOpacity>
|
|
241
|
-
|
|
242
|
-
<TouchableOpacity
|
|
243
|
-
style={[styles.button, styles.customButton]}
|
|
244
|
-
onPress={trackCustomEvent}
|
|
245
|
-
>
|
|
246
|
-
<Text style={styles.buttonText}>🎯 Track Custom Event</Text>
|
|
247
|
-
</TouchableOpacity>
|
|
248
|
-
</View>
|
|
249
|
-
|
|
250
|
-
{/* Event Log */}
|
|
251
|
-
<View style={styles.section}>
|
|
252
|
-
<Text style={styles.sectionTitle}>📝 Automatic Events Log</Text>
|
|
253
|
-
<View style={styles.eventLog}>
|
|
254
|
-
{autoEvents.length === 0 ? (
|
|
255
|
-
<Text style={styles.noEvents}>No events yet...</Text>
|
|
256
|
-
) : (
|
|
257
|
-
autoEvents.map((event, index) => (
|
|
258
|
-
<Text key={index} style={styles.eventItem}>
|
|
259
|
-
{event}
|
|
260
|
-
</Text>
|
|
261
|
-
))
|
|
262
|
-
)}
|
|
263
|
-
</View>
|
|
264
|
-
</View>
|
|
265
|
-
|
|
266
|
-
{/* Auto-Events Features */}
|
|
267
|
-
<View style={styles.section}>
|
|
268
|
-
<Text style={styles.sectionTitle}>✨ Included Automatic Events</Text>
|
|
269
|
-
<View style={styles.featureList}>
|
|
270
|
-
<Text style={styles.featureItem}>✅ Session Start/End</Text>
|
|
271
|
-
<Text style={styles.featureItem}>✅ App Foreground/Background</Text>
|
|
272
|
-
<Text style={styles.featureItem}>✅ Pageviews</Text>
|
|
273
|
-
<Text style={styles.featureItem}>✅ App Install Detection</Text>
|
|
274
|
-
<Text style={styles.featureItem}>✅ App Updates</Text>
|
|
275
|
-
<Text style={styles.featureItem}>✅ App Launch Performance</Text>
|
|
276
|
-
<Text style={styles.featureItem}>✅ Revenue Events</Text>
|
|
277
|
-
<Text style={styles.featureItem}>✅ SDK Initialization</Text>
|
|
278
|
-
<Text style={styles.featureItem}>✅ Attribution Tracking</Text>
|
|
279
|
-
</View>
|
|
280
|
-
</View>
|
|
281
|
-
|
|
282
|
-
<View style={styles.footer}>
|
|
283
|
-
<Text style={styles.footerText}>
|
|
284
|
-
🎉 All events are automatically captured and sent to your dashboard!
|
|
285
|
-
</Text>
|
|
286
|
-
</View>
|
|
287
|
-
</ScrollView>
|
|
288
|
-
</SafeAreaView>
|
|
289
|
-
);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
const styles = StyleSheet.create({
|
|
293
|
-
container: {
|
|
294
|
-
flex: 1,
|
|
295
|
-
backgroundColor: '#f5f5f5',
|
|
296
|
-
},
|
|
297
|
-
content: {
|
|
298
|
-
flex: 1,
|
|
299
|
-
padding: 20,
|
|
300
|
-
},
|
|
301
|
-
title: {
|
|
302
|
-
fontSize: 24,
|
|
303
|
-
fontWeight: 'bold',
|
|
304
|
-
textAlign: 'center',
|
|
305
|
-
marginBottom: 8,
|
|
306
|
-
color: '#333',
|
|
307
|
-
},
|
|
308
|
-
subtitle: {
|
|
309
|
-
fontSize: 16,
|
|
310
|
-
textAlign: 'center',
|
|
311
|
-
marginBottom: 30,
|
|
312
|
-
color: '#666',
|
|
313
|
-
},
|
|
314
|
-
section: {
|
|
315
|
-
marginBottom: 25,
|
|
316
|
-
},
|
|
317
|
-
sectionTitle: {
|
|
318
|
-
fontSize: 18,
|
|
319
|
-
fontWeight: '600',
|
|
320
|
-
marginBottom: 12,
|
|
321
|
-
color: '#333',
|
|
322
|
-
},
|
|
323
|
-
infoCard: {
|
|
324
|
-
backgroundColor: 'white',
|
|
325
|
-
padding: 15,
|
|
326
|
-
borderRadius: 8,
|
|
327
|
-
borderLeftWidth: 4,
|
|
328
|
-
borderLeftColor: '#007AFF',
|
|
329
|
-
},
|
|
330
|
-
infoText: {
|
|
331
|
-
fontSize: 14,
|
|
332
|
-
marginBottom: 6,
|
|
333
|
-
color: '#444',
|
|
334
|
-
fontFamily: 'Monaco',
|
|
335
|
-
},
|
|
336
|
-
button: {
|
|
337
|
-
backgroundColor: '#007AFF',
|
|
338
|
-
padding: 15,
|
|
339
|
-
borderRadius: 8,
|
|
340
|
-
marginBottom: 10,
|
|
341
|
-
alignItems: 'center',
|
|
342
|
-
},
|
|
343
|
-
revenueButton: {
|
|
344
|
-
backgroundColor: '#34C759',
|
|
345
|
-
},
|
|
346
|
-
updateButton: {
|
|
347
|
-
backgroundColor: '#FF9500',
|
|
348
|
-
},
|
|
349
|
-
sessionButton: {
|
|
350
|
-
backgroundColor: '#FF3B30',
|
|
351
|
-
},
|
|
352
|
-
customButton: {
|
|
353
|
-
backgroundColor: '#5856D6',
|
|
354
|
-
},
|
|
355
|
-
buttonText: {
|
|
356
|
-
color: 'white',
|
|
357
|
-
fontSize: 16,
|
|
358
|
-
fontWeight: '600',
|
|
359
|
-
},
|
|
360
|
-
eventLog: {
|
|
361
|
-
backgroundColor: 'white',
|
|
362
|
-
padding: 15,
|
|
363
|
-
borderRadius: 8,
|
|
364
|
-
maxHeight: 200,
|
|
365
|
-
},
|
|
366
|
-
noEvents: {
|
|
367
|
-
textAlign: 'center',
|
|
368
|
-
color: '#999',
|
|
369
|
-
fontStyle: 'italic',
|
|
370
|
-
},
|
|
371
|
-
eventItem: {
|
|
372
|
-
fontSize: 12,
|
|
373
|
-
marginBottom: 6,
|
|
374
|
-
color: '#333',
|
|
375
|
-
fontFamily: 'Monaco',
|
|
376
|
-
borderBottomWidth: 1,
|
|
377
|
-
borderBottomColor: '#eee',
|
|
378
|
-
paddingBottom: 4,
|
|
379
|
-
},
|
|
380
|
-
featureList: {
|
|
381
|
-
backgroundColor: 'white',
|
|
382
|
-
padding: 15,
|
|
383
|
-
borderRadius: 8,
|
|
384
|
-
},
|
|
385
|
-
featureItem: {
|
|
386
|
-
fontSize: 14,
|
|
387
|
-
marginBottom: 8,
|
|
388
|
-
color: '#333',
|
|
389
|
-
},
|
|
390
|
-
footer: {
|
|
391
|
-
marginTop: 20,
|
|
392
|
-
padding: 20,
|
|
393
|
-
backgroundColor: 'white',
|
|
394
|
-
borderRadius: 8,
|
|
395
|
-
alignItems: 'center',
|
|
396
|
-
},
|
|
397
|
-
footerText: {
|
|
398
|
-
fontSize: 16,
|
|
399
|
-
color: '#34C759',
|
|
400
|
-
fontWeight: '600',
|
|
401
|
-
textAlign: 'center',
|
|
402
|
-
},
|
|
403
|
-
});
|
package/examples/example.tsx
DELETED
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Datalyr React Native SDK Example
|
|
3
|
-
*
|
|
4
|
-
* This example shows how to integrate the Datalyr SDK into a React Native app
|
|
5
|
-
* for mobile attribution and event tracking.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import React, { useEffect, useState } from 'react';
|
|
9
|
-
import {
|
|
10
|
-
View,
|
|
11
|
-
Text,
|
|
12
|
-
Button,
|
|
13
|
-
StyleSheet,
|
|
14
|
-
Alert,
|
|
15
|
-
ScrollView,
|
|
16
|
-
StatusBar,
|
|
17
|
-
} from 'react-native';
|
|
18
|
-
import { datalyr } from '@datalyr/react-native';
|
|
19
|
-
|
|
20
|
-
const App: React.FC = () => {
|
|
21
|
-
const [sdkStatus, setSdkStatus] = useState<any>(null);
|
|
22
|
-
const [isInitialized, setIsInitialized] = useState(false);
|
|
23
|
-
|
|
24
|
-
useEffect(() => {
|
|
25
|
-
initializeDatalyr();
|
|
26
|
-
}, []);
|
|
27
|
-
|
|
28
|
-
const initializeDatalyr = async () => {
|
|
29
|
-
try {
|
|
30
|
-
// Initialize with your workspace ID and API key
|
|
31
|
-
await datalyr.initialize({
|
|
32
|
-
workspaceId: 'ozLZblQ8hN', // Replace with your actual workspace ID
|
|
33
|
-
apiKey: 'dk_your_api_key', // Required for authentication
|
|
34
|
-
debug: true, // Enable debug logging
|
|
35
|
-
enableAttribution: true, // ✅ Deep link attribution tracking
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
setIsInitialized(true);
|
|
39
|
-
updateStatus();
|
|
40
|
-
|
|
41
|
-
// Track app launch
|
|
42
|
-
await datalyr.track('app_launch', {
|
|
43
|
-
app_version: '1.0.0',
|
|
44
|
-
platform: 'ios', // or 'android'
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
console.log('Datalyr SDK initialized successfully!');
|
|
48
|
-
} catch (error) {
|
|
49
|
-
console.error('Failed to initialize Datalyr SDK:', error);
|
|
50
|
-
Alert.alert('Error', 'Failed to initialize Datalyr SDK');
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const updateStatus = () => {
|
|
55
|
-
const status = datalyr.getStatus();
|
|
56
|
-
setSdkStatus(status);
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const trackPurchase = async () => {
|
|
60
|
-
try {
|
|
61
|
-
await datalyr.track('purchase', {
|
|
62
|
-
value: 29.99,
|
|
63
|
-
currency: 'USD',
|
|
64
|
-
item_id: 'product_123',
|
|
65
|
-
item_name: 'Premium Subscription',
|
|
66
|
-
category: 'subscription',
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
Alert.alert('Success', 'Purchase event tracked!');
|
|
70
|
-
updateStatus();
|
|
71
|
-
} catch (error) {
|
|
72
|
-
console.error('Error tracking purchase:', error);
|
|
73
|
-
Alert.alert('Error', 'Failed to track purchase');
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
const trackScreenView = async () => {
|
|
78
|
-
try {
|
|
79
|
-
await datalyr.screen('home_screen', {
|
|
80
|
-
section: 'main',
|
|
81
|
-
user_type: 'premium',
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
Alert.alert('Success', 'Pageview tracked!');
|
|
85
|
-
updateStatus();
|
|
86
|
-
} catch (error) {
|
|
87
|
-
console.error('Error tracking pageview:', error);
|
|
88
|
-
Alert.alert('Error', 'Failed to track pageview');
|
|
89
|
-
}
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
const identifyUser = async () => {
|
|
93
|
-
try {
|
|
94
|
-
await datalyr.identify('user_12345', {
|
|
95
|
-
email: 'user@example.com',
|
|
96
|
-
name: 'John Doe',
|
|
97
|
-
plan: 'premium',
|
|
98
|
-
signup_date: new Date().toISOString(),
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
Alert.alert('Success', 'User identified!');
|
|
102
|
-
updateStatus();
|
|
103
|
-
} catch (error) {
|
|
104
|
-
console.error('Error identifying user:', error);
|
|
105
|
-
Alert.alert('Error', 'Failed to identify user');
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
const flushEvents = async () => {
|
|
110
|
-
try {
|
|
111
|
-
await datalyr.flush();
|
|
112
|
-
Alert.alert('Success', 'Events flushed!');
|
|
113
|
-
updateStatus();
|
|
114
|
-
} catch (error) {
|
|
115
|
-
console.error('Error flushing events:', error);
|
|
116
|
-
Alert.alert('Error', 'Failed to flush events');
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
const resetUser = async () => {
|
|
121
|
-
try {
|
|
122
|
-
await datalyr.reset();
|
|
123
|
-
Alert.alert('Success', 'User data reset!');
|
|
124
|
-
updateStatus();
|
|
125
|
-
} catch (error) {
|
|
126
|
-
console.error('Error resetting user:', error);
|
|
127
|
-
Alert.alert('Error', 'Failed to reset user');
|
|
128
|
-
}
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
return (
|
|
132
|
-
<View style={styles.container}>
|
|
133
|
-
<StatusBar barStyle="dark-content" />
|
|
134
|
-
<ScrollView style={styles.scrollView} contentContainerStyle={styles.content}>
|
|
135
|
-
<Text style={styles.title}>Datalyr SDK Example</Text>
|
|
136
|
-
|
|
137
|
-
<View style={styles.statusContainer}>
|
|
138
|
-
<Text style={styles.statusTitle}>SDK Status:</Text>
|
|
139
|
-
<Text style={styles.statusText}>
|
|
140
|
-
Initialized: {isInitialized ? '✅' : '❌'}
|
|
141
|
-
</Text>
|
|
142
|
-
{sdkStatus && (
|
|
143
|
-
<>
|
|
144
|
-
<Text style={styles.statusText}>
|
|
145
|
-
Workspace: {sdkStatus.workspaceId}
|
|
146
|
-
</Text>
|
|
147
|
-
<Text style={styles.statusText}>
|
|
148
|
-
Visitor ID: {sdkStatus.visitorId.substring(0, 8)}...
|
|
149
|
-
</Text>
|
|
150
|
-
<Text style={styles.statusText}>
|
|
151
|
-
Session ID: {sdkStatus.sessionId.substring(0, 12)}...
|
|
152
|
-
</Text>
|
|
153
|
-
<Text style={styles.statusText}>
|
|
154
|
-
User ID: {sdkStatus.currentUserId || 'Not set'}
|
|
155
|
-
</Text>
|
|
156
|
-
<Text style={styles.statusText}>
|
|
157
|
-
Queue Size: {sdkStatus.queueStats?.queueSize || 0}
|
|
158
|
-
</Text>
|
|
159
|
-
</>
|
|
160
|
-
)}
|
|
161
|
-
</View>
|
|
162
|
-
|
|
163
|
-
<View style={styles.buttonContainer}>
|
|
164
|
-
<Button
|
|
165
|
-
title="Track Purchase Event"
|
|
166
|
-
onPress={trackPurchase}
|
|
167
|
-
disabled={!isInitialized}
|
|
168
|
-
/>
|
|
169
|
-
|
|
170
|
-
<Button
|
|
171
|
-
title="Track Pageview"
|
|
172
|
-
onPress={trackScreenView}
|
|
173
|
-
disabled={!isInitialized}
|
|
174
|
-
/>
|
|
175
|
-
|
|
176
|
-
<Button
|
|
177
|
-
title="Identify User"
|
|
178
|
-
onPress={identifyUser}
|
|
179
|
-
disabled={!isInitialized}
|
|
180
|
-
/>
|
|
181
|
-
|
|
182
|
-
<Button
|
|
183
|
-
title="Flush Events"
|
|
184
|
-
onPress={flushEvents}
|
|
185
|
-
disabled={!isInitialized}
|
|
186
|
-
/>
|
|
187
|
-
|
|
188
|
-
<Button
|
|
189
|
-
title="Reset User Data"
|
|
190
|
-
onPress={resetUser}
|
|
191
|
-
disabled={!isInitialized}
|
|
192
|
-
/>
|
|
193
|
-
|
|
194
|
-
<Button
|
|
195
|
-
title="Refresh Status"
|
|
196
|
-
onPress={updateStatus}
|
|
197
|
-
disabled={!isInitialized}
|
|
198
|
-
/>
|
|
199
|
-
</View>
|
|
200
|
-
</ScrollView>
|
|
201
|
-
</View>
|
|
202
|
-
);
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
const styles = StyleSheet.create({
|
|
206
|
-
container: {
|
|
207
|
-
flex: 1,
|
|
208
|
-
backgroundColor: '#f5f5f5',
|
|
209
|
-
},
|
|
210
|
-
scrollView: {
|
|
211
|
-
flex: 1,
|
|
212
|
-
},
|
|
213
|
-
content: {
|
|
214
|
-
padding: 20,
|
|
215
|
-
},
|
|
216
|
-
title: {
|
|
217
|
-
fontSize: 24,
|
|
218
|
-
fontWeight: 'bold',
|
|
219
|
-
textAlign: 'center',
|
|
220
|
-
marginBottom: 30,
|
|
221
|
-
color: '#333',
|
|
222
|
-
},
|
|
223
|
-
statusContainer: {
|
|
224
|
-
backgroundColor: '#fff',
|
|
225
|
-
padding: 15,
|
|
226
|
-
borderRadius: 8,
|
|
227
|
-
marginBottom: 20,
|
|
228
|
-
elevation: 2,
|
|
229
|
-
shadowOffset: { width: 0, height: 2 },
|
|
230
|
-
shadowOpacity: 0.1,
|
|
231
|
-
shadowRadius: 4,
|
|
232
|
-
},
|
|
233
|
-
statusTitle: {
|
|
234
|
-
fontSize: 18,
|
|
235
|
-
fontWeight: 'bold',
|
|
236
|
-
marginBottom: 10,
|
|
237
|
-
color: '#333',
|
|
238
|
-
},
|
|
239
|
-
statusText: {
|
|
240
|
-
fontSize: 14,
|
|
241
|
-
marginBottom: 5,
|
|
242
|
-
color: '#666',
|
|
243
|
-
fontFamily: 'monospace',
|
|
244
|
-
},
|
|
245
|
-
buttonContainer: {
|
|
246
|
-
gap: 10,
|
|
247
|
-
},
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
export default App;
|