Browse Source

feature(wallet): build new wallet modal/refactor current wallet component

renovate/lint-staged-8.x
Jack Mallers 7 years ago
parent
commit
54c31e2de3
  1. 1
      app/components/Form/Form.scss
  2. 4
      app/components/Form/Pay.js
  3. 75
      app/components/Wallet/ReceiveModal.js
  4. 25
      app/components/Wallet/ReceiveModal.scss
  5. 51
      app/components/Wallet/Wallet.js
  6. 21
      app/components/Wallet/Wallet.scss
  7. 23
      app/reducers/address.js
  8. 11
      app/routes/activity/containers/ActivityContainer.js
  9. 3
      app/routes/app/components/App.js
  10. 13
      app/routes/app/containers/AppContainer.js

1
app/components/Form/Form.scss

@ -24,4 +24,3 @@
color: $white; color: $white;
} }
} }

4
app/components/Form/Pay.js

@ -60,9 +60,6 @@ class Pay extends Component {
setCurrency setCurrency
} = this.props } = this.props
console.log('errors: ', errors)
console.log('showErrors: ', showErrors)
const displayNodeName = (pubkey) => { const displayNodeName = (pubkey) => {
const node = find(nodes, n => n.pub_key === pubkey) const node = find(nodes, n => n.pub_key === pubkey)
@ -83,7 +80,6 @@ class Pay extends Component {
return ( return (
<div className={styles.container}> <div className={styles.container}>
{showPayLoadingScreen && <LoadingBolt />}
<header className={styles.header}> <header className={styles.header}>
<Isvg src={paperPlane} /> <Isvg src={paperPlane} />
<h1>Make Payment</h1> <h1>Make Payment</h1>

75
app/components/Wallet/ReceiveModal.js

@ -1,55 +1,57 @@
import React from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import ReactModal from 'react-modal'
import copy from 'copy-to-clipboard' import copy from 'copy-to-clipboard'
import QRCode from 'qrcode.react' import QRCode from 'qrcode.react'
import { showNotification } from 'notifications'
import { FaCopy } from 'react-icons/lib/fa' import { FaCopy } from 'react-icons/lib/fa'
import { MdClose } from 'react-icons/lib/md' import Isvg from 'react-inlinesvg'
import x from 'icons/x.svg'
import { showNotification } from 'notifications'
import styles from './ReceiveModal.scss' import styles from './ReceiveModal.scss'
const ReceiveModal = ({ class ReceiveModal extends React.Component {
isOpen, hideActivityModal, pubkey, address, newAddress, qrCodeType, changeQrCode constructor(props) {
}) => { super(props)
const customStyles = {
overlay: { this.state = {
cursor: 'pointer' qrCodeType: 1
},
content: {
top: 'auto',
left: '0',
right: '0',
bottom: 'auto',
width: '40%',
margin: '50px auto',
borderRadius: 'none',
padding: '0'
} }
} }
render() {
const copyOnClick = (data) => { const copyOnClick = (data) => {
copy(data) copy(data)
showNotification('Noice', 'Successfully copied to clipboard') showNotification('Noice', 'Successfully copied to clipboard')
} }
const changeQrCode = () => {
if (this.state.qrCodeType === 1) {
this.setState({ qrCodeType: 2 })
} else {
this.setState({ qrCodeType: 1 })
}
}
const {
isOpen,
pubkey,
address,
newAddress,
closeReceiveModal
} = this.props
const { qrCodeType } = this.state
if (!isOpen) { return null }
return ( return (
<ReactModal <div className={styles.container}>
isOpen={isOpen}
ariaHideApp
shouldCloseOnOverlayClick
contentLabel='No Overlay Click Modal'
onRequestClose={() => hideActivityModal()}
parentSelector={() => document.body}
style={customStyles}
>
<div className={styles.closeContainer}> <div className={styles.closeContainer}>
<span onClick={() => hideActivityModal()}> <span onClick={closeReceiveModal}>
<MdClose /> <Isvg src={x} />
</span> </span>
</div> </div>
<header className={styles.header}>
<div className={styles.container}>
<header>
<div className={styles.qrcodes}> <div className={styles.qrcodes}>
<QRCode value={qrCodeType === 1 ? address : pubkey} /> <QRCode value={qrCodeType === 1 ? address : pubkey} />
</div> </div>
@ -86,18 +88,15 @@ const ReceiveModal = ({
</p> </p>
</section> </section>
</div> </div>
</ReactModal>
) )
} }
}
ReceiveModal.propTypes = { ReceiveModal.propTypes = {
isOpen: PropTypes.bool.isRequired, isOpen: PropTypes.bool.isRequired,
hideActivityModal: PropTypes.func.isRequired,
pubkey: PropTypes.string.isRequired, pubkey: PropTypes.string.isRequired,
address: PropTypes.string.isRequired, address: PropTypes.string.isRequired,
newAddress: PropTypes.func.isRequired, newAddress: PropTypes.func.isRequired
changeQrCode: PropTypes.func.isRequired,
qrCodeType: PropTypes.number.isRequired
} }
export default ReceiveModal export default ReceiveModal

25
app/components/Wallet/ReceiveModal.scss

@ -1,19 +1,31 @@
@import '../../variables.scss'; @import '../../variables.scss';
.container {
position: relative;
height: 100vh;
background: $bluegrey;
}
.closeContainer { .closeContainer {
background: $lightgrey;
text-align: right; text-align: right;
padding: 10px; padding: 20px 40px 0px;
span { span {
color: $darkestgrey;
font-size: 20px;
cursor: pointer; cursor: pointer;
opacity: 1.0;
transition: 0.25s all;
&:hover {
opacity: 0.5;
} }
} }
.container { svg {
header { color: $white;
}
}
.header {
background: $lightgrey; background: $lightgrey;
padding: 10px 40px 40px; padding: 10px 40px 40px;
text-align: center; text-align: center;
@ -92,7 +104,6 @@
} }
} }
} }
}
.addressHeader { .addressHeader {
display: flex; display: flex;

51
app/components/Wallet/Wallet.js

@ -2,62 +2,32 @@ import React, { Component } from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { FaAngleDown } from 'react-icons/lib/fa' import { FaAngleDown } from 'react-icons/lib/fa'
import Isvg from 'react-inlinesvg' import Isvg from 'react-inlinesvg'
import { btc } from 'utils' import { btc } from 'utils'
import Value from 'components/Value' import Value from 'components/Value'
import bitcoinIcon from 'icons/bitcoin.svg' import bitcoinIcon from 'icons/bitcoin.svg'
import zapLogo from 'icons/zap_logo.svg' import zapLogo from 'icons/zap_logo.svg'
import qrCode from 'icons/qrcode.svg' import qrCode from 'icons/qrcode.svg'
import ReceiveModal from './ReceiveModal'
import styles from './Wallet.scss' import styles from './Wallet.scss'
class Wallet extends Component { const Wallet = ({
constructor(props) {
super(props)
this.state = {
modalOpen: false,
qrCodeType: 1
}
}
render() {
const {
balance, balance,
address, address,
info, info,
newAddress, newAddress,
openReceiveModal,
ticker, ticker,
currentTicker, currentTicker,
openPayForm, openPayForm,
openRequestForm openRequestForm,
} = this.props showPayLoadingScreen
}) => {
const { modalOpen, qrCodeType } = this.state
const usdAmount = btc.satoshisToUsd((parseInt(balance.walletBalance, 10) + parseInt(balance.channelBalance, 10)), currentTicker.price_usd) const usdAmount = btc.satoshisToUsd((parseInt(balance.walletBalance, 10) + parseInt(balance.channelBalance, 10)), currentTicker.price_usd)
const changeQrCode = () => {
const qrCodeNum = this.state.qrCodeType === 1 ? 2 : 1
this.setState({ qrCodeType: qrCodeNum })
}
return ( return (
<div className={styles.wallet}> <div className={styles.wallet}>
{
(
modalOpen &&
<ReceiveModal
isOpen={modalOpen}
hideActivityModal={() => this.setState({ modalOpen: false })}
pubkey={info.data.identity_pubkey}
address={address}
newAddress={newAddress}
qrCodeType={qrCodeType}
changeQrCode={changeQrCode}
/>
)
}
<div className={styles.content}> <div className={styles.content}>
<header className={styles.header}> <header className={styles.header}>
<section className={styles.logo}> <section className={styles.logo}>
@ -85,7 +55,7 @@ class Wallet extends Component {
/> />
<i className={styles.currency}>{btc.renderCurrency(ticker.currency)}</i> <i className={styles.currency}>{btc.renderCurrency(ticker.currency)}</i>
</span> </span>
<span onClick={() => this.setState({ modalOpen: true })}> <span onClick={openReceiveModal}>
<Isvg className={styles.bitcoinLogo} src={qrCode} /> <Isvg className={styles.bitcoinLogo} src={qrCode} />
</span> </span>
</h1> </h1>
@ -98,12 +68,15 @@ class Wallet extends Component {
<div className={styles.pay} onClick={openPayForm}>Pay</div> <div className={styles.pay} onClick={openPayForm}>Pay</div>
<div className={styles.request} onClick={openRequestForm}>Request</div> <div className={styles.request} onClick={openRequestForm}>Request</div>
</div> </div>
<div className={styles.notificationBox}>
<section className={styles.spinner} />
<section>Gang gang gang baby</section>
</div>
</div> </div>
</div> </div>
</div> </div>
) )
} }
}
Wallet.propTypes = { Wallet.propTypes = {
balance: PropTypes.object.isRequired, balance: PropTypes.object.isRequired,

21
app/components/Wallet/Wallet.scss

@ -141,6 +141,27 @@
margin-right: 20px; margin-right: 20px;
} }
} }
.notificationBox {
text-align: right;
font-size: 12px;
}
} }
.spinner {
border: 1px solid rgba(0, 0, 0, 0.1);
border-left-color: rgba(0, 0, 0, 0.4);
-webkit-border-radius: 999px;
-moz-border-radius: 999px;
border-radius: 999px;
}
.spinner {
margin: 0 auto;
height: 20px;
width: 20px;
-webkit-animation: animation-rotate 1000ms linear infinite;
-moz-animation: animation-rotate 1000ms linear infinite;
-o-animation: animation-rotate 1000ms linear infinite;
animation: animation-rotate 1000ms linear infinite;
}

23
app/reducers/address.js

@ -5,6 +5,9 @@ import { ipcRenderer } from 'electron'
export const GET_ADDRESS = 'GET_ADDRESS' export const GET_ADDRESS = 'GET_ADDRESS'
export const RECEIVE_ADDRESS = 'RECEIVE_ADDRESS' export const RECEIVE_ADDRESS = 'RECEIVE_ADDRESS'
export const OPEN_WALLET_MODAL = 'OPEN_WALLET_MODAL'
export const CLOSE_WALLET_MODAL = 'CLOSE_WALLET_MODAL'
// LND expects types to be sent as int, so this object will allow mapping from string to int // LND expects types to be sent as int, so this object will allow mapping from string to int
const addressTypes = { const addressTypes = {
p2wkh: 0, p2wkh: 0,
@ -21,6 +24,18 @@ export function getAddress() {
} }
} }
export function openWalletModal() {
return {
type: OPEN_WALLET_MODAL
}
}
export function closeWalletModal() {
return {
type: CLOSE_WALLET_MODAL
}
}
// Send IPC event for getinfo // Send IPC event for getinfo
export const newAddress = type => async (dispatch) => { export const newAddress = type => async (dispatch) => {
dispatch(getAddress()) dispatch(getAddress())
@ -35,7 +50,10 @@ export const receiveAddress = (event, address) => dispatch => dispatch({ type: R
// ------------------------------------ // ------------------------------------
const ACTION_HANDLERS = { const ACTION_HANDLERS = {
[GET_ADDRESS]: state => ({ ...state, addressLoading: true }), [GET_ADDRESS]: state => ({ ...state, addressLoading: true }),
[RECEIVE_ADDRESS]: (state, { address }) => ({ ...state, addressLoading: false, address }) [RECEIVE_ADDRESS]: (state, { address }) => ({ ...state, addressLoading: false, address }),
[OPEN_WALLET_MODAL]: state => ({ ...state, walletModal: true }),
[CLOSE_WALLET_MODAL]: state => ({ ...state, walletModal: false })
} }
// ------------------------------------ // ------------------------------------
@ -43,7 +61,8 @@ const ACTION_HANDLERS = {
// ------------------------------------ // ------------------------------------
const initialState = { const initialState = {
addressLoading: false, addressLoading: false,
address: '' address: '',
walletModal: false
} }
export default function addressReducer(state = initialState, action) { export default function addressReducer(state = initialState, action) {

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

@ -20,9 +20,11 @@ import {
activitySelectors, activitySelectors,
updateSearchText updateSearchText
} from 'reducers/activity' } from 'reducers/activity'
import { newAddress } from 'reducers/address' import { newAddress, openWalletModal } from 'reducers/address'
import { setFormType } from 'reducers/form' import { setFormType } from 'reducers/form'
import { payFormSelectors } from 'reducers/payform'
import Activity from '../components/Activity' import Activity from '../components/Activity'
const mapDispatchToProps = { const mapDispatchToProps = {
@ -37,6 +39,7 @@ const mapDispatchToProps = {
changeFilter, changeFilter,
toggleFilterPulldown, toggleFilterPulldown,
newAddress, newAddress,
openWalletModal,
fetchBalance, fetchBalance,
updateSearchText, updateSearchText,
setFormType setFormType
@ -62,7 +65,9 @@ const mapStateToProps = state => ({
currentTicker: tickerSelectors.currentTicker(state), currentTicker: tickerSelectors.currentTicker(state),
currentActivity: activitySelectors.currentActivity(state)(state), currentActivity: activitySelectors.currentActivity(state)(state),
nonActiveFilters: activitySelectors.nonActiveFilters(state) nonActiveFilters: activitySelectors.nonActiveFilters(state),
showPayLoadingScreen: payFormSelectors.showPayLoadingScreen(state),
}) })
const mergeProps = (stateProps, dispatchProps, ownProps) => { const mergeProps = (stateProps, dispatchProps, ownProps) => {
@ -72,9 +77,11 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
info: stateProps.info, info: stateProps.info,
ticker: stateProps.ticker, ticker: stateProps.ticker,
currentTicker: stateProps.currentTicker, currentTicker: stateProps.currentTicker,
showPayLoadingScreen: stateProps.showPayLoadingScreen,
setCurrency: dispatchProps.setCurrency, setCurrency: dispatchProps.setCurrency,
newAddress: dispatchProps.newAddress, newAddress: dispatchProps.newAddress,
openReceiveModal: dispatchProps.openWalletModal,
openPayForm: () => dispatchProps.setFormType('PAY_FORM'), openPayForm: () => dispatchProps.setFormType('PAY_FORM'),
openRequestForm: () => dispatchProps.setFormType('REQUEST_FORM') openRequestForm: () => dispatchProps.setFormType('REQUEST_FORM')
} }

3
app/routes/app/components/App.js

@ -11,6 +11,7 @@ import Network from 'components/Contacts/Network'
import ContactModal from 'components/Contacts/ContactModal' import ContactModal from 'components/Contacts/ContactModal'
import ContactsForm from 'components/Contacts/ContactsForm' import ContactsForm from 'components/Contacts/ContactsForm'
import ReceiveModal from 'components/Wallet/ReceiveModal'
import ActivityModal from 'components/Activity/ActivityModal' import ActivityModal from 'components/Activity/ActivityModal'
import styles from './App.scss' import styles from './App.scss'
@ -57,6 +58,7 @@ class App extends Component {
contactModalProps, contactModalProps,
contactsFormProps, contactsFormProps,
networkTabProps, networkTabProps,
receiveModalProps,
activityModalProps, activityModalProps,
children children
@ -81,6 +83,7 @@ class App extends Component {
<Form formType={form.formType} formProps={formProps} closeForm={closeForm} /> <Form formType={form.formType} formProps={formProps} closeForm={closeForm} />
<ReceiveModal {...receiveModalProps} />
<ActivityModal {...activityModalProps} /> <ActivityModal {...activityModalProps} />
<div className={styles.content}> <div className={styles.content}>

13
app/routes/app/containers/AppContainer.js

@ -3,7 +3,7 @@ import { connect } from 'react-redux'
import { fetchTicker, setCurrency, tickerSelectors } from 'reducers/ticker' import { fetchTicker, setCurrency, tickerSelectors } from 'reducers/ticker'
import { newAddress } from 'reducers/address' import { newAddress, closeWalletModal } from 'reducers/address'
import { fetchInfo } from 'reducers/info' import { fetchInfo } from 'reducers/info'
@ -61,6 +61,7 @@ const mapDispatchToProps = {
setCurrency, setCurrency,
newAddress, newAddress,
closeWalletModal,
fetchInfo, fetchInfo,
@ -339,6 +340,14 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
} }
} }
const receiveModalProps = {
isOpen: stateProps.address.walletModal,
pubkey: stateProps.info.data.identity_pubkey,
address: stateProps.address.address,
newAddress: dispatchProps.newAddress,
closeReceiveModal: dispatchProps.closeWalletModal
}
return { return {
...stateProps, ...stateProps,
...dispatchProps, ...dispatchProps,
@ -350,6 +359,8 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
contactsFormProps, contactsFormProps,
// props for the contact modal // props for the contact modal
contactModalProps, contactModalProps,
// props for the receive modal
receiveModalProps,
// props for the activity modals // props for the activity modals
activityModalProps, activityModalProps,
// Props to pass to the pay form // Props to pass to the pay form

Loading…
Cancel
Save