diff --git a/app/components/Form/Pay.js b/app/components/Form/Pay.js
index ced4d19d..57f4bc94 100644
--- a/app/components/Form/Pay.js
+++ b/app/components/Form/Pay.js
@@ -5,8 +5,9 @@ import find from 'lodash/find'
import Isvg from 'react-inlinesvg'
import paperPlane from 'icons/paper_plane.svg'
import link from 'icons/link.svg'
-
import { FaAngleDown } from 'react-icons/lib/fa'
+
+import { btc } from 'utils'
import LoadingBolt from 'components/LoadingBolt'
import CurrencyIcon from 'components/CurrencyIcon'
@@ -29,10 +30,11 @@ class Pay extends Component {
render() {
const {
- payform: { amount, payInput, showErrors, invoice },
+ payform: { amount, payInput, showErrors, invoice, showCurrencyFilters },
currency,
crypto,
nodes,
+ ticker,
isOnchain,
isLn,
@@ -41,6 +43,9 @@ class Pay extends Component {
inputCaption,
showPayLoadingScreen,
payFormIsValid: { errors, isValid },
+ payInputMin,
+ currentCurrencyFilters,
+ currencyName,
setPayAmount,
onPayAmountBlur,
@@ -48,20 +53,31 @@ class Pay extends Component {
setPayInput,
onPayInputBlur,
- onPaySubmit
+ setCurrencyFilters,
+
+ onPaySubmit,
+
+ setCurrency
} = this.props
const displayNodeName = (pubkey) => {
- console.log('nodes: ', nodes)
- console.log('pubkey: ', pubkey)
const node = find(nodes, n => n.pub_key === pubkey)
- console.log('node: ', node)
if (node && node.alias.length) { return node.alias }
return pubkey.substring(0, 10)
}
+ const onCurrencyFilterClick = (currency) => {
+ if (!isLn) {
+ // change the input amount
+ setPayAmount(btc.convert(ticker.currency, currency, currentAmount))
+ }
+
+ setCurrency(currency)
+ setCurrencyFilters(false)
+ }
+
return (
{showPayLoadingScreen &&
}
@@ -122,18 +138,21 @@ class Pay extends Component {
readOnly={isLn}
/>
-
- BTC
+ setCurrencyFilters(!showCurrencyFilters)}>
+ {currencyName}
-
- - Bits
- - Satoshis
+
+ {
+ currentCurrencyFilters.map(filter =>
+ - onCurrencyFilterClick(filter.key)}>{filter.name}
+ )
+ }
- {`≈ ${usdAmount} USD`}
+ {`≈ ${usdAmount || 0} USD`}
@@ -149,7 +168,10 @@ class Pay extends Component {
Pay.propTypes = {
payform: PropTypes.shape({
- amount: PropTypes.string.isRequired,
+ amount: PropTypes.oneOfType([
+ PropTypes.string,
+ PropTypes.number
+ ]).isRequired,
payInput: PropTypes.string.isRequired,
showErrors: PropTypes.object.isRequired
}).isRequired,
diff --git a/app/components/Form/Pay.scss b/app/components/Form/Pay.scss
index 52997373..55a8b954 100644
--- a/app/components/Form/Pay.scss
+++ b/app/components/Form/Pay.scss
@@ -89,6 +89,7 @@
}
.currency {
+ position: relative;
display: flex;
flex-direction: row;
align-items: center;
@@ -114,6 +115,23 @@
ul {
visibility: hidden;
position: absolute;
+ top: 30px;
+
+ &.active {
+ visibility: visible;
+ }
+
+ li {
+ padding: 8px 15px;
+ background: #191919;
+ cursor: pointer;
+ transition: 0.25s hover;
+ border-bottom: 1px solid #0f0f0f;
+
+ &:hover {
+ background: #0f0f0f;
+ }
+ }
}
}
diff --git a/app/reducers/payform.js b/app/reducers/payform.js
index da66ecc4..4fc2221e 100644
--- a/app/reducers/payform.js
+++ b/app/reducers/payform.js
@@ -9,7 +9,7 @@ import { btc, bech32 } from '../utils'
// Initial State
const initialState = {
- amount: '0',
+ amount: '',
payInput: '',
invoice: {
@@ -20,6 +20,8 @@ const initialState = {
destination: ''
},
+ showCurrencyFilters: false,
+
showErrors: {
amount: false,
payInput: false
@@ -32,6 +34,8 @@ export const SET_PAY_AMOUNT = 'SET_PAY_AMOUNT'
export const SET_PAY_INPUT = 'SET_PAY_INPUT'
export const SET_PAY_INVOICE = 'SET_PAY_INVOICE'
+export const SET_CURRENCY_FILTERS = 'SET_CURRENCY_FILTERS'
+
export const UPDATE_PAY_ERRORS = 'UPDATE_PAY_ERRORS'
export const RESET_FORM = 'RESET_FORM'
@@ -60,6 +64,13 @@ export function setPayInvoice(invoice) {
}
}
+export function setCurrencyFilters(showCurrencyFilters) {
+ return {
+ type: SET_CURRENCY_FILTERS,
+ showCurrencyFilters
+ }
+}
+
export function updatePayErrors(errorsObject) {
return {
type: UPDATE_PAY_ERRORS,
@@ -87,6 +98,7 @@ const ACTION_HANDLERS = {
[SET_PAY_AMOUNT]: (state, { amount }) => ({ ...state, amount, showErrors: Object.assign(state.showErrors, { amount: false }) }),
[SET_PAY_INPUT]: (state, { payInput }) => ({ ...state, payInput, showErrors: Object.assign(state.showErrors, { payInput: false }) }),
[SET_PAY_INVOICE]: (state, { invoice }) => ({ ...state, invoice, showErrors: Object.assign(state.showErrors, { amount: false }) }),
+ [SET_CURRENCY_FILTERS]: (state, { showCurrencyFilters }) => ({ ...state, showCurrencyFilters }),
[UPDATE_PAY_ERRORS]: (state, { errorsObject }) => ({ ...state, showErrors: Object.assign(state.showErrors, errorsObject) }),
@@ -140,12 +152,23 @@ payFormSelectors.currentAmount = createSelector(
payFormSelectors.isLn,
payAmountSelector,
payInvoiceSelector,
- (isLn, amount, invoice) => {
+ currencySelector,
+ (isLn, amount, invoice, currency) => {
if (isLn) {
- return btc.satoshisToBtc((invoice.num_satoshis || 0))
+ switch (currency) {
+ case 'btc':
+ return btc.satoshisToBtc((invoice.num_satoshis || 0))
+ case 'bits':
+ return btc.satoshisToBits((invoice.num_satoshis || 0))
+ case 'sats':
+ return invoice.num_satoshis
+ default:
+ return invoice.num_satoshis
+
+ }
}
- return amount > 0 ? amount : null
+ return amount
}
)
@@ -162,7 +185,33 @@ payFormSelectors.usdAmount = createSelector(
return btc.satoshisToUsd((invoice.num_satoshis || 0), ticker.price_usd)
}
- return btc.btcToUsd(amount, ticker.price_usd)
+ switch (currency) {
+ case 'btc':
+ return btc.btcToUsd(amount, ticker.price_usd)
+ case 'bits':
+ return btc.bitsToUsd(amount, ticker.price_usd)
+ case 'sats':
+ return btc.satoshisToUsd(amount, ticker.price_usd)
+ default:
+ return ''
+
+ }
+ }
+)
+
+payFormSelectors.payInputMin = createSelector(
+ currencySelector,
+ (currency) => {
+ switch (currency) {
+ case 'btc':
+ return '0.00000001'
+ case 'bits':
+ return '0.01'
+ case 'sats':
+ return '1'
+ default:
+ return '0'
+ }
}
)
diff --git a/app/reducers/ticker.js b/app/reducers/ticker.js
index 32665a5a..2a9aee11 100644
--- a/app/reducers/ticker.js
+++ b/app/reducers/ticker.js
@@ -77,6 +77,8 @@ const ACTION_HANDLERS = {
// Selectors
const tickerSelectors = {}
const cryptoSelector = state => state.ticker.crypto
+const currencyFiltersSelector = state => state.ticker.currencyFilters
+const currencySelector = state => state.ticker.currency
const bitcoinTickerSelector = state => state.ticker.btcTicker
const litecoinTickerSelector = state => state.ticker.ltcTicker
@@ -87,6 +89,22 @@ tickerSelectors.currentTicker = createSelector(
(crypto, btcTicker, ltcTicker) => (crypto === 'btc' ? btcTicker : ltcTicker)
)
+tickerSelectors.currentCurrencyFilters = createSelector(
+ currencySelector,
+ currencyFiltersSelector,
+ (currency, filters) => filters.filter(f => f.key !== currency)
+)
+
+tickerSelectors.currencyName = createSelector(
+ currencySelector,
+ (currency) => {
+ if (currency === 'btc') { return 'BTC' }
+ if (currency === 'sats') { return 'satohis' }
+
+ return currency
+ }
+)
+
export { tickerSelectors }
// ------------------------------------
@@ -97,7 +115,21 @@ const initialState = {
currency: '',
crypto: '',
btcTicker: null,
- ltcTicker: null
+ ltcTicker: null,
+ currencyFilters: [
+ {
+ key: 'btc',
+ name: 'BTC'
+ },
+ {
+ key: 'bits',
+ name: 'bits'
+ },
+ {
+ key: 'sats',
+ name: 'satoshis'
+ }
+ ]
}
export default function tickerReducer(state = initialState, action) {
diff --git a/app/routes/app/containers/AppContainer.js b/app/routes/app/containers/AppContainer.js
index bd39879d..1e89057e 100644
--- a/app/routes/app/containers/AppContainer.js
+++ b/app/routes/app/containers/AppContainer.js
@@ -11,7 +11,7 @@ import { showModal, hideModal } from 'reducers/modal'
import { setFormType } from 'reducers/form'
-import { setPayAmount, setPayInput, updatePayErrors, payFormSelectors } from 'reducers/payform'
+import { setPayAmount, setPayInput, setCurrencyFilters, updatePayErrors, payFormSelectors } from 'reducers/payform'
import { setRequestAmount, setRequestMemo } from 'reducers/requestform'
@@ -69,6 +69,7 @@ const mapDispatchToProps = {
setPayAmount,
setPayInput,
+ setCurrencyFilters,
updatePayErrors,
setRequestAmount,
@@ -130,6 +131,8 @@ const mapStateToProps = state => ({
network: state.network,
currentTicker: tickerSelectors.currentTicker(state),
+ currentCurrencyFilters: tickerSelectors.currentCurrencyFilters(state),
+ currencyName: tickerSelectors.currencyName(state),
isOnchain: payFormSelectors.isOnchain(state),
isLn: payFormSelectors.isLn(state),
currentAmount: payFormSelectors.currentAmount(state),
@@ -137,6 +140,7 @@ const mapStateToProps = state => ({
inputCaption: payFormSelectors.inputCaption(state),
showPayLoadingScreen: payFormSelectors.showPayLoadingScreen(state),
payFormIsValid: payFormSelectors.payFormIsValid(state),
+ payInputMin: payFormSelectors.payInputMin(state),
syncPercentage: lndSelectors.syncPercentage(state),
filteredNetworkNodes: contactFormSelectors.filteredNetworkNodes(state),
@@ -157,6 +161,7 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
currency: stateProps.ticker.currency,
crypto: stateProps.ticker.crypto,
nodes: stateProps.network.nodes,
+ ticker: stateProps.ticker,
isOnchain: stateProps.isOnchain,
isLn: stateProps.isLn,
@@ -165,10 +170,15 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
inputCaption: stateProps.inputCaption,
showPayLoadingScreen: stateProps.showPayLoadingScreen,
payFormIsValid: stateProps.payFormIsValid,
+ payInputMin: stateProps.payInputMin,
+ currentCurrencyFilters: stateProps.currentCurrencyFilters,
+ currencyName: stateProps.currencyName,
setPayAmount: dispatchProps.setPayAmount,
setPayInput: dispatchProps.setPayInput,
+ setCurrencyFilters: dispatchProps.setCurrencyFilters,
fetchInvoice: dispatchProps.fetchInvoice,
+ setCurrency: dispatchProps.setCurrency,
onPayAmountBlur: () => {
// If the amount is now valid and showErrors was on, turn it off
diff --git a/app/utils/btc.js b/app/utils/btc.js
index 32c470d1..945cccf7 100644
--- a/app/utils/btc.js
+++ b/app/utils/btc.js
@@ -1,11 +1,52 @@
import sb from 'satoshi-bitcoin'
-
+//////////////////////
+// BTC to things /////
+/////////////////////
export function btcToSatoshis(btc) {
if (btc === undefined || btc === null || btc === '') return null
return sb.toSatoshi(btc)
}
+export function btcToBits(btc) {
+ if (btc === undefined || btc === null || btc === '') return null
+
+ return satoshisToBits(sb.toSatoshi(btc))
+}
+
+export function btcToUsd(btc, price) {
+ const amount = parseFloat(btc * price).toFixed(2)
+ return (btc > 0 && amount <= 0) ? '< 0.01' : amount.toLocaleString('en')
+}
+
+////////////////////////////
+// bits to things /////////
+//////////////////////////
+
+export function bitsToBtc(bits, price) {
+ if (bits === undefined || bits === null || bits === '') return null
+ const sats = bits * 100
+
+ return satoshisToBtc(sats, price)
+}
+
+export function bitsToSatoshis(bits, price) {
+ if (bits === undefined || bits === null || bits === '') return null
+
+ return bits * 100
+}
+
+export function bitsToUsd(bits, price) {
+ if (bits === undefined || bits === null || bits === '') return null
+ const sats = bits * 100
+
+ return satoshisToUsd(sats, price)
+}
+
+////////////////////////////
+// satoshis to things /////
+//////////////////////////
+
export function satoshisToBtc(satoshis) {
if (satoshis === undefined || satoshis === null || satoshis === '') return null
@@ -20,17 +61,13 @@ export function satoshisToBits(satoshis) {
return bitsAmount > 0 ? bitsAmount : bitsAmount * -1
}
-export function btcToUsd(btc, price) {
- const amount = parseFloat(btc * price).toFixed(2)
- return (btc > 0 && amount <= 0) ? '< 0.01' : amount.toLocaleString('en')
-}
-
export function satoshisToUsd(satoshis, price) {
if (satoshis === undefined || satoshis === null || satoshis === '') return null
return btcToUsd(satoshisToBtc(satoshis), price)
}
+
export function renderCurrency(currency) {
switch (currency) {
case 'btc':
@@ -44,11 +81,57 @@ export function renderCurrency(currency) {
}
}
+export function convert(from, to, amount, price) {
+ switch (from) {
+ case 'btc':
+ switch (to) {
+ case 'bits':
+ return btcToBits(amount)
+ case 'sats':
+ return btcToSatoshis(amount)
+ case 'usd':
+ return btcToUsd(amount, price)
+ }
+ break
+ case 'bits':
+ switch (to) {
+ case 'btc':
+ return bitsToBtc(amount)
+ case 'sats':
+ return bitsToSatoshis(amount)
+ case 'usd':
+ return bitsToUsd(amount, price)
+ }
+ break
+ case 'sats':
+ switch (to) {
+ case 'btc':
+ return satoshisToBtc(amount)
+ case 'bits':
+ return satoshisToBits(amount)
+ case 'usd':
+ return satoshisToUsd(amount, price)
+ }
+ break
+ default:
+ return ''
+ }
+}
+
export default {
btcToSatoshis,
+ btcToBits,
+ btcToUsd,
+
+ bitsToBtc,
+ bitsToSatoshis,
+ bitsToUsd,
+
satoshisToBtc,
satoshisToBits,
satoshisToUsd,
- btcToUsd,
- renderCurrency
+
+ renderCurrency,
+
+ convert
}