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
- }
-
-
- -
-
-
-
-
- {
- invoices.map((invoiceItem, index) => (
- - setInvoice(invoiceItem)}>
-
-
{`${invoiceItem.payment_request.substring(0, 75)}...`}
-
-
-
-
- {
- 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
- }
-
-
- -
-
-
-
-
-
- {
- 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: