jackmallers
7 years ago
committed by
GitHub
39 changed files with 1199 additions and 210 deletions
@ -0,0 +1,50 @@ |
|||||
|
$curve: cubic-bezier(0.650, 0.000, 0.450, 1.000); |
||||
|
|
||||
|
.checkmark__circle { |
||||
|
stroke-dasharray: 166; |
||||
|
stroke-dashoffset: 166; |
||||
|
stroke-width: 2; |
||||
|
stroke-miterlimit: 10; |
||||
|
stroke: $main; |
||||
|
fill: none; |
||||
|
animation: stroke .6s $curve forwards; |
||||
|
} |
||||
|
|
||||
|
.checkmark { |
||||
|
width: 56px; |
||||
|
height: 56px; |
||||
|
border-radius: 50%; |
||||
|
stroke-width: 2; |
||||
|
stroke: #fff; |
||||
|
stroke-miterlimit: 10; |
||||
|
box-shadow: inset 0px 0px 0px $main; |
||||
|
animation: fill .4s ease-in-out .4s forwards, scale .3s ease-in-out .9s both; |
||||
|
} |
||||
|
|
||||
|
.checkmark__check { |
||||
|
transform-origin: 50% 50%; |
||||
|
stroke-dasharray: 48; |
||||
|
stroke-dashoffset: 48; |
||||
|
animation: stroke .3s $curve .8s forwards; |
||||
|
} |
||||
|
|
||||
|
@keyframes stroke { |
||||
|
100% { |
||||
|
stroke-dashoffset: 0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@keyframes scale { |
||||
|
0%, 100% { |
||||
|
transform: none; |
||||
|
} |
||||
|
50% { |
||||
|
transform: scale3d(1.1, 1.1, 1); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@keyframes fill { |
||||
|
100% { |
||||
|
box-shadow: inset 0px 0px 0px 30px $main; |
||||
|
} |
||||
|
} |
@ -0,0 +1,6 @@ |
|||||
|
import React from 'react' |
||||
|
import Isvg from 'react-inlinesvg' |
||||
|
|
||||
|
const AnimatedCheckmark = () => <Isvg src={'./components/AnimatedCheckmark/checkmark.svg'} /> |
||||
|
|
||||
|
export default AnimatedCheckmark |
After Width: | Height: | Size: 238 B |
@ -0,0 +1,3 @@ |
|||||
|
import AnimatedCheckmark from './AnimatedCheckmark' |
||||
|
|
||||
|
export default AnimatedCheckmark |
@ -0,0 +1,15 @@ |
|||||
|
import React from 'react' |
||||
|
import path from 'path' |
||||
|
import Isvg from 'react-inlinesvg' |
||||
|
import styles from './LoadingBolt.scss' |
||||
|
|
||||
|
const LoadingBolt = () => ( |
||||
|
<div className={styles.container}> |
||||
|
<div className={styles.content}> |
||||
|
<Isvg className={styles.bolt} src={path.join(__dirname, '..', 'resources/cloudbolt.svg')} /> |
||||
|
<h1>loading</h1> |
||||
|
</div> |
||||
|
</div> |
||||
|
) |
||||
|
|
||||
|
export default LoadingBolt |
@ -0,0 +1,29 @@ |
|||||
|
@import '../../variables.scss'; |
||||
|
|
||||
|
.container { |
||||
|
z-index: 1000; |
||||
|
position: absolute; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
background: $white; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.content { |
||||
|
position: relative; |
||||
|
top: calc(50% - 250px); |
||||
|
min-height: 250px; |
||||
|
|
||||
|
.bolt svg { |
||||
|
height: 150px; |
||||
|
width: 150px; |
||||
|
} |
||||
|
|
||||
|
h1 { |
||||
|
color: $main; |
||||
|
margin-top: 50px; |
||||
|
font-size: 25px; |
||||
|
} |
||||
|
} |
@ -0,0 +1,3 @@ |
|||||
|
import LoadingBolt from './LoadingBolt' |
||||
|
|
||||
|
export default LoadingBolt |
@ -0,0 +1,47 @@ |
|||||
|
// ------------------------------------
|
||||
|
// Initial State
|
||||
|
// ------------------------------------
|
||||
|
const initialState = { |
||||
|
modalType: null, |
||||
|
modalProps: {} |
||||
|
} |
||||
|
|
||||
|
// ------------------------------------
|
||||
|
// Constants
|
||||
|
// ------------------------------------
|
||||
|
export const SHOW_MODAL = 'SHOW_MODAL' |
||||
|
export const HIDE_MODAL = 'HIDE_MODAL' |
||||
|
|
||||
|
// ------------------------------------
|
||||
|
// Actions
|
||||
|
// ------------------------------------
|
||||
|
export function showModal(modalType, modalProps) { |
||||
|
return { |
||||
|
type: SHOW_MODAL, |
||||
|
modalType, |
||||
|
modalProps |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export function hideModal() { |
||||
|
return { |
||||
|
type: HIDE_MODAL |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// ------------------------------------
|
||||
|
// Action Handlers
|
||||
|
// ------------------------------------
|
||||
|
const ACTION_HANDLERS = { |
||||
|
[SHOW_MODAL]: (state, { modalType, modalProps }) => ({ ...state, modalType, modalProps }), |
||||
|
[HIDE_MODAL]: () => initialState |
||||
|
} |
||||
|
|
||||
|
// ------------------------------------
|
||||
|
// Reducer
|
||||
|
// ------------------------------------
|
||||
|
export default function modalReducer(state = initialState, action) { |
||||
|
const handler = ACTION_HANDLERS[action.type] |
||||
|
|
||||
|
return handler ? handler(state, action) : state |
||||
|
} |
@ -0,0 +1,146 @@ |
|||||
|
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 { |
||||
|
sendingPayment, |
||||
|
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> |
||||
|
{ |
||||
|
sendingPayment ? |
||||
|
<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 = { |
||||
|
sendingPayment: PropTypes.bool.isRequired, |
||||
|
invoiceAmount: PropTypes.string.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 |
@ -0,0 +1,142 @@ |
|||||
|
@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%); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,3 @@ |
|||||
|
import Pay from './Pay' |
||||
|
|
||||
|
export default Pay |
@ -0,0 +1,68 @@ |
|||||
|
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 |
@ -0,0 +1,110 @@ |
|||||
|
@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%); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,3 @@ |
|||||
|
import Request from './Request' |
||||
|
|
||||
|
export default Request |
@ -0,0 +1,42 @@ |
|||||
|
import React from 'react' |
||||
|
import PropTypes from 'prop-types' |
||||
|
import { MdClose } from 'react-icons/lib/md' |
||||
|
import SuccessfulSendCoins from './SuccessfulSendCoins' |
||||
|
import styles from './ModalRoot.scss' |
||||
|
|
||||
|
const MODAL_COMPONENTS = { |
||||
|
SUCCESSFUL_SEND_COINS: SuccessfulSendCoins |
||||
|
/* other modals */ |
||||
|
} |
||||
|
|
||||
|
const ModalRoot = ({ modalType, modalProps, hideModal, currentTicker, currency }) => { |
||||
|
if (!modalType) { return null } |
||||
|
|
||||
|
const SpecificModal = MODAL_COMPONENTS[modalType] |
||||
|
return ( |
||||
|
<div className={styles.container}> |
||||
|
<div className={styles.content}> |
||||
|
<div className={styles.esc} onClick={hideModal}> |
||||
|
<MdClose /> |
||||
|
</div> |
||||
|
|
||||
|
<SpecificModal |
||||
|
{...modalProps} |
||||
|
hideModal={hideModal} |
||||
|
currentTicker={currentTicker} |
||||
|
currency={currency} |
||||
|
/> |
||||
|
</div> |
||||
|
</div> |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
ModalRoot.propTypes = { |
||||
|
modalType: PropTypes.string, |
||||
|
modalProps: PropTypes.object.isRequired, |
||||
|
hideModal: PropTypes.func.isRequired, |
||||
|
currentTicker: PropTypes.object.isRequired, |
||||
|
currency: PropTypes.string.isRequired |
||||
|
} |
||||
|
|
||||
|
export default ModalRoot |
@ -0,0 +1,42 @@ |
|||||
|
@import '../../../../../variables.scss'; |
||||
|
|
||||
|
.container { |
||||
|
position: absolute; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
z-index: 10; |
||||
|
background: #fff; |
||||
|
} |
||||
|
|
||||
|
.content { |
||||
|
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; |
||||
|
} |
||||
|
} |
@ -0,0 +1,40 @@ |
|||||
|
import { shell } from 'electron' |
||||
|
import React from 'react' |
||||
|
import PropTypes from 'prop-types' |
||||
|
import AnimatedCheckmark from '../../../../../../components/AnimatedCheckmark' |
||||
|
import { btc } from '../../../../../../utils' |
||||
|
import styles from './SuccessfulSendCoins.scss' |
||||
|
|
||||
|
const SuccessfulSendCoins = ({ amount, addr, txid, hideModal, currentTicker, currency }) => { |
||||
|
const calculatedAmount = currency === 'usd' ? btc.satoshisToUsd(amount, currentTicker.price_usd) : btc.satoshisToBtc(amount) |
||||
|
|
||||
|
return ( |
||||
|
<div className={styles.container}> |
||||
|
<AnimatedCheckmark /> |
||||
|
<h1> |
||||
|
You |
||||
|
<span className={styles.link} onClick={() => shell.openExternal(`https://testnet.smartbit.com.au/tx/${txid}`)}>sent</span> |
||||
|
<span className={styles.amount}>{calculatedAmount} {currency.toUpperCase()}</span> |
||||
|
to |
||||
|
<span className={styles.addr}>{addr}</span> |
||||
|
</h1> |
||||
|
<div className={styles.button} onClick={hideModal}> |
||||
|
Done |
||||
|
</div> |
||||
|
</div> |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
SuccessfulSendCoins.propTypes = { |
||||
|
amount: PropTypes.oneOfType([ |
||||
|
PropTypes.number, |
||||
|
PropTypes.string |
||||
|
]).isRequired, |
||||
|
addr: PropTypes.string.isRequired, |
||||
|
txid: PropTypes.string.isRequired, |
||||
|
hideModal: PropTypes.func.isRequired, |
||||
|
currentTicker: PropTypes.object.isRequired, |
||||
|
currency: PropTypes.string.isRequired |
||||
|
} |
||||
|
|
||||
|
export default SuccessfulSendCoins |
@ -0,0 +1,37 @@ |
|||||
|
@import '../../../../../../variables.scss'; |
||||
|
|
||||
|
.container { |
||||
|
position: relative; |
||||
|
min-height: 250px; |
||||
|
top: calc(50% - 250px); |
||||
|
text-align: center; |
||||
|
|
||||
|
h1 { |
||||
|
font-size: 20px; |
||||
|
margin: 50px 0; |
||||
|
|
||||
|
.link { |
||||
|
cursor: pointer; |
||||
|
color: $main; |
||||
|
text-decoration: underline; |
||||
|
} |
||||
|
|
||||
|
.amount, .addr { |
||||
|
font-weight: bold; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.button { |
||||
|
text-align: center; |
||||
|
border-radius: 8px; |
||||
|
background: $main; |
||||
|
padding: 20px 10px; |
||||
|
font-weight: bold; |
||||
|
cursor: pointer; |
||||
|
text-transform: uppercase; |
||||
|
letter-spacing: .2px; |
||||
|
color: $white; |
||||
|
width: 15%; |
||||
|
margin: 0 auto; |
||||
|
} |
||||
|
} |
@ -0,0 +1,3 @@ |
|||||
|
import SuccessfulSendCoins from './SuccessfulSendCoins' |
||||
|
|
||||
|
export default SuccessfulSendCoins |
@ -0,0 +1,3 @@ |
|||||
|
import ModalRoot from './ModalRoot' |
||||
|
|
||||
|
export default ModalRoot |
After Width: | Height: | Size: 1.3 KiB |
@ -0,0 +1,5 @@ |
|||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 50 50" version="1.1" width="100" height="100"> |
||||
|
<g id="surface1"> |
||||
|
<path style="" class="thunderstorm-path" d="M 26 5 C 21.890625 5 18.4375 7.535156 16.90625 11.09375 C 16.605469 11.0625 16.3125 11 16 11 C 11.792969 11 8.320313 13.925781 7.34375 17.84375 C 4.210938 19.253906 2 22.351563 2 26 C 2 30.957031 6.042969 35 11 35 L 16.125 35 L 15.0625 37.625 L 14.53125 39 L 20.5625 39 L 18.0625 45.65625 L 16.9375 48.625 L 19.5625 46.8125 L 32.5625 37.90625 L 33 37.59375 L 33 36 L 28.71875 36 L 29.28125 35 L 39 35 C 43.957031 35 48 30.957031 48 26 C 48 22.417969 45.851563 19.382813 42.8125 17.9375 C 42.292969 13.710938 38.910156 10.433594 34.625 10.125 C 32.90625 7.097656 29.726563 5 26 5 Z M 26 7 C 29.148438 7 31.847656 8.804688 33.15625 11.4375 L 33.4375 12 L 34.0625 12 C 37.792969 12.023438 40.777344 14.941406 40.96875 18.625 L 41 19.28125 L 41.59375 19.5 C 44.164063 20.535156 46 23.046875 46 26 C 46 29.878906 42.878906 33 39 33 L 30.375 33 L 32.875 28.5 L 33.6875 27 L 19.3125 27 L 19.0625 27.625 L 16.90625 33 L 11 33 C 7.121094 33 4 29.878906 4 26 C 4 23.007813 5.871094 20.476563 8.5 19.46875 L 9.03125 19.28125 L 9.125 18.71875 C 9.726563 15.464844 12.5625 13 16 13 C 16.433594 13 16.855469 13.046875 17.28125 13.125 L 18.15625 13.28125 L 18.40625 12.46875 C 19.46875 9.300781 22.460938 7 26 7 Z M 20.6875 29 L 30.28125 29 L 26.125 36.5 L 25.3125 38 L 28.90625 38 L 21.03125 43.40625 L 22.9375 38.34375 L 23.4375 37 L 17.5 37 Z "/> |
||||
|
</g> |
||||
|
</svg> |
Loading…
Reference in new issue