(Fix) - #1605 QR Input address fix (#1612)

* Add types

* Fix missing address in input field

* Fix reopening file upload modal once closed

* Error first callback onFileUploadHandlerClose

* Adds error text for qrs that can't be read
Fixes popping up again for wrong qr codes

* Fix opening modal

Co-authored-by: nicolas <nicosampler@users.noreply.github.com>
This commit is contained in:
Agustin Pane 2020-11-19 12:22:48 -03:00 committed by GitHub
parent 486bb4b203
commit e482d3259b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 60 additions and 42 deletions

View File

@ -16,7 +16,7 @@ const styles = () => ({
position: 'absolute', position: 'absolute',
top: '120px', top: '120px',
width: '500px', width: '500px',
height: '530px', height: '540px',
borderRadius: sm, borderRadius: sm,
backgroundColor: '#ffffff', backgroundColor: '#ffffff',
boxShadow: '0 0 5px 0 rgba(74, 85, 121, 0.5)', boxShadow: '0 0 5px 0 rgba(74, 85, 121, 0.5)',

View File

@ -3,7 +3,7 @@ import { useState } from 'react'
import * as React from 'react' import * as React from 'react'
import QRIcon from 'src/assets/icons/qrcode.svg' import QRIcon from 'src/assets/icons/qrcode.svg'
import ScanQRModal from 'src/components/ScanQRModal' import { ScanQRModal } from 'src/components/ScanQRModal'
import Img from 'src/components/layout/Img' import Img from 'src/components/layout/Img'
const useStyles = makeStyles({ const useStyles = makeStyles({
@ -12,7 +12,11 @@ const useStyles = makeStyles({
}, },
}) })
export const ScanQRWrapper = (props) => { type Props = {
handleScan: (dataResult: string, closeQrModal: () => void) => void
}
export const ScanQRWrapper = ({ handleScan }: Props): React.ReactElement => {
const classes = useStyles() const classes = useStyles()
const [qrModalOpen, setQrModalOpen] = useState(false) const [qrModalOpen, setQrModalOpen] = useState(false)
@ -25,7 +29,7 @@ export const ScanQRWrapper = (props) => {
} }
const onScanFinished = (value) => { const onScanFinished = (value) => {
props.handleScan(value, closeQrModal) handleScan(value, closeQrModal)
} }
return ( return (
@ -34,9 +38,7 @@ export const ScanQRWrapper = (props) => {
alt="Scan QR" alt="Scan QR"
className={classes.qrCodeBtn} className={classes.qrCodeBtn}
height={20} height={20}
onClick={() => { onClick={() => openQrModal()}
openQrModal()
}}
role="button" role="button"
src={QRIcon} src={QRIcon}
testId="qr-icon" testId="qr-icon"

View File

@ -1,6 +1,6 @@
import CircularProgress from '@material-ui/core/CircularProgress' import CircularProgress from '@material-ui/core/CircularProgress'
import IconButton from '@material-ui/core/IconButton' import IconButton from '@material-ui/core/IconButton'
import { withStyles } from '@material-ui/core/styles' import { makeStyles } from '@material-ui/core/styles'
import Close from '@material-ui/icons/Close' import Close from '@material-ui/icons/Close'
import * as React from 'react' import * as React from 'react'
import QrReader from 'react-qr-reader' import QrReader from 'react-qr-reader'
@ -15,11 +15,21 @@ import Col from 'src/components/layout/Col'
import Hairline from 'src/components/layout/Hairline' import Hairline from 'src/components/layout/Hairline'
import Paragraph from 'src/components/layout/Paragraph' import Paragraph from 'src/components/layout/Paragraph'
import Row from 'src/components/layout/Row' import Row from 'src/components/layout/Row'
import { useEffect, useState } from 'react'
const { useEffect, useState } = React const useStyles = makeStyles(styles)
const ScanQRModal = ({ classes, isOpen, onClose, onScan }) => { type Props = {
const [hasWebcam, setHasWebcam] = useState<any>(null) isOpen: boolean
onClose: () => void
onScan: (value: string) => void
}
export const ScanQRModal = ({ isOpen, onClose, onScan }: Props): React.ReactElement => {
const classes = useStyles()
const [useWebcam, setUseWebcam] = useState<boolean | null>(null)
const [fileUploadModalOpen, setFileUploadModalOpen] = useState<boolean>(false)
const [error, setError] = useState<string | null>(null)
const scannerRef: any = React.createRef() const scannerRef: any = React.createRef()
const openImageDialog = React.useCallback(() => { const openImageDialog = React.useCallback(() => {
scannerRef.current.openImageDialog() scannerRef.current.openImageDialog()
@ -28,22 +38,35 @@ const ScanQRModal = ({ classes, isOpen, onClose, onScan }) => {
useEffect(() => { useEffect(() => {
checkWebcam( checkWebcam(
() => { () => {
setHasWebcam(true) setUseWebcam(true)
}, },
() => { () => {
setHasWebcam(false) setUseWebcam(false)
}, },
) )
}, []) }, [])
useEffect(() => { useEffect(() => {
// this fires only when the hasWebcam changes to false (null > false (user doesn't have webcam) if (useWebcam === false && !fileUploadModalOpen && !error) {
// , true > false (user switched from webcam to file upload)) setFileUploadModalOpen(true)
// Doesn't fire on re-render
if (hasWebcam === false) {
openImageDialog() openImageDialog()
} }
}, [hasWebcam, openImageDialog]) }, [useWebcam, openImageDialog, fileUploadModalOpen, setFileUploadModalOpen, error])
const onFileScannedResolve = (error: string | null, successData: string | null) => {
if (successData) {
onScan(successData)
}
if (error) {
console.error('Error uploading file', error)
setError(`The QR could not be read`)
}
if (!useWebcam) {
setError(`The QR could not be read`)
}
setFileUploadModalOpen(false)
}
return ( return (
<Modal description="Receive Tokens Form" handleClose={onClose} open={isOpen} title="Receive Tokens"> <Modal description="Receive Tokens Form" handleClose={onClose} open={isOpen} title="Receive Tokens">
@ -57,19 +80,16 @@ const ScanQRModal = ({ classes, isOpen, onClose, onScan }) => {
</Row> </Row>
<Hairline /> <Hairline />
<Col className={classes.detailsContainer} layout="column" middle="xs"> <Col className={classes.detailsContainer} layout="column" middle="xs">
{hasWebcam === null ? ( {error}
{useWebcam === null ? (
<Block className={classes.loaderContainer} justify="center"> <Block className={classes.loaderContainer} justify="center">
<CircularProgress /> <CircularProgress />
</Block> </Block>
) : ( ) : (
<QrReader <QrReader
legacyMode={!hasWebcam} legacyMode={!useWebcam}
onError={(err) => { onError={(err) => onFileScannedResolve(err, null)}
console.error(err) onScan={(data) => onFileScannedResolve(null, data)}
}}
onScan={(data) => {
if (data) onScan(data)
}}
ref={scannerRef} ref={scannerRef}
style={{ width: '400px', height: '400px' }} style={{ width: '400px', height: '400px' }}
/> />
@ -85,11 +105,9 @@ const ScanQRModal = ({ classes, isOpen, onClose, onScan }) => {
color="primary" color="primary"
minWidth={154} minWidth={154}
onClick={() => { onClick={() => {
if (hasWebcam) { setUseWebcam(false)
setHasWebcam(false) setError(null)
} else { setFileUploadModalOpen(false)
openImageDialog()
}
}} }}
variant="contained" variant="contained"
> >
@ -99,5 +117,3 @@ const ScanQRModal = ({ classes, isOpen, onClose, onScan }) => {
</Modal> </Modal>
) )
} }
export default withStyles(styles as any)(ScanQRModal)

View File

@ -1,6 +1,7 @@
import { background, lg, secondaryText, sm } from 'src/theme/variables' import { background, lg, secondaryText, sm } from 'src/theme/variables'
import { createStyles } from '@material-ui/core'
export const styles = () => ({ export const styles = createStyles({
heading: { heading: {
padding: lg, padding: lg,
justifyContent: 'space-between', justifyContent: 'space-between',

View File

@ -8,7 +8,7 @@ import { getAddressValidator } from './validators'
import QRIcon from 'src/assets/icons/qrcode.svg' import QRIcon from 'src/assets/icons/qrcode.svg'
import trash from 'src/assets/icons/trash.svg' import trash from 'src/assets/icons/trash.svg'
import ScanQRModal from 'src/components/ScanQRModal' import { ScanQRModal } from 'src/components/ScanQRModal'
import OpenPaper from 'src/components/Stepper/OpenPaper' import OpenPaper from 'src/components/Stepper/OpenPaper'
import AddressInput from 'src/components/forms/AddressInput' import AddressInput from 'src/components/forms/AddressInput'
import Field from 'src/components/forms/Field' import Field from 'src/components/forms/Field'
@ -97,10 +97,10 @@ const SafeOwnersForm = (props): React.ReactElement => {
setNumOwners(numOwners + 1) setNumOwners(numOwners + 1)
} }
const handleScan = (value) => { const handleScan = (value: string | null) => {
let scannedAddress = value let scannedAddress = value
if (scannedAddress.startsWith('ethereum:')) { if (scannedAddress?.startsWith('ethereum:')) {
scannedAddress = scannedAddress.replace('ethereum:', '') scannedAddress = scannedAddress.replace('ethereum:', '')
} }

View File

@ -27,7 +27,7 @@ export interface EthAddressInputProps {
text: string text: string
} }
const EthAddressInput = ({ export const EthAddressInput = ({
isContract = true, isContract = true,
isRequired = true, isRequired = true,
name, name,
@ -57,6 +57,7 @@ const EthAddressInput = ({
scannedAddress = scannedAddress.replace('ethereum:', '') scannedAddress = scannedAddress.replace('ethereum:', '')
} }
setSelectedEntry({ address: scannedAddress })
onScannedValue(scannedAddress) onScannedValue(scannedAddress)
closeQrModal() closeQrModal()
} }
@ -97,5 +98,3 @@ const EthAddressInput = ({
</> </>
) )
} }
export default EthAddressInput

View File

@ -22,7 +22,7 @@ import Hairline from 'src/components/layout/Hairline'
import Img from 'src/components/layout/Img' import Img from 'src/components/layout/Img'
import Paragraph from 'src/components/layout/Paragraph' import Paragraph from 'src/components/layout/Paragraph'
import Row from 'src/components/layout/Row' import Row from 'src/components/layout/Row'
import ScanQRModal from 'src/components/ScanQRModal' import { ScanQRModal } from 'src/components/ScanQRModal'
import { safeSelector } from 'src/logic/safe/store/selectors' import { safeSelector } from 'src/logic/safe/store/selectors'
import SafeInfo from 'src/routes/safe/components/Balances/SendModal/SafeInfo' import SafeInfo from 'src/routes/safe/components/Balances/SendModal/SafeInfo'
import { ContractsAddressBookInput } from 'src/routes/safe/components/Balances/SendModal/screens/AddressBookInput' import { ContractsAddressBookInput } from 'src/routes/safe/components/Balances/SendModal/screens/AddressBookInput'

View File

@ -11,7 +11,7 @@ import { safeSelector } from 'src/logic/safe/store/selectors'
import Paragraph from 'src/components/layout/Paragraph' import Paragraph from 'src/components/layout/Paragraph'
import Buttons from './Buttons' import Buttons from './Buttons'
import ContractABI from './ContractABI' import ContractABI from './ContractABI'
import EthAddressInput from './EthAddressInput' import { EthAddressInput } from './EthAddressInput'
import FormDivisor from './FormDivisor' import FormDivisor from './FormDivisor'
import FormErrorMessage from './FormErrorMessage' import FormErrorMessage from './FormErrorMessage'
import Header from './Header' import Header from './Header'