Skip to content

Commit aa35834

Browse files
sirpyL03TJ3
andauthored
add: mvp age verification (#4331)
* add: mvp age verification * fix: button overlapping picture on android * fix: remove wrongfuly used deps * add: show duplicate id expiration date on web * add: try again to giveup screen * add: design changes * add: change duplicate messaging and add link * fix: age error text * add: update fv flow texts --------- Co-authored-by: LewisB <[email protected]>
1 parent c8c93ec commit aa35834

File tree

17 files changed

+334
-149
lines changed

17 files changed

+334
-149
lines changed
Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,30 @@
11
import React from 'react'
2+
import { View } from 'react-native'
3+
import { CheckBox as WebCheckBox } from 'react-native-web'
4+
import RNCheckBox from '@react-native-community/checkbox'
5+
import { isMobileNative } from '../../../lib/utils/platform'
6+
import { withStyles } from '../../../lib/styles'
27

3-
const CheckBox = ({ onClick, children }) => (
4-
<label style={{ marginBottom: 24, display: 'flex', alignItems: 'center', flexDirection: 'row' }}>
5-
<input type="checkbox" onClick={onClick} style={{ width: 24, height: 24 }} />
8+
const CheckBoxComponent = isMobileNative ? RNCheckBox : WebCheckBox
9+
const CheckBox = ({ onClick, value, styles, children }) => (
10+
<View style={styles.container}>
11+
<CheckBoxComponent value={value} onValueChange={onClick} style={styles.checkbox} />
612
{children}
7-
</label>
13+
</View>
814
)
915

10-
export default CheckBox
16+
const mapStylesToProps = () => ({
17+
container: {
18+
flexDirection: 'row',
19+
alignItems: 'center',
20+
},
21+
checkbox: {
22+
width: 24,
23+
height: 24,
24+
marginRight: 8,
25+
},
26+
})
27+
28+
export default withStyles(mapStylesToProps)(CheckBox)
29+
30+
// export default CheckBox

src/components/common/buttons/CheckBox.native.jsx

Lines changed: 0 additions & 26 deletions
This file was deleted.
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import React, { useEffect } from 'react'
2+
import { View } from 'react-native'
3+
import { t } from '@lingui/macro'
4+
5+
import Text from '../../common/view/Text'
6+
import Separator from '../../common/layout/Separator'
7+
import { Section } from '../../common'
8+
import FaceVerificationErrorSmiley from '../../common/animations/FaceVerificationErrorSmiley'
9+
10+
import { isMobileOnly } from '../../../lib/utils/platform'
11+
import { getDesignRelativeHeight, getDesignRelativeWidth } from '../../../lib/utils/sizes'
12+
import { withStyles } from '../../../lib/styles'
13+
14+
import { fireEvent, FV_AGECHECKERROR } from '../../../lib/analytics/analytics'
15+
16+
const AgeCheckError = ({ styles, displayTitle, onRetry, nav, exception }) => {
17+
useEffect(() => {
18+
if (!exception) {
19+
return
20+
}
21+
22+
fireEvent(FV_AGECHECKERROR)
23+
}, [])
24+
25+
return (
26+
<Section style={styles.descriptionContainer} justifyContent="space-evenly">
27+
<Section.Title fontWeight="medium" textTransform="none" color="red">
28+
{t`You must be 18 years or older to get verified.`}
29+
</Section.Title>
30+
<Section.Row justifyContent="space-around">
31+
<View style={styles.halfIllustration}>
32+
<FaceVerificationErrorSmiley />
33+
</View>
34+
</Section.Row>
35+
<Section style={styles.errorSection}>
36+
<Separator width={2} />
37+
<View style={styles.descriptionWrapper}>
38+
<Text color="primary" fontWeight="bold" fontSize={18} lineHeight={25}>
39+
{t`It seems your are under 18 years of age.`}
40+
</Text>
41+
<Text color="primary" fontSize={18} lineHeight={25}>
42+
{t`If you think this is a mistake
43+
please contact support.`}
44+
</Text>
45+
</View>
46+
<Separator width={2} />
47+
</Section>
48+
</Section>
49+
)
50+
}
51+
52+
const getStylesFromProps = ({ theme }) => {
53+
return {
54+
halfIllustration: {
55+
marginTop: isMobileOnly ? getDesignRelativeHeight(25) : 0,
56+
marginBottom: isMobileOnly ? getDesignRelativeHeight(30) : 0,
57+
width: getDesignRelativeWidth(130, false),
58+
maxHeight: isMobileOnly ? getDesignRelativeHeight(97) : 'auto',
59+
display: 'flex',
60+
justifyContent: 'center',
61+
marginRight: 0,
62+
marginLeft: 0,
63+
},
64+
descriptionContainer: {
65+
flex: 1,
66+
marginBottom: 0,
67+
paddingBottom: getDesignRelativeHeight(theme.sizes.defaultDouble),
68+
paddingLeft: getDesignRelativeWidth(theme.sizes.default),
69+
paddingRight: getDesignRelativeWidth(theme.sizes.default),
70+
paddingTop: getDesignRelativeHeight(theme.sizes.default),
71+
width: '100%',
72+
},
73+
actionsSpace: {
74+
marginBottom: getDesignRelativeHeight(16),
75+
},
76+
errorSection: {
77+
paddingBottom: 0,
78+
paddingTop: 0,
79+
marginBottom: 0,
80+
},
81+
descriptionWrapper: {
82+
paddingTop: getDesignRelativeHeight(25),
83+
paddingBottom: getDesignRelativeHeight(25),
84+
},
85+
}
86+
}
87+
88+
export default withStyles(getStylesFromProps)(AgeCheckError)

src/components/faceVerification/components/DuplicateFoundError.jsx

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import React, { useEffect } from 'react'
2-
import { View } from 'react-native'
1+
import React, { useCallback, useEffect } from 'react'
2+
import { Linking, View } from 'react-native'
33
import { t } from '@lingui/macro'
4-
4+
import { get } from 'lodash'
5+
import moment from 'moment'
56
import Text from '../../common/view/Text'
67
import { Section } from '../../common'
78

@@ -13,6 +14,12 @@ import FVErrorTwinSVG from '../../../assets/FaceVerification/FVErrorTwin.svg'
1314
import { fireEvent, FV_DUPLICATEERROR } from '../../../lib/analytics/analytics'
1415

1516
const DuplicateFoundError = ({ styles, displayTitle, onRetry, nav, exception }) => {
17+
const onLearnMore = useCallback(() => {
18+
Linking.openURL('https://docs.gooddollar.org/frequently-asked-questions/troubleshooting#help-it-says-i-have-a-twin')
19+
}, [])
20+
21+
const expiration = get(exception, 'response.enrollmentResult.duplicate.expiration')
22+
1623
useEffect(() => {
1724
if (!exception) {
1825
return
@@ -29,23 +36,38 @@ const DuplicateFoundError = ({ styles, displayTitle, onRetry, nav, exception })
2936
{displayTitle}
3037
</Section.Title>
3138
)}
32-
{(displayTitle ? `,\n` : '') +
33-
t`Unfortunately we found
34-
your twin...`}
39+
{(displayTitle ? `,\n` : '') + t`We found your twin...`}
3540
</Section.Title>
3641
<Section style={styles.errorSection}>
3742
<View style={styles.descriptionWrapper}>
38-
<Text>
39-
<Text fontSize={18} lineHeight={25} fontWeight="bold">
40-
{t`You can open ONLY ONE account
43+
<Text fontSize={16} lineHeight={25} fontWeight="bold">
44+
{t`You can verify ONLY ONE wallet address
4145
per person. `}
42-
</Text>
43-
<Text fontSize={18} lineHeight={25}>
44-
{t`If this is your only active
45-
account - please contact our support`}
46-
</Text>
46+
</Text>
47+
<Text fontSize={18} lineHeight={25}>
48+
{t`If this is your only active
49+
account - please contact support.`}
4750
</Text>
4851
</View>
52+
{expiration && (
53+
<View marginTop={20}>
54+
<Text fontSize={16} lineHeight={25} fontWeight="bold">
55+
{t`The existing identity will expire on ${moment(expiration).format('l')}.
56+
After this expiry, you may verify a different wallet address.`}
57+
</Text>
58+
<Text
59+
color="primary"
60+
fontWeight="bold"
61+
fontSize={18}
62+
lineHeight={26}
63+
textDecorationLine="underline"
64+
style={styles.learnMore}
65+
onPress={onLearnMore}
66+
>
67+
{t`Learn More`}
68+
</Text>
69+
</View>
70+
)}
4971
</Section>
5072
<Section.Row justifyContent="space-evenly">
5173
<View style={styles.errorImage}>

src/components/faceVerification/components/ErrorButtons.jsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,27 @@ import { withStyles } from '../../../lib/styles'
1111

1212
const { fvTypeformUrl } = Config
1313

14-
const ErrorButtons = ({ styles, screenProps, navigation, onRetry, reachedMax }) => {
14+
const ErrorButtons = ({ styles, screenProps, navigation, onRetry, reachedMax, invert = false }) => {
1515
const onContactSupport = useCallback(() => openLink(fvTypeformUrl), [])
1616

1717
return (
1818
<View style={styles.buttonsContainer}>
1919
{!reachedMax ? (
20-
<View>
21-
<CustomButton onPress={onRetry} style={styles.actionsSpace}>
20+
<View style={{ flex: 1 }}>
21+
<CustomButton onPress={onRetry} style={styles.actionsSpace} mode={invert ? 'outlined' : undefined}>
2222
TRY AGAIN
2323
</CustomButton>
24-
<CustomButton onPress={onContactSupport} mode="outlined">
24+
<CustomButton onPress={onContactSupport} mode={invert ? undefined : 'outlined'}>
2525
{t`CONTACT SUPPORT`}
2626
</CustomButton>
2727
</View>
2828
) : (
29-
<GiveUpButton navigation={navigation} />
29+
<View>
30+
<GiveUpButton navigation={navigation} />
31+
<CustomButton onPress={onRetry} style={styles.actionsSpace}>
32+
TRY AGAIN
33+
</CustomButton>
34+
</View>
3035
)}
3136
</View>
3237
)
@@ -37,6 +42,7 @@ const getStylesFromProps = ({ theme }) => ({
3742
width: '100%',
3843
},
3944
actionsSpace: {
45+
marginTop: 10, //native design fix
4046
marginBottom: getDesignRelativeHeight(16),
4147
},
4248
})

src/components/faceVerification/components/Instructions.jsx

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { CustomButton, Section, Wrapper } from '../../common'
1212
import { getDesignRelativeHeight, getDesignRelativeWidth, isLargeDevice } from '../../../lib/utils/sizes'
1313
import normalize from '../../../lib/utils/normalizeText'
1414
import { withStyles } from '../../../lib/styles'
15-
import { isBrowser } from '../../../lib/utils/platform'
15+
import { isBrowser, isMobile } from '../../../lib/utils/platform'
1616

1717
// assets
1818
import illustration from '../../../assets/FRInstructions.png'
@@ -32,26 +32,42 @@ const Dot = () => (
3232
</Text>
3333
)
3434

35-
const Instructions = ({ styles, onDismiss = noop, ready }) => (
35+
const Instructions = ({ styles, onDismiss = noop, ready, fvStarted = false }) => (
3636
<Wrapper>
3737
<Section style={styles.topContainer} grow>
3838
<View style={styles.mainContent}>
3939
<Image source={illustration} resizeMode="contain" style={styles.illustration} />
4040
<View style={styles.descriptionContainer}>
41-
<View style={styles.descriptionWrapper}>
42-
<Text style={styles.text}>
43-
<Dot />
44-
{t`Hold Your Camera at Eye Level`}
45-
</Text>
46-
<Text style={styles.text}>
47-
<Dot />
48-
{t`Light Your Face Evenly`}
49-
</Text>
50-
<Text style={styles.text}>
51-
<Dot />
52-
{t`Avoid Smiling & Back Light`}
53-
</Text>
54-
</View>
41+
{!fvStarted ? (
42+
<View style={styles.descriptionWrapper}>
43+
{!isMobile && (
44+
<Text style={styles.text}>
45+
<Dot />
46+
{t`Face Directly In Front of the Camera`}
47+
</Text>
48+
)}
49+
<Text style={styles.text}>
50+
<Dot />
51+
{t`Hold Your Camera at Eye Level`}
52+
</Text>
53+
<Text style={styles.text}>
54+
<Dot />
55+
{t`Light Your Face Evenly`}
56+
</Text>
57+
<Text style={styles.text}>
58+
<Dot />
59+
{t`Avoid Smiling & Back Light`}
60+
</Text>
61+
</View>
62+
) : (
63+
<View style={styles.warnDescriptionWrapper}>
64+
<Text style={styles.warnText}>{t`Notice:
65+
Face verifying for someone else's use is against the terms & service policy.`}</Text>
66+
<Text
67+
style={styles.warnText}
68+
>{t`Doing so may result in a loss of funds and/or your account being blocked.`}</Text>
69+
</View>
70+
)}
5571
</View>
5672
<CustomButton
5773
loading={!ready}
@@ -123,6 +139,10 @@ const getStylesFromProps = ({ theme }) => ({
123139
flexDirection: 'column',
124140
alignItems: 'flex-start',
125141
},
142+
warnDescriptionWrapper: {
143+
flexDirection: 'column',
144+
alignItems: 'center',
145+
},
126146
descriptionWrapperB: {
127147
backgroundColor: theme.colors.darkGray,
128148
borderRadius: 8,
@@ -136,6 +156,13 @@ const getStylesFromProps = ({ theme }) => ({
136156
fontSize: normalize(isLargeDevice ? 22 : 20),
137157
lineHeight: isLargeDevice ? 36 : 34,
138158
},
159+
warnText: {
160+
// textAlign: 'center',
161+
fontSize: normalize(isLargeDevice ? 22 : 20),
162+
lineHeight: isLargeDevice ? 36 : 34,
163+
fontWeight: 'bold',
164+
color: theme.colors.red,
165+
},
139166
textB: {
140167
textAlign: 'left',
141168
fontSize: 16,

src/components/faceVerification/hooks/useFaceTecVerification.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ export default (options = null) => {
125125
name = 'DuplicateFoundError'
126126
} else if (/face.+n.t\s+match/.test(message)) {
127127
name = 'NotMatchError'
128+
} else if (/age check failed/.test(message)) {
129+
name = 'AgeCheckError'
128130
} else {
129131
// the following code is needed to categorize exceptions
130132
// then we could display specific error messages

0 commit comments

Comments
 (0)