@eohjsc/react-native-smart-city 0.3.49 → 0.3.51
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/package.json +1 -1
- package/src/commons/ActionGroup/OnOffTemplate/index.js +6 -8
- package/src/commons/ActionGroup/SliderRangeTemplate.js +7 -2
- package/src/commons/ActionGroup/__test__/OnOffTemplate.test.js +98 -0
- package/src/commons/ActionGroup/__test__/SliderRangeTemplate.test.js +27 -3
- package/src/commons/ActionTemplate/__test__/CurtainAction.test.js +64 -0
- package/src/commons/ActionTemplate/__test__/OnOffSmartLockAction.test.js +54 -0
- package/src/commons/Device/HorizontalBarChart.js +0 -1
- package/src/commons/Device/PMSensor/PMSensorIndicatior.js +3 -1
- package/src/commons/Processing/styles.js +0 -2
- package/src/commons/Sharing/WrapHeaderScrollable.js +5 -4
- package/src/commons/UnitSummary/ConfigHistoryChart/__test__/ConfigHistoryChart.test.js +9 -2
- package/src/commons/UnitSummary/ConfigHistoryChart/index.js +41 -39
- package/src/configs/Constants.js +2 -0
- package/src/configs/SCConfig.js +3 -0
- package/src/navigations/AddDeviceStack.js +0 -5
- package/src/navigations/UnitStack.js +5 -4
- package/src/screens/AQIGuide/index.js +2 -2
- package/src/screens/ActivityLog/styles/itemLogStyles.js +1 -0
- package/src/screens/AddNewDevice/__test__/AddNewDevice.test.js +1 -1
- package/src/screens/AddNewGateway/ConnectingDevice.js +25 -3
- package/src/screens/AddNewGateway/ConnectingWifiGuide.js +1 -1
- package/src/screens/AddNewGateway/ConnectingWifiGuideStyles.js +10 -0
- package/src/screens/AddNewGateway/ConnectingZigbeeDevice.js +3 -17
- package/src/screens/AddNewGateway/ShareWifiPassword.js +2 -1
- package/src/screens/AddNewGateway/__test__/ConnectingWifiDevice.test.js +2 -1
- package/src/screens/AddNewGateway/__test__/ConnectingZigbeeDevice.test.js +27 -1
- package/src/screens/Device/detail.js +1 -3
- package/src/screens/Gateway/components/Information/styles.js +0 -1
- package/src/screens/Notification/__test__/NotificationItem.test.js +1 -0
- package/src/screens/Notification/components/NotificationItem.js +16 -1
- package/src/screens/Notification/index.js +1 -0
- package/src/screens/Notification/styles/indexStyles.js +3 -0
- package/src/screens/Sharing/SelectPermission.js +2 -2
- package/src/screens/SmartAccount/SuccessfullyConnected/__test__/SuccessfullyConnected.test.js +26 -7
- package/src/screens/SmartAccount/SuccessfullyConnected/index.js +29 -11
- package/src/screens/SyncLGDevice/__test__/AddLGDevice.test.js +1 -1
- package/src/screens/Template/__test__/GatewayList.test.js +1 -1
- package/src/screens/Template/__test__/Information.test.js +1 -1
- package/src/screens/Unit/Detail.js +24 -18
- package/src/screens/Unit/__test__/Detail.test.js +62 -18
- package/src/utils/Apis/axios.js +52 -36
- package/src/utils/I18n/translations/en.json +4 -0
- package/src/utils/I18n/translations/vi.json +5 -1
- package/src/utils/Storage.js +0 -4
- package/src/utils/Utils.js +1 -1
- package/src/utils/__test__/Utils.test.js +27 -3
- package/src/screens/AddNewDevice/ConnectingDevices.js +0 -62
- package/src/screens/AddNewDevice/__test__/ConnectingDevices.test.js +0 -110
package/package.json
CHANGED
|
@@ -75,9 +75,8 @@ const OnOffTemplate = memo(({ actionGroup = {}, doAction, sensor }) => {
|
|
|
75
75
|
break;
|
|
76
76
|
case DEVICE_TYPE.LG_THINQ:
|
|
77
77
|
setTempIsOn((prev) => !prev);
|
|
78
|
-
|
|
79
|
-
await doAction(action_data, JSON.stringify({ value: !isOn }));
|
|
80
|
-
}
|
|
78
|
+
action_data &&
|
|
79
|
+
(await doAction(action_data, JSON.stringify({ value: !isOn })));
|
|
81
80
|
break;
|
|
82
81
|
default:
|
|
83
82
|
if (action_data) {
|
|
@@ -97,11 +96,10 @@ const OnOffTemplate = memo(({ actionGroup = {}, doAction, sensor }) => {
|
|
|
97
96
|
break;
|
|
98
97
|
}
|
|
99
98
|
updateStatusFromPusher();
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
99
|
+
sensor?.is_managed_by_backend &&
|
|
100
|
+
config &&
|
|
101
|
+
sensor.device_type === DEVICE_TYPE.LG_THINQ &&
|
|
102
|
+
watchMultiConfigs([config]);
|
|
105
103
|
}, [
|
|
106
104
|
allow_config_store_value,
|
|
107
105
|
config,
|
|
@@ -30,14 +30,19 @@ const SliderRangeTemplate = memo(({ actionGroup = {}, doAction, sensor }) => {
|
|
|
30
30
|
const [valueBrightness, setValueBrightness] = useState(getPercent());
|
|
31
31
|
const [isFirstTime, setIsFirstTime] = useState(true);
|
|
32
32
|
|
|
33
|
+
// TODO Thinh: remove action_brightness_data
|
|
33
34
|
const onChangeBrightness = useCallback(
|
|
34
35
|
async (value) => {
|
|
35
36
|
await doAction(
|
|
36
|
-
configuration?.action_brightness_data,
|
|
37
|
+
configuration?.action_brightness_data || configuration?.action_data,
|
|
37
38
|
JSON.stringify({ value_brness: value })
|
|
38
39
|
);
|
|
39
40
|
},
|
|
40
|
-
[
|
|
41
|
+
[
|
|
42
|
+
configuration?.action_brightness_data,
|
|
43
|
+
configuration?.action_data,
|
|
44
|
+
doAction,
|
|
45
|
+
]
|
|
41
46
|
);
|
|
42
47
|
|
|
43
48
|
useEffect(() => {
|
|
@@ -227,6 +227,7 @@ describe('Test OnOffTemplate', () => {
|
|
|
227
227
|
});
|
|
228
228
|
|
|
229
229
|
it('render with template OnOffSimpleActionTemplate with just action_data lg_thinq', async () => {
|
|
230
|
+
jest.useFakeTimers();
|
|
230
231
|
actionGroup = {
|
|
231
232
|
template: 'OnOffSimpleActionTemplate',
|
|
232
233
|
configuration: {
|
|
@@ -242,6 +243,7 @@ describe('Test OnOffTemplate', () => {
|
|
|
242
243
|
tree = await create(
|
|
243
244
|
wrapComponent(actionGroup, mockDoAction, {
|
|
244
245
|
device_type: DEVICE_TYPE.LG_THINQ,
|
|
246
|
+
is_managed_by_backend: true,
|
|
245
247
|
})
|
|
246
248
|
);
|
|
247
249
|
});
|
|
@@ -253,12 +255,108 @@ describe('Test OnOffTemplate', () => {
|
|
|
253
255
|
await act(async () => {
|
|
254
256
|
await template[0].props.triggerAction();
|
|
255
257
|
});
|
|
258
|
+
jest.runAllTimers();
|
|
256
259
|
expect(mockDoAction).toHaveBeenCalledWith(
|
|
257
260
|
action_data,
|
|
258
261
|
JSON.stringify({ value: false })
|
|
259
262
|
);
|
|
260
263
|
});
|
|
261
264
|
|
|
265
|
+
it('render with template OnOffSimpleActionTemplate with action_data zigbee trigger off', async () => {
|
|
266
|
+
actionGroup = {
|
|
267
|
+
template: 'OnOffSimpleActionTemplate',
|
|
268
|
+
configuration: {
|
|
269
|
+
config: 5,
|
|
270
|
+
action_on_data: action_on_data,
|
|
271
|
+
action_off_data: action_off_data,
|
|
272
|
+
icon: 'up',
|
|
273
|
+
is_on_value: [2],
|
|
274
|
+
allow_config_store_value: true,
|
|
275
|
+
},
|
|
276
|
+
title: 'Turn on / off',
|
|
277
|
+
};
|
|
278
|
+
const mockDoAction = jest.fn();
|
|
279
|
+
await act(async () => {
|
|
280
|
+
tree = await create(
|
|
281
|
+
wrapComponent(actionGroup, mockDoAction, {
|
|
282
|
+
device_type: DEVICE_TYPE.ZIGBEE,
|
|
283
|
+
})
|
|
284
|
+
);
|
|
285
|
+
});
|
|
286
|
+
const instance = tree.root;
|
|
287
|
+
const template = instance.findAllByType(OnOffSimpleTemplate);
|
|
288
|
+
|
|
289
|
+
await act(async () => {
|
|
290
|
+
await template[0].props.triggerAction();
|
|
291
|
+
});
|
|
292
|
+
expect(mockDoAction).toHaveBeenCalledWith(
|
|
293
|
+
action_off_data,
|
|
294
|
+
JSON.stringify({ state: 0, config_id: 5, config_value: 0 })
|
|
295
|
+
);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it('render with template OnOffSimpleActionTemplate with action_data zigbee trigger on', async () => {
|
|
299
|
+
actionGroup = {
|
|
300
|
+
template: 'OnOffSimpleActionTemplate',
|
|
301
|
+
configuration: {
|
|
302
|
+
config: 5,
|
|
303
|
+
action_on_data: action_on_data,
|
|
304
|
+
action_off_data: action_off_data,
|
|
305
|
+
icon: 'up',
|
|
306
|
+
is_on_value: [1],
|
|
307
|
+
allow_config_store_value: true,
|
|
308
|
+
},
|
|
309
|
+
title: 'Turn on / off',
|
|
310
|
+
};
|
|
311
|
+
const mockDoAction = jest.fn();
|
|
312
|
+
await act(async () => {
|
|
313
|
+
tree = await create(
|
|
314
|
+
wrapComponent(actionGroup, mockDoAction, {
|
|
315
|
+
device_type: DEVICE_TYPE.ZIGBEE,
|
|
316
|
+
})
|
|
317
|
+
);
|
|
318
|
+
});
|
|
319
|
+
const instance = tree.root;
|
|
320
|
+
const template = instance.findAllByType(OnOffSimpleTemplate);
|
|
321
|
+
|
|
322
|
+
await act(async () => {
|
|
323
|
+
await template[0].props.triggerAction();
|
|
324
|
+
});
|
|
325
|
+
expect(mockDoAction).toHaveBeenCalledWith(
|
|
326
|
+
action_on_data,
|
|
327
|
+
JSON.stringify({ state: 1, config_id: 5, config_value: 1 })
|
|
328
|
+
);
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
it('render with template OnOffSimpleActionTemplate with zigbee device wrong action_data', async () => {
|
|
332
|
+
actionGroup = {
|
|
333
|
+
template: 'OnOffSimpleActionTemplate',
|
|
334
|
+
configuration: {
|
|
335
|
+
config: 5,
|
|
336
|
+
action_data: action_data,
|
|
337
|
+
icon: 'up',
|
|
338
|
+
is_on_value: [2],
|
|
339
|
+
allow_config_store_value: true,
|
|
340
|
+
},
|
|
341
|
+
title: 'Turn on / off',
|
|
342
|
+
};
|
|
343
|
+
const mockDoAction = jest.fn();
|
|
344
|
+
await act(async () => {
|
|
345
|
+
tree = await create(
|
|
346
|
+
wrapComponent(actionGroup, mockDoAction, {
|
|
347
|
+
device_type: DEVICE_TYPE.ZIGBEE,
|
|
348
|
+
})
|
|
349
|
+
);
|
|
350
|
+
});
|
|
351
|
+
const instance = tree.root;
|
|
352
|
+
const template = instance.findAllByType(OnOffSimpleTemplate);
|
|
353
|
+
|
|
354
|
+
await act(async () => {
|
|
355
|
+
await template[0].props.triggerAction();
|
|
356
|
+
});
|
|
357
|
+
expect(mockDoAction).not.toHaveBeenCalled();
|
|
358
|
+
});
|
|
359
|
+
|
|
262
360
|
it('render with template OnOffSimpleActionTemplate disabled', async () => {
|
|
263
361
|
actionGroup = {
|
|
264
362
|
template: 'OnOffSimpleActionTemplate',
|
|
@@ -27,7 +27,7 @@ describe('Test SliderRangeTemplate', () => {
|
|
|
27
27
|
let wrapper;
|
|
28
28
|
let actionGroup;
|
|
29
29
|
|
|
30
|
-
const
|
|
30
|
+
const action_data = {
|
|
31
31
|
color: '#00979D',
|
|
32
32
|
command_prefer_over_bluetooth: false,
|
|
33
33
|
command_prefer_over_googlehome: false,
|
|
@@ -42,7 +42,7 @@ describe('Test SliderRangeTemplate', () => {
|
|
|
42
42
|
template: 'ColorPickerTemplate',
|
|
43
43
|
configuration: {
|
|
44
44
|
config: 5,
|
|
45
|
-
|
|
45
|
+
action_data,
|
|
46
46
|
},
|
|
47
47
|
title: '',
|
|
48
48
|
};
|
|
@@ -58,7 +58,31 @@ describe('Test SliderRangeTemplate', () => {
|
|
|
58
58
|
const silderRange = instance.findAllByType(SliderRange);
|
|
59
59
|
expect(silderRange).toHaveLength(1);
|
|
60
60
|
await act(async () => {
|
|
61
|
-
await silderRange[0].props.onSlidingComplete();
|
|
61
|
+
await silderRange[0].props.onSlidingComplete(50);
|
|
62
62
|
});
|
|
63
|
+
expect(mockDoAction).toHaveBeenCalledWith(
|
|
64
|
+
action_data,
|
|
65
|
+
JSON.stringify({ value_brness: 50 })
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('render template SliderRangeTemplate with data backward compatible', async () => {
|
|
70
|
+
actionGroup.configuration.action_data = undefined;
|
|
71
|
+
actionGroup.configuration.action_brightness_data = action_data;
|
|
72
|
+
useConfigGlobalState.mockImplementation(() => [{}, jest.fn()]);
|
|
73
|
+
const sensor = { is_managed_by_backend: true, name: 'Sensor' };
|
|
74
|
+
await act(async () => {
|
|
75
|
+
wrapper = await create(wrapComponent(actionGroup, mockDoAction, sensor));
|
|
76
|
+
});
|
|
77
|
+
const instance = wrapper.root;
|
|
78
|
+
const silderRange = instance.findAllByType(SliderRange);
|
|
79
|
+
expect(silderRange).toHaveLength(1);
|
|
80
|
+
await act(async () => {
|
|
81
|
+
await silderRange[0].props.onSlidingComplete(50);
|
|
82
|
+
});
|
|
83
|
+
expect(mockDoAction).toHaveBeenCalledWith(
|
|
84
|
+
action_data,
|
|
85
|
+
JSON.stringify({ value_brness: 50 })
|
|
86
|
+
);
|
|
63
87
|
});
|
|
64
88
|
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import renderer, { act } from 'react-test-renderer';
|
|
3
|
+
import { TouchableOpacity } from 'react-native';
|
|
4
|
+
|
|
5
|
+
import CurtainAction from '../CurtainAction';
|
|
6
|
+
import { SCProvider } from '../../../context';
|
|
7
|
+
import { mockSCStore } from '../../../context/mockStore';
|
|
8
|
+
|
|
9
|
+
const wrapComponent = (configuration, onPress) => (
|
|
10
|
+
<SCProvider initState={mockSCStore({})}>
|
|
11
|
+
<CurtainAction configuration={configuration} onPress={onPress} />
|
|
12
|
+
</SCProvider>
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
describe('Test CurtainAction', () => {
|
|
16
|
+
let tree;
|
|
17
|
+
|
|
18
|
+
it('test onPress curtain action', async () => {
|
|
19
|
+
const configuration = {
|
|
20
|
+
open_action: 'a',
|
|
21
|
+
close_action: 'b',
|
|
22
|
+
stop_action: 'c',
|
|
23
|
+
text1: '1',
|
|
24
|
+
text2: '2',
|
|
25
|
+
text3: '3',
|
|
26
|
+
};
|
|
27
|
+
const mockFuntion = jest.fn();
|
|
28
|
+
await act(async () => {
|
|
29
|
+
tree = renderer.create(wrapComponent(configuration, mockFuntion));
|
|
30
|
+
});
|
|
31
|
+
const instance = tree.root;
|
|
32
|
+
const touchOpacity = instance.findAllByType(TouchableOpacity);
|
|
33
|
+
|
|
34
|
+
expect(touchOpacity).toHaveLength(3);
|
|
35
|
+
await act(async () => {
|
|
36
|
+
touchOpacity[0].props.onPress();
|
|
37
|
+
});
|
|
38
|
+
expect(mockFuntion).toHaveBeenCalledWith({
|
|
39
|
+
name: configuration.text1,
|
|
40
|
+
action: configuration.close_action,
|
|
41
|
+
template: undefined,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
mockFuntion.mockClear();
|
|
45
|
+
await act(async () => {
|
|
46
|
+
touchOpacity[1].props.onPress();
|
|
47
|
+
});
|
|
48
|
+
expect(mockFuntion).toHaveBeenCalledWith({
|
|
49
|
+
name: configuration.text2,
|
|
50
|
+
action: configuration.stop_action,
|
|
51
|
+
template: undefined,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
mockFuntion.mockClear();
|
|
55
|
+
await act(async () => {
|
|
56
|
+
touchOpacity[2].props.onPress();
|
|
57
|
+
});
|
|
58
|
+
expect(mockFuntion).toHaveBeenCalledWith({
|
|
59
|
+
name: configuration.text3,
|
|
60
|
+
action: configuration.open_action,
|
|
61
|
+
template: undefined,
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import renderer, { act } from 'react-test-renderer';
|
|
3
|
+
import { TouchableOpacity } from 'react-native';
|
|
4
|
+
|
|
5
|
+
import OnOffSmartLockAction from '../OnOffSmartLockAction';
|
|
6
|
+
import { SCProvider } from '../../../context';
|
|
7
|
+
import { mockSCStore } from '../../../context/mockStore';
|
|
8
|
+
|
|
9
|
+
const wrapComponent = (configuration, onPress) => (
|
|
10
|
+
<SCProvider initState={mockSCStore({})}>
|
|
11
|
+
<OnOffSmartLockAction configuration={configuration} onPress={onPress} />
|
|
12
|
+
</SCProvider>
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
describe('Test OnOffSmartLockAction', () => {
|
|
16
|
+
let tree;
|
|
17
|
+
|
|
18
|
+
it('test onPress smart lock action', async () => {
|
|
19
|
+
const configuration = {
|
|
20
|
+
action_on: 'a',
|
|
21
|
+
action_off: 'b',
|
|
22
|
+
text_on: 'on',
|
|
23
|
+
text_off: 'off',
|
|
24
|
+
};
|
|
25
|
+
const mockFuntion = jest.fn();
|
|
26
|
+
await act(async () => {
|
|
27
|
+
tree = renderer.create(wrapComponent(configuration, mockFuntion));
|
|
28
|
+
});
|
|
29
|
+
const instance = tree.root;
|
|
30
|
+
const touchOpacity = instance.findAllByType(TouchableOpacity);
|
|
31
|
+
|
|
32
|
+
expect(touchOpacity).toHaveLength(2);
|
|
33
|
+
await act(async () => {
|
|
34
|
+
touchOpacity[0].props.onPress();
|
|
35
|
+
});
|
|
36
|
+
expect(mockFuntion).toHaveBeenCalledWith({
|
|
37
|
+
...configuration,
|
|
38
|
+
name: configuration.text_off,
|
|
39
|
+
action: configuration.action_off,
|
|
40
|
+
action_on: null,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
mockFuntion.mockClear();
|
|
44
|
+
await act(async () => {
|
|
45
|
+
touchOpacity[1].props.onPress();
|
|
46
|
+
});
|
|
47
|
+
expect(mockFuntion).toHaveBeenCalledWith({
|
|
48
|
+
...configuration,
|
|
49
|
+
name: configuration.text_on,
|
|
50
|
+
action: configuration.action_on,
|
|
51
|
+
action_off: null,
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -9,7 +9,9 @@ const keyExtractor = (item) => item.id.toString();
|
|
|
9
9
|
const PMSensorIndicatior = memo(({ data = [], style }) => {
|
|
10
10
|
const renderItem = useCallback(
|
|
11
11
|
({ item }) => {
|
|
12
|
-
const getValue =
|
|
12
|
+
const getValue = ['', null, undefined, NaN].includes(item?.value)
|
|
13
|
+
? '--'
|
|
14
|
+
: item?.value;
|
|
13
15
|
return (
|
|
14
16
|
<QualityIndicatorItem
|
|
15
17
|
key={item.id.toString()}
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { StyleSheet } from 'react-native';
|
|
2
2
|
import { Colors, Constants } from '../../configs';
|
|
3
|
-
import { getStatusBarHeight } from 'react-native-iphone-x-helper';
|
|
4
3
|
|
|
5
4
|
export default StyleSheet.create({
|
|
6
5
|
wrap: {
|
|
7
|
-
paddingTop: getStatusBarHeight(true),
|
|
8
6
|
backgroundColor: Colors.White,
|
|
9
7
|
width: '100%',
|
|
10
8
|
height: '100%',
|
|
@@ -5,9 +5,10 @@ import {
|
|
|
5
5
|
Animated,
|
|
6
6
|
View,
|
|
7
7
|
Platform,
|
|
8
|
+
SafeAreaView,
|
|
8
9
|
} from 'react-native';
|
|
9
10
|
import { ActivityIndicator } from '@ant-design/react-native';
|
|
10
|
-
import {
|
|
11
|
+
import { isIphoneX } from 'react-native-iphone-x-helper';
|
|
11
12
|
|
|
12
13
|
import { Colors, Theme } from '../../configs';
|
|
13
14
|
import HeaderAni, { heightHeader } from '../../commons/HeaderAni';
|
|
@@ -49,7 +50,8 @@ const WrapHeaderScrollable = ({
|
|
|
49
50
|
);
|
|
50
51
|
|
|
51
52
|
return (
|
|
52
|
-
|
|
53
|
+
// NOTE: We have problem if don't use SafeAreaView in here. Hinh will remove it later
|
|
54
|
+
<SafeAreaView style={[styles.container, headerAniStyle]}>
|
|
53
55
|
<HeaderAni
|
|
54
56
|
scrollY={animatedScrollYValue}
|
|
55
57
|
contentHeight={contentHeight}
|
|
@@ -103,7 +105,7 @@ const WrapHeaderScrollable = ({
|
|
|
103
105
|
</View>
|
|
104
106
|
)}
|
|
105
107
|
</Animated.ScrollView>
|
|
106
|
-
</
|
|
108
|
+
</SafeAreaView>
|
|
107
109
|
);
|
|
108
110
|
};
|
|
109
111
|
|
|
@@ -112,7 +114,6 @@ export default memo(WrapHeaderScrollable);
|
|
|
112
114
|
const styles = StyleSheet.create({
|
|
113
115
|
container: {
|
|
114
116
|
flex: 1,
|
|
115
|
-
paddingTop: getStatusBarHeight() + 10,
|
|
116
117
|
},
|
|
117
118
|
scrollView: {
|
|
118
119
|
flex: 1,
|
|
@@ -66,6 +66,7 @@ describe('Test HistoryChart', () => {
|
|
|
66
66
|
const configs = [{ id: 1 }];
|
|
67
67
|
await act(async () => {
|
|
68
68
|
tree = await create(wrapComponent(configs));
|
|
69
|
+
jest.runAllTimers();
|
|
69
70
|
});
|
|
70
71
|
await assertChartData([]);
|
|
71
72
|
});
|
|
@@ -91,6 +92,7 @@ describe('Test HistoryChart', () => {
|
|
|
91
92
|
const configs = [{ id: 1 }];
|
|
92
93
|
await act(async () => {
|
|
93
94
|
tree = await create(wrapComponent(configs));
|
|
95
|
+
jest.runAllTimers();
|
|
94
96
|
});
|
|
95
97
|
await assertChartData([{ x: 1, y: 2 }]);
|
|
96
98
|
});
|
|
@@ -116,6 +118,7 @@ describe('Test HistoryChart', () => {
|
|
|
116
118
|
const configs = [{ id: 1 }];
|
|
117
119
|
await act(async () => {
|
|
118
120
|
tree = await create(wrapComponent(configs));
|
|
121
|
+
jest.runAllTimers();
|
|
119
122
|
});
|
|
120
123
|
await assertChartData([{ x: 1, y: 2 }]);
|
|
121
124
|
});
|
|
@@ -141,6 +144,7 @@ describe('Test HistoryChart', () => {
|
|
|
141
144
|
const configs = [{ id: 1 }];
|
|
142
145
|
await act(async () => {
|
|
143
146
|
tree = await create(wrapComponent(configs));
|
|
147
|
+
jest.runAllTimers();
|
|
144
148
|
});
|
|
145
149
|
await assertChartData([
|
|
146
150
|
{ x: 1, y: 2 },
|
|
@@ -171,6 +175,7 @@ describe('Test HistoryChart', () => {
|
|
|
171
175
|
const configs = [{ id: 1 }];
|
|
172
176
|
await act(async () => {
|
|
173
177
|
tree = await create(wrapComponent(configs));
|
|
178
|
+
jest.runAllTimers();
|
|
174
179
|
});
|
|
175
180
|
await assertChartData([
|
|
176
181
|
{ x: 1, y: 2 },
|
|
@@ -183,7 +188,6 @@ describe('Test HistoryChart', () => {
|
|
|
183
188
|
const cacheUrl = 'https://s3.eoh.io/xxx.json';
|
|
184
189
|
const response = {
|
|
185
190
|
data: {
|
|
186
|
-
channel: 'cache-xxx',
|
|
187
191
|
configs: [
|
|
188
192
|
{
|
|
189
193
|
id: 1,
|
|
@@ -192,6 +196,7 @@ describe('Test HistoryChart', () => {
|
|
|
192
196
|
middle: {
|
|
193
197
|
ready: [],
|
|
194
198
|
not_ready: [{ date: '2022-03-03', url: cacheUrl }],
|
|
199
|
+
channel: 'cache-xxx',
|
|
195
200
|
},
|
|
196
201
|
},
|
|
197
202
|
],
|
|
@@ -202,6 +207,7 @@ describe('Test HistoryChart', () => {
|
|
|
202
207
|
const configs = [{ id: 1 }];
|
|
203
208
|
await act(async () => {
|
|
204
209
|
tree = await create(wrapComponent(configs));
|
|
210
|
+
jest.runAllTimers();
|
|
205
211
|
});
|
|
206
212
|
await assertChartData([
|
|
207
213
|
{ x: 1, y: 2 },
|
|
@@ -228,7 +234,6 @@ describe('Test HistoryChart', () => {
|
|
|
228
234
|
const cacheUrl4 = 'https://s3.eoh.io/xxx4.json';
|
|
229
235
|
const response = {
|
|
230
236
|
data: {
|
|
231
|
-
channel: 'cache-xxx',
|
|
232
237
|
configs: [
|
|
233
238
|
{
|
|
234
239
|
id: 1,
|
|
@@ -243,6 +248,7 @@ describe('Test HistoryChart', () => {
|
|
|
243
248
|
{ date: '2022-03-03', url: cacheUrl2 },
|
|
244
249
|
{ date: '2022-03-05', url: cacheUrl4 },
|
|
245
250
|
],
|
|
251
|
+
channel: 'cache-xxx',
|
|
246
252
|
},
|
|
247
253
|
},
|
|
248
254
|
],
|
|
@@ -256,6 +262,7 @@ describe('Test HistoryChart', () => {
|
|
|
256
262
|
const configs = [{ id: 1 }];
|
|
257
263
|
await act(async () => {
|
|
258
264
|
tree = await create(wrapComponent(configs));
|
|
265
|
+
jest.runAllTimers();
|
|
259
266
|
});
|
|
260
267
|
await assertChartData([
|
|
261
268
|
{ x: 1, y: 2 },
|
|
@@ -61,46 +61,44 @@ export const updateConfigChart = async (
|
|
|
61
61
|
})
|
|
62
62
|
);
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
...config.middle.ready,
|
|
80
|
-
];
|
|
81
|
-
|
|
82
|
-
// sort
|
|
83
|
-
middleDataByDay.sort((a, b) => (a.date > b.date ? 1 : -1)); // small to large
|
|
84
|
-
const middleData = middleDataByDay.map((x) => x.data).flat();
|
|
85
|
-
|
|
86
|
-
data_by_id[config.id] = [
|
|
87
|
-
...config.head,
|
|
88
|
-
...middleData,
|
|
89
|
-
...config.tail,
|
|
90
|
-
];
|
|
91
|
-
})
|
|
92
|
-
);
|
|
64
|
+
data.configs.map((config) => {
|
|
65
|
+
if (config.middle.not_ready.length > 0) {
|
|
66
|
+
const channel = getPusher().subscribe(config.middle.channel);
|
|
67
|
+
channel.bind('caching-value-log-process', async ({ success }) => {
|
|
68
|
+
await Promise.all(
|
|
69
|
+
config.middle.not_ready.map((item) =>
|
|
70
|
+
(async () => {
|
|
71
|
+
item.data = await fetchDataS3(item.url);
|
|
72
|
+
})()
|
|
73
|
+
)
|
|
74
|
+
);
|
|
75
|
+
const middleDataByDay = [
|
|
76
|
+
...config.middle.not_ready,
|
|
77
|
+
...config.middle.ready,
|
|
78
|
+
];
|
|
93
79
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
80
|
+
middleDataByDay.sort((a, b) => (a.date > b.date ? 1 : -1)); // small to large
|
|
81
|
+
const middleData = middleDataByDay.map((x) => x.data).flat();
|
|
82
|
+
data_by_id[config.id] = [...config.head, ...middleData, ...config.tail];
|
|
83
|
+
setChartData((chartData) => {
|
|
84
|
+
const index = chartData.map((c) => c.id).indexOf(config.id);
|
|
85
|
+
chartData[index].data = data_by_id[config.id];
|
|
86
|
+
return [...chartData];
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
});
|
|
102
91
|
};
|
|
103
92
|
|
|
93
|
+
const areEqual = ({ configs: oldConfigs }, { configs: newConfigs }) => {
|
|
94
|
+
return (
|
|
95
|
+
JSON.stringify(oldConfigs.map((config) => config.id).sort()) ===
|
|
96
|
+
JSON.stringify(newConfigs.map((config) => config.id).sort())
|
|
97
|
+
);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
let timeoutId;
|
|
101
|
+
|
|
104
102
|
const ConfigHistoryChart = memo(({ configs }) => {
|
|
105
103
|
const [chartData, setChartData] = useState(configs);
|
|
106
104
|
const [startDate, setStartDate] = useState(
|
|
@@ -128,7 +126,11 @@ const ConfigHistoryChart = memo(({ configs }) => {
|
|
|
128
126
|
});
|
|
129
127
|
updateConfigChart(success, data, configuration, setChartData);
|
|
130
128
|
};
|
|
131
|
-
|
|
129
|
+
|
|
130
|
+
timeoutId = setTimeout(fetchData, 200);
|
|
131
|
+
return () => {
|
|
132
|
+
clearTimeout(timeoutId);
|
|
133
|
+
};
|
|
132
134
|
}, [startDate, endDate, configs]);
|
|
133
135
|
|
|
134
136
|
if (!chartData.length) {
|
|
@@ -143,6 +145,6 @@ const ConfigHistoryChart = memo(({ configs }) => {
|
|
|
143
145
|
setEndDate={setEndDate}
|
|
144
146
|
/>
|
|
145
147
|
);
|
|
146
|
-
});
|
|
148
|
+
}, areEqual);
|
|
147
149
|
|
|
148
150
|
export default ConfigHistoryChart;
|
package/src/configs/Constants.js
CHANGED
|
@@ -254,6 +254,7 @@ export const NOTIFICATION_TYPES = {
|
|
|
254
254
|
FIRE: 'FIRE',
|
|
255
255
|
SOS: 'SOS',
|
|
256
256
|
FILTER_WATER: 'FILTER_WATER',
|
|
257
|
+
LOW_BATTERY: 'LOW_BATTERY',
|
|
257
258
|
};
|
|
258
259
|
|
|
259
260
|
export const ACTIVITY_LOG_TYPES = {
|
|
@@ -276,6 +277,7 @@ export const PROBLEM_CODE = {
|
|
|
276
277
|
UNKNOWN_ERROR: 'UNKNOWN_ERROR',
|
|
277
278
|
CANCEL_ERROR: 'CANCEL_ERROR',
|
|
278
279
|
ADDRESS_CHANGING: 'Please wait 30s for changing address.',
|
|
280
|
+
READ_CONFIG_PERMISSION: 'read_config_permission_error',
|
|
279
281
|
};
|
|
280
282
|
|
|
281
283
|
export const DATE_TIME_FORMAT = {
|
package/src/configs/SCConfig.js
CHANGED
|
@@ -86,6 +86,7 @@ LocaleConfig.locales.en = {
|
|
|
86
86
|
};
|
|
87
87
|
|
|
88
88
|
const SCDefaultConfig = {
|
|
89
|
+
ENV: 'PRODUCTION',
|
|
89
90
|
apiRoot: 'https://backend.eoh.io/api',
|
|
90
91
|
GOOGLE_MAP_API_KEY: 'AIzaSyCF1Q-WFXCnfAHhOeXRF9WK7eT-TtxO9ss',
|
|
91
92
|
LG_CLIENT_ID: '2b85aee334f046848341547894bb7c4e',
|
|
@@ -100,6 +101,7 @@ const SCDefaultConfig = {
|
|
|
100
101
|
|
|
101
102
|
export class SCConfig {
|
|
102
103
|
static apiRoot = SCDefaultConfig.apiRoot;
|
|
104
|
+
static ENV = SCDefaultConfig.ENV;
|
|
103
105
|
static GOOGLE_MAP_API_KEY = SCDefaultConfig.GOOGLE_MAP_API_KEY;
|
|
104
106
|
static LG_CLIENT_ID = SCDefaultConfig.LG_CLIENT_ID;
|
|
105
107
|
static LG_REDIRECT_URI_APP = SCDefaultConfig.LG_REDIRECT_URI_APP;
|
|
@@ -115,6 +117,7 @@ export class SCConfig {
|
|
|
115
117
|
export const initSCConfig = (config) => {
|
|
116
118
|
api.setBaseURL(config.apiRoot ?? SCDefaultConfig.apiRoot);
|
|
117
119
|
LocaleConfig.defaultLocale = config.language ?? SCConfig.language;
|
|
120
|
+
SCConfig.ENV = config.ENV ?? SCConfig.ENV;
|
|
118
121
|
SCConfig.language = config.language ?? SCConfig.language;
|
|
119
122
|
SCConfig.apiRoot = config.apiRoot ?? SCDefaultConfig.apiRoot;
|
|
120
123
|
SCConfig.GOOGLE_MAP_API_KEY =
|
|
@@ -4,7 +4,6 @@ import React, { memo } from 'react';
|
|
|
4
4
|
import AddCommonSelectUnit from '../screens/AddCommon/SelectUnit';
|
|
5
5
|
import AddCommonSelectSubUnit from '../screens/AddCommon/SelectSubUnit';
|
|
6
6
|
import AddNewDevice from '../screens/AddNewDevice';
|
|
7
|
-
import ConnectingDevices from '../screens/AddNewDevice/ConnectingDevices';
|
|
8
7
|
import Route from '../utils/Route';
|
|
9
8
|
import { screenOptions } from './utils';
|
|
10
9
|
|
|
@@ -27,10 +26,6 @@ export const AddDeviceStack = memo(() => {
|
|
|
27
26
|
component={AddCommonSelectSubUnit}
|
|
28
27
|
/>
|
|
29
28
|
<Stack.Screen name={Route.AddNewDevice} component={AddNewDevice} />
|
|
30
|
-
<Stack.Screen
|
|
31
|
-
name={Route.ConnectingDevices}
|
|
32
|
-
component={ConnectingDevices}
|
|
33
|
-
/>
|
|
34
29
|
</Stack.Navigator>
|
|
35
30
|
);
|
|
36
31
|
});
|