-
Notifications
You must be signed in to change notification settings - Fork 1.7k
implement basic badges/certifications/flair #3665
Conversation
The sms verification store got created when `isTestnet` (from the Redux state) was still `undefined`.
I'm not sure I get what you mean by "blocked by MUI" - there is however already a "Badge" component There are a number of places where out components match the names of the MUI components, nothing wrong with that since we typically wrap and extend. |
The name "badge" is already "taken" by Material UI, so it might be unintuitive to have a component |
|
||
import { hashToImageUrl } from '../../redux/providers/imagesReducer'; | ||
|
||
const defaultIcon = '/api/content/371b226f700d8577fe849d7b2729bc2e4be8c06c38159fb880a6a0cc276af012'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No. We cannot do this. It assumes a certain network setup.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the solution is to change hashToImageUrl
to accept string hashes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can have a default icon pointing an Image file in Assets
|
||
import ABI from '../../../contracts/abi/certifier.json'; | ||
|
||
export default (api) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any specific reason why we are in a "only a single function per file" mode here? As per previous PRs, we are just cluterring the directories and making multiple code imports, no reason no to have the functionality grouped. (I would put all files in this directory into one, easy to access, easy to see the whole picture)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any specific reason why we are in a "only a single function per file" mode here?
This is just personal taste & being used to it. Will remove as far as I agree with the following point.
I would put all files in this directory into one, easy to access, easy to see the whole picture
On purpose, I stored middleware, actions and reducers in separate files. It underlines the whole style of using Redux by making it less tempting to intertwine actions & their reactions.
What about moving checkIfCertified
and fetchCertifier
into middleware.js
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it makes sense, by all means.
This is not about personal taste, for the most part when you go into a component you cannot see if it was written by me, Nicolas, Jannis or Tomasz since it follows a consistent approach and way of doing things, where all adapted to. Would like to keep it that way and not leave personal preferences scattered along the codebase, I would prefer not looking at a component and knowing by the style who did it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As long, as we don't mix things we shouldn't mix or break with best practices, I fully agree! :)
@@ -67,6 +71,10 @@ export default class Header extends Component { | |||
<Balance | |||
account={ account } | |||
balance={ balance } /> | |||
<Certifications | |||
certifications={ certifications } | |||
dappsUrl={ api.dappsUrl } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really want to pass this here? The api is on context and it is an Certification specific thing for rendering. Adds no real value from just having another prop for details available in the component already.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea is to have smart & dumb components or at least move in this direction, as it is considered best practice.
If Certifications
is really only going to be used in this place, I will move it. Otherwise (e.g. when it's used in Accounts
) it makes sense to keep Certifications
dumb.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From what I can tell, certifications
is a Redux state, thus we could connect Certifications
to the state and make it dumb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ngotchac Not sure I get what you mean, but "dumb"/presentational components are usually not aware of Redux.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I meant is that you can connect your dumb Certifications
component to the Redux store, so the Connector won't be dumb, but the presentation Component will be. It's just not to have to pass props to it all the way from Account
which doesn't really care about the certifications
per se
const { api } = this.context; | ||
const { address } = nextProps.params; | ||
this.setState({ | ||
verificationStore: new VerificationStore(api, address, isTestnet) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason the store is not on the main class (like typically used elsewhere), but rather as a state component?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this related to https://github.com/ethcore/parity/pull/3665#discussion_r89991234 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it is just quite unintuitive having a state mechanism inside another state mechanism. Since you have a store (granted not easy here), you can get rid of state completely. So basically if you look what happens elsewhere, it is a case of -
static propTypes = {
...
}
store = new Store(...)
render () {
return (
<div>{ this.store.name }</div>
);
}
So store is class-level, not within state. (In a perfect world these types of store components probably won't even have state, easy with new components, a process getting there with existing) So taking this state-within-state approach is probably due to a specific reason, just trying to understand why.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, thought you were talking about the badges. Just putting the store
as a class prop didn't come to my mind, will move.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't instantiate VerificationStore
right away, I need to wait for isTestnet
having an actual (boolean) value. This is the problem I mentioned in Slack.
Still, I can move store
from state
into the instance itself. But then, the Reavt mechanisms of rerendering when changes happen won't work anymore, do they?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So why not waiting for isTestnet to be available before rendering the component ? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ngotchac So showing nothing/a loader, like discussed on Slack?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ngotchac I put the verificationStore
into <Account>
to make it independent from the modal component. Back then, this was the first step of moving away from Redux.
I could wait for isTestnet
to render the whole account page, but that's out of scope of this PR.
|
||
import ABI from '../../../contracts/abi/badgereg.json'; | ||
|
||
const address = '0xcF5A62987294fd2087252FD812443508528C52bF'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be in the register
import badgeRegABI from '../../../contracts/abi/badgereg.json'; | ||
import certifierABI from '../../../contracts/abi/certifier.json'; | ||
|
||
const badgeRegAddress = '0xcF5A62987294fd2087252FD812443508528C52bF'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should definitely be in the register, no ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had it on morden
, but forgot it on ropsten
.
const knownCertifiers = [ 'smsverification' ]; | ||
|
||
export const fetchCertifier = (api) => { | ||
const registry = api.newContract(badgeRegABI, badgeRegAddress); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not having this in a contract JS file like tokenreg
, githubhint
, etc...?
@@ -132,7 +140,9 @@ class Contract extends Component { | |||
<Page> | |||
<Header | |||
account={ account } | |||
balance={ balance } /> | |||
balance={ balance } | |||
certifications={ certificationsOfAccount } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this still needed?
|
||
const ZERO = '0x0000000000000000000000000000000000000000000000000000000000000000'; | ||
|
||
export default (api, registry) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing wrong with the logic, but please follow the same style as the other contracts. This one is the inconsistent one, really don't need the extra mental overhead for "preferences".
@@ -33,6 +34,7 @@ export default class Contracts { | |||
this._signaturereg = new SignatureReg(api, this._registry); | |||
this._tokenreg = new TokenReg(api, this._registry); | |||
this._githubhint = new GithubHint(api, this._registry); | |||
this.badgeReg = BadgeReg(api, this._registry); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As per the above comment, fit in with what is there, please.
@@ -30,7 +31,8 @@ export default function (api) { | |||
const middleware = [ | |||
settings.toMiddleware(), | |||
signer.toMiddleware(), | |||
errors.toMiddleware() | |||
errors.toMiddleware(), | |||
certificationsMiddleware(api) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason for not following the conventions, i.e. toMiddleware()
as per the rest? (Took a long time to get all the middleware grouped and following a pattern after it was scattered all around.)
@@ -67,6 +69,10 @@ export default class Header extends Component { | |||
<Balance | |||
account={ account } | |||
balance={ balance } /> | |||
<Certifications | |||
account={ account.address } | |||
dappsUrl={ api.dappsUrl } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still don't believe dappsUrl should be passed in, not critical though, can live with it.
@gavofyork Feel free to complain about the visual style, as the technical problems are out of the way now.
|
} | ||
|
||
function mapStateToProps (state) { | ||
return { certifications: state.certifications }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quick note about Redux state : for containers like this, we should use this as mapStateToProps
:
function mapStateToProps (_, initProps) {
const { account } = this.props;
return (state) => {
const certification = state.certifications[account];
return { certification };
};
}
This is better because only the right certification
Object is passed to the props, which means that the Component will not re-render when other certifications changes (which is the case if you pass the whole state.certifications
Object).
In case someone needs to play on Ropsten, the info above is no longer valid:
OprahBadge is at |
This PR is a first take on #2156.
In the Account page, the badges are shown below the tokens, in a similar style.
The redux middleware fetches the addresses of all individual badge contracts from
BadgeReg.sol
and expects all of them to implement theCertifier.sol
interface.SMSVerification.sol
is one of them. The badge icons get fetched fromGitHubHint.sol
, based on theIMG
meta field inBadgeReg.sol
.In the code, this functionality is called "certifier" right now. I'm not really happy with that, will consider changing it. The term "badge" is blocked however by Material UI.
The current styling wastes a lot of space. I'm also not sure wether the badges should or should not be displayed in the style of tokens.
To play with it on
ropsten
:0x01e1a37118Fe3BeFd17C426FA962cff2C9099835
–SMSVerification.sol
0xdD6a26f8971dF44698a2A3213512A5e3a0f97F61
–OprahBadge.sol
, where you can get a badge by just requesting it for free0xcF5A62987294fd2087252FD812443508528C52bF
–BadgeReg.sol
@gavofyork registered on
mainnet
:0x837A5e6f966945AbC67cB0B3f8ef62aE04Ed63ce
–BadgeReg.sol
0x503b323dBe5457b7Ccc0Af9Bc246E5450B934E97
–SMSVerification.sol