Skip to content

Commit

Permalink
Neolink redesign send (#100)
Browse files Browse the repository at this point in the history
* Begin redesign send. Remove label from state in send and home

* Implement new send design

* Errors wip

* Set up errors on form input fields

* Add sendconfirmpage to send

* Add error message

* remove br causing style issues

* Correct tests

* Different styling on AccountPage depending on whether or not the options flag is passed

* Adjust tests further

* Add proptypes to SendSuccessPage

* Add onclick handler to success page

* Remove unused import in send.js

* Add necessary parameter to getHomeScreenBalance callback
  • Loading branch information
FredrikOseberg authored and slipo committed Apr 23, 2018
1 parent c75d456 commit d316365
Show file tree
Hide file tree
Showing 15 changed files with 574 additions and 142 deletions.
33 changes: 29 additions & 4 deletions __tests__/components/Login.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,13 @@ describe('Login', () => {
test('shows loading', done => {
const loginForm = mount(
<Provider store={ store }>
<LoginForm setAccount={ jest.fn } account={ { wif: '' } } accounts={ validAccount } setBalance={ jest.fn } />
<LoginForm
setAccount={ jest.fn }
account={ { wif: '' } }
accounts={ validAccount }
setBalance={ jest.fn }
setTransactions={ jest.fn }
/>
</Provider>
)
loginForm
Expand All @@ -49,6 +55,7 @@ describe('Login', () => {
account={ { wif: '' } }
accounts={ {} }
setBalance={ jest.fn }
setTransactions={ jest.fn }
/>
)
expect(loginForm.contains('CreateOrImportWallet'))
Expand All @@ -62,7 +69,13 @@ describe('Login', () => {

const loginForm = mount(
<Provider store={ store }>
<LoginForm setAccount={ jest.fn } account={ preLoggedIn } accounts={ validAccount } setBalance={ jest.fn } />
<LoginForm
setAccount={ jest.fn }
account={ preLoggedIn }
accounts={ validAccount }
setBalance={ jest.fn }
setTransactions={ jest.fn }
/>
</Provider>
)
expect(loginForm.html()).toEqual(null)
Expand All @@ -80,7 +93,13 @@ describe('Login', () => {

const loginForm = mount(
<Provider store={ store }>
<LoginForm setAccount={ setAccount } account={ { wif: '' } } accounts={ validAccount } setBalance={ jest.fn } />
<LoginForm
setAccount={ setAccount }
account={ { wif: '' } }
accounts={ validAccount }
setBalance={ jest.fn }
setTransactions={ jest.fn }
/>
</Provider>
)

Expand All @@ -97,7 +116,13 @@ describe('Login', () => {

const loginForm = mount(
<Provider store={ store }>
<LoginForm setAccount={ jest.fn } account={ { wif: '' } } accounts={ validAccount } setBalance={ jest.fn } />
<LoginForm
setAccount={ jest.fn }
account={ { wif: '' } }
accounts={ validAccount }
setBalance={ jest.fn }
setTransactions={ jest.fn }
/>
</Provider>
)
loginForm.find('input[name="passPhrase"]').simulate('change', { target: { id: 'passPhrase', value: 'wrong' } })
Expand Down
75 changes: 51 additions & 24 deletions __tests__/containers/Send.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react'
import { Provider } from 'react-redux'
import { mount } from 'enzyme'
import { api } from '@cityofzion/neon-js'
import Neon from '@cityofzion/neon-js'
import { createStore, combineReducers } from 'redux'
import { reducer as formReducer } from 'redux-form'

Expand All @@ -16,33 +16,50 @@ const setup = () => {
},
account: {
wif: testKeys.t1.wif,
address: testKeys.t1.address,
},
accounts: {
[testKeys['t1']['address']]: {
address: testKeys.t1.address,
label: 'My account',
},
},
setBalance: () => {},
label: 'Somelabel',
address: testKeys.t1.address,
}

const store = createStore(combineReducers({ form: formReducer }))
const wrapper = mount(<Provider store={ store }><SendForm { ...props } /></Provider>)
const wrapper = mount(
<Provider store={ store }>
<SendForm { ...props } />
</Provider>
)

return {
wrapper,
}
}

describe('Send', () => {
test('Amount passed to neon-js correctly', async (done) => {
test('Amount passed to neon-js correctly', async done => {
const { wrapper } = setup()

wrapper.find('input[name="address"]').simulate('change', { target: { name: 'address', value: testKeys.t1.address } })
wrapper
.find('input[name="address"]')
.simulate('change', { target: { name: 'address', value: testKeys.t1.address } })
wrapper.find('input[name="amount"]').simulate('change', { target: { name: 'amount', value: '2.00000001' } })
wrapper.find('select').simulate('change', { target: { value: 'GAS' } })

api.neoscan.doSendAsset = jest.fn((net, address, wif, amounts) => {
Neon.do.sendAsset = jest.fn((net, address, wif, amounts) => {
return new Promise((resolve, reject) => {
expect(amounts['GAS']).toEqual(2.00000001)
done()
})
})

wrapper.find('form').simulate('submit')
wrapper.find('.confirmSendCardAcceptButton').simulate('click')
})

test('Address must be valid', async () => {
Expand All @@ -54,7 +71,7 @@ describe('Send', () => {
wrapper.find('form').simulate('submit')

const sendState = wrapper.find(Send).instance().state
expect(sendState.errorMsg).toEqual('The address you entered was not valid.')
expect(sendState.errors.address).toEqual('The address you entered was not valid.')
})

test('Address must not be empty', async () => {
Expand All @@ -66,68 +83,78 @@ describe('Send', () => {
wrapper.find('form').simulate('submit')

const sendState = wrapper.find(Send).instance().state
expect(sendState.errorMsg).toEqual('Address field is required')
expect(sendState.errors.address).toEqual('Address field is required')
})

test('Amount must not be empty', async () => {
const { wrapper } = setup()

wrapper.find('input[name="address"]').simulate('change', { target: { name: 'address', value: testKeys.t1.address } })
wrapper
.find('input[name="address"]')
.simulate('change', { target: { name: 'address', value: testKeys.t1.address } })
wrapper.find('input[name="amount"]').simulate('change', { target: { name: 'amount', value: '' } })

wrapper.find('form').simulate('submit')

const sendState = wrapper.find(Send).instance().state
expect(sendState.errorMsg).toEqual('Amount field is required')
expect(sendState.errors.amount).toEqual('Amount field is required')
})

test('Amount must be numeric', async () => {
const { wrapper } = setup()

wrapper.find('input[name="address"]').simulate('change', { target: { name: 'address', value: testKeys.t1.address } })
wrapper
.find('input[name="address"]')
.simulate('change', { target: { name: 'address', value: testKeys.t1.address } })
wrapper.find('input[name="amount"]').simulate('change', { target: { name: 'amount', value: 'a' } })

wrapper.find('form').simulate('submit')

const sendState = wrapper.find(Send).instance().state
expect(sendState.errorMsg).toEqual('You must enter a valid number.')
expect(sendState.errors.amount).toEqual('You must enter a valid number.')
})

test('Amount must be positive', async () => {
const { wrapper } = setup()

wrapper.find('input[name="address"]').simulate('change', { target: { name: 'address', value: testKeys.t1.address } })
wrapper
.find('input[name="address"]')
.simulate('change', { target: { name: 'address', value: testKeys.t1.address } })
wrapper.find('input[name="amount"]').simulate('change', { target: { name: 'amount', value: '-1' } })

wrapper.find('form').simulate('submit')

const sendState = wrapper.find(Send).instance().state
expect(sendState.errorMsg).toEqual('You cannot send zero or negative amounts of an asset.')
expect(sendState.errors.amount).toEqual('You cannot send zero or negative amounts of an asset.')
})

test('Amount must be whole number if sending NEO', async () => {
const { wrapper } = setup()

wrapper.find('input[name="address"]').simulate('change', { target: { name: 'address', value: testKeys.t1.address } })
wrapper
.find('input[name="address"]')
.simulate('change', { target: { name: 'address', value: testKeys.t1.address } })
wrapper.find('input[name="amount"]').simulate('change', { target: { name: 'amount', value: '1.01' } })
wrapper.find('select').simulate('change', { target: { value: 'NEO' } })

wrapper.find('form').simulate('submit')

const sendState = wrapper.find(Send).instance().state
expect(sendState.errorMsg).toEqual('You cannot send fractional amounts of NEO.')
expect(sendState.errors.amount).toEqual('You cannot send fractional amounts of NEO.')
})

test('Asset type must be valid', async () => {
const { wrapper } = setup()
// test('Asset type must be valid', async () => {
// const { wrapper } = setup()

wrapper.find('input[name="address"]').simulate('change', { target: { name: 'address', value: testKeys.t1.address } })
wrapper.find('input[name="amount"]').simulate('change', { target: { name: 'amount', value: '1' } })
wrapper.find('select').simulate('change', { target: { value: 'INVALID' } })
// wrapper
// .find('input[name="address"]')
// .simulate('change', { target: { name: 'address', value: testKeys.t1.address } })
// wrapper.find('input[name="amount"]').simulate('change', { target: { name: 'amount', value: '1' } })
// wrapper.find('select').simulate('change', { target: { value: 'INVALID' } })

wrapper.find('form').simulate('submit')
// wrapper.find('form').simulate('submit')

const sendState = wrapper.find(Send).instance().state
expect(sendState.errorMsg).toEqual('Asset Type invalid.')
})
// const sendState = wrapper.find(Send).instance().state
// expect(sendState.errorMsg).toEqual('Asset Type invalid.')
// })
})
7 changes: 7 additions & 0 deletions src/app/components/AccountInfo/AccountInfo.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
align-items: center;
}

.accountInfoNoOptions {
display: flex;
justify-content: center;
align-items: center;
}

.accountInfoDetails {
width: 70%;
}
Expand Down Expand Up @@ -145,4 +151,5 @@
border: none;
color: #585858;
position: absolute;
cursor: pointer;
}
64 changes: 33 additions & 31 deletions src/app/components/AccountInfo/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,46 +18,49 @@ const AccountInfo = ({
getBalance,
showDropDown,
toggleDropDownMenu,
network,
updateBalance,
showOptions,
}) => {
let dropDownClasses = showDropDown
? `${style.accountInfoDropDown} ${style.accountInfoDropDownActive}`
: style.accountInfoDropDown

let accountDetailsClasses = showOptions ? style.accountInfo : style.accountInfoNoOptions
return (
<Fragment>
<div className={ style.accountInfo }>
<div className={ accountDetailsClasses }>
<div className={ style.accountInfoImageContainer }>
<img src={ neonPNG } alt='Neo' />
</div>
<div className={ style.accountInfoDetails }>
<h2 className={ style.accountInfoDetailsHeading }>{label}</h2>
<p className={ style.accountInfoDetailsParagraph }>{address}</p>
</div>
<div className={ style.accountInfoDropDownContainer }>
<button className={ style.accountDropDownButton } onClick={ toggleDropDownMenu }>
<i className='fa fa-ellipsis-v' />
</button>
<div className={ dropDownClasses }>
<ul className={ style.accountInfoDropDownList }>
<li className={ style.accountInfoDropDownListItem }>
<Link to='/send' className={ style.dropDownLinks }>
<i className='fas fa-paper-plane' />Send
</Link>
</li>
<li className={ style.accountInfoDropDownListItem }>
<Link to={ `https://neoscan.io/address/${address}` } target='_blank' className={ style.dropDownLinks }>
<i className='fas fa-eye' />View on Neoscan
</Link>
</li>
<li className={ style.accountInfoDropDownListItem }>
<button className={ style.dropDownLinksButton } onClick={ onClickHandler }>
<i className='fas fa-pencil-alt' />Rename
</button>
</li>
</ul>
{showOptions && (
<div className={ style.accountInfoDropDownContainer }>
<button className={ style.accountDropDownButton } onClick={ toggleDropDownMenu }>
<i className='fa fa-ellipsis-v' />
</button>
<div className={ dropDownClasses }>
<ul className={ style.accountInfoDropDownList }>
<li className={ style.accountInfoDropDownListItem }>
<Link to='/send' className={ style.dropDownLinks }>
<i className='fas fa-paper-plane' />Send
</Link>
</li>
<li className={ style.accountInfoDropDownListItem }>
<Link to={ `https://neoscan.io/address/${address}` } target='_blank' className={ style.dropDownLinks }>
<i className='fas fa-eye' />View on Neoscan
</Link>
</li>
<li className={ style.accountInfoDropDownListItem }>
<button className={ style.dropDownLinksButton } onClick={ onClickHandler }>
<i className='fas fa-pencil-alt' />Rename
</button>
</li>
</ul>
</div>
</div>
</div>
)}
</div>

{amountsError ? (
Expand All @@ -71,7 +74,7 @@ const AccountInfo = ({
<img src={ neonPNG } alt='Neo' className={ style.accountInfoNeoAmountImg } />
<p className={ style.accountInfoAmountParagraph }>{neo} NEO</p>
</div>
<button className={ style.accountInfoRefreshButton } onClick={ () => updateBalance(network) }>
<button className={ style.accountInfoRefreshButton } onClick={ getBalance }>
<i className='fas fa-sync' />
</button>
<div className={ style.accountInfoGasAmount }>
Expand All @@ -86,16 +89,15 @@ const AccountInfo = ({

AccountInfo.propTypes = {
label: PropTypes.string.isRequired,
showOptions: PropTypes.bool,
onClickHandler: PropTypes.func,
getBalance: PropTypes.func,
neo: PropTypes.number,
gas: PropTypes.number,
address: PropTypes.string.isRequired,
amountsError: PropTypes.string,
showDropDown: PropTypes.bool.isRequired,
toggleDropDownMenu: PropTypes.func.isRequired,
network: PropTypes.string.isRequired,
updateBalance: PropTypes.func.isRequired,
showDropDown: PropTypes.bool,
toggleDropDownMenu: PropTypes.func,
}

export default AccountInfo
Loading

0 comments on commit d316365

Please sign in to comment.