@eohjsc/react-native-smart-city 0.3.24 → 0.3.27

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 (33) hide show
  1. package/package.json +1 -1
  2. package/src/commons/ActionGroup/SliderRangeTemplate.js +7 -7
  3. package/src/commons/Dashboard/MyUnit/__test__/MyUnit.test.js +55 -5
  4. package/src/commons/Dashboard/MyUnit/index.js +58 -11
  5. package/src/commons/MenuActionMore/index.js +1 -3
  6. package/src/commons/Popover/index.js +26 -0
  7. package/src/configs/Constants.js +4 -0
  8. package/src/context/actionType.ts +2 -0
  9. package/src/context/reducer.ts +10 -0
  10. package/src/hooks/Common/useGGHomeDeviceConnected.js +9 -2
  11. package/src/hooks/Common/usePopover.js +0 -8
  12. package/src/hooks/IoT/useGGHomeConnection.js +0 -1
  13. package/src/navigations/UnitStack.js +10 -2
  14. package/src/screens/GuestInfo/index.js +11 -4
  15. package/src/screens/GuestInfo/styles/indexStyles.js +7 -0
  16. package/src/screens/ManageAccess/index.js +14 -5
  17. package/src/screens/ManageAccess/styles/ManageAccessStyles.js +9 -0
  18. package/src/screens/PlayBackCamera/Timer.js +3 -0
  19. package/src/screens/PlayBackCamera/__test__/index.test.js +8 -1
  20. package/src/screens/PlayBackCamera/index.js +67 -46
  21. package/src/screens/ScriptDetail/__test__/index.test.js +0 -3
  22. package/src/screens/ScriptDetail/index.js +7 -10
  23. package/src/screens/Unit/Detail.js +16 -10
  24. package/src/screens/Unit/SmartAccount.js +7 -6
  25. package/src/screens/Unit/Summaries.js +8 -1
  26. package/src/screens/Unit/components/Header/index.js +1 -1
  27. package/src/screens/Unit/components/MyUnitDevice/index.js +29 -12
  28. package/src/screens/Unit/components/__test__/AutomateScript.test.js +116 -0
  29. package/src/screens/Unit/components/__test__/Header.test.js +1 -1
  30. package/src/screens/Unit/components/__test__/MyUnitDevice.test.js +2 -2
  31. package/src/screens/Unit/hook/useUnitConnectRemoteDevices.js +6 -5
  32. package/src/screens/Unit/components/MyUnit/index.js +0 -136
  33. package/src/screens/Unit/components/__test__/MyUnit.test.js +0 -35
@@ -13,13 +13,13 @@ import Text from '../../commons/Text';
13
13
  import Timer from './Timer';
14
14
  import { useStatusBarPreview } from '../../hooks/Common/useStatusBar';
15
15
  import MediaPlayerFull from '../../commons/MediaPlayerDetail/MediaPlayerFull';
16
- import { TESTID } from '../../configs/Constants';
16
+ import { DATE_TIME_FORMAT, TESTID } from '../../configs/Constants';
17
17
 
18
- let dateTemp = moment().format('YYYY-MM-DD');
18
+ let dateTemp = moment().format(DATE_TIME_FORMAT.YMD);
19
19
  let isFirstTime = true;
20
20
 
21
21
  const PlayBackCamera = () => {
22
- const now = useMemo(() => moment().format('YYYY-MM-DD'), []);
22
+ const now = useMemo(() => moment().format(DATE_TIME_FORMAT.YMD), []);
23
23
  const hourTemp = useMemo(() => moment().format('HH:mm:ss'), []);
24
24
  const arrHourTemp = useMemo(() => hourTemp.split(':'), [hourTemp]);
25
25
  const t = useTranslations();
@@ -33,7 +33,8 @@ const PlayBackCamera = () => {
33
33
  s: arrHourTemp[2],
34
34
  });
35
35
  const [uri, setUri] = useState(item?.configuration?.uri);
36
- const [paused, setPaused] = useState(true);
36
+ const [mainURI, setMainURI] = useState(uri);
37
+ const [paused, setPaused] = useState(false);
37
38
  const onOpenDateModal = useCallback(() => {
38
39
  setIsShowDate(true);
39
40
  }, []);
@@ -49,15 +50,19 @@ const PlayBackCamera = () => {
49
50
  }, [selected]);
50
51
 
51
52
  const onAddDate = useCallback(() => {
53
+ setPaused(true);
52
54
  if (selected !== now) {
53
- const date = moment(selected).add(1, 'days').format('YYYY-MM-DD');
55
+ const date = moment(selected).add(1, 'days').format(DATE_TIME_FORMAT.YMD);
54
56
  setSelected(date);
55
57
  dateTemp = date;
56
58
  }
57
59
  }, [selected, now]);
58
60
 
59
61
  const onSubtractDate = useCallback(() => {
60
- const date = moment(selected).subtract(1, 'days').format('YYYY-MM-DD');
62
+ setPaused(true);
63
+ const date = moment(selected)
64
+ .subtract(1, 'days')
65
+ .format(DATE_TIME_FORMAT.YMD);
61
66
  setSelected(date);
62
67
  dateTemp = date;
63
68
  }, [selected]);
@@ -72,6 +77,25 @@ const PlayBackCamera = () => {
72
77
  [item?.configuration?.time_zone]
73
78
  );
74
79
 
80
+ const onScrollEndDrag = useCallback(() => {
81
+ setMainURI(uri);
82
+ setPaused(false);
83
+ }, [uri]);
84
+
85
+ const onDayPress = useCallback((day) => {
86
+ setPaused(true);
87
+ setSelected(day.dateString);
88
+ }, []);
89
+
90
+ const onPressArrowLeft = useCallback((subtractMonth) => {
91
+ setPaused(true);
92
+ subtractMonth && subtractMonth();
93
+ }, []);
94
+
95
+ const onPressArrowRight = useCallback((addMonth) => {
96
+ addMonth && addMonth();
97
+ }, []);
98
+
75
99
  const onChangeValue = useCallback(
76
100
  (value, selectedTime) => {
77
101
  if (!isFirstTime) {
@@ -100,10 +124,6 @@ const PlayBackCamera = () => {
100
124
  }T${getHourWithTimeZone(h)}${m}${s}Z`
101
125
  );
102
126
  }
103
- const to = setTimeout(() => {
104
- setPaused(false);
105
- clearTimeout(to);
106
- }, 100);
107
127
  }
108
128
  },
109
129
  [
@@ -115,27 +135,37 @@ const PlayBackCamera = () => {
115
135
  ]
116
136
  );
117
137
 
138
+ const renderArrow = useCallback((direction) => {
139
+ return (
140
+ <Image
141
+ source={Images.arrowLeft}
142
+ style={[direction !== 'left' && styles.arrowRight]}
143
+ />
144
+ );
145
+ }, []);
146
+
118
147
  useEffect(() => {
119
- setPaused(true);
120
- const date = selected.split('-');
121
- const playback = item?.configuration?.playback || '';
122
- if (
123
- selected === now &&
124
- parseInt(moment().format('HH:mm:ss'), 10) <=
125
- parseInt(`${hour.h}:${hour.m}:${hour.s}`, 10)
126
- ) {
127
- setUri(item?.configuration?.uri);
128
- } else {
129
- setUri(
130
- `${playback.split('=')[0]}=${date[0]}${date[1]}${
131
- date[2]
132
- }T${getHourWithTimeZone(hour.h)}${hour.m}${hour.s}Z`
133
- );
148
+ if (!isFirstTime) {
149
+ const date = selected.split('-');
150
+ const playback = item?.configuration?.playback || '';
151
+ if (
152
+ selected === now &&
153
+ parseInt(moment().format('HH:mm:ss'), 10) <=
154
+ parseInt(`${hour.h}:${hour.m}:${hour.s}`, 10)
155
+ ) {
156
+ setMainURI(item?.configuration?.uri);
157
+ } else {
158
+ setMainURI(
159
+ `${playback.split('=')[0]}=${date[0]}${date[1]}${
160
+ date[2]
161
+ }T${getHourWithTimeZone(hour.h)}${hour.m}${hour.s}Z`
162
+ );
163
+ }
164
+ const to = setTimeout(() => {
165
+ setPaused(false);
166
+ clearTimeout(to);
167
+ }, 100);
134
168
  }
135
- const to = setTimeout(() => {
136
- setPaused(false);
137
- clearTimeout(to);
138
- }, 100);
139
169
  // eslint-disable-next-line react-hooks/exhaustive-deps
140
170
  }, [selected, getHourWithTimeZone]);
141
171
 
@@ -152,7 +182,7 @@ const PlayBackCamera = () => {
152
182
  clearTimeout(to);
153
183
  }, 2000);
154
184
  return () => {
155
- dateTemp = moment().format('YYYY-MM-DD');
185
+ dateTemp = moment().format(DATE_TIME_FORMAT.YMD);
156
186
  isFirstTime = true;
157
187
  };
158
188
  }, []);
@@ -161,7 +191,7 @@ const PlayBackCamera = () => {
161
191
  <View style={styles.wrap}>
162
192
  <HeaderCustom title={t('video_detail')} />
163
193
  <MediaPlayerFull
164
- uri={uri}
194
+ uri={mainURI}
165
195
  isPaused={paused}
166
196
  thumbnail={thumbnail}
167
197
  isShowFullScreenIcon
@@ -223,6 +253,7 @@ const PlayBackCamera = () => {
223
253
  indicatorHeight={40}
224
254
  onChangeValue={onChangeValue}
225
255
  selected={selected}
256
+ onScrollEndDrag={onScrollEndDrag}
226
257
  />
227
258
  </View>
228
259
  </View>
@@ -230,13 +261,10 @@ const PlayBackCamera = () => {
230
261
  <ModalCustom isVisible={isShowDate} style={styles.modal}>
231
262
  <View style={styles.wrapDate}>
232
263
  <Calendar
233
- onDayPress={(day) => {
234
- setSelected(day.dateString);
235
- }}
236
- maxDate={moment().format('YYYY-MM-DD')}
237
- onMonthChange={(month) => {}}
238
- onPressArrowLeft={(subtractMonth) => subtractMonth()}
239
- onPressArrowRight={(addMonth) => addMonth()}
264
+ onDayPress={onDayPress}
265
+ maxDate={moment().format(DATE_TIME_FORMAT.YMD)}
266
+ onPressArrowLeft={onPressArrowLeft}
267
+ onPressArrowRight={onPressArrowRight}
240
268
  markedDates={{
241
269
  [selected]: {
242
270
  selected: true,
@@ -246,14 +274,7 @@ const PlayBackCamera = () => {
246
274
  },
247
275
  }}
248
276
  enableSwipeMonths={true}
249
- renderArrow={(direction) => {
250
- if (direction === 'left') {
251
- return <Image source={Images.arrowLeft} />;
252
- }
253
- return (
254
- <Image source={Images.arrowLeft} style={styles.arrowRight} />
255
- );
256
- }}
277
+ renderArrow={renderArrow}
257
278
  headerStyle={styles.headerStyle}
258
279
  />
259
280
  <View style={styles.viewSeparated} />
@@ -103,7 +103,6 @@ describe('Test ScriptDetail', () => {
103
103
 
104
104
  await act(async () => {
105
105
  await menu.props.onItemClick(rename);
106
- await menu.props.hideComplete();
107
106
  });
108
107
  expect(menu.props.isVisible).toBeFalsy();
109
108
  expect(alertAction.props.visible).toBeTruthy();
@@ -130,7 +129,6 @@ describe('Test ScriptDetail', () => {
130
129
 
131
130
  await act(async () => {
132
131
  await menu.props.onItemClick(rename);
133
- await menu.props.hideComplete();
134
132
  });
135
133
  expect(menu.props.isVisible).toBeFalsy();
136
134
  expect(alertAction.props.visible).toBeTruthy();
@@ -154,7 +152,6 @@ describe('Test ScriptDetail', () => {
154
152
 
155
153
  await act(async () => {
156
154
  await menu.props.onItemClick(deleteItem);
157
- await menu.props.hideComplete();
158
155
  });
159
156
  expect(alertAction.props.visible).toBeTruthy();
160
157
  mock.onDelete(API.AUTOMATE.SCRIPT(1)).reply(204);
@@ -43,6 +43,7 @@ import { popAction } from '../../navigations/utils';
43
43
  import { TESTID } from '../../configs/Constants';
44
44
  import useKeyboardAnimated from '../../hooks/Explore/useKeyboardAnimated';
45
45
  import { REPEAT_OPTIONS } from '../SetSchedule/components/RepeatOptionsPopup';
46
+ import { useSCContextSelector } from '../../context';
46
47
 
47
48
  const PreventDoubleTouch = withPreventDoubleClick(TouchableOpacity);
48
49
 
@@ -50,14 +51,8 @@ const ScriptDetail = ({ route }) => {
50
51
  const { navigate, goBack, dispatch } = useNavigation();
51
52
  const { params = {} } = route;
52
53
  const refMenuAction = useRef();
53
- const {
54
- childRef,
55
- showingPopover,
56
- showPopoverWithRef,
57
- hidePopover,
58
- hidingPopoverComplete,
59
- hidePopoverComplete,
60
- } = usePopover();
54
+ const { childRef, showingPopover, showPopoverWithRef, hidePopover } =
55
+ usePopover();
61
56
  const t = useTranslations();
62
57
  const {
63
58
  id,
@@ -84,6 +79,9 @@ const ScriptDetail = ({ route }) => {
84
79
  const [data, setData] = useState([]);
85
80
 
86
81
  const { isStarred, starScript, unstarScript } = useStarredScript(automate);
82
+ const popoverAnimating = useSCContextSelector(
83
+ (state) => state.app.popoverAnimating
84
+ );
87
85
 
88
86
  const [transY] = useKeyboardAnimated(-16);
89
87
  const animatedStyle = Platform.select({
@@ -483,7 +481,6 @@ const ScriptDetail = ({ route }) => {
483
481
  <MenuActionMore
484
482
  isVisible={showingPopover}
485
483
  hideMore={hidePopover}
486
- hideComplete={hidePopoverComplete}
487
484
  listMenuItem={listMenuItem}
488
485
  childRef={childRef}
489
486
  onItemClick={onItemClick}
@@ -491,7 +488,7 @@ const ScriptDetail = ({ route }) => {
491
488
  wrapStyle={styles.wrapStyle}
492
489
  />
493
490
  <AlertAction
494
- visible={stateAlertAction.visible && hidingPopoverComplete}
491
+ visible={stateAlertAction.visible && !popoverAnimating}
495
492
  hideModal={hideAlertAction}
496
493
  title={stateAlertAction.title}
497
494
  message={stateAlertAction.message}
@@ -291,6 +291,21 @@ const UnitDetail = ({ route }) => {
291
291
  navigate(isLavidaSource ? Routes.SmartHomeDashboard : Routes.Dashboard);
292
292
  }, [isLavidaSource, navigate]);
293
293
 
294
+ const renderCamera = useMemo(() => {
295
+ return (
296
+ isFirstOpenCamera &&
297
+ isIOS && (
298
+ <MediaPlayerDetail
299
+ uri={Constants.URL_STREAM_CAMERA_DEMO}
300
+ isPaused={false}
301
+ width={1}
302
+ height={1}
303
+ style={styles.fakeCamera}
304
+ />
305
+ )
306
+ );
307
+ }, [isFirstOpenCamera, isIOS]);
308
+
294
309
  useEffect(() => {
295
310
  watchNotificationData(user, onRefresh);
296
311
  return () => unwatchNotificationData(user);
@@ -319,16 +334,7 @@ const UnitDetail = ({ route }) => {
319
334
  hideRightPlus={!isOwner}
320
335
  onBack={(isSuccessfullyConnected && Dashboard) || (routeName && onBack)}
321
336
  >
322
- {/* NOTE: This is a trick to fix camera not full screen on first open app */}
323
- {isFirstOpenCamera && isIOS && (
324
- <MediaPlayerDetail
325
- uri={Constants.URL_STREAM_CAMERA_DEMO}
326
- isPaused={false}
327
- width={1}
328
- height={1}
329
- style={styles.fakeCamera}
330
- />
331
- )}
337
+ {renderCamera}
332
338
 
333
339
  <View style={styles.container}>
334
340
  <Summaries unit={unit} />
@@ -14,11 +14,12 @@ import Routes from '../../utils/Route';
14
14
  import { useNavigation } from '@react-navigation/native';
15
15
  import { axiosDelete, axiosGet } from '../../utils/Apis/axios';
16
16
  import { SmartAccountItem } from './SmartAccountItem';
17
- import { usePopover, useBoolean } from '../../hooks/Common';
17
+ import { usePopover } from '../../hooks/Common';
18
18
  import { MenuActionMore, AlertAction, FullLoading } from '../../commons';
19
19
  import { useTranslations } from '../../hooks/Common/useTranslations';
20
20
  import { useStateAlertRemove } from '../Unit/hook/useStateAlertRemove';
21
21
  import { ToastBottomHelper } from '../../utils/Utils';
22
+ import { useSCContextSelector } from '../../context';
22
23
 
23
24
  const ListSmartAccount = ({ route }) => {
24
25
  const { unitId } = route?.params || {};
@@ -27,6 +28,9 @@ const ListSmartAccount = ({ route }) => {
27
28
  const smartAccountRef = useRef(null);
28
29
  const { navigate } = useNavigation();
29
30
  const [loadingRemoveItem, setLoadingRemoveItem] = useState(false);
31
+ const popoverAnimating = useSCContextSelector(
32
+ (state) => state.app.popoverAnimating
33
+ );
30
34
 
31
35
  const getAllSmartAccounts = useCallback(async () => {
32
36
  const { success, data: accountData } = await axiosGet(
@@ -39,7 +43,6 @@ const ListSmartAccount = ({ route }) => {
39
43
 
40
44
  const { childRef, showingPopover, showPopoverWithRef, hidePopover } =
41
45
  usePopover();
42
- const [lockShowing, acquireLockShowing, releaseLockShowing] = useBoolean();
43
46
  const { stateAlertRemove, onShowRemoveAlert, hideAlertAction } =
44
47
  useStateAlertRemove();
45
48
 
@@ -62,11 +65,10 @@ const ListSmartAccount = ({ route }) => {
62
65
  return;
63
66
  }
64
67
  if (item.action === 'remove') {
65
- acquireLockShowing();
66
68
  onShowRemoveAlert(smartAccountRef.current.brand)();
67
69
  }
68
70
  },
69
- [acquireLockShowing, onShowRemoveAlert]
71
+ [onShowRemoveAlert]
70
72
  );
71
73
 
72
74
  const deleteSmartAccount = useCallback(async () => {
@@ -124,7 +126,7 @@ const ListSmartAccount = ({ route }) => {
124
126
  })}
125
127
  </View>
126
128
  <AlertAction
127
- visible={stateAlertRemove.visible && !lockShowing}
129
+ visible={stateAlertRemove.visible && !popoverAnimating}
128
130
  hideModal={hideAlertAction}
129
131
  title={stateAlertRemove.title}
130
132
  message={stateAlertRemove.message}
@@ -142,7 +144,6 @@ const ListSmartAccount = ({ route }) => {
142
144
  listMenuItem={listMenuItem}
143
145
  childRef={childRef}
144
146
  onItemClick={onItemClick}
145
- hideComplete={releaseLockShowing}
146
147
  />
147
148
  </WrapHeaderScrollable>
148
149
  {loadingRemoveItem && <FullLoading />}
@@ -6,6 +6,7 @@ import { useIsFocused, useNavigation } from '@react-navigation/native';
6
6
  import { axiosGet } from '../../utils/Apis/axios';
7
7
  import { API } from '../../configs';
8
8
  import { useReceiveNotifications } from '../../hooks';
9
+ import { useSCContextSelector } from '../../context';
9
10
 
10
11
  const Summaries = memo(({ unit }) => {
11
12
  const [unitSummaries, setUnitSummaries] = useState([]);
@@ -14,6 +15,9 @@ const Summaries = memo(({ unit }) => {
14
15
  const isFocused = useIsFocused();
15
16
  const navigation = useNavigation();
16
17
  const appState = useRef(AppState.currentState);
18
+ const popoverAnimating = useSCContextSelector(
19
+ (state) => state.app.popoverAnimating
20
+ );
17
21
 
18
22
  const fetchUnitSummary = useCallback(async () => {
19
23
  if (!unit.id) {
@@ -33,6 +37,9 @@ const Summaries = memo(({ unit }) => {
33
37
 
34
38
  const goToSummary = useCallback(
35
39
  (summary) => {
40
+ if (popoverAnimating) {
41
+ return;
42
+ }
36
43
  navigation.navigate(Routes.UnitSummary, {
37
44
  summaryId: summary.id,
38
45
  unitId: unit.id,
@@ -40,7 +47,7 @@ const Summaries = memo(({ unit }) => {
40
47
  unitData: unit,
41
48
  });
42
49
  },
43
- [navigation, unit]
50
+ [navigation, popoverAnimating, unit]
44
51
  );
45
52
 
46
53
  const continuousFetchSummary = useCallback(async () => {
@@ -1,6 +1,6 @@
1
1
  import React, { useRef, useState } from 'react';
2
2
  import { Dimensions, View, TouchableOpacity, StyleSheet } from 'react-native';
3
- import Popover from 'react-native-popover-view';
3
+ import Popover from '../../../../commons/Popover';
4
4
  import { IconOutline } from '@ant-design/icons-react-native';
5
5
  import { useTranslations } from '../../../../hooks/Common/useTranslations';
6
6
 
@@ -1,15 +1,17 @@
1
1
  import React, { useState, useCallback } from 'react';
2
2
  import { StyleSheet, View, TouchableOpacity } from 'react-native';
3
3
  import { useNavigation } from '@react-navigation/native';
4
+ import { useGGHomeDeviceConnected } from '../../../../hooks/Common';
4
5
 
5
6
  import ItemQuickAction from '../../../../commons/Action/ItemQuickAction';
6
7
  import Text from '../../../../commons/Text';
7
8
  import Routes from '../../../../utils/Route';
8
9
  import { Colors } from '../../../../configs';
9
10
  import FImage from '../../../../commons/FImage';
11
+ import { DEVICE_TYPE } from '../../../../configs/Constants';
10
12
 
11
- const MyUnitDevice = ({ sensor, unit }) => {
12
- const [status, setStatus] = useState(sensor.status);
13
+ const MyUnitDevice = ({ device, unit }) => {
14
+ const [status, setStatus] = useState(device.status);
13
15
  const { navigate } = useNavigation();
14
16
 
15
17
  const goToSensorDisplay = useCallback(() => {
@@ -17,34 +19,49 @@ const MyUnitDevice = ({ sensor, unit }) => {
17
19
  screen: Routes.DeviceDetail,
18
20
  params: {
19
21
  unitData: unit,
20
- sensorData: sensor,
22
+ sensorData: device,
21
23
  },
22
24
  });
23
- }, [navigate, sensor, unit]);
25
+ }, [navigate, device, unit]);
26
+
27
+ const { isConnecting: isGGHomeConnecting } = useGGHomeDeviceConnected(device);
28
+
29
+ const canRenderQuickAction = (() => {
30
+ if (
31
+ !!device &&
32
+ !device?.is_managed_by_backend &&
33
+ device?.device_type === DEVICE_TYPE.GOOGLE_HOME
34
+ ) {
35
+ return !isGGHomeConnecting;
36
+ }
37
+ return true;
38
+ })();
24
39
 
25
40
  return (
26
41
  <View style={styles.item}>
27
42
  <TouchableOpacity style={styles.flex1} onPress={goToSensorDisplay}>
28
43
  <View style={styles.rowCenter}>
29
- <FImage style={styles.image} source={{ uri: sensor?.icon_kit }} />
44
+ <FImage style={styles.image} source={{ uri: device?.icon_kit }} />
30
45
  <View style={styles.marginTop3}>
31
46
  <Text numberOfLines={1} semibold style={styles.nameDevice}>
32
- {sensor.name}
47
+ {device.name}
33
48
  </Text>
34
49
  <View style={styles.roomDevice}>
35
50
  <Text numberOfLines={1} style={styles.roomDevicePart}>
36
- {sensor.station_name}
51
+ {device.station_name}
37
52
  {status ? ` - ${status}` : ''}
38
53
  </Text>
39
54
  </View>
40
55
  </View>
41
56
  </View>
42
57
  </TouchableOpacity>
43
- <ItemQuickAction
44
- sensor={sensor}
45
- wrapperStyle={styles.iconCircle}
46
- setStatus={setStatus}
47
- />
58
+ {canRenderQuickAction && (
59
+ <ItemQuickAction
60
+ sensor={device}
61
+ wrapperStyle={styles.iconCircle}
62
+ setStatus={setStatus}
63
+ />
64
+ )}
48
65
  </View>
49
66
  );
50
67
  };
@@ -0,0 +1,116 @@
1
+ import React from 'react';
2
+ import { TouchableWithoutFeedback, View } from 'react-native';
3
+ import { act, create } from 'react-test-renderer';
4
+ import { AUTOMATE_TYPE } from '../../../../configs/Constants';
5
+ import { SCProvider } from '../../../../context';
6
+ import { mockSCStore } from '../../../../context/mockStore';
7
+ import AutomateScript from '../AutomateScript';
8
+
9
+ const mockOnPress = jest.fn();
10
+
11
+ const wrapComponent = (isSelected, automate = 'automate') => (
12
+ <SCProvider initState={mockSCStore({})}>
13
+ <AutomateScript
14
+ automate={automate}
15
+ onPress={mockOnPress}
16
+ isSelected={isSelected}
17
+ />
18
+ </SCProvider>
19
+ );
20
+
21
+ describe('test AutomateScript screen', () => {
22
+ let tree,
23
+ automate = { type: '' };
24
+ it('Test isSelected=false', async () => {
25
+ await act(async () => {
26
+ tree = await create(wrapComponent(false, automate));
27
+ });
28
+ const instance = tree.root;
29
+ const TouchableWithoutFeedbacks = instance.findAllByType(
30
+ TouchableWithoutFeedback
31
+ );
32
+ await TouchableWithoutFeedbacks[0].props.onPress();
33
+ expect(mockOnPress).toBeCalledWith(automate);
34
+ });
35
+
36
+ it('Test isSelected=true', async () => {
37
+ await act(async () => {
38
+ tree = await create(wrapComponent(true));
39
+ });
40
+ const instance = tree.root;
41
+ const Views = instance.findAllByType(View);
42
+ expect(Views[0].props.style).toEqual([
43
+ {
44
+ padding: 12,
45
+ borderRadius: 10,
46
+ shadowColor: '#303133',
47
+ shadowOffset: {
48
+ height: 2,
49
+ width: 0,
50
+ },
51
+ shadowOpacity: 0.1,
52
+ shadowRadius: 3,
53
+ elevation: 4,
54
+ width: 353,
55
+ height: 204.144578313253,
56
+ backgroundColor: '#FFFFFF',
57
+ justifyContent: 'space-between',
58
+ marginBottom: 8,
59
+ },
60
+ {
61
+ borderColor: '#00979D',
62
+ borderWidth: 2,
63
+ },
64
+ ]);
65
+ });
66
+
67
+ it('Test render VALUE_CHANGE', async () => {
68
+ automate = { ...automate, type: AUTOMATE_TYPE.VALUE_CHANGE };
69
+ await act(async () => {
70
+ tree = await create(wrapComponent(true, automate));
71
+ });
72
+ const instance = tree.root;
73
+ const Views = instance.findAllByType(View);
74
+ expect(Views).toHaveLength(9);
75
+ });
76
+
77
+ it('Test render ONE_TAP', async () => {
78
+ automate = { ...automate, type: AUTOMATE_TYPE.ONE_TAP };
79
+ await act(async () => {
80
+ tree = await create(wrapComponent(true, automate));
81
+ });
82
+ const instance = tree.root;
83
+ const Views = instance.findAllByType(View);
84
+ expect(Views).toHaveLength(9);
85
+ });
86
+
87
+ it('Test render EVENT', async () => {
88
+ automate = { ...automate, type: AUTOMATE_TYPE.EVENT };
89
+ await act(async () => {
90
+ tree = await create(wrapComponent(true, automate));
91
+ });
92
+ const instance = tree.root;
93
+ const Views = instance.findAllByType(View);
94
+ expect(Views).toHaveLength(9);
95
+ });
96
+
97
+ it('Test render SCHEDULE', async () => {
98
+ automate = { ...automate, type: AUTOMATE_TYPE.SCHEDULE };
99
+ await act(async () => {
100
+ tree = await create(wrapComponent(true, automate));
101
+ });
102
+ const instance = tree.root;
103
+ const Views = instance.findAllByType(View);
104
+ expect(Views).toHaveLength(9);
105
+ });
106
+
107
+ it('Test render with iconKit', async () => {
108
+ automate = { ...automate, script: { icon_kit: 'iconKit' } };
109
+ await act(async () => {
110
+ tree = await create(wrapComponent(true, automate));
111
+ });
112
+ const instance = tree.root;
113
+ const Views = instance.findAllByType(View);
114
+ expect(Views).toHaveLength(10);
115
+ });
116
+ });
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import renderer, { act } from 'react-test-renderer';
3
3
  import Modal from 'react-native-modal';
4
- import Popover from 'react-native-popover-view';
4
+ import Popover from '../../../../commons/Popover';
5
5
 
6
6
  import { SCProvider } from '../../../../context';
7
7
  import { mockSCStore } from '../../../../context/mockStore';
@@ -26,7 +26,7 @@ describe('Test MyUnitDevice', () => {
26
26
 
27
27
  beforeEach(() => {
28
28
  props = {
29
- sensor: {
29
+ device: {
30
30
  status: 'Ok',
31
31
  name: 'Test',
32
32
  station_name: '',
@@ -54,7 +54,7 @@ describe('Test MyUnitDevice', () => {
54
54
  });
55
55
 
56
56
  it('Test render without status', async () => {
57
- props.sensor.status = undefined;
57
+ props.device.status = undefined;
58
58
  await act(() => {
59
59
  tree = create(wrapComponent(props));
60
60
  });
@@ -5,7 +5,9 @@ import { useGGHomeConnection } from '../../../hooks/IoT';
5
5
  import { useSCContextSelector } from '../../../context';
6
6
 
7
7
  export const useUnitConnectRemoteDevices = (unit) => {
8
- const { isNetworkConnected } = useSCContextSelector((state) => state.app);
8
+ const isNetworkConnected = useSCContextSelector(
9
+ (state) => state.app.isNetworkConnected
10
+ );
9
11
 
10
12
  const { connectGoogleHome } = useGGHomeConnection();
11
13
 
@@ -21,15 +23,14 @@ export const useUnitConnectRemoteDevices = (unit) => {
21
23
  }, []);
22
24
 
23
25
  useEffect(() => {
24
- if (unit.remote_control_options && unit.remote_control_options.bluetooth) {
26
+ if (unit?.remote_control_options?.bluetooth) {
25
27
  scanBluetoothDevices(unit.remote_control_options.bluetooth);
26
28
  }
27
29
  }, [unit]);
28
30
 
29
31
  useEffect(() => {
30
32
  if (
31
- unit.remote_control_options &&
32
- unit.remote_control_options.googlehome?.length &&
33
+ unit?.remote_control_options?.googlehome?.length &&
33
34
  isNetworkConnected
34
35
  ) {
35
36
  (async () => {
@@ -40,7 +41,7 @@ export const useUnitConnectRemoteDevices = (unit) => {
40
41
  }, [unit, isNetworkConnected]);
41
42
 
42
43
  useEffect(() => {
43
- if (unit.remote_control_options && unit.remote_control_options.lg_thinq) {
44
+ if (unit?.remote_control_options?.lg_thinq) {
44
45
  (async () => {
45
46
  await handleLgThinqConnect(unit.remote_control_options.lg_thinq);
46
47
  })();