@eohjsc/react-native-smart-city 0.5.0 → 0.5.2-rc
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 +2 -2
- package/src/commons/ActionGroup/OnOffTemplate/OnOffButtonTemplateStyle.js +0 -1
- package/src/commons/ActionGroup/OnOffTemplate/OnOffSimpleTemplateStyle.js +1 -0
- package/src/commons/ActionGroup/OnOffTemplate/SwitchButtonTemplate.js +60 -48
- package/src/commons/ActionGroup/OnOffTemplate/index.js +1 -2
- package/src/commons/ActionGroup/SliderRangeTemplate.js +60 -64
- package/src/commons/ActionGroup/SliderRangeTemplateStyles.js +2 -4
- package/src/commons/ActionGroup/TerminalBoxTemplate.js +6 -6
- package/src/commons/ActionGroup/TextBoxTemplate.js +2 -2
- package/src/commons/ActionGroup/__test__/SliderRangeTemplate.test.js +72 -16
- package/src/commons/ActionGroup/__test__/SwitchButtonTemplate.test.js +33 -25
- package/src/commons/ActionGroup/__test__/TextBoxTemplate.test.js +19 -0
- package/src/commons/Device/RainningSensor/CurrentRainSensor.js +50 -45
- package/src/commons/Form/TextInput.js +2 -0
- package/src/commons/Header/Styles/HeaderCustomStyles.js +1 -1
- package/src/commons/HeaderAni/index.js +1 -1
- package/src/commons/ProcessingBar/index.js +32 -0
- package/src/commons/ProcessingBar/styles.js +57 -0
- package/src/commons/Sharing/WrapHeaderScrollable.js +1 -2
- package/src/configs/AccessibilityLabel.js +8 -0
- package/src/navigations/AddMemberStack.js +8 -3
- package/src/screens/AddCommon/SelectUnit.js +1 -1
- package/src/screens/AddCommon/__test__/SelectUnit.test.js +1 -1
- package/src/screens/Automate/AddNewAction/SetupScriptDelay.js +1 -1
- package/src/screens/Automate/Components/InputName.js +8 -2
- package/src/screens/Automate/EditActionsList/index.js +5 -5
- package/src/screens/Automate/OneTap/__test__/AddNewOneTap.test.js +17 -3
- package/src/screens/Device/components/SensorDisplayItem.js +7 -3
- package/src/screens/Device/detail.js +1 -1
- package/src/screens/EnterPassword/index.js +3 -2
- package/src/screens/Sharing/Components/CheckBoxConfig.js +44 -0
- package/src/screens/Sharing/Components/CheckBoxCustom.js +2 -13
- package/src/screens/Sharing/Components/CheckBoxSubUnit.js +35 -0
- package/src/screens/Sharing/Components/EndDevice.js +93 -0
- package/src/screens/Sharing/Components/Styles/CheckBoxConfigStyles.js +18 -0
- package/src/screens/Sharing/Components/Styles/DeviceItemStyles.js +28 -35
- package/src/screens/Sharing/Components/index.js +1 -2
- package/src/screens/Sharing/InfoMemberUnit.js +5 -3
- package/src/screens/Sharing/SelectShareDevice.js +273 -0
- package/src/screens/Sharing/SelectUser.js +6 -0
- package/src/screens/Sharing/Styles/SelectPermissionStyles.js +2 -11
- package/src/screens/Sharing/UnitMemberList.js +2 -1
- package/src/screens/Sharing/UpdateShareDevice.js +322 -0
- package/src/screens/Sharing/__test__/SelectShareDevice.test.js +215 -0
- package/src/screens/Sharing/__test__/UnitMemberList.test.js +1 -1
- package/src/screens/Sharing/__test__/UpdateShareDevice.test.js +307 -0
- package/src/screens/Sharing/hooks/index.js +5 -0
- package/src/screens/SubUnit/AddSubUnit.js +2 -6
- package/src/screens/SubUnit/EditSubUnitStyles.js +2 -1
- package/src/screens/Unit/AddMenu.js +1 -1
- package/src/screens/Unit/ManageUnitStyles.js +1 -1
- package/src/utils/I18n/translations/en.js +2 -0
- package/src/utils/I18n/translations/vi.js +2 -0
- package/src/utils/Route/index.js +2 -1
- package/src/commons/ActionGroup/OnOffTemplate/styles.js +0 -7
- package/src/screens/Sharing/Components/DeviceItem.js +0 -146
- package/src/screens/Sharing/Components/__test__/DeviceItem.test.js +0 -48
- package/src/screens/Sharing/SharingSelectPermission.js +0 -409
- package/src/screens/Sharing/__test__/SharingSelectPermission.test.js +0 -292
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import { act } from '@testing-library/react-hooks';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Alert } from 'react-native';
|
|
4
|
+
import { create } from 'react-test-renderer';
|
|
5
|
+
import MockAdapter from 'axios-mock-adapter';
|
|
6
|
+
import { ViewButtonBottom } from '../../../commons';
|
|
7
|
+
import { SCProvider } from '../../../context';
|
|
8
|
+
import { mockSCStore } from '../../../context/mockStore';
|
|
9
|
+
import API from '../../../configs/API';
|
|
10
|
+
import api from '../../../utils/Apis/axios';
|
|
11
|
+
import UpdateShareDevice from '../UpdateShareDevice';
|
|
12
|
+
import AccessibilityLabel from '../../../configs/AccessibilityLabel';
|
|
13
|
+
|
|
14
|
+
const mock = new MockAdapter(api.axiosInstance);
|
|
15
|
+
jest.spyOn(Alert, 'alert').mockImplementation(() => {});
|
|
16
|
+
const mockNavigate = jest.fn();
|
|
17
|
+
const mockGoBack = jest.fn();
|
|
18
|
+
jest.mock('@react-navigation/native', () => {
|
|
19
|
+
return {
|
|
20
|
+
...jest.requireActual('@react-navigation/native'),
|
|
21
|
+
useNavigation: () => ({
|
|
22
|
+
navigate: mockNavigate,
|
|
23
|
+
goBack: mockGoBack,
|
|
24
|
+
}),
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const wrapComponent = (route) => (
|
|
29
|
+
<SCProvider initState={mockSCStore({})}>
|
|
30
|
+
<UpdateShareDevice route={route} />
|
|
31
|
+
</SCProvider>
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
describe('Test UpdateShareDevice', () => {
|
|
35
|
+
let tree;
|
|
36
|
+
let route = {
|
|
37
|
+
params: {
|
|
38
|
+
unit: { id: 1, name: 'unit 1' },
|
|
39
|
+
member: {
|
|
40
|
+
id: 1,
|
|
41
|
+
name: 'a',
|
|
42
|
+
phone_number: '0901234567',
|
|
43
|
+
email: 'email@gmail.com',
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
let listDevices = [
|
|
48
|
+
{
|
|
49
|
+
id: 1,
|
|
50
|
+
name: 'Sub unit',
|
|
51
|
+
devices: [
|
|
52
|
+
{
|
|
53
|
+
id: 2,
|
|
54
|
+
actions: [{ id: 3, name: 'action 1' }],
|
|
55
|
+
read_configs: [{ id: 4, name: 'config 1' }],
|
|
56
|
+
name: 'child1',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 5,
|
|
60
|
+
actions: [{ id: 6, name: 'action 2' }],
|
|
61
|
+
read_configs: [{ id: 7, name: 'config 2' }],
|
|
62
|
+
name: 'child2',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: 8,
|
|
66
|
+
actions: [],
|
|
67
|
+
read_configs: [],
|
|
68
|
+
name: 'child3',
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
afterEach(() => {
|
|
75
|
+
Alert.alert.mockReset();
|
|
76
|
+
mock.resetHistory();
|
|
77
|
+
mockNavigate.mockClear();
|
|
78
|
+
mockGoBack.mockClear();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const clickCheckBoxAllDevice = async (instance, statusCheckbox) => {
|
|
82
|
+
const checkBoxAllDevice = instance.find(
|
|
83
|
+
(el) =>
|
|
84
|
+
el.props.accessibilityLabel ===
|
|
85
|
+
`${AccessibilityLabel.CHECK_BOX_CUSTOM}-undefined`
|
|
86
|
+
);
|
|
87
|
+
expect(checkBoxAllDevice.props.isChecked).toEqual(statusCheckbox);
|
|
88
|
+
await act(async () => {
|
|
89
|
+
await checkBoxAllDevice.props.onPress();
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const clickCheckBoxSubUnit = async (instance, statusCheckbox) => {
|
|
94
|
+
const checkBoxSubunit = instance.find(
|
|
95
|
+
(el) =>
|
|
96
|
+
el.props.accessibilityLabel ===
|
|
97
|
+
`${AccessibilityLabel.CHECK_BOX_CUSTOM}-0`
|
|
98
|
+
);
|
|
99
|
+
expect(checkBoxSubunit.props.isChecked).toEqual(statusCheckbox);
|
|
100
|
+
await act(async () => {
|
|
101
|
+
await checkBoxSubunit.props.onPress();
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const clickCheckBoxConfig = async (instance, configId, statusCheckbox) => {
|
|
106
|
+
let checkBoxConfig = instance.find(
|
|
107
|
+
(el) =>
|
|
108
|
+
el.props.accessibilityLabel ===
|
|
109
|
+
`${AccessibilityLabel.SHARE_DEVICE.CHECK_BOX_CONFIG}-${configId}`
|
|
110
|
+
);
|
|
111
|
+
expect(checkBoxConfig.props.isChecked).toEqual(statusCheckbox);
|
|
112
|
+
await act(async () => {
|
|
113
|
+
await checkBoxConfig.props.onPress();
|
|
114
|
+
});
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const clickExpandEndDevice = async (instance, indexEndDevice, statusIcon) => {
|
|
118
|
+
const expandEndDevice = instance.find(
|
|
119
|
+
(el) =>
|
|
120
|
+
el.props.accessibilityLabel ===
|
|
121
|
+
`${AccessibilityLabel.SHARE_DEVICE.EXPAND_END_DEVICE}-${indexEndDevice}`
|
|
122
|
+
);
|
|
123
|
+
expect(expandEndDevice.props.name).toEqual(statusIcon);
|
|
124
|
+
await act(async () => {
|
|
125
|
+
await expandEndDevice.props.onPress();
|
|
126
|
+
});
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const clickNameEndDevice = async (instance, indexEndDevice) => {
|
|
130
|
+
const nameEndDevice = instance.find(
|
|
131
|
+
(el) =>
|
|
132
|
+
el.props.accessibilityLabel ===
|
|
133
|
+
`${AccessibilityLabel.SHARE_DEVICE.CLICK_NAME_END_DEVICE}-${indexEndDevice}`
|
|
134
|
+
);
|
|
135
|
+
await act(async () => {
|
|
136
|
+
await nameEndDevice.props.onPress();
|
|
137
|
+
});
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
it('test user update share device by phone', async () => {
|
|
141
|
+
mock.onGet(API.SHARE.UNIT_PERMISSIONS(1)).reply(200, listDevices);
|
|
142
|
+
mock.onGet(API.SHARE.UNIT_MEMBER_SHARE_DEVICE(1, 1)).reply(200, []);
|
|
143
|
+
mock.onPost(API.SHARE.SHARE()).reply(200);
|
|
144
|
+
|
|
145
|
+
await act(async () => {
|
|
146
|
+
tree = await create(wrapComponent(route));
|
|
147
|
+
});
|
|
148
|
+
let instance = tree.root;
|
|
149
|
+
await clickNameEndDevice(instance, 0); // click to select all configs in end device index 0
|
|
150
|
+
await clickNameEndDevice(instance, 0); // click again to remove all configs, and coverage expand end device
|
|
151
|
+
await clickCheckBoxConfig(instance, 3, false); // click to select action
|
|
152
|
+
await clickCheckBoxConfig(instance, 3, true); // click again to coverage case status reversal
|
|
153
|
+
await clickCheckBoxConfig(instance, 4, false); // click to select config
|
|
154
|
+
await clickCheckBoxConfig(instance, 4, true); // click again to coverage case status reversal
|
|
155
|
+
await clickExpandEndDevice(instance, 0, 'up');
|
|
156
|
+
await clickExpandEndDevice(instance, 0, 'down'); // click again to coverage case status reversal
|
|
157
|
+
|
|
158
|
+
await clickCheckBoxAllDevice(instance, false); // click to select all device
|
|
159
|
+
await clickCheckBoxSubUnit(instance, true); // click to remove all device in sub unit id 1
|
|
160
|
+
await clickNameEndDevice(instance, 1); // click to select all configs in end device index 1
|
|
161
|
+
await clickNameEndDevice(instance, 2); // click to select all configs in end device index 2
|
|
162
|
+
|
|
163
|
+
const ViewButtonBottomElement = instance.findAllByType(ViewButtonBottom);
|
|
164
|
+
await act(async () => {
|
|
165
|
+
ViewButtonBottomElement[0].props.onRightClick();
|
|
166
|
+
});
|
|
167
|
+
expect(mockGoBack).toBeCalled();
|
|
168
|
+
expect(mock.history.post[0].data).toEqual(
|
|
169
|
+
JSON.stringify({
|
|
170
|
+
phone: '0901234567',
|
|
171
|
+
email: '',
|
|
172
|
+
unit: 1,
|
|
173
|
+
permissions: {
|
|
174
|
+
read_permissions: [
|
|
175
|
+
{ id: 5, values: [7] },
|
|
176
|
+
{ id: 8, values: [] },
|
|
177
|
+
],
|
|
178
|
+
control_permissions: [{ id: 5, values: [6] }],
|
|
179
|
+
},
|
|
180
|
+
is_remove_old_permission: true,
|
|
181
|
+
})
|
|
182
|
+
);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('test user update share device by email', async () => {
|
|
186
|
+
mock.onGet(API.SHARE.UNIT_PERMISSIONS(1)).reply(200, listDevices);
|
|
187
|
+
mock.onGet(API.SHARE.UNIT_MEMBER_SHARE_DEVICE(1, 1)).reply(200, []);
|
|
188
|
+
mock.onPost(API.SHARE.SHARE()).reply(200);
|
|
189
|
+
|
|
190
|
+
route.params.member.phone_number = '';
|
|
191
|
+
await act(async () => {
|
|
192
|
+
tree = await create(wrapComponent(route));
|
|
193
|
+
});
|
|
194
|
+
const instance = tree.root;
|
|
195
|
+
await clickNameEndDevice(instance, 0); // click to select all configs in end device index 0
|
|
196
|
+
const ViewButtonBottomElement = instance.findAllByType(ViewButtonBottom);
|
|
197
|
+
expect(ViewButtonBottomElement).toHaveLength(1);
|
|
198
|
+
await act(async () => {
|
|
199
|
+
ViewButtonBottomElement[0].props.onRightClick();
|
|
200
|
+
});
|
|
201
|
+
expect(mockGoBack).toBeCalled();
|
|
202
|
+
expect(mock.history.post[0].data).toEqual(
|
|
203
|
+
JSON.stringify({
|
|
204
|
+
phone: '',
|
|
205
|
+
email: 'email@gmail.com',
|
|
206
|
+
unit: 1,
|
|
207
|
+
permissions: {
|
|
208
|
+
read_permissions: [{ id: 2, values: [4] }],
|
|
209
|
+
control_permissions: [{ id: 2, values: [3] }],
|
|
210
|
+
},
|
|
211
|
+
is_remove_old_permission: true,
|
|
212
|
+
})
|
|
213
|
+
);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('test user update share device not have phone and email', async () => {
|
|
217
|
+
mock.onGet(API.SHARE.UNIT_PERMISSIONS(1)).reply(200, listDevices);
|
|
218
|
+
mock.onGet(API.SHARE.UNIT_MEMBER_SHARE_DEVICE(1, 1)).reply(200, []);
|
|
219
|
+
mock.onPost(API.SHARE.SHARE()).reply(400);
|
|
220
|
+
|
|
221
|
+
route.params.member.phone_number = '';
|
|
222
|
+
route.params.member.email = '';
|
|
223
|
+
await act(async () => {
|
|
224
|
+
tree = await create(wrapComponent(route));
|
|
225
|
+
});
|
|
226
|
+
const instance = tree.root;
|
|
227
|
+
await clickNameEndDevice(instance, 0); // click to select all configs in end device index 0
|
|
228
|
+
const ViewButtonBottomElement = instance.findAllByType(ViewButtonBottom);
|
|
229
|
+
expect(ViewButtonBottomElement).toHaveLength(1);
|
|
230
|
+
await act(async () => {
|
|
231
|
+
ViewButtonBottomElement[0].props.onRightClick();
|
|
232
|
+
});
|
|
233
|
+
expect(mockGoBack).not.toBeCalled();
|
|
234
|
+
expect(mock.history.post[0].data).toEqual(
|
|
235
|
+
JSON.stringify({
|
|
236
|
+
phone: '',
|
|
237
|
+
email: '',
|
|
238
|
+
unit: 1,
|
|
239
|
+
permissions: {
|
|
240
|
+
read_permissions: [{ id: 2, values: [4] }],
|
|
241
|
+
control_permissions: [{ id: 2, values: [3] }],
|
|
242
|
+
},
|
|
243
|
+
is_remove_old_permission: true,
|
|
244
|
+
})
|
|
245
|
+
);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('test no data, api get UNIT_PERMISSIONS false', async () => {
|
|
249
|
+
mock.onGet(API.SHARE.UNIT_PERMISSIONS(1)).reply(400);
|
|
250
|
+
|
|
251
|
+
await act(async () => {
|
|
252
|
+
tree = await create(wrapComponent(route));
|
|
253
|
+
});
|
|
254
|
+
const instance = tree.root;
|
|
255
|
+
|
|
256
|
+
let text = instance.find(
|
|
257
|
+
(el) =>
|
|
258
|
+
el.props.accessibilityLabel === AccessibilityLabel.TEXT_NO_DATA_STATIONS
|
|
259
|
+
);
|
|
260
|
+
expect(text.props.children).toEqual('No data');
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it('test api get UNIT_MEMBER_SHARE_DEVICE false', async () => {
|
|
264
|
+
mock.onGet(API.SHARE.UNIT_PERMISSIONS(1)).reply(200, listDevices);
|
|
265
|
+
mock.onGet(API.SHARE.UNIT_MEMBER_SHARE_DEVICE(1, 1)).reply(400);
|
|
266
|
+
|
|
267
|
+
await act(async () => {
|
|
268
|
+
tree = await create(wrapComponent(route));
|
|
269
|
+
});
|
|
270
|
+
const instance = tree.root;
|
|
271
|
+
|
|
272
|
+
let text = instance.findAll(
|
|
273
|
+
(el) =>
|
|
274
|
+
el.props.accessibilityLabel === AccessibilityLabel.TEXT_NO_DATA_STATIONS
|
|
275
|
+
);
|
|
276
|
+
expect(text).toEqual([]);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it('user not choose device click button back', async () => {
|
|
280
|
+
await act(async () => {
|
|
281
|
+
tree = await create(wrapComponent(route));
|
|
282
|
+
});
|
|
283
|
+
const instance = tree.root;
|
|
284
|
+
const ViewButtonBottomElement = instance.findAllByType(ViewButtonBottom);
|
|
285
|
+
expect(ViewButtonBottomElement).toHaveLength(1);
|
|
286
|
+
|
|
287
|
+
await act(async () => {
|
|
288
|
+
ViewButtonBottomElement[0].props.onLeftClick();
|
|
289
|
+
});
|
|
290
|
+
expect(mockGoBack).toBeCalled();
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it('user not choose device click button next', async () => {
|
|
294
|
+
await act(async () => {
|
|
295
|
+
tree = await create(wrapComponent(route));
|
|
296
|
+
});
|
|
297
|
+
const instance = tree.root;
|
|
298
|
+
const ViewButtonBottomElement = instance.findAllByType(ViewButtonBottom);
|
|
299
|
+
expect(ViewButtonBottomElement).toHaveLength(1);
|
|
300
|
+
await act(async () => {
|
|
301
|
+
ViewButtonBottomElement[0].props.onRightClick();
|
|
302
|
+
});
|
|
303
|
+
expect(Alert.alert.mock.calls[0][1]).toEqual(
|
|
304
|
+
'Please choose at least one sensor.'
|
|
305
|
+
);
|
|
306
|
+
});
|
|
307
|
+
});
|
|
@@ -16,6 +16,7 @@ const useDataMember = (unitId, userUnitId = undefined) => {
|
|
|
16
16
|
const [loading, setLoading] = useState(true);
|
|
17
17
|
const user = useSCContextSelector((state) => state?.auth?.account?.user);
|
|
18
18
|
const { isOwner } = useIsOwnerOfUnit(userUnitId);
|
|
19
|
+
const [isRemoving, setIsRemoving] = useState(false);
|
|
19
20
|
|
|
20
21
|
const insertAndShift = (arr, from, to) => {
|
|
21
22
|
let cutOut = arr.splice(from, 1)[0]; // cut the element at index 'from'
|
|
@@ -50,12 +51,15 @@ const useDataMember = (unitId, userUnitId = undefined) => {
|
|
|
50
51
|
|
|
51
52
|
const removeMember = useCallback(
|
|
52
53
|
async (id, name) => {
|
|
54
|
+
setIsRemoving(true);
|
|
53
55
|
await axiosDelete(API.SHARE.UNITS_MEMBER_DETAIL(unitId, id));
|
|
54
56
|
ToastBottomHelper.success(
|
|
55
57
|
t('sharing_removed_user', {
|
|
56
58
|
name,
|
|
57
59
|
})
|
|
58
60
|
);
|
|
61
|
+
|
|
62
|
+
setIsRemoving(false);
|
|
59
63
|
goBack();
|
|
60
64
|
},
|
|
61
65
|
[goBack, t, unitId]
|
|
@@ -85,6 +89,7 @@ const useDataMember = (unitId, userUnitId = undefined) => {
|
|
|
85
89
|
isRefresh,
|
|
86
90
|
onRefresh,
|
|
87
91
|
loading,
|
|
92
|
+
isRemoving,
|
|
88
93
|
};
|
|
89
94
|
};
|
|
90
95
|
|
|
@@ -183,12 +183,8 @@ const AddSubUnit = ({ route }) => {
|
|
|
183
183
|
);
|
|
184
184
|
|
|
185
185
|
const validateData = useMemo(() => {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
} else {
|
|
189
|
-
return roomName === '' || wallpaper === '';
|
|
190
|
-
}
|
|
191
|
-
}, [roomName, wallpaper, location, isAddUnit]);
|
|
186
|
+
return roomName === '';
|
|
187
|
+
}, [roomName]);
|
|
192
188
|
|
|
193
189
|
const onChooseLocation = useCallback(() => {
|
|
194
190
|
navigate(Routes.AddLocationMaps);
|
|
@@ -11,6 +11,7 @@ export default StyleSheet.create({
|
|
|
11
11
|
flex: 1,
|
|
12
12
|
},
|
|
13
13
|
title: {
|
|
14
|
+
paddingTop: 22,
|
|
14
15
|
paddingLeft: 22,
|
|
15
16
|
fontSize: 24,
|
|
16
17
|
lineHeight: 32,
|
|
@@ -43,7 +44,7 @@ export default StyleSheet.create({
|
|
|
43
44
|
bottom: 0,
|
|
44
45
|
borderWidth: 0,
|
|
45
46
|
alignSelf: 'center',
|
|
46
|
-
paddingBottom:
|
|
47
|
+
paddingBottom: 36 + getBottomSpace(),
|
|
47
48
|
},
|
|
48
49
|
removeText: {
|
|
49
50
|
borderBottomWidth: 1,
|
|
@@ -54,7 +54,7 @@ const AddMenu = memo(({ unit, afterItemClick, showAdd, setHideAdd }) => {
|
|
|
54
54
|
image: <AddMemberIcon width={43} height={43} />,
|
|
55
55
|
onClick: () =>
|
|
56
56
|
navigation.navigate(Routes.AddMemberStack, {
|
|
57
|
-
screen: Routes.
|
|
57
|
+
screen: Routes.SelectShareDevice,
|
|
58
58
|
params: { unit },
|
|
59
59
|
}),
|
|
60
60
|
},
|
|
@@ -1464,6 +1464,8 @@ export default {
|
|
|
1464
1464
|
end_devices_added: 'end devices added',
|
|
1465
1465
|
bellow_widget_is_not_configured: 'Bellow widget is not configured',
|
|
1466
1466
|
bellow_widget_is_wrongly_configured: 'Bellow widget is wrongly configured',
|
|
1467
|
+
widget_have_not_been_shared:
|
|
1468
|
+
'{widget} widget have not been shared. Please contact the owner',
|
|
1467
1469
|
'customize...': 'Customize...',
|
|
1468
1470
|
uri_invalid: 'URI invalid',
|
|
1469
1471
|
when_value_is: 'When value is',
|
|
@@ -1474,6 +1474,8 @@ export default {
|
|
|
1474
1474
|
end_devices_added: 'thiết bị được thêm vào',
|
|
1475
1475
|
bellow_widget_is_not_configured: 'Tiện ích bên dưới chưa được cấu hình',
|
|
1476
1476
|
bellow_widget_is_wrongly_configured: 'Tiện ích bên dưới được cấu hình sai',
|
|
1477
|
+
widget_have_not_been_shared:
|
|
1478
|
+
'Tiện ích {widget} chưa được chia sẽ. Vui lòng liên hệ với chủ sở hữu',
|
|
1477
1479
|
'customize...': 'Tùy chỉnh...',
|
|
1478
1480
|
uri_invalid: 'URI không hợp lệ',
|
|
1479
1481
|
when_value_is: 'Khi giá trị là',
|
package/src/utils/Route/index.js
CHANGED
|
@@ -75,7 +75,8 @@ const Routes = {
|
|
|
75
75
|
ConnectingWifiGuide: 'ConnectingWifiGuide',
|
|
76
76
|
|
|
77
77
|
UnitMemberList: 'UnitMemberList',
|
|
78
|
-
|
|
78
|
+
UpdateShareDevice: 'UpdateShareDevice',
|
|
79
|
+
SelectShareDevice: 'SelectShareDevice',
|
|
79
80
|
SharingInviteMembers: 'SharingInviteMembers',
|
|
80
81
|
LocationNearMe: 'LocationNearMe',
|
|
81
82
|
WindSpeed: 'WindSpeed',
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import React, { memo, useEffect, useMemo, useState } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
View,
|
|
4
|
-
Text,
|
|
5
|
-
LayoutAnimation,
|
|
6
|
-
Platform,
|
|
7
|
-
UIManager,
|
|
8
|
-
TouchableOpacity,
|
|
9
|
-
} from 'react-native';
|
|
10
|
-
import { IconOutline } from '@ant-design/icons-react-native';
|
|
11
|
-
import { Colors } from '../../../configs';
|
|
12
|
-
import styles from './Styles/DeviceItemStyles';
|
|
13
|
-
import FImage from '../../../commons/FImage';
|
|
14
|
-
import { TitleCheckBox } from '.';
|
|
15
|
-
import { CheckBoxCustom } from '.';
|
|
16
|
-
import { AccessibilityLabel } from '../../../configs/Constants';
|
|
17
|
-
|
|
18
|
-
const DeviceItem = ({
|
|
19
|
-
item = {},
|
|
20
|
-
isRenderSeparated,
|
|
21
|
-
onTickedChild,
|
|
22
|
-
onTickedDevice,
|
|
23
|
-
onTickedDeviceIcon,
|
|
24
|
-
isItemExpanded,
|
|
25
|
-
toggleItem,
|
|
26
|
-
idGroup,
|
|
27
|
-
}) => {
|
|
28
|
-
const {
|
|
29
|
-
id = '',
|
|
30
|
-
name = '',
|
|
31
|
-
actions = [],
|
|
32
|
-
read_configs = [],
|
|
33
|
-
icon_kit = '',
|
|
34
|
-
isChecked,
|
|
35
|
-
} = item;
|
|
36
|
-
const [dataConfig, setDataConfig] = useState([
|
|
37
|
-
...actions.map((i) => ({ ...i, isControl: true })),
|
|
38
|
-
...read_configs.map((i) => ({ ...i, isConfig: true })),
|
|
39
|
-
]);
|
|
40
|
-
|
|
41
|
-
const onPressItem = () => {
|
|
42
|
-
if (dataConfig.length > 0) {
|
|
43
|
-
toggleItem();
|
|
44
|
-
LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
|
|
45
|
-
} else {
|
|
46
|
-
handleOnTickedDevice();
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
const handleOnTickedChild = (group, checked, childId) => {
|
|
51
|
-
const dataTemp = [...dataConfig];
|
|
52
|
-
const indexTemp = dataTemp.findIndex((i) => i.id === childId);
|
|
53
|
-
dataTemp.splice(indexTemp, 1, {
|
|
54
|
-
...dataTemp[indexTemp],
|
|
55
|
-
isChecked: checked,
|
|
56
|
-
});
|
|
57
|
-
setDataConfig(dataTemp);
|
|
58
|
-
onTickedChild &&
|
|
59
|
-
onTickedChild(
|
|
60
|
-
group,
|
|
61
|
-
id,
|
|
62
|
-
childId,
|
|
63
|
-
checked,
|
|
64
|
-
Boolean(dataTemp[indexTemp]?.isConfig)
|
|
65
|
-
);
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
const isCheckedIcon = useMemo(() => {
|
|
69
|
-
return dataConfig.some((i) => i.isChecked);
|
|
70
|
-
}, [dataConfig]);
|
|
71
|
-
|
|
72
|
-
const handleOnTickedIcon = () => {
|
|
73
|
-
onTickedDeviceIcon && onTickedDeviceIcon(idGroup, id, isCheckedIcon);
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
const handleOnTickedDevice = () => {
|
|
77
|
-
onTickedDevice && onTickedDevice(idGroup, id, !isChecked);
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
useEffect(() => {
|
|
81
|
-
Platform.OS === 'android' &&
|
|
82
|
-
UIManager.setLayoutAnimationEnabledExperimental &&
|
|
83
|
-
UIManager.setLayoutAnimationEnabledExperimental(true);
|
|
84
|
-
}, []);
|
|
85
|
-
|
|
86
|
-
const renderData = useMemo(() => {
|
|
87
|
-
return dataConfig.map((i) => (
|
|
88
|
-
<TitleCheckBox
|
|
89
|
-
title={i.name}
|
|
90
|
-
wrapCheckBoxStyle={styles.wrapCheckBoxStyle}
|
|
91
|
-
onPress={handleOnTickedChild}
|
|
92
|
-
isChecked={i.isChecked}
|
|
93
|
-
id={i.id}
|
|
94
|
-
titleStyle={styles.titleStyle}
|
|
95
|
-
key={i.id}
|
|
96
|
-
idGroup={idGroup}
|
|
97
|
-
isConfig={i.isConfig}
|
|
98
|
-
isControl={i.isControl}
|
|
99
|
-
wrapStyle={styles.wrapStyleTitle}
|
|
100
|
-
/>
|
|
101
|
-
));
|
|
102
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
103
|
-
}, [dataConfig]);
|
|
104
|
-
|
|
105
|
-
return (
|
|
106
|
-
<View style={[styles.wrap, !isRenderSeparated && styles.isRenderSeparated]}>
|
|
107
|
-
<TouchableOpacity onPress={handleOnTickedIcon}>
|
|
108
|
-
<FImage
|
|
109
|
-
source={{ uri: icon_kit }}
|
|
110
|
-
style={styles.viewLeft}
|
|
111
|
-
tintColor={isCheckedIcon ? Colors.Primary : Colors.Gray}
|
|
112
|
-
/>
|
|
113
|
-
</TouchableOpacity>
|
|
114
|
-
<View style={styles.wrapRight}>
|
|
115
|
-
<View style={styles.viewRight}>
|
|
116
|
-
<Text
|
|
117
|
-
numberOfLines={1}
|
|
118
|
-
style={styles.text}
|
|
119
|
-
onPress={onPressItem}
|
|
120
|
-
accessibilityLabel={AccessibilityLabel.TEXT_SENSOR_ITEM}
|
|
121
|
-
>
|
|
122
|
-
{name}
|
|
123
|
-
</Text>
|
|
124
|
-
{dataConfig.length > 0 ? (
|
|
125
|
-
<IconOutline
|
|
126
|
-
onPress={onPressItem}
|
|
127
|
-
name={isItemExpanded ? 'up' : 'down'}
|
|
128
|
-
size={20}
|
|
129
|
-
color={Colors.Gray6}
|
|
130
|
-
/>
|
|
131
|
-
) : (
|
|
132
|
-
<CheckBoxCustom
|
|
133
|
-
isChecked={isChecked}
|
|
134
|
-
onPress={onPressItem}
|
|
135
|
-
wrapStyle={styles.checkBox}
|
|
136
|
-
/>
|
|
137
|
-
)}
|
|
138
|
-
</View>
|
|
139
|
-
{isItemExpanded && <View style={styles.wrapExpand}>{renderData}</View>}
|
|
140
|
-
{isRenderSeparated && <View style={styles.viewSeparated} />}
|
|
141
|
-
</View>
|
|
142
|
-
</View>
|
|
143
|
-
);
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
export default memo(DeviceItem);
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { create, act } from 'react-test-renderer';
|
|
3
|
-
|
|
4
|
-
import { SCProvider } from '../../../../context';
|
|
5
|
-
import { mockSCStore } from '../../../../context/mockStore';
|
|
6
|
-
import DeviceItem from '../DeviceItem';
|
|
7
|
-
import { Text } from 'react-native';
|
|
8
|
-
import { AccessibilityLabel } from '../../../../configs/Constants';
|
|
9
|
-
|
|
10
|
-
const mockOnTickedDevice = jest.fn();
|
|
11
|
-
const mockOnTickedChild = jest.fn();
|
|
12
|
-
const wrapComponent = (item) => (
|
|
13
|
-
<SCProvider initState={mockSCStore({})}>
|
|
14
|
-
<DeviceItem
|
|
15
|
-
item={item}
|
|
16
|
-
onTickedChild={mockOnTickedChild}
|
|
17
|
-
onTickedSensor={mockOnTickedDevice}
|
|
18
|
-
activeItemId={item.id}
|
|
19
|
-
/>
|
|
20
|
-
</SCProvider>
|
|
21
|
-
);
|
|
22
|
-
|
|
23
|
-
describe('test DeviceTemplate', () => {
|
|
24
|
-
it('test DeviceTemplate', async () => {
|
|
25
|
-
const item = {
|
|
26
|
-
id: 1,
|
|
27
|
-
name: 'abc',
|
|
28
|
-
actions: [],
|
|
29
|
-
read_configs: [],
|
|
30
|
-
icon_kit: '',
|
|
31
|
-
isChecked: true,
|
|
32
|
-
};
|
|
33
|
-
let tree;
|
|
34
|
-
await act(async () => {
|
|
35
|
-
tree = await create(wrapComponent(item));
|
|
36
|
-
});
|
|
37
|
-
const instance = tree.root;
|
|
38
|
-
const onPressText = instance.find(
|
|
39
|
-
(el) =>
|
|
40
|
-
el.type === Text &&
|
|
41
|
-
el.props.accessibilityLabel === AccessibilityLabel.TEXT_SENSOR_ITEM
|
|
42
|
-
);
|
|
43
|
-
expect(onPressText).toBeDefined();
|
|
44
|
-
await act(async () => {
|
|
45
|
-
onPressText.props.onPress();
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
});
|