@eohjsc/react-native-smart-city 0.2.89 → 0.2.92
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 +1 -1
- package/src/commons/ActionGroup/ColorPickerTemplate.js +30 -24
- package/src/commons/ActionGroup/OnOffSmartLock/OnOffSmartLock.js +60 -12
- package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/__test__/index.test.js +47 -0
- package/src/commons/ActionGroup/OnOffSmartLock/PasscodeList/index.js +2 -0
- package/src/commons/ActionGroup/OnOffTemplate/index.js +48 -28
- package/src/commons/ActionGroup/SliderRangeTemplate.js +19 -5
- package/src/commons/ActionGroup/__test__/ColorPickerTemplate.test.js +74 -0
- package/src/commons/ActionGroup/__test__/OnOffSmartLock.test.js +107 -0
- package/src/commons/ActionGroup/__test__/SliderRangeTemplate.test.js +71 -0
- package/src/commons/ActionGroup/index.js +1 -1
- package/src/commons/Calendar/index.js +5 -1
- package/src/commons/ConnectingProcess/__test__/Connecting.test.js +4 -1
- package/src/commons/Device/HorizontalBarChart.js +6 -2
- package/src/commons/SubUnit/Favorites/index.js +4 -35
- package/src/commons/SubUnit/ShortDetail.js +7 -41
- package/src/configs/Constants.js +5 -0
- package/src/hooks/Common/index.js +2 -0
- package/src/hooks/Common/useSensorsStatus.js +52 -0
- package/src/screens/AddNewGateway/PlugAndPlay/__test__/ConnectWifiWarning.test.js +1 -0
- package/src/screens/AddNewGateway/__test__/SelectGateway.test.js +61 -0
- package/src/screens/Device/__test__/DetailHistoryChart.test.js +40 -0
- package/src/screens/Device/detail.js +46 -29
- package/src/screens/HanetCamera/Detail.js +20 -13
- package/src/screens/HanetCamera/ManageAccess.js +10 -52
- package/src/screens/HanetCamera/MemberInfo.js +59 -13
- package/src/screens/HanetCamera/__test__/ManageAccess.test.js +19 -0
- package/src/screens/HanetCamera/__test__/MemberInfo.test.js +57 -10
- package/src/screens/HanetCamera/components/RequestFaceIDPopup.js +90 -0
- package/src/screens/HanetCamera/hooks/__test__/useHanetCheckinData.test.js +9 -12
- package/src/screens/HanetCamera/hooks/useHanetCheckinData.js +10 -7
- package/src/screens/HanetCamera/styles/manageAccessStyles.js +0 -14
- package/src/screens/Unit/Detail.js +1 -7
- package/src/screens/Unit/components/MyUnitDevice/index.js +13 -10
- package/src/screens/Unit/components/__test__/MyUnitDevice.test.js +2 -2
- package/src/utils/I18n/translations/en.json +1 -0
- package/src/utils/I18n/translations/vi.json +1 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState, useCallback } from 'react';
|
|
1
|
+
import React, { useState, useCallback, useEffect } from 'react';
|
|
2
2
|
import { Image } from 'react-native';
|
|
3
3
|
import { Calendar } from 'react-native-calendars';
|
|
4
4
|
import moment from 'moment';
|
|
@@ -20,6 +20,10 @@ export default ({
|
|
|
20
20
|
const t = useTranslations();
|
|
21
21
|
const [dateSelected, setDateSelected] = useState(defaultDate);
|
|
22
22
|
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
setDateSelected(defaultDate);
|
|
25
|
+
}, [defaultDate]);
|
|
26
|
+
|
|
23
27
|
const onDateSelected = useCallback(
|
|
24
28
|
(day) => {
|
|
25
29
|
setDateSelected(moment(day.timestamp));
|
|
@@ -14,9 +14,12 @@ describe('Test ConnectingProcess', () => {
|
|
|
14
14
|
let tree;
|
|
15
15
|
test('create ConnectingProcess', () => {
|
|
16
16
|
const scan_sensor_data = { imei: 'SENSOR-afasdfas' };
|
|
17
|
+
const devicePrefixName = 'SENSOR';
|
|
17
18
|
const gateway = { id: 1, name: 'gateway' };
|
|
18
19
|
const station = { id: 1, icon_kit: 'a', name: 'station' };
|
|
19
|
-
const route = {
|
|
20
|
+
const route = {
|
|
21
|
+
params: { scan_sensor_data, gateway, station, devicePrefixName },
|
|
22
|
+
};
|
|
20
23
|
act(() => {
|
|
21
24
|
tree = renderer.create(wrapComponent(route));
|
|
22
25
|
});
|
|
@@ -105,7 +105,11 @@ const HorizontalBarChart = memo(({ datas, config }) => {
|
|
|
105
105
|
|
|
106
106
|
const heightChart = useMemo(() => {
|
|
107
107
|
const dataX = datas[0].data.map((item) => item.x);
|
|
108
|
-
return dataX.length > 1
|
|
108
|
+
return dataX.length > 1
|
|
109
|
+
? dataX.length === 2
|
|
110
|
+
? dataX.length * 55 + 30
|
|
111
|
+
: dataX.length * 55
|
|
112
|
+
: 90;
|
|
109
113
|
}, [datas]);
|
|
110
114
|
|
|
111
115
|
useEffect(() => {
|
|
@@ -171,7 +175,7 @@ const styles = StyleSheet.create({
|
|
|
171
175
|
},
|
|
172
176
|
webviewStyle: {
|
|
173
177
|
flex: 1,
|
|
174
|
-
minHeight:
|
|
178
|
+
minHeight: 0,
|
|
175
179
|
height: 300,
|
|
176
180
|
opacity: 0.99,
|
|
177
181
|
},
|
|
@@ -1,55 +1,24 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import { View } from 'react-native';
|
|
3
3
|
import { useTranslations } from '../../../hooks/Common/useTranslations';
|
|
4
|
-
import {
|
|
4
|
+
import { useSensorsStatus } from '../../../hooks/Common';
|
|
5
5
|
|
|
6
6
|
import { Section } from '../../Section';
|
|
7
7
|
import ItemDevice from '../../Device/ItemDevice';
|
|
8
8
|
import ItemOneTap from '../OneTap/ItemOneTap';
|
|
9
9
|
import ItemAddNew from '../../Device/ItemAddNew';
|
|
10
10
|
import styles from './styles';
|
|
11
|
-
import { API } from '../../../configs';
|
|
12
|
-
import { axiosGet } from '../../../utils/Apis/axios';
|
|
13
11
|
|
|
14
12
|
const SubUnitFavorites = ({
|
|
15
13
|
unit,
|
|
16
14
|
isOwner,
|
|
17
15
|
favorites,
|
|
18
|
-
serverDown,
|
|
19
16
|
isGGHomeConnected,
|
|
20
17
|
wrapItemStyle,
|
|
21
18
|
}) => {
|
|
22
19
|
const t = useTranslations();
|
|
23
|
-
const isFocused = useIsFocused();
|
|
24
|
-
const intervalSensorStatus = useRef();
|
|
25
|
-
const [sensorsStatus, setSensorsStatus] = useState([]);
|
|
26
20
|
|
|
27
|
-
|
|
28
|
-
if (isFocused) {
|
|
29
|
-
const getSensorsStatus = async () => {
|
|
30
|
-
const params = new URLSearchParams();
|
|
31
|
-
if (favorites?.devices?.length > 0) {
|
|
32
|
-
favorites.devices.forEach((sensor) => {
|
|
33
|
-
params.append('sensors', sensor.id);
|
|
34
|
-
});
|
|
35
|
-
const { success, data } = await axiosGet(
|
|
36
|
-
API.UNIT.SENSORS_STATUS(unit.id),
|
|
37
|
-
{
|
|
38
|
-
params: params,
|
|
39
|
-
}
|
|
40
|
-
);
|
|
41
|
-
if (success) {
|
|
42
|
-
setSensorsStatus(data);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
const updateInterval = setInterval(getSensorsStatus, 5000);
|
|
47
|
-
intervalSensorStatus.current = updateInterval;
|
|
48
|
-
return () => clearInterval(updateInterval);
|
|
49
|
-
} else {
|
|
50
|
-
clearInterval(intervalSensorStatus.current);
|
|
51
|
-
}
|
|
52
|
-
}, [isFocused, favorites?.devices, unit.id]);
|
|
21
|
+
const { getStatus, serverDown } = useSensorsStatus(unit, favorites?.devices);
|
|
53
22
|
|
|
54
23
|
const handleOnAddNew = () => {
|
|
55
24
|
alert(t('feature_under_development'));
|
|
@@ -74,7 +43,7 @@ const SubUnitFavorites = ({
|
|
|
74
43
|
station={sensor.station}
|
|
75
44
|
isGGHomeConnected={isGGHomeConnected}
|
|
76
45
|
serverDown={serverDown}
|
|
77
|
-
status={
|
|
46
|
+
status={getStatus(sensor)}
|
|
78
47
|
wrapStyle={wrapItemStyle}
|
|
79
48
|
/>
|
|
80
49
|
))}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import { StyleSheet, View } from 'react-native';
|
|
3
|
-
import { useNavigation
|
|
3
|
+
import { useNavigation } from '@react-navigation/native';
|
|
4
4
|
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
5
|
+
import { useSensorsStatus } from '../../hooks/Common';
|
|
5
6
|
|
|
6
|
-
import { Images, Device
|
|
7
|
+
import { Images, Device } from '../../configs';
|
|
7
8
|
import { DEVICE_TYPE, TESTID } from '../../configs/Constants';
|
|
8
9
|
import { Section } from '../Section';
|
|
9
10
|
import Text from '../Text';
|
|
@@ -14,51 +15,16 @@ import { standardizeCameraScreenSize } from '../../utils/Utils';
|
|
|
14
15
|
import Routes from '../../utils/Route';
|
|
15
16
|
import FastImage from 'react-native-fast-image';
|
|
16
17
|
import MediaPlayerDetail from '../MediaPlayerDetail';
|
|
17
|
-
import { axiosGet } from '../../utils/Apis/axios';
|
|
18
18
|
|
|
19
19
|
const { standardizeWidth, standardizeHeight } = standardizeCameraScreenSize(
|
|
20
20
|
Device.screenWidth - 32
|
|
21
21
|
);
|
|
22
22
|
|
|
23
|
-
const ShortDetailSubUnit = ({
|
|
24
|
-
unit,
|
|
25
|
-
station,
|
|
26
|
-
serverDown,
|
|
27
|
-
isGGHomeConnected,
|
|
28
|
-
}) => {
|
|
23
|
+
const ShortDetailSubUnit = ({ unit, station, isGGHomeConnected }) => {
|
|
29
24
|
const t = useTranslations();
|
|
30
|
-
const isFocused = useIsFocused();
|
|
31
25
|
const { navigate } = useNavigation();
|
|
32
|
-
const intervalSensorStatus = useRef();
|
|
33
26
|
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
useEffect(() => {
|
|
37
|
-
if (isFocused) {
|
|
38
|
-
const getSensorsStatus = async () => {
|
|
39
|
-
const params = new URLSearchParams();
|
|
40
|
-
if (station?.sensors?.length > 0) {
|
|
41
|
-
station.sensors.forEach((sensor) => {
|
|
42
|
-
params.append('sensors', sensor.id);
|
|
43
|
-
});
|
|
44
|
-
const { success, data } = await axiosGet(
|
|
45
|
-
API.UNIT.SENSORS_STATUS(unit.id),
|
|
46
|
-
{
|
|
47
|
-
params: params,
|
|
48
|
-
}
|
|
49
|
-
);
|
|
50
|
-
if (success) {
|
|
51
|
-
setSensorsStatus(data);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
const updateInterval = setInterval(getSensorsStatus, 5000);
|
|
56
|
-
intervalSensorStatus.current = updateInterval;
|
|
57
|
-
return () => clearInterval(updateInterval);
|
|
58
|
-
} else {
|
|
59
|
-
clearInterval(intervalSensorStatus.current);
|
|
60
|
-
}
|
|
61
|
-
}, [isFocused, station?.sensors, unit.id]);
|
|
27
|
+
const { getStatus, serverDown } = useSensorsStatus(unit, station?.sensors);
|
|
62
28
|
|
|
63
29
|
const renderCamera = () => {
|
|
64
30
|
if (station?.camera) {
|
|
@@ -158,7 +124,7 @@ const ShortDetailSubUnit = ({
|
|
|
158
124
|
station={station}
|
|
159
125
|
isGGHomeConnected={isGGHomeConnected}
|
|
160
126
|
serverDown={serverDown}
|
|
161
|
-
status={
|
|
127
|
+
status={getStatus(sensor)}
|
|
162
128
|
/>
|
|
163
129
|
);
|
|
164
130
|
}
|
package/src/configs/Constants.js
CHANGED
|
@@ -74,6 +74,7 @@ export const Constants = {
|
|
|
74
74
|
export const DEVICE_TYPE = {
|
|
75
75
|
LG_THINQ: 'LG_THINQ',
|
|
76
76
|
HANET: 'HANET',
|
|
77
|
+
ZIGBEE: 'ZIGBEE',
|
|
77
78
|
};
|
|
78
79
|
|
|
79
80
|
const marginItem = 12;
|
|
@@ -393,6 +394,7 @@ export const TESTID = {
|
|
|
393
394
|
BUTTON_TEMPLATE_2: 'BUTTON_TEMPLATE_2',
|
|
394
395
|
BUTTON_TEMPLATE_3: 'BUTTON_TEMPLATE_3',
|
|
395
396
|
TEXT_DOOR_LOOK_ON_OFF: 'TEXT_DOOR_LOOK_ON_OFF',
|
|
397
|
+
BUTTON_ON_OFF: 'BUTTON_ON_OFF',
|
|
396
398
|
|
|
397
399
|
// Device Detail
|
|
398
400
|
DEVICE_DETAIL_MEDIA_PLAYER: 'DEVICE_DETAIL_MEDIA_PLAYER',
|
|
@@ -679,6 +681,9 @@ export const TESTID = {
|
|
|
679
681
|
GENERATE_PASSCODE_SET_TIME: 'GENERATE_PASSCODE_SET_TIME',
|
|
680
682
|
GENERATE_PASSCODE_SET_DURATION: 'GENERATE_PASSCODE_SET_DURATION',
|
|
681
683
|
|
|
684
|
+
//Passcode
|
|
685
|
+
PASSCODE_LIST: 'PASSCODE_LIST',
|
|
686
|
+
|
|
682
687
|
//AutoLock
|
|
683
688
|
AUTO_LOCK_BUTTON_ENABLE: 'AUTO_LOCK_BUTTON_ENABLE',
|
|
684
689
|
AUTO_LOCK_BUTTON_INSTANT: 'AUTO_LOCK_BUTTON_INSTANT',
|
|
@@ -4,6 +4,7 @@ import useForceUpdate from './useForceUpdate';
|
|
|
4
4
|
import useKeyboardShow from './useKeyboardShow';
|
|
5
5
|
import usePopover from './usePopover';
|
|
6
6
|
import useTitleHeader from './useTitleHeader';
|
|
7
|
+
import useSensorsStatus from './useSensorsStatus';
|
|
7
8
|
import { useBlockBackAndroid } from './useBlockBackAndroid';
|
|
8
9
|
import { useIsOwnerOfUnit } from './useIsOwnerOfUnit';
|
|
9
10
|
import { useStatusBar } from './useStatusBar';
|
|
@@ -20,4 +21,5 @@ export {
|
|
|
20
21
|
useIsOwnerOfUnit,
|
|
21
22
|
useStatusBar,
|
|
22
23
|
useGetIdUser,
|
|
24
|
+
useSensorsStatus,
|
|
23
25
|
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { useState, useEffect, useRef } from 'react';
|
|
2
|
+
import { useIsFocused } from '@react-navigation/native';
|
|
3
|
+
import { axiosGet } from '../../utils/Apis/axios';
|
|
4
|
+
import { API } from '../../configs';
|
|
5
|
+
|
|
6
|
+
const useSensorsStatus = (unit, sensors) => {
|
|
7
|
+
const isFocused = useIsFocused();
|
|
8
|
+
const intervalSensorStatus = useRef();
|
|
9
|
+
const [sensorsStatus, setSensorsStatus] = useState([]);
|
|
10
|
+
const [serverDown, setServerDown] = useState(false);
|
|
11
|
+
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (isFocused) {
|
|
14
|
+
const getSensorsStatus = async () => {
|
|
15
|
+
const params = new URLSearchParams();
|
|
16
|
+
if (sensors?.length > 0) {
|
|
17
|
+
sensors.forEach((sensor) => {
|
|
18
|
+
params.append('sensors', sensor.id);
|
|
19
|
+
});
|
|
20
|
+
const { success, data, resp_status } = await axiosGet(
|
|
21
|
+
API.UNIT.SENSORS_STATUS(unit.id),
|
|
22
|
+
{
|
|
23
|
+
params: params,
|
|
24
|
+
}
|
|
25
|
+
);
|
|
26
|
+
if (success) {
|
|
27
|
+
setSensorsStatus(data);
|
|
28
|
+
setServerDown(false);
|
|
29
|
+
} else if (resp_status >= 500) {
|
|
30
|
+
setServerDown(true);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
const updateInterval = setInterval(getSensorsStatus, 5000);
|
|
35
|
+
intervalSensorStatus.current = updateInterval;
|
|
36
|
+
return () => clearInterval(updateInterval);
|
|
37
|
+
} else {
|
|
38
|
+
clearInterval(intervalSensorStatus.current);
|
|
39
|
+
}
|
|
40
|
+
}, [isFocused, sensors, unit.id]);
|
|
41
|
+
|
|
42
|
+
const getStatus = (sensor) => {
|
|
43
|
+
sensorsStatus.find((s) => s.id === sensor.id);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
getStatus,
|
|
48
|
+
serverDown,
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export default useSensorsStatus;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { act, create } from 'react-test-renderer';
|
|
3
|
+
import axios from 'axios';
|
|
4
|
+
|
|
5
|
+
import AddNewGatewaySelectGateway from '../SelectGateway';
|
|
6
|
+
import { SCProvider } from '../../../context';
|
|
7
|
+
import { mockSCStore } from '../../../context/mockStore';
|
|
8
|
+
import { SafeAreaView } from 'react-native';
|
|
9
|
+
|
|
10
|
+
const wrapComponent = (route) => (
|
|
11
|
+
<SCProvider initState={mockSCStore({})}>
|
|
12
|
+
<AddNewGatewaySelectGateway route={route} />
|
|
13
|
+
</SCProvider>
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
jest.mock('axios');
|
|
17
|
+
|
|
18
|
+
jest.mock('react', () => {
|
|
19
|
+
return { ...jest.requireActual('react'), memo: (x) => x };
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const mockedNavigate = jest.fn();
|
|
23
|
+
const mockedGoBack = jest.fn();
|
|
24
|
+
|
|
25
|
+
jest.mock('@react-navigation/native', () => {
|
|
26
|
+
return {
|
|
27
|
+
...jest.requireActual('@react-navigation/native'),
|
|
28
|
+
useNavigation: () => ({
|
|
29
|
+
navigate: mockedNavigate,
|
|
30
|
+
goBack: mockedGoBack,
|
|
31
|
+
}),
|
|
32
|
+
useIsFocused: () => true,
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
describe('Test AddNewGatewaySelectGateway', () => {
|
|
37
|
+
let tree;
|
|
38
|
+
let route;
|
|
39
|
+
|
|
40
|
+
afterEach(() => {
|
|
41
|
+
axios.get.mockClear();
|
|
42
|
+
mockedNavigate.mockClear();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
beforeEach(() => {
|
|
46
|
+
route = {
|
|
47
|
+
params: {
|
|
48
|
+
unit_id: 1,
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test('create AddNewGatewaySelectGateway', async () => {
|
|
54
|
+
await act(async () => {
|
|
55
|
+
tree = await create(wrapComponent(route));
|
|
56
|
+
});
|
|
57
|
+
const instance = tree.root;
|
|
58
|
+
const safeAreaView = instance.findAllByType(SafeAreaView);
|
|
59
|
+
expect(safeAreaView).toHaveLength(1);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import renderer, { act } from 'react-test-renderer';
|
|
3
|
+
import { DetailHistoryChart } from '../components/DetailHistoryChart';
|
|
4
|
+
import { SCProvider } from '../../../context';
|
|
5
|
+
import { mockSCStore } from '../../../context/mockStore';
|
|
6
|
+
import HistoryChart from '../../../commons/Device/HistoryChart';
|
|
7
|
+
const mockSetState = jest.fn();
|
|
8
|
+
jest.mock('react', () => {
|
|
9
|
+
return {
|
|
10
|
+
...jest.requireActual('react'),
|
|
11
|
+
memo: (x) => x,
|
|
12
|
+
useState: jest.fn((init) => [init, mockSetState]),
|
|
13
|
+
};
|
|
14
|
+
});
|
|
15
|
+
const wrapComponent = (item, sensor) => (
|
|
16
|
+
<SCProvider initState={mockSCStore({})}>
|
|
17
|
+
<DetailHistoryChart item={item} sensor={sensor} />
|
|
18
|
+
</SCProvider>
|
|
19
|
+
);
|
|
20
|
+
describe('Test DetailHistoryChart', () => {
|
|
21
|
+
let tree;
|
|
22
|
+
test('create DetailHistoryChart', () => {
|
|
23
|
+
const item = {
|
|
24
|
+
configuration: {
|
|
25
|
+
configs: [0],
|
|
26
|
+
icon: 'slack',
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
const sensor = {
|
|
30
|
+
name: 'Sensor name',
|
|
31
|
+
is_managed_by_backend: false,
|
|
32
|
+
};
|
|
33
|
+
act(() => {
|
|
34
|
+
tree = renderer.create(wrapComponent(item, sensor));
|
|
35
|
+
});
|
|
36
|
+
const instance = tree.root;
|
|
37
|
+
const historyChart = instance.findAllByType(HistoryChart);
|
|
38
|
+
expect(historyChart).toHaveLength(1);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -8,7 +8,6 @@ import React, {
|
|
|
8
8
|
import { View, TouchableOpacity } from 'react-native';
|
|
9
9
|
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
10
10
|
import moment from 'moment';
|
|
11
|
-
import _ from 'lodash';
|
|
12
11
|
import { get } from 'lodash';
|
|
13
12
|
import { useSelector } from 'react-redux';
|
|
14
13
|
import { IconFill, IconOutline } from '@ant-design/icons-react-native';
|
|
@@ -463,10 +462,14 @@ const DeviceDetail = ({ route }) => {
|
|
|
463
462
|
setDisplayValues((currentDisplayValues) => {
|
|
464
463
|
for (const [configId, value] of Object.entries(configValues)) {
|
|
465
464
|
const intId = parseInt(configId);
|
|
466
|
-
const index =
|
|
465
|
+
const index = currentDisplayValues.findIndex(
|
|
466
|
+
(element) => element.id === intId
|
|
467
|
+
);
|
|
468
|
+
|
|
469
|
+
const item = currentDisplayValues[index];
|
|
467
470
|
if (index !== -1) {
|
|
468
471
|
currentDisplayValues[index].value = value;
|
|
469
|
-
currentDisplayValues[index].evaluate =
|
|
472
|
+
currentDisplayValues[index].evaluate = item.evaluate;
|
|
470
473
|
} else {
|
|
471
474
|
currentDisplayValues.push({
|
|
472
475
|
id: intId,
|
|
@@ -496,7 +499,19 @@ const DeviceDetail = ({ route }) => {
|
|
|
496
499
|
params: { unitId: unit?.id, group },
|
|
497
500
|
});
|
|
498
501
|
}, [navigation, unit?.group, unit?.id]);
|
|
499
|
-
|
|
502
|
+
const isHaveColorSliderTemplate = useMemo(() => {
|
|
503
|
+
let isFlag = false;
|
|
504
|
+
display?.items.some((item) => {
|
|
505
|
+
switch (item?.configuration?.template) {
|
|
506
|
+
case 'color_picker_template':
|
|
507
|
+
case 'slider_range_template':
|
|
508
|
+
return (isFlag = true);
|
|
509
|
+
default:
|
|
510
|
+
return (isFlag = false);
|
|
511
|
+
}
|
|
512
|
+
});
|
|
513
|
+
return isFlag;
|
|
514
|
+
}, [display]);
|
|
500
515
|
// replace isConnected=True to see template
|
|
501
516
|
const renderSensorConnected = () => {
|
|
502
517
|
return (
|
|
@@ -536,31 +551,33 @@ const DeviceDetail = ({ route }) => {
|
|
|
536
551
|
);
|
|
537
552
|
}
|
|
538
553
|
})}
|
|
539
|
-
|
|
540
|
-
{
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
554
|
+
{!!isHaveColorSliderTemplate && (
|
|
555
|
+
<Card title={t('controller')}>
|
|
556
|
+
{display.items.map((item) => {
|
|
557
|
+
switch (item?.configuration?.template) {
|
|
558
|
+
case 'color_picker_template':
|
|
559
|
+
case 'slider_range_template':
|
|
560
|
+
return (
|
|
561
|
+
<SensorDisplayItem
|
|
562
|
+
testID={TESTID.SENSOR_DISPLAY_ITEM}
|
|
563
|
+
key={item.id.toString()}
|
|
564
|
+
item={item}
|
|
565
|
+
emergency={onEmergencyButtonPress}
|
|
566
|
+
sensor={sensor}
|
|
567
|
+
getData={getData}
|
|
568
|
+
maxValue={maxValue}
|
|
569
|
+
offsetTitle={offsetTitle}
|
|
570
|
+
setOffsetTitle={setOffsetTitle}
|
|
571
|
+
setShowWindDirection={setShowWindDirection}
|
|
572
|
+
background={station?.background}
|
|
573
|
+
/>
|
|
574
|
+
);
|
|
575
|
+
default:
|
|
576
|
+
return <></>;
|
|
577
|
+
}
|
|
578
|
+
})}
|
|
579
|
+
</Card>
|
|
580
|
+
)}
|
|
564
581
|
</SensorConnectStatusViewHeader>
|
|
565
582
|
);
|
|
566
583
|
};
|
|
@@ -81,13 +81,18 @@ const HanetCameraDetail = ({ route }) => {
|
|
|
81
81
|
|
|
82
82
|
const CheckInItem = useCallback(
|
|
83
83
|
({ item }) => {
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
84
|
+
const textMaskMapping = {
|
|
85
|
+
MASK_OFF: t('mask_off'),
|
|
86
|
+
MASK_ON: t('mask_on'),
|
|
87
|
+
};
|
|
88
|
+
const textNameMapping = {
|
|
89
|
+
STRANGER: t('stranger'),
|
|
90
|
+
IMAGE_FROM_CAMERA: t('image_from_camera'),
|
|
91
|
+
};
|
|
92
|
+
const textMask = textMaskMapping[item.detected_mask] || '';
|
|
93
|
+
const textName = textNameMapping[item.person_type] || item.person_name;
|
|
94
|
+
const isStranger = !['EMPLOYEE', 'CUSTOMER'].includes(item.person_type);
|
|
95
|
+
|
|
91
96
|
return (
|
|
92
97
|
<View style={styles.wrapItem}>
|
|
93
98
|
<Text type="Body" color={Colors.Gray7} style={styles.timeCheckIn}>
|
|
@@ -103,13 +108,15 @@ const HanetCameraDetail = ({ route }) => {
|
|
|
103
108
|
</View>
|
|
104
109
|
<View style={styles.wrapItemInfo}>
|
|
105
110
|
<Text type="Body" color={isStranger ? Colors.Red6 : Colors.Gray9}>
|
|
106
|
-
{
|
|
111
|
+
{textName}
|
|
107
112
|
</Text>
|
|
108
|
-
|
|
109
|
-
<
|
|
110
|
-
{
|
|
111
|
-
|
|
112
|
-
|
|
113
|
+
{!!textMask && (
|
|
114
|
+
<View style={styles.itemDescription}>
|
|
115
|
+
<Text type="Label" color={Colors.Gray7}>
|
|
116
|
+
{textMask}
|
|
117
|
+
</Text>
|
|
118
|
+
</View>
|
|
119
|
+
)}
|
|
113
120
|
</View>
|
|
114
121
|
<View style={styles.wrapAvatar}>
|
|
115
122
|
<Image
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import React, { useCallback, useMemo } from 'react';
|
|
2
2
|
import { View, TouchableOpacity, Image, FlatList } from 'react-native';
|
|
3
3
|
import { useNavigation } from '@react-navigation/native';
|
|
4
|
-
import ImagePicker from 'react-native-image-crop-picker';
|
|
5
4
|
import { Icon } from '@ant-design/react-native';
|
|
6
|
-
import { IconOutline
|
|
5
|
+
import { IconOutline } from '@ant-design/icons-react-native';
|
|
7
6
|
import { HeaderCustom } from '../../commons/Header';
|
|
8
|
-
import BottomSheet from '../../commons/BottomSheet';
|
|
9
7
|
import Text from '../../commons/Text';
|
|
8
|
+
import RequestFaceIDPopup from './components/RequestFaceIDPopup';
|
|
10
9
|
import styles from './styles/manageAccessStyles';
|
|
11
10
|
import { useTranslations } from '../../hooks/Common/useTranslations';
|
|
12
11
|
import { useHanetPlaceMembers } from './hooks';
|
|
@@ -14,7 +13,6 @@ import { useBoolean } from '../../hooks/Common';
|
|
|
14
13
|
import { Colors } from '../../configs';
|
|
15
14
|
import { TESTID } from '../../configs/Constants';
|
|
16
15
|
import Routes from '../../utils/Route';
|
|
17
|
-
import SmartPhoneSvg from '../../../assets/images/Common/SmartPhone.svg';
|
|
18
16
|
|
|
19
17
|
const HanetManageAccess = ({ route }) => {
|
|
20
18
|
const t = useTranslations();
|
|
@@ -40,7 +38,7 @@ const HanetManageAccess = ({ route }) => {
|
|
|
40
38
|
const [showAddMemberModal, setShowAddMemberModal, setHideAddMemberModal] =
|
|
41
39
|
useBoolean();
|
|
42
40
|
|
|
43
|
-
const
|
|
41
|
+
const onCaptureFaceID = () => {
|
|
44
42
|
navigate(Routes.HanetCaptureFaceID, {
|
|
45
43
|
title: t('add_new_member'),
|
|
46
44
|
hanetPlace: hanetPlace,
|
|
@@ -52,15 +50,7 @@ const HanetManageAccess = ({ route }) => {
|
|
|
52
50
|
});
|
|
53
51
|
};
|
|
54
52
|
|
|
55
|
-
const
|
|
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);
|
|
53
|
+
const onChooseFile = (result) => {
|
|
64
54
|
navigate(Routes.HanetMemberInfo, {
|
|
65
55
|
hanetPlace: hanetPlace,
|
|
66
56
|
hanetMember: {
|
|
@@ -72,25 +62,6 @@ const HanetManageAccess = ({ route }) => {
|
|
|
72
62
|
});
|
|
73
63
|
};
|
|
74
64
|
|
|
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
65
|
const MemberItem = useCallback(
|
|
95
66
|
({ item }) => {
|
|
96
67
|
return (
|
|
@@ -146,26 +117,13 @@ const HanetManageAccess = ({ route }) => {
|
|
|
146
117
|
contentContainerStyle={styles.contentContainerStyle}
|
|
147
118
|
scrollIndicatorInsets={{ right: 1 }}
|
|
148
119
|
/>
|
|
149
|
-
<
|
|
150
|
-
isVisible={showAddMemberModal}
|
|
151
|
-
onBackdropPress={setHideAddMemberModal}
|
|
120
|
+
<RequestFaceIDPopup
|
|
152
121
|
title={t('add_member')}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
{
|
|
156
|
-
|
|
157
|
-
|
|
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>
|
|
122
|
+
isVisible={showAddMemberModal}
|
|
123
|
+
setHide={setHideAddMemberModal}
|
|
124
|
+
onCaptureFaceID={onCaptureFaceID}
|
|
125
|
+
onChooseFile={onChooseFile}
|
|
126
|
+
/>
|
|
169
127
|
</View>
|
|
170
128
|
);
|
|
171
129
|
};
|