@eohjsc/react-native-smart-city 0.3.79 → 0.3.81
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 +1 -1
- package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/__test__/index.test.js +12 -0
- package/src/commons/ActionGroup/OnOffTemplate/SwitchButtonTemplate.js +63 -0
- package/src/commons/ActionGroup/OptionsDropdownActionTemplate.js +5 -5
- package/src/commons/ActionGroup/SliderRangeTemplate.js +2 -7
- package/src/commons/ActionGroup/__test__/NumberUpDownTemplate.test.js +2 -2
- package/src/commons/ActionGroup/__test__/SliderRangeTemplate.test.js +0 -20
- package/src/commons/ActionGroup/__test__/SwitchButtonTemplate.test.js +93 -0
- package/src/commons/ActionGroup/hooks/useDropdownAction.js +0 -1
- package/src/commons/ActionGroup/index.js +3 -0
- package/src/commons/SelectGateway/index.js +1 -1
- package/src/configs/Constants.js +2 -0
- package/src/configs/IOPinConstants.js +33 -0
- package/src/screens/AddNewAction/SelectAction.js +1 -1
- package/src/screens/Device/utils/index.js +4 -4
- package/src/screens/Notification/__test__/NotificationItem.test.js +2 -0
- package/src/screens/Notification/components/NotificationItem.js +23 -0
- package/src/screens/Template/__test__/detail.test.js +20 -3
- package/src/utils/I18n/translations/en.json +2 -0
- package/src/utils/I18n/translations/vi.json +2 -0
- package/src/utils/Utils.js +19 -2
- package/src/utils/__test__/Utils.test.js +15 -0
package/package.json
CHANGED
|
@@ -80,4 +80,16 @@ describe('Test SetupGeneratePasscode', () => {
|
|
|
80
80
|
const wheelDateTimePicker = instance.findAllByType(WheelDateTimePicker);
|
|
81
81
|
expect(wheelDateTimePicker).toHaveLength(3);
|
|
82
82
|
});
|
|
83
|
+
|
|
84
|
+
it('Test onTimePicked', async () => {
|
|
85
|
+
await act(async () => {
|
|
86
|
+
tree = await create(wrapComponent());
|
|
87
|
+
});
|
|
88
|
+
const instance = tree.root;
|
|
89
|
+
const wheelDateTimePickers = instance.findAllByType(WheelDateTimePicker);
|
|
90
|
+
await act(async () => {
|
|
91
|
+
wheelDateTimePickers[0].props.onPicked(new Date(2022, 10, 10));
|
|
92
|
+
});
|
|
93
|
+
expect(wheelDateTimePickers[0].props.defaultValue).toBe(1668038400000);
|
|
94
|
+
});
|
|
83
95
|
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import React, { memo, useCallback, useState } from 'react';
|
|
2
|
+
import { Switch, View } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import Text from '../../Text';
|
|
5
|
+
import { Colors } from '../../../configs';
|
|
6
|
+
import styles from './OnOffButtonTemplateStyle';
|
|
7
|
+
import AccessibilityLabel from '../../../configs/AccessibilityLabel';
|
|
8
|
+
|
|
9
|
+
const SwitchButtonTemplate = memo(
|
|
10
|
+
({ isOn, triggerAction, actionGroup = {}, isLight = false, doAction }) => {
|
|
11
|
+
const [_isOn, setIsOn] = useState(isOn);
|
|
12
|
+
|
|
13
|
+
const { configuration = {}, id } = actionGroup;
|
|
14
|
+
const {
|
|
15
|
+
action_off_data,
|
|
16
|
+
action_on_data,
|
|
17
|
+
text_on,
|
|
18
|
+
text_off,
|
|
19
|
+
color_on,
|
|
20
|
+
color_off,
|
|
21
|
+
} = configuration;
|
|
22
|
+
|
|
23
|
+
const onChangeSwitch = useCallback(() => {
|
|
24
|
+
if (_isOn) {
|
|
25
|
+
setIsOn(false);
|
|
26
|
+
doAction(action_off_data, null);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
doAction(action_on_data, null);
|
|
30
|
+
setIsOn(true);
|
|
31
|
+
}, [action_off_data, action_on_data, doAction, _isOn]);
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<>
|
|
35
|
+
<View style={styles.barrierControlContainer}>
|
|
36
|
+
<Switch
|
|
37
|
+
trackColor={{ false: color_off, true: color_on }}
|
|
38
|
+
ios_backgroundColor={_isOn ? color_on : color_off}
|
|
39
|
+
onValueChange={onChangeSwitch}
|
|
40
|
+
value={_isOn}
|
|
41
|
+
/>
|
|
42
|
+
<Text
|
|
43
|
+
style={[
|
|
44
|
+
styles.textBig,
|
|
45
|
+
{ color: _isOn ? Colors.Gray8 : Colors.Gray6 },
|
|
46
|
+
]}
|
|
47
|
+
accessibilityLabel={`${AccessibilityLabel.SENSOR_STATUS}-${id}`}
|
|
48
|
+
>
|
|
49
|
+
{_isOn ? text_on : text_off}
|
|
50
|
+
</Text>
|
|
51
|
+
</View>
|
|
52
|
+
|
|
53
|
+
{!!actionGroup.title && !isLight && (
|
|
54
|
+
<Text type="H3" semibold center>
|
|
55
|
+
{actionGroup.title}
|
|
56
|
+
</Text>
|
|
57
|
+
)}
|
|
58
|
+
</>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
export default SwitchButtonTemplate;
|
|
@@ -17,10 +17,10 @@ import SvgCurrentState from '../../../assets/images/Device/current-state.svg';
|
|
|
17
17
|
import SvgWindStrength from '../../../assets/images/Device/wind-strength.svg';
|
|
18
18
|
|
|
19
19
|
function getOptionValue(option, allow_config_store_value) {
|
|
20
|
-
if (option
|
|
21
|
-
return option
|
|
20
|
+
if (option?.value_text && !allow_config_store_value) {
|
|
21
|
+
return option?.value_text;
|
|
22
22
|
}
|
|
23
|
-
return option
|
|
23
|
+
return option?.value_int;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
const OptionsDropdownActionTemplate = ({
|
|
@@ -29,7 +29,7 @@ const OptionsDropdownActionTemplate = ({
|
|
|
29
29
|
sensor = {},
|
|
30
30
|
}) => {
|
|
31
31
|
const t = useTranslations();
|
|
32
|
-
const { configuration = {}, title } = actionGroup;
|
|
32
|
+
const { configuration = {}, title = '' } = actionGroup;
|
|
33
33
|
const {
|
|
34
34
|
action_data,
|
|
35
35
|
options = [],
|
|
@@ -155,7 +155,7 @@ const OptionsDropdownActionTemplate = ({
|
|
|
155
155
|
<AlertAction
|
|
156
156
|
visible={stateAlert.visible}
|
|
157
157
|
hideModal={hideAlertAction}
|
|
158
|
-
title={
|
|
158
|
+
title={title}
|
|
159
159
|
message={stateAlert.message}
|
|
160
160
|
leftButtonTitle={stateAlert.leftButton}
|
|
161
161
|
leftButtonClick={hideAlertAction}
|
|
@@ -30,19 +30,14 @@ const SliderRangeTemplate = memo(({ actionGroup = {}, doAction, sensor }) => {
|
|
|
30
30
|
const [valueBrightness, setValueBrightness] = useState(getPercent());
|
|
31
31
|
const [isFirstTime, setIsFirstTime] = useState(true);
|
|
32
32
|
|
|
33
|
-
// TODO Thinh: remove action_brightness_data
|
|
34
33
|
const onChangeBrightness = useCallback(
|
|
35
34
|
async (value) => {
|
|
36
35
|
await doAction(
|
|
37
|
-
configuration?.
|
|
36
|
+
configuration?.action_data,
|
|
38
37
|
JSON.stringify({ value_brness: value, value: value })
|
|
39
38
|
);
|
|
40
39
|
},
|
|
41
|
-
[
|
|
42
|
-
configuration?.action_brightness_data,
|
|
43
|
-
configuration?.action_data,
|
|
44
|
-
doAction,
|
|
45
|
-
]
|
|
40
|
+
[configuration?.action_data, doAction]
|
|
46
41
|
);
|
|
47
42
|
|
|
48
43
|
useEffect(() => {
|
|
@@ -250,7 +250,7 @@ describe('Test NumberUpDownActionTemplate', () => {
|
|
|
250
250
|
});
|
|
251
251
|
|
|
252
252
|
const text = instance.findByType(Text);
|
|
253
|
-
expect(text.props.children).toEqual('24 *C');
|
|
253
|
+
expect(text.props.children).toEqual('24 *C');
|
|
254
254
|
});
|
|
255
255
|
|
|
256
256
|
it('action up with allow_config_store_value false', async () => {
|
|
@@ -276,7 +276,7 @@ describe('Test NumberUpDownActionTemplate', () => {
|
|
|
276
276
|
});
|
|
277
277
|
|
|
278
278
|
const text = instance.findByType(Text);
|
|
279
|
-
expect(text.props.children).toEqual('26 *C');
|
|
279
|
+
expect(text.props.children).toEqual('26 *C');
|
|
280
280
|
});
|
|
281
281
|
|
|
282
282
|
it('action down limit ', async () => {
|
|
@@ -66,26 +66,6 @@ describe('Test SliderRangeTemplate', () => {
|
|
|
66
66
|
);
|
|
67
67
|
});
|
|
68
68
|
|
|
69
|
-
it('render template SliderRangeTemplate with data backward compatible', async () => {
|
|
70
|
-
actionGroup.configuration.action_data = undefined;
|
|
71
|
-
actionGroup.configuration.action_brightness_data = action_data;
|
|
72
|
-
useConfigGlobalState.mockImplementation(() => [{}, jest.fn()]);
|
|
73
|
-
const sensor = { is_managed_by_backend: true, name: 'Sensor' };
|
|
74
|
-
await act(async () => {
|
|
75
|
-
wrapper = await create(wrapComponent(actionGroup, mockDoAction, sensor));
|
|
76
|
-
});
|
|
77
|
-
const instance = wrapper.root;
|
|
78
|
-
const silderRange = instance.findAllByType(SliderRange);
|
|
79
|
-
expect(silderRange).toHaveLength(1);
|
|
80
|
-
await act(async () => {
|
|
81
|
-
await silderRange[0].props.onSlidingComplete(50);
|
|
82
|
-
});
|
|
83
|
-
expect(mockDoAction).toHaveBeenCalledWith(
|
|
84
|
-
action_data,
|
|
85
|
-
JSON.stringify({ value_brness: 50, value: 50 })
|
|
86
|
-
);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
69
|
it('render template SliderRangeTemplate with config value not null', async () => {
|
|
90
70
|
useConfigGlobalState.mockImplementation(() => [
|
|
91
71
|
{
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { act, create } from 'react-test-renderer';
|
|
3
|
+
|
|
4
|
+
import { mockSCStore } from '../../../context/mockStore';
|
|
5
|
+
import { SCProvider } from '../../../context';
|
|
6
|
+
import SwitchButtonTemplate from '../OnOffTemplate/SwitchButtonTemplate';
|
|
7
|
+
|
|
8
|
+
const wrapComponent = (actionGroup, mockDoAction) => (
|
|
9
|
+
<SCProvider initState={mockSCStore({})}>
|
|
10
|
+
<SwitchButtonTemplate actionGroup={actionGroup} doAction={mockDoAction} />
|
|
11
|
+
</SCProvider>
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
jest.mock('@react-navigation/native', () => {
|
|
15
|
+
return {
|
|
16
|
+
...jest.requireActual('@react-navigation/native'),
|
|
17
|
+
useFocusEffect: jest.fn(),
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('Test SwitchButtonTemplate', () => {
|
|
22
|
+
const action_on_data = {
|
|
23
|
+
color: '#00979D',
|
|
24
|
+
command_prefer_over_bluetooth: true,
|
|
25
|
+
command_prefer_over_googlehome: false,
|
|
26
|
+
command_prefer_over_internet: false,
|
|
27
|
+
googlehome_actions: [],
|
|
28
|
+
icon: 'caret-up',
|
|
29
|
+
id: 20,
|
|
30
|
+
key: '5ed1d4dc-a905-47cd-b0c9-f979644bd21a',
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const action_off_data = {
|
|
34
|
+
color: '#00979D',
|
|
35
|
+
command_prefer_over_bluetooth: true,
|
|
36
|
+
command_prefer_over_googlehome: false,
|
|
37
|
+
command_prefer_over_internet: false,
|
|
38
|
+
googlehome_actions: [],
|
|
39
|
+
icon: 'caret-up',
|
|
40
|
+
id: 20,
|
|
41
|
+
key: '5ed1d4dc-a905-47cd-b0c9-f979644bd21a',
|
|
42
|
+
};
|
|
43
|
+
const actionGroup = {
|
|
44
|
+
configuration: {
|
|
45
|
+
action_on: '5ed1d4dc-a905-47cd-b0c9-f979644bd21a',
|
|
46
|
+
action_on_data: action_on_data,
|
|
47
|
+
icon_on: 'caret-up',
|
|
48
|
+
text_on: 'ON',
|
|
49
|
+
action_off: '5ed1d4dc-a905-47cd-b0c9-f979644bd21b',
|
|
50
|
+
action_off_data: action_off_data,
|
|
51
|
+
icon_off: 'caret-up',
|
|
52
|
+
text_off: 'OFF',
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
let wrapper;
|
|
56
|
+
|
|
57
|
+
const assertRender = async () => {
|
|
58
|
+
const mockDoAction = jest.fn();
|
|
59
|
+
|
|
60
|
+
await act(async () => {
|
|
61
|
+
wrapper = create(wrapComponent(actionGroup, mockDoAction));
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const renderJson = wrapper.toJSON();
|
|
65
|
+
expect(renderJson[1].props?.visible).toEqual(false);
|
|
66
|
+
expect(renderJson[1]?.type).toEqual('Modal');
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
it('render state on', async () => {
|
|
70
|
+
await assertRender(true, 'ON');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('render state off', async () => {
|
|
74
|
+
await assertRender(false, 'OFF');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const assertActionCall = async (state, action_data) => {
|
|
78
|
+
const mockDoAction = jest.fn();
|
|
79
|
+
await act(async () => {
|
|
80
|
+
wrapper = create(wrapComponent(actionGroup, mockDoAction));
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
expect(mockDoAction).not.toHaveBeenCalled();
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
it('action state on', async () => {
|
|
87
|
+
await assertActionCall(true, action_off_data);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('action state off', async () => {
|
|
91
|
+
await assertActionCall(false, action_on_data);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
@@ -13,6 +13,7 @@ import ColorPickerTemplate from './ColorPickerTemplate';
|
|
|
13
13
|
import SliderRangeTemplate from './SliderRangeTemplate';
|
|
14
14
|
import OnOffSmartLock from './OnOffSmartLock/OnOffSmartLock';
|
|
15
15
|
import TwoButtonTemplate from './TwoButtonTemplate';
|
|
16
|
+
import SwitchButtonTemplate from './OnOffTemplate/SwitchButtonTemplate';
|
|
16
17
|
|
|
17
18
|
export const getActionComponent = (template) => {
|
|
18
19
|
switch (template) {
|
|
@@ -46,6 +47,8 @@ export const getActionComponent = (template) => {
|
|
|
46
47
|
return SliderRangeTemplate;
|
|
47
48
|
case 'two_button_action_template':
|
|
48
49
|
return TwoButtonTemplate;
|
|
50
|
+
case 'switch_button_action_template':
|
|
51
|
+
return SwitchButtonTemplate;
|
|
49
52
|
default:
|
|
50
53
|
return null;
|
|
51
54
|
}
|
|
@@ -122,7 +122,7 @@ const SelectGateway = ({
|
|
|
122
122
|
onRightClick={onRightClickNext}
|
|
123
123
|
accessibilityLabelPrefix={AccessibilityLabel.PREFIX.SELECT_UNIT}
|
|
124
124
|
/>
|
|
125
|
-
<ModalCustom // todo
|
|
125
|
+
<ModalCustom // todo Nhat - make reused component
|
|
126
126
|
onBackButtonPress={goBack}
|
|
127
127
|
isVisible={showPopupGuide}
|
|
128
128
|
style={styles.modal}
|
package/src/configs/Constants.js
CHANGED
|
@@ -260,6 +260,8 @@ 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_CHANGE_UNIT_OLD_OWNER: 'NOTIFY_CHANGE_UNIT_OLD_OWNER',
|
|
264
|
+
NOTIFY_CHANGE_UNIT_NEW_OWNER: 'NOTIFY_CHANGE_UNIT_NEW_OWNER',
|
|
263
265
|
AIR_QUALITY: 'AIR_QUALITY',
|
|
264
266
|
TURBIDITY: 'TURBIDITY',
|
|
265
267
|
PH: 'PH',
|
|
@@ -283,3 +283,36 @@ export const STM32_ANALOG_WRITE = [
|
|
|
283
283
|
{ key: '73', value: 'PB14' },
|
|
284
284
|
{ key: '74', value: 'PB4' },
|
|
285
285
|
];
|
|
286
|
+
|
|
287
|
+
export const ESP8266_DIGITAL = [
|
|
288
|
+
{ key: '0', value: 'GPIO 0 - D3' },
|
|
289
|
+
{ key: '1', value: 'GPIO 1 - D10 - UART 0 TX' },
|
|
290
|
+
{ key: '2', value: 'GPIO 2 - D4 - UART 0 TX2' },
|
|
291
|
+
{ key: '3', value: 'GPIO 3 - D9 - UART 0 RX' },
|
|
292
|
+
{ key: '4', value: 'GPIO 4 - D2' },
|
|
293
|
+
{ key: '5', value: 'GPIO 5 - D1' },
|
|
294
|
+
{ key: '12', value: 'GPIO 12 - D6' },
|
|
295
|
+
{ key: '13', value: 'GPIO 13 - D7 - UART 1 RX' },
|
|
296
|
+
{ key: '14', value: 'GPIO 14 - D5' },
|
|
297
|
+
{ key: '15', value: 'GPIO 15 - D8 - UART 1 TX' },
|
|
298
|
+
{ key: '16', value: 'GPIO 16 - D0' },
|
|
299
|
+
];
|
|
300
|
+
|
|
301
|
+
export const ESP8266_ANALOG_READ = [{ key: '17', value: 'GPIO 17 - A0' }];
|
|
302
|
+
|
|
303
|
+
export const ESP8266_ANALOG_WRITE = [
|
|
304
|
+
{ key: '0', value: 'GPIO 0 - D3' },
|
|
305
|
+
{ key: '1', value: 'GPIO 1 - D10 - UART 0 TX' },
|
|
306
|
+
{ key: '2', value: 'GPIO 2 - D4 - UART 0 TX2' },
|
|
307
|
+
{ key: '3', value: 'GPIO 3 - D9 - UART 0 RX' },
|
|
308
|
+
{ key: '4', value: 'GPIO 4 - D2' },
|
|
309
|
+
{ key: '5', value: 'GPIO 5 - D1' },
|
|
310
|
+
{ key: '12', value: 'GPIO 12 - D6' },
|
|
311
|
+
{ key: '13', value: 'GPIO 13 - D7 - UART 1 RX' },
|
|
312
|
+
{ key: '14', value: 'GPIO 14 - D5' },
|
|
313
|
+
{ key: '15', value: 'GPIO 15 - D8 - UART 1 TX' },
|
|
314
|
+
];
|
|
315
|
+
|
|
316
|
+
export const LANGUAGE = {
|
|
317
|
+
DEFAULT: 'vi',
|
|
318
|
+
};
|
|
@@ -441,7 +441,7 @@ const SelectAction = memo(({ route }) => {
|
|
|
441
441
|
onSelectAction={handleOnSelectAction}
|
|
442
442
|
accessibilityLabel={AccessibilityLabel.ACTION_ITEM}
|
|
443
443
|
/>
|
|
444
|
-
{/* TODO:
|
|
444
|
+
{/* TODO: Nhat - refactor/combine with value_change case */}
|
|
445
445
|
{!!sensorData &&
|
|
446
446
|
sensorData.map((item) => {
|
|
447
447
|
const isHasValue = !!item?.value;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
export const getConfigControlFromDeviceDisplay = (deviceDisplay) => {
|
|
2
2
|
const configIds = [];
|
|
3
|
-
deviceDisplay?.items.map((item) => {
|
|
3
|
+
(deviceDisplay?.items || []).map((item) => {
|
|
4
4
|
if (item.type !== 'action') {
|
|
5
5
|
return;
|
|
6
6
|
}
|
|
7
|
-
const actionGroup = item
|
|
8
|
-
const { configuration } = actionGroup;
|
|
7
|
+
const actionGroup = item?.configuration || {};
|
|
8
|
+
const { configuration = {} } = actionGroup;
|
|
9
9
|
|
|
10
10
|
switch (actionGroup.template) {
|
|
11
11
|
case 'on_off_button_action_template':
|
|
@@ -21,7 +21,7 @@ export const getConfigControlFromDeviceDisplay = (deviceDisplay) => {
|
|
|
21
21
|
}
|
|
22
22
|
break;
|
|
23
23
|
case 'StatesGridActionTemplate':
|
|
24
|
-
configuration
|
|
24
|
+
(configuration?.options || []).forEach((option) => {
|
|
25
25
|
configIds.push(option.config);
|
|
26
26
|
});
|
|
27
27
|
break;
|
|
@@ -54,6 +54,7 @@ describe('test NotificationItem', () => {
|
|
|
54
54
|
NOTIFICATION_TYPES.NOTIFY_MEMBER_LEAVE_UNIT,
|
|
55
55
|
NOTIFICATION_TYPES.NOTIFY_REMOVE_SUB_UNIT,
|
|
56
56
|
NOTIFICATION_TYPES.NOTIFY_REMOVE_DEVICE,
|
|
57
|
+
NOTIFICATION_TYPES.NOTIFY_CHANGE_UNIT_OLD_OWNER,
|
|
57
58
|
];
|
|
58
59
|
|
|
59
60
|
for (const content_code of listCase2) {
|
|
@@ -76,6 +77,7 @@ describe('test NotificationItem', () => {
|
|
|
76
77
|
NOTIFICATION_TYPES.NOTIFY_UPDATE_ADDRESS,
|
|
77
78
|
NOTIFICATION_TYPES.NOTIFY_RENAME_SUB_UNIT,
|
|
78
79
|
NOTIFICATION_TYPES.NOTIFY_INVITE_MEMBER,
|
|
80
|
+
NOTIFICATION_TYPES.NOTIFY_CHANGE_UNIT_NEW_OWNER,
|
|
79
81
|
];
|
|
80
82
|
|
|
81
83
|
for (const content_code of listCaseUnitDetail) {
|
|
@@ -355,6 +355,29 @@ const NotificationItem = memo(({ item }) => {
|
|
|
355
355
|
default:
|
|
356
356
|
return null;
|
|
357
357
|
}
|
|
358
|
+
case NOTIFICATION_TYPES.NOTIFY_CHANGE_UNIT_OLD_OWNER:
|
|
359
|
+
return {
|
|
360
|
+
content: customColorText(
|
|
361
|
+
t('text_notification_content_change_unit_for_old_owner')
|
|
362
|
+
),
|
|
363
|
+
redirect: () => null,
|
|
364
|
+
iconContent: <Image source={Images.logo} style={styles.logo} />,
|
|
365
|
+
};
|
|
366
|
+
case NOTIFICATION_TYPES.NOTIFY_CHANGE_UNIT_NEW_OWNER:
|
|
367
|
+
return {
|
|
368
|
+
content: customColorText(
|
|
369
|
+
t('text_notification_content_change_unit_for_new_owner')
|
|
370
|
+
),
|
|
371
|
+
redirect: () => {
|
|
372
|
+
navigation.navigate(Routes.UnitStack, {
|
|
373
|
+
screen: Routes.UnitDetail,
|
|
374
|
+
params: {
|
|
375
|
+
unitId,
|
|
376
|
+
},
|
|
377
|
+
});
|
|
378
|
+
},
|
|
379
|
+
iconContent: <Image source={Images.logo} style={styles.logo} />,
|
|
380
|
+
};
|
|
358
381
|
default:
|
|
359
382
|
return null;
|
|
360
383
|
}
|
|
@@ -35,7 +35,11 @@ jest.mock('@react-navigation/native', () => {
|
|
|
35
35
|
|
|
36
36
|
describe('Test Detail', () => {
|
|
37
37
|
useRoute.mockReturnValue({
|
|
38
|
-
params: {
|
|
38
|
+
params: {
|
|
39
|
+
item: {
|
|
40
|
+
id: 1,
|
|
41
|
+
},
|
|
42
|
+
},
|
|
39
43
|
});
|
|
40
44
|
let tree;
|
|
41
45
|
|
|
@@ -43,9 +47,9 @@ describe('Test Detail', () => {
|
|
|
43
47
|
mock.onGet(API.DEV_MODE.DASHBOARD.GET_WIDGETS(1)).reply(200, [
|
|
44
48
|
{
|
|
45
49
|
id: 1,
|
|
46
|
-
type: '
|
|
50
|
+
type: 'value',
|
|
47
51
|
configuration: {
|
|
48
|
-
|
|
52
|
+
configs: [{ id: 1 }],
|
|
49
53
|
},
|
|
50
54
|
},
|
|
51
55
|
]);
|
|
@@ -81,8 +85,21 @@ describe('Test Detail', () => {
|
|
|
81
85
|
await TouchableOpacities[1].props.onPress();
|
|
82
86
|
});
|
|
83
87
|
const menuActionMore = instance.findByType(MenuActionMore);
|
|
88
|
+
const mockDoAction = jest.fn();
|
|
89
|
+
const item = {
|
|
90
|
+
text: 'text',
|
|
91
|
+
doAction: mockDoAction,
|
|
92
|
+
};
|
|
93
|
+
await act(async () => {
|
|
94
|
+
await menuActionMore.props.onItemClick(item);
|
|
95
|
+
});
|
|
96
|
+
expect(mockDoAction).toBeCalled();
|
|
84
97
|
const modalPopupCT = instance.findByType(ModalPopupCT);
|
|
85
98
|
mock.onGet(API.DEV_MODE.DASHBOARD.DETAIL(1)).reply(200);
|
|
99
|
+
await act(async () => {
|
|
100
|
+
await menuActionMore.props.listMenuItem[0].doAction();
|
|
101
|
+
});
|
|
102
|
+
expect(mockNavigate).toHaveBeenCalled();
|
|
86
103
|
await act(async () => {
|
|
87
104
|
await menuActionMore.props.listMenuItem[3].doAction();
|
|
88
105
|
});
|
|
@@ -690,6 +690,8 @@
|
|
|
690
690
|
"text_notification_content_emergency": "The Emergency button has been activated at **unit_name**: **sub_unit_name**. Please check now!",
|
|
691
691
|
"text_notification_content_emergency_resolve": "Emergency situation activated at **unit_name**: **sub_unit_name** has resolved.",
|
|
692
692
|
"text_notification_content_invite_member": "**unit_owner_name** invited you to join **unit_name**.",
|
|
693
|
+
"text_notification_content_change_unit_for_old_owner": "Your ownership of **unit_name** has been assigned to **new_owner_name**.",
|
|
694
|
+
"text_notification_content_change_unit_for_new_owner": "You are now the owner of **unit_name**.",
|
|
693
695
|
"this_spot_does_not_exsit": "This spot does not exist",
|
|
694
696
|
"please_scan_again_or_contact_the_parking_manager": "Please scan again or contact the parking manager",
|
|
695
697
|
"this_spot_does_not_support_to_scan": "This spot does not support to scan",
|
|
@@ -704,6 +704,8 @@
|
|
|
704
704
|
"text_notification_content_emergency": "Một tình huống khẩn cấp vừa được kích hoạt tại **unit_name**: **sub_unit_name**. Vui lòng kiểm tra ngay!",
|
|
705
705
|
"text_notification_content_emergency_resolve": "Tình huống khẩn cấp được kích hoạt tại **unit_name**: **sub_unit_name** đã được giải quyết.",
|
|
706
706
|
"text_notification_content_invite_member": "**unit_owner_name** mời bạn đến địa điểm **unit_name**.",
|
|
707
|
+
"text_notification_content_change_unit_for_old_owner": "Quyền sở hữu **unit_name** của bạn đã được chỉ định cho **new_owner_name**.",
|
|
708
|
+
"text_notification_content_change_unit_for_new_owner": "Bạn hiện là chủ sở hữu của **unit_name**.",
|
|
707
709
|
"this_spot_does_not_exsit": "Vị trí đỗ này không tồn tại",
|
|
708
710
|
"please_scan_again_or_contact_the_parking_manager": "Vui lòng quét lại hoặc liên hệ với người quản lý bãi đậu xe",
|
|
709
711
|
"this_spot_does_not_support_to_scan": "Vị trí đỗ này không hỗ trợ quét",
|
package/src/utils/Utils.js
CHANGED
|
@@ -18,6 +18,9 @@ import {
|
|
|
18
18
|
WRITE_DIGITAL_PIN_MODE,
|
|
19
19
|
WRITE_ANALOG_PIN_MODE,
|
|
20
20
|
LANGUAGE,
|
|
21
|
+
ESP8266_DIGITAL,
|
|
22
|
+
ESP8266_ANALOG_READ,
|
|
23
|
+
ESP8266_ANALOG_WRITE,
|
|
21
24
|
} from '../configs/IOPinConstants';
|
|
22
25
|
|
|
23
26
|
export const setAxiosDefaultAuthToken = (token) => {
|
|
@@ -150,8 +153,12 @@ export const notImplemented = (t) => {
|
|
|
150
153
|
};
|
|
151
154
|
|
|
152
155
|
export const roundNumber = (value, round = 2) => {
|
|
153
|
-
if (
|
|
154
|
-
|
|
156
|
+
if (typeof value === 'string') {
|
|
157
|
+
const temp = value.split(' ');
|
|
158
|
+
return (
|
|
159
|
+
Math.round((isNaN(temp[0]) ? 0 : temp[0]) * 10 ** round) / 10 ** round +
|
|
160
|
+
` ${temp[1] || ''}`
|
|
161
|
+
);
|
|
155
162
|
}
|
|
156
163
|
return value;
|
|
157
164
|
};
|
|
@@ -168,6 +175,16 @@ export const PIN_MODE_MAPPING = {
|
|
|
168
175
|
};
|
|
169
176
|
|
|
170
177
|
export const PIN_MAPPING = {
|
|
178
|
+
esp8266: {
|
|
179
|
+
read: {
|
|
180
|
+
boolean: ESP8266_DIGITAL,
|
|
181
|
+
integer: ESP8266_ANALOG_READ,
|
|
182
|
+
},
|
|
183
|
+
write: {
|
|
184
|
+
boolean: ESP8266_DIGITAL,
|
|
185
|
+
integer: ESP8266_ANALOG_WRITE,
|
|
186
|
+
},
|
|
187
|
+
},
|
|
171
188
|
esp32: {
|
|
172
189
|
read: {
|
|
173
190
|
boolean: ESP32_DIGITAL,
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
ToastBottomHelper,
|
|
20
20
|
objectIds,
|
|
21
21
|
notImplemented,
|
|
22
|
+
roundNumber,
|
|
22
23
|
} from '../Utils';
|
|
23
24
|
|
|
24
25
|
describe('Test utils', () => {
|
|
@@ -50,6 +51,9 @@ describe('Test utils', () => {
|
|
|
50
51
|
it('test setAxiosDefaultLanguage', () => {
|
|
51
52
|
setAxiosDefaultLanguage('en');
|
|
52
53
|
expect(api.headers['Accept-Language']).toBe('en');
|
|
54
|
+
|
|
55
|
+
setAxiosDefaultLanguage();
|
|
56
|
+
expect(api.headers['Accept-Language']).toBe('vi');
|
|
53
57
|
});
|
|
54
58
|
|
|
55
59
|
it('test setAxiosDefaultAuthToken', () => {
|
|
@@ -134,6 +138,7 @@ describe('Test utils', () => {
|
|
|
134
138
|
configIds: [],
|
|
135
139
|
});
|
|
136
140
|
});
|
|
141
|
+
|
|
137
142
|
it('test objectIds with devices', async () => {
|
|
138
143
|
const data = await objectIds([
|
|
139
144
|
{
|
|
@@ -166,4 +171,14 @@ describe('Test utils', () => {
|
|
|
166
171
|
});
|
|
167
172
|
expect(mockTranslate).toBeCalledWith('feature_under_development');
|
|
168
173
|
});
|
|
174
|
+
|
|
175
|
+
it('Test roundNumber', async () => {
|
|
176
|
+
let result;
|
|
177
|
+
result = await roundNumber('NaN kwh');
|
|
178
|
+
expect(result).toBe('0 kwh');
|
|
179
|
+
result = await roundNumber('123.123 kwh');
|
|
180
|
+
expect(result).toBe('123.12 kwh');
|
|
181
|
+
result = await roundNumber(12.12);
|
|
182
|
+
expect(result).toBe(12.12);
|
|
183
|
+
});
|
|
169
184
|
});
|