react-native-netmera 2.1.0-alpha05 → 2.1.0-beta02
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/README.md +15 -12
- package/android/src/main/java/com/netmera/reactnativesdk/RNNetmeraModule.kt +7 -7
- package/ios/RNNetmeraRCTEventEmitter.swift +3 -1
- package/lib/module/NetmeraAnalyticProvider.js +18 -12
- package/lib/module/NetmeraAnalyticProvider.js.map +1 -1
- package/lib/module/autotracking/useNavigationTracking.js +3 -1
- package/lib/module/autotracking/useNavigationTracking.js.map +1 -1
- package/lib/module/autotracking/useTapTracking.js +60 -26
- package/lib/module/autotracking/useTapTracking.js.map +1 -1
- package/lib/typescript/src/NetmeraAnalyticProvider.d.ts.map +1 -1
- package/lib/typescript/src/autotracking/useNavigationTracking.d.ts.map +1 -1
- package/lib/typescript/src/autotracking/useTapTracking.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/NetmeraAnalyticProvider.tsx +26 -18
- package/src/autotracking/useNavigationTracking.ts +3 -1
- package/src/autotracking/useTapTracking.ts +56 -24
package/README.md
CHANGED
|
@@ -555,13 +555,20 @@ Netmera Autotracking automatically captures screen transitions via **React Navig
|
|
|
555
555
|
|
|
556
556
|
### NetmeraAnalyticProvider
|
|
557
557
|
|
|
558
|
-
Wrap your `
|
|
558
|
+
Wrap your app with `NetmeraAnalyticProvider` and pass a `navigationRef` so the provider can subscribe to screen changes. The provider handles both screen tracking and tap tracking based on the configuration received from the Netmera dashboard.
|
|
559
|
+
|
|
560
|
+
**Dynamic API** (React Navigation v6 / v7):
|
|
559
561
|
|
|
560
562
|
```tsx
|
|
563
|
+
import { useNavigationContainerRef, NavigationContainer } from '@react-navigation/native';
|
|
564
|
+
import { NetmeraAnalyticProvider } from 'react-native-netmera';
|
|
565
|
+
|
|
561
566
|
export default function App() {
|
|
567
|
+
const navigationRef = useNavigationContainerRef();
|
|
568
|
+
|
|
562
569
|
return (
|
|
563
|
-
<NetmeraAnalyticProvider>
|
|
564
|
-
<NavigationContainer>
|
|
570
|
+
<NetmeraAnalyticProvider navigationRef={navigationRef}>
|
|
571
|
+
<NavigationContainer ref={navigationRef}>
|
|
565
572
|
{/* your navigators */}
|
|
566
573
|
</NavigationContainer>
|
|
567
574
|
</NetmeraAnalyticProvider>
|
|
@@ -569,24 +576,20 @@ export default function App() {
|
|
|
569
576
|
}
|
|
570
577
|
```
|
|
571
578
|
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
On **React Navigation v7+** the provider locates the navigation container automatically via the React fiber tree (no extra configuration needed).
|
|
575
|
-
|
|
576
|
-
On **React Navigation v6 and below** the fiber-based detection is not available. Pass an explicit `navigationRef` prop so the provider can subscribe to screen changes:
|
|
579
|
+
**Static API** (React Navigation v7):
|
|
577
580
|
|
|
578
581
|
```tsx
|
|
579
|
-
import { useNavigationContainerRef,
|
|
582
|
+
import { useNavigationContainerRef, createStaticNavigation } from '@react-navigation/native';
|
|
580
583
|
import { NetmeraAnalyticProvider } from 'react-native-netmera';
|
|
581
584
|
|
|
585
|
+
const Navigation = createStaticNavigation(RootStack);
|
|
586
|
+
|
|
582
587
|
export default function App() {
|
|
583
588
|
const navigationRef = useNavigationContainerRef();
|
|
584
589
|
|
|
585
590
|
return (
|
|
586
591
|
<NetmeraAnalyticProvider navigationRef={navigationRef}>
|
|
587
|
-
<
|
|
588
|
-
{/* your navigators */}
|
|
589
|
-
</NavigationContainer>
|
|
592
|
+
<Navigation ref={navigationRef} />
|
|
590
593
|
</NetmeraAnalyticProvider>
|
|
591
594
|
);
|
|
592
595
|
}
|
|
@@ -63,7 +63,7 @@ class RNNetmeraModule(reactContext: ReactApplicationContext) :
|
|
|
63
63
|
|
|
64
64
|
@ReactMethod(isBlockingSynchronousMethod = true)
|
|
65
65
|
fun checkNotificationPermission(): String {
|
|
66
|
-
val activity: Activity? = reactContext
|
|
66
|
+
val activity: Activity? = reactContext?.currentActivity
|
|
67
67
|
return if (activity != null) {
|
|
68
68
|
Netmera.checkNotificationPermission(activity).toString()
|
|
69
69
|
} else {
|
|
@@ -74,7 +74,7 @@ class RNNetmeraModule(reactContext: ReactApplicationContext) :
|
|
|
74
74
|
|
|
75
75
|
@ReactMethod
|
|
76
76
|
fun requestPushNotificationAuthorization(promise: Promise) {
|
|
77
|
-
val activity: Activity? = reactContext
|
|
77
|
+
val activity: Activity? = reactContext?.currentActivity
|
|
78
78
|
if (activity == null) {
|
|
79
79
|
promise.reject(
|
|
80
80
|
ERROR_CODE_INVALID_ACTIVITY,
|
|
@@ -702,18 +702,18 @@ class RNNetmeraModule(reactContext: ReactApplicationContext) :
|
|
|
702
702
|
const val ERROR_MESSAGE_NOTIFICATION_PERMISSION =
|
|
703
703
|
"Error occurred while requesting notification permission. "
|
|
704
704
|
|
|
705
|
-
|
|
705
|
+
var reactContext: ReactApplicationContext? = null
|
|
706
706
|
|
|
707
707
|
fun emitEvent(eventName: String, eventData: String) {
|
|
708
708
|
reactContext
|
|
709
|
-
|
|
710
|
-
|
|
709
|
+
?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
710
|
+
?.emit(eventName, eventData)
|
|
711
711
|
}
|
|
712
712
|
|
|
713
713
|
fun emitEvent(eventName: String, eventData: WritableMap) {
|
|
714
714
|
reactContext
|
|
715
|
-
|
|
716
|
-
|
|
715
|
+
?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
716
|
+
?.emit(eventName, eventData)
|
|
717
717
|
}
|
|
718
718
|
|
|
719
719
|
private fun hasKey(map: MutableMap<*, *>, key: String?): Boolean {
|
|
@@ -154,6 +154,8 @@ public class RNNetmeraRCTEventEmitter: RCTEventEmitter {
|
|
|
154
154
|
|
|
155
155
|
static func onAutoTrackConfigUpdate(_ body: [String: Bool]) {
|
|
156
156
|
guard let emitter = emitterInstance else { return }
|
|
157
|
-
|
|
157
|
+
DispatchQueue.main.async {
|
|
158
|
+
emitter.sendEvent(withName: EventName.onAutoTrackConfigUpdate, body: body)
|
|
159
|
+
}
|
|
158
160
|
}
|
|
159
161
|
}
|
|
@@ -9,6 +9,7 @@ import { NativeEventEmitter, NativeModules, StyleSheet, View } from 'react-nativ
|
|
|
9
9
|
import { useNavigationTracking } from "./autotracking/useNavigationTracking.js";
|
|
10
10
|
import { useTapTracking } from "./autotracking/useTapTracking.js";
|
|
11
11
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
12
|
+
const _emitter = new NativeEventEmitter(NativeModules.RNNetmeraRCTEventEmitter);
|
|
12
13
|
/**
|
|
13
14
|
* Wraps your app to enable automatic screen tracking and tap tracking.
|
|
14
15
|
* Place it outside your NavigationContainer (or Static Navigation component).
|
|
@@ -19,23 +20,28 @@ export function NetmeraAnalyticProvider({
|
|
|
19
20
|
}) {
|
|
20
21
|
const [config, setConfig] = useState(null);
|
|
21
22
|
const appliedConfigRef = useRef(null);
|
|
22
|
-
const applyConfig =
|
|
23
|
-
const
|
|
24
|
-
if (
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
const applyConfig = incomingConfig => {
|
|
24
|
+
const currentConfig = appliedConfigRef.current;
|
|
25
|
+
if (currentConfig?.isScreenFlowEnabled === incomingConfig.isScreenFlowEnabled && currentConfig?.isInputActionEnabled === incomingConfig.isInputActionEnabled && currentConfig?.shouldCollectValues === incomingConfig.shouldCollectValues) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
appliedConfigRef.current = incomingConfig;
|
|
29
|
+
setConfig(incomingConfig);
|
|
30
|
+
console.log('[NMAutotrack] screen tracking', incomingConfig.isScreenFlowEnabled ? 'enabled' : 'disabled');
|
|
31
|
+
console.log('[NMAutotrack] input action tracking', incomingConfig.isInputActionEnabled ? `enabled ${incomingConfig.shouldCollectValues ? 'with' : 'without'} collection values` : 'disabled');
|
|
29
32
|
};
|
|
30
33
|
useEffect(() => {
|
|
31
|
-
NativeModules.RNNetmera?.getAutoTrackConfig?.()?.then(
|
|
32
|
-
if (
|
|
34
|
+
NativeModules.RNNetmera?.getAutoTrackConfig?.()?.then(fetchedConfig => {
|
|
35
|
+
if (fetchedConfig) {
|
|
36
|
+
applyConfig(fetchedConfig);
|
|
37
|
+
}
|
|
33
38
|
})?.catch(_err => {});
|
|
34
39
|
}, []);
|
|
35
40
|
useEffect(() => {
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
41
|
+
const subscription = _emitter.addListener('onAutoTrackConfigUpdate', updatedConfig => {
|
|
42
|
+
if (updatedConfig) {
|
|
43
|
+
applyConfig(updatedConfig);
|
|
44
|
+
}
|
|
39
45
|
});
|
|
40
46
|
return () => subscription.remove();
|
|
41
47
|
}, []);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","useEffect","useRef","useState","NativeEventEmitter","NativeModules","StyleSheet","View","useNavigationTracking","useTapTracking","jsx","_jsx","NetmeraAnalyticProvider","children","navigationRef","config","setConfig","appliedConfigRef","applyConfig","
|
|
1
|
+
{"version":3,"names":["React","useEffect","useRef","useState","NativeEventEmitter","NativeModules","StyleSheet","View","useNavigationTracking","useTapTracking","jsx","_jsx","_emitter","RNNetmeraRCTEventEmitter","NetmeraAnalyticProvider","children","navigationRef","config","setConfig","appliedConfigRef","applyConfig","incomingConfig","currentConfig","current","isScreenFlowEnabled","isInputActionEnabled","shouldCollectValues","console","log","RNNetmera","getAutoTrackConfig","then","fetchedConfig","catch","_err","subscription","addListener","updatedConfig","remove","screenFlowEnabled","inputActionEnabled","onTouchStart","onTouchEnd","style","styles","container","create","flex"],"sourceRoot":"../../src","sources":["NetmeraAnalyticProvider.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -30,7 +30,9 @@ export function useNavigationTracking(navigationRef, enabled, screenLogEnabled)
|
|
|
30
30
|
screenLogEnabledRef.current = screenLogEnabled;
|
|
31
31
|
}, [screenLogEnabled]);
|
|
32
32
|
useEffect(() => {
|
|
33
|
-
if (!enabled || !isNavContainerRef(navigationRef?.current))
|
|
33
|
+
if (!enabled || !isNavContainerRef(navigationRef?.current)) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
34
36
|
const navRef = navigationRef.current;
|
|
35
37
|
const handleChange = () => {
|
|
36
38
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["useEffect","useRef","setCurrentScreen","RNNetmera","isNavContainerRef","value","addListener","getCurrentRoute","isReady","useNavigationTracking","navigationRef","enabled","screenLogEnabled","screenLogEnabledRef","current","navRef","handleChange","route","name","trackView","_","unsubState","unsubReady","undefined"],"sourceRoot":"../../../src","sources":["autotracking/useNavigationTracking.ts"],"mappings":";;AAAA;AACA;AACA;;AAEA,SAASA,SAAS,EAAEC,MAAM,QAAQ,OAAO;AAEzC,SAASC,gBAAgB,QAAQ,6BAA0B;AAC3D,SAASC,SAAS,QAAQ,uBAAoB;;AAE9C;AACA,SAASC,iBAAiBA,CAACC,KAAU,EAAW;EAC9C,OACEA,KAAK,IAAI,IAAI,IACb,OAAOA,KAAK,CAACC,WAAW,KAAK,UAAU,IACvC,OAAOD,KAAK,CAACE,eAAe,KAAK,UAAU,IAC3C,OAAOF,KAAK,CAACG,OAAO,KAAK,UAAU;AAEvC;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,qBAAqBA,CACnCC,aAA+C,EAC/CC,OAAgB,EAChBC,gBAAyB,EACnB;EACN,MAAMC,mBAAmB,GAAGZ,MAAM,CAACW,gBAAgB,CAAC;EAEpDZ,SAAS,CAAC,MAAM;IACda,mBAAmB,CAACC,OAAO,GAAGF,gBAAgB;EAChD,CAAC,EAAE,CAACA,gBAAgB,CAAC,CAAC;EAEtBZ,SAAS,CAAC,MAAM;IACd,IAAI,CAACW,OAAO,IAAI,CAACP,iBAAiB,CAACM,aAAa,EAAEI,OAAO,CAAC,EAAE;
|
|
1
|
+
{"version":3,"names":["useEffect","useRef","setCurrentScreen","RNNetmera","isNavContainerRef","value","addListener","getCurrentRoute","isReady","useNavigationTracking","navigationRef","enabled","screenLogEnabled","screenLogEnabledRef","current","navRef","handleChange","route","name","trackView","_","unsubState","unsubReady","undefined"],"sourceRoot":"../../../src","sources":["autotracking/useNavigationTracking.ts"],"mappings":";;AAAA;AACA;AACA;;AAEA,SAASA,SAAS,EAAEC,MAAM,QAAQ,OAAO;AAEzC,SAASC,gBAAgB,QAAQ,6BAA0B;AAC3D,SAASC,SAAS,QAAQ,uBAAoB;;AAE9C;AACA,SAASC,iBAAiBA,CAACC,KAAU,EAAW;EAC9C,OACEA,KAAK,IAAI,IAAI,IACb,OAAOA,KAAK,CAACC,WAAW,KAAK,UAAU,IACvC,OAAOD,KAAK,CAACE,eAAe,KAAK,UAAU,IAC3C,OAAOF,KAAK,CAACG,OAAO,KAAK,UAAU;AAEvC;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,qBAAqBA,CACnCC,aAA+C,EAC/CC,OAAgB,EAChBC,gBAAyB,EACnB;EACN,MAAMC,mBAAmB,GAAGZ,MAAM,CAACW,gBAAgB,CAAC;EAEpDZ,SAAS,CAAC,MAAM;IACda,mBAAmB,CAACC,OAAO,GAAGF,gBAAgB;EAChD,CAAC,EAAE,CAACA,gBAAgB,CAAC,CAAC;EAEtBZ,SAAS,CAAC,MAAM;IACd,IAAI,CAACW,OAAO,IAAI,CAACP,iBAAiB,CAACM,aAAa,EAAEI,OAAO,CAAC,EAAE;MAC1D;IACF;IAEA,MAAMC,MAAM,GAAGL,aAAa,CAAEI,OAAO;IAErC,MAAME,YAAY,GAAGA,CAAA,KAAM;MACzB,IAAI;QACF,MAAMC,KAAK,GAAGF,MAAM,CAACR,eAAe,CAAC,CAAC;QACtC,IAAIU,KAAK,EAAEC,IAAI,EAAE;UACfhB,gBAAgB,CAACe,KAAK,CAACC,IAAI,CAAC;UAC5B,IAAIL,mBAAmB,CAACC,OAAO,EAAE;YAC/BX,SAAS,CAACgB,SAAS,CAACF,KAAK,CAACC,IAAI,CAAC;UACjC;QACF;MACF,CAAC,CAAC,OAAOE,CAAC,EAAE,CAAC;IACf,CAAC;IAED,MAAMC,UAAU,GAAGN,MAAM,CAACT,WAAW,CAAC,OAAO,EAAEU,YAAY,CAAC;;IAE5D;IACA;IACA,IAAIM,UAAoC;IACxC,IAAIP,MAAM,CAACP,OAAO,CAAC,CAAC,EAAE;MACpBQ,YAAY,CAAC,CAAC;IAChB,CAAC,MAAM;MACLM,UAAU,GAAGP,MAAM,CAACT,WAAW,CAAC,OAAO,EAAE,MAAM;QAC7CU,YAAY,CAAC,CAAC;QACdM,UAAU,GAAG,CAAC;QACdA,UAAU,GAAGC,SAAS;MACxB,CAAC,CAAC;IACJ;IAEA,OAAO,MAAM;MACXF,UAAU,GAAG,CAAC;MACdC,UAAU,GAAG,CAAC;IAChB,CAAC;EACH,CAAC,EAAE,CAACX,OAAO,EAAED,aAAa,CAAC,CAAC;AAC9B","ignoreList":[]}
|
|
@@ -28,7 +28,9 @@ function isSwitch(props) {
|
|
|
28
28
|
function isInsideSelectionControl(fiber) {
|
|
29
29
|
let node = fiber?.return;
|
|
30
30
|
for (let d = 0; d < 5 && node; d++, node = node.return) {
|
|
31
|
-
if (node?.memoizedProps?.onSelect != null)
|
|
31
|
+
if (node?.memoizedProps?.onSelect != null) {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
32
34
|
}
|
|
33
35
|
return false;
|
|
34
36
|
}
|
|
@@ -36,16 +38,22 @@ function isInsideSelectionControl(fiber) {
|
|
|
36
38
|
// ── Identifier resolution ─────────────────────────────────────────────────────
|
|
37
39
|
|
|
38
40
|
function textFromChildren(children, depth = 0) {
|
|
39
|
-
if (depth > MAX_TEXT_DEPTH)
|
|
41
|
+
if (depth > MAX_TEXT_DEPTH) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
40
44
|
if (typeof children === 'string') {
|
|
41
45
|
const t = children.trim();
|
|
42
46
|
return t.length > 0 ? t : undefined;
|
|
43
47
|
}
|
|
44
|
-
if (typeof children === 'number')
|
|
48
|
+
if (typeof children === 'number') {
|
|
49
|
+
return String(children);
|
|
50
|
+
}
|
|
45
51
|
if (Array.isArray(children)) {
|
|
46
52
|
for (const child of children) {
|
|
47
53
|
const t = textFromChildren(child, depth + 1);
|
|
48
|
-
if (t)
|
|
54
|
+
if (t) {
|
|
55
|
+
return t;
|
|
56
|
+
}
|
|
49
57
|
}
|
|
50
58
|
return undefined;
|
|
51
59
|
}
|
|
@@ -57,7 +65,9 @@ function textFromChildren(children, depth = 0) {
|
|
|
57
65
|
|
|
58
66
|
// Priority: accessibilityLabel → testID → placeholder (TextInput) → first child text.
|
|
59
67
|
function resolveIdentifier(props) {
|
|
60
|
-
if (!props)
|
|
68
|
+
if (!props) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
61
71
|
if (typeof props.accessibilityLabel === 'string' && props.accessibilityLabel.trim()) {
|
|
62
72
|
return props.accessibilityLabel.trim();
|
|
63
73
|
}
|
|
@@ -96,7 +106,9 @@ function resolveListIndex(startFiber) {
|
|
|
96
106
|
}
|
|
97
107
|
}
|
|
98
108
|
if (sections) {
|
|
99
|
-
if (cellKey.endsWith(':header') || cellKey.endsWith(':footer'))
|
|
109
|
+
if (cellKey.endsWith(':header') || cellKey.endsWith(':footer')) {
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
100
112
|
|
|
101
113
|
// Mirrors VirtualizedSectionList._getItem offset arithmetic:
|
|
102
114
|
// flatIndex 0 → section 0 header
|
|
@@ -106,12 +118,16 @@ function resolveListIndex(startFiber) {
|
|
|
106
118
|
let idx = flatIndex - 1;
|
|
107
119
|
for (let si = 0; si < sections.length; si++) {
|
|
108
120
|
const count = sections[si].data?.length ?? 0;
|
|
109
|
-
if (idx === -1 || idx === count)
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
121
|
+
if (idx === -1 || idx === count) {
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
124
|
+
if (idx < count) {
|
|
125
|
+
return {
|
|
126
|
+
type: 'sectionlist',
|
|
127
|
+
sectionIndex: si,
|
|
128
|
+
itemIndex: idx
|
|
129
|
+
};
|
|
130
|
+
}
|
|
115
131
|
idx -= count + 2;
|
|
116
132
|
}
|
|
117
133
|
return undefined;
|
|
@@ -126,9 +142,10 @@ function resolveListIndex(startFiber) {
|
|
|
126
142
|
|
|
127
143
|
// ── Log path ──────────────────────────────────────────────────────────────────
|
|
128
144
|
|
|
129
|
-
function buildPath(screen, listType, identifier, indexSuffix,
|
|
130
|
-
const
|
|
131
|
-
|
|
145
|
+
function buildPath(screen, listType, identifier, indexSuffix, switchValue) {
|
|
146
|
+
const screenName = screen ?? 'unknown';
|
|
147
|
+
const base = listType ? `${screenName}|${listType}|${identifier}` : `${screenName}|${identifier}`;
|
|
148
|
+
return switchValue !== undefined ? `${base}|${switchValue}${indexSuffix}` : `${base}${indexSuffix}`;
|
|
132
149
|
}
|
|
133
150
|
|
|
134
151
|
// ── Hook ──────────────────────────────────────────────────────────────────────
|
|
@@ -156,7 +173,9 @@ export function useTapTracking(enabled, shouldCollectValues) {
|
|
|
156
173
|
shouldCollectValuesRef.current = shouldCollectValues;
|
|
157
174
|
}, [shouldCollectValues]);
|
|
158
175
|
const onTouchStart = useCallback(e => {
|
|
159
|
-
if (!enabledRef.current)
|
|
176
|
+
if (!enabledRef.current) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
160
179
|
let switchValue;
|
|
161
180
|
try {
|
|
162
181
|
let fiber = e._targetInst;
|
|
@@ -175,16 +194,23 @@ export function useTapTracking(enabled, shouldCollectValues) {
|
|
|
175
194
|
};
|
|
176
195
|
}, []);
|
|
177
196
|
const onTouchEnd = useCallback(e => {
|
|
178
|
-
if (!enabledRef.current)
|
|
197
|
+
if (!enabledRef.current) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
179
200
|
const start = touchStartRef.current;
|
|
180
|
-
if (start) {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
201
|
+
if (!start) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const dx = Math.abs(e.nativeEvent.pageX - start.x);
|
|
205
|
+
const dy = Math.abs(e.nativeEvent.pageY - start.y);
|
|
206
|
+
if (dx > TAP_THRESHOLD || dy > TAP_THRESHOLD) {
|
|
207
|
+
return;
|
|
184
208
|
}
|
|
185
209
|
try {
|
|
186
210
|
let node = e._targetInst;
|
|
187
|
-
if (!node)
|
|
211
|
+
if (!node) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
188
214
|
|
|
189
215
|
// Pass 1: walk up to find the first interactive ancestor.
|
|
190
216
|
// e.g. tapping a <Text> inside a <Pressable> yields the Pressable.
|
|
@@ -198,7 +224,9 @@ export function useTapTracking(enabled, shouldCollectValues) {
|
|
|
198
224
|
node = node.return;
|
|
199
225
|
depth++;
|
|
200
226
|
}
|
|
201
|
-
if (!interactiveNode)
|
|
227
|
+
if (!interactiveNode) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
202
230
|
|
|
203
231
|
// Pass 2: resolve identifier from the interactive fiber and up to 2 ancestors.
|
|
204
232
|
// The look-ahead handles TouchableOpacity, where the inner Animated.View fiber
|
|
@@ -207,12 +235,18 @@ export function useTapTracking(enabled, shouldCollectValues) {
|
|
|
207
235
|
let identifier;
|
|
208
236
|
for (let i = 0; i < 3 && identifierNode; i++) {
|
|
209
237
|
identifier = resolveIdentifier(identifierNode.memoizedProps);
|
|
210
|
-
if (identifier)
|
|
238
|
+
if (identifier) {
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
211
241
|
identifierNode = identifierNode.return;
|
|
212
242
|
}
|
|
213
|
-
if (!identifier)
|
|
243
|
+
if (!identifier) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
214
246
|
const isSwitchNode = isSwitch(interactiveNode.memoizedProps);
|
|
215
|
-
if (!isSwitchNode && isInsideSelectionControl(interactiveNode))
|
|
247
|
+
if (!isSwitchNode && isInsideSelectionControl(interactiveNode)) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
216
250
|
const screen = getCurrentScreen();
|
|
217
251
|
if (screen !== lastScreenRef.current) {
|
|
218
252
|
switchLastLoggedRef.current.clear();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["useCallback","useEffect","useRef","getCurrentScreen","RNNetmera","MAX_FIBER_DEPTH","MAX_TEXT_DEPTH","TAP_THRESHOLD","isInteractive","props","onPress","onClick","onValueChange","isSwitch","value","isInsideSelectionControl","fiber","node","return","d","memoizedProps","onSelect","textFromChildren","children","depth","undefined","t","trim","length","String","Array","isArray","child","resolveIdentifier","accessibilityLabel","testID","placeholder","resolveListIndex","startFiber","p","index","cellKey","onUnmount","flatIndex","stateNode","sections","up","i","upProps","endsWith","idx","si","count","data","type","sectionIndex","itemIndex","buildPath","screen","listType","identifier","indexSuffix","base","useTapTracking","enabled","shouldCollectValues","enabledRef","shouldCollectValuesRef","touchStartRef","lastScreenRef","switchLastLoggedRef","Map","current","clear","onTouchStart","e","
|
|
1
|
+
{"version":3,"names":["useCallback","useEffect","useRef","getCurrentScreen","RNNetmera","MAX_FIBER_DEPTH","MAX_TEXT_DEPTH","TAP_THRESHOLD","isInteractive","props","onPress","onClick","onValueChange","isSwitch","value","isInsideSelectionControl","fiber","node","return","d","memoizedProps","onSelect","textFromChildren","children","depth","undefined","t","trim","length","String","Array","isArray","child","resolveIdentifier","accessibilityLabel","testID","placeholder","resolveListIndex","startFiber","p","index","cellKey","onUnmount","flatIndex","stateNode","sections","up","i","upProps","endsWith","idx","si","count","data","type","sectionIndex","itemIndex","buildPath","screen","listType","identifier","indexSuffix","switchValue","screenName","base","useTapTracking","enabled","shouldCollectValues","enabledRef","shouldCollectValuesRef","touchStartRef","lastScreenRef","switchLastLoggedRef","Map","current","clear","onTouchStart","e","_targetInst","_","x","nativeEvent","pageX","y","pageY","onTouchEnd","start","dx","Math","abs","dy","interactiveNode","identifierNode","isSwitchNode","listIndex","lastLogged","get","newValue","preTapValue","set","switchPath","trackAction","tapPath"],"sourceRoot":"../../../src","sources":["autotracking/useTapTracking.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NetmeraAnalyticProvider.d.ts","sourceRoot":"","sources":["../../../src/NetmeraAnalyticProvider.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAsC,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"NetmeraAnalyticProvider.d.ts","sourceRoot":"","sources":["../../../src/NetmeraAnalyticProvider.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAY3D,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B;;;;;;;;;;;;;;;;;;;OAmBG;IACH,aAAa,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;CACtC;AAQD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,EACtC,QAAQ,EACR,aAAa,GACd,EAAE,4BAA4B,2CA4E9B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useNavigationTracking.d.ts","sourceRoot":"","sources":["../../../../src/autotracking/useNavigationTracking.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAc/B;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,aAAa,EAAE,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,SAAS,EAC/C,OAAO,EAAE,OAAO,EAChB,gBAAgB,EAAE,OAAO,GACxB,IAAI,
|
|
1
|
+
{"version":3,"file":"useNavigationTracking.d.ts","sourceRoot":"","sources":["../../../../src/autotracking/useNavigationTracking.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAc/B;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,aAAa,EAAE,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,SAAS,EAC/C,OAAO,EAAE,OAAO,EAChB,gBAAgB,EAAE,OAAO,GACxB,IAAI,CA8CN"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useTapTracking.d.ts","sourceRoot":"","sources":["../../../../src/autotracking/useTapTracking.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"useTapTracking.d.ts","sourceRoot":"","sources":["../../../../src/autotracking/useTapTracking.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AA4K1D,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,mBAAmB,EAAE,OAAO;sBA6BtC,qBAAqB;oBAsBvB,qBAAqB;EA6GzD"}
|
package/package.json
CHANGED
|
@@ -12,6 +12,8 @@ import {
|
|
|
12
12
|
import { useNavigationTracking } from './autotracking/useNavigationTracking';
|
|
13
13
|
import { useTapTracking } from './autotracking/useTapTracking';
|
|
14
14
|
|
|
15
|
+
const _emitter = new NativeEventEmitter(NativeModules.RNNetmeraRCTEventEmitter);
|
|
16
|
+
|
|
15
17
|
export interface NetmeraAnalyticProviderProps {
|
|
16
18
|
children: React.ReactNode;
|
|
17
19
|
/**
|
|
@@ -54,42 +56,48 @@ export function NetmeraAnalyticProvider({
|
|
|
54
56
|
const [config, setConfig] = useState<AutoTrackConfig | null>(null);
|
|
55
57
|
const appliedConfigRef = useRef<AutoTrackConfig | null>(null);
|
|
56
58
|
|
|
57
|
-
const applyConfig = (
|
|
58
|
-
const
|
|
59
|
+
const applyConfig = (incomingConfig: AutoTrackConfig) => {
|
|
60
|
+
const currentConfig = appliedConfigRef.current;
|
|
59
61
|
if (
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
currentConfig?.isScreenFlowEnabled ===
|
|
63
|
+
incomingConfig.isScreenFlowEnabled &&
|
|
64
|
+
currentConfig?.isInputActionEnabled ===
|
|
65
|
+
incomingConfig.isInputActionEnabled &&
|
|
66
|
+
currentConfig?.shouldCollectValues === incomingConfig.shouldCollectValues
|
|
67
|
+
) {
|
|
64
68
|
return;
|
|
65
|
-
|
|
66
|
-
|
|
69
|
+
}
|
|
70
|
+
appliedConfigRef.current = incomingConfig;
|
|
71
|
+
setConfig(incomingConfig);
|
|
67
72
|
console.log(
|
|
68
73
|
'[NMAutotrack] screen tracking',
|
|
69
|
-
|
|
74
|
+
incomingConfig.isScreenFlowEnabled ? 'enabled' : 'disabled'
|
|
70
75
|
);
|
|
71
76
|
console.log(
|
|
72
77
|
'[NMAutotrack] input action tracking',
|
|
73
|
-
|
|
78
|
+
incomingConfig.isInputActionEnabled
|
|
79
|
+
? `enabled ${incomingConfig.shouldCollectValues ? 'with' : 'without'} collection values`
|
|
80
|
+
: 'disabled'
|
|
74
81
|
);
|
|
75
82
|
};
|
|
76
83
|
|
|
77
84
|
useEffect(() => {
|
|
78
85
|
NativeModules.RNNetmera?.getAutoTrackConfig?.()
|
|
79
|
-
?.then((
|
|
80
|
-
if (
|
|
86
|
+
?.then((fetchedConfig: AutoTrackConfig | null) => {
|
|
87
|
+
if (fetchedConfig) {
|
|
88
|
+
applyConfig(fetchedConfig);
|
|
89
|
+
}
|
|
81
90
|
})
|
|
82
91
|
?.catch((_err: unknown) => {});
|
|
83
92
|
}, []);
|
|
84
93
|
|
|
85
94
|
useEffect(() => {
|
|
86
|
-
const
|
|
87
|
-
NativeModules.RNNetmeraRCTEventEmitter
|
|
88
|
-
);
|
|
89
|
-
const subscription = emitter.addListener(
|
|
95
|
+
const subscription = _emitter.addListener(
|
|
90
96
|
'onAutoTrackConfigUpdate',
|
|
91
|
-
(
|
|
92
|
-
if (
|
|
97
|
+
(updatedConfig: AutoTrackConfig) => {
|
|
98
|
+
if (updatedConfig) {
|
|
99
|
+
applyConfig(updatedConfig);
|
|
100
|
+
}
|
|
93
101
|
}
|
|
94
102
|
);
|
|
95
103
|
return () => subscription.remove();
|
|
@@ -40,7 +40,9 @@ export function useNavigationTracking(
|
|
|
40
40
|
}, [screenLogEnabled]);
|
|
41
41
|
|
|
42
42
|
useEffect(() => {
|
|
43
|
-
if (!enabled || !isNavContainerRef(navigationRef?.current))
|
|
43
|
+
if (!enabled || !isNavContainerRef(navigationRef?.current)) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
44
46
|
|
|
45
47
|
const navRef = navigationRef!.current;
|
|
46
48
|
|
|
@@ -32,7 +32,9 @@ function isSwitch(props: any): boolean {
|
|
|
32
32
|
function isInsideSelectionControl(fiber: any): boolean {
|
|
33
33
|
let node: any = fiber?.return;
|
|
34
34
|
for (let d = 0; d < 5 && node; d++, node = node.return) {
|
|
35
|
-
if (node?.memoizedProps?.onSelect != null)
|
|
35
|
+
if (node?.memoizedProps?.onSelect != null) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
36
38
|
}
|
|
37
39
|
return false;
|
|
38
40
|
}
|
|
@@ -40,16 +42,22 @@ function isInsideSelectionControl(fiber: any): boolean {
|
|
|
40
42
|
// ── Identifier resolution ─────────────────────────────────────────────────────
|
|
41
43
|
|
|
42
44
|
function textFromChildren(children: any, depth = 0): string | undefined {
|
|
43
|
-
if (depth > MAX_TEXT_DEPTH)
|
|
45
|
+
if (depth > MAX_TEXT_DEPTH) {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
44
48
|
if (typeof children === 'string') {
|
|
45
49
|
const t = children.trim();
|
|
46
50
|
return t.length > 0 ? t : undefined;
|
|
47
51
|
}
|
|
48
|
-
if (typeof children === 'number')
|
|
52
|
+
if (typeof children === 'number') {
|
|
53
|
+
return String(children);
|
|
54
|
+
}
|
|
49
55
|
if (Array.isArray(children)) {
|
|
50
56
|
for (const child of children) {
|
|
51
57
|
const t = textFromChildren(child, depth + 1);
|
|
52
|
-
if (t)
|
|
58
|
+
if (t) {
|
|
59
|
+
return t;
|
|
60
|
+
}
|
|
53
61
|
}
|
|
54
62
|
return undefined;
|
|
55
63
|
}
|
|
@@ -61,7 +69,9 @@ function textFromChildren(children: any, depth = 0): string | undefined {
|
|
|
61
69
|
|
|
62
70
|
// Priority: accessibilityLabel → testID → placeholder (TextInput) → first child text.
|
|
63
71
|
function resolveIdentifier(props: any): string | undefined {
|
|
64
|
-
if (!props)
|
|
72
|
+
if (!props) {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
65
75
|
if (
|
|
66
76
|
typeof props.accessibilityLabel === 'string' &&
|
|
67
77
|
props.accessibilityLabel.trim()
|
|
@@ -117,8 +127,9 @@ function resolveListIndex(startFiber: any): ListIndex | undefined {
|
|
|
117
127
|
}
|
|
118
128
|
|
|
119
129
|
if (sections) {
|
|
120
|
-
if (cellKey.endsWith(':header') || cellKey.endsWith(':footer'))
|
|
130
|
+
if (cellKey.endsWith(':header') || cellKey.endsWith(':footer')) {
|
|
121
131
|
return undefined;
|
|
132
|
+
}
|
|
122
133
|
|
|
123
134
|
// Mirrors VirtualizedSectionList._getItem offset arithmetic:
|
|
124
135
|
// flatIndex 0 → section 0 header
|
|
@@ -128,9 +139,12 @@ function resolveListIndex(startFiber: any): ListIndex | undefined {
|
|
|
128
139
|
let idx = flatIndex - 1;
|
|
129
140
|
for (let si = 0; si < sections.length; si++) {
|
|
130
141
|
const count = sections[si].data?.length ?? 0;
|
|
131
|
-
if (idx === -1 || idx === count)
|
|
132
|
-
|
|
142
|
+
if (idx === -1 || idx === count) {
|
|
143
|
+
return undefined;
|
|
144
|
+
}
|
|
145
|
+
if (idx < count) {
|
|
133
146
|
return { type: 'sectionlist', sectionIndex: si, itemIndex: idx };
|
|
147
|
+
}
|
|
134
148
|
idx -= count + 2;
|
|
135
149
|
}
|
|
136
150
|
return undefined;
|
|
@@ -148,13 +162,14 @@ function buildPath(
|
|
|
148
162
|
listType: string | null,
|
|
149
163
|
identifier: string,
|
|
150
164
|
indexSuffix: string,
|
|
151
|
-
|
|
165
|
+
switchValue?: boolean
|
|
152
166
|
): string {
|
|
167
|
+
const screenName = screen ?? 'unknown';
|
|
153
168
|
const base = listType
|
|
154
|
-
? `${
|
|
155
|
-
: `${
|
|
156
|
-
return
|
|
157
|
-
? `${base}|${
|
|
169
|
+
? `${screenName}|${listType}|${identifier}`
|
|
170
|
+
: `${screenName}|${identifier}`;
|
|
171
|
+
return switchValue !== undefined
|
|
172
|
+
? `${base}|${switchValue}${indexSuffix}`
|
|
158
173
|
: `${base}${indexSuffix}`;
|
|
159
174
|
}
|
|
160
175
|
|
|
@@ -190,7 +205,9 @@ export function useTapTracking(enabled: boolean, shouldCollectValues: boolean) {
|
|
|
190
205
|
}, [shouldCollectValues]);
|
|
191
206
|
|
|
192
207
|
const onTouchStart = useCallback((e: GestureResponderEvent) => {
|
|
193
|
-
if (!enabledRef.current)
|
|
208
|
+
if (!enabledRef.current) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
194
211
|
let switchValue: boolean | undefined;
|
|
195
212
|
try {
|
|
196
213
|
let fiber: any = (e as any)._targetInst;
|
|
@@ -210,17 +227,24 @@ export function useTapTracking(enabled: boolean, shouldCollectValues: boolean) {
|
|
|
210
227
|
}, []);
|
|
211
228
|
|
|
212
229
|
const onTouchEnd = useCallback((e: GestureResponderEvent) => {
|
|
213
|
-
if (!enabledRef.current)
|
|
230
|
+
if (!enabledRef.current) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
214
233
|
const start = touchStartRef.current;
|
|
215
|
-
if (start) {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
234
|
+
if (!start) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const dx = Math.abs(e.nativeEvent.pageX - start.x);
|
|
238
|
+
const dy = Math.abs(e.nativeEvent.pageY - start.y);
|
|
239
|
+
if (dx > TAP_THRESHOLD || dy > TAP_THRESHOLD) {
|
|
240
|
+
return;
|
|
219
241
|
}
|
|
220
242
|
|
|
221
243
|
try {
|
|
222
244
|
let node: any = (e as any)._targetInst;
|
|
223
|
-
if (!node)
|
|
245
|
+
if (!node) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
224
248
|
|
|
225
249
|
// Pass 1: walk up to find the first interactive ancestor.
|
|
226
250
|
// e.g. tapping a <Text> inside a <Pressable> yields the Pressable.
|
|
@@ -234,7 +258,9 @@ export function useTapTracking(enabled: boolean, shouldCollectValues: boolean) {
|
|
|
234
258
|
node = node.return;
|
|
235
259
|
depth++;
|
|
236
260
|
}
|
|
237
|
-
if (!interactiveNode)
|
|
261
|
+
if (!interactiveNode) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
238
264
|
|
|
239
265
|
// Pass 2: resolve identifier from the interactive fiber and up to 2 ancestors.
|
|
240
266
|
// The look-ahead handles TouchableOpacity, where the inner Animated.View fiber
|
|
@@ -243,14 +269,20 @@ export function useTapTracking(enabled: boolean, shouldCollectValues: boolean) {
|
|
|
243
269
|
let identifier: string | undefined;
|
|
244
270
|
for (let i = 0; i < 3 && identifierNode; i++) {
|
|
245
271
|
identifier = resolveIdentifier(identifierNode.memoizedProps);
|
|
246
|
-
if (identifier)
|
|
272
|
+
if (identifier) {
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
247
275
|
identifierNode = identifierNode.return;
|
|
248
276
|
}
|
|
249
277
|
|
|
250
|
-
if (!identifier)
|
|
278
|
+
if (!identifier) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
251
281
|
|
|
252
282
|
const isSwitchNode = isSwitch(interactiveNode.memoizedProps);
|
|
253
|
-
if (!isSwitchNode && isInsideSelectionControl(interactiveNode))
|
|
283
|
+
if (!isSwitchNode && isInsideSelectionControl(interactiveNode)) {
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
254
286
|
|
|
255
287
|
const screen = getCurrentScreen();
|
|
256
288
|
if (screen !== lastScreenRef.current) {
|