@eohjsc/react-native-smart-city 0.7.15 → 0.7.16

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.
@@ -111,6 +111,34 @@ describe('Test ScriptDetail', () => {
111
111
  };
112
112
  });
113
113
 
114
+ const expectMockedDispatch = (screen, screenParams) => {
115
+ const mockState = {
116
+ routes: [{ name: 'Home' }],
117
+ };
118
+ const updatedState = mockedDispatch.mock.calls[0][0](mockState);
119
+ expect(updatedState).toEqual({
120
+ type: 'RESET',
121
+ payload: {
122
+ index: 2,
123
+ routes: [
124
+ {
125
+ name: 'Home',
126
+ },
127
+ {
128
+ name: Routes.ScriptDetail,
129
+ params: route.params,
130
+ },
131
+ {
132
+ name: screen,
133
+ params: screenParams,
134
+ },
135
+ ],
136
+ },
137
+ });
138
+ expect(mockedDispatch).toHaveBeenCalledTimes(1);
139
+ mockedDispatch.mockClear();
140
+ };
141
+
114
142
  it('test rename script', async () => {
115
143
  await act(async () => {
116
144
  tree = await create(wrapComponent(route));
@@ -370,56 +398,41 @@ describe('Test ScriptDetail', () => {
370
398
  AccessibilityLabel.AUTOMATE_LIST_SCRIPT_ACTION &&
371
399
  el.type === TouchableOpacity
372
400
  );
373
- expect(listScriptActions).toHaveLength(4);
401
+ expect(listScriptActions).toHaveLength(5);
374
402
  await act(async () => {
375
403
  await listScriptActions[0].props.onPress();
376
404
  });
377
405
 
378
- expect(global.mockedNavigate).toHaveBeenCalledWith(
379
- Routes.SelectControlDevices,
380
- {
381
- unitId: route.params.preAutomate.unit,
382
- automateId: route.params.preAutomate.id,
383
- numberActionCanAdd: 2,
384
- closeScreen: undefined,
385
- routeName: null,
386
- }
387
- );
388
- mockedNavigate.mockClear();
406
+ expectMockedDispatch(Routes.SelectControlDevices, {
407
+ unitId: route.params.preAutomate.unit,
408
+ automateId: route.params.preAutomate.id,
409
+ numberActionCanAdd: 2,
410
+ closeScreen: undefined,
411
+ routeName: null,
412
+ });
389
413
  await act(async () => {
390
414
  await listScriptActions[1].props.onPress();
391
415
  });
392
416
 
393
- expect(global.mockedNavigate).toHaveBeenCalledWith(
394
- Routes.SetupScriptNotify,
395
- {
396
- automate: route.params.preAutomate,
397
- unitId: route.params.preAutomate.unit,
398
- }
399
- );
400
- mockedNavigate.mockClear();
417
+ expectMockedDispatch(Routes.SetupScriptNotify, {
418
+ automate: route.params.preAutomate,
419
+ unitId: route.params.preAutomate.unit,
420
+ });
401
421
  await act(async () => {
402
422
  await listScriptActions[2].props.onPress();
403
423
  });
404
424
 
405
- expect(global.mockedNavigate).toHaveBeenCalledWith(
406
- Routes.SetupScriptDelay,
407
- {
408
- automate: route.params.preAutomate,
409
- }
410
- );
411
- mockedNavigate.mockClear();
425
+ expectMockedDispatch(Routes.SetupScriptDelay, {
426
+ automate: route.params.preAutomate,
427
+ });
412
428
  await act(async () => {
413
429
  await listScriptActions[3].props.onPress();
414
430
  });
415
431
 
416
- expect(global.mockedNavigate).toHaveBeenCalledWith(
417
- Routes.SetupScriptEmail,
418
- {
419
- automate: route.params.preAutomate,
420
- unitId: route.params.preAutomate.unit,
421
- }
422
- );
432
+ expectMockedDispatch(Routes.SetupScriptEmail, {
433
+ automate: route.params.preAutomate,
434
+ unitId: route.params.preAutomate.unit,
435
+ });
423
436
  });
424
437
 
425
438
  it('test press disable script', async () => {
@@ -19,6 +19,7 @@ import Add from '../../../../assets/images/Add.svg';
19
19
  import Delay from '../../../../assets/images/Delay.svg';
20
20
  import Notify from '../../../../assets/images/Notify.svg';
21
21
  import Email from '../../../../assets/images/Email.svg';
22
+ import Sms from '../../../../assets/images/Sms.svg';
22
23
  import IconComponent from '../../../commons/IconComponent';
23
24
  import MenuActionMore from '../../../commons/MenuActionMore';
24
25
  import WrapHeaderScrollable from '../../../commons/Sharing/WrapHeaderScrollable';
@@ -39,6 +40,8 @@ import RenameScript from './Components/RenameScript';
39
40
  import { useStarredScript } from './hooks/useStarredScript';
40
41
  import styles from './Styles/indexStyles';
41
42
  import ItemConditionScriptDetail from '../../../commons/Automate/ItemConditionScriptDetail';
43
+ import { ModalCustom } from '../../../commons/Modal';
44
+ import { Card } from '../../../commons/CardShadow';
42
45
 
43
46
  const PreventDoubleTouch = withPreventDoubleClick(TouchableOpacity);
44
47
 
@@ -68,7 +71,8 @@ const ScriptDetail = ({ route }) => {
68
71
  const [isShowRename, setIsShowRename] = useState(false);
69
72
  const [isShowDelete, setIsShowDelete] = useState(false);
70
73
  const [isShowAddAction, setIsShowAddAction] = useState(false);
71
-
74
+ const [isShowLocalControl, setIsShowLocalControl] = useState(false);
75
+ const [listChipShared, setListChipShared] = useState([]);
72
76
  const {
73
77
  script,
74
78
  type,
@@ -79,7 +83,18 @@ const ScriptDetail = ({ route }) => {
79
83
  value_change,
80
84
  } = automate;
81
85
  const { end_device_id, unit_id } = value_change || {};
82
- const { enable } = script || {};
86
+ const {
87
+ enable,
88
+ chip_local_control,
89
+ is_local_control,
90
+ chip_id_local_control,
91
+ } = script || {};
92
+
93
+ const [local_control, setLocalControl] = useState({
94
+ is_local_control,
95
+ chip_local_control,
96
+ chip_id_local_control,
97
+ });
83
98
  const [enableScript, setEnableScript] = useState(enable);
84
99
  const refMenuAction1 = useRef();
85
100
  const onShowActivityLog = useCallback(() => {
@@ -97,6 +112,42 @@ const ScriptDetail = ({ route }) => {
97
112
  });
98
113
  }, [navigate, automateId, type, unit]);
99
114
 
115
+ const handleNavigate = useCallback(
116
+ (screen, screenParams) => {
117
+ dispatch((state) => {
118
+ const index = state.routes.findIndex((r) => r.name === closeScreen);
119
+ let routes = [];
120
+ if (!closeScreen) {
121
+ routes = state.routes;
122
+ } else if (index >= 0) {
123
+ routes = state.routes.slice(0, index + 1);
124
+ }
125
+ const hasScriptDetail = routes.some(
126
+ (r) => r.name === Routes.ScriptDetail
127
+ );
128
+
129
+ if (!hasScriptDetail) {
130
+ routes.push({
131
+ name: Routes.ScriptDetail,
132
+ params: route.params,
133
+ });
134
+ }
135
+
136
+ routes.push({
137
+ name: screen,
138
+ params: screenParams,
139
+ });
140
+
141
+ return CommonActions.reset({
142
+ ...state,
143
+ routes: routes,
144
+ index: routes.length - 1,
145
+ });
146
+ });
147
+ },
148
+ [closeScreen, dispatch, route.params]
149
+ );
150
+
100
151
  const handleUpdateAutomate = useCallback(async () => {
101
152
  if (!can_edit) {
102
153
  ToastBottomHelper.error(
@@ -110,40 +161,11 @@ const ScriptDetail = ({ route }) => {
110
161
  }
111
162
 
112
163
  // Reset stack and navigate to AddUnknownTypeSmart
113
- dispatch((state) => {
114
- const index = state.routes.findIndex((r) => r.name === closeScreen);
115
- let routes = [];
116
- if (!closeScreen) {
117
- routes = state.routes;
118
- } else if (index >= 0) {
119
- routes = state.routes.slice(0, index + 1);
120
- }
121
- const hasScriptDetail = routes.some(
122
- (r) => r.name === Routes.ScriptDetail
123
- );
124
-
125
- if (!hasScriptDetail) {
126
- routes.push({
127
- name: Routes.ScriptDetail,
128
- params: route.params,
129
- });
130
- }
131
-
132
- routes.push({
133
- name: Routes.AddUnknownTypeSmart,
134
- params: {
135
- automate,
136
- closeScreen: route.name,
137
- },
138
- });
139
-
140
- return CommonActions.reset({
141
- ...state,
142
- routes: routes,
143
- index: routes.length - 1,
144
- });
164
+ handleNavigate(Routes.AddUnknownTypeSmart, {
165
+ automate,
166
+ closeScreen: route.name,
145
167
  });
146
- }, [automate, can_edit, closeScreen, enableScript, dispatch, route, t]);
168
+ }, [automate, can_edit, enableScript, route.name, t, handleNavigate]);
147
169
 
148
170
  const listMenuItem = useMemo(
149
171
  () => [
@@ -309,6 +331,83 @@ const ScriptDetail = ({ route }) => {
309
331
  showPopoverWithRef1(refMenuAction1);
310
332
  }, [showPopoverWithRef1, refMenuAction1]);
311
333
 
334
+ const onCloseLocalControl = () => setIsShowLocalControl(false);
335
+
336
+ const fetchChipShared = useCallback(async () => {
337
+ const { success, data: listChip } = await axiosGet(
338
+ API.DEV_MODE.GATEWAY.SHARED(),
339
+ {
340
+ unit: unit_id,
341
+ },
342
+ true
343
+ );
344
+ if (success) {
345
+ setListChipShared(listChip);
346
+ }
347
+ }, [unit_id]);
348
+
349
+ const onShowLocalControl = useCallback(async () => {
350
+ setIsShowLocalControl(true);
351
+ }, []);
352
+
353
+ useEffect(() => {
354
+ fetchChipShared();
355
+ }, [fetchChipShared]);
356
+
357
+ const onPressSelectChip = useCallback(
358
+ async (enable_local_control, item) => {
359
+ const { success } = await axiosPost(
360
+ API.AUTOMATE.ENABLE_LOCAL_CONTROL(automateId),
361
+ {
362
+ is_local_control: enable_local_control,
363
+ chip_local_control: item.id,
364
+ }
365
+ );
366
+ setIsShowLocalControl(false);
367
+ if (success) {
368
+ setLocalControl({
369
+ is_local_control: enable_local_control,
370
+ chip_local_control: item.name,
371
+ chip_id_local_control: item.id,
372
+ });
373
+ }
374
+ },
375
+ [automateId]
376
+ );
377
+
378
+ const renderLocalControl = useMemo(() => {
379
+ if (!!can_edit && type !== AUTOMATE_TYPE.ONE_TAP) {
380
+ return (
381
+ <View style={styles.row}>
382
+ <Text type="H3" semibold style={styles.width40}>
383
+ {t('local_control')}
384
+ </Text>
385
+ <Card style={styles.card}>
386
+ <TouchableOpacity
387
+ style={styles.localControl}
388
+ onPress={onShowLocalControl}
389
+ >
390
+ <Text numberOfLines={1}>
391
+ {local_control.is_local_control
392
+ ? local_control.chip_local_control
393
+ : t('disable')}
394
+ </Text>
395
+
396
+ <IconOutline name="down" size={15} style={styles.marginLeft5} />
397
+ </TouchableOpacity>
398
+ </Card>
399
+ </View>
400
+ );
401
+ }
402
+ }, [
403
+ can_edit,
404
+ local_control.chip_local_control,
405
+ local_control.is_local_control,
406
+ onShowLocalControl,
407
+ t,
408
+ type,
409
+ ]);
410
+
312
411
  return (
313
412
  <View style={styles.wrap}>
314
413
  <WrapHeaderScrollable
@@ -326,6 +425,7 @@ const ScriptDetail = ({ route }) => {
326
425
  <Switch value={enableScript} onValueChange={onChangeSwitch} />
327
426
  </View>
328
427
  )}
428
+ {renderLocalControl}
329
429
  <Text type="H3" semibold>
330
430
  {t('how_to_start')}
331
431
  </Text>
@@ -370,6 +470,7 @@ const ScriptDetail = ({ route }) => {
370
470
  index={index}
371
471
  enableScript={enableScript}
372
472
  t={t}
473
+ local_control={local_control}
373
474
  />
374
475
  ))}
375
476
  {!!can_edit && !!enableScript && (
@@ -414,6 +515,8 @@ const ScriptDetail = ({ route }) => {
414
515
  numberActionAdded={data.length}
415
516
  isVisible={isShowAddAction}
416
517
  setIsVisible={setIsShowAddAction}
518
+ type={type}
519
+ navigate={handleNavigate}
417
520
  />
418
521
  <RenameScript
419
522
  automate={automate}
@@ -426,14 +529,60 @@ const ScriptDetail = ({ route }) => {
426
529
  setIsVisible={setIsShowDelete}
427
530
  isVisible={isShowDelete}
428
531
  />
532
+ <ModalCustom
533
+ isVisible={isShowLocalControl}
534
+ onBackButtonPress={onCloseLocalControl}
535
+ onBackdropPress={onCloseLocalControl}
536
+ >
537
+ <View style={styles.popoverStyle}>
538
+ <TouchableOpacity
539
+ style={styles.textDisable}
540
+ onPress={() => {
541
+ onPressSelectChip(false, {
542
+ id: local_control.chip_id_local_control,
543
+ name: local_control.chip_local_control,
544
+ });
545
+ }}
546
+ >
547
+ <Text>{t('disable')}</Text>
548
+ {!local_control.is_local_control && (
549
+ <IconOutline style={styles.checked} name={'check'} size={20} />
550
+ )}
551
+ </TouchableOpacity>
552
+ {listChipShared.map((item) => (
553
+ <TouchableOpacity
554
+ style={styles.listChip}
555
+ onPress={() => {
556
+ onPressSelectChip(true, item);
557
+ }}
558
+ >
559
+ <Text>{item.name}</Text>
560
+ {local_control.chip_id_local_control === item.id &&
561
+ local_control.is_local_control && (
562
+ <IconOutline
563
+ style={styles.checked}
564
+ name={'check'}
565
+ size={20}
566
+ />
567
+ )}
568
+ </TouchableOpacity>
569
+ ))}
570
+ </View>
571
+ </ModalCustom>
429
572
  </View>
430
573
  );
431
574
  };
432
575
 
433
- const Item = ({ item, index, enableScript, t }) => {
434
- const color = enableScript ? Colors.Gray9 : Colors.Gray7;
576
+ const Item = ({ item, index, enableScript, t, local_control }) => {
577
+ let color = enableScript ? Colors.Gray9 : Colors.Gray7;
435
578
  const paddedIndex = (index + 1).toString().padStart(2, '0');
436
- const { action_script, notify_script, delay_script, email_script } = item;
579
+ const {
580
+ action_script,
581
+ notify_script,
582
+ delay_script,
583
+ email_script,
584
+ sms_script,
585
+ } = item;
437
586
  if (action_script) {
438
587
  const {
439
588
  sensor_icon_kit,
@@ -564,6 +713,38 @@ const Item = ({ item, index, enableScript, t }) => {
564
713
  </View>
565
714
  </View>
566
715
  );
716
+ } else if (sms_script) {
717
+ const { message, str_phone_numbers } = sms_script;
718
+ color = local_control.is_local_control ? color : Colors.Gray7;
719
+ return (
720
+ <View style={styles.wrapItem}>
721
+ <View style={styles.leftItem}>
722
+ <Text color={color} type="H4" semibold>
723
+ {paddedIndex}
724
+ </Text>
725
+ </View>
726
+ <View style={styles.rightItem}>
727
+ <View style={styles.insideItemRight}>
728
+ <View style={styles.iconEndDevice}>
729
+ <Sms />
730
+ </View>
731
+ <View style={styles.contentItem}>
732
+ <Text numberOfLines={1} type="H4" color={color} semibold>
733
+ {message}
734
+ </Text>
735
+ <Text numberOfLines={1} type="H4" color={color}>
736
+ {str_phone_numbers}
737
+ </Text>
738
+ </View>
739
+ </View>
740
+ {!local_control.is_local_control && (
741
+ <Text numberOfLines={1} type="H4" color={Colors.Red}>
742
+ {t('only_in_local_control')}
743
+ </Text>
744
+ )}
745
+ </View>
746
+ </View>
747
+ );
567
748
  }
568
749
  };
569
750
 
@@ -727,10 +727,13 @@ export default {
727
727
  update_title_notification: 'Update title',
728
728
  update_message_notification: 'Update warning content',
729
729
  email_content: 'E-mail content',
730
+ sms_content: 'SMS content',
730
731
  email_to: 'E-mail to',
732
+ sms_to: 'SMS to',
731
733
  subject: 'Subject',
732
734
  message: 'Message...',
733
735
  no_email: 'No email address',
736
+ no_phone_number: 'No phone number',
734
737
  update_title_email: 'Update title',
735
738
  update_message_email: 'Update warning content',
736
739
  update_action: 'Update action',
@@ -1068,9 +1071,16 @@ export default {
1068
1071
  automate: 'Automate',
1069
1072
  smart: 'Smart',
1070
1073
  enable_this_script: 'Enable this script',
1074
+ local_control: 'Local control',
1075
+ choose_gateway: 'Choose gateway',
1071
1076
  this_script_has_been_disabled: 'This script has been disabled',
1077
+ disable: 'Disable',
1072
1078
  control_device: 'Control device',
1073
1079
  send_email: 'Send e-mail',
1080
+ sms_alarm: 'SMS Alarm',
1081
+ message_sms:
1082
+ 'Warning content: "There is a fire alarm from the 1st floor, please check."',
1083
+ only_in_local_control: 'Operates only in local control mode',
1074
1084
  send_app_notification: 'Send app notification',
1075
1085
  delay_the_action: 'Delay the action',
1076
1086
  email_the_action: 'Send e-mail',
@@ -750,10 +750,13 @@ export default {
750
750
  update_title_notification: 'Cập nhật tiêu đề',
751
751
  update_message_notification: 'Cập nhật nội dung cảnh báo',
752
752
  email_content: 'Nội dung E-mail',
753
+ sms_content: 'Nội dung SMS',
753
754
  email_to: 'Gửi E-mail tới',
755
+ sms_to: 'SMS tới',
754
756
  subject: 'Tiêu đè',
755
757
  message: 'Tin nhắn...',
756
758
  no_email: 'Không có địa chỉ email',
759
+ no_phone_number: 'Không có số điện thoại',
757
760
  update_action: 'Cập nhật hành động',
758
761
  updated_action_order: 'Đã cập nhật thứ tự hành động',
759
762
  message_notification:
@@ -1078,9 +1081,16 @@ export default {
1078
1081
  automate: 'Tự động',
1079
1082
  smart: 'Thông minh',
1080
1083
  enable_this_script: 'Kích hoạt kịch bản này',
1084
+ local_control: 'Điều khiển cục bộ',
1085
+ choose_gateway: 'Chọn gateway',
1081
1086
  this_script_has_been_disabled: 'Kịch bản này đã bị vô hiệu hoá',
1087
+ disable: 'Vô hiệu hóa',
1082
1088
  control_device: 'Thiết bị điều khiển',
1083
1089
  send_email: 'Gửi e-mail',
1090
+ sms_alarm: 'Cảnh báo SMS',
1091
+ message_sms:
1092
+ 'Nội dung cảnh báo: “Đang có tín hiệu báo cháy từ lầu 1, vui lòng kiểm tra.”',
1093
+ only_in_local_control: 'Chỉ hoạt động ở chế độ điều khiển cục bộ',
1084
1094
  send_app_notification: 'Gửi thông báo qua ứng dụng',
1085
1095
  delay_the_action: 'Trì hoãn hành động',
1086
1096
  wait: 'Chờ đợi',
@@ -139,8 +139,11 @@ const Routes = {
139
139
  SetupScriptNotify: 'SetupScriptNotify',
140
140
  SetupScriptDelay: 'SetupScriptDelay',
141
141
  SetupScriptEmail: 'SetupScriptEmail',
142
+ SetupScriptSms: 'SetupScriptSms',
142
143
  SetupScriptReceiverEmail: 'SetupScriptReceiverEmail',
143
144
  UpdateReceiverEmailScript: 'UpdateReceiverEmailScript',
145
+ SetupScriptReceiverSms: 'SetupScriptReceiverSms',
146
+ UpdateReceiverSmsScript: 'UpdateReceiverSmsScript',
144
147
  ScenarioName: 'ScenarioName',
145
148
  ValueChangeName: 'ValueChangeName',
146
149
  AllCamera: 'AllCamera',