Skip to content

Commit

Permalink
add: improve error display (#281)
Browse files Browse the repository at this point in the history
* add: improve error display

* add: FR events

* add: FR events
  • Loading branch information
sirpy authored Jul 23, 2019
1 parent b71d667 commit f1fddc3
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 24 deletions.
2 changes: 1 addition & 1 deletion src/components/dashboard/FaceRecognition/FRError.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const FRError = props => {
}

const gotoFR = () => {
props.screenProps.navigateTo('FaceVerification')
props.screenProps.navigateTo('FaceVerification', { showHelper: false })
}

log.debug(props.screenProps)
Expand Down
3 changes: 3 additions & 0 deletions src/components/dashboard/FaceRecognition/FRIntro.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { CustomButton, Section, Wrapper } from '../../common'
import Divider from '../../../assets/Dividers - Long Line - Stroke Width 2 - Round Cap - Light Blue.svg'
import SmileyHug from '../../../assets/smileyhug.svg'
import GDStore from '../../../lib/undux/GDStore'
import { fireEvent } from '../../../lib/analytics/analytics'

import logger from '../../../lib/logger/pino-logger'

Expand All @@ -24,6 +25,8 @@ const FRIntro = props => {
}
if (isValid) {
props.screenProps.pop({ isValid: true })
} else {
fireEvent('FR_Intro')
}
const gotoPrivacyArticle = () => props.screenProps.push('PP')
const gotoFR = () => props.screenProps.navigateTo('FaceVerification')
Expand Down
25 changes: 19 additions & 6 deletions src/components/dashboard/FaceRecognition/FaceRecognition.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { DashboardProps } from '../Dashboard'
import logger from '../../../lib/logger/pino-logger'
import { Wrapper } from '../../common'
import userStorage from '../../../lib/gundb/UserStorage'
import { fireEvent } from '../../../lib/analytics/analytics'
import FRapi from './FaceRecognitionAPI'
import type FaceRecognitionResponse from './FaceRecognitionAPI'
import GuidedFR from './GuidedFRProcessResults'
Expand All @@ -27,6 +28,7 @@ type State = {
zoomReady: boolean,
captureResult: ZoomCaptureResult,
isWhitelisted: boolean | void,
showHelper: boolean,
}

/**
Expand All @@ -47,6 +49,7 @@ class FaceRecognition extends React.Component<FaceRecognitionProps, State> {
zoomReady: false,
captureResult: {},
isWhitelisted: undefined,
showHelper: get(this.props, 'screenProps.screenState.showHelper', true),
}

loadedZoom: any
Expand Down Expand Up @@ -88,6 +91,7 @@ class FaceRecognition extends React.Component<FaceRecognitionProps, State> {
onCaptureResult = (captureResult?: ZoomCaptureResult): void => {
//TODO: rami check uninitilized, return
log.debug('zoom capture completed', { captureResult })
fireEvent('FR_Capture')
if (captureResult === undefined) {
log.error('empty capture result')
this.showFRError('empty capture result')
Expand All @@ -110,9 +114,9 @@ class FaceRecognition extends React.Component<FaceRecognitionProps, State> {
log.error('FR API call failed:', { result })
this.showFRError(result.error) // TODO: rami
} else if (get(result, 'enrollResult.enrollmentIdentifier', undefined)) {
this.setState({ ...this.state, isWhitelisted: true })
this.setState({ ...this.state, isAPISuccess: true })
} else {
this.setState({ ...this.state, isWhitelisted: false })
this.setState({ ...this.state, isAPISuccess: false })
}
} catch (e) {
log.error('FR API call failed:', e, e.message)
Expand All @@ -121,22 +125,30 @@ class FaceRecognition extends React.Component<FaceRecognitionProps, State> {
}

showFRError = (error: string | Error) => {
fireEvent('FR_Error')
this.setState({ showZoomCapture: false, showGuidedFR: false, sessionId: undefined }, () => {
this.props.screenProps.navigateTo('FRError', { error })
})
}

retry = () => {
this.setState({ showGuidedFR: false, sessionId: undefined, showZoomCapture: true })
fireEvent('FR_Retry')
this.setState({
showGuidedFR: false,
sessionId: undefined,
showZoomCapture: true,
isAPISuccess: undefined,
showHelper: false,
})
}

done = () => {
fireEvent('FR_Success')
this.props.screenProps.pop({ isValid: true })
}

render() {
const { showZoomCapture, showGuidedFR, sessionId, isWhitelisted } = this.state
log.debug('Render:', { showZoomCapture })
const { showZoomCapture, showGuidedFR, sessionId, isAPISuccess } = this.state
return (
<Wrapper>
{showGuidedFR && (
Expand All @@ -146,7 +158,7 @@ class FaceRecognition extends React.Component<FaceRecognitionProps, State> {
retry={this.retry}
done={this.done}
navigation={this.props.screenProps}
isWhitelisted={isWhitelisted}
isAPISuccess={isAPISuccess}
/>
)}

Expand All @@ -157,6 +169,7 @@ class FaceRecognition extends React.Component<FaceRecognitionProps, State> {
showZoomCapture={this.state.zoomReady && showZoomCapture}
loadedZoom={this.loadedZoom}
onError={this.showFRError}
showHelper={this.state.showHelper}
/>
)}
</Wrapper>
Expand Down
52 changes: 37 additions & 15 deletions src/components/dashboard/FaceRecognition/GuidedFRProcessResults.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { ActivityIndicator, Image, StyleSheet, View } from 'react-native'
import { Text } from 'react-native-paper'
import normalize from 'react-native-elements/src/helpers/normalizeText'
import find from 'lodash/find'
import findKey from 'lodash/findKey'
import mapValues from 'lodash/mapValues'
import { CustomButton, Section } from '../../common'
import logger from '../../../lib/logger/pino-logger'
import goodWallet from '../../../lib/wallet/GoodWallet'
Expand All @@ -13,6 +15,7 @@ import Check from '../../../assets/Icons - Success - White.svg'
import Cross from '../../../assets/Icons - Close X - White.svg'
import LookingGood from '../../../assets/LookingGood.svg'
import GDStore from '../../../lib/undux/GDStore'
import { fireEvent } from '../../../lib/analytics/analytics'

const log = logger.child({ from: 'GuidedFRProcessResults' })

Expand All @@ -38,7 +41,7 @@ const FRStep = ({ title, isActive, status, isProcessFailed, paddingBottom }) =>
</View>
)
}
const GuidedFRProcessResults = ({ profileSaved, sessionId, retry, done, navigation, isWhitelisted }: any) => {
const GuidedFRProcessResults = ({ profileSaved, sessionId, retry, done, navigation, isAPISuccess }: any) => {
const store = GDStore.useStore()
const { fullName } = store.get('profile')

Expand All @@ -48,12 +51,17 @@ const GuidedFRProcessResults = ({ profileSaved, sessionId, retry, done, navigati
isEnrolled: undefined,
isLive: undefined,
isWhitelisted: undefined,
isProfileSaved: undefined,
})

const updateProgress = data => {
log.debug('updating progress', { data })

// let explanation = ''
let failedFR = findKey(data, (v, k) => v === false)
if (failedFR) {
fireEvent(`FR_Failed`, { failedFR })
}
setStatus({ ...processStatus, ...data })

// log.debug('analyzed data,', { processStatus })
Expand All @@ -80,7 +88,7 @@ const GuidedFRProcessResults = ({ profileSaved, sessionId, retry, done, navigati

// let [showDialogWithData] = useDialog()
let gun = userStorage.gun
log.debug({ sessionId, isWhitelisted })
log.debug({ sessionId, isAPISuccess })

useEffect(() => {
log.debug('subscriping to gun updates:', { sessionId })
Expand Down Expand Up @@ -112,22 +120,27 @@ const GuidedFRProcessResults = ({ profileSaved, sessionId, retry, done, navigati
const gotoSupport = () => {
navigation.push('Support')
}

useEffect(() => {
//done save profile and call done callback
if (processStatus.isWhitelisted) {
saveProfileAndDone()
}
}, [processStatus.isWhitelisted])

//API call finished, so it will pass isWhitelisted to us
//this is a backup incase the gundb messaging doesnt work
const gunOK = find(processStatus, (v, k) => v !== undefined)
if (gunOK === undefined && isWhitelisted) {
processStatus.isWhitelisted = true
saveProfileAndDone()
} else if (gunOK === undefined && isWhitelisted === false) {
processStatus.isWhitelisted = false
}
useEffect(() => {
if (isAPISuccess === undefined) {
return
}

//API call finished, so it will pass isWhitelisted to us
//this is a backup incase the gundb messaging doesnt work
const gunOK = find(processStatus, (v, k) => v !== undefined)
if (gunOK === undefined) {
const newStatus = mapValues(processStatus, v => false)
setStatus({ ...newStatus, isWhitelisted: isAPISuccess, useAPIResult: true })
}
}, [isAPISuccess])

const isProcessFailed =
processStatus.isNotDuplicate === false ||
Expand Down Expand Up @@ -156,7 +169,9 @@ const GuidedFRProcessResults = ({ profileSaved, sessionId, retry, done, navigati
) : null

let helpText
if (processStatus.isNotDuplicate === false) {
if (processStatus.useAPIResult && isAPISuccess === false) {
helpText = 'Something went wrong, please try again...'
} else if (processStatus.isNotDuplicate === false) {
helpText = (
<View>
<Text style={styles.textHelp}>
Expand All @@ -182,7 +197,7 @@ const GuidedFRProcessResults = ({ profileSaved, sessionId, retry, done, navigati
helpText =
'We could not verify you are a living person. Funny hu? please make sure:\n\n\
A. Center your webcam\n\
B. Ensure camera is at eye level\n\
B. Camera is at eye level\n\
C. Light your face evenly'
} else if (isProcessFailed) {
helpText = 'Something went wrong, please try again...'
Expand Down Expand Up @@ -223,6 +238,7 @@ C. Light your face evenly'
<FRStep
title={'Checking liveness'}
isActive={
isProcessFailed ||
isProcessSuccess ||
(processStatus.isNotDuplicate !== undefined && processStatus.isNotDuplicate === true)
}
Expand All @@ -231,14 +247,20 @@ C. Light your face evenly'
/>
<FRStep
title={'Validating identity'}
isActive={isProcessSuccess || (processStatus.isLive !== undefined && processStatus.isLive === true)}
isActive={
isProcessFailed ||
isProcessSuccess ||
(processStatus.isLive !== undefined && processStatus.isLive === true)
}
status={isProcessSuccess || processStatus.isWhitelisted}
isProcessFailed={isProcessFailed}
/>
<FRStep
title={'Updating profile'}
isActive={
isProcessSuccess || (processStatus.isWhitelisted !== undefined && processStatus.isWhitelisted === true)
isProcessFailed ||
isProcessSuccess ||
(processStatus.isWhitelisted !== undefined && processStatus.isWhitelisted === true)
}
status={isProcessSuccess || processStatus.isProfileSaved}
isProcessFailed={isProcessFailed}
Expand Down
2 changes: 2 additions & 0 deletions src/components/dashboard/FaceRecognition/UnsupportedDevice.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Divider from '../../../assets/Dividers - Long Line - Stroke Width 2 - Rou
import Oops from '../../../assets/oops.svg'
import GDStore from '../../../lib/undux/GDStore'
import logger from '../../../lib/logger/pino-logger'
import { fireEvent } from '../../../lib/analytics/analytics'

const log = logger.child({ from: 'UnsupportedDevice' })

Expand Down Expand Up @@ -46,6 +47,7 @@ const UnsupportedDevice = props => {
}

useEffect(() => {
fireEvent(`FR_Unsupported_${reason}`)
generateQRCode()
}, [])

Expand Down
11 changes: 9 additions & 2 deletions src/components/dashboard/FaceRecognition/ZoomCapture.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,16 @@ type ZoomCaptureProps = {
loadedZoom: boolean,
onCaptureResult: (captureResult?: ZoomCaptureResult) => void,
onError: (error: string) => void,
showHelper: boolean,
}

const HelperWizard = props => {
const { done } = props
const { done, skip } = props
const [step, setStep] = useState(0)
const nextStep = () => setStep(step + 1)
if (skip) {
return null
}
let text, imgs
switch (step) {
case 0:
Expand Down Expand Up @@ -138,6 +142,9 @@ class ZoomCapture extends React.Component<ZoomCaptureProps> {
let zoomSDK = this.props.loadedZoom
this.zoom = new Zoom(zoomSDK, track)
await this.zoom.ready
if (this.props.showHelper === false) {
this.captureUserMediaZoom()
}
} catch (e) {
log.error(`Failed on capture, error: ${e}`)
this.props.onError(e)
Expand Down Expand Up @@ -178,7 +185,7 @@ class ZoomCapture extends React.Component<ZoomCaptureProps> {
<View style={styles.bottomSection}>
<div id="zoom-parent-container" style={getVideoContainerStyles()}>
<View id="helper" style={styles.helper}>
<HelperWizard done={this.captureUserMediaZoom} />
<HelperWizard done={this.captureUserMediaZoom} skip={this.props.showHelper === false} />
</View>
<div id="zoom-interface-container" style={{ position: 'absolute' }} />
{<Camera onCameraLoad={this.cameraReady} onError={this.props.onError} />}
Expand Down

0 comments on commit f1fddc3

Please sign in to comment.