From 6200ab6d49a49a6a56fb5c8fc33c744c79602a63 Mon Sep 17 00:00:00 2001 From: selankon Date: Thu, 20 Jul 2023 12:07:39 +0200 Subject: [PATCH 01/29] Create votingType selector --- src/containers/setupCommunity/index.tsx | 33 +++++++++++++++++++++++++ src/locales/en/common.json | 14 ++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/containers/setupCommunity/index.tsx b/src/containers/setupCommunity/index.tsx index 9666efa90..ed584a54b 100644 --- a/src/containers/setupCommunity/index.tsx +++ b/src/containers/setupCommunity/index.tsx @@ -96,6 +96,39 @@ const SetupCommunityForm: React.FC = () => { /> + + + {membership === 'multisig' && ( <> diff --git a/src/locales/en/common.json b/src/locales/en/common.json index 638ee476f..c26ab8a32 100644 --- a/src/locales/en/common.json +++ b/src/locales/en/common.json @@ -756,7 +756,19 @@ "descriptionLinkLabel": "read this guide", "descriptionLinkURL": "https://aragon.org/how-to/set-up-your-dao-governance-in-8-steps", "distributeTokensHelpertextLinkLabel": "read our guide", - "distributeTokensHelpertextLinkURL": "https://aragon.org/how-to/distribute-a-dao-governance-token" + "distributeTokensHelpertextLinkURL": "https://aragon.org/how-to/distribute-a-dao-governance-token", + "votingType": { + "title": "Should voting take place on-chain or off-chain", + "onChain": { + "title": "On-chain", + "subtitle": "The voting process and the execution of actions binded to a proposal are both on-chain" + }, + "offChain": { + "title": "Off-chain", + "subtitle": "The voting process is off-chain, while the proof of all votes and the execution are done by a multisig called \"Guardians\"" + } + + } }, "step4": { "label": "Step 4", From b794a88a561a4fa164e86f614e07ce27bc3f5354 Mon Sep 17 00:00:00 2001 From: selankon Date: Thu, 20 Jul 2023 12:10:16 +0200 Subject: [PATCH 02/29] Create ProposalCreation component --- src/containers/configureCommunity/index.tsx | 4 ++ .../configureCommunity/proposalCreation.tsx | 60 +++++++++++++++++++ .../setupCommunity/addExistingToken.tsx | 14 ----- .../setupCommunity/createNewToken.tsx | 9 --- src/containers/setupCommunity/index.tsx | 4 -- src/pages/createDAO.tsx | 20 +++++-- 6 files changed, 80 insertions(+), 31 deletions(-) create mode 100644 src/containers/configureCommunity/proposalCreation.tsx diff --git a/src/containers/configureCommunity/index.tsx b/src/containers/configureCommunity/index.tsx index 6f8d5a12d..e9cadc3b1 100644 --- a/src/containers/configureCommunity/index.tsx +++ b/src/containers/configureCommunity/index.tsx @@ -21,6 +21,7 @@ import { MIN_DURATION_HOURS, } from 'utils/constants'; import {getDaysHoursMins} from 'utils/date'; +import {ProposalCreation} from './proposalCreation'; export type ConfigureCommunityProps = { isSettingPage?: boolean; @@ -396,6 +397,9 @@ const ConfigureCommunity: React.FC = ({ )} + + + ); }; diff --git a/src/containers/configureCommunity/proposalCreation.tsx b/src/containers/configureCommunity/proposalCreation.tsx new file mode 100644 index 000000000..56ad6f3c7 --- /dev/null +++ b/src/containers/configureCommunity/proposalCreation.tsx @@ -0,0 +1,60 @@ +import {useFormContext, useWatch} from 'react-hook-form'; +import {useTranslation} from 'react-i18next'; +import useScreen from '../../hooks/useScreen'; +import {MultisigEligibility} from '../../components/multisigEligibility'; +import React from 'react'; +import {Label} from '@aragon/ods'; +import {SelectEligibility} from '../../components/selectEligibility'; +import styled from 'styled-components'; + +const TokenProposalCreation = () => { + const [isCustomToken, tokenType] = useWatch({ + name: ['isCustomToken', 'tokenType'], + }); + const {t} = useTranslation(); + const isAllowedToConfigureVotingEligibility = + isCustomToken || tokenType === 'ERC-20' || tokenType === 'governance-ERC20'; + return ( + <> + {isAllowedToConfigureVotingEligibility && ( + <> + + + + + )} + + ); +}; + +export const ProposalCreation = () => { + const {control} = useFormContext(); + const {t} = useTranslation(); + const {isMobile} = useScreen(); + const [membership, isCustomToken] = useWatch({ + name: ['membership', 'isCustomToken'], + }); + + return ( +
+ {membership === 'multisig' && ( + <> + + + )} + {membership === 'token' && ( + <> + + + )} +
+ ); +}; + +const DescriptionContainer = styled.div.attrs({ + className: 'space-y-0.5', +})``; diff --git a/src/containers/setupCommunity/addExistingToken.tsx b/src/containers/setupCommunity/addExistingToken.tsx index e7990b216..bf385dc14 100644 --- a/src/containers/setupCommunity/addExistingToken.tsx +++ b/src/containers/setupCommunity/addExistingToken.tsx @@ -86,9 +86,6 @@ const AddExistingToken: React.FC = () => { [clearErrors, network, provider, resetField, setValue] ); - const isAllowedToConfigureVotingEligibility = - tokenType === 'ERC-20' || tokenType === 'governance-ERC20'; - return ( <> @@ -136,17 +133,6 @@ const AddExistingToken: React.FC = () => { )} /> - {isAllowedToConfigureVotingEligibility && ( - - - - - - )} ); }; diff --git a/src/containers/setupCommunity/createNewToken.tsx b/src/containers/setupCommunity/createNewToken.tsx index 11c8c213a..7b2154dce 100644 --- a/src/containers/setupCommunity/createNewToken.tsx +++ b/src/containers/setupCommunity/createNewToken.tsx @@ -101,15 +101,6 @@ const CreateNewToken: React.FC = () => { /> - - - - - ); }; diff --git a/src/containers/setupCommunity/index.tsx b/src/containers/setupCommunity/index.tsx index ed584a54b..e4bb11d6a 100644 --- a/src/containers/setupCommunity/index.tsx +++ b/src/containers/setupCommunity/index.tsx @@ -6,7 +6,6 @@ import styled from 'styled-components'; import CreateNewToken from './createNewToken'; import {MultisigWallets} from 'components/multisigWallets'; -import {MultisigEligibility} from 'components/multisigEligibility'; import {FormSection} from 'containers/setupVotingForm'; import {ToggleCheckList} from 'containers/setupVotingForm/multisig'; import AddExistingToken from './addExistingToken'; @@ -134,9 +133,6 @@ const SetupCommunityForm: React.FC = () => { - - - )} diff --git a/src/pages/createDAO.tsx b/src/pages/createDAO.tsx index 95a37ad6e..647c59446 100644 --- a/src/pages/createDAO.tsx +++ b/src/pages/createDAO.tsx @@ -176,9 +176,6 @@ const CreateDAO: React.FC = () => { ) { return false; } - if (!['multisig', 'anyone'].includes(eligibilityType)) { - return false; - } return true; // if token based dao } else { @@ -228,6 +225,19 @@ const CreateDAO: React.FC = () => { tokenType, ]); + const proposalCreationIsValid = useMemo(() => { + // required fields not dirty + // if multisig + if (membership === 'multisig') { + if (!['multisig', 'anyone'].includes(eligibilityType)) { + return false; + } + return true; + } else { + return !errors.eligibilityTokenAmount; + } + }, [eligibilityType, errors.eligibilityTokenAmount, membership]); + const daoConfigureCommunity = useMemo(() => { if ( errors.minimumApproval || @@ -330,7 +340,9 @@ const CreateDAO: React.FC = () => { handleNextButtonTracking(next, '4_configure_governance', { minimum_approval: formMethods.getValues('minimumApproval'), From bf8db4ffbfcf698c3213a111a477580197239b1c Mon Sep 17 00:00:00 2001 From: selankon Date: Thu, 20 Jul 2023 12:43:07 +0200 Subject: [PATCH 03/29] Add missing CreateDaoFormData property --- src/pages/createDAO.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/createDAO.tsx b/src/pages/createDAO.tsx index 647c59446..2e3be2b57 100644 --- a/src/pages/createDAO.tsx +++ b/src/pages/createDAO.tsx @@ -55,6 +55,7 @@ export type CreateDaoFormData = { voteReplacement: boolean; multisigWallets: MultisigWalletField[]; multisigMinimumApprovals: number; + votingType: 'onChain' | 'offChain'; }; const defaultValues = { @@ -328,6 +329,7 @@ const CreateDAO: React.FC = () => { onNextButtonClicked={next => handleNextButtonTracking(next, '3_setup_community', { governance_type: formMethods.getValues('membership'), + voting_type: formMethods.getValues('votingType'), token_name: formMethods.getValues('tokenName'), symbol: formMethods.getValues('tokenSymbol'), token_address: formMethods.getValues('tokenAddress.address'), From 332327279d3757dbc0f75c77984a42456fc9f19f Mon Sep 17 00:00:00 2001 From: selankon Date: Fri, 21 Jul 2023 13:25:52 +0200 Subject: [PATCH 04/29] Implement add executive commite wallets --- src/components/addCommitteeMembers/footer.tsx | 50 ++++++ src/components/addCommitteeMembers/header.tsx | 26 +++ src/components/addCommitteeMembers/index.tsx | 126 +++++++++++++ src/components/addCommitteeMembers/row.tsx | 169 ++++++++++++++++++ src/containers/defineCommittee/index.tsx | 43 +++++ src/locales/en/common.json | 15 ++ src/pages/createDAO.tsx | 2 + 7 files changed, 431 insertions(+) create mode 100644 src/components/addCommitteeMembers/footer.tsx create mode 100644 src/components/addCommitteeMembers/header.tsx create mode 100644 src/components/addCommitteeMembers/index.tsx create mode 100644 src/components/addCommitteeMembers/row.tsx create mode 100644 src/containers/defineCommittee/index.tsx diff --git a/src/components/addCommitteeMembers/footer.tsx b/src/components/addCommitteeMembers/footer.tsx new file mode 100644 index 000000000..e90a08632 --- /dev/null +++ b/src/components/addCommitteeMembers/footer.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import styled from 'styled-components'; +import {Label} from '@aragon/ods'; +import {useTranslation} from 'react-i18next'; + +type WalletsFooterProps = { + totalAddresses: number; +}; + +const AddWalletsFooter: React.FC = ({totalAddresses}) => { + const {t} = useTranslation(); + + return ( + + + + + + {t('labels.whitelistWallets.totalWallets')} + + + {totalAddresses} + + + + ); +}; + +export default AddWalletsFooter; + +export const Container = styled.div.attrs({ + className: 'hidden tablet:flex tablet:flex-col p-2 bg-ui-0', +})``; + +const FooterRow = styled.div.attrs({ + className: 'flex', +})``; + +export const FooterItem1 = styled.div.attrs({ + className: 'flex-1', +})``; + +export const FooterItem2 = styled.div.attrs({ + className: 'w-8 text-right', +})``; + +const StyledLabel = styled.p.attrs({ + className: 'text-ui-800', +})``; diff --git a/src/components/addCommitteeMembers/header.tsx b/src/components/addCommitteeMembers/header.tsx new file mode 100644 index 000000000..c188f83e1 --- /dev/null +++ b/src/components/addCommitteeMembers/header.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import styled from 'styled-components'; +import {Label} from '@aragon/ods'; +import {useTranslation} from 'react-i18next'; + +const AddWalletsHeader: React.FC = () => { + const {t} = useTranslation(); + + return ( + + + + + ); +}; + +export default AddWalletsHeader; + +export const Container = styled.div.attrs({ + className: 'hidden tablet:flex p-2 space-x-2 bg-ui-0', +})``; + +export const HeaderItem = styled.div.attrs({ + className: 'flex-1', +})``; diff --git a/src/components/addCommitteeMembers/index.tsx b/src/components/addCommitteeMembers/index.tsx new file mode 100644 index 000000000..7be619853 --- /dev/null +++ b/src/components/addCommitteeMembers/index.tsx @@ -0,0 +1,126 @@ +import { + AlertInline, + ButtonIcon, + ButtonText, + Dropdown, + IconMenuVertical, + ListItemAction, +} from '@aragon/ods'; +import React, {useEffect} from 'react'; +import {useFieldArray, useFormContext, useWatch} from 'react-hook-form'; +import {useTranslation} from 'react-i18next'; +import styled from 'styled-components'; + +import {useAlertContext} from 'context/alert'; +import {useWallet} from 'hooks/useWallet'; +import Footer from './footer'; +import Header from './header'; +import Row from './row'; + +const AddCommitteeMembers: React.FC = () => { + const {t} = useTranslation(); + const {address, ensName} = useWallet(); + + const {control, trigger} = useFormContext(); + const wallets = useWatch({name: 'committee', control: control}); + const {fields, append, remove} = useFieldArray({ + name: 'committee', + control, + }); + const {alert} = useAlertContext(); + + const controlledFields = fields.map((field, index) => { + return { + ...field, + ...(wallets && {...wallets[index]}), + }; + }); + + useEffect(() => { + if (address && !wallets) { + // uncomment when minting to treasury is ready + // insert(1, {address: address, amount: '0'}); + append({address, ensName, amount: 1}); + } + }, [address, append, ensName, wallets]); + + // setTimeout added because instant trigger not working + const handleAddWallet = () => { + append({address: '', ensName: '', amount: 1}); + setTimeout(() => { + trigger(`committee.${controlledFields.length}`); + }, 50); + }; + + const handleDeleteRow = (index: number) => { + remove(index); + setTimeout(() => { + trigger('committee'); + }); + }; + + return ( + + + {controlledFields.length > 0 &&
} + {controlledFields.map((field, index) => { + return ( + + ); + })} +