@inngageregistry/inngage-react 3.3.1 → 4.0.0-alpha.2
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/package.json +1 -1
- package/src/Inngage.ts +126 -131
- package/src/api/api.ts +28 -0
- package/src/{services → api}/handler.ts +21 -9
- package/src/components/in_app.tsx +102 -0
- package/src/components/modal.tsx +221 -0
- package/src/components/styles.ts +91 -91
- package/src/firebase/notifications_listener.ts +117 -0
- package/src/index.ts +2 -2
- package/src/models/requests.ts +42 -0
- package/src/services/api_service.ts +30 -0
- package/src/utils.ts +0 -24
- package/src/components/Inapp.tsx +0 -321
- package/src/notificationsListener.ts +0 -178
- package/src/services/inngage.ts +0 -23
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inngageregistry/inngage-react",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0-alpha.2",
|
|
4
4
|
"description": "Inngage Plugin for React Native applications for marketing campaign optimization using Push Notification.",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.d.ts",
|
package/src/Inngage.ts
CHANGED
|
@@ -3,62 +3,62 @@ import DeviceInfo from "react-native-device-info";
|
|
|
3
3
|
import * as RNLocalize from "react-native-localize";
|
|
4
4
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import { subscriptionApi, eventsApi, addUserDataApi } from "./services/inngage";
|
|
6
|
+
import { formatDate } from "./utils";
|
|
7
|
+
import { InngageNotificationMessage } from "./firebase/notifications_listener";
|
|
9
8
|
import { InngageProperties } from './models/inngage_properties';
|
|
10
9
|
|
|
11
10
|
import RNPermissions, { NotificationOption, RESULTS } from 'react-native-permissions';
|
|
12
11
|
|
|
12
|
+
import ApiService from './services/api_service';
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
SUBSCRIBE_REQUEST,
|
|
16
|
+
EVENT_REQUEST,
|
|
17
|
+
USER_DATA_REQUEST,
|
|
18
|
+
} from './models/requests';
|
|
19
|
+
|
|
20
|
+
const API_LEVEL_33 = 33;
|
|
21
|
+
|
|
13
22
|
// --- Get Firebase Access ------/
|
|
14
|
-
const getFirebaseAccess = async ()
|
|
15
|
-
|
|
16
|
-
return await handleNotificationsPermission();
|
|
17
|
-
} catch (error) {
|
|
18
|
-
console.error('Erro no getFirebaseAccess: ', error);
|
|
19
|
-
throw error;
|
|
20
|
-
}
|
|
23
|
+
const getFirebaseAccess = async () => {
|
|
24
|
+
return await handleNotificationsPermission();
|
|
21
25
|
};
|
|
22
26
|
|
|
23
27
|
const handleNotificationsPermission = async () => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
console.error(error);
|
|
37
|
-
throw error;
|
|
28
|
+
const options: NotificationOption[] = ['alert', 'badge', 'sound'];
|
|
29
|
+
const apiLevel = await DeviceInfo.getApiLevel();
|
|
30
|
+
|
|
31
|
+
const permissionGranted =
|
|
32
|
+
apiLevel >= API_LEVEL_33
|
|
33
|
+
? (await RNPermissions.requestNotifications(options)).status === RESULTS.GRANTED
|
|
34
|
+
: (await firebase.messaging().requestPermission()) ===
|
|
35
|
+
firebase.messaging.AuthorizationStatus.AUTHORIZED ||
|
|
36
|
+
firebase.messaging.AuthorizationStatus.PROVISIONAL;
|
|
37
|
+
|
|
38
|
+
if (permissionGranted) {
|
|
39
|
+
return await getFirebaseToken();
|
|
38
40
|
}
|
|
41
|
+
|
|
42
|
+
throw new Error('Notification permission not granted');
|
|
39
43
|
};
|
|
40
44
|
|
|
41
|
-
const getFirebaseToken = async ()
|
|
42
|
-
|
|
43
|
-
let fcmToken = await AsyncStorage.getItem('fcmToken');
|
|
45
|
+
const getFirebaseToken = async () => {
|
|
46
|
+
let fcmToken = await AsyncStorage.getItem('fcmToken');
|
|
44
47
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
if (!fcmToken) {
|
|
49
|
+
if (!firebase.messaging().isDeviceRegisteredForRemoteMessages) {
|
|
50
|
+
await firebase.messaging().registerDeviceForRemoteMessages?.();
|
|
51
|
+
}
|
|
49
52
|
|
|
50
|
-
|
|
53
|
+
const newFcmToken = await firebase.messaging().getToken?.();
|
|
51
54
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
55
|
+
if (newFcmToken) {
|
|
56
|
+
await AsyncStorage.setItem('fcmToken', newFcmToken);
|
|
57
|
+
return newFcmToken;
|
|
56
58
|
}
|
|
57
|
-
return fcmToken || null;
|
|
58
|
-
} catch (error) {
|
|
59
|
-
console.error(error);
|
|
60
|
-
throw error;
|
|
61
59
|
}
|
|
60
|
+
|
|
61
|
+
return fcmToken || null;
|
|
62
62
|
};
|
|
63
63
|
|
|
64
64
|
interface SubscriptionProps {
|
|
@@ -83,126 +83,121 @@ interface SendEventProps {
|
|
|
83
83
|
eventValues?: any
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
86
|
+
class Inngage {
|
|
87
|
+
private static instance: Inngage;
|
|
88
|
+
private apiService: ApiService;
|
|
89
|
+
|
|
90
|
+
constructor() {
|
|
91
|
+
this.apiService = new ApiService();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
static getInstance(): Inngage {
|
|
95
|
+
if (!Inngage.instance) {
|
|
96
|
+
Inngage.instance = new Inngage();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return Inngage.instance;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
static async notificationListener(firebaseListenCallback?: any) {
|
|
89
103
|
try {
|
|
90
|
-
|
|
104
|
+
InngageNotificationMessage(firebaseListenCallback)
|
|
91
105
|
} catch (e) {
|
|
92
|
-
console.
|
|
93
|
-
return { subscribed: false };
|
|
106
|
+
console.log(e)
|
|
94
107
|
}
|
|
95
|
-
}
|
|
108
|
+
}
|
|
96
109
|
|
|
97
|
-
|
|
110
|
+
static async subscribe({
|
|
98
111
|
appToken,
|
|
99
|
-
dev,
|
|
100
112
|
friendlyIdentifier,
|
|
101
113
|
customFields,
|
|
102
|
-
customData,
|
|
103
114
|
phoneNumber,
|
|
104
115
|
email,
|
|
105
|
-
}: SubscriptionProps)
|
|
116
|
+
}: SubscriptionProps) {
|
|
117
|
+
const inngage = Inngage.getInstance();
|
|
118
|
+
|
|
106
119
|
InngageProperties.appToken = appToken;
|
|
107
120
|
InngageProperties.identifier = friendlyIdentifier!;
|
|
108
121
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
phone_Number: phoneNumber,
|
|
140
|
-
email: email,
|
|
141
|
-
}
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
const request = subscriptionRequestAdapter(rawRequest, customData, customFields)
|
|
145
|
-
const subscribe = await subscriptionApi(request, dev);
|
|
146
|
-
return subscribe;
|
|
147
|
-
} catch (e) {
|
|
148
|
-
console.error(e);
|
|
149
|
-
return { subscribed: false };
|
|
122
|
+
const respToken = await getFirebaseAccess();
|
|
123
|
+
|
|
124
|
+
const { countryCode: osLocale, languageCode: osLanguage } = RNLocalize.getLocales()[0] || {};
|
|
125
|
+
const deviceManufacturer = await DeviceInfo.getManufacturer();
|
|
126
|
+
const installTime = await DeviceInfo.getFirstInstallTime();
|
|
127
|
+
const lastUpdateTime = await DeviceInfo.getLastUpdateTime();
|
|
128
|
+
const uuid = await DeviceInfo.getUniqueId();
|
|
129
|
+
const appInstalledIn = formatDate(installTime);
|
|
130
|
+
const appUpdatedIn = formatDate(lastUpdateTime);
|
|
131
|
+
|
|
132
|
+
const subscription = {
|
|
133
|
+
registerSubscriberRequest: {
|
|
134
|
+
app_token: appToken,
|
|
135
|
+
identifier: friendlyIdentifier,
|
|
136
|
+
registration: respToken,
|
|
137
|
+
platform: DeviceInfo.getSystemName(),
|
|
138
|
+
sdk: DeviceInfo.getBuildNumber(),
|
|
139
|
+
deviceModel: DeviceInfo.getModel(),
|
|
140
|
+
deviceManufacturer,
|
|
141
|
+
osLocale,
|
|
142
|
+
osLanguage,
|
|
143
|
+
os_version: DeviceInfo.getReadableVersion(),
|
|
144
|
+
app_version: DeviceInfo.getBuildNumber(),
|
|
145
|
+
appInstalledIn,
|
|
146
|
+
appUpdatedIn,
|
|
147
|
+
uuid,
|
|
148
|
+
phone_Number: phoneNumber,
|
|
149
|
+
email: email,
|
|
150
|
+
customFields: customFields,
|
|
151
|
+
}
|
|
150
152
|
}
|
|
151
|
-
},
|
|
152
153
|
|
|
153
|
-
|
|
154
|
-
|
|
154
|
+
return inngage.apiService.subscribe(subscription);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
static async sendEvent({
|
|
155
158
|
eventName,
|
|
156
|
-
identifier,
|
|
157
|
-
registration,
|
|
158
159
|
conversionEvent,
|
|
159
160
|
conversionValue,
|
|
160
161
|
conversionNotId,
|
|
161
162
|
eventValues,
|
|
162
|
-
}: SendEventProps)
|
|
163
|
+
}: SendEventProps) {
|
|
164
|
+
const inngage = Inngage.getInstance();
|
|
165
|
+
|
|
166
|
+
const registration = await getFirebaseAccess();
|
|
163
167
|
|
|
164
|
-
const
|
|
168
|
+
const request = {
|
|
165
169
|
newEventRequest: {
|
|
166
|
-
|
|
167
|
-
identifier: identifier,
|
|
168
|
-
registration
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
170
|
+
appToken: InngageProperties.appToken,
|
|
171
|
+
identifier: InngageProperties.identifier,
|
|
172
|
+
registration,
|
|
173
|
+
eventName,
|
|
174
|
+
conversionEvent: !!conversionEvent,
|
|
175
|
+
conversionValue,
|
|
176
|
+
conversionNotId,
|
|
177
|
+
eventValues,
|
|
178
|
+
},
|
|
175
179
|
};
|
|
176
180
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
return { subscribed: false };
|
|
183
|
-
}
|
|
184
|
-
},
|
|
181
|
+
return inngage.apiService.sendEvent(request);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
static async addUserData(customFields: any): Promise<any> {
|
|
185
|
+
const inngage = Inngage.getInstance();
|
|
185
186
|
|
|
186
|
-
|
|
187
|
-
const rawRequest = {
|
|
187
|
+
const request = {
|
|
188
188
|
fieldsRequest: {
|
|
189
|
-
|
|
189
|
+
appToken: InngageProperties.appToken,
|
|
190
190
|
identifier: InngageProperties.identifier,
|
|
191
|
-
|
|
192
|
-
}
|
|
191
|
+
customField: customFields,
|
|
192
|
+
},
|
|
193
193
|
};
|
|
194
194
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
return await addUserDataApi(request);
|
|
198
|
-
} catch (e) {
|
|
199
|
-
console.error(e);
|
|
200
|
-
}
|
|
201
|
-
},
|
|
195
|
+
return inngage.apiService.addUserData(request);
|
|
196
|
+
}
|
|
202
197
|
|
|
203
|
-
setDebugMode(value: boolean) {
|
|
204
|
-
InngageProperties.debugMode = value
|
|
198
|
+
static setDebugMode(value: boolean) {
|
|
199
|
+
InngageProperties.debugMode = value;
|
|
205
200
|
}
|
|
206
201
|
}
|
|
207
202
|
|
|
208
|
-
export default Inngage;
|
|
203
|
+
export default Inngage;
|
package/src/api/api.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { fetchClient } from './handler'
|
|
2
|
+
|
|
3
|
+
const apiEndpoints = {
|
|
4
|
+
subscription: '/subscription/',
|
|
5
|
+
notification: '/notification/',
|
|
6
|
+
events: '/events/newEvent/',
|
|
7
|
+
addUserData: '/subscription/addCustomField',
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const makeApiCall = (method: string, request: any, endpoint: string) => {
|
|
11
|
+
return fetchClient(method, request, endpoint);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const subscriptionApi = (request: any) => {
|
|
15
|
+
return makeApiCall('POST', request, apiEndpoints.subscription);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const notificationApi = (request: any) => {
|
|
19
|
+
return makeApiCall('POST', request, apiEndpoints.notification);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const eventsApi = (request: any) => {
|
|
23
|
+
return makeApiCall('POST', request, apiEndpoints.events);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const addUserDataApi = (request: any) => {
|
|
27
|
+
return makeApiCall('POST', request, apiEndpoints.addUserData);
|
|
28
|
+
};
|
|
@@ -30,12 +30,24 @@ const requestConfigFactory = (method, request) => {
|
|
|
30
30
|
return objToSend
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
export const fetchClient = (
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
33
|
+
export const fetchClient = async (
|
|
34
|
+
method: string,
|
|
35
|
+
requestBody: any,
|
|
36
|
+
path: string,
|
|
37
|
+
isDev = false
|
|
38
|
+
): Promise<Response> => {
|
|
39
|
+
try {
|
|
40
|
+
const url: URL = new URL(`${baseUrlHook[isDev as any]}${path}`);
|
|
41
|
+
const request: RequestInit = requestConfigFactory(method, requestBody);
|
|
42
|
+
const response: Response = await fetch(url, request);
|
|
43
|
+
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
throw new Error(`Network response was not ok (${response.status})`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return response;
|
|
49
|
+
} catch (error: any) {
|
|
50
|
+
console.error('Fetch Error:', error.message);
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
Text,
|
|
5
|
+
TouchableOpacity,
|
|
6
|
+
ImageBackground,
|
|
7
|
+
} from "react-native";
|
|
8
|
+
|
|
9
|
+
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
10
|
+
|
|
11
|
+
import { buildStyles } from "./styles";
|
|
12
|
+
import { Modal } from "../components/modal";
|
|
13
|
+
|
|
14
|
+
interface InAppData {
|
|
15
|
+
inapp_message: boolean
|
|
16
|
+
title: string
|
|
17
|
+
body: string
|
|
18
|
+
title_font_color: string
|
|
19
|
+
body_font_color: string
|
|
20
|
+
background_color: string
|
|
21
|
+
btn_left_txt_color: string
|
|
22
|
+
btn_left_bg_color: string
|
|
23
|
+
btn_right_txt_color: string
|
|
24
|
+
btn_right_bg_color: string
|
|
25
|
+
background_image: string
|
|
26
|
+
btn_left_text: string
|
|
27
|
+
btn_left_action_type: string
|
|
28
|
+
btn_left_action_link: string
|
|
29
|
+
btn_right_text: string
|
|
30
|
+
btn_right_action_type: string
|
|
31
|
+
btn_right_action_link: string
|
|
32
|
+
rick_content: string
|
|
33
|
+
inpression: string
|
|
34
|
+
bg_img_action_type: string
|
|
35
|
+
bg_img_action_link: string
|
|
36
|
+
dot_color: string
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function InAppContainer(): JSX.Element {
|
|
40
|
+
const [data, setData] = React.useState<InAppData>();
|
|
41
|
+
const [visible, setVisible] = React.useState(false);
|
|
42
|
+
|
|
43
|
+
React.useEffect(() => {
|
|
44
|
+
const fetchAdditionalData = async () => {
|
|
45
|
+
try {
|
|
46
|
+
const data = await AsyncStorage.getItem('inapp');
|
|
47
|
+
if (data) {
|
|
48
|
+
const parsedData = JSON.parse(data);
|
|
49
|
+
|
|
50
|
+
setVisible(true);
|
|
51
|
+
setData(parsedData);
|
|
52
|
+
}
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.error('Error retrieving additionalData from AsyncStorage:', error);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
fetchAdditionalData();
|
|
59
|
+
}, []);
|
|
60
|
+
|
|
61
|
+
const styles = buildStyles(data);
|
|
62
|
+
|
|
63
|
+
const handleDismissInApp = async () => {
|
|
64
|
+
await AsyncStorage.removeItem('inapp');
|
|
65
|
+
setVisible(false);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (data != null)
|
|
69
|
+
console.log('data in app', data)
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<Modal
|
|
73
|
+
renderToHardwareTextureAndroid={true}
|
|
74
|
+
transparent={true}
|
|
75
|
+
visible={visible}>
|
|
76
|
+
<ImageBackground style={styles.content} source={{ uri: data?.background_image }}>
|
|
77
|
+
<TouchableOpacity style={styles.closeButton} onPress={handleDismissInApp}>
|
|
78
|
+
<Text>X</Text>
|
|
79
|
+
</TouchableOpacity>
|
|
80
|
+
<View style={styles.messageData}>
|
|
81
|
+
<Text style={styles.title}>{data?.title}</Text>
|
|
82
|
+
<Text style={styles.body}>{data?.body}</Text>
|
|
83
|
+
</View>
|
|
84
|
+
<View style={styles.footer}>
|
|
85
|
+
<TouchableOpacity
|
|
86
|
+
style={styles.buttonLeft}>
|
|
87
|
+
<Text style={styles.textButton}>{data?.btn_left_text}</Text>
|
|
88
|
+
</TouchableOpacity>
|
|
89
|
+
<TouchableOpacity
|
|
90
|
+
style={styles.buttonRight}>
|
|
91
|
+
<Text style={styles.textButton}>{data?.btn_right_text}</Text>
|
|
92
|
+
</TouchableOpacity>
|
|
93
|
+
</View>
|
|
94
|
+
</ImageBackground>
|
|
95
|
+
</Modal>
|
|
96
|
+
)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|