@eohjsc/react-native-smart-city 0.3.72 → 0.3.74

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 (28) hide show
  1. package/package.json +1 -1
  2. package/src/Images/ThreeButton/buttonCircleBig.png +0 -0
  3. package/src/Images/ThreeButton/buttonCircleSmall.png +0 -0
  4. package/src/commons/ActionGroup/ThreeButtonTemplate/__test__/ThreeButtonCircle.test.js +52 -0
  5. package/src/commons/ActionGroup/ThreeButtonTemplate/__test__/ThreeButtonDefault.test.js +52 -0
  6. package/src/commons/ActionGroup/{__test__ → ThreeButtonTemplate/__test__}/ThreeButtonTemplate.test.js +21 -8
  7. package/src/commons/ActionGroup/ThreeButtonTemplate/components/ThreeButtonCircle.js +103 -0
  8. package/src/commons/ActionGroup/ThreeButtonTemplate/components/ThreeButtonCircleStyles.js +31 -0
  9. package/src/commons/ActionGroup/ThreeButtonTemplate/components/ThreeButtonDefault.js +96 -0
  10. package/src/commons/ActionGroup/{ThreeButtonTemplateStyle.js → ThreeButtonTemplate/components/ThreeButtonDefaultStyles.js} +11 -34
  11. package/src/commons/ActionGroup/{ThreeButtonTemplate.js → ThreeButtonTemplate/index.js} +48 -51
  12. package/src/commons/ActionGroup/ThreeButtonTemplate/styles.js +27 -0
  13. package/src/commons/Device/HorizontalBarChart.js +1 -1
  14. package/src/configs/SCConfig.js +3 -0
  15. package/src/hooks/IoT/useBluetoothConnection.js +2 -1
  16. package/src/screens/AddLocationMaps/index.js +1 -1
  17. package/src/screens/AddNewGateway/ConnectingWifiGuide.js +4 -1
  18. package/src/screens/AllGateway/DetailConfigActionModbus/index.js +6 -4
  19. package/src/screens/AllGateway/GatewayConnectionMethods/__test__/index.test.js +4 -1
  20. package/src/screens/AllGateway/GatewayConnectionMethods/index.js +4 -2
  21. package/src/screens/AllGateway/GatewayInfo/__test__/index.test.js +2 -1
  22. package/src/screens/AllGateway/components/Information/__test__/index.test.js +2 -1
  23. package/src/screens/AllGateway/components/Information/index.js +4 -2
  24. package/src/screens/GuestInfo/index.js +2 -2
  25. package/src/screens/Sharing/InfoMemberUnit.js +2 -2
  26. package/src/screens/Unit/SelectAddress.js +1 -1
  27. package/src/utils/I18n/translations/en.json +13 -12
  28. package/src/utils/I18n/translations/vi.json +12 -11
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@eohjsc/react-native-smart-city",
3
3
  "title": "React Native Smart Home",
4
- "version": "0.3.72",
4
+ "version": "0.3.74",
5
5
  "description": "TODO",
6
6
  "main": "index.js",
7
7
  "files": [
@@ -0,0 +1,52 @@
1
+ import React from 'react';
2
+ import renderer, { act } from 'react-test-renderer';
3
+ import { TouchableOpacity } from 'react-native';
4
+
5
+ import { SCProvider } from '../../../../context';
6
+ import { mockSCStore } from '../../../../context/mockStore';
7
+ import ThreeButtonCircle from '../components/ThreeButtonCircle';
8
+
9
+ const mockOnButton1Press = jest.fn();
10
+ const mockOnButton2Press = jest.fn();
11
+ const mockOnButton3Press = jest.fn();
12
+
13
+ const wrapComponent = (props) => (
14
+ <SCProvider initState={mockSCStore({})}>
15
+ <ThreeButtonCircle {...props} />
16
+ </SCProvider>
17
+ );
18
+
19
+ describe('Test ThreeButtonCircle', () => {
20
+ let props = {
21
+ icon1: 'icon1',
22
+ text1: 'text1',
23
+ icon2: 'icon2',
24
+ text2: 'text2',
25
+ icon3: 'icon3',
26
+ text3: 'text3',
27
+ onButton1Press: mockOnButton1Press,
28
+ onButton2Press: mockOnButton2Press,
29
+ onButton3Press: mockOnButton3Press,
30
+ };
31
+ let wrapper;
32
+
33
+ it('render ThreeButtonCircle', async () => {
34
+ await act(async () => {
35
+ wrapper = renderer.create(wrapComponent(props));
36
+ });
37
+ const instance = wrapper.root;
38
+ const touchableOpacities = instance.findAllByType(TouchableOpacity);
39
+ expect(touchableOpacities).toHaveLength(3);
40
+ });
41
+ it('render ThreeButtonCircle onPressButton', async () => {
42
+ await act(async () => {
43
+ wrapper = renderer.create(wrapComponent(props));
44
+ });
45
+ const instance = wrapper.root;
46
+ const touchableOpacities = instance.findAllByType(TouchableOpacity);
47
+ await act(async () => {
48
+ touchableOpacities[0].props.onPress();
49
+ });
50
+ expect(mockOnButton1Press).toBeCalled();
51
+ });
52
+ });
@@ -0,0 +1,52 @@
1
+ import React from 'react';
2
+ import renderer, { act } from 'react-test-renderer';
3
+ import { TouchableOpacity } from 'react-native';
4
+
5
+ import { SCProvider } from '../../../../context';
6
+ import { mockSCStore } from '../../../../context/mockStore';
7
+ import ThreeButtonDefault from '../components/ThreeButtonDefault';
8
+
9
+ const mockOnButton1Press = jest.fn();
10
+ const mockOnButton2Press = jest.fn();
11
+ const mockOnButton3Press = jest.fn();
12
+
13
+ const wrapComponent = (props) => (
14
+ <SCProvider initState={mockSCStore({})}>
15
+ <ThreeButtonDefault {...props} />
16
+ </SCProvider>
17
+ );
18
+
19
+ describe('Test ThreeButtonDefault', () => {
20
+ let props = {
21
+ icon1: 'icon1',
22
+ text1: 'text1',
23
+ icon2: 'icon2',
24
+ text2: 'text2',
25
+ icon3: 'icon3',
26
+ text3: 'text3',
27
+ onButton1Press: mockOnButton1Press,
28
+ onButton2Press: mockOnButton2Press,
29
+ onButton3Press: mockOnButton3Press,
30
+ };
31
+ let wrapper;
32
+
33
+ it('render ThreeButtonDefault', async () => {
34
+ await act(async () => {
35
+ wrapper = renderer.create(wrapComponent(props));
36
+ });
37
+ const instance = wrapper.root;
38
+ const touchableOpacities = instance.findAllByType(TouchableOpacity);
39
+ expect(touchableOpacities).toHaveLength(3);
40
+ });
41
+ it('render ThreeButtonDefault onPressButton', async () => {
42
+ await act(async () => {
43
+ wrapper = renderer.create(wrapComponent(props));
44
+ });
45
+ const instance = wrapper.root;
46
+ const touchableOpacities = instance.findAllByType(TouchableOpacity);
47
+ await act(async () => {
48
+ touchableOpacities[0].props.onPress();
49
+ });
50
+ expect(mockOnButton1Press).toBeCalled();
51
+ });
52
+ });
@@ -1,10 +1,11 @@
1
1
  import React from 'react';
2
2
  import renderer, { act } from 'react-test-renderer';
3
- import { TouchableOpacity } from 'react-native';
4
3
 
5
- import ThreeButtonTemplate from '../ThreeButtonTemplate';
6
- import { SCProvider } from '../../../context';
7
- import { mockSCStore } from '../../../context/mockStore';
4
+ import ThreeButtonTemplate from '..';
5
+ import { SCProvider } from '../../../../context';
6
+ import { mockSCStore } from '../../../../context/mockStore';
7
+ import ThreeButtonDefault from '../components/ThreeButtonDefault';
8
+ import ThreeButtonCircle from '../components/ThreeButtonCircle';
8
9
 
9
10
  const wrapComponent = (actionGroup) => (
10
11
  <SCProvider initState={mockSCStore({})}>
@@ -13,7 +14,7 @@ const wrapComponent = (actionGroup) => (
13
14
  );
14
15
 
15
16
  describe('Test ThreeButtonTemplate', () => {
16
- const actionGroup = {
17
+ let actionGroup = {
17
18
  configuration: {
18
19
  action1: '2b949045-8e03-4c07-a855-7794ade2e69c',
19
20
  action1_data: {
@@ -61,12 +62,24 @@ describe('Test ThreeButtonTemplate', () => {
61
62
 
62
63
  let wrapper;
63
64
 
64
- it('render ThreeButtonTemplate', async () => {
65
+ it('render ThreeButtonDefault', async () => {
65
66
  await act(async () => {
66
67
  wrapper = renderer.create(wrapComponent(actionGroup));
67
68
  });
68
69
  const instance = wrapper.root;
69
- const touchableOpacities = instance.findAllByType(TouchableOpacity);
70
- expect(touchableOpacities.length).toEqual(3);
70
+ const ThreeButtonDefaults = instance.findAllByType(ThreeButtonDefault);
71
+ expect(ThreeButtonDefaults).toHaveLength(1);
72
+ });
73
+ it('render ThreeButtonCircle', async () => {
74
+ const actionGroupCT = {
75
+ ...actionGroup,
76
+ configuration: { ...actionGroup?.configuration, layout: 'circle' },
77
+ };
78
+ await act(async () => {
79
+ wrapper = renderer.create(wrapComponent(actionGroupCT));
80
+ });
81
+ const instance = wrapper.root;
82
+ const ThreeButtonCircles = instance.findAllByType(ThreeButtonCircle);
83
+ expect(ThreeButtonCircles).toHaveLength(1);
71
84
  });
72
85
  });
@@ -0,0 +1,103 @@
1
+ import React, { memo, useMemo } from 'react';
2
+ import { TouchableOpacity, View } from 'react-native';
3
+ import styles from './ThreeButtonCircleStyles';
4
+ import Text from '../../../Text';
5
+ import { AccessibilityLabel } from '../../../../configs/Constants';
6
+ import IconComponent from '../../../IconComponent';
7
+ import buttonCircleSmall from '../../../../Images/ThreeButton/buttonCircleSmall.png';
8
+ import buttonCircleBig from '../../../../Images/ThreeButton/buttonCircleBig.png';
9
+ import FImage from '../../../FImage';
10
+
11
+ const ThreeButtonCircle = memo(
12
+ ({
13
+ icon1,
14
+ text1,
15
+ icon2,
16
+ text2,
17
+ icon3,
18
+ text3,
19
+ onButton1Press,
20
+ onButton2Press,
21
+ onButton3Press,
22
+ }) => {
23
+ const listButton = useMemo(() => {
24
+ return [
25
+ {
26
+ id: 1,
27
+ button: {
28
+ accessibilityLabel: AccessibilityLabel.BUTTON_CIRCLE_TEMPLATE_1,
29
+ onPress: onButton1Press,
30
+ },
31
+ fimage: {
32
+ source: buttonCircleSmall,
33
+ style: styles.iconSmall,
34
+ text: text1,
35
+ icon: icon1,
36
+ },
37
+ },
38
+ {
39
+ id: 2,
40
+ button: {
41
+ accessibilityLabel: AccessibilityLabel.BUTTON_CIRCLE_TEMPLATE_2,
42
+ onPress: onButton2Press,
43
+ },
44
+ fimage: {
45
+ source: buttonCircleBig,
46
+ style: styles.iconBig,
47
+ text: text2,
48
+ icon: icon2,
49
+ },
50
+ },
51
+ {
52
+ id: 3,
53
+ button: {
54
+ accessibilityLabel: AccessibilityLabel.BUTTON_CIRCLE_TEMPLATE_3,
55
+ onPress: onButton3Press,
56
+ },
57
+ fimage: {
58
+ source: buttonCircleSmall,
59
+ style: styles.iconSmall,
60
+ text: text3,
61
+ icon: icon3,
62
+ },
63
+ },
64
+ ];
65
+ }, [
66
+ icon1,
67
+ icon2,
68
+ icon3,
69
+ onButton1Press,
70
+ onButton2Press,
71
+ onButton3Press,
72
+ text1,
73
+ text2,
74
+ text3,
75
+ ]);
76
+
77
+ return (
78
+ <View style={styles.threeButtonCircle}>
79
+ {listButton.map((item, index) => {
80
+ return (
81
+ <TouchableOpacity
82
+ accessibilityLabel={item?.button?.accessibilityLabel}
83
+ onPress={item?.button?.onPress}
84
+ key={item?.id || index}
85
+ >
86
+ <View style={styles.buttonAction}>
87
+ <FImage
88
+ source={item?.fimage.source}
89
+ style={[styles.center, item?.fimage?.style]}
90
+ >
91
+ <IconComponent icon={item?.fimage?.icon} />
92
+ <Text style={styles.text}>{item?.fimage?.text}</Text>
93
+ </FImage>
94
+ </View>
95
+ </TouchableOpacity>
96
+ );
97
+ })}
98
+ </View>
99
+ );
100
+ }
101
+ );
102
+
103
+ export default ThreeButtonCircle;
@@ -0,0 +1,31 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ export default StyleSheet.create({
4
+ threeButtonCircle: {
5
+ flexDirection: 'row',
6
+ alignItems: 'center',
7
+ justifyContent: 'space-around',
8
+ },
9
+ iconSmall: {
10
+ height: 102,
11
+ width: 102,
12
+ marginBottom: 12,
13
+ },
14
+ iconBig: {
15
+ height: 170,
16
+ width: 170,
17
+ paddingBottom: 10,
18
+ },
19
+ center: {
20
+ justifyContent: 'center',
21
+ alignItems: 'center',
22
+ },
23
+ buttonAction: {
24
+ flex: 1,
25
+ aspectRatio: 1,
26
+ marginHorizontal: 4,
27
+ alignItems: 'center',
28
+ justifyContent: 'center',
29
+ resizeMode: 'contain',
30
+ },
31
+ });
@@ -0,0 +1,96 @@
1
+ import React, { memo, useMemo } from 'react';
2
+ import { TouchableOpacity, View } from 'react-native';
3
+ import styles from './ThreeButtonDefaultStyles';
4
+ import Text from '../../../Text';
5
+ import { AccessibilityLabel } from '../../../../configs/Constants';
6
+ import IconComponent from '../../../IconComponent';
7
+
8
+ const ThreeButtonDefault = memo(
9
+ ({
10
+ icon1,
11
+ text1,
12
+ icon2,
13
+ text2,
14
+ icon3,
15
+ text3,
16
+ onButton1Press,
17
+ onButton2Press,
18
+ onButton3Press,
19
+ }) => {
20
+ const Icon2CT = () => {
21
+ return icon2 === 'stop' ? (
22
+ <View style={styles.squareStop} />
23
+ ) : (
24
+ <IconComponent icon={icon2} iconSize={30} />
25
+ );
26
+ };
27
+
28
+ const listButton = useMemo(() => {
29
+ return [
30
+ {
31
+ id: 1,
32
+ button: {
33
+ accessibilityLabel: AccessibilityLabel.BUTTON_TEMPLATE_1,
34
+ onPress: onButton1Press,
35
+ },
36
+ icon: icon1,
37
+ text: text1,
38
+ },
39
+ {
40
+ id: 2,
41
+ button: {
42
+ accessibilityLabel: AccessibilityLabel.BUTTON_TEMPLATE_2,
43
+ onPress: onButton2Press,
44
+ },
45
+ icon: icon2,
46
+ text: text2,
47
+ },
48
+ {
49
+ id: 3,
50
+ button: {
51
+ accessibilityLabel: AccessibilityLabel.BUTTON_TEMPLATE_3,
52
+ onPress: onButton3Press,
53
+ },
54
+ icon: icon3,
55
+ text: text3,
56
+ },
57
+ ];
58
+ }, [
59
+ icon1,
60
+ icon2,
61
+ icon3,
62
+ onButton1Press,
63
+ onButton2Press,
64
+ onButton3Press,
65
+ text1,
66
+ text2,
67
+ text3,
68
+ ]);
69
+
70
+ return (
71
+ <View style={styles.threeButtonDefault}>
72
+ {listButton.map((item, index) => {
73
+ return (
74
+ <TouchableOpacity
75
+ accessibilityLabel={item?.button?.accessibilityLabel}
76
+ style={styles.buttonAction}
77
+ onPress={item?.button?.onPress}
78
+ key={item?.id || index}
79
+ >
80
+ <View style={styles.imageButton}>
81
+ {item?.id === 2 ? (
82
+ <Icon2CT />
83
+ ) : (
84
+ <IconComponent icon={item?.icon} iconSize={30} />
85
+ )}
86
+ </View>
87
+ <Text style={styles.text}>{item?.text}</Text>
88
+ </TouchableOpacity>
89
+ );
90
+ })}
91
+ </View>
92
+ );
93
+ }
94
+ );
95
+
96
+ export default ThreeButtonDefault;
@@ -1,12 +1,8 @@
1
1
  import { StyleSheet } from 'react-native';
2
- import { Colors } from '../../configs';
2
+ import { Colors } from '../../../../configs';
3
3
 
4
4
  export default StyleSheet.create({
5
- wrap: {
6
- flex: 1,
7
- marginBottom: 16,
8
- },
9
- threeButton: {
5
+ threeButtonDefault: {
10
6
  flexDirection: 'row',
11
7
  justifyContent: 'space-around',
12
8
  padding: 16,
@@ -15,15 +11,7 @@ export default StyleSheet.create({
15
11
  borderColor: Colors.Gray4,
16
12
  borderRadius: 10,
17
13
  },
18
- imageButton: {
19
- height: 32,
20
- marginBottom: 7,
21
- },
22
- text: {
23
- fontSize: 14,
24
- lineHeight: 22,
25
- },
26
- buttonActionDoor: {
14
+ buttonAction: {
27
15
  flex: 1,
28
16
  aspectRatio: 1,
29
17
  marginHorizontal: 4,
@@ -34,6 +22,14 @@ export default StyleSheet.create({
34
22
  borderColor: Colors.Gray3,
35
23
  borderRadius: 10,
36
24
  },
25
+ imageButton: {
26
+ height: 32,
27
+ marginBottom: 7,
28
+ },
29
+ text: {
30
+ fontSize: 14,
31
+ lineHeight: 22,
32
+ },
37
33
  squareStop: {
38
34
  marginHorizontal: 8,
39
35
  marginVertical: 8,
@@ -44,23 +40,4 @@ export default StyleSheet.create({
44
40
  backgroundColor: Colors.Primary,
45
41
  borderRadius: 1,
46
42
  },
47
- lockSwitch: {
48
- flexDirection: 'row',
49
- justifyContent: 'space-between',
50
- marginBottom: 7,
51
- },
52
- iconLock: {
53
- paddingBottom: 7,
54
- },
55
- textLockDoor: {
56
- paddingLeft: 12,
57
- height: 24,
58
- fontSize: 16,
59
- lineHeight: 24,
60
- },
61
- lockDoor: {
62
- flexDirection: 'row',
63
- alignItems: 'flex-end',
64
- paddingLeft: 5,
65
- },
66
43
  });
@@ -1,10 +1,12 @@
1
- import React, { memo, useCallback, useState } from 'react';
2
- import { TouchableOpacity, View, Switch } from 'react-native';
3
- import styles from './ThreeButtonTemplateStyle';
4
- import Text from '../Text';
5
- import { AccessibilityLabel } from '../../configs/Constants';
6
- import { Colors } from '../../configs';
7
- import IconComponent from '../IconComponent';
1
+ import React, { memo, useCallback, useState, useMemo } from 'react';
2
+ import { View, Switch } from 'react-native';
3
+ import styles from './styles';
4
+ import Text from '../../Text';
5
+ import { AccessibilityLabel } from '../../../configs/Constants';
6
+ import { Colors } from '../../../configs';
7
+ import IconComponent from '../../IconComponent';
8
+ import ThreeButtonCircle from './components/ThreeButtonCircle';
9
+ import ThreeButtonDefault from './components/ThreeButtonDefault';
8
10
 
9
11
  const ThreeButtonTemplate = memo(({ actionGroup, doAction }) => {
10
12
  const { configuration } = actionGroup;
@@ -25,15 +27,11 @@ const ThreeButtonTemplate = memo(({ actionGroup, doAction }) => {
25
27
  icon_kit3_data,
26
28
  text_door_lock,
27
29
  is_display_lock,
30
+ layout,
28
31
  } = configuration || {};
32
+
29
33
  const [lock, setLock] = useState(false);
30
- const iconCustom = (icon) => {
31
- return icon === 'stop' ? (
32
- <View style={styles.squareStop} />
33
- ) : (
34
- <IconComponent icon={icon} iconSize={30} />
35
- );
36
- };
34
+
37
35
  const onButton1Press = useCallback(() => {
38
36
  doAction(action1_data, null);
39
37
  }, [action1_data, doAction]);
@@ -84,45 +82,44 @@ const ThreeButtonTemplate = memo(({ actionGroup, doAction }) => {
84
82
  );
85
83
  };
86
84
 
85
+ const renderLayoutThreeButton = useMemo(() => {
86
+ const props = {
87
+ icon1: icon_kit1_data?.icon || icon1,
88
+ icon2: icon_kit2_data?.icon || icon2,
89
+ icon3: icon_kit3_data?.icon || icon3,
90
+ text1: text1,
91
+ text2: text2,
92
+ text3: text3,
93
+ onButton1Press: onButton1Press,
94
+ onButton2Press: onButton2Press,
95
+ onButton3Press: onButton3Press,
96
+ };
97
+ switch (layout) {
98
+ case 'circle': {
99
+ return <ThreeButtonCircle {...props} />;
100
+ }
101
+ default:
102
+ return <ThreeButtonDefault {...props} />;
103
+ }
104
+ }, [
105
+ icon1,
106
+ icon2,
107
+ icon3,
108
+ icon_kit1_data?.icon,
109
+ icon_kit2_data?.icon,
110
+ icon_kit3_data?.icon,
111
+ layout,
112
+ onButton1Press,
113
+ onButton2Press,
114
+ onButton3Press,
115
+ text1,
116
+ text2,
117
+ text3,
118
+ ]);
119
+
87
120
  return (
88
121
  <View style={styles.wrap}>
89
- <View style={styles.threeButton}>
90
- <TouchableOpacity
91
- accessibilityLabel={AccessibilityLabel.BUTTON_TEMPLATE_1}
92
- style={styles.buttonActionDoor}
93
- onPress={onButton1Press}
94
- underlayColor={Colors.Gray2}
95
- >
96
- <View style={styles.imageButton}>
97
- <IconComponent icon={icon_kit1_data?.icon || icon1} iconSize={30} />
98
- </View>
99
- <Text style={styles.text}>{text1}</Text>
100
- </TouchableOpacity>
101
-
102
- <TouchableOpacity
103
- accessibilityLabel={AccessibilityLabel.BUTTON_TEMPLATE_2}
104
- style={styles.buttonActionDoor}
105
- onPress={onButton2Press}
106
- underlayColor={Colors.Gray2}
107
- >
108
- <View style={styles.imageButton}>
109
- {iconCustom(icon_kit2_data?.icon || icon2)}
110
- </View>
111
- <Text style={styles.text}>{text2}</Text>
112
- </TouchableOpacity>
113
-
114
- <TouchableOpacity
115
- accessibilityLabel={AccessibilityLabel.BUTTON_TEMPLATE_3}
116
- style={styles.buttonActionDoor}
117
- onPress={onButton3Press}
118
- underlayColor={Colors.Gray2}
119
- >
120
- <View style={styles.imageButton}>
121
- <IconComponent icon={icon_kit3_data?.icon || icon3} iconSize={30} />
122
- </View>
123
- <Text style={styles.text}>{text3}</Text>
124
- </TouchableOpacity>
125
- </View>
122
+ {renderLayoutThreeButton}
126
123
  <View style={styles.lockSwitch}>
127
124
  {is_display_lock &&
128
125
  itemLock(
@@ -0,0 +1,27 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ export default StyleSheet.create({
4
+ wrap: {
5
+ flex: 1,
6
+ marginBottom: 16,
7
+ },
8
+ lockSwitch: {
9
+ flexDirection: 'row',
10
+ justifyContent: 'space-between',
11
+ marginBottom: 7,
12
+ },
13
+ iconLock: {
14
+ paddingBottom: 7,
15
+ },
16
+ textLockDoor: {
17
+ paddingLeft: 12,
18
+ height: 24,
19
+ fontSize: 16,
20
+ lineHeight: 24,
21
+ },
22
+ lockDoor: {
23
+ flexDirection: 'row',
24
+ alignItems: 'flex-end',
25
+ paddingLeft: 5,
26
+ },
27
+ });
@@ -1,7 +1,7 @@
1
1
  import React, { memo, useEffect, useMemo, useState } from 'react';
2
2
  import { View, StyleSheet } from 'react-native';
3
3
  import { isEmpty } from 'lodash';
4
- const HighchartsReactNative = () => null;
4
+ import HighchartsReactNative from '@eohjsc/highcharts';
5
5
 
6
6
  import { Colors } from '../../configs';
7
7
  import { getMaxValueIndex } from '../../utils/chartHelper/getMaxValueIndex';
@@ -99,6 +99,7 @@ const SCDefaultConfig = {
99
99
  pusherAppCluster: 'ap1',
100
100
  intervalWatchConfigTime: 30000,
101
101
  setCurrentSensorDisplay: () => {},
102
+ appName: 'E-Ra',
102
103
  };
103
104
 
104
105
  export class SCConfig {
@@ -115,6 +116,7 @@ export class SCConfig {
115
116
  static language = 'en';
116
117
  static intervalWatchConfigTime = SCDefaultConfig.intervalWatchConfigTime;
117
118
  static setCurrentSensorDisplay = SCDefaultConfig.setCurrentSensorDisplay;
119
+ static appName = SCDefaultConfig.appName;
118
120
  }
119
121
 
120
122
  export const initSCConfig = (config) => {
@@ -140,4 +142,5 @@ export const initSCConfig = (config) => {
140
142
  config.intervalWatchConfigTime ?? SCDefaultConfig.intervalWatchConfigTime;
141
143
  SCConfig.setCurrentSensorDisplay =
142
144
  config.setCurrentSensorDisplay ?? SCDefaultConfig.setCurrentSensorDisplay;
145
+ SCConfig.appName = config.appName ?? SCDefaultConfig.appName;
143
146
  };
@@ -6,6 +6,7 @@ import { scanBluetoothDevices } from '../../iot/RemoteControl/Bluetooth';
6
6
  import Permissions from 'react-native-permissions';
7
7
  import { OpenSetting } from '../../utils/Permission/common';
8
8
  import { useTranslations } from '../Common/useTranslations';
9
+ import { SCConfig } from '../../configs';
9
10
 
10
11
  const permissions = [
11
12
  'android.permission.BLUETOOTH_CONNECT',
@@ -77,7 +78,7 @@ const useBluetoothConnection = (fnCallback) => {
77
78
  if (blocked) {
78
79
  OpenSetting(
79
80
  t('bluetooth_rationale_title'),
80
- t('bluetooth_rationale_message')
81
+ t('bluetooth_rationale_message', { appName: SCConfig.appName })
81
82
  );
82
83
  }
83
84
  const granted = Object.values(results).every((result) =>
@@ -150,7 +150,7 @@ const AddLocationMaps = memo(() => {
150
150
  permissionResult === RESULTS.BLOCKED &&
151
151
  OpenSetting(
152
152
  t('location_rationale_title'),
153
- t('location_require_message')
153
+ t('location_require_message', { appName: SCConfig.appName })
154
154
  );
155
155
  } else if (error.code === GEOLOCATION_ERROR.POSITION_UNAVAILABLE) {
156
156
  const locationEnabaled = await openPromptEnableLocation();
@@ -18,6 +18,7 @@ import AccessibilityLabel from '../../configs/AccessibilityLabel';
18
18
  import LoadingCircle from '../../Images/Common/loading-circle.json';
19
19
  import FullLoading from '../../commons/FullLoading';
20
20
  import { useWifiManage } from './hooks/useWifiManage';
21
+ import { SCConfig } from '../../configs';
21
22
 
22
23
  let intervalSend = null;
23
24
  let socket;
@@ -196,7 +197,9 @@ const ConnectingWifiGuide = ({ route }) => {
196
197
  <>
197
198
  <View style={styles.guideContent}>
198
199
  <InteractSmartphoneIcon width={94} height={94} />
199
- <Text style={styles.txtContent}>{t('connect_wifi_asking')}</Text>
200
+ <Text style={styles.txtContent}>
201
+ {t('connect_wifi_asking', { appName: SCConfig.appName })}
202
+ </Text>
200
203
  </View>
201
204
  <BottomButtonView
202
205
  style={styles.bottomButtonView}
@@ -4,11 +4,13 @@ import { useRoute, useNavigation } from '@react-navigation/native';
4
4
 
5
5
  import DetailConfigAction from '../components/DetailConfigAction';
6
6
  import DetailActionModbus from '../components/DetailActionModbus';
7
+ import { useTranslations } from '../../../hooks/Common/useTranslations';
7
8
  import { calculateLength, calculateStartAddress } from '../utils';
8
9
  import Routes from '../../../utils/Route';
9
10
  import styles from './styles';
10
11
 
11
12
  const DetailConfigActionModbus = () => {
13
+ const t = useTranslations();
12
14
  const { params = {} } = useRoute();
13
15
  const { navigate } = useNavigation();
14
16
  const {
@@ -46,7 +48,7 @@ const DetailConfigActionModbus = () => {
46
48
  },
47
49
  {
48
50
  id: 2,
49
- title: 'Sa',
51
+ title: t('data_address'),
50
52
  data: sa,
51
53
  },
52
54
  {
@@ -55,7 +57,7 @@ const DetailConfigActionModbus = () => {
55
57
  data: len,
56
58
  },
57
59
  ],
58
- [itemActionConfig?.func, len, sa]
60
+ [itemActionConfig?.func, len, sa, t]
59
61
  );
60
62
 
61
63
  const listConfigWrite = useMemo(
@@ -67,7 +69,7 @@ const DetailConfigActionModbus = () => {
67
69
  },
68
70
  {
69
71
  id: 2,
70
- title: 'Sa',
72
+ title: t('data_address'),
71
73
  data: sa,
72
74
  },
73
75
  {
@@ -81,7 +83,7 @@ const DetailConfigActionModbus = () => {
81
83
  data: itemActionConfig?.ex || '--',
82
84
  },
83
85
  ],
84
- [itemActionConfig?.ex, itemActionConfig?.func, len, sa]
86
+ [itemActionConfig?.ex, itemActionConfig?.func, len, sa, t]
85
87
  );
86
88
 
87
89
  const listAction = useMemo(
@@ -7,6 +7,7 @@ import { mockSCStore } from '../../../../context/mockStore';
7
7
  import GatewayConnectionMethods from '..';
8
8
  import { HeaderCustom } from '../../../../commons';
9
9
  import { AccessibilityLabel } from '../../../../configs/Constants';
10
+ import { getTranslate } from '../../../../utils/I18n';
10
11
 
11
12
  const wrapComponent = () => (
12
13
  <SCProvider initState={mockSCStore({})}>
@@ -31,7 +32,9 @@ describe('Test GatewayConnectionMethods', () => {
31
32
 
32
33
  expect(headerCustom).toHaveLength(1);
33
34
  expect(text.props.children).toEqual(
34
- 'Visit EoH Web to set up other connection options.'
35
+ getTranslate('en', 'visit_eoh_web_to_set_up_other_connection', {
36
+ appName: 'E-Ra',
37
+ })
35
38
  );
36
39
  expect(flatList).toHaveLength(1);
37
40
  });
@@ -1,7 +1,7 @@
1
1
  import React, { useCallback, memo, useMemo } from 'react';
2
2
  import { View, FlatList } from 'react-native';
3
3
 
4
- import { Colors } from '../../../configs';
4
+ import { Colors, SCConfig } from '../../../configs';
5
5
  import t from '../../../hooks/Common/useTranslations';
6
6
  import { Text, HeaderCustom } from '../../../commons';
7
7
  import styles from './styles';
@@ -56,7 +56,9 @@ const GatewayConnectionMethods = () => {
56
56
  AccessibilityLabel.GATEWAY_CONNECTION_METHODS_TEXT
57
57
  }
58
58
  >
59
- {t('visit_eoh_web_to_set_up_other_connection')}
59
+ {t('visit_eoh_web_to_set_up_other_connection', {
60
+ appName: SCConfig.appName,
61
+ })}
60
62
  </Text>
61
63
  <FlatList
62
64
  contentContainerStyle={styles.contentContainerStyle}
@@ -14,6 +14,7 @@ import api from '../../../../utils/Apis/axios';
14
14
  import GatewayInfo from '..';
15
15
  import t from '../../../../hooks/Common/useTranslations';
16
16
  import ModalPopupCT from '../../../../commons/ModalPopupCT';
17
+ import { SCConfig } from '../../../../configs';
17
18
 
18
19
  const mockPop = jest.fn();
19
20
  const mock = new MockAdapter(api.axiosInstance);
@@ -93,7 +94,7 @@ describe('Test GatewayInfo', () => {
93
94
  const btnDelete = buttonDelete(instance);
94
95
  expect(headerCustom).toHaveLength(1);
95
96
  expect(alert.props.children[1].props.children.props.children).toEqual(
96
- t('go_to_eoh_web_to_see_firmware')
97
+ t('go_to_eoh_web_to_see_firmware', { appName: SCConfig.appName })
97
98
  );
98
99
  expect(flatList).toHaveLength(1);
99
100
  const textConnect = btnConnect.findAllByType(Text);
@@ -7,6 +7,7 @@ import { mockSCStore } from '../../../../../context/mockStore';
7
7
  import { HeaderCustom } from '../../../../../commons';
8
8
  import Information from '../../../components/Information';
9
9
  import { AccessibilityLabel } from '../../../../../configs/Constants';
10
+ import { getTranslate } from '../../../../../utils/I18n';
10
11
 
11
12
  const mockHandleDeleteGateway = jest.fn();
12
13
  const mockHandleConnectionMethods = jest.fn();
@@ -51,7 +52,7 @@ describe('Test Information', () => {
51
52
  expect(headerCustom).toHaveLength(1);
52
53
  expect(flatList).toHaveLength(1);
53
54
  expect(viewAlert.props.children[1].props.children.props.children).toEqual(
54
- 'Go to EoH web to see firmware configuration'
55
+ getTranslate('en', 'go_to_eoh_web_to_see_firmware', { appName: 'E-Ra' })
55
56
  );
56
57
  const buttonConnect = instance.findByProps({
57
58
  accessibilityLabel:
@@ -1,6 +1,6 @@
1
1
  import React, { useCallback, memo } from 'react';
2
2
  import { TouchableOpacity, View, Image, FlatList } from 'react-native';
3
- import { Colors } from '../../../../configs';
3
+ import { Colors, SCConfig } from '../../../../configs';
4
4
  import t from '../../../../hooks/Common/useTranslations';
5
5
  import { Text, HeaderCustom } from '../../../../commons';
6
6
  import Images from '../../../../configs/Images';
@@ -51,7 +51,9 @@ const Information = ({
51
51
  <Image source={Images.inforCode} />
52
52
  <View style={styles.flex1}>
53
53
  <Text type="H4" style={styles.marginLeft16}>
54
- {t('go_to_eoh_web_to_see_firmware')}
54
+ {t('go_to_eoh_web_to_see_firmware', {
55
+ appName: SCConfig.appName,
56
+ })}
55
57
  </Text>
56
58
  </View>
57
59
  </View>
@@ -12,7 +12,7 @@ import Text from '../../commons/Text';
12
12
  import { useBoolean } from '../../hooks/Common';
13
13
  import { axiosGet, axiosPut } from '../../utils/Apis/axios';
14
14
 
15
- import { API, Colors } from '../../configs';
15
+ import { API, Colors, SCConfig } from '../../configs';
16
16
  import {
17
17
  ACCESS_SCHEDULE_PROPERTIES,
18
18
  typeMaps,
@@ -123,7 +123,7 @@ const GuestInfo = ({ route }) => {
123
123
  )}
124
124
  {guest?.id && (
125
125
  <RowGuestInfo
126
- textLeft={t('eoh_account_id')}
126
+ textLeft={t('eoh_account_id', { appName: SCConfig.appName })}
127
127
  textRight={guest.id}
128
128
  />
129
129
  )}
@@ -4,7 +4,7 @@ import { useTranslations } from '../../hooks/Common/useTranslations';
4
4
  import { CircleView } from '../../commons/CircleView';
5
5
  import Text from '../../commons/Text';
6
6
  import { shortEmailName } from '../../utils/Utils';
7
- import { Colors, Images, API } from '../../configs';
7
+ import { Colors, Images, API, SCConfig } from '../../configs';
8
8
  import { HeaderCustom } from '../../commons/Header';
9
9
  import RowMemberInfo from '../GuestInfo/components/RowGuestInfo';
10
10
  import { useIsOwnerOfUnit } from '../../hooks/Common';
@@ -203,7 +203,7 @@ const InfoMemberUnit = memo(({ route }) => {
203
203
  )}
204
204
  {memberInfo?.id && (
205
205
  <RowMemberInfo
206
- textLeft={t('eoh_account_id')}
206
+ textLeft={t('eoh_account_id', { appName: SCConfig.appName })}
207
207
  textRight={memberInfo?.phone_number || memberInfo.id}
208
208
  />
209
209
  )}
@@ -148,7 +148,7 @@ const SelectAddress = memo(({ route }) => {
148
148
  permissionResult === RESULTS.BLOCKED &&
149
149
  OpenSetting(
150
150
  t('location_rationale_title'),
151
- t('location_require_message')
151
+ t('location_require_message', { appName: SCConfig.appName })
152
152
  );
153
153
  } else if (error.code === GEOLOCATION_ERROR.POSITION_UNAVAILABLE) {
154
154
  const locationEnabaled = await openPromptEnableLocation();
@@ -253,13 +253,13 @@
253
253
  "popular_locations": "Popular locations",
254
254
  "text_search_location_placeholder": "Search public areas, shops, restaurants,...",
255
255
  "location_rationale_title": "Location Permission Required",
256
- "location_rationale_message": "EoH only uses your location to display weather and air quality.",
256
+ "location_rationale_message": "{appName} only uses your location to display weather and air quality.",
257
257
  "camera_rationale_title": "Camera Permission Required",
258
- "camera_rationale_message": "EoH only uses your camera to take photo",
258
+ "camera_rationale_message": "{appName} only uses your camera to take photo",
259
259
  "photo_rationale_title": "Photo Permission Required",
260
- "photo_rationale_message": "EoH only uses your photo to upload",
260
+ "photo_rationale_message": "{appName} only uses your photo to upload",
261
261
  "bluetooth_rationale_title": "Bluetooth Permission Required",
262
- "bluetooth_rationale_message": "EoH only uses Bluetooth to scan and control devices",
262
+ "bluetooth_rationale_message": "{appName} only uses Bluetooth to scan and control devices",
263
263
  "recommendations": "Recommendations",
264
264
  "Open windows for more fresh air": "Open windows for more fresh air",
265
265
  "notify_new_version_title": "Update available",
@@ -624,7 +624,7 @@
624
624
  "your_location_info": "Your location information:",
625
625
  "text_send_now": "SEND NOW",
626
626
  "text_no_charge_outside_parking_hour": "There is no charge outside these parking hour",
627
- "notify_update_app": "A new EoH update is now available. Please update to new version to continue using the app.",
627
+ "notify_update_app": "A new {appName} update is now available. Please update to new version to continue using the app.",
628
628
  "update_now": "Update now",
629
629
  "removed_successfully": "Removed successfully!",
630
630
  "spot_name": "Spot name",
@@ -736,7 +736,7 @@
736
736
  "guests": "Guests",
737
737
  "no_guest": "No guest",
738
738
  "guest_info": "Guest Information",
739
- "eoh_account_id": "EoH account ID",
739
+ "eoh_account_id": "{appName} account ID",
740
740
  "access_schedule": "Access Schedule",
741
741
  "always": "Always",
742
742
  "recurring": "Recurring",
@@ -903,7 +903,7 @@
903
903
  "gateway_warning_content_3": "In the next steps, you will be instructed to connect to wifi for the device. ",
904
904
  "gateway_warning_content_4": "To give you a good experience, you need to know the name and password of the wifi network and make sure the device is placed in a good location.",
905
905
  "warning_beta_test_feature": "This feature is in beta test, not official yet",
906
- "connecting_gateway_warning_1": "By continuing, EoH needs to connect to the device's wifi.",
906
+ "connecting_gateway_warning_1": "By continuing, {appName} needs to connect to the device's wifi.",
907
907
  "connecting_gateway_warning_2": "A message will appear asking you to connect.",
908
908
  "remove_account": "Remove Account",
909
909
  "brightness": "Brightness",
@@ -974,7 +974,7 @@
974
974
  "This {name} was removed!" : "This {name} was removed!",
975
975
  "camera_request_permission": "Camera request permission",
976
976
  "camera_request_permission_des": "To use camera, please unlock camera permission",
977
- "location_require_message": "EoH needs your location permission to get current location.",
977
+ "location_require_message": "{appName} needs your location permission to get current location.",
978
978
  "turn_on_location_service": "Turn on location service for your phone",
979
979
  "turn_on_location_service_des": "To continue, let your device turn on location by turning on location service in Settings",
980
980
  "detected": "Detected",
@@ -1021,7 +1021,7 @@
1021
1021
  "device_connect_directly_to_the_gateway": "Device connected directly to the gateway",
1022
1022
  "zigbee": "Zigbee",
1023
1023
  "device_connect_remotely_to_the_gateway": "Device connected remotely to the gateway",
1024
- "connect_wifi_asking": "By continuing, EoH needs to connect to the device's Wifi. A message will appear asking you to connect.",
1024
+ "connect_wifi_asking": "By continuing, {appName} needs to connect to the device's Wifi. A message will appear asking you to connect.",
1025
1025
  "previous": "Previous",
1026
1026
  "invalid_qr_code": "Invalid QR Code",
1027
1027
  "invalid_qr_code_warning": "This device can't be added using a QR code",
@@ -1052,7 +1052,7 @@
1052
1052
  "need_add_gateway_before_add_device": "You need to add a new Gateway before adding the device.",
1053
1053
  "fail_to_discover_device_wifi": "Fail to discover device wifi",
1054
1054
  "try_to_turn_on_device_or_try_again": "Try to turn on device or Try again",
1055
- "go_to_eoh_web_to_see_firmware": "Go to EoH web to see firmware configuration",
1055
+ "go_to_eoh_web_to_see_firmware": "Go to {appName} web to see firmware configuration",
1056
1056
  "general_information":"General information",
1057
1057
  "connection_methods": "Connection methods",
1058
1058
  "delete_gateway":"Delete gateway",
@@ -1062,7 +1062,7 @@
1062
1062
  "activate_date":"Activate date",
1063
1063
  "warranty_expiration_date":"Warranty expiration date",
1064
1064
  "firmware_version":"Firmware version",
1065
- "visit_eoh_web_to_set_up_other_connection": "Visit EoH Web to set up other connection options.",
1065
+ "visit_eoh_web_to_set_up_other_connection": "Visit {appName} Web to set up other connection options.",
1066
1066
  "delete_successfully":"Delete successfully!",
1067
1067
  "reboot_successfully": "Reboot successfully!",
1068
1068
  "message_delete_gateway": "This will fully remove Gateway with Info, Devices, Data Stream from the gateway.",
@@ -1114,5 +1114,6 @@
1114
1114
  "default_value": "Default value",
1115
1115
  "config_type": "Config type",
1116
1116
  "pin": "PIN",
1117
- "pin_mode": "PIN mode"
1117
+ "pin_mode": "PIN mode",
1118
+ "data_address": "Data address"
1118
1119
  }
@@ -288,13 +288,13 @@
288
288
  "popular_locations": "Địa điểm phổ biến",
289
289
  "text_search_location_placeholder": "Tìm kiếm địa điểm công cộng, cửa hàng, nhà hàng,...",
290
290
  "location_rationale_title": "Yêu cầu cho phép truy cập vị trí",
291
- "location_rationale_message": "EoH chỉ sử dụng vị trí của bạn để hiển thị thông tin thời tiết và chất lượng không khí.",
291
+ "location_rationale_message": "{appName} chỉ sử dụng vị trí của bạn để hiển thị thông tin thời tiết và chất lượng không khí.",
292
292
  "camera_rationale_title": "Yêu cầu cho phép truy cập máy ảnh",
293
- "camera_rationale_message": "EoH chỉ sử dụng máy ảnh của bạn",
293
+ "camera_rationale_message": "{appName} chỉ sử dụng máy ảnh của bạn",
294
294
  "photo_rationale_title": "Yêu cầu cho phép truy cập ảnh",
295
- "photo_rationale_message": "EoH chỉ sử dụng thư viện ảnh để upload",
295
+ "photo_rationale_message": "{appName} chỉ sử dụng thư viện ảnh để upload",
296
296
  "bluetooth_rationale_title": "Yêu cầu cho phép sử dụng Bluetooth",
297
- "bluetooth_rationale_message": "EoH sử dụng Bluetooth để quét và điều khiển thiết bị",
297
+ "bluetooth_rationale_message": "{appName} sử dụng Bluetooth để quét và điều khiển thiết bị",
298
298
  "recommendations": "Đề xuất",
299
299
  "Open windows for more fresh air": "Mở cửa sổ để đưa không khí sạch vào nhà",
300
300
  "notify_new_version_title": "Có bản cập nhật!",
@@ -742,7 +742,7 @@
742
742
  "guests": "Những vị khách",
743
743
  "no_guest": "Không có vị khách nào",
744
744
  "guest_info": "Thông tin khách",
745
- "eoh_account_id": "ID tài khoản EoH",
745
+ "eoh_account_id": "ID tài khoản {appName}",
746
746
  "access_schedule": "Lịch truy cập",
747
747
  "always": "Luôn luôn",
748
748
  "recurring": "Tuần hoàn",
@@ -901,7 +901,7 @@
901
901
  "gateway_warning_content_3": "Trong các bước tiếp theo, bạn sẽ được hướng dẫn kết nối wifi cho thiết bị. ",
902
902
  "gateway_warning_content_4": "Bạn cần biết tên và mật khẩu của mạng wifi và đảm bảo thiết bị được đặt ở vị trí tốt.",
903
903
  "warning_beta_test_feature": "Tính năng này đang ở giai đoạn beta test, chưa phải bản chính thức.",
904
- "connecting_gateway_warning_1": "Bằng việc tiếp tục, EoH cần kết nối với Wifi của thiết bị.",
904
+ "connecting_gateway_warning_1": "Bằng việc tiếp tục, {appName} cần kết nối với Wifi của thiết bị.",
905
905
  "connecting_gateway_warning_2": "Một thông báo sẽ hiện lên và yêu cầu bạn kết nối.",
906
906
  "add_gateway_success": "Thêm gateway thành công",
907
907
  "tap_to_add_new_schedule": "Nhấn + để thêm lịch trình mới",
@@ -973,7 +973,7 @@
973
973
  "location_perm_denied": "Ứng dụng không cho phép truy cập vị trí.",
974
974
  "camera_request_permission": "Quyền yêu cầu máy ảnh",
975
975
  "camera_request_permission_des": "Để sử dụng máy ảnh, vui lòng mở khóa quyền đối với máy ảnh",
976
- "location_require_message": "Eoh cần quyền truy cập vị trí của bạn để lấy vị trí hiện tại.",
976
+ "location_require_message": "{appName} cần quyền truy cập vị trí của bạn để lấy vị trí hiện tại.",
977
977
  "turn_on_location_service": "Bật dịch vụ vị trí cho điện thoại của bạn",
978
978
  "turn_on_location_service_des": "Để tiếp tục, bật dịch vụ vị trí cho điện thoại của bạn trong Cài Đặt",
979
979
  "detected": "Phát hiện",
@@ -1019,7 +1019,7 @@
1019
1019
  "device_connect_directly_to_the_gateway": "Thiết bị được kết nối trực tiếp với gateway",
1020
1020
  "zigbee": "Zigbee",
1021
1021
  "device_connect_remotely_to_the_gateway": "Thiết bị được kết nối từ xa với gateway",
1022
- "connect_wifi_asking": "Bằng việc tiếp tục, EoH cần kết nối với Wifi của thiết bị. Một thông báo sẽ hiện lên và yêu cầu bạn kết nối.",
1022
+ "connect_wifi_asking": "Bằng việc tiếp tục, {appName} cần kết nối với Wifi của thiết bị. Một thông báo sẽ hiện lên và yêu cầu bạn kết nối.",
1023
1023
  "previous": "Trước",
1024
1024
  "invalid_qr_code": "Mã QR không hợp lệ",
1025
1025
  "invalid_qr_code_warning": "Không thể thêm thiết bị bằng mã QR này",
@@ -1051,7 +1051,7 @@
1051
1051
  "need_add_gateway_before_add_device": "Bạn cần thêm mới 1 Gateway trước khi thêm thiết bị.",
1052
1052
  "fail_to_discover_device_wifi": "Không phát hiện được wifi của thiết bị",
1053
1053
  "try_to_turn_on_device_or_try_again": "Thử bật thiết bị hoặc Thử lại",
1054
- "go_to_eoh_web_to_see_firmware": "Vào web EoH để xem cấu hình firmware",
1054
+ "go_to_eoh_web_to_see_firmware": "Vào web {appName} để xem cấu hình firmware",
1055
1055
  "general_information":"Thông tin chung",
1056
1056
  "connection_methods": "Các phương thức kết nối",
1057
1057
  "delete_gateway":"Xoá cửa ngõ",
@@ -1061,7 +1061,7 @@
1061
1061
  "activate_date":"Ngày kích hoạt",
1062
1062
  "warranty_expiration_date":"Ngày hết hạn bảo hành",
1063
1063
  "firmware_version":"Phiên bản phần mềm",
1064
- "visit_eoh_web_to_set_up_other_connection": "Truy cập EoH Web để thiết lập các tùy chọn kết nối khác.",
1064
+ "visit_eoh_web_to_set_up_other_connection": "Truy cập {appName} Web để thiết lập các tùy chọn kết nối khác.",
1065
1065
  "delete_successfully":"Xoá thành công!",
1066
1066
  "reboot_successfully": "Khởi động lại thành công!",
1067
1067
  "message_delete_gateway": "Thao tác này sẽ loại bỏ hoàn toàn Gateway với Thông tin, Thiết bị, Luồng dữ liệu khỏi cổng.",
@@ -1113,5 +1113,6 @@
1113
1113
  "default_value": "Giá trị mặc định",
1114
1114
  "config_type": "Loại cấu hình",
1115
1115
  "pin": "PIN",
1116
- "pin_mode": "Chế độ mã PIN"
1116
+ "pin_mode": "Chế độ mã PIN",
1117
+ "data_address": "Địa chỉ dữ liệu"
1117
1118
  }