@eohjsc/react-native-smart-city 0.5.1 → 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.
Files changed (36) hide show
  1. package/package.json +1 -1
  2. package/src/commons/ActionGroup/OnOffTemplate/OnOffSimpleTemplateStyle.js +1 -0
  3. package/src/commons/ActionGroup/SliderRangeTemplate.js +10 -3
  4. package/src/commons/ActionGroup/__test__/SliderRangeTemplate.test.js +4 -0
  5. package/src/commons/ProcessingBar/index.js +32 -0
  6. package/src/commons/ProcessingBar/styles.js +57 -0
  7. package/src/configs/AccessibilityLabel.js +8 -0
  8. package/src/navigations/AddMemberStack.js +8 -3
  9. package/src/screens/AddCommon/SelectUnit.js +1 -1
  10. package/src/screens/AddCommon/__test__/SelectUnit.test.js +1 -1
  11. package/src/screens/EnterPassword/index.js +3 -2
  12. package/src/screens/Sharing/Components/CheckBoxConfig.js +44 -0
  13. package/src/screens/Sharing/Components/CheckBoxCustom.js +2 -13
  14. package/src/screens/Sharing/Components/CheckBoxSubUnit.js +35 -0
  15. package/src/screens/Sharing/Components/EndDevice.js +93 -0
  16. package/src/screens/Sharing/Components/Styles/CheckBoxConfigStyles.js +18 -0
  17. package/src/screens/Sharing/Components/Styles/DeviceItemStyles.js +28 -35
  18. package/src/screens/Sharing/Components/index.js +1 -2
  19. package/src/screens/Sharing/InfoMemberUnit.js +5 -3
  20. package/src/screens/Sharing/SelectShareDevice.js +273 -0
  21. package/src/screens/Sharing/SelectUser.js +6 -0
  22. package/src/screens/Sharing/Styles/SelectPermissionStyles.js +2 -11
  23. package/src/screens/Sharing/UnitMemberList.js +2 -1
  24. package/src/screens/Sharing/UpdateShareDevice.js +322 -0
  25. package/src/screens/Sharing/__test__/SelectShareDevice.test.js +215 -0
  26. package/src/screens/Sharing/__test__/UnitMemberList.test.js +1 -1
  27. package/src/screens/Sharing/__test__/UpdateShareDevice.test.js +307 -0
  28. package/src/screens/Sharing/hooks/index.js +5 -0
  29. package/src/screens/SubUnit/AddSubUnit.js +2 -6
  30. package/src/screens/SubUnit/EditSubUnitStyles.js +2 -1
  31. package/src/screens/Unit/AddMenu.js +1 -1
  32. package/src/utils/Route/index.js +2 -1
  33. package/src/screens/Sharing/Components/DeviceItem.js +0 -146
  34. package/src/screens/Sharing/Components/__test__/DeviceItem.test.js +0 -48
  35. package/src/screens/Sharing/SharingSelectPermission.js +0 -409
  36. package/src/screens/Sharing/__test__/SharingSelectPermission.test.js +0 -292
@@ -0,0 +1,273 @@
1
+ import React, { memo, useCallback, useEffect, useMemo, useState } from 'react';
2
+ import { View, FlatList, Alert, ActivityIndicator } from 'react-native';
3
+ import { useNavigation } from '@react-navigation/native';
4
+
5
+ import { useTranslations } from '../../hooks/Common/useTranslations';
6
+ import ViewButtonBottom from '../../commons/ViewButtonBottom';
7
+ import Text from '../../commons/Text';
8
+ import styles from './Styles/SelectPermissionStyles';
9
+ import { axiosGet } from '../../utils/Apis/axios';
10
+ import Routes from '../../utils/Route';
11
+ import { API, Colors } from '../../configs';
12
+ import { AccessibilityLabel } from '../../configs/Constants';
13
+ import CheckBoxSubUnit from './Components/CheckBoxSubUnit';
14
+ import EndDevice from './Components/EndDevice';
15
+
16
+ const SelectShareDevice = ({ route }) => {
17
+ const { unit } = route.params;
18
+ const t = useTranslations();
19
+ const navigation = useNavigation();
20
+ const [dataStations, setDataStations] = useState([]);
21
+ const [isTickAllDevices, setIsTickAllDevices] = useState(false);
22
+ const [expandedItemIds, setExpandedItemIds] = useState([]);
23
+ const [needRefresh, setNeedRefresh] = useState(false);
24
+ const [loading, setLoading] = useState(true);
25
+
26
+ const onTickAllDevices = (indexSubUnit, isChecked) => {
27
+ setIsTickAllDevices(isChecked);
28
+ const updatedDataStations = dataStations.map((station) => ({
29
+ ...station,
30
+ isChecked,
31
+ devices: station.devices.map((device) => ({
32
+ ...device,
33
+ isChecked,
34
+ actions: device.actions.map((action) => ({
35
+ ...action,
36
+ isChecked,
37
+ })),
38
+ read_configs: device.read_configs.map((config) => ({
39
+ ...config,
40
+ isChecked,
41
+ })),
42
+ })),
43
+ }));
44
+ setDataStations(updatedDataStations);
45
+ };
46
+
47
+ const onTickSubUnit = (indexSubUnit, isChecked) => {
48
+ dataStations[indexSubUnit] = {
49
+ ...dataStations[indexSubUnit],
50
+ isChecked,
51
+ devices: dataStations[indexSubUnit].devices.map((i) => ({
52
+ ...i,
53
+ isChecked,
54
+ actions: i.actions.map((j) => ({ ...j, isChecked })),
55
+ read_configs: i.read_configs.map((j) => ({ ...j, isChecked })),
56
+ })),
57
+ };
58
+ setDataStations(dataStations);
59
+ setIsTickAllDevices(!dataStations.some((object) => !object.isChecked));
60
+ setNeedRefresh(true);
61
+ };
62
+
63
+ const onTickEndDevice = (indexSubUnit, indexEndDevice, item, isChecked) => {
64
+ item.isChecked = isChecked;
65
+ item.actions = item.actions.map((j) => ({ ...j, isChecked }));
66
+ item.read_configs = item.read_configs.map((j) => ({ ...j, isChecked }));
67
+
68
+ dataStations[indexSubUnit].devices[indexEndDevice] = item;
69
+
70
+ dataStations[indexSubUnit] = {
71
+ ...dataStations[indexSubUnit],
72
+ isChecked:
73
+ dataStations[indexSubUnit].devices.length ===
74
+ dataStations[indexSubUnit].devices.filter((i) => i.isChecked).length,
75
+ };
76
+ setIsTickAllDevices(!dataStations.some((i) => !i.isChecked));
77
+ setDataStations(dataStations);
78
+ setNeedRefresh(true);
79
+ };
80
+
81
+ const onTickedChild = (
82
+ indexSubUnit,
83
+ indexEndDevice,
84
+ configId,
85
+ item,
86
+ isConfig,
87
+ isChecked
88
+ ) => {
89
+ const subUnit = dataStations[indexSubUnit];
90
+ const device = subUnit.devices[indexEndDevice];
91
+ const configs = item[`${isConfig ? 'read_configs' : 'actions'}`];
92
+ const child = configs.find((i) => i.id === configId);
93
+
94
+ child.isChecked = isChecked;
95
+ device.isChecked =
96
+ configs.length === configs.filter((i) => i.isChecked).length;
97
+
98
+ subUnit.isChecked =
99
+ subUnit.devices.length ===
100
+ subUnit.devices.filter((i) => i.isChecked).length;
101
+
102
+ setIsTickAllDevices(!dataStations.some((i) => !i.isChecked));
103
+ setDataStations(dataStations);
104
+ setNeedRefresh(true);
105
+ };
106
+
107
+ const toggleExpandEndDevice = (deviceItem) => () => {
108
+ setExpandedItemIds((ids) => {
109
+ const index = ids.indexOf(deviceItem.id);
110
+ if (index !== -1) {
111
+ return [...ids.slice(0, index), ...ids.slice(index + 1)];
112
+ } else {
113
+ return [...ids, deviceItem.id];
114
+ }
115
+ });
116
+ };
117
+
118
+ const expandEndDevice = (deviceItem) => () => {
119
+ if (!expandedItemIds.includes(deviceItem.id)) {
120
+ setExpandedItemIds((prev) => [...prev, deviceItem.id]);
121
+ }
122
+ };
123
+
124
+ const GroupEndDevice = ({ item, indexSubUnit }) => {
125
+ const { name, devices, isChecked } = item;
126
+ return (
127
+ <View style={styles.viewGroup}>
128
+ <CheckBoxSubUnit
129
+ title={name}
130
+ item={item}
131
+ onPress={onTickSubUnit}
132
+ isChecked={isChecked}
133
+ indexSubUnit={indexSubUnit}
134
+ />
135
+ <View style={styles.wrapDevice}>
136
+ {devices.map((i, index) => (
137
+ <EndDevice
138
+ item={i}
139
+ key={i.id}
140
+ onTickedChild={onTickedChild}
141
+ onTickEndDevice={onTickEndDevice}
142
+ isItemExpanded={expandedItemIds.includes(i.id)}
143
+ toggleExpandEndDevice={toggleExpandEndDevice(i)}
144
+ expandEndDevice={expandEndDevice(i)}
145
+ indexSubUnit={indexSubUnit}
146
+ indexEndDevice={index}
147
+ />
148
+ ))}
149
+ </View>
150
+ </View>
151
+ );
152
+ };
153
+
154
+ const renderSubUnit = ({ item, index }) => (
155
+ <GroupEndDevice key={item.id} item={item} indexSubUnit={index} />
156
+ );
157
+
158
+ const renderFlatList = useMemo(() => {
159
+ setNeedRefresh(false);
160
+ return (
161
+ <FlatList
162
+ keyExtractor={(item) => item.id}
163
+ extraData={dataStations}
164
+ data={dataStations}
165
+ renderItem={renderSubUnit}
166
+ scrollIndicatorInsets={{ right: 1 }}
167
+ ListHeaderComponent={
168
+ <CheckBoxSubUnit
169
+ title={t('text_all_devices')}
170
+ onPress={onTickAllDevices}
171
+ isChecked={isTickAllDevices}
172
+ />
173
+ }
174
+ />
175
+ );
176
+ // eslint-disable-next-line react-hooks/exhaustive-deps
177
+ }, [dataStations, isTickAllDevices, expandedItemIds, needRefresh]);
178
+
179
+ const getUnitPermission = useCallback(async () => {
180
+ const { success, data } = await axiosGet(
181
+ API.SHARE.UNIT_PERMISSIONS(unit.id)
182
+ );
183
+ if (success) {
184
+ setDataStations(data);
185
+ }
186
+ setLoading(false);
187
+ }, [unit.id]);
188
+
189
+ useEffect(() => {
190
+ getUnitPermission();
191
+ }, [getUnitPermission, unit]);
192
+
193
+ const onPressBottom = async () => {
194
+ setLoading(true);
195
+ let read_permissions = [];
196
+ let control_permissions = [];
197
+
198
+ for (const station of dataStations) {
199
+ for (const end_device of station.devices) {
200
+ const action_ids = end_device.actions
201
+ .filter((action) => action.isChecked)
202
+ .map((action) => action.id);
203
+
204
+ const config_ids = end_device.read_configs
205
+ .filter((config) => config.isChecked)
206
+ .map((config) => config.id);
207
+
208
+ if (action_ids.length > 0) {
209
+ control_permissions.push({ id: end_device.id, values: action_ids });
210
+ }
211
+
212
+ if (config_ids.length > 0) {
213
+ read_permissions.push({ id: end_device.id, values: config_ids });
214
+ }
215
+
216
+ if (
217
+ action_ids.length === 0 &&
218
+ config_ids.length === 0 &&
219
+ end_device.isChecked
220
+ ) {
221
+ read_permissions.push({ id: end_device.id, values: [] });
222
+ }
223
+ }
224
+ }
225
+
226
+ if (read_permissions.length === 0 && control_permissions.length === 0) {
227
+ setLoading(false);
228
+ Alert.alert('', t('choose_at_least_one'));
229
+ return;
230
+ }
231
+ navigation.navigate(Routes.SharingInviteMembers, {
232
+ unit,
233
+ permissions: { read_permissions, control_permissions },
234
+ });
235
+ };
236
+
237
+ return (
238
+ <View style={styles.wrap}>
239
+ <Text semibold style={styles.title}>
240
+ {t('select_device')}
241
+ </Text>
242
+ <Text style={styles.subtitle}>{t('sharing_select_devices_hint')}</Text>
243
+ <View style={styles.contentContainer}>
244
+ {loading ? (
245
+ <ActivityIndicator color={Colors.Primary} />
246
+ ) : dataStations.length > 0 ? (
247
+ renderFlatList
248
+ ) : (
249
+ <Text
250
+ style={styles.textNodata}
251
+ accessibilityLabel={AccessibilityLabel.TEXT_NO_DATA_STATIONS}
252
+ >
253
+ {t('no_data')}
254
+ </Text>
255
+ )}
256
+ </View>
257
+ <View style={styles.wrapViewButtonStyle}>
258
+ <ViewButtonBottom
259
+ accessibilityLabelPrefix={
260
+ AccessibilityLabel.PREFIX.SHARING_SELECT_PERMISSION
261
+ }
262
+ leftTitle={t('cancel')}
263
+ onLeftClick={() => navigation.goBack()}
264
+ rightTitle={t('next')}
265
+ rightDisabled={false}
266
+ onRightClick={onPressBottom}
267
+ />
268
+ </View>
269
+ </View>
270
+ );
271
+ };
272
+
273
+ export default memo(SelectShareDevice);
@@ -21,6 +21,7 @@ import { 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';
24
+ import ProcessingBar from '../../commons/ProcessingBar';
24
25
 
25
26
  const SharingInviteMembers = ({ route }) => {
26
27
  const t = useTranslations();
@@ -29,6 +30,8 @@ const SharingInviteMembers = ({ route }) => {
29
30
  const [errorText, setErrorText] = useState('');
30
31
  const [content, setContent] = useState('');
31
32
  const [users, setUsers] = useState([]);
33
+ const [isAdding, setIsAdding] = useState(false);
34
+
32
35
  const sharePermissions = useCallback(
33
36
  async (phone, email) => {
34
37
  Keyboard.dismiss();
@@ -38,6 +41,7 @@ const SharingInviteMembers = ({ route }) => {
38
41
  if (userSharedPermission.length) {
39
42
  return false;
40
43
  }
44
+ setIsAdding(true);
41
45
  const { success, data } = await axiosPost(API.SHARE.SHARE(), {
42
46
  phone,
43
47
  email,
@@ -48,6 +52,7 @@ const SharingInviteMembers = ({ route }) => {
48
52
  ToastBottomHelper.success(t('invited_user', { user: phone || email }));
49
53
  setUsers([...users, data.user]);
50
54
  }
55
+ setIsAdding(false);
51
56
  },
52
57
  [users, unit.id, permissions, t]
53
58
  );
@@ -156,6 +161,7 @@ const SharingInviteMembers = ({ route }) => {
156
161
  onRightClick={onPressNext}
157
162
  accessibilityLabelPrefix={AccessibilityLabel.PREFIX.BUTTON_ADD_MEMBER}
158
163
  />
164
+ {isAdding && <ProcessingBar totalPercent={0.1} />}
159
165
  </View>
160
166
  );
161
167
  };
@@ -2,13 +2,12 @@ import { StyleSheet } from 'react-native';
2
2
  import { getStatusBarHeight } from 'react-native-iphone-x-helper';
3
3
  import { Colors } from '../../../configs';
4
4
  import { Constants, normalize } from '../../../configs/Constants';
5
- import { FONT_PREFIX } from '../../../configs/Constants';
6
5
 
7
6
  export default StyleSheet.create({
8
7
  wrap: {
9
8
  flex: 1,
10
9
  backgroundColor: Colors.Gray2,
11
- paddingTop: getStatusBarHeight() + 10,
10
+ paddingTop: getStatusBarHeight() + 20,
12
11
  },
13
12
  contentContainer: {
14
13
  flex: 1,
@@ -18,7 +17,7 @@ export default StyleSheet.create({
18
17
  color: Colors.Gray9,
19
18
  fontSize: 20,
20
19
  lineHeight: 28,
21
- marginTop: 8,
20
+ marginTop: 10,
22
21
  marginBottom: 4,
23
22
  marginLeft: 16,
24
23
  },
@@ -51,17 +50,9 @@ export default StyleSheet.create({
51
50
  },
52
51
  textAllDevice: {
53
52
  fontSize: 16,
54
- lineHeight: 24,
55
- fontWeight: '600',
56
- fontFamily: FONT_PREFIX + '-' + 'Semibold',
57
- fontStyle: 'normal',
58
53
  },
59
54
  GroupDeviceItem: {
60
55
  fontSize: 14,
61
- lineHeight: 22,
62
- fontWeight: '600',
63
- fontFamily: FONT_PREFIX + '-' + 'Semibold',
64
- fontStyle: 'normal',
65
56
  },
66
57
  wrapViewButtonStyle: {
67
58
  paddingTop: 70,
@@ -49,7 +49,7 @@ const UnitMemberList = ({ route }) => {
49
49
  }
50
50
 
51
51
  navigate(Routes.AddMemberStack, {
52
- screen: Routes.SharingSelectPermission,
52
+ screen: Routes.SelectShareDevice,
53
53
  params: { unit: { id: unitId } },
54
54
  });
55
55
  }, [
@@ -109,6 +109,7 @@ const UnitMemberList = ({ route }) => {
109
109
  />
110
110
  )}
111
111
  </WrapHeaderScrollable>
112
+
112
113
  <AlertAction
113
114
  visible={stateAlertSharingMenu.visible}
114
115
  hideModal={hideStateAlertSharingMenu}
@@ -0,0 +1,322 @@
1
+ import React, { memo, useCallback, useEffect, useMemo, useState } from 'react';
2
+ import { View, FlatList, Alert, ActivityIndicator } from 'react-native';
3
+ import { useNavigation } from '@react-navigation/native';
4
+
5
+ import { useTranslations } from '../../hooks/Common/useTranslations';
6
+ import ViewButtonBottom from '../../commons/ViewButtonBottom';
7
+ import Text from '../../commons/Text';
8
+ import styles from './Styles/SelectPermissionStyles';
9
+ import { axiosGet, axiosPost } from '../../utils/Apis/axios';
10
+ import { objectIds } from '../../utils/Utils';
11
+ import { API, Colors } from '../../configs';
12
+ import { AccessibilityLabel } from '../../configs/Constants';
13
+ import CheckBoxSubUnit from './Components/CheckBoxSubUnit';
14
+ import EndDevice from './Components/EndDevice';
15
+
16
+ const UpdateShareDevice = ({ route }) => {
17
+ const t = useTranslations();
18
+ const { unit, member } = route.params;
19
+ const navigation = useNavigation();
20
+ const [dataStations, setDataStations] = useState([]);
21
+ const [isTickAllDevices, setIsTickAllDevices] = useState(false);
22
+ const [expandedItemIds, setExpandedItemIds] = useState([]);
23
+ const [loading, setLoading] = useState(true);
24
+ const [needRefresh, setNeedRefresh] = useState(false);
25
+
26
+ const onTickAllDevices = (indexSubUnit, isChecked) => {
27
+ setIsTickAllDevices(isChecked);
28
+ const updatedDataStations = dataStations.map((station) => ({
29
+ ...station,
30
+ isChecked,
31
+ devices: station.devices.map((device) => ({
32
+ ...device,
33
+ isChecked,
34
+ actions: device.actions.map((action) => ({
35
+ ...action,
36
+ isChecked,
37
+ })),
38
+ read_configs: device.read_configs.map((config) => ({
39
+ ...config,
40
+ isChecked,
41
+ })),
42
+ })),
43
+ }));
44
+ setDataStations(updatedDataStations);
45
+ };
46
+
47
+ const onTickSubUnit = (indexSubUnit, isChecked) => {
48
+ dataStations[indexSubUnit] = {
49
+ ...dataStations[indexSubUnit],
50
+ isChecked,
51
+ devices: dataStations[indexSubUnit].devices.map((i) => ({
52
+ ...i,
53
+ isChecked,
54
+ actions: i.actions.map((j) => ({ ...j, isChecked })),
55
+ read_configs: i.read_configs.map((j) => ({ ...j, isChecked })),
56
+ })),
57
+ };
58
+ setDataStations(dataStations);
59
+ setIsTickAllDevices(!dataStations.some((object) => !object.isChecked));
60
+ setNeedRefresh(true);
61
+ };
62
+
63
+ const onTickEndDevice = (indexSubUnit, indexEndDevice, item, isChecked) => {
64
+ item.isChecked = isChecked;
65
+ item.actions = item.actions.map((j) => ({ ...j, isChecked }));
66
+ item.read_configs = item.read_configs.map((j) => ({ ...j, isChecked }));
67
+
68
+ dataStations[indexSubUnit].devices[indexEndDevice] = item;
69
+
70
+ dataStations[indexSubUnit] = {
71
+ ...dataStations[indexSubUnit],
72
+ isChecked:
73
+ dataStations[indexSubUnit].devices.length ===
74
+ dataStations[indexSubUnit].devices.filter((i) => i.isChecked).length,
75
+ };
76
+ setIsTickAllDevices(!dataStations.some((i) => !i.isChecked));
77
+ setDataStations(dataStations);
78
+ setNeedRefresh(true);
79
+ };
80
+
81
+ const onTickedChild = (
82
+ indexSubUnit,
83
+ indexEndDevice,
84
+ configId,
85
+ item,
86
+ isConfig,
87
+ isChecked
88
+ ) => {
89
+ const subUnit = dataStations[indexSubUnit];
90
+ const device = subUnit.devices[indexEndDevice];
91
+ const configs = item[`${isConfig ? 'read_configs' : 'actions'}`];
92
+ const child = configs.find((i) => i.id === configId);
93
+
94
+ child.isChecked = isChecked;
95
+ device.isChecked =
96
+ configs.length === configs.filter((i) => i.isChecked).length;
97
+
98
+ subUnit.isChecked =
99
+ subUnit.devices.length ===
100
+ subUnit.devices.filter((i) => i.isChecked).length;
101
+
102
+ setIsTickAllDevices(!dataStations.some((i) => !i.isChecked));
103
+ setDataStations(dataStations);
104
+ setNeedRefresh(true);
105
+ };
106
+ const toggleExpandEndDevice = (deviceItem) => () => {
107
+ setExpandedItemIds((ids) => {
108
+ const index = ids.indexOf(deviceItem.id);
109
+ if (index !== -1) {
110
+ return [...ids.slice(0, index), ...ids.slice(index + 1)];
111
+ } else {
112
+ return [...ids, deviceItem.id];
113
+ }
114
+ });
115
+ };
116
+
117
+ const expandEndDevice = (deviceItem) => () => {
118
+ if (!expandedItemIds.includes(deviceItem.id)) {
119
+ setExpandedItemIds((prev) => [...prev, deviceItem.id]);
120
+ }
121
+ };
122
+
123
+ const autoCheckedGroup = (stations, dataDeviceShared) => {
124
+ const { deviceIds, actionIds, configIds } = objectIds(dataDeviceShared);
125
+ const updatedStations = stations.map((station) => ({
126
+ ...station,
127
+ isChecked: station.devices.every((device) =>
128
+ deviceIds.includes(device.id)
129
+ ),
130
+ devices: station.devices.map((device) => ({
131
+ ...device,
132
+ isChecked: deviceIds.includes(device.id),
133
+ actions: device.actions.map((action) => ({
134
+ ...action,
135
+ isChecked: actionIds.includes(action.id),
136
+ })),
137
+ read_configs: device.read_configs.map((config) => ({
138
+ ...config,
139
+ isChecked: configIds.includes(config.id),
140
+ })),
141
+ })),
142
+ }));
143
+ setDataStations(updatedStations);
144
+ setIsTickAllDevices(
145
+ updatedStations.length ===
146
+ updatedStations.filter((i) => i.isChecked).length
147
+ );
148
+ };
149
+
150
+ const GroupEndDevice = ({ item, indexSubUnit }) => {
151
+ const { name, devices, isChecked } = item;
152
+ return (
153
+ <View style={styles.viewGroup}>
154
+ <CheckBoxSubUnit
155
+ title={name}
156
+ onPress={onTickSubUnit}
157
+ isChecked={isChecked}
158
+ indexSubUnit={indexSubUnit}
159
+ />
160
+ <View style={styles.wrapDevice}>
161
+ {devices.map((i, index) => (
162
+ <EndDevice
163
+ item={i}
164
+ key={i.id}
165
+ onTickedChild={onTickedChild}
166
+ onTickEndDevice={onTickEndDevice}
167
+ isItemExpanded={expandedItemIds.includes(i.id)}
168
+ toggleExpandEndDevice={toggleExpandEndDevice(i)}
169
+ expandEndDevice={expandEndDevice(i)}
170
+ indexSubUnit={indexSubUnit}
171
+ indexEndDevice={index}
172
+ />
173
+ ))}
174
+ </View>
175
+ </View>
176
+ );
177
+ };
178
+
179
+ const onPressBottom = async () => {
180
+ setLoading(true);
181
+ let read_permissions = [];
182
+ let control_permissions = [];
183
+
184
+ for (const station of dataStations) {
185
+ for (const end_device of station.devices) {
186
+ const action_ids = end_device.actions
187
+ .filter((action) => action.isChecked)
188
+ .map((action) => action.id);
189
+
190
+ const config_ids = end_device.read_configs
191
+ .filter((config) => config.isChecked)
192
+ .map((config) => config.id);
193
+
194
+ if (action_ids.length > 0) {
195
+ control_permissions.push({ id: end_device.id, values: action_ids });
196
+ }
197
+
198
+ if (config_ids.length > 0) {
199
+ read_permissions.push({ id: end_device.id, values: config_ids });
200
+ }
201
+
202
+ if (
203
+ action_ids.length === 0 &&
204
+ config_ids.length === 0 &&
205
+ end_device.isChecked
206
+ ) {
207
+ read_permissions.push({ id: end_device.id, values: [] });
208
+ }
209
+ }
210
+ }
211
+
212
+ if (!read_permissions.length && !control_permissions.length) {
213
+ setLoading(false);
214
+ Alert.alert('', t('choose_at_least_one'));
215
+ return;
216
+ }
217
+ let phone = '';
218
+ let email = '';
219
+ if (member.phone_number) {
220
+ phone = member.phone_number;
221
+ email = '';
222
+ } else if (member.email) {
223
+ phone = '';
224
+ email = member.email;
225
+ }
226
+ const { success } = await axiosPost(API.SHARE.SHARE(), {
227
+ phone,
228
+ email,
229
+ unit: unit.id,
230
+ permissions: { read_permissions, control_permissions },
231
+ is_remove_old_permission: true,
232
+ });
233
+ setLoading(false);
234
+ success && navigation.goBack();
235
+ };
236
+
237
+ const renderSubUnit = ({ item, index }) => (
238
+ <GroupEndDevice key={item.id} item={item} indexSubUnit={index} />
239
+ );
240
+
241
+ const renderFlatList = useMemo(() => {
242
+ setNeedRefresh(false);
243
+ return (
244
+ <FlatList
245
+ keyExtractor={(item) => item.id}
246
+ extraData={dataStations}
247
+ data={dataStations}
248
+ renderItem={renderSubUnit}
249
+ scrollIndicatorInsets={{ right: 1 }}
250
+ ListHeaderComponent={
251
+ <CheckBoxSubUnit
252
+ title={t('text_all_devices')}
253
+ onPress={onTickAllDevices}
254
+ isChecked={isTickAllDevices}
255
+ />
256
+ }
257
+ />
258
+ );
259
+ // eslint-disable-next-line react-hooks/exhaustive-deps
260
+ }, [dataStations, isTickAllDevices, expandedItemIds, needRefresh]);
261
+
262
+ const getShareUnitPermission = useCallback(
263
+ async (stations) => {
264
+ const { success, data } = await axiosGet(
265
+ API.SHARE.UNIT_MEMBER_SHARE_DEVICE(unit.id, member.id)
266
+ );
267
+ if (success) {
268
+ autoCheckedGroup(stations, data);
269
+ }
270
+ },
271
+ [member.id, unit.id]
272
+ );
273
+
274
+ const getUnitPermission = useCallback(async () => {
275
+ const { success, data } = await axiosGet(
276
+ API.SHARE.UNIT_PERMISSIONS(unit.id)
277
+ );
278
+ if (success) {
279
+ setDataStations(data);
280
+ await getShareUnitPermission(data);
281
+ }
282
+ setLoading(false);
283
+ }, [getShareUnitPermission, unit.id]);
284
+
285
+ useEffect(() => {
286
+ getUnitPermission();
287
+ }, [getUnitPermission]);
288
+
289
+ return (
290
+ <View style={styles.wrap}>
291
+ <Text semibold style={styles.title}>
292
+ {t('select_device')}
293
+ </Text>
294
+ <Text style={styles.subtitle}>{t('sharing_select_devices_hint')}</Text>
295
+ <View style={styles.contentContainer}>
296
+ {loading ? (
297
+ <ActivityIndicator color={Colors.Primary} />
298
+ ) : dataStations.length > 0 ? (
299
+ renderFlatList
300
+ ) : (
301
+ <Text
302
+ style={styles.textNodata}
303
+ accessibilityLabel={AccessibilityLabel.TEXT_NO_DATA_STATIONS}
304
+ >
305
+ {t('no_data')}
306
+ </Text>
307
+ )}
308
+ </View>
309
+ <View style={styles.wrapViewButtonStyle}>
310
+ <ViewButtonBottom
311
+ leftTitle={t('cancel')}
312
+ onLeftClick={() => navigation.goBack()}
313
+ rightTitle={t('done')}
314
+ rightDisabled={false}
315
+ onRightClick={onPressBottom}
316
+ />
317
+ </View>
318
+ </View>
319
+ );
320
+ };
321
+
322
+ export default memo(UpdateShareDevice);