@eohjsc/react-native-smart-city 0.3.81 → 0.3.83
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 +2 -2
- package/src/Images/Common/Sunny.png +0 -0
- package/src/Images/Common/Sunny@2x.png +0 -0
- package/src/Images/Common/Sunny@3x.png +0 -0
- package/src/commons/ActionGroup/SliderRangeTemplateStyles.js +1 -0
- package/src/commons/ActionGroup/__test__/OnOffButtonTemplate.test.js +54 -12
- package/src/commons/Device/ProgressBar/__test__/ProgressBar.test.js +49 -0
- package/src/commons/Device/ProgressBar/index.js +45 -0
- package/src/commons/Device/ProgressBar/styles.js +33 -0
- package/src/commons/Device/RainningSensor/CurrentRainSensor.js +14 -3
- package/src/commons/Device/RainningSensor/__test__/CurrentRainSensor.test.js +43 -3
- package/src/commons/Popover/__test__/index.test.js +31 -0
- package/src/configs/Colors.js +1 -0
- package/src/configs/Constants.js +1 -0
- package/src/configs/IOPinConstants.js +92 -165
- package/src/configs/Images.js +1 -0
- package/src/screens/AddNewDevice/__test__/AddNewDevice.test.js +17 -8
- package/src/screens/AddNewDevice/index.js +5 -4
- package/src/screens/AllGateway/DetailConfigActionInternal/__test__/index.test.js +1 -1
- package/src/screens/AllGateway/DetailConfigActionInternal/index.js +21 -23
- package/src/screens/AllGateway/DeviceInternalDetail/__test__/index.test.js +8 -6
- package/src/screens/AllGateway/DeviceInternalDetail/index.js +2 -0
- package/src/screens/AllGateway/hooks/useGateway.js +30 -2
- package/src/screens/Device/__test__/DetailHistoryChart.test.js +34 -21
- package/src/screens/Device/__test__/EmergencyCountdown.test.js +34 -0
- package/src/screens/Device/components/SensorDisplayItem.js +3 -0
- package/src/screens/EmergencySetting/__test__/index.test.js +22 -0
- package/src/screens/Notification/components/NotificationItem.js +8 -0
- package/src/screens/SyncLGDevice/AddLGDevice.js +5 -4
- package/src/screens/Unit/Detail.js +8 -7
- package/src/screens/Unit/components/MyUnitDevice/index.js +5 -2
- package/src/screens/Unit/hook/useFavorites.js +1 -1
- package/src/utils/Converter/__test__/timer.test.js +7 -0
- package/src/utils/Functions/preloadImages.js +1 -1
- package/src/utils/I18n/translations/en.json +3 -1
- package/src/utils/I18n/translations/vi.json +4 -1
- package/src/utils/Utils.js +18 -11
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.3.
|
|
4
|
+
"version": "0.3.83",
|
|
5
5
|
"description": "TODO",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"files": [
|
|
@@ -162,7 +162,7 @@
|
|
|
162
162
|
"react-native-credit-card-input": "^0.4.1",
|
|
163
163
|
"react-native-dash": "^0.0.11",
|
|
164
164
|
"react-native-deep-linking": "^2.2.0",
|
|
165
|
-
"react-native-device-info": "^
|
|
165
|
+
"react-native-device-info": "^10.3.0",
|
|
166
166
|
"react-native-draggable-flatlist": "^2.6.2",
|
|
167
167
|
"react-native-fast-image": "^8.3.2",
|
|
168
168
|
"react-native-geocoder": "^0.5.0",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
+
import { TouchableOpacity } from 'react-native';
|
|
2
3
|
import { act, create } from 'react-test-renderer';
|
|
4
|
+
|
|
3
5
|
import OnOffTemplate from '../OnOffTemplate';
|
|
4
6
|
import { mockSCStore } from '../../../context/mockStore';
|
|
5
7
|
import { SCProvider } from '../../../context';
|
|
8
|
+
import Text from '../../Text';
|
|
9
|
+
import { useConfigGlobalState } from '../../../iot/states';
|
|
10
|
+
|
|
11
|
+
jest.mock('../../../iot/states', () => ({
|
|
12
|
+
useConfigGlobalState: jest.fn(),
|
|
13
|
+
}));
|
|
6
14
|
|
|
7
15
|
const wrapComponent = (actionGroup, mockDoAction) => (
|
|
8
16
|
<SCProvider initState={mockSCStore({})}>
|
|
@@ -49,45 +57,79 @@ describe('Test OneBigButtonTemplate', () => {
|
|
|
49
57
|
action_off_data: action_off_data,
|
|
50
58
|
icon_off: 'caret-up',
|
|
51
59
|
text_off: 'OFF',
|
|
60
|
+
config: 1,
|
|
52
61
|
},
|
|
62
|
+
template: 'on_off_button_action_template',
|
|
63
|
+
id: 1,
|
|
53
64
|
};
|
|
54
65
|
let wrapper;
|
|
55
66
|
|
|
56
|
-
|
|
67
|
+
beforeEach(() => {
|
|
68
|
+
useConfigGlobalState.mockClear();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const assertRender = async (textValue) => {
|
|
57
72
|
const mockDoAction = jest.fn();
|
|
58
73
|
|
|
59
74
|
await act(async () => {
|
|
60
75
|
wrapper = create(wrapComponent(actionGroup, mockDoAction));
|
|
61
76
|
});
|
|
62
77
|
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
expect(
|
|
66
|
-
expect(renderJson[1]?.type).toEqual('Modal');
|
|
78
|
+
const instance = wrapper.root;
|
|
79
|
+
const texts = instance.findAllByType(Text);
|
|
80
|
+
expect(texts[0].props.children).toEqual(textValue);
|
|
67
81
|
};
|
|
68
82
|
|
|
69
83
|
it('render state on', async () => {
|
|
70
|
-
|
|
84
|
+
useConfigGlobalState.mockImplementation(() => [
|
|
85
|
+
{
|
|
86
|
+
1: {
|
|
87
|
+
value: 1,
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
jest.fn(),
|
|
91
|
+
]);
|
|
92
|
+
await assertRender('ON');
|
|
71
93
|
});
|
|
72
94
|
|
|
73
95
|
it('render state off', async () => {
|
|
74
|
-
|
|
96
|
+
useConfigGlobalState.mockImplementation(() => [
|
|
97
|
+
{
|
|
98
|
+
1: {
|
|
99
|
+
value: 0,
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
jest.fn(),
|
|
103
|
+
]);
|
|
104
|
+
await assertRender('OFF');
|
|
75
105
|
});
|
|
76
106
|
|
|
77
|
-
const assertActionCall = async (state, action_data) => {
|
|
107
|
+
const assertActionCall = async (state, action_data, data2) => {
|
|
108
|
+
useConfigGlobalState.mockImplementation(() => [
|
|
109
|
+
{
|
|
110
|
+
1: {
|
|
111
|
+
value: state,
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
jest.fn(),
|
|
115
|
+
]);
|
|
78
116
|
const mockDoAction = jest.fn();
|
|
79
117
|
await act(async () => {
|
|
80
118
|
wrapper = create(wrapComponent(actionGroup, mockDoAction));
|
|
81
119
|
});
|
|
82
|
-
|
|
83
|
-
|
|
120
|
+
const instance = wrapper.root;
|
|
121
|
+
const button = instance.findByType(TouchableOpacity);
|
|
122
|
+
await act(async () => {
|
|
123
|
+
await button.props.onPress();
|
|
124
|
+
});
|
|
125
|
+
expect(mockDoAction).toHaveBeenCalledWith(action_data, data2);
|
|
84
126
|
};
|
|
85
127
|
|
|
86
128
|
it('action state on', async () => {
|
|
87
|
-
await assertActionCall(true,
|
|
129
|
+
await assertActionCall(true, action_on_data, { state: 0, value: 0 });
|
|
88
130
|
});
|
|
89
131
|
|
|
90
132
|
it('action state off', async () => {
|
|
91
|
-
await assertActionCall(false,
|
|
133
|
+
await assertActionCall(false, action_off_data, { state: 1, value: 1 });
|
|
92
134
|
});
|
|
93
135
|
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/* eslint-disable promise/prefer-await-to-callbacks */
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { useSelector } from 'react-redux';
|
|
4
|
+
import renderer, { act } from 'react-test-renderer';
|
|
5
|
+
|
|
6
|
+
import ProgressBar from '..';
|
|
7
|
+
import Text from '../../../Text';
|
|
8
|
+
import { SCProvider } from '../../../../context';
|
|
9
|
+
import { mockSCStore } from '../../../../context/mockStore';
|
|
10
|
+
|
|
11
|
+
jest.mock('react-redux', () => ({
|
|
12
|
+
...jest.requireActual('react-redux'),
|
|
13
|
+
useSelector: jest.fn(),
|
|
14
|
+
}));
|
|
15
|
+
|
|
16
|
+
const wrapComponent = (item, data) => (
|
|
17
|
+
<SCProvider initState={mockSCStore({})}>
|
|
18
|
+
<ProgressBar item={item} data={data} />
|
|
19
|
+
</SCProvider>
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
describe('Test ProgressBar', () => {
|
|
23
|
+
let tree;
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
const localState = {
|
|
26
|
+
language: 'en',
|
|
27
|
+
};
|
|
28
|
+
useSelector.mockImplementation((cb) => {
|
|
29
|
+
return cb(localState);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('render ProgressBar', async () => {
|
|
34
|
+
const item = {
|
|
35
|
+
label: 'Value bar',
|
|
36
|
+
configuration: { max_value: 100 },
|
|
37
|
+
value: 8,
|
|
38
|
+
};
|
|
39
|
+
const data = [{ value: 10 }];
|
|
40
|
+
await act(async () => {
|
|
41
|
+
tree = renderer.create(wrapComponent(item, data));
|
|
42
|
+
});
|
|
43
|
+
const instance = tree.root;
|
|
44
|
+
const texts = instance.findAllByType(Text);
|
|
45
|
+
expect(texts[0].props.children).toBe('Value bar');
|
|
46
|
+
expect(texts[1].props.children).toEqual(['Max value', ': ', 100]);
|
|
47
|
+
expect(texts[2].props.children).toEqual([10, '%']);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import React, { memo, useMemo } from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
import * as Progress from 'react-native-progress';
|
|
4
|
+
|
|
5
|
+
import { Colors } from '../../../configs';
|
|
6
|
+
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
7
|
+
import Text from '../../Text';
|
|
8
|
+
import styles from './styles';
|
|
9
|
+
|
|
10
|
+
const ProgressBar = memo(({ data = [], item }) => {
|
|
11
|
+
const t = useTranslations();
|
|
12
|
+
|
|
13
|
+
const maxValue = useMemo(() => {
|
|
14
|
+
return Number(item?.configuration?.max_value) || 60;
|
|
15
|
+
}, [item?.configuration?.max_value]);
|
|
16
|
+
const value = data.length ? data[0].value : 0;
|
|
17
|
+
const percent = value / maxValue; // a number between 0 and 1
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<View style={styles.container}>
|
|
21
|
+
<Text size={16} style={styles.textLabel}>
|
|
22
|
+
{item?.label || 'Label'}
|
|
23
|
+
</Text>
|
|
24
|
+
|
|
25
|
+
<Text size={16} style={styles.textMaxValue}>
|
|
26
|
+
{t('max_value')}: {maxValue}
|
|
27
|
+
</Text>
|
|
28
|
+
|
|
29
|
+
<View style={styles.wrapProgressBar}>
|
|
30
|
+
<Progress.Bar
|
|
31
|
+
progress={percent}
|
|
32
|
+
height={40}
|
|
33
|
+
width={200}
|
|
34
|
+
color={Colors.Blue16}
|
|
35
|
+
unfilledColor={Colors.Blue15}
|
|
36
|
+
borderWidth={0}
|
|
37
|
+
borderRadius={10}
|
|
38
|
+
/>
|
|
39
|
+
<Text style={styles.textValue}>{value}%</Text>
|
|
40
|
+
</View>
|
|
41
|
+
</View>
|
|
42
|
+
);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
export default ProgressBar;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { StyleSheet } from 'react-native';
|
|
2
|
+
|
|
3
|
+
import { Colors } from '../../../configs';
|
|
4
|
+
|
|
5
|
+
export default StyleSheet.create({
|
|
6
|
+
container: {
|
|
7
|
+
flex: 1,
|
|
8
|
+
flexDirection: 'column', //column direction
|
|
9
|
+
marginRight: 60,
|
|
10
|
+
marginLeft: 60,
|
|
11
|
+
borderWidth: 1,
|
|
12
|
+
padding: 12,
|
|
13
|
+
borderRadius: 8,
|
|
14
|
+
borderColor: Colors.Gray4,
|
|
15
|
+
},
|
|
16
|
+
textLabel: {
|
|
17
|
+
paddingHorizontal: 16,
|
|
18
|
+
paddingTop: 8,
|
|
19
|
+
},
|
|
20
|
+
textMaxValue: {
|
|
21
|
+
textAlign: 'right',
|
|
22
|
+
},
|
|
23
|
+
wrapProgressBar: {
|
|
24
|
+
flex: 1,
|
|
25
|
+
flexDirection: 'row',
|
|
26
|
+
justifyContent: 'center',
|
|
27
|
+
alignItems: 'center',
|
|
28
|
+
padding: 8,
|
|
29
|
+
},
|
|
30
|
+
textValue: {
|
|
31
|
+
marginLeft: 8,
|
|
32
|
+
},
|
|
33
|
+
});
|
|
@@ -6,6 +6,8 @@ import { Colors } from '../../../configs';
|
|
|
6
6
|
import { CircleView } from '../../../commons';
|
|
7
7
|
import Text from '../../../commons/Text';
|
|
8
8
|
import IconComponent from '../../IconComponent';
|
|
9
|
+
import images from '../../../configs/Images';
|
|
10
|
+
import FImage from '../../FImage';
|
|
9
11
|
|
|
10
12
|
const CurrentRainSensor = memo(({ data = [] }) => {
|
|
11
13
|
const item = data.length
|
|
@@ -31,9 +33,14 @@ const CurrentRainSensor = memo(({ data = [] }) => {
|
|
|
31
33
|
start={{ x: 1, y: 0 }}
|
|
32
34
|
end={{ x: 1, y: 1 }}
|
|
33
35
|
/>
|
|
34
|
-
|
|
35
|
-
icon={icon_kit_data?.icon || icon
|
|
36
|
-
|
|
36
|
+
{icon_kit_data?.icon || icon ? (
|
|
37
|
+
<IconComponent icon={icon_kit_data?.icon || icon} />
|
|
38
|
+
) : (
|
|
39
|
+
<FImage
|
|
40
|
+
source={images.activeCurrentSensor}
|
|
41
|
+
style={styles.iconDefault}
|
|
42
|
+
/>
|
|
43
|
+
)}
|
|
37
44
|
<Text style={styles.text}>{text}</Text>
|
|
38
45
|
</CircleView>
|
|
39
46
|
</View>
|
|
@@ -68,4 +75,8 @@ const styles = StyleSheet.create({
|
|
|
68
75
|
lineHeight: 32,
|
|
69
76
|
fontSize: 24,
|
|
70
77
|
},
|
|
78
|
+
iconDefault: {
|
|
79
|
+
width: 37,
|
|
80
|
+
height: 37,
|
|
81
|
+
},
|
|
71
82
|
});
|
|
@@ -2,6 +2,8 @@ import React from 'react';
|
|
|
2
2
|
import { View } from 'react-native';
|
|
3
3
|
import renderer, { act } from 'react-test-renderer';
|
|
4
4
|
import CurrentRainSensor from '../CurrentRainSensor';
|
|
5
|
+
import FImage from '../../../FImage';
|
|
6
|
+
import IconComponent from '../../../IconComponent';
|
|
5
7
|
|
|
6
8
|
describe('Test CurrentRainSensor', () => {
|
|
7
9
|
let tree;
|
|
@@ -21,7 +23,7 @@ describe('Test CurrentRainSensor', () => {
|
|
|
21
23
|
});
|
|
22
24
|
const instance = tree.root;
|
|
23
25
|
const Views = instance.findAllByType(View);
|
|
24
|
-
expect(Views).toHaveLength(
|
|
26
|
+
expect(Views).toHaveLength(3);
|
|
25
27
|
});
|
|
26
28
|
|
|
27
29
|
it('render CurrentRainSensor raining: true', async () => {
|
|
@@ -40,7 +42,7 @@ describe('Test CurrentRainSensor', () => {
|
|
|
40
42
|
});
|
|
41
43
|
const instance = tree.root;
|
|
42
44
|
const Views = instance.findAllByType(View);
|
|
43
|
-
expect(Views).toHaveLength(
|
|
45
|
+
expect(Views).toHaveLength(3);
|
|
44
46
|
});
|
|
45
47
|
|
|
46
48
|
it('render CurrentRainSensor data empty', async () => {
|
|
@@ -49,6 +51,44 @@ describe('Test CurrentRainSensor', () => {
|
|
|
49
51
|
});
|
|
50
52
|
const instance = tree.root;
|
|
51
53
|
const Views = instance.findAllByType(View);
|
|
52
|
-
expect(Views).toHaveLength(
|
|
54
|
+
expect(Views).toHaveLength(3);
|
|
55
|
+
});
|
|
56
|
+
it('render CurrentRainSensor default icon', async () => {
|
|
57
|
+
const data = [
|
|
58
|
+
{
|
|
59
|
+
evaluate: {
|
|
60
|
+
text: 'default',
|
|
61
|
+
backgroundColor: '#FEFFE6',
|
|
62
|
+
borderColor: '#FADB14',
|
|
63
|
+
icon_kit_data: '',
|
|
64
|
+
icon: '',
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
];
|
|
68
|
+
await act(async () => {
|
|
69
|
+
tree = renderer.create(<CurrentRainSensor data={data} />);
|
|
70
|
+
});
|
|
71
|
+
const instance = tree.root;
|
|
72
|
+
const fimage = instance.findAllByType(FImage);
|
|
73
|
+
expect(fimage).toHaveLength(1);
|
|
74
|
+
});
|
|
75
|
+
it('render CurrentRainSensor has icon kit and icon', async () => {
|
|
76
|
+
const data = [
|
|
77
|
+
{
|
|
78
|
+
evaluate: {
|
|
79
|
+
text: 'default',
|
|
80
|
+
backgroundColor: '#FEFFE6',
|
|
81
|
+
borderColor: '#FADB14',
|
|
82
|
+
icon_kit_data: 'http:s//',
|
|
83
|
+
icon: 'http:s//',
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
];
|
|
87
|
+
await act(async () => {
|
|
88
|
+
tree = renderer.create(<CurrentRainSensor data={data} />);
|
|
89
|
+
});
|
|
90
|
+
const instance = tree.root;
|
|
91
|
+
const iconComponent = instance.findAllByType(IconComponent);
|
|
92
|
+
expect(iconComponent).toHaveLength(1);
|
|
53
93
|
});
|
|
54
94
|
});
|
|
@@ -0,0 +1,31 @@
|
|
|
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 PopoverComponent from '../index';
|
|
6
|
+
import Popover from 'react-native-popover-view';
|
|
7
|
+
|
|
8
|
+
const wrapComponent = (data) => (
|
|
9
|
+
<SCProvider initState={mockSCStore({})}>
|
|
10
|
+
<PopoverComponent {...data} />
|
|
11
|
+
</SCProvider>
|
|
12
|
+
);
|
|
13
|
+
const mockOnCloseComplete = jest.fn();
|
|
14
|
+
describe('Test PopoverComponent', () => {
|
|
15
|
+
let tree;
|
|
16
|
+
|
|
17
|
+
it('Test Popover', async () => {
|
|
18
|
+
await act(async () => {
|
|
19
|
+
tree = await create(
|
|
20
|
+
wrapComponent({ isVisible: true, onCloseComplete: mockOnCloseComplete })
|
|
21
|
+
);
|
|
22
|
+
});
|
|
23
|
+
const instance = tree.root;
|
|
24
|
+
const popover = instance.findByType(Popover);
|
|
25
|
+
await act(async () => {
|
|
26
|
+
popover.props.onCloseComplete();
|
|
27
|
+
});
|
|
28
|
+
expect(popover.props.isVisible).toEqual(true);
|
|
29
|
+
expect(mockOnCloseComplete).toBeCalled();
|
|
30
|
+
});
|
|
31
|
+
});
|
package/src/configs/Colors.js
CHANGED
package/src/configs/Constants.js
CHANGED
|
@@ -260,6 +260,7 @@ export const NOTIFICATION_TYPES = {
|
|
|
260
260
|
NOTIFY_REMOVE_SUB_UNIT: 'NOTIFY_REMOVE_SUB_UNIT',
|
|
261
261
|
NOTIFY_REMOVE_DEVICE: 'NOTIFY_REMOVE_DEVICE',
|
|
262
262
|
NOTIFY_EMERGENCY: 'NOTIFY_EMERGENCY',
|
|
263
|
+
NOTIFY_UPGRADE_SYSTEM: 'NOTIFY_UPGRADE_SYSTEM',
|
|
263
264
|
NOTIFY_CHANGE_UNIT_OLD_OWNER: 'NOTIFY_CHANGE_UNIT_OLD_OWNER',
|
|
264
265
|
NOTIFY_CHANGE_UNIT_NEW_OWNER: 'NOTIFY_CHANGE_UNIT_NEW_OWNER',
|
|
265
266
|
AIR_QUALITY: 'AIR_QUALITY',
|