cyb/src/containers/governance/governance.tsx

/* eslint-disable camelcase */

import { Pane } from '@cybercongress/gravity';
import { useQuery } from '@tanstack/react-query';
import { ProposalStatus } from 'cosmjs-types/cosmos/gov/v1beta1/gov';
import dateFormat from 'dateformat';
import React, { useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import Loader2 from 'src/components/ui/Loader2';
import { BASE_DENOM, DENOM_LIQUID } from 'src/constants/config';
import { useQueryClient } from 'src/contexts/queryClient';
import { useAdviser } from 'src/features/adviser/context';
import { routes } from 'src/routes';
import { ActionBar, CardStatisics } from '../../components';
import { getProposals } from '../../utils/governance';
import { coinDecimals, formatNumber } from '../../utils/utils';
import { AcceptedCard, ActiveCard, RejectedCard } from './components/card';
import Columns from './components/columns';
import styles from './components/styles.module.scss';

type KeyOfProposalStatus = keyof typeof ProposalStatus;

function Statistics({
  communityPoolCyber,
  staked,
}: {
  communityPoolCyber: number;
  staked: number;
}) {
  return (
    <Pane
      marginTop={10}
      marginBottom={50}
      display="grid"
      gridTemplateColumns="repeat(auto-fit, minmax(250px, 1fr))"
      gridGap="20px"
    >
      <CardStatisics
        title={`Community pool, ${BASE_DENOM.toUpperCase()}`}
        value={formatNumber(Math.floor(communityPoolCyber))}
      />
      <Link to="/sphere">
        <CardStatisics title="% of staked BOOT" value={formatNumber(staked * 100)} link />
      </Link>
      <Link to="/network/bostrom/parameters">
        <CardStatisics title="Network parameters" value={53} link />
      </Link>
    </Pane>
  );
}

function ProposalWrapper({
  proposalId,
  children,
}: {
  proposalId: string;
  children: React.ReactNode;
}) {
  return (
    <Link key={proposalId} style={{ color: 'unset' }} to={`/senate/${proposalId}`}>
      {children}
    </Link>
  );
}

//  ProposalsData['proposals'] extends (infer U)[] ? U : never
const mapProposalToCard = (proposal: any) => {
  const {
    id,
    total_deposit,
    status,
    deposit_end_time,
    voting_end_time,
    final_tally_result,
    title,
    messages,
  } = proposal;

  const type = messages[0].content ? messages[0].content['@type'] : messages[0]['@type'];

  return {
    proposalId: id,
    title: title || '<not set>',
    totalDeposit: total_deposit,
    state: ProposalStatus[status as KeyOfProposalStatus],
    timeEndDeposit: deposit_end_time
      ? dateFormat(new Date(deposit_end_time), 'dd/mm/yyyy, HH:MM:ss')
      : undefined,
    timeEndVoting: voting_end_time
      ? dateFormat(new Date(voting_end_time), 'dd/mm/yyyy, HH:MM:ss')
      : undefined,
    amounts: total_deposit[0] || undefined,
    votes: final_tally_result || undefined,
    type,
  };
};

function Governance() {
  const queryClient = useQueryClient();
  const [communityPoolCyber, setCommunityPoolCyber] = useState(0);
  const [staked, setStaked] = useState(0);
  const [_isLoadingStatistics, setIsLoadingStatistics] = useState(true);
  const { setAdviser } = useAdviser();

  useEffect(() => {
    setAdviser(
      <>
        the place where community will hear you
        <br /> propose your idea here
      </>
    );
  }, [setAdviser]);

  useEffect(() => {
    const getStatistics = async () => {
      if (queryClient) {
        setIsLoadingStatistics(true);
        let communityPool = 0;
        const totalCyb: Record<string, number> = {};
        let stakedBoot = 0;

        const dataCommunityPool = await queryClient.communityPool();
        const { pool } = dataCommunityPool;
        if (dataCommunityPool !== null) {
          communityPool = coinDecimals(Math.floor(parseFloat(pool[0].amount)));
        }
        setCommunityPoolCyber(communityPool);

        const datagetTotalSupply = await queryClient.totalSupply();
        if (Object.keys(datagetTotalSupply).length > 0) {
          datagetTotalSupply.forEach((item) => {
            totalCyb[item.denom] = parseFloat(item.amount);
          });
        }
        if (totalCyb[BASE_DENOM] && totalCyb[DENOM_LIQUID]) {
          stakedBoot = totalCyb[DENOM_LIQUID] / totalCyb[BASE_DENOM];
        }
        setStaked(stakedBoot);
        setIsLoadingStatistics(false);
      }
    };
    getStatistics();
  }, [queryClient]);

  const { data: tableData = [], isLoading: isLoadingProposals } = useQuery(
    ['proposals'],
    async () => {
      const response = await getProposals();
      return response || [];
    }
  );

  const active = (tableData || [])
    .reverse()
    .filter(
      (item) =>
        ProposalStatus[item.status as KeyOfProposalStatus] < ProposalStatus.PROPOSAL_STATUS_PASSED
    )
    .map(mapProposalToCard)
    .map((item) => (
      <ProposalWrapper proposalId={item.proposalId!} key={`active_${item.proposalId}`}>
        <ActiveCard
          key={item.proposalId}
          id={item.proposalId}
          name={item.title}
          type={item.type}
          state={item.state}
          timeEndDeposit={item.timeEndDeposit}
          timeEndVoting={item.timeEndVoting}
        />
      </ProposalWrapper>
    ));

  const accepted = (tableData || [])
    .filter(
      (item) =>
        ProposalStatus[item.status as KeyOfProposalStatus] === ProposalStatus.PROPOSAL_STATUS_PASSED
    )
    .map(mapProposalToCard)
    .map((item) => (
      <ProposalWrapper proposalId={item.proposalId} key={`accepted_${item.proposalId}`}>
        <AcceptedCard
          key={item.proposalId}
          id={item.proposalId}
          name={item.title}
          votes={item.votes}
          type={item.type}
          timeEnd={item.timeEndDeposit}
        />
      </ProposalWrapper>
    ));

  const rejected = (tableData || [])
    .reverse()
    .filter(
      (item) =>
        ProposalStatus[item.status as KeyOfProposalStatus] > ProposalStatus.PROPOSAL_STATUS_PASSED
    )
    .map(mapProposalToCard)
    .map((item) => (
      <ProposalWrapper proposalId={item.proposalId} key={`rejected_${item.proposalId}`}>
        <RejectedCard
          key={item.proposalId}
          id={item.proposalId}
          name={item.title}
          votes={item.votes}
          type={item.type}
          timeEnd={item.timeEndVoting}
        />
      </ProposalWrapper>
    ));

  return (
    <>
      <Statistics communityPoolCyber={communityPoolCyber} staked={staked} />

      {isLoadingProposals ? (
        <Loader2 />
      ) : (
        <div className={styles.column}>
          <Columns title="Active">{active}</Columns>
          <Columns title="Accepted">{accepted}</Columns>
          <Columns title="Rejected">{rejected}</Columns>
        </div>
      )}

      <ActionBar
        button={{
          text: 'Propose',
          link: routes.senate.routes.new.path,
        }}
      />
    </>
  );
}

export default Governance;

Synonyms

pussy-ts/src/containers/governance/governance.tsx

Neighbours