react-native-acoustic-connect-beta 18.0.13 → 18.0.15
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/Examples/SampleUI/.detoxrc.js +83 -0
- package/Examples/SampleUI/ConnectConfig.json +2 -2
- package/Examples/SampleUI/android/app/build.gradle +3 -0
- package/Examples/SampleUI/android/app/src/main/java/com/sampleui/MainActivity.kt +0 -35
- package/Examples/SampleUI/android/settings.gradle +1 -1
- package/Examples/SampleUI/package.json +8 -6
- package/Examples/SampleUI/scripts/integration-test-android.sh +292 -0
- package/Examples/SampleUI/src/Examples/DialogExample.tsx +88 -2
- package/Examples/SampleUI/src/Examples/Dialogs/DialogTrackingTest.tsx +307 -0
- package/Examples/SampleUI/src/Examples/Dialogs/index.tsx +37 -0
- package/Examples/SampleUI/src/index.native.tsx +5 -5
- package/android/build.gradle +2 -2
- package/android/src/main/assets/ConnectAdvancedConfig.json +1 -1
- package/android/src/main/assets/TealeafAdvancedConfig.json +1 -1
- package/android/src/main/java/com/acousticconnectrn/HybridAcousticConnectRN.kt +787 -490
- package/ios/HybridAcousticConnectRN.swift +79 -4
- package/lib/commonjs/TLTRN.js +69 -0
- package/lib/commonjs/TLTRN.js.map +1 -1
- package/lib/commonjs/components/Connect.js +31 -29
- package/lib/commonjs/components/Connect.js.map +1 -1
- package/lib/commonjs/docs/DialogTracking.md +252 -0
- package/lib/commonjs/docs/NativeImplementation.md +176 -0
- package/lib/commonjs/examples/DialogTrackingExample.js +175 -0
- package/lib/commonjs/examples/DialogTrackingExample.js.map +1 -0
- package/lib/commonjs/examples/HOCDialogExample.js +296 -0
- package/lib/commonjs/examples/HOCDialogExample.js.map +1 -0
- package/lib/commonjs/index.js +28 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/utils/DialogDebugger.js +216 -0
- package/lib/commonjs/utils/DialogDebugger.js.map +1 -0
- package/lib/commonjs/utils/DialogListener.js +203 -0
- package/lib/commonjs/utils/DialogListener.js.map +1 -0
- package/lib/commonjs/utils/useDialogTracking.js +107 -0
- package/lib/commonjs/utils/useDialogTracking.js.map +1 -0
- package/lib/commonjs/utils/withAcousticAutoDialog.js +282 -0
- package/lib/commonjs/utils/withAcousticAutoDialog.js.map +1 -0
- package/lib/module/TLTRN.js +69 -0
- package/lib/module/TLTRN.js.map +1 -1
- package/lib/module/components/Connect.js +32 -31
- package/lib/module/components/Connect.js.map +1 -1
- package/lib/module/docs/DialogTracking.md +252 -0
- package/lib/module/docs/NativeImplementation.md +176 -0
- package/lib/module/examples/DialogTrackingExample.js +172 -0
- package/lib/module/examples/DialogTrackingExample.js.map +1 -0
- package/lib/module/examples/HOCDialogExample.js +292 -0
- package/lib/module/examples/HOCDialogExample.js.map +1 -0
- package/lib/module/index.js +5 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/utils/DialogDebugger.js +211 -0
- package/lib/module/utils/DialogDebugger.js.map +1 -0
- package/lib/module/utils/DialogListener.js +199 -0
- package/lib/module/utils/DialogListener.js.map +1 -0
- package/lib/module/utils/useDialogTracking.js +102 -0
- package/lib/module/utils/useDialogTracking.js.map +1 -0
- package/lib/module/utils/withAcousticAutoDialog.js +275 -0
- package/lib/module/utils/withAcousticAutoDialog.js.map +1 -0
- package/lib/typescript/src/TLTRN.d.ts +7 -0
- package/lib/typescript/src/TLTRN.d.ts.map +1 -1
- package/lib/typescript/src/components/Connect.d.ts +2 -2
- package/lib/typescript/src/components/Connect.d.ts.map +1 -1
- package/lib/typescript/src/examples/DialogTrackingExample.d.ts +17 -0
- package/lib/typescript/src/examples/DialogTrackingExample.d.ts.map +1 -0
- package/lib/typescript/src/examples/HOCDialogExample.d.ts +21 -0
- package/lib/typescript/src/examples/HOCDialogExample.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +5 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/react-native-acoustic-connect.nitro.d.ts +4 -0
- package/lib/typescript/src/specs/react-native-acoustic-connect.nitro.d.ts.map +1 -1
- package/lib/typescript/src/utils/DialogDebugger.d.ts +58 -0
- package/lib/typescript/src/utils/DialogDebugger.d.ts.map +1 -0
- package/lib/typescript/src/utils/DialogListener.d.ts +85 -0
- package/lib/typescript/src/utils/DialogListener.d.ts.map +1 -0
- package/lib/typescript/src/utils/useDialogTracking.d.ts +25 -0
- package/lib/typescript/src/utils/useDialogTracking.d.ts.map +1 -0
- package/lib/typescript/src/utils/withAcousticAutoDialog.d.ts +37 -0
- package/lib/typescript/src/utils/withAcousticAutoDialog.d.ts.map +1 -0
- package/nitrogen/generated/android/c++/JHybridAcousticConnectRNSpec.cpp +26 -0
- package/nitrogen/generated/android/c++/JHybridAcousticConnectRNSpec.hpp +4 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/acousticconnectrn/HybridAcousticConnectRNSpec.kt +16 -0
- package/nitrogen/generated/ios/c++/HybridAcousticConnectRNSpecSwift.hpp +32 -0
- package/nitrogen/generated/ios/swift/HybridAcousticConnectRNSpec.swift +4 -0
- package/nitrogen/generated/ios/swift/HybridAcousticConnectRNSpec_cxx.swift +71 -0
- package/nitrogen/generated/shared/c++/HybridAcousticConnectRNSpec.cpp +4 -0
- package/nitrogen/generated/shared/c++/HybridAcousticConnectRNSpec.hpp +4 -0
- package/package.json +1 -1
- package/scripts/ConnectConfig.json +1 -1
- package/src/TLTRN.ts +75 -0
- package/src/components/Connect.tsx +92 -101
- package/src/docs/DialogTracking.md +252 -0
- package/src/docs/NativeImplementation.md +176 -0
- package/src/examples/DialogTrackingExample.tsx +163 -0
- package/src/examples/HOCDialogExample.tsx +253 -0
- package/src/index.ts +5 -1
- package/src/specs/react-native-acoustic-connect.nitro.ts +5 -0
- package/src/utils/DialogDebugger.ts +224 -0
- package/src/utils/DialogListener.ts +238 -0
- package/src/utils/useDialogTracking.ts +102 -0
- package/src/utils/withAcousticAutoDialog.tsx +312 -0
package/src/TLTRN.ts
CHANGED
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
import MessageQueue from "react-native/Libraries/BatchedBridge/MessageQueue.js";
|
|
13
13
|
import { Platform } from "react-native";
|
|
14
14
|
import KeyboardListener from "./utils/KeyboardListener";
|
|
15
|
+
import DialogListener from "./utils/DialogListener";
|
|
16
|
+
import type { DialogEvent, DialogButtonClickEvent, DialogDismissEvent } from "./utils/DialogListener";
|
|
15
17
|
import AcousticConnectRN from './index';
|
|
16
18
|
|
|
17
19
|
// @ts-ignore
|
|
@@ -153,6 +155,79 @@ class TLTRN {
|
|
|
153
155
|
return result;
|
|
154
156
|
};
|
|
155
157
|
|
|
158
|
+
// New dialog event logging methods
|
|
159
|
+
static logDialogShowEvent = async (dialogId: string, dialogTitle: string, dialogType: string) => {
|
|
160
|
+
let result = false
|
|
161
|
+
try {
|
|
162
|
+
result = AcousticConnectRN.logDialogShowEvent(dialogId, dialogTitle, dialogType);
|
|
163
|
+
} catch (error: Error | any) {
|
|
164
|
+
console.log('LogDialogShowEvent error: ', error.message);
|
|
165
|
+
}
|
|
166
|
+
return result;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
static logDialogDismissEvent = async (dialogId: string, dismissReason: string) => {
|
|
170
|
+
let result = false
|
|
171
|
+
try {
|
|
172
|
+
result = AcousticConnectRN.logDialogDismissEvent(dialogId, dismissReason);
|
|
173
|
+
} catch (error: Error | any) {
|
|
174
|
+
console.log('LogDialogDismissEvent error: ', error.message);
|
|
175
|
+
}
|
|
176
|
+
return result;
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
static logDialogButtonClickEvent = async (dialogId: string, buttonText: string, buttonIndex: number) => {
|
|
180
|
+
let result = false
|
|
181
|
+
try {
|
|
182
|
+
result = AcousticConnectRN.logDialogButtonClickEvent(dialogId, buttonText, buttonIndex);
|
|
183
|
+
} catch (error: Error | any) {
|
|
184
|
+
console.log('LogDialogButtonClickEvent error: ', error.message);
|
|
185
|
+
}
|
|
186
|
+
return result;
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
static logDialogCustomEvent = async (dialogId: string, eventName: string, values: Record<string, string | number | boolean>) => {
|
|
190
|
+
let result = false
|
|
191
|
+
try {
|
|
192
|
+
result = AcousticConnectRN.logDialogCustomEvent(dialogId, eventName, values);
|
|
193
|
+
} catch (error: Error | any) {
|
|
194
|
+
console.log('LogDialogCustomEvent error: ', error.message);
|
|
195
|
+
}
|
|
196
|
+
return result;
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
// Dialog event interceptor methods
|
|
200
|
+
static eventListenerRegistered = false;
|
|
201
|
+
static eventListenerUnsubscribe: (() => void) | null = null;
|
|
202
|
+
|
|
203
|
+
static interceptDialogEvents = (enable: boolean) => {
|
|
204
|
+
const dialogListener = DialogListener.getInstance();
|
|
205
|
+
|
|
206
|
+
if (enable && !TLTRN.eventListenerRegistered) {
|
|
207
|
+
dialogListener.startIntercepting();
|
|
208
|
+
TLTRN.eventListenerUnsubscribe = dialogListener.addEventListener((event: DialogEvent | DialogButtonClickEvent | DialogDismissEvent) => {
|
|
209
|
+
if ('buttonText' in event) {
|
|
210
|
+
// This is a button click event
|
|
211
|
+
TLTRN.logDialogButtonClickEvent(event.dialogId, event.buttonText, event.buttonIndex);
|
|
212
|
+
} else if ('dismissReason' in event) {
|
|
213
|
+
// This is a dialog dismiss event
|
|
214
|
+
TLTRN.logDialogDismissEvent(event.dialogId, event.dismissReason);
|
|
215
|
+
} else {
|
|
216
|
+
// This is a dialog show event
|
|
217
|
+
TLTRN.logDialogShowEvent(event.dialogId, event.dialogTitle, event.dialogType);
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
TLTRN.eventListenerRegistered = true;
|
|
221
|
+
} else if (!enable && TLTRN.eventListenerRegistered) {
|
|
222
|
+
dialogListener.stopIntercepting();
|
|
223
|
+
if (TLTRN.eventListenerUnsubscribe) {
|
|
224
|
+
TLTRN.eventListenerUnsubscribe();
|
|
225
|
+
TLTRN.eventListenerUnsubscribe = null;
|
|
226
|
+
}
|
|
227
|
+
TLTRN.eventListenerRegistered = false;
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
|
|
156
231
|
static listenToBridge = (message: any) => {
|
|
157
232
|
if (TLTRN.displayDebug) {
|
|
158
233
|
console.log(
|
|
@@ -9,118 +9,109 @@
|
|
|
9
9
|
********************************************************************************************/
|
|
10
10
|
import React, { useCallback, useEffect, useRef, forwardRef } from "react";
|
|
11
11
|
import { View, StyleSheet, Platform, NativeModules, findNodeHandle } from "react-native";
|
|
12
|
-
import type { LayoutChangeEvent } from "react-native";
|
|
13
|
-
import TLTRN from
|
|
12
|
+
import type { LayoutChangeEvent } from "react-native"; // Use type-only import for LayoutChangeEvent
|
|
13
|
+
import TLTRN from '../TLTRN';
|
|
14
14
|
|
|
15
15
|
interface ConnectProps {
|
|
16
16
|
children: React.ReactNode;
|
|
17
17
|
captureKeyboardEvents: boolean;
|
|
18
|
-
|
|
18
|
+
captureDialogEvents?: boolean; // New prop for dialog event capture
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
const Connect =
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
<View
|
|
102
|
-
style={styles.connect_main}
|
|
103
|
-
onLayout={onLayout}
|
|
104
|
-
onStartShouldSetResponderCapture={onStartShouldSetResponderCapture}
|
|
105
|
-
>
|
|
106
|
-
{children}
|
|
107
|
-
</View>
|
|
108
|
-
);
|
|
109
|
-
});
|
|
21
|
+
const Connect: React.FC<ConnectProps> = ({ children, captureKeyboardEvents, captureDialogEvents = false }) => {
|
|
22
|
+
const navigation = (children as any).ref; // Type assertion for children with ref
|
|
23
|
+
const currentRoute = useRef<string | undefined>(undefined);
|
|
24
|
+
const initial = useRef<boolean>(false);
|
|
25
|
+
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
TLTRN.interceptKeyboardEvents(captureKeyboardEvents);
|
|
28
|
+
}, [captureKeyboardEvents]);
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
TLTRN.interceptDialogEvents(captureDialogEvents);
|
|
32
|
+
}, [captureDialogEvents]);
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (
|
|
36
|
+
!navigation ||
|
|
37
|
+
typeof navigation.current.addListener !== "function" ||
|
|
38
|
+
typeof navigation.current.getCurrentRoute !== "function"
|
|
39
|
+
) {
|
|
40
|
+
console.warn(
|
|
41
|
+
"Connect: The Connect component's first child must be a NavigationContainer with a ref."
|
|
42
|
+
);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Listen for the 'state' event to track navigation state changes
|
|
47
|
+
const unsubscribeState = navigation.current.addListener("state", () => {
|
|
48
|
+
currentRoute.current = extractName(navigation) || navigation.current.getCurrentRoute()?.name;
|
|
49
|
+
console.log("State change - ", currentRoute.current);
|
|
50
|
+
|
|
51
|
+
if (Platform.OS === "ios" && currentRoute && currentRoute.current) {
|
|
52
|
+
TLTRN.logScreenViewPageName(currentRoute.current);
|
|
53
|
+
} else if (Platform.OS === "android") {
|
|
54
|
+
TLTRN.logScreenViewPageName(currentRoute.current);
|
|
55
|
+
TLTRN.logScreenLayout(currentRoute.current);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Cleanup listeners when the component unmounts or dependencies change
|
|
60
|
+
return () => {
|
|
61
|
+
unsubscribeState();
|
|
62
|
+
};
|
|
63
|
+
}, [navigation]);
|
|
64
|
+
|
|
65
|
+
const onStartShouldSetResponderCapture = useCallback((event: any) => {
|
|
66
|
+
currentRoute.current = extractName(navigation) || navigation.current.getCurrentRoute()?.name;
|
|
67
|
+
if (currentRoute && currentRoute.current) {
|
|
68
|
+
TLTRN.logScreenViewPageName(currentRoute.current);
|
|
69
|
+
}
|
|
70
|
+
TLTRN.logClickEvent(event);
|
|
71
|
+
return false; // Must be false; true means this component becomes the touch responder and events don't bubble
|
|
72
|
+
}, []);
|
|
73
|
+
|
|
74
|
+
const onLayout = useCallback((event: LayoutChangeEvent) => {
|
|
75
|
+
if (initial.current) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
initial.current = true;
|
|
79
|
+
|
|
80
|
+
console.log("event - ", event.nativeEvent);
|
|
81
|
+
|
|
82
|
+
currentRoute.current = navigation.current.getCurrentRoute()?.name;
|
|
83
|
+
if (Platform.OS === "ios" && currentRoute && currentRoute.current) {
|
|
84
|
+
TLTRN.logScreenViewPageName(currentRoute.current);
|
|
85
|
+
} else if (Platform.OS === "android") {
|
|
86
|
+
TLTRN.logScreenLayout(currentRoute.current);
|
|
87
|
+
}
|
|
88
|
+
return true
|
|
89
|
+
}, [navigation]);
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<View
|
|
93
|
+
style={styles.connect_main}
|
|
94
|
+
onLayout={onLayout}
|
|
95
|
+
onStartShouldSetResponderCapture={onStartShouldSetResponderCapture}
|
|
96
|
+
>
|
|
97
|
+
{children}
|
|
98
|
+
</View>
|
|
99
|
+
);
|
|
100
|
+
};
|
|
110
101
|
|
|
111
102
|
function extractName(navigation: any): string {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
103
|
+
const routeParams = navigation.current.getCurrentRoute()?.params;
|
|
104
|
+
if (routeParams) {
|
|
105
|
+
const { name } = routeParams;
|
|
106
|
+
return name ? name : navigation.current?.getCurrentRoute()?.name || "";
|
|
107
|
+
}
|
|
108
|
+
return "";
|
|
118
109
|
}
|
|
119
110
|
|
|
120
111
|
export default Connect;
|
|
121
112
|
|
|
122
113
|
const styles = StyleSheet.create({
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
114
|
+
connect_main: {
|
|
115
|
+
flex: 1,
|
|
116
|
+
},
|
|
126
117
|
});
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# Dialog Event Tracking
|
|
2
|
+
|
|
3
|
+
This document describes the dialog event tracking functionality added to the Acoustic Connect React Native SDK.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The dialog tracking system provides automatic and manual tracking of dialog popup events and user interactions. It supports:
|
|
8
|
+
|
|
9
|
+
- **Automatic tracking** of React Native's `Alert.alert()` calls
|
|
10
|
+
- **Manual tracking** of custom dialog components
|
|
11
|
+
- **Button click tracking** for both automatic and custom dialogs
|
|
12
|
+
- **Event logging** to the Acoustic Connect backend
|
|
13
|
+
|
|
14
|
+
## Features
|
|
15
|
+
|
|
16
|
+
### 1. Automatic Alert.alert Interception
|
|
17
|
+
|
|
18
|
+
The system automatically intercepts and tracks all `Alert.alert()` calls without requiring any code changes:
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
// This will be automatically tracked
|
|
22
|
+
Alert.alert(
|
|
23
|
+
'Confirmation',
|
|
24
|
+
'Are you sure?',
|
|
25
|
+
[
|
|
26
|
+
{ text: 'Cancel', style: 'cancel' },
|
|
27
|
+
{ text: 'OK', onPress: () => console.log('OK pressed') }
|
|
28
|
+
]
|
|
29
|
+
);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 2. Manual Custom Dialog Tracking
|
|
33
|
+
|
|
34
|
+
For custom dialog components, you can manually track events:
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { useDialogTracking } from 'react-native-acoustic-connect-beta';
|
|
38
|
+
|
|
39
|
+
const MyComponent = () => {
|
|
40
|
+
const { generateDialogId, trackDialogShow, trackDialogDismiss } = useDialogTracking();
|
|
41
|
+
|
|
42
|
+
const showDialog = () => {
|
|
43
|
+
const dialogId = generateDialogId();
|
|
44
|
+
trackDialogShow(dialogId, 'My Custom Dialog', [
|
|
45
|
+
{ text: 'Cancel', style: 'cancel' },
|
|
46
|
+
{ text: 'OK' }
|
|
47
|
+
]);
|
|
48
|
+
// Show your custom dialog
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const hideDialog = () => {
|
|
52
|
+
const dialogId = generateDialogId(); // Store this in your component state
|
|
53
|
+
trackDialogDismiss(dialogId, 'user_dismiss');
|
|
54
|
+
// Hide your custom dialog
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### 3. Button Click Tracking
|
|
60
|
+
|
|
61
|
+
Track button clicks in custom dialogs:
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
const { createTrackedButton } = useDialogTracking();
|
|
65
|
+
|
|
66
|
+
const showDialogWithTrackedButtons = () => {
|
|
67
|
+
const dialogId = generateDialogId();
|
|
68
|
+
const originalButtons = [
|
|
69
|
+
{ text: 'No', style: 'cancel' },
|
|
70
|
+
{ text: 'Yes', onPress: () => console.log('Yes pressed') }
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
// Create tracked buttons
|
|
74
|
+
const trackedButtons = originalButtons.map((button, index) =>
|
|
75
|
+
createTrackedButton(dialogId, button, index)
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
trackDialogShow(dialogId, 'Confirmation', trackedButtons);
|
|
79
|
+
};
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 4. HOC-Based Automatic Tracking
|
|
83
|
+
|
|
84
|
+
For the easiest integration, use the HOC (Higher-Order Component) approach:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import { withAcousticAutoDialog } from 'react-native-acoustic-connect-beta';
|
|
88
|
+
import { Dialog } from 'react-native-paper';
|
|
89
|
+
|
|
90
|
+
// Create tracked version of your dialog component
|
|
91
|
+
const TrackedDialog = withAcousticAutoDialog(Dialog);
|
|
92
|
+
|
|
93
|
+
// Use normally - all events automatically tracked!
|
|
94
|
+
<TrackedDialog
|
|
95
|
+
visible={dialogVisible}
|
|
96
|
+
onDismiss={hideDialog}
|
|
97
|
+
title="My Dialog"
|
|
98
|
+
>
|
|
99
|
+
<Dialog.Content>
|
|
100
|
+
<Text>Dialog content</Text>
|
|
101
|
+
</Dialog.Content>
|
|
102
|
+
<Dialog.Actions>
|
|
103
|
+
<Button onPress={hideDialog}>Cancel</Button>
|
|
104
|
+
<Button onPress={confirmAction}>Confirm</Button>
|
|
105
|
+
</Dialog.Actions>
|
|
106
|
+
</TrackedDialog>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The HOC automatically tracks:
|
|
110
|
+
- Dialog show events
|
|
111
|
+
- Dialog dismiss events
|
|
112
|
+
- Button click events within the dialog
|
|
113
|
+
- Recursively scans dialog children for buttons
|
|
114
|
+
|
|
115
|
+
## Setup
|
|
116
|
+
|
|
117
|
+
### 1. Enable Dialog Tracking in Connect Component
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
import { Connect } from 'react-native-acoustic-connect-beta';
|
|
121
|
+
|
|
122
|
+
<Connect
|
|
123
|
+
captureKeyboardEvents={true}
|
|
124
|
+
captureDialogEvents={true} // Enable dialog tracking
|
|
125
|
+
>
|
|
126
|
+
<NavigationContainer ref={navigationRef}>
|
|
127
|
+
{/* Your app content */}
|
|
128
|
+
</NavigationContainer>
|
|
129
|
+
</Connect>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### 2. Use the useDialogTracking Hook
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
import { useDialogTracking } from 'react-native-acoustic-connect-beta';
|
|
136
|
+
|
|
137
|
+
const MyComponent = () => {
|
|
138
|
+
const dialogTracking = useDialogTracking();
|
|
139
|
+
|
|
140
|
+
// Use dialogTracking methods...
|
|
141
|
+
};
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## API Reference
|
|
145
|
+
|
|
146
|
+
### Connect Component Props
|
|
147
|
+
|
|
148
|
+
| Prop | Type | Default | Description |
|
|
149
|
+
|------|------|---------|-------------|
|
|
150
|
+
| `captureDialogEvents` | `boolean` | `false` | Enable automatic dialog event tracking |
|
|
151
|
+
|
|
152
|
+
### useDialogTracking Hook
|
|
153
|
+
|
|
154
|
+
Returns an object with the following methods:
|
|
155
|
+
|
|
156
|
+
#### `generateDialogId(): string`
|
|
157
|
+
Generates a unique dialog identifier.
|
|
158
|
+
|
|
159
|
+
#### `trackDialogShow(dialogId: string, title: string, buttons?: AlertButton[]): void`
|
|
160
|
+
Tracks a dialog show event.
|
|
161
|
+
|
|
162
|
+
#### `trackDialogDismiss(dialogId: string, reason: string): void`
|
|
163
|
+
Tracks a dialog dismiss event.
|
|
164
|
+
|
|
165
|
+
#### `trackDialogButtonClick(dialogId: string, buttonText: string, buttonIndex: number): void`
|
|
166
|
+
Tracks a dialog button click event.
|
|
167
|
+
|
|
168
|
+
#### `trackDialogCustomEvent(dialogId: string, eventName: string, values: Record<string, string \| number \| boolean>): void`
|
|
169
|
+
Tracks a custom dialog event.
|
|
170
|
+
|
|
171
|
+
#### `createTrackedButton(dialogId: string, button: AlertButton, buttonIndex: number): AlertButton`
|
|
172
|
+
Creates a button with automatic click tracking.
|
|
173
|
+
|
|
174
|
+
#### `cleanup(): void`
|
|
175
|
+
Cleans up dialog tracking state.
|
|
176
|
+
|
|
177
|
+
### DialogListener Class
|
|
178
|
+
|
|
179
|
+
For advanced usage, you can directly use the DialogListener class:
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
import { DialogListener } from 'react-native-acoustic-connect-beta';
|
|
183
|
+
|
|
184
|
+
const dialogListener = DialogListener.getInstance();
|
|
185
|
+
dialogListener.startIntercepting();
|
|
186
|
+
dialogListener.addEventListener((event) => {
|
|
187
|
+
console.log('Dialog event:', event);
|
|
188
|
+
});
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Event Types
|
|
192
|
+
|
|
193
|
+
### DialogEvent
|
|
194
|
+
```typescript
|
|
195
|
+
interface DialogEvent {
|
|
196
|
+
dialogId: string;
|
|
197
|
+
dialogTitle: string;
|
|
198
|
+
dialogType: 'alert' | 'custom' | 'modal';
|
|
199
|
+
timestamp: number;
|
|
200
|
+
buttons?: AlertButton[];
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### DialogButtonClickEvent
|
|
205
|
+
```typescript
|
|
206
|
+
interface DialogButtonClickEvent {
|
|
207
|
+
dialogId: string;
|
|
208
|
+
buttonText: string;
|
|
209
|
+
buttonIndex: number;
|
|
210
|
+
timestamp: number;
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Native Interface Methods
|
|
215
|
+
|
|
216
|
+
The following methods are added to the AcousticConnectRN interface:
|
|
217
|
+
|
|
218
|
+
- `logDialogShowEvent(dialogId: string, dialogTitle: string, dialogType: string): boolean`
|
|
219
|
+
- `logDialogDismissEvent(dialogId: string, dismissReason: string): boolean`
|
|
220
|
+
- `logDialogButtonClickEvent(dialogId: string, buttonText: string, buttonIndex: number): boolean`
|
|
221
|
+
- `logDialogCustomEvent(dialogId: string, eventName: string, values: Record<string, string \| number \| boolean>): boolean`
|
|
222
|
+
|
|
223
|
+
## Best Practices
|
|
224
|
+
|
|
225
|
+
1. **Store Dialog IDs**: When manually tracking custom dialogs, store the dialog ID in your component state to properly track dismiss events.
|
|
226
|
+
|
|
227
|
+
2. **Use Consistent Naming**: Use descriptive dialog titles and button text for better analytics.
|
|
228
|
+
|
|
229
|
+
3. **Handle Errors**: Wrap dialog tracking calls in try-catch blocks to prevent app crashes.
|
|
230
|
+
|
|
231
|
+
4. **Clean Up**: Call the cleanup method when components unmount to prevent memory leaks.
|
|
232
|
+
|
|
233
|
+
## Example Implementation
|
|
234
|
+
|
|
235
|
+
See `src/examples/DialogTrackingExample.tsx` for a complete example showing all features.
|
|
236
|
+
|
|
237
|
+
## Troubleshooting
|
|
238
|
+
|
|
239
|
+
### Dialog events not being tracked
|
|
240
|
+
1. Ensure `captureDialogEvents={true}` is set on the Connect component
|
|
241
|
+
2. Check that the DialogListener is properly initialized
|
|
242
|
+
3. Verify that the native AcousticConnectRN interface is available
|
|
243
|
+
|
|
244
|
+
### Custom dialog tracking not working
|
|
245
|
+
1. Make sure you're calling `trackDialogShow` before showing the dialog
|
|
246
|
+
2. Store the dialog ID and use it consistently for dismiss events
|
|
247
|
+
3. Use `createTrackedButton` for automatic button click tracking
|
|
248
|
+
|
|
249
|
+
### Performance considerations
|
|
250
|
+
- Dialog tracking is lightweight and shouldn't impact app performance
|
|
251
|
+
- The system uses efficient event delegation and cleanup
|
|
252
|
+
- Dialog IDs are generated using a simple algorithm to avoid external dependencies
|