@eohjsc/react-native-smart-city 0.7.19 → 0.7.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/images/Schedule.svg +39 -0
- package/assets/images/ValueChange.svg +49 -0
- package/package.json +1 -1
- package/src/commons/Automate/ButtonAddCondition.js +51 -0
- package/src/commons/Automate/ItemConditionScriptDetail.js +28 -15
- package/src/commons/Automate/ItemConditionScriptDetailStyles.js +9 -0
- package/src/configs/API.js +12 -1
- package/src/configs/AccessibilityLabel.js +6 -0
- package/src/context/actionType.ts +5 -0
- package/src/context/reducer.ts +30 -1
- package/src/navigations/UnitStack.js +8 -0
- package/src/screens/AddNewGateway/ScanDeviceLocal.js +15 -14
- package/src/screens/AddNewGateway/__test__/ScanDeviceLocal.test.js +51 -1
- package/src/screens/AddNewGateway/hooks/useConnectDevice.js +11 -9
- package/src/screens/AllGateway/DeviceInternalDetail/__test__/index.test.js +28 -0
- package/src/screens/AllGateway/DeviceModbusDetail/__test__/index.test.js +1 -1
- package/src/screens/AllGateway/__test__/index.test.js +19 -0
- package/src/screens/AllGateway/hooks/useGateway.js +16 -9
- package/src/screens/Automate/AddNewAction/SetupConfigCondition.js +73 -30
- package/src/screens/Automate/AddNewAction/__test__/SetupConfigCondition.test.js +115 -10
- package/src/screens/Automate/AddNewAutoSmart/AddTypeSmart.js +7 -3
- package/src/screens/Automate/ScriptDetail/Components/DeleteCondition.js +51 -0
- package/src/screens/Automate/ScriptDetail/Components/ModalAddCondition.js +196 -0
- package/src/screens/Automate/ScriptDetail/Styles/indexStyles.js +19 -0
- package/src/screens/Automate/ScriptDetail/__test__/index.test.js +441 -47
- package/src/screens/Automate/ScriptDetail/index.js +402 -106
- package/src/screens/Automate/ScriptDetail/utils.js +7 -11
- package/src/screens/Automate/SetSchedule/AddEditConditionSchedule.js +173 -0
- package/src/screens/Automate/SetSchedule/__test__/AddEditConditionSchedule.test.js +211 -0
- package/src/utils/I18n/translations/en.js +24 -0
- package/src/utils/I18n/translations/vi.js +24 -1
- package/src/utils/Route/index.js +1 -0
|
@@ -85,6 +85,25 @@ describe('Test Gateway screen', () => {
|
|
|
85
85
|
expect(flatList.props.data).toEqual([{ id: 1, name: 'device 1' }]);
|
|
86
86
|
});
|
|
87
87
|
|
|
88
|
+
it('render Gateway onLoadMore', async () => {
|
|
89
|
+
await act(async () => {
|
|
90
|
+
tree = await create(wrapComponent());
|
|
91
|
+
});
|
|
92
|
+
const instance = tree.root;
|
|
93
|
+
const flatList = instance.findByType(FlatList);
|
|
94
|
+
expect(flatList.props.data).toEqual([]);
|
|
95
|
+
mock
|
|
96
|
+
.onGet(API.DEV_MODE.GATEWAY.LIST())
|
|
97
|
+
.reply(200, { results: [{ id: 1, name: 'device 1' }] });
|
|
98
|
+
await act(async () => {
|
|
99
|
+
await flatList.props.onMomentumScrollBegin();
|
|
100
|
+
});
|
|
101
|
+
await act(async () => {
|
|
102
|
+
await flatList.props.onEndReached();
|
|
103
|
+
});
|
|
104
|
+
expect(flatList.props.data).toEqual([{ id: 1, name: 'device 1' }]);
|
|
105
|
+
});
|
|
106
|
+
|
|
88
107
|
it('Test render empty', async () => {
|
|
89
108
|
await act(async () => {
|
|
90
109
|
tree = await create(wrapComponent());
|
|
@@ -146,26 +146,29 @@ export const useGateway = () => {
|
|
|
146
146
|
isModbus,
|
|
147
147
|
numberGoBack = 1
|
|
148
148
|
) => {
|
|
149
|
-
let
|
|
149
|
+
let response;
|
|
150
150
|
if (isInternal) {
|
|
151
|
-
|
|
151
|
+
response = await axiosDelete(
|
|
152
152
|
API.DEV_MODE.ARDUINO.DEVICE_DETAIL(gatewayId, deviceId)
|
|
153
153
|
);
|
|
154
|
-
success &&
|
|
154
|
+
response.success &&
|
|
155
|
+
setGatewayDevices((prev) => ({ ...prev, internal: [] }));
|
|
155
156
|
}
|
|
156
157
|
if (isZigbee) {
|
|
157
|
-
|
|
158
|
+
response = await axiosDelete(
|
|
158
159
|
API.DEV_MODE.ZIGBEE.DEVICE_DETAIL(gatewayId, deviceId)
|
|
159
160
|
);
|
|
160
|
-
success &&
|
|
161
|
+
response.success &&
|
|
162
|
+
setGatewayDevices((prev) => ({ ...prev, zigbee: [] }));
|
|
161
163
|
}
|
|
162
164
|
if (isModbus) {
|
|
163
|
-
|
|
165
|
+
response = await axiosDelete(
|
|
164
166
|
API.DEV_MODE.MODBUS.DEVICE_DETAIL(gatewayId, deviceId)
|
|
165
167
|
);
|
|
166
|
-
success &&
|
|
168
|
+
response.success &&
|
|
169
|
+
setGatewayDevices((prev) => ({ ...prev, modbus: [] }));
|
|
167
170
|
}
|
|
168
|
-
if (success) {
|
|
171
|
+
if (response.success) {
|
|
169
172
|
ToastBottomHelper.success(t('delete_successfully'));
|
|
170
173
|
navigation.pop(numberGoBack);
|
|
171
174
|
}
|
|
@@ -259,7 +262,11 @@ export const useGateway = () => {
|
|
|
259
262
|
params: { secret },
|
|
260
263
|
}
|
|
261
264
|
);
|
|
262
|
-
|
|
265
|
+
if (success) {
|
|
266
|
+
setDetailChipQr(data);
|
|
267
|
+
} else {
|
|
268
|
+
ToastBottomHelper.error(t('chip_qr_not_found'));
|
|
269
|
+
}
|
|
263
270
|
}, []);
|
|
264
271
|
|
|
265
272
|
return {
|
|
@@ -16,6 +16,10 @@ import Routes from '../../../utils/Route';
|
|
|
16
16
|
import { ToastBottomHelper } from '../../../utils/Utils';
|
|
17
17
|
import NewActionWrapper from './NewActionWrapper';
|
|
18
18
|
import styles from './Styles/SetupSensorStyles';
|
|
19
|
+
import { useSCContextSelector } from '../../../context';
|
|
20
|
+
import { axiosPost, axiosPut } from '../../../utils/Apis/axios';
|
|
21
|
+
import { API } from '../../../configs';
|
|
22
|
+
import { AccessibilityLabel, AUTOMATE_TYPE } from '../../../configs/Constants';
|
|
19
23
|
|
|
20
24
|
const valueEvaluationToOptions = (valueEvaluation) => {
|
|
21
25
|
if (valueEvaluation.template === 'range') {
|
|
@@ -51,22 +55,23 @@ const SetupConfigCondition = () => {
|
|
|
51
55
|
const [selectedCondition, setSelectedCondition] = useState(undefined);
|
|
52
56
|
const [customCondition, setCustomCondition] = useState(undefined);
|
|
53
57
|
const [isShowModal, setIsShowModal] = useState(false);
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
{
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
]
|
|
69
|
-
|
|
58
|
+
|
|
59
|
+
const isCreateCondition = useSCContextSelector(
|
|
60
|
+
(state) => state.automate.isCreateCondition
|
|
61
|
+
);
|
|
62
|
+
const isUpdateCondition = useSCContextSelector(
|
|
63
|
+
(state) => state.automate.isUpdateCondition
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const normalConditions = useMemo(
|
|
67
|
+
() => [
|
|
68
|
+
{ label: `${t('is_below')} (<)`, value: '<' },
|
|
69
|
+
{ label: `${t('is_equal')} (=)`, value: '=' },
|
|
70
|
+
{ label: `${t('is_above')} (>)`, value: '>' },
|
|
71
|
+
],
|
|
72
|
+
[t]
|
|
73
|
+
);
|
|
74
|
+
|
|
70
75
|
const conditionOptions = useMemo(() => {
|
|
71
76
|
if (config?.value_evaluations?.length) {
|
|
72
77
|
const options = [];
|
|
@@ -85,15 +90,56 @@ const SetupConfigCondition = () => {
|
|
|
85
90
|
setIsShowModal(true);
|
|
86
91
|
};
|
|
87
92
|
|
|
88
|
-
const
|
|
93
|
+
const handleNavigate = useCallback(async () => {
|
|
94
|
+
if (!isCreateCondition && !isUpdateCondition) {
|
|
95
|
+
navigate(Routes.ValueChangeName, {
|
|
96
|
+
automate,
|
|
97
|
+
closeScreen,
|
|
98
|
+
unitId,
|
|
99
|
+
});
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const data = {
|
|
103
|
+
type: AUTOMATE_TYPE.VALUE_CHANGE,
|
|
104
|
+
condition: automate.condition,
|
|
105
|
+
config: automate.config,
|
|
106
|
+
value: automate.value,
|
|
107
|
+
};
|
|
108
|
+
const apiCall = isCreateCondition
|
|
109
|
+
? await axiosPost(API.AUTOMATE.ADD_CONDITION(automate.id), data)
|
|
110
|
+
: await axiosPut(
|
|
111
|
+
API.AUTOMATE.UPDATE_CONDITION(automate.id, isUpdateCondition),
|
|
112
|
+
data
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
const { success } = apiCall;
|
|
116
|
+
|
|
117
|
+
if (success) {
|
|
118
|
+
ToastBottomHelper.success(
|
|
119
|
+
isCreateCondition
|
|
120
|
+
? t('add_condition_success')
|
|
121
|
+
: t('edit_condition_success')
|
|
122
|
+
);
|
|
123
|
+
navigate({
|
|
124
|
+
name: Routes.ScriptDetail,
|
|
125
|
+
params: { preAutomate: automate },
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}, [
|
|
129
|
+
automate,
|
|
130
|
+
closeScreen,
|
|
131
|
+
isCreateCondition,
|
|
132
|
+
isUpdateCondition,
|
|
133
|
+
navigate,
|
|
134
|
+
t,
|
|
135
|
+
unitId,
|
|
136
|
+
]);
|
|
137
|
+
|
|
138
|
+
const setupCondition = async (condition) => {
|
|
89
139
|
automate.condition = condition?.condition;
|
|
90
140
|
automate.value = condition?.value;
|
|
91
141
|
setSelectedCondition(condition);
|
|
92
|
-
|
|
93
|
-
automate,
|
|
94
|
-
closeScreen,
|
|
95
|
-
unitId,
|
|
96
|
-
});
|
|
142
|
+
handleNavigate();
|
|
97
143
|
};
|
|
98
144
|
|
|
99
145
|
const resetCustomizeCondition = useCallback(() => {
|
|
@@ -146,9 +192,10 @@ const SetupConfigCondition = () => {
|
|
|
146
192
|
{t('when_value_is', { config_name: config.name })}
|
|
147
193
|
</Text>
|
|
148
194
|
<View style={styles.flatListCondition}>
|
|
149
|
-
{normalConditions.map((item) => {
|
|
195
|
+
{normalConditions.map((item, index) => {
|
|
150
196
|
return (
|
|
151
197
|
<GridItem
|
|
198
|
+
key={`GridItem${index}`}
|
|
152
199
|
onPress={() => {
|
|
153
200
|
automate.condition = item.value;
|
|
154
201
|
setCustomCondition(item.value);
|
|
@@ -180,18 +227,14 @@ const SetupConfigCondition = () => {
|
|
|
180
227
|
<Button
|
|
181
228
|
type="primary"
|
|
182
229
|
title={t('continue')}
|
|
183
|
-
|
|
184
|
-
onPress={() => {
|
|
230
|
+
accessibilityLabel={AccessibilityLabel.BUTTON_CONTINUE}
|
|
231
|
+
onPress={async () => {
|
|
185
232
|
if (isNaN(automate.value) || !automate.condition) {
|
|
186
233
|
ToastBottomHelper.error(t('please_enter_a_number'), '', 3000);
|
|
187
234
|
return;
|
|
188
235
|
}
|
|
189
236
|
setIsShowModal(false);
|
|
190
|
-
|
|
191
|
-
automate,
|
|
192
|
-
closeScreen,
|
|
193
|
-
unitId,
|
|
194
|
-
});
|
|
237
|
+
handleNavigate();
|
|
195
238
|
}}
|
|
196
239
|
style={styles.buttonContinue}
|
|
197
240
|
textSemiBold={false}
|
|
@@ -7,18 +7,15 @@ import { showAllGridItems } from '../../../../commons/ActionTemplate/__test__/ut
|
|
|
7
7
|
import TextInput from '../../../../commons/Form/TextInput';
|
|
8
8
|
import GridItem from '../../../../commons/Grid/GridItem';
|
|
9
9
|
import { ModalCustom } from '../../../../commons/Modal';
|
|
10
|
-
import { SCProvider } from '../../../../context';
|
|
10
|
+
import { SCProvider, useSCContextSelector } from '../../../../context';
|
|
11
11
|
import { mockSCStore } from '../../../../context/mockStore';
|
|
12
12
|
import Routes from '../../../../utils/Route';
|
|
13
13
|
import { ToastBottomHelper } from '../../../../utils/Utils';
|
|
14
14
|
import SetupConfigCondition from '../SetupConfigCondition';
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
memo: (x) => x,
|
|
20
|
-
};
|
|
21
|
-
});
|
|
15
|
+
import AccessibilityLabel from '../../../../configs/AccessibilityLabel';
|
|
16
|
+
import { API } from '../../../../configs';
|
|
17
|
+
import api from '../../../../utils/Apis/axios';
|
|
18
|
+
import MockAdapter from 'axios-mock-adapter';
|
|
22
19
|
|
|
23
20
|
const BOOLEAN_VALUE_EVALUATION_CONFIGURATION = {
|
|
24
21
|
id: 1,
|
|
@@ -39,10 +36,25 @@ const wrapComponent = (configuration, onPress) => (
|
|
|
39
36
|
</SCProvider>
|
|
40
37
|
);
|
|
41
38
|
|
|
39
|
+
jest.mock('../../../../context', () => ({
|
|
40
|
+
...jest.requireActual('../../../../context'),
|
|
41
|
+
useSCContextSelector: jest.fn(),
|
|
42
|
+
}));
|
|
43
|
+
|
|
44
|
+
const mock = new MockAdapter(api.axiosInstance);
|
|
45
|
+
|
|
42
46
|
describe('Test SetupConfigCondition', () => {
|
|
43
47
|
const spyToastError = jest.spyOn(ToastBottomHelper, 'error');
|
|
44
48
|
|
|
45
49
|
let tree;
|
|
50
|
+
useSCContextSelector.mockImplementation((selector) =>
|
|
51
|
+
selector({
|
|
52
|
+
automate: {
|
|
53
|
+
isCreateCondition: false,
|
|
54
|
+
isUpdateCondition: false,
|
|
55
|
+
},
|
|
56
|
+
})
|
|
57
|
+
);
|
|
46
58
|
beforeEach(() => {
|
|
47
59
|
tree = null;
|
|
48
60
|
spyToastError.mockClear();
|
|
@@ -150,6 +162,14 @@ describe('Test SetupConfigCondition', () => {
|
|
|
150
162
|
});
|
|
151
163
|
|
|
152
164
|
it('choose config value evaluation', async () => {
|
|
165
|
+
useSCContextSelector.mockImplementation((selector) =>
|
|
166
|
+
selector({
|
|
167
|
+
automate: {
|
|
168
|
+
isCreateCondition: false,
|
|
169
|
+
isUpdateCondition: false,
|
|
170
|
+
},
|
|
171
|
+
})
|
|
172
|
+
);
|
|
153
173
|
useRoute.mockReturnValue({
|
|
154
174
|
params: {
|
|
155
175
|
automate: {},
|
|
@@ -183,6 +203,14 @@ describe('Test SetupConfigCondition', () => {
|
|
|
183
203
|
});
|
|
184
204
|
|
|
185
205
|
const testCustomCondition = async (value) => {
|
|
206
|
+
useSCContextSelector.mockImplementation((selector) =>
|
|
207
|
+
selector({
|
|
208
|
+
automate: {
|
|
209
|
+
isCreateCondition: false,
|
|
210
|
+
isUpdateCondition: false,
|
|
211
|
+
},
|
|
212
|
+
})
|
|
213
|
+
);
|
|
186
214
|
useRoute.mockReturnValue({
|
|
187
215
|
params: {
|
|
188
216
|
automate: {},
|
|
@@ -225,7 +253,7 @@ describe('Test SetupConfigCondition', () => {
|
|
|
225
253
|
});
|
|
226
254
|
|
|
227
255
|
const bottomButtonView = instance.findByProps({
|
|
228
|
-
|
|
256
|
+
accessibilityLabel: AccessibilityLabel.BUTTON_CONTINUE,
|
|
229
257
|
});
|
|
230
258
|
|
|
231
259
|
await act(async () => {
|
|
@@ -273,7 +301,7 @@ describe('Test SetupConfigCondition', () => {
|
|
|
273
301
|
});
|
|
274
302
|
|
|
275
303
|
const bottomButtonView = instance.findByProps({
|
|
276
|
-
|
|
304
|
+
accessibilityLabel: AccessibilityLabel.BUTTON_CONTINUE,
|
|
277
305
|
});
|
|
278
306
|
|
|
279
307
|
await act(async () => {
|
|
@@ -333,4 +361,81 @@ describe('Test SetupConfigCondition', () => {
|
|
|
333
361
|
'Customize conditions'
|
|
334
362
|
);
|
|
335
363
|
});
|
|
364
|
+
|
|
365
|
+
it('test isCreateCondition success', async () => {
|
|
366
|
+
useSCContextSelector.mockImplementation((selector) =>
|
|
367
|
+
selector({
|
|
368
|
+
automate: {
|
|
369
|
+
isCreateCondition: true,
|
|
370
|
+
isUpdateCondition: false,
|
|
371
|
+
},
|
|
372
|
+
})
|
|
373
|
+
);
|
|
374
|
+
useRoute.mockReturnValue({
|
|
375
|
+
params: {
|
|
376
|
+
config: {
|
|
377
|
+
id: 1,
|
|
378
|
+
name: 'config name',
|
|
379
|
+
title: 'is below (<)',
|
|
380
|
+
value_evaluations: [BOOLEAN_VALUE_EVALUATION_CONFIGURATION],
|
|
381
|
+
},
|
|
382
|
+
automate: { id: 1 },
|
|
383
|
+
sensorData: [],
|
|
384
|
+
},
|
|
385
|
+
});
|
|
386
|
+
mock.onPost(API.AUTOMATE.ADD_CONDITION(1)).reply(200);
|
|
387
|
+
await act(async () => {
|
|
388
|
+
tree = await create(wrapComponent());
|
|
389
|
+
});
|
|
390
|
+
const instance = tree.root;
|
|
391
|
+
|
|
392
|
+
const gridItems = instance.findAllByType(GridItem);
|
|
393
|
+
expect(gridItems).toHaveLength(3);
|
|
394
|
+
await act(async () => {
|
|
395
|
+
gridItems[0].props.onPress();
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
expect(global.mockedNavigate).toBeCalledWith({
|
|
399
|
+
name: 'ScriptDetail',
|
|
400
|
+
params: {
|
|
401
|
+
preAutomate: { condition: 'value_evaluation', id: 1, value: [1, 0] },
|
|
402
|
+
},
|
|
403
|
+
});
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
it('test isUpdateCondition fail', async () => {
|
|
407
|
+
useSCContextSelector.mockImplementation((selector) =>
|
|
408
|
+
selector({
|
|
409
|
+
automate: {
|
|
410
|
+
isCreateCondition: false,
|
|
411
|
+
isUpdateCondition: 1,
|
|
412
|
+
},
|
|
413
|
+
})
|
|
414
|
+
);
|
|
415
|
+
useRoute.mockReturnValue({
|
|
416
|
+
params: {
|
|
417
|
+
config: {
|
|
418
|
+
id: 1,
|
|
419
|
+
name: 'config name',
|
|
420
|
+
title: 'is below (<)',
|
|
421
|
+
value_evaluations: [BOOLEAN_VALUE_EVALUATION_CONFIGURATION],
|
|
422
|
+
},
|
|
423
|
+
automate: { id: 1 },
|
|
424
|
+
sensorData: [],
|
|
425
|
+
},
|
|
426
|
+
});
|
|
427
|
+
mock.onPut(API.AUTOMATE.UPDATE_CONDITION(1, 1)).reply(400);
|
|
428
|
+
await act(async () => {
|
|
429
|
+
tree = await create(wrapComponent());
|
|
430
|
+
});
|
|
431
|
+
const instance = tree.root;
|
|
432
|
+
|
|
433
|
+
const gridItems = instance.findAllByType(GridItem);
|
|
434
|
+
expect(gridItems).toHaveLength(3);
|
|
435
|
+
await act(async () => {
|
|
436
|
+
gridItems[0].props.onPress();
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
expect(global.mockedNavigate).not.toBeCalled();
|
|
440
|
+
});
|
|
336
441
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useNavigation } from '@react-navigation/native';
|
|
2
|
-
import React, { useCallback, useState } from 'react';
|
|
2
|
+
import React, { useCallback, useContext, useState } from 'react';
|
|
3
3
|
import { View } from 'react-native';
|
|
4
4
|
import ItemAutomate from '../../../commons/Automate/ItemAutomate';
|
|
5
5
|
import { HeaderCustom } from '../../../commons/Header';
|
|
@@ -8,9 +8,12 @@ import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
|
8
8
|
import Routes from '../../../utils/Route';
|
|
9
9
|
import styles from './styles/AddNewAutoSmartStyles';
|
|
10
10
|
import { AUTOMATE_TYPE } from '../../../configs/Constants';
|
|
11
|
+
import { SCContext } from '../../../context';
|
|
12
|
+
import { Action } from '../../../context/actionType';
|
|
11
13
|
|
|
12
14
|
const AddTypeSmart = ({ smartTypes, route }) => {
|
|
13
15
|
const t = useTranslations();
|
|
16
|
+
const { setAction } = useContext(SCContext);
|
|
14
17
|
const { navigate, goBack } = useNavigation();
|
|
15
18
|
const { automate = {}, closeScreen } = route?.params || {};
|
|
16
19
|
const { id, unit, type } = automate;
|
|
@@ -30,7 +33,8 @@ const AddTypeSmart = ({ smartTypes, route }) => {
|
|
|
30
33
|
unitId: unit,
|
|
31
34
|
closeScreen: closeScreen,
|
|
32
35
|
};
|
|
33
|
-
|
|
36
|
+
setAction(Action.IS_CREATE_CONDITION, false);
|
|
37
|
+
setAction(Action.IS_UPDATE_CONDITION, false);
|
|
34
38
|
if (!unit && dataAutomate.type === AUTOMATE_TYPE.VALUE_CHANGE) {
|
|
35
39
|
navigate(Routes.SelectUnit, params);
|
|
36
40
|
return;
|
|
@@ -38,7 +42,7 @@ const AddTypeSmart = ({ smartTypes, route }) => {
|
|
|
38
42
|
|
|
39
43
|
navigate(dataAutomate.route, params);
|
|
40
44
|
},
|
|
41
|
-
[smartTypes, automate, unit, closeScreen, navigate]
|
|
45
|
+
[smartTypes, automate, unit, closeScreen, setAction, navigate]
|
|
42
46
|
);
|
|
43
47
|
|
|
44
48
|
const onSelectType = (index) => {
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import React, { useCallback } from 'react';
|
|
2
|
+
import { API, Colors } from '../../../../configs';
|
|
3
|
+
import AlertAction from '../../../../commons/AlertAction';
|
|
4
|
+
import { axiosDelete } from '../../../../utils/Apis/axios';
|
|
5
|
+
import { ToastBottomHelper } from '../../../../utils/Utils';
|
|
6
|
+
import { useTranslations } from '../../../../hooks/Common/useTranslations';
|
|
7
|
+
import AccessibilityLabel from '../../../../configs/AccessibilityLabel';
|
|
8
|
+
|
|
9
|
+
const DeleteCondition = ({
|
|
10
|
+
automate,
|
|
11
|
+
setAutomate,
|
|
12
|
+
condition,
|
|
13
|
+
isVisible,
|
|
14
|
+
setIsVisible,
|
|
15
|
+
}) => {
|
|
16
|
+
const t = useTranslations();
|
|
17
|
+
const deleteScript = useCallback(async () => {
|
|
18
|
+
const { success } = await axiosDelete(
|
|
19
|
+
API.AUTOMATE.DELETE_CONDITION(automate.id, condition.id)
|
|
20
|
+
);
|
|
21
|
+
if (success) {
|
|
22
|
+
ToastBottomHelper.success(t('removed_successfully'));
|
|
23
|
+
const conditions = automate.conditions.filter(
|
|
24
|
+
(el) => el.id !== condition.id
|
|
25
|
+
);
|
|
26
|
+
setAutomate((prev) => ({ ...prev, conditions }));
|
|
27
|
+
} else {
|
|
28
|
+
ToastBottomHelper.error(t('remove_failed'));
|
|
29
|
+
}
|
|
30
|
+
setIsVisible({});
|
|
31
|
+
}, [automate, condition.id, setAutomate, setIsVisible, t]);
|
|
32
|
+
|
|
33
|
+
const hidePopup = () => setIsVisible({});
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<AlertAction
|
|
37
|
+
visible={isVisible}
|
|
38
|
+
hideModal={hidePopup}
|
|
39
|
+
title={t('title_delete_condition')}
|
|
40
|
+
message={t('message_delete_condition')}
|
|
41
|
+
leftButtonTitle={t('cancel')}
|
|
42
|
+
leftButtonClick={hidePopup}
|
|
43
|
+
rightButtonTitle={t('remove')}
|
|
44
|
+
rightButtonClick={deleteScript}
|
|
45
|
+
rightButtonStyle={{ color: Colors.Red6 }}
|
|
46
|
+
accessibilityLabel={AccessibilityLabel.AUTOMATE_DELETE_CONDITION}
|
|
47
|
+
/>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export default DeleteCondition;
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import React, { memo, useContext, useMemo } from 'react';
|
|
2
|
+
|
|
3
|
+
import { useRoute } from '@react-navigation/native';
|
|
4
|
+
|
|
5
|
+
import { ModalCustom } from '../../../../commons/Modal';
|
|
6
|
+
import { StyleSheet, View } from 'react-native';
|
|
7
|
+
import { Colors } from '../../../../configs';
|
|
8
|
+
import { useTranslations } from '../../../../hooks/Common/useTranslations';
|
|
9
|
+
import { useBackendPermission } from '../../../../utils/Permission/backend';
|
|
10
|
+
import ValueChange from '../../../../../assets/images/Automation-fill.svg';
|
|
11
|
+
import Schedule from '../../../../../assets/images/Schedule.svg';
|
|
12
|
+
import { TouchableOpacity } from 'react-native';
|
|
13
|
+
import { Text } from '../../../../commons';
|
|
14
|
+
import Routes from '../../../../utils/Route';
|
|
15
|
+
import AccessibilityLabel from '../../../../configs/AccessibilityLabel';
|
|
16
|
+
import { SCContext } from '../../../../context';
|
|
17
|
+
import { Action } from '../../../../context/actionType';
|
|
18
|
+
|
|
19
|
+
const ModalAddCondition = memo(
|
|
20
|
+
({ automate, isVisible, setIsVisible, numberActionAdded, navigate }) => {
|
|
21
|
+
const t = useTranslations();
|
|
22
|
+
const { setAction } = useContext(SCContext);
|
|
23
|
+
const { unit } = automate;
|
|
24
|
+
const { name: currentScreenName } = useRoute();
|
|
25
|
+
const permissions = useBackendPermission();
|
|
26
|
+
const { max_actions_per_automation } = permissions || {};
|
|
27
|
+
|
|
28
|
+
const listItem = useMemo(() => {
|
|
29
|
+
return [
|
|
30
|
+
{
|
|
31
|
+
id: 'time_frame',
|
|
32
|
+
text: t('time_frame'),
|
|
33
|
+
example: t('ex_time_frame'),
|
|
34
|
+
image: <Schedule />,
|
|
35
|
+
onClick: () => {
|
|
36
|
+
setIsVisible(false);
|
|
37
|
+
navigate(Routes.AddEditConditionSchedule, {
|
|
38
|
+
automate: automate,
|
|
39
|
+
closeScreen: Routes.ScriptDetail,
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
id: 'when_value_change',
|
|
45
|
+
text: t('when_value_change'),
|
|
46
|
+
example: t('ex_when_value_change'),
|
|
47
|
+
image: <ValueChange />,
|
|
48
|
+
onClick: () => {
|
|
49
|
+
setIsVisible(false);
|
|
50
|
+
const navParams = {
|
|
51
|
+
automate: automate,
|
|
52
|
+
closeScreen: currentScreenName,
|
|
53
|
+
numberActionCanAdd:
|
|
54
|
+
max_actions_per_automation - numberActionAdded,
|
|
55
|
+
routeName: unit ? null : Routes.SelectControlDevices,
|
|
56
|
+
};
|
|
57
|
+
setAction(Action.IS_UPDATE_CONDITION, false);
|
|
58
|
+
setAction(Action.IS_CREATE_CONDITION, true);
|
|
59
|
+
navigate(Routes.SelectMonitorDevices, navParams);
|
|
60
|
+
if (unit) {
|
|
61
|
+
navigate(Routes.SelectMonitorDevices, navParams);
|
|
62
|
+
} else {
|
|
63
|
+
navigate(Routes.SelectUnit, {
|
|
64
|
+
automate,
|
|
65
|
+
routeName: Routes.SelectMonitorDevices,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
];
|
|
71
|
+
}, [
|
|
72
|
+
automate,
|
|
73
|
+
currentScreenName,
|
|
74
|
+
max_actions_per_automation,
|
|
75
|
+
navigate,
|
|
76
|
+
numberActionAdded,
|
|
77
|
+
setAction,
|
|
78
|
+
setIsVisible,
|
|
79
|
+
t,
|
|
80
|
+
unit,
|
|
81
|
+
]);
|
|
82
|
+
|
|
83
|
+
const hidePopup = () => setIsVisible(false);
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<ModalCustom
|
|
87
|
+
isVisible={isVisible}
|
|
88
|
+
onBackButtonPress={hidePopup}
|
|
89
|
+
onBackdropPress={hidePopup}
|
|
90
|
+
style={styles.container}
|
|
91
|
+
>
|
|
92
|
+
<View style={styles.popoverStyle}>
|
|
93
|
+
<View style={styles.modalWrapper}>
|
|
94
|
+
<View style={styles.modalHeader}>
|
|
95
|
+
<Text style={styles.modalHeaderText} semibold>
|
|
96
|
+
{t('add_condition')}
|
|
97
|
+
</Text>
|
|
98
|
+
</View>
|
|
99
|
+
{listItem.map((item, index) => {
|
|
100
|
+
return (
|
|
101
|
+
<View style={styles.rowItem} key={`rowItem-${index}`}>
|
|
102
|
+
<TouchableOpacity
|
|
103
|
+
onPress={item.onClick}
|
|
104
|
+
accessibilityLabel={
|
|
105
|
+
AccessibilityLabel.AUTOMATE_LIST_SCRIPT_ACTION
|
|
106
|
+
}
|
|
107
|
+
>
|
|
108
|
+
<View style={styles.wapItem}>
|
|
109
|
+
<View style={styles.imageItem}>{item.image}</View>
|
|
110
|
+
<View style={styles.colItem}>
|
|
111
|
+
<Text type="Body" semibold>
|
|
112
|
+
{item.text}
|
|
113
|
+
</Text>
|
|
114
|
+
<Text style={styles.textItem} numberOfLines={1}>
|
|
115
|
+
{item.example}
|
|
116
|
+
</Text>
|
|
117
|
+
</View>
|
|
118
|
+
</View>
|
|
119
|
+
</TouchableOpacity>
|
|
120
|
+
</View>
|
|
121
|
+
);
|
|
122
|
+
})}
|
|
123
|
+
</View>
|
|
124
|
+
</View>
|
|
125
|
+
</ModalCustom>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
export default ModalAddCondition;
|
|
131
|
+
|
|
132
|
+
const styles = StyleSheet.create({
|
|
133
|
+
container: {
|
|
134
|
+
flex: 1,
|
|
135
|
+
margin: 0,
|
|
136
|
+
},
|
|
137
|
+
popoverStyle: {
|
|
138
|
+
width: '100%',
|
|
139
|
+
backgroundColor: Colors.White,
|
|
140
|
+
bottom: 0,
|
|
141
|
+
left: 0,
|
|
142
|
+
position: 'absolute',
|
|
143
|
+
borderRadius: 10,
|
|
144
|
+
paddingBottom: 50,
|
|
145
|
+
},
|
|
146
|
+
modalWrapper: {
|
|
147
|
+
flex: 1,
|
|
148
|
+
flexDirection: 'column',
|
|
149
|
+
backgroundColor: Colors.White,
|
|
150
|
+
borderRadius: 10,
|
|
151
|
+
},
|
|
152
|
+
modalHeader: {
|
|
153
|
+
padding: 16,
|
|
154
|
+
marginBottom: 10,
|
|
155
|
+
backgroundColor: Colors.White,
|
|
156
|
+
alignItems: 'center',
|
|
157
|
+
justifyContent: 'center',
|
|
158
|
+
borderBottomWidth: 1,
|
|
159
|
+
borderTopLeftRadius: 20,
|
|
160
|
+
borderTopRightRadius: 20,
|
|
161
|
+
borderColor: Colors.Gray4,
|
|
162
|
+
},
|
|
163
|
+
modalHeaderText: {
|
|
164
|
+
fontSize: 16,
|
|
165
|
+
lineHeight: 24,
|
|
166
|
+
color: Colors.Gray9,
|
|
167
|
+
},
|
|
168
|
+
rowItem: {
|
|
169
|
+
padding: 16,
|
|
170
|
+
marginBottom: 10,
|
|
171
|
+
marginHorizontal: 10,
|
|
172
|
+
backgroundColor: Colors.White,
|
|
173
|
+
borderRadius: 16,
|
|
174
|
+
borderWidth: 1,
|
|
175
|
+
borderColor: Colors.Gray4,
|
|
176
|
+
},
|
|
177
|
+
wapItem: {
|
|
178
|
+
flexDirection: 'row',
|
|
179
|
+
alignItems: 'center',
|
|
180
|
+
justifyContent: 'center',
|
|
181
|
+
},
|
|
182
|
+
imageItem: {
|
|
183
|
+
width: '10%',
|
|
184
|
+
alignItems: 'center',
|
|
185
|
+
justifyContent: 'center',
|
|
186
|
+
marginRight: 20,
|
|
187
|
+
},
|
|
188
|
+
colItem: {
|
|
189
|
+
flex: 1,
|
|
190
|
+
flexDirection: 'column',
|
|
191
|
+
},
|
|
192
|
+
textItem: {
|
|
193
|
+
color: Colors.Gray8,
|
|
194
|
+
fontSize: 12,
|
|
195
|
+
},
|
|
196
|
+
});
|