@eohjsc/react-native-smart-city 0.2.96 → 0.2.99
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/README.md +35 -14
- package/package.json +16 -4
- package/src/commons/Action/ItemQuickAction.js +5 -2
- package/src/commons/ActionGroup/ColorPickerTemplate.js +1 -1
- package/src/commons/ActionGroup/NumberUpDownActionTemplate.js +12 -4
- package/src/commons/ActionGroup/OnOffSmartLock/OnOffSmartLock.js +7 -4
- package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/index.js +1 -0
- package/src/commons/ActionGroup/OnOffTemplate/OnOffSimpleTemplate.js +10 -10
- package/src/commons/ActionGroup/OnOffTemplate/index.js +18 -15
- package/src/commons/ActionGroup/OptionsDropdownActionTemplate.js +8 -2
- package/src/commons/ActionGroup/SliderRangeTemplate.js +1 -1
- package/src/commons/ActionGroup/SmartTiviActionTemplate/SmartTiviActionTemplate.js +4 -1
- package/src/commons/ActionGroup/StatesGridActionTemplate.js +14 -4
- package/src/commons/ActionGroup/TimerActionTemplate.js +9 -1
- package/src/commons/ActionGroup/TwoButtonTemplate/index.js +13 -9
- package/src/commons/ActionGroup/__test__/OnOffButtonTemplate.test.js +14 -14
- package/src/commons/ActionGroup/__test__/OnOffTemplate.test.js +53 -78
- package/src/commons/ActionGroup/__test__/OneBigButtonTemplate.test.js +36 -20
- package/src/commons/Auth/AccountList.js +1 -1
- package/src/commons/{Connecting → Connecting}/__test__/Connecting.test.js +0 -0
- package/src/commons/{Connecting → Connecting}/index.js +0 -0
- package/src/commons/{Connecting → Connecting}/styles.js +0 -0
- package/src/commons/ConnectingProcess/index.js +1 -1
- package/src/commons/Device/HistoryChart.js +6 -2
- package/src/commons/Device/PMSensor/PMSensorIndicatior.js +16 -12
- package/src/commons/Device/PMSensor/PMSensorIndicatorStyles.js +3 -0
- package/src/commons/Device/WaterQualitySensor/ListQualityIndicator.js +1 -0
- package/src/commons/FieldTemplate/ChooseUserField/ChooseFieldStyles.js +25 -0
- package/src/commons/FieldTemplate/ChooseUserField/ChoosePopup.js +96 -0
- package/src/commons/FieldTemplate/ChooseUserField/ChoosePopupStyles.js +39 -0
- package/src/commons/FieldTemplate/ChooseUserField/__test__/index.test.js +113 -0
- package/src/commons/FieldTemplate/ChooseUserField/index.js +62 -0
- package/src/commons/FieldTemplate/PasscodeField/PasscodeFieldStyles.js +30 -0
- package/src/commons/FieldTemplate/PasscodeField/__test__/index.test.js +93 -0
- package/src/commons/FieldTemplate/PasscodeField/index.js +43 -0
- package/src/commons/FieldTemplate/ScheduleField/ScheduleFieldStyles.js +13 -0
- package/src/commons/FieldTemplate/ScheduleField/__test__/index.test.js +182 -0
- package/src/commons/FieldTemplate/ScheduleField/index.js +176 -0
- package/src/commons/FullLoading/index.js +2 -1
- package/src/commons/MenuActionAddnew/index.js +1 -0
- package/src/commons/MenuActionList/index.js +1 -0
- package/src/commons/MenuActionMore/index.js +1 -1
- package/src/commons/PreventAccess/__test__/PreventAccess.test.js +62 -0
- package/src/commons/PreventAccess/index.js +67 -0
- package/src/commons/PreventAccess/styles.js +33 -0
- package/src/commons/WheelDateTimePicker/index.js +2 -1
- package/src/configs/API.js +3 -0
- package/src/configs/Constants.js +16 -1
- package/src/iot/RemoteControl/GoogleHome.js +24 -11
- package/src/iot/RemoteControl/__test__/GoogleHome.test.js +32 -0
- package/src/navigations/UnitStack.js +8 -0
- package/src/screens/AQIGuide/index.js +1 -1
- package/src/screens/ActivityLog/FilterPopup.js +2 -0
- package/src/screens/AddCommon/SelectSubUnit.js +1 -0
- package/src/screens/AddCommon/SelectUnit.js +1 -0
- package/src/screens/AddLocationMaps/index.js +4 -1
- package/src/screens/AddNewAction/SelectSensorDevices.js +14 -3
- package/src/screens/AddNewAction/__test__/SelectSensorDevices.test.js +34 -92
- package/src/screens/AddNewAutoSmart/__test__/AddNewAutoSmart.test.js +3 -1
- package/src/screens/AddNewAutoSmart/index.js +5 -2
- package/src/screens/AddNewDevice/index.js +1 -0
- package/src/screens/AddNewGateway/PlugAndPlay/ConnectWifiWarning.js +1 -1
- package/src/screens/AddNewGateway/PlugAndPlay/GatewayWifiList.js +4 -1
- package/src/screens/AddNewGateway/SelectGateway.js +1 -0
- package/src/screens/AddNewGateway/SetupGatewayWifi.js +1 -0
- package/src/screens/AddNewGateway/index.js +1 -0
- package/src/screens/AddNewOneTap/__test__/AddNewOneTap.test.js +1 -1
- package/src/screens/AddNewOneTap/index.js +3 -2
- package/src/screens/Automate/index.js +2 -0
- package/src/screens/Device/__test__/detail.test.js +4 -4
- package/src/screens/Device/detail.js +44 -6
- package/src/screens/EmergencyContacts/EmergencyContactsSelectContacts.js +5 -2
- package/src/screens/EmergencyContacts/__test__/EmergencyContactList.test.js +14 -0
- package/src/screens/EmergencyContacts/__test__/EmergencyContactsSelectContacts.test.js +19 -1
- package/src/screens/EmergencySetting/index.js +4 -1
- package/src/screens/Explore/index.js +2 -0
- package/src/screens/GuestInfo/__test__/index.test.js +1 -1
- package/src/screens/GuestInfo/components/RecurringDetail.js +1 -0
- package/src/screens/GuestInfo/components/TemporaryDetail.js +2 -2
- package/src/screens/ManageAccess/index.js +1 -0
- package/src/screens/MoveToAnotherSubUnit/index.js +1 -1
- package/src/screens/ScanChipQR/components/QRScan/index.js +1 -0
- package/src/screens/ScriptDetail/index.js +3 -3
- package/src/screens/SelectUnit/__test__/index.test.js +1 -1
- package/src/screens/SelectUnit/index.js +5 -2
- package/src/screens/SetSchedule/index.js +6 -2
- package/src/screens/SharedUnit/index.js +2 -0
- package/src/screens/Sharing/MemberList.js +12 -11
- package/src/screens/Sharing/SelectPermission.js +1 -1
- package/src/screens/Sharing/hooks/index.js +3 -0
- package/src/screens/SideMenuDetail/SideMenuDetailStyles.js +28 -0
- package/src/screens/SideMenuDetail/__test__/index.test.js +165 -0
- package/src/screens/SideMenuDetail/index.js +149 -0
- package/src/screens/SmartIr/components/SelectBrand.js +1 -1
- package/src/screens/SubUnit/ManageSubUnit.js +1 -0
- package/src/screens/SyncLGDevice/AddLGDevice.js +1 -0
- package/src/screens/TDSGuide/index.js +4 -1
- package/src/screens/UVIndexGuide/index.js +1 -1
- package/src/screens/Unit/Detail.js +18 -5
- package/src/screens/Unit/SelectAddress.js +4 -1
- package/src/screens/Unit/Station/index.js +1 -0
- package/src/screens/Unit/Summaries.js +1 -1
- package/src/screens/Unit/__test__/Detail.test.js +25 -5
- package/src/screens/UnitSummary/__test__/index.test.js +32 -0
- package/src/screens/UnitSummary/components/3PPowerConsumption/index.js +1 -1
- package/src/screens/WaterQualityGuide/index.js +1 -1
- package/src/utils/I18n/translations/en.json +5 -1
- package/src/utils/I18n/translations/vi.json +5 -1
- package/src/utils/Route/index.js +1 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import React, { memo, useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
import styles from './ScheduleFieldStyles';
|
|
4
|
+
import moment from 'moment';
|
|
5
|
+
|
|
6
|
+
import Text from '../../Text';
|
|
7
|
+
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
8
|
+
import AccessScheduleItem from '../../../screens/GuestInfo/components/AccessScheduleItem';
|
|
9
|
+
import RecurringDetail from '../../../screens/GuestInfo/components/RecurringDetail';
|
|
10
|
+
import TemporaryDetail from '../../../screens/GuestInfo/components/TemporaryDetail';
|
|
11
|
+
import { useBoolean } from '../../../hooks/Common';
|
|
12
|
+
import WheelDateTimePicker from '../../WheelDateTimePicker';
|
|
13
|
+
import { ACCESS_SCHEDULE } from '../../../screens/GuestInfo/constant';
|
|
14
|
+
|
|
15
|
+
const ScheduleField = ({ dataItem, index, setDataForm, dataForm }) => {
|
|
16
|
+
const t = useTranslations();
|
|
17
|
+
const [accessSchedule, setAccessSchedule] = useState('always');
|
|
18
|
+
const [lockShowing, releaseLockShowing, acquireLockShowing] =
|
|
19
|
+
useBoolean(true);
|
|
20
|
+
|
|
21
|
+
const [stateDateTimePicker, setStateDateTimePicker] = useState({
|
|
22
|
+
isVisible: false,
|
|
23
|
+
mode: 'time',
|
|
24
|
+
defaultValue: moment(),
|
|
25
|
+
setter: null,
|
|
26
|
+
});
|
|
27
|
+
const [recurringTimeStart, setRecurringTimeStart] = useState(moment());
|
|
28
|
+
const [recurringTimeEnd, setRecurringTimeEnd] = useState(
|
|
29
|
+
moment().add(1, 'hours')
|
|
30
|
+
);
|
|
31
|
+
const [recurringTimeRepeat, setRecurringTimeRepeat] = useState([]);
|
|
32
|
+
const [temporaryTimeStart, setTemporaryTimeStart] = useState(moment());
|
|
33
|
+
const [temporaryTimeEnd, setTemporaryTimeEnd] = useState(
|
|
34
|
+
moment().add(1, 'days')
|
|
35
|
+
);
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (accessSchedule === ACCESS_SCHEDULE.ALWAYS) {
|
|
38
|
+
dataItem.valid = true;
|
|
39
|
+
dataItem.data = {
|
|
40
|
+
access_schedule: accessSchedule,
|
|
41
|
+
};
|
|
42
|
+
} else if (accessSchedule === ACCESS_SCHEDULE.RECURRING) {
|
|
43
|
+
dataItem.valid = true;
|
|
44
|
+
dataItem.data = {
|
|
45
|
+
access_schedule: accessSchedule,
|
|
46
|
+
recurring_time_start: recurringTimeStart.format(),
|
|
47
|
+
recurring_time_end: recurringTimeEnd.format(),
|
|
48
|
+
recurring_time_repeat: recurringTimeRepeat,
|
|
49
|
+
};
|
|
50
|
+
} else if (accessSchedule === ACCESS_SCHEDULE.TEMPORARY) {
|
|
51
|
+
if (temporaryTimeStart > temporaryTimeEnd) {
|
|
52
|
+
dataItem.valid = false;
|
|
53
|
+
} else {
|
|
54
|
+
dataItem.valid = true;
|
|
55
|
+
dataItem.data = {
|
|
56
|
+
access_schedule: accessSchedule,
|
|
57
|
+
temporary_time_start: temporaryTimeStart.format(),
|
|
58
|
+
temporary_time_end: temporaryTimeEnd.format(),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
dataItem[dataItem.action.type] = dataItem.action.id[accessSchedule];
|
|
63
|
+
dataForm[index] = dataItem;
|
|
64
|
+
setDataForm([...dataForm]);
|
|
65
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
66
|
+
}, [
|
|
67
|
+
accessSchedule,
|
|
68
|
+
recurringTimeEnd,
|
|
69
|
+
recurringTimeRepeat,
|
|
70
|
+
recurringTimeStart,
|
|
71
|
+
temporaryTimeEnd,
|
|
72
|
+
temporaryTimeStart,
|
|
73
|
+
]);
|
|
74
|
+
const onShowSetDateTime = useCallback(
|
|
75
|
+
(currentValue, setter, mode) => {
|
|
76
|
+
releaseLockShowing();
|
|
77
|
+
setStateDateTimePicker((state) => ({
|
|
78
|
+
...state,
|
|
79
|
+
isVisible: true,
|
|
80
|
+
mode: mode,
|
|
81
|
+
defaultValue: currentValue,
|
|
82
|
+
setter: setter,
|
|
83
|
+
}));
|
|
84
|
+
},
|
|
85
|
+
[releaseLockShowing]
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
const onHideSetDateTime = useCallback(() => {
|
|
89
|
+
acquireLockShowing();
|
|
90
|
+
setStateDateTimePicker((state) => ({
|
|
91
|
+
...state,
|
|
92
|
+
isVisible: false,
|
|
93
|
+
}));
|
|
94
|
+
}, [setStateDateTimePicker, acquireLockShowing]);
|
|
95
|
+
|
|
96
|
+
const onDateTimePicked = useCallback(
|
|
97
|
+
(timeData) => {
|
|
98
|
+
const setter = stateDateTimePicker.setter;
|
|
99
|
+
setter && setter(moment(timeData));
|
|
100
|
+
},
|
|
101
|
+
[stateDateTimePicker]
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
const listAccessSchedule = useMemo(
|
|
105
|
+
() => [
|
|
106
|
+
{
|
|
107
|
+
text: t(`${ACCESS_SCHEDULE.ALWAYS}`),
|
|
108
|
+
value: ACCESS_SCHEDULE.ALWAYS,
|
|
109
|
+
detail: () => <></>,
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
text: t(`${ACCESS_SCHEDULE.RECURRING}`),
|
|
113
|
+
value: ACCESS_SCHEDULE.RECURRING,
|
|
114
|
+
detail: () => (
|
|
115
|
+
<RecurringDetail
|
|
116
|
+
onShowSetDateTime={onShowSetDateTime}
|
|
117
|
+
recurringTimeStart={recurringTimeStart}
|
|
118
|
+
recurringTimeEnd={recurringTimeEnd}
|
|
119
|
+
recurringTimeRepeat={recurringTimeRepeat}
|
|
120
|
+
setRecurringTimeStart={setRecurringTimeStart}
|
|
121
|
+
setRecurringTimeEnd={setRecurringTimeEnd}
|
|
122
|
+
setRecurringTimeRepeat={setRecurringTimeRepeat}
|
|
123
|
+
/>
|
|
124
|
+
),
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
text: t(`${ACCESS_SCHEDULE.TEMPORARY}`),
|
|
128
|
+
value: ACCESS_SCHEDULE.TEMPORARY,
|
|
129
|
+
detail: () => (
|
|
130
|
+
<TemporaryDetail
|
|
131
|
+
onShowSetDateTime={onShowSetDateTime}
|
|
132
|
+
temporaryTimeStart={temporaryTimeStart}
|
|
133
|
+
temporaryTimeEnd={temporaryTimeEnd}
|
|
134
|
+
setTemporaryTimeStart={setTemporaryTimeStart}
|
|
135
|
+
setTemporaryTimeEnd={setTemporaryTimeEnd}
|
|
136
|
+
/>
|
|
137
|
+
),
|
|
138
|
+
},
|
|
139
|
+
],
|
|
140
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
141
|
+
[
|
|
142
|
+
onShowSetDateTime,
|
|
143
|
+
recurringTimeEnd,
|
|
144
|
+
recurringTimeRepeat,
|
|
145
|
+
recurringTimeStart,
|
|
146
|
+
temporaryTimeEnd,
|
|
147
|
+
temporaryTimeStart,
|
|
148
|
+
]
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
return (
|
|
152
|
+
<View style={styles.wrapper}>
|
|
153
|
+
<Text style={styles.textHeadLine}>{t('access_schedule')}</Text>
|
|
154
|
+
|
|
155
|
+
{listAccessSchedule.map((item, index) => (
|
|
156
|
+
<AccessScheduleItem
|
|
157
|
+
key={index}
|
|
158
|
+
item={item}
|
|
159
|
+
isSelected={item.value === accessSchedule}
|
|
160
|
+
onSelect={setAccessSchedule}
|
|
161
|
+
isSetupGeneratePasscode
|
|
162
|
+
/>
|
|
163
|
+
))}
|
|
164
|
+
<WheelDateTimePicker
|
|
165
|
+
mode={stateDateTimePicker.mode}
|
|
166
|
+
isVisible={stateDateTimePicker.isVisible && lockShowing}
|
|
167
|
+
defaultValue={stateDateTimePicker.defaultValue}
|
|
168
|
+
onPicked={onDateTimePicked}
|
|
169
|
+
onCancel={onHideSetDateTime}
|
|
170
|
+
onHide={releaseLockShowing}
|
|
171
|
+
/>
|
|
172
|
+
</View>
|
|
173
|
+
);
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
export default memo(ScheduleField);
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { create } from 'react-test-renderer';
|
|
3
|
+
import { act } from 'react-test-renderer';
|
|
4
|
+
import PreventAccess from '..';
|
|
5
|
+
import { TESTID } from '../../../configs/Constants';
|
|
6
|
+
import { SCProvider } from '../../../context';
|
|
7
|
+
import { mockSCStore } from '../../../context/mockStore';
|
|
8
|
+
import Text from '../../Text';
|
|
9
|
+
|
|
10
|
+
const mockGoBack = jest.fn();
|
|
11
|
+
|
|
12
|
+
const wrapComponent = (headerBodyText, visible, hidePreventAccess) => (
|
|
13
|
+
<SCProvider initState={mockSCStore({})}>
|
|
14
|
+
<PreventAccess
|
|
15
|
+
headerBodyText={headerBodyText}
|
|
16
|
+
visible={visible}
|
|
17
|
+
hidePreventAccess={hidePreventAccess}
|
|
18
|
+
/>
|
|
19
|
+
</SCProvider>
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
jest.mock('@react-navigation/native', () => {
|
|
23
|
+
return {
|
|
24
|
+
...jest.requireActual('@react-navigation/native'),
|
|
25
|
+
useRoute: jest.fn(),
|
|
26
|
+
useNavigation: () => ({
|
|
27
|
+
goBack: mockGoBack,
|
|
28
|
+
}),
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe('Test PreventAccess.test', () => {
|
|
33
|
+
let tree;
|
|
34
|
+
let headerBodyText;
|
|
35
|
+
let visible;
|
|
36
|
+
let hidePreventAccess = () => {};
|
|
37
|
+
|
|
38
|
+
test('onItemClick MenuActionList', () => {
|
|
39
|
+
act(() => {
|
|
40
|
+
tree = create(wrapComponent(headerBodyText, visible, hidePreventAccess));
|
|
41
|
+
});
|
|
42
|
+
const instance = tree.root;
|
|
43
|
+
const text = instance.findAllByType(Text);
|
|
44
|
+
expect(text).toHaveLength(5);
|
|
45
|
+
const button1 = instance.find(
|
|
46
|
+
(el) => el.props.testID === TESTID.BUTTON_PREVENT_ACCESS
|
|
47
|
+
);
|
|
48
|
+
const button2 = instance.find(
|
|
49
|
+
(el) => el.props.testID === TESTID.TEXT_PREVENT_ACCESS
|
|
50
|
+
);
|
|
51
|
+
act(() => {
|
|
52
|
+
button1.props.onBackButtonPress();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
act(() => {
|
|
56
|
+
button2.props.onPress();
|
|
57
|
+
});
|
|
58
|
+
expect(button1).toBeDefined();
|
|
59
|
+
expect(button2).toBeDefined();
|
|
60
|
+
expect(mockGoBack).toHaveBeenCalled();
|
|
61
|
+
});
|
|
62
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import React, { memo, useCallback, useMemo } from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
import Modal from 'react-native-modal';
|
|
4
|
+
import { useNavigation } from '@react-navigation/native';
|
|
5
|
+
|
|
6
|
+
import t from '../../hooks/Common/useTranslations';
|
|
7
|
+
import Text from '../Text';
|
|
8
|
+
import { Colors } from '../../configs';
|
|
9
|
+
import { styles } from './styles';
|
|
10
|
+
import { TESTID } from '../../configs/Constants';
|
|
11
|
+
|
|
12
|
+
const PreventAccess = memo(({ headerBodyText, visible, hidePreventAccess }) => {
|
|
13
|
+
const { goBack } = useNavigation();
|
|
14
|
+
|
|
15
|
+
const dataText = useMemo(() => {
|
|
16
|
+
return {
|
|
17
|
+
headerText: t('note'),
|
|
18
|
+
bodyText: t('This {name} was removed!', {
|
|
19
|
+
name: headerBodyText ? headerBodyText : '',
|
|
20
|
+
}),
|
|
21
|
+
endOfText: t('back'),
|
|
22
|
+
};
|
|
23
|
+
}, [headerBodyText]);
|
|
24
|
+
|
|
25
|
+
const handleBackPress = useCallback(() => {
|
|
26
|
+
hidePreventAccess();
|
|
27
|
+
goBack();
|
|
28
|
+
}, [goBack, hidePreventAccess]);
|
|
29
|
+
|
|
30
|
+
const handleDonePopup = useCallback(() => {
|
|
31
|
+
goBack();
|
|
32
|
+
hidePreventAccess();
|
|
33
|
+
}, [goBack, hidePreventAccess]);
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<Modal
|
|
37
|
+
isVisible={visible}
|
|
38
|
+
transparent={true}
|
|
39
|
+
onBackButtonPress={handleBackPress}
|
|
40
|
+
style={styles.container}
|
|
41
|
+
testID={TESTID.BUTTON_PREVENT_ACCESS}
|
|
42
|
+
>
|
|
43
|
+
<View style={styles.popoverStyle}>
|
|
44
|
+
<View style={styles.actionTextWrap}>
|
|
45
|
+
<Text size={17} bold color={Colors.Gray9} style={styles.textHeader}>
|
|
46
|
+
{dataText?.headerText}
|
|
47
|
+
</Text>
|
|
48
|
+
<Text type="H4" color={Colors.Gray8} style={styles.textNotification}>
|
|
49
|
+
{dataText?.bodyText}
|
|
50
|
+
</Text>
|
|
51
|
+
</View>
|
|
52
|
+
<View style={styles.endOfText}>
|
|
53
|
+
<Text
|
|
54
|
+
testID={TESTID.TEXT_PREVENT_ACCESS}
|
|
55
|
+
size={16}
|
|
56
|
+
bold
|
|
57
|
+
color={Colors.Primary}
|
|
58
|
+
onPress={handleDonePopup}
|
|
59
|
+
>
|
|
60
|
+
{dataText?.endOfText}
|
|
61
|
+
</Text>
|
|
62
|
+
</View>
|
|
63
|
+
</View>
|
|
64
|
+
</Modal>
|
|
65
|
+
);
|
|
66
|
+
});
|
|
67
|
+
export default PreventAccess;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { StyleSheet } from 'react-native';
|
|
2
|
+
|
|
3
|
+
import { Colors } from '../../configs';
|
|
4
|
+
|
|
5
|
+
export const styles = StyleSheet.create({
|
|
6
|
+
container: {
|
|
7
|
+
flex: 1,
|
|
8
|
+
},
|
|
9
|
+
popoverStyle: {
|
|
10
|
+
flex: 1,
|
|
11
|
+
width: '100%',
|
|
12
|
+
backgroundColor: Colors.White,
|
|
13
|
+
position: 'absolute',
|
|
14
|
+
borderRadius: 10,
|
|
15
|
+
},
|
|
16
|
+
actionTextWrap: {
|
|
17
|
+
marginTop: 14,
|
|
18
|
+
marginHorizontal: 20,
|
|
19
|
+
},
|
|
20
|
+
textHeader: {
|
|
21
|
+
marginVertical: 10,
|
|
22
|
+
},
|
|
23
|
+
textNotification: {
|
|
24
|
+
lineHeight: 20,
|
|
25
|
+
},
|
|
26
|
+
endOfText: {
|
|
27
|
+
flexDirection: 'row',
|
|
28
|
+
justifyContent: 'flex-end',
|
|
29
|
+
marginTop: 5,
|
|
30
|
+
marginBottom: 20,
|
|
31
|
+
marginRight: 20,
|
|
32
|
+
},
|
|
33
|
+
});
|
|
@@ -104,6 +104,7 @@ const WheelDateTimePicker = ({
|
|
|
104
104
|
|
|
105
105
|
return (
|
|
106
106
|
<BottomSheet
|
|
107
|
+
testID={TESTID.WHEEL_DATE_TIME_PICKER}
|
|
107
108
|
isVisible={isVisible}
|
|
108
109
|
onBackdropPress={onPickerCancel}
|
|
109
110
|
onHide={onHide}
|
|
@@ -173,7 +174,7 @@ const WheelDateTimePicker = ({
|
|
|
173
174
|
onLeftClick={onPickerCancel}
|
|
174
175
|
rightTitle={t('done')}
|
|
175
176
|
onRightClick={onDone}
|
|
176
|
-
testIDPrefix={TESTID.
|
|
177
|
+
testIDPrefix={TESTID.WHEEL_DATE_TIME_PICKER_BUTTON}
|
|
177
178
|
/>
|
|
178
179
|
</BottomSheet>
|
|
179
180
|
);
|
package/src/configs/API.js
CHANGED
|
@@ -65,6 +65,9 @@ const API = {
|
|
|
65
65
|
SCConfig.apiRoot + `/property_manager/sensors/${id}/`,
|
|
66
66
|
DISPLAY: (id) =>
|
|
67
67
|
SCConfig.apiRoot + `/property_manager/sensors/${id}/display/`,
|
|
68
|
+
SIDE_MENU_DETAIL: (id, side_menu_id) =>
|
|
69
|
+
SCConfig.apiRoot +
|
|
70
|
+
`/property_manager/sensors/${id}/display/side_menu/${side_menu_id}/`,
|
|
68
71
|
DISPLAY_VALUES: (id) =>
|
|
69
72
|
SCConfig.apiRoot + `/property_manager/sensors/${id}/display_values/`,
|
|
70
73
|
DISPLAY_VALUES_V2: (id) =>
|
package/src/configs/Constants.js
CHANGED
|
@@ -674,13 +674,16 @@ export const TESTID = {
|
|
|
674
674
|
|
|
675
675
|
// WheelDateTimePicker
|
|
676
676
|
WHEEL_DATE_TIME_PICKER: 'WHEEL_DATE_TIME_PICKER',
|
|
677
|
+
WHEEL_DATE_TIME_PICKER_BUTTON: 'WHEEL_DATE_TIME_PICKER_BUTTON',
|
|
677
678
|
|
|
678
679
|
// GuestInfo
|
|
679
680
|
SAVE_ACCESS_SCHEDULE: 'SAVE_ACCESS_SCHEDULE',
|
|
680
681
|
ACCESS_SCHEDULE_RADIO_BUTTON: 'ACCESS_SCHEDULE_RADIO_BUTTON',
|
|
681
682
|
ACCESS_SCHEDULE_SHEET: 'ACCESS_SCHEDULE_SHEET',
|
|
682
683
|
RECURRING_TEXT_BUTTON: 'RECURRING_TEXT_BUTTON',
|
|
683
|
-
|
|
684
|
+
RECURRING_REPEAT_ITEM: 'RECURRING_REPEAT_ITEM',
|
|
685
|
+
TEMPORARY_START_TEXT_BUTTON: 'TEMPORARY_START_TEXT_BUTTON',
|
|
686
|
+
TEMPORARY_END_TEXT_BUTTON: 'TEMPORARY_END_TEXT_BUTTON',
|
|
684
687
|
|
|
685
688
|
// ActivityLog
|
|
686
689
|
FILTER_BUTTON: 'FILTER_BUTTON',
|
|
@@ -722,6 +725,18 @@ export const TESTID = {
|
|
|
722
725
|
AUTO_LOCK_BUTTON_ENABLE: 'AUTO_LOCK_BUTTON_ENABLE',
|
|
723
726
|
AUTO_LOCK_BUTTON_INSTANT: 'AUTO_LOCK_BUTTON_INSTANT',
|
|
724
727
|
AUTO_LOCK_BUTTON_RELOCK_TIMING: 'AUTO_LOCK_BUTTON_RELOCK_TIMING',
|
|
728
|
+
|
|
729
|
+
//PreventAccess
|
|
730
|
+
BUTTON_PREVENT_ACCESS: 'BUTTON_PREVENT_ACCESS',
|
|
731
|
+
TEXT_PREVENT_ACCESS: 'TEXT_PREVENT_ACCESS',
|
|
732
|
+
|
|
733
|
+
//Template field
|
|
734
|
+
CHOOSE_FIELD: 'CHOOSE_FIELD',
|
|
735
|
+
CHOOSE_POPUP: 'CHOOSE_POPUP',
|
|
736
|
+
CHOOSE_ITEM: 'CHOOSE_ITEM',
|
|
737
|
+
|
|
738
|
+
PASSCODE_FIELD: 'PASSCODE_FIELD',
|
|
739
|
+
SUBMIT: 'SUBMIT',
|
|
725
740
|
};
|
|
726
741
|
|
|
727
742
|
export const NOTIFICATION_TYPES = {
|
|
@@ -201,8 +201,22 @@ function getServiceName(message) {
|
|
|
201
201
|
return serviceSplit.join('_');
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
+
async function sendCommandSingleAction(connection, ghAction, data) {
|
|
205
|
+
const { message } = ghAction || {};
|
|
206
|
+
const name = getServiceName(message);
|
|
207
|
+
|
|
208
|
+
if (name && data) {
|
|
209
|
+
message.service_data[name] = data;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
await connection.sendMessagePromise(message);
|
|
213
|
+
}
|
|
214
|
+
|
|
204
215
|
export async function sendCommandOverGoogleHome(sensor, action, data) {
|
|
205
|
-
if (
|
|
216
|
+
if (
|
|
217
|
+
!(action.googlehome_actions && action.googlehome_actions.length) &&
|
|
218
|
+
!action.googlehome_action
|
|
219
|
+
) {
|
|
206
220
|
return;
|
|
207
221
|
}
|
|
208
222
|
|
|
@@ -212,20 +226,19 @@ export async function sendCommandOverGoogleHome(sensor, action, data) {
|
|
|
212
226
|
return;
|
|
213
227
|
}
|
|
214
228
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
229
|
+
if (action.googlehome_actions) {
|
|
230
|
+
for (let i = 0; i < action.googlehome_actions.length; i++) {
|
|
231
|
+
await sendCommandSingleAction(
|
|
232
|
+
connection,
|
|
233
|
+
action.googlehome_actions[i],
|
|
234
|
+
data
|
|
235
|
+
);
|
|
222
236
|
}
|
|
223
|
-
|
|
224
|
-
await connection.
|
|
237
|
+
} else if (action.googlehome_action) {
|
|
238
|
+
await sendCommandSingleAction(connection, action.googlehome_action, data);
|
|
225
239
|
}
|
|
226
240
|
|
|
227
241
|
const { success } = await axiosPost(API.SENSOR.ACTIVITY_LOG(), {
|
|
228
|
-
sensor_id: sensor.id,
|
|
229
242
|
action_id: action.id,
|
|
230
243
|
message: 'Trigger by user action with google home',
|
|
231
244
|
});
|
|
@@ -75,6 +75,9 @@ describe('Remote Control Google Home', () => {
|
|
|
75
75
|
message: 'message',
|
|
76
76
|
},
|
|
77
77
|
],
|
|
78
|
+
googlehome_action: {
|
|
79
|
+
message: 'message',
|
|
80
|
+
},
|
|
78
81
|
};
|
|
79
82
|
|
|
80
83
|
const response = {
|
|
@@ -223,6 +226,35 @@ describe('Remote Control Google Home', () => {
|
|
|
223
226
|
});
|
|
224
227
|
});
|
|
225
228
|
|
|
229
|
+
it('Send command over google home action googlehome_action one to one', async () => {
|
|
230
|
+
action.googlehome_actions = null;
|
|
231
|
+
action.googlehome_action.message = {
|
|
232
|
+
type: 'call_service',
|
|
233
|
+
domain: 'climate',
|
|
234
|
+
service: 'set_temperature',
|
|
235
|
+
service_data: {
|
|
236
|
+
temperature: 0,
|
|
237
|
+
entity_id: 'climate.dqsmart_0108f6cdde',
|
|
238
|
+
},
|
|
239
|
+
id: 20,
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
axios.post.mockImplementation(async () => {
|
|
243
|
+
return response;
|
|
244
|
+
});
|
|
245
|
+
await googleHomeConnect(options);
|
|
246
|
+
await sendCommandOverGoogleHome(sensor, action, 19);
|
|
247
|
+
|
|
248
|
+
action.googlehome_action.message.service_data.temperature = 19;
|
|
249
|
+
expect(connection.sendMessagePromise).toBeCalledWith(
|
|
250
|
+
action.googlehome_action.message
|
|
251
|
+
);
|
|
252
|
+
expect(axios.post).toHaveBeenCalledWith(API.SENSOR.ACTIVITY_LOG(), {
|
|
253
|
+
action_id: 1,
|
|
254
|
+
message: 'Trigger by user action with google home',
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
|
|
226
258
|
it('Send command over google home that not connected', async () => {
|
|
227
259
|
await googleHomeConnect(options);
|
|
228
260
|
await sendCommandOverGoogleHome({ chip_id: 2 }, action);
|
|
@@ -55,6 +55,7 @@ import { HanetCameraStack } from './HanetCameraStack';
|
|
|
55
55
|
|
|
56
56
|
import { axiosGet } from '../utils/Apis/axios';
|
|
57
57
|
import { API } from '../configs';
|
|
58
|
+
import SideMenuDetail from '../screens/SideMenuDetail';
|
|
58
59
|
|
|
59
60
|
const Stack = createStackNavigator();
|
|
60
61
|
|
|
@@ -263,6 +264,13 @@ export const UnitStack = memo((props) => {
|
|
|
263
264
|
headerShown: false,
|
|
264
265
|
}}
|
|
265
266
|
/>
|
|
267
|
+
<Stack.Screen
|
|
268
|
+
name={Route.SideMenuDetail}
|
|
269
|
+
component={SideMenuDetail}
|
|
270
|
+
options={{
|
|
271
|
+
headerShown: false,
|
|
272
|
+
}}
|
|
273
|
+
/>
|
|
266
274
|
<Stack.Screen
|
|
267
275
|
name={Route.UnitMemberList}
|
|
268
276
|
component={SharingMemberList}
|
|
@@ -83,7 +83,7 @@ const AQIGuide = memo(() => {
|
|
|
83
83
|
|
|
84
84
|
return (
|
|
85
85
|
<SafeAreaView style={styles.container}>
|
|
86
|
-
<ScrollView style={styles.container}>
|
|
86
|
+
<ScrollView style={styles.container} scrollIndicatorInsets={{ right: 1 }}>
|
|
87
87
|
{titles.map((item, index) => {
|
|
88
88
|
const { title, des } = item;
|
|
89
89
|
return (
|
|
@@ -169,7 +169,10 @@ const AddLocationMaps = memo(() => {
|
|
|
169
169
|
</Text>
|
|
170
170
|
<View style={styles.searchLocation}>
|
|
171
171
|
<SearchBarLocation input={input} onTextInput={onTextInput} />
|
|
172
|
-
<ScrollView
|
|
172
|
+
<ScrollView
|
|
173
|
+
style={styles.searchData}
|
|
174
|
+
scrollIndicatorInsets={{ right: 1 }}
|
|
175
|
+
>
|
|
173
176
|
{searchData.map((item) => (
|
|
174
177
|
<RowLocation item={item} onPress={onPressRowLocation} />
|
|
175
178
|
))}
|