Browse Source

feature(header, activity): new activity and header

renovate/lint-staged-8.x
Jack Mallers 7 years ago
parent
commit
907b81da8c
  1. 50
      app/components/Wallet/Wallet.js
  2. 110
      app/components/Wallet/Wallet.scss
  3. 16
      app/icons/bitcoin.svg
  4. 1
      app/icons/check_circle.svg
  5. 1
      app/icons/clock.svg
  6. 27
      app/icons/qrcode.svg
  7. 16
      app/icons/zap_logo.svg
  8. 3
      app/main.dev.js
  9. 48
      app/reducers/activity.js
  10. 50
      app/routes/activity/components/Activity.js
  11. 99
      app/routes/activity/components/Activity.scss
  12. 79
      app/routes/activity/components/components/Activity.scss
  13. 34
      app/routes/activity/components/components/Invoice/Invoice.js
  14. 16
      app/routes/activity/components/components/Payment/Payment.js
  15. 16
      app/routes/activity/components/components/Transaction/Transaction.js
  16. 21
      app/routes/activity/containers/ActivityContainer.js
  17. 11
      app/routes/app/components/App.js
  18. 2
      app/routes/app/components/App.scss
  19. 4
      app/routes/app/containers/AppContainer.js
  20. 3
      app/utils/btc.js
  21. 5
      app/variables.scss

50
app/components/Wallet/Wallet.js

@ -1,9 +1,11 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { FaQrcode } from 'react-icons/lib/fa'
import { FaQrcode, FaAngleDown } from 'react-icons/lib/fa'
import Isvg from 'react-inlinesvg'
import { btc } from 'utils'
import skinnyBitcoinIcon from 'icons/skinny_bitcoin.svg'
import bitcoinIcon from 'icons/bitcoin.svg'
import zapLogo from 'icons/zap_logo.svg'
import qrCode from 'icons/qrcode.svg'
import ReceiveModal from './ReceiveModal'
import styles from './Wallet.scss'
@ -23,10 +25,14 @@ class Wallet extends Component {
balance,
address,
info,
newAddress
newAddress,
currentTicker,
openPayForm,
openRequestForm
} = this.props
const { modalOpen, qrCodeType } = this.state
const usdAmount = parseFloat(btc.satoshisToUsd(balance.walletBalance, currentTicker.price_usd)).toLocaleString()
const changeQrCode = () => {
const qrCodeNum = this.state.qrCodeType === 1 ? 2 : 1
@ -51,22 +57,39 @@ class Wallet extends Component {
)
}
<div className={styles.content}>
<header className={styles.header}>
<section className={styles.logo}>
<Isvg className={styles.bitcoinLogo} src={zapLogo} />
</section>
<section className={styles.user}>
<div>
<span>{info.data.alias}</span>
<FaAngleDown />
</div>
</section>
</header>
<div className={styles.left}>
<div className={styles.leftContent}>
<Isvg className={styles.bitcoinLogo} src={skinnyBitcoinIcon} />
<Isvg className={styles.bitcoinLogo} src={bitcoinIcon} />
<div className={styles.details}>
<h1>{btc.satoshisToBtc(parseFloat(balance.walletBalance) + parseFloat(balance.channelBalance))} BTC</h1>
<span>{btc.satoshisToBtc(balance.walletBalance)} available</span>
<span>{btc.satoshisToBtc(balance.channelBalance)} in channels</span>
<h1>
<span>
{btc.satoshisToBtc(parseFloat(balance.walletBalance) + parseFloat(balance.channelBalance))}BTC
</span>
<span onClick={() => this.setState({ modalOpen: true })}>
<Isvg className={styles.bitcoinLogo} src={qrCode} />
</span>
</h1>
<span className={styles.usdValue}> ${usdAmount}</span>
</div>
</div>
</div>
<div className={styles.right}>
<div className={styles.rightContent}>
<div className={`buttonPrimary ${styles.addressButton}`} onClick={() => this.setState({ modalOpen: true })}>
<FaQrcode />
Address
</div>
<div className={styles.pay} onClick={openPayForm}>Pay</div>
<div className={styles.request} onClick={openRequestForm}>Request</div>
</div>
</div>
</div>
@ -79,7 +102,10 @@ Wallet.propTypes = {
balance: PropTypes.object.isRequired,
address: PropTypes.string.isRequired,
info: PropTypes.object.isRequired,
newAddress: PropTypes.func.isRequired
newAddress: PropTypes.func.isRequired,
currentTicker: PropTypes.object.isRequired,
openPayForm: PropTypes.func.isRequired,
openRequestForm: PropTypes.func.isRequired
}
export default Wallet

110
app/components/Wallet/Wallet.scss

@ -1,10 +1,31 @@
@import '../../variables.scss';
.wallet {
cursor: pointer;
background: $lightgrey;
background: $bluegrey;
color: $white;
transition: background 0.25s;
height: 150px;
padding: 20px 40px;
}
.header {
display: flex;
flex-direction: row;
justify-content: space-between;
.logo span svg {
width: 64px;
height: 24px;
}
.user {
cursor: pointer;
transition: all 0.25s;
&:hover {
opacity: 0.5;
}
}
}
.left, .right {
@ -14,7 +35,7 @@
height: 150px;
.leftContent, .rightContent {
padding: 25px;
padding: 25px 0;
}
}
@ -23,8 +44,8 @@
flex-direction: row;
.bitcoinLogo svg {
width: 100px;
height: 100px;
width: 32px;
height: 32px;
}
.details {
@ -33,14 +54,37 @@
justify-content: center;
h1 {
font-size: 24px;
font-weight: bold;
margin-bottom: 10px;
letter-spacing: 1.5px;
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: $white;
width: 20px;
height: 32px;
opacity: 1;
margin-left: 5px;
cursor: pointer;
transition: all 0.25s;
&:hover {
opacity: 0.5;
}
}
}
span {
margin: 2.5px 0;
.usdValue {
font-size: 12px;
margin-left: 10px;
font-style: italic;
}
}
@ -56,42 +100,24 @@
justify-content: flex-end;
align-items: right;
.addressButton {
box-shadow: none;
.pay, .request {
font-size: 16px;
font-weight: bold;
color: $white;
background: $spaceblue;
padding: 15px;
width: 100px;
text-align: center;
border-radius: 5px;
cursor: pointer;
transition: all 0.25s;
padding-top: 12px;
padding-bottom: 10px;
font-size: 14px;
&:hover {
background: darken($main, 10%);
}
span {
display: inline-block;
vertical-align: top;
&:nth-child(1) svg {
width: 14px;
height: 14px;
margin-right: 5px;
}
}
}
div {
padding: 7px 20px;
background: $main;
transition: background 0.25s;
color: $black;
&:hover {
background: darken($main, 10%);
opacity: 0.5;
}
svg {
font-size: 35px;
margin-right: 10px;
&:nth-child(1) {
margin-right: 20px;
}
}
}

16
app/icons/bitcoin.svg

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="32px" height="33px" viewBox="0 0 32 33" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 48.2 (47327) - http://www.bohemiancoding.com/sketch -->
<title>Bitcoin</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Pay-Hover-Copy" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" transform="translate(-56.000000, -92.000000)">
<g id="Group" transform="translate(56.000000, 90.000000)" fill="#F5B300">
<g id="Bitcoin" transform="translate(0.000000, 2.000000)">
<g id="btc">
<path d="M15.85,32.1 C7.09628672,32.1 0,25.0037133 0,16.25 C0,7.49628672 7.09628672,0.4 15.85,0.4 C24.6037133,0.4 31.7,7.49628672 31.7,16.25 C31.7,25.0037133 24.6037133,32.1 15.85,32.1 Z M11.55,8.15 C11.5,8.2 11.5,8.2 11.7,8.05 C11.55,8.6 11.4,9.2 11.25,9.75 C11.2,9.85 11.25,9.9 11.35,9.9 C11.75,10 12.2,10.1 12.65,10.25 C13.1,10.4 13.35,10.85 13.25,11.25 C12.65,13.85 12,16.4 11.35,18.95 C11.3,19.3 11,19.5 10.6,19.4 C10.25,19.35 9.85,19.25 9.5,19.15 C9.35,19.15 9.3,19.15 9.25,19.3 C9.1,19.7 8.9,20.15 8.7,20.6 C8.6,20.8 8.55,20.95 8.45,21.15 C9.65,21.45 10.8,21.75 11.95,22.05 C11.95,22.15 11.9,22.2 11.9,22.25 C11.65,23.05 11.45,23.9 11.25,24.75 C11.2,24.85 11.2,24.9 11.35,24.95 C11.85,25.05 12.35,25.15 12.85,25.3 C13,25.35 13,25.3 13.05,25.2 C13.15,24.75 13.3,24.3 13.4,23.85 C13.5,23.4 13.65,22.95 13.75,22.5 C14.2,22.6 14.6,22.7 15,22.8 C15.1,22.85 15.05,22.9 15.05,23 C14.8,23.8 14.6,24.65 14.4,25.5 C14.35,25.6 14.35,25.65 14.5,25.7 C14.95,25.8 15.45,25.95 15.9,26.05 C16.15,26.15 16.15,26.1 16.2,25.9 C16.4,25.1 16.6,24.25 16.8,23.45 C16.85,23.3 16.95,23.25 17.1,23.3 C18.1,23.45 19.1,23.55 20.15,23.4 C20.95,23.3 21.65,22.95 22.2,22.3 C22.65,21.75 22.9,21.15 23.1,20.45 C23.25,19.9 23.3,19.3 23.2,18.75 C23,18.05 22.6,17.5 22,17.05 C21.8,16.9 21.6,16.8 21.4,16.65 C21.5,16.65 21.55,16.6 21.6,16.6 C22,16.45 22.4,16.25 22.7,15.95 C23.1,15.55 23.3,15.05 23.45,14.5 C23.65,13.7 23.6,12.9 23.15,12.15 C22.8,11.65 22.35,11.25 21.85,10.95 C21.3,10.7 20.75,10.45 20.2,10.2 C20.05,10.15 20,10.1 20.05,9.95 C20.15,9.7 20.2,9.45 20.25,9.2 C20.4,8.6 20.55,8 20.7,7.35 C20.65,7.35 20.65,7.3 20.6,7.3 C20.05,7.15 19.55,7.05 19.05,6.9 C18.95,6.85 18.9,6.9 18.9,7 C18.85,7.2 18.8,7.4 18.75,7.6 C18.55,8.25 18.4,8.85 18.25,9.5 C18.2,9.55 18.15,9.65 18.1,9.65 C17.7,9.55 17.25,9.45 16.85,9.35 C16.9,9.25 16.9,9.2 16.9,9.15 C17.1,8.35 17.3,7.5 17.5,6.7 C17.55,6.6 17.55,6.55 17.4,6.5 C16.9,6.4 16.45,6.3 15.95,6.15 C15.8,6.1 15.75,6.15 15.7,6.3 C15.5,7.15 15.3,7.95 15.1,8.8 C15.05,8.95 15,9 14.85,8.95 C14.3,8.8 13.75,8.7 13.2,8.55 C12.65,8.4 12.1,8.3 11.55,8.15 Z M14.1,20.5 C14.3,19.75 14.45,19.05 14.65,18.35 C14.75,17.85 14.9,17.4 15,16.9 C15.05,16.75 15.05,16.7 15.2,16.75 C16.2,16.95 17.25,17.15 18.15,17.65 C18.55,17.9 18.95,18.15 19.2,18.55 C19.75,19.35 19.35,20.6 18.4,20.9 C17.85,21.1 17.3,21.1 16.7,21.05 C15.85,21 15,20.75 14.2,20.55 C14.2,20.55 14.15,20.5 14.1,20.5 Z M18.3,15.4 C17.5,15.4 16.85,15.25 16.1,15.15 C15.9,15.1 15.75,15.05 15.55,15 C15.45,14.95 15.4,14.9 15.45,14.8 C15.75,13.75 16,12.75 16.25,11.7 C16.3,11.55 16.35,11.5 16.5,11.55 C17.25,11.75 17.95,11.9 18.65,12.2 C19.1,12.4 19.55,12.7 19.8,13.15 C20.3,14 19.8,15.1 18.85,15.3 C18.65,15.35 18.4,15.4 18.3,15.4 Z" id="Combined-Shape" fill-rule="nonzero"></path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

1
app/icons/check_circle.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-check-circle"><path d="M22 11.07V12a10 10 0 1 1-5.93-9.14"></path><polyline points="23 3 12 14 9 11"></polyline></svg>

After

Width:  |  Height:  |  Size: 322 B

1
app/icons/clock.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-clock"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 15 15"></polyline></svg>

After

Width:  |  Height:  |  Size: 304 B

27
app/icons/qrcode.svg

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 48.2 (47327) - http://www.bohemiancoding.com/sketch -->
<title>Group 23</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="v1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" transform="translate(-276.000000, -96.000000)" opacity="0.5">
<g id="Group-23" transform="translate(276.000000, 96.000000)" fill="#FFFFFF" fill-rule="nonzero">
<g id="Group-22">
<g id="Group">
<path d="M0.4,4.80896 C0.17904,4.80896 0,4.62992 0,4.40896 L0,0.4 C0,0.17904 0.17904,0 0.4,0 L4.40896,0 C4.62992,0 4.80896,0.17904 4.80896,0.4 C4.80896,0.62096 4.62992,0.8 4.40896,0.8 L0.8,0.8 L0.8,4.40896 C0.8,4.62992 0.62096,4.80896 0.4,4.80896 Z" id="Shape"></path>
<path d="M15.6,16 L11.59088,16 C11.36992,16 11.19088,15.82096 11.19088,15.6 C11.19088,15.37904 11.36992,15.2 11.59088,15.2 L15.2,15.2 L15.2,11.59088 C15.2,11.36992 15.37904,11.19088 15.6,11.19088 C15.82096,11.19088 16,11.36992 16,11.59088 L16,15.6 C16,15.82096 15.82096,16 15.6,16 Z" id="Shape"></path>
</g>
<g id="Group">
<path d="M15.6,4.80896 C15.37904,4.80896 15.2,4.62992 15.2,4.40896 L15.2,0.8 L11.59088,0.8 C11.36992,0.8 11.19088,0.62096 11.19088,0.4 C11.19088,0.17904 11.36992,0 11.59088,0 L15.6,0 C15.82096,0 16,0.17904 16,0.4 L16,4.40896 C16,4.62992 15.82096,4.80896 15.6,4.80896 Z" id="Shape"></path>
<path d="M4.40896,16 L0.4,16 C0.17904,16 0,15.82096 0,15.6 L0,11.59088 C0,11.36992 0.17904,11.19088 0.4,11.19088 C0.62096,11.19088 0.8,11.36992 0.8,11.59088 L0.8,15.2 L4.40896,15.2 C4.62992,15.2 4.80896,15.37904 4.80896,15.6 C4.80896,15.82096 4.62992,16 4.40896,16 Z" id="Shape"></path>
</g>
<path d="M11.5875,11.9803571 L7.6,11.9803571 C7.38298571,11.9803571 7.20714286,11.8045143 7.20714286,11.5875 L7.20714286,7.99285714 L3.6125,7.99285714 C3.39548571,7.99285714 3.21964286,7.81701429 3.21964286,7.6 C3.21964286,7.38298571 3.39548571,7.20714286 3.6125,7.20714286 L7.6,7.20714286 C7.81701429,7.20714286 7.99285714,7.38298571 7.99285714,7.6 L7.99285714,11.1946429 L11.5875,11.1946429 C11.8045143,11.1946429 11.9803571,11.3704857 11.9803571,11.5875 C11.9803571,11.8045143 11.8045143,11.9803571 11.5875,11.9803571 Z" id="Shape"></path>
<path d="M11.5875,9.87857143 C11.3704857,9.87857143 11.1946429,9.70272857 11.1946429,9.48571429 L11.1946429,7.99285714 L9.87857143,7.99285714 L9.87857143,9.48571429 C9.87857143,9.70272857 9.70272857,9.87857143 9.48571429,9.87857143 C9.2687,9.87857143 9.09285714,9.70272857 9.09285714,9.48571429 L9.09285714,7.6 C9.09285714,7.38298571 9.2687,7.20714286 9.48571429,7.20714286 L11.5875,7.20714286 C11.8045143,7.20714286 11.9803571,7.38298571 11.9803571,7.6 L11.9803571,9.48571429 C11.9803571,9.70272857 11.8045143,9.87857143 11.5875,9.87857143 Z" id="Shape"></path>
<path d="M5.71428571,6.10714286 L3.6125,6.10714286 C3.39548571,6.10714286 3.21964286,5.9313 3.21964286,5.71428571 L3.21964286,3.6125 C3.21964286,3.39548571 3.39548571,3.21964286 3.6125,3.21964286 L5.71428571,3.21964286 C5.9313,3.21964286 6.10714286,3.39548571 6.10714286,3.6125 L6.10714286,5.71428571 C6.10714286,5.9313 5.9313,6.10714286 5.71428571,6.10714286 Z M4.00535714,5.32142857 L5.32142857,5.32142857 L5.32142857,4.00535714 L4.00535714,4.00535714 L4.00535714,5.32142857 Z" id="Shape"></path>
<path d="M11.5875,6.10714286 L9.48571429,6.10714286 C9.2687,6.10714286 9.09285714,5.9313 9.09285714,5.71428571 L9.09285714,3.6125 C9.09285714,3.39548571 9.2687,3.21964286 9.48571429,3.21964286 L11.5875,3.21964286 C11.8045143,3.21964286 11.9803571,3.39548571 11.9803571,3.6125 L11.9803571,5.71428571 C11.9803571,5.9313 11.8045143,6.10714286 11.5875,6.10714286 Z M9.87857143,5.32142857 L11.1946429,5.32142857 L11.1946429,4.00535714 L9.87857143,4.00535714 L9.87857143,5.32142857 Z" id="Shape"></path>
<path d="M5.71428571,11.9803571 L3.6125,11.9803571 C3.39548571,11.9803571 3.21964286,11.8045143 3.21964286,11.5875 L3.21964286,9.48571429 C3.21964286,9.2687 3.39548571,9.09285714 3.6125,9.09285714 L5.71428571,9.09285714 C5.9313,9.09285714 6.10714286,9.2687 6.10714286,9.48571429 L6.10714286,11.5875 C6.10714286,11.8045143 5.9313,11.9803571 5.71428571,11.9803571 Z M4.00535714,11.1946429 L5.32142857,11.1946429 L5.32142857,9.87857143 L4.00535714,9.87857143 L4.00535714,11.1946429 Z" id="Shape"></path>
<path d="M7.6,6.10714286 C7.38298571,6.10714286 7.20714286,5.9313 7.20714286,5.71428571 L7.20714286,3.6125 C7.20714286,3.39548571 7.38298571,3.21964286 7.6,3.21964286 C7.81701429,3.21964286 7.99285714,3.39548571 7.99285714,3.6125 L7.99285714,5.71428571 C7.99285714,5.9313 7.81701429,6.10714286 7.6,6.10714286 Z" id="Shape"></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.9 KiB

16
app/icons/zap_logo.svg

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="60px" height="21px" viewBox="0 0 60 21" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 48.2 (47327) - http://www.bohemiancoding.com/sketch -->
<title>Group 5</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Pay-Hover-Copy" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" transform="translate(-56.000000, -23.000000)">
<g id="Group-5" transform="translate(56.000000, 20.000000)">
<path d="M29.5332033,18.0136719 L36.3984377,18.0136719 L36.3984377,19 L28.0878908,19 L28.0878908,18.140625 L34.4941408,9.43945312 L28.2832033,9.43945312 L28.2832033,8.43359375 L35.9687502,8.43359375 L35.9687502,9.30273438 L29.5332033,18.0136719 Z M46.1582032,19 C46.0410151,18.6679671 45.9661461,18.1764355 45.9335938,17.5253906 C45.5234355,18.0592475 45.0009798,18.4710272 44.366211,18.7607422 C43.7314422,19.0504572 43.0592484,19.1953125 42.3496094,19.1953125 C41.3339794,19.1953125 40.5120475,18.9121122 39.8837891,18.3457031 C39.2555308,17.779294 38.9414063,17.0631554 38.9414063,16.1972656 C38.9414063,15.1686146 39.3694619,14.3548207 40.225586,13.7558594 C41.0817101,13.156898 42.274732,12.8574219 43.8046876,12.8574219 L45.9238282,12.8574219 L45.9238282,11.65625 C45.9238282,10.9010379 45.6910831,10.3069683 45.225586,9.87402344 C44.7600889,9.44107856 44.0813847,9.22460938 43.1894532,9.22460938 C42.375647,9.22460938 41.7018256,9.43294063 41.1679688,9.84960938 C40.634112,10.2662781 40.3671876,10.7675752 40.3671876,11.3535156 L39.1953126,11.34375 C39.1953126,10.5039021 39.5859337,9.77637026 40.3671876,9.16113281 C41.1484415,8.54589536 42.1087183,8.23828125 43.2480469,8.23828125 C44.4264382,8.23828125 45.3557909,8.53287466 46.0361329,9.12207031 C46.7164748,9.71126597 47.0664062,10.5331979 47.0859376,11.5878906 L47.0859376,16.5878906 C47.0859376,17.6100312 47.1933584,18.3749975 47.4082032,18.8828125 L47.4082032,19 L46.1582032,19 Z M42.4863282,18.1601562 C43.2675821,18.1601562 43.9658173,17.9713561 44.5810547,17.59375 C45.1962922,17.2161439 45.6438789,16.7115917 45.9238282,16.0800781 L45.9238282,13.7558594 L43.8339844,13.7558594 C42.668614,13.7688803 41.7571648,13.9820943 41.0996094,14.3955078 C40.4420541,14.8089213 40.1132813,15.3769495 40.1132813,16.0996094 C40.1132813,16.6920603 40.3330057,17.1835918 40.772461,17.5742188 C41.2119163,17.9648457 41.7831997,18.1601562 42.4863282,18.1601562 Z M59.6972656,13.8242188 C59.6972656,15.4713624 59.3326859,16.7783155 58.6035156,17.7451172 C57.8743453,18.7119189 56.8977925,19.1953125 55.6738281,19.1953125 C54.2285083,19.1953125 53.1217486,18.6875051 52.3535156,17.671875 L52.3535156,23.0625 L51.1914062,23.0625 L51.1914062,8.43359375 L52.2753906,8.43359375 L52.3339843,9.92773438 C53.0957069,8.80142666 54.1992115,8.23828125 55.6445312,8.23828125 C56.9075583,8.23828125 57.8987594,8.71679209 58.618164,9.67382812 C59.3375686,10.6308642 59.6972656,11.9589759 59.6972656,13.6582031 L59.6972656,13.8242188 Z M58.5253906,13.6191406 C58.5253906,12.2714776 58.2487006,11.2070352 57.6953124,10.4257812 C57.1419243,9.64452734 56.3704476,9.25390625 55.3808593,9.25390625 C54.6647099,9.25390625 54.0494817,9.42643057 53.5351562,9.77148438 C53.0208307,10.1165382 52.6269544,10.6178353 52.3535156,11.2753906 L52.3535156,16.34375 C52.6334649,16.9492218 53.0338515,17.4114567 53.5546874,17.7304688 C54.0755234,18.0494808 54.6907516,18.2089844 55.4003906,18.2089844 C56.3834684,18.2089844 57.1500623,17.8167357 57.7001953,17.0322266 C58.2503282,16.2477174 58.5253906,15.1100335 58.5253906,13.6191406 Z" id="zap" fill="#FFFFFF"></path>
<g id="cloud-lightning" transform="translate(0.000000, 4.000000)" stroke-linecap="round" stroke-linejoin="round" stroke-width="0.77">
<path d="M15.0416667,12.2863636 C17.0346026,11.8913673 18.396646,10.0866143 18.1922712,8.11170759 C17.9878963,6.13680088 16.283606,4.63436876 14.25,4.63636364 L13.2525,4.63636364 C12.5303096,1.90723362 10.0081977,0.000523827862 7.12041491,0.000523855726 C4.23263213,0.000523883591 1.71052026,1.90723373 0.988329904,4.63636375 C0.26613955,7.36549378 1.52676812,10.2258816 4.05333333,11.5909091" id="Shape" stroke="#FFFFFF"></path>
<polyline id="Shape" stroke="#F5B300" points="10.2916667 7.72727273 7.125 12.3636364 11.875 12.3636364 8.70833333 17"></polyline>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

3
app/main.dev.js

@ -146,7 +146,8 @@ const startLnd = () => {
'--neutrino.connect=127.0.0.1:18333',
'--autopilot.active',
'--debuglevel=debug',
'--noencryptwallet'
'--noencryptwallet',
'--alias=jimmymow'
]
)
.on('error', error => console.log(`lnd error: ${error}`))

48
app/reducers/activity.js

@ -7,11 +7,11 @@ 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' }
{ key: 'ALL_ACTIVITY', name: 'All' },
{ key: 'SENT_ACTIVITY', name: 'Sent' },
{ key: 'REQUESTED_ACTIVITY', name: 'Requested' },
{ key: 'PENDING_ACTIVITY', name: 'Pending' },
{ key: 'FUNDED_ACTIVITY', name: 'Funding Transactions' }
],
modal: {
modalType: null,
@ -91,6 +91,7 @@ const searchSelector = state => state.activity.searchText
const paymentsSelector = state => state.payment.payments
const invoicesSelector = state => state.invoice.invoices
const transactionsSelector = state => state.transaction.transactions
const channelsSelector = state => state.channels.channels
const allActivity = createSelector(
searchSelector,
@ -138,12 +139,41 @@ const transactionActivity = createSelector(
transactions => transactions
)
const sentActivity = createSelector(
transactionsSelector,
paymentsSelector,
(transactions, payments) => {
const sentTransactions = transactions.filter(transaction => transaction.amount < 0)
return [...sentTransactions, ...payments].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 pendingActivity = createSelector(
invoicesSelector,
invoices => invoices.filter(invoice => !invoice.settled)
)
const fundedActivity = createSelector(
transactionsSelector,
channelsSelector,
(transactions, channels) => {
const fundingTxIds = channels.map(channel => channel.channel_point.split(':')[0])
return transactions.filter(transaction => fundingTxIds.includes(transaction.tx_hash))
}
)
const FILTERS = {
ALL_ACTIVITY: allActivity,
LN_ACTIVITY: lnActivity,
PAYMENT_ACTIVITY: paymentActivity,
INVOICE_ACTIVITY: invoiceActivity,
TRANSACTION_ACTIVITY: transactionActivity
SENT_ACTIVITY: sentActivity,
REQUESTED_ACTIVITY: invoiceActivity,
PENDING_ACTIVITY: pendingActivity,
FUNDED_ACTIVITY: fundedActivity
}
activitySelectors.currentActivity = createSelector(

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

@ -21,13 +21,14 @@ class Activity extends Component {
componentWillMount() {
const {
fetchPayments, fetchInvoices, fetchTransactions, fetchBalance
fetchPayments, fetchInvoices, fetchTransactions, fetchBalance, fetchChannels
} = this.props
fetchBalance()
fetchPayments()
fetchInvoices()
fetchTransactions()
fetchChannels()
}
renderActivity(activity) {
@ -54,13 +55,15 @@ class Activity extends Component {
info,
payment: { paymentLoading },
currentTicker,
activity: { modal, filter, filterPulldown, searchText },
activity: { modal, filters, filter, filterPulldown, searchText },
hideActivityModal,
changeFilter,
toggleFilterPulldown,
currentActivity,
nonActiveFilters,
newAddress
newAddress,
openPayForm,
openRequestForm
} = this.props
if (invoiceLoading || paymentLoading) { return <LoadingBolt /> }
@ -68,7 +71,7 @@ class Activity extends Component {
if (!balance.channelBalance || !balance.walletBalance) { return <LoadingBolt /> }
return (
<div>
<div style={{ height: '100%' }}>
<Modal
modalType={modal.modalType}
modalProps={modal.modalProps}
@ -77,33 +80,26 @@ class Activity extends Component {
currentTicker={currentTicker}
/>
<Wallet balance={balance} address={address} info={info} newAddress={newAddress} />
<div className={styles.search}>
<label className={`${styles.label} ${styles.input}`} htmlFor='invoiceSearch'>
<MdSearch />
</label>
<input
value={searchText}
onChange={event => updateSearchText(event.target.value)}
className={`${styles.text} ${styles.input}`}
placeholder='Search by hash...'
type='text'
id='invoiceSearch'
/>
</div>
<Wallet
balance={balance}
address={address}
info={info}
newAddress={newAddress}
currentTicker={currentTicker}
openPayForm={openPayForm}
openRequestForm={openRequestForm}
/>
<div className={styles.activities}>
<header className={styles.header}>
<section>
<h2 onClick={toggleFilterPulldown}>
{filter.name} <span className={filterPulldown && styles.pulldown}><FaAngleDown /></span>
</h2>
<ul className={`${styles.filters} ${filterPulldown && styles.active}`}>
<ul className={styles.filters}>
{
nonActiveFilters.map(f => (
<li key={f.key} onClick={() => changeFilter(f)}>
{f.name}
filters.map(f => (
<li key={f.key} className={f.key === filter.key && styles.activeFilter} onClick={() => changeFilter(f)}>
<span>{f.name}</span>
<div className={f.key === filter.key && styles.activeBorder} />
</li>
))
}
@ -142,6 +138,8 @@ Activity.propTypes = {
changeFilter: PropTypes.func.isRequired,
newAddress: PropTypes.func.isRequired,
toggleFilterPulldown: PropTypes.func.isRequired,
openPayForm: PropTypes.func.isRequired,
openRequestForm: PropTypes.func.isRequired,
activity: PropTypes.object.isRequired,
currentActivity: PropTypes.array.isRequired,

99
app/routes/activity/components/Activity.scss

@ -32,91 +32,66 @@
.activities {
background: $white;
height: 100%;
.header {
padding: 60px 0 20px 0;
background: $spaceblue;
color: $white;
margin: 0 auto;
padding: 0 40px;
border-bottom: 1px solid $spaceborder;
section {
position: relative;
margin-left: auto;
margin-right: auto;
padding-left: 100px;
padding-right: 100px;
max-width: 964px;
h2 {
color: $bluegrey;
}
}
h2, h2 span {
color: $bluegrey;
cursor: pointer;
transition: color 0.25s;
.filters {
display: flex;
flex-direction: row;
li {
position: relative;
margin: 0 15px;
opacity: 0.5;
font-size: 14px;
cursor: pointer;
padding: 20px 0;
&:hover {
color: lighten($bluegrey, 10%);
&.activeFilter {
opacity: 1;
}
&:nth-child(1) {
margin-left: 0;
}
}
}
h2, .filters li {
text-transform: uppercase;
letter-spacing: 1.5px;
color: $darkestgrey;
font-size: 14px;
font-weight: 400;
}
h2 span.pulldown {
color: $main;
}
.filters {
display: none;
&.active {
display: block;
.activeBorder {
width: 100%;
height: 1px;
background: white;
position: absolute;
bottom: -100px;
z-index: 10;
li {
margin: 5px 0;
cursor: pointer;
&:hover {
color: $main;
}
}
}
}
bottom: -1px;
}
}
}
}
.activityContainer {
background: $white;
background: $spaceblue;
transition: opacity 0.25s;
padding-bottom: 50px;
height: 100%;
overflow-y: scroll;
padding-top: 20px;
&.pulldown {
opacity: 0.15;
}
}
.activityList {
width: 75%;
margin: 0 auto;
background: $white;
}
.activity {
padding: 0 100px;
padding: 0 40px;
&:hover {
background-color: #f0f0f0;
transition-delay: 0s;
outline: $grey solid 1px;
}
.left, .center, .right {

79
app/routes/activity/components/components/Activity.scss

@ -4,15 +4,12 @@
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;
color: $white;
position: relative;
}
@ -37,22 +34,20 @@
justify-content: center;
align-items: center;
padding-right: 50px;
min-width: 90px;
time {
text-transform: uppercase;
section {
margin: 2.5px 0;
}
&:nth-child(1) {
display: flex;
align-items: center;
height: 38px;
font-size: 18px;
margin-bottom: 5px;
}
svg {
width: 12.5px;
height: 12.5px;
}
&:nth-child(2) {
font-size: 12px;
}
}
time {
font-size: 12px;
}
}
.data {
@ -61,6 +56,10 @@
flex: 6;
justify-content: space-evenly;
&:nth-child(2) {
font-size: 10px;
}
.title {
margin-bottom: 5px;
}
@ -70,23 +69,24 @@
}
h3, span {
font-size: 18px;
font-size: 14px;
font-weight: bold;
letter-spacing: 1.2px;
}
.icon {
display: inline-block;
flex: none;
position: relative;
width: 36px;
height: 36px;
border: 1px solid $darkestgrey;
width: 20px;
height: 20px;
background: $main;
border-radius: 50%;
margin-right: 15px;
margin-right: 5px;
svg {
color: $main;
font-size: 16px;
color: $spaceblue;
font-size: 10px;
vertical-align: middle;
display: flex;
top: 0;
@ -116,16 +116,33 @@
flex-direction: column;
flex: 1;
text-align: right;
font-size: 16px;
&.positive span:nth-child(1) {
font-weight: bold;
color: $main;
}
font-size: 12px;
color: $white;
span {
&:nth-child(1) {
margin-bottom: 5px;
}
&:nth-child(2) {
font-size: 12px;
font-size: 10px;
opacity: 0.5;
}
.plus, .minus {
margin-right: 2px;
}
.plus {
color: $green;
}
.minus {
color: $red;
}
}
}
.unpaid svg {
opacity: 0.5;
}

34
app/routes/activity/components/components/Invoice/Invoice.js

@ -2,31 +2,31 @@ import React from 'react'
import PropTypes from 'prop-types'
import Moment from 'react-moment'
import 'moment-timezone'
import Isvg from 'react-inlinesvg'
import { FaBolt, FaClockO } from 'react-icons/lib/fa'
import { btc } from 'utils'
import checkmarkIcon from 'icons/check_circle.svg'
import clockIcon from 'icons/clock.svg'
import styles from '../Activity.scss'
const Invoice = ({
invoice, ticker, currentTicker, showActivityModal
}) => (
<div className={styles.container} onClick={() => showActivityModal('INVOICE', { invoice })}>
{
!invoice.settled ?
<div className={styles.clock}>
<i className='hint--top' data-hint='Request has not been paid'>
<FaClockO />
</i>
</div>
:
null
}
<div className={styles.date}>
<Moment format='D'>
{invoice.creation_date * 1000}
</Moment>
<Moment format='MMMM'>
{invoice.creation_date * 1000}
</Moment>
<section className={!invoice.settled && styles.unpaid}>
{
invoice.settled ?
<Isvg src={checkmarkIcon} />
:
<i className='hint--top' data-hint='Request has not been paid'>
<Isvg src={clockIcon} />
</i>
}
</section>
<section>
<Moment format='MMM'>{invoice.creation_date * 1000}</Moment> <Moment format='D'>{invoice.creation_date * 1000}</Moment>
</section>
</div>
<div className={styles.data}>
<div className={styles.title}>
@ -46,7 +46,7 @@ const Invoice = ({
</div>
<div className={`${styles.amount} ${invoice.settled ? styles.positive : styles.negative}`}>
<span className='hint--top' data-hint='Invoice amount'>
+
<i className={styles.plus}>+</i>
{
ticker.currency === 'usd' ?
btc.satoshisToUsd(invoice.value, currentTicker.price_usd)

16
app/routes/activity/components/components/Payment/Payment.js

@ -2,8 +2,10 @@ import React from 'react'
import PropTypes from 'prop-types'
import Moment from 'react-moment'
import 'moment-timezone'
import Isvg from 'react-inlinesvg'
import { FaBolt } from 'react-icons/lib/fa'
import { btc } from 'utils'
import checkmarkIcon from 'icons/check_circle.svg'
import styles from '../Activity.scss'
const Payment = ({
@ -11,12 +13,12 @@ const Payment = ({
}) => (
<div className={styles.container} onClick={() => showActivityModal('PAYMENT', { payment })}>
<div className={styles.date}>
<Moment format='D'>
{payment.creation_date * 1000}
</Moment>
<Moment format='MMMM'>
{payment.creation_date * 1000}
</Moment>
<section>
<Isvg src={checkmarkIcon} />
</section>
<section>
<Moment format='MMM'>{payment.creation_date * 1000}</Moment> <Moment format='D'>{payment.creation_date * 1000}</Moment>
</section>
</div>
<div className={styles.data}>
<div className={styles.title}>
@ -36,7 +38,7 @@ const Payment = ({
</div>
<div className={styles.amount}>
<span className='hint--top' data-hint='Payment amount'>
-
<i className={styles.minus}>-</i>
{
ticker.currency === 'usd' ?
btc.satoshisToUsd(payment.value, currentTicker.price_usd)

16
app/routes/activity/components/components/Transaction/Transaction.js

@ -2,8 +2,10 @@ import React from 'react'
import PropTypes from 'prop-types'
import Moment from 'react-moment'
import 'moment-timezone'
import Isvg from 'react-inlinesvg'
import { FaChain } from 'react-icons/lib/fa'
import { btc } from 'utils'
import checkmarkIcon from 'icons/check_circle.svg'
import styles from '../Activity.scss'
const Transaction = ({
@ -11,12 +13,12 @@ const Transaction = ({
}) => (
<div className={styles.container} onClick={() => showActivityModal('TRANSACTION', { transaction })}>
<div className={styles.date}>
<Moment format='D'>
{transaction.time_stamp * 1000}
</Moment>
<Moment format='MMMM'>
{transaction.time_stamp * 1000}
</Moment>
<section>
<Isvg src={checkmarkIcon} />
</section>
<section>
<Moment format='MMM'>{transaction.time_stamp * 1000}</Moment> <Moment format='D'>{transaction.time_stamp * 1000}</Moment>
</section>
</div>
<div className={styles.data}>
<div className={styles.title}>
@ -36,7 +38,7 @@ const Transaction = ({
</div>
<div className={`${styles.amount} ${transaction.amount > 0 ? styles.positive : styles.negative}`}>
<span className='hint--top' data-hint='Transaction amount'>
{ transaction.amount > 0 ? '+' : '' }
<i className={transaction.amount > 0 ? styles.plus : styles.minus}>{ transaction.amount > 0 ? '+' : '-' }</i>
{
ticker.currency === 'usd' ?
btc.satoshisToUsd(transaction.amount, currentTicker.price_usd)

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

@ -21,6 +21,8 @@ import {
updateSearchText
} from 'reducers/activity'
import { newAddress } from 'reducers/address'
import { setFormType } from 'reducers/form'
import { fetchChannels } from 'reducers/channels'
import Activity from '../components/Activity'
@ -36,7 +38,9 @@ const mapDispatchToProps = {
toggleFilterPulldown,
newAddress,
fetchBalance,
updateSearchText
updateSearchText,
setFormType,
fetchChannels
}
const mapStateToProps = state => ({
@ -62,4 +66,17 @@ const mapStateToProps = state => ({
nonActiveFilters: activitySelectors.nonActiveFilters(state)
})
export default connect(mapStateToProps, mapDispatchToProps)(Activity)
const mergeProps = (stateProps, dispatchProps, ownProps) => {
return {
...stateProps,
...dispatchProps,
...ownProps,
// action to open the pay form
openPayForm: () => dispatchProps.setFormType('PAY_FORM'),
// action to open the request form
openRequestForm: () => dispatchProps.setFormType('REQUEST_FORM'),
}
}
export default connect(mapStateToProps, mapDispatchToProps, mergeProps)(Activity)

11
app/routes/app/components/App.js

@ -24,8 +24,6 @@ class App extends Component {
currentTicker,
form,
openPayForm,
openRequestForm,
formProps,
closeForm,
@ -38,7 +36,7 @@ class App extends Component {
if (!currentTicker) { return <LoadingBolt /> }
return (
<div>
<div style={{ height: '100%' }}>
<div className={styles.titleBar} />
<GlobalError error={error} clearError={clearError} />
<ModalRoot
@ -51,11 +49,6 @@ class App extends Component {
<Form formType={form.formType} formProps={formProps} closeForm={closeForm} />
<Nav
openPayForm={openPayForm}
openRequestForm={openRequestForm}
/>
<div className={styles.content}>
{children}
</div>
@ -76,8 +69,6 @@ App.propTypes = {
fetchInfo: PropTypes.func.isRequired,
hideModal: PropTypes.func.isRequired,
fetchTicker: PropTypes.func.isRequired,
openPayForm: PropTypes.func.isRequired,
openRequestForm: PropTypes.func.isRequired,
clearError: PropTypes.func.isRequired,
currentTicker: PropTypes.object,

2
app/routes/app/components/App.scss

@ -2,7 +2,7 @@
.content {
position: relative;
width: 85%;
width: 100%;
height: 100vh;
display: inline-block;
vertical-align: top;

4
app/routes/app/containers/AppContainer.js

@ -179,10 +179,6 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
// Props to pass to the pay form
formProps: formProps(stateProps.form.formType),
// action to open the pay form
openPayForm: () => dispatchProps.setFormType('PAY_FORM'),
// action to open the request form
openRequestForm: () => dispatchProps.setFormType('REQUEST_FORM'),
// action to close form
closeForm: () => dispatchProps.setFormType(null)

3
app/utils/btc.js

@ -9,7 +9,8 @@ export function btcToSatoshis(btc) {
export function satoshisToBtc(satoshis) {
if (satoshis === undefined || satoshis === null || satoshis === '') return null
return sb.toBitcoin(satoshis).toFixed(8)
const btcAmount = sb.toBitcoin(satoshis).toFixed(8)
return btcAmount > 0 ? btcAmount : btcAmount * -1
}
export function btcToUsd(btc, price) {

5
app/variables.scss

@ -8,12 +8,15 @@ $traditionalgrey: #cccccc;
$lightgrey: #F7F7F7;
$darkgrey: #EBEBEB;
$darkestgrey: #999999;
$bluegrey: #555459;
$bluegrey: #2A2D38;
$spacegrey: #222E2B;
$spaceblue: #252832;
$spaceborder: #404040;
$green: #0bb634;
$terminalgreen: #00FF00;
$red: #FF556A;
$blue: #007bb6;
$orange: #FF8A65;
$yellow: #FFF680;
$curve: cubic-bezier(0.650, 0.000, 0.450, 1.000);
Loading…
Cancel
Save