Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Additional building-block UI components #4239

Merged
merged 7 commits into from
Jan 20, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@
"phoneformat.js": "1.0.3",
"promise-worker": "1.1.1",
"push.js": "0.0.11",
"qrcode-npm": "0.0.3",
"qs": "6.3.0",
"react": "15.4.1",
"react-ace": "4.1.0",
Expand Down
67 changes: 67 additions & 0 deletions js/src/ui/CurrencySymbol/currencySymbol.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
// This file is part of Parity.

// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.

import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';

const SYMBOL_ETC = 'ETC';
const SYMBOL_ETH = 'ETH';
const SYMBOL_EXP = 'EXP';

class CurrencySymbol extends Component {
static propTypes = {
className: PropTypes.string,
netChain: PropTypes.string.isRequired,
netSymbol: PropTypes.string.isRequired
}

render () {
const { className, netSymbol } = this.props;

return (
<span className={ className }>{ netSymbol }</span>
);
}
}

function mapStateToProps (state) {
const { netChain } = state.nodeStatus;
let netSymbol;

switch (netChain) {
case 'classic':
netSymbol = SYMBOL_ETC;
break;

case 'expanse':
netSymbol = SYMBOL_EXP;
break;

default:
netSymbol = SYMBOL_ETH;
break;
}

return {
netChain,
netSymbol
};
}

export default connect(
mapStateToProps,
null
)(CurrencySymbol);
81 changes: 81 additions & 0 deletions js/src/ui/CurrencySymbol/currencySymbol.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
// This file is part of Parity.

// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.

import { shallow } from 'enzyme';
import React from 'react';
import sinon from 'sinon';

import CurrencySymbol from './';

let component;
let store;

function createRedux (netChain = 'ropsten') {
store = {
dispatch: sinon.stub(),
subscribe: sinon.stub(),
getState: () => {
return {
nodeStatus: {
netChain
}
};
}
};

return store;
}

function render (netChain, props = {}) {
component = shallow(
<CurrencySymbol { ...props } />,
{
context: {
store: createRedux(netChain)
}
}
).find('CurrencySymbol').shallow();

return component;
}

describe('ui/CurrencySymbol', () => {
it('renders defaults', () => {
expect(render()).to.be.ok;
});

it('passes the className as provided', () => {
expect(render('ropsten', { className: 'test' }).find('span').hasClass('test')).to.be.true;
});

describe('currencies', () => {
it('renders ETH as default', () => {
expect(render().text()).equal('ETH');
});

it('renders ETC for classic', () => {
expect(render('classic').text()).equal('ETC');
});

it('renders EXP for expanse', () => {
expect(render('expanse').text()).equal('EXP');
});

it('renders ETH as default', () => {
expect(render('somethingElse').text()).equal('ETH');
});
});
});
17 changes: 17 additions & 0 deletions js/src/ui/CurrencySymbol/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
// This file is part of Parity.

// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.

export default from './currencySymbol';
17 changes: 17 additions & 0 deletions js/src/ui/QrCode/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
// This file is part of Parity.

// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.

export default from './qrCode';
83 changes: 83 additions & 0 deletions js/src/ui/QrCode/qrCode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
// This file is part of Parity.

// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.

// https://github.com/cmanzana/qrcode-npm packaging the standard
// https://github.com/kazuhikoarase/qrcode-generator
import { qrcode } from 'qrcode-npm';
import React, { Component, PropTypes } from 'react';

const QROPTS = {
CODE_TYPE: 4,
ERROR_LEVEL: 'M'
};

export default class QrCode extends Component {
static propTypes = {
className: PropTypes.string,
margin: PropTypes.number,
size: PropTypes.number,
value: PropTypes.string.isRequired
};

static defaultProps = {
margin: 2,
size: 5
};

state = {
image: null
};

componentWillMount () {
this.generateCode(this.props);
}

componentWillReceiveProps (nextProps) {
const hasChanged = nextProps.value !== this.props.value ||
nextProps.size !== this.props.size ||
nextProps.margin !== this.props.margin;

if (hasChanged) {
this.generateCode(nextProps);
}
}

render () {
const { className } = this.props;
const { image } = this.state;

return (
<div
className={ className }
dangerouslySetInnerHTML={ {
__html: image
} }
/>
);
}

generateCode (props) {
const { margin, size, value } = props;
const qr = qrcode(QROPTS.CODE_TYPE, QROPTS.ERROR_LEVEL);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't this be taken out of the function?

Copy link
Contributor Author

@jacogr jacogr Jan 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can test when in used to see if we can further optimise it, however should be more than ok as-is since it is not going to crazy generating, only does so when props change.

(Don't want to go down the route and assume too much in the actual library atm. Small enough to read fully, but rather verify properly since I had the same concern, but since we add data and generate it may not clear the state between uses.)

As for testing, there is the features PR that can allow for playground.


qr.addData(value);
qr.make();

this.setState({
image: qr.createImgTag(size, margin)
});
}
}
108 changes: 108 additions & 0 deletions js/src/ui/QrCode/qrCode.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
// This file is part of Parity.

// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.

import { shallow } from 'enzyme';
import React from 'react';
import sinon from 'sinon';

import QrCode from './';

const DEFAULT_PROPS = {
margin: 1,
size: 4,
value: 'someTestValue'
};

let component;
let instance;

function render (props = {}) {
component = shallow(
<QrCode
{ ...DEFAULT_PROPS }
{ ...props }
/>
);
instance = component.instance();

return component;
}

describe('ui/QrCode', () => {
beforeEach(() => {
render();
sinon.spy(instance, 'generateCode');
});

afterEach(() => {
instance.generateCode.restore();
});

it('renders defaults', () => {
expect(component).to.be.ok;
});

describe('lifecycle', () => {
describe('componentWillMount', () => {
it('generates the image on mount', () => {
instance.componentWillMount();
expect(instance.generateCode).to.have.been.calledWith(DEFAULT_PROPS);
});
});

describe('componentWillReceiveProps', () => {
it('does not re-generate when no props changed', () => {
instance.componentWillReceiveProps(DEFAULT_PROPS);
expect(instance.generateCode).not.to.have.been.called;
});

it('does not re-generate when className changed', () => {
const nextProps = Object.assign({}, DEFAULT_PROPS, { className: 'test' });

instance.componentWillReceiveProps(nextProps);
expect(instance.generateCode).not.to.have.been.called;
});

it('does not re-generate when additional property changed', () => {
const nextProps = Object.assign({}, DEFAULT_PROPS, { something: 'test' });

instance.componentWillReceiveProps(nextProps);
expect(instance.generateCode).not.to.have.been.called;
});

it('does re-generate when value changed', () => {
const nextProps = Object.assign({}, DEFAULT_PROPS, { value: 'somethingElse' });

instance.componentWillReceiveProps(nextProps);
expect(instance.generateCode).to.have.been.calledWith(nextProps);
});

it('does re-generate when size changed', () => {
const nextProps = Object.assign({}, DEFAULT_PROPS, { size: 10 });

instance.componentWillReceiveProps(nextProps);
expect(instance.generateCode).to.have.been.calledWith(nextProps);
});

it('does re-generate when margin changed', () => {
const nextProps = Object.assign({}, DEFAULT_PROPS, { margin: 10 });

instance.componentWillReceiveProps(nextProps);
expect(instance.generateCode).to.have.been.calledWith(nextProps);
});
});
});
});
Loading