Skip to content

Commit

Permalink
Merge pull request #519 from DemocracyEarth/dapp
Browse files Browse the repository at this point in the history
New Ledger Feed
  • Loading branch information
santisiri authored Jul 24, 2020
2 parents 8ea57bf + 37466c7 commit 647e260
Show file tree
Hide file tree
Showing 34 changed files with 410 additions and 10,874 deletions.
7 changes: 6 additions & 1 deletion i18n/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -884,5 +884,10 @@
"search-ragequit": "💸 Ragequit of {{shares}} shares from {{dao}} by {{address}}",
"search-default": "🔍 {{searchTerm}}",
"search-dates": "📅 {{searchTerm}}",
"moloch-unsponsored": "Unsponsored Proposal"
"moloch-unsponsored": "Unsponsored Proposal",
"voted-yes": "{{shares}} {{label}} for <strong>Yes</strong> to {{proposal}}",
"voted-no": "{{shares}} {{label}} for <strong>No</strong> to {{proposal}}",
"shares": "shares",
"share": "share",
"arrow-verb": ""
}
1 change: 0 additions & 1 deletion imports/startup/both/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ if (Meteor.isClient) {
import '/imports/ui/templates/layout/load/load.js';
import '/imports/ui/templates/components/identity/login/login.js';
import '/imports/ui/templates/components/identity/card/card.js';
import '/imports/ui/templates/components/decision/contract/contract.js';
import '/imports/ui/templates/widgets/feed/feed.js';

Router.plugin('reywood:iron-router-ga');
Expand Down
3 changes: 1 addition & 2 deletions imports/ui/components/Account/Account.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Meteor } from 'meteor/meteor';
import React from 'react';
import PropTypes from 'prop-types';
import { TAPi18n } from 'meteor/tap:i18n';

import ApolloClient, { gql, InMemoryCache } from 'apollo-boost';
import { ApolloProvider } from 'react-apollo';
Expand Down Expand Up @@ -57,7 +56,7 @@ const AccountQuery = ({ publicAddress, width, height }) => {

if (publicAddress !== '0x0000000000000000000000000000000000000000') {
const { loading, error, data } = useQuery(gql(ENS_ACCOUNT.replace('{{ensAddress}}', publicAddress)));

if (loading) {
return (
<div className="identity">
Expand Down
2 changes: 1 addition & 1 deletion imports/ui/components/DAO/DAO.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const DAOQuery = ({ publicAddress, width, height }) => {
if (!daoTitle) {
label = shortenCryptoName(publicAddress);
} else {
label = daoTitle;
label = (daoTitle.length > 20) ? `${daoTitle.slice(0, 19)}...` : daoTitle;
}

return (
Expand Down
29 changes: 29 additions & 0 deletions imports/ui/components/Ledger/Ledger.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import PropTypes from 'prop-types';
import { TAPi18n } from 'meteor/tap:i18n';

import Vote from '/imports/ui/components/Vote/Vote.jsx';

/**
* @summary displays the contents of a poll
*/
const Ledger = () => {
return (
<div>
<div className="ledger-title">
<h4>{TAPi18n.__('recent-activity')}</h4>
</div>
<Vote />
<div className="ledger-footer" />
</div>
);
};

Ledger.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
]),
};

export default Ledger;
5 changes: 5 additions & 0 deletions imports/ui/components/Ledger/ledger.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<template name="ledger">
<div>
{{> React component=Ledger}}
</div>
</template>
12 changes: 12 additions & 0 deletions imports/ui/components/Ledger/ledger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Template } from 'meteor/templating';

import Ledger from '/imports/ui/components/Ledger/Ledger.jsx';

import '/imports/ui/components/Ledger/ledger.html';

Template.ledger.helpers({
Ledger() {
return Ledger;
},
});

9 changes: 4 additions & 5 deletions imports/ui/components/Post/Post.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ export default class Post extends Component {

render() {
return (
<div className="vote vote-search vote-feed nondraggable vote-poll" href={`/dao/${this.props.daoName}/proposal/${this.props.proposalIndex}`}>
<div className="vote vote-search vote-feed nondraggable vote-poll" href={this.props.href}>
<div className="checkbox checkbox-custom">
<div className="meta meta-search meta-bar">
<Account publicAddress={this.props.memberAddress} width="24px" height="24px" />
<DAO publicAddress={this.props.daoAddress} width="24px" height="24px" />
<Account publicAddress={this.props.memberAddress} width="16px" height="16px" />
<DAO publicAddress={this.props.daoAddress} width="16px" height="16px" />
</div>
<div className="option-proposal">
<div className="option-title option-link option-search title-input">
Expand Down Expand Up @@ -96,9 +96,8 @@ export default class Post extends Component {
}

Post.propTypes = {
href: PropTypes.string,
description: PropTypes.string,
proposalIndex: PropTypes.string,
daoName: PropTypes.string,
daoAddress: PropTypes.string,
memberAddress: PropTypes.string,
children: PropTypes.oneOfType([
Expand Down
27 changes: 22 additions & 5 deletions imports/ui/components/Stamp/Stamp.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import parser from 'html-react-parser';

import { createDateQuery } from '/imports/ui/templates/widgets/transaction/transaction';
import { timeComplete } from '/imports/ui/modules/chronos';
import { timeComplete, timeCompressed, hourOnly, timeSince, countdown } from '/imports/ui/modules/chronos';

const _dateURL = (timestamp) => {
const from = new Date(parseInt(timestamp.toNumber() * 1000, 10));
Expand All @@ -20,18 +20,34 @@ export default class Stamp extends Component {
constructor(props) {
super(props);

const date = new Date(parseInt(this.props.timestamp.toNumber() * 1000, 10));

this.state = {
url: _dateURL(this.props.timestamp),
label: timeComplete(date),
label: this.getFormattedLabel(this.props.format),
fullDate: this.getFormattedLabel(),
};
}

getFormattedLabel(format) {
const date = new Date(parseInt(this.props.timestamp.toNumber() * 1000, 10));

switch (format) {
case 'timeCompressed':
return timeCompressed(date);
case 'hourOnly':
return hourOnly(date);
case 'timeSince':
return timeSince(date);
case 'countdown':
return countdown(date);
default:
}
return timeComplete(date);
}

render() {
return (
<div className="date-info">
<a href={this.state.url} className="verifier verifier-live verifier-feed">
<a href={this.state.url} title={this.state.fullDate.replace(/&#183;/g, '·')} className="verifier verifier-live verifier-feed">
{parser(this.state.label)}
</a>
</div>
Expand All @@ -41,4 +57,5 @@ export default class Stamp extends Component {

Stamp.propTypes = {
timestamp: PropTypes.string,
format: PropTypes.string,
};
14 changes: 9 additions & 5 deletions imports/ui/components/Timeline/Placeholder.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import React from 'react';
import PropTypes from 'prop-types';

/**
* @summary displays the contents of a poll
*/
const Placeholder = () => {
const _preloader = () => {
return (
<div id="feedItem-placeholder" className="vote vote-search vote-feed nondraggable">
<div className="vote vote-search vote-feed nondraggable">
<div className="checkbox checkbox-custom">
<div className="meta meta-search meta-bar">
<div className="identity">
Expand Down Expand Up @@ -38,6 +35,13 @@ const Placeholder = () => {
);
};

/**
* @summary displays the contents of a poll
*/
const Placeholder = () => {
return _preloader();
};

Placeholder.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
Expand Down
2 changes: 1 addition & 1 deletion imports/ui/components/Timeline/Timeline.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const Feed = (props) => {

return (
<Post
key={proposal.id} accountAddress={accountAddress}
key={proposal.id} accountAddress={accountAddress} href={url}
description={proposal.details} memberAddress={proposal.memberAddress}
daoAddress={daoAddress}
>
Expand Down
10 changes: 9 additions & 1 deletion imports/ui/components/Token/Token.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,15 @@ const _getRenderNumber = (value, token, decimals) => {
const TokenQuery = ({ publicAddress, quantity, symbol, decimals }) => {
const { loading, error, data } = useQuery(GET_TOKEN);

if (loading) return null;
if (loading) {
return (
<div className="token">
<div className="token-ticker">
<div className="option-placeholder token-placeholder" />
</div>
</div>
);
}
if (error) return `Error! ${error}`;

let token = _.findWhere(data.tokens, { symbol });
Expand Down
52 changes: 52 additions & 0 deletions imports/ui/components/Transaction/Transaction.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { TAPi18n } from 'meteor/tap:i18n';
import parser from 'html-react-parser';

import { defaults } from '/lib/const';
import { getDescription } from '/imports/ui/components/Post/Post.jsx';

const numeral = require('numeral');

/**
* @summary displays the contents of a poll
*/
export default class Transaction extends Component {
getVote() {
const label = (this.props.quantity.toNumber() === 1) ? 'share' : 'shares';

const title = `<em>${getDescription(this.props.description).title}</em>`;

switch (this.props.uintVote) {
case defaults.YES:
return (
<div href={this.props.uintVote} className="transaction-action transaction-action-passed">
{parser(TAPi18n.__('voted-yes').replace('{{shares}}', numeral(this.props.quantity).format('0,0')).replace('{{label}}', label).replace('{{proposal}}', title))}
</div>
);
case defaults.NO:
return (
<div href={this.props.uintVote} className="transaction-action transaction-action-rejected">
{parser(TAPi18n.__('voted-no').replace('{{shares}}', numeral(this.props.quantity).format('0,0')).replace('{{label}}', label).replace('{{proposal}}', title))}
</div>
);
default:
}
return null;
}

render() {
return (
<div className="preview-info">
{this.getVote()}
</div>
);
}
}

Transaction.propTypes = {
uintVote: PropTypes.number,
quantity: PropTypes.string,
description: PropTypes.string,
};

87 changes: 87 additions & 0 deletions imports/ui/components/Vote/Vote.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { Meteor } from 'meteor/meteor';
import React from 'react';

import ApolloClient, { gql, InMemoryCache } from 'apollo-boost';
import { ApolloProvider } from 'react-apollo';
import { useQuery } from '@apollo/react-hooks';

import Account from '/imports/ui/components/Account/Account.jsx';
import DAO from '/imports/ui/components/DAO/DAO.jsx';
import Stamp from '/imports/ui/components/Stamp/Stamp.jsx';
import Transaction from '/imports/ui/components/Transaction/Transaction.jsx';

const client = new ApolloClient({
uri: Meteor.settings.public.graph.molochs,
cache: new InMemoryCache(),
});

const GET_VOTES = gql`
{
votes(first: 7, orderBy:createdAt, orderDirection:desc) {
id
createdAt
uintVote
molochAddress
memberAddress
proposal {
details
id
}
member {
shares
}
}
}
`;


/**
* @summary displays the contents of a poll
*/
/**
* @summary graph query of token
* @param {string} publicAddress of the token contract
* @param {string} quantity with a big number
* @param {string} symbol with a ticker
* @param {string} decimal numbers this token takes
*/
const VoteQuery = () => {
const { loading, error, data } = useQuery(GET_VOTES);

console.log(data);

if (loading) {
return (
<div className="token">
<div className="token-ticker">
<div className="option-placeholder token-placeholder" />
</div>
</div>
);
}
if (error) return `Error! ${error}`;

return data.votes.map((vote) => {
return (
<div className="event-vote">
<Account publicAddress={vote.memberAddress} width="16px" height="16px" />
<DAO publicAddress={vote.molochAddress} width="16px" height="16px" />
<Transaction uintVote={vote.uintVote} description={vote.proposal.details} quantity={vote.member.shares} />
<Stamp timestamp={vote.createdAt} format="timeSince" />
</div>
);
});
};

/**
* @summary renders a post in the timeline
*/
const Vote = () => {
return (
<ApolloProvider client={client}>
<VoteQuery />
</ApolloProvider>
);
};

export default Vote;
5 changes: 5 additions & 0 deletions imports/ui/components/Vote/vote.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<template name="vote">
<div>
{{> React component=Vote}}
</div>
</template>
12 changes: 12 additions & 0 deletions imports/ui/components/Vote/vote.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Template } from 'meteor/templating';

import Vote from '/imports/ui/components/Vote/Vote.jsx';

import '/imports/ui/components/Vote/vote.html';

Template.vote.helpers({
Vote() {
return Vote;
},
});

Loading

0 comments on commit 647e260

Please sign in to comment.