mimz-react-native-tracker 1.0.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/src/utils.js ADDED
@@ -0,0 +1,180 @@
1
+ /**
2
+ * MimzUtils - Utility helpers for the Mimz React Native SDK
3
+ * Replaces browser-specific utilities (URL parsing, device info, etc.)
4
+ */
5
+
6
+ const { Platform, Dimensions } = require('react-native');
7
+
8
+ /**
9
+ * Generate a unique ID (replaces browser Date.now().toString(36) + random)
10
+ * @returns {string}
11
+ */
12
+ const generateUniqueId = () => {
13
+ return Date.now().toString(36) + Math.random().toString(36).substring(2);
14
+ };
15
+
16
+ /**
17
+ * Parse UTM parameters from a URL string (e.g., a deep link)
18
+ * In native apps, UTMs come from deep links, not the current URL bar
19
+ * @param {string} url - The deep link URL to parse
20
+ * @returns {object} - Object containing all found UTM and tracking params
21
+ */
22
+ const parseUtmFromUrl = (url) => {
23
+ const utmParams = {};
24
+
25
+ if (!url || typeof url !== 'string') return utmParams;
26
+
27
+ try {
28
+ // Handle both full URLs and query strings
29
+ let queryString = '';
30
+ if (url.includes('?')) {
31
+ queryString = url.split('?')[1];
32
+ } else if (url.includes('&') || url.includes('=')) {
33
+ queryString = url;
34
+ }
35
+
36
+ if (!queryString) return utmParams;
37
+
38
+ // Standard UTM parameters
39
+ const trackedFields = [
40
+ 'utm_source',
41
+ 'utm_medium',
42
+ 'utm_campaign',
43
+ 'utm_term',
44
+ 'utm_content',
45
+ 'utm_device',
46
+ 'utm_devicemodel',
47
+ // Additional tracking parameters
48
+ 'fbclid',
49
+ 'msclkid',
50
+ 'gclid',
51
+ ];
52
+
53
+ // Parse query string manually (no URLSearchParams in some RN environments)
54
+ const pairs = queryString.split('&');
55
+ pairs.forEach((pair) => {
56
+ const [key, value] = pair.split('=');
57
+ if (key && value) {
58
+ const decodedKey = decodeURIComponent(key.trim());
59
+ const decodedValue = decodeURIComponent(value.trim());
60
+ if (trackedFields.includes(decodedKey)) {
61
+ utmParams[decodedKey] = decodedValue;
62
+ }
63
+ }
64
+ });
65
+ } catch (error) {
66
+ console.warn('[MimzTracker] Error parsing UTM from URL:', error.message);
67
+ }
68
+
69
+ return utmParams;
70
+ };
71
+
72
+ /**
73
+ * Get device information (replaces browser userAgent-based detection)
74
+ * @returns {object} - Device info object
75
+ */
76
+ const getDeviceInfo = () => {
77
+ const { width, height } = Dimensions.get('window');
78
+ const pixelRatio = require('react-native').PixelRatio?.get() || 1;
79
+
80
+ return {
81
+ screenWidth: width,
82
+ screenHeight: height,
83
+ deviceType: Platform.isPad ? 'Tablet' : 'Mobile',
84
+ deviceModel: Platform.constants?.Model || Platform.constants?.Brand || 'Unknown',
85
+ os: Platform.OS === 'ios' ? 'iOS' : Platform.OS === 'android' ? 'Android' : Platform.OS,
86
+ osVersion: Platform.Version ? String(Platform.Version) : 'Unknown',
87
+ browser: 'Native App',
88
+ language: 'en', // Can be overridden via react-native-localize
89
+ colorDepth: 24,
90
+ pixelRatio: pixelRatio,
91
+ touchScreen: true,
92
+ userAgent: `MimzSDK/1.0 (${Platform.OS}; ${Platform.Version})`,
93
+ platform: 'react-native',
94
+ };
95
+ };
96
+
97
+ /**
98
+ * Determine traffic source from a referral URL (deep link referrer)
99
+ * @param {string} referrerUrl - The referrer/deep link source URL
100
+ * @returns {object} - Traffic source details
101
+ */
102
+ const getTrafficSource = (referrerUrl) => {
103
+ let source = 'Direct';
104
+ let trafficSource = 'Direct';
105
+
106
+ if (!referrerUrl || typeof referrerUrl !== 'string') {
107
+ return { trafficSource, source, organicSource: null, organicSourceStr: null };
108
+ }
109
+
110
+ const lowerUrl = referrerUrl.toLowerCase();
111
+
112
+ // Detect source from the referrer URL
113
+ if (lowerUrl.includes('google')) source = 'Google';
114
+ else if (lowerUrl.includes('facebook') || lowerUrl.includes('fb.com')) source = 'Facebook';
115
+ else if (lowerUrl.includes('instagram')) source = 'Instagram';
116
+ else if (lowerUrl.includes('twitter') || lowerUrl.includes('t.co')) source = 'Twitter';
117
+ else if (lowerUrl.includes('linkedin')) source = 'LinkedIn';
118
+ else if (lowerUrl.includes('youtube')) source = 'YouTube';
119
+ else if (lowerUrl.includes('snapchat')) source = 'Snapchat';
120
+ else if (lowerUrl.includes('pinterest')) source = 'Pinterest';
121
+ else if (lowerUrl.includes('bing')) source = 'Bing';
122
+ else if (lowerUrl.includes('yahoo')) source = 'Yahoo';
123
+ else if (lowerUrl.includes('duckduckgo')) source = 'Duckduckgo';
124
+ else if (lowerUrl.includes('tumblr')) source = 'Tumblr';
125
+ else source = 'Other';
126
+
127
+ // Classify traffic type
128
+ const searchEngines = ['Google', 'Bing', 'Yahoo', 'Duckduckgo'];
129
+ const socialPlatforms = ['Facebook', 'Twitter', 'Instagram', 'Snapchat', 'YouTube', 'Pinterest', 'LinkedIn', 'Tumblr'];
130
+
131
+ if (searchEngines.includes(source)) {
132
+ trafficSource = 'Organic';
133
+ } else if (socialPlatforms.includes(source)) {
134
+ trafficSource = 'Social';
135
+ } else if (source === 'Direct') {
136
+ trafficSource = 'Direct';
137
+ } else {
138
+ trafficSource = 'Referral';
139
+ }
140
+
141
+ return {
142
+ trafficSource,
143
+ source,
144
+ organicSource: trafficSource === 'Organic' ? referrerUrl : null,
145
+ organicSourceStr: trafficSource === 'Organic' ? source : null,
146
+ };
147
+ };
148
+
149
+ /**
150
+ * Get the user's IP address using an external service
151
+ * @returns {Promise<string>}
152
+ */
153
+ const getUserIp = async () => {
154
+ try {
155
+ const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
156
+ const timeoutId = controller ? setTimeout(() => controller.abort(), 2000) : null;
157
+
158
+ const response = await fetch('https://api.ipify.org?format=json', {
159
+ signal: controller?.signal,
160
+ });
161
+
162
+ if (timeoutId) clearTimeout(timeoutId);
163
+
164
+ if (response.ok) {
165
+ const data = await response.json();
166
+ return data?.ip || '0.0.0.0';
167
+ }
168
+ return '0.0.0.0';
169
+ } catch (error) {
170
+ return '0.0.0.0';
171
+ }
172
+ };
173
+
174
+ module.exports = {
175
+ generateUniqueId,
176
+ parseUtmFromUrl,
177
+ getDeviceInfo,
178
+ getTrafficSource,
179
+ getUserIp,
180
+ };