@eohjsc/react-native-smart-city 0.3.60 → 0.3.62
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/index.js +4 -2
- package/package.json +1 -1
- package/src/commons/Action/ItemQuickAction.js +9 -3
- package/src/commons/Device/PMSensor/PMSensorIndicatior.js +2 -1
- package/src/commons/Header/HeaderCustom.js +4 -1
- package/src/hooks/IoT/__test__/useRemoteControl.test.js +42 -0
- package/src/hooks/IoT/useRemoteControl.js +28 -9
- package/src/iot/RemoteControl/Bluetooth.js +4 -8
- package/src/navigations/AllGatewayStack.js +58 -0
- package/src/navigations/Main.js +197 -197
- package/src/navigations/UnitStack.js +8 -0
- package/src/screens/Device/components/SensorDisplayItem.js +10 -4
- package/src/screens/Gateway/__test__/index.test.js +8 -2
- package/src/screens/Gateway/index.js +36 -24
- package/src/screens/Gateway/styles.js +9 -1
- package/src/screens/Unit/MoreMenu.js +12 -1
- package/src/utils/Apis/axios.js +1 -1
- package/src/utils/I18n/translations/en.json +3 -1
- package/src/utils/I18n/translations/vi.json +3 -1
- package/src/utils/Route/index.js +2 -0
- package/src/utils/Utils.js +7 -0
package/index.js
CHANGED
|
@@ -19,8 +19,9 @@ import MyUnit from './src/commons/Dashboard/MyUnit';
|
|
|
19
19
|
import SharedUnit from './src/commons/Unit/SharedUnit';
|
|
20
20
|
import { Action } from './src/context/actionType';
|
|
21
21
|
import { withRemoteControl } from './src/hoc';
|
|
22
|
-
import DevModeStack from './src/navigations/Main';
|
|
22
|
+
// import DevModeStack from './src/navigations/Main';
|
|
23
23
|
import { SmartAccountStack } from './src/navigations/SmartAccountStack';
|
|
24
|
+
import { AllGatewayStack } from './src/navigations/AllGatewayStack';
|
|
24
25
|
|
|
25
26
|
export {
|
|
26
27
|
AddSubUnitStack,
|
|
@@ -46,6 +47,7 @@ export {
|
|
|
46
47
|
SCWrapper,
|
|
47
48
|
Action,
|
|
48
49
|
withRemoteControl,
|
|
49
|
-
DevModeStack,
|
|
50
|
+
// DevModeStack,
|
|
50
51
|
SmartAccountStack,
|
|
52
|
+
AllGatewayStack,
|
|
51
53
|
};
|
package/package.json
CHANGED
|
@@ -14,6 +14,7 @@ const ItemQuickAction = memo(({ sensor, wrapperStyle, setStatus }) => {
|
|
|
14
14
|
const [isOn, setIsOn] = useState(false);
|
|
15
15
|
|
|
16
16
|
const sendRemoteCommand = useRemoteControl();
|
|
17
|
+
const [processing, setProcessing] = useState(false);
|
|
17
18
|
|
|
18
19
|
useEffect(() => {
|
|
19
20
|
if (!(sensor.quick_action?.config_id in configValues)) {
|
|
@@ -38,7 +39,11 @@ const ItemQuickAction = memo(({ sensor, wrapperStyle, setStatus }) => {
|
|
|
38
39
|
}, [isOn, setStatus, sensor.quick_action]);
|
|
39
40
|
|
|
40
41
|
const userId = useSCContextSelector((state) => state?.auth.account.user.id);
|
|
41
|
-
const onActionPress = useCallback(() => {
|
|
42
|
+
const onActionPress = useCallback(async () => {
|
|
43
|
+
if (processing) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
setProcessing(true);
|
|
42
47
|
let data = null;
|
|
43
48
|
if (
|
|
44
49
|
action?.allow_config_store_value_id === sensor?.quick_action?.config_id
|
|
@@ -56,7 +61,7 @@ const ItemQuickAction = memo(({ sensor, wrapperStyle, setStatus }) => {
|
|
|
56
61
|
}
|
|
57
62
|
data = JSON.stringify(data);
|
|
58
63
|
}
|
|
59
|
-
sendRemoteCommand(sensor, action, data, userId);
|
|
64
|
+
await sendRemoteCommand(sensor, action, data, userId);
|
|
60
65
|
setIsSendingCommand(true);
|
|
61
66
|
|
|
62
67
|
if (!sensor.quick_action.will_auto_update_status) {
|
|
@@ -64,7 +69,8 @@ const ItemQuickAction = memo(({ sensor, wrapperStyle, setStatus }) => {
|
|
|
64
69
|
setIsOn(action.id === sensor.quick_action.on_action.id);
|
|
65
70
|
}, sensor.quick_action.interval);
|
|
66
71
|
}
|
|
67
|
-
|
|
72
|
+
setProcessing(false);
|
|
73
|
+
}, [processing, action, sensor, sendRemoteCommand, userId]);
|
|
68
74
|
|
|
69
75
|
if (!action) {
|
|
70
76
|
return <View />;
|
|
@@ -3,6 +3,7 @@ import { View } from 'react-native';
|
|
|
3
3
|
import { FlatList } from 'react-native';
|
|
4
4
|
import QualityIndicatorItem from '../WaterQualitySensor/QualityIndicatorsItem';
|
|
5
5
|
import styles from './PMSensorIndicatorStyles';
|
|
6
|
+
import { roundNumber } from '../../../utils/Utils';
|
|
6
7
|
|
|
7
8
|
//using for PM2.5-10, CO, UV, Rainflow Sensor
|
|
8
9
|
const keyExtractor = (item) => item.id.toString();
|
|
@@ -11,7 +12,7 @@ const PMSensorIndicatior = memo(({ data = [], style }) => {
|
|
|
11
12
|
({ item }) => {
|
|
12
13
|
const getValue = ['', null, undefined, NaN].includes(item?.value)
|
|
13
14
|
? '--'
|
|
14
|
-
: item?.value;
|
|
15
|
+
: roundNumber(item?.value);
|
|
15
16
|
return (
|
|
16
17
|
<QualityIndicatorItem
|
|
17
18
|
key={item.id.toString()}
|
|
@@ -28,6 +28,7 @@ const HeaderCustom = ({
|
|
|
28
28
|
isCanBack = true,
|
|
29
29
|
customTitle = false,
|
|
30
30
|
buttonBackStyles,
|
|
31
|
+
headerStyles,
|
|
31
32
|
}) => {
|
|
32
33
|
const t = useTranslations();
|
|
33
34
|
const { goBack } = useNavigation();
|
|
@@ -46,7 +47,9 @@ const HeaderCustom = ({
|
|
|
46
47
|
}, []);
|
|
47
48
|
|
|
48
49
|
return (
|
|
49
|
-
<View
|
|
50
|
+
<View
|
|
51
|
+
style={[styles.wrap, isShowSeparator && styles.separator, headerStyles]}
|
|
52
|
+
>
|
|
50
53
|
{isCanBack && (
|
|
51
54
|
<TouchableOpacity
|
|
52
55
|
style={[styles.buttonBack, buttonBackStyles]}
|
|
@@ -9,6 +9,7 @@ import { sendCommandOverHomeAssistant } from '../../../iot/RemoteControl/HomeAss
|
|
|
9
9
|
import { sendCommandOverInternet } from '../../../iot/RemoteControl/Internet';
|
|
10
10
|
import { SCProvider } from '../../../context';
|
|
11
11
|
import { mockSCStore } from '../../../context/mockStore';
|
|
12
|
+
import { ToastBottomHelper } from '../../../utils/Utils';
|
|
12
13
|
|
|
13
14
|
jest.mock('../../../iot/RemoteControl/Bluetooth');
|
|
14
15
|
jest.mock('../../../iot/RemoteControl/HomeAssistant');
|
|
@@ -112,6 +113,47 @@ describe('Test useRemoteControl', () => {
|
|
|
112
113
|
expect(sendCommandOverHomeAssistant).not.toBeCalled();
|
|
113
114
|
});
|
|
114
115
|
|
|
116
|
+
const testCommandViaBluetooth = async (
|
|
117
|
+
command_prefer_over_bluetooth,
|
|
118
|
+
command_prefer_over_internet
|
|
119
|
+
) => {
|
|
120
|
+
action.command_prefer_over_bluetooth = command_prefer_over_bluetooth;
|
|
121
|
+
action.command_prefer_over_internet = command_prefer_over_internet;
|
|
122
|
+
action.is_only_bluetooth = true;
|
|
123
|
+
const spyToastError = jest.spyOn(ToastBottomHelper, 'error');
|
|
124
|
+
|
|
125
|
+
const { result: sendRemoteCommand } = renderHook(() => useRemoteControl(), {
|
|
126
|
+
wrapper,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
sendCommandOverBluetooth.mockImplementation(() => {
|
|
130
|
+
throw SEND_COMMAND_OVER_BLUETOOTH_FAIL;
|
|
131
|
+
});
|
|
132
|
+
sendCommandOverInternet.mockImplementation(async () => true);
|
|
133
|
+
await act(async () => {
|
|
134
|
+
await sendRemoteCommand.current(sensor, action, data, userId);
|
|
135
|
+
});
|
|
136
|
+
expect(sendCommandOverBluetooth).toBeCalledWith(
|
|
137
|
+
sensor,
|
|
138
|
+
action,
|
|
139
|
+
data,
|
|
140
|
+
userId
|
|
141
|
+
);
|
|
142
|
+
expect(sendCommandOverInternet).not.toBeCalled();
|
|
143
|
+
expect(sendCommandOverHomeAssistant).not.toBeCalled();
|
|
144
|
+
expect(spyToastError).toBeCalled();
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
// eslint-disable-next-line max-len
|
|
148
|
+
it('test send remote command via bluetooth failed then not send via internet, action is only bluetooth, not prefer internet', async () => {
|
|
149
|
+
testCommandViaBluetooth(true, false);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// eslint-disable-next-line max-len
|
|
153
|
+
it('test send remote command via bluetooth failed then not send via internet, action is only bluetooth, prefer internet', async () => {
|
|
154
|
+
testCommandViaBluetooth(false, true);
|
|
155
|
+
});
|
|
156
|
+
|
|
115
157
|
it('test send remote command via bluetooth failed throw unhandled error', async () => {
|
|
116
158
|
const { result: sendRemoteCommand } = renderHook(() => useRemoteControl(), {
|
|
117
159
|
wrapper,
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
} from '../../iot/RemoteControl/Bluetooth';
|
|
9
9
|
import { ToastBottomHelper } from '../../utils/Utils';
|
|
10
10
|
import { t } from 'i18n-js';
|
|
11
|
+
import NetInfo from '@react-native-community/netinfo';
|
|
11
12
|
|
|
12
13
|
const useRemoteControl = () => {
|
|
13
14
|
const homeAssistantConnections = useSCContextSelector(
|
|
@@ -29,20 +30,38 @@ const useRemoteControl = () => {
|
|
|
29
30
|
try {
|
|
30
31
|
return await sendCommandOverBluetooth(device, action, data, userId);
|
|
31
32
|
} catch (err) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
const netState = await NetInfo.fetch();
|
|
34
|
+
if (netState.isConnected) {
|
|
35
|
+
result = false;
|
|
36
|
+
|
|
37
|
+
if (err === SEND_COMMAND_OVER_BLUETOOTH_FAIL) {
|
|
38
|
+
// Checking only bluetooth: not force internet
|
|
39
|
+
if (!action.is_only_bluetooth) {
|
|
40
|
+
result = await sendCommandOverInternet(
|
|
41
|
+
device,
|
|
42
|
+
action,
|
|
43
|
+
data,
|
|
44
|
+
'bluetooth'
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
} else {
|
|
49
|
+
throw err;
|
|
50
|
+
}
|
|
40
51
|
} else {
|
|
41
|
-
|
|
52
|
+
return false;
|
|
42
53
|
}
|
|
43
54
|
}
|
|
44
55
|
}
|
|
45
56
|
|
|
57
|
+
// Checking only bluetooth: not other options
|
|
58
|
+
if (action.is_only_bluetooth) {
|
|
59
|
+
ToastBottomHelper.error(
|
|
60
|
+
t('this_command_is_just_support_bluetooth_only')
|
|
61
|
+
);
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
|
|
46
65
|
if (action.command_prefer_over_internet) {
|
|
47
66
|
return await sendCommandOverInternet(
|
|
48
67
|
device,
|
|
@@ -140,7 +140,7 @@ export const sendDataOverBluetooth = async (
|
|
|
140
140
|
let connectedDevice = null;
|
|
141
141
|
let fullDataDevice = null;
|
|
142
142
|
let result = true;
|
|
143
|
-
|
|
143
|
+
|
|
144
144
|
try {
|
|
145
145
|
connectedDevice = await device.connect();
|
|
146
146
|
fullDataDevice =
|
|
@@ -148,15 +148,15 @@ export const sendDataOverBluetooth = async (
|
|
|
148
148
|
await fullDataDevice.monitorCharacteristicForService(
|
|
149
149
|
BLE.BLE_REMOTE_SERVICE_UUID,
|
|
150
150
|
BLE.BLE_REMOTE_CHARACTERISTIC_UUID_TX,
|
|
151
|
-
(error, characteristic) => {
|
|
151
|
+
async (error, characteristic) => {
|
|
152
152
|
const notify = error ? '' : base64.decode(characteristic.value);
|
|
153
153
|
if (notify === BLE.BLE_RESPONSE_OK) {
|
|
154
154
|
ToastBottomHelper.success(
|
|
155
155
|
t('control_device_via_bluetooth_successfully')
|
|
156
156
|
);
|
|
157
157
|
if (!keepConnect) {
|
|
158
|
-
bleManager.cancelTransaction(BLE.BLE_LISTER_RESPONSE_CONTROL);
|
|
159
|
-
device.
|
|
158
|
+
await bleManager.cancelTransaction(BLE.BLE_LISTER_RESPONSE_CONTROL);
|
|
159
|
+
await bleManager.cancelDeviceConnection(device.id);
|
|
160
160
|
}
|
|
161
161
|
} else if (notify === BLE.BLE_RESPONSE_FAILED) {
|
|
162
162
|
ToastBottomHelper.error(t('control_device_via_bluetooth_failed'));
|
|
@@ -179,10 +179,6 @@ export const sendDataOverBluetooth = async (
|
|
|
179
179
|
return result;
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
-
const timeout = setTimeout(() => {
|
|
183
|
-
device.cancelConnection();
|
|
184
|
-
clearTimeout(timeout);
|
|
185
|
-
}, responseTime);
|
|
186
182
|
return result;
|
|
187
183
|
};
|
|
188
184
|
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import React, { memo } from 'react';
|
|
2
|
+
import { createStackNavigator } from '@react-navigation/stack';
|
|
3
|
+
|
|
4
|
+
import GatewayDetail from '../screens/Gateway/GatewayDetail';
|
|
5
|
+
import GatewayInfo from '../screens/Gateway/GatewayInfo';
|
|
6
|
+
import GatewayConnectionMethods from '../screens/Gateway/GatewayConnectionMethods';
|
|
7
|
+
import DeviceZigbeeDetail from '../screens/Gateway/DeviceZigbeeDetail';
|
|
8
|
+
import DeviceGatewayInfo from '../screens/Gateway/DeviceGatewayInfo';
|
|
9
|
+
import DetailConfigActionZigbee from '../screens/Gateway/DetailConfigActionZigbee';
|
|
10
|
+
import DeviceModbusDetail from '../screens/Gateway/DeviceModbusDetail';
|
|
11
|
+
import DetailConfigActionModbus from '../screens/Gateway/DetailConfigActionModbus';
|
|
12
|
+
import DetailChildConfigActionModbus from '../screens/Gateway/DetailConfigActionModbus';
|
|
13
|
+
import Route from '../utils/Route'; // utils/Route
|
|
14
|
+
import { screenOptions } from './utils';
|
|
15
|
+
|
|
16
|
+
const Stack = createStackNavigator();
|
|
17
|
+
|
|
18
|
+
export const AllGatewayStack = memo(() => {
|
|
19
|
+
return (
|
|
20
|
+
<Stack.Navigator
|
|
21
|
+
screenOptions={{
|
|
22
|
+
...screenOptions,
|
|
23
|
+
headerShown: false,
|
|
24
|
+
}}
|
|
25
|
+
>
|
|
26
|
+
<Stack.Screen component={GatewayDetail} name={Route.GatewayDetail} />
|
|
27
|
+
<Stack.Screen component={GatewayInfo} name={Route.GatewayInfo} />
|
|
28
|
+
<Stack.Screen
|
|
29
|
+
component={DeviceGatewayInfo}
|
|
30
|
+
name={Route.DeviceGatewayInfo}
|
|
31
|
+
/>
|
|
32
|
+
<Stack.Screen
|
|
33
|
+
component={GatewayConnectionMethods}
|
|
34
|
+
name={Route.GatewayConnectionMethods}
|
|
35
|
+
/>
|
|
36
|
+
<Stack.Screen
|
|
37
|
+
component={DeviceZigbeeDetail}
|
|
38
|
+
name={Route.DeviceZigbeeDetail}
|
|
39
|
+
/>
|
|
40
|
+
<Stack.Screen
|
|
41
|
+
component={DeviceModbusDetail}
|
|
42
|
+
name={Route.DeviceModbusDetail}
|
|
43
|
+
/>
|
|
44
|
+
<Stack.Screen
|
|
45
|
+
component={DetailConfigActionZigbee}
|
|
46
|
+
name={Route.DetailConfigActionZigbee}
|
|
47
|
+
/>
|
|
48
|
+
<Stack.Screen
|
|
49
|
+
component={DetailConfigActionModbus}
|
|
50
|
+
name={Route.DetailConfigActionModbus}
|
|
51
|
+
/>
|
|
52
|
+
<Stack.Screen
|
|
53
|
+
component={DetailChildConfigActionModbus}
|
|
54
|
+
name={Route.DetailChildConfigActionModbus}
|
|
55
|
+
/>
|
|
56
|
+
</Stack.Navigator>
|
|
57
|
+
);
|
|
58
|
+
});
|
package/src/navigations/Main.js
CHANGED
|
@@ -1,209 +1,209 @@
|
|
|
1
|
-
import React, { useMemo, useRef } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from 'react-native';
|
|
9
|
-
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
|
|
10
|
-
import { createDrawerNavigator } from '@react-navigation/drawer';
|
|
11
|
-
import { useNavigation } from '@react-navigation/native';
|
|
12
|
-
import { getStatusBarHeight } from 'react-native-iphone-x-helper';
|
|
13
|
-
import { createStackNavigator } from '@react-navigation/stack';
|
|
1
|
+
// import React, { useMemo, useRef } from 'react';
|
|
2
|
+
// import {
|
|
3
|
+
// Animated,
|
|
4
|
+
// View,
|
|
5
|
+
// TouchableOpacity,
|
|
6
|
+
// StyleSheet,
|
|
7
|
+
// Image,
|
|
8
|
+
// } from 'react-native';
|
|
9
|
+
// import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
|
|
10
|
+
// import { createDrawerNavigator } from '@react-navigation/drawer';
|
|
11
|
+
// import { useNavigation } from '@react-navigation/native';
|
|
12
|
+
// import { getStatusBarHeight } from 'react-native-iphone-x-helper';
|
|
13
|
+
// import { createStackNavigator } from '@react-navigation/stack';
|
|
14
14
|
|
|
15
|
-
import Tabbar from '../commons/Tabbar';
|
|
16
|
-
import { Colors, Constants, Images } from '../configs';
|
|
17
|
-
import t from '../hooks/Common/useTranslations';
|
|
18
|
-
import Routes from '../utils/Route';
|
|
19
|
-
import GatewayStack from './GatewayStack';
|
|
20
|
-
import SmartStack from './SmartStack';
|
|
21
|
-
import TemplateStack from './TemplateStack';
|
|
22
|
-
import DrawerContainer from '../screens/Drawer';
|
|
23
|
-
import { AccessibilityLabel } from '../configs/Constants';
|
|
24
|
-
import Text from '../commons/Text';
|
|
25
|
-
import { screenOptions } from './utils';
|
|
26
|
-
import TemplateDetail from '../screens/Template/detail';
|
|
27
|
-
import Information from '../screens/Template/Information';
|
|
28
|
-
import GatewayList from '../screens/Template/GatewayList';
|
|
29
|
-
import EditTemplate from '../screens/Template/EditTemplate';
|
|
30
|
-
import GatewayDetail from '../screens/Gateway/GatewayDetail';
|
|
31
|
-
import GatewayInfo from '../screens/Gateway/GatewayInfo';
|
|
32
|
-
import GatewayConnectionMethods from '../screens/Gateway/GatewayConnectionMethods';
|
|
33
|
-
import DeviceZigbeeDetail from '../screens/Gateway/DeviceZigbeeDetail';
|
|
34
|
-
import DeviceGatewayInfo from '../screens/Gateway/DeviceGatewayInfo';
|
|
35
|
-
import DetailConfigActionZigbee from '../screens/Gateway/DetailConfigActionZigbee';
|
|
36
|
-
import DeviceModbusDetail from '../screens/Gateway/DeviceModbusDetail';
|
|
37
|
-
import DetailConfigActionModbus from '../screens/Gateway/DetailConfigActionModbus';
|
|
38
|
-
import DetailChildConfigActionModbus from '../screens/Gateway/DetailConfigActionModbus';
|
|
39
|
-
import { useBlockBackAndroid } from '../hooks/Common';
|
|
15
|
+
// import Tabbar from '../commons/Tabbar';
|
|
16
|
+
// import { Colors, Constants, Images } from '../configs';
|
|
17
|
+
// import t from '../hooks/Common/useTranslations';
|
|
18
|
+
// import Routes from '../utils/Route';
|
|
19
|
+
// import GatewayStack from './GatewayStack';
|
|
20
|
+
// import SmartStack from './SmartStack';
|
|
21
|
+
// import TemplateStack from './TemplateStack';
|
|
22
|
+
// import DrawerContainer from '../screens/Drawer';
|
|
23
|
+
// import { AccessibilityLabel } from '../configs/Constants';
|
|
24
|
+
// import Text from '../commons/Text';
|
|
25
|
+
// import { screenOptions } from './utils';
|
|
26
|
+
// import TemplateDetail from '../screens/Template/detail';
|
|
27
|
+
// import Information from '../screens/Template/Information';
|
|
28
|
+
// import GatewayList from '../screens/Template/GatewayList';
|
|
29
|
+
// import EditTemplate from '../screens/Template/EditTemplate';
|
|
30
|
+
// import GatewayDetail from '../screens/Gateway/GatewayDetail';
|
|
31
|
+
// import GatewayInfo from '../screens/Gateway/GatewayInfo';
|
|
32
|
+
// import GatewayConnectionMethods from '../screens/Gateway/GatewayConnectionMethods';
|
|
33
|
+
// import DeviceZigbeeDetail from '../screens/Gateway/DeviceZigbeeDetail';
|
|
34
|
+
// import DeviceGatewayInfo from '../screens/Gateway/DeviceGatewayInfo';
|
|
35
|
+
// import DetailConfigActionZigbee from '../screens/Gateway/DetailConfigActionZigbee';
|
|
36
|
+
// import DeviceModbusDetail from '../screens/Gateway/DeviceModbusDetail';
|
|
37
|
+
// import DetailConfigActionModbus from '../screens/Gateway/DetailConfigActionModbus';
|
|
38
|
+
// import DetailChildConfigActionModbus from '../screens/Gateway/DetailConfigActionModbus';
|
|
39
|
+
// import { useBlockBackAndroid } from '../hooks/Common';
|
|
40
40
|
|
|
41
|
-
const Tab = createBottomTabNavigator();
|
|
42
|
-
const Drawer = createDrawerNavigator();
|
|
43
|
-
const Stack = createStackNavigator();
|
|
41
|
+
// const Tab = createBottomTabNavigator();
|
|
42
|
+
// const Drawer = createDrawerNavigator();
|
|
43
|
+
// const Stack = createStackNavigator();
|
|
44
44
|
|
|
45
|
-
const getWidth = () => {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
};
|
|
45
|
+
// const getWidth = () => {
|
|
46
|
+
// const Width = Constants.width - 12;
|
|
47
|
+
// return Width / 3;
|
|
48
|
+
// };
|
|
49
49
|
|
|
50
|
-
const MainDevMode = () => {
|
|
51
|
-
|
|
50
|
+
// const MainDevMode = () => {
|
|
51
|
+
// const navigation = useNavigation();
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
53
|
+
// const listTabName = useMemo(
|
|
54
|
+
// () => [
|
|
55
|
+
// {
|
|
56
|
+
// name: Routes.TemplateStack,
|
|
57
|
+
// tabBarLabel: t('dashboard'),
|
|
58
|
+
// component: TemplateStack,
|
|
59
|
+
// },
|
|
60
|
+
// {
|
|
61
|
+
// name: Routes.GatewayStack,
|
|
62
|
+
// tabBarLabel: t('gateways'),
|
|
63
|
+
// component: GatewayStack,
|
|
64
|
+
// },
|
|
65
|
+
// {
|
|
66
|
+
// name: Routes.SmartStack,
|
|
67
|
+
// tabBarLabel: t('smart'),
|
|
68
|
+
// component: SmartStack,
|
|
69
|
+
// },
|
|
70
|
+
// ],
|
|
71
|
+
// []
|
|
72
|
+
// );
|
|
73
73
|
|
|
74
|
-
|
|
74
|
+
// const tabOffSetValue = useRef(new Animated.Value(0)).current;
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
76
|
+
// const Header = () => {
|
|
77
|
+
// return (
|
|
78
|
+
// <View style={styles.wrapHeader}>
|
|
79
|
+
// <TouchableOpacity
|
|
80
|
+
// style={styles.btnMenu}
|
|
81
|
+
// onPress={() => navigation.toggleDrawer()}
|
|
82
|
+
// accessibilityLabel={AccessibilityLabel.BURGER_MENU_ICON}
|
|
83
|
+
// >
|
|
84
|
+
// <Image source={Images.menu} style={styles.menu} />
|
|
85
|
+
// </TouchableOpacity>
|
|
86
|
+
// <Text style={styles.textHeader}>{t('developer_mode')}</Text>
|
|
87
|
+
// </View>
|
|
88
|
+
// );
|
|
89
|
+
// };
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
};
|
|
91
|
+
// return (
|
|
92
|
+
// <>
|
|
93
|
+
// <Header />
|
|
94
|
+
// <Tab.Navigator tabBar={(props) => <Tabbar {...props} />}>
|
|
95
|
+
// {listTabName.map((item) => (
|
|
96
|
+
// <Tab.Screen
|
|
97
|
+
// name={item.name}
|
|
98
|
+
// component={item.component}
|
|
99
|
+
// options={{
|
|
100
|
+
// tabBarLabel: item.tabBarLabel,
|
|
101
|
+
// tabOffSetValue,
|
|
102
|
+
// }}
|
|
103
|
+
// />
|
|
104
|
+
// ))}
|
|
105
|
+
// </Tab.Navigator>
|
|
106
|
+
// <Animated.View
|
|
107
|
+
// // eslint-disable-next-line react-native/no-inline-styles
|
|
108
|
+
// style={{
|
|
109
|
+
// width: getWidth() - 4,
|
|
110
|
+
// transform: [{ translateX: tabOffSetValue }],
|
|
111
|
+
// height: 2,
|
|
112
|
+
// backgroundColor: Colors.Primary,
|
|
113
|
+
// position: 'absolute',
|
|
114
|
+
// bottom: 70,
|
|
115
|
+
// left: 8,
|
|
116
|
+
// borderRadius: 1,
|
|
117
|
+
// }}
|
|
118
|
+
// />
|
|
119
|
+
// </>
|
|
120
|
+
// );
|
|
121
|
+
// };
|
|
122
122
|
|
|
123
|
-
const DrawerScreen = () => {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
};
|
|
123
|
+
// const DrawerScreen = () => {
|
|
124
|
+
// useBlockBackAndroid();
|
|
125
|
+
// return (
|
|
126
|
+
// <Drawer.Navigator
|
|
127
|
+
// backBehavior="none"
|
|
128
|
+
// drawerContent={(props) => <DrawerContainer {...props} />}
|
|
129
|
+
// drawerStyle={{ paddingTop: getStatusBarHeight() }}
|
|
130
|
+
// >
|
|
131
|
+
// <Drawer.Screen name={Routes.MainDevMode} component={MainDevMode} />
|
|
132
|
+
// </Drawer.Navigator>
|
|
133
|
+
// );
|
|
134
|
+
// };
|
|
135
135
|
|
|
136
|
-
const DevModeStack = () => {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
};
|
|
136
|
+
// const DevModeStack = () => {
|
|
137
|
+
// return (
|
|
138
|
+
// <Stack.Navigator
|
|
139
|
+
// screenOptions={{
|
|
140
|
+
// ...screenOptions,
|
|
141
|
+
// headerShown: false,
|
|
142
|
+
// }}
|
|
143
|
+
// >
|
|
144
|
+
// <Stack.Screen component={DrawerScreen} name={Routes.DrawerScreen} />
|
|
145
|
+
// <Stack.Screen component={TemplateDetail} name={Routes.TemplateDetail} />
|
|
146
|
+
// <Stack.Screen component={GatewayDetail} name={Routes.GatewayDetail} />
|
|
147
|
+
// <Stack.Screen component={GatewayInfo} name={Routes.GatewayInfo} />
|
|
148
|
+
// <Stack.Screen
|
|
149
|
+
// component={DeviceGatewayInfo}
|
|
150
|
+
// name={Routes.DeviceGatewayInfo}
|
|
151
|
+
// />
|
|
152
|
+
// <Stack.Screen
|
|
153
|
+
// component={GatewayConnectionMethods}
|
|
154
|
+
// name={Routes.GatewayConnectionMethods}
|
|
155
|
+
// />
|
|
156
|
+
// <Stack.Screen
|
|
157
|
+
// component={DeviceZigbeeDetail}
|
|
158
|
+
// name={Routes.DeviceZigbeeDetail}
|
|
159
|
+
// />
|
|
160
|
+
// <Stack.Screen
|
|
161
|
+
// component={DeviceModbusDetail}
|
|
162
|
+
// name={Routes.DeviceModbusDetail}
|
|
163
|
+
// />
|
|
164
|
+
// <Stack.Screen
|
|
165
|
+
// component={DetailConfigActionZigbee}
|
|
166
|
+
// name={Routes.DetailConfigActionZigbee}
|
|
167
|
+
// />
|
|
168
|
+
// <Stack.Screen
|
|
169
|
+
// component={DetailConfigActionModbus}
|
|
170
|
+
// name={Routes.DetailConfigActionModbus}
|
|
171
|
+
// />
|
|
172
|
+
// <Stack.Screen
|
|
173
|
+
// component={DetailChildConfigActionModbus}
|
|
174
|
+
// name={Routes.DetailChildConfigActionModbus}
|
|
175
|
+
// />
|
|
176
|
+
// <Stack.Screen component={Information} name={Routes.Information} />
|
|
177
|
+
// <Stack.Screen component={GatewayList} name={Routes.GatewayList} />
|
|
178
|
+
// <Stack.Screen component={EditTemplate} name={Routes.EditTemplate} />
|
|
179
|
+
// </Stack.Navigator>
|
|
180
|
+
// );
|
|
181
|
+
// };
|
|
182
182
|
|
|
183
|
-
export default DevModeStack;
|
|
183
|
+
// export default DevModeStack;
|
|
184
184
|
|
|
185
|
-
const styles = StyleSheet.create({
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
});
|
|
185
|
+
// const styles = StyleSheet.create({
|
|
186
|
+
// btnMenu: {
|
|
187
|
+
// width: 40,
|
|
188
|
+
// height: 40,
|
|
189
|
+
// justifyContent: 'center',
|
|
190
|
+
// alignItems: 'center',
|
|
191
|
+
// marginLeft: 10,
|
|
192
|
+
// },
|
|
193
|
+
// wrapHeader: {
|
|
194
|
+
// height: 100,
|
|
195
|
+
// paddingTop: getStatusBarHeight(),
|
|
196
|
+
// flexDirection: 'row',
|
|
197
|
+
// alignItems: 'center',
|
|
198
|
+
// backgroundColor: Colors.Gray2,
|
|
199
|
+
// },
|
|
200
|
+
// textHeader: {
|
|
201
|
+
// fontSize: 20,
|
|
202
|
+
// fontWeight: 'bold',
|
|
203
|
+
// color: Colors.Gray9,
|
|
204
|
+
// },
|
|
205
|
+
// menu: {
|
|
206
|
+
// width: 24,
|
|
207
|
+
// height: 24,
|
|
208
|
+
// },
|
|
209
|
+
// });
|
|
@@ -53,6 +53,7 @@ import EmergencySetting from '../screens/EmergencySetting';
|
|
|
53
53
|
import ConfirmUnitDeletion from '../screens/ConfirmUnitDeletion';
|
|
54
54
|
import InfoMemberUnit from '../screens/Sharing/InfoMemberUnit';
|
|
55
55
|
import EnterPassword from '../screens/EnterPassword';
|
|
56
|
+
import AllGateway from '../screens/Gateway';
|
|
56
57
|
import SelectAddToFavorites from '../screens/Unit/SelectAddToFavorites';
|
|
57
58
|
import { HanetCameraStack } from './HanetCameraStack';
|
|
58
59
|
import { axiosGet, fetchWithCache } from '../utils/Apis/axios';
|
|
@@ -462,6 +463,13 @@ export const UnitStack = memo((props) => {
|
|
|
462
463
|
headerShown: false,
|
|
463
464
|
}}
|
|
464
465
|
/>
|
|
466
|
+
<Stack.Screen
|
|
467
|
+
name={Route.AllGateway}
|
|
468
|
+
component={AllGateway}
|
|
469
|
+
options={{
|
|
470
|
+
headerShown: false,
|
|
471
|
+
}}
|
|
472
|
+
/>
|
|
465
473
|
</Stack.Navigator>
|
|
466
474
|
);
|
|
467
475
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useCallback } from 'react';
|
|
1
|
+
import React, { useCallback, useState } from 'react';
|
|
2
2
|
import { View } from 'react-native';
|
|
3
3
|
import ActionGroup from '../../../commons/ActionGroup';
|
|
4
4
|
import { CardDevMode } from '../../../commons/DevMode';
|
|
@@ -46,17 +46,23 @@ export const SensorDisplayItem = ({
|
|
|
46
46
|
const { isEditingTemplate } = useSCContextSelector((state) => state.devMode);
|
|
47
47
|
|
|
48
48
|
const sendRemoteCommand = useRemoteControl();
|
|
49
|
+
const [processing, setProcessing] = useState(false);
|
|
49
50
|
|
|
50
51
|
const doAction = useCallback(
|
|
51
|
-
(action, data) => {
|
|
52
|
-
|
|
52
|
+
async (action, data) => {
|
|
53
|
+
if (processing) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
setProcessing(true);
|
|
57
|
+
await sendRemoteCommand(
|
|
53
58
|
isEditingTemplate ? action?.end_device : sensor,
|
|
54
59
|
action,
|
|
55
60
|
data,
|
|
56
61
|
userId
|
|
57
62
|
);
|
|
63
|
+
setProcessing(false);
|
|
58
64
|
},
|
|
59
|
-
[isEditingTemplate, sensor,
|
|
65
|
+
[processing, sendRemoteCommand, isEditingTemplate, sensor, userId]
|
|
60
66
|
);
|
|
61
67
|
|
|
62
68
|
if (type === 'compass') {
|
|
@@ -65,8 +65,14 @@ describe('Test Gateway screen', () => {
|
|
|
65
65
|
await act(async () => {
|
|
66
66
|
await gatewayItems[0].props.onPress();
|
|
67
67
|
});
|
|
68
|
-
expect(mockNavigate).toBeCalledWith(Routes.
|
|
69
|
-
|
|
68
|
+
expect(mockNavigate).toBeCalledWith(Routes.AllGatewayStack, {
|
|
69
|
+
params: {
|
|
70
|
+
item: {
|
|
71
|
+
id: 1,
|
|
72
|
+
name: 'device 1',
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
screen: 'GatewayDetail',
|
|
70
76
|
});
|
|
71
77
|
});
|
|
72
78
|
|
|
@@ -9,6 +9,7 @@ import { useGateway } from './hooks/useGateway';
|
|
|
9
9
|
import { AccessibilityLabel } from '../../configs/Constants';
|
|
10
10
|
import Routes from '../../utils/Route';
|
|
11
11
|
import styles from './styles';
|
|
12
|
+
import { HeaderCustom } from '../../commons/Header';
|
|
12
13
|
|
|
13
14
|
const Gateway = ({ route }) => {
|
|
14
15
|
const t = useTranslations();
|
|
@@ -25,7 +26,10 @@ const Gateway = ({ route }) => {
|
|
|
25
26
|
|
|
26
27
|
const goGoDetail = useCallback(
|
|
27
28
|
(item) => () => {
|
|
28
|
-
navigate(Routes.
|
|
29
|
+
navigate(Routes.AllGatewayStack, {
|
|
30
|
+
screen: Routes.GatewayDetail,
|
|
31
|
+
params: { item },
|
|
32
|
+
});
|
|
29
33
|
},
|
|
30
34
|
[navigate]
|
|
31
35
|
);
|
|
@@ -66,30 +70,38 @@ const Gateway = ({ route }) => {
|
|
|
66
70
|
}, [isFocused, fetchDataGateways]);
|
|
67
71
|
|
|
68
72
|
return (
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
<FlatList
|
|
76
|
-
onRefresh={onRefresh}
|
|
77
|
-
refreshing={refresh}
|
|
78
|
-
columnWrapperStyle={styles.spaceBetween}
|
|
79
|
-
showsVerticalScrollIndicator={false}
|
|
80
|
-
showsHorizontalScrollIndicator={false}
|
|
81
|
-
contentContainerStyle={[
|
|
82
|
-
styles.contentContainerStyle,
|
|
83
|
-
gatewaysSearched?.length === 0 && styles.flex1,
|
|
84
|
-
]}
|
|
85
|
-
keyExtractor={(item) => item?.id}
|
|
86
|
-
data={gatewaysSearched}
|
|
87
|
-
renderItem={renderItem}
|
|
88
|
-
extraData={gatewaysSearched}
|
|
89
|
-
ListEmptyComponent={renderListEmptyComponent}
|
|
90
|
-
numColumns={2}
|
|
73
|
+
<>
|
|
74
|
+
<HeaderCustom
|
|
75
|
+
title={t('all_gateway')}
|
|
76
|
+
titleStyles={styles.titleLeft}
|
|
77
|
+
buttonBackStyles={styles.buttonBackStyles}
|
|
78
|
+
headerStyles={styles.header}
|
|
91
79
|
/>
|
|
92
|
-
|
|
80
|
+
<View
|
|
81
|
+
style={styles.wrap}
|
|
82
|
+
accessibilityLabel={AccessibilityLabel.LIST_GATEWAY}
|
|
83
|
+
>
|
|
84
|
+
<Label name={t('gateway')} />
|
|
85
|
+
<Search onSearch={setNameSearch} />
|
|
86
|
+
<FlatList
|
|
87
|
+
onRefresh={onRefresh}
|
|
88
|
+
refreshing={refresh}
|
|
89
|
+
columnWrapperStyle={styles.spaceBetween}
|
|
90
|
+
showsVerticalScrollIndicator={false}
|
|
91
|
+
showsHorizontalScrollIndicator={false}
|
|
92
|
+
contentContainerStyle={[
|
|
93
|
+
styles.contentContainerStyle,
|
|
94
|
+
gatewaysSearched?.length === 0 && styles.flex1,
|
|
95
|
+
]}
|
|
96
|
+
keyExtractor={(item) => item?.id}
|
|
97
|
+
data={gatewaysSearched}
|
|
98
|
+
renderItem={renderItem}
|
|
99
|
+
extraData={gatewaysSearched}
|
|
100
|
+
ListEmptyComponent={renderListEmptyComponent}
|
|
101
|
+
numColumns={2}
|
|
102
|
+
/>
|
|
103
|
+
</View>
|
|
104
|
+
</>
|
|
93
105
|
);
|
|
94
106
|
};
|
|
95
107
|
|
|
@@ -4,7 +4,6 @@ import { Colors } from '../../configs';
|
|
|
4
4
|
export default StyleSheet.create({
|
|
5
5
|
wrap: {
|
|
6
6
|
flex: 1,
|
|
7
|
-
paddingTop: 16,
|
|
8
7
|
paddingHorizontal: 16,
|
|
9
8
|
backgroundColor: Colors.White,
|
|
10
9
|
},
|
|
@@ -29,4 +28,13 @@ export default StyleSheet.create({
|
|
|
29
28
|
flex1: {
|
|
30
29
|
flex: 1,
|
|
31
30
|
},
|
|
31
|
+
titleLeft: {
|
|
32
|
+
textAlign: 'left',
|
|
33
|
+
},
|
|
34
|
+
buttonBackStyles: {
|
|
35
|
+
marginRight: 24,
|
|
36
|
+
},
|
|
37
|
+
header: {
|
|
38
|
+
backgroundColor: Colors.White,
|
|
39
|
+
},
|
|
32
40
|
});
|
|
@@ -44,8 +44,19 @@ const MoreMenu = ({
|
|
|
44
44
|
text: t('smart_account'),
|
|
45
45
|
data: { unitId: unit?.id, unit },
|
|
46
46
|
};
|
|
47
|
+
const RouteAllGateway = {
|
|
48
|
+
id: 'all-gateway',
|
|
49
|
+
route: Routes.AllGateway,
|
|
50
|
+
text: t('all_gateway'),
|
|
51
|
+
data: { unitId: unit?.id, unit },
|
|
52
|
+
};
|
|
47
53
|
return isOwner
|
|
48
|
-
? [
|
|
54
|
+
? [
|
|
55
|
+
RouteManageUnit,
|
|
56
|
+
RouteUnitMemberList,
|
|
57
|
+
ListSmartAccount,
|
|
58
|
+
RouteAllGateway,
|
|
59
|
+
]
|
|
49
60
|
: [RouteUnitMemberList];
|
|
50
61
|
}, [t, unit, isOwner]);
|
|
51
62
|
|
package/src/utils/Apis/axios.js
CHANGED
|
@@ -50,7 +50,7 @@ const shouldHideError = async (message) => {
|
|
|
50
50
|
return true;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
if (message === 'Network Error') {
|
|
53
|
+
if (message === 'Network Error' || message === PROBLEM_CODE.NETWORK_ERROR) {
|
|
54
54
|
const netState = await NetInfo.fetch();
|
|
55
55
|
if (!netState.isConnected) {
|
|
56
56
|
return true;
|
|
@@ -1106,5 +1106,7 @@
|
|
|
1106
1106
|
"text_alert_modal_popup_ct": "It’s a critical action and cannot be undone.",
|
|
1107
1107
|
"text_understand_modal_popup_ct": "I fully understand that this action is critical and will lead to data loss.",
|
|
1108
1108
|
"cannot_find_device_wifi": "Cannot find Device's Wifi",
|
|
1109
|
-
"
|
|
1109
|
+
"this_command_is_just_support_bluetooth_only": "This command is just support bluetooth only",
|
|
1110
|
+
"photo_request_permission_des": "To select photo from gallery, please unlock access photo permission",
|
|
1111
|
+
"all_gateway": "All Gateway"
|
|
1110
1112
|
}
|
|
@@ -1105,5 +1105,7 @@
|
|
|
1105
1105
|
"text_working_hard": "Chúng tôi đang làm việc chăm chỉ để làm cho điều này hoạt động",
|
|
1106
1106
|
"photo_request_permission": "Quyền yêu cầu ảnh",
|
|
1107
1107
|
"cannot_find_device_wifi": "Không thể tìm thấy Wifi của thiết bị",
|
|
1108
|
-
"
|
|
1108
|
+
"this_command_is_just_support_bluetooth_only": "Lệnh gửi này chỉ hỗ trợ bluetooth",
|
|
1109
|
+
"photo_request_permission_des": "Để chọn ảnh từ thư viện, vui lòng mở khóa quyền truy cập ảnh",
|
|
1110
|
+
"all_gateway": "Tất cả cổng kết nối"
|
|
1109
1111
|
}
|
package/src/utils/Route/index.js
CHANGED
|
@@ -180,6 +180,8 @@ const Routes = {
|
|
|
180
180
|
EditTemplate: 'EditTemplate',
|
|
181
181
|
SmartAccountStack: 'SmartAccountStack',
|
|
182
182
|
SuccessfullyConnected: 'SuccessfullyConnected',
|
|
183
|
+
AllGatewayStack: 'AllGatewayStack',
|
|
184
|
+
AllGateway: 'AllGateway',
|
|
183
185
|
};
|
|
184
186
|
|
|
185
187
|
export default Routes;
|
package/src/utils/Utils.js
CHANGED
|
@@ -133,6 +133,13 @@ export const notImplemented = (t) => {
|
|
|
133
133
|
Alert.alert(t('feature_under_development'));
|
|
134
134
|
};
|
|
135
135
|
|
|
136
|
+
export const roundNumber = (value, round = 2) => {
|
|
137
|
+
if (!isNaN) {
|
|
138
|
+
return Math.round((value || 0) * 10 ** round) / 10 ** round;
|
|
139
|
+
}
|
|
140
|
+
return value;
|
|
141
|
+
};
|
|
142
|
+
|
|
136
143
|
export default {
|
|
137
144
|
validateEmail,
|
|
138
145
|
isObjectEmpty,
|