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

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 (118) hide show
  1. package/index.js +2 -0
  2. package/package.json +1 -1
  3. package/src/Images/Common/device_icon.png +0 -0
  4. package/src/Images/DevMode/gateway.png +0 -0
  5. package/src/Images/DevMode/gateway@2x.png +0 -0
  6. package/src/Images/DevMode/gateway@3x.png +0 -0
  7. package/src/Images/DevMode/menu.png +0 -0
  8. package/src/Images/DevMode/menu@2x.png +0 -0
  9. package/src/Images/DevMode/menu@3x.png +0 -0
  10. package/src/Images/DevMode/search.png +0 -0
  11. package/src/Images/DevMode/search@2x.png +0 -0
  12. package/src/Images/DevMode/search@3x.png +0 -0
  13. package/src/Images/DevMode/smart.png +0 -0
  14. package/src/Images/DevMode/smart@2x.png +0 -0
  15. package/src/Images/DevMode/smart@3x.png +0 -0
  16. package/src/Images/DevMode/template.png +0 -0
  17. package/src/Images/DevMode/template@2x.png +0 -0
  18. package/src/Images/DevMode/template@3x.png +0 -0
  19. package/src/commons/Action/ItemQuickAction.js +1 -0
  20. package/src/commons/ActionGroup/CurtainButtonTemplate.js +1 -2
  21. package/src/commons/ActionGroup/OnOffTemplate/OnOffButtonTemplate.js +2 -0
  22. package/src/commons/ActionGroup/SliderRangeTemplate.js +22 -14
  23. package/src/commons/ActionTemplate/CurtainAction.js +60 -0
  24. package/src/commons/ActionTemplate/CurtainActionStyles.js +11 -0
  25. package/src/commons/ActionTemplate/OnOffSmartLockAction.js +44 -0
  26. package/src/commons/ActionTemplate/OnOffSmartLockActionStyles.js +11 -0
  27. package/src/commons/ActionTemplate/index.js +18 -0
  28. package/src/commons/BottomButtonView/index.js +1 -0
  29. package/src/commons/Button/index.js +2 -0
  30. package/src/commons/CameraDevice/index.js +1 -2
  31. package/src/commons/ConnectingProcess/DeviceItem/DeviceItem.js +20 -12
  32. package/src/commons/ConnectingProcess/DeviceItem/DeviceItemStyles.js +2 -0
  33. package/src/commons/ConnectingProcess/__test__/DeviceItem.test.js +1 -1
  34. package/src/commons/ConnectingProcess/index.js +11 -0
  35. package/src/commons/Dashboard/MyUnit/index.js +1 -1
  36. package/src/commons/DevMode/Label.js +10 -0
  37. package/src/commons/DevMode/Search.js +20 -0
  38. package/src/commons/DevMode/Styles/LabelStyles.js +8 -0
  39. package/src/commons/DevMode/Styles/SearchStyles.js +21 -0
  40. package/src/commons/DevMode/index.js +3 -0
  41. package/src/commons/Device/ItemAddNew/index.js +5 -1
  42. package/src/commons/Device/ItemDevice.js +12 -9
  43. package/src/commons/Form/TextInput.js +4 -0
  44. package/src/commons/HeaderAni/index.js +1 -0
  45. package/src/commons/MediaPlayerDetail/index.js +0 -20
  46. package/src/commons/MenuActionMore/index.js +11 -1
  47. package/src/commons/Modal/index.js +1 -2
  48. package/src/commons/NavBar/index.js +13 -1
  49. package/src/commons/Popover/index.js +7 -6
  50. package/src/commons/SubUnit/OneTap/ItemOneTap.js +4 -1
  51. package/src/commons/SubUnit/ShortDetail.js +1 -0
  52. package/src/commons/SummaryItem/index.js +2 -1
  53. package/src/commons/Tabbar/Styles/indexStyles.js +51 -0
  54. package/src/commons/Tabbar/index.js +110 -0
  55. package/src/commons/Unit/HeaderUnit/index.js +2 -0
  56. package/src/commons/Unit/SharedUnit.js +1 -0
  57. package/src/commons/WrapParallaxScrollView/index.js +16 -2
  58. package/src/configs/Colors.js +4 -0
  59. package/src/configs/Constants.js +16 -0
  60. package/src/configs/Images.js +6 -0
  61. package/src/hooks/Common/useDevicesStatus.js +1 -1
  62. package/src/hooks/IoT/useValueEvaluation.js +10 -19
  63. package/src/iot/RemoteControl/GoogleHome.js +6 -6
  64. package/src/navigations/GatewayStack.js +23 -0
  65. package/src/navigations/Main.js +144 -0
  66. package/src/navigations/SmartStack.js +23 -0
  67. package/src/navigations/TemplateStack.js +23 -0
  68. package/src/navigations/UnitStack.js +5 -8
  69. package/src/screens/AddNewAction/Device/index.js +5 -1
  70. package/src/screens/AddNewAction/SelectAction.js +36 -15
  71. package/src/screens/AddNewAction/__test__/SelectAction.test.js +1 -0
  72. package/src/screens/AddNewAutoSmart/index.js +2 -0
  73. package/src/screens/AddNewGateway/PlugAndPlay/GatewayWifiList.js +13 -1
  74. package/src/screens/AllCamera/__test__/index.test.js +1 -8
  75. package/src/screens/AllCamera/index.js +0 -13
  76. package/src/screens/Device/components/SensorConnectStatusViewHeader.js +10 -11
  77. package/src/screens/Device/detail.js +35 -16
  78. package/src/screens/Device/hooks/__test__/useEmergencyButton.test.js +37 -0
  79. package/src/screens/Device/hooks/useFavoriteDevice.js +4 -2
  80. package/src/screens/Drawer/Drawer.test.js +24 -0
  81. package/src/screens/Drawer/index.js +198 -0
  82. package/src/screens/EmergencyContacts/EmergencyContactsAddNew.js +3 -3
  83. package/src/screens/EmergencyContacts/EmergencyContactsSelectContacts.js +4 -7
  84. package/src/screens/Gateway/__test__/index.test.js +16 -0
  85. package/src/screens/Gateway/index.js +8 -0
  86. package/src/screens/Notification/__test__/NotificationItem.test.js +74 -104
  87. package/src/screens/Notification/components/NotificationItem.js +40 -239
  88. package/src/screens/ScriptDetail/__test__/index.test.js +40 -1
  89. package/src/screens/ScriptDetail/index.js +2 -1
  90. package/src/screens/Sharing/Components/SensorItem.js +4 -1
  91. package/src/screens/Sharing/Components/Styles/SensorItemStyles.js +4 -0
  92. package/src/screens/Sharing/Components/Styles/TitleCheckBoxStyles.js +4 -0
  93. package/src/screens/Sharing/Components/TitleCheckBox.js +17 -8
  94. package/src/screens/Smart/__test__/index.test.js +16 -0
  95. package/src/screens/Smart/index.js +8 -0
  96. package/src/screens/SubUnit/AddSubUnit.js +1 -1
  97. package/src/screens/SubUnit/EditSubUnit.js +4 -1
  98. package/src/screens/Template/Styles/indexStyles.js +51 -0
  99. package/src/screens/Template/__test__/index.test.js +16 -0
  100. package/src/screens/Template/index.js +84 -0
  101. package/src/screens/Unit/Detail.js +16 -28
  102. package/src/screens/Unit/MoreMenu.js +16 -1
  103. package/src/screens/Unit/SelectAddToFavorites.js +11 -1
  104. package/src/screens/Unit/Station/__test__/index.test.js +41 -0
  105. package/src/screens/Unit/Station/index.js +0 -1
  106. package/src/screens/Unit/Summaries.js +6 -1
  107. package/src/screens/Unit/__test__/Detail.test.js +1 -5
  108. package/src/screens/Unit/components/AutomateScript/index.js +5 -2
  109. package/src/utils/Converter/__test__/timer.test.js +99 -0
  110. package/src/utils/Functions/Search.js +17 -0
  111. package/src/utils/Functions/ShortEmail.js +4 -0
  112. package/src/utils/Functions/__test__/Search.test.js +6 -0
  113. package/src/utils/Functions/__test__/ShortEmail.test.js +6 -0
  114. package/src/utils/I18n/translations/en.json +37 -42
  115. package/src/utils/I18n/translations/vi.json +37 -44
  116. package/src/utils/Route/index.js +6 -0
  117. package/src/commons/Modal/ModalFullVideo.js +0 -48
  118. package/src/commons/Modal/Styles/ModalFullVideoStyles.js +0 -26
@@ -0,0 +1,51 @@
1
+ import { StyleSheet } from 'react-native';
2
+ import { Colors, Constants } from '../../../configs';
3
+
4
+ export default StyleSheet.create({
5
+ wrap: {
6
+ flex: 1,
7
+ backgroundColor: Colors.White,
8
+ padding: 16,
9
+ },
10
+ wrapEmpty: {
11
+ flex: 1,
12
+ justifyContent: 'center',
13
+ alignItems: 'center',
14
+ marginTop: -100,
15
+ },
16
+ textEmpty1: {
17
+ fontSize: 20,
18
+ fontWeight: 'bold',
19
+ },
20
+ textEmpty2: {
21
+ fontSize: 14,
22
+ fontWeight: '400',
23
+ color: Colors.Neutral.Neutral5,
24
+ marginTop: 7,
25
+ },
26
+ contentContainerStyle: {
27
+ flex: 1,
28
+ },
29
+ item: {
30
+ width: (Constants.width - 42) / 2,
31
+ height: 128,
32
+ borderRadius: 8,
33
+ borderWidth: 1,
34
+ borderColor: Colors.Neutral.Neutral3,
35
+ marginBottom: 16,
36
+ justifyContent: 'space-around',
37
+ alignItems: 'center',
38
+ },
39
+ oddItem: {
40
+ marginRight: 10,
41
+ },
42
+ nameItem: {
43
+ fontSize: 14,
44
+ fontWeight: 'bold',
45
+ },
46
+ countItem: {
47
+ fontSize: 12,
48
+ fontWeight: 400,
49
+ color: Colors.Neutral.Neutral5,
50
+ },
51
+ });
@@ -0,0 +1,16 @@
1
+ import React from 'react';
2
+ import { FlatList } from 'react-native';
3
+ import { act, create } from 'react-test-renderer';
4
+ import Template from '..';
5
+
6
+ describe('Test Template screen', () => {
7
+ let tree;
8
+ it('Test render', async () => {
9
+ await act(async () => {
10
+ tree = await create(<Template />);
11
+ });
12
+ const instance = tree.root;
13
+ const FlatLists = instance.findAllByType(FlatList);
14
+ expect(FlatLists).toHaveLength(1);
15
+ });
16
+ });
@@ -0,0 +1,84 @@
1
+ import React, { useCallback, useMemo, useState } from 'react';
2
+ import {
3
+ View,
4
+ TouchableWithoutFeedback,
5
+ Keyboard,
6
+ FlatList,
7
+ } from 'react-native';
8
+ import { Label } from '../../commons/DevMode';
9
+ import Search from '../../commons/DevMode/Search';
10
+ import Text from '../../commons/Text';
11
+ import t from '../../hooks/Common/useTranslations';
12
+ import { convertToSlug } from '../../utils/Functions/Search';
13
+ import styles from './Styles/indexStyles';
14
+
15
+ const arrTemplates = [
16
+ {
17
+ id: 1,
18
+ name: 'Template name 1',
19
+ count: 2,
20
+ },
21
+ {
22
+ id: 2,
23
+ name: 'Template name 2',
24
+ },
25
+ {
26
+ id: 3,
27
+ name: 'Template name 3',
28
+ },
29
+ ];
30
+
31
+ const Template = () => {
32
+ const [data, setData] = useState(arrTemplates);
33
+
34
+ const onSearch = useCallback((value) => {
35
+ if (value === '') {
36
+ setData(arrTemplates);
37
+ return;
38
+ }
39
+ const dataTemp = arrTemplates.filter((item) =>
40
+ convertToSlug(item?.name).includes(convertToSlug(value))
41
+ );
42
+ setData(dataTemp);
43
+ }, []);
44
+
45
+ const renderListEmptyComponent = useMemo(() => {
46
+ return (
47
+ <View style={styles.wrapEmpty}>
48
+ <Text style={styles.textEmpty1}>{t('no_template_yet')}</Text>
49
+ <Text style={styles.textEmpty2}>{t('add_your_template')}</Text>
50
+ </View>
51
+ );
52
+ }, []);
53
+
54
+ const renderItem = ({ item, index }) => {
55
+ return (
56
+ <View style={[styles.item, index % 2 === 0 && styles.oddItem]}>
57
+ <Text style={styles.nameItem}>{item?.name}</Text>
58
+ <Text style={styles.countItem}>{`${
59
+ item?.count > 0 ? item?.count : t('no')
60
+ } ${t('gateways').toLowerCase()}`}</Text>
61
+ </View>
62
+ );
63
+ };
64
+
65
+ return (
66
+ <TouchableWithoutFeedback onPress={Keyboard.dismiss}>
67
+ <View style={styles.wrap}>
68
+ <Label name={t('template')} />
69
+ <Search onSearch={onSearch} />
70
+ <FlatList
71
+ contentContainerStyle={styles.contentContainerStyle}
72
+ keyExtractor={(item) => item?.id}
73
+ data={data}
74
+ renderItem={renderItem}
75
+ extraData={data}
76
+ ListEmptyComponent={renderListEmptyComponent}
77
+ numColumns={2}
78
+ />
79
+ </View>
80
+ </TouchableWithoutFeedback>
81
+ );
82
+ };
83
+
84
+ export default Template;
@@ -33,7 +33,6 @@ import WrapParallaxScrollView from '../../commons/WrapParallaxScrollView';
33
33
  import { SCContext, useSCContextSelector } from '../../context';
34
34
  import { Action } from '../../context/actionType';
35
35
  import CameraDevice from '../../commons/CameraDevice';
36
- import { ModalFullVideo } from '../../commons/Modal';
37
36
  import { useNavigation } from '@react-navigation/native';
38
37
  import Routes from '../../utils/Route';
39
38
  import SubUnitAutomate from '../../commons/SubUnit/OneTap';
@@ -63,6 +62,7 @@ const UnitDetail = ({ route }) => {
63
62
  routeName,
64
63
  stationId,
65
64
  isAddSubUnit,
65
+ isEditSubUnit,
66
66
  isSuccessfullyConnected,
67
67
  } = route.params;
68
68
 
@@ -92,8 +92,6 @@ const UnitDetail = ({ route }) => {
92
92
  const [showAdd, setShowAdd, setHideAdd] = useBoolean();
93
93
  const [showPreventAccess, setShowPreventAccess, setHidePreventAccess] =
94
94
  useBoolean(false);
95
- const [isFullScreen, setIsFullScreen] = useState(false);
96
- const [dataFullScreen, setDataFullScreen] = useState();
97
95
  const appState = useRef(AppState.currentState);
98
96
 
99
97
  const { childRef, showingPopover, showPopoverWithRef, hidePopover } =
@@ -105,24 +103,17 @@ const UnitDetail = ({ route }) => {
105
103
  listAutomate
106
104
  );
107
105
 
108
- const handleFullScreen = (data) => {
109
- setIsFullScreen(!isFullScreen);
110
- setDataFullScreen(data);
111
- };
112
-
113
- const onClose = useCallback(() => {
114
- setIsFullScreen(false);
115
- }, []);
116
-
117
106
  const prepareData = useCallback(
118
107
  (rawUnitData) => {
119
108
  rawUnitData.stations.unshift({
120
109
  isOneTap: true,
121
110
  name: t('smart'),
111
+ id: 'smart',
122
112
  });
123
113
  rawUnitData.stations.unshift({
124
114
  isFavorites: true,
125
115
  name: t('favorites'),
116
+ id: 'favorites',
126
117
  });
127
118
  },
128
119
  [t]
@@ -217,8 +208,9 @@ const UnitDetail = ({ route }) => {
217
208
  }, [unit, indexStation]);
218
209
 
219
210
  useEffect(() => {
211
+ isEditSubUnit && setIndexStation(0);
220
212
  isOneTap && setIndexStation(1);
221
- }, [isOneTap]);
213
+ }, [isEditSubUnit, isOneTap]);
222
214
 
223
215
  useEffect(() => {
224
216
  if (listMenuItem.length && isAddSubUnit) {
@@ -227,7 +219,7 @@ const UnitDetail = ({ route }) => {
227
219
  }, [listMenuItem.length, isAddSubUnit]);
228
220
 
229
221
  useEffect(() => {
230
- if (listMenuItem.length && stationId) {
222
+ if (!isEditSubUnit && listMenuItem.length && stationId) {
231
223
  const getStationCurrent = listMenuItem.filter(
232
224
  (item) => item?.station.id === stationId
233
225
  );
@@ -262,13 +254,7 @@ const UnitDetail = ({ route }) => {
262
254
  );
263
255
  }
264
256
  if (station?.camera_devices) {
265
- return (
266
- <CameraDevice
267
- station={station}
268
- handleFullScreen={handleFullScreen}
269
- goToPlayBack={goToPlayBack}
270
- />
271
- );
257
+ return <CameraDevice station={station} goToPlayBack={goToPlayBack} />;
272
258
  } else if (station?.isOneTap) {
273
259
  return (
274
260
  <SubUnitAutomate
@@ -318,7 +304,8 @@ const UnitDetail = ({ route }) => {
318
304
  clearTimeout(to);
319
305
  }, 3000);
320
306
  }
321
- }, [isFirstOpenCamera, isIOS, setAction]);
307
+ // eslint-disable-next-line react-hooks/exhaustive-deps
308
+ }, [isFirstOpenCamera, isIOS]);
322
309
 
323
310
  return (
324
311
  <WrapParallaxScrollView
@@ -333,6 +320,8 @@ const UnitDetail = ({ route }) => {
333
320
  onMore={showPopoverWithRef}
334
321
  hideRightPlus={!isOwner}
335
322
  onBack={(isSuccessfullyConnected && Dashboard) || (routeName && onBack)}
323
+ accessibilityLabel={TESTID.UNIT_DETAIL_PARALLAX_SCROLLVIEW}
324
+ idButtonMore={TESTID.UNIT_DETAIL_PARALLAX_BUTTON_MORE}
336
325
  >
337
326
  {renderCamera}
338
327
 
@@ -344,6 +333,9 @@ const UnitDetail = ({ route }) => {
344
333
  listMenuItem={listMenuItem}
345
334
  onSnapToItem={onSnapToItem}
346
335
  indexStation={indexStation}
336
+ idLabelScrollView={TESTID.NAV_LIST}
337
+ idLabelItem={TESTID.SUB_UNIT_NAME}
338
+ idLabelIconBars={TESTID.NAVBAR_ICON_BARS}
347
339
  />
348
340
  {renderDetailSubUnit()}
349
341
  {!!unit.can_add && unit.stations.length === 0 && (
@@ -364,12 +356,8 @@ const UnitDetail = ({ route }) => {
364
356
  isOwner={isOwner}
365
357
  childRef={childRef}
366
358
  showingPopover={showingPopover}
367
- />
368
- <ModalFullVideo
369
- isVisible={isFullScreen}
370
- data={dataFullScreen}
371
- modalStyles={styles.modal}
372
- onClose={onClose}
359
+ idLabelPopover={TESTID.UNIT_DETAIL_POPUP_MORE}
360
+ idLabelItem={TESTID.UNIT_DETAIL_POPUP_MORE_ITEM}
373
361
  />
374
362
  <PreventAccess
375
363
  visible={showPreventAccess}
@@ -5,7 +5,16 @@ import { useNavigation } from '@react-navigation/native';
5
5
  import { MenuActionMore } from '../../commons';
6
6
 
7
7
  const MoreMenu = memo(
8
- ({ unit, isOwner, hidePopover, childRef, showingPopover }) => {
8
+ ({
9
+ unit,
10
+ isOwner,
11
+ hidePopover,
12
+ childRef,
13
+ showingPopover,
14
+ idLabelPopover,
15
+ idLabelScrollView,
16
+ idLabelItem,
17
+ }) => {
9
18
  const t = useTranslations();
10
19
  const navigation = useNavigation();
11
20
 
@@ -19,16 +28,19 @@ const MoreMenu = memo(
19
28
 
20
29
  const listMenuItem = useMemo(() => {
21
30
  const RouteManageUnit = {
31
+ id: 1,
22
32
  route: Routes.ManageUnit,
23
33
  text: t('manage_unit'),
24
34
  data: { unitId: unit.id, unit },
25
35
  };
26
36
  const RouteUnitMemberList = {
37
+ id: 2,
27
38
  route: Routes.UnitMemberList,
28
39
  text: t('members'),
29
40
  data: { unitId: unit.id, unit },
30
41
  };
31
42
  const ListSmartAccount = {
43
+ id: 3,
32
44
  route: Routes.ListSmartAccount,
33
45
  text: t('smart_account'),
34
46
  data: { unitId: unit.id, unit },
@@ -45,6 +57,9 @@ const MoreMenu = memo(
45
57
  listMenuItem={listMenuItem}
46
58
  childRef={childRef}
47
59
  onItemClick={onItemClick}
60
+ idLabelPopover={idLabelPopover}
61
+ idLabelScrollView={idLabelScrollView}
62
+ idLabelItem={idLabelItem}
48
63
  />
49
64
  );
50
65
  }
@@ -21,6 +21,7 @@ import { SCContext } from '../../context';
21
21
  import { Action } from '../../context/actionType';
22
22
  import { axiosGet, axiosPost } from '../../utils/Apis/axios';
23
23
  import { API, Colors } from '../../configs';
24
+ import { TESTID } from '../../configs/Constants';
24
25
  import styles from './SelectAddToFavoritesStyles';
25
26
 
26
27
  const SelectAddToFavorites = memo(({ route }) => {
@@ -136,7 +137,12 @@ const SelectAddToFavorites = memo(({ route }) => {
136
137
 
137
138
  const rightComponent = useMemo(
138
139
  () => (
139
- <TouchableOpacity style={styles.buttonClose} onPress={goBack}>
140
+ <TouchableOpacity
141
+ testID={TESTID.ICON_BACK}
142
+ accessibilityLabel={TESTID.ICON_BACK}
143
+ style={styles.buttonClose}
144
+ onPress={goBack}
145
+ >
140
146
  <Icon name={'close'} size={24} color={Colors.Black} />
141
147
  </TouchableOpacity>
142
148
  ),
@@ -151,6 +157,8 @@ const SelectAddToFavorites = memo(({ route }) => {
151
157
  style={styles.wrap}
152
158
  contentContainerStyle={styles.contentContainerStyle}
153
159
  scrollIndicatorInsets={{ right: 1 }}
160
+ testID={TESTID.LIST_FAVORITES}
161
+ idLabelScrollView={TESTID.LIST_FAVORITES}
154
162
  >
155
163
  <Text bold type="H2" style={styles.title}>
156
164
  {t('select_device')}
@@ -162,6 +170,8 @@ const SelectAddToFavorites = memo(({ route }) => {
162
170
  listMenuItem={listMenuItem}
163
171
  onSnapToItem={onSnapToItem}
164
172
  indexStation={indexStation}
173
+ idLabelItem={TESTID.SUB_UNIT_FAVORITES}
174
+ idLabelIconBars={TESTID.NAVBAR_ICON_BARS_ADD_FAVORITES}
165
175
  style={styles.navbar}
166
176
  />
167
177
  )}
@@ -0,0 +1,41 @@
1
+ import React from 'react';
2
+ import { FlatList } from 'react-native';
3
+ import { act, create } from 'react-test-renderer';
4
+ import Station from '..';
5
+ import { SCProvider } from '../../../../context';
6
+ import { mockSCStore } from '../../../../context/mockStore';
7
+
8
+ const mockOnSnapToItem = jest.fn();
9
+
10
+ const wrapComponent = (route) => (
11
+ <SCProvider initState={mockSCStore({})}>
12
+ <Station
13
+ listStation={[{ id: 1, station: { id: 1 }, text: 'station1' }]}
14
+ onSnapToItem={mockOnSnapToItem}
15
+ indexStation={1}
16
+ />
17
+ </SCProvider>
18
+ );
19
+
20
+ describe('Test Station', async () => {
21
+ let tree;
22
+ let route = {
23
+ unitId: 1,
24
+ unitData: {
25
+ id: 1,
26
+ },
27
+ isOneTap: false,
28
+ routeName: 'Test',
29
+ stationId: 1,
30
+ isAddSubUnit: false,
31
+ isSuccessfullyConnected: false,
32
+ };
33
+ it('Test render', async () => {
34
+ await act(async () => {
35
+ tree = create(wrapComponent(route));
36
+ });
37
+ const instance = tree.root;
38
+ const FlatLists = instance.findAllByType(FlatList);
39
+ expect(FlatLists).toHaveLength(1);
40
+ });
41
+ });
@@ -73,7 +73,6 @@ const Station = ({ listStation = [], onSnapToItem, indexStation }) => {
73
73
  renderItem={renderItem}
74
74
  showsHorizontalScrollIndicator={false}
75
75
  scrollIndicatorInsets={{ right: 1 }}
76
- testID={TESTID.NAV_LIST}
77
76
  />
78
77
  </View>
79
78
  );
@@ -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 { TESTID } from '../../configs/Constants';
9
10
  import { useSCContextSelector } from '../../context';
10
11
 
11
12
  const Summaries = memo(({ unit }) => {
@@ -108,7 +109,11 @@ const Summaries = memo(({ unit }) => {
108
109
  return (
109
110
  <>
110
111
  {!unitSummaries || !unitSummaries.length ? null : (
111
- <ScrollView horizontal={true} scrollIndicatorInsets={{ right: 1 }}>
112
+ <ScrollView
113
+ horizontal={true}
114
+ scrollIndicatorInsets={{ right: 1 }}
115
+ accessibilityLabel={TESTID.UNIT_DETAIL_UNIT_SUMMARY_VIEW}
116
+ >
112
117
  {unitSummaries.map((item, index) => (
113
118
  <SummaryItem key={index} item={item} goToSummary={goToSummary} />
114
119
  ))}
@@ -12,7 +12,6 @@ import { TESTID } from '../../../configs/Constants';
12
12
  import { SCProvider } from '../../../context';
13
13
  import { mockSCStore } from '../../../context/mockStore';
14
14
  import CameraDevice from '../../../commons/CameraDevice';
15
- import { ModalFullVideo } from '../../../commons/Modal';
16
15
  import SubUnitFavorites from '../../../commons/SubUnit/Favorites';
17
16
  import api from '../../../utils/Apis/axios';
18
17
  import PreventAccess from '../../../commons/PreventAccess';
@@ -352,11 +351,7 @@ describe('Test UnitDetail', () => {
352
351
  el.props.testID === TESTID.SUB_UNIT_FULL_CAMERA &&
353
352
  el.type === TouchableOpacity
354
353
  );
355
-
356
354
  expect(fullCamera).toHaveLength(0);
357
- const fullView = instance.findAllByType(ModalFullVideo);
358
- expect(fullView).toHaveLength(1);
359
- expect(fullView[0].props.isVisible).toEqual(false);
360
355
  });
361
356
 
362
357
  test('onPress subunit camera devices', async () => {
@@ -438,6 +433,7 @@ describe('Test UnitDetail', () => {
438
433
  };
439
434
  route.params.isAddSubUnit = true;
440
435
  route.params.unitData = unitData;
436
+ route.params.isSuccessfullyConnected = false;
441
437
  await act(async () => {
442
438
  tree = await renderer.create(wrapComponent(route, account));
443
439
  });
@@ -9,7 +9,7 @@ import ValueChange from '../../../../../assets/images/ValueChange.svg';
9
9
  import Schedule from '../../../../../assets/images/Schedule.svg';
10
10
  import Event from '../../../../../assets/images/Event.svg';
11
11
  import styles from './styles';
12
- import { AUTOMATE_TYPE } from '../../../../configs/Constants';
12
+ import { AUTOMATE_TYPE, TESTID } from '../../../../configs/Constants';
13
13
  import { Colors } from '../../../../configs';
14
14
 
15
15
  const AutomateScript = ({ automate, onPress, isSelected }) => {
@@ -36,7 +36,10 @@ const AutomateScript = ({ automate, onPress, isSelected }) => {
36
36
  };
37
37
 
38
38
  return (
39
- <TouchableWithoutFeedback onPress={_onPress}>
39
+ <TouchableWithoutFeedback
40
+ onPress={_onPress}
41
+ accessibilityLabel={`${TESTID.TOUCHABLE_ACTION_ADD_ITEM_AUTOMATE_FAVORITE}-${automate.id}`}
42
+ >
40
43
  <View style={[styles.container, isSelected && styles.active]}>
41
44
  <View style={styles.boxIcon}>{displayIcon()}</View>
42
45
  <View>
@@ -0,0 +1,99 @@
1
+ import { getDateData, getTitleFromTime, timeDifference } from '../time';
2
+
3
+ describe('Test timer', () => {
4
+ let result;
5
+ it('Test timeDifference when elapsed < msPerMinute and symbol=false', async () => {
6
+ result = await timeDifference(
7
+ new Date('2022-08-01T03:24:01'),
8
+ new Date('2022-08-01T03:24:00')
9
+ );
10
+ expect(result).toBe('1 seconds ago');
11
+ });
12
+
13
+ it('Test timeDifference when elapsed < msPerMinute and symbol=true', async () => {
14
+ result = await timeDifference(
15
+ new Date('2022-08-01T03:24:01'),
16
+ new Date('2022-08-01T03:24:00'),
17
+ true
18
+ );
19
+ expect(result).toBe('1 secs ago');
20
+ });
21
+
22
+ it('Test timeDifference when elapsed < msPerHour and symbol=false', async () => {
23
+ result = await timeDifference(
24
+ new Date('2022-08-01T03:24:01'),
25
+ new Date('2022-08-01T03:00:00')
26
+ );
27
+ expect(result).toBe('24 minutes ago');
28
+ });
29
+
30
+ it('Test timeDifference when elapsed < msPerHour and symbol=true', async () => {
31
+ result = await timeDifference(
32
+ new Date('2022-08-01T03:24:01'),
33
+ new Date('2022-08-01T03:00:00'),
34
+ true
35
+ );
36
+ expect(result).toBe('24 mins ago');
37
+ });
38
+
39
+ it('Test timeDifference when elapsed < msPerDay and symbol=false', async () => {
40
+ result = await timeDifference(
41
+ new Date('2022-08-01T03:24:01'),
42
+ new Date('2022-08-01T02:00:00')
43
+ );
44
+ expect(result).toBe('1 hours ago');
45
+ });
46
+
47
+ it('Test timeDifference when elapsed < msPerMonthe', async () => {
48
+ result = await timeDifference(
49
+ new Date('2022-08-01T03:24:01'),
50
+ new Date('2022-07-31T02:00:00')
51
+ );
52
+ expect(result).toBe('1 days ago');
53
+ });
54
+
55
+ it('Test timeDifference when elapsed < msPerYear', async () => {
56
+ result = await timeDifference(
57
+ new Date('2022-08-01T03:24:01'),
58
+ new Date('2022-05-31T02:00:00')
59
+ );
60
+ expect(result).toBe('2 months ago');
61
+ });
62
+
63
+ it('Test timeDifference when elapsed > msPerYear', async () => {
64
+ result = await timeDifference(
65
+ new Date('2022-08-01T03:24:01'),
66
+ new Date('2021-05-31T02:00:00')
67
+ );
68
+ expect(result).toBe('1 years ago');
69
+ });
70
+
71
+ it('Test getTitleFromTime when time = current', async () => {
72
+ result = await getTitleFromTime(new Date(), new Date());
73
+ expect(result).toBe('Today');
74
+ });
75
+
76
+ it('Test getTitleFromTime when time > current', async () => {
77
+ result = await getTitleFromTime(
78
+ new Date('2022-05-31T02:00:00'),
79
+ new Date('2022-05-30T02:00:00')
80
+ );
81
+ expect(result).toBe('31/05/2022');
82
+ });
83
+
84
+ it('Test getTitleFromTime when time < current', async () => {
85
+ result = await getTitleFromTime(
86
+ new Date('2022-05-29T02:00:00'),
87
+ new Date('2022-05-30T02:00:00')
88
+ );
89
+ expect(result).toBe('Yesterday');
90
+ });
91
+
92
+ it('Test getDateData', async () => {
93
+ result = await getDateData(
94
+ new Date('2022-05-30T02:00:00'),
95
+ new Date('2022-06-30T02:00:00')
96
+ );
97
+ expect(result).toEqual([[], 0]);
98
+ });
99
+ });
@@ -0,0 +1,17 @@
1
+ export const formatVietnamese = (str) => {
2
+ str = str.toLowerCase();
3
+ str = str.replace(/à|á|ạ|ả|ã|â|ầ|ấ|ậ|ẩ|ẫ|ă|ằ|ắ|ặ|ẳ|ẵ/g, 'a');
4
+ str = str.replace(/è|é|ẹ|ẻ|ẽ|ê|ề|ế|ệ|ể|ễ/g, 'e');
5
+ str = str.replace(/ì|í|ị|ỉ|ĩ/g, 'i');
6
+ str = str.replace(/ò|ó|ọ|ỏ|õ|ô|ồ|ố|ộ|ổ|ỗ|ơ|ờ|ớ|ợ|ở|ỡ/g, 'o');
7
+ str = str.replace(/ù|ú|ụ|ủ|ũ|ư|ừ|ứ|ự|ử|ữ/g, 'u');
8
+ str = str.replace(/ỳ|ý|ỵ|ỷ|ỹ/g, 'y');
9
+ str = str.replace(/đ/g, 'd');
10
+ return str;
11
+ };
12
+
13
+ export const convertToSlug = (text) => {
14
+ text = text.substring(0, Math.max(80, text.length));
15
+ text = formatVietnamese(text);
16
+ return text.toLowerCase().replace(/[^\w ]+/g, '');
17
+ };
@@ -0,0 +1,4 @@
1
+ export const shortEmailName = (email) => {
2
+ const regex = '([^@]+)';
3
+ return email?.match(regex)[0] || '';
4
+ };
@@ -0,0 +1,6 @@
1
+ const { convertToSlug } = require('../Search');
2
+
3
+ it('Test Search function', () => {
4
+ const data = convertToSlug('Bệnh viện');
5
+ expect(data).toEqual('benh vien');
6
+ });
@@ -0,0 +1,6 @@
1
+ import { shortEmailName } from '../ShortEmail';
2
+
3
+ it('Test shortEmailName function', () => {
4
+ const data = shortEmailName('emailExample@gmail.com');
5
+ expect(data).toEqual('emailExample');
6
+ });