UNPKG

viettel-ekyc-sdk

Version:
269 lines 12.7 kB
/* eslint-disable react-hooks/exhaustive-deps */ import React, { useCallback, useEffect, useState } from 'react'; import { Image, StyleSheet, TouchableOpacity, View } from 'react-native'; import { RNCamera } from 'react-native-camera'; import { useCamera } from 'react-native-camera-hooks'; import { ActionFaceFrame } from '../components/actionFrame'; import { BackgroundFrontCamera } from '../components/BackgroundCamera'; import { Loadding } from '../components/Loadding'; import { RequireFrame } from '../components/RequireFrame'; import { WarningFaceFrame } from '../components/WarningFrame'; import { SUCCESS } from '../constants/api'; import { circleCameraBg, toggleCameraImage } from '../constants/assetsRequire'; import { getCircleInitPosition, requireFaceActionListConstant, requireFrameListConstant, } from '../constants/camera'; import { stylesCamera } from '../constants/style'; import { checkFaceSanityPost, checkLivenessPost } from '../utils/api'; import { getBase64FromUri } from '../utils/utils'; const circleCameraPosition = getCircleInitPosition(circleCameraBg, { x: 100, y: 155, r: 265, }); const Sound = require('react-native-sound'); Sound.setCategory('Playback'); export const FaceComponent = ({ initialCamera, faceLivenessConfiguration, afterTakePictureAction, warningFrame, loadingComponent, enableFaceDetect, enableCheckSanity, enableCheckTempering, }) => { const [{ cameraRef, type, ratio, autoFocus, autoFocusPoint }, { toggleFacing, takePicture },] = useCamera(initialCamera); const initFaceImages = []; const [selectedIndex, setSelectedIndex] = useState(0); const [faceImages, setFaceImages] = useState(initFaceImages); let initRequireFrameList = []; const [requireFrameList, setRequireFrameList] = useState(initRequireFrameList); // const [enableFD, setEnableFD] = useState( // enableFaceDetect !== undefined ? enableFaceDetect : true // ) let enableFD = enableFaceDetect !== undefined ? enableFaceDetect : true; const [errorMessage, setErrorMessage] = useState(''); let [isLoading, setIsLoading] = useState(false); /** * Get require item list match with require from props * @returns RequireItem|undefined [] */ const getRequireFrameList = useCallback(() => { if (faceLivenessConfiguration) { return faceLivenessConfiguration.requireList.map((item) => { return requireFrameListConstant.find((requireItem) => requireItem.action === item.toLowerCase().trim()); }); } return []; }, [faceLivenessConfiguration]); /** * Get require frame list match with require from props * Set sound with first require list */ useEffect(() => { var _a; const requireFrames = getRequireFrameList(); if (requireFrames.length > 0) { setRequireFrameList(requireFrames); let whoosh = new Sound((_a = requireFrames[0]) === null || _a === void 0 ? void 0 : _a.sound, (error) => { if (!error) { whoosh.play(() => { }); } else { console.log('Error sound'); } }); } }, [getRequireFrameList]); /** * Promise after get all image match require list */ useEffect(() => { if ((faceLivenessConfiguration && faceImages.length === requireFrameList.length && requireFrameList.length > 0) || (!faceLivenessConfiguration && faceImages.length === 1)) { enableFD = false; setIsLoading(true); afterTakePictureAction({ images: faceImages, errorMessage: errorMessage }); setIsLoading(false); } }, [faceLivenessConfiguration, faceImages, requireFrameList.length]); /** * Sound when next require */ useEffect(() => { var _a; if (selectedIndex < requireFrameList.length) { let whoosh = new Sound((_a = requireFrameList[selectedIndex]) === null || _a === void 0 ? void 0 : _a.sound, (error) => { if (!error) { whoosh.play(() => { }); } }); } }, [requireFrameList, selectedIndex]); const processImage = async (imageUri) => { var _a, _b, _c, _d, _e, _f, _g, _h; const imageUriBase64 = await getBase64FromUri(imageUri); let message = ''; if (enableCheckTempering && enableCheckSanity) { const [livenessResponse, sanityResponse] = await Promise.all([ checkLivenessPost(imageUriBase64), checkFaceSanityPost(imageUriBase64), ]); if (((_a = sanityResponse.data) === null || _a === void 0 ? void 0 : _a.code) !== SUCCESS) { message = ((_b = sanityResponse.data) === null || _b === void 0 ? void 0 : _b.message) || ''; } else { message = ''; if (((_c = livenessResponse.data) === null || _c === void 0 ? void 0 : _c.code) === SUCCESS && ((_d = livenessResponse.data) === null || _d === void 0 ? void 0 : _d.verify_result)) { setFaceImages([...faceImages, imageUri]); if (faceLivenessConfiguration !== undefined) { setSelectedIndex(selectedIndex + 1); } } } } else if (enableCheckSanity) { const sanityResponse = await checkFaceSanityPost(imageUriBase64); if (((_e = sanityResponse.data) === null || _e === void 0 ? void 0 : _e.code) !== SUCCESS) { message = ((_f = sanityResponse.data) === null || _f === void 0 ? void 0 : _f.message) || ''; } else { message = ''; setFaceImages([...faceImages, imageUri]); if (faceLivenessConfiguration !== undefined) { setSelectedIndex(selectedIndex + 1); } } } else if (enableCheckTempering) { const livenessResponse = await checkLivenessPost(imageUriBase64); if (((_g = livenessResponse.data) === null || _g === void 0 ? void 0 : _g.code) === SUCCESS && ((_h = livenessResponse.data) === null || _h === void 0 ? void 0 : _h.verify_result)) { message = ''; setFaceImages([...faceImages, imageUri]); if (faceLivenessConfiguration !== undefined) { setSelectedIndex(selectedIndex + 1); } } else { message = 'Không phải ảnh selfie hoặc không có khuôn mặt'; } } else { setFaceImages([...faceImages, imageUri]); if (faceLivenessConfiguration !== undefined) { setSelectedIndex(selectedIndex + 1); } } if (!faceLivenessConfiguration && message !== '') { afterTakePictureAction({ images: faceImages, errorMessage: message, }); } }; /** * When detected face, if match with require and config => add to faceImages * @param faceArray : Array * @returns */ const onFacesDetected = async (faceArray) => { var _a; if (faceArray.length > 0) { const face = faceArray[0]; if (faceLivenessConfiguration && face.bottomMouthPosition && (face.rightEyePosition || face.leftEyePosition)) { let yawAngle = requireFaceActionListConstant.portrait; let pitchAngle = requireFaceActionListConstant.portrait; let status; if (face.yawAngle !== undefined) { if (face.yawAngle >= faceLivenessConfiguration.yawAngle) { yawAngle = requireFaceActionListConstant.right; } else if (face.yawAngle <= -faceLivenessConfiguration.yawAngle) { yawAngle = requireFaceActionListConstant.left; } } if (face.inclinationAngle !== undefined) { if (face.inclinationAngle >= faceLivenessConfiguration.pitchAngle) { pitchAngle = requireFaceActionListConstant.down; } else if (face.inclinationAngle <= -faceLivenessConfiguration.pitchAngle) { pitchAngle = requireFaceActionListConstant.up; } } if (face.smilingProbability !== undefined && face.smilingProbability >= faceLivenessConfiguration.smilingProbability) { status = requireFaceActionListConstant.smile; } else if (pitchAngle === requireFaceActionListConstant.portrait) { status = yawAngle; } else if (yawAngle === requireFaceActionListConstant.portrait) { status = pitchAngle; } console.log('status: ', status); if (status !== undefined && ((_a = requireFrameList[selectedIndex]) === null || _a === void 0 ? void 0 : _a.action) === status) { const picture = await takePicture(); if (picture === null || picture === void 0 ? void 0 : picture.uri) { await processImage(picture === null || picture === void 0 ? void 0 : picture.uri); } } } } }; const onCapture = async () => { setIsLoading(true); const picture = await takePicture(); await processImage(picture === null || picture === void 0 ? void 0 : picture.uri); setIsLoading(false); }; return (React.createElement(View, { style: styles.container }, React.createElement(BackgroundFrontCamera, null), React.createElement(View, { style: styles.cameraPreview }, React.createElement(RNCamera, { ref: cameraRef, autoFocusPointOfInterest: autoFocusPoint.normalized, type: type, ratio: ratio, style: styles.cameraMain, captureAudio: false, autoFocus: autoFocus === 1 || autoFocus === 'on' ? 'on' : 'off', faceDetectionMode: RNCamera.Constants.FaceDetection.Mode.fast, faceDetectionClassifications: RNCamera.Constants.FaceDetection.Classifications.all, faceDetectionLandmarks: RNCamera.Constants.FaceDetection.Landmarks.all, onFacesDetected: async (faceArray) => { if (enableFD) { enableFD = false; await onFacesDetected(faceArray.faces); if (selectedIndex < requireFrameList.length) { enableFD = true; } } } })), React.createElement(View, { style: stylesCamera.mainContainer }, React.createElement(View, { style: stylesCamera.warningAndActionContainer }, warningFrame || React.createElement(WarningFaceFrame, null), faceLivenessConfiguration ? (React.createElement(RequireFrame, { requireList: requireFrameList, selectedIndex: selectedIndex })) : (React.createElement(ActionFaceFrame, { capture: async () => { await onCapture(); } })))), React.createElement(TouchableOpacity, { testID: 'button', onPress: toggleFacing, style: styles.toggleFacing }, React.createElement(Image, { source: toggleCameraImage, style: styles.toggleCameraImage, resizeMode: 'contain' })), isLoading ? (loadingComponent !== undefined ? (loadingComponent()) : (React.createElement(Loadding, null))) : (React.createElement(View, null)))); }; const styles = StyleSheet.create({ container: { flex: 1, position: 'relative', }, cameraPreview: { height: circleCameraPosition.r * 2, width: circleCameraPosition.r * 2, position: 'absolute', top: circleCameraPosition.y, left: circleCameraPosition.x, right: circleCameraPosition.x, overflow: 'hidden', borderRadius: circleCameraPosition.r, zIndex: 10, }, cameraMain: { height: circleCameraPosition.r * 2, width: circleCameraPosition.r * 2, }, toggleFacing: { width: 50, height: 50, position: 'absolute', top: 30, right: 20, zIndex: 10, }, toggleCameraImage: { width: 50, height: 50 }, }); //# sourceMappingURL=FaceComponent.js.map