@eohjsc/react-native-smart-city 0.2.94 → 0.2.97

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 (61) hide show
  1. package/package.json +16 -4
  2. package/src/Images/Common/member.svg +4 -0
  3. package/src/Images/Common/owner.svg +3 -0
  4. package/src/commons/ActionGroup/NumberUpDownActionTemplate.js +5 -1
  5. package/src/commons/ActionGroup/OptionsDropdownActionTemplate.js +5 -1
  6. package/src/commons/ActionGroup/__test__/OptionsDropdownTemplate.test.js +2 -2
  7. package/src/commons/Connecting/__test__/Connecting.test.js +23 -0
  8. package/src/commons/Connecting/index.js +67 -0
  9. package/src/commons/Connecting/styles.js +28 -0
  10. package/src/commons/ConnectingProcess/index.js +3 -54
  11. package/src/commons/Device/HistoryChart.js +2 -2
  12. package/src/commons/MenuActionMore/index.js +10 -16
  13. package/src/commons/PreventAccess/index.js +59 -0
  14. package/src/commons/PreventAccess/styles.js +33 -0
  15. package/src/commons/Sharing/MemberList.js +5 -10
  16. package/src/commons/Sharing/RowMember.js +128 -38
  17. package/src/commons/Sharing/__test__/MemberList.test.js +3 -3
  18. package/src/commons/Sharing/__test__/RowMember.test.js +4 -4
  19. package/src/configs/API.js +12 -2
  20. package/src/configs/Constants.js +10 -0
  21. package/src/hooks/Common/useSensorsStatus.js +33 -23
  22. package/src/iot/RemoteControl/GoogleHome.js +24 -11
  23. package/src/iot/RemoteControl/__test__/GoogleHome.test.js +32 -0
  24. package/src/navigations/UnitStack.js +16 -0
  25. package/src/screens/AddNewAction/SelectSensorDevices.js +6 -1
  26. package/src/screens/AddNewAction/__test__/SelectSensorDevices.test.js +34 -92
  27. package/src/screens/AddNewGateway/PlugAndPlay/ConnectWifiWarning.js +12 -3
  28. package/src/screens/AddNewGateway/PlugAndPlay/FirstWarning.js +5 -1
  29. package/src/screens/AddNewGateway/PlugAndPlay/GatewayWifiList.js +9 -1
  30. package/src/screens/Device/detail.js +16 -3
  31. package/src/screens/EditActionsList/Styles/indexStyles.js +1 -0
  32. package/src/screens/EmergencyContacts/EmergencyContactsList.js +1 -1
  33. package/src/screens/EmergencyContacts/EmergencyContactsSelectContacts.js +29 -11
  34. package/src/screens/EmergencyContacts/__test__/EmergencyContactList.test.js +1 -0
  35. package/src/screens/EmergencyContacts/__test__/EmergencyContactsSelectContacts.test.js +56 -0
  36. package/src/screens/EnterPassword/__test__/EnterPassword.test.js +124 -0
  37. package/src/screens/EnterPassword/index.js +84 -0
  38. package/src/screens/EnterPassword/styles.js +36 -0
  39. package/src/screens/Sharing/Components/ItemChangeRole.js +43 -0
  40. package/src/screens/Sharing/Components/SensorItem.js +7 -1
  41. package/src/screens/Sharing/Components/Styles/ItemChangeRoleStyles.js +35 -0
  42. package/src/screens/Sharing/Components/__test__/ItemChangeRole.test.js +37 -0
  43. package/src/screens/Sharing/Components/__test__/SensorItem.test.js +53 -0
  44. package/src/screens/Sharing/InfoMemberUnit.js +274 -0
  45. package/src/screens/Sharing/MemberList.js +50 -53
  46. package/src/screens/Sharing/SelectPermission.js +93 -12
  47. package/src/screens/Sharing/Styles/inforMemberUnitStyles.js +92 -0
  48. package/src/screens/Sharing/__test__/InfoMemberUnit.test.js +121 -0
  49. package/src/screens/Sharing/__test__/MemberList.test.js +9 -24
  50. package/src/screens/Sharing/__test__/SelectPermission.test.js +53 -0
  51. package/src/screens/Sharing/hooks/index.js +76 -32
  52. package/src/screens/Unit/Detail.js +28 -13
  53. package/src/screens/Unit/ManageUnit.js +5 -5
  54. package/src/screens/Unit/ManageUnitStyles.js +1 -0
  55. package/src/screens/Unit/__test__/Detail.test.js +25 -5
  56. package/src/screens/UnitSummary/components/3PPowerConsumption/index.js +1 -1
  57. package/src/screens/UnitSummary/components/PowerConsumption/index.js +1 -1
  58. package/src/utils/I18n/translations/en.json +16 -1
  59. package/src/utils/I18n/translations/vi.json +14 -1
  60. package/src/utils/Route/index.js +2 -0
  61. package/src/utils/Utils.js +21 -0
@@ -1,13 +1,12 @@
1
1
  import React, { memo, useMemo } from 'react';
2
- import { StyleSheet, View } from 'react-native';
3
- import { IconOutline } from '@ant-design/icons-react-native';
2
+ import { StyleSheet, View, TouchableOpacity, Image } from 'react-native';
4
3
  import { useTranslations } from '../../hooks/Common/useTranslations';
5
-
6
4
  import { Colors } from '../../configs';
7
5
  import Text from '../../commons/Text';
8
6
  import { shortEmailName } from '../../utils/Utils';
9
-
10
- import BtnRemoveMember from './BtnRemoveMember';
7
+ import { CircleView } from '../CircleView';
8
+ import { useNavigation } from '@react-navigation/native';
9
+ import Routes from '../../utils/Route';
11
10
 
12
11
  const arrColor = [
13
12
  Colors.GeekBlue3,
@@ -19,46 +18,88 @@ const arrColor = [
19
18
  Colors.Cyan2,
20
19
  ];
21
20
  const RowMember = memo(
22
- ({ member, index, ownerId, currentUserId, onPressRemove }) => {
21
+ ({
22
+ member,
23
+ index,
24
+ ownerId,
25
+ unit,
26
+ currentUserId,
27
+ type,
28
+ leftIcon = true,
29
+ rightComponent = true,
30
+ }) => {
23
31
  const t = useTranslations();
24
- const canRemoveMember = useMemo(
25
- () => ownerId === currentUserId && member.id !== ownerId,
26
- [currentUserId, member.id, ownerId]
27
- );
32
+ const { navigate } = useNavigation();
28
33
  const [role, roleColor] = useMemo(
29
34
  () =>
30
- member.id === ownerId
35
+ member?.id === ownerId
31
36
  ? [t('owner'), Colors.Primary]
32
- : member.id === currentUserId
33
- ? [t('me'), Colors.Gray6]
34
- : ['', ''],
35
- [currentUserId, member.id, ownerId, t]
37
+ : member?.id === currentUserId
38
+ ? [t('me'), Colors.Primary]
39
+ : [t('member'), Colors.Gray6],
40
+ [currentUserId, member?.id, ownerId, t]
36
41
  );
37
- const paddingBottom = role ? 16 : 23;
42
+ const firstWordsInName = useMemo(() => {
43
+ const wordTemp = member?.name || shortEmailName(member?.email) || '';
44
+ return wordTemp?.charAt();
45
+ }, [member?.email, member?.name]);
46
+
38
47
  if (member?.id === ownerId && member?.share_id) {
39
48
  return null;
40
49
  }
50
+ const circleColorTypes = {
51
+ primary: 'primary',
52
+ disable: 'disable',
53
+ noneBG: 'none',
54
+ };
55
+ const circleColor = type
56
+ ? circleColorTypes[type]
57
+ : arrColor[index % arrColor.length];
58
+
59
+ const onPressInfo = () => {
60
+ navigate(Routes.UnitMemberInformation, {
61
+ member,
62
+ ownerId,
63
+ unit,
64
+ });
65
+ };
41
66
  return (
42
67
  <View style={styles.rowContainer}>
43
- <View
44
- style={[
45
- styles.iconContainer,
46
- { backgroundColor: arrColor[index % arrColor.length] },
47
- ]}
48
- >
49
- <IconOutline name={'user'} size={20} color={Colors.White} />
50
- </View>
51
- <View style={[styles.infoContainer, { paddingBottom: paddingBottom }]}>
52
- <Text style={styles.textName}>
53
- {member?.name || shortEmailName(member.email) || ''}
54
- </Text>
55
- {!!role && (
56
- <Text style={[styles.textRole, { color: roleColor }]}>{role}</Text>
57
- )}
58
- {canRemoveMember && (
59
- <BtnRemoveMember onPressRemove={onPressRemove} member={member} />
60
- )}
61
- </View>
68
+ <TouchableOpacity onPress={onPressInfo} disabled={type === 'disable'}>
69
+ <View style={styles.Border}>
70
+ {!!leftIcon && (
71
+ <View style={styles.paddingLeft16}>
72
+ {member?.avatar ? (
73
+ <Image
74
+ source={{ uri: member?.avatar }}
75
+ style={styles.avatar}
76
+ />
77
+ ) : (
78
+ <CircleView size={40} backgroundColor={circleColor} center>
79
+ <Text color={Colors.White}>{firstWordsInName}</Text>
80
+ </CircleView>
81
+ )}
82
+ </View>
83
+ )}
84
+ <View style={styles.columnFlex}>
85
+ <Text style={styles.titleName}>
86
+ {member?.name || shortEmailName(member?.email) || ''}
87
+ </Text>
88
+ {member?.phone_number && (
89
+ <Text style={styles.status}> {member?.phone_number}</Text>
90
+ )}
91
+ </View>
92
+ {!!rightComponent && (
93
+ <View style={styles.endFlex}>
94
+ {!!role && (
95
+ <Text style={[styles.textRole, { color: roleColor }]}>
96
+ {role}
97
+ </Text>
98
+ )}
99
+ </View>
100
+ )}
101
+ </View>
102
+ </TouchableOpacity>
62
103
  </View>
63
104
  );
64
105
  }
@@ -68,9 +109,7 @@ export default RowMember;
68
109
 
69
110
  const styles = StyleSheet.create({
70
111
  rowContainer: {
71
- flexDirection: 'row',
72
- alignItems: 'center',
73
- paddingHorizontal: 16,
112
+ flex: 1,
74
113
  },
75
114
  iconContainer: {
76
115
  alignItems: 'center',
@@ -107,4 +146,55 @@ const styles = StyleSheet.create({
107
146
  textCenter: {
108
147
  alignSelf: 'center',
109
148
  },
149
+ columnFlex: {
150
+ paddingLeft: 16,
151
+ justifyContent: 'center',
152
+ flexDirection: 'column',
153
+ },
154
+ rowFlex: {
155
+ flexDirection: 'row',
156
+ },
157
+ endFlex: {
158
+ flex: 1,
159
+ justifyContent: 'flex-start',
160
+ alignItems: 'flex-end',
161
+ paddingRight: 16,
162
+ },
163
+ Border: {
164
+ display: 'flex',
165
+ width: '100%',
166
+ borderWidth: 0,
167
+ borderColor: Colors.Gray4,
168
+ borderBottomWidth: 1,
169
+ borderStyle: 'solid',
170
+ flexDirection: 'row',
171
+ paddingTop: 16,
172
+ paddingBottom: 16,
173
+ },
174
+ titleName: {
175
+ fontSize: 16,
176
+ lineHeight: 24,
177
+ fontStyle: 'normal',
178
+ fontWeight: '400',
179
+ color: Colors.Gray9,
180
+ },
181
+ status: {
182
+ fontSize: 12,
183
+ lineHeight: 20,
184
+ fontStyle: 'normal',
185
+ fontWeight: '400',
186
+ color: Colors.Gray7,
187
+ },
188
+ container: {
189
+ paddingTop: 0,
190
+ },
191
+ paddingLeft16: {
192
+ paddingLeft: 16,
193
+ },
194
+ avatar: {
195
+ height: 40,
196
+ width: 40,
197
+ borderRadius: 40,
198
+ backgroundColor: Colors.Primary,
199
+ },
110
200
  });
@@ -27,7 +27,7 @@ describe('MemberList', () => {
27
27
  });
28
28
  const instance = tree.root;
29
29
  const textInputs = instance.findAllByType(Text);
30
- expect(textInputs.length).toBe(4);
30
+ expect(textInputs.length).toBe(5);
31
31
  });
32
32
  test('MemberList snapshot id dataMember !== ownerId', () => {
33
33
  const dataMember = [{ id: 1, name: 'CEO' }];
@@ -36,7 +36,7 @@ describe('MemberList', () => {
36
36
  });
37
37
  const instance = tree.root;
38
38
  const textInputs = instance.findAllByType(Text);
39
- expect(textInputs.length).toBe(3);
39
+ expect(textInputs.length).toBe(5);
40
40
  });
41
41
  test('MemberList snapshot id dataMember === currentUserId', () => {
42
42
  const dataMember = [{ id: 1, name: 'CEO' }];
@@ -45,7 +45,7 @@ describe('MemberList', () => {
45
45
  });
46
46
  const instance = tree.root;
47
47
  const textInputs = instance.findAllByType(Text);
48
- expect(textInputs.length).toBe(4);
48
+ expect(textInputs.length).toBe(5);
49
49
  });
50
50
  test('MemberList dataMember null', () => {
51
51
  const dataMember = [];
@@ -26,8 +26,8 @@ describe('RowMember', () => {
26
26
  });
27
27
  const instance = tree.root;
28
28
  const textInputs = instance.findAllByType(Text);
29
- expect(textInputs.length).toBe(4);
30
- expect(textInputs[0].props.children).toEqual('CEO');
29
+ expect(textInputs.length).toBe(5);
30
+ expect(textInputs[1].props.children).toEqual('CEO');
31
31
  });
32
32
  test('RowMember owner dont have name show start of email ', () => {
33
33
  const dataMember = { id: 1, name: '', email: 'abc@gmail.com' };
@@ -36,7 +36,7 @@ describe('RowMember', () => {
36
36
  });
37
37
  const instance = tree.root;
38
38
  const textInputs = instance.findAllByType(Text);
39
- expect(textInputs.length).toBe(4);
40
- expect(textInputs[0].props.children).toEqual('abc');
39
+ expect(textInputs.length).toBe(5);
40
+ expect(textInputs[1].props.children).toEqual('abc');
41
41
  });
42
42
  });
@@ -39,6 +39,8 @@ const API = {
39
39
  SCConfig.apiRoot + `/property_manager/units/${id}/add_gateway/`,
40
40
  SENSORS_STATUS: (id) =>
41
41
  SCConfig.apiRoot + `/property_manager/units/${id}/sensors_status/`,
42
+ CHANGE_OWNER: (id) =>
43
+ SCConfig.apiRoot + `/property_manager/units/${id}/change_owner/`,
42
44
  FAVOURITE_DEVICES: (id) =>
43
45
  SCConfig.apiRoot + `/property_manager/units/${id}/favourite_devices/`,
44
46
  },
@@ -137,9 +139,9 @@ const API = {
137
139
  CHECK_SEND_EMAIL: () =>
138
140
  SCConfig.apiRoot + '/connection_manager/googlehome/check_send_email/',
139
141
  },
140
- POWER_CONSUME: {
142
+ VALUE_CONSUME: {
141
143
  DISPLAY_HISTORY: () =>
142
- SCConfig.apiRoot + '/property_manager/power_consume/display_history/',
144
+ SCConfig.apiRoot + '/property_manager/value_consume/display_history/',
143
145
  },
144
146
  SHARE: {
145
147
  UNITS: () => SCConfig.apiRoot + '/property_manager/sharing/units/',
@@ -150,6 +152,12 @@ const API = {
150
152
  UNITS_MEMBER_DETAIL: (id, shareId) =>
151
153
  SCConfig.apiRoot +
152
154
  `/property_manager/sharing/units/${id}/members/${shareId}/`,
155
+ UNIT_MEMBER_INFO: (unit_id, member_id) =>
156
+ SCConfig.apiRoot +
157
+ `/property_manager/sharing/units/${unit_id}/member/${member_id}/information/`,
158
+ UNIT_MEMBER_SHARE_DEVICE: (unit_id, member_id) =>
159
+ SCConfig.apiRoot +
160
+ `/property_manager/sharing/units/${unit_id}/member/${member_id}/shared_devices/`,
153
161
  SHARE: () => SCConfig.apiRoot + '/property_manager/sharing/share/',
154
162
  },
155
163
  EMERGENCY: {
@@ -157,6 +165,8 @@ const API = {
157
165
  },
158
166
  EMERGENCY_BUTTON: {
159
167
  CREATE_CONTACT: () => SCConfig.apiRoot + '/emergency_button/contacts/',
168
+ CREATE_BATCH: () =>
169
+ SCConfig.apiRoot + '/emergency_button/contacts/create_batch/',
160
170
  CONTACTS: () => SCConfig.apiRoot + '/emergency_button/contacts/',
161
171
  REMOVE_CONTACTS: (id) =>
162
172
  SCConfig.apiRoot + `/emergency_button/contacts/${id}/`,
@@ -217,6 +217,10 @@ export const TESTID = {
217
217
  MY_UNIT_NO_UNIT: 'MY_UNIT_NO_UNIT',
218
218
  ITEM_UNIT: 'ITEM_UNIT',
219
219
 
220
+ //member list
221
+ SHARING_MEMBER: 'SHARING_MEMBER',
222
+ REMOVE_MEMBER: 'REMOVE_MEMBER',
223
+
220
224
  // SmartTiviTemplate
221
225
  SMART_TIVI_TEMPLATE: {
222
226
  BIG_BUTTON: 'BIG_BUTTON',
@@ -309,6 +313,10 @@ export const TESTID = {
309
313
  BUTTON_SELECT_VISA: 'BUTTON_SELECT_VISA',
310
314
  BUTTON_SELECT_MASTER_CARD: 'BUTTON_SELECT_MASTER_CARD',
311
315
 
316
+ //Enter Password
317
+ ENTER_PASSWORD_TEXT_INPUT_PASSWORD: 'ENTER_PASSWORD_TEXT_INPUT_PASSWORD',
318
+ ENTER_PASSWORD_BUTTON_DONE: 'ENTER_PASSWORD_BUTTON_DONE',
319
+
312
320
  // Map Dashboard
313
321
  PARKING_MARKER: 'PARKING_MARKER',
314
322
 
@@ -424,6 +432,8 @@ export const TESTID = {
424
432
  ITEM_QUICK_ACTION_PRESS: 'ITEM_QUICK_ACTION_PRESS',
425
433
  TIME_COUNT_DOWN_TEXT: 'TIME_COUNT_DOWN_TEXT',
426
434
  ACTION_ITEM: 'ACTION_ITEM',
435
+ // Sensor Item
436
+ TEXT_SENSOR_ITEM: 'TEXT_SENSOR_ITEM',
427
437
 
428
438
  // DeviceInfo
429
439
  DEVICE_INFO_BATTERY: 'DEVICE_INFO_BATTERY',
@@ -1,5 +1,6 @@
1
- import { useState, useEffect, useRef } from 'react';
1
+ import { useState, useEffect, useRef, useCallback } from 'react';
2
2
  import { useIsFocused } from '@react-navigation/native';
3
+ import { throttle } from 'lodash';
3
4
  import { axiosGet } from '../../utils/Apis/axios';
4
5
  import { API } from '../../configs';
5
6
 
@@ -9,35 +10,44 @@ const useSensorsStatus = (unit, sensors) => {
9
10
  const [sensorsStatus, setSensorsStatus] = useState([]);
10
11
  const [serverDown, setServerDown] = useState(false);
11
12
 
12
- useEffect(() => {
13
- if (isFocused) {
14
- const getSensorsStatus = async () => {
15
- const params = new URLSearchParams();
16
- if (sensors?.length > 0) {
17
- sensors.forEach((sensor) => {
18
- params.append('sensors', sensor.id);
19
- });
20
- const { success, data, resp_status } = await axiosGet(
21
- API.UNIT.SENSORS_STATUS(unit.id),
22
- {
23
- params: params,
24
- }
25
- );
26
- if (success) {
27
- setSensorsStatus(data);
28
- setServerDown(false);
29
- } else if (resp_status >= 500) {
30
- setServerDown(true);
13
+ // eslint-disable-next-line react-hooks/exhaustive-deps
14
+ const getSensorsStatus = useCallback(
15
+ throttle(async (unit, sensors) => {
16
+ const params = new URLSearchParams();
17
+ if (sensors?.length > 0) {
18
+ sensors.forEach((sensor) => {
19
+ params.append('sensors', sensor.id);
20
+ });
21
+ const { success, data, resp_status } = await axiosGet(
22
+ API.UNIT.SENSORS_STATUS(unit.id),
23
+ {
24
+ params: params,
31
25
  }
26
+ );
27
+ if (success) {
28
+ setSensorsStatus(data);
29
+ setServerDown(false);
30
+ } else if (resp_status > 500) {
31
+ setServerDown(true);
32
32
  }
33
- };
34
- const updateInterval = setInterval(getSensorsStatus, 5000);
33
+ }
34
+ }, 3000),
35
+ []
36
+ );
37
+
38
+ useEffect(() => {
39
+ if (isFocused) {
40
+ getSensorsStatus(unit, sensors);
41
+ const updateInterval = setInterval(
42
+ () => getSensorsStatus(unit, sensors),
43
+ 5000
44
+ );
35
45
  intervalSensorStatus.current = updateInterval;
36
46
  return () => clearInterval(updateInterval);
37
47
  } else {
38
48
  clearInterval(intervalSensorStatus.current);
39
49
  }
40
- }, [isFocused, sensors, unit.id]);
50
+ }, [isFocused, getSensorsStatus, unit, sensors]);
41
51
 
42
52
  const getStatus = (sensor) => {
43
53
  sensorsStatus.find((s) => s.id === sensor.id);
@@ -201,8 +201,22 @@ function getServiceName(message) {
201
201
  return serviceSplit.join('_');
202
202
  }
203
203
 
204
+ async function sendCommandSingleAction(connection, ghAction, data) {
205
+ const { message } = ghAction || {};
206
+ const name = getServiceName(message);
207
+
208
+ if (name && data) {
209
+ message.service_data[name] = data;
210
+ }
211
+
212
+ await connection.sendMessagePromise(message);
213
+ }
214
+
204
215
  export async function sendCommandOverGoogleHome(sensor, action, data) {
205
- if (!action.googlehome_actions || !action.googlehome_actions.length) {
216
+ if (
217
+ !(action.googlehome_actions && action.googlehome_actions.length) &&
218
+ !action.googlehome_action
219
+ ) {
206
220
  return;
207
221
  }
208
222
 
@@ -212,20 +226,19 @@ export async function sendCommandOverGoogleHome(sensor, action, data) {
212
226
  return;
213
227
  }
214
228
 
215
- for (let i = 0; i < action.googlehome_actions.length; i++) {
216
- const ghAction = action.googlehome_actions[i];
217
- const { message } = ghAction;
218
- const name = getServiceName(ghAction.message);
219
-
220
- if (name && data) {
221
- message.service_data[name] = data;
229
+ if (action.googlehome_actions) {
230
+ for (let i = 0; i < action.googlehome_actions.length; i++) {
231
+ await sendCommandSingleAction(
232
+ connection,
233
+ action.googlehome_actions[i],
234
+ data
235
+ );
222
236
  }
223
-
224
- await connection.sendMessagePromise(message);
237
+ } else if (action.googlehome_action) {
238
+ await sendCommandSingleAction(connection, action.googlehome_action, data);
225
239
  }
226
240
 
227
241
  const { success } = await axiosPost(API.SENSOR.ACTIVITY_LOG(), {
228
- sensor_id: sensor.id,
229
242
  action_id: action.id,
230
243
  message: 'Trigger by user action with google home',
231
244
  });
@@ -75,6 +75,9 @@ describe('Remote Control Google Home', () => {
75
75
  message: 'message',
76
76
  },
77
77
  ],
78
+ googlehome_action: {
79
+ message: 'message',
80
+ },
78
81
  };
79
82
 
80
83
  const response = {
@@ -223,6 +226,35 @@ describe('Remote Control Google Home', () => {
223
226
  });
224
227
  });
225
228
 
229
+ it('Send command over google home action googlehome_action one to one', async () => {
230
+ action.googlehome_actions = null;
231
+ action.googlehome_action.message = {
232
+ type: 'call_service',
233
+ domain: 'climate',
234
+ service: 'set_temperature',
235
+ service_data: {
236
+ temperature: 0,
237
+ entity_id: 'climate.dqsmart_0108f6cdde',
238
+ },
239
+ id: 20,
240
+ };
241
+
242
+ axios.post.mockImplementation(async () => {
243
+ return response;
244
+ });
245
+ await googleHomeConnect(options);
246
+ await sendCommandOverGoogleHome(sensor, action, 19);
247
+
248
+ action.googlehome_action.message.service_data.temperature = 19;
249
+ expect(connection.sendMessagePromise).toBeCalledWith(
250
+ action.googlehome_action.message
251
+ );
252
+ expect(axios.post).toHaveBeenCalledWith(API.SENSOR.ACTIVITY_LOG(), {
253
+ action_id: 1,
254
+ message: 'Trigger by user action with google home',
255
+ });
256
+ });
257
+
226
258
  it('Send command over google home that not connected', async () => {
227
259
  await googleHomeConnect(options);
228
260
  await sendCommandOverGoogleHome({ chip_id: 2 }, action);
@@ -49,6 +49,8 @@ import SetUpSensor from '../screens/AddNewAction/SetupSensor';
49
49
  import EditDevice from '../screens/Device/EditDevice/index';
50
50
  import EmergencySetting from '../screens/EmergencySetting';
51
51
  import ConfirmUnitDeletion from '../screens/ConfirmUnitDeletion';
52
+ import InfoMemberUnit from '../screens/Sharing/InfoMemberUnit';
53
+ import EnterPassword from '../screens/EnterPassword';
52
54
  import { HanetCameraStack } from './HanetCameraStack';
53
55
 
54
56
  import { axiosGet } from '../utils/Apis/axios';
@@ -268,6 +270,20 @@ export const UnitStack = memo((props) => {
268
270
  headerShown: false,
269
271
  }}
270
272
  />
273
+ <Stack.Screen
274
+ name={Route.UnitMemberInformation}
275
+ component={InfoMemberUnit}
276
+ options={{
277
+ headerShown: false,
278
+ }}
279
+ />
280
+ <Stack.Screen
281
+ name={Route.EnterPassword}
282
+ component={EnterPassword}
283
+ options={{
284
+ headerShown: false,
285
+ }}
286
+ />
271
287
  <Stack.Screen
272
288
  name={Route.DeviceInfo}
273
289
  component={DeviceInfo}
@@ -37,6 +37,7 @@ const SelectSensorDevices = memo(({ route }) => {
37
37
  const [selectedDevice, setSelectedDevice] = useState();
38
38
  const { navigate, dispatch, goBack } = useNavigation();
39
39
  const isSelectSensor = title === AUTOMATE_SELECT.SELECT_SENSOR;
40
+ const [loading, setLoading] = useState(true);
40
41
 
41
42
  const onSnapToItem = useCallback(
42
43
  (item, index) => {
@@ -83,6 +84,7 @@ const SelectSensorDevices = memo(({ route }) => {
83
84
  }
84
85
  }
85
86
  );
87
+ setLoading(false);
86
88
  }, [automate.sensor_id, isSelectSensor, unit]);
87
89
 
88
90
  useEffect(() => {
@@ -162,6 +164,9 @@ const SelectSensorDevices = memo(({ route }) => {
162
164
  // eslint-disable-next-line react-hooks/exhaustive-deps
163
165
  [route.params]
164
166
  );
167
+ if (loading) {
168
+ return null;
169
+ }
165
170
 
166
171
  return (
167
172
  <View style={styles.wrap}>
@@ -175,7 +180,7 @@ const SelectSensorDevices = memo(({ route }) => {
175
180
  {t(title)}
176
181
  </Text>
177
182
 
178
- {listStation ? (
183
+ {listStation.length ? (
179
184
  <NavBar
180
185
  listStation={listStation}
181
186
  listMenuItem={listMenuItem}