@eohjsc/react-native-smart-city 0.7.8 → 0.7.10

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 (85) hide show
  1. package/assets/images/AddNewDevice/add-scan-device-icon.svg +13 -0
  2. package/assets/images/Email.svg +9 -0
  3. package/assets/images/lan.svg +3 -0
  4. package/assets/images/wifi-open.svg +3 -0
  5. package/package.json +2 -1
  6. package/src/commons/ActionGroup/StatesGridActionTemplate.js +7 -3
  7. package/src/commons/ActionGroup/__test__/StatesGridActionTemplate.test.js +7 -3
  8. package/src/commons/AlertAction/index.js +1 -0
  9. package/src/commons/Auth/AccountItem.js +17 -3
  10. package/src/commons/Auth/AccountList.js +3 -7
  11. package/src/commons/ConnectWifi/__test__/ConnectWifi.test.js +373 -0
  12. package/src/commons/ConnectWifi/index.js +201 -0
  13. package/src/commons/ConnectWifi/styles.js +69 -0
  14. package/src/commons/Form/TextInputPassword.js +1 -1
  15. package/src/commons/OneTapTemplate/StatesGridActionTemplate.js +6 -2
  16. package/src/configs/API.js +12 -0
  17. package/src/configs/AccessibilityLabel.js +7 -0
  18. package/src/configs/Constants.js +1 -0
  19. package/src/hooks/Common/index.js +2 -2
  20. package/src/hooks/Common/useBlockBack.js +36 -0
  21. package/src/hooks/useMqtt.js +10 -5
  22. package/src/navigations/AddGatewayStack.js +2 -0
  23. package/src/navigations/AllGatewayStack.js +4 -0
  24. package/src/navigations/Main.js +2 -2
  25. package/src/navigations/UnitStack.js +32 -0
  26. package/src/screens/AddNewGateway/ConnectingWifiDevice.js +7 -6
  27. package/src/screens/AddNewGateway/ScanDeviceLocal.js +267 -0
  28. package/src/screens/AddNewGateway/ScanDeviceLocalStyles.js +58 -0
  29. package/src/screens/AddNewGateway/SelectDeviceSubUnit.js +10 -2
  30. package/src/screens/AddNewGateway/SelectDeviceType.js +19 -2
  31. package/src/screens/AddNewGateway/__test__/ScanDeviceLocal.test.js +475 -0
  32. package/src/screens/AddNewGateway/__test__/SelectDeviceType.test.js +2 -2
  33. package/src/screens/AddNewGateway/configs/API.js +8 -0
  34. package/src/screens/AddNewGateway/hooks/useConnectDevice.js +59 -0
  35. package/src/screens/AllGateway/GatewayInfo/__test__/index.test.js +58 -1
  36. package/src/screens/AllGateway/GatewayInfo/index.js +8 -6
  37. package/src/screens/AllGateway/GatewayWifi/__test__/index.test.js +319 -0
  38. package/src/screens/AllGateway/GatewayWifi/index.js +107 -0
  39. package/src/screens/AllGateway/Successfully/__test__/index.test.js +77 -0
  40. package/src/screens/AllGateway/Successfully/index.js +66 -0
  41. package/src/screens/AllGateway/Successfully/styles.js +35 -0
  42. package/src/screens/AllGateway/components/Information/index.js +17 -1
  43. package/src/screens/AllGateway/components/RowItem/index.js +12 -1
  44. package/src/screens/AllGateway/hooks/__test__/index.test.js +18 -0
  45. package/src/screens/AllGateway/hooks/useGateway.js +13 -0
  46. package/src/screens/Automate/AddNewAction/SetupConfigCondition.js +3 -3
  47. package/src/screens/Automate/AddNewAction/SetupScriptEmail.js +83 -0
  48. package/src/screens/Automate/AddNewAction/SetupScriptReceiverEmail.js +166 -0
  49. package/src/screens/Automate/AddNewAction/Styles/SetupScriptEmailStyles.js +37 -0
  50. package/src/screens/Automate/AddNewAction/Styles/SetupScriptReceiverEmailStyles.js +79 -0
  51. package/src/screens/Automate/AddNewAction/__test__/ChooseAction.test.js +1 -1
  52. package/src/screens/Automate/AddNewAction/__test__/SetupConfigCondition.test.js +13 -5
  53. package/src/screens/Automate/AddNewAction/__test__/SetupScriptEmail.test.js +76 -0
  54. package/src/screens/Automate/AddNewAction/__test__/SetupScriptReceiverEmail.test.js +105 -0
  55. package/src/screens/Automate/EditActionsList/Styles/UpdateReceiverEmailScriptStyles.js +78 -0
  56. package/src/screens/Automate/EditActionsList/UpdateEmailScript.js +80 -0
  57. package/src/screens/Automate/EditActionsList/UpdateReceiverEmailScript.js +179 -0
  58. package/src/screens/Automate/EditActionsList/__tests__/UpdateEmailScript.test.js +81 -0
  59. package/src/screens/Automate/EditActionsList/__tests__/UpdateReceiverEmailScript.test.js +83 -0
  60. package/src/screens/Automate/EditActionsList/__tests__/index.test.js +38 -5
  61. package/src/screens/Automate/EditActionsList/index.js +59 -2
  62. package/src/screens/Automate/ScriptDetail/Components/AddActionScript.js +20 -0
  63. package/src/screens/Automate/ScriptDetail/Styles/indexStyles.js +5 -3
  64. package/src/screens/Automate/ScriptDetail/__test__/index.test.js +127 -21
  65. package/src/screens/Automate/ScriptDetail/index.js +57 -14
  66. package/src/screens/SharedUnit/index.js +2 -2
  67. package/src/screens/Sharing/SelectUser.js +47 -47
  68. package/src/screens/Sharing/__test__/SelectUser.test.js +57 -103
  69. package/src/screens/SubUnit/ManageSubUnit.js +94 -90
  70. package/src/screens/SubUnit/ManageSubUnitStyles.js +4 -6
  71. package/src/screens/SubUnit/RearrageSubUnit.js +90 -0
  72. package/src/screens/SubUnit/RearrrageSubUnitStyle.js +65 -0
  73. package/src/screens/SubUnit/__test__/ManageSubUnit.test.js +35 -19
  74. package/src/screens/SubUnit/__test__/RearrangeSubUnit.test.js +129 -0
  75. package/src/screens/SubUnit/hooks/__test__/useManageSubUnit.test.js +6 -7
  76. package/src/screens/SubUnit/hooks/useManageSubUnit.js +8 -16
  77. package/src/screens/Unit/Detail.js +2 -6
  78. package/src/screens/Unit/ManageUnit.js +1 -1
  79. package/src/utils/Functions/__test__/ShortEmail.test.js +5 -0
  80. package/src/utils/I18n/translations/en.js +46 -8
  81. package/src/utils/I18n/translations/vi.js +37 -4
  82. package/src/utils/Route/index.js +7 -0
  83. package/src/commons/Auth/__test__/AccountItem.test.js +0 -31
  84. package/src/hooks/Common/useBlockBackAndroid.js +0 -21
  85. package/src/screens/SubUnit/DetailStyles.js +0 -46
@@ -0,0 +1,267 @@
1
+ import { useNavigation } from '@react-navigation/native';
2
+ import LottieView from 'lottie-react-native';
3
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
4
+ import {
5
+ FlatList,
6
+ TouchableOpacity,
7
+ ActivityIndicator,
8
+ View,
9
+ } from 'react-native';
10
+ import Zeroconf from 'react-native-zeroconf';
11
+ import { v4 as uuidv4 } from 'uuid';
12
+
13
+ import LanIcon from '../../../assets/images/lan.svg';
14
+ import {
15
+ FullLoading,
16
+ RadioCircle,
17
+ ViewButtonBottom,
18
+ HeaderCustom,
19
+ Text,
20
+ } from '../../commons';
21
+ import { DEVICE_TYPE } from '../../configs/Constants';
22
+ import AccessibilityLabel from '../../configs/AccessibilityLabel';
23
+ import { useTranslations } from '../../hooks/Common/useTranslations';
24
+ import LoadingCircle from '../../Images/Common/loading-circle.json';
25
+ import Routes from '../../utils/Route';
26
+ import { ToastBottomHelper } from '../../utils/Utils';
27
+ import { useConnectDevice } from './hooks/useConnectDevice';
28
+ import { useGateway } from '../AllGateway/hooks/useGateway';
29
+ import styles from './ScanDeviceLocalStyles';
30
+
31
+ let zeroconf;
32
+
33
+ const DeviceItem = ({ item, setSelectedDevice, selectedDevice }) => {
34
+ const handleSelectDevice = useCallback(
35
+ (device) => {
36
+ setSelectedDevice(device);
37
+ },
38
+ [setSelectedDevice]
39
+ );
40
+
41
+ return (
42
+ <TouchableOpacity
43
+ onPress={() => handleSelectDevice(item)}
44
+ accessibilityLabel={`${AccessibilityLabel.SELECT_DEVICE}-${item.host}`}
45
+ >
46
+ <View style={styles.listItem}>
47
+ <RadioCircle
48
+ active={selectedDevice?.host === item.host}
49
+ accessibilityLabel={`${AccessibilityLabel.SELECT_RADIO_DEVICE}-${item.host}`}
50
+ />
51
+ <View style={styles.textItem}>
52
+ <Text type="H4">{item.name}</Text>
53
+ </View>
54
+ <View style={styles.lanIcon}>
55
+ <LanIcon />
56
+ </View>
57
+ </View>
58
+ </TouchableOpacity>
59
+ );
60
+ };
61
+
62
+ const ScanDeviceLocal = ({ route }) => {
63
+ const { unit, subUnit } = route?.params || {};
64
+ const t = useTranslations();
65
+ const { navigate, goBack } = useNavigation();
66
+ const { detailChipQr, fetchChipQrDetail } = useGateway();
67
+
68
+ const [deviceList, setDeviceList] = useState([]);
69
+ const [selectedDevice, setSelectedDevice] = useState();
70
+ const [isShowLoading, setIsShowLoading] = useState(false);
71
+
72
+ const { deviceInfo, fetchDeviceInfo, sendConfigToDevice } = useConnectDevice(
73
+ selectedDevice?.host
74
+ );
75
+
76
+ const code = useMemo(() => {
77
+ return uuidv4();
78
+ }, []);
79
+
80
+ const rightDisabled = useMemo(() => {
81
+ if (!deviceInfo?.secret) {
82
+ return true;
83
+ }
84
+ return deviceInfo.secret !== detailChipQr?.secret;
85
+ }, [deviceInfo?.secret, detailChipQr?.secret]);
86
+
87
+ const goToConnectingDevice = useCallback(() => {
88
+ navigate(Routes.ConnectingWifiDevice, {
89
+ unit,
90
+ subUnit: subUnit,
91
+ addDeviceType: deviceInfo?.type,
92
+ qrData: detailChipQr,
93
+ gateway: deviceInfo,
94
+ code,
95
+ });
96
+ }, [deviceInfo, detailChipQr, code, navigate, subUnit, unit]);
97
+
98
+ const goToSelectSubUnit = useCallback(() => {
99
+ navigate(Routes.SelectDeviceSubUnit, {
100
+ unit,
101
+ deviceType: DEVICE_TYPE.SCAN_DEVICE,
102
+ qrData: detailChipQr,
103
+ gateway: deviceInfo,
104
+ code,
105
+ });
106
+ }, [deviceInfo, detailChipQr, code, navigate, unit]);
107
+
108
+ const onConnectingDevice = useCallback(async () => {
109
+ setIsShowLoading(true);
110
+ const success = await sendConfigToDevice({
111
+ token: code,
112
+ host: detailChipQr?.host,
113
+ port: detailChipQr?.port,
114
+ });
115
+ setIsShowLoading(false);
116
+ if (!success) {
117
+ ToastBottomHelper.error(t('error_sending_data_to_wifi_device'));
118
+ return;
119
+ }
120
+ if (!subUnit && deviceInfo?.type !== 'gateway') {
121
+ goToSelectSubUnit();
122
+ return;
123
+ }
124
+ goToConnectingDevice();
125
+ }, [
126
+ code,
127
+ subUnit,
128
+ deviceInfo?.type,
129
+ detailChipQr,
130
+ t,
131
+ sendConfigToDevice,
132
+ goToSelectSubUnit,
133
+ goToConnectingDevice,
134
+ ]);
135
+
136
+ const renderItem = useCallback(
137
+ ({ item }) => {
138
+ return (
139
+ <DeviceItem
140
+ item={item}
141
+ setSelectedDevice={setSelectedDevice}
142
+ selectedDevice={selectedDevice}
143
+ />
144
+ );
145
+ },
146
+ [selectedDevice, setSelectedDevice]
147
+ );
148
+
149
+ const handleGoBack = useCallback(() => {
150
+ if (zeroconf) {
151
+ zeroconf.stop();
152
+ zeroconf = null;
153
+ }
154
+ goBack();
155
+ }, [goBack]);
156
+
157
+ useEffect(() => {
158
+ try {
159
+ if (!zeroconf) {
160
+ zeroconf = new Zeroconf();
161
+ }
162
+
163
+ setDeviceList([]);
164
+
165
+ zeroconf.on('resolved', (service) => {
166
+ setDeviceList((prev) => {
167
+ const newList = [...prev];
168
+ const index = newList.findIndex(
169
+ (item) => item.host === service?.host
170
+ );
171
+ if (index === -1) {
172
+ newList.push(service);
173
+ }
174
+ return newList;
175
+ });
176
+ });
177
+
178
+ zeroconf.on('remove', (name) => {
179
+ setDeviceList((prev) => {
180
+ const newList = [...prev];
181
+ const index = newList.findIndex((item) => item.name === name);
182
+ if (index !== -1) {
183
+ newList.splice(index, 1);
184
+ }
185
+ return newList;
186
+ });
187
+ });
188
+
189
+ zeroconf.on('error', () => {
190
+ zeroconf.stop();
191
+ zeroconf.scan('plugandplay', 'tcp');
192
+ });
193
+
194
+ zeroconf.scan('plugandplay', 'tcp');
195
+ // eslint-disable-next-line no-empty
196
+ } catch (error) {}
197
+ return () => {
198
+ if (zeroconf) {
199
+ zeroconf.stop();
200
+ zeroconf = null;
201
+ }
202
+ };
203
+ }, []);
204
+
205
+ useEffect(() => {
206
+ if (selectedDevice) {
207
+ fetchDeviceInfo();
208
+ }
209
+ }, [selectedDevice, fetchDeviceInfo]);
210
+
211
+ useEffect(() => {
212
+ if (deviceInfo) {
213
+ fetchChipQrDetail(deviceInfo?.secret);
214
+ }
215
+ }, [deviceInfo, fetchChipQrDetail]);
216
+
217
+ return (
218
+ <View style={styles.container}>
219
+ <HeaderCustom
220
+ onGoBack={handleGoBack}
221
+ title={t('device_scaned')}
222
+ isShowSeparator
223
+ />
224
+ {!deviceList.length ? (
225
+ <ActivityIndicator style={styles.containerLoading} />
226
+ ) : (
227
+ <>
228
+ <Text style={styles.subTitle} type="Body">
229
+ {t('select_device_and_connect')}
230
+ </Text>
231
+ <FlatList
232
+ style={styles.listContainer}
233
+ keyExtractor={(item) => item?.host}
234
+ data={deviceList}
235
+ renderItem={renderItem}
236
+ extraData={deviceList}
237
+ numColumns={1}
238
+ />
239
+ </>
240
+ )}
241
+
242
+ <ViewButtonBottom
243
+ leftTitle={t('cancel')}
244
+ onLeftClick={handleGoBack}
245
+ rightTitle={t('connect')}
246
+ rightDisabled={rightDisabled}
247
+ onRightClick={onConnectingDevice}
248
+ accessibilityLabelPrefix={AccessibilityLabel.PREFIX.SELECT_DEVICE}
249
+ />
250
+ {isShowLoading && (
251
+ <FullLoading
252
+ styleBackground={styles.backgroundLoading}
253
+ customIcon={
254
+ <LottieView
255
+ source={LoadingCircle}
256
+ autoPlay
257
+ loop
258
+ style={styles.loading}
259
+ />
260
+ }
261
+ />
262
+ )}
263
+ </View>
264
+ );
265
+ };
266
+
267
+ export default ScanDeviceLocal;
@@ -0,0 +1,58 @@
1
+ import { StyleSheet } from 'react-native';
2
+ import { Colors } from '../../configs';
3
+
4
+ export default StyleSheet.create({
5
+ container: {
6
+ flex: 1,
7
+ backgroundColor: Colors.Gray2,
8
+ },
9
+ title: {
10
+ marginVertical: 16,
11
+ marginLeft: 16,
12
+ },
13
+ subTitle: {
14
+ fontSize: 14,
15
+ lineHeight: 22,
16
+ marginTop: 16,
17
+ marginLeft: 16,
18
+ marginBottom: 16,
19
+ },
20
+ listContainer: {
21
+ flex: 1,
22
+ borderWidth: 1,
23
+ backgroundColor: Colors.White,
24
+ borderRadius: 20,
25
+ borderColor: Colors.Gray4,
26
+ },
27
+ listItem: {
28
+ flex: 1,
29
+ flexDirection: 'row',
30
+ justifyContent: 'space-between',
31
+ alignItems: 'center',
32
+ borderBottomColor: Colors.Gray4,
33
+ borderBottomWidth: 1,
34
+ paddingVertical: 16,
35
+ marginRight: 24,
36
+ marginLeft: 16,
37
+ },
38
+ textItem: {
39
+ flex: 1,
40
+ height: 'auto',
41
+ paddingLeft: 16,
42
+ },
43
+ lanIcon: {
44
+ paddingRight: 16,
45
+ },
46
+ loading: {
47
+ width: 40,
48
+ height: 40,
49
+ },
50
+ backgroundLoading: {
51
+ backgroundColor: Colors.Gray21,
52
+ },
53
+ containerLoading: {
54
+ flex: 1,
55
+ justifyContent: 'center',
56
+ alignItems: 'center',
57
+ },
58
+ });
@@ -6,7 +6,7 @@ import Routes from '../../utils/Route';
6
6
  import { DEVICE_TYPE } from '../../configs/Constants';
7
7
 
8
8
  const SelectDeviceSubUnit = ({ route }) => {
9
- const { unit, deviceType } = route?.params || {};
9
+ const { unit, deviceType, ...rest } = route?.params || {};
10
10
  const t = useTranslations();
11
11
  const navigation = useNavigation();
12
12
  const onPressNext = useCallback(
@@ -30,9 +30,17 @@ const SelectDeviceSubUnit = ({ route }) => {
30
30
  subUnit: chosenSubUnit,
31
31
  });
32
32
  break;
33
+ case DEVICE_TYPE.SCAN_DEVICE:
34
+ navigation.navigate(Routes.ConnectingWifiDevice, {
35
+ unit,
36
+ subUnit: chosenSubUnit,
37
+ deviceType,
38
+ ...rest,
39
+ });
40
+ break;
33
41
  }
34
42
  },
35
- [deviceType, navigation, unit]
43
+ [deviceType, navigation, unit, rest]
36
44
  );
37
45
  return (
38
46
  <SelectSubUnit
@@ -11,6 +11,7 @@ import AddGatewayIcon from '../../../assets/images/AddNewDevice/add-gateway-icon
11
11
  import AddWifiDeviceIcon from '../../../assets/images/AddNewDevice/add-wifi-device-icon.svg';
12
12
  import AddModbusDeviceIcon from '../../../assets/images/AddNewDevice/add-modbus-device-icon.svg';
13
13
  import AddZigbeeDeviceIcon from '../../../assets/images/AddNewDevice/add-zigbee-device-icon.svg';
14
+ import AddScanDeviceIcon from '../../../assets/images/AddNewDevice/add-scan-device-icon.svg';
14
15
  import styles from './SelectDeviceTypeStyles';
15
16
  import AccessibilityLabel from '../../configs/AccessibilityLabel';
16
17
  import { DEVICE_TYPE } from '../../configs/Constants';
@@ -62,6 +63,7 @@ const getPermissionCode = (deviceType) => {
62
63
  case 'gateway_qr':
63
64
  return 'plug_and_play_gateway';
64
65
  case 'wifi_device_qr':
66
+ case 'scan_device':
65
67
  return 'plug_and_play_wifi';
66
68
  case 'modbus_device_qr':
67
69
  return 'plug_and_play_modbus';
@@ -132,6 +134,17 @@ const SelectDeviceType = ({ route }) => {
132
134
  title: t('zigbee'),
133
135
  subtitle: t('device_connect_remotely_to_the_gateway'),
134
136
  },
137
+ {
138
+ id: 'scan_device',
139
+ image: <AddScanDeviceIcon width={60} height={60} />,
140
+ route: Routes.ScanDeviceLocal,
141
+ data: {
142
+ unit,
143
+ subUnit,
144
+ },
145
+ title: t('scan'),
146
+ subtitle: t('device_connected_to_local_network'),
147
+ },
135
148
  ];
136
149
  if (subUnit?.id) {
137
150
  list.shift();
@@ -154,7 +167,7 @@ const SelectDeviceType = ({ route }) => {
154
167
  return false;
155
168
  }
156
169
 
157
- if (['gateway_qr', 'wifi_device_qr'].includes(itemSelect)) {
170
+ if (['gateway_qr', 'wifi_device_qr', 'scan_device'].includes(itemSelect)) {
158
171
  if (permissions?.max_chips_per_unit <= unitCountSummary?.total_chips) {
159
172
  ToastBottomHelper.error(
160
173
  t('reach_max_chips_per_unit', {
@@ -167,7 +180,11 @@ const SelectDeviceType = ({ route }) => {
167
180
  }
168
181
  }
169
182
 
170
- if (['wifi_device_qr', 'modbus_device_qr', 'zigbee'].includes(itemSelect)) {
183
+ if (
184
+ ['wifi_device_qr', 'scan_device', 'modbus_device_qr', 'zigbee'].includes(
185
+ itemSelect
186
+ )
187
+ ) {
171
188
  if (
172
189
  permissions?.max_configs_per_unit <= unitCountSummary?.total_configs
173
190
  ) {