@momo-kits/foundation 0.81.1-optimize.21 → 0.81.1-rc.0

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.
Files changed (45) hide show
  1. package/Application/BottomSheet.tsx +27 -23
  2. package/Application/BottomTab/BottomTabBar.tsx +2 -2
  3. package/Application/BottomTab/index.tsx +2 -3
  4. package/Application/Components.tsx +288 -42
  5. package/Application/Localize.ts +44 -0
  6. package/Application/ModalScreen.tsx +2 -2
  7. package/Application/Navigation.ts +4 -18
  8. package/Application/NavigationContainer.tsx +10 -21
  9. package/Application/Navigator.ts +14 -16
  10. package/Application/StackScreen.tsx +211 -113
  11. package/Application/index.ts +5 -3
  12. package/Application/types.ts +30 -11
  13. package/Application/utils.tsx +60 -18
  14. package/Badge/BadgeDotAnimation.tsx +95 -0
  15. package/Badge/index.tsx +2 -1
  16. package/Badge/styles.ts +50 -6
  17. package/Button/index.tsx +0 -1
  18. package/Icon/types.ts +0 -1
  19. package/Input/Input.tsx +51 -17
  20. package/Input/InputDropDown.tsx +44 -47
  21. package/Input/InputMoney.tsx +56 -6
  22. package/Input/InputOTP.tsx +10 -6
  23. package/Input/InputSearch.tsx +259 -146
  24. package/Input/TextTyping.tsx +113 -0
  25. package/Input/common.tsx +29 -10
  26. package/Input/index.tsx +75 -74
  27. package/Input/styles.ts +43 -7
  28. package/Layout/FloatingButton.tsx +1 -1
  29. package/Layout/GridSystem.tsx +1 -1
  30. package/Layout/ItemList.tsx +3 -2
  31. package/Layout/Screen.tsx +174 -91
  32. package/Layout/styles.ts +0 -6
  33. package/Layout/types.ts +1 -1
  34. package/Pagination/PaginationScroll.tsx +2 -2
  35. package/Pagination/styles.ts +1 -1
  36. package/Popup/PopupNotify.tsx +3 -3
  37. package/Tag/index.tsx +9 -2
  38. package/Tag/styles.ts +3 -2
  39. package/Tag/types.ts +12 -0
  40. package/Title/index.tsx +6 -9
  41. package/Title/styles.ts +4 -4
  42. package/code-scanner.js +4 -4
  43. package/package.json +6 -5
  44. package/publish.sh +12 -22
  45. package/verify.js +36 -42
@@ -21,10 +21,10 @@ const ModalScreen: React.FC<any> = props => {
21
21
  };
22
22
 
23
23
  const Modal: React.FC<ModalParams> = props => {
24
- const {theme, navigator} = useContext(ApplicationContext);
24
+ const {navigator} = useContext(ApplicationContext);
25
25
  const {screen, barrierDismissible} = props.route.params;
26
26
  const Component = useRef(screen).current;
27
- const navigation = new Navigation(props.navigation, theme);
27
+ const navigation = new Navigation(props.navigation);
28
28
  const params = {
29
29
  ...props.route.params,
30
30
  navigation,
@@ -1,17 +1,13 @@
1
- import React from 'react';
2
1
  import {NavigationProp} from '@react-navigation/native';
3
- import {NavigationOptions, Theme} from './types';
4
- import {HeaderRightAction} from './index';
2
+ import {NavigationOptions} from './types';
5
3
  import {getOptions} from './utils';
6
- import {HeaderToolkitAction} from './Components';
7
4
 
8
5
  class Navigation {
9
6
  instance: NavigationProp<any>;
10
- readonly theme: Theme;
7
+ onHeaderRightChange?: (width: number) => void;
11
8
 
12
- constructor(instance: any, theme: Theme) {
9
+ constructor(instance: any) {
13
10
  this.instance = instance;
14
- this.theme = theme;
15
11
  }
16
12
 
17
13
  /**
@@ -19,16 +15,6 @@ class Navigation {
19
15
  * @param params
20
16
  */
21
17
  private filterParams = (params: NavigationOptions) => {
22
- if (params.headerRight) {
23
- const headerRight = params.headerRight?.({}) as React.ReactElement;
24
- const type = headerRight?.type;
25
- if (type !== HeaderRightAction && type !== HeaderToolkitAction) {
26
- console.warn(
27
- 'headerRight contains element type of HeaderRightAction | HeaderToolkitAction, Please check again.',
28
- );
29
- }
30
- }
31
-
32
18
  if (params.headerLeft) {
33
19
  console.warn('headerLeft not allow override render by design system!');
34
20
  delete params.headerLeft;
@@ -42,7 +28,7 @@ class Navigation {
42
28
  * @param params
43
29
  */
44
30
  setOptions = (params: NavigationOptions) => {
45
- params = getOptions(this.filterParams(params), this.theme);
31
+ params = getOptions(this.filterParams(params), this);
46
32
  this.instance.setOptions(params);
47
33
  };
48
34
  }
@@ -10,9 +10,9 @@ import StackScreen from './StackScreen';
10
10
  import ModalScreen from './ModalScreen';
11
11
  import Navigator from './Navigator';
12
12
  import {getDialogOptions, getModalOptions, getStackOptions} from './utils';
13
- import {LocalizationObject, NavigationContainerProps} from './types';
13
+ import {NavigationContainerProps} from './types';
14
14
  import {ApplicationContext} from './index';
15
- import kitLocalization from '../Assets/language.json';
15
+ import Localize from './Localize';
16
16
 
17
17
  const Stack = createStackNavigator();
18
18
 
@@ -21,15 +21,18 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
21
21
  theme,
22
22
  options,
23
23
  maxApi,
24
- localization,
25
24
  initialParams,
25
+ localize = new Localize({vi: {}, en: {}}),
26
26
  }) => {
27
27
  const navigationRef = useRef<NavigationContainerRef>(null);
28
28
  const isReady = useRef(false);
29
29
  const navigator = useRef(new Navigator(navigationRef, isReady));
30
30
  const [showGrid, setShowGrid] = useState(false);
31
31
  const config = useRef<any>();
32
-
32
+ /**
33
+ * inject data for navigator
34
+ */
35
+ navigator.current.maxApi = maxApi;
33
36
  /**
34
37
  * handle mini language & listen change
35
38
  * engine only shake to enable grid view
@@ -39,7 +42,7 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
39
42
  'onChangeGrid',
40
43
  enable => {
41
44
  setShowGrid(!!enable);
42
- },
45
+ }
43
46
  );
44
47
 
45
48
  return () => {
@@ -47,22 +50,8 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
47
50
  };
48
51
  }, []);
49
52
 
50
- /**
51
- * inject data for navigator
52
- */
53
- navigator.current.maxApi = maxApi;
54
-
55
- /**
56
- * translate
57
- * @param key
58
- */
59
53
  const translate = (key: string) => {
60
- const language: 'vi' | 'en' = 'vi';
61
- const mergedLocalization: LocalizationObject = {
62
- vi: {...localization?.vi, ...kitLocalization.vi},
63
- en: {...localization?.en, ...kitLocalization.en},
64
- };
65
- return mergedLocalization?.[language]?.[key] || key;
54
+ return localize?.translate(key);
66
55
  };
67
56
 
68
57
  return (
@@ -87,7 +76,7 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
87
76
  notification: theme.colors.error.primary,
88
77
  },
89
78
  }}
90
- ref={navigator.current?.ref}
79
+ ref={navigationRef}
91
80
  onReady={() => {
92
81
  isReady.current = true;
93
82
  }}
@@ -12,7 +12,7 @@ class Navigator {
12
12
  toolkitConfig?: HeaderToolkitProps;
13
13
  maxApi?: any;
14
14
  dismissData?: any;
15
- toolkitCallback?: (item: any) => void;
15
+ toolkitCallback?: (key: string) => void;
16
16
 
17
17
  constructor(navigation: any, isReady: any) {
18
18
  this.ref = navigation;
@@ -25,7 +25,7 @@ class Navigator {
25
25
  */
26
26
  push = (params: ScreenParams) => {
27
27
  if (this.isReady.current) {
28
- this.ref.current.dispatch(StackActions.push('Stack', params));
28
+ this.ref.current?.dispatch?.(StackActions.push('Stack', params));
29
29
  }
30
30
  };
31
31
 
@@ -35,7 +35,7 @@ class Navigator {
35
35
  */
36
36
  replace = (params: ScreenParams) => {
37
37
  if (this.isReady.current) {
38
- this.ref.current.dispatch(StackActions.replace('Stack', params));
38
+ this.ref.current?.dispatch?.(StackActions.replace('Stack', params));
39
39
  }
40
40
  };
41
41
  /**
@@ -44,7 +44,7 @@ class Navigator {
44
44
  */
45
45
  pop = (count?: number) => {
46
46
  if (this.isReady.current) {
47
- this.ref.current.dispatch(StackActions.pop(count ?? 1));
47
+ this.ref.current?.dispatch?.(StackActions.pop(count ?? 1));
48
48
  }
49
49
  };
50
50
 
@@ -54,7 +54,7 @@ class Navigator {
54
54
  */
55
55
  present = (params: ScreenParams) => {
56
56
  if (this.isReady.current) {
57
- this.ref.current.dispatch(StackActions.push('Dialog', params));
57
+ this.ref.current?.dispatch?.(StackActions.push('Dialog', params));
58
58
  }
59
59
  };
60
60
 
@@ -64,7 +64,7 @@ class Navigator {
64
64
  */
65
65
  showModal = (params: ModalParams) => {
66
66
  if (this.isReady.current) {
67
- this.ref.current.dispatch(StackActions.push('Modal', params));
67
+ this.ref.current?.dispatch?.(StackActions.push('Modal', params));
68
68
  }
69
69
  };
70
70
 
@@ -74,11 +74,11 @@ class Navigator {
74
74
  */
75
75
  showBottomSheet = (params: BottomSheetParams) => {
76
76
  if (this.isReady.current) {
77
- this.ref.current.dispatch(
77
+ this.ref.current?.dispatch?.(
78
78
  StackActions.push('Modal', {
79
79
  ...params,
80
80
  isBottomSheet: true,
81
- }),
81
+ })
82
82
  );
83
83
  }
84
84
  };
@@ -88,7 +88,7 @@ class Navigator {
88
88
  */
89
89
  popToTop = () => {
90
90
  if (this.isReady.current) {
91
- this.ref.current.dispatch(StackActions.popToTop());
91
+ this.ref.current?.dispatch?.(StackActions.popToTop());
92
92
  }
93
93
  };
94
94
 
@@ -99,11 +99,11 @@ class Navigator {
99
99
  */
100
100
  navigate = (name: string, params: any) => {
101
101
  if (this.isReady.current) {
102
- this.ref.current.dispatch(
102
+ this.ref.current?.dispatch?.(
103
103
  CommonActions.navigate({
104
104
  name,
105
105
  params,
106
- }),
106
+ })
107
107
  );
108
108
  }
109
109
  };
@@ -114,7 +114,7 @@ class Navigator {
114
114
  */
115
115
  reset = (params: ScreenParams) => {
116
116
  if (this.isReady.current) {
117
- this.ref.current.dispatch(
117
+ this.ref.current?.dispatch?.(
118
118
  CommonActions.reset({
119
119
  index: 0,
120
120
  routes: [
@@ -124,7 +124,7 @@ class Navigator {
124
124
  params,
125
125
  },
126
126
  ],
127
- }),
127
+ })
128
128
  );
129
129
  }
130
130
  };
@@ -141,9 +141,7 @@ class Navigator {
141
141
  * set callback function for toolkit
142
142
  * @param callback
143
143
  */
144
- setToolkitCallback = (
145
- callback: (item: {key: string; action: string}) => void,
146
- ) => {
144
+ setToolkitCallback = (callback: (key: string) => void) => {
147
145
  this.toolkitCallback = callback;
148
146
  };
149
147
  }
@@ -1,6 +1,6 @@
1
1
  import React, {useContext, useEffect, useLayoutEffect, useRef} from 'react';
2
2
  import {useHeaderHeight} from '@react-navigation/stack';
3
- import {InteractionManager, Linking, View} from 'react-native';
3
+ import {Alert, InteractionManager, Linking, View} from 'react-native';
4
4
  import {ScreenParams} from './types';
5
5
  import Navigation from './Navigation';
6
6
  import {ApplicationContext, MiniAppContext, ScreenContext} from './index';
@@ -8,103 +8,30 @@ 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
88
14
  * @constructor
89
15
  */
90
16
  const StackScreen: React.FC<ScreenParams> = props => {
91
- const {theme, 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>({
98
- releaseLoad: undefined,
99
- releaseInteraction: undefined,
17
+ const {showGrid, navigator} = useContext(ApplicationContext);
18
+ const tracking = useRef<any>({
100
19
  timeoutLoad: undefined,
101
20
  timeoutInteraction: undefined,
21
+ timeoutTracking: undefined,
22
+ startTime: Date.now(),
23
+ endTime: Date.now(),
24
+ traceIdLoad: undefined,
25
+ traceIdInteraction: undefined,
26
+ releaseLoad: undefined,
27
+ releaseInteraction: undefined,
28
+ timeLoad: 0,
29
+ timeInteraction: 0,
102
30
  });
103
- const interaction = useRef<any>();
104
- const context = useContext<any>(MiniAppContext);
105
31
 
32
+ const context = useContext<any>(MiniAppContext);
106
33
  const {screen: Component, options, initialParams} = props.route.params;
107
- const navigation = new Navigation(props.navigation, theme);
34
+ const navigation = new Navigation(props.navigation);
108
35
  const heightHeader = useHeaderHeight();
109
36
 
110
37
  const data = {
@@ -117,14 +44,24 @@ const StackScreen: React.FC<ScreenParams> = props => {
117
44
  delete data.initialParams;
118
45
 
119
46
  const screenName = Component?.name || Component?.type?.name || 'Invalid';
47
+ const routes = props.navigation.getState()?.routes || [];
120
48
 
121
49
  /**
122
50
  * set options for screen
123
51
  */
124
52
  useLayoutEffect(() => {
53
+ let defaultOptions = {
54
+ headerRight: {
55
+ type: 'toolkit',
56
+ },
57
+ };
125
58
  if (options) {
126
- navigation.setOptions(options);
59
+ defaultOptions = {
60
+ ...defaultOptions,
61
+ ...options,
62
+ };
127
63
  }
64
+ navigation.setOptions(defaultOptions);
128
65
  }, [options]);
129
66
 
130
67
  /**
@@ -137,17 +74,38 @@ const StackScreen: React.FC<ScreenParams> = props => {
137
74
  }, 300);
138
75
  }
139
76
 
140
- navigator?.maxApi?.of?.({screenName});
141
- tracked.current.timeoutLoad = setTimeout(() => {
77
+ const subscription = props.navigation?.addListener?.('focus', () => {
78
+ navigator?.maxApi?.of?.({screenName});
79
+ navigator?.maxApi?.getDataObserver('CURRENT_SCREEN', (data: any) => {
80
+ let preScreenName = data?.screenName;
81
+ if (routes?.length > 1) {
82
+ const screen = routes?.[routes?.length - 2]?.params?.screen;
83
+ preScreenName = screen?.name || screen?.type?.name || 'Invalid';
84
+ }
85
+ onScreenNavigated(preScreenName);
86
+ navigator?.maxApi?.setObserver('CURRENT_SCREEN', {screenName});
87
+ });
88
+ });
89
+ navigator?.maxApi?.startTraceScreenLoad?.(screenName, (data: any) => {
90
+ tracking.current.traceIdLoad = data?.traceId;
91
+ });
92
+ navigator?.maxApi?.startTraceScreenInteraction?.(
93
+ screenName,
94
+ (data: any) => {
95
+ tracking.current.traceIdInteraction = data?.traceId;
96
+ }
97
+ );
98
+
99
+ tracking.current.timeoutTracking = setTimeout(() => {
142
100
  onScreenLoad();
143
- }, 5000);
144
- tracked.current.timeoutInteraction = setTimeout(() => {
145
101
  onScreenInteraction();
146
102
  }, 5000);
147
103
 
148
104
  return () => {
149
105
  onScreenLoad();
150
106
  onScreenInteraction();
107
+ clearTimeout(tracking.current.timeoutTracking);
108
+ subscription?.();
151
109
  };
152
110
  }, []);
153
111
 
@@ -155,8 +113,12 @@ const StackScreen: React.FC<ScreenParams> = props => {
155
113
  * tracking for screen load
156
114
  */
157
115
  const onScreenLoad = () => {
158
- clearTimeout(tracked.current.timeoutLoad);
159
- if (!tracked.current?.releaseLoad) {
116
+ if (!tracking.current?.releaseLoad) {
117
+ if (tracking.current.timeLoad === 0) {
118
+ tracking.current.timeLoad =
119
+ tracking.current.endTime - tracking.current.startTime;
120
+ }
121
+
160
122
  context.autoTracking?.({
161
123
  appId: context.appId,
162
124
  code: context.code,
@@ -164,13 +126,26 @@ const StackScreen: React.FC<ScreenParams> = props => {
164
126
  screenName,
165
127
  componentName: 'Screen',
166
128
  state: 'load',
167
- duration: timeLoad.current,
129
+ duration: tracking.current.timeLoad,
168
130
  });
131
+ navigator?.maxApi?.stopTrace?.(
132
+ tracking.current.traceIdLoad,
133
+ {value: tracking.current.timeLoad / 1000},
134
+ null
135
+ );
136
+ tracking.current.releaseLoad = true;
137
+
138
+ /**
139
+ * debug
140
+ */
169
141
  navigator?.maxApi?.showToastDebug?.({
170
- appId: `auto - ${context.appId}`,
171
- message: `${screenName} screen_load_time ${timeLoad.current}`,
142
+ appId: context.appId,
143
+ message: `${screenName} screen_load_time ${tracking.current.timeLoad}`,
144
+ type: 'ERROR',
172
145
  });
173
- tracked.current.releaseLoad = true;
146
+ if (tracking.current.timeLoad <= 0 && context.enableAutoId) {
147
+ Alert.alert(screenName, "Can't get screen load time");
148
+ }
174
149
  }
175
150
  };
176
151
 
@@ -178,8 +153,15 @@ const StackScreen: React.FC<ScreenParams> = props => {
178
153
  * tracking for screen load
179
154
  */
180
155
  const onScreenInteraction = () => {
181
- clearTimeout(tracked.current.timeoutInteraction);
182
- if (!tracked.current?.releaseInteraction) {
156
+ if (!tracking.current?.releaseInteraction) {
157
+ if (tracking.current.timeLoad === 0) {
158
+ tracking.current.timeLoad =
159
+ tracking.current.endTime - tracking.current.startTime;
160
+ }
161
+ if (tracking.current.timeInteraction === 0) {
162
+ tracking.current.timeInteraction = tracking.current.timeLoad;
163
+ }
164
+
183
165
  context.autoTracking?.({
184
166
  appId: context.appId,
185
167
  code: context.code,
@@ -187,32 +169,74 @@ const StackScreen: React.FC<ScreenParams> = props => {
187
169
  screenName,
188
170
  componentName: 'Screen',
189
171
  state: 'interaction',
190
- duration: timeInteraction.current - timeLoad.current,
172
+ duration: tracking.current.timeInteraction - tracking.current.timeLoad,
173
+ totalDuration: tracking.current.timeInteraction,
191
174
  });
175
+ navigator?.maxApi?.stopTrace?.(
176
+ tracking.current.traceIdInteraction,
177
+ {value: tracking.current.timeInteraction / 1000},
178
+ null
179
+ );
180
+ tracking.current.releaseInteraction = true;
192
181
 
182
+ /**
183
+ * debug toast
184
+ */
193
185
  navigator?.maxApi?.showToastDebug?.({
194
- appId: `auto - ${context.appId}`,
195
- message: `${screenName} screen_interaction_time ${timeInteraction.current}`,
186
+ appId: context.appId,
187
+ message: `${screenName} screen_interaction_time ${tracking.current.timeInteraction}`,
188
+ type: 'ERROR',
196
189
  });
197
- tracked.current.releaseInteraction = true;
190
+ if (tracking.current.timeInteraction <= 0 && context.enableAutoId) {
191
+ Alert.alert(screenName, "Can't get screen interaction time");
192
+ }
198
193
  }
199
194
  };
200
195
 
196
+ /**
197
+ * tracking for screen navigated
198
+ */
199
+ const onScreenNavigated = (preScreenName: string) => {
200
+ context.autoTracking?.({
201
+ appId: context.appId,
202
+ code: context.code,
203
+ buildNumber: context.buildNumber,
204
+ preScreenName,
205
+ screenName,
206
+ componentName: 'Screen',
207
+ state: 'navigated',
208
+ });
209
+
210
+ /**
211
+ * debug toast
212
+ */
213
+ navigator?.maxApi?.showToastDebug?.({
214
+ appId: context.appId,
215
+ message: `${screenName} screen_navigated`,
216
+ type: 'ERROR',
217
+ });
218
+ };
219
+
201
220
  return (
202
221
  <ScreenContext.Provider
203
222
  value={{
204
223
  screenName,
205
224
  onElementLoad: () => {
206
- endTime.current = Date.now();
207
- interaction.current?.cancel?.();
208
- interaction.current = InteractionManager.runAfterInteractions(() => {
209
- timeInteraction.current = Date.now() - startTime.current;
210
- });
211
- clearTimeout(timeoutLoad.current);
212
- timeoutLoad.current = setTimeout(() => {
213
- if (timeLoad.current === 0) {
214
- timeLoad.current = endTime.current - startTime.current;
225
+ clearTimeout(tracking.current.timeoutLoad);
226
+ tracking.current.endTime = Date.now();
227
+ tracking.current.timeoutInteraction?.cancel?.();
228
+ tracking.current.timeoutInteraction =
229
+ InteractionManager.runAfterInteractions(() => {
230
+ tracking.current.timeInteraction =
231
+ Date.now() - tracking.current.startTime;
232
+ });
233
+ tracking.current.timeoutLoad = setTimeout(() => {
234
+ if (tracking.current.timeLoad === 0) {
235
+ tracking.current.timeLoad =
236
+ tracking.current.endTime - tracking.current.startTime;
215
237
  }
238
+ onScreenLoad();
239
+ onScreenInteraction();
216
240
  }, 2000);
217
241
  },
218
242
  }}>
@@ -227,4 +251,78 @@ const StackScreen: React.FC<ScreenParams> = props => {
227
251
  );
228
252
  };
229
253
 
254
+ /**
255
+ * Empty screen for unvalidated screen name
256
+ * @constructor
257
+ */
258
+ const EmptyScreen: React.FC = () => {
259
+ return (
260
+ <View
261
+ style={{
262
+ backgroundColor: Colors.black_01,
263
+ padding: Spacing.M,
264
+ borderRadius: Radius.M,
265
+ }}>
266
+ <Text typography={'header_m_bold'}>Unvalidated screen name</Text>
267
+ <Text
268
+ typography={'description_default_regular'}
269
+ style={{paddingVertical: Spacing.S}}>
270
+ Your screen has not been rendered because Platform has not detected the
271
+ screen name. Please migrate to support this feature.
272
+ </Text>
273
+ <Text typography={'header_default'} style={{width: '100%'}}>
274
+ Possible fixes:
275
+ </Text>
276
+ <View style={{marginLeft: Spacing.S}}>
277
+ <Text typography={'body_default_regular'}>1. Off webpack config</Text>
278
+ <Text typography={'body_default_regular'}>
279
+ 2. Screen name refactoring
280
+ </Text>
281
+ <View style={{marginLeft: Spacing.S}}>
282
+ <Text
283
+ typography={'description_default_regular'}
284
+ style={{marginBottom: Spacing.S}}>
285
+ - Với các screen push/import dạng arrow function ={'>'} đổi thành
286
+ named function
287
+ </Text>
288
+ <Text
289
+ typography={'description_default_regular'}
290
+ style={{marginBottom: Spacing.S}}>
291
+ - Với các screen import dạng High Order Component ={'>'} rename
292
+ generic function thành named function
293
+ </Text>
294
+ <Text
295
+ typography={'description_default_regular'}
296
+ style={{marginBottom: Spacing.S}}>
297
+ - Với Tab Navigator, Platform sẽ lấy Tab Container làm screen name.
298
+ Trong trường hợp miniapp muốn track riêng action cho từng tab, tham
299
+ khảo theo docs
300
+ </Text>
301
+ </View>
302
+ </View>
303
+ <Text typography={'header_s_semibold'}>More information: </Text>
304
+ <Text
305
+ typography={'body_default_regular'}
306
+ color={Colors.blue_01}
307
+ onPress={() => {
308
+ Linking.openURL(
309
+ 'https://gitlab.mservice.com.vn/momo-platform/mini-app/-/tree/vn.momo.uikits/dev/app'
310
+ );
311
+ }}>
312
+ Mini App: vn.momo.uikits/dev
313
+ </Text>
314
+ <Text
315
+ typography={'body_default_regular'}
316
+ color={Colors.blue_01}
317
+ onPress={() => {
318
+ Linking.openURL(
319
+ 'https://docs.google.com/presentation/d/1bIFoh8gRXb6hsnGJz4O1Kxg4_oNikB1KuuEt2wULCDM/edit?usp=sharing'
320
+ );
321
+ }}>
322
+ https://docs.google.com/presentation/d/1bIFoh8gRXb6hsnGJz4O1Kxg4_oNikB1KuuEt2wULCDM/edit?usp=sharing
323
+ </Text>
324
+ </View>
325
+ );
326
+ };
327
+
230
328
  export default StackScreen;