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

implement basic badges/certifications/flair #3665

Merged
merged 18 commits into from
Nov 30, 2016
Merged

implement basic badges/certifications/flair #3665

merged 18 commits into from
Nov 30, 2016

Conversation

derhuerst
Copy link
Contributor

@derhuerst derhuerst commented Nov 29, 2016

This PR is a first take on #2156.

In the Account page, the badges are shown below the tokens, in a similar style.

certifications

The redux middleware fetches the addresses of all individual badge contracts from BadgeReg.sol and expects all of them to implement the Certifier.sol interface. SMSVerification.sol is one of them. The badge icons get fetched from GitHubHint.sol, based on the IMG meta field in BadgeReg.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 free
  • 0xcF5A62987294fd2087252FD812443508528C52bF – BadgeReg.sol

@gavofyork registered on mainnet:

  • 0x837A5e6f966945AbC67cB0B3f8ef62aE04Ed63ce – BadgeReg.sol
  • 0x503b323dBe5457b7Ccc0Af9Bc246E5450B934E97 – SMSVerification.sol

@derhuerst derhuerst added A0-pleasereview 🤓 Pull request needs code review. M7-ui labels Nov 29, 2016
@jacogr
Copy link
Contributor

jacogr commented Nov 29, 2016

I'm not sure I get what you mean by "blocked by MUI" - there is however already a "Badge" component ui/Badge (which is used by the TabBar - that can move that one to "Bubble", this can move to "Badge", everybody happy.)

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.

@derhuerst
Copy link
Contributor Author

derhuerst commented Nov 29, 2016

I'm not sure I get what you mean by "blocked by MUI" - there is however already a "Badge" component ui/Badge (which is used by the TabBar - that can move that one to "Bubble", this can move to "Badge", everybody happy.)

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 Badge that does something else than what most people would expect. It's only a minor impediment though.


import { hashToImageUrl } from '../../redux/providers/imagesReducer';

const defaultIcon = '/api/content/371b226f700d8577fe849d7b2729bc2e4be8c06c38159fb880a6a0cc276af012';
Copy link
Contributor

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.

Copy link
Contributor Author

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?

Copy link
Contributor

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) => {
Copy link
Contributor

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)

Copy link
Contributor Author

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?

Copy link
Contributor

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.

Copy link
Contributor Author

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 }
Copy link
Contributor

@jacogr jacogr Nov 29, 2016

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.

Copy link
Contributor Author

@derhuerst derhuerst Nov 29, 2016

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.

Copy link
Contributor

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

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)
Copy link
Contributor

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

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.

Copy link
Contributor Author

@derhuerst derhuerst Nov 29, 2016

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.

Copy link
Contributor Author

@derhuerst derhuerst Nov 29, 2016

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?

Copy link
Contributor

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 ? :)

Copy link
Contributor Author

@derhuerst derhuerst Nov 29, 2016

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?

Copy link
Contributor Author

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';
Copy link
Contributor

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';
Copy link
Contributor

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 ?

Copy link
Contributor Author

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);
Copy link
Contributor

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 }
Copy link
Contributor

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) => {
Copy link
Contributor

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);
Copy link
Contributor

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)
Copy link
Contributor

@jacogr jacogr Nov 29, 2016

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 }
Copy link
Contributor

@jacogr jacogr Nov 29, 2016

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.

@jacogr jacogr added A8-looksgood 🦄 Pull request is reviewed well. and removed A0-pleasereview 🤓 Pull request needs code review. labels Nov 30, 2016
@derhuerst
Copy link
Contributor Author

derhuerst commented Nov 30, 2016

@gavofyork Feel free to complain about the visual style, as the technical problems are out of the way now.

BTW: Will also put the certfications in the address view, which is basically th place where they are the most interesting. It is in there.

}

function mapStateToProps (state) {
return { certifications: state.certifications };
Copy link
Contributor

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).

@coveralls
Copy link

Coverage Status

Coverage decreased (-0.03%) to 85.95% when pulling af18344 on jr-sms-badges into 79e7947 on master.

@jacogr jacogr merged commit 784dcaf into master Nov 30, 2016
@jacogr jacogr deleted the jr-sms-badges branch November 30, 2016 20:39
@chevdor
Copy link

chevdor commented Sep 17, 2017

In case someone needs to play on Ropsten, the info above is no longer valid:

To play with it on ropsten:

0x01e1a37118Fe3BeFd17C426FA962cff2C9099835 – SMSVerification.sol
0xdD6a26f8971dF44698a2A3213512A5e3a0f97F61 – OprahBadge.sol, where you can get a badge by just requesting it for free
0xcF5A62987294fd2087252FD812443508528C52bF – BadgeReg.sol

OprahBadge is at 0x72f4b7a806d8fd0a2f7d66c0CD1D71ea40Be5669
Additionnally, emailverification is at 0x4A99350b039068fD326a318C599Be2E09E657D4A

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
A8-looksgood 🦄 Pull request is reviewed well.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants