@eohjsc/react-native-smart-city 0.3.92 → 0.3.94
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/package.json +5 -1
- package/src/commons/ActionGroup/SliderRangeTemplate.js +2 -2
- package/src/commons/AlertAction/index.js +5 -0
- package/src/commons/BottomButtonView/index.js +22 -4
- package/src/commons/Button/index.js +5 -0
- package/src/commons/Device/ConnectedViewHeader.js +0 -1
- package/src/commons/Device/Emergency/EmergencyDetail.js +4 -2
- package/src/commons/Device/Emergency/__test__/EmergencyDetail.test.js +4 -2
- package/src/commons/Device/ProgressBar/index.js +3 -1
- package/src/commons/Device/ProgressBar/styles.js +1 -4
- package/src/commons/Device/WindSpeed/Anemometer/index.js +1 -1
- package/src/commons/Header/HeaderCustom.js +8 -18
- package/src/commons/SubUnit/OneTap/ItemOneTap.js +84 -129
- package/src/commons/SubUnit/OneTap/__test__/SubUnitAutomate.test.js +74 -39
- package/src/commons/SubUnit/OneTap/index.js +24 -4
- package/src/commons/ViewButtonBottom/index.js +32 -4
- package/src/configs/API.js +4 -0
- package/src/configs/AccessibilityLabel.js +1 -0
- package/src/configs/BLE.js +1 -0
- package/src/context/actionType.ts +2 -1
- package/src/context/mockStore.ts +1 -0
- package/src/context/reducer.ts +12 -1
- package/src/hooks/Explore/useKeyboardAnimated.js +10 -4
- package/src/hooks/IoT/useBluetoothConnection.js +14 -26
- package/src/hooks/useMqtt.js +95 -0
- package/src/iot/Monitor.js +2 -1
- package/src/iot/RemoteControl/Bluetooth.js +56 -19
- package/src/iot/RemoteControl/__test__/Bluetooth.test.js +140 -0
- package/src/iot/mqtt.js +233 -0
- package/src/navigations/UnitStack.js +11 -3
- package/src/screens/AddLocationMaps/index.js +18 -16
- package/src/screens/AddLocationMaps/indexStyle.js +3 -0
- package/src/screens/AddNewGateway/ConnectingDevice.js +7 -0
- package/src/screens/AddNewGateway/RenameNewDevices.js +2 -2
- package/src/screens/AddNewGateway/SelectDeviceType.js +67 -9
- package/src/screens/AddNewGateway/__test__/ConnectingZigbeeDevice.test.js +35 -0
- package/src/screens/AddNewGateway/__test__/SelectDeviceType.test.js +183 -29
- package/src/screens/Automate/AddNewAction/NewActionWrapper.js +3 -6
- package/src/screens/Automate/AddNewAction/SetupConfigCondition.js +29 -29
- package/src/screens/Automate/AddNewAction/__test__/SetupSensor.test.js +45 -39
- package/src/screens/Automate/AddNewAutoSmart/AddAutomationTypeSmart.js +25 -0
- package/src/screens/{AddNewAutoSmart/index.js → Automate/AddNewAutoSmart/AddTypeSmart.js} +16 -51
- package/src/screens/Automate/AddNewAutoSmart/AddUnknownTypeSmart.js +29 -0
- package/src/screens/{AddNewAutoSmart → Automate/AddNewAutoSmart}/__test__/AddNewAutoSmart.test.js +11 -11
- package/src/screens/{AddNewAutoSmart → Automate/AddNewAutoSmart}/styles/AddNewAutoSmartStyles.js +1 -1
- package/src/screens/Automate/Components/InputNameStyles.js +1 -1
- package/src/screens/Automate/EditActionsList/__tests__/index.test.js +11 -25
- package/src/screens/Automate/EditActionsList/index.js +32 -33
- package/src/screens/Automate/MultiUnits.js +29 -19
- package/src/screens/Automate/ScriptDetail/__test__/index.test.js +78 -5
- package/src/screens/Automate/ScriptDetail/index.js +38 -10
- package/src/screens/Automate/Styles/MultiUnitsStyles.js +1 -1
- package/src/screens/Automate/__test__/MultiUnits.test.js +64 -7
- package/src/screens/Automate/__test__/index.test.js +45 -11
- package/src/screens/Automate/index.js +53 -38
- package/src/screens/Device/__test__/detail.test.js +1 -1
- package/src/screens/Device/__test__/mqttDetail.test.js +599 -0
- package/src/screens/Device/components/SensorDisplayItem.js +1 -7
- package/src/screens/Device/detail.js +64 -30
- package/src/screens/Device/hooks/__test__/useEvaluateValue.test.js +24 -1
- package/src/screens/Device/hooks/useDeviceWatchConfigControl.js +13 -3
- package/src/screens/SelectUnit/__test__/index.test.js +8 -13
- package/src/screens/Sharing/InfoMemberUnit.js +2 -2
- package/src/screens/Sharing/MemberList.js +28 -7
- package/src/screens/Sharing/__test__/InfoMemberUnit.test.js +32 -18
- package/src/screens/Sharing/__test__/MemberList.test.js +37 -4
- package/src/screens/SmartAccount/__test__/SmartAccount.test.js +8 -4
- package/src/screens/SmartAccount/index.js +8 -9
- package/src/screens/SmartAccount/style.js +8 -7
- package/src/screens/Unit/AddMenu.js +42 -19
- package/src/screens/Unit/Detail.js +4 -19
- package/src/screens/Unit/Summaries.js +6 -17
- package/src/screens/Unit/__test__/AddMenu.test.js +68 -15
- package/src/screens/Unit/__test__/Summaries.test.js +2 -2
- package/src/screens/Unit/components/AutomateScript/index.js +1 -1
- package/src/utils/FactoryGateway.js +525 -0
- package/src/utils/I18n/translations/en.js +1409 -0
- package/src/utils/I18n/translations/vi.js +1411 -0
- package/src/utils/I18n/translations.ts +2 -2
- package/src/utils/Permission/backend.js +7 -0
- package/src/utils/Route/index.js +2 -1
- package/src/utils/Utils.js +11 -0
- package/src/commons/Device/SensorConnectedStatus.js +0 -56
- package/src/commons/Device/__test__/SensorConnectedStatus.test.js +0 -29
- package/src/screens/Sharing/__test__/MemberList2.test.js +0 -74
- package/src/utils/I18n/translations/en.json +0 -1138
- package/src/utils/I18n/translations/vi.json +0 -1136
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { create, act } from 'react-test-renderer';
|
|
3
3
|
import Toast from 'react-native-toast-message';
|
|
4
|
-
|
|
4
|
+
import { useNavigation } from '@react-navigation/native';
|
|
5
|
+
import { TouchableOpacity } from 'react-native';
|
|
5
6
|
import MockAdapter from 'axios-mock-adapter';
|
|
7
|
+
|
|
6
8
|
import { SCProvider } from '../../../../context';
|
|
7
9
|
import { mockSCStore } from '../../../../context/mockStore';
|
|
8
10
|
import ScriptDetail from '../index';
|
|
@@ -14,16 +16,16 @@ import {
|
|
|
14
16
|
AccessibilityLabel,
|
|
15
17
|
} from '../../../../configs/Constants';
|
|
16
18
|
import { API } from '../../../../configs';
|
|
17
|
-
import { TouchableOpacity } from 'react-native';
|
|
18
19
|
import Routes from '../../../../utils/Route';
|
|
19
20
|
import WrapHeaderScrollable from '../../../../commons/Sharing/WrapHeaderScrollable';
|
|
20
21
|
import ItemAutomate from '../../../../commons/Automate/ItemAutomate';
|
|
21
22
|
import api from '../../../../utils/Apis/axios';
|
|
22
23
|
import Text from '../../../../commons/Text';
|
|
23
|
-
import {
|
|
24
|
+
import { ToastBottomHelper } from '../../../../utils/Utils';
|
|
25
|
+
import { getTranslate } from '../../../../utils/I18n';
|
|
24
26
|
|
|
25
|
-
const wrapComponent = (route) => (
|
|
26
|
-
<SCProvider initState={mockSCStore(
|
|
27
|
+
const wrapComponent = (route, storeData = {}) => (
|
|
28
|
+
<SCProvider initState={mockSCStore(storeData)}>
|
|
27
29
|
<ScriptDetail route={route} />
|
|
28
30
|
</SCProvider>
|
|
29
31
|
);
|
|
@@ -48,6 +50,7 @@ describe('Test ScriptDetail', () => {
|
|
|
48
50
|
unit: 2,
|
|
49
51
|
author: 'Le Minh Tam',
|
|
50
52
|
id: 1,
|
|
53
|
+
can_edit: true,
|
|
51
54
|
type: 'value_change',
|
|
52
55
|
value_change: {
|
|
53
56
|
condition: '<',
|
|
@@ -123,6 +126,26 @@ describe('Test ScriptDetail', () => {
|
|
|
123
126
|
expect(Toast.show).toHaveBeenCalled();
|
|
124
127
|
});
|
|
125
128
|
|
|
129
|
+
it('test cannot rename script', async () => {
|
|
130
|
+
route.params.preAutomate.can_edit = false;
|
|
131
|
+
const spyToastError = jest.spyOn(ToastBottomHelper, 'error');
|
|
132
|
+
|
|
133
|
+
await act(async () => {
|
|
134
|
+
tree = await create(wrapComponent(route));
|
|
135
|
+
});
|
|
136
|
+
const instance = tree.root;
|
|
137
|
+
const menu = instance.findByProps({
|
|
138
|
+
accessibilityLabel: AccessibilityLabel.ICON_MORE,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
await act(async () => {
|
|
142
|
+
await menu.props.onPress();
|
|
143
|
+
});
|
|
144
|
+
expect(spyToastError).toBeCalledWith(
|
|
145
|
+
getTranslate('en', 'only_owner_has_permission_to_edit_this_script')
|
|
146
|
+
);
|
|
147
|
+
});
|
|
148
|
+
|
|
126
149
|
it('test delete script', async () => {
|
|
127
150
|
await act(async () => {
|
|
128
151
|
tree = await create(wrapComponent(route));
|
|
@@ -218,6 +241,56 @@ describe('Test ScriptDetail', () => {
|
|
|
218
241
|
});
|
|
219
242
|
});
|
|
220
243
|
|
|
244
|
+
it('test press add action reach limit', async () => {
|
|
245
|
+
mock.onGet(API.AUTOMATE.SCRIPT(1)).reply(200, data);
|
|
246
|
+
await act(async () => {
|
|
247
|
+
tree = await create(
|
|
248
|
+
wrapComponent(route, {
|
|
249
|
+
auth: {
|
|
250
|
+
account: {
|
|
251
|
+
user: {
|
|
252
|
+
permissions: {
|
|
253
|
+
max_actions_per_automation: 0,
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
})
|
|
259
|
+
);
|
|
260
|
+
});
|
|
261
|
+
const instance = tree.root;
|
|
262
|
+
const button = instance.find(
|
|
263
|
+
(el) =>
|
|
264
|
+
el.props.accessibilityLabel ===
|
|
265
|
+
AccessibilityLabel.BUTTON_ADD_SCRIPT_ACTION &&
|
|
266
|
+
el.type === TouchableOpacity
|
|
267
|
+
);
|
|
268
|
+
const spyToastError = jest.spyOn(ToastBottomHelper, 'error');
|
|
269
|
+
await act(async () => {
|
|
270
|
+
await button.props.onPress();
|
|
271
|
+
});
|
|
272
|
+
expect(mockNavigate).not.toBeCalled();
|
|
273
|
+
expect(spyToastError).toBeCalledWith(
|
|
274
|
+
getTranslate('en', 'reach_max_actions_per_automation')
|
|
275
|
+
);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it('test not see add action', async () => {
|
|
279
|
+
route.params.preAutomate.can_edit = false;
|
|
280
|
+
mock.onGet(API.AUTOMATE.SCRIPT(1)).reply(200, data);
|
|
281
|
+
await act(async () => {
|
|
282
|
+
tree = await create(wrapComponent(route));
|
|
283
|
+
});
|
|
284
|
+
const instance = tree.root;
|
|
285
|
+
const buttons = instance.findAll(
|
|
286
|
+
(el) =>
|
|
287
|
+
el.props.accessibilityLabel ===
|
|
288
|
+
AccessibilityLabel.BUTTON_ADD_SCRIPT_ACTION &&
|
|
289
|
+
el.type === TouchableOpacity
|
|
290
|
+
);
|
|
291
|
+
expect(buttons).toHaveLength(0);
|
|
292
|
+
});
|
|
293
|
+
|
|
221
294
|
it('test onPress onGoBack', async () => {
|
|
222
295
|
await act(async () => {
|
|
223
296
|
tree = await create(wrapComponent(route));
|
|
@@ -30,6 +30,7 @@ import { AccessibilityLabel, AUTOMATE_TYPE } from '../../../configs/Constants';
|
|
|
30
30
|
import RenameScript from './Components/RenameScript';
|
|
31
31
|
import DeleteScript from './Components/DeleteScript';
|
|
32
32
|
import Images from '../../../configs/Images';
|
|
33
|
+
import { useBackendPermission } from '../../../utils/Permission/backend';
|
|
33
34
|
|
|
34
35
|
const PreventDoubleTouch = withPreventDoubleClick(TouchableOpacity);
|
|
35
36
|
|
|
@@ -45,7 +46,9 @@ const ScriptDetail = ({ route }) => {
|
|
|
45
46
|
saveAt,
|
|
46
47
|
preAutomate = {}, // pre-loaded automate data
|
|
47
48
|
newAutomate, // updated automate data
|
|
49
|
+
newActionsList, // updated actions list
|
|
48
50
|
} = params;
|
|
51
|
+
|
|
49
52
|
const [automate, setAutomate] = useState(preAutomate);
|
|
50
53
|
const [data, setData] = useState([]);
|
|
51
54
|
const [isShowRename, setIsShowRename] = useState(false);
|
|
@@ -81,10 +84,15 @@ const ScriptDetail = ({ route }) => {
|
|
|
81
84
|
[t, onShowActivityLog]
|
|
82
85
|
);
|
|
83
86
|
|
|
84
|
-
const handleShowMenuAction = useCallback(
|
|
85
|
-
()
|
|
86
|
-
|
|
87
|
-
|
|
87
|
+
const handleShowMenuAction = useCallback(() => {
|
|
88
|
+
if (!automate?.can_edit) {
|
|
89
|
+
ToastBottomHelper.error(
|
|
90
|
+
t('only_owner_has_permission_to_edit_this_script')
|
|
91
|
+
);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
showPopoverWithRef(refMenuAction);
|
|
95
|
+
}, [automate?.can_edit, showPopoverWithRef, t]);
|
|
88
96
|
|
|
89
97
|
const onItemClick = useCallback((item) => {
|
|
90
98
|
item.doAction();
|
|
@@ -115,14 +123,14 @@ const ScriptDetail = ({ route }) => {
|
|
|
115
123
|
const handleScriptAction = useCallback(async () => {
|
|
116
124
|
const { success } = await axiosPost(API.AUTOMATE.ACTION_ONE_TAP(id));
|
|
117
125
|
if (success) {
|
|
118
|
-
ToastBottomHelper.success(t('
|
|
126
|
+
ToastBottomHelper.success(t('activated_successfully'));
|
|
119
127
|
} else {
|
|
120
|
-
ToastBottomHelper.error(t('
|
|
128
|
+
ToastBottomHelper.error(t('activation_failed'));
|
|
121
129
|
}
|
|
122
130
|
}, [id, t]);
|
|
123
131
|
|
|
124
132
|
const handleUpdateAutomate = useCallback(async () => {
|
|
125
|
-
navigate(Routes.
|
|
133
|
+
navigate(Routes.AddUnknownTypeSmart, {
|
|
126
134
|
automate,
|
|
127
135
|
closeScreen: route.name,
|
|
128
136
|
});
|
|
@@ -132,6 +140,10 @@ const ScriptDetail = ({ route }) => {
|
|
|
132
140
|
fetchAutomate();
|
|
133
141
|
}, [fetchAutomate]);
|
|
134
142
|
|
|
143
|
+
useEffect(() => {
|
|
144
|
+
newActionsList && setData(newActionsList);
|
|
145
|
+
}, [newActionsList]);
|
|
146
|
+
|
|
135
147
|
const rightComponent = useMemo(
|
|
136
148
|
() => (
|
|
137
149
|
<View style={styles.rightComponent}>
|
|
@@ -140,6 +152,7 @@ const ScriptDetail = ({ route }) => {
|
|
|
140
152
|
onPress={handleShowMenuAction}
|
|
141
153
|
ref={refMenuAction}
|
|
142
154
|
style={[styles.headerButton, styles.moreButton]}
|
|
155
|
+
accessibilityLabel={AccessibilityLabel.ICON_MORE}
|
|
143
156
|
>
|
|
144
157
|
<Icon name={'more'} size={27} color={Colors.Black} />
|
|
145
158
|
</TouchableOpacity>
|
|
@@ -187,7 +200,7 @@ const ScriptDetail = ({ route }) => {
|
|
|
187
200
|
<Text type="H3" color={Colors.Gray9} semibold>
|
|
188
201
|
{t('active_list')}
|
|
189
202
|
</Text>
|
|
190
|
-
{data.length > 0 && (
|
|
203
|
+
{data.length > 0 && !!automate?.can_edit && (
|
|
191
204
|
<TouchableOpacity
|
|
192
205
|
onPress={onPressEdit}
|
|
193
206
|
style={styles.editButton}
|
|
@@ -204,7 +217,9 @@ const ScriptDetail = ({ route }) => {
|
|
|
204
217
|
{data.map((item, index) => (
|
|
205
218
|
<Item key={item?.id} item={item} index={index} />
|
|
206
219
|
))}
|
|
207
|
-
|
|
220
|
+
{!!automate?.can_edit && (
|
|
221
|
+
<ItemAdd automate={automate} index={data.length} />
|
|
222
|
+
)}
|
|
208
223
|
</View>
|
|
209
224
|
</WrapHeaderScrollable>
|
|
210
225
|
<MenuActionMore
|
|
@@ -282,9 +297,14 @@ const Item = ({ item, index }) => {
|
|
|
282
297
|
const ItemAdd = ({ automate, index }) => {
|
|
283
298
|
const t = useTranslations();
|
|
284
299
|
const { navigate } = useNavigation();
|
|
300
|
+
const permissions = useBackendPermission();
|
|
285
301
|
const { name: currentScreenName } = useRoute();
|
|
286
302
|
|
|
287
303
|
const onPressAddAction = useCallback(() => {
|
|
304
|
+
if (permissions?.max_actions_per_automation <= index) {
|
|
305
|
+
ToastBottomHelper.error(t('reach_max_actions_per_automation'));
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
288
308
|
const navParams = {
|
|
289
309
|
unitId: automate.unit,
|
|
290
310
|
automateId: automate.id,
|
|
@@ -295,7 +315,15 @@ const ItemAdd = ({ automate, index }) => {
|
|
|
295
315
|
automate.unit ? Routes.SelectControlDevices : Routes.SelectUnit,
|
|
296
316
|
navParams
|
|
297
317
|
);
|
|
298
|
-
}, [
|
|
318
|
+
}, [
|
|
319
|
+
permissions?.max_actions_per_automation,
|
|
320
|
+
index,
|
|
321
|
+
automate.unit,
|
|
322
|
+
automate.id,
|
|
323
|
+
currentScreenName,
|
|
324
|
+
navigate,
|
|
325
|
+
t,
|
|
326
|
+
]);
|
|
299
327
|
|
|
300
328
|
return (
|
|
301
329
|
<View style={styles.wrapItem}>
|
|
@@ -15,11 +15,12 @@ import { getTranslate } from '../../../utils/I18n';
|
|
|
15
15
|
import { AUTOMATE_TYPE } from '../../../configs/Constants';
|
|
16
16
|
import api from '../../../utils/Apis/axios';
|
|
17
17
|
import { API } from '../../../configs';
|
|
18
|
+
import { ToastBottomHelper } from '../../../utils/Utils';
|
|
18
19
|
|
|
19
20
|
const mock = new MockAdapter(api.axiosInstance);
|
|
20
21
|
|
|
21
|
-
const wrapComponent = () => (
|
|
22
|
-
<SCProvider initState={mockSCStore(
|
|
22
|
+
const wrapComponent = (storeData = {}) => (
|
|
23
|
+
<SCProvider initState={mockSCStore(storeData)}>
|
|
23
24
|
<MultiUnits />
|
|
24
25
|
</SCProvider>
|
|
25
26
|
);
|
|
@@ -31,6 +32,7 @@ describe('Test MultiUnits', () => {
|
|
|
31
32
|
beforeEach(() => {
|
|
32
33
|
mockedNavigate.mockClear();
|
|
33
34
|
useRoute.mockClear();
|
|
35
|
+
mock.reset();
|
|
34
36
|
});
|
|
35
37
|
|
|
36
38
|
it('Test is multi unit and current is Automation tab', async () => {
|
|
@@ -106,7 +108,7 @@ describe('Test MultiUnits', () => {
|
|
|
106
108
|
ItemAddNews[0].props.onAddNew();
|
|
107
109
|
});
|
|
108
110
|
expect(mockedNavigate).toBeCalledWith(Routes.UnitStack, {
|
|
109
|
-
screen: Routes.
|
|
111
|
+
screen: Routes.AddUnknownTypeSmart,
|
|
110
112
|
params: {
|
|
111
113
|
automate: { unit: undefined },
|
|
112
114
|
closeScreen: undefined,
|
|
@@ -151,9 +153,7 @@ describe('Test MultiUnits', () => {
|
|
|
151
153
|
mock.onGet(API.AUTOMATE.GET_MULTI_UNITS()).reply(200, response);
|
|
152
154
|
useRoute.mockReturnValue({
|
|
153
155
|
params: {
|
|
154
|
-
|
|
155
|
-
unitName: null,
|
|
156
|
-
unit: null,
|
|
156
|
+
unit: {},
|
|
157
157
|
},
|
|
158
158
|
});
|
|
159
159
|
await act(async () => {
|
|
@@ -180,9 +180,66 @@ describe('Test MultiUnits', () => {
|
|
|
180
180
|
});
|
|
181
181
|
});
|
|
182
182
|
|
|
183
|
+
it('create new smart but reach max', async () => {
|
|
184
|
+
const response = [
|
|
185
|
+
{
|
|
186
|
+
id: 1,
|
|
187
|
+
user: 223,
|
|
188
|
+
type: 'one_tap',
|
|
189
|
+
config: null,
|
|
190
|
+
value: null,
|
|
191
|
+
activate_at: '2021-09-22T14:16:54Z',
|
|
192
|
+
condition: null,
|
|
193
|
+
script: {
|
|
194
|
+
id: 1,
|
|
195
|
+
name: 'Tap to up down up down coc coc coc coc coc',
|
|
196
|
+
icon: null,
|
|
197
|
+
icon_kit:
|
|
198
|
+
'https://eoh-gateway-backend.eoh.io/_Category_Sensors_Type_Garage_door_StyleC_olorful.png',
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
];
|
|
202
|
+
mock.onGet(API.UNIT.AUTOMATE(1)).reply(200, response);
|
|
203
|
+
useRoute.mockReturnValue({
|
|
204
|
+
params: {
|
|
205
|
+
unit: { id: 1 },
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
await act(async () => {
|
|
209
|
+
tree = await create(
|
|
210
|
+
wrapComponent({
|
|
211
|
+
auth: {
|
|
212
|
+
account: {
|
|
213
|
+
user: {
|
|
214
|
+
permissions: {
|
|
215
|
+
max_automations_per_unit: 0,
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
})
|
|
221
|
+
);
|
|
222
|
+
});
|
|
223
|
+
const instance = tree.root;
|
|
224
|
+
const itemAddNews = instance.findAllByType(ItemAddNew);
|
|
225
|
+
const spyToastError = jest.spyOn(ToastBottomHelper, 'error');
|
|
226
|
+
await act(async () => {
|
|
227
|
+
itemAddNews[0].props.onAddNew();
|
|
228
|
+
});
|
|
229
|
+
expect(mockedNavigate).not.toBeCalled();
|
|
230
|
+
expect(spyToastError).toBeCalledWith(
|
|
231
|
+
getTranslate('en', 'reach_max_automations_per_unit')
|
|
232
|
+
);
|
|
233
|
+
});
|
|
234
|
+
|
|
183
235
|
it('Test is not multi unit', async () => {
|
|
184
236
|
useRoute.mockReturnValue({
|
|
185
|
-
params: {
|
|
237
|
+
params: {
|
|
238
|
+
unit: {
|
|
239
|
+
id: 1,
|
|
240
|
+
name: '',
|
|
241
|
+
},
|
|
242
|
+
},
|
|
186
243
|
});
|
|
187
244
|
await act(async () => {
|
|
188
245
|
tree = await create(wrapComponent());
|
|
@@ -13,11 +13,13 @@ import { AccessibilityLabel } from '../../../configs/Constants';
|
|
|
13
13
|
import api from '../../../utils/Apis/axios';
|
|
14
14
|
import { API } from '../../../configs';
|
|
15
15
|
import { useNavigation } from '@react-navigation/native';
|
|
16
|
+
import { getTranslate } from '../../../utils/I18n';
|
|
17
|
+
import { ToastBottomHelper } from '../../../utils/Utils';
|
|
16
18
|
|
|
17
19
|
const mock = new MockAdapter(api.axiosInstance);
|
|
18
20
|
|
|
19
|
-
const wrapComponent = () => (
|
|
20
|
-
<SCProvider initState={mockSCStore(
|
|
21
|
+
const wrapComponent = (storeData = {}) => (
|
|
22
|
+
<SCProvider initState={mockSCStore(storeData)}>
|
|
21
23
|
<Automate />
|
|
22
24
|
</SCProvider>
|
|
23
25
|
);
|
|
@@ -92,7 +94,7 @@ describe('Test Automate', () => {
|
|
|
92
94
|
ItemAddNews[0].props.onAddNew('MultiUnit');
|
|
93
95
|
});
|
|
94
96
|
expect(mockedNavigate).toBeCalledWith(Routes.UnitStack, {
|
|
95
|
-
screen: Routes.
|
|
97
|
+
screen: Routes.AddUnknownTypeSmart,
|
|
96
98
|
params: {
|
|
97
99
|
closeScreen: undefined,
|
|
98
100
|
automate: { unit: undefined },
|
|
@@ -100,6 +102,44 @@ describe('Test Automate', () => {
|
|
|
100
102
|
});
|
|
101
103
|
});
|
|
102
104
|
|
|
105
|
+
it('onPress onAddNew but reach limit', async () => {
|
|
106
|
+
mock.onGet(API.AUTOMATE.GET_SMART()).reply(200, [
|
|
107
|
+
{
|
|
108
|
+
type: 'MultiUnit',
|
|
109
|
+
unit_id: 1,
|
|
110
|
+
automates: [],
|
|
111
|
+
},
|
|
112
|
+
]);
|
|
113
|
+
|
|
114
|
+
await act(async () => {
|
|
115
|
+
tree = await create(
|
|
116
|
+
wrapComponent({
|
|
117
|
+
auth: {
|
|
118
|
+
account: {
|
|
119
|
+
user: {
|
|
120
|
+
permissions: {
|
|
121
|
+
max_automations_per_unit: 0,
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
})
|
|
127
|
+
);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const instance = tree.root;
|
|
131
|
+
|
|
132
|
+
const itemAddNew = instance.findByType(ItemAddNew);
|
|
133
|
+
const spyToastError = jest.spyOn(ToastBottomHelper, 'error');
|
|
134
|
+
await act(async () => {
|
|
135
|
+
itemAddNew.props.onAddNew(1, []);
|
|
136
|
+
});
|
|
137
|
+
expect(mockedNavigate).not.toBeCalled();
|
|
138
|
+
expect(spyToastError).toBeCalledWith(
|
|
139
|
+
getTranslate('en', 'reach_max_automations_per_unit')
|
|
140
|
+
);
|
|
141
|
+
});
|
|
142
|
+
|
|
103
143
|
it('Test success get Automate onPressItem to ScriptDetail', async () => {
|
|
104
144
|
const response = {
|
|
105
145
|
status: 200,
|
|
@@ -193,10 +233,7 @@ describe('Test Automate', () => {
|
|
|
193
233
|
});
|
|
194
234
|
|
|
195
235
|
expect(mockedNavigate).toBeCalledWith(Routes.MultiUnits, {
|
|
196
|
-
|
|
197
|
-
unitName: '',
|
|
198
|
-
unit: { id: undefined },
|
|
199
|
-
isOwner: true,
|
|
236
|
+
unit: { id: undefined, name: '' },
|
|
200
237
|
});
|
|
201
238
|
|
|
202
239
|
mockedNavigate.mockClear();
|
|
@@ -205,10 +242,7 @@ describe('Test Automate', () => {
|
|
|
205
242
|
});
|
|
206
243
|
|
|
207
244
|
expect(mockedNavigate).toBeCalledWith(Routes.MultiUnits, {
|
|
208
|
-
|
|
209
|
-
unitName: 'La Vida',
|
|
210
|
-
unit: { id: 3 },
|
|
211
|
-
isOwner: false,
|
|
245
|
+
unit: { id: 3, name: 'La Vida' },
|
|
212
246
|
});
|
|
213
247
|
});
|
|
214
248
|
});
|
|
@@ -25,7 +25,8 @@ import ItemAddNew from '../../commons/Device/ItemAddNew';
|
|
|
25
25
|
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
26
26
|
import { useGetIdUser } from '../../hooks/Common';
|
|
27
27
|
import { AccessibilityLabel, UNIT_TYPES } from '../../configs/Constants';
|
|
28
|
-
import { keyExtractor } from '../../utils/Utils';
|
|
28
|
+
import { keyExtractor, ToastBottomHelper } from '../../utils/Utils';
|
|
29
|
+
import { useBackendPermission } from '../../utils/Permission/backend';
|
|
29
30
|
|
|
30
31
|
const Automate = () => {
|
|
31
32
|
const t = useTranslations();
|
|
@@ -38,6 +39,7 @@ const Automate = () => {
|
|
|
38
39
|
const starredScriptIds = useSCContextSelector(
|
|
39
40
|
(state) => state.automate.starredScriptIds
|
|
40
41
|
);
|
|
42
|
+
const permissions = useBackendPermission();
|
|
41
43
|
|
|
42
44
|
const sortedAutomateData = useMemo(() => {
|
|
43
45
|
return automatesData.map((unit) => {
|
|
@@ -64,35 +66,48 @@ const Automate = () => {
|
|
|
64
66
|
}, 1000);
|
|
65
67
|
}, []);
|
|
66
68
|
|
|
67
|
-
const onPressItem = (
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
69
|
+
const onPressItem = useCallback(
|
|
70
|
+
(item) => {
|
|
71
|
+
navigate(Routes.UnitStack, {
|
|
72
|
+
screen: Routes.ScriptDetail,
|
|
73
|
+
params: {
|
|
74
|
+
id: item?.id,
|
|
75
|
+
closeScreen: currentRouteName,
|
|
76
|
+
preAutomate: item, // pre-loaded automate data
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
},
|
|
80
|
+
[currentRouteName, navigate]
|
|
81
|
+
);
|
|
77
82
|
|
|
78
|
-
const handleOnAddNew = (
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
const handleOnAddNew = useCallback(
|
|
84
|
+
(id, automates) => {
|
|
85
|
+
if (id) {
|
|
86
|
+
// only limit per unit
|
|
87
|
+
if (permissions.max_automations_per_unit <= automates.length) {
|
|
88
|
+
ToastBottomHelper.error(t('reach_max_automations_per_unit'));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
navigate(Routes.UnitStack, {
|
|
93
|
+
screen: Routes.AddUnknownTypeSmart,
|
|
94
|
+
params: {
|
|
95
|
+
automate: { unit: id },
|
|
96
|
+
closeScreen: currentRouteName,
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
},
|
|
100
|
+
[currentRouteName, navigate, permissions?.max_automations_per_unit, t]
|
|
101
|
+
);
|
|
87
102
|
|
|
88
|
-
const onPressArrowRight = (
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
103
|
+
const onPressArrowRight = useCallback(
|
|
104
|
+
(unit) => {
|
|
105
|
+
navigate(Routes.MultiUnits, {
|
|
106
|
+
unit,
|
|
107
|
+
});
|
|
108
|
+
},
|
|
109
|
+
[navigate]
|
|
110
|
+
);
|
|
96
111
|
|
|
97
112
|
const renderItem = useCallback(
|
|
98
113
|
({ item = {} }) => {
|
|
@@ -112,7 +127,7 @@ const Automate = () => {
|
|
|
112
127
|
isOwner={isOwner}
|
|
113
128
|
automate={automate}
|
|
114
129
|
wrapSyles={styles.wrapAutomateItem}
|
|
115
|
-
onPressItem={onPressItem(automate, unit_id, type, isOwner)}
|
|
130
|
+
onPressItem={() => onPressItem(automate, unit_id, type, isOwner)}
|
|
116
131
|
/>
|
|
117
132
|
);
|
|
118
133
|
};
|
|
@@ -124,12 +139,12 @@ const Automate = () => {
|
|
|
124
139
|
{type === UNIT_TYPES.MULTI ? t('multi_unit') : unit_name}
|
|
125
140
|
</Text>
|
|
126
141
|
<TouchableOpacity
|
|
127
|
-
onPress={
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
142
|
+
onPress={() =>
|
|
143
|
+
onPressArrowRight({
|
|
144
|
+
name: unit_name,
|
|
145
|
+
id: unit_id,
|
|
146
|
+
})
|
|
147
|
+
}
|
|
133
148
|
style={styles.arrowRightButton}
|
|
134
149
|
accessibilityLabel={AccessibilityLabel.ICON_ARROW_RIGHT}
|
|
135
150
|
>
|
|
@@ -143,7 +158,7 @@ const Automate = () => {
|
|
|
143
158
|
renderItem={renderItemAutomate}
|
|
144
159
|
showsHorizontalScrollIndicator={false}
|
|
145
160
|
contentContainerStyle={styles.contentContainerStyle2}
|
|
146
|
-
ListFooterComponent={renderListFooterComponent(unit_id)}
|
|
161
|
+
ListFooterComponent={renderListFooterComponent(unit_id, automates)}
|
|
147
162
|
scrollIndicatorInsets={{ right: 1 }}
|
|
148
163
|
/>
|
|
149
164
|
</View>
|
|
@@ -153,10 +168,10 @@ const Automate = () => {
|
|
|
153
168
|
[sortedAutomateData]
|
|
154
169
|
);
|
|
155
170
|
|
|
156
|
-
const renderListFooterComponent = (unitId) => (
|
|
171
|
+
const renderListFooterComponent = (unitId, automates) => (
|
|
157
172
|
<ItemAddNew
|
|
158
173
|
title={t('add_new')}
|
|
159
|
-
onAddNew={handleOnAddNew(unitId)}
|
|
174
|
+
onAddNew={() => handleOnAddNew(unitId, automates)}
|
|
160
175
|
wrapStyle={styles.addNewItem}
|
|
161
176
|
/>
|
|
162
177
|
);
|