UNPKG

onfido-sdk-ui

Version:

JavaScript SDK view layer for Onfido identity verification

173 lines (152 loc) 5.17 kB
// @flow import * as React from 'react' import { h, Component } from 'preact' import type { ChallengeType, ChallengeResultType } from './Challenge' import Camera from '../Camera' import CameraError from '../CameraError' import Title from '../Title' import { ToggleFullScreen } from '../FullScreen' import { FaceOverlay } from '../Overlay' import { currentMilliseconds } from '../utils' import { getRecordedVideo } from '../utils/camera' import { sendScreen } from '../../Tracker' import Recording from './Recording' import NotRecording from './NotRecording' import withChallenges from './withChallenges' import { localised } from '../../locales' import type { LocalisedType } from '../../locales' type Props = { challenges: ChallengeType[], challengesId: any, onRedo: void => void, onVideoCapture: ({ blob: ?Blob, challengeData: ?ChallengeResultType }) => void, onSwitchChallenge: void => void, renderFallback: Function, trackScreen: Function, inactiveError: Object } & LocalisedType type State = { currentIndex: number, isRecording: boolean, hasMediaStream: boolean, hasBecomeInactive: boolean, hasRecordingTakenTooLong: boolean, startedAt: number, switchSeconds?: number, } const initialState = { startedAt: undefined, switchSeconds: undefined, currentIndex: 0, isRecording: false, hasMediaStream: false, hasBecomeInactive: false, hasRecordingTakenTooLong: false, } const recordingTooLongError = { name: 'LIVENESS_TIMEOUT', type: 'warning' } class Video extends Component<Props, State> { webcam = null state: State = { ...initialState } componentWillReceiveProps(nextProps: Props) { if (nextProps.challenges !== this.props.challenges) { this.setState({ ...initialState }) } } startRecording = () => { this.webcam && this.webcam.startRecording() this.setState({isRecording: true, hasBecomeInactive: false}) } stopRecording = () => { this.webcam && this.webcam.stopRecording() this.setState({isRecording: false}) } handleRecordingStart = () => { if (this.state.hasMediaStream) { this.startRecording() this.setState({ startedAt: currentMilliseconds() }) sendScreen(['face_video_capture_step_1']) } } handleRecordingStop = () => { const { switchSeconds, hasRecordingTakenTooLong } = this.state const { challenges, challengesId: id } = this.props const challengeData = { challenges, id, switchSeconds } this.stopRecording() if (this.webcam && !hasRecordingTakenTooLong) { getRecordedVideo(this.webcam, (data) => this.props.onVideoCapture({...data, challengeData})) } } handleNextChallenge = () => { const { startedAt, currentIndex } = this.state this.setState({ currentIndex: currentIndex + 1 }) if (startedAt) { this.setState({ switchSeconds: currentMilliseconds() - startedAt }) sendScreen(['face_video_capture_step_2']) } } handleMediaStream = () => { this.setState({ hasMediaStream: true }) } handleInactivityTimeout = () => { this.setState({ hasBecomeInactive: true }) } handleRecordingTimeout = () => { this.setState({ hasRecordingTakenTooLong: true }) this.stopRecording() } redoActionsFallback = (text: string) => <span onClick={this.props.onRedo}>{text}</span> renderError = () => { const { trackScreen, renderFallback, inactiveError } = this.props return ( <CameraError {...{ trackScreen }} {...(this.state.hasRecordingTakenTooLong ? { error: recordingTooLongError, renderFallback: this.redoActionsFallback, hasBackdrop: true, } : { error: inactiveError, isDismissible: true, renderFallback, }) } /> ) } render = () => { const { translate, challenges = [] } = this.props const { isRecording, currentIndex, hasBecomeInactive, hasRecordingTakenTooLong } = this.state const currentChallenge = challenges[currentIndex] || {} const isLastChallenge = currentIndex === challenges.length - 1 const hasError = hasBecomeInactive || hasRecordingTakenTooLong return ( <div> <Camera {...this.props} webcamRef={ c => this.webcam = c } onUserMedia={ this.handleMediaStream } renderTitle={ !isRecording && <Title title={translate('capture.liveness.challenges.position_face')} />} {...(hasError ? { renderError: this.renderError() } : {}) } video > <ToggleFullScreen /> <FaceOverlay isWithoutHole={ hasError || isRecording } /> { isRecording ? <Recording {...{currentChallenge, isLastChallenge, hasError}} onNext={this.handleNextChallenge} onStop={this.handleRecordingStop} onTimeout={this.handleRecordingTimeout} /> : <NotRecording {...{hasError}} onStart={this.handleRecordingStart} onTimeout={this.handleInactivityTimeout} /> } </Camera> </div> ) } } export default localised(withChallenges(Video))