@eohjsc/react-native-smart-city 0.2.86 → 0.2.87
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/brightnessBlack.svg +12 -0
- package/index.js +4 -0
- package/package.json +1 -1
- package/src/Images/SmartIr/AC.svg +14 -0
- package/src/Images/SmartIr/DIY.svg +3 -0
- package/src/Images/SmartIr/Fan.svg +10 -0
- package/src/Images/SmartIr/Fridge.svg +5 -0
- package/src/Images/SmartIr/TV.svg +10 -0
- package/src/Images/SmartIr/WM.svg +11 -0
- package/src/Images/SmartIr/index.js +7 -0
- package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/AutoLockStyles.js +40 -0
- package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/ButtonWrapper.js +65 -0
- package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/ButtonWrapperStyles.js +43 -0
- package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/__test__/index.test.js +48 -0
- package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/index.js +57 -0
- package/src/commons/ActionGroup/{OnOffSmartLock.js → OnOffSmartLock/OnOffSmartLock.js} +5 -5
- package/src/commons/ActionGroup/{OnOffSmartLockStyle.js → OnOffSmartLock/OnOffSmartLockStyle.js} +1 -1
- package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/ItemPasscode.js +48 -0
- package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/ItemPasscodeStyles.js +42 -0
- package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/PasscodeListStyles.js +49 -0
- package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/index.js +66 -0
- package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/ButtonWrapper.js +96 -0
- package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/SetupGeneratePasscodeStyles.js +98 -0
- package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/__test__/index.test.js +62 -0
- package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/index.js +249 -0
- package/src/commons/ActionGroup/OnOffTemplate/index.js +4 -2
- package/src/commons/ActionGroup/OptionsDropdownActionTemplate.js +2 -1
- package/src/commons/ActionGroup/SmartTiviActionTemplate/SmartTiviActionTemplate.js +188 -186
- package/src/commons/ActionGroup/StatesGridActionTemplate.js +2 -1
- package/src/commons/ActionGroup/index.js +1 -1
- package/src/commons/Device/DisconnectedView.js +7 -1
- package/src/commons/Device/LinearChart.js +3 -40
- package/src/commons/Device/__test__/DisconnectedView.test.js +13 -2
- package/src/commons/RowItem/index.js +12 -7
- package/src/commons/WheelDateTimePicker/index.js +18 -4
- package/src/configs/API.js +1 -1
- package/src/configs/Colors.js +1 -0
- package/src/configs/Constants.js +11 -0
- package/src/context/mockStore.ts +1 -0
- package/src/iot/RemoteControl/Bluetooth.js +3 -3
- package/src/navigations/SmartIrStack.js +31 -0
- package/src/navigations/SmartLockStack.js +51 -0
- package/src/navigations/UnitStack.js +12 -3
- package/src/screens/AddCommon/__test__/SelectSubUnit.test.js +1 -1
- package/src/screens/AddNewGateway/PlugAndPlay/ConnectWifiWarning.js +77 -55
- package/src/screens/AddNewGateway/PlugAndPlay/GatewayWifiList.js +141 -27
- package/src/screens/AddNewGateway/PlugAndPlay/__test__/ConnectWifiWarning.test.js +58 -0
- package/src/screens/AddNewGateway/PlugAndPlay/__test__/GatewayWifiList.test.js +26 -2
- package/src/screens/Device/components/SensorConnectStatusViewHeader.js +13 -2
- package/src/screens/Device/detail.js +49 -10
- package/src/screens/Device/hooks/useDisconnectedDevice.js +21 -5
- package/src/screens/GuestInfo/components/AccessScheduleItem.js +9 -2
- package/src/screens/GuestInfo/components/RecurringDetail.js +3 -2
- package/src/screens/GuestInfo/components/TemporaryDetail.js +3 -2
- package/src/screens/GuestInfo/styles/AccessScheduleItemStyles.js +3 -0
- package/src/screens/Notification/__test__/NotificationItem.test.js +1 -0
- package/src/screens/Notification/components/NotificationItem.js +16 -0
- package/src/screens/SmartIr/__test__/GroupButtonByType.test.js +54 -0
- package/src/screens/SmartIr/__test__/SelectBrand.test.js +74 -0
- package/src/screens/SmartIr/__test__/SelectDeviceType.test.js +64 -0
- package/src/screens/SmartIr/__test__/SmartIr.test.js +1 -0
- package/src/screens/SmartIr/components/GroupButtonByType/GroupButtonByType.js +86 -0
- package/src/screens/SmartIr/components/GroupButtonByType/GroupButtonByTypeStyles.js +76 -0
- package/src/screens/SmartIr/components/SelectBrand.js +61 -0
- package/src/screens/SmartIr/components/SelectBrandStyles.js +14 -0
- package/src/screens/SmartIr/components/SelectDeviceType.js +96 -0
- package/src/screens/SmartIr/components/SelectDeviceTypeStyles.js +30 -0
- package/src/screens/SmartIr/index.js +8 -3
- package/src/screens/Unit/Detail.js +7 -3
- package/src/screens/Unit/components/MyUnitDevice/index.js +2 -4
- package/src/screens/Unit/components/__test__/MyUnitDevice.test.js +38 -9
- package/src/utils/I18n/translations/en.json +24 -1
- package/src/utils/I18n/translations/vi.json +24 -1
- package/src/utils/Route/index.js +9 -1
|
@@ -79,7 +79,7 @@ const DeviceDetail = ({ route }) => {
|
|
|
79
79
|
isConnected: true,
|
|
80
80
|
displayTemplate: true,
|
|
81
81
|
});
|
|
82
|
-
|
|
82
|
+
const [serverDown, setServerDown] = useState(false);
|
|
83
83
|
const isDeviceConnectedViaBle = useMemo(
|
|
84
84
|
() => isDeviceConnected(sensor?.remote_control_options?.bluetooth?.address),
|
|
85
85
|
[sensor]
|
|
@@ -99,15 +99,23 @@ const DeviceDetail = ({ route }) => {
|
|
|
99
99
|
});
|
|
100
100
|
}, [display]);
|
|
101
101
|
|
|
102
|
-
useDisconnectedDevice(sensorName, isDeviceHasBle);
|
|
102
|
+
useDisconnectedDevice(sensorName, isDeviceHasBle, serverDown);
|
|
103
103
|
|
|
104
104
|
const netInfo = useNetInfo();
|
|
105
105
|
|
|
106
|
-
const isShowSetupEmergencyContact =
|
|
106
|
+
const isShowSetupEmergencyContact = useMemo(() => {
|
|
107
107
|
display.items.filter(
|
|
108
108
|
(item) =>
|
|
109
109
|
item.type === 'emergency' && item.configuration.type === 'button'
|
|
110
110
|
).length > 0;
|
|
111
|
+
}, [display.items]);
|
|
112
|
+
|
|
113
|
+
const isShowSetUpSmartLock = useMemo(() => {
|
|
114
|
+
display.items.filter(
|
|
115
|
+
(item) =>
|
|
116
|
+
item.type === 'smartLock' && item.configuration.type === 'button'
|
|
117
|
+
).length > 0;
|
|
118
|
+
}, [display.items]);
|
|
111
119
|
|
|
112
120
|
const addToFavorites = useCallback(async () => {
|
|
113
121
|
const { success } = await axiosPost(
|
|
@@ -177,16 +185,16 @@ const DeviceDetail = ({ route }) => {
|
|
|
177
185
|
return;
|
|
178
186
|
}
|
|
179
187
|
|
|
180
|
-
const
|
|
188
|
+
const { success, data, resp_status } = await axiosGet(
|
|
181
189
|
API.SENSOR.DISPLAY(sensor?.id),
|
|
182
190
|
{},
|
|
183
191
|
true
|
|
184
192
|
);
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
if (
|
|
189
|
-
const config =
|
|
193
|
+
if (success) {
|
|
194
|
+
setDisplay(data);
|
|
195
|
+
setServerDown(false);
|
|
196
|
+
if (data.items.length) {
|
|
197
|
+
const config = data.items[0].configuration;
|
|
190
198
|
if (config.hasOwnProperty('max_value')) {
|
|
191
199
|
setMaxValue(config.max_value);
|
|
192
200
|
}
|
|
@@ -201,6 +209,8 @@ const DeviceDetail = ({ route }) => {
|
|
|
201
209
|
}
|
|
202
210
|
}
|
|
203
211
|
}
|
|
212
|
+
} else if (resp_status >= 500) {
|
|
213
|
+
setServerDown(true);
|
|
204
214
|
}
|
|
205
215
|
setLoading((preState) => ({ ...preState, displayTemplate: false }));
|
|
206
216
|
|
|
@@ -303,6 +313,33 @@ const DeviceDetail = ({ route }) => {
|
|
|
303
313
|
deviceInfo: display.items.filter((item) => item.type === 'device_info'),
|
|
304
314
|
},
|
|
305
315
|
});
|
|
316
|
+
if (isShowSetUpSmartLock) {
|
|
317
|
+
menuItems.push({
|
|
318
|
+
route: Routes.SmartLockStack,
|
|
319
|
+
data: {
|
|
320
|
+
screen: Routes.AutoLock,
|
|
321
|
+
},
|
|
322
|
+
text: t('auto_lock'),
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
if (isOwner && isShowSetUpSmartLock) {
|
|
326
|
+
menuItems.push({
|
|
327
|
+
route: Routes.SmartLockStack,
|
|
328
|
+
data: {
|
|
329
|
+
screen: Routes.SetupGeneratePasscode,
|
|
330
|
+
},
|
|
331
|
+
text: t('setup_generate_passcode'),
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
if (isShowSetUpSmartLock) {
|
|
335
|
+
menuItems.push({
|
|
336
|
+
route: Routes.SmartLockStack,
|
|
337
|
+
data: {
|
|
338
|
+
screen: Routes.PasscodeList,
|
|
339
|
+
},
|
|
340
|
+
text: t('passcode_list'),
|
|
341
|
+
});
|
|
342
|
+
}
|
|
306
343
|
if (!isFavourite) {
|
|
307
344
|
menuItems.unshift({
|
|
308
345
|
doAction: addToFavorites,
|
|
@@ -319,11 +356,12 @@ const DeviceDetail = ({ route }) => {
|
|
|
319
356
|
display.items,
|
|
320
357
|
isOwner,
|
|
321
358
|
isShowSetupEmergencyContact,
|
|
359
|
+
isShowSetUpSmartLock,
|
|
322
360
|
t,
|
|
323
361
|
isFavourite,
|
|
324
362
|
sensor,
|
|
325
|
-
sensorName,
|
|
326
363
|
unit,
|
|
364
|
+
sensorName,
|
|
327
365
|
station,
|
|
328
366
|
emergencyDeviceId,
|
|
329
367
|
addToFavorites,
|
|
@@ -465,6 +503,7 @@ const DeviceDetail = ({ route }) => {
|
|
|
465
503
|
isDisplayTime={isShowSetupEmergencyContact ? false : isDisplayTime}
|
|
466
504
|
showWindDirection={showWindDirection}
|
|
467
505
|
isGGHomeConnected={isGGHomeConnected}
|
|
506
|
+
isDeviceHasBle={isDeviceHasBle}
|
|
468
507
|
>
|
|
469
508
|
{display.items.map((item) => (
|
|
470
509
|
<SensorDisplayItem
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import NetInfo from '@react-native-community/netinfo';
|
|
2
|
+
import { useNavigation } from '@react-navigation/native';
|
|
2
3
|
import { useCallback, useEffect } from 'react';
|
|
3
4
|
import { Alert, Linking, Platform } from 'react-native';
|
|
4
5
|
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
@@ -8,16 +9,22 @@ import {
|
|
|
8
9
|
} from '../../../iot/RemoteControl/Bluetooth';
|
|
9
10
|
import { ToastBottomHelper } from '../../../utils/Utils';
|
|
10
11
|
|
|
11
|
-
export const useDisconnectedDevice = (
|
|
12
|
+
export const useDisconnectedDevice = (
|
|
13
|
+
sensorName,
|
|
14
|
+
isDeviceHasBle,
|
|
15
|
+
serverDown
|
|
16
|
+
) => {
|
|
12
17
|
const t = useTranslations();
|
|
13
18
|
const openBluetoothIOS = () => {
|
|
14
19
|
Linking.openURL('App-Prefs:Bluetooth');
|
|
15
20
|
};
|
|
21
|
+
const { goBack } = useNavigation();
|
|
16
22
|
const actions =
|
|
17
23
|
Platform.OS === 'ios'
|
|
18
24
|
? [
|
|
19
25
|
{
|
|
20
26
|
text: 'Skip',
|
|
27
|
+
onPress: () => goBack(),
|
|
21
28
|
},
|
|
22
29
|
{
|
|
23
30
|
text: 'Open',
|
|
@@ -27,6 +34,7 @@ export const useDisconnectedDevice = (sensorName, isDeviceHasBle) => {
|
|
|
27
34
|
: [
|
|
28
35
|
{
|
|
29
36
|
text: 'Skip',
|
|
37
|
+
onPress: () => goBack(),
|
|
30
38
|
},
|
|
31
39
|
{
|
|
32
40
|
text: 'Open',
|
|
@@ -38,8 +46,11 @@ export const useDisconnectedDevice = (sensorName, isDeviceHasBle) => {
|
|
|
38
46
|
const isBluetoothEnabled = useIsBluetoothEnabled();
|
|
39
47
|
|
|
40
48
|
const checkNetWorkConnect = useCallback(
|
|
41
|
-
async (isHavingInternet, isBtEnabled) => {
|
|
42
|
-
if (
|
|
49
|
+
async (isHavingInternet, isBtEnabled, serverDown) => {
|
|
50
|
+
if (!isDeviceHasBle) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (isHavingInternet === false || serverDown) {
|
|
43
54
|
// TODO avoid case first render isHavingInternet == null
|
|
44
55
|
if (isBtEnabled === true) {
|
|
45
56
|
ToastBottomHelper.info(
|
|
@@ -64,6 +75,11 @@ export const useDisconnectedDevice = (sensorName, isDeviceHasBle) => {
|
|
|
64
75
|
);
|
|
65
76
|
|
|
66
77
|
useEffect(() => {
|
|
67
|
-
checkNetWorkConnect(netState.isConnected, isBluetoothEnabled);
|
|
68
|
-
}, [
|
|
78
|
+
checkNetWorkConnect(netState.isConnected, isBluetoothEnabled, serverDown);
|
|
79
|
+
}, [
|
|
80
|
+
netState.isConnected,
|
|
81
|
+
isBluetoothEnabled,
|
|
82
|
+
checkNetWorkConnect,
|
|
83
|
+
serverDown,
|
|
84
|
+
]);
|
|
69
85
|
};
|
|
@@ -5,14 +5,21 @@ import Text from '../../../commons/Text';
|
|
|
5
5
|
import { TESTID } from '../../../configs/Constants';
|
|
6
6
|
import styles from '../styles/AccessScheduleItemStyles';
|
|
7
7
|
|
|
8
|
-
const AccessScheduleItem = ({
|
|
8
|
+
const AccessScheduleItem = ({
|
|
9
|
+
item,
|
|
10
|
+
isSelected,
|
|
11
|
+
onSelect,
|
|
12
|
+
isSetupGeneratePasscode,
|
|
13
|
+
}) => {
|
|
9
14
|
const DetailComponent = item.detail;
|
|
10
15
|
const handleOnSelect = useCallback(() => {
|
|
11
16
|
onSelect(item.value);
|
|
12
17
|
}, [item.value, onSelect]);
|
|
13
18
|
|
|
14
19
|
return (
|
|
15
|
-
<View
|
|
20
|
+
<View
|
|
21
|
+
style={isSetupGeneratePasscode ? styles.WrapnotPadding : styles.rowWrap}
|
|
22
|
+
>
|
|
16
23
|
<View style={styles.rowContent}>
|
|
17
24
|
<TouchableOpacity
|
|
18
25
|
style={styles.row}
|
|
@@ -7,6 +7,7 @@ import { Colors } from '../../../configs';
|
|
|
7
7
|
import { REPEAT_ITEMS } from '../constant';
|
|
8
8
|
import styles from '../styles/AccessScheduleDetailStyles';
|
|
9
9
|
import { TESTID } from '../../../configs/Constants';
|
|
10
|
+
import moment from 'moment';
|
|
10
11
|
|
|
11
12
|
const RecurringDetail = ({
|
|
12
13
|
onShowSetDateTime,
|
|
@@ -73,7 +74,7 @@ const RecurringDetail = ({
|
|
|
73
74
|
testID={TESTID.RECURRING_TEXT_BUTTON}
|
|
74
75
|
>
|
|
75
76
|
<Text type="Body" color={Colors.Orange} style={styles.value}>
|
|
76
|
-
{recurringTimeStart.format('hh:mm A')}
|
|
77
|
+
{moment(recurringTimeStart).format('hh:mm A')}
|
|
77
78
|
</Text>
|
|
78
79
|
</TouchableOpacity>
|
|
79
80
|
<Text type="Body" color={Colors.Gray8} style={styles.title}>
|
|
@@ -84,7 +85,7 @@ const RecurringDetail = ({
|
|
|
84
85
|
testID={TESTID.RECURRING_TEXT_BUTTON}
|
|
85
86
|
>
|
|
86
87
|
<Text type="Body" color={Colors.Orange} style={styles.value}>
|
|
87
|
-
{recurringTimeEnd.format('hh:mm A')}
|
|
88
|
+
{moment(recurringTimeEnd).format('hh:mm A')}
|
|
88
89
|
</Text>
|
|
89
90
|
</TouchableOpacity>
|
|
90
91
|
<Text type="Body" color={Colors.Gray8} style={styles.title}>
|
|
@@ -5,6 +5,7 @@ import Text from '../../../commons/Text';
|
|
|
5
5
|
import { Colors } from '../../../configs';
|
|
6
6
|
import styles from '../styles/AccessScheduleDetailStyles';
|
|
7
7
|
import { TESTID } from '../../../configs/Constants';
|
|
8
|
+
import moment from 'moment';
|
|
8
9
|
|
|
9
10
|
const TemporaryDetail = ({
|
|
10
11
|
onShowSetDateTime,
|
|
@@ -32,7 +33,7 @@ const TemporaryDetail = ({
|
|
|
32
33
|
testID={TESTID.TEMPORARY_TEXT_BUTTON}
|
|
33
34
|
>
|
|
34
35
|
<Text type="Body" color={Colors.Orange} style={styles.value}>
|
|
35
|
-
{temporaryTimeStart.format('hh:mm A DD/MM/YYYY')}
|
|
36
|
+
{moment(temporaryTimeStart).format('hh:mm A DD/MM/YYYY')}
|
|
36
37
|
</Text>
|
|
37
38
|
</TouchableOpacity>
|
|
38
39
|
<Text type="Body" color={Colors.Gray8} style={styles.title}>
|
|
@@ -43,7 +44,7 @@ const TemporaryDetail = ({
|
|
|
43
44
|
testID={TESTID.TEMPORARY_TEXT_BUTTON}
|
|
44
45
|
>
|
|
45
46
|
<Text type="Body" color={Colors.Orange} style={styles.value}>
|
|
46
|
-
{temporaryTimeEnd.format('hh:mm A DD/MM/YYYY')}
|
|
47
|
+
{moment(temporaryTimeEnd).format('hh:mm A DD/MM/YYYY')}
|
|
47
48
|
</Text>
|
|
48
49
|
</TouchableOpacity>
|
|
49
50
|
</View>
|
|
@@ -191,6 +191,7 @@ describe('test NotificationItem', () => {
|
|
|
191
191
|
SENSOR_TYPE.SMOKE,
|
|
192
192
|
SENSOR_TYPE.FIRE,
|
|
193
193
|
SENSOR_TYPE.SOS,
|
|
194
|
+
SENSOR_TYPE.FILTER_WATER,
|
|
194
195
|
];
|
|
195
196
|
for (const sensorType of listSensorType2) {
|
|
196
197
|
test(`create ItemNotification NOTIFY_INDICATOR sensor_type ${sensorType}`, () => {
|
|
@@ -352,6 +352,22 @@ const NotificationItem = memo(({ item }) => {
|
|
|
352
352
|
}),
|
|
353
353
|
iconContent: <Image source={Images.logo} style={styles.logo} />,
|
|
354
354
|
};
|
|
355
|
+
case SENSOR_TYPE.FILTER_WATER:
|
|
356
|
+
return {
|
|
357
|
+
content: customColorText(
|
|
358
|
+
t('text_notification_content_replace_water_filter'),
|
|
359
|
+
arrParams
|
|
360
|
+
),
|
|
361
|
+
redirect: () =>
|
|
362
|
+
navigation.navigate(Routes.UnitStack, {
|
|
363
|
+
screen: Routes.DeviceDetail,
|
|
364
|
+
params: {
|
|
365
|
+
unitId,
|
|
366
|
+
sensorId,
|
|
367
|
+
},
|
|
368
|
+
}),
|
|
369
|
+
iconContent: <Image source={Images.logo} style={styles.logo} />,
|
|
370
|
+
};
|
|
355
371
|
default:
|
|
356
372
|
return {
|
|
357
373
|
content: customColorText(
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import renderer, { act } from 'react-test-renderer';
|
|
3
|
+
import GroupButtonByType from '../components/GroupButtonByType/GroupButtonByType';
|
|
4
|
+
import { SCProvider } from '../../../context';
|
|
5
|
+
import { mockSCStore } from '../../../context/mockStore';
|
|
6
|
+
import WrapHeaderScrollable from '../../../commons/Sharing/WrapHeaderScrollable';
|
|
7
|
+
|
|
8
|
+
const wrapComponent = (route) => (
|
|
9
|
+
<SCProvider initState={mockSCStore({})}>
|
|
10
|
+
<GroupButtonByType route={route} />
|
|
11
|
+
</SCProvider>
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
const mockNavigate = jest.fn();
|
|
15
|
+
const mockSetState = jest.fn();
|
|
16
|
+
jest.mock('@react-navigation/native', () => {
|
|
17
|
+
return {
|
|
18
|
+
...jest.requireActual('@react-navigation/native'),
|
|
19
|
+
useNavigation: () => ({
|
|
20
|
+
navigate: mockNavigate,
|
|
21
|
+
}),
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
jest.mock('react', () => {
|
|
25
|
+
return {
|
|
26
|
+
...jest.requireActual('react'),
|
|
27
|
+
memo: (x) => x,
|
|
28
|
+
useState: jest.fn((init) => [init, mockSetState]),
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
describe('Test GroupButtonByType', () => {
|
|
32
|
+
let tree;
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
mockNavigate.mockClear();
|
|
35
|
+
});
|
|
36
|
+
afterEach(() => {
|
|
37
|
+
mockSetState.mockClear();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('render GroupButtonByType', () => {
|
|
41
|
+
const route = {
|
|
42
|
+
params: {
|
|
43
|
+
device_type: { id: 1, name: '', icon: '' },
|
|
44
|
+
brand: { id: 1, name: '' },
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
act(() => {
|
|
48
|
+
tree = renderer.create(wrapComponent(route));
|
|
49
|
+
});
|
|
50
|
+
const instance = tree.root;
|
|
51
|
+
const wrapHeaderScrollable = instance.findAllByType(WrapHeaderScrollable);
|
|
52
|
+
expect(wrapHeaderScrollable).toHaveLength(1);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ScrollView } from 'react-native';
|
|
3
|
+
import renderer, { act } from 'react-test-renderer';
|
|
4
|
+
import SelectBrand from '../components/SelectBrand';
|
|
5
|
+
import { SCProvider } from '../../../context';
|
|
6
|
+
import { mockSCStore } from '../../../context/mockStore';
|
|
7
|
+
import { RowItem } from '../../../commons/RowItem';
|
|
8
|
+
|
|
9
|
+
const wrapComponent = (route) => (
|
|
10
|
+
<SCProvider initState={mockSCStore({})}>
|
|
11
|
+
<SelectBrand route={route} />
|
|
12
|
+
</SCProvider>
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
const mockNavigate = jest.fn();
|
|
16
|
+
const mockSetState = jest.fn();
|
|
17
|
+
jest.mock('@react-navigation/native', () => {
|
|
18
|
+
return {
|
|
19
|
+
...jest.requireActual('@react-navigation/native'),
|
|
20
|
+
useNavigation: () => ({
|
|
21
|
+
navigate: mockNavigate,
|
|
22
|
+
}),
|
|
23
|
+
};
|
|
24
|
+
});
|
|
25
|
+
jest.mock('react', () => {
|
|
26
|
+
return {
|
|
27
|
+
...jest.requireActual('react'),
|
|
28
|
+
memo: (x) => x,
|
|
29
|
+
useState: jest.fn((init) => [init, mockSetState]),
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
describe('Test SelectBrand', () => {
|
|
33
|
+
let tree;
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
mockNavigate.mockClear();
|
|
36
|
+
});
|
|
37
|
+
afterEach(() => {
|
|
38
|
+
mockSetState.mockClear();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('render SelectBrand', () => {
|
|
42
|
+
const route = {
|
|
43
|
+
params: {
|
|
44
|
+
device_type: { id: 1, name: '' },
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
act(() => {
|
|
48
|
+
tree = renderer.create(wrapComponent(route));
|
|
49
|
+
});
|
|
50
|
+
const instance = tree.root;
|
|
51
|
+
const scrollView = instance.findAllByType(ScrollView);
|
|
52
|
+
expect(scrollView).toHaveLength(1);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('Row SmartIr onPress', () => {
|
|
56
|
+
const route = {
|
|
57
|
+
params: {
|
|
58
|
+
device_type: { id: 1, name: '' },
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
act(() => {
|
|
62
|
+
tree = renderer.create(wrapComponent(route));
|
|
63
|
+
});
|
|
64
|
+
const instance = tree.root;
|
|
65
|
+
const scrollView = instance.findAllByType(ScrollView);
|
|
66
|
+
expect(scrollView).toHaveLength(1);
|
|
67
|
+
const rowItem = instance.findAllByType(RowItem);
|
|
68
|
+
expect(rowItem).toHaveLength(3);
|
|
69
|
+
act(() => {
|
|
70
|
+
rowItem[0].props.onPress();
|
|
71
|
+
});
|
|
72
|
+
expect(mockNavigate).toHaveBeenCalled();
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ScrollView, TouchableOpacity } from 'react-native';
|
|
3
|
+
import renderer, { act } from 'react-test-renderer';
|
|
4
|
+
import SelectDeviceType from '../components/SelectDeviceType';
|
|
5
|
+
import { SCProvider } from '../../../context';
|
|
6
|
+
import { mockSCStore } from '../../../context/mockStore';
|
|
7
|
+
|
|
8
|
+
const wrapComponent = () => (
|
|
9
|
+
<SCProvider initState={mockSCStore({})}>
|
|
10
|
+
<SelectDeviceType />
|
|
11
|
+
</SCProvider>
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
const mockNavigate = jest.fn();
|
|
15
|
+
const mockSetState = jest.fn();
|
|
16
|
+
jest.mock('@react-navigation/native', () => {
|
|
17
|
+
return {
|
|
18
|
+
...jest.requireActual('@react-navigation/native'),
|
|
19
|
+
useNavigation: () => ({
|
|
20
|
+
navigate: mockNavigate,
|
|
21
|
+
}),
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
jest.mock('react', () => {
|
|
25
|
+
return {
|
|
26
|
+
...jest.requireActual('react'),
|
|
27
|
+
memo: (x) => x,
|
|
28
|
+
useState: jest.fn((init) => [init, mockSetState]),
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
describe('Test SelectDeviceType', () => {
|
|
32
|
+
let tree;
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
mockNavigate.mockClear();
|
|
35
|
+
});
|
|
36
|
+
afterEach(() => {
|
|
37
|
+
mockSetState.mockClear();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('render SelectDeviceType', () => {
|
|
41
|
+
act(() => {
|
|
42
|
+
tree = renderer.create(wrapComponent());
|
|
43
|
+
});
|
|
44
|
+
const instance = tree.root;
|
|
45
|
+
const scrollView = instance.findAllByType(ScrollView);
|
|
46
|
+
expect(scrollView).toHaveLength(1);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('itemDevice SelectDeviceType onPress', () => {
|
|
50
|
+
act(() => {
|
|
51
|
+
tree = renderer.create(wrapComponent());
|
|
52
|
+
});
|
|
53
|
+
const instance = tree.root;
|
|
54
|
+
const scrollView = instance.findAllByType(ScrollView);
|
|
55
|
+
expect(scrollView).toHaveLength(1);
|
|
56
|
+
const touchableOpacity = instance.findAllByType(TouchableOpacity);
|
|
57
|
+
expect(touchableOpacity).toHaveLength(7);
|
|
58
|
+
const itemDevice = touchableOpacity[1];
|
|
59
|
+
act(() => {
|
|
60
|
+
itemDevice.props.onPress();
|
|
61
|
+
});
|
|
62
|
+
expect(mockNavigate).toHaveBeenCalled();
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import React, { memo, useCallback, useState, useMemo } from 'react';
|
|
2
|
+
import { View, TouchableOpacity, Alert } from 'react-native';
|
|
3
|
+
import WrapHeaderScrollable from '../../../../commons/Sharing/WrapHeaderScrollable';
|
|
4
|
+
import { useTranslations } from '../../../../hooks/Common/useTranslations';
|
|
5
|
+
import SmartTiviActionTemplate from '../../../../commons/ActionGroup/SmartTiviActionTemplate/SmartTiviActionTemplate';
|
|
6
|
+
import Text from '../../../../commons/Text';
|
|
7
|
+
|
|
8
|
+
import { IconOutline } from '@ant-design/icons-react-native';
|
|
9
|
+
import { Colors } from '../../../../configs';
|
|
10
|
+
|
|
11
|
+
import styles from './GroupButtonByTypeStyles';
|
|
12
|
+
|
|
13
|
+
const GroupButtonByType = memo(({ route }) => {
|
|
14
|
+
const t = useTranslations();
|
|
15
|
+
const [groupButton] = useState({ id: 1, template: 'tivi' });
|
|
16
|
+
const GroupButtonTemplate = useCallback(() => {
|
|
17
|
+
switch (groupButton?.template) {
|
|
18
|
+
case 'tivi':
|
|
19
|
+
return <SmartTiviActionTemplate />;
|
|
20
|
+
default:
|
|
21
|
+
return <></>;
|
|
22
|
+
}
|
|
23
|
+
}, [groupButton]);
|
|
24
|
+
const rightComponent = useMemo(
|
|
25
|
+
() => (
|
|
26
|
+
<View style={styles.rightComponent}>
|
|
27
|
+
<>
|
|
28
|
+
<TouchableOpacity
|
|
29
|
+
onPress={() => Alert.alert(t('feature_under_development'))}
|
|
30
|
+
style={[styles.headerButton]}
|
|
31
|
+
>
|
|
32
|
+
<IconOutline name={'reload'} size={27} color={Colors.Black} />
|
|
33
|
+
</TouchableOpacity>
|
|
34
|
+
<TouchableOpacity
|
|
35
|
+
onPress={() => Alert.alert(t('feature_under_development'))}
|
|
36
|
+
style={[styles.headerButton]}
|
|
37
|
+
>
|
|
38
|
+
<IconOutline name={'more'} size={27} color={Colors.Black} />
|
|
39
|
+
</TouchableOpacity>
|
|
40
|
+
</>
|
|
41
|
+
)
|
|
42
|
+
</View>
|
|
43
|
+
),
|
|
44
|
+
[t]
|
|
45
|
+
);
|
|
46
|
+
const AlertBottom = useCallback(() => {
|
|
47
|
+
return (
|
|
48
|
+
<View style={styles.alertBottom}>
|
|
49
|
+
<View style={styles.alertContent}>
|
|
50
|
+
<Text>{t('make_sure_3_button_available')}</Text>
|
|
51
|
+
<View style={styles.alertButtons}>
|
|
52
|
+
<TouchableOpacity
|
|
53
|
+
style={styles.selectButton}
|
|
54
|
+
onPress={() => Alert.alert(t('feature_under_development'))}
|
|
55
|
+
>
|
|
56
|
+
<Text color={Colors.White}>{t('select_this_one')}</Text>
|
|
57
|
+
</TouchableOpacity>
|
|
58
|
+
<TouchableOpacity
|
|
59
|
+
style={styles.nextButton}
|
|
60
|
+
onPress={() => Alert.alert(t('feature_under_development'))}
|
|
61
|
+
>
|
|
62
|
+
<Text color={Colors.Gray8}>{t('next_one')}</Text>
|
|
63
|
+
</TouchableOpacity>
|
|
64
|
+
</View>
|
|
65
|
+
</View>
|
|
66
|
+
</View>
|
|
67
|
+
);
|
|
68
|
+
}, [t]);
|
|
69
|
+
return (
|
|
70
|
+
<View style={styles.container}>
|
|
71
|
+
<WrapHeaderScrollable
|
|
72
|
+
title={t('Tivi')}
|
|
73
|
+
headerAniStyle={styles.header}
|
|
74
|
+
styleScrollView={styles.scrollView}
|
|
75
|
+
rightComponent={rightComponent}
|
|
76
|
+
>
|
|
77
|
+
<View style={styles.wrapItem}>
|
|
78
|
+
<GroupButtonTemplate />
|
|
79
|
+
</View>
|
|
80
|
+
</WrapHeaderScrollable>
|
|
81
|
+
<AlertBottom />
|
|
82
|
+
</View>
|
|
83
|
+
);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
export default GroupButtonByType;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { StyleSheet } from 'react-native';
|
|
2
|
+
import { Colors, Constants } from '../../../../configs';
|
|
3
|
+
import { getStatusBarHeight } from 'react-native-iphone-x-helper';
|
|
4
|
+
export const heightHeader = 44 + 44 + getStatusBarHeight() + 10;
|
|
5
|
+
|
|
6
|
+
const flexCenter = {
|
|
7
|
+
justifyContent: 'center',
|
|
8
|
+
alignItems: 'center',
|
|
9
|
+
};
|
|
10
|
+
const styleButton = {
|
|
11
|
+
width: Constants.width / 2 - 32,
|
|
12
|
+
paddingVertical: 8,
|
|
13
|
+
paddingHorizontal: 32,
|
|
14
|
+
borderRadius: 30,
|
|
15
|
+
marginHorizontal: 8,
|
|
16
|
+
...flexCenter,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default StyleSheet.create({
|
|
20
|
+
container: {
|
|
21
|
+
flex: 1,
|
|
22
|
+
},
|
|
23
|
+
header: {
|
|
24
|
+
borderBottomWidth: 0,
|
|
25
|
+
},
|
|
26
|
+
scrollView: {
|
|
27
|
+
backgroundColor: Colors.White,
|
|
28
|
+
position: 'relative',
|
|
29
|
+
},
|
|
30
|
+
wrapItem: {
|
|
31
|
+
flex: 1,
|
|
32
|
+
},
|
|
33
|
+
rightComponent: {
|
|
34
|
+
flexDirection: 'row',
|
|
35
|
+
paddingRight: 8,
|
|
36
|
+
},
|
|
37
|
+
headerButton: {
|
|
38
|
+
paddingHorizontal: 10,
|
|
39
|
+
},
|
|
40
|
+
alertBottom: {
|
|
41
|
+
backgroundColor: Colors.White,
|
|
42
|
+
height: 120,
|
|
43
|
+
left: 0,
|
|
44
|
+
right: 0,
|
|
45
|
+
bottom: 0,
|
|
46
|
+
borderRadius: 10,
|
|
47
|
+
},
|
|
48
|
+
alertContent: {
|
|
49
|
+
flex: 1,
|
|
50
|
+
backgroundColor: Colors.Blue13,
|
|
51
|
+
...flexCenter,
|
|
52
|
+
borderRadius: 10,
|
|
53
|
+
shadowColor: Colors.Shadow,
|
|
54
|
+
shadowOffset: {
|
|
55
|
+
width: 0,
|
|
56
|
+
height: 20,
|
|
57
|
+
},
|
|
58
|
+
shadowOpacity: 0.25,
|
|
59
|
+
shadowRadius: 4.84,
|
|
60
|
+
elevation: 5,
|
|
61
|
+
},
|
|
62
|
+
alertButtons: {
|
|
63
|
+
marginTop: 16,
|
|
64
|
+
flexDirection: 'row',
|
|
65
|
+
},
|
|
66
|
+
selectButton: {
|
|
67
|
+
backgroundColor: Colors.Primary,
|
|
68
|
+
...styleButton,
|
|
69
|
+
},
|
|
70
|
+
nextButton: {
|
|
71
|
+
backgroundColor: Colors.Gray1,
|
|
72
|
+
borderColor: Colors.Gray5,
|
|
73
|
+
borderWidth: 1,
|
|
74
|
+
...styleButton,
|
|
75
|
+
},
|
|
76
|
+
});
|