@eohjsc/react-native-smart-city 0.3.97 → 0.3.99
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/package.json +1 -3
- package/src/commons/Dashboard/MyUnit/index.js +8 -2
- package/src/commons/Device/WindSpeed/Anemometer/index.js +19 -20
- package/src/commons/Device/WindSpeed/__test__/Anemometer.test.js +21 -2
- package/src/commons/SubUnit/OneTap/__test__/SubUnitAutomate.test.js +3 -4
- package/src/commons/SubUnit/OneTap/index.js +3 -1
- package/src/configs/AccessibilityLabel.js +1 -0
- package/src/configs/Constants.js +1 -0
- package/src/context/actionType.ts +1 -0
- package/src/context/mockStore.ts +3 -0
- package/src/context/reducer.ts +7 -1
- package/src/screens/ActivityLog/hooks/index.js +5 -1
- package/src/screens/AddCommon/SelectUnit.js +1 -0
- package/src/screens/AddNewGateway/ScanGatewayQR.js +0 -5
- package/src/screens/AddNewGateway/SelectDeviceType.js +7 -3
- package/src/screens/AddNewGateway/__test__/ScanGatewayQR.test.js +0 -1
- package/src/screens/AddNewGateway/__test__/SelectDeviceType.test.js +19 -12
- package/src/screens/Automate/AddNewAction/SetupConfigCondition.js +7 -16
- package/src/screens/Automate/AddNewAction/__test__/SetupSensor.test.js +5 -19
- package/src/screens/Automate/MultiUnits.js +8 -2
- package/src/screens/Automate/ScriptDetail/__test__/index.test.js +3 -4
- package/src/screens/Automate/ScriptDetail/index.js +3 -1
- package/src/screens/Automate/__test__/MultiUnits.test.js +6 -5
- package/src/screens/Automate/__test__/index.test.js +6 -5
- package/src/screens/Automate/index.js +8 -2
- package/src/screens/Device/detail.js +4 -3
- package/src/screens/Device/utils/index.js +2 -1
- package/src/screens/Notification/__test__/NotificationItem.test.js +1 -0
- package/src/screens/Notification/components/NotificationItem.js +8 -0
- package/src/screens/Sharing/MemberList.js +3 -1
- package/src/screens/Sharing/__test__/MemberList.test.js +3 -4
- package/src/screens/SmartAccount/Connecting/index.js +2 -2
- package/src/screens/SmartAccount/Connecting/style.js +1 -1
- package/src/screens/SmartAccount/SuccessfullyConnected/index.js +4 -2
- package/src/screens/SmartAccount/SuccessfullyConnected/styles.js +3 -0
- package/src/screens/SmartAccount/index.js +1 -0
- package/src/screens/SubUnit/AddSubUnit.js +16 -0
- package/src/screens/SubUnit/__test__/AddSubUnit.test.js +55 -3
- package/src/screens/Unit/AddMenu.js +3 -1
- package/src/utils/I18n/translations/en.js +16 -16
- package/src/utils/I18n/translations/vi.js +16 -13
- package/src/utils/Utils.js +6 -6
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eohjsc/react-native-smart-city",
|
|
3
3
|
"title": "React Native Smart Home",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.99",
|
|
5
5
|
"description": "TODO",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"files": [
|
|
@@ -178,7 +178,6 @@
|
|
|
178
178
|
"react-native-input-credit-card": "^0.5.5",
|
|
179
179
|
"react-native-iphone-x-helper": "^1.2.1",
|
|
180
180
|
"react-native-linear-gradient": "^2.5.6",
|
|
181
|
-
"react-native-loading-dots": "^1.3.2",
|
|
182
181
|
"react-native-localize": "^1.4.1",
|
|
183
182
|
"react-native-maps": "0.27.1",
|
|
184
183
|
"react-native-maps-directions": "^1.8.0",
|
|
@@ -200,7 +199,6 @@
|
|
|
200
199
|
"react-native-svg": "^12.1.0",
|
|
201
200
|
"react-native-toast-message": "^2.1.1",
|
|
202
201
|
"react-native-udp": "^4.1.3",
|
|
203
|
-
"react-native-unimodules": "^0.11.0",
|
|
204
202
|
"react-native-version-check": "^3.4.2",
|
|
205
203
|
"react-native-vlc-media-player": "^1.0.41",
|
|
206
204
|
"react-native-webview": "11.17.2",
|
|
@@ -67,11 +67,17 @@ const MyUnit = ({ refreshing }) => {
|
|
|
67
67
|
if (isNeedUpdateCache) {
|
|
68
68
|
setAction(Action.IS_CHECK_CLEAR_CACHE_UNITS, false);
|
|
69
69
|
const { success, data } = await axiosGet(API.UNIT.MY_UNITS(), {}, true);
|
|
70
|
-
|
|
70
|
+
if (success) {
|
|
71
|
+
setMyUnits(data);
|
|
72
|
+
setAction(Action.SET_MY_UNITS, data);
|
|
73
|
+
}
|
|
71
74
|
} else {
|
|
72
75
|
await fetchWithCache(API.UNIT.MY_UNITS(), {}, (response) => {
|
|
73
76
|
const { success, data } = response;
|
|
74
|
-
|
|
77
|
+
if (success) {
|
|
78
|
+
setMyUnits(data);
|
|
79
|
+
setAction(Action.SET_MY_UNITS, data);
|
|
80
|
+
}
|
|
75
81
|
});
|
|
76
82
|
}
|
|
77
83
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
@@ -34,7 +34,7 @@ const Anemometer = memo(
|
|
|
34
34
|
}, [item?.configuration?.max_value]);
|
|
35
35
|
|
|
36
36
|
const value = data.length ? data[0].value : 0;
|
|
37
|
-
const measure = data.length ? data[0].measure : 'm/s';
|
|
37
|
+
const measure = data.length ? data[0].unit || data[0].measure : 'm/s';
|
|
38
38
|
|
|
39
39
|
const radius = (size - strokeWidth) / 2;
|
|
40
40
|
const viewBox = `0 0 ${width} ${width}`;
|
|
@@ -178,25 +178,24 @@ const Anemometer = memo(
|
|
|
178
178
|
</View>
|
|
179
179
|
|
|
180
180
|
<View style={styles.textValue}>
|
|
181
|
-
{
|
|
182
|
-
<
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
)}
|
|
181
|
+
<Svg width={width} height={width} {...viewBox}>
|
|
182
|
+
<Text
|
|
183
|
+
fill={Colors.Lime6}
|
|
184
|
+
fontSize={valueSize[0]}
|
|
185
|
+
fontWeight="bold"
|
|
186
|
+
x={width / 2}
|
|
187
|
+
y={width / 2 + valueSize[1]}
|
|
188
|
+
textAnchor="middle"
|
|
189
|
+
fontFamily={Fonts.Regular}
|
|
190
|
+
onPressIn={handleShowToolTip(true)}
|
|
191
|
+
onPressOut={handleShowToolTip(false)}
|
|
192
|
+
accessibilityLabel={AccessibilityLabel.GAUGE_VALUE}
|
|
193
|
+
>
|
|
194
|
+
{value.toString().length > 10
|
|
195
|
+
? value.toString().substring(0, 10) + '...'
|
|
196
|
+
: value}
|
|
197
|
+
</Text>
|
|
198
|
+
</Svg>
|
|
200
199
|
{isShowToolTip && (
|
|
201
200
|
<View
|
|
202
201
|
style={{
|
|
@@ -19,14 +19,17 @@ describe('Test Anemometer', () => {
|
|
|
19
19
|
const text = instance.findAllByType(Text);
|
|
20
20
|
expect(text.length).toBe(5);
|
|
21
21
|
});
|
|
22
|
+
|
|
22
23
|
it('render Anemometer data null', async () => {
|
|
23
24
|
let data = [];
|
|
24
25
|
await act(async () => {
|
|
25
26
|
wrapper = renderer.create(<Anemometer data={data} maxValue={1} />);
|
|
26
27
|
});
|
|
27
28
|
const instance = wrapper.root;
|
|
28
|
-
const
|
|
29
|
-
|
|
29
|
+
const textValue = instance.findByProps({
|
|
30
|
+
accessibilityLabel: AccessibilityLabel.GAUGE_VALUE,
|
|
31
|
+
});
|
|
32
|
+
expect(textValue.props.children).toEqual(0);
|
|
30
33
|
});
|
|
31
34
|
|
|
32
35
|
it('test render value font size length < 4', async () => {
|
|
@@ -114,4 +117,20 @@ describe('Test Anemometer', () => {
|
|
|
114
117
|
});
|
|
115
118
|
expect(view.props.style.transform[0].translateX).toEqual(-50);
|
|
116
119
|
});
|
|
120
|
+
|
|
121
|
+
it('test render measure', async () => {
|
|
122
|
+
let data = [
|
|
123
|
+
{
|
|
124
|
+
value: 123456789,
|
|
125
|
+
unit: '%',
|
|
126
|
+
},
|
|
127
|
+
];
|
|
128
|
+
await act(async () => {
|
|
129
|
+
wrapper = renderer.create(<Anemometer data={data} maxValue={1} />);
|
|
130
|
+
});
|
|
131
|
+
let instance = wrapper.root;
|
|
132
|
+
const text = instance.findAllByType(Text);
|
|
133
|
+
expect(text).toHaveLength(5);
|
|
134
|
+
expect(text[4].props.children).toEqual('%');
|
|
135
|
+
});
|
|
117
136
|
});
|
|
@@ -282,10 +282,9 @@ describe('test Item', () => {
|
|
|
282
282
|
});
|
|
283
283
|
expect(mockedNavigate).not.toBeCalled();
|
|
284
284
|
expect(spyToastError).toBeCalledWith(
|
|
285
|
-
getTranslate(
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
)
|
|
285
|
+
getTranslate('en', 'reach_max_automations_per_unit'),
|
|
286
|
+
'',
|
|
287
|
+
7000
|
|
289
288
|
);
|
|
290
289
|
});
|
|
291
290
|
|
|
@@ -409,6 +409,7 @@ export default {
|
|
|
409
409
|
EMERGENCY_POPUP: 'EMERGENCY_POPUP',
|
|
410
410
|
RESOLVED_EMERGENCY_POPUP: 'RESOLVED_EMERGENCY_POPUP',
|
|
411
411
|
TOTAL_POWER_CONSUMPTION: 'TOTAL_POWER_CONSUMPTION',
|
|
412
|
+
GAUGE_VALUE: 'GAUGE_VALUE',
|
|
412
413
|
|
|
413
414
|
// Shared unit
|
|
414
415
|
ICON_REMOVE_PIN_SHARED_UNIT: 'ICON_REMOVE_PIN_SHARED_UNIT',
|
package/src/configs/Constants.js
CHANGED
package/src/context/mockStore.ts
CHANGED
|
@@ -25,6 +25,7 @@ export const mockDataStore: ContextData = {
|
|
|
25
25
|
barStyle: '',
|
|
26
26
|
},
|
|
27
27
|
listAction: [],
|
|
28
|
+
myUnits: [],
|
|
28
29
|
unit: {
|
|
29
30
|
favoriteDeviceIds: [],
|
|
30
31
|
},
|
|
@@ -95,6 +96,7 @@ export const mockSCStore = (data: ContextData): ContextData => {
|
|
|
95
96
|
appState: 'active',
|
|
96
97
|
...data.app,
|
|
97
98
|
},
|
|
99
|
+
myUnits: [...mockDataStore.myUnits, ...(data?.myUnits || [])],
|
|
98
100
|
unit: {
|
|
99
101
|
favoriteDeviceIds: [
|
|
100
102
|
...mockDataStore.unit.favoriteDeviceIds,
|
|
@@ -130,5 +132,6 @@ export const mockSCStore = (data: ContextData): ContextData => {
|
|
|
130
132
|
bluetooth: {
|
|
131
133
|
...mockDataStore.bluetooth,
|
|
132
134
|
},
|
|
135
|
+
percent: mockDataStore.percent,
|
|
133
136
|
};
|
|
134
137
|
};
|
package/src/context/reducer.ts
CHANGED
|
@@ -33,6 +33,7 @@ export type ContextData = {
|
|
|
33
33
|
devMode: DevModeType;
|
|
34
34
|
bluetooth: BluetoothType;
|
|
35
35
|
percent: number;
|
|
36
|
+
myUnits: [];
|
|
36
37
|
};
|
|
37
38
|
|
|
38
39
|
export type Action = {
|
|
@@ -54,6 +55,7 @@ export const initialState = {
|
|
|
54
55
|
listDevice: {} as ListDevice,
|
|
55
56
|
listAction: [] as ListAction,
|
|
56
57
|
percent: 0,
|
|
58
|
+
myUnits: [],
|
|
57
59
|
unit: {
|
|
58
60
|
favoriteDeviceIds: [],
|
|
59
61
|
},
|
|
@@ -537,7 +539,11 @@ export const reducer = (currentState: ContextData, action: Action) => {
|
|
|
537
539
|
appState: payload,
|
|
538
540
|
},
|
|
539
541
|
};
|
|
540
|
-
|
|
542
|
+
case Action.SET_MY_UNITS:
|
|
543
|
+
return {
|
|
544
|
+
...currentState,
|
|
545
|
+
myUnits: payload,
|
|
546
|
+
};
|
|
541
547
|
default:
|
|
542
548
|
return currentState;
|
|
543
549
|
}
|
|
@@ -62,7 +62,11 @@ export default ({ id, type, share, filterEnabled }) => {
|
|
|
62
62
|
if (api?.needPermission && !permissions?.[api?.needPermission]) {
|
|
63
63
|
setIsLoading(false);
|
|
64
64
|
setIsRefreshing(false);
|
|
65
|
-
ToastBottomHelper.error(
|
|
65
|
+
ToastBottomHelper.error(
|
|
66
|
+
t(`no_permission_${api?.needPermission}`),
|
|
67
|
+
'',
|
|
68
|
+
7000
|
|
69
|
+
);
|
|
66
70
|
return;
|
|
67
71
|
}
|
|
68
72
|
|
|
@@ -150,7 +150,7 @@ const SelectDeviceType = ({ route }) => {
|
|
|
150
150
|
const handleOnSelect = (itemSelect) => {
|
|
151
151
|
const needPermission = getPermissionCode(itemSelect);
|
|
152
152
|
if (!permissions?.[needPermission]) {
|
|
153
|
-
ToastBottomHelper.error(t(`no_permission_${needPermission}`));
|
|
153
|
+
ToastBottomHelper.error(t(`no_permission_${needPermission}`), '', 7000);
|
|
154
154
|
return false;
|
|
155
155
|
}
|
|
156
156
|
|
|
@@ -159,7 +159,9 @@ const SelectDeviceType = ({ route }) => {
|
|
|
159
159
|
ToastBottomHelper.error(
|
|
160
160
|
t('reach_max_chips_per_unit', {
|
|
161
161
|
length: permissions?.max_chips_per_unit,
|
|
162
|
-
})
|
|
162
|
+
}),
|
|
163
|
+
'',
|
|
164
|
+
7000
|
|
163
165
|
);
|
|
164
166
|
return false;
|
|
165
167
|
}
|
|
@@ -172,7 +174,9 @@ const SelectDeviceType = ({ route }) => {
|
|
|
172
174
|
ToastBottomHelper.error(
|
|
173
175
|
t('reach_max_configs_per_unit', {
|
|
174
176
|
length: permissions?.max_configs_per_unit,
|
|
175
|
-
})
|
|
177
|
+
}),
|
|
178
|
+
'',
|
|
179
|
+
7000
|
|
176
180
|
);
|
|
177
181
|
return false;
|
|
178
182
|
}
|
|
@@ -62,7 +62,6 @@ describe('test scan gateway device QR', () => {
|
|
|
62
62
|
const bottomSheet = instance.findByProps({
|
|
63
63
|
title: getTranslate('en', 'invalid_qr_code'),
|
|
64
64
|
});
|
|
65
|
-
expect(bottomSheet.props.isVisible).toBe(true);
|
|
66
65
|
|
|
67
66
|
const buttonBottom = instance.findByType(ViewButtonBottom);
|
|
68
67
|
await act(async () => {
|
|
@@ -14,6 +14,7 @@ import api from '../../../utils/Apis/axios';
|
|
|
14
14
|
import API from '../../../configs/API';
|
|
15
15
|
import { ToastBottomHelper } from '../../../utils/Utils';
|
|
16
16
|
import { getTranslate } from '../../../utils/I18n';
|
|
17
|
+
|
|
17
18
|
const wrapComponent = (route, storeData = {}) => (
|
|
18
19
|
<SCProvider initState={mockSCStore(storeData)}>
|
|
19
20
|
<SelectDeviceType route={route} />
|
|
@@ -147,10 +148,9 @@ describe('Test select device type', () => {
|
|
|
147
148
|
});
|
|
148
149
|
expect(mockedNavigate).not.toBeCalled();
|
|
149
150
|
expect(spyToastError).toBeCalledWith(
|
|
150
|
-
getTranslate(
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
)
|
|
151
|
+
getTranslate('en', 'reach_max_configs_per_unit'),
|
|
152
|
+
'',
|
|
153
|
+
7000
|
|
154
154
|
);
|
|
155
155
|
});
|
|
156
156
|
|
|
@@ -189,10 +189,9 @@ describe('Test select device type', () => {
|
|
|
189
189
|
});
|
|
190
190
|
expect(mockedNavigate).not.toBeCalled();
|
|
191
191
|
expect(spyToastError).toBeCalledWith(
|
|
192
|
-
getTranslate(
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
)
|
|
192
|
+
getTranslate('en', 'reach_max_chips_per_unit'),
|
|
193
|
+
'',
|
|
194
|
+
7000
|
|
196
195
|
);
|
|
197
196
|
});
|
|
198
197
|
|
|
@@ -209,7 +208,9 @@ describe('Test select device type', () => {
|
|
|
209
208
|
},
|
|
210
209
|
});
|
|
211
210
|
expect(spyToastError).toBeCalledWith(
|
|
212
|
-
getTranslate('en', 'no_permission_plug_and_play_gateway')
|
|
211
|
+
getTranslate('en', 'no_permission_plug_and_play_gateway'),
|
|
212
|
+
'',
|
|
213
|
+
7000
|
|
213
214
|
);
|
|
214
215
|
});
|
|
215
216
|
|
|
@@ -226,7 +227,9 @@ describe('Test select device type', () => {
|
|
|
226
227
|
},
|
|
227
228
|
});
|
|
228
229
|
expect(spyToastError).toBeCalledWith(
|
|
229
|
-
getTranslate('en', 'no_permission_plug_and_play_zigbee')
|
|
230
|
+
getTranslate('en', 'no_permission_plug_and_play_zigbee'),
|
|
231
|
+
'',
|
|
232
|
+
7000
|
|
230
233
|
);
|
|
231
234
|
});
|
|
232
235
|
|
|
@@ -243,7 +246,9 @@ describe('Test select device type', () => {
|
|
|
243
246
|
},
|
|
244
247
|
});
|
|
245
248
|
expect(spyToastError).toBeCalledWith(
|
|
246
|
-
getTranslate('en', 'no_permission_plug_and_play_wifi')
|
|
249
|
+
getTranslate('en', 'no_permission_plug_and_play_wifi'),
|
|
250
|
+
'',
|
|
251
|
+
7000
|
|
247
252
|
);
|
|
248
253
|
});
|
|
249
254
|
|
|
@@ -260,7 +265,9 @@ describe('Test select device type', () => {
|
|
|
260
265
|
},
|
|
261
266
|
});
|
|
262
267
|
expect(spyToastError).toBeCalledWith(
|
|
263
|
-
getTranslate('en', 'no_permission_plug_and_play_modbus')
|
|
268
|
+
getTranslate('en', 'no_permission_plug_and_play_modbus'),
|
|
269
|
+
'',
|
|
270
|
+
7000
|
|
264
271
|
);
|
|
265
272
|
});
|
|
266
273
|
|
|
@@ -68,25 +68,16 @@ const SetupConfigCondition = () => {
|
|
|
68
68
|
};
|
|
69
69
|
|
|
70
70
|
const onSave = useCallback(() => {
|
|
71
|
-
const conditionValue =
|
|
72
|
-
|
|
71
|
+
const conditionValue = itemActiveModal?.value;
|
|
72
|
+
|
|
73
|
+
if (isNaN(parseFloat(conditionValue)) || !isFinite(conditionValue)) {
|
|
73
74
|
ToastBottomHelper.error(t('value_must_be_a_number'));
|
|
74
75
|
return;
|
|
75
76
|
}
|
|
76
77
|
|
|
77
|
-
if (
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
t('value_must_be_greater_than_min', { min: item.range_min })
|
|
81
|
-
);
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
if (item.range_max !== null && conditionValue > item.range_max) {
|
|
85
|
-
ToastBottomHelper.error(
|
|
86
|
-
t('value_must_be_less_than_max', { max: item.range_max })
|
|
87
|
-
);
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
78
|
+
if (Math.abs(conditionValue)?.toString()?.length > 6) {
|
|
79
|
+
ToastBottomHelper.error(t('value_must_be_6_digits_or_less'));
|
|
80
|
+
return;
|
|
90
81
|
}
|
|
91
82
|
|
|
92
83
|
navigate({
|
|
@@ -99,7 +90,7 @@ const SetupConfigCondition = () => {
|
|
|
99
90
|
},
|
|
100
91
|
},
|
|
101
92
|
});
|
|
102
|
-
}, [item.id,
|
|
93
|
+
}, [item.id, itemActiveModal, navigate, t]);
|
|
103
94
|
|
|
104
95
|
useEffect(() => {
|
|
105
96
|
!hasNoValueEvaluation && setValue(1);
|
|
@@ -80,13 +80,11 @@ describe('Test SetupConfigCondition', () => {
|
|
|
80
80
|
expect(mockGoBack).toBeCalled();
|
|
81
81
|
});
|
|
82
82
|
|
|
83
|
-
const
|
|
83
|
+
const testConditionValue = async (value, message) => {
|
|
84
84
|
useRoute.mockReturnValue({
|
|
85
85
|
params: {
|
|
86
86
|
item: {
|
|
87
87
|
id: 1,
|
|
88
|
-
range_min: rangeMin,
|
|
89
|
-
range_max: rangeMax,
|
|
90
88
|
decimal_behind: 0,
|
|
91
89
|
title: 'is below (<)',
|
|
92
90
|
sensor_type: 'air_quality',
|
|
@@ -116,22 +114,10 @@ describe('Test SetupConfigCondition', () => {
|
|
|
116
114
|
}
|
|
117
115
|
};
|
|
118
116
|
|
|
119
|
-
it('Test render when have maximum', async () => {
|
|
120
|
-
await testWithRange(0, 10, '128', 'Value must be less than 10');
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
it('Test render when have no maximum', async () => {
|
|
124
|
-
await testWithRange(0, null, '128', null);
|
|
125
|
-
});
|
|
126
|
-
it('Test render when have minium', async () => {
|
|
127
|
-
await testWithRange(4, 10, '1', 'Value must be greater than 4');
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
it('Test render when have no minium', async () => {
|
|
131
|
-
await testWithRange(null, 10, '1', null);
|
|
132
|
-
});
|
|
133
|
-
|
|
134
117
|
it('Test render when have input not number', async () => {
|
|
135
|
-
await
|
|
118
|
+
await testConditionValue('abc', 'Value must be a number');
|
|
119
|
+
});
|
|
120
|
+
it('Test render when have input value must be 6 digits or less', async () => {
|
|
121
|
+
await testConditionValue('1234567', 'Value must be 6 digits or less');
|
|
136
122
|
});
|
|
137
123
|
});
|
|
@@ -81,12 +81,18 @@ const MultiUnits = () => {
|
|
|
81
81
|
ToastBottomHelper.error(
|
|
82
82
|
t('reach_max_automations_per_unit', {
|
|
83
83
|
length: permissions.max_automations_per_unit,
|
|
84
|
-
})
|
|
84
|
+
}),
|
|
85
|
+
'',
|
|
86
|
+
7000
|
|
85
87
|
);
|
|
86
88
|
return;
|
|
87
89
|
}
|
|
88
90
|
} else if (!permissions?.smart_script_for_multi_unit) {
|
|
89
|
-
ToastBottomHelper.error(
|
|
91
|
+
ToastBottomHelper.error(
|
|
92
|
+
t('no_permission_smart_script_for_multi_unit'),
|
|
93
|
+
'',
|
|
94
|
+
7000
|
|
95
|
+
);
|
|
90
96
|
return;
|
|
91
97
|
}
|
|
92
98
|
if (tabActive === AUTOMATE_TABS.SCENARIO) {
|
|
@@ -271,10 +271,9 @@ describe('Test ScriptDetail', () => {
|
|
|
271
271
|
});
|
|
272
272
|
expect(mockNavigate).not.toBeCalled();
|
|
273
273
|
expect(spyToastError).toBeCalledWith(
|
|
274
|
-
getTranslate(
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
)
|
|
274
|
+
getTranslate('en', 'reach_max_actions_per_automation'),
|
|
275
|
+
'',
|
|
276
|
+
7000
|
|
278
277
|
);
|
|
279
278
|
});
|
|
280
279
|
|
|
@@ -252,10 +252,9 @@ describe('Test MultiUnits', () => {
|
|
|
252
252
|
});
|
|
253
253
|
expect(mockedNavigate).not.toBeCalled();
|
|
254
254
|
expect(spyToastError).toBeCalledWith(
|
|
255
|
-
getTranslate(
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
)
|
|
255
|
+
getTranslate('en', 'reach_max_automations_per_unit'),
|
|
256
|
+
'',
|
|
257
|
+
7000
|
|
259
258
|
);
|
|
260
259
|
});
|
|
261
260
|
|
|
@@ -291,7 +290,9 @@ describe('Test MultiUnits', () => {
|
|
|
291
290
|
});
|
|
292
291
|
expect(mockedNavigate).not.toBeCalled();
|
|
293
292
|
expect(spyToastError).toBeCalledWith(
|
|
294
|
-
getTranslate('en', 'no_permission_smart_script_for_multi_unit')
|
|
293
|
+
getTranslate('en', 'no_permission_smart_script_for_multi_unit'),
|
|
294
|
+
'',
|
|
295
|
+
7000
|
|
295
296
|
);
|
|
296
297
|
});
|
|
297
298
|
|
|
@@ -148,10 +148,9 @@ describe('Test Automate', () => {
|
|
|
148
148
|
});
|
|
149
149
|
expect(mockedNavigate).not.toBeCalled();
|
|
150
150
|
expect(spyToastError).toBeCalledWith(
|
|
151
|
-
getTranslate(
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
)
|
|
151
|
+
getTranslate('en', 'reach_max_automations_per_unit'),
|
|
152
|
+
'',
|
|
153
|
+
7000
|
|
155
154
|
);
|
|
156
155
|
});
|
|
157
156
|
|
|
@@ -295,7 +294,9 @@ describe('Test Automate', () => {
|
|
|
295
294
|
});
|
|
296
295
|
expect(mockedNavigate).not.toBeCalled();
|
|
297
296
|
expect(spyToastError).toBeCalledWith(
|
|
298
|
-
getTranslate('en', 'no_permission_smart_script_for_multi_unit')
|
|
297
|
+
getTranslate('en', 'no_permission_smart_script_for_multi_unit'),
|
|
298
|
+
'',
|
|
299
|
+
7000
|
|
299
300
|
);
|
|
300
301
|
});
|
|
301
302
|
});
|
|
@@ -88,12 +88,18 @@ const Automate = () => {
|
|
|
88
88
|
ToastBottomHelper.error(
|
|
89
89
|
t('reach_max_automations_per_unit', {
|
|
90
90
|
length: permissions.max_automations_per_unit,
|
|
91
|
-
})
|
|
91
|
+
}),
|
|
92
|
+
'',
|
|
93
|
+
7000
|
|
92
94
|
);
|
|
93
95
|
return;
|
|
94
96
|
}
|
|
95
97
|
} else if (!permissions?.smart_script_for_multi_unit) {
|
|
96
|
-
ToastBottomHelper.error(
|
|
98
|
+
ToastBottomHelper.error(
|
|
99
|
+
t('no_permission_smart_script_for_multi_unit'),
|
|
100
|
+
'',
|
|
101
|
+
7000
|
|
102
|
+
);
|
|
97
103
|
return;
|
|
98
104
|
}
|
|
99
105
|
navigate(Routes.UnitStack, {
|
|
@@ -501,13 +501,14 @@ const DeviceDetail = ({ route }) => {
|
|
|
501
501
|
const configIds = [];
|
|
502
502
|
|
|
503
503
|
display.items.map((item) => {
|
|
504
|
+
const type = item?.template || item?.type;
|
|
504
505
|
if (!item.configuration) {
|
|
505
506
|
return;
|
|
506
507
|
}
|
|
507
|
-
if (!['action', 'value'].includes(
|
|
508
|
+
if (!['action', 'value'].includes(type)) {
|
|
508
509
|
return;
|
|
509
510
|
}
|
|
510
|
-
if (
|
|
511
|
+
if (type === 'action') {
|
|
511
512
|
if (
|
|
512
513
|
[
|
|
513
514
|
'on_off_button_action_template',
|
|
@@ -518,7 +519,7 @@ const DeviceDetail = ({ route }) => {
|
|
|
518
519
|
configIds.push(item.configuration.configuration.config);
|
|
519
520
|
}
|
|
520
521
|
}
|
|
521
|
-
if (
|
|
522
|
+
if (type === 'value') {
|
|
522
523
|
item.configuration.configs.map((config) => {
|
|
523
524
|
if (!configIds.includes(config.id)) {
|
|
524
525
|
configIds.push(config.id);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export const getConfigControlFromDeviceDisplay = (deviceDisplay) => {
|
|
2
2
|
const configIds = [];
|
|
3
3
|
(deviceDisplay?.items || []).map((item) => {
|
|
4
|
-
|
|
4
|
+
const type = item?.template || item?.type;
|
|
5
|
+
if (type !== 'action') {
|
|
5
6
|
return;
|
|
6
7
|
}
|
|
7
8
|
const actionGroup = item?.configuration || {};
|
|
@@ -55,6 +55,7 @@ describe('test NotificationItem', () => {
|
|
|
55
55
|
NOTIFICATION_TYPES.NOTIFY_REMOVE_SUB_UNIT,
|
|
56
56
|
NOTIFICATION_TYPES.NOTIFY_REMOVE_DEVICE,
|
|
57
57
|
NOTIFICATION_TYPES.NOTIFY_CHANGE_UNIT_OLD_OWNER,
|
|
58
|
+
NOTIFICATION_TYPES.SUBSCRIBE_SUCCESS,
|
|
58
59
|
];
|
|
59
60
|
|
|
60
61
|
for (const content_code of listCase2) {
|
|
@@ -408,6 +408,14 @@ const NotificationItem = memo(({ item }) => {
|
|
|
408
408
|
redirect: () => null,
|
|
409
409
|
iconContent: <Image source={Images.logo} style={styles.logo} />,
|
|
410
410
|
};
|
|
411
|
+
case NOTIFICATION_TYPES.SUBSCRIBE_SUCCESS:
|
|
412
|
+
return {
|
|
413
|
+
content: customColorText(
|
|
414
|
+
t('text_notification_content_subscribe_success')
|
|
415
|
+
),
|
|
416
|
+
redirect: () => null,
|
|
417
|
+
iconContent: <Image source={Images.logo} style={styles.logo} />,
|
|
418
|
+
};
|
|
411
419
|
default:
|
|
412
420
|
return null;
|
|
413
421
|
}
|
|
@@ -101,10 +101,9 @@ describe('test MemberList', () => {
|
|
|
101
101
|
});
|
|
102
102
|
expect(mockedNavigate).not.toBeCalled();
|
|
103
103
|
expect(spyToastError).toBeCalledWith(
|
|
104
|
-
getTranslate(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
)
|
|
104
|
+
getTranslate('en', 'reach_max_members_per_unit'),
|
|
105
|
+
'',
|
|
106
|
+
7000
|
|
108
107
|
);
|
|
109
108
|
});
|
|
110
109
|
});
|
|
@@ -2,7 +2,6 @@ import React, { useEffect, useCallback, useContext } from 'react';
|
|
|
2
2
|
import { View } from 'react-native';
|
|
3
3
|
import { useNavigation } from '@react-navigation/native';
|
|
4
4
|
import * as Progress from 'react-native-progress';
|
|
5
|
-
import LoadingDots from 'react-native-loading-dots';
|
|
6
5
|
|
|
7
6
|
import Text from '../../../commons/Text';
|
|
8
7
|
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
@@ -25,6 +24,7 @@ const SmartAccountConnecting = ({ route }) => {
|
|
|
25
24
|
password,
|
|
26
25
|
brand,
|
|
27
26
|
unit_id,
|
|
27
|
+
unitName,
|
|
28
28
|
listDeviceIds,
|
|
29
29
|
stationId,
|
|
30
30
|
nameSubUnit,
|
|
@@ -95,6 +95,7 @@ const SmartAccountConnecting = ({ route }) => {
|
|
|
95
95
|
smart_account_id: smart_account_id,
|
|
96
96
|
smart_account_id_from_backend: smart_account_id_from_backend,
|
|
97
97
|
unit_id: unit_id,
|
|
98
|
+
unitName,
|
|
98
99
|
stationId,
|
|
99
100
|
username,
|
|
100
101
|
brand,
|
|
@@ -139,7 +140,6 @@ const SmartAccountConnecting = ({ route }) => {
|
|
|
139
140
|
<Text bold style={styles.connectingText}>
|
|
140
141
|
{t('connecting_smart_account')}
|
|
141
142
|
</Text>
|
|
142
|
-
<LoadingDots />
|
|
143
143
|
</View>
|
|
144
144
|
|
|
145
145
|
<Text style={styles.warningText}>
|
|
@@ -21,12 +21,13 @@ const SuccessfullyConnected = memo(({ route }) => {
|
|
|
21
21
|
listSelectDevice,
|
|
22
22
|
smart_account_id,
|
|
23
23
|
unit_id,
|
|
24
|
+
unitName,
|
|
24
25
|
stationId,
|
|
25
26
|
smart_account_id_from_backend,
|
|
26
27
|
username,
|
|
27
28
|
brand,
|
|
28
29
|
chipId,
|
|
29
|
-
} = route.params;
|
|
30
|
+
} = route.params || {};
|
|
30
31
|
const t = useTranslations();
|
|
31
32
|
const { navigate, dispatch } = useNavigation();
|
|
32
33
|
const [info, setInfo] = useState({});
|
|
@@ -139,7 +140,7 @@ const SuccessfullyConnected = memo(({ route }) => {
|
|
|
139
140
|
{t('successfully_connected')}
|
|
140
141
|
</Text>
|
|
141
142
|
<Text size={14} style={styles.textHome}>
|
|
142
|
-
{
|
|
143
|
+
{`${unitName} - ${nameSubUnit}`}
|
|
143
144
|
</Text>
|
|
144
145
|
{!loading && info?.sensors?.length !== 0 ? (
|
|
145
146
|
<View>
|
|
@@ -187,6 +188,7 @@ const SuccessfullyConnected = memo(({ route }) => {
|
|
|
187
188
|
accessibilityLabelPrefix={
|
|
188
189
|
AccessibilityLabel.PREFIX.BUTTON_BOTTOM_SMART_ACCOUNT
|
|
189
190
|
}
|
|
191
|
+
wrapStyle={styles.wrapViewButton}
|
|
190
192
|
/>
|
|
191
193
|
</View>
|
|
192
194
|
</>
|
|
@@ -20,11 +20,16 @@ import { AccessibilityLabel } from '../../configs/Constants';
|
|
|
20
20
|
import styles from './AddSubUnitStyles';
|
|
21
21
|
import useKeyboardShow from '../../hooks/Common/useKeyboardShow';
|
|
22
22
|
import { replace } from '../../navigations/utils';
|
|
23
|
+
import { useBackendPermission } from '../../utils/Permission/backend';
|
|
24
|
+
import { useSCContextSelector } from '../../context';
|
|
23
25
|
|
|
24
26
|
const AddSubUnit = ({ route }) => {
|
|
25
27
|
const t = useTranslations();
|
|
26
28
|
const { dismissKeyboard } = useKeyboardShow();
|
|
27
29
|
const { navigate, goBack, dispatch } = useNavigation();
|
|
30
|
+
const permissions = useBackendPermission();
|
|
31
|
+
const myUnits = useSCContextSelector((state) => state.myUnits);
|
|
32
|
+
|
|
28
33
|
const {
|
|
29
34
|
unit,
|
|
30
35
|
addType,
|
|
@@ -38,6 +43,10 @@ const AddSubUnit = ({ route }) => {
|
|
|
38
43
|
const [showImagePicker, setShowImagePicker] = useState(false);
|
|
39
44
|
let awaitCreate = useRef(false);
|
|
40
45
|
|
|
46
|
+
const unitChoose = useMemo(() => {
|
|
47
|
+
return myUnits?.find((item) => item?.id === unit?.id);
|
|
48
|
+
}, [myUnits, unit?.id]);
|
|
49
|
+
|
|
41
50
|
const cleanData = () => {
|
|
42
51
|
setRoomName('');
|
|
43
52
|
setWallpaper('');
|
|
@@ -124,6 +133,11 @@ const AddSubUnit = ({ route }) => {
|
|
|
124
133
|
cleanData();
|
|
125
134
|
} else {
|
|
126
135
|
awaitCreate.current = false;
|
|
136
|
+
if (
|
|
137
|
+
unitChoose?.stations?.length >= permissions?.max_stations_per_unit
|
|
138
|
+
) {
|
|
139
|
+
ToastBottomHelper.error(t('reach_max_stations_per_unit'), '', 7000);
|
|
140
|
+
}
|
|
127
141
|
}
|
|
128
142
|
}
|
|
129
143
|
}
|
|
@@ -140,6 +154,8 @@ const AddSubUnit = ({ route }) => {
|
|
|
140
154
|
goBack,
|
|
141
155
|
navigate,
|
|
142
156
|
route.params,
|
|
157
|
+
unitChoose?.stations?.length,
|
|
158
|
+
permissions?.max_stations_per_unit,
|
|
143
159
|
]);
|
|
144
160
|
|
|
145
161
|
const onChoosePhoto = useCallback(() => {
|
|
@@ -14,9 +14,10 @@ import { SCProvider } from '../../../context';
|
|
|
14
14
|
import { mockSCStore } from '../../../context/mockStore';
|
|
15
15
|
import api from '../../../utils/Apis/axios';
|
|
16
16
|
import { API } from '../../../configs';
|
|
17
|
+
import { ToastBottomHelper } from '../../../utils/Utils';
|
|
17
18
|
|
|
18
|
-
const wrapComponent = (route) => (
|
|
19
|
-
<SCProvider initState={mockSCStore(
|
|
19
|
+
const wrapComponent = (route, storeData = {}) => (
|
|
20
|
+
<SCProvider initState={mockSCStore(storeData)}>
|
|
20
21
|
<AddSubUnit route={route} />
|
|
21
22
|
</SCProvider>
|
|
22
23
|
);
|
|
@@ -297,7 +298,19 @@ describe('Test AddSubUnit', () => {
|
|
|
297
298
|
};
|
|
298
299
|
mock.onPost(API.SUB_UNIT.CREATE_SUB_UNIT(1)).reply(200, {});
|
|
299
300
|
await act(async () => {
|
|
300
|
-
tree = await create(
|
|
301
|
+
tree = await create(
|
|
302
|
+
wrapComponent(route, {
|
|
303
|
+
auth: {
|
|
304
|
+
account: {
|
|
305
|
+
user: {
|
|
306
|
+
permissions: {
|
|
307
|
+
max_stations_per_unit: 100,
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
},
|
|
311
|
+
},
|
|
312
|
+
})
|
|
313
|
+
);
|
|
301
314
|
});
|
|
302
315
|
const instance = tree.root;
|
|
303
316
|
const viewButtonBottom = await makeValidateData(instance);
|
|
@@ -307,6 +320,45 @@ describe('Test AddSubUnit', () => {
|
|
|
307
320
|
expect(mockNavigationDispatch).toBeCalledWith(mockReplace);
|
|
308
321
|
});
|
|
309
322
|
|
|
323
|
+
it('test no permission create fail sub-unit is out side Unit', async () => {
|
|
324
|
+
route.params = {
|
|
325
|
+
...route.params,
|
|
326
|
+
isInsideUnit: false,
|
|
327
|
+
};
|
|
328
|
+
const spyToastError = jest.spyOn(ToastBottomHelper, 'error');
|
|
329
|
+
mock.onPost(API.SUB_UNIT.CREATE_SUB_UNIT(1)).reply(400, {});
|
|
330
|
+
await act(async () => {
|
|
331
|
+
tree = await create(
|
|
332
|
+
wrapComponent(route, {
|
|
333
|
+
auth: {
|
|
334
|
+
account: {
|
|
335
|
+
user: {
|
|
336
|
+
permissions: {
|
|
337
|
+
max_stations_per_unit: 0,
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
},
|
|
341
|
+
},
|
|
342
|
+
myUnits: [
|
|
343
|
+
{ id: 1, name: 'unit 1', stations: [{ id: 1, name: 'station' }] },
|
|
344
|
+
],
|
|
345
|
+
})
|
|
346
|
+
);
|
|
347
|
+
});
|
|
348
|
+
const instance = tree.root;
|
|
349
|
+
const viewButtonBottom = await makeValidateData(instance);
|
|
350
|
+
|
|
351
|
+
await act(async () => {
|
|
352
|
+
await viewButtonBottom.props.onRightClick();
|
|
353
|
+
});
|
|
354
|
+
expect(spyToastError).toBeCalledWith(
|
|
355
|
+
getTranslate('en', 'reach_max_stations_per_unit'),
|
|
356
|
+
'',
|
|
357
|
+
7000
|
|
358
|
+
);
|
|
359
|
+
expect(mockNavigationDispatch).not.toBeCalled();
|
|
360
|
+
});
|
|
361
|
+
|
|
310
362
|
it('test create sub-unit type AddHassiDevice', async () => {
|
|
311
363
|
route.params = {
|
|
312
364
|
...route.params,
|
|
@@ -885,6 +885,9 @@ export default {
|
|
|
885
885
|
text_notification_content_when_trial_will_end:
|
|
886
886
|
'The service usage period is only **days** days left, ' +
|
|
887
887
|
'Package **product_name** will automatically renew on **trial_end** with **amount** **currency**',
|
|
888
|
+
text_notification_content_subscribe_success:
|
|
889
|
+
'Your account has just successfully registered for the **plan_name** plan - expires on **expire**. ' +
|
|
890
|
+
"Let's experience the new features now!",
|
|
888
891
|
text_notification_content_your_account_upgraded_3_month:
|
|
889
892
|
'Congratulations! Your account has just been upgraded to a 3-month free PREMIUM plan ' +
|
|
890
893
|
'as a sincere thanking word to your loyalty of the BETA version of E-Ra IoT Platform. ' +
|
|
@@ -1392,34 +1395,31 @@ export default {
|
|
|
1392
1395
|
'To provide a better user experience, [Era] will perform a system upgrade.The upgrade will take about 10 ' +
|
|
1393
1396
|
'minutes.\n\n Some device control functions will be interrupted during the upgrade.[Era] would like to ask ' +
|
|
1394
1397
|
'for your understanding for this inconvenience.\n\nBest regards.',
|
|
1395
|
-
value_must_be_greater_than_min: 'Value must be greater than {min}',
|
|
1396
|
-
value_must_be_less_than_max: 'Value must be less than {max}',
|
|
1397
1398
|
value_must_be_a_number: 'Value must be a number',
|
|
1398
1399
|
reach_max_stations_per_unit:
|
|
1399
|
-
|
|
1400
|
+
'Sub-unit is incomplete. Please visit app.e-ra.io to complete your operation.',
|
|
1400
1401
|
not_support_plug_and_play: 'Not support plug and play',
|
|
1401
1402
|
reach_max_actions_per_automation:
|
|
1402
|
-
|
|
1403
|
+
'Action is incomplete. Please visit app.e-ra.io to complete your operation.',
|
|
1403
1404
|
reach_max_automations_per_unit:
|
|
1404
|
-
|
|
1405
|
+
'Automation is incomplete. Please visit app.e-ra.io to complete your operation.',
|
|
1405
1406
|
reach_max_members_per_unit:
|
|
1406
|
-
|
|
1407
|
+
'Member is incomplete. Please visit app.e-ra.io to complete your operation.',
|
|
1407
1408
|
reach_max_chips_per_unit:
|
|
1408
|
-
|
|
1409
|
+
'Chip is incomplete. Please visit app.e-ra.io to complete your operation.',
|
|
1409
1410
|
reach_max_configs_per_unit:
|
|
1410
|
-
|
|
1411
|
+
'Config is incomplete. Please visit app.e-ra.io to complete your operation.',
|
|
1411
1412
|
no_permission_plug_and_play_modbus:
|
|
1412
|
-
'Add modbus is
|
|
1413
|
+
'Add modbus is incomplete. Please visit app.e-ra.io to complete your operation.',
|
|
1413
1414
|
no_permission_plug_and_play_zigbee:
|
|
1414
|
-
'Add zigbee is
|
|
1415
|
+
'Add zigbee is incomplete. Please visit app.e-ra.io to complete your operation.',
|
|
1415
1416
|
no_permission_plug_and_play_wifi:
|
|
1416
|
-
'Add wifi is
|
|
1417
|
+
'Add wifi is incomplete. Please visit app.e-ra.io to complete your operation.',
|
|
1417
1418
|
no_permission_plug_and_play_gateway:
|
|
1418
|
-
'Add gateway is
|
|
1419
|
+
'Add gateway is incomplete. Please visit app.e-ra.io to complete your operation.',
|
|
1419
1420
|
no_permission_view_action_log:
|
|
1420
|
-
|
|
1421
|
-
'View action log is currently not available on your Subscription. Please upgrade your plan for a better experience!',
|
|
1421
|
+
'View action log is incomplete. Please visit app.e-ra.io to complete your operation.',
|
|
1422
1422
|
no_permission_smart_script_for_multi_unit:
|
|
1423
|
-
|
|
1424
|
-
|
|
1423
|
+
'Smart script for Multi Unit is incomplete. Please visit app.e-ra.io to complete your operation.',
|
|
1424
|
+
value_must_be_6_digits_or_less: 'Value must be 6 digits or less',
|
|
1425
1425
|
};
|
|
@@ -901,6 +901,9 @@ export default {
|
|
|
901
901
|
text_notification_content_when_trial_will_end:
|
|
902
902
|
'Thời hạn sử dụng dịch vụ chỉ còn **days** ngày, ' +
|
|
903
903
|
'Gói **product_name** sẽ tự động gia hạn vào ngày **trial_end** với **amount** **currency**',
|
|
904
|
+
text_notification_content_subscribe_success:
|
|
905
|
+
'Tài khoản của bạn vừa đăng ký thành công gói **plan_name** - ngày kết thúc **expire**. ' +
|
|
906
|
+
'Cùng trải nghiệm các tính năng mới ngay thôi!',
|
|
904
907
|
text_notification_content_your_account_upgraded_3_month:
|
|
905
908
|
'Xin chúc mừng! Tài khoản của bạn vừa được nâng cấp lên gói PREMIUM miễn phí 3 tháng ' +
|
|
906
909
|
'nhằm tri ân người dùng phiên bản BETA của E-Ra IoT Platform. ' +
|
|
@@ -1404,29 +1407,29 @@ export default {
|
|
|
1404
1407
|
value_must_be_less_than_max: 'Giá trị phải nhỏ hơn {max}',
|
|
1405
1408
|
value_must_be_a_number: 'Giá trị phải là một số',
|
|
1406
1409
|
reach_max_stations_per_unit:
|
|
1407
|
-
'
|
|
1410
|
+
'Sub-unit chưa hoàn tất. Hãy truy cập app.e-ra.io để hoàn thiện thao tác của bạn.',
|
|
1408
1411
|
not_support_plug_and_play: 'Không hỗ trợ kết nối tự động',
|
|
1409
1412
|
reach_max_actions_per_automation:
|
|
1410
|
-
'
|
|
1413
|
+
'Action chưa hoàn tất. Hãy truy cập app.e-ra.io để hoàn thiện thao tác của bạn.',
|
|
1411
1414
|
reach_max_automations_per_unit:
|
|
1412
|
-
'
|
|
1415
|
+
'Automation chưa hoàn tất. Hãy truy cập app.e-ra.io để hoàn thiện thao tác của bạn.',
|
|
1413
1416
|
reach_max_members_per_unit:
|
|
1414
|
-
'
|
|
1417
|
+
'Member chưa hoàn tất. Hãy truy cập app.e-ra.io để hoàn thiện thao tác của bạn.',
|
|
1415
1418
|
reach_max_chips_per_unit:
|
|
1416
|
-
'
|
|
1419
|
+
'Chip chưa hoàn tất. Hãy truy cập app.e-ra.io để hoàn thiện thao tác của bạn.',
|
|
1417
1420
|
reach_max_configs_per_unit:
|
|
1418
|
-
'
|
|
1421
|
+
'Config chưa hoàn tất. Hãy truy cập app.e-ra.io để hoàn thiện thao tác của bạn.',
|
|
1419
1422
|
no_permission_plug_and_play_modbus:
|
|
1420
|
-
'Kết nối tự động modbus
|
|
1423
|
+
'Kết nối tự động modbus chưa hoàn tất. Hãy truy cập app.e-ra.io để hoàn thiện thao tác của bạn.',
|
|
1421
1424
|
no_permission_plug_and_play_zigbee:
|
|
1422
|
-
'Kết nối tự động zigbee
|
|
1425
|
+
'Kết nối tự động zigbee chưa hoàn tất. Hãy truy cập app.e-ra.io để hoàn thiện thao tác của bạn.',
|
|
1423
1426
|
no_permission_plug_and_play_wifi:
|
|
1424
|
-
'Kết nối tự động wifi
|
|
1427
|
+
'Kết nối tự động wifi chưa hoàn tất. Hãy truy cập app.e-ra.io để hoàn thiện thao tác của bạn.',
|
|
1425
1428
|
no_permission_plug_and_play_gateway:
|
|
1426
|
-
'Kết nối tự động gateway
|
|
1429
|
+
'Kết nối tự động gateway chưa hoàn tất. Hãy truy cập app.e-ra.io để hoàn thiện thao tác của bạn.',
|
|
1427
1430
|
no_permission_view_action_log:
|
|
1428
|
-
'Xem lịch sử hoạt động
|
|
1431
|
+
'Xem lịch sử hoạt động chưa hoàn tất. Hãy truy cập app.e-ra.io để hoàn thiện thao tác của bạn.',
|
|
1429
1432
|
no_permission_smart_script_for_multi_unit:
|
|
1430
|
-
|
|
1431
|
-
|
|
1433
|
+
'Kịch bản thông minh cho nhiều địa điểm chưa hoàn tất. Hãy truy cập app.e-ra.io để hoàn thiện thao tác của bạn.',
|
|
1434
|
+
value_must_be_6_digits_or_less: 'Giá trị phải nhỏ hơn 6 chữ số',
|
|
1432
1435
|
};
|
package/src/utils/Utils.js
CHANGED
|
@@ -88,31 +88,31 @@ export const openMapDirection = (item) => () => {
|
|
|
88
88
|
};
|
|
89
89
|
|
|
90
90
|
export const ToastBottomHelper = {
|
|
91
|
-
success: (msg, line2) => {
|
|
91
|
+
success: (msg, line2, visibilityTime = 1000) => {
|
|
92
92
|
Toast.show({
|
|
93
93
|
type: 'success',
|
|
94
94
|
position: 'bottom',
|
|
95
95
|
text1: msg,
|
|
96
96
|
text2: line2,
|
|
97
|
-
visibilityTime:
|
|
97
|
+
visibilityTime: visibilityTime,
|
|
98
98
|
});
|
|
99
99
|
},
|
|
100
|
-
error: (msg, line2) => {
|
|
100
|
+
error: (msg, line2, visibilityTime = 1000) => {
|
|
101
101
|
Toast.show({
|
|
102
102
|
type: 'error',
|
|
103
103
|
position: 'bottom',
|
|
104
104
|
text1: msg,
|
|
105
105
|
text2: line2,
|
|
106
|
-
visibilityTime:
|
|
106
|
+
visibilityTime: visibilityTime,
|
|
107
107
|
});
|
|
108
108
|
},
|
|
109
|
-
info: (msg, line2) => {
|
|
109
|
+
info: (msg, line2, visibilityTime = 1000) => {
|
|
110
110
|
Toast.show({
|
|
111
111
|
type: 'info',
|
|
112
112
|
position: 'bottom',
|
|
113
113
|
text1: msg,
|
|
114
114
|
text2: line2,
|
|
115
|
-
visibilityTime:
|
|
115
|
+
visibilityTime: visibilityTime,
|
|
116
116
|
});
|
|
117
117
|
},
|
|
118
118
|
};
|