From 392eeea211f0576c50675d887ed716db6c72ab3d Mon Sep 17 00:00:00 2001 From: Kirill Klimenko Date: Mon, 8 Apr 2024 15:22:39 +0200 Subject: [PATCH] Eliminate CreateProposal and use ProposalBuilder instead --- .../ProposalBuilder/ProposalDetails.tsx | 33 ++-- .../ProposalBuilder/ProposalMetadata.tsx | 29 +++- .../ProposalBuilder/ProposalTransaction.tsx | 77 +++++---- .../ProposalBuilder/ProposalTransactions.tsx | 9 +- .../ProposalTransactionsForm.tsx | 3 +- src/components/ProposalBuilder/constants.ts | 2 +- src/components/ProposalBuilder/index.tsx | 26 +-- .../ProposalCreate/ProposalDetails.tsx | 70 -------- .../ProposalCreate/ProposalHeader.tsx | 47 ------ .../ProposalCreate/ProposalMetadata.tsx | 81 ---------- src/components/ProposalCreate/Transaction.tsx | 131 --------------- .../ProposalCreate/Transactions.tsx | 118 -------------- .../ProposalCreate/TransactionsForm.tsx | 97 ----------- src/components/ProposalCreate/constants.ts | 19 --- .../ui/modals/ProposalTemplateModal.tsx | 22 +-- .../loaders/governance/useAzoriusListeners.ts | 4 +- .../loaders/governance/useAzoriusProposals.ts | 6 +- src/hooks/DAO/proposal/useGetMetadata.ts | 20 ++- src/hooks/DAO/proposal/usePrepareProposal.ts | 16 +- src/hooks/DAO/proposal/useSubmitProposal.ts | 4 +- .../useCreateProposalSchema.ts} | 15 +- .../proposalCreate/useCreateProposalSchema.ts | 75 --------- src/i18n/locales/en/proposal.json | 2 +- .../proposal-templates/new/index.tsx | 4 +- .../daos/[daoAddress]/proposals/new/index.tsx | 152 +----------------- src/types/createProposal.ts | 27 ---- src/types/daoProposal.ts | 6 +- src/types/index.ts | 2 +- src/types/proposalBuilder.ts | 6 + 29 files changed, 178 insertions(+), 925 deletions(-) delete mode 100644 src/components/ProposalCreate/ProposalDetails.tsx delete mode 100644 src/components/ProposalCreate/ProposalHeader.tsx delete mode 100644 src/components/ProposalCreate/ProposalMetadata.tsx delete mode 100644 src/components/ProposalCreate/Transaction.tsx delete mode 100644 src/components/ProposalCreate/Transactions.tsx delete mode 100644 src/components/ProposalCreate/TransactionsForm.tsx delete mode 100644 src/components/ProposalCreate/constants.ts rename src/hooks/schemas/{createProposalTemplate/useCreateProposalTemplateSchema.ts => proposalBuilder/useCreateProposalSchema.ts} (83%) delete mode 100644 src/hooks/schemas/proposalCreate/useCreateProposalSchema.ts delete mode 100644 src/types/createProposal.ts diff --git a/src/components/ProposalBuilder/ProposalDetails.tsx b/src/components/ProposalBuilder/ProposalDetails.tsx index 4bb24d63d0..e7b917e2bd 100644 --- a/src/components/ProposalBuilder/ProposalDetails.tsx +++ b/src/components/ProposalBuilder/ProposalDetails.tsx @@ -3,7 +3,7 @@ import { FormikProps } from 'formik'; import { Fragment, PropsWithChildren } from 'react'; import { useTranslation } from 'react-i18next'; import { BACKGROUND_SEMI_TRANSPARENT } from '../../constants/common'; -import { CreateProposalForm } from '../../types/proposalBuilder'; +import { CreateProposalForm, ProposalBuilderMode } from '../../types/proposalBuilder'; import Markdown from '../ui/proposal/Markdown'; import '../../assets/css/Markdown.css'; @@ -30,7 +30,8 @@ export function TransactionValueContainer({ export default function ProposalTemplateDetails({ values: { proposalMetadata, transactions }, -}: FormikProps) { + mode, +}: FormikProps & { mode: ProposalBuilderMode }) { const { t } = useTranslation(['proposalTemplate', 'proposal']); const trimmedTitle = proposalMetadata.title?.trim(); @@ -51,19 +52,21 @@ export default function ProposalTemplateDetails({ {t('previewTitle')} {trimmedTitle} - - {t('previewThumnbail')} - {trimmedTitle && ( - title.slice(0, 2)} - /> - )} - + {mode === 'template' && ( + + {t('previewThumnbail')} + {trimmedTitle && ( + title.slice(0, 2)} + /> + )} + + )} {t('proposalTemplateDescription')} { setFormState: (state: CreateProposalState) => void; + mode: ProposalBuilderMode; } export default function ProposalMetadata({ @@ -14,8 +15,10 @@ export default function ProposalMetadata({ setFieldValue, errors: { proposalMetadata: proposalMetadataError }, setFormState, + mode, }: ProposalMetadataProps) { - const { t } = useTranslation(['proposalTemplate', 'common']); + const { t } = useTranslation(['proposalTemplate', 'proposal', 'common']); + const isProposalMode = mode === 'proposal'; return ( <> @@ -25,8 +28,14 @@ export default function ProposalMetadata({ mt={4} > setFieldValue('proposalMetadata.title', e.target.value)} @@ -35,9 +44,17 @@ export default function ProposalMetadata({ maxLength={50} /> setFieldValue('proposalMetadata.description', e.target.value)} diff --git a/src/components/ProposalBuilder/ProposalTransaction.tsx b/src/components/ProposalBuilder/ProposalTransaction.tsx index b9f83bede1..ad256b811b 100644 --- a/src/components/ProposalBuilder/ProposalTransaction.tsx +++ b/src/components/ProposalBuilder/ProposalTransaction.tsx @@ -2,7 +2,7 @@ import { VStack, HStack, Text, Box, Flex, IconButton } from '@chakra-ui/react'; import { AddPlus, Minus } from '@decent-org/fractal-ui'; import { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; -import { CreateProposalTransaction } from '../../types/proposalBuilder'; +import { CreateProposalTransaction, ProposalBuilderMode } from '../../types/proposalBuilder'; import ABISelector, { ABIElement } from '../ui/forms/ABISelector'; import ExampleLabel from '../ui/forms/ExampleLabel'; import { BigNumberComponent, InputComponent } from '../ui/forms/InputComponent'; @@ -15,6 +15,7 @@ interface ProposalTransactionProps { txAddressError?: string; txFunctionError?: string; setFieldValue: (field: string, value: any, shouldValidate?: boolean | undefined) => void; + mode: ProposalBuilderMode; } export default function ProposalTransaction({ @@ -24,7 +25,9 @@ export default function ProposalTransaction({ txAddressError, txFunctionError, setFieldValue, + mode, }: ProposalTransactionProps) { + const isProposalMode = mode === 'proposal'; const { t } = useTranslation(['proposal', 'proposalTemplate', 'common']); const handleABISelectorChange = useCallback( (value: ABIElement) => { @@ -170,34 +173,38 @@ export default function ProposalTransaction({ alignItems="center" mt={4} > - - setFieldValue( - `transactions.${transactionIndex}.parameters.${i}.label`, - e.target.value, - ) - } - disabled={transactionPending || !!parameter.value} - testId={`transactions.${transactionIndex}.parameters.${i}.label`} - subLabel={ - - {t('helperParameterLabel', { ns: 'proposalTemplate' })} - - } - gridContainerProps={{ - display: 'inline-flex', - flexWrap: 'wrap', - width: '30%', - }} - inputContainerProps={{ - width: '100%', - }} - /> - {t('or', { ns: 'common' })} + {!isProposalMode && ( + <> + + setFieldValue( + `transactions.${transactionIndex}.parameters.${i}.label`, + e.target.value, + ) + } + disabled={transactionPending || !!parameter.value} + testId={`transactions.${transactionIndex}.parameters.${i}.label`} + subLabel={ + + {t('helperParameterLabel', { ns: 'proposalTemplate' })} + + } + gridContainerProps={{ + display: 'inline-flex', + flexWrap: 'wrap', + width: '30%', + }} + inputContainerProps={{ + width: '100%', + }} + /> + {t('or', { ns: 'common' })} + + )} {t('example', { ns: 'common' })}: value - - {t('proposalTemplateLeaveBlank', { ns: 'proposalTemplate' })} - + {!isProposalMode && ( + + {t('proposalTemplateLeaveBlank', { ns: 'proposalTemplate' })} + + )} } @@ -282,7 +291,9 @@ export default function ProposalTransaction({ {`${t('example', { ns: 'common' })}:`} {'1.2'} - {t('ethParemeterHelper', { ns: 'proposalTemplate' })} + {!isProposalMode && ( + {t('ethParemeterHelper', { ns: 'proposalTemplate' })} + )} } errorMessage={undefined} diff --git a/src/components/ProposalBuilder/ProposalTransactions.tsx b/src/components/ProposalBuilder/ProposalTransactions.tsx index 1f114ec7b6..6191e73acd 100644 --- a/src/components/ProposalBuilder/ProposalTransactions.tsx +++ b/src/components/ProposalBuilder/ProposalTransactions.tsx @@ -12,13 +12,18 @@ import { FormikErrors, FormikProps } from 'formik'; import { Dispatch, SetStateAction } from 'react'; import { useTranslation } from 'react-i18next'; import { BigNumberValuePair } from '../../types'; -import { CreateProposalForm, CreateProposalTransaction } from '../../types/proposalBuilder'; +import { + CreateProposalForm, + CreateProposalTransaction, + ProposalBuilderMode, +} from '../../types/proposalBuilder'; import ProposalTransaction from './ProposalTransaction'; interface ProposalTransactionsProps extends FormikProps { pendingTransaction: boolean; expandedIndecies: number[]; setExpandedIndecies: Dispatch>; + mode: ProposalBuilderMode; } export default function ProposalTransactions({ values: { transactions }, @@ -27,6 +32,7 @@ export default function ProposalTransactions({ pendingTransaction, expandedIndecies, setExpandedIndecies, + mode, }: ProposalTransactionsProps) { const { t } = useTranslation(['proposal', 'proposalTemplate', 'common']); @@ -105,6 +111,7 @@ export default function ProposalTransactions({ transactionIndex={index} setFieldValue={setFieldValue} transactionPending={pendingTransaction} + mode={mode} /> diff --git a/src/components/ProposalBuilder/ProposalTransactionsForm.tsx b/src/components/ProposalBuilder/ProposalTransactionsForm.tsx index a79037f0b6..25e267eb00 100644 --- a/src/components/ProposalBuilder/ProposalTransactionsForm.tsx +++ b/src/components/ProposalBuilder/ProposalTransactionsForm.tsx @@ -4,7 +4,7 @@ import { FormikProps } from 'formik'; import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { CreateProposalState } from '../../types'; -import { CreateProposalForm } from '../../types/proposalBuilder'; +import { CreateProposalForm, ProposalBuilderMode } from '../../types/proposalBuilder'; import { scrollToBottom } from '../../utils/ui'; import ProposalTransactions from './ProposalTransactions'; import { DEFAULT_PROPOSAL_TRANSACTION } from './constants'; @@ -14,6 +14,7 @@ interface ProposalTransactionsFormProps extends FormikProps setFormState: (state: CreateProposalState) => void; canUserCreateProposal?: boolean; safeNonce?: number; + mode: ProposalBuilderMode; } export default function ProposalTransactionsForm(props: ProposalTransactionsFormProps) { diff --git a/src/components/ProposalBuilder/constants.ts b/src/components/ProposalBuilder/constants.ts index bd76faf013..8eb29adad4 100644 --- a/src/components/ProposalBuilder/constants.ts +++ b/src/components/ProposalBuilder/constants.ts @@ -13,7 +13,7 @@ export const DEFAULT_PROPOSAL_TRANSACTION: CreateProposalTransaction = { ], }; -export const DEFAULT_PROPOSAL_TEMPLATE = { +export const DEFAULT_PROPOSAL = { nonce: undefined, proposalMetadata: { title: '', diff --git a/src/components/ProposalBuilder/index.tsx b/src/components/ProposalBuilder/index.tsx index 354dd8fd91..93d3cbfe19 100644 --- a/src/components/ProposalBuilder/index.tsx +++ b/src/components/ProposalBuilder/index.tsx @@ -7,23 +7,22 @@ import { useNavigate } from 'react-router-dom'; import { BACKGROUND_SEMI_TRANSPARENT } from '../../constants/common'; import { DAO_ROUTES, BASE_ROUTES } from '../../constants/routes'; import useSubmitProposal from '../../hooks/DAO/proposal/useSubmitProposal'; -import useCreateProposalTemplateSchema from '../../hooks/schemas/createProposalTemplate/useCreateProposalTemplateSchema'; +import useCreateProposalSchema from '../../hooks/schemas/proposalBuilder/useCreateProposalSchema'; import { useCanUserCreateProposal } from '../../hooks/utils/useCanUserSubmitProposal'; import { useFractal } from '../../providers/App/AppProvider'; import { useNetworkConfig } from '../../providers/NetworkConfig/NetworkConfigProvider'; import { CreateProposalState, ProposalExecuteData } from '../../types'; -import { CreateProposalForm } from '../../types/proposalBuilder'; +import { CreateProposalForm, ProposalBuilderMode } from '../../types/proposalBuilder'; import { CustomNonceInput } from '../ui/forms/CustomNonceInput'; import PageHeader from '../ui/page/Header/PageHeader'; import ProposalDetails from './ProposalDetails'; import ProposalMetadata from './ProposalMetadata'; import ProposalTransactionsForm from './ProposalTransactionsForm'; -import { DEFAULT_PROPOSAL_TEMPLATE } from './constants'; interface IProposalBuilder { - mode: 'proposal' | 'template'; + mode: ProposalBuilderMode; prepareProposalData: (values: CreateProposalForm) => Promise; - initialValues: typeof DEFAULT_PROPOSAL_TEMPLATE; + initialValues: CreateProposalForm; } const templateAreaTwoCol = '"content details"'; @@ -47,7 +46,7 @@ export default function ProposalBuilder({ const { addressPrefix } = useNetworkConfig(); const { submitProposal, pendingCreateTx } = useSubmitProposal(); const { canUserCreateProposal } = useCanUserCreateProposal(); - const { createProposalTemplateValidation } = useCreateProposalTemplateSchema(); + const { createProposalValidation } = useCreateProposalSchema(); const successCallback = () => { if (daoAddress) { @@ -58,7 +57,7 @@ export default function ProposalBuilder({ return ( - validationSchema={createProposalTemplateValidation} + validationSchema={createProposalValidation} initialValues={initialValues} enableReinitialize onSubmit={async values => { @@ -88,7 +87,11 @@ export default function ProposalBuilder({
) : ( @@ -173,6 +177,7 @@ export default function ProposalBuilder({ canUserCreateProposal={canUserCreateProposal} pendingTransaction={pendingCreateTx} safeNonce={safe?.nonce} + mode={mode} {...formikProps} /> @@ -184,7 +189,10 @@ export default function ProposalBuilder({ area="details" w="100%" > - + diff --git a/src/components/ProposalCreate/ProposalDetails.tsx b/src/components/ProposalCreate/ProposalDetails.tsx deleted file mode 100644 index 2592d2f3de..0000000000 --- a/src/components/ProposalCreate/ProposalDetails.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import { Box, Divider, Flex, HStack, Text } from '@chakra-ui/react'; -import { useTranslation } from 'react-i18next'; -import { BACKGROUND_SEMI_TRANSPARENT } from '../../constants/common'; -import { useFractal } from '../../providers/App/AppProvider'; -import { AzoriusGovernance, GovernanceType } from '../../types'; -import ContentBoxTitle from '../ui/containers/ContentBox/ContentBoxTitle'; -import { BarLoader } from '../ui/loaders/BarLoader'; - -export function ProposalDetails() { - const { - node: { daoAddress, safe }, - governance, - } = useFractal(); - const { type } = governance; - const azoriusGovernance = governance as AzoriusGovernance; - const { t } = useTranslation(['proposal']); - return ( - - {!type || !daoAddress || !safe ? ( - - - - ) : ( - - {t('proposalSummaryTitle')} - - {type === GovernanceType.MULTISIG ? ( - - {t('labelProposalSigners')} - - {safe.threshold}/{safe.owners?.length} - - - ) : ( - <> - - {t('labelProposalVotingPeriod')} - {azoriusGovernance.votingStrategy?.votingPeriod?.formatted} - - - {t('labelProposalQuorum')} - - {azoriusGovernance.votingStrategy?.quorumPercentage?.formatted || - azoriusGovernance.votingStrategy?.quorumThreshold?.formatted} - - - - {t('labelProposalTimelock')} - {azoriusGovernance.votingStrategy?.timeLockPeriod?.formatted} - - - )} - - )} - - ); -} diff --git a/src/components/ProposalCreate/ProposalHeader.tsx b/src/components/ProposalCreate/ProposalHeader.tsx deleted file mode 100644 index 38983b7773..0000000000 --- a/src/components/ProposalCreate/ProposalHeader.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { HStack, Spacer, Text, Tooltip } from '@chakra-ui/react'; -import { Alert } from '@decent-org/fractal-ui'; -import { useTranslation } from 'react-i18next'; -import { TOOLTIP_MAXW } from '../../constants/common'; -import { CustomNonceInput } from '../ui/forms/CustomNonceInput'; - -export function ProposalHeader({ - isAzorius, - metadataTitle, - nonce, - setNonce, -}: { - isAzorius?: boolean; - metadataTitle?: string; - nonce?: number; - setNonce: (nonce?: number) => void; -}) { - const { t } = useTranslation('proposal'); - - return ( - - - {metadataTitle ? metadataTitle : t('proposal', { ns: 'proposal' })} - - {!isAzorius && ( - - - - )} - - {!isAzorius && ( - - )} - - ); -} diff --git a/src/components/ProposalCreate/ProposalMetadata.tsx b/src/components/ProposalCreate/ProposalMetadata.tsx deleted file mode 100644 index a25642fc5c..0000000000 --- a/src/components/ProposalCreate/ProposalMetadata.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import { Button, Divider, VStack } from '@chakra-ui/react'; -import { FormikProps } from 'formik'; -import { useTranslation } from 'react-i18next'; -import { CreateProposalForm, CreateProposalState } from '../../types'; -import { InputComponent, TextareaComponent } from '../ui/forms/InputComponent'; - -export interface AzoriusMetadataProps extends FormikProps { - isVisible: boolean; - setFormState: (state: CreateProposalState) => void; -} - -function ProposalMetadata(props: AzoriusMetadataProps) { - const { - values: { proposalMetadata }, - setFieldValue, - errors: { proposalMetadata: proposalMetadataError }, - isVisible, - setFormState, - } = props; - const { t } = useTranslation(['proposal', 'common']); - - if (!isVisible) return null; - - return ( - <> - - setFieldValue('proposalMetadata.title', e.target.value)} - disabled={false} - placeholder={t('proposalTitlePlaceholder')} - testId="metadata.title" - /> - setFieldValue('proposalMetadata.description', e.target.value)} - disabled={false} - placeholder={t('proposalDescriptionPlaceholder')} - rows={9} - /> - setFieldValue('proposalMetadata.documentationUrl', e.target.value)} - value={proposalMetadata.documentationUrl} - disabled={false} - placeholder={t('proposalAdditionalResourcesPlaceholder')} - errorMessage={ - proposalMetadata.documentationUrl && proposalMetadataError?.documentationUrl - } - testId="metadata.documentationUrl" - /> - - - - - ); -} - -export default ProposalMetadata; diff --git a/src/components/ProposalCreate/Transaction.tsx b/src/components/ProposalCreate/Transaction.tsx deleted file mode 100644 index 481328f087..0000000000 --- a/src/components/ProposalCreate/Transaction.tsx +++ /dev/null @@ -1,131 +0,0 @@ -import { VStack, HStack, Text } from '@chakra-ui/react'; -import { useTranslation } from 'react-i18next'; -import { CreateProposalTransaction } from '../../types/createProposal'; -import ExampleLabel from '../ui/forms/ExampleLabel'; -import { BigNumberComponent, InputComponent } from '../ui/forms/InputComponent'; - -interface TransactionProps { - transaction: CreateProposalTransaction; - transactionIndex: number; - transactionPending: boolean; - txAddressError?: string; - txFunctionError?: string; - setFieldValue: (field: string, value: any, shouldValidate?: boolean | undefined) => void; -} - -function Transaction({ - transaction, - transactionIndex, - transactionPending, - txAddressError, - txFunctionError, - setFieldValue, -}: TransactionProps) { - const { t } = useTranslation(['proposal', 'common']); - - return ( - - - {`${t('example', { ns: 'common' })}:`} - 0x4168592... - - } - errorMessage={transaction.targetAddress && txAddressError ? txAddressError : undefined} - value={transaction.targetAddress} - testId="transaction.targetAddress" - onChange={e => - setFieldValue(`transactions.${transactionIndex}.targetAddress`, e.target.value) - } - /> - - - setFieldValue(`transactions.${transactionIndex}.functionName`, e.target.value) - } - disabled={transactionPending} - subLabel={ - - {`${t('example', { ns: 'common' })}:`} - transfer - - } - // @todo update withn new error messages - errorMessage={undefined} - testId="transaction.functionName" - /> - - setFieldValue(`transactions.${transactionIndex}.functionSignature`, e.target.value) - } - disabled={transactionPending} - subLabel={ - - {`${t('example', { ns: 'common' })}:`} - address, uint256 - - } - testId="transaction.functionSignature" - errorMessage={ - transaction.functionSignature && txFunctionError ? txFunctionError : undefined - } - /> - setFieldValue(`transactions.${transactionIndex}.parameters`, e.target.value)} - disabled={transactionPending} - subLabel={ - - {`${t('example', { ns: 'common' })}:`} - - {'0xADC74eE329a23060d3CB431Be0AB313740c191E7, 1000000000'} - - - } - testId="transaction.parameters" - errorMessage={transaction.parameters && txFunctionError ? txFunctionError : undefined} - /> - - - {`${t('example', { ns: 'common' })}:`} - {'1.2'} - - } - errorMessage={undefined} - value={transaction.ethValue.bigNumberValue} - onChange={e => { - setFieldValue(`transactions.${transactionIndex}.ethValue`, e); - }} - decimalPlaces={18} - /> - - ); -} - -export default Transaction; diff --git a/src/components/ProposalCreate/Transactions.tsx b/src/components/ProposalCreate/Transactions.tsx deleted file mode 100644 index 29207f54e5..0000000000 --- a/src/components/ProposalCreate/Transactions.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import { - Box, - Accordion, - AccordionButton, - AccordionItem, - AccordionPanel, - HStack, - IconButton, -} from '@chakra-ui/react'; -import { ArrowDown, ArrowRight, Minus } from '@decent-org/fractal-ui'; -import { FormikErrors, FormikProps } from 'formik'; -import { Dispatch, SetStateAction } from 'react'; -import { useTranslation } from 'react-i18next'; -import { BigNumberValuePair, CreateProposalForm, CreateProposalTransaction } from '../../types'; -import Transaction from './Transaction'; - -interface TransactionsProps extends FormikProps { - isVisible: boolean; - pendingTransaction: boolean; - expandedIndecies: number[]; - setExpandedIndecies: Dispatch>; -} -function Transactions({ - values: { transactions }, - errors, - setFieldValue, - pendingTransaction, - expandedIndecies, - setExpandedIndecies, -}: TransactionsProps) { - const { t } = useTranslation(['proposal', 'common']); - - const removeTransaction = (transactionIndex: number) => { - const transactionsArr = [...transactions]; - transactionsArr.splice(transactionIndex, 1); - setFieldValue('transactions', transactionsArr); - }; - return ( - - {transactions.map((_, index) => { - const txErrors = errors?.transactions?.[index] as - | FormikErrors> - | undefined; - const txAddressError = txErrors?.targetAddress; - const txFunctionError = txErrors?.encodedFunctionData; - - return ( - - {({ isExpanded }) => ( - - - { - setExpandedIndecies(indexArray => { - if (indexArray.includes(index)) { - const newTxArr = [...indexArray]; - newTxArr.splice(newTxArr.indexOf(index), 1); - return newTxArr; - } else { - return [...indexArray, index]; - } - }); - }} - p={0} - textStyle="text-button-md-semibold" - color="grayscale.100" - > - {isExpanded ? : } - {t('transaction')} {index + 1} - - {index !== 0 || transactions.length !== 1 ? ( - } - aria-label={t('removetransactionlabel')} - variant="unstyled" - onClick={() => removeTransaction(index)} - minWidth="auto" - _hover={{ color: 'gold.500' }} - _disabled={{ opacity: 0.4, cursor: 'default' }} - sx={{ '&:disabled:hover': { color: 'inherit', opacity: 0.4 } }} - isDisabled={pendingTransaction} - /> - ) : ( - - )} - - - - - - )} - - ); - })} - - ); -} - -export default Transactions; diff --git a/src/components/ProposalCreate/TransactionsForm.tsx b/src/components/ProposalCreate/TransactionsForm.tsx deleted file mode 100644 index 43d83bd404..0000000000 --- a/src/components/ProposalCreate/TransactionsForm.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import { Button, Box, Flex, Text, VStack, Divider, Alert, AlertTitle } from '@chakra-ui/react'; -import { Info } from '@decent-org/fractal-ui'; -import { FormikProps } from 'formik'; -import { useState } from 'react'; -import { useTranslation } from 'react-i18next'; -import { CreateProposalForm, CreateProposalState } from '../../types'; -import { scrollToBottom } from '../../utils/ui'; -import Transactions from './Transactions'; -import { DEFAULT_TRANSACTION } from './constants'; - -interface TransactionsFormProps extends FormikProps { - isVisible: boolean; - pendingTransaction: boolean; - setFormState: (state: CreateProposalState) => void; - canUserCreateProposal?: boolean; -} - -function TransactionsForm(props: TransactionsFormProps) { - const { - isVisible, - pendingTransaction, - setFormState, - setFieldValue, - values: { transactions }, - errors: { transactions: transactionsError }, - canUserCreateProposal, - } = props; - const { t } = useTranslation(['proposal', 'common']); - const [expandedIndecies, setExpandedIndecies] = useState([0]); - - if (!isVisible) return null; - - return ( - - - - - - - - - {t('transactionExecutionAlertMessage')} - - - - - - - - - - - ); -} - -export default TransactionsForm; diff --git a/src/components/ProposalCreate/constants.ts b/src/components/ProposalCreate/constants.ts deleted file mode 100644 index 6c8c3a7486..0000000000 --- a/src/components/ProposalCreate/constants.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { BigNumber } from 'ethers'; -export const DEFAULT_TRANSACTION = { - targetAddress: '', - ethValue: { value: '0', bigNumberValue: BigNumber.from('0') }, - functionName: '', - functionSignature: '', - parameters: '', - encodedFunctionData: undefined, -}; - -export const DEFAULT_PROPOSAL = { - proposalMetadata: { - title: '', - description: '', - documentationUrl: '', - }, - transactions: [DEFAULT_TRANSACTION], - nonce: 0, -}; diff --git a/src/components/ui/modals/ProposalTemplateModal.tsx b/src/components/ui/modals/ProposalTemplateModal.tsx index d9250b6941..a96b227aa5 100644 --- a/src/components/ui/modals/ProposalTemplateModal.tsx +++ b/src/components/ui/modals/ProposalTemplateModal.tsx @@ -8,7 +8,7 @@ import { Switch, VStack, } from '@chakra-ui/react'; -import { utils, BigNumber } from 'ethers'; +import { BigNumber } from 'ethers'; import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; @@ -21,7 +21,6 @@ import { useFractal } from '../../../providers/App/AppProvider'; import { useNetworkConfig } from '../../../providers/NetworkConfig/NetworkConfigProvider'; import { BigNumberValuePair } from '../../../types'; import { ProposalTemplate } from '../../../types/proposalBuilder'; -import { isValidUrl } from '../../../utils/url'; import { CustomNonceInput } from '../forms/CustomNonceInput'; import { BigNumberComponent, InputComponent } from '../forms/InputComponent'; import Markdown from '../proposal/Markdown'; @@ -115,27 +114,10 @@ export default function ProposalTemplateModal({ documentationUrl: '', }; - const proposalTransactions = filledProposalTransactions.map( - ({ targetAddress, ethValue, functionName, parameters }) => { - return { - targetAddress: utils.getAddress(targetAddress), // Safe proposal creation/execution might fail if targetAddress is not checksummed - ethValue, - functionName, - functionSignature: parameters.map(parameter => parameter.signature.trim()).join(', '), - parameters: parameters - .map(parameter => - isValidUrl(parameter.value!.trim()) - ? encodeURIComponent(parameter.value!.trim()) // If parameter.value is valid URL with special symbols like ":" or "?" - decoding might fail, thus we need to encode URL - : parameter.value!.trim(), - ) - .join(', '), - }; - }, - ); try { const proposalData = await prepareProposal({ proposalMetadata, - transactions: proposalTransactions, + transactions: filledProposalTransactions, }); submitProposal({ diff --git a/src/hooks/DAO/loaders/governance/useAzoriusListeners.ts b/src/hooks/DAO/loaders/governance/useAzoriusListeners.ts index 291a938e46..8784feeeda 100644 --- a/src/hooks/DAO/loaders/governance/useAzoriusListeners.ts +++ b/src/hooks/DAO/loaders/governance/useAzoriusListeners.ts @@ -13,7 +13,7 @@ import { useFractal } from '../../../../providers/App/AppProvider'; import { FractalGovernanceAction } from '../../../../providers/App/governance/action'; import { useEthersProvider } from '../../../../providers/Ethers/hooks/useEthersProvider'; import { - ProposalMetadata, + CreateProposalMetadata, VotingStrategyType, DecodedTransaction, FractalActions, @@ -49,7 +49,7 @@ const proposalCreatedEventListener = ( return; } - const metaDataEvent: ProposalMetadata = JSON.parse(metadata); + const metaDataEvent: CreateProposalMetadata = JSON.parse(metadata); const proposalData = { metaData: { title: metaDataEvent.title, diff --git a/src/hooks/DAO/loaders/governance/useAzoriusProposals.ts b/src/hooks/DAO/loaders/governance/useAzoriusProposals.ts index 1e8b61d0f5..3988776699 100644 --- a/src/hooks/DAO/loaders/governance/useAzoriusProposals.ts +++ b/src/hooks/DAO/loaders/governance/useAzoriusProposals.ts @@ -8,7 +8,7 @@ import { VotedEvent as ERC721VotedEvent } from '@fractal-framework/fractal-contr import { useCallback, useEffect, useMemo, useRef } from 'react'; import { useFractal } from '../../../../providers/App/AppProvider'; import { useEthersProvider } from '../../../../providers/Ethers/hooks/useEthersProvider'; -import { ProposalMetadata, VotingStrategyType, DecodedTransaction } from '../../../../types'; +import { CreateProposalMetadata, VotingStrategyType, DecodedTransaction } from '../../../../types'; import { AzoriusProposal } from '../../../../types/daoProposal'; import { Providers } from '../../../../types/network'; import { mapProposalCreatedEventToProposal, decodeTransactions } from '../../../../utils'; @@ -140,7 +140,9 @@ export const useAzoriusProposals = () => { for (const proposalCreatedEvent of proposalCreatedEvents) { let proposalData; if (proposalCreatedEvent.args.metadata) { - const metadataEvent: ProposalMetadata = JSON.parse(proposalCreatedEvent.args.metadata); + const metadataEvent: CreateProposalMetadata = JSON.parse( + proposalCreatedEvent.args.metadata, + ); const decodedTransactions = await decodeTransactions( _decode, proposalCreatedEvent.args.transactions, diff --git a/src/hooks/DAO/proposal/useGetMetadata.ts b/src/hooks/DAO/proposal/useGetMetadata.ts index edcc6975c9..6a80aeee06 100644 --- a/src/hooks/DAO/proposal/useGetMetadata.ts +++ b/src/hooks/DAO/proposal/useGetMetadata.ts @@ -2,7 +2,11 @@ import { utils } from 'ethers'; import { useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import useIPFSClient from '../../../providers/App/hooks/useIPFSClient'; -import { FractalProposal, ProposalMetadata, SafeMultisigTransactionResponse } from '../../../types'; +import { + FractalProposal, + CreateProposalMetadata, + SafeMultisigTransactionResponse, +} from '../../../types'; import { CacheKeys } from '../../utils/cache/cacheDefaults'; import { DBObjectKeys, useIndexedDB } from '../../utils/cache/useLocalDB'; @@ -20,15 +24,15 @@ interface Transaction { const useGetMultisigMetadata = (proposal: FractalProposal | null | undefined) => { const ipfsClient = useIPFSClient(); - const [multisigMetadata, setMultisigMetadata] = useState( - undefined, - ); + const [multisigMetadata, setMultisigMetadata] = useState< + undefined | CreateProposalMetadata | null + >(undefined); const [setValue, getValue] = useIndexedDB(DBObjectKeys.DECODED_TRANSACTIONS); const fetchMultisigMetadata = useCallback(async () => { if (!proposal) return; - const cached: ProposalMetadata = await getValue( + const cached: CreateProposalMetadata = await getValue( CacheKeys.MULTISIG_METADATA_PREFIX + proposal.proposalId, ); if (cached) { @@ -59,7 +63,7 @@ const useGetMultisigMetadata = (proposal: FractalProposal | null | undefined) => try { const decoded = new utils.AbiCoder().decode(['string'], encodedMetadata); const ipfsHash = (decoded as string[])[0]; - const meta: ProposalMetadata = await ipfsClient.cat(ipfsHash); + const meta: CreateProposalMetadata = await ipfsClient.cat(ipfsHash); // cache the metadata JSON await setValue(CacheKeys.MULTISIG_METADATA_PREFIX + proposal.proposalId, meta); @@ -78,7 +82,9 @@ const useGetMultisigMetadata = (proposal: FractalProposal | null | undefined) => return { multisigMetadata }; }; -export const useGetMetadata = (proposal: FractalProposal | null | undefined): ProposalMetadata => { +export const useGetMetadata = ( + proposal: FractalProposal | null | undefined, +): CreateProposalMetadata => { const { multisigMetadata } = useGetMultisigMetadata(proposal); const { t } = useTranslation('dashboard'); diff --git a/src/hooks/DAO/proposal/usePrepareProposal.ts b/src/hooks/DAO/proposal/usePrepareProposal.ts index c9914cd0b3..e81a71463c 100644 --- a/src/hooks/DAO/proposal/usePrepareProposal.ts +++ b/src/hooks/DAO/proposal/usePrepareProposal.ts @@ -1,8 +1,8 @@ import { useCallback } from 'react'; import { useEthersSigner } from '../../../providers/Ethers/hooks/useEthersSigner'; -import { CreateProposalForm } from '../../../types'; +import { CreateProposalForm } from '../../../types/proposalBuilder'; import { encodeFunction } from '../../../utils/crypto'; -import { couldBeENS } from '../../../utils/url'; +import { couldBeENS, isValidUrl } from '../../../utils/url'; export function usePrepareProposal() { const signer = useEthersSigner(); @@ -12,7 +12,17 @@ export function usePrepareProposal() { const transactionsWithEncoding = transactions.map(tx => { return { ...tx, - encodedFunctionData: encodeFunction(tx.functionName, tx.functionSignature, tx.parameters), + encodedFunctionData: encodeFunction( + tx.functionName, + tx.parameters.map(parameter => parameter.signature.trim()).join(', '), + tx.parameters + .map(parameter => + isValidUrl(parameter.value!.trim()) + ? encodeURIComponent(parameter.value!.trim()) // If parameter.value is valid URL with special symbols like ":" or "?" - decoding might fail, thus we need to encode URL + : parameter.value!.trim(), + ) + .join(', '), + ), }; }); const targets = await Promise.all( diff --git a/src/hooks/DAO/proposal/useSubmitProposal.ts b/src/hooks/DAO/proposal/useSubmitProposal.ts index e4fa5a562e..fe24c2151c 100644 --- a/src/hooks/DAO/proposal/useSubmitProposal.ts +++ b/src/hooks/DAO/proposal/useSubmitProposal.ts @@ -15,7 +15,7 @@ import { useSafeAPI } from '../../../providers/App/hooks/useSafeAPI'; import { useEthersProvider } from '../../../providers/Ethers/hooks/useEthersProvider'; import { useEthersSigner } from '../../../providers/Ethers/hooks/useEthersSigner'; import { useNetworkConfig } from '../../../providers/NetworkConfig/NetworkConfigProvider'; -import { MetaTransaction, ProposalExecuteData, ProposalMetadata } from '../../../types'; +import { MetaTransaction, ProposalExecuteData, CreateProposalMetadata } from '../../../types'; import { buildSafeApiUrl, getAzoriusModuleFromModules } from '../../../utils'; import useSafeContracts from '../../safe/useSafeContracts'; import useSignerOrProvider from '../../utils/useSignerOrProvider'; @@ -116,7 +116,7 @@ export default function useSubmitProposal() { proposalData.metaData.description || proposalData.metaData.documentationUrl ) { - const metaData: ProposalMetadata = { + const metaData: CreateProposalMetadata = { title: proposalData.metaData.title || '', description: proposalData.metaData.description || '', documentationUrl: proposalData.metaData.documentationUrl || '', diff --git a/src/hooks/schemas/createProposalTemplate/useCreateProposalTemplateSchema.ts b/src/hooks/schemas/proposalBuilder/useCreateProposalSchema.ts similarity index 83% rename from src/hooks/schemas/createProposalTemplate/useCreateProposalTemplateSchema.ts rename to src/hooks/schemas/proposalBuilder/useCreateProposalSchema.ts index 9da83d62af..cb7b9a92ae 100644 --- a/src/hooks/schemas/createProposalTemplate/useCreateProposalTemplateSchema.ts +++ b/src/hooks/schemas/proposalBuilder/useCreateProposalSchema.ts @@ -5,10 +5,10 @@ import { useFractal } from '../../../providers/App/AppProvider'; import { useValidationAddress } from '../common/useValidationAddress'; /** - * validation schema for Create Proposal Template workflow + * validation schema for Create Proposal workflow * @dev https://www.npmjs.com/package/yup */ -const useCreateProposalTemplateSchema = () => { +const useCreateProposalSchema = () => { const { t } = useTranslation('proposal'); const { addressValidationTest } = useValidationAddress(); const { @@ -30,7 +30,7 @@ const useCreateProposalTemplateSchema = () => { return false; }; - const createProposalTemplateValidation = useMemo( + const createProposalValidation = useMemo( () => Yup.object().shape({ transactions: Yup.array() @@ -59,9 +59,10 @@ const useCreateProposalTemplateSchema = () => { ), }), ), - proposalTemplateMetadata: Yup.object().shape({ + proposalMetadata: Yup.object().shape({ title: Yup.string().trim().required().max(50), - description: Yup.string().trim().notRequired().max(300), + description: Yup.string().trim().notRequired(), + documentationUrl: Yup.string().trim().notRequired(), }), nonce: Yup.number() .required() @@ -69,7 +70,7 @@ const useCreateProposalTemplateSchema = () => { }), [addressValidationTest, t, safe], ); - return { createProposalTemplateValidation }; + return { createProposalValidation }; }; -export default useCreateProposalTemplateSchema; +export default useCreateProposalSchema; diff --git a/src/hooks/schemas/proposalCreate/useCreateProposalSchema.ts b/src/hooks/schemas/proposalCreate/useCreateProposalSchema.ts deleted file mode 100644 index 7389278cd8..0000000000 --- a/src/hooks/schemas/proposalCreate/useCreateProposalSchema.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { useMemo } from 'react'; -import { useTranslation } from 'react-i18next'; -import * as Yup from 'yup'; -import { encodeFunction } from '../../../utils/crypto'; -import { useValidationAddress } from '../common/useValidationAddress'; - -/** - * validation schema for Create Proposal workflow - * @dev https://www.npmjs.com/package/yup - */ -export const useCreateProposalSchema = () => { - const { addressValidationTest } = useValidationAddress(); - - const { t } = useTranslation('proposal'); - - const createProposalValidation = useMemo( - () => - Yup.object().shape({ - transactions: Yup.array() - .min(1) - .of( - Yup.object().shape({ - targetAddress: Yup.string().required().test(addressValidationTest), - ethValue: Yup.object().shape({ - value: Yup.string(), - }), - functionName: Yup.string().matches(/^[a-z0-9]+$/i, { - message: t('functionNameError'), - }), - functionSignature: Yup.string(), - parameters: Yup.string(), - encodedFunctionData: Yup.string().test({ - message: t('errorInvalidFragments'), - test: (_, context) => { - const functionName = context.parent.functionName; - const functionSignature = context.parent.functionSignature; - const parameters = context.parent.parameters; - if (!functionName) return false; - const encodedFunction = encodeFunction( - functionName, - functionSignature, - parameters, - ); - - return !!encodedFunction; - }, - }), - }), - ), - proposalMetadata: Yup.object().shape({ - title: Yup.string().notRequired(), - description: Yup.string().notRequired(), - documentationUrl: Yup.string() - .notRequired() - .when({ - is: (value?: string) => !!value, - then: schema => - schema.test({ - message: t('Invalid URL'), - test: value => { - try { - return Boolean(new URL(value || '')); - } catch (e) { - return false; - } - }, - }), - }), - }), - nonce: Yup.number(), - }), - [addressValidationTest, t], - ); - return { createProposalValidation }; -}; diff --git a/src/i18n/locales/en/proposal.json b/src/i18n/locales/en/proposal.json index 2f8da0fd37..c01bebca56 100644 --- a/src/i18n/locales/en/proposal.json +++ b/src/i18n/locales/en/proposal.json @@ -2,7 +2,7 @@ "proposalOverview": "Proposal Overview", "breakdownTitle": "Breakdown", "labelTargetAddress": "Target Address", - "helperTargetAddress": "The smart contract address this proposal will modify", + "helperTargetAddress": "The smart contract address this proposal will modify. Paste address and we'll try to fetch ABI for this contract from Etherscan", "labelFunctionName": "Function Name", "helperFunctionName": "The name of the function to be called if this proposal passes", "labelFunctionSignature": "Function Signature", diff --git a/src/pages/daos/[daoAddress]/proposal-templates/new/index.tsx b/src/pages/daos/[daoAddress]/proposal-templates/new/index.tsx index a5366c743b..4ccb364cc3 100644 --- a/src/pages/daos/[daoAddress]/proposal-templates/new/index.tsx +++ b/src/pages/daos/[daoAddress]/proposal-templates/new/index.tsx @@ -2,7 +2,7 @@ import { BigNumber } from 'ethers'; import { useEffect, useState, useMemo } from 'react'; import { useSearchParams } from 'react-router-dom'; import ProposalBuilder from '../../../../../components/ProposalBuilder'; -import { DEFAULT_PROPOSAL_TEMPLATE } from '../../../../../components/ProposalBuilder/constants'; +import { DEFAULT_PROPOSAL } from '../../../../../components/ProposalBuilder/constants'; import { logError } from '../../../../../helpers/errorLogging'; import useCreateProposalTemplate from '../../../../../hooks/DAO/proposal/useCreateProposalTemplate'; import useIPFSClient from '../../../../../providers/App/hooks/useIPFSClient'; @@ -10,7 +10,7 @@ import { ProposalTemplate } from '../../../../../types/proposalBuilder'; export default function CreateProposalTemplatePage() { const ipfsClient = useIPFSClient(); - const [initialProposalTemplate, setInitialProposalTemplate] = useState(DEFAULT_PROPOSAL_TEMPLATE); + const [initialProposalTemplate, setInitialProposalTemplate] = useState(DEFAULT_PROPOSAL); const { prepareProposalTemplateProposal } = useCreateProposalTemplate(); const [searchParams] = useSearchParams(); const defaultProposalTemplatesHash = useMemo( diff --git a/src/pages/daos/[daoAddress]/proposals/new/index.tsx b/src/pages/daos/[daoAddress]/proposals/new/index.tsx index bd0954259a..7a33cb0a6d 100644 --- a/src/pages/daos/[daoAddress]/proposals/new/index.tsx +++ b/src/pages/daos/[daoAddress]/proposals/new/index.tsx @@ -1,55 +1,17 @@ -import { Grid, GridItem, Box, Flex, Center } from '@chakra-ui/react'; -import { Trash } from '@decent-org/fractal-ui'; -import { Formik, FormikProps } from 'formik'; -import { useState, useMemo } from 'react'; -import { useTranslation } from 'react-i18next'; -import { useNavigate } from 'react-router-dom'; -import { ProposalDetails } from '../../../../../components/ProposalCreate/ProposalDetails'; -import { ProposalHeader } from '../../../../../components/ProposalCreate/ProposalHeader'; -import ProposalMetadata from '../../../../../components/ProposalCreate/ProposalMetadata'; -import TransactionsForm from '../../../../../components/ProposalCreate/TransactionsForm'; -import { DEFAULT_PROPOSAL } from '../../../../../components/ProposalCreate/constants'; +import { Center } from '@chakra-ui/react'; +import ProposalBuilder from '../../../../../components/ProposalBuilder'; +import { DEFAULT_PROPOSAL } from '../../../../../components/ProposalBuilder/constants'; import { BarLoader } from '../../../../../components/ui/loaders/BarLoader'; -import PageHeader from '../../../../../components/ui/page/Header/PageHeader'; -import { BACKGROUND_SEMI_TRANSPARENT, HEADER_HEIGHT } from '../../../../../constants/common'; -import { DAO_ROUTES } from '../../../../../constants/routes'; +import { HEADER_HEIGHT } from '../../../../../constants/common'; import { usePrepareProposal } from '../../../../../hooks/DAO/proposal/usePrepareProposal'; -import useSubmitProposal from '../../../../../hooks/DAO/proposal/useSubmitProposal'; -import { useCreateProposalSchema } from '../../../../../hooks/schemas/proposalCreate/useCreateProposalSchema'; -import { useCanUserCreateProposal } from '../../../../../hooks/utils/useCanUserSubmitProposal'; import { useFractal } from '../../../../../providers/App/AppProvider'; -import { useNetworkConfig } from '../../../../../providers/NetworkConfig/NetworkConfigProvider'; -import { CreateProposalForm, CreateProposalState, GovernanceType } from '../../../../../types'; - -const templateAreaTwoCol = '"content details"'; -const templateAreaSingleCol = `"content" - "details"`; export default function ProposalCreatePage() { const { node: { daoAddress, safe }, governance: { type }, } = useFractal(); - const { addressPrefix } = useNetworkConfig(); - const { createProposalValidation } = useCreateProposalSchema(); const { prepareProposal } = usePrepareProposal(); - const { submitProposal, pendingCreateTx } = useSubmitProposal(); - const { canUserCreateProposal } = useCanUserCreateProposal(); - - const navigate = useNavigate(); - const { t } = useTranslation(['proposal', 'common', 'breadcrumbs']); - - const [formState, setFormState] = useState(CreateProposalState.METADATA_FORM); - const isAzorius = useMemo( - () => type === GovernanceType.AZORIUS_ERC20 || type === GovernanceType.AZORIUS_ERC721, - [type], - ); - - const successCallback = () => { - if (daoAddress) { - navigate(DAO_ROUTES.proposals.relative(addressPrefix, daoAddress)); - } - }; if (!type || !daoAddress || !safe) { return ( @@ -60,108 +22,10 @@ export default function ProposalCreatePage() { } return ( - - validationSchema={createProposalValidation} + { - const { nonce } = values; - const proposalData = await prepareProposal(values); - submitProposal({ - proposalData, - nonce, - pendingToastMessage: t('proposalCreatePendingToastMessage'), - successToastMessage: t('proposalCreateSuccessToastMessage'), - failedToastMessage: t('proposalCreateFailureToastMessage'), - successCallback, - }); - }} - validateOnMount - isInitialValid={false} - > - {(formikProps: FormikProps) => { - const { handleSubmit, setFieldValue, values } = formikProps; - return ( - - - - navigate(DAO_ROUTES.proposals.relative(addressPrefix, daoAddress)) - } - isButtonDisabled={pendingCreateTx} - /> - - - - - { - setFieldValue('nonce', nonce); - }} - /> - - - - - - - - - - - - - ); - }} - + mode="proposal" + prepareProposalData={prepareProposal} + /> ); } diff --git a/src/types/createProposal.ts b/src/types/createProposal.ts deleted file mode 100644 index dbb8522d44..0000000000 --- a/src/types/createProposal.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { BigNumberValuePair } from './common'; - -export enum CreateProposalState { - METADATA_FORM, - TRANSACTIONS_FORM, -} - -export interface CreateProposalTransaction { - targetAddress: string; - ethValue: T; - functionName: string; - functionSignature: string; - parameters: string; - encodedFunctionData?: string; -} - -export type ProposalMetadata = { - title: string; - description: string; - documentationUrl: string; -}; - -export type CreateProposalForm = { - transactions: CreateProposalTransaction[]; - proposalMetadata: ProposalMetadata; - nonce?: number; -}; diff --git a/src/types/daoProposal.ts b/src/types/daoProposal.ts index 3783e86e4f..9e4f57de49 100644 --- a/src/types/daoProposal.ts +++ b/src/types/daoProposal.ts @@ -1,11 +1,11 @@ import { BigNumber, BigNumberish } from 'ethers'; -import { ProposalMetadata } from './createProposal'; import { GovernanceActivity } from './fractal'; +import { CreateProposalMetadata } from './proposalBuilder'; import { SafeMultisigConfirmationResponse } from './safeGlobal'; import { MetaTransaction, DecodedTransaction } from './transaction'; export interface ProposalExecuteData extends ExecuteData { - metaData: ProposalMetadata; + metaData: CreateProposalMetadata; } export interface ExecuteData { @@ -20,7 +20,7 @@ export type CreateProposalFunc = (proposal: { }) => void; export type ProposalData = { - metaData?: ProposalMetadata; + metaData?: CreateProposalMetadata; transactions?: MetaTransaction[]; decodedTransactions: DecodedTransaction[]; }; diff --git a/src/types/index.ts b/src/types/index.ts index e4968af8de..39819b0953 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -2,7 +2,7 @@ export * from './account'; export * from './common'; export * from './contract'; export * from './createDAO'; -export * from './createProposal'; +export * from './proposalBuilder'; export * from './daoGeneral'; export * from './daoGovernance'; export * from './daoGuard'; diff --git a/src/types/proposalBuilder.ts b/src/types/proposalBuilder.ts index 8b957137e9..28dbf9859b 100644 --- a/src/types/proposalBuilder.ts +++ b/src/types/proposalBuilder.ts @@ -1,5 +1,9 @@ import { BigNumberValuePair } from './common'; +export enum CreateProposalState { + METADATA_FORM, + TRANSACTIONS_FORM, +} export interface CreateProposalTransaction { targetAddress: string; ethValue: T; @@ -14,8 +18,10 @@ export interface CreateProposalTransaction { export type CreateProposalMetadata = { title: string; description: string; + documentationUrl?: string; }; +export type ProposalBuilderMode = 'proposal' | 'template'; export type CreateProposalForm = { transactions: CreateProposalTransaction[]; proposalMetadata: CreateProposalMetadata;