@inngageregistry/inngage-react 4.0.0-alpha.1 → 4.0.0-alpha.3
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 +9 -21
- package/src/components/in_app.tsx +140 -99
- package/src/components/modal.tsx +221 -0
- package/src/components/styles.ts +58 -85
- package/src/firebase/notifications_listener.ts +23 -14
- package/src/index.ts +2 -2
- package/src/utils.ts +0 -24
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inngageregistry/inngage-react",
|
|
3
|
-
"version": "4.0.0-alpha.
|
|
3
|
+
"version": "4.0.0-alpha.3",
|
|
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,7 +3,7 @@ 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 {
|
|
6
|
+
import { formatDate } from "./utils";
|
|
7
7
|
import { InngageNotificationMessage } from "./firebase/notifications_listener";
|
|
8
8
|
import { InngageProperties } from './models/inngage_properties';
|
|
9
9
|
|
|
@@ -11,12 +11,6 @@ import RNPermissions, { NotificationOption, RESULTS } from 'react-native-permiss
|
|
|
11
11
|
|
|
12
12
|
import ApiService from './services/api_service';
|
|
13
13
|
|
|
14
|
-
import {
|
|
15
|
-
SUBSCRIBE_REQUEST,
|
|
16
|
-
EVENT_REQUEST,
|
|
17
|
-
USER_DATA_REQUEST,
|
|
18
|
-
} from './models/requests';
|
|
19
|
-
|
|
20
14
|
const API_LEVEL_33 = 33;
|
|
21
15
|
|
|
22
16
|
// --- Get Firebase Access ------/
|
|
@@ -73,10 +67,7 @@ interface SubscriptionProps {
|
|
|
73
67
|
}
|
|
74
68
|
|
|
75
69
|
interface SendEventProps {
|
|
76
|
-
appToken: string,
|
|
77
70
|
eventName: string,
|
|
78
|
-
identifier?: string,
|
|
79
|
-
registration?: string,
|
|
80
71
|
conversionEvent?: boolean,
|
|
81
72
|
conversionValue?: number,
|
|
82
73
|
conversionNotId?: string,
|
|
@@ -130,7 +121,6 @@ class Inngage {
|
|
|
130
121
|
const appUpdatedIn = formatDate(lastUpdateTime);
|
|
131
122
|
|
|
132
123
|
const subscription = {
|
|
133
|
-
...SUBSCRIBE_REQUEST,
|
|
134
124
|
registerSubscriberRequest: {
|
|
135
125
|
app_token: appToken,
|
|
136
126
|
identifier: friendlyIdentifier,
|
|
@@ -157,28 +147,27 @@ class Inngage {
|
|
|
157
147
|
|
|
158
148
|
static async sendEvent({
|
|
159
149
|
eventName,
|
|
160
|
-
conversionEvent,
|
|
161
|
-
conversionValue,
|
|
162
|
-
conversionNotId,
|
|
150
|
+
conversionEvent = false,
|
|
151
|
+
conversionValue = 0,
|
|
152
|
+
conversionNotId = "",
|
|
163
153
|
eventValues,
|
|
164
154
|
}: SendEventProps) {
|
|
165
155
|
const inngage = Inngage.getInstance();
|
|
166
156
|
|
|
167
157
|
const registration = await getFirebaseAccess();
|
|
168
158
|
|
|
169
|
-
const request =
|
|
170
|
-
...EVENT_REQUEST,
|
|
159
|
+
const request = {
|
|
171
160
|
newEventRequest: {
|
|
172
161
|
appToken: InngageProperties.appToken,
|
|
173
162
|
identifier: InngageProperties.identifier,
|
|
174
163
|
registration,
|
|
175
164
|
eventName,
|
|
176
|
-
conversionEvent
|
|
165
|
+
conversionEvent,
|
|
177
166
|
conversionValue,
|
|
178
167
|
conversionNotId,
|
|
179
168
|
eventValues,
|
|
180
169
|
},
|
|
181
|
-
}
|
|
170
|
+
};
|
|
182
171
|
|
|
183
172
|
return inngage.apiService.sendEvent(request);
|
|
184
173
|
}
|
|
@@ -186,14 +175,13 @@ class Inngage {
|
|
|
186
175
|
static async addUserData(customFields: any): Promise<any> {
|
|
187
176
|
const inngage = Inngage.getInstance();
|
|
188
177
|
|
|
189
|
-
const request =
|
|
190
|
-
...USER_DATA_REQUEST,
|
|
178
|
+
const request = {
|
|
191
179
|
fieldsRequest: {
|
|
192
180
|
appToken: InngageProperties.appToken,
|
|
193
181
|
identifier: InngageProperties.identifier,
|
|
194
182
|
customField: customFields,
|
|
195
183
|
},
|
|
196
|
-
}
|
|
184
|
+
};
|
|
197
185
|
|
|
198
186
|
return inngage.apiService.addUserData(request);
|
|
199
187
|
}
|
|
@@ -1,117 +1,158 @@
|
|
|
1
|
-
import React from
|
|
1
|
+
import * as React from "react";
|
|
2
2
|
import {
|
|
3
|
-
Modal,
|
|
4
|
-
View,
|
|
5
3
|
StyleSheet,
|
|
4
|
+
Image,
|
|
5
|
+
View,
|
|
6
6
|
Text,
|
|
7
7
|
TouchableOpacity,
|
|
8
8
|
ImageBackground,
|
|
9
|
-
|
|
10
|
-
PlatformColor,
|
|
9
|
+
Dimensions,
|
|
11
10
|
} from "react-native";
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
13
|
+
import Carousel from 'react-native-snap-carousel';
|
|
14
|
+
|
|
15
|
+
import { buildStyles } from "./styles";
|
|
16
|
+
import { Modal } from "../components/modal";
|
|
17
|
+
import { InngageProperties } from "../models/inngage_properties";
|
|
18
|
+
|
|
19
|
+
interface InAppData {
|
|
20
|
+
inapp_message: boolean
|
|
21
|
+
title: string
|
|
22
|
+
body: string
|
|
23
|
+
title_font_color: string
|
|
24
|
+
body_font_color: string
|
|
25
|
+
background_color: string
|
|
26
|
+
btn_left_txt_color: string
|
|
27
|
+
btn_left_bg_color: string
|
|
28
|
+
btn_right_txt_color: string
|
|
29
|
+
btn_right_bg_color: string
|
|
30
|
+
background_image: string
|
|
31
|
+
btn_left_txt: string
|
|
32
|
+
btn_left_action_type: string
|
|
33
|
+
btn_left_action_link: string
|
|
34
|
+
btn_right_txt: string
|
|
35
|
+
btn_right_action_type: string
|
|
36
|
+
btn_right_action_link: string
|
|
37
|
+
rich_content: string
|
|
38
|
+
inpression: string
|
|
39
|
+
bg_img_action_type: string
|
|
40
|
+
bg_img_action_link: string
|
|
41
|
+
dot_color: string
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface InAppRichContent {
|
|
45
|
+
carousel: boolean
|
|
46
|
+
img1: string
|
|
47
|
+
img2: string
|
|
48
|
+
img3: string
|
|
49
|
+
img4: string
|
|
50
|
+
img5: string
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
interface InAppProps {
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function InApp(props: InAppProps): JSX.Element {
|
|
58
|
+
const { width: screenWidth } = Dimensions.get('window');
|
|
59
|
+
|
|
60
|
+
const sliderWidth = screenWidth;
|
|
61
|
+
const itemWidth = screenWidth * 0.9;
|
|
62
|
+
|
|
63
|
+
const [data, setData] = React.useState<InAppData>();
|
|
64
|
+
const [richContent, setRichContent] = React.useState<InAppRichContent>();
|
|
65
|
+
const [visible, setVisible] = React.useState(false);
|
|
66
|
+
|
|
67
|
+
React.useEffect(() => {
|
|
68
|
+
const fetchAdditionalData = async () => {
|
|
69
|
+
try {
|
|
70
|
+
console.log('in app message')
|
|
71
|
+
const data = await AsyncStorage.getItem('inapp');
|
|
72
|
+
if (data) {
|
|
73
|
+
const parsedData = JSON.parse(data);
|
|
74
|
+
const richContentData = parsedData.rich_content;
|
|
75
|
+
|
|
76
|
+
setVisible(true);
|
|
77
|
+
setData(parsedData);
|
|
78
|
+
setRichContent(richContentData);
|
|
79
|
+
}
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.error('Error retrieving additionalData from AsyncStorage:', error);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
fetchAdditionalData();
|
|
86
|
+
}, []);
|
|
87
|
+
|
|
88
|
+
const styles = buildStyles(data, screenWidth * 0.9);
|
|
89
|
+
|
|
90
|
+
const handleDismissInApp = async () => {
|
|
91
|
+
await AsyncStorage.removeItem('inapp');
|
|
92
|
+
setVisible(false);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const imageUrls: string[] = [
|
|
96
|
+
richContent?.img1 ?? '',
|
|
97
|
+
richContent?.img2 ?? '',
|
|
98
|
+
richContent?.img3 ?? '',
|
|
99
|
+
richContent?.img4 ?? '',
|
|
100
|
+
richContent?.img5 ?? ''
|
|
101
|
+
];
|
|
102
|
+
|
|
103
|
+
const stylesCarousel = StyleSheet.create({
|
|
104
|
+
itemContainer: {
|
|
105
|
+
justifyContent: 'center',
|
|
106
|
+
height: 250
|
|
107
|
+
},
|
|
108
|
+
itemImg: {
|
|
109
|
+
height: 250,
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
const _renderItem = ({ item, index }) => {
|
|
114
|
+
return (
|
|
115
|
+
<View style={stylesCarousel.itemContainer}>
|
|
116
|
+
<Image style={[props, stylesCarousel.itemImg]} source={{ uri: item }} />
|
|
117
|
+
</View>
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (InngageProperties.getDebugMode() && data != null) {
|
|
122
|
+
console.log('INNGAGE - Data In App:', data)
|
|
123
|
+
console.log('INNGAGE - Data Rich Content:', richContent)
|
|
124
|
+
}
|
|
125
|
+
|
|
15
126
|
return (
|
|
16
127
|
<Modal
|
|
17
128
|
renderToHardwareTextureAndroid={true}
|
|
18
129
|
transparent={true}
|
|
19
|
-
visible={
|
|
20
|
-
<ImageBackground style={styles.content} source={{ uri:
|
|
130
|
+
visible={visible}>
|
|
131
|
+
<ImageBackground style={styles.content} source={{ uri: data?.background_image }}>
|
|
132
|
+
{richContent?.carousel ? <Carousel
|
|
133
|
+
layout={"default"}
|
|
134
|
+
data={imageUrls}
|
|
135
|
+
sliderWidth={sliderWidth}
|
|
136
|
+
itemWidth={itemWidth}
|
|
137
|
+
renderItem={_renderItem} /> : null}
|
|
138
|
+
<TouchableOpacity style={styles.closeButton} onPress={handleDismissInApp}>
|
|
139
|
+
<Text>X</Text>
|
|
140
|
+
</TouchableOpacity>
|
|
21
141
|
<View style={styles.messageData}>
|
|
22
|
-
<Text style={styles.title}>data
|
|
23
|
-
<Text style={styles.body}>
|
|
142
|
+
<Text style={styles.title}>{data?.title}</Text>
|
|
143
|
+
<Text style={styles.body}>{data?.body}</Text>
|
|
24
144
|
</View>
|
|
25
145
|
<View style={styles.footer}>
|
|
26
|
-
<TouchableOpacity
|
|
27
|
-
style={styles.
|
|
28
|
-
<Text style={styles.textButton}>
|
|
29
|
-
</TouchableOpacity>
|
|
30
|
-
<TouchableOpacity
|
|
31
|
-
style={styles.
|
|
32
|
-
<Text style={styles.textButton}>
|
|
33
|
-
</TouchableOpacity>
|
|
146
|
+
{data?.btn_left_txt != null ? <TouchableOpacity
|
|
147
|
+
style={styles.buttonLeft}>
|
|
148
|
+
<Text style={styles.textButton}>{data?.btn_left_txt}</Text>
|
|
149
|
+
</TouchableOpacity> : null}
|
|
150
|
+
{data?.btn_right_txt != null ? <TouchableOpacity
|
|
151
|
+
style={styles.buttonRight}>
|
|
152
|
+
<Text style={styles.textButton}>{data?.btn_right_txt}</Text>
|
|
153
|
+
</TouchableOpacity> : null}
|
|
34
154
|
</View>
|
|
35
155
|
</ImageBackground>
|
|
36
156
|
</Modal>
|
|
37
157
|
)
|
|
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
|
-
})
|
|
158
|
+
}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import {
|
|
3
|
+
Animated, Easing,
|
|
4
|
+
Modal as ReactNativeModal,
|
|
5
|
+
ModalProps as ReactNativeModalProps,
|
|
6
|
+
Platform,
|
|
7
|
+
StyleProp,
|
|
8
|
+
StyleSheet,
|
|
9
|
+
TouchableWithoutFeedback,
|
|
10
|
+
ViewStyle
|
|
11
|
+
} from "react-native";
|
|
12
|
+
import { Component } from "react";
|
|
13
|
+
|
|
14
|
+
const MODAL_ANIM_DURATION = 300;
|
|
15
|
+
const MODAL_BACKDROP_OPACITY = 0.3;
|
|
16
|
+
|
|
17
|
+
const CONTENT_ANIMATION_IN = Platform.select({
|
|
18
|
+
ios: {
|
|
19
|
+
opacity: {
|
|
20
|
+
inputRange: [0, 1],
|
|
21
|
+
outputRange: [0, 1],
|
|
22
|
+
},
|
|
23
|
+
scale: {
|
|
24
|
+
inputRange: [0, 0.5, 1],
|
|
25
|
+
outputRange: [1.2, 1.1, 1],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
android: {
|
|
29
|
+
opacity: {
|
|
30
|
+
inputRange: [0, 0.5, 1],
|
|
31
|
+
outputRange: [0, 1, 1],
|
|
32
|
+
},
|
|
33
|
+
scale: {
|
|
34
|
+
inputRange: [0, 1],
|
|
35
|
+
outputRange: [0.3, 1],
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
default: {
|
|
39
|
+
opacity: {
|
|
40
|
+
inputRange: [0, 0.5, 1],
|
|
41
|
+
outputRange: [0, 1, 1],
|
|
42
|
+
},
|
|
43
|
+
scale: {
|
|
44
|
+
inputRange: [0, 1],
|
|
45
|
+
outputRange: [0.3, 1],
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const CONTENT_ANIMATION_OUT = Platform.select({
|
|
51
|
+
default: {
|
|
52
|
+
opacity: {
|
|
53
|
+
inputRange: [0, 1],
|
|
54
|
+
outputRange: [0, 1],
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
export interface ModalProps extends ReactNativeModalProps {
|
|
60
|
+
onBackdropPress?: () => void;
|
|
61
|
+
onHide?: () => void;
|
|
62
|
+
visible?: boolean;
|
|
63
|
+
contentStyle?: StyleProp<ViewStyle>;
|
|
64
|
+
useNativeDriver?: boolean;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
interface ModalState {
|
|
68
|
+
visible: boolean;
|
|
69
|
+
currentAnimation: "none" | "in" | "out";
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export class Modal extends Component<ModalProps, ModalState> {
|
|
73
|
+
static defaultProps: Partial<ModalProps> = {
|
|
74
|
+
onBackdropPress: () => null,
|
|
75
|
+
onHide: () => null,
|
|
76
|
+
visible: false,
|
|
77
|
+
useNativeDriver: false,
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
state: ModalState = {
|
|
81
|
+
visible: Boolean(this.props.visible),
|
|
82
|
+
currentAnimation: "none",
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
animVal = new Animated.Value(0);
|
|
86
|
+
_isMounted = false;
|
|
87
|
+
|
|
88
|
+
componentDidMount() {
|
|
89
|
+
this._isMounted = true;
|
|
90
|
+
if (this.state.visible) {
|
|
91
|
+
this.show();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
componentWillUnmount() {
|
|
96
|
+
this._isMounted = false;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
componentDidUpdate(prevProps: ModalProps) {
|
|
100
|
+
if (this.props.visible && !prevProps.visible) {
|
|
101
|
+
this.show();
|
|
102
|
+
} else if (!this.props.visible && prevProps.visible) {
|
|
103
|
+
this.hide();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
show = () => {
|
|
108
|
+
this.setState({ visible: true, currentAnimation: "in" }, () => {
|
|
109
|
+
Animated.timing(this.animVal, {
|
|
110
|
+
easing: Easing.inOut(Easing.quad),
|
|
111
|
+
useNativeDriver: Boolean(this.props.useNativeDriver),
|
|
112
|
+
duration: MODAL_ANIM_DURATION,
|
|
113
|
+
toValue: 1,
|
|
114
|
+
}).start(() => {
|
|
115
|
+
this.setState({ currentAnimation: "none" });
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
hide = () => {
|
|
121
|
+
this.setState({ currentAnimation: "out" }, () => {
|
|
122
|
+
Animated.timing(this.animVal, {
|
|
123
|
+
easing: Easing.inOut(Easing.quad),
|
|
124
|
+
useNativeDriver: Boolean(this.props.useNativeDriver),
|
|
125
|
+
duration: MODAL_ANIM_DURATION,
|
|
126
|
+
toValue: 0,
|
|
127
|
+
}).start(() => {
|
|
128
|
+
if (this._isMounted) {
|
|
129
|
+
this.setState({ currentAnimation: "none" });
|
|
130
|
+
this.setState({ visible: false }, this.props.onHide);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
render() {
|
|
137
|
+
const {
|
|
138
|
+
children,
|
|
139
|
+
onBackdropPress,
|
|
140
|
+
contentStyle,
|
|
141
|
+
...otherProps
|
|
142
|
+
} = this.props;
|
|
143
|
+
const { currentAnimation, visible } = this.state;
|
|
144
|
+
|
|
145
|
+
const backdropAnimatedStyle = {
|
|
146
|
+
opacity: this.animVal.interpolate({
|
|
147
|
+
inputRange: [0, 1],
|
|
148
|
+
outputRange: [0, MODAL_BACKDROP_OPACITY],
|
|
149
|
+
}),
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const contentAnimatedStyle =
|
|
153
|
+
currentAnimation === "in"
|
|
154
|
+
? {
|
|
155
|
+
opacity: this.animVal.interpolate({
|
|
156
|
+
inputRange: CONTENT_ANIMATION_IN.opacity.inputRange,
|
|
157
|
+
outputRange: CONTENT_ANIMATION_IN.opacity.outputRange,
|
|
158
|
+
extrapolate: "clamp",
|
|
159
|
+
}),
|
|
160
|
+
transform: [
|
|
161
|
+
{
|
|
162
|
+
scale: this.animVal.interpolate({
|
|
163
|
+
inputRange: CONTENT_ANIMATION_IN.scale.inputRange,
|
|
164
|
+
outputRange: CONTENT_ANIMATION_IN.scale.outputRange,
|
|
165
|
+
extrapolate: "clamp",
|
|
166
|
+
}),
|
|
167
|
+
},
|
|
168
|
+
],
|
|
169
|
+
}
|
|
170
|
+
: {
|
|
171
|
+
opacity: this.animVal.interpolate({
|
|
172
|
+
inputRange: CONTENT_ANIMATION_OUT.opacity.inputRange,
|
|
173
|
+
outputRange: CONTENT_ANIMATION_OUT.opacity.outputRange,
|
|
174
|
+
extrapolate: "clamp",
|
|
175
|
+
}),
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
return (
|
|
179
|
+
<ReactNativeModal
|
|
180
|
+
transparent
|
|
181
|
+
animationType="none"
|
|
182
|
+
{...otherProps}
|
|
183
|
+
visible={visible}
|
|
184
|
+
>
|
|
185
|
+
<TouchableWithoutFeedback onPress={onBackdropPress}>
|
|
186
|
+
<Animated.View style={[styles.backdrop, backdropAnimatedStyle]} />
|
|
187
|
+
</TouchableWithoutFeedback>
|
|
188
|
+
{visible && (
|
|
189
|
+
<Animated.View
|
|
190
|
+
style={[styles.content, contentAnimatedStyle, contentStyle]}
|
|
191
|
+
pointerEvents="box-none"
|
|
192
|
+
needsOffscreenAlphaCompositing={["in", "out"].includes(
|
|
193
|
+
currentAnimation
|
|
194
|
+
)}
|
|
195
|
+
>
|
|
196
|
+
{children}
|
|
197
|
+
</Animated.View>
|
|
198
|
+
)}
|
|
199
|
+
</ReactNativeModal>
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const styles = StyleSheet.create({
|
|
205
|
+
backdrop: {
|
|
206
|
+
position: "absolute",
|
|
207
|
+
top: 0,
|
|
208
|
+
bottom: 0,
|
|
209
|
+
left: 0,
|
|
210
|
+
right: 0,
|
|
211
|
+
backgroundColor: "black",
|
|
212
|
+
opacity: 0,
|
|
213
|
+
},
|
|
214
|
+
content: {
|
|
215
|
+
flex: 1,
|
|
216
|
+
alignItems: "center",
|
|
217
|
+
justifyContent: "center",
|
|
218
|
+
},
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
export default Modal;
|
package/src/components/styles.ts
CHANGED
|
@@ -1,97 +1,70 @@
|
|
|
1
|
-
import { StyleSheet } from "react-native";
|
|
1
|
+
import { PlatformColor, StyleSheet } from "react-native";
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
SLIDER_WIDTH: number;
|
|
6
|
-
}
|
|
7
|
-
export const styleInapp = ({ SLIDER_WIDTH }: styleInappProps) => StyleSheet.create({
|
|
8
|
-
carouselContainer: {
|
|
9
|
-
width: "100%",
|
|
10
|
-
marginTop: 10,
|
|
11
|
-
},
|
|
12
|
-
styleContainer: {
|
|
13
|
-
backgroundColor: 'white',
|
|
14
|
-
elevation: 10,
|
|
15
|
-
borderRadius: 10,
|
|
16
|
-
width: SLIDER_WIDTH * 0.8,
|
|
17
|
-
height: 480,
|
|
18
|
-
},
|
|
19
|
-
counter: {
|
|
20
|
-
alignSelf: 'center',
|
|
21
|
-
marginVertical: 10
|
|
22
|
-
},
|
|
4
|
+
export const buildStyles = (data: any, screen: any) => StyleSheet.create({
|
|
23
5
|
closeButton: {
|
|
24
6
|
position: 'absolute',
|
|
25
|
-
|
|
26
|
-
right:
|
|
27
|
-
|
|
28
|
-
width: 30,
|
|
29
|
-
height: 30,
|
|
30
|
-
borderRadius: 20,
|
|
31
|
-
backgroundColor: '#00000020',
|
|
32
|
-
justifyContent: 'center',
|
|
33
|
-
alignItems: 'center',
|
|
34
|
-
zIndex: 90,
|
|
35
|
-
},
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
interface styleItemProps {
|
|
39
|
-
msg: any,
|
|
40
|
-
checkBG: Function,
|
|
41
|
-
}
|
|
42
|
-
export const styleItem = ({ msg, checkBG }: styleItemProps) => StyleSheet.create({
|
|
43
|
-
btn_left: {
|
|
44
|
-
backgroundColor: msg.btn_left_bg_color || "#FFFFFF",
|
|
45
|
-
height: 40,
|
|
46
|
-
width: 100,
|
|
47
|
-
alignItems: 'center',
|
|
48
|
-
justifyContent: 'center',
|
|
49
|
-
marginRight: 20,
|
|
50
|
-
marginLeft: 10,
|
|
51
|
-
flex: 1
|
|
7
|
+
top: 10,
|
|
8
|
+
right: 10,
|
|
9
|
+
zIndex: 10,
|
|
52
10
|
},
|
|
53
|
-
|
|
54
|
-
backgroundColor:
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
11
|
+
content: {
|
|
12
|
+
backgroundColor: data?.background_color,
|
|
13
|
+
flexDirection: "column",
|
|
14
|
+
borderRadius: 3,
|
|
15
|
+
paddingBottom: 16,
|
|
16
|
+
paddingRight: 16,
|
|
17
|
+
paddingLeft: 16,
|
|
18
|
+
margin: 16,
|
|
19
|
+
overflow: "hidden",
|
|
20
|
+
elevation: 10,
|
|
21
|
+
width: screen,
|
|
22
|
+
alignItems: "center"
|
|
61
23
|
},
|
|
62
|
-
|
|
63
|
-
|
|
24
|
+
messageData: { marginTop: 12 },
|
|
25
|
+
footer: {
|
|
26
|
+
flexDirection: "row",
|
|
27
|
+
alignItems: "center",
|
|
28
|
+
justifyContent: "flex-end",
|
|
29
|
+
marginTop: 4,
|
|
64
30
|
},
|
|
65
|
-
|
|
66
|
-
color:
|
|
31
|
+
title: {
|
|
32
|
+
color: PlatformColor(
|
|
33
|
+
`@android:color/${"primary_text_light"}`
|
|
34
|
+
),
|
|
35
|
+
fontWeight: "500",
|
|
36
|
+
fontSize: 18,
|
|
67
37
|
},
|
|
68
38
|
body: {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
justifyContent: 'center',
|
|
75
|
-
},
|
|
76
|
-
bodyText: {
|
|
77
|
-
color: msg.body_font_color || "#000000",
|
|
78
|
-
textAlign: 'justify',
|
|
39
|
+
color: PlatformColor(
|
|
40
|
+
`@android:color/${"secondary_text_light"}`
|
|
41
|
+
),
|
|
42
|
+
fontSize: 16,
|
|
43
|
+
marginTop: 10,
|
|
79
44
|
marginBottom: 10,
|
|
80
|
-
fontSize: 15,
|
|
81
|
-
marginHorizontal: 10
|
|
82
45
|
},
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
46
|
+
buttonLeft: {
|
|
47
|
+
margin: 2,
|
|
48
|
+
flex: 1,
|
|
49
|
+
backgroundColor: data?.btn_left_bg_color,
|
|
50
|
+
justifyContent: "center",
|
|
51
|
+
alignItems: "center",
|
|
52
|
+
},
|
|
53
|
+
buttonRight: {
|
|
54
|
+
margin: 2,
|
|
55
|
+
flex: 1,
|
|
56
|
+
backgroundColor: data?.btn_right_bg_color,
|
|
57
|
+
justifyContent: "center",
|
|
58
|
+
alignItems: "center",
|
|
59
|
+
},
|
|
60
|
+
textButton: {
|
|
61
|
+
color: PlatformColor(
|
|
62
|
+
`@android:color/${"secondary_text_light"}`
|
|
63
|
+
),
|
|
64
|
+
textAlign: "center",
|
|
65
|
+
backgroundColor: "transparent",
|
|
66
|
+
padding: 8,
|
|
67
|
+
fontSize: 14,
|
|
68
|
+
textTransform: "uppercase",
|
|
88
69
|
},
|
|
89
|
-
|
|
90
|
-
backgroundColor: msg.dot_color || "#FFFFFF",
|
|
91
|
-
borderRadius: 100,
|
|
92
|
-
width: 8,
|
|
93
|
-
height: 8,
|
|
94
|
-
marginLeft: 5,
|
|
95
|
-
elevation: 5,
|
|
96
|
-
}
|
|
97
|
-
});
|
|
70
|
+
})
|
|
@@ -8,6 +8,15 @@ import PushNotification, { Importance } from 'react-native-push-notification'
|
|
|
8
8
|
import { InngageProperties } from '../models/inngage_properties';
|
|
9
9
|
import * as ApiService from '../services/api_service'
|
|
10
10
|
|
|
11
|
+
export const messagingHeadlessTask = () => {
|
|
12
|
+
return messaging().setBackgroundMessageHandler(async remoteMessage => {
|
|
13
|
+
if (InngageProperties.getDebugMode())
|
|
14
|
+
console.log('INNGAGE - Data in background and closed app: ', remoteMessage)
|
|
15
|
+
if (remoteMessage?.data?.additional_data != null)
|
|
16
|
+
await AsyncStorage.setItem('inapp', remoteMessage?.data?.additional_data);
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
11
20
|
export const InngageNotificationMessage = (firebaseListenCallback?: any) => {
|
|
12
21
|
useEffect(() => {
|
|
13
22
|
PushNotification.configure({
|
|
@@ -34,44 +43,44 @@ export const InngageNotificationMessage = (firebaseListenCallback?: any) => {
|
|
|
34
43
|
})
|
|
35
44
|
useEffect(() => {
|
|
36
45
|
const handleMessage = async (remoteMessage: any) => {
|
|
46
|
+
const notificationData = remoteMessage.data;
|
|
47
|
+
|
|
37
48
|
if (InngageProperties.getDebugMode())
|
|
38
49
|
console.log('Remote message received in foreground: ', remoteMessage);
|
|
39
50
|
|
|
40
51
|
if (firebaseListenCallback != null && remoteMessage != null)
|
|
41
|
-
firebaseListenCallback(
|
|
52
|
+
firebaseListenCallback(notificationData)
|
|
42
53
|
|
|
43
54
|
PushNotification.localNotification({
|
|
44
55
|
autoCancel: true,
|
|
45
56
|
bigPictureUrl: remoteMessage.notification?.android?.imageUrl,
|
|
46
57
|
largeIconUrl: remoteMessage.notification?.android?.imageUrl,
|
|
47
|
-
title:
|
|
48
|
-
message:
|
|
58
|
+
title: notificationData?.title,
|
|
59
|
+
message: notificationData?.body,
|
|
49
60
|
vibration: 300,
|
|
50
61
|
channelId: "channel_id",
|
|
51
62
|
});
|
|
63
|
+
|
|
64
|
+
if (notificationData.additional_data != null)
|
|
65
|
+
await AsyncStorage.setItem('inapp', notificationData.additional_data);
|
|
66
|
+
|
|
52
67
|
};
|
|
53
68
|
|
|
54
69
|
return messaging().onMessage(handleMessage);
|
|
55
70
|
}, []);
|
|
56
71
|
|
|
57
72
|
useEffect(() => {
|
|
58
|
-
|
|
59
|
-
if (InngageProperties.getDebugMode())
|
|
60
|
-
console.log('Remote message received in background: ', remoteMessage);
|
|
61
|
-
|
|
73
|
+
messaging().onNotificationOpenedApp(remoteMessage => {
|
|
62
74
|
if (remoteMessage != null)
|
|
63
75
|
firebaseListenCallback(remoteMessage.data)
|
|
64
76
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
})
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
return messaging().setBackgroundMessageHandler(backgroundHandler);
|
|
77
|
+
handleNotification(remoteMessage)
|
|
78
|
+
})
|
|
71
79
|
}, []);
|
|
72
80
|
|
|
73
81
|
useEffect(() => {
|
|
74
82
|
messaging().getInitialNotification().then(async (value) => {
|
|
83
|
+
|
|
75
84
|
if (value !== null)
|
|
76
85
|
handleUniqueRemoteMessage(value);
|
|
77
86
|
});
|
|
@@ -88,7 +97,7 @@ export const InngageNotificationMessage = (firebaseListenCallback?: any) => {
|
|
|
88
97
|
handleNotification(remoteMessage)
|
|
89
98
|
}
|
|
90
99
|
} catch (e) {
|
|
91
|
-
console.
|
|
100
|
+
console.error(e);
|
|
92
101
|
}
|
|
93
102
|
};
|
|
94
103
|
|
package/src/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { InApp } from './components/in_app';
|
|
2
2
|
import Inngage from './Inngage';
|
|
3
3
|
|
|
4
4
|
//-------------- In-APP Component -------------//
|
|
5
|
-
export {
|
|
5
|
+
export { InApp };
|
|
6
6
|
|
|
7
7
|
//-------------- Inngage Wrapper --------------//
|
|
8
8
|
export default Inngage;
|
package/src/utils.ts
CHANGED
|
@@ -24,30 +24,6 @@ export const showAlertLink = (title: string, body: string, appName: string, link
|
|
|
24
24
|
})
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export const subscriptionRequestAdapter = (sdkRequest, useCustomData, customData) => {
|
|
28
|
-
if (useCustomData) {
|
|
29
|
-
return {
|
|
30
|
-
registerSubscriberRequest: {
|
|
31
|
-
...sdkRequest.registerSubscriberRequest,
|
|
32
|
-
custom_field: customData
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return {
|
|
37
|
-
registerSubscriberRequest: {
|
|
38
|
-
...sdkRequest.registerSubscriberRequest
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export const eventRequest = (request) => {
|
|
44
|
-
return { ...request }
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export const addUserDataRequest = (request) => {
|
|
48
|
-
return { ...request }
|
|
49
|
-
}
|
|
50
|
-
|
|
51
27
|
export const isEmpty = (obj: any) => {
|
|
52
28
|
for (var prop in obj) {
|
|
53
29
|
if (obj.hasOwnProperty(prop)) {
|