@eohjsc/react-native-smart-city 0.2.69 → 0.2.73

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.
Files changed (28) hide show
  1. package/package.json +1 -1
  2. package/src/Images/Common/buttonLeftCurtain@2x.png +0 -0
  3. package/src/Images/Common/buttonLeftCurtain@3x.png +0 -0
  4. package/src/Images/Common/{buttonPause-center-curtain.png → buttonPauseCurtain.png} +0 -0
  5. package/src/Images/Common/buttonPauseCurtain@2x.png +0 -0
  6. package/src/Images/Common/buttonPauseCurtain@3x.png +0 -0
  7. package/src/Images/Common/buttonRightCurtain@2x.png +0 -0
  8. package/src/Images/Common/buttonRightCurtain@3x.png +0 -0
  9. package/src/commons/CameraDevice/index.js +1 -1
  10. package/src/commons/Device/HorizontalBarChart.js +2 -1
  11. package/src/commons/Device/WaterQualitySensor/QualityIndicatorsItem.js +1 -1
  12. package/src/configs/Constants.js +2 -0
  13. package/src/configs/Images.js +1 -1
  14. package/src/context/SCContext.tsx +2 -0
  15. package/src/context/actionType.ts +2 -0
  16. package/src/context/reducer.ts +10 -0
  17. package/src/navigations/utils.js +3 -0
  18. package/src/screens/AddCommon/SelectSubUnit.js +10 -2
  19. package/src/screens/AddNewGateway/index.js +5 -1
  20. package/src/screens/AddNewOneTap/__test__/AddNewOneTap.test.js +0 -22
  21. package/src/screens/AddNewOneTap/index.js +15 -13
  22. package/src/screens/Notification/components/NotificationItem.js +24 -1
  23. package/src/screens/Notification/styles/NotificationItemStyles.js +1 -1
  24. package/src/screens/Sharing/SelectUser.js +13 -1
  25. package/src/screens/Unit/Detail.js +12 -9
  26. package/src/utils/I18n/translations/en.json +8 -1
  27. package/src/utils/I18n/translations/vi.json +9 -1
  28. package/src/utils/Route/index.js +1 -0
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.2.69",
4
+ "version": "0.2.73",
5
5
  "description": "TODO",
6
6
  "main": "index.js",
7
7
  "files": [
@@ -42,7 +42,7 @@ const CameraDevice = ({ station, handleFullScreen, goToPlayBack }) => {
42
42
  )}
43
43
  </View>
44
44
 
45
- {station.camera_devices.map((device) => (
45
+ {(station?.camera_devices || []).map((device) => (
46
46
  <View
47
47
  key={device.id}
48
48
  style={[
@@ -65,8 +65,9 @@ const HorizontalBarChart = memo(({ datas, config }) => {
65
65
  }
66
66
 
67
67
  const formatMoney = (number) => {
68
+ const formatNumber = number.toFixed();
68
69
  return (
69
- parseInt(number, 10)
70
+ parseInt(formatNumber, 10)
70
71
  .toFixed(0)
71
72
  .toString()
72
73
  .replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1.') + 'đ'
@@ -68,7 +68,7 @@ const styles = StyleSheet.create({
68
68
  borderWidth: 1,
69
69
  borderColor: Colors.Gray4,
70
70
  marginRight: 8,
71
- width: (width / 375) * 109,
71
+ width: (width / 375) * 112,
72
72
  },
73
73
  rowFlex: {
74
74
  flexDirection: 'row',
@@ -610,6 +610,8 @@ export const NOTIFICATION_TYPES = {
610
610
  PARKING_COMPLETED_DUE_TO_CAR_LEAVE: 'PARKING_COMPLETED_DUE_TO_CAR_LEAVE',
611
611
  NOTIFY_INVITE_MEMBER: 'NOTIFY_INVITE_MEMBER',
612
612
  REMINDER: 'REMINDER',
613
+ NOTIFY_REMOVE_UNIT: 'NOTIFY_REMOVE_UNIT',
614
+ NOTIFY_REMOVE_MEMBER: 'NOTIFY_REMOVE_MEMBER',
613
615
  };
614
616
 
615
617
  export const ACTIVITY_LOG_TYPES = {
@@ -7,7 +7,7 @@ export default {
7
7
  file: require('../Images/Common/file.png'),
8
8
  activeButton: require('../Images/Common/ActiveButton.png'),
9
9
  logo: require('../Images/Common/logo.png'),
10
- buttonPauseCurtain: require('../Images/Common/buttonPause-center-curtain.png'),
10
+ buttonPauseCurtain: require('../Images/Common/buttonPauseCurtain.png'),
11
11
  buttonLeftCurtain: require('../Images/Common/buttonLeftCurtain.png'),
12
12
  buttonRightCurtain: require('../Images/Common/buttonRightCurtain.png'),
13
13
  };
@@ -9,6 +9,7 @@ import {
9
9
  } from './actionType';
10
10
  import { initialState, Action, ContextData, reducer } from './reducer';
11
11
  import { setConfigGlobalState } from '../iot/states.js';
12
+ import { setAxiosDefaultLanguage } from '../utils/Utils';
12
13
 
13
14
  type SCContextType = {
14
15
  stateData: ContextData;
@@ -46,6 +47,7 @@ export const SCProvider = ({ children, initState = initialState }) => {
46
47
  const setLocale = (language: Language) => {
47
48
  setConfigGlobalState('lang', language);
48
49
  setAction('UPDATE_LANGUAGE', language);
50
+ setAxiosDefaultLanguage(language);
49
51
  };
50
52
 
51
53
  const setAction = <T extends ActionType>(
@@ -5,6 +5,7 @@ export const Action = {
5
5
  LIST_DEVICE_TYPES: 'LIST_DEVICE_TYPES',
6
6
  LIST_ACTION: 'LIST_ACTION',
7
7
  IS_FIRST_OPEN_CAMERA: 'IS_FIRST_OPEN_CAMERA',
8
+ IS_LAVIDA_SOURCE: 'IS_LAVIDA_SOURCE',
8
9
  };
9
10
 
10
11
  export type AuthData = {
@@ -48,4 +49,5 @@ export type ActionDataMap = {
48
49
 
49
50
  export type AppType = {
50
51
  isFirstOpenCamera: boolean;
52
+ isLavidaSource: boolean;
51
53
  };
@@ -39,6 +39,7 @@ export const initialState = {
39
39
  listAction: [] as ListAction,
40
40
  app: {
41
41
  isFirstOpenCamera: true,
42
+ isLavidaSource: false,
42
43
  },
43
44
  };
44
45
 
@@ -97,6 +98,15 @@ export const reducer = (currentState: ContextData, action: Action) => {
97
98
  isFirstOpenCamera: payload,
98
99
  },
99
100
  };
101
+ case Action.IS_LAVIDA_SOURCE: {
102
+ return {
103
+ ...currentState,
104
+ app: {
105
+ ...currentState.app,
106
+ isLavidaSource: payload,
107
+ },
108
+ };
109
+ }
100
110
  default:
101
111
  return currentState;
102
112
  }
@@ -19,6 +19,9 @@ export const screenOptions = {
19
19
 
20
20
  export const popAction = (value) => StackActions.pop(value);
21
21
 
22
+ export const replace = (routeName, params) =>
23
+ StackActions.replace(routeName, params);
24
+
22
25
  export default {
23
26
  navigate,
24
27
  goBack,
@@ -17,8 +17,14 @@ const AddCommonSelectSubUnit = ({ route }) => {
17
17
  const t = useTranslations();
18
18
  const navigation = useNavigation();
19
19
  const isFocused = useIsFocused();
20
- const { addType, unit_id, sensor_data, listSelectDevice, smart_account_id } =
21
- route.params;
20
+ const {
21
+ addType,
22
+ unit_id,
23
+ sensor_data,
24
+ listSelectDevice,
25
+ smart_account_id,
26
+ smart_account_id_from_backend,
27
+ } = route.params;
22
28
  const [selectedIndex, setSelectedIndex] = useState(-1);
23
29
  const [unit, setUnit] = useState([]);
24
30
  const [title, setTitle] = useState('');
@@ -79,6 +85,7 @@ const AddCommonSelectSubUnit = ({ route }) => {
79
85
  listSelectDevice: listSelectDevice,
80
86
  smart_account_id: smart_account_id,
81
87
  unit_id: unit_id,
88
+ smart_account_id_from_backend: smart_account_id_from_backend,
82
89
  });
83
90
  break;
84
91
  case 'AddVconnexDevice':
@@ -107,6 +114,7 @@ const AddCommonSelectSubUnit = ({ route }) => {
107
114
  listSelectDevice,
108
115
  smart_account_id,
109
116
  unit_id,
117
+ smart_account_id_from_backend,
110
118
  ]);
111
119
 
112
120
  const handleSelectIndex = (index) => {
@@ -48,6 +48,10 @@ const AddNewGateway = memo(({ route }) => {
48
48
  return true;
49
49
  }, [chipName, imei]);
50
50
 
51
+ const textGateWay = !wifiName
52
+ ? t('please_add_your_phone_number_and_chip_name')
53
+ : t('Please_add_gateway_name');
54
+
51
55
  return (
52
56
  <SafeAreaView style={styles.wrap}>
53
57
  <Text
@@ -65,7 +69,7 @@ const AddNewGateway = memo(({ route }) => {
65
69
  color={Colors.Gray8}
66
70
  style={styles.textNote}
67
71
  >
68
- {t('please_add_your_phone_number_and_chip_name')}
72
+ {textGateWay}
69
73
  </Text>
70
74
 
71
75
  <ScrollView
@@ -99,28 +99,6 @@ describe('test AddNewOneTap', () => {
99
99
  await act(async () => {
100
100
  await item[0].props.onPress();
101
101
  });
102
- expect(mockedNavigate).toHaveBeenCalledWith(Routes.ScriptDetail, {
103
- havePermission: true,
104
- id: 1,
105
- type: 'one_tap',
106
- name: 'Tap to up',
107
- unit: {
108
- id: 1,
109
- },
110
- isCreateScriptSuccess: true,
111
- automate: {
112
- id: 1,
113
- script: {
114
- id: 1,
115
- name: 'William Miller',
116
- },
117
- type: 'one_tap',
118
- unit: 1,
119
- weekday_repeat: [],
120
- },
121
- isAutomateTab: false,
122
- isMultiUnits: false,
123
- });
124
102
  });
125
103
  test('create AddNewOneTap fail', async () => {
126
104
  Platform.OS = 'android';
@@ -12,7 +12,7 @@ import Text from '../../commons/Text';
12
12
  import { useTranslations } from '../../hooks/Common/useTranslations';
13
13
  import { axiosPost, axiosPut } from '../../utils/Apis/axios';
14
14
  import Routes from '../../utils/Route';
15
- import { popAction } from '../../navigations/utils';
15
+ import { popAction, replace } from '../../navigations/utils';
16
16
  import { AUTOMATE_TYPE } from '../../configs/Constants';
17
17
 
18
18
  const AddNewOneTap = memo(({ route }) => {
@@ -41,17 +41,19 @@ const AddNewOneTap = memo(({ route }) => {
41
41
  ? await axiosPut(API.AUTOMATE.UPDATE_AUTOMATE(automateId), params)
42
42
  : await axiosPost(API.AUTOMATE.CREATE_AUTOMATE(), params);
43
43
  if (success) {
44
- navigate(Routes.ScriptDetail, {
45
- unit: unit,
46
- id: data.id,
47
- name: name,
48
- type: type,
49
- automate: { ...automate, ...data },
50
- havePermission: true,
51
- isCreateScriptSuccess: true,
52
- isAutomateTab: isAutomateTab,
53
- isMultiUnits,
54
- });
44
+ dispatch(
45
+ replace(Routes.ScriptDetail, {
46
+ unit: unit,
47
+ id: data.id,
48
+ name: name,
49
+ type: type,
50
+ automate: { ...automate, ...data },
51
+ havePermission: true,
52
+ isCreateScriptSuccess: true,
53
+ isAutomateTab: isAutomateTab,
54
+ isMultiUnits,
55
+ })
56
+ );
55
57
  }
56
58
  }, [
57
59
  isMultiUnits,
@@ -61,7 +63,7 @@ const AddNewOneTap = memo(({ route }) => {
61
63
  automateData,
62
64
  automate,
63
65
  automateId,
64
- navigate,
66
+ dispatch,
65
67
  isAutomateTab,
66
68
  ]);
67
69
 
@@ -67,7 +67,7 @@ const NotificationItem = memo(({ item }) => {
67
67
  iconContent: (
68
68
  <IconComponent
69
69
  icon_outlined={'usergroup-add'}
70
- style={styles.iconInviteMember}
70
+ style={styles.backgroundSummer}
71
71
  />
72
72
  ),
73
73
  };
@@ -220,6 +220,29 @@ const NotificationItem = memo(({ item }) => {
220
220
  params: { id: booking_id },
221
221
  }),
222
222
  };
223
+ case NOTIFICATION_TYPES.NOTIFY_REMOVE_UNIT:
224
+ const unitOwerName = paramsJSON?.unit_owner_name;
225
+ const textNotify = unitOwerName
226
+ ? t('text_notification_content_remove_unit_to_member')
227
+ : t('text_notification_content_remove_unit_to_owner');
228
+ return {
229
+ content: customColorText(textNotify, arrParams),
230
+ redirect: () => null,
231
+ iconContent: (
232
+ <IconComponent icon={'home'} style={styles.backgroundSummer} />
233
+ ),
234
+ };
235
+ case NOTIFICATION_TYPES.NOTIFY_REMOVE_MEMBER:
236
+ return {
237
+ content: customColorText(
238
+ t('text_notification_content_remove_member'),
239
+ arrParams
240
+ ),
241
+ redirect: () => null,
242
+ iconContent: (
243
+ <IconComponent icon={'home'} style={styles.backgroundSummer} />
244
+ ),
245
+ };
223
246
  default:
224
247
  return {
225
248
  content: customColorText(t('this_notification_will_be_updated_soon')),
@@ -33,7 +33,7 @@ export default StyleSheet.create({
33
33
  iconNotification: {
34
34
  width: '46%',
35
35
  },
36
- iconInviteMember: {
36
+ backgroundSummer: {
37
37
  width: '46%',
38
38
  color: Colors.Summer,
39
39
  },
@@ -21,6 +21,7 @@ import {
21
21
  import { axiosPost } from '../../utils/Apis/axios';
22
22
  import { TESTID } from '../../configs/Constants';
23
23
  import Text from '../../commons/Text';
24
+ import { ToastBottomHelper } from '../../utils/Utils';
24
25
 
25
26
  const SelectUser = ({ route }) => {
26
27
  const t = useTranslations();
@@ -46,9 +47,20 @@ const SelectUser = ({ route }) => {
46
47
  });
47
48
  if (success) {
48
49
  setUsers([...users, data.user]);
50
+ } else {
51
+ const textTemp = t(
52
+ data?.phone
53
+ ? 'text_phone_share_permission'
54
+ : data?.email
55
+ ? 'text_email_share_permission'
56
+ : ''
57
+ );
58
+ ToastBottomHelper.error(
59
+ t('error_share_permission', { data: phone || email, text: textTemp })
60
+ );
49
61
  }
50
62
  },
51
- [unit, permissions, users]
63
+ [users, unit.id, permissions, t]
52
64
  );
53
65
 
54
66
  const validate = useCallback(() => {
@@ -18,7 +18,7 @@ import { lgThinqConnect } from '../../iot/RemoteControl/LG';
18
18
  import ShortDetailSubUnit from '../../commons/SubUnit/ShortDetail';
19
19
  import NavBar from '../../commons/NavBar';
20
20
  import WrapParallaxScrollView from '../../commons/WrapParallaxScrollView';
21
- import { SCContext } from '../../context';
21
+ import { SCContext, useSCContextSelector } from '../../context';
22
22
  import { Action } from '../../context/actionType';
23
23
  import CameraDevice from '../../commons/CameraDevice';
24
24
  import { ModalFullVideo } from '../../commons/Modal';
@@ -43,6 +43,9 @@ const UnitDetail = ({ route }) => {
43
43
  const isFocused = useIsFocused();
44
44
  const { stateData, setAction } = useContext(SCContext);
45
45
  const { navigate } = useNavigation();
46
+ const isLavidaSource = useSCContextSelector(
47
+ (state) => state.app.isLavidaSource
48
+ );
46
49
 
47
50
  const [unit, setUnit] = useState(unitData || { id: unitId });
48
51
  const [appState, setAppState] = useState(AppState.currentState);
@@ -122,12 +125,12 @@ const UnitDetail = ({ route }) => {
122
125
  if (success) {
123
126
  setListAutomate([
124
127
  {
125
- text: t(AUTOMATE_TYPE.ONE_TAP),
128
+ text: t(AUTOMATE_TYPE.SCENARIO),
126
129
  data: data.filter((item) => item.type === AUTOMATE_TYPE.ONE_TAP),
127
130
  type: AUTOMATE_TYPE.ONE_TAP,
128
131
  },
129
132
  {
130
- text: t(AUTOMATE_TYPE.SCENARIO),
133
+ text: t(AUTOMATE_TYPE.AUTOMATION),
131
134
  data: data.filter((item) => item.type !== AUTOMATE_TYPE.ONE_TAP),
132
135
  type: AUTOMATE_TYPE.AUTOMATION,
133
136
  },
@@ -273,7 +276,7 @@ const UnitDetail = ({ route }) => {
273
276
  />
274
277
  );
275
278
  }
276
- if (station.camera_devices) {
279
+ if (station?.camera_devices) {
277
280
  return (
278
281
  <CameraDevice
279
282
  station={station}
@@ -281,7 +284,7 @@ const UnitDetail = ({ route }) => {
281
284
  goToPlayBack={goToPlayBack}
282
285
  />
283
286
  );
284
- } else if (station.isOneTap) {
287
+ } else if (station?.isOneTap) {
285
288
  return (
286
289
  <SubUnitAutomate
287
290
  isOwner={isOwner}
@@ -302,12 +305,12 @@ const UnitDetail = ({ route }) => {
302
305
  };
303
306
 
304
307
  const onBack = useCallback(() => {
305
- navigate(routeName);
306
- }, [navigate, routeName]);
308
+ navigate(isLavidaSource ? Routes.SmartHomeDashboard : routeName);
309
+ }, [navigate, routeName, isLavidaSource]);
307
310
 
308
311
  const Dashboard = useCallback(() => {
309
- navigate(Routes.Dashboard);
310
- }, [navigate]);
312
+ navigate(isLavidaSource ? Routes.SmartHomeDashboard : Routes.Dashboard);
313
+ }, [isLavidaSource, navigate]);
311
314
 
312
315
  return (
313
316
  <WrapParallaxScrollView
@@ -196,7 +196,7 @@
196
196
  "text_poor_level": "Poor",
197
197
  "text_very_poor_level": "Very poor",
198
198
  "text_clo_low_range": "< 0.2 mg/l",
199
- "text_clo_good_range": "< 0.2 - 0.5 mg/l",
199
+ "text_clo_good_range": "0.2 - 0.5 mg/l",
200
200
  "text_clo_high_range": "> 0.5 mg/l",
201
201
  "turbidity_guide": "Water Turbidity Guide",
202
202
  "what_is_turbidity": "What is Water Turbidity?",
@@ -668,6 +668,9 @@
668
668
  "text_notification_content_pay_fine_successfully": "Your violation **%{booking}** has been paid successfully.",
669
669
  "text_notification_content_pay_fine_and_extend_successfully": "Your violation **%{booking_id_old}** has been paid successfully. The new parking session **%{booking_id_new}** is now extended until **%{leave_time}**.",
670
670
  "text_notification_content_stop_violation_free_parking_zone": "Free parking zone. You have an unpaid violation. Please complete your fine.",
671
+ "text_notification_content_remove_unit_to_owner": "Unit **%{unit_name}** has been removed successfully.",
672
+ "text_notification_content_remove_unit_to_member": "Unit **%{unit_name}** has been removed by **%{unit_owner_name}**. You cannot access to this unit anymore.",
673
+ "text_notification_content_remove_member": "You were remove from **%{unit_name}** by **%{unit_owner_name}**. You cannot access to this unit anymore.",
671
674
  "this_spot_does_not_exsit": "This spot does not exist",
672
675
  "please_scan_again_or_contact_the_parking_manager": "Please scan again or contact the parking manager",
673
676
  "this_spot_does_not_support_to_scan": "This spot does not support to scan",
@@ -747,6 +750,7 @@
747
750
  "edit_actions_list": "Edit Actions List",
748
751
  "des_edit_actions_list": "Hold and hover to rearrange actions order",
749
752
  "please_add_your_phone_number_and_chip_name": "Please add your phone number and chip name",
753
+ "Please_add_gateway_name" : "Please add gateway name",
750
754
  "phone_number_of_data_sim": "Phone number of data sim",
751
755
  "select_a_sub_unit": "Select a sub-unit that you want to add this gateway",
752
756
  "all_camera": "All Cameras",
@@ -889,5 +893,8 @@
889
893
  "location_permission_required_wifi_message": "This app needs location permission as this is required to scan for wifi networks.",
890
894
  "deny": "DENY",
891
895
  "allow": "ALLOW",
896
+ "error_share_permission": "{text} {data} does not exist!",
897
+ "text_phone_share_permission": "The phone",
898
+ "text_email_share_permission": "Email",
892
899
  "yes_remove": "Yes,remove"
893
900
  }
@@ -232,7 +232,7 @@
232
232
  "text_poor_level": "Kém",
233
233
  "text_very_poor_level": "Rất kém",
234
234
  "text_clo_low_range": "< 0.2 mg/l",
235
- "text_clo_good_range": "< 0.2 - 0.5 mg/l",
235
+ "text_clo_good_range": "0.2 - 0.5 mg/l",
236
236
  "text_clo_high_range": "> 0.5 mg/l",
237
237
  "turbidity_guide": "Độ đục",
238
238
  "what_is_turbidity": "Độ đục của nước là gì?",
@@ -676,6 +676,9 @@
676
676
  "text_notification_content_pay_fine_successfully": "Đỗ xe vi phạm **%{booking}** của bạn đã được thanh toán.",
677
677
  "text_notification_content_pay_fine_and_extend_successfully": "Đỗ xe vi phạm **%{oldbooking}** của bạn đã được thanh toán thành công. Phiên đỗ xe mới **%{newbooking}** sẽ kết thúc vào lúc **%{time}**.",
678
678
  "text_notification_content_stop_violation_free_parking_zone": "Thời gian đậu xe miễn phí. Bạn có một vi phạm chưa được thanh toán. Vui lòng hoàn thành tiền phạt của bạn.",
679
+ "text_notification_content_remove_unit_to_owner": "Địa điểm **%{unit_name}** vừa được xoá thành công.",
680
+ "text_notification_content_remove_unit_to_member": "Địa điểm **%{unit_name}** vừa được xoá bởi **%{unit_owner_name}**. Bạn không thể truy cập vào địa điểm này được nữa.",
681
+ "text_notification_content_remove_member": "Bạn vừa được xoá khỏi **%{unit_name}** bởi **%{unit_owner_name}**. Bạn không thể truy cập vào địa điểm này được nữa.",
679
682
  "this_spot_does_not_exsit": "Vị trí đỗ này không tồn tại",
680
683
  "please_scan_again_or_contact_the_parking_manager": "Vui lòng quét lại hoặc liên hệ với người quản lý bãi đậu xe",
681
684
  "this_spot_does_not_support_to_scan": "Vị trí đỗ này không hỗ trợ quét",
@@ -685,6 +688,7 @@
685
688
  "command_send_fail_googlehome": "Lệnh gởi thất bại đến google home",
686
689
  "command_googlehome_ready": "Google Home kết nối thành công",
687
690
  "command_googlehome_lost": "Google Home bị mất kết nối. Đang kết nối lại...",
691
+ "text_sub_unit_not_have_device": "Khu vực không có thiết bị để điều khiển",
688
692
  "confirm": "Xác nhận",
689
693
  "car_validate_warning": "Vui lòng nhập đúng định dạng biển số xe \nVD: %{example}",
690
694
  "are_you_sure_this_resolved": "Bạn có chắc tình huống khẩn cấp này đã được xử lý xong? Các thành viên thuộc địa điểm này cũng sẽ nhận được thông báo.",
@@ -750,6 +754,7 @@
750
754
  "modbus_fail": "Modbus failrate",
751
755
  "rssi_node": "RSSI Node",
752
756
  "please_add_your_phone_number_and_chip_name": "Vui lòng thêm số điện thoại và tên chip của bạn",
757
+ "Please_add_gateway_name" : "Vui lòng thêm tên gateway",
753
758
  "phone_number_of_data_sim": "Số điện thoại của dữ liệu sim",
754
759
  "select_a_sub_unit": "Lựa chọn một khu vực mà bạn muốn thêm gateway",
755
760
  "all_camera": "All Cameras",
@@ -891,5 +896,8 @@
891
896
  "location_permission_required_wifi_message": "Ứng dụng này cần có quyền định vị vì ứng dụng này được yêu cầu để quét các mạng Wi-Fi.",
892
897
  "deny": "Từ chối",
893
898
  "allow": "Cho phép",
899
+ "error_share_permission": "{text} {data} không tồn tại!",
900
+ "text_phone_share_permission": "Số điện thoại",
901
+ "text_email_share_permission": "Email",
894
902
  "yes_remove": "Có,loại bỏ"
895
903
  }
@@ -126,6 +126,7 @@ const Routes = {
126
126
  GatewayWifiList: 'GatewayWifiList',
127
127
  ConfirmUnitDeletion: 'ConfirmUnitDeletion',
128
128
  SmartAccount: 'SmartAccount',
129
+ SmartHomeDashboard: 'SmartHomeDashboard',
129
130
  };
130
131
 
131
132
  export default Routes;