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

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.
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.24",
4
+ "version": "0.3.25",
5
5
  "description": "TODO",
6
6
  "main": "index.js",
7
7
  "files": [
@@ -858,3 +858,7 @@ export const PROBLEM_CODE = {
858
858
  UNKNOWN_ERROR: 'UNKNOWN_ERROR',
859
859
  CANCEL_ERROR: 'CANCEL_ERROR',
860
860
  };
861
+
862
+ export const DATE_TIME_FORMAT = {
863
+ YMD: 'YYYY-MM-DD',
864
+ };
@@ -25,6 +25,7 @@ const Timer = ({
25
25
  normalHeight = 20,
26
26
  value,
27
27
  selected,
28
+ onScrollEndDrag,
28
29
  }) => {
29
30
  const scrollViewRef = useRef();
30
31
  const [scrollX] = useState(new Animated.Value(0));
@@ -113,6 +114,8 @@ const Timer = ({
113
114
  ],
114
115
  { useNativeDriver: true }
115
116
  )}
117
+ onScrollEndDrag={onScrollEndDrag}
118
+ onMomentumScrollEnd={onScrollEndDrag}
116
119
  >
117
120
  {renderTime}
118
121
  </Animated.ScrollView>
@@ -1,6 +1,8 @@
1
1
  import moment from 'moment';
2
2
  import React from 'react';
3
3
  import { Animated, TouchableOpacity } from 'react-native';
4
+ import { Calendar } from 'react-native-calendars';
5
+
4
6
  import { act, create } from 'react-test-renderer';
5
7
  import PlayBackCamera from '..';
6
8
  import { ModalCustom } from '../../../commons/Modal';
@@ -58,6 +60,11 @@ describe('Test PlayBackCamera', () => {
58
60
  await textOpenModal[0].props.onPress();
59
61
  expect(mockSetState).toBeCalledWith(true);
60
62
 
63
+ const Calendars = instance.findAllByType(Calendar);
64
+ expect(Calendars).toHaveLength(1);
65
+ await Calendars[0].props.onDayPress({ dateString: '2022-07-01' });
66
+ expect(mockSetState).toBeCalledWith('2022-07-01');
67
+
61
68
  mockSetState.mockClear();
62
69
  const buttonCancel = instance.findAll(
63
70
  (el) =>
@@ -83,7 +90,7 @@ describe('Test PlayBackCamera', () => {
83
90
  el.type === TouchableOpacity
84
91
  );
85
92
  await buttonAddDate[0].props.onPress();
86
- expect(mockSetState).not.toBeCalled();
93
+ expect(mockSetState).toBeCalled();
87
94
 
88
95
  mockSetState.mockClear();
89
96
  const buttonSubDate = instance.findAll(
@@ -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} />
@@ -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} />
@@ -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
+ });