Skip to content
This repository has been archived by the owner on Apr 28, 2023. It is now read-only.

Commit

Permalink
feat: add QR code scanner (#221)
Browse files Browse the repository at this point in the history
  • Loading branch information
michael1011 authored Sep 28, 2019
1 parent 005d107 commit e0ce5c3
Show file tree
Hide file tree
Showing 8 changed files with 189 additions and 27 deletions.
37 changes: 37 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"react-jss": "^8.6.1",
"react-loader-spinner": "^3.1.2",
"react-notifications-component": "^1.1.1",
"react-qr-reader": "^2.2.1",
"react-redux": "^7.1.0",
"react-responsive-modal": "^4.0.1",
"react-router-dom": "^5.0.1",
Expand Down
1 change: 1 addition & 0 deletions src/asset/icons/camera_icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
166 changes: 144 additions & 22 deletions src/components/inputarea/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import React from 'react';
import injectSheet from 'react-jss';
import PropTypes from 'prop-types';
import injectSheet from 'react-jss';
import QrReader from 'react-qr-reader';
import ReactNotification from 'react-notifications-component';
import { notificationData } from '../../utils';

const cameraIcon = require('../../asset/icons/camera_icon.svg');

const styles = theme => ({
wrapper: {
formGroup: {
position: 'relative',
},
textBox: {
border: 'none',
resize: 'none',
fontSize: '18px',
Expand All @@ -18,27 +26,141 @@ const styles = theme => ({
width: () => `${300}px`,
},
},
cameraIcon: {
width: '32px',
height: '32px',
position: 'absolute',
right: '5px',
bottom: '6px',
cursor: 'pointer',
},
qrScannerWrapper: {
position: 'fixed',
height: '300px',
width: '300px',
top: '50%',
left: '50%',
marginTop: '-150px',
marginLeft: '-150px',
zIndex: '99999999999999999999',
},
});

const InputArea = ({
classes,
autoFocus,
height,
width,
onChange,
value,
placeholder,
}) => (
<textarea
autoFocus={autoFocus}
value={value}
placeholder={placeholder}
className={classes.wrapper}
rows={height}
cols={width}
onChange={e => onChange(e.target.value)}
/>
);
class InputArea extends React.Component {
constructor(props) {
super(props);

this.notificationDom = React.createRef();

this.state = {
value: '',
openScanner: false,
};
}

clickListener = () => {
this.setState({
openScanner: false,
});

document.removeEventListener('click', this.clickListener);
};

openScanner = () => {
document.addEventListener('click', this.clickListener);

this.setState({
openScanner: true,
});
};

handleScan = data => {
if (data !== null) {
console.log(`Scanned QR code: ${data}`);

this.props.onChange(data);

this.setState({
value: data,
openScanner: false,
});
}
};

handleScanError = error => {
this.setState({
openScanner: false,
});

const errorMessage = {
title: 'Could not scan QR code',
message: error.toString(),
};

console.log(`${errorMessage.title}: ${errorMessage.message}`);

this.notificationDom.current.addNotification(
notificationData(errorMessage, 1)
);
};

render() {
const {
classes,
autoFocus,
height,
width,
onChange,
placeholder,
showQrScanner,
} = this.props;

return (
<div className={classes.formGroup}>
<ReactNotification ref={this.notificationDom} />
<textarea
autoFocus={autoFocus}
value={this.state.value}
placeholder={placeholder}
className={classes.textBox}
rows={height}
cols={width}
onChange={event => {
const newValue = event.target.value;

this.setState({
value: newValue,
});
onChange(newValue);
}}
/>
{this.state.openScanner ? (
<div className={classes.qrScannerWrapper}>
<QrReader
delay={500}
onScan={this.handleScan}
onError={this.handleScanError}
className={classes.qrScanner}
style={{ width: '100%' }}
/>
</div>
) : (
undefined
)}
{showQrScanner ? (
<img
className={classes.cameraIcon}
src={cameraIcon}
alt={'Scan QR code'}
onClick={this.openScanner}
/>
) : (
undefined
)}
</div>
);
}
}

InputArea.propTypes = {
classes: PropTypes.object.isRequired,
Expand All @@ -47,8 +169,8 @@ InputArea.propTypes = {
onChange: PropTypes.func.isRequired,
error: PropTypes.bool.isRequired,
autoFocus: PropTypes.bool,
value: PropTypes.string,
placeholder: PropTypes.string,
showQrScanner: PropTypes.bool,
};

export default injectSheet(styles)(InputArea);
2 changes: 0 additions & 2 deletions src/constants/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ export const boltzApi =
? process.env.REACT_APP_BOLTZ_API
: process.env.REACT_APP_BOLTZ_API_ONION;

console.log(boltzApi);

// LND node URIs
export const bitcoinLnd = process.env.REACT_APP_BITCOIN_LND;
export const bitcoinLndOnion = process.env.REACT_APP_BITCOIN_LND_ONION;
Expand Down
1 change: 1 addition & 0 deletions src/views/refund/steps/InputDestinationAddress.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const StyledInputDestinationAddress = ({
<InputArea
height={150}
width={500}
showQrScanner={true}
onChange={setDestinationAddress}
placeholder={`EG: ${getSampleAddress(currency)}`}
/>
Expand Down
5 changes: 3 additions & 2 deletions src/views/reverse/steps/inputAddress.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,15 @@ class StyledInputAddress extends React.Component {
return (
<View className={classes.wrapper}>
<p className={classes.title}>
Paste a <b>{getCurrencyName(swapInfo.quote)}</b> address to which you
want to receive
Paste or scan a <b>{getCurrencyName(swapInfo.quote)}</b> address to
which you want to receive
</p>
<InputArea
width={600}
autoFocus={true}
height={150}
error={error}
showQrScanner={true}
onChange={this.onChange}
placeholder={`EG: ${getSampleAddress(swapInfo.quote)}`}
/>
Expand Down
3 changes: 2 additions & 1 deletion src/views/swap/steps/inputInvoice.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ class StyledInputInvoice extends React.Component {
return (
<View className={classes.wrapper}>
<p className={classes.title}>
Paste a <b>{getCurrencyName(swapInfo.quote)}</b> Lightning {}
Paste or scan a <b>{getCurrencyName(swapInfo.quote)}</b> Lightning {}
<FaBolt size={25} color="#FFFF00" /> invoice for <br />
<b>
{toSatoshi(swapInfo.quoteAmount)}{' '}
Expand All @@ -86,6 +86,7 @@ class StyledInputInvoice extends React.Component {
height={150}
error={error}
autoFocus={true}
showQrScanner={true}
value={this.state.value}
onChange={this.onChange}
placeholder={`EG: ${getSampleInvoice(swapInfo.quote)}`}
Expand Down

0 comments on commit e0ce5c3

Please sign in to comment.