diff --git a/pioneer/packages/joy-proposals/src/Proposal/ProposalDetails.tsx b/pioneer/packages/joy-proposals/src/Proposal/ProposalDetails.tsx index f3f85b5fe7..075f87843a 100644 --- a/pioneer/packages/joy-proposals/src/Proposal/ProposalDetails.tsx +++ b/pioneer/packages/joy-proposals/src/Proposal/ProposalDetails.tsx @@ -5,7 +5,7 @@ import Body from './Body'; import VotingSection from './VotingSection'; import Votes from './Votes'; import { MyAccountProps, withMyAccount } from '@polkadot/joy-utils/MyAccount'; -import { ParsedProposal, ProposalVotes } from '@polkadot/joy-utils/types/proposals'; +import { ParsedProposal } from '@polkadot/joy-utils/types/proposals'; import { withCalls } from '@polkadot/react-api'; import { withMulti } from '@polkadot/react-api/with'; @@ -14,7 +14,6 @@ import { ProposalId, ProposalDecisionStatuses, ApprovedProposalStatuses, Executi import { BlockNumber } from '@polkadot/types/interfaces'; import { MemberId } from '@joystream/types/members'; import { Seat } from '@joystream/types/council'; -import { PromiseComponent } from '@polkadot/joy-utils/react/components'; import ProposalDiscussion from './discussion/ProposalDiscussion'; import styled from 'styled-components'; @@ -115,7 +114,6 @@ export function getExtendedStatus (proposal: ParsedProposal, bestNumber: BlockNu type ProposalDetailsProps = MyAccountProps & { proposal: ParsedProposal; proposalId: ProposalId; - votesListState: { data: ProposalVotes | null; error: any; loading: boolean }; bestNumber?: BlockNumber; council?: Seat[]; }; @@ -127,8 +125,7 @@ function ProposalDetails ({ myMemberId, iAmMember, council, - bestNumber, - votesListState + bestNumber }: ProposalDetailsProps) { const iAmCouncilMember = Boolean(iAmMember && council && council.some(seat => seat.member.toString() === myAddress)); const iAmProposer = Boolean(iAmMember && myMemberId !== undefined && proposal.proposerId === myMemberId.toNumber()); @@ -156,12 +153,7 @@ function ProposalDetails ({ memberId={ myMemberId as MemberId } isVotingPeriod={ isVotingPeriod }/> ) } - - - + diff --git a/pioneer/packages/joy-proposals/src/Proposal/ProposalFromId.tsx b/pioneer/packages/joy-proposals/src/Proposal/ProposalFromId.tsx index 9750685060..4ddfa58251 100644 --- a/pioneer/packages/joy-proposals/src/Proposal/ProposalFromId.tsx +++ b/pioneer/packages/joy-proposals/src/Proposal/ProposalFromId.tsx @@ -12,14 +12,14 @@ export default function ProposalFromId (props: RouteComponentProps) { } } = props; - const { proposal: proposalState, votes: votesState } = useProposalSubscription(new ProposalId(id)); + const proposalState = useProposalSubscription(new ProposalId(id)); return ( - + ); } diff --git a/pioneer/packages/joy-proposals/src/Proposal/Votes.tsx b/pioneer/packages/joy-proposals/src/Proposal/Votes.tsx index 576e10e1c9..6eec0b42c8 100644 --- a/pioneer/packages/joy-proposals/src/Proposal/Votes.tsx +++ b/pioneer/packages/joy-proposals/src/Proposal/Votes.tsx @@ -1,50 +1,67 @@ import React from 'react'; import { Header, Divider, Table, Icon } from 'semantic-ui-react'; import useVoteStyles from './useVoteStyles'; -import { ProposalVotes } from '@polkadot/joy-utils/types/proposals'; import { VoteKind } from '@joystream/types/proposals'; import { VoteKindStr } from './VotingSection'; import ProfilePreview from '@polkadot/joy-utils/MemberProfilePreview'; +import { useTransport, usePromise } from '@polkadot/joy-utils/react/hooks'; +import { ParsedProposal, ProposalVotes } from '@polkadot/joy-utils/types/proposals'; +import { PromiseComponent } from '@polkadot/joy-utils/react/components'; type VotesProps = { - votes: ProposalVotes; + proposal: ParsedProposal; }; -export default function Votes ({ votes }: VotesProps) { - if (!votes.votes.length) { - return
No votes have been submitted!
; - } +export default function Votes ({ proposal: { id, votingResults } }: VotesProps) { + const transport = useTransport(); + const [votes, error, loading] = usePromise( + () => transport.proposals.votes(id), + null, + [votingResults] + ); return ( - <> -
- All Votes: ({votes.votes.length}/{votes.councilMembersLength}) -
- - - - {votes.votes.map((proposalVote, idx) => { - const { vote, member } = proposalVote; - const voteStr = (vote as VoteKind).type.toString() as VoteKindStr; - const { icon, textColor } = useVoteStyles(voteStr); - return ( - - - - {voteStr} - - - - - - ); - })} - -
- + + { (votes && votes.votes.length > 0) + ? ( + <> +
+ All Votes: ({votes.votes.length}/{votes.councilMembersLength}) +
+ + + + {votes.votes.map((proposalVote, idx) => { + const { vote, member } = proposalVote; + const voteStr = (vote as VoteKind).type.toString() as VoteKindStr; + const { icon, textColor } = useVoteStyles(voteStr); + return ( + + + + {voteStr} + + + + + + ); + })} + +
+ + ) + : ( +
No votes have been submitted!
+ ) + } +
); } diff --git a/pioneer/packages/joy-utils/src/react/hooks/proposals/useProposalSubscription.tsx b/pioneer/packages/joy-utils/src/react/hooks/proposals/useProposalSubscription.tsx index 13697257e5..554d7c4026 100644 --- a/pioneer/packages/joy-utils/src/react/hooks/proposals/useProposalSubscription.tsx +++ b/pioneer/packages/joy-utils/src/react/hooks/proposals/useProposalSubscription.tsx @@ -1,39 +1,41 @@ import { useState, useEffect } from 'react'; -import { ParsedProposal, ProposalVotes } from '../../../types/proposals'; -import { useTransport, usePromise } from '../'; +import { useTransport } from '../'; import { ProposalId } from '@joystream/types/proposals'; +import { ParsedProposal } from '@polkadot/joy-utils/types/proposals'; // Take advantage of polkadot api subscriptions to re-fetch proposal data and votes // each time there is some runtime change in the proposal const useProposalSubscription = (id: ProposalId) => { const transport = useTransport(); - // State holding an "unsubscribe method" - const [unsubscribeProposal, setUnsubscribeProposal] = useState<(() => void) | null>(null); - - const [proposal, proposalError, proposalLoading, refreshProposal] = usePromise( - () => transport.proposals.proposalById(id), - {} as ParsedProposal - ); - - const [votes, votesError, votesLoading, refreshVotes] = usePromise( - () => transport.proposals.votes(id), - null - ); - - // Function to re-fetch the data using transport - const refreshProposalData = () => { - refreshProposal(); - refreshVotes(); - }; + // State holding current proposal data + const [data, setData] = useState(null); + const [error, setError] = useState(null); + const [loading, setLoading] = useState(true); useEffect(() => { // onMount... let unmounted = false; + let unsubscribeProposal: (() => void) | undefined; + const refreshProposalData = () => { + transport.proposals.proposalById(id) + .then(newData => { + if (!unmounted) { + setData(newData); + setLoading(false); + } + }) + .catch(error => { + if (!unmounted) { + setError(error); + setLoading(false); + } + }); + }; // Create the subscription transport.proposals.subscribeProposal(id, refreshProposalData) .then(unsubscribe => { if (!unmounted) { - setUnsubscribeProposal(() => unsubscribe); + unsubscribeProposal = unsubscribe; } else { unsubscribe(); // If already unmounted - unsubscribe immedietally! } @@ -42,14 +44,13 @@ const useProposalSubscription = (id: ProposalId) => { // onUnmount... // Clean the subscription unmounted = true; - if (unsubscribeProposal !== null) unsubscribeProposal(); + if (unsubscribeProposal) { + unsubscribeProposal(); + } }; }, []); - return { - proposal: { data: proposal, error: proposalError, loading: proposalLoading }, - votes: { data: votes, error: votesError, loading: votesLoading } - }; + return { data, error, loading }; }; export default useProposalSubscription;