@eohjsc/react-native-smart-city 0.2.85 → 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 (148) hide show
  1. package/assets/images/Common/Calendar.svg +3 -0
  2. package/assets/images/Common/SmartPhone.svg +3 -0
  3. package/assets/images/Device/button-lock.svg +3 -0
  4. package/assets/images/Device/button-unlock.svg +3 -0
  5. package/assets/images/Hanet/CaptureFaceID.svg +25 -0
  6. package/assets/images/Hanet/FaceFrame.svg +6 -0
  7. package/assets/images/brightnessBlack.svg +12 -0
  8. package/index.js +4 -0
  9. package/package.json +2 -2
  10. package/src/Images/SmartIr/AC.svg +14 -0
  11. package/src/Images/SmartIr/DIY.svg +3 -0
  12. package/src/Images/SmartIr/Fan.svg +10 -0
  13. package/src/Images/SmartIr/Fridge.svg +5 -0
  14. package/src/Images/SmartIr/Remote.svg +15 -0
  15. package/src/Images/SmartIr/SmartIr.svg +4 -0
  16. package/src/Images/SmartIr/TV.svg +10 -0
  17. package/src/Images/SmartIr/Union.svg +9 -0
  18. package/src/Images/SmartIr/WM.svg +11 -0
  19. package/src/Images/SmartIr/index.js +10 -0
  20. package/src/commons/ActionGroup/ColorPickerTemplate.js +51 -0
  21. package/src/commons/ActionGroup/ColorPickerTemplateStyles.js +17 -0
  22. package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/AutoLockStyles.js +40 -0
  23. package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/ButtonWrapper.js +65 -0
  24. package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/ButtonWrapperStyles.js +43 -0
  25. package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/__test__/index.test.js +48 -0
  26. package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/index.js +57 -0
  27. package/src/commons/ActionGroup/OnOffSmartLock/OnOffSmartLock.js +48 -0
  28. package/src/commons/ActionGroup/OnOffSmartLock/OnOffSmartLockStyle.js +51 -0
  29. package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/ItemPasscode.js +48 -0
  30. package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/ItemPasscodeStyles.js +42 -0
  31. package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/PasscodeListStyles.js +49 -0
  32. package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/index.js +66 -0
  33. package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/ButtonWrapper.js +96 -0
  34. package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/SetupGeneratePasscodeStyles.js +98 -0
  35. package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/__test__/index.test.js +62 -0
  36. package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/index.js +249 -0
  37. package/src/commons/ActionGroup/OnOffTemplate/index.js +4 -2
  38. package/src/commons/ActionGroup/OptionsDropdownActionTemplate.js +2 -1
  39. package/src/commons/ActionGroup/SliderRangeTemplate.js +64 -0
  40. package/src/commons/ActionGroup/{LightActionTemplateStyles.js → SliderRangeTemplateStyles.js} +0 -8
  41. package/src/commons/ActionGroup/SmartTiviActionTemplate/SmartTiviActionTemplate.js +167 -186
  42. package/src/commons/ActionGroup/StatesGridActionTemplate.js +2 -1
  43. package/src/commons/ActionGroup/index.js +9 -3
  44. package/src/commons/BottomSheet/index.js +2 -1
  45. package/src/commons/ConnectingProcess/index.js +5 -2
  46. package/src/commons/Device/DisconnectedView.js +7 -1
  47. package/src/commons/Device/Hanet/ItemHanetDevice.js +109 -0
  48. package/src/commons/Device/HistoryChart.js +2 -2
  49. package/src/commons/Device/HorizontalBarChart.js +7 -0
  50. package/src/commons/Device/ItemDevice.js +24 -16
  51. package/src/commons/Device/LinearChart.js +14 -41
  52. package/src/commons/Device/__test__/DisconnectedView.test.js +13 -2
  53. package/src/commons/MediaPlayer/__test__/index.test.js +45 -0
  54. package/src/commons/RowItem/index.js +12 -7
  55. package/src/commons/SubUnit/Favorites/index.js +2 -2
  56. package/src/commons/SubUnit/ShortDetail.js +48 -41
  57. package/src/commons/SubUnit/__test__/ShortDetail.test.js +57 -48
  58. package/src/commons/WheelDateTimePicker/index.js +18 -4
  59. package/src/configs/API.js +24 -2
  60. package/src/configs/Colors.js +1 -0
  61. package/src/configs/Constants.js +61 -0
  62. package/src/configs/SCConfig.js +1 -1
  63. package/src/context/actionType.ts +4 -0
  64. package/src/context/mockStore.ts +3 -0
  65. package/src/context/reducer.ts +20 -0
  66. package/src/iot/RemoteControl/Bluetooth.js +3 -22
  67. package/src/iot/RemoteControl/index.js +0 -1
  68. package/src/navigations/HanetCameraStack.js +41 -0
  69. package/src/navigations/SmartIrStack.js +31 -0
  70. package/src/navigations/SmartLockStack.js +51 -0
  71. package/src/navigations/UnitStack.js +46 -4
  72. package/src/screens/ActivityLog/hooks/index.js +17 -3
  73. package/src/screens/ActivityLog/index.js +3 -0
  74. package/src/screens/AddCommon/SelectSubUnit.js +1 -0
  75. package/src/screens/AddCommon/__test__/SelectSubUnit.test.js +1 -1
  76. package/src/screens/AddNewAction/SelectSensorDevices.js +4 -2
  77. package/src/screens/AddNewGateway/PlugAndPlay/ConnectWifiWarning.js +88 -73
  78. package/src/screens/AddNewGateway/PlugAndPlay/FirstWarning.js +4 -2
  79. package/src/screens/AddNewGateway/PlugAndPlay/GatewayWifiList.js +155 -27
  80. package/src/screens/AddNewGateway/PlugAndPlay/__test__/ConnectWifiWarning.test.js +65 -0
  81. package/src/screens/AddNewGateway/PlugAndPlay/__test__/GatewayWifiList.test.js +26 -2
  82. package/src/screens/AddNewOneTap/index.js +32 -17
  83. package/src/screens/Automate/index.js +2 -2
  84. package/src/screens/Device/EditDevice/index.js +5 -3
  85. package/src/screens/Device/__test__/detail.test.js +0 -10
  86. package/src/screens/Device/components/SensorConnectStatusViewHeader.js +13 -2
  87. package/src/screens/Device/components/SensorDisplayItem.js +3 -0
  88. package/src/screens/Device/detail.js +119 -38
  89. package/src/screens/Device/hooks/useDisconnectedDevice.js +28 -16
  90. package/src/screens/GuestInfo/components/AccessScheduleItem.js +9 -2
  91. package/src/screens/GuestInfo/components/RecurringDetail.js +3 -2
  92. package/src/screens/GuestInfo/components/TemporaryDetail.js +3 -2
  93. package/src/screens/GuestInfo/styles/AccessScheduleItemStyles.js +3 -0
  94. package/src/screens/HanetCamera/CaptureFaceID.js +210 -0
  95. package/src/screens/HanetCamera/Detail.js +252 -0
  96. package/src/screens/HanetCamera/ManageAccess.js +173 -0
  97. package/src/screens/HanetCamera/MemberInfo.js +208 -0
  98. package/src/screens/HanetCamera/__test__/CaptureFaceID.test.js +133 -0
  99. package/src/screens/HanetCamera/__test__/Detail.test.js +185 -0
  100. package/src/screens/HanetCamera/__test__/ManageAccess.test.js +152 -0
  101. package/src/screens/HanetCamera/__test__/MemberInfo.test.js +178 -0
  102. package/src/screens/HanetCamera/components/CheckinHeader.js +37 -0
  103. package/src/screens/HanetCamera/hooks/__test__/useHanetCheckinData.test.js +151 -0
  104. package/src/screens/HanetCamera/hooks/__test__/useHanetPlaceMembers.test.js +71 -0
  105. package/src/screens/HanetCamera/hooks/index.js +5 -0
  106. package/src/screens/HanetCamera/hooks/useHanetCheckinData.js +116 -0
  107. package/src/screens/HanetCamera/hooks/useHanetPlaceMembers.js +86 -0
  108. package/src/screens/HanetCamera/hooks/useStateAlertAction.js +62 -0
  109. package/src/screens/HanetCamera/styles/captureFaceIDStyles.js +50 -0
  110. package/src/screens/HanetCamera/styles/checkinHeaderStyles.js +24 -0
  111. package/src/screens/HanetCamera/styles/detailStyles.js +107 -0
  112. package/src/screens/HanetCamera/styles/manageAccessStyles.js +49 -0
  113. package/src/screens/HanetCamera/styles/memberInfoStyles.js +73 -0
  114. package/src/screens/HanetCamera/utils/Monitor.js +52 -0
  115. package/src/screens/Notification/__test__/NotificationItem.test.js +16 -3
  116. package/src/screens/Notification/components/NotificationItem.js +68 -8
  117. package/src/screens/ScanChipQR/__test__/ScanChipQR.test.js +1 -0
  118. package/src/screens/ScanChipQR/hooks/index.js +90 -44
  119. package/src/screens/ScriptDetail/index.js +1 -6
  120. package/src/screens/SelectUnit/index.js +1 -0
  121. package/src/screens/SharedUnit/index.js +1 -1
  122. package/src/screens/SmartIr/__test__/ButtonsBottom.test.js +31 -0
  123. package/src/screens/SmartIr/__test__/GroupButtonByType.test.js +80 -0
  124. package/src/screens/SmartIr/__test__/SelectBrand.test.js +65 -0
  125. package/src/screens/SmartIr/__test__/SelectDeviceType.test.js +57 -0
  126. package/src/screens/SmartIr/__test__/SmartIr.test.js +62 -0
  127. package/src/screens/SmartIr/components/GroupButtonByType/ButtonsBottom.js +45 -0
  128. package/src/screens/SmartIr/components/GroupButtonByType/ButtonsBottomStyles.js +31 -0
  129. package/src/screens/SmartIr/components/GroupButtonByType/GroupButtonByType.js +208 -0
  130. package/src/screens/SmartIr/components/GroupButtonByType/GroupButtonByTypeStyles.js +113 -0
  131. package/src/screens/SmartIr/components/SelectBrand.js +61 -0
  132. package/src/screens/SmartIr/components/SelectBrandStyles.js +14 -0
  133. package/src/screens/SmartIr/components/SelectDeviceType.js +96 -0
  134. package/src/screens/SmartIr/components/SelectDeviceTypeStyles.js +30 -0
  135. package/src/screens/SmartIr/index.js +28 -0
  136. package/src/screens/SmartIr/styles.js +14 -0
  137. package/src/screens/Unit/AddMenu.js +4 -1
  138. package/src/screens/Unit/Detail.js +8 -12
  139. package/src/screens/Unit/__test__/Detail.test.js +0 -10
  140. package/src/screens/Unit/components/MyUnitDevice/index.js +2 -4
  141. package/src/screens/Unit/components/__test__/MyUnitDevice.test.js +38 -9
  142. package/src/screens/UnitSummary/components/PowerConsumeHistoryChart/__test__/index.test.js +32 -1
  143. package/src/screens/UnitSummary/components/PowerConsumeHistoryChart/index.js +1 -1
  144. package/src/utils/I18n/translations/en.json +59 -2
  145. package/src/utils/I18n/translations/vi.json +59 -2
  146. package/src/utils/Route/index.js +14 -0
  147. package/src/commons/ActionGroup/LightActionTemplate.js +0 -103
  148. 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;