src/pages/governance/_components/ProposalDetail.tsx
import BigNumber from "bignumber.js";
import classNames from "classnames";
import { AiFillGithub, AiFillRedditCircle } from "react-icons/ai";
import { MdAccessTimeFilled } from "react-icons/md";
import { NumericFormat } from "react-number-format";
import {
GovernanceProposal,
GovernanceProposalStatus,
GovernanceProposalType,
} from "@defichain/whale-api-client/dist/api/governance";
import { Link } from "@components/commons/link/Link";
import {
isValidOCGGithubUrl,
isValidOCGRedditUrl,
} from "utils/commons/LinkValidator";
import { ProposalDisplayName } from "./ProposalCard";
import { OnChainGovernanceTitles } from "../enum/onChainGovernanceTitles";
import { EmergencyChip } from "./EmergencyChip";
export function ProposalDetail({
proposal,
proposalCreationDate,
proposalEndDate,
}: {
proposal: GovernanceProposal;
proposalCreationDate: string;
proposalEndDate: string;
}) {
const blockPageLink =
proposal.status === GovernanceProposalStatus.VOTING
? `/blocks/countdown/${proposal.cycleEndHeight}`
: `/blocks/${proposal.cycleEndHeight}`;
const isEmergencyProposal = proposal.options?.includes("emergency");
return (
<div className="md:border md:p-6 border-gray-200 dark:border-dark-gray-200 rounded-lg md:dark:bg-dark-gray-100">
<div className="flex mb-2">
<div className="flex justify-between p-2 bg-gray-100 dark:bg-dark-gray-200 rounded">
<span className="text-sm font-medium text-gray-900 dark:text-dark-gray-900">
{ProposalDisplayName[proposal.type]}
</span>
</div>
{isEmergencyProposal && (
<EmergencyChip wrapperClassName="py-2 ml-2" className="text-sm" />
)}
</div>
<div className="text-gray-900 dark:text-dark-gray-900 text-2xl font-semibold md:text-4xl break-words">
{proposal.title}
</div>
<div className="mb-6 md:mb-8 mt-1 md:mt-2 flex md:flex-row flex-col">
<span className="text-sm md:text-base text-gray-500 dark:text-dark-gray-500">
Txn:
</span>
<Link href={{ pathname: `/transactions/${proposal.proposalId}` }}>
<a className="text-sm md:text-base font-semibold hover:underline text-blue-500 cursor-pointer break-all">
{proposal.proposalId}
</a>
</Link>
</div>
<div className="grid md:grid-cols-3 gap-y-3 md:gap-y-8 md:gap-x-8">
<div className="flex flex-row md:flex-col items-center">
<div className="w-1/2 md:w-full mb-0 md:mb-2">
<DetailSectionTitle label="Date posted" />
</div>
<div className="w-1/2 md:w-full flex">
<span className="text-gray-900 dark:text-dark-gray-900 text-sm md:text-lg text-right md:text-left w-full">
{proposalCreationDate}
</span>
</div>
</div>
{proposal.status !== GovernanceProposalStatus.VOTING && (
<div className="flex flex-row md:flex-col">
<div className="w-1/2 md:w-full mb-0 md:mb-2">
<DetailSectionTitle label="Ended on" />
</div>
<div className="w-1/2 md:w-full flex flex-col">
<span className="md:text-lg text-sm text-gray-900 dark:text-dark-gray-900 text-right md:text-left">
Block {proposal.cycleEndHeight}
</span>
<span className="text-gray-600 dark:text-dark-gray-600 text-xs text-right md:text-left w-full">
{proposalEndDate}
</span>
</div>
</div>
)}
{proposal.type === GovernanceProposalType.COMMUNITY_FUND_PROPOSAL && (
<>
<div className="flex flex-row md:flex-col items-center">
<div className="w-1/2 md:w-full mb-0 md:mb-2">
<DetailSectionTitle label="Cycles" />
</div>
<div className="w-1/2 md:w-full flex">
<span className="text-gray-900 dark:text-dark-gray-900 text-sm md:text-lg text-right md:text-left w-full">
{`${
proposal.totalCycles > 1
? `${proposal.currentCycle} of ${proposal.totalCycles} cycles`
: `${proposal.totalCycles} cycle`
}`}
</span>
</div>
</div>
<div className="flex flex-row md:flex-col md:row-start-2">
<div className="w-1/2 md:w-full mb-0 md:mb-2">
<DetailSectionTitle label="Receiving address" />
</div>
<div className="w-1/2 md:w-full flex">
<span className="text-sm md:text-lg text-right md:text-left w-full break-all text-gray-900 dark:text-dark-gray-900">
{proposal.payoutAddress}
</span>
</div>
</div>
<div className="flex flex-row md:flex-col md:row-start-2 items-center">
<div className="w-1/2 md:w-full mb-0 md:mb-2">
<DetailSectionTitle label="Amount requested" />
</div>
<div className="w-1/2 md:w-full flex">
<NumericFormat
value={new BigNumber(proposal.amount ?? 0).toFixed(2)}
fixedDecimalScale
thousandSeparator=","
displayType="text"
suffix=" DFI"
className="text-gray-900 dark:text-dark-gray-900 text-sm md:text-lg text-right md:text-left w-full"
/>
</div>
</div>
</>
)}
<div
className={classNames(
"flex flex-row md:flex-col items-center md:items-start",
{
"md:row-start-2":
proposal.type ===
GovernanceProposalType.COMMUNITY_FUND_PROPOSAL,
}
)}
>
<div className="w-1/2 md:w-full mb-0 md:mb-1">
<DetailSectionTitle label="Discussions" />
</div>
<div className="w-1/2 md:w-fit flex">
<a
target="_blank"
href={proposal.context}
className="text-right md:text-left w-full"
rel="noreferrer"
>
<div className="flex flex-row justify-end items-center gap-x-1 md:gap-x-1 md:px-2 md:py-1 md:border-[0.5px] rounded-[30px] border-gray-200 dark:border-dark-gray-200 hover:border-primary-200 hover:dark:border-dark-primary-200 focus:border-primary-400 focus:dark:border-dark-primary-400 md:w-fit">
{isValidOCGGithubUrl(proposal.context) ? (
<>
<AiFillGithub
size={24}
className="text-gray-900 dark:text-dark-gray-900"
/>
<span className="text-gray-600 dark:text-dark-gray-600 text-sm font-medium">
{OnChainGovernanceTitles.Github}
</span>
</>
) : isValidOCGRedditUrl(proposal.context) ? (
<>
<AiFillRedditCircle
size={24}
className="text-gray-900 dark:text-dark-gray-900"
/>
<span className="text-gray-600 dark:text-dark-gray-600 text-sm font-medium">
{OnChainGovernanceTitles.Reddit}
</span>
</>
) : (
<span className="text-gray-600 dark:text-dark-gray-600 text-sm font-medium">
{OnChainGovernanceTitles.Link}
</span>
)}
</div>
</a>
</div>
</div>
</div>
{proposal.status === GovernanceProposalStatus.VOTING && (
<div className="mt-8 py-3 px-[18px] flex bg-blue-50 dark:bg-dark-blue-500/[0.15] rounded">
<MdAccessTimeFilled
size={22}
className="self-center mr-[18px] text-blue-500"
/>
<div>
<span className="text-sm md:text-lg text-gray-900 dark:text-dark-gray-900">
Voting concludes at
</span>
<Link href={{ pathname: blockPageLink }}>
<a className="text-sm md:text-lg font-semibold hover:underline text-blue-500 cursor-pointer mr-2">
Block {proposal.cycleEndHeight}
</a>
</Link>
<span className="block md:inline text-sm text-gray-500 dark:text-dark-gray-500 align-text-top">
({proposalEndDate})
</span>
</div>
</div>
)}
</div>
);
}
function DetailSectionTitle({
label,
customStyle,
}: {
label: string;
customStyle?: string;
}) {
return (
<span
className={classNames(
"text-gray-500 dark:text-dark-gray-500 text-sm lg:mb-2",
customStyle
)}
>
{label}
</span>
);
}