@momo-kits/foundation 0.102.6-beta.0 → 0.102.6-beta.10

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.
@@ -8,80 +8,6 @@ import {GridSystem} from '../Layout';
8
8
  import {Text} from '../Text';
9
9
  import {Colors, Radius, Spacing} from '../Consts';
10
10
 
11
- /**
12
- * Empty screen for unvalidated screen name
13
- * @constructor
14
- */
15
- const EmptyScreen: React.FC = () => {
16
- return (
17
- <View
18
- style={{
19
- backgroundColor: Colors.black_01,
20
- padding: Spacing.M,
21
- borderRadius: Radius.M,
22
- }}>
23
- <Text typography={'header_m_bold'}>Unvalidated screen name</Text>
24
- <Text
25
- typography={'description_default_regular'}
26
- style={{paddingVertical: Spacing.S}}>
27
- Your screen has not been rendered because Platform has not detected the
28
- screen name. Please migrate to support this feature.
29
- </Text>
30
- <Text typography={'header_default'} style={{width: '100%'}}>
31
- Possible fixes:
32
- </Text>
33
- <View style={{marginLeft: Spacing.S}}>
34
- <Text typography={'body_default_regular'}>1. Off webpack config</Text>
35
- <Text typography={'body_default_regular'}>
36
- 2. Screen name refactoring
37
- </Text>
38
- <View style={{marginLeft: Spacing.S}}>
39
- <Text
40
- typography={'description_default_regular'}
41
- style={{marginBottom: Spacing.S}}>
42
- - Với các screen push/import dạng arrow function ={'>'} đổi thành
43
- named function
44
- </Text>
45
- <Text
46
- typography={'description_default_regular'}
47
- style={{marginBottom: Spacing.S}}>
48
- - Với các screen import dạng High Order Component ={'>'} rename
49
- generic function thành named function
50
- </Text>
51
- <Text
52
- typography={'description_default_regular'}
53
- style={{marginBottom: Spacing.S}}>
54
- - Với Tab Navigator, Platform sẽ lấy Tab Container làm screen name.
55
- Trong trường hợp miniapp muốn track riêng action cho từng tab, tham
56
- khảo theo docs
57
- </Text>
58
- </View>
59
- </View>
60
- <Text typography={'header_s_semibold'}>More information: </Text>
61
- <Text
62
- typography={'body_default_regular'}
63
- color={Colors.blue_01}
64
- onPress={() => {
65
- Linking.openURL(
66
- 'https://gitlab.mservice.com.vn/momo-platform/mini-app/-/tree/vn.momo.uikits/dev/app'
67
- );
68
- }}>
69
- Mini App: vn.momo.uikits/dev
70
- </Text>
71
- <Text
72
- typography={'body_default_regular'}
73
- color={Colors.blue_01}
74
- onPress={() => {
75
- Linking.openURL(
76
- 'https://docs.google.com/presentation/d/1bIFoh8gRXb6hsnGJz4O1Kxg4_oNikB1KuuEt2wULCDM/edit?usp=sharing'
77
- );
78
- }}>
79
- https://docs.google.com/presentation/d/1bIFoh8gRXb6hsnGJz4O1Kxg4_oNikB1KuuEt2wULCDM/edit?usp=sharing
80
- </Text>
81
- </View>
82
- );
83
- };
84
-
85
11
  /**
86
12
  * container for stack screen
87
13
  * @param props
@@ -89,18 +15,19 @@ const EmptyScreen: React.FC = () => {
89
15
  */
90
16
  const StackScreen: React.FC<ScreenParams> = props => {
91
17
  const {showGrid, navigator} = useContext(ApplicationContext);
92
- const startTime = useRef(Date.now());
93
- const endTime = useRef(Date.now());
94
- const timeLoad = useRef(0);
95
- const timeInteraction = useRef(0);
96
- const timeoutLoad = useRef<any>();
97
- const tracked = useRef<any>({
18
+ const tracking = useRef<any>({
19
+ timeoutLoad: undefined,
20
+ interaction: undefined,
21
+ startTime: Date.now(),
22
+ endTime: Date.now(),
98
23
  traceIdLoad: undefined,
99
24
  traceIdInteraction: undefined,
100
25
  releaseLoad: undefined,
101
26
  releaseInteraction: undefined,
27
+ timeLoad: 0,
28
+ timeInteraction: 0,
102
29
  });
103
- const interaction = useRef<any>();
30
+
104
31
  const context = useContext<any>(MiniAppContext);
105
32
  const {screen: Component, options, initialParams} = props.route.params;
106
33
  const navigation = new Navigation(props.navigation);
@@ -116,6 +43,7 @@ const StackScreen: React.FC<ScreenParams> = props => {
116
43
  delete data.initialParams;
117
44
 
118
45
  const screenName = Component?.name || Component?.type?.name || 'Invalid';
46
+ const routes = props.navigation.getState()?.routes || [];
119
47
 
120
48
  /**
121
49
  * set options for screen
@@ -145,18 +73,31 @@ const StackScreen: React.FC<ScreenParams> = props => {
145
73
  }, 300);
146
74
  }
147
75
  navigator?.maxApi?.of?.({screenName});
76
+ const subscription = props.navigation?.addListener?.('focus', () => {
77
+ navigator?.maxApi?.getDataObserver('CURRENT_SCREEN', (data: any) => {
78
+ let preScreenName = data?.screenName;
79
+ if (routes?.length > 1) {
80
+ const screen = routes?.[routes?.length - 2]?.params?.screen;
81
+ preScreenName = screen?.name || screen?.type?.name || 'Invalid';
82
+ }
83
+ onScreenNavigated(preScreenName);
84
+ navigator?.maxApi?.setObserver('CURRENT_SCREEN', {screenName});
85
+ });
86
+ });
148
87
  navigator?.maxApi?.startTraceScreenLoad?.(screenName, (data: any) => {
149
- tracked.current.traceIdLoad = data?.traceId;
88
+ tracking.current.traceIdLoad = data?.traceId;
150
89
  });
151
90
  navigator?.maxApi?.startTraceScreenInteraction?.(
152
91
  screenName,
153
92
  (data: any) => {
154
- tracked.current.traceIdInteraction = data?.traceId;
93
+ tracking.current.traceIdInteraction = data?.traceId;
155
94
  }
156
95
  );
96
+
157
97
  return () => {
158
98
  onScreenLoad();
159
99
  onScreenInteraction();
100
+ subscription?.();
160
101
  };
161
102
  }, []);
162
103
 
@@ -164,9 +105,10 @@ const StackScreen: React.FC<ScreenParams> = props => {
164
105
  * tracking for screen load
165
106
  */
166
107
  const onScreenLoad = () => {
167
- if (!tracked.current?.releaseLoad) {
168
- if (timeLoad.current === 0) {
169
- timeLoad.current = endTime.current - startTime.current;
108
+ if (!tracking.current?.releaseLoad) {
109
+ if (tracking.current.timeLoad === 0) {
110
+ tracking.current.timeLoad =
111
+ tracking.current.endTime - tracking.current.startTime;
170
112
  }
171
113
 
172
114
  context.autoTracking?.({
@@ -174,27 +116,26 @@ const StackScreen: React.FC<ScreenParams> = props => {
174
116
  code: context.code,
175
117
  buildNumber: context.buildNumber,
176
118
  screenName,
177
- action: 'push',
178
119
  componentName: 'Screen',
179
120
  state: 'load',
180
- duration: timeLoad.current,
121
+ duration: tracking.current.timeLoad,
181
122
  });
182
123
  navigator?.maxApi?.stopTrace?.(
183
- tracked.current.traceIdLoad,
184
- {value: timeLoad.current / 1000},
124
+ tracking.current.traceIdLoad,
125
+ {value: tracking.current.timeLoad / 1000},
185
126
  null
186
127
  );
187
- tracked.current.releaseLoad = true;
128
+ tracking.current.releaseLoad = true;
188
129
 
189
130
  /**
190
131
  * debug
191
132
  */
192
133
  navigator?.maxApi?.showToastDebug?.({
193
134
  appId: context.appId,
194
- message: `${screenName} screen_load_time ${timeLoad.current}`,
195
- type: 'error',
135
+ message: `${screenName} screen_load_time ${tracking.current.timeLoad}`,
136
+ type: 'ERROR',
196
137
  });
197
- if (timeLoad.current <= 0 && context.enableAutoId) {
138
+ if (tracking.current.timeLoad <= 0 && context.enableAutoId) {
198
139
  Alert.alert(screenName, "Can't get screen load time");
199
140
  }
200
141
  }
@@ -204,12 +145,13 @@ const StackScreen: React.FC<ScreenParams> = props => {
204
145
  * tracking for screen load
205
146
  */
206
147
  const onScreenInteraction = () => {
207
- if (!tracked.current?.releaseInteraction) {
208
- if (timeLoad.current === 0) {
209
- timeLoad.current = endTime.current - startTime.current;
148
+ if (!tracking.current?.releaseInteraction) {
149
+ if (tracking.current.timeLoad === 0) {
150
+ tracking.current.timeLoad =
151
+ tracking.current.endTime - tracking.current.startTime;
210
152
  }
211
- if (timeInteraction.current === 0) {
212
- timeInteraction.current = timeLoad.current;
153
+ if (tracking.current.timeInteraction === 0) {
154
+ tracking.current.timeInteraction = tracking.current.timeLoad;
213
155
  }
214
156
 
215
157
  context.autoTracking?.({
@@ -219,43 +161,71 @@ const StackScreen: React.FC<ScreenParams> = props => {
219
161
  screenName,
220
162
  componentName: 'Screen',
221
163
  state: 'interaction',
222
- duration: timeInteraction.current - timeLoad.current,
164
+ duration: tracking.current.timeInteraction - tracking.current.timeLoad,
165
+ totalDuration: tracking.current.timeInteraction,
223
166
  });
224
167
  navigator?.maxApi?.stopTrace?.(
225
- tracked.current.traceIdInteraction,
226
- {value: timeInteraction.current / 1000},
168
+ tracking.current.traceIdInteraction,
169
+ {value: tracking.current.timeInteraction / 1000},
227
170
  null
228
171
  );
229
- tracked.current.releaseInteraction = true;
172
+ tracking.current.releaseInteraction = true;
230
173
 
231
174
  /**
232
175
  * debug toast
233
176
  */
234
177
  navigator?.maxApi?.showToastDebug?.({
235
178
  appId: context.appId,
236
- message: `${screenName} screen_interaction_time ${timeInteraction.current}`,
237
- type: 'error',
179
+ message: `${screenName} screen_interaction_time ${tracking.current.timeInteraction}`,
180
+ type: 'ERROR',
238
181
  });
239
- if (timeInteraction.current <= 0 && context.enableAutoId) {
182
+ if (tracking.current.timeInteraction <= 0 && context.enableAutoId) {
240
183
  Alert.alert(screenName, "Can't get screen interaction time");
241
184
  }
242
185
  }
243
186
  };
244
187
 
188
+ /**
189
+ * tracking for screen navigated
190
+ */
191
+ const onScreenNavigated = (preScreenName: string) => {
192
+ context.autoTracking?.({
193
+ appId: context.appId,
194
+ code: context.code,
195
+ buildNumber: context.buildNumber,
196
+ preScreenName,
197
+ screenName,
198
+ componentName: 'Screen',
199
+ state: 'navigated',
200
+ });
201
+
202
+ /**
203
+ * debug toast
204
+ */
205
+ navigator?.maxApi?.showToastDebug?.({
206
+ appId: context.appId,
207
+ message: `${screenName} screen_navigated`,
208
+ type: 'ERROR',
209
+ });
210
+ };
211
+
245
212
  return (
246
213
  <ScreenContext.Provider
247
214
  value={{
248
215
  screenName,
249
216
  onElementLoad: () => {
250
- clearTimeout(timeoutLoad.current);
251
- endTime.current = Date.now();
252
- interaction.current?.cancel?.();
253
- interaction.current = InteractionManager.runAfterInteractions(() => {
254
- timeInteraction.current = Date.now() - startTime.current;
255
- });
256
- timeoutLoad.current = setTimeout(() => {
257
- if (timeLoad.current === 0) {
258
- timeLoad.current = endTime.current - startTime.current;
217
+ clearTimeout(tracking.current.timeoutLoad);
218
+ tracking.current.endTime = Date.now();
219
+ tracking.current.interaction?.cancel?.();
220
+ tracking.current.interaction =
221
+ InteractionManager.runAfterInteractions(() => {
222
+ tracking.current.timeInteraction =
223
+ Date.now() - tracking.current.startTime;
224
+ });
225
+ tracking.current.timeoutLoad = setTimeout(() => {
226
+ if (tracking.current.timeLoad === 0) {
227
+ tracking.current.timeLoad =
228
+ tracking.current.endTime - tracking.current.startTime;
259
229
  }
260
230
  onScreenLoad();
261
231
  onScreenInteraction();
@@ -273,4 +243,78 @@ const StackScreen: React.FC<ScreenParams> = props => {
273
243
  );
274
244
  };
275
245
 
246
+ /**
247
+ * Empty screen for unvalidated screen name
248
+ * @constructor
249
+ */
250
+ const EmptyScreen: React.FC = () => {
251
+ return (
252
+ <View
253
+ style={{
254
+ backgroundColor: Colors.black_01,
255
+ padding: Spacing.M,
256
+ borderRadius: Radius.M,
257
+ }}>
258
+ <Text typography={'header_m_bold'}>Unvalidated screen name</Text>
259
+ <Text
260
+ typography={'description_default_regular'}
261
+ style={{paddingVertical: Spacing.S}}>
262
+ Your screen has not been rendered because Platform has not detected the
263
+ screen name. Please migrate to support this feature.
264
+ </Text>
265
+ <Text typography={'header_default'} style={{width: '100%'}}>
266
+ Possible fixes:
267
+ </Text>
268
+ <View style={{marginLeft: Spacing.S}}>
269
+ <Text typography={'body_default_regular'}>1. Off webpack config</Text>
270
+ <Text typography={'body_default_regular'}>
271
+ 2. Screen name refactoring
272
+ </Text>
273
+ <View style={{marginLeft: Spacing.S}}>
274
+ <Text
275
+ typography={'description_default_regular'}
276
+ style={{marginBottom: Spacing.S}}>
277
+ - Với các screen push/import dạng arrow function ={'>'} đổi thành
278
+ named function
279
+ </Text>
280
+ <Text
281
+ typography={'description_default_regular'}
282
+ style={{marginBottom: Spacing.S}}>
283
+ - Với các screen import dạng High Order Component ={'>'} rename
284
+ generic function thành named function
285
+ </Text>
286
+ <Text
287
+ typography={'description_default_regular'}
288
+ style={{marginBottom: Spacing.S}}>
289
+ - Với Tab Navigator, Platform sẽ lấy Tab Container làm screen name.
290
+ Trong trường hợp miniapp muốn track riêng action cho từng tab, tham
291
+ khảo theo docs
292
+ </Text>
293
+ </View>
294
+ </View>
295
+ <Text typography={'header_s_semibold'}>More information: </Text>
296
+ <Text
297
+ typography={'body_default_regular'}
298
+ color={Colors.blue_01}
299
+ onPress={() => {
300
+ Linking.openURL(
301
+ 'https://gitlab.mservice.com.vn/momo-platform/mini-app/-/tree/vn.momo.uikits/dev/app'
302
+ );
303
+ }}>
304
+ Mini App: vn.momo.uikits/dev
305
+ </Text>
306
+ <Text
307
+ typography={'body_default_regular'}
308
+ color={Colors.blue_01}
309
+ onPress={() => {
310
+ Linking.openURL(
311
+ 'https://docs.google.com/presentation/d/1bIFoh8gRXb6hsnGJz4O1Kxg4_oNikB1KuuEt2wULCDM/edit?usp=sharing'
312
+ );
313
+ }}>
314
+ https://docs.google.com/presentation/d/1bIFoh8gRXb6hsnGJz4O1Kxg4_oNikB1KuuEt2wULCDM/edit?usp=sharing
315
+ </Text>
316
+ </View>
317
+ );
318
+ };
319
+
276
320
  export default StackScreen;
@@ -0,0 +1,122 @@
1
+ import React, {useEffect, useRef} from 'react';
2
+ import {Animated, StyleSheet, View} from 'react-native';
3
+ import {BadgeDotProps} from './types';
4
+ import CommonStyle from './styles';
5
+
6
+ const DURATION = 500;
7
+
8
+ const BadgeDotAnimation = ({size, style}: BadgeDotProps) => {
9
+ // Refs for animated values
10
+ const scaleAnim = useRef(new Animated.Value(1)).current;
11
+ const waveScaleAnim = useRef(new Animated.Value(1)).current;
12
+ const waveOpacityAnim = useRef(new Animated.Value(0)).current;
13
+
14
+ const dotStyle = size === 'small' ? styles.dotSmall : styles.dot;
15
+ const waveStyle = size === 'small' ? styles.waveSmall : styles.wave;
16
+
17
+ useEffect(() => {
18
+ // Infinite loop animation for the scale and wave effect
19
+ const animation = Animated.loop(
20
+ Animated.parallel([
21
+ // Dot pulse animation
22
+ Animated.sequence([
23
+ Animated.spring(scaleAnim, {
24
+ toValue: 1, // Scale up slightly
25
+ friction: 5, // Controls the "bounciness" of the spring
26
+ tension: 30, // Controls the "stiffness" of the spring
27
+ useNativeDriver: true,
28
+ }),
29
+ Animated.spring(scaleAnim, {
30
+ toValue: 1.1,
31
+ friction: 5,
32
+ tension: 30,
33
+ useNativeDriver: true,
34
+ }),
35
+ ]), // Wave animation
36
+ Animated.sequence([
37
+ Animated.timing(waveScaleAnim, {
38
+ toValue: 2.5,
39
+ duration: DURATION * 3,
40
+ useNativeDriver: true,
41
+ }),
42
+ Animated.timing(waveScaleAnim, {
43
+ toValue: 1, // Reset wave size
44
+ duration: 0,
45
+ useNativeDriver: true,
46
+ }),
47
+ ]), // Wave opacity animation
48
+ Animated.sequence([
49
+ Animated.timing(waveOpacityAnim, {
50
+ toValue: 0.3, // Wave becomes visible
51
+ duration: DURATION * 2,
52
+ useNativeDriver: true,
53
+ }),
54
+ Animated.timing(waveOpacityAnim, {
55
+ toValue: 0, // Wave fades out
56
+ duration: DURATION,
57
+ useNativeDriver: true,
58
+ }),
59
+ ]),
60
+ ])
61
+ );
62
+ animation.start();
63
+
64
+ return () => {
65
+ animation.stop();
66
+ };
67
+ }, []);
68
+
69
+ return (
70
+ <View style={[styles.container, style]}>
71
+ {/* Wave Animation */}
72
+ <Animated.View
73
+ style={[
74
+ waveStyle,
75
+ {
76
+ transform: [{scale: waveScaleAnim}],
77
+ opacity: waveOpacityAnim,
78
+ },
79
+ ]}
80
+ />
81
+ {/* Dot Animation */}
82
+ <Animated.View
83
+ style={[
84
+ dotStyle,
85
+ {
86
+ transform: [{scale: scaleAnim}],
87
+ },
88
+ ]}
89
+ />
90
+ </View>
91
+ );
92
+ };
93
+
94
+ const styles = StyleSheet.create({
95
+ ...CommonStyle,
96
+ container: {
97
+ position: 'relative',
98
+ alignItems: 'center',
99
+ justifyContent: 'center',
100
+ },
101
+ dot: {
102
+ ...CommonStyle.dot,
103
+ borderWidth: 0,
104
+ },
105
+ dotSmall: {
106
+ ...CommonStyle.dotSmall,
107
+ borderWidth: 0,
108
+ },
109
+ wave: {
110
+ ...CommonStyle.dot,
111
+ opacity: 0,
112
+ position: 'absolute',
113
+ borderWidth: 0,
114
+ },
115
+ waveSmall: {
116
+ ...CommonStyle.dotSmall,
117
+ borderWidth: 0,
118
+ position: 'absolute',
119
+ },
120
+ });
121
+
122
+ export default BadgeDotAnimation;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/foundation",
3
- "version": "0.102.6-beta.0",
3
+ "version": "0.102.6-beta.10",
4
4
  "description": "React Native Component Kits",
5
5
  "main": "index.ts",
6
6
  "scripts": {},
package/publish.sh CHANGED
@@ -9,8 +9,8 @@ elif [ "$1" == "latest" ]; then
9
9
  npm version prerelease --preid=rc
10
10
  npm publish --tag latest --access=public
11
11
  else
12
- # npm version $(npm view @momo-kits/foundation@beta version)
13
- # npm version prerelease --preid=beta
12
+ npm version $(npm view @momo-kits/foundation@beta version)
13
+ npm version prerelease --preid=beta
14
14
  npm publish --tag beta --access=public
15
15
  fi
16
16