@eohjsc/react-native-smart-city 0.4.59 → 0.4.61

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 (40) hide show
  1. package/package.json +1 -2
  2. package/src/commons/Action/ItemQuickAction.js +1 -1
  3. package/src/commons/Action/__test__/ItemQuickAction.test.js +22 -8
  4. package/src/commons/Automate/ItemAutomate.js +4 -9
  5. package/src/commons/Button/index.js +4 -2
  6. package/src/commons/Device/RainningSensor/CurrentRainSensor.js +49 -36
  7. package/src/commons/Grid/GridItem.js +20 -0
  8. package/src/commons/Grid/GridItemStyles.js +32 -0
  9. package/src/configs/API.js +0 -2
  10. package/src/configs/Constants.js +0 -1
  11. package/src/context/actionType.ts +1 -0
  12. package/src/context/reducer.ts +19 -1
  13. package/src/screens/Automate/AddNewAction/ChooseAction.js +0 -2
  14. package/src/screens/Automate/AddNewAction/ChooseConfig.js +46 -161
  15. package/src/screens/Automate/AddNewAction/Components/SelectDevices.js +2 -6
  16. package/src/screens/Automate/AddNewAction/NewActionWrapper.js +10 -6
  17. package/src/screens/Automate/AddNewAction/SelectMonitorDevices.js +1 -0
  18. package/src/screens/Automate/AddNewAction/SetupConfigCondition.js +143 -173
  19. package/src/screens/Automate/AddNewAction/Styles/SelectActionStyles.js +8 -0
  20. package/src/screens/Automate/AddNewAction/Styles/SetupSensorStyles.js +29 -62
  21. package/src/screens/Automate/AddNewAction/__test__/ChooseAction.test.js +77 -9
  22. package/src/screens/Automate/AddNewAction/__test__/ChooseConfig.test.js +23 -83
  23. package/src/screens/Automate/AddNewAction/__test__/SelectControlDevices.test.js +2 -19
  24. package/src/screens/Automate/AddNewAction/__test__/SetupConfigCondition.test.js +125 -94
  25. package/src/screens/Automate/AddNewAutoSmart/AddAutomationTypeSmart.js +0 -4
  26. package/src/screens/Automate/AddNewAutoSmart/AddTypeSmart.js +24 -27
  27. package/src/screens/Automate/AddNewAutoSmart/AddUnknownTypeSmart.js +0 -4
  28. package/src/screens/Automate/AddNewAutoSmart/__test__/AddNewAutoSmart.test.js +1 -21
  29. package/src/screens/Automate/ScriptDetail/utils.js +42 -19
  30. package/src/screens/Automate/index.js +2 -4
  31. package/src/screens/Device/__test__/sensorDisplayItem.test.js +9 -0
  32. package/src/screens/Device/components/SensorDisplayItem.js +3 -0
  33. package/src/screens/Device/hooks/__test__/useEvaluateValue.test.js +1 -1
  34. package/src/screens/Device/hooks/useEvaluateValue.js +10 -6
  35. package/src/screens/Notification/__test__/Notification.test.js +10 -0
  36. package/src/screens/Unit/__test__/AddMenu.test.js +76 -0
  37. package/src/screens/WaterQualityGuide/__test__/index.test.js +0 -5
  38. package/src/utils/I18n/translations/en.js +2 -0
  39. package/src/utils/I18n/translations/vi.js +2 -0
  40. package/src/utils/Route/index.js +5 -0
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.4.59",
4
+ "version": "0.4.61",
5
5
  "description": "TODO",
6
6
  "main": "index.js",
7
7
  "files": [
@@ -37,7 +37,6 @@
37
37
  "android-deploy-test": "bundle exec fastlane android beta",
38
38
  "reset-cache": "react-native start --reset-cache",
39
39
  "merge_conflict": "yarn jest && yarn update_coverage_result && yarn check_coverage_config",
40
- "jest": "jest --detectOpenHandles",
41
40
  "jest1": "jest --detectOpenHandles --coverage=0",
42
41
  "example": "yarn --cwd example",
43
42
  "pods": "cd example && pod-install --quiet",
@@ -18,7 +18,7 @@ const ItemQuickAction = memo(
18
18
  interval,
19
19
  will_auto_update_status,
20
20
  } = quick_action || {};
21
- const [action, setAction] = useState(sensor.action);
21
+ const [action, setAction] = useState(sensor?.action);
22
22
  // eslint-disable-next-line no-unused-vars
23
23
  const [configValues, _] = useConfigGlobalState('configValues');
24
24
  const [isOn, setIsOn] = useState(false);
@@ -8,7 +8,6 @@ import { factory } from 'factory-girl';
8
8
  import IconComponent from '../../IconComponent';
9
9
  import { IconOutline } from '@ant-design/icons-react-native';
10
10
  import Toast from 'react-native-toast-message';
11
-
12
11
  class Sensor {}
13
12
 
14
13
  factory.define('Sensor', Sensor, {});
@@ -63,21 +62,17 @@ describe('Test ItemQuickAction', () => {
63
62
  });
64
63
 
65
64
  it('render with no action', async () => {
66
- const newSensor = await factory.build('Sensor');
67
65
  await act(async () => {
68
- tree = await create(<ItemQuickAction sensor={newSensor} />);
66
+ tree = await create(<ItemQuickAction />);
69
67
  });
70
68
  const instance = tree.root;
71
- const buttonOnActionPress = instance.find(
69
+ const buttonOnActionPress = instance.findAll(
72
70
  (el) =>
73
71
  el.props.accessibilityLabel ===
74
72
  `${AccessibilityLabel.ITEM_QUICK_ACTION_PRESS}-${sensor?.id}` &&
75
73
  el.type === TouchableOpacity
76
74
  );
77
- await act(async () => {
78
- await buttonOnActionPress.props.onPress();
79
- });
80
- expect(Toast.show).not.toBeCalled();
75
+ expect(buttonOnActionPress).toHaveLength(0);
81
76
  });
82
77
 
83
78
  it('click quick action icon down , isSendingCommand = true', async () => {
@@ -244,4 +239,23 @@ describe('Test ItemQuickAction', () => {
244
239
  expect(icon.props.icon).toEqual(sensor.quick_action.off_action.icon);
245
240
  expect(icon.props.icon).not.toEqual(sensor.quick_action.on_action.icon);
246
241
  };
242
+ it('render quick action only show status can not control', async () => {
243
+ sensor.quick_action.off_action = null;
244
+ sensor.quick_action.on_action = null;
245
+
246
+ await act(async () => {
247
+ tree = await create(<ItemQuickAction sensor={sensor} />);
248
+ });
249
+ const instance = tree.root;
250
+ const buttonOnActionPress = instance.find(
251
+ (el) =>
252
+ el.props.accessibilityLabel ===
253
+ `${AccessibilityLabel.ITEM_QUICK_ACTION_PRESS}-${sensor?.id}` &&
254
+ el.type === TouchableOpacity
255
+ );
256
+ await act(async () => {
257
+ await buttonOnActionPress.props.onPress();
258
+ });
259
+ expect(Toast.show).not.toBeCalled();
260
+ });
247
261
  });
@@ -20,11 +20,11 @@ const ItemAutomate = ({
20
20
  const item = AUTOMATES[automate?.type];
21
21
  const isItemOneTap = AUTOMATES[automate?.type] === AUTOMATES.one_tap;
22
22
  const Icon = item?.icon;
23
- const valueEvaluation = useGetEvaluateValue(automate?.config);
23
+ const valueEvaluations = useGetEvaluateValue(automate?.config, automate.unit);
24
24
 
25
25
  const textCondition = useMemo(() => {
26
- return generateAutomationConditionText(automate, valueEvaluation, t);
27
- }, [automate, t, valueEvaluation]);
26
+ return generateAutomationConditionText(automate, valueEvaluations, t);
27
+ }, [automate, t, valueEvaluations]);
28
28
 
29
29
  const renderText = useMemo(() => {
30
30
  if (textCondition) {
@@ -45,12 +45,7 @@ const ItemAutomate = ({
45
45
  return;
46
46
  }
47
47
 
48
- setSelectedIndex((currentIndex) => {
49
- if (currentIndex !== index) {
50
- return index;
51
- }
52
- return -1;
53
- });
48
+ setSelectedIndex(index);
54
49
  }, [index, setSelectedIndex, onPress]);
55
50
 
56
51
  return (
@@ -121,10 +121,10 @@ const TextSize = {
121
121
  // Type
122
122
  // auth, primary, info, cancel, disabled, disabledBorder, primaryBorder, alert, alertBorder, underline, setupBorder
123
123
 
124
- export default ({
124
+ const Button = ({
125
125
  title,
126
126
  onPress,
127
- width,
127
+ width = 100,
128
128
  height = 48,
129
129
  activeOpacity,
130
130
  type,
@@ -178,6 +178,8 @@ export default ({
178
178
  );
179
179
  };
180
180
 
181
+ export default Button;
182
+
181
183
  const styles = StyleSheet.create({
182
184
  button: {
183
185
  width: '100%',
@@ -9,43 +9,57 @@ import IconComponent from '../../IconComponent';
9
9
  import images from '../../../configs/Images';
10
10
  import FImage from '../../FImage';
11
11
 
12
- const CurrentRainSensor = memo(({ data = [], isWidgetOrder }) => {
13
- const item = data.length
14
- ? data[0]
15
- : {
16
- evaluate: {},
17
- };
18
- const { text, backgroundColor, borderColor, icon, icon_kit_data } =
19
- item.evaluate || {};
12
+ const CurrentRainSensor = memo(
13
+ ({
14
+ data = [],
15
+ isWidgetOrder,
16
+ size = 180,
17
+ textType = 'H2',
18
+ iconSize = 30,
19
+ }) => {
20
+ const item = data.length
21
+ ? data[0]
22
+ : {
23
+ evaluate: {},
24
+ };
25
+ const { text, backgroundColor, borderColor, icon, icon_kit_data } =
26
+ item.evaluate || {};
20
27
 
21
- return (
22
- <View style={[styles.standard, isWidgetOrder && styles.marginBottomZero]}>
23
- <CircleView
24
- size={190}
25
- backgroundColor={backgroundColor}
26
- borderWidth={2}
27
- borderColor={borderColor}
28
- style={styles.center}
29
- >
30
- <LinearGradient
31
- style={styles.linearView}
32
- colors={[Colors.TransparentWhite, 'white']}
33
- start={{ x: 1, y: 0 }}
34
- end={{ x: 1, y: 1 }}
35
- />
36
- {icon_kit_data?.icon || icon ? (
37
- <IconComponent icon={icon_kit_data?.icon || icon} />
38
- ) : (
39
- <FImage
40
- source={images.activeCurrentSensor}
41
- style={styles.iconDefault}
28
+ return (
29
+ <View style={[styles.standard, isWidgetOrder && styles.marginBottomZero]}>
30
+ <CircleView
31
+ size={size}
32
+ backgroundColor={backgroundColor}
33
+ borderWidth={2}
34
+ borderColor={borderColor}
35
+ style={styles.center}
36
+ >
37
+ <LinearGradient
38
+ style={styles.linearView}
39
+ colors={[Colors.TransparentWhite, 'white']}
40
+ start={{ x: 1, y: 0 }}
41
+ end={{ x: 1, y: 1 }}
42
42
  />
43
- )}
44
- <Text style={styles.text}>{text}</Text>
45
- </CircleView>
46
- </View>
47
- );
48
- });
43
+ {icon_kit_data?.icon || icon ? (
44
+ <IconComponent
45
+ size={iconSize}
46
+ iconSize={iconSize}
47
+ icon={icon_kit_data?.icon || icon}
48
+ />
49
+ ) : (
50
+ <FImage
51
+ source={images.activeCurrentSensor}
52
+ style={styles.iconDefault}
53
+ />
54
+ )}
55
+ <Text type={textType} style={styles.text}>
56
+ {text}
57
+ </Text>
58
+ </CircleView>
59
+ </View>
60
+ );
61
+ }
62
+ );
49
63
 
50
64
  export default CurrentRainSensor;
51
65
 
@@ -76,7 +90,6 @@ const styles = StyleSheet.create({
76
90
  text: {
77
91
  marginTop: 8,
78
92
  lineHeight: 32,
79
- fontSize: 24,
80
93
  },
81
94
  iconDefault: {
82
95
  width: 37,
@@ -0,0 +1,20 @@
1
+ import React, { memo } from 'react';
2
+ import { TouchableWithoutFeedback, View } from 'react-native';
3
+ import styles from './GridItemStyles';
4
+
5
+ const GridItem = memo(
6
+ ({ icon, accessibilityLabel, selected, onPress, item, children }) => {
7
+ const isActive = selected && styles.active;
8
+
9
+ return (
10
+ <TouchableWithoutFeedback
11
+ onPress={() => onPress && onPress(item)}
12
+ accessibilityLabel={accessibilityLabel}
13
+ >
14
+ <View style={[styles.container, isActive]}>{children}</View>
15
+ </TouchableWithoutFeedback>
16
+ );
17
+ }
18
+ );
19
+
20
+ export default GridItem;
@@ -0,0 +1,32 @@
1
+ import { StyleSheet } from 'react-native';
2
+ import { Constants, Colors } from '../../configs';
3
+
4
+ const marginItem = 12;
5
+ const marginHorizontal = 16;
6
+ const widthItem = (Constants.width - marginHorizontal * 2 - marginItem) / 2;
7
+
8
+ export default StyleSheet.create({
9
+ container: {
10
+ padding: 12,
11
+ borderRadius: 10,
12
+ shadowColor: Colors.Shadow,
13
+ shadowOffset: {
14
+ width: 0,
15
+ height: 2,
16
+ },
17
+ shadowOpacity: 0.1,
18
+ shadowRadius: 3,
19
+ elevation: 4,
20
+ width: widthItem,
21
+ backgroundColor: Colors.White,
22
+ justifyContent: 'space-between',
23
+ marginBottom: 16,
24
+ },
25
+ active: {
26
+ borderColor: Colors.Primary,
27
+ borderWidth: 2,
28
+ },
29
+ lineHeight22: {
30
+ lineHeight: 22,
31
+ },
32
+ });
@@ -181,8 +181,6 @@ const API = {
181
181
  SET_READ: (id) => `/notifications/eoh/${id}/set_read/`,
182
182
  },
183
183
  VALUE_EVALUATIONS: () => '/property_manager/config_value_evaluations/',
184
- FETCH_VALUE_EVALUATION: (id) =>
185
- `/property_manager/config_value_evaluations/${id}/`,
186
184
  EXTERNAL: {
187
185
  GOOGLE_MAP: {
188
186
  AUTO_COMPLETE:
@@ -119,7 +119,6 @@ export const AUTOMATE_TYPE = {
119
119
  ONE_TAP: 'one_tap',
120
120
  VALUE_CHANGE: 'value_change',
121
121
  SCHEDULE: 'schedule',
122
- EVENT: 'event',
123
122
  };
124
123
 
125
124
  export const AUTOMATE_TABS = {
@@ -24,6 +24,7 @@ export const Action = {
24
24
  CHANGE_HOME_ASSISTANT_CONN_STATE: 'CHANGE_HOME_ASSISTANT_CONN_STATE',
25
25
  SET_LG_THINQ_CONNECTED: 'SET_LG_THINQ_CONNECTED',
26
26
  UPDATE_VALUE_EVALUATIONS: 'UPDATE_VALUE_EVALUATIONS',
27
+ INIT_VALUE_EVALUATIONS: 'INIT_VALUE_EVALUATIONS',
27
28
  NEED_UPDATE_VALUE_EVALUATIONS: 'NEED_UPDATE_VALUE_EVALUATIONS',
28
29
  ON_RECEIVE_NOTIFICATION: 'ON_RECEIVE_NOTIFICATION',
29
30
  SET_DEVICES_STATUS: 'SET_DEVICES_STATUS',
@@ -416,13 +416,31 @@ export const reducer = (currentState: ContextData, action: Action) => {
416
416
  data,
417
417
  (dict, item) => {
418
418
  item.configs.map((configId) => {
419
- dict[configId] = item;
419
+ if (!dict[configId]) {
420
+ dict[configId] = [item];
421
+ } else {
422
+ dict[configId] = [...dict[configId], item];
423
+ }
420
424
  });
421
425
  return dict;
422
426
  },
423
427
  currentState.valueEvaluations
424
428
  ),
425
429
  };
430
+
431
+ case Action.INIT_VALUE_EVALUATIONS:
432
+ // eslint-disable-next-line no-case-declarations
433
+ const { configId } = payload;
434
+ // eslint-disable-next-line no-case-declarations
435
+ const valueEvaluations = currentState.valueEvaluations || {};
436
+ if (valueEvaluations[configId] === undefined) {
437
+ valueEvaluations[configId] = [];
438
+ }
439
+ return {
440
+ ...currentState,
441
+ valueEvaluations,
442
+ };
443
+
426
444
  case Action.NEED_UPDATE_VALUE_EVALUATIONS:
427
445
  return {
428
446
  ...currentState,
@@ -57,8 +57,6 @@ const RenderActionItem = ({ device, item, handleOnSelectAction, index }) => {
57
57
  onSelectAction={handleOnSelectAction}
58
58
  />
59
59
  );
60
- default:
61
- return null;
62
60
  }
63
61
  };
64
62
 
@@ -1,47 +1,29 @@
1
1
  import React, { useCallback, useEffect, useState } from 'react';
2
- import { Image, TouchableOpacity, View } from 'react-native';
2
+ import { View } from 'react-native';
3
3
  import { useNavigation } from '@react-navigation/native';
4
4
 
5
5
  import { useTranslations } from '../../../hooks/Common/useTranslations';
6
6
  import Text from '../../../commons/Text';
7
7
  import { axiosGet } from '../../../utils/Apis/axios';
8
- import { API, Colors, Images } from '../../../configs';
8
+ import { API, Colors } from '../../../configs';
9
9
  import Routes from '../../../utils/Route';
10
10
  import styles from './Styles/SelectActionStyles';
11
- import { TitleCheckBox } from '../../Sharing/Components';
12
11
  import { LoadingSelectAction } from './Components';
13
- import { ToastBottomHelper } from '../../../utils/Utils';
14
- import {
15
- generateAutomationConditionText,
16
- generateAutomationDataConditionText,
17
- } from '../ScriptDetail/utils';
18
- import { useSCContextSelector } from '../../../context';
19
12
  import { AUTOMATE_TYPE } from '../../../configs/Constants';
20
13
  import NewActionWrapper from './NewActionWrapper';
14
+ import GridItem from '../../../commons/Grid/GridItem';
21
15
 
22
16
  const ChooseConfig = ({ route }) => {
23
17
  const t = useTranslations();
24
18
  const { navigate } = useNavigation();
25
- const {
26
- device,
27
- automate = {},
28
- newCondition,
29
- closeScreen,
30
- } = route?.params || {};
19
+ const { device, automate = {}, closeScreen } = route?.params || {};
31
20
 
32
21
  const [configs, setConfigs] = useState([]);
33
- const [checkedItem, setCheckedItem] = useState({ id: automate?.config_id });
22
+ const [selectedConfigId, setSelectedConfigId] = useState(automate?.config_id);
34
23
  const [isLoading, setIsLoading] = useState(false);
35
- const valueEvaluations = useSCContextSelector((state) => {
36
- return state.valueEvaluations;
37
- });
38
- const [conditions, setConditions] = useState({});
39
24
  const fetchData = useCallback(async () => {
40
25
  setIsLoading(true);
41
26
  const params = {};
42
- if (automate?.type === AUTOMATE_TYPE.EVENT) {
43
- params.type = 'event';
44
- }
45
27
 
46
28
  const { success, data: automateData } = await axiosGet(
47
29
  API.AUTOMATE.DISPLAY_CONFIGS(device.id),
@@ -52,157 +34,60 @@ const ChooseConfig = ({ route }) => {
52
34
  setConfigs(automateData);
53
35
  }
54
36
  setIsLoading(false);
55
- }, [device.id, automate?.type]);
56
-
57
- const onSave = useCallback(() => {
58
- let condition = conditions[checkedItem?.id];
59
- const isDefault =
60
- automate?.config_id && automate?.config_id === checkedItem?.id;
61
- if (!condition && !isDefault) {
62
- ToastBottomHelper.error(t('please_choose_condition_before_continue'));
63
- return;
64
- }
65
-
66
- navigate(Routes.ValueChangeName, {
67
- automate: {
68
- ...automate,
69
- ...condition,
70
- },
71
- closeScreen,
72
- });
73
- }, [conditions, checkedItem?.id, navigate, automate, closeScreen, t]);
74
-
75
- const onChecked = useCallback(
76
- (_, isChecked, id) => {
77
- setCheckedItem(isChecked ? configs.find((i) => i?.id === id) : {});
78
- },
79
- [configs]
80
- );
37
+ }, [device.id]);
81
38
 
82
- const renderCondition = useCallback(
83
- (item) => {
84
- return generateAutomationDataConditionText(
85
- automate?.type,
86
- item.name,
87
- conditions[item.id],
88
- item.value_evaluation || {
89
- // backward compatible
90
- template: item.evaluate_template,
91
- configuration: item.evaluate_configuration,
92
- },
93
- t
94
- );
39
+ const goToSetupConfig = useCallback(
40
+ (config) => {
41
+ setSelectedConfigId(config?.id);
42
+ automate.config = config?.id;
43
+ navigate(Routes.SetupConfigCondition, {
44
+ config,
45
+ automate,
46
+ closeScreen,
47
+ });
95
48
  },
96
- [automate?.type, conditions, t]
97
- );
98
-
99
- const renderConfigs = useCallback(
100
- (configs) => {
101
- const onPressItem = (item) => () => {
102
- navigate(Routes.SetupConfigCondition, {
103
- item,
104
- defaultCondition: conditions[item.id],
105
- closeScreen,
106
- });
107
- };
108
- if (configs.length) {
109
- return configs.map((item) => {
110
- const hasCondition = conditions[item.id];
111
- const isChecked = checkedItem?.id === item?.id;
112
- const isDefault = automate?.config_id === item?.id;
113
- return (
114
- <View style={styles.wrapItem} key={item?.id}>
115
- <TitleCheckBox
116
- onPress={onChecked}
117
- id={item?.id}
118
- title={item?.name}
119
- titleStyle={styles.titleStyle}
120
- wrapStyle={styles.wrapStyleCheckBox}
121
- isChecked={isChecked}
122
- />
123
- <TouchableOpacity
124
- onPress={onPressItem(item)}
125
- style={[styles.wrapCondition, styles.shadowView]}
126
- accessibilityLabel={`config-${item.id}`}
127
- >
128
- <Text type="Body" color={Colors.Gray7}>
129
- {t('condition')}
130
- </Text>
131
- <Text
132
- numberOfLines={1}
133
- type="H4"
134
- semibold={isChecked}
135
- style={styles.description}
136
- >
137
- {hasCondition
138
- ? renderCondition(item)
139
- : isDefault
140
- ? generateAutomationConditionText(
141
- automate,
142
- valueEvaluations[automate?.config_id],
143
- t
144
- )
145
- : t('no_condition')}
146
- </Text>
147
- {hasCondition && (
148
- <Image source={Images.arrowBack} style={styles.arrowRight} />
149
- )}
150
- </TouchableOpacity>
151
- </View>
152
- );
153
- });
154
- } else {
155
- return (
156
- <View style={styles.textCenter}>
157
- <Text type="Body" center color={Colors.Gray7}>
158
- {t('end_device_not_support_script', {
159
- not_support: t(automate?.type),
160
- support:
161
- automate?.type === AUTOMATE_TYPE.EVENT
162
- ? t(AUTOMATE_TYPE.VALUE_CHANGE)
163
- : t(AUTOMATE_TYPE.EVENT),
164
- })}
165
- </Text>
166
- </View>
167
- );
168
- }
169
- },
170
- [
171
- automate,
172
- checkedItem?.id,
173
- closeScreen,
174
- conditions,
175
- navigate,
176
- onChecked,
177
- renderCondition,
178
- t,
179
- valueEvaluations,
180
- ]
49
+ [automate, closeScreen, navigate]
181
50
  );
182
51
 
183
52
  useEffect(() => {
184
53
  fetchData();
185
54
  }, [fetchData]);
186
55
 
187
- useEffect(() => {
188
- newCondition &&
189
- setConditions((prev) => ({
190
- ...prev,
191
- [newCondition.config]: newCondition,
192
- }));
193
- }, [newCondition]);
194
-
195
56
  return (
196
57
  <NewActionWrapper
197
58
  name={t('set_up {name}', { name: device?.name })}
198
59
  nextTitle={t('continue')}
199
- onNext={onSave}
200
- canNext={checkedItem?.id}
201
60
  >
202
- {isLoading ? (
203
- <LoadingSelectAction style={styles.container} />
204
- ) : (
205
- renderConfigs(configs)
61
+ {isLoading && <LoadingSelectAction style={styles.container} />}
62
+ {!isLoading && !configs.length && (
63
+ <View style={styles.textCenter}>
64
+ <Text type="Body" center color={Colors.Gray7}>
65
+ {t('end_device_not_support_script', {
66
+ not_support: t(automate?.type),
67
+ support:
68
+ automate?.type === AUTOMATE_TYPE.EVENT
69
+ ? t(AUTOMATE_TYPE.VALUE_CHANGE)
70
+ : t(AUTOMATE_TYPE.EVENT),
71
+ })}
72
+ </Text>
73
+ </View>
74
+ )}
75
+ {!isLoading && (
76
+ <View style={styles.boxDevices}>
77
+ {configs.map((config) => (
78
+ <GridItem
79
+ selected={config?.id === selectedConfigId}
80
+ onPress={goToSetupConfig}
81
+ item={config}
82
+ accessibilityLabel={`config-${config?.id}`}
83
+ key={config?.id}
84
+ >
85
+ <Text numberOfLines={1} semibold type="Body" color={Colors.Gray9}>
86
+ {config.name}
87
+ </Text>
88
+ </GridItem>
89
+ ))}
90
+ </View>
206
91
  )}
207
92
  </NewActionWrapper>
208
93
  );
@@ -30,15 +30,11 @@ const SelectDevices = ({
30
30
  } else {
31
31
  setSelectedDevice(sensor);
32
32
  }
33
+ onPressContinue(sensor, indexStation);
33
34
  };
34
35
 
35
36
  return (
36
- <NewActionWrapper
37
- nextTitle={t('continue')}
38
- onNext={() => onPressContinue(selectedDevice, indexStation)}
39
- canNext={Object.keys(selectedDevice || {}).length}
40
- name={title}
41
- >
37
+ <NewActionWrapper name={title}>
42
38
  {listStation.length ? (
43
39
  <NavBar
44
40
  listStation={listStation}
@@ -11,6 +11,8 @@ import { AccessibilityLabel } from '../../../configs/Constants';
11
11
  import { HeaderCustom } from '../../../commons';
12
12
 
13
13
  const NewActionWrapper = ({ name, children, canNext, onNext, nextTitle }) => {
14
+ const hasNext =
15
+ canNext !== undefined || onNext !== undefined || nextTitle !== undefined;
14
16
  const { navigate } = useNavigation();
15
17
  const { params = {} } = useRoute();
16
18
  const { closeScreen } = params;
@@ -42,12 +44,14 @@ const NewActionWrapper = ({ name, children, canNext, onNext, nextTitle }) => {
42
44
  wrapTitleStyle={styles.wrapTitleStyle}
43
45
  />
44
46
  <KeyboardAwareScrollView>{children}</KeyboardAwareScrollView>
45
- <BottomButtonView
46
- style={styles.bottomButtonView}
47
- mainTitle={nextTitle}
48
- onPressMain={onNext}
49
- typeMain={canNext ? 'primary' : 'disabled'}
50
- />
47
+ {hasNext && (
48
+ <BottomButtonView
49
+ style={styles.bottomButtonView}
50
+ mainTitle={nextTitle}
51
+ onPressMain={onNext}
52
+ typeMain={canNext ? 'primary' : 'disabled'}
53
+ />
54
+ )}
51
55
  </View>
52
56
  );
53
57
  };
@@ -30,6 +30,7 @@ const SelectMonitorDevices = ({ route }) => {
30
30
  configs,
31
31
  (response) => {
32
32
  const { success, data } = response;
33
+
33
34
  if (success) {
34
35
  const newData = data.filter((item) => item.sensors.length > 0);
35
36
  const listMenu = newData.map((item, index) => ({