@eohjsc/react-native-smart-city 0.2.45 → 0.2.49
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/README.md +9 -0
- package/index.js +6 -0
- package/package.json +23 -3
- package/src/Images/Common/logo.png +0 -0
- package/src/Images/Common/logo@2x.png +0 -0
- package/src/Images/Common/logo@3x.png +0 -0
- package/src/commons/ActionTemplate/index.js +40 -25
- package/src/commons/Automate/ItemAutomate.js +2 -2
- package/src/commons/Dashboard/MyPinnedSharedUnit/index.js +82 -0
- package/src/commons/Dashboard/MyPinnedSharedUnit/styles.js +78 -0
- package/src/commons/Dashboard/MyUnit/__test__/MyUnit.test.js +60 -0
- package/src/commons/Dashboard/MyUnit/index.js +111 -0
- package/src/commons/Dashboard/MyUnit/styles.js +61 -0
- package/src/commons/Device/ConnectedViewHeader.js +4 -1
- package/src/commons/Form/TextInput.js +1 -1
- package/src/commons/MediaPlayer/index.js +6 -1
- package/src/commons/OneTapTemplate/OptionsDropdownActionTemplate.js +3 -3
- package/src/{screens/Unit/components → commons}/SearchLocation/RowLocation.js +2 -2
- package/src/{screens/Unit/components → commons}/SearchLocation/RowLocationStyles.js +1 -1
- package/src/{screens/Unit/components → commons}/SearchLocation/SearchBarLocationStyles.js +1 -1
- package/src/{screens/Unit/components → commons}/SearchLocation/__test__/RowLocation.test.js +2 -2
- package/src/{screens/Unit/components → commons}/SearchLocation/index.js +2 -2
- package/src/commons/SubUnit/OneTap/ItemOneTap.js +3 -1
- package/src/commons/SubUnit/OneTap/__test__/SubUnitAutomate.test.js +2 -0
- package/src/commons/SubUnit/ShortDetail.js +1 -1
- package/src/commons/Unit/SharedUnit.js +2 -2
- package/src/configs/API.js +11 -4
- package/src/configs/Constants.js +19 -6
- package/src/configs/Images.js +1 -0
- package/src/iot/RemoteControl/Bluetooth.js +10 -1
- package/src/iot/RemoteControl/Internet.js +0 -2
- package/src/navigations/AddDeviceStack.js +5 -0
- package/src/navigations/AddUnitStack.js +2 -0
- package/src/navigations/UnitStack.js +8 -0
- package/src/screens/ActivityLog/FilterPopup.js +24 -17
- package/src/screens/ActivityLog/ItemLog.js +26 -22
- package/src/screens/ActivityLog/__test__/FilterPopup.test.js +1 -0
- package/src/screens/ActivityLog/__test__/ItemLog.test.js +0 -20
- package/src/screens/ActivityLog/__test__/index.test.js +3 -0
- package/src/screens/ActivityLog/hooks/__test__/index.test.js +8 -0
- package/src/screens/ActivityLog/hooks/index.js +5 -9
- package/src/screens/ActivityLog/index.js +4 -4
- package/src/screens/ActivityLog/styles/filterPopupStyles.js +3 -0
- package/src/screens/AddCommon/SelectSubUnit.js +10 -1
- package/src/screens/AddCommon/SelectUnit.js +11 -0
- package/src/screens/AddLocationMaps/index.js +124 -74
- package/src/screens/AddLocationMaps/indexStyle.js +58 -0
- package/src/screens/AddNewAction/SelectAction.js +59 -4
- package/src/screens/AddNewAction/SelectSensorDevices.js +27 -5
- package/src/screens/AddNewAction/SetupSensor.js +1 -6
- package/src/screens/AddNewAction/__test__/SelectAction.test.js +6 -4
- package/src/screens/AddNewAutoSmart/__test__/AddNewAutoSmart.test.js +11 -1
- package/src/screens/AddNewAutoSmart/index.js +24 -13
- package/src/screens/AddNewDevice/ConnectingDevices.js +3 -0
- package/src/screens/AddNewGateway/ConnectingGatewayStyles.js +10 -1
- package/src/screens/AddNewOneTap/__test__/AddNewOneTap.test.js +9 -1
- package/src/screens/AddNewOneTap/index.js +11 -6
- package/src/screens/Automate/MultiUnits.js +14 -53
- package/src/screens/Automate/__test__/MultiUnits.test.js +5 -246
- package/src/screens/Automate/__test__/index.test.js +1 -0
- package/src/screens/Automate/index.js +1 -0
- package/src/screens/Device/__test__/detail.test.js +14 -0
- package/src/screens/Device/components/DetailHistoryChart.js +63 -0
- package/src/screens/Device/components/EmergencyCountdown.js +29 -0
- package/src/screens/Device/components/SensorConnectStatusViewHeader.js +57 -0
- package/src/screens/Device/components/SensorDisplayItem.js +127 -0
- package/src/screens/Device/detail.js +81 -294
- package/src/screens/Device/hooks/useDisconnectedDevice.js +63 -0
- package/src/screens/Device/styles.js +0 -10
- package/src/screens/GuestInfo/components/RecurringDetail.js +2 -2
- package/src/screens/Notification/components/NotificationItem.js +31 -14
- package/src/screens/Notification/styles/NotificationItemStyles.js +5 -0
- package/src/screens/ScanChipQR/__test__/ScanChipQR.test.js +12 -3
- package/src/screens/ScanChipQR/components/QRScan/__test__/QRScan.test.js +11 -2
- package/src/screens/ScanSensorQR/__test__/ScanSensorQR.test.js +12 -3
- package/src/screens/ScriptDetail/__test__/index.test.js +83 -3
- package/src/screens/ScriptDetail/hooks/index.js +4 -0
- package/src/screens/ScriptDetail/index.js +65 -4
- package/src/screens/SetSchedule/__test__/SelectWeekday.test.js +2 -2
- package/src/screens/SetSchedule/__test__/index.test.js +8 -0
- package/src/screens/SetSchedule/components/SelectWeekday.js +13 -7
- package/src/screens/SetSchedule/index.js +28 -6
- package/src/screens/Sharing/Components/__test__/TitleCheckBox.test.js +38 -0
- package/src/screens/SubUnit/AddSubUnit.js +113 -29
- package/src/screens/SubUnit/AddSubUnitStyles.js +10 -0
- package/src/screens/SubUnit/__test__/AddSubUnit.test.js +1 -0
- package/src/screens/TDSGuide/index.js +15 -19
- package/src/screens/Unit/MoreMenu.js +6 -1
- package/src/screens/Unit/SelectLocation.js +2 -3
- package/src/screens/Unit/SmartAccount.js +141 -0
- package/src/screens/Unit/SmartAccountItem.js +51 -0
- package/src/screens/Unit/SmartAccountStyles.js +46 -0
- package/src/screens/Unit/__test__/SmartAccount.test.js +58 -0
- package/src/screens/Unit/hook/useStateAlertRemove.js +36 -0
- package/src/utils/I18n/translations/en.json +26 -2
- package/src/utils/I18n/translations/vi.json +38 -14
- package/src/utils/Route/index.js +4 -0
- package/src/utils/Validation.js +3 -1
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import NetInfo from '@react-native-community/netinfo';
|
|
2
|
+
import { useCallback, useEffect } from 'react';
|
|
3
|
+
import { Alert, Linking, Platform } from 'react-native';
|
|
4
|
+
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
5
|
+
import {
|
|
6
|
+
enableBluetoothForAndroid,
|
|
7
|
+
isBluetoothEnabled,
|
|
8
|
+
} from '../../../iot/RemoteControl/Bluetooth';
|
|
9
|
+
|
|
10
|
+
export const useDisconnectedDevice = (isConnected, sensorName) => {
|
|
11
|
+
const t = useTranslations();
|
|
12
|
+
const openBluetoothIOS = () => {
|
|
13
|
+
Linking.openURL('App-Prefs:Bluetooth');
|
|
14
|
+
};
|
|
15
|
+
const actions =
|
|
16
|
+
Platform.OS === 'ios'
|
|
17
|
+
? [
|
|
18
|
+
{
|
|
19
|
+
text: 'Skip',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
text: 'Open',
|
|
23
|
+
onPress: () => openBluetoothIOS(),
|
|
24
|
+
},
|
|
25
|
+
]
|
|
26
|
+
: [
|
|
27
|
+
{
|
|
28
|
+
text: 'Skip',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
text: 'Open',
|
|
32
|
+
onPress: () => enableBluetoothForAndroid(),
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
const checkNetWorkConnect = useCallback(async () => {
|
|
36
|
+
const netState = await NetInfo.fetch();
|
|
37
|
+
if (!isConnected || !netState.isConnected) {
|
|
38
|
+
const isBtEnabled = await isBluetoothEnabled();
|
|
39
|
+
if (isBtEnabled) {
|
|
40
|
+
Alert.alert(
|
|
41
|
+
'',
|
|
42
|
+
t(
|
|
43
|
+
'your_internet_is_disconnected_change_to_control_via_bluetooth_connection',
|
|
44
|
+
{ name: sensorName }
|
|
45
|
+
)
|
|
46
|
+
);
|
|
47
|
+
} else {
|
|
48
|
+
Alert.alert(
|
|
49
|
+
'',
|
|
50
|
+
t(
|
|
51
|
+
'your_connection_to_the_server_was_disconnected_please_open_the_bluetooth_to_continue'
|
|
52
|
+
),
|
|
53
|
+
actions
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
58
|
+
}, [isConnected]);
|
|
59
|
+
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
checkNetWorkConnect();
|
|
62
|
+
}, [checkNetWorkConnect]);
|
|
63
|
+
};
|
|
@@ -24,9 +24,6 @@ export default StyleSheet.create({
|
|
|
24
24
|
paddingHorizontal: 16,
|
|
25
25
|
paddingTop: 16,
|
|
26
26
|
},
|
|
27
|
-
chartStyle: {
|
|
28
|
-
paddingHorizontal: 16,
|
|
29
|
-
},
|
|
30
27
|
bottomButtonEmergencyResolve: {
|
|
31
28
|
borderTopWidth: 1,
|
|
32
29
|
borderColor: Colors.Gray4,
|
|
@@ -37,13 +34,6 @@ export default StyleSheet.create({
|
|
|
37
34
|
marginHorizontal: 16,
|
|
38
35
|
marginBottom: 32,
|
|
39
36
|
},
|
|
40
|
-
countDown: {
|
|
41
|
-
marginBottom: 16,
|
|
42
|
-
marginTop: 8,
|
|
43
|
-
},
|
|
44
|
-
messageCountDown: {
|
|
45
|
-
marginBottom: 8,
|
|
46
|
-
},
|
|
47
37
|
locationName: {
|
|
48
38
|
flex: 1,
|
|
49
39
|
alignItems: 'center',
|
|
@@ -73,7 +73,7 @@ const RecurringDetail = ({
|
|
|
73
73
|
testID={TESTID.RECURRING_TEXT_BUTTON}
|
|
74
74
|
>
|
|
75
75
|
<Text type="Body" color={Colors.Orange} style={styles.value}>
|
|
76
|
-
{recurringTimeStart.format('
|
|
76
|
+
{recurringTimeStart.format('hh:mm A')}
|
|
77
77
|
</Text>
|
|
78
78
|
</TouchableOpacity>
|
|
79
79
|
<Text type="Body" color={Colors.Gray8} style={styles.title}>
|
|
@@ -84,7 +84,7 @@ const RecurringDetail = ({
|
|
|
84
84
|
testID={TESTID.RECURRING_TEXT_BUTTON}
|
|
85
85
|
>
|
|
86
86
|
<Text type="Body" color={Colors.Orange} style={styles.value}>
|
|
87
|
-
{recurringTimeEnd.format('
|
|
87
|
+
{recurringTimeEnd.format('hh:mm A')}
|
|
88
88
|
</Text>
|
|
89
89
|
</TouchableOpacity>
|
|
90
90
|
<Text type="Body" color={Colors.Gray8} style={styles.title}>
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React, { memo, useCallback, useMemo, useState } from 'react';
|
|
2
|
-
import { View, TouchableOpacity } from 'react-native';
|
|
2
|
+
import { View, TouchableOpacity, Image } from 'react-native';
|
|
3
3
|
import moment from 'moment';
|
|
4
4
|
import { useNavigation } from '@react-navigation/native';
|
|
5
5
|
|
|
6
6
|
import styles from '../styles/NotificationItemStyles';
|
|
7
7
|
import Text from '../../../commons/Text';
|
|
8
|
-
import { Colors, API } from '../../../configs';
|
|
8
|
+
import { Colors, API, Images } from '../../../configs';
|
|
9
9
|
import IconComponent from '../../../commons/IconComponent';
|
|
10
10
|
import { NOTIFICATION_TYPES } from '../../../configs/Constants';
|
|
11
11
|
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
@@ -18,14 +18,18 @@ const NotificationItem = memo(({ item }) => {
|
|
|
18
18
|
const { id, icon, created_at, is_read, params, content_code } = item;
|
|
19
19
|
const [isRead, setIsRead] = useState(is_read);
|
|
20
20
|
const timeFormat = moment(created_at).format('LT DD/MM/YYYY');
|
|
21
|
+
const regex = useMemo(() => {
|
|
22
|
+
return /\B'|'\B/g;
|
|
23
|
+
}, []);
|
|
24
|
+
|
|
21
25
|
let arrParams = useMemo(() => {
|
|
22
26
|
const values = [];
|
|
23
|
-
const paramsJSON = JSON.parse(params.replace(
|
|
27
|
+
const paramsJSON = JSON.parse(params.replace(regex, '"'));
|
|
24
28
|
Object.entries(paramsJSON).forEach(([key, value]) => {
|
|
25
29
|
values.push(value);
|
|
26
30
|
});
|
|
27
31
|
return values;
|
|
28
|
-
}, [params]);
|
|
32
|
+
}, [params, regex]);
|
|
29
33
|
|
|
30
34
|
const customColorText = (text, params) => {
|
|
31
35
|
return text.split('**').map((str, i) =>
|
|
@@ -42,7 +46,7 @@ const NotificationItem = memo(({ item }) => {
|
|
|
42
46
|
};
|
|
43
47
|
|
|
44
48
|
const renderItem = useCallback(() => {
|
|
45
|
-
const paramsJSON = JSON.parse(params.replace(
|
|
49
|
+
const paramsJSON = JSON.parse(params.replace(regex, '"'));
|
|
46
50
|
const booking_id = paramsJSON.booking_id && paramsJSON.booking_id;
|
|
47
51
|
switch (content_code) {
|
|
48
52
|
case NOTIFICATION_TYPES.NOTIFY_INVITE_MEMBER:
|
|
@@ -60,7 +64,12 @@ const NotificationItem = memo(({ item }) => {
|
|
|
60
64
|
},
|
|
61
65
|
});
|
|
62
66
|
},
|
|
63
|
-
|
|
67
|
+
iconContent: (
|
|
68
|
+
<IconComponent
|
|
69
|
+
icon_outlined={'usergroup-add'}
|
|
70
|
+
style={styles.iconInviteMember}
|
|
71
|
+
/>
|
|
72
|
+
),
|
|
64
73
|
};
|
|
65
74
|
case NOTIFICATION_TYPES.REMIND_TO_MAKE_PAYMENT:
|
|
66
75
|
return {
|
|
@@ -211,10 +220,19 @@ const NotificationItem = memo(({ item }) => {
|
|
|
211
220
|
params: { id: booking_id },
|
|
212
221
|
}),
|
|
213
222
|
};
|
|
223
|
+
case NOTIFICATION_TYPES.REMINDER:
|
|
224
|
+
return {
|
|
225
|
+
content: customColorText(
|
|
226
|
+
t('text_notification_content_update_reminder'),
|
|
227
|
+
arrParams
|
|
228
|
+
),
|
|
229
|
+
redirect: () => navigation.navigate(Routes.PersonalHealthStack),
|
|
230
|
+
iconContent: <Image source={Images.logo} style={styles.logo} />,
|
|
231
|
+
};
|
|
214
232
|
}
|
|
215
|
-
}, [arrParams, content_code, navigation, params, t]);
|
|
233
|
+
}, [arrParams, content_code, navigation, params, regex, t]);
|
|
216
234
|
|
|
217
|
-
const { content, redirect,
|
|
235
|
+
const { content, redirect, iconContent } = renderItem() || {};
|
|
218
236
|
|
|
219
237
|
const onItemPress = useCallback(() => {
|
|
220
238
|
if (!isRead) {
|
|
@@ -224,16 +242,15 @@ const NotificationItem = memo(({ item }) => {
|
|
|
224
242
|
setIsRead(true);
|
|
225
243
|
}, [id, isRead, redirect]);
|
|
226
244
|
|
|
245
|
+
if (!content) {
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
|
|
227
249
|
return (
|
|
228
250
|
<TouchableOpacity onPress={onItemPress}>
|
|
229
251
|
<View style={[styles.container, !isRead && styles.backgroundGray]}>
|
|
230
252
|
<View style={styles.wrapIcon}>
|
|
231
|
-
{
|
|
232
|
-
<IconComponent
|
|
233
|
-
icon_outlined={'usergroup-add'}
|
|
234
|
-
style={styles.iconInviteMember}
|
|
235
|
-
/>
|
|
236
|
-
) : (
|
|
253
|
+
{iconContent || (
|
|
237
254
|
<IconComponent iconKit={icon} style={styles.iconNotification} />
|
|
238
255
|
)}
|
|
239
256
|
</View>
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { create, act } from 'react-test-renderer';
|
|
3
3
|
import axios from 'axios';
|
|
4
|
+
|
|
5
|
+
import { SCProvider } from '../../../context';
|
|
6
|
+
import { mockSCStore } from '../../../context/mockStore';
|
|
4
7
|
import ScanChipQR from '..';
|
|
5
8
|
import QRScan from '../components/QRScan';
|
|
6
9
|
import Routes from '../../../utils/Route';
|
|
7
10
|
|
|
11
|
+
const wrapComponent = (route) => (
|
|
12
|
+
<SCProvider initState={mockSCStore({})}>
|
|
13
|
+
<ScanChipQR route={route} />
|
|
14
|
+
</SCProvider>
|
|
15
|
+
);
|
|
16
|
+
|
|
8
17
|
const mockedNavigate = jest.fn();
|
|
9
18
|
const mockedGoBack = jest.fn();
|
|
10
19
|
|
|
@@ -45,7 +54,7 @@ describe('test ScanChipQR', () => {
|
|
|
45
54
|
test('create ScanChipQR', async () => {
|
|
46
55
|
let tree;
|
|
47
56
|
await act(async () => {
|
|
48
|
-
tree = await create(
|
|
57
|
+
tree = await create(wrapComponent(route));
|
|
49
58
|
});
|
|
50
59
|
const instance = tree.root;
|
|
51
60
|
const qrScan = instance.findAllByType(QRScan);
|
|
@@ -69,7 +78,7 @@ describe('test ScanChipQR', () => {
|
|
|
69
78
|
let tree;
|
|
70
79
|
const body = { id: 1, imei: 'IMEI_X', name: 'New Chip' };
|
|
71
80
|
await act(async () => {
|
|
72
|
-
tree = await create(
|
|
81
|
+
tree = await create(wrapComponent(route));
|
|
73
82
|
});
|
|
74
83
|
const instance = tree.root;
|
|
75
84
|
const qrScan = instance.findByType(QRScan);
|
|
@@ -100,7 +109,7 @@ describe('test ScanChipQR', () => {
|
|
|
100
109
|
let tree;
|
|
101
110
|
const body = { id: 1, imei: 'IMEI_X', name: 'New Chip' };
|
|
102
111
|
await act(async () => {
|
|
103
|
-
tree = await create(
|
|
112
|
+
tree = await create(wrapComponent(route));
|
|
104
113
|
});
|
|
105
114
|
const instance = tree.root;
|
|
106
115
|
const qrScan = instance.findByType(QRScan);
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { RNCamera } from 'react-native-camera';
|
|
3
3
|
import { act, create } from 'react-test-renderer';
|
|
4
|
+
|
|
5
|
+
import { SCProvider } from '../../../../../context';
|
|
6
|
+
import { mockSCStore } from '../../../../../context/mockStore';
|
|
4
7
|
import QRScan from '../index';
|
|
5
8
|
|
|
6
9
|
const mockedPop = jest.fn();
|
|
@@ -17,6 +20,12 @@ jest.mock('@react-navigation/native', () => {
|
|
|
17
20
|
};
|
|
18
21
|
});
|
|
19
22
|
|
|
23
|
+
const wrapComponent = (data) => (
|
|
24
|
+
<SCProvider initState={mockSCStore({})}>
|
|
25
|
+
<QRScan {...data} />
|
|
26
|
+
</SCProvider>
|
|
27
|
+
);
|
|
28
|
+
|
|
20
29
|
describe('Test QRScan', () => {
|
|
21
30
|
let data;
|
|
22
31
|
|
|
@@ -32,7 +41,7 @@ describe('Test QRScan', () => {
|
|
|
32
41
|
|
|
33
42
|
test('render QRScan', async () => {
|
|
34
43
|
act(() => {
|
|
35
|
-
tree = create(
|
|
44
|
+
tree = create(wrapComponent(data));
|
|
36
45
|
});
|
|
37
46
|
const instance = tree.root;
|
|
38
47
|
const RNCam = instance.findAllByType(RNCamera);
|
|
@@ -41,7 +50,7 @@ describe('Test QRScan', () => {
|
|
|
41
50
|
|
|
42
51
|
test('onBarCodeRead', async () => {
|
|
43
52
|
act(() => {
|
|
44
|
-
tree = create(
|
|
53
|
+
tree = create(wrapComponent(data));
|
|
45
54
|
});
|
|
46
55
|
const instance = tree.root;
|
|
47
56
|
const RNCam = instance.findByType(RNCamera);
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { create, act } from 'react-test-renderer';
|
|
3
3
|
import axios from 'axios';
|
|
4
|
+
|
|
5
|
+
import { SCProvider } from '../../../context';
|
|
6
|
+
import { mockSCStore } from '../../../context/mockStore';
|
|
4
7
|
import ScanSensorQR from '..';
|
|
5
8
|
import QRScan from '../../ScanChipQR/components/QRScan';
|
|
6
9
|
import API from '../../../configs/API';
|
|
7
10
|
import Routes from '../../../utils/Route';
|
|
8
11
|
|
|
12
|
+
const wrapComponent = (route) => (
|
|
13
|
+
<SCProvider initState={mockSCStore({})}>
|
|
14
|
+
<ScanSensorQR route={route} />
|
|
15
|
+
</SCProvider>
|
|
16
|
+
);
|
|
17
|
+
|
|
9
18
|
const mockedNavigate = jest.fn();
|
|
10
19
|
const mockedGoBack = jest.fn();
|
|
11
20
|
|
|
@@ -46,7 +55,7 @@ describe('test ScanSensorQR', () => {
|
|
|
46
55
|
test('create ScanSensorQR', async () => {
|
|
47
56
|
let tree;
|
|
48
57
|
await act(async () => {
|
|
49
|
-
tree = await create(
|
|
58
|
+
tree = await create(wrapComponent(route));
|
|
50
59
|
});
|
|
51
60
|
const instance = tree.root;
|
|
52
61
|
const qrScan = instance.findAllByType(QRScan);
|
|
@@ -70,7 +79,7 @@ describe('test ScanSensorQR', () => {
|
|
|
70
79
|
let tree;
|
|
71
80
|
const body = { id: 1, imei: 'IMEI_X', name: 'New Chip' };
|
|
72
81
|
await act(async () => {
|
|
73
|
-
tree = await create(
|
|
82
|
+
tree = await create(wrapComponent(route));
|
|
74
83
|
});
|
|
75
84
|
const instance = tree.root;
|
|
76
85
|
const qrScan = instance.findByType(QRScan);
|
|
@@ -103,7 +112,7 @@ describe('test ScanSensorQR', () => {
|
|
|
103
112
|
let tree;
|
|
104
113
|
const body = { id: 1, imei: 'IMEI_X', name: 'New Chip' };
|
|
105
114
|
await act(async () => {
|
|
106
|
-
tree = await create(
|
|
115
|
+
tree = await create(wrapComponent(route));
|
|
107
116
|
});
|
|
108
117
|
const instance = tree.root;
|
|
109
118
|
const qrScan = instance.findByType(QRScan);
|
|
@@ -16,6 +16,7 @@ import { API } from '../../../configs';
|
|
|
16
16
|
import { TouchableOpacity } from 'react-native';
|
|
17
17
|
import Routes from '../../../utils/Route';
|
|
18
18
|
import WrapHeaderScrollable from '../../../commons/Sharing/WrapHeaderScrollable';
|
|
19
|
+
import ItemAutomate from '../../../commons/Automate/ItemAutomate';
|
|
19
20
|
|
|
20
21
|
const wrapComponent = (route) => (
|
|
21
22
|
<SCProvider initState={mockSCStore({})}>
|
|
@@ -271,9 +272,12 @@ describe('Test ScriptDetail', () => {
|
|
|
271
272
|
});
|
|
272
273
|
});
|
|
273
274
|
|
|
274
|
-
const _testGoToActivityLog = (automateType, activityLogType) => {
|
|
275
|
+
const _testGoToActivityLog = (automateType, activityLogType, isMultiUnit) => {
|
|
275
276
|
test('test go to activity log', async () => {
|
|
276
277
|
route.params.type = automateType;
|
|
278
|
+
if (isMultiUnit) {
|
|
279
|
+
route.params.unit.id = undefined;
|
|
280
|
+
}
|
|
277
281
|
await act(async () => {
|
|
278
282
|
tree = await create(wrapComponent(route));
|
|
279
283
|
});
|
|
@@ -288,13 +292,89 @@ describe('Test ScriptDetail', () => {
|
|
|
288
292
|
id: route.params.id,
|
|
289
293
|
type: activityLogType,
|
|
290
294
|
share: route.params.unit,
|
|
295
|
+
filterEnabled: {
|
|
296
|
+
user: !isMultiUnit,
|
|
297
|
+
date: true,
|
|
298
|
+
},
|
|
291
299
|
});
|
|
292
300
|
});
|
|
293
301
|
};
|
|
294
302
|
|
|
295
303
|
_testGoToActivityLog(
|
|
296
304
|
AUTOMATE_TYPE.ONE_TAP,
|
|
297
|
-
`automate.${AUTOMATE_TYPE.ONE_TAP}
|
|
305
|
+
`automate.${AUTOMATE_TYPE.ONE_TAP}`,
|
|
306
|
+
false
|
|
298
307
|
);
|
|
299
|
-
_testGoToActivityLog(AUTOMATE_TYPE.VALUE_CHANGE, 'automate');
|
|
308
|
+
_testGoToActivityLog(AUTOMATE_TYPE.VALUE_CHANGE, 'automate', false);
|
|
309
|
+
_testGoToActivityLog(AUTOMATE_TYPE.VALUE_CHANGE, 'automate', true);
|
|
310
|
+
|
|
311
|
+
test('Test render textCondition value change >', async () => {
|
|
312
|
+
route.params = {
|
|
313
|
+
...route.params,
|
|
314
|
+
type: AUTOMATE_TYPE.VALUE_CHANGE,
|
|
315
|
+
automate: {
|
|
316
|
+
repeat: 'once',
|
|
317
|
+
date_repeat: '2022-01-02',
|
|
318
|
+
time_repeat: '09:10:00',
|
|
319
|
+
weekday_repeat: ['1', '2', '4', '6'],
|
|
320
|
+
config_name: 'Light Value',
|
|
321
|
+
value: 3,
|
|
322
|
+
condition: '>',
|
|
323
|
+
},
|
|
324
|
+
};
|
|
325
|
+
await act(() => {
|
|
326
|
+
tree = create(wrapComponent(route));
|
|
327
|
+
});
|
|
328
|
+
const instance = tree.root;
|
|
329
|
+
const itemAutomate = instance.findByType(ItemAutomate);
|
|
330
|
+
expect(itemAutomate.props.textCondition).toEqual(
|
|
331
|
+
'Light Value higher than 3'
|
|
332
|
+
);
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
test('Test render textCondition value change =', async () => {
|
|
336
|
+
route.params = {
|
|
337
|
+
...route.params,
|
|
338
|
+
type: AUTOMATE_TYPE.VALUE_CHANGE,
|
|
339
|
+
automate: {
|
|
340
|
+
repeat: 'once',
|
|
341
|
+
date_repeat: '2022-01-02',
|
|
342
|
+
time_repeat: '09:10:00',
|
|
343
|
+
weekday_repeat: ['1', '2', '4', '6'],
|
|
344
|
+
config_name: 'Light Value',
|
|
345
|
+
value: 3,
|
|
346
|
+
condition: '=',
|
|
347
|
+
},
|
|
348
|
+
};
|
|
349
|
+
await act(() => {
|
|
350
|
+
tree = create(wrapComponent(route));
|
|
351
|
+
});
|
|
352
|
+
const instance = tree.root;
|
|
353
|
+
const itemAutomate = instance.findByType(ItemAutomate);
|
|
354
|
+
expect(itemAutomate.props.textCondition).toEqual('Light Value equal 3');
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
test('Test render textCondition value change <', async () => {
|
|
358
|
+
route.params = {
|
|
359
|
+
...route.params,
|
|
360
|
+
type: AUTOMATE_TYPE.VALUE_CHANGE,
|
|
361
|
+
automate: {
|
|
362
|
+
repeat: 'once',
|
|
363
|
+
date_repeat: '2022-01-02',
|
|
364
|
+
time_repeat: '09:10:00',
|
|
365
|
+
weekday_repeat: ['1', '2', '4', '6'],
|
|
366
|
+
config_name: 'Light Value',
|
|
367
|
+
value: 3,
|
|
368
|
+
condition: '<',
|
|
369
|
+
},
|
|
370
|
+
};
|
|
371
|
+
await act(() => {
|
|
372
|
+
tree = create(wrapComponent(route));
|
|
373
|
+
});
|
|
374
|
+
const instance = tree.root;
|
|
375
|
+
const itemAutomate = instance.findByType(ItemAutomate);
|
|
376
|
+
expect(itemAutomate.props.textCondition).toEqual(
|
|
377
|
+
'Light Value lower than 3'
|
|
378
|
+
);
|
|
379
|
+
});
|
|
300
380
|
});
|
|
@@ -43,6 +43,7 @@ import { AUTOMATE_SELECT, AUTOMATE_TYPE } from '../../configs/Constants';
|
|
|
43
43
|
import { popAction } from '../../navigations/utils';
|
|
44
44
|
import { TESTID } from '../../configs/Constants';
|
|
45
45
|
import useKeyboardAnimated from '../../hooks/Explore/useKeyboardAnimated';
|
|
46
|
+
import { REPEAT_OPTIONS } from '../SetSchedule/components/RepeatOptionsPopup';
|
|
46
47
|
|
|
47
48
|
const PreventDoubleTouch = withPreventDoubleClick(TouchableOpacity);
|
|
48
49
|
|
|
@@ -61,6 +62,7 @@ const ScriptDetail = ({ route }) => {
|
|
|
61
62
|
const t = useTranslations();
|
|
62
63
|
const {
|
|
63
64
|
id,
|
|
65
|
+
automate = {},
|
|
64
66
|
name = '',
|
|
65
67
|
type,
|
|
66
68
|
havePermission,
|
|
@@ -70,7 +72,6 @@ const ScriptDetail = ({ route }) => {
|
|
|
70
72
|
isAutomateTab,
|
|
71
73
|
isCreateNewAction,
|
|
72
74
|
isMultiUnits,
|
|
73
|
-
textCondition = '',
|
|
74
75
|
} = params;
|
|
75
76
|
const [isStar, setIsStar] = useState(false);
|
|
76
77
|
const [scriptName, setScriptName] = useState(name);
|
|
@@ -214,15 +215,15 @@ const ScriptDetail = ({ route }) => {
|
|
|
214
215
|
|
|
215
216
|
const handleUpdateAutomate = useCallback(async () => {
|
|
216
217
|
navigate(Routes.AddNewAutoSmart, {
|
|
217
|
-
type
|
|
218
|
-
|
|
218
|
+
type,
|
|
219
|
+
automate,
|
|
219
220
|
unit,
|
|
220
221
|
isAutomateTab,
|
|
221
222
|
isMultiUnits,
|
|
222
223
|
scriptName: name,
|
|
223
224
|
});
|
|
224
225
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
225
|
-
}, [name]);
|
|
226
|
+
}, [name, automate]);
|
|
226
227
|
|
|
227
228
|
const onGoBack = useCallback(() => {
|
|
228
229
|
if (isCreateScriptSuccess || isCreateNewAction) {
|
|
@@ -351,6 +352,66 @@ const ScriptDetail = ({ route }) => {
|
|
|
351
352
|
return () => backHandler.remove();
|
|
352
353
|
}, [isCreateScriptSuccess]);
|
|
353
354
|
const isHaveScriptActions = data?.length > 0;
|
|
355
|
+
|
|
356
|
+
const textCondition = useMemo(() => {
|
|
357
|
+
const {
|
|
358
|
+
condition,
|
|
359
|
+
config_name,
|
|
360
|
+
value,
|
|
361
|
+
repeat,
|
|
362
|
+
date_repeat,
|
|
363
|
+
time_repeat,
|
|
364
|
+
weekday_repeat,
|
|
365
|
+
} = automate;
|
|
366
|
+
if (type === AUTOMATE_TYPE.VALUE_CHANGE) {
|
|
367
|
+
let textCondition;
|
|
368
|
+
if (condition === '>') {
|
|
369
|
+
textCondition = 'higher_than';
|
|
370
|
+
} else if (condition === '<') {
|
|
371
|
+
textCondition = 'lower_than';
|
|
372
|
+
} else if (condition === '=') {
|
|
373
|
+
textCondition = 'equal';
|
|
374
|
+
}
|
|
375
|
+
return `${config_name} ${t(textCondition)} ${value}`;
|
|
376
|
+
} else if (type === AUTOMATE_TYPE.SCHEDULE) {
|
|
377
|
+
const time =
|
|
378
|
+
time_repeat.length >= 8
|
|
379
|
+
? time_repeat.substring(0, time_repeat.length - 3)
|
|
380
|
+
: time_repeat;
|
|
381
|
+
const date = date_repeat.split('-').reverse().join('/');
|
|
382
|
+
const weekday = {
|
|
383
|
+
1: t('mon'),
|
|
384
|
+
2: t('tue'),
|
|
385
|
+
3: t('wed'),
|
|
386
|
+
4: t('thu'),
|
|
387
|
+
5: t('fri'),
|
|
388
|
+
6: t('sat'),
|
|
389
|
+
0: t('sun'),
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
if (repeat === REPEAT_OPTIONS.ONCE) {
|
|
393
|
+
return `${time} ${date}`;
|
|
394
|
+
} else if (repeat === REPEAT_OPTIONS.EVERYDAY) {
|
|
395
|
+
return `${t('every_day_at', { time })}`;
|
|
396
|
+
} else if (repeat === REPEAT_OPTIONS.EVERYWEEK) {
|
|
397
|
+
//sort 0 is last number, exp: [1,3,5,0]
|
|
398
|
+
const newWeekdayRepeat = weekday_repeat.map((item) => parseInt(item));
|
|
399
|
+
const sortWeekday = newWeekdayRepeat.sort((a, b) => {
|
|
400
|
+
if (a !== 0 && b === 0) {
|
|
401
|
+
return -1;
|
|
402
|
+
}
|
|
403
|
+
if (a === 0 && b !== 0) {
|
|
404
|
+
return 1;
|
|
405
|
+
}
|
|
406
|
+
return a - b;
|
|
407
|
+
});
|
|
408
|
+
const textWeekday = sortWeekday.map((item) => weekday[item]).join(', ');
|
|
409
|
+
return `${textWeekday} ${t('at')} ${time}`;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
return null;
|
|
413
|
+
}, [t, automate, type]);
|
|
414
|
+
|
|
354
415
|
return (
|
|
355
416
|
<View style={styles.wrap}>
|
|
356
417
|
<WrapHeaderScrollable
|
|
@@ -28,7 +28,7 @@ test('test select', async () => {
|
|
|
28
28
|
await act(async () => {
|
|
29
29
|
await items[0].props.onPress();
|
|
30
30
|
});
|
|
31
|
-
expect(mockSetWeekday).toBeCalledWith(['
|
|
31
|
+
expect(mockSetWeekday).toBeCalledWith(['1']);
|
|
32
32
|
|
|
33
33
|
mockSetWeekday.mockClear();
|
|
34
34
|
props = {
|
|
@@ -44,5 +44,5 @@ test('test select', async () => {
|
|
|
44
44
|
await act(async () => {
|
|
45
45
|
await items[0].props.onPress();
|
|
46
46
|
});
|
|
47
|
-
expect(mockSetWeekday).toBeCalledWith([]);
|
|
47
|
+
expect(mockSetWeekday).toBeCalledWith(['0', '1']);
|
|
48
48
|
});
|
|
@@ -162,6 +162,14 @@ describe('Test SetSchedule', () => {
|
|
|
162
162
|
isAutomateTab: true,
|
|
163
163
|
isScript: undefined,
|
|
164
164
|
isMultiUnits: undefined,
|
|
165
|
+
automateId: undefined,
|
|
166
|
+
scriptName: undefined,
|
|
167
|
+
automate: {
|
|
168
|
+
date_repeat: '2021-01-24',
|
|
169
|
+
repeat: 'once',
|
|
170
|
+
time_repeat: '12:00:00',
|
|
171
|
+
weekday_repeat: [],
|
|
172
|
+
},
|
|
165
173
|
});
|
|
166
174
|
});
|
|
167
175
|
});
|
|
@@ -5,7 +5,15 @@ import { Colors } from '../../../configs';
|
|
|
5
5
|
import styles from '../styles/SelectWeekdayStyles';
|
|
6
6
|
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
7
7
|
|
|
8
|
-
const WEEKDAY_ITEMS = [
|
|
8
|
+
const WEEKDAY_ITEMS = [
|
|
9
|
+
{ day: 'Mon', value: 1 },
|
|
10
|
+
{ day: 'Tue', value: 2 },
|
|
11
|
+
{ day: 'Wed', value: 3 },
|
|
12
|
+
{ day: 'Thu', value: 4 },
|
|
13
|
+
{ day: 'Fri', value: 5 },
|
|
14
|
+
{ day: 'Sat', value: 6 },
|
|
15
|
+
{ day: 'Sun', value: 0 },
|
|
16
|
+
];
|
|
9
17
|
|
|
10
18
|
const SelectWeekday = ({ weekday, setWeekday }) => {
|
|
11
19
|
const t = useTranslations();
|
|
@@ -23,11 +31,10 @@ const SelectWeekday = ({ weekday, setWeekday }) => {
|
|
|
23
31
|
);
|
|
24
32
|
|
|
25
33
|
const WeekdayItem = useCallback(
|
|
26
|
-
({ item,
|
|
34
|
+
({ item, isSelected }) => {
|
|
27
35
|
return (
|
|
28
36
|
<TouchableOpacity
|
|
29
|
-
|
|
30
|
-
onPress={() => onSetWeekday(`${index}`)}
|
|
37
|
+
onPress={() => onSetWeekday(`${item?.value}`)}
|
|
31
38
|
style={[styles.item, isSelected && styles.selected]}
|
|
32
39
|
>
|
|
33
40
|
<Text
|
|
@@ -36,7 +43,7 @@ const SelectWeekday = ({ weekday, setWeekday }) => {
|
|
|
36
43
|
style={styles.text}
|
|
37
44
|
semibold
|
|
38
45
|
>
|
|
39
|
-
{item}
|
|
46
|
+
{item?.day}
|
|
40
47
|
</Text>
|
|
41
48
|
</TouchableOpacity>
|
|
42
49
|
);
|
|
@@ -54,8 +61,7 @@ const SelectWeekday = ({ weekday, setWeekday }) => {
|
|
|
54
61
|
<WeekdayItem
|
|
55
62
|
key={index}
|
|
56
63
|
item={item}
|
|
57
|
-
|
|
58
|
-
isSelected={weekday.includes(`${index}`)}
|
|
64
|
+
isSelected={weekday.includes(`${item?.value}`)}
|
|
59
65
|
/>
|
|
60
66
|
))}
|
|
61
67
|
</View>
|