@eohjsc/react-native-smart-city 0.7.35 → 0.7.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@eohjsc/react-native-smart-city",
3
3
  "title": "React Native Smart Home",
4
- "version": "0.7.35",
4
+ "version": "0.7.37",
5
5
  "description": "TODO",
6
6
  "main": "index.js",
7
7
  "files": [
@@ -203,6 +203,11 @@
203
203
  "validator": "^13.1.1",
204
204
  "victory-native": "^41.0.1"
205
205
  },
206
+ "peerDependencies": {
207
+ "react": ">=18.0.0",
208
+ "react-native": ">=0.73.0",
209
+ "react-native-vision-camera": ">=4.0.0"
210
+ },
206
211
  "bugs": {
207
212
  "url": "https://github.com/github_account/react-native-smart-city/issues"
208
213
  },
@@ -151,7 +151,7 @@ const styles = StyleSheet.create({
151
151
  androidStyle: {
152
152
  lineHeight: 22,
153
153
  includeFontPadding: false,
154
- marginBottom: 8,
154
+ marginVertical: 8,
155
155
  },
156
156
  lineHeight20: {
157
157
  lineHeight: 20,
@@ -10,7 +10,7 @@ export default StyleSheet.create({
10
10
  paddingLeft: 7,
11
11
  paddingRight: 10,
12
12
  paddingBottom: 6,
13
- paddingTop: getStatusBarHeight() + 20,
13
+ paddingTop: getStatusBarHeight() + 30,
14
14
  },
15
15
  separator: {
16
16
  borderBottomWidth: 0.5,
@@ -10,7 +10,7 @@ import { AccessibilityLabel } from '../../configs/Constants';
10
10
 
11
11
  const screenHeight = Constants.height;
12
12
  const default_height = 45;
13
- const paddingIos = getStatusBarHeight() + 20;
13
+ const paddingIos = getStatusBarHeight() + 30;
14
14
  export const title_height = 44;
15
15
  export const heightHeader = default_height + title_height + paddingIos;
16
16
 
@@ -1,5 +1,5 @@
1
1
  import React, { memo, useCallback } from 'react';
2
- import { FlatList, StyleSheet, View } from 'react-native';
2
+ import { StyleSheet, View } from 'react-native';
3
3
  import { useTranslations } from '../../hooks/Common/useTranslations';
4
4
 
5
5
  import { Colors } from '../../configs';
@@ -8,7 +8,6 @@ import ImageButton from '../ImageButton';
8
8
  import { ModalCustom } from '../Modal';
9
9
  import packageJson from '../../../package.json';
10
10
 
11
- const keyExtractor = (item) => item.id.toString();
12
11
  const MenuActionAddnew = memo(
13
12
  ({ visible, hideModal, dataActions, onItemClick }) => {
14
13
  const t = useTranslations();
@@ -21,25 +20,6 @@ const MenuActionAddnew = memo(
21
20
  [onItemClick]
22
21
  );
23
22
 
24
- const renderItem = useCallback(
25
- ({ item }) => {
26
- return (
27
- <View
28
- style={{
29
- ...styles.action,
30
- flexBasis: `${100 / numColumns}%`,
31
- }}
32
- >
33
- <ImageButton onPress={() => onPress(item)} image={item.image} />
34
- <View style={styles.actionTextWrap}>
35
- <Text styles={styles.actionText}>{item.text}</Text>
36
- </View>
37
- </View>
38
- );
39
- },
40
- [numColumns, onPress]
41
- );
42
-
43
23
  return (
44
24
  <ModalCustom
45
25
  isVisible={visible}
@@ -53,15 +33,23 @@ const MenuActionAddnew = memo(
53
33
  <Text style={styles.modalHeaderText}>{t('add_new')}</Text>
54
34
  </View>
55
35
 
56
- <FlatList
57
- bounces={false}
58
- numColumns={numColumns}
59
- contentContainerStyle={styles.actionWrapper}
60
- data={dataActions}
61
- keyExtractor={keyExtractor}
62
- renderItem={renderItem}
63
- scrollIndicatorInsets={{ right: 1 }}
64
- />
36
+ <View style={styles.actionWrapper}>
37
+ {dataActions.map((item) => (
38
+ <View
39
+ key={item.id.toString()}
40
+ style={[styles.action, { width: `${100 / numColumns}%` }]}
41
+ >
42
+ <ImageButton
43
+ onPress={() => onPress(item)}
44
+ image={item.image}
45
+ />
46
+ <View style={styles.actionTextWrap}>
47
+ <Text style={styles.actionText}>{item.text}</Text>
48
+ </View>
49
+ </View>
50
+ ))}
51
+ </View>
52
+
65
53
  <View style={styles.modalHeader}>
66
54
  <Text
67
55
  style={styles.modalHeaderText}
@@ -88,7 +76,6 @@ const styles = StyleSheet.create({
88
76
  borderRadius: 10,
89
77
  },
90
78
  modalWrapper: {
91
- flex: 1,
92
79
  flexDirection: 'column',
93
80
  backgroundColor: Colors.White,
94
81
  borderRadius: 10,
@@ -110,7 +97,8 @@ const styles = StyleSheet.create({
110
97
  },
111
98
  actionWrapper: {
112
99
  padding: 16,
113
- flex: 1,
100
+ flexDirection: 'row',
101
+ flexWrap: 'wrap',
114
102
  },
115
103
  action: {
116
104
  marginBottom: 25,
@@ -106,8 +106,7 @@ const HeaderUnit = memo(({ transparent, unit }) => {
106
106
 
107
107
  export default HeaderUnit;
108
108
 
109
- const stickyHeaderHeight =
110
- Device.TopbarHeight + (Device.isIOS ? 0 : StatusBar.currentHeight);
109
+ const stickyHeaderHeight = Device.TopbarHeight + (Device.isIOS ? 0 : 30);
111
110
 
112
111
  const styles = StyleSheet.create({
113
112
  container: {
@@ -10,8 +10,7 @@ import FImage from '../FImage';
10
10
  import { useTranslations } from '../../hooks/Common/useTranslations';
11
11
  import ParallaxScrollView from '../../libs/react-native-parallax-scroll-view';
12
12
 
13
- const stickyHeaderHeight =
14
- Device.TopbarHeight + (Device.isIOS ? 0 : StatusBar.currentHeight);
13
+ const stickyHeaderHeight = Device.TopbarHeight + (Device.isIOS ? 0 : 30);
15
14
 
16
15
  const WrapParallaxScrollView = ({ children, unit, onRefresh }) => {
17
16
  const { name = '', background } = unit;
@@ -17,6 +17,6 @@ export default {
17
17
  isIOS: Platform.OS === 'ios',
18
18
  isIphoneX,
19
19
  ToolbarHeight: isIphoneX ? 44 : Platform.OS === 'ios' ? 20 : 0,
20
- TopbarHeight: isIphoneX ? 88 : Platform.OS === 'ios' ? 64 : 44, //incule toolbar
20
+ TopbarHeight: isIphoneX ? 88 : Platform.OS === 'ios' ? 64 : 50, //incule toolbar
21
21
  androidSmallHeight: Platform.OS === 'android' && height < 600,
22
22
  };
@@ -34,7 +34,6 @@ const Automate = () => {
34
34
  const isFocused = useIsFocused();
35
35
  const { setOptions, navigate } = useNavigation();
36
36
  const [automatesData, setAutomatesData] = useState([]);
37
- const [isLoading, setIsLoading] = useState(false);
38
37
  const { name: currentRouteName } = useRoute();
39
38
  const starredScriptIds = useSCContextSelector(
40
39
  (state) => state.automate.starredScriptIds
@@ -55,8 +54,11 @@ const Automate = () => {
55
54
  }, [automatesData, starredScriptIds]);
56
55
 
57
56
  const getAutomates = useCallback(async () => {
58
- setIsLoading(true);
59
- const { success, data } = await axiosGet(API.AUTOMATE.GET_SMART());
57
+ const { success, data } = await axiosGet(
58
+ API.AUTOMATE.GET_SMART(),
59
+ {},
60
+ true
61
+ );
60
62
  if (success && data && data.length) {
61
63
  const multiUnit = data[0];
62
64
  const haveAutomates = data
@@ -67,7 +69,6 @@ const Automate = () => {
67
69
  .filter((unit) => !unit.automates.length);
68
70
  setAutomatesData([multiUnit, ...haveAutomates, ...notHaveAutomates]);
69
71
  }
70
- setIsLoading(false);
71
72
  }, []);
72
73
 
73
74
  const onPressItem = useCallback(
@@ -224,7 +225,6 @@ const Automate = () => {
224
225
 
225
226
  return (
226
227
  <View style={styles.wrap}>
227
- {isLoading && <Loading />}
228
228
  <FlatList
229
229
  keyExtractor={keyExtractor}
230
230
  data={sortedAutomateData}
@@ -1,7 +1,11 @@
1
- import React, { memo, useState, useRef } from 'react';
2
- import { View, ActivityIndicator, TouchableOpacity } from 'react-native';
1
+ import React, { memo, useState, useRef, useEffect } from 'react';
2
+ import { View, ActivityIndicator, TouchableOpacity, Image } from 'react-native';
3
3
  import { useNavigation } from '@react-navigation/native';
4
- import { RNCamera } from 'react-native-camera';
4
+ import {
5
+ Camera,
6
+ useCameraDevice,
7
+ useCameraPermission,
8
+ } from 'react-native-vision-camera';
5
9
  import { HeaderCustom } from '../../commons/Header';
6
10
  import { FullLoading } from '../../commons';
7
11
  import Text from '../../commons/Text';
@@ -30,37 +34,44 @@ const CaptureFaceID = ({ route }) => {
30
34
  const [capturing, setCapturing] = useState(false);
31
35
  const [imageUri, setImageUri] = useState();
32
36
  const [loading, setLoading] = useState(false);
37
+ const [isCameraActive, setIsCameraActive] = useState(true);
33
38
 
34
- const refCamera = useRef();
39
+ const refCamera = useRef(null);
40
+ const { hasPermission, requestPermission } = useCameraPermission();
41
+ const device = useCameraDevice('back');
42
+
43
+ useEffect(() => {
44
+ if (!hasPermission) {
45
+ requestPermission();
46
+ }
47
+ }, [hasPermission, requestPermission]);
35
48
 
36
49
  const beginCaptureFace = async () => {
37
50
  setCapturing(true);
38
51
  setOpenCamera(true);
52
+ setIsCameraActive(true);
39
53
  };
40
54
 
41
55
  const captureFace = async () => {
42
56
  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);
57
+ try {
58
+ const photo = await refCamera.current.takePhoto({
59
+ qualityPrioritization: 'balanced',
60
+ });
61
+ const uri = `file://${photo.path}`;
62
+ setImageUri(uri);
63
+ setCapturing(false);
64
+ setIsCameraActive(false);
65
+ } catch (error) {
66
+ console.error('Failed to take photo:', error);
67
+ }
56
68
  }
57
69
  };
58
70
 
59
71
  const resumeCapture = () => {
60
- if (refCamera.current) {
61
- setCapturing(true);
62
- refCamera.current.resumePreview();
63
- }
72
+ setCapturing(true);
73
+ setImageUri(undefined);
74
+ setIsCameraActive(true);
64
75
  };
65
76
 
66
77
  const updateMemberFaceID = async () => {
@@ -109,30 +120,48 @@ const CaptureFaceID = ({ route }) => {
109
120
  }
110
121
  };
111
122
 
123
+ const renderCameraContent = () => {
124
+ if (!hasPermission || !device) {
125
+ return <LoadingCamera />;
126
+ }
127
+
128
+ return (
129
+ <>
130
+ <Camera
131
+ ref={refCamera}
132
+ style={{
133
+ height: Constants.height,
134
+ width: Constants.width,
135
+ }}
136
+ device={device}
137
+ isActive={isCameraActive}
138
+ photo={true}
139
+ />
140
+ {isCameraActive && (
141
+ <View style={styles.maskOuter}>
142
+ <FaceFrameSvg />
143
+ </View>
144
+ )}
145
+ {!isCameraActive && imageUri && (
146
+ <Image
147
+ source={{ uri: imageUri }}
148
+ style={{
149
+ position: 'absolute',
150
+ height: Constants.height,
151
+ width: Constants.width,
152
+ }}
153
+ />
154
+ )}
155
+ </>
156
+ );
157
+ };
158
+
112
159
  return (
113
160
  <View style={styles.container}>
114
161
  <HeaderCustom title={title} isShowSeparator />
115
162
  {openCamera && (
116
163
  <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.maskOuter}>
131
- <FaceFrameSvg />
132
- </View>
133
- );
134
- }}
135
- </RNCamera>
164
+ {renderCameraContent()}
136
165
  </View>
137
166
  )}
138
167
  {!openCamera && (
@@ -5,12 +5,40 @@ import MockAdapter from 'axios-mock-adapter';
5
5
  import { SCProvider } from '../../../context';
6
6
  import { mockSCStore } from '../../../context/mockStore';
7
7
  import HanetCaptureFaceID from '../CaptureFaceID';
8
- import { RNCamera } from 'react-native-camera';
8
+ import { Camera } from 'react-native-vision-camera';
9
9
  import api from '../../../utils/Apis/axios';
10
10
  import { API } from '../../../configs';
11
11
 
12
12
  const mock = new MockAdapter(api.axiosInstance);
13
13
 
14
+ const mockTakePhoto = jest.fn().mockResolvedValue({
15
+ path: '/mock/path/photo.jpg',
16
+ width: 1280,
17
+ height: 720,
18
+ });
19
+
20
+ jest.mock('react-native-vision-camera', () => {
21
+ const React = require('react');
22
+ const { View } = require('react-native');
23
+
24
+ return {
25
+ Camera: React.forwardRef((props, ref) => {
26
+ React.useImperativeHandle(ref, () => ({
27
+ takePhoto: mockTakePhoto,
28
+ }));
29
+ return <View testID="mock-camera" {...props} />;
30
+ }),
31
+ useCameraDevice: () => ({
32
+ id: 'mock-device',
33
+ position: 'back',
34
+ }),
35
+ useCameraPermission: () => ({
36
+ hasPermission: true,
37
+ requestPermission: jest.fn().mockResolvedValue(true),
38
+ }),
39
+ };
40
+ });
41
+
14
42
  const wrapComponent = (route) => (
15
43
  <SCProvider initState={mockSCStore({})}>
16
44
  <HanetCaptureFaceID route={route} />
@@ -23,6 +51,7 @@ describe('Test HanetCaptureFaceID', () => {
23
51
 
24
52
  beforeEach(() => {
25
53
  mockSetAvatar.mockClear();
54
+ mockTakePhoto.mockClear();
26
55
  route = {
27
56
  params: {
28
57
  title: 'title',
@@ -46,7 +75,7 @@ describe('Test HanetCaptureFaceID', () => {
46
75
  await act(async () => {
47
76
  await touches[1].props.onPress();
48
77
  });
49
- const camera = instance.findByType(RNCamera);
78
+ const camera = instance.findByType(Camera);
50
79
  expect(camera).toBeDefined();
51
80
 
52
81
  // capture
@@ -51,7 +51,9 @@ const Notification = memo(() => {
51
51
 
52
52
  const fetchNotifications = useCallback(async (pageParam) => {
53
53
  const { success, data } = await axiosGet(
54
- API.NOTIFICATION.LIST_EOH_NOTIFICATIONS(pageParam)
54
+ API.NOTIFICATION.LIST_EOH_NOTIFICATIONS(pageParam),
55
+ {},
56
+ true
55
57
  );
56
58
  if (success) {
57
59
  setNotifications((preState) => preState.concat(data.results));
@@ -69,7 +71,9 @@ const Notification = memo(() => {
69
71
  const onRefresh = useCallback(async () => {
70
72
  setPage(1);
71
73
  const { success, data } = await axiosGet(
72
- API.NOTIFICATION.LIST_EOH_NOTIFICATIONS(1)
74
+ API.NOTIFICATION.LIST_EOH_NOTIFICATIONS(1),
75
+ {},
76
+ true
73
77
  );
74
78
  if (success) {
75
79
  setNotifications(data.results);
@@ -1,14 +1,34 @@
1
1
  import React from 'react';
2
- import { RNCamera } from 'react-native-camera';
3
2
  import { act, create } from 'react-test-renderer';
4
3
 
5
4
  import { SCProvider } from '../../../../../context';
6
5
  import { mockSCStore } from '../../../../../context/mockStore';
7
6
  import QRScan from '../index';
7
+ import { Camera } from 'react-native-vision-camera';
8
8
 
9
9
  const mockedOnScan = jest.fn();
10
10
  const mockedSetLoading = jest.fn();
11
11
 
12
+ jest.mock('react-native-vision-camera', () => {
13
+ const React = require('react');
14
+ const { View } = require('react-native');
15
+
16
+ return {
17
+ Camera: React.forwardRef((props, ref) => (
18
+ <View testID="mock-camera" {...props} />
19
+ )),
20
+ useCameraDevice: () => ({
21
+ id: 'mock-device',
22
+ position: 'back',
23
+ }),
24
+ useCameraPermission: () => ({
25
+ hasPermission: true,
26
+ requestPermission: jest.fn().mockResolvedValue(true),
27
+ }),
28
+ useCodeScanner: (options) => options,
29
+ };
30
+ });
31
+
12
32
  const wrapComponent = (data) => (
13
33
  <SCProvider initState={mockSCStore({})}>
14
34
  <QRScan {...data} />
@@ -20,6 +40,7 @@ describe('Test QRScan', () => {
20
40
 
21
41
  beforeEach(() => {
22
42
  Date.now = jest.fn(() => new Date('2021-01-24T12:00:00.000Z'));
43
+ mockedOnScan.mockClear();
23
44
  data = {
24
45
  onScan: mockedOnScan,
25
46
  loading: false,
@@ -33,21 +54,27 @@ describe('Test QRScan', () => {
33
54
  tree = await create(wrapComponent(data));
34
55
  });
35
56
  const instance = tree.root;
36
- const RNCam = instance.findAllByType(RNCamera);
37
- expect(RNCam).toHaveLength(1);
57
+ const cameras = instance.findAllByType(Camera);
58
+ expect(cameras).toHaveLength(1);
38
59
  });
39
60
 
40
- it('onBarCodeRead', async () => {
61
+ it('onCodeScanned via codeScanner prop', async () => {
41
62
  await act(async () => {
42
63
  tree = await create(wrapComponent(data));
43
64
  });
44
65
  const instance = tree.root;
45
- const RNCam = instance.findByType(RNCamera);
66
+ const camera = instance.findByType(Camera);
67
+
68
+ // Simulate code scanned by calling the codeScanner callback
69
+ const codeScanner = camera.props.codeScanner;
70
+ expect(codeScanner).toBeDefined();
46
71
 
47
- const e = { data: JSON.stringify({ id: 1 }) };
48
72
  await act(async () => {
49
- RNCam.props.onBarCodeRead(e);
73
+ codeScanner.onCodeScanned([{ value: JSON.stringify({ id: 1 }) }]);
50
74
  });
51
- expect(mockedOnScan).toHaveBeenCalled();
75
+ expect(mockedOnScan).toHaveBeenCalledWith(
76
+ JSON.stringify({ id: 1 }),
77
+ expect.any(Function)
78
+ );
52
79
  });
53
80
  });
@@ -8,7 +8,12 @@ import {
8
8
  TouchableOpacity,
9
9
  } from 'react-native';
10
10
  import { IconOutline } from '@ant-design/icons-react-native';
11
- import { RNCamera } from 'react-native-camera';
11
+ import {
12
+ Camera,
13
+ useCameraDevice,
14
+ useCameraPermission,
15
+ useCodeScanner,
16
+ } from 'react-native-vision-camera';
12
17
  import { getStatusBarHeight } from 'react-native-iphone-x-helper';
13
18
  import { useTranslations } from '../../../../hooks/Common/useTranslations';
14
19
 
@@ -52,18 +57,24 @@ const QRScan = ({ isScanReady = true, onScan }) => {
52
57
  const isFocused = useIsFocused();
53
58
 
54
59
  const [loading, setLoading] = useState(false);
60
+ const { hasPermission, requestPermission } = useCameraPermission();
61
+ const device = useCameraDevice('back');
62
+
63
+ useEffect(() => {
64
+ if (!hasPermission) {
65
+ requestPermission();
66
+ }
67
+ }, [hasPermission, requestPermission]);
55
68
 
56
- const onBarCodeRead = useCallback(
57
- (e) => {
58
- if (isScanReady) {
69
+ const codeScanner = useCodeScanner({
70
+ codeTypes: ['qr', 'ean-13', 'code-128'],
71
+ onCodeScanned: (codes) => {
72
+ if (isScanReady && codes.length > 0 && !loading) {
59
73
  setLoading(true);
60
- if (!loading) {
61
- onScan(e.data, setLoading);
62
- }
74
+ onScan(codes[0].value, setLoading);
63
75
  }
64
76
  },
65
- [isScanReady, loading, onScan]
66
- );
77
+ });
67
78
 
68
79
  const onPressClose = useCallback(() => {
69
80
  navigation.pop();
@@ -73,63 +84,69 @@ const QRScan = ({ isScanReady = true, onScan }) => {
73
84
  isFocused && setLoading(false);
74
85
  }, [isFocused, setLoading]);
75
86
 
87
+ if (!hasPermission) {
88
+ return <LoadingCamera />;
89
+ }
90
+
91
+ if (!device) {
92
+ return <LoadingCamera />;
93
+ }
94
+
76
95
  return (
77
- <RNCamera
78
- style={styles.preview}
79
- type={RNCamera.Constants.Type.back}
80
- onBarCodeRead={onBarCodeRead}
81
- >
82
- {({ camera, status, recordAudioPermissionStatus }) => {
83
- if (status !== 'READY') {
84
- return <LoadingCamera />;
85
- }
86
- return (
87
- <View style={styles.maskOuter}>
88
- <View
89
- style={[
90
- { flex: maskRowHeight },
91
- styles.maskRow,
92
- styles.maskFrame,
93
- ]}
94
- />
95
- <View style={styles.maskCenter}>
96
- <View style={[{ width: maskColWidth }, styles.maskFrame]} />
97
- <View style={styles.maskInner} />
98
- <View style={[{ width: maskColWidth }, styles.maskFrame]} />
99
- </View>
100
- <View style={styles.scanningGuide}>
101
- <Text style={styles.scanningGuideText}>
102
- {t('qr_scan_guidelines')}
103
- </Text>
104
- </View>
105
- <View
106
- style={[
107
- { flex: maskRowHeight },
108
- styles.maskRow,
109
- styles.maskFrame,
110
- ]}
111
- />
112
- <CircleButton
113
- onPress={onPressClose}
114
- size={32}
115
- backgroundColor={Colors.White}
116
- borderWidth={1}
117
- borderColor={Colors.Gray4}
118
- style={styles.buttonClose}
119
- >
120
- <IconOutline name={'close'} size={24} co />
121
- </CircleButton>
122
- {loading && <VerifyingQRCode />}
123
- </View>
124
- );
125
- }}
126
- </RNCamera>
96
+ <View style={styles.container}>
97
+ <Camera
98
+ style={StyleSheet.absoluteFill}
99
+ device={device}
100
+ isActive={isFocused}
101
+ codeScanner={codeScanner}
102
+ />
103
+ <View style={styles.maskOuter}>
104
+ <View
105
+ style={[
106
+ { flex: maskRowHeight },
107
+ styles.maskRow,
108
+ styles.maskFrame,
109
+ ]}
110
+ />
111
+ <View style={styles.maskCenter}>
112
+ <View style={[{ width: maskColWidth }, styles.maskFrame]} />
113
+ <View style={styles.maskInner} />
114
+ <View style={[{ width: maskColWidth }, styles.maskFrame]} />
115
+ </View>
116
+ <View style={styles.scanningGuide}>
117
+ <Text style={styles.scanningGuideText}>
118
+ {t('qr_scan_guidelines')}
119
+ </Text>
120
+ </View>
121
+ <View
122
+ style={[
123
+ { flex: maskRowHeight },
124
+ styles.maskRow,
125
+ styles.maskFrame,
126
+ ]}
127
+ />
128
+ <CircleButton
129
+ onPress={onPressClose}
130
+ size={32}
131
+ backgroundColor={Colors.White}
132
+ borderWidth={1}
133
+ borderColor={Colors.Gray4}
134
+ style={styles.buttonClose}
135
+ >
136
+ <IconOutline name={'close'} size={24} />
137
+ </CircleButton>
138
+ {loading && <VerifyingQRCode />}
139
+ </View>
140
+ </View>
127
141
  );
128
142
  };
129
143
 
130
144
  export default QRScan;
131
145
 
132
146
  const styles = StyleSheet.create({
147
+ container: {
148
+ flex: 1,
149
+ },
133
150
  preview: {
134
151
  flex: 1,
135
152
  justifyContent: 'flex-end',
@@ -51,7 +51,8 @@ const Shared = () => {
51
51
  const filterSharedUnits = useCallback(async (field, config) => {
52
52
  const { success, data } = await axiosGet(
53
53
  API.UNIT.FILTER_SHARED_UNITS(field),
54
- config
54
+ config,
55
+ true
55
56
  );
56
57
  if (success) {
57
58
  setSharedUnits(data);
@@ -9,7 +9,7 @@ export default StyleSheet.create({
9
9
  wrap: {
10
10
  flex: 1,
11
11
  backgroundColor: Colors.Gray2,
12
- paddingTop: getStatusBarHeight() + 10,
12
+ paddingTop: getStatusBarHeight() + 30,
13
13
  },
14
14
  padding: {
15
15
  paddingHorizontal: 16,