Merge pull request #49 from grant-project/show-contribution-amounts-frontend
Show Proposal Contribution Amounts
This commit is contained in:
commit
210b656939
|
@ -12,11 +12,11 @@ import { RadioChangeEvent } from 'antd/lib/radio';
|
|||
import TrusteeFields from './TrusteeFields';
|
||||
import MilestoneFields, { Milestone } from './MilestoneFields';
|
||||
import CreateSuccess from './CreateSuccess';
|
||||
import { computePercentage } from 'utils/helpers';
|
||||
import { getAmountError } from 'utils/validators';
|
||||
import MarkdownEditor from 'components/MarkdownEditor';
|
||||
import * as Styled from './styled';
|
||||
|
||||
import { Wei, toWei } from 'utils/units';
|
||||
import BN from 'bn.js';
|
||||
interface StateProps {
|
||||
crowdFundLoading: AppState['web3']['crowdFundLoading'];
|
||||
crowdFundError: AppState['web3']['crowdFundError'];
|
||||
|
@ -74,8 +74,8 @@ const DEFAULT_STATE: State = {
|
|||
milestoneDeadline: 60 * 60 * 24 * 7,
|
||||
};
|
||||
|
||||
function milestoneToMilestoneAmount(milestone: Milestone, raiseGoal: number) {
|
||||
return computePercentage(raiseGoal, milestone.payoutPercent);
|
||||
function milestoneToMilestoneAmount(milestone: Milestone, raiseGoal: Wei) {
|
||||
return raiseGoal.divn(100).mul(new BN(milestone.payoutPercent));
|
||||
}
|
||||
|
||||
class CreateProposal extends React.Component<Props, State> {
|
||||
|
@ -159,7 +159,7 @@ class CreateProposal extends React.Component<Props, State> {
|
|||
};
|
||||
|
||||
createCrowdFund = async () => {
|
||||
const { contract, createCrowdFund, web3 } = this.props;
|
||||
const { contract, createCrowdFund } = this.props;
|
||||
const {
|
||||
title,
|
||||
proposalBody,
|
||||
|
@ -173,10 +173,9 @@ class CreateProposal extends React.Component<Props, State> {
|
|||
} = this.state;
|
||||
|
||||
const backendData = { content: proposalBody, title, category };
|
||||
|
||||
const targetInWei = web3.utils.toWei(String(amountToRaise), 'ether');
|
||||
const targetInWei = toWei(amountToRaise, 'ether');
|
||||
const milestoneAmounts = milestones.map(milestone =>
|
||||
milestoneToMilestoneAmount(milestone, targetInWei),
|
||||
Wei(milestoneToMilestoneAmount(milestone, targetInWei)),
|
||||
);
|
||||
const immediateFirstMilestonePayout = milestones[0].immediatePayout;
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
import React from 'react';
|
||||
import { Spin } from 'antd';
|
||||
import { CrowdFund } from 'modules/proposals/reducers';
|
||||
import UserRow from 'components/UserRow';
|
||||
import * as ProposalStyled from '../styled';
|
||||
import Placeholder from 'components/Placeholder';
|
||||
import UnitDisplay from 'components/UnitDisplay';
|
||||
|
||||
interface Props {
|
||||
crowdFund: CrowdFund;
|
||||
}
|
||||
|
||||
const ContributorsBlock = ({ crowdFund }: Props) => {
|
||||
let content;
|
||||
if (crowdFund) {
|
||||
if (crowdFund.contributors.length) {
|
||||
content = crowdFund.contributors.map(contributor => (
|
||||
<UserRow
|
||||
key={contributor.address}
|
||||
address={contributor.address}
|
||||
secondary={<UnitDisplay value={contributor.contributionAmount} symbol="ETH" />}
|
||||
/>
|
||||
));
|
||||
} else {
|
||||
content = (
|
||||
<Placeholder
|
||||
style={{ minHeight: '220px' }}
|
||||
title="No contributors found"
|
||||
subtitle={`
|
||||
It appears that your campaign hasn't yet been funded.
|
||||
Check back later once you've received at least one contribution!
|
||||
`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
} else {
|
||||
content = <Spin />;
|
||||
}
|
||||
|
||||
return (
|
||||
<ProposalStyled.SideBlock>
|
||||
{crowdFund.contributors.length ? (
|
||||
<>
|
||||
<ProposalStyled.BlockTitle>Contributors</ProposalStyled.BlockTitle>
|
||||
<ProposalStyled.Block>{content}</ProposalStyled.Block>
|
||||
</>
|
||||
) : (
|
||||
content
|
||||
)}
|
||||
</ProposalStyled.SideBlock>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContributorsBlock;
|
|
@ -15,6 +15,7 @@ import Milestones from './Milestones';
|
|||
import CommentsTab from './Comments';
|
||||
import UpdatesTab from './Updates';
|
||||
import GovernanceTab from './Governance';
|
||||
import ContributorsTab from './Contributors';
|
||||
// import CommunityTab from './Community';
|
||||
import * as Styled from './styled';
|
||||
import { withRouter } from 'next/router';
|
||||
|
@ -113,9 +114,12 @@ class ProposalDetail extends React.Component<Props, State> {
|
|||
<div style={{ marginTop: '1.5rem' }} />
|
||||
<UpdatesTab proposalId={proposal.proposalId} />
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane tab="Governance" key="governanc">
|
||||
<Tabs.TabPane tab="Governance" key="governance">
|
||||
<GovernanceTab proposal={proposal} />
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane tab="Contributors" key="contributors">
|
||||
<ContributorsTab crowdFund={proposal.crowdFund} />
|
||||
</Tabs.TabPane>
|
||||
</Tabs>
|
||||
)}
|
||||
</Styled.Container>
|
||||
|
|
|
@ -5,11 +5,10 @@ import * as Styled from './styled';
|
|||
|
||||
interface Props {
|
||||
address: string;
|
||||
secondary?: React.ReactNode;
|
||||
}
|
||||
|
||||
// TODO - don't hardcode monero image
|
||||
|
||||
const UserRow = ({ address }: Props) => (
|
||||
const UserRow = ({ address, secondary }: Props) => (
|
||||
<Styled.Container>
|
||||
<Styled.Avatar>
|
||||
<Identicon address={address} />
|
||||
|
@ -18,7 +17,7 @@ const UserRow = ({ address }: Props) => (
|
|||
<Styled.InfoMain>
|
||||
<ShortAddress address={address} />
|
||||
</Styled.InfoMain>
|
||||
<Styled.InfoSecondary>{/* user.title */}</Styled.InfoSecondary>
|
||||
{secondary && <Styled.InfoSecondary>{secondary}</Styled.InfoSecondary>}
|
||||
</Styled.Info>
|
||||
</Styled.Container>
|
||||
);
|
||||
|
|
|
@ -14,7 +14,7 @@ export interface User {
|
|||
|
||||
export interface Contributor {
|
||||
address: string;
|
||||
contributionAmount: string;
|
||||
contributionAmount: Wei;
|
||||
refundVote: boolean;
|
||||
refunded: boolean;
|
||||
proportionalContribution: string;
|
||||
|
|
|
@ -7,6 +7,7 @@ import { sleep } from 'utils/helpers';
|
|||
import { fetchProposal, fetchProposals } from 'modules/proposals/actions';
|
||||
import { PROPOSAL_CATEGORY } from 'api/constants';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { Wei } from 'utils/units';
|
||||
|
||||
type GetState = () => AppState;
|
||||
|
||||
|
@ -97,10 +98,10 @@ interface MilestoneData {
|
|||
}
|
||||
|
||||
interface ProposalContractData {
|
||||
ethAmount: number | string; // TODO: BigNumber
|
||||
ethAmount: Wei;
|
||||
payOutAddress: string;
|
||||
trusteesAddresses: string[];
|
||||
milestoneAmounts: number[] | string[]; // TODO: BigNumber
|
||||
milestoneAmounts: Wei[];
|
||||
milestones: MilestoneData[];
|
||||
durationInMinutes: number;
|
||||
milestoneVotingPeriodInMinutes: number;
|
||||
|
|
|
@ -5,7 +5,3 @@ export function isNumeric(n: any) {
|
|||
export async function sleep(ms: number) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
export function computePercentage(num: number, percent: number) {
|
||||
return (num / 100) * percent;
|
||||
}
|
||||
|
|
|
@ -93,7 +93,13 @@ const fromWei = (wei: Wei, unit: UnitKey) => {
|
|||
return baseToConvertedUnit(wei.toString(), decimal);
|
||||
};
|
||||
|
||||
const toWei = (value: string, decimal: number): Wei => {
|
||||
const toWei = (value: string, unitType: number | UnitKey): Wei => {
|
||||
let decimal;
|
||||
if (typeof unitType === 'number') {
|
||||
decimal = unitType;
|
||||
} else if (typeof unitType === 'string') {
|
||||
decimal = getDecimalFromEtherUnit(unitType);
|
||||
}
|
||||
const wei = convertedToBaseUnit(value, decimal);
|
||||
return Wei(wei);
|
||||
};
|
||||
|
|
|
@ -2,6 +2,7 @@ import Web3 from 'web3';
|
|||
import { CrowdFund, Milestone, MILESTONE_STATE } from 'modules/proposals/reducers';
|
||||
import { collectArrayElements } from 'utils/web3Utils';
|
||||
import { Wei } from 'utils/units';
|
||||
import BN from 'bn.js';
|
||||
|
||||
export async function getCrowdFundState(
|
||||
crowdFundContract: any,
|
||||
|
@ -26,7 +27,10 @@ export async function getCrowdFundState(
|
|||
? 100
|
||||
: balance.divn(100).isZero()
|
||||
? 0
|
||||
: target.div(balance.divn(100)).toNumber();
|
||||
: balance
|
||||
.mul(new BN(100))
|
||||
.div(target)
|
||||
.toNumber();
|
||||
const amountVotingForRefund = isRaiseGoalReached
|
||||
? Wei(await crowdFundContract.methods.amountVotingForRefund().call({ from: account }))
|
||||
: Wei('0');
|
||||
|
@ -103,6 +107,11 @@ export async function getCrowdFundState(
|
|||
.call({ form: account }),
|
||||
),
|
||||
);
|
||||
contributor.contributionAmount = Wei(
|
||||
await crowdFundContract.methods
|
||||
.getContributorContributionAmount(addr)
|
||||
.call({ from: account }),
|
||||
);
|
||||
return contributor;
|
||||
}),
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue