@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.
Files changed (123) hide show
  1. package/assets/images/Illustrations.svg +83 -0
  2. package/assets/images/{WeatherChange.svg → ValueChange.svg} +0 -0
  3. package/index.js +2 -0
  4. package/package.json +3 -1
  5. package/src/Images/Common/file.png +0 -0
  6. package/src/Images/Common/fullscreen.png +0 -0
  7. package/src/commons/ActionGroup/OnOffTemplate/index.js +5 -0
  8. package/src/commons/ActionGroup/__test__/NumberUpDownTemplate.test.js +294 -0
  9. package/src/commons/ActionGroup/__test__/NumberUpDownTemplateWithNullConfigValue.test.js +60 -0
  10. package/src/commons/AlertAction/__test__/AlertAction.test.js +6 -6
  11. package/src/commons/AlertAction/index.js +2 -0
  12. package/src/commons/Automate/ItemAutomate.js +7 -1
  13. package/src/commons/Automate/__test__/ItemAutomate.test.js +16 -0
  14. package/src/commons/Automate/__test__/ItemScriptAction.test.js +16 -0
  15. package/src/commons/BackDefault/__test__/BackDefault.test.js +21 -0
  16. package/src/commons/BottomScrollPicker/index.js +5 -1
  17. package/src/commons/BottomSheet/index.js +10 -5
  18. package/src/commons/ButtonPopup/__test__/__snapshots__/ButtonPopup.test.js.snap +2 -0
  19. package/src/commons/ButtonPopup/index.js +2 -0
  20. package/src/commons/Calendar/index.js +72 -0
  21. package/src/commons/Calendar/styles.js +11 -0
  22. package/src/commons/Device/ItemAddNew/index.js +2 -2
  23. package/src/commons/Explore/__test__/HeaderExplore.test.js +25 -0
  24. package/src/commons/Explore/__test__/LocationItem.test.js +31 -0
  25. package/src/commons/Header/HeaderCustom.js +7 -3
  26. package/src/commons/HeaderAni/index.js +31 -3
  27. package/src/commons/HorizontalPicker/index.js +134 -0
  28. package/src/commons/HorizontalPicker/styles.js +56 -0
  29. package/src/commons/Modal/__test__/ModalBottom.test.js +39 -0
  30. package/src/commons/RowItem/__test__/RowItem.test.js +16 -0
  31. package/src/commons/RowItem/index.js +61 -0
  32. package/src/commons/RowItem/styles.js +53 -0
  33. package/src/commons/Sharing/WrapHeaderScrollable.js +78 -74
  34. package/src/commons/SubUnit/OneTap/ItemOneTap.js +73 -69
  35. package/src/commons/SubUnit/OneTap/__test__/SubUnitAutomate.test.js +47 -1
  36. package/src/commons/SubUnit/OneTap/index.js +2 -2
  37. package/src/commons/Unit/__test__/SharedUnit.test.js +330 -0
  38. package/src/commons/WheelDateTimePicker/index.js +16 -8
  39. package/src/commons/index.js +2 -0
  40. package/src/configs/API.js +5 -1
  41. package/src/configs/Constants.js +18 -3
  42. package/src/configs/Theme.js +20 -0
  43. package/src/context/SCContext.tsx +2 -2
  44. package/src/context/mockStore.ts +3 -1
  45. package/src/hooks/Common/__test__/useStatusbar.test.js +28 -0
  46. package/src/navigations/AutomateStack.js +45 -0
  47. package/src/navigations/UnitStack.js +33 -14
  48. package/src/navigations/utils.js +8 -0
  49. package/src/screens/AddNewAction/Components/LoadingSelectAction.js +40 -0
  50. package/src/screens/AddNewAction/Components/index.js +3 -0
  51. package/src/screens/AddNewAction/SelectAction.js +147 -62
  52. package/src/screens/AddNewAction/{SelectDevice.js → SelectSensorDevices.js} +42 -12
  53. package/src/screens/AddNewAction/SetupSensor.js +221 -0
  54. package/src/screens/AddNewAction/Styles/SelectActionStyles.js +43 -5
  55. package/src/screens/AddNewAction/Styles/{SelectDeviceStyles.js → SelectSensorDevicesStyles.js} +0 -0
  56. package/src/screens/AddNewAction/Styles/SetupSensorStyles.js +76 -0
  57. package/src/screens/AddNewAction/__test__/SelectAction.test.js +0 -19
  58. package/src/screens/AddNewAction/__test__/{SelectDevice.test.js → SelectSensorDevices.test.js} +3 -3
  59. package/src/screens/AddNewAction/__test__/SetupSensor.test.js +125 -0
  60. package/src/screens/AddNewAutoSmart/__test__/AddNewAutoSmart.test.js +69 -12
  61. package/src/screens/AddNewAutoSmart/index.js +42 -14
  62. package/src/screens/AddNewOneTap/AddNewOneTapStyles.js +4 -3
  63. package/src/screens/AddNewOneTap/__test__/AddNewOneTap.test.js +1 -0
  64. package/src/screens/AddNewOneTap/index.js +7 -4
  65. package/src/screens/AllCamera/__test__/index.test.js +103 -0
  66. package/src/screens/Automate/Components/Loading.js +64 -0
  67. package/src/screens/Automate/Styles/indexStyles.js +64 -0
  68. package/src/screens/Automate/__test__/Loading.test.js +16 -0
  69. package/src/screens/Automate/__test__/index.test.js +93 -0
  70. package/src/screens/Automate/index.js +148 -0
  71. package/src/screens/Device/__test__/detail.test.js +64 -0
  72. package/src/screens/Device/detail.js +17 -7
  73. package/src/screens/EditActionsList/index.js +2 -2
  74. package/src/screens/GuestInfo/__test__/index.test.js +176 -0
  75. package/src/screens/GuestInfo/components/AccessScheduleItem.js +6 -1
  76. package/src/screens/GuestInfo/components/AccessScheduleSheet.js +26 -15
  77. package/src/screens/GuestInfo/components/HeaderGuestInfo.js +6 -1
  78. package/src/screens/GuestInfo/components/RecurringDetail.js +9 -2
  79. package/src/screens/GuestInfo/components/TemporaryDetail.js +9 -2
  80. package/src/screens/GuestInfo/constant.js +2 -2
  81. package/src/screens/GuestInfo/index.js +4 -5
  82. package/src/screens/PlayBackCamera/Timer.js +1 -1
  83. package/src/screens/ScriptDetail/Styles/indexStyles.js +14 -0
  84. package/src/screens/ScriptDetail/__test__/index.test.js +119 -0
  85. package/src/screens/ScriptDetail/hooks/index.js +55 -0
  86. package/src/screens/ScriptDetail/index.js +124 -23
  87. package/src/screens/SelectUnit/Styles/indexStyles.js +55 -0
  88. package/src/screens/SelectUnit/__test__/index.test.js +85 -0
  89. package/src/screens/SelectUnit/index.js +100 -0
  90. package/src/screens/SetSchedule/__test__/index.test.js +97 -0
  91. package/src/screens/SetSchedule/components/RepeatOptionsPopup.js +56 -0
  92. package/src/screens/SetSchedule/components/RowItem.js +27 -0
  93. package/src/screens/SetSchedule/components/SelectWeekday.js +65 -0
  94. package/src/screens/SetSchedule/index.js +139 -0
  95. package/src/screens/SetSchedule/styles/RepeatOptionsPopupStyles.js +22 -0
  96. package/src/screens/SetSchedule/styles/RowItemStyles.js +29 -0
  97. package/src/screens/SetSchedule/styles/SelectWeekdayStyles.js +26 -0
  98. package/src/screens/{AddNewScriptAction/AddNewScriptActionStyles.js → SetSchedule/styles/indexStyles.js} +6 -12
  99. package/src/screens/Sharing/__test__/MemberList.test.js +21 -28
  100. package/src/screens/SubUnit/EditSubUnit.js +274 -0
  101. package/src/screens/SubUnit/EditSubUnitStyles.js +119 -0
  102. package/src/screens/SubUnit/ManageSubUnit.js +112 -370
  103. package/src/screens/SubUnit/ManageSubUnitStyles.js +40 -0
  104. package/src/screens/SubUnit/__test__/EditSubUnit.test.js +427 -0
  105. package/src/screens/SubUnit/__test__/ManageSubUnit.test.js +42 -386
  106. package/src/screens/SubUnit/hooks/__test__/useManageSubUnit.test.js +85 -0
  107. package/src/screens/SubUnit/hooks/useManageSubUnit.js +35 -0
  108. package/src/screens/Unit/Detail.js +3 -2
  109. package/src/screens/Unit/ManageUnit.js +10 -0
  110. package/src/screens/Unit/components/SearchLocation/__test__/RowLocation.test.js +36 -0
  111. package/src/screens/Unit/components/__test__/MyUnit.test.js +35 -0
  112. package/src/screens/Unit/components/__test__/MyUnitDevice.test.js +32 -0
  113. package/src/screens/UnitSummary/components/__test__/UnitSummary.test.js +67 -0
  114. package/src/screens/UnitSummary/components/__test__/index.test.js +48 -0
  115. package/src/screens/UnitSummary/components/index.js +1 -37
  116. package/src/screens/UnitSummary/components/indexstyles.js +39 -0
  117. package/src/utils/Apis/axios.js +0 -4
  118. package/src/utils/I18n/translations/en.json +30 -4
  119. package/src/utils/I18n/translations/vi.json +29 -3
  120. package/src/utils/Route/index.js +6 -1
  121. package/src/utils/__test__/InitData.test.js +20 -0
  122. package/src/commons/Automate/ItemAddNewScriptAction.js +0 -30
  123. 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 isVisible={isVisible} onHide={onCancel} title={t('set_hour')}>
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 = ({ isVisible, onHide, title, children }) => {
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={onHide}
14
- onBackdropPress={onHide}
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={
@@ -31,6 +31,8 @@ const ButtonPopup = ({
31
31
  isVisible={visible}
32
32
  onBackButtonPress={onClose}
33
33
  onBackdropPress={onClose}
34
+ useNativeDriver={true}
35
+ useNativeDriverForBackdrop={true}
34
36
  testID={TESTID.MODAL_BUTTON_POPUP}
35
37
  >
36
38
  <View style={styles.popoverStyle}>
@@ -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
+ };
@@ -0,0 +1,11 @@
1
+ import { StyleSheet } from 'react-native';
2
+
3
+ export default StyleSheet.create({
4
+ calendar: {
5
+ borderTopLeftRadius: 20,
6
+ borderTopRightRadius: 20,
7
+ },
8
+ arrowRight: {
9
+ transform: [{ rotate: '180deg' }],
10
+ },
11
+ });
@@ -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
- ({ scrollY, onLeft, title, rightComponent, headerStyle }) => {
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, 16],
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={[styles.container, headerStyle, { height: headerHeightAnim }]}
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
+ );