Browse Source

fix(lint): start fixing linting error

renovate/lint-staged-8.x
Jack Mallers 7 years ago
parent
commit
abb1b02a36
  1. 27
      .eslintrc
  2. 9
      app/api/index.js
  3. 10
      app/containers/Root.js
  4. 10
      app/package.json
  5. 10
      app/reducers/activity.js
  6. 8
      app/reducers/balance.js
  7. 42
      app/reducers/channels.js
  8. 29
      app/reducers/form.js
  9. 4
      app/reducers/info.js
  10. 24
      app/reducers/payment.js
  11. 9
      app/reducers/ticker.js
  12. 44
      app/routes/activity/components/Activity.js
  13. 188
      app/routes/activity/components/components/Invoices.js
  14. 74
      app/routes/activity/components/components/Modal.js
  15. 190
      app/routes/activity/components/components/Payments.js
  16. 38
      app/routes/activity/containers/ActivityContainer.js
  17. 2
      app/routes/activity/index.js
  18. 219
      app/routes/app/components/components/Form/Form.js
  19. 2
      app/routes/app/components/components/Form/index.js
  20. 36
      app/routes/app/components/components/Socket.js
  21. 36
      app/routes/app/containers/AppContainer.js
  22. 2
      app/routes/app/index.js
  23. 43
      app/routes/wallet/components/Wallet.js
  24. 129
      app/routes/wallet/components/components/Channels/Channels.js
  25. 2
      app/routes/wallet/components/components/Channels/Channels.scss
  26. 120
      app/routes/wallet/components/components/Channels/components/Channel/Channel.js
  27. 2
      app/routes/wallet/components/components/Channels/components/Channel/index.js
  28. 221
      app/routes/wallet/components/components/Channels/components/ChannelForm/ChannelForm.js
  29. 2
      app/routes/wallet/components/components/Channels/components/ChannelForm/index.js
  30. 2
      app/routes/wallet/components/components/Channels/components/ChannelModal/ChannelModal.js
  31. 2
      app/routes/wallet/components/components/Channels/components/ChannelModal/ChannelModal.scss
  32. 2
      app/routes/wallet/components/components/Channels/components/ChannelModal/index.js
  33. 121
      app/routes/wallet/components/components/Channels/components/ClosedPendingChannel/ClosedPendingChannel.js
  34. 2
      app/routes/wallet/components/components/Channels/components/ClosedPendingChannel/index.js
  35. 118
      app/routes/wallet/components/components/Channels/components/OpenPendingChannel/OpenPendingChannel.js
  36. 2
      app/routes/wallet/components/components/Channels/components/OpenPendingChannel/index.js
  37. 2
      app/routes/wallet/components/components/Channels/index.js
  38. 87
      app/routes/wallet/components/components/Peers/Peers.js
  39. 2
      app/routes/wallet/components/components/Peers/Peers.scss
  40. 27
      app/routes/wallet/components/components/Peers/components/Peer/Peer.js
  41. 2
      app/routes/wallet/components/components/Peers/components/Peer/Peer.scss
  42. 2
      app/routes/wallet/components/components/Peers/components/Peer/index.js
  43. 2
      app/routes/wallet/components/components/Peers/components/PeerForm/PeerForm.scss
  44. 2
      app/routes/wallet/components/components/Peers/components/PeerForm/index.js
  45. 2
      app/routes/wallet/components/components/Peers/components/PeerModal/PeerModal.scss
  46. 2
      app/routes/wallet/components/components/Peers/components/PeerModal/index.js
  47. 2
      app/routes/wallet/components/components/Peers/index.js
  48. 68
      app/routes/wallet/containers/WalletContainer.js
  49. 2
      app/routes/wallet/index.js
  50. 2
      app/store/configureStore.dev.js
  51. 6
      app/utils/index.js
  52. 6
      app/utils/usd.js
  53. 2
      internals/scripts/CheckNodeEnv.js
  54. 396
      package-lock.json
  55. 11
      package.json
  56. 13
      test/actions/__snapshots__/counter.spec.js.snap
  57. 41
      test/actions/counter.spec.js
  58. 68
      test/components/Counter.spec.js
  59. 63
      test/components/__snapshots__/Counter.spec.js.snap
  60. 57
      test/containers/CounterPage.spec.js
  61. 9
      test/reducers/__snapshots__/counter.spec.js.snap
  62. 22
      test/reducers/counter.spec.js
  63. 10
      webpack.config.base.js
  64. 2
      webpack.config.main.prod.js

27
.eslintrc

@ -10,27 +10,12 @@
"node": true "node": true
}, },
"rules": { "rules": {
"arrow-parens": ["off"], "comma-dangle": ["error", "never"],
"compat/compat": "error", "semi": 0,
"consistent-return": "off", "indent": 2,
"comma-dangle": "off", "jsx-quotes": ["error", "prefer-single"],
"flowtype-errors/show-errors": "error", "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
"generator-star-spacing": "off", "no-static-element-interactions": 0
"import/no-unresolved": "error",
"import/no-extraneous-dependencies": "off",
"no-console": "off",
"no-use-before-define": "off",
"no-multi-assign": "off",
"promise/param-names": "error",
"promise/always-return": "error",
"promise/catch-or-return": "error",
"promise/no-native": "off",
"react/sort-comp": ["error", {
"order": ["type-annotations", "static-methods", "lifecycle", "everything-else", "render"]
}],
"react/jsx-no-bind": "off",
"react/jsx-filename-extension": ["error", { "extensions": [".js", ".jsx"] }],
"react/prefer-stateless-function": "off"
}, },
"plugins": [ "plugins": [
"flowtype", "flowtype",

9
app/api/index.js

@ -24,12 +24,11 @@ export function callApi(endpoint, method = 'get', data = null) {
} }
return axios(payload) return axios(payload)
.then(response => response.data) .then(response => response.data)
.catch(error => error) .catch(error => error)
} }
export function callApis(endpoints) { export function callApis(endpoints) {
const BASE_URL = 'http://localhost:3000/api/'
return axios.all(endpoints.map(endpoint => callApi(endpoint))) return axios.all(endpoints.map(endpoint => callApi(endpoint)))
} }
@ -39,6 +38,6 @@ export function requestTicker() {
method: 'get', method: 'get',
url: BASE_URL url: BASE_URL
}) })
.then(response => response.data) .then(response => response.data)
.catch(error => error) .catch(error => error)
} }

10
app/containers/Root.js

@ -1,8 +1,8 @@
// @flow // @flow
import React from 'react'; import React from 'react'
import { Provider } from 'react-redux'; import { Provider } from 'react-redux'
import { ConnectedRouter } from 'react-router-redux'; import { ConnectedRouter } from 'react-router-redux'
import Routes from '../routes'; import Routes from '../routes'
type RootType = { type RootType = {
store: {}, store: {},
@ -16,5 +16,5 @@ export default function Root({ store, history }: RootType) {
<Routes /> <Routes />
</ConnectedRouter> </ConnectedRouter>
</Provider> </Provider>
); )
} }

10
app/package.json

@ -1,12 +1,12 @@
{ {
"name": "electron-react-boilerplate", "name": "Zap Desktop",
"productName": "electron-react-boilerplate", "productName": "Zap Desktop",
"version": "1.0.0", "version": "0.0.1",
"description": "Electron application boilerplate based on React, React Router, Webpack, React Hot Loader for rapid application development", "description": "Electron application boilerplate based on React, React Router, Webpack, React Hot Loader for rapid application development",
"main": "./main.prod.js", "main": "./main.prod.js",
"author": { "author": {
"name": "C. T. Lin", "name": "Jack Mallers",
"email": "chentsulin@gmail.com", "email": "jimmymowschess@gmail.com",
"url": "https://github.com/chentsulin" "url": "https://github.com/chentsulin"
}, },
"scripts": { "scripts": {

10
app/reducers/activity.js

@ -18,7 +18,7 @@ export function receiveActvity(data) {
return { return {
type: RECEIVE_ACTIVITY, type: RECEIVE_ACTIVITY,
payments: data[0].data.payments.reverse(), payments: data[0].data.payments.reverse(),
invoices: data[1].data.invoices.reverse() invoices: data[1].data.invoices.reverse()
} }
} }
@ -32,8 +32,10 @@ export const fetchActivity = () => async (dispatch) => {
// Action Handlers // Action Handlers
// ------------------------------------ // ------------------------------------
const ACTION_HANDLERS = { const ACTION_HANDLERS = {
[GET_ACTIVITY]: (state) => ({ ...state, activityLoading: true }), [GET_ACTIVITY]: state => ({ ...state, activityLoading: true }),
[RECEIVE_ACTIVITY]: (state, { payments, invoices }) => ({ ...state, activityLoading: false, payments, invoices }) [RECEIVE_ACTIVITY]: (state, { payments, invoices }) => (
{ ...state, activityLoading: false, payments, invoices }
)
} }
// ------------------------------------ // ------------------------------------
@ -49,4 +51,4 @@ export default function activityReducer(state = initialState, action) {
const handler = ACTION_HANDLERS[action.type] const handler = ACTION_HANDLERS[action.type]
return handler ? handler(state, action) : state return handler ? handler(state, action) : state
} }

8
app/reducers/balance.js

@ -32,8 +32,10 @@ export const fetchBalance = () => async (dispatch) => {
// Action Handlers // Action Handlers
// ------------------------------------ // ------------------------------------
const ACTION_HANDLERS = { const ACTION_HANDLERS = {
[GET_BALANCE]: (state) => ({ ...state, balanceLoading: true }), [GET_BALANCE]: state => ({ ...state, balanceLoading: true }),
[RECEIVE_BALANCE]: (state, { walletBalance, channelBalance }) => ({ ...state, balanceLoading: false, walletBalance, channelBalance }) [RECEIVE_BALANCE]: (state, { walletBalance, channelBalance }) => (
{ ...state, balanceLoading: false, walletBalance, channelBalance }
)
} }
// ------------------------------------ // ------------------------------------
@ -49,4 +51,4 @@ export default function balanceReducer(state = initialState, action) {
const handler = ACTION_HANDLERS[action.type] const handler = ACTION_HANDLERS[action.type]
return handler ? handler(state, action) : state return handler ? handler(state, action) : state
} }

42
app/reducers/channels.js

@ -1,5 +1,4 @@
import { createSelector } from 'reselect' import { createSelector } from 'reselect'
import { usd, btc } from '../utils'
import { callApi, callApis } from '../api' import { callApi, callApis } from '../api'
// ------------------------------------ // ------------------------------------
// Constants // Constants
@ -47,19 +46,6 @@ export function receiveChannels(channels) {
} }
} }
export function getPendingChannels() {
return {
type: GET_PENDING_CHANNELS
}
}
export function receivePendingChannels({ pendingChannels }) {
return {
type: RECEIVE_PENDING_CHANNELS,
pendingChannels
}
}
export function openingChannel() { export function openingChannel() {
return { return {
type: OPENING_CHANNEL type: OPENING_CHANNEL
@ -88,9 +74,12 @@ export const openChannel = ({ pubkey, localamt, pushamt }) => async (dispatch) =
const payload = { pubkey, localamt, pushamt } const payload = { pubkey, localamt, pushamt }
dispatch(openingChannel()) dispatch(openingChannel())
const channel = await callApi('addchannel', 'post', payload) const channel = await callApi('addchannel', 'post', payload)
console.log('channel: ', channel)
channel.data ? dispatch(openingSuccessful()) : dispatch(openingFailure()) if (channel.data) {
dispatch(openingSuccessful())
} else {
dispatch(openingFailure())
}
return channel return channel
} }
@ -99,12 +88,16 @@ export const openChannel = ({ pubkey, localamt, pushamt }) => async (dispatch) =
// Action Handlers // Action Handlers
// ------------------------------------ // ------------------------------------
const ACTION_HANDLERS = { const ACTION_HANDLERS = {
[SET_CHANNEL_FORM]: (state, { form }) => ({ ...state, channelForm: Object.assign({}, state.channelForm, form) }), [SET_CHANNEL_FORM]: (state, { form }) => (
{ ...state, channelForm: Object.assign({}, state.channelForm, form) }
),
[SET_CHANNEL]: (state, { channel }) => ({ ...state, channel }), [SET_CHANNEL]: (state, { channel }) => ({ ...state, channel }),
[GET_CHANNELS]: (state) => ({ ...state, channelsLoading: true }), [GET_CHANNELS]: (state) => ({ ...state, channelsLoading: true }),
[RECEIVE_CHANNELS]: (state, { channels, pendingChannels }) => ({ ...state, channelsLoading: false, channels, pendingChannels }), [RECEIVE_CHANNELS]: (state, { channels, pendingChannels }) => (
{ ...state, channelsLoading: false, channels, pendingChannels }
),
[OPENING_CHANNEL]: (state) => ({ ...state, openingChannel: true }), [OPENING_CHANNEL]: (state) => ({ ...state, openingChannel: true }),
} }
@ -140,18 +133,7 @@ const initialState = {
pendingChannels: { pendingChannels: {
total_limbo_balance: '', total_limbo_balance: '',
pending_open_channels: [], pending_open_channels: [],
pending_closing_channels: [ pending_closing_channels: [],
{
"channel": {
"remote_node_pub": "02ef6248210e27b0f0df4d11d876e63f56e04bcb0054d0d8b6ba6a1a3e90dc56e1",
"channel_point": "5f6c522970e81069075c27be8799d0e2fb16dd4975cbd84c07b1a8bc9ece9918:0",
"capacity": "10000",
"local_balance": "312",
"remote_balance": "0"
},
"closing_txid": "4c0a25b0955e9efca46065a317a9560c9e3618356d4985e1a905eeb662e40bdb"
}
],
pending_force_closing_channels: [] pending_force_closing_channels: []
}, },
channel: null, channel: null,

29
app/reducers/form.js

@ -1,3 +1,13 @@
// Initial State
const initialState = {
modalOpen: false,
formType: 'pay',
amount: '0',
message: '',
pubkey: '',
payment_request: ''
}
// Constants // Constants
// ------------------------------------ // ------------------------------------
export const SET_FORM = 'SET_FORM' export const SET_FORM = 'SET_FORM'
@ -39,10 +49,10 @@ export function setPubkey(pubkey) {
} }
} }
export function setPaymentRequest(payment_request) { export function setPaymentRequest(paymentRequest) {
return { return {
type: SET_PAYMENT_REQUEST, type: SET_PAYMENT_REQUEST,
payment_request paymentRequest
} }
} }
@ -60,24 +70,17 @@ const ACTION_HANDLERS = {
[SET_AMOUNT]: (state, { amount }) => ({ ...state, amount }), [SET_AMOUNT]: (state, { amount }) => ({ ...state, amount }),
[SET_MESSAGE]: (state, { message }) => ({ ...state, message }), [SET_MESSAGE]: (state, { message }) => ({ ...state, message }),
[SET_PUBKEY]: (state, { pubkey }) => ({ ...state, pubkey }), [SET_PUBKEY]: (state, { pubkey }) => ({ ...state, pubkey }),
[SET_PAYMENT_REQUEST]: (state, { payment_request }) => ({ ...state, payment_request }), [SET_PAYMENT_REQUEST]: (state, { paymentRequest }) => (
{ ...state, payment_request: paymentRequest }
),
[RESET_FORM]: () => (initialState) [RESET_FORM]: () => (initialState)
} }
// ------------------------------------ // ------------------------------------
// Reducer // Reducer
// ------------------------------------ // ------------------------------------
const initialState = {
modalOpen: false,
formType: 'pay',
amount: '0',
message: '',
pubkey: '',
payment_request: ''
}
export default function formReducer(state = initialState, action) { export default function formReducer(state = initialState, action) {
const handler = ACTION_HANDLERS[action.type] const handler = ACTION_HANDLERS[action.type]
return handler ? handler(state, action) : state return handler ? handler(state, action) : state
} }

4
app/reducers/info.js

@ -31,7 +31,7 @@ export const fetchInfo = () => async (dispatch) => {
// Action Handlers // Action Handlers
// ------------------------------------ // ------------------------------------
const ACTION_HANDLERS = { const ACTION_HANDLERS = {
[GET_INFO]: (state) => ({ ...state, infoLoading: true }), [GET_INFO]: state => ({ ...state, infoLoading: true }),
[RECEIVE_INFO]: (state, { data }) => ({ ...state, infoLoading: false, data }) [RECEIVE_INFO]: (state, { data }) => ({ ...state, infoLoading: false, data })
} }
@ -47,4 +47,4 @@ export default function infoReducer(state = initialState, action) {
const handler = ACTION_HANDLERS[action.type] const handler = ACTION_HANDLERS[action.type]
return handler ? handler(state, action) : state return handler ? handler(state, action) : state
} }

24
app/reducers/payment.js

@ -1,6 +1,6 @@
import { createSelector } from 'reselect' import { createSelector } from 'reselect'
import { callApi } from '../api' import { callApi } from '../api'
import { btc } from '../utils'
// ------------------------------------ // ------------------------------------
// Constants // Constants
// ------------------------------------ // ------------------------------------
@ -58,19 +58,19 @@ export function paymentFailed() {
export const fetchPayments = () => async (dispatch) => { export const fetchPayments = () => async (dispatch) => {
dispatch(getPayments()) dispatch(getPayments())
const payments = await callApi('payments') const payments = await callApi('payments')
payments ?
if (payments) {
dispatch(receivePayments(payments.data)) dispatch(receivePayments(payments.data))
: } else {
dispatch(paymentFailed()) dispatch(paymentFailed())
}
return payments return payments
} }
export const payInvoice = (payment_request) => async (dispatch) => { export const payInvoice = (paymentRequest) => async (dispatch) => {
console.log('payment_request: ', payment_request)
dispatch(sendPayment()) dispatch(sendPayment())
const payment = await callApi('sendpayment', 'post', { payment_request }) const payment = await callApi('sendpayment', 'post', { payment_request: paymentRequest })
console.log('payment: ', payment)
payment ? payment ?
dispatch(fetchPayments()) dispatch(fetchPayments())
@ -86,9 +86,11 @@ export const payInvoice = (payment_request) => async (dispatch) => {
// ------------------------------------ // ------------------------------------
const ACTION_HANDLERS = { const ACTION_HANDLERS = {
[SET_PAYMENT]: (state, { payment }) => ({ ...state, payment }), [SET_PAYMENT]: (state, { payment }) => ({ ...state, payment }),
[GET_PAYMENTS]: (state) => ({ ...state, paymentLoading: true }), [GET_PAYMENTS]: state => ({ ...state, paymentLoading: true }),
[RECEIVE_PAYMENTS]: (state, { payments }) => ({ ...state, paymentLoading: false, payments }), [RECEIVE_PAYMENTS]: (state, { payments }) => ({ ...state, paymentLoading: false, payments }),
[PAYMENT_SUCCESSFULL]: (state, { payment }) => ({ ...state, paymentLoading: false, payments: [payment, ...state.payments] }) [PAYMENT_SUCCESSFULL]: (state, { payment }) => (
{ ...state, paymentLoading: false, payments: [payment, ...state.payments] }
)
} }
const paymentSelectors = {} const paymentSelectors = {}
@ -96,7 +98,7 @@ const modalPaymentSelector = state => state.payment.payment
paymentSelectors.paymentModalOpen = createSelector( paymentSelectors.paymentModalOpen = createSelector(
modalPaymentSelector, modalPaymentSelector,
payment => payment ? true : false payment => (payment ? true : false)
) )
export { paymentSelectors } export { paymentSelectors }
@ -114,4 +116,4 @@ export default function paymentReducer(state = initialState, action) {
const handler = ACTION_HANDLERS[action.type] const handler = ACTION_HANDLERS[action.type]
return handler ? handler(state, action) : state return handler ? handler(state, action) : state
} }

9
app/reducers/ticker.js

@ -1,4 +1,3 @@
import { createSelector } from 'reselect'
import { requestTicker } from '../api' import { requestTicker } from '../api'
// ------------------------------------ // ------------------------------------
// Constants // Constants
@ -43,8 +42,10 @@ export const fetchTicker = () => async (dispatch) => {
// ------------------------------------ // ------------------------------------
const ACTION_HANDLERS = { const ACTION_HANDLERS = {
[SET_CURRENCY]: (state, { currency }) => ({ ...state, currency }), [SET_CURRENCY]: (state, { currency }) => ({ ...state, currency }),
[GET_TICKER]: (state) => ({ ...state, tickerLoading: true }), [GET_TICKER]: state => ({ ...state, tickerLoading: true }),
[RECIEVE_TICKER]: (state, { ticker }) => ({...state, tickerLoading: false, btcTicker: ticker[0] }) [RECIEVE_TICKER]: (state, { ticker }) => (
{ ...state, tickerLoading: false, btcTicker: ticker[0] }
)
} }
// ------------------------------------ // ------------------------------------
@ -61,4 +62,4 @@ export default function tickerReducer(state = initialState, action) {
const handler = ACTION_HANDLERS[action.type] const handler = ACTION_HANDLERS[action.type]
return handler ? handler(state, action) : state return handler ? handler(state, action) : state
} }

44
app/routes/activity/components/Activity.js

@ -1,5 +1,5 @@
// @flow
import React, { Component } from 'react' import React, { Component } from 'react'
import PropTypes from 'prop-types'
import CSSTransitionGroup from 'react-transition-group/CSSTransitionGroup' import CSSTransitionGroup from 'react-transition-group/CSSTransitionGroup'
import { MdSearch } from 'react-icons/lib/md' import { MdSearch } from 'react-icons/lib/md'
import Payments from './components/Payments' import Payments from './components/Payments'
@ -7,19 +7,19 @@ import Invoices from './components/Invoices'
import styles from './Activity.scss' import styles from './Activity.scss'
class Activity extends Component { class Activity extends Component {
constructor(props, context) { constructor(props, context) {
super(props, context) super(props, context)
this.state = { this.state = {
tab: 1 tab: 1
}
} }
}
componentWillMount() { componentWillMount() {
const { fetchPayments, fetchInvoices } = this.props const { fetchPayments, fetchInvoices } = this.props
fetchPayments() fetchPayments()
fetchInvoices() fetchInvoices()
} }
render() { render() {
const { tab } = this.state const { tab } = this.state
@ -39,10 +39,10 @@ class Activity extends Component {
return ( return (
<div> <div>
<div className={styles.search}> <div className={styles.search}>
<label className={`${styles.label} ${styles.input}`}> <label className={`${styles.label} ${styles.input}`}>
<MdSearch /> <MdSearch />
</label> </label>
<input <input
value={tab === 1 ? '' : invoicesSearchText} value={tab === 1 ? '' : invoicesSearchText}
onChange={event => tab === 1 ? null : searchInvoices(event.target.value)} onChange={event => tab === 1 ? null : searchInvoices(event.target.value)}
className={`${styles.text} ${styles.input}`} className={`${styles.text} ${styles.input}`}
@ -70,7 +70,6 @@ class Activity extends Component {
{ {
tab === 1 ? tab === 1 ?
<Payments <Payments
key={1}
payment={payment} payment={payment}
payments={payments} payments={payments}
ticker={ticker} ticker={ticker}
@ -79,7 +78,6 @@ class Activity extends Component {
/> />
: :
<Invoices <Invoices
key={2}
invoice={invoice} invoice={invoice}
invoices={invoices} invoices={invoices}
ticker={ticker} ticker={ticker}
@ -94,4 +92,16 @@ class Activity extends Component {
} }
} }
Activity.propTypes = {
ticker: PropTypes.object.isRequired,
searchInvoices: PropTypes.func.isRequired,
invoices: PropTypes.array.isRequired,
invoice: PropTypes.object.isRequired,
payment: PropTypes.object.isRequired,
setPayment: PropTypes.func.isRequired,
setInvoice: PropTypes.func.isRequired,
paymentModalOpen: PropTypes.bool.isRequired,
invoiceModalOpen: PropTypes.bool.isRequired
}
export default Activity export default Activity

188
app/routes/activity/components/components/Invoices.js

@ -1,5 +1,5 @@
// @flow import React from 'react'
import React, { Component } from 'react' import PropTypes from 'prop-types'
import Moment from 'react-moment' import Moment from 'react-moment'
import 'moment-timezone' import 'moment-timezone'
import { FaBitcoin, FaDollar } from 'react-icons/lib/fa' import { FaBitcoin, FaDollar } from 'react-icons/lib/fa'
@ -9,105 +9,105 @@ import Modal from './Modal'
import { btc } from '../../../../utils' import { btc } from '../../../../utils'
import styles from './Invoices.scss' import styles from './Invoices.scss'
class Invoices extends Component { const Invoices = ({
render() { invoice,
const { invoices,
invoice, ticker,
invoices, setInvoice,
ticker, invoiceModalOpen
setInvoice, }) => (
invoiceModalOpen <div>
} = this.props <Modal isOpen={invoiceModalOpen} resetObject={setInvoice}>
{
return ( invoice ?
<div> <div className={styles.invoiceModal}>
<Modal isOpen={invoiceModalOpen} resetObject={setInvoice}> <h3>{invoice.memo}</h3>
{ <h1>
invoice ? {
<div className={styles.invoiceModal}> ticker.currency === 'btc' ?
<h3>{invoice.memo}</h3> <FaBitcoin style={{ verticalAlign: 'top' }} />
<h1> :
{ <FaDollar style={{ verticalAlign: 'top' }} />
ticker.currency === 'btc' ? }
<FaBitcoin style={{ verticalAlign: 'top' }} /> <span className={styles.value}>
: {
<FaDollar style={{ verticalAlign: 'top' }} /> ticker.currency === 'btc' ?
} btc.satoshisToBtc(invoice.value)
<span className={styles.value}> :
{ btc.satoshisToUsd(invoice.value, ticker.btcTicker.price_usd)
ticker.currency === 'btc' ? }
btc.satoshisToBtc(invoice.value) </span>
: </h1>
btc.satoshisToUsd(invoice.value, ticker.btcTicker.price_usd) <div className={styles.qrcode}>
} <QRCode value={invoice.payment_request} size={200} />
</span> <input
</h1> readOnly
<div className={styles.qrcode}> className={styles.paymentRequest}
<QRCode value={invoice.payment_request} size={200} /> onClick={(event) => event.target.select()}
<input defaultValue={invoice.payment_request}
readOnly />
className={styles.paymentRequest} </div>
onClick={(event) => event.target.select()} <div className={styles.settled}>
defaultValue={invoice.payment_request} {
/> invoice.settled ?
</div> <p><MdCheck style={{ verticalAlign: 'top' }} /> Paid</p>
<div className={styles.settled}> :
{ <p>Not Paid</p>
invoice.settled ? }
<p><MdCheck style={{ verticalAlign: 'top' }} /> Paid</p> </div>
: <p className={styles.date}>
<p>Not Paid</p> Created on
} <Moment format='MMM Do'>{invoice.creation_date * 1000}</Moment>
</div> </p>
<p className={styles.date}> </div>
Created on :
<Moment format='MMM Do'> null
{invoice.creation_date * 1000} }
</Moment> </Modal>
</p> <ul className={styles.invoices}>
</div> <li className={styles.invoiceTitles}>
: <div className={styles.left}>
null <div>Payment Request</div>
} </div>
</Modal> <div className={styles.center}>
<ul className={styles.invoices}> <div>Memo</div>
<li className={styles.invoiceTitles}> </div>
<div className={styles.right}>
<div>Amount</div>
</div>
</li>
{
invoices.map((invoice, index) =>
<li key={index} className={styles.invoice} onClick={() => setInvoice(invoice)}>
<div className={styles.left}> <div className={styles.left}>
<div>Payment Request</div> <div className={styles.path}>{`${invoice.payment_request.substring(0, 75)}...`}</div>
</div> </div>
<div className={styles.center}> <div className={styles.center}>
<div>Memo</div> <div>{invoice.memo}</div>
</div> </div>
<div className={styles.right}> <div className={styles.right}>
<div>Amount</div> <div className={invoice.settled ? styles.settled : null}>
{
ticker.currency === 'btc' ?
btc.satoshisToBtc(invoice.value)
:
btc.satoshisToUsd(invoice.value, ticker.btcTicker.price_usd)
}
</div>
</div> </div>
</li> </li>
{ )
invoices.map((invoice, index) => }
<li key={index} className={styles.invoice} onClick={() => setInvoice(invoice)}> </ul>
<div className={styles.left}> </div>
<div className={styles.path}>{`${invoice.payment_request.substring(0, 75)}...`}</div> )
</div>
<div className={styles.center}> Invoices.propTypes = {
<div>{invoice.memo}</div> invoice: PropTypes.object,
</div> invoices: PropTypes.array.isRequired,
<div className={styles.right}> ticker: PropTypes.object.isRequired,
<div className={invoice.settled ? styles.settled : null}> setInvoice: PropTypes.func.isRequired,
{ invoiceModalOpen: PropTypes.bool.isRequired
ticker.currency === 'btc' ?
btc.satoshisToBtc(invoice.value)
:
btc.satoshisToUsd(invoice.value, ticker.btcTicker.price_usd)
}
</div>
</div>
</li>
)
}
</ul>
</div>
)
}
} }
export default Invoices export default Invoices

74
app/routes/activity/components/components/Modal.js

@ -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

190
app/routes/activity/components/components/Payments.js

@ -1,5 +1,5 @@
// @flow import React from 'react'
import React, { Component } from 'react' import PropTypes from 'prop-types'
import Moment from 'react-moment' import Moment from 'react-moment'
import 'moment-timezone' import 'moment-timezone'
import { FaBitcoin, FaDollar } from 'react-icons/lib/fa' import { FaBitcoin, FaDollar } from 'react-icons/lib/fa'
@ -7,107 +7,107 @@ import Modal from './Modal'
import { btc } from '../../../../utils' import { btc } from '../../../../utils'
import styles from './Payments.scss' import styles from './Payments.scss'
class Payments extends Component { const Payments = ({
render() { payment,
const { payments,
payment, ticker,
payments, setPayment,
ticker, paymentModalOpen
setPayment, }) => (
paymentModalOpen <div>
} = this.props <Modal isOpen={paymentModalOpen} resetObject={setPayment}>
console.log('payments: ', payments) {
return ( payment ?
<div> <div className={styles.paymentModal}>
<Modal isOpen={paymentModalOpen} resetObject={setPayment}> <h3>{payment.payment_hash}</h3>
{ <h1>
payment ? {
<div className={styles.paymentModal}> ticker.currency === 'btc' ?
<h3>{payment.payment_hash}</h3> <FaBitcoin style={{ verticalAlign: 'top' }} />
<h1> :
{ <FaDollar style={{ verticalAlign: 'top' }} />
ticker.currency === 'btc' ? }
<FaBitcoin style={{ verticalAlign: 'top' }} /> <span className={styles.value}>
: {
<FaDollar style={{ verticalAlign: 'top' }} /> ticker.currency === 'btc' ?
} btc.satoshisToBtc(payment.value)
<span className={styles.value}> :
{ btc.satoshisToUsd(payment.value, ticker.btcTicker.price_usd)
ticker.currency === 'btc' ? }
btc.satoshisToBtc(payment.value) </span>
: </h1>
btc.satoshisToUsd(payment.value, ticker.btcTicker.price_usd) <dl>
} <dt>Fee</dt>
</span> <dd>{payment.fee}</dd>
</h1> <dt>Date</dt>
<dl> <dd>
<dt>Fee</dt> <Moment format='MMM Do'>{payment.creation_date * 1000}</Moment>
<dd>{payment.fee}</dd> </dd>
<dt>Date</dt> </dl>
<dd> </div>
<Moment format='MMM Do'> :
{payment.creation_date * 1000} null
</Moment></dd> }
</dl> </Modal>
</div> <ul className={styles.payments}>
: <li className={styles.paymentTitles}>
null <div className={styles.left}>
} <div>Public Key</div>
</Modal> </div>
<div className={styles.center}>
<ul className={styles.payments}> <div>Date</div>
<li className={styles.paymentTitles}> </div>
<div className={styles.center}>
<div>Fee</div>
</div>
<div className={styles.right}>
<div>Amount</div>
</div>
</li>
{
payments.map((payment, index) =>
<li key={index} className={styles.payment} onClick={() => setPayment(payment)}>
<div className={styles.left}> <div className={styles.left}>
<div>Public Key</div> <div className={styles.path}>{payment.path[0]}</div>
</div> </div>
<div className={styles.center}> <div className={styles.center}>
<div>Date</div> <div className={styles.date}>
<Moment format="MMMM Do">{payment.creation_date * 1000}</Moment>
</div>
</div> </div>
<div className={styles.center}> <div className={styles.right}>
<div>Fee</div> <span className={styles.fee}>
{
ticker.currency === 'btc' ?
btc.satoshisToBtc(payment.fee)
:
btc.satoshisToUsd(payment.fee, ticker.btcTicker.price_usd)
}
</span>
</div> </div>
<div className={styles.right}> <div className={styles.right}>
<div>Amount</div> <span className={styles.value}>
{
ticker.currency === 'btc' ?
btc.satoshisToBtc(payment.value)
:
btc.satoshisToUsd(payment.value, ticker.btcTicker.price_usd)
}
</span>
</div> </div>
</li> </li>
{ )
payments.map((payment, index) => }
<li key={index} className={styles.payment} onClick={() => setPayment(payment)}> </ul>
<div className={styles.left}> </div>
<div className={styles.path}>{payment.path[0]}</div> )
</div>
<div className={styles.center}> Payments.propTypes = {
<div className={styles.date}> payment: PropTypes.object,
<Moment format="MMMM Do">{payment.creation_date * 1000}</Moment> payments: PropTypes.array.isRequired,
</div> ticker: PropTypes.object.isRequired,
</div> setPayment: PropTypes.func.isRequired,
<div className={styles.right}> paymentModalOpen: PropTypes.bool.isRequired
<span className={styles.fee}>
{
ticker.currency === 'btc' ?
btc.satoshisToBtc(payment.fee)
:
btc.satoshisToUsd(payment.fee, ticker.btcTicker.price_usd)
}
</span>
</div>
<div className={styles.right}>
<span className={styles.value}>
{
ticker.currency === 'btc' ?
btc.satoshisToBtc(payment.value)
:
btc.satoshisToUsd(payment.value, ticker.btcTicker.price_usd)
}
</span>
</div>
</li>
)
}
</ul>
</div>
)
}
} }
export default Payments export default Payments

38
app/routes/activity/containers/ActivityContainer.js

@ -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)

2
app/routes/activity/index.js

@ -1,3 +1,3 @@
import ActivityContainer from './containers/ActivityContainer' import ActivityContainer from './containers/ActivityContainer'
export default ActivityContainer export default ActivityContainer

219
app/routes/app/components/components/Form/Form.js

@ -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

2
app/routes/app/components/components/Form/index.js

@ -1,3 +1,3 @@
import Form from './Form' import Form from './Form'
export default Form export default Form

36
app/routes/app/components/components/Socket.js

@ -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

36
app/routes/app/containers/AppContainer.js

@ -10,27 +10,27 @@ import { fetchChannels } from '../../../reducers/channels'
import { setAmount, setMessage, setPubkey, setPaymentRequest } from '../../../reducers/form' import { setAmount, setMessage, setPubkey, setPaymentRequest } from '../../../reducers/form'
const mapDispatchToProps = { const mapDispatchToProps = {
fetchTicker, fetchTicker,
setCurrency, setCurrency,
fetchBalance, fetchBalance,
fetchInfo, fetchInfo,
setAmount, setAmount,
setMessage, setMessage,
setPubkey, setPubkey,
setPaymentRequest, setPaymentRequest,
setForm, setForm,
createInvoice, createInvoice,
payInvoice, payInvoice,
fetchChannels, fetchChannels,
fetchInvoice fetchInvoice
} }
const mapStateToProps = (state) => ({ const mapStateToProps = (state) => ({
ticker: state.ticker, ticker: state.ticker,
balance: state.balance, balance: state.balance,
payment: state.payment, payment: state.payment,
form: state.form, form: state.form,
invoice: state.invoice invoice: state.invoice
}) })
export default connect(mapStateToProps, mapDispatchToProps)(App) export default connect(mapStateToProps, mapDispatchToProps)(App)

2
app/routes/app/index.js

@ -1,3 +1,3 @@
import AppContainer from './containers/AppContainer' import AppContainer from './containers/AppContainer'
export default AppContainer export default AppContainer

43
app/routes/wallet/components/Wallet.js

@ -1,26 +1,25 @@
// @flow
import React, { Component } from 'react' import React, { Component } from 'react'
import PropTypes from 'prop-types'
import ReactSVG from 'react-svg' import ReactSVG from 'react-svg'
import { FaCircle } from 'react-icons/lib/fa' import Peers from './components/Peers'
import Peers from './components/peers' import Channels from './components/Channels'
import Channels from './components/channels'
import styles from './Wallet.scss' import styles from './Wallet.scss'
class Wallet extends Component { class Wallet extends Component {
componentWillMount() { componentWillMount() {
const { fetchInfo, fetchPeers, fetchChannels } = this.props const { fetchInfo, fetchPeers, fetchChannels } = this.props
fetchInfo() fetchInfo()
fetchPeers() fetchPeers()
fetchChannels() fetchChannels()
} }
render() { render() {
const { const {
info, info,
ticker, ticker,
peers: { peersLoading, peers, peer, peerForm }, peers: { peersLoading, peers, peer, peerForm },
channels: { channelsLoading, channels, channel, channelForm, pendingChannels }, channels: { channelsLoading, channels, channel, channelForm, pendingChannels },
setPeer, setPeer,
setChannel, setChannel,
peerModalOpen, peerModalOpen,
@ -31,13 +30,13 @@ class Wallet extends Component {
disconnectRequest, disconnectRequest,
allChannels, allChannels,
openChannel openChannel
} = this.props } = this.props
return ( return (
<div className={styles.wallet}> <div className={styles.wallet}>
<section className={styles.header}> <section className={styles.header}>
<ReactSVG path='../resources/zap_2.svg' /> <ReactSVG path='../resources/zap_2.svg' />
<h1>{info.data.identity_pubkey}</h1> <h1>{info.data.identity_pubkey}</h1>
</section> </section>
<section className={styles.walletData}> <section className={styles.walletData}>
<Peers <Peers
@ -71,5 +70,11 @@ class Wallet extends Component {
} }
} }
Wallet.propTypes = {
fetchInfo: PropTypes.func.isRequired,
fetchPeers: PropTypes.func.isRequired,
fetchChannels: PropTypes.func.isRequired
}
export default Wallet export default Wallet

129
app/routes/wallet/components/components/Channels/Channels.js

@ -1,5 +1,5 @@
// @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 ChannelModal from './components/ChannelModal' import ChannelModal from './components/ChannelModal'
import ChannelForm from './components/ChannelForm' import ChannelForm from './components/ChannelForm'
@ -8,67 +8,72 @@ import OpenPendingChannel from './components/OpenPendingChannel'
import ClosedPendingChannel from './components/ClosedPendingChannel' import ClosedPendingChannel from './components/ClosedPendingChannel'
import styles from './Channels.scss' import styles from './Channels.scss'
class Channels extends Component { const Channels = ({
render() { ticker,
const { peers,
ticker, channelsLoading,
peers, modalChannel,
channelsLoading, setChannel,
channels, channelModalOpen,
modalChannel, channelForm,
setChannel, setChannelForm,
channelModalOpen, allChannels,
channelForm, openChannel
setChannelForm, }) => (
pendingChannels, <div className={styles.channels}>
allChannels, <ChannelModal isOpen={channelModalOpen} resetChannel={setChannel} channel={modalChannel} />
openChannel <ChannelForm form={channelForm} setForm={setChannelForm} ticker={ticker} peers={peers} openChannel={openChannel} />
} = this.props <div className={styles.header}>
<h3>Channels</h3>
<div
className={`${styles.openChannel} hint--top`}
data-hint='Open a channel'
onClick={() => setChannelForm({ isOpen: true })}
>
<TiPlus />
</div>
</div>
<ul>
{
!channelsLoading ?
allChannels.map((channel, index) => {
if (channel.hasOwnProperty('blocks_till_open')) {
return (
<OpenPendingChannel key={index} channel={channel} ticker={ticker} />
)
} else if (channel.hasOwnProperty('closing_txid')) {
return (
<ClosedPendingChannel key={index} channel={channel} ticker={ticker} />
)
} else {
return (
<Channel
key={channel.chan_id}
ticker={ticker}
channel={channel}
setChannel={setChannel}
/>
)
}
})
:
'Loading...'
}
</ul>
</div>
)
return ( Channels.propTypes = {
<div className={styles.channels}> ticker: PropTypes.object.isRequired,
<ChannelModal isOpen={channelModalOpen} resetChannel={setChannel} channel={modalChannel} /> peers: PropTypes.array.isRequired,
<ChannelForm form={channelForm} setForm={setChannelForm} ticker={ticker} peers={peers} openChannel={openChannel} /> channelsLoading: PropTypes.bool.isRequired,
<div className={styles.header}> modalChannel: PropTypes.object,
<h3>Channels</h3> setChannel: PropTypes.func.isRequired,
<div channelModalOpen: PropTypes.bool.isRequired,
className={`${styles.openChannel} hint--top`} channelForm: PropTypes.object.isRequired,
data-hint='Open a channel' setChannelForm: PropTypes.func.isRequired,
onClick={() => setChannelForm({ isOpen: true })} allChannels: PropTypes.array.isRequired,
> openChannel: PropTypes.func.isRequired
<TiPlus />
</div>
</div>
<ul>
{
!channelsLoading ?
allChannels.map((channel, index) => {
if (channel.hasOwnProperty('blocks_till_open')) {
return (
<OpenPendingChannel key={index} channel={channel} ticker={ticker} />
)
} else if (channel.hasOwnProperty('closing_txid')) {
return (
<ClosedPendingChannel key={index} channel={channel} ticker={ticker} />
)
} else {
return (
<Channel
key={channel.chan_id}
ticker={ticker}
channel={channel}
setChannel={setChannel}
/>
)
}
})
:
'Loading...'
}
</ul>
</div>
)
}
} }
export default Channels export default Channels

2
app/routes/wallet/components/components/Channels/Channels.scss

@ -42,4 +42,4 @@
font-weight: 400; font-weight: 400;
margin-bottom: 10px; margin-bottom: 10px;
} }
} }

120
app/routes/wallet/components/components/Channels/components/Channel/Channel.js

@ -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

2
app/routes/wallet/components/components/Channels/components/Channel/index.js

@ -1,3 +1,3 @@
import Channel from './Channel' import Channel from './Channel'
export default Channel export default Channel

221
app/routes/wallet/components/components/Channels/components/ChannelForm/ChannelForm.js

@ -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

2
app/routes/wallet/components/components/Channels/components/ChannelForm/index.js

@ -1,3 +1,3 @@
import ChannelForm from './ChannelForm' import ChannelForm from './ChannelForm'
export default ChannelForm export default ChannelForm

2
app/routes/wallet/components/components/Channels/components/ChannelModal/ChannelModal.js

@ -90,4 +90,4 @@ class ChannelModal extends Component {
} }
export default ChannelModal export default ChannelModal

2
app/routes/wallet/components/components/Channels/components/ChannelModal/ChannelModal.scss

@ -121,4 +121,4 @@
text-align: center; text-align: center;
margin-top: 50px; margin-top: 50px;
text-transform: uppercase; text-transform: uppercase;
} }

2
app/routes/wallet/components/components/Channels/components/ChannelModal/index.js

@ -1,3 +1,3 @@
import ChannelModal from './ChannelModal' import ChannelModal from './ChannelModal'
export default ChannelModal export default ChannelModal

121
app/routes/wallet/components/components/Channels/components/ClosedPendingChannel/ClosedPendingChannel.js

@ -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

2
app/routes/wallet/components/components/Channels/components/ClosedPendingChannel/index.js

@ -1,3 +1,3 @@
import ClosedPendingChannel from './ClosedPendingChannel' import ClosedPendingChannel from './ClosedPendingChannel'
export default ClosedPendingChannel export default ClosedPendingChannel

118
app/routes/wallet/components/components/Channels/components/OpenPendingChannel/OpenPendingChannel.js

@ -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

2
app/routes/wallet/components/components/Channels/components/OpenPendingChannel/index.js

@ -1,3 +1,3 @@
import OpenPendingChannel from './OpenPendingChannel' import OpenPendingChannel from './OpenPendingChannel'
export default OpenPendingChannel export default OpenPendingChannel

2
app/routes/wallet/components/components/Channels/index.js

@ -1,3 +1,3 @@
import Channels from './Channels' import Channels from './Channels'
export default Channels export default Channels

87
app/routes/wallet/components/components/Peers/Peers.js

@ -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

2
app/routes/wallet/components/components/Peers/Peers.scss

@ -42,4 +42,4 @@
font-weight: 400; font-weight: 400;
margin-bottom: 10px; margin-bottom: 10px;
} }
} }

27
app/routes/wallet/components/components/Peers/components/Peer/Peer.js

@ -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

2
app/routes/wallet/components/components/Peers/components/Peer/Peer.scss

@ -31,4 +31,4 @@
font-weight: 200; font-weight: 200;
color: $main; color: $main;
} }
} }

2
app/routes/wallet/components/components/Peers/components/Peer/index.js

@ -1,3 +1,3 @@
import Peer from './Peer' import Peer from './Peer'
export default Peer export default Peer

2
app/routes/wallet/components/components/Peers/components/PeerForm/PeerForm.scss

@ -66,4 +66,4 @@
border-right: 1px solid lighten($main, 20%); border-right: 1px solid lighten($main, 20%);
} }
} }
} }

2
app/routes/wallet/components/components/Peers/components/PeerForm/index.js

@ -1,3 +1,3 @@
import PeerForm from './PeerForm' import PeerForm from './PeerForm'
export default PeerForm export default PeerForm

2
app/routes/wallet/components/components/Peers/components/PeerModal/PeerModal.scss

@ -70,4 +70,4 @@
background: darken($red, 10%); background: darken($red, 10%);
} }
} }
} }

2
app/routes/wallet/components/components/Peers/components/PeerModal/index.js

@ -1,3 +1,3 @@
import PeerModal from './PeerModal' import PeerModal from './PeerModal'
export default PeerModal export default PeerModal

2
app/routes/wallet/components/components/Peers/index.js

@ -1,3 +1,3 @@
import Peers from './Peers' import Peers from './Peers'
export default Peers export default Peers

68
app/routes/wallet/containers/WalletContainer.js

@ -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)

2
app/routes/wallet/index.js

@ -1,3 +1,3 @@
import WalletContainer from './containers/WalletContainer' import WalletContainer from './containers/WalletContainer'
export default WalletContainer export default WalletContainer

2
app/store/configureStore.dev.js

@ -35,7 +35,7 @@ const configureStore = (initialState?: counterStateType) => {
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
// Options: http://zalmoxisus.github.io/redux-devtools-extension/API/Arguments.html // Options: http://zalmoxisus.github.io/redux-devtools-extension/API/Arguments.html
actionCreators, actionCreators
}) })
: compose; : compose;
/* eslint-enable no-underscore-dangle */ /* eslint-enable no-underscore-dangle */

6
app/utils/index.js

@ -2,6 +2,6 @@ import btc from './btc'
import usd from './usd' import usd from './usd'
export default { export default {
btc, btc,
usd usd
} }

6
app/utils/usd.js

@ -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
} }

2
internals/scripts/CheckNodeEnv.js

@ -7,9 +7,11 @@ export default function CheckNodeEnv(expectedEnv: string) {
} }
if (process.env.NODE_ENV !== expectedEnv) { if (process.env.NODE_ENV !== expectedEnv) {
/* eslint-disable */
console.log(chalk.whiteBright.bgRed.bold( console.log(chalk.whiteBright.bgRed.bold(
`"process.env.NODE_ENV" must be "${expectedEnv}" to use this webpack config` `"process.env.NODE_ENV" must be "${expectedEnv}" to use this webpack config`
)); ));
/* eslint-enable */
process.exit(2); process.exit(2);
} }
} }

396
package-lock.json

@ -408,9 +408,9 @@
} }
}, },
"aria-query": { "aria-query": {
"version": "0.5.0", "version": "0.7.0",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-0.5.0.tgz", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-0.7.0.tgz",
"integrity": "sha1-heMVLNjMW6sY2+1hzZxPzlT6ecM=", "integrity": "sha512-/r2lHl09V3o74+2MLKEdewoj37YZqiQZnfen1O4iNlrOjUgeKuu1U2yF3iKh6HJxqF+OXkLMfQv65Z/cvxD6vA==",
"dev": true, "dev": true,
"requires": { "requires": {
"ast-types-flow": "0.0.7" "ast-types-flow": "0.0.7"
@ -2781,12 +2781,12 @@
"dev": true "dev": true
}, },
"cli-cursor": { "cli-cursor": {
"version": "1.0.2", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
"integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
"dev": true, "dev": true,
"requires": { "requires": {
"restore-cursor": "1.0.1" "restore-cursor": "2.0.0"
} }
}, },
"cli-width": { "cli-width": {
@ -4618,9 +4618,9 @@
} }
}, },
"emoji-regex": { "emoji-regex": {
"version": "6.5.0", "version": "6.5.1",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.5.0.tgz", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.5.1.tgz",
"integrity": "sha512-Vja85njef5T0kGfRUFkyl0etU9+49L1LNKR5oE41wAGRtJR64/a+JX3I8YCIur/uXj4Kt4cNe5i8bfd58ilgKQ==", "integrity": "sha512-PAHp6TxrCy7MGMFidro8uikr+zlJJKJ/Q6mm2ExZ7HwkyR9lSVFfE3kt36qcwa24BQL7y0G9axycGjK1A/0uNQ==",
"dev": true "dev": true
}, },
"emojis-list": { "emojis-list": {
@ -4888,48 +4888,61 @@
} }
}, },
"eslint": { "eslint": {
"version": "3.19.0", "version": "4.4.1",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.4.1.tgz",
"integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", "integrity": "sha1-mc1+r8/8ov+Zpcj18qR01jZLS9M=",
"dev": true, "dev": true,
"requires": { "requires": {
"ajv": "5.2.2",
"babel-code-frame": "6.22.0", "babel-code-frame": "6.22.0",
"chalk": "1.1.3", "chalk": "1.1.3",
"concat-stream": "1.6.0", "concat-stream": "1.6.0",
"cross-spawn": "5.1.0",
"debug": "2.6.8", "debug": "2.6.8",
"doctrine": "2.0.0", "doctrine": "2.0.0",
"escope": "3.6.0", "eslint-scope": "3.7.1",
"espree": "3.4.3", "espree": "3.5.0",
"esquery": "1.0.0", "esquery": "1.0.0",
"estraverse": "4.2.0", "estraverse": "4.2.0",
"esutils": "2.0.2", "esutils": "2.0.2",
"file-entry-cache": "2.0.0", "file-entry-cache": "2.0.0",
"functional-red-black-tree": "1.0.1",
"glob": "7.1.2", "glob": "7.1.2",
"globals": "9.18.0", "globals": "9.18.0",
"ignore": "3.3.3", "ignore": "3.3.3",
"imurmurhash": "0.1.4", "imurmurhash": "0.1.4",
"inquirer": "0.12.0", "inquirer": "3.2.1",
"is-my-json-valid": "2.16.0",
"is-resolvable": "1.0.0", "is-resolvable": "1.0.0",
"js-yaml": "3.7.0", "js-yaml": "3.9.1",
"json-stable-stringify": "1.0.1", "json-stable-stringify": "1.0.1",
"levn": "0.3.0", "levn": "0.3.0",
"lodash": "4.17.4", "lodash": "4.17.4",
"minimatch": "3.0.4",
"mkdirp": "0.5.1", "mkdirp": "0.5.1",
"natural-compare": "1.4.0", "natural-compare": "1.4.0",
"optionator": "0.8.2", "optionator": "0.8.2",
"path-is-inside": "1.0.2", "path-is-inside": "1.0.2",
"pluralize": "1.2.1", "pluralize": "4.0.0",
"progress": "1.1.8", "progress": "2.0.0",
"require-uncached": "1.0.3", "require-uncached": "1.0.3",
"shelljs": "0.7.8", "semver": "5.3.0",
"strip-bom": "3.0.0",
"strip-json-comments": "2.0.1", "strip-json-comments": "2.0.1",
"table": "3.8.3", "table": "4.0.1",
"text-table": "0.2.0", "text-table": "0.2.0"
"user-home": "2.0.0"
}, },
"dependencies": { "dependencies": {
"ajv": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.2.tgz",
"integrity": "sha1-R8aNaehvXZUxA7AHSpQw3GPaXjk=",
"dev": true,
"requires": {
"co": "4.6.0",
"fast-deep-equal": "1.0.0",
"json-schema-traverse": "0.3.1",
"json-stable-stringify": "1.0.1"
}
},
"chalk": { "chalk": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
@ -4943,28 +4956,41 @@
"supports-color": "2.0.0" "supports-color": "2.0.0"
} }
}, },
"strip-bom": { "esprima": {
"version": "3.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz",
"integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==",
"dev": true "dev": true
},
"js-yaml": {
"version": "3.9.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.9.1.tgz",
"integrity": "sha512-CbcG379L1e+mWBnLvHWWeLs8GyV/EMw862uLI3c+GxVyDHWZcjZinwuBd3iW2pgxgIlksW/1vNJa4to+RvDOww==",
"dev": true,
"requires": {
"argparse": "1.0.9",
"esprima": "4.0.0"
}
} }
} }
}, },
"eslint-config-airbnb": { "eslint-config-airbnb": {
"version": "15.0.2", "version": "15.1.0",
"resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-15.0.2.tgz", "resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-15.1.0.tgz",
"integrity": "sha512-4nI0Jp3ekTPuYKa2r8R8jq/CsDDaCwXkzV0V0BFyFSKJlQclAqJaJFXM/E6EjSFzVnK2PYNlEiIR3524Z0i2Mw==", "integrity": "sha512-m0q9fiMBzDAIbirlGnpJNWToIhdhJmXXnMG+IFflYzzod9231ZhtmGKegKg8E9T8F1YuVaDSU1FnCm5b9iXVhQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"eslint-config-airbnb-base": "11.2.0" "eslint-config-airbnb-base": "11.3.1"
} }
}, },
"eslint-config-airbnb-base": { "eslint-config-airbnb-base": {
"version": "11.2.0", "version": "11.3.1",
"resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-11.2.0.tgz", "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-11.3.1.tgz",
"integrity": "sha1-GancRIGib3CQRUXsBAEWh2AY+FM=", "integrity": "sha512-BXVH7PV5yiLjnkv49iOLJ8dWp+ljZf310ytQpqwrunFADiEbWRyN0tPGDU36FgEbdLvhJDWcJOngYDzPF4shDw==",
"dev": true "dev": true,
"requires": {
"eslint-restricted-globals": "0.1.1"
}
}, },
"eslint-formatter-pretty": { "eslint-formatter-pretty": {
"version": "1.1.0", "version": "1.1.0",
@ -5236,17 +5262,17 @@
"dev": true "dev": true
}, },
"eslint-plugin-jsx-a11y": { "eslint-plugin-jsx-a11y": {
"version": "5.0.3", "version": "5.1.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-5.0.3.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-5.1.1.tgz",
"integrity": "sha1-SpOfduwSUBBSiCMzG/lIzFczgLY=", "integrity": "sha512-5I9SpoP7gT4wBFOtXT8/tXNPYohHBVfyVfO17vkbC7r9kEIxYJF12D3pKqhk8+xnk12rfxKClS3WCFpVckFTPQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"aria-query": "0.5.0", "aria-query": "0.7.0",
"array-includes": "3.0.3", "array-includes": "3.0.3",
"ast-types-flow": "0.0.7", "ast-types-flow": "0.0.7",
"axobject-query": "0.1.0", "axobject-query": "0.1.0",
"damerau-levenshtein": "1.0.4", "damerau-levenshtein": "1.0.4",
"emoji-regex": "6.5.0", "emoji-regex": "6.5.1",
"jsx-ast-utils": "1.4.1" "jsx-ast-utils": "1.4.1"
} }
}, },
@ -5257,20 +5283,47 @@
"dev": true "dev": true
}, },
"eslint-plugin-react": { "eslint-plugin-react": {
"version": "7.1.0", "version": "7.2.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.1.0.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.2.1.tgz",
"integrity": "sha1-J3cKzzn1/UnNCvQIPOWBBOs5DUw=", "integrity": "sha512-7hN8YJO7bkxPdPfuSRz+xWKC0xk1BBp8yn8ehXaxklcMFdIoIQnhtBXc3iv042CGQH4LbKFMgDdOAjoAnnqr7Q==",
"dev": true, "dev": true,
"requires": { "requires": {
"doctrine": "2.0.0", "doctrine": "2.0.0",
"has": "1.0.1", "has": "1.0.1",
"jsx-ast-utils": "1.4.1" "jsx-ast-utils": "2.0.0"
},
"dependencies": {
"jsx-ast-utils": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.0.0.tgz",
"integrity": "sha1-7Aaj1gzzB+XhGdrHutgeifCW8Pg=",
"dev": true,
"requires": {
"array-includes": "3.0.3"
}
}
}
},
"eslint-restricted-globals": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz",
"integrity": "sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=",
"dev": true
},
"eslint-scope": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz",
"integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=",
"dev": true,
"requires": {
"esrecurse": "4.2.0",
"estraverse": "4.2.0"
} }
}, },
"espree": { "espree": {
"version": "3.4.3", "version": "3.5.0",
"resolved": "https://registry.npmjs.org/espree/-/espree-3.4.3.tgz", "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.0.tgz",
"integrity": "sha1-KRC1zNSc6JPC//+qtP2LOjG4I3Q=", "integrity": "sha1-mDWGJb3QVYYeon4oZ+pyn69GPY0=",
"dev": true, "dev": true,
"requires": { "requires": {
"acorn": "5.1.1", "acorn": "5.1.1",
@ -5397,12 +5450,6 @@
"resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.0.tgz", "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.0.tgz",
"integrity": "sha1-ODXxJ6vwdb/ggtCu1EhAV8eOPIk=" "integrity": "sha1-ODXxJ6vwdb/ggtCu1EhAV8eOPIk="
}, },
"exit-hook": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz",
"integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=",
"dev": true
},
"expand-brackets": { "expand-brackets": {
"version": "0.1.5", "version": "0.1.5",
"resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
@ -5723,13 +5770,12 @@
} }
}, },
"figures": { "figures": {
"version": "1.7.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
"integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
"dev": true, "dev": true,
"requires": { "requires": {
"escape-string-regexp": "1.0.5", "escape-string-regexp": "1.0.5"
"object-assign": "4.1.1"
} }
}, },
"file-entry-cache": { "file-entry-cache": {
@ -7141,6 +7187,12 @@
"is-callable": "1.1.3" "is-callable": "1.1.3"
} }
}, },
"functional-red-black-tree": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
"integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
"dev": true
},
"gather-stream": { "gather-stream": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/gather-stream/-/gather-stream-1.0.0.tgz", "resolved": "https://registry.npmjs.org/gather-stream/-/gather-stream-1.0.0.tgz",
@ -7172,21 +7224,6 @@
"globule": "1.2.0" "globule": "1.2.0"
} }
}, },
"generate-function": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz",
"integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=",
"dev": true
},
"generate-object-property": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
"integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=",
"dev": true,
"requires": {
"is-property": "1.0.2"
}
},
"get-caller-file": { "get-caller-file": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz",
@ -8119,37 +8156,62 @@
"dev": true "dev": true
}, },
"inquirer": { "inquirer": {
"version": "0.12.0", "version": "3.2.1",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.2.1.tgz",
"integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", "integrity": "sha512-QgW3eiPN8gpj/K5vVpHADJJgrrF0ho/dZGylikGX7iqAdRgC9FVKYKWFLx6hZDBFcOLEoSqINYrVPeFAeG/PdA==",
"dev": true, "dev": true,
"requires": { "requires": {
"ansi-escapes": "1.4.0", "ansi-escapes": "2.0.0",
"ansi-regex": "2.1.1", "chalk": "2.0.1",
"chalk": "1.1.3", "cli-cursor": "2.1.0",
"cli-cursor": "1.0.2",
"cli-width": "2.1.0", "cli-width": "2.1.0",
"figures": "1.7.0", "external-editor": "2.0.4",
"figures": "2.0.0",
"lodash": "4.17.4", "lodash": "4.17.4",
"readline2": "1.0.1", "mute-stream": "0.0.7",
"run-async": "0.1.0", "run-async": "2.3.0",
"rx-lite": "3.1.2", "rx-lite": "4.0.8",
"string-width": "1.0.2", "rx-lite-aggregates": "4.0.8",
"strip-ansi": "3.0.1", "string-width": "2.1.1",
"strip-ansi": "4.0.0",
"through": "2.3.8" "through": "2.3.8"
}, },
"dependencies": { "dependencies": {
"chalk": { "ansi-escapes": {
"version": "1.1.3", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-2.0.0.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "integrity": "sha1-W65SvkJIeN2Xg+iRDj/Cki6DyBs=",
"dev": true
},
"ansi-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
"dev": true
},
"is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
"dev": true
},
"string-width": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
"dev": true, "dev": true,
"requires": { "requires": {
"ansi-styles": "2.2.1", "is-fullwidth-code-point": "2.0.0",
"escape-string-regexp": "1.0.5", "strip-ansi": "4.0.0"
"has-ansi": "2.0.0", }
"strip-ansi": "3.0.1", },
"supports-color": "2.0.0" "strip-ansi": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
"dev": true,
"requires": {
"ansi-regex": "3.0.0"
} }
} }
} }
@ -8335,26 +8397,6 @@
"is-extglob": "1.0.0" "is-extglob": "1.0.0"
} }
}, },
"is-my-json-valid": {
"version": "2.16.0",
"resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz",
"integrity": "sha1-8Hndm/2uZe4gOKrorLyGqxCeNpM=",
"dev": true,
"requires": {
"generate-function": "2.0.0",
"generate-object-property": "1.2.0",
"jsonpointer": "4.0.1",
"xtend": "4.0.1"
},
"dependencies": {
"xtend": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
"dev": true
}
}
},
"is-npm": { "is-npm": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz",
@ -8447,12 +8489,6 @@
"integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=",
"dev": true "dev": true
}, },
"is-property": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
"integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=",
"dev": true
},
"is-redirect": { "is-redirect": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz",
@ -9492,12 +9528,6 @@
"integrity": "sha1-MwVCrT8KZUZlt3jz6y2an6UHrGQ=", "integrity": "sha1-MwVCrT8KZUZlt3jz6y2an6UHrGQ=",
"dev": true "dev": true
}, },
"jsonpointer": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz",
"integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=",
"dev": true
},
"JSONStream": { "JSONStream": {
"version": "0.8.4", "version": "0.8.4",
"resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-0.8.4.tgz", "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-0.8.4.tgz",
@ -10435,9 +10465,9 @@
} }
}, },
"mute-stream": { "mute-stream": {
"version": "0.0.5", "version": "0.0.7",
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
"integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
"dev": true "dev": true
}, },
"nan": { "nan": {
@ -10935,10 +10965,13 @@
"dev": true "dev": true
}, },
"onetime": { "onetime": {
"version": "1.1.0", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
"integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
"dev": true "dev": true,
"requires": {
"mimic-fn": "1.1.0"
}
}, },
"opener": { "opener": {
"version": "1.4.3", "version": "1.4.3",
@ -11333,9 +11366,9 @@
} }
}, },
"pluralize": { "pluralize": {
"version": "1.2.1", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-4.0.0.tgz",
"integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=", "integrity": "sha1-WbcIwcAZCi9pLxx2GMRGsFL9F2I=",
"dev": true "dev": true
}, },
"pn": { "pn": {
@ -12038,9 +12071,9 @@
"dev": true "dev": true
}, },
"progress": { "progress": {
"version": "1.1.8", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz",
"integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=",
"dev": true "dev": true
}, },
"progress-stream": { "progress-stream": {
@ -12642,26 +12675,6 @@
} }
} }
}, },
"readline2": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz",
"integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=",
"dev": true,
"requires": {
"code-point-at": "1.1.0",
"is-fullwidth-code-point": "1.0.0",
"mute-stream": "0.0.5"
}
},
"rechoir": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
"integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
"dev": true,
"requires": {
"resolve": "1.3.3"
}
},
"redbox-react": { "redbox-react": {
"version": "1.4.3", "version": "1.4.3",
"resolved": "https://registry.npmjs.org/redbox-react/-/redbox-react-1.4.3.tgz", "resolved": "https://registry.npmjs.org/redbox-react/-/redbox-react-1.4.3.tgz",
@ -13053,13 +13066,13 @@
"dev": true "dev": true
}, },
"restore-cursor": { "restore-cursor": {
"version": "1.0.1", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
"integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
"dev": true, "dev": true,
"requires": { "requires": {
"exit-hook": "1.1.1", "onetime": "2.0.1",
"onetime": "1.1.0" "signal-exit": "3.0.2"
} }
}, },
"rgb2hex": { "rgb2hex": {
@ -13097,12 +13110,12 @@
} }
}, },
"run-async": { "run-async": {
"version": "0.1.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
"integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
"dev": true, "dev": true,
"requires": { "requires": {
"once": "1.4.0" "is-promise": "2.1.0"
} }
}, },
"rx": { "rx": {
@ -13112,11 +13125,20 @@
"dev": true "dev": true
}, },
"rx-lite": { "rx-lite": {
"version": "3.1.2", "version": "4.0.8",
"resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz",
"integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=", "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=",
"dev": true "dev": true
}, },
"rx-lite-aggregates": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz",
"integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=",
"dev": true,
"requires": {
"rx-lite": "4.0.8"
}
},
"safe-buffer": { "safe-buffer": {
"version": "5.1.1", "version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
@ -13471,17 +13493,6 @@
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
"dev": true "dev": true
}, },
"shelljs": {
"version": "0.7.8",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz",
"integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=",
"dev": true,
"requires": {
"glob": "7.1.2",
"interpret": "1.0.3",
"rechoir": "0.6.2"
}
},
"shellwords": { "shellwords": {
"version": "0.1.0", "version": "0.1.0",
"resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.0.tgz", "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.0.tgz",
@ -14581,9 +14592,9 @@
} }
}, },
"table": { "table": {
"version": "3.8.3", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", "resolved": "https://registry.npmjs.org/table/-/table-4.0.1.tgz",
"integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", "integrity": "sha1-qBFsEz+sLGH0pCCrbN9cTWHw5DU=",
"dev": true, "dev": true,
"requires": { "requires": {
"ajv": "4.11.8", "ajv": "4.11.8",
@ -15293,15 +15304,6 @@
"integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=",
"dev": true "dev": true
}, },
"user-home": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz",
"integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=",
"dev": true,
"requires": {
"os-homedir": "1.0.2"
}
},
"utf8-byte-length": { "utf8-byte-length": {
"version": "1.0.4", "version": "1.0.4",
"resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz",

11
package.json

@ -139,18 +139,18 @@
"electron-devtools-installer": "^2.2.0", "electron-devtools-installer": "^2.2.0",
"enzyme": "^2.9.1", "enzyme": "^2.9.1",
"enzyme-to-json": "^1.5.1", "enzyme-to-json": "^1.5.1",
"eslint": "^3.19.0", "eslint": "^4.4.1",
"eslint-config-airbnb": "^15.0.1", "eslint-config-airbnb": "^15.1.0",
"eslint-formatter-pretty": "^1.1.0", "eslint-formatter-pretty": "^1.1.0",
"eslint-import-resolver-webpack": "^0.8.3", "eslint-import-resolver-webpack": "^0.8.3",
"eslint-plugin-compat": "^1.0.4", "eslint-plugin-compat": "^1.0.4",
"eslint-plugin-flowtype": "^2.33.0", "eslint-plugin-flowtype": "^2.33.0",
"eslint-plugin-flowtype-errors": "^3.3.0", "eslint-plugin-flowtype-errors": "^3.3.0",
"eslint-plugin-import": "^2.6.0", "eslint-plugin-import": "^2.7.0",
"eslint-plugin-jest": "^20.0.3", "eslint-plugin-jest": "^20.0.3",
"eslint-plugin-jsx-a11y": "5.0.3", "eslint-plugin-jsx-a11y": "^5.1.1",
"eslint-plugin-promise": "^3.5.0", "eslint-plugin-promise": "^3.5.0",
"eslint-plugin-react": "^7.1.0", "eslint-plugin-react": "^7.2.1",
"express": "^4.15.3", "express": "^4.15.3",
"extract-text-webpack-plugin": "^2.1.0", "extract-text-webpack-plugin": "^2.1.0",
"fbjs-scripts": "^0.8.0", "fbjs-scripts": "^0.8.0",
@ -188,6 +188,7 @@
"font-awesome": "^4.7.0", "font-awesome": "^4.7.0",
"history": "^4.6.3", "history": "^4.6.3",
"moment-timezone": "^0.5.13", "moment-timezone": "^0.5.13",
"prop-types": "^15.5.10",
"qrcode.react": "^0.7.1", "qrcode.react": "^0.7.1",
"react": "^15.6.1", "react": "^15.6.1",
"react-addons-css-transition-group": "^15.6.0", "react-addons-css-transition-group": "^15.6.0",

13
test/actions/__snapshots__/counter.spec.js.snap

@ -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",
}
`;

41
test/actions/counter.spec.js

@ -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);
});
});

68
test/components/Counter.spec.js

@ -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);
});
});

63
test/components/__snapshots__/Counter.spec.js.snap

@ -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>
`;

57
test/containers/CounterPage.spec.js

@ -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$/);
});
});
});

9
test/reducers/__snapshots__/counter.spec.js.snap

@ -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`;

22
test/reducers/counter.spec.js

@ -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();
});
});
});

10
webpack.config.base.js

@ -36,8 +36,8 @@ export default {
extensions: ['.js', '.jsx', '.json'], extensions: ['.js', '.jsx', '.json'],
modules: [ modules: [
path.join(__dirname, 'app'), path.join(__dirname, 'app'),
'node_modules', 'node_modules'
], ]
}, },
plugins: [ plugins: [
@ -45,6 +45,6 @@ export default {
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production') 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production')
}), }),
new webpack.NamedModulesPlugin(), new webpack.NamedModulesPlugin()
], ]
}; }

2
webpack.config.main.prod.js

@ -58,5 +58,5 @@ export default merge.smart(baseConfig, {
node: { node: {
__dirname: false, __dirname: false,
__filename: false __filename: false
}, }
}); });

Loading…
Cancel
Save