From 977359f438e17d9bef5f63d791aaf7a98cbd953c Mon Sep 17 00:00:00 2001 From: Adam Goth Date: Tue, 2 Nov 2021 08:52:02 +0100 Subject: [PATCH 1/4] Add text for expired and not passed --- modules/executive/helpers/getStatusText.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/modules/executive/helpers/getStatusText.ts b/modules/executive/helpers/getStatusText.ts index dc3a15d34..d00db4ece 100644 --- a/modules/executive/helpers/getStatusText.ts +++ b/modules/executive/helpers/getStatusText.ts @@ -1,4 +1,5 @@ import { formatDateWithTime } from 'lib/datetime'; +import { isBefore } from 'date-fns'; import { SPELL_SCHEDULED_DATE_OVERRIDES } from 'lib/constants'; import { SpellData } from '../types/spellData'; import { ZERO_ADDRESS } from 'stores/accounts'; @@ -11,6 +12,7 @@ export const getStatusText = (proposalAddress: string, spellData?: SpellData): s chief has been activated!`; } + // check if scheduled or has been executed if (spellData.hasBeenScheduled || spellData.dateExecuted) { if (typeof spellData.dateExecuted === 'string') { return `Passed on ${formatDateWithTime(spellData.datePassed)}. Executed on ${formatDateWithTime( @@ -25,5 +27,15 @@ export const getStatusText = (proposalAddress: string, spellData?: SpellData): s .`; } } + + // hasn't been scheduled or executed, check if expired + const isExpired = spellData.expiration ? isBefore(new Date(spellData.expiration), new Date()) : false; + if (isExpired) { + return `This proposal expired at ${formatDateWithTime( + spellData.expiration + )} and can no longer be exectuted.`; + } + + // hasn't been scheduled, executed, hasn't expired, must be active and not passed yet return 'This proposal has not yet passed and is not available for execution.'; }; From ec1bf983f3deada48180116dca35a7eb8f69b23d Mon Sep 17 00:00:00 2001 From: Adam Goth Date: Tue, 2 Nov 2021 13:33:50 +0100 Subject: [PATCH 2/4] Add mkr needed to pass --- .../components/ExecutiveOverviewCard.tsx | 9 +++--- modules/executive/helpers/getStatusText.ts | 26 +++++++++++++++-- modules/executive/hooks/useMkrOnHat.ts | 28 +++++++++++++++++++ pages/executive/[proposal-id].tsx | 15 ++++++++-- 4 files changed, 68 insertions(+), 10 deletions(-) create mode 100644 modules/executive/hooks/useMkrOnHat.ts diff --git a/modules/executive/components/ExecutiveOverviewCard.tsx b/modules/executive/components/ExecutiveOverviewCard.tsx index 5ad790915..c89b33d14 100644 --- a/modules/executive/components/ExecutiveOverviewCard.tsx +++ b/modules/executive/components/ExecutiveOverviewCard.tsx @@ -17,17 +17,18 @@ import Stack from 'modules/app/components/layout/layouts/Stack'; import VoteModal from './VoteModal'; import { useAnalytics } from 'modules/app/client/analytics/useAnalytics'; import { ANALYTICS_PAGES } from 'modules/app/client/analytics/analytics.constants'; +import { useMkrOnHat } from 'modules/executive/hooks/useMkrOnHat'; type Props = { proposal: Proposal; - spellData?: SpellData; isHat: boolean; + spellData?: SpellData; }; -export default function ExecutiveOverviewCard({ proposal, spellData, isHat, ...props }: Props): JSX.Element { +export default function ExecutiveOverviewCard({ proposal, isHat, spellData, ...props }: Props): JSX.Element { const { trackButtonClick } = useAnalytics(ANALYTICS_PAGES.EXECUTIVE); - const account = useAccountsStore(state => state.currentAccount); + const { data: mkrOnHat } = useMkrOnHat(); const [voting, setVoting] = useState(false); const { data: votedProposals } = useVotedProposals(); const network = getNetwork(); @@ -178,7 +179,7 @@ export default function ExecutiveOverviewCard({ proposal, spellData, isHat, ...p - {getStatusText(proposal.address, spellData)} + {getStatusText({ proposalAddress: proposal.address, spellData, mkrOnHat })} diff --git a/modules/executive/helpers/getStatusText.ts b/modules/executive/helpers/getStatusText.ts index d00db4ece..0800b3109 100644 --- a/modules/executive/helpers/getStatusText.ts +++ b/modules/executive/helpers/getStatusText.ts @@ -1,10 +1,20 @@ +import BigNumber from 'bignumber.js'; import { formatDateWithTime } from 'lib/datetime'; import { isBefore } from 'date-fns'; import { SPELL_SCHEDULED_DATE_OVERRIDES } from 'lib/constants'; import { SpellData } from '../types/spellData'; import { ZERO_ADDRESS } from 'stores/accounts'; +import { CurrencyObject } from 'types/currency'; -export const getStatusText = (proposalAddress: string, spellData?: SpellData): string => { +export const getStatusText = ({ + proposalAddress, + spellData, + mkrOnHat +}: { + proposalAddress: string; + spellData?: SpellData; + mkrOnHat?: CurrencyObject; +}): string => { if (!spellData) return 'Fetching status...'; if (proposalAddress === ZERO_ADDRESS) { @@ -28,12 +38,22 @@ export const getStatusText = (proposalAddress: string, spellData?: SpellData): s } } - // hasn't been scheduled or executed, check if expired + // hasn't been passed or executed, check if expired const isExpired = spellData.expiration ? isBefore(new Date(spellData.expiration), new Date()) : false; if (isExpired) { return `This proposal expired at ${formatDateWithTime( spellData.expiration - )} and can no longer be exectuted.`; + )} and can no longer be executed.`; + } + + // not expired, passed, or executed, check support level + if (!!spellData.mkrSupport && !!mkrOnHat) { + return `${mkrOnHat + .toBigNumber() + .minus(new BigNumber(spellData.mkrSupport)) + .toFormat(2)} additional MKR support needed to pass. Expires at ${formatDateWithTime( + spellData.expiration + )}.`; } // hasn't been scheduled, executed, hasn't expired, must be active and not passed yet diff --git a/modules/executive/hooks/useMkrOnHat.ts b/modules/executive/hooks/useMkrOnHat.ts new file mode 100644 index 000000000..894bf8627 --- /dev/null +++ b/modules/executive/hooks/useMkrOnHat.ts @@ -0,0 +1,28 @@ +import getMaker from 'lib/maker'; +import useSWR from 'swr'; +import { CurrencyObject } from 'types/currency'; + +type MkrOnHatResponse = { + data?: CurrencyObject; + loading: boolean; + error: Error; +}; + +export const useMkrOnHat = (): MkrOnHatResponse => { + const { data, error } = useSWR( + '/executive/mkr-on-hat', + async () => { + const maker = await getMaker(); + const hat = await maker.service('chief').getHat(); + return maker.service('chief').getApprovalCount(hat); + }, + // refresh every 5 mins + { refreshInterval: 300000 } + ); + + return { + data, + loading: !error && !data, + error + }; +}; diff --git a/pages/executive/[proposal-id].tsx b/pages/executive/[proposal-id].tsx index 79b402cdf..816a79ffd 100644 --- a/pages/executive/[proposal-id].tsx +++ b/pages/executive/[proposal-id].tsx @@ -14,6 +14,7 @@ import invariant from 'tiny-invariant'; import { getExecutiveProposal, getExecutiveProposals } from 'modules/executive/api/fetchExecutives'; import { useSpellData } from 'modules/executive/hooks/useSpellData'; import { useVotedProposals } from 'modules/executive/hooks/useVotedProposals'; +import { useMkrOnHat } from 'modules/executive/hooks/useMkrOnHat'; import { getNetwork, isDefaultNetwork } from 'lib/maker'; import { cutMiddle, limitString } from 'lib/string'; import { getStatusText } from 'modules/executive/helpers/getStatusText'; @@ -38,6 +39,7 @@ import { SpellEffectsTab } from 'modules/executive/components/SpellEffectsTab'; //types import { CMSProposal, Proposal, SpellData } from 'modules/executive/types'; +import { CurrencyObject } from 'types/currency'; type Props = { proposal: Proposal; @@ -50,17 +52,21 @@ const editMarkdown = content => { const ProposalTimingBanner = ({ proposal, - spellData + spellData, + mkrOnHat }: { proposal: CMSProposal; spellData?: SpellData; + mkrOnHat?: CurrencyObject; }): JSX.Element => { if (spellData || proposal.address === ZERO_ADDRESS) return ( <> - {getStatusText(proposal.address, spellData)} + + {getStatusText({ proposalAddress: proposal.address, spellData, mkrOnHat })} + @@ -81,6 +87,7 @@ const ProposalView = ({ proposal }: Props): JSX.Element => { ); const { data: votedProposals } = useVotedProposals(); + const { data: mkrOnHat } = useMkrOnHat(); const { data: comments, error: commentsError } = useSWR( `/api/executive/comments/list/${proposal.address}`, @@ -202,7 +209,9 @@ const ProposalView = ({ proposal }: Props): JSX.Element => { , commentsTab ]} - banner={} + banner={ + + } > ) : ( Date: Tue, 2 Nov 2021 14:02:07 +0100 Subject: [PATCH 3/4] Attempt CI update --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 17a060099..a91e7e60c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,6 +3,7 @@ jobs: install: docker: - image: circleci/node:14.17.3 + resource_class: large steps: - checkout - restore_cache: From 471d0c2c336230035660051cd608acd2f6e710a4 Mon Sep 17 00:00:00 2001 From: Adam Goth Date: Tue, 2 Nov 2021 14:14:30 +0100 Subject: [PATCH 4/4] Undo --- .circleci/config.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a91e7e60c..17a060099 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,7 +3,6 @@ jobs: install: docker: - image: circleci/node:14.17.3 - resource_class: large steps: - checkout - restore_cache: