@eohjsc/react-native-smart-city 0.7.21 → 0.7.23

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 (101) hide show
  1. package/package.json +1 -1
  2. package/src/Images/Common/default_end_device.png +0 -0
  3. package/src/commons/ActionGroup/TerminalBoxTemplate.js +3 -0
  4. package/src/commons/ActionTemplate/OnOffButtonAction.js +38 -4
  5. package/src/commons/ActionTemplate/OnOffSimpleAction.js +55 -15
  6. package/src/commons/ActionTemplate/OnOffSmartLockAction.js +46 -8
  7. package/src/commons/ActionTemplate/SwitchButtonAction.js +35 -4
  8. package/src/commons/ActionTemplate/ThreeButtonAction.js +13 -3
  9. package/src/commons/ActionTemplate/__test__/OnOffButtonAction.test.js +46 -7
  10. package/src/commons/ActionTemplate/__test__/OnOffSimpleAction.test.js +66 -6
  11. package/src/commons/ActionTemplate/__test__/OnOffSmartLockAction.test.js +53 -13
  12. package/src/commons/ActionTemplate/__test__/SwitchButtonAction.test.js +46 -7
  13. package/src/commons/ActionTemplate/__test__/index.test.js +6 -2
  14. package/src/commons/ActionTemplate/index.js +65 -10
  15. package/src/commons/Dashboard/MyUnit/index.js +19 -20
  16. package/src/commons/DevMode/Search.js +1 -1
  17. package/src/commons/Device/RainningSensor/CurrentRainSensor.js +5 -5
  18. package/src/commons/MediaPlayerDetail/MediaPlayerFull.js +26 -32
  19. package/src/commons/OneTapTemplate/StatesGridActionTemplate.js +8 -6
  20. package/src/commons/SubUnit/OneTap/__test__/SubUnitAutomate.test.js +6 -0
  21. package/src/commons/SubUnit/OneTap/index.js +5 -0
  22. package/src/commons/UnitSummary/ConfigHistoryChart/index.js +9 -11
  23. package/src/commons/Widgets/IFrameWithConfig/IFrameWithConfig.js +2 -2
  24. package/src/commons/Widgets/IFrameWithConfig/__tests__/IFrameWithConfig.test.js +1 -1
  25. package/src/configs/API.js +10 -0
  26. package/src/configs/AccessibilityLabel.js +5 -1
  27. package/src/configs/Images.js +1 -0
  28. package/src/navigations/AddMemberStack.js +3 -3
  29. package/src/screens/ActivityLog/__test__/index.test.js +10 -0
  30. package/src/screens/ActivityLog/hooks/index.js +1 -1
  31. package/src/screens/AddCommon/SelectUnit.js +3 -2
  32. package/src/screens/AddLocationMaps/__test__/index.test.js +13 -13
  33. package/src/screens/Automate/AddNewAction/ChooseAction.js +15 -51
  34. package/src/screens/Automate/AddNewAction/SelectControlDevices.js +13 -3
  35. package/src/screens/Automate/AddNewAction/SetupConfigCondition.js +74 -54
  36. package/src/screens/Automate/AddNewAction/__test__/ChooseAction.test.js +114 -4
  37. package/src/screens/Automate/AddNewAction/__test__/ChooseConfig.test.js +9 -11
  38. package/src/screens/Automate/AddNewAction/__test__/SetupConfigCondition.test.js +37 -8
  39. package/src/screens/Automate/AddNewAutoSmart/AddTypeSmart.js +5 -0
  40. package/src/screens/Automate/AddNewAutoSmart/__test__/AddAutomationTypeSmart.test.js +31 -0
  41. package/src/screens/Automate/AddNewAutoSmart/__test__/AddNewAutoSmart.test.js +18 -2
  42. package/src/screens/Automate/Components/InputName.js +7 -6
  43. package/src/screens/Automate/Constants.js +12 -0
  44. package/src/screens/Automate/EditActionsList/UpdateActionScript.js +24 -55
  45. package/src/screens/Automate/EditActionsList/__tests__/UpdateActionScript.test.js +298 -41
  46. package/src/screens/Automate/EditActionsList/__tests__/index.test.js +2 -2
  47. package/src/screens/Automate/EditActionsList/index.js +26 -14
  48. package/src/screens/Automate/MultiUnits.js +9 -1
  49. package/src/screens/Automate/OneTap/__test__/AddNewOneTap.test.js +3 -3
  50. package/src/screens/Automate/ScriptDetail/Components/AddActionScript.js +4 -10
  51. package/src/screens/Automate/ScriptDetail/Components/DeleteScript.js +2 -4
  52. package/src/screens/Automate/ScriptDetail/__test__/index.test.js +78 -0
  53. package/src/screens/Automate/ScriptDetail/index.js +16 -10
  54. package/src/screens/Automate/ScriptDetail/utils.js +39 -35
  55. package/src/screens/Automate/SetSchedule/AddEditConditionSchedule.js +27 -160
  56. package/src/screens/Automate/SetSchedule/EditSchedule.js +269 -0
  57. package/src/screens/Automate/SetSchedule/__test__/AddEditConditionSchedule.test.js +327 -22
  58. package/src/screens/Automate/SetSchedule/__test__/index.test.js +35 -22
  59. package/src/screens/Automate/SetSchedule/components/RepeatOptionsPopup.js +2 -8
  60. package/src/screens/Automate/SetSchedule/index.js +15 -129
  61. package/src/screens/Automate/SetSchedule/styles/indexStyles.js +9 -0
  62. package/src/screens/Automate/__test__/MultiUnits.test.js +6 -1
  63. package/src/screens/Automate/hooks/useAction.js +222 -0
  64. package/src/screens/ConfirmUnitDeletion/__test__/ConfirmUnitDeletion.test.js +69 -13
  65. package/src/screens/ConfirmUnitDeletion/index.js +14 -14
  66. package/src/screens/Device/__test__/detail.test.js +48 -1
  67. package/src/screens/Device/detail.js +46 -3
  68. package/src/screens/PlayBackCamera/__test__/index.test.js +48 -13
  69. package/src/screens/PlayBackCamera/index.js +1 -1
  70. package/src/screens/Sharing/Components/ConfigItem.js +34 -0
  71. package/src/screens/Sharing/Components/DeviceItem.js +77 -0
  72. package/src/screens/Sharing/Components/ItemChangeRole.js +3 -4
  73. package/src/screens/Sharing/Components/ShareDeviceSelector.js +255 -0
  74. package/src/screens/Sharing/Components/Styles/CheckBoxCustomStyles.js +1 -1
  75. package/src/screens/Sharing/Components/Styles/DeviceItemStyles.js +11 -27
  76. package/src/screens/Sharing/{Styles/SelectPermissionStyles.js → Components/Styles/ShareDeviceSelectorStyles.js} +3 -11
  77. package/src/screens/Sharing/Components/SubUnitItem.js +28 -0
  78. package/src/screens/Sharing/Components/SubUnitTreeView.js +68 -0
  79. package/src/screens/Sharing/Components/TitleCheckBox.js +23 -41
  80. package/src/screens/Sharing/Components/__test__/ItemChangeRole.test.js +7 -7
  81. package/src/screens/Sharing/Components/__test__/ShareDeviceSelector.test.js +298 -0
  82. package/src/screens/Sharing/Components/index.js +14 -1
  83. package/src/screens/Sharing/InfoMemberUnit.js +20 -20
  84. package/src/screens/Sharing/SelectShareDevice.js +11 -255
  85. package/src/screens/Sharing/SelectUser.js +12 -12
  86. package/src/screens/Sharing/UpdateShareDevice.js +45 -301
  87. package/src/screens/Sharing/__test__/InfoMemberUnit.test.js +58 -11
  88. package/src/screens/Sharing/__test__/SelectShareDevice.test.js +51 -160
  89. package/src/screens/Sharing/__test__/SelectUser.test.js +72 -10
  90. package/src/screens/Sharing/__test__/UpdateShareDevice.test.js +49 -209
  91. package/src/utils/Apis/axios.js +6 -0
  92. package/src/utils/I18n/translations/en.js +9 -1
  93. package/src/utils/I18n/translations/vi.js +10 -2
  94. package/src/commons/Sharing/StationDevicePermissions.js +0 -204
  95. package/src/screens/Automate/constants.js +0 -0
  96. package/src/screens/Sharing/Components/CheckBoxConfig.js +0 -44
  97. package/src/screens/Sharing/Components/CheckBoxSubUnit.js +0 -35
  98. package/src/screens/Sharing/Components/EndDevice.js +0 -93
  99. package/src/screens/Sharing/Components/Styles/CheckBoxConfigStyles.js +0 -18
  100. package/src/screens/Sharing/Components/Styles/TitleCheckBoxStyles.js +0 -21
  101. package/src/screens/Sharing/Components/__test__/TitleCheckBox.test.js +0 -31
@@ -1,141 +1,27 @@
1
1
  import { useNavigation } from '@react-navigation/native';
2
- import moment from 'moment';
3
- import React, { memo, useCallback, useState } from 'react';
4
- import { ScrollView } from 'react-native';
5
- import Calendar from '../../../commons/Calendar';
6
- import WheelDateTimePicker from '../../../commons/WheelDateTimePicker';
7
- import { useBoolean } from '../../../hooks/Common';
8
- import { useTranslations } from '../../../hooks/Common/useTranslations';
2
+ import React, { useCallback } from 'react';
9
3
  import Routes from '../../../utils/Route';
10
- import NewActionWrapper from '../AddNewAction/NewActionWrapper';
11
- import RepeatOptionsPopup, {
12
- REPEAT_OPTIONS,
13
- } from './components/RepeatOptionsPopup';
14
- import RowItem from './components/RowItem';
15
- import SelectWeekday from './components/SelectWeekday';
16
- import styles from './styles/indexStyles';
4
+ import EditSchedule from './EditSchedule';
17
5
 
18
6
  const SetSchedule = ({ route }) => {
19
- const t = useTranslations();
20
7
  const { automate = {}, closeScreen } = route?.params || {};
21
8
  const { navigate } = useNavigation();
22
- const [repeat, setRepeat] = useState(automate.repeat || REPEAT_OPTIONS.ONCE);
23
9
 
24
- const getDateString = (date) => {
25
- const today = moment();
26
- if (date.isSame(today, 'day')) {
27
- return date.format(`[${t('today')}], D MMMM YYYY `);
28
- }
29
- return date.format('ddd, D MMMM YYYY');
30
- };
31
-
32
- const [time, setTime] = useState(
33
- automate.time_repeat
34
- ? moment(automate.time_repeat, 'HH:mm:ss')
35
- : moment().second(0)
36
- );
37
- const [date, setDate] = useState(
38
- automate.date_repeat ? moment(automate.date_repeat, 'YYYY-MM-DD') : moment()
39
- );
40
- const [weekday, setWeekday] = useState(automate.weekday_repeat || []);
41
-
42
- const [showRepeatOptions, setShowRepeatOptions, setHideRepeatOptions] =
43
- useBoolean();
44
- const [showTimePicker, setShowTimePicker, setHideTimePicker] = useBoolean();
45
- const [showCalendar, setShowCalendar, setHideCalendar] = useBoolean();
46
-
47
- const handleOnSave = useCallback(() => {
48
- navigate(Routes.ValueChangeName, {
49
- closeScreen: closeScreen,
50
- automate: {
51
- ...automate,
52
- repeat: repeat,
53
- time_repeat: time.format('HH:mm:ss'),
54
- date_repeat: date.format('YYYY-MM-DD'),
55
- weekday_repeat: weekday,
56
- },
57
- unitId: automate.unit,
58
- });
59
- }, [navigate, closeScreen, automate, repeat, time, date, weekday]);
60
-
61
- const onSetRepeatOption = useCallback(
62
- (value) => {
63
- setRepeat(value);
64
- setHideRepeatOptions();
10
+ const handleOnSave = useCallback(
11
+ (data) => {
12
+ navigate(Routes.ValueChangeName, {
13
+ closeScreen: closeScreen,
14
+ automate: {
15
+ ...automate,
16
+ conditions: [data],
17
+ },
18
+ unitId: automate.unit,
19
+ });
65
20
  },
66
- [setRepeat, setHideRepeatOptions]
21
+ [navigate, closeScreen, automate]
67
22
  );
68
23
 
69
- const onTimePicked = useCallback(
70
- (timeData) => {
71
- setTime(moment(timeData));
72
- },
73
- [setTime]
74
- );
75
-
76
- const onDatePicked = useCallback(
77
- (datePicked) => {
78
- setDate(datePicked);
79
- },
80
- [setDate]
81
- );
82
-
83
- return (
84
- <NewActionWrapper
85
- name={t('set_schedule')}
86
- onNext={handleOnSave}
87
- canNext
88
- nextTitle={t('save')}
89
- >
90
- <ScrollView
91
- contentContainerStyle={styles.scollView}
92
- scrollIndicatorInsets={{ right: 1 }}
93
- >
94
- <RowItem
95
- title={t('set_time')}
96
- value={time.format('HH:mm')}
97
- icon="clock-circle"
98
- onPress={setShowTimePicker}
99
- />
100
- {repeat === REPEAT_OPTIONS.ONCE && (
101
- <RowItem
102
- title={t('select_date')}
103
- value={getDateString(date)}
104
- icon="calendar"
105
- onPress={setShowCalendar}
106
- />
107
- )}
108
- {repeat === REPEAT_OPTIONS.EVERYWEEK && (
109
- <SelectWeekday weekday={weekday} setWeekday={setWeekday} />
110
- )}
111
- <RowItem
112
- title={t('repeat')}
113
- value={t(`${repeat}`)}
114
- arrow
115
- onPress={setShowRepeatOptions}
116
- />
117
- </ScrollView>
118
- <RepeatOptionsPopup
119
- isVisible={showRepeatOptions}
120
- onHide={setHideRepeatOptions}
121
- onSetRepeat={onSetRepeatOption}
122
- />
123
- <WheelDateTimePicker
124
- mode="time"
125
- isVisible={showTimePicker}
126
- defaultValue={time.valueOf()}
127
- onCancel={setHideTimePicker}
128
- onPicked={onTimePicked}
129
- />
130
- <Calendar
131
- isVisible={showCalendar}
132
- defaultDate={date}
133
- minDate={moment()}
134
- onCancel={setHideCalendar}
135
- onConfirm={onDatePicked}
136
- />
137
- </NewActionWrapper>
138
- );
24
+ return <EditSchedule onSave={handleOnSave} />;
139
25
  };
140
26
 
141
- export default memo(SetSchedule);
27
+ export default SetSchedule;
@@ -20,4 +20,13 @@ export default StyleSheet.create({
20
20
  borderTopWidth: 1,
21
21
  backgroundColor: Colors.White,
22
22
  },
23
+ inputWrap: {
24
+ marginTop: 0,
25
+ },
26
+ inputNumber: {
27
+ borderWidth: 1,
28
+ borderColor: Colors.Gray4,
29
+ borderStyle: 'solid',
30
+ borderRadius: 10,
31
+ },
23
32
  });
@@ -190,11 +190,16 @@ describe('Test MultiUnits', () => {
190
190
  await act(async () => {
191
191
  ItemAddNews[0].props.onAddNew();
192
192
  });
193
- expect(global.mockedNavigate).toBeCalledWith(Routes.UnitStack, {
193
+ expect(global.mockedNavigate).toHaveBeenCalledWith(Routes.UnitStack, {
194
194
  screen: Routes.ScenarioName,
195
195
  params: {
196
196
  automate: {
197
197
  type: AUTOMATE_TYPE.ONE_TAP,
198
+ conditions: [
199
+ {
200
+ type: AUTOMATE_TYPE.ONE_TAP,
201
+ },
202
+ ],
198
203
  unit: undefined,
199
204
  },
200
205
  closeScreen: undefined,
@@ -0,0 +1,222 @@
1
+ import { useCallback, useEffect, useMemo, useState } from 'react';
2
+
3
+ import { API } from '../../../configs';
4
+ import {
5
+ axiosDelete,
6
+ axiosGet,
7
+ axiosPost,
8
+ axiosPut,
9
+ } from '../../../utils/Apis/axios';
10
+
11
+ const useAction = (device, scriptItems, activatedScript = {}) => {
12
+ const {
13
+ action_script,
14
+ toggle_script,
15
+ order = scriptItems.length + 1,
16
+ } = activatedScript;
17
+ const [saveActions, setSaveActions] = useState([]);
18
+ const [displayActions, setDisplayActions] = useState([]);
19
+
20
+ const listAction = useMemo(() => {
21
+ return saveActions
22
+ .filter((item) => !item.is_toggle)
23
+ .map((item) => ({
24
+ action: item.action,
25
+ data: item.data,
26
+ order: order + item.index,
27
+ }));
28
+ }, [saveActions, order]);
29
+
30
+ const listToggle = useMemo(() => {
31
+ return saveActions
32
+ .filter((item) => item.is_toggle)
33
+ .map((item) => ({
34
+ action_on: item.action_on,
35
+ action_off: item.action_off,
36
+ config: item.config,
37
+ action_on_data: item.action_on_data,
38
+ action_off_data: item.action_off_data,
39
+ is_on_values: item.is_on_values,
40
+ order: order + item.index,
41
+ }));
42
+ }, [saveActions, order]);
43
+
44
+ const fetchDisplayActions = useCallback(async () => {
45
+ const { success, data } = await axiosGet(
46
+ API.DEVICE.DISPLAY_ACTIONS(device.id)
47
+ );
48
+
49
+ success && setDisplayActions(data);
50
+ }, [device.id]);
51
+
52
+ const onSelectAction = useCallback((action) => {
53
+ setSaveActions((prevActions) => {
54
+ const index = prevActions.findIndex(
55
+ (item) => item.index === action.index
56
+ );
57
+ if (index !== -1) {
58
+ const newActions = [...prevActions];
59
+ newActions[index] = action;
60
+ return newActions;
61
+ } else {
62
+ return [...prevActions, action];
63
+ }
64
+ });
65
+ }, []);
66
+
67
+ const onAddAction = useCallback(
68
+ async (automateId, unitId, startOrder, numberAction) => {
69
+ if (!listAction.length) {
70
+ return false;
71
+ }
72
+ const { success } = await axiosPost(
73
+ API.AUTOMATE.ADD_SCRIPT_ACTION(automateId),
74
+ {
75
+ list_action: listAction,
76
+ ...(startOrder && { start_order: startOrder }),
77
+ ...(numberAction && { number_action: numberAction }),
78
+ unit: unitId,
79
+ }
80
+ );
81
+ return success;
82
+ },
83
+ [listAction]
84
+ );
85
+
86
+ const onAddToggle = useCallback(
87
+ async (automateId, unitId, startOrder, numberAction) => {
88
+ if (!listToggle.length) {
89
+ return false;
90
+ }
91
+ const { success } = await axiosPost(
92
+ API.AUTOMATE.ADD_SCRIPT_TOGGLE(automateId),
93
+ {
94
+ list_action: listToggle,
95
+ ...(startOrder && { start_order: startOrder }),
96
+ ...(numberAction && { number_action: numberAction }),
97
+ unit: unitId,
98
+ }
99
+ );
100
+ return success;
101
+ },
102
+ [listToggle]
103
+ );
104
+
105
+ const onAddSubmit = useCallback(
106
+ async (automateId, unitId) => {
107
+ const actionSuccess = await onAddAction(automateId, unitId);
108
+ const toggleSuccess = await onAddToggle(automateId, unitId);
109
+ return actionSuccess || toggleSuccess;
110
+ },
111
+ [onAddAction, onAddToggle]
112
+ );
113
+
114
+ const onDeleteScript = useCallback(async (automateId, scriptId) => {
115
+ const { success } = await axiosDelete(
116
+ API.AUTOMATE.DELETE_SCRIPT_ITEM(automateId, scriptId)
117
+ );
118
+ return success;
119
+ }, []);
120
+
121
+ const onUpdateAction = useCallback(
122
+ async (automateId, scriptId, unitId) => {
123
+ if (!action_script) {
124
+ const success = await onDeleteScript(automateId, scriptId);
125
+ return (
126
+ success &&
127
+ (await onAddAction(
128
+ automateId,
129
+ unitId,
130
+ listAction[0].order,
131
+ saveActions.length
132
+ ))
133
+ );
134
+ }
135
+ const { success } = await axiosPut(
136
+ API.AUTOMATE.UPDATE_SCRIPT_ACTION(automateId),
137
+ {
138
+ id: scriptId,
139
+ list_action: listAction,
140
+ number_action: saveActions.length,
141
+ unit: unitId,
142
+ }
143
+ );
144
+ return success;
145
+ },
146
+ [action_script, listAction, saveActions.length, onAddAction, onDeleteScript]
147
+ );
148
+
149
+ const onUpdateToggle = useCallback(
150
+ async (automateId, scriptId, unitId) => {
151
+ if (!toggle_script) {
152
+ const success = await onDeleteScript(automateId, scriptId);
153
+ return (
154
+ success &&
155
+ (await onAddToggle(
156
+ automateId,
157
+ unitId,
158
+ listToggle[0].order,
159
+ saveActions.length
160
+ ))
161
+ );
162
+ }
163
+ const { success } = await axiosPut(
164
+ API.AUTOMATE.UPDATE_SCRIPT_TOGGLE(automateId),
165
+ {
166
+ id: scriptId,
167
+ list_action: listToggle,
168
+ number_action: saveActions.length,
169
+ unit: unitId,
170
+ }
171
+ );
172
+ return success;
173
+ },
174
+ [toggle_script, listToggle, saveActions.length, onAddToggle, onDeleteScript]
175
+ );
176
+
177
+ const onUpdateSubmit = useCallback(
178
+ async (automateId, scriptId, unitId) => {
179
+ if (saveActions[0].is_toggle) {
180
+ const toggleSuccess = await onUpdateToggle(
181
+ automateId,
182
+ scriptId,
183
+ unitId
184
+ );
185
+ const actionSuccess = await onAddAction(automateId, unitId);
186
+ return toggleSuccess || actionSuccess;
187
+ } else {
188
+ const actionSuccess = await onUpdateAction(
189
+ automateId,
190
+ scriptId,
191
+ unitId
192
+ );
193
+ const toggleSuccess = await onAddToggle(automateId, unitId);
194
+ return actionSuccess || toggleSuccess;
195
+ }
196
+ },
197
+ [saveActions, onAddAction, onAddToggle, onUpdateAction, onUpdateToggle]
198
+ );
199
+
200
+ useEffect(() => {
201
+ fetchDisplayActions();
202
+ }, [fetchDisplayActions]);
203
+
204
+ return {
205
+ displayActions,
206
+ saveActions,
207
+
208
+ setDisplayActions,
209
+ setSaveActions,
210
+ onSelectAction,
211
+
212
+ onAddAction,
213
+ onAddToggle,
214
+ onAddSubmit,
215
+
216
+ onUpdateAction,
217
+ onUpdateToggle,
218
+ onUpdateSubmit,
219
+ };
220
+ };
221
+
222
+ export default useAction;
@@ -1,15 +1,18 @@
1
- import React from 'react';
2
1
  import renderer, { act } from 'react-test-renderer';
3
2
 
4
- import { SCProvider } from '../../../context';
5
- import { mockSCStore } from '../../../context/mockStore';
3
+ import API from '../../../configs/API';
4
+ import { AccessibilityLabel } from '../../../configs/Constants';
5
+ import { Button } from '../../../commons';
6
6
  import ConfirmUnitDeletion from '../index';
7
+ import MockAdapter from 'axios-mock-adapter';
8
+ import React from 'react';
9
+ import Routes from '../../../utils/Route';
10
+ import { SCProvider } from '../../../context';
11
+ import { ToastBottomHelper } from '../../../utils/Utils';
7
12
  import _TextInput from '../../../commons/Form/TextInput';
8
- import { TouchableOpacity } from 'react-native';
9
- import { AccessibilityLabel } from '../../../configs/Constants';
10
- import API from '../../../configs/API';
11
13
  import api from '../../../utils/Apis/axios';
12
- import MockAdapter from 'axios-mock-adapter';
14
+ import { mockSCStore } from '../../../context/mockStore';
15
+ import { useNavigation } from '@react-navigation/native';
13
16
 
14
17
  const mock = new MockAdapter(api.axiosInstance);
15
18
  const wrapComponent = (route, navigation) => (
@@ -21,7 +24,8 @@ const wrapComponent = (route, navigation) => (
21
24
  describe('Test ConfirmUnitDeletion', () => {
22
25
  let tree;
23
26
  let route;
24
-
27
+ const spyToast = jest.spyOn(ToastBottomHelper, 'success');
28
+ const mockNavigate = useNavigation().navigate;
25
29
  beforeAll(() => {
26
30
  route = {
27
31
  params: {
@@ -31,6 +35,10 @@ describe('Test ConfirmUnitDeletion', () => {
31
35
  },
32
36
  };
33
37
  });
38
+ beforeEach(() => {
39
+ spyToast.mockClear();
40
+ mockNavigate.mockClear();
41
+ });
34
42
 
35
43
  it('test render ConfirmUnitDeletion', async () => {
36
44
  await act(async () => {
@@ -43,7 +51,8 @@ describe('Test ConfirmUnitDeletion', () => {
43
51
  textInput.props.onChange();
44
52
  });
45
53
  });
46
- it('Onpress button ConfirmUnitDeletion ', async () => {
54
+ it('Onpress button ConfirmUnitDeletion success', async () => {
55
+ mock.onDelete(API.UNIT.MANAGE_UNIT(10)).reply(204);
47
56
  await act(async () => {
48
57
  tree = await renderer.create(wrapComponent(route));
49
58
  });
@@ -52,16 +61,63 @@ describe('Test ConfirmUnitDeletion', () => {
52
61
  const touchableOpacity = instance.find(
53
62
  (el) =>
54
63
  el.props.accessibilityLabel ===
55
- AccessibilityLabel.CONFIRM_UNIT_DELETION_BUTTON &&
56
- el.type === TouchableOpacity
64
+ AccessibilityLabel.CONFIRM_UNIT_DELETION_BUTTON && el.type === Button
57
65
  );
58
66
  const textInput = instance.findByType(_TextInput);
67
+ await act(async () => {
68
+ textInput.props.onChange('YES');
69
+ });
59
70
  await act(async () => {
60
71
  touchableOpacity.props.onPress();
61
72
  });
73
+ expect(spyToast).toHaveBeenLastCalledWith('Unit was deleted successfully.');
74
+ expect(mockNavigate).toHaveBeenCalledWith(Routes.Dashboard);
75
+ });
76
+
77
+ it('Onpress button ConfirmUnitDeletion response error', async () => {
78
+ mock.onDelete(API.UNIT.MANAGE_UNIT(10)).reply(400);
62
79
  await act(async () => {
63
- textInput.props.onChange();
80
+ tree = await renderer.create(wrapComponent(route));
81
+ });
82
+ const instance = tree.root;
83
+
84
+ const touchableOpacity = instance.find(
85
+ (el) =>
86
+ el.props.accessibilityLabel ===
87
+ AccessibilityLabel.CONFIRM_UNIT_DELETION_BUTTON && el.type === Button
88
+ );
89
+ const textInput = instance.findByType(_TextInput);
90
+ await act(async () => {
91
+ textInput.props.onChange('YES');
92
+ });
93
+ await act(async () => {
94
+ touchableOpacity.props.onPress();
95
+ });
96
+ expect(spyToast).not.toHaveBeenCalled();
97
+ expect(mockNavigate).not.toHaveBeenCalled();
98
+ });
99
+
100
+ it('Onpress button ConfirmUnitDeletion wrong text confirm', async () => {
101
+ mock.onDelete(API.UNIT.MANAGE_UNIT(10)).reply(204);
102
+ await act(async () => {
103
+ tree = await renderer.create(wrapComponent(route));
104
+ });
105
+ const instance = tree.root;
106
+
107
+ const touchableOpacity = instance.find(
108
+ (el) =>
109
+ el.props.accessibilityLabel ===
110
+ AccessibilityLabel.CONFIRM_UNIT_DELETION_BUTTON && el.type === Button
111
+ );
112
+ const textInput = instance.findByType(_TextInput);
113
+ await act(async () => {
114
+ textInput.props.onChange('XXX');
115
+ });
116
+ await act(async () => {
117
+ touchableOpacity.props.onPress();
64
118
  });
65
- mock.onDelete(API.UNIT.MANAGE_UNIT(1)).reply(204);
119
+ expect(spyToast).not.toHaveBeenCalled();
120
+ expect(mockNavigate).not.toHaveBeenCalled();
121
+ expect(textInput.props.errorText).toEqual('Please enter correct');
66
122
  });
67
123
  });
@@ -1,31 +1,31 @@
1
+ import { API, Colors } from '../../configs';
1
2
  import React, { useCallback, useContext, useState } from 'react';
2
- import { View } from 'react-native';
3
- import { useNavigation } from '@react-navigation/native';
4
3
 
5
- import { useTranslations } from '../../hooks/Common/useTranslations';
6
- import styles from './styles';
7
- import WrapHeaderScrollable from '../../commons/Sharing/WrapHeaderScrollable';
8
- import Text from '../../commons/Text';
9
- import { API, Colors } from '../../configs';
10
- import _TextInput from '../../commons/Form/TextInput';
4
+ import { AccessibilityLabel } from '../../configs/Constants';
5
+ import { Action } from '../../context/actionType';
11
6
  import { Button } from '../../commons';
12
7
  import Routes from '../../utils/Route';
13
- import { axiosDelete } from '../../utils/Apis/axios';
14
- import { ToastBottomHelper } from '../../utils/Utils';
15
- import { AccessibilityLabel } from '../../configs/Constants';
16
8
  import { SCContext } from '../../context';
17
- import { Action } from '../../context/actionType';
9
+ import Text from '../../commons/Text';
10
+ import { ToastBottomHelper } from '../../utils/Utils';
11
+ import { View } from 'react-native';
12
+ import WrapHeaderScrollable from '../../commons/Sharing/WrapHeaderScrollable';
13
+ import _TextInput from '../../commons/Form/TextInput';
14
+ import { axiosDelete } from '../../utils/Apis/axios';
15
+ import styles from './styles';
16
+ import { useNavigation } from '@react-navigation/native';
17
+ import { useTranslations } from '../../hooks/Common/useTranslations';
18
18
 
19
19
  const ConfirmUnitDeletion = ({ route }) => {
20
20
  const { setAction } = useContext(SCContext);
21
21
  const t = useTranslations();
22
22
  const { unit } = route?.params || {};
23
23
  const navigation = useNavigation();
24
- const [confirm, setConfrim] = useState('');
24
+ const [confirm, setConfirm] = useState('');
25
25
  const [errorText, setErrorText] = useState();
26
26
 
27
27
  const onChangePassword = useCallback((value) => {
28
- setConfrim(value);
28
+ setConfirm(value);
29
29
  }, []);
30
30
 
31
31
  const onSendPress = useCallback(async () => {
@@ -8,6 +8,7 @@ import CurrentRainSensor from '../../../commons/Device/RainningSensor/CurrentRai
8
8
  import { AlertSendConfirm } from '../../../commons/EmergencyButton/AlertSendConfirm';
9
9
  import { AlertSent } from '../../../commons/EmergencyButton/AlertSent';
10
10
  import Text from '../../../commons/Text';
11
+ import { SensorConnectStatusViewHeader } from '../components/SensorConnectStatusViewHeader';
11
12
  import { API } from '../../../configs';
12
13
  import { AccessibilityLabel } from '../../../configs/Constants';
13
14
  import { SCProvider } from '../../../context';
@@ -369,10 +370,19 @@ describe('test DeviceDetail', () => {
369
370
  const instance = tree.root;
370
371
  const scrollView = instance.findByType(ScrollView);
371
372
  const refreshControl = scrollView.props.refreshControl;
373
+ expect(mock.history.post).toHaveLength(2);
372
374
  await act(async () => {
373
375
  refreshControl.props.onRefresh();
374
376
  });
375
377
  expect(scrollView).toBeDefined();
378
+ expect(mock.history.post).toHaveLength(4);
379
+ const urls = mock.history.post.map((item) => item.url);
380
+ expect(
381
+ urls.filter((url) => url === API.UNIT.END_DEVICES_STATUS(1))
382
+ ).toHaveLength(2);
383
+ expect(
384
+ urls.filter((url) => url === API.HOME_ASSISTANT.CHECK_SEND_EMAIL())
385
+ ).toHaveLength(2);
376
386
  });
377
387
 
378
388
  it('Should render SensorDisplayItem', async () => {
@@ -760,7 +770,7 @@ describe('test DeviceDetail', () => {
760
770
 
761
771
  it('Test fetchUnitDetail', async () => {
762
772
  const unitId = 1;
763
- mock.onGet(API.UNIT.UNIT_DETAIL(unitId)).reply(200);
773
+ mock.onGet(API.UNIT.UNIT_DETAIL(unitId)).reply(200, { id: unitId });
764
774
  await act(async () => {
765
775
  await create(
766
776
  wrapComponent(store, account, {
@@ -773,6 +783,43 @@ describe('test DeviceDetail', () => {
773
783
  expect(urls).toContain(API.UNIT.UNIT_DETAIL(unitId));
774
784
  });
775
785
 
786
+ it('Test fetch end device status', async () => {
787
+ const unitId = 1;
788
+ mock.onGet(API.UNIT.UNIT_DETAIL(unitId)).reply(200, { id: unitId });
789
+ mock.onPost(API.UNIT.END_DEVICES_STATUS(unitId)).reply(200, [
790
+ {
791
+ id: 1,
792
+ is_connected: true,
793
+ },
794
+ ]);
795
+ await act(async () => {
796
+ tree = await create(
797
+ wrapComponent(store, account, {
798
+ ...route,
799
+ params: { ...route.params, unitData: null, unitId: unitId },
800
+ })
801
+ );
802
+ });
803
+ const instance = tree.root;
804
+ const sensorConnectStatus = instance.findByType(
805
+ SensorConnectStatusViewHeader
806
+ );
807
+ expect(sensorConnectStatus.props.connectedViaNetwork).toBeTruthy();
808
+ expect(mock.history.post).toHaveLength(1);
809
+ expect(mock.history.post[0].url).toEqual(
810
+ API.UNIT.END_DEVICES_STATUS(unitId)
811
+ );
812
+ });
813
+
814
+ it('Test not fetch end device status if not managed by backend', async () => {
815
+ route.params.sensorData.is_managed_by_backend = false;
816
+ await act(async () => {
817
+ tree = await create(wrapComponent(store, account, route));
818
+ });
819
+ const urls = mock.history.post.map((x) => x.url);
820
+ expect(urls).not.toContain(API.UNIT.END_DEVICES_STATUS(1));
821
+ });
822
+
776
823
  it('should render device detail, useWatchConfig value', async () => {
777
824
  mock.onGet(API.CHIP.JSON_CONFIGURATION).reply(200, []);
778
825
  const responseDisplay = {