diff --git a/app/lnd/methods/index.js b/app/lnd/methods/index.js index a891a453..d6038aaf 100644 --- a/app/lnd/methods/index.js +++ b/app/lnd/methods/index.js @@ -49,6 +49,12 @@ export default function (lnd, event, msg, data) { ) .catch(error => console.log('channels error: ', error)) break + case 'transactions': + // Data looks like { transactions: [] } + walletController.getTransactions(lnd) + .then(transactionsData => event.sender.send('receiveTransactions', transactionsData)) + .catch(error => console.log('transactions error: ', error)) + break case 'payments': // Data looks like { payments: [] } paymentsController.listPayments(lnd) @@ -80,7 +86,12 @@ export default function (lnd, event, msg, data) { .then(newinvoice => event.sender.send( 'createdInvoice', - Object.assign(newinvoice, { memo: data.memo, value: data.value, r_hash: new Buffer(newinvoice.r_hash, 'hex').toString('hex') }) + Object.assign(newinvoice, { + memo: data.memo, + value: data.value, + r_hash: new Buffer(newinvoice.r_hash, 'hex').toString('hex'), + creation_date: Date.now() / 1000 + }) ) ) .catch(error => console.log('addInvoice error: ', error)) @@ -96,8 +107,8 @@ export default function (lnd, event, msg, data) { // Transaction looks like { txid: String } // { amount, addr } = data walletController.sendCoins(lnd, data) - .then(({ txid }) => event.sender.send('sendSuccessful', { amount: data.amount, addr: data.addr, txid })) - .catch(error => event.sender.send('sendCoinsError', { error })) + .then(({ txid }) => event.sender.send('transactionSuccessful', { amount: data.amount, addr: data.addr, txid })) + .catch(error => event.sender.send('transactionError', { error })) break case 'openChannel': // Response is empty. Streaming updates on channel status and updates diff --git a/app/reducers/activity.js b/app/reducers/activity.js new file mode 100644 index 00000000..d7c1d06b --- /dev/null +++ b/app/reducers/activity.js @@ -0,0 +1,145 @@ +import { createSelector } from 'reselect' + +// ------------------------------------ +// Initial State +// ------------------------------------ +const initialState = { + filterPulldown: false, + filter: { key: 'ALL_ACTIVITY', name: 'All Activity' }, + filters: [ + { key: 'ALL_ACTIVITY', name: 'All Activity' }, + { key: 'LN_ACTIVITY', name: 'LN Activity' }, + { key: 'PAYMENT_ACTIVITY', name: 'LN Payments' }, + { key: 'INVOICE_ACTIVITY', name: 'LN Invoices' }, + { key: 'TRANSACTION_ACTIVITY', name: 'On-chain Activity' } + ], + modal: { + modalType: null, + modalProps: {} + } +} + +// ------------------------------------ +// Constants +// ------------------------------------ +export const SHOW_ACTIVITY_MODAL = 'SHOW_ACTIVITY_MODAL' +export const HIDE_ACTIVITY_MODAL = 'HIDE_ACTIVITY_MODAL' + +export const CHANGE_FILTER = 'CHANGE_FILTER' + +export const TOGGLE_PULLDOWN = 'TOGGLE_PULLDOWN' + +// ------------------------------------ +// Actions +// ------------------------------------ +export function showActivityModal(modalType, modalProps) { + return { + type: SHOW_ACTIVITY_MODAL, + modalType, + modalProps + } +} + +export function hideActivityModal() { + return { + type: HIDE_ACTIVITY_MODAL + } +} + +export function changeFilter(filter) { + return { + type: CHANGE_FILTER, + filter + } +} + +export function toggleFilterPulldown() { + return { + type: TOGGLE_PULLDOWN + } +} + +// ------------------------------------ +// Action Handlers +// ------------------------------------ +const ACTION_HANDLERS = { + [SHOW_ACTIVITY_MODAL]: (state, { modalType, modalProps }) => ({ ...state, modal: { modalType, modalProps } }), + [HIDE_ACTIVITY_MODAL]: state => ({ ...state, modal: { modalType: null, modalProps: {} } }), + [CHANGE_FILTER]: (state, { filter }) => ({ ...state, filter, filterPulldown: false }), + [TOGGLE_PULLDOWN]: state => ({ ...state, filterPulldown: !state.filterPulldown }) +} + +// ------------------------------------ +// Selectors +// ------------------------------------ +const activitySelectors = {} +const filtersSelector = state => state.activity.filters +const filterSelector = state => state.activity.filter +const paymentsSelector = state => state.payment.payments +const invoicesSelector = state => state.invoice.invoices +const transactionsSelector = state => state.transaction.transactions + +const allActivity = createSelector( + paymentsSelector, + invoicesSelector, + transactionsSelector, + (payments, invoices, transactions) => [...payments, ...invoices, ...transactions].sort((a, b) => { + const aTimestamp = Object.prototype.hasOwnProperty.call(a, 'time_stamp') ? a.time_stamp : a.creation_date + const bTimestamp = Object.prototype.hasOwnProperty.call(b, 'time_stamp') ? b.time_stamp : b.creation_date + + return bTimestamp - aTimestamp + }) +) + +const lnActivity = createSelector( + paymentsSelector, + invoicesSelector, + (payments, invoices) => [...payments, ...invoices].sort((a, b) => b.creation_date - a.creation_date) +) + +const paymentActivity = createSelector( + paymentsSelector, + payments => payments +) + +const invoiceActivity = createSelector( + invoicesSelector, + invoices => invoices +) + +const transactionActivity = createSelector( + transactionsSelector, + transactions => transactions +) + +const FILTERS = { + ALL_ACTIVITY: allActivity, + LN_ACTIVITY: lnActivity, + PAYMENT_ACTIVITY: paymentActivity, + INVOICE_ACTIVITY: invoiceActivity, + TRANSACTION_ACTIVITY: transactionActivity +} + +activitySelectors.currentActivity = createSelector( + filterSelector, + filter => FILTERS[filter.key] +) + +activitySelectors.nonActiveFilters = createSelector( + filtersSelector, + filterSelector, + (filters, filter) => filters.filter(f => f.key !== filter.key) +) + + +export { activitySelectors } + + +// ------------------------------------ +// Reducer +// ------------------------------------ +export default function activityReducer(state = initialState, action) { + const handler = ACTION_HANDLERS[action.type] + + return handler ? handler(state, action) : state +} diff --git a/app/reducers/index.js b/app/reducers/index.js index c736b6e3..4c906733 100644 --- a/app/reducers/index.js +++ b/app/reducers/index.js @@ -11,6 +11,8 @@ import form from './form' import invoice from './invoice' import modal from './modal' import address from './address' +import transaction from './transaction' +import activity from './activity' const rootReducer = combineReducers({ router, @@ -23,7 +25,9 @@ const rootReducer = combineReducers({ form, invoice, modal, - address + address, + transaction, + activity }) export default rootReducer diff --git a/app/reducers/ipc.js b/app/reducers/ipc.js index 78988e07..c61ccd20 100644 --- a/app/reducers/ipc.js +++ b/app/reducers/ipc.js @@ -19,9 +19,10 @@ import { pushclosechannelstatus } from './channels' -import { receivePayments, paymentSuccessful, sendSuccessful, sendCoinsError } from './payment' +import { receivePayments, paymentSuccessful } from './payment' import { receiveInvoices, createdInvoice, receiveFormInvoice } from './invoice' import { receiveBalance } from './balance' +import { receiveTransactions, transactionSuccessful, transactionError } from './transaction' // Import all receiving IPC event handlers and pass them into createIpc const ipc = createIpc({ @@ -40,8 +41,6 @@ const ipc = createIpc({ receiveBalance, paymentSuccessful, - sendSuccessful, - sendCoinsError, channelSuccessful, pushchannelupdated, @@ -58,7 +57,11 @@ const ipc = createIpc({ disconnectSuccess, receiveAddress, - receiveCryptocurrency + receiveCryptocurrency, + + receiveTransactions, + transactionSuccessful, + transactionError }) export default ipc diff --git a/app/reducers/payment.js b/app/reducers/payment.js index 4bfdf453..710a4a94 100644 --- a/app/reducers/payment.js +++ b/app/reducers/payment.js @@ -1,8 +1,6 @@ import { createSelector } from 'reselect' import { ipcRenderer } from 'electron' -import { btc, usd } from '../utils' import { setForm, resetForm } from './form' -import { showModal } from './modal' // ------------------------------------ // Constants @@ -66,32 +64,19 @@ export const payInvoice = paymentRequest => (dispatch) => { ipcRenderer.send('lnd', { msg: 'sendPayment', data: { paymentRequest } }) } -export const sendCoins = ({ value, addr, currency, rate }) => (dispatch) => { - const amount = currency === 'usd' ? btc.btcToSatoshis(usd.usdToBtc(value, rate)) : btc.btcToSatoshis(value) - dispatch(sendPayment()) - ipcRenderer.send('lnd', { msg: 'sendCoins', data: { amount, addr } }) -} - // Receive IPC event for successful payment // TODO: Add payment to state, not a total re-fetch -export const paymentSuccessful = () => fetchPayments() - -export const sendSuccessful = (event, { amount, addr, txid }) => (dispatch) => { +export const paymentSuccessful = () => (dispatch) => { // Close the form modal once the payment was succesful dispatch(setForm({ modalOpen: false })) - // Show successful payment state - dispatch(showModal('SUCCESSFUL_SEND_COINS', { txid, amount, addr })) - // TODO: Add successful on-chain payment to payments list once payments list supports on-chain and LN - // dispatch({ type: PAYMENT_SUCCESSFULL, payment: { amount, addr, txid, pending: true } }) - dispatch({ type: PAYMENT_SUCCESSFULL }) + + // Refetch payments (TODO: dont do a full refetch, rather append new tx to list) + dispatch(fetchPayments()) + // Reset the payment form dispatch(resetForm()) } -export const sendCoinsError = () => (dispatch) => { - dispatch({ type: PAYMENT_FAILED }) -} - // ------------------------------------ // Action Handlers diff --git a/app/reducers/transaction.js b/app/reducers/transaction.js new file mode 100644 index 00000000..f3dc7ca5 --- /dev/null +++ b/app/reducers/transaction.js @@ -0,0 +1,92 @@ +import { ipcRenderer } from 'electron' +import { btc, usd } from '../utils' +import { setForm, resetForm } from './form' +import { showModal } from './modal' + +// ------------------------------------ +// Constants +// ------------------------------------ +export const GET_TRANSACTIONS = 'GET_TRANSACTIONS' +export const RECEIVE_TRANSACTIONS = 'RECEIVE_TRANSACTIONS' + +export const SEND_TRANSACTION = 'SEND_TRANSACTION' + +export const TRANSACTION_SUCCESSFULL = 'TRANSACTION_SUCCESSFULL' +export const TRANSACTION_FAILED = 'TRANSACTION_FAILED' + +// ------------------------------------ +// Actions +// ------------------------------------ +export function getTransactions() { + return { + type: GET_TRANSACTIONS + } +} + +export function sendTransaction() { + return { + type: SEND_TRANSACTION + } +} + +// Send IPC event for payments +export const fetchTransactions = () => (dispatch) => { + dispatch(getTransactions()) + ipcRenderer.send('lnd', { msg: 'transactions' }) +} + +// Receive IPC event for payments +export const receiveTransactions = (event, { transactions }) => dispatch => dispatch({ type: RECEIVE_TRANSACTIONS, transactions }) + +export const sendCoins = ({ value, addr, currency, rate }) => (dispatch) => { + const amount = currency === 'usd' ? btc.btcToSatoshis(usd.usdToBtc(value, rate)) : btc.btcToSatoshis(value) + dispatch(sendTransaction()) + ipcRenderer.send('lnd', { msg: 'sendCoins', data: { amount, addr } }) +} + +// Receive IPC event for successful payment +// TODO: Add payment to state, not a total re-fetch +export const transactionSuccessful = (event, { amount, addr, txid }) => (dispatch) => { + // Get the new list of transactions (TODO dont do an entire new fetch) + fetchTransactions() + // Close the form modal once the payment was succesful + dispatch(setForm({ modalOpen: false })) + // Show successful payment state + dispatch(showModal('SUCCESSFUL_SEND_COINS', { txid, amount, addr })) + // TODO: Add successful on-chain payment to payments list once payments list supports on-chain and LN + // dispatch({ type: PAYMENT_SUCCESSFULL, payment: { amount, addr, txid, pending: true } }) + dispatch({ type: TRANSACTION_SUCCESSFULL }) + // Reset the payment form + dispatch(resetForm()) +} + +export const transactionError = () => (dispatch) => { + dispatch({ type: TRANSACTION_FAILED }) +} + + +// ------------------------------------ +// Action Handlers +// ------------------------------------ +const ACTION_HANDLERS = { + [GET_TRANSACTIONS]: state => ({ ...state, transactionLoading: true }), + [SEND_TRANSACTION]: state => ({ ...state, sendingTransaction: true }), + [RECEIVE_TRANSACTIONS]: (state, { transactions }) => ({ ...state, transactionLoading: false, transactions }), + [TRANSACTION_SUCCESSFULL]: state => ({ ...state, sendingTransaction: false }), + [TRANSACTION_FAILED]: state => ({ ...state, sendingTransaction: false }) +} + +// ------------------------------------ +// Reducer +// ------------------------------------ +const initialState = { + sendingTransaction: false, + transactionLoading: false, + transactions: [] +} + +export default function transactionReducer(state = initialState, action) { + const handler = ACTION_HANDLERS[action.type] + + return handler ? handler(state, action) : state +} diff --git a/app/routes/activity/components/Activity.js b/app/routes/activity/components/Activity.js index 85692c8e..e1651291 100644 --- a/app/routes/activity/components/Activity.js +++ b/app/routes/activity/components/Activity.js @@ -1,52 +1,80 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import { MdSearch } from 'react-icons/lib/md' -import Payments from './components/Payments' -import Invoices from './components/Invoices' +import { FaAngleDown } from 'react-icons/lib/fa' + +import Invoice from './components/Invoice' +import Payment from './components/Payment' +import Transaction from './components/Transaction' + +import Modal from './components/Modal' + import styles from './Activity.scss' class Activity extends Component { constructor(props, context) { super(props, context) - this.state = { - tab: 1 - } + this.renderActivity = this.renderActivity.bind(this) } componentWillMount() { - const { fetchPayments, fetchInvoices } = this.props + const { fetchPayments, fetchInvoices, fetchTransactions } = this.props fetchPayments() fetchInvoices() + fetchTransactions() + } + + renderActivity(activity) { + const { ticker, currentTicker, showActivityModal } = this.props + + if (Object.prototype.hasOwnProperty.call(activity, 'block_hash')) { + // activity is an on-chain tx + return + } else if (Object.prototype.hasOwnProperty.call(activity, 'payment_request')) { + // activity is an LN invoice + return + } + // activity is an LN payment + return } render() { - const { tab } = this.state const { ticker, searchInvoices, - invoices, - invoice: { invoicesSearchText, invoice, invoiceLoading }, - payment: { payment, payments, paymentLoading }, - setPayment, - setInvoice, - paymentModalOpen, - invoiceModalOpen, - currentTicker + invoice: { invoicesSearchText, invoiceLoading }, + payment: { paymentLoading }, + currentTicker, + activity: { modal, filter, filterPulldown }, + hideActivityModal, + changeFilter, + toggleFilterPulldown, + currentActivity, + nonActiveFilters } = this.props if (invoiceLoading || paymentLoading) { return
Loading...
} + return (
+ +
(tab === 1 ? null : searchInvoices(event.target.value))} + value={invoicesSearchText} + onChange={event => searchInvoices(event.target.value)} className={`${styles.text} ${styles.input}`} - placeholder={tab === 1 ? 'Search transactions by amount, public key, channel' : 'Search requests by memo'} + placeholder='Search by amount, hash, memo, etc' type='text' id='invoiceSearch' /> @@ -54,41 +82,30 @@ class Activity extends Component {
- this.setState({ tab: 1 })} - > - Payments - - this.setState({ tab: 2 })} - > - Requests - +
+

+ {filter.name} +

+
    + { + nonActiveFilters.map(f => + (
  • changeFilter(f)}> + {f.name} +
  • ) + ) + } +
+
-
+
    { - tab === 1 ? - - : - + currentActivity.map((activity, index) => ( +
  • + {this.renderActivity(activity)} +
  • + )) } -
+
) @@ -98,16 +115,19 @@ class Activity extends Component { Activity.propTypes = { fetchPayments: PropTypes.func.isRequired, fetchInvoices: PropTypes.func.isRequired, + fetchTransactions: PropTypes.func.isRequired, 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, - currentTicker: PropTypes.object.isRequired + currentTicker: PropTypes.object.isRequired, + showActivityModal: PropTypes.func.isRequired, + hideActivityModal: PropTypes.func.isRequired, + changeFilter: PropTypes.func.isRequired, + toggleFilterPulldown: PropTypes.func.isRequired, + activity: PropTypes.object.isRequired, + currentActivity: PropTypes.array.isRequired, + nonActiveFilters: PropTypes.array.isRequired } export default Activity diff --git a/app/routes/activity/components/Activity.scss b/app/routes/activity/components/Activity.scss index 8846d58f..241e00c4 100644 --- a/app/routes/activity/components/Activity.scss +++ b/app/routes/activity/components/Activity.scss @@ -34,39 +34,68 @@ background: $lightgrey; .header { - width: 75%; + padding: 60px 0 20px 0; margin: 0 auto; + + section { + position: relative; + margin-left: auto; + margin-right: auto; + padding-left: 100px; + padding-right: 100px; + max-width: 964px; + } + + h2, h2 span { + cursor: pointer; + transition: color 0.25s; + + &:hover { + color: lighten($darkestgrey, 10%); + } + } - .title { - display: inline-block; - margin: 60px 0 20px 0; - padding: 5px 10px; - background: $lightgrey; - color: $darkestgrey; + h2, .filters li { text-transform: uppercase; + letter-spacing: 1.5px; + color: $darkestgrey; font-size: 14px; - font-weight: 400; - letter-spacing: 1.6px; - cursor: pointer; - transition: all 0.5s; - - &:first-child { - border-right: 1px solid $darkestgrey; - } - - - &.active { - color: $main; - font-weight: bold; - } + font-weight: 400; + } + + h2 span.pulldown { + color: $main; + } + + .filters { + display: none; + + &.active { + display: block; + position: absolute; + bottom: -100px; + z-index: 10; + + li { + margin: 5px 0; + cursor: pointer; + + &:hover { + color: $main; + } + } + } } } } .activityContainer { background: $white; - padding: 20px 0; - + transition: opacity 0.25s; + + &.pulldown { + opacity: 0.15; + } } .activityList { @@ -76,9 +105,13 @@ } .activity { - padding: 35px 10px; - border-bottom: 1px solid $grey; - font-size: 14px; + padding: 0 100px; + + &:hover { + background-color: #f0f0f0; + transition-delay: 0s; + outline: $grey solid 1px; + } .left, .center, .right { display: inline-block; diff --git a/app/routes/activity/components/components/Activity.scss b/app/routes/activity/components/components/Activity.scss new file mode 100644 index 00000000..993f309b --- /dev/null +++ b/app/routes/activity/components/components/Activity.scss @@ -0,0 +1,131 @@ +@import '../../../../variables.scss'; + +.container { + display: flex; + flex-direction: row; + cursor: pointer; + max-width: 960px; + margin: 0 auto; + height: 76px; + align-items: center; + border-bottom: 1px solid $grey; + font-size: 14px; + transition: background-color .1s linear; + transition-delay: .1s; + color: $darkestgrey; + position: relative; +} + +.clock { + display: flex; + justify-content: center; + align-items: center; + position: absolute; + top: 0; + left: -100px; + width: 100px; + height: 77px; + + svg { + font-size: 18px; + } +} + +.date { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding-right: 50px; + + time { + text-transform: uppercase; + + &:nth-child(1) { + display: flex; + align-items: center; + height: 38px; + font-size: 18px; + margin-bottom: 5px; + } + + &:nth-child(2) { + font-size: 12px; + } + } +} + +.data { + display: flex; + flex-direction: column; + flex: 6; + justify-content: space-evenly; + + .title { + margin-bottom: 5px; + } + + .icon, h3, span { + vertical-align: middle; + } + + h3, span { + font-size: 18px; + font-weight: bold; + } + + .icon { + display: inline-block; + flex: none; + position: relative; + width: 36px; + height: 36px; + border: 1px solid $darkestgrey; + border-radius: 50%; + margin-right: 15px; + + svg { + color: $main; + font-size: 16px; + vertical-align: middle; + display: flex; + top: 0; + left: 50%; + height: 100%; + margin: 0 auto; + } + } + + h3 { + display: inline-block; + + &:after { + content: " "; + display: inline-block; + width: 3px; + } + } + + span { + text-transform: uppercase; + } +} + +.amount { + display: flex; + flex-direction: column; + flex: 1; + text-align: right; + font-size: 16px; + + &.positive span:nth-child(1) { + font-weight: bold; + color: $main; + } + + span { + &:nth-child(2) { + font-size: 12px; + } + } +} diff --git a/app/routes/activity/components/components/Invoice/Invoice.js b/app/routes/activity/components/components/Invoice/Invoice.js new file mode 100644 index 00000000..bdf617bf --- /dev/null +++ b/app/routes/activity/components/components/Invoice/Invoice.js @@ -0,0 +1,74 @@ +import React from 'react' +import PropTypes from 'prop-types' +import Moment from 'react-moment' +import 'moment-timezone' +import { FaBolt, FaClockO } from 'react-icons/lib/fa' +import { btc } from '../../../../../utils' +import styles from '../Activity.scss' + +const Invoice = ({ invoice, ticker, currentTicker, showActivityModal }) => ( +
showActivityModal('INVOICE', { invoice })}> + { + !invoice.settled ? +
+ + + +
+ : + null + } +
+ + {invoice.creation_date * 1000} + + + {invoice.creation_date * 1000} + +
+
+
+ + + +

+ { invoice.settled ? 'Received' : 'Requested' } +

+ + {ticker.currency} + +
+
+ {invoice.r_hash.toString('hex')} +
+
+
+ + + + { + ticker.currency === 'usd' ? + btc.satoshisToUsd(invoice.value, currentTicker.price_usd) + : + btc.satoshisToBtc(invoice.value) + } + + + { + ticker.currency === 'usd' ? + btc.satoshisToUsd(invoice.fee, currentTicker.price_usd) + : + btc.satoshisToBtc(invoice.fee) + } + +
+
+) + +Invoice.propTypes = { + invoice: PropTypes.object.isRequired, + ticker: PropTypes.object.isRequired, + currentTicker: PropTypes.object.isRequired, + showActivityModal: PropTypes.func.isRequired +} + +export default Invoice diff --git a/app/routes/activity/components/components/Invoice/Invoice.scss b/app/routes/activity/components/components/Invoice/Invoice.scss new file mode 100644 index 00000000..e69de29b diff --git a/app/routes/activity/components/components/Invoice/index.js b/app/routes/activity/components/components/Invoice/index.js new file mode 100644 index 00000000..31b99355 --- /dev/null +++ b/app/routes/activity/components/components/Invoice/index.js @@ -0,0 +1,3 @@ +import Invoice from './Invoice' + +export default Invoice diff --git a/app/routes/activity/components/components/Invoices.js b/app/routes/activity/components/components/Invoices.js deleted file mode 100644 index 6be86f51..00000000 --- a/app/routes/activity/components/components/Invoices.js +++ /dev/null @@ -1,110 +0,0 @@ -import React from 'react' -import PropTypes from 'prop-types' -import Moment from 'react-moment' -import 'moment-timezone' -import { MdCheck } from 'react-icons/lib/md' -import QRCode from 'qrcode.react' -import Modal from './Modal' -import CurrencyIcon from '../../../../components/CurrencyIcon' -import { btc } from '../../../../utils' -import styles from './Invoices.scss' - -const Invoices = ({ - invoice, - invoices, - ticker, - setInvoice, - invoiceModalOpen, - currentTicker -}) => ( -
- - { - invoice ? -
-

{invoice.memo}

-

- - - { - ticker.currency === 'usd' ? - btc.satoshisToUsd(invoice.value, currentTicker.price_usd) - : - btc.satoshisToBtc(invoice.value) - } - -

-
- - event.target.select()} - defaultValue={invoice.payment_request} - /> -
-
- { - invoice.settled ? -

Paid

- : -

Not Paid

- } -
-

- Created on - {invoice.creation_date * 1000} -

-
- : - null - } -
-
    -
  • -
    -
    Payment Request
    -
    -
    -
    Memo
    -
    -
    -
    Amount
    -
    -
  • - { - invoices.map((invoiceItem, index) => ( -
  • setInvoice(invoiceItem)}> -
    -
    {`${invoiceItem.payment_request.substring(0, 75)}...`}
    -
    -
    -
    {invoiceItem.memo}
    -
    -
    -
    - { - ticker.currency === 'usd' ? - btc.satoshisToUsd(invoiceItem.value, currentTicker.price_usd) - : - btc.satoshisToBtc(invoiceItem.value) - } -
    -
    -
  • - )) - } -
-
-) - -Invoices.propTypes = { - invoice: PropTypes.object, - invoices: PropTypes.array.isRequired, - ticker: PropTypes.object.isRequired, - setInvoice: PropTypes.func.isRequired, - invoiceModalOpen: PropTypes.bool.isRequired, - currentTicker: PropTypes.object.isRequired -} - -export default Invoices diff --git a/app/routes/activity/components/components/Invoices.scss b/app/routes/activity/components/components/Invoices.scss deleted file mode 100644 index 0a30b26b..00000000 --- a/app/routes/activity/components/components/Invoices.scss +++ /dev/null @@ -1,125 +0,0 @@ -@import '../../../../variables.scss'; - -.invoiceModal { - padding: 40px; - - h3 { - font-size: 24px; - color: $black; - font-weight: bold; - text-align: center; - margin-bottom: 10px; - } - - h1 { - text-align: center; - color: $main; - margin: 20px 20px 60px 0; - - svg { - font-size: 30px; - vertical-align: top; - } - - span svg[data-icon='ltc'] { - width: 30px; - height: 30px; - vertical-align: top; - - g { - transform: scale(1.75) translate(-5px, -5px); - } - } - - .value { - font-size: 60px; - } - } - - .qrcode { - text-align: center; - - .paymentRequest { - text-align: center; - font-size: 0.5vw; - margin-top: 20px; - padding: 5px; - border-radius: 5px; - background: $lightgrey; - border: 1px solid $darkgrey; - display: block; - width: 100%; - } - } - - .settled { - text-align: center; - color: $main; - text-transform: uppercase; - font-size: 20px; - margin: 30px 0; - font-weight: bold; - - svg { - line-height: 20px; - } - } - - .date { - text-align: center; - - time { - margin-left: 3px; - } - } -} - -.invoices { - width: 75%; - margin: 0 auto; - background: $white; -} - -.invoice, .invoiceTitles { - display: flex; - flex-direction: 'row'; - padding: 35px 10px; - border-bottom: 1px solid $grey; - font-size: 14px; - - .left { - flex: 7; - } - - .center { - flex: 2; - } - - .right { - flex: 1; - } - - .settled { - color: $main; - font-weight: bold; - } -} - -.invoiceTitles { - border: none; - - .left, .center, .right { - color: $black; - text-transform: uppercase; - font-size: 16px; - font-weight: bold; - } -} - -.invoice { - cursor: pointer; - - &:hover { - background: #f0f0f0; - } -} diff --git a/app/routes/activity/components/components/Modal.js b/app/routes/activity/components/components/Modal.js deleted file mode 100644 index 145ed1bf..00000000 --- a/app/routes/activity/components/components/Modal.js +++ /dev/null @@ -1,41 +0,0 @@ -import React from 'react' -import PropTypes from 'prop-types' -import ReactModal from 'react-modal' - -const Modal = ({ isOpen, resetObject, children }) => { - const customStyles = { - overlay: { - cursor: 'pointer' - }, - content: { - top: 'auto', - left: '20%', - right: '0', - bottom: 'auto', - width: '40%', - margin: '50px auto' - } - } - - return ( - resetObject(null)} - parentSelector={() => document.body} - style={customStyles} - > - {children} - - ) -} - -Modal.propTypes = { - isOpen: PropTypes.bool.isRequired, - resetObject: PropTypes.func.isRequired, - children: PropTypes.object -} - -export default Modal diff --git a/app/routes/activity/components/components/Modal/Invoice/Invoice.js b/app/routes/activity/components/components/Modal/Invoice/Invoice.js new file mode 100644 index 00000000..7e605377 --- /dev/null +++ b/app/routes/activity/components/components/Modal/Invoice/Invoice.js @@ -0,0 +1,61 @@ +import React from 'react' +import PropTypes from 'prop-types' + +import Moment from 'react-moment' +import 'moment-timezone' + +import QRCode from 'qrcode.react' + +import { MdCheck } from 'react-icons/lib/md' + +import CurrencyIcon from '../../../../../../components/CurrencyIcon' +import { btc } from '../../../../../../utils' + +import styles from './Invoice.scss' + + +const Invoice = ({ invoice, ticker, currentTicker }) => ( +
+

{invoice.memo}

+

+ + + { + ticker.currency === 'usd' ? + btc.satoshisToUsd(invoice.value, currentTicker.price_usd) + : + btc.satoshisToBtc(invoice.value) + } + +

+
+ + event.target.select()} + defaultValue={invoice.payment_request} + /> +
+
+ { + invoice.settled ? +

Paid

+ : +

Not Paid

+ } +
+

+ Created on + {invoice.creation_date * 1000} +

+
+) + +Invoice.propTypes = { + invoice: PropTypes.object.isRequired, + ticker: PropTypes.object.isRequired, + currentTicker: PropTypes.object.isRequired +} + +export default Invoice diff --git a/app/routes/activity/components/components/Modal/Invoice/Invoice.scss b/app/routes/activity/components/components/Modal/Invoice/Invoice.scss new file mode 100644 index 00000000..6a55e812 --- /dev/null +++ b/app/routes/activity/components/components/Modal/Invoice/Invoice.scss @@ -0,0 +1,75 @@ +@import '../../../../../../variables.scss'; + +.container { + padding: 40px; + + h3 { + font-size: 24px; + color: $black; + font-weight: bold; + text-align: center; + margin-bottom: 10px; + } + + h1 { + text-align: center; + color: $main; + margin: 20px 20px 60px 0; + + svg { + font-size: 30px; + vertical-align: top; + } + + span svg[data-icon='ltc'] { + width: 30px; + height: 30px; + vertical-align: top; + + g { + transform: scale(1.75) translate(-5px, -5px); + } + } + + .value { + font-size: 60px; + } + } + + .qrcode { + text-align: center; + + .paymentRequest { + text-align: center; + font-size: 0.5vw; + margin-top: 20px; + padding: 5px; + border-radius: 5px; + background: $lightgrey; + border: 1px solid $darkgrey; + display: block; + width: 100%; + } + } + + .settled { + text-align: center; + color: $main; + text-transform: uppercase; + font-size: 20px; + margin: 30px 0; + font-weight: bold; + + svg { + line-height: 20px; + } + } + + .date { + text-align: center; + + time { + margin-left: 3px; + } + } +} \ No newline at end of file diff --git a/app/routes/activity/components/components/Modal/Invoice/index.js b/app/routes/activity/components/components/Modal/Invoice/index.js new file mode 100644 index 00000000..31b99355 --- /dev/null +++ b/app/routes/activity/components/components/Modal/Invoice/index.js @@ -0,0 +1,3 @@ +import Invoice from './Invoice' + +export default Invoice diff --git a/app/routes/activity/components/components/Modal/Modal.js b/app/routes/activity/components/components/Modal/Modal.js new file mode 100644 index 00000000..58722e21 --- /dev/null +++ b/app/routes/activity/components/components/Modal/Modal.js @@ -0,0 +1,57 @@ +import React from 'react' +import PropTypes from 'prop-types' +import ReactModal from 'react-modal' + +import Transaction from './Transaction' +import Payment from './Payment' +import Invoice from './Invoice' + +const Modal = ({ modalType, modalProps, hideActivityModal, ticker, currentTicker }) => { + const MODAL_COMPONENTS = { + TRANSACTION: Transaction, + PAYMENT: Payment, + INVOICE: Invoice + + } + const customStyles = { + overlay: { + cursor: 'pointer' + }, + content: { + top: 'auto', + left: '20%', + right: '0', + bottom: 'auto', + width: '40%', + margin: '50px auto' + } + } + + if (!modalType) { return null } + + const SpecificModal = MODAL_COMPONENTS[modalType] + + return ( + hideActivityModal()} + parentSelector={() => document.body} + style={customStyles} + > + + + ) +} + +Modal.propTypes = { + modalType: PropTypes.string, + modalProps: PropTypes.object.isRequired, + hideActivityModal: PropTypes.func.isRequired, + ticker: PropTypes.object.isRequired, + currentTicker: PropTypes.object.isRequired +} + +export default Modal diff --git a/app/routes/activity/components/components/Modal/Payment/Payment.js b/app/routes/activity/components/components/Modal/Payment/Payment.js new file mode 100644 index 00000000..fec8218d --- /dev/null +++ b/app/routes/activity/components/components/Modal/Payment/Payment.js @@ -0,0 +1,44 @@ +import React from 'react' +import PropTypes from 'prop-types' + +import Moment from 'react-moment' +import 'moment-timezone' + +import CurrencyIcon from '../../../../../../components/CurrencyIcon' +import { btc } from '../../../../../../utils' + +import styles from './Payment.scss' + + +const Payment = ({ payment, ticker, currentTicker }) => ( +
+

{payment.payment_hash}

+

+ + + { + ticker.currency === 'usd' ? + btc.satoshisToUsd(payment.value, currentTicker.price_usd) + : + btc.satoshisToBtc(payment.value) + } + +

+
+
Fee
+
{payment.fee}
+
Date
+
+ {payment.creation_date * 1000} +
+
+
+) + +Payment.propTypes = { + payment: PropTypes.object.isRequired, + ticker: PropTypes.object.isRequired, + currentTicker: PropTypes.object.isRequired +} + +export default Payment diff --git a/app/routes/activity/components/components/Modal/Payment/Payment.scss b/app/routes/activity/components/components/Modal/Payment/Payment.scss new file mode 100644 index 00000000..304fce58 --- /dev/null +++ b/app/routes/activity/components/components/Modal/Payment/Payment.scss @@ -0,0 +1,55 @@ +@import '../../../../../../variables.scss'; + +.container { + padding: 40px; + + h1 { + text-align: center; + color: $main; + margin: 60px 30px 60px 0; + + svg { + font-size: 30px; + vertical-align: top; + } + + span svg[data-icon='ltc'] { + width: 30px; + height: 30px; + vertical-align: top; + + g { + transform: scale(1.75) translate(-5px, -5px); + } + } + + .value { + font-size: 80px; + } + } + + h3 { + font-size: 14px; + text-align: center; + color: $black; + font-weight: bold; + } + + dt { + text-align: left; + float: left; + clear: left; + font-weight: 500; + padding: 20px 35px 19px 0; + color: $black; + font-weight: bold; + } + + dd { + text-align: right; + font-weight: 400; + padding: 19px 0; + margin-left: 0; + border-top: 1px solid $darkgrey; + } +} \ No newline at end of file diff --git a/app/routes/activity/components/components/Modal/Payment/index.js b/app/routes/activity/components/components/Modal/Payment/index.js new file mode 100644 index 00000000..3f7e6951 --- /dev/null +++ b/app/routes/activity/components/components/Modal/Payment/index.js @@ -0,0 +1,3 @@ +import Payment from './Payment' + +export default Payment diff --git a/app/routes/activity/components/components/Modal/Transaction/Transaction.js b/app/routes/activity/components/components/Modal/Transaction/Transaction.js new file mode 100644 index 00000000..9b38dc96 --- /dev/null +++ b/app/routes/activity/components/components/Modal/Transaction/Transaction.js @@ -0,0 +1,54 @@ +import React from 'react' +import PropTypes from 'prop-types' + +import Moment from 'react-moment' +import 'moment-timezone' + +import CurrencyIcon from '../../../../../../components/CurrencyIcon' +import { btc } from '../../../../../../utils' + +import styles from './Transaction.scss' + + +const Transaction = ({ transaction, ticker, currentTicker }) => ( +
+

+ { + transaction.amount < 0 ? + 'Sent' + : + 'Received' + } +

+

{transaction.tx_hash}

+

+ + + { + ticker.currency === 'usd' ? + btc.satoshisToUsd(transaction.amount, currentTicker.price_usd) + : + btc.satoshisToBtc(transaction.amount) + } + +

+
+
Confirmations
+
{transaction.num_confirmations}
+
Fee
+
{transaction.total_fees}
+
Date
+
+ {transaction.time_stamp * 1000} +
+
+
+) + +Transaction.propTypes = { + transaction: PropTypes.object.isRequired, + ticker: PropTypes.object.isRequired, + currentTicker: PropTypes.object.isRequired +} + +export default Transaction diff --git a/app/routes/activity/components/components/Modal/Transaction/Transaction.scss b/app/routes/activity/components/components/Modal/Transaction/Transaction.scss new file mode 100644 index 00000000..283de75b --- /dev/null +++ b/app/routes/activity/components/components/Modal/Transaction/Transaction.scss @@ -0,0 +1,63 @@ +@import '../../../../../../variables.scss'; + +.container { + padding: 40px; + + h1 { + text-align: center; + color: $main; + margin: 60px 30px 60px 0; + + svg { + font-size: 30px; + vertical-align: top; + } + + span svg[data-icon='ltc'] { + width: 30px; + height: 30px; + vertical-align: top; + + g { + transform: scale(1.75) translate(-5px, -5px); + } + } + + .value { + font-size: 75px; + } + } + + h3 { + font-size: 14px; + text-align: center; + color: $black; + font-weight: bold; + } + + h2 { + text-align: center; + margin-bottom: 30px; + text-transform: uppercase; + letter-spacing: 1.5px; + font-size: 24px; + } + + dt { + text-align: left; + float: left; + clear: left; + font-weight: 500; + padding: 20px 35px 19px 0; + color: $black; + font-weight: bold; + } + + dd { + text-align: right; + font-weight: 400; + padding: 19px 0; + margin-left: 0; + border-top: 1px solid $darkgrey; + } +} \ No newline at end of file diff --git a/app/routes/activity/components/components/Modal/Transaction/index.js b/app/routes/activity/components/components/Modal/Transaction/index.js new file mode 100644 index 00000000..7fc5e311 --- /dev/null +++ b/app/routes/activity/components/components/Modal/Transaction/index.js @@ -0,0 +1,3 @@ +import Transaction from './Transaction' + +export default Transaction diff --git a/app/routes/activity/components/components/Modal/index.js b/app/routes/activity/components/components/Modal/index.js new file mode 100644 index 00000000..498702f4 --- /dev/null +++ b/app/routes/activity/components/components/Modal/index.js @@ -0,0 +1,3 @@ +import Modal from './Modal' + +export default Modal diff --git a/app/routes/activity/components/components/Payment/Payment.js b/app/routes/activity/components/components/Payment/Payment.js new file mode 100644 index 00000000..4b855678 --- /dev/null +++ b/app/routes/activity/components/components/Payment/Payment.js @@ -0,0 +1,64 @@ +import React from 'react' +import PropTypes from 'prop-types' +import Moment from 'react-moment' +import 'moment-timezone' +import { FaBolt } from 'react-icons/lib/fa' +import { btc } from '../../../../../utils' +import styles from '../Activity.scss' + +const Payment = ({ payment, ticker, currentTicker, showActivityModal }) => ( +
showActivityModal('PAYMENT', { payment })}> +
+ + {payment.creation_date * 1000} + + + {payment.creation_date * 1000} + +
+
+
+ + + +

+ Sent +

+ + {ticker.currency} + +
+
+ {payment.payment_hash.toString('hex')} +
+
+
+ + - + { + ticker.currency === 'usd' ? + btc.satoshisToUsd(payment.value, currentTicker.price_usd) + : + btc.satoshisToBtc(payment.value) + } + + + { + ticker.currency === 'usd' ? + btc.satoshisToUsd(payment.fee, currentTicker.price_usd) + : + btc.satoshisToBtc(payment.fee) + } + +
+
+) + +Payment.propTypes = { + payment: PropTypes.object.isRequired, + ticker: PropTypes.object.isRequired, + currentTicker: PropTypes.object.isRequired, + showActivityModal: PropTypes.func.isRequired +} + +export default Payment diff --git a/app/routes/activity/components/components/Payment/Payment.scss b/app/routes/activity/components/components/Payment/Payment.scss new file mode 100644 index 00000000..e69de29b diff --git a/app/routes/activity/components/components/Payment/index.js b/app/routes/activity/components/components/Payment/index.js new file mode 100644 index 00000000..3f7e6951 --- /dev/null +++ b/app/routes/activity/components/components/Payment/index.js @@ -0,0 +1,3 @@ +import Payment from './Payment' + +export default Payment diff --git a/app/routes/activity/components/components/Payments.js b/app/routes/activity/components/components/Payments.js deleted file mode 100644 index b65875e4..00000000 --- a/app/routes/activity/components/components/Payments.js +++ /dev/null @@ -1,112 +0,0 @@ -import React from 'react' -import PropTypes from 'prop-types' -import Moment from 'react-moment' -import 'moment-timezone' -import Modal from './Modal' -import CurrencyIcon from '../../../../components/CurrencyIcon' -import { btc } from '../../../../utils' -import styles from './Payments.scss' - -const Payments = ({ - payment, - payments, - ticker, - setPayment, - paymentModalOpen, - currentTicker -}) => ( -
- - { - payment ? -
-

{payment.payment_hash}

-

- - - { - ticker.currency === 'usd' ? - btc.satoshisToUsd(payment.value, currentTicker.price_usd) - : - btc.satoshisToBtc(payment.value) - } - -

-
-
Fee
-
{payment.fee}
-
Date
-
- {payment.creation_date * 1000} -
-
-
- : - null - } -
-
    -
  • -
    -
    Public Key
    -
    -
    -
    Date
    -
    -
    -
    Fee
    -
    -
    -
    Amount
    -
    -
  • - { - payments.map((paymentItem, index) => - ( -
  • setPayment(paymentItem)}> -
    -
    {paymentItem.path[0]}
    -
    -
    -
    - {paymentItem.creation_date * 1000} -
    -
    -
    - - { - ticker.currency === 'usd' ? - btc.satoshisToUsd(paymentItem.fee, currentTicker.price_usd) - : - btc.satoshisToBtc(paymentItem.fee) - } - -
    -
    - - { - ticker.currency === 'usd' ? - btc.satoshisToUsd(paymentItem.value, currentTicker.price_usd) - : - btc.satoshisToBtc(paymentItem.value) - } - -
    -
  • - ) - ) - } -
-
-) - -Payments.propTypes = { - payment: PropTypes.object, - payments: PropTypes.array.isRequired, - ticker: PropTypes.object.isRequired, - setPayment: PropTypes.func.isRequired, - paymentModalOpen: PropTypes.bool.isRequired, - currentTicker: PropTypes.object.isRequired -} - -export default Payments diff --git a/app/routes/activity/components/components/Payments.scss b/app/routes/activity/components/components/Payments.scss deleted file mode 100644 index c7a697cb..00000000 --- a/app/routes/activity/components/components/Payments.scss +++ /dev/null @@ -1,102 +0,0 @@ -@import '../../../../variables.scss'; - -.paymentModal { - padding: 40px; - - h1 { - text-align: center; - color: $main; - margin: 60px 30px 60px 0; - - svg { - font-size: 30px; - vertical-align: top; - } - - span svg[data-icon='ltc'] { - width: 30px; - height: 30px; - vertical-align: top; - - g { - transform: scale(1.75) translate(-5px, -5px); - } - } - - .value { - font-size: 80px; - } - } - - h3 { - font-size: 14px; - text-align: center; - color: $black; - font-weight: bold; - } - - dt { - text-align: left; - float: left; - clear: left; - font-weight: 500; - padding: 20px 35px 19px 0; - color: $black; - font-weight: bold; - } - - dd { - text-align: right; - font-weight: 400; - padding: 19px 0; - margin-left: 0; - border-top: 1px solid $darkgrey; - } -} - -.payments { - width: 75%; - margin: 0 auto; - background: $white; -} - -.payment, .paymentTitles { - display: flex; - flex-direction: 'row'; - padding: 35px 10px; - border-bottom: 1px solid $grey; - font-size: 14px; - - .left, .center, .right { - display: inline-block; - vertical-align: top; - } - - .center, .right { - flex: 1; - } - - .left { - flex: 7; - } -} - -.paymentTitles { - border: none; - - .left, .center, .right { - color: $black; - text-transform: uppercase; - font-size: 16px; - font-weight: bold; - } -} - - -.payment { - cursor: pointer; - - &:hover { - background: #f0f0f0; - } -} diff --git a/app/routes/activity/components/components/Transaction/Transaction.js b/app/routes/activity/components/components/Transaction/Transaction.js new file mode 100644 index 00000000..eba080f5 --- /dev/null +++ b/app/routes/activity/components/components/Transaction/Transaction.js @@ -0,0 +1,64 @@ +import React from 'react' +import PropTypes from 'prop-types' +import Moment from 'react-moment' +import 'moment-timezone' +import { FaChain } from 'react-icons/lib/fa' +import { btc } from '../../../../../utils' +import styles from '../Activity.scss' + +const Transaction = ({ transaction, ticker, currentTicker, showActivityModal }) => ( +
showActivityModal('TRANSACTION', { transaction })}> +
+ + {transaction.time_stamp * 1000} + + + {transaction.time_stamp * 1000} + +
+
+
+ + + +

+ { transaction.amount > 0 ? 'Received' : 'Sent' } +

+ + {ticker.currency} + +
+
+ {transaction.tx_hash} +
+
+
0 ? styles.positive : styles.negative}`}> + + { transaction.amount > 0 ? '+' : '' } + { + ticker.currency === 'usd' ? + btc.satoshisToUsd(transaction.amount, currentTicker.price_usd) + : + btc.satoshisToBtc(transaction.amount) + } + + + { + ticker.currency === 'usd' ? + btc.satoshisToUsd(transaction.total_fees, currentTicker.price_usd) + : + btc.satoshisToBtc(transaction.total_fees) + } + +
+
+) + +Transaction.propTypes = { + transaction: PropTypes.object.isRequired, + ticker: PropTypes.object.isRequired, + currentTicker: PropTypes.object.isRequired, + showActivityModal: PropTypes.func.isRequired +} + +export default Transaction diff --git a/app/routes/activity/components/components/Transaction/Transaction.scss b/app/routes/activity/components/components/Transaction/Transaction.scss new file mode 100644 index 00000000..5bf06196 --- /dev/null +++ b/app/routes/activity/components/components/Transaction/Transaction.scss @@ -0,0 +1,111 @@ +@import '../../../../../variables.scss'; + +.container { + display: flex; + flex-direction: row; + cursor: pointer; + max-width: 960px; + margin: 0 auto; + height: 76px; + align-items: center; + border-bottom: 1px solid $grey; + font-size: 14px; + transition: background-color .1s linear; + transition-delay: .1s; + color: $darkestgrey; + position: relative; +} + +.icon { + display: block; + margin-right: 20px; + flex: none; + position: relative; + width: 36px; + height: 36px; + border: 1px solid $darkestgrey; + border-radius: 50%; + + svg { + color: $main; + font-size: 16px; + vertical-align: middle; + display: flex; + top: 0; + left: 50%; + height: 100%; + margin: 0 auto; + } +} + +.data { + display: flex; + flex-direction: row; + flex: 6 0; + + .title { + flex: 8 0; + } + + .subtitle { + padding-left: 20px; + flex: 2 0; + } +} + +.subtitle, .date { + text-align: center; +} + +.date { + padding-left: 20px; + flex: 1 0; +} + +.amount { + flex: 1 0; + padding-left: 20px; + + &.negative { + font-weight: 200; + } + + &.positive { + color: $main; + font-weight: 500; + } + + section { + display: inline-block; + vertical-align: top; + text-align: right; + font-size: 0; + margin: 0; + padding: 0; + + &:nth-child(1) { + width: 20%; + } + + &:nth-child(2) { + width: 80%; + } + } + + svg { + font-size: 20px; + } + + span { + display: block; + + &:nth-child(1) { + font-size: 14px; + } + + &:nth-child(2) { + font-size: 10px; + } + } +} + diff --git a/app/routes/activity/components/components/Transaction/index.js b/app/routes/activity/components/components/Transaction/index.js new file mode 100644 index 00000000..7fc5e311 --- /dev/null +++ b/app/routes/activity/components/components/Transaction/index.js @@ -0,0 +1,3 @@ +import Transaction from './Transaction' + +export default Transaction diff --git a/app/routes/activity/containers/ActivityContainer.js b/app/routes/activity/containers/ActivityContainer.js index 1b3cba45..219ad1a0 100644 --- a/app/routes/activity/containers/ActivityContainer.js +++ b/app/routes/activity/containers/ActivityContainer.js @@ -11,6 +11,14 @@ import { fetchPayments, paymentSelectors } from '../../../reducers/payment' +import { fetchTransactions } from '../../../reducers/transaction' +import { + showActivityModal, + hideActivityModal, + changeFilter, + toggleFilterPulldown, + activitySelectors +} from '../../../reducers/activity' import Activity from '../components/Activity' const mapDispatchToProps = { @@ -18,7 +26,12 @@ const mapDispatchToProps = { setInvoice, fetchPayments, fetchInvoices, - searchInvoices + fetchTransactions, + searchInvoices, + showActivityModal, + hideActivityModal, + changeFilter, + toggleFilterPulldown } const mapStateToProps = state => ({ @@ -34,7 +47,10 @@ const mapStateToProps = state => ({ paymentModalOpen: paymentSelectors.paymentModalOpen(state), invoiceModalOpen: invoiceSelectors.invoiceModalOpen(state), - currentTicker: tickerSelectors.currentTicker(state) + currentTicker: tickerSelectors.currentTicker(state), + + currentActivity: activitySelectors.currentActivity(state)(state), + nonActiveFilters: activitySelectors.nonActiveFilters(state) }) export default connect(mapStateToProps, mapDispatchToProps)(Activity) diff --git a/app/routes/app/components/App.js b/app/routes/app/components/App.js index 421be3fc..a46f155a 100644 --- a/app/routes/app/components/App.js +++ b/app/routes/app/components/App.js @@ -27,7 +27,7 @@ class App extends Component { setMessage, setPubkey, setPaymentRequest, - payment, + transaction: { sendingTransaction }, peers, setCurrency, setForm, @@ -60,10 +60,10 @@ class App extends Component { setMessage={setMessage} setPubkey={setPubkey} setPaymentRequest={setPaymentRequest} - payment={payment} peers={peers} ticker={ticker} form={form} + sendingTransaction={sendingTransaction} createInvoice={createInvoice} payInvoice={payInvoice} sendCoins={sendCoins} @@ -102,7 +102,7 @@ App.propTypes = { setMessage: PropTypes.func.isRequired, setPubkey: PropTypes.func.isRequired, setPaymentRequest: PropTypes.func.isRequired, - payment: PropTypes.object.isRequired, + transaction: PropTypes.object.isRequired, peers: PropTypes.array, setCurrency: PropTypes.func.isRequired, setForm: PropTypes.func.isRequired, diff --git a/app/routes/app/components/components/Form/Form.js b/app/routes/app/components/components/Form/Form.js index a57dafe9..0126daeb 100644 --- a/app/routes/app/components/components/Form/Form.js +++ b/app/routes/app/components/components/Form/Form.js @@ -7,7 +7,6 @@ import styles from './Form.scss' const Form = ({ form: { formType, amount, onchainAmount, message, payment_request }, - payment: { sendingPayment }, setAmount, setOnchainAmount, setMessage, @@ -22,7 +21,8 @@ const Form = ({ formInvoice, currentTicker, isOnchain, - isLn + isLn, + sendingTransaction }) => (
@@ -33,7 +33,7 @@ const Form = ({ { formType === 'pay' ? { - sendingPayment ? + sendingTransaction ? : null @@ -127,8 +127,11 @@ class Pay extends Component { } Pay.propTypes = { - sendingPayment: PropTypes.bool.isRequired, - invoiceAmount: PropTypes.string.isRequired, + sendingTransaction: PropTypes.bool.isRequired, + invoiceAmount: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number + ]).isRequired, onchainAmount: PropTypes.string.isRequired, setOnchainAmount: PropTypes.func.isRequired, payment_request: PropTypes.string.isRequired, diff --git a/app/routes/app/containers/AppContainer.js b/app/routes/app/containers/AppContainer.js index 3f2e8153..27961910 100644 --- a/app/routes/app/containers/AppContainer.js +++ b/app/routes/app/containers/AppContainer.js @@ -5,7 +5,8 @@ import { fetchBalance } from '../../../reducers/balance' import { fetchInfo } from '../../../reducers/info' import { createInvoice, fetchInvoice } from '../../../reducers/invoice' import { hideModal } from '../../../reducers/modal' -import { payInvoice, sendCoins } from '../../../reducers/payment' +import { payInvoice } from '../../../reducers/payment' +import { sendCoins } from '../../../reducers/transaction' import { fetchChannels } from '../../../reducers/channels' import { setForm, @@ -42,6 +43,7 @@ const mapStateToProps = state => ({ ticker: state.ticker, balance: state.balance, payment: state.payment, + transaction: state.transaction, form: state.form, invoice: state.invoice, modal: state.modal, diff --git a/app/tooltip.scss b/app/tooltip.scss index 65eb544c..6ca18e7a 100644 --- a/app/tooltip.scss +++ b/app/tooltip.scss @@ -130,4 +130,4 @@ .hint--left:hover:before { -webkit-transform: translateX(-8px); transform: translateX(-8px); -} \ No newline at end of file +} diff --git a/package.json b/package.json index 88ee631d..fb7da571 100644 --- a/package.json +++ b/package.json @@ -185,7 +185,7 @@ }, "dependencies": { "axios": "^0.16.2", - "bitcoinjs-lib": "^3.1.1", + "bitcoinjs-lib": "^3.2.0", "bitcore-lib": "^0.14.0", "devtron": "^1.4.0", "electron-debug": "^1.2.0", diff --git a/yarn.lock b/yarn.lock index da74513f..0a74c2aa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1472,6 +1472,10 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" +bech32@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/bech32/-/bech32-0.0.3.tgz#736747c4a6531c5d8937d0400498de30e93b2f9c" + beeper@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/beeper/-/beeper-1.1.1.tgz#e6d5ea8c5dad001304a70b22638447f69cb2f809" @@ -1505,10 +1509,11 @@ bitcoin-ops@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/bitcoin-ops/-/bitcoin-ops-1.3.0.tgz#6b126b585537bc679b02ed499f14450cffc37e13" -bitcoinjs-lib@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/bitcoinjs-lib/-/bitcoinjs-lib-3.1.1.tgz#c2b1efe455992be88f6be70b5f6fe1a93b9abd90" +bitcoinjs-lib@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/bitcoinjs-lib/-/bitcoinjs-lib-3.2.0.tgz#23d435523b26b15ce58d539172c1c2cbc83141a1" dependencies: + bech32 "0.0.3" bigi "^1.4.0" bip66 "^1.1.0" bitcoin-ops "^1.3.0" @@ -1520,7 +1525,7 @@ bitcoinjs-lib@^3.1.1: pushdata-bitcoin "^1.0.1" randombytes "^2.0.1" safe-buffer "^5.0.1" - typeforce "^1.8.7" + typeforce "^1.11.3" varuint-bitcoin "^1.0.4" wif "^2.0.1" @@ -8705,7 +8710,7 @@ typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -typeforce@^1.8.7: +typeforce@^1.11.3: version "1.11.4" resolved "https://registry.yarnpkg.com/typeforce/-/typeforce-1.11.4.tgz#07ce3abcce836761243ae483dce5bc609786205c" dependencies: