@eohjsc/react-native-smart-city 0.3.23 → 0.3.26

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 (44) hide show
  1. package/package.json +1 -1
  2. package/src/commons/ActionGroup/CurtainButtonTemplate.js +9 -17
  3. package/src/commons/ActionGroup/NumberUpDownActionTemplate.js +6 -8
  4. package/src/commons/ActionGroup/OnOffSmartLock/OnOffSmartLock.js +3 -13
  5. package/src/commons/ActionGroup/OnOffTemplate/index.js +4 -23
  6. package/src/commons/ActionGroup/OneBigButtonTemplate.js +2 -3
  7. package/src/commons/ActionGroup/OptionsDropdownActionTemplate.js +2 -6
  8. package/src/commons/ActionGroup/SliderRangeTemplate.js +8 -10
  9. package/src/commons/ActionGroup/StatesGridActionTemplate.js +2 -14
  10. package/src/commons/ActionGroup/ThreeButtonTemplate.js +6 -9
  11. package/src/commons/ActionGroup/TwoButtonTemplate/index.js +6 -18
  12. package/src/commons/ActionGroup/__test__/CurtainButtonTemplate.test.js +3 -15
  13. package/src/commons/ActionGroup/__test__/NumberUpDownTemplate.test.js +1 -2
  14. package/src/commons/ActionGroup/__test__/OnOffSmartLock.test.js +2 -10
  15. package/src/commons/ActionGroup/__test__/OnOffTemplate.test.js +3 -15
  16. package/src/commons/ActionGroup/__test__/OneBigButtonTemplate.test.js +1 -1
  17. package/src/commons/ActionGroup/__test__/OptionsDropdownTemplate.test.js +3 -9
  18. package/src/commons/ActionGroup/__test__/StatesGridActionTemplate.test.js +1 -7
  19. package/src/commons/ActionGroup/__test__/TwoButtonTemplate.test.js +10 -2
  20. package/src/commons/ActionGroup/__test__/index.test.js +7 -17
  21. package/src/commons/ConnectingProcess/index.js +6 -25
  22. package/src/commons/Device/HistoryChart.js +8 -6
  23. package/src/commons/RowItem/styles.js +0 -1
  24. package/src/commons/SubUnit/ShortDetail.js +13 -1
  25. package/src/configs/API.js +1 -1
  26. package/src/configs/Constants.js +4 -0
  27. package/src/context/actionType.ts +1 -0
  28. package/src/context/reducer.ts +9 -0
  29. package/src/hooks/IoT/__test__/useRemoteControl.test.js +9 -11
  30. package/src/hooks/IoT/useRemoteControl.js +2 -3
  31. package/src/iot/RemoteControl/Internet.js +1 -8
  32. package/src/navigations/UnitStack.js +11 -0
  33. package/src/screens/Device/components/SensorDisplayItem.js +2 -2
  34. package/src/screens/Device/detail.js +0 -7
  35. package/src/screens/GuestInfo/index.js +11 -4
  36. package/src/screens/GuestInfo/styles/indexStyles.js +7 -0
  37. package/src/screens/ManageAccess/index.js +14 -5
  38. package/src/screens/ManageAccess/styles/ManageAccessStyles.js +9 -0
  39. package/src/screens/PlayBackCamera/Timer.js +3 -0
  40. package/src/screens/PlayBackCamera/__test__/index.test.js +8 -1
  41. package/src/screens/PlayBackCamera/index.js +86 -49
  42. package/src/screens/Unit/Detail.js +16 -10
  43. package/src/screens/Unit/components/MyUnitDevice/index.js +2 -1
  44. package/src/screens/Unit/components/__test__/AutomateScript.test.js +116 -0
@@ -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,19 +50,52 @@ 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]);
64
69
 
70
+ const getHourWithTimeZone = useCallback(
71
+ // eslint-disable-next-line no-shadow
72
+ (hour) => {
73
+ const hourWithTimezone =
74
+ parseInt(hour, 10) + parseInt(item?.configuration?.time_zone || 0, 10);
75
+ return hourWithTimezone < 10 ? '0' + hourWithTimezone : hourWithTimezone;
76
+ },
77
+ [item?.configuration?.time_zone]
78
+ );
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
+
65
99
  const onChangeValue = useCallback(
66
100
  (value, selectedTime) => {
67
101
  if (!isFirstTime) {
@@ -87,41 +121,53 @@ const PlayBackCamera = () => {
87
121
  setUri(
88
122
  `${playback.split('=')[0]}=${date[0]}${date[1]}${
89
123
  date[2]
90
- }T${h}${m}${s}Z`
124
+ }T${getHourWithTimeZone(h)}${m}${s}Z`
91
125
  );
92
126
  }
93
- const to = setTimeout(() => {
94
- setPaused(false);
95
- clearTimeout(to);
96
- }, 100);
97
127
  }
98
128
  },
99
- [arrHourTemp, item?.configuration, now]
129
+ [
130
+ arrHourTemp,
131
+ getHourWithTimeZone,
132
+ item?.configuration?.playback,
133
+ item?.configuration?.uri,
134
+ now,
135
+ ]
100
136
  );
101
137
 
138
+ const renderArrow = useCallback((direction) => {
139
+ return (
140
+ <Image
141
+ source={Images.arrowLeft}
142
+ style={[direction !== 'left' && styles.arrowRight]}
143
+ />
144
+ );
145
+ }, []);
146
+
102
147
  useEffect(() => {
103
- setPaused(true);
104
- const date = selected.split('-');
105
- const playback = item?.configuration?.playback || '';
106
- if (
107
- selected === now &&
108
- parseInt(moment().format('HH:mm:ss'), 10) <=
109
- parseInt(`${hour.h}:${hour.m}:${hour.s}`, 10)
110
- ) {
111
- setUri(item?.configuration?.uri);
112
- } else {
113
- setUri(
114
- `${playback.split('=')[0]}=${date[0]}${date[1]}${date[2]}T${hour.h}${
115
- hour.m
116
- }${hour.s}Z`
117
- );
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);
118
168
  }
119
- const to = setTimeout(() => {
120
- setPaused(false);
121
- clearTimeout(to);
122
- }, 100);
123
169
  // eslint-disable-next-line react-hooks/exhaustive-deps
124
- }, [selected]);
170
+ }, [selected, getHourWithTimeZone]);
125
171
 
126
172
  useEffect(() => {
127
173
  // eslint-disable-next-line react-hooks/rules-of-hooks
@@ -136,7 +182,7 @@ const PlayBackCamera = () => {
136
182
  clearTimeout(to);
137
183
  }, 2000);
138
184
  return () => {
139
- dateTemp = moment().format('YYYY-MM-DD');
185
+ dateTemp = moment().format(DATE_TIME_FORMAT.YMD);
140
186
  isFirstTime = true;
141
187
  };
142
188
  }, []);
@@ -145,7 +191,7 @@ const PlayBackCamera = () => {
145
191
  <View style={styles.wrap}>
146
192
  <HeaderCustom title={t('video_detail')} />
147
193
  <MediaPlayerFull
148
- uri={uri}
194
+ uri={mainURI}
149
195
  isPaused={paused}
150
196
  thumbnail={thumbnail}
151
197
  isShowFullScreenIcon
@@ -207,6 +253,7 @@ const PlayBackCamera = () => {
207
253
  indicatorHeight={40}
208
254
  onChangeValue={onChangeValue}
209
255
  selected={selected}
256
+ onScrollEndDrag={onScrollEndDrag}
210
257
  />
211
258
  </View>
212
259
  </View>
@@ -214,13 +261,10 @@ const PlayBackCamera = () => {
214
261
  <ModalCustom isVisible={isShowDate} style={styles.modal}>
215
262
  <View style={styles.wrapDate}>
216
263
  <Calendar
217
- onDayPress={(day) => {
218
- setSelected(day.dateString);
219
- }}
220
- maxDate={moment().format('YYYY-MM-DD')}
221
- onMonthChange={(month) => {}}
222
- onPressArrowLeft={(subtractMonth) => subtractMonth()}
223
- onPressArrowRight={(addMonth) => addMonth()}
264
+ onDayPress={onDayPress}
265
+ maxDate={moment().format(DATE_TIME_FORMAT.YMD)}
266
+ onPressArrowLeft={onPressArrowLeft}
267
+ onPressArrowRight={onPressArrowRight}
224
268
  markedDates={{
225
269
  [selected]: {
226
270
  selected: true,
@@ -230,14 +274,7 @@ const PlayBackCamera = () => {
230
274
  },
231
275
  }}
232
276
  enableSwipeMonths={true}
233
- renderArrow={(direction) => {
234
- if (direction === 'left') {
235
- return <Image source={Images.arrowLeft} />;
236
- }
237
- return (
238
- <Image source={Images.arrowLeft} style={styles.arrowRight} />
239
- );
240
- }}
277
+ renderArrow={renderArrow}
241
278
  headerStyle={styles.headerStyle}
242
279
  />
243
280
  <View style={styles.viewSeparated} />
@@ -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} />
@@ -67,7 +67,7 @@ const styles = StyleSheet.create({
67
67
  borderRadius: 16,
68
68
  justifyContent: 'center',
69
69
  alignItems: 'center',
70
- marginLeft: 10,
70
+ marginLeft: 5,
71
71
  },
72
72
  nameDevice: {
73
73
  fontSize: 14,
@@ -81,6 +81,7 @@ const styles = StyleSheet.create({
81
81
  roomDevicePart: {
82
82
  fontSize: 12,
83
83
  lineHeight: 20,
84
+ width: '100%',
84
85
  },
85
86
  rowCenter: {
86
87
  flexDirection: 'row',
@@ -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
+ });