react-native-userleap 2.20.0 → 3.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/android/build.gradle +3 -2
- package/android/src/main/java/com/userleap/reactnative/UserLeapModule.java +218 -75
- package/index.d.ts +28 -3
- package/index.js +57 -12
- package/ios/UserLeapBindings.m +128 -31
- package/ios/UserLeapBindings.xcodeproj/project.xcworkspace/xcuserdata/kurt.hobson.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/package.json +8 -10
- package/react-native-userleap.podspec +1 -1
package/android/build.gradle
CHANGED
|
@@ -70,11 +70,12 @@ repositories {
|
|
|
70
70
|
}
|
|
71
71
|
dependencies {
|
|
72
72
|
implementation 'com.facebook.react:react-native:+' // From node_modules
|
|
73
|
-
|
|
73
|
+
implementation "androidx.webkit:webkit:1.8.0"
|
|
74
|
+
|
|
74
75
|
// Use conditional logic for local vs Maven
|
|
75
76
|
if (findProject(':userleap-android-sdk') != null) {
|
|
76
77
|
implementation project(':userleap-android-sdk')
|
|
77
78
|
} else {
|
|
78
|
-
implementation ("com.userleap:userleap-android-sdk:2.
|
|
79
|
+
implementation ("com.userleap:userleap-android-sdk:2.23.0") // update this version on android updates
|
|
79
80
|
}
|
|
80
81
|
}
|
|
@@ -1,20 +1,31 @@
|
|
|
1
1
|
package com.userleap.reactnative;
|
|
2
2
|
|
|
3
3
|
import android.app.Activity;
|
|
4
|
+
import android.util.Log;
|
|
4
5
|
|
|
5
6
|
import androidx.fragment.app.FragmentActivity;
|
|
6
7
|
|
|
8
|
+
import com.facebook.react.bridge.Arguments;
|
|
7
9
|
import com.facebook.react.bridge.Callback;
|
|
8
10
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
9
11
|
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
|
10
12
|
import com.facebook.react.bridge.ReactMethod;
|
|
11
13
|
import com.facebook.react.bridge.ReadableArray;
|
|
12
14
|
import com.facebook.react.bridge.ReadableMap;
|
|
13
|
-
|
|
15
|
+
import com.facebook.react.bridge.WritableMap;
|
|
16
|
+
import com.userleap.EventListener;
|
|
17
|
+
import com.userleap.EventName;
|
|
18
|
+
import com.userleap.EventPayload;
|
|
19
|
+
import com.userleap.SprigEvent;
|
|
20
|
+
import com.userleap.SprigSurveyResult;
|
|
14
21
|
import com.userleap.SurveyState;
|
|
15
22
|
import com.userleap.UserLeap;
|
|
16
23
|
|
|
24
|
+
import org.json.JSONException;
|
|
25
|
+
import org.json.JSONObject;
|
|
26
|
+
|
|
17
27
|
import java.util.HashMap;
|
|
28
|
+
import java.util.Iterator;
|
|
18
29
|
import java.util.List;
|
|
19
30
|
import java.util.Map;
|
|
20
31
|
import java.util.Objects;
|
|
@@ -25,19 +36,10 @@ import javax.annotation.Nullable;
|
|
|
25
36
|
import kotlin.Unit;
|
|
26
37
|
import kotlin.jvm.functions.Function1;
|
|
27
38
|
|
|
28
|
-
import android.util.Log;
|
|
29
|
-
|
|
30
|
-
import com.userleap.EventListener;
|
|
31
|
-
import com.userleap.EventName;
|
|
32
|
-
import com.userleap.SprigEvent;
|
|
33
|
-
import com.userleap.SprigLoggingLevel;
|
|
34
|
-
import com.userleap.UserLeap;
|
|
35
|
-
|
|
36
|
-
import kotlin.Unit;
|
|
37
|
-
import kotlin.jvm.functions.Function1;
|
|
38
|
-
|
|
39
39
|
public class UserLeapModule extends ReactContextBaseJavaModule {
|
|
40
40
|
|
|
41
|
+
private static final String TAG = "UserLeapModule";
|
|
42
|
+
|
|
41
43
|
private final ReactApplicationContext reactContext;
|
|
42
44
|
|
|
43
45
|
public UserLeapModule(ReactApplicationContext reactContext) {
|
|
@@ -50,6 +52,115 @@ public class UserLeapModule extends ReactContextBaseJavaModule {
|
|
|
50
52
|
return "UserLeapBindings";
|
|
51
53
|
}
|
|
52
54
|
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
// Bridge helpers
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Converts UPPER_SNAKE_CASE to camelCase to match the iOS event naming
|
|
61
|
+
* convention expected by the JS layer.
|
|
62
|
+
* e.g. "SURVEY_WILL_PRESENT" -> "surveyWillPresent"
|
|
63
|
+
*/
|
|
64
|
+
private String toCamelCase(String upperSnakeCase) {
|
|
65
|
+
String[] parts = upperSnakeCase.toLowerCase().split("_");
|
|
66
|
+
StringBuilder sb = new StringBuilder(parts[0]);
|
|
67
|
+
for (int i = 1; i < parts.length; i++) {
|
|
68
|
+
sb.append(Character.toUpperCase(parts[i].charAt(0)));
|
|
69
|
+
sb.append(parts[i].substring(1));
|
|
70
|
+
}
|
|
71
|
+
return sb.toString();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Shallow-converts a JSONObject to a WritableMap for passing across the RN bridge.
|
|
76
|
+
*/
|
|
77
|
+
private WritableMap jsonObjectToWritableMap(@Nullable JSONObject json) {
|
|
78
|
+
WritableMap map = Arguments.createMap();
|
|
79
|
+
if (json == null) {
|
|
80
|
+
return map;
|
|
81
|
+
}
|
|
82
|
+
Iterator<String> keys = json.keys();
|
|
83
|
+
while (keys.hasNext()) {
|
|
84
|
+
String key = keys.next();
|
|
85
|
+
try {
|
|
86
|
+
Object value = json.get(key);
|
|
87
|
+
if (value instanceof String) {
|
|
88
|
+
map.putString(key, (String) value);
|
|
89
|
+
} else if (value instanceof Boolean) {
|
|
90
|
+
map.putBoolean(key, (Boolean) value);
|
|
91
|
+
} else if (value instanceof Integer) {
|
|
92
|
+
map.putInt(key, (Integer) value);
|
|
93
|
+
} else if (value instanceof Double) {
|
|
94
|
+
map.putDouble(key, (Double) value);
|
|
95
|
+
} else if (value instanceof JSONObject) {
|
|
96
|
+
map.putMap(key, jsonObjectToWritableMap((JSONObject) value));
|
|
97
|
+
} else if (value == JSONObject.NULL) {
|
|
98
|
+
map.putNull(key);
|
|
99
|
+
} else {
|
|
100
|
+
map.putString(key, value.toString());
|
|
101
|
+
}
|
|
102
|
+
} catch (JSONException e) {
|
|
103
|
+
Log.w(TAG, "Failed to convert key '" + key + "' from SprigEvent data", e);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return map;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Converts a SprigSurveyResult to a WritableMap for passing across the RN bridge.
|
|
111
|
+
* Returns { surveyState: string, surveyId: int }
|
|
112
|
+
*/
|
|
113
|
+
private WritableMap surveyResultToWritableMap(SprigSurveyResult surveyResult) {
|
|
114
|
+
WritableMap resultMap = Arguments.createMap();
|
|
115
|
+
resultMap.putString("surveyState", surveyResult.getSurveyState().name());
|
|
116
|
+
if (surveyResult.getSurveyId() != null) {
|
|
117
|
+
resultMap.putInt("surveyId", surveyResult.getSurveyId());
|
|
118
|
+
} else {
|
|
119
|
+
resultMap.putInt("surveyId", 0);
|
|
120
|
+
}
|
|
121
|
+
return resultMap;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Wraps a RN Callback as a Function1<SprigSurveyResult, Unit> for the EventPayload API.
|
|
126
|
+
* Returns null if the callback is null.
|
|
127
|
+
*/
|
|
128
|
+
private @Nullable Function1<SprigSurveyResult, Unit> wrapResultCallback(@Nullable final Callback callback) {
|
|
129
|
+
if (callback == null) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
return new Function1<SprigSurveyResult, Unit>() {
|
|
133
|
+
@Override
|
|
134
|
+
public Unit invoke(SprigSurveyResult surveyResult) {
|
|
135
|
+
callback.invoke(surveyResultToWritableMap(surveyResult));
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
private Map<String, String> stringifyMap(ReadableMap map) {
|
|
142
|
+
Map<String, String> stringifiedMap = new HashMap<>();
|
|
143
|
+
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
|
|
144
|
+
stringifiedMap = map.toHashMap().entrySet().stream()
|
|
145
|
+
.filter(m -> m.getKey() != null && m.getValue() != null)
|
|
146
|
+
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().toString()));
|
|
147
|
+
}
|
|
148
|
+
return stringifiedMap;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private @Nullable FragmentActivity getFragmentActivity() {
|
|
152
|
+
Activity activity = getCurrentActivity();
|
|
153
|
+
if (activity instanceof FragmentActivity) {
|
|
154
|
+
return (FragmentActivity) activity;
|
|
155
|
+
} else {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// ---------------------------------------------------------------------------
|
|
161
|
+
// SDK properties
|
|
162
|
+
// ---------------------------------------------------------------------------
|
|
163
|
+
|
|
53
164
|
@ReactMethod(isBlockingSynchronousMethod = true)
|
|
54
165
|
public int visitorIdentifier() {
|
|
55
166
|
final Integer visitorIdentifierObject = UserLeap.INSTANCE.getVisitorIdentifier();
|
|
@@ -67,15 +178,16 @@ public class UserLeapModule extends ReactContextBaseJavaModule {
|
|
|
67
178
|
return UserLeap.INSTANCE.getSdkVersion();
|
|
68
179
|
}
|
|
69
180
|
|
|
181
|
+
// ---------------------------------------------------------------------------
|
|
182
|
+
// Configuration
|
|
183
|
+
// ---------------------------------------------------------------------------
|
|
184
|
+
|
|
70
185
|
@ReactMethod
|
|
71
186
|
public void configure(String environment, ReadableMap configuration) {
|
|
72
|
-
|
|
73
187
|
UserLeap.INSTANCE.addEventListener(EventName.LOGGING_EVENT, new EventListener() {
|
|
74
188
|
@Override
|
|
75
189
|
public void onEvent(SprigEvent event) {
|
|
76
|
-
|
|
77
190
|
String tag = "SprigLoggingEvent";
|
|
78
|
-
|
|
79
191
|
switch (event.getLogLevel()) {
|
|
80
192
|
case INFO:
|
|
81
193
|
Log.i(tag, event.getLogMessage());
|
|
@@ -95,13 +207,17 @@ public class UserLeapModule extends ReactContextBaseJavaModule {
|
|
|
95
207
|
});
|
|
96
208
|
|
|
97
209
|
UserLeap.INSTANCE.configure(
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
210
|
+
reactContext,
|
|
211
|
+
environment,
|
|
212
|
+
stringifyMap(configuration),
|
|
213
|
+
getFragmentActivity()
|
|
102
214
|
);
|
|
103
215
|
}
|
|
104
216
|
|
|
217
|
+
// ---------------------------------------------------------------------------
|
|
218
|
+
// Deprecated track methods (return SurveyState string)
|
|
219
|
+
// ---------------------------------------------------------------------------
|
|
220
|
+
|
|
105
221
|
@ReactMethod
|
|
106
222
|
public void track(String event, final Callback surveyStateCallback) {
|
|
107
223
|
trackAndIdentify(event, null, null, surveyStateCallback);
|
|
@@ -109,19 +225,17 @@ public class UserLeapModule extends ReactContextBaseJavaModule {
|
|
|
109
225
|
|
|
110
226
|
@ReactMethod
|
|
111
227
|
public void trackWithProperties(String event, String userId, String partnerAnonymousId, ReadableMap properties, final Callback surveyStateCallback) {
|
|
112
|
-
|
|
228
|
+
if (surveyStateCallback == null) {
|
|
113
229
|
UserLeap.INSTANCE.track(event, userId, partnerAnonymousId, stringifyMap(properties));
|
|
114
|
-
|
|
230
|
+
} else {
|
|
115
231
|
UserLeap.INSTANCE.track(event, userId, partnerAnonymousId, stringifyMap(properties), new Function1<SurveyState, Unit>() {
|
|
116
232
|
@Override
|
|
117
233
|
public Unit invoke(SurveyState surveyState) {
|
|
118
|
-
|
|
119
|
-
surveyStateCallback.invoke(surveyState.name());
|
|
120
|
-
}
|
|
234
|
+
surveyStateCallback.invoke(surveyState.name());
|
|
121
235
|
return null;
|
|
122
236
|
}
|
|
123
|
-
});
|
|
124
|
-
|
|
237
|
+
});
|
|
238
|
+
}
|
|
125
239
|
}
|
|
126
240
|
|
|
127
241
|
@ReactMethod
|
|
@@ -139,50 +253,46 @@ public class UserLeapModule extends ReactContextBaseJavaModule {
|
|
|
139
253
|
}
|
|
140
254
|
}
|
|
141
255
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
@ReactMethod
|
|
148
|
-
public void setVisitorAttribute(String key, String value) {
|
|
149
|
-
UserLeap.INSTANCE.setVisitorAttribute(key, value);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
@ReactMethod
|
|
153
|
-
public void setVisitorAttributes(ReadableMap attributes) {
|
|
154
|
-
UserLeap.INSTANCE.setVisitorAttributes(stringifyMap(attributes));
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
@ReactMethod
|
|
158
|
-
public void setVisitorAttributesAndIdentify(ReadableMap attributes, String userId, String partnerAnonymousId) {
|
|
159
|
-
UserLeap.INSTANCE.setVisitorAttributes(stringifyMap(attributes), userId, partnerAnonymousId);
|
|
160
|
-
}
|
|
256
|
+
// ---------------------------------------------------------------------------
|
|
257
|
+
// New track methods (return SprigSurveyResult via EventPayload)
|
|
258
|
+
// ---------------------------------------------------------------------------
|
|
161
259
|
|
|
162
260
|
@ReactMethod
|
|
163
|
-
public void
|
|
164
|
-
|
|
165
|
-
List<String> attributeStrings = attributes.toArrayList().stream()
|
|
166
|
-
.map(object -> Objects.toString(object, null))
|
|
167
|
-
.collect(Collectors.toList());
|
|
168
|
-
UserLeap.INSTANCE.removeVisitorAttributes(attributeStrings);
|
|
169
|
-
}
|
|
261
|
+
public void trackEvent(String event, final Callback surveyStateCallback) {
|
|
262
|
+
trackEventAndIdentify(event, null, null, surveyStateCallback);
|
|
170
263
|
}
|
|
171
264
|
|
|
172
265
|
@ReactMethod
|
|
173
|
-
public void
|
|
174
|
-
|
|
266
|
+
public void trackEventWithProperties(String event, String userId, String partnerAnonymousId, ReadableMap properties, final Callback surveyStateCallback) {
|
|
267
|
+
EventPayload payload = new EventPayload(
|
|
268
|
+
event,
|
|
269
|
+
userId,
|
|
270
|
+
partnerAnonymousId,
|
|
271
|
+
stringifyMap(properties),
|
|
272
|
+
wrapResultCallback(surveyStateCallback),
|
|
273
|
+
null, // shouldShowSurveyCallback
|
|
274
|
+
null // deprecated callback
|
|
275
|
+
);
|
|
276
|
+
UserLeap.INSTANCE.track(payload);
|
|
175
277
|
}
|
|
176
278
|
|
|
177
279
|
@ReactMethod
|
|
178
|
-
public void
|
|
179
|
-
|
|
280
|
+
public void trackEventAndIdentify(String event, String userId, String partnerAnonymousId, final Callback surveyStateCallback) {
|
|
281
|
+
EventPayload payload = new EventPayload(
|
|
282
|
+
event,
|
|
283
|
+
userId,
|
|
284
|
+
partnerAnonymousId,
|
|
285
|
+
null, // properties
|
|
286
|
+
wrapResultCallback(surveyStateCallback),
|
|
287
|
+
null, // shouldShowSurveyCallback
|
|
288
|
+
null // deprecated callback
|
|
289
|
+
);
|
|
290
|
+
UserLeap.INSTANCE.track(payload);
|
|
180
291
|
}
|
|
181
292
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}
|
|
293
|
+
// ---------------------------------------------------------------------------
|
|
294
|
+
// Track and present
|
|
295
|
+
// ---------------------------------------------------------------------------
|
|
186
296
|
|
|
187
297
|
@ReactMethod
|
|
188
298
|
public void trackAndPresent(String event) {
|
|
@@ -194,6 +304,10 @@ public class UserLeapModule extends ReactContextBaseJavaModule {
|
|
|
194
304
|
UserLeap.INSTANCE.trackAndPresent(event, userId, partnerAnonymousId, getFragmentActivity());
|
|
195
305
|
}
|
|
196
306
|
|
|
307
|
+
// ---------------------------------------------------------------------------
|
|
308
|
+
// Survey presentation
|
|
309
|
+
// ---------------------------------------------------------------------------
|
|
310
|
+
|
|
197
311
|
@ReactMethod
|
|
198
312
|
public void presentSurvey() {
|
|
199
313
|
UserLeap.INSTANCE.presentSurvey(null);
|
|
@@ -214,23 +328,52 @@ public class UserLeapModule extends ReactContextBaseJavaModule {
|
|
|
214
328
|
UserLeap.INSTANCE.unpauseDisplayingSurveys();
|
|
215
329
|
}
|
|
216
330
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
}
|
|
331
|
+
// ---------------------------------------------------------------------------
|
|
332
|
+
// User identity & attributes
|
|
333
|
+
// ---------------------------------------------------------------------------
|
|
334
|
+
|
|
335
|
+
@ReactMethod
|
|
336
|
+
public void setEmailAddress(String emailAddress) {
|
|
337
|
+
UserLeap.INSTANCE.setEmailAddress(emailAddress);
|
|
225
338
|
}
|
|
226
339
|
|
|
227
|
-
|
|
228
|
-
|
|
340
|
+
@ReactMethod
|
|
341
|
+
public void setVisitorAttribute(String key, String value) {
|
|
342
|
+
UserLeap.INSTANCE.setVisitorAttribute(key, value);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
@ReactMethod
|
|
346
|
+
public void setVisitorAttributes(ReadableMap attributes) {
|
|
347
|
+
UserLeap.INSTANCE.setVisitorAttributes(stringifyMap(attributes));
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
@ReactMethod
|
|
351
|
+
public void setVisitorAttributesAndIdentify(ReadableMap attributes, String userId, String partnerAnonymousId) {
|
|
352
|
+
UserLeap.INSTANCE.setVisitorAttributes(stringifyMap(attributes), userId, partnerAnonymousId);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
@ReactMethod
|
|
356
|
+
public void removeVisitorAttributes(ReadableArray attributes) {
|
|
229
357
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
358
|
+
List<String> attributeStrings = attributes.toArrayList().stream()
|
|
359
|
+
.map(object -> Objects.toString(object, null))
|
|
360
|
+
.collect(Collectors.toList());
|
|
361
|
+
UserLeap.INSTANCE.removeVisitorAttributes(attributeStrings);
|
|
233
362
|
}
|
|
234
|
-
return stringifiedMap;
|
|
235
363
|
}
|
|
236
|
-
|
|
364
|
+
|
|
365
|
+
@ReactMethod
|
|
366
|
+
public void setPreviewKey(String previewKey) {
|
|
367
|
+
UserLeap.INSTANCE.setPreviewKey(previewKey);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
@ReactMethod
|
|
371
|
+
public void setUserIdentifier(String identifier) {
|
|
372
|
+
UserLeap.INSTANCE.setUserIdentifier(identifier);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
@ReactMethod
|
|
376
|
+
public void logout() {
|
|
377
|
+
UserLeap.INSTANCE.logout();
|
|
378
|
+
}
|
|
379
|
+
}
|
package/index.d.ts
CHANGED
|
@@ -4,15 +4,43 @@ declare namespace UserLeap {
|
|
|
4
4
|
DISABLED: string;
|
|
5
5
|
NO_SURVEY: string;
|
|
6
6
|
};
|
|
7
|
+
|
|
7
8
|
function visitorIdentifier(): number;
|
|
8
9
|
function visitorIdentifierString(): string;
|
|
9
10
|
function sdkVersion(): string;
|
|
10
11
|
function configure(environment: string, configuration?: {[key: string]: any}): void;
|
|
11
12
|
function setPreviewKey(previewKey: string): void;
|
|
12
13
|
function presentSurvey(): void;
|
|
14
|
+
/**
|
|
15
|
+
* @deprecated This function is outdated. Use `trackEvent()` instead.
|
|
16
|
+
*/
|
|
13
17
|
function track(event: string, surveyStateCallback: ((surveyState: string) => void)): void;
|
|
18
|
+
/**
|
|
19
|
+
* @deprecated This function is outdated. Use `trackEventWithProperties()` instead.
|
|
20
|
+
*/
|
|
14
21
|
function trackWithProperties(event: string, userId: string | undefined, partnerAnonymousId: string | undefined, properties: {[key: string]: any}, surveyStateCallback: ((surveyState: string) => void)): void;
|
|
22
|
+
/**
|
|
23
|
+
* @deprecated This function is outdated. Use `trackEventAndIdentify()` instead.
|
|
24
|
+
*/
|
|
15
25
|
function trackAndIdentify(event: string, userId: string | undefined, partnerAnonymousId: string | undefined, surveyStateCallback: ((surveyState: string) => void)): void;
|
|
26
|
+
function trackEvent(
|
|
27
|
+
event: string,
|
|
28
|
+
surveyResultCallback: (result: { surveyState: string; surveyId: number }) => void
|
|
29
|
+
): void;
|
|
30
|
+
function trackEventWithProperties(
|
|
31
|
+
event: string,
|
|
32
|
+
userId: string | undefined,
|
|
33
|
+
partnerAnonymousId: string | undefined,
|
|
34
|
+
properties: { [key: string]: any },
|
|
35
|
+
surveyResultCallback: (result: { surveyState: string; surveyId: number }) => void
|
|
36
|
+
): void;
|
|
37
|
+
|
|
38
|
+
function trackEventAndIdentify(
|
|
39
|
+
event: string,
|
|
40
|
+
userId: string | undefined,
|
|
41
|
+
partnerAnonymousId: string | undefined,
|
|
42
|
+
surveyResultCallback: (result: { surveyState: string; surveyId: number }) => void
|
|
43
|
+
): void;
|
|
16
44
|
function setEmailAddress(emailAddress: string): void;
|
|
17
45
|
function setVisitorAttribute(key: string, value: string): void;
|
|
18
46
|
function setVisitorAttributes(attributes: {[key: string]: string}): void;
|
|
@@ -25,8 +53,5 @@ declare namespace UserLeap {
|
|
|
25
53
|
function unpauseDisplayingSurveys(): void;
|
|
26
54
|
function trackAndPresent(event: string): void;
|
|
27
55
|
function trackIdentifyAndPresent(event: string, userId: string | undefined, partnerAnonymousId: string | undefined): void;
|
|
28
|
-
// Uncomment for UI testing
|
|
29
|
-
// function renderSnapshotForUITest(name: string, maskingLevel: string)
|
|
30
|
-
|
|
31
56
|
}
|
|
32
57
|
export default UserLeap;
|
package/index.js
CHANGED
|
@@ -8,6 +8,7 @@ const SurveyState = {
|
|
|
8
8
|
NO_SURVEY: "NO_SURVEY",
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
+
|
|
11
12
|
const stringifyAttributes = (attributes) => {
|
|
12
13
|
if (!(attributes instanceof Object && attributes.constructor === Object))
|
|
13
14
|
return {};
|
|
@@ -21,7 +22,7 @@ const isValidPlatform = () => {
|
|
|
21
22
|
//Platform.Version is a number for android and string for ios
|
|
22
23
|
return (
|
|
23
24
|
(Platform.OS === "android" && String(Platform.Version) >= "21") ||
|
|
24
|
-
(Platform.OS === "ios" && String(Platform.Version) >= "
|
|
25
|
+
(Platform.OS === "ios" && String(Platform.Version) >= "15.0")
|
|
25
26
|
);
|
|
26
27
|
};
|
|
27
28
|
|
|
@@ -35,7 +36,7 @@ const visitorIdentifier = () => {
|
|
|
35
36
|
|
|
36
37
|
const sdkVersion = () => {
|
|
37
38
|
if (Platform.OS === "ios") {
|
|
38
|
-
if (String(Platform.Version) >= "
|
|
39
|
+
if (String(Platform.Version) >= "15.0") {
|
|
39
40
|
return NativeModules.UserLeapBindings.sdkVersion();
|
|
40
41
|
}
|
|
41
42
|
} else {
|
|
@@ -81,12 +82,18 @@ const presentSurvey = () => {
|
|
|
81
82
|
}
|
|
82
83
|
};
|
|
83
84
|
|
|
85
|
+
/**
|
|
86
|
+
* @deprecated This function is outdated. Use `trackEvent()` instead.
|
|
87
|
+
*/
|
|
84
88
|
const track = (event, surveyStateCallback) => {
|
|
85
89
|
if (isValidPlatform()) {
|
|
86
90
|
NativeModules.UserLeapBindings.track(event, surveyStateCallback);
|
|
87
91
|
}
|
|
88
92
|
};
|
|
89
93
|
|
|
94
|
+
/**
|
|
95
|
+
* @deprecated This function is outdated. Use `trackEventWithProperties()` instead.
|
|
96
|
+
*/
|
|
90
97
|
const trackWithProperties = (
|
|
91
98
|
event,
|
|
92
99
|
userId,
|
|
@@ -105,6 +112,9 @@ const trackWithProperties = (
|
|
|
105
112
|
}
|
|
106
113
|
};
|
|
107
114
|
|
|
115
|
+
/**
|
|
116
|
+
* @deprecated This function is outdated. Use `trackEventAndIdentify()` instead.
|
|
117
|
+
*/
|
|
108
118
|
const trackAndIdentify = (
|
|
109
119
|
event,
|
|
110
120
|
userId,
|
|
@@ -121,6 +131,46 @@ const trackAndIdentify = (
|
|
|
121
131
|
}
|
|
122
132
|
};
|
|
123
133
|
|
|
134
|
+
const trackEvent = (event, surveyResultCallback) => {
|
|
135
|
+
if (isValidPlatform()) {
|
|
136
|
+
NativeModules.UserLeapBindings.trackEvent(event, surveyResultCallback);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const trackEventWithProperties = (
|
|
141
|
+
event,
|
|
142
|
+
userId,
|
|
143
|
+
partnerAnonymousId,
|
|
144
|
+
properties,
|
|
145
|
+
surveyResultCallback
|
|
146
|
+
) => {
|
|
147
|
+
if (isValidPlatform()) {
|
|
148
|
+
NativeModules.UserLeapBindings.trackEventWithProperties(
|
|
149
|
+
event,
|
|
150
|
+
userId,
|
|
151
|
+
partnerAnonymousId,
|
|
152
|
+
properties,
|
|
153
|
+
surveyResultCallback
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const trackEventAndIdentify = (
|
|
159
|
+
event,
|
|
160
|
+
userId,
|
|
161
|
+
partnerAnonynmousId,
|
|
162
|
+
surveyResultCallback
|
|
163
|
+
) => {
|
|
164
|
+
if (isValidPlatform()) {
|
|
165
|
+
NativeModules.UserLeapBindings.trackEventAndIdentify(
|
|
166
|
+
event,
|
|
167
|
+
userId,
|
|
168
|
+
partnerAnonynmousId,
|
|
169
|
+
surveyResultCallback
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
|
|
124
174
|
const setEmailAddress = (emailAddress) => {
|
|
125
175
|
if (isValidPlatform()) {
|
|
126
176
|
NativeModules.UserLeapBindings.setEmailAddress(emailAddress);
|
|
@@ -207,15 +257,7 @@ const trackIdentifyAndPresent = (event, userId, partnerAnonynmousId) => {
|
|
|
207
257
|
}
|
|
208
258
|
};
|
|
209
259
|
|
|
210
|
-
// Uncomment for UI testing
|
|
211
|
-
// const renderSnapshotForUITest = (name, maskingLevel) => {
|
|
212
|
-
// if (isValidPlatform()) {
|
|
213
|
-
// NativeModules.UserLeapBindings.renderSnapshotForUITest(name, maskingLevel);
|
|
214
|
-
// }
|
|
215
|
-
// }
|
|
216
|
-
|
|
217
260
|
const UserLeap = {
|
|
218
|
-
SurveyState,
|
|
219
261
|
visitorIdentifier,
|
|
220
262
|
visitorIdentifierString,
|
|
221
263
|
sdkVersion,
|
|
@@ -225,6 +267,9 @@ const UserLeap = {
|
|
|
225
267
|
track,
|
|
226
268
|
trackWithProperties,
|
|
227
269
|
trackAndIdentify,
|
|
270
|
+
trackEvent,
|
|
271
|
+
trackEventWithProperties,
|
|
272
|
+
trackEventAndIdentify,
|
|
228
273
|
setEmailAddress,
|
|
229
274
|
setVisitorAttribute,
|
|
230
275
|
setVisitorAttributes,
|
|
@@ -237,8 +282,8 @@ const UserLeap = {
|
|
|
237
282
|
dismissActiveSurvey,
|
|
238
283
|
pauseDisplayingSurveys,
|
|
239
284
|
unpauseDisplayingSurveys,
|
|
240
|
-
// Uncomment for UI testing
|
|
241
|
-
// renderSnapshotForUITest,
|
|
242
285
|
};
|
|
243
286
|
|
|
287
|
+
UserLeap.SurveyState = SurveyState;
|
|
288
|
+
|
|
244
289
|
export default UserLeap;
|
package/ios/UserLeapBindings.m
CHANGED
|
@@ -18,6 +18,13 @@
|
|
|
18
18
|
return dispatch_get_main_queue();
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
-(NSDictionary *) parseSurveyResult:(SprigSurveyResult *)result {
|
|
22
|
+
SurveyState state = [result surveyState];
|
|
23
|
+
NSString *surveyStateString = [self getSurveyState:state];
|
|
24
|
+
NSInteger surveyId = [result surveyId];
|
|
25
|
+
return @{@"surveyState": surveyStateString, @"surveyId": @(surveyId)};
|
|
26
|
+
}
|
|
27
|
+
|
|
21
28
|
- (NSString *)getSurveyState:(SurveyState)surveyState
|
|
22
29
|
{
|
|
23
30
|
NSString *surveyStateBinding = @"NO_SURVEY";
|
|
@@ -31,6 +38,9 @@
|
|
|
31
38
|
case SurveyStateNoSurvey:
|
|
32
39
|
surveyStateBinding = @"NO_SURVEY";
|
|
33
40
|
break;
|
|
41
|
+
case SurveyStatePreviousSurveyReady:
|
|
42
|
+
surveyStateBinding = @"PREVIOUS_SURVEY_READY";
|
|
43
|
+
break;
|
|
34
44
|
}
|
|
35
45
|
return surveyStateBinding;
|
|
36
46
|
}
|
|
@@ -58,6 +68,7 @@ RCT_EXPORT_METHOD(configure:(NSString *)environmentId configuration:(NSDictionar
|
|
|
58
68
|
[[UserLeap shared] _passWithRnExtractor:self];
|
|
59
69
|
}
|
|
60
70
|
|
|
71
|
+
|
|
61
72
|
RCT_EXPORT_METHOD(setPreviewKey:(NSString *)previewKey)
|
|
62
73
|
{
|
|
63
74
|
[[UserLeap shared] setPreviewKey:previewKey];
|
|
@@ -68,6 +79,7 @@ RCT_EXPORT_METHOD(presentSurvey)
|
|
|
68
79
|
[[UserLeap shared] presentSurveyFrom:RCTPresentedViewController()];
|
|
69
80
|
}
|
|
70
81
|
|
|
82
|
+
/// Use trackEvent instead of track
|
|
71
83
|
RCT_EXPORT_METHOD(track:(NSString *)eventName
|
|
72
84
|
surveyStateCallback:(RCTResponseSenderBlock)callback)
|
|
73
85
|
{
|
|
@@ -80,33 +92,50 @@ RCT_EXPORT_METHOD(track:(NSString *)eventName
|
|
|
80
92
|
}
|
|
81
93
|
}
|
|
82
94
|
|
|
95
|
+
RCT_EXPORT_METHOD(trackEvent:(NSString *)eventName
|
|
96
|
+
surveyResultCallback:(RCTResponseSenderBlock)callback)
|
|
97
|
+
{
|
|
98
|
+
EventPayload *payload = [[EventPayload alloc] initWithEventName:eventName userId:nil partnerAnonymousId:nil properties:nil handler:nil resultHandler:^(SprigSurveyResult * result) {
|
|
99
|
+
if (callback != nil) {
|
|
100
|
+
callback(@[[self parseSurveyResult:result]]);
|
|
101
|
+
}
|
|
102
|
+
}];
|
|
103
|
+
[[UserLeap shared] trackWithPayload: payload];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/// Use trackEventWithProperties instead of trackWithProperties
|
|
83
107
|
RCT_EXPORT_METHOD(trackWithProperties:(NSString *)eventName
|
|
84
108
|
userId:(NSString * _Nullable)userId
|
|
85
109
|
partnerAnonymousId:(NSString * _Nullable)partnerAnonymousId
|
|
86
110
|
properties: (NSDictionary *)properties
|
|
87
111
|
surveyStateCallback:(RCTResponseSenderBlock)callback)
|
|
88
112
|
{
|
|
89
|
-
if (callback != nil) {
|
|
90
113
|
[[UserLeap shared] trackWithEventName:eventName userId:userId partnerAnonymousId:partnerAnonymousId properties:properties handler:^(enum SurveyState surveyState) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
114
|
+
callback(@[[self getSurveyState:surveyState]]);
|
|
115
|
+
}];
|
|
116
|
+
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
RCT_EXPORT_METHOD(trackEventWithProperties:(NSString *)eventName
|
|
120
|
+
userId:(NSString * _Nullable)userId
|
|
121
|
+
partnerAnonymousId:(NSString * _Nullable)partnerAnonymousId
|
|
122
|
+
properties: (NSDictionary *)properties
|
|
123
|
+
surveyResultCallback:(RCTResponseSenderBlock)callback)
|
|
124
|
+
{
|
|
125
|
+
EventPayload *payload = [[EventPayload alloc] initWithEventName:eventName
|
|
126
|
+
userId:userId
|
|
127
|
+
partnerAnonymousId:partnerAnonymousId
|
|
128
|
+
properties:properties
|
|
129
|
+
handler:nil
|
|
130
|
+
resultHandler:^(SprigSurveyResult * result) {
|
|
131
|
+
if (callback != nil) {
|
|
132
|
+
callback(@[[self parseSurveyResult:result]]);
|
|
102
133
|
}
|
|
103
|
-
callback(@[surveyStateBinding]);
|
|
104
134
|
}];
|
|
105
|
-
|
|
106
|
-
[[UserLeap shared] trackWithEventName:eventName userId:userId partnerAnonymousId:partnerAnonymousId properties:properties handler:nil];
|
|
107
|
-
}
|
|
135
|
+
[[UserLeap shared] trackWithPayload: payload];
|
|
108
136
|
}
|
|
109
137
|
|
|
138
|
+
/// Use trackEventAndIdentify instead of trackAndIdentify
|
|
110
139
|
RCT_EXPORT_METHOD(trackAndIdentify:(NSString *)eventName
|
|
111
140
|
userId:(NSString *)userId
|
|
112
141
|
partnerAnonymousId:(NSString *)partnerAnonymousId
|
|
@@ -119,7 +148,24 @@ RCT_EXPORT_METHOD(trackAndIdentify:(NSString *)eventName
|
|
|
119
148
|
} else {
|
|
120
149
|
[[UserLeap shared] trackWithEventName:eventName userId:userId partnerAnonymousId:partnerAnonymousId handler:nil];
|
|
121
150
|
}
|
|
122
|
-
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
RCT_EXPORT_METHOD(trackEventAndIdentify:(NSString *)eventName
|
|
154
|
+
userId:(NSString *)userId
|
|
155
|
+
partnerAnonymousId:(NSString *)partnerAnonymousId
|
|
156
|
+
surveyResultCallback:(RCTResponseSenderBlock)callback)
|
|
157
|
+
{
|
|
158
|
+
EventPayload *payload = [[EventPayload alloc] initWithEventName:eventName
|
|
159
|
+
userId:userId
|
|
160
|
+
partnerAnonymousId:partnerAnonymousId
|
|
161
|
+
properties:nil
|
|
162
|
+
handler:nil
|
|
163
|
+
resultHandler:^(SprigSurveyResult * result) {
|
|
164
|
+
if (callback != nil) {
|
|
165
|
+
callback(@[[self parseSurveyResult:result]]);
|
|
166
|
+
}
|
|
167
|
+
}];
|
|
168
|
+
[[UserLeap shared] trackWithPayload: payload];
|
|
123
169
|
}
|
|
124
170
|
|
|
125
171
|
RCT_EXPORT_METHOD(setEmailAddress:(NSString *)emailAddress)
|
|
@@ -168,21 +214,54 @@ RCT_EXPORT_METHOD(trackIdentifyAndPresent:(NSString *)eventName userId:(NSString
|
|
|
168
214
|
}
|
|
169
215
|
|
|
170
216
|
- (_SGRNTextProperties *)textPropertiesFromView:(UIView * _Nonnull)passedView {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
217
|
+
|
|
218
|
+
// Legacy for pre new arch.
|
|
219
|
+
if ([passedView isKindOfClass:[RCTTextView class]]) {
|
|
220
|
+
RCTUIManager* uiManager = [self.bridge moduleForClass:[RCTUIManager class]];
|
|
221
|
+
RCTTextView *textView = (RCTTextView *)passedView;
|
|
222
|
+
__block _SGRNTextProperties *textProperties = [[_SGRNTextProperties alloc] init];
|
|
223
|
+
dispatch_sync(RCTGetUIManagerQueue(), ^{
|
|
224
|
+
RCTShadowView *shadowView = [uiManager shadowViewForReactTag:textView.reactTag];
|
|
225
|
+
if ([shadowView isKindOfClass:[RCTTextShadowView class]]) {
|
|
226
|
+
RCTTextShadowView *textShadowView = (RCTTextShadowView *)shadowView;
|
|
227
|
+
NSString *text = [self extractText: textShadowView.reactSubviews];
|
|
228
|
+
if (text.length == 0) return;
|
|
229
|
+
textProperties.text = text;
|
|
230
|
+
textProperties.color = textShadowView.textAttributes.foregroundColor;
|
|
231
|
+
textProperties.alignment = textShadowView.textAttributes.alignment;
|
|
232
|
+
textProperties.font = textShadowView.textAttributes.effectiveFont;
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
if (textProperties.text.length == 0) return nil;
|
|
236
|
+
return textProperties;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Text under new arch.
|
|
240
|
+
Class ParagraphComponentView = NSClassFromString(@"RCTParagraphComponentView");
|
|
241
|
+
if (ParagraphComponentView && [passedView isKindOfClass:ParagraphComponentView]) {
|
|
242
|
+
NSString *text = [self extractTextFromParagraphComponentView:passedView];
|
|
243
|
+
if (text.length == 0) return nil;
|
|
244
|
+
_SGRNTextProperties *textProperties = [[_SGRNTextProperties alloc] init];
|
|
245
|
+
textProperties.text = text;
|
|
246
|
+
if ([passedView respondsToSelector:@selector(attributedText)]) {
|
|
247
|
+
NSAttributedString *attrText = [passedView performSelector:@selector(attributedText)];
|
|
248
|
+
if (attrText.length > 0) {
|
|
249
|
+
NSDictionary *attrs = [attrText attributesAtIndex:0 effectiveRange:nil];
|
|
250
|
+
if (!textProperties.color && attrs[NSForegroundColorAttributeName]) {
|
|
251
|
+
textProperties.color = attrs[NSForegroundColorAttributeName];
|
|
252
|
+
}
|
|
253
|
+
if (!textProperties.font && attrs[NSFontAttributeName]) {
|
|
254
|
+
textProperties.font = attrs[NSFontAttributeName];
|
|
255
|
+
}
|
|
256
|
+
NSParagraphStyle *style = attrs[NSParagraphStyleAttributeName];
|
|
257
|
+
if (style) {
|
|
258
|
+
textProperties.alignment = style.alignment;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
183
261
|
}
|
|
184
|
-
|
|
185
|
-
|
|
262
|
+
return textProperties;
|
|
263
|
+
}
|
|
264
|
+
return nil;
|
|
186
265
|
}
|
|
187
266
|
|
|
188
267
|
RCT_EXPORT_METHOD(dismissActiveSurvey)
|
|
@@ -225,4 +304,22 @@ RCT_EXPORT_METHOD(unpauseDisplayingSurveys)
|
|
|
225
304
|
}
|
|
226
305
|
return text;
|
|
227
306
|
}
|
|
307
|
+
|
|
308
|
+
- (NSString *)extractTextFromParagraphComponentView:(UIView *)view {
|
|
309
|
+
if ([view respondsToSelector:@selector(attributedText)]) {
|
|
310
|
+
NSAttributedString *attrText = [view performSelector:@selector(attributedText)];
|
|
311
|
+
return attrText.string;
|
|
312
|
+
}
|
|
313
|
+
if ([view respondsToSelector:@selector(text)]) {
|
|
314
|
+
NSString *text = [view performSelector:@selector(text)];
|
|
315
|
+
return text;
|
|
316
|
+
}
|
|
317
|
+
NSMutableString *result = [NSMutableString string];
|
|
318
|
+
for (UIView *subview in view.subviews) {
|
|
319
|
+
NSString *subText = [self extractTextFromParagraphComponentView:subview];
|
|
320
|
+
if (subText) [result appendString:subText];
|
|
321
|
+
}
|
|
322
|
+
return result;
|
|
323
|
+
}
|
|
324
|
+
|
|
228
325
|
@end
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-userleap",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "React Native module for UserLeap",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -17,11 +17,6 @@
|
|
|
17
17
|
"scripts": {
|
|
18
18
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
19
19
|
},
|
|
20
|
-
"repository": {
|
|
21
|
-
"type": "git",
|
|
22
|
-
"url": "git+https://github.com/UserLeap/react-native-userleap.git",
|
|
23
|
-
"baseUrl": "https://github.com/UserLeap/react-native-userleap"
|
|
24
|
-
},
|
|
25
20
|
"keywords": [
|
|
26
21
|
"userleap",
|
|
27
22
|
"react-native",
|
|
@@ -38,9 +33,12 @@
|
|
|
38
33
|
"babel-jest": "29.7.0",
|
|
39
34
|
"eslint": "7.32.0",
|
|
40
35
|
"jest": "29.7.0",
|
|
41
|
-
"
|
|
42
|
-
"react": "
|
|
43
|
-
"react-native": "0.
|
|
36
|
+
"@react-native/babel-preset": "^0.81.0",
|
|
37
|
+
"react": "19.1.0",
|
|
38
|
+
"react-native": "0.81.0",
|
|
44
39
|
"react-test-renderer": "18.2.0"
|
|
40
|
+
},
|
|
41
|
+
"overrides": {
|
|
42
|
+
"js-yaml": "3.14.2"
|
|
45
43
|
}
|
|
46
|
-
}
|
|
44
|
+
}
|