@eohjsc/react-native-smart-city 0.2.91 → 0.2.94
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/assets/images/Device/air-dry.svg +3 -0
- package/assets/images/Device/auto.svg +3 -0
- package/assets/images/Device/circulator.svg +4 -0
- package/assets/images/Device/clean.svg +5 -0
- package/assets/images/Device/current-state.svg +3 -0
- package/assets/images/Device/door-state.svg +3 -0
- package/assets/images/Device/wind-strength.svg +12 -0
- package/package.json +1 -1
- package/src/commons/Action/ItemQuickAction.js +1 -0
- package/src/commons/Action/__test__/ItemQuickAction.test.js +49 -2
- package/src/commons/ActionGroup/ColorPickerTemplate.js +30 -24
- package/src/commons/ActionGroup/OnOffSmartLock/OnOffSmartLock.js +60 -12
- package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/__test__/index.test.js +47 -0
- package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/index.js +2 -0
- package/src/commons/ActionGroup/OnOffTemplate/OnOffSimpleTemplateStyle.js +2 -1
- package/src/commons/ActionGroup/OnOffTemplate/index.js +48 -28
- package/src/commons/ActionGroup/OptionsDropdownActionTemplate.js +31 -11
- package/src/commons/ActionGroup/OptionsDropdownActionTemplateStyle.js +5 -2
- package/src/commons/ActionGroup/SliderRangeTemplate.js +19 -5
- package/src/commons/ActionGroup/StatesGridActionTemplate.js +42 -36
- package/src/commons/ActionGroup/StatesGridActionTemplateStyle.js +5 -10
- package/src/commons/ActionGroup/TimerActionTemplate.js +14 -10
- package/src/commons/ActionGroup/TimerActionTemplateStyles.js +12 -0
- package/src/commons/ActionGroup/TwoButtonTemplate/TwoButtonTemplateStyles.js +55 -0
- package/src/commons/ActionGroup/TwoButtonTemplate/index.js +170 -0
- package/src/commons/ActionGroup/__test__/ColorPickerTemplate.test.js +74 -0
- package/src/commons/ActionGroup/__test__/OnOffSmartLock.test.js +107 -0
- package/src/commons/ActionGroup/__test__/SliderRangeTemplate.test.js +71 -0
- package/src/commons/ActionGroup/__test__/TimerActionTemplate.test.js +1 -1
- package/src/commons/ActionGroup/__test__/TwoButtonTemplate.test.js +112 -0
- package/src/commons/ActionGroup/index.js +4 -1
- package/src/commons/Calendar/index.js +5 -1
- package/src/commons/CameraDevice/index.js +6 -1
- package/src/commons/ConnectingProcess/__test__/Connecting.test.js +4 -1
- package/src/commons/Device/HistoryChart.js +2 -2
- package/src/commons/Device/HorizontalBarChart.js +6 -2
- package/src/commons/Device/ItemDevice.js +3 -13
- package/src/commons/Explore/SearchBox/__test__/SearchBox.test.js +19 -0
- package/src/commons/Explore/SearchBox/index.js +2 -0
- package/src/commons/IconComponent/index.js +32 -26
- package/src/commons/MediaPlayerDetail/index.js +16 -4
- package/src/commons/MenuActionMore/index.js +14 -1
- package/src/commons/Modal/ModalCustom.js +9 -1
- package/src/commons/SubUnit/Favorites/index.js +11 -41
- package/src/commons/SubUnit/ShortDetail.js +7 -41
- package/src/commons/SubUnit/__test__/Favorites.test.js +33 -35
- package/src/configs/API.js +4 -0
- package/src/configs/Colors.js +1 -0
- package/src/configs/Constants.js +29 -0
- package/src/context/actionType.ts +17 -0
- package/src/context/mockStore.ts +18 -0
- package/src/context/reducer.ts +102 -0
- package/src/hooks/Common/index.js +2 -0
- package/src/hooks/Common/useSensorsStatus.js +52 -0
- package/src/iot/RemoteControl/Bluetooth.js +2 -0
- package/src/iot/RemoteControl/GoogleHome.js +1 -0
- package/src/navigations/AutomateStack.js +16 -1
- package/src/navigations/UnitStack.js +27 -0
- package/src/screens/AddCommon/SelectSubUnit.js +1 -0
- package/src/screens/AddCommon/__test__/SelectSubUnit.test.js +2 -0
- package/src/screens/AddNewAction/Device/__test__/index.test.js +1 -1
- package/src/screens/AddNewAction/SelectAction.js +13 -15
- package/src/screens/AddNewAction/__test__/SelectAction.test.js +0 -7
- package/src/screens/AddNewGateway/PlugAndPlay/ConnectWifiWarning.js +2 -0
- package/src/screens/AddNewGateway/PlugAndPlay/GatewayWifiList.js +2 -0
- package/src/screens/AddNewGateway/PlugAndPlay/__test__/ConnectWifiWarning.test.js +10 -0
- package/src/screens/AddNewGateway/PlugAndPlay/__test__/GatewayWifiList.test.js +15 -0
- package/src/screens/AddNewGateway/SetupGatewayWifi.js +6 -1
- package/src/screens/AddNewGateway/__test__/SelectGateway.test.js +61 -0
- package/src/screens/AddNewGateway/__test__/SetupGateway.test.js +34 -0
- package/src/screens/AllCamera/index.js +1 -0
- package/src/screens/Automate/MultiUnits.js +9 -9
- package/src/screens/Automate/index.js +21 -20
- package/src/screens/Device/__test__/DetailHistoryChart.test.js +40 -0
- package/src/screens/Device/__test__/detail.test.js +119 -86
- package/src/screens/Device/detail.js +38 -51
- package/src/screens/Device/hooks/useFavoriteDevice.js +38 -0
- package/src/screens/EmergencyContacts/EmergencyContactsList.js +1 -1
- package/src/screens/EmergencyContacts/EmergencyContactsSelectContacts.js +41 -44
- package/src/screens/EmergencyContacts/__test__/EmergencyContactList.test.js +1 -0
- package/src/screens/EmergencyContacts/__test__/EmergencyContactsSelectContacts.test.js +18 -19
- package/src/screens/HanetCamera/Detail.js +20 -13
- package/src/screens/HanetCamera/ManageAccess.js +10 -52
- package/src/screens/HanetCamera/MemberInfo.js +59 -13
- package/src/screens/HanetCamera/__test__/ManageAccess.test.js +19 -0
- package/src/screens/HanetCamera/__test__/MemberInfo.test.js +57 -10
- package/src/screens/HanetCamera/components/RequestFaceIDPopup.js +90 -0
- package/src/screens/HanetCamera/hooks/__test__/useHanetCheckinData.test.js +9 -12
- package/src/screens/HanetCamera/hooks/useHanetCheckinData.js +10 -7
- package/src/screens/HanetCamera/styles/manageAccessStyles.js +0 -14
- package/src/screens/MoveToAnotherSubUnit/index.js +3 -1
- package/src/screens/Notification/__test__/NotificationItem.test.js +64 -53
- package/src/screens/Notification/components/NotificationItem.js +13 -4
- package/src/screens/ScriptDetail/__test__/index.test.js +15 -4
- package/src/screens/ScriptDetail/hooks/useStarredScript.js +32 -0
- package/src/screens/ScriptDetail/index.js +11 -20
- package/src/screens/SharedUnit/__test__/TabHeader.test.js +5 -0
- package/src/screens/Sharing/SelectUser.js +3 -23
- package/src/screens/Sharing/__test__/SelectUser.test.js +12 -80
- package/src/screens/SmartIr/__test__/GroupButtonByType.test.js +33 -0
- package/src/screens/SmartIr/components/GroupButtonByType/GroupButtonByType.js +2 -0
- package/src/screens/Unit/ChooseLocation.js +5 -0
- package/src/screens/Unit/Detail.js +34 -44
- package/src/screens/Unit/ManageUnit.js +21 -20
- package/src/screens/Unit/ManageUnitStyles.js +1 -0
- package/src/screens/Unit/SelectAddress.js +8 -2
- package/src/screens/Unit/Summaries.js +12 -15
- package/src/screens/Unit/__test__/Detail.test.js +25 -0
- package/src/screens/Unit/components/MyUnitDevice/index.js +13 -10
- package/src/screens/Unit/components/__test__/Header.test.js +32 -0
- package/src/screens/Unit/components/__test__/MyUnitDevice.test.js +2 -2
- package/src/screens/Unit/hook/useFavorites.js +28 -0
- package/src/utils/Apis/axios.js +7 -2
- package/src/utils/I18n/translations/en.json +3 -5
- package/src/utils/I18n/translations/vi.json +2 -4
|
@@ -11,7 +11,6 @@ import { API } from '../../../configs';
|
|
|
11
11
|
import { getTranslate } from '../../../utils/I18n';
|
|
12
12
|
import { SCProvider } from '../../../context';
|
|
13
13
|
import { mockSCStore } from '../../../context/mockStore';
|
|
14
|
-
import { ToastBottomHelper } from '../../../utils/Utils';
|
|
15
14
|
|
|
16
15
|
const wrapComponent = (route) => (
|
|
17
16
|
<SCProvider initState={mockSCStore({})}>
|
|
@@ -53,6 +52,7 @@ describe('test SelectUser container', () => {
|
|
|
53
52
|
let route;
|
|
54
53
|
|
|
55
54
|
beforeEach(() => {
|
|
55
|
+
axios.post.mockClear();
|
|
56
56
|
route = {
|
|
57
57
|
params: {
|
|
58
58
|
unit: {
|
|
@@ -66,10 +66,6 @@ describe('test SelectUser container', () => {
|
|
|
66
66
|
};
|
|
67
67
|
});
|
|
68
68
|
|
|
69
|
-
afterEach(() => {
|
|
70
|
-
axios.post.mockClear();
|
|
71
|
-
});
|
|
72
|
-
|
|
73
69
|
const findByTestId = (instance, id) => {
|
|
74
70
|
return instance.find((el) => el.props.testID === id);
|
|
75
71
|
};
|
|
@@ -158,8 +154,16 @@ describe('test SelectUser container', () => {
|
|
|
158
154
|
expect(axios.post).not.toHaveBeenCalled();
|
|
159
155
|
});
|
|
160
156
|
|
|
161
|
-
test('_TextInput onChange phone,
|
|
162
|
-
const response = {
|
|
157
|
+
test('_TextInput onChange phone, validated and call api sharedPermission', async () => {
|
|
158
|
+
const response = {
|
|
159
|
+
status: 200,
|
|
160
|
+
data: {
|
|
161
|
+
user: {
|
|
162
|
+
id: 2,
|
|
163
|
+
name: 'user add',
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
};
|
|
163
167
|
mockAxiosPost(response);
|
|
164
168
|
|
|
165
169
|
await act(async () => {
|
|
@@ -190,78 +194,6 @@ describe('test SelectUser container', () => {
|
|
|
190
194
|
});
|
|
191
195
|
|
|
192
196
|
accountList = instance.findAllByType(AccountList);
|
|
193
|
-
expect(accountList).toHaveLength(
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
test('_TextInput onChange unitOwner phone, validate and call api sharedPermission', async () => {
|
|
197
|
-
const response = {
|
|
198
|
-
status: 400,
|
|
199
|
-
data: { non_field_errors: 'You cannot invite yourself' },
|
|
200
|
-
};
|
|
201
|
-
mockAxiosPost(response);
|
|
202
|
-
|
|
203
|
-
const spyToastError = jest.spyOn(ToastBottomHelper, 'error');
|
|
204
|
-
|
|
205
|
-
await act(async () => {
|
|
206
|
-
tree = create(wrapComponent(route));
|
|
207
|
-
});
|
|
208
|
-
const instance = tree.root;
|
|
209
|
-
|
|
210
|
-
const textInput = instance.findByType(_TextInput);
|
|
211
|
-
const button = instance.findByType(Button);
|
|
212
|
-
|
|
213
|
-
await act(async () => {
|
|
214
|
-
await textInput.props.onChange('0909123456');
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
await act(async () => {
|
|
218
|
-
await button.props.onPress();
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
expect(textInput.props.errorText).toEqual('');
|
|
222
|
-
expect(axios.post).toHaveBeenCalledWith(API.SHARE.SHARE(), {
|
|
223
|
-
phone: '0909123456',
|
|
224
|
-
email: '',
|
|
225
|
-
unit: 1,
|
|
226
|
-
permissions: { controlPermissions: {}, readPermissions: {} },
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
expect(spyToastError).toBeCalled();
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
test('_TextInput onChange phone, validate and call api not sharedPermission', async () => {
|
|
233
|
-
const response = {
|
|
234
|
-
status: 400,
|
|
235
|
-
data: { phone: '0909123456' },
|
|
236
|
-
};
|
|
237
|
-
mockAxiosPost(response);
|
|
238
|
-
|
|
239
|
-
const spyToastError = jest.spyOn(ToastBottomHelper, 'error');
|
|
240
|
-
|
|
241
|
-
await act(async () => {
|
|
242
|
-
tree = create(wrapComponent(route));
|
|
243
|
-
});
|
|
244
|
-
const instance = tree.root;
|
|
245
|
-
|
|
246
|
-
const textInput = instance.findByType(_TextInput);
|
|
247
|
-
const button = instance.findByType(Button);
|
|
248
|
-
|
|
249
|
-
await act(async () => {
|
|
250
|
-
await textInput.props.onChange('0909123456');
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
await act(async () => {
|
|
254
|
-
await button.props.onPress();
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
expect(textInput.props.errorText).toEqual('');
|
|
258
|
-
expect(axios.post).toHaveBeenCalledWith(API.SHARE.SHARE(), {
|
|
259
|
-
phone: '0909123456',
|
|
260
|
-
email: '',
|
|
261
|
-
unit: 1,
|
|
262
|
-
permissions: { controlPermissions: {}, readPermissions: {} },
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
expect(spyToastError).toBeCalled();
|
|
197
|
+
expect(accountList).toHaveLength(1);
|
|
266
198
|
});
|
|
267
199
|
});
|
|
@@ -5,6 +5,8 @@ import { SCProvider } from '../../../context';
|
|
|
5
5
|
import { mockSCStore } from '../../../context/mockStore';
|
|
6
6
|
import WrapHeaderScrollable from '../../../commons/Sharing/WrapHeaderScrollable';
|
|
7
7
|
import { ButtonsBottom } from '../components/GroupButtonByType/ButtonsBottom';
|
|
8
|
+
import { TESTID } from '../../../configs/Constants';
|
|
9
|
+
import TextInput from '../../../commons/Form/TextInput';
|
|
8
10
|
|
|
9
11
|
const wrapComponent = (route) => (
|
|
10
12
|
<SCProvider initState={mockSCStore({})}>
|
|
@@ -42,6 +44,18 @@ describe('Test GroupButtonByType', () => {
|
|
|
42
44
|
const instance = tree.root;
|
|
43
45
|
const wrapHeaderScrollable = instance.findAllByType(WrapHeaderScrollable);
|
|
44
46
|
expect(wrapHeaderScrollable).toHaveLength(1);
|
|
47
|
+
|
|
48
|
+
const ButtonBottom = instance.find(
|
|
49
|
+
(el) => el.props.testID === TESTID.GROUP_BUTTON_TYPE.BUTTON_BOTTOM
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
act(() => {
|
|
53
|
+
ButtonBottom.props.onPressLeft();
|
|
54
|
+
});
|
|
55
|
+
act(() => {
|
|
56
|
+
ButtonBottom.props.onPressRight();
|
|
57
|
+
});
|
|
58
|
+
expect(ButtonBottom).toBeDefined();
|
|
45
59
|
});
|
|
46
60
|
test('onPressLeft ButtonsBottom', () => {
|
|
47
61
|
const route = {
|
|
@@ -77,4 +91,23 @@ describe('Test GroupButtonByType', () => {
|
|
|
77
91
|
buttonsBottom[0].props.onPressRight();
|
|
78
92
|
});
|
|
79
93
|
});
|
|
94
|
+
|
|
95
|
+
test('onChange TextInputPassword', async () => {
|
|
96
|
+
const route = {
|
|
97
|
+
params: {
|
|
98
|
+
device_type: { id: 1, name: '', icon: '' },
|
|
99
|
+
brand: { id: 1, name: '' },
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
act(() => {
|
|
103
|
+
tree = renderer.create(wrapComponent(route));
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const instance = tree.root;
|
|
107
|
+
const textInput = instance.findAllByType(TextInput);
|
|
108
|
+
await act(async () => {
|
|
109
|
+
await textInput[0].props.onChange();
|
|
110
|
+
});
|
|
111
|
+
expect(textInput).toHaveLength(1);
|
|
112
|
+
});
|
|
80
113
|
});
|
|
@@ -13,6 +13,7 @@ import { ButtonsBottom } from './ButtonsBottom';
|
|
|
13
13
|
import { Remote, SmartIr, Union } from '../../../../Images/SmartIr';
|
|
14
14
|
|
|
15
15
|
import styles from './GroupButtonByTypeStyles';
|
|
16
|
+
import { TESTID } from '../../../../configs/Constants';
|
|
16
17
|
|
|
17
18
|
const GroupButtonByType = memo(({ route }) => {
|
|
18
19
|
const t = useTranslations();
|
|
@@ -141,6 +142,7 @@ const GroupButtonByType = memo(({ route }) => {
|
|
|
141
142
|
selectionColor={Colors.Primary}
|
|
142
143
|
/>
|
|
143
144
|
<ButtonsBottom
|
|
145
|
+
testID={TESTID.GROUP_BUTTON_TYPE.BUTTON_BOTTOM}
|
|
144
146
|
onPressLeft={cancelButton}
|
|
145
147
|
onPressRight={ApplyButton}
|
|
146
148
|
textLeft={t('cancel')}
|
|
@@ -5,6 +5,7 @@ import MapView, { PROVIDER_GOOGLE } from 'react-native-maps';
|
|
|
5
5
|
import { useNavigation } from '@react-navigation/native';
|
|
6
6
|
import MarkerGeolocation from '../../../assets/images/Map/MarkerGeolocation.svg';
|
|
7
7
|
import BottomButtonView from '../../commons/BottomButtonView';
|
|
8
|
+
import { FullLoading } from '../../commons';
|
|
8
9
|
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
9
10
|
|
|
10
11
|
navigator.geolocation = require('@react-native-community/geolocation');
|
|
@@ -27,6 +28,7 @@ const ChooseLocation = memo(({ route }) => {
|
|
|
27
28
|
const { location, setAddress, setLocation } = route.params;
|
|
28
29
|
const { goBack } = useNavigation();
|
|
29
30
|
const [currentLocation, setCurrentLocation] = useState(location);
|
|
31
|
+
const [loading, setLoading] = useState(false);
|
|
30
32
|
const mapRef = useRef(null);
|
|
31
33
|
|
|
32
34
|
const onDone = useCallback(async () => {
|
|
@@ -34,6 +36,7 @@ const ChooseLocation = memo(({ route }) => {
|
|
|
34
36
|
return;
|
|
35
37
|
}
|
|
36
38
|
const { latitude, longitude } = currentLocation;
|
|
39
|
+
setLoading(true);
|
|
37
40
|
const { success, data } = await axiosGet(
|
|
38
41
|
API.EXTERNAL.GOOGLE_MAP.GET_LOCATION_FROM_LAT_LNG,
|
|
39
42
|
{
|
|
@@ -53,6 +56,7 @@ const ChooseLocation = memo(({ route }) => {
|
|
|
53
56
|
});
|
|
54
57
|
goBack();
|
|
55
58
|
}
|
|
59
|
+
setLoading(false);
|
|
56
60
|
}, [currentLocation, setAddress, setLocation, goBack]);
|
|
57
61
|
|
|
58
62
|
const onRegionChange = useCallback(
|
|
@@ -89,6 +93,7 @@ const ChooseLocation = memo(({ route }) => {
|
|
|
89
93
|
onPressMain={onDone}
|
|
90
94
|
typeMain="primaryText"
|
|
91
95
|
/>
|
|
96
|
+
{loading && <FullLoading />}
|
|
92
97
|
</View>
|
|
93
98
|
);
|
|
94
99
|
});
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, {
|
|
2
|
+
useCallback,
|
|
3
|
+
useContext,
|
|
4
|
+
useEffect,
|
|
5
|
+
useState,
|
|
6
|
+
useRef,
|
|
7
|
+
} from 'react';
|
|
2
8
|
import { AppState, RefreshControl, View } from 'react-native';
|
|
3
9
|
import { useIsFocused } from '@react-navigation/native';
|
|
4
10
|
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
@@ -16,6 +22,7 @@ import {
|
|
|
16
22
|
useIsOwnerOfUnit,
|
|
17
23
|
usePopover,
|
|
18
24
|
} from '../../hooks/Common';
|
|
25
|
+
import { useFavorites } from './hook/useFavorites';
|
|
19
26
|
import { scanBluetoothDevices } from '../../iot/RemoteControl/Bluetooth';
|
|
20
27
|
import { googleHomeConnect } from '../../iot/RemoteControl/GoogleHome';
|
|
21
28
|
import { axiosPost, fetchWithCache } from '../../utils/Apis/axios';
|
|
@@ -31,7 +38,11 @@ import { useNavigation } from '@react-navigation/native';
|
|
|
31
38
|
import Routes from '../../utils/Route';
|
|
32
39
|
import SubUnitAutomate from '../../commons/SubUnit/OneTap';
|
|
33
40
|
import SubUnitFavorites from '../../commons/SubUnit/Favorites';
|
|
34
|
-
import {
|
|
41
|
+
import {
|
|
42
|
+
AUTOMATE_TYPE,
|
|
43
|
+
NOTIFICATION_TYPES,
|
|
44
|
+
TESTID,
|
|
45
|
+
} from '../../configs/Constants';
|
|
35
46
|
import {
|
|
36
47
|
watchNotificationData,
|
|
37
48
|
unwatchNotificationData,
|
|
@@ -66,27 +77,27 @@ const UnitDetail = ({ route }) => {
|
|
|
66
77
|
);
|
|
67
78
|
|
|
68
79
|
const [unit, setUnit] = useState(unitData || { id: unitId });
|
|
69
|
-
const [appState, setAppState] = useState(AppState.currentState);
|
|
70
80
|
const [listMenuItem, setListMenuItem] = useState([]);
|
|
71
81
|
const [listStation, setListStation] = useState([]);
|
|
72
82
|
const [listAutomate, setListAutomate] = useState([]);
|
|
73
|
-
const [favorites, setFavorites] = useState({
|
|
74
|
-
devices: [],
|
|
75
|
-
automates: [],
|
|
76
|
-
});
|
|
77
83
|
const [isGGHomeConnected, setIsGGHomeConnected] = useState(false);
|
|
78
84
|
const [station, setStation] = useState({});
|
|
79
85
|
const [indexStation, setIndexStation] = useState(0);
|
|
80
86
|
const [showAdd, setShowAdd, setHideAdd] = useBoolean();
|
|
81
87
|
const [isFullScreen, setIsFullScreen] = useState(false);
|
|
82
88
|
const [dataFullScreen, setDataFullScreen] = useState();
|
|
83
|
-
const
|
|
89
|
+
const appState = useRef(AppState.currentState);
|
|
84
90
|
|
|
85
91
|
const { childRef, showingPopover, showPopoverWithRef, hidePopover } =
|
|
86
92
|
usePopover();
|
|
87
93
|
|
|
88
94
|
const { isOwner } = useIsOwnerOfUnit(unit.user_id);
|
|
89
95
|
|
|
96
|
+
const { favoriteDevices, favoriteAutomates } = useFavorites(
|
|
97
|
+
unit.stations || [],
|
|
98
|
+
listAutomate
|
|
99
|
+
);
|
|
100
|
+
|
|
90
101
|
const handleFullScreen = (data) => {
|
|
91
102
|
setIsFullScreen(!isFullScreen);
|
|
92
103
|
setDataFullScreen(data);
|
|
@@ -106,18 +117,6 @@ const UnitDetail = ({ route }) => {
|
|
|
106
117
|
isFavorites: true,
|
|
107
118
|
name: t('favorites'),
|
|
108
119
|
});
|
|
109
|
-
let favoriteDevices = [];
|
|
110
|
-
rawUnitData.stations.forEach((stationItem) => {
|
|
111
|
-
if (stationItem.sensors) {
|
|
112
|
-
favoriteDevices = favoriteDevices.concat(
|
|
113
|
-
stationItem.sensors.filter((sensorItem) => sensorItem.is_favourite)
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
setFavorites((prevData) => ({
|
|
118
|
-
...prevData,
|
|
119
|
-
devices: favoriteDevices,
|
|
120
|
-
}));
|
|
121
120
|
},
|
|
122
121
|
[t]
|
|
123
122
|
);
|
|
@@ -125,13 +124,10 @@ const UnitDetail = ({ route }) => {
|
|
|
125
124
|
const fetchDetails = useCallback(async () => {
|
|
126
125
|
getAutomates();
|
|
127
126
|
await fetchWithCache(API.UNIT.UNIT_DETAIL(unitId), {}, (response) => {
|
|
128
|
-
const { success, data
|
|
127
|
+
const { success, data } = response;
|
|
129
128
|
if (success) {
|
|
130
|
-
setServerDown(false);
|
|
131
129
|
prepareData(data);
|
|
132
130
|
setUnit(data);
|
|
133
|
-
} else if (resp_status >= 500) {
|
|
134
|
-
setServerDown(true);
|
|
135
131
|
}
|
|
136
132
|
});
|
|
137
133
|
}, [setUnit, unitId, prepareData, getAutomates]);
|
|
@@ -157,10 +153,6 @@ const UnitDetail = ({ route }) => {
|
|
|
157
153
|
type: AUTOMATE_TYPE.AUTOMATION,
|
|
158
154
|
},
|
|
159
155
|
]);
|
|
160
|
-
setFavorites((prevData) => ({
|
|
161
|
-
...prevData,
|
|
162
|
-
automates: data.filter((item) => item?.script?.is_star),
|
|
163
|
-
}));
|
|
164
156
|
}
|
|
165
157
|
}
|
|
166
158
|
);
|
|
@@ -174,23 +166,21 @@ const UnitDetail = ({ route }) => {
|
|
|
174
166
|
[fetchDetails]
|
|
175
167
|
);
|
|
176
168
|
|
|
177
|
-
|
|
178
|
-
(nextAppState) => {
|
|
179
|
-
if (
|
|
169
|
+
useEffect(() => {
|
|
170
|
+
const subscription = AppState.addEventListener('change', (nextAppState) => {
|
|
171
|
+
if (
|
|
172
|
+
appState.current.match(/inactive|background/) &&
|
|
173
|
+
nextAppState === 'active'
|
|
174
|
+
) {
|
|
180
175
|
fetchDetails();
|
|
181
176
|
}
|
|
182
|
-
|
|
183
|
-
}
|
|
184
|
-
[appState, fetchDetails]
|
|
185
|
-
);
|
|
186
|
-
|
|
187
|
-
useEffect(() => {
|
|
188
|
-
AppState.addEventListener('change', handleAppStateChange);
|
|
177
|
+
appState.current = nextAppState;
|
|
178
|
+
});
|
|
189
179
|
|
|
190
180
|
return () => {
|
|
191
|
-
|
|
181
|
+
subscription.remove();
|
|
192
182
|
};
|
|
193
|
-
}, [
|
|
183
|
+
}, [fetchDetails]);
|
|
194
184
|
|
|
195
185
|
const handleGoogleHomeConnect = useCallback(
|
|
196
186
|
async (options) => {
|
|
@@ -303,11 +293,11 @@ const UnitDetail = ({ route }) => {
|
|
|
303
293
|
if (station?.isFavorites) {
|
|
304
294
|
return (
|
|
305
295
|
<SubUnitFavorites
|
|
306
|
-
unit={unit}
|
|
307
296
|
isOwner={isOwner}
|
|
308
|
-
|
|
297
|
+
unit={unit}
|
|
298
|
+
favoriteDevices={favoriteDevices}
|
|
299
|
+
favoriteAutomates={favoriteAutomates}
|
|
309
300
|
wrapItemStyle={styles.wrapItemStyle}
|
|
310
|
-
serverDown={serverDown}
|
|
311
301
|
isGGHomeConnected={isGGHomeConnected}
|
|
312
302
|
/>
|
|
313
303
|
);
|
|
@@ -334,7 +324,6 @@ const UnitDetail = ({ route }) => {
|
|
|
334
324
|
<ShortDetailSubUnit
|
|
335
325
|
unit={unit}
|
|
336
326
|
station={station}
|
|
337
|
-
serverDown={serverDown}
|
|
338
327
|
isGGHomeConnected={isGGHomeConnected}
|
|
339
328
|
/>
|
|
340
329
|
);
|
|
@@ -371,6 +360,7 @@ const UnitDetail = ({ route }) => {
|
|
|
371
360
|
<View style={styles.container}>
|
|
372
361
|
<Summaries unit={unit} />
|
|
373
362
|
<NavBar
|
|
363
|
+
testID={TESTID.NAVBAR_ON_SNAP_ITEM}
|
|
374
364
|
listStation={listStation}
|
|
375
365
|
listMenuItem={listMenuItem}
|
|
376
366
|
onSnapToItem={onSnapToItem}
|
|
@@ -39,25 +39,25 @@ const ButtonWrapper = ({
|
|
|
39
39
|
style={styles.buttonWrapper}
|
|
40
40
|
>
|
|
41
41
|
<View style={styles.buttonInfo}>
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
</Text>
|
|
46
|
-
) : (
|
|
47
|
-
(icon && <Image source={{ uri: icon }} style={styles.avatar} />) || (
|
|
48
|
-
<View style={styles.avatar}>
|
|
49
|
-
<Icon name={'user'} size={27} />
|
|
50
|
-
</View>
|
|
51
|
-
)
|
|
52
|
-
)}
|
|
42
|
+
<Text type="H4" semibold>
|
|
43
|
+
{title}
|
|
44
|
+
</Text>
|
|
53
45
|
<View style={styles.buttonValue}>
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
46
|
+
{!icon ? (
|
|
47
|
+
<Text
|
|
48
|
+
type="Body"
|
|
49
|
+
color={valueColor || Colors.Gray7}
|
|
50
|
+
style={styles.value}
|
|
51
|
+
>
|
|
52
|
+
{value}
|
|
53
|
+
</Text>
|
|
54
|
+
) : (
|
|
55
|
+
<Image source={{ uri: value }} style={styles.avatar} /> || (
|
|
56
|
+
<View style={styles.avatar}>
|
|
57
|
+
<Icon name={'user'} size={27} />
|
|
58
|
+
</View>
|
|
59
|
+
)
|
|
60
|
+
)}
|
|
61
61
|
<IconOutline name="right" size={20} color={Colors.Gray7} />
|
|
62
62
|
</View>
|
|
63
63
|
</View>
|
|
@@ -218,8 +218,9 @@ const ManageUnit = ({ route }) => {
|
|
|
218
218
|
<>
|
|
219
219
|
<ButtonWrapper
|
|
220
220
|
onPress={() => handleChoosePhoto('avatar')}
|
|
221
|
-
value={
|
|
222
|
-
icon
|
|
221
|
+
value={unitData.icon}
|
|
222
|
+
icon
|
|
223
|
+
title={t('icon_unit')}
|
|
223
224
|
testID={TESTID.MANAGE_UNIT_CHANGE_PHOTO}
|
|
224
225
|
/>
|
|
225
226
|
<ButtonWrapper
|
|
@@ -9,6 +9,7 @@ import BottomButtonView from '../../commons/BottomButtonView';
|
|
|
9
9
|
import SearchBarLocation from '../../commons/SearchLocation';
|
|
10
10
|
import RowLocation from '../../commons/SearchLocation/RowLocation';
|
|
11
11
|
import Text from '../../commons/Text';
|
|
12
|
+
import { FullLoading } from '../../commons';
|
|
12
13
|
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
13
14
|
|
|
14
15
|
navigator.geolocation = require('@react-native-community/geolocation');
|
|
@@ -34,6 +35,7 @@ const SelectAddress = memo(({ route }) => {
|
|
|
34
35
|
const [input, setInput] = useState('');
|
|
35
36
|
const [searchData, setSearchData] = useState([]);
|
|
36
37
|
const [searchedLocation, setSearchedLocation] = useState(null);
|
|
38
|
+
const [loading, setLoading] = useState(false);
|
|
37
39
|
const mapRef = useRef(null);
|
|
38
40
|
|
|
39
41
|
const onDone = useCallback(() => {
|
|
@@ -116,6 +118,7 @@ const SelectAddress = memo(({ route }) => {
|
|
|
116
118
|
async (position) => {
|
|
117
119
|
const currentLatitude = JSON.stringify(position.coords.latitude);
|
|
118
120
|
const currentLongitude = JSON.stringify(position.coords.longitude);
|
|
121
|
+
setLoading(true);
|
|
119
122
|
const { success, data } = await axiosGet(
|
|
120
123
|
API.EXTERNAL.GOOGLE_MAP.GET_LOCATION_FROM_LAT_LNG,
|
|
121
124
|
{
|
|
@@ -134,9 +137,11 @@ const SelectAddress = memo(({ route }) => {
|
|
|
134
137
|
longitude: result.geometry.location.lng,
|
|
135
138
|
});
|
|
136
139
|
}
|
|
140
|
+
setLoading(false);
|
|
137
141
|
},
|
|
138
|
-
|
|
139
|
-
|
|
142
|
+
// eslint-disable-next-line promise/prefer-await-to-callbacks
|
|
143
|
+
(error) => {}
|
|
144
|
+
// { enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 } enable on emulator
|
|
140
145
|
);
|
|
141
146
|
}, []);
|
|
142
147
|
|
|
@@ -233,6 +238,7 @@ const SelectAddress = memo(({ route }) => {
|
|
|
233
238
|
typeMain="primaryText"
|
|
234
239
|
typeSecondary="primaryText"
|
|
235
240
|
/>
|
|
241
|
+
{loading && <FullLoading />}
|
|
236
242
|
</View>
|
|
237
243
|
);
|
|
238
244
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { memo, useCallback, useEffect, useState } from 'react';
|
|
1
|
+
import React, { memo, useCallback, useEffect, useState, useRef } from 'react';
|
|
2
2
|
import { AppState, ScrollView } from 'react-native';
|
|
3
3
|
import SummaryItem from '../../commons/SummaryItem';
|
|
4
4
|
import Routes from '../../utils/Route';
|
|
@@ -8,12 +8,11 @@ import { API } from '../../configs';
|
|
|
8
8
|
|
|
9
9
|
const Summaries = memo(({ unit }) => {
|
|
10
10
|
const [unitSummaries, setUnitSummaries] = useState([]);
|
|
11
|
-
const [appState, setAppState] = useState(AppState.currentState);
|
|
12
11
|
// eslint-disable-next-line no-unused-vars
|
|
13
12
|
const [localState, _] = useState({});
|
|
14
13
|
const isFocused = useIsFocused();
|
|
15
|
-
|
|
16
14
|
const navigation = useNavigation();
|
|
15
|
+
const appState = useRef(AppState.currentState);
|
|
17
16
|
|
|
18
17
|
const fetchUnitSummary = useCallback(async () => {
|
|
19
18
|
if (!unit.id) {
|
|
@@ -55,23 +54,21 @@ const Summaries = memo(({ unit }) => {
|
|
|
55
54
|
}
|
|
56
55
|
}, [localState, fetchUnitSummary]);
|
|
57
56
|
|
|
58
|
-
|
|
59
|
-
(nextAppState) => {
|
|
60
|
-
if (
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
const subscription = AppState.addEventListener('change', (nextAppState) => {
|
|
59
|
+
if (
|
|
60
|
+
appState.current.match(/inactive|background/) &&
|
|
61
|
+
nextAppState === 'active'
|
|
62
|
+
) {
|
|
61
63
|
fetchUnitSummary();
|
|
62
64
|
}
|
|
63
|
-
|
|
64
|
-
}
|
|
65
|
-
[appState, fetchUnitSummary]
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
useEffect(() => {
|
|
69
|
-
AppState.addEventListener('change', handleAppStateChange);
|
|
65
|
+
appState.current = nextAppState;
|
|
66
|
+
});
|
|
70
67
|
|
|
71
68
|
return () => {
|
|
72
|
-
|
|
69
|
+
subscription.remove();
|
|
73
70
|
};
|
|
74
|
-
}, [
|
|
71
|
+
}, [fetchUnitSummary]);
|
|
75
72
|
|
|
76
73
|
useEffect(() => {
|
|
77
74
|
if (!isFocused) {
|
|
@@ -514,4 +514,29 @@ describe('Test UnitDetail', () => {
|
|
|
514
514
|
const favorites = instance.findAllByType(SubUnitFavorites);
|
|
515
515
|
expect(favorites).toHaveLength(1);
|
|
516
516
|
});
|
|
517
|
+
test('render navbar', async () => {
|
|
518
|
+
const unitData = {
|
|
519
|
+
stations: [
|
|
520
|
+
{
|
|
521
|
+
isFavorites: true,
|
|
522
|
+
name: 'Favorites',
|
|
523
|
+
},
|
|
524
|
+
],
|
|
525
|
+
};
|
|
526
|
+
await act(async () => {
|
|
527
|
+
tree = await renderer.create(
|
|
528
|
+
wrapComponent({ params: { ...route.params, unitData } }, account)
|
|
529
|
+
);
|
|
530
|
+
});
|
|
531
|
+
const instance = tree.root;
|
|
532
|
+
const navBar = instance.find(
|
|
533
|
+
(el) => el.props.testID === TESTID.NAVBAR_ON_SNAP_ITEM
|
|
534
|
+
);
|
|
535
|
+
|
|
536
|
+
await act(() => {
|
|
537
|
+
navBar.props.onSnapToItem();
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
expect(navBar).toBeDefined();
|
|
541
|
+
});
|
|
517
542
|
});
|
|
@@ -24,17 +24,19 @@ const MyUnitDevice = ({ sensor, unit }) => {
|
|
|
24
24
|
|
|
25
25
|
return (
|
|
26
26
|
<View style={styles.item}>
|
|
27
|
-
<TouchableOpacity style={styles.
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
<
|
|
31
|
-
{
|
|
32
|
-
|
|
33
|
-
<View style={styles.roomDevice}>
|
|
34
|
-
<Text style={styles.roomDevicePart}>
|
|
35
|
-
{sensor.station_name}
|
|
36
|
-
{status ? ` - ${status}` : ''}
|
|
27
|
+
<TouchableOpacity style={styles.flex1} onPress={goToSensorDisplay}>
|
|
28
|
+
<View style={styles.rowCenter}>
|
|
29
|
+
<Image style={styles.image} source={Images.mainDoor} />
|
|
30
|
+
<View style={styles.marginTop3}>
|
|
31
|
+
<Text semibold style={styles.nameDevice}>
|
|
32
|
+
{sensor.name}
|
|
37
33
|
</Text>
|
|
34
|
+
<View style={styles.roomDevice}>
|
|
35
|
+
<Text style={styles.roomDevicePart}>
|
|
36
|
+
{sensor.station_name}
|
|
37
|
+
{status ? ` - ${status}` : ''}
|
|
38
|
+
</Text>
|
|
39
|
+
</View>
|
|
38
40
|
</View>
|
|
39
41
|
</View>
|
|
40
42
|
</TouchableOpacity>
|
|
@@ -92,6 +94,7 @@ const styles = StyleSheet.create({
|
|
|
92
94
|
flex: 1,
|
|
93
95
|
marginTop: 3,
|
|
94
96
|
},
|
|
97
|
+
flex1: { flex: 1 },
|
|
95
98
|
});
|
|
96
99
|
|
|
97
100
|
export default MyUnitDevice;
|
|
@@ -8,6 +8,7 @@ import { mockSCStore } from '../../../../context/mockStore';
|
|
|
8
8
|
import Header from '../Header';
|
|
9
9
|
import ImageButton from '../../../../commons/ImageButton';
|
|
10
10
|
import Routes from '../../../../utils/Route';
|
|
11
|
+
import { TouchableOpacity } from 'react-native';
|
|
11
12
|
|
|
12
13
|
const wrapComponent = (title, goBack, dark, hideRight) => (
|
|
13
14
|
<SCProvider initState={mockSCStore({})}>
|
|
@@ -15,6 +16,19 @@ const wrapComponent = (title, goBack, dark, hideRight) => (
|
|
|
15
16
|
</SCProvider>
|
|
16
17
|
);
|
|
17
18
|
|
|
19
|
+
const mockedNavigate = jest.fn();
|
|
20
|
+
const mockedGoBack = jest.fn();
|
|
21
|
+
jest.mock('@react-navigation/native', () => {
|
|
22
|
+
return {
|
|
23
|
+
...jest.requireActual('@react-navigation/native'),
|
|
24
|
+
useNavigation: () => ({
|
|
25
|
+
navigate: mockedNavigate,
|
|
26
|
+
goBack: mockedGoBack,
|
|
27
|
+
}),
|
|
28
|
+
useIsFocused: () => true,
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
|
|
18
32
|
describe('Test Header', () => {
|
|
19
33
|
let tree;
|
|
20
34
|
test('test hideModal', () => {
|
|
@@ -53,4 +67,22 @@ describe('Test Header', () => {
|
|
|
53
67
|
});
|
|
54
68
|
expect(popover.props.isVisible).toBe(false);
|
|
55
69
|
});
|
|
70
|
+
|
|
71
|
+
test('test onpress touchableOpacity', () => {
|
|
72
|
+
act(() => {
|
|
73
|
+
tree = renderer.create(wrapComponent());
|
|
74
|
+
});
|
|
75
|
+
const instance = tree.root;
|
|
76
|
+
const touchableOpacity = instance.findAllByType(TouchableOpacity);
|
|
77
|
+
|
|
78
|
+
act(() => {
|
|
79
|
+
touchableOpacity[0].props.onPress();
|
|
80
|
+
touchableOpacity[1].props.onPress();
|
|
81
|
+
touchableOpacity[2].props.onPress();
|
|
82
|
+
touchableOpacity[3].props.onPress();
|
|
83
|
+
});
|
|
84
|
+
expect(touchableOpacity).toHaveLength(4);
|
|
85
|
+
expect(touchableOpacity).toBeDefined();
|
|
86
|
+
expect(mockedGoBack).toHaveBeenCalled();
|
|
87
|
+
});
|
|
56
88
|
});
|