import { ArrowOutwardRounded, HourglassTopRounded, RotateRightOutlined, TimelapseRounded, TimerRounded, } from '@mui/icons-material' import clsx from 'clsx' import { ComponentType } from 'react' import { useTranslation } from 'react-i18next' import TimeAgo from 'react-timeago' import { Coin, GovProposalActionDisplayProps, GovProposalDecodedContent, GovProposalWithDecodedContent, StatefulTokenAmountDisplayProps, } from '@dao-dao/types' import { ProposalStatus } from '@dao-dao/types/protobuf/codegen/cosmos/gov/v1beta1/gov' import { formatDateTimeTz, govProposalToDecodedContent } from '@dao-dao/utils' import { useChainContext } from '../../contexts' import { useTranslatedTimeDeltaFormatter } from '../../hooks' import { IconButtonLink } from '../icon_buttons' import { MarkdownRenderer } from '../MarkdownRenderer' import { Tooltip } from '../tooltip' import { ProposalStatusAndInfo, ProposalStatusAndInfoProps, } from './ProposalStatusAndInfo' export type GovernanceProposalProps = { // Defined if created. Adds external link to proposal and displays ID. id?: string status?: ProposalStatus | 'pending' content: GovProposalDecodedContent deposit: Coin[] startDate?: Date // End of deposit period or voting period, depending on status. endDate?: Date className?: string TokenAmountDisplay: ComponentType GovProposalActionDisplay: ComponentType } export const GovernanceProposal = ({ id, status, content, deposit, startDate, endDate, className, TokenAmountDisplay, GovProposalActionDisplay, }: GovernanceProposalProps) => { const { t } = useTranslation() const timeAgoFormatter = useTranslatedTimeDeltaFormatter({ words: false }) const { config } = useChainContext() const title = content.title || undefined const description = content.description || undefined const info = [ ...(status ? ([ { Icon: RotateRightOutlined, label: t('title.status'), Value: (props) => (

{t(GOV_PROPOSAL_STATUS_I18N_KEY_MAP[status])}

), }, ] as ProposalStatusAndInfoProps['info']) : []), ...(startDate && status !== ProposalStatus.PROPOSAL_STATUS_DEPOSIT_PERIOD ? ([ { Icon: TimelapseRounded, label: t('title.votingOpened'), Value: (props) => (

{typeof startDate === 'string' ? startDate : formatDateTimeTz(startDate)}

), }, ] as ProposalStatusAndInfoProps['info']) : []), // If open for voting, show relative time until end. ...(endDate && status !== ProposalStatus.PROPOSAL_STATUS_DEPOSIT_PERIOD ? status === ProposalStatus.PROPOSAL_STATUS_VOTING_PERIOD ? ([ { Icon: HourglassTopRounded, label: t('title.timeLeft'), Value: (props) => (

), }, ] as ProposalStatusAndInfoProps['info']) : // If closed, show end date. ([ { Icon: TimerRounded, label: t('title.votingClosed'), Value: (props) =>

{formatDateTimeTz(endDate)}

, }, ] as ProposalStatusAndInfoProps['info']) : []), ] return (

{id ? `${id} ` : ''} {title}

{!!id && !!config?.explorerUrlTemplates?.govProp && ( )}
{info.length > 0 && ( )} {!!description && ( )} {!!deposit.length && (

{t('title.deposit')}

{deposit.map((coin) => ( ))}
)}
) } export const GOV_PROPOSAL_STATUS_I18N_KEY_MAP: Record< ProposalStatus | 'pending', string > = { [ProposalStatus.PROPOSAL_STATUS_UNSPECIFIED]: 'govProposalStatus.unspecified', [ProposalStatus.PROPOSAL_STATUS_DEPOSIT_PERIOD]: 'govProposalStatus.depositPeriod', [ProposalStatus.PROPOSAL_STATUS_VOTING_PERIOD]: 'govProposalStatus.votingPeriod', [ProposalStatus.PROPOSAL_STATUS_PASSED]: 'govProposalStatus.passed', [ProposalStatus.PROPOSAL_STATUS_REJECTED]: 'govProposalStatus.rejected', [ProposalStatus.PROPOSAL_STATUS_FAILED]: 'govProposalStatus.failed', [ProposalStatus.UNRECOGNIZED]: 'govProposalStatus.unrecognized', pending: 'govProposalStatus.pendingSubmission', } export type GovernanceProposalFromProposalProps = Pick< GovernanceProposalProps, 'GovProposalActionDisplay' | 'TokenAmountDisplay' | 'className' > & { proposal: GovProposalWithDecodedContent } export const GovernanceProposalFromProposal = ({ proposal, ...props }: GovernanceProposalFromProposalProps) => ( )