@eohjsc/react-native-smart-city 0.2.86 → 0.2.89

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 (126) 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/assets/images/brightnessBlack.svg +12 -0
  6. package/index.js +4 -0
  7. package/package.json +3 -3
  8. package/src/Images/SmartIr/AC.svg +14 -0
  9. package/src/Images/SmartIr/DIY.svg +3 -0
  10. package/src/Images/SmartIr/Fan.svg +10 -0
  11. package/src/Images/SmartIr/Fridge.svg +5 -0
  12. package/src/Images/SmartIr/Remote.svg +15 -0
  13. package/src/Images/SmartIr/SmartIr.svg +4 -0
  14. package/src/Images/SmartIr/TV.svg +10 -0
  15. package/src/Images/SmartIr/Union.svg +9 -0
  16. package/src/Images/SmartIr/WM.svg +11 -0
  17. package/src/Images/SmartIr/index.js +10 -0
  18. package/src/commons/ActionGroup/ColorPickerTemplate.js +51 -0
  19. package/src/commons/ActionGroup/ColorPickerTemplateStyles.js +17 -0
  20. package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/AutoLockStyles.js +40 -0
  21. package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/ButtonWrapper.js +65 -0
  22. package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/ButtonWrapperStyles.js +43 -0
  23. package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/__test__/index.test.js +48 -0
  24. package/src/commons/ActionGroup/OnOffSmartLock/AutoLock/index.js +57 -0
  25. package/src/commons/ActionGroup/{OnOffSmartLock.js → OnOffSmartLock/OnOffSmartLock.js} +5 -5
  26. package/src/commons/ActionGroup/{OnOffSmartLockStyle.js → OnOffSmartLock/OnOffSmartLockStyle.js} +1 -1
  27. package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/ItemPasscode.js +48 -0
  28. package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/ItemPasscodeStyles.js +42 -0
  29. package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/PasscodeListStyles.js +49 -0
  30. package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/index.js +66 -0
  31. package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/ButtonWrapper.js +96 -0
  32. package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/SetupGeneratePasscodeStyles.js +98 -0
  33. package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/__test__/index.test.js +62 -0
  34. package/src/commons/ActionGroup/OnOffSmartLock/SetupGeneratePasscode/index.js +249 -0
  35. package/src/commons/ActionGroup/OnOffTemplate/index.js +4 -2
  36. package/src/commons/ActionGroup/OptionsDropdownActionTemplate.js +2 -1
  37. package/src/commons/ActionGroup/SliderRangeTemplate.js +64 -0
  38. package/src/commons/ActionGroup/{LightActionTemplateStyles.js → SliderRangeTemplateStyles.js} +0 -8
  39. package/src/commons/ActionGroup/SmartTiviActionTemplate/SmartTiviActionTemplate.js +167 -186
  40. package/src/commons/ActionGroup/StatesGridActionTemplate.js +2 -1
  41. package/src/commons/ActionGroup/index.js +7 -4
  42. package/src/commons/BottomSheet/index.js +2 -1
  43. package/src/commons/Device/DisconnectedView.js +7 -1
  44. package/src/commons/Device/Hanet/ItemHanetDevice.js +109 -0
  45. package/src/commons/Device/HistoryChart.js +2 -2
  46. package/src/commons/Device/HorizontalBarChart.js +7 -0
  47. package/src/commons/Device/ItemDevice.js +18 -15
  48. package/src/commons/Device/LinearChart.js +14 -41
  49. package/src/commons/Device/__test__/DisconnectedView.test.js +13 -2
  50. package/src/commons/RowItem/index.js +12 -7
  51. package/src/commons/SubUnit/Favorites/index.js +2 -2
  52. package/src/commons/SubUnit/ShortDetail.js +39 -20
  53. package/src/commons/WheelDateTimePicker/index.js +18 -4
  54. package/src/configs/API.js +23 -1
  55. package/src/configs/Colors.js +1 -0
  56. package/src/configs/Constants.js +48 -0
  57. package/src/configs/SCConfig.js +1 -1
  58. package/src/context/actionType.ts +4 -0
  59. package/src/context/mockStore.ts +3 -0
  60. package/src/context/reducer.ts +20 -0
  61. package/src/iot/RemoteControl/Bluetooth.js +3 -22
  62. package/src/iot/RemoteControl/index.js +0 -1
  63. package/src/navigations/HanetCameraStack.js +41 -0
  64. package/src/navigations/SmartIrStack.js +31 -0
  65. package/src/navigations/SmartLockStack.js +51 -0
  66. package/src/navigations/UnitStack.js +46 -4
  67. package/src/screens/ActivityLog/hooks/index.js +1 -1
  68. package/src/screens/AddCommon/__test__/SelectSubUnit.test.js +1 -1
  69. package/src/screens/AddNewGateway/PlugAndPlay/ConnectWifiWarning.js +79 -72
  70. package/src/screens/AddNewGateway/PlugAndPlay/GatewayWifiList.js +155 -27
  71. package/src/screens/AddNewGateway/PlugAndPlay/__test__/ConnectWifiWarning.test.js +65 -0
  72. package/src/screens/AddNewGateway/PlugAndPlay/__test__/GatewayWifiList.test.js +26 -2
  73. package/src/screens/Device/__test__/detail.test.js +0 -10
  74. package/src/screens/Device/components/SensorConnectStatusViewHeader.js +13 -2
  75. package/src/screens/Device/detail.js +118 -38
  76. package/src/screens/Device/hooks/useDisconnectedDevice.js +28 -16
  77. package/src/screens/GuestInfo/components/AccessScheduleItem.js +9 -2
  78. package/src/screens/GuestInfo/components/RecurringDetail.js +3 -2
  79. package/src/screens/GuestInfo/components/TemporaryDetail.js +3 -2
  80. package/src/screens/GuestInfo/styles/AccessScheduleItemStyles.js +3 -0
  81. package/src/screens/HanetCamera/CaptureFaceID.js +210 -0
  82. package/src/screens/HanetCamera/Detail.js +252 -0
  83. package/src/screens/HanetCamera/ManageAccess.js +173 -0
  84. package/src/screens/HanetCamera/MemberInfo.js +208 -0
  85. package/src/screens/HanetCamera/__test__/CaptureFaceID.test.js +133 -0
  86. package/src/screens/HanetCamera/__test__/Detail.test.js +185 -0
  87. package/src/screens/HanetCamera/__test__/ManageAccess.test.js +152 -0
  88. package/src/screens/HanetCamera/__test__/MemberInfo.test.js +178 -0
  89. package/src/screens/HanetCamera/components/CheckinHeader.js +37 -0
  90. package/src/screens/HanetCamera/hooks/__test__/useHanetCheckinData.test.js +151 -0
  91. package/src/screens/HanetCamera/hooks/__test__/useHanetPlaceMembers.test.js +71 -0
  92. package/src/screens/HanetCamera/hooks/index.js +5 -0
  93. package/src/screens/HanetCamera/hooks/useHanetCheckinData.js +116 -0
  94. package/src/screens/HanetCamera/hooks/useHanetPlaceMembers.js +86 -0
  95. package/src/screens/HanetCamera/hooks/useStateAlertAction.js +62 -0
  96. package/src/screens/HanetCamera/styles/captureFaceIDStyles.js +50 -0
  97. package/src/screens/HanetCamera/styles/checkinHeaderStyles.js +24 -0
  98. package/src/screens/HanetCamera/styles/detailStyles.js +107 -0
  99. package/src/screens/HanetCamera/styles/manageAccessStyles.js +49 -0
  100. package/src/screens/HanetCamera/styles/memberInfoStyles.js +73 -0
  101. package/src/screens/HanetCamera/utils/Monitor.js +52 -0
  102. package/src/screens/Notification/__test__/NotificationItem.test.js +1 -0
  103. package/src/screens/Notification/components/NotificationItem.js +16 -0
  104. package/src/screens/SmartIr/__test__/ButtonsBottom.test.js +31 -0
  105. package/src/screens/SmartIr/__test__/GroupButtonByType.test.js +80 -0
  106. package/src/screens/SmartIr/__test__/SelectBrand.test.js +65 -0
  107. package/src/screens/SmartIr/__test__/SelectDeviceType.test.js +57 -0
  108. package/src/screens/SmartIr/__test__/SmartIr.test.js +1 -0
  109. package/src/screens/SmartIr/components/GroupButtonByType/ButtonsBottom.js +45 -0
  110. package/src/screens/SmartIr/components/GroupButtonByType/ButtonsBottomStyles.js +31 -0
  111. package/src/screens/SmartIr/components/GroupButtonByType/GroupButtonByType.js +208 -0
  112. package/src/screens/SmartIr/components/GroupButtonByType/GroupButtonByTypeStyles.js +113 -0
  113. package/src/screens/SmartIr/components/SelectBrand.js +61 -0
  114. package/src/screens/SmartIr/components/SelectBrandStyles.js +14 -0
  115. package/src/screens/SmartIr/components/SelectDeviceType.js +96 -0
  116. package/src/screens/SmartIr/components/SelectDeviceTypeStyles.js +30 -0
  117. package/src/screens/SmartIr/index.js +8 -3
  118. package/src/screens/Unit/Detail.js +7 -11
  119. package/src/screens/Unit/__test__/Detail.test.js +0 -10
  120. package/src/screens/Unit/components/MyUnitDevice/index.js +2 -4
  121. package/src/screens/Unit/components/__test__/MyUnitDevice.test.js +38 -9
  122. package/src/utils/I18n/translations/en.json +51 -1
  123. package/src/utils/I18n/translations/vi.json +51 -1
  124. package/src/utils/Route/index.js +14 -1
  125. package/src/commons/ActionGroup/LightActionTemplate.js +0 -103
  126. package/src/commons/ActionGroup/__test__/LightActionTemplate.test.js +0 -59
@@ -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;
@@ -0,0 +1,208 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { View, TouchableOpacity, Image, Platform } from 'react-native';
3
+ import { useNavigation } from '@react-navigation/native';
4
+ import { IconFill } from '@ant-design/icons-react-native';
5
+ import { HeaderCustom } from '../../commons/Header';
6
+ import { AlertAction, FullLoading } from '../../commons';
7
+ import BottomButtonView from '../../commons/BottomButtonView';
8
+ import TextInput from '../../commons/Form/TextInput';
9
+ import Text from '../../commons/Text';
10
+ import { useStateAlertAction } from './hooks';
11
+ import { useTranslations } from '../../hooks/Common/useTranslations';
12
+ import useKeyboardAnimated from '../../hooks/Explore/useKeyboardAnimated';
13
+ import styles from './styles/memberInfoStyles';
14
+ import { Colors, API } from '../../configs';
15
+ import { axiosDelete, axiosPatch, axiosPost } from '../../utils/Apis/axios';
16
+ import Routes from '../../utils/Route';
17
+
18
+ const HanetMemberInfo = ({ route }) => {
19
+ const t = useTranslations();
20
+ const { navigate, goBack } = useNavigation();
21
+ const { hanetPlace, hanetMember, isAddNewMember } = route.params;
22
+ const [memberAvatar, setMemberAvatar] = useState(hanetMember.avatar_uri);
23
+ const [memberName, setMemberName] = useState(hanetMember.name);
24
+ const [inputName, setInputName] = useState(hanetMember.name);
25
+ const [error, setError] = useState('');
26
+ const [loading, setLoading] = useState(false);
27
+
28
+ useEffect(() => {
29
+ setMemberAvatar(hanetMember.avatar_uri);
30
+ setMemberName(hanetMember.name);
31
+ }, [hanetMember]);
32
+
33
+ const { stateAlertAction, hideAlertAction, showRename, showDelete } =
34
+ useStateAlertAction();
35
+
36
+ const onShowRename = () => {
37
+ setInputName(memberName);
38
+ showRename(isAddNewMember);
39
+ };
40
+
41
+ const onShowDelete = () => {
42
+ showDelete();
43
+ };
44
+
45
+ const setFaceID = () => {
46
+ navigate(Routes.HanetCaptureFaceID, {
47
+ title: t('set_photo_id'),
48
+ hanetPlace,
49
+ hanetMember: {
50
+ ...hanetMember,
51
+ avatar_uri: memberAvatar,
52
+ name: memberName,
53
+ },
54
+ memberAvatar,
55
+ setMemberAvatar,
56
+ isAddNewMember,
57
+ });
58
+ };
59
+
60
+ const finishRegister = async () => {
61
+ setLoading(true);
62
+ const formData = new FormData();
63
+ const name = memberAvatar.split('/').pop();
64
+ const ext = memberAvatar.split('.').pop();
65
+ formData.append('face_id', {
66
+ name: name,
67
+ type: `image/${ext}`,
68
+ uri: memberAvatar,
69
+ });
70
+ formData.append('name', memberName);
71
+ const { success, data } = await axiosPost(
72
+ API.CAMERA.HANET.REGISTER(hanetPlace.place_id),
73
+ formData,
74
+ {
75
+ headers: { 'Content-Type': 'multipart/form-data' },
76
+ }
77
+ );
78
+ if (success) {
79
+ navigate(Routes.HanetManageAccess, {
80
+ hanetPlace: hanetPlace,
81
+ });
82
+ } else {
83
+ setError(data.detail);
84
+ }
85
+ setLoading(false);
86
+ };
87
+
88
+ const renameMember = async () => {
89
+ hideAlertAction();
90
+ if (isAddNewMember) {
91
+ setMemberName(inputName);
92
+ return;
93
+ }
94
+
95
+ setLoading(true);
96
+ const { success } = await axiosPatch(
97
+ API.CAMERA.HANET.RENAME_MEMBER(hanetPlace.place_id, hanetMember.alias_id),
98
+ {
99
+ name: inputName,
100
+ }
101
+ );
102
+ success && setMemberName(inputName);
103
+ setLoading(false);
104
+ };
105
+
106
+ const removeMember = async () => {
107
+ hideAlertAction();
108
+ setLoading(true);
109
+ const { success } = await axiosDelete(
110
+ API.CAMERA.HANET.REMOVE_MEMBER(hanetPlace.place_id, hanetMember.alias_id)
111
+ );
112
+ success && goBack();
113
+ setLoading(false);
114
+ };
115
+
116
+ const handleRenameOrDelete = () => {
117
+ if (stateAlertAction.isDelete) {
118
+ removeMember();
119
+ } else {
120
+ renameMember();
121
+ }
122
+ };
123
+
124
+ const [transY] = useKeyboardAnimated(-16);
125
+ const animatedStyle = Platform.select({
126
+ ios: {
127
+ marginBottom: transY,
128
+ },
129
+ });
130
+
131
+ return (
132
+ <View style={styles.container}>
133
+ <HeaderCustom title={t('member_info')} isShowSeparator />
134
+ <View style={styles.wrapAvatar}>
135
+ <Image source={{ uri: memberAvatar }} style={styles.avatar} />
136
+ </View>
137
+ <TouchableOpacity
138
+ onPress={setFaceID}
139
+ style={[styles.row, !!error && { borderBottomColor: Colors.Red6 }]}
140
+ >
141
+ <IconFill name="camera" size={27} color={Colors.Primary} />
142
+ <Text
143
+ type="Body"
144
+ bold
145
+ color={Colors.Primary}
146
+ style={styles.textSetPhoto}
147
+ >
148
+ {t('set_photo_id')}
149
+ </Text>
150
+ <Image source={{ uri: memberAvatar }} style={styles.photoID} />
151
+ </TouchableOpacity>
152
+ {!!error && (
153
+ <Text type="Label" style={styles.textError} color={Colors.Red6}>
154
+ {error}
155
+ </Text>
156
+ )}
157
+ <TouchableOpacity
158
+ onPress={onShowRename}
159
+ style={[styles.row, styles.spaceBetween]}
160
+ >
161
+ <Text type="H4" bold color={Colors.Gray9}>
162
+ {t('text_name')}
163
+ </Text>
164
+ <Text type="Body" color={Colors.Gray8}>
165
+ {memberName}
166
+ </Text>
167
+ </TouchableOpacity>
168
+ {!isAddNewMember && (
169
+ <TouchableOpacity onPress={onShowDelete} style={styles.buttonRemove}>
170
+ <Text type="H4" color={Colors.Red6} underline bold>
171
+ {t('remove_member')}
172
+ </Text>
173
+ </TouchableOpacity>
174
+ )}
175
+ {isAddNewMember && (
176
+ <BottomButtonView
177
+ mainTitle={t('finish')}
178
+ onPressMain={finishRegister}
179
+ style={styles.bottomButton}
180
+ />
181
+ )}
182
+ {loading && <FullLoading />}
183
+ <AlertAction
184
+ visible={stateAlertAction.visible}
185
+ hideModal={hideAlertAction}
186
+ title={stateAlertAction.title}
187
+ message={stateAlertAction.message}
188
+ leftButtonTitle={stateAlertAction.leftButton}
189
+ leftButtonClick={hideAlertAction}
190
+ rightButtonTitle={stateAlertAction.rightButton}
191
+ rightButtonClick={handleRenameOrDelete}
192
+ rightButtonStyle={{ color: stateAlertAction.rightColor }}
193
+ animatedStyle={animatedStyle}
194
+ >
195
+ {!stateAlertAction.isDelete && (
196
+ <TextInput
197
+ onChange={(text) => setInputName(text)}
198
+ defaultValue={inputName}
199
+ textInputStyle={styles.textInput}
200
+ maxLength={64}
201
+ />
202
+ )}
203
+ </AlertAction>
204
+ </View>
205
+ );
206
+ };
207
+
208
+ export default HanetMemberInfo;