@eohjsc/react-native-smart-city 0.3.33 → 0.3.36

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 (96) hide show
  1. package/assets/images/AddNewDevice/add-gateway-icon.svg +13 -0
  2. package/assets/images/AddNewDevice/add-modbus-device-icon.svg +8 -0
  3. package/assets/images/AddNewDevice/add-wifi-device-icon.svg +4 -0
  4. package/assets/images/AddNewDevice/add-zigbee-device-icon.svg +4 -0
  5. package/assets/images/AddNewDevice/interact-smartphone-icon.svg +14 -0
  6. package/assets/images/AddNewDevice/on-icon.svg +5 -0
  7. package/assets/images/AddNewDevice/router-connect-icon.svg +3 -0
  8. package/index.js +2 -0
  9. package/package.json +2 -1
  10. package/src/Images/SmartAccount/DienQuang.png +0 -0
  11. package/src/Images/SmartAccount/DienQuang@2x.png +0 -0
  12. package/src/Images/SmartAccount/DienQuang@3x.png +0 -0
  13. package/src/Images/SmartAccount/LG.png +0 -0
  14. package/src/Images/SmartAccount/LG@2x.png +0 -0
  15. package/src/Images/SmartAccount/LG@3x.png +0 -0
  16. package/src/Images/SmartAccount/Samsung.png +0 -0
  17. package/src/Images/SmartAccount/Samsung@2x.png +0 -0
  18. package/src/Images/SmartAccount/Samsung@3x.png +0 -0
  19. package/src/commons/Device/HorizontalBarChart.js +2 -6
  20. package/src/commons/SelectSubUnit/index.js +18 -18
  21. package/src/commons/SelectSubUnit/styles.js +0 -3
  22. package/src/commons/SelectUnit/index.js +2 -3
  23. package/src/commons/SelectUnit/styles.js +1 -2
  24. package/src/configs/API.js +10 -0
  25. package/src/configs/AccessibilityLabel.js +18 -0
  26. package/src/configs/Constants.js +2 -0
  27. package/src/configs/Images.js +2 -0
  28. package/src/context/actionType.ts +3 -0
  29. package/src/context/reducer.ts +22 -0
  30. package/src/navigations/AddGatewayStack.js +15 -0
  31. package/src/navigations/SmartAccountStack.js +52 -0
  32. package/src/screens/AddCommon/SelectSubUnit.js +17 -13
  33. package/src/screens/AddCommon/SelectUnit.js +14 -7
  34. package/src/screens/AddCommon/__test__/SelectSubUnit.test.js +18 -11
  35. package/src/screens/AddCommon/__test__/SelectUnit.test.js +13 -6
  36. package/src/screens/AddNewAction/SetupSensor.js +6 -0
  37. package/src/screens/AddNewGateway/ConnectingModbusDevice.js +0 -1
  38. package/src/screens/AddNewGateway/ConnectingWifiGuide.js +167 -0
  39. package/src/screens/AddNewGateway/ConnectingWifiGuideStyles.js +58 -0
  40. package/src/screens/AddNewGateway/PlugAndPlay/ConnectRouterGuide.js +49 -0
  41. package/src/screens/AddNewGateway/PlugAndPlay/ConnectRouterGuideStyles.js +31 -0
  42. package/src/screens/AddNewGateway/PlugAndPlay/FirstWarning.js +0 -5
  43. package/src/screens/AddNewGateway/PlugAndPlay/ZigbeeDeviceConnectGuide.js +51 -0
  44. package/src/screens/AddNewGateway/PlugAndPlay/__test__/FirstWarning.test.js +1 -1
  45. package/src/screens/AddNewGateway/ScanGatewayQR.js +23 -12
  46. package/src/screens/AddNewGateway/ScanModbusQR.js +75 -11
  47. package/src/screens/AddNewGateway/ScanWifiDeviceQR.js +19 -9
  48. package/src/screens/AddNewGateway/SelectDeviceSubUnit.js +26 -7
  49. package/src/screens/AddNewGateway/SelectDeviceType.js +145 -43
  50. package/src/screens/AddNewGateway/SelectDeviceTypeStyles.js +51 -0
  51. package/src/screens/AddNewGateway/SelectDeviceUnit.js +1 -1
  52. package/src/screens/AddNewGateway/SelectZigbeeGateway.js +1 -1
  53. package/src/screens/AddNewGateway/ShareWifiPassword.js +7 -112
  54. package/src/screens/AddNewGateway/__test__/ConnectingWifiGuide.test.js +224 -0
  55. package/src/screens/AddNewGateway/__test__/ScanGatewayQR.test.js +6 -7
  56. package/src/screens/AddNewGateway/__test__/ScanModbusQR.test.js +4 -6
  57. package/src/screens/AddNewGateway/__test__/ScanWifiDeviceQR.test.js +5 -7
  58. package/src/screens/AddNewGateway/__test__/SelectDeviceSubUnit.test.js +2 -1
  59. package/src/screens/AddNewGateway/__test__/SelectDeviceType.test.js +46 -11
  60. package/src/screens/AddNewGateway/__test__/SelectZigbeeGateway.test.js +1 -1
  61. package/src/screens/AddNewGateway/__test__/ShareWifiPassword.test.js +4 -143
  62. package/src/screens/EditActionsList/__tests__/index.test.js +120 -0
  63. package/src/screens/EditActionsList/index.js +15 -5
  64. package/src/screens/ScanChipQR/components/InvalidQRCode/index.js +33 -0
  65. package/src/screens/ScanChipQR/components/QRScan/index.js +7 -5
  66. package/src/screens/SharedUnit/__test__/ShareUnit.test.js +25 -0
  67. package/src/screens/SharedUnit/index.js +2 -0
  68. package/src/screens/Sharing/Components/DeviceItem.js +24 -8
  69. package/src/screens/Sharing/SelectPermission.js +78 -62
  70. package/src/screens/Sharing/__test__/SelectPermission.test.js +55 -2
  71. package/src/screens/SmartAccount/Connecting/index.js +171 -0
  72. package/src/screens/SmartAccount/Connecting/style.js +50 -0
  73. package/src/screens/SmartAccount/ListDevice/DeviceItem.js +45 -0
  74. package/src/screens/SmartAccount/ListDevice/__test__/DeviceItem.test.js +34 -0
  75. package/src/screens/SmartAccount/ListDevice/__test__/ListDevice.test.js +139 -0
  76. package/src/screens/SmartAccount/ListDevice/index.js +185 -0
  77. package/src/screens/SmartAccount/ListDevice/styles/DeviceItemStyles.js +70 -0
  78. package/src/screens/SmartAccount/ListDevice/styles/index.js +85 -0
  79. package/src/screens/SmartAccount/SuccessfullyConnected/DeviceItem.js +37 -0
  80. package/src/screens/SmartAccount/SuccessfullyConnected/DeviceItemStyles.js +49 -0
  81. package/src/screens/SmartAccount/SuccessfullyConnected/__test__/DeviceItem.test.js +65 -0
  82. package/src/screens/SmartAccount/SuccessfullyConnected/__test__/SuccessfullyConnected.test.js +88 -0
  83. package/src/screens/SmartAccount/SuccessfullyConnected/index.js +101 -0
  84. package/src/screens/SmartAccount/SuccessfullyConnected/styles.js +42 -0
  85. package/src/screens/SmartAccount/__test__/Connecting.test.js +86 -0
  86. package/src/screens/SmartAccount/__test__/SmartAccount.test.js +249 -0
  87. package/src/screens/SmartAccount/index.js +172 -0
  88. package/src/screens/SmartAccount/style.js +70 -0
  89. package/src/screens/SyncLGDevice/__test__/AddLGDevice.test.js +37 -10
  90. package/src/screens/Unit/AddMenu.js +4 -5
  91. package/src/screens/Unit/SmartAccount.js +8 -5
  92. package/src/screens/Unit/__test__/SmartAccount.test.js +8 -5
  93. package/src/utils/I18n/translations/en.json +35 -2
  94. package/src/utils/I18n/translations/vi.json +36 -2
  95. package/src/utils/Route/index.js +6 -0
  96. package/src/utils/Validation.js +4 -0
@@ -0,0 +1,171 @@
1
+ import React, { useEffect, useCallback, useContext } from 'react';
2
+ import { SafeAreaView, View } from 'react-native';
3
+ import { useNavigation } from '@react-navigation/native';
4
+ import * as Progress from 'react-native-progress';
5
+ import AnimatedEllipsis from 'react-native-animated-ellipsis';
6
+
7
+ import Text from '../../../commons/Text';
8
+ import { useTranslations } from '../../../hooks/Common/useTranslations';
9
+ import { Action } from '../../../context/actionType';
10
+ import { SCContext, useSCContextSelector } from '../../../context';
11
+ import { axiosPost } from '../../../utils/Apis/axios';
12
+ import { API, Colors, Constants } from '../../../configs';
13
+ import Routes from '../../../utils/Route';
14
+ import { ToastBottomHelper } from '../../../utils/Utils';
15
+ import styles from './style';
16
+
17
+ const SmartAccountConnecting = ({ route }) => {
18
+ const t = useTranslations();
19
+ const { setAction } = useContext(SCContext);
20
+ const { navigate } = useNavigation();
21
+ const percent = useSCContextSelector((state) => state.percent);
22
+
23
+ const {
24
+ username,
25
+ password,
26
+ brand,
27
+ unit_id,
28
+ listDeviceIds,
29
+ stationId,
30
+ nameSubUnit,
31
+ listSelectDevice,
32
+ smart_account_id,
33
+ smart_account_id_from_backend,
34
+ device_data,
35
+ } = route.params;
36
+
37
+ const handleRefreshPercent = useCallback(() => {
38
+ const to = setTimeout(() => {
39
+ setAction(Action.REFRESH_PERCENT);
40
+ clearTimeout(to);
41
+ }, 1500);
42
+ // eslint-disable-next-line react-hooks/exhaustive-deps
43
+ }, []);
44
+
45
+ const connectingAccount = useCallback(async () => {
46
+ setAction(Action.PERCENT_LOADED);
47
+ const { success, data } = await axiosPost(API.SMART_ACCOUNT.SYNC, {
48
+ username: username,
49
+ password: password,
50
+ brand: brand,
51
+ unit: unit_id,
52
+ });
53
+
54
+ if (success) {
55
+ setAction(Action.PROCESS_DONE);
56
+ const timeConnecting = setTimeout(() => {
57
+ navigate(Routes.ListDeviceSmartAccount, {
58
+ username: username,
59
+ brand: brand,
60
+ device_data: data.sensors_unidentified || device_data,
61
+ unit_id: unit_id,
62
+ smart_account_id_from_backend: data.smart_account_id,
63
+ });
64
+
65
+ clearTimeout(timeConnecting);
66
+ }, 1000);
67
+ } else {
68
+ navigate(Routes.SmartAccount, {
69
+ params: {},
70
+ });
71
+ ToastBottomHelper.error(data[Object.keys(data)[0]][0]);
72
+ }
73
+ handleRefreshPercent();
74
+ // eslint-disable-next-line react-hooks/exhaustive-deps
75
+ }, [brand, navigate, password, unit_id, username]);
76
+
77
+ const addDeviceToStation = useCallback(async () => {
78
+ setAction(Action.PERCENT_LOADED);
79
+ const { success } = await axiosPost(
80
+ API.SMART_ACCOUNT.ADD_DEVICE_TO_STATION,
81
+ {
82
+ sensor_ids: listDeviceIds,
83
+ station: stationId,
84
+ }
85
+ );
86
+ if (success) {
87
+ setAction(Action.PROCESS_DONE);
88
+ const timeAddDevice = setTimeout(() => {
89
+ navigate(Routes.SuccessfullyConnected, {
90
+ nameSubUnit: nameSubUnit,
91
+ listDeviceIds: listDeviceIds,
92
+ listSelectDevice,
93
+ smart_account_id: smart_account_id,
94
+ smart_account_id_from_backend: smart_account_id_from_backend,
95
+ unit_id: unit_id,
96
+ stationId,
97
+ username,
98
+ brand,
99
+ });
100
+ clearTimeout(timeAddDevice);
101
+ }, 1000);
102
+ }
103
+ handleRefreshPercent();
104
+ // eslint-disable-next-line react-hooks/exhaustive-deps
105
+ }, [
106
+ listSelectDevice,
107
+ listDeviceIds,
108
+ nameSubUnit,
109
+ navigate,
110
+ smart_account_id,
111
+ smart_account_id_from_backend,
112
+ unit_id,
113
+ stationId,
114
+ ]);
115
+
116
+ useEffect(() => {
117
+ if (percent && percent !== 1) {
118
+ const to = setTimeout(() => {
119
+ setAction(Action.PERCENT_LOADED);
120
+ clearTimeout(to);
121
+ }, 1000);
122
+ }
123
+ }, [percent, setAction]);
124
+
125
+ useEffect(() => {
126
+ if (listDeviceIds) {
127
+ addDeviceToStation();
128
+ } else {
129
+ connectingAccount();
130
+ }
131
+ }, [addDeviceToStation, connectingAccount, listDeviceIds]);
132
+
133
+ return (
134
+ <SafeAreaView style={styles.wrap}>
135
+ <View style={styles.boxText}>
136
+ <Text bold style={styles.connectingText}>
137
+ {t('connecting_smart_account')}
138
+ </Text>
139
+ <AnimatedEllipsis style={styles.animatedEllipsis} />
140
+ </View>
141
+
142
+ <Text style={styles.warningText}>
143
+ {t('warning_connecting_smart_account')}
144
+ </Text>
145
+ <View style={styles.progressBar}>
146
+ <View style={styles.connecting}>
147
+ <Text type="H4" bold>
148
+ {t('continue')}
149
+ </Text>
150
+ </View>
151
+ </View>
152
+ <View style={styles.percentLoad}>
153
+ <Progress.Bar
154
+ progress={percent}
155
+ animated={true}
156
+ color={Colors.Primary}
157
+ indeterminateAnimationDuration={1000}
158
+ height={7}
159
+ width={Constants.width - 80}
160
+ useNativeDriver={true}
161
+ />
162
+ <Text style={styles.textPercentLoad}>{`${parseInt(
163
+ percent * 100,
164
+ 10
165
+ )}%`}</Text>
166
+ </View>
167
+ </SafeAreaView>
168
+ );
169
+ };
170
+
171
+ export default SmartAccountConnecting;
@@ -0,0 +1,50 @@
1
+ import { StyleSheet } from 'react-native';
2
+ import { getStatusBarHeight } from 'react-native-iphone-x-helper';
3
+ import { Colors } from '../../../configs';
4
+
5
+ export default StyleSheet.create({
6
+ wrap: {
7
+ paddingTop: getStatusBarHeight(true),
8
+ backgroundColor: Colors.White,
9
+ width: '100%',
10
+ height: '100%',
11
+ },
12
+ connectingText: {
13
+ marginLeft: 30,
14
+ marginTop: 16,
15
+ fontSize: 20,
16
+ color: Colors.Gray9,
17
+ },
18
+ animatedEllipsis: {
19
+ fontSize: 25,
20
+ color: Colors.Gray9,
21
+ marginTop: 14,
22
+ },
23
+ warningText: {
24
+ marginHorizontal: 30,
25
+ marginTop: 16,
26
+ fontSize: 14,
27
+ color: Colors.Gray8,
28
+ },
29
+ boxText: {
30
+ flexDirection: 'row',
31
+ },
32
+ progressBar: {
33
+ flexDirection: 'column',
34
+ marginTop: 180,
35
+ marginHorizontal: 30,
36
+ },
37
+ connecting: {
38
+ flexDirection: 'row',
39
+ justifyContent: 'center',
40
+ marginBottom: 10,
41
+ },
42
+ percentLoad: {
43
+ flexDirection: 'row',
44
+ justifyContent: 'center',
45
+ alignItems: 'center',
46
+ },
47
+ textPercentLoad: {
48
+ marginLeft: 10,
49
+ },
50
+ });
@@ -0,0 +1,45 @@
1
+ import React, { memo } from 'react';
2
+ import { TouchableOpacity, View } from 'react-native';
3
+ import FImage from '../../../commons/FImage';
4
+ import Text from '../../../commons/Text';
5
+ import AccessibilityLabel from '../../../configs/AccessibilityLabel';
6
+ import { useTranslations } from '../../../hooks/Common/useTranslations';
7
+ import styles from './styles/DeviceItemStyles';
8
+
9
+ const DeviceItem = memo(
10
+ ({ id, name, setListSelectedDevice, isSelected, icon, item }) => {
11
+ const t = useTranslations();
12
+
13
+ return (
14
+ <TouchableOpacity
15
+ onPress={() => setListSelectedDevice(id, item)}
16
+ accessibilityLabel={AccessibilityLabel.TOUCH_SELECT_ITEM_SMART_ACCOUNT}
17
+ >
18
+ <View
19
+ style={[
20
+ styles.container,
21
+ isSelected ? styles.colorSelected : styles.colorUnSelected,
22
+ ]}
23
+ >
24
+ <View style={styles.opticalPower}>
25
+ <FImage source={{ uri: icon }} style={styles.iconSensor} />
26
+ <View
27
+ style={[
28
+ styles.circle,
29
+ isSelected ? styles.circle : styles.circleNotChange,
30
+ ]}
31
+ />
32
+ </View>
33
+ <Text type="H4" semibold style={styles.nameSensor}>
34
+ {name}
35
+ </Text>
36
+ <Text type="Label" style={styles.redText}>
37
+ {t('click_here_to_setup_device')}
38
+ </Text>
39
+ </View>
40
+ </TouchableOpacity>
41
+ );
42
+ }
43
+ );
44
+
45
+ export default DeviceItem;
@@ -0,0 +1,34 @@
1
+ import React from 'react';
2
+ import { act, create } from 'react-test-renderer';
3
+ import Text from '../../../../commons/Text';
4
+ import { SCProvider } from '../../../../context';
5
+ import { mockSCStore } from '../../../../context/mockStore';
6
+ import DeviceItem from '../DeviceItem';
7
+
8
+ const wrapComponent = (props) => (
9
+ <SCProvider initState={mockSCStore({})}>
10
+ <DeviceItem {...props} />
11
+ </SCProvider>
12
+ );
13
+
14
+ jest.mock('react', () => {
15
+ return {
16
+ ...jest.requireActual('react'),
17
+ memo: (x) => x,
18
+ };
19
+ });
20
+
21
+ test('test DeviceItem', () => {
22
+ let tree;
23
+ let props = {
24
+ icon: '',
25
+ name: 'test',
26
+ itemId: 2,
27
+ };
28
+ act(() => {
29
+ tree = create(wrapComponent(props));
30
+ });
31
+ const instance = tree.root;
32
+ const texts = instance.findAllByType(Text);
33
+ expect(texts).toHaveLength(4);
34
+ });
@@ -0,0 +1,139 @@
1
+ import React from 'react';
2
+ import renderer, { act } from 'react-test-renderer';
3
+ import { SafeAreaView, TouchableOpacity } from 'react-native';
4
+
5
+ import ListDevice from '../index';
6
+ import { SCProvider } from '../../../../context';
7
+ import { mockSCStore } from '../../../../context/mockStore';
8
+ import Text from '../../../../commons/Text';
9
+ import api from '../../../../utils/Apis/axios';
10
+ import { API } from '../../../../configs';
11
+ import Routes from '../../../../utils/Route';
12
+ import MockAdapter from 'axios-mock-adapter';
13
+ import AccessibilityLabel from '../../../../configs/AccessibilityLabel';
14
+
15
+ const mock = new MockAdapter(api.axiosInstance);
16
+
17
+ const mockedNavigate = jest.fn();
18
+ jest.mock('@react-navigation/native', () => {
19
+ return {
20
+ ...jest.requireActual('@react-navigation/native'),
21
+ useNavigation: () => ({
22
+ navigate: mockedNavigate,
23
+ }),
24
+ useIsFocused: () => true,
25
+ };
26
+ });
27
+
28
+ const wrapComponent = (route) => (
29
+ <SCProvider initState={mockSCStore({})}>
30
+ <ListDevice route={route} />
31
+ </SCProvider>
32
+ );
33
+
34
+ describe('Test ListDeviceSmartAccount', () => {
35
+ let tree;
36
+ afterEach(() => {
37
+ mockedNavigate.mockClear();
38
+ });
39
+ test('render ListDeviceSmartAccount', () => {
40
+ const route = {
41
+ params: {
42
+ username: 'abc',
43
+ password: '123456',
44
+ brand: '',
45
+ smart_account_id: 1,
46
+ device_data: [
47
+ { id: 1, name: 'sensor 1' },
48
+ { id: 2, name: 'sensor 2' },
49
+ ],
50
+ },
51
+ };
52
+ act(() => {
53
+ tree = renderer.create(wrapComponent(route));
54
+ });
55
+ const instance = tree.root;
56
+ const texts = instance.findAllByType(Text);
57
+ const safeAreaView = instance.findAllByType(SafeAreaView);
58
+ expect(texts).toHaveLength(12);
59
+ expect(safeAreaView).toHaveLength(1);
60
+ });
61
+
62
+ test('render ListDevice has not device_data', async () => {
63
+ const route = {
64
+ params: {
65
+ username: 'abc',
66
+ password: '123456',
67
+ brand: '',
68
+ smart_account_id: 1,
69
+ },
70
+ };
71
+ mock
72
+ .onGet(API.SMART_ACCOUNT.FETCH_UNIDENTIFIED_DEVICE_OF_SMART_ACCOUNT(1))
73
+ .reply(200, [
74
+ { id: 1, name: 'sensor 1' },
75
+ { id: 2, name: 'sensor 2' },
76
+ ]);
77
+ act(() => {
78
+ tree = renderer.create(wrapComponent(route));
79
+ });
80
+
81
+ const instance = tree.root;
82
+ const safeAreaView = instance.findAllByType(SafeAreaView);
83
+ const buttons = instance.findAllByType(TouchableOpacity);
84
+ await buttons[2].props.onPress();
85
+ const touchs = instance.find(
86
+ (el) =>
87
+ el.props.accessibilityLabel === AccessibilityLabel.TOUCH_SELECT_ALL &&
88
+ el.type === TouchableOpacity
89
+ );
90
+ await act(async () => {
91
+ await touchs.props.onPress();
92
+ });
93
+
94
+ expect(safeAreaView).toHaveLength(1);
95
+ expect(mockedNavigate).toBeCalledWith(Routes.AddDeviceStack, {
96
+ screen: Routes.AddCommonSelectSubUnit,
97
+ params: {
98
+ addType: 'AddHassiDevice',
99
+ brand: '',
100
+ listSelectDevice: [],
101
+ listDeviceIds: [],
102
+ device_data: undefined,
103
+ smart_account_id: 1,
104
+ smart_account_id_from_backend: undefined,
105
+ unit_id: undefined,
106
+ username: 'abc',
107
+ },
108
+ });
109
+ });
110
+
111
+ test('render handle Selected device', () => {
112
+ const route = {
113
+ params: {
114
+ username: 'abc',
115
+ password: '123456',
116
+ brand: '',
117
+ smart_account_id: 1,
118
+ device_data: [
119
+ { id: 1, name: 'sensor 1' },
120
+ { id: 2, name: 'sensor 2' },
121
+ ],
122
+ },
123
+ };
124
+ act(() => {
125
+ tree = renderer.create(wrapComponent(route));
126
+ });
127
+ const instance = tree.root;
128
+ const touchSelectItem = instance.findAll(
129
+ (el) =>
130
+ el.props.accessibilityLabel ===
131
+ AccessibilityLabel.TOUCH_SELECT_ITEM_SMART_ACCOUNT &&
132
+ el.type === TouchableOpacity
133
+ );
134
+ act(async () => {
135
+ await touchSelectItem[0].props.onPress(1, { id: 1, name: 'sensor 1' });
136
+ });
137
+ expect(touchSelectItem).toBeDefined();
138
+ });
139
+ });
@@ -0,0 +1,185 @@
1
+ import React, { useCallback, useEffect, useRef, useState } from 'react';
2
+ import { View, Image, TouchableOpacity } from 'react-native';
3
+ import { useNavigation, useIsFocused } from '@react-navigation/native';
4
+
5
+ import { useTranslations } from '../../../hooks/Common/useTranslations';
6
+ import { Button } from '../../../commons';
7
+ import Text from '../../../commons/Text';
8
+ import WrapHeaderScrollable from '../../../commons/Sharing/WrapHeaderScrollable';
9
+ import DeviceItem from './DeviceItem';
10
+ import { API, Colors, Images } from '../../../configs';
11
+ import { axiosGet } from '../../../utils/Apis/axios';
12
+ import Routes from '../../../utils/Route';
13
+ import styles from './styles/index';
14
+ import AccessibilityLabel from '../../../configs/AccessibilityLabel';
15
+
16
+ const ListDeviceSmartAccount = ({ route }) => {
17
+ const {
18
+ username,
19
+ brand,
20
+ device_data,
21
+ unit_id,
22
+ smart_account_id,
23
+ smart_account_id_from_backend,
24
+ } = route.params;
25
+ const t = useTranslations();
26
+ const isFocused = useIsFocused();
27
+ const [listSelectedDevice, setListSelectedDevice] = useState([]);
28
+ const [listDeviceSuccess, setListDeviceSuccess] = useState([]);
29
+ const [listDevices, setListDevices] = useState(device_data || []);
30
+ const { navigate, goBack } = useNavigation();
31
+ let circleOfSelectAll = useRef(false);
32
+ // eslint-disable-next-line react-hooks/exhaustive-deps
33
+ const listSelectAll = [];
34
+
35
+ const fetchSensorData = useCallback(async () => {
36
+ const { success, data } = await axiosGet(
37
+ API.SMART_ACCOUNT.FETCH_UNIDENTIFIED_DEVICE_OF_SMART_ACCOUNT(
38
+ smart_account_id
39
+ )
40
+ );
41
+ if (success) {
42
+ setListDevices(data);
43
+ }
44
+ }, [smart_account_id]);
45
+
46
+ useEffect(() => {
47
+ if (!device_data && smart_account_id && isFocused) {
48
+ fetchSensorData();
49
+ setListDeviceSuccess([]);
50
+ setListSelectedDevice([]);
51
+ }
52
+ }, [fetchSensorData, isFocused, device_data, smart_account_id]);
53
+
54
+ const handleSelectedDevice = useCallback(
55
+ (id, item) => {
56
+ if (listSelectedDevice.includes(id)) {
57
+ setListSelectedDevice((oldArray) =>
58
+ oldArray.filter((itemDevice) => itemDevice !== id)
59
+ );
60
+ setListDeviceSuccess((oldArray) =>
61
+ oldArray.filter((itemDevice) => itemDevice !== item)
62
+ );
63
+ circleOfSelectAll.current = false;
64
+ } else {
65
+ setListSelectedDevice((oldArray) => [...oldArray, id]);
66
+ setListDeviceSuccess((oldArray) => [...oldArray, item]);
67
+ if (listDevices.length - 1 === listSelectedDevice.length) {
68
+ circleOfSelectAll.current = true;
69
+ }
70
+ }
71
+ },
72
+ [listSelectedDevice, listDevices.length]
73
+ );
74
+
75
+ const gotoSelectSubUnit = useCallback(() => {
76
+ navigate(Routes.AddDeviceStack, {
77
+ screen: Routes.AddCommonSelectSubUnit,
78
+ params: {
79
+ username,
80
+ brand,
81
+ listDeviceIds: listSelectedDevice,
82
+ unit_id: unit_id,
83
+ addType: 'AddHassiDevice',
84
+ device_data: device_data,
85
+ smart_account_id: smart_account_id,
86
+ listSelectDevice: listDeviceSuccess,
87
+ smart_account_id_from_backend: smart_account_id_from_backend,
88
+ },
89
+ });
90
+ }, [
91
+ brand,
92
+ listDeviceSuccess,
93
+ listSelectedDevice,
94
+ navigate,
95
+ device_data,
96
+ smart_account_id,
97
+ smart_account_id_from_backend,
98
+ unit_id,
99
+ username,
100
+ ]);
101
+
102
+ const handleSelectAll = useCallback(() => {
103
+ for (let i = 0; i < listDevices.length; i++) {
104
+ listSelectAll.push(listDevices[i].id);
105
+ }
106
+ if (listSelectAll.length !== listSelectedDevice.length) {
107
+ setListSelectedDevice(listSelectAll);
108
+ setListDeviceSuccess(listDevices);
109
+ circleOfSelectAll.current = true;
110
+ }
111
+ if (listSelectAll.length === listSelectedDevice.length) {
112
+ setListSelectedDevice([]);
113
+ setListDeviceSuccess([]);
114
+ circleOfSelectAll.current = false;
115
+ }
116
+ }, [listSelectAll, listSelectedDevice.length, listDevices]);
117
+
118
+ return (
119
+ <View style={styles.wrap}>
120
+ <WrapHeaderScrollable
121
+ onLeft={() => (device_data ? navigate(Routes.Dashboard) : goBack())}
122
+ title={brand === 'google_home' && 'Điện Quang'}
123
+ headerAniStyle={styles.headerAniStyle}
124
+ >
125
+ <View style={styles.contentContainer}>
126
+ <View style={styles.rowUsername}>
127
+ <Image width={50} source={Images.dienquang} />
128
+ <Text style={styles.textUsername}>{username}</Text>
129
+ </View>
130
+ <View style={styles.containerTypeDevice}>
131
+ <View style={styles.typeDeviceItem}>
132
+ <Text type="Body" color={Colors.Green7}>
133
+ {t('unidentified')}
134
+ </Text>
135
+ </View>
136
+ </View>
137
+ <View style={styles.textAllDevice}>
138
+ <Text style={styles.allDevices} type="H3">
139
+ {`${t('text_all_devices')} (${
140
+ device_data ? device_data.length : listDevices.length
141
+ })`}
142
+ </Text>
143
+ <TouchableOpacity
144
+ onPress={handleSelectAll}
145
+ style={styles.selectAll}
146
+ accessibilityLabel={AccessibilityLabel.TOUCH_SELECT_ALL}
147
+ >
148
+ <View
149
+ style={[
150
+ circleOfSelectAll.current
151
+ ? styles.circle
152
+ : styles.circleNotChange,
153
+ ]}
154
+ />
155
+ <Text style={styles.allDevices} type="H3">
156
+ {t('select_all')}
157
+ </Text>
158
+ </TouchableOpacity>
159
+ </View>
160
+ <View style={styles.boxDevices}>
161
+ {(device_data ? device_data : listDevices).map((item) => (
162
+ <DeviceItem
163
+ id={item.id}
164
+ name={item.name}
165
+ icon={item.icon_kit}
166
+ item={item}
167
+ setListSelectedDevice={handleSelectedDevice}
168
+ isSelected={listSelectedDevice.includes(item.id)}
169
+ />
170
+ ))}
171
+ </View>
172
+ </View>
173
+ </WrapHeaderScrollable>
174
+ <View style={styles.btnFixed}>
175
+ <Button
176
+ onPress={gotoSelectSubUnit}
177
+ type={listSelectedDevice.length ? 'primary' : 'disabled'}
178
+ title={t('next')}
179
+ />
180
+ </View>
181
+ </View>
182
+ );
183
+ };
184
+
185
+ export default ListDeviceSmartAccount;
@@ -0,0 +1,70 @@
1
+ import { StyleSheet } from 'react-native';
2
+ import { Colors, Constants } from '../../../../configs';
3
+
4
+ const marginItem = 12;
5
+ const marginHorizontal = 16;
6
+ const widthItem = (Constants.width - marginHorizontal * 2 - marginItem) / 2;
7
+ const heightItem = (widthItem / 166) * 145;
8
+
9
+ export default StyleSheet.create({
10
+ container: {
11
+ padding: 12,
12
+ borderRadius: 10,
13
+ shadowRadius: 1,
14
+ width: widthItem,
15
+ height: heightItem,
16
+ borderWidth: 1,
17
+ borderColor: Colors.Gray4,
18
+ backgroundColor: Colors.White,
19
+ justifyContent: 'space-between',
20
+ marginBottom: 16,
21
+ },
22
+ colorUnSelected: {
23
+ shadowColor: Colors.Shadow,
24
+ shadowOpacity: 0.3,
25
+ shadowOffset: {
26
+ width: 0,
27
+ height: 2,
28
+ },
29
+ },
30
+ colorSelected: {
31
+ shadowColor: Colors.Green,
32
+ shadowOpacity: 1,
33
+ shadowOffset: {
34
+ width: 0,
35
+ height: 0,
36
+ },
37
+ },
38
+ iconSensor: {
39
+ width: 40,
40
+ height: 40,
41
+ resizeMode: 'contain',
42
+ },
43
+ nameSensor: {
44
+ color: Colors.Gray9,
45
+ marginTop: 5,
46
+ },
47
+ redText: {
48
+ color: Colors.Red,
49
+ },
50
+ opticalPower: {
51
+ flexDirection: 'row',
52
+ justifyContent: 'space-between',
53
+ },
54
+ circle: {
55
+ backgroundColor: Colors.Primary,
56
+ width: 15,
57
+ height: 15,
58
+ borderRadius: 15,
59
+ borderWidth: 1,
60
+ borderColor: Colors.Primary,
61
+ },
62
+ circleNotChange: {
63
+ backgroundColor: Colors.White,
64
+ width: 15,
65
+ height: 15,
66
+ borderRadius: 15,
67
+ borderWidth: 1,
68
+ borderColor: Colors.Gray6,
69
+ },
70
+ });