implement basic badges/certifications/flair (#3665)
* sms verification: Certifications component
* sms verification: actions & reducers for certifications
* sms verification: put Certifications component into place
* sms verification: show certification icons
* sms verification: show certification titles
* sms verification: default icon for certifications
* sms verificaiton: lint issue 👕, fix testnet detection
The sms verification store got created when `isTestnet` (from the
Redux state) was still `undefined`.
* move certification helpers into middleware file
* connect Certifications to Redux
* don't pass certifications as prop
* move default certification icon into assets
* separate file for BadgeReg.sol
* don't pass certifications as prop
* Fix import name
* make BadgeReg a class
* make certifications middleware a class
* Certifications: pass in certifications of account
This commit is contained in:
parent
837ff1bc7d
commit
784dcaff7c
4
js/assets/images/certifications/unknown.svg
Normal file
4
js/assets/images/certifications/unknown.svg
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle fill="#4A90E2" cx="50" cy="50" r="50"/>
|
||||||
|
<path d="M20 45 L10 55 L35 85 L90 35 L80 25 L36 65 z" fill="#FFF"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 213 B |
1
js/src/contracts/abi/badgereg.json
Normal file
1
js/src/contracts/abi/badgereg.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_addr","type":"address"},{"name":"_name","type":"bytes32"}],"name":"register","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"fromName","outputs":[{"name":"id","type":"uint256"},{"name":"addr","type":"address"},{"name":"owner","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"badgeCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_fee","type":"uint256"}],"name":"setFee","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_id","type":"uint256"},{"name":"_key","type":"bytes32"}],"name":"meta","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"drain","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_id","type":"uint256"}],"name":"unregister","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_addr","type":"address"}],"name":"fromAddress","outputs":[{"name":"id","type":"uint256"},{"name":"name","type":"bytes32"},{"name":"owner","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_id","type":"uint256"}],"name":"badge","outputs":[{"name":"addr","type":"address"},{"name":"name","type":"bytes32"},{"name":"owner","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_id","type":"uint256"},{"name":"_key","type":"bytes32"},{"name":"_value","type":"bytes32"}],"name":"setMeta","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_addr","type":"address"},{"name":"_name","type":"bytes32"},{"name":"_owner","type":"address"}],"name":"registerAs","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"fee","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"},{"indexed":true,"name":"id","type":"uint256"},{"indexed":false,"name":"addr","type":"address"}],"name":"Registered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"},{"indexed":true,"name":"id","type":"uint256"}],"name":"Unregistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"id","type":"uint256"},{"indexed":true,"name":"key","type":"bytes32"},{"indexed":false,"name":"value","type":"bytes32"}],"name":"MetaChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"old","type":"address"},{"indexed":true,"name":"current","type":"address"}],"name":"NewOwner","type":"event"}]
|
1
js/src/contracts/abi/certifier.json
Normal file
1
js/src/contracts/abi/certifier.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
[{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"}],"name":"certified","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"get","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Confirmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"who","type":"address"}],"name":"Revoked","type":"event"}]
|
@ -14,6 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import badgereg from './badgereg.json';
|
||||||
import basiccoin from './basiccoin.json';
|
import basiccoin from './basiccoin.json';
|
||||||
import basiccoinmanager from './basiccoinmanager.json';
|
import basiccoinmanager from './basiccoinmanager.json';
|
||||||
import dappreg from './dappreg.json';
|
import dappreg from './dappreg.json';
|
||||||
@ -28,6 +29,7 @@ import tokenreg from './tokenreg.json';
|
|||||||
import wallet from './wallet.json';
|
import wallet from './wallet.json';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
badgereg,
|
||||||
basiccoin,
|
basiccoin,
|
||||||
basiccoinmanager,
|
basiccoinmanager,
|
||||||
dappreg,
|
dappreg,
|
||||||
|
66
js/src/contracts/badgereg.js
Normal file
66
js/src/contracts/badgereg.js
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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 { bytesToHex, hex2Ascii } from '../api/util/format';
|
||||||
|
|
||||||
|
import ABI from './abi/certifier.json';
|
||||||
|
|
||||||
|
const ZERO = '0x0000000000000000000000000000000000000000000000000000000000000000';
|
||||||
|
|
||||||
|
export default class BadgeReg {
|
||||||
|
constructor (api, registry) {
|
||||||
|
this._api = api;
|
||||||
|
this._registry = registry;
|
||||||
|
|
||||||
|
registry.getContract('badgereg');
|
||||||
|
this.certifiers = {}; // by name
|
||||||
|
this.contracts = {}; // by name
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchCertifier (name) {
|
||||||
|
if (this.certifiers[name]) {
|
||||||
|
return Promise.resolve(this.certifiers[name]);
|
||||||
|
}
|
||||||
|
return this._registry.getContract('badgereg')
|
||||||
|
.then((badgeReg) => {
|
||||||
|
return badgeReg.instance.fromName.call({}, [name])
|
||||||
|
.then(([ id, address ]) => {
|
||||||
|
return Promise.all([
|
||||||
|
badgeReg.instance.meta.call({}, [id, 'TITLE']),
|
||||||
|
badgeReg.instance.meta.call({}, [id, 'IMG'])
|
||||||
|
])
|
||||||
|
.then(([ title, img ]) => {
|
||||||
|
title = bytesToHex(title);
|
||||||
|
title = title === ZERO ? null : hex2Ascii(title);
|
||||||
|
if (bytesToHex(img) === ZERO) img = null;
|
||||||
|
|
||||||
|
const data = { address, name, title, icon: img };
|
||||||
|
this.certifiers[name] = data;
|
||||||
|
return data;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
checkIfCertified (certifier, address) {
|
||||||
|
if (!this.contracts[certifier]) {
|
||||||
|
this.contracts[certifier] = this._api.newContract(ABI, certifier);
|
||||||
|
}
|
||||||
|
const contract = this.contracts[certifier];
|
||||||
|
|
||||||
|
return contract.instance.certified.call({}, [address]);
|
||||||
|
}
|
||||||
|
}
|
@ -20,6 +20,7 @@ import SignatureReg from './signaturereg';
|
|||||||
import TokenReg from './tokenreg';
|
import TokenReg from './tokenreg';
|
||||||
import GithubHint from './githubhint';
|
import GithubHint from './githubhint';
|
||||||
import * as smsVerification from './sms-verification';
|
import * as smsVerification from './sms-verification';
|
||||||
|
import BadgeReg from './badgereg';
|
||||||
|
|
||||||
let instance = null;
|
let instance = null;
|
||||||
|
|
||||||
@ -33,6 +34,7 @@ export default class Contracts {
|
|||||||
this._signaturereg = new SignatureReg(api, this._registry);
|
this._signaturereg = new SignatureReg(api, this._registry);
|
||||||
this._tokenreg = new TokenReg(api, this._registry);
|
this._tokenreg = new TokenReg(api, this._registry);
|
||||||
this._githubhint = new GithubHint(api, this._registry);
|
this._githubhint = new GithubHint(api, this._registry);
|
||||||
|
this.badgeReg = new BadgeReg(api, this._registry);
|
||||||
}
|
}
|
||||||
|
|
||||||
get registry () {
|
get registry () {
|
||||||
|
@ -20,17 +20,20 @@ import SettingsMiddleware from '../views/Settings/middleware';
|
|||||||
import SignerMiddleware from './providers/signerMiddleware';
|
import SignerMiddleware from './providers/signerMiddleware';
|
||||||
|
|
||||||
import statusMiddleware from '../views/Status/middleware';
|
import statusMiddleware from '../views/Status/middleware';
|
||||||
|
import CertificationsMiddleware from './providers/certifications/middleware';
|
||||||
|
|
||||||
export default function (api) {
|
export default function (api) {
|
||||||
const errors = new ErrorsMiddleware();
|
const errors = new ErrorsMiddleware();
|
||||||
const signer = new SignerMiddleware(api);
|
const signer = new SignerMiddleware(api);
|
||||||
const settings = new SettingsMiddleware();
|
const settings = new SettingsMiddleware();
|
||||||
const status = statusMiddleware();
|
const status = statusMiddleware();
|
||||||
|
const certifications = new CertificationsMiddleware();
|
||||||
|
|
||||||
const middleware = [
|
const middleware = [
|
||||||
settings.toMiddleware(),
|
settings.toMiddleware(),
|
||||||
signer.toMiddleware(),
|
signer.toMiddleware(),
|
||||||
errors.toMiddleware()
|
errors.toMiddleware(),
|
||||||
|
certifications.toMiddleware()
|
||||||
];
|
];
|
||||||
|
|
||||||
return middleware.concat(status, thunk);
|
return middleware.concat(status, thunk);
|
||||||
|
23
js/src/redux/providers/certifications/actions.js
Normal file
23
js/src/redux/providers/certifications/actions.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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 const fetchCertifications = (address) => ({
|
||||||
|
type: 'fetchCertifications', address
|
||||||
|
});
|
||||||
|
|
||||||
|
export const addCertification = (address, name, title, icon) => ({
|
||||||
|
type: 'addCertification', address, name, title, icon
|
||||||
|
});
|
51
js/src/redux/providers/certifications/middleware.js
Normal file
51
js/src/redux/providers/certifications/middleware.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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 Contracts from '../../../contracts';
|
||||||
|
import { addCertification } from './actions';
|
||||||
|
|
||||||
|
const knownCertifiers = [ 'smsverification' ];
|
||||||
|
|
||||||
|
export default class CertificationsMiddleware {
|
||||||
|
toMiddleware () {
|
||||||
|
return (store) => (next) => (action) => {
|
||||||
|
if (action.type !== 'fetchCertifications') {
|
||||||
|
return next(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { address } = action;
|
||||||
|
const badgeReg = Contracts.get().badgeReg;
|
||||||
|
|
||||||
|
knownCertifiers.forEach((name) => {
|
||||||
|
badgeReg.fetchCertifier(name)
|
||||||
|
.then((cert) => {
|
||||||
|
return badgeReg.checkIfCertified(cert.address, address)
|
||||||
|
.then((isCertified) => {
|
||||||
|
if (isCertified) {
|
||||||
|
const { name, title, icon } = cert;
|
||||||
|
store.dispatch(addCertification(address, name, title, icon));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
if (err) {
|
||||||
|
console.error(`Failed to check if ${address} certified by ${name}:`, err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
33
js/src/redux/providers/certifications/reducer.js
Normal file
33
js/src/redux/providers/certifications/reducer.js
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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/>.
|
||||||
|
|
||||||
|
const initialState = {};
|
||||||
|
|
||||||
|
export default (state = initialState, action) => {
|
||||||
|
if (action.type !== 'addCertification') {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { address, name, icon, title } = action;
|
||||||
|
const certifications = state[address] || [];
|
||||||
|
|
||||||
|
if (certifications.some((c) => c.name === name)) {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
const newCertifications = certifications.concat({ name, icon, title });
|
||||||
|
|
||||||
|
return { ...state, [address]: newCertifications };
|
||||||
|
};
|
@ -18,6 +18,7 @@ import { combineReducers } from 'redux';
|
|||||||
import { routerReducer } from 'react-router-redux';
|
import { routerReducer } from 'react-router-redux';
|
||||||
|
|
||||||
import { apiReducer, balancesReducer, blockchainReducer, compilerReducer, imagesReducer, personalReducer, signerReducer, statusReducer as nodeStatusReducer, snackbarReducer } from './providers';
|
import { apiReducer, balancesReducer, blockchainReducer, compilerReducer, imagesReducer, personalReducer, signerReducer, statusReducer as nodeStatusReducer, snackbarReducer } from './providers';
|
||||||
|
import certificationsReducer from './providers/certifications/reducer';
|
||||||
|
|
||||||
import errorReducer from '../ui/Errors/reducers';
|
import errorReducer from '../ui/Errors/reducers';
|
||||||
import settingsReducer from '../views/Settings/reducers';
|
import settingsReducer from '../views/Settings/reducers';
|
||||||
@ -32,6 +33,7 @@ export default function () {
|
|||||||
settings: settingsReducer,
|
settings: settingsReducer,
|
||||||
|
|
||||||
balances: balancesReducer,
|
balances: balancesReducer,
|
||||||
|
certifications: certificationsReducer,
|
||||||
blockchain: blockchainReducer,
|
blockchain: blockchainReducer,
|
||||||
compiler: compilerReducer,
|
compiler: compilerReducer,
|
||||||
images: imagesReducer,
|
images: imagesReducer,
|
||||||
|
46
js/src/ui/Certifications/certifications.css
Normal file
46
js/src/ui/Certifications/certifications.css
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/* Copyright 2015, 2016 Ethcore (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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.certifications {
|
||||||
|
margin-top: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.certification {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
margin-right: .5em;
|
||||||
|
padding: .3em .6em .2em 2.6em;
|
||||||
|
border-radius: 1em;
|
||||||
|
line-height: 1em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
background-color: rgba(255, 255, 255, 0.07);
|
||||||
|
}
|
||||||
|
|
||||||
|
.certification:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
position: absolute;
|
||||||
|
top: -.25em;
|
||||||
|
left: 0;
|
||||||
|
width: 2em;
|
||||||
|
height: 2em;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border-radius: 1em;
|
||||||
|
}
|
87
js/src/ui/Certifications/certifications.js
Normal file
87
js/src/ui/Certifications/certifications.js
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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';
|
||||||
|
import { bindActionCreators } from 'redux';
|
||||||
|
|
||||||
|
import { hashToImageUrl } from '../../redux/providers/imagesReducer';
|
||||||
|
import { fetchCertifications } from '../../redux/providers/certifications/actions';
|
||||||
|
|
||||||
|
import defaultIcon from '../../../assets/images/certifications/unknown.svg';
|
||||||
|
|
||||||
|
import styles from './certifications.css';
|
||||||
|
|
||||||
|
class Certifications extends Component {
|
||||||
|
static propTypes = {
|
||||||
|
account: PropTypes.string.isRequired,
|
||||||
|
certifications: PropTypes.array.isRequired,
|
||||||
|
dappsUrl: PropTypes.string.isRequired,
|
||||||
|
|
||||||
|
fetchCertifications: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillMount () {
|
||||||
|
const { account, fetchCertifications } = this.props;
|
||||||
|
fetchCertifications(account);
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { certifications } = this.props;
|
||||||
|
|
||||||
|
if (certifications.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.certifications }>
|
||||||
|
{ certifications.map(this.renderCertification) }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderCertification = (certification) => {
|
||||||
|
const { name, title, icon } = certification;
|
||||||
|
const { dappsUrl } = this.props;
|
||||||
|
|
||||||
|
const classNames = `${styles.certification} ${!icon ? styles.noIcon : ''}`;
|
||||||
|
const img = icon ? dappsUrl + hashToImageUrl(icon) : defaultIcon;
|
||||||
|
return (
|
||||||
|
<div className={ classNames } key={ name }>
|
||||||
|
<img className={ styles.icon } src={ img } />
|
||||||
|
<div className={ styles.text }>{ title || name }</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapStateToProps (_, initProps) {
|
||||||
|
const { account } = initProps;
|
||||||
|
|
||||||
|
return (state) => {
|
||||||
|
const certifications = state.certifications[account] || [];
|
||||||
|
return { certifications };
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapDispatchToProps (dispatch) {
|
||||||
|
return bindActionCreators({ fetchCertifications }, dispatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(Certifications);
|
17
js/src/ui/Certifications/index.js
Normal file
17
js/src/ui/Certifications/index.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (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 './certifications';
|
@ -23,6 +23,7 @@ import Badge from './Badge';
|
|||||||
import Balance from './Balance';
|
import Balance from './Balance';
|
||||||
import BlockStatus from './BlockStatus';
|
import BlockStatus from './BlockStatus';
|
||||||
import Button from './Button';
|
import Button from './Button';
|
||||||
|
import Certifications from './Certifications';
|
||||||
import ConfirmDialog from './ConfirmDialog';
|
import ConfirmDialog from './ConfirmDialog';
|
||||||
import Container, { Title as ContainerTitle } from './Container';
|
import Container, { Title as ContainerTitle } from './Container';
|
||||||
import ContextProvider from './ContextProvider';
|
import ContextProvider from './ContextProvider';
|
||||||
@ -55,6 +56,7 @@ export {
|
|||||||
Balance,
|
Balance,
|
||||||
BlockStatus,
|
BlockStatus,
|
||||||
Button,
|
Button,
|
||||||
|
Certifications,
|
||||||
ConfirmDialog,
|
ConfirmDialog,
|
||||||
Container,
|
Container,
|
||||||
ContainerTitle,
|
ContainerTitle,
|
||||||
|
@ -18,6 +18,7 @@ import React, { Component, PropTypes } from 'react';
|
|||||||
|
|
||||||
import { Balance, Container, ContainerTitle, IdentityIcon, IdentityName, Tags } from '../../../ui';
|
import { Balance, Container, ContainerTitle, IdentityIcon, IdentityName, Tags } from '../../../ui';
|
||||||
import CopyToClipboard from '../../../ui/CopyToClipboard';
|
import CopyToClipboard from '../../../ui/CopyToClipboard';
|
||||||
|
import Certifications from '../../../ui/Certifications';
|
||||||
|
|
||||||
import styles from './header.css';
|
import styles from './header.css';
|
||||||
|
|
||||||
@ -32,6 +33,7 @@ export default class Header extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
|
const { api } = this.context;
|
||||||
const { account, balance } = this.props;
|
const { account, balance } = this.props;
|
||||||
const { address, meta, uuid } = account;
|
const { address, meta, uuid } = account;
|
||||||
|
|
||||||
@ -67,6 +69,10 @@ export default class Header extends Component {
|
|||||||
<Balance
|
<Balance
|
||||||
account={ account }
|
account={ account }
|
||||||
balance={ balance } />
|
balance={ balance } />
|
||||||
|
<Certifications
|
||||||
|
account={ account.address }
|
||||||
|
dappsUrl={ api.dappsUrl }
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
</Container>
|
||||||
</div>
|
</div>
|
||||||
|
@ -64,12 +64,6 @@ class Account extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
const { api } = this.context;
|
|
||||||
const { address } = this.props.params;
|
|
||||||
const { isTestnet } = this.props;
|
|
||||||
|
|
||||||
const verificationStore = new VerificationStore(api, address, isTestnet);
|
|
||||||
this.setState({ verificationStore });
|
|
||||||
this.setVisibleAccounts();
|
this.setVisibleAccounts();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,6 +74,15 @@ class Account extends Component {
|
|||||||
if (prevAddress !== nextAddress) {
|
if (prevAddress !== nextAddress) {
|
||||||
this.setVisibleAccounts(nextProps);
|
this.setVisibleAccounts(nextProps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { isTestnet } = nextProps;
|
||||||
|
if (typeof isTestnet === 'boolean' && !this.state.verificationStore) {
|
||||||
|
const { api } = this.context;
|
||||||
|
const { address } = nextProps.params;
|
||||||
|
this.setState({
|
||||||
|
verificationStore: new VerificationStore(api, address, isTestnet)
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount () {
|
componentWillUnmount () {
|
||||||
@ -115,7 +118,8 @@ class Account extends Component {
|
|||||||
<Page>
|
<Page>
|
||||||
<Header
|
<Header
|
||||||
account={ account }
|
account={ account }
|
||||||
balance={ balance } />
|
balance={ balance }
|
||||||
|
/>
|
||||||
<Transactions
|
<Transactions
|
||||||
accounts={ accounts }
|
accounts={ accounts }
|
||||||
address={ address } />
|
address={ address } />
|
||||||
|
@ -132,7 +132,8 @@ class Contract extends Component {
|
|||||||
<Page>
|
<Page>
|
||||||
<Header
|
<Header
|
||||||
account={ account }
|
account={ account }
|
||||||
balance={ balance } />
|
balance={ balance }
|
||||||
|
/>
|
||||||
<Queries
|
<Queries
|
||||||
contract={ contract }
|
contract={ contract }
|
||||||
values={ queryValues } />
|
values={ queryValues } />
|
||||||
@ -447,7 +448,10 @@ function mapStateToProps (state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function mapDispatchToProps (dispatch) {
|
function mapDispatchToProps (dispatch) {
|
||||||
return bindActionCreators({ newError, setVisibleAccounts }, dispatch);
|
return bindActionCreators({
|
||||||
|
newError,
|
||||||
|
setVisibleAccounts
|
||||||
|
}, dispatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
|
Loading…
Reference in New Issue
Block a user