@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.
Files changed (49) hide show
  1. package/package.json +1 -1
  2. package/src/commons/ActionGroup/OnOffTemplate/index.js +6 -8
  3. package/src/commons/ActionGroup/SliderRangeTemplate.js +7 -2
  4. package/src/commons/ActionGroup/__test__/OnOffTemplate.test.js +98 -0
  5. package/src/commons/ActionGroup/__test__/SliderRangeTemplate.test.js +27 -3
  6. package/src/commons/ActionTemplate/__test__/CurtainAction.test.js +64 -0
  7. package/src/commons/ActionTemplate/__test__/OnOffSmartLockAction.test.js +54 -0
  8. package/src/commons/Device/HorizontalBarChart.js +0 -1
  9. package/src/commons/Device/PMSensor/PMSensorIndicatior.js +3 -1
  10. package/src/commons/Processing/styles.js +0 -2
  11. package/src/commons/Sharing/WrapHeaderScrollable.js +5 -4
  12. package/src/commons/UnitSummary/ConfigHistoryChart/__test__/ConfigHistoryChart.test.js +9 -2
  13. package/src/commons/UnitSummary/ConfigHistoryChart/index.js +41 -39
  14. package/src/configs/Constants.js +2 -0
  15. package/src/configs/SCConfig.js +3 -0
  16. package/src/navigations/AddDeviceStack.js +0 -5
  17. package/src/navigations/UnitStack.js +5 -4
  18. package/src/screens/AQIGuide/index.js +2 -2
  19. package/src/screens/ActivityLog/styles/itemLogStyles.js +1 -0
  20. package/src/screens/AddNewDevice/__test__/AddNewDevice.test.js +1 -1
  21. package/src/screens/AddNewGateway/ConnectingDevice.js +25 -3
  22. package/src/screens/AddNewGateway/ConnectingWifiGuide.js +1 -1
  23. package/src/screens/AddNewGateway/ConnectingWifiGuideStyles.js +10 -0
  24. package/src/screens/AddNewGateway/ConnectingZigbeeDevice.js +3 -17
  25. package/src/screens/AddNewGateway/ShareWifiPassword.js +2 -1
  26. package/src/screens/AddNewGateway/__test__/ConnectingWifiDevice.test.js +2 -1
  27. package/src/screens/AddNewGateway/__test__/ConnectingZigbeeDevice.test.js +27 -1
  28. package/src/screens/Device/detail.js +1 -3
  29. package/src/screens/Gateway/components/Information/styles.js +0 -1
  30. package/src/screens/Notification/__test__/NotificationItem.test.js +1 -0
  31. package/src/screens/Notification/components/NotificationItem.js +16 -1
  32. package/src/screens/Notification/index.js +1 -0
  33. package/src/screens/Notification/styles/indexStyles.js +3 -0
  34. package/src/screens/Sharing/SelectPermission.js +2 -2
  35. package/src/screens/SmartAccount/SuccessfullyConnected/__test__/SuccessfullyConnected.test.js +26 -7
  36. package/src/screens/SmartAccount/SuccessfullyConnected/index.js +29 -11
  37. package/src/screens/SyncLGDevice/__test__/AddLGDevice.test.js +1 -1
  38. package/src/screens/Template/__test__/GatewayList.test.js +1 -1
  39. package/src/screens/Template/__test__/Information.test.js +1 -1
  40. package/src/screens/Unit/Detail.js +24 -18
  41. package/src/screens/Unit/__test__/Detail.test.js +62 -18
  42. package/src/utils/Apis/axios.js +52 -36
  43. package/src/utils/I18n/translations/en.json +4 -0
  44. package/src/utils/I18n/translations/vi.json +5 -1
  45. package/src/utils/Storage.js +0 -4
  46. package/src/utils/Utils.js +1 -1
  47. package/src/utils/__test__/Utils.test.js +27 -3
  48. package/src/screens/AddNewDevice/ConnectingDevices.js +0 -62
  49. package/src/screens/AddNewDevice/__test__/ConnectingDevices.test.js +0 -110
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@eohjsc/react-native-smart-city",
3
3
  "title": "React Native Smart Home",
4
- "version": "0.3.49",
4
+ "version": "0.3.51",
5
5
  "description": "TODO",
6
6
  "main": "index.js",
7
7
  "files": [
@@ -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
- if (action_data) {
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
- if (sensor?.is_managed_by_backend) {
101
- if (config && sensor.device_type === DEVICE_TYPE.LG_THINQ) {
102
- watchMultiConfigs([config]);
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
- [configuration?.action_brightness_data, doAction]
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 action_brightness_data = {
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
- action_brightness_data: action_brightness_data,
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
+ });
@@ -163,7 +163,6 @@ const styles = StyleSheet.create({
163
163
  backgroundColor: Colors.White,
164
164
  justifyContent: 'center',
165
165
  flex: 1,
166
- marginRight: 24,
167
166
  },
168
167
  chartStyle: {
169
168
  backgroundColor: Colors.White,
@@ -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 = item?.value >= 0 ? item?.value : '--';
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 { getStatusBarHeight, isIphoneX } from 'react-native-iphone-x-helper';
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
- <View style={[styles.container, headerAniStyle]}>
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
- </View>
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
- if (data.channel) {
65
- const channel = getPusher().subscribe(data.channel);
66
- // eslint-disable-next-line no-shadow
67
- channel.bind('caching-value-log-process', async ({ success }) => {
68
- await Promise.all(
69
- data.configs.map(async (config) => {
70
- if (config.middle.not_ready.length) {
71
- await Promise.all(
72
- config.middle.not_ready.map(async (item) => {
73
- item.data = await fetchDataS3(item.url);
74
- })
75
- );
76
- }
77
- const middleDataByDay = [
78
- ...config.middle.not_ready,
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
- setChartData(
95
- configuration.map((config) => {
96
- config.data = data_by_id[config.id];
97
- return config;
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
- fetchData();
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;
@@ -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 = {
@@ -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
  });