@eohjsc/react-native-smart-city 0.7.22 → 0.7.24

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 (61) hide show
  1. package/package.json +1 -1
  2. package/src/commons/ActionGroup/TerminalBoxTemplate.js +3 -0
  3. package/src/commons/ActionTemplate/OnOffButtonAction.js +38 -4
  4. package/src/commons/ActionTemplate/OnOffSimpleAction.js +55 -15
  5. package/src/commons/ActionTemplate/OnOffSmartLockAction.js +46 -8
  6. package/src/commons/ActionTemplate/SwitchButtonAction.js +35 -4
  7. package/src/commons/ActionTemplate/ThreeButtonAction.js +13 -3
  8. package/src/commons/ActionTemplate/__test__/OnOffButtonAction.test.js +46 -7
  9. package/src/commons/ActionTemplate/__test__/OnOffSimpleAction.test.js +66 -6
  10. package/src/commons/ActionTemplate/__test__/OnOffSmartLockAction.test.js +53 -13
  11. package/src/commons/ActionTemplate/__test__/SwitchButtonAction.test.js +46 -7
  12. package/src/commons/ActionTemplate/__test__/index.test.js +6 -2
  13. package/src/commons/ActionTemplate/index.js +65 -10
  14. package/src/commons/MediaPlayerDetail/MediaPlayerFull.js +26 -32
  15. package/src/commons/OneTapTemplate/StatesGridActionTemplate.js +8 -6
  16. package/src/commons/SubUnit/OneTap/__test__/SubUnitAutomate.test.js +6 -0
  17. package/src/commons/SubUnit/OneTap/index.js +5 -0
  18. package/src/commons/UnitSummary/ConfigHistoryChart/index.js +16 -12
  19. package/src/commons/Widgets/IFrameWithConfig/IFrameWithConfig.js +3 -1
  20. package/src/commons/Widgets/IFrameWithConfig/__tests__/IFrameWithConfig.test.js +1 -1
  21. package/src/configs/API.js +6 -0
  22. package/src/configs/AccessibilityLabel.js +2 -0
  23. package/src/screens/ActivityLog/__test__/index.test.js +10 -0
  24. package/src/screens/ActivityLog/hooks/index.js +1 -1
  25. package/src/screens/Automate/AddNewAction/ChooseAction.js +15 -51
  26. package/src/screens/Automate/AddNewAction/SelectControlDevices.js +13 -3
  27. package/src/screens/Automate/AddNewAction/SetupConfigCondition.js +74 -54
  28. package/src/screens/Automate/AddNewAction/__test__/ChooseAction.test.js +114 -4
  29. package/src/screens/Automate/AddNewAction/__test__/SetupConfigCondition.test.js +37 -8
  30. package/src/screens/Automate/AddNewAutoSmart/AddTypeSmart.js +5 -0
  31. package/src/screens/Automate/AddNewAutoSmart/__test__/AddNewAutoSmart.test.js +18 -2
  32. package/src/screens/Automate/Components/InputName.js +7 -6
  33. package/src/screens/Automate/Constants.js +12 -0
  34. package/src/screens/Automate/EditActionsList/UpdateActionScript.js +24 -55
  35. package/src/screens/Automate/EditActionsList/__tests__/UpdateActionScript.test.js +298 -41
  36. package/src/screens/Automate/EditActionsList/__tests__/index.test.js +2 -2
  37. package/src/screens/Automate/EditActionsList/index.js +26 -14
  38. package/src/screens/Automate/MultiUnits.js +9 -1
  39. package/src/screens/Automate/OneTap/__test__/AddNewOneTap.test.js +3 -3
  40. package/src/screens/Automate/ScriptDetail/Components/AddActionScript.js +4 -10
  41. package/src/screens/Automate/ScriptDetail/Components/DeleteScript.js +2 -4
  42. package/src/screens/Automate/ScriptDetail/__test__/index.test.js +78 -0
  43. package/src/screens/Automate/ScriptDetail/index.js +16 -10
  44. package/src/screens/Automate/ScriptDetail/utils.js +39 -15
  45. package/src/screens/Automate/SetSchedule/AddEditConditionSchedule.js +27 -160
  46. package/src/screens/Automate/SetSchedule/EditSchedule.js +269 -0
  47. package/src/screens/Automate/SetSchedule/__test__/AddEditConditionSchedule.test.js +327 -22
  48. package/src/screens/Automate/SetSchedule/__test__/index.test.js +35 -22
  49. package/src/screens/Automate/SetSchedule/components/RepeatOptionsPopup.js +2 -8
  50. package/src/screens/Automate/SetSchedule/index.js +15 -129
  51. package/src/screens/Automate/SetSchedule/styles/indexStyles.js +9 -0
  52. package/src/screens/Automate/__test__/MultiUnits.test.js +6 -1
  53. package/src/screens/Automate/hooks/useAction.js +222 -0
  54. package/src/screens/Device/__test__/detail.test.js +48 -1
  55. package/src/screens/Device/detail.js +46 -3
  56. package/src/screens/PlayBackCamera/__test__/index.test.js +48 -13
  57. package/src/screens/PlayBackCamera/index.js +1 -1
  58. package/src/utils/Apis/axios.js +6 -0
  59. package/src/utils/I18n/translations/en.js +8 -0
  60. package/src/utils/I18n/translations/vi.js +12 -4
  61. package/src/screens/Automate/constants.js +0 -0
@@ -2,13 +2,21 @@ import React from 'react';
2
2
  import renderer, { act } from 'react-test-renderer';
3
3
  import { TouchableOpacity } from 'react-native';
4
4
 
5
+ import Text from '../../Text';
6
+ import AccessibilityLabel from '../../../configs/AccessibilityLabel';
5
7
  import OnOffSmartLockAction from '../OnOffSmartLockAction';
6
8
  import { SCProvider } from '../../../context';
7
9
  import { mockSCStore } from '../../../context/mockStore';
8
10
 
9
- const wrapComponent = (configuration, onPress) => (
11
+ const wrapComponent = (configuration, onPress, onPressToggle) => (
10
12
  <SCProvider initState={mockSCStore({})}>
11
- <OnOffSmartLockAction configuration={configuration} onPress={onPress} />
13
+ <OnOffSmartLockAction
14
+ configuration={configuration}
15
+ onPress={onPress}
16
+ onPressToggle={onPressToggle}
17
+ title={'Lock'}
18
+ template={'OnOffSmartLockActionTemplate'}
19
+ />
12
20
  </SCProvider>
13
21
  );
14
22
 
@@ -17,38 +25,70 @@ describe('Test OnOffSmartLockAction', () => {
17
25
 
18
26
  it('test onPress smart lock action', async () => {
19
27
  const configuration = {
20
- action_on: 'a',
21
- action_off: 'b',
22
- text_on: 'on',
23
- text_off: 'off',
28
+ action_off: 'f49e1577-493d-4bae-a9ab-3b0f96a4ec52',
29
+ action_on: '94600cbe-2035-47d5-bd43-89ace5d59796',
30
+ text_on: 'Open',
31
+ text_off: 'Close',
24
32
  };
25
33
  const mockFuntion = jest.fn();
34
+ const mockToggle = jest.fn();
26
35
  await act(async () => {
27
- tree = await renderer.create(wrapComponent(configuration, mockFuntion));
36
+ tree = await renderer.create(
37
+ wrapComponent(configuration, mockFuntion, mockToggle)
38
+ );
28
39
  });
29
40
  const instance = tree.root;
30
41
  const touchOpacity = instance.findAllByType(TouchableOpacity);
31
42
 
32
- expect(touchOpacity).toHaveLength(2);
43
+ expect(touchOpacity).toHaveLength(3);
33
44
  await act(async () => {
34
45
  touchOpacity[0].props.onPress();
35
46
  });
47
+ expect(mockFuntion).toHaveBeenCalledWith({
48
+ ...configuration,
49
+ name: configuration.text_on,
50
+ action: configuration.action_on,
51
+ action_off: null,
52
+ template: 'OnOffSmartLockActionTemplate',
53
+ is_toggle: false,
54
+ });
55
+ expect(mockToggle).not.toHaveBeenCalled();
56
+
57
+ mockFuntion.mockClear();
58
+ await act(async () => {
59
+ touchOpacity[1].props.onPress();
60
+ });
36
61
  expect(mockFuntion).toHaveBeenCalledWith({
37
62
  ...configuration,
38
63
  name: configuration.text_off,
39
64
  action: configuration.action_off,
40
65
  action_on: null,
66
+ template: 'OnOffSmartLockActionTemplate',
67
+ is_toggle: false,
41
68
  });
69
+ expect(mockToggle).not.toHaveBeenCalled();
42
70
 
43
71
  mockFuntion.mockClear();
44
72
  await act(async () => {
45
- touchOpacity[1].props.onPress();
73
+ touchOpacity[2].props.onPress();
46
74
  });
47
- expect(mockFuntion).toHaveBeenCalledWith({
75
+ expect(mockFuntion).not.toHaveBeenCalled();
76
+ expect(mockToggle).toHaveBeenCalledWith({
48
77
  ...configuration,
49
- name: configuration.text_on,
50
- action: configuration.action_on,
51
- action_off: null,
78
+ action_on_data: null,
79
+ action_off_data: null,
80
+ template: 'OnOffSmartLockActionTemplate',
81
+ is_toggle: true,
52
82
  });
83
+
84
+ const textTitle = instance.findAll(
85
+ (el) =>
86
+ el.props.accessibilityLabel ===
87
+ AccessibilityLabel.ON_OFF_BUTTON_ACTION_TITLE && el.type === Text
88
+ );
89
+ expect(textTitle).toHaveLength(3);
90
+ expect(textTitle[0].props.children).toEqual('Lock - Open');
91
+ expect(textTitle[1].props.children).toEqual('Lock - Close');
92
+ expect(textTitle[2].props.children).toEqual('Lock - Toggle');
53
93
  });
54
94
  });
@@ -8,11 +8,12 @@ import Text from '../../Text';
8
8
  import AccessibilityLabel from '../../../configs/AccessibilityLabel';
9
9
  import SwitchButtonAction from '../SwitchButtonAction';
10
10
 
11
- const wrapComponent = (configuration, onPress) => (
11
+ const wrapComponent = (configuration, onPress, onPressToggle) => (
12
12
  <SCProvider initState={mockSCStore({})}>
13
13
  <SwitchButtonAction
14
14
  configuration={configuration}
15
15
  onPress={onPress}
16
+ onPressToggle={onPressToggle}
16
17
  title={'Cong tac 1'}
17
18
  template={'switch_button_action_template'}
18
19
  />
@@ -30,26 +31,64 @@ describe('Test SwitchButtonAction', () => {
30
31
  action_on: '94600cbe-2035-47d5-bd43-89ace5d59796',
31
32
  };
32
33
  const mockFuntion = jest.fn();
34
+ const mockToggle = jest.fn();
33
35
  await act(async () => {
34
- tree = await renderer.create(wrapComponent(configuration, mockFuntion));
36
+ tree = await renderer.create(
37
+ wrapComponent(configuration, mockFuntion, mockToggle)
38
+ );
35
39
  });
36
40
  const instance = tree.root;
37
41
  const touchOpacity = instance.findAllByType(TouchableOpacity);
38
42
 
39
- expect(touchOpacity).toHaveLength(2);
43
+ expect(touchOpacity).toHaveLength(3);
40
44
  await act(async () => {
41
45
  touchOpacity[0].props.onPress();
46
+ });
47
+ expect(mockFuntion).toHaveBeenCalledWith({
48
+ ...configuration,
49
+ name: configuration.text_on,
50
+ action: configuration.action_on,
51
+ action_off: null,
52
+ template: 'switch_button_action_template',
53
+ is_toggle: false,
54
+ });
55
+ expect(mockToggle).not.toHaveBeenCalled();
56
+
57
+ mockFuntion.mockClear();
58
+ await act(async () => {
42
59
  touchOpacity[1].props.onPress();
43
60
  });
44
- expect(mockFuntion).toHaveBeenCalled();
61
+ expect(mockFuntion).toHaveBeenCalledWith({
62
+ ...configuration,
63
+ name: configuration.text_off,
64
+ action: configuration.action_off,
65
+ action_on: null,
66
+ template: 'switch_button_action_template',
67
+ is_toggle: false,
68
+ });
69
+ expect(mockToggle).not.toHaveBeenCalled();
70
+
71
+ mockFuntion.mockClear();
72
+ await act(async () => {
73
+ touchOpacity[2].props.onPress();
74
+ });
75
+ expect(mockFuntion).not.toHaveBeenCalled();
76
+ expect(mockToggle).toHaveBeenCalledWith({
77
+ ...configuration,
78
+ action_on_data: null,
79
+ action_off_data: null,
80
+ template: 'switch_button_action_template',
81
+ is_toggle: true,
82
+ });
45
83
 
46
84
  const textTitle = instance.findAll(
47
85
  (el) =>
48
86
  el.props.accessibilityLabel ===
49
87
  AccessibilityLabel.ON_OFF_BUTTON_ACTION_TITLE && el.type === Text
50
88
  );
51
- expect(textTitle).toHaveLength(2);
52
- expect(textTitle[0].props.children).toEqual(['Cong tac 1', ' ', 'On']);
53
- expect(textTitle[1].props.children).toEqual(['Cong tac 1', ' ', 'Off']);
89
+ expect(textTitle).toHaveLength(3);
90
+ expect(textTitle[0].props.children).toEqual('Cong tac 1 - On');
91
+ expect(textTitle[1].props.children).toEqual('Cong tac 1 - Off');
92
+ expect(textTitle[2].props.children).toEqual('Cong tac 1 - Toggle');
54
93
  });
55
94
  });
@@ -39,7 +39,7 @@ describe('Test ActionTemplate', () => {
39
39
  },
40
40
  };
41
41
  let switchTemplate = {
42
- title: '',
42
+ title: 'LED',
43
43
  template: 'switch_button_action_template',
44
44
  configuration: {
45
45
  text_on: 'On',
@@ -88,6 +88,7 @@ describe('Test ActionTemplate', () => {
88
88
  template: 'three_button_action_template',
89
89
  });
90
90
  });
91
+
91
92
  it('test render SwitchButtonAction', async () => {
92
93
  await act(async () => {
93
94
  tree = await renderer.create(wrapComponent(switchTemplate));
@@ -99,6 +100,9 @@ describe('Test ActionTemplate', () => {
99
100
  el.props.accessibilityLabel ===
100
101
  AccessibilityLabel.ON_OFF_BUTTON_ACTION_TITLE && el.type === Text
101
102
  );
102
- expect(textTitle).toHaveLength(2);
103
+ expect(textTitle).toHaveLength(3);
104
+ expect(textTitle[0].props.children).toEqual('LED - On');
105
+ expect(textTitle[1].props.children).toEqual('LED - Off');
106
+ expect(textTitle[2].props.children).toEqual('LED - Toggle');
103
107
  });
104
108
  });
@@ -20,19 +20,27 @@ const ActionTemplate = memo(({ device, item, onSelectAction }) => {
20
20
  const onClose = () => setVisible(false);
21
21
  const [actionName, setActionName] = useState();
22
22
 
23
- const onPressSelectAction = useCallback(
24
- (action) => {
23
+ const getActionData = useCallback(
24
+ (action, value) => {
25
25
  let actionData = null;
26
26
  if (device?.device_type === DEVICE_TYPE.ZIGBEE) {
27
- const state = action?.action_on ? 1 : 0;
27
+ const state = value;
28
28
  actionData = { state: state };
29
29
  if (action?.allow_config_store_value && action?.config) {
30
30
  actionData.config_id = action.config;
31
31
  actionData.config_value = state;
32
32
  }
33
33
  } else if (device?.device_type === DEVICE_TYPE.LG_THINQ) {
34
- actionData = { value: action?.action_on ? 1 : 0 };
34
+ actionData = { value };
35
35
  }
36
+ return actionData;
37
+ },
38
+ [device?.device_type]
39
+ );
40
+
41
+ const onPressSelectAction = useCallback(
42
+ (action) => {
43
+ const actionData = getActionData(action, action?.action_on ? 1 : 0);
36
44
  setVisible(false);
37
45
  setActionName(action?.name);
38
46
  onSelectAction &&
@@ -42,31 +50,78 @@ const ActionTemplate = memo(({ device, item, onSelectAction }) => {
42
50
  action: action?.action,
43
51
  data: actionData,
44
52
  template: action?.template,
53
+ is_toggle: action?.is_toggle,
54
+ });
55
+ },
56
+ [item?.index, onSelectAction, getActionData]
57
+ );
58
+
59
+ const onPressSelectToggle = useCallback(
60
+ (toggle) => {
61
+ const actionOnData = getActionData(toggle, 1);
62
+ const actionOffData = getActionData(toggle, 0);
63
+ setVisible(false);
64
+ setActionName(t('toggle'));
65
+ onSelectAction &&
66
+ onSelectAction({
67
+ index: item?.index,
68
+ action_on: toggle?.action_on,
69
+ action_on_data: actionOnData,
70
+ action_off: toggle?.action_off,
71
+ action_off_data: actionOffData,
72
+ config: toggle?.config,
73
+ is_on_values: toggle?.is_on_value,
74
+ template: toggle?.template,
75
+ is_toggle: toggle?.is_toggle,
45
76
  });
46
77
  },
47
- [device?.device_type, item?.index, onSelectAction]
78
+ [item?.index, onSelectAction, getActionData, t]
48
79
  );
49
80
 
50
81
  const renderAction = useMemo(() => {
51
82
  switch (item.template) {
52
83
  case 'on_off_button_action_template':
53
- return <OnOffButtonAction {...item} onPress={onPressSelectAction} />;
84
+ return (
85
+ <OnOffButtonAction
86
+ {...item}
87
+ onPress={onPressSelectAction}
88
+ onPressToggle={onPressSelectToggle}
89
+ />
90
+ );
54
91
  case 'one_button_action_template':
55
92
  return <OneButtonAction {...item} onPress={onPressSelectAction} />;
56
93
  case 'three_button_action_template':
57
94
  return <ThreeButtonAction {...item} onPress={onPressSelectAction} />;
58
95
  case 'OnOffSimpleActionTemplate':
59
- return <OnOffSimpleAction {...item} onPress={onPressSelectAction} />;
96
+ return (
97
+ <OnOffSimpleAction
98
+ {...item}
99
+ onPress={onPressSelectAction}
100
+ onPressToggle={onPressSelectToggle}
101
+ />
102
+ );
60
103
  case 'curtain_action_template':
61
104
  return <CurtainAction {...item} onPress={onPressSelectAction} />;
62
105
  case 'OnOffSmartLockActionTemplate':
63
- return <OnOffSmartLockAction {...item} onPress={onPressSelectAction} />;
106
+ return (
107
+ <OnOffSmartLockAction
108
+ {...item}
109
+ onPress={onPressSelectAction}
110
+ onPressToggle={onPressSelectToggle}
111
+ />
112
+ );
64
113
  case 'switch_button_action_template':
65
- return <SwitchButtonAction {...item} onPress={onPressSelectAction} />;
114
+ return (
115
+ <SwitchButtonAction
116
+ {...item}
117
+ onPress={onPressSelectAction}
118
+ onPressToggle={onPressSelectToggle}
119
+ />
120
+ );
66
121
  default:
67
122
  return null;
68
123
  }
69
- }, [item, onPressSelectAction]);
124
+ }, [item, onPressSelectAction, onPressSelectToggle]);
70
125
 
71
126
  return (
72
127
  <>
@@ -45,37 +45,6 @@ const MediaPlayerFull = ({
45
45
  setIsFullScreen(!isFullScreen);
46
46
  }, [isFullScreen]);
47
47
 
48
- const renderCamera = useMemo(() => {
49
- return (
50
- <VLCPlayer
51
- autoAspectRatio={true}
52
- videoAspectRatio={
53
- isFullScreen
54
- ? `${Constants.height}:${Constants.width}`
55
- : `${Constants.width}:224`
56
- }
57
- source={{
58
- initType: 2,
59
- hwDecoderEnabled: 1,
60
- hwDecoderForced: 1,
61
- uri,
62
- initOptions: [
63
- '--no-audio',
64
- '--rtsp-tcp',
65
- '--network-caching=150',
66
- '--rtsp-caching=150',
67
- '--no-stats',
68
- '--tcp-caching=150',
69
- '--realrtsp-caching=150',
70
- ],
71
- }}
72
- style={styles.video}
73
- resizeMode={'cover'}
74
- isLive={true}
75
- />
76
- );
77
- }, [isFullScreen, uri]);
78
-
79
48
  useEffect(() => {
80
49
  setPaused(isPaused);
81
50
  }, [isPaused]);
@@ -137,7 +106,32 @@ const MediaPlayerFull = ({
137
106
  />
138
107
  </View>
139
108
  ) : (
140
- renderCamera
109
+ <VLCPlayer
110
+ autoAspectRatio={true}
111
+ videoAspectRatio={
112
+ isFullScreen
113
+ ? `${Constants.height}:${Constants.width}`
114
+ : `${Constants.width}:224`
115
+ }
116
+ source={{
117
+ initType: 2,
118
+ hwDecoderEnabled: 1,
119
+ hwDecoderForced: 1,
120
+ uri,
121
+ initOptions: [
122
+ '--no-audio',
123
+ '--rtsp-tcp',
124
+ '--network-caching=150',
125
+ '--rtsp-caching=150',
126
+ '--no-stats',
127
+ '--tcp-caching=150',
128
+ '--realrtsp-caching=150',
129
+ ],
130
+ }}
131
+ style={styles.video}
132
+ resizeMode={'cover'}
133
+ isLive={true}
134
+ />
141
135
  )}
142
136
  <View style={styles.buttonView}>
143
137
  <View style={styles.buttonPause}>
@@ -14,24 +14,25 @@ const ActionItem = ({
14
14
  setVisible,
15
15
  template,
16
16
  item,
17
+ option,
17
18
  }) => {
18
19
  const handleSelectAction = useCallback(() => {
19
20
  let actionData = null;
20
- const { allow_config_store_value, config, is_on_value } = item;
21
+ const { allow_config_store_value, config, is_on_value } = option;
21
22
  if (allow_config_store_value && config) {
22
23
  actionData = { config_id: config, config_value: is_on_value };
23
24
  }
24
- setActionName(item.text);
25
+ setActionName(option.text);
25
26
 
26
27
  onSelectAction &&
27
28
  onSelectAction({
28
29
  index: item.index,
29
- action: item.action,
30
+ action: option.action,
30
31
  data: actionData,
31
32
  template,
32
33
  });
33
34
  setVisible(false);
34
- }, [item, setActionName, onSelectAction, template, setVisible]);
35
+ }, [item, option, setActionName, onSelectAction, template, setVisible]);
35
36
 
36
37
  return (
37
38
  <TouchableOpacity
@@ -39,7 +40,7 @@ const ActionItem = ({
39
40
  accessibilityLabel={AccessibilityLabel.STATES_GRID_ACTION_GRID_ITEM}
40
41
  >
41
42
  <Text type="H4" style={styles.textWithLine}>
42
- {item.text}
43
+ {option.text}
43
44
  </Text>
44
45
  </TouchableOpacity>
45
46
  );
@@ -71,7 +72,8 @@ const StatesGridActionTemplate = ({ device, item, onSelectAction }) => {
71
72
  <View style={styles.modalContent}>
72
73
  {options.map((option, index) => (
73
74
  <ActionItem
74
- item={option}
75
+ item={item}
76
+ option={option}
75
77
  key={index}
76
78
  setActionName={setActionName}
77
79
  onSelectAction={onSelectAction}
@@ -91,9 +91,15 @@ describe('test Item', () => {
91
91
  expect(global.mockedNavigate).toHaveBeenCalledWith(Routes.ScenarioName, {
92
92
  automate: {
93
93
  type: 'one_tap',
94
+ conditions: [
95
+ {
96
+ type: 'one_tap',
97
+ },
98
+ ],
94
99
  unit: undefined,
95
100
  },
96
101
  closeScreen: undefined,
102
+ unitId: undefined,
97
103
  });
98
104
  mockedNavigate.mockClear();
99
105
 
@@ -55,6 +55,11 @@ const SubUnitAutomate = ({ isOwner, listAutomate, unit, wrapItemStyle }) => {
55
55
  navigate(Routes.ScenarioName, {
56
56
  automate: {
57
57
  type: AUTOMATE_TYPE.ONE_TAP,
58
+ conditions: [
59
+ {
60
+ type: AUTOMATE_TYPE.ONE_TAP,
61
+ },
62
+ ],
58
63
  unit: unit?.id,
59
64
  },
60
65
  unitId: unit?.id,
@@ -23,7 +23,13 @@ export const useFetchConfigHistory = (
23
23
  ) => {
24
24
  const fetchDataDisplayHistory = useCallback(
25
25
  async (startDate, endDate, setProcessing = () => {}) => {
26
- if (!configs.length || !startDate || !endDate) {
26
+ if (
27
+ !configs ||
28
+ !Array.isArray(configs) ||
29
+ !configs.length ||
30
+ !startDate ||
31
+ !endDate
32
+ ) {
27
33
  return;
28
34
  }
29
35
 
@@ -86,13 +92,11 @@ export const updateConfigChart = async (
86
92
  ];
87
93
  })
88
94
  );
89
-
90
- setChartData(
91
- configuration.map((config) => {
92
- config.data = data_by_id[config.id];
93
- return config;
94
- })
95
- );
95
+ const chartData = configuration.map((config) => {
96
+ config.data = data_by_id[config.id];
97
+ return config;
98
+ });
99
+ setChartData(chartData);
96
100
 
97
101
  data.configs.map((config) => {
98
102
  if (config.middle.not_ready.length > 0) {
@@ -113,10 +117,10 @@ export const updateConfigChart = async (
113
117
  middleDataByDay.sort((a, b) => (a.date > b.date ? 1 : -1)); // small to large
114
118
  const middleData = middleDataByDay.map((x) => x.data).flat();
115
119
  data_by_id[config.id] = [...config.head, ...middleData, ...config.tail];
116
- setChartData((chartData) => {
117
- const index = chartData.map((c) => c.id).indexOf(config.id);
118
- chartData[index].data = data_by_id[config.id];
119
- return [...chartData];
120
+ setChartData((prev) => {
121
+ const index = prev.map((c) => c.id).indexOf(config.id);
122
+ prev[index].data = data_by_id[config.id];
123
+ return [...prev];
120
124
  });
121
125
  });
122
126
  }
@@ -1,6 +1,7 @@
1
1
  import moment from 'moment';
2
2
  import React, { memo, useCallback, useEffect, useRef, useState } from 'react';
3
3
 
4
+ import API from '../../../configs/API';
4
5
  import { styles as useIframeStyle } from '../IFrame/IFrameStyles';
5
6
  import { styles } from './IFrameWithConfigStyles';
6
7
  import IconComponent from '../../IconComponent';
@@ -24,7 +25,8 @@ const IFrameWithConfig = memo(
24
25
  const [chartData, setChartData] = useState(configuration?.history_configs);
25
26
  const fetchDataDisplayHistory = useFetchConfigHistory(
26
27
  configuration?.history_configs,
27
- setChartData
28
+ setChartData,
29
+ API.CONFIG.DISPLAY_HISTORY_V5()
28
30
  );
29
31
 
30
32
  const postMessage = useCallback((message) => {
@@ -252,7 +252,7 @@ describe('Test IFrame With Config', () => {
252
252
  });
253
253
 
254
254
  const mockAxios = new MockAdapter(api.axiosInstance);
255
- mockAxios.onGet(API.CONFIG.DISPLAY_HISTORY_V3()).reply(200, {
255
+ mockAxios.onGet(API.CONFIG.DISPLAY_HISTORY_V5()).reply(200, {
256
256
  configs: [
257
257
  {
258
258
  id: 1,
@@ -90,6 +90,7 @@ const API = {
90
90
  CONFIG: {
91
91
  DISPLAY_HISTORY_V3: () => '/chip_manager/configs/value_history_v3/',
92
92
  DISPLAY_HISTORY_V4: () => '/chip_manager/configs/value_history_v4/',
93
+ DISPLAY_HISTORY_V5: () => '/chip_manager/configs/value_history_v5/',
93
94
  },
94
95
  AUTOMATE: {
95
96
  ACTION_ONE_TAP: (id) => `/property_manager/automate/${id}/action_one_tap/`,
@@ -109,12 +110,16 @@ const API = {
109
110
  `/property_manager/automate/${automateId}/update_script_notify/`,
110
111
  UPDATE_SCRIPT_ACTION: (automateId) =>
111
112
  `/property_manager/automate/${automateId}/update_script_action/`,
113
+ UPDATE_SCRIPT_TOGGLE: (automateId) =>
114
+ `/property_manager/automate/${automateId}/update_script_toggle/`,
112
115
  UPDATE_SCRIPT_EMAIL: (automateId) =>
113
116
  `/property_manager/automate/${automateId}/update_script_email/`,
114
117
  UPDATE_SCRIPT_SMS: (automateId) =>
115
118
  `/property_manager/automate/${automateId}/update_script_sms/`,
116
119
  ADD_SCRIPT_ACTION: (id) =>
117
120
  `/property_manager/automate/${id}/add_script_action/`,
121
+ ADD_SCRIPT_TOGGLE: (id) =>
122
+ `/property_manager/automate/${id}/add_script_toggle/`,
118
123
  ADD_SCRIPT_NOTIFY: (id) =>
119
124
  `/property_manager/automate/${id}/add_script_notify/`,
120
125
  ADD_SCRIPT_DELAY: (id) =>
@@ -125,6 +130,7 @@ const API = {
125
130
  FETCH_AUTOMATE: (automateId) =>
126
131
  `/property_manager/automate_v2/${automateId}/`,
127
132
  CREATE_AUTOMATE: () => '/property_manager/automate/',
133
+ CREATE_AUTOMATE_V2: () => '/property_manager/automate_v2/',
128
134
  UPDATE_AUTOMATE: (automateId) =>
129
135
  `/property_manager/automate/${automateId}/`,
130
136
  ENABLE_SCRIPT: (automateId) =>
@@ -306,6 +306,7 @@ export default {
306
306
  ONE_BUTTON: 'ONE_BUTTON',
307
307
  ON_BUTTON: 'ON_BUTTON',
308
308
  OFF_BUTTON: 'OFF_BUTTON',
309
+ TOGGLE_BUTTON: 'TOGGLE_BUTTON',
309
310
 
310
311
  // Device Detail
311
312
  DEVICE_DETAIL_MEDIA_PLAYER: 'DEVICE_DETAIL_MEDIA_PLAYER',
@@ -610,6 +611,7 @@ export default {
610
611
  // OnOffSimpleAction
611
612
  ON_OFF_SIMPLE_ACTION_ON: 'ON_OFF_SIMPLE_ACTION_ON',
612
613
  ON_OFF_SIMPLE_ACTION_OFF: 'ON_OFF_SIMPLE_ACTION_OFF',
614
+ ON_OFF_SIMPLE_ACTION_TOGGLE: 'ON_OFF_SIMPLE_ACTION_TOGGLE',
613
615
 
614
616
  // Add New Device LG
615
617
  ADD_NEW_DEVICE_LG_ADD: 'ADD_NEW_DEVICE_LG_ADD',
@@ -198,4 +198,14 @@ describe('Test Activity log', () => {
198
198
  const items = instance.findAllByType(ItemLog);
199
199
  expect(items).toHaveLength(0);
200
200
  });
201
+
202
+ it('render type null', async () => {
203
+ route.params.type = undefined;
204
+ await act(async () => {
205
+ tree = await create(wrapComponent(route));
206
+ });
207
+ const instance = tree.root;
208
+ const items = instance.findAllByType(ItemLog);
209
+ expect(items).toHaveLength(0);
210
+ });
201
211
  });
@@ -120,7 +120,7 @@ export default ({ id, type, share, filterEnabled }) => {
120
120
 
121
121
  const fetchMembers = async () => {
122
122
  const api = apiMaps[type];
123
- if (!filterEnabled?.user) {
123
+ if (!api?.memberUrl || !filterEnabled?.user) {
124
124
  return;
125
125
  }
126
126
  const { success, data } = await axiosGet(api.memberUrl(share?.id));