@eohjsc/react-native-smart-city 0.2.68 → 0.2.69

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 (26) hide show
  1. package/package.json +1 -1
  2. package/src/commons/ActionGroup/CurtainButtonTemplate.js +0 -30
  3. package/src/commons/ActionGroup/CurtainButtonTemplateStyle.js +0 -12
  4. package/src/commons/ActionGroup/__test__/CurtainButtonTemplate.test.js +1 -1
  5. package/src/commons/AlertAction/index.js +4 -3
  6. package/src/commons/SubUnit/OneTap/OneTapStyles.js +14 -5
  7. package/src/commons/SubUnit/OneTap/__test__/SubUnitAutomate.test.js +5 -68
  8. package/src/commons/SubUnit/OneTap/index.js +24 -33
  9. package/src/commons/ViewButtonBottom/index.js +4 -0
  10. package/src/screens/SharedUnit/index.js +7 -5
  11. package/src/screens/Sharing/Components/SensorItem.js +27 -12
  12. package/src/screens/Sharing/Components/Styles/SensorItemStyles.js +4 -0
  13. package/src/screens/Sharing/SelectPermission.js +44 -32
  14. package/src/screens/Sharing/__test__/SelectPermission.test.js +2 -1
  15. package/src/screens/SubUnit/AddSubUnit.js +4 -1
  16. package/src/screens/Unit/Detail.js +2 -2
  17. package/src/screens/Unit/SmartAccount.js +36 -15
  18. package/src/screens/Unit/SmartAccountStyles.js +20 -0
  19. package/src/screens/Unit/hook/useStateAlertRemove.js +4 -6
  20. package/src/utils/I18n/translations/en.json +3 -2
  21. package/src/utils/I18n/translations/vi.json +3 -2
  22. package/src/commons/ActionGroup/__test__/MenuActionAddSchedule.test.js +0 -71
  23. package/src/commons/ActionGroup/hooks/AccessScheduleDetailStyles.js +0 -41
  24. package/src/commons/ActionGroup/hooks/MenuActionAddSchedule.js +0 -110
  25. package/src/commons/ActionGroup/hooks/MenuActionAddScheduleStyle.js +0 -69
  26. package/src/commons/ActionGroup/hooks/RecurringDetail.js +0 -97
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@eohjsc/react-native-smart-city",
3
3
  "title": "React Native Smart Home",
4
- "version": "0.2.68",
4
+ "version": "0.2.69",
5
5
  "description": "TODO",
6
6
  "main": "index.js",
7
7
  "files": [
@@ -1,22 +1,14 @@
1
1
  import React, { memo, useCallback, useState } from 'react';
2
2
  import { TouchableOpacity, View, Switch, Image } from 'react-native';
3
3
  import { Icon } from '@ant-design/react-native';
4
- import { useTranslations } from '../../hooks/Common/useTranslations';
5
4
  import styles from './CurtainButtonTemplateStyle';
6
5
  import Text from '../Text';
7
6
  import { TESTID } from '../../configs/Constants';
8
7
  import { Colors, Images } from '../../configs';
9
- import { Section } from '../../commons/Section';
10
- import { IconOutline } from '@ant-design/icons-react-native';
11
- import MenuActionAddSchedule from './hooks/MenuActionAddSchedule';
12
- import { useBoolean } from '../../hooks/Common';
13
8
 
14
9
  const CurtainButtonTemplate = memo(({ actionGroup, doAction }) => {
15
- const t = useTranslations();
16
10
  const { configuration } = actionGroup;
17
11
  const [lock, setLock] = useState(false);
18
- const [isShowModal, setShowModal, setHideModal] = useBoolean(false);
19
-
20
12
  const onButtonOpenPress = useCallback(
21
13
  () => doAction(configuration.open_action_data),
22
14
  [configuration.open_action_data, doAction]
@@ -118,28 +110,6 @@ const CurtainButtonTemplate = memo(({ actionGroup, doAction }) => {
118
110
  lock ? Colors.Primary : Colors.Gray6
119
111
  )}
120
112
  </View>
121
- <Section style={styles.section}>
122
- <View style={styles.reminderOption}>
123
- <Text type="H4" color={Colors.Gray8}>
124
- {t('schedule')}
125
- </Text>
126
- <TouchableOpacity onPress={setShowModal}>
127
- <IconOutline name="plus" size={20} />
128
- </TouchableOpacity>
129
- </View>
130
- <View>
131
- <TouchableOpacity
132
- onPress={setShowModal}
133
- style={styles.tapToAddSchedule}
134
- >
135
- <Text type="Body" color={Colors.Gray6} center>
136
- {t('tap_to_add_new_schedule')}
137
- </Text>
138
- </TouchableOpacity>
139
- </View>
140
-
141
- <MenuActionAddSchedule visible={isShowModal} hideModal={setHideModal} />
142
- </Section>
143
113
  </>
144
114
  );
145
115
  });
@@ -29,18 +29,6 @@ export default StyleSheet.create({
29
29
  alignItems: 'flex-end',
30
30
  paddingLeft: 5,
31
31
  },
32
- section: {
33
- marginHorizontal: 20,
34
- borderRadius: 10,
35
- },
36
- reminderOption: {
37
- flex: 1,
38
- flexDirection: 'row',
39
- justifyContent: 'space-between',
40
- },
41
- tapToAddSchedule: {
42
- paddingVertical: 50,
43
- },
44
32
  buttonActionCurtain: {
45
33
  flex: 1,
46
34
  aspectRatio: 1,
@@ -67,6 +67,6 @@ describe('Test CurtainButtonTemplate', () => {
67
67
  });
68
68
  const instance = wrapper.root;
69
69
  const touchableOpacities = instance.findAllByType(TouchableOpacity);
70
- expect(touchableOpacities.length).toEqual(18);
70
+ expect(touchableOpacities.length).toEqual(3);
71
71
  });
72
72
  });
@@ -22,6 +22,8 @@ const AlertAction = ({
22
22
  children,
23
23
  testIDPrefix = '',
24
24
  animatedStyle,
25
+ boxLeftButtonStyle,
26
+ boxRightButtonStyle,
25
27
  }) => {
26
28
  return (
27
29
  <ModalCustom
@@ -54,6 +56,8 @@ const AlertAction = ({
54
56
  onRightClick={rightButtonClick}
55
57
  styleButtonLeftText={leftButtonStyle}
56
58
  styleButtonRightText={rightButtonStyle}
59
+ styleButtonLeft={boxLeftButtonStyle}
60
+ styleButtonRight={boxRightButtonStyle}
57
61
  testIDPrefix={testIDPrefix}
58
62
  />
59
63
  </View>
@@ -85,10 +89,8 @@ const styles = StyleSheet.create({
85
89
  modalHeader: {
86
90
  padding: 16,
87
91
  backgroundColor: Colors.White,
88
- borderBottomWidth: 1,
89
92
  borderTopLeftRadius: 20,
90
93
  borderTopRightRadius: 20,
91
- borderColor: Colors.Gray4,
92
94
  },
93
95
  modalHeaderText: {
94
96
  fontSize: 16,
@@ -97,7 +99,6 @@ const styles = StyleSheet.create({
97
99
  },
98
100
  descriptionText: {
99
101
  paddingHorizontal: 16,
100
- paddingTop: 16,
101
102
  },
102
103
  });
103
104
 
@@ -33,13 +33,19 @@ export default StyleSheet.create({
33
33
  alignItems: 'center',
34
34
  paddingBottom: 3,
35
35
  },
36
- dropDown: {
37
- width: 114,
38
- height: 40,
36
+ borderSelection: {
37
+ flexDirection: 'row',
38
+ justifyContent: 'center',
39
+ alignItems: 'center',
40
+ paddingHorizontal: 5,
41
+ paddingLeft: 15,
39
42
  borderRadius: 30,
40
43
  backgroundColor: Colors.Gray3,
41
44
  },
42
- boxDropDown: {
45
+ notShowBorder: {
46
+ paddingLeft: 15,
47
+ },
48
+ boxTextScenarito: {
43
49
  justifyContent: 'center',
44
50
  flexDirection: 'row',
45
51
  alignItems: 'center',
@@ -48,8 +54,11 @@ export default StyleSheet.create({
48
54
  android: 6,
49
55
  }),
50
56
  },
51
- textDropDown: {
57
+ textSelection: {
52
58
  color: Colors.Primary,
53
59
  marginRight: 10,
54
60
  },
61
+ boxScenario: {
62
+ flexDirection: 'row',
63
+ },
55
64
  });
@@ -267,82 +267,19 @@ describe('test Item', () => {
267
267
  expect(goDetail).toHaveLength(1);
268
268
  });
269
269
 
270
- test('render click select option filter by automation', async () => {
271
- data.isOwner = false;
272
- data.type = 'schedule';
273
- data.listAutomate = [
274
- {
275
- text: AUTOMATE_TYPE.SCENARIO,
276
- type: AUTOMATE_TYPE.ONE_TAP,
277
- data: [
278
- {
279
- id: 1,
280
- user: 6,
281
- type: 'one_tap',
282
- activate_at: null,
283
- script: {
284
- name: 'One-tap',
285
- icon: '',
286
- icon_kit: '',
287
- },
288
- },
289
- ],
290
- },
291
- {
292
- text: AUTOMATE_TYPE.AUTOMATION,
293
- type: AUTOMATE_TYPE.AUTOMATION,
294
- data: [
295
- {
296
- id: 2,
297
- user: 6,
298
- type: 'schedule',
299
- activate_at: null,
300
- script: {
301
- name: 'Rain',
302
- icon: '',
303
- icon_kit: '',
304
- },
305
- },
306
- ],
307
- },
308
- ];
309
- const response = {
310
- status: 200,
311
- };
312
-
313
- await axios.post.mockImplementation(async () => {
314
- return response;
315
- });
316
-
270
+ test('render click select option by automation', async () => {
317
271
  await act(async () => {
318
272
  tree = await create(wrapComponent(data));
319
273
  });
320
-
321
274
  const instance = tree.root;
322
- const menuDropDown = instance.find(
275
+ const touchableOpacity = instance.findAll(
323
276
  (el) =>
324
277
  el.props.testID === TESTID.SUB_UNIT_SELECT_AUTOMATE_TYPE &&
325
278
  el.type === TouchableOpacity
326
279
  );
327
- await act(async () => {
328
- await menuDropDown.props.onPress();
280
+ act(() => {
281
+ touchableOpacity[0].props.onPress();
329
282
  });
330
-
331
- const menu = instance.find(
332
- (el) => el.props.testID === TESTID.NAVBAR_MENU_ACTION_MORE
333
- );
334
-
335
- expect(menu.props.isVisible).toBeTruthy();
336
-
337
- const automation = menu.props.listMenuItem[1];
338
-
339
- await act(async () => {
340
- await menu.props.onItemClick(automation, 1);
341
- });
342
-
343
- const text = instance.find(
344
- (el) => el.props.testID === TESTID.SUB_UNIT_TEXT_DROPDOWN
345
- );
346
- expect(text.props.children).toEqual(AUTOMATE_TYPE.AUTOMATION);
283
+ expect(touchableOpacity).toHaveLength(1);
347
284
  });
348
285
  });
@@ -1,16 +1,13 @@
1
1
  import React, { useCallback, useEffect, useRef, useState } from 'react';
2
2
  import { TouchableOpacity, View } from 'react-native';
3
- import { Icon } from '@ant-design/react-native';
4
3
 
5
- import { MenuActionMore, Section } from '../..';
4
+ import { Section } from '../..';
6
5
  import ItemAddNew from '../../Device/ItemAddNew';
7
6
  import ItemOneTap from './ItemOneTap';
8
7
  import { useTranslations } from '../../../hooks/Common/useTranslations';
9
8
  import { useNavigation } from '@react-navigation/native';
10
9
  import Routes from '../../../utils/Route/index.js';
11
10
  import { AUTOMATE_TYPE, TESTID } from '../../../configs/Constants';
12
- import { Colors } from '../../../configs/Colors.js';
13
- import usePopover from '../../../hooks/Common/usePopover.js';
14
11
  import Text from '../../Text/index.js';
15
12
 
16
13
  import styles from './OneTapStyles.js';
@@ -33,11 +30,8 @@ const SubUnitAutomate = ({ isOwner, listAutomate, unit, wrapItemStyle }) => {
33
30
  break;
34
31
  }
35
32
  };
36
- const { childRef, showingPopover, showPopoverWithRef, hidePopover } =
37
- usePopover();
38
33
 
39
34
  const refMenuAction = useRef();
40
- const handleShowMenuAction = () => showPopoverWithRef(refMenuAction);
41
35
 
42
36
  const onItemClick = useCallback((item, index) => {
43
37
  setAutomates(item);
@@ -50,23 +44,30 @@ const SubUnitAutomate = ({ isOwner, listAutomate, unit, wrapItemStyle }) => {
50
44
 
51
45
  return (
52
46
  <Section style={styles.noShadow}>
53
- <TouchableOpacity
54
- style={styles.dropDown}
55
- onPress={handleShowMenuAction}
56
- ref={refMenuAction}
57
- testID={TESTID.SUB_UNIT_SELECT_AUTOMATE_TYPE}
58
- >
59
- <View style={styles.boxDropDown}>
60
- <Text
61
- testID={TESTID.SUB_UNIT_TEXT_DROPDOWN}
62
- style={styles.textDropDown}
63
- semibold
47
+ <View style={styles.boxScenario}>
48
+ {listAutomate.map((item, index) => (
49
+ <TouchableOpacity
50
+ style={
51
+ indexAutomate === index
52
+ ? styles.borderSelection
53
+ : styles.notShowBorder
54
+ }
55
+ onPress={() => onItemClick(item, index)}
56
+ ref={refMenuAction}
57
+ testID={TESTID.SUB_UNIT_SELECT_AUTOMATE_TYPE}
64
58
  >
65
- {automates?.text}
66
- </Text>
67
- <Icon name={'caret-down'} size={14} style={{ color: Colors.Gray8 }} />
68
- </View>
69
- </TouchableOpacity>
59
+ <View style={styles.boxTextScenarito}>
60
+ <Text
61
+ testID={TESTID.SUB_UNIT_TEXT_DROPDOWN}
62
+ style={styles.textSelection}
63
+ semibold
64
+ >
65
+ {item?.text}
66
+ </Text>
67
+ </View>
68
+ </TouchableOpacity>
69
+ ))}
70
+ </View>
70
71
  <View style={styles.boxDevices}>
71
72
  {automates?.data &&
72
73
  automates.data.map((item) => (
@@ -78,16 +79,6 @@ const SubUnitAutomate = ({ isOwner, listAutomate, unit, wrapItemStyle }) => {
78
79
  wrapStyle={wrapItemStyle}
79
80
  />
80
81
  </View>
81
- <MenuActionMore
82
- isVisible={showingPopover}
83
- hideMore={hidePopover}
84
- listMenuItem={listAutomate}
85
- childRef={childRef}
86
- onItemClick={onItemClick}
87
- isTextCenter={false}
88
- testID={TESTID.NAVBAR_MENU_ACTION_MORE}
89
- wrapStyle={styles.wrapStyle}
90
- />
91
82
  </Section>
92
83
  );
93
84
  };
@@ -16,6 +16,8 @@ const ViewButtonBottom = ({
16
16
  styleButton,
17
17
  styleButtonLeftText,
18
18
  styleButtonRightText,
19
+ styleButtonLeft,
20
+ styleButtonRight,
19
21
  testIDPrefix = '',
20
22
  }) => {
21
23
  const useTwoButton = leftTitle && rightTitle;
@@ -27,6 +29,7 @@ const ViewButtonBottom = ({
27
29
  style={[
28
30
  styles.button,
29
31
  styleButton,
32
+ styleButtonLeft,
30
33
  useTwoButton && styles.buttonMarginRight,
31
34
  ]}
32
35
  onPress={onLeftClick}
@@ -48,6 +51,7 @@ const ViewButtonBottom = ({
48
51
  style={[
49
52
  styles.button,
50
53
  styleButton,
54
+ styleButtonRight,
51
55
  useTwoButton && styles.buttonMarginLeft,
52
56
  ]}
53
57
  onPress={onRightClick}
@@ -1,9 +1,9 @@
1
1
  import React, { useEffect, useCallback, useState, useMemo } from 'react';
2
2
  import { View, TouchableOpacity, FlatList, RefreshControl } from 'react-native';
3
- import { useNavigation } from '@react-navigation/native';
3
+ import { useNavigation, useIsFocused } from '@react-navigation/native';
4
+
4
5
  import { axiosGet } from '../../utils/Apis/axios';
5
6
  import { useTranslations } from '../../hooks/Common/useTranslations';
6
-
7
7
  import { API } from '../../configs';
8
8
  import Text from '../../commons/Text';
9
9
  import SharedUnit from '../../commons/Unit/SharedUnit';
@@ -24,7 +24,7 @@ const Shared = () => {
24
24
  useTitleHeader(t('text_shared_with_me'));
25
25
  const navigation = useNavigation();
26
26
  const [tab, setTabActiveState] = useState(0);
27
-
27
+ const isFocused = useIsFocused();
28
28
  const [sharedUnits, setSharedUnits] = useState([]);
29
29
 
30
30
  const dataStarred = useMemo(
@@ -73,8 +73,10 @@ const Shared = () => {
73
73
  }, [language, forceUpdate]);
74
74
 
75
75
  useEffect(() => {
76
- filterSharedUnits(filter);
77
- }, [filterSharedUnits, filter]);
76
+ if (isFocused) {
77
+ filterSharedUnits(filter);
78
+ }
79
+ }, [filterSharedUnits, filter, isFocused]);
78
80
 
79
81
  const onRefresh = useCallback(() => {
80
82
  filterSharedUnits(filter);
@@ -5,11 +5,13 @@ import { Colors } from '../../../configs';
5
5
  import styles from './Styles/SensorItemStyles';
6
6
  import FImage from '../../../commons/FImage';
7
7
  import { TitleCheckBox } from '.';
8
+ import { CheckBoxCustom } from '.';
8
9
 
9
10
  const SensorItem = ({
10
11
  item = {},
11
12
  isRenderSeparated,
12
13
  onTickedChild,
14
+ onTickedSensor,
13
15
  titleGroup,
14
16
  activeItemId,
15
17
  setActiveItemId,
@@ -21,21 +23,22 @@ const SensorItem = ({
21
23
  actions = [],
22
24
  read_configs = [],
23
25
  icon_kit = '',
26
+ isChecked,
24
27
  } = item;
25
- const [expanded, setExpanded] = useState(activeItemId === id);
26
28
  const [dataConfig, setDataConfig] = useState([
27
29
  ...actions,
28
30
  ...read_configs.map((i) => ({ ...i, isConfig: true })),
29
31
  ]);
30
32
 
33
+ const expanded = activeItemId === id;
34
+
31
35
  const onPressItem = () => {
32
- setActiveItemId(id);
33
- if (activeItemId === id) {
34
- setExpanded(!expanded);
36
+ if (dataConfig.length > 0) {
37
+ expanded ? setActiveItemId(-1) : setActiveItemId(id);
38
+ LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
35
39
  } else {
36
- setExpanded(false);
40
+ handleOnTickedSensor();
37
41
  }
38
- LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
39
42
  };
40
43
 
41
44
  const handleOnTickedChild = (idGroup, isChecked, childId) => {
@@ -56,6 +59,10 @@ const SensorItem = ({
56
59
  );
57
60
  };
58
61
 
62
+ const handleOnTickedSensor = () => {
63
+ onTickedSensor && onTickedSensor(idGroup, id, !isChecked);
64
+ };
65
+
59
66
  useEffect(() => {
60
67
  if (
61
68
  Platform.OS === 'android' &&
@@ -97,12 +104,20 @@ const SensorItem = ({
97
104
  <Text numberOfLines={1} style={styles.text} onPress={onPressItem}>
98
105
  {name}
99
106
  </Text>
100
- <IconOutline
101
- onPress={onPressItem}
102
- name={expanded ? 'up' : 'down'}
103
- size={20}
104
- color={Colors.Gray6}
105
- />
107
+ {dataConfig.length > 0 ? (
108
+ <IconOutline
109
+ onPress={onPressItem}
110
+ name={expanded ? 'up' : 'down'}
111
+ size={20}
112
+ color={Colors.Gray6}
113
+ />
114
+ ) : (
115
+ <CheckBoxCustom
116
+ isChecked={isChecked}
117
+ onPress={onPressItem}
118
+ wrapStyle={styles.checkBox}
119
+ />
120
+ )}
106
121
  </View>
107
122
  {expanded && <View style={styles.wrapExpand}>{renderData}</View>}
108
123
  {isRenderSeparated && <View style={styles.viewSeparated} />}
@@ -53,4 +53,8 @@ export default StyleSheet.create({
53
53
  wrapExpand: {
54
54
  marginTop: 10,
55
55
  },
56
+ checkBox: {
57
+ width: normalize(20),
58
+ height: normalize(20),
59
+ },
56
60
  });
@@ -38,11 +38,12 @@ const SelectPermission = ({ route }) => {
38
38
  ...i,
39
39
  isChecked,
40
40
  }));
41
- for (let sensor in data) {
42
- for (let item in data[sensor].sensors) {
43
- const itemTemp = data[sensor].sensors[item];
44
- data[sensor].sensors[item] = {
41
+ for (let station in data) {
42
+ for (let item in data[station].sensors) {
43
+ const itemTemp = data[station].sensors[item];
44
+ data[station].sensors[item] = {
45
45
  ...itemTemp,
46
+ isChecked,
46
47
  actions: itemTemp.actions.map((i) => ({
47
48
  ...i,
48
49
  isChecked,
@@ -63,6 +64,7 @@ const SelectPermission = ({ route }) => {
63
64
  isChecked,
64
65
  sensors: data[index]?.sensors.map((i) => ({
65
66
  ...i,
67
+ isChecked,
66
68
  actions: i.actions.map((j) => ({ ...j, isChecked })),
67
69
  read_configs: i.read_configs.map((j) => ({ ...j, isChecked })),
68
70
  })),
@@ -80,33 +82,38 @@ const SelectPermission = ({ route }) => {
80
82
  isReadConfig
81
83
  ) => {
82
84
  let data = [...dataStationTemp];
83
- const indexGroup = data.findIndex((item) => item.id === idGroup);
84
- const indexSensor = (data[indexGroup]?.sensors || []).findIndex(
85
- (item) => item.id === sensorId
85
+ const group = data.find((i) => i.id === idGroup);
86
+ const sensor = group.sensors.find((i) => i.id === sensorId);
87
+ const child = sensor[`${isReadConfig ? 'read_configs' : 'actions'}`].find(
88
+ (i) => i.id === childId
86
89
  );
87
- const indexChild = (data[indexGroup]?.sensors || [])[indexSensor][
88
- `${isReadConfig ? 'read_configs' : 'actions'}`
89
- ].findIndex((item) => item.id === childId);
90
- (data[indexGroup]?.sensors || [])[indexSensor][
91
- `${isReadConfig ? 'read_configs' : 'actions'}`
92
- ][indexChild] = {
93
- ...(data[indexGroup]?.sensors || [])[indexSensor][
94
- `${isReadConfig ? 'read_configs' : 'actions'}`
95
- ][indexChild],
96
- isChecked,
97
- };
98
- for (let i of data) {
99
- if (i.sensors.length) {
100
- let isChecked;
101
- let arrChecked = [];
102
- for (let j of i.sensors) {
103
- isChecked = !(
104
- j.actions.some((k) => !k.isChecked) ||
105
- j.read_configs.some((k) => !k.isChecked)
106
- );
107
- arrChecked.push(isChecked);
108
- }
109
- i.isChecked = !arrChecked.some((i) => !i);
90
+
91
+ child.isChecked = isChecked;
92
+ sensor.isChecked = !(
93
+ sensor.read_configs.some((i) => !i.isChecked) ||
94
+ sensor.actions.some((i) => !i.isChecked)
95
+ );
96
+
97
+ for (let station of data) {
98
+ if (station.sensors.length) {
99
+ station.isChecked = !station.sensors.some((i) => !i.isChecked);
100
+ }
101
+ }
102
+ setIsTickAllDevices(!dataStationTemp.some((i) => !i.isChecked));
103
+ dataStationTemp = data;
104
+ setDataStations(data);
105
+ };
106
+
107
+ const onTickedSensor = (idGroup, sensorId, isChecked) => {
108
+ let data = [...dataStationTemp];
109
+ const group = data.find((i) => i.id === idGroup);
110
+ const sensor = group.sensors.find((i) => i.id === sensorId);
111
+
112
+ sensor.isChecked = isChecked;
113
+
114
+ for (let station of data) {
115
+ if (station.sensors.length) {
116
+ station.isChecked = !station.sensors.some((i) => !i.isChecked);
110
117
  }
111
118
  }
112
119
  setIsTickAllDevices(!dataStationTemp.some((i) => !i.isChecked));
@@ -133,6 +140,7 @@ const SelectPermission = ({ route }) => {
133
140
  key={i.id}
134
141
  isRenderSeparated={index !== sensors.length - 1}
135
142
  onTickedChild={onTickedChild}
143
+ onTickedSensor={onTickedSensor}
136
144
  titleGroup={name}
137
145
  activeItemId={activeItemId}
138
146
  setActiveItemId={setActiveItemId}
@@ -147,8 +155,8 @@ const SelectPermission = ({ route }) => {
147
155
  const onPressNext = () => {
148
156
  let read_permissions = [],
149
157
  control_permissions = [];
150
- for (let sensor of dataStationTemp) {
151
- for (let item of sensor.sensors) {
158
+ for (let station of dataStationTemp) {
159
+ for (let item of station.sensors) {
152
160
  let arrIdControlTemp = [],
153
161
  arrIdReadTemp = [];
154
162
  for (let i of item.actions) {
@@ -161,6 +169,10 @@ const SelectPermission = ({ route }) => {
161
169
  control_permissions.push({ id: item.id, values: arrIdControlTemp });
162
170
  arrIdReadTemp.length &&
163
171
  read_permissions.push({ id: item.id, values: arrIdReadTemp });
172
+ !arrIdControlTemp.length &&
173
+ !arrIdReadTemp.length &&
174
+ item.isChecked &&
175
+ read_permissions.push({ id: item.id, values: [] });
164
176
  }
165
177
  }
166
178
  if (!read_permissions.length && !control_permissions.length) {
@@ -144,6 +144,7 @@ describe('Test SelectPermission', () => {
144
144
  {
145
145
  actions: [{ id: 136, isChecked: true, name: 'action 1' }],
146
146
  id: 123,
147
+ isChecked: true,
147
148
  name: 'child1',
148
149
  read_configs: [{ id: 137, isChecked: true, name: 'config 1' }],
149
150
  },
@@ -165,7 +166,7 @@ describe('Test SelectPermission', () => {
165
166
  const SensorItemElement = instance.findAllByType(SensorItem);
166
167
  expect(SensorItemElement).toHaveLength(1);
167
168
  act(() => {
168
- SensorItemElement[0].props.onTickedChild(204, 123, 136, true, true);
169
+ SensorItemElement[0].props.onTickedChild(204, 123, 137, true, true);
169
170
  });
170
171
  expect(mockSetDataStations).toBeCalled();
171
172
  });
@@ -24,9 +24,11 @@ import { axiosPost, createFormData } from '../../utils/Apis/axios';
24
24
  import { ToastBottomHelper } from '../../utils/Utils';
25
25
  import { TESTID } from '../../configs/Constants';
26
26
  import styles from './AddSubUnitStyles';
27
+ import useKeyboardShow from '../../hooks/Common/useKeyboardShow';
27
28
 
28
29
  const AddSubUnit = ({ route }) => {
29
30
  const t = useTranslations();
31
+ const { dismissKeyboard } = useKeyboardShow();
30
32
  const { navigate, goBack } = useNavigation();
31
33
  const { unit, addType, isAddUnit, location = '' } = route?.params;
32
34
  const [roomName, setRoomName] = useState('');
@@ -126,8 +128,9 @@ const AddSubUnit = ({ route }) => {
126
128
  ]);
127
129
 
128
130
  const onChoosePhoto = useCallback(() => {
131
+ dismissKeyboard();
129
132
  setShowImagePicker(true);
130
- }, []);
133
+ }, [dismissKeyboard]);
131
134
 
132
135
  useEffect(() => {
133
136
  if (imageUrl) {
@@ -122,12 +122,12 @@ const UnitDetail = ({ route }) => {
122
122
  if (success) {
123
123
  setListAutomate([
124
124
  {
125
- text: t(AUTOMATE_TYPE.SCENARIO),
125
+ text: t(AUTOMATE_TYPE.ONE_TAP),
126
126
  data: data.filter((item) => item.type === AUTOMATE_TYPE.ONE_TAP),
127
127
  type: AUTOMATE_TYPE.ONE_TAP,
128
128
  },
129
129
  {
130
- text: t(AUTOMATE_TYPE.AUTOMATION),
130
+ text: t(AUTOMATE_TYPE.SCENARIO),
131
131
  data: data.filter((item) => item.type !== AUTOMATE_TYPE.ONE_TAP),
132
132
  type: AUTOMATE_TYPE.AUTOMATION,
133
133
  },
@@ -14,9 +14,10 @@ import Routes from '../../utils/Route';
14
14
  import { useNavigation } from '@react-navigation/native';
15
15
  import { axiosDelete, axiosGet } from '../../utils/Apis/axios';
16
16
  import { SmartAccountItem } from './SmartAccountItem';
17
- import { usePopover } from '../../hooks/Common';
18
- import { MenuActionMore } from '../../commons';
17
+ import { usePopover, useBoolean } from '../../hooks/Common';
18
+ import { MenuActionMore, AlertAction } from '../../commons';
19
19
  import { useTranslations } from '../../hooks/Common/useTranslations';
20
+ import { useStateAlertRemove } from '../Unit/hook/useStateAlertRemove';
20
21
 
21
22
  const ListSmartAccount = ({ route }) => {
22
23
  const { unitId } = route?.params || {};
@@ -36,6 +37,9 @@ const ListSmartAccount = ({ route }) => {
36
37
 
37
38
  const { childRef, showingPopover, showPopoverWithRef, hidePopover } =
38
39
  usePopover();
40
+ const [lockShowing, acquireLockShowing, releaseLockShowing] = useBoolean();
41
+ const { stateAlertRemove, onShowRemoveAlert, hideAlertAction } =
42
+ useStateAlertRemove();
39
43
 
40
44
  useEffect(() => {
41
45
  getAllSmartAccounts();
@@ -50,29 +54,31 @@ const ListSmartAccount = ({ route }) => {
50
54
  [showPopoverWithRef]
51
55
  );
52
56
 
53
- const deleteSmartAccount = useCallback(async () => {
54
- if (!smartAccountRef?.current) {
55
- return;
56
- }
57
- const id = smartAccountRef.current.id;
58
- const { success } = await axiosDelete(
59
- API.SMART_ACCOUNT.REMOVE_SMART_ACCOUNT(id)
60
- );
61
- success && getAllSmartAccounts();
62
- }, [getAllSmartAccounts]);
63
-
64
57
  const onItemClick = useCallback(
65
58
  (item) => {
66
59
  if (!smartAccountRef?.current) {
67
60
  return;
68
61
  }
69
62
  if (item.action === 'remove') {
70
- deleteSmartAccount();
63
+ acquireLockShowing();
64
+ onShowRemoveAlert(smartAccountRef.current.brand)();
71
65
  }
72
66
  },
73
- [deleteSmartAccount]
67
+ [acquireLockShowing, onShowRemoveAlert]
74
68
  );
75
69
 
70
+ const deleteSmartAccount = useCallback(async () => {
71
+ hideAlertAction();
72
+ if (!smartAccountRef?.current) {
73
+ return;
74
+ }
75
+ const id = smartAccountRef.current.id;
76
+ const { success } = await axiosDelete(
77
+ API.SMART_ACCOUNT.REMOVE_SMART_ACCOUNT(id)
78
+ );
79
+ success && getAllSmartAccounts();
80
+ }, [getAllSmartAccounts, hideAlertAction]);
81
+
76
82
  const listMenuItem = useMemo(() => {
77
83
  return [{ action: 'remove', text: t('remove_account') }];
78
84
  }, [t]);
@@ -88,6 +94,7 @@ const ListSmartAccount = ({ route }) => {
88
94
  },
89
95
  [navigate, unitId]
90
96
  );
97
+
91
98
  return (
92
99
  <View style={styles.wrap}>
93
100
  <WrapHeaderScrollable
@@ -109,12 +116,26 @@ const ListSmartAccount = ({ route }) => {
109
116
  );
110
117
  })}
111
118
  </View>
119
+ <AlertAction
120
+ visible={stateAlertRemove.visible && !lockShowing}
121
+ hideModal={hideAlertAction}
122
+ title={stateAlertRemove.title}
123
+ message={stateAlertRemove.message}
124
+ leftButtonTitle={stateAlertRemove.leftButton}
125
+ leftButtonClick={deleteSmartAccount}
126
+ rightButtonTitle={stateAlertRemove.rightButton}
127
+ rightButtonClick={hideAlertAction}
128
+ boxLeftButtonStyle={styles.boxButtonNotSelect}
129
+ boxRightButtonStyle={styles.boxButtonSelect}
130
+ rightButtonStyle={styles.textRightButton}
131
+ />
112
132
  <MenuActionMore
113
133
  isVisible={showingPopover}
114
134
  hideMore={hidePopover}
115
135
  listMenuItem={listMenuItem}
116
136
  childRef={childRef}
117
137
  onItemClick={onItemClick}
138
+ hideComplete={releaseLockShowing}
118
139
  />
119
140
  </WrapHeaderScrollable>
120
141
  </View>
@@ -42,4 +42,24 @@ export default StyleSheet.create({
42
42
  borderColor: Colors.ShadownTransparent,
43
43
  borderTopWidth: 1,
44
44
  },
45
+ boxButtonNotSelect: {
46
+ marginVertical: 16,
47
+ height: 45,
48
+ borderRadius: 30,
49
+ borderColor: Colors.Primary,
50
+ borderWidth: 1,
51
+ paddingVertical: 0,
52
+ },
53
+ boxButtonSelect: {
54
+ marginVertical: 16,
55
+ height: 45,
56
+ borderRadius: 30,
57
+ borderColor: Colors.Primary,
58
+ backgroundColor: Colors.Primary,
59
+ borderWidth: 1,
60
+ paddingVertical: 0,
61
+ },
62
+ textRightButton: {
63
+ color: Colors.White,
64
+ },
45
65
  });
@@ -5,10 +5,10 @@ export const useStateAlertRemove = () => {
5
5
  const t = useTranslations();
6
6
  const [stateAlertRemove, setStateAlertRemove] = useState({
7
7
  visible: false,
8
- title: t('delete_smart_account'),
8
+ title: t('remove_account'),
9
9
  message: '',
10
- leftButton: t('cancel'),
11
- rightButton: t('remove'),
10
+ leftButton: t('yes_remove'),
11
+ rightButton: t('cancel'),
12
12
  });
13
13
  const hideAlertAction = useCallback(() => {
14
14
  setStateAlertRemove((state) => ({
@@ -22,9 +22,7 @@ export const useStateAlertRemove = () => {
22
22
  setStateAlertRemove((state) => ({
23
23
  ...state,
24
24
  visible: true,
25
- message: `${t('are_you_sure_want_to_delete', {
26
- text: brand === 'google_home' ? 'Điện Quang' : brand,
27
- })}`,
25
+ message: t('this_action_will_remove_all_related_devices'),
28
26
  }));
29
27
  },
30
28
  [t]
@@ -798,7 +798,7 @@
798
798
  "smart": "Smart",
799
799
  "smart_account": "Smart account",
800
800
  "delete_smart_account": "Delete smart account",
801
- "are_you_sure_want_to_delete": "Are you sure you want to delete {text} ?",
801
+ "this_action_will_remove_all_related_devices": "This action will remove all related devices and it’s setting forever. Do you wish to continue?",
802
802
  "multi_unit": "Multi Units",
803
803
  "edit_device": "Edit Device",
804
804
  "device_name": "Device name",
@@ -888,5 +888,6 @@
888
888
  "location_permission_required_wifi_title": "Location permission is required for WiFi connections",
889
889
  "location_permission_required_wifi_message": "This app needs location permission as this is required to scan for wifi networks.",
890
890
  "deny": "DENY",
891
- "allow": "ALLOW"
891
+ "allow": "ALLOW",
892
+ "yes_remove": "Yes,remove"
892
893
  }
@@ -799,7 +799,7 @@
799
799
  "smart": "Thông minh",
800
800
  "smart_account": "Tài khoản thông minh",
801
801
  "delete_smart_account": "Xóa tài khoản thông minh",
802
- "are_you_sure_want_to_delete": "Bạn có muốn xóa {text} ?",
802
+ "this_action_will_remove_all_related_devices": "Hành động này sẽ xóa tất cả các thiết bị liên quan và nó sẽ cài đặt vĩnh viễn. Bạn có muốn tiếp tục không?",
803
803
  "edit_device": "Chỉnh sửa thiết bị",
804
804
  "device_name": "Tên thiết bị",
805
805
  "rename_successfully": "Đổi tên thành công!",
@@ -890,5 +890,6 @@
890
890
  "location_permission_required_wifi_title": "Quyền vị trí là bắt buộc đối với kết nối WiFi",
891
891
  "location_permission_required_wifi_message": "Ứng dụng này cần có quyền định vị vì ứng dụng này được yêu cầu để quét các mạng Wi-Fi.",
892
892
  "deny": "Từ chối",
893
- "allow": "Cho phép"
893
+ "allow": "Cho phép",
894
+ "yes_remove": "Có,loại bỏ"
894
895
  }
@@ -1,71 +0,0 @@
1
- import React from 'react';
2
- import renderer, { act } from 'react-test-renderer';
3
-
4
- import MenuActionAddSchedule from '../hooks/MenuActionAddSchedule';
5
- import { SCProvider } from '../../../context';
6
- import { mockSCStore } from '../../../context/mockStore';
7
- import RecurringDetail from '../hooks/RecurringDetail';
8
- import WheelDateTimePicker from '../../WheelDateTimePicker';
9
-
10
- const mockSetState = jest.fn();
11
- jest.mock('react', () => {
12
- return {
13
- ...jest.requireActual('react'),
14
- memo: (x) => x,
15
- useState: jest.fn((init) => [init, mockSetState]),
16
- };
17
- });
18
-
19
- const wrapComponent = (actionGroup) => (
20
- <SCProvider initState={mockSCStore({})}>
21
- <MenuActionAddSchedule />
22
- </SCProvider>
23
- );
24
-
25
- const mockedNavigate = jest.fn();
26
-
27
- jest.mock('@react-navigation/native', () => {
28
- return {
29
- ...jest.requireActual('@react-navigation/native'),
30
- useNavigation: () => ({
31
- goBack: mockedNavigate,
32
- }),
33
- };
34
- });
35
-
36
- jest.mock('react', () => {
37
- return {
38
- ...jest.requireActual('react'),
39
- memo: (x) => x,
40
- };
41
- });
42
-
43
- jest.mock('axios');
44
-
45
- describe('Test MenuActionAddSchedule', () => {
46
- let tree;
47
-
48
- test('test render MenuActionAddSchedule', async () => {
49
- await act(async () => {
50
- tree = await renderer.create(wrapComponent());
51
- });
52
- const instance = tree.root;
53
-
54
- const recurringDetail = instance.findByType(RecurringDetail);
55
- await act(async () => {
56
- recurringDetail.props.onShowSetDateTime();
57
- });
58
-
59
- const wheelDateTimePicker = instance.findByType(WheelDateTimePicker);
60
-
61
- await act(async () => {
62
- wheelDateTimePicker.props.onPicked();
63
- });
64
-
65
- await act(async () => {
66
- wheelDateTimePicker.props.onCancel();
67
- });
68
-
69
- expect(wheelDateTimePicker.props.isVisible).toEqual(false);
70
- });
71
- });
@@ -1,41 +0,0 @@
1
- import { StyleSheet } from 'react-native';
2
- import { Colors } from '../../../configs';
3
-
4
- export default StyleSheet.create({
5
- title: {
6
- marginTop: 16,
7
- },
8
- value: {
9
- marginTop: 8,
10
- marginBottom: 12,
11
- },
12
- repeatWrap: {
13
- flexDirection: 'row',
14
- justifyContent: 'space-around',
15
- marginTop: 16,
16
- },
17
- repeatItem: {
18
- width: 24,
19
- height: 24,
20
- justifyContent: 'center',
21
- alignItems: 'center',
22
- borderRadius: 12,
23
- borderWidth: 0,
24
- borderColor: Colors.Orange,
25
- },
26
- repeatItemSelected: {
27
- borderWidth: 1,
28
- },
29
- repeatText: {
30
- lineHeight: 16,
31
- },
32
- curtainText: {
33
- fontSize: 17,
34
- marginTop: 12,
35
- color: Colors.Gray9,
36
- },
37
- boder: {
38
- borderBottomWidth: 1,
39
- borderColor: Colors.Gray4,
40
- },
41
- });
@@ -1,110 +0,0 @@
1
- import React, { memo, useCallback, useState } from 'react';
2
- import { View } from 'react-native';
3
- import { useTranslations } from '../../../hooks/Common/useTranslations';
4
-
5
- import Text from '../../Text';
6
- import { ModalCustom } from '../../Modal';
7
- import ViewButtonBottom from '../../ViewButtonBottom';
8
- import WheelDateTimePicker from '../../WheelDateTimePicker';
9
- import moment from 'moment';
10
- import { useBoolean } from '../../../hooks/Common';
11
- import RecurringDetail from './RecurringDetail';
12
- import _TextInput from '../../../commons/Form/TextInput';
13
- import styles from './MenuActionAddScheduleStyle';
14
-
15
- const MenuActionAddSchedule = memo(({ visible, hideModal, onItemClick }) => {
16
- const t = useTranslations();
17
-
18
- const [stateDateTimePicker, setStateDateTimePicker] = useState({
19
- isVisible: false,
20
- mode: 'time',
21
- defaultValue: moment().valueOf(),
22
- setter: null,
23
- });
24
-
25
- const [lockShowing, releaseLockShowing, acquireLockShowing] =
26
- useBoolean(true);
27
- const [recurringTimeStart, setRecurringTimeStart] = useState('');
28
- const [recurringTimeEnd, setRecurringTimeEnd] = useState('');
29
- const [recurringTimeRepeat, setRecurringTimeRepeat] = useState('');
30
-
31
- const onShowSetDateTime = useCallback(
32
- (currentValue, setter, mode) => {
33
- acquireLockShowing();
34
- setStateDateTimePicker((state) => ({
35
- ...state,
36
- isVisible: true,
37
- mode: mode,
38
- defaultValue: currentValue,
39
- setter: setter,
40
- }));
41
- },
42
- [setStateDateTimePicker, acquireLockShowing]
43
- );
44
-
45
- const onDateTimePicked = useCallback(
46
- (timeData) => {
47
- const setter = stateDateTimePicker.setter;
48
- setter && setter(moment(timeData));
49
- },
50
- [stateDateTimePicker]
51
- );
52
-
53
- const onHideSetDateTime = useCallback(() => {
54
- acquireLockShowing();
55
- setStateDateTimePicker((state) => ({
56
- ...state,
57
- isVisible: false,
58
- }));
59
- }, [setStateDateTimePicker, acquireLockShowing]);
60
-
61
- return (
62
- <ModalCustom
63
- isVisible={visible}
64
- onBackButtonPress={hideModal}
65
- onBackdropPress={hideModal}
66
- style={styles.container}
67
- >
68
- <View style={styles.popoverStyle}>
69
- <View style={styles.modalWrapper}>
70
- <View style={styles.modalHeader}>
71
- <Text style={styles.modalHeaderText}>{t('add_schedule')}</Text>
72
- <View style={styles.boder} />
73
- <RecurringDetail
74
- onShowSetDateTime={onShowSetDateTime}
75
- recurringTimeStart={recurringTimeStart}
76
- recurringTimeEnd={recurringTimeEnd}
77
- recurringTimeRepeat={recurringTimeRepeat}
78
- setRecurringTimeStart={setRecurringTimeStart}
79
- setRecurringTimeEnd={setRecurringTimeEnd}
80
- setRecurringTimeRepeat={setRecurringTimeRepeat}
81
- />
82
-
83
- <Text style={styles.subName}>{t('schedule_name')}</Text>
84
- <_TextInput
85
- placeholder={t('enter_name')}
86
- wrapStyle={styles.noMarginTop}
87
- textInputStyle={styles.textInput}
88
- />
89
- <View style={styles.ViewButtonBottom}>
90
- <ViewButtonBottom
91
- leftTitle={t('cancel')}
92
- onLeftClick={hideModal}
93
- rightTitle={t('done')}
94
- />
95
- </View>
96
- <WheelDateTimePicker
97
- mode={stateDateTimePicker.mode}
98
- isVisible={stateDateTimePicker.isVisible && lockShowing}
99
- defaultValue={stateDateTimePicker.defaultValue}
100
- onPicked={onDateTimePicked}
101
- onCancel={onHideSetDateTime}
102
- onHide={releaseLockShowing}
103
- />
104
- </View>
105
- </View>
106
- </View>
107
- </ModalCustom>
108
- );
109
- });
110
- export default MenuActionAddSchedule;
@@ -1,69 +0,0 @@
1
- import { Colors } from '../../../configs';
2
- import { StyleSheet } from 'react-native';
3
-
4
- export default StyleSheet.create({
5
- container: {
6
- flex: 1,
7
- margin: 0,
8
- },
9
- popoverStyle: {
10
- width: '100%',
11
- backgroundColor: Colors.White,
12
- bottom: 0,
13
- left: 0,
14
- position: 'absolute',
15
- borderRadius: 10,
16
- },
17
- modalWrapper: {
18
- flex: 1,
19
- flexDirection: 'column',
20
- backgroundColor: Colors.White,
21
- borderRadius: 10,
22
- },
23
- modalHeader: {
24
- padding: 16,
25
- backgroundColor: Colors.White,
26
- justifyContent: 'flex-start',
27
- },
28
- modalHeaderText: {
29
- fontSize: 17,
30
- lineHeight: 24,
31
- color: Colors.Gray9,
32
- fontWeight: 'bold',
33
- borderTopLeftRadius: 20,
34
- borderTopRightRadius: 20,
35
- marginVertical: 20,
36
- },
37
- boder: {
38
- borderBottomWidth: 1,
39
- borderColor: Colors.Gray4,
40
- },
41
- subName: {
42
- color: Colors.Gray8,
43
- marginTop: 12,
44
- },
45
- ViewButtonBottom: {
46
- borderTopWidth: 1,
47
- borderTopColor: Colors.Gray4,
48
- },
49
- scheduleName: {
50
- fontSize: 17,
51
- marginTop: 12,
52
- color: Colors.Gray9,
53
- marginBottom: 12,
54
- },
55
- noMarginTop: {
56
- marginTop: 0,
57
- backgroundColor: Colors.White,
58
- },
59
- textInput: {
60
- marginTop: 0,
61
- borderWidth: 0,
62
- borderBottomWidth: 1,
63
- borderBottomColor: Colors.Gray4,
64
- paddingLeft: 0,
65
- backgroundColor: Colors.White,
66
- fontSize: 17,
67
- color: Colors.Gray9,
68
- },
69
- });
@@ -1,97 +0,0 @@
1
- import React, { useCallback } from 'react';
2
- import { View, TouchableOpacity } from 'react-native';
3
- import { useTranslations } from '../../../hooks/Common/useTranslations';
4
-
5
- import Text from '../../../commons/Text';
6
- import { Colors } from '../../../configs';
7
- import { REPEAT_ITEMS } from '../../../screens/GuestInfo/constant';
8
- import styles from './AccessScheduleDetailStyles';
9
-
10
- const RecurringDetail = ({
11
- onShowSetDateTime,
12
- recurringTimeStart,
13
- recurringTimeEnd,
14
- recurringTimeRepeat,
15
- setRecurringTimeStart,
16
- setRecurringTimeEnd,
17
- setRecurringTimeRepeat,
18
- }) => {
19
- const t = useTranslations();
20
- const onSetTimeStart = useCallback(() => {
21
- onShowSetDateTime();
22
- }, [onShowSetDateTime]);
23
-
24
- const onSetTimeEnd = useCallback(() => {
25
- onShowSetDateTime();
26
- }, [onShowSetDateTime]);
27
-
28
- const onSetRepeat = useCallback(
29
- (item) => {
30
- const index = recurringTimeRepeat.indexOf(item.value);
31
- if (index !== -1) {
32
- setRecurringTimeRepeat([
33
- ...recurringTimeRepeat.slice(0, index),
34
- ...recurringTimeRepeat.slice(index + 1),
35
- ]);
36
- } else {
37
- setRecurringTimeRepeat([...recurringTimeRepeat, item.value]);
38
- }
39
- },
40
- [recurringTimeRepeat, setRecurringTimeRepeat]
41
- );
42
-
43
- const renderRepeatItem = useCallback(
44
- (item, index, isSelected) => {
45
- return (
46
- <TouchableOpacity
47
- key={index}
48
- style={[styles.repeatItem, isSelected && styles.repeatItemSelected]}
49
- onPress={() => onSetRepeat(item)}
50
- >
51
- <Text
52
- type="Body"
53
- lineHeight={16}
54
- color={isSelected ? Colors.Orange : item.color}
55
- style={styles.repeatText}
56
- >
57
- {item.text}
58
- </Text>
59
- </TouchableOpacity>
60
- );
61
- },
62
- [onSetRepeat]
63
- );
64
-
65
- return (
66
- <View>
67
- <Text style={styles.curtainText}>{t('curtain_opens')}</Text>
68
- <TouchableOpacity onPress={onSetTimeStart}>
69
- <Text type="Body" color={Colors.Orange} style={styles.value}>
70
- 07:00 AM
71
- </Text>
72
- </TouchableOpacity>
73
- <View style={styles.boder} />
74
- <Text style={styles.curtainText}>{t('curtain_closes')}</Text>
75
- <TouchableOpacity onPress={onSetTimeEnd}>
76
- <Text type="Body" color={Colors.Orange} style={styles.value}>
77
- 12:00 AM
78
- </Text>
79
- </TouchableOpacity>
80
- <View style={styles.boder} />
81
- <Text type="Body" color={Colors.Gray8} style={styles.title}>
82
- {t('repeat')}
83
- </Text>
84
- <View style={styles.repeatWrap}>
85
- {REPEAT_ITEMS.map((item, index) =>
86
- renderRepeatItem(
87
- item,
88
- index,
89
- recurringTimeRepeat.includes(item.value)
90
- )
91
- )}
92
- </View>
93
- </View>
94
- );
95
- };
96
-
97
- export default RecurringDetail;