@eohjsc/react-native-smart-city 0.3.98 → 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 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.98",
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",
@@ -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
- {!!value && (
182
- <Svg width={width} height={width} {...viewBox}>
183
- <Text
184
- fill={Colors.Lime6}
185
- fontSize={valueSize[0]}
186
- fontWeight="bold"
187
- x={width / 2}
188
- y={width / 2 + valueSize[1]}
189
- textAnchor="middle"
190
- fontFamily={Fonts.Regular}
191
- onPressIn={handleShowToolTip(true)}
192
- onPressOut={handleShowToolTip(false)}
193
- >
194
- {value.toString().length > 10
195
- ? value.toString().substring(0, 10) + '...'
196
- : value}
197
- </Text>
198
- </Svg>
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 text = instance.findAllByType(Text);
29
- expect(text.length).toBe(4);
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
  });
@@ -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',
@@ -233,6 +233,7 @@ export const NOTIFICATION_TYPES = {
233
233
  FILTER_WATER: 'FILTER_WATER',
234
234
  LOW_BATTERY: 'LOW_BATTERY',
235
235
  BROADCAST_NOTIFICATION: 'BROADCAST_NOTIFICATION',
236
+ SUBSCRIBE_SUCCESS: 'SUBSCRIBE_SUCCESS',
236
237
  };
237
238
 
238
239
  export const ACTIVITY_LOG_TYPES = {
@@ -77,6 +77,7 @@ const AddCommonSelectUnit = ({ route }) => {
77
77
  password: route.params.password,
78
78
  brand: route.params.brand,
79
79
  unit_id: unit?.id,
80
+ unitName: unit?.name,
80
81
  },
81
82
  });
82
83
  break;
@@ -22,11 +22,6 @@ const ScanGatewayQR = memo(({ route }) => {
22
22
  setLoading(false);
23
23
  return;
24
24
  }
25
- if (data?.prefix !== 'lite') {
26
- setIsInvalidQrCode(true);
27
- setLoading(false);
28
- return;
29
- }
30
25
  navigate(Routes.ConnectingWifiGuide, {
31
26
  unit,
32
27
  stationId,
@@ -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 () => {
@@ -68,25 +68,16 @@ const SetupConfigCondition = () => {
68
68
  };
69
69
 
70
70
  const onSave = useCallback(() => {
71
- const conditionValue = parseFloat(itemActiveModal?.value);
72
- if (isNaN(conditionValue)) {
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 (['<', '>', '='].includes(itemActiveModal?.condition)) {
78
- if (item.range_min !== null && conditionValue < item.range_min) {
79
- ToastBottomHelper.error(
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, item.range_max, item.range_min, itemActiveModal, navigate, t]);
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 testWithRange = async (rangeMin, rangeMax, value, message) => {
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 testWithRange(null, 10, 'abc', 'Value must be a number');
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
  });
@@ -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(item.type)) {
508
+ if (!['action', 'value'].includes(type)) {
508
509
  return;
509
510
  }
510
- if (item.type === 'action') {
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 (item.type === 'value') {
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
- if (item.type !== 'action') {
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
  }
@@ -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}>
@@ -22,7 +22,7 @@ export default StyleSheet.create({
22
22
  },
23
23
  warningText: {
24
24
  marginHorizontal: 30,
25
- marginTop: 16,
25
+ marginTop: 8,
26
26
  fontSize: 14,
27
27
  color: Colors.Gray8,
28
28
  },
@@ -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
- {`Home - ${nameSubUnit}`}
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
  </>
@@ -96,4 +96,7 @@ export default StyleSheet.create({
96
96
  resizeMode: 'contain',
97
97
  marginRight: 10,
98
98
  },
99
+ wrapViewButton: {
100
+ position: 'relative',
101
+ },
99
102
  });
@@ -50,6 +50,7 @@ const SmartAccount = ({ route }) => {
50
50
  password: password,
51
51
  brand: 'google_home',
52
52
  unit_id: route?.params?.unitId,
53
+ unitName: route?.params?.unitName,
53
54
  });
54
55
  } else {
55
56
  navigate(Routes.AddDeviceStack, {
@@ -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,32 +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
- 'Sub-unit is incomplete. Please visit e-ra to complete your operation.',
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
- 'Action is incomplete. Please visit e-ra to complete your operation.',
1403
+ 'Action is incomplete. Please visit app.e-ra.io to complete your operation.',
1403
1404
  reach_max_automations_per_unit:
1404
- 'Automation is incomplete. Please visit e-ra to complete your operation.',
1405
+ 'Automation is incomplete. Please visit app.e-ra.io to complete your operation.',
1405
1406
  reach_max_members_per_unit:
1406
- 'Member is incomplete. Please visit e-ra to complete your operation.',
1407
+ 'Member is incomplete. Please visit app.e-ra.io to complete your operation.',
1407
1408
  reach_max_chips_per_unit:
1408
- 'Chip is incomplete. Please visit e-ra to complete your operation.',
1409
+ 'Chip is incomplete. Please visit app.e-ra.io to complete your operation.',
1409
1410
  reach_max_configs_per_unit:
1410
- 'Config is incomplete. Please visit e-ra to complete your operation.',
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 incomplete. Please visit e-ra to complete your operation.',
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 incomplete. Please visit e-ra to complete your operation.',
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 incomplete. Please visit e-ra to complete your operation.',
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 incomplete. Please visit e-ra to complete your operation.',
1419
+ 'Add gateway is incomplete. Please visit app.e-ra.io to complete your operation.',
1419
1420
  no_permission_view_action_log:
1420
- 'View action log is incomplete. Please visit e-ra to complete your operation.',
1421
+ 'View action log is incomplete. Please visit app.e-ra.io to complete your operation.',
1421
1422
  no_permission_smart_script_for_multi_unit:
1422
- 'Smart script for Multi Unit is incomplete. Please visit e-ra to complete your operation.',
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',
1423
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,28 +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
- 'Sub-unit chưa hoàn tất. Hãy truy cập e-ra để hoàn thiện thao tác của bạn.',
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
- 'Action chưa hoàn tất. Hãy truy cập e-ra để hoàn thiện thao tác của bạn.',
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
- 'Automation chưa hoàn tất. Hãy truy cập e-ra để hoàn thiện thao tác của bạn.',
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
- 'Member chưa hoàn tất. Hãy truy cập e-ra để hoàn thiện thao tác của bạn.',
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
- 'Chip chưa hoàn tất. Hãy truy cập e-ra để hoàn thiện thao tác của bạn.',
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
- 'Config chưa hoàn tất. Hãy truy cập e-ra để hoàn thiện thao tác của bạn.',
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 chưa hoàn tất. Hãy truy cập e-ra để hoàn thiện thao tác của bạn.',
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 chưa hoàn tất. Hãy truy cập e-ra để hoàn thiện thao tác của bạn.',
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 chưa hoàn tất. Hãy truy cập e-ra để hoàn thiện thao tác của bạn.',
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 chưa hoàn tất. Hãy truy cập e-ra để hoàn thiện thao tác của bạn.',
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 chưa hoàn tất. Hãy truy cập e-ra để hoàn thiện thao tác của bạn.',
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
- 'Kịch bản thông minh cho nhiều địa điểm chưa hoàn tất. Hãy truy cập e-ra để hoàn thiện thao tác của bạn.',
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ố',
1431
1435
  };