From 7233fb934b76b2aa267159bdccf8865a55049c66 Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Tue, 7 May 2019 09:37:54 -0400 Subject: [PATCH] feat: added kudos wall (#24) * feat: leaderboard for admins * feat: added kudos wall --- app/js/components/Header.js | 17 ++++++++------- app/js/components/Home.js | 21 ++++++++++++++----- app/js/components/Praise.js | 34 ++++++++++++++++++++++++++++++ app/js/components/Withdrawal.js | 35 ++++--------------------------- app/js/components/header.scss | 2 +- app/js/components/home.scss | 6 +++--- app/js/services/Meritocracy.js | 37 +++++++++++++++++++++++++++++++++ app/js/utils.js | 6 ++++++ 8 files changed, 111 insertions(+), 47 deletions(-) create mode 100644 app/js/components/Praise.js diff --git a/app/js/components/Header.js b/app/js/components/Header.js index 40fb9f5..fedce06 100644 --- a/app/js/components/Header.js +++ b/app/js/components/Header.js @@ -10,14 +10,17 @@ const Header = ({ isUserAdmin }) => ( Logo Status Meritocracy - {isUserAdmin && ( - - - + + + + + + )} ); diff --git a/app/js/components/Home.js b/app/js/components/Home.js index 5efda90..74ec651 100644 --- a/app/js/components/Home.js +++ b/app/js/components/Home.js @@ -1,8 +1,8 @@ /*global web3*/ import React, { Fragment } from 'react'; -import { Tabs, Tab } from 'react-bootstrap'; +import { Tabs, Tab, Container } from 'react-bootstrap'; import Meritocracy from 'Embark/contracts/Meritocracy'; -import { getFormattedContributorList, getCurrentContributorData } from '../services/Meritocracy'; +import { getFormattedContributorList, getCurrentContributorData, getAllPraises } from '../services/Meritocracy'; import './home.scss'; import Step1 from './Step1'; import Step2 from './Step2'; @@ -10,7 +10,7 @@ import Loading from './Loading'; import Complete from './Complete'; import Error from './Error'; import Withdrawal from './Withdrawal'; -import {sortByAlpha} from '../utils'; +import {sortByAlpha, sortByAttribute} from '../utils'; /* TODO: - list praise for contributor @@ -33,7 +33,8 @@ class Home extends React.Component { praise: '', step: 'HOME', checkbox: false, - tab: 'reward' + tab: 'reward', + praises: [] }; constructor(props) { @@ -53,6 +54,11 @@ class Home extends React.Component { const currentContributor = await getCurrentContributorData(); this.setState({ busy: false, currentContributor, contributorList: contributorList.sort(sortByAlpha('label'))}); + + getAllPraises().then(praises => { + this.setState({praises: praises.sort(sortByAttribute('time'))}); + }); + } catch (error) { this.setState({ errorMsg: error.message || error }); } @@ -188,6 +194,7 @@ class Home extends React.Component { award, currentContributor, praise, + praises, errorMsg, step, checkbox, @@ -230,7 +237,11 @@ class Home extends React.Component { {step === 'COMPLETE' && } - + + + {praises.map((item, i) => )} + + {step === 'HOME' && ( { + const name = contributorList.find(x => x.value === item.author); + const date = moment.unix(item.time).fromNow(); + return ( + + + {!item.praise && ( + + {(name && name.label) ||
} {individual ? "has sent you" : "sent"}{' '} + {web3.utils.fromWei(item.amount, 'ether')} SNT {!individual && to {item.destination}}, {date} + + )} + + {item.praise && ( + + {(name && name.label) ||
}{!individual && to {item.destination}}, {date} +
+ "{item.praise}" + {web3.utils.fromWei(item.amount, 'ether')} SNT +
+ + )} + + + ); +}; + +export default Praise; diff --git a/app/js/components/Withdrawal.js b/app/js/components/Withdrawal.js index 378e4b7..4671d39 100644 --- a/app/js/components/Withdrawal.js +++ b/app/js/components/Withdrawal.js @@ -1,9 +1,7 @@ -/* global web3 */ import React, { Fragment } from 'react'; -import { Row, Col, Button, Container } from 'react-bootstrap'; -import moment from 'moment'; +import { Button, Container } from 'react-bootstrap'; import info from '../../images/red-info.svg'; -import Address from './Address'; +import Praise from './Praise'; import './withdrawal.scss'; @@ -19,32 +17,7 @@ const Withdrawal = ({ totalReceived, allocation, onClick, contributorList, prais {praises && - praises.map((item, i) => { - const name = contributorList.find(x => x.value === item.author); - const date = moment.unix(item.time).fromNow(); - return ( - - - {!item.praise && ( - - {(name && name.label) ||
} has sent you{' '} - {web3.utils.fromWei(item.amount, 'ether')} SNT {date} - - )} - - {item.praise && ( - - {(name && name.label) || item.author}, {date} -
- "{item.praise}" - {web3.utils.fromWei(item.amount, 'ether')} SNT -
-
- )} - - - ); - })} + praises.map((item, i) => )}

@@ -57,7 +30,7 @@ const Withdrawal = ({ totalReceived, allocation, onClick, contributorList, prais

- {parseInt(allocation, 10) > 0 && ( + {totalReceived !== '0' && parseInt(allocation, 10) > 0 && (

diff --git a/app/js/components/header.scss b/app/js/components/header.scss index 75acd73..d831f66 100644 --- a/app/js/components/header.scss +++ b/app/js/components/header.scss @@ -1,6 +1,6 @@ .header { .navbar-brand { - font-size: 22px; + font-size: 20px; font-weight: bold; } } diff --git a/app/js/components/home.scss b/app/js/components/home.scss index b75a4fd..1ede138 100644 --- a/app/js/components/home.scss +++ b/app/js/components/home.scss @@ -7,8 +7,8 @@ border: none; color: $dark; border-bottom: 2px solid $dark; - font-size: 17px; - width: 48%; + font-size: 15px; + width: 32%; text-align: center; &.active { @@ -17,7 +17,7 @@ } &+.nav-link { - margin-left: 4%; + margin-left: 2%; } } } diff --git a/app/js/services/Meritocracy.js b/app/js/services/Meritocracy.js index 99c1767..6aba51c 100644 --- a/app/js/services/Meritocracy.js +++ b/app/js/services/Meritocracy.js @@ -140,6 +140,43 @@ export async function getContributorData(_address) { return currentContributor; } +export function getAllPraises() { + + return new Promise(function(resolve) { + let praisesPromises = []; + let praiseNumPromises = []; + for(let i = 0; i < contributorList.length; i++){ + praiseNumPromises.push(Meritocracy.methods.getStatusLength(contributorList[i].value).call()); + } + + Promise.all(praiseNumPromises).then(praiseNums => { + for(let i = 0; i < contributorList.length; i++){ + let currPraises = []; + for(let j = 0; j < praiseNums[i]; j++){ + currPraises.push(Meritocracy.methods.getStatus(contributorList[i].value, j).call()); + } + praisesPromises.push(currPraises); + } + + const allPromises = Promise.all( + praisesPromises.map(function(innerPromiseArray) { + return Promise.all(innerPromiseArray); + }) + ); + + allPromises.then(praises => { + for(let i = 0; i < praises.length; i++){ + praises[i] = praises[i].map(x => { + x.destination = contributorList[i].label; + return x; + }); + } + resolve(praises.flat()); + }); + }); + }); + +} export async function getContributor(_address) { const contributor = await Meritocracy.methods.contributors(_address).call(); diff --git a/app/js/utils.js b/app/js/utils.js index 84a964f..0edf8a7 100644 --- a/app/js/utils.js +++ b/app/js/utils.js @@ -12,6 +12,12 @@ export const sortByAttribute = field => (a, b) => { return 0; }; +export const sortByAttributeDesc = field => (a, b) => { + if (a[field] < b[field]) return -1; + if (a[field] > b[field]) return 1; + return 0; +}; + export const sortNullableArray = field => (a, b) => { const a_field = a[field] || []; const b_field = b[field] || [];