Jack Mallers
7 years ago
11 changed files with 6 additions and 742 deletions
@ -1,93 +0,0 @@ |
|||
import React from 'react' |
|||
import PropTypes from 'prop-types' |
|||
import { MdClose } from 'react-icons/lib/md' |
|||
import Pay from './components/Pay' |
|||
import Request from './components/Request' |
|||
import styles from './Form.scss' |
|||
|
|||
const Form = ({ |
|||
form: { formType, amount, onchainAmount, message, payment_request }, |
|||
setAmount, |
|||
setOnchainAmount, |
|||
setMessage, |
|||
setPaymentRequest, |
|||
ticker: { currency, crypto }, |
|||
isOpen, |
|||
close, |
|||
createInvoice, |
|||
payInvoice, |
|||
sendCoins, |
|||
fetchInvoice, |
|||
formInvoice, |
|||
currentTicker, |
|||
isOnchain, |
|||
isLn, |
|||
sendingTransaction |
|||
}) => ( |
|||
<div className={`${styles.formContainer} ${isOpen ? styles.open : ''}`}> |
|||
<div className={styles.container}> |
|||
<div className={styles.esc} onClick={close}> |
|||
<MdClose /> |
|||
</div> |
|||
<div className={styles.content}> |
|||
{ |
|||
formType === 'pay' ? |
|||
<Pay |
|||
sendingTransaction={sendingTransaction} |
|||
invoiceAmount={formInvoice.amount} |
|||
onchainAmount={onchainAmount} |
|||
setOnchainAmount={setOnchainAmount} |
|||
amount={formInvoice.amount} |
|||
payment_request={payment_request} |
|||
setPaymentRequest={setPaymentRequest} |
|||
fetchInvoice={fetchInvoice} |
|||
payInvoice={payInvoice} |
|||
sendCoins={sendCoins} |
|||
currentTicker={currentTicker} |
|||
currency={currency} |
|||
crypto={crypto} |
|||
close={close} |
|||
isOnchain={isOnchain} |
|||
isLn={isLn} |
|||
/> |
|||
: |
|||
<Request |
|||
amount={amount} |
|||
setAmount={setAmount} |
|||
payment_request={payment_request} |
|||
setMessage={setMessage} |
|||
createInvoice={createInvoice} |
|||
message={message} |
|||
currentTicker={currentTicker} |
|||
currency={currency} |
|||
crypto={crypto} |
|||
close={close} |
|||
/> |
|||
|
|||
} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
) |
|||
|
|||
Form.propTypes = { |
|||
form: PropTypes.object.isRequired, |
|||
ticker: PropTypes.object.isRequired, |
|||
setAmount: PropTypes.func.isRequired, |
|||
setOnchainAmount: PropTypes.func.isRequired, |
|||
setMessage: PropTypes.func.isRequired, |
|||
setPaymentRequest: PropTypes.func.isRequired, |
|||
isOpen: PropTypes.bool.isRequired, |
|||
close: PropTypes.func.isRequired, |
|||
createInvoice: PropTypes.func.isRequired, |
|||
payInvoice: PropTypes.func.isRequired, |
|||
sendCoins: PropTypes.func.isRequired, |
|||
fetchInvoice: PropTypes.func.isRequired, |
|||
formInvoice: PropTypes.object.isRequired, |
|||
currentTicker: PropTypes.object.isRequired, |
|||
isOnchain: PropTypes.bool.isRequired, |
|||
isLn: PropTypes.bool.isRequired, |
|||
sendingTransaction: PropTypes.bool.isRequired |
|||
} |
|||
|
|||
export default Form |
@ -1,159 +0,0 @@ |
|||
@import '../../../../../variables.scss'; |
|||
|
|||
.formContainer { |
|||
position: absolute; |
|||
top: 0; |
|||
bottom: 0; |
|||
width: 100%; |
|||
height: 100vh; |
|||
background: $white; |
|||
z-index: 0; |
|||
opacity: 0; |
|||
transition: all 0.5s; |
|||
|
|||
&.open { |
|||
opacity: 1; |
|||
z-index: 10; |
|||
} |
|||
} |
|||
|
|||
.container { |
|||
position: relative; |
|||
height: 100vh; |
|||
margin: 5%; |
|||
} |
|||
|
|||
.esc { |
|||
position: absolute; |
|||
top: 0; |
|||
right: 0; |
|||
color: $darkestgrey; |
|||
cursor: pointer; |
|||
padding: 20px; |
|||
border-radius: 50%; |
|||
|
|||
&:hover { |
|||
color: $bluegrey; |
|||
background: $darkgrey; |
|||
} |
|||
|
|||
&:active { |
|||
color: $white; |
|||
background: $main; |
|||
} |
|||
|
|||
svg { |
|||
width: 32px; |
|||
height: 32px; |
|||
} |
|||
} |
|||
|
|||
.content { |
|||
width: 50%; |
|||
margin: 0 auto; |
|||
display: flex; |
|||
flex-direction: column; |
|||
height: 75vh; |
|||
justify-content: center; |
|||
align-items: center; |
|||
|
|||
.amountContainer { |
|||
color: $main; |
|||
display: flex; |
|||
justify-content: center; |
|||
min-height: 120px; |
|||
margin-bottom: 20px; |
|||
|
|||
label, input[type=text] { |
|||
color: inherit; |
|||
display: inline-block; |
|||
vertical-align: top; |
|||
padding: 0; |
|||
} |
|||
|
|||
label { |
|||
svg { |
|||
width: 85px; |
|||
height: 85px; |
|||
} |
|||
|
|||
svg[data-icon='ltc'] { |
|||
margin-right: 10px; |
|||
|
|||
g { |
|||
transform: scale(1.75) translate(-5px, -5px); |
|||
} |
|||
} |
|||
} |
|||
|
|||
input[type=text] { |
|||
width: 100px; |
|||
font-size: 180px; |
|||
border: none; |
|||
outline: 0; |
|||
-webkit-appearance: none; |
|||
} |
|||
} |
|||
|
|||
.inputContainer { |
|||
width: 100%; |
|||
display: flex; |
|||
justify-content: center; |
|||
font-size: 18px; |
|||
height: auto; |
|||
min-height: 55px; |
|||
margin-bottom: 20px; |
|||
border: 1px solid $traditionalgrey; |
|||
border-radius: 6px; |
|||
position: relative; |
|||
padding: 0 20px; |
|||
|
|||
label, input[type=text] { |
|||
font-size: inherit; |
|||
} |
|||
|
|||
label { |
|||
padding-top: 19px; |
|||
padding-bottom: 12px; |
|||
color: $traditionalgrey; |
|||
} |
|||
|
|||
input[type=text] { |
|||
width: 100%; |
|||
border: none; |
|||
outline: 0; |
|||
-webkit-appearance: none; |
|||
height: 55px; |
|||
padding: 0 10px; |
|||
} |
|||
} |
|||
|
|||
.buttonGroup { |
|||
width: 100%; |
|||
display: flex; |
|||
flex-direction: row; |
|||
border-radius: 6px; |
|||
overflow: hidden; |
|||
|
|||
.button { |
|||
cursor: pointer; |
|||
height: 55px; |
|||
min-height: 55px; |
|||
text-transform: none; |
|||
font-size: 18px; |
|||
transition: opacity .2s ease-out; |
|||
background: $main; |
|||
color: $white; |
|||
border: none; |
|||
font-weight: 500; |
|||
padding: 0; |
|||
width: 100%; |
|||
text-align: center; |
|||
line-height: 55px; |
|||
|
|||
&:first-child { |
|||
border-right: 1px solid lighten($main, 20%); |
|||
} |
|||
} |
|||
} |
|||
} |
@ -1,149 +0,0 @@ |
|||
import React, { Component } from 'react' |
|||
import PropTypes from 'prop-types' |
|||
import { FaBolt, FaChain } from 'react-icons/lib/fa' |
|||
import CurrencyIcon from 'components/CurrencyIcon' |
|||
import LoadingBolt from 'components/LoadingBolt' |
|||
import { btc } from 'utils' |
|||
import styles from './Pay.scss' |
|||
|
|||
class Pay extends Component { |
|||
componentDidUpdate(prevProps) { |
|||
const { isOnchain, isLn, fetchInvoice, payment_request } = this.props |
|||
|
|||
if (isOnchain) { this.amountInput.focus() } |
|||
if ((prevProps.payment_request !== payment_request) && isLn) { fetchInvoice(payment_request) } |
|||
} |
|||
|
|||
render() { |
|||
const { |
|||
sendingTransaction, |
|||
invoiceAmount, |
|||
onchainAmount, |
|||
setOnchainAmount, |
|||
payment_request, |
|||
setPaymentRequest, |
|||
payInvoice, |
|||
sendCoins, |
|||
currentTicker, |
|||
currency, |
|||
crypto, |
|||
isOnchain, |
|||
isLn |
|||
} = this.props |
|||
|
|||
const payClicked = () => { |
|||
if (!isOnchain && !isLn) { return } |
|||
|
|||
if (isOnchain) { sendCoins({ value: onchainAmount, addr: payment_request, currency, rate: currentTicker.price_usd }) } |
|||
if (isLn) { payInvoice(payment_request) } |
|||
} |
|||
|
|||
const calculateAmount = value => (currency === 'usd' ? btc.satoshisToUsd(value, currentTicker.price_usd) : btc.satoshisToBtc(value)) |
|||
|
|||
return ( |
|||
<div> |
|||
{ |
|||
sendingTransaction ? |
|||
<LoadingBolt /> |
|||
: |
|||
null |
|||
|
|||
} |
|||
<div className={styles.container}> |
|||
<section className={`${styles.amountContainer} ${isLn ? styles.ln : ''}`}> |
|||
<label htmlFor='amount'> |
|||
<CurrencyIcon currency={currency} crypto={crypto} /> |
|||
</label> |
|||
<input |
|||
type='text' |
|||
ref={input => this.amountInput = input} // eslint-disable-line
|
|||
size='' |
|||
style={ |
|||
isLn ? |
|||
{ width: '75%', fontSize: '85px' } |
|||
: |
|||
{ width: `${onchainAmount.length > 1 ? (onchainAmount.length * 15) - 5 : 25}%`, fontSize: `${190 - (onchainAmount.length ** 2)}px` } |
|||
} |
|||
value={isLn ? calculateAmount(invoiceAmount) : onchainAmount} |
|||
onChange={event => setOnchainAmount(event.target.value)} |
|||
id='amount' |
|||
readOnly={isLn} |
|||
/> |
|||
</section> |
|||
<div className={styles.inputContainer}> |
|||
<div className={styles.info}> |
|||
{(() => { |
|||
if (isOnchain) { |
|||
return ( |
|||
<span>{`You're about to send ${onchainAmount} ${currency.toUpperCase()} on-chain which should take around 10 minutes`}</span> |
|||
) |
|||
} else if (isLn) { |
|||
return ( |
|||
<span>{`You're about to send ${calculateAmount(invoiceAmount)} ${currency.toUpperCase()} over the Lightning Network which will be instant`}</span> // eslint-disable-line |
|||
) |
|||
} |
|||
return null |
|||
})()} |
|||
</div> |
|||
<aside className={styles.paymentIcon}> |
|||
{(() => { |
|||
if (isOnchain) { |
|||
return ( |
|||
<i> |
|||
<span>on-chain</span> |
|||
<FaChain /> |
|||
</i> |
|||
) |
|||
} else if (isLn) { |
|||
return ( |
|||
<i> |
|||
<span>lightning network</span> |
|||
<FaBolt /> |
|||
</i> |
|||
) |
|||
} |
|||
return null |
|||
})()} |
|||
</aside> |
|||
<section className={styles.input}> |
|||
<input |
|||
type='text' |
|||
placeholder='Payment request or bitcoin address' |
|||
value={payment_request} |
|||
onChange={event => setPaymentRequest(event.target.value)} |
|||
id='paymentRequest' |
|||
/> |
|||
</section> |
|||
</div> |
|||
<section className={styles.buttonGroup}> |
|||
<div className={styles.button} onClick={payClicked}> |
|||
Pay |
|||
</div> |
|||
</section> |
|||
</div> |
|||
</div> |
|||
) |
|||
} |
|||
} |
|||
|
|||
Pay.propTypes = { |
|||
sendingTransaction: PropTypes.bool.isRequired, |
|||
invoiceAmount: PropTypes.oneOfType([ |
|||
PropTypes.string, |
|||
PropTypes.number |
|||
]).isRequired, |
|||
onchainAmount: PropTypes.string.isRequired, |
|||
setOnchainAmount: PropTypes.func.isRequired, |
|||
payment_request: PropTypes.string.isRequired, |
|||
setPaymentRequest: PropTypes.func.isRequired, |
|||
fetchInvoice: PropTypes.func.isRequired, |
|||
payInvoice: PropTypes.func.isRequired, |
|||
sendCoins: PropTypes.func.isRequired, |
|||
currentTicker: PropTypes.object.isRequired, |
|||
currency: PropTypes.string.isRequired, |
|||
crypto: PropTypes.string.isRequired, |
|||
isOnchain: PropTypes.bool.isRequired, |
|||
isLn: PropTypes.bool.isRequired |
|||
} |
|||
|
|||
export default Pay |
@ -1,142 +0,0 @@ |
|||
@import '../../../../../../../variables.scss'; |
|||
|
|||
.container { |
|||
margin: 0 auto; |
|||
display: flex; |
|||
flex-direction: column; |
|||
height: 75vh; |
|||
justify-content: center; |
|||
align-items: center; |
|||
} |
|||
|
|||
.amountContainer { |
|||
color: $main; |
|||
display: flex; |
|||
justify-content: center; |
|||
min-height: 120px; |
|||
margin-bottom: 20px; |
|||
min-height: 175px; |
|||
|
|||
&.ln { |
|||
opacity: 0.75; |
|||
} |
|||
|
|||
label, input[type=text] { |
|||
color: inherit; |
|||
display: inline-block; |
|||
vertical-align: top; |
|||
padding: 0; |
|||
} |
|||
|
|||
label { |
|||
svg { |
|||
width: 85px; |
|||
height: 85px; |
|||
} |
|||
|
|||
svg[data-icon='ltc'] { |
|||
margin-right: 10px; |
|||
|
|||
g { |
|||
transform: scale(1.75) translate(-5px, -5px); |
|||
} |
|||
} |
|||
} |
|||
|
|||
input[type=text] { |
|||
width: 100px; |
|||
font-size: 180px; |
|||
border: none; |
|||
outline: 0; |
|||
-webkit-appearance: none; |
|||
} |
|||
} |
|||
|
|||
.inputContainer { |
|||
position: relative; |
|||
width: 100%; |
|||
padding: 40px 0; |
|||
cursor: pointer; |
|||
|
|||
.info { |
|||
margin-bottom: 10px; |
|||
min-height: 19px; |
|||
} |
|||
|
|||
.paymentIcon { |
|||
position: absolute; |
|||
width: 20%; |
|||
left: calc(-12.5% - 75px); |
|||
top: 42px; |
|||
color: $main; |
|||
font-size: 50px; |
|||
text-align: center; |
|||
|
|||
span { |
|||
text-transform: uppercase; |
|||
display: block; |
|||
font-size: 12px; |
|||
font-weight: 200; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.input { |
|||
display: flex; |
|||
justify-content: center; |
|||
font-size: 18px; |
|||
height: auto; |
|||
min-height: 55px; |
|||
border: 1px solid $traditionalgrey; |
|||
border-radius: 6px; |
|||
position: relative; |
|||
padding: 0 20px; |
|||
|
|||
label, input[type=text] { |
|||
font-size: inherit; |
|||
} |
|||
|
|||
label { |
|||
padding-top: 19px; |
|||
padding-bottom: 12px; |
|||
color: $traditionalgrey; |
|||
} |
|||
|
|||
input[type=text] { |
|||
width: 100%; |
|||
border: none; |
|||
outline: 0; |
|||
-webkit-appearance: none; |
|||
height: 55px; |
|||
padding: 0 10px; |
|||
} |
|||
} |
|||
|
|||
.buttonGroup { |
|||
width: 100%; |
|||
display: flex; |
|||
flex-direction: row; |
|||
border-radius: 6px; |
|||
overflow: hidden; |
|||
|
|||
.button { |
|||
cursor: pointer; |
|||
height: 55px; |
|||
min-height: 55px; |
|||
text-transform: none; |
|||
font-size: 18px; |
|||
transition: opacity .2s ease-out; |
|||
background: $main; |
|||
color: $white; |
|||
border: none; |
|||
font-weight: 500; |
|||
padding: 0; |
|||
width: 100%; |
|||
text-align: center; |
|||
line-height: 55px; |
|||
|
|||
&:first-child { |
|||
border-right: 1px solid lighten($main, 20%); |
|||
} |
|||
} |
|||
} |
@ -1,3 +0,0 @@ |
|||
import Pay from './Pay' |
|||
|
|||
export default Pay |
@ -1,68 +0,0 @@ |
|||
import React from 'react' |
|||
import PropTypes from 'prop-types' |
|||
import CurrencyIcon from 'components/CurrencyIcon' |
|||
import styles from './Request.scss' |
|||
|
|||
const Request = ({ |
|||
amount, |
|||
setAmount, |
|||
setMessage, |
|||
createInvoice, |
|||
message, |
|||
currentTicker, |
|||
currency, |
|||
crypto, |
|||
close |
|||
}) => { |
|||
const requestClicked = () => { |
|||
createInvoice(amount, message, currency, currentTicker.price_usd) |
|||
close() |
|||
} |
|||
|
|||
return ( |
|||
<div className={styles.container}> |
|||
<section className={styles.amountContainer}> |
|||
<label htmlFor='amount'> |
|||
<CurrencyIcon currency={currency} crypto={crypto} /> |
|||
</label> |
|||
<input |
|||
type='text' |
|||
size='' |
|||
style={{ width: `${amount.length > 1 ? (amount.length * 15) - 5 : 25}%`, fontSize: `${190 - (amount.length ** 2)}px` }} |
|||
value={amount} |
|||
onChange={event => setAmount(event.target.value)} |
|||
id='amount' |
|||
/> |
|||
</section> |
|||
<section className={styles.inputContainer}> |
|||
<label htmlFor='paymentRequest'>Request:</label> |
|||
<input |
|||
type='text' |
|||
placeholder='Dinner, Rent, etc' |
|||
value={message} |
|||
onChange={event => setMessage(event.target.value)} |
|||
id='paymentRequest' |
|||
/> |
|||
</section> |
|||
<section className={styles.buttonGroup}> |
|||
<div className={styles.button} onClick={requestClicked}> |
|||
Request |
|||
</div> |
|||
</section> |
|||
</div> |
|||
) |
|||
} |
|||
|
|||
Request.propTypes = { |
|||
amount: PropTypes.string.isRequired, |
|||
setAmount: PropTypes.func.isRequired, |
|||
setMessage: PropTypes.func.isRequired, |
|||
createInvoice: PropTypes.func.isRequired, |
|||
message: PropTypes.string.isRequired, |
|||
currentTicker: PropTypes.object.isRequired, |
|||
currency: PropTypes.string.isRequired, |
|||
crypto: PropTypes.string.isRequired, |
|||
close: PropTypes.func.isRequired |
|||
} |
|||
|
|||
export default Request |
@ -1,110 +0,0 @@ |
|||
@import '../../../../../../../variables.scss'; |
|||
|
|||
.container { |
|||
margin: 0 auto; |
|||
display: flex; |
|||
flex-direction: column; |
|||
height: 75vh; |
|||
justify-content: center; |
|||
align-items: center; |
|||
} |
|||
|
|||
.amountContainer { |
|||
color: $main; |
|||
display: flex; |
|||
justify-content: center; |
|||
min-height: 120px; |
|||
margin-bottom: 20px; |
|||
|
|||
label, input[type=text] { |
|||
color: inherit; |
|||
display: inline-block; |
|||
vertical-align: top; |
|||
padding: 0; |
|||
} |
|||
|
|||
label { |
|||
svg { |
|||
width: 85px; |
|||
height: 85px; |
|||
} |
|||
|
|||
svg[data-icon='ltc'] { |
|||
margin-right: 10px; |
|||
|
|||
g { |
|||
transform: scale(1.75) translate(-5px, -5px); |
|||
} |
|||
} |
|||
} |
|||
|
|||
input[type=text] { |
|||
width: 100px; |
|||
font-size: 180px; |
|||
border: none; |
|||
outline: 0; |
|||
-webkit-appearance: none; |
|||
} |
|||
} |
|||
|
|||
.inputContainer { |
|||
width: 100%; |
|||
display: flex; |
|||
justify-content: center; |
|||
font-size: 18px; |
|||
height: auto; |
|||
min-height: 55px; |
|||
margin-bottom: 20px; |
|||
border: 1px solid $traditionalgrey; |
|||
border-radius: 6px; |
|||
position: relative; |
|||
padding: 0 20px; |
|||
|
|||
label, input[type=text] { |
|||
font-size: inherit; |
|||
} |
|||
|
|||
label { |
|||
padding-top: 19px; |
|||
padding-bottom: 12px; |
|||
color: $traditionalgrey; |
|||
} |
|||
|
|||
input[type=text] { |
|||
width: 100%; |
|||
border: none; |
|||
outline: 0; |
|||
-webkit-appearance: none; |
|||
height: 55px; |
|||
padding: 0 10px; |
|||
} |
|||
} |
|||
|
|||
.buttonGroup { |
|||
width: 100%; |
|||
display: flex; |
|||
flex-direction: row; |
|||
border-radius: 6px; |
|||
overflow: hidden; |
|||
|
|||
.button { |
|||
cursor: pointer; |
|||
height: 55px; |
|||
min-height: 55px; |
|||
text-transform: none; |
|||
font-size: 18px; |
|||
transition: opacity .2s ease-out; |
|||
background: $main; |
|||
color: $white; |
|||
border: none; |
|||
font-weight: 500; |
|||
padding: 0; |
|||
width: 100%; |
|||
text-align: center; |
|||
line-height: 55px; |
|||
|
|||
&:first-child { |
|||
border-right: 1px solid lighten($main, 20%); |
|||
} |
|||
} |
|||
} |
@ -1,3 +0,0 @@ |
|||
import Request from './Request' |
|||
|
|||
export default Request |
@ -1,3 +0,0 @@ |
|||
import Form from './Form' |
|||
|
|||
export default Form |
Loading…
Reference in new issue