@eohjsc/react-native-smart-city 0.3.39 → 0.3.41

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 (48) hide show
  1. package/assets/images/AddNewDevice/gateway-icon.svg +12 -0
  2. package/package.json +1 -1
  3. package/src/commons/Header/HeaderCustom.js +9 -6
  4. package/src/commons/SelectGateway/index.js +63 -21
  5. package/src/commons/SelectGateway/styles.js +25 -4
  6. package/src/commons/SelectSubUnit/index.js +2 -3
  7. package/src/commons/SelectSubUnit/styles.js +1 -3
  8. package/src/commons/StatusBox/index.js +19 -0
  9. package/src/commons/StatusBox/styles.js +30 -0
  10. package/src/commons/SubUnit/ShortDetail.js +7 -4
  11. package/src/commons/SubUnit/__test__/ShortDetail.test.js +3 -1
  12. package/src/commons/index.js +8 -1
  13. package/src/configs/API.js +4 -0
  14. package/src/configs/AccessibilityLabel.js +2 -1
  15. package/src/configs/Colors.js +1 -0
  16. package/src/screens/AddCommon/__test__/SelectSubUnit.test.js +2 -2
  17. package/src/screens/AddNewGateway/ConnectingDevice.js +6 -2
  18. package/src/screens/AddNewGateway/ConnectingModbusDevice.js +4 -2
  19. package/src/screens/AddNewGateway/ConnectingWifiDevice.js +15 -7
  20. package/src/screens/AddNewGateway/ConnectingWifiGuide.js +4 -3
  21. package/src/screens/AddNewGateway/ConnectingZigbeeDevice.js +3 -2
  22. package/src/screens/AddNewGateway/RenameNewDevices.js +85 -50
  23. package/src/screens/AddNewGateway/RenameNewDevicesStyles.js +18 -14
  24. package/src/screens/AddNewGateway/ScanGatewayQR.js +2 -1
  25. package/src/screens/AddNewGateway/ScanModbusQR.js +5 -5
  26. package/src/screens/AddNewGateway/SelectDeviceSubUnit.js +3 -0
  27. package/src/screens/AddNewGateway/SelectDeviceType.js +7 -6
  28. package/src/screens/AddNewGateway/SelectModbusGateway.js +19 -3
  29. package/src/screens/AddNewGateway/SelectZigbeeGateway.js +3 -2
  30. package/src/screens/AddNewGateway/ShareWifiPassword.js +12 -2
  31. package/src/screens/AddNewGateway/__test__/ConnectingZigbeeDevice.test.js +6 -3
  32. package/src/screens/AddNewGateway/__test__/RenameNewDevices.test.js +28 -9
  33. package/src/screens/AddNewGateway/__test__/ScanModbusQR.test.js +1 -3
  34. package/src/screens/AddNewGateway/__test__/SelectModbusGateway.test.js +1 -1
  35. package/src/screens/Device/detail.js +14 -10
  36. package/src/screens/Gateway/__test__/index.test.js +32 -5
  37. package/src/screens/Gateway/components/GatewayItem/__test__/index.test.js +83 -0
  38. package/src/screens/Gateway/components/GatewayItem/index.js +27 -0
  39. package/src/screens/Gateway/components/GatewayItem/styles.js +62 -0
  40. package/src/screens/Gateway/hooks/useGateway.js +38 -0
  41. package/src/screens/Gateway/index.js +77 -5
  42. package/src/screens/Gateway/styles.js +32 -0
  43. package/src/screens/SubUnit/Detail.js +2 -1
  44. package/src/screens/Unit/AddMenu.js +1 -1
  45. package/src/screens/Unit/Detail.js +3 -1
  46. package/src/utils/I18n/translations/en.json +17 -1
  47. package/src/utils/I18n/translations/vi.json +16 -0
  48. package/src/utils/Route/index.js +1 -0
@@ -1,16 +1,43 @@
1
1
  import React from 'react';
2
- import { View } from 'react-native';
2
+ import { FlatList } from 'react-native';
3
3
  import { act, create } from 'react-test-renderer';
4
4
  import Gateway from '..';
5
+ import { SCProvider } from '../../../context';
6
+ import { mockSCStore } from '../../../context/mockStore';
7
+ import { AccessibilityLabel } from '../../../configs/Constants';
5
8
 
6
- describe('Test Template screen', () => {
9
+ const wrapComponent = (route) => (
10
+ <SCProvider initState={mockSCStore({})}>
11
+ <Gateway />
12
+ </SCProvider>
13
+ );
14
+
15
+ describe('Test Gateway screen', () => {
7
16
  let tree;
8
17
  it('Test render', async () => {
9
18
  await act(async () => {
10
- tree = await create(<Gateway />);
19
+ tree = await create(wrapComponent());
20
+ });
21
+ const instance = tree.root;
22
+ const view = instance.findByProps({
23
+ accessibilityLabel: AccessibilityLabel.LIST_GATEWAY,
24
+ });
25
+ const flatLists = instance.findAllByType(FlatList);
26
+ expect(view.props.children[0].props.children).toEqual('Gateway');
27
+ expect(flatLists).toHaveLength(1);
28
+ });
29
+
30
+ it('Test render empty', async () => {
31
+ await act(async () => {
32
+ tree = await create(wrapComponent());
11
33
  });
12
34
  const instance = tree.root;
13
- const Views = instance.findAllByType(View);
14
- expect(Views).toHaveLength(1);
35
+ const flatLists = instance.findAllByType(FlatList);
36
+ expect(
37
+ flatLists[0].props.ListEmptyComponent.props.children.props.text1
38
+ ).toEqual('No Gateway yet');
39
+ expect(
40
+ flatLists[0].props.ListEmptyComponent.props.children.props.text2
41
+ ).toEqual("You don't have any gateway");
15
42
  });
16
43
  });
@@ -0,0 +1,83 @@
1
+ import React from 'react';
2
+ import { create, act } from 'react-test-renderer';
3
+ import { TouchableOpacity } from 'react-native';
4
+ import { SCProvider } from '../../../../../context';
5
+ import { mockSCStore } from '../../../../../context/mockStore';
6
+ import GatewayItem from '..';
7
+
8
+ const mockOnPressItem = jest.fn();
9
+
10
+ const wrapComponent = (item) => (
11
+ <SCProvider initState={mockSCStore({})}>
12
+ <GatewayItem item={item} onPress={mockOnPressItem} />
13
+ </SCProvider>
14
+ );
15
+
16
+ const mockNavigate = jest.fn();
17
+ jest.mock('@react-navigation/native', () => {
18
+ return {
19
+ ...jest.requireActual('@react-navigation/native'),
20
+ useNavigation: () => ({
21
+ navigate: mockNavigate,
22
+ }),
23
+ useIsFocused: jest.fn(),
24
+ };
25
+ });
26
+
27
+ describe('Test GatewayItem', () => {
28
+ let tree;
29
+ let item;
30
+ beforeEach(() => {
31
+ item = {
32
+ id: 1,
33
+ name: 'gatewayItem',
34
+ is_connected: false,
35
+ last_healthy: 1,
36
+ };
37
+ mockNavigate.mockClear();
38
+ });
39
+
40
+ it('test render GatewayItem connect false', async () => {
41
+ await act(async () => {
42
+ tree = await create(wrapComponent(item));
43
+ });
44
+ const instance = tree.root;
45
+
46
+ const buttons = instance.findAllByType(TouchableOpacity);
47
+ expect(buttons).toHaveLength(1);
48
+ });
49
+
50
+ it('test render GatewayItem connect true', async () => {
51
+ item = {
52
+ ...item,
53
+ is_connected: true,
54
+ };
55
+ await act(async () => {
56
+ tree = await create(wrapComponent(item));
57
+ });
58
+ const instance = tree.root;
59
+
60
+ const buttons = instance.findAllByType(TouchableOpacity);
61
+ expect(buttons).toHaveLength(1);
62
+ });
63
+
64
+ it('test render GatewayItem onPress', async () => {
65
+ item = {
66
+ id: 1,
67
+ name: 'gatewayItem',
68
+ is_connected: false,
69
+ last_healthy: 1,
70
+ };
71
+ await act(async () => {
72
+ tree = await create(wrapComponent(item));
73
+ });
74
+ const instance = tree.root;
75
+
76
+ const buttons = instance.findAllByType(TouchableOpacity);
77
+ expect(buttons).toHaveLength(1);
78
+ await act(async () => {
79
+ await buttons[0].props.onPress();
80
+ });
81
+ expect(mockOnPressItem).toHaveBeenCalled();
82
+ });
83
+ });
@@ -0,0 +1,27 @@
1
+ import React, { memo } from 'react';
2
+ import { TouchableOpacity, View } from 'react-native';
3
+ import { Colors } from '../../../../configs';
4
+ import { Text, StatusBox } from '../../../../commons';
5
+ import styles from './styles';
6
+
7
+ const GatewayItem = ({ item, onPress }) => {
8
+ return (
9
+ <View style={styles.wrap}>
10
+ <TouchableOpacity style={styles.button} onPress={onPress}>
11
+ <View style={styles.viewTitle}>
12
+ <Text type="Body" bold color={Colors.Gray9} style={styles.textTitle}>
13
+ {item?.name}
14
+ </Text>
15
+ </View>
16
+ <View style={styles.viewValue}>
17
+ <Text type="Body" color={Colors.Gray20} style={styles.textValue}>
18
+ {`${item?.last_healthy || '--'} dBm`}
19
+ </Text>
20
+ </View>
21
+ <StatusBox status={item?.is_connected} />
22
+ </TouchableOpacity>
23
+ </View>
24
+ );
25
+ };
26
+
27
+ export default memo(GatewayItem);
@@ -0,0 +1,62 @@
1
+ import { StyleSheet } from 'react-native';
2
+ import { Colors, Constants } from '../../../../configs';
3
+
4
+ export default StyleSheet.create({
5
+ wrap: {
6
+ padding: 16,
7
+ marginBottom: 16,
8
+ backgroundColor: Colors.White,
9
+ borderRadius: 8,
10
+ width: Constants.width / 2 - 24,
11
+ borderWidth: 1,
12
+ borderColor: Colors.Neutral.Neutral3,
13
+ },
14
+ button: {
15
+ flex: 1,
16
+ justifyContent: 'space-between',
17
+ },
18
+ viewTitle: {
19
+ marginBottom: 6,
20
+ },
21
+ viewValue: {
22
+ marginBottom: 6,
23
+ },
24
+ textTitle: {
25
+ lineHeight: 20,
26
+ height: 40,
27
+ fontWeight: 600,
28
+ textOverflow: 'ellipsis',
29
+ },
30
+ textValue: {
31
+ fontWeight: 400,
32
+ },
33
+ viewStatus: {
34
+ width: 65,
35
+ paddingHorizontal: 8,
36
+ paddingVertical: 4,
37
+ borderRadius: 54,
38
+ backgroundColor: Colors.White,
39
+ borderColor: Colors.Neutral.Neutral3,
40
+ borderWidth: 1,
41
+ },
42
+ textStatus: {
43
+ fontStyle: 'normal',
44
+ fontWeight: 600,
45
+ letterSpacing: 0.04,
46
+ fontSize: 12,
47
+ lineHeight: 16,
48
+ textTransform: 'uppercase',
49
+ textAlign: 'center',
50
+ },
51
+ listGateways: {
52
+ width: '100%',
53
+ paddingVertical: 16,
54
+ },
55
+ textOnline: {
56
+ fontStyle: 'bold',
57
+ },
58
+ viewOnline: {
59
+ backgroundColor: Colors.LightGreen,
60
+ borderWidth: 0,
61
+ },
62
+ });
@@ -0,0 +1,38 @@
1
+ import { useCallback, useState } from 'react';
2
+ import { axiosGet } from '../../../utils/Apis/axios';
3
+ import API from '../../../configs/API';
4
+
5
+ export default () => {
6
+ const [loading, setLoading] = useState(true);
7
+ const [gateways, setGateways] = useState([]);
8
+ const [nameSearch, setNameSearch] = useState('');
9
+ const [gatewayDetail, setGatewayDetail] = useState([]);
10
+
11
+ const fetchDataDetail = useCallback(async () => {
12
+ setLoading(true);
13
+ const { success, data } = await axiosGet(API.DEV_MODE.GATEWAY.LIST());
14
+ if (success) {
15
+ setGatewayDetail(data?.results || []);
16
+ }
17
+ setLoading(false);
18
+ }, []);
19
+
20
+ const fetchDataGateways = useCallback(async () => {
21
+ setLoading(true);
22
+ const { success, data } = await axiosGet(API.DEV_MODE.GATEWAY.LIST());
23
+ if (success) {
24
+ setGateways(data?.results || []);
25
+ }
26
+ setLoading(false);
27
+ }, []);
28
+
29
+ return {
30
+ gateways,
31
+ fetchDataGateways,
32
+ loading,
33
+ setNameSearch,
34
+ nameSearch,
35
+ gatewayDetail,
36
+ fetchDataDetail,
37
+ };
38
+ };
@@ -1,8 +1,80 @@
1
- import React from 'react';
2
- import { View } from 'react-native';
1
+ import React, { useCallback, memo, useEffect, useMemo } from 'react';
2
+ import { View, FlatList } from 'react-native';
3
+ import { useNavigation, useIsFocused } from '@react-navigation/native';
4
+ import { AccessibilityLabel } from '../../configs/Constants';
5
+ import { Colors } from '../../configs';
6
+ import { useTranslations } from '../../hooks/Common/useTranslations';
7
+ import { Text } from '../../commons';
8
+ import styles from './styles';
9
+ import { Search, EmptyComponent } from '../../commons/DevMode';
10
+ import GatewayItem from './components/GatewayItem';
11
+ import useGateway from './hooks/useGateway';
12
+ import Routes from '../../utils/Route';
3
13
 
4
- const Gateway = () => {
5
- return <View />;
14
+ const Gateway = ({ route }) => {
15
+ const t = useTranslations();
16
+ const isFocused = useIsFocused();
17
+ const { navigate } = useNavigation();
18
+ const { gateways, fetchDataGateways, setNameSearch, nameSearch } =
19
+ useGateway();
20
+
21
+ const goGoDetail = useCallback(
22
+ (item) => () => {
23
+ navigate(Routes.GatewayDetail, { item });
24
+ },
25
+ [navigate]
26
+ );
27
+
28
+ const gatewaysSearched = useMemo(() => {
29
+ return gateways.filter(
30
+ (item) =>
31
+ item?.name?.toLowerCase()?.indexOf(nameSearch?.toLowerCase()) > -1
32
+ );
33
+ }, [gateways, nameSearch]);
34
+
35
+ const renderListEmptyComponent = useMemo(() => {
36
+ return (
37
+ <View style={styles.wrapEmpty}>
38
+ <EmptyComponent
39
+ text1={t('no_gateway_yet')}
40
+ text2={t('you_dont_have_any_gateway')}
41
+ />
42
+ </View>
43
+ );
44
+ }, [t]);
45
+
46
+ const renderItem = useCallback(
47
+ ({ item, index }) => (
48
+ <GatewayItem item={item} key={index} onPress={goGoDetail(item)} />
49
+ ),
50
+ [goGoDetail]
51
+ );
52
+
53
+ useEffect(() => {
54
+ isFocused && fetchDataGateways();
55
+ }, [isFocused, fetchDataGateways]);
56
+
57
+ return (
58
+ <View
59
+ style={styles.wrap}
60
+ accessibilityLabel={AccessibilityLabel.LIST_GATEWAY}
61
+ >
62
+ <Text type="H3" bold color={Colors.Gray9} style={styles.textTitle}>
63
+ {t('gateway')}
64
+ </Text>
65
+ <Search onSearch={setNameSearch} />
66
+ <FlatList
67
+ columnWrapperStyle={styles.spaceBetween}
68
+ contentContainerStyle={styles.contentContainerStyle}
69
+ keyExtractor={(item) => item?.id}
70
+ data={gatewaysSearched}
71
+ renderItem={renderItem}
72
+ extraData={gatewaysSearched}
73
+ ListEmptyComponent={renderListEmptyComponent}
74
+ numColumns={2}
75
+ />
76
+ </View>
77
+ );
6
78
  };
7
79
 
8
- export default Gateway;
80
+ export default memo(Gateway);
@@ -0,0 +1,32 @@
1
+ import { StyleSheet } from 'react-native';
2
+ import { Colors, Constants } from '../../configs';
3
+
4
+ export default StyleSheet.create({
5
+ wrap: {
6
+ flex: 1,
7
+ paddingTop: 16,
8
+ paddingHorizontal: 16,
9
+ backgroundColor: Colors.Gray2,
10
+ },
11
+ textTitle: {
12
+ fontStyle: 'normal',
13
+ fontWeight: 650,
14
+ fontSize: 28,
15
+ lineHeight: 36,
16
+ marignBottom: 16,
17
+ },
18
+ scrollview: {
19
+ flex: 1,
20
+ },
21
+ contentContainerStyle: {
22
+ flexDirection: 'column',
23
+ },
24
+ wrapEmpty: {
25
+ justifyContent: 'center',
26
+ alignItems: 'center',
27
+ height: Constants.height - 330,
28
+ },
29
+ spaceBetween: {
30
+ justifyContent: 'space-between',
31
+ },
32
+ });
@@ -74,8 +74,9 @@ const SubUnitDetail = ({ route }) => {
74
74
 
75
75
  const onAdd = useCallback(() => {
76
76
  navigation.navigate(Routes.AddGatewayStack, {
77
- screen: Routes.FirstWarning,
77
+ screen: Routes.SelectDeviceType,
78
78
  params: {
79
+ stationName: station.name,
79
80
  stationId: station.id,
80
81
  unitId: unit.id,
81
82
  unitName: unit.name,
@@ -43,7 +43,7 @@ const AddMenu = memo(({ unit, afterItemClick, showAdd, setHideAdd }) => {
43
43
  text: t('device'),
44
44
  image: <AddDeviceIcon width={43} height={43} />,
45
45
  data: {
46
- screen: Routes.FirstWarning,
46
+ screen: Routes.SelectDeviceType,
47
47
  params: { unitId: unit?.id, unitName: unit?.name },
48
48
  },
49
49
  },
@@ -265,7 +265,9 @@ const UnitDetail = ({ route }) => {
265
265
  />
266
266
  );
267
267
  } else if (station) {
268
- return <ShortDetailSubUnit unit={unit} station={station} />;
268
+ return (
269
+ <ShortDetailSubUnit unit={unit} station={station} isOwner={isOwner} />
270
+ );
269
271
  }
270
272
  };
271
273
 
@@ -999,6 +999,10 @@
999
999
  "no_template_yet": "No Template yet",
1000
1000
  "add_your_template": "Add your template at web app",
1001
1001
  "edit_template": "Edit template",
1002
+ "no_gateway_yet": "No Gateway yet",
1003
+ "you_dont_have_any_gateway": "You don't have any gateway",
1004
+ "gateway_information": "Gateway information",
1005
+ "reboot": "Reboot",
1002
1006
  "information": "Information",
1003
1007
  "gateway_list": "Gateway list",
1004
1008
  "delete_template": "Delete template",
@@ -1035,12 +1039,24 @@
1035
1039
  "turn_off_device": "Turn off device",
1036
1040
  "turn_off_device_when_scan_qr_guide": "Turn off the device you want to add new before scanning the QR code. Press ‘’OK’’ to continue.",
1037
1041
  "connect_to_router": "Connect to the Router",
1038
- "connect_router_content": "Please plug in the gatewayand connect it to the router, making sure your phone and the gatewayare under the same network. Then, comfirm that the light is on and press “Next”",
1042
+ "connect_router_content": "Please plug in the gateway and connect it to the router, making sure your phone and the gateway are under the same network. Then, comfirm that the light is on and press “Next”",
1039
1043
  "turn_on_zigbee_device": "Turn on zigbee device",
1040
1044
  "turn_on_device_to_connect": "Turn on device to connect",
1041
1045
  "turn_on_zigbee_device_content": "Power ON the device and keep the device connected to the router. Make sure the end device still ON",
1042
1046
  "read_device_manual_guide": "Read Device's manual guide for more details.",
1047
+ "no_gateway": "No Gateway!",
1048
+ "need_add_gateway_before_add_device": "You need to add a new Gateway before adding the device.",
1043
1049
  "fail_to_discover_device_wifi": "Fail to discover device wifi",
1044
1050
  "try_to_turn_on_device_or_try_again": "Try to turn on device or Try again",
1051
+ "click_on_box_to_rename_device": "Click on the box to rename your device",
1052
+ "cannot_connect_to_device_wifi": "Cannot connect to device's wifi",
1053
+ "try_turn_on_device_or_try_again": "Try turn on device or try again",
1054
+ "fail_trigger_scan_wifi_on_device": "Fail trigger scan wifi on device",
1055
+ "fail_add_wifi_device": "Fail add wifi device",
1056
+ "connecting_wifi_device": "Connecting wifi device",
1057
+ "connecting_to_device": "Connecting to device",
1058
+ "connecting_modbus_device": "Connecting to modbus device",
1059
+ "connecting_zigbee_device": "Connecting to zigbee device",
1060
+ "connecting_to_gateway": "Connecting to gateway",
1045
1061
  "click_here_to_setup_device": "Click here to setup device"
1046
1062
  }
@@ -998,6 +998,10 @@
998
998
  "no_template_yet": "Chưa có mẫu nào",
999
999
  "add_your_template": "Thêm mẫu của bạn trên web",
1000
1000
  "edit_template": "Chỉnh sửa mẫu",
1001
+ "no_gateway_yet": "Chưa có cổng nào",
1002
+ "you_dont_have_any_gateway": "Bạn không có bất kỳ cổng nào",
1003
+ "gateway_information": "Thông tin cổng",
1004
+ "reboot": "Khởi động lại",
1001
1005
  "information": "Thông tin",
1002
1006
  "gateway_list": "Danh sách cổng vào",
1003
1007
  "delete_template": "Xóa mẫu",
@@ -1038,7 +1042,19 @@
1038
1042
  "turn_on_device_to_connect": "Bật thiết bị để kết nối",
1039
1043
  "turn_on_zigbee_device_content": "BẬT nguồn thiết bị và giữ thiết bị kết nối với bộ định tuyến. Đảm bảo thiết bị cuối vẫn BẬT",
1040
1044
  "read_device_manual_guide": "Đọc hướng dẫn sử dụng của Thiết bị để biết thêm chi tiết.",
1045
+ "no_gateway": "Không có Gateway!",
1046
+ "need_add_gateway_before_add_device": "Bạn cần thêm mới 1 Gateway trước khi thêm thiết bị.",
1041
1047
  "fail_to_discover_device_wifi": "Không phát hiện được wifi của thiết bị",
1042
1048
  "try_to_turn_on_device_or_try_again": "Thử bật thiết bị hoặc Thử lại",
1049
+ "click_on_box_to_rename_device": "Nhấp vào ô để đổi tên thiết bị của bạn",
1050
+ "cannot_connect_to_device_wifi": "Không thể kết nối với wifi của thiết bị",
1051
+ "try_turn_on_device_or_try_again": "Hãy thử bật thiết bị hoặc thử lại",
1052
+ "fail_trigger_scan_wifi_on_device": "Không kích hoạt được quét wifi trên thiết bị",
1053
+ "fail_add_wifi_device": "Không thêm được thiết bị Wi-Fi",
1054
+ "connecting_wifi_device": "Kết nối thiết bị wifi",
1055
+ "connecting_to_device": "Đang kết nối với thiết bị",
1056
+ "connecting_modbus_device": "Kết nối với thiết bị modbus",
1057
+ "connecting_zigbee_device": "Kết nối với thiết bị zigbee",
1058
+ "connecting_to_gateway": "Kết nối với gateway",
1043
1059
  "click_here_to_setup_device": "Chọn thiết bị thêm vào phòng"
1044
1060
  }
@@ -160,6 +160,7 @@ const Routes = {
160
160
  Template: 'Template',
161
161
  TemplateDetail: 'TemplateDetail',
162
162
  Gateway: 'Gateway',
163
+ GatewayDetail: 'GatewayDetail',
163
164
  Smart: 'Smart',
164
165
  TemplateStack: 'TemplateStack',
165
166
  GatewayStack: 'GatewayStack',