From 2fdb0fc5234591ab67a653750dcc179fdc1d662f Mon Sep 17 00:00:00 2001 From: Kirill Klimenko Date: Mon, 8 Apr 2024 14:29:33 +0200 Subject: [PATCH] Refactor CreateProposalTemplateForm into ProposalBuilder and make it more generic to be compatible with creating regular proposal --- .../ProposalDetails.tsx} | 10 +- .../ProposalMetadata.tsx} | 30 ++- .../ProposalTransaction.tsx} | 14 +- .../ProposalTransactions.tsx} | 19 +- .../ProposalTransactionsForm.tsx} | 24 +-- .../constants.ts | 8 +- src/components/ProposalBuilder/index.tsx | 192 ++++++++++++++++++ .../ProposalTemplateCard.tsx | 2 +- .../ui/modals/ForkProposalTemplateModal.tsx | 2 +- .../ui/modals/ProposalTemplateModal.tsx | 2 +- .../DAO/proposal/useCreateProposalTemplate.ts | 8 +- .../proposal-templates/new/index.tsx | 180 +--------------- src/providers/App/governance/action.ts | 2 +- src/types/createProposalTemplate.ts | 32 --- src/types/fractal.ts | 2 +- src/types/proposalBuilder.ts | 27 +++ 16 files changed, 287 insertions(+), 267 deletions(-) rename src/components/{CreateProposalTemplate/ProposalTemplateDetails.tsx => ProposalBuilder/ProposalDetails.tsx} (93%) rename src/components/{CreateProposalTemplate/ProposalTemplateMetadata.tsx => ProposalBuilder/ProposalMetadata.tsx} (54%) rename src/components/{CreateProposalTemplate/ProposalTemplateTransaction.tsx => ProposalBuilder/ProposalTransaction.tsx} (96%) rename src/components/{CreateProposalTemplate/ProposalTemplateTransactions.tsx => ProposalBuilder/ProposalTransactions.tsx} (86%) rename src/components/{CreateProposalTemplate/ProposalTemplateTransactionsForm.tsx => ProposalBuilder/ProposalTransactionsForm.tsx} (78%) rename src/components/{CreateProposalTemplate => ProposalBuilder}/constants.ts (52%) create mode 100644 src/components/ProposalBuilder/index.tsx delete mode 100644 src/types/createProposalTemplate.ts create mode 100644 src/types/proposalBuilder.ts diff --git a/src/components/CreateProposalTemplate/ProposalTemplateDetails.tsx b/src/components/ProposalBuilder/ProposalDetails.tsx similarity index 93% rename from src/components/CreateProposalTemplate/ProposalTemplateDetails.tsx rename to src/components/ProposalBuilder/ProposalDetails.tsx index a470459623..4bb24d63d0 100644 --- a/src/components/CreateProposalTemplate/ProposalTemplateDetails.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 { CreateProposalTemplateForm } from '../../types/createProposalTemplate'; +import { CreateProposalForm } from '../../types/proposalBuilder'; import Markdown from '../ui/proposal/Markdown'; import '../../assets/css/Markdown.css'; @@ -29,10 +29,10 @@ export function TransactionValueContainer({ } export default function ProposalTemplateDetails({ - values: { proposalTemplateMetadata, transactions }, -}: FormikProps) { + values: { proposalMetadata, transactions }, +}: FormikProps) { const { t } = useTranslation(['proposalTemplate', 'proposal']); - const trimmedTitle = proposalTemplateMetadata.title?.trim(); + const trimmedTitle = proposalMetadata.title?.trim(); return ( {t('proposalTemplateDescription')} diff --git a/src/components/CreateProposalTemplate/ProposalTemplateMetadata.tsx b/src/components/ProposalBuilder/ProposalMetadata.tsx similarity index 54% rename from src/components/CreateProposalTemplate/ProposalTemplateMetadata.tsx rename to src/components/ProposalBuilder/ProposalMetadata.tsx index 3d58b366e3..29573b0a88 100644 --- a/src/components/CreateProposalTemplate/ProposalTemplateMetadata.tsx +++ b/src/components/ProposalBuilder/ProposalMetadata.tsx @@ -1,22 +1,20 @@ import { Button, Divider, VStack } from '@chakra-ui/react'; import { FormikProps } from 'formik'; import { useTranslation } from 'react-i18next'; -import { - CreateProposalTemplateForm, - CreateProposalTemplateFormState, -} from '../../types/createProposalTemplate'; +import { CreateProposalState } from '../../types'; +import { CreateProposalForm } from '../../types/proposalBuilder'; import { InputComponent, TextareaComponent } from '../ui/forms/InputComponent'; -export interface ProposalTemplateMetadataProps extends FormikProps { - setFormState: (state: CreateProposalTemplateFormState) => void; +export interface ProposalMetadataProps extends FormikProps { + setFormState: (state: CreateProposalState) => void; } -export default function ProposalTemplateMetadata({ - values: { proposalTemplateMetadata }, +export default function ProposalMetadata({ + values: { proposalMetadata }, setFieldValue, - errors: { proposalTemplateMetadata: proposalTemplateMetadataError }, + errors: { proposalMetadata: proposalMetadataError }, setFormState, -}: ProposalTemplateMetadataProps) { +}: ProposalMetadataProps) { const { t } = useTranslation(['proposalTemplate', 'common']); return ( @@ -30,8 +28,8 @@ export default function ProposalTemplateMetadata({ label={t('proposalTemplateTitle')} helper={t('proposalTemplateTitleHelperText')} isRequired - value={proposalTemplateMetadata.title} - onChange={e => setFieldValue('proposalTemplateMetadata.title', e.target.value)} + value={proposalMetadata.title} + onChange={e => setFieldValue('proposalMetadata.title', e.target.value)} disabled={false} testId="metadata.title" maxLength={50} @@ -41,8 +39,8 @@ export default function ProposalTemplateMetadata({ subLabel={t('')} helper={t('proposalTemplateDescriptionHelperText')} isRequired={false} - value={proposalTemplateMetadata.description} - onChange={e => setFieldValue('proposalTemplateMetadata.description', e.target.value)} + value={proposalMetadata.description} + onChange={e => setFieldValue('proposalMetadata.description', e.target.value)} disabled={false} rows={12} /> @@ -54,8 +52,8 @@ export default function ProposalTemplateMetadata({ /> diff --git a/src/components/CreateProposalTemplate/ProposalTemplateTransaction.tsx b/src/components/ProposalBuilder/ProposalTransaction.tsx similarity index 96% rename from src/components/CreateProposalTemplate/ProposalTemplateTransaction.tsx rename to src/components/ProposalBuilder/ProposalTransaction.tsx index 33e5c5bdd5..b9f83bede1 100644 --- a/src/components/CreateProposalTemplate/ProposalTemplateTransaction.tsx +++ b/src/components/ProposalBuilder/ProposalTransaction.tsx @@ -2,14 +2,14 @@ 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 { CreateProposalTemplateTransaction } from '../../types/createProposalTemplate'; +import { CreateProposalTransaction } from '../../types/proposalBuilder'; import ABISelector, { ABIElement } from '../ui/forms/ABISelector'; import ExampleLabel from '../ui/forms/ExampleLabel'; import { BigNumberComponent, InputComponent } from '../ui/forms/InputComponent'; -import { DEFAULT_PROPOSAL_TEMPLATE_TRANSACTION } from './constants'; +import { DEFAULT_PROPOSAL_TRANSACTION } from './constants'; -interface ProposalTemplateTransactionProps { - transaction: CreateProposalTemplateTransaction; +interface ProposalTransactionProps { + transaction: CreateProposalTransaction; transactionIndex: number; transactionPending: boolean; txAddressError?: string; @@ -17,14 +17,14 @@ interface ProposalTemplateTransactionProps { setFieldValue: (field: string, value: any, shouldValidate?: boolean | undefined) => void; } -export default function ProposalTemplateTransaction({ +export default function ProposalTransaction({ transaction, transactionIndex, transactionPending, txAddressError, txFunctionError, setFieldValue, -}: ProposalTemplateTransactionProps) { +}: ProposalTransactionProps) { const { t } = useTranslation(['proposal', 'proposalTemplate', 'common']); const handleABISelectorChange = useCallback( (value: ABIElement) => { @@ -123,7 +123,7 @@ export default function ProposalTemplateTransaction({ onClick={() => setFieldValue(`transactions.${transactionIndex}.parameters`, [ ...transaction.parameters, - DEFAULT_PROPOSAL_TEMPLATE_TRANSACTION, + DEFAULT_PROPOSAL_TRANSACTION, ]) } > diff --git a/src/components/CreateProposalTemplate/ProposalTemplateTransactions.tsx b/src/components/ProposalBuilder/ProposalTransactions.tsx similarity index 86% rename from src/components/CreateProposalTemplate/ProposalTemplateTransactions.tsx rename to src/components/ProposalBuilder/ProposalTransactions.tsx index 1b4c5b4849..1f114ec7b6 100644 --- a/src/components/CreateProposalTemplate/ProposalTemplateTransactions.tsx +++ b/src/components/ProposalBuilder/ProposalTransactions.tsx @@ -12,25 +12,22 @@ import { FormikErrors, FormikProps } from 'formik'; import { Dispatch, SetStateAction } from 'react'; import { useTranslation } from 'react-i18next'; import { BigNumberValuePair } from '../../types'; -import { - CreateProposalTemplateForm, - CreateProposalTemplateTransaction, -} from '../../types/createProposalTemplate'; -import ProposalTemplateTransaction from './ProposalTemplateTransaction'; +import { CreateProposalForm, CreateProposalTransaction } from '../../types/proposalBuilder'; +import ProposalTransaction from './ProposalTransaction'; -interface ProposalTemplateTransactionsProps extends FormikProps { +interface ProposalTransactionsProps extends FormikProps { pendingTransaction: boolean; expandedIndecies: number[]; setExpandedIndecies: Dispatch>; } -export default function ProposalTemplateTransactions({ +export default function ProposalTransactions({ values: { transactions }, errors, setFieldValue, pendingTransaction, expandedIndecies, setExpandedIndecies, -}: ProposalTemplateTransactionsProps) { +}: ProposalTransactionsProps) { const { t } = useTranslation(['proposal', 'proposalTemplate', 'common']); const removeTransaction = (transactionIndex: number) => { @@ -46,7 +43,7 @@ export default function ProposalTemplateTransactions({ > {transactions.map((_, index) => { const txErrors = errors?.transactions?.[index] as - | FormikErrors> + | FormikErrors> | undefined; const txAddressError = txErrors?.targetAddress; const txFunctionError = txErrors?.functionName; @@ -101,8 +98,8 @@ export default function ProposalTemplateTransactions({ )} - { +interface ProposalTransactionsFormProps extends FormikProps { pendingTransaction: boolean; - setFormState: (state: CreateProposalTemplateFormState) => void; + setFormState: (state: CreateProposalState) => void; canUserCreateProposal?: boolean; safeNonce?: number; } -export default function ProposalTemplateTransactionsForm( - props: ProposalTemplateTransactionsFormProps, -) { +export default function ProposalTransactionsForm(props: ProposalTransactionsFormProps) { const { pendingTransaction, setFormState, @@ -41,7 +37,7 @@ export default function ProposalTemplateTransactionsForm( return ( - { - setFieldValue('transactions', [...transactions, DEFAULT_PROPOSAL_TEMPLATE_TRANSACTION]); + setFieldValue('transactions', [...transactions, DEFAULT_PROPOSAL_TRANSACTION]); setExpandedIndecies([transactions.length]); scrollToBottom(); }} @@ -85,7 +81,7 @@ export default function ProposalTemplateTransactionsForm( textStyle="text-md-mono-regular" color="gold.500" cursor="pointer" - onClick={() => setFormState(CreateProposalTemplateFormState.METADATA_FORM)} + onClick={() => setFormState(CreateProposalState.METADATA_FORM)} mb={4} > {t('back', { ns: 'common' })} diff --git a/src/components/CreateProposalTemplate/constants.ts b/src/components/ProposalBuilder/constants.ts similarity index 52% rename from src/components/CreateProposalTemplate/constants.ts rename to src/components/ProposalBuilder/constants.ts index 4c7930e184..bd76faf013 100644 --- a/src/components/CreateProposalTemplate/constants.ts +++ b/src/components/ProposalBuilder/constants.ts @@ -1,6 +1,6 @@ -import { CreateProposalTemplateTransaction } from '../../types/createProposalTemplate'; +import { CreateProposalTransaction } from '../../types/proposalBuilder'; -export const DEFAULT_PROPOSAL_TEMPLATE_TRANSACTION: CreateProposalTemplateTransaction = { +export const DEFAULT_PROPOSAL_TRANSACTION: CreateProposalTransaction = { targetAddress: '', ethValue: { value: '', bigNumberValue: undefined }, functionName: '', @@ -15,9 +15,9 @@ export const DEFAULT_PROPOSAL_TEMPLATE_TRANSACTION: CreateProposalTemplateTransa export const DEFAULT_PROPOSAL_TEMPLATE = { nonce: undefined, - proposalTemplateMetadata: { + proposalMetadata: { title: '', description: '', }, - transactions: [DEFAULT_PROPOSAL_TEMPLATE_TRANSACTION], + transactions: [DEFAULT_PROPOSAL_TRANSACTION], }; diff --git a/src/components/ProposalBuilder/index.tsx b/src/components/ProposalBuilder/index.tsx new file mode 100644 index 0000000000..590f84f6aa --- /dev/null +++ b/src/components/ProposalBuilder/index.tsx @@ -0,0 +1,192 @@ +import { Box, Flex, Grid, GridItem, Text } from '@chakra-ui/react'; +import { Trash } from '@decent-org/fractal-ui'; +import { Formik, FormikProps } from 'formik'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +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 { 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 { 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'; + prepareProposalData: (values: CreateProposalForm) => Promise; + initialValues: typeof DEFAULT_PROPOSAL_TEMPLATE; +} + +const templateAreaTwoCol = '"content details"'; +const templateAreaSingleCol = `"content" + "details"`; + +export default function ProposalBuilder({ mode, initialValues, prepareProposalData }: IProposalBuilder) { + const [formState, setFormState] = useState(CreateProposalState.METADATA_FORM); + const { t } = useTranslation(['proposalTemplate', 'proposal']); + + const isProposalMode = mode === 'proposal'; + + const navigate = useNavigate(); + const { + node: { daoAddress, safe }, + } = useFractal(); + const { addressPrefix } = useNetworkConfig(); + const { submitProposal, pendingCreateTx } = useSubmitProposal(); + const { canUserCreateProposal } = useCanUserCreateProposal(); + const { createProposalTemplateValidation } = useCreateProposalTemplateSchema(); + + const successCallback = () => { + if (daoAddress) { + // Redirecting to proposals page so that user will see Proposal for Proposal Template creation + navigate(DAO_ROUTES.proposals.relative(addressPrefix, daoAddress)); + } + }; + + return ( + + validationSchema={createProposalTemplateValidation} + initialValues={initialValues} + enableReinitialize + onSubmit={async values => { + if (canUserCreateProposal) { + const proposalData = await prepareProposalData(values); + if (proposalData) { + submitProposal({ + proposalData, + nonce: values?.nonce, + pendingToastMessage: t('proposalCreatePendingToastMessage', { ns: 'proposal' }), + successToastMessage: t('proposalCreateSuccessToastMessage', { ns: 'proposal' }), + failedToastMessage: t('proposalCreateFailureToastMessage', { ns: 'proposal' }), + successCallback, + }); + } + } + }} + > + {(formikProps: FormikProps) => { + const { handleSubmit } = formikProps; + + if (!daoAddress) { + return; + } + + return ( +
+ + + navigate( + daoAddress + ? isProposalMode + ? DAO_ROUTES.proposals.relative(addressPrefix, daoAddress) + : DAO_ROUTES.proposalTemplates.relative(addressPrefix, daoAddress) + : BASE_ROUTES.landing, + ) + } + isButtonDisabled={pendingCreateTx} + /> + + + + + {formState === CreateProposalState.METADATA_FORM ? ( + + ) : ( + <> + + + {formikProps.values.proposalMetadata.title} + + formikProps.setFieldValue('nonce', newNonce)} + align="end" + /> + + + + )} + + + + + + + + +
+ ); + }} + + ); +} diff --git a/src/components/ProposalTemplates/ProposalTemplateCard.tsx b/src/components/ProposalTemplates/ProposalTemplateCard.tsx index cc8336146a..fcecd49fdf 100644 --- a/src/components/ProposalTemplates/ProposalTemplateCard.tsx +++ b/src/components/ProposalTemplates/ProposalTemplateCard.tsx @@ -9,7 +9,7 @@ import useSubmitProposal from '../../hooks/DAO/proposal/useSubmitProposal'; import { useCanUserCreateProposal } from '../../hooks/utils/useCanUserSubmitProposal'; import { useFractal } from '../../providers/App/AppProvider'; import { useNetworkConfig } from '../../providers/NetworkConfig/NetworkConfigProvider'; -import { ProposalTemplate } from '../../types/createProposalTemplate'; +import { ProposalTemplate } from '../../types/proposalBuilder'; import ContentBox from '../ui/containers/ContentBox'; import { OptionMenu } from '../ui/menus/OptionMenu'; import { ModalType } from '../ui/modals/ModalProvider'; diff --git a/src/components/ui/modals/ForkProposalTemplateModal.tsx b/src/components/ui/modals/ForkProposalTemplateModal.tsx index f63cf23d7d..ccfe6c5536 100644 --- a/src/components/ui/modals/ForkProposalTemplateModal.tsx +++ b/src/components/ui/modals/ForkProposalTemplateModal.tsx @@ -9,7 +9,7 @@ import { useCanUserCreateProposal } from '../../../hooks/utils/useCanUserSubmitP import useSignerOrProvider from '../../../hooks/utils/useSignerOrProvider'; import { useFractal } from '../../../providers/App/AppProvider'; import { useNetworkConfig } from '../../../providers/NetworkConfig/NetworkConfigProvider'; -import { ProposalTemplate } from '../../../types/createProposalTemplate'; +import { ProposalTemplate } from '../../../types/proposalBuilder'; import { InputComponent } from '../forms/InputComponent'; interface IForkProposalTemplateModalProps { diff --git a/src/components/ui/modals/ProposalTemplateModal.tsx b/src/components/ui/modals/ProposalTemplateModal.tsx index 210849e214..d9250b6941 100644 --- a/src/components/ui/modals/ProposalTemplateModal.tsx +++ b/src/components/ui/modals/ProposalTemplateModal.tsx @@ -20,7 +20,7 @@ import { useCanUserCreateProposal } from '../../../hooks/utils/useCanUserSubmitP import { useFractal } from '../../../providers/App/AppProvider'; import { useNetworkConfig } from '../../../providers/NetworkConfig/NetworkConfigProvider'; import { BigNumberValuePair } from '../../../types'; -import { ProposalTemplate } from '../../../types/createProposalTemplate'; +import { ProposalTemplate } from '../../../types/proposalBuilder'; import { isValidUrl } from '../../../utils/url'; import { CustomNonceInput } from '../forms/CustomNonceInput'; import { BigNumberComponent, InputComponent } from '../forms/InputComponent'; diff --git a/src/hooks/DAO/proposal/useCreateProposalTemplate.ts b/src/hooks/DAO/proposal/useCreateProposalTemplate.ts index b804e740f2..625005cf84 100644 --- a/src/hooks/DAO/proposal/useCreateProposalTemplate.ts +++ b/src/hooks/DAO/proposal/useCreateProposalTemplate.ts @@ -3,7 +3,7 @@ import { useCallback } from 'react'; import { useFractal } from '../../../providers/App/AppProvider'; import useIPFSClient from '../../../providers/App/hooks/useIPFSClient'; import { ProposalExecuteData } from '../../../types'; -import { CreateProposalTemplateForm } from '../../../types/createProposalTemplate'; +import { CreateProposalForm } from '../../../types/proposalBuilder'; import { couldBeENS } from '../../../utils/url'; import useSafeContracts from '../../safe/useSafeContracts'; import useSignerOrProvider from '../../utils/useSignerOrProvider'; @@ -18,7 +18,7 @@ export default function useCreateProposalTemplate() { } = useFractal(); const prepareProposalTemplateProposal = useCallback( - async (values: CreateProposalTemplateForm) => { + async (values: CreateProposalForm) => { if (proposalTemplates && signerOrProvider && keyValuePairsContract) { const proposalMetadata = { title: 'Create Proposal Template', @@ -28,8 +28,8 @@ export default function useCreateProposalTemplate() { }; const proposalTemplateData = { - title: values.proposalTemplateMetadata.title.trim(), - description: values.proposalTemplateMetadata.description.trim(), + title: values.proposalMetadata.title.trim(), + description: values.proposalMetadata.description.trim(), transactions: await Promise.all( values.transactions.map(async tx => ({ ...tx, diff --git a/src/pages/daos/[daoAddress]/proposal-templates/new/index.tsx b/src/pages/daos/[daoAddress]/proposal-templates/new/index.tsx index d557d064f7..a5366c743b 100644 --- a/src/pages/daos/[daoAddress]/proposal-templates/new/index.tsx +++ b/src/pages/daos/[daoAddress]/proposal-templates/new/index.tsx @@ -1,42 +1,17 @@ -import { Box, Flex, Grid, GridItem, Text } from '@chakra-ui/react'; -import { Trash } from '@decent-org/fractal-ui'; import { BigNumber } from 'ethers'; -import { Formik, FormikProps } from 'formik'; import { useEffect, useState, useMemo } from 'react'; -import { useTranslation } from 'react-i18next'; -import { useNavigate, useSearchParams } from 'react-router-dom'; -import ProposalTemplateDetails from '../../../../../components/CreateProposalTemplate/ProposalTemplateDetails'; -import ProposalTemplateMetadata from '../../../../../components/CreateProposalTemplate/ProposalTemplateMetadata'; -import ProposalTemplateTransactionsForm from '../../../../../components/CreateProposalTemplate/ProposalTemplateTransactionsForm'; -import { DEFAULT_PROPOSAL_TEMPLATE } from '../../../../../components/CreateProposalTemplate/constants'; -import { CustomNonceInput } from '../../../../../components/ui/forms/CustomNonceInput'; -import PageHeader from '../../../../../components/ui/page/Header/PageHeader'; -import { BACKGROUND_SEMI_TRANSPARENT } from '../../../../../constants/common'; -import { BASE_ROUTES, DAO_ROUTES } from '../../../../../constants/routes'; +import { useSearchParams } from 'react-router-dom'; +import ProposalBuilder from '../../../../../components/ProposalBuilder'; +import { DEFAULT_PROPOSAL_TEMPLATE } from '../../../../../components/ProposalBuilder/constants'; import { logError } from '../../../../../helpers/errorLogging'; import useCreateProposalTemplate from '../../../../../hooks/DAO/proposal/useCreateProposalTemplate'; -import useSubmitProposal from '../../../../../hooks/DAO/proposal/useSubmitProposal'; -import useCreateProposalTemplateSchema from '../../../../../hooks/schemas/createProposalTemplate/useCreateProposalTemplateSchema'; -import { useCanUserCreateProposal } from '../../../../../hooks/utils/useCanUserSubmitProposal'; -import { useFractal } from '../../../../../providers/App/AppProvider'; import useIPFSClient from '../../../../../providers/App/hooks/useIPFSClient'; -import { useNetworkConfig } from '../../../../../providers/NetworkConfig/NetworkConfigProvider'; -import { - CreateProposalTemplateForm, - CreateProposalTemplateFormState, - ProposalTemplate, -} from '../../../../../types/createProposalTemplate'; - -const templateAreaTwoCol = '"content details"'; -const templateAreaSingleCol = `"content" - "details"`; +import { ProposalTemplate } from '../../../../../types/proposalBuilder'; export default function CreateProposalTemplatePage() { - const [formState, setFormState] = useState(CreateProposalTemplateFormState.METADATA_FORM); + const ipfsClient = useIPFSClient(); const [initialProposalTemplate, setInitialProposalTemplate] = useState(DEFAULT_PROPOSAL_TEMPLATE); - const { t } = useTranslation(['proposalTemplate', 'proposal']); - - const navigate = useNavigate(); + const { prepareProposalTemplateProposal } = useCreateProposalTemplate(); const [searchParams] = useSearchParams(); const defaultProposalTemplatesHash = useMemo( () => searchParams?.get('templatesHash'), @@ -47,24 +22,6 @@ export default function CreateProposalTemplatePage() { [searchParams], ); - const { - node: { daoAddress, safe }, - } = useFractal(); - const { addressPrefix } = useNetworkConfig(); - - const { prepareProposalTemplateProposal } = useCreateProposalTemplate(); - const { submitProposal, pendingCreateTx } = useSubmitProposal(); - const { canUserCreateProposal } = useCanUserCreateProposal(); - const { createProposalTemplateValidation } = useCreateProposalTemplateSchema(); - const ipfsClient = useIPFSClient(); - - const successCallback = () => { - if (daoAddress) { - // Redirecting to proposals page so that user will see Proposal for Proposal Template creation - navigate(DAO_ROUTES.proposals.relative(addressPrefix, daoAddress)); - } - }; - useEffect(() => { const loadInitialTemplate = async () => { if (defaultProposalTemplatesHash && defaultProposalTemplateIndex) { @@ -74,7 +31,7 @@ export default function CreateProposalTemplatePage() { if (initialTemplate) { const newInitialValue = { nonce: undefined, - proposalTemplateMetadata: { + proposalMetadata: { title: initialTemplate.title, description: initialTemplate.description || '', }, @@ -97,125 +54,10 @@ export default function CreateProposalTemplatePage() { }, [defaultProposalTemplatesHash, defaultProposalTemplateIndex, ipfsClient]); return ( - - validationSchema={createProposalTemplateValidation} + { - if (canUserCreateProposal) { - const proposalData = await prepareProposalTemplateProposal(values); - if (proposalData) { - submitProposal({ - proposalData, - nonce: values?.nonce, - pendingToastMessage: t('proposalCreatePendingToastMessage', { ns: 'proposal' }), - successToastMessage: t('proposalCreateSuccessToastMessage', { ns: 'proposal' }), - failedToastMessage: t('proposalCreateFailureToastMessage', { ns: 'proposal' }), - successCallback, - }); - } - } - }} - > - {(formikProps: FormikProps) => { - const { handleSubmit } = formikProps; - - if (!daoAddress) { - return; - } - - return ( -
- - - navigate( - daoAddress - ? DAO_ROUTES.proposalTemplates.relative(addressPrefix, daoAddress) - : BASE_ROUTES.landing, - ) - } - isButtonDisabled={pendingCreateTx} - /> - - - - - {formState === CreateProposalTemplateFormState.METADATA_FORM ? ( - - ) : ( - <> - - - {formikProps.values.proposalTemplateMetadata.title} - - formikProps.setFieldValue('nonce', newNonce)} - align="end" - /> - - - - )} - - - - - - - - -
- ); - }} - + prepareProposalData={prepareProposalTemplateProposal} + /> ); } diff --git a/src/providers/App/governance/action.ts b/src/providers/App/governance/action.ts index 0293593ea8..70b14153b6 100644 --- a/src/providers/App/governance/action.ts +++ b/src/providers/App/governance/action.ts @@ -11,7 +11,7 @@ import { GovernanceType, ERC721TokenData, } from '../../../types'; -import { ProposalTemplate } from '../../../types/createProposalTemplate'; +import { ProposalTemplate } from '../../../types/proposalBuilder'; export enum FractalGovernanceAction { SET_GOVERNANCE_TYPE = 'SET_GOVERNANCE_TYPE', diff --git a/src/types/createProposalTemplate.ts b/src/types/createProposalTemplate.ts deleted file mode 100644 index bab428f939..0000000000 --- a/src/types/createProposalTemplate.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { BigNumberValuePair } from './common'; - -export enum CreateProposalTemplateFormState { - METADATA_FORM, - TRANSACTIONS_FORM, -} - -export interface CreateProposalTemplateTransaction { - targetAddress: string; - ethValue: T; - functionName: string; - parameters: { - signature: string; - label?: string; - value?: string; - }[]; -} - -export type CreateProposalTemplateMetadata = { - title: string; - description: string; -}; - -export type CreateProposalTemplateForm = { - transactions: CreateProposalTemplateTransaction[]; - proposalTemplateMetadata: CreateProposalTemplateMetadata; - nonce?: number; -}; - -export type ProposalTemplate = { - transactions: CreateProposalTemplateTransaction[]; -} & CreateProposalTemplateMetadata; diff --git a/src/types/fractal.ts b/src/types/fractal.ts index 94223dd398..24b48dc666 100644 --- a/src/types/fractal.ts +++ b/src/types/fractal.ts @@ -35,10 +35,10 @@ import { TreasuryActions } from '../providers/App/treasury/action'; import { NodeActions } from './../providers/App/node/action'; import { ERC721TokenData, VotesTokenData } from './account'; import { ContractConnection } from './contract'; -import { ProposalTemplate } from './createProposalTemplate'; import { FreezeGuardType, FreezeVotingType } from './daoGovernance'; import { ProposalData, MultisigProposal, AzoriusProposal, SnapshotProposal } from './daoProposal'; import { TreasuryActivity } from './daoTreasury'; +import { ProposalTemplate } from './proposalBuilder'; import { AllTransfersListResponse, SafeInfoResponseWithGuard } from './safeGlobal'; import { BNFormattedPair } from './votingFungibleToken'; /** diff --git a/src/types/proposalBuilder.ts b/src/types/proposalBuilder.ts new file mode 100644 index 0000000000..8b957137e9 --- /dev/null +++ b/src/types/proposalBuilder.ts @@ -0,0 +1,27 @@ +import { BigNumberValuePair } from './common'; + +export interface CreateProposalTransaction { + targetAddress: string; + ethValue: T; + functionName: string; + parameters: { + signature: string; + label?: string; + value?: string; + }[]; +} + +export type CreateProposalMetadata = { + title: string; + description: string; +}; + +export type CreateProposalForm = { + transactions: CreateProposalTransaction[]; + proposalMetadata: CreateProposalMetadata; + nonce?: number; +}; + +export type ProposalTemplate = { + transactions: CreateProposalTransaction[]; +} & CreateProposalMetadata;