wallet-stack 1.0.0-alpha.131 → 1.0.0-alpha.133

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.
Files changed (59) hide show
  1. package/locales/base/translation.json +11 -0
  2. package/package.json +2 -3
  3. package/src/analytics/Events.tsx +3 -10
  4. package/src/analytics/Properties.tsx +9 -25
  5. package/src/analytics/docs.ts +11 -8
  6. package/src/app/ErrorMessages.ts +1 -7
  7. package/src/identity/actions.ts +1 -97
  8. package/src/identity/contactMapping.test.ts +3 -28
  9. package/src/identity/contactMapping.ts +2 -88
  10. package/src/identity/reducer.ts +0 -77
  11. package/src/identity/saga.ts +2 -85
  12. package/src/identity/selectors.ts +0 -2
  13. package/src/images/Images.ts +3 -0
  14. package/src/images/assets/invite-modal.png +0 -0
  15. package/src/images/assets/invite-modal@1.5x.png +0 -0
  16. package/src/images/assets/invite-modal@2x.png +0 -0
  17. package/src/images/assets/invite-modal@3x.png +0 -0
  18. package/src/images/assets/invite-modal@4x.png +0 -0
  19. package/src/images/assets/minipay.png +0 -0
  20. package/src/images/assets/minipay@1.5x.png +0 -0
  21. package/src/images/assets/minipay@2x.png +0 -0
  22. package/src/images/assets/minipay@3x.png +0 -0
  23. package/src/images/assets/minipay@4x.png +0 -0
  24. package/src/images/assets/valora.png +0 -0
  25. package/src/images/assets/valora@1.5x.png +0 -0
  26. package/src/images/assets/valora@2x.png +0 -0
  27. package/src/images/assets/valora@3x.png +0 -0
  28. package/src/images/assets/valora@4x.png +0 -0
  29. package/src/index.d.ts +0 -1
  30. package/src/navigator/Navigator.tsx +10 -14
  31. package/src/navigator/Screens.tsx +2 -2
  32. package/src/navigator/types.tsx +5 -6
  33. package/src/qrcode/utils.test.tsx +4 -96
  34. package/src/qrcode/utils.ts +5 -114
  35. package/src/redux/migrations.test.ts +13 -0
  36. package/src/redux/migrations.ts +4 -0
  37. package/src/redux/store.test.ts +1 -2
  38. package/src/redux/store.ts +1 -1
  39. package/src/send/SelectRecipientAddress.test.tsx +146 -0
  40. package/src/send/SelectRecipientAddress.tsx +166 -0
  41. package/src/send/SendConfirmation.test.tsx +28 -0
  42. package/src/send/SendConfirmation.tsx +18 -1
  43. package/src/send/SendInvite.test.tsx +107 -0
  44. package/src/send/SendInvite.tsx +99 -0
  45. package/src/send/SendSelectRecipient.test.tsx +44 -223
  46. package/src/send/SendSelectRecipient.tsx +41 -149
  47. package/src/send/actions.ts +0 -26
  48. package/src/send/saga.ts +1 -6
  49. package/src/components/AccountNumberCard.tsx +0 -23
  50. package/src/components/ErrorMessageInline.tsx +0 -78
  51. package/src/components/SingleDigitInput.tsx +0 -53
  52. package/src/icons/HamburgerCard.tsx +0 -55
  53. package/src/identity/saga.test.ts +0 -103
  54. package/src/identity/secureSend.ts +0 -171
  55. package/src/send/ValidateRecipientAccount.test.tsx +0 -182
  56. package/src/send/ValidateRecipientAccount.tsx +0 -392
  57. package/src/send/ValidateRecipientIntro.test.tsx +0 -61
  58. package/src/send/ValidateRecipientIntro.tsx +0 -136
  59. package/src/send/__snapshots__/ValidateRecipientAccount.test.tsx.snap +0 -777
@@ -1,392 +0,0 @@
1
- import { NativeStackScreenProps } from '@react-navigation/native-stack'
2
- import * as React from 'react'
3
- import { WithTranslation } from 'react-i18next'
4
- import { Keyboard, StyleSheet, Text, View } from 'react-native'
5
- import { connect } from 'react-redux'
6
- import AppAnalytics from 'src/analytics/AppAnalytics'
7
- import { SendEvents } from 'src/analytics/Events'
8
- import { ErrorMessages } from 'src/app/ErrorMessages'
9
- import AccountNumberCard from 'src/components/AccountNumberCard'
10
- import BackButton from 'src/components/BackButton'
11
- import Button, { BtnTypes } from 'src/components/Button'
12
- import CodeRow, { CodeRowStatus } from 'src/components/CodeRow'
13
- import ErrorMessageInline from 'src/components/ErrorMessageInline'
14
- import KeyboardAwareScrollView from 'src/components/KeyboardAwareScrollView'
15
- import KeyboardSpacer from 'src/components/KeyboardSpacer'
16
- import Modal from 'src/components/Modal'
17
- import { SingleDigitInput } from 'src/components/SingleDigitInput'
18
- import TextButton from 'src/components/TextButton'
19
- import { withTranslation } from 'src/i18n'
20
- import HamburgerCard from 'src/icons/HamburgerCard'
21
- import InfoIcon from 'src/icons/InfoIcon'
22
- import { validateRecipientAddress, validateRecipientAddressReset } from 'src/identity/actions'
23
- import { AddressValidationType } from 'src/identity/reducer'
24
- import { getAddressValidationType, getSecureSendAddress } from 'src/identity/secureSend'
25
- import { emptyHeader } from 'src/navigator/Headers'
26
- import { navigate } from 'src/navigator/NavigationService'
27
- import { Screens } from 'src/navigator/Screens'
28
- import { StackParamList } from 'src/navigator/types'
29
- import { Recipient, getDisplayName } from 'src/recipients/recipient'
30
- import { RootState } from 'src/redux/reducers'
31
- import { TransactionDataInput } from 'src/send/types'
32
- import colors from 'src/styles/colors'
33
- import { typeScale } from 'src/styles/fonts'
34
-
35
- const FULL_ADDRESS_PLACEHOLDER = '0xf1b1d5a6e7728g309c4a025k122d71ad75a61976'
36
- const PARTIAL_ADDRESS_PLACEHOLDER = ['a', '0', 'F', '4']
37
-
38
- interface StateProps {
39
- recipient: Recipient
40
- transactionData?: TransactionDataInput
41
- addressValidationType: AddressValidationType
42
- validationSuccessful: boolean
43
- error?: ErrorMessages | null
44
- validatedAddress?: string
45
- isMiniPayRecipient: boolean
46
- }
47
-
48
- interface State {
49
- inputValue: string
50
- singleDigitInputValueArr: string[]
51
- isModalVisible: boolean
52
- digitsRefs: React.MutableRefObject<any>[]
53
- }
54
-
55
- interface DispatchProps {
56
- validateRecipientAddressReset: typeof validateRecipientAddressReset
57
- validateRecipientAddress: typeof validateRecipientAddress
58
- }
59
-
60
- type OwnProps = NativeStackScreenProps<StackParamList, Screens.ValidateRecipientAccount>
61
- type Props = StateProps & DispatchProps & WithTranslation & OwnProps
62
-
63
- const mapDispatchToProps = {
64
- validateRecipientAddressReset,
65
- validateRecipientAddress,
66
- }
67
-
68
- const mapStateToProps = (state: RootState, ownProps: OwnProps): StateProps => {
69
- const { route } = ownProps
70
- const { recipient } = route.params
71
- const e164PhoneNumber = recipient.e164PhoneNumber
72
- const error = state.alert ? state.alert.underlyingError : null
73
- const secureSendPhoneNumberMapping = state.identity.secureSendPhoneNumberMapping
74
- const validationSuccessful =
75
- !!e164PhoneNumber && !!secureSendPhoneNumberMapping[e164PhoneNumber]?.validationSuccessful
76
- const addressValidationType: AddressValidationType = getAddressValidationType(
77
- recipient,
78
- secureSendPhoneNumberMapping
79
- )
80
- const validatedAddress = getSecureSendAddress(recipient, secureSendPhoneNumberMapping)
81
- const isMiniPayRecipient =
82
- !!validatedAddress && state.identity.addressToVerifiedBy?.[validatedAddress] === 'minipay'
83
-
84
- return {
85
- recipient,
86
- validationSuccessful,
87
- addressValidationType,
88
- error,
89
- validatedAddress,
90
- isMiniPayRecipient,
91
- }
92
- }
93
-
94
- export const validateRecipientAccountScreenNavOptions = () => ({
95
- ...emptyHeader,
96
- headerLeft: () => <BackButton eventName={SendEvents.send_secure_back} />,
97
- })
98
-
99
- export class ValidateRecipientAccount extends React.Component<Props, State> {
100
- state: State = {
101
- inputValue: '',
102
- singleDigitInputValueArr: [],
103
- isModalVisible: false,
104
- digitsRefs: [React.createRef(), React.createRef(), React.createRef(), React.createRef()],
105
- }
106
-
107
- componentDidMount = () => {
108
- const e164PhoneNumber = this.props.recipient.e164PhoneNumber
109
- if (e164PhoneNumber) {
110
- this.props.validateRecipientAddressReset(e164PhoneNumber)
111
- }
112
- }
113
-
114
- componentDidUpdate = (prevProps: Props) => {
115
- const { validationSuccessful, route, validatedAddress } = this.props
116
- const { singleDigitInputValueArr } = this.state
117
-
118
- if (validationSuccessful && !prevProps.validationSuccessful && validatedAddress) {
119
- navigate(Screens.SendEnterAmount, {
120
- origin: route.params.origin,
121
- recipient: {
122
- ...route.params.recipient,
123
- address: validatedAddress,
124
- },
125
- isFromScan: false,
126
- forceTokenId: route.params.forceTokenId,
127
- defaultTokenIdOverride: route.params.defaultTokenIdOverride,
128
- isMiniPayRecipient: this.props.isMiniPayRecipient,
129
- })
130
- }
131
-
132
- // If the user has entered 4 valid digits, dismiss the keyboard
133
- if (singleDigitInputValueArr.filter((entry) => /[a-f0-9]/gi.test(entry)).length === 4) {
134
- Keyboard.dismiss()
135
- }
136
- }
137
-
138
- onPressConfirm = () => {
139
- const { inputValue, singleDigitInputValueArr } = this.state
140
- const { recipient, addressValidationType } = this.props
141
- const { requesterAddress } = this.props.route.params
142
- const inputToValidate =
143
- addressValidationType === AddressValidationType.FULL
144
- ? inputValue
145
- : singleDigitInputValueArr.join('')
146
-
147
- AppAnalytics.track(SendEvents.send_secure_submit, {
148
- partialAddressValidation: addressValidationType === AddressValidationType.PARTIAL,
149
- address: inputToValidate,
150
- })
151
-
152
- this.props.validateRecipientAddress(
153
- inputToValidate,
154
- addressValidationType,
155
- recipient,
156
- requesterAddress
157
- )
158
- }
159
-
160
- onInputChange = (value: string) => {
161
- this.setState({ inputValue: value })
162
- }
163
-
164
- onSingleDigitInputChange = (value: string, index: number) => {
165
- const { singleDigitInputValueArr, digitsRefs } = this.state
166
- if (value === ' ') return
167
- if (value !== '') {
168
- digitsRefs[index + 1]?.current?.focus()
169
- } else {
170
- digitsRefs[index - 1]?.current?.focus()
171
- }
172
- singleDigitInputValueArr[index] = value
173
- this.setState({ singleDigitInputValueArr })
174
- }
175
-
176
- toggleModal = () => {
177
- const { addressValidationType } = this.props
178
-
179
- if (this.state.isModalVisible) {
180
- AppAnalytics.track(SendEvents.send_secure_info, {
181
- partialAddressValidation: addressValidationType === AddressValidationType.PARTIAL,
182
- })
183
- } else {
184
- AppAnalytics.track(SendEvents.send_secure_info_dismissed, {
185
- partialAddressValidation: addressValidationType === AddressValidationType.PARTIAL,
186
- })
187
- }
188
-
189
- this.setState({ isModalVisible: !this.state.isModalVisible })
190
- }
191
-
192
- shouldShowClipboard = () => false
193
-
194
- renderInstructionsAndInputField = () => {
195
- const { t, recipient, addressValidationType } = this.props
196
- const { inputValue, singleDigitInputValueArr, digitsRefs } = this.state
197
-
198
- if (addressValidationType === AddressValidationType.FULL) {
199
- return (
200
- <View>
201
- <Text style={styles.body}>
202
- {recipient.name
203
- ? t('confirmAccountNumber.body1Full', { displayName: recipient.name })
204
- : t('confirmAccountNumber.body1FullNoDisplayName')}
205
- </Text>
206
- <Text style={styles.body}>{t('confirmAccountNumber.body2Full')}</Text>
207
- <Text style={styles.codeHeader}>{t('accountInputHeaderFull')}</Text>
208
- <CodeRow
209
- status={CodeRowStatus.INPUTTING}
210
- inputValue={inputValue}
211
- inputPlaceholder={FULL_ADDRESS_PLACEHOLDER}
212
- onInputChange={this.onInputChange}
213
- shouldShowClipboard={this.shouldShowClipboard}
214
- testID="ValidateRecipientAccount/TextInput"
215
- />
216
- </View>
217
- )
218
- }
219
-
220
- const singleDigitInputComponentArr = PARTIAL_ADDRESS_PLACEHOLDER.map(
221
- (placeholderValue, index) => (
222
- <View style={styles.singleDigitInputWrapper} key={placeholderValue}>
223
- <SingleDigitInput
224
- forwardedRef={digitsRefs[index]}
225
- inputValue={singleDigitInputValueArr[index]}
226
- inputPlaceholder={placeholderValue}
227
- onInputChange={(value) => this.onSingleDigitInputChange(value, index)}
228
- testID={`SingleDigitInput/digit${index}`}
229
- />
230
- </View>
231
- )
232
- )
233
-
234
- return (
235
- <View>
236
- <Text style={styles.body}>
237
- {recipient.name
238
- ? t('confirmAccountNumber.bodyPartial', { displayName: recipient.name })
239
- : t('confirmAccountNumber.bodyPartialNoDisplayName')}
240
- </Text>
241
- <Text style={styles.codeHeader}>{t('accountInputHeaderPartial')}</Text>
242
- <View style={styles.singleDigitInputContainer}>{singleDigitInputComponentArr}</View>
243
- </View>
244
- )
245
- }
246
-
247
- render = () => {
248
- const { t, recipient, error, addressValidationType } = this.props
249
- const { singleDigitInputValueArr, inputValue } = this.state
250
- const displayName = getDisplayName(recipient, t)
251
- const isFilled =
252
- addressValidationType === AddressValidationType.FULL
253
- ? inputValue.length > 0
254
- : singleDigitInputValueArr.filter((entry) => /[a-f0-9]/gi.test(entry)).length === 4
255
-
256
- return (
257
- <>
258
- <KeyboardAwareScrollView
259
- contentContainerStyle={styles.scrollContainer}
260
- keyboardShouldPersistTaps={'always'}
261
- >
262
- <View>
263
- <Text testID="ConfirmAccountNumber/Title" style={styles.h2}>
264
- {t('confirmAccountNumber.title')}
265
- </Text>
266
- <View>{this.renderInstructionsAndInputField()}</View>
267
- <ErrorMessageInline error={error} />
268
- <Button
269
- style={styles.button}
270
- onPress={this.onPressConfirm}
271
- text={t('confirmAccountNumber.submit')}
272
- type={BtnTypes.PRIMARY}
273
- testID="ConfirmAccountButton"
274
- disabled={!isFilled}
275
- />
276
- </View>
277
- <View style={styles.helpContainer}>
278
- <InfoIcon />
279
- <Text onPress={this.toggleModal} style={styles.askHelpText}>
280
- {t('confirmAccountNumber.help', { displayName })}
281
- </Text>
282
- </View>
283
- </KeyboardAwareScrollView>
284
- <KeyboardSpacer />
285
- <Modal isVisible={this.state.isModalVisible}>
286
- <Text style={styles.modalHeader}>{t('helpModal.header')}</Text>
287
- <Text style={styles.modalBody}>{t('helpModal.body1')}</Text>
288
- <View style={styles.menuContainer}>
289
- <View style={styles.menuCardContainer}>
290
- <HamburgerCard />
291
- </View>
292
- <Text style={styles.menuText}>Menu</Text>
293
- </View>
294
- <Text style={styles.modalBody}>{t('helpModal.body2')}</Text>
295
- <View style={styles.addressContainer}>
296
- <AccountNumberCard address={FULL_ADDRESS_PLACEHOLDER} />
297
- <Text style={styles.modalBody2}>{t('helpModal.body3')}</Text>
298
- </View>
299
- <View style={styles.modalButtonContainer}>
300
- <TextButton onPress={this.toggleModal}>{t('dismiss')}</TextButton>
301
- </View>
302
- </Modal>
303
- </>
304
- )
305
- }
306
- }
307
-
308
- const styles = StyleSheet.create({
309
- scrollContainer: {
310
- flexGrow: 1,
311
- paddingHorizontal: 16,
312
- justifyContent: 'space-between',
313
- },
314
- singleDigitInputContainer: {
315
- flexDirection: 'row',
316
- },
317
- singleDigitInputWrapper: {
318
- paddingRight: 8,
319
- },
320
- codeHeader: {
321
- ...typeScale.labelSemiBoldSmall,
322
- paddingVertical: 8,
323
- },
324
- h2: {
325
- ...typeScale.titleSmall,
326
- paddingVertical: 16,
327
- },
328
- button: {
329
- paddingVertical: 16,
330
- },
331
- helpContainer: {
332
- flexDirection: 'row',
333
- alignItems: 'center',
334
- paddingBottom: 24,
335
- },
336
- askHelpText: {
337
- ...typeScale.bodySmall,
338
- paddingLeft: 8,
339
- textDecorationLine: 'underline',
340
- },
341
- body: {
342
- ...typeScale.bodyMedium,
343
- paddingBottom: 16,
344
- },
345
- modalBody: {
346
- ...typeScale.bodyMedium,
347
- textAlign: 'center',
348
- paddingVertical: 8,
349
- },
350
- modalHeader: {
351
- ...typeScale.titleSmall,
352
- textAlign: 'center',
353
- paddingBottom: 4,
354
- },
355
- modalBody2: {
356
- ...typeScale.bodySmall,
357
- textAlign: 'center',
358
- color: colors.contentSecondary,
359
- paddingVertical: 16,
360
- paddingTop: 16,
361
- },
362
- menuContainer: {
363
- flexDirection: 'row',
364
- alignItems: 'center',
365
- justifyContent: 'center',
366
- paddingVertical: 8,
367
- },
368
- menuCardContainer: {
369
- paddingHorizontal: 8,
370
- },
371
- menuText: {
372
- ...typeScale.bodySmall,
373
- color: colors.contentSecondary,
374
- paddingHorizontal: 8,
375
- },
376
- addressContainer: {
377
- paddingVertical: 8,
378
- alignItems: 'center',
379
- justifyContent: 'center',
380
- },
381
- modalButtonContainer: {
382
- paddingVertical: 24,
383
- flexDirection: 'row',
384
- alignItems: 'center',
385
- justifyContent: 'space-evenly',
386
- },
387
- })
388
-
389
- export default connect<StateProps, DispatchProps, OwnProps, RootState>(
390
- mapStateToProps,
391
- mapDispatchToProps
392
- )(withTranslation<Props>()(ValidateRecipientAccount))
@@ -1,61 +0,0 @@
1
- import { fireEvent, render } from '@testing-library/react-native'
2
- import * as React from 'react'
3
- import { Provider } from 'react-redux'
4
- import { SendOrigin } from 'src/analytics/types'
5
- import { AddressValidationType } from 'src/identity/reducer'
6
- import { navigate } from 'src/navigator/NavigationService'
7
- import { Screens } from 'src/navigator/Screens'
8
- import ValidateRecipientIntro from 'src/send/ValidateRecipientIntro'
9
- import { createMockStore } from 'test/utils'
10
- import { mockEthTokenId, mockNavigation, mockTransactionData } from 'test/values'
11
-
12
- const store = createMockStore()
13
-
14
- const mockRoute = {
15
- name: Screens.ValidateRecipientIntro as Screens.ValidateRecipientIntro,
16
- key: '1',
17
- params: {
18
- transactionData: mockTransactionData,
19
- addressValidationType: AddressValidationType.FULL,
20
- origin: SendOrigin.AppSendFlow,
21
- recipient: mockTransactionData.recipient,
22
- defaultTokenIdOverride: mockEthTokenId,
23
- },
24
- }
25
-
26
- describe('ValidateRecipientIntro', () => {
27
- beforeEach(() => {
28
- jest.clearAllMocks()
29
- })
30
- it('navigates to account confirmation screen when Confirm Account button clicked', () => {
31
- const tree = render(
32
- <Provider store={store}>
33
- <ValidateRecipientIntro navigation={mockNavigation} route={mockRoute} />
34
- </Provider>
35
- )
36
- fireEvent.press(tree.getByTestId('confirmAccountButton'))
37
- expect(navigate).toHaveBeenCalledWith(Screens.ValidateRecipientAccount, {
38
- origin: SendOrigin.AppSendFlow,
39
- defaultTokenIdOverride: mockEthTokenId,
40
- forceTokenId: undefined,
41
- requesterAddress: undefined,
42
- recipient: mockTransactionData.recipient,
43
- })
44
- })
45
-
46
- it('navigates to QR Scanner screen when Scan QR Code button clicked', () => {
47
- const tree = render(
48
- <Provider store={store}>
49
- <ValidateRecipientIntro navigation={mockNavigation} route={mockRoute} />
50
- </Provider>
51
- )
52
- fireEvent.press(tree.getByTestId('scanQRCode'))
53
- expect(navigate).toHaveBeenCalledWith(Screens.QRNavigator, {
54
- screen: Screens.QRScanner,
55
- params: {
56
- onQRCodeDetected: expect.any(Function),
57
- showSecureSendStyling: true,
58
- },
59
- })
60
- })
61
- })
@@ -1,136 +0,0 @@
1
- import { NativeStackScreenProps } from '@react-navigation/native-stack'
2
- import * as React from 'react'
3
- import { useTranslation } from 'react-i18next'
4
- import { ScrollView, StyleSheet, Text, View } from 'react-native'
5
- import { SafeAreaView } from 'react-native-safe-area-context'
6
- import AppAnalytics from 'src/analytics/AppAnalytics'
7
- import { SendEvents } from 'src/analytics/Events'
8
- import CancelButton from 'src/components/CancelButton'
9
- import ContactCircle from 'src/components/ContactCircle'
10
- import TextButton from 'src/components/TextButton'
11
- import { emptyHeader } from 'src/navigator/Headers'
12
- import { navigate } from 'src/navigator/NavigationService'
13
- import { Screens } from 'src/navigator/Screens'
14
- import { StackParamList } from 'src/navigator/types'
15
- import { getDisplayName } from 'src/recipients/recipient'
16
- import { useDispatch } from 'src/redux/hooks'
17
- import { handleQRCodeDetectedSecureSend } from 'src/send/actions'
18
- import { QrCode } from 'src/send/types'
19
- import { typeScale } from 'src/styles/fonts'
20
-
21
- const AVATAR_SIZE = 64
22
-
23
- type Props = NativeStackScreenProps<StackParamList, Screens.ValidateRecipientIntro>
24
-
25
- export const validateRecipientIntroScreenNavOptions = () => ({
26
- ...emptyHeader,
27
- headerLeft: () => <CancelButton eventName={SendEvents.send_secure_cancel} buttonType="icon" />,
28
- })
29
-
30
- const ValidateRecipientIntro = ({ route }: Props) => {
31
- const { t } = useTranslation()
32
- const dispatch = useDispatch()
33
- const { requesterAddress, origin, recipient, forceTokenId, defaultTokenIdOverride } = route.params
34
-
35
- const onQRCodeDetected = (data: QrCode) => {
36
- dispatch(
37
- handleQRCodeDetectedSecureSend(
38
- data,
39
- recipient,
40
- requesterAddress,
41
- forceTokenId,
42
- defaultTokenIdOverride
43
- )
44
- )
45
- }
46
-
47
- const onPressScanCode = () => {
48
- navigate(Screens.QRNavigator, {
49
- screen: Screens.QRScanner,
50
- params: {
51
- onQRCodeDetected,
52
- showSecureSendStyling: true,
53
- },
54
- })
55
-
56
- AppAnalytics.track(SendEvents.send_secure_start, { confirmByScan: true })
57
- }
58
-
59
- const onPressConfirmAccount = () => {
60
- navigate(Screens.ValidateRecipientAccount, {
61
- requesterAddress,
62
- origin,
63
- recipient,
64
- forceTokenId,
65
- defaultTokenIdOverride,
66
- })
67
-
68
- AppAnalytics.track(SendEvents.send_secure_start, { confirmByScan: false })
69
- }
70
-
71
- const displayName = getDisplayName(recipient, t)
72
- const e164PhoneNumber = recipient.e164PhoneNumber
73
-
74
- return (
75
- <SafeAreaView style={styles.container}>
76
- <ScrollView contentContainerStyle={styles.scrollContainer}>
77
- <View style={styles.iconContainer}>
78
- <ContactCircle size={AVATAR_SIZE} recipient={recipient} />
79
- </View>
80
- <Text style={styles.validationHeader}>
81
- {!recipient.name
82
- ? t('confirmAccount.headerNoDisplayName')
83
- : t('confirmAccount.header', { displayName })}
84
- </Text>
85
- <Text style={styles.body}>{t('secureSendExplanation.body1', { e164PhoneNumber })}</Text>
86
- <View style={styles.buttonContainer}>
87
- <TextButton style={styles.button} onPress={onPressScanCode} testID={'scanQRCode'}>
88
- {t('scanQRCode')}
89
- </TextButton>
90
- <TextButton
91
- style={styles.button}
92
- onPress={onPressConfirmAccount}
93
- testID={'confirmAccountButton'}
94
- >
95
- {t('confirmAccount.button')}
96
- </TextButton>
97
- </View>
98
- </ScrollView>
99
- </SafeAreaView>
100
- )
101
- }
102
-
103
- const styles = StyleSheet.create({
104
- container: {
105
- flex: 1,
106
- justifyContent: 'space-between',
107
- },
108
- scrollContainer: {
109
- flex: 1,
110
- paddingHorizontal: 24,
111
- paddingBottom: 30,
112
- justifyContent: 'flex-start',
113
- },
114
- iconContainer: {
115
- alignItems: 'center',
116
- },
117
- buttonContainer: {
118
- paddingBottom: 45,
119
- alignItems: 'center',
120
- },
121
- button: {
122
- paddingVertical: 16,
123
- },
124
- validationHeader: {
125
- ...typeScale.titleSmall,
126
- paddingVertical: 16,
127
- textAlign: 'center',
128
- },
129
- body: {
130
- ...typeScale.bodySmall,
131
- textAlign: 'center',
132
- paddingBottom: 16,
133
- },
134
- })
135
-
136
- export default ValidateRecipientIntro