Browse Source

improve members, councils data structure

Joystream Stats 4 years ago
parent
commit
fef8d94cba

+ 42 - 80
src/App.tsx

@@ -6,9 +6,8 @@ import * as get from "./lib/getters";
 import { domain, wsLocation } from "./config";
 import proposalPosts from "./proposalPosts";
 import axios from "axios";
-//import moment from "moment";
+import { ProposalDetail } from "./types";
 
-// types
 import {
   Api,
   Block,
@@ -18,13 +17,12 @@ import {
   Category,
   Channel,
   Post,
+  Seat,
   Thread,
 } from "./types";
 import { types } from "@joystream/types";
-import { Seat } from "@joystream/types/augment/all/types";
 import { ApiPromise, WsProvider } from "@polkadot/api";
-import { AccountId, Header } from "@polkadot/types/interfaces";
-import { MemberId } from "@joystream/types/members";
+import { Header } from "@polkadot/types/interfaces";
 import { VoteKind } from "@joystream/types/proposals";
 
 interface IProps {}
@@ -57,6 +55,7 @@ const initialState = {
 
 class App extends React.Component<IProps, IState> {
   async initializeSocket() {
+    console.debug(`Connecting to ${wsLocation}`);
     const provider = new WsProvider(wsLocation);
     const api = await ApiPromise.create({ provider, types });
     await api.isReady;
@@ -178,7 +177,7 @@ class App extends React.Component<IProps, IState> {
       const curation = String(data.curation_status);
       const createdAt = data.created;
       const principal = Number(data.principal_id);
-      this.fetchMemberByAccount(api, accountId);
+      //this.fetchMemberByAccount(api, accountId);
 
       const channel: Channel = {
         id,
@@ -219,7 +218,6 @@ class App extends React.Component<IProps, IState> {
       const unmoderatedThreads = Number(data.num_direct_unmoderated_threads);
       const position = Number(data.position_in_parent_category);
       const moderatorId = String(data.moderator_id);
-      if (moderatorId !== "") this.fetchMemberByAccount(api, moderatorId);
 
       const category: Category = {
         id,
@@ -236,7 +234,6 @@ class App extends React.Component<IProps, IState> {
         moderatorId,
       };
 
-      //console.debug(data, category);
       const categories = this.state.categories.concat(category);
       this.save("categories", categories);
     }
@@ -255,11 +252,8 @@ class App extends React.Component<IProps, IState> {
       //const createdAt = moment(data.created_at);
       const createdAt = data.created_at;
       const authorId = String(data.author_id);
-      this.fetchMemberByAccount(api, authorId);
 
       const post: Post = { id, threadId, text, authorId, createdAt };
-
-      //console.debug(data, post);
       const posts = this.state.posts.concat(post);
       this.save("posts", posts);
     }
@@ -277,7 +271,6 @@ class App extends React.Component<IProps, IState> {
       const moderation = data.moderation;
       const createdAt = String(data.created_at.block);
       const authorId = String(data.author_id);
-      this.fetchMemberByAccount(api, authorId);
 
       const thread: Thread = {
         id,
@@ -289,7 +282,6 @@ class App extends React.Component<IProps, IState> {
         authorId,
       };
 
-      //console.debug(data, thread);
       const threads = this.state.threads.concat(thread);
       this.save("threads", threads);
     }
@@ -297,32 +289,19 @@ class App extends React.Component<IProps, IState> {
   }
 
   async fetchCouncils(api: Api, currentRound: number) {
-    if (this.state.councils.length)
-      return this.state.councils.map((council) =>
-        council.map((seat) => this.fetchMember(api, seat))
-      );
-
-    let councils: number[][] = [];
+    let { councils } = this.state;
     const cycle = 201600;
 
     for (let round = 0; round < currentRound; round++) {
-      let council: number[] = [];
       const block = 57601 + round * cycle;
-      console.debug(`Fetching council at block ${block}`);
+      if (councils[round] || block > this.state.block) continue;
 
+      console.debug(`Fetching council at block ${block}`);
       const blockHash = await api.rpc.chain.getBlockHash(block);
       if (!blockHash) continue;
-      const seats: Seat[] = await api.query.council.activeCouncil.at(blockHash);
 
-      seats.forEach(async (seat) => {
-        const member = await this.fetchMemberByAccount(
-          api,
-          String(seat.member)
-        );
-        council = council.concat(Number(member.id));
-        councils[round] = council;
-        this.save("councils", councils);
-      });
+      councils[round] = await api.query.council.activeCouncil.at(blockHash);
+      this.save("councils", councils);
     }
   }
 
@@ -335,40 +314,42 @@ class App extends React.Component<IProps, IState> {
     let { proposals } = this.state;
     const exists = proposals.find((p) => p && p.id === id);
 
-    if (
-      exists &&
-      exists.votesByMemberId &&
-      exists.votesByMemberId.length &&
-      exists.stage === "Finalized"
-    )
-      return;
+    if (exists) {
+      if (exists.stage === "Finalized" && exists.votesByAccount) return;
+      return this.fetchVotesPerProposal(api, exists);
+    }
+
     console.debug(`Fetching proposal ${id}`);
     const proposal = await get.proposalDetail(api, id);
-
     if (!proposal) return console.warn(`Empty result (proposal ${id})`);
+
     proposals[id] = proposal;
     this.save("proposals", proposals);
-    this.fetchVotesPerProposal(api, id);
-    this.fetchMember(api, proposal.authorId);
+    this.fetchVotesPerProposal(api, proposal);
   }
 
-  async fetchVotesPerProposal(api: Api, proposalId: number) {
-    const { councils, proposals } = this.state;
-    const proposal = proposals.find((p) => p && p.id === proposalId);
-    if (!proposal) return console.warn(`Proposal ${proposalId} not found.`);
+  async fetchVotesPerProposal(api: Api, proposal: ProposalDetail) {
+    const { votesByAccount } = proposal;
+    if (votesByAccount && votesByAccount.length) return;
 
-    console.debug(`Fetching proposal votes (${proposalId})`);
-    let memberIds: { [key: string]: number } = {};
-    councils.map((ids: number[]) =>
-      ids.map((memberId: number) => memberIds[`${memberId}`]++)
+    console.debug(`Fetching proposal votes (${proposal.id})`);
+    const { councils, proposals } = this.state;
+    let members: Member[] = [];
+    councils.map((seats) =>
+      seats.forEach(async (seat: Seat) => {
+        if (members.find((member) => member.account === seat.member)) return;
+        const member = this.state.members.find(
+          (m) => m.account === seat.member
+        );
+        member && members.push(member);
+      })
     );
 
     const { id } = proposal;
-    proposal.votesByMemberId = await Promise.all(
-      Object.keys(memberIds).map(async (key: string) => {
-        const memberId = parseInt(key);
-        const vote = await this.fetchVoteByProposalByVoter(api, id, memberId);
-        return { vote, memberId };
+    proposal.votesByAccount = await Promise.all(
+      members.map(async (member) => {
+        const vote = await this.fetchVoteByProposalByVoter(api, id, member.id);
+        return { vote, handle: member.handle };
       })
     );
     proposals[id] = proposal;
@@ -378,8 +359,9 @@ class App extends React.Component<IProps, IState> {
   async fetchVoteByProposalByVoter(
     api: Api,
     proposalId: number,
-    voterId: MemberId | number
+    voterId: number
   ): Promise<string> {
+    console.debug(`Fetching vote by ${voterId} for proposal ${proposalId}`);
     const vote: VoteKind = await api.query.proposalsEngine.voteExistsByProposalByVoter(
       proposalId,
       voterId
@@ -398,39 +380,21 @@ class App extends React.Component<IProps, IState> {
 
   async fetchNominators(api: Api) {
     const nominatorEntries = await api.query.staking.nominators.entries();
-    const nominators = nominatorEntries.map((n: any) => {
-      const name = n[0].toHuman();
-      this.fetchMemberByAccount(api, name);
-      return `${name}`;
-    });
+    const nominators = nominatorEntries.map((n: any) => String(n[0].toHuman()));
     this.save("nominators", nominators);
   }
   async fetchValidators(api: Api) {
     const validatorEntries = await api.query.session.validators();
-    const validators = await validatorEntries.map((v: any) => {
-      this.fetchMemberByAccount(api, v.toJSON());
-      return String(v);
-    });
+    const validators = await validatorEntries.map((v: any) => String(v));
     this.save("validators", validators);
   }
 
   // accounts
   async fetchMembers(api: Api, lastId: number) {
     for (let id = lastId; id > 0; id--) {
-      if (this.state.members.find((m) => m.id === id)) return;
-      console.debug(`fetching member ${id}`);
-      const member = await this.fetchMember(api, id);
-      if (!member) return console.warn(`Failed to fetch member ${id}`);
-      const members = this.state.members.push(member);
-      this.save("members", members);
+      this.fetchMember(api, id);
     }
   }
-  getHandle(account: AccountId | string): string {
-    const member = this.state.members.find(
-      (m) => String(m.account) === String(account)
-    );
-    return member ? member.handle : String(account);
-  }
   async fetchMemberByAccount(api: Api, account: string): Promise<Member> {
     const exists = this.state.members.find(
       (m: Member) => String(m.account) === String(account)
@@ -455,8 +419,7 @@ class App extends React.Component<IProps, IState> {
     const registeredAt = Number(membership.registered_at_block);
     const member: Member = { id, handle, account, registeredAt, about };
     const members = this.state.members.concat(member);
-
-    if (members.length) this.save(`members`, members);
+    this.save(`members`, members);
     this.updateHandles(members);
     return member;
   }
@@ -620,7 +583,7 @@ class App extends React.Component<IProps, IState> {
 
   render() {
     if (this.state.loading) return <Loading />;
-    return <Routes getHandle={this.getHandle} {...this.state} />;
+    return <Routes {...this.state} />;
   }
 
   componentDidMount() {
@@ -637,7 +600,6 @@ class App extends React.Component<IProps, IState> {
     this.state = initialState;
     this.fetchTokenomics = this.fetchTokenomics.bind(this);
     this.fetchProposal = this.fetchProposal.bind(this);
-    this.getHandle = this.getHandle.bind(this);
   }
 }
 

+ 10 - 10
src/components/Councils/Leaderboard.tsx

@@ -1,7 +1,7 @@
 import React from "react";
 import { Table } from "react-bootstrap";
 
-import { Member, ProposalDetail } from "../../types";
+import { Member, ProposalDetail, Seat } from "../../types";
 
 interface CouncilMember {
   handle: string;
@@ -18,16 +18,16 @@ interface CouncilVotes {
 const LeaderBoard = (props: {
   proposals: ProposalDetail[];
   members: Member[];
-  councils: number[][];
+  councils: Seat[][];
   cycle: number;
 }) => {
   const { cycle, councils, proposals } = props;
 
-  const summarizeVotes = (id: number, propList: ProposalDetail[]) => {
+  const summarizeVotes = (handle: string, propList: ProposalDetail[]) => {
     let votes = 0;
     propList.forEach((p) => {
-      if (!p || !p.votesByMemberId) return;
-      const vote = p.votesByMemberId.find((v) => v.memberId === id);
+      if (!p || !p.votesByAccount) return;
+      const vote = p.votesByAccount.find((v) => v.handle === handle);
       if (vote && vote.vote !== "") votes++;
     });
     return votes;
@@ -45,15 +45,15 @@ const LeaderBoard = (props: {
       const proposalCount = proposalsRound.length;
 
       const members: CouncilMember[] = council.map(
-        (id: number): CouncilMember => {
-          const member = props.members.find((m) => m.id === id);
+        (seat): CouncilMember => {
+          const member = props.members.find((m) => m.account === seat.member);
           if (!member)
             return { handle: ``, votes: 0, proposalCount, percentage: 0 };
 
-          councilMembers.find((m) => m.id === id) ||
+          councilMembers.find((m) => m.id === member.id) ||
             councilMembers.push(member);
 
-          let votes = summarizeVotes(Number(member.id), proposalsRound);
+          let votes = summarizeVotes(member.handle, proposalsRound);
           const percentage = Math.round((100 * votes) / proposalCount);
           return { handle: member.handle, votes, proposalCount, percentage };
         }
@@ -65,7 +65,7 @@ const LeaderBoard = (props: {
 
   councilMembers = councilMembers
     .map((m) => {
-      return { ...m, id: summarizeVotes(Number(m.id), props.proposals) };
+      return { ...m, id: summarizeVotes(m.handle, props.proposals) };
     })
     .sort((a, b) => b.id - a.id);
 

+ 18 - 22
src/components/Councils/index.tsx

@@ -1,6 +1,6 @@
 import React from "react";
 import { OverlayTrigger, Tooltip, Table } from "react-bootstrap";
-import { Member, ProposalDetail } from "../../types";
+import { Member, ProposalDetail, Seat, Vote } from "../../types";
 import LeaderBoard from "./Leaderboard";
 import Back from "../Back";
 
@@ -13,7 +13,7 @@ const cycle = termDuration + announcingPeriod + votingPeriod + revealingPeriod;
 
 const Rounds = (props: {
   members: Member[];
-  councils: number[][];
+  councils: Seat[][];
   proposals: any;
 }) => {
   const { councils, members, proposals } = props;
@@ -72,15 +72,15 @@ const Rounds = (props: {
 
 const CouncilVotes = (props: {
   round: number;
-  council: number[];
+  council: Seat[];
   members: Member[];
   proposals: ProposalDetail[];
 }) => {
   const { council, members, proposals, round } = props;
 
   let councilMembers: Member[] = [];
-  council.forEach((id) => {
-    const member = members.find((m) => m.id === id);
+  council.forEach((seat) => {
+    const member = members.find((m) => m.account === seat.member);
     if (!member) return;
     councilMembers.push(member);
   });
@@ -122,10 +122,13 @@ const CouncilVotes = (props: {
                 </td>
               </OverlayTrigger>
 
-              {p.votesByMemberId &&
-                council.map((memberId) => (
-                  <td key={memberId}>
-                    <Vote votes={p.votesByMemberId} memberId={memberId} />
+              {p.votesByAccount &&
+                council.map((seat) => (
+                  <td key={seat.member}>
+                    <VoteDiv
+                      votes={p.votesByAccount}
+                      member={members.find((m) => m.account === seat.member)}
+                    />
                   </td>
                 ))}
             </tr>
@@ -140,15 +143,12 @@ const CouncilVotes = (props: {
   );
 };
 
-const Vote = (props: {
-  votes?: { vote: string; memberId: number }[];
-  memberId: number;
-}) => {
-  const { votes, memberId } = props;
+const VoteDiv = (props: { votes?: Vote[]; member?: Member }) => {
+  const { votes, member } = props;
+  if (!votes || !member) return <span />;
 
-  if (!votes) return <div></div>;
-  const v = votes.find((v) => v.memberId === memberId);
-  if (!v) return <div></div>;
+  const v = votes.find((v) => v.handle === member.handle);
+  if (!v) return <span />;
 
   const styles: { [key: string]: string } = {
     Approve: "btn btn-success",
@@ -156,11 +156,7 @@ const Vote = (props: {
     Abstain: "btn btn-outline-light",
   };
 
-  return (
-    <div style={{ width: 100 }} className={`text-center p-1 ${styles[v.vote]}`}>
-      {v.vote}
-    </div>
-  );
+  return <div className={`text-center p-1 ${styles[v.vote]}`}>{v.vote}</div>;
 };
 
 export default Rounds;

+ 2 - 2
src/components/Dashboard/index.tsx

@@ -10,8 +10,8 @@ const Dashboard = (props: IState) => {
   const { block, councils, domain, handles, members, proposals } = props;
   const council: Member[] = [];
   if (councils.length)
-    councils[councils.length - 1].forEach((memberId) => {
-      const member = members.find((m) => m.id === memberId);
+    councils[councils.length - 1].forEach((seat) => {
+      const member = members.find((m) => seat.member === m.account);
       member && council.push(member);
     });
 

+ 11 - 9
src/components/Members/Member.tsx

@@ -1,5 +1,5 @@
 import React from "react";
-import { Member, Post, ProposalDetail } from "../../types";
+import { Member, Post, ProposalDetail, Seat } from "../../types";
 import { domain } from "../../config";
 import Summary from "./Summary";
 import NotFound from "./NotFound";
@@ -8,7 +8,7 @@ import Back from "../Back";
 const MemberBox = (props: {
   match: { params: { handle: string } };
   members: Member[];
-  councils: number[][];
+  councils: Seat[][];
   proposals: ProposalDetail[];
   posts: Post[];
   block: number;
@@ -16,29 +16,31 @@ const MemberBox = (props: {
   validators: string[];
 }) => {
   const { block, now, councils, members, posts, proposals } = props;
-  const handle = props.match.params.handle;
+  const h = props.match.params.handle;
   const member = members.find(
-    (m) => m.handle === handle || String(m.account) === handle
+    (m) => m.handle === h || String(m.account) === h || m.id === Number(h)
   );
   if (!member) return <NotFound />;
 
-  const id = Number(member.id);
   const council = councils[councils.length - 1];
   if (!council) return <div>Loading..</div>;
-  const isCouncilMember = council.includes(id);
+  const isCouncilMember = council.find(
+    (seat) => seat.member === member.account
+  );
 
   return (
     <div>
       <Back target="/members" />
       <div className="box">
         {isCouncilMember && <div>council member</div>}
-        <a href={`${domain}/#/members/${handle}`}>
-          <h1>{handle}</h1>
+        <a href={`${domain}/#/members/${member.handle}`}>
+          <h1>{member.handle}</h1>
+          <span>{member.account}</span>
         </a>
 
         <Summary
           councils={councils}
-          handle={handle}
+          handle={member.handle}
           member={member}
           posts={posts}
           proposals={proposals}

+ 2 - 2
src/components/Members/MemberBox.tsx

@@ -1,11 +1,11 @@
 import React from "react";
 import { OverlayTrigger, Tooltip } from "react-bootstrap";
 import { Link } from "react-router-dom";
-import { Member, Post, ProposalDetail } from "../../types";
+import { Member, Post, ProposalDetail, Seat } from "../../types";
 import MemberOverlay from "./MemberOverlay";
 
 const MemberBox = (props: {
-  councils: number[][];
+  councils: Seat[][];
   members: Member[];
   proposals: ProposalDetail[];
   posts: Post[];

+ 5 - 3
src/components/Members/MemberOverlay.tsx

@@ -1,5 +1,5 @@
 import React from "react";
-import { Member, Post, ProposalDetail } from "../../types";
+import { Member, Post, ProposalDetail, Seat } from "../../types";
 import { domain } from "../../config";
 import Summary from "./Summary";
 import NotFound from "./NotFound";
@@ -7,7 +7,7 @@ import NotFound from "./NotFound";
 const MemberBox = (props: {
   handle: string;
   members: Member[];
-  councils: number[][];
+  councils: Seat[][];
   proposals: ProposalDetail[];
   posts: Post[];
   startTime: number;
@@ -19,7 +19,9 @@ const MemberBox = (props: {
 
   const council = councils[councils.length - 1];
   if (!council) return <div>Loading..</div>;
-  const isCouncilMember = council.includes(member.id);
+  const isCouncilMember = council.find(
+    (seat) => seat.member === member.account
+  );
 
   return (
     <div className="box">

+ 1 - 1
src/components/Members/NotFound.tsx

@@ -4,7 +4,7 @@ import { Link } from "react-router-dom";
 const NotFound = (props: { nolink?: boolean }) => {
   return (
     <div className="box">
-      <div> Member not found</div>
+      <div>No membership found.</div>
       {props.nolink || <Link to={`/members`}>Back</Link>}
     </div>
   );

+ 7 - 5
src/components/Members/Summary/index.tsx

@@ -1,5 +1,5 @@
 import React from "react";
-import { Member, Post, ProposalDetail } from "../../../types";
+import { Member, Post, ProposalDetail, Seat } from "../../../types";
 import { domain } from "../../../config";
 
 import About from "./About";
@@ -15,7 +15,7 @@ interface ProposalVote {
 }
 
 const Summary = (props: {
-  councils: number[][];
+  councils: Seat[][];
   handle: string;
   member: Member;
   posts: Post[];
@@ -25,12 +25,14 @@ const Summary = (props: {
 }) => {
   const { councils, handle, member, proposals, startTime } = props;
 
-  const onCouncil = councils.filter((c) => c.includes(member.id));
+  const onCouncil = councils.filter((c) =>
+    c.find((seat) => seat.member === member.account)
+  );
 
   let votes: ProposalVote[] = [];
   proposals.forEach((p) => {
-    if (!p || !p.votesByMemberId) return;
-    const vote = p.votesByMemberId.find((v) => v.memberId === member.id);
+    if (!p || !p.votesByAccount) return;
+    const vote = p.votesByAccount.find((v) => v.handle === member.handle);
     if (vote && vote.vote !== ``) votes.push({ proposal: p, vote: vote.vote });
   });
   const createdProposals = proposals.filter((p) => p && p.author === handle);

+ 2 - 2
src/components/Members/index.tsx

@@ -1,11 +1,11 @@
 import React from "react";
-import { Handles, Member, Post, ProposalDetail } from "../../types";
+import { Handles, Member, Post, ProposalDetail, Seat } from "../../types";
 import MemberBox from "./MemberBox";
 import Loading from "../Loading";
 import Back from "../Back";
 
 interface IProps {
-  councils: number[][];
+  councils: Seat[][];
   members: Member[];
   handles: Handles;
   proposals: ProposalDetail[];

+ 2 - 2
src/components/Proposals/ProposalTable.tsx

@@ -3,7 +3,7 @@ import { OverlayTrigger, Tooltip } from "react-bootstrap";
 import Row from "./Row";
 import NavBar from "./NavBar";
 import Types from "./Types";
-import { Member, Post, ProposalDetail, ProposalPost } from "../../types";
+import { Member, Post, ProposalDetail, ProposalPost, Seat } from "../../types";
 
 interface IProps {
   block: number;
@@ -13,7 +13,7 @@ interface IProps {
   startTime: number;
 
   // author overlay
-  councils: number[][];
+  councils: Seat[][];
   posts: Post[];
   validators: string[];
 }

+ 11 - 9
src/components/Proposals/Row.tsx

@@ -9,7 +9,14 @@ import Votes from "./VotesTooltip";
 import VoteButton from "./VoteButton";
 import moment from "moment";
 
-import { Member, Post, ProposalDetail, ProposalPost, Vote } from "../../types";
+import {
+  Member,
+  Post,
+  ProposalDetail,
+  ProposalPost,
+  Seat,
+  Vote,
+} from "../../types";
 import { ProposalParameters, VotingResults } from "@joystream/types/proposals";
 
 const formatTime = (time: number) => {
@@ -41,10 +48,10 @@ const ProposalRow = (props: {
   votes: VotingResults;
   members: Member[];
   posts: ProposalPost[];
-  votesByMemberId?: Vote[];
+  votesByAccount?: Vote[];
 
   // author overlay
-  councils: number[][];
+  councils: Seat[][];
   forumPosts: Post[];
   proposals: ProposalDetail[];
   validators: string[];
@@ -80,11 +87,6 @@ const ProposalRow = (props: {
   const hoursStr = hours ? `${hours}h` : "";
   const duration = blocks ? `${daysStr} ${hoursStr} / ${blocks} blocks` : "";
 
-  const getHandle = (memberId: number): string => {
-    const member = members.find((m) => m.id === memberId);
-    return member ? member.handle : String(memberId);
-  };
-
   return (
     <div className="d-flex flex-row justify-content-between text-left p-2">
       <div className="text-right">{id}</div>
@@ -128,7 +130,7 @@ const ProposalRow = (props: {
         placement="left"
         overlay={
           <Tooltip id={`votes-${id}`}>
-            <Votes getHandle={getHandle} votes={props.votesByMemberId} />
+            <Votes votes={props.votesByAccount} />
           </Tooltip>
         }
       >

+ 6 - 12
src/components/Proposals/VotesTooltip.tsx

@@ -2,24 +2,18 @@ import React from "react";
 import { Table } from "react-bootstrap";
 import { Vote } from "../../types";
 
-const VotesTooltip = (props: {
-  getHandle: (id: number) => string;
-  votes?: Vote[];
-}) => {
-  const { getHandle } = props;
-  let votes;
+const VotesTooltip = (props: { votes?: Vote[] }) => {
+  if (!props.votes) return <div>Fetching votes..</div>;
 
-  if (props.votes)
-    votes = props.votes.filter((v) => (v.vote === `` ? false : true));
-  if (!votes) return <div>Fetching votes..</div>;
+  const votes = props.votes.filter((v) => (v.vote === `` ? false : true));
   if (!votes.length) return <div>No votes</div>;
 
   return (
     <Table className="text-left text-light">
       <tbody>
-        {votes.map((v: { memberId: number; vote: string }) => (
-          <tr key={`vote-${v.memberId}`}>
-            <td>{getHandle(v.memberId)}:</td>
+        {votes.map((v) => (
+          <tr key={v.handle}>
+            <td>{v.handle}:</td>
             <td>{v.vote}</td>
           </tr>
         ))}

+ 2 - 2
src/components/Proposals/index.tsx

@@ -1,5 +1,5 @@
 import React from "react";
-import { Member, ProposalDetail, Post, ProposalPost } from "../../types";
+import { Member, ProposalDetail, Post, ProposalPost, Seat } from "../../types";
 import Loading from "..//Loading";
 import ProposalTable from "./ProposalTable";
 
@@ -11,7 +11,7 @@ const Proposals = (props: {
   members: Member[];
 
   // author overlay
-  councils: number[][];
+  councils: Seat[][];
   posts: Post[];
   validators: string[];
 }) => {

+ 11 - 4
src/types.ts

@@ -22,7 +22,7 @@ export interface IState {
   nominators: string[];
   validators: string[];
   loading: boolean;
-  councils: number[][];
+  councils: Seat[][];
   councilElection?: { stage: any; round: number; termEndsAt: number };
   channels: Channel[];
   categories: Category[];
@@ -40,7 +40,14 @@ export interface IState {
 }
 
 export interface Seat {
-  member: AccountId;
+  member: string;
+  stake: number;
+  backers: Backer[];
+}
+
+export interface Backer {
+  member: string;
+  stake: number;
 }
 
 export interface Council {
@@ -69,14 +76,14 @@ export interface ProposalDetail {
   description: any;
   votes: VotingResults;
   type: string;
-  votesByMemberId?: Vote[];
+  votesByAccount?: Vote[];
   author: string;
   authorId: number;
 }
 
 export interface Vote {
   vote: string;
-  memberId: number;
+  handle: string;
 }
 
 export type ProposalArray = number[];