@momo-kits/foundation 0.92.1-tracking.9 → 0.92.2-tracking.2

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.
@@ -1,13 +1,14 @@
1
1
  import React, {useContext, useEffect, useLayoutEffect, useRef} from 'react';
2
2
  import {ScreenParams} from './types';
3
3
  import Navigation from './Navigation';
4
- import {ApplicationContext, MiniAppContext} from './index';
4
+ import {ApplicationContext} from './index';
5
5
  import {GridSystem} from '../Layout';
6
6
  import {useHeaderHeight} from '@react-navigation/stack';
7
7
  import {Alert, InteractionManager} from 'react-native';
8
8
 
9
9
  const {
10
10
  ScreenContext,
11
+ MiniAppContext,
11
12
  } = require('react-native/Libraries/Components/ScreenContext');
12
13
 
13
14
  const StackScreen: React.FC<ScreenParams> = props => {
@@ -15,15 +16,18 @@ const StackScreen: React.FC<ScreenParams> = props => {
15
16
  const startTime = useRef(Date.now());
16
17
  const endTime = useRef(Date.now());
17
18
  const timeLoad = useRef(0);
18
- const timeout = useRef<any>();
19
+ const timeInteraction = useRef(0);
20
+ const timeoutLoad = useRef<any>();
21
+ const tracked = useRef<any>({
22
+ releaseLoad: undefined,
23
+ releaseInteraction: undefined,
24
+ timeoutLoad: undefined,
25
+ timeoutInteraction: undefined,
26
+ });
27
+ const interaction = useRef<any>();
28
+ const context = useContext<any>(MiniAppContext);
19
29
 
20
- const context = useContext(MiniAppContext);
21
-
22
- const {
23
- screen: Component,
24
- options,
25
- initialParams,
26
- }: ScreenParams = props.route.params;
30
+ const {screen: Component, options, initialParams} = props.route.params;
27
31
  const navigation = new Navigation(props.navigation, theme);
28
32
  const heightHeader = useHeaderHeight();
29
33
 
@@ -36,18 +40,12 @@ const StackScreen: React.FC<ScreenParams> = props => {
36
40
  delete data.screen;
37
41
  delete data.initialParams;
38
42
 
43
+ const screenName = Component?.name || Component?.type?.name || 'Invalid';
44
+
39
45
  /**
40
46
  * set options for screen
41
47
  */
42
48
  useLayoutEffect(() => {
43
- InteractionManager.runAfterInteractions(() => {
44
- navigator?.maxApi?.showToastDebug?.({
45
- appId: context.appId,
46
- message: `${Component.name} screen_interaction_time ${
47
- Date.now() - startTime.current
48
- }`,
49
- });
50
- });
51
49
  if (options) {
52
50
  navigation.setOptions(options);
53
51
  }
@@ -57,81 +55,93 @@ const StackScreen: React.FC<ScreenParams> = props => {
57
55
  * tracking for screen
58
56
  */
59
57
  useEffect(() => {
60
- if (__DEV__) {
61
- if (!Component.name || Component.name === 'screen') {
62
- Alert.alert(
63
- 'Design system',
64
- `Unvalidated screen name "${Component.name}" !`,
65
- );
66
- }
58
+ if (__DEV__ && (!screenName || screenName == 'Invalid')) {
59
+ Alert.alert('Design system', `Unvalidated screen name "${screenName}" !`);
67
60
  }
68
61
 
69
- const tracking = {
70
- ...context,
71
- screen_name: Component.name,
62
+ tracked.current.timeoutLoad = setTimeout(() => {
63
+ onScreenLoad();
64
+ }, 5000);
65
+ tracked.current.timeoutInteraction = setTimeout(() => {
66
+ onScreenInteraction();
67
+ }, 5000);
68
+ return () => {
69
+ onScreenLoad();
70
+ onScreenInteraction();
72
71
  };
72
+ }, []);
73
73
 
74
- const routes = props.navigation.getState()?.routes || [];
75
- const routesLength = routes.length;
76
- let pre_screen_name = '';
77
- if (routesLength > 1) {
78
- pre_screen_name = routes[routesLength - 2]?.params?.screen?.name;
74
+ /**
75
+ * tracking for screen load
76
+ */
77
+ const onScreenLoad = () => {
78
+ clearTimeout(tracked.current.timeoutLoad);
79
+ if (!tracked.current?.releaseLoad) {
80
+ navigator?.maxApi?.dispatchFunction?.('autoTracking', {
81
+ appId: context.appId,
82
+ code: context.code,
83
+ screenName,
84
+ componentName: 'Screen',
85
+ state: 'load',
86
+ time: timeLoad.current,
87
+ });
88
+ navigator?.maxApi?.showToastDebug?.({
89
+ appId: `auto - ${context.appId}`,
90
+ message: `${screenName} screen_load_time ${timeLoad.current}`,
91
+ });
92
+ tracked.current.releaseLoad = true;
79
93
  }
94
+ };
80
95
 
81
- const params = {
82
- ...tracking,
83
- pre_screen_name,
84
- trigger_id: '111378000000000000',
85
- };
86
- navigator?.maxApi?.trackEvent?.('service_frame_displayed', params);
87
- navigator?.maxApi?.showToastDebug?.({
88
- appId: context.appId,
89
- message: `${Component.name} service_frame_displayed`,
90
- params,
91
- });
96
+ /**
97
+ * tracking for screen load
98
+ */
99
+ const onScreenInteraction = () => {
100
+ clearTimeout(tracked.current.timeoutInteraction);
101
+ if (!tracked.current?.releaseInteraction) {
102
+ navigator?.maxApi?.dispatchFunction?.('autoTracking', {
103
+ appId: context.appId,
104
+ code: context.code,
105
+ screenName,
106
+ componentName: 'Screen',
107
+ state: 'interaction',
108
+ time: timeInteraction.current,
109
+ });
92
110
 
93
- return props.navigation.addListener('beforeRemove', () => {
94
- const params = {
95
- ...tracking,
96
- trigger_id: '111154000000000000',
97
- icon_name: 'back',
98
- };
99
- navigator?.maxApi?.trackEvent?.('service_icon_clicked', params);
100
111
  navigator?.maxApi?.showToastDebug?.({
101
- appId: context.appId,
102
- message: `${Component.name} service_icon_clicked`,
103
- params,
112
+ appId: `auto - ${context.appId}`,
113
+ message: `${screenName} screen_interaction_time ${timeInteraction.current}`,
104
114
  });
105
- });
106
- }, []);
115
+ tracked.current.releaseInteraction = true;
116
+ }
117
+ };
107
118
 
108
119
  return (
109
120
  <ScreenContext.Provider
110
121
  value={{
111
- appId: context.appId,
112
- code: context.code,
113
- screenName: Component.name,
122
+ screenName,
114
123
  autoTracking: (data: any) => {
115
124
  navigator?.maxApi?.dispatchFunction?.('autoTracking', data);
116
125
  },
117
126
  onElementLoad: () => {
118
127
  endTime.current = Date.now();
119
- clearTimeout(timeout.current);
120
- timeout.current = setTimeout(() => {
128
+ interaction.current?.cancel?.();
129
+ interaction.current = InteractionManager.runAfterInteractions(() => {
130
+ timeInteraction.current = Date.now() - startTime.current;
131
+ });
132
+ clearTimeout(timeoutLoad.current);
133
+ timeoutLoad.current = setTimeout(() => {
121
134
  if (timeLoad.current === 0) {
122
135
  timeLoad.current = endTime.current - startTime.current;
123
- navigator?.maxApi?.showToastDebug?.({
124
- appId: context.appId,
125
- message: `${Component.name} screen_load_time ${timeLoad.current}`,
126
- });
127
136
  }
128
- }, 1000);
137
+ }, 2000);
129
138
  },
130
139
  }}>
131
140
  <Component
132
141
  heightHeader={heightHeader}
133
142
  {...data}
134
- onScreenLoad={() => {}}
143
+ onScreenLoad={onScreenLoad}
144
+ onScreenInteraction={onScreenInteraction}
135
145
  />
136
146
  {showGrid && <GridSystem />}
137
147
  </ScreenContext.Provider>
@@ -1,9 +1,9 @@
1
- import {Animated, ViewProps} from 'react-native';
2
1
  import {StackNavigationOptions} from '@react-navigation/stack';
3
2
  import React from 'react';
4
- import Navigator from './Navigator';
3
+ import {Animated, FlatListProps, ViewProps} from 'react-native';
5
4
  import {PopupNotifyProps} from '../Popup/types';
6
5
  import Navigation from './Navigation';
6
+ import Navigator from './Navigator';
7
7
 
8
8
  type Screen = React.ComponentType<NavigationScreenProps>;
9
9
 
@@ -94,8 +94,8 @@ export type NavigationContainerProps = {
94
94
  options?: NavigationOptions;
95
95
  theme: Theme;
96
96
  maxApi: any;
97
- initialParams: Record<string, any>;
98
97
  localization?: LocalizationObject;
98
+ initialParams?: any;
99
99
  };
100
100
 
101
101
  export type NavigationScreenProps = {
@@ -119,8 +119,8 @@ export interface ModalParams extends ScreenParams {
119
119
  export interface BottomSheetParams extends ScreenParams {
120
120
  [key: string]: any;
121
121
  onDismiss?: () => void;
122
- snapPoint?: '30%' | '50%' | '70%' | '90%' | 'content';
123
- indicatorColor?: string;
122
+ footerComponent?: React.ReactNode;
123
+ flatListProps: FlatListProps<any>;
124
124
  }
125
125
 
126
126
  export type NavigationButtonProps = {
@@ -189,7 +189,6 @@ export type HeaderToolkitProps = {
189
189
  export interface HeaderAnimatedProps extends ViewProps {
190
190
  animatedValue: Animated.Value;
191
191
  image: string;
192
- onPress?: () => void;
193
192
  }
194
193
 
195
194
  export type BottomTabItemProps = {
@@ -211,6 +210,14 @@ export type BottomTabProps = {
211
210
  tabPress?: any;
212
211
  focus?: any;
213
212
  };
213
+ floatingButton?: FloatingButtonProps;
214
+ };
215
+
216
+ export type FloatingButtonProps = {
217
+ container?: React.ReactNode;
218
+ icon: string | React.ReactNode;
219
+ label: string;
220
+ onPress: () => void;
214
221
  };
215
222
 
216
223
  export type AnimatedHeader = {
@@ -142,19 +142,29 @@ const getOptions = (params: NavigationOptions, theme: Theme) => {
142
142
  };
143
143
  };
144
144
 
145
- const getAccessibilityID = (key = '') => {
145
+ const getAccessibilityID = (
146
+ key = '',
147
+ override: string | undefined = undefined,
148
+ ) => {
146
149
  if (isIOS) {
147
150
  return {
148
151
  accessible: true,
149
- testID: key,
152
+ testID: override || key,
150
153
  };
151
154
  } else {
152
155
  return {
153
- accessibilityLabel: key,
156
+ accessibilityLabel: override || key,
154
157
  };
155
158
  }
156
159
  };
157
160
 
161
+ const cleanNameForTracking = (word = ''): string => {
162
+ return word
163
+ .normalize('NFD')
164
+ .replace(/[\u0300-\u036f |\s]/g, '')
165
+ .toLowerCase();
166
+ };
167
+
158
168
  const formatComponentName = (word = '') => {
159
169
  const accentsMap = {
160
170
  a: 'á|à|ả|ã|ạ|â|ấ|ầ|ẩ|ẫ|ậ|ă|ắ|ằ|ẳ|ẵ|ặ',
@@ -198,4 +208,5 @@ export {
198
208
  formatComponentName,
199
209
  formatNameLength,
200
210
  getAccessibilityID,
211
+ cleanNameForTracking,
201
212
  };
package/Badge/Badge.tsx CHANGED
@@ -46,7 +46,7 @@ const Badge: FC<BadgeProps> = ({label = 'Label', style, backgroundColor}) => {
46
46
 
47
47
  return (
48
48
  <View style={[style, styles.badge, {backgroundColor: badgeColor}]}>
49
- <Text color={Colors.black_01} typography={'action_xs_bold'}>
49
+ <Text color={Colors.black_01} typography={'action_xxs_bold'}>
50
50
  {formatTitle()}
51
51
  </Text>
52
52
  </View>
package/Button/index.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import React, {FC, useContext} from 'react';
1
+ import React, {FC, useContext, useState} from 'react';
2
2
  import {
3
3
  Animated,
4
4
  StyleSheet,
@@ -7,17 +7,17 @@ import {
7
7
  View,
8
8
  } from 'react-native';
9
9
  import LinearGradient from 'react-native-linear-gradient';
10
- import {ApplicationContext, MiniAppContext} from '../Application';
10
+ import {ApplicationContext} from '../Application';
11
11
  import {Text} from '../Text';
12
12
  import {Typography} from '../Text/types';
13
13
  import {Colors, Spacing} from '../Consts';
14
14
  import styles from './styles';
15
15
  import {Icon} from '../Icon';
16
16
  import {Loader} from '../Loader';
17
- import {formatComponentName, getAccessibilityID} from '../Application/utils';
17
+ import {formatComponentName} from '../Application/utils';
18
18
 
19
19
  const {
20
- ScreenContext,
20
+ ComponentContext,
21
21
  } = require('react-native/Libraries/Components/ScreenContext');
22
22
 
23
23
  const AnimationLinear = Animated.createAnimatedComponent(LinearGradient);
@@ -76,10 +76,6 @@ export interface ButtonProps extends TouchableOpacityProps {
76
76
  onPress: () => void;
77
77
 
78
78
  params?: any;
79
-
80
- componentId?: string;
81
-
82
- accessibilityID?: object
83
79
  }
84
80
 
85
81
  const Button: FC<ButtonProps> = ({
@@ -93,15 +89,16 @@ const Button: FC<ButtonProps> = ({
93
89
  title = 'Button',
94
90
  onPress,
95
91
  params,
96
- componentId,
97
92
  accessibilityLabel,
98
- accessibilityID,
99
93
  ...rest
100
94
  }) => {
101
95
  const {theme, config} = useContext(ApplicationContext);
102
- const {appId, code} = useContext(MiniAppContext)
103
96
  const {gradient, color} = config?.navigationBar?.buttonColors ?? {};
104
97
  let gradientPros;
98
+ let state = 'enabled';
99
+ if (loading) {
100
+ state = 'loading';
101
+ }
105
102
  if (gradient?.length > 0 && type == 'primary') {
106
103
  gradientPros = {
107
104
  colors: gradient,
@@ -110,7 +107,6 @@ const Button: FC<ButtonProps> = ({
110
107
  };
111
108
  }
112
109
 
113
- const screenInfo = useContext<any>(ScreenContext);
114
110
  const getSizeStyle = () => {
115
111
  const styleSheet: {[key: string]: any} = styles;
116
112
  return styleSheet[size ?? 'small'];
@@ -306,25 +302,20 @@ const Button: FC<ButtonProps> = ({
306
302
  };
307
303
 
308
304
  const activeOpacity = type === 'disabled' ? 0.75 : 0.5;
309
- const selfAccessibilityID = accessibilityID ? accessibilityID : getAccessibilityID?.(`${appId}/${code}/${screenInfo.screenName}/btn_${title}`)
305
+
310
306
  return (
311
- <ScreenContext.Provider
307
+ <ComponentContext.Provider
312
308
  value={{
313
- ...screenInfo,
314
309
  componentName: 'Button',
315
310
  params,
316
- state: loading
317
- ? 'loading'
318
- : type === 'disabled'
319
- ? 'disabled'
320
- : 'enabled',
321
- componentId,
311
+ state: state,
312
+ componentId: accessibilityLabel,
322
313
  componentValue: formatComponentName(title),
323
314
  action: 'click',
324
315
  }}>
325
316
  <TouchableOpacity
326
317
  {...rest}
327
- {...selfAccessibilityID}
318
+ accessibilityLabel={accessibilityLabel}
328
319
  activeOpacity={activeOpacity}
329
320
  onPress={onPressButton}
330
321
  style={buttonStyle}>
@@ -336,7 +327,7 @@ const Button: FC<ButtonProps> = ({
336
327
  )}
337
328
  {gradientPros && <View style={styles.strokeView} />}
338
329
  </TouchableOpacity>
339
- </ScreenContext.Provider>
330
+ </ComponentContext.Provider>
340
331
  );
341
332
  };
342
333
 
@@ -2,28 +2,26 @@ import React, {FC, useContext} from 'react';
2
2
  import {TouchableOpacity, View} from 'react-native';
3
3
  import {CheckBoxProps} from './types';
4
4
  import styles from './styles';
5
- import {ApplicationContext, MiniAppContext} from '../Application';
5
+ import {ApplicationContext} from '../Application';
6
6
  import {Text} from '../Text';
7
7
  import {Icon} from '../Icon';
8
- import {formatNameLength, getAccessibilityID} from '../Application/utils';
8
+ import {formatNameLength} from '../Application/utils';
9
9
 
10
10
  const {
11
- ScreenContext,
11
+ ComponentContext,
12
12
  } = require('react-native/Libraries/Components/ScreenContext');
13
13
 
14
14
  const CheckBox: FC<CheckBoxProps> = ({
15
15
  value,
16
- disabled,
16
+ disabled = false,
17
17
  onChange,
18
18
  style,
19
19
  label,
20
20
  indeterminate,
21
21
  params,
22
- componentId,
22
+ accessibilityLabel,
23
23
  }) => {
24
- const {appId} = useContext(MiniAppContext)
25
24
  const {theme} = useContext(ApplicationContext);
26
- const screenInfo = useContext<any>(ScreenContext);
27
25
  const haveValue = value || indeterminate;
28
26
  const iconSource = indeterminate ? 'ic_minus' : 'ic_checked';
29
27
  let borderColor = theme.colors.text.default;
@@ -42,22 +40,20 @@ const CheckBox: FC<CheckBoxProps> = ({
42
40
  backgroundColor = theme.colors.background.tonal;
43
41
  }
44
42
  }
45
- const accessibilityID = getAccessibilityID?.(`${appId}/${screenInfo.screenName}/cbx_${label}_${value}`)
46
43
 
47
44
  return (
48
- <ScreenContext.Provider
45
+ <ComponentContext.Provider
49
46
  value={{
50
- ...screenInfo,
51
- componentName: 'Button',
47
+ componentName: 'CheckBox',
52
48
  params,
53
49
  state: disabled ? 'disabled' : 'filled',
54
- componentId,
50
+ componentId: accessibilityLabel,
55
51
  action: 'click',
56
52
  componentLabel: formatNameLength(label || ''),
57
53
  componentValue: indeterminate ? 'indetermine' : value,
58
54
  }}>
59
55
  <TouchableOpacity
60
- {...accessibilityID}
56
+ accessibilityLabel={accessibilityLabel}
61
57
  activeOpacity={0.8}
62
58
  onPress={() => onChange?.(!value)}
63
59
  disabled={disabled}
@@ -77,12 +73,8 @@ const CheckBox: FC<CheckBoxProps> = ({
77
73
  </View>
78
74
  {!!label && <Text typography={'body_default_regular'}>{label}</Text>}
79
75
  </TouchableOpacity>
80
- </ScreenContext.Provider>
76
+ </ComponentContext.Provider>
81
77
  );
82
78
  };
83
79
 
84
- CheckBox.defaultProps = {
85
- disabled: false,
86
- };
87
-
88
80
  export {CheckBox};
package/CheckBox/types.ts CHANGED
@@ -1,6 +1,6 @@
1
- import {ViewStyle} from 'react-native';
1
+ import {TouchableOpacityProps, ViewStyle} from 'react-native';
2
2
 
3
- export type CheckBoxProps = {
3
+ export interface CheckBoxProps extends TouchableOpacityProps {
4
4
  /**
5
5
  * Represents whether the CheckBox is currently checked (`true`) or unchecked (`false`).
6
6
  */
@@ -36,7 +36,5 @@ export type CheckBoxProps = {
36
36
  */
37
37
  style?: ViewStyle;
38
38
 
39
- params?: any
40
-
41
- componentId?: string
42
- };
39
+ params?: any;
40
+ }
@@ -213,6 +213,20 @@ const Shadow = {
213
213
  elevation: 6,
214
214
  },
215
215
  }),
216
+
217
+ Pink: Platform.select({
218
+ ios: {
219
+ shadowColor: '#e27eb5',
220
+ shadowOffset: {width: 0, height: 6},
221
+ shadowOpacity: 0.25,
222
+ shadowRadius: 8,
223
+ },
224
+ android: {
225
+ elevation: 16,
226
+ shadowColor: '#e27eb5',
227
+ shadowOpacity: 0.25,
228
+ },
229
+ }),
216
230
  };
217
231
 
218
232
  export {Colors, Spacing, Radius, Shadow};
package/Icon/index.tsx CHANGED
@@ -5,7 +5,12 @@ import {IconProps} from './types';
5
5
  import {ApplicationContext} from '../Application';
6
6
  import {Image} from '../Image';
7
7
 
8
- const Icon: React.FC<IconProps> = ({source, size, color, style = {}}) => {
8
+ const Icon: React.FC<IconProps> = ({
9
+ source = 'ic_back',
10
+ size = 24,
11
+ color,
12
+ style = {},
13
+ }) => {
9
14
  const {theme} = useContext(ApplicationContext);
10
15
 
11
16
  /**
@@ -20,8 +25,8 @@ const Icon: React.FC<IconProps> = ({source, size, color, style = {}}) => {
20
25
  };
21
26
 
22
27
  const tintColorProps = color !== null && {
23
- tintColor: color ?? theme.colors.text.default
24
- }
28
+ tintColor: color ?? theme.colors.text.default,
29
+ };
25
30
 
26
31
  return (
27
32
  <Image
@@ -33,9 +38,4 @@ const Icon: React.FC<IconProps> = ({source, size, color, style = {}}) => {
33
38
  );
34
39
  };
35
40
 
36
- Icon.defaultProps = {
37
- source: 'ic_back',
38
- size: 24,
39
- };
40
-
41
41
  export {Icon, IconSources, IconBankSources};
@@ -12,7 +12,7 @@ import styles from './styles';
12
12
  import {formatComponentName} from '../Application/utils';
13
13
 
14
14
  const {
15
- ScreenContext,
15
+ ComponentContext,
16
16
  } = require('react-native/Libraries/Components/ScreenContext');
17
17
 
18
18
  export interface IconButtonProps extends TouchableOpacityProps {
@@ -33,21 +33,18 @@ export interface IconButtonProps extends TouchableOpacityProps {
33
33
  size?: 'large' | 'small';
34
34
 
35
35
  params?: any;
36
-
37
- componentId?: string;
38
36
  }
39
37
 
40
38
  const IconButton: React.FC<IconButtonProps> = ({
41
- type,
39
+ type = 'primary',
42
40
  icon,
43
41
  size,
44
42
  onPress,
45
43
  params,
46
- componentId,
44
+ accessibilityLabel,
47
45
  ...rest
48
46
  }) => {
49
47
  const {theme} = useContext(ApplicationContext);
50
- const screenInfo = useContext<any>(ScreenContext);
51
48
 
52
49
  /**
53
50
  * get size icon button
@@ -133,30 +130,25 @@ const IconButton: React.FC<IconButtonProps> = ({
133
130
  const iconSize = size === 'small' ? 16 : 24;
134
131
 
135
132
  return (
136
- <ScreenContext.Provider
133
+ <ComponentContext.Provider
137
134
  value={{
138
- ...screenInfo,
139
135
  componentName: 'IconButton',
140
136
  params,
141
137
  state: type === 'disabled' ? 'disabled' : 'enabled',
142
- componentId,
138
+ componentId: accessibilityLabel,
143
139
  componentValue: formatComponentName(icon),
144
140
  action: 'click',
145
141
  }}>
146
142
  <TouchableOpacity
147
143
  {...rest}
144
+ accessibilityLabel={accessibilityLabel}
148
145
  activeOpacity={activeOpacity}
149
146
  onPress={onPressButton}
150
147
  style={buttonStyle}>
151
148
  <Icon size={iconSize} source={icon} color={getIconColor()} />
152
149
  </TouchableOpacity>
153
- </ScreenContext.Provider>
150
+ </ComponentContext.Provider>
154
151
  );
155
152
  };
156
153
 
157
- IconButton.defaultProps = {
158
- type: 'primary',
159
- disabled: false,
160
- };
161
-
162
154
  export {IconButton};