@inngageregistry/inngage-react 3.3.1 → 4.0.0-alpha.1

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inngageregistry/inngage-react",
3
- "version": "3.3.1",
3
+ "version": "4.0.0-alpha.01",
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 { addUserDataRequest, eventRequest, formatDate, subscriptionRequestAdapter } from "./utils";
7
- import notificationsListener, { notificationsListenerProps } from "./notificationsListener";
8
- import { subscriptionApi, eventsApi, addUserDataApi } from "./services/inngage";
6
+ import { addUserDataRequest, eventRequest, 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 (): Promise<string | null> => {
15
- try {
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
- try {
25
- const options: NotificationOption[] = ['alert', 'badge', 'sound'];
26
- const apiLevel = await DeviceInfo.getApiLevel();
27
- const isPermissionGranted =
28
- apiLevel >= 33
29
- ? ((await RNPermissions.requestNotifications(options)).status) === RESULTS.GRANTED
30
- : (await firebase.messaging().requestPermission()) ===
31
- firebase.messaging.AuthorizationStatus.AUTHORIZED ||
32
- firebase.messaging.AuthorizationStatus.PROVISIONAL;
33
-
34
- return isPermissionGranted ? await getFirebaseToken() : null;
35
- } catch (error) {
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 (): Promise<string | null> => {
42
- try {
43
- let fcmToken = await AsyncStorage.getItem('fcmToken');
45
+ const getFirebaseToken = async () => {
46
+ let fcmToken = await AsyncStorage.getItem('fcmToken');
44
47
 
45
- if (!fcmToken) {
46
- if (!firebase.messaging().isDeviceRegisteredForRemoteMessages) {
47
- await firebase.messaging().registerDeviceForRemoteMessages?.();
48
- }
48
+ if (!fcmToken) {
49
+ if (!firebase.messaging().isDeviceRegisteredForRemoteMessages) {
50
+ await firebase.messaging().registerDeviceForRemoteMessages?.();
51
+ }
49
52
 
50
- const newFcmToken = await firebase.messaging().getToken?.();
53
+ const newFcmToken = await firebase.messaging().getToken?.();
51
54
 
52
- if (newFcmToken) {
53
- await AsyncStorage.setItem('fcmToken', newFcmToken);
54
- return newFcmToken;
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,124 @@ interface SendEventProps {
83
83
  eventValues?: any
84
84
  }
85
85
 
86
- const Inngage = {
87
- // ------------ Register Notification Listener ------------//
88
- RegisterNotificationListener: async (props: notificationsListenerProps) => {
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
- await notificationsListener({ ...props });
104
+ InngageNotificationMessage(firebaseListenCallback)
91
105
  } catch (e) {
92
- console.error(e);
93
- return { subscribed: false };
106
+ console.log(e)
94
107
  }
95
- },
108
+ }
96
109
 
97
- Subscribe: async ({
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
- try {
110
- const respToken = await getFirebaseAccess()
111
-
112
- const locales = RNLocalize.getLocales();
113
-
114
- const os_locale = locales ? locales[0].countryCode : ''
115
- const os_language = locales && locales.length ? locales[0].languageCode : ''
116
- const device_manufacturer = await DeviceInfo.getManufacturer();
117
- const installTime = await DeviceInfo.getFirstInstallTime();
118
- const lastUpdateTime = await DeviceInfo.getLastUpdateTime();
119
- const uuid = await DeviceInfo.getUniqueId();
120
- const app_installed_in = formatDate(installTime);
121
- const app_updated_in = formatDate(lastUpdateTime);
122
-
123
- const rawRequest = {
124
- registerSubscriberRequest: {
125
- app_token: appToken,
126
- identifier: friendlyIdentifier,
127
- registration: respToken,
128
- platform: DeviceInfo.getSystemName(),
129
- sdk: DeviceInfo.getBuildNumber(),
130
- device_model: DeviceInfo.getModel(),
131
- device_manufacturer,
132
- os_locale,
133
- os_language,
134
- os_version: DeviceInfo.getReadableVersion(),
135
- app_version: DeviceInfo.getBuildNumber(),
136
- app_installed_in,
137
- app_updated_in,
138
- uuid,
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
+ ...SUBSCRIBE_REQUEST,
134
+ registerSubscriberRequest: {
135
+ app_token: appToken,
136
+ identifier: friendlyIdentifier,
137
+ registration: respToken,
138
+ platform: DeviceInfo.getSystemName(),
139
+ sdk: DeviceInfo.getBuildNumber(),
140
+ deviceModel: DeviceInfo.getModel(),
141
+ deviceManufacturer,
142
+ osLocale,
143
+ osLanguage,
144
+ os_version: DeviceInfo.getReadableVersion(),
145
+ app_version: DeviceInfo.getBuildNumber(),
146
+ appInstalledIn,
147
+ appUpdatedIn,
148
+ uuid,
149
+ phone_Number: phoneNumber,
150
+ email: email,
151
+ customFields: customFields,
152
+ }
150
153
  }
151
- },
152
154
 
153
- SendEvent: async ({
154
- appToken,
155
+ return inngage.apiService.subscribe(subscription);
156
+ }
157
+
158
+ static async sendEvent({
155
159
  eventName,
156
- identifier,
157
- registration,
158
160
  conversionEvent,
159
161
  conversionValue,
160
162
  conversionNotId,
161
163
  eventValues,
162
- }: SendEventProps) => {
164
+ }: SendEventProps) {
165
+ const inngage = Inngage.getInstance();
166
+
167
+ const registration = await getFirebaseAccess();
163
168
 
164
- const rawRequest = {
169
+ const request = eventRequest({
170
+ ...EVENT_REQUEST,
165
171
  newEventRequest: {
166
- app_token: appToken,
167
- identifier: identifier,
168
- registration: registration,
169
- event_name: eventName,
170
- conversion_event: conversionEvent ?? false,
171
- conversion_value: conversionValue ?? 0,
172
- conversion_notid: conversionNotId ?? '',
173
- event_values: eventValues ?? {}
174
- }
175
- };
172
+ appToken: InngageProperties.appToken,
173
+ identifier: InngageProperties.identifier,
174
+ registration,
175
+ eventName,
176
+ conversionEvent: !!conversionEvent,
177
+ conversionValue,
178
+ conversionNotId,
179
+ eventValues,
180
+ },
181
+ });
182
+
183
+ return inngage.apiService.sendEvent(request);
184
+ }
176
185
 
177
- const request = eventRequest(rawRequest)
178
- try {
179
- return await eventsApi(request);
180
- } catch (e) {
181
- console.error(e)
182
- return { subscribed: false };
183
- }
184
- },
186
+ static async addUserData(customFields: any): Promise<any> {
187
+ const inngage = Inngage.getInstance();
185
188
 
186
- async addUserData(customFields: any): Promise<any> {
187
- const rawRequest = {
189
+ const request = addUserDataRequest({
190
+ ...USER_DATA_REQUEST,
188
191
  fieldsRequest: {
189
- app_token: InngageProperties.appToken,
192
+ appToken: InngageProperties.appToken,
190
193
  identifier: InngageProperties.identifier,
191
- custom_field: customFields ?? {}
192
- }
193
- };
194
+ customField: customFields,
195
+ },
196
+ });
194
197
 
195
- const request = addUserDataRequest(rawRequest);
196
- try {
197
- return await addUserDataApi(request);
198
- } catch (e) {
199
- console.error(e);
200
- }
201
- },
198
+ return inngage.apiService.addUserData(request);
199
+ }
202
200
 
203
- setDebugMode(value: boolean) {
204
- InngageProperties.debugMode = value
201
+ static setDebugMode(value: boolean) {
202
+ InngageProperties.debugMode = value;
205
203
  }
206
204
  }
207
205
 
208
- export default Inngage;
206
+ 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 = (method, requestBody, path, isDev = false): Promise<Response> => {
34
- return new Promise((resolve) => {
35
- const url = String(baseUrlHook[isDev as any]).concat(path)
36
- const request = requestConfigFactory(method, requestBody)
37
- fetch(url, request)
38
- .then(resolve)
39
- .catch(err => console.error('Fetch Error', err))
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,117 @@
1
+ import React from 'react';
2
+ import {
3
+ Modal,
4
+ View,
5
+ StyleSheet,
6
+ Text,
7
+ TouchableOpacity,
8
+ ImageBackground,
9
+ Platform,
10
+ PlatformColor,
11
+ } from "react-native";
12
+
13
+ export function InAppContainer(data: any): JSX.Element {
14
+ const styles = buildStyles(data)
15
+ return (
16
+ <Modal
17
+ renderToHardwareTextureAndroid={true}
18
+ transparent={true}
19
+ visible={true}>
20
+ <ImageBackground style={styles.content} source={{ uri: "" }}>
21
+ <View style={styles.messageData}>
22
+ <Text style={styles.title}>data.title</Text>
23
+ <Text style={styles.body}>Corpo</Text>
24
+ </View>
25
+ <View style={styles.footer}>
26
+ <TouchableOpacity
27
+ style={styles.button}>
28
+ <Text style={styles.textButton}>Teste</Text>
29
+ </TouchableOpacity>
30
+ <TouchableOpacity
31
+ style={styles.button}>
32
+ <Text style={styles.textButton}>Teste</Text>
33
+ </TouchableOpacity>
34
+ </View>
35
+ </ImageBackground>
36
+ </Modal>
37
+ )
38
+ }
39
+
40
+ const buildStyles = ({ data }) => StyleSheet.create({
41
+ content: Platform.select({
42
+ android: {
43
+ backgroundColor: PlatformColor("?attr/colorBackgroundFloating"),
44
+ flexDirection: "column",
45
+ borderRadius: 3,
46
+ padding: 16,
47
+ margin: 16,
48
+ overflow: "hidden",
49
+ elevation: 10,
50
+ minWidth: 300,
51
+ alignItems: "center"
52
+ },
53
+ default: {}
54
+ }),
55
+ messageData: Platform.select({
56
+ android: {
57
+ marginTop: 12
58
+ },
59
+ default: {}
60
+ }),
61
+ footer: {
62
+ flexDirection: "row",
63
+ ...Platform.select({
64
+ android: {
65
+ alignItems: "center",
66
+ justifyContent: "flex-end",
67
+ marginTop: 4,
68
+ },
69
+ default: {},
70
+ }),
71
+ },
72
+ title: Platform.select({
73
+ android: {
74
+ color: PlatformColor(
75
+ `@android:color/${"primary_text_light"}`
76
+ ),
77
+ fontWeight: "500",
78
+ fontSize: 18,
79
+ },
80
+
81
+ default: {},
82
+ }),
83
+ body: Platform.select({
84
+ android: {
85
+ color: PlatformColor(
86
+ `@android:color/${"secondary_text_light"}`
87
+ ),
88
+ fontSize: 16,
89
+ marginTop: 10,
90
+ marginBottom: 10,
91
+ },
92
+ default: {},
93
+ }),
94
+ button: Platform.select({
95
+ android: {
96
+ margin: 2,
97
+ flex: 1,
98
+ backgroundColor: "red",
99
+ justifyContent: "center",
100
+ alignItems: "center",
101
+ },
102
+ default: {},
103
+ }),
104
+ textButton: Platform.select({
105
+ android: {
106
+ color: PlatformColor(
107
+ `@android:color/${"secondary_text_light"}`
108
+ ),
109
+ textAlign: "center",
110
+ backgroundColor: "transparent",
111
+ padding: 8,
112
+ fontSize: 14,
113
+ textTransform: "uppercase",
114
+ },
115
+ default: {},
116
+ }),
117
+ })
@@ -0,0 +1,105 @@
1
+ import { useEffect } from 'react';
2
+
3
+ import AsyncStorage from '@react-native-async-storage/async-storage';
4
+
5
+ import messaging from '@react-native-firebase/messaging';
6
+ import PushNotification, { Importance } from 'react-native-push-notification'
7
+
8
+ import { InngageProperties } from '../models/inngage_properties';
9
+ import * as ApiService from '../services/api_service'
10
+
11
+ export const InngageNotificationMessage = (firebaseListenCallback?: any) => {
12
+ useEffect(() => {
13
+ PushNotification.configure({
14
+ onNotification: function (data: any) {
15
+ if (data.foreground) {
16
+ handleNotification(data)
17
+ }
18
+ },
19
+ popInitialNotification: true,
20
+ requestPermissions: true
21
+ })
22
+ PushNotification.createChannel({
23
+ channelId: 'channel_id',
24
+ channelName: 'default',
25
+ importance: Importance.HIGH,
26
+ playSound: true,
27
+ soundName: 'default',
28
+ vibrate: true
29
+ }, (created: any) => {
30
+ if (created) {
31
+ console.log('Channel created');
32
+ }
33
+ });
34
+ })
35
+ useEffect(() => {
36
+ const handleMessage = async (remoteMessage: any) => {
37
+ if (InngageProperties.getDebugMode())
38
+ console.log('Remote message received in foreground: ', remoteMessage);
39
+
40
+ if (firebaseListenCallback != null && remoteMessage != null)
41
+ firebaseListenCallback(remoteMessage.data)
42
+
43
+ PushNotification.localNotification({
44
+ autoCancel: true,
45
+ bigPictureUrl: remoteMessage.notification?.android?.imageUrl,
46
+ largeIconUrl: remoteMessage.notification?.android?.imageUrl,
47
+ title: remoteMessage.data?.title,
48
+ message: remoteMessage.data?.body,
49
+ vibration: 300,
50
+ channelId: "channel_id",
51
+ });
52
+ };
53
+
54
+ return messaging().onMessage(handleMessage);
55
+ }, []);
56
+
57
+ useEffect(() => {
58
+ const backgroundHandler = async (remoteMessage: any) => {
59
+ if (InngageProperties.getDebugMode())
60
+ console.log('Remote message received in background: ', remoteMessage);
61
+
62
+ if (remoteMessage != null)
63
+ firebaseListenCallback(remoteMessage.data)
64
+
65
+ messaging().onNotificationOpenedApp(remoteMessage => {
66
+ handleNotification(remoteMessage)
67
+ })
68
+ };
69
+
70
+ return messaging().setBackgroundMessageHandler(backgroundHandler);
71
+ }, []);
72
+
73
+ useEffect(() => {
74
+ messaging().getInitialNotification().then(async (value) => {
75
+ if (value !== null)
76
+ handleUniqueRemoteMessage(value);
77
+ });
78
+ }, [])
79
+
80
+ const handleUniqueRemoteMessage = async (
81
+ remoteMessage: { messageId?: string }) => {
82
+ try {
83
+ const lastRemoteMessageId = await AsyncStorage.getItem('LAST_REMOTE_MESSAGE_ID');
84
+ const newRemoteMessageId = remoteMessage?.messageId;
85
+
86
+ if (newRemoteMessageId && lastRemoteMessageId !== newRemoteMessageId) {
87
+ await AsyncStorage.setItem('LAST_REMOTE_MESSAGE_ID', newRemoteMessageId);
88
+ handleNotification(remoteMessage)
89
+ }
90
+ } catch (e) {
91
+ console.log(e);
92
+ }
93
+ };
94
+
95
+ async function handleNotification(remoteMessage) {
96
+ const notId = remoteMessage.data?.notId;
97
+ const request = {
98
+ notificationRequest: {
99
+ id: notId,
100
+ app_token: InngageProperties.appToken,
101
+ }
102
+ };
103
+ await ApiService.sendNotification(request);
104
+ }
105
+ }
package/src/index.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { Inapp } from './components/Inapp';
1
+ import { InAppContainer } from './components/in_app';
2
2
  import Inngage from './Inngage';
3
3
 
4
4
  //-------------- In-APP Component -------------//
5
- export { Inapp };
5
+ export { InAppContainer };
6
6
 
7
7
  //-------------- Inngage Wrapper --------------//
8
8
  export default Inngage;
@@ -0,0 +1,42 @@
1
+ export const SUBSCRIBE_REQUEST = {
2
+ registerSubscriberRequest: {
3
+ appToken: '',
4
+ identifier: '',
5
+ registration: '',
6
+ platform: '',
7
+ sdk: '',
8
+ deviceModel: '',
9
+ deviceManufacturer: '',
10
+ osLocale: '',
11
+ osLanguage: '',
12
+ osVersion: '',
13
+ appVersion: '',
14
+ appInstalledIn: '',
15
+ appUpdatedIn: '',
16
+ uuid: '',
17
+ phoneNumber: '',
18
+ email: '',
19
+ customFields: {},
20
+ },
21
+ };
22
+
23
+ export const EVENT_REQUEST = {
24
+ newEventRequest: {
25
+ appToken: '',
26
+ identifier: '',
27
+ registration: '',
28
+ eventName: '',
29
+ conversionEvent: false,
30
+ conversionValue: 0,
31
+ conversionNotId: '',
32
+ eventValues: {},
33
+ },
34
+ };
35
+
36
+ export const USER_DATA_REQUEST = {
37
+ fieldsRequest: {
38
+ appToken: '',
39
+ identifier: '',
40
+ customField: {},
41
+ },
42
+ };
@@ -0,0 +1,30 @@
1
+ import { InngageProperties } from '../models/inngage_properties';
2
+ import { subscriptionApi, notificationApi, eventsApi, addUserDataApi } from '../api/api';
3
+
4
+ class ApiService {
5
+ async subscribe(request: any) {
6
+ if (InngageProperties.getDebugMode())
7
+ console.log('INNGAGE PAYLOAD SUBSCRIPTION: ', request)
8
+ return subscriptionApi(request);
9
+ }
10
+
11
+ async sendEvent(request: any, dev = false) {
12
+ if (InngageProperties.getDebugMode())
13
+ console.log('INNGAGE PAYLOAD EVENT: ', request)
14
+ return eventsApi(request);
15
+ }
16
+
17
+ async addUserData(request: any, dev = false) {
18
+ if (InngageProperties.getDebugMode())
19
+ console.log('INNGAGE PAYLOAD ADDUSERDATA: ', request)
20
+ return addUserDataApi(request);
21
+ }
22
+ }
23
+
24
+ export async function sendNotification(request: any, dev = false) {
25
+ if (InngageProperties.getDebugMode())
26
+ console.log('INNGAGE PAYLOAD NOTIFICATION: ', request)
27
+ return notificationApi(request);
28
+ }
29
+
30
+ export default ApiService;
@@ -1,321 +0,0 @@
1
- import React, { useState, useEffect, useRef } from 'react';
2
- import {
3
- Modal,
4
- View,
5
- Text,
6
- TouchableHighlight,
7
- TouchableOpacity,
8
- Image,
9
- ScrollView,
10
- ImageBackground,
11
- Linking,
12
- Dimensions,
13
- } from "react-native";
14
- import DeviceInfo from "react-native-device-info";
15
- import AsyncStorage from '@react-native-async-storage/async-storage';
16
- import Carousel, { Pagination } from 'react-native-snap-carousel';
17
-
18
- import { showAlertLink, isEmpty } from "../utils";
19
- import { linkInApp } from "../notificationsListener";
20
- import { styleInapp, styleItem } from './styles';
21
-
22
- const SLIDER_WIDTH = Dimensions.get('window').width;
23
- const SLIDER_HEIGHT = Dimensions.get('window').height;
24
- const ITEM_WIDTH = Math.round(SLIDER_WIDTH * 0.8);
25
- const ITEM_HEIGHT = Math.round(SLIDER_HEIGHT * 0.8);
26
-
27
- export interface InappProps {
28
- mediaStyle?: any;
29
- titleStyle?: any;
30
- bodyStyle?: any;
31
- buttonLeftStyle?: any;
32
- buttonRightStyle?: any;
33
- buttonTitleLeftStyle?: any;
34
- buttonTitleRightStyle?: any;
35
- styleContainer?: any;
36
- onClose?: 'clear';
37
- }
38
- export const Inapp = (props: InappProps) => {
39
- const [data, setData] = useState<any>([])
40
- const [indIm, setIndImg] = useState(0)
41
- const [visible, setVisible] = useState(true)
42
- const [bgImage, setbgImage] = useState<any>(undefined) // TODO, need a placeholder
43
-
44
- const CarouselRef = useRef<Carousel<any>>(null);
45
- const ScrollRef1 = useRef<ScrollView>(null);
46
- const ScrollRef2 = useRef<ScrollView>(null);
47
- const ScrollRef3 = useRef<ScrollView>(null);
48
-
49
-
50
- interface _renderItemProps {
51
- item: any;
52
- index: number;
53
- }
54
- const _renderItem = ({ item, index }: _renderItemProps) => {
55
- let msg = JSON.parse(item.data.additional_data)
56
- let arrayImgs: any = []
57
- let indImg = 0
58
-
59
- const checkBG = () => {
60
- if (msg.background_img != '') {
61
- return null
62
- } else {
63
- return msg.background_color
64
- }
65
- }
66
-
67
- const itemStyles = styleItem({ msg, checkBG })
68
-
69
- const chooseRef = () => {
70
- if (index == 0) {
71
- return ScrollRef1
72
- }
73
- if (index == 1) {
74
- return ScrollRef2
75
- }
76
- if (index == 2) {
77
- return ScrollRef3
78
- }
79
- }
80
-
81
-
82
- const pagination = ref => {
83
- return (
84
- <Pagination
85
- dotsLength={arrayImgs.length}
86
- activeDotIndex={indIm}
87
- containerStyle={{ height: 2, padding: 0, margin: 0 }}
88
- renderDots={(activeIndex, total, context) => {
89
- let dots: any = []
90
- var size = 0
91
- for (let i = 0; i < total; i++) {
92
- if (activeIndex == i) {
93
- size = 13
94
- } else {
95
- size = 8
96
- }
97
- dots.push(
98
- <TouchableOpacity
99
- onPress={() => {
100
- ref.current.scrollTo({ x: i * 220, y: 0, animated: true })
101
- if (i * 220 === 0) {
102
- setIndImg(0)
103
- } else if (i * 220 === 220) {
104
- setIndImg(1)
105
- } else if (i * 220 === 440) {
106
- setIndImg(2)
107
- }
108
- }}
109
- key={i.toString()}
110
- style={[itemStyles.dot, { width: size, height: size }]}
111
- />
112
- )
113
- }
114
- return (
115
- dots
116
- )
117
- }
118
- }
119
- />
120
- );
121
- }
122
-
123
- const handleButton = (title: string, body: string, url: string, type: string) => {
124
- if (type === '' || url === '') {
125
- return
126
- }
127
- const openLinkByType = (type, url) => (type === 'deep' ? Linking.openURL(url) : linkInApp(url))
128
-
129
- return Linking.canOpenURL(url).then((supported) => {
130
- if (supported) {
131
- showAlertLink(
132
- title,
133
- body,
134
- `${DeviceInfo.getApplicationName()}`,
135
- `Acessar ${url} ?`,
136
- ).then(() => { supported && openLinkByType(type, url) })
137
- }
138
- }).catch(console.error)
139
- }
140
-
141
- const imgCarosel = () => {
142
- if (msg.rich_content.carousel == true) {
143
- if (msg.rich_content.img1 != '') {
144
- arrayImgs.push({ url: msg.rich_content.img1 })
145
- }
146
- if (msg.rich_content.img2 != '') {
147
- arrayImgs.push({ url: msg.rich_content.img2 })
148
- }
149
- if (msg.rich_content.img3 != '') {
150
- arrayImgs.push({ url: msg.rich_content.img3 })
151
- }
152
- let arrayElements = arrayImgs.map((item, index) => (
153
- <Image key={index.toString()} style={[props.mediaStyle, { width: 200, height: 200, marginRight: 10 }]} source={{ uri: item.url }} />
154
- ));
155
- return arrayElements
156
- } else if (arrayImgs.length <= 0) {
157
- return (
158
- <Image style={[props.mediaStyle, { width: 200, height: 200 }]} source={{ uri: item.data.picture }} />
159
- )
160
- }
161
- else {
162
- return (
163
- <Image style={[props.mediaStyle, { width: 200, height: 200 }]} source={{ uri: item.data.picture }} />
164
- )
165
- }
166
- }
167
- return (
168
- <View style={[itemStyles.body]}>
169
- <Text style={[itemStyles.title, props.titleStyle]}>{msg.title}</Text>
170
- <ScrollView
171
- ref={chooseRef()}
172
- horizontal
173
- snapToInterval={220}
174
- decelerationRate="fast"
175
- showsHorizontalScrollIndicator={false}
176
- style={{ width: 200, height: 240 }}
177
- contentContainerStyle={{ alignItems: 'center', justifyContent: 'center' }}
178
- onMomentumScrollEnd={(e) => {
179
- if (Math.round(e.nativeEvent.contentOffset.x) === 0
180
- ) {
181
- indImg = 0
182
- setIndImg(indImg)
183
- }
184
- if (Math.round(e.nativeEvent.contentOffset.x) === 220
185
- ) {
186
- indImg = 1
187
- setIndImg(indImg)
188
- }
189
- if (Math.round(e.nativeEvent.contentOffset.x) === 430
190
- ) {
191
- indImg = 2
192
- setIndImg(indImg)
193
- }
194
- }}
195
- >
196
- {imgCarosel()}
197
- </ScrollView>
198
- {
199
- msg.rich_content.carousel == true ?
200
- pagination(chooseRef()) : null
201
-
202
- }
203
- <Text style={[itemStyles.bodyText, props.bodyStyle]}>{msg.body}</Text>
204
- <View style={{ flexDirection: "row", marginBottom: 0, justifyContent: 'center' }}>
205
- <TouchableOpacity onPress={() => handleButton(msg.title, msg.body, msg.btn_left_action_link, msg.btn_left_action_type)} style={[itemStyles.btn_left, props.buttonLeftStyle]}>
206
- <View>
207
- <Text style={[itemStyles.btn_left_title, props.buttonTitleLeftStyle]}>{msg.btn_left_txt}</Text>
208
- </View>
209
- </TouchableOpacity>
210
- <TouchableOpacity onPress={() => handleButton(msg.title, msg.body, msg.btn_right_action_link, msg.btn_right_action_type)} style={[itemStyles.btn_right, props.buttonRightStyle]}>
211
- <View>
212
- <Text style={[itemStyles.btn_right_title, props.buttonTitleRightStyle]}>{msg.btn_right_txt}</Text>
213
- </View>
214
- </TouchableOpacity>
215
- </View>
216
- </View>
217
- );
218
- }
219
-
220
- useEffect(() => {
221
- onLoad();
222
- }, [])
223
-
224
- const onLoad = async () => {
225
- let temp: any = []
226
- const messages = JSON.parse(await AsyncStorage.getItem('inngage') ?? '[]')
227
-
228
- if (messages !== null) {
229
- messages.forEach((el) => {
230
- if (!isEmpty(el)) {
231
- temp.push(el)
232
- }
233
- })
234
-
235
- let msg: any = {}
236
- if (temp.length > 0 && temp[0]?.data?.additional_data) {
237
- msg = JSON.parse(temp[0].data.additional_data)
238
- }
239
-
240
- if (msg.background_img != '') {
241
- setbgImage({ uri: msg.background_img })
242
- } else {
243
- setbgImage(undefined)
244
- }
245
- setData(temp)
246
- }
247
- }
248
-
249
- const handleClose = async () => {
250
- if (props.onClose) {
251
- if (props.onClose.toLowerCase() === 'clear') {
252
- await AsyncStorage.removeItem('inngage');
253
- }
254
- }
255
- setVisible(false)
256
- }
257
-
258
- const handleBg = index => {
259
- let msg = JSON.parse(data[index].data.additional_data)
260
- if (msg.background_img != '') {
261
- setbgImage({ uri: msg.background_img })
262
- } else {
263
- setbgImage(undefined)
264
- }
265
- }
266
-
267
- if (data.length > 0) {
268
- return (
269
- <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
270
- <Modal
271
- animationType='slide'
272
- visible={visible}
273
- transparent={true}
274
- style={{ justifyContent: 'center', alignItems: 'center', backgroundColor: 'blue' }}
275
- ><View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
276
- <View style={[styles.styleContainer, props.styleContainer]}>
277
- <ImageBackground style={{ width: '100%', alignItems: 'center', justifyContent: 'center' }} resizeMode='cover' imageStyle={{ borderRadius: 10, alignSelf: 'stretch', height: 480 }} source={bgImage}>
278
- <TouchableHighlight
279
- onPress={() => handleClose()}
280
- underlayColor='#cccccc'
281
- style={styles.closeButton}
282
- >
283
- <Text style={{ fontWeight: 'bold', color: '#ffffff' }}>
284
- X
285
- </Text>
286
- </TouchableHighlight>
287
- <Carousel
288
- vertical
289
- ref={CarouselRef}
290
- layout={'default'}
291
- layoutCardOffset={10}
292
- data={data}
293
- inactiveSlideOpacity={0}
294
- containerCustomStyle={{
295
- backgroundColor: 'white',
296
- elevation: 10,
297
- borderRadius: 10,
298
- width: SLIDER_WIDTH * 0.8,
299
- height: 480,
300
- }}
301
- contentContainerCustomStyle={{ justifyContent: 'center' }}
302
- inactiveSlideShift={0}
303
- onSnapToItem={(index) => {
304
- handleBg(index)
305
- }}
306
- renderItem={({ item, index }) => _renderItem({ item, index })}
307
- sliderHeight={500}
308
- itemHeight={500}
309
- />
310
- </ImageBackground>
311
- </View>
312
- </View>
313
- </Modal>
314
- </View>
315
- );
316
- } else {
317
- return null
318
- }
319
- };
320
-
321
- const styles = styleInapp({ SLIDER_WIDTH })
@@ -1,178 +0,0 @@
1
- import { Linking } from 'react-native'
2
- import InAppBrowser from 'react-native-inappbrowser-reborn'
3
- import messaging from '@react-native-firebase/messaging';
4
- import { showAlert } from './utils'
5
- import { notificationApi } from './services/inngage'
6
- import AsyncStorage from '@react-native-async-storage/async-storage';
7
- import PushNotification, { Importance } from 'react-native-push-notification'
8
-
9
- export const linkInApp = (link: string) => {
10
- InAppBrowser.open(link, {
11
- dismissButtonStyle: 'cancel',
12
- preferredBarTintColor: 'gray',
13
- preferredControlTintColor: 'white',
14
- readerMode: false,
15
- showTitle: true,
16
- toolbarColor: '#6200EE',
17
- secondaryToolbarColor: 'black',
18
- enableUrlBarHiding: true,
19
- enableDefaultShare: true,
20
- forceCloseOnRedirection: false,
21
- animations: {
22
- startEnter: 'slide_in_right',
23
- startExit: 'slide_out_left',
24
- endEnter: 'slide_in_right',
25
- endExit: 'slide_out_left',
26
- },
27
- })
28
- }
29
-
30
- const openLinkByType = (type: string, url: string) => {
31
- const linkTypeHandlers: Record<string, () => void> = {
32
- deep: () => Linking.openURL(url),
33
- // inapp: () => linkInApp(url),
34
- };
35
-
36
- const handler = linkTypeHandlers[type];
37
- if (handler) {
38
- handler();
39
- }
40
- };
41
-
42
- const openCommonNotification = ({ appToken, dev, remoteMessage, enableAlert, state }) => {
43
- if (!remoteMessage)
44
- return
45
-
46
- const { data } = remoteMessage
47
- if (!data || (data && !Object.keys(data).length))
48
- return
49
-
50
- const { notId, title, body, type, url } = data
51
- const request = {
52
- notificationRequest: {
53
- id: notId,
54
- app_token: appToken,
55
- }
56
- }
57
-
58
- if (url) {
59
- Linking.canOpenURL(url).then((supported) => {
60
- if (supported) {
61
- supported && openLinkByType(type, url)
62
- }
63
- }).catch(console.error)
64
- }
65
-
66
- return notificationApi(request, dev)
67
- }
68
-
69
- const handleUniqueRemoteMessage = async (
70
- remoteMessage: { messageId?: string },
71
- handleInitialNotification: (value: { messageId?: string }) => void
72
- ) => {
73
- try {
74
- const lastRemoteMessageId = await AsyncStorage.getItem('LAST_REMOTE_MESSAGE_ID');
75
- const newRemoteMessageId = remoteMessage?.messageId;
76
-
77
- if (newRemoteMessageId && lastRemoteMessageId !== newRemoteMessageId) {
78
- await AsyncStorage.setItem('LAST_REMOTE_MESSAGE_ID', newRemoteMessageId);
79
- handleInitialNotification(remoteMessage);
80
- }
81
- } catch (e) {
82
- console.error(e);
83
- }
84
- };
85
-
86
- export interface notificationsListenerProps {
87
- appToken: string,
88
- dev?: boolean,
89
- enableAlert: boolean,
90
- onNotificationOpenedApp?: any,
91
- }
92
- export default async ({ appToken, dev, enableAlert, onNotificationOpenedApp }: notificationsListenerProps) => {
93
- var messageArray: any = [];
94
-
95
- if (typeof onNotificationOpenedApp == 'function') {
96
- messaging().getInitialNotification().then(async (value) => {
97
- onNotificationOpenedApp(value?.data);
98
- if (value !== null)
99
- handleUniqueRemoteMessage(value, async (value) => {
100
- await handleInitialNotification(value);
101
- });
102
- });
103
- }
104
-
105
- const handleBackgroundMessage = async (remoteMessage: any) => {
106
- }
107
-
108
- const handleNotificationOpenedApp = async (remoteMessage: any) => {
109
- await openCommonNotification({ appToken, dev, remoteMessage, enableAlert, state: 'Background' })
110
- }
111
-
112
- const handleInitialNotification = async (remoteMessage: any) => {
113
- await openCommonNotification({ appToken, dev, remoteMessage, enableAlert, state: 'Closed' })
114
- }
115
-
116
- const handleForegroundMessage = async (remoteMessage: any) => {
117
- try {
118
- PushNotification.configure({
119
- onNotification: function (notification) {
120
- openCommonNotification({ appToken, dev, remoteMessage, enableAlert, state: 'Foreground' })
121
- },
122
- popInitialNotification: true,
123
- requestPermissions: true
124
- })
125
-
126
- PushNotification.createChannel({
127
- channelId: 'high_importance_channel',
128
- channelName: 'default',
129
- importance: Importance.HIGH,
130
- playSound: true,
131
- soundName: 'default',
132
- vibrate: true
133
- }, (created) => {
134
-
135
- });
136
-
137
- } catch (e) {
138
- console.error(e)
139
- }
140
- try {
141
- PushNotification.localNotification({
142
- autoCancel: true,
143
- title: remoteMessage.data!.title,
144
- message: remoteMessage.data!.body,
145
- vibration: 300,
146
- channelId: "high_importance_channel"
147
- });
148
- } catch (e) {
149
- console.error(e)
150
- }
151
-
152
- if (remoteMessage != null && remoteMessage.data!.additional_data) {
153
- let msg = JSON.parse(remoteMessage.data!.additional_data)
154
- if (msg.inapp_message == true) {
155
- const currentMessages = await AsyncStorage.getItem('inngage');
156
- if (currentMessages !== null) {
157
- messageArray = JSON.parse(currentMessages);
158
- }
159
- messageArray.push(remoteMessage);
160
- await AsyncStorage.setItem('inngage', JSON.stringify(messageArray));
161
- }
162
- } else if (remoteMessage != null && !remoteMessage.data!.additional_data) {
163
- if (enableAlert) {
164
- showAlert(remoteMessage.data!.title, remoteMessage.data!.body)
165
- }
166
- }
167
- }
168
-
169
- messaging().setBackgroundMessageHandler(handleBackgroundMessage)
170
- messaging().onNotificationOpenedApp(handleNotificationOpenedApp)
171
- messaging().getInitialNotification().then(async (remoteMessage) => {
172
- if (remoteMessage !== null)
173
- handleUniqueRemoteMessage(remoteMessage, async (value) => {
174
- await handleInitialNotification(value);
175
- });
176
- })
177
- messaging().onMessage(handleForegroundMessage)
178
- }
@@ -1,23 +0,0 @@
1
- import { InngageProperties } from '../models/inngage_properties'
2
- import { fetchClient } from './handler'
3
-
4
- export const subscriptionApi = (request, dev = false) => {
5
- if (InngageProperties.getDebugMode())
6
- console.log('subscriptionApi', request)
7
- return fetchClient('POST', request, '/subscription/', !!dev)
8
- }
9
- export const notificationApi = (request, dev = false) => {
10
- if (InngageProperties.getDebugMode())
11
- console.log('notificationApi', request)
12
- return fetchClient('POST', request, '/notification/', !!dev)
13
- }
14
- export const eventsApi = (request, dev = false) => {
15
- if (InngageProperties.getDebugMode())
16
- console.log('eventsApi', request)
17
- return fetchClient('POST', request, '/events/newEvent/', !!dev)
18
- }
19
- export const addUserDataApi = (request, dev = false) => {
20
- if (InngageProperties.getDebugMode())
21
- console.log('addUserData', request)
22
- return fetchClient('POST', request, '/subscription/addCustomField', !!dev)
23
- }