@eohjsc/react-native-smart-city 0.2.87 → 0.2.88

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 (76) hide show
  1. package/assets/images/Common/Calendar.svg +3 -0
  2. package/assets/images/Common/SmartPhone.svg +3 -0
  3. package/assets/images/Hanet/CaptureFaceID.svg +25 -0
  4. package/assets/images/Hanet/FaceFrame.svg +6 -0
  5. package/package.json +2 -2
  6. package/src/Images/SmartIr/Remote.svg +15 -0
  7. package/src/Images/SmartIr/SmartIr.svg +4 -0
  8. package/src/Images/SmartIr/Union.svg +9 -0
  9. package/src/Images/SmartIr/index.js +4 -1
  10. package/src/commons/ActionGroup/ColorPickerTemplate.js +51 -0
  11. package/src/commons/ActionGroup/ColorPickerTemplateStyles.js +17 -0
  12. package/src/commons/ActionGroup/SliderRangeTemplate.js +64 -0
  13. package/src/commons/ActionGroup/{LightActionTemplateStyles.js → SliderRangeTemplateStyles.js} +0 -8
  14. package/src/commons/ActionGroup/SmartTiviActionTemplate/SmartTiviActionTemplate.js +47 -68
  15. package/src/commons/ActionGroup/index.js +6 -3
  16. package/src/commons/BottomSheet/index.js +2 -1
  17. package/src/commons/Device/Hanet/ItemHanetDevice.js +109 -0
  18. package/src/commons/Device/HistoryChart.js +2 -2
  19. package/src/commons/Device/HorizontalBarChart.js +7 -0
  20. package/src/commons/Device/ItemDevice.js +18 -15
  21. package/src/commons/Device/LinearChart.js +11 -1
  22. package/src/commons/SubUnit/Favorites/index.js +2 -2
  23. package/src/commons/SubUnit/ShortDetail.js +39 -20
  24. package/src/configs/API.js +22 -0
  25. package/src/configs/Constants.js +37 -0
  26. package/src/configs/SCConfig.js +1 -1
  27. package/src/context/actionType.ts +4 -0
  28. package/src/context/mockStore.ts +2 -0
  29. package/src/context/reducer.ts +20 -0
  30. package/src/iot/RemoteControl/Bluetooth.js +0 -19
  31. package/src/iot/RemoteControl/index.js +0 -1
  32. package/src/navigations/HanetCameraStack.js +41 -0
  33. package/src/navigations/UnitStack.js +34 -1
  34. package/src/screens/ActivityLog/hooks/index.js +1 -1
  35. package/src/screens/AddNewGateway/PlugAndPlay/ConnectWifiWarning.js +51 -66
  36. package/src/screens/AddNewGateway/PlugAndPlay/GatewayWifiList.js +68 -54
  37. package/src/screens/AddNewGateway/PlugAndPlay/__test__/ConnectWifiWarning.test.js +7 -0
  38. package/src/screens/Device/__test__/detail.test.js +0 -10
  39. package/src/screens/Device/detail.js +70 -29
  40. package/src/screens/Device/hooks/useDisconnectedDevice.js +16 -20
  41. package/src/screens/HanetCamera/CaptureFaceID.js +210 -0
  42. package/src/screens/HanetCamera/Detail.js +252 -0
  43. package/src/screens/HanetCamera/ManageAccess.js +173 -0
  44. package/src/screens/HanetCamera/MemberInfo.js +208 -0
  45. package/src/screens/HanetCamera/__test__/CaptureFaceID.test.js +133 -0
  46. package/src/screens/HanetCamera/__test__/Detail.test.js +185 -0
  47. package/src/screens/HanetCamera/__test__/ManageAccess.test.js +152 -0
  48. package/src/screens/HanetCamera/__test__/MemberInfo.test.js +178 -0
  49. package/src/screens/HanetCamera/components/CheckinHeader.js +37 -0
  50. package/src/screens/HanetCamera/hooks/__test__/useHanetCheckinData.test.js +151 -0
  51. package/src/screens/HanetCamera/hooks/__test__/useHanetPlaceMembers.test.js +71 -0
  52. package/src/screens/HanetCamera/hooks/index.js +5 -0
  53. package/src/screens/HanetCamera/hooks/useHanetCheckinData.js +116 -0
  54. package/src/screens/HanetCamera/hooks/useHanetPlaceMembers.js +86 -0
  55. package/src/screens/HanetCamera/hooks/useStateAlertAction.js +62 -0
  56. package/src/screens/HanetCamera/styles/captureFaceIDStyles.js +50 -0
  57. package/src/screens/HanetCamera/styles/checkinHeaderStyles.js +24 -0
  58. package/src/screens/HanetCamera/styles/detailStyles.js +107 -0
  59. package/src/screens/HanetCamera/styles/manageAccessStyles.js +49 -0
  60. package/src/screens/HanetCamera/styles/memberInfoStyles.js +73 -0
  61. package/src/screens/HanetCamera/utils/Monitor.js +52 -0
  62. package/src/screens/SmartIr/__test__/ButtonsBottom.test.js +31 -0
  63. package/src/screens/SmartIr/__test__/GroupButtonByType.test.js +35 -9
  64. package/src/screens/SmartIr/__test__/SelectBrand.test.js +0 -9
  65. package/src/screens/SmartIr/__test__/SelectDeviceType.test.js +1 -8
  66. package/src/screens/SmartIr/components/GroupButtonByType/ButtonsBottom.js +45 -0
  67. package/src/screens/SmartIr/components/GroupButtonByType/ButtonsBottomStyles.js +31 -0
  68. package/src/screens/SmartIr/components/GroupButtonByType/GroupButtonByType.js +156 -34
  69. package/src/screens/SmartIr/components/GroupButtonByType/GroupButtonByTypeStyles.js +52 -15
  70. package/src/screens/Unit/Detail.js +2 -10
  71. package/src/screens/Unit/__test__/Detail.test.js +0 -10
  72. package/src/utils/I18n/translations/en.json +28 -1
  73. package/src/utils/I18n/translations/vi.json +27 -0
  74. package/src/utils/Route/index.js +5 -0
  75. package/src/commons/ActionGroup/LightActionTemplate.js +0 -103
  76. package/src/commons/ActionGroup/__test__/LightActionTemplate.test.js +0 -59
@@ -0,0 +1,210 @@
1
+ import React, { memo, useState, useRef } from 'react';
2
+ import { View, ActivityIndicator, TouchableOpacity } from 'react-native';
3
+ import { useNavigation } from '@react-navigation/native';
4
+ import { RNCamera } from 'react-native-camera';
5
+ import { HeaderCustom } from '../../commons/Header';
6
+ import { FullLoading } from '../../commons';
7
+ import Text from '../../commons/Text';
8
+ import { useTranslations } from '../../hooks/Common/useTranslations';
9
+ import CaptureFaceIDSvg from '../../../assets/images/Hanet/CaptureFaceID.svg';
10
+ import FaceFrameSvg from '../../../assets/images/Hanet/FaceFrame.svg';
11
+ import { axiosPatch } from '../../utils/Apis/axios';
12
+ import { Colors, Constants, API } from '../../configs';
13
+ import styles from './styles/captureFaceIDStyles';
14
+ import Routes from '../../utils/Route';
15
+
16
+ const LoadingCamera = memo(() => {
17
+ return (
18
+ <View style={styles.containerLoading}>
19
+ <ActivityIndicator />
20
+ </View>
21
+ );
22
+ });
23
+
24
+ const CaptureFaceID = ({ route }) => {
25
+ const t = useTranslations();
26
+ const { navigate, goBack } = useNavigation();
27
+ const { title, hanetPlace, hanetMember, setMemberAvatar, isAddNewMember } =
28
+ route.params;
29
+ const [openCamera, setOpenCamera] = useState(false);
30
+ const [capturing, setCapturing] = useState(false);
31
+ const [imageUri, setImageUri] = useState();
32
+ const [loading, setLoading] = useState(false);
33
+
34
+ const refCamera = useRef();
35
+
36
+ const beginCaptureFace = async () => {
37
+ setCapturing(true);
38
+ setOpenCamera(true);
39
+ };
40
+
41
+ const captureFace = async () => {
42
+ if (refCamera.current) {
43
+ const options = {
44
+ quality: 0.7,
45
+ height: 1280,
46
+ width: 736,
47
+ imageType: 'jpg',
48
+ pauseAfterCapture: true,
49
+ forceUpOrientation: true,
50
+ fixOrientation: true,
51
+ orientation: 'portrait',
52
+ };
53
+ const data = await refCamera.current.takePictureAsync(options);
54
+ setImageUri(data.uri);
55
+ setCapturing(false);
56
+ }
57
+ };
58
+
59
+ const resumeCapture = () => {
60
+ if (refCamera.current) {
61
+ setCapturing(true);
62
+ refCamera.current.resumePreview();
63
+ }
64
+ };
65
+
66
+ const updateMemberFaceID = async () => {
67
+ const formData = new FormData();
68
+ const name = imageUri.split('/').pop();
69
+ const ext = imageUri.split('.').pop();
70
+ formData.append('face_id', {
71
+ name: name,
72
+ type: `image/${ext}`,
73
+ uri: imageUri,
74
+ });
75
+ setLoading(true);
76
+ const { success, data } = await axiosPatch(
77
+ API.CAMERA.HANET.UPDATE_FACE_ID(
78
+ hanetPlace.place_id,
79
+ hanetMember.alias_id
80
+ ),
81
+ formData,
82
+ {
83
+ headers: { 'Content-Type': 'multipart/form-data' },
84
+ }
85
+ );
86
+ if (success) {
87
+ setMemberAvatar(data.avatar_uri);
88
+ goBack();
89
+ }
90
+ setLoading(false);
91
+ };
92
+
93
+ const newMemberDoneGetFaceID = () => {
94
+ navigate(Routes.HanetMemberInfo, {
95
+ hanetPlace: hanetPlace,
96
+ hanetMember: {
97
+ ...hanetMember,
98
+ avatar_uri: imageUri,
99
+ },
100
+ isAddNewMember: true,
101
+ });
102
+ };
103
+
104
+ const processFaceID = async () => {
105
+ if (isAddNewMember) {
106
+ newMemberDoneGetFaceID();
107
+ } else {
108
+ await updateMemberFaceID();
109
+ }
110
+ };
111
+
112
+ return (
113
+ <View style={styles.container}>
114
+ <HeaderCustom title={title} isShowSeparator />
115
+ {openCamera && (
116
+ <View style={styles.wrapCamera}>
117
+ <RNCamera
118
+ ref={refCamera}
119
+ style={{
120
+ height: Constants.height,
121
+ width: Constants.width,
122
+ }}
123
+ type={RNCamera.Constants.Type.back}
124
+ >
125
+ {({ camera, status, recordAudioPermissionStatus }) => {
126
+ if (status !== 'READY') {
127
+ return <LoadingCamera />;
128
+ }
129
+ return (
130
+ <View style={styles.maskOutter}>
131
+ <FaceFrameSvg />
132
+ </View>
133
+ );
134
+ }}
135
+ </RNCamera>
136
+ </View>
137
+ )}
138
+ {!openCamera && (
139
+ <View style={styles.center}>
140
+ <CaptureFaceIDSvg />
141
+ <Text type="H3" color={Colors.Gray9} bold style={styles.textDes}>
142
+ {t('text_des_capture_face_id')}
143
+ </Text>
144
+ </View>
145
+ )}
146
+ <View
147
+ style={[
148
+ styles.wrapBottom,
149
+ // eslint-disable-next-line react-native/no-inline-styles
150
+ openCamera && { height: '30%' },
151
+ openCamera &&
152
+ // eslint-disable-next-line react-native/no-inline-styles
153
+ !capturing && { justifyContent: 'flex-end', paddingBottom: 0 },
154
+ ]}
155
+ >
156
+ {!openCamera && (
157
+ <TouchableOpacity
158
+ onPress={beginCaptureFace}
159
+ style={styles.bottomButton}
160
+ >
161
+ <Text type="H4" semibold color={Colors.White}>
162
+ {t('begin')}
163
+ </Text>
164
+ </TouchableOpacity>
165
+ )}
166
+ {openCamera && capturing && (
167
+ <>
168
+ <Text
169
+ type="H3"
170
+ color={Colors.Gray9}
171
+ bold
172
+ center
173
+ style={styles.textLocateFace}
174
+ >
175
+ {t('text_des_locate_hanet_face_id')}
176
+ </Text>
177
+ <TouchableOpacity onPress={captureFace} style={styles.bottomButton}>
178
+ <Text type="H4" semibold color={Colors.White}>
179
+ {t('capture')}
180
+ </Text>
181
+ </TouchableOpacity>
182
+ </>
183
+ )}
184
+ {openCamera && !capturing && (
185
+ <>
186
+ <TouchableOpacity
187
+ onPress={processFaceID}
188
+ style={styles.bottomButton}
189
+ >
190
+ <Text type="H4" semibold color={Colors.White}>
191
+ {t('continue')}
192
+ </Text>
193
+ </TouchableOpacity>
194
+ <TouchableOpacity
195
+ onPress={resumeCapture}
196
+ style={[styles.bottomButton, styles.bottomButton2]}
197
+ >
198
+ <Text type="H4" semibold color={Colors.Primary}>
199
+ {t('capture_again')}
200
+ </Text>
201
+ </TouchableOpacity>
202
+ </>
203
+ )}
204
+ </View>
205
+ {loading && <FullLoading />}
206
+ </View>
207
+ );
208
+ };
209
+
210
+ export default CaptureFaceID;
@@ -0,0 +1,252 @@
1
+ import React, {
2
+ useState,
3
+ useEffect,
4
+ useMemo,
5
+ useCallback,
6
+ useRef,
7
+ } from 'react';
8
+ import { View, TouchableOpacity, FlatList, Image } from 'react-native';
9
+ import { useNavigation } from '@react-navigation/native';
10
+ import { Icon } from '@ant-design/react-native';
11
+ import moment from 'moment';
12
+ import styles from './styles/detailStyles';
13
+ import { HeaderCustom } from '../../commons/Header';
14
+ import { MenuActionMore } from '../../commons';
15
+ import CheckinHeader from './components/CheckinHeader';
16
+ import Text from '../../commons/Text';
17
+ import Calendar from '../../commons/Calendar';
18
+ import { usePopover, useBoolean, useIsOwnerOfUnit } from '../../hooks/Common';
19
+ import { useTranslations } from '../../hooks/Common/useTranslations';
20
+ import { useHanetCheckinData } from './hooks';
21
+ import { API, Colors } from '../../configs';
22
+ import { TESTID } from '../../configs/Constants';
23
+ import {
24
+ watchHanetCheckinData,
25
+ unwatchHanetCheckinData,
26
+ } from './utils/Monitor';
27
+ import Routes from '../../utils/Route';
28
+ import { axiosGet } from '../../utils/Apis/axios';
29
+
30
+ const HanetCameraDetail = ({ route }) => {
31
+ const t = useTranslations();
32
+ const { navigate } = useNavigation();
33
+ const [hanetCamera, setHanetCamera] = useState();
34
+ const [showCalendar, setShowCalendar, setHideCalendar] = useBoolean();
35
+
36
+ // eslint-disable-next-line no-unused-vars
37
+ const { unit, station, sensor, title } = route.params;
38
+ const { isOwner } = useIsOwnerOfUnit(unit?.user_id);
39
+
40
+ const fetchDisplayConfig = useCallback(async () => {
41
+ const { success, data } = await axiosGet(
42
+ API.SENSOR.DISPLAY(sensor?.id),
43
+ {},
44
+ true
45
+ );
46
+ if (
47
+ success &&
48
+ data.items.length > 0 &&
49
+ data.items[0].type === 'hanet_camera'
50
+ ) {
51
+ setHanetCamera(data.items[0].configuration);
52
+ }
53
+ }, [sensor?.id]);
54
+
55
+ useEffect(() => {
56
+ fetchDisplayConfig();
57
+ }, [fetchDisplayConfig]);
58
+
59
+ const {
60
+ checkinData,
61
+ countMember,
62
+ countStranger,
63
+ refreshing,
64
+ loadingMore,
65
+ onRefresh,
66
+ onLoadMore,
67
+ date,
68
+ onChangeDate,
69
+ onMomentumScrollBegin,
70
+ onReceiveNewCheckinData,
71
+ } = useHanetCheckinData(hanetCamera);
72
+
73
+ useEffect(() => {
74
+ if (!hanetCamera) {
75
+ return;
76
+ }
77
+ watchHanetCheckinData(hanetCamera, onReceiveNewCheckinData);
78
+ return () => unwatchHanetCheckinData(hanetCamera);
79
+ // eslint-disable-next-line react-hooks/exhaustive-deps
80
+ }, [hanetCamera]);
81
+
82
+ const CheckInItem = useCallback(
83
+ ({ item }) => {
84
+ const textMask =
85
+ item.detected_mask === 'MASK_OFF'
86
+ ? t('mask_off')
87
+ : item.detected_mask === 'MASK_ON'
88
+ ? t('mask_on')
89
+ : '';
90
+ const isStranger = item.person_type === 'STRANGER';
91
+ return (
92
+ <View style={styles.wrapItem}>
93
+ <Text type="Body" color={Colors.Gray7} style={styles.timeCheckIn}>
94
+ {moment(item.created_at).format('HH:mm:ss')}
95
+ </Text>
96
+ <View style={styles.verticalLine}>
97
+ <View
98
+ style={[
99
+ styles.centerCircle,
100
+ { backgroundColor: isStranger ? Colors.Red6 : Colors.Primary },
101
+ ]}
102
+ />
103
+ </View>
104
+ <View style={styles.wrapItemInfo}>
105
+ <Text type="Body" color={isStranger ? Colors.Red6 : Colors.Gray9}>
106
+ {isStranger ? t('stranger') : item.person_name}
107
+ </Text>
108
+ <View style={styles.itemDescription}>
109
+ <Text type="Label" color={Colors.Gray7}>
110
+ {textMask}
111
+ </Text>
112
+ </View>
113
+ </View>
114
+ <View style={styles.wrapAvatar}>
115
+ <Image
116
+ source={{ uri: item.detected_image_uri }}
117
+ style={styles.avatar}
118
+ />
119
+ </View>
120
+ </View>
121
+ );
122
+ },
123
+ [t]
124
+ );
125
+
126
+ const onDatePicked = (datePicked) => {
127
+ onChangeDate(moment(datePicked));
128
+ };
129
+
130
+ const onPickNextDate = () => {
131
+ if (date.isSame(moment(), 'date')) {
132
+ return;
133
+ }
134
+ onChangeDate(moment(date).add(1, 'days'));
135
+ };
136
+
137
+ const onPickPreviousDate = () => {
138
+ onChangeDate(moment(date).add(-1, 'days'));
139
+ };
140
+
141
+ const listMenuItem = useMemo(() => {
142
+ if (isOwner) {
143
+ return [
144
+ {
145
+ text: t('manage_access'),
146
+ route: Routes.HanetManageAccess,
147
+ data: {
148
+ hanetPlace: hanetCamera?.place,
149
+ },
150
+ },
151
+ ];
152
+ }
153
+ return [];
154
+ }, [t, isOwner, hanetCamera?.place]);
155
+
156
+ const onItemMenuClicked = useCallback(
157
+ (item) => {
158
+ navigate(item.route, item.data);
159
+ },
160
+ [navigate]
161
+ );
162
+
163
+ const { childRef, showingPopover, showPopoverWithRef, hidePopover } =
164
+ usePopover();
165
+ const refMenuAction = useRef();
166
+ const handleShowMenuAction = useCallback(() => {
167
+ showPopoverWithRef(refMenuAction);
168
+ }, [showPopoverWithRef, refMenuAction]);
169
+
170
+ const HeaderRight = useMemo(
171
+ () => {
172
+ if (isOwner) {
173
+ return (
174
+ <View style={styles.headerRight}>
175
+ <TouchableOpacity
176
+ style={styles.button}
177
+ onPress={handleShowMenuAction}
178
+ ref={refMenuAction}
179
+ >
180
+ <Icon name={'more'} size={27} color={Colors.Black} />
181
+ </TouchableOpacity>
182
+ </View>
183
+ );
184
+ }
185
+ return <></>;
186
+ },
187
+ // eslint-disable-next-line react-hooks/exhaustive-deps
188
+ [isOwner]
189
+ );
190
+
191
+ return (
192
+ <View style={styles.container}>
193
+ <HeaderCustom
194
+ title={title}
195
+ rightComponent={HeaderRight}
196
+ isShowSeparator
197
+ />
198
+ <View style={styles.wrapTop}>
199
+ <CheckinHeader
200
+ date={date}
201
+ onPickPreviousDate={onPickPreviousDate}
202
+ onPickNextDate={onPickNextDate}
203
+ setShowCalendar={setShowCalendar}
204
+ />
205
+ <View style={[styles.row2, styles.marginTop16]}>
206
+ <Text type="Body" color={Colors.Gray7} style={styles.marginRight10}>
207
+ {`${t('member')}: `}
208
+ <Text color={Colors.Primary} testID={TESTID.TEXT_COUNT_MEMBER}>
209
+ {countMember !== null ? countMember : '--'}
210
+ </Text>
211
+ </Text>
212
+ <Text type="Body" color={Colors.Gray7}>
213
+ {`${t('stranger')}: `}
214
+ <Text color={Colors.Red6} testID={TESTID.TEXT_COUNT_STRANGER}>
215
+ {countStranger !== null ? countStranger : '--'}
216
+ </Text>
217
+ </Text>
218
+ </View>
219
+ </View>
220
+ <FlatList
221
+ data={checkinData}
222
+ extraData={checkinData}
223
+ refreshing={refreshing}
224
+ isLoadMore={loadingMore}
225
+ onRefresh={onRefresh}
226
+ onLoadMore={onLoadMore}
227
+ onMomentumScrollBegin={onMomentumScrollBegin}
228
+ renderItem={CheckInItem}
229
+ contentContainerStyle={styles.contentContainerStyle}
230
+ scrollIndicatorInsets={{ right: 1 }}
231
+ />
232
+ <MenuActionMore
233
+ isVisible={showingPopover}
234
+ hideMore={hidePopover}
235
+ listMenuItem={listMenuItem}
236
+ childRef={childRef}
237
+ onItemClick={onItemMenuClicked}
238
+ wrapStyle={styles.menuAction}
239
+ isTextCenter={false}
240
+ />
241
+ <Calendar
242
+ isVisible={showCalendar}
243
+ defaultDate={date}
244
+ maxDate={moment()}
245
+ onCancel={setHideCalendar}
246
+ onConfirm={onDatePicked}
247
+ />
248
+ </View>
249
+ );
250
+ };
251
+
252
+ export default HanetCameraDetail;
@@ -0,0 +1,173 @@
1
+ import React, { useCallback, useMemo } from 'react';
2
+ import { View, TouchableOpacity, Image, FlatList } from 'react-native';
3
+ import { useNavigation } from '@react-navigation/native';
4
+ import ImagePicker from 'react-native-image-crop-picker';
5
+ import { Icon } from '@ant-design/react-native';
6
+ import { IconOutline, IconFill } from '@ant-design/icons-react-native';
7
+ import { HeaderCustom } from '../../commons/Header';
8
+ import BottomSheet from '../../commons/BottomSheet';
9
+ import Text from '../../commons/Text';
10
+ import styles from './styles/manageAccessStyles';
11
+ import { useTranslations } from '../../hooks/Common/useTranslations';
12
+ import { useHanetPlaceMembers } from './hooks';
13
+ import { useBoolean } from '../../hooks/Common';
14
+ import { Colors } from '../../configs';
15
+ import { TESTID } from '../../configs/Constants';
16
+ import Routes from '../../utils/Route';
17
+ import SmartPhoneSvg from '../../../assets/images/Common/SmartPhone.svg';
18
+
19
+ const HanetManageAccess = ({ route }) => {
20
+ const t = useTranslations();
21
+ const { navigate } = useNavigation();
22
+
23
+ const { hanetPlace } = route.params;
24
+ const {
25
+ data,
26
+ refreshing,
27
+ loadingMore,
28
+ onRefresh,
29
+ onLoadMore,
30
+ onMomentumScrollBegin,
31
+ } = useHanetPlaceMembers(hanetPlace);
32
+
33
+ const onPressItem = (item) => () => {
34
+ navigate(Routes.HanetMemberInfo, {
35
+ hanetPlace: hanetPlace,
36
+ hanetMember: item,
37
+ });
38
+ };
39
+
40
+ const [showAddMemberModal, setShowAddMemberModal, setHideAddMemberModal] =
41
+ useBoolean();
42
+
43
+ const captureFaceID = () => {
44
+ navigate(Routes.HanetCaptureFaceID, {
45
+ title: t('add_new_member'),
46
+ hanetPlace: hanetPlace,
47
+ hanetMember: {
48
+ alias_id: null,
49
+ name: null,
50
+ },
51
+ isAddNewMember: true,
52
+ });
53
+ };
54
+
55
+ const chooseFile = async () => {
56
+ const options = {
57
+ mediaType: 'photo',
58
+ compressImageMaxHeight: 1280,
59
+ compressImageMaxWidth: 738,
60
+ compressImageQuality: 0.7,
61
+ forceJpg: true,
62
+ };
63
+ const result = await ImagePicker.openPicker(options);
64
+ navigate(Routes.HanetMemberInfo, {
65
+ hanetPlace: hanetPlace,
66
+ hanetMember: {
67
+ alias_id: null,
68
+ name: null,
69
+ avatar_uri: result.path,
70
+ },
71
+ isAddNewMember: true,
72
+ });
73
+ };
74
+
75
+ const addMemberOptions = [
76
+ {
77
+ icon: <IconFill name="camera" color={Colors.Gray9} size={27} />,
78
+ text: t('capture_image'),
79
+ onChoose: () => {
80
+ setHideAddMemberModal();
81
+ captureFaceID();
82
+ },
83
+ },
84
+ {
85
+ icon: <SmartPhoneSvg />,
86
+ text: t('pick_available_image_from_your_phone'),
87
+ onChoose: () => {
88
+ setHideAddMemberModal();
89
+ chooseFile();
90
+ },
91
+ },
92
+ ];
93
+
94
+ const MemberItem = useCallback(
95
+ ({ item }) => {
96
+ return (
97
+ <TouchableOpacity
98
+ onPress={onPressItem(item)}
99
+ style={styles.wrapItem}
100
+ testID={TESTID.ROW_HANET_MANAGE_ACCESS}
101
+ >
102
+ <Image source={{ uri: item.avatar_uri }} style={styles.itemAvatar} />
103
+ <Text type="H4" color={Colors.Gray9} style={styles.itemName}>
104
+ {' '}
105
+ {item.name}
106
+ </Text>
107
+ <IconOutline name="right" size={20} color={Colors.Gray6} />
108
+ </TouchableOpacity>
109
+ );
110
+ },
111
+ // eslint-disable-next-line react-hooks/exhaustive-deps
112
+ [navigate]
113
+ );
114
+
115
+ const HeaderRight = useMemo(
116
+ () => (
117
+ <View style={styles.headerRight}>
118
+ <TouchableOpacity
119
+ onPress={setShowAddMemberModal}
120
+ testID={TESTID.HANET_MANAGE_ACCESS_ADD_BUTTON}
121
+ >
122
+ <Icon name={'plus'} size={27} color={Colors.Black} />
123
+ </TouchableOpacity>
124
+ </View>
125
+ ),
126
+ // eslint-disable-next-line react-hooks/exhaustive-deps
127
+ []
128
+ );
129
+
130
+ return (
131
+ <View style={styles.container}>
132
+ <HeaderCustom
133
+ title={t('manage_access')}
134
+ rightComponent={HeaderRight}
135
+ isShowSeparator
136
+ />
137
+ <FlatList
138
+ data={data}
139
+ extraData={data}
140
+ refreshing={refreshing}
141
+ isLoadMore={loadingMore}
142
+ onRefresh={onRefresh}
143
+ onLoadMore={onLoadMore}
144
+ onMomentumScrollBegin={onMomentumScrollBegin}
145
+ renderItem={MemberItem}
146
+ contentContainerStyle={styles.contentContainerStyle}
147
+ scrollIndicatorInsets={{ right: 1 }}
148
+ />
149
+ <BottomSheet
150
+ isVisible={showAddMemberModal}
151
+ onBackdropPress={setHideAddMemberModal}
152
+ title={t('add_member')}
153
+ style={styles.addMemberModal}
154
+ >
155
+ {addMemberOptions.map((option, i) => (
156
+ <TouchableOpacity
157
+ key={i}
158
+ onPress={option.onChoose}
159
+ style={styles.row}
160
+ testID={`${TESTID.HANET_ADD_MEMBER_OPTION}_${i}`}
161
+ >
162
+ {option.icon}
163
+ <Text type="H4" color={Colors.Gray9} style={styles.textOption}>
164
+ {option.text}
165
+ </Text>
166
+ </TouchableOpacity>
167
+ ))}
168
+ </BottomSheet>
169
+ </View>
170
+ );
171
+ };
172
+
173
+ export default HanetManageAccess;