@eohjsc/react-native-smart-city 0.2.65 → 0.2.69
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/Popover/Dashboard/SmartAccount.svg +5 -0
- package/assets/images/scan-qr-gateway.svg +14 -0
- package/assets/images/wifi-gateway.svg +18 -0
- package/assets/images/wifi.svg +3 -0
- package/package.json +3 -1
- package/src/commons/Action/ItemQuickAction.js +4 -3
- package/src/commons/ActionGroup/CurtainButtonTemplate.js +0 -30
- package/src/commons/ActionGroup/CurtainButtonTemplateStyle.js +0 -12
- package/src/commons/ActionGroup/__test__/CurtainButtonTemplate.test.js +1 -1
- package/src/commons/AlertAction/index.js +4 -3
- package/src/commons/Dashboard/MyPinnedSharedUnit/__test__/MyPinnedSharedUnit.test.js +70 -0
- package/src/commons/Device/HistoryChart.js +18 -18
- package/src/commons/Device/HorizontalBarChart.js +1 -2
- package/src/commons/Device/LinearChart.js +13 -3
- package/src/commons/SubUnit/OneTap/OneTapStyles.js +14 -5
- package/src/commons/SubUnit/OneTap/__test__/SubUnitAutomate.test.js +5 -68
- package/src/commons/SubUnit/OneTap/index.js +24 -33
- package/src/commons/UnitSummary/ConfigHistoryChart/__test__/ConfigHistoryChart.test.js +29 -0
- package/src/commons/UnitSummary/ConfigHistoryChart.js +4 -6
- package/src/commons/ViewButtonBottom/index.js +4 -0
- package/src/configs/API.js +2 -0
- package/src/configs/BLE.js +3 -0
- package/src/iot/RemoteControl/Bluetooth.js +34 -6
- package/src/iot/RemoteControl/__test__/Bluetooth.test.js +1 -0
- package/src/iot/RemoteControl/__test__/index.mock.js +1 -0
- package/src/iot/RemoteControl/index.js +7 -2
- package/src/navigations/AddDeviceStack.js +2 -0
- package/src/navigations/AddGatewayStack.js +11 -0
- package/src/navigations/AddLGDeviceStack.js +2 -0
- package/src/navigations/AddMemberStack.js +2 -0
- package/src/navigations/AddSubUnitStack.js +2 -0
- package/src/navigations/AddUnitStack.js +2 -0
- package/src/navigations/EmergencyContactsStack.js +2 -0
- package/src/navigations/SharedStack.js +2 -0
- package/src/navigations/UnitStack.js +2 -0
- package/src/screens/AddCommon/SelectSubUnit.js +14 -1
- package/src/screens/AddNewGateway/PlugAndPlay/ConnectWifiWarning.js +190 -0
- package/src/screens/AddNewGateway/PlugAndPlay/FirstWarning.js +73 -0
- package/src/screens/AddNewGateway/PlugAndPlay/GatewayWifiList.js +154 -0
- package/src/screens/AddNewGateway/PlugAndPlay/__test__/FirstWarning.test.js +60 -0
- package/src/screens/AddNewGateway/PlugAndPlay/__test__/GatewayWifiList.test.js +35 -0
- package/src/screens/AddNewGateway/__test__/SetupGateway.test.js +90 -0
- package/src/screens/Device/EditDevice/index.js +3 -3
- package/src/screens/Device/components/SensorDisplayItem.js +4 -2
- package/src/screens/ScanChipQR/hooks/index.js +14 -5
- package/src/screens/SharedUnit/index.js +7 -5
- package/src/screens/Sharing/Components/SensorItem.js +27 -12
- package/src/screens/Sharing/Components/Styles/SensorItemStyles.js +4 -0
- package/src/screens/Sharing/SelectPermission.js +44 -32
- package/src/screens/Sharing/__test__/SelectPermission.test.js +2 -1
- package/src/screens/SubUnit/AddSubUnit.js +4 -24
- package/src/screens/TDSGuide/index.js +5 -2
- package/src/screens/Unit/AddMenu.js +15 -0
- package/src/screens/Unit/Detail.js +15 -4
- package/src/screens/Unit/SmartAccount.js +36 -15
- package/src/screens/Unit/SmartAccountStyles.js +20 -0
- package/src/screens/Unit/components/__test__/MyUnitDevice.test.js +10 -6
- package/src/screens/Unit/hook/useStateAlertRemove.js +4 -6
- package/src/screens/UnitSummary/components/PowerConsumption/index.js +2 -4
- package/src/screens/UnitSummary/components/RunningDevices/__test__/index.test.js +10 -6
- package/src/utils/Apis/axios.js +2 -3
- package/src/utils/I18n/translations/en.json +27 -4
- package/src/utils/I18n/translations/vi.json +27 -4
- package/src/utils/Route/index.js +4 -0
- package/src/utils/Utils.js +0 -4
- package/src/commons/ActionGroup/__test__/MenuActionAddSchedule.test.js +0 -71
- package/src/commons/ActionGroup/hooks/AccessScheduleDetailStyles.js +0 -41
- package/src/commons/ActionGroup/hooks/MenuActionAddSchedule.js +0 -110
- package/src/commons/ActionGroup/hooks/MenuActionAddScheduleStyle.js +0 -69
- package/src/commons/ActionGroup/hooks/RecurringDetail.js +0 -97
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React, { useEffect, useCallback, useState, useMemo } from 'react';
|
|
2
2
|
import { View, TouchableOpacity, FlatList, RefreshControl } from 'react-native';
|
|
3
|
-
import { useNavigation } from '@react-navigation/native';
|
|
3
|
+
import { useNavigation, useIsFocused } from '@react-navigation/native';
|
|
4
|
+
|
|
4
5
|
import { axiosGet } from '../../utils/Apis/axios';
|
|
5
6
|
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
6
|
-
|
|
7
7
|
import { API } from '../../configs';
|
|
8
8
|
import Text from '../../commons/Text';
|
|
9
9
|
import SharedUnit from '../../commons/Unit/SharedUnit';
|
|
@@ -24,7 +24,7 @@ const Shared = () => {
|
|
|
24
24
|
useTitleHeader(t('text_shared_with_me'));
|
|
25
25
|
const navigation = useNavigation();
|
|
26
26
|
const [tab, setTabActiveState] = useState(0);
|
|
27
|
-
|
|
27
|
+
const isFocused = useIsFocused();
|
|
28
28
|
const [sharedUnits, setSharedUnits] = useState([]);
|
|
29
29
|
|
|
30
30
|
const dataStarred = useMemo(
|
|
@@ -73,8 +73,10 @@ const Shared = () => {
|
|
|
73
73
|
}, [language, forceUpdate]);
|
|
74
74
|
|
|
75
75
|
useEffect(() => {
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
if (isFocused) {
|
|
77
|
+
filterSharedUnits(filter);
|
|
78
|
+
}
|
|
79
|
+
}, [filterSharedUnits, filter, isFocused]);
|
|
78
80
|
|
|
79
81
|
const onRefresh = useCallback(() => {
|
|
80
82
|
filterSharedUnits(filter);
|
|
@@ -5,11 +5,13 @@ import { Colors } from '../../../configs';
|
|
|
5
5
|
import styles from './Styles/SensorItemStyles';
|
|
6
6
|
import FImage from '../../../commons/FImage';
|
|
7
7
|
import { TitleCheckBox } from '.';
|
|
8
|
+
import { CheckBoxCustom } from '.';
|
|
8
9
|
|
|
9
10
|
const SensorItem = ({
|
|
10
11
|
item = {},
|
|
11
12
|
isRenderSeparated,
|
|
12
13
|
onTickedChild,
|
|
14
|
+
onTickedSensor,
|
|
13
15
|
titleGroup,
|
|
14
16
|
activeItemId,
|
|
15
17
|
setActiveItemId,
|
|
@@ -21,21 +23,22 @@ const SensorItem = ({
|
|
|
21
23
|
actions = [],
|
|
22
24
|
read_configs = [],
|
|
23
25
|
icon_kit = '',
|
|
26
|
+
isChecked,
|
|
24
27
|
} = item;
|
|
25
|
-
const [expanded, setExpanded] = useState(activeItemId === id);
|
|
26
28
|
const [dataConfig, setDataConfig] = useState([
|
|
27
29
|
...actions,
|
|
28
30
|
...read_configs.map((i) => ({ ...i, isConfig: true })),
|
|
29
31
|
]);
|
|
30
32
|
|
|
33
|
+
const expanded = activeItemId === id;
|
|
34
|
+
|
|
31
35
|
const onPressItem = () => {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
36
|
+
if (dataConfig.length > 0) {
|
|
37
|
+
expanded ? setActiveItemId(-1) : setActiveItemId(id);
|
|
38
|
+
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
|
|
35
39
|
} else {
|
|
36
|
-
|
|
40
|
+
handleOnTickedSensor();
|
|
37
41
|
}
|
|
38
|
-
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
|
|
39
42
|
};
|
|
40
43
|
|
|
41
44
|
const handleOnTickedChild = (idGroup, isChecked, childId) => {
|
|
@@ -56,6 +59,10 @@ const SensorItem = ({
|
|
|
56
59
|
);
|
|
57
60
|
};
|
|
58
61
|
|
|
62
|
+
const handleOnTickedSensor = () => {
|
|
63
|
+
onTickedSensor && onTickedSensor(idGroup, id, !isChecked);
|
|
64
|
+
};
|
|
65
|
+
|
|
59
66
|
useEffect(() => {
|
|
60
67
|
if (
|
|
61
68
|
Platform.OS === 'android' &&
|
|
@@ -97,12 +104,20 @@ const SensorItem = ({
|
|
|
97
104
|
<Text numberOfLines={1} style={styles.text} onPress={onPressItem}>
|
|
98
105
|
{name}
|
|
99
106
|
</Text>
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
107
|
+
{dataConfig.length > 0 ? (
|
|
108
|
+
<IconOutline
|
|
109
|
+
onPress={onPressItem}
|
|
110
|
+
name={expanded ? 'up' : 'down'}
|
|
111
|
+
size={20}
|
|
112
|
+
color={Colors.Gray6}
|
|
113
|
+
/>
|
|
114
|
+
) : (
|
|
115
|
+
<CheckBoxCustom
|
|
116
|
+
isChecked={isChecked}
|
|
117
|
+
onPress={onPressItem}
|
|
118
|
+
wrapStyle={styles.checkBox}
|
|
119
|
+
/>
|
|
120
|
+
)}
|
|
106
121
|
</View>
|
|
107
122
|
{expanded && <View style={styles.wrapExpand}>{renderData}</View>}
|
|
108
123
|
{isRenderSeparated && <View style={styles.viewSeparated} />}
|
|
@@ -38,11 +38,12 @@ const SelectPermission = ({ route }) => {
|
|
|
38
38
|
...i,
|
|
39
39
|
isChecked,
|
|
40
40
|
}));
|
|
41
|
-
for (let
|
|
42
|
-
for (let item in data[
|
|
43
|
-
const itemTemp = data[
|
|
44
|
-
data[
|
|
41
|
+
for (let station in data) {
|
|
42
|
+
for (let item in data[station].sensors) {
|
|
43
|
+
const itemTemp = data[station].sensors[item];
|
|
44
|
+
data[station].sensors[item] = {
|
|
45
45
|
...itemTemp,
|
|
46
|
+
isChecked,
|
|
46
47
|
actions: itemTemp.actions.map((i) => ({
|
|
47
48
|
...i,
|
|
48
49
|
isChecked,
|
|
@@ -63,6 +64,7 @@ const SelectPermission = ({ route }) => {
|
|
|
63
64
|
isChecked,
|
|
64
65
|
sensors: data[index]?.sensors.map((i) => ({
|
|
65
66
|
...i,
|
|
67
|
+
isChecked,
|
|
66
68
|
actions: i.actions.map((j) => ({ ...j, isChecked })),
|
|
67
69
|
read_configs: i.read_configs.map((j) => ({ ...j, isChecked })),
|
|
68
70
|
})),
|
|
@@ -80,33 +82,38 @@ const SelectPermission = ({ route }) => {
|
|
|
80
82
|
isReadConfig
|
|
81
83
|
) => {
|
|
82
84
|
let data = [...dataStationTemp];
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
|
|
85
|
+
const group = data.find((i) => i.id === idGroup);
|
|
86
|
+
const sensor = group.sensors.find((i) => i.id === sensorId);
|
|
87
|
+
const child = sensor[`${isReadConfig ? 'read_configs' : 'actions'}`].find(
|
|
88
|
+
(i) => i.id === childId
|
|
86
89
|
);
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
90
|
+
|
|
91
|
+
child.isChecked = isChecked;
|
|
92
|
+
sensor.isChecked = !(
|
|
93
|
+
sensor.read_configs.some((i) => !i.isChecked) ||
|
|
94
|
+
sensor.actions.some((i) => !i.isChecked)
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
for (let station of data) {
|
|
98
|
+
if (station.sensors.length) {
|
|
99
|
+
station.isChecked = !station.sensors.some((i) => !i.isChecked);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
setIsTickAllDevices(!dataStationTemp.some((i) => !i.isChecked));
|
|
103
|
+
dataStationTemp = data;
|
|
104
|
+
setDataStations(data);
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const onTickedSensor = (idGroup, sensorId, isChecked) => {
|
|
108
|
+
let data = [...dataStationTemp];
|
|
109
|
+
const group = data.find((i) => i.id === idGroup);
|
|
110
|
+
const sensor = group.sensors.find((i) => i.id === sensorId);
|
|
111
|
+
|
|
112
|
+
sensor.isChecked = isChecked;
|
|
113
|
+
|
|
114
|
+
for (let station of data) {
|
|
115
|
+
if (station.sensors.length) {
|
|
116
|
+
station.isChecked = !station.sensors.some((i) => !i.isChecked);
|
|
110
117
|
}
|
|
111
118
|
}
|
|
112
119
|
setIsTickAllDevices(!dataStationTemp.some((i) => !i.isChecked));
|
|
@@ -133,6 +140,7 @@ const SelectPermission = ({ route }) => {
|
|
|
133
140
|
key={i.id}
|
|
134
141
|
isRenderSeparated={index !== sensors.length - 1}
|
|
135
142
|
onTickedChild={onTickedChild}
|
|
143
|
+
onTickedSensor={onTickedSensor}
|
|
136
144
|
titleGroup={name}
|
|
137
145
|
activeItemId={activeItemId}
|
|
138
146
|
setActiveItemId={setActiveItemId}
|
|
@@ -147,8 +155,8 @@ const SelectPermission = ({ route }) => {
|
|
|
147
155
|
const onPressNext = () => {
|
|
148
156
|
let read_permissions = [],
|
|
149
157
|
control_permissions = [];
|
|
150
|
-
for (let
|
|
151
|
-
for (let item of
|
|
158
|
+
for (let station of dataStationTemp) {
|
|
159
|
+
for (let item of station.sensors) {
|
|
152
160
|
let arrIdControlTemp = [],
|
|
153
161
|
arrIdReadTemp = [];
|
|
154
162
|
for (let i of item.actions) {
|
|
@@ -161,6 +169,10 @@ const SelectPermission = ({ route }) => {
|
|
|
161
169
|
control_permissions.push({ id: item.id, values: arrIdControlTemp });
|
|
162
170
|
arrIdReadTemp.length &&
|
|
163
171
|
read_permissions.push({ id: item.id, values: arrIdReadTemp });
|
|
172
|
+
!arrIdControlTemp.length &&
|
|
173
|
+
!arrIdReadTemp.length &&
|
|
174
|
+
item.isChecked &&
|
|
175
|
+
read_permissions.push({ id: item.id, values: [] });
|
|
164
176
|
}
|
|
165
177
|
}
|
|
166
178
|
if (!read_permissions.length && !control_permissions.length) {
|
|
@@ -144,6 +144,7 @@ describe('Test SelectPermission', () => {
|
|
|
144
144
|
{
|
|
145
145
|
actions: [{ id: 136, isChecked: true, name: 'action 1' }],
|
|
146
146
|
id: 123,
|
|
147
|
+
isChecked: true,
|
|
147
148
|
name: 'child1',
|
|
148
149
|
read_configs: [{ id: 137, isChecked: true, name: 'config 1' }],
|
|
149
150
|
},
|
|
@@ -165,7 +166,7 @@ describe('Test SelectPermission', () => {
|
|
|
165
166
|
const SensorItemElement = instance.findAllByType(SensorItem);
|
|
166
167
|
expect(SensorItemElement).toHaveLength(1);
|
|
167
168
|
act(() => {
|
|
168
|
-
SensorItemElement[0].props.onTickedChild(204, 123,
|
|
169
|
+
SensorItemElement[0].props.onTickedChild(204, 123, 137, true, true);
|
|
169
170
|
});
|
|
170
171
|
expect(mockSetDataStations).toBeCalled();
|
|
171
172
|
});
|
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
SafeAreaView,
|
|
14
14
|
} from 'react-native';
|
|
15
15
|
import { useNavigation } from '@react-navigation/native';
|
|
16
|
-
import ImageResizer from 'react-native-image-resizer';
|
|
17
16
|
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
18
17
|
|
|
19
18
|
import { API, Colors } from '../../configs';
|
|
@@ -25,29 +24,11 @@ import { axiosPost, createFormData } from '../../utils/Apis/axios';
|
|
|
25
24
|
import { ToastBottomHelper } from '../../utils/Utils';
|
|
26
25
|
import { TESTID } from '../../configs/Constants';
|
|
27
26
|
import styles from './AddSubUnitStyles';
|
|
28
|
-
|
|
29
|
-
const MAX_FILE_SIZE_BYTES = 1.5 * 1024 * 1024; // 1.5mb
|
|
30
|
-
|
|
31
|
-
const prepareImageToUpload = async (image) => {
|
|
32
|
-
if (!image || image.size < MAX_FILE_SIZE_BYTES) {
|
|
33
|
-
return image;
|
|
34
|
-
}
|
|
35
|
-
const result = await ImageResizer.createResizedImage(
|
|
36
|
-
image.path,
|
|
37
|
-
1280,
|
|
38
|
-
1280,
|
|
39
|
-
'JPEG',
|
|
40
|
-
70
|
|
41
|
-
);
|
|
42
|
-
return {
|
|
43
|
-
fileName: result?.name,
|
|
44
|
-
type: 'image/jpeg',
|
|
45
|
-
uri: result?.uri,
|
|
46
|
-
};
|
|
47
|
-
};
|
|
27
|
+
import useKeyboardShow from '../../hooks/Common/useKeyboardShow';
|
|
48
28
|
|
|
49
29
|
const AddSubUnit = ({ route }) => {
|
|
50
30
|
const t = useTranslations();
|
|
31
|
+
const { dismissKeyboard } = useKeyboardShow();
|
|
51
32
|
const { navigate, goBack } = useNavigation();
|
|
52
33
|
const { unit, addType, isAddUnit, location = '' } = route?.params;
|
|
53
34
|
const [roomName, setRoomName] = useState('');
|
|
@@ -72,7 +53,6 @@ const AddSubUnit = ({ route }) => {
|
|
|
72
53
|
address: location,
|
|
73
54
|
background: wallpaper,
|
|
74
55
|
};
|
|
75
|
-
dataObj.background = await prepareImageToUpload(dataObj.background);
|
|
76
56
|
const formData = createFormData(dataObj, ['background']);
|
|
77
57
|
const { success, data } = await axiosPost(
|
|
78
58
|
API.UNIT.CREATE_UNIT(),
|
|
@@ -99,7 +79,6 @@ const AddSubUnit = ({ route }) => {
|
|
|
99
79
|
if (!awaitCreate.current) {
|
|
100
80
|
awaitCreate.current = true;
|
|
101
81
|
const dataObj = { name: roomName, background: wallpaper };
|
|
102
|
-
dataObj.background = await prepareImageToUpload(dataObj.background);
|
|
103
82
|
const formData = createFormData(dataObj, ['background']);
|
|
104
83
|
const { success } = await axiosPost(
|
|
105
84
|
API.SUB_UNIT.CREATE_SUB_UNIT(unit.id),
|
|
@@ -149,8 +128,9 @@ const AddSubUnit = ({ route }) => {
|
|
|
149
128
|
]);
|
|
150
129
|
|
|
151
130
|
const onChoosePhoto = useCallback(() => {
|
|
131
|
+
dismissKeyboard();
|
|
152
132
|
setShowImagePicker(true);
|
|
153
|
-
}, []);
|
|
133
|
+
}, [dismissKeyboard]);
|
|
154
134
|
|
|
155
135
|
useEffect(() => {
|
|
156
136
|
if (imageUrl) {
|
|
@@ -22,12 +22,12 @@ const TDSGuide = memo(() => {
|
|
|
22
22
|
>
|
|
23
23
|
{t('what_is_tds_title')}
|
|
24
24
|
</Text>
|
|
25
|
-
<Text
|
|
25
|
+
<Text style={styles.tdsText}>{t('what_is_tds_text')}</Text>
|
|
26
26
|
<Text type="H3" semibold style={styles.titlePadding}>
|
|
27
27
|
{t('tds_guidlines_title')}
|
|
28
28
|
</Text>
|
|
29
29
|
<>
|
|
30
|
-
<Text
|
|
30
|
+
<Text style={styles.tdsText}>
|
|
31
31
|
{t('tds_guidlines_text_1')}
|
|
32
32
|
{'\n'}
|
|
33
33
|
{'\n'}
|
|
@@ -56,4 +56,7 @@ const styles = StyleSheet.create({
|
|
|
56
56
|
paddingTop: 20,
|
|
57
57
|
paddingBottom: 10,
|
|
58
58
|
},
|
|
59
|
+
tdsText: {
|
|
60
|
+
fontSize: 15,
|
|
61
|
+
},
|
|
59
62
|
});
|
|
@@ -4,6 +4,7 @@ import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
|
4
4
|
import Routes from '../../utils/Route';
|
|
5
5
|
import AddSubUnitIcon from '../../../assets/images/Popover/Dashboard/AddSubUnit.svg';
|
|
6
6
|
import AddDeviceIcon from '../../../assets/images/Popover/Dashboard/AddDevice.svg';
|
|
7
|
+
import SmartAccount from '../../../assets/images/Popover/Dashboard/SmartAccount.svg';
|
|
7
8
|
import AddMemberIcon from '../../../assets/images/Popover/Dashboard/AddMember.svg';
|
|
8
9
|
import { useNavigation } from '@react-navigation/native';
|
|
9
10
|
|
|
@@ -50,6 +51,20 @@ const AddMenu = memo(({ unit, afterItemClick, showAdd, setHideAdd }) => {
|
|
|
50
51
|
image: <AddDeviceIcon width={43} height={43} />, // TODO change icon
|
|
51
52
|
data: { screen: Routes.SetupGatewayWifi, params: { unit_id: unit.id } },
|
|
52
53
|
},
|
|
54
|
+
{
|
|
55
|
+
id: 5,
|
|
56
|
+
route: Routes.AddGatewayStack,
|
|
57
|
+
text: t('gateway') + ' Wifi',
|
|
58
|
+
image: <AddDeviceIcon width={43} height={43} />,
|
|
59
|
+
data: { screen: Routes.FirstWarning, params: { unit_id: unit.id } },
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: 6,
|
|
63
|
+
route: Routes.SmartAccount,
|
|
64
|
+
text: t('name_smart_account'),
|
|
65
|
+
image: <SmartAccount width={43} height={43} />, // TODO change icon
|
|
66
|
+
type: Routes.SmartAccount,
|
|
67
|
+
},
|
|
53
68
|
];
|
|
54
69
|
}, [t, unit]);
|
|
55
70
|
|
|
@@ -31,7 +31,14 @@ import { AUTOMATE_TYPE } from '../../configs/Constants';
|
|
|
31
31
|
const UnitDetail = ({ route }) => {
|
|
32
32
|
const t = useTranslations();
|
|
33
33
|
|
|
34
|
-
const {
|
|
34
|
+
const {
|
|
35
|
+
unitId,
|
|
36
|
+
unitData,
|
|
37
|
+
isOneTap,
|
|
38
|
+
routeName,
|
|
39
|
+
isAddSubUnit,
|
|
40
|
+
isSuccessfullyConnected,
|
|
41
|
+
} = route.params;
|
|
35
42
|
|
|
36
43
|
const isFocused = useIsFocused();
|
|
37
44
|
const { stateData, setAction } = useContext(SCContext);
|
|
@@ -115,12 +122,12 @@ const UnitDetail = ({ route }) => {
|
|
|
115
122
|
if (success) {
|
|
116
123
|
setListAutomate([
|
|
117
124
|
{
|
|
118
|
-
text: t(AUTOMATE_TYPE.
|
|
125
|
+
text: t(AUTOMATE_TYPE.ONE_TAP),
|
|
119
126
|
data: data.filter((item) => item.type === AUTOMATE_TYPE.ONE_TAP),
|
|
120
127
|
type: AUTOMATE_TYPE.ONE_TAP,
|
|
121
128
|
},
|
|
122
129
|
{
|
|
123
|
-
text: t(AUTOMATE_TYPE.
|
|
130
|
+
text: t(AUTOMATE_TYPE.SCENARIO),
|
|
124
131
|
data: data.filter((item) => item.type !== AUTOMATE_TYPE.ONE_TAP),
|
|
125
132
|
type: AUTOMATE_TYPE.AUTOMATION,
|
|
126
133
|
},
|
|
@@ -298,6 +305,10 @@ const UnitDetail = ({ route }) => {
|
|
|
298
305
|
navigate(routeName);
|
|
299
306
|
}, [navigate, routeName]);
|
|
300
307
|
|
|
308
|
+
const Dashboard = useCallback(() => {
|
|
309
|
+
navigate(Routes.Dashboard);
|
|
310
|
+
}, [navigate]);
|
|
311
|
+
|
|
301
312
|
return (
|
|
302
313
|
<WrapParallaxScrollView
|
|
303
314
|
uriImg={unit.background}
|
|
@@ -310,7 +321,7 @@ const UnitDetail = ({ route }) => {
|
|
|
310
321
|
onAdd={setShowAdd}
|
|
311
322
|
onMore={showPopoverWithRef}
|
|
312
323
|
hideRightPlus={!isOwner}
|
|
313
|
-
onBack={routeName && onBack}
|
|
324
|
+
onBack={(isSuccessfullyConnected && Dashboard) || (routeName && onBack)}
|
|
314
325
|
>
|
|
315
326
|
<View style={styles.container}>
|
|
316
327
|
<Summaries unit={unit} />
|
|
@@ -14,9 +14,10 @@ import Routes from '../../utils/Route';
|
|
|
14
14
|
import { useNavigation } from '@react-navigation/native';
|
|
15
15
|
import { axiosDelete, axiosGet } from '../../utils/Apis/axios';
|
|
16
16
|
import { SmartAccountItem } from './SmartAccountItem';
|
|
17
|
-
import { usePopover } from '../../hooks/Common';
|
|
18
|
-
import { MenuActionMore } from '../../commons';
|
|
17
|
+
import { usePopover, useBoolean } from '../../hooks/Common';
|
|
18
|
+
import { MenuActionMore, AlertAction } from '../../commons';
|
|
19
19
|
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
20
|
+
import { useStateAlertRemove } from '../Unit/hook/useStateAlertRemove';
|
|
20
21
|
|
|
21
22
|
const ListSmartAccount = ({ route }) => {
|
|
22
23
|
const { unitId } = route?.params || {};
|
|
@@ -36,6 +37,9 @@ const ListSmartAccount = ({ route }) => {
|
|
|
36
37
|
|
|
37
38
|
const { childRef, showingPopover, showPopoverWithRef, hidePopover } =
|
|
38
39
|
usePopover();
|
|
40
|
+
const [lockShowing, acquireLockShowing, releaseLockShowing] = useBoolean();
|
|
41
|
+
const { stateAlertRemove, onShowRemoveAlert, hideAlertAction } =
|
|
42
|
+
useStateAlertRemove();
|
|
39
43
|
|
|
40
44
|
useEffect(() => {
|
|
41
45
|
getAllSmartAccounts();
|
|
@@ -50,29 +54,31 @@ const ListSmartAccount = ({ route }) => {
|
|
|
50
54
|
[showPopoverWithRef]
|
|
51
55
|
);
|
|
52
56
|
|
|
53
|
-
const deleteSmartAccount = useCallback(async () => {
|
|
54
|
-
if (!smartAccountRef?.current) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
const id = smartAccountRef.current.id;
|
|
58
|
-
const { success } = await axiosDelete(
|
|
59
|
-
API.SMART_ACCOUNT.REMOVE_SMART_ACCOUNT(id)
|
|
60
|
-
);
|
|
61
|
-
success && getAllSmartAccounts();
|
|
62
|
-
}, [getAllSmartAccounts]);
|
|
63
|
-
|
|
64
57
|
const onItemClick = useCallback(
|
|
65
58
|
(item) => {
|
|
66
59
|
if (!smartAccountRef?.current) {
|
|
67
60
|
return;
|
|
68
61
|
}
|
|
69
62
|
if (item.action === 'remove') {
|
|
70
|
-
|
|
63
|
+
acquireLockShowing();
|
|
64
|
+
onShowRemoveAlert(smartAccountRef.current.brand)();
|
|
71
65
|
}
|
|
72
66
|
},
|
|
73
|
-
[
|
|
67
|
+
[acquireLockShowing, onShowRemoveAlert]
|
|
74
68
|
);
|
|
75
69
|
|
|
70
|
+
const deleteSmartAccount = useCallback(async () => {
|
|
71
|
+
hideAlertAction();
|
|
72
|
+
if (!smartAccountRef?.current) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const id = smartAccountRef.current.id;
|
|
76
|
+
const { success } = await axiosDelete(
|
|
77
|
+
API.SMART_ACCOUNT.REMOVE_SMART_ACCOUNT(id)
|
|
78
|
+
);
|
|
79
|
+
success && getAllSmartAccounts();
|
|
80
|
+
}, [getAllSmartAccounts, hideAlertAction]);
|
|
81
|
+
|
|
76
82
|
const listMenuItem = useMemo(() => {
|
|
77
83
|
return [{ action: 'remove', text: t('remove_account') }];
|
|
78
84
|
}, [t]);
|
|
@@ -88,6 +94,7 @@ const ListSmartAccount = ({ route }) => {
|
|
|
88
94
|
},
|
|
89
95
|
[navigate, unitId]
|
|
90
96
|
);
|
|
97
|
+
|
|
91
98
|
return (
|
|
92
99
|
<View style={styles.wrap}>
|
|
93
100
|
<WrapHeaderScrollable
|
|
@@ -109,12 +116,26 @@ const ListSmartAccount = ({ route }) => {
|
|
|
109
116
|
);
|
|
110
117
|
})}
|
|
111
118
|
</View>
|
|
119
|
+
<AlertAction
|
|
120
|
+
visible={stateAlertRemove.visible && !lockShowing}
|
|
121
|
+
hideModal={hideAlertAction}
|
|
122
|
+
title={stateAlertRemove.title}
|
|
123
|
+
message={stateAlertRemove.message}
|
|
124
|
+
leftButtonTitle={stateAlertRemove.leftButton}
|
|
125
|
+
leftButtonClick={deleteSmartAccount}
|
|
126
|
+
rightButtonTitle={stateAlertRemove.rightButton}
|
|
127
|
+
rightButtonClick={hideAlertAction}
|
|
128
|
+
boxLeftButtonStyle={styles.boxButtonNotSelect}
|
|
129
|
+
boxRightButtonStyle={styles.boxButtonSelect}
|
|
130
|
+
rightButtonStyle={styles.textRightButton}
|
|
131
|
+
/>
|
|
112
132
|
<MenuActionMore
|
|
113
133
|
isVisible={showingPopover}
|
|
114
134
|
hideMore={hidePopover}
|
|
115
135
|
listMenuItem={listMenuItem}
|
|
116
136
|
childRef={childRef}
|
|
117
137
|
onItemClick={onItemClick}
|
|
138
|
+
hideComplete={releaseLockShowing}
|
|
118
139
|
/>
|
|
119
140
|
</WrapHeaderScrollable>
|
|
120
141
|
</View>
|
|
@@ -42,4 +42,24 @@ export default StyleSheet.create({
|
|
|
42
42
|
borderColor: Colors.ShadownTransparent,
|
|
43
43
|
borderTopWidth: 1,
|
|
44
44
|
},
|
|
45
|
+
boxButtonNotSelect: {
|
|
46
|
+
marginVertical: 16,
|
|
47
|
+
height: 45,
|
|
48
|
+
borderRadius: 30,
|
|
49
|
+
borderColor: Colors.Primary,
|
|
50
|
+
borderWidth: 1,
|
|
51
|
+
paddingVertical: 0,
|
|
52
|
+
},
|
|
53
|
+
boxButtonSelect: {
|
|
54
|
+
marginVertical: 16,
|
|
55
|
+
height: 45,
|
|
56
|
+
borderRadius: 30,
|
|
57
|
+
borderColor: Colors.Primary,
|
|
58
|
+
backgroundColor: Colors.Primary,
|
|
59
|
+
borderWidth: 1,
|
|
60
|
+
paddingVertical: 0,
|
|
61
|
+
},
|
|
62
|
+
textRightButton: {
|
|
63
|
+
color: Colors.White,
|
|
64
|
+
},
|
|
45
65
|
});
|
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { View } from 'react-native';
|
|
3
3
|
import { act, create } from 'react-test-renderer';
|
|
4
|
+
import { SCProvider } from '../../../../context';
|
|
5
|
+
import { mockSCStore } from '../../../../context/mockStore';
|
|
4
6
|
import MyUnitDevice from '../MyUnitDevice';
|
|
5
7
|
|
|
8
|
+
const wrapComponent = (sensor) => (
|
|
9
|
+
<SCProvider initState={mockSCStore({})}>
|
|
10
|
+
<MyUnitDevice sensor={sensor} />
|
|
11
|
+
</SCProvider>
|
|
12
|
+
);
|
|
13
|
+
|
|
6
14
|
describe('Test MyUnitDevice', () => {
|
|
7
15
|
let tree;
|
|
8
16
|
|
|
9
17
|
it('Test render with status', async () => {
|
|
10
18
|
await act(() => {
|
|
11
19
|
tree = create(
|
|
12
|
-
|
|
13
|
-
sensor={{ status: 'Ok', name: 'Test', station_name: '' }}
|
|
14
|
-
/>
|
|
20
|
+
wrapComponent({ status: 'Ok', name: 'Test', station_name: '' })
|
|
15
21
|
);
|
|
16
22
|
});
|
|
17
23
|
const instance = tree.root;
|
|
@@ -21,9 +27,7 @@ describe('Test MyUnitDevice', () => {
|
|
|
21
27
|
|
|
22
28
|
it('Test render without status', async () => {
|
|
23
29
|
await act(() => {
|
|
24
|
-
tree = create(
|
|
25
|
-
<MyUnitDevice sensor={{ name: 'Test', station_name: '' }} />
|
|
26
|
-
);
|
|
30
|
+
tree = create(wrapComponent({ name: 'Test', station_name: '' }));
|
|
27
31
|
});
|
|
28
32
|
const instance = tree.root;
|
|
29
33
|
const Views = instance.findAllByType(View);
|
|
@@ -5,10 +5,10 @@ export const useStateAlertRemove = () => {
|
|
|
5
5
|
const t = useTranslations();
|
|
6
6
|
const [stateAlertRemove, setStateAlertRemove] = useState({
|
|
7
7
|
visible: false,
|
|
8
|
-
title: t('
|
|
8
|
+
title: t('remove_account'),
|
|
9
9
|
message: '',
|
|
10
|
-
leftButton: t('
|
|
11
|
-
rightButton: t('
|
|
10
|
+
leftButton: t('yes_remove'),
|
|
11
|
+
rightButton: t('cancel'),
|
|
12
12
|
});
|
|
13
13
|
const hideAlertAction = useCallback(() => {
|
|
14
14
|
setStateAlertRemove((state) => ({
|
|
@@ -22,9 +22,7 @@ export const useStateAlertRemove = () => {
|
|
|
22
22
|
setStateAlertRemove((state) => ({
|
|
23
23
|
...state,
|
|
24
24
|
visible: true,
|
|
25
|
-
message:
|
|
26
|
-
text: brand === 'google_home' ? 'Điện Quang' : brand,
|
|
27
|
-
})}`,
|
|
25
|
+
message: t('this_action_will_remove_all_related_devices'),
|
|
28
26
|
}));
|
|
29
27
|
},
|
|
30
28
|
[t]
|
|
@@ -77,10 +77,8 @@ const PowerConsumption = memo(({ summaryDetail }) => {
|
|
|
77
77
|
const dataTotal = [];
|
|
78
78
|
dataTotal.push(totalPower);
|
|
79
79
|
|
|
80
|
-
const [startDate, setStartDate] = useState(
|
|
81
|
-
|
|
82
|
-
);
|
|
83
|
-
const [endDate, setEndDate] = useState(moment().valueOf());
|
|
80
|
+
const [startDate, setStartDate] = useState(moment().subtract(6, 'days'));
|
|
81
|
+
const [endDate, setEndDate] = useState(moment());
|
|
84
82
|
const [groupBy, setGroupBy] = useState('date');
|
|
85
83
|
const [getData, setData] = useState([]);
|
|
86
84
|
const [chartConfig, setChartConfig] = useState({
|
|
@@ -3,6 +3,14 @@ import { act, create } from 'react-test-renderer';
|
|
|
3
3
|
import RunningDevices from '..';
|
|
4
4
|
import { TouchableOpacity } from 'react-native';
|
|
5
5
|
import ItemDevice from '../../../../../commons/Device/ItemDevice';
|
|
6
|
+
import { mockSCStore } from '../../../../../context/mockStore';
|
|
7
|
+
import { SCProvider } from '../../../../../context';
|
|
8
|
+
|
|
9
|
+
const wrapComponent = (unit, summaryDetail) => (
|
|
10
|
+
<SCProvider initState={mockSCStore({})}>
|
|
11
|
+
<RunningDevices unit={unit} summaryDetail={summaryDetail} />
|
|
12
|
+
</SCProvider>
|
|
13
|
+
);
|
|
6
14
|
|
|
7
15
|
const mockedNavigate = jest.fn();
|
|
8
16
|
|
|
@@ -55,9 +63,7 @@ describe('test RunningDevices', () => {
|
|
|
55
63
|
};
|
|
56
64
|
|
|
57
65
|
await act(async () => {
|
|
58
|
-
tree = await create(
|
|
59
|
-
<RunningDevices unit={unit} summaryDetail={summaryDetail} />
|
|
60
|
-
);
|
|
66
|
+
tree = await create(wrapComponent(unit, summaryDetail));
|
|
61
67
|
});
|
|
62
68
|
const instance = tree.root;
|
|
63
69
|
const texts = instance.findAllByType(ItemDevice);
|
|
@@ -95,9 +101,7 @@ describe('test RunningDevices', () => {
|
|
|
95
101
|
};
|
|
96
102
|
|
|
97
103
|
await act(async () => {
|
|
98
|
-
tree = await create(
|
|
99
|
-
<RunningDevices unit={unit} summaryDetail={summaryDetail} />
|
|
100
|
-
);
|
|
104
|
+
tree = await create(wrapComponent(unit, summaryDetail));
|
|
101
105
|
});
|
|
102
106
|
const instance = tree.root;
|
|
103
107
|
const texts = instance.findAllByType(ItemDevice);
|