139 lines
4.9 KiB
TypeScript
139 lines
4.9 KiB
TypeScript
import { BigNumber } from '@0x/utils';
|
|
import * as _ from 'lodash';
|
|
import * as React from 'react';
|
|
import styled from 'styled-components';
|
|
|
|
import { Button } from 'ts/components/button';
|
|
import { DocumentTitle } from 'ts/components/document_title';
|
|
import { Column, Section } from 'ts/components/newLayout';
|
|
import { SiteWrap } from 'ts/components/siteWrap';
|
|
import { Heading, Paragraph } from 'ts/components/text';
|
|
import { Proposal, proposals } from 'ts/pages/governance/data';
|
|
import { VoteIndexCard } from 'ts/pages/governance/vote_index_card';
|
|
import { TallyInterface } from 'ts/types';
|
|
import { configs } from 'ts/utils/configs';
|
|
import { constants } from 'ts/utils/constants';
|
|
import { documentConstants } from 'ts/utils/document_meta_constants';
|
|
import { utils } from 'ts/utils/utils';
|
|
|
|
const ZEIP_IDS = Object.keys(proposals).map(idString => parseInt(idString, 10));
|
|
const ZEIP_PROPOSALS: Proposal[] = ZEIP_IDS.map(id => proposals[id]).sort(
|
|
(a, b) => b.voteStartDate.unix() - a.voteStartDate.unix(),
|
|
);
|
|
|
|
export interface VoteIndexProps {}
|
|
|
|
interface ZeipTallyMap {
|
|
[id: number]: TallyInterface;
|
|
}
|
|
|
|
export interface VoteIndexState {
|
|
tallys?: ZeipTallyMap;
|
|
}
|
|
|
|
export class VoteIndex extends React.Component<VoteIndexProps, VoteIndexState> {
|
|
public state: VoteIndexState = {
|
|
tallys: undefined,
|
|
};
|
|
|
|
public componentDidMount(): void {
|
|
// tslint:disable:no-floating-promises
|
|
this._fetchTallysAsync();
|
|
}
|
|
|
|
public render(): React.ReactNode {
|
|
return (
|
|
<SiteWrap>
|
|
<DocumentTitle {...documentConstants.VOTE} />
|
|
<Section isTextCentered={true} isPadded={true} padding="150px 0px 110px">
|
|
<Column>
|
|
<Heading size="medium" isCentered={true}>
|
|
0x Protocol Governance
|
|
</Heading>
|
|
<SubtitleContentWrap>
|
|
<Paragraph size="medium" isCentered={true} isMuted={true} marginBottom="0">
|
|
Vote on 0x Improvement Proposals (ZEIPs) using ZRX tokens.
|
|
</Paragraph>
|
|
<ButtonWrapper>
|
|
<Button
|
|
href={constants.URL_VOTE_FAQ}
|
|
isWithArrow={true}
|
|
isAccentColor={true}
|
|
shouldUseAnchorTag={true}
|
|
target="_blank"
|
|
>
|
|
FAQ
|
|
</Button>
|
|
</ButtonWrapper>
|
|
</SubtitleContentWrap>
|
|
</Column>
|
|
</Section>
|
|
<VoteIndexCardWrapper>
|
|
{ZEIP_PROPOSALS.map(proposal => {
|
|
const tally = this.state.tallys && this.state.tallys[proposal.zeipId];
|
|
return <VoteIndexCard key={proposal.zeipId} tally={tally} {...proposal} />;
|
|
})}
|
|
</VoteIndexCardWrapper>
|
|
</SiteWrap>
|
|
);
|
|
}
|
|
private async _fetchVoteStatusAsync(zeipId: number): Promise<TallyInterface> {
|
|
try {
|
|
const voteDomain = utils.isProduction()
|
|
? `https://${configs.DOMAIN_VOTE}`
|
|
: `https://${configs.DOMAIN_VOTE}/staging`;
|
|
const voteEndpoint = `${voteDomain}/v1/tally/${zeipId}`;
|
|
const response = await fetch(voteEndpoint, {
|
|
method: 'get',
|
|
mode: 'cors',
|
|
credentials: 'same-origin',
|
|
headers: {
|
|
'content-type': 'application/json; charset=utf-8',
|
|
},
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error('Request failed');
|
|
}
|
|
|
|
const responseData = await response.json();
|
|
let { no, yes } = responseData;
|
|
yes = new BigNumber(yes);
|
|
no = new BigNumber(no);
|
|
const tally = {
|
|
...responseData,
|
|
yes: new BigNumber(yes),
|
|
no: new BigNumber(no),
|
|
};
|
|
return tally;
|
|
} catch (e) {
|
|
// Empty block
|
|
return {
|
|
yes: new BigNumber(0),
|
|
no: new BigNumber(0),
|
|
};
|
|
}
|
|
}
|
|
|
|
private async _fetchTallysAsync(): Promise<void> {
|
|
const tallyResponses = await Promise.all(ZEIP_IDS.map(async zeipId => this._fetchVoteStatusAsync(zeipId)));
|
|
const tallys: { [key: number]: TallyInterface } = {};
|
|
ZEIP_IDS.forEach((zeipId, i) => (tallys[zeipId] = tallyResponses[i]));
|
|
this.setState({ tallys });
|
|
}
|
|
}
|
|
|
|
const VoteIndexCardWrapper = styled.div`
|
|
margin-bottom: 150px;
|
|
`;
|
|
|
|
const SubtitleContentWrap = styled.div`
|
|
& > * {
|
|
display: inline;
|
|
}
|
|
`;
|
|
|
|
const ButtonWrapper = styled.div`
|
|
margin-left: 0.5rem;
|
|
`;
|