* 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:
parent
486bb4b203
commit
e482d3259b
|
@ -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)',
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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)
|
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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:', '')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -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'
|
||||||
|
|
Loading…
Reference in New Issue