@momo-kits/foundation 0.121.3 → 0.121.4-rc.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.
@@ -50,7 +50,7 @@ const BottomSheet: React.FC<BottomSheetParams> = props => {
50
50
  useKeyboardAvoidingView = true,
51
51
  useScrollOverflow = false,
52
52
  keyboardVerticalOffset,
53
- useDivider,
53
+ useDivider = true,
54
54
  }: BottomSheetParams = props.route.params;
55
55
 
56
56
  const customEasingOpen = Easing.bezier(0.05, 0.7, 0.1, 1);
@@ -7,7 +7,7 @@ import {useSafeAreaInsets} from 'react-native-safe-area-context';
7
7
  import {Colors} from '../../Consts';
8
8
  import {Icon} from '../../Icon';
9
9
  import {exportFontFamily, Text} from '../../Text';
10
- import {ApplicationContext} from '../index';
10
+ import {ApplicationContext, MiniAppContext} from '../index';
11
11
  import StackScreen from '../StackScreen';
12
12
  import {BottomTabProps} from '../types';
13
13
  import {getOptions, getStackOptions} from '../utils';
@@ -17,6 +17,8 @@ const Tab = createBottomTabNavigator();
17
17
  const Stack = createStackNavigator();
18
18
 
19
19
  const TabScreen: React.FC<any> = ({route, navigation}) => {
20
+ const {navigator} = useContext(ApplicationContext);
21
+ const context = useContext<any>(MiniAppContext);
20
22
  const {nested, options, screen, initialParams} = route?.params;
21
23
  const useAnimation = route?.params?.useAnimation ?? true;
22
24
 
@@ -24,6 +26,7 @@ const TabScreen: React.FC<any> = ({route, navigation}) => {
24
26
  const scaleValue = 0.97;
25
27
  const opacity = new Animated.Value(opacityValue);
26
28
  const scale = new Animated.Value(scaleValue);
29
+ const screenName = screen?.name || screen?.type?.name || 'Invalid';
27
30
 
28
31
  useFocusEffect(
29
32
  React.useCallback(() => {
@@ -39,6 +42,14 @@ const TabScreen: React.FC<any> = ({route, navigation}) => {
39
42
  useNativeDriver: true,
40
43
  }),
41
44
  ]).start();
45
+
46
+ setTimeout(() => {
47
+ navigator?.maxApi?.getDataObserver?.('current_screen', (data: any) => {
48
+ onScreenNavigated(data?.screenName, screenName);
49
+ navigator?.maxApi?.setObserver?.('current_screen', {screenName});
50
+ });
51
+ }, 100);
52
+
42
53
  return () => {
43
54
  if (navigation.getState().index !== route?.params.index) {
44
55
  Animated.parallel([
@@ -58,6 +69,45 @@ const TabScreen: React.FC<any> = ({route, navigation}) => {
58
69
  }, [navigation])
59
70
  );
60
71
 
72
+ useEffect(() => {
73
+ const onFocusApp = navigator?.maxApi?.listen?.('onFocusApp', () => {
74
+ if (navigation.isFocused()) {
75
+ navigator?.maxApi?.getDataObserver?.('current_screen', (data: any) => {
76
+ onScreenNavigated(data?.screenName, screenName);
77
+ navigator?.maxApi?.setObserver?.('current_screen', {screenName});
78
+ });
79
+ }
80
+ });
81
+
82
+ return () => {
83
+ onFocusApp?.();
84
+ };
85
+ }, []);
86
+
87
+ const onScreenNavigated = (preScreenName: string, screenName: string) => {
88
+ const data: any = {
89
+ preScreenName,
90
+ screenName,
91
+ componentName: 'Screen',
92
+ state: 'navigated',
93
+ action: 'push',
94
+ };
95
+
96
+ context?.autoTracking?.({
97
+ ...context,
98
+ ...data,
99
+ });
100
+
101
+ /**
102
+ * debug toast
103
+ */
104
+ navigator?.maxApi?.showToastDebug?.({
105
+ appId: context.appId,
106
+ message: `${screenName} screen_navigated`,
107
+ type: 'ERROR',
108
+ });
109
+ };
110
+
61
111
  let opacityStyle: undefined | Animated.Value = undefined;
62
112
  let scaleStyle: number | Animated.Value = 1;
63
113
  if (useAnimation) {
@@ -86,6 +136,7 @@ const TabScreen: React.FC<any> = ({route, navigation}) => {
86
136
  screen,
87
137
  options: stackOptions,
88
138
  initialParams,
139
+ bottomTab: 'nested',
89
140
  }}
90
141
  options={{...getStackOptions()}}
91
142
  />
@@ -110,6 +161,7 @@ const TabScreen: React.FC<any> = ({route, navigation}) => {
110
161
  screen,
111
162
  options: stackOptions,
112
163
  initialParams,
164
+ bottomTab: 'default',
113
165
  }}
114
166
  options={{...getStackOptions(), ...options}}
115
167
  />
@@ -55,6 +55,7 @@ const HeaderToolkitAction: React.FC<any> = ({
55
55
  useShortcut = false,
56
56
  useMore = false,
57
57
  tools = [],
58
+ useCloseIcon = false,
58
59
  }) => {
59
60
  const {navigator} = useContext(ApplicationContext);
60
61
  const context = useContext<any>(MiniAppContext);
@@ -104,14 +105,14 @@ const HeaderToolkitAction: React.FC<any> = ({
104
105
  );
105
106
 
106
107
  const onDismiss = () => {
107
- if (isWhiteList) {
108
- navigator?.maxApi?.dispatchFunction?.('dismissAll');
109
- } else {
108
+ if (useCloseIcon && !isWhiteList) {
110
109
  navigator?.maxApi?.dispatchFunction?.(
111
110
  'dismiss',
112
111
  navigator?.dismissData,
113
112
  undefined
114
113
  );
114
+ } else {
115
+ navigator?.maxApi?.dispatchFunction?.('dismissAll');
115
116
  }
116
117
  };
117
118
 
@@ -299,7 +300,9 @@ const HeaderToolkitAction: React.FC<any> = ({
299
300
  <Icon
300
301
  color={tintColor}
301
302
  source={
302
- isWhiteList ? '16_basic_home' : '16_navigation_close_circle'
303
+ useCloseIcon && !isWhiteList
304
+ ? '16_navigation_close_circle'
305
+ : '16_basic_home'
303
306
  }
304
307
  size={20}
305
308
  />
@@ -96,7 +96,7 @@ const Modal: React.FC<ModalParams> = props => {
96
96
  style={StyleSheet.absoluteFillObject}>
97
97
  <KeyboardAvoidingView
98
98
  style={Styles.flexCenter}
99
- behavior={Platform.OS === 'ios' ? 'padding' : 'height'}>
99
+ behavior={Platform.OS === 'ios' ? 'padding' : undefined}>
100
100
  <Pressable
101
101
  style={StyleSheet.absoluteFillObject}
102
102
  onPress={() => onDismiss(undefined, barrierDismissible)}>
@@ -30,7 +30,6 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
30
30
  }) => {
31
31
  const context = useContext<any>(MiniAppContext);
32
32
  const navigationRef = useRef<NavigationContainerRef>(null);
33
- const routes = useRef<any>();
34
33
  const isReady = useRef(false);
35
34
  const navigator = useRef(new Navigator(navigationRef, isReady));
36
35
  const [showGrid, setShowGrid] = useState(false);
@@ -74,49 +73,6 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
74
73
  return localize?.translate(data as string);
75
74
  };
76
75
 
77
- /**
78
- * navigation state route change handle
79
- * @param preScreenName
80
- * @param screenName
81
- * @param action
82
- * @param type
83
- */
84
- const onScreenNavigated = (
85
- preScreenName: string,
86
- screenName: string,
87
- action: string,
88
- type: 'Screen' | 'Modal' | 'BottomSheet'
89
- ) => {
90
- let data: any = {
91
- preScreenName,
92
- screenName,
93
- componentName: type,
94
- state: 'navigated',
95
- };
96
- if (type !== 'Screen') {
97
- data = {
98
- preScreenName,
99
- screenName,
100
- componentName: type,
101
- };
102
- }
103
-
104
- context?.autoTracking?.({
105
- ...context,
106
- ...data,
107
- action,
108
- });
109
-
110
- /**
111
- * debug toast
112
- */
113
- maxApi?.showToastDebug?.({
114
- appId: context.appId,
115
- message: `${screenName} screen_navigated`,
116
- type: 'ERROR',
117
- });
118
- };
119
-
120
76
  navigator.current.setCurrentContext = setCurrentContext;
121
77
 
122
78
  return (
@@ -158,57 +114,6 @@ const NavigationContainer: React.FC<NavigationContainerProps> = ({
158
114
  ref={navigationRef}
159
115
  onReady={() => {
160
116
  isReady.current = true;
161
- routes.current = navigationRef.current?.getRootState?.()?.routes;
162
- maxApi?.getDataObserver('CURRENT_SCREEN', (data: any) => {
163
- onScreenNavigated(
164
- data?.screenName,
165
- screen?.name,
166
- 'push',
167
- 'Screen'
168
- );
169
- maxApi?.setObserver('CURRENT_SCREEN', {
170
- screenName: screen?.name,
171
- });
172
- });
173
- }}
174
- onStateChange={state => {
175
- const lastedRoute: any = state?.routes?.[state?.index];
176
- const oldRoute: any =
177
- routes.current?.[routes.current?.length - 1];
178
- const lasted = lastedRoute?.params?.screen;
179
- const previous = oldRoute?.params?.screen;
180
- const preScreenName = previous?.name ?? previous?.type?.name;
181
- const screenName = lasted?.name ?? lasted?.type?.name;
182
-
183
- let action: string;
184
- let type: 'Screen' | 'Modal' | 'BottomSheet';
185
-
186
- if (lastedRoute?.name === 'Modal') {
187
- type = 'Modal';
188
- action = 'open';
189
- if (lastedRoute?.params?.isBottomSheet) {
190
- type = 'BottomSheet';
191
- }
192
- } else if (oldRoute?.name === 'Modal') {
193
- action = 'close';
194
- type = 'Modal';
195
- if (oldRoute?.params?.isBottomSheet) {
196
- type = 'BottomSheet';
197
- }
198
- } else {
199
- type = 'Screen';
200
- if (routes.current?.length > (state?.routes?.length ?? 0)) {
201
- action = 'back';
202
- } else {
203
- action = 'push';
204
- }
205
- }
206
-
207
- onScreenNavigated(preScreenName, screenName, action, type);
208
-
209
- routes.current = state?.routes;
210
- maxApi?.of?.({screenName});
211
- maxApi?.setObserver('CURRENT_SCREEN', {screenName});
212
117
  }}
213
118
  independent={true}>
214
119
  <Stack.Navigator initialRouteName="Stack" headerMode="screen">
@@ -17,24 +17,36 @@ const runAfterInteractions = InteractionManager.runAfterInteractions;
17
17
  const StackScreen: React.FC<ScreenParams> = props => {
18
18
  const {showGrid, navigator} = useContext(ApplicationContext);
19
19
  const tracking = useRef<any>({
20
+ mounted: false,
20
21
  timeoutLoad: undefined,
21
22
  timeoutInteraction: undefined,
22
23
  timeoutTracking: undefined,
24
+ timeoutLoading: undefined,
23
25
  startTime: Date.now(),
24
26
  endTime: Date.now(),
25
27
  traceIdLoad: undefined,
26
28
  traceIdInteraction: undefined,
27
29
  releaseLoad: undefined,
28
30
  releaseInteraction: undefined,
31
+ releaseUserInteraction: undefined,
32
+ releaseLoading: false,
29
33
  timeLoad: 0,
30
34
  timeInteraction: 0,
35
+ timeStartLoading: 0,
36
+ timeEndLoading: 0,
31
37
  widgets: [],
32
38
  params: undefined,
39
+ lastElement: undefined,
33
40
  });
34
41
  const widgets = useRef<any>([]);
35
42
  const context = useContext<any>(MiniAppContext);
36
- const lastElement = useRef<any>(null);
37
- const {screen: Component, options, initialParams} = props.route.params;
43
+
44
+ const {
45
+ screen: Component,
46
+ options,
47
+ initialParams,
48
+ bottomTab,
49
+ } = props.route.params;
38
50
  const navigation = new Navigation(props.navigation, context);
39
51
  const heightHeader = useHeaderHeight();
40
52
 
@@ -62,6 +74,8 @@ const StackScreen: React.FC<ScreenParams> = props => {
62
74
  * tracking for screen
63
75
  */
64
76
  useEffect(() => {
77
+ let focusScreen: any;
78
+ let onFocusApp: any;
65
79
  if (['Invalid', 'screen'].includes(screenName)) {
66
80
  navigator?.maxApi?.showPopup?.('notice', {
67
81
  title: 'Invalid screen name',
@@ -70,6 +84,26 @@ const StackScreen: React.FC<ScreenParams> = props => {
70
84
  });
71
85
  }
72
86
 
87
+ if (!bottomTab) {
88
+ focusScreen = props.navigation.addListener('focus', () => {
89
+ navigator?.maxApi?.getDataObserver?.('current_screen', (data: any) => {
90
+ onScreenNavigated(data?.screenName, screenName);
91
+ navigator?.maxApi?.setObserver?.('current_screen', {screenName});
92
+ });
93
+ });
94
+ onFocusApp = navigator?.maxApi?.listen?.('onFocusApp', () => {
95
+ if (props.navigation.isFocused()) {
96
+ navigator?.maxApi?.getDataObserver?.(
97
+ 'current_screen',
98
+ (data: any) => {
99
+ onScreenNavigated(data?.screenName, screenName);
100
+ navigator?.maxApi?.setObserver?.('current_screen', {screenName});
101
+ }
102
+ );
103
+ }
104
+ });
105
+ }
106
+
73
107
  navigator?.maxApi?.startTraceScreenLoad?.(
74
108
  screenName,
75
109
  context,
@@ -93,10 +127,41 @@ const StackScreen: React.FC<ScreenParams> = props => {
93
127
  return () => {
94
128
  onScreenLoad();
95
129
  onScreenInteraction();
130
+ clearTimeout(tracking.current.timeoutLoad);
131
+ clearTimeout(tracking.current.timeoutInteraction);
96
132
  clearTimeout(tracking.current.timeoutTracking);
133
+ clearTimeout(tracking.current.timeoutLoading);
134
+ focusScreen?.();
135
+ onFocusApp?.();
97
136
  };
98
137
  }, []);
99
138
 
139
+ const onScreenNavigated = (preScreenName: string, screenName: string) => {
140
+ const data: any = {
141
+ preScreenName,
142
+ screenName,
143
+ componentName: 'Screen',
144
+ state: 'navigated',
145
+ action: tracking.current?.mounted ? 'back' : 'push',
146
+ };
147
+
148
+ context?.autoTracking?.({
149
+ ...context,
150
+ ...data,
151
+ });
152
+
153
+ tracking.current.mounted = true;
154
+
155
+ /**
156
+ * debug toast
157
+ */
158
+ navigator?.maxApi?.showToastDebug?.({
159
+ appId: context.appId,
160
+ message: `${screenName} screen_navigated`,
161
+ type: 'ERROR',
162
+ });
163
+ };
164
+
100
165
  /**
101
166
  * tracking for screen load
102
167
  */
@@ -116,7 +181,7 @@ const StackScreen: React.FC<ScreenParams> = props => {
116
181
  widgets: tracking.current.widgets,
117
182
  params: tracking.current.params,
118
183
  version: version,
119
- lastElement: lastElement.current,
184
+ lastElement: tracking.current.lastElement,
120
185
  });
121
186
  navigator?.maxApi?.stopTrace?.(
122
187
  tracking.current.traceIdLoad,
@@ -133,10 +198,13 @@ const StackScreen: React.FC<ScreenParams> = props => {
133
198
  message: `${screenName} screen_load_time ${timeLoad}`,
134
199
  type: 'ERROR',
135
200
  });
136
- if (__DEV__ && lastElement.current?.children?.current?.length > 0) {
201
+ if (
202
+ __DEV__ &&
203
+ tracking.current.lastElement?.children?.current?.length > 0
204
+ ) {
137
205
  Alert.alert(
138
206
  `${screenName}- load ${timeLoad}ms`,
139
- JSON.stringify(lastElement.current?.children?.current)
207
+ JSON.stringify(tracking.current.lastElement?.children?.current)
140
208
  );
141
209
  }
142
210
  }
@@ -183,6 +251,49 @@ const StackScreen: React.FC<ScreenParams> = props => {
183
251
  }
184
252
  };
185
253
 
254
+ /**
255
+ * tracking for first interaction by user
256
+ */
257
+ const onFirstInteraction = (action: string) => {
258
+ if (!tracking.current?.releaseUserInteraction) {
259
+ const timeLoad = tracking.current.endTime - tracking.current.startTime;
260
+ context?.autoTracking?.({
261
+ ...context,
262
+ screenName,
263
+ componentName: 'Screen',
264
+ state: 'interaction',
265
+ duration: timeLoad,
266
+ action,
267
+ });
268
+ tracking.current.releaseUserInteraction = true;
269
+
270
+ /**
271
+ * debug
272
+ */
273
+ navigator?.maxApi?.showToastDebug?.({
274
+ appId: context.appId,
275
+ message: `${screenName} user_interaction ${timeLoad}`,
276
+ type: 'ERROR',
277
+ });
278
+ }
279
+ };
280
+
281
+ const onScreenLoading = () => {
282
+ if (!tracking.current?.releaseLoading) {
283
+ const timeLoad =
284
+ tracking.current.timeEndLoading - tracking.current.timeStartLoading;
285
+ context?.autoTracking?.({
286
+ ...context,
287
+ screenName,
288
+ componentName: 'Screen',
289
+ state: 'loading',
290
+ duration: timeLoad,
291
+ loadingType: 'skeleton',
292
+ });
293
+ tracking.current.releaseLoading = true;
294
+ }
295
+ };
296
+
186
297
  return (
187
298
  <ScreenContext.Provider
188
299
  value={{
@@ -213,6 +324,7 @@ const StackScreen: React.FC<ScreenParams> = props => {
213
324
  }
214
325
  return;
215
326
  }
327
+
216
328
  /**
217
329
  * tracking for element screen load
218
330
  */
@@ -228,7 +340,7 @@ const StackScreen: React.FC<ScreenParams> = props => {
228
340
  * support for debug last element
229
341
  */
230
342
  if (data?.componentName) {
231
- lastElement.current = data;
343
+ tracking.current.lastElement = data;
232
344
  }
233
345
 
234
346
  /**
@@ -237,6 +349,7 @@ const StackScreen: React.FC<ScreenParams> = props => {
237
349
  if (data?.interaction) {
238
350
  onScreenLoad();
239
351
  onScreenInteraction();
352
+ onFirstInteraction(data?.action);
240
353
  }
241
354
  /**
242
355
  * timeout for handle tracking screen
@@ -253,6 +366,26 @@ const StackScreen: React.FC<ScreenParams> = props => {
253
366
  onScreenInteraction();
254
367
  }, 2000);
255
368
  },
369
+ onLoading: (loading: boolean) => {
370
+ if (loading && tracking.current.timeStartLoading === 0) {
371
+ tracking.current.timeStartLoading = Date.now();
372
+ }
373
+
374
+ /**
375
+ * tracking for loading screen
376
+ */
377
+ clearTimeout(tracking.current.timeoutLoading);
378
+ if (!loading) {
379
+ tracking.current.timeEndLoading = Date.now();
380
+ }
381
+
382
+ /**
383
+ * timeout for handle tracking screen
384
+ */
385
+ tracking.current.timeoutLoading = setTimeout(() => {
386
+ onScreenLoading();
387
+ }, 2000);
388
+ },
256
389
  onSetParams: (data: ScreenTrackingParams) => {
257
390
  tracking.current.params = data;
258
391
  },
@@ -21,6 +21,9 @@ const MiniAppContext = (Platform as any).MiniAppContext ?? Context;
21
21
  const ScreenContext = (Platform as any).ScreenContext ?? Context;
22
22
  const ComponentContext = (Platform as any).ComponentContext ?? Context;
23
23
  const SkeletonContext = createContext({loading: false});
24
+ const TrackingScopeContext = createContext<{scopeName?: string}>({
25
+ scopeName: undefined,
26
+ });
24
27
 
25
28
  export {
26
29
  ApplicationContext,
@@ -39,4 +42,5 @@ export {
39
42
  HeaderAnimated,
40
43
  setAutomationID,
41
44
  useComponentId,
45
+ TrackingScopeContext,
42
46
  };
@@ -192,6 +192,7 @@ export type HeaderRightToolkit = {
192
192
  tools?: ToolGroup[];
193
193
  preventClose?: PopupNotifyProps;
194
194
  useMore?: boolean;
195
+ useCloseIcon?: boolean;
195
196
  };
196
197
 
197
198
  export interface HeaderBackProps extends NavigationButtonProps {
@@ -13,7 +13,7 @@ import {
13
13
  import {HeaderTitleProps, NavigationOptions} from './types';
14
14
  import {Colors} from '../Consts';
15
15
  import {Animated, Platform} from 'react-native';
16
- import {MiniAppContext, ScreenContext} from './index';
16
+ import {MiniAppContext, ScreenContext, TrackingScopeContext} from './index';
17
17
 
18
18
  /**
19
19
  * default options for stack screen
@@ -173,12 +173,13 @@ const setAutomationID = (accessibilityLabel = '') => {
173
173
  const useComponentId = (componentName: string, accessibilityLabel?: string) => {
174
174
  const app = useContext<any>(MiniAppContext);
175
175
  const screen = useContext<any>(ScreenContext);
176
+ const {scopeName} = useContext<any>(TrackingScopeContext);
176
177
 
177
178
  const componentId = useMemo(() => {
178
179
  if (accessibilityLabel) {
179
180
  return accessibilityLabel;
180
181
  }
181
- return `${app.appId}/${app.code}/${screen.screenName}/${componentName}`;
182
+ return `${app.appId}/${app.code}/${screen.screenName}/${scopeName}/${componentName}`;
182
183
  }, [componentName, accessibilityLabel, app, screen]);
183
184
 
184
185
  return {componentId};
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import {TrackingScopeContext} from '../Application';
3
+
4
+ const TrackingScope = ({
5
+ scopeName,
6
+ children,
7
+ }: {
8
+ scopeName: string;
9
+ children: any;
10
+ }) => {
11
+ return (
12
+ <TrackingScopeContext.Provider value={{scopeName}}>
13
+ {children}
14
+ </TrackingScopeContext.Provider>
15
+ );
16
+ };
17
+
18
+ export {TrackingScope};
package/Layout/index.ts CHANGED
@@ -7,6 +7,7 @@ import {GridContextProps} from './types';
7
7
  import Item from './Item';
8
8
  import ItemList from './ItemList';
9
9
  import ItemSectionList from './ItemSectionList';
10
+ import {TrackingScope} from './TrackingScope';
10
11
 
11
12
  const GridContext = createContext<GridContextProps>({
12
13
  numberOfColumns: 12,
@@ -24,4 +25,5 @@ export {
24
25
  Item,
25
26
  ItemList,
26
27
  ItemSectionList,
28
+ TrackingScope,
27
29
  };
@@ -1,4 +1,4 @@
1
- import React, {useEffect, useMemo, useRef, useState} from 'react';
1
+ import React, {useContext, useEffect, useMemo, useRef, useState} from 'react';
2
2
  import {
3
3
  Animated,
4
4
  Easing,
@@ -12,9 +12,10 @@ import LinearGradient from 'react-native-linear-gradient';
12
12
  import {SkeletonTypes} from './types';
13
13
  import {Colors, Styles} from '../Consts';
14
14
  import styles from './styles';
15
- import {SkeletonContext} from '../Application';
15
+ import {ScreenContext, SkeletonContext} from '../Application';
16
16
 
17
17
  const Skeleton: React.FC<SkeletonTypes> = ({style}) => {
18
+ const screen = useContext<any>(ScreenContext);
18
19
  const [width, setWidth] = useState(0);
19
20
  const PRIMARY_COLOR = Colors.black_05;
20
21
  const HIGHLIGHT_COLOR1 = Colors.black_05;
@@ -33,14 +34,16 @@ const Skeleton: React.FC<SkeletonTypes> = ({style}) => {
33
34
  duration: 1000,
34
35
  easing: Easing.linear,
35
36
  useNativeDriver: Platform.OS !== 'web',
36
- }),
37
+ })
37
38
  );
38
39
  }, [beginShimmerPosition]);
39
40
 
40
41
  useEffect(() => {
41
42
  animatedValue.start();
43
+ screen?.onLoading?.(true);
42
44
  return () => {
43
45
  animatedValue.stop();
46
+ screen?.onLoading?.(false);
44
47
  };
45
48
  }, [animatedValue]);
46
49
 
@@ -49,6 +52,7 @@ const Skeleton: React.FC<SkeletonTypes> = ({style}) => {
49
52
  setWidth(newWidth);
50
53
  }
51
54
  };
55
+
52
56
  return (
53
57
  <View style={[styles.container, style]}>
54
58
  <View
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@momo-kits/foundation",
3
- "version": "0.121.3",
3
+ "version": "0.121.4-rc.1",
4
4
  "minimumDeployTarget": 32,
5
- "deploymentTarget": 120,
5
+ "deploymentTarget": 121,
6
6
  "description": "React Native Component Kits",
7
7
  "main": "index.ts",
8
8
  "scripts": {},
@@ -16,13 +16,13 @@
16
16
  "react-native-linear-gradient": "2.8.3",
17
17
  "react-native-gesture-handler": "1.10.3",
18
18
  "react-native-fast-image": "8.1.5",
19
+ "@react-navigation/bottom-tabs": "https://oauth2:TGi6oBj-LdzsKpLXQSoH@gitlab.mservice.com.vn/momo-platform/public/react-native-bottom-tabs.git",
19
20
  "@react-navigation/core": "5.16.1",
20
21
  "@react-navigation/native": "5.9.8",
21
22
  "@react-navigation/routers": "5.7.4",
22
- "react-native-reanimated": "git+https://oauth2:TGi6oBj-LdzsKpLXQSoH@gitlab.mservice.com.vn/momo-platform/public/react-native-reanimated.git#v1.13.4_gradle_7",
23
- "lottie-react-native": "https://oauth2:TGi6oBj-LdzsKpLXQSoH@gitlab.mservice.com.vn/momo-platform/public/momo-lottie-react-native.git",
24
- "@react-navigation/stack": "https://oauth2:TGi6oBj-LdzsKpLXQSoH@gitlab.mservice.com.vn/momo-platform/public/react-navigation-stack.git",
25
- "@react-navigation/bottom-tabs": "https://oauth2:TGi6oBj-LdzsKpLXQSoH@gitlab.mservice.com.vn/momo-platform/public/react-native-bottom-tabs.git"
23
+ "react-native-reanimated": "https://oauth2:TGi6oBj-LdzsKpLXQSoH@gitlab.mservice.com.vn/momo-platform/public/react-native-reanimated.git#v1.13.4_gradle_7",
24
+ "lottie-react-native": "https://oauth2:TGi6oBj-LdzsKpLXQSoH@gitlab.mservice.com.vn/momo-platform/public/momo-lottie-react-native.git#test_lottie_ios",
25
+ "@react-navigation/stack": "https://oauth2:TGi6oBj-LdzsKpLXQSoH@gitlab.mservice.com.vn/momo-platform/public/react-navigation-stack.git"
26
26
  },
27
27
  "peerDependencies": {
28
28
  "react-native": "*"
package/publish.sh CHANGED
@@ -9,10 +9,13 @@ elif [ "$1" == "latest" ]; then
9
9
  npm version $(npm view @momo-kits/foundation@latest version)
10
10
  npm version prerelease --preid=rc
11
11
  npm publish --tag latest --access=public
12
- else
12
+ elif [ "$1" == "beta" ]; then
13
13
  npm version $(npm view @momo-kits/foundation@beta version)
14
14
  npm version prerelease --preid=beta
15
15
  npm publish --tag beta --access=public
16
+ else
17
+ npm publish --tag alpha --access=public
16
18
  fi
19
+
17
20
  PACKAGE_NAME=$(npm pkg get name)
18
21
  NEW_PACKAGE_VERSION=$(npm pkg get version)
@@ -1,192 +0,0 @@
1
- import React, {useContext} from 'react';
2
- import {StyleSheet, TouchableOpacity, View} from 'react-native';
3
- import {ApplicationContext, MiniAppContext} from '../index';
4
- import {Colors, Radius, Spacing, Styles} from '../../Consts';
5
- import {Text} from '../../Text';
6
- import {Icon} from '../../Icon';
7
-
8
- const ServiceItem: React.FC<any> = ({service}) => {
9
- const {theme, translate} = useContext(ApplicationContext);
10
- const {title, description, icon, onPress} = service;
11
- const serviceTitle = translate?.(title);
12
- const serviceDescription = translate?.(description);
13
-
14
- return (
15
- <TouchableOpacity onPress={onPress} style={Styles.row}>
16
- <View style={styles.iconWrapper}>
17
- <Icon color={theme.colors.text.hint} source={icon} size={28} />
18
- </View>
19
- <View>
20
- <View style={Styles.row}>
21
- <Text typography={'action_xs_bold'}>{serviceTitle}</Text>
22
- <Icon source={'arrow_chevron_right_small'} size={16} />
23
- </View>
24
- <Text
25
- typography={'description_xs_regular'}
26
- color={theme.colors.text.hint}>
27
- {serviceDescription}
28
- </Text>
29
- </View>
30
- </TouchableOpacity>
31
- );
32
- };
33
-
34
- const BottomSheetHelpCenter: React.FC<any> = ({onRequestClose}) => {
35
- const {theme, navigator} = useContext(ApplicationContext);
36
- const context = useContext<any>(MiniAppContext);
37
-
38
- const onPressFaq = () => {
39
- const routes = navigator?.ref.current?.getRootState()?.routes || [];
40
- const routesLength = routes.length;
41
- let screenName = routes?.[0]?.params?.screen?.name;
42
- if (routesLength > 1) {
43
- screenName = routes[routesLength - 2]?.params?.screen?.name;
44
- }
45
-
46
- context?.autoTracking?.({
47
- ...context,
48
- componentName: 'TouchableOpacity',
49
- componentId: 'bottomsheet_faq_item',
50
- screenName: screenName,
51
- });
52
-
53
- onRequestClose?.(() => {
54
- navigator?.maxApi?.startFeatureCode?.(
55
- 'helpcenter_problemlevel1',
56
- context?.toolkitConfig?.faq
57
- );
58
- });
59
- };
60
-
61
- const onPressChatbot = () => {
62
- const routes = navigator?.ref.current?.getRootState()?.routes || [];
63
- const routesLength = routes.length;
64
- let screenName = routes?.[0]?.params?.screen?.name;
65
- if (routesLength > 1) {
66
- screenName = routes[routesLength - 2]?.params?.screen?.name;
67
- }
68
-
69
- context?.autoTracking?.({
70
- ...context,
71
- componentName: 'TouchableOpacity',
72
- componentId: 'bottomsheet_chatbot_item',
73
- screenName: screenName,
74
- });
75
-
76
- onRequestClose?.(() => {
77
- navigator?.maxApi?.getDataObserver('CURRENT_SCREEN', (data: any) => {
78
- let screenName = data?.screenName;
79
- navigator?.maxApi?.startFeatureCode?.('chatbot', {
80
- botId: 'botGptCs',
81
- forwardParams: {
82
- forService: 'navigation',
83
- mini_app_id: context?.appId,
84
- feature_code: context?.code,
85
- screen_name: screenName,
86
- },
87
- });
88
- });
89
- });
90
- };
91
-
92
- const onPressFeedback = () => {
93
- const routes = navigator?.ref.current?.getRootState()?.routes || [];
94
- const routesLength = routes.length;
95
- let screenName = routes?.[0]?.params?.screen?.name;
96
- if (routesLength > 1) {
97
- screenName = routes[routesLength - 2]?.params?.screen?.name;
98
- }
99
-
100
- context?.autoTracking?.({
101
- ...context,
102
- componentName: 'TouchableOpacity',
103
- componentId: 'bottomsheet_feedback_item',
104
- screenName: screenName,
105
- });
106
-
107
- onRequestClose?.(() => {
108
- navigator?.maxApi?.startFeatureCode?.('feedback', {
109
- forService: 'navigation',
110
- loggedStatus: true,
111
- application: {
112
- appId: context?.appId,
113
- appCode: context?.code,
114
- appName: context?.name?.['en'],
115
- buildNumber: context?.buildNumber,
116
- },
117
- newUi: true,
118
- stepFeedback: 1,
119
- });
120
- });
121
- };
122
-
123
- const services = [
124
- {
125
- title: {vi: 'Câu hỏi thường gặp', en: 'Câu hỏi thường gặp'},
126
- description: {
127
- vi: 'Giải đáp các thắc mắc mọi người thường gặp',
128
- en: 'Giải đáp các thắc mắc mọi người thường gặp',
129
- },
130
- icon: 'notifications_circle_question',
131
- onPress: onPressFaq,
132
- },
133
- {
134
- title: {vi: 'Hỗ trợ trực tuyến', en: 'Hỗ trợ trực tuyến'},
135
- description: {
136
- vi: 'Trả lời mọi câu hỏi của bạn 24/7',
137
- en: 'Trả lời mọi câu hỏi của bạn 24/7',
138
- },
139
- icon: 'ic_support',
140
- onPress: onPressChatbot,
141
- },
142
- {
143
- title: {vi: 'Chia sẻ góp ý', en: 'Chia sẻ góp ý'},
144
- description: {
145
- vi: 'Đề xuất cải thiện hoặc báo lỗi sản phẩm/dịch vụ',
146
- en: 'Đề xuất cải thiện hoặc báo lỗi sản phẩm/dịch vụ',
147
- },
148
- icon: 'file_mail',
149
- onPress: onPressFeedback,
150
- },
151
- ];
152
-
153
- return (
154
- <View
155
- style={[
156
- styles.container,
157
- {
158
- backgroundColor: theme.colors.background.surface,
159
- },
160
- ]}>
161
- {services.map((item, index) => {
162
- return (
163
- <>
164
- <ServiceItem service={item} />
165
- {index !== services.length - 1 && <View style={styles.divider} />}
166
- </>
167
- );
168
- })}
169
- </View>
170
- );
171
- };
172
-
173
- const styles = StyleSheet.create({
174
- container: {height: 300, width: '100%', padding: Spacing.M},
175
- divider: {
176
- marginVertical: Spacing.M,
177
- backgroundColor: Colors.black_02,
178
- height: 1,
179
- width: '100%',
180
- },
181
- iconWrapper: {
182
- width: 36,
183
- height: 36,
184
- backgroundColor: Colors.black_02,
185
- borderRadius: Radius.M,
186
- marginRight: Spacing.S,
187
- alignItems: 'center',
188
- justifyContent: 'center',
189
- },
190
- });
191
-
192
- export {BottomSheetHelpCenter};