@eohjsc/react-native-smart-city 0.4.96 → 0.4.97

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.4.96",
4
+ "version": "0.4.97",
5
5
  "description": "TODO",
6
6
  "main": "index.js",
7
7
  "files": [
@@ -76,10 +76,7 @@ const OnOffTemplate = memo(({ item = {}, doAction, sensor = {} }) => {
76
76
  config_value: isOn ? 0 : 1,
77
77
  };
78
78
  }
79
-
80
- if (device_type === DEVICE_TYPE.LG_THINQ) {
81
- setTempIsOn((prev) => !prev);
82
- }
79
+ setTempIsOn((prev) => !prev);
83
80
  await doAction(action_data, data);
84
81
  updateStatusFromPusher(); // todo Bang read about this magic
85
82
 
@@ -46,7 +46,7 @@ const TextBoxTemplate = ({ item, doAction, isWidgetOrder }) => {
46
46
  <AlertAction
47
47
  visible={stateAlert.visible}
48
48
  hideModal={hideAlertAction}
49
- title={t('change')}
49
+ title={t('enter_parameters')}
50
50
  message={stateAlert.message}
51
51
  leftButtonTitle={stateAlert.leftButton}
52
52
  leftButtonClick={hideAlertAction}
@@ -44,7 +44,4 @@ export default StyleSheet.create({
44
44
  marginBottom: 24,
45
45
  marginTop: 16,
46
46
  },
47
- flexContent: {
48
- // flexDirection: 'row',
49
- },
50
47
  });
@@ -0,0 +1,97 @@
1
+ import React, { memo, useState, useCallback, useEffect } from 'react';
2
+ import { View, TouchableOpacity } from 'react-native';
3
+ import { useTranslations } from '../../hooks/Common/useTranslations';
4
+ import styles from './TextBoxActionTemplateStyles';
5
+ import { Colors } from '../../configs';
6
+ import SelectActionCard from '../SelectActionCard';
7
+ import Text from '../Text';
8
+ import { useConfigGlobalState } from '../../iot/states';
9
+ import { AccessibilityLabel } from '../../configs/Constants';
10
+ import { ModalCustom } from '../Modal';
11
+ import _TextInput from '../Form/TextInput';
12
+
13
+ const SliderRangeActionTemplate = ({ device, item, onSelectAction }) => {
14
+ const t = useTranslations();
15
+ const [visible, setVisible] = useState(false);
16
+ const onClose = () => setVisible(false);
17
+ const onPress = () => setVisible(true);
18
+ const { configuration, template, title } = item;
19
+ const { config, action } = configuration;
20
+ const [configValues] = useConfigGlobalState('configValues');
21
+ const [value, setValue] = useState();
22
+
23
+ const onInputChange = (value) => {
24
+ setValue(value);
25
+ };
26
+
27
+ useEffect(() => {
28
+ const configValue = configValues[config.id]?.value;
29
+ setValue(configValue);
30
+ }, [configValues, config]);
31
+
32
+ const onPressDone = useCallback(() => {
33
+ let actionData = { value: value };
34
+ setValue(value);
35
+ onSelectAction &&
36
+ onSelectAction({
37
+ index: item.index,
38
+ action,
39
+ data: actionData,
40
+ template,
41
+ });
42
+ onClose();
43
+ }, [value, onSelectAction, item.index, action, template]);
44
+
45
+ return (
46
+ <>
47
+ <SelectActionCard onPress={onPress} action={value} title={title} />
48
+
49
+ <ModalCustom
50
+ isVisible={visible}
51
+ onBackButtonPress={onClose}
52
+ onBackdropPress={onClose}
53
+ >
54
+ <View style={styles.popoverStyle}>
55
+ <View>
56
+ <Text type="H4" bold style={styles.textWithLine}>
57
+ {t('enter_value')}
58
+ </Text>
59
+ <View style={styles.modalContent}>
60
+ <_TextInput
61
+ wrapStyle={styles.wrapInputStyle}
62
+ value={value}
63
+ onChange={onInputChange}
64
+ keyboardType={'numeric'}
65
+ />
66
+ </View>
67
+ <View style={styles.wrapButton}>
68
+ <TouchableOpacity
69
+ onPress={onClose}
70
+ accessibilityLabel={AccessibilityLabel.BUTTON_CANCEL}
71
+ >
72
+ <Text type="H4" bold color={Colors.Primary}>
73
+ {t('cancel')}
74
+ </Text>
75
+ </TouchableOpacity>
76
+ <TouchableOpacity
77
+ onPress={onPressDone}
78
+ accessibilityLabel={AccessibilityLabel.BUTTON_DONE}
79
+ disabled={!value}
80
+ >
81
+ <Text
82
+ type="H4"
83
+ bold
84
+ color={!value ? Colors.Gray : Colors.Primary}
85
+ >
86
+ {t('done')}
87
+ </Text>
88
+ </TouchableOpacity>
89
+ </View>
90
+ </View>
91
+ </View>
92
+ </ModalCustom>
93
+ </>
94
+ );
95
+ };
96
+
97
+ export default memo(SliderRangeActionTemplate);
@@ -0,0 +1,96 @@
1
+ import React, { memo, useState, useCallback, useEffect } from 'react';
2
+ import { View, TouchableOpacity } from 'react-native';
3
+ import { useTranslations } from '../../hooks/Common/useTranslations';
4
+ import styles from './TextBoxActionTemplateStyles';
5
+ import { Colors } from '../../configs';
6
+ import SelectActionCard from '../SelectActionCard';
7
+ import Text from '../Text';
8
+ import { useConfigGlobalState } from '../../iot/states';
9
+ import { AccessibilityLabel } from '../../configs/Constants';
10
+ import { ModalCustom } from '../Modal';
11
+ import _TextInput from '../Form/TextInput';
12
+
13
+ const TextBoxActionTemplate = ({ device, item, onSelectAction }) => {
14
+ const t = useTranslations();
15
+ const [visible, setVisible] = useState(false);
16
+ const onClose = () => setVisible(false);
17
+ const onPress = () => setVisible(true);
18
+ const { configuration, template, title } = item;
19
+ const { config, action } = configuration;
20
+ const [configValues] = useConfigGlobalState('configValues');
21
+ const [value, setValue] = useState();
22
+
23
+ const onInputChange = (value) => {
24
+ setValue(value);
25
+ };
26
+
27
+ useEffect(() => {
28
+ const configValue = configValues[config.id]?.value;
29
+
30
+ setValue(configValue);
31
+ }, [configValues, config]);
32
+
33
+ const onPressDone = useCallback(() => {
34
+ let actionData = { value: value };
35
+ setValue(value);
36
+ onSelectAction &&
37
+ onSelectAction({
38
+ index: item.index,
39
+ action,
40
+ data: actionData,
41
+ template,
42
+ });
43
+ onClose();
44
+ }, [value, onSelectAction, item.index, action, template]);
45
+
46
+ return (
47
+ <>
48
+ <SelectActionCard onPress={onPress} action={value} title={title} />
49
+ <ModalCustom
50
+ isVisible={visible}
51
+ onBackButtonPress={onClose}
52
+ onBackdropPress={onClose}
53
+ >
54
+ <View style={styles.popoverStyle}>
55
+ <View>
56
+ <Text type="H4" bold style={styles.textWithLine}>
57
+ {t('enter_parameters')}
58
+ </Text>
59
+ <View style={styles.modalContent}>
60
+ <_TextInput
61
+ wrapStyle={styles.wrapInputStyle}
62
+ value={value}
63
+ onChange={onInputChange}
64
+ />
65
+ </View>
66
+ <View style={styles.wrapButton}>
67
+ <TouchableOpacity
68
+ onPress={onClose}
69
+ accessibilityLabel={AccessibilityLabel.TEXT_BOX_BUTTON_CANCEL}
70
+ >
71
+ <Text type="H4" bold color={Colors.Primary}>
72
+ {t('cancel')}
73
+ </Text>
74
+ </TouchableOpacity>
75
+ <TouchableOpacity
76
+ onPress={onPressDone}
77
+ accessibilityLabel={AccessibilityLabel.TEXT_BOX_BUTTON_DONE}
78
+ disabled={!value}
79
+ >
80
+ <Text
81
+ type="H4"
82
+ bold
83
+ color={!!value ? Colors.Primary : Colors.Gray}
84
+ >
85
+ {t('done')}
86
+ </Text>
87
+ </TouchableOpacity>
88
+ </View>
89
+ </View>
90
+ </View>
91
+ </ModalCustom>
92
+ </>
93
+ );
94
+ };
95
+
96
+ export default memo(TextBoxActionTemplate);
@@ -0,0 +1,28 @@
1
+ import { StyleSheet } from 'react-native';
2
+ import { Colors } from '../../configs';
3
+
4
+ export default StyleSheet.create({
5
+ popoverStyle: {
6
+ width: '100%',
7
+ backgroundColor: Colors.White,
8
+ borderRadius: 10,
9
+ },
10
+ textWithLine: {
11
+ padding: 16,
12
+ },
13
+ modalContent: {
14
+ paddingBottom: 26,
15
+ flexDirection: 'row',
16
+ justifyContent: 'center',
17
+ alignItems: 'center',
18
+ },
19
+ wrapInputStyle: {
20
+ width: '90%',
21
+ },
22
+ wrapButton: {
23
+ flexDirection: 'row',
24
+ justifyContent: 'space-around',
25
+ alignItems: 'center',
26
+ marginBottom: 24,
27
+ },
28
+ });
@@ -0,0 +1,96 @@
1
+ import React from 'react';
2
+ import { create, act } from 'react-test-renderer';
3
+ import { SCProvider } from '../../../context';
4
+ import { mockSCStore } from '../../../context/mockStore';
5
+ import { TouchableOpacity } from 'react-native';
6
+ import { AccessibilityLabel } from '../../../configs/Constants';
7
+ import SelectActionCard from '../../SelectActionCard';
8
+ import _TextInput from '../../Form/TextInput';
9
+ import SliderRangeActionTemplate from '../SliderRangeActionTemplate';
10
+
11
+ const mockOnSelectAction = jest.fn();
12
+
13
+ const wrapComponent = (item, params = {}) => (
14
+ <SCProvider initState={mockSCStore({})}>
15
+ <SliderRangeActionTemplate
16
+ item={item}
17
+ onSelectAction={mockOnSelectAction}
18
+ {...params}
19
+ />
20
+ </SCProvider>
21
+ );
22
+
23
+ describe('Test SliderRangeActionTemplate', () => {
24
+ let tree;
25
+ let data = {
26
+ title: 'Slider range',
27
+ template: 'slider_range_template',
28
+ configuration: {
29
+ keep_track_config: true,
30
+ config: { id: 1023 },
31
+ action: 'b498234c-6c1a-452d-a1d1-87a314c20528',
32
+ },
33
+ };
34
+
35
+ beforeEach(() => {
36
+ mockOnSelectAction.mockClear();
37
+ });
38
+
39
+ const renderOptions = async (params = {}) => {
40
+ await act(async () => {
41
+ tree = await create(wrapComponent(data, params));
42
+ });
43
+ const instance = tree.root;
44
+ const card = instance.findByType(SelectActionCard);
45
+ await act(async () => {
46
+ card.props.onPress();
47
+ });
48
+ return instance;
49
+ };
50
+
51
+ it('Test onPress Done', async () => {
52
+ const instance = await renderOptions();
53
+ const textInput = instance.findByType(_TextInput);
54
+ await act(async () => {
55
+ await textInput.props.onChange('123');
56
+ });
57
+ const touchableOpacity = instance.find(
58
+ (item) =>
59
+ item.props.accessibilityLabel === AccessibilityLabel.BUTTON_DONE &&
60
+ item.type === TouchableOpacity
61
+ );
62
+ await act(async () => {
63
+ touchableOpacity.props.onPress();
64
+ });
65
+ expect(mockOnSelectAction).toHaveBeenCalledWith({
66
+ action: 'b498234c-6c1a-452d-a1d1-87a314c20528',
67
+ data: { value: '123' },
68
+ index: undefined,
69
+ template: 'slider_range_template',
70
+ });
71
+ });
72
+
73
+ it('Test onPress Cancel', async () => {
74
+ const instance = await renderOptions();
75
+ const textInput = instance.findByType(_TextInput);
76
+ await act(async () => {
77
+ await textInput.props.onChange('');
78
+ });
79
+ const touchableDone = instance.find(
80
+ (item) =>
81
+ item.props.accessibilityLabel === AccessibilityLabel.BUTTON_DONE &&
82
+ item.type === TouchableOpacity
83
+ );
84
+ expect(touchableDone.props.disabled).toBeTruthy();
85
+
86
+ const touchableOpacity = instance.find(
87
+ (item) =>
88
+ item.props.accessibilityLabel === AccessibilityLabel.BUTTON_CANCEL &&
89
+ item.type === TouchableOpacity
90
+ );
91
+ await act(async () => {
92
+ touchableOpacity.props.onPress();
93
+ });
94
+ expect(mockOnSelectAction).not.toHaveBeenCalled();
95
+ });
96
+ });
@@ -0,0 +1,99 @@
1
+ import React from 'react';
2
+ import { create, act } from 'react-test-renderer';
3
+ import { SCProvider } from '../../../context';
4
+ import { mockSCStore } from '../../../context/mockStore';
5
+ import { TouchableOpacity } from 'react-native';
6
+ import { AccessibilityLabel } from '../../../configs/Constants';
7
+ import SelectActionCard from '../../SelectActionCard';
8
+ import TextBoxActionTemplate from '../TextBoxActionTemplate';
9
+ import _TextInput from '../../Form/TextInput';
10
+
11
+ const mockOnSelectAction = jest.fn();
12
+
13
+ const wrapComponent = (item, params = {}) => (
14
+ <SCProvider initState={mockSCStore({})}>
15
+ <TextBoxActionTemplate
16
+ item={item}
17
+ onSelectAction={mockOnSelectAction}
18
+ {...params}
19
+ />
20
+ </SCProvider>
21
+ );
22
+
23
+ describe('Test TextBoxActionTemplate', () => {
24
+ let tree;
25
+ let data = {
26
+ title: '',
27
+ template: 'TextBoxTemplate',
28
+ configuration: {
29
+ keep_track_config: true,
30
+ config: { id: 1023 },
31
+ action: 'b498234c-6c1a-452d-a1d1-87a314c20528',
32
+ },
33
+ };
34
+
35
+ beforeEach(() => {
36
+ mockOnSelectAction.mockClear();
37
+ });
38
+
39
+ const renderOptions = async (params = {}) => {
40
+ await act(async () => {
41
+ tree = await create(wrapComponent(data, params));
42
+ });
43
+ const instance = tree.root;
44
+ const card = instance.findByType(SelectActionCard);
45
+ await act(async () => {
46
+ card.props.onPress();
47
+ });
48
+ return instance;
49
+ };
50
+
51
+ it('Test onPress Done', async () => {
52
+ const instance = await renderOptions();
53
+ const textInput = instance.findByType(_TextInput);
54
+ await act(async () => {
55
+ await textInput.props.onChange('123');
56
+ });
57
+ const touchableOpacity = instance.find(
58
+ (item) =>
59
+ item.props.accessibilityLabel ===
60
+ AccessibilityLabel.TEXT_BOX_BUTTON_DONE &&
61
+ item.type === TouchableOpacity
62
+ );
63
+ await act(async () => {
64
+ touchableOpacity.props.onPress();
65
+ });
66
+ expect(mockOnSelectAction).toHaveBeenCalledWith({
67
+ action: 'b498234c-6c1a-452d-a1d1-87a314c20528',
68
+ data: { value: '123' },
69
+ index: undefined,
70
+ template: 'TextBoxTemplate',
71
+ });
72
+ });
73
+
74
+ it('Test onPress Cancel', async () => {
75
+ const instance = await renderOptions();
76
+ const textInput = instance.findByType(_TextInput);
77
+ await act(async () => {
78
+ await textInput.props.onChange('');
79
+ });
80
+ const touchableDone = instance.find(
81
+ (item) =>
82
+ item.props.accessibilityLabel ===
83
+ AccessibilityLabel.TEXT_BOX_BUTTON_DONE &&
84
+ item.type === TouchableOpacity
85
+ );
86
+ expect(touchableDone.props.disabled).toBeTruthy();
87
+
88
+ const touchableOpacity = instance.find(
89
+ (item) =>
90
+ item.props.accessibilityLabel ===
91
+ AccessibilityLabel.TEXT_BOX_BUTTON_CANCEL &&
92
+ item.type === TouchableOpacity
93
+ );
94
+ await act(async () => {
95
+ touchableOpacity.props.onPress();
96
+ });
97
+ expect(mockOnSelectAction).not.toHaveBeenCalled();
98
+ });
99
+ });
@@ -497,6 +497,7 @@ export default {
497
497
  CONNECTED_GATEWAY_UNIT_NAME: 'CONNECTED_GATEWAY_UNIT_NAME',
498
498
  CONNECTED_GATEWAY_CHIP_NAME: 'CONNECTED_GATEWAY_CHIP_NAME',
499
499
  BUTTON_DONE: 'BUTTON_DONE',
500
+ BUTTON_CANCEL: 'BUTTON_CANCEL',
500
501
 
501
502
  // Add New Device
502
503
  ADD_NEW_DEVICE_ADD: 'ADD_NEW_DEVICE_ADD',
@@ -561,7 +562,8 @@ export default {
561
562
  NUMBER_ACTION_DOWN: 'NUMBER_ACTION_DOWN',
562
563
  //TestBoxTemplate
563
564
  TEXT_BOX_BUTTON_EDIT: 'TEXT_BOX_BUTTON_EDIT',
564
-
565
+ TEXT_BOX_BUTTON_CANCEL: 'TEXT_BOX_BUTTON_CANCEL',
566
+ TEXT_BOX_BUTTON_DONE: 'TEXT_BOX_BUTTON_DONE',
565
567
  // OnOffButtonAction
566
568
  ON_OFF_BUTTON_ACTION_TITLE: 'ON_OFF_BUTTON_ACTION_TITLE',
567
569
 
@@ -13,6 +13,8 @@ import Routes from '../../../utils/Route';
13
13
  import NewActionWrapper from './NewActionWrapper';
14
14
  import moment from 'moment';
15
15
  import { ToastBottomHelper } from '../../../utils/Utils';
16
+ import TextBoxActionTemplate from '../../../commons/OneTapTemplate/TextBoxActionTemplate';
17
+ import SliderRangeActionTemplate from '../../../commons/OneTapTemplate/SliderRangeActionTemplate';
16
18
 
17
19
  const RenderActionItem = ({ device, item, handleOnSelectAction, index, t }) => {
18
20
  item.index = index;
@@ -58,6 +60,24 @@ const RenderActionItem = ({ device, item, handleOnSelectAction, index, t }) => {
58
60
  onSelectAction={handleOnSelectAction}
59
61
  />
60
62
  );
63
+ case 'slider_range_template':
64
+ return (
65
+ <SliderRangeActionTemplate
66
+ key={item.id}
67
+ device={device}
68
+ item={item}
69
+ onSelectAction={handleOnSelectAction}
70
+ />
71
+ );
72
+ case 'TextBoxTemplate':
73
+ return (
74
+ <TextBoxActionTemplate
75
+ key={item.id}
76
+ device={device}
77
+ item={item}
78
+ onSelectAction={handleOnSelectAction}
79
+ />
80
+ );
61
81
  default:
62
82
  ToastBottomHelper.error(
63
83
  t('template_not_supported', { template: item.template }),
@@ -1469,4 +1469,6 @@ export default {
1469
1469
  when_value_is: 'When value is',
1470
1470
  template_not_supported: '"{template}" not yet supported',
1471
1471
  invited_user: 'Invited user {user}',
1472
+ enter_value: 'Enter value',
1473
+ enter_parameters: 'Enter parameters',
1472
1474
  };
@@ -1479,4 +1479,6 @@ export default {
1479
1479
  when_value_is: 'Khi giá trị là',
1480
1480
  template_not_supported: '"{template}" chưa được hỗ trợ',
1481
1481
  invited_user: 'Đã mời người dùng {user}',
1482
+ enter_value: 'Nhập giá trị',
1483
+ enter_parameters: 'Nhập thông số',
1482
1484
  };