Browse Source

Merge pull request #865 from mrfelton/feat/ui-crypto-dropdown

feat(ui): add Dropdown component
renovate/lint-staged-8.x
JimmyMow 6 years ago
committed by GitHub
parent
commit
050190ab81
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 51
      app/components/Activity/InvoiceModal/InvoiceModal.js
  2. 46
      app/components/Activity/InvoiceModal/InvoiceModal.scss
  3. 48
      app/components/Activity/PaymentModal/PaymentModal.js
  4. 46
      app/components/Activity/PaymentModal/PaymentModal.scss
  5. 47
      app/components/Activity/TransactionModal/TransactionModal.js
  6. 46
      app/components/Activity/TransactionModal/TransactionModal.scss
  7. 35
      app/components/Contacts/SubmitChannelForm/SubmitChannelForm.js
  8. 49
      app/components/Contacts/SubmitChannelForm/SubmitChannelForm.scss
  9. 48
      app/components/Form/Pay/Pay.js
  10. 49
      app/components/Form/Pay/Pay.scss
  11. 43
      app/components/Form/Request/Request.js
  12. 51
      app/components/Form/Request/Request.scss
  13. 3
      app/components/UI/Button.js
  14. 181
      app/components/UI/Dropdown.js
  15. 3
      app/components/UI/GlobalStyle.js
  16. 10
      app/components/UI/Page.js
  17. 216
      app/components/Wallet/Wallet.js
  18. 169
      app/components/Wallet/Wallet.scss
  19. 7
      app/containers/Activity.js
  20. 58
      app/containers/App.js
  21. 21
      app/reducers/activity.js
  22. 18
      app/reducers/contactsform.js
  23. 15
      app/reducers/info.js
  24. 17
      app/reducers/payform.js
  25. 18
      app/reducers/requestform.js
  26. 36
      app/reducers/ticker.js
  27. 6
      app/themes/dark.js
  28. 6
      app/themes/light.js
  29. 1
      package.json
  30. 58
      stories/components/dropdown.stories.js
  31. 7
      test/unit/components/Form.spec.js
  32. 24
      test/unit/components/Form/Pay.spec.js
  33. 14
      test/unit/components/Form/Request.spec.js
  34. 30
      test/unit/components/UI/Dropdown.spec.js
  35. 4
      test/unit/components/UI/__snapshots__/Button.spec.js.snap
  36. 81
      test/unit/components/UI/__snapshots__/Dropdown.spec.js.snap
  37. 7
      test/unit/components/UI/__snapshots__/Page.spec.js.snap
  38. 40
      test/unit/reducers/__snapshots__/activity.spec.js.snap
  39. 3
      test/unit/reducers/__snapshots__/info.spec.js.snap
  40. 11
      test/unit/reducers/activity.spec.js
  41. 9
      yarn.lock

51
app/components/Activity/InvoiceModal/InvoiceModal.js

@ -1,18 +1,13 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import QRCode from 'qrcode.react' import QRCode from 'qrcode.react'
import copy from 'copy-to-clipboard' import copy from 'copy-to-clipboard'
import { showNotification } from 'lib/utils/notifications' import { showNotification } from 'lib/utils/notifications'
import FaAngleDown from 'react-icons/lib/fa/angle-down'
import Value from 'components/Value' import Value from 'components/Value'
import Dropdown from 'components/UI/Dropdown'
import { FormattedDate, FormattedTime, FormattedMessage } from 'react-intl' import { FormattedDate, FormattedTime, FormattedMessage } from 'react-intl'
import Countdown from '../Countdown' import Countdown from '../Countdown'
import messages from './messages' import messages from './messages'
import styles from './InvoiceModal.scss' import styles from './InvoiceModal.scss'
const InvoiceModal = ({ const InvoiceModal = ({
@ -20,13 +15,7 @@ const InvoiceModal = ({
ticker, ticker,
currentTicker, currentTicker,
toggleCurrencyProps: { toggleCurrencyProps: { currencyFilters, setCurrency }
setActivityModalCurrencyFilters,
showCurrencyFilters,
currencyName,
currentCurrencyFilters,
onCurrencyFilterClick
}
}) => { }) => {
const copyPaymentRequest = () => { const copyPaymentRequest = () => {
copy(invoice.payment_request) copy(invoice.payment_request)
@ -56,30 +45,18 @@ const InvoiceModal = ({
<section className={styles.right}> <section className={styles.right}>
<div className={styles.details}> <div className={styles.details}>
<section className={styles.amount}> <section className={styles.amount}>
<h1> <Value
<Value value={invoice.finalAmount}
value={invoice.finalAmount} currency={ticker.currency}
currency={ticker.currency} currentTicker={currentTicker}
currentTicker={currentTicker} fiatTicker={ticker.fiatTicker}
fiatTicker={ticker.fiatTicker} />
/> <Dropdown
</h1> activeKey={ticker.currency}
<section items={currencyFilters}
className={styles.currentCurrency} onChange={setCurrency}
onClick={() => setActivityModalCurrencyFilters(!showCurrencyFilters)} ml={2}
> />
<span>{currencyName}</span>
<span>
<FaAngleDown />
</span>
</section>
<ul className={showCurrencyFilters ? styles.active : undefined}>
{currentCurrencyFilters.map(filter => (
<li key={filter.key} onClick={() => onCurrencyFilterClick(filter.key)}>
{filter.name}
</li>
))}
</ul>
</section> </section>
<section className={styles.date}> <section className={styles.date}>
<p> <p>

46
app/components/Activity/InvoiceModal/InvoiceModal.scss

@ -46,51 +46,7 @@
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
position: relative; position: relative;
font-size: 40px;
h1 {
font-size: 40px;
margin-right: 10px;
}
.currentCurrency {
cursor: pointer;
transition: 0.25s all;
&:hover {
opacity: 0.5;
}
span {
font-size: 14px;
&:nth-child(1) {
font-weight: bold;
}
}
}
ul {
visibility: hidden;
position: absolute;
top: 40px;
right: -50px;
&.active {
visibility: visible;
}
li {
padding: 8px 15px;
background: var(--lightBackground);
cursor: pointer;
transition: 0.25s hover;
border-bottom: 1px solid var(--lightestBackground);
&:hover {
background: var(--lightestBackground);
}
}
}
} }
.date { .date {

48
app/components/Activity/PaymentModal/PaymentModal.js

@ -1,16 +1,11 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import Dropdown from 'components/UI/Dropdown'
import FaAngleDown from 'react-icons/lib/fa/angle-down'
import PaperPlane from 'components/Icon/PaperPlane' import PaperPlane from 'components/Icon/PaperPlane'
import Zap from 'components/Icon/Zap' import Zap from 'components/Icon/Zap'
import Value from 'components/Value' import Value from 'components/Value'
import { FormattedDate, FormattedTime, FormattedMessage } from 'react-intl' import { FormattedDate, FormattedTime, FormattedMessage } from 'react-intl'
import messages from './messages' import messages from './messages'
import styles from './PaymentModal.scss' import styles from './PaymentModal.scss'
const PaymentModal = ({ const PaymentModal = ({
@ -18,13 +13,7 @@ const PaymentModal = ({
ticker, ticker,
currentTicker, currentTicker,
toggleCurrencyProps: { toggleCurrencyProps: { currencyName, currencyFilters, setCurrency }
setActivityModalCurrencyFilters,
showCurrencyFilters,
currencyName,
currentCurrencyFilters,
onCurrencyFilterClick
}
}) => ( }) => (
<div className={styles.container}> <div className={styles.container}>
<header className={styles.header}> <header className={styles.header}>
@ -55,31 +44,14 @@ const PaymentModal = ({
</header> </header>
<div className={styles.amount}> <div className={styles.amount}>
<h1> <i className={`${styles.symbol} ${payment.value > 0 ? styles.active : undefined}`}>-</i>
<i className={`${styles.symbol} ${payment.value > 0 ? styles.active : undefined}`}>-</i> <Value
<Value value={payment.value}
value={payment.value} currency={ticker.currency}
currency={ticker.currency} currentTicker={currentTicker}
currentTicker={currentTicker} fiatTicker={ticker.fiatTicker}
fiatTicker={ticker.fiatTicker} />
/> <Dropdown activeKey={ticker.currency} items={currencyFilters} onChange={setCurrency} ml={2} />
</h1>
<section
className={styles.currentCurrency}
onClick={() => setActivityModalCurrencyFilters(!showCurrencyFilters)}
>
<span>{currencyName}</span>
<span>
<FaAngleDown />
</span>
<ul className={showCurrencyFilters ? styles.active : undefined}>
{currentCurrencyFilters.map(filter => (
<li key={filter.key} onClick={() => onCurrencyFilterClick(filter.key)}>
{filter.name}
</li>
))}
</ul>
</section>
</div> </div>
<div className={styles.date}> <div className={styles.date}>

46
app/components/Activity/PaymentModal/PaymentModal.scss

@ -60,51 +60,7 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 20px; padding: 20px;
font-size: 40px;
h1 {
font-size: 40px;
}
section {
font-size: 20px;
margin-left: 10px;
position: relative;
cursor: pointer;
&:hover {
span {
opacity: 0.5;
}
}
span {
transition: all 0.25s;
}
ul {
visibility: hidden;
position: absolute;
top: 40px;
right: -50px;
font-size: 12px;
&.active {
visibility: visible;
}
li {
padding: 8px 15px;
background: var(--lightBackground);
cursor: pointer;
transition: 0.25s hover;
border-bottom: 1px solid var(--lightestBackground);
&:hover {
background: var(--lightestBackground);
}
}
}
}
} }
.date { .date {

47
app/components/Activity/TransactionModal/TransactionModal.js

@ -1,6 +1,6 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import FaAngleDown from 'react-icons/lib/fa/angle-down' import Dropdown from 'components/UI/Dropdown'
import PaperPlane from 'components/Icon/PaperPlane' import PaperPlane from 'components/Icon/PaperPlane'
import Hand from 'components/Icon/Hand' import Hand from 'components/Icon/Hand'
import ChainLink from 'components/Icon/ChainLink' import ChainLink from 'components/Icon/ChainLink'
@ -19,13 +19,7 @@ const TransactionModal = ({
currentTicker, currentTicker,
network, network,
toggleCurrencyProps: { toggleCurrencyProps: { currencyName, currencyFilters, setCurrency }
setActivityModalCurrencyFilters,
showCurrencyFilters,
currencyName,
currentCurrencyFilters,
onCurrencyFilterClick
}
}) => ( }) => (
<div className={styles.container}> <div className={styles.container}>
<header className={styles.header}> <header className={styles.header}>
@ -72,33 +66,16 @@ const TransactionModal = ({
</header> </header>
<div className={styles.amount}> <div className={styles.amount}>
<h1> <i className={`${styles.symbol} ${transaction.received ? styles.active : undefined}`}>
<i className={`${styles.symbol} ${transaction.received ? styles.active : undefined}`}> {transaction.received ? '+' : '-'}
{transaction.received ? '+' : '-'} </i>
</i> <Value
<Value value={transaction.amount}
value={transaction.amount} currency={ticker.currency}
currency={ticker.currency} currentTicker={currentTicker}
currentTicker={currentTicker} fiatTicker={ticker.fiatTicker}
fiatTicker={ticker.fiatTicker} />
/> <Dropdown activeKey={ticker.currency} items={currencyFilters} onChange={setCurrency} ml={2} />
</h1>
<section
className={styles.currentCurrency}
onClick={() => setActivityModalCurrencyFilters(!showCurrencyFilters)}
>
<span>{currencyName}</span>
<span>
<FaAngleDown />
</span>
<ul className={showCurrencyFilters ? styles.active : undefined}>
{currentCurrencyFilters.map(filter => (
<li key={filter.key} onClick={() => onCurrencyFilterClick(filter.key)}>
{filter.name}
</li>
))}
</ul>
</section>
</div> </div>
<div className={styles.date}> <div className={styles.date}>

46
app/components/Activity/TransactionModal/TransactionModal.scss

@ -68,51 +68,7 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 20px; padding: 20px;
font-size: 40px;
h1 {
font-size: 40px;
}
section {
font-size: 20px;
margin-left: 10px;
position: relative;
cursor: pointer;
&:hover {
span {
opacity: 0.5;
}
}
span {
transition: all 0.25s;
}
ul {
visibility: hidden;
position: absolute;
top: 40px;
right: -50px;
font-size: 12px;
&.active {
visibility: visible;
}
li {
padding: 8px 15px;
background: var(--lightBackground);
cursor: pointer;
transition: 0.25s hover;
border-bottom: 1px solid var(--lightestBackground);
&:hover {
background: var(--lightestBackground);
}
}
}
}
} }
.date { .date {

35
app/components/Contacts/SubmitChannelForm/SubmitChannelForm.js

@ -1,11 +1,11 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import FaAngleDown from 'react-icons/lib/fa/angle-down'
import FaExclamationCircle from 'react-icons/lib/fa/exclamation-circle' import FaExclamationCircle from 'react-icons/lib/fa/exclamation-circle'
import AmountInput from 'components/AmountInput' import AmountInput from 'components/AmountInput'
import Button from 'components/UI/Button' import Button from 'components/UI/Button'
import Dropdown from 'components/UI/Dropdown'
import { FormattedNumber, FormattedMessage } from 'react-intl' import { FormattedNumber, FormattedMessage } from 'react-intl'
import messages from './messages' import messages from './messages'
@ -37,14 +37,7 @@ class SubmitChannelForm extends React.Component {
ticker, ticker,
toggleCurrencyProps: { toggleCurrencyProps: { currencyFilters, onCurrencyFilterClick, contactFormFiatAmount }
setContactsCurrencyFilters,
showCurrencyFilters,
currencyName,
currentCurrencyFilters,
onCurrencyFilterClick,
contactFormFiatAmount
}
} = this.props } = this.props
const renderTitle = () => { const renderTitle = () => {
@ -126,24 +119,12 @@ class SubmitChannelForm extends React.Component {
onChangeEvent={updateContactCapacity} onChangeEvent={updateContactCapacity}
ref={this.amountInput} ref={this.amountInput}
/> />
<div className={styles.currency}> <Dropdown
<section activeKey={ticker.currency}
className={styles.currentCurrency} items={currencyFilters}
onClick={() => setContactsCurrencyFilters(!showCurrencyFilters)} onChange={onCurrencyFilterClick}
> ml={2}
<span>{currencyName}</span> />
<span>
<FaAngleDown />
</span>
</section>
<ul className={showCurrencyFilters ? styles.active : undefined}>
{currentCurrencyFilters.map(filter => (
<li key={filter.key} onClick={() => onCurrencyFilterClick(filter.key)}>
{filter.name}
</li>
))}
</ul>
</div>
</div> </div>
<div className={styles.fiatAmount}> <div className={styles.fiatAmount}>
{'≈ '} {'≈ '}

49
app/components/Contacts/SubmitChannelForm/SubmitChannelForm.scss

@ -1,7 +1,6 @@
@import 'styles/variables.scss'; @import 'styles/variables.scss';
.content { .content {
padding: 0 40px;
color: var(--primaryText); color: var(--primaryText);
margin: 0 auto; margin: 0 auto;
width: 500px; width: 500px;
@ -72,7 +71,7 @@
input { input {
font-size: 25px; font-size: 25px;
max-width: 110px; max-width: 180px;
background: transparent; background: transparent;
outline: none; outline: none;
border: 1px solid #404040; border: 1px solid #404040;
@ -91,52 +90,6 @@
-webkit-text-fill-color: initial; -webkit-text-fill-color: initial;
} }
.currency {
position: relative;
display: flex;
flex-direction: row;
align-items: center;
padding-left: 10px;
.currentCurrency {
cursor: pointer;
transition: 0.25s all;
&:hover {
opacity: 0.5;
}
span {
font-size: 14px;
&:nth-child(1) {
font-weight: bold;
}
}
}
ul {
visibility: hidden;
position: absolute;
top: 30px;
&.active {
visibility: visible;
}
li {
padding: 8px 15px;
background: var(--lightBackground);
cursor: pointer;
transition: 0.25s hover;
&:hover {
background: var(--lightestBackground);
}
}
}
}
.fiatAmount { .fiatAmount {
margin-top: 20px; margin-top: 20px;
opacity: 0.75; opacity: 0.75;

48
app/components/Form/Pay/Pay.js

@ -3,11 +3,11 @@ import PropTypes from 'prop-types'
import PaperPlane from 'components/Icon/PaperPlane' import PaperPlane from 'components/Icon/PaperPlane'
import ChainLink from 'components/Icon/ChainLink' import ChainLink from 'components/Icon/ChainLink'
import FaAngleDown from 'react-icons/lib/fa/angle-down'
import { btc } from 'lib/utils' import { btc } from 'lib/utils'
import AmountInput from 'components/AmountInput' import AmountInput from 'components/AmountInput'
import Button from 'components/UI/Button' import Button from 'components/UI/Button'
import Dropdown from 'components/UI/Dropdown'
import { FormattedNumber, FormattedMessage, injectIntl } from 'react-intl' import { FormattedNumber, FormattedMessage, injectIntl } from 'react-intl'
import messages from './messages' import messages from './messages'
@ -46,28 +46,20 @@ class Pay extends Component {
render() { render() {
const { const {
payform: { payInput, showErrors, invoice, showCurrencyFilters }, payform: { payInput, showErrors, invoice },
nodes, nodes,
ticker, ticker,
isOnchain, isOnchain,
isLn, isLn,
currentAmount, currentAmount,
fiatAmount, fiatAmount,
payFormIsValid: { errors, isValid }, payFormIsValid: { errors, isValid },
currentCurrencyFilters, currencyFilters,
currencyName,
setPayAmount, setPayAmount,
onPayAmountBlur, onPayAmountBlur,
setPayInput, setPayInput,
onPayInputBlur, onPayInputBlur,
setCurrencyFilters,
onPaySubmit, onPaySubmit,
setCurrency, setCurrency,
intl intl
} = this.props } = this.props
@ -87,9 +79,7 @@ class Pay extends Component {
// change the input amount // change the input amount
setPayAmount(btc.convert(ticker.currency, currency, currentAmount)) setPayAmount(btc.convert(ticker.currency, currency, currentAmount))
} }
setCurrency(currency) setCurrency(currency)
setCurrencyFilters(false)
} }
return ( return (
@ -164,24 +154,12 @@ class Pay extends Component {
onBlurEvent={onPayAmountBlur} onBlurEvent={onPayAmountBlur}
readOnly={isLn} readOnly={isLn}
/> />
<div className={styles.currency}> <Dropdown
<section activeKey={ticker.currency}
className={styles.currentCurrency} items={currencyFilters}
onClick={() => setCurrencyFilters(!showCurrencyFilters)} onChange={onCurrencyFilterClick}
> ml={2}
<span>{currencyName}</span> />
<span>
<FaAngleDown />
</span>
</section>
<ul className={showCurrencyFilters ? styles.active : undefined}>
{currentCurrencyFilters.map(filter => (
<li key={filter.key} onClick={() => onCurrencyFilterClick(filter.key)}>
{filter.name}
</li>
))}
</ul>
</div>
</div> </div>
<div className={styles.fiatAmount}> <div className={styles.fiatAmount}>
@ -221,7 +199,6 @@ Pay.propTypes = {
showErrors: PropTypes.object.isRequired showErrors: PropTypes.object.isRequired
}).isRequired, }).isRequired,
currencyName: PropTypes.string.isRequired, currencyName: PropTypes.string.isRequired,
isOnchain: PropTypes.bool.isRequired, isOnchain: PropTypes.bool.isRequired,
isLn: PropTypes.bool.isRequired, isLn: PropTypes.bool.isRequired,
currentAmount: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), currentAmount: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
@ -230,21 +207,16 @@ Pay.propTypes = {
errors: PropTypes.object, errors: PropTypes.object,
isValid: PropTypes.bool isValid: PropTypes.bool
}).isRequired, }).isRequired,
setPayAmount: PropTypes.func.isRequired, setPayAmount: PropTypes.func.isRequired,
onPayAmountBlur: PropTypes.func.isRequired, onPayAmountBlur: PropTypes.func.isRequired,
setPayInput: PropTypes.func.isRequired, setPayInput: PropTypes.func.isRequired,
onPayInputBlur: PropTypes.func.isRequired, onPayInputBlur: PropTypes.func.isRequired,
fetchInvoice: PropTypes.func.isRequired, fetchInvoice: PropTypes.func.isRequired,
onPaySubmit: PropTypes.func.isRequired, onPaySubmit: PropTypes.func.isRequired,
setCurrencyFilters: PropTypes.func.isRequired,
setCurrency: PropTypes.func.isRequired, setCurrency: PropTypes.func.isRequired,
ticker: PropTypes.object.isRequired, ticker: PropTypes.object.isRequired,
nodes: PropTypes.array.isRequired, nodes: PropTypes.array.isRequired,
currentCurrencyFilters: PropTypes.array.isRequired currencyFilters: PropTypes.array.isRequired
} }
export default injectIntl(Pay) export default injectIntl(Pay)

49
app/components/Form/Pay/Pay.scss

@ -1,7 +1,6 @@
@import 'styles/variables.scss'; @import 'styles/variables.scss';
.container { .container {
padding: 0 40px;
margin: 0 auto; margin: 0 auto;
width: 500px; width: 500px;
} }
@ -50,7 +49,6 @@
.amount .bottom { .amount .bottom {
display: flex; display: flex;
flex-direction: row;
align-items: center; align-items: center;
input { input {
@ -95,53 +93,6 @@
} }
} }
.currency {
position: relative;
display: flex;
flex-direction: row;
align-items: center;
margin-left: 12px;
.currentCurrency {
cursor: pointer;
transition: 0.25s all;
&:hover {
opacity: 0.5;
}
span {
font-size: 14px;
&:nth-child(1) {
font-weight: bold;
}
}
}
ul {
visibility: hidden;
position: absolute;
top: 30px;
z-index: z("form", "pay");
&.active {
visibility: visible;
}
li {
padding: 8px 15px;
background: var(--lightBackground);
cursor: pointer;
transition: 0.25s hover;
&:hover {
background: var(--darkestBackground);
}
}
}
}
.fiatAmount { .fiatAmount {
margin-top: 10px; margin-top: 10px;
opacity: 0.5; opacity: 0.5;

43
app/components/Form/Request/Request.js

@ -2,11 +2,11 @@ import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import Hand from 'components/Icon/Hand' import Hand from 'components/Icon/Hand'
import FaAngleDown from 'react-icons/lib/fa/angle-down'
import { btc } from 'lib/utils' import { btc } from 'lib/utils'
import AmountInput from 'components/AmountInput' import AmountInput from 'components/AmountInput'
import Button from 'components/UI/Button' import Button from 'components/UI/Button'
import Dropdown from 'components/UI/Dropdown'
import { FormattedNumber, FormattedMessage, injectIntl } from 'react-intl' import { FormattedNumber, FormattedMessage, injectIntl } from 'react-intl'
import messages from './messages' import messages from './messages'
@ -14,27 +14,20 @@ import messages from './messages'
import styles from './Request.scss' import styles from './Request.scss'
const Request = ({ const Request = ({
requestform: { amount, memo, showCurrencyFilters }, requestform: { amount, memo },
ticker, ticker,
setRequestAmount, setRequestAmount,
setRequestMemo, setRequestMemo,
setCurrency, setCurrency,
setRequestCurrencyFilters,
currencyName,
requestFiatAmount, requestFiatAmount,
currencyFilters,
currentCurrencyFilters,
onRequestSubmit, onRequestSubmit,
intl intl
}) => { }) => {
const onCurrencyFilterClick = currency => { const onCurrencyFilterClick = currency => {
// change the input amount // change the input amount
setRequestAmount(btc.convert(ticker.currency, currency, amount)) setRequestAmount(btc.convert(ticker.currency, currency, amount))
setCurrency(currency) setCurrency(currency)
setRequestCurrencyFilters(false)
} }
return ( return (
@ -61,24 +54,12 @@ const Request = ({
currency={ticker.currency} currency={ticker.currency}
onChangeEvent={setRequestAmount} onChangeEvent={setRequestAmount}
/> />
<div className={styles.currency}> <Dropdown
<section activeKey={ticker.currency}
className={styles.currentCurrency} items={currencyFilters}
onClick={() => setRequestCurrencyFilters(!showCurrencyFilters)} onChange={onCurrencyFilterClick}
> ml={2}
<span>{currencyName}</span> />
<span>
<FaAngleDown />
</span>
</section>
<ul className={showCurrencyFilters ? styles.active : undefined}>
{currentCurrencyFilters.map(filter => (
<li key={filter.key} onClick={() => onCurrencyFilterClick(filter.key)}>
{filter.name}
</li>
))}
</ul>
</div>
</div> </div>
<div className={styles.fiatAmount}> <div className={styles.fiatAmount}>
@ -123,17 +104,13 @@ Request.propTypes = {
amount: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), amount: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
memo: PropTypes.string memo: PropTypes.string
}).isRequired, }).isRequired,
requestFiatAmount: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), requestFiatAmount: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
currencyName: PropTypes.string.isRequired, currencyName: PropTypes.string.isRequired,
currencyFilters: PropTypes.array.isRequired,
currentCurrencyFilters: PropTypes.array.isRequired,
setRequestAmount: PropTypes.func.isRequired, setRequestAmount: PropTypes.func.isRequired,
setRequestMemo: PropTypes.func.isRequired, setRequestMemo: PropTypes.func.isRequired,
onRequestSubmit: PropTypes.func.isRequired, onRequestSubmit: PropTypes.func.isRequired,
setCurrency: PropTypes.func.isRequired, setCurrency: PropTypes.func.isRequired,
setRequestCurrencyFilters: PropTypes.func.isRequired,
ticker: PropTypes.object.isRequired ticker: PropTypes.object.isRequired
} }

51
app/components/Form/Request/Request.scss

@ -1,7 +1,6 @@
@import 'styles/variables.scss'; @import 'styles/variables.scss';
.container { .container {
padding: 0 40px;
margin: 0 auto; margin: 0 auto;
width: 500px; width: 500px;
} }
@ -55,6 +54,9 @@
} }
.bottom { .bottom {
display: flex;
align-items: center;
input { input {
background: transparent; background: transparent;
outline: none; outline: none;
@ -74,53 +76,6 @@
} }
} }
.currency {
position: relative;
display: flex;
flex-direction: row;
align-items: center;
margin-left: 12px;
.currentCurrency {
cursor: pointer;
transition: 0.25s all;
&:hover {
opacity: 0.5;
}
span {
font-size: 14px;
&:nth-child(1) {
font-weight: bold;
}
}
}
ul {
visibility: hidden;
position: absolute;
top: 30px;
z-index: z("form", "request");
&.active {
visibility: visible;
}
li {
padding: 8px 15px;
background: var(--lightBackground);
cursor: pointer;
transition: 0.25s hover;
&:hover {
background: var(--darkestBackground);
}
}
}
}
.fiatAmount { .fiatAmount {
margin-top: 10px; margin-top: 10px;
opacity: 0.5; opacity: 0.5;

3
app/components/UI/Button.js

@ -10,9 +10,6 @@ const Wrapper = styled(BaseButton)`
border-radius: 5; border-radius: 5;
font-weight: normal; font-weight: normal;
line-height: '18px'; line-height: '18px';
&:focus {
box-shadow: 0 0 3px ${props => props.theme.lightningOrange};
}
&:disabled { &:disabled {
opacity: 0.5; opacity: 0.5;
} }

181
app/components/UI/Dropdown.js

@ -0,0 +1,181 @@
import React from 'react'
import PropTypes from 'prop-types'
import { Box, Flex } from 'rebass'
import styled, { withTheme } from 'styled-components'
import FaAngleDown from 'react-icons/lib/fa/angle-down'
import FaAngleUp from 'react-icons/lib/fa/angle-up'
import Check from 'components/Icon/Check'
import Text from 'components/UI/Text'
/**
* Container
*/
const DropdownContainer = styled(Flex)({})
DropdownContainer.defaultProps = {
flexDirection: 'column',
flexWrap: 'none',
display: 'relative'
}
/**
* Button
*/
const DropdownButton = styled(Box)({
appearance: 'none',
display: 'inline-block',
textAlign: 'center',
lineHeight: 'inherit',
textDecoration: 'none',
border: 'none',
outline: 'none',
background: 'transparent',
color: 'inherit',
cursor: 'pointer'
})
DropdownButton.defaultProps = {
as: 'button',
m: 0,
px: 0,
py: 2,
textAlign: 'left'
}
/**
* Menu
*/
const MenuContainer = styled(Box)({
display: 'relative'
})
const Menu = styled(Box)({
cursor: 'pointer',
display: 'inline-block',
position: 'absolute',
'z-index': '999',
'min-width': '70px',
'list-style-type': 'none',
'border-radius': '3px',
'box-shadow': '0 3px 4px 0 rgba(30, 30, 30, 0.5)'
})
Menu.defaultProps = {
as: 'ul',
m: 0,
p: 0,
bg: 'lightestBackground'
}
/**
* MenuItem
*/
const MenuItem = styled(Box)`
cursor: pointer;
&:hover {
background-color: ${props => props.theme.colors.darkestBackground};
}
`
MenuItem.defaultProps = {
as: 'li',
px: 2,
py: 2
}
/**
* @render react
* @name Dropdown
* @example
* <Dropdown items={[
* {name: 'Item 1', key: 'key1'},
* {name: 'Item 2', key: 'key2'}
* ]} activeKey="key1" />
*/
class Dropdown extends React.Component {
state = {
isOpen: false
}
onChange = this.onChange.bind(this)
toggleMenu = this.toggleMenu.bind(this)
setWrapperRef = this.setWrapperRef.bind(this)
handleClickOutside = this.handleClickOutside.bind(this)
static propTypes = {
activeKey: PropTypes.string.isRequired,
items: PropTypes.arrayOf(
PropTypes.shape({
key: PropTypes.string.isRequired,
name: PropTypes.string.isRequired
})
).isRequired,
onChange: PropTypes.func
}
componentDidMount() {
document.addEventListener('mousedown', this.handleClickOutside)
}
componentWillUnmount() {
document.removeEventListener('mousedown', this.handleClickOutside)
}
onChange(key) {
const { onChange, activeKey } = this.props
if (key !== activeKey) {
if (onChange) {
onChange(key)
}
}
this.setState({ isOpen: false })
}
setWrapperRef(node) {
this.wrapperRef = node
}
handleClickOutside(event) {
if (this.wrapperRef && !this.wrapperRef.contains(event.target)) {
this.setState({ isOpen: false })
}
}
toggleMenu() {
const { isOpen } = this.state
this.setState({ isOpen: !isOpen })
}
render() {
const { isOpen } = this.state
const { activeKey, items, theme, ...rest } = this.props
const selectedItem = items.find(c => c.key === activeKey)
return (
<DropdownContainer ref={this.setWrapperRef} {...rest}>
<DropdownButton type="button" onClick={this.toggleMenu}>
<Text textAlign="left">
{selectedItem ? selectedItem.name : activeKey}{' '}
{isOpen ? <FaAngleUp /> : <FaAngleDown />}
</Text>
</DropdownButton>
{isOpen && (
<MenuContainer>
<Menu>
{items.map(item => {
return (
<MenuItem key={item.key} onClick={() => this.onChange(item.key)}>
<Flex alignItems="center">
<Text width="18px">
{activeKey === item.key && (
<Check height="0.95em" color={theme.colors.superGreen} />
)}
</Text>
<Text>{item.name}</Text>
</Flex>
</MenuItem>
)
})}
</Menu>
</MenuContainer>
)}
</DropdownContainer>
)
}
}
export default withTheme(Dropdown)

3
app/components/UI/GlobalStyle.js

@ -11,11 +11,10 @@ const GlobalStyle = createGlobalStyle`
position: relative; position: relative;
box-sizing: border-box; box-sizing: border-box;
overflow-y: hidden; overflow-y: hidden;
margin: 0;
padding: 0;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-webkit-tap-highlight-color: rgba(255, 255, 255, 0); -webkit-tap-highlight-color: rgba(255, 255, 255, 0);
font-family: 'Roboto', Arial, Helvetica, sans-serif; font-family: 'Roboto', Arial, Helvetica, sans-serif;
font-size: 13px;
} }
` `

10
app/components/UI/Page.js

@ -12,9 +12,13 @@ const Page = props => (
{...props} {...props}
as="article" as="article"
alignItems="stretch" alignItems="stretch"
width="950" bg="darkestBackground"
bg="white" css={{
css={{ height: '600px', 'min-height': '700px', 'min-width': '950px' }} 'min-height': '700px',
'min-width': '950px',
'overflow-y': 'hidden',
'box-shadow': '0 3px 4px 0 rgba(30, 30, 30, 0.5)'
}}
/> />
) )

216
app/components/Wallet/Wallet.js

@ -2,11 +2,13 @@ import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import FaAngleUp from 'react-icons/lib/fa/angle-up' import FaAngleUp from 'react-icons/lib/fa/angle-up'
import FaAngleDown from 'react-icons/lib/fa/angle-down' import FaAngleDown from 'react-icons/lib/fa/angle-down'
import { Box, Flex } from 'rebass'
import { btc, blockExplorer } from 'lib/utils' import { btc, blockExplorer } from 'lib/utils'
import Value from 'components/Value' import Value from 'components/Value'
import Settings from 'components/Settings' import Settings from 'components/Settings'
import Button from 'components/UI/Button' import Button from 'components/UI/Button'
import Text from 'components/UI/Text'
import Dropdown from 'components/UI/Dropdown'
import CheckAnimated from 'components/Icon/CheckAnimated' import CheckAnimated from 'components/Icon/CheckAnimated'
import ZapLogo from 'components/Icon/ZapLogo' import ZapLogo from 'components/Icon/ZapLogo'
@ -29,10 +31,8 @@ const Wallet = ({
showPayLoadingScreen, showPayLoadingScreen,
showSuccessPayScreen, showSuccessPayScreen,
successTransactionScreen, successTransactionScreen,
currentCurrencyFilters, currencyFilters,
currencyName,
setCurrency, setCurrency,
setWalletCurrencyFilters,
network, network,
settingsProps, settingsProps,
paymentTimeout, paymentTimeout,
@ -43,24 +43,22 @@ const Wallet = ({
currentTicker[ticker.fiatTicker].last currentTicker[ticker.fiatTicker].last
) )
const onCurrencyFilterClick = currency => {
setCurrency(currency)
setWalletCurrencyFilters(false)
}
return ( return (
<div className={`${styles.wallet}`}> <div className={`${styles.wallet}`}>
<div className={styles.content}> <Flex as="header" justifyContent="space-between">
<header className={styles.header}> <Flex as="section" alignItems="center">
<section className={styles.logo}> {theme === 'light' ? (
{theme === 'light' ? ( <ZapLogoBlack width="70px" height="32px" />
<ZapLogoBlack width="70px" height="32px" /> ) : (
) : ( <ZapLogo width="70px" height="32px" />
<ZapLogo width="70px" height="32px" /> )}
)} {info.data.testnet && (
{info.data.testnet && <span className={styles.testnetPill}>Testnet</span>} <Text color="superGreen" fontSize={1} ml={2}>
</section> Testnet
</Text>
)}
</Flex>
<Box as="section">
<section className={styles.user}> <section className={styles.user}>
<div <div
className={`${styles.alias} ${settingsProps.settings.settingsOpen && className={`${styles.alias} ${settingsProps.settings.settingsOpen &&
@ -72,102 +70,93 @@ const Wallet = ({
</div> </div>
{settingsProps.settings.settingsOpen && <Settings {...settingsProps} />} {settingsProps.settings.settingsOpen && <Settings {...settingsProps} />}
</section> </section>
</header> </Box>
</Flex>
<div className={styles.left}> <Flex as="header" justifyContent="space-between" mt={4}>
<div className={styles.leftContent}> <Box as="section">
<span onClick={openReceiveModal} className={styles.qrCode}> <Flex alignItems="baseline">
<Qrcode width="20px" height="32px" /> <Box onClick={openReceiveModal} className={styles.qrCode} mr={2}>
</span> <Qrcode width="20px" height="20px" />
<div className={styles.details}> </Box>
<h1> <Flex flexDirection="column">
<span> <Text fontSize="24px" letterSpacing={2}>
<Value <Value
value={parseFloat(balance.walletBalance) + parseFloat(balance.channelBalance)} value={parseFloat(balance.walletBalance) + parseFloat(balance.channelBalance)}
currency={ticker.currency} currency={ticker.currency}
currentTicker={currentTicker} currentTicker={currentTicker}
fiatTicker={ticker.fiatTicker} fiatTicker={ticker.fiatTicker}
/> />
<section className={styles.currencyContainer}> </Text>
<i className={styles.currency}>{currencyName}</i> </Flex>
<span onClick={() => setWalletCurrencyFilters(!info.showWalletCurrencyFilters)}> <Dropdown
<FaAngleDown /> activeKey={ticker.currency}
</span> items={currencyFilters}
onChange={setCurrency}
<ul className={info.showWalletCurrencyFilters ? styles.active : undefined}> ml={2}
{currentCurrencyFilters.map(filter => ( />
<li key={filter.key} onClick={() => onCurrencyFilterClick(filter.key)}> </Flex>
{filter.name} <Box ml={30} mt={1}>
</li> {Boolean(fiatAmount) && (
))}
</ul>
</section>
</span>
</h1>
{Boolean(fiatAmount) && (
<span>
{'≈ '}
<FormattedNumber
currency={ticker.fiatTicker}
style="currency"
value={fiatAmount}
/>
</span>
)}
</div>
</div>
</div>
<div className={styles.right}>
<div className={styles.rightContent}>
<Button onClick={openPayForm} variant="primary" my={10} mx={7.5} width={100}>
<FormattedMessage {...messages.pay} />
</Button>
<Button onClick={openRequestForm} variant="primary" my={10} mx={7.5} width={100}>
<FormattedMessage {...messages.request} />
</Button>
</div>
<div className={styles.notificationBox}>
{showPayLoadingScreen && (
<span> <span>
<div className={styles.spinnerContainer}> {'≈ '}
<section className={`${styles.spinner} ${styles.icon}`} /> <FormattedNumber currency={ticker.fiatTicker} style="currency" value={fiatAmount} />
<span className={styles.timeout}>{paymentTimeout / 1000}</span>
</div>
<section>
<FormattedMessage {...messages.sending_tx} />
</section>
</span> </span>
)} )}
{showSuccessPayScreen && ( </Box>
<span> </Box>
<section className={styles.icon}> <Box as="section">
<CheckAnimated /> <Button onClick={openPayForm} variant="primary" mx={7.5} width={100}>
</section> <FormattedMessage {...messages.pay} />
<section> </Button>
<FormattedMessage {...messages.payment_success} /> <Button onClick={openRequestForm} variant="primary" mx={7.5} width={100}>
</section> <FormattedMessage {...messages.request} />
</span> </Button>
)} </Box>
{successTransactionScreen.show && ( </Flex>
<span>
<section className={styles.icon}> <Box mt={2}>
<CheckAnimated /> <div className={styles.notificationBox}>
</section> {showPayLoadingScreen && (
<section> <span>
<span <div className={styles.spinnerContainer}>
className={styles.txLink} <section className={`${styles.spinner} ${styles.icon}`} />
onClick={() => { <span className={styles.timeout}>{paymentTimeout / 1000}</span>
return blockExplorer.showTransaction(network, successTransactionScreen.txid) </div>
}} <section>
> <FormattedMessage {...messages.sending_tx} />
<FormattedMessage {...messages.transaction_success} /> </section>
</span> </span>
</section> )}
</span> {showSuccessPayScreen && (
)} <span>
</div> <section className={styles.icon}>
<CheckAnimated />
</section>
<section>
<FormattedMessage {...messages.payment_success} />
</section>
</span>
)}
{successTransactionScreen.show && (
<span>
<section className={styles.icon}>
<CheckAnimated />
</section>
<section>
<span
className={styles.txLink}
onClick={() => {
return blockExplorer.showTransaction(network, successTransactionScreen.txid)
}}
>
<FormattedMessage {...messages.transaction_success} />
</span>
</section>
</span>
)}
</div> </div>
</div> </Box>
</div> </div>
) )
} }
@ -185,11 +174,10 @@ Wallet.propTypes = {
network: PropTypes.object.isRequired, network: PropTypes.object.isRequired,
successTransactionScreen: PropTypes.object.isRequired, successTransactionScreen: PropTypes.object.isRequired,
settingsProps: PropTypes.object.isRequired, settingsProps: PropTypes.object.isRequired,
currentCurrencyFilters: PropTypes.array.isRequired, currencyFilters: PropTypes.array.isRequired,
currencyName: PropTypes.string.isRequired, currencyName: PropTypes.string.isRequired,
paymentTimeout: PropTypes.number.isRequired, paymentTimeout: PropTypes.number.isRequired,
setCurrency: PropTypes.func.isRequired, setCurrency: PropTypes.func.isRequired
setWalletCurrencyFilters: PropTypes.func.isRequired
} }
export default Wallet export default Wallet

169
app/components/Wallet/Wallet.scss

@ -3,176 +3,27 @@
.wallet { .wallet {
background: var(--lightBackground); background: var(--lightBackground);
color: var(--primaryText); color: var(--primaryText);
transition: background 0.25s; height: 180px;
height: 150px;
padding: 20px 40px; padding: 20px 40px;
} }
.header { .user {
display: flex; position: relative;
flex-direction: row; cursor: pointer;
justify-content: space-between; transition: all 0.25s;
.logo span {
line-height: 24px;
svg {
width: 64px;
height: 24px;
vertical-align: top;
}
}
.testnetPill {
margin-left: 10px;
font-size: 10px;
border-radius: 100px;
color: rgb(57, 230, 115);
}
.user {
position: relative;
cursor: pointer;
transition: all 0.25s;
.aliasText:hover {
opacity: 0.5;
}
}
}
.left,
.right {
display: inline-block;
vertical-align: top;
width: 50%;
height: 150px;
.leftContent, .aliasText:hover {
.rightContent { opacity: 0.5;
padding: 25px 0;
} }
} }
.leftContent { .qrCode {
display: flex; cursor: pointer;
flex-direction: row; svg {
.qrCode {
cursor: pointer;
}
.qrCode svg {
g { g {
fill: var(--gray); fill: var(--gray);
} }
} }
.details {
display: flex;
flex-direction: column;
justify-content: center;
h1 {
display: flex;
flex-direction: row;
span:nth-child(1) {
font-size: 24px;
line-height: 32px;
font-weight: 500;
margin-left: 10px;
margin-bottom: 5px;
letter-spacing: 1.5px;
}
span:nth-child(2) svg {
color: var(--primaryText);
width: 20px;
height: 32px;
opacity: 1;
margin-left: 5px;
cursor: pointer;
transition: all 0.25s;
&:hover {
opacity: 0.5;
}
}
.currency {
margin-left: 2.5px;
}
.currencyContainer {
position: relative;
display: inline-block;
svg {
width: 25px;
height: 32px;
color: var(--white);
}
ul {
visibility: hidden;
position: absolute;
top: 30px;
&.active {
visibility: visible;
}
li {
font-size: 12px;
padding: 0 15px;
background: var(--lightestBackground);
cursor: pointer;
transition: 0.25s hover;
&:hover {
background: var(--darkestBackground);
}
}
}
}
}
.tickerButtons {
display: flex;
flex-direction: row;
section {
margin: 5px;
font-size: 10px;
border-radius: 5px;
border: 1px solid var(--white);
padding: 5px 10px;
cursor: pointer;
opacity: 0.5;
transition: 0.25s all;
&.active {
background: $main;
color: $spaceborder;
border-color: $spaceborder;
opacity: 1;
}
}
}
}
svg {
font-size: 100px;
color: $main;
}
}
.rightContent {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: right;
} }
.notificationBox { .notificationBox {

7
app/containers/Activity.js

@ -20,7 +20,6 @@ import {
import { walletAddress, openWalletModal } from 'reducers/address' import { walletAddress, openWalletModal } from 'reducers/address'
import { setFormType } from 'reducers/form' import { setFormType } from 'reducers/form'
import { payFormSelectors } from 'reducers/payform' import { payFormSelectors } from 'reducers/payform'
import { setWalletCurrencyFilters } from 'reducers/info'
import { setSettingsOpen, setActiveSubMenu, disableSubMenu } from 'reducers/settings' import { setSettingsOpen, setActiveSubMenu, disableSubMenu } from 'reducers/settings'
import { setTheme, themeSelectors } from 'reducers/theme' import { setTheme, themeSelectors } from 'reducers/theme'
@ -47,7 +46,6 @@ const mapDispatchToProps = {
updateSearchActive, updateSearchActive,
updateSearchText, updateSearchText,
setFormType, setFormType,
setWalletCurrencyFilters,
setSettingsOpen, setSettingsOpen,
setActiveSubMenu, setActiveSubMenu,
disableSubMenu, disableSubMenu,
@ -76,7 +74,7 @@ const mapStateToProps = state => ({
invoiceModalOpen: invoiceSelectors.invoiceModalOpen(state), invoiceModalOpen: invoiceSelectors.invoiceModalOpen(state),
currentTicker: tickerSelectors.currentTicker(state), currentTicker: tickerSelectors.currentTicker(state),
currentCurrencyFilters: tickerSelectors.currentCurrencyFilters(state), currencyFilters: tickerSelectors.currencyFilters(state),
currencyName: tickerSelectors.currencyName(state), currencyName: tickerSelectors.currencyName(state),
@ -101,14 +99,13 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => ({
showPayLoadingScreen: stateProps.showPayLoadingScreen, showPayLoadingScreen: stateProps.showPayLoadingScreen,
showSuccessPayScreen: stateProps.payment.showSuccessPayScreen, showSuccessPayScreen: stateProps.payment.showSuccessPayScreen,
successTransactionScreen: stateProps.transaction.successTransactionScreen, successTransactionScreen: stateProps.transaction.successTransactionScreen,
currentCurrencyFilters: stateProps.currentCurrencyFilters, currencyFilters: stateProps.currencyFilters,
currencyName: stateProps.currencyName, currencyName: stateProps.currencyName,
network: stateProps.info.network, network: stateProps.info.network,
paymentTimeout: stateProps.payment.paymentTimeout, paymentTimeout: stateProps.payment.paymentTimeout,
theme: stateProps.currentTheme, theme: stateProps.currentTheme,
setCurrency: dispatchProps.setCurrency, setCurrency: dispatchProps.setCurrency,
setWalletCurrencyFilters: dispatchProps.setWalletCurrencyFilters,
walletAddress: dispatchProps.walletAddress, walletAddress: dispatchProps.walletAddress,
openReceiveModal: dispatchProps.openWalletModal, openReceiveModal: dispatchProps.openWalletModal,
openPayForm: () => dispatchProps.setFormType('PAY_FORM'), openPayForm: () => dispatchProps.setFormType('PAY_FORM'),

58
app/containers/App.js

@ -9,19 +9,8 @@ import { setCurrency, tickerSelectors, fetchTicker } from 'reducers/ticker'
import { closeWalletModal } from 'reducers/address' import { closeWalletModal } from 'reducers/address'
import { fetchInfo, infoSelectors } from 'reducers/info' import { fetchInfo, infoSelectors } from 'reducers/info'
import { setFormType } from 'reducers/form' import { setFormType } from 'reducers/form'
import { import { setPayAmount, setPayInput, updatePayErrors, payFormSelectors } from 'reducers/payform'
setPayAmount, import { setRequestAmount, setRequestMemo, requestFormSelectors } from 'reducers/requestform'
setPayInput,
setCurrencyFilters,
updatePayErrors,
payFormSelectors
} from 'reducers/payform'
import {
setRequestAmount,
setRequestMemo,
setRequestCurrencyFilters,
requestFormSelectors
} from 'reducers/requestform'
import { sendCoins } from 'reducers/transaction' import { sendCoins } from 'reducers/transaction'
import { payInvoice } from 'reducers/payment' import { payInvoice } from 'reducers/payment'
import { createInvoice, fetchInvoice } from 'reducers/invoice' import { createInvoice, fetchInvoice } from 'reducers/invoice'
@ -51,17 +40,12 @@ import {
updateContactCapacity, updateContactCapacity,
setNode, setNode,
contactFormSelectors, contactFormSelectors,
updateManualFormErrors, updateManualFormErrors
setContactsCurrencyFilters
} from 'reducers/contactsform' } from 'reducers/contactsform'
import { fetchBalance } from 'reducers/balance' import { fetchBalance } from 'reducers/balance'
import { fetchDescribeNetwork } from 'reducers/network' import { fetchDescribeNetwork } from 'reducers/network'
import { clearError } from 'reducers/error' import { clearError } from 'reducers/error'
import { import { hideActivityModal, activitySelectors } from 'reducers/activity'
hideActivityModal,
setActivityModalCurrencyFilters,
activitySelectors
} from 'reducers/activity'
import App from 'components/App' import App from 'components/App'
import withLoading from 'components/withLoading' import withLoading from 'components/withLoading'
@ -73,11 +57,9 @@ const mapDispatchToProps = {
setFormType, setFormType,
setPayAmount, setPayAmount,
setPayInput, setPayInput,
setCurrencyFilters,
updatePayErrors, updatePayErrors,
setRequestAmount, setRequestAmount,
setRequestMemo, setRequestMemo,
setRequestCurrencyFilters,
sendCoins, sendCoins,
payInvoice, payInvoice,
createInvoice, createInvoice,
@ -105,11 +87,9 @@ const mapDispatchToProps = {
setNode, setNode,
contactFormSelectors, contactFormSelectors,
updateManualFormErrors, updateManualFormErrors,
setContactsCurrencyFilters,
setChannelFormType, setChannelFormType,
fetchDescribeNetwork, fetchDescribeNetwork,
hideActivityModal, hideActivityModal
setActivityModalCurrencyFilters
} }
const mapStateToProps = state => ({ const mapStateToProps = state => ({
@ -142,7 +122,7 @@ const mapStateToProps = state => ({
currentTheme: themeSelectors.currentTheme(state), currentTheme: themeSelectors.currentTheme(state),
currentTicker: tickerSelectors.currentTicker(state), currentTicker: tickerSelectors.currentTicker(state),
currentCurrencyFilters: tickerSelectors.currentCurrencyFilters(state), currencyFilters: tickerSelectors.currencyFilters(state),
currencyName: tickerSelectors.currencyName(state), currencyName: tickerSelectors.currencyName(state),
isOnchain: payFormSelectors.isOnchain(state), isOnchain: payFormSelectors.isOnchain(state),
@ -186,12 +166,11 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
showPayLoadingScreen: stateProps.showPayLoadingScreen, showPayLoadingScreen: stateProps.showPayLoadingScreen,
payFormIsValid: stateProps.payFormIsValid, payFormIsValid: stateProps.payFormIsValid,
payInputMin: stateProps.payInputMin, payInputMin: stateProps.payInputMin,
currentCurrencyFilters: stateProps.currentCurrencyFilters, currencyFilters: stateProps.currencyFilters,
currencyName: stateProps.currencyName, currencyName: stateProps.currencyName,
setPayAmount: dispatchProps.setPayAmount, setPayAmount: dispatchProps.setPayAmount,
setPayInput: dispatchProps.setPayInput, setPayInput: dispatchProps.setPayInput,
setCurrencyFilters: dispatchProps.setCurrencyFilters,
fetchInvoice: dispatchProps.fetchInvoice, fetchInvoice: dispatchProps.fetchInvoice,
setCurrency: dispatchProps.setCurrency, setCurrency: dispatchProps.setCurrency,
@ -250,15 +229,13 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
requestform: stateProps.requestform, requestform: stateProps.requestform,
ticker: stateProps.ticker, ticker: stateProps.ticker,
currentCurrencyFilters: stateProps.currentCurrencyFilters, currencyFilters: stateProps.currencyFilters,
showCurrencyFilters: stateProps.showCurrencyFilters,
currencyName: stateProps.currencyName, currencyName: stateProps.currencyName,
requestFiatAmount: stateProps.requestFiatAmount, requestFiatAmount: stateProps.requestFiatAmount,
setRequestAmount: dispatchProps.setRequestAmount, setRequestAmount: dispatchProps.setRequestAmount,
setRequestMemo: dispatchProps.setRequestMemo, setRequestMemo: dispatchProps.setRequestMemo,
setCurrency: dispatchProps.setCurrency, setCurrency: dispatchProps.setCurrency,
setRequestCurrencyFilters: dispatchProps.setRequestCurrencyFilters,
onRequestSubmit: () => onRequestSubmit: () =>
dispatchProps.createInvoice( dispatchProps.createInvoice(
@ -349,16 +326,9 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
hideActivityModal: dispatchProps.hideActivityModal, hideActivityModal: dispatchProps.hideActivityModal,
toggleCurrencyProps: { toggleCurrencyProps: {
currentCurrencyFilters: stateProps.currentCurrencyFilters, currencyFilters: stateProps.currencyFilters,
currencyName: stateProps.currencyName, currencyName: stateProps.currencyName,
showCurrencyFilters: stateProps.activity.modal.showCurrencyFilters, setCurrency: dispatchProps.setCurrency
setActivityModalCurrencyFilters: dispatchProps.setActivityModalCurrencyFilters,
setCurrencyFilters: dispatchProps.setCurrencyFilters,
onCurrencyFilterClick: currency => {
dispatchProps.setCurrency(currency)
dispatchProps.setActivityModalCurrencyFilters(false)
}
} }
} }
@ -388,19 +358,15 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
ticker: stateProps.ticker, ticker: stateProps.ticker,
toggleCurrencyProps: { toggleCurrencyProps: {
currentCurrencyFilters: stateProps.currentCurrencyFilters, currencyFilters: stateProps.currencyFilters,
currencyName: stateProps.currencyName, currencyName: stateProps.currencyName,
showCurrencyFilters: stateProps.contactsform.showCurrencyFilters,
contactFormFiatAmount: stateProps.contactFormFiatAmount, contactFormFiatAmount: stateProps.contactFormFiatAmount,
setCurrency: dispatchProps.setCurrency,
setContactsCurrencyFilters: dispatchProps.setContactsCurrencyFilters,
setCurrencyFilters: dispatchProps.setCurrencyFilters,
onCurrencyFilterClick: currency => { onCurrencyFilterClick: currency => {
dispatchProps.updateContactCapacity( dispatchProps.updateContactCapacity(
btc.convert(stateProps.ticker.currency, currency, stateProps.contactsform.contactCapacity) btc.convert(stateProps.ticker.currency, currency, stateProps.contactsform.contactCapacity)
) )
dispatchProps.setCurrency(currency) dispatchProps.setCurrency(currency)
dispatchProps.setContactsCurrencyFilters(false)
} }
} }
} }

21
app/reducers/activity.js

@ -14,8 +14,7 @@ const initialState = {
], ],
modal: { modal: {
itemType: null, itemType: null,
itemId: null, itemId: null
showCurrencyFilters: false
}, },
searchActive: false, searchActive: false,
searchText: '', searchText: '',
@ -34,8 +33,6 @@ export const TOGGLE_PULLDOWN = 'TOGGLE_PULLDOWN'
export const TOGGLE_EXPIRED_REQUESTS = 'TOGGLE_EXPIRED_REQUESTS' export const TOGGLE_EXPIRED_REQUESTS = 'TOGGLE_EXPIRED_REQUESTS'
export const SET_ACTIVITY_MODAL_CURRENCY_FILTERS = 'SET_ACTIVITY_MODAL_CURRENCY_FILTERS'
export const UPDATE_SEARCH_ACTIVE = 'UPDATE_SEARCH_ACTIVE' export const UPDATE_SEARCH_ACTIVE = 'UPDATE_SEARCH_ACTIVE'
export const UPDATE_SEARCH_TEXT = 'UPDATE_SEARCH_TEXT' export const UPDATE_SEARCH_TEXT = 'UPDATE_SEARCH_TEXT'
@ -83,13 +80,6 @@ export function updateSearchText(searchText) {
} }
} }
export function setActivityModalCurrencyFilters(showCurrencyFilters) {
return {
type: SET_ACTIVITY_MODAL_CURRENCY_FILTERS,
showCurrencyFilters
}
}
export function toggleExpiredRequests() { export function toggleExpiredRequests() {
return { return {
type: TOGGLE_EXPIRED_REQUESTS type: TOGGLE_EXPIRED_REQUESTS
@ -112,15 +102,6 @@ const ACTION_HANDLERS = {
showExpiredRequests: !state.showExpiredRequests showExpiredRequests: !state.showExpiredRequests
}), }),
[SET_ACTIVITY_MODAL_CURRENCY_FILTERS]: (state, { showCurrencyFilters }) => ({
...state,
modal: {
itemType: state.modal.itemType,
itemId: state.modal.itemId,
showCurrencyFilters
}
}),
[UPDATE_SEARCH_ACTIVE]: (state, { searchActive }) => ({ ...state, searchActive }), [UPDATE_SEARCH_ACTIVE]: (state, { searchActive }) => ({ ...state, searchActive }),
[UPDATE_SEARCH_TEXT]: (state, { searchText }) => ({ ...state, searchText }) [UPDATE_SEARCH_TEXT]: (state, { searchText }) => ({ ...state, searchText })
} }

18
app/reducers/contactsform.js

@ -19,9 +19,7 @@ const initialState = {
}, },
manualFormOpen: false, manualFormOpen: false,
submitChannelFormOpen: false, submitChannelFormOpen: false
showCurrencyFilters: false
} }
// Constants // Constants
@ -50,8 +48,6 @@ export const UPDATE_MANUAL_FORM_ERRORS = 'UPDATE_MANUAL_FORM_ERRORS'
export const UPDATE_MANUAL_FORM_SEARCH_QUERY = 'UPDATE_MANUAL_FORM_SEARCH_QUERY' export const UPDATE_MANUAL_FORM_SEARCH_QUERY = 'UPDATE_MANUAL_FORM_SEARCH_QUERY'
export const SET_CONTACTS_CURRENCY_FILTERS = 'SET_CONTACTS_CURRENCY_FILTERS'
// ------------------------------------ // ------------------------------------
// Actions // Actions
// ------------------------------------ // ------------------------------------
@ -145,13 +141,6 @@ export function updateManualFormErrors(errorsObject) {
} }
} }
export function setContactsCurrencyFilters(showCurrencyFilters) {
return {
type: SET_CONTACTS_CURRENCY_FILTERS,
showCurrencyFilters
}
}
// ------------------------------------ // ------------------------------------
// Action Handlers // Action Handlers
// ------------------------------------ // ------------------------------------
@ -183,11 +172,6 @@ const ACTION_HANDLERS = {
[UPDATE_MANUAL_FORM_SEARCH_QUERY]: (state, { manualSearchQuery }) => ({ [UPDATE_MANUAL_FORM_SEARCH_QUERY]: (state, { manualSearchQuery }) => ({
...state, ...state,
manualSearchQuery manualSearchQuery
}),
[SET_CONTACTS_CURRENCY_FILTERS]: (state, { showCurrencyFilters }) => ({
...state,
showCurrencyFilters
}) })
} }

15
app/reducers/info.js

@ -8,7 +8,6 @@ import { walletAddress } from './address'
// ------------------------------------ // ------------------------------------
export const GET_INFO = 'GET_INFO' export const GET_INFO = 'GET_INFO'
export const RECEIVE_INFO = 'RECEIVE_INFO' export const RECEIVE_INFO = 'RECEIVE_INFO'
export const SET_WALLET_CURRENCY_FILTERS = 'SET_WALLET_CURRENCY_FILTERS'
export const SET_HAS_SYNCED = 'SET_HAS_SYNCED' export const SET_HAS_SYNCED = 'SET_HAS_SYNCED'
// ------------------------------------ // ------------------------------------
@ -20,13 +19,6 @@ export function getInfo() {
} }
} }
export function setWalletCurrencyFilters(showWalletCurrencyFilters) {
return {
type: SET_WALLET_CURRENCY_FILTERS,
showWalletCurrencyFilters
}
}
export const setHasSynced = hasSynced => { export const setHasSynced = hasSynced => {
return { return {
type: SET_HAS_SYNCED, type: SET_HAS_SYNCED,
@ -85,10 +77,6 @@ const ACTION_HANDLERS = {
infoLoading: false, infoLoading: false,
network: data.testnet ? networks.testnet : networks.mainnet, network: data.testnet ? networks.testnet : networks.mainnet,
data data
}),
[SET_WALLET_CURRENCY_FILTERS]: (state, { showWalletCurrencyFilters }) => ({
...state,
showWalletCurrencyFilters
}) })
} }
@ -99,8 +87,7 @@ const initialState = {
infoLoading: false, infoLoading: false,
hasSynced: undefined, hasSynced: undefined,
network: {}, network: {},
data: {}, data: {}
showWalletCurrencyFilters: false
} }
// Selectors // Selectors

17
app/reducers/payform.js

@ -18,8 +18,6 @@ const initialState = {
destination: '' destination: ''
}, },
showCurrencyFilters: false,
showErrors: { showErrors: {
amount: false, amount: false,
payInput: false payInput: false
@ -31,11 +29,7 @@ const initialState = {
export const SET_PAY_AMOUNT = 'SET_PAY_AMOUNT' export const SET_PAY_AMOUNT = 'SET_PAY_AMOUNT'
export const SET_PAY_INPUT = 'SET_PAY_INPUT' export const SET_PAY_INPUT = 'SET_PAY_INPUT'
export const SET_PAY_INVOICE = 'SET_PAY_INVOICE' export const SET_PAY_INVOICE = 'SET_PAY_INVOICE'
export const SET_PAY_CURRENCY_FILTERS = 'SET_PAY_CURRENCY_FILTERS'
export const UPDATE_PAY_ERRORS = 'UPDATE_PAY_ERRORS' export const UPDATE_PAY_ERRORS = 'UPDATE_PAY_ERRORS'
export const RESET_FORM = 'RESET_FORM' export const RESET_FORM = 'RESET_FORM'
// ------------------------------------ // ------------------------------------
@ -62,13 +56,6 @@ export function setPayInvoice(invoice) {
} }
} }
export function setCurrencyFilters(showCurrencyFilters) {
return {
type: SET_PAY_CURRENCY_FILTERS,
showCurrencyFilters
}
}
export function updatePayErrors(errorsObject) { export function updatePayErrors(errorsObject) {
return { return {
type: UPDATE_PAY_ERRORS, type: UPDATE_PAY_ERRORS,
@ -108,10 +95,6 @@ const ACTION_HANDLERS = {
invoice, invoice,
showErrors: Object.assign(state.showErrors, { amount: false }) showErrors: Object.assign(state.showErrors, { amount: false })
}), }),
[SET_PAY_CURRENCY_FILTERS]: (state, { showCurrencyFilters }) => ({
...state,
showCurrencyFilters
}),
[UPDATE_PAY_ERRORS]: (state, { errorsObject }) => ({ [UPDATE_PAY_ERRORS]: (state, { errorsObject }) => ({
...state, ...state,

18
app/reducers/requestform.js

@ -5,8 +5,7 @@ import { tickerSelectors } from './ticker'
// Initial State // Initial State
const initialState = { const initialState = {
amount: '', amount: '',
memo: '', memo: ''
showCurrencyFilters: false
} }
// Constants // Constants
@ -14,9 +13,6 @@ const initialState = {
export const SET_REQUEST_AMOUNT = 'SET_REQUEST_AMOUNT' export const SET_REQUEST_AMOUNT = 'SET_REQUEST_AMOUNT'
export const SET_REQUEST_MEMO = 'SET_REQUEST_MEMO' export const SET_REQUEST_MEMO = 'SET_REQUEST_MEMO'
export const SET_PAY_INVOICE = 'SET_PAY_INVOICE' export const SET_PAY_INVOICE = 'SET_PAY_INVOICE'
export const SET_REQUEST_CURRENCY_FILTERS = 'SET_REQUEST_CURRENCY_FILTERS'
export const RESET_FORM = 'RESET_FORM' export const RESET_FORM = 'RESET_FORM'
// ------------------------------------ // ------------------------------------
@ -42,24 +38,12 @@ export function resetRequestForm() {
} }
} }
export function setRequestCurrencyFilters(showCurrencyFilters) {
return {
type: SET_REQUEST_CURRENCY_FILTERS,
showCurrencyFilters
}
}
// ------------------------------------ // ------------------------------------
// Action Handlers // Action Handlers
// ------------------------------------ // ------------------------------------
const ACTION_HANDLERS = { const ACTION_HANDLERS = {
[SET_REQUEST_AMOUNT]: (state, { amount }) => ({ ...state, amount }), [SET_REQUEST_AMOUNT]: (state, { amount }) => ({ ...state, amount }),
[SET_REQUEST_MEMO]: (state, { memo }) => ({ ...state, memo }), [SET_REQUEST_MEMO]: (state, { memo }) => ({ ...state, memo }),
[SET_REQUEST_CURRENCY_FILTERS]: (state, { showCurrencyFilters }) => ({
...state,
showCurrencyFilters
}),
[RESET_FORM]: () => initialState [RESET_FORM]: () => initialState
} }

36
app/reducers/ticker.js

@ -92,13 +92,14 @@ const ACTION_HANDLERS = {
// Selectors // Selectors
const tickerSelectors = {} const tickerSelectors = {}
const cryptoSelector = state => state.ticker.crypto const cryptoSelector = state => state.ticker.crypto
const currencyFiltersSelector = state => state.ticker.currencyFilters
const currencySelector = state => state.ticker.currency const currencySelector = state => state.ticker.currency
const currencyFiltersSelector = state => state.ticker.currencyFilters
const bitcoinTickerSelector = state => state.ticker.btcTicker const bitcoinTickerSelector = state => state.ticker.btcTicker
const litecoinTickerSelector = state => state.ticker.ltcTicker const litecoinTickerSelector = state => state.ticker.ltcTicker
const tickerLoading = state => state.ticker.tickerLoading const tickerLoadingSelector = state => state.ticker.tickerLoading
tickerSelectors.tickerLoading = tickerLoading tickerSelectors.currency = currencySelector
tickerSelectors.tickerLoading = tickerLoadingSelector
tickerSelectors.currentTicker = createSelector( tickerSelectors.currentTicker = createSelector(
cryptoSelector, cryptoSelector,
@ -107,25 +108,30 @@ tickerSelectors.currentTicker = createSelector(
(crypto, btcTicker, ltcTicker) => (crypto === 'btc' ? btcTicker : ltcTicker) (crypto, btcTicker, ltcTicker) => (crypto === 'btc' ? btcTicker : ltcTicker)
) )
tickerSelectors.currentCurrencyFilters = createSelector( tickerSelectors.currencyFilters = createSelector(
currencySelector, infoSelectors.networkSelector,
currencyFiltersSelector, currencyFiltersSelector,
(currency, filters) => filters.filter(f => f.key !== currency) (network, currencyFilters = []) => {
if (!network || !network.unitPrefix) {
return currencyFilters
}
return currencyFilters.map(item => {
item.name = `${network.unitPrefix}${item.name}`
return item
})
}
) )
tickerSelectors.currencyName = createSelector( tickerSelectors.currencyName = createSelector(
currencySelector, currencySelector,
infoSelectors.networkSelector, tickerSelectors.currencyFilters,
(currency, network) => { (currency, currencyFilters = []) => {
let unit = currency let unit = currency
if (currency === 'btc') { const selectedCurrency = currencyFilters.find(c => c.key === currency)
unit = 'BTC' if (selectedCurrency) {
unit = selectedCurrency.name
} }
if (currency === 'sats') { return unit
unit = 'satoshis'
}
return `${network.unitPrefix}${unit}`
} }
) )

6
app/themes/dark.js

@ -17,6 +17,9 @@ const buttons = {
color: colors.lightningOrange, color: colors.lightningOrange,
'&:hover:enabled': { '&:hover:enabled': {
backgroundColor: colors.highlight backgroundColor: colors.highlight
},
'&:focus': {
backgroundColor: colors.highlight
} }
}, },
primary: { primary: {
@ -28,6 +31,9 @@ const buttons = {
color: colors.white, color: colors.white,
'&:hover:enabled': { '&:hover:enabled': {
color: colors.lightningOrange color: colors.lightningOrange
},
'&:focus': {
color: colors.lightningOrange
} }
} }
} }

6
app/themes/light.js

@ -17,6 +17,9 @@ const buttons = {
color: colors.lightningOrange, color: colors.lightningOrange,
'&:hover:enabled': { '&:hover:enabled': {
backgroundColor: colors.highlight backgroundColor: colors.highlight
},
'&:focus': {
backgroundColor: colors.highlight
} }
}, },
primary: { primary: {
@ -28,6 +31,9 @@ const buttons = {
color: colors.lightningOrange, color: colors.lightningOrange,
'&:hover:enabled': { '&:hover:enabled': {
color: colors.black color: colors.black
},
'&:focus': {
color: colors.black
} }
} }
} }

1
package.json

@ -211,6 +211,7 @@
"@babel/register": "^7.0.0", "@babel/register": "^7.0.0",
"@commitlint/cli": "^7.2.1", "@commitlint/cli": "^7.2.1",
"@commitlint/config-conventional": "^7.1.2", "@commitlint/config-conventional": "^7.1.2",
"@sambego/storybook-state": "^1.3.1",
"@storybook/addon-actions": "^4.0.2", "@storybook/addon-actions": "^4.0.2",
"@storybook/addon-console": "^1.1.0", "@storybook/addon-console": "^1.1.0",
"@storybook/addon-info": "^4.0.2", "@storybook/addon-info": "^4.0.2",

58
stories/components/dropdown.stories.js

@ -0,0 +1,58 @@
import React from 'react'
import { storiesOf } from '@storybook/react'
import { StateDecorator, Store } from '@sambego/storybook-state'
import Dropdown from 'components/UI/Dropdown'
const store = new Store({
crypto: 'btc',
fiat: 'usd',
cryptoCurrencies: [
{
key: 'btc',
name: 'BTC'
},
{
key: 'bits',
name: 'bits'
},
{
key: 'sats',
name: 'satoshis'
}
],
fiatCurrencies: [
{
key: 'usd',
name: 'USD'
},
{
key: 'eur',
name: 'EUR'
},
{
key: 'gbp',
name: 'GBP'
}
]
})
storiesOf('Components.Dropdown', module)
.addDecorator(StateDecorator(store))
.add('Crypto', () => {
return (
<Dropdown
activeKey={store.get('crypto')}
items={store.get('cryptoCurrencies')}
onChange={crypto => store.set({ crypto })}
/>
)
})
.add('Fiat', () => {
return (
<Dropdown
activeKey={store.get('fiat')}
items={store.get('fiatCurrencies')}
onChange={fiat => store.set({ fiat })}
/>
)
})

7
test/unit/components/Form.spec.js

@ -29,12 +29,11 @@ const payFormProps = {
inputCaption: '', inputCaption: '',
showPayLoadingScreen: true, showPayLoadingScreen: true,
payFormIsValid: {}, payFormIsValid: {},
currentCurrencyFilters: [], currencyFilters: [],
currencyName: '', currencyName: '',
setPayAmount: () => {}, setPayAmount: () => {},
setPayInput: () => {}, setPayInput: () => {},
setCurrencyFilters: () => {},
fetchInvoice: () => {}, fetchInvoice: () => {},
setCurrency: () => {}, setCurrency: () => {},
@ -49,15 +48,13 @@ const requestFormProps = {
requestform: {}, requestform: {},
ticker: {}, ticker: {},
currentCurrencyFilters: [], currencyFilters: [],
showCurrencyFilters: true,
currencyName: '', currencyName: '',
requestFiatAmount: '', requestFiatAmount: '',
setRequestAmount: () => {}, setRequestAmount: () => {},
setRequestMemo: () => {}, setRequestMemo: () => {},
setCurrency: () => {}, setCurrency: () => {},
setRequestCurrencyFilters: () => {},
onRequestSubmit: () => {} onRequestSubmit: () => {}
} }

24
test/unit/components/Form/Pay.spec.js

@ -2,8 +2,9 @@ import React from 'react'
import { configure } from 'enzyme' import { configure } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16' import Adapter from 'enzyme-adapter-react-16'
import 'jest-styled-components' import 'jest-styled-components'
import { ThemeProvider } from 'styled-components'
import Pay from 'components/Form/Pay' import Pay from 'components/Form/Pay'
import { dark as theme } from 'themes' import { dark } from 'themes'
import { mountWithIntl } from '../../__helpers__/intl-enzyme-test-helper' import { mountWithIntl } from '../../__helpers__/intl-enzyme-test-helper'
configure({ adapter: new Adapter() }) configure({ adapter: new Adapter() })
@ -30,12 +31,11 @@ const defaultProps = {
inputCaption: '', inputCaption: '',
showPayLoadingScreen: true, showPayLoadingScreen: true,
payFormIsValid: {}, payFormIsValid: {},
currentCurrencyFilters: [], currencyFilters: [],
currencyName: '', currencyName: '',
setPayAmount: () => {}, setPayAmount: () => {},
setPayInput: () => {}, setPayInput: () => {},
setCurrencyFilters: () => {},
fetchInvoice: () => {}, fetchInvoice: () => {},
setCurrency: () => {}, setCurrency: () => {},
@ -48,7 +48,11 @@ const defaultProps = {
describe('Form', () => { describe('Form', () => {
describe('should show the form without an input', () => { describe('should show the form without an input', () => {
const el = mountWithIntl(<Pay {...defaultProps} theme={theme} />) const el = mountWithIntl(
<ThemeProvider theme={dark}>
<Pay {...defaultProps} />
</ThemeProvider>
)
it('should contain Pay', () => { it('should contain Pay', () => {
expect(el.find('input#paymentRequest').props.value).toBe(undefined) expect(el.find('input#paymentRequest').props.value).toBe(undefined)
@ -57,7 +61,11 @@ describe('Form', () => {
describe('should show lightning with a lightning input', () => { describe('should show lightning with a lightning input', () => {
const props = { ...defaultProps, isLn: true } const props = { ...defaultProps, isLn: true }
const el = mountWithIntl(<Pay {...props} theme={theme} />) const el = mountWithIntl(
<ThemeProvider theme={dark}>
<Pay {...props} />
</ThemeProvider>
)
it('should contain Pay', () => { it('should contain Pay', () => {
expect(el.find('input#paymentRequest').props.value).toBe(undefined) expect(el.find('input#paymentRequest').props.value).toBe(undefined)
@ -66,7 +74,11 @@ describe('Form', () => {
describe('should show on-chain with an on-chain input', () => { describe('should show on-chain with an on-chain input', () => {
const props = { ...defaultProps, isOnchain: true } const props = { ...defaultProps, isOnchain: true }
const el = mountWithIntl(<Pay {...props} theme={theme} />) const el = mountWithIntl(
<ThemeProvider theme={dark}>
<Pay {...props} />
</ThemeProvider>
)
it('should contain Pay', () => { it('should contain Pay', () => {
expect(el.find('input#paymentRequest').props.value).toBe(undefined) expect(el.find('input#paymentRequest').props.value).toBe(undefined)

14
test/unit/components/Form/Request.spec.js

@ -1,9 +1,9 @@
import React from 'react' import React from 'react'
import { configure } from 'enzyme' import { configure } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16' import Adapter from 'enzyme-adapter-react-16'
import { ThemeProvider } from 'styled-components'
import Request from 'components/Form/Request' import Request from 'components/Form/Request'
import { dark } from 'themes'
import { mountWithIntl } from '../../__helpers__/intl-enzyme-test-helper' import { mountWithIntl } from '../../__helpers__/intl-enzyme-test-helper'
configure({ adapter: new Adapter() }) configure({ adapter: new Adapter() })
@ -15,15 +15,13 @@ const defaultProps = {
fiatTicker: 'USD' fiatTicker: 'USD'
}, },
currentCurrencyFilters: [], currencyFilters: [],
showCurrencyFilters: true,
currencyName: '', currencyName: '',
requestFiatAmount: '', requestFiatAmount: '',
setRequestAmount: () => {}, setRequestAmount: () => {},
setRequestMemo: () => {}, setRequestMemo: () => {},
setCurrency: () => {}, setCurrency: () => {},
setRequestCurrencyFilters: () => {},
onRequestSubmit: () => {} onRequestSubmit: () => {}
} }
@ -31,7 +29,11 @@ const defaultProps = {
describe('Form', () => { describe('Form', () => {
describe('should show request form when formType is REQUEST_FORM', () => { describe('should show request form when formType is REQUEST_FORM', () => {
const props = { ...defaultProps } const props = { ...defaultProps }
const el = mountWithIntl(<Request {...props} />) const el = mountWithIntl(
<ThemeProvider theme={dark}>
<Request {...props} />
</ThemeProvider>
)
it('should contain Request', () => { it('should contain Request', () => {
expect(el.contains('Request Payment')).toBe(true) expect(el.contains('Request Payment')).toBe(true)
}) })

30
test/unit/components/UI/Dropdown.spec.js

@ -0,0 +1,30 @@
import React from 'react'
import Dropdown from 'components/UI/Dropdown'
import renderer from 'react-test-renderer'
import { dark } from 'themes'
const currencies = [
{
key: 'btc',
name: 'BTC'
},
{
key: 'bits',
name: 'bits'
},
{
key: 'sats',
name: 'satoshis'
}
]
const setCurrency = jest.fn()
describe('component.Dropdown', () => {
it('should render correctly', () => {
const tree = renderer
.create(<Dropdown theme={dark} activeKey="btc" items={currencies} onClick={setCurrency} />)
.toJSON()
expect(tree).toMatchSnapshot()
})
})

4
test/unit/components/UI/__snapshots__/Button.spec.js.snap

@ -33,10 +33,6 @@ exports[`component.UI.Button should render correctly 1`] = `
line-height: '18px'; line-height: '18px';
} }
.c0:focus {
box-shadow: 0 0 3px;
}
.c0:disabled { .c0:disabled {
opacity: 0.5; opacity: 0.5;
} }

81
test/unit/components/UI/__snapshots__/Dropdown.spec.js.snap

@ -0,0 +1,81 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`component.Dropdown should render correctly 1`] = `
.c2 {
font-size: m;
text-align: left;
}
.c0 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-wrap: none;
-ms-flex-wrap: none;
flex-wrap: none;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
}
.c1 {
margin: 0px;
padding-left: 0px;
padding-right: 0px;
padding-top: 8px;
padding-bottom: 8px;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
display: inline-block;
text-align: center;
line-height: inherit;
-webkit-text-decoration: none;
text-decoration: none;
border: none;
outline: none;
background: transparent;
color: inherit;
cursor: pointer;
}
<div
className="c0"
display="relative"
onClick={[MockFunction]}
>
<button
className="c1"
onClick={[Function]}
type="button"
>
<div
className="c2"
fontSize="m"
>
BTC
<svg
fill="currentColor"
height="1em"
preserveAspectRatio="xMidYMid meet"
style={
Object {
"color": undefined,
"verticalAlign": "middle",
}
}
viewBox="0 0 40 40"
width="1em"
>
<g>
<path
d="m31 16.4q0 0.3-0.2 0.5l-10.4 10.4q-0.3 0.3-0.5 0.3t-0.6-0.3l-10.4-10.4q-0.2-0.2-0.2-0.5t0.2-0.5l1.2-1.1q0.2-0.2 0.5-0.2t0.5 0.2l8.8 8.8 8.7-8.8q0.3-0.2 0.5-0.2t0.6 0.2l1.1 1.1q0.2 0.2 0.2 0.5z"
/>
</g>
</svg>
</div>
</button>
</div>
`;

7
test/unit/components/UI/__snapshots__/Page.spec.js.snap

@ -2,11 +2,11 @@
exports[`component.UI.Page should render correctly 1`] = ` exports[`component.UI.Page should render correctly 1`] = `
.c0 { .c0 {
width: 950; background-color: darkestBackground;
background-color: white;
height: 600px;
min-height: 700px; min-height: 700px;
min-width: 950px; min-width: 950px;
overflow-y: hidden;
box-shadow: 0 3px 4px 0 rgba(30,30,30,0.5);
display: -webkit-box; display: -webkit-box;
display: -webkit-flex; display: -webkit-flex;
display: -ms-flexbox; display: -ms-flexbox;
@ -19,6 +19,5 @@ exports[`component.UI.Page should render correctly 1`] = `
<article <article
className="c0" className="c0"
width="950"
/> />
`; `;

40
test/unit/reducers/__snapshots__/activity.spec.js.snap

@ -25,7 +25,6 @@ Object {
"modal": Object { "modal": Object {
"itemId": null, "itemId": null,
"itemType": null, "itemType": null,
"showCurrencyFilters": false,
}, },
"searchActive": false, "searchActive": false,
"searchText": "", "searchText": "",
@ -68,42 +67,6 @@ Object {
} }
`; `;
exports[`reducers activityReducer should correctly setActivityModalCurrencyFilters 1`] = `
Object {
"filter": Object {
"key": "ALL_ACTIVITY",
"name": "All Activity",
},
"filterPulldown": false,
"filters": Array [
Object {
"key": "ALL_ACTIVITY",
"name": "all",
},
Object {
"key": "SENT_ACTIVITY",
"name": "sent",
},
Object {
"key": "REQUESTED_ACTIVITY",
"name": "requested",
},
Object {
"key": "PENDING_ACTIVITY",
"name": "pending",
},
],
"modal": Object {
"itemId": null,
"itemType": null,
"showCurrencyFilters": undefined,
},
"searchActive": false,
"searchText": "",
"showExpiredRequests": false,
}
`;
exports[`reducers activityReducer should correctly showActivityModal 1`] = ` exports[`reducers activityReducer should correctly showActivityModal 1`] = `
Object { Object {
"filter": Object { "filter": Object {
@ -167,7 +130,6 @@ Object {
"modal": Object { "modal": Object {
"itemId": null, "itemId": null,
"itemType": null, "itemType": null,
"showCurrencyFilters": false,
}, },
"searchActive": false, "searchActive": false,
"searchText": "", "searchText": "",
@ -203,7 +165,6 @@ Object {
"modal": Object { "modal": Object {
"itemId": null, "itemId": null,
"itemType": null, "itemType": null,
"showCurrencyFilters": false,
}, },
"searchActive": undefined, "searchActive": undefined,
"searchText": "", "searchText": "",
@ -239,7 +200,6 @@ Object {
"modal": Object { "modal": Object {
"itemId": null, "itemId": null,
"itemType": null, "itemType": null,
"showCurrencyFilters": false,
}, },
"searchActive": false, "searchActive": false,
"searchText": undefined, "searchText": undefined,

3
test/unit/reducers/__snapshots__/info.spec.js.snap

@ -6,7 +6,6 @@ Object {
"hasSynced": undefined, "hasSynced": undefined,
"infoLoading": true, "infoLoading": true,
"network": Object {}, "network": Object {},
"showWalletCurrencyFilters": false,
} }
`; `;
@ -32,7 +31,6 @@ Object {
"name": null, "name": null,
"unitPrefix": "", "unitPrefix": "",
}, },
"showWalletCurrencyFilters": false,
} }
`; `;
@ -42,6 +40,5 @@ Object {
"hasSynced": undefined, "hasSynced": undefined,
"infoLoading": false, "infoLoading": false,
"network": Object {}, "network": Object {},
"showWalletCurrencyFilters": false,
} }
`; `;

11
test/unit/reducers/activity.spec.js

@ -3,7 +3,6 @@ import activityReducer, {
HIDE_ACTIVITY_MODAL, HIDE_ACTIVITY_MODAL,
CHANGE_FILTER, CHANGE_FILTER,
TOGGLE_PULLDOWN, TOGGLE_PULLDOWN,
SET_ACTIVITY_MODAL_CURRENCY_FILTERS,
UPDATE_SEARCH_ACTIVE, UPDATE_SEARCH_ACTIVE,
UPDATE_SEARCH_TEXT UPDATE_SEARCH_TEXT
} from 'reducers/activity' } from 'reducers/activity'
@ -26,10 +25,6 @@ describe('reducers', () => {
expect(TOGGLE_PULLDOWN).toEqual('TOGGLE_PULLDOWN') expect(TOGGLE_PULLDOWN).toEqual('TOGGLE_PULLDOWN')
}) })
it('should have SET_ACTIVITY_MODAL_CURRENCY_FILTERS', () => {
expect(SET_ACTIVITY_MODAL_CURRENCY_FILTERS).toEqual('SET_ACTIVITY_MODAL_CURRENCY_FILTERS')
})
it('should have UPDATE_SEARCH_ACTIVE', () => { it('should have UPDATE_SEARCH_ACTIVE', () => {
expect(UPDATE_SEARCH_ACTIVE).toEqual('UPDATE_SEARCH_ACTIVE') expect(UPDATE_SEARCH_ACTIVE).toEqual('UPDATE_SEARCH_ACTIVE')
}) })
@ -58,12 +53,6 @@ describe('reducers', () => {
).toMatchSnapshot() ).toMatchSnapshot()
}) })
it('should correctly setActivityModalCurrencyFilters', () => {
expect(
activityReducer(undefined, { type: SET_ACTIVITY_MODAL_CURRENCY_FILTERS })
).toMatchSnapshot()
})
it('should correctly updateSearchActive', () => { it('should correctly updateSearchActive', () => {
expect(activityReducer(undefined, { type: UPDATE_SEARCH_ACTIVE })).toMatchSnapshot() expect(activityReducer(undefined, { type: UPDATE_SEARCH_ACTIVE })).toMatchSnapshot()
}) })

9
yarn.lock

@ -1101,6 +1101,13 @@
dependencies: dependencies:
styled-system "^3.0.1" styled-system "^3.0.1"
"@sambego/storybook-state@^1.3.1":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@sambego/storybook-state/-/storybook-state-1.3.1.tgz#9aec5f8e10e9df3f689eb70eff6903d41d9ce2a7"
integrity sha512-JFnu/AuAcpk8trsxUweFUGRF92a/qpg8ZpAclusOVs5jp7XvhiEsJehqGlqueytZpZyzFgTkla8Mjh/D98FaXQ==
dependencies:
uuid "^3.1.0"
"@samverschueren/stream-to-observable@^0.3.0": "@samverschueren/stream-to-observable@^0.3.0":
version "0.3.0" version "0.3.0"
resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz#ecdf48d532c58ea477acfcab80348424f8d0662f" resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz#ecdf48d532c58ea477acfcab80348424f8d0662f"
@ -16369,7 +16376,7 @@ uuid@3.2.1:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14"
integrity sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA== integrity sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==
uuid@^3.0.1, uuid@^3.2.1, uuid@^3.3.2: uuid@^3.0.1, uuid@^3.1.0, uuid@^3.2.1, uuid@^3.3.2:
version "3.3.2" version "3.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==

Loading…
Cancel
Save