@eohjsc/react-native-smart-city 0.2.54 → 0.2.58

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 (60) hide show
  1. package/assets/images/SonosSpeaker/buttonpause-active.svg +3 -0
  2. package/assets/images/SonosSpeaker/buttonpause-notactive.svg +3 -0
  3. package/assets/images/SonosSpeaker/picture-main-notactive.svg +5 -0
  4. package/assets/images/SonosSpeaker/picture-main.svg +6 -0
  5. package/assets/images/SonosSpeaker/picture-volume.svg +3 -0
  6. package/package.json +4 -23
  7. package/src/commons/AlertAction/index.js +3 -3
  8. package/src/commons/Auth/__test__/AccountList.test.js +33 -0
  9. package/src/commons/CameraDevice/index.js +2 -0
  10. package/src/commons/CardShadow/index.js +1 -1
  11. package/src/commons/CardShadow/styles.js +1 -3
  12. package/src/commons/DateTimeRangeChange/index.js +2 -2
  13. package/src/commons/Device/HistoryChart.js +9 -39
  14. package/src/commons/Device/HorizontalBarChart.js +1 -1
  15. package/src/commons/Device/LinearChart.js +0 -34
  16. package/src/commons/Device/PMSensor/PMSensorIndicatior.js +1 -1
  17. package/src/commons/Device/PMSensor/PMSensorIndicatorStyles.js +2 -1
  18. package/src/commons/Device/SonosSpeaker/__test__/SonosSpeaker.test.js +57 -0
  19. package/src/commons/Device/SonosSpeaker/index.js +88 -0
  20. package/src/commons/Device/SonosSpeaker/styles.js +57 -0
  21. package/src/commons/Form/CurrencyInput.js +163 -0
  22. package/src/commons/Form/__test__/CurrencyInput.test.js +65 -0
  23. package/src/commons/MediaPlayerDetail/index.js +160 -160
  24. package/src/commons/Sharing/RowMember.js +7 -2
  25. package/src/commons/Sharing/__test__/RowMember.test.js +42 -0
  26. package/src/commons/SubUnit/ShortDetail.js +11 -5
  27. package/src/commons/ThreeButtonHistory/__test__/ThreeButtonHistory.test.js +17 -8
  28. package/src/commons/ThreeButtonHistory/index.js +52 -23
  29. package/src/commons/UnitSummary/AirQuality/SegmentedRoundDisplay/index.js +1 -1
  30. package/src/configs/API.js +5 -0
  31. package/src/configs/Constants.js +3 -3
  32. package/src/configs/SCConfig.js +8 -0
  33. package/src/iot/RemoteControl/Bluetooth.js +14 -0
  34. package/src/iot/RemoteControl/index.js +0 -1
  35. package/src/screens/ActivityLog/ItemLog.js +9 -0
  36. package/src/screens/ActivityLog/__test__/ItemLog.test.js +43 -0
  37. package/src/screens/AddCommon/SelectSubUnit.js +24 -2
  38. package/src/screens/AddCommon/SelectUnit.js +12 -0
  39. package/src/screens/Device/__test__/detail.test.js +0 -5
  40. package/src/screens/Device/components/SensorDisplayItem.js +10 -10
  41. package/src/screens/Device/detail.js +15 -1
  42. package/src/screens/Device/hooks/useDisconnectedDevice.js +31 -26
  43. package/src/screens/Sharing/MemberList.js +2 -9
  44. package/src/screens/SubUnit/AddSubUnit.js +78 -59
  45. package/src/screens/TDSGuide/index.js +6 -4
  46. package/src/screens/Unit/Detail.js +7 -1
  47. package/src/screens/Unit/ManageUnit/index.test.js +34 -0
  48. package/src/screens/Unit/ManageUnit.js +3 -4
  49. package/src/screens/Unit/SmartAccount.js +2 -3
  50. package/src/screens/Unit/SmartAccountItem.js +1 -1
  51. package/src/screens/Unit/Summaries.js +5 -1
  52. package/src/screens/Unit/hook/useStateAlertRemove.js +3 -1
  53. package/src/screens/UnitSummary/components/3PPowerConsumption/index.js +1 -1
  54. package/src/screens/UnitSummary/components/PowerConsumption/index.js +1 -1
  55. package/src/screens/UnitSummary/components/WaterQuality/Item/index.js +1 -3
  56. package/src/screens/UnitSummary/index.js +3 -2
  57. package/src/utils/Apis/axios.js +17 -5
  58. package/src/utils/I18n/translations/en.json +8 -3
  59. package/src/utils/I18n/translations/vi.json +9 -4
  60. package/src/utils/Utils.js +22 -2
@@ -214,18 +214,27 @@ describe('test ThreeButtonHistory', () => {
214
214
  await calendar.props.onDayPress({ dateString: date });
215
215
  });
216
216
  };
217
- await selectDate('2021-09-20');
218
- await selectDate('2021-09-02');
219
- await selectDate('2021-09-09');
220
- await selectDate('2021-09-10');
221
- await selectDate('2021-09-05');
222
- await selectDate('2021-09-05');
223
- await selectDate('2021-09-20');
217
+ // 2 -> 9
218
+ await selectDate('2021-09-20'); // 2 -> 20
219
+ await selectDate('2021-09-01'); // 1 -> 20
220
+ await selectDate('2021-09-15'); // 1 -> 15
221
+ await selectDate('2021-09-05'); // 5 -> 15
222
+ await selectDate('2021-09-15'); // 5 -> null
223
+ await selectDate('2021-09-05'); // null -> null
224
+ await selectDate('2021-09-10'); // 10 -> null
225
+ await selectDate('2021-09-05'); // 5 -> 10
226
+ await selectDate('2021-09-10'); // 5 -> null
227
+ await selectDate('2021-09-20'); // 5 -> 20
228
+ await selectDate('2021-09-05'); // null -> 20
229
+ await selectDate('2021-09-25'); // 20 -> 25
230
+ await selectDate('2021-09-20'); // null -> 25
231
+ await selectDate('2021-09-10'); // 10 -> 25
232
+
224
233
  const viewButtonBottom = instance.findByType(ViewButtonBottom);
225
234
  await act(async () => {
226
235
  await viewButtonBottom.props.onRightClick();
227
236
  });
228
237
  expect(mockSetStartDate).toBeCalledWith(moment('2021-09-10').valueOf());
229
- expect(mockSetEndDate).toBeCalledWith(moment('2021-09-20').valueOf());
238
+ expect(mockSetEndDate).toBeCalledWith(moment('2021-09-25').valueOf());
230
239
  });
231
240
  });
@@ -20,7 +20,7 @@ const ThreeButtonHistory = memo(
20
20
  const t = useTranslations();
21
21
  const calendarRef = useRef();
22
22
  const [selectedIndex, setSelectedIndex] = useState(2);
23
- const [isShowDate, setIsShowDate] = useState(false);
23
+ const [showCalendar, setShowCalendar] = useState(false);
24
24
  const [selectedStart, setSelectedStart] = useState(
25
25
  moment(startDate).format('YYYY-MM-DD')
26
26
  );
@@ -57,15 +57,15 @@ const ThreeButtonHistory = memo(
57
57
  [selectedIndex]
58
58
  );
59
59
 
60
- const onPressCancel = useCallback(() => {
60
+ const onCalendarCancel = useCallback(() => {
61
61
  if (showSelectMonth) {
62
62
  setShowSelectMonth(false);
63
63
  return;
64
64
  }
65
- setIsShowDate(false);
65
+ setShowCalendar(false);
66
66
  }, [showSelectMonth, setShowSelectMonth]);
67
67
 
68
- const onPressDone = useCallback(() => {
68
+ const onCalendarDone = useCallback(() => {
69
69
  if (showSelectMonth) {
70
70
  setShowSelectMonth(false);
71
71
  return;
@@ -73,7 +73,7 @@ const ThreeButtonHistory = memo(
73
73
  if (selectedStart === null || selectedEnd === null) {
74
74
  return;
75
75
  }
76
- setIsShowDate(false);
76
+ setShowCalendar(false);
77
77
  setStartDate(moment(selectedStart).valueOf());
78
78
  setEndDate(moment(selectedEnd).valueOf());
79
79
  }, [
@@ -85,9 +85,12 @@ const ThreeButtonHistory = memo(
85
85
  setShowSelectMonth,
86
86
  ]);
87
87
 
88
- const onDayPress = useCallback(
88
+ const onDateSelected = useCallback(
89
89
  (date) => {
90
90
  const selectedDate = date.dateString;
91
+ const mmSelectedDate = moment(selectedDate);
92
+ onMonthSelected(mmSelectedDate);
93
+
91
94
  if (selectedDate === selectedStart) {
92
95
  setSelectedStart(null);
93
96
  return;
@@ -96,25 +99,54 @@ const ThreeButtonHistory = memo(
96
99
  setSelectedEnd(null);
97
100
  return;
98
101
  }
99
- if (selectedStart !== null && selectedEnd !== null) {
102
+
103
+ if (!!selectedStart && !!selectedEnd) {
104
+ if (mmSelectedDate.isAfter(selectedEnd, 'date')) {
105
+ setSelectedEnd(selectedDate);
106
+ return;
107
+ }
108
+ if (mmSelectedDate.isBefore(selectedStart, 'date')) {
109
+ setSelectedStart(selectedDate);
110
+ return;
111
+ }
112
+ if (
113
+ Math.abs(mmSelectedDate.diff(selectedStart, 'days')) <=
114
+ Math.abs(mmSelectedDate.diff(selectedEnd, 'days'))
115
+ ) {
116
+ setSelectedStart(selectedDate);
117
+ } else {
118
+ setSelectedEnd(selectedDate);
119
+ }
120
+ return;
121
+ }
122
+
123
+ if (selectedStart) {
124
+ if (mmSelectedDate.isBefore(selectedStart, 'date')) {
125
+ setSelectedStart(selectedDate);
126
+ setSelectedEnd(selectedStart);
127
+ } else {
128
+ setSelectedEnd(selectedDate);
129
+ }
100
130
  return;
101
131
  }
102
- if (selectedEnd === null) {
103
- setSelectedEnd(selectedDate);
104
- } else {
105
- if (moment(selectedDate).isAfter(selectedEnd, 'date')) {
132
+
133
+ if (selectedEnd) {
134
+ if (mmSelectedDate.isAfter(selectedEnd, 'date')) {
106
135
  setSelectedStart(selectedEnd);
107
136
  setSelectedEnd(selectedDate);
108
137
  } else {
109
138
  setSelectedStart(selectedDate);
110
139
  }
140
+ return;
111
141
  }
142
+
143
+ setSelectedStart(selectedDate);
112
144
  },
113
- [selectedStart, selectedEnd]
145
+ [selectedStart, selectedEnd, onMonthSelected]
114
146
  );
115
147
 
116
148
  const onPressItemButton = useCallback(
117
- (index) => {
149
+ (index) => () => {
118
150
  switch (index) {
119
151
  case 0:
120
152
  setGroupBy('week');
@@ -124,9 +156,7 @@ const ThreeButtonHistory = memo(
124
156
  break;
125
157
  case 2:
126
158
  setGroupBy('date');
127
- if (selectedIndex === 2) {
128
- setIsShowDate(true);
129
- }
159
+ selectedIndex === 2 && setShowCalendar(true);
130
160
  }
131
161
  setSelectedIndex(index);
132
162
  },
@@ -212,7 +242,6 @@ const ThreeButtonHistory = memo(
212
242
  },
213
243
  },
214
244
  selected: true,
215
- disableTouchEvent: true,
216
245
  color: Colors.Gray4,
217
246
  };
218
247
  }
@@ -228,15 +257,15 @@ const ThreeButtonHistory = memo(
228
257
  <ItemButton
229
258
  key={index}
230
259
  dateTitle={item.dateTitle}
231
- onPress={() => onPressItemButton(index)}
260
+ onPress={onPressItemButton(index)}
232
261
  isSelected={selectedIndex === index}
233
262
  />
234
263
  );
235
264
  })}
236
265
  </View>
237
266
  <BottomSheet
238
- isVisible={isShowDate}
239
- onBackdropPress={onPressCancel}
267
+ isVisible={showCalendar}
268
+ onBackdropPress={onCalendarCancel}
240
269
  style={styles.modal}
241
270
  >
242
271
  <View style={styles.calendar}>
@@ -257,7 +286,7 @@ const ThreeButtonHistory = memo(
257
286
  current={currentMonth.format('YYYY-MM-DD')}
258
287
  style={showSelectMonth && styles.displayNone}
259
288
  markingType={'custom'}
260
- onDayPress={onDayPress}
289
+ onDayPress={onDateSelected}
261
290
  maxDate={moment().format('YYYY-MM-DD')}
262
291
  markedDates={markedDates}
263
292
  hideArrows={true}
@@ -267,9 +296,9 @@ const ThreeButtonHistory = memo(
267
296
  <View style={styles.separator} />
268
297
  <ViewButtonBottom
269
298
  leftTitle={t('cancel')}
270
- onLeftClick={onPressCancel}
299
+ onLeftClick={onCalendarCancel}
271
300
  rightTitle={t('done')}
272
- onRightClick={onPressDone}
301
+ onRightClick={onCalendarDone}
273
302
  />
274
303
  </View>
275
304
  </BottomSheet>
@@ -163,7 +163,7 @@ const SegmentedRoundDisplay = ({
163
163
  <Text
164
164
  x={svgWidth / 2 + 50}
165
165
  fontWeight="normal"
166
- fontSize={valueText.toString().length >= 6 ? 46 : 56}
166
+ fontSize={valueText.toString().length >= 6 ? 35 : 56}
167
167
  y={svgHeight / 2 + 30}
168
168
  fill={filledArcColor}
169
169
  textAnchor="middle"
@@ -172,6 +172,11 @@ const API = {
172
172
  SCConfig.apiRoot +
173
173
  `/connection_manager/lg_thinq/device_status/${sensorId}/`,
174
174
  },
175
+ VCONNEX: {
176
+ AUTHORIZE: (client_id, redirect_uri, user_id, station_id) =>
177
+ // eslint-disable-next-line max-len
178
+ `https://partner-api-stg.vconnex.vn/oauth/authorize?client_id=${client_id}&redirect_uri=${redirect_uri}&response_type=code&scope=SYNCH&scope=CONTROL&scope=QUERY&state=${user_id}@${station_id}`,
179
+ },
175
180
  },
176
181
  NOTIFICATION: {
177
182
  LIST_ALL_NOTIFICATIONS: (page, type) =>
@@ -1,6 +1,6 @@
1
1
  import { Platform, Dimensions, StatusBar } from 'react-native';
2
2
  import { RFValue } from 'react-native-responsive-fontsize';
3
- import OneTap from '../../assets/images/OneTap@1x.svg';
3
+ import OneTap from '../../assets/images/OneTap.svg';
4
4
  import ValueChange from '../../assets/images/ValueChange.svg';
5
5
  import Schedule from '../../assets/images/Schedule.svg';
6
6
 
@@ -116,13 +116,13 @@ export const AUTOMATES = {
116
116
  value_change: {
117
117
  value: AUTOMATE_TYPE.VALUE_CHANGE,
118
118
  title: 'value_change',
119
- explanation: 'short_explanation',
119
+ explanation: 'setup_the_conditions',
120
120
  icon: ValueChange,
121
121
  },
122
122
  schedule: {
123
123
  value: AUTOMATE_TYPE.SCHEDULE,
124
124
  title: 'schedule',
125
- explanation: 'short_explanation',
125
+ explanation: 'setup_the_schedule',
126
126
  icon: Schedule,
127
127
  },
128
128
  };
@@ -90,6 +90,8 @@ const SCDefaultConfig = {
90
90
  LG_CLIENT_ID: '2b85aee334f046848341547894bb7c4e',
91
91
  LG_REDIRECT_URI_APP: 'app://eoh/sync-lg-device',
92
92
  LG_URL: 'https://qt-vn.m.lgaccount.com/emp/v2',
93
+ VCONNEX_CLIENT_ID: '',
94
+ VCONNEX_REDIRECT_URI_APP: '',
93
95
  pusherAppKey: '9a591ae4a764acc08714',
94
96
  pusherAppCluster: 'ap1',
95
97
  };
@@ -100,6 +102,8 @@ export class SCConfig {
100
102
  static LG_CLIENT_ID = SCDefaultConfig.LG_CLIENT_ID;
101
103
  static LG_REDIRECT_URI_APP = SCDefaultConfig.LG_REDIRECT_URI_APP;
102
104
  static LG_URL = SCDefaultConfig.LG_URL;
105
+ static VCONNEX_CLIENT_ID = SCDefaultConfig.VCONNEX_CLIENT_ID;
106
+ static VCONNEX_REDIRECT_URI_APP = SCDefaultConfig.VCONNEX_REDIRECT_URI_APP;
103
107
  static pusherAppKey = SCDefaultConfig.pusherAppKey;
104
108
  static pusherAppCluste = SCDefaultConfig.pusherAppCluster;
105
109
  }
@@ -113,6 +117,10 @@ export const initSCConfig = (config) => {
113
117
  SCConfig.LG_REDIRECT_URI_APP =
114
118
  config.LG_REDIRECT_URI_APP ?? SCDefaultConfig.LG_REDIRECT_URI_APP;
115
119
  SCConfig.LG_URL = config.LG_URL ?? SCDefaultConfig.LG_URL;
120
+ SCConfig.VCONNEX_CLIENT_ID =
121
+ config.VCONNEX_CLIENT_ID ?? SCDefaultConfig.VCONNEX_CLIENT_ID;
122
+ SCConfig.VCONNEX_REDIRECT_URI_APP =
123
+ config.VCONNEX_REDIRECT_URI_APP ?? SCDefaultConfig.VCONNEX_REDIRECT_URI_APP;
116
124
  SCConfig.pusherAppKey = config.pusherAppKey ?? SCDefaultConfig.pusherAppKey;
117
125
  SCConfig.pusherAppCluster =
118
126
  config.pusherAppCluster ?? SCDefaultConfig.pusherAppCluster;
@@ -5,6 +5,7 @@ import t from '../../hooks/Common/useTranslations';
5
5
  import base64 from 'react-native-base64';
6
6
  import { BleManager } from 'react-native-ble-plx';
7
7
  import { ToastBottomHelper } from '../../utils/Utils';
8
+ import { useEffect, useState } from 'react';
8
9
 
9
10
  const bluetoothDevices = {};
10
11
  const needToScanDevices = [];
@@ -165,6 +166,19 @@ export const isBluetoothEnabled = async () => {
165
166
  return state === 'PoweredOn';
166
167
  };
167
168
 
169
+ export const useIsBluetoothEnabled = () => {
170
+ const [isEnabled, setIsEnabled] = useState(null);
171
+
172
+ useEffect(() => {
173
+ const subscription = bleManager.onStateChange((state) => {
174
+ setIsEnabled(state === 'PoweredOn');
175
+ }, true);
176
+
177
+ return () => subscription.remove();
178
+ }, []);
179
+ return isEnabled;
180
+ };
181
+
168
182
  export const enableBluetoothForAndroid = async () => {
169
183
  await bleManager.enable();
170
184
  };
@@ -16,7 +16,6 @@ export const sendRemoteCommand = async (sensor, action, data) => {
16
16
  );
17
17
  return;
18
18
  }
19
-
20
19
  if (action.command_prefer_over_bluetooth) {
21
20
  try {
22
21
  await sendCommandOverBluetooth(sensor, action, data);
@@ -39,6 +39,15 @@ const DetailLog = ({ item }) => {
39
39
  <Text style={styles.name}>{item.name || item.params?.username}</Text>
40
40
  </Text>
41
41
  );
42
+ default:
43
+ return (
44
+ <Text style={styles.text}>
45
+ {item.action_name
46
+ ? `${item.action_name} ${t('by')} `
47
+ : `${t('activated_by')} `}
48
+ <Text style={styles.name}>{item.name || item.params?.username}</Text>
49
+ </Text>
50
+ );
42
51
  }
43
52
  };
44
53
 
@@ -60,6 +60,49 @@ test('test ItemLog one tap', () => {
60
60
  expect(texts[2].props.children).toBe(props.item.params.username);
61
61
  });
62
62
 
63
+ test('test ItemLog script update', () => {
64
+ let tree;
65
+ let props = {
66
+ item: {
67
+ content_code: 'SCRIPT_UPDATED_BY',
68
+ params: {
69
+ username: 'username',
70
+ },
71
+ created_at: '2021-07-02T15:48:24.917932Z',
72
+ },
73
+ type: 'automate',
74
+ length: 2,
75
+ index: 1,
76
+ };
77
+ act(() => {
78
+ tree = create(wrapComponent(props));
79
+ });
80
+ const instance = tree.root;
81
+ const texts = instance.findAllByType(Text);
82
+ expect(texts[2].props.children).toBe(props.item.params.username);
83
+ });
84
+
85
+ test('test ItemLog no content_code', () => {
86
+ let tree;
87
+ let props = {
88
+ item: {
89
+ params: {
90
+ username: 'username',
91
+ },
92
+ created_at: '2021-07-02T15:48:24.917932Z',
93
+ },
94
+ type: 'action',
95
+ length: 2,
96
+ index: 1,
97
+ };
98
+ act(() => {
99
+ tree = create(wrapComponent(props));
100
+ });
101
+ const instance = tree.root;
102
+ const texts = instance.findAllByType(Text);
103
+ expect(texts[2].props.children).toBe(props.item.params.username);
104
+ });
105
+
63
106
  describe('test ItemLog emergency event', () => {
64
107
  let tree;
65
108
  let props;
@@ -11,6 +11,7 @@ import Routes from '../../utils/Route';
11
11
  import { TESTID } from '../../configs/Constants';
12
12
  import styles from './SelectSubUnitStyles';
13
13
  import Button from '../../commons/Button';
14
+ import { SCConfig } from '../../configs/SCConfig';
14
15
 
15
16
  const AddCommonSelectSubUnit = ({ route }) => {
16
17
  const t = useTranslations();
@@ -31,6 +32,9 @@ const AddCommonSelectSubUnit = ({ route }) => {
31
32
  case 'AddHassiDevice':
32
33
  setTitle(t('select_a_sub_unit'));
33
34
  break;
35
+ case 'AddVconnexDevice':
36
+ setTitle(t('select_a_sub_unit'));
37
+ break;
34
38
  default:
35
39
  setTitle(t('add_new_gateway'));
36
40
  setSubTitle(t('select_a_sub_unit'));
@@ -70,10 +74,28 @@ const AddCommonSelectSubUnit = ({ route }) => {
70
74
  station: subUnits[selectedIndex]?.id,
71
75
  });
72
76
  break;
77
+ case 'AddVconnexDevice':
78
+ navigation.navigate(Routes.Browser, {
79
+ link: API.IOT.VCONNEX.AUTHORIZE(
80
+ SCConfig.VCONNEX_CLIENT_ID,
81
+ SCConfig.VCONNEX_REDIRECT_URI_APP,
82
+ unit.user_id,
83
+ subUnits[selectedIndex]?.id
84
+ ),
85
+ });
86
+ break;
73
87
  default:
74
88
  break;
75
89
  }
76
- }, [addType, navigation, subUnits, selectedIndex, unit.name, route.params]);
90
+ }, [
91
+ addType,
92
+ navigation,
93
+ subUnits,
94
+ selectedIndex,
95
+ unit?.name,
96
+ unit.user_id,
97
+ route.params,
98
+ ]);
77
99
 
78
100
  const handleSelectIndex = (index) => {
79
101
  if (index !== selectedIndex) {
@@ -86,7 +108,7 @@ const AddCommonSelectSubUnit = ({ route }) => {
86
108
  const addSubUnit = useCallback(() => {
87
109
  navigation.navigate(Routes.AddSubUnitStack, {
88
110
  screen: Routes.AddSubUnit,
89
- params: { unit, ...route.params },
111
+ params: { unit, ...route.params, addType: 'AddHassiDevice' },
90
112
  });
91
113
  }, [navigation, unit, route.params]);
92
114
 
@@ -48,6 +48,9 @@ const AddCommonSelectUnit = ({ route }) => {
48
48
  case 'AddHassioDevice':
49
49
  setTitle(t('text_select_a_unit'));
50
50
  break;
51
+ case 'AddVconnexDevice':
52
+ setTitle(t('text_select_a_unit'));
53
+ break;
51
54
  default:
52
55
  setTitle(t('add_new_sub_unit'));
53
56
  setSubTitle(t('add_new_subunit_select_unit'));
@@ -102,6 +105,15 @@ const AddCommonSelectUnit = ({ route }) => {
102
105
  unit_id: units[selectedIndex].id,
103
106
  });
104
107
  break;
108
+ case 'AddVconnexDevice':
109
+ navigation.navigate(Routes.AddDeviceStack, {
110
+ screen: Routes.AddCommonSelectSubUnit,
111
+ params: {
112
+ unit_id: units[selectedIndex].id,
113
+ addType: 'AddVconnexDevice',
114
+ },
115
+ });
116
+ break;
105
117
  default:
106
118
  break;
107
119
  }
@@ -239,11 +239,6 @@ describe('test DeviceDetail', () => {
239
239
  );
240
240
  expect(sensorDisplayItem.length).toEqual(2);
241
241
 
242
- const itemMediaPlayer = instance.find(
243
- (el) => el.props.testID === TESTID.DEVICE_DETAIL_MEDIA_PLAYER
244
- );
245
- expect(itemMediaPlayer).toBeDefined();
246
-
247
242
  const itemActionGroup = instance.find(
248
243
  (el) => el.props.testID === TESTID.DEVICE_DETAIL_ACTION_GROUP
249
244
  );
@@ -2,11 +2,8 @@ import React, { useCallback } from 'react';
2
2
  import { View } from 'react-native';
3
3
  import ActionGroup from '../../../commons/ActionGroup';
4
4
  import { Card } from '../../../commons/CardShadow';
5
- import MediaPlayer from '../../../commons/MediaPlayer';
6
- import { Device } from '../../../configs';
7
5
  import { TESTID } from '../../../configs/Constants';
8
6
  import { useTranslations } from '../../../hooks/Common/useTranslations';
9
- import { standardizeCameraScreenSize } from '../../../utils/Utils';
10
7
  import { DetailHistoryChart } from './DetailHistoryChart';
11
8
  import { sendRemoteCommand } from '../../../iot/RemoteControl';
12
9
  import CurrentRainSensor from '../../../commons/Device/RainningSensor/CurrentRainSensor';
@@ -20,8 +17,11 @@ import ListQualityIndicator from '../../../commons/Device/WaterQualitySensor/Lis
20
17
  import EmergencyDetail from '../../../commons/Device/Emergency/EmergencyDetail';
21
18
  import EmergencyButton from '../../../commons/Device/Emergency/EmergencyButton';
22
19
  import FooterInfo from '../../../commons/Device/FooterInfo';
20
+ import MediaPlayerDetail from '../../../commons/MediaPlayerDetail';
21
+ import { standardizeCameraScreenSize } from '../../../utils/Utils';
22
+ import { Device } from '../../../configs';
23
23
 
24
- const { standardizeHeight, standardizeWidth } = standardizeCameraScreenSize(
24
+ const { standardizeWidth, standardizeHeight } = standardizeCameraScreenSize(
25
25
  Device.screenWidth - 32
26
26
  );
27
27
 
@@ -51,15 +51,15 @@ export const SensorDisplayItem = ({
51
51
  return (
52
52
  <Card title={t('camera')}>
53
53
  <View style={styles.mediaContainer}>
54
- <MediaPlayer
55
- testID={TESTID.DEVICE_DETAIL_MEDIA_PLAYER}
54
+ <MediaPlayerDetail
56
55
  uri={item.configuration.uri}
57
- style={{ height: standardizeHeight }}
58
- ratioWidth={standardizeWidth - 32}
59
56
  thumbnail={{
60
- uri: item.configuration.preview_uri,
57
+ uri: background,
61
58
  }}
62
- background={{ uri: background }}
59
+ key={`camera-device-${item.configuration.id}`}
60
+ cameraName={item.configuration.name}
61
+ width={standardizeWidth - 32}
62
+ height={standardizeHeight - 16}
63
63
  />
64
64
  </View>
65
65
  </Card>
@@ -79,7 +79,21 @@ const DeviceDetail = ({ route }) => {
79
79
  [sensor]
80
80
  );
81
81
 
82
- useDisconnectedDevice(isConnected, sensorName);
82
+ const isDeviceHasBle = useMemo(() => {
83
+ const action = display.items.filter((item) => item.type === 'action');
84
+ if (action.length === 0) {
85
+ return false;
86
+ }
87
+
88
+ return action.some((item) => {
89
+ const { configuration } = item?.configuration;
90
+ return JSON.stringify(configuration).includes(
91
+ '"command_prefer_over_bluetooth":true'
92
+ );
93
+ });
94
+ }, [display]);
95
+
96
+ useDisconnectedDevice(sensorName, isDeviceHasBle);
83
97
 
84
98
  const netInfo = useNetInfo();
85
99
 
@@ -4,10 +4,11 @@ import { Alert, Linking, Platform } from 'react-native';
4
4
  import { useTranslations } from '../../../hooks/Common/useTranslations';
5
5
  import {
6
6
  enableBluetoothForAndroid,
7
- isBluetoothEnabled,
7
+ useIsBluetoothEnabled,
8
8
  } from '../../../iot/RemoteControl/Bluetooth';
9
+ import { ToastBottomHelper } from '../../../utils/Utils';
9
10
 
10
- export const useDisconnectedDevice = (isConnected, sensorName) => {
11
+ export const useDisconnectedDevice = (sensorName, isDeviceHasBle) => {
11
12
  const t = useTranslations();
12
13
  const openBluetoothIOS = () => {
13
14
  Linking.openURL('App-Prefs:Bluetooth');
@@ -32,32 +33,36 @@ export const useDisconnectedDevice = (isConnected, sensorName) => {
32
33
  onPress: () => enableBluetoothForAndroid(),
33
34
  },
34
35
  ];
35
- const checkNetWorkConnect = useCallback(async () => {
36
- const netState = await NetInfo.fetch();
37
- if (!isConnected || !netState.isConnected) {
38
- const isBtEnabled = await isBluetoothEnabled();
39
- if (isBtEnabled) {
40
- Alert.alert(
41
- '',
42
- t(
43
- 'your_internet_is_disconnected_change_to_control_via_bluetooth_connection',
44
- { name: sensorName }
45
- )
46
- );
47
- } else {
48
- Alert.alert(
49
- '',
50
- t(
51
- 'your_connection_to_the_server_was_disconnected_please_open_the_bluetooth_to_continue'
52
- ),
53
- actions
54
- );
36
+
37
+ const netState = NetInfo.useNetInfo();
38
+ const isBluetoothEnabled = useIsBluetoothEnabled();
39
+
40
+ const checkNetWorkConnect = useCallback(
41
+ async (isHavingInternet, isBtEnabled) => {
42
+ if (!isHavingInternet && isDeviceHasBle) {
43
+ if (isBtEnabled === true) {
44
+ ToastBottomHelper.info(
45
+ t('your_internet_is_disconnected', { name: sensorName }),
46
+ t('change_to_control_via_bluetooth_connection', {
47
+ name: sensorName,
48
+ })
49
+ );
50
+ } else if (isBtEnabled === false) {
51
+ Alert.alert(
52
+ '',
53
+ t(
54
+ 'your_connection_to_the_server_was_disconnected_please_open_the_bluetooth_to_continue'
55
+ ),
56
+ actions
57
+ );
58
+ }
55
59
  }
56
- }
60
+ },
57
61
  // eslint-disable-next-line react-hooks/exhaustive-deps
58
- }, [isConnected]);
62
+ [isDeviceHasBle]
63
+ );
59
64
 
60
65
  useEffect(() => {
61
- checkNetWorkConnect();
62
- }, [checkNetWorkConnect]);
66
+ checkNetWorkConnect(netState.isConnected, isBluetoothEnabled);
67
+ }, [netState.isConnected, isBluetoothEnabled, checkNetWorkConnect]);
63
68
  };
@@ -1,12 +1,7 @@
1
1
  import React, { useCallback } from 'react';
2
2
  import { IconOutline } from '@ant-design/icons-react-native';
3
3
  import { useNavigation } from '@react-navigation/native';
4
- import {
5
- StyleSheet,
6
- TouchableOpacity,
7
- View,
8
- ActivityIndicator,
9
- } from 'react-native';
4
+ import { StyleSheet, TouchableOpacity, View } from 'react-native';
10
5
  import { useTranslations } from '../../hooks/Common/useTranslations';
11
6
 
12
7
  import { Colors } from '../../configs';
@@ -91,9 +86,7 @@ const MemberList = ({ route }) => {
91
86
  loading={isRefresh}
92
87
  onRefresh={onRefresh}
93
88
  >
94
- {loading ? (
95
- <ActivityIndicator />
96
- ) : (
89
+ {!loading && (
97
90
  <SharingMembers
98
91
  dataMember={dataMembers}
99
92
  ownerId={unit.user_id}