Jack Mallers
7 years ago
64 changed files with 1216 additions and 1475 deletions
@ -1,45 +1,43 @@ |
|||||
// @flow
|
import React from 'react' |
||||
import React, { Component } from 'react' |
import PropTypes from 'prop-types' |
||||
import ReactModal from 'react-modal' |
import ReactModal from 'react-modal' |
||||
import Moment from 'react-moment' |
import Moment from 'react-moment' |
||||
import 'moment-timezone' |
import 'moment-timezone' |
||||
|
|
||||
|
const Modal = ({ isOpen, resetObject, children }) => { |
||||
class Modal extends Component { |
const customStyles = { |
||||
render() { |
overlay: { |
||||
const customStyles = { |
cursor: 'pointer' |
||||
overlay: { |
}, |
||||
cursor: 'pointer' |
content : { |
||||
}, |
top: 'auto', |
||||
content : { |
left: '20%', |
||||
top: 'auto', |
right: '0', |
||||
left: '20%', |
bottom: 'auto', |
||||
right: '0', |
width: '40%', |
||||
bottom: 'auto', |
margin: '50px auto' |
||||
width: '40%', |
|
||||
margin: '50px auto' |
|
||||
} |
|
||||
} |
} |
||||
const { |
} |
||||
isOpen, |
|
||||
resetObject, |
return ( |
||||
children |
<ReactModal |
||||
} = this.props |
isOpen={isOpen} |
||||
|
contentLabel="No Overlay Click Modal" |
||||
return ( |
ariaHideApp={true} |
||||
<ReactModal |
shouldCloseOnOverlayClick={true} |
||||
isOpen={isOpen} |
onRequestClose={() => resetObject(null)} |
||||
contentLabel="No Overlay Click Modal" |
parentSelector={() => document.body} |
||||
ariaHideApp={true} |
style={customStyles} |
||||
shouldCloseOnOverlayClick={true} |
> |
||||
onRequestClose={() => resetObject(null)} |
{children} |
||||
parentSelector={() => document.body} |
</ReactModal> |
||||
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 { connect } from 'react-redux' |
||||
import { |
import { |
||||
fetchInvoices, |
fetchInvoices, |
||||
searchInvoices, |
searchInvoices, |
||||
setInvoice, |
setInvoice, |
||||
invoiceSelectors |
invoiceSelectors |
||||
} from '../../../reducers/invoice' |
} from '../../../reducers/invoice' |
||||
import { |
import { |
||||
setPayment, |
setPayment, |
||||
fetchPayments, |
fetchPayments, |
||||
paymentSelectors |
paymentSelectors |
||||
} from '../../../reducers/payment' |
} from '../../../reducers/payment' |
||||
import Activity from '../components/Activity' |
import Activity from '../components/Activity' |
||||
|
|
||||
const mapDispatchToProps = { |
const mapDispatchToProps = { |
||||
setPayment, |
setPayment, |
||||
setInvoice, |
setInvoice, |
||||
fetchPayments, |
fetchPayments, |
||||
fetchInvoices, |
fetchInvoices, |
||||
searchInvoices |
searchInvoices |
||||
} |
} |
||||
|
|
||||
const mapStateToProps = (state) => ({ |
const mapStateToProps = (state) => ({ |
||||
activity: state.activity, |
activity: state.activity, |
||||
|
|
||||
payment: state.payment, |
payment: state.payment, |
||||
|
|
||||
invoice: state.invoice, |
invoice: state.invoice, |
||||
invoices: invoiceSelectors.invoices(state), |
invoices: invoiceSelectors.invoices(state), |
||||
|
|
||||
ticker: state.ticker, |
ticker: state.ticker, |
||||
|
|
||||
paymentModalOpen: paymentSelectors.paymentModalOpen(state), |
paymentModalOpen: paymentSelectors.paymentModalOpen(state), |
||||
invoiceModalOpen: invoiceSelectors.invoiceModalOpen(state) |
invoiceModalOpen: invoiceSelectors.invoiceModalOpen(state) |
||||
}) |
}) |
||||
|
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Activity) |
export default connect(mapStateToProps, mapDispatchToProps)(Activity) |
@ -1,3 +1,3 @@ |
|||||
import ActivityContainer from './containers/ActivityContainer' |
import ActivityContainer from './containers/ActivityContainer' |
||||
|
|
||||
export default ActivityContainer |
export default ActivityContainer |
||||
|
@ -1,122 +1,137 @@ |
|||||
// @flow
|
import React from 'react' |
||||
import React, { Component } from 'react' |
import PropTypes from 'prop-types' |
||||
import { FaDollar, FaBitcoin } from 'react-icons/lib/fa' |
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 { btc } from '../../../../../utils' |
||||
import styles from './Form.scss' |
import styles from './Form.scss' |
||||
|
|
||||
class Form extends Component { |
const Form = ({ |
||||
render() { |
form: { formType, amount, message, payment_request }, |
||||
const { |
setAmount, |
||||
form: { formType, amount, message, pubkey, payment_request }, |
setMessage, |
||||
setAmount, |
setPaymentRequest, |
||||
setMessage, |
ticker: { currency, btcTicker }, |
||||
setPubkey, |
isOpen, |
||||
setPaymentRequest, |
close, |
||||
ticker: { currency, btcTicker }, |
createInvoice, |
||||
isOpen, |
payInvoice, |
||||
close, |
fetchInvoice, |
||||
createInvoice, |
formInvoice |
||||
payInvoice, |
}) => { |
||||
fetchInvoice, |
const requestClicked = () => { |
||||
formInvoice |
createInvoice(amount, message, currency, btcTicker.price_usd) |
||||
} = this.props |
.then((success) => { |
||||
|
|
||||
const requestClicked = () => { |
|
||||
createInvoice(amount, message, currency, btcTicker.price_usd) |
|
||||
.then(success => { |
|
||||
if (success) { close() } |
if (success) { close() } |
||||
}) |
}) |
||||
} |
} |
||||
|
|
||||
const payClicked = () => { |
const payClicked = () => { |
||||
payInvoice(payment_request) |
payInvoice(payment_request) |
||||
.then(success => { |
.then((success) => { |
||||
console.log('success: ', success) |
|
||||
if (success) { close() } |
if (success) { close() } |
||||
}) |
}) |
||||
} |
} |
||||
|
|
||||
const paymentRequestOnChange = (payreq) => { |
const paymentRequestOnChange = (payreq) => { |
||||
setPaymentRequest(payreq) |
setPaymentRequest(payreq) |
||||
if (payreq.length === 124) { fetchInvoice(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 ( |
return ( |
||||
<div className={`${styles.formContainer} ${isOpen ? styles.open : ''}`}> |
<div className={`${styles.formContainer} ${isOpen ? styles.open : ''}`}> |
||||
<div className={styles.container}> |
<div className={styles.container}> |
||||
<div className={styles.esc} onClick={close}> |
<div className={styles.esc} onClick={close}> |
||||
<MdClose /> |
<MdClose /> |
||||
</div> |
</div> |
||||
<div className={styles.content}> |
<div className={styles.content}> |
||||
<section className={styles.amountContainer}> |
<section className={styles.amountContainer}> |
||||
<label> |
<label> |
||||
{ |
{ |
||||
currency === 'btc' ? |
currency === 'btc' ? |
||||
<FaBitcoin /> |
<FaBitcoin /> |
||||
: |
: |
||||
<FaDollar /> |
<FaDollar /> |
||||
} |
} |
||||
</label> |
</label> |
||||
<input |
<input |
||||
type='text' |
type='text' |
||||
size='' |
size='' |
||||
style={ |
style={ |
||||
formType === 'pay' ? |
formType === 'pay' ? |
||||
{ width: '75%', fontSize: '100px' } |
{ width: '75%', fontSize: '100px' } |
||||
: |
: |
||||
{ width: `${amount.length > 1 ? (amount.length * 15) - 5 : 25}%`, fontSize: `${190 - (amount.length ** 2)}px` } |
{ width: `${amount.length > 1 ? (amount.length * 15) - 5 : 25}%`, fontSize: `${190 - (amount.length ** 2)}px` } |
||||
} |
} |
||||
value={formType === 'pay' ? calculateAmount(formInvoice.amount) : amount} |
value={formType === 'pay' ? calculateAmount(formInvoice.amount) : amount} |
||||
onChange={(event) => setAmount(event.target.value)} |
onChange={event => setAmount(event.target.value)} |
||||
readOnly={formType === 'pay'} |
readOnly={formType === 'pay'} |
||||
/> |
/> |
||||
</section> |
</section> |
||||
{ |
{ |
||||
formType === 'pay' ? |
formType === 'pay' ? |
||||
<section className={styles.inputContainer}> |
<section className={styles.inputContainer}> |
||||
<label>Request:</label> |
<label>Request:</label> |
||||
<input |
<input |
||||
type='text' |
type='text' |
||||
placeholder='Payment Request' |
placeholder='Payment Request' |
||||
value={payment_request} |
value={payment_request} |
||||
onChange={(event) => paymentRequestOnChange(event.target.value)} |
onChange={(event) => paymentRequestOnChange(event.target.value)} |
||||
/> |
/> |
||||
</section> |
</section> |
||||
: |
: |
||||
<section className={styles.inputContainer}> |
<section className={styles.inputContainer}> |
||||
<label>For:</label> |
<label>For:</label> |
||||
<input |
<input |
||||
type='text' |
type='text' |
||||
placeholder='Dinner, Rent, etc' |
placeholder='Dinner, Rent, etc' |
||||
value={message} |
value={message} |
||||
onChange={(e) => setMessage(e.target.value)} |
onChange={(e) => setMessage(e.target.value)} |
||||
/> |
/> |
||||
</section> |
</section> |
||||
} |
} |
||||
{ |
{ |
||||
formType === 'pay' ? |
formType === 'pay' ? |
||||
<section className={styles.buttonGroup}> |
<section className={styles.buttonGroup}> |
||||
<div className={styles.button} onClick={payClicked}> |
<div className={styles.button} onClick={payClicked}> |
||||
Pay |
Pay |
||||
</div> |
</div> |
||||
</section> |
</section> |
||||
: |
: |
||||
<section className={styles.buttonGroup}> |
<section className={styles.buttonGroup}> |
||||
<div className={styles.button} onClick={requestClicked}> |
<div className={styles.button} onClick={requestClicked}> |
||||
Request |
Request |
||||
</div> |
</div> |
||||
</section> |
</section> |
||||
} |
} |
||||
</div> |
|
||||
</div> |
</div> |
||||
</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' |
import Form from './Form' |
||||
|
|
||||
export default Form |
export default Form |
||||
|
@ -1,26 +1,20 @@ |
|||||
// @flow
|
import React from 'react' |
||||
import React, { Component } from 'react' |
import PropTypes from 'prop-types' |
||||
import Websocket from 'react-websocket' |
import Websocket from 'react-websocket' |
||||
|
|
||||
class Socket extends Component { |
const Socket = ({ fetchChannels }) => { |
||||
render() { |
const onMessage = () => { |
||||
const onMessage = ({ event, data }) => { |
// TODO: Assumes only socket relationship is with channels. Actually flesh out socket logic
|
||||
console.log('data: ', data) |
fetchChannels() |
||||
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} /> |
|
||||
) |
|
||||
} |
} |
||||
|
|
||||
|
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' |
import AppContainer from './containers/AppContainer' |
||||
|
|
||||
export default AppContainer |
export default AppContainer |
||||
|
@ -1,65 +1,65 @@ |
|||||
// @flow
|
import React from 'react' |
||||
import React, { Component } from 'react' |
import PropTypes from 'prop-types' |
||||
import { btc } from '../../../../../../../utils' |
import { btc } from '../../../../../../../utils' |
||||
import styles from './Channel.scss' |
import styles from './Channel.scss' |
||||
|
|
||||
class Channel extends Component { |
const Channel = ({ ticker, channel, setChannel }) => ( |
||||
render() { |
<li className={styles.channel} onClick={() => setChannel(channel)}> |
||||
const { ticker, channel, setChannel } = this.props |
<h1 className={styles.status}>Status: Open</h1> |
||||
return ( |
<div className={styles.left}> |
||||
<li className={styles.channel} onClick={() => setChannel(channel)}> |
<section className={styles.remotePubkey}> |
||||
<h1 className={styles.status}>Status: Open</h1> |
<span>Remote Pubkey</span> |
||||
<div className={styles.left}> |
<h4>{channel.remote_pubkey}</h4> |
||||
<section className={styles.remotePubkey}> |
</section> |
||||
<span>Remote Pubkey</span> |
<section className={styles.channelPoint}> |
||||
<h4>{channel.remote_pubkey}</h4> |
<span>Channel Point</span> |
||||
</section> |
<h4>{channel.channel_point}</h4> |
||||
<section className={styles.channelPoint}> |
</section> |
||||
<span>Channel Point</span> |
</div> |
||||
<h4>{channel.channel_point}</h4> |
<div className={styles.right}> |
||||
</section> |
<section className={styles.capacity}> |
||||
</div> |
<span>Capacity</span> |
||||
<div className={styles.right}> |
<h2> |
||||
<section className={styles.capacity}> |
{ |
||||
<span>Capacity</span> |
ticker.currency === 'btc' ? |
||||
<h2> |
btc.satoshisToBtc(channel.capacity) |
||||
{ |
: |
||||
ticker.currency === 'btc' ? |
btc.satoshisToUsd(channel.capacity, ticker.btcTicker.price_usd) |
||||
btc.satoshisToBtc(channel.capacity) |
} |
||||
: |
</h2> |
||||
btc.satoshisToUsd(channel.capacity, ticker.btcTicker.price_usd) |
</section> |
||||
} |
<div className={styles.balances}> |
||||
</h2> |
<section> |
||||
</section> |
<h4> |
||||
<div className={styles.balances}> |
{ |
||||
<section> |
ticker.currency === 'btc' ? |
||||
<h4> |
btc.satoshisToBtc(channel.local_balance) |
||||
{ |
: |
||||
ticker.currency === 'btc' ? |
btc.satoshisToUsd(channel.local_balance, ticker.btcTicker.price_usd) |
||||
btc.satoshisToBtc(channel.local_balance) |
} |
||||
: |
</h4> |
||||
btc.satoshisToUsd(channel.local_balance, ticker.btcTicker.price_usd) |
<span>Local</span> |
||||
} |
</section> |
||||
</h4> |
<section> |
||||
<span>Local</span> |
<h4> |
||||
</section> |
{ |
||||
<section> |
ticker.currency === 'btc' ? |
||||
<h4> |
btc.satoshisToBtc(channel.remote_balance) |
||||
{ |
: |
||||
ticker.currency === 'btc' ? |
btc.satoshisToUsd(channel.remote_balance, ticker.btcTicker.price_usd) |
||||
btc.satoshisToBtc(channel.remote_balance) |
} |
||||
: |
</h4> |
||||
btc.satoshisToUsd(channel.remote_balance, ticker.btcTicker.price_usd) |
<span>Remote</span> |
||||
} |
</section> |
||||
</h4> |
</div> |
||||
<span>Remote</span> |
</div> |
||||
</section> |
</li> |
||||
</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' |
import Channel from './Channel' |
||||
|
|
||||
export default Channel |
export default Channel |
||||
|
@ -1,125 +1,126 @@ |
|||||
// @flow
|
import React from 'react' |
||||
import React, { Component } from 'react' |
import PropTypes from 'prop-types' |
||||
import ReactModal from 'react-modal' |
import ReactModal from 'react-modal' |
||||
import { FaUser, FaBitcoin, FaDollar } from 'react-icons/lib/fa' |
import { FaUser, FaBitcoin, FaDollar } from 'react-icons/lib/fa' |
||||
import { usd, btc } from '../../../../../../../utils' |
import { usd, btc } from '../../../../../../../utils' |
||||
import styles from './ChannelForm.scss' |
import styles from './ChannelForm.scss' |
||||
|
|
||||
class ChannelForm extends Component { |
const ChannelForm = ({ form, setForm, ticker, peers, openChannel }) => { |
||||
render() { |
const submitClicked = () => { |
||||
const submitClicked = () => { |
const { form: { node_key, local_amt, push_amt }, openChannel, ticker } = this.props |
||||
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)) |
||||
console.log('ticker: ', ticker) |
const pushamt = ticker.currency === 'btc' ? btc.btcToSatoshis(push_amt) : btc.btcToSatoshis(usd.usdToBtc(push_amt, ticker.btcTicker.price_usd)) |
||||
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 { form, setForm, ticker, peers, openChannel } = this.props |
openChannel({ pubkey: node_key, localamt, pushamt }).then(channel => { |
||||
|
if (channel.data) { setForm({ isOpen: false }) } |
||||
|
}) |
||||
|
} |
||||
|
|
||||
return ( |
const customStyles = { |
||||
<div> |
overlay: { |
||||
<ReactModal |
cursor: 'pointer', |
||||
isOpen={form.isOpen} |
overflowY: 'auto' |
||||
contentLabel="No Overlay Click Modal" |
}, |
||||
ariaHideApp={true} |
content : { |
||||
shouldCloseOnOverlayClick={true} |
top: 'auto', |
||||
onRequestClose={() => setForm({ isOpen: false })} |
left: '20%', |
||||
parentSelector={() => document.body} |
right: '0', |
||||
style={customStyles} |
bottom: 'auto', |
||||
> |
width: '40%', |
||||
<div className={styles.form}> |
margin: '50px auto', |
||||
<h1 className={styles.title}>Open a new channel</h1> |
padding: '40px' |
||||
|
} |
||||
<section className={styles.pubkey}> |
} |
||||
<label><FaUser /></label> |
|
||||
<input |
return ( |
||||
type='text' |
<div> |
||||
size='' |
<ReactModal |
||||
placeholder='Peer public key' |
isOpen={form.isOpen} |
||||
value={form.node_key} |
contentLabel="No Overlay Click Modal" |
||||
onChange={(event) => setForm({ node_key: event.target.value })} |
ariaHideApp={true} |
||||
/> |
shouldCloseOnOverlayClick={true} |
||||
</section> |
onRequestClose={() => setForm({ isOpen: false })} |
||||
<section className={styles.local}> |
parentSelector={() => document.body} |
||||
<label> |
style={customStyles} |
||||
{ |
> |
||||
ticker.currency === 'btc' ? |
<div className={styles.form}> |
||||
<FaBitcoin /> |
<h1 className={styles.title}>Open a new channel</h1> |
||||
: |
|
||||
<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> |
|
||||
|
|
||||
<ul className={styles.peers}> |
<section className={styles.pubkey}> |
||||
<h2>Connected Peers</h2> |
<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 ? |
ticker.currency === 'btc' ? |
||||
peers.map(peer => |
<FaBitcoin /> |
||||
<li key={peer.peer_id} className={styles.peer} onClick={() => setForm({ node_key: peer.pub_key })}> |
: |
||||
<h4>{peer.address}</h4> |
<FaDollar /> |
||||
<h1>{peer.pub_key}</h1> |
|
||||
</li> |
|
||||
) |
|
||||
: |
|
||||
null |
|
||||
} |
} |
||||
</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}> |
<ul className={styles.peers}> |
||||
<div className={styles.button} onClick={submitClicked}> |
<h2>Connected Peers</h2> |
||||
Submit |
{ |
||||
</div> |
peers.length ? |
||||
</div> |
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> |
</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 |
export default ChannelForm |
||||
|
@ -1,3 +1,3 @@ |
|||||
import ChannelForm from './ChannelForm' |
import ChannelForm from './ChannelForm' |
||||
|
|
||||
export default ChannelForm |
export default ChannelForm |
||||
|
@ -1,3 +1,3 @@ |
|||||
import ChannelModal from './ChannelModal' |
import ChannelModal from './ChannelModal' |
||||
|
|
||||
export default ChannelModal |
export default ChannelModal |
||||
|
@ -1,66 +1,67 @@ |
|||||
// @flow
|
|
||||
import { shell } from 'electron' |
import { shell } from 'electron' |
||||
import React, { Component } from 'react' |
import React from 'react' |
||||
|
import PropTypes from 'prop-types' |
||||
import { btc } from '../../../../../../../utils' |
import { btc } from '../../../../../../../utils' |
||||
import styles from './ClosedPendingChannel.scss' |
import styles from './ClosedPendingChannel.scss' |
||||
|
|
||||
class ClosedPendingChannel extends Component { |
const ClosedPendingChannel = ({ ticker, channel: { channel, closing_txid }, setChannel }) => ( |
||||
render() { |
<li className={styles.channel} onClick={() => shell.openExternal(`https://testnet.smartbit.com.au/tx/${closing_txid}`)}> |
||||
const { ticker, channel: { channel, closing_txid }, setChannel } = this.props |
<h1 className={styles.closing}>Status: Closing</h1> |
||||
return ( |
<div className={styles.left}> |
||||
<li className={styles.channel} onClick={() => shell.openExternal(`https://testnet.smartbit.com.au/tx/${closing_txid}`)}> |
<section className={styles.remotePubkey}> |
||||
<h1 className={styles.closing}>Status: Closing</h1> |
<span>Remote Pubkey</span> |
||||
<div className={styles.left}> |
<h4>{channel.remote_node_pub}</h4> |
||||
<section className={styles.remotePubkey}> |
</section> |
||||
<span>Remote Pubkey</span> |
<section className={styles.channelPoint}> |
||||
<h4>{channel.remote_node_pub}</h4> |
<span>Channel Point</span> |
||||
</section> |
<h4>{channel.channel_point}</h4> |
||||
<section className={styles.channelPoint}> |
</section> |
||||
<span>Channel Point</span> |
</div> |
||||
<h4>{channel.channel_point}</h4> |
<div className={styles.right}> |
||||
</section> |
<section className={styles.capacity}> |
||||
</div> |
<span>Capacity</span> |
||||
<div className={styles.right}> |
<h2> |
||||
<section className={styles.capacity}> |
{ |
||||
<span>Capacity</span> |
ticker.currency === 'btc' ? |
||||
<h2> |
btc.satoshisToBtc(channel.capacity) |
||||
{ |
: |
||||
ticker.currency === 'btc' ? |
btc.satoshisToUsd(channel.capacity, ticker.btcTicker.price_usd) |
||||
btc.satoshisToBtc(channel.capacity) |
} |
||||
: |
</h2> |
||||
btc.satoshisToUsd(channel.capacity, ticker.btcTicker.price_usd) |
</section> |
||||
} |
<div className={styles.balances}> |
||||
</h2> |
<section> |
||||
</section> |
<h4> |
||||
<div className={styles.balances}> |
{ |
||||
<section> |
ticker.currency === 'btc' ? |
||||
<h4> |
btc.satoshisToBtc(channel.local_balance) |
||||
{ |
: |
||||
ticker.currency === 'btc' ? |
btc.satoshisToUsd(channel.local_balance, ticker.btcTicker.price_usd) |
||||
btc.satoshisToBtc(channel.local_balance) |
} |
||||
: |
</h4> |
||||
btc.satoshisToUsd(channel.local_balance, ticker.btcTicker.price_usd) |
<span>Local</span> |
||||
} |
</section> |
||||
</h4> |
<section> |
||||
<span>Local</span> |
<h4> |
||||
</section> |
{ |
||||
<section> |
ticker.currency === 'btc' ? |
||||
<h4> |
btc.satoshisToBtc(channel.remote_balance) |
||||
{ |
: |
||||
ticker.currency === 'btc' ? |
btc.satoshisToUsd(channel.remote_balance, ticker.btcTicker.price_usd) |
||||
btc.satoshisToBtc(channel.remote_balance) |
} |
||||
: |
</h4> |
||||
btc.satoshisToUsd(channel.remote_balance, ticker.btcTicker.price_usd) |
<span>Remote</span> |
||||
} |
</section> |
||||
</h4> |
</div> |
||||
<span>Remote</span> |
</div> |
||||
</section> |
</li> |
||||
</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' |
import ClosedPendingChannel from './ClosedPendingChannel' |
||||
|
|
||||
export default ClosedPendingChannel |
export default ClosedPendingChannel |
||||
|
@ -1,66 +1,66 @@ |
|||||
// @flow
|
// @flow
|
||||
import { shell } from 'electron' |
import { shell } from 'electron' |
||||
import React, { Component } from 'react' |
import React from 'react' |
||||
|
import PropTypes from 'prop-types' |
||||
import { btc } from '../../../../../../../utils' |
import { btc } from '../../../../../../../utils' |
||||
import styles from './OpenPendingChannel.scss' |
import styles from './OpenPendingChannel.scss' |
||||
|
|
||||
class OpenPendingChannel extends Component { |
const OpenPendingChannel = ({ ticker, channel: { channel } }) => ( |
||||
render() { |
<li className={styles.channel} onClick={() => shell.openExternal(`https://testnet.smartbit.com.au/tx/${channel.channel_point.split(':')[0]}`)}> |
||||
const { ticker, channel: { channel } } = this.props |
<h1 className={styles.pending}>Status: Pending</h1> |
||||
return ( |
<div className={styles.left}> |
||||
<li className={styles.channel} onClick={() => shell.openExternal(`https://testnet.smartbit.com.au/tx/${channel.channel_point.split(':')[0]}`)}> |
<section className={styles.remotePubkey}> |
||||
<h1 className={styles.pending}>Status: Pending</h1> |
<span>Remote Pubkey</span> |
||||
<div className={styles.left}> |
<h4>{channel.remote_node_pub}</h4> |
||||
<section className={styles.remotePubkey}> |
</section> |
||||
<span>Remote Pubkey</span> |
<section className={styles.channelPoint}> |
||||
<h4>{channel.remote_node_pub}</h4> |
<span>Channel Point</span> |
||||
</section> |
<h4>{channel.channel_point}</h4> |
||||
<section className={styles.channelPoint}> |
</section> |
||||
<span>Channel Point</span> |
</div> |
||||
<h4>{channel.channel_point}</h4> |
<div className={styles.right}> |
||||
</section> |
<section className={styles.capacity}> |
||||
</div> |
<span>Capacity</span> |
||||
<div className={styles.right}> |
<h2> |
||||
<section className={styles.capacity}> |
{ |
||||
<span>Capacity</span> |
ticker.currency === 'btc' ? |
||||
<h2> |
btc.satoshisToBtc(channel.capacity) |
||||
{ |
: |
||||
ticker.currency === 'btc' ? |
btc.satoshisToUsd(channel.capacity, ticker.btcTicker.price_usd) |
||||
btc.satoshisToBtc(channel.capacity) |
} |
||||
: |
</h2> |
||||
btc.satoshisToUsd(channel.capacity, ticker.btcTicker.price_usd) |
</section> |
||||
} |
<div className={styles.balances}> |
||||
</h2> |
<section> |
||||
</section> |
<h4> |
||||
<div className={styles.balances}> |
{ |
||||
<section> |
ticker.currency === 'btc' ? |
||||
<h4> |
btc.satoshisToBtc(channel.local_balance) |
||||
{ |
: |
||||
ticker.currency === 'btc' ? |
btc.satoshisToUsd(channel.local_balance, ticker.btcTicker.price_usd) |
||||
btc.satoshisToBtc(channel.local_balance) |
} |
||||
: |
</h4> |
||||
btc.satoshisToUsd(channel.local_balance, ticker.btcTicker.price_usd) |
<span>Local</span> |
||||
} |
</section> |
||||
</h4> |
<section> |
||||
<span>Local</span> |
<h4> |
||||
</section> |
{ |
||||
<section> |
ticker.currency === 'btc' ? |
||||
<h4> |
btc.satoshisToBtc(channel.remote_balance) |
||||
{ |
: |
||||
ticker.currency === 'btc' ? |
btc.satoshisToUsd(channel.remote_balance, ticker.btcTicker.price_usd) |
||||
btc.satoshisToBtc(channel.remote_balance) |
} |
||||
: |
</h4> |
||||
btc.satoshisToUsd(channel.remote_balance, ticker.btcTicker.price_usd) |
<span>Remote</span> |
||||
} |
</section> |
||||
</h4> |
</div> |
||||
<span>Remote</span> |
</div> |
||||
</section> |
</li> |
||||
</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' |
import OpenPendingChannel from './OpenPendingChannel' |
||||
|
|
||||
export default OpenPendingChannel |
export default OpenPendingChannel |
||||
|
@ -1,3 +1,3 @@ |
|||||
import Channels from './Channels' |
import Channels from './Channels' |
||||
|
|
||||
export default Channels |
export default Channels |
||||
|
@ -1,51 +1,56 @@ |
|||||
// @flow
|
import React from 'react' |
||||
import React, { Component } from 'react' |
import PropTypes from 'prop-types' |
||||
import { TiPlus } from 'react-icons/lib/ti' |
import { TiPlus } from 'react-icons/lib/ti' |
||||
import PeerModal from './components/PeerModal' |
import PeerModal from './components/PeerModal' |
||||
import PeerForm from './components/PeerForm' |
import PeerForm from './components/PeerForm' |
||||
import Peer from './components/Peer' |
import Peer from './components/Peer' |
||||
import styles from './Peers.scss' |
import styles from './Peers.scss' |
||||
|
|
||||
class Peers extends Component { |
const Peers = ({ |
||||
render() { |
peersLoading, |
||||
const { |
peers, |
||||
peersLoading, |
setPeer, |
||||
peers, |
modalPeer, |
||||
peer, |
peerModalOpen, |
||||
setPeer, |
peerForm, |
||||
modalPeer, |
setPeerForm, |
||||
peerModalOpen, |
connect, |
||||
peerForm, |
disconnect |
||||
setPeerForm, |
}) => ( |
||||
connect, |
<div className={styles.peers}> |
||||
disconnect, |
<PeerModal isOpen={peerModalOpen} resetPeer={setPeer} peer={modalPeer} disconnect={disconnect} /> |
||||
} = this.props |
<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 ( |
Peers.propTypes = { |
||||
<div className={styles.peers}> |
peersLoading: PropTypes.bool.isRequired, |
||||
<PeerModal isOpen={peerModalOpen} resetPeer={setPeer} peer={modalPeer} disconnect={disconnect} /> |
peers: PropTypes.array.isRequired, |
||||
<PeerForm form={peerForm} setForm={setPeerForm} connect={connect} /> |
setPeer: PropTypes.func.isRequired, |
||||
<div className={styles.header}> |
modalPeer: PropTypes.object, |
||||
<h3>Peers</h3> |
peerModalOpen: PropTypes.bool.isRequired, |
||||
<div |
peerForm: PropTypes.object.isRequired, |
||||
className={`${styles.connectPeer} hint--top`} |
setPeerForm: PropTypes.func.isRequired, |
||||
data-hint='Connect to a peer' |
connect: PropTypes.func.isRequired, |
||||
onClick={() => setPeerForm({ isOpen: true })} |
disconnect: PropTypes.func.isRequired |
||||
> |
|
||||
<TiPlus /> |
|
||||
</div> |
|
||||
</div> |
|
||||
<ul> |
|
||||
{ |
|
||||
!peersLoading ? |
|
||||
peers.map(peer => <Peer key={peer.peer_id} peer={peer} setPeer={setPeer} />) |
|
||||
: |
|
||||
'Loading...' |
|
||||
} |
|
||||
</ul> |
|
||||
</div> |
|
||||
) |
|
||||
} |
|
||||
} |
} |
||||
|
|
||||
export default Peers |
export default Peers |
||||
|
@ -1,18 +1,17 @@ |
|||||
// @flow
|
import React from 'react' |
||||
import React, { Component } from 'react' |
import PropTypes from 'prop-types' |
||||
import styles from './Peer.scss' |
import styles from './Peer.scss' |
||||
|
|
||||
class Peer extends Component { |
const Peer = ({ peer, setPeer }) => ( |
||||
render() { |
<li className={styles.peer} onClick={() => setPeer(peer)}> |
||||
const { peer, setPeer } = this.props |
<h4>{peer.address}</h4> |
||||
return ( |
<h1>{peer.pub_key}</h1> |
||||
<li className={styles.peer} onClick={() => setPeer(peer)}> |
</li> |
||||
<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' |
import Peer from './Peer' |
||||
|
|
||||
export default Peer |
export default Peer |
||||
|
@ -1,3 +1,3 @@ |
|||||
import PeerForm from './PeerForm' |
import PeerForm from './PeerForm' |
||||
|
|
||||
export default PeerForm |
export default PeerForm |
||||
|
@ -1,3 +1,3 @@ |
|||||
import PeerModal from './PeerModal' |
import PeerModal from './PeerModal' |
||||
|
|
||||
export default PeerModal |
export default PeerModal |
||||
|
@ -1,3 +1,3 @@ |
|||||
import Peers from './Peers' |
import Peers from './Peers' |
||||
|
|
||||
export default Peers |
export default Peers |
||||
|
@ -1,51 +1,51 @@ |
|||||
import { connect } from 'react-redux' |
import { connect } from 'react-redux' |
||||
import { fetchInfo } from '../../../reducers/info' |
import { fetchInfo } from '../../../reducers/info' |
||||
import { |
import { |
||||
fetchPeers, |
fetchPeers, |
||||
setPeer, |
setPeer, |
||||
peersSelectors, |
peersSelectors, |
||||
setPeerForm, |
setPeerForm, |
||||
connectRequest, |
connectRequest, |
||||
disconnectRequest |
disconnectRequest |
||||
} from '../../../reducers/peers' |
} from '../../../reducers/peers' |
||||
import { |
import { |
||||
fetchChannels, |
fetchChannels, |
||||
fetchPendingChannels, |
fetchPendingChannels, |
||||
setChannel, |
setChannel, |
||||
channelsSelectors, |
channelsSelectors, |
||||
setChannelForm, |
setChannelForm, |
||||
openChannel |
openChannel |
||||
} from '../../../reducers/channels' |
} from '../../../reducers/channels' |
||||
import Wallet from '../components/Wallet' |
import Wallet from '../components/Wallet' |
||||
|
|
||||
const mapDispatchToProps = { |
const mapDispatchToProps = { |
||||
fetchInfo, |
fetchInfo, |
||||
|
|
||||
fetchPeers, |
fetchPeers, |
||||
setPeer, |
setPeer, |
||||
connectRequest, |
connectRequest, |
||||
disconnectRequest, |
disconnectRequest, |
||||
|
|
||||
fetchChannels, |
fetchChannels, |
||||
fetchPendingChannels, |
fetchPendingChannels, |
||||
setChannel, |
setChannel, |
||||
openChannel, |
openChannel, |
||||
|
|
||||
setPeerForm, |
setPeerForm, |
||||
setChannelForm |
setChannelForm |
||||
} |
} |
||||
|
|
||||
const mapStateToProps = (state) => ({ |
const mapStateToProps = (state) => ({ |
||||
info: state.info, |
info: state.info, |
||||
ticker: state.ticker, |
ticker: state.ticker, |
||||
|
|
||||
peers: state.peers, |
peers: state.peers, |
||||
channels: state.channels, |
channels: state.channels, |
||||
|
|
||||
allChannels: channelsSelectors.allChannels(state), |
allChannels: channelsSelectors.allChannels(state), |
||||
|
|
||||
peerModalOpen: peersSelectors.peerModalOpen(state), |
peerModalOpen: peersSelectors.peerModalOpen(state), |
||||
channelModalOpen: channelsSelectors.channelModalOpen(state), |
channelModalOpen: channelsSelectors.channelModalOpen(state) |
||||
}) |
}) |
||||
|
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Wallet) |
export default connect(mapStateToProps, mapDispatchToProps)(Wallet) |
||||
|
@ -1,3 +1,3 @@ |
|||||
import WalletContainer from './containers/WalletContainer' |
import WalletContainer from './containers/WalletContainer' |
||||
|
|
||||
export default WalletContainer |
export default WalletContainer |
||||
|
@ -1,9 +1,9 @@ |
|||||
export function usdToBtc(usd, rate) { |
export function usdToBtc(usd, rate) { |
||||
if (usd == undefined || usd === '') return |
if (usd === undefined || usd === '') return null |
||||
|
|
||||
return (usd / rate).toFixed(8) |
return (usd / rate).toFixed(8) |
||||
} |
} |
||||
|
|
||||
export default { |
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