Skip to content
This repository has been archived by the owner on Apr 15, 2019. It is now read-only.

Commit

Permalink
Merge pull request #534 from LiskHQ/516-click-to-send
Browse files Browse the repository at this point in the history
Implement click to send functionality in React - Closes #516
  • Loading branch information
slaweet authored Aug 2, 2017
2 parents 9b50d4e + 4cb6b53 commit 6598bdf
Show file tree
Hide file tree
Showing 10 changed files with 158 additions and 29 deletions.
2 changes: 1 addition & 1 deletion features/top.feature
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ Feature: Main page top area

Scenario: should show balance
Given I'm logged in as "empty account"
Then I should see text "0 LSK" in "balance" element
Then I should see text "0 LSK" in "balance value" element

23 changes: 14 additions & 9 deletions src/components/account/accountComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import styles from './account.css';
import Address from './address';
import LiskAmount from '../liskAmount';
import { getAccountStatus } from '../../utils/api/account';
import ClickToSend from '../send/clickToSend';
import { toRawLsk } from '../../utils/lsk';

/**
* Contains some of the important and basic information about the account
Expand Down Expand Up @@ -59,17 +61,20 @@ class AccountComponent extends React.Component {
</div>
</div>
</article>
<article className={grid['col-xs-4']}>
<article className={`${grid['col-xs-4']} balance`}>
<div className="box">
<h3 className={styles.title}>Balance</h3>
<div className={styles['value-wrapper']}>
<p className="inner primary full hasTip balance">
<LiskAmount val={this.props.account.balance} /> LSK
</p>
<p className="inner secondary tooltip">
Click to send all funds
</p>
</div>
<ClickToSend
rawAmount={Math.max(0, this.props.account.balance - toRawLsk(0.1))} >
<div className={styles['value-wrapper']}>
<p className="inner primary full hasTip balance-value">
<LiskAmount val={this.props.account.balance} /> LSK
</p>
<p className="inner secondary tooltip">
Click to send all funds
</p>
</div>
</ClickToSend>
</div>
</article>
</section>
Expand Down
23 changes: 14 additions & 9 deletions src/components/account/accountComponent.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import chai, { expect } from 'chai';
import { spy } from 'sinon';
import sinonChai from 'sinon-chai';
import { shallow, mount } from 'enzyme';
import { Provider } from 'react-redux';
import store from '../../store';
import AccountComponent from './accountComponent';
import ClickToSend from '../send/clickToSend';

chai.use(sinonChai);

Expand All @@ -26,6 +29,7 @@ describe('AccountComponent', () => {
isDelegate: false,
address: '16313739661670634666L',
username: 'lisk-nano',
balance: 1e8,
};

it(' should render 3 article tags', () => {
Expand All @@ -42,25 +46,26 @@ describe('AccountComponent', () => {
expect(wrapper.find('.material-icons').text()).to.be.equal(expectedValue);
});

it('depicts being offline when peers.offline is false', () => {
const wrapper = shallow(<AccountComponent account={testAccount} peers={peers}
onActivePeerUpdated={onActivePeerUpdated} />);
const expectedValue = 'error';
expect(wrapper.find('.material-icons').text()).to.be.equal(expectedValue);
it('should render balance with ClickToSend component', () => {
const wrapper = mount(<Provider store={store}>
<AccountComponent account={testAccount} peers={peers}
onActivePeerUpdated={onActivePeerUpdated} />
</Provider>);
expect(wrapper.find('.balance').find(ClickToSend)).to.have.lengthOf(1);
});

describe('componentDidMount', () => {
it('should be called once', () => {
const actionSpy = spy(AccountComponent.prototype, 'componentDidMount');
mount(<AccountComponent account={testAccount} peers={peers}
onActivePeerUpdated={onActivePeerUpdated} />);
mount(<Provider store={store}><AccountComponent account={testAccount} peers={peers}
onActivePeerUpdated={onActivePeerUpdated} /></Provider>);
expect(actionSpy).to.have.been.calledWith();
});

it('binds listener to beat event', () => {
const actionSpy = spy(document, 'addEventListener');
mount(<AccountComponent account={testAccount} peers={peers}
onActivePeerUpdated={onActivePeerUpdated} />);
mount(<Provider store={store}><AccountComponent account={testAccount} peers={peers}
onActivePeerUpdated={onActivePeerUpdated} /></Provider>);
expect(actionSpy).to.have.been.calledWith();
});
});
Expand Down
15 changes: 15 additions & 0 deletions src/components/send/clickToSend.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { connect } from 'react-redux';
import { dialogDisplayed } from '../../actions/dialog';
import ClickToSendComponent from './clickToSendComponent';


const mapDispatchToProps = dispatch => ({
setActiveDialog: data => dispatch(dialogDisplayed(data)),
});

const ClickToSend = connect(
null,
mapDispatchToProps,
)(ClickToSendComponent);

export default ClickToSend;
19 changes: 19 additions & 0 deletions src/components/send/clickToSend.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';
import { expect } from 'chai';
import { mount } from 'enzyme';
import { Provider } from 'react-redux';
import ClickToSend from './clickToSend';
import store from '../../store';


describe('Send Container', () => {
let wrapper;

beforeEach(() => {
wrapper = mount(<Provider store={store}><ClickToSend /></Provider>);
});

it('should render ClickToSendComponent', () => {
expect(wrapper.find('ClickToSendComponent')).to.have.lengthOf(1);
});
});
23 changes: 23 additions & 0 deletions src/components/send/clickToSendComponent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';
import styles from './send.css';
import Send from '../send';
import { fromRawLsk } from '../../utils/lsk';


const ClickToSendComponent = props => (
props.disabled ?
props.children :
<span className={styles.clickable}
onClick={() => (props.setActiveDialog({
title: 'Send',
childComponent: Send,
childComponentProps: {
amount: props.rawAmount ? fromRawLsk(props.rawAmount) : props.amount,
recipient: props.recipient,
},
}))}>
{props.children}
</span>
);

export default ClickToSendComponent;
46 changes: 46 additions & 0 deletions src/components/send/clickToSendComponent.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from 'react';
import chai, { expect } from 'chai';
import { mount } from 'enzyme';
import chaiEnzyme from 'chai-enzyme';
import sinon from 'sinon';
import sinonChai from 'sinon-chai';
import ClickToSendComponent from './clickToSendComponent';

const Dummy = () => (<span />);

chai.use(sinonChai);
chai.use(chaiEnzyme()); // Note the invocation at the end
describe('ClickToSendComponent', () => {
let setActiveDialog;

beforeEach(() => {
setActiveDialog = sinon.spy();
});

it('allows open send modal with prefilled address ', () => {
const wrapper = mount(
<ClickToSendComponent address='16313739661670634666L'
setActiveDialog={setActiveDialog}><Dummy /></ClickToSendComponent>);
wrapper.simulate('click');
expect(setActiveDialog).to.have.been.calledWith();
expect(wrapper.find('Dummy')).to.have.length(1);
});

it('allows open send modal with prefilled rawAmount ', () => {
const wrapper = mount(
<ClickToSendComponent rawAmount='100000000'
setActiveDialog={setActiveDialog}><Dummy /></ClickToSendComponent>);
wrapper.simulate('click');
expect(setActiveDialog).to.have.been.calledWith();
expect(wrapper.find('Dummy')).to.have.length(1);
});

it('should do nothing if props.disabled', () => {
const wrapper = mount(
<ClickToSendComponent disabled={true}
setActiveDialog={setActiveDialog}><Dummy />
</ClickToSendComponent>);
wrapper.simulate('click');
expect(wrapper.find('Dummy')).to.have.length(1);
});
});
4 changes: 4 additions & 0 deletions src/components/send/send.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@
line-height: 14px;
color: grey;
}

.clickable {
cursor: pointer;
}
24 changes: 16 additions & 8 deletions src/components/transactions/amount.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,29 @@ import React from 'react';
import styles from './transactions.css';
import LiskAmount from '../liskAmount';
import { TooltipWrapper } from '../timestamp';
import ClickToSend from '../send/clickToSend';

const Amount = (props) => {
let template = null;
let tooltipText = null;
const amount = <LiskAmount val={props.value.amount} />;
const params = {};
if (props.value.type === 0 &&
props.value.senderId === props.value.recipientId) {
template = <span className={styles.grayButton}>{amount}</span>;
params.className = 'grayButton';
} else if (props.value.senderId !== props.address) {
template = <span className={styles.inButton}>{amount}</span>;
params.className = 'inButton';
} else if (props.value.type !== 0 || props.value.recipientId !== props.address) {
template = <span className={styles.outButton}>{amount}</span>;
tooltipText = 'Repeat the transaction';
params.className = 'outButton';
params.tooltipText = 'Repeat the transaction';
params.clickToSendEnabled = true;
}
return <TooltipWrapper tooltip={tooltipText}>{template}</TooltipWrapper>;
return <TooltipWrapper tooltip={params.tooltipText} >
<ClickToSend rawAmount={props.value.amount}
recipient={props.value.recipientId}
disabled={!params.clickToSendEnabled}>
<span className={styles[params.className]}>
<LiskAmount val={props.value.amount} />
</span>
</ClickToSend>
</TooltipWrapper>;
};
// <FormattedNumber val={props.value.fee}></FormattedNumber>
export default Amount;
8 changes: 6 additions & 2 deletions src/components/transactions/transactionType.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { TooltipWrapper } from '../timestamp';
import sytles from './transactions.css';
import ClickToSend from '../send/clickToSend';

const TransactionType = (props) => {
let type;
Expand Down Expand Up @@ -30,8 +31,11 @@ const TransactionType = (props) => {
type = false;
break;
}
const template = type ? <span className={sytles.smallButton}>{type}</span>
: <TooltipWrapper tooltip="Send to this recipient">{props.senderId}</TooltipWrapper>;
const template = type ?
<span className={sytles.smallButton}>{type}</span> :
<ClickToSend recipient={props.senderId} >
<TooltipWrapper tooltip="Send to this recipient">{props.senderId}</TooltipWrapper>
</ClickToSend>;
return template;
};

Expand Down

0 comments on commit 6598bdf

Please sign in to comment.