@eohjsc/react-native-smart-city 0.7.8 → 0.7.9
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/AddNewDevice/add-scan-device-icon.svg +13 -0
- package/assets/images/Email.svg +9 -0
- package/assets/images/lan.svg +3 -0
- package/assets/images/wifi-open.svg +3 -0
- package/package.json +2 -1
- package/src/commons/ActionGroup/StatesGridActionTemplate.js +7 -3
- package/src/commons/ActionGroup/__test__/StatesGridActionTemplate.test.js +7 -3
- package/src/commons/AlertAction/index.js +1 -0
- package/src/commons/Auth/AccountItem.js +17 -3
- package/src/commons/Auth/AccountList.js +3 -7
- package/src/commons/ConnectWifi/__test__/ConnectWifi.test.js +373 -0
- package/src/commons/ConnectWifi/index.js +201 -0
- package/src/commons/ConnectWifi/styles.js +69 -0
- package/src/commons/Form/TextInputPassword.js +1 -1
- package/src/commons/OneTapTemplate/StatesGridActionTemplate.js +6 -2
- package/src/configs/API.js +12 -0
- package/src/configs/AccessibilityLabel.js +7 -0
- package/src/configs/Constants.js +1 -0
- package/src/hooks/Common/index.js +2 -2
- package/src/hooks/Common/useBlockBack.js +36 -0
- package/src/hooks/useMqtt.js +10 -5
- package/src/navigations/AddGatewayStack.js +2 -0
- package/src/navigations/AllGatewayStack.js +4 -0
- package/src/navigations/Main.js +2 -2
- package/src/navigations/UnitStack.js +32 -0
- package/src/screens/AddNewGateway/ConnectingWifiDevice.js +7 -6
- package/src/screens/AddNewGateway/ScanDeviceLocal.js +267 -0
- package/src/screens/AddNewGateway/ScanDeviceLocalStyles.js +58 -0
- package/src/screens/AddNewGateway/SelectDeviceSubUnit.js +10 -2
- package/src/screens/AddNewGateway/SelectDeviceType.js +19 -2
- package/src/screens/AddNewGateway/__test__/ScanDeviceLocal.test.js +475 -0
- package/src/screens/AddNewGateway/__test__/SelectDeviceType.test.js +2 -2
- package/src/screens/AddNewGateway/configs/API.js +8 -0
- package/src/screens/AddNewGateway/hooks/useConnectDevice.js +59 -0
- package/src/screens/AllGateway/GatewayInfo/__test__/index.test.js +58 -1
- package/src/screens/AllGateway/GatewayInfo/index.js +8 -6
- package/src/screens/AllGateway/GatewayWifi/__test__/index.test.js +319 -0
- package/src/screens/AllGateway/GatewayWifi/index.js +107 -0
- package/src/screens/AllGateway/Successfully/__test__/index.test.js +77 -0
- package/src/screens/AllGateway/Successfully/index.js +66 -0
- package/src/screens/AllGateway/Successfully/styles.js +35 -0
- package/src/screens/AllGateway/components/Information/index.js +17 -1
- package/src/screens/AllGateway/components/RowItem/index.js +12 -1
- package/src/screens/AllGateway/hooks/__test__/index.test.js +18 -0
- package/src/screens/AllGateway/hooks/useGateway.js +13 -0
- package/src/screens/Automate/AddNewAction/SetupConfigCondition.js +3 -3
- package/src/screens/Automate/AddNewAction/SetupScriptEmail.js +79 -0
- package/src/screens/Automate/AddNewAction/SetupScriptReceiverEmail.js +166 -0
- package/src/screens/Automate/AddNewAction/Styles/SetupScriptEmailStyles.js +37 -0
- package/src/screens/Automate/AddNewAction/Styles/SetupScriptReceiverEmailStyles.js +79 -0
- package/src/screens/Automate/AddNewAction/__test__/ChooseAction.test.js +1 -1
- package/src/screens/Automate/AddNewAction/__test__/SetupConfigCondition.test.js +13 -5
- package/src/screens/Automate/AddNewAction/__test__/SetupScriptEmail.test.js +76 -0
- package/src/screens/Automate/AddNewAction/__test__/SetupScriptReceiverEmail.test.js +105 -0
- package/src/screens/Automate/EditActionsList/Styles/UpdateReceiverEmailScriptStyles.js +78 -0
- package/src/screens/Automate/EditActionsList/UpdateEmailScript.js +80 -0
- package/src/screens/Automate/EditActionsList/UpdateReceiverEmailScript.js +179 -0
- package/src/screens/Automate/EditActionsList/__tests__/UpdateEmailScript.test.js +81 -0
- package/src/screens/Automate/EditActionsList/__tests__/UpdateReceiverEmailScript.test.js +83 -0
- package/src/screens/Automate/EditActionsList/__tests__/index.test.js +38 -5
- package/src/screens/Automate/EditActionsList/index.js +59 -2
- package/src/screens/Automate/ScriptDetail/Components/AddActionScript.js +20 -0
- package/src/screens/Automate/ScriptDetail/Styles/indexStyles.js +5 -3
- package/src/screens/Automate/ScriptDetail/__test__/index.test.js +127 -21
- package/src/screens/Automate/ScriptDetail/index.js +57 -14
- package/src/screens/SharedUnit/index.js +2 -2
- package/src/screens/Sharing/SelectUser.js +47 -47
- package/src/screens/Sharing/__test__/SelectUser.test.js +57 -103
- package/src/screens/SubUnit/ManageSubUnit.js +94 -90
- package/src/screens/SubUnit/ManageSubUnitStyles.js +4 -6
- package/src/screens/SubUnit/RearrageSubUnit.js +90 -0
- package/src/screens/SubUnit/RearrrageSubUnitStyle.js +65 -0
- package/src/screens/SubUnit/__test__/ManageSubUnit.test.js +35 -19
- package/src/screens/SubUnit/__test__/RearrangeSubUnit.test.js +129 -0
- package/src/screens/SubUnit/hooks/__test__/useManageSubUnit.test.js +6 -7
- package/src/screens/SubUnit/hooks/useManageSubUnit.js +8 -16
- package/src/screens/Unit/Detail.js +2 -6
- package/src/screens/Unit/ManageUnit.js +1 -1
- package/src/utils/Functions/__test__/ShortEmail.test.js +5 -0
- package/src/utils/I18n/translations/en.js +46 -8
- package/src/utils/I18n/translations/vi.js +37 -4
- package/src/utils/Route/index.js +7 -0
- package/src/commons/Auth/__test__/AccountItem.test.js +0 -31
- package/src/hooks/Common/useBlockBackAndroid.js +0 -21
- package/src/screens/SubUnit/DetailStyles.js +0 -46
|
@@ -8,6 +8,7 @@ import { GestureHandlerRootView } from 'react-native-gesture-handler';
|
|
|
8
8
|
import Close from '../../../../assets/images/Close.svg';
|
|
9
9
|
import Delay from '../../../../assets/images/Delay.svg';
|
|
10
10
|
import Notify from '../../../../assets/images/Notify.svg';
|
|
11
|
+
import Email from '../../../../assets/images/Email.svg';
|
|
11
12
|
import Rearrange from '../../../../assets/images/Rearrange.svg';
|
|
12
13
|
import { FullLoading } from '../../../commons';
|
|
13
14
|
import FImage from '../../../commons/FImage';
|
|
@@ -23,6 +24,7 @@ import { ToastBottomHelper } from '../../../utils/Utils';
|
|
|
23
24
|
import styles from './Styles/indexStyles';
|
|
24
25
|
import UpdateDelayScript from './UpdateDelayScript';
|
|
25
26
|
import UpdateNotifyScript from './UpdateNotifyScript';
|
|
27
|
+
import UpdateEmailScript from './UpdateEmailScript';
|
|
26
28
|
|
|
27
29
|
const EditActionsList = () => {
|
|
28
30
|
const t = useTranslations();
|
|
@@ -138,7 +140,7 @@ const EditActionsList = () => {
|
|
|
138
140
|
({ item, getIndex, drag, isActive }) => {
|
|
139
141
|
const index = getIndex();
|
|
140
142
|
const paddedIndex = (index + 1).toString().padStart(2, '0');
|
|
141
|
-
const { action_script, notify_script, delay_script } = item;
|
|
143
|
+
const { action_script, notify_script, delay_script, email_script } = item;
|
|
142
144
|
if (action_script) {
|
|
143
145
|
const {
|
|
144
146
|
sensor_icon_kit,
|
|
@@ -236,6 +238,37 @@ const EditActionsList = () => {
|
|
|
236
238
|
/>
|
|
237
239
|
);
|
|
238
240
|
}
|
|
241
|
+
if (email_script) {
|
|
242
|
+
const { title, message, str_emails } = email_script;
|
|
243
|
+
|
|
244
|
+
return (
|
|
245
|
+
<CommonItem
|
|
246
|
+
paddedIndex={paddedIndex}
|
|
247
|
+
icon={
|
|
248
|
+
<View style={styles.iconItem}>
|
|
249
|
+
<Email />
|
|
250
|
+
</View>
|
|
251
|
+
}
|
|
252
|
+
content={
|
|
253
|
+
<>
|
|
254
|
+
<Text numberOfLines={1} type="H4" color={Colors.Gray9} semibold>
|
|
255
|
+
{title}
|
|
256
|
+
</Text>
|
|
257
|
+
<Text numberOfLines={1} type="H4" color={Colors.Gray9}>
|
|
258
|
+
{message}
|
|
259
|
+
</Text>
|
|
260
|
+
<Text numberOfLines={1} type="H4" color={Colors.Gray9}>
|
|
261
|
+
{str_emails}
|
|
262
|
+
</Text>
|
|
263
|
+
</>
|
|
264
|
+
}
|
|
265
|
+
onPress={() => onPressRemove(item)}
|
|
266
|
+
onPressUpdate={() => onShowPopupUpdate(item, index)}
|
|
267
|
+
isActive={isActive}
|
|
268
|
+
drag={drag}
|
|
269
|
+
/>
|
|
270
|
+
);
|
|
271
|
+
}
|
|
239
272
|
},
|
|
240
273
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
241
274
|
[needRefresh]
|
|
@@ -246,6 +279,7 @@ const EditActionsList = () => {
|
|
|
246
279
|
action_script,
|
|
247
280
|
notify_script,
|
|
248
281
|
delay_script,
|
|
282
|
+
email_script,
|
|
249
283
|
id: scriptItemId,
|
|
250
284
|
} = scriptItem;
|
|
251
285
|
|
|
@@ -294,6 +328,18 @@ const EditActionsList = () => {
|
|
|
294
328
|
/>
|
|
295
329
|
);
|
|
296
330
|
}
|
|
331
|
+
if (email_script) {
|
|
332
|
+
return (
|
|
333
|
+
<UpdateEmailScript
|
|
334
|
+
unitId={unitId}
|
|
335
|
+
automateId={id}
|
|
336
|
+
scriptItemId={scriptItemId}
|
|
337
|
+
email_script={email_script}
|
|
338
|
+
t={t}
|
|
339
|
+
onClosePopup={onClosePopup}
|
|
340
|
+
/>
|
|
341
|
+
);
|
|
342
|
+
}
|
|
297
343
|
}, [actionsList, id, navigate, scriptItem, t, unitId, updateIndex]);
|
|
298
344
|
|
|
299
345
|
const onDragEnd = useCallback(
|
|
@@ -309,7 +355,8 @@ const EditActionsList = () => {
|
|
|
309
355
|
);
|
|
310
356
|
|
|
311
357
|
const renderMessageRemove = useMemo(() => {
|
|
312
|
-
const { action_script, notify_script, delay_script } =
|
|
358
|
+
const { action_script, notify_script, delay_script, email_script } =
|
|
359
|
+
itemRemove;
|
|
313
360
|
if (action_script) {
|
|
314
361
|
return (
|
|
315
362
|
<ParsedText
|
|
@@ -353,6 +400,16 @@ const EditActionsList = () => {
|
|
|
353
400
|
</ParsedText>
|
|
354
401
|
);
|
|
355
402
|
}
|
|
403
|
+
if (email_script) {
|
|
404
|
+
return (
|
|
405
|
+
<ParsedText
|
|
406
|
+
style={styles.messageDelete}
|
|
407
|
+
childrenProps={{ allowFontScaling: false }}
|
|
408
|
+
>
|
|
409
|
+
{t('message_delete_notify', { title: email_script.title })}
|
|
410
|
+
</ParsedText>
|
|
411
|
+
);
|
|
412
|
+
}
|
|
356
413
|
}, [itemRemove, t]);
|
|
357
414
|
|
|
358
415
|
return (
|
|
@@ -10,6 +10,7 @@ import { useBackendPermission } from '../../../../utils/Permission/backend';
|
|
|
10
10
|
import Event from '../../../../../assets/images/Event.svg';
|
|
11
11
|
import Notify from '../../../../../assets/images/Notify.svg';
|
|
12
12
|
import Delay from '../../../../../assets/images/Delay.svg';
|
|
13
|
+
import Email from '../../../../../assets/images/Email.svg';
|
|
13
14
|
import { TouchableOpacity } from 'react-native';
|
|
14
15
|
import { IconOutline } from '@ant-design/icons-react-native';
|
|
15
16
|
import { Text } from '../../../../commons';
|
|
@@ -79,6 +80,25 @@ const AddActionScript = memo(
|
|
|
79
80
|
});
|
|
80
81
|
},
|
|
81
82
|
},
|
|
83
|
+
{
|
|
84
|
+
id: 'send_email',
|
|
85
|
+
text: t('send_email'),
|
|
86
|
+
image: <Email />,
|
|
87
|
+
onClick: () => {
|
|
88
|
+
setIsVisible(false);
|
|
89
|
+
if (unit) {
|
|
90
|
+
navigate(Routes.SetupScriptEmail, {
|
|
91
|
+
automate,
|
|
92
|
+
unitId: unit,
|
|
93
|
+
});
|
|
94
|
+
} else {
|
|
95
|
+
navigate(Routes.SelectUnit, {
|
|
96
|
+
automate,
|
|
97
|
+
routeName: Routes.SetupScriptEmail,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
},
|
|
82
102
|
];
|
|
83
103
|
}, [
|
|
84
104
|
automate,
|
|
@@ -101,13 +101,15 @@ export default StyleSheet.create({
|
|
|
101
101
|
},
|
|
102
102
|
rightItem: {
|
|
103
103
|
flex: 1,
|
|
104
|
-
marginLeft: 4,
|
|
105
|
-
borderRadius: 4,
|
|
106
104
|
borderColor: Colors.Gray4,
|
|
107
105
|
borderWidth: 1,
|
|
108
|
-
|
|
106
|
+
borderRadius: 4,
|
|
109
107
|
paddingVertical: 15,
|
|
110
108
|
paddingHorizontal: 16,
|
|
109
|
+
marginLeft: 4,
|
|
110
|
+
},
|
|
111
|
+
insideItemRight: {
|
|
112
|
+
flexDirection: 'row',
|
|
111
113
|
},
|
|
112
114
|
rightItemAdd: {
|
|
113
115
|
flex: 1,
|
|
@@ -38,10 +38,13 @@ describe('Test ScriptDetail', () => {
|
|
|
38
38
|
let tree;
|
|
39
39
|
|
|
40
40
|
const mockGoBack = useNavigation().goBack;
|
|
41
|
+
const mockAddListener = useNavigation().addListener;
|
|
41
42
|
const mockedNavigate = useNavigation().navigate;
|
|
42
43
|
beforeEach(() => {
|
|
43
44
|
mockGoBack.mockClear();
|
|
45
|
+
mockAddListener.mockClear();
|
|
44
46
|
mockedNavigate.mockClear();
|
|
47
|
+
global.mockedNavigate.mockClear();
|
|
45
48
|
mock.reset();
|
|
46
49
|
route = {
|
|
47
50
|
params: {
|
|
@@ -91,6 +94,16 @@ describe('Test ScriptDetail', () => {
|
|
|
91
94
|
notify_script: null,
|
|
92
95
|
delay_script: { delay: 10 },
|
|
93
96
|
},
|
|
97
|
+
{
|
|
98
|
+
action_script: null,
|
|
99
|
+
notify_script: null,
|
|
100
|
+
email_script: {
|
|
101
|
+
title: 'title',
|
|
102
|
+
message: 'message',
|
|
103
|
+
unit_id: 60,
|
|
104
|
+
str_emails: 'email0@eoh.io',
|
|
105
|
+
},
|
|
106
|
+
},
|
|
94
107
|
],
|
|
95
108
|
};
|
|
96
109
|
});
|
|
@@ -165,12 +178,12 @@ describe('Test ScriptDetail', () => {
|
|
|
165
178
|
await act(async () => {
|
|
166
179
|
await menu.props.onPress();
|
|
167
180
|
});
|
|
168
|
-
expect(spyToastError).
|
|
181
|
+
expect(spyToastError).toHaveBeenCalledWith(
|
|
169
182
|
getTranslate('en', 'only_owner_has_permission_to_edit_this_script')
|
|
170
183
|
);
|
|
171
184
|
});
|
|
172
185
|
|
|
173
|
-
it('test cannot
|
|
186
|
+
it('test cannot edit condition because not owner', async () => {
|
|
174
187
|
route.params.preAutomate.can_edit = false;
|
|
175
188
|
const spyToastError = jest.spyOn(ToastBottomHelper, 'error');
|
|
176
189
|
|
|
@@ -194,14 +207,46 @@ describe('Test ScriptDetail', () => {
|
|
|
194
207
|
|
|
195
208
|
await act(async () => {
|
|
196
209
|
menuActionMore.props.onItemClick({ doAction: jest.fn() });
|
|
197
|
-
menuActionMore.props.listMenuItem[
|
|
210
|
+
menuActionMore.props.listMenuItem[0].doAction();
|
|
198
211
|
});
|
|
199
212
|
|
|
200
|
-
expect(spyToastError).
|
|
213
|
+
expect(spyToastError).toHaveBeenCalledWith(
|
|
201
214
|
getTranslate('en', 'only_owner_has_permission_to_edit_this_script')
|
|
202
215
|
);
|
|
203
216
|
});
|
|
204
217
|
|
|
218
|
+
it('test cannot edit condition because script disabled', async () => {
|
|
219
|
+
route.params.preAutomate.script.enable = false;
|
|
220
|
+
const spyToastError = jest.spyOn(ToastBottomHelper, 'error');
|
|
221
|
+
|
|
222
|
+
await act(async () => {
|
|
223
|
+
tree = await create(wrapComponent(route));
|
|
224
|
+
});
|
|
225
|
+
const instance = tree.root;
|
|
226
|
+
const button = instance.find(
|
|
227
|
+
(el) =>
|
|
228
|
+
el.props.accessibilityLabel === AccessibilityLabel.ICON_MENU_POPUP &&
|
|
229
|
+
el.type === TouchableOpacity
|
|
230
|
+
);
|
|
231
|
+
await act(async () => {
|
|
232
|
+
await button.props.onPress();
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
const menuActionMore = instance.find(
|
|
236
|
+
(el) =>
|
|
237
|
+
el.props.accessibilityLabel === AccessibilityLabel.MENU_POPPER_MORE_2
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
await act(async () => {
|
|
241
|
+
menuActionMore.props.onItemClick({ doAction: jest.fn() });
|
|
242
|
+
menuActionMore.props.listMenuItem[0].doAction();
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
expect(spyToastError).toBeCalledWith(
|
|
246
|
+
getTranslate('en', 'this_script_has_been_disabled')
|
|
247
|
+
);
|
|
248
|
+
});
|
|
249
|
+
|
|
205
250
|
it('test delete script', async () => {
|
|
206
251
|
await act(async () => {
|
|
207
252
|
tree = await create(wrapComponent(route));
|
|
@@ -322,7 +367,7 @@ describe('Test ScriptDetail', () => {
|
|
|
322
367
|
AccessibilityLabel.AUTOMATE_LIST_SCRIPT_ACTION &&
|
|
323
368
|
el.type === TouchableOpacity
|
|
324
369
|
);
|
|
325
|
-
expect(listScriptActions).toHaveLength(
|
|
370
|
+
expect(listScriptActions).toHaveLength(4);
|
|
326
371
|
await act(async () => {
|
|
327
372
|
await listScriptActions[0].props.onPress();
|
|
328
373
|
});
|
|
@@ -360,6 +405,18 @@ describe('Test ScriptDetail', () => {
|
|
|
360
405
|
automate: route.params.preAutomate,
|
|
361
406
|
}
|
|
362
407
|
);
|
|
408
|
+
mockedNavigate.mockClear();
|
|
409
|
+
await act(async () => {
|
|
410
|
+
await listScriptActions[3].props.onPress();
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
expect(global.mockedNavigate).toHaveBeenCalledWith(
|
|
414
|
+
Routes.SetupScriptEmail,
|
|
415
|
+
{
|
|
416
|
+
automate: route.params.preAutomate,
|
|
417
|
+
unitId: route.params.preAutomate.unit,
|
|
418
|
+
}
|
|
419
|
+
);
|
|
363
420
|
});
|
|
364
421
|
|
|
365
422
|
it('test press disable script', async () => {
|
|
@@ -418,8 +475,8 @@ describe('Test ScriptDetail', () => {
|
|
|
418
475
|
await act(async () => {
|
|
419
476
|
await button.props.onPress();
|
|
420
477
|
});
|
|
421
|
-
expect(global.mockedNavigate).not.
|
|
422
|
-
expect(spyToastError).
|
|
478
|
+
expect(global.mockedNavigate).not.toHaveBeenCalled();
|
|
479
|
+
expect(spyToastError).toHaveBeenCalledWith(
|
|
423
480
|
getTranslate('en', 'reach_max_actions_per_automation', { length: 0 }),
|
|
424
481
|
'',
|
|
425
482
|
7000
|
|
@@ -500,21 +557,24 @@ describe('Test ScriptDetail', () => {
|
|
|
500
557
|
_testGoToActivityLog(3, AUTOMATE_TYPE.VALUE_CHANGE, 'automate', undefined);
|
|
501
558
|
|
|
502
559
|
it('Test render textCondition value change >', async () => {
|
|
560
|
+
const automate = {
|
|
561
|
+
can_edit: true,
|
|
562
|
+
type: AUTOMATE_TYPE.VALUE_CHANGE,
|
|
563
|
+
value_change: {
|
|
564
|
+
config_name: 'Light Value',
|
|
565
|
+
value: 3,
|
|
566
|
+
condition: '>',
|
|
567
|
+
end_device_id: 1,
|
|
568
|
+
unit_id: 1,
|
|
569
|
+
},
|
|
570
|
+
script: {
|
|
571
|
+
name: 'name',
|
|
572
|
+
enable: true,
|
|
573
|
+
},
|
|
574
|
+
};
|
|
503
575
|
route.params = {
|
|
504
576
|
...route.params,
|
|
505
|
-
preAutomate:
|
|
506
|
-
can_edit: true,
|
|
507
|
-
type: AUTOMATE_TYPE.VALUE_CHANGE,
|
|
508
|
-
value_change: {
|
|
509
|
-
config_name: 'Light Value',
|
|
510
|
-
value: 3,
|
|
511
|
-
condition: '>',
|
|
512
|
-
},
|
|
513
|
-
script: {
|
|
514
|
-
name: 'name',
|
|
515
|
-
enable: true,
|
|
516
|
-
},
|
|
517
|
-
},
|
|
577
|
+
preAutomate: automate,
|
|
518
578
|
};
|
|
519
579
|
await act(async () => {
|
|
520
580
|
tree = await create(wrapComponent(route));
|
|
@@ -534,9 +594,29 @@ describe('Test ScriptDetail', () => {
|
|
|
534
594
|
);
|
|
535
595
|
await act(async () => {
|
|
536
596
|
menuActionMore.props.onItemClick({ doAction: jest.fn() });
|
|
597
|
+
menuActionMore.props.listMenuItem[2].doAction();
|
|
598
|
+
});
|
|
599
|
+
expect(global.mockedNavigate).toBeCalledWith(Routes.AddUnknownTypeSmart, {
|
|
600
|
+
automate,
|
|
601
|
+
closeScreen: undefined,
|
|
602
|
+
});
|
|
603
|
+
global.mockedNavigate.mockClear();
|
|
604
|
+
expect(menuActionMore.props.listMenuItem[0].text).toEqual('Device display');
|
|
605
|
+
await act(async () => {
|
|
537
606
|
menuActionMore.props.listMenuItem[0].doAction();
|
|
538
607
|
});
|
|
539
|
-
expect(global.mockedNavigate).
|
|
608
|
+
expect(global.mockedNavigate).toBeCalledWith(Routes.DeviceDetail, {
|
|
609
|
+
sensorId: 1,
|
|
610
|
+
unitId: 1,
|
|
611
|
+
});
|
|
612
|
+
global.mockedNavigate.mockClear();
|
|
613
|
+
expect(menuActionMore.props.listMenuItem[1].text).toEqual('Unit');
|
|
614
|
+
await act(async () => {
|
|
615
|
+
menuActionMore.props.listMenuItem[1].doAction();
|
|
616
|
+
});
|
|
617
|
+
expect(global.mockedNavigate).toBeCalledWith(Routes.UnitDetail, {
|
|
618
|
+
unitId: 1,
|
|
619
|
+
});
|
|
540
620
|
});
|
|
541
621
|
|
|
542
622
|
it('Test render textCondition value change =', async () => {
|
|
@@ -623,4 +703,30 @@ describe('Test ScriptDetail', () => {
|
|
|
623
703
|
'Mon, Tue, Thu, Sat at 19:00'
|
|
624
704
|
);
|
|
625
705
|
});
|
|
706
|
+
|
|
707
|
+
it('test navigate to UnitDetail on event beforeRemove', async () => {
|
|
708
|
+
route.params.closeScreen = Routes.UnitDetail;
|
|
709
|
+
route.params.preAutomate.unit = 2;
|
|
710
|
+
|
|
711
|
+
await act(async () => {
|
|
712
|
+
await create(wrapComponent(route));
|
|
713
|
+
});
|
|
714
|
+
|
|
715
|
+
// beforeRemove test when swipe to back
|
|
716
|
+
const navigation = useNavigation();
|
|
717
|
+
const beforeRemoveEvent = { preventDefault: jest.fn() };
|
|
718
|
+
const beforeRemoveListener = navigation.addListener.mock.calls.find(
|
|
719
|
+
([event]) => event === 'beforeRemove'
|
|
720
|
+
)[1];
|
|
721
|
+
|
|
722
|
+
await act(async () => {
|
|
723
|
+
beforeRemoveListener(beforeRemoveEvent);
|
|
724
|
+
});
|
|
725
|
+
|
|
726
|
+
expect(mockAddListener).toHaveBeenCalled();
|
|
727
|
+
expect(beforeRemoveEvent.preventDefault).toHaveBeenCalled();
|
|
728
|
+
expect(mockedNavigate).toHaveBeenCalledWith(Routes.UnitDetail, {
|
|
729
|
+
unitId: 2,
|
|
730
|
+
});
|
|
731
|
+
});
|
|
626
732
|
});
|
|
@@ -14,6 +14,7 @@ import { useIsFocused, useNavigation } from '@react-navigation/native';
|
|
|
14
14
|
import Add from '../../../../assets/images/Add.svg';
|
|
15
15
|
import Delay from '../../../../assets/images/Delay.svg';
|
|
16
16
|
import Notify from '../../../../assets/images/Notify.svg';
|
|
17
|
+
import Email from '../../../../assets/images/Email.svg';
|
|
17
18
|
import IconComponent from '../../../commons/IconComponent';
|
|
18
19
|
import MenuActionMore from '../../../commons/MenuActionMore';
|
|
19
20
|
import WrapHeaderScrollable from '../../../commons/Sharing/WrapHeaderScrollable';
|
|
@@ -22,7 +23,7 @@ import withPreventDoubleClick from '../../../commons/WithPreventDoubleClick';
|
|
|
22
23
|
import { API, Colors } from '../../../configs';
|
|
23
24
|
import { AccessibilityLabel, AUTOMATE_TYPE } from '../../../configs/Constants';
|
|
24
25
|
import Images from '../../../configs/Images';
|
|
25
|
-
import { usePopover } from '../../../hooks/Common';
|
|
26
|
+
import { useBlockBack, usePopover } from '../../../hooks/Common';
|
|
26
27
|
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
27
28
|
import { axiosGet, axiosPost } from '../../../utils/Apis/axios';
|
|
28
29
|
import { useBackendPermission } from '../../../utils/Permission/backend';
|
|
@@ -127,7 +128,16 @@ const ScriptDetail = ({ route }) => {
|
|
|
127
128
|
const items = [
|
|
128
129
|
{ text: t('edit_condition'), doAction: () => handleUpdateAutomate() },
|
|
129
130
|
];
|
|
130
|
-
if (
|
|
131
|
+
if (unit_id) {
|
|
132
|
+
items.unshift({
|
|
133
|
+
text: t('text_unit'),
|
|
134
|
+
doAction: () =>
|
|
135
|
+
navigate(Routes.UnitDetail, {
|
|
136
|
+
unitId: unit_id,
|
|
137
|
+
}),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
if (end_device_id) {
|
|
131
141
|
items.unshift({
|
|
132
142
|
text: t('device_display'),
|
|
133
143
|
doAction: () =>
|
|
@@ -138,7 +148,7 @@ const ScriptDetail = ({ route }) => {
|
|
|
138
148
|
});
|
|
139
149
|
}
|
|
140
150
|
return items;
|
|
141
|
-
}, [t, handleUpdateAutomate,
|
|
151
|
+
}, [t, handleUpdateAutomate, navigate, unit_id, end_device_id]);
|
|
142
152
|
|
|
143
153
|
const handleShowMenuAction = useCallback(() => {
|
|
144
154
|
if (!can_edit) {
|
|
@@ -219,6 +229,8 @@ const ScriptDetail = ({ route }) => {
|
|
|
219
229
|
[automateId]
|
|
220
230
|
);
|
|
221
231
|
|
|
232
|
+
useBlockBack(handleGoBack);
|
|
233
|
+
|
|
222
234
|
useEffect(() => {
|
|
223
235
|
if (isFocused) {
|
|
224
236
|
fetchAutomate();
|
|
@@ -385,7 +397,7 @@ const ScriptDetail = ({ route }) => {
|
|
|
385
397
|
const Item = ({ item, index, enableScript, t }) => {
|
|
386
398
|
const color = enableScript ? Colors.Gray9 : Colors.Gray7;
|
|
387
399
|
const paddedIndex = (index + 1).toString().padStart(2, '0');
|
|
388
|
-
const { action_script, notify_script, delay_script } = item;
|
|
400
|
+
const { action_script, notify_script, delay_script, email_script } = item;
|
|
389
401
|
if (action_script) {
|
|
390
402
|
const {
|
|
391
403
|
sensor_icon_kit,
|
|
@@ -444,16 +456,18 @@ const Item = ({ item, index, enableScript, t }) => {
|
|
|
444
456
|
</Text>
|
|
445
457
|
</View>
|
|
446
458
|
<View style={styles.rightItem}>
|
|
447
|
-
<View style={styles.
|
|
448
|
-
<
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
<
|
|
452
|
-
{
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
{
|
|
456
|
-
|
|
459
|
+
<View style={styles.insideItemRight}>
|
|
460
|
+
<View style={styles.iconEndDevice}>
|
|
461
|
+
<Notify />
|
|
462
|
+
</View>
|
|
463
|
+
<View style={styles.contentItem}>
|
|
464
|
+
<Text numberOfLines={1} type="H4" color={color} semibold>
|
|
465
|
+
{title}
|
|
466
|
+
</Text>
|
|
467
|
+
<Text numberOfLines={1} type="H4" color={color}>
|
|
468
|
+
{message}
|
|
469
|
+
</Text>
|
|
470
|
+
</View>
|
|
457
471
|
</View>
|
|
458
472
|
</View>
|
|
459
473
|
</View>
|
|
@@ -482,6 +496,35 @@ const Item = ({ item, index, enableScript, t }) => {
|
|
|
482
496
|
</View>
|
|
483
497
|
</View>
|
|
484
498
|
);
|
|
499
|
+
} else if (email_script) {
|
|
500
|
+
const { title, message, str_emails } = email_script;
|
|
501
|
+
return (
|
|
502
|
+
<View style={styles.wrapItem}>
|
|
503
|
+
<View style={styles.leftItem}>
|
|
504
|
+
<Text color={color} type="H4" semibold>
|
|
505
|
+
{paddedIndex}
|
|
506
|
+
</Text>
|
|
507
|
+
</View>
|
|
508
|
+
<View style={styles.rightItem}>
|
|
509
|
+
<View style={styles.insideItemRight}>
|
|
510
|
+
<View style={styles.iconEndDevice}>
|
|
511
|
+
<Email />
|
|
512
|
+
</View>
|
|
513
|
+
<View style={styles.contentItem}>
|
|
514
|
+
<Text numberOfLines={1} type="H4" color={color} semibold>
|
|
515
|
+
{title}
|
|
516
|
+
</Text>
|
|
517
|
+
<Text numberOfLines={1} type="H4" color={color}>
|
|
518
|
+
{message}
|
|
519
|
+
</Text>
|
|
520
|
+
</View>
|
|
521
|
+
</View>
|
|
522
|
+
<Text numberOfLines={1} type="H4" color={color}>
|
|
523
|
+
{str_emails}
|
|
524
|
+
</Text>
|
|
525
|
+
</View>
|
|
526
|
+
</View>
|
|
527
|
+
);
|
|
485
528
|
}
|
|
486
529
|
};
|
|
487
530
|
|
|
@@ -7,7 +7,7 @@ import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
|
7
7
|
import { API } from '../../configs';
|
|
8
8
|
import Text from '../../commons/Text';
|
|
9
9
|
import SharedUnit from '../../commons/Unit/SharedUnit';
|
|
10
|
-
import {
|
|
10
|
+
import { useBlockBack } from '../../hooks/Common';
|
|
11
11
|
import { AccessibilityLabel } from '../../configs/Constants';
|
|
12
12
|
|
|
13
13
|
import styles from './styles';
|
|
@@ -17,7 +17,7 @@ import { ModalCustom } from '../../commons/Modal';
|
|
|
17
17
|
import useTitleHeader from '../../hooks/Common/useTitleHeader';
|
|
18
18
|
|
|
19
19
|
const Shared = () => {
|
|
20
|
-
|
|
20
|
+
useBlockBack();
|
|
21
21
|
const t = useTranslations();
|
|
22
22
|
useTitleHeader(t('text_shared_with_me'));
|
|
23
23
|
const navigation = useNavigation();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useCallback, useState } from 'react';
|
|
1
|
+
import React, { useCallback, useMemo, useState } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
Keyboard,
|
|
4
4
|
StyleSheet,
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
isValidEmailAddress,
|
|
18
18
|
isValidPhoneNumber,
|
|
19
19
|
} from '../../utils/Validation';
|
|
20
|
-
import { axiosPost } from '../../utils/Apis/axios';
|
|
20
|
+
import { axiosGet, axiosPost } from '../../utils/Apis/axios';
|
|
21
21
|
import { AccessibilityLabel } from '../../configs/Constants';
|
|
22
22
|
import Text from '../../commons/Text';
|
|
23
23
|
import { ToastBottomHelper } from '../../utils/Utils';
|
|
@@ -30,49 +30,45 @@ const SharingInviteMembers = ({ route }) => {
|
|
|
30
30
|
const [errorText, setErrorText] = useState('');
|
|
31
31
|
const [content, setContent] = useState('');
|
|
32
32
|
const [users, setUsers] = useState([]);
|
|
33
|
-
const sharePermissions = useCallback(
|
|
34
|
-
async (phone, email) => {
|
|
35
|
-
Keyboard.dismiss();
|
|
36
|
-
let userSharedPermission = await users.filter(
|
|
37
|
-
(user) => user.phone_number === phone || user.email === email
|
|
38
|
-
);
|
|
39
|
-
if (userSharedPermission.length) {
|
|
40
|
-
return false;
|
|
41
|
-
}
|
|
42
|
-
const { success, data } = await axiosPost(API.SHARE.SHARE(), {
|
|
43
|
-
phone,
|
|
44
|
-
email,
|
|
45
|
-
unit: unit.id,
|
|
46
|
-
permissions,
|
|
47
|
-
});
|
|
48
|
-
if (success) {
|
|
49
|
-
ToastBottomHelper.success(t('invited_user', { user: phone || email }));
|
|
50
|
-
setUsers([...users, data.user]);
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
[users, unit.id, permissions, t]
|
|
54
|
-
);
|
|
55
33
|
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
34
|
+
const handleSearchUser = useCallback(async () => {
|
|
35
|
+
if (!isValidPhoneNumber(content) && !isValidEmailAddress(content)) {
|
|
36
|
+
setErrorText(t('invalid_phone_number_or_email'));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const apiUrl = isValidPhoneNumber(content)
|
|
40
|
+
? API.SHARE.SEARCH_USER_BY_PHONE(content)
|
|
41
|
+
: API.SHARE.SEARCH_USER_BY_EMAIL(content);
|
|
42
|
+
|
|
43
|
+
const { success, data } = await axiosGet(apiUrl);
|
|
44
|
+
if (success) {
|
|
45
|
+
const userExists = users.some((user) => user.id === data.id);
|
|
46
|
+
if (!userExists) {
|
|
47
|
+
setUsers((prevUsers) => [data, ...prevUsers]);
|
|
65
48
|
}
|
|
66
49
|
} else {
|
|
67
|
-
|
|
50
|
+
ToastBottomHelper.error(t('not_found'));
|
|
68
51
|
}
|
|
69
52
|
setErrorText('');
|
|
70
|
-
|
|
71
|
-
}, [content, sharePermissions, t]);
|
|
53
|
+
}, [content, t, users]);
|
|
72
54
|
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
55
|
+
const onPressInvite = useCallback(async () => {
|
|
56
|
+
const userIds = users.map((item) => item.id);
|
|
57
|
+
|
|
58
|
+
const { success } = await axiosPost(API.SHARE.SHARE_V2(), {
|
|
59
|
+
user_ids: userIds,
|
|
60
|
+
unit: unit.id,
|
|
61
|
+
permissions,
|
|
62
|
+
is_remove_old_permission: true,
|
|
63
|
+
});
|
|
64
|
+
if (success) {
|
|
65
|
+
ToastBottomHelper.success(t('invited_user'));
|
|
66
|
+
navigate(Routes.UnitDetail, { unitId: unit.id });
|
|
67
|
+
setUsers([]);
|
|
68
|
+
}
|
|
69
|
+
}, [navigate, permissions, t, unit.id, users]);
|
|
70
|
+
|
|
71
|
+
const isInValid = useMemo(() => users.length === 0, [users]);
|
|
76
72
|
|
|
77
73
|
return (
|
|
78
74
|
<View style={styles.wrapContainer}>
|
|
@@ -116,8 +112,8 @@ const SharingInviteMembers = ({ route }) => {
|
|
|
116
112
|
<View style={styles.buttonWrapper}>
|
|
117
113
|
<Button
|
|
118
114
|
type="primary"
|
|
119
|
-
title={t('
|
|
120
|
-
onPress={
|
|
115
|
+
title={t('check')}
|
|
116
|
+
onPress={handleSearchUser}
|
|
121
117
|
style={Theme.shadow}
|
|
122
118
|
accessibilityLabel={AccessibilityLabel.INVITE_PHONE_NUMBER}
|
|
123
119
|
/>
|
|
@@ -141,7 +137,7 @@ const SharingInviteMembers = ({ route }) => {
|
|
|
141
137
|
</Text>
|
|
142
138
|
</View>
|
|
143
139
|
<View style={[styles.addedWrapper]}>
|
|
144
|
-
<AccountList accounts={users} />
|
|
140
|
+
<AccountList accounts={users} setUsers={setUsers} />
|
|
145
141
|
</View>
|
|
146
142
|
</View>
|
|
147
143
|
)}
|
|
@@ -152,10 +148,10 @@ const SharingInviteMembers = ({ route }) => {
|
|
|
152
148
|
disableKeyBoardAnimated={true}
|
|
153
149
|
leftTitle={t('back')}
|
|
154
150
|
onLeftClick={goBack}
|
|
155
|
-
rightTitle={t('
|
|
156
|
-
rightDisabled={
|
|
157
|
-
onRightClick={
|
|
158
|
-
|
|
151
|
+
rightTitle={t('add_user_invite')}
|
|
152
|
+
rightDisabled={isInValid}
|
|
153
|
+
onRightClick={onPressInvite}
|
|
154
|
+
accessibilityLabel={AccessibilityLabel.PREFIX.BUTTON_ADD_MEMBER}
|
|
159
155
|
/>
|
|
160
156
|
</View>
|
|
161
157
|
);
|
|
@@ -203,8 +199,12 @@ const styles = StyleSheet.create({
|
|
|
203
199
|
color: Colors.Gray8,
|
|
204
200
|
},
|
|
205
201
|
addedWrapper: {
|
|
206
|
-
...Theme.whiteBoxRadius,
|
|
207
202
|
marginTop: 8,
|
|
203
|
+
paddingTop: 15,
|
|
204
|
+
paddingHorizontal: 15,
|
|
205
|
+
borderRadius: 20,
|
|
206
|
+
borderWidth: 1,
|
|
207
|
+
borderColor: Colors.Gray5,
|
|
208
208
|
},
|
|
209
209
|
containerUsers: {
|
|
210
210
|
marginTop: 24,
|