pussy-ts/src/containers/governance/proposalsDetail.jsx

/* eslint-disable react/no-children-prop */
import { useEffect, useState } from 'react';
import { Pane, Text, ActionBar } from '@cybercongress/gravity';
import { Link, useParams } from 'react-router-dom';
import { connect } from 'react-redux';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import rehypeSanitize from 'rehype-sanitize';

import { ContainerGradientText, IconStatus, Item } from '../../components';

import {
  getStakingPool,
  getTallying,
  getProposalsDetail,
  getProposer,
  getMinDeposit,
  getTallyingProposals,
} from '../../utils/governance';
import ActionBarDetail from './actionBarDatail';

import { formatNumber } from '../../utils/utils';

import ProposalsIdDetail from './proposalsIdDetail';
import ProposalsDetailProgressBar from './proposalsDetailProgressBar';
import ProposalsIdDetailTableVoters from './proposalsDetailTableVoters';
import { PROPOSAL_STATUS } from '../../utils/config';
import useSetActiveAddress from '../../hooks/useSetActiveAddress';
import { MainContainer } from '../portal/components';

const finalTallyResult = (item) => {
  const finalVotes = {
    yes: 0,
    no: 0,
    abstain: 0,
    noWithVeto: 0,
    finalTotalVotes: 0,
  };
  let finalTotalVotes = 0;
  const yes = parseInt(item.yes, 10);
  const abstain = parseInt(item.abstain, 10);
  const no = parseInt(item.no, 10);
  const noWithVeto = parseInt(item.no_with_veto, 10);

  finalTotalVotes = yes + abstain + no + noWithVeto;
  if (finalTotalVotes !== 0) {
    finalVotes.yes = (yes / finalTotalVotes) * 100;
    finalVotes.no = (no / finalTotalVotes) * 100;
    finalVotes.abstain = (abstain / finalTotalVotes) * 100;
    finalVotes.noWithVeto = (noWithVeto / finalTotalVotes) * 100;
    finalVotes.finalTotalVotes = finalTotalVotes;
  }

  return finalVotes;
};

function ProposalsDetail({ defaultAccount }) {
  const { proposalId } = useParams();
  const { addressActive } = useSetActiveAddress(defaultAccount);
  const [proposals, setProposals] = useState({});
  const [updateFunc, setUpdateFunc] = useState(0);
  const [tally, setTally] = useState({
    participation: 0,
    yes: 0,
    abstain: 0,
    no: 0,
    noWithVeto: 0,
  });
  const [tallying, setTallying] = useState({
    quorum: 0,
    threshold: 0,
    veto_threshold: 0,
  });

  const [totalDeposit, setTotalDeposit] = useState(0);
  const [minDeposit, setMinDeposit] = useState(0);

  useEffect(() => {
    const getProposalsInfo = async () => {
      setProposals({});
      let proposalsInfo = {};
      let totalDepositAmount = 0;
      if (proposalId && proposalId > 0) {
        const responseProposalsDetail = await getProposalsDetail(proposalId);
        if (Object.keys(responseProposalsDetail).length > 0) {
          proposalsInfo = { ...responseProposalsDetail };
          const { title, description, plan, changes, recipient, amount } =
            responseProposalsDetail.content;
          proposalsInfo.title = title;
          proposalsInfo.type = responseProposalsDetail.content['@type'];
          proposalsInfo.description = description;
          proposalsInfo.status =
            PROPOSAL_STATUS[responseProposalsDetail.status];

          if (plan) {
            proposalsInfo.plan = plan;
          }
          if (changes) {
            proposalsInfo.changes = changes;
          }
          if (recipient) {
            proposalsInfo.recipient = recipient;
          }
          if (amount) {
            proposalsInfo.amount = amount;
          }

          const responseProposer = await getProposer(proposalId);

          if (responseProposer !== null) {
            proposalsInfo.proposer = responseProposer.proposer;
          }

          if (responseProposalsDetail.total_deposit.length) {
            totalDepositAmount = parseFloat(
              responseProposalsDetail.total_deposit[0].amount
            );
          }
        }
      }
      setTotalDeposit(totalDepositAmount);
      setProposals(proposalsInfo);
    };
    getProposalsInfo();
  }, [proposalId, updateFunc]);

  useEffect(() => {
    const getStatusVoting = async () => {
      setProposals({});
      let tallyTemp = {};
      let participation = 0;
      let tallyResult = {};
      if (proposalId && proposalId > 0) {
        const stakingPool = await getStakingPool();

        const tallyingResponse = await getTallying();
        if (tallyingResponse !== null) {
          setTallying({ ...tallyingResponse });
        }

        const responceTallyingProposals = await getTallyingProposals(
          proposalId
        );

        if (responceTallyingProposals !== null) {
          tallyResult = responceTallyingProposals;
        } else {
          tallyResult = proposals.final_tally_result;
        }

        tallyTemp = finalTallyResult(tallyResult);
        participation =
          (tallyTemp.finalTotalVotes / stakingPool.bonded_tokens) * 100;
        tallyTemp.participation = participation;
      }
      setTally(tallyTemp);
    };
    getStatusVoting();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [proposalId, updateFunc]);

  useEffect(() => {
    const getDeposit = async () => {
      let minDepositAmount = 0;
      const minDepositData = await getMinDeposit();
      if (minDepositData !== null) {
        minDepositAmount = parseFloat(minDepositData.min_deposit[0].amount);
      }

      setMinDeposit(minDepositAmount);
    };
    getDeposit();
  }, [updateFunc]);

  const getSubStr = (str) => {
    let string = str;
    if (string.indexOf('cosmos-sdk/') !== -1) {
      string = string.slice(string.indexOf('/') + 1);
      return string;
    }
    return string;
  };

  console.log(`proposals`, proposals);
  console.log(`addressActive`, addressActive);

  return (
    <>
      <MainContainer width="100%">
        <Pane display="flex" alignItems="center">
          <Text fontSize="25px" color="#fff">
            {proposals.title && ` #${proposalId} ${proposals.title}`}
          </Text>
        </Pane>

        {proposals.status && (
          <Pane>
            <IconStatus status={proposals.status} text marginRight={8} />
          </Pane>
        )}
        <ContainerGradientText>
          <Item
            marginBottom={15}
            title="Proposer"
            value={
              <Link to={`/network/bostrom/contract/${proposals.proposer}`}>
                {proposals.proposer}
              </Link>
            }
          />
          {proposals.type && (
            <Item
              marginBottom={15}
              title="Type"
              value={getSubStr(proposals.type)}
            />
          )}
          {proposals.recipient && (
            <Item
              title="Recipient"
              marginBottom={15}
              value={
                <Link to={`/network/bostrom/contract/${proposals.recipient}`}>
                  {proposals.recipient}
                </Link>
              }
            />
          )}
          {proposals.amount && (
            <Item
              title="Amount"
              marginBottom={15}
              value={`${formatNumber(
                parseFloat(proposals.amount[0].amount)
              )} ${proposals.amount[0].denom.toUpperCase()}`}
            />
          )}
          {proposals.description && (
            <Item
              title="Description"
              value={
                <Pane className="container-description">
                  <ReactMarkdown
                    children={proposals.description.replace(/\\n/g, '\n')}
                    rehypePlugins={[rehypeSanitize]}
                    remarkPlugins={[remarkGfm]}
                  />
                </Pane>
              }
            />
          )}
          {proposals.changes && Object.keys(proposals.changes).length > 0 && (
            <Item
              title="Changes"
              value={
                <Pane className="container-description">
                  {proposals.changes.map((item) => (
                    <Pane key={item.key}>
                      {item.subspace}: {item.key} {item.value}
                    </Pane>
                  ))}
                </Pane>
              }
            />
          )}
          {proposals.plan && (
            <Item
              title="Plan"
              value={
                <Pane className="container-description">
                  <Pane>name: {proposals.plan.name}</Pane>
                  <Pane>height: {proposals.plan.height}</Pane>
                </Pane>
              }
            />
          )}
        </ContainerGradientText>

        <ProposalsIdDetail
          proposals={proposals}
          tallying={tallying}
          tally={tally}
          totalDeposit={totalDeposit}
          marginBottom={20}
        />

        <ProposalsDetailProgressBar
          proposals={proposals}
          totalDeposit={totalDeposit}
          minDeposit={minDeposit}
          tallying={tallying}
          tally={tally}
        />

        {proposals.status > PROPOSAL_STATUS.PROPOSAL_STATUS_DEPOSIT_PERIOD && (
          <ProposalsIdDetailTableVoters
            proposalId={proposalId}
            updateFunc={updateFunc}
          />
        )}
      </MainContainer>
      {addressActive !== null && addressActive.keys === 'keplr' ? (
        <ActionBarDetail
          id={proposalId}
          proposals={proposals}
          minDeposit={minDeposit}
          totalDeposit={totalDeposit}
          update={() => setUpdateFunc((item) => item + 1)}
          addressActive={addressActive}
        />
      ) : (
        <ActionBar>
          <Pane>
            <Link
              style={{
                paddingTop: 10,
                paddingBottom: 10,
                display: 'block',
              }}
              className="btn"
              to="/"
            >
              add address to your pocket from keplr
            </Link>
          </Pane>
        </ActionBar>
      )}
    </>
  );
}

const mapStateToProps = (store) => {
  return {
    defaultAccount: store.pocket.defaultAccount,
  };
};

export default connect(mapStateToProps)(ProposalsDetail);

Neighbours