Browse Source

Votes - basic integration

Leszek Wiesner 4 years ago
parent
commit
4e9be073d3

+ 3 - 2
packages/joy-proposals/src/Proposal/ProposalDetails.tsx

@@ -4,8 +4,9 @@ import { Container } from "semantic-ui-react";
 import Details from "./Details";
 import Body from "./Body";
 import VotingSection from "./VotingSection";
+import Votes from "./Votes";
 import { MyAccountProps, withMyAccount } from "@polkadot/joy-utils/MyAccount"
-import { ParsedProposal } from "../runtime/transport";
+import { ParsedProposal } from "../runtime";
 import { withCalls } from '@polkadot/react-api';
 import { withMulti } from '@polkadot/react-api/with';
 
@@ -74,7 +75,7 @@ function ProposalDetails({ proposal, proposalId, myAddress, myMemberId, iAmMembe
           memberId={ myMemberId as MemberId }
           isVotingPeriod={ extendedStatus.substage === 'Voting period' }/>
       ) }
-      {/* <Votes votes={votes} total={totalVotes} />  TODO: Implement */}
+      <Votes proposalId={proposalId} />
     </Container>
   );
 }

+ 43 - 12
packages/joy-proposals/src/Proposal/Votes.tsx

@@ -1,35 +1,66 @@
 import React from "react";
+import { IdentityIcon } from '@polkadot/react-components';
 import { Header, Divider, Table, Image, Icon } from "semantic-ui-react";
-
-import { Vote } from "./ProposalDetails";
 import useVoteStyles from "./useVoteStyles";
+import { useTransport, ProposalVote } from "../runtime";
+import { ProposalId, VoteKind } from "@joystream/types/proposals";
+import { VoteKindStr } from "./VotingSection";
+import { usePromise } from "../utils";
+import Loading from "./Loading";
+import Error from "./Error";
 
 type VotesProps = {
-  votes: Vote[];
-  total: number;
+  proposalId: ProposalId
 };
 
-export default function Votes({ votes, total }: VotesProps) {
+export default function Votes({ proposalId }: VotesProps) {
+  const transport = useTransport();
+  const [votes, loading, error] = usePromise<ProposalVote[]>(() => transport.votes(proposalId), []);
+
+  if (loading && !error) {
+    return <Loading text="Fetching the votes..." />;
+  } else if (error) {
+    return <Error error={error} />;
+  }
+
+  const nonEmptyVotes = votes.filter(proposalVote => proposalVote.vote !== null);
+
+  if (!nonEmptyVotes.length) {
+    return (
+      <Header as="h3">
+        No votes submitted yet!
+      </Header>
+    );
+  }
+
   return (
     <>
       <Header as="h3">
-        All Votes: ({votes.length} / {total})
+        All Votes: ({nonEmptyVotes.length} / {votes.length})
       </Header>
       <Divider />
       <Table basic="very">
         <Table.Body>
-          {votes.map((vote, idx) => {
-            const { icon, textColor } = useVoteStyles(vote.value);
+          {nonEmptyVotes.map((proposalVote, idx) => {
+            const { vote, member } = proposalVote;
+            const voteStr = (vote as VoteKind).type.toString() as VoteKindStr;
+            const { icon, textColor } = useVoteStyles(voteStr);
             return (
-              <Table.Row key={`${vote.by.name}-${idx}`}>
+              <Table.Row key={`${member.handle}-${idx}`}>
                 <Table.Cell className={textColor}>
                   <Icon name={icon} />
-                  {vote.value}
+                  {voteStr}
                 </Table.Cell>
                 <Table.Cell>
-                  <Image src={vote.by.avatar} avatar /> {vote.by.name}
+                { member.avatar_uri ?
+                  <Image src={ member.avatar_uri } avatar floated="left" />
+                  : <IdentityIcon className="image" value={member.root_account} size={40} /> }
+                  { member.handle }
                 </Table.Cell>
-                <Table.Cell className="text-grey">{vote.createdAt}</Table.Cell>
+                {/*
+                  TODO: Integrate:
+                  <Table.Cell className="text-grey">{vote.createdAt}</Table.Cell>
+                */}
               </Table.Row>
             );
           })}

+ 1 - 1
packages/joy-proposals/src/Proposal/VotingSection.tsx

@@ -11,7 +11,7 @@ import { usePromise } from "../utils";
 
 // TODO: joy-types (there's something similar already I think)
 const voteKinds = ["Approve", "Slash", "Abstain", "Reject"] as const;
-type VoteKindStr = "Approve" | "Slash" | "Abstain" | "Reject";
+export type VoteKindStr = "Approve" | "Slash" | "Abstain" | "Reject";
 
 type VoteButtonProps = {
   memberId: MemberId,

+ 1 - 1
packages/joy-proposals/src/runtime/index.ts

@@ -1,4 +1,4 @@
-export { ParsedProposal, ProposalType } from "./transport";
+export { ParsedProposal, ProposalType, ProposalVote } from "./transport";
 export { SubstrateTransport } from "./transport.substrate";
 export { MockTransport } from "./transport.mock";
 export { SubstrateProvider, useTransport } from "./TransportContext";

+ 3 - 3
packages/joy-proposals/src/runtime/transport.substrate.ts

@@ -1,4 +1,4 @@
-import { Transport, ParsedProposal, ProposalType, ProposalTypes, ParsedMember } from "./transport";
+import { Transport, ParsedProposal, ProposalType, ProposalTypes, ParsedMember, ProposalVote } from "./transport";
 import { Proposal, ProposalId, Seats, VoteKind } from "@joystream/types/proposals";
 import { MemberId } from "@joystream/types/members";
 import { ApiProps } from "@polkadot/react-api/types";
@@ -123,7 +123,7 @@ export class SubstrateTransport extends Transport {
     return this.proposalsCodex.proposalDetailsByProposalId(id);
   }
 
-  async councilMembers() {
+  async councilMembers(): Promise<(ParsedMember & { memberId: MemberId })[]> {
     const council = (await this.council.activeCouncil()) as Seats;
     return Promise.all(
       council.map(async seat => {
@@ -143,7 +143,7 @@ export class SubstrateTransport extends Transport {
     return hasVoted ? vote : null;
   }
 
-  async votes(proposalId: ProposalId) {
+  async votes(proposalId: ProposalId): Promise<ProposalVote[]> {
     const councilMembers = await this.councilMembers();
     return Promise.all(
       councilMembers.map(async member => {

+ 7 - 1
packages/joy-proposals/src/runtime/transport.ts

@@ -1,4 +1,5 @@
-import { ProposalId } from "@joystream/types/proposals";
+import { ProposalId, VoteKind } from "@joystream/types/proposals";
+import { MemberId } from "@joystream/types/members";
 // FIXME: Those don't have the same names as in the runtime
 export const ProposalTypes = [
   "Text",
@@ -51,6 +52,11 @@ export type ParsedProposal = {
   };
 };
 
+export type ProposalVote = {
+  vote: VoteKind | null;
+  member: (ParsedMember & { memberId: MemberId });
+};
+
 export abstract class Transport {
   abstract proposals(): Promise<ParsedProposal[]>;
 }