@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.
- package/index.js +2 -0
- package/package.json +2 -1
- package/src/Images/Common/buttonLeftCurtain.png +0 -0
- package/src/Images/Common/buttonLeftCurtain@2x.png +0 -0
- package/src/Images/Common/buttonLeftCurtain@3x.png +0 -0
- package/src/commons/Action/ItemQuickAction.js +1 -12
- package/src/commons/Action/__test__/ItemQuickAction.test.js +1 -1
- package/src/commons/ActionGroup/ColorPickerTemplate.js +2 -9
- package/src/commons/ActionGroup/CurtainButtonTemplate.js +14 -21
- package/src/commons/ActionGroup/CurtainButtonTemplateStyle.js +5 -0
- package/src/commons/ActionGroup/NumberUpDownActionTemplate.js +12 -24
- package/src/commons/ActionGroup/OnOffSmartLock/OnOffSmartLock.js +10 -17
- package/src/commons/ActionGroup/OnOffTemplate/index.js +10 -35
- package/src/commons/ActionGroup/OneBigButtonTemplate.js +2 -3
- package/src/commons/ActionGroup/OptionsDropdownActionTemplate.js +7 -8
- package/src/commons/ActionGroup/SliderRangeTemplate.js +3 -10
- package/src/commons/ActionGroup/StatesGridActionTemplate.js +9 -24
- package/src/commons/ActionGroup/ThreeButtonTemplate.js +6 -9
- package/src/commons/ActionGroup/TimerActionTemplate.js +11 -4
- package/src/commons/ActionGroup/TwoButtonTemplate/index.js +18 -33
- package/src/commons/ActionGroup/__test__/CurtainButtonTemplate.test.js +3 -15
- package/src/commons/ActionGroup/__test__/NumberUpDownTemplate.test.js +38 -4
- package/src/commons/ActionGroup/__test__/OnOffButtonTemplate.test.js +7 -0
- package/src/commons/ActionGroup/__test__/OnOffSmartLock.test.js +17 -12
- package/src/commons/ActionGroup/__test__/OnOffTemplate.test.js +11 -16
- package/src/commons/ActionGroup/__test__/OneBigButtonTemplate.test.js +1 -1
- package/src/commons/ActionGroup/__test__/OptionsDropdownTemplate.test.js +11 -10
- package/src/commons/ActionGroup/__test__/StatesGridActionTemplate.test.js +8 -7
- package/src/commons/ActionGroup/__test__/TimerActionTemplate.test.js +8 -1
- package/src/commons/ActionGroup/__test__/TimerActionTemplateWithutConfigValue.test.js +7 -0
- package/src/commons/ActionGroup/__test__/TwoButtonTemplate.test.js +17 -2
- package/src/commons/ActionGroup/__test__/index.test.js +15 -18
- package/src/commons/ConnectingProcess/index.js +6 -25
- package/src/commons/Device/HistoryChart.js +8 -6
- package/src/commons/Device/ItemDevice.js +79 -35
- package/src/commons/MediaPlayerDetail/index.js +5 -0
- package/src/commons/RowItem/index.js +6 -2
- package/src/commons/SubUnit/Favorites/index.js +24 -6
- package/src/commons/SubUnit/ShortDetail.js +31 -5
- package/src/commons/SubUnit/__test__/Favorites.test.js +1 -0
- package/src/commons/SubUnit/__test__/ShortDetail.test.js +1 -0
- package/src/configs/API.js +9 -4
- package/src/configs/Constants.js +8 -2
- package/src/configs/SCConfig.js +4 -0
- package/src/context/actionType.ts +7 -5
- package/src/context/mockStore.ts +10 -3
- package/src/context/reducer.ts +29 -15
- package/src/hoc/index.js +3 -0
- package/src/hoc/withRemoteControl.js +10 -0
- package/src/hooks/Common/index.js +2 -2
- package/src/hooks/Common/useDevicesStatus.js +57 -0
- package/src/hooks/Common/useGGHomeDeviceConnected.js +3 -3
- package/src/hooks/IoT/__test__/useGGHomeConnection.test.js +1 -2
- package/src/hooks/IoT/__test__/useRemoteControl.test.js +9 -11
- package/src/hooks/IoT/index.js +9 -1
- package/src/hooks/IoT/useGGHomeConnection.js +0 -1
- package/src/hooks/IoT/useRemoteControl.js +2 -3
- package/src/hooks/IoT/useUnwatchLGDeviceConfigControl.js +29 -0
- package/src/hooks/IoT/useValueEvaluation.js +17 -4
- package/src/hooks/IoT/useWatchConfigs.js +34 -0
- package/src/iot/Monitor.js +13 -20
- package/src/iot/RemoteControl/GoogleHome.js +12 -13
- package/src/iot/RemoteControl/Internet.js +1 -8
- package/src/iot/RemoteControl/LG.js +1 -0
- package/src/iot/RemoteControl/__test__/GoogleHome.test.js +7 -2
- package/src/navigations/UnitStack.js +27 -3
- package/src/screens/AddNewAction/SelectAction.js +1 -1
- package/src/screens/AddNewAction/SetupSensor.js +4 -0
- package/src/screens/AddNewGateway/PlugAndPlay/ConnectWifiWarning.js +44 -78
- package/src/screens/AddNewGateway/PlugAndPlay/GatewayWifiList.js +15 -35
- package/src/screens/AddNewGateway/PlugAndPlay/__test__/GatewayWifiList.test.js +2 -0
- package/src/screens/AllCamera/__test__/index.test.js +1 -1
- package/src/screens/Device/__test__/detail.test.js +1 -54
- package/src/screens/Device/components/SensorConnectStatusViewHeader.js +18 -8
- package/src/screens/Device/components/SensorDisplayItem.js +2 -2
- package/src/screens/Device/detail.js +36 -30
- package/src/screens/Device/hooks/__test__/useEvaluateValue.test.js +102 -0
- package/src/screens/Device/hooks/useDeviceWatchConfigControl.js +20 -0
- package/src/screens/Device/utils/index.js +45 -0
- package/src/screens/Device/utils/index.test.js +111 -0
- package/src/screens/EmergencyContacts/EmergencyContactsAddNew.js +35 -22
- package/src/screens/EmergencyContacts/EmergencyContactsSelectContacts.js +2 -1
- package/src/screens/EmergencyContacts/__test__/EmergencyContactAddNew.test.js +36 -2
- package/src/screens/MoveToAnotherSubUnit/__test__/index.test.js +0 -2
- package/src/screens/Notification/__test__/NotificationItem.test.js +84 -19
- package/src/screens/Notification/components/NotificationItem.js +64 -31
- package/src/screens/PlayBackCamera/index.js +22 -6
- package/src/screens/ScriptDetail/hooks/useStarredScript.js +2 -2
- package/src/screens/SubUnit/AddSubUnit.js +2 -1
- package/src/screens/Unit/AddMenu.js +4 -0
- package/src/screens/Unit/{SelectFavoritesDevices.js → SelectAddToFavorites.js} +81 -26
- package/src/screens/Unit/{SelectFavoritesDevicesStyles.js → SelectAddToFavoritesStyles.js} +0 -0
- package/src/screens/Unit/__test__/CheckSendEmail.test.js +12 -0
- package/src/screens/Unit/__test__/Detail.test.js +2 -3
- package/src/screens/Unit/__test__/SelectAddToFavorites.test.js +267 -0
- package/src/screens/Unit/components/AutomateScript/index.js +65 -0
- package/src/screens/Unit/components/AutomateScript/styles.js +48 -0
- package/src/screens/Unit/components/MyUnitDevice/index.js +4 -2
- package/src/screens/UnitSummary/components/3PPowerConsumption/index.js +4 -2
- package/src/utils/I18n/translations/en.json +7 -2
- package/src/utils/I18n/translations/vi.json +6 -1
- package/src/utils/Route/index.js +1 -1
- package/src/hooks/Common/useSensorsStatus.js +0 -62
- 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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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('
|
|
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
|
-
<
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
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 {
|
|
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:
|
|
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:
|
|
57
|
+
params: { id: 1 },
|
|
54
58
|
},
|
|
55
59
|
{
|
|
56
60
|
content_code: NOTIFICATION_TYPES.EXPIRE_PARKING_SESSION,
|
|
57
61
|
screen: Routes.SmartParkingBookingDetails,
|
|
58
|
-
params:
|
|
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:
|
|
67
|
+
params: { id: 1 },
|
|
64
68
|
},
|
|
65
69
|
{
|
|
66
70
|
content_code: NOTIFICATION_TYPES.BOOKING_SUCCESSFULLY,
|
|
67
71
|
screen: Routes.SmartParkingBookingDetails,
|
|
68
|
-
params:
|
|
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:
|
|
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:
|
|
82
|
+
params: { id: 1 },
|
|
79
83
|
},
|
|
80
84
|
{
|
|
81
85
|
content_code: NOTIFICATION_TYPES.PAY_FINE_SUCCESSFULLY,
|
|
82
86
|
screen: Routes.SmartParkingBookingDetails,
|
|
83
|
-
params:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
128
|
+
params: { tab: 1 },
|
|
125
129
|
},
|
|
126
130
|
{
|
|
127
131
|
content_code: NOTIFICATION_TYPES.PARKING_COMPLETED,
|
|
128
132
|
screen: Routes.MyBookingList,
|
|
129
|
-
params:
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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
|
});
|