Swap Part 5 (#150)

* refactor notificationMessage

* MVP Bitcoin QR

* refactor currentrates and add loading state

* fix text space

* translate hardcoded text

* only show QR code when attempting to swap Bitcoin as the origin kind

* remove commented import

* add flow typings

* Don't show a notification of a stringified element
This commit is contained in:
Daniel Ternyak 2017-08-31 08:56:49 -07:00 committed by GitHub
parent a4ec6f6139
commit efee709d0f
8 changed files with 95 additions and 69 deletions

View File

@ -0,0 +1,39 @@
import React, { Component } from 'react';
import QRCode from 'qrcode.react';
type Props = {
paymentAddress: string,
amount: number
};
export default class BitcoinQR extends Component {
props: Props;
render() {
const { paymentAddress, amount } = this.props;
return (
<div>
<section className="row block swap-address text-center">
<label> Your Address </label>
<div className="qr-code">
<QRCode value={`bitcoin:${paymentAddress}amount=${amount}`} />
</div>
<br />
<p className="text-danger">
Orders that take too long will have to be processed manually &amp;
and may delay the amount of time it takes to receive your coins.
<br />
<a
href="https://shapeshift.io/#/btcfee"
target="_blank"
rel="noopener"
>
Please use the recommended TX fees seen here.
</a>
</p>
</section>
</div>
);
}
}

View File

@ -5,6 +5,7 @@ import { toFixedIfLarger } from 'utils/formatters';
import type { Pairs } from 'actions/swapTypes'; import type { Pairs } from 'actions/swapTypes';
import { bityReferralURL } from 'config/data'; import { bityReferralURL } from 'config/data';
import bityLogoWhite from 'assets/images/logo-bity-white.svg'; import bityLogoWhite from 'assets/images/logo-bity-white.svg';
import Spinner from 'components/ui/Spinner';
export default class CurrentRates extends Component { export default class CurrentRates extends Component {
props: Pairs; props: Pairs;
@ -25,9 +26,29 @@ export default class CurrentRates extends Component {
}); });
}; };
render() { buildPairRate = (origin: string, destination: string) => {
const { ETHBTC, ETHREP, BTCETH, BTCREP } = this.props; const pair = origin + destination;
const statePair = this.state[pair + 'Amount'];
const propsPair = this.props[pair];
return !propsPair
? <Spinner />
: <p className="mono">
<input
className="form-control input-sm"
onChange={this.onChange}
value={statePair}
name={pair + 'Amount'}
/>
<span>
{` ${origin} = ${toFixedIfLarger(
statePair * propsPair,
6
)} ${destination}`}
</span>
</p>;
};
render() {
return ( return (
<article className="swap-rates"> <article className="swap-rates">
<section className="row"> <section className="row">
@ -36,66 +57,18 @@ export default class CurrentRates extends Component {
</h5> </h5>
</section> </section>
<section className="row order-panel"> <section className="row order-panel">
<div className="col-sm-6 order-info"> {
<p className="mono"> <div>
<input <div className="col-sm-6 order-info">
className="form-control input-sm" {this.buildPairRate('ETH', 'BTC')}
onChange={this.onChange} {this.buildPairRate('ETH', 'REP')}
value={this.state.ETHBTCAmount} </div>
name="ETHBTCAmount" <div className="col-sm-6 order-info">
/> {this.buildPairRate('BTC', 'ETH')}
<span> {this.buildPairRate('BTC', 'REP')}
{` ETH = ${toFixedIfLarger( </div>
this.state.ETHBTCAmount * ETHBTC, </div>
6 }
)} BTC`}
</span>
</p>
<p className="mono">
<input
className="form-control input-sm"
onChange={this.onChange}
value={this.state.ETHREPAmount}
name="ETHREPAmount"
/>
<span>
{` ETH = ${toFixedIfLarger(
this.state.ETHREPAmount * ETHREP,
6
)} REP`}
</span>
</p>
</div>
<div className="col-sm-6 order-info">
<p className="mono">
<input
className="form-control input-sm"
onChange={this.onChange}
value={this.state.BTCETHAmount}
name="BTCETHAmount"
/>
<span>
{` BTC = ${toFixedIfLarger(
this.state.BTCETHAmount * BTCETH,
6
)} ETH`}
</span>
</p>
<p className="mono">
<input
className="form-control input-sm"
onChange={this.onChange}
value={this.state.BTCREPAmount}
name="BTCREPAmount"
/>
<span>
{` BTC = ${toFixedIfLarger(
this.state.BTCREPAmount * BTCREP,
6
)} REP`}
</span>
</p>
</div>
<a className="link bity-logo" href={bityReferralURL} target="_blank"> <a className="link bity-logo" href={bityReferralURL} target="_blank">
<img src={bityLogoWhite} width={120} height={49} /> <img src={bityLogoWhite} width={120} height={49} />
</a> </a>

View File

@ -6,6 +6,7 @@ import type {
} from 'actions/swap'; } from 'actions/swap';
import SwapProgress from './SwapProgress'; import SwapProgress from './SwapProgress';
import PaymentInfo from './PaymentInfo'; import PaymentInfo from './PaymentInfo';
import BitcoinQR from './BitcoinQR';
type ReduxStateProps = { type ReduxStateProps = {
destinationAddress: string, destinationAddress: string,
@ -77,6 +78,7 @@ export default class PartThree extends Component {
<div> <div>
<SwapProgress {...SwapProgressProps} /> <SwapProgress {...SwapProgressProps} />
<PaymentInfo {...PaymentInfoProps} /> <PaymentInfo {...PaymentInfoProps} />
{orderStatus === 'OPEN' && originKind === 'BTC' && <BitcoinQR />}
</div> </div>
); );
} }

View File

@ -18,7 +18,7 @@ export default class PaymentInfo extends Component {
{translate('SWAP_order_CTA')} {translate('SWAP_order_CTA')}
</span> </span>
<strong> <strong>
{this.props.originAmount} {this.props.originKind}{' '} {' '}{this.props.originAmount} {this.props.originKind}{' '}
</strong> </strong>
<span> <span>
{translate('SENDModal_Content_2')} {translate('SENDModal_Content_2')}

View File

@ -40,12 +40,13 @@ export default class SwapProgress extends Component {
if (!hasShownViewTx) { if (!hasShownViewTx) {
let linkElement; let linkElement;
let link; let link;
const notificationMessage = translate('SUCCESS_3', true) + outputTx;
// everything but BTC is a token // everything but BTC is a token
if (destinationKind !== 'BTC') { if (destinationKind !== 'BTC') {
link = bityConfig.ethExplorer.replace('[[txHash]]', outputTx); link = bityConfig.ethExplorer.replace('[[txHash]]', outputTx);
linkElement = ( linkElement = (
<a href={link} target="_blank" rel="noopener"> <a href={link} target="_blank" rel="noopener">
{' '}View your transaction{' '} ${notificationMessage}
</a> </a>
); );
// BTC uses a different explorer // BTC uses a different explorer
@ -53,7 +54,7 @@ export default class SwapProgress extends Component {
link = bityConfig.btcExplorer.replace('[[txHash]]', outputTx); link = bityConfig.btcExplorer.replace('[[txHash]]', outputTx);
linkElement = ( linkElement = (
<a href={link} target="_blank" rel="noopener"> <a href={link} target="_blank" rel="noopener">
{' '}View your transaction{' '} ${notificationMessage}
</a> </a>
); );
} }

View File

@ -138,7 +138,6 @@ export function* bityTimeRemaining() {
yield put(orderTimeSwap(0)); yield put(orderTimeSwap(0));
yield put(stopPollBityOrderStatus()); yield put(stopPollBityOrderStatus());
yield put({ type: 'SWAP_STOP_LOAD_BITY_RATES' }); yield put({ type: 'SWAP_STOP_LOAD_BITY_RATES' });
if (!hasShownNotification) { if (!hasShownNotification) {
hasShownNotification = true; hasShownNotification = true;
yield put( yield put(
@ -147,7 +146,6 @@ export function* bityTimeRemaining() {
} }
break; break;
case 'CANC': case 'CANC':
yield put(orderTimeSwap(0));
yield put(stopPollBityOrderStatus()); yield put(stopPollBityOrderStatus());
yield put({ type: 'SWAP_STOP_LOAD_BITY_RATES' }); yield put({ type: 'SWAP_STOP_LOAD_BITY_RATES' });
if (!hasShownNotification) { if (!hasShownNotification) {
@ -158,7 +156,6 @@ export function* bityTimeRemaining() {
} }
break; break;
case 'RCVE': case 'RCVE':
yield put(orderTimeSwap(0));
if (!hasShownNotification) { if (!hasShownNotification) {
hasShownNotification = true; hasShownNotification = true;
yield put( yield put(
@ -167,7 +164,6 @@ export function* bityTimeRemaining() {
} }
break; break;
case 'FILL': case 'FILL':
yield put(orderTimeSwap(0));
yield put(stopPollBityOrderStatus()); yield put(stopPollBityOrderStatus());
yield put({ type: 'SWAP_STOP_LOAD_BITY_RATES' }); yield put({ type: 'SWAP_STOP_LOAD_BITY_RATES' });
break; break;

14
package-lock.json generated
View File

@ -10030,6 +10030,11 @@
"integrity": "sha1-3QG6ydBtMObyGa7LglPunr3DCPE=", "integrity": "sha1-3QG6ydBtMObyGa7LglPunr3DCPE=",
"dev": true "dev": true
}, },
"qr.js": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/qr.js/-/qr.js-0.0.0.tgz",
"integrity": "sha1-ys6GOG9ZoNuAUPqQ2baw6IoeNk8="
},
"qrcode": { "qrcode": {
"version": "0.8.2", "version": "0.8.2",
"resolved": "https://registry.npmjs.org/qrcode/-/qrcode-0.8.2.tgz", "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-0.8.2.tgz",
@ -10048,6 +10053,15 @@
} }
} }
}, },
"qrcode.react": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/qrcode.react/-/qrcode.react-0.7.1.tgz",
"integrity": "sha1-b8UBfxcCUEiRkRVYHaXjdbCUZ0I=",
"requires": {
"prop-types": "15.5.10",
"qr.js": "0.0.0"
}
},
"qs": { "qs": {
"version": "6.4.0", "version": "6.4.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz",

View File

@ -22,6 +22,7 @@
"moment": "^2.18.1", "moment": "^2.18.1",
"prop-types": "^15.5.8", "prop-types": "^15.5.8",
"qrcode": "^0.8.2", "qrcode": "^0.8.2",
"qrcode.react": "^0.7.1",
"react": "^15.4.2", "react": "^15.4.2",
"react-dom": "^15.4.2", "react-dom": "^15.4.2",
"react-markdown": "^2.5.0", "react-markdown": "^2.5.0",