Jack Mallers
7 years ago
64 changed files with 1216 additions and 1475 deletions
@ -1,45 +1,43 @@ |
|||
// @flow
|
|||
import React, { Component } from 'react' |
|||
import React from 'react' |
|||
import PropTypes from 'prop-types' |
|||
import ReactModal from 'react-modal' |
|||
import Moment from 'react-moment' |
|||
import 'moment-timezone' |
|||
|
|||
|
|||
class Modal extends Component { |
|||
render() { |
|||
const customStyles = { |
|||
overlay: { |
|||
cursor: 'pointer' |
|||
}, |
|||
content : { |
|||
top: 'auto', |
|||
left: '20%', |
|||
right: '0', |
|||
bottom: 'auto', |
|||
width: '40%', |
|||
margin: '50px auto' |
|||
} |
|||
const Modal = ({ isOpen, resetObject, children }) => { |
|||
const customStyles = { |
|||
overlay: { |
|||
cursor: 'pointer' |
|||
}, |
|||
content : { |
|||
top: 'auto', |
|||
left: '20%', |
|||
right: '0', |
|||
bottom: 'auto', |
|||
width: '40%', |
|||
margin: '50px auto' |
|||
} |
|||
const { |
|||
isOpen, |
|||
resetObject, |
|||
children |
|||
} = this.props |
|||
|
|||
return ( |
|||
<ReactModal |
|||
isOpen={isOpen} |
|||
contentLabel="No Overlay Click Modal" |
|||
ariaHideApp={true} |
|||
shouldCloseOnOverlayClick={true} |
|||
onRequestClose={() => resetObject(null)} |
|||
parentSelector={() => document.body} |
|||
style={customStyles} |
|||
> |
|||
{children} |
|||
</ReactModal> |
|||
) |
|||
} |
|||
} |
|||
|
|||
return ( |
|||
<ReactModal |
|||
isOpen={isOpen} |
|||
contentLabel="No Overlay Click Modal" |
|||
ariaHideApp={true} |
|||
shouldCloseOnOverlayClick={true} |
|||
onRequestClose={() => resetObject(null)} |
|||
parentSelector={() => document.body} |
|||
style={customStyles} |
|||
> |
|||
{children} |
|||
</ReactModal> |
|||
) |
|||
} |
|||
|
|||
Modal.propTypes = { |
|||
isOpen: PropTypes.bool.isRequired, |
|||
resetObject: PropTypes.func.isRequired, |
|||
children: PropTypes.object |
|||
} |
|||
|
|||
export default Modal |
|||
export default Modal |
|||
|
@ -1,37 +1,37 @@ |
|||
import { connect } from 'react-redux' |
|||
import { |
|||
fetchInvoices, |
|||
searchInvoices, |
|||
setInvoice, |
|||
invoiceSelectors |
|||
fetchInvoices, |
|||
searchInvoices, |
|||
setInvoice, |
|||
invoiceSelectors |
|||
} from '../../../reducers/invoice' |
|||
import { |
|||
setPayment, |
|||
fetchPayments, |
|||
paymentSelectors |
|||
setPayment, |
|||
fetchPayments, |
|||
paymentSelectors |
|||
} from '../../../reducers/payment' |
|||
import Activity from '../components/Activity' |
|||
|
|||
const mapDispatchToProps = { |
|||
setPayment, |
|||
setInvoice, |
|||
fetchPayments, |
|||
fetchInvoices, |
|||
searchInvoices |
|||
setPayment, |
|||
setInvoice, |
|||
fetchPayments, |
|||
fetchInvoices, |
|||
searchInvoices |
|||
} |
|||
|
|||
const mapStateToProps = (state) => ({ |
|||
activity: state.activity, |
|||
activity: state.activity, |
|||
|
|||
payment: state.payment, |
|||
payment: state.payment, |
|||
|
|||
invoice: state.invoice, |
|||
invoices: invoiceSelectors.invoices(state), |
|||
invoice: state.invoice, |
|||
invoices: invoiceSelectors.invoices(state), |
|||
|
|||
ticker: state.ticker, |
|||
ticker: state.ticker, |
|||
|
|||
paymentModalOpen: paymentSelectors.paymentModalOpen(state), |
|||
invoiceModalOpen: invoiceSelectors.invoiceModalOpen(state) |
|||
paymentModalOpen: paymentSelectors.paymentModalOpen(state), |
|||
invoiceModalOpen: invoiceSelectors.invoiceModalOpen(state) |
|||
}) |
|||
|
|||
export default connect(mapStateToProps, mapDispatchToProps)(Activity) |
@ -1,3 +1,3 @@ |
|||
import ActivityContainer from './containers/ActivityContainer' |
|||
|
|||
export default ActivityContainer |
|||
export default ActivityContainer |
|||
|
@ -1,122 +1,137 @@ |
|||
// @flow
|
|||
import React, { Component } from 'react' |
|||
import React from 'react' |
|||
import PropTypes from 'prop-types' |
|||
import { FaDollar, FaBitcoin } from 'react-icons/lib/fa' |
|||
import { MdArrowBack, MdClose } from 'react-icons/lib/md' |
|||
import { MdClose } from 'react-icons/lib/md' |
|||
import { btc } from '../../../../../utils' |
|||
import styles from './Form.scss' |
|||
|
|||
class Form extends Component { |
|||
render() { |
|||
const { |
|||
form: { formType, amount, message, pubkey, payment_request }, |
|||
setAmount, |
|||
setMessage, |
|||
setPubkey, |
|||
setPaymentRequest, |
|||
ticker: { currency, btcTicker }, |
|||
isOpen, |
|||
close, |
|||
createInvoice, |
|||
payInvoice, |
|||
fetchInvoice, |
|||
formInvoice |
|||
} = this.props |
|||
|
|||
const requestClicked = () => { |
|||
createInvoice(amount, message, currency, btcTicker.price_usd) |
|||
.then(success => { |
|||
const Form = ({ |
|||
form: { formType, amount, message, payment_request }, |
|||
setAmount, |
|||
setMessage, |
|||
setPaymentRequest, |
|||
ticker: { currency, btcTicker }, |
|||
isOpen, |
|||
close, |
|||
createInvoice, |
|||
payInvoice, |
|||
fetchInvoice, |
|||
formInvoice |
|||
}) => { |
|||
const requestClicked = () => { |
|||
createInvoice(amount, message, currency, btcTicker.price_usd) |
|||
.then((success) => { |
|||
if (success) { close() } |
|||
}) |
|||
} |
|||
} |
|||
|
|||
const payClicked = () => { |
|||
payInvoice(payment_request) |
|||
.then(success => { |
|||
console.log('success: ', success) |
|||
const payClicked = () => { |
|||
payInvoice(payment_request) |
|||
.then((success) => { |
|||
if (success) { close() } |
|||
}) |
|||
} |
|||
} |
|||
|
|||
const paymentRequestOnChange = (payreq) => { |
|||
setPaymentRequest(payreq) |
|||
if (payreq.length === 124) { fetchInvoice(payreq) } |
|||
} |
|||
const paymentRequestOnChange = (payreq) => { |
|||
setPaymentRequest(payreq) |
|||
if (payreq.length === 124) { fetchInvoice(payreq) } |
|||
} |
|||
|
|||
const calculateAmount = (amount) => currency === 'btc' ? btc.satoshisToBtc(amount) : btc.satoshisToUsd(amount, btcTicker.price_usd) |
|||
const calculateAmount = value => (currency === 'btc' ? btc.satoshisToBtc(value) : btc.satoshisToUsd(value, btcTicker.price_usd)) |
|||
|
|||
return ( |
|||
<div className={`${styles.formContainer} ${isOpen ? styles.open : ''}`}> |
|||
<div className={styles.container}> |
|||
<div className={styles.esc} onClick={close}> |
|||
<MdClose /> |
|||
</div> |
|||
<div className={styles.content}> |
|||
<section className={styles.amountContainer}> |
|||
<label> |
|||
{ |
|||
currency === 'btc' ? |
|||
return ( |
|||
<div className={`${styles.formContainer} ${isOpen ? styles.open : ''}`}> |
|||
<div className={styles.container}> |
|||
<div className={styles.esc} onClick={close}> |
|||
<MdClose /> |
|||
</div> |
|||
<div className={styles.content}> |
|||
<section className={styles.amountContainer}> |
|||
<label> |
|||
{ |
|||
currency === 'btc' ? |
|||
<FaBitcoin /> |
|||
: |
|||
<FaDollar /> |
|||
} |
|||
</label> |
|||
<input |
|||
type='text' |
|||
size='' |
|||
style={ |
|||
formType === 'pay' ? |
|||
{ width: '75%', fontSize: '100px' } |
|||
: |
|||
{ width: `${amount.length > 1 ? (amount.length * 15) - 5 : 25}%`, fontSize: `${190 - (amount.length ** 2)}px` } |
|||
} |
|||
value={formType === 'pay' ? calculateAmount(formInvoice.amount) : amount} |
|||
onChange={(event) => setAmount(event.target.value)} |
|||
readOnly={formType === 'pay'} |
|||
/> |
|||
</section> |
|||
{ |
|||
formType === 'pay' ? |
|||
<section className={styles.inputContainer}> |
|||
<label>Request:</label> |
|||
<input |
|||
type='text' |
|||
placeholder='Payment Request' |
|||
value={payment_request} |
|||
onChange={(event) => paymentRequestOnChange(event.target.value)} |
|||
/> |
|||
</section> |
|||
: |
|||
<section className={styles.inputContainer}> |
|||
<label>For:</label> |
|||
<input |
|||
type='text' |
|||
placeholder='Dinner, Rent, etc' |
|||
value={message} |
|||
onChange={(e) => setMessage(e.target.value)} |
|||
/> |
|||
</section> |
|||
} |
|||
{ |
|||
formType === 'pay' ? |
|||
<section className={styles.buttonGroup}> |
|||
<div className={styles.button} onClick={payClicked}> |
|||
Pay |
|||
</div> |
|||
</section> |
|||
: |
|||
<section className={styles.buttonGroup}> |
|||
<div className={styles.button} onClick={requestClicked}> |
|||
Request |
|||
</div> |
|||
</section> |
|||
} |
|||
</div> |
|||
} |
|||
</label> |
|||
<input |
|||
type='text' |
|||
size='' |
|||
style={ |
|||
formType === 'pay' ? |
|||
{ width: '75%', fontSize: '100px' } |
|||
: |
|||
{ width: `${amount.length > 1 ? (amount.length * 15) - 5 : 25}%`, fontSize: `${190 - (amount.length ** 2)}px` } |
|||
} |
|||
value={formType === 'pay' ? calculateAmount(formInvoice.amount) : amount} |
|||
onChange={event => setAmount(event.target.value)} |
|||
readOnly={formType === 'pay'} |
|||
/> |
|||
</section> |
|||
{ |
|||
formType === 'pay' ? |
|||
<section className={styles.inputContainer}> |
|||
<label>Request:</label> |
|||
<input |
|||
type='text' |
|||
placeholder='Payment Request' |
|||
value={payment_request} |
|||
onChange={(event) => paymentRequestOnChange(event.target.value)} |
|||
/> |
|||
</section> |
|||
: |
|||
<section className={styles.inputContainer}> |
|||
<label>For:</label> |
|||
<input |
|||
type='text' |
|||
placeholder='Dinner, Rent, etc' |
|||
value={message} |
|||
onChange={(e) => setMessage(e.target.value)} |
|||
/> |
|||
</section> |
|||
} |
|||
{ |
|||
formType === 'pay' ? |
|||
<section className={styles.buttonGroup}> |
|||
<div className={styles.button} onClick={payClicked}> |
|||
Pay |
|||
</div> |
|||
</section> |
|||
: |
|||
<section className={styles.buttonGroup}> |
|||
<div className={styles.button} onClick={requestClicked}> |
|||
Request |
|||
</div> |
|||
</section> |
|||
} |
|||
</div> |
|||
</div> |
|||
) |
|||
} |
|||
</div> |
|||
) |
|||
} |
|||
|
|||
Form.propTypes = {} |
|||
Form.propTypes = { |
|||
form: PropTypes.object.isRequired, |
|||
ticker: PropTypes.object.isRequired, |
|||
formType: PropTypes.string, |
|||
amount: PropTypes.oneOfType([ |
|||
PropTypes.string, |
|||
PropTypes.number |
|||
]), |
|||
message: PropTypes.string, |
|||
payment_request: PropTypes.string, |
|||
setAmount: PropTypes.func.isRequired, |
|||
setMessage: PropTypes.func.isRequired, |
|||
setPaymentRequest: PropTypes.func.isRequired, |
|||
currency: PropTypes.string, |
|||
btcTicker: PropTypes.object, |
|||
isOpen: PropTypes.bool.isRequired, |
|||
close: PropTypes.func.isRequired, |
|||
createInvoice: PropTypes.func.isRequired, |
|||
payInvoice: PropTypes.func.isRequired, |
|||
fetchInvoice: PropTypes.func.isRequired, |
|||
formInvoice: PropTypes.object.isRequired |
|||
} |
|||
|
|||
export default Form |
|||
export default Form |
|||
|
@ -1,3 +1,3 @@ |
|||
import Form from './Form' |
|||
|
|||
export default Form |
|||
export default Form |
|||
|
@ -1,26 +1,20 @@ |
|||
// @flow
|
|||
import React, { Component } from 'react' |
|||
import React from 'react' |
|||
import PropTypes from 'prop-types' |
|||
import Websocket from 'react-websocket' |
|||
|
|||
class Socket extends Component { |
|||
render() { |
|||
const onMessage = ({ event, data }) => { |
|||
console.log('data: ', data) |
|||
this.props.fetchChannels() |
|||
// switch(data.event) {
|
|||
// case CHANNEL_DATA:
|
|||
// console.log('channel data')
|
|||
// if (data.update === 'chan_pending') {
|
|||
// let zapNotification = new Notification({
|
|||
|
|||
// })
|
|||
// }
|
|||
// }
|
|||
} |
|||
return ( |
|||
<Websocket debug url='ws://localhost:3000/' onMessage={onMessage} /> |
|||
) |
|||
const Socket = ({ fetchChannels }) => { |
|||
const onMessage = () => { |
|||
// TODO: Assumes only socket relationship is with channels. Actually flesh out socket logic
|
|||
fetchChannels() |
|||
} |
|||
|
|||
return ( |
|||
<Websocket debug url='ws://localhost:3000/' onMessage={onMessage} /> |
|||
) |
|||
} |
|||
|
|||
Socket.propTypes = { |
|||
fetchChannels: PropTypes.func.isRequired |
|||
} |
|||
|
|||
export default Socket |
|||
export default Socket |
|||
|
@ -1,3 +1,3 @@ |
|||
import AppContainer from './containers/AppContainer' |
|||
|
|||
export default AppContainer |
|||
export default AppContainer |
|||
|
@ -1,65 +1,65 @@ |
|||
// @flow
|
|||
import React, { Component } from 'react' |
|||
import React from 'react' |
|||
import PropTypes from 'prop-types' |
|||
import { btc } from '../../../../../../../utils' |
|||
import styles from './Channel.scss' |
|||
|
|||
class Channel extends Component { |
|||
render() { |
|||
const { ticker, channel, setChannel } = this.props |
|||
return ( |
|||
<li className={styles.channel} onClick={() => setChannel(channel)}> |
|||
<h1 className={styles.status}>Status: Open</h1> |
|||
<div className={styles.left}> |
|||
<section className={styles.remotePubkey}> |
|||
<span>Remote Pubkey</span> |
|||
<h4>{channel.remote_pubkey}</h4> |
|||
</section> |
|||
<section className={styles.channelPoint}> |
|||
<span>Channel Point</span> |
|||
<h4>{channel.channel_point}</h4> |
|||
</section> |
|||
</div> |
|||
<div className={styles.right}> |
|||
<section className={styles.capacity}> |
|||
<span>Capacity</span> |
|||
<h2> |
|||
{ |
|||
ticker.currency === 'btc' ? |
|||
btc.satoshisToBtc(channel.capacity) |
|||
: |
|||
btc.satoshisToUsd(channel.capacity, ticker.btcTicker.price_usd) |
|||
} |
|||
</h2> |
|||
</section> |
|||
<div className={styles.balances}> |
|||
<section> |
|||
<h4> |
|||
{ |
|||
ticker.currency === 'btc' ? |
|||
btc.satoshisToBtc(channel.local_balance) |
|||
: |
|||
btc.satoshisToUsd(channel.local_balance, ticker.btcTicker.price_usd) |
|||
} |
|||
</h4> |
|||
<span>Local</span> |
|||
</section> |
|||
<section> |
|||
<h4> |
|||
{ |
|||
ticker.currency === 'btc' ? |
|||
btc.satoshisToBtc(channel.remote_balance) |
|||
: |
|||
btc.satoshisToUsd(channel.remote_balance, ticker.btcTicker.price_usd) |
|||
} |
|||
</h4> |
|||
<span>Remote</span> |
|||
</section> |
|||
</div> |
|||
</div> |
|||
</li> |
|||
) |
|||
} |
|||
} |
|||
const Channel = ({ ticker, channel, setChannel }) => ( |
|||
<li className={styles.channel} onClick={() => setChannel(channel)}> |
|||
<h1 className={styles.status}>Status: Open</h1> |
|||
<div className={styles.left}> |
|||
<section className={styles.remotePubkey}> |
|||
<span>Remote Pubkey</span> |
|||
<h4>{channel.remote_pubkey}</h4> |
|||
</section> |
|||
<section className={styles.channelPoint}> |
|||
<span>Channel Point</span> |
|||
<h4>{channel.channel_point}</h4> |
|||
</section> |
|||
</div> |
|||
<div className={styles.right}> |
|||
<section className={styles.capacity}> |
|||
<span>Capacity</span> |
|||
<h2> |
|||
{ |
|||
ticker.currency === 'btc' ? |
|||
btc.satoshisToBtc(channel.capacity) |
|||
: |
|||
btc.satoshisToUsd(channel.capacity, ticker.btcTicker.price_usd) |
|||
} |
|||
</h2> |
|||
</section> |
|||
<div className={styles.balances}> |
|||
<section> |
|||
<h4> |
|||
{ |
|||
ticker.currency === 'btc' ? |
|||
btc.satoshisToBtc(channel.local_balance) |
|||
: |
|||
btc.satoshisToUsd(channel.local_balance, ticker.btcTicker.price_usd) |
|||
} |
|||
</h4> |
|||
<span>Local</span> |
|||
</section> |
|||
<section> |
|||
<h4> |
|||
{ |
|||
ticker.currency === 'btc' ? |
|||
btc.satoshisToBtc(channel.remote_balance) |
|||
: |
|||
btc.satoshisToUsd(channel.remote_balance, ticker.btcTicker.price_usd) |
|||
} |
|||
</h4> |
|||
<span>Remote</span> |
|||
</section> |
|||
</div> |
|||
</div> |
|||
</li> |
|||
) |
|||
|
|||
Channel.propTypes = { |
|||
ticker: PropTypes.object.isRequired, |
|||
channel: PropTypes.object.isRequired, |
|||
setChannel: PropTypes.func.isRequired |
|||
} |
|||
|
|||
export default Channel |
|||
export default Channel |
|||
|
@ -1,3 +1,3 @@ |
|||
import Channel from './Channel' |
|||
|
|||
export default Channel |
|||
export default Channel |
|||
|
@ -1,125 +1,126 @@ |
|||
// @flow
|
|||
import React, { Component } from 'react' |
|||
import React from 'react' |
|||
import PropTypes from 'prop-types' |
|||
import ReactModal from 'react-modal' |
|||
import { FaUser, FaBitcoin, FaDollar } from 'react-icons/lib/fa' |
|||
import { usd, btc } from '../../../../../../../utils' |
|||
import styles from './ChannelForm.scss' |
|||
|
|||
class ChannelForm extends Component { |
|||
render() { |
|||
const submitClicked = () => { |
|||
const { form: { node_key, local_amt, push_amt }, openChannel, ticker } = this.props |
|||
console.log('ticker: ', ticker) |
|||
const localamt = ticker.currency === 'btc' ? btc.btcToSatoshis(local_amt) : btc.btcToSatoshis(usd.usdToBtc(local_amt, ticker.btcTicker.price_usd)) |
|||
const pushamt = ticker.currency === 'btc' ? btc.btcToSatoshis(push_amt) : btc.btcToSatoshis(usd.usdToBtc(push_amt, ticker.btcTicker.price_usd)) |
|||
|
|||
openChannel({ pubkey: node_key, localamt, pushamt }).then(channel => { |
|||
if (channel.data) { setForm({ isOpen: false }) } |
|||
}) |
|||
} |
|||
|
|||
const customStyles = { |
|||
overlay: { |
|||
cursor: 'pointer', |
|||
overflowY: 'auto' |
|||
}, |
|||
content : { |
|||
top: 'auto', |
|||
left: '20%', |
|||
right: '0', |
|||
bottom: 'auto', |
|||
width: '40%', |
|||
margin: '50px auto', |
|||
padding: '40px' |
|||
} |
|||
} |
|||
const ChannelForm = ({ form, setForm, ticker, peers, openChannel }) => { |
|||
const submitClicked = () => { |
|||
const { form: { node_key, local_amt, push_amt }, openChannel, ticker } = this.props |
|||
const localamt = ticker.currency === 'btc' ? btc.btcToSatoshis(local_amt) : btc.btcToSatoshis(usd.usdToBtc(local_amt, ticker.btcTicker.price_usd)) |
|||
const pushamt = ticker.currency === 'btc' ? btc.btcToSatoshis(push_amt) : btc.btcToSatoshis(usd.usdToBtc(push_amt, ticker.btcTicker.price_usd)) |
|||
|
|||
const { form, setForm, ticker, peers, openChannel } = this.props |
|||
openChannel({ pubkey: node_key, localamt, pushamt }).then(channel => { |
|||
if (channel.data) { setForm({ isOpen: false }) } |
|||
}) |
|||
} |
|||
|
|||
return ( |
|||
<div> |
|||
<ReactModal |
|||
isOpen={form.isOpen} |
|||
contentLabel="No Overlay Click Modal" |
|||
ariaHideApp={true} |
|||
shouldCloseOnOverlayClick={true} |
|||
onRequestClose={() => setForm({ isOpen: false })} |
|||
parentSelector={() => document.body} |
|||
style={customStyles} |
|||
> |
|||
<div className={styles.form}> |
|||
<h1 className={styles.title}>Open a new channel</h1> |
|||
|
|||
<section className={styles.pubkey}> |
|||
<label><FaUser /></label> |
|||
<input |
|||
type='text' |
|||
size='' |
|||
placeholder='Peer public key' |
|||
value={form.node_key} |
|||
onChange={(event) => setForm({ node_key: event.target.value })} |
|||
/> |
|||
</section> |
|||
<section className={styles.local}> |
|||
<label> |
|||
{ |
|||
ticker.currency === 'btc' ? |
|||
<FaBitcoin /> |
|||
: |
|||
<FaDollar /> |
|||
} |
|||
</label> |
|||
<input |
|||
type='text' |
|||
size='' |
|||
placeholder='Local amount' |
|||
value={form.local_amt} |
|||
onChange={(event) => setForm({ local_amt: event.target.value })} |
|||
/> |
|||
</section> |
|||
<section className={styles.push}> |
|||
<label> |
|||
{ |
|||
ticker.currency === 'btc' ? |
|||
<FaBitcoin /> |
|||
: |
|||
<FaDollar /> |
|||
} |
|||
</label> |
|||
<input |
|||
type='text' |
|||
size='' |
|||
placeholder='Push amount' |
|||
value={form.push_amt} |
|||
onChange={(event) => setForm({ push_amt: event.target.value })} |
|||
/> |
|||
</section> |
|||
const customStyles = { |
|||
overlay: { |
|||
cursor: 'pointer', |
|||
overflowY: 'auto' |
|||
}, |
|||
content : { |
|||
top: 'auto', |
|||
left: '20%', |
|||
right: '0', |
|||
bottom: 'auto', |
|||
width: '40%', |
|||
margin: '50px auto', |
|||
padding: '40px' |
|||
} |
|||
} |
|||
|
|||
return ( |
|||
<div> |
|||
<ReactModal |
|||
isOpen={form.isOpen} |
|||
contentLabel="No Overlay Click Modal" |
|||
ariaHideApp={true} |
|||
shouldCloseOnOverlayClick={true} |
|||
onRequestClose={() => setForm({ isOpen: false })} |
|||
parentSelector={() => document.body} |
|||
style={customStyles} |
|||
> |
|||
<div className={styles.form}> |
|||
<h1 className={styles.title}>Open a new channel</h1> |
|||
|
|||
<ul className={styles.peers}> |
|||
<h2>Connected Peers</h2> |
|||
<section className={styles.pubkey}> |
|||
<label><FaUser /></label> |
|||
<input |
|||
type='text' |
|||
size='' |
|||
placeholder='Peer public key' |
|||
value={form.node_key} |
|||
onChange={(event) => setForm({ node_key: event.target.value })} |
|||
/> |
|||
</section> |
|||
<section className={styles.local}> |
|||
<label> |
|||
{ |
|||
peers.length ? |
|||
peers.map(peer => |
|||
<li key={peer.peer_id} className={styles.peer} onClick={() => setForm({ node_key: peer.pub_key })}> |
|||
<h4>{peer.address}</h4> |
|||
<h1>{peer.pub_key}</h1> |
|||
</li> |
|||
) |
|||
: |
|||
null |
|||
ticker.currency === 'btc' ? |
|||
<FaBitcoin /> |
|||
: |
|||
<FaDollar /> |
|||
} |
|||
</ul> |
|||
</label> |
|||
<input |
|||
type='text' |
|||
size='' |
|||
placeholder='Local amount' |
|||
value={form.local_amt} |
|||
onChange={(event) => setForm({ local_amt: event.target.value })} |
|||
/> |
|||
</section> |
|||
<section className={styles.push}> |
|||
<label> |
|||
{ |
|||
ticker.currency === 'btc' ? |
|||
<FaBitcoin /> |
|||
: |
|||
<FaDollar /> |
|||
} |
|||
</label> |
|||
<input |
|||
type='text' |
|||
size='' |
|||
placeholder='Push amount' |
|||
value={form.push_amt} |
|||
onChange={(event) => setForm({ push_amt: event.target.value })} |
|||
/> |
|||
</section> |
|||
|
|||
<div className={styles.buttonGroup}> |
|||
<div className={styles.button} onClick={submitClicked}> |
|||
Submit |
|||
</div> |
|||
</div> |
|||
<ul className={styles.peers}> |
|||
<h2>Connected Peers</h2> |
|||
{ |
|||
peers.length ? |
|||
peers.map(peer => |
|||
<li key={peer.peer_id} className={styles.peer} onClick={() => setForm({ node_key: peer.pub_key })}> |
|||
<h4>{peer.address}</h4> |
|||
<h1>{peer.pub_key}</h1> |
|||
</li> |
|||
) |
|||
: |
|||
null |
|||
} |
|||
</ul> |
|||
|
|||
<div className={styles.buttonGroup}> |
|||
<div className={styles.button} onClick={submitClicked}>Submit</div> |
|||
</div> |
|||
</ReactModal> |
|||
</div> |
|||
) |
|||
} |
|||
</div> |
|||
</ReactModal> |
|||
</div> |
|||
) |
|||
} |
|||
|
|||
ChannelForm.propTypes = { |
|||
form: PropTypes.object.isRequired, |
|||
setForm: PropTypes.func.isRequired, |
|||
ticker: PropTypes.object.isRequired, |
|||
peers: PropTypes.array.isRequired, |
|||
openChannel: PropTypes.func.isRequired |
|||
} |
|||
|
|||
export default ChannelForm |
|||
|
@ -1,3 +1,3 @@ |
|||
import ChannelForm from './ChannelForm' |
|||
|
|||
export default ChannelForm |
|||
export default ChannelForm |
|||
|
@ -1,3 +1,3 @@ |
|||
import ChannelModal from './ChannelModal' |
|||
|
|||
export default ChannelModal |
|||
export default ChannelModal |
|||
|
@ -1,66 +1,67 @@ |
|||
// @flow
|
|||
import { shell } from 'electron' |
|||
import React, { Component } from 'react' |
|||
import React from 'react' |
|||
import PropTypes from 'prop-types' |
|||
import { btc } from '../../../../../../../utils' |
|||
import styles from './ClosedPendingChannel.scss' |
|||
|
|||
class ClosedPendingChannel extends Component { |
|||
render() { |
|||
const { ticker, channel: { channel, closing_txid }, setChannel } = this.props |
|||
return ( |
|||
<li className={styles.channel} onClick={() => shell.openExternal(`https://testnet.smartbit.com.au/tx/${closing_txid}`)}> |
|||
<h1 className={styles.closing}>Status: Closing</h1> |
|||
<div className={styles.left}> |
|||
<section className={styles.remotePubkey}> |
|||
<span>Remote Pubkey</span> |
|||
<h4>{channel.remote_node_pub}</h4> |
|||
</section> |
|||
<section className={styles.channelPoint}> |
|||
<span>Channel Point</span> |
|||
<h4>{channel.channel_point}</h4> |
|||
</section> |
|||
</div> |
|||
<div className={styles.right}> |
|||
<section className={styles.capacity}> |
|||
<span>Capacity</span> |
|||
<h2> |
|||
{ |
|||
ticker.currency === 'btc' ? |
|||
btc.satoshisToBtc(channel.capacity) |
|||
: |
|||
btc.satoshisToUsd(channel.capacity, ticker.btcTicker.price_usd) |
|||
} |
|||
</h2> |
|||
</section> |
|||
<div className={styles.balances}> |
|||
<section> |
|||
<h4> |
|||
{ |
|||
ticker.currency === 'btc' ? |
|||
btc.satoshisToBtc(channel.local_balance) |
|||
: |
|||
btc.satoshisToUsd(channel.local_balance, ticker.btcTicker.price_usd) |
|||
} |
|||
</h4> |
|||
<span>Local</span> |
|||
</section> |
|||
<section> |
|||
<h4> |
|||
{ |
|||
ticker.currency === 'btc' ? |
|||
btc.satoshisToBtc(channel.remote_balance) |
|||
: |
|||
btc.satoshisToUsd(channel.remote_balance, ticker.btcTicker.price_usd) |
|||
} |
|||
</h4> |
|||
<span>Remote</span> |
|||
</section> |
|||
</div> |
|||
</div> |
|||
</li> |
|||
) |
|||
} |
|||
} |
|||
const ClosedPendingChannel = ({ ticker, channel: { channel, closing_txid }, setChannel }) => ( |
|||
<li className={styles.channel} onClick={() => shell.openExternal(`https://testnet.smartbit.com.au/tx/${closing_txid}`)}> |
|||
<h1 className={styles.closing}>Status: Closing</h1> |
|||
<div className={styles.left}> |
|||
<section className={styles.remotePubkey}> |
|||
<span>Remote Pubkey</span> |
|||
<h4>{channel.remote_node_pub}</h4> |
|||
</section> |
|||
<section className={styles.channelPoint}> |
|||
<span>Channel Point</span> |
|||
<h4>{channel.channel_point}</h4> |
|||
</section> |
|||
</div> |
|||
<div className={styles.right}> |
|||
<section className={styles.capacity}> |
|||
<span>Capacity</span> |
|||
<h2> |
|||
{ |
|||
ticker.currency === 'btc' ? |
|||
btc.satoshisToBtc(channel.capacity) |
|||
: |
|||
btc.satoshisToUsd(channel.capacity, ticker.btcTicker.price_usd) |
|||
} |
|||
</h2> |
|||
</section> |
|||
<div className={styles.balances}> |
|||
<section> |
|||
<h4> |
|||
{ |
|||
ticker.currency === 'btc' ? |
|||
btc.satoshisToBtc(channel.local_balance) |
|||
: |
|||
btc.satoshisToUsd(channel.local_balance, ticker.btcTicker.price_usd) |
|||
} |
|||
</h4> |
|||
<span>Local</span> |
|||
</section> |
|||
<section> |
|||
<h4> |
|||
{ |
|||
ticker.currency === 'btc' ? |
|||
btc.satoshisToBtc(channel.remote_balance) |
|||
: |
|||
btc.satoshisToUsd(channel.remote_balance, ticker.btcTicker.price_usd) |
|||
} |
|||
</h4> |
|||
<span>Remote</span> |
|||
</section> |
|||
</div> |
|||
</div> |
|||
</li> |
|||
) |
|||
|
|||
ClosedPendingChannel.propTypes = { |
|||
ticker: PropTypes.object.isRequired, |
|||
channel: PropTypes.object.isRequired, |
|||
closing_txid: PropTypes.string, |
|||
setChannel: PropTypes.func |
|||
} |
|||
|
|||
export default ClosedPendingChannel |
|||
export default ClosedPendingChannel |
|||
|
@ -1,3 +1,3 @@ |
|||
import ClosedPendingChannel from './ClosedPendingChannel' |
|||
|
|||
export default ClosedPendingChannel |
|||
export default ClosedPendingChannel |
|||
|
@ -1,66 +1,66 @@ |
|||
// @flow
|
|||
import { shell } from 'electron' |
|||
import React, { Component } from 'react' |
|||
import React from 'react' |
|||
import PropTypes from 'prop-types' |
|||
import { btc } from '../../../../../../../utils' |
|||
import styles from './OpenPendingChannel.scss' |
|||
|
|||
class OpenPendingChannel extends Component { |
|||
render() { |
|||
const { ticker, channel: { channel } } = this.props |
|||
return ( |
|||
<li className={styles.channel} onClick={() => shell.openExternal(`https://testnet.smartbit.com.au/tx/${channel.channel_point.split(':')[0]}`)}> |
|||
<h1 className={styles.pending}>Status: Pending</h1> |
|||
<div className={styles.left}> |
|||
<section className={styles.remotePubkey}> |
|||
<span>Remote Pubkey</span> |
|||
<h4>{channel.remote_node_pub}</h4> |
|||
</section> |
|||
<section className={styles.channelPoint}> |
|||
<span>Channel Point</span> |
|||
<h4>{channel.channel_point}</h4> |
|||
</section> |
|||
</div> |
|||
<div className={styles.right}> |
|||
<section className={styles.capacity}> |
|||
<span>Capacity</span> |
|||
<h2> |
|||
{ |
|||
ticker.currency === 'btc' ? |
|||
btc.satoshisToBtc(channel.capacity) |
|||
: |
|||
btc.satoshisToUsd(channel.capacity, ticker.btcTicker.price_usd) |
|||
} |
|||
</h2> |
|||
</section> |
|||
<div className={styles.balances}> |
|||
<section> |
|||
<h4> |
|||
{ |
|||
ticker.currency === 'btc' ? |
|||
btc.satoshisToBtc(channel.local_balance) |
|||
: |
|||
btc.satoshisToUsd(channel.local_balance, ticker.btcTicker.price_usd) |
|||
} |
|||
</h4> |
|||
<span>Local</span> |
|||
</section> |
|||
<section> |
|||
<h4> |
|||
{ |
|||
ticker.currency === 'btc' ? |
|||
btc.satoshisToBtc(channel.remote_balance) |
|||
: |
|||
btc.satoshisToUsd(channel.remote_balance, ticker.btcTicker.price_usd) |
|||
} |
|||
</h4> |
|||
<span>Remote</span> |
|||
</section> |
|||
</div> |
|||
</div> |
|||
</li> |
|||
) |
|||
} |
|||
} |
|||
const OpenPendingChannel = ({ ticker, channel: { channel } }) => ( |
|||
<li className={styles.channel} onClick={() => shell.openExternal(`https://testnet.smartbit.com.au/tx/${channel.channel_point.split(':')[0]}`)}> |
|||
<h1 className={styles.pending}>Status: Pending</h1> |
|||
<div className={styles.left}> |
|||
<section className={styles.remotePubkey}> |
|||
<span>Remote Pubkey</span> |
|||
<h4>{channel.remote_node_pub}</h4> |
|||
</section> |
|||
<section className={styles.channelPoint}> |
|||
<span>Channel Point</span> |
|||
<h4>{channel.channel_point}</h4> |
|||
</section> |
|||
</div> |
|||
<div className={styles.right}> |
|||
<section className={styles.capacity}> |
|||
<span>Capacity</span> |
|||
<h2> |
|||
{ |
|||
ticker.currency === 'btc' ? |
|||
btc.satoshisToBtc(channel.capacity) |
|||
: |
|||
btc.satoshisToUsd(channel.capacity, ticker.btcTicker.price_usd) |
|||
} |
|||
</h2> |
|||
</section> |
|||
<div className={styles.balances}> |
|||
<section> |
|||
<h4> |
|||
{ |
|||
ticker.currency === 'btc' ? |
|||
btc.satoshisToBtc(channel.local_balance) |
|||
: |
|||
btc.satoshisToUsd(channel.local_balance, ticker.btcTicker.price_usd) |
|||
} |
|||
</h4> |
|||
<span>Local</span> |
|||
</section> |
|||
<section> |
|||
<h4> |
|||
{ |
|||
ticker.currency === 'btc' ? |
|||
btc.satoshisToBtc(channel.remote_balance) |
|||
: |
|||
btc.satoshisToUsd(channel.remote_balance, ticker.btcTicker.price_usd) |
|||
} |
|||
</h4> |
|||
<span>Remote</span> |
|||
</section> |
|||
</div> |
|||
</div> |
|||
</li> |
|||
) |
|||
|
|||
OpenPendingChannel.propTypes = { |
|||
ticker: PropTypes.object.isRequired, |
|||
channel: PropTypes.object.isRequired |
|||
} |
|||
|
|||
export default OpenPendingChannel |
|||
export default OpenPendingChannel |
|||
|
@ -1,3 +1,3 @@ |
|||
import OpenPendingChannel from './OpenPendingChannel' |
|||
|
|||
export default OpenPendingChannel |
|||
export default OpenPendingChannel |
|||
|
@ -1,3 +1,3 @@ |
|||
import Channels from './Channels' |
|||
|
|||
export default Channels |
|||
export default Channels |
|||
|
@ -1,51 +1,56 @@ |
|||
// @flow
|
|||
import React, { Component } from 'react' |
|||
import React from 'react' |
|||
import PropTypes from 'prop-types' |
|||
import { TiPlus } from 'react-icons/lib/ti' |
|||
import PeerModal from './components/PeerModal' |
|||
import PeerForm from './components/PeerForm' |
|||
import Peer from './components/Peer' |
|||
import styles from './Peers.scss' |
|||
|
|||
class Peers extends Component { |
|||
render() { |
|||
const { |
|||
peersLoading, |
|||
peers, |
|||
peer, |
|||
setPeer, |
|||
modalPeer, |
|||
peerModalOpen, |
|||
peerForm, |
|||
setPeerForm, |
|||
connect, |
|||
disconnect, |
|||
} = this.props |
|||
const Peers = ({ |
|||
peersLoading, |
|||
peers, |
|||
setPeer, |
|||
modalPeer, |
|||
peerModalOpen, |
|||
peerForm, |
|||
setPeerForm, |
|||
connect, |
|||
disconnect |
|||
}) => ( |
|||
<div className={styles.peers}> |
|||
<PeerModal isOpen={peerModalOpen} resetPeer={setPeer} peer={modalPeer} disconnect={disconnect} /> |
|||
<PeerForm form={peerForm} setForm={setPeerForm} connect={connect} /> |
|||
<div className={styles.header}> |
|||
<h3>Peers</h3> |
|||
<div |
|||
className={`${styles.connectPeer} hint--top`} |
|||
data-hint='Connect to a peer' |
|||
onClick={() => setPeerForm({ isOpen: true })} |
|||
> |
|||
<TiPlus /> |
|||
</div> |
|||
</div> |
|||
<ul> |
|||
{ |
|||
!peersLoading ? |
|||
peers.map(peer => <Peer key={peer.peer_id} peer={peer} setPeer={setPeer} />) |
|||
: |
|||
'Loading...' |
|||
} |
|||
</ul> |
|||
</div> |
|||
) |
|||
|
|||
return ( |
|||
<div className={styles.peers}> |
|||
<PeerModal isOpen={peerModalOpen} resetPeer={setPeer} peer={modalPeer} disconnect={disconnect} /> |
|||
<PeerForm form={peerForm} setForm={setPeerForm} connect={connect} /> |
|||
<div className={styles.header}> |
|||
<h3>Peers</h3> |
|||
<div |
|||
className={`${styles.connectPeer} hint--top`} |
|||
data-hint='Connect to a peer' |
|||
onClick={() => setPeerForm({ isOpen: true })} |
|||
> |
|||
<TiPlus /> |
|||
</div> |
|||
</div> |
|||
<ul> |
|||
{ |
|||
!peersLoading ? |
|||
peers.map(peer => <Peer key={peer.peer_id} peer={peer} setPeer={setPeer} />) |
|||
: |
|||
'Loading...' |
|||
} |
|||
</ul> |
|||
</div> |
|||
) |
|||
} |
|||
Peers.propTypes = { |
|||
peersLoading: PropTypes.bool.isRequired, |
|||
peers: PropTypes.array.isRequired, |
|||
setPeer: PropTypes.func.isRequired, |
|||
modalPeer: PropTypes.object, |
|||
peerModalOpen: PropTypes.bool.isRequired, |
|||
peerForm: PropTypes.object.isRequired, |
|||
setPeerForm: PropTypes.func.isRequired, |
|||
connect: PropTypes.func.isRequired, |
|||
disconnect: PropTypes.func.isRequired |
|||
} |
|||
|
|||
export default Peers |
|||
|
@ -1,18 +1,17 @@ |
|||
// @flow
|
|||
import React, { Component } from 'react' |
|||
import React from 'react' |
|||
import PropTypes from 'prop-types' |
|||
import styles from './Peer.scss' |
|||
|
|||
class Peer extends Component { |
|||
render() { |
|||
const { peer, setPeer } = this.props |
|||
return ( |
|||
<li className={styles.peer} onClick={() => setPeer(peer)}> |
|||
<h4>{peer.address}</h4> |
|||
<h1>{peer.pub_key}</h1> |
|||
</li> |
|||
) |
|||
} |
|||
} |
|||
const Peer = ({ peer, setPeer }) => ( |
|||
<li className={styles.peer} onClick={() => setPeer(peer)}> |
|||
<h4>{peer.address}</h4> |
|||
<h1>{peer.pub_key}</h1> |
|||
</li> |
|||
) |
|||
|
|||
Peer.propTypes = { |
|||
peer: PropTypes.object.isRequired, |
|||
setPeer: PropTypes.func.isRequired |
|||
} |
|||
|
|||
export default Peer |
|||
export default Peer |
|||
|
@ -1,3 +1,3 @@ |
|||
import Peer from './Peer' |
|||
|
|||
export default Peer |
|||
export default Peer |
|||
|
@ -1,3 +1,3 @@ |
|||
import PeerForm from './PeerForm' |
|||
|
|||
export default PeerForm |
|||
export default PeerForm |
|||
|
@ -1,3 +1,3 @@ |
|||
import PeerModal from './PeerModal' |
|||
|
|||
export default PeerModal |
|||
export default PeerModal |
|||
|
@ -1,3 +1,3 @@ |
|||
import Peers from './Peers' |
|||
|
|||
export default Peers |
|||
export default Peers |
|||
|
@ -1,51 +1,51 @@ |
|||
import { connect } from 'react-redux' |
|||
import { fetchInfo } from '../../../reducers/info' |
|||
import { |
|||
fetchPeers, |
|||
setPeer, |
|||
peersSelectors, |
|||
setPeerForm, |
|||
connectRequest, |
|||
disconnectRequest |
|||
fetchPeers, |
|||
setPeer, |
|||
peersSelectors, |
|||
setPeerForm, |
|||
connectRequest, |
|||
disconnectRequest |
|||
} from '../../../reducers/peers' |
|||
import { |
|||
fetchChannels, |
|||
fetchPendingChannels, |
|||
setChannel, |
|||
channelsSelectors, |
|||
setChannelForm, |
|||
openChannel |
|||
fetchChannels, |
|||
fetchPendingChannels, |
|||
setChannel, |
|||
channelsSelectors, |
|||
setChannelForm, |
|||
openChannel |
|||
} from '../../../reducers/channels' |
|||
import Wallet from '../components/Wallet' |
|||
|
|||
const mapDispatchToProps = { |
|||
fetchInfo, |
|||
|
|||
fetchPeers, |
|||
setPeer, |
|||
connectRequest, |
|||
disconnectRequest, |
|||
|
|||
fetchChannels, |
|||
fetchPendingChannels, |
|||
setChannel, |
|||
openChannel, |
|||
|
|||
setPeerForm, |
|||
setChannelForm |
|||
fetchInfo, |
|||
|
|||
fetchPeers, |
|||
setPeer, |
|||
connectRequest, |
|||
disconnectRequest, |
|||
|
|||
fetchChannels, |
|||
fetchPendingChannels, |
|||
setChannel, |
|||
openChannel, |
|||
|
|||
setPeerForm, |
|||
setChannelForm |
|||
} |
|||
|
|||
const mapStateToProps = (state) => ({ |
|||
info: state.info, |
|||
ticker: state.ticker, |
|||
|
|||
peers: state.peers, |
|||
channels: state.channels, |
|||
info: state.info, |
|||
ticker: state.ticker, |
|||
|
|||
peers: state.peers, |
|||
channels: state.channels, |
|||
|
|||
allChannels: channelsSelectors.allChannels(state), |
|||
allChannels: channelsSelectors.allChannels(state), |
|||
|
|||
peerModalOpen: peersSelectors.peerModalOpen(state), |
|||
channelModalOpen: channelsSelectors.channelModalOpen(state), |
|||
peerModalOpen: peersSelectors.peerModalOpen(state), |
|||
channelModalOpen: channelsSelectors.channelModalOpen(state) |
|||
}) |
|||
|
|||
export default connect(mapStateToProps, mapDispatchToProps)(Wallet) |
|||
|
@ -1,3 +1,3 @@ |
|||
import WalletContainer from './containers/WalletContainer' |
|||
|
|||
export default WalletContainer |
|||
export default WalletContainer |
|||
|
@ -1,9 +1,9 @@ |
|||
export function usdToBtc(usd, rate) { |
|||
if (usd == undefined || usd === '') return |
|||
if (usd === undefined || usd === '') return null |
|||
|
|||
return (usd / rate).toFixed(8) |
|||
} |
|||
|
|||
export default { |
|||
usdToBtc |
|||
} |
|||
usdToBtc |
|||
} |
|||
|
@ -1,13 +0,0 @@ |
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP |
|||
|
|||
exports[`actions should decrement should create decrement action 1`] = ` |
|||
Object { |
|||
"type": "DECREMENT_COUNTER", |
|||
} |
|||
`; |
|||
|
|||
exports[`actions should increment should create increment action 1`] = ` |
|||
Object { |
|||
"type": "INCREMENT_COUNTER", |
|||
} |
|||
`; |
@ -1,41 +0,0 @@ |
|||
import { spy } from 'sinon'; |
|||
import * as actions from '../../app/actions/counter'; |
|||
|
|||
describe('actions', () => { |
|||
it('should increment should create increment action', () => { |
|||
expect(actions.increment()).toMatchSnapshot(); |
|||
}); |
|||
|
|||
it('should decrement should create decrement action', () => { |
|||
expect(actions.decrement()).toMatchSnapshot(); |
|||
}); |
|||
|
|||
it('should incrementIfOdd should create increment action', () => { |
|||
const fn = actions.incrementIfOdd(); |
|||
expect(fn).toBeInstanceOf(Function); |
|||
const dispatch = spy(); |
|||
const getState = () => ({ counter: 1 }); |
|||
fn(dispatch, getState); |
|||
expect(dispatch.calledWith({ type: actions.INCREMENT_COUNTER })).toBe(true); |
|||
}); |
|||
|
|||
it('should incrementIfOdd shouldnt create increment action if counter is even', () => { |
|||
const fn = actions.incrementIfOdd(); |
|||
const dispatch = spy(); |
|||
const getState = () => ({ counter: 2 }); |
|||
fn(dispatch, getState); |
|||
expect(dispatch.called).toBe(false); |
|||
}); |
|||
|
|||
// There's no nice way to test this at the moment...
|
|||
it('should incrementAsync', done => { |
|||
const fn = actions.incrementAsync(1); |
|||
expect(fn).toBeInstanceOf(Function); |
|||
const dispatch = spy(); |
|||
fn(dispatch); |
|||
setTimeout(() => { |
|||
expect(dispatch.calledWith({ type: actions.INCREMENT_COUNTER })).toBe(true); |
|||
done(); |
|||
}, 5); |
|||
}); |
|||
}); |
@ -1,68 +0,0 @@ |
|||
import { spy } from 'sinon'; |
|||
import React from 'react'; |
|||
import { shallow } from 'enzyme'; |
|||
import { BrowserRouter as Router } from 'react-router-dom'; |
|||
import renderer from 'react-test-renderer'; |
|||
import Counter from '../../app/components/Counter'; |
|||
|
|||
function setup() { |
|||
const actions = { |
|||
increment: spy(), |
|||
incrementIfOdd: spy(), |
|||
incrementAsync: spy(), |
|||
decrement: spy() |
|||
}; |
|||
const component = shallow(<Counter counter={1} {...actions} />); |
|||
return { |
|||
component, |
|||
actions, |
|||
buttons: component.find('button'), |
|||
p: component.find('.counter') |
|||
}; |
|||
} |
|||
|
|||
describe('Counter component', () => { |
|||
it('should should display count', () => { |
|||
const { p } = setup(); |
|||
expect(p.text()).toMatch(/^1$/); |
|||
}); |
|||
|
|||
it('should first button should call increment', () => { |
|||
const { buttons, actions } = setup(); |
|||
buttons.at(0).simulate('click'); |
|||
expect(actions.increment.called).toBe(true); |
|||
}); |
|||
|
|||
it('should match exact snapshot', () => { |
|||
const { actions } = setup(); |
|||
const tree = renderer |
|||
.create( |
|||
<div> |
|||
<Router> |
|||
<Counter counter={1} {...actions} /> |
|||
</Router> |
|||
</div> |
|||
) |
|||
.toJSON(); |
|||
|
|||
expect(tree).toMatchSnapshot(); |
|||
}); |
|||
|
|||
it('should second button should call decrement', () => { |
|||
const { buttons, actions } = setup(); |
|||
buttons.at(1).simulate('click'); |
|||
expect(actions.decrement.called).toBe(true); |
|||
}); |
|||
|
|||
it('should third button should call incrementIfOdd', () => { |
|||
const { buttons, actions } = setup(); |
|||
buttons.at(2).simulate('click'); |
|||
expect(actions.incrementIfOdd.called).toBe(true); |
|||
}); |
|||
|
|||
it('should fourth button should call incrementAsync', () => { |
|||
const { buttons, actions } = setup(); |
|||
buttons.at(3).simulate('click'); |
|||
expect(actions.incrementAsync.called).toBe(true); |
|||
}); |
|||
}); |
@ -1,63 +0,0 @@ |
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP |
|||
|
|||
exports[`Counter component should match exact snapshot 1`] = ` |
|||
<div> |
|||
<div> |
|||
<div |
|||
className="backButton" |
|||
data-tid="backButton" |
|||
> |
|||
<a |
|||
href="/" |
|||
onClick={[Function]} |
|||
> |
|||
<i |
|||
className="fa fa-arrow-left fa-3x" |
|||
/> |
|||
</a> |
|||
</div> |
|||
<div |
|||
className="counter counter" |
|||
data-tid="counter" |
|||
> |
|||
1 |
|||
</div> |
|||
<div |
|||
className="btnGroup" |
|||
> |
|||
<button |
|||
className="btn" |
|||
data-tclass="btn" |
|||
onClick={[Function]} |
|||
> |
|||
<i |
|||
className="fa fa-plus" |
|||
/> |
|||
</button> |
|||
<button |
|||
className="btn" |
|||
data-tclass="btn" |
|||
onClick={[Function]} |
|||
> |
|||
<i |
|||
className="fa fa-minus" |
|||
/> |
|||
</button> |
|||
<button |
|||
className="btn" |
|||
data-tclass="btn" |
|||
onClick={[Function]} |
|||
> |
|||
odd |
|||
</button> |
|||
<button |
|||
className="btn" |
|||
data-tclass="btn" |
|||
onClick={[Function]} |
|||
> |
|||
async |
|||
</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
`; |
@ -1,57 +0,0 @@ |
|||
import React from 'react'; |
|||
import { mount } from 'enzyme'; |
|||
import { Provider } from 'react-redux'; |
|||
import { createBrowserHistory } from 'history'; |
|||
import { ConnectedRouter } from 'react-router-redux'; |
|||
import CounterPage from '../../app/containers/CounterPage'; |
|||
import { configureStore } from '../../app/store/configureStore'; |
|||
|
|||
function setup(initialState) { |
|||
const store = configureStore(initialState); |
|||
const history = createBrowserHistory(); |
|||
const app = mount( |
|||
<Provider store={store}> |
|||
<ConnectedRouter history={history}> |
|||
<CounterPage /> |
|||
</ConnectedRouter> |
|||
</Provider> |
|||
); |
|||
return { |
|||
app, |
|||
buttons: app.find('button'), |
|||
p: app.find('.counter') |
|||
}; |
|||
} |
|||
|
|||
describe('containers', () => { |
|||
describe('App', () => { |
|||
it('should display initial count', () => { |
|||
const { p } = setup(); |
|||
expect(p.text()).toMatch(/^0$/); |
|||
}); |
|||
|
|||
it('should display updated count after increment button click', () => { |
|||
const { buttons, p } = setup(); |
|||
buttons.at(0).simulate('click'); |
|||
expect(p.text()).toMatch(/^1$/); |
|||
}); |
|||
|
|||
it('should display updated count after descrement button click', () => { |
|||
const { buttons, p } = setup(); |
|||
buttons.at(1).simulate('click'); |
|||
expect(p.text()).toMatch(/^-1$/); |
|||
}); |
|||
|
|||
it('shouldnt change if even and if odd button clicked', () => { |
|||
const { buttons, p } = setup(); |
|||
buttons.at(2).simulate('click'); |
|||
expect(p.text()).toMatch(/^0$/); |
|||
}); |
|||
|
|||
it('should change if odd and if odd button clicked', () => { |
|||
const { buttons, p } = setup({ counter: 1 }); |
|||
buttons.at(2).simulate('click'); |
|||
expect(p.text()).toMatch(/^2$/); |
|||
}); |
|||
}); |
|||
}); |
@ -1,9 +0,0 @@ |
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP |
|||
|
|||
exports[`reducers counter should handle DECREMENT_COUNTER 1`] = `0`; |
|||
|
|||
exports[`reducers counter should handle INCREMENT_COUNTER 1`] = `2`; |
|||
|
|||
exports[`reducers counter should handle initial state 1`] = `0`; |
|||
|
|||
exports[`reducers counter should handle unknown action type 1`] = `1`; |
@ -1,22 +0,0 @@ |
|||
import counter from '../../app/reducers/counter'; |
|||
import { INCREMENT_COUNTER, DECREMENT_COUNTER } from '../../app/actions/counter'; |
|||
|
|||
describe('reducers', () => { |
|||
describe('counter', () => { |
|||
it('should handle initial state', () => { |
|||
expect(counter(undefined, {})).toMatchSnapshot(); |
|||
}); |
|||
|
|||
it('should handle INCREMENT_COUNTER', () => { |
|||
expect(counter(1, { type: INCREMENT_COUNTER })).toMatchSnapshot(); |
|||
}); |
|||
|
|||
it('should handle DECREMENT_COUNTER', () => { |
|||
expect(counter(1, { type: DECREMENT_COUNTER })).toMatchSnapshot(); |
|||
}); |
|||
|
|||
it('should handle unknown action type', () => { |
|||
expect(counter(1, { type: 'unknown' })).toMatchSnapshot(); |
|||
}); |
|||
}); |
|||
}); |
Loading…
Reference in new issue