@convivainc/conviva-react-native-appanalytics 0.2.10000 → 0.3.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 CHANGED
@@ -1,5 +1,33 @@
1
1
 
2
2
  # Changelog
3
+ ## 0.3.0 (14/Apr/2026)
4
+ - Babel plugin simplified to `@convivainc/conviva-react-native-appanalytics/plugin`; app-level `babel-types` and `babel-template` dependencies no longer needed.
5
+ - `add-react-displayname` plugin no longer needed; absorbed internally by the Conviva plugin.
6
+ - Using latest android(v1.3.1) and ios(v1.10.2) native packages.
7
+
8
+ ## 0.2.8 (06/Apr/2025)
9
+ - Added trackRevenueEvent API to track purchase and revenue events.
10
+ - Using latest android(v1.3.1) and ios(v1.10.1) native packages.
11
+
12
+ ## 0.2.7 (31/Dec/2025)
13
+ - Supports network request url query params tracking.
14
+ - Enhanced the remote configuration feature to support instant updates.
15
+ - Using latest android(v1.2.6) and ios(v1.8.0) native packages.
16
+
17
+ ## 0.2.6 (16/Dec/2025)
18
+ - Improves App Load Time metric by collecting more data.
19
+ - Using latest android(v1.2.6) and ios(v1.7.0) native packages.
20
+
21
+ ## 0.2.5 (25/Nov/2025)
22
+ - Improved crash reporting and ANRs to deliver deeper insights and faster fixes for a more stable app experience. Applicable for:
23
+ - Android 11 (API 30) and above
24
+ - iOS 14 and above
25
+
26
+ ## 0.2.4 (16/Oct/2025)
27
+ - Using latest android(v1.2.3) and ios(v1.5.0) native packages.
28
+
29
+ ## 0.2.3 (23/Sep/2025)
30
+ - Resolved an issue where certain network requests on Apple mobile platforms were not being captured by the DPI module.
3
31
 
4
32
  ## 0.2.2 (27/Mar/2025)
5
33
  - Exposing getClientId and setClientId methods for ts.
package/README.md CHANGED
@@ -76,22 +76,40 @@ tracker.trackPageView(pageViewEvent);
76
76
  ```
77
77
 
78
78
  ## Auto detect button clicks.
79
- Even though the React Native components can be natively mapped in Android and iOS, for the Auto detection of button clicks for **Button**, **TouchableHighlight**, **TouchableOpacity**, **TouchableWithoutFeedback** and **TouchableNativeFeedback** Components, needs explicit addition of babel transfomation. Add below plugin code in your application .babel.rc or babel.config.js file:
79
+ Even though the React Native components can be natively mapped in Android and iOS, for the Auto detection of button clicks for **Button**, **TouchableHighlight**, **TouchableOpacity**, **TouchableWithoutFeedback** and **TouchableNativeFeedback** Components, needs explicit addition of babel transformation. Add below plugin code in your application `.babelrc` or `babel.config.js` file:
80
80
 
81
+ **>= 0.3.0** - no extra dependencies needed in the app:
81
82
  ```js
82
83
 
83
- "plugins": ["./node_modules/@convivainc/conviva-react-native-appanalytics/instrumentation/index.js"]
84
+ "plugins": ["@convivainc/conviva-react-native-appanalytics/plugin"]
84
85
 
85
86
  ```
86
87
 
87
- ## Auto detect ScreenView Events for tracking screen navigation.
88
- To support Conviva to Auto Detect the Screen Name part of the ScreenView Events, add below plugin code in your application .babel.rc or babel.config.js file:
88
+ **<= 0.2.8** - also required `babel-types` and `babel-template` as explicit app-level dependencies:
89
89
  ```js
90
90
 
91
+ "plugins": ["./node_modules/@convivainc/conviva-react-native-appanalytics/instrumentation/index.js"]
92
+
93
+ ```
94
+ ```json
95
+
96
+ "babel-types": "...",
97
+ "babel-template": "..."
98
+
99
+ ```
100
+
101
+ ## `displayName` auto-detection
102
+ **<= 0.2.8** - required as a separate entry in `.babelrc` / `babel.config.js`:
103
+ ```js
91
104
  "plugins": ["add-react-displayname"]
105
+ ```
92
106
 
107
+ **>= 0.3.0** - no separate entry needed. `displayName` auto-detection is absorbed internally by the Conviva plugin:
108
+ ```js
109
+ "plugins": ["@convivainc/conviva-react-native-appanalytics/plugin"]
93
110
  ```
94
111
 
112
+ ## Auto detect ScreenView Events for tracking screen navigation.
95
113
  For React Navigation versions 5 and above, to autocapture screenviews, wrap withReactNavigationAutotrack(autocaptureNavigationTrack) around the NavigationContainer:
96
114
 
97
115
  ```js
@@ -114,7 +132,7 @@ withReactNavigationAutotrack(autocaptureNavigationTrack)(NavigationContainer);
114
132
  </ConvivaNavigationContainer>
115
133
  ```
116
134
 
117
- For React Navigation versions below 5, wrap the AppContainer (the result of a call to React Navigations createAppContainer() method) with withReactNavigationAutotrack(autocaptureNavigationTrack)
135
+ For React Navigation versions below 5, wrap the AppContainer (the result of a call to React Navigation's createAppContainer() method) with withReactNavigationAutotrack(autocaptureNavigationTrack)
118
136
  ```js
119
137
 
120
138
  let AppNavigator = createStackNavigator(
@@ -189,9 +207,9 @@ tracker.clearAllCustomTags();
189
207
  Event | Occurrence |
190
208
  ------|------------ |
191
209
  network_request | after receiving the network request response ; auto collected from the Native Sensors, Need android-plugin inclusion for Android|
192
- screen_view | when the screen is interacted on either first launch or relaunch ; auto collected from the Native Sensors + React Native Screens; Need add-react-displayname plugin and wrapping of Navigation Components |
210
+ screen_view | when the screen is interacted on either first launch or relaunch ; auto collected from the Native Sensors + React Native Screens; Need Conviva `plugin.js` (includes `displayName` injection) and wrapping of Navigation Components |
193
211
  application_error | when an error occurrs in the application ; auto collected from the Native Sensors|
194
- button_click | on the button click callback ; auto collected from the Native Sensors + React Native **Button**, **TouchableHighlight**, **TouchableOpacity**, **TouchableWithoutFeedback** and **TouchableNativeFeedback** Components; Need Conviva index.js from the node_modules folder|
212
+ button_click | on the button click callback ; auto collected from the Native Sensors + React Native **Button**, **TouchableHighlight**, **TouchableOpacity**, **TouchableWithoutFeedback** and **TouchableNativeFeedback** Components; Need Conviva `plugin.js` from the node_modules folder|
195
213
  application_background | when the application is taken to the background ; auto collected from the Native Sensors|
196
214
  application_foreground | when the application is taken to the foreground ; auto collected from the Native Sensors|
197
215
  application_install | when the application is launched for the first time after it's installed. (It's not the exact installed time.) |
@@ -20,5 +20,5 @@ Pod::Spec.new do |s|
20
20
  s.requires_arc = true
21
21
 
22
22
  s.dependency "React-Core"
23
- s.dependency "ConvivaAppAnalytics", "1.1.10000"
23
+ s.dependency "ConvivaAppAnalytics", "1.10.2"
24
24
  end
@@ -16,6 +16,7 @@ buildscript {
16
16
  apply plugin: "com.android.library"
17
17
 
18
18
  android {
19
+ namespace "com.conviva.react.apptracker"
19
20
  compileSdkVersion safeExtGet('compileSdkVersion', 33)
20
21
  buildToolsVersion safeExtGet('buildToolsVersion', '30.0.2')
21
22
 
@@ -51,5 +52,5 @@ dependencies {
51
52
  implementation "com.squareup.okhttp3:okhttp:4.9.3"
52
53
  implementation "com.facebook.react:react-native:+"
53
54
  implementation 'com.googlecode.json-simple:json-simple:1.1'
54
- implementation 'com.conviva.sdk:conviva-android-tracker:1.2.1'
55
+ implementation 'com.conviva.sdk:conviva-android-tracker:1.3.1'
55
56
  }
@@ -1,2 +1,3 @@
1
1
  android.useAndroidX=true
2
- android.enableJetifier=true
2
+ android.enableJetifier=true
3
+ android.defaults.buildfeatures.buildconfig=true
@@ -13,6 +13,8 @@ import com.conviva.apptracker.configuration.TrackerConfiguration;
13
13
  import com.conviva.apptracker.controller.TrackerController;
14
14
  import com.conviva.apptracker.event.ButtonClick;
15
15
  import com.conviva.apptracker.event.ConsentGranted;
16
+ import com.conviva.apptracker.revenue.ConvivaRevenueEvent;
17
+ import com.conviva.apptracker.revenue.ConvivaRevenueEventItem;
16
18
  import com.conviva.apptracker.event.ConsentWithdrawn;
17
19
  import com.conviva.apptracker.event.DeepLinkReceived;
18
20
  import com.conviva.apptracker.event.EcommerceTransaction;
@@ -37,6 +39,7 @@ import com.facebook.react.bridge.ReadableArray;
37
39
  import com.facebook.react.bridge.ReadableMap;
38
40
  import com.facebook.react.bridge.ReadableMapKeySetIterator;
39
41
 
42
+ import org.json.JSONObject;
40
43
  import org.json.simple.JSONValue;
41
44
 
42
45
  import java.util.ArrayList;
@@ -48,13 +51,40 @@ import java.util.concurrent.TimeUnit;
48
51
  import okhttp3.OkHttpClient;
49
52
  import okhttp3.Request;
50
53
 
54
+ import com.facebook.react.bridge.ReactMarker;
55
+ import com.facebook.react.bridge.ReactMarker.MarkerListener;
56
+ import com.facebook.react.bridge.ReactMarkerConstants;
57
+
58
+
51
59
  public class RNConvivaTrackerModule extends ReactContextBaseJavaModule {
52
60
 
53
61
  private final ReactApplicationContext reactContext;
54
62
 
63
+ public static volatile long contentAppearedTimestamp;
64
+
65
+
55
66
  public RNConvivaTrackerModule(ReactApplicationContext reactContext) {
56
67
  super(reactContext);
57
68
  this.reactContext = reactContext;
69
+
70
+ addContentAppearedMarkerListener();
71
+ }
72
+
73
+ private void addContentAppearedMarkerListener() {
74
+ if (contentAppearedTimestamp <= 0) {
75
+ ReactMarker.addListener(new MarkerListener() {
76
+ @Override
77
+ public void logMarker(ReactMarkerConstants name, String tag, int instanceKey) {
78
+ if (name == ReactMarkerConstants.CONTENT_APPEARED && contentAppearedTimestamp <= 0) {
79
+ contentAppearedTimestamp = System.currentTimeMillis();
80
+ TrackerController tracker = ConvivaAppAnalytics.getDefaultTracker();
81
+ if (tracker != null) {
82
+ tracker.setContentAppearedTimestamp(contentAppearedTimestamp);
83
+ }
84
+ }
85
+ }
86
+ });
87
+ }
58
88
  }
59
89
 
60
90
  @Override
@@ -163,7 +193,12 @@ public class RNConvivaTrackerModule extends ReactContextBaseJavaModule {
163
193
  }
164
194
 
165
195
  // create the tracker
166
- ConvivaAppAnalytics.createTracker(this.reactContext, customerKey, appName, controllers.toArray(new Configuration[controllers.size()]));
196
+ TrackerController trackerController = ConvivaAppAnalytics.createTracker(this.reactContext, customerKey, appName, controllers.toArray(new Configuration[controllers.size()]));
197
+
198
+ //Set the contentAppearedTimestamp if already captured
199
+ if(trackerController != null && contentAppearedTimestamp > 0) {
200
+ trackerController.setContentAppearedTimestamp(contentAppearedTimestamp);
201
+ }
167
202
 
168
203
  promise.resolve(true);
169
204
 
@@ -188,6 +223,16 @@ public class RNConvivaTrackerModule extends ReactContextBaseJavaModule {
188
223
  }
189
224
  }
190
225
 
226
+ @ReactMethod
227
+ public void cleanup(Promise promise) {
228
+ try {
229
+ // commented out deprecated methods
230
+ promise.resolve(true);
231
+
232
+ } catch (Throwable t) {
233
+ promise.reject("ERROR", t.getMessage());
234
+ }
235
+ }
191
236
  @ReactMethod
192
237
  public void removeAllTrackers(Promise promise) {
193
238
  try {
@@ -501,6 +546,78 @@ public class RNConvivaTrackerModule extends ReactContextBaseJavaModule {
501
546
  }
502
547
  }
503
548
 
549
+ @ReactMethod
550
+ public void trackRevenueEvent(ReadableMap details, Promise promise) {
551
+ try {
552
+ String namespace = details.getString("tracker");
553
+ TrackerController trackerController = getTracker(namespace);
554
+ if (trackerController != null) {
555
+ ReadableMap argmap = details.getMap("eventData");
556
+
557
+ double totalOrderAmount = argmap.getDouble("totalOrderAmount");
558
+ String transactionId = argmap.getString("transactionId");
559
+ String currency = argmap.getString("currency");
560
+
561
+ ConvivaRevenueEvent.Builder builder =
562
+ ConvivaRevenueEvent.builder(totalOrderAmount, transactionId, currency);
563
+
564
+ if (argmap.hasKey("taxAmount") && !argmap.isNull("taxAmount"))
565
+ builder.taxAmount(argmap.getDouble("taxAmount"));
566
+ if (argmap.hasKey("shippingCost") && !argmap.isNull("shippingCost"))
567
+ builder.shippingCost(argmap.getDouble("shippingCost"));
568
+ if (argmap.hasKey("discount") && !argmap.isNull("discount"))
569
+ builder.discount(argmap.getDouble("discount"));
570
+ if (argmap.hasKey("cartSize") && !argmap.isNull("cartSize"))
571
+ builder.cartSize(argmap.getInt("cartSize"));
572
+ if (argmap.hasKey("paymentMethod") && !argmap.isNull("paymentMethod"))
573
+ builder.paymentMethod(argmap.getString("paymentMethod"));
574
+ if (argmap.hasKey("paymentProvider") && !argmap.isNull("paymentProvider"))
575
+ builder.paymentProvider(argmap.getString("paymentProvider"));
576
+ if (argmap.hasKey("extraMetadata") && !argmap.isNull("extraMetadata"))
577
+ builder.extraMetadata(new JSONObject(argmap.getMap("extraMetadata").toHashMap()));
578
+
579
+ if (argmap.hasKey("items") && !argmap.isNull("items")) {
580
+ ReadableArray itemsArray = argmap.getArray("items");
581
+ List<ConvivaRevenueEventItem> items = new ArrayList<>();
582
+ for (int i = 0; i < itemsArray.size(); i++) {
583
+ ReadableMap itemDict = itemsArray.getMap(i);
584
+ ConvivaRevenueEventItem.Builder itemBuilder = ConvivaRevenueEventItem.builder();
585
+ if (itemDict.hasKey("productId") && !itemDict.isNull("productId"))
586
+ itemBuilder.productId(itemDict.getString("productId"));
587
+ if (itemDict.hasKey("name") && !itemDict.isNull("name"))
588
+ itemBuilder.name(itemDict.getString("name"));
589
+ if (itemDict.hasKey("sku") && !itemDict.isNull("sku"))
590
+ itemBuilder.sku(itemDict.getString("sku"));
591
+ if (itemDict.hasKey("category") && !itemDict.isNull("category"))
592
+ itemBuilder.category(EventUtil.createStrings(itemDict.getArray("category")));
593
+ if (itemDict.hasKey("unitPrice") && !itemDict.isNull("unitPrice"))
594
+ itemBuilder.unitPrice(itemDict.getDouble("unitPrice"));
595
+ if (itemDict.hasKey("quantity") && !itemDict.isNull("quantity"))
596
+ itemBuilder.quantity(itemDict.getInt("quantity"));
597
+ if (itemDict.hasKey("discount") && !itemDict.isNull("discount"))
598
+ itemBuilder.discount(itemDict.getDouble("discount"));
599
+ if (itemDict.hasKey("brand") && !itemDict.isNull("brand"))
600
+ itemBuilder.brand(itemDict.getString("brand"));
601
+ if (itemDict.hasKey("variant") && !itemDict.isNull("variant"))
602
+ itemBuilder.variant(itemDict.getString("variant"));
603
+ if (itemDict.hasKey("extraMetadata") && !itemDict.isNull("extraMetadata"))
604
+ itemBuilder.extraMetadata(new JSONObject(itemDict.getMap("extraMetadata").toHashMap()));
605
+ items.add(itemBuilder.build());
606
+ }
607
+ builder.items(items);
608
+ }
609
+
610
+ trackerController.trackRevenueEvent(builder.build());
611
+ promise.resolve(true);
612
+ } else {
613
+ promise.reject("ERROR", "TrackerController is null");
614
+ }
615
+
616
+ } catch (Throwable t) {
617
+ promise.reject("ERROR", t.getMessage());
618
+ }
619
+ }
620
+
504
621
  @ReactMethod
505
622
  public void setCustomTags(ReadableMap details, Promise promise) {
506
623
  try {
@@ -947,6 +1064,21 @@ public class RNConvivaTrackerModule extends ReactContextBaseJavaModule {
947
1064
  }
948
1065
  }
949
1066
 
1067
+ @ReactMethod
1068
+ private void setContentAppearedTimestamp(ReadableMap argmap, Promise promise) {
1069
+ try {
1070
+ String namespace = argmap.getString("tracker");
1071
+ long contentAppearedTimestamp = (long) argmap.getDouble("contentAppearedTimestamp");
1072
+ TrackerController trackerController = getTracker(namespace);
1073
+ if (trackerController != null) {
1074
+ trackerController.setContentAppearedTimestamp(contentAppearedTimestamp);
1075
+ }
1076
+ promise.resolve(true);
1077
+ } catch (Throwable t) {
1078
+ promise.reject("ERROR", t.getMessage());
1079
+ }
1080
+ }
1081
+
950
1082
  private TrackerController getTracker(String namespace) {
951
1083
  return namespace == null ? ConvivaAppAnalytics.getDefaultTracker() : ConvivaAppAnalytics.getTracker(namespace);
952
1084
  }
@@ -4,6 +4,6 @@ import com.conviva.react.apptracker.BuildConfig;
4
4
 
5
5
  public class TrackerVersion {
6
6
 
7
- public final static String RN_CONVIVA_TRACKER_VERSION = "rn-0.2.2";
7
+ public final static String RN_CONVIVA_TRACKER_VERSION = "rn-0.3.0";
8
8
 
9
9
  }
@@ -71,6 +71,11 @@ interface NetworkConfiguration {
71
71
  */
72
72
  requestHeaders?: Record<string, string>;
73
73
  }
74
+ interface TraceparentConfiguration {
75
+ force: Boolean;
76
+ enabled: Boolean;
77
+ targetUrl: string[];
78
+ }
74
79
  /**
75
80
  * TrackerConfiguration
76
81
  */
@@ -304,6 +309,7 @@ interface RemoteConfiguration {
304
309
  */
305
310
  interface TrackerControllerConfiguration {
306
311
  networkConfig?: NetworkConfiguration;
312
+ traceparentConfig?: TraceparentConfiguration;
307
313
  trackerConfig?: TrackerConfiguration;
308
314
  sessionConfig?: SessionConfiguration;
309
315
  emitterConfig?: EmitterConfiguration;
@@ -572,6 +578,39 @@ type MessageNotificationProps = {
572
578
  */
573
579
  trigger: Trigger;
574
580
  };
581
+ /**
582
+ * RevenueEventItem properties.
583
+ * All fields are optional.
584
+ */
585
+ type RevenueEventItemProps = {
586
+ productId?: string;
587
+ name?: string;
588
+ sku?: string;
589
+ category?: string[];
590
+ unitPrice?: number;
591
+ quantity?: number;
592
+ discount?: number;
593
+ brand?: string;
594
+ variant?: string;
595
+ extraMetadata?: Record<string, unknown>;
596
+ };
597
+ /**
598
+ * RevenueEvent properties.
599
+ * Required: totalOrderAmount, transactionId, currency.
600
+ */
601
+ type RevenueEventProps = {
602
+ totalOrderAmount: number;
603
+ transactionId: string;
604
+ currency: string;
605
+ taxAmount?: number;
606
+ shippingCost?: number;
607
+ discount?: number;
608
+ cartSize?: number;
609
+ paymentMethod?: string;
610
+ paymentProvider?: string;
611
+ items?: RevenueEventItemProps[];
612
+ extraMetadata?: Record<string, unknown>;
613
+ };
575
614
  /**
576
615
  * The ReactNativeTracker type
577
616
  */
@@ -656,6 +695,13 @@ type ReactNativeTracker = {
656
695
  * @returns {Promise}
657
696
  */
658
697
  readonly trackCustomEvent: (eventName: string, eventData: any, contexts?: EventContext[]) => Promise<void>;
698
+ /**
699
+ * Tracks a revenue event
700
+ *
701
+ * @param argmap - The revenue event properties
702
+ * @param contexts - The array of event contexts
703
+ */
704
+ readonly trackRevenueEvent: (argmap: RevenueEventProps, contexts?: EventContext[]) => Promise<void>;
659
705
  /**
660
706
  * Sets custom tags
661
707
  *
@@ -848,6 +894,12 @@ declare function removeTracker(trackerNamespace: string): Promise<boolean>;
848
894
  * @returns - A boolean promise
849
895
  */
850
896
  declare function removeAllTrackers(): Promise<boolean>;
897
+ /**
898
+ * Cleanup
899
+ *
900
+ * @returns - A boolean promise
901
+ */
902
+ declare function cleanup(): Promise<boolean>;
851
903
  /**
852
904
  * Gets the cliend id
853
905
  *
@@ -868,4 +920,4 @@ declare const _default: {
868
920
  withReactNavigationAutotrack: (AppContainer: any) => react.ForwardRefExoticComponent<react.RefAttributes<any>>;
869
921
  };
870
922
 
871
- export { Basis, BufferOption, ConsentDocument, ConsentGrantedProps, ConsentWithdrawnProps, DeepLinkReceivedProps, DevicePlatform, EcommerceItem, EcommerceTransactionProps, EmitterConfiguration, EventContext, GCConfiguration, GdprConfiguration, GlobalContext, HttpMethod, LogLevel, MessageNotificationProps, NetworkConfiguration, PageViewProps, ReactNativeTracker, ScreenSize, ScreenViewProps, SelfDescribing, SessionConfiguration, StructuredProps, SubjectConfiguration, TimingProps, TrackerConfiguration, TrackerControllerConfiguration, Trigger, autocaptureNavigationTrack, createTracker, _default as default, getWebViewCallback, removeAllTrackers, removeTracker, withReactNavigationAutotrack, getClientId, setClientId};
923
+ export { Basis, BufferOption, ConsentDocument, ConsentGrantedProps, ConsentWithdrawnProps, DeepLinkReceivedProps, DevicePlatform, EcommerceItem, EcommerceTransactionProps, EmitterConfiguration, EventContext, GCConfiguration, GdprConfiguration, GlobalContext, HttpMethod, LogLevel, MessageNotificationProps, NetworkConfiguration, PageViewProps, ReactNativeTracker, RevenueEventItemProps, RevenueEventProps, ScreenSize, ScreenViewProps, SelfDescribing, SessionConfiguration, StructuredProps, SubjectConfiguration, TimingProps, TrackerConfiguration, TrackerControllerConfiguration, Trigger, autocaptureNavigationTrack, cleanup, createTracker, _default as default, getClientId, getWebViewCallback, removeAllTrackers, removeTracker, setClientId, withReactNavigationAutotrack };
@@ -52,11 +52,11 @@ function safeWaitCallback(callPromise, errHandle) {
52
52
  * Handles an error.
53
53
  *
54
54
  * @param err - The error to be handled.
55
+ * @param alwaysLog - When true, the error is logged regardless of the __DEV__ flag.
55
56
  */
56
- function errorHandler(err) {
57
- if (__DEV__) {
57
+ function errorHandler(err, alwaysLog = false) {
58
+ if (__DEV__ || alwaysLog) {
58
59
  console.warn('ConvivaTracker:' + err.message);
59
- return undefined;
60
60
  }
61
61
  return undefined;
62
62
  }
@@ -128,6 +128,10 @@ const logMessages = {
128
128
  deepLinkReq: 'deepLinkReceived event requires the url parameter to be set',
129
129
  messageNotificationReq: 'messageNotification event requires title, body, and trigger parameters to be set',
130
130
  trackCustomEvent: 'trackCustomEvent event requires name and data',
131
+ revenueEventNullEvent: 'event is null. Event not sent.',
132
+ revenueEventInvalidTotalOrderAmount: 'Must be a finite number. Event not sent.',
133
+ revenueEventInvalidTransactionId: 'Must be a non-empty string. Event not sent.',
134
+ revenueEventInvalidCurrency: 'Must be a non-empty string. Event not sent.',
131
135
  trackClickEvent: 'click event requires atleast one attribute',
132
136
  // custom tags contexts
133
137
  setCustomTags: 'setCustomTags requires tags',
@@ -152,6 +156,7 @@ const logMessages = {
152
156
  trackEcommerceTransaction: 'trackEcommerceTransaction:',
153
157
  trackDeepLinkReceived: 'trackDeepLinkReceivedEvent:',
154
158
  trackMessageNotification: 'trackMessageNotificationEvent:',
159
+ trackRevenueEvent: 'trackRevenueEvent:',
155
160
  removeGlobalContexts: 'removeGlobalContexts:',
156
161
  addGlobalContexts: 'addGlobalContexts:',
157
162
  // setters
@@ -413,11 +418,26 @@ function validateEcommerceTransaction(argmap) {
413
418
  return Promise.resolve(true);
414
419
  }
415
420
  /**
416
- * Validates a custom event
421
+ * Validates a revenue event
417
422
  *
418
423
  * @param argmap {Object} - the object to validate
419
424
  * @returns - boolean promise
420
425
  */
426
+ function validateRevenueEvent(argmap) {
427
+ if (!isObject(argmap)) {
428
+ return Promise.reject(new Error(logMessages.revenueEventNullEvent));
429
+ }
430
+ if (typeof argmap.totalOrderAmount !== 'number' || !Number.isFinite(argmap.totalOrderAmount)) {
431
+ return Promise.reject(new Error(`invalid totalOrderAmount "${argmap.totalOrderAmount}". ${logMessages.revenueEventInvalidTotalOrderAmount}`));
432
+ }
433
+ if (typeof argmap.transactionId !== 'string' || argmap.transactionId.trim() === '') {
434
+ return Promise.reject(new Error(`invalid transactionId "${argmap.transactionId}". ${logMessages.revenueEventInvalidTransactionId}`));
435
+ }
436
+ if (typeof argmap.currency !== 'string' || argmap.currency.trim() === '') {
437
+ return Promise.reject(new Error(`invalid currency "${argmap.currency}". ${logMessages.revenueEventInvalidCurrency}`));
438
+ }
439
+ return Promise.resolve(true);
440
+ }
421
441
  function validateCustomEvent(argmap) {
422
442
  // validate type
423
443
  if (!isObject(argmap)) {
@@ -954,6 +974,26 @@ function trackCustomEvent$1(namespace, name, arg, contexts = []) {
954
974
  throw new Error(`${logMessages.trackCustomEvent} ${error.message}`);
955
975
  });
956
976
  }
977
+ /**
978
+ * Tracks a revenue event
979
+ *
980
+ * @param namespace {string} - the tracker namespace
981
+ * @param argmap {Object} - the event data
982
+ * @param contexts {Array}- the event contexts
983
+ * @returns {Promise}
984
+ */
985
+ function trackRevenueEvent$1(namespace, argmap, contexts = []) {
986
+ return validateRevenueEvent(argmap)
987
+ .then(() => validateContexts(contexts))
988
+ .then(() => RNConvivaTracker.trackRevenueEvent({
989
+ tracker: namespace,
990
+ eventData: argmap,
991
+ contexts: contexts
992
+ }))
993
+ .catch((error) => {
994
+ throw new Error(`${logMessages.trackRevenueEvent} ${error.message}`);
995
+ });
996
+ }
957
997
  /**
958
998
  * Sets custom tags
959
999
  *
@@ -1330,6 +1370,14 @@ function removeAllTrackers$1() {
1330
1370
  }
1331
1371
  return Promise.resolve(RNConvivaTracker.removeAllTrackers());
1332
1372
  }
1373
+ /**
1374
+ * Cleanup
1375
+ *
1376
+ * @returns - A void promise
1377
+ */
1378
+ function cleanup$1() {
1379
+ return Promise.resolve(RNConvivaTracker.cleanup());
1380
+ }
1333
1381
  /**
1334
1382
  * Get the client id which is in prescribed format.
1335
1383
  *
@@ -1508,6 +1556,20 @@ function trackCustomEvent(namespace) {
1508
1556
  return trackCustomEvent$1(namespace, eventName, eventData, contexts);
1509
1557
  };
1510
1558
  }
1559
+ /**
1560
+ * Returns a function to track a RevenueEvent by a tracker
1561
+ *
1562
+ * @param namespace {string} - The tracker namespace
1563
+ * @returns - A function to track a RevenueEvent
1564
+ */
1565
+ function trackRevenueEvent(namespace) {
1566
+ return function (argmap, contexts = []) {
1567
+ if (!isTrackerInitialised) {
1568
+ return Promise.reject(new Error(logMessages.createTrackerNotSet));
1569
+ }
1570
+ return trackRevenueEvent$1(namespace, argmap, contexts);
1571
+ };
1572
+ }
1511
1573
  function setCustomTags(namespace) {
1512
1574
  return function (tags, contexts = []) {
1513
1575
  if (!isTrackerInitialised) {
@@ -2015,7 +2077,7 @@ class NavigationUtil {
2015
2077
  }
2016
2078
  }
2017
2079
 
2018
- const version = "0.22.6";
2080
+ const version = "0.3.0";
2019
2081
 
2020
2082
  const { Platform } = require('react-native');
2021
2083
  let reactNativeVersionString = null;
@@ -2174,6 +2236,8 @@ controllerConfig = {}) {
2174
2236
  }));
2175
2237
  // mkMethod creates methods subscribed to the initTrackerPromise
2176
2238
  const mkMethod = safeWait(initTrackerPromise, errorHandler);
2239
+ // mkMethodAlwaysLog creates methods that always log errors, regardless of __DEV__
2240
+ const mkMethodAlwaysLog = safeWait(initTrackerPromise, (err) => errorHandler(err, true));
2177
2241
  // mkCallback creates callbacks subscribed to the initTrackerPromise
2178
2242
  const mkCallback = safeWaitCallback(initTrackerPromise, errorHandler);
2179
2243
  // track methods
@@ -2189,6 +2253,7 @@ controllerConfig = {}) {
2189
2253
  const trackDeepLinkReceivedEvent$1 = mkMethod(trackDeepLinkReceivedEvent(namespace));
2190
2254
  const trackMessageNotificationEvent$1 = mkMethod(trackMessageNotificationEvent(namespace));
2191
2255
  const trackCustomEvent$1 = mkMethod(trackCustomEvent(namespace));
2256
+ const trackRevenueEvent$1 = mkMethodAlwaysLog(trackRevenueEvent(namespace));
2192
2257
  const trackClickEvent$1 = mkMethod(trackClickEvent(namespace));
2193
2258
  // custom tags contexts
2194
2259
  const setCustomTags$1 = mkMethod(setCustomTags(namespace));
@@ -2229,6 +2294,7 @@ controllerConfig = {}) {
2229
2294
  trackDeepLinkReceivedEvent: trackDeepLinkReceivedEvent$1,
2230
2295
  trackMessageNotificationEvent: trackMessageNotificationEvent$1,
2231
2296
  trackCustomEvent: trackCustomEvent$1,
2297
+ trackRevenueEvent: trackRevenueEvent$1,
2232
2298
  setCustomTags: setCustomTags$1,
2233
2299
  setCustomTagsWithCategory: setCustomTagsWithCategory$1,
2234
2300
  clearCustomTags: clearCustomTags$1,
@@ -2274,6 +2340,15 @@ function removeAllTrackers() {
2274
2340
  return removeAllTrackers$1()
2275
2341
  .catch((e) => errorHandler(e));
2276
2342
  }
2343
+ /**
2344
+ * Cleanup
2345
+ *
2346
+ * @returns - A boolean promise
2347
+ */
2348
+ function cleanup() {
2349
+ return cleanup$1()
2350
+ .catch((e) => errorHandler(e));
2351
+ }
2277
2352
  /**
2278
2353
  * Gets the cliend id
2279
2354
  *
@@ -2298,7 +2373,6 @@ const autocaptureNavigationTrack = handleError((payload) => {
2298
2373
  trackScreenViewEvent('CAT')(payload).catch((e) => errorHandler(e));
2299
2374
  }, 'Event autocapture', true);
2300
2375
  const autocaptureTrack = handleError((payload) => {
2301
- checkDisplayNamePlugin();
2302
2376
  trackClickEvent('CAT')(payload).catch((e) => errorHandler(e));
2303
2377
  }, 'Event autocapture', true);
2304
2378
  var index = {
@@ -2306,5 +2380,5 @@ var index = {
2306
2380
  withReactNavigationAutotrack: withReactNavigationAutotrack(autocaptureNavigationTrack)
2307
2381
  };
2308
2382
 
2309
- export { autocaptureNavigationTrack, createTracker, index as default, getClientId, getWebViewCallback, removeAllTrackers, removeTracker, setClientId, withReactNavigationAutotrack };
2383
+ export { autocaptureNavigationTrack, cleanup, createTracker, index as default, getClientId, getWebViewCallback, removeAllTrackers, removeTracker, setClientId, withReactNavigationAutotrack };
2310
2384
  //# sourceMappingURL=conviva-react-native-appanalytics.js.map
@@ -1,66 +1,4 @@
1
- const t = require('babel-types');
2
- const template = require('babel-template');
3
-
4
- const convivaLibImport = template(`(
5
- require('@convivainc/conviva-react-native-appanalytics').default || {
6
- HIGHER_ORDER_COMP: (Component) => Component,
7
- }
8
- )`);
9
-
10
- const createHigherOrderComponent = template(`
11
- const COMPONENT_ID = HIGHER_ORDER_COMP_CALL_EXPRESSION;
12
- `);
13
-
14
- const ALLOWED_TOUCHABLE_COMPONENTS = [
15
- 'TouchableOpacity',
16
- 'TouchableNativeFeedback',
17
- 'TouchableWithoutFeedback',
18
- 'TouchableHighlight',
19
- ];
20
-
21
- const replaceWithTouchableAutoTrackHigherOrderComponent = path => {
22
-
23
- if (!ALLOWED_TOUCHABLE_COMPONENTS.includes(path.node.id.name)) {
24
- return;
25
- }
26
- // console.log("replaceWithTouchableAutoTrackHigherOrderComponent++");
27
-
28
- const equivalentExpression = t.classExpression(
29
- path.node.id,
30
- path.node.superClass,
31
- path.node.body,
32
- path.node.decorators || []
33
- );
34
-
35
- const hocID = t.identifier('convivaTouchableAutoTrack');
36
-
37
- const convivaImport = convivaLibImport({
38
- HIGHER_ORDER_COMP: hocID,
39
- });
40
-
41
- const autotrackExpression = t.callExpression(
42
- t.memberExpression(convivaImport.expression, hocID),
43
- [equivalentExpression]
44
- );
45
-
46
- const replacement = createHigherOrderComponent({
47
- COMPONENT_ID: path.node.id,
48
- HIGHER_ORDER_COMP_CALL_EXPRESSION: autotrackExpression,
49
- });
50
-
51
- path.replaceWith(replacement);
52
-
53
- // console.log("replaceWithTouchableAutoTrackHigherOrderComponent--");
54
- };
55
-
56
- function transform(babel) {
57
- return {
58
- visitor: {
59
- ClassDeclaration(path) {
60
- replaceWithTouchableAutoTrackHigherOrderComponent(path);
61
- },
62
- },
63
- };
64
- }
65
-
66
- module.exports = transform;
1
+ 'use strict';
2
+ // Backward-compatibility shim. The canonical implementation lives in plugin.js.
3
+ // Existing integrations that reference this path directly continue to work.
4
+ module.exports = require('../plugin.js');
@@ -45,6 +45,8 @@
45
45
  #import <ConvivaAppAnalytics/CATEcommerce.h>
46
46
  #import <ConvivaAppAnalytics/CATDeepLinkReceived.h>
47
47
  #import <ConvivaAppAnalytics/CATMessageNotification.h>
48
+ #import <ConvivaAppAnalytics/CATRevenueEvent.h>
49
+ #import <ConvivaAppAnalytics/CATRevenueEventItem.h>
48
50
  #import <Foundation/NSObject.h>
49
51
 
50
52
  @implementation RNConvivaTracker
@@ -173,6 +175,11 @@ RCT_EXPORT_METHOD(removeAllTrackers: (RCTPromiseResolveBlock)resolve rejecter:(R
173
175
  resolve(@YES);
174
176
  }
175
177
 
178
+ RCT_EXPORT_METHOD(cleanup: (RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
179
+ [CATAppAnalytics cleanup];
180
+ resolve(@YES);
181
+ }
182
+
176
183
  RCT_EXPORT_METHOD(trackSelfDescribingEvent:
177
184
  (NSDictionary *)details
178
185
  resolver:(RCTPromiseResolveBlock)resolve
@@ -650,6 +657,101 @@ RCT_EXPORT_METHOD(trackCustomEvent:
650
657
  }
651
658
  }
652
659
 
660
+ RCT_EXPORT_METHOD(trackRevenueEvent:
661
+ (NSDictionary *)details
662
+ resolver:(RCTPromiseResolveBlock)resolve
663
+ rejecter:(RCTPromiseRejectBlock)reject) {
664
+
665
+ NSString *namespace = [details objectForKey:@"tracker"];
666
+
667
+ id<CATTrackerController> trackerController = [self trackerByNamespace:namespace];
668
+
669
+ if (trackerController != nil) {
670
+ NSDictionary *argmap = [details objectForKey:@"eventData"];
671
+
672
+ NSNumber *totalOrderAmount = [argmap objectForKey:@"totalOrderAmount"];
673
+ NSString *transactionId = [argmap objectForKey:@"transactionId"];
674
+ NSString *currency = [argmap objectForKey:@"currency"];
675
+
676
+ CATRevenueEvent *event = [[CATRevenueEvent alloc]
677
+ initWithTotalOrderAmount:totalOrderAmount
678
+ transactionId:transactionId
679
+ currency:currency];
680
+
681
+ if ([argmap objectForKey:@"taxAmount"] && ![[argmap objectForKey:@"taxAmount"] isEqual:[NSNull null]]) {
682
+ event.taxAmount = [argmap objectForKey:@"taxAmount"];
683
+ }
684
+ if ([argmap objectForKey:@"shippingCost"] && ![[argmap objectForKey:@"shippingCost"] isEqual:[NSNull null]]) {
685
+ event.shippingCost = [argmap objectForKey:@"shippingCost"];
686
+ }
687
+ if ([argmap objectForKey:@"discount"] && ![[argmap objectForKey:@"discount"] isEqual:[NSNull null]]) {
688
+ event.discount = [argmap objectForKey:@"discount"];
689
+ }
690
+ if ([argmap objectForKey:@"cartSize"] && ![[argmap objectForKey:@"cartSize"] isEqual:[NSNull null]]) {
691
+ event.cartSize = [argmap objectForKey:@"cartSize"];
692
+ }
693
+ if ([argmap objectForKey:@"paymentMethod"] && ![[argmap objectForKey:@"paymentMethod"] isEqual:[NSNull null]]) {
694
+ event.paymentMethod = [argmap objectForKey:@"paymentMethod"];
695
+ }
696
+ if ([argmap objectForKey:@"paymentProvider"] && ![[argmap objectForKey:@"paymentProvider"] isEqual:[NSNull null]]) {
697
+ event.paymentProvider = [argmap objectForKey:@"paymentProvider"];
698
+ }
699
+ if ([argmap objectForKey:@"extraMetadata"] && ![[argmap objectForKey:@"extraMetadata"] isEqual:[NSNull null]]) {
700
+ event.extraMetadata = [argmap objectForKey:@"extraMetadata"];
701
+ }
702
+
703
+ NSArray *itemsArray = [argmap objectForKey:@"items"];
704
+ if (itemsArray && ![itemsArray isEqual:[NSNull null]] && [itemsArray isKindOfClass:[NSArray class]]) {
705
+ NSMutableArray<CATRevenueEventItem *> *items = [NSMutableArray array];
706
+ for (NSDictionary *itemDict in itemsArray) {
707
+ if (![itemDict isKindOfClass:[NSDictionary class]]) continue;
708
+
709
+ CATRevenueEventItem *item = [[CATRevenueEventItem alloc] init];
710
+
711
+ if ([itemDict objectForKey:@"productId"] && ![[itemDict objectForKey:@"productId"] isEqual:[NSNull null]]) {
712
+ item.productId = [itemDict objectForKey:@"productId"];
713
+ }
714
+ if ([itemDict objectForKey:@"name"] && ![[itemDict objectForKey:@"name"] isEqual:[NSNull null]]) {
715
+ item.name = [itemDict objectForKey:@"name"];
716
+ }
717
+ if ([itemDict objectForKey:@"sku"] && ![[itemDict objectForKey:@"sku"] isEqual:[NSNull null]]) {
718
+ item.sku = [itemDict objectForKey:@"sku"];
719
+ }
720
+ if ([itemDict objectForKey:@"category"] && ![[itemDict objectForKey:@"category"] isEqual:[NSNull null]]) {
721
+ item.category = [itemDict objectForKey:@"category"];
722
+ }
723
+ if ([itemDict objectForKey:@"unitPrice"] && ![[itemDict objectForKey:@"unitPrice"] isEqual:[NSNull null]]) {
724
+ item.unitPrice = [itemDict objectForKey:@"unitPrice"];
725
+ }
726
+ if ([itemDict objectForKey:@"quantity"] && ![[itemDict objectForKey:@"quantity"] isEqual:[NSNull null]]) {
727
+ item.quantity = [itemDict objectForKey:@"quantity"];
728
+ }
729
+ if ([itemDict objectForKey:@"discount"] && ![[itemDict objectForKey:@"discount"] isEqual:[NSNull null]]) {
730
+ item.discount = [itemDict objectForKey:@"discount"];
731
+ }
732
+ if ([itemDict objectForKey:@"brand"] && ![[itemDict objectForKey:@"brand"] isEqual:[NSNull null]]) {
733
+ item.brand = [itemDict objectForKey:@"brand"];
734
+ }
735
+ if ([itemDict objectForKey:@"variant"] && ![[itemDict objectForKey:@"variant"] isEqual:[NSNull null]]) {
736
+ item.variant = [itemDict objectForKey:@"variant"];
737
+ }
738
+ if ([itemDict objectForKey:@"extraMetadata"] && ![[itemDict objectForKey:@"extraMetadata"] isEqual:[NSNull null]]) {
739
+ item.extraMetadata = [itemDict objectForKey:@"extraMetadata"];
740
+ }
741
+
742
+ [items addObject:item];
743
+ }
744
+ event.items = items;
745
+ }
746
+
747
+ [trackerController trackRevenueEvent:event];
748
+ resolve(@YES);
749
+ } else {
750
+ NSError* error = [NSError errorWithDomain:@"ConvivaAppAnalytics" code:200 userInfo:nil];
751
+ reject(@"ERROR", @"tracker with given namespace not found", error);
752
+ }
753
+ }
754
+
653
755
  RCT_EXPORT_METHOD(setCustomTags:
654
756
  (NSDictionary *)details
655
757
  resolver:(RCTPromiseResolveBlock)resolve
@@ -1021,7 +1123,7 @@ RCT_EXPORT_METHOD(getIsInBackground:
1021
1123
  // NSError* error = [NSError errorWithDomain:@"ConvivaAppAnalytics" code:200 userInfo:nil];
1022
1124
  // reject(@"ERROR", @"tracker with given namespace not found", error);
1023
1125
  // }
1024
-
1126
+
1025
1127
  @try {
1026
1128
  resolve(@(YES));
1027
1129
  } @catch (NSException *exception) {
@@ -22,6 +22,6 @@
22
22
 
23
23
  @implementation RNTrackerVersion
24
24
 
25
- NSString * const kRNTrackerVersion = @"rn-0.2.10000";
25
+ NSString * const kRNTrackerVersion = @"rn-0.3.0";
26
26
 
27
27
  @end
package/package.json CHANGED
@@ -1,12 +1,18 @@
1
1
  {
2
2
  "name": "@convivainc/conviva-react-native-appanalytics",
3
- "version": "0.2.10000",
3
+ "version": "0.3.0",
4
4
  "description": "Conviva React Native Application Analytics Library",
5
5
  "main": "conviva-react-native-appanalytics.js",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+github.com:Conviva/conviva-react-native-appanalytics.git"
9
9
  },
10
+ "dependencies": {
11
+ "@babel/plugin-transform-react-display-name": "^7.0.0",
12
+ "hoist-non-react-statics": "^3.3.2",
13
+ "lodash": "^4.17.21",
14
+ "tslib": "^2.6.0"
15
+ },
10
16
  "keywords": [
11
17
  "Conviva",
12
18
  "Application",
package/plugin.js ADDED
@@ -0,0 +1,140 @@
1
+ 'use strict';
2
+
3
+ // Resolve babel-types and babel-template in a version-agnostic way.
4
+ // Priority order:
5
+ // 1. Use types/template injected by Babel itself (Babel 7 plugin API).
6
+ // 2. Fall back to @babel/types / @babel/template (Babel 7 standalone packages).
7
+ // 3. Fall back to babel-types / babel-template (Babel 6 legacy packages,
8
+ // guaranteed present via this package's own dependencies).
9
+ // The fallback chain means the plugin works whether the host project uses
10
+ // Babel 6 or Babel 7, without requiring either legacy package to be installed
11
+ // explicitly by the consuming app.
12
+
13
+ function resolveTypes(babel) {
14
+ if (babel && babel.types) {
15
+ return babel.types;
16
+ }
17
+ try { return require('@babel/types'); } catch (_) {}
18
+ try { return require('babel-types'); } catch (_) {}
19
+ throw new Error('[conviva] Could not resolve babel types. Install @babel/types (Babel 7) or babel-types (Babel 6).');
20
+ }
21
+
22
+ function resolveTemplate(babel) {
23
+ if (babel && babel.template) {
24
+ return babel.template;
25
+ }
26
+ try { return require('@babel/template').default || require('@babel/template'); } catch (_) {}
27
+ try { return require('babel-template'); } catch (_) {}
28
+ throw new Error('[conviva] Could not resolve babel template. Install @babel/template (Babel 7) or babel-template (Babel 6).');
29
+ }
30
+
31
+ const ALLOWED_TOUCHABLE_COMPONENTS = [
32
+ 'TouchableOpacity',
33
+ 'TouchableNativeFeedback',
34
+ 'TouchableWithoutFeedback',
35
+ 'TouchableHighlight',
36
+ ];
37
+
38
+ function replaceWithTouchableAutoTrackHigherOrderComponent(path, t, template) {
39
+ if (!ALLOWED_TOUCHABLE_COMPONENTS.includes(path.node.id.name)) {
40
+ return;
41
+ }
42
+
43
+ const convivaLibImport = template(`(
44
+ require('@convivainc/conviva-react-native-appanalytics').default || {
45
+ HIGHER_ORDER_COMP: (Component) => Component,
46
+ }
47
+ )`);
48
+
49
+ const createHigherOrderComponent = template(`
50
+ const COMPONENT_ID = HIGHER_ORDER_COMP_CALL_EXPRESSION;
51
+ `);
52
+
53
+ const equivalentExpression = t.classExpression(
54
+ path.node.id,
55
+ path.node.superClass,
56
+ path.node.body,
57
+ path.node.decorators || []
58
+ );
59
+
60
+ const hocID = t.identifier('convivaTouchableAutoTrack');
61
+
62
+ const convivaImport = convivaLibImport({
63
+ HIGHER_ORDER_COMP: hocID,
64
+ });
65
+
66
+ const autotrackExpression = t.callExpression(
67
+ t.memberExpression(convivaImport.expression, hocID),
68
+ [equivalentExpression]
69
+ );
70
+
71
+ const replacement = createHigherOrderComponent({
72
+ COMPONENT_ID: path.node.id,
73
+ HIGHER_ORDER_COMP_CALL_EXPRESSION: autotrackExpression,
74
+ });
75
+
76
+ path.replaceWith(replacement);
77
+ }
78
+
79
+ // @babel/plugin-transform-react-display-name is listed in this package's
80
+ // dependencies, so it is always present in the package's own node_modules.
81
+ function resolveDisplayNamePlugin() {
82
+ try {
83
+ const mod = require('@babel/plugin-transform-react-display-name');
84
+ return mod.default || mod;
85
+ } catch (_) {}
86
+ throw new Error(
87
+ '[conviva] Could not resolve @babel/plugin-transform-react-display-name. ' +
88
+ 'Make sure it is installed: npm install --save-dev @babel/plugin-transform-react-display-name'
89
+ );
90
+ }
91
+
92
+ // Injects `ClassName.displayName = 'ClassName'` after ES6 class declarations
93
+ // that contain a render() method. This covers the gap left by
94
+ // @babel/plugin-transform-react-display-name v7.x, which only handles
95
+ // React.createClass() / createReactClass() call patterns and has no
96
+ // ClassDeclaration visitor.
97
+ // Touchable components are skipped because they are replaced entirely by the
98
+ // HOC wrapping logic above.
99
+ function injectClassDisplayName(path, t) {
100
+ const className = path.node.id && path.node.id.name;
101
+ if (!className || ALLOWED_TOUCHABLE_COMPONENTS.includes(className)) return;
102
+
103
+ const hasRenderMethod = path.node.body.body.some(
104
+ member =>
105
+ member.type === 'ClassMethod' &&
106
+ member.key &&
107
+ member.key.name === 'render'
108
+ );
109
+ if (!hasRenderMethod) return;
110
+
111
+ path.insertAfter(
112
+ t.expressionStatement(
113
+ t.assignmentExpression(
114
+ '=',
115
+ t.memberExpression(t.identifier(className), t.identifier('displayName')),
116
+ t.stringLiteral(className)
117
+ )
118
+ )
119
+ );
120
+ }
121
+
122
+ function transform(babel) {
123
+ const t = resolveTypes(babel);
124
+ const template = resolveTemplate(babel);
125
+
126
+ return {
127
+ // Bundles @babel/plugin-transform-react-display-name so consumers don't
128
+ // need to add it separately - display name injection is a Conviva concern
129
+ // required for screen_view auto-detection via ConvivaNavigationContainer.
130
+ inherits: resolveDisplayNamePlugin(),
131
+ visitor: {
132
+ ClassDeclaration(path) {
133
+ replaceWithTouchableAutoTrackHigherOrderComponent(path, t, template);
134
+ injectClassDisplayName(path, t);
135
+ },
136
+ },
137
+ };
138
+ }
139
+
140
+ module.exports = transform;