@eohjsc/react-native-smart-city 0.7.7 → 0.7.9
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.
- package/assets/images/AddNewDevice/add-scan-device-icon.svg +13 -0
- package/assets/images/Email.svg +9 -0
- package/assets/images/lan.svg +3 -0
- package/assets/images/wifi-open.svg +3 -0
- package/package.json +4 -3
- package/src/commons/ActionGroup/StatesGridActionTemplate.js +7 -3
- package/src/commons/ActionGroup/__test__/StatesGridActionTemplate.test.js +7 -3
- package/src/commons/AlertAction/index.js +1 -0
- package/src/commons/Auth/AccountItem.js +17 -3
- package/src/commons/Auth/AccountList.js +3 -7
- package/src/commons/ConnectWifi/__test__/ConnectWifi.test.js +373 -0
- package/src/commons/ConnectWifi/index.js +201 -0
- package/src/commons/ConnectWifi/styles.js +69 -0
- package/src/commons/Device/LabelValue/__test__/LabelValue.test.js +74 -0
- package/src/commons/Device/LabelValue/index.js +49 -0
- package/src/commons/Device/LabelValue/styles.js +33 -0
- package/src/commons/Form/TextInputPassword.js +1 -1
- package/src/commons/OneTapTemplate/StatesGridActionTemplate.js +6 -2
- package/src/configs/API.js +12 -0
- package/src/configs/AccessibilityLabel.js +7 -0
- package/src/configs/Constants.js +1 -0
- package/src/hooks/Common/index.js +2 -2
- package/src/hooks/Common/useBlockBack.js +36 -0
- package/src/hooks/useMqtt.js +10 -5
- package/src/navigations/AddGatewayStack.js +2 -0
- package/src/navigations/AllGatewayStack.js +4 -0
- package/src/navigations/Main.js +2 -2
- package/src/navigations/UnitStack.js +32 -0
- package/src/screens/AddNewGateway/ConnectingWifiDevice.js +7 -6
- package/src/screens/AddNewGateway/ScanDeviceLocal.js +267 -0
- package/src/screens/AddNewGateway/ScanDeviceLocalStyles.js +58 -0
- package/src/screens/AddNewGateway/SelectDeviceSubUnit.js +10 -2
- package/src/screens/AddNewGateway/SelectDeviceType.js +19 -2
- package/src/screens/AddNewGateway/__test__/ScanDeviceLocal.test.js +475 -0
- package/src/screens/AddNewGateway/__test__/SelectDeviceType.test.js +2 -2
- package/src/screens/AddNewGateway/configs/API.js +8 -0
- package/src/screens/AddNewGateway/hooks/useConnectDevice.js +59 -0
- package/src/screens/AllGateway/GatewayInfo/__test__/index.test.js +58 -1
- package/src/screens/AllGateway/GatewayInfo/index.js +8 -6
- package/src/screens/AllGateway/GatewayWifi/__test__/index.test.js +319 -0
- package/src/screens/AllGateway/GatewayWifi/index.js +107 -0
- package/src/screens/AllGateway/Successfully/__test__/index.test.js +77 -0
- package/src/screens/AllGateway/Successfully/index.js +66 -0
- package/src/screens/AllGateway/Successfully/styles.js +35 -0
- package/src/screens/AllGateway/components/Information/index.js +17 -1
- package/src/screens/AllGateway/components/RowItem/index.js +12 -1
- package/src/screens/AllGateway/hooks/__test__/index.test.js +18 -0
- package/src/screens/AllGateway/hooks/useGateway.js +13 -0
- package/src/screens/Automate/AddNewAction/SetupConfigCondition.js +3 -3
- package/src/screens/Automate/AddNewAction/SetupScriptEmail.js +79 -0
- package/src/screens/Automate/AddNewAction/SetupScriptReceiverEmail.js +166 -0
- package/src/screens/Automate/AddNewAction/Styles/SetupScriptEmailStyles.js +37 -0
- package/src/screens/Automate/AddNewAction/Styles/SetupScriptReceiverEmailStyles.js +79 -0
- package/src/screens/Automate/AddNewAction/__test__/ChooseAction.test.js +1 -1
- package/src/screens/Automate/AddNewAction/__test__/SetupConfigCondition.test.js +13 -5
- package/src/screens/Automate/AddNewAction/__test__/SetupScriptEmail.test.js +76 -0
- package/src/screens/Automate/AddNewAction/__test__/SetupScriptReceiverEmail.test.js +105 -0
- package/src/screens/Automate/EditActionsList/Styles/UpdateReceiverEmailScriptStyles.js +78 -0
- package/src/screens/Automate/EditActionsList/UpdateEmailScript.js +80 -0
- package/src/screens/Automate/EditActionsList/UpdateReceiverEmailScript.js +179 -0
- package/src/screens/Automate/EditActionsList/__tests__/UpdateEmailScript.test.js +81 -0
- package/src/screens/Automate/EditActionsList/__tests__/UpdateReceiverEmailScript.test.js +83 -0
- package/src/screens/Automate/EditActionsList/__tests__/index.test.js +38 -5
- package/src/screens/Automate/EditActionsList/index.js +59 -2
- package/src/screens/Automate/ScriptDetail/Components/AddActionScript.js +20 -0
- package/src/screens/Automate/ScriptDetail/Styles/indexStyles.js +5 -3
- package/src/screens/Automate/ScriptDetail/__test__/index.test.js +127 -21
- package/src/screens/Automate/ScriptDetail/index.js +57 -14
- package/src/screens/Device/__test__/sensorDisplayItem.test.js +22 -0
- package/src/screens/Device/components/SensorDisplayItem.js +10 -0
- package/src/screens/SharedUnit/index.js +2 -2
- package/src/screens/Sharing/SelectUser.js +47 -47
- package/src/screens/Sharing/__test__/SelectUser.test.js +57 -103
- package/src/screens/SubUnit/ManageSubUnit.js +94 -90
- package/src/screens/SubUnit/ManageSubUnitStyles.js +4 -6
- package/src/screens/SubUnit/RearrageSubUnit.js +90 -0
- package/src/screens/SubUnit/RearrrageSubUnitStyle.js +65 -0
- package/src/screens/SubUnit/__test__/ManageSubUnit.test.js +35 -19
- package/src/screens/SubUnit/__test__/RearrangeSubUnit.test.js +129 -0
- package/src/screens/SubUnit/hooks/__test__/useManageSubUnit.test.js +6 -7
- package/src/screens/SubUnit/hooks/useManageSubUnit.js +8 -16
- package/src/screens/Unit/Detail.js +2 -6
- package/src/screens/Unit/ManageUnit.js +1 -1
- package/src/utils/Functions/__test__/ShortEmail.test.js +5 -0
- package/src/utils/I18n/translations/en.js +46 -8
- package/src/utils/I18n/translations/vi.js +37 -4
- package/src/utils/Route/index.js +7 -0
- package/src/commons/Auth/__test__/AccountItem.test.js +0 -31
- package/src/hooks/Common/useBlockBackAndroid.js +0 -21
- package/src/screens/SubUnit/DetailStyles.js +0 -46
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import renderer, { act } from 'react-test-renderer';
|
|
3
|
+
import { Alert } from 'react-native';
|
|
4
|
+
import { useNavigation } from '@react-navigation/native';
|
|
5
|
+
import mqtt from 'precompiled-mqtt/dist/mqtt.browser';
|
|
6
|
+
|
|
7
|
+
import { SCProvider } from '../../../../context';
|
|
8
|
+
import { mockSCStore } from '../../../../context/mockStore';
|
|
9
|
+
import { getTranslate } from '../../../../utils/I18n';
|
|
10
|
+
import Routes from '../../../../utils/Route';
|
|
11
|
+
|
|
12
|
+
import ConnectWifi from '../../../../commons/ConnectWifi';
|
|
13
|
+
import GatewayWifi from '../index';
|
|
14
|
+
|
|
15
|
+
jest.mock('precompiled-mqtt/dist/mqtt.browser', () => {
|
|
16
|
+
return {
|
|
17
|
+
connect: jest.fn(() => {
|
|
18
|
+
return {
|
|
19
|
+
on: jest.fn(),
|
|
20
|
+
subscribe: jest.fn(),
|
|
21
|
+
publish: jest.fn(),
|
|
22
|
+
end: jest.fn(),
|
|
23
|
+
};
|
|
24
|
+
}),
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const wrapComponent = ({ props }) => (
|
|
29
|
+
<SCProvider initState={mockSCStore({})}>
|
|
30
|
+
<GatewayWifi {...props} />
|
|
31
|
+
</SCProvider>
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
describe('Test GatewayWifi', () => {
|
|
35
|
+
let tree;
|
|
36
|
+
let mockClient;
|
|
37
|
+
|
|
38
|
+
const mockNavigate = useNavigation().navigate;
|
|
39
|
+
const spyAlert = jest.spyOn(Alert, 'alert');
|
|
40
|
+
|
|
41
|
+
const props = {
|
|
42
|
+
route: {
|
|
43
|
+
params: {
|
|
44
|
+
gateway: {
|
|
45
|
+
mqtt_server: {
|
|
46
|
+
websocket_host: 'mqtt.example.com',
|
|
47
|
+
websocket_port: 8083,
|
|
48
|
+
},
|
|
49
|
+
code: '123456',
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
beforeEach(() => {
|
|
56
|
+
jest.useFakeTimers();
|
|
57
|
+
jest.spyOn(global, 'setTimeout');
|
|
58
|
+
jest.spyOn(global, 'clearTimeout');
|
|
59
|
+
mockClient = {
|
|
60
|
+
on: jest.fn(),
|
|
61
|
+
subscribe: jest.fn(),
|
|
62
|
+
publish: jest.fn(),
|
|
63
|
+
end: jest.fn(),
|
|
64
|
+
};
|
|
65
|
+
mqtt.connect.mockReturnValue(mockClient);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
afterEach(() => {
|
|
69
|
+
global.setTimeout.mockRestore();
|
|
70
|
+
global.clearTimeout.mockRestore();
|
|
71
|
+
jest.clearAllMocks();
|
|
72
|
+
jest.useRealTimers();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const triggerConnect = async () => {
|
|
76
|
+
const connectCallback = mockClient.on.mock.calls.find(
|
|
77
|
+
(call) => call[0] === 'connect'
|
|
78
|
+
)[1];
|
|
79
|
+
await act(async () => {
|
|
80
|
+
connectCallback();
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const triggerMessage = async (topic, payload) => {
|
|
85
|
+
const messageCallback = mockClient.on.mock.calls.find(
|
|
86
|
+
(call) => call[0] === 'message'
|
|
87
|
+
)[1];
|
|
88
|
+
await act(async () => {
|
|
89
|
+
messageCallback(topic, JSON.stringify(payload), {});
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const triggerOnChangeWifi = async (wifiDetails) => {
|
|
94
|
+
const instance = tree.root;
|
|
95
|
+
const connectWifi = instance.findByType(ConnectWifi);
|
|
96
|
+
const onConnect = connectWifi.props.onConnect;
|
|
97
|
+
|
|
98
|
+
await act(async () => {
|
|
99
|
+
onConnect(wifiDetails);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
expect(mockClient.publish).toHaveBeenCalledWith(
|
|
103
|
+
'eoh/chip/123456/wifi/change',
|
|
104
|
+
JSON.stringify({
|
|
105
|
+
ssid: wifiDetails.wifiSsid,
|
|
106
|
+
password: wifiDetails.wifiPassword,
|
|
107
|
+
})
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
expect(setTimeout).toHaveBeenCalledWith(expect.any(Function), 120000);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
it('test connects to MQTT server on mount and subscribes to topics', async () => {
|
|
114
|
+
await act(async () => {
|
|
115
|
+
tree = await renderer.create(wrapComponent({ props }));
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
expect(mqtt.connect).toHaveBeenCalledWith('wss://mqtt.example.com:8083', {
|
|
119
|
+
username: '123456',
|
|
120
|
+
password: '123456',
|
|
121
|
+
});
|
|
122
|
+
expect(mockClient.on).toHaveBeenCalledTimes(2);
|
|
123
|
+
expect(mockClient.on).toHaveBeenCalledWith('connect', expect.any(Function));
|
|
124
|
+
expect(mockClient.on).toHaveBeenCalledWith('message', expect.any(Function));
|
|
125
|
+
|
|
126
|
+
await act(async () => {
|
|
127
|
+
triggerConnect();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
expect(mockClient.subscribe).toHaveBeenCalledWith(
|
|
131
|
+
'eoh/chip/123456/wifi/list'
|
|
132
|
+
);
|
|
133
|
+
expect(mockClient.subscribe).toHaveBeenCalledWith(
|
|
134
|
+
'eoh/chip/123456/wifi/change_result'
|
|
135
|
+
);
|
|
136
|
+
expect(mockClient.publish).toHaveBeenCalledWith(
|
|
137
|
+
'eoh/chip/123456/wifi/ask',
|
|
138
|
+
'1'
|
|
139
|
+
);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('test with no mqtt server', async () => {
|
|
143
|
+
const newProps = {
|
|
144
|
+
route: {},
|
|
145
|
+
};
|
|
146
|
+
await act(async () => {
|
|
147
|
+
tree = await renderer.create(wrapComponent({ props: newProps }));
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const instance = tree.root;
|
|
151
|
+
const connectWifi = instance.findByType(ConnectWifi);
|
|
152
|
+
const onConnect = connectWifi.props.onConnect;
|
|
153
|
+
|
|
154
|
+
await act(async () => {
|
|
155
|
+
onConnect({ wifiSsid: 'NewWiFi', wifiPassword: 'NewPassword123' });
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
expect(mqtt.connect).not.toHaveBeenCalled();
|
|
159
|
+
expect(mockClient.on).not.toHaveBeenCalled();
|
|
160
|
+
expect(mockClient.subscribe).not.toHaveBeenCalled();
|
|
161
|
+
expect(mockClient.publish).not.toHaveBeenCalled();
|
|
162
|
+
expect(mockClient.end).not.toHaveBeenCalled();
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('test handles receiving wifi list message', async () => {
|
|
166
|
+
await act(async () => {
|
|
167
|
+
tree = await renderer.create(wrapComponent({ props }));
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
await act(async () => {
|
|
171
|
+
triggerConnect();
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const wifiList = [
|
|
175
|
+
{ ssid: 'HomeWiFi', encryption: 'WPA2/PSK' },
|
|
176
|
+
{ ssid: 'OpenNetwork', encryption: 'OPEN' },
|
|
177
|
+
];
|
|
178
|
+
|
|
179
|
+
await act(async () => {
|
|
180
|
+
triggerMessage('eoh/chip/123456/wifi/list', wifiList);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const instance = tree.root;
|
|
184
|
+
const connectWifi = instance.findByType(ConnectWifi);
|
|
185
|
+
expect(connectWifi.props.wifiList).toEqual(wifiList);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('test handles successful wifi change result message', async () => {
|
|
189
|
+
await act(async () => {
|
|
190
|
+
tree = await renderer.create(wrapComponent({ props }));
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
await act(async () => {
|
|
194
|
+
triggerConnect();
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
await act(async () => {
|
|
198
|
+
triggerOnChangeWifi({
|
|
199
|
+
wifiSsid: 'NewWiFi',
|
|
200
|
+
wifiPassword: 'NewPassword123',
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
await act(async () => {
|
|
205
|
+
triggerMessage('eoh/chip/123456/wifi/change_result', { success: true });
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
expect(mockNavigate).toHaveBeenCalledWith(Routes.Successfully, {
|
|
209
|
+
gateway: props.route.params.gateway,
|
|
210
|
+
wifiName: 'NewWiFi',
|
|
211
|
+
});
|
|
212
|
+
expect(clearTimeout).toHaveBeenCalledWith(expect.any(Number));
|
|
213
|
+
expect(mockClient.end).not.toHaveBeenCalled();
|
|
214
|
+
|
|
215
|
+
await act(async () => {
|
|
216
|
+
triggerMessage('eoh/chip/123456/wifi/change_result', { success: true });
|
|
217
|
+
});
|
|
218
|
+
expect(clearTimeout).toHaveBeenCalledTimes(1);
|
|
219
|
+
|
|
220
|
+
await act(async () => {
|
|
221
|
+
tree.unmount();
|
|
222
|
+
});
|
|
223
|
+
expect(mockClient.end).toHaveBeenCalled();
|
|
224
|
+
expect(clearTimeout).toHaveBeenCalledTimes(1);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it('test handles failed wifi change result message', async () => {
|
|
228
|
+
await act(async () => {
|
|
229
|
+
tree = await renderer.create(wrapComponent({ props }));
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
await act(async () => {
|
|
233
|
+
triggerConnect();
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
await act(async () => {
|
|
237
|
+
triggerOnChangeWifi({
|
|
238
|
+
wifiSsid: 'NewWiFi',
|
|
239
|
+
wifiPassword: 'NewPassword123',
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
await act(async () => {
|
|
244
|
+
triggerMessage('eoh/chip/123456/wifi/change_result', { success: false });
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
expect(spyAlert).toHaveBeenCalledWith(
|
|
248
|
+
getTranslate('en', 'failed'),
|
|
249
|
+
getTranslate('en', 'change_wifi_failed')
|
|
250
|
+
);
|
|
251
|
+
expect(mockNavigate).not.toHaveBeenCalled();
|
|
252
|
+
expect(mockClient.end).not.toHaveBeenCalled();
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it('test publishes wifi change on onChangeWifi and sets timeout', async () => {
|
|
256
|
+
await act(async () => {
|
|
257
|
+
tree = await renderer.create(wrapComponent({ props }));
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
await act(async () => {
|
|
261
|
+
triggerConnect();
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
await act(async () => {
|
|
265
|
+
triggerOnChangeWifi({
|
|
266
|
+
wifiSsid: 'NewWiFi',
|
|
267
|
+
wifiPassword: 'NewPassword123',
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
await act(async () => {
|
|
272
|
+
jest.runAllTimers();
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
expect(spyAlert).toHaveBeenCalledWith(
|
|
276
|
+
getTranslate('en', 'failed'),
|
|
277
|
+
getTranslate('en', 'connection_timeout')
|
|
278
|
+
);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('test handles unmount', async () => {
|
|
282
|
+
await act(async () => {
|
|
283
|
+
tree = await renderer.create(wrapComponent({ props }));
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
await act(async () => {
|
|
287
|
+
triggerConnect();
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
await act(async () => {
|
|
291
|
+
triggerOnChangeWifi({
|
|
292
|
+
wifiSsid: 'NewWiFi',
|
|
293
|
+
wifiPassword: 'NewPassword123',
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
expect(mockClient.end).not.toHaveBeenCalled();
|
|
298
|
+
expect(clearTimeout).not.toHaveBeenCalled();
|
|
299
|
+
|
|
300
|
+
await act(async () => {
|
|
301
|
+
tree.unmount();
|
|
302
|
+
});
|
|
303
|
+
expect(mockClient.end).toHaveBeenCalled();
|
|
304
|
+
expect(clearTimeout).toHaveBeenCalledWith(expect.any(Number));
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it('test receives change result message before connect', async () => {
|
|
308
|
+
await act(async () => {
|
|
309
|
+
renderer.create(wrapComponent({ props }));
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
await act(async () => {
|
|
313
|
+
triggerMessage('eoh/chip/123456/wifi/change_result', { success: true });
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
expect(mockNavigate).not.toHaveBeenCalled();
|
|
317
|
+
expect(spyAlert).not.toHaveBeenCalled();
|
|
318
|
+
});
|
|
319
|
+
});
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { useNavigation } from '@react-navigation/native';
|
|
2
|
+
import React, { memo, useCallback, useEffect, useState, useRef } from 'react';
|
|
3
|
+
import { Alert } from 'react-native';
|
|
4
|
+
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
5
|
+
import { connectMqttServer } from '../../../hooks/useMqtt';
|
|
6
|
+
import Routes from '../../../utils/Route';
|
|
7
|
+
import ConnectWifi from '../../../commons/ConnectWifi';
|
|
8
|
+
|
|
9
|
+
const GatewayWifi = ({ route }) => {
|
|
10
|
+
const { gateway } = route?.params || {};
|
|
11
|
+
|
|
12
|
+
const t = useTranslations();
|
|
13
|
+
const { navigate, goBack } = useNavigation();
|
|
14
|
+
|
|
15
|
+
const mqttClientRef = useRef(null);
|
|
16
|
+
const timeoutIdRef = useRef(null);
|
|
17
|
+
const wifiNameRef = useRef(null);
|
|
18
|
+
|
|
19
|
+
const [wifiList, setWifiList] = useState([]);
|
|
20
|
+
const [isShowLoading, setIsShowLoading] = useState(false);
|
|
21
|
+
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (!gateway?.mqtt_server) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const client = connectMqttServer(gateway.mqtt_server, gateway.code);
|
|
28
|
+
|
|
29
|
+
client.on('connect', () => {
|
|
30
|
+
client.subscribe(`eoh/chip/${gateway.code}/wifi/list`);
|
|
31
|
+
client.subscribe(`eoh/chip/${gateway.code}/wifi/change_result`);
|
|
32
|
+
client.publish(`eoh/chip/${gateway.code}/wifi/ask`, '1');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
client.on('message', async (topic, payload) => {
|
|
36
|
+
if (topic === `eoh/chip/${gateway.code}/wifi/change_result`) {
|
|
37
|
+
if (!wifiNameRef.current) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (timeoutIdRef.current) {
|
|
41
|
+
clearTimeout(timeoutIdRef.current);
|
|
42
|
+
timeoutIdRef.current = null;
|
|
43
|
+
}
|
|
44
|
+
const result = JSON.parse(payload.toString());
|
|
45
|
+
if (result.success) {
|
|
46
|
+
navigate(Routes.Successfully, {
|
|
47
|
+
gateway,
|
|
48
|
+
wifiName: wifiNameRef.current,
|
|
49
|
+
});
|
|
50
|
+
} else {
|
|
51
|
+
setIsShowLoading(false);
|
|
52
|
+
Alert.alert(t('failed'), t('change_wifi_failed'));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (topic === `eoh/chip/${gateway.code}/wifi/list`) {
|
|
57
|
+
setWifiList(JSON.parse(payload.toString()));
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
mqttClientRef.current = client;
|
|
62
|
+
return () => {
|
|
63
|
+
client.end();
|
|
64
|
+
if (timeoutIdRef.current) {
|
|
65
|
+
clearTimeout(timeoutIdRef.current);
|
|
66
|
+
timeoutIdRef.current = null;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}, [gateway, t, navigate]);
|
|
70
|
+
|
|
71
|
+
const onChangeWifi = useCallback(
|
|
72
|
+
({ wifiSsid, wifiPassword }) => {
|
|
73
|
+
if (!mqttClientRef.current) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
timeoutIdRef.current = setTimeout(() => {
|
|
78
|
+
setIsShowLoading(false);
|
|
79
|
+
Alert.alert(t('failed'), t('connection_timeout'));
|
|
80
|
+
}, 120000);
|
|
81
|
+
|
|
82
|
+
mqttClientRef.current.publish(
|
|
83
|
+
`eoh/chip/${gateway.code}/wifi/change`,
|
|
84
|
+
JSON.stringify({
|
|
85
|
+
ssid: wifiSsid,
|
|
86
|
+
password: wifiPassword,
|
|
87
|
+
})
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
wifiNameRef.current = wifiSsid;
|
|
91
|
+
},
|
|
92
|
+
[gateway, t]
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<ConnectWifi
|
|
97
|
+
title={'change_wifi'}
|
|
98
|
+
wifiList={wifiList}
|
|
99
|
+
onConnect={onChangeWifi}
|
|
100
|
+
onGoBack={goBack}
|
|
101
|
+
isShowLoading={isShowLoading}
|
|
102
|
+
setIsShowLoading={setIsShowLoading}
|
|
103
|
+
/>
|
|
104
|
+
);
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export default memo(GatewayWifi);
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import renderer, { act } from 'react-test-renderer';
|
|
3
|
+
import { TouchableOpacity } from 'react-native';
|
|
4
|
+
import { useNavigation } from '@react-navigation/native';
|
|
5
|
+
|
|
6
|
+
import { SCProvider } from '../../../../context';
|
|
7
|
+
import { mockSCStore } from '../../../../context/mockStore';
|
|
8
|
+
import AccessibilityLabel from '../../../../configs/AccessibilityLabel';
|
|
9
|
+
import Routes from '../../../../utils/Route';
|
|
10
|
+
|
|
11
|
+
import Successfully from '../index';
|
|
12
|
+
|
|
13
|
+
const wrapComponent = ({ props }) => (
|
|
14
|
+
<SCProvider initState={mockSCStore({})}>
|
|
15
|
+
<Successfully {...props} />
|
|
16
|
+
</SCProvider>
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
describe('test Successfully', () => {
|
|
20
|
+
let tree;
|
|
21
|
+
|
|
22
|
+
const mockNavigate = useNavigation().navigate;
|
|
23
|
+
|
|
24
|
+
const props = {
|
|
25
|
+
route: {
|
|
26
|
+
params: {
|
|
27
|
+
gateway: { id: 1, name: 'Gateway1' },
|
|
28
|
+
wifiName: 'HomeWiFi',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
afterEach(() => {
|
|
34
|
+
mockNavigate.mockClear();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('test navigates to GatewayInfo with correct parameters when Done is pressed', async () => {
|
|
38
|
+
await act(async () => {
|
|
39
|
+
tree = await renderer.create(wrapComponent({ props }));
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const instance = tree.root;
|
|
43
|
+
const doneButton = instance.find(
|
|
44
|
+
(el) =>
|
|
45
|
+
el.props.accessibilityLabel === AccessibilityLabel.BUTTON_DONE &&
|
|
46
|
+
el.type === TouchableOpacity
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
await act(async () => {
|
|
50
|
+
doneButton.props.onPress();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
expect(mockNavigate).toHaveBeenCalledWith(Routes.GatewayInfo, {
|
|
54
|
+
chipId: 1,
|
|
55
|
+
gatewayName: 'Gateway1',
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('test handles missing route params', async () => {
|
|
60
|
+
await act(async () => {
|
|
61
|
+
tree = await renderer.create(wrapComponent({}));
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const instance = tree.root;
|
|
65
|
+
const doneButton = instance.find(
|
|
66
|
+
(el) =>
|
|
67
|
+
el.props.accessibilityLabel === AccessibilityLabel.BUTTON_DONE &&
|
|
68
|
+
el.type === TouchableOpacity
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
await act(async () => {
|
|
72
|
+
doneButton.props.onPress();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
expect(mockNavigate).not.toHaveBeenCalled();
|
|
76
|
+
});
|
|
77
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React, { useCallback } from 'react';
|
|
2
|
+
import { TouchableOpacity, View } from 'react-native';
|
|
3
|
+
import { IconOutline } from '@ant-design/icons-react-native';
|
|
4
|
+
import { useNavigation } from '@react-navigation/native';
|
|
5
|
+
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
6
|
+
import { Colors } from '../../../configs';
|
|
7
|
+
import Text from '../../../commons/Text';
|
|
8
|
+
import AccessibilityLabel from '../../../configs/AccessibilityLabel';
|
|
9
|
+
import Routes from '../../../utils/Route';
|
|
10
|
+
import { HeaderCustom } from '../../../commons/Header';
|
|
11
|
+
|
|
12
|
+
import styles from './styles';
|
|
13
|
+
|
|
14
|
+
const Successfully = ({ route }) => {
|
|
15
|
+
const { gateway, wifiName } = route?.params || {};
|
|
16
|
+
|
|
17
|
+
const t = useTranslations();
|
|
18
|
+
const { navigate } = useNavigation();
|
|
19
|
+
|
|
20
|
+
const onPressDone = useCallback(() => {
|
|
21
|
+
if (!gateway) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
navigate(Routes.GatewayInfo, {
|
|
25
|
+
chipId: gateway?.id,
|
|
26
|
+
gatewayName: gateway?.name,
|
|
27
|
+
});
|
|
28
|
+
}, [navigate, gateway]);
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<View style={styles.container}>
|
|
32
|
+
<HeaderCustom
|
|
33
|
+
title={t('connect_wifi')}
|
|
34
|
+
isShowSeparator
|
|
35
|
+
isCanBack={false}
|
|
36
|
+
/>
|
|
37
|
+
<View style={styles.content}>
|
|
38
|
+
<View style={styles.viewIconSuccess}>
|
|
39
|
+
<IconOutline name="check-circle" size={48} color={Colors.Green6} />
|
|
40
|
+
<Text
|
|
41
|
+
semibold
|
|
42
|
+
color={Colors.Black}
|
|
43
|
+
size={20}
|
|
44
|
+
style={styles.textStatus}
|
|
45
|
+
>
|
|
46
|
+
{t('successfully_connected')}
|
|
47
|
+
</Text>
|
|
48
|
+
<Text size={14} color={Colors.Gray9} style={styles.textInfo}>
|
|
49
|
+
{`${t('you_have_successfully_connected_wifi')}: ${wifiName}`}
|
|
50
|
+
</Text>
|
|
51
|
+
</View>
|
|
52
|
+
</View>
|
|
53
|
+
<TouchableOpacity
|
|
54
|
+
style={styles.btnDone}
|
|
55
|
+
onPress={onPressDone}
|
|
56
|
+
accessibilityLabel={AccessibilityLabel.BUTTON_DONE}
|
|
57
|
+
>
|
|
58
|
+
<Text semibold size={16} color={Colors.Primary}>
|
|
59
|
+
{t('done')}
|
|
60
|
+
</Text>
|
|
61
|
+
</TouchableOpacity>
|
|
62
|
+
</View>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export default Successfully;
|
|
@@ -0,0 +1,35 @@
|
|
|
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.White,
|
|
8
|
+
justifyContent: 'center',
|
|
9
|
+
alignItems: 'center',
|
|
10
|
+
},
|
|
11
|
+
content: {
|
|
12
|
+
flex: 1,
|
|
13
|
+
justifyContent: 'center',
|
|
14
|
+
alignItems: 'center',
|
|
15
|
+
},
|
|
16
|
+
btnDone: {
|
|
17
|
+
height: 48,
|
|
18
|
+
width: '100%',
|
|
19
|
+
alignItems: 'center',
|
|
20
|
+
marginTop: 100,
|
|
21
|
+
},
|
|
22
|
+
textStatus: {
|
|
23
|
+
marginTop: 8,
|
|
24
|
+
marginBottom: 16,
|
|
25
|
+
},
|
|
26
|
+
textInfo: {
|
|
27
|
+
textAlign: 'center',
|
|
28
|
+
lineHeight: 24,
|
|
29
|
+
marginHorizontal: 20,
|
|
30
|
+
},
|
|
31
|
+
viewIconSuccess: {
|
|
32
|
+
alignItems: 'center',
|
|
33
|
+
justifyContent: 'center',
|
|
34
|
+
},
|
|
35
|
+
});
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import React, { useCallback, memo } from 'react';
|
|
2
2
|
import { TouchableOpacity, View, Image, FlatList } from 'react-native';
|
|
3
|
+
import { useNavigation } from '@react-navigation/native';
|
|
4
|
+
import Routes from '../../../../utils/Route';
|
|
3
5
|
import { Colors, SCConfig } from '../../../../configs';
|
|
4
6
|
import t from '../../../../hooks/Common/useTranslations';
|
|
5
7
|
import { Text, HeaderCustom } from '../../../../commons';
|
|
6
8
|
import Images from '../../../../configs/Images';
|
|
9
|
+
import { ToastBottomHelper } from '../../../../utils/Utils';
|
|
7
10
|
import { AccessibilityLabel } from '../../../../configs/Constants';
|
|
8
11
|
import styles from './styles';
|
|
9
12
|
import RowItem from '../RowItem';
|
|
@@ -12,12 +15,23 @@ const Information = ({
|
|
|
12
15
|
listInformation,
|
|
13
16
|
handleDeleteGateway,
|
|
14
17
|
handleConnectionMethods,
|
|
18
|
+
gatewayDetail,
|
|
15
19
|
isDevice = false,
|
|
16
20
|
title = t('gateway_information'),
|
|
17
21
|
isModbus,
|
|
18
22
|
buttonBackStyles,
|
|
19
23
|
methodsConnection,
|
|
20
24
|
}) => {
|
|
25
|
+
const { navigate } = useNavigation();
|
|
26
|
+
|
|
27
|
+
const handleChangeWifi = useCallback(() => {
|
|
28
|
+
if (!gatewayDetail?.is_connected) {
|
|
29
|
+
ToastBottomHelper.error(t('gateway_need_to_be_connected'));
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
navigate(Routes.GatewayWifi, { gateway: gatewayDetail });
|
|
33
|
+
}, [navigate, gatewayDetail]);
|
|
34
|
+
|
|
21
35
|
const renderItem = useCallback(
|
|
22
36
|
({ item, index }) => {
|
|
23
37
|
return (
|
|
@@ -26,10 +40,12 @@ const Information = ({
|
|
|
26
40
|
subTitle={item?.data}
|
|
27
41
|
key={index}
|
|
28
42
|
isShowCopy={item?.id === 5 && !isModbus}
|
|
43
|
+
isShowChangeWifi={item?.id === 3 && !isModbus}
|
|
44
|
+
handleChangeWifi={handleChangeWifi}
|
|
29
45
|
/>
|
|
30
46
|
);
|
|
31
47
|
},
|
|
32
|
-
[isModbus]
|
|
48
|
+
[isModbus, handleChangeWifi]
|
|
33
49
|
);
|
|
34
50
|
|
|
35
51
|
return (
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { memo, useCallback, useMemo } from 'react';
|
|
2
2
|
import { TouchableOpacity, View } from 'react-native';
|
|
3
3
|
import Clipboard from '@react-native-clipboard/clipboard';
|
|
4
|
+
import { IconOutline } from '@ant-design/icons-react-native';
|
|
4
5
|
|
|
5
6
|
import t from '../../../../hooks/Common/useTranslations';
|
|
6
7
|
import FileCopy from '../../../../Images/DevMode/file_copy.svg';
|
|
@@ -14,6 +15,8 @@ const RowItem = ({
|
|
|
14
15
|
subTitle = '--',
|
|
15
16
|
isShowCopy = false,
|
|
16
17
|
onRowOne = false,
|
|
18
|
+
isShowChangeWifi = false,
|
|
19
|
+
handleChangeWifi,
|
|
17
20
|
}) => {
|
|
18
21
|
const handleCopy = useCallback(() => {
|
|
19
22
|
Clipboard?.setString(subTitle);
|
|
@@ -39,9 +42,17 @@ const RowItem = ({
|
|
|
39
42
|
<FileCopy />
|
|
40
43
|
</TouchableOpacity>
|
|
41
44
|
)}
|
|
45
|
+
{!!isShowChangeWifi && (
|
|
46
|
+
<TouchableOpacity
|
|
47
|
+
onPress={handleChangeWifi}
|
|
48
|
+
accessibilityLabel={AccessibilityLabel.CHANGE_WIFI}
|
|
49
|
+
>
|
|
50
|
+
<IconOutline name="edit" size={25} />
|
|
51
|
+
</TouchableOpacity>
|
|
52
|
+
)}
|
|
42
53
|
</>
|
|
43
54
|
);
|
|
44
|
-
}, [handleCopy, isShowCopy, subTitle]);
|
|
55
|
+
}, [handleCopy, handleChangeWifi, isShowCopy, isShowChangeWifi, subTitle]);
|
|
45
56
|
|
|
46
57
|
return (
|
|
47
58
|
<View
|