Fix/1622 proposal vote deadline fixes (#1730)
* Fix/1622: Partial progress * Fix/1622: Proposal forms fields now correctly updating when vote deadline 'use min' and 'use max' are clicked * Fix/1622: Removing some unused imports * Fix/1622: WIP commit for generics for deadline component * Fix/1622: WIP commit for generics for deadline component * Fix/1622: Separate minMax functions * Fix/1622: Updated unit tests * Update apps/token/src/routes/governance/components/propose/proposal-form-vote-and-enactment-deadline.spec.tsx Co-authored-by: Dexter Edwards <dexter.edwards93@gmail.com> * Fix/1622: Tweaks from PR comments * Fix/1622: Tests fixes * chore: fix min proposer change for tests * frontend-monorepo-1622 Removed unused value in governance-flow.cy.js Co-authored-by: Dexter Edwards <dexter.edwards93@gmail.com> Co-authored-by: Joe <joe@vega.xyz>
This commit is contained in:
parent
2fa640a467
commit
269d3820dc
@ -61,7 +61,7 @@ context(
|
|||||||
cy.verify_page_header('The $VEGA token');
|
cy.verify_page_header('The $VEGA token');
|
||||||
cy.get_network_parameters().then((network_parameters) => {
|
cy.get_network_parameters().then((network_parameters) => {
|
||||||
cy.wrap(
|
cy.wrap(
|
||||||
network_parameters['spam.protection.proposal.min.tokens'] /
|
network_parameters['spam.protection.voting.min.tokens'] /
|
||||||
1000000000000000000
|
1000000000000000000
|
||||||
).as('minProposerBalance');
|
).as('minProposerBalance');
|
||||||
cy.wrap(
|
cy.wrap(
|
||||||
@ -115,11 +115,6 @@ context(
|
|||||||
0.00001,
|
0.00001,
|
||||||
'Asserting that value is at least 0.00001 for network parameter minProposerBalance'
|
'Asserting that value is at least 0.00001 for network parameter minProposerBalance'
|
||||||
);
|
);
|
||||||
assert.isAtLeast(
|
|
||||||
parseInt(this.minVoterBalance),
|
|
||||||
0.00001,
|
|
||||||
'Asserting that value is at least 0.00001 for network parameter minVoterBalance'
|
|
||||||
);
|
|
||||||
assert.isAtLeast(
|
assert.isAtLeast(
|
||||||
parseFloat(this.requiredParticipation),
|
parseFloat(this.requiredParticipation),
|
||||||
0.00001,
|
0.00001,
|
||||||
|
@ -23,16 +23,20 @@ const expectedDate = (expected: string) => new Date(expected).toLocaleString();
|
|||||||
|
|
||||||
const renderComponent = () => {
|
const renderComponent = () => {
|
||||||
const register = jest.fn();
|
const register = jest.fn();
|
||||||
|
const setValue = jest.fn();
|
||||||
render(
|
render(
|
||||||
<ProposalFormVoteAndEnactmentDeadline
|
<ProposalFormVoteAndEnactmentDeadline
|
||||||
|
onVoteMinMax={setValue}
|
||||||
voteRegister={register('proposalVoteDeadline')}
|
voteRegister={register('proposalVoteDeadline')}
|
||||||
voteErrorMessage={undefined}
|
voteErrorMessage={undefined}
|
||||||
voteMinClose={minVoteDeadline}
|
voteMinClose={minVoteDeadline}
|
||||||
voteMaxClose={maxVoteDeadline}
|
voteMaxClose={maxVoteDeadline}
|
||||||
|
onEnactMinMax={setValue}
|
||||||
enactmentRegister={register('proposalEnactmentDeadline')}
|
enactmentRegister={register('proposalEnactmentDeadline')}
|
||||||
enactmentErrorMessage={undefined}
|
enactmentErrorMessage={undefined}
|
||||||
enactmentMinClose={minEnactDeadline}
|
enactmentMinClose={minEnactDeadline}
|
||||||
enactmentMaxClose={maxEnactDeadline}
|
enactmentMaxClose={maxEnactDeadline}
|
||||||
|
onValidationMinMax={setValue}
|
||||||
validationRequired={true}
|
validationRequired={true}
|
||||||
validationRegister={register('proposalValidationDeadline')}
|
validationRegister={register('proposalValidationDeadline')}
|
||||||
validationErrorMessage={undefined}
|
validationErrorMessage={undefined}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { useEffect, useState, useMemo } from 'react';
|
import { useEffect, useState, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { parse as ISO8601Parse, toSeconds } from 'iso8601-duration';
|
|
||||||
import {
|
import {
|
||||||
ButtonLink,
|
ButtonLink,
|
||||||
FormGroup,
|
FormGroup,
|
||||||
@ -8,22 +7,29 @@ import {
|
|||||||
InputError,
|
InputError,
|
||||||
} from '@vegaprotocol/ui-toolkit';
|
} from '@vegaprotocol/ui-toolkit';
|
||||||
import { addHours, addMinutes } from 'date-fns';
|
import { addHours, addMinutes } from 'date-fns';
|
||||||
|
import {
|
||||||
|
deadlineToSeconds,
|
||||||
|
secondsToRoundedHours,
|
||||||
|
} from '@vegaprotocol/governance';
|
||||||
import { ProposalFormSubheader } from './proposal-form-subheader';
|
import { ProposalFormSubheader } from './proposal-form-subheader';
|
||||||
import type { UseFormRegisterReturn } from 'react-hook-form';
|
import type { UseFormRegisterReturn } from 'react-hook-form';
|
||||||
|
|
||||||
interface DeadlineProps {
|
interface DeadlineProps {
|
||||||
vote: number;
|
vote: number;
|
||||||
enactment: number;
|
enactment: number | undefined;
|
||||||
validation: number;
|
validation: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DeadlineDatesProps {
|
interface DeadlineDatesProps {
|
||||||
vote: Date;
|
vote: Date;
|
||||||
enactment: Date;
|
enactment: Date | undefined;
|
||||||
validation: Date;
|
validation: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ValidationFormProps {
|
interface ValidationFormProps {
|
||||||
|
onValidationMinMax:
|
||||||
|
| ((field: 'proposalValidationDeadline', value: string) => void)
|
||||||
|
| undefined;
|
||||||
validationRegister:
|
validationRegister:
|
||||||
| UseFormRegisterReturn<'proposalValidationDeadline'>
|
| UseFormRegisterReturn<'proposalValidationDeadline'>
|
||||||
| undefined;
|
| undefined;
|
||||||
@ -34,6 +40,7 @@ interface ValidationFormProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ValidationForm = ({
|
const ValidationForm = ({
|
||||||
|
onValidationMinMax,
|
||||||
validationRegister,
|
validationRegister,
|
||||||
deadlines,
|
deadlines,
|
||||||
deadlineDates,
|
deadlineDates,
|
||||||
@ -69,13 +76,24 @@ const ValidationForm = ({
|
|||||||
<div className="flex items-center gap-4 text-sm">
|
<div className="flex items-center gap-4 text-sm">
|
||||||
<ButtonLink
|
<ButtonLink
|
||||||
data-testid="min-validation"
|
data-testid="min-validation"
|
||||||
onClick={() => updateValidationDeadlineAndDate(0)}
|
onClick={() => {
|
||||||
|
onValidationMinMax &&
|
||||||
|
onValidationMinMax('proposalValidationDeadline', '0');
|
||||||
|
updateValidationDeadlineAndDate(0);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{t('UseMin')}
|
{t('UseMin')}
|
||||||
</ButtonLink>
|
</ButtonLink>
|
||||||
<ButtonLink
|
<ButtonLink
|
||||||
data-testid="max-validation"
|
data-testid="max-validation"
|
||||||
onClick={() => updateValidationDeadlineAndDate(deadlines.vote)}
|
onClick={() => {
|
||||||
|
onValidationMinMax &&
|
||||||
|
onValidationMinMax(
|
||||||
|
'proposalValidationDeadline',
|
||||||
|
deadlines.vote.toString()
|
||||||
|
);
|
||||||
|
updateValidationDeadlineAndDate(deadlines.vote);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{t('UseMax')}
|
{t('UseMax')}
|
||||||
</ButtonLink>
|
</ButtonLink>
|
||||||
@ -108,6 +126,9 @@ const ValidationForm = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
interface EnactmentFormProps {
|
interface EnactmentFormProps {
|
||||||
|
onEnactMinMax:
|
||||||
|
| ((field: 'proposalEnactmentDeadline', value: string) => void)
|
||||||
|
| undefined;
|
||||||
enactmentRegister:
|
enactmentRegister:
|
||||||
| UseFormRegisterReturn<'proposalEnactmentDeadline'>
|
| UseFormRegisterReturn<'proposalEnactmentDeadline'>
|
||||||
| undefined;
|
| undefined;
|
||||||
@ -120,6 +141,7 @@ interface EnactmentFormProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const EnactmentForm = ({
|
const EnactmentForm = ({
|
||||||
|
onEnactMinMax,
|
||||||
enactmentRegister,
|
enactmentRegister,
|
||||||
deadlines,
|
deadlines,
|
||||||
deadlineDates,
|
deadlineDates,
|
||||||
@ -157,13 +179,27 @@ const EnactmentForm = ({
|
|||||||
<div className="flex items-center gap-4 text-sm">
|
<div className="flex items-center gap-4 text-sm">
|
||||||
<ButtonLink
|
<ButtonLink
|
||||||
data-testid="min-enactment"
|
data-testid="min-enactment"
|
||||||
onClick={() => updateEnactmentDeadlineAndDate(minEnactmentHours)}
|
onClick={() => {
|
||||||
|
onEnactMinMax &&
|
||||||
|
onEnactMinMax(
|
||||||
|
'proposalEnactmentDeadline',
|
||||||
|
minEnactmentHours.toString()
|
||||||
|
);
|
||||||
|
updateEnactmentDeadlineAndDate(minEnactmentHours);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{t('UseMin')}
|
{t('UseMin')}
|
||||||
</ButtonLink>
|
</ButtonLink>
|
||||||
<ButtonLink
|
<ButtonLink
|
||||||
data-testid="max-enactment"
|
data-testid="max-enactment"
|
||||||
onClick={() => updateEnactmentDeadlineAndDate(maxEnactmentHours)}
|
onClick={() => {
|
||||||
|
onEnactMinMax &&
|
||||||
|
onEnactMinMax(
|
||||||
|
'proposalEnactmentDeadline',
|
||||||
|
maxEnactmentHours.toString()
|
||||||
|
);
|
||||||
|
updateEnactmentDeadlineAndDate(maxEnactmentHours);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{t('UseMax')}
|
{t('UseMax')}
|
||||||
</ButtonLink>
|
</ButtonLink>
|
||||||
@ -188,33 +224,42 @@ const EnactmentForm = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
export interface ProposalFormVoteAndEnactmentDeadlineProps {
|
export interface ProposalFormVoteAndEnactmentDeadlineProps {
|
||||||
|
onVoteMinMax: (field: 'proposalVoteDeadline', value: string) => void;
|
||||||
voteRegister: UseFormRegisterReturn<'proposalVoteDeadline'>;
|
voteRegister: UseFormRegisterReturn<'proposalVoteDeadline'>;
|
||||||
voteErrorMessage: string | undefined;
|
voteErrorMessage: string | undefined;
|
||||||
voteMinClose: string;
|
voteMinClose: string;
|
||||||
voteMaxClose: string;
|
voteMaxClose: string;
|
||||||
enactmentRequired?: boolean;
|
enactmentRequired?: boolean;
|
||||||
|
onEnactMinMax?: (field: 'proposalEnactmentDeadline', value: string) => void;
|
||||||
enactmentRegister?: UseFormRegisterReturn<'proposalEnactmentDeadline'>;
|
enactmentRegister?: UseFormRegisterReturn<'proposalEnactmentDeadline'>;
|
||||||
enactmentErrorMessage?: string;
|
enactmentErrorMessage?: string;
|
||||||
enactmentMinClose?: string;
|
enactmentMinClose?: string;
|
||||||
enactmentMaxClose?: string;
|
enactmentMaxClose?: string;
|
||||||
validationRequired?: boolean;
|
validationRequired?: boolean;
|
||||||
|
onValidationMinMax?: (
|
||||||
|
field: 'proposalValidationDeadline',
|
||||||
|
value: string
|
||||||
|
) => void;
|
||||||
validationRegister?: UseFormRegisterReturn<'proposalValidationDeadline'>;
|
validationRegister?: UseFormRegisterReturn<'proposalValidationDeadline'>;
|
||||||
validationErrorMessage?: string;
|
validationErrorMessage?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ProposalFormVoteAndEnactmentDeadline = ({
|
export function ProposalFormVoteAndEnactmentDeadline({
|
||||||
|
onVoteMinMax,
|
||||||
voteRegister,
|
voteRegister,
|
||||||
voteErrorMessage,
|
voteErrorMessage,
|
||||||
voteMinClose,
|
voteMinClose,
|
||||||
voteMaxClose,
|
voteMaxClose,
|
||||||
|
onEnactMinMax,
|
||||||
enactmentRegister,
|
enactmentRegister,
|
||||||
enactmentErrorMessage,
|
enactmentErrorMessage,
|
||||||
enactmentMinClose,
|
enactmentMinClose,
|
||||||
enactmentMaxClose,
|
enactmentMaxClose,
|
||||||
validationRequired,
|
validationRequired,
|
||||||
|
onValidationMinMax,
|
||||||
validationRegister,
|
validationRegister,
|
||||||
validationErrorMessage,
|
validationErrorMessage,
|
||||||
}: ProposalFormVoteAndEnactmentDeadlineProps) => {
|
}: ProposalFormVoteAndEnactmentDeadlineProps) {
|
||||||
const {
|
const {
|
||||||
minVoteSeconds,
|
minVoteSeconds,
|
||||||
maxVoteSeconds,
|
maxVoteSeconds,
|
||||||
@ -222,18 +267,12 @@ export const ProposalFormVoteAndEnactmentDeadline = ({
|
|||||||
maxEnactmentSeconds,
|
maxEnactmentSeconds,
|
||||||
} = useMemo(
|
} = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
minVoteSeconds: toSeconds(
|
minVoteSeconds: deadlineToSeconds(voteMinClose),
|
||||||
ISO8601Parse(`PT${voteMinClose.toUpperCase()}`)
|
maxVoteSeconds: deadlineToSeconds(voteMaxClose),
|
||||||
),
|
|
||||||
maxVoteSeconds: toSeconds(
|
|
||||||
ISO8601Parse(`PT${voteMaxClose.toUpperCase()}`)
|
|
||||||
),
|
|
||||||
minEnactmentSeconds:
|
minEnactmentSeconds:
|
||||||
enactmentMinClose &&
|
enactmentMinClose && deadlineToSeconds(enactmentMinClose),
|
||||||
toSeconds(ISO8601Parse(`PT${enactmentMinClose.toUpperCase()}`)),
|
|
||||||
maxEnactmentSeconds:
|
maxEnactmentSeconds:
|
||||||
enactmentMaxClose &&
|
enactmentMaxClose && deadlineToSeconds(enactmentMaxClose),
|
||||||
toSeconds(ISO8601Parse(`PT${enactmentMaxClose.toUpperCase()}`)),
|
|
||||||
}),
|
}),
|
||||||
[voteMinClose, voteMaxClose, enactmentMinClose, enactmentMaxClose]
|
[voteMinClose, voteMaxClose, enactmentMinClose, enactmentMaxClose]
|
||||||
);
|
);
|
||||||
@ -243,17 +282,14 @@ export const ProposalFormVoteAndEnactmentDeadline = ({
|
|||||||
const { minVoteHours, maxVoteHours, minEnactmentHours, maxEnactmentHours } =
|
const { minVoteHours, maxVoteHours, minEnactmentHours, maxEnactmentHours } =
|
||||||
useMemo(
|
useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
minVoteHours:
|
minVoteHours: secondsToRoundedHours(minVoteSeconds),
|
||||||
Math.floor(minVoteSeconds / 3600) > 1
|
maxVoteHours: secondsToRoundedHours(maxVoteSeconds),
|
||||||
? Math.floor(minVoteSeconds / 3600)
|
minEnactmentHours: minEnactmentSeconds
|
||||||
: 1,
|
? secondsToRoundedHours(minEnactmentSeconds)
|
||||||
maxVoteHours: Math.floor(maxVoteSeconds / 3600),
|
: undefined,
|
||||||
minEnactmentHours:
|
maxEnactmentHours: maxEnactmentSeconds
|
||||||
minEnactmentSeconds && Math.floor(minEnactmentSeconds / 3600) > 1
|
? secondsToRoundedHours(maxEnactmentSeconds)
|
||||||
? Math.floor(minEnactmentSeconds / 3600)
|
: undefined,
|
||||||
: 1,
|
|
||||||
maxEnactmentHours:
|
|
||||||
maxEnactmentSeconds && Math.floor(maxEnactmentSeconds / 3600),
|
|
||||||
}),
|
}),
|
||||||
[minVoteSeconds, maxVoteSeconds, minEnactmentSeconds, maxEnactmentSeconds]
|
[minVoteSeconds, maxVoteSeconds, minEnactmentSeconds, maxEnactmentSeconds]
|
||||||
);
|
);
|
||||||
@ -269,7 +305,9 @@ export const ProposalFormVoteAndEnactmentDeadline = ({
|
|||||||
deadlines.vote === minVoteHours
|
deadlines.vote === minVoteHours
|
||||||
? addHours(addMinutes(new Date(), 2), deadlines.vote)
|
? addHours(addMinutes(new Date(), 2), deadlines.vote)
|
||||||
: addHours(new Date(), deadlines.vote),
|
: addHours(new Date(), deadlines.vote),
|
||||||
enactment: addHours(new Date(), deadlines.vote + deadlines.enactment),
|
enactment: deadlines.enactment
|
||||||
|
? addHours(new Date(), deadlines.vote + deadlines.enactment)
|
||||||
|
: undefined,
|
||||||
validation:
|
validation:
|
||||||
deadlines.validation === 0
|
deadlines.validation === 0
|
||||||
? addHours(addMinutes(new Date(), 2), deadlines.validation)
|
? addHours(addMinutes(new Date(), 2), deadlines.validation)
|
||||||
@ -284,7 +322,9 @@ export const ProposalFormVoteAndEnactmentDeadline = ({
|
|||||||
deadlines.vote === minVoteHours
|
deadlines.vote === minVoteHours
|
||||||
? addHours(addMinutes(new Date(), 2), deadlines.vote)
|
? addHours(addMinutes(new Date(), 2), deadlines.vote)
|
||||||
: addHours(new Date(), deadlines.vote),
|
: addHours(new Date(), deadlines.vote),
|
||||||
enactment: addHours(new Date(), deadlines.vote + deadlines.enactment),
|
enactment: deadlines.enactment
|
||||||
|
? addHours(new Date(), deadlines.vote + deadlines.enactment)
|
||||||
|
: undefined,
|
||||||
validation:
|
validation:
|
||||||
deadlines.validation === 0
|
deadlines.validation === 0
|
||||||
? addHours(addMinutes(new Date(), 2), deadlines.validation)
|
? addHours(addMinutes(new Date(), 2), deadlines.validation)
|
||||||
@ -301,7 +341,7 @@ export const ProposalFormVoteAndEnactmentDeadline = ({
|
|||||||
setDeadlines((prev) => ({
|
setDeadlines((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
vote: hours,
|
vote: hours,
|
||||||
validation: Math.min(prev.validation, hours),
|
validation: prev.validation && Math.min(prev.validation, hours),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// If the vote deadline is set to minimum, add 2 mins to the date as we do
|
// If the vote deadline is set to minimum, add 2 mins to the date as we do
|
||||||
@ -317,7 +357,9 @@ export const ProposalFormVoteAndEnactmentDeadline = ({
|
|||||||
hours === minVoteHours
|
hours === minVoteHours
|
||||||
? addHours(addMinutes(new Date(), 2), hours)
|
? addHours(addMinutes(new Date(), 2), hours)
|
||||||
: addHours(new Date(), hours),
|
: addHours(new Date(), hours),
|
||||||
enactment: addHours(new Date(), hours + deadlines.enactment),
|
enactment: deadlines.enactment
|
||||||
|
? addHours(new Date(), hours + deadlines.enactment)
|
||||||
|
: undefined,
|
||||||
validation: addHours(new Date(), Math.min(hours, deadlines.validation)),
|
validation: addHours(new Date(), Math.min(hours, deadlines.validation)),
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
@ -384,13 +426,19 @@ export const ProposalFormVoteAndEnactmentDeadline = ({
|
|||||||
<div className="flex items-center gap-4 text-sm">
|
<div className="flex items-center gap-4 text-sm">
|
||||||
<ButtonLink
|
<ButtonLink
|
||||||
data-testid="min-vote"
|
data-testid="min-vote"
|
||||||
onClick={() => updateVoteDeadlineAndDate(minVoteHours)}
|
onClick={() => {
|
||||||
|
onVoteMinMax('proposalVoteDeadline', minVoteHours.toString());
|
||||||
|
updateVoteDeadlineAndDate(minVoteHours);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{t('UseMin')}
|
{t('UseMin')}
|
||||||
</ButtonLink>
|
</ButtonLink>
|
||||||
<ButtonLink
|
<ButtonLink
|
||||||
data-testid="max-vote"
|
data-testid="max-vote"
|
||||||
onClick={() => updateVoteDeadlineAndDate(maxVoteHours)}
|
onClick={() => {
|
||||||
|
onVoteMinMax('proposalVoteDeadline', maxVoteHours.toString());
|
||||||
|
updateVoteDeadlineAndDate(maxVoteHours);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{t('UseMax')}
|
{t('UseMax')}
|
||||||
</ButtonLink>
|
</ButtonLink>
|
||||||
@ -422,6 +470,7 @@ export const ProposalFormVoteAndEnactmentDeadline = ({
|
|||||||
|
|
||||||
{validationRequired && (
|
{validationRequired && (
|
||||||
<ValidationForm
|
<ValidationForm
|
||||||
|
onValidationMinMax={onValidationMinMax}
|
||||||
validationRegister={validationRegister}
|
validationRegister={validationRegister}
|
||||||
deadlines={deadlines}
|
deadlines={deadlines}
|
||||||
deadlineDates={deadlineDates}
|
deadlineDates={deadlineDates}
|
||||||
@ -430,8 +479,9 @@ export const ProposalFormVoteAndEnactmentDeadline = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{enactmentMinClose && enactmentMaxClose && maxEnactmentHours && (
|
{minEnactmentHours && maxEnactmentHours && (
|
||||||
<EnactmentForm
|
<EnactmentForm
|
||||||
|
onEnactMinMax={onEnactMinMax}
|
||||||
enactmentRegister={enactmentRegister}
|
enactmentRegister={enactmentRegister}
|
||||||
deadlines={deadlines}
|
deadlines={deadlines}
|
||||||
deadlineDates={deadlineDates}
|
deadlineDates={deadlineDates}
|
||||||
@ -443,4 +493,4 @@ export const ProposalFormVoteAndEnactmentDeadline = ({
|
|||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
@ -3,6 +3,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import {
|
import {
|
||||||
getClosingTimestamp,
|
getClosingTimestamp,
|
||||||
useProposalSubmit,
|
useProposalSubmit,
|
||||||
|
deadlineToRoundedHours,
|
||||||
} from '@vegaprotocol/governance';
|
} from '@vegaprotocol/governance';
|
||||||
import { useEnvironment } from '@vegaprotocol/environment';
|
import { useEnvironment } from '@vegaprotocol/environment';
|
||||||
import {
|
import {
|
||||||
@ -44,10 +45,17 @@ export const ProposeFreeform = () => {
|
|||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
formState: { isSubmitting, errors },
|
formState: { isSubmitting, errors },
|
||||||
|
setValue,
|
||||||
} = useForm<FreeformProposalFormFields>();
|
} = useForm<FreeformProposalFormFields>();
|
||||||
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
||||||
|
|
||||||
const onSubmit = async (fields: FreeformProposalFormFields) => {
|
const onSubmit = async (fields: FreeformProposalFormFields) => {
|
||||||
|
const isVoteDeadlineAtMinimum =
|
||||||
|
fields.proposalVoteDeadline ===
|
||||||
|
deadlineToRoundedHours(
|
||||||
|
params.governance_proposal_freeform_minClose
|
||||||
|
).toString();
|
||||||
|
|
||||||
await submit({
|
await submit({
|
||||||
rationale: {
|
rationale: {
|
||||||
title: fields.proposalTitle,
|
title: fields.proposalTitle,
|
||||||
@ -55,7 +63,10 @@ export const ProposeFreeform = () => {
|
|||||||
},
|
},
|
||||||
terms: {
|
terms: {
|
||||||
newFreeform: {},
|
newFreeform: {},
|
||||||
closingTimestamp: getClosingTimestamp(fields.proposalVoteDeadline),
|
closingTimestamp: getClosingTimestamp(
|
||||||
|
fields.proposalVoteDeadline,
|
||||||
|
isVoteDeadlineAtMinimum
|
||||||
|
),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -114,6 +125,7 @@ export const ProposeFreeform = () => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<ProposalFormVoteAndEnactmentDeadline
|
<ProposalFormVoteAndEnactmentDeadline
|
||||||
|
onVoteMinMax={setValue}
|
||||||
voteRegister={register('proposalVoteDeadline', {
|
voteRegister={register('proposalVoteDeadline', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
|
@ -9,6 +9,7 @@ import {
|
|||||||
getClosingTimestamp,
|
getClosingTimestamp,
|
||||||
getEnactmentTimestamp,
|
getEnactmentTimestamp,
|
||||||
useProposalSubmit,
|
useProposalSubmit,
|
||||||
|
deadlineToRoundedHours,
|
||||||
} from '@vegaprotocol/governance';
|
} from '@vegaprotocol/governance';
|
||||||
import { useEnvironment } from '@vegaprotocol/environment';
|
import { useEnvironment } from '@vegaprotocol/environment';
|
||||||
import {
|
import {
|
||||||
@ -89,6 +90,7 @@ export const ProposeNetworkParameter = () => {
|
|||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
formState: { isSubmitting, errors },
|
formState: { isSubmitting, errors },
|
||||||
|
setValue,
|
||||||
} = useForm<NetworkParameterProposalFormFields>();
|
} = useForm<NetworkParameterProposalFormFields>();
|
||||||
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
||||||
|
|
||||||
@ -100,6 +102,13 @@ export const ProposeNetworkParameter = () => {
|
|||||||
const acutalNetworkParamKey = fields.proposalNetworkParameterKey
|
const acutalNetworkParamKey = fields.proposalNetworkParameterKey
|
||||||
.split('_')
|
.split('_')
|
||||||
.join('.');
|
.join('.');
|
||||||
|
|
||||||
|
const isVoteDeadlineAtMinimum =
|
||||||
|
fields.proposalVoteDeadline ===
|
||||||
|
deadlineToRoundedHours(
|
||||||
|
params.governance_proposal_updateNetParam_minClose
|
||||||
|
).toString();
|
||||||
|
|
||||||
await submit({
|
await submit({
|
||||||
rationale: {
|
rationale: {
|
||||||
title: fields.proposalTitle,
|
title: fields.proposalTitle,
|
||||||
@ -112,10 +121,14 @@ export const ProposeNetworkParameter = () => {
|
|||||||
value: fields.proposalNetworkParameterValue,
|
value: fields.proposalNetworkParameterValue,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
closingTimestamp: getClosingTimestamp(fields.proposalVoteDeadline),
|
closingTimestamp: getClosingTimestamp(
|
||||||
|
fields.proposalVoteDeadline,
|
||||||
|
isVoteDeadlineAtMinimum
|
||||||
|
),
|
||||||
enactmentTimestamp: getEnactmentTimestamp(
|
enactmentTimestamp: getEnactmentTimestamp(
|
||||||
fields.proposalVoteDeadline,
|
fields.proposalVoteDeadline,
|
||||||
fields.proposalEnactmentDeadline
|
fields.proposalEnactmentDeadline,
|
||||||
|
isVoteDeadlineAtMinimum
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -243,6 +256,7 @@ export const ProposeNetworkParameter = () => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<ProposalFormVoteAndEnactmentDeadline
|
<ProposalFormVoteAndEnactmentDeadline
|
||||||
|
onVoteMinMax={setValue}
|
||||||
voteRegister={register('proposalVoteDeadline', {
|
voteRegister={register('proposalVoteDeadline', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
@ -253,6 +267,7 @@ export const ProposeNetworkParameter = () => {
|
|||||||
voteMaxClose={
|
voteMaxClose={
|
||||||
params.governance_proposal_updateNetParam_maxClose
|
params.governance_proposal_updateNetParam_maxClose
|
||||||
}
|
}
|
||||||
|
onEnactMinMax={setValue}
|
||||||
enactmentRegister={register('proposalEnactmentDeadline', {
|
enactmentRegister={register('proposalEnactmentDeadline', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
|
@ -5,6 +5,7 @@ import {
|
|||||||
getEnactmentTimestamp,
|
getEnactmentTimestamp,
|
||||||
getValidationTimestamp,
|
getValidationTimestamp,
|
||||||
useProposalSubmit,
|
useProposalSubmit,
|
||||||
|
deadlineToRoundedHours,
|
||||||
} from '@vegaprotocol/governance';
|
} from '@vegaprotocol/governance';
|
||||||
import { useEnvironment } from '@vegaprotocol/environment';
|
import { useEnvironment } from '@vegaprotocol/environment';
|
||||||
import {
|
import {
|
||||||
@ -59,10 +60,17 @@ export const ProposeNewAsset = () => {
|
|||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
formState: { isSubmitting, errors },
|
formState: { isSubmitting, errors },
|
||||||
|
setValue,
|
||||||
} = useForm<NewAssetProposalFormFields>();
|
} = useForm<NewAssetProposalFormFields>();
|
||||||
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
||||||
|
|
||||||
const onSubmit = async (fields: NewAssetProposalFormFields) => {
|
const onSubmit = async (fields: NewAssetProposalFormFields) => {
|
||||||
|
const isVoteDeadlineAtMinimum =
|
||||||
|
fields.proposalVoteDeadline ===
|
||||||
|
deadlineToRoundedHours(
|
||||||
|
params.governance_proposal_asset_minClose
|
||||||
|
).toString();
|
||||||
|
|
||||||
await submit({
|
await submit({
|
||||||
rationale: {
|
rationale: {
|
||||||
title: fields.proposalTitle,
|
title: fields.proposalTitle,
|
||||||
@ -72,10 +80,14 @@ export const ProposeNewAsset = () => {
|
|||||||
newAsset: {
|
newAsset: {
|
||||||
...JSON.parse(fields.proposalTerms),
|
...JSON.parse(fields.proposalTerms),
|
||||||
},
|
},
|
||||||
closingTimestamp: getClosingTimestamp(fields.proposalVoteDeadline),
|
closingTimestamp: getClosingTimestamp(
|
||||||
|
fields.proposalVoteDeadline,
|
||||||
|
isVoteDeadlineAtMinimum
|
||||||
|
),
|
||||||
enactmentTimestamp: getEnactmentTimestamp(
|
enactmentTimestamp: getEnactmentTimestamp(
|
||||||
fields.proposalVoteDeadline,
|
fields.proposalVoteDeadline,
|
||||||
fields.proposalEnactmentDeadline
|
fields.proposalEnactmentDeadline,
|
||||||
|
isVoteDeadlineAtMinimum
|
||||||
),
|
),
|
||||||
validationTimestamp: getValidationTimestamp(
|
validationTimestamp: getValidationTimestamp(
|
||||||
fields.proposalValidationDeadline
|
fields.proposalValidationDeadline
|
||||||
@ -155,12 +167,14 @@ export const ProposeNewAsset = () => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<ProposalFormVoteAndEnactmentDeadline
|
<ProposalFormVoteAndEnactmentDeadline
|
||||||
|
onVoteMinMax={setValue}
|
||||||
voteRegister={register('proposalVoteDeadline', {
|
voteRegister={register('proposalVoteDeadline', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
voteErrorMessage={errors?.proposalVoteDeadline?.message}
|
voteErrorMessage={errors?.proposalVoteDeadline?.message}
|
||||||
voteMinClose={params.governance_proposal_asset_minClose}
|
voteMinClose={params.governance_proposal_asset_minClose}
|
||||||
voteMaxClose={params.governance_proposal_asset_maxClose}
|
voteMaxClose={params.governance_proposal_asset_maxClose}
|
||||||
|
onEnactMinMax={setValue}
|
||||||
enactmentRegister={register('proposalEnactmentDeadline', {
|
enactmentRegister={register('proposalEnactmentDeadline', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
@ -170,6 +184,7 @@ export const ProposeNewAsset = () => {
|
|||||||
enactmentMinClose={params.governance_proposal_asset_minEnact}
|
enactmentMinClose={params.governance_proposal_asset_minEnact}
|
||||||
enactmentMaxClose={params.governance_proposal_asset_maxEnact}
|
enactmentMaxClose={params.governance_proposal_asset_maxEnact}
|
||||||
validationRequired={true}
|
validationRequired={true}
|
||||||
|
onValidationMinMax={setValue}
|
||||||
validationRegister={register('proposalValidationDeadline', {
|
validationRegister={register('proposalValidationDeadline', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
|
@ -4,6 +4,7 @@ import {
|
|||||||
getClosingTimestamp,
|
getClosingTimestamp,
|
||||||
getEnactmentTimestamp,
|
getEnactmentTimestamp,
|
||||||
useProposalSubmit,
|
useProposalSubmit,
|
||||||
|
deadlineToRoundedHours,
|
||||||
} from '@vegaprotocol/governance';
|
} from '@vegaprotocol/governance';
|
||||||
import { useEnvironment } from '@vegaprotocol/environment';
|
import { useEnvironment } from '@vegaprotocol/environment';
|
||||||
import {
|
import {
|
||||||
@ -57,10 +58,17 @@ export const ProposeNewMarket = () => {
|
|||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
formState: { isSubmitting, errors },
|
formState: { isSubmitting, errors },
|
||||||
|
setValue,
|
||||||
} = useForm<NewMarketProposalFormFields>();
|
} = useForm<NewMarketProposalFormFields>();
|
||||||
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
||||||
|
|
||||||
const onSubmit = async (fields: NewMarketProposalFormFields) => {
|
const onSubmit = async (fields: NewMarketProposalFormFields) => {
|
||||||
|
const isVoteDeadlineAtMinimum =
|
||||||
|
fields.proposalVoteDeadline ===
|
||||||
|
deadlineToRoundedHours(
|
||||||
|
params.governance_proposal_market_minClose
|
||||||
|
).toString();
|
||||||
|
|
||||||
await submit({
|
await submit({
|
||||||
rationale: {
|
rationale: {
|
||||||
title: fields.proposalTitle,
|
title: fields.proposalTitle,
|
||||||
@ -70,10 +78,14 @@ export const ProposeNewMarket = () => {
|
|||||||
newMarket: {
|
newMarket: {
|
||||||
...JSON.parse(fields.proposalTerms),
|
...JSON.parse(fields.proposalTerms),
|
||||||
},
|
},
|
||||||
closingTimestamp: getClosingTimestamp(fields.proposalVoteDeadline),
|
closingTimestamp: getClosingTimestamp(
|
||||||
|
fields.proposalVoteDeadline,
|
||||||
|
isVoteDeadlineAtMinimum
|
||||||
|
),
|
||||||
enactmentTimestamp: getEnactmentTimestamp(
|
enactmentTimestamp: getEnactmentTimestamp(
|
||||||
fields.proposalVoteDeadline,
|
fields.proposalVoteDeadline,
|
||||||
fields.proposalEnactmentDeadline
|
fields.proposalEnactmentDeadline,
|
||||||
|
isVoteDeadlineAtMinimum
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -150,12 +162,14 @@ export const ProposeNewMarket = () => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<ProposalFormVoteAndEnactmentDeadline
|
<ProposalFormVoteAndEnactmentDeadline
|
||||||
|
onVoteMinMax={setValue}
|
||||||
voteRegister={register('proposalVoteDeadline', {
|
voteRegister={register('proposalVoteDeadline', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
voteErrorMessage={errors?.proposalVoteDeadline?.message}
|
voteErrorMessage={errors?.proposalVoteDeadline?.message}
|
||||||
voteMinClose={params.governance_proposal_market_minClose}
|
voteMinClose={params.governance_proposal_market_minClose}
|
||||||
voteMaxClose={params.governance_proposal_market_maxClose}
|
voteMaxClose={params.governance_proposal_market_maxClose}
|
||||||
|
onEnactMinMax={setValue}
|
||||||
enactmentRegister={register('proposalEnactmentDeadline', {
|
enactmentRegister={register('proposalEnactmentDeadline', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
|
@ -4,6 +4,7 @@ import {
|
|||||||
getClosingTimestamp,
|
getClosingTimestamp,
|
||||||
getEnactmentTimestamp,
|
getEnactmentTimestamp,
|
||||||
useProposalSubmit,
|
useProposalSubmit,
|
||||||
|
deadlineToRoundedHours,
|
||||||
} from '@vegaprotocol/governance';
|
} from '@vegaprotocol/governance';
|
||||||
import { useEnvironment } from '@vegaprotocol/environment';
|
import { useEnvironment } from '@vegaprotocol/environment';
|
||||||
import {
|
import {
|
||||||
@ -57,10 +58,17 @@ export const ProposeUpdateAsset = () => {
|
|||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
formState: { isSubmitting, errors },
|
formState: { isSubmitting, errors },
|
||||||
|
setValue,
|
||||||
} = useForm<UpdateAssetProposalFormFields>();
|
} = useForm<UpdateAssetProposalFormFields>();
|
||||||
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
||||||
|
|
||||||
const onSubmit = async (fields: UpdateAssetProposalFormFields) => {
|
const onSubmit = async (fields: UpdateAssetProposalFormFields) => {
|
||||||
|
const isVoteDeadlineAtMinimum =
|
||||||
|
fields.proposalVoteDeadline ===
|
||||||
|
deadlineToRoundedHours(
|
||||||
|
params.governance_proposal_updateAsset_minClose
|
||||||
|
).toString();
|
||||||
|
|
||||||
await submit({
|
await submit({
|
||||||
rationale: {
|
rationale: {
|
||||||
title: fields.proposalTitle,
|
title: fields.proposalTitle,
|
||||||
@ -70,10 +78,14 @@ export const ProposeUpdateAsset = () => {
|
|||||||
updateAsset: {
|
updateAsset: {
|
||||||
...JSON.parse(fields.proposalTerms),
|
...JSON.parse(fields.proposalTerms),
|
||||||
},
|
},
|
||||||
closingTimestamp: getClosingTimestamp(fields.proposalVoteDeadline),
|
closingTimestamp: getClosingTimestamp(
|
||||||
|
fields.proposalVoteDeadline,
|
||||||
|
isVoteDeadlineAtMinimum
|
||||||
|
),
|
||||||
enactmentTimestamp: getEnactmentTimestamp(
|
enactmentTimestamp: getEnactmentTimestamp(
|
||||||
fields.proposalVoteDeadline,
|
fields.proposalVoteDeadline,
|
||||||
fields.proposalEnactmentDeadline
|
fields.proposalEnactmentDeadline,
|
||||||
|
isVoteDeadlineAtMinimum
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -152,6 +164,7 @@ export const ProposeUpdateAsset = () => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<ProposalFormVoteAndEnactmentDeadline
|
<ProposalFormVoteAndEnactmentDeadline
|
||||||
|
onVoteMinMax={setValue}
|
||||||
voteRegister={register('proposalVoteDeadline', {
|
voteRegister={register('proposalVoteDeadline', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
|
@ -6,6 +6,7 @@ import {
|
|||||||
getClosingTimestamp,
|
getClosingTimestamp,
|
||||||
getEnactmentTimestamp,
|
getEnactmentTimestamp,
|
||||||
useProposalSubmit,
|
useProposalSubmit,
|
||||||
|
deadlineToRoundedHours,
|
||||||
} from '@vegaprotocol/governance';
|
} from '@vegaprotocol/governance';
|
||||||
import { useEnvironment } from '@vegaprotocol/environment';
|
import { useEnvironment } from '@vegaprotocol/environment';
|
||||||
import {
|
import {
|
||||||
@ -117,10 +118,17 @@ export const ProposeUpdateMarket = () => {
|
|||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
formState: { isSubmitting, errors },
|
formState: { isSubmitting, errors },
|
||||||
|
setValue,
|
||||||
} = useForm<UpdateMarketProposalFormFields>();
|
} = useForm<UpdateMarketProposalFormFields>();
|
||||||
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
const { finalizedProposal, submit, Dialog } = useProposalSubmit();
|
||||||
|
|
||||||
const onSubmit = async (fields: UpdateMarketProposalFormFields) => {
|
const onSubmit = async (fields: UpdateMarketProposalFormFields) => {
|
||||||
|
const isVoteDeadlineAtMinimum =
|
||||||
|
fields.proposalVoteDeadline ===
|
||||||
|
deadlineToRoundedHours(
|
||||||
|
params.governance_proposal_updateMarket_minClose
|
||||||
|
).toString();
|
||||||
|
|
||||||
await submit({
|
await submit({
|
||||||
rationale: {
|
rationale: {
|
||||||
title: fields.proposalTitle,
|
title: fields.proposalTitle,
|
||||||
@ -133,10 +141,14 @@ export const ProposeUpdateMarket = () => {
|
|||||||
...JSON.parse(fields.proposalTerms),
|
...JSON.parse(fields.proposalTerms),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
closingTimestamp: getClosingTimestamp(fields.proposalVoteDeadline),
|
closingTimestamp: getClosingTimestamp(
|
||||||
|
fields.proposalVoteDeadline,
|
||||||
|
isVoteDeadlineAtMinimum
|
||||||
|
),
|
||||||
enactmentTimestamp: getEnactmentTimestamp(
|
enactmentTimestamp: getEnactmentTimestamp(
|
||||||
fields.proposalVoteDeadline,
|
fields.proposalVoteDeadline,
|
||||||
fields.proposalEnactmentDeadline
|
fields.proposalEnactmentDeadline,
|
||||||
|
isVoteDeadlineAtMinimum
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -269,6 +281,7 @@ export const ProposeUpdateMarket = () => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<ProposalFormVoteAndEnactmentDeadline
|
<ProposalFormVoteAndEnactmentDeadline
|
||||||
|
onVoteMinMax={setValue}
|
||||||
voteRegister={register('proposalVoteDeadline', {
|
voteRegister={register('proposalVoteDeadline', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
@ -279,6 +292,7 @@ export const ProposeUpdateMarket = () => {
|
|||||||
voteMaxClose={
|
voteMaxClose={
|
||||||
params.governance_proposal_updateMarket_maxClose
|
params.governance_proposal_updateMarket_maxClose
|
||||||
}
|
}
|
||||||
|
onEnactMinMax={setValue}
|
||||||
enactmentRegister={register('proposalEnactmentDeadline', {
|
enactmentRegister={register('proposalEnactmentDeadline', {
|
||||||
required: t('Required'),
|
required: t('Required'),
|
||||||
})}
|
})}
|
||||||
|
41
libs/governance/src/utils/deadline-helpers.spec.ts
Normal file
41
libs/governance/src/utils/deadline-helpers.spec.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { deadlineToSeconds, secondsToRoundedHours } from './deadline-helpers';
|
||||||
|
|
||||||
|
describe('deadlineToSeconds', () => {
|
||||||
|
it('should throw an error if the deadline does not match the format "XhXmXs"', () => {
|
||||||
|
expect(() => deadlineToSeconds('abcde')).toThrowError(
|
||||||
|
'Invalid deadline format, expected format "XhXmXs", got "abcde"'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should convert "0h0m1s" to 1', () => {
|
||||||
|
expect(deadlineToSeconds('0h0m1s')).toEqual(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should convert "0h1m0s" to 60', () => {
|
||||||
|
expect(deadlineToSeconds('0h1m0s')).toEqual(60);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should convert "1h0m0s" to 3600', () => {
|
||||||
|
expect(deadlineToSeconds('1h0m0s')).toEqual(3600);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should convert "1h1m1s" to 3661', () => {
|
||||||
|
expect(deadlineToSeconds('1h1m1s')).toEqual(3661);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('secondsToRoundedHours', () => {
|
||||||
|
it('should return 1 hour for anything up to 3600 seconds', () => {
|
||||||
|
expect(secondsToRoundedHours(0)).toEqual(1);
|
||||||
|
expect(secondsToRoundedHours(3600)).toEqual(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should round to the nearest hour for anything more than 3600 seconds', () => {
|
||||||
|
// 5399 seconds is 1 hour 29 minutes 59 seconds
|
||||||
|
expect(secondsToRoundedHours(5399)).toEqual(1);
|
||||||
|
expect(secondsToRoundedHours(5400)).toEqual(2);
|
||||||
|
// 8999 seconds is 2 hours 29 minutes 59 seconds
|
||||||
|
expect(secondsToRoundedHours(8999)).toEqual(2);
|
||||||
|
expect(secondsToRoundedHours(9000)).toEqual(3);
|
||||||
|
});
|
||||||
|
});
|
22
libs/governance/src/utils/deadline-helpers.ts
Normal file
22
libs/governance/src/utils/deadline-helpers.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { parse as ISO8601Parse, toSeconds } from 'iso8601-duration';
|
||||||
|
|
||||||
|
// Converts API deadlines ("XhXmXs") to seconds
|
||||||
|
export const deadlineToSeconds = (deadline: string) => {
|
||||||
|
// check that the deadline string matches the format "XhXmXs"
|
||||||
|
const regex = /^(\d+h)?(\d+m)?(\d+s)?$/;
|
||||||
|
if (!regex.test(deadline)) {
|
||||||
|
throw new Error(
|
||||||
|
`Invalid deadline format, expected format "XhXmXs", got "${deadline}"`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return toSeconds(ISO8601Parse(`PT${deadline.toUpperCase()}`));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Converts seconds to rounded hours, min 1 hour
|
||||||
|
export const secondsToRoundedHours = (seconds: number) => {
|
||||||
|
const hours = Math.round(seconds / 3600);
|
||||||
|
return hours < 1 ? 1 : hours;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deadlineToRoundedHours = (deadline: string) =>
|
||||||
|
secondsToRoundedHours(deadlineToSeconds(deadline));
|
@ -11,23 +11,31 @@ afterEach(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('getClosingTimestamp', () => {
|
describe('getClosingTimestamp', () => {
|
||||||
it('should return the correct timestamp if the proposalVoteDeadline is 1 (when 2 mins are added)', () => {
|
it('should return the correct timestamp if the proposalVoteDeadline is set to minimum (when 2 mins are added)', () => {
|
||||||
const proposalVoteDeadline = '1';
|
const proposalVoteDeadline = '1';
|
||||||
|
const isMinimumDeadlineSelected = true;
|
||||||
const expected = Math.floor(
|
const expected = Math.floor(
|
||||||
getTime(
|
getTime(
|
||||||
addHours(addMinutes(new Date(), 2), Number(proposalVoteDeadline))
|
addHours(addMinutes(new Date(), 2), Number(proposalVoteDeadline))
|
||||||
) / 1000
|
) / 1000
|
||||||
);
|
);
|
||||||
const actual = getClosingTimestamp(proposalVoteDeadline);
|
const actual = getClosingTimestamp(
|
||||||
|
proposalVoteDeadline,
|
||||||
|
isMinimumDeadlineSelected
|
||||||
|
);
|
||||||
expect(actual).toEqual(expected);
|
expect(actual).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the correct timestamp if the proposalVoteDeadline is 2 (when no extra mins are added)', () => {
|
it('should return the correct timestamp if the proposalVoteDeadline is not set to minimum (when no extra mins are added)', () => {
|
||||||
const proposalVoteDeadline = '2';
|
const proposalVoteDeadline = '2';
|
||||||
|
const isMinimumDeadlineSelected = false;
|
||||||
const expected = Math.floor(
|
const expected = Math.floor(
|
||||||
getTime(addHours(new Date(), Number(proposalVoteDeadline))) / 1000
|
getTime(addHours(new Date(), Number(proposalVoteDeadline))) / 1000
|
||||||
);
|
);
|
||||||
const actual = getClosingTimestamp(proposalVoteDeadline);
|
const actual = getClosingTimestamp(
|
||||||
|
proposalVoteDeadline,
|
||||||
|
isMinimumDeadlineSelected
|
||||||
|
);
|
||||||
expect(actual).toEqual(expected);
|
expect(actual).toEqual(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,13 +1,16 @@
|
|||||||
import { addHours, addMinutes, getTime } from 'date-fns';
|
import { addHours, addMinutes, getTime } from 'date-fns';
|
||||||
|
|
||||||
// If proposaVoteDeadline is at its minimum of 1 hour, then we add
|
// If proposaVoteDeadline is at its minimum, then we add
|
||||||
// 2 extra minutes to the closing timestamp to ensure that there's time
|
// 2 extra minutes to the closing timestamp to ensure that there's time
|
||||||
// to confirm in the wallet.
|
// to confirm in the wallet.
|
||||||
|
|
||||||
export const getClosingTimestamp = (proposalVoteDeadline: string) =>
|
export const getClosingTimestamp = (
|
||||||
|
proposalVoteDeadline: string,
|
||||||
|
minimumDeadlineSelected: boolean
|
||||||
|
) =>
|
||||||
Math.floor(
|
Math.floor(
|
||||||
getTime(
|
getTime(
|
||||||
proposalVoteDeadline === '1'
|
minimumDeadlineSelected
|
||||||
? addHours(addMinutes(new Date(), 2), Number(proposalVoteDeadline))
|
? addHours(addMinutes(new Date(), 2), Number(proposalVoteDeadline))
|
||||||
: addHours(new Date(), Number(proposalVoteDeadline))
|
: addHours(new Date(), Number(proposalVoteDeadline))
|
||||||
) / 1000
|
) / 1000
|
||||||
|
@ -13,6 +13,7 @@ afterEach(() => {
|
|||||||
describe('getEnactmentTimestamp', () => {
|
describe('getEnactmentTimestamp', () => {
|
||||||
it('should return the correct timestamp', () => {
|
it('should return the correct timestamp', () => {
|
||||||
const proposalVoteDeadline = '2';
|
const proposalVoteDeadline = '2';
|
||||||
|
const isMinimumVoteDeadlineSelected = false;
|
||||||
const enactmentDeadline = '1';
|
const enactmentDeadline = '1';
|
||||||
const expected = Math.floor(
|
const expected = Math.floor(
|
||||||
getTime(
|
getTime(
|
||||||
@ -24,7 +25,8 @@ describe('getEnactmentTimestamp', () => {
|
|||||||
);
|
);
|
||||||
const actual = getEnactmentTimestamp(
|
const actual = getEnactmentTimestamp(
|
||||||
proposalVoteDeadline,
|
proposalVoteDeadline,
|
||||||
enactmentDeadline
|
enactmentDeadline,
|
||||||
|
isMinimumVoteDeadlineSelected
|
||||||
);
|
);
|
||||||
expect(actual).toEqual(expected);
|
expect(actual).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
@ -3,12 +3,20 @@ import { getClosingTimestamp } from './get-closing-timestamp';
|
|||||||
|
|
||||||
export const getEnactmentTimestamp = (
|
export const getEnactmentTimestamp = (
|
||||||
proposalVoteDeadline: string,
|
proposalVoteDeadline: string,
|
||||||
enactmentDeadline: string
|
enactmentDeadline: string,
|
||||||
|
minimumVoteDeadlineSelected: boolean
|
||||||
) =>
|
) =>
|
||||||
Math.floor(
|
Math.floor(
|
||||||
getTime(
|
getTime(
|
||||||
addHours(
|
addHours(
|
||||||
new Date(fromUnixTime(getClosingTimestamp(proposalVoteDeadline))),
|
new Date(
|
||||||
|
fromUnixTime(
|
||||||
|
getClosingTimestamp(
|
||||||
|
proposalVoteDeadline,
|
||||||
|
minimumVoteDeadlineSelected
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
Number(enactmentDeadline)
|
Number(enactmentDeadline)
|
||||||
)
|
)
|
||||||
) / 1000
|
) / 1000
|
||||||
|
@ -2,3 +2,4 @@ export * from './proposal-dialog-helpers';
|
|||||||
export * from './get-closing-timestamp';
|
export * from './get-closing-timestamp';
|
||||||
export * from './get-enactment-timestamp';
|
export * from './get-enactment-timestamp';
|
||||||
export * from './get-validation-timestamp';
|
export * from './get-validation-timestamp';
|
||||||
|
export * from './deadline-helpers';
|
||||||
|
Loading…
Reference in New Issue
Block a user