@eohjsc/react-native-smart-city 0.2.26 → 0.2.27
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/assets/images/Illustrations.svg +83 -0
- package/assets/images/{WeatherChange.svg → ValueChange.svg} +0 -0
- package/index.js +2 -0
- package/package.json +3 -1
- package/src/Images/Common/file.png +0 -0
- package/src/Images/Common/fullscreen.png +0 -0
- package/src/commons/ActionGroup/OnOffTemplate/index.js +5 -0
- package/src/commons/ActionGroup/__test__/NumberUpDownTemplate.test.js +294 -0
- package/src/commons/ActionGroup/__test__/NumberUpDownTemplateWithNullConfigValue.test.js +60 -0
- package/src/commons/AlertAction/__test__/AlertAction.test.js +6 -6
- package/src/commons/AlertAction/index.js +2 -0
- package/src/commons/Automate/ItemAutomate.js +7 -1
- package/src/commons/Automate/__test__/ItemAutomate.test.js +16 -0
- package/src/commons/Automate/__test__/ItemScriptAction.test.js +16 -0
- package/src/commons/BackDefault/__test__/BackDefault.test.js +21 -0
- package/src/commons/BottomScrollPicker/index.js +5 -1
- package/src/commons/BottomSheet/index.js +10 -5
- package/src/commons/ButtonPopup/__test__/__snapshots__/ButtonPopup.test.js.snap +2 -0
- package/src/commons/ButtonPopup/index.js +2 -0
- package/src/commons/Calendar/index.js +72 -0
- package/src/commons/Calendar/styles.js +11 -0
- package/src/commons/Device/ItemAddNew/index.js +2 -2
- package/src/commons/Explore/__test__/HeaderExplore.test.js +25 -0
- package/src/commons/Explore/__test__/LocationItem.test.js +31 -0
- package/src/commons/Header/HeaderCustom.js +7 -3
- package/src/commons/HeaderAni/index.js +31 -3
- package/src/commons/HorizontalPicker/index.js +134 -0
- package/src/commons/HorizontalPicker/styles.js +56 -0
- package/src/commons/Modal/__test__/ModalBottom.test.js +39 -0
- package/src/commons/RowItem/__test__/RowItem.test.js +16 -0
- package/src/commons/RowItem/index.js +61 -0
- package/src/commons/RowItem/styles.js +53 -0
- package/src/commons/Sharing/WrapHeaderScrollable.js +78 -74
- package/src/commons/SubUnit/OneTap/ItemOneTap.js +73 -69
- package/src/commons/SubUnit/OneTap/__test__/SubUnitAutomate.test.js +47 -1
- package/src/commons/SubUnit/OneTap/index.js +2 -2
- package/src/commons/Unit/__test__/SharedUnit.test.js +330 -0
- package/src/commons/WheelDateTimePicker/index.js +16 -8
- package/src/commons/index.js +2 -0
- package/src/configs/API.js +5 -1
- package/src/configs/Constants.js +18 -3
- package/src/configs/Theme.js +20 -0
- package/src/context/SCContext.tsx +2 -2
- package/src/context/mockStore.ts +3 -1
- package/src/hooks/Common/__test__/useStatusbar.test.js +28 -0
- package/src/navigations/AutomateStack.js +45 -0
- package/src/navigations/UnitStack.js +33 -14
- package/src/navigations/utils.js +8 -0
- package/src/screens/AddNewAction/Components/LoadingSelectAction.js +40 -0
- package/src/screens/AddNewAction/Components/index.js +3 -0
- package/src/screens/AddNewAction/SelectAction.js +147 -62
- package/src/screens/AddNewAction/{SelectDevice.js → SelectSensorDevices.js} +42 -12
- package/src/screens/AddNewAction/SetupSensor.js +221 -0
- package/src/screens/AddNewAction/Styles/SelectActionStyles.js +43 -5
- package/src/screens/AddNewAction/Styles/{SelectDeviceStyles.js → SelectSensorDevicesStyles.js} +0 -0
- package/src/screens/AddNewAction/Styles/SetupSensorStyles.js +76 -0
- package/src/screens/AddNewAction/__test__/SelectAction.test.js +0 -19
- package/src/screens/AddNewAction/__test__/{SelectDevice.test.js → SelectSensorDevices.test.js} +3 -3
- package/src/screens/AddNewAction/__test__/SetupSensor.test.js +125 -0
- package/src/screens/AddNewAutoSmart/__test__/AddNewAutoSmart.test.js +69 -12
- package/src/screens/AddNewAutoSmart/index.js +42 -14
- package/src/screens/AddNewOneTap/AddNewOneTapStyles.js +4 -3
- package/src/screens/AddNewOneTap/__test__/AddNewOneTap.test.js +1 -0
- package/src/screens/AddNewOneTap/index.js +7 -4
- package/src/screens/AllCamera/__test__/index.test.js +103 -0
- package/src/screens/Automate/Components/Loading.js +64 -0
- package/src/screens/Automate/Styles/indexStyles.js +64 -0
- package/src/screens/Automate/__test__/Loading.test.js +16 -0
- package/src/screens/Automate/__test__/index.test.js +93 -0
- package/src/screens/Automate/index.js +148 -0
- package/src/screens/Device/__test__/detail.test.js +64 -0
- package/src/screens/Device/detail.js +17 -7
- package/src/screens/EditActionsList/index.js +2 -2
- package/src/screens/GuestInfo/__test__/index.test.js +176 -0
- package/src/screens/GuestInfo/components/AccessScheduleItem.js +6 -1
- package/src/screens/GuestInfo/components/AccessScheduleSheet.js +26 -15
- package/src/screens/GuestInfo/components/HeaderGuestInfo.js +6 -1
- package/src/screens/GuestInfo/components/RecurringDetail.js +9 -2
- package/src/screens/GuestInfo/components/TemporaryDetail.js +9 -2
- package/src/screens/GuestInfo/constant.js +2 -2
- package/src/screens/GuestInfo/index.js +4 -5
- package/src/screens/PlayBackCamera/Timer.js +1 -1
- package/src/screens/ScriptDetail/Styles/indexStyles.js +14 -0
- package/src/screens/ScriptDetail/__test__/index.test.js +119 -0
- package/src/screens/ScriptDetail/hooks/index.js +55 -0
- package/src/screens/ScriptDetail/index.js +124 -23
- package/src/screens/SelectUnit/Styles/indexStyles.js +55 -0
- package/src/screens/SelectUnit/__test__/index.test.js +85 -0
- package/src/screens/SelectUnit/index.js +100 -0
- package/src/screens/SetSchedule/__test__/index.test.js +97 -0
- package/src/screens/SetSchedule/components/RepeatOptionsPopup.js +56 -0
- package/src/screens/SetSchedule/components/RowItem.js +27 -0
- package/src/screens/SetSchedule/components/SelectWeekday.js +65 -0
- package/src/screens/SetSchedule/index.js +139 -0
- package/src/screens/SetSchedule/styles/RepeatOptionsPopupStyles.js +22 -0
- package/src/screens/SetSchedule/styles/RowItemStyles.js +29 -0
- package/src/screens/SetSchedule/styles/SelectWeekdayStyles.js +26 -0
- package/src/screens/{AddNewScriptAction/AddNewScriptActionStyles.js → SetSchedule/styles/indexStyles.js} +6 -12
- package/src/screens/Sharing/__test__/MemberList.test.js +21 -28
- package/src/screens/SubUnit/EditSubUnit.js +274 -0
- package/src/screens/SubUnit/EditSubUnitStyles.js +119 -0
- package/src/screens/SubUnit/ManageSubUnit.js +112 -370
- package/src/screens/SubUnit/ManageSubUnitStyles.js +40 -0
- package/src/screens/SubUnit/__test__/EditSubUnit.test.js +427 -0
- package/src/screens/SubUnit/__test__/ManageSubUnit.test.js +42 -386
- package/src/screens/SubUnit/hooks/__test__/useManageSubUnit.test.js +85 -0
- package/src/screens/SubUnit/hooks/useManageSubUnit.js +35 -0
- package/src/screens/Unit/Detail.js +3 -2
- package/src/screens/Unit/ManageUnit.js +10 -0
- package/src/screens/Unit/components/SearchLocation/__test__/RowLocation.test.js +36 -0
- package/src/screens/Unit/components/__test__/MyUnit.test.js +35 -0
- package/src/screens/Unit/components/__test__/MyUnitDevice.test.js +32 -0
- package/src/screens/UnitSummary/components/__test__/UnitSummary.test.js +67 -0
- package/src/screens/UnitSummary/components/__test__/index.test.js +48 -0
- package/src/screens/UnitSummary/components/index.js +1 -37
- package/src/screens/UnitSummary/components/indexstyles.js +39 -0
- package/src/utils/Apis/axios.js +0 -4
- package/src/utils/I18n/translations/en.json +30 -4
- package/src/utils/I18n/translations/vi.json +29 -3
- package/src/utils/Route/index.js +6 -1
- package/src/utils/__test__/InitData.test.js +20 -0
- package/src/commons/Automate/ItemAddNewScriptAction.js +0 -30
- package/src/screens/AddNewScriptAction/index.js +0 -100
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
import { act, create } from 'react-test-renderer';
|
|
4
|
+
import ItemScriptAction from '../ItemScriptAction';
|
|
5
|
+
|
|
6
|
+
describe('Test LocationItem', () => {
|
|
7
|
+
let tree;
|
|
8
|
+
it('Test render', async () => {
|
|
9
|
+
await act(() => {
|
|
10
|
+
tree = create(<ItemScriptAction item={{}} />);
|
|
11
|
+
});
|
|
12
|
+
const instance = tree.root;
|
|
13
|
+
const Views = instance.findAllByType(View);
|
|
14
|
+
expect(Views).toHaveLength(7);
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import renderer, { act } from 'react-test-renderer';
|
|
3
|
+
import { TouchableOpacity } from 'react-native';
|
|
4
|
+
import BackDefault from '../index';
|
|
5
|
+
|
|
6
|
+
describe('Test BackDefault', () => {
|
|
7
|
+
let tree;
|
|
8
|
+
test('create BackDefault', () => {
|
|
9
|
+
let goBack = () => {};
|
|
10
|
+
let color = { color: 'fff' };
|
|
11
|
+
let fixedHeight = { Height: 50 };
|
|
12
|
+
act(() => {
|
|
13
|
+
tree = renderer.create(
|
|
14
|
+
<BackDefault goBack={goBack} color={color} fixedHeight={fixedHeight} />
|
|
15
|
+
);
|
|
16
|
+
});
|
|
17
|
+
const instance = tree.root;
|
|
18
|
+
const buttons = instance.findAllByType(TouchableOpacity);
|
|
19
|
+
expect(buttons.length).toEqual(1);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -35,7 +35,11 @@ const BottomScrollPicker = ({ isVisible, onPicked, onHide, min, max }) => {
|
|
|
35
35
|
}, [number, onHide, onPicked]);
|
|
36
36
|
|
|
37
37
|
return (
|
|
38
|
-
<BottomSheet
|
|
38
|
+
<BottomSheet
|
|
39
|
+
isVisible={isVisible}
|
|
40
|
+
onBackdropPress={onCancel}
|
|
41
|
+
title={t('set_hour')}
|
|
42
|
+
>
|
|
39
43
|
<View style={styles.container}>
|
|
40
44
|
<Picker
|
|
41
45
|
dataSource={numberData}
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import React, { memo } from 'react';
|
|
2
2
|
import { View } from 'react-native';
|
|
3
3
|
import Modal from 'react-native-modal';
|
|
4
|
-
|
|
5
4
|
import Text from '../Text';
|
|
6
|
-
|
|
7
5
|
import styles from './styles';
|
|
8
6
|
|
|
9
|
-
const BottomSheet = ({
|
|
7
|
+
const BottomSheet = ({
|
|
8
|
+
isVisible,
|
|
9
|
+
onBackdropPress,
|
|
10
|
+
onHide,
|
|
11
|
+
title,
|
|
12
|
+
children,
|
|
13
|
+
}) => {
|
|
10
14
|
return (
|
|
11
15
|
<Modal
|
|
12
16
|
isVisible={isVisible}
|
|
13
|
-
onBackButtonPress={
|
|
14
|
-
onBackdropPress={
|
|
17
|
+
onBackButtonPress={onBackdropPress}
|
|
18
|
+
onBackdropPress={onBackdropPress}
|
|
19
|
+
onModalHide={onHide}
|
|
15
20
|
style={styles.modalContainer}
|
|
16
21
|
useNativeDriver={true}
|
|
17
22
|
useNativeDriverForBackdrop={true}
|
|
@@ -26,6 +26,7 @@ exports[`Test button popup create button popup 1`] = `
|
|
|
26
26
|
swipeThreshold={100}
|
|
27
27
|
testID="MODAL_BUTTON_POPUP"
|
|
28
28
|
transparent={true}
|
|
29
|
+
useNativeDriverForBackdrop={true}
|
|
29
30
|
visible={false}
|
|
30
31
|
>
|
|
31
32
|
<View
|
|
@@ -87,6 +88,7 @@ exports[`Test button popup create button popup 1`] = `
|
|
|
87
88
|
]
|
|
88
89
|
}
|
|
89
90
|
swipeThreshold={100}
|
|
91
|
+
useNativeDriverForBackdrop={true}
|
|
90
92
|
>
|
|
91
93
|
<View
|
|
92
94
|
style={
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import React, { useState, useCallback } from 'react';
|
|
2
|
+
import { Image } from 'react-native';
|
|
3
|
+
import { Calendar } from 'react-native-calendars';
|
|
4
|
+
import moment from 'moment';
|
|
5
|
+
import BottomSheet from '../BottomSheet';
|
|
6
|
+
import ViewButtonBottom from '../ViewButtonBottom';
|
|
7
|
+
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
8
|
+
import { Images, Colors } from '../../configs';
|
|
9
|
+
import styles from './styles';
|
|
10
|
+
|
|
11
|
+
export default ({
|
|
12
|
+
isVisible,
|
|
13
|
+
onHide,
|
|
14
|
+
onConfirm,
|
|
15
|
+
defaultDate = moment(),
|
|
16
|
+
minDate,
|
|
17
|
+
maxDate,
|
|
18
|
+
}) => {
|
|
19
|
+
const t = useTranslations();
|
|
20
|
+
const [dateSelected, setDateSelected] = useState(defaultDate);
|
|
21
|
+
|
|
22
|
+
const onDateSelected = useCallback(
|
|
23
|
+
(day) => {
|
|
24
|
+
setDateSelected(moment(day.timestamp));
|
|
25
|
+
},
|
|
26
|
+
[setDateSelected]
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const onCancel = useCallback(() => {
|
|
30
|
+
onHide && onHide();
|
|
31
|
+
}, [onHide]);
|
|
32
|
+
|
|
33
|
+
const onDone = useCallback(() => {
|
|
34
|
+
onConfirm && onConfirm(dateSelected);
|
|
35
|
+
onHide && onHide();
|
|
36
|
+
}, [onHide, onConfirm, dateSelected]);
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<BottomSheet isVisible={isVisible} onBackdropPress={onCancel}>
|
|
40
|
+
<Calendar
|
|
41
|
+
style={styles.calendar}
|
|
42
|
+
onDayPress={onDateSelected}
|
|
43
|
+
minDate={minDate?.format('YYYY-MM-DD')}
|
|
44
|
+
maxDate={maxDate?.format('YYYY-MM-DD')}
|
|
45
|
+
onMonthChange={(month) => {}}
|
|
46
|
+
onPressArrowLeft={(subtractMonth) => subtractMonth()}
|
|
47
|
+
onPressArrowRight={(addMonth) => addMonth()}
|
|
48
|
+
markedDates={{
|
|
49
|
+
[dateSelected.format('YYYY-MM-DD')]: {
|
|
50
|
+
selected: true,
|
|
51
|
+
disableTouchEvent: true,
|
|
52
|
+
selectedColor: Colors.Primary,
|
|
53
|
+
selectedTextColor: Colors.White,
|
|
54
|
+
},
|
|
55
|
+
}}
|
|
56
|
+
enableSwipeMonths={true}
|
|
57
|
+
renderArrow={(direction) => (
|
|
58
|
+
<Image
|
|
59
|
+
source={Images.arrowLeft}
|
|
60
|
+
style={direction !== 'left' && styles.arrowRight}
|
|
61
|
+
/>
|
|
62
|
+
)}
|
|
63
|
+
/>
|
|
64
|
+
<ViewButtonBottom
|
|
65
|
+
leftTitle={t('cancel')}
|
|
66
|
+
onLeftClick={onCancel}
|
|
67
|
+
rightTitle={t('done')}
|
|
68
|
+
onRightClick={onDone}
|
|
69
|
+
/>
|
|
70
|
+
</BottomSheet>
|
|
71
|
+
);
|
|
72
|
+
};
|
|
@@ -7,10 +7,10 @@ import { Colors } from '../../../configs';
|
|
|
7
7
|
import styles from './styles';
|
|
8
8
|
import { TESTID } from '../../../configs/Constants';
|
|
9
9
|
|
|
10
|
-
const ItemAddNew = memo(({ title, onAddNew }) => {
|
|
10
|
+
const ItemAddNew = memo(({ title, onAddNew, wrapStyle }) => {
|
|
11
11
|
return (
|
|
12
12
|
<TouchableWithoutFeedback onPress={onAddNew}>
|
|
13
|
-
<View style={styles.container}>
|
|
13
|
+
<View style={[styles.container, wrapStyle]}>
|
|
14
14
|
<View style={styles.boxIcon}>
|
|
15
15
|
<TouchableOpacity
|
|
16
16
|
style={styles.buttonPlus}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import renderer, { act } from 'react-test-renderer';
|
|
3
|
+
import Text from '../../../commons/Text';
|
|
4
|
+
import HeaderExplore from '../HeaderExplore';
|
|
5
|
+
import { SCProvider } from '../../../context';
|
|
6
|
+
import { mockSCStore } from '../../../context/mockStore';
|
|
7
|
+
|
|
8
|
+
const wrapComponent = () => (
|
|
9
|
+
<SCProvider initState={mockSCStore({})}>
|
|
10
|
+
<HeaderExplore />
|
|
11
|
+
</SCProvider>
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
describe('Test HeaderExplore', () => {
|
|
15
|
+
let tree;
|
|
16
|
+
|
|
17
|
+
test('render HeaderExplore', () => {
|
|
18
|
+
act(() => {
|
|
19
|
+
tree = renderer.create(wrapComponent());
|
|
20
|
+
});
|
|
21
|
+
const instance = tree.root;
|
|
22
|
+
const button = instance.findAllByType(Text);
|
|
23
|
+
expect(button.length).toBe(1);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import renderer, { act } from 'react-test-renderer';
|
|
3
|
+
import { TouchableOpacity } from 'react-native';
|
|
4
|
+
import LocationItem from '../LocationItem';
|
|
5
|
+
import { SCProvider } from '../../../context';
|
|
6
|
+
import { mockSCStore } from '../../../context/mockStore';
|
|
7
|
+
|
|
8
|
+
const wrapComponent = (item, mockFunc, margin) => (
|
|
9
|
+
<SCProvider initState={mockSCStore({})}>
|
|
10
|
+
<LocationItem item={item} onPress={mockFunc} margin={margin} />
|
|
11
|
+
</SCProvider>
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
let tree;
|
|
15
|
+
describe('Test LocationItem', () => {
|
|
16
|
+
test('render LocationItem', async () => {
|
|
17
|
+
const item = { background: '', name: '', address: '', distance: '' };
|
|
18
|
+
const margin = { marginLeft: 10 };
|
|
19
|
+
const mockFunc = jest.fn();
|
|
20
|
+
await act(() => {
|
|
21
|
+
tree = renderer.create(wrapComponent(item, mockFunc, margin));
|
|
22
|
+
});
|
|
23
|
+
const instance = tree.root;
|
|
24
|
+
const button = instance.findAllByType(TouchableOpacity);
|
|
25
|
+
expect(button.length).toEqual(1);
|
|
26
|
+
act(() => {
|
|
27
|
+
button[0].props.onPress();
|
|
28
|
+
});
|
|
29
|
+
expect(mockFunc).toBeCalledTimes(1);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { memo, useRef } from 'react';
|
|
1
|
+
import React, { memo, useCallback, useRef } from 'react';
|
|
2
2
|
import { View, Text, TouchableOpacity, Image } from 'react-native';
|
|
3
3
|
import Images from '../../configs/Images';
|
|
4
4
|
import { Colors } from '../../configs';
|
|
@@ -18,20 +18,24 @@ const HeaderCustom = ({
|
|
|
18
18
|
titleStyles,
|
|
19
19
|
isShowClose = false,
|
|
20
20
|
onGoBack,
|
|
21
|
+
onClose,
|
|
21
22
|
}) => {
|
|
22
23
|
const t = useTranslations();
|
|
23
24
|
const { goBack } = useNavigation();
|
|
24
25
|
const refMenuAction = useRef();
|
|
25
26
|
const refAddAction = useRef();
|
|
26
27
|
const handleAddAction = () => {};
|
|
27
|
-
// eslint-disable-next-line no-alert
|
|
28
|
-
const handleClose = () => alert(t('feature_under_development'));
|
|
29
28
|
const handleShowMenuAction = () => showPopoverWithRef(refMenuAction);
|
|
30
29
|
const handleGoback = () => {
|
|
31
30
|
onGoBack && onGoBack();
|
|
32
31
|
goBack();
|
|
33
32
|
};
|
|
34
33
|
|
|
34
|
+
const handleClose = useCallback(() => {
|
|
35
|
+
onClose ? onClose() : alert(t('feature_under_development'));
|
|
36
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
37
|
+
}, []);
|
|
38
|
+
|
|
35
39
|
return (
|
|
36
40
|
<View style={[styles.wrap, isShowSeparator && styles.separator]}>
|
|
37
41
|
<TouchableOpacity style={styles.buttonBack} onPress={handleGoback}>
|
|
@@ -13,7 +13,14 @@ export const title_height = 44;
|
|
|
13
13
|
export const heightHeader = default_height + title_height + paddingIos;
|
|
14
14
|
|
|
15
15
|
const HeaderAni = memo(
|
|
16
|
-
({
|
|
16
|
+
({
|
|
17
|
+
scrollY,
|
|
18
|
+
onLeft,
|
|
19
|
+
title,
|
|
20
|
+
rightComponent,
|
|
21
|
+
headerStyle,
|
|
22
|
+
headerAniCenterStyle,
|
|
23
|
+
}) => {
|
|
17
24
|
const { goBack } = useNavigation();
|
|
18
25
|
const onPressLeft = useCallback(() => {
|
|
19
26
|
if (onLeft) {
|
|
@@ -22,6 +29,9 @@ const HeaderAni = memo(
|
|
|
22
29
|
goBack();
|
|
23
30
|
}
|
|
24
31
|
}, [goBack, onLeft]);
|
|
32
|
+
|
|
33
|
+
const headerX = headerAniCenterStyle ? 75 : 16;
|
|
34
|
+
|
|
25
35
|
const titleTransformY = scrollY.interpolate({
|
|
26
36
|
inputRange: [0, 2 * title_height],
|
|
27
37
|
outputRange: [0, -title_height],
|
|
@@ -29,7 +39,7 @@ const HeaderAni = memo(
|
|
|
29
39
|
});
|
|
30
40
|
const titleTransformX = scrollY.interpolate({
|
|
31
41
|
inputRange: [0, 2 * title_height],
|
|
32
|
-
outputRange: [0,
|
|
42
|
+
outputRange: [0, headerX],
|
|
33
43
|
extrapolate: 'clamp',
|
|
34
44
|
});
|
|
35
45
|
const titleScale = scrollY.interpolate({
|
|
@@ -44,10 +54,17 @@ const HeaderAni = memo(
|
|
|
44
54
|
});
|
|
45
55
|
|
|
46
56
|
const titleMarginRight = rightComponent ? 80 : 0;
|
|
57
|
+
const checkHeaderAniCenterStyle = headerAniCenterStyle
|
|
58
|
+
? styles.containerNoneBorder
|
|
59
|
+
: styles.container;
|
|
47
60
|
|
|
48
61
|
return (
|
|
49
62
|
<Animated.View
|
|
50
|
-
style={[
|
|
63
|
+
style={[
|
|
64
|
+
checkHeaderAniCenterStyle,
|
|
65
|
+
headerStyle,
|
|
66
|
+
{ height: headerHeightAnim },
|
|
67
|
+
]}
|
|
51
68
|
>
|
|
52
69
|
<View style={styles.header}>
|
|
53
70
|
<TouchableOpacity style={styles.btnBack} onPress={onPressLeft}>
|
|
@@ -118,6 +135,17 @@ const styles = StyleSheet.create({
|
|
|
118
135
|
zIndex: 3,
|
|
119
136
|
paddingTop: paddingIos,
|
|
120
137
|
},
|
|
138
|
+
containerNoneBorder: {
|
|
139
|
+
backgroundColor: Colors.White,
|
|
140
|
+
width: '100%',
|
|
141
|
+
position: 'absolute',
|
|
142
|
+
top: 0,
|
|
143
|
+
left: 0,
|
|
144
|
+
right: 0,
|
|
145
|
+
height: 100,
|
|
146
|
+
zIndex: 3,
|
|
147
|
+
paddingTop: paddingIos,
|
|
148
|
+
},
|
|
121
149
|
content: {
|
|
122
150
|
position: 'absolute',
|
|
123
151
|
width: '100%',
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import React, { useEffect, useMemo, useRef, useState, memo } from 'react';
|
|
2
|
+
import { View, Animated } from 'react-native';
|
|
3
|
+
import { Constants, Colors } from '../../configs';
|
|
4
|
+
import Text from '../Text';
|
|
5
|
+
import styles from './styles';
|
|
6
|
+
|
|
7
|
+
let isCanChangeValue = false;
|
|
8
|
+
|
|
9
|
+
const HorizontalPicker = ({
|
|
10
|
+
width = Constants.width,
|
|
11
|
+
onChangeValue,
|
|
12
|
+
minimum = 0,
|
|
13
|
+
maximum = 100,
|
|
14
|
+
segmentSpacing = 20,
|
|
15
|
+
step = 10,
|
|
16
|
+
stepColor = Colors.Gray7,
|
|
17
|
+
stepHeight = 40,
|
|
18
|
+
stepWidth = 2,
|
|
19
|
+
normalColor = Colors.Gray7,
|
|
20
|
+
normalHeight = 20,
|
|
21
|
+
normalWidth = 2,
|
|
22
|
+
style,
|
|
23
|
+
value = 0,
|
|
24
|
+
}) => {
|
|
25
|
+
const scrollViewRef = useRef();
|
|
26
|
+
const [scrollX] = useState(new Animated.Value(0));
|
|
27
|
+
|
|
28
|
+
const spacerWidth = (width - stepWidth) / 2;
|
|
29
|
+
let time = useMemo(() => minimum, [minimum]);
|
|
30
|
+
|
|
31
|
+
const renderTime = useMemo(() => {
|
|
32
|
+
const data = [...Array(maximum - minimum + 1).keys()].map(
|
|
33
|
+
(i) => i + minimum
|
|
34
|
+
);
|
|
35
|
+
return (
|
|
36
|
+
<View style={[styles.wrap]}>
|
|
37
|
+
<View
|
|
38
|
+
style={{
|
|
39
|
+
width: spacerWidth,
|
|
40
|
+
}}
|
|
41
|
+
/>
|
|
42
|
+
{data.map((i, index) => {
|
|
43
|
+
const isStep = i % step === 0;
|
|
44
|
+
return (
|
|
45
|
+
<View key={index}>
|
|
46
|
+
<View
|
|
47
|
+
key={i}
|
|
48
|
+
// eslint-disable-next-line react-native/no-inline-styles
|
|
49
|
+
style={{
|
|
50
|
+
backgroundColor: isStep ? stepColor : normalColor,
|
|
51
|
+
height: isStep ? stepHeight : normalHeight,
|
|
52
|
+
width: isStep ? stepWidth : normalWidth,
|
|
53
|
+
borderRadius: isStep ? stepWidth / 2 : normalWidth / 2,
|
|
54
|
+
marginRight: i === maximum ? 0 : segmentSpacing,
|
|
55
|
+
}}
|
|
56
|
+
/>
|
|
57
|
+
{isStep && (
|
|
58
|
+
<Text
|
|
59
|
+
color={Colors.Gray7}
|
|
60
|
+
style={[styles.time, time < 10 && styles.time2]}
|
|
61
|
+
>
|
|
62
|
+
{time++}
|
|
63
|
+
</Text>
|
|
64
|
+
)}
|
|
65
|
+
</View>
|
|
66
|
+
);
|
|
67
|
+
})}
|
|
68
|
+
<View
|
|
69
|
+
style={{
|
|
70
|
+
width: (width - stepWidth) / 2,
|
|
71
|
+
}}
|
|
72
|
+
/>
|
|
73
|
+
</View>
|
|
74
|
+
);
|
|
75
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
76
|
+
}, [maximum, minimum, time]);
|
|
77
|
+
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
const scrollListener = scrollX.addListener(({ value }) => {
|
|
80
|
+
isCanChangeValue && onChangeValue && onChangeValue(value);
|
|
81
|
+
});
|
|
82
|
+
return () => scrollX.removeListener(scrollListener);
|
|
83
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
84
|
+
}, []);
|
|
85
|
+
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
if (!isCanChangeValue && scrollViewRef && scrollViewRef.current) {
|
|
88
|
+
const to1 = setTimeout(() => {
|
|
89
|
+
scrollViewRef.current.scrollTo({ x: value * 128 });
|
|
90
|
+
clearTimeout(to1);
|
|
91
|
+
}, 300);
|
|
92
|
+
const to2 = setTimeout(() => {
|
|
93
|
+
isCanChangeValue = true;
|
|
94
|
+
clearTimeout(to2);
|
|
95
|
+
}, 1000);
|
|
96
|
+
}
|
|
97
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
98
|
+
}, [value, isCanChangeValue, scrollViewRef]);
|
|
99
|
+
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
return () => (isCanChangeValue = false);
|
|
102
|
+
}, []);
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<View style={[styles.container, style]}>
|
|
106
|
+
<Animated.ScrollView
|
|
107
|
+
ref={scrollViewRef}
|
|
108
|
+
horizontal
|
|
109
|
+
contentContainerStyle={styles.contentContainerStyle}
|
|
110
|
+
bounces={false}
|
|
111
|
+
showsHorizontalScrollIndicator={false}
|
|
112
|
+
scrollEventThrottle={16}
|
|
113
|
+
onScroll={Animated.event(
|
|
114
|
+
[
|
|
115
|
+
{
|
|
116
|
+
nativeEvent: {
|
|
117
|
+
contentOffset: { x: scrollX },
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
],
|
|
121
|
+
{ useNativeDriver: true }
|
|
122
|
+
)}
|
|
123
|
+
>
|
|
124
|
+
{renderTime}
|
|
125
|
+
</Animated.ScrollView>
|
|
126
|
+
|
|
127
|
+
<View style={[styles.indicator]} pointerEvents="none">
|
|
128
|
+
<View style={styles.childIndicator} />
|
|
129
|
+
</View>
|
|
130
|
+
</View>
|
|
131
|
+
);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
export default memo(HorizontalPicker);
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { StyleSheet } from 'react-native';
|
|
2
|
+
import { Colors } from '../../configs';
|
|
3
|
+
|
|
4
|
+
export default StyleSheet.create({
|
|
5
|
+
contentContainerStyle: {
|
|
6
|
+
justifyContent: 'flex-end',
|
|
7
|
+
},
|
|
8
|
+
wrap: {
|
|
9
|
+
flexDirection: 'row',
|
|
10
|
+
alignItems: 'center',
|
|
11
|
+
},
|
|
12
|
+
time: {
|
|
13
|
+
position: 'absolute',
|
|
14
|
+
top: 20,
|
|
15
|
+
width: 50,
|
|
16
|
+
fontSize: 10,
|
|
17
|
+
marginLeft: 1,
|
|
18
|
+
},
|
|
19
|
+
time2: {
|
|
20
|
+
left: 2,
|
|
21
|
+
},
|
|
22
|
+
indicator: {
|
|
23
|
+
justifyContent: 'center',
|
|
24
|
+
alignItems: 'center',
|
|
25
|
+
position: 'absolute',
|
|
26
|
+
width: '100%',
|
|
27
|
+
height: '100%',
|
|
28
|
+
},
|
|
29
|
+
step: {
|
|
30
|
+
width: 12,
|
|
31
|
+
height: 12,
|
|
32
|
+
borderRadius: 6,
|
|
33
|
+
},
|
|
34
|
+
normal: {
|
|
35
|
+
width: 4,
|
|
36
|
+
height: 4,
|
|
37
|
+
borderRadius: 2,
|
|
38
|
+
marginTop: 4,
|
|
39
|
+
},
|
|
40
|
+
container: {
|
|
41
|
+
height: 80,
|
|
42
|
+
marginTop: 80,
|
|
43
|
+
},
|
|
44
|
+
childrenIndicator: {
|
|
45
|
+
width: 12,
|
|
46
|
+
height: 80,
|
|
47
|
+
borderRadius: 8,
|
|
48
|
+
backgroundColor: Colors.Primary,
|
|
49
|
+
},
|
|
50
|
+
childIndicator: {
|
|
51
|
+
width: 12,
|
|
52
|
+
height: 80,
|
|
53
|
+
backgroundColor: Colors.Primary,
|
|
54
|
+
borderRadius: 8,
|
|
55
|
+
},
|
|
56
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { View } from 'react-native';
|
|
3
|
+
import { create } from 'react-test-renderer';
|
|
4
|
+
import { act } from 'react-test-renderer';
|
|
5
|
+
import { ModalBottom } from '../';
|
|
6
|
+
import { SCProvider } from '../../../context';
|
|
7
|
+
import { mockSCStore } from '../../../context/mockStore';
|
|
8
|
+
|
|
9
|
+
const wrapComponent = (isVisible) => (
|
|
10
|
+
<SCProvider initState={mockSCStore({})}>
|
|
11
|
+
<ModalBottom isVisible={isVisible} />
|
|
12
|
+
</SCProvider>
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
describe('Test ModalBottom', () => {
|
|
16
|
+
let tree;
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
jest.useFakeTimers();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('Test render with isVisible', async () => {
|
|
23
|
+
await act(() => {
|
|
24
|
+
tree = create(wrapComponent(true));
|
|
25
|
+
});
|
|
26
|
+
const instance = tree.root;
|
|
27
|
+
const Views = instance.findAllByType(View);
|
|
28
|
+
expect(Views).toHaveLength(5);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('Test render without isVisible', async () => {
|
|
32
|
+
await act(() => {
|
|
33
|
+
tree = create(wrapComponent());
|
|
34
|
+
});
|
|
35
|
+
const instance = tree.root;
|
|
36
|
+
const Views = instance.findAllByType(View);
|
|
37
|
+
expect(Views).toHaveLength(5);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import renderer, { act } from 'react-test-renderer';
|
|
3
|
+
import { TouchableOpacity } from 'react-native';
|
|
4
|
+
import { RowItem } from '../index';
|
|
5
|
+
|
|
6
|
+
describe('Test RowUser', () => {
|
|
7
|
+
let tree;
|
|
8
|
+
test('create RowUser', () => {
|
|
9
|
+
act(() => {
|
|
10
|
+
tree = renderer.create(<RowItem text="Text" type="primary" />);
|
|
11
|
+
});
|
|
12
|
+
const instance = tree.root;
|
|
13
|
+
const buttons = instance.findAllByType(TouchableOpacity);
|
|
14
|
+
expect(buttons.length).toEqual(1);
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import React, { memo } from 'react';
|
|
2
|
+
import { TouchableOpacity, View } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { Colors } from '../../configs';
|
|
5
|
+
import Text from '../Text';
|
|
6
|
+
import styles from './styles';
|
|
7
|
+
import { CircleView } from '../CircleView';
|
|
8
|
+
|
|
9
|
+
const arrColor = [
|
|
10
|
+
Colors.GeekBlue3,
|
|
11
|
+
Colors.Purple3,
|
|
12
|
+
Colors.Orange3,
|
|
13
|
+
Colors.Volcano3,
|
|
14
|
+
Colors.Blue9,
|
|
15
|
+
Colors.Green3,
|
|
16
|
+
Colors.Cyan2,
|
|
17
|
+
];
|
|
18
|
+
export const RowItem = memo(
|
|
19
|
+
({
|
|
20
|
+
index = 0,
|
|
21
|
+
type, //primary | disable | undefined
|
|
22
|
+
leftIcon,
|
|
23
|
+
text,
|
|
24
|
+
subtext,
|
|
25
|
+
subtextColor = Colors.Gray6,
|
|
26
|
+
rightComponent,
|
|
27
|
+
onPress,
|
|
28
|
+
}) => {
|
|
29
|
+
const circleColorTypes = {
|
|
30
|
+
primary: 'primary',
|
|
31
|
+
disable: 'disable',
|
|
32
|
+
noneBG: 'none',
|
|
33
|
+
};
|
|
34
|
+
const circleColor = type
|
|
35
|
+
? circleColorTypes[type]
|
|
36
|
+
: arrColor[index % arrColor.length];
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<>
|
|
40
|
+
<View style={styles.wrapItem}>
|
|
41
|
+
<TouchableOpacity onPress={onPress} disabled={type === 'disable'}>
|
|
42
|
+
<View style={styles.Border}>
|
|
43
|
+
<View style={styles.paddingLeft16}>
|
|
44
|
+
<CircleView size={40} backgroundColor={circleColor} center>
|
|
45
|
+
{leftIcon}
|
|
46
|
+
</CircleView>
|
|
47
|
+
</View>
|
|
48
|
+
<View style={styles.columeFlex}>
|
|
49
|
+
<Text style={styles.titleName}> {text}</Text>
|
|
50
|
+
<Text style={styles.status}> {subtext}</Text>
|
|
51
|
+
</View>
|
|
52
|
+
{!!rightComponent && (
|
|
53
|
+
<View style={styles.endFlex}>{rightComponent}</View>
|
|
54
|
+
)}
|
|
55
|
+
</View>
|
|
56
|
+
</TouchableOpacity>
|
|
57
|
+
</View>
|
|
58
|
+
</>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
);
|