@eohjsc/react-native-smart-city 0.3.21 → 0.3.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 (104) hide show
  1. package/index.js +2 -0
  2. package/package.json +2 -1
  3. package/src/Images/Common/buttonLeftCurtain.png +0 -0
  4. package/src/Images/Common/buttonLeftCurtain@2x.png +0 -0
  5. package/src/Images/Common/buttonLeftCurtain@3x.png +0 -0
  6. package/src/commons/Action/ItemQuickAction.js +1 -12
  7. package/src/commons/Action/__test__/ItemQuickAction.test.js +1 -1
  8. package/src/commons/ActionGroup/ColorPickerTemplate.js +2 -9
  9. package/src/commons/ActionGroup/CurtainButtonTemplate.js +14 -21
  10. package/src/commons/ActionGroup/CurtainButtonTemplateStyle.js +5 -0
  11. package/src/commons/ActionGroup/NumberUpDownActionTemplate.js +12 -24
  12. package/src/commons/ActionGroup/OnOffSmartLock/OnOffSmartLock.js +10 -17
  13. package/src/commons/ActionGroup/OnOffTemplate/index.js +10 -35
  14. package/src/commons/ActionGroup/OneBigButtonTemplate.js +2 -3
  15. package/src/commons/ActionGroup/OptionsDropdownActionTemplate.js +7 -8
  16. package/src/commons/ActionGroup/SliderRangeTemplate.js +3 -10
  17. package/src/commons/ActionGroup/StatesGridActionTemplate.js +9 -24
  18. package/src/commons/ActionGroup/ThreeButtonTemplate.js +6 -9
  19. package/src/commons/ActionGroup/TimerActionTemplate.js +11 -4
  20. package/src/commons/ActionGroup/TwoButtonTemplate/index.js +18 -33
  21. package/src/commons/ActionGroup/__test__/CurtainButtonTemplate.test.js +3 -15
  22. package/src/commons/ActionGroup/__test__/NumberUpDownTemplate.test.js +38 -4
  23. package/src/commons/ActionGroup/__test__/OnOffButtonTemplate.test.js +7 -0
  24. package/src/commons/ActionGroup/__test__/OnOffSmartLock.test.js +17 -12
  25. package/src/commons/ActionGroup/__test__/OnOffTemplate.test.js +11 -16
  26. package/src/commons/ActionGroup/__test__/OneBigButtonTemplate.test.js +1 -1
  27. package/src/commons/ActionGroup/__test__/OptionsDropdownTemplate.test.js +11 -10
  28. package/src/commons/ActionGroup/__test__/StatesGridActionTemplate.test.js +8 -7
  29. package/src/commons/ActionGroup/__test__/TimerActionTemplate.test.js +8 -1
  30. package/src/commons/ActionGroup/__test__/TimerActionTemplateWithutConfigValue.test.js +7 -0
  31. package/src/commons/ActionGroup/__test__/TwoButtonTemplate.test.js +17 -2
  32. package/src/commons/ActionGroup/__test__/index.test.js +15 -18
  33. package/src/commons/ConnectingProcess/index.js +6 -25
  34. package/src/commons/Device/HistoryChart.js +8 -6
  35. package/src/commons/Device/ItemDevice.js +79 -35
  36. package/src/commons/MediaPlayerDetail/index.js +5 -0
  37. package/src/commons/RowItem/index.js +6 -2
  38. package/src/commons/SubUnit/Favorites/index.js +24 -6
  39. package/src/commons/SubUnit/ShortDetail.js +31 -5
  40. package/src/commons/SubUnit/__test__/Favorites.test.js +1 -0
  41. package/src/commons/SubUnit/__test__/ShortDetail.test.js +1 -0
  42. package/src/configs/API.js +9 -4
  43. package/src/configs/Constants.js +8 -2
  44. package/src/configs/SCConfig.js +4 -0
  45. package/src/context/actionType.ts +7 -5
  46. package/src/context/mockStore.ts +10 -3
  47. package/src/context/reducer.ts +29 -15
  48. package/src/hoc/index.js +3 -0
  49. package/src/hoc/withRemoteControl.js +10 -0
  50. package/src/hooks/Common/index.js +2 -2
  51. package/src/hooks/Common/useDevicesStatus.js +57 -0
  52. package/src/hooks/Common/useGGHomeDeviceConnected.js +3 -3
  53. package/src/hooks/IoT/__test__/useGGHomeConnection.test.js +1 -2
  54. package/src/hooks/IoT/__test__/useRemoteControl.test.js +9 -11
  55. package/src/hooks/IoT/index.js +9 -1
  56. package/src/hooks/IoT/useGGHomeConnection.js +0 -1
  57. package/src/hooks/IoT/useRemoteControl.js +2 -3
  58. package/src/hooks/IoT/useUnwatchLGDeviceConfigControl.js +29 -0
  59. package/src/hooks/IoT/useValueEvaluation.js +17 -4
  60. package/src/hooks/IoT/useWatchConfigs.js +34 -0
  61. package/src/iot/Monitor.js +13 -20
  62. package/src/iot/RemoteControl/GoogleHome.js +12 -13
  63. package/src/iot/RemoteControl/Internet.js +1 -8
  64. package/src/iot/RemoteControl/LG.js +1 -0
  65. package/src/iot/RemoteControl/__test__/GoogleHome.test.js +7 -2
  66. package/src/navigations/UnitStack.js +27 -3
  67. package/src/screens/AddNewAction/SelectAction.js +1 -1
  68. package/src/screens/AddNewAction/SetupSensor.js +4 -0
  69. package/src/screens/AddNewGateway/PlugAndPlay/ConnectWifiWarning.js +44 -78
  70. package/src/screens/AddNewGateway/PlugAndPlay/GatewayWifiList.js +15 -35
  71. package/src/screens/AddNewGateway/PlugAndPlay/__test__/GatewayWifiList.test.js +2 -0
  72. package/src/screens/AllCamera/__test__/index.test.js +1 -1
  73. package/src/screens/Device/__test__/detail.test.js +1 -54
  74. package/src/screens/Device/components/SensorConnectStatusViewHeader.js +18 -8
  75. package/src/screens/Device/components/SensorDisplayItem.js +2 -2
  76. package/src/screens/Device/detail.js +36 -30
  77. package/src/screens/Device/hooks/__test__/useEvaluateValue.test.js +102 -0
  78. package/src/screens/Device/hooks/useDeviceWatchConfigControl.js +20 -0
  79. package/src/screens/Device/utils/index.js +45 -0
  80. package/src/screens/Device/utils/index.test.js +111 -0
  81. package/src/screens/EmergencyContacts/EmergencyContactsAddNew.js +35 -22
  82. package/src/screens/EmergencyContacts/EmergencyContactsSelectContacts.js +2 -1
  83. package/src/screens/EmergencyContacts/__test__/EmergencyContactAddNew.test.js +36 -2
  84. package/src/screens/MoveToAnotherSubUnit/__test__/index.test.js +0 -2
  85. package/src/screens/Notification/__test__/NotificationItem.test.js +84 -19
  86. package/src/screens/Notification/components/NotificationItem.js +64 -31
  87. package/src/screens/PlayBackCamera/index.js +22 -6
  88. package/src/screens/ScriptDetail/hooks/useStarredScript.js +2 -2
  89. package/src/screens/SubUnit/AddSubUnit.js +2 -1
  90. package/src/screens/Unit/AddMenu.js +4 -0
  91. package/src/screens/Unit/{SelectFavoritesDevices.js → SelectAddToFavorites.js} +81 -26
  92. package/src/screens/Unit/{SelectFavoritesDevicesStyles.js → SelectAddToFavoritesStyles.js} +0 -0
  93. package/src/screens/Unit/__test__/CheckSendEmail.test.js +12 -0
  94. package/src/screens/Unit/__test__/Detail.test.js +2 -3
  95. package/src/screens/Unit/__test__/SelectAddToFavorites.test.js +267 -0
  96. package/src/screens/Unit/components/AutomateScript/index.js +65 -0
  97. package/src/screens/Unit/components/AutomateScript/styles.js +48 -0
  98. package/src/screens/Unit/components/MyUnitDevice/index.js +4 -2
  99. package/src/screens/UnitSummary/components/3PPowerConsumption/index.js +4 -2
  100. package/src/utils/I18n/translations/en.json +7 -2
  101. package/src/utils/I18n/translations/vi.json +6 -1
  102. package/src/utils/Route/index.js +1 -1
  103. package/src/hooks/Common/useSensorsStatus.js +0 -62
  104. package/src/screens/Unit/__test__/SelectFavoritesDevices.test.js +0 -110
@@ -0,0 +1,102 @@
1
+ import React from 'react';
2
+ import { renderHook } from '@testing-library/react-hooks';
3
+ import { useEvaluateValue } from '../useEvaluateValue';
4
+ import { SCProvider } from '../../../../context';
5
+ import { mockSCStore } from '../../../../context/mockStore';
6
+
7
+ const wrapper =
8
+ (valueEvaluations) =>
9
+ ({ children }) =>
10
+ (
11
+ <SCProvider initState={mockSCStore({ valueEvaluations })}>
12
+ {children}
13
+ </SCProvider>
14
+ );
15
+
16
+ const mockUseContext = jest.fn().mockImplementation(() => ({
17
+ stateData: mockSCStore({}),
18
+ setAction: jest.fn(),
19
+ }));
20
+
21
+ React.useContext = mockUseContext;
22
+
23
+ describe('Test useEvaluateValue', () => {
24
+ let valueEvaluations = {};
25
+
26
+ beforeEach(() => {
27
+ valueEvaluations = {
28
+ [1]: {
29
+ template: 'range',
30
+ configuration: {
31
+ ranges: [
32
+ { start: 0.5, end: 1.5, evaluate: { text: 'On' } },
33
+ { start: -0.5, end: 0.49, evaluate: { text: 'Off' } },
34
+ ],
35
+ },
36
+ },
37
+ [2]: {
38
+ template: 'boolean',
39
+ configuration: {
40
+ on: {
41
+ value: 1,
42
+ evaluate: {
43
+ text: 'On',
44
+ },
45
+ },
46
+ off: {
47
+ value: 0,
48
+ evaluate: {
49
+ text: 'Off',
50
+ },
51
+ },
52
+ },
53
+ },
54
+ };
55
+ });
56
+
57
+ it('test value null or undefined', async () => {
58
+ const { result: evaluateValue } = renderHook(() => useEvaluateValue(), {
59
+ wrapper: wrapper(valueEvaluations),
60
+ });
61
+
62
+ expect(evaluateValue.current(1, null).text).toBe('--');
63
+ expect(evaluateValue.current(1, undefined).text).toBe('--');
64
+ });
65
+
66
+ it('test not found ValueEvaluation', async () => {
67
+ const { result: evaluateValue } = renderHook(() => useEvaluateValue(), {
68
+ wrapper: wrapper(valueEvaluations),
69
+ });
70
+
71
+ expect(evaluateValue.current(3, 1)).toBe(null);
72
+ });
73
+
74
+ it('test template not handle', async () => {
75
+ valueEvaluations[1].template = 'other_template';
76
+ const { result: evaluateValue } = renderHook(() => useEvaluateValue(), {
77
+ wrapper: wrapper(valueEvaluations),
78
+ });
79
+
80
+ expect(evaluateValue.current(1, 1)).toBe(null);
81
+ });
82
+
83
+ it('test evaluate range', async () => {
84
+ const { result: evaluateValue } = renderHook(() => useEvaluateValue(), {
85
+ wrapper: wrapper(valueEvaluations),
86
+ });
87
+
88
+ expect(evaluateValue.current(1, 1).text).toBe('On');
89
+ expect(evaluateValue.current(1, 0).text).toBe('Off');
90
+ expect(evaluateValue.current(1, 100).text).toBe(100);
91
+ });
92
+
93
+ it('test evaluate boolean', async () => {
94
+ const { result: evaluateValue } = renderHook(() => useEvaluateValue(), {
95
+ wrapper: wrapper(valueEvaluations),
96
+ });
97
+
98
+ expect(evaluateValue.current(2, 0).text).toBe('Off');
99
+ expect(evaluateValue.current(2, 1).text).toBe('On');
100
+ expect(evaluateValue.current(2, 2).text).toBe(2);
101
+ });
102
+ });
@@ -0,0 +1,20 @@
1
+ import { useMemo } from 'react';
2
+ import { DEVICE_TYPE } from '../../../configs/Constants';
3
+ import { getConfigControlFromDeviceDisplay } from '../utils';
4
+ import { useWatchConfigs } from '../../../hooks/IoT';
5
+
6
+ export const useDeviceWatchConfigControl = (device, display) => {
7
+ const configsNeedWatching = useMemo(() => {
8
+ if (
9
+ !device?.is_managed_by_backend ||
10
+ [DEVICE_TYPE.GOOGLE_HOME, DEVICE_TYPE.LG_THINQ].includes(
11
+ device?.device_type
12
+ )
13
+ ) {
14
+ return [];
15
+ }
16
+ return getConfigControlFromDeviceDisplay(display);
17
+ }, [device, display]);
18
+
19
+ useWatchConfigs(configsNeedWatching);
20
+ };
@@ -0,0 +1,45 @@
1
+ export const getConfigControlFromDeviceDisplay = (deviceDisplay) => {
2
+ const configIds = [];
3
+ deviceDisplay?.items.map((item) => {
4
+ if (item.type !== 'action') {
5
+ return;
6
+ }
7
+ const actionGroup = item.configuration;
8
+ const { configuration } = actionGroup;
9
+
10
+ switch (actionGroup.template) {
11
+ case 'on_off_button_action_template':
12
+ case 'OnOffButtonActionTemplate':
13
+ case 'OnOffSimpleActionTemplate':
14
+ case 'OnOffSmartLockActionTemplate':
15
+ case 'NumberUpDownActionTemplate':
16
+ case 'OptionsDropdownActionTemplate':
17
+ case 'color_picker_template':
18
+ case 'slider_range_template':
19
+ if (configuration.config) {
20
+ configIds.push(configuration.config);
21
+ }
22
+ break;
23
+ case 'StatesGridActionTemplate':
24
+ configuration.options.forEach((option) => {
25
+ configIds.push(option.config);
26
+ });
27
+ break;
28
+ case 'TimerActionTemplate':
29
+ if (configuration.config_hour) {
30
+ configIds.push(configuration.config_hour);
31
+ }
32
+ if (configuration.config_minute) {
33
+ configIds.push(configuration.config_minute);
34
+ }
35
+ break;
36
+ case 'two_button_action_template':
37
+ configIds.push(configuration.button1.config);
38
+ configIds.push(configuration.button2.config);
39
+ break;
40
+ default:
41
+ break;
42
+ }
43
+ });
44
+ return configIds;
45
+ };
@@ -0,0 +1,111 @@
1
+ import { getConfigControlFromDeviceDisplay } from './index';
2
+
3
+ describe('Test getConfigControlFromDeviceDisplay', () => {
4
+ let deviceDisplay;
5
+
6
+ test('test onoff template', () => {
7
+ deviceDisplay = {
8
+ items: [
9
+ {
10
+ type: 'action',
11
+ configuration: {
12
+ template: 'on_off_button_action_template',
13
+ configuration: {
14
+ config: 1,
15
+ },
16
+ },
17
+ },
18
+ {
19
+ type: 'action',
20
+ configuration: {
21
+ template: 'OnOffButtonActionTemplate',
22
+ configuration: {
23
+ config: 1,
24
+ },
25
+ },
26
+ },
27
+ {
28
+ type: 'action',
29
+ configuration: {
30
+ template: 'OnOffSimpleActionTemplate',
31
+ configuration: {
32
+ config: null,
33
+ },
34
+ },
35
+ },
36
+ ],
37
+ };
38
+ const configs = getConfigControlFromDeviceDisplay(deviceDisplay);
39
+ expect(configs).toHaveLength(2);
40
+ });
41
+
42
+ test('test state grid template', () => {
43
+ deviceDisplay = {
44
+ items: [
45
+ {
46
+ type: 'action',
47
+ configuration: {
48
+ template: 'StatesGridActionTemplate',
49
+ configuration: {
50
+ options: [
51
+ {
52
+ config: 1,
53
+ },
54
+ ],
55
+ },
56
+ },
57
+ },
58
+ ],
59
+ };
60
+ const configs = getConfigControlFromDeviceDisplay(deviceDisplay);
61
+ expect(configs).toHaveLength(1);
62
+ });
63
+
64
+ test('test timer action template', () => {
65
+ deviceDisplay = {
66
+ items: [
67
+ {
68
+ type: 'action',
69
+ configuration: {
70
+ template: 'TimerActionTemplate',
71
+ configuration: {
72
+ config_hour: 1,
73
+ config_minute: 1,
74
+ },
75
+ },
76
+ },
77
+ {
78
+ type: 'action',
79
+ configuration: {
80
+ template: 'TimerActionTemplate',
81
+ configuration: {
82
+ config_hour: null,
83
+ config_minute: null,
84
+ },
85
+ },
86
+ },
87
+ ],
88
+ };
89
+ const configs = getConfigControlFromDeviceDisplay(deviceDisplay);
90
+ expect(configs).toHaveLength(2);
91
+ });
92
+
93
+ test('test two button template', () => {
94
+ deviceDisplay = {
95
+ items: [
96
+ {
97
+ type: 'action',
98
+ configuration: {
99
+ template: 'two_button_action_template',
100
+ configuration: {
101
+ button1: { config: 1 },
102
+ button2: { config: 2 },
103
+ },
104
+ },
105
+ },
106
+ ],
107
+ };
108
+ const configs = getConfigControlFromDeviceDisplay(deviceDisplay);
109
+ expect(configs).toHaveLength(2);
110
+ });
111
+ });
@@ -1,20 +1,19 @@
1
1
  import React, { useCallback, useState } from 'react';
2
- import { SafeAreaView, StyleSheet, TextInput } from 'react-native';
2
+ import { SafeAreaView, StyleSheet, TextInput, View } from 'react-native';
3
3
  import { useNavigation } from '@react-navigation/native';
4
4
  import { useTranslations } from '../../hooks/Common/useTranslations';
5
5
  import { Section, ViewButtonBottom } from '../../commons';
6
6
  import WrapHeaderScrollable from '../../commons/Sharing/WrapHeaderScrollable';
7
7
  import { API, Colors } from '../../configs';
8
- import { useKeyboardShow } from '../../hooks/Common';
9
8
  import { TESTID } from '../../configs/Constants';
10
9
  import { axiosPost } from '../../utils/Apis/axios';
11
10
  import { ToastBottomHelper } from '../../utils/Utils';
11
+ import { isValidPhoneNumber } from '../../utils/Validation';
12
12
 
13
13
  export const EmergencyContactsAddNew = ({ route }) => {
14
14
  const t = useTranslations();
15
15
  const { group } = route.params;
16
16
  const { goBack } = useNavigation();
17
- const { keyboardBottomPadding } = useKeyboardShow();
18
17
  const [textName, setTextName] = useState('');
19
18
  const [textPhone, setTextPhone] = useState('');
20
19
  const onTextNameChange = useCallback(
@@ -33,22 +32,28 @@ export const EmergencyContactsAddNew = ({ route }) => {
33
32
  goBack();
34
33
  }, [goBack]);
35
34
  const onSave = useCallback(async () => {
36
- const { success } = await axiosPost(API.EMERGENCY_BUTTON.CREATE_CONTACT(), {
37
- group: group.id,
38
- phone_number: textPhone,
39
- name: textName,
40
- });
41
- if (success) {
42
- goBack();
35
+ if (isValidPhoneNumber(textPhone)) {
36
+ const { success } = await axiosPost(
37
+ API.EMERGENCY_BUTTON.CREATE_CONTACT(),
38
+ {
39
+ group: group.id,
40
+ phone_number: textPhone,
41
+ name: textName,
42
+ }
43
+ );
44
+ if (success) {
45
+ goBack();
46
+ ToastBottomHelper.success(t('create_contact_success'));
47
+ } else {
48
+ ToastBottomHelper.error(t('create_contact_failed'));
49
+ }
43
50
  } else {
44
- ToastBottomHelper.error(t('create_contact_failed'));
51
+ ToastBottomHelper.error(t('invalid_phone_number'));
45
52
  }
46
53
  }, [goBack, group.id, t, textName, textPhone]);
47
54
 
48
55
  return (
49
- <SafeAreaView
50
- style={[styles.wrap, { marginBottom: keyboardBottomPadding }]}
51
- >
56
+ <SafeAreaView style={styles.wrap}>
52
57
  <WrapHeaderScrollable title={t('create_contact')}>
53
58
  <Section type={'border'}>
54
59
  <TextInput
@@ -58,6 +63,7 @@ export const EmergencyContactsAddNew = ({ route }) => {
58
63
  placeholder={t('text_name')}
59
64
  underlineColorAndroid={null}
60
65
  onChangeText={onTextNameChange}
66
+ maxLength={64}
61
67
  />
62
68
  <TextInput
63
69
  testID={TESTID.ON_CHANGE_PHONE_EMERGENCY_CONTACT}
@@ -67,17 +73,20 @@ export const EmergencyContactsAddNew = ({ route }) => {
67
73
  underlineColorAndroid={null}
68
74
  keyboardType={'phone-pad'}
69
75
  onChangeText={onTextPhoneChange}
76
+ maxLength={64}
70
77
  />
71
78
  </Section>
72
79
  </WrapHeaderScrollable>
73
- <ViewButtonBottom
74
- leftTitle={t('cancel')}
75
- leftDisabled={false}
76
- onLeftClick={onCancel}
77
- rightTitle={t('save')}
78
- rightDisabled={!textPhone || !textName}
79
- onRightClick={onSave}
80
- />
80
+ <View style={styles.viewButtonBottom}>
81
+ <ViewButtonBottom
82
+ leftTitle={t('cancel')}
83
+ leftDisabled={false}
84
+ onLeftClick={onCancel}
85
+ rightTitle={t('save')}
86
+ rightDisabled={!textPhone || !textName}
87
+ onRightClick={onSave}
88
+ />
89
+ </View>
81
90
  </SafeAreaView>
82
91
  );
83
92
  };
@@ -95,4 +104,8 @@ const styles = StyleSheet.create({
95
104
  fontFamily: 'SFProDisplay-Regular',
96
105
  lineHeight: 24,
97
106
  },
107
+ viewButtonBottom: {
108
+ borderTopWidth: 1,
109
+ borderTopColor: Colors.Gray4,
110
+ },
98
111
  });
@@ -27,8 +27,9 @@ export const EmergencyContactsSelectContacts = ({ route }) => {
27
27
  setLoading(true);
28
28
  const { success, data } = await axiosGet(API.SHARE.UNITS_MEMBERS(id));
29
29
  if (success) {
30
+ const result = data.filter((item) => item?.name && item?.phone_number);
30
31
  setLoading(false);
31
- setDataContact(data);
32
+ setDataContact(result);
32
33
  }
33
34
  }, []);
34
35
 
@@ -115,22 +115,40 @@ describe('test EmergencyContactAddNew', () => {
115
115
  const instance = tree.root;
116
116
  const viewButtonBottom = instance.findByType(ViewButtonBottom);
117
117
 
118
+ const TextInput_ = instance.find(
119
+ (el) =>
120
+ el.props.testID === TESTID.ON_CHANGE_PHONE_EMERGENCY_CONTACT &&
121
+ el.type === TextInput
122
+ );
123
+
118
124
  await act(async () => {
125
+ await TextInput_.props.onChangeText('0901603859');
119
126
  await viewButtonBottom.props.onRightClick();
120
127
  });
121
128
 
122
129
  expect(mockedGoBack).toHaveBeenCalledTimes(1);
123
130
  });
124
131
 
125
- test('onSave fail', async () => {
132
+ test('onSave failed', async () => {
126
133
  await act(async () => {
127
134
  tree = await create(wrapComponent(route));
128
135
  });
129
136
  const instance = tree.root;
130
137
  const viewButtonBottom = instance.findByType(ViewButtonBottom);
131
138
 
139
+ const TextInput_ = instance.find(
140
+ (el) =>
141
+ el.props.testID === TESTID.ON_CHANGE_PHONE_EMERGENCY_CONTACT &&
142
+ el.type === TextInput
143
+ );
144
+
132
145
  mock.onPost(API.EMERGENCY_BUTTON.CREATE_CONTACT()).reply(400);
133
- await viewButtonBottom.props.onRightClick();
146
+
147
+ await act(async () => {
148
+ await TextInput_.props.onChangeText('0901603859');
149
+ await viewButtonBottom.props.onRightClick();
150
+ });
151
+
134
152
  expect(Toast.show).toHaveBeenCalledWith({
135
153
  type: 'error',
136
154
  position: 'bottom',
@@ -139,4 +157,20 @@ describe('test EmergencyContactAddNew', () => {
139
157
  });
140
158
  expect(mockedGoBack).not.toHaveBeenCalled();
141
159
  });
160
+
161
+ test('invalid phone number', async () => {
162
+ await act(async () => {
163
+ tree = await create(wrapComponent(route));
164
+ });
165
+ const instance = tree.root;
166
+ const viewButtonBottom = instance.findByType(ViewButtonBottom);
167
+
168
+ await viewButtonBottom.props.onRightClick();
169
+ expect(Toast.show).toHaveBeenCalledWith({
170
+ type: 'error',
171
+ position: 'bottom',
172
+ text1: getTranslate('en', 'invalid_phone_number'),
173
+ visibilityTime: 1000,
174
+ });
175
+ });
142
176
  });
@@ -65,7 +65,6 @@ describe('Test Render ListSubUnit', () => {
65
65
  icon_kit: '',
66
66
  id: 73,
67
67
  is_managed_by_backend: true,
68
- is_other_device: false,
69
68
  name: 'Multi-Air Quality',
70
69
  quick_action: null,
71
70
  },
@@ -91,7 +90,6 @@ describe('Test Render ListSubUnit', () => {
91
90
  icon_kit: '',
92
91
  id: 73,
93
92
  is_managed_by_backend: true,
94
- is_other_device: false,
95
93
  name: 'Multi-Air Quality',
96
94
  quick_action: null,
97
95
  },
@@ -6,7 +6,11 @@ import MockAdapter from 'axios-mock-adapter';
6
6
  import { SCProvider } from '../../../context';
7
7
  import { mockSCStore } from '../../../context/mockStore';
8
8
  import NotificationItem from '../components/NotificationItem';
9
- import { NOTIFICATION_TYPES, SENSOR_TYPE } from '../../../configs/Constants';
9
+ import {
10
+ NOTIFICATION_TYPES,
11
+ SENSOR_TYPE,
12
+ EMERGENCY_TYPE,
13
+ } from '../../../configs/Constants';
10
14
  import Routes from '../../../utils/Route';
11
15
  import { API } from '../../../configs';
12
16
  import api from '../../../utils/Apis/axios';
@@ -37,7 +41,7 @@ describe('test NotificationItem', () => {
37
41
  id: 1,
38
42
  content_code: '',
39
43
  is_read: true,
40
- params: "{'booking_id': 1, 'booking_id_new': 1}",
44
+ params: { booking_id: 1, booking_id_new: 1 },
41
45
  created_at: '',
42
46
  icon: '',
43
47
  };
@@ -50,47 +54,47 @@ describe('test NotificationItem', () => {
50
54
  {
51
55
  content_code: NOTIFICATION_TYPES.REMIND_TO_MAKE_PAYMENT,
52
56
  screen: Routes.SmartParkingBookingDetails,
53
- params: "{ 'id': 1 }",
57
+ params: { id: 1 },
54
58
  },
55
59
  {
56
60
  content_code: NOTIFICATION_TYPES.EXPIRE_PARKING_SESSION,
57
61
  screen: Routes.SmartParkingBookingDetails,
58
- params: "{ 'id': 1 }",
62
+ params: { id: 1 },
59
63
  },
60
64
  {
61
65
  content_code: NOTIFICATION_TYPES.REMIND_TO_SCAN_QR_CODE,
62
66
  screen: Routes.SmartParkingBookingDetails,
63
- params: "{ 'id': 1 }",
67
+ params: { id: 1 },
64
68
  },
65
69
  {
66
70
  content_code: NOTIFICATION_TYPES.BOOKING_SUCCESSFULLY,
67
71
  screen: Routes.SmartParkingBookingDetails,
68
- params: "{ 'id': 1 }",
72
+ params: { id: 1 },
69
73
  },
70
74
  {
71
75
  content_code: NOTIFICATION_TYPES.BOOKING_EXPIRED_AND_VIOLATION_CREATED,
72
76
  screen: Routes.SmartParkingBookingDetails,
73
- params: "{ 'id': 1 }",
77
+ params: { id: 1 },
74
78
  },
75
79
  {
76
80
  content_code: NOTIFICATION_TYPES.MOVE_CAR_WITHOUT_PAY_VIOLATION,
77
81
  screen: Routes.SmartParkingBookingDetails,
78
- params: "{ 'id': 1 }",
82
+ params: { id: 1 },
79
83
  },
80
84
  {
81
85
  content_code: NOTIFICATION_TYPES.PAY_FINE_SUCCESSFULLY,
82
86
  screen: Routes.SmartParkingBookingDetails,
83
- params: "{ 'id': 1 }",
87
+ params: { id: 1 },
84
88
  },
85
89
  {
86
90
  content_code: NOTIFICATION_TYPES.STOP_VIOLATION_FREE_PARKING_ZONE,
87
91
  screen: Routes.SmartParkingBookingDetails,
88
- params: "{ 'id': 1 }",
92
+ params: { id: 1 },
89
93
  },
90
94
  {
91
95
  content_code: NOTIFICATION_TYPES.PAY_FINE_AND_EXTEND_SUCCESSFULLY,
92
96
  screen: Routes.SmartParkingBookingDetails,
93
- params: "{ 'id': 1 }",
97
+ params: { id: 1 },
94
98
  },
95
99
  ];
96
100
 
@@ -116,17 +120,17 @@ describe('test NotificationItem', () => {
116
120
  {
117
121
  content_code: NOTIFICATION_TYPES.USER_CANCEL,
118
122
  screen: Routes.MyBookingList,
119
- params: "{ 'tab': 1 }",
123
+ params: { tab: 1 },
120
124
  },
121
125
  {
122
126
  content_code: NOTIFICATION_TYPES.SYSTEM_CANCEL_NO_PAYMENT,
123
127
  screen: Routes.MyBookingList,
124
- params: "{ 'tab': 1 }",
128
+ params: { tab: 1 },
125
129
  },
126
130
  {
127
131
  content_code: NOTIFICATION_TYPES.PARKING_COMPLETED,
128
132
  screen: Routes.MyBookingList,
129
- params: "{ 'tab': 1 }",
133
+ params: { tab: 1 },
130
134
  },
131
135
  ];
132
136
  for (const notify of listCaseSmartParking2) {
@@ -181,7 +185,11 @@ describe('test NotificationItem', () => {
181
185
  for (const sensorType of listSensorType) {
182
186
  test(`create ItemNotification NOTIFY_INDICATOR sensor_type ${sensorType}`, () => {
183
187
  item.content_code = NOTIFICATION_TYPES.NOTIFY_INDICATOR;
184
- item.params = `{'sensor_type': '${sensorType}', 'unit_id': 5, 'summary_id': 11}`;
188
+ item.params = {
189
+ sensor_type: sensorType,
190
+ unit_id: 5,
191
+ summary_id: 11,
192
+ };
185
193
  act(() => {
186
194
  tree = create(wrapComponent(item));
187
195
  });
@@ -209,7 +217,11 @@ describe('test NotificationItem', () => {
209
217
  for (const sensorType of listSensorType2) {
210
218
  test(`create ItemNotification NOTIFY_INDICATOR sensor_type ${sensorType}`, () => {
211
219
  item.content_code = NOTIFICATION_TYPES.NOTIFY_INDICATOR;
212
- item.params = `{'sensor_type': '${sensorType}', 'unit_id': 70, 'sensor_id': 394}`;
220
+ item.params = {
221
+ sensor_type: sensorType,
222
+ unit_id: 70,
223
+ sensor_id: 394,
224
+ };
213
225
 
214
226
  act(() => {
215
227
  tree = create(wrapComponent(item));
@@ -231,8 +243,11 @@ describe('test NotificationItem', () => {
231
243
 
232
244
  test('test onClick Item Notify', () => {
233
245
  item.content_code = NOTIFICATION_TYPES.NOTIFY_INDICATOR;
234
- item.params =
235
- "{'sensor_type': 'air_quality', 'unit_id': 5, 'summary_id': 11}";
246
+ item.params = {
247
+ sensor_type: 'air_quality',
248
+ unit_id: 5,
249
+ summary_id: 11,
250
+ };
236
251
  item.is_read = false;
237
252
  act(() => {
238
253
  tree = create(wrapComponent(item));
@@ -254,7 +269,7 @@ describe('test NotificationItem', () => {
254
269
 
255
270
  test('test render Notify not in any case', () => {
256
271
  item.content_code = 'NEW CASE';
257
- item.params = "{ 'unit_id': 1 }";
272
+ item.params = { unit_id: 1 };
258
273
  act(() => {
259
274
  tree = create(wrapComponent(item));
260
275
  });
@@ -279,4 +294,54 @@ describe('test NotificationItem', () => {
279
294
  });
280
295
  expect(mockNavigate).not.toHaveBeenCalledWith();
281
296
  });
297
+
298
+ test('test notify emergency ', () => {
299
+ item.content_code = NOTIFICATION_TYPES.NOTIFY_EMERGENCY;
300
+ item.params = {
301
+ unit_id: 1,
302
+ sensor_id: 1,
303
+ type: EMERGENCY_TYPE.CREATED,
304
+ };
305
+
306
+ act(() => {
307
+ tree = create(wrapComponent(item));
308
+ });
309
+ const instance = tree.root;
310
+ const button = instance.findByType(TouchableOpacity);
311
+ act(() => {
312
+ button.props.onPress();
313
+ });
314
+ expect(mockNavigate).toHaveBeenCalledWith(Routes.UnitStack, {
315
+ screen: Routes.DeviceDetail,
316
+ params: {
317
+ unitId: 1,
318
+ sensorId: 1,
319
+ },
320
+ });
321
+ });
322
+
323
+ test('test notify emergency_resolve ', () => {
324
+ item.content_code = NOTIFICATION_TYPES.NOTIFY_EMERGENCY;
325
+ item.params = {
326
+ unit_id: 1,
327
+ sensor_id: 1,
328
+ type: EMERGENCY_TYPE.RESOLVE,
329
+ };
330
+
331
+ act(() => {
332
+ tree = create(wrapComponent(item));
333
+ });
334
+ const instance = tree.root;
335
+ const button = instance.findByType(TouchableOpacity);
336
+ act(() => {
337
+ button.props.onPress();
338
+ });
339
+ expect(mockNavigate).toHaveBeenCalledWith(Routes.UnitStack, {
340
+ screen: Routes.DeviceDetail,
341
+ params: {
342
+ unitId: 1,
343
+ sensorId: 1,
344
+ },
345
+ });
346
+ });
282
347
  });