From b4c970a204ee710621a6b9077401f4d48935299e Mon Sep 17 00:00:00 2001 From: Madusha Prasanjith Date: Tue, 5 Apr 2022 11:52:59 +0530 Subject: [PATCH 1/6] feat: Update action builder option styles. --- .../Guilds/ActionsBuilder/Option/EditMode.tsx | 27 ++++++++++++++----- .../Guilds/ActionsBuilder/Option/ViewMode.tsx | 27 ++++++++++++++----- .../Guilds/ActionsBuilder/Option/styles.tsx | 9 ++++--- .../ActionsBuilder/common/DataTag/index.tsx | 17 ++++++++++++ .../common/EditButton/index.tsx | 13 +++++++++ .../ActionsBuilder/common/Grip/index.tsx | 13 +++++++++ .../Guilds/ActionsBuilder/index.tsx | 14 +++------- 7 files changed, 93 insertions(+), 27 deletions(-) create mode 100644 src/components/Guilds/ActionsBuilder/common/DataTag/index.tsx create mode 100644 src/components/Guilds/ActionsBuilder/common/EditButton/index.tsx create mode 100644 src/components/Guilds/ActionsBuilder/common/Grip/index.tsx diff --git a/src/components/Guilds/ActionsBuilder/Option/EditMode.tsx b/src/components/Guilds/ActionsBuilder/Option/EditMode.tsx index 8c460cb78d..6cf3e733dc 100644 --- a/src/components/Guilds/ActionsBuilder/Option/EditMode.tsx +++ b/src/components/Guilds/ActionsBuilder/Option/EditMode.tsx @@ -1,10 +1,13 @@ import { ProposalOptionTag } from '../common/ProposalOptionTag'; import AddButton from '../common/AddButton'; import ActionEditor from '../Action/EditMode'; -import { ActionCountLabel, DetailWrapper, OptionWrapper } from './styles'; +import { Detail, DetailWrapper, OptionWrapper } from './styles'; import { DecodedAction, Option } from '../types'; import { useState } from 'react'; import ActionModal from 'components/Guilds/ActionsModal'; +import Grip from '../common/Grip'; +import DataTag from '../common/DataTag'; +import EditButton from '../common/EditButton'; interface OptionRowProps { option: Option; @@ -31,11 +34,23 @@ const OptionEditMode: React.FC = ({ option, onChange }) => { return ( - - - {option?.actions?.length || 'No'} on-chain{' '} - {option?.actions?.length > 2 ? 'actions' : 'action'} - +
+ + + + + + + + + {option?.actions?.length || 'No'} on-chain{' '} + {option?.actions?.length >= 2 ? 'actions' : 'action'} + + +
+
+ Edit +
{option?.decodedActions?.map((action, index) => ( diff --git a/src/components/Guilds/ActionsBuilder/Option/ViewMode.tsx b/src/components/Guilds/ActionsBuilder/Option/ViewMode.tsx index 3e22ec2cbb..ab813fdac8 100644 --- a/src/components/Guilds/ActionsBuilder/Option/ViewMode.tsx +++ b/src/components/Guilds/ActionsBuilder/Option/ViewMode.tsx @@ -1,7 +1,10 @@ import { ProposalOptionTag } from '../common/ProposalOptionTag'; import ActionView from '../Action/ViewMode'; -import { ActionCountLabel, DetailWrapper, OptionWrapper } from './styles'; +import { Detail, DetailWrapper, OptionWrapper } from './styles'; import { Option } from '../types'; +import DataTag from '../common/DataTag'; +import Grip from '../common/Grip'; +import EditButton from '../common/EditButton'; interface OptionRowProps { data: Option; @@ -11,11 +14,23 @@ const OptionViewMode: React.FC = ({ data }) => { return ( - - - {data?.actions?.length || 'No'} on-chain{' '} - {data?.actions?.length >= 2 ? 'actions' : 'action'} - +
+ + + + + + + + + {data?.actions?.length || 'No'} on-chain{' '} + {data?.actions?.length >= 2 ? 'actions' : 'action'} + + +
+
+ Edit +
{data?.actions?.map((action, index) => ( diff --git a/src/components/Guilds/ActionsBuilder/Option/styles.tsx b/src/components/Guilds/ActionsBuilder/Option/styles.tsx index 4ae71320b6..2ebd12178a 100644 --- a/src/components/Guilds/ActionsBuilder/Option/styles.tsx +++ b/src/components/Guilds/ActionsBuilder/Option/styles.tsx @@ -1,10 +1,6 @@ import styled from 'styled-components'; import { Box } from 'components/Guilds/common/Layout'; -export const ActionCountLabel = styled.span` - color: ${({ theme }) => theme.gray}; -`; - export const OptionWrapper = styled(Box)` padding: 1rem; `; @@ -15,3 +11,8 @@ export const DetailWrapper = styled(Box)` flex-direction: row; justify-content: space-between; `; + +export const Detail = styled(Box)` + display: inline-flex; + margin-right: 0.75rem; +`; diff --git a/src/components/Guilds/ActionsBuilder/common/DataTag/index.tsx b/src/components/Guilds/ActionsBuilder/common/DataTag/index.tsx new file mode 100644 index 0000000000..50eb4c7ff3 --- /dev/null +++ b/src/components/Guilds/ActionsBuilder/common/DataTag/index.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import styled from 'styled-components'; + +interface DataTagProps { + children: React.ReactElement; +} + +const DataTag = styled.span` + border-radius: 0.5rem; + padding: 0.25rem 0.5rem; + background: ${({ theme }) => theme.colors.muted}; + border: 1px solid ${({ theme }) => theme.colors.muted}; + color: ${({ color }) => color}; + border-color: ${({ color }) => color}; +`; + +export default DataTag; diff --git a/src/components/Guilds/ActionsBuilder/common/EditButton/index.tsx b/src/components/Guilds/ActionsBuilder/common/EditButton/index.tsx new file mode 100644 index 0000000000..6eb9d808a2 --- /dev/null +++ b/src/components/Guilds/ActionsBuilder/common/EditButton/index.tsx @@ -0,0 +1,13 @@ +import { Button } from 'components/Guilds/common/Button'; +import styled from 'styled-components'; + +const EditButton = styled(Button).attrs({ + variant: 'secondary', +})` + font-weight: ${({ theme }) => theme.fontWeights.medium}; + font-size: ${({ theme }) => theme.fontSizes.label}; + margin: 0; + padding: 0.25rem 0.75rem; +`; + +export default EditButton; diff --git a/src/components/Guilds/ActionsBuilder/common/Grip/index.tsx b/src/components/Guilds/ActionsBuilder/common/Grip/index.tsx new file mode 100644 index 0000000000..41924bab23 --- /dev/null +++ b/src/components/Guilds/ActionsBuilder/common/Grip/index.tsx @@ -0,0 +1,13 @@ +import styled from 'styled-components'; +import { FaGripVertical } from 'react-icons/fa'; + +const Grip = styled(FaGripVertical)` + cursor: grabbing; + color: ${({ theme }) => theme.colors.proposalText.lightGrey}; + + &:hover { + color: ${({ theme }) => theme.colors.text}; + } +`; + +export default Grip; diff --git a/src/components/Guilds/ActionsBuilder/index.tsx b/src/components/Guilds/ActionsBuilder/index.tsx index 24287e2801..01f2028d43 100644 --- a/src/components/Guilds/ActionsBuilder/index.tsx +++ b/src/components/Guilds/ActionsBuilder/index.tsx @@ -1,7 +1,5 @@ -import styled from 'styled-components'; import { useState } from 'react'; import { Header as CardHeader } from '../common/Card'; -import { Button as CommonButton } from '../common/Button'; import SidebarCard, { SidebarCardHeaderSpaced, } from 'components/Guilds/SidebarCard'; @@ -9,13 +7,7 @@ import EditMode from './EditMode'; import ViewMode from './ViewMode'; import { Option } from './types'; import { bulkEncodeCallsFromOptions } from 'hooks/Guilds/contracts/useEncodedCall'; - -const Button = styled(CommonButton)` - font-weight: ${({ theme }) => theme.fontWeights.medium}; - font-size: ${({ theme }) => theme.fontSizes.label}; - margin: 0; - padding: 0.25rem 0.75rem; -`; +import EditButton from './common/EditButton'; interface ActionsBuilderProps { options: Option[]; @@ -44,12 +36,12 @@ export const ActionsBuilder: React.FC = ({ Actions {editable && ( - + )} } From d609197ccf1dc76286c474ebf3258caacbbf9b6c Mon Sep 17 00:00:00 2001 From: Madusha Prasanjith Date: Tue, 5 Apr 2022 12:06:33 +0530 Subject: [PATCH 2/6] feat: Update action builder action styles. --- .../Guilds/ActionsBuilder/Action/ViewMode.tsx | 41 ++++++++++++++----- .../Guilds/ActionsBuilder/Option/ViewMode.tsx | 13 ++++-- 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/src/components/Guilds/ActionsBuilder/Action/ViewMode.tsx b/src/components/Guilds/ActionsBuilder/Action/ViewMode.tsx index 418c4332e4..38e4b5cc7e 100644 --- a/src/components/Guilds/ActionsBuilder/Action/ViewMode.tsx +++ b/src/components/Guilds/ActionsBuilder/Action/ViewMode.tsx @@ -8,6 +8,8 @@ import { useDecodedCall } from 'hooks/Guilds/contracts/useDecodedCall'; import { getInfoLineView, getSummaryView } from '../SupportedActions'; import CallDetails from '../CallDetails'; import { Call } from '../types'; +import Grip from '../common/Grip'; +import EditButton from '../common/EditButton'; const CardWrapperWithMargin = styled(CardWrapper)` margin-top: 0.8rem; @@ -29,10 +31,10 @@ const CardLabel = styled(Box)` const ChevronIcon = styled.span` cursor: pointer; - height: 1.25rem; - width: 1.25rem; + height: 1.4rem; + width: 1.4rem; border-radius: 50%; - border: 1px solid ${({ theme }) => theme.colors.proposalText.grey}; + border: 1px solid ${({ theme }) => theme.colors.muted}; display: inline-flex; justify-content: center; align-items: center; @@ -64,6 +66,20 @@ const TabButton = styled(Button)` `} `; +const GripWithMargin = styled(Grip)` + margin-right: 1rem; +`; + +const EditButtonWithMargin = styled(EditButton)` + margin-right: 0.625rem; +`; + +const CardActions = styled.div` + display: flex; + justify-content: center; + align-items: center; +`; + interface ActionViewProps { call: Call; } @@ -82,15 +98,20 @@ const ActionView: React.FC = ({ call }) => { + + {InfoLine && } - setExpanded(!expanded)}> - {expanded ? ( - - ) : ( - - )} - + + Edit + setExpanded(!expanded)}> + {expanded ? ( + + ) : ( + + )} + + {expanded && ( diff --git a/src/components/Guilds/ActionsBuilder/Option/ViewMode.tsx b/src/components/Guilds/ActionsBuilder/Option/ViewMode.tsx index ab813fdac8..08e3a0f55c 100644 --- a/src/components/Guilds/ActionsBuilder/Option/ViewMode.tsx +++ b/src/components/Guilds/ActionsBuilder/Option/ViewMode.tsx @@ -1,3 +1,4 @@ +import styled from 'styled-components'; import { ProposalOptionTag } from '../common/ProposalOptionTag'; import ActionView from '../Action/ViewMode'; import { Detail, DetailWrapper, OptionWrapper } from './styles'; @@ -10,6 +11,10 @@ interface OptionRowProps { data: Option; } +const ActionsWrapper = styled.div` + margin-left: 1.75rem; +`; + const OptionViewMode: React.FC = ({ data }) => { return ( @@ -33,9 +38,11 @@ const OptionViewMode: React.FC = ({ data }) => { - {data?.actions?.map((action, index) => ( - - ))} + + {data?.actions?.map((action, index) => ( + + ))} + ); }; From 7a58355d35778f495659b4065057096b1be841a9 Mon Sep 17 00:00:00 2001 From: Madusha Prasanjith Date: Tue, 5 Apr 2022 20:00:14 +0530 Subject: [PATCH 3/6] feat: Update action builder view mode styles. --- .../Guilds/ActionsBuilder/Action/ViewMode.tsx | 7 ++- .../Guilds/ActionsBuilder/EditMode.tsx | 20 +++++-- .../Guilds/ActionsBuilder/Option/EditMode.tsx | 60 +++++++++++++------ .../Guilds/ActionsBuilder/index.tsx | 27 ++++----- 4 files changed, 71 insertions(+), 43 deletions(-) diff --git a/src/components/Guilds/ActionsBuilder/Action/ViewMode.tsx b/src/components/Guilds/ActionsBuilder/Action/ViewMode.tsx index 38e4b5cc7e..17f5070947 100644 --- a/src/components/Guilds/ActionsBuilder/Action/ViewMode.tsx +++ b/src/components/Guilds/ActionsBuilder/Action/ViewMode.tsx @@ -82,9 +82,10 @@ const CardActions = styled.div` interface ActionViewProps { call: Call; + isEditable?: boolean; } -const ActionView: React.FC = ({ call }) => { +const ActionView: React.FC = ({ call, isEditable }) => { const { decodedCall } = useDecodedCall(call); const [expanded, setExpanded] = useState(false); @@ -98,12 +99,12 @@ const ActionView: React.FC = ({ call }) => { - + {isEditable && } {InfoLine && } - Edit + {isEditable && Edit} setExpanded(!expanded)}> {expanded ? ( diff --git a/src/components/Guilds/ActionsBuilder/EditMode.tsx b/src/components/Guilds/ActionsBuilder/EditMode.tsx index 97f8981dcd..06718f99c6 100644 --- a/src/components/Guilds/ActionsBuilder/EditMode.tsx +++ b/src/components/Guilds/ActionsBuilder/EditMode.tsx @@ -9,11 +9,16 @@ const AddOptionWrapper = styled(Box)` padding: 1rem; `; interface EditModeProps { + isEditable: boolean; options: Option[]; onChange: (options: Option[]) => void; } -const EditMode: React.FC = ({ options, onChange }) => { +const EditMode: React.FC = ({ + isEditable, + options, + onChange, +}) => { function addOption() { onChange([ ...options, @@ -37,15 +42,20 @@ const EditMode: React.FC = ({ options, onChange }) => { key={idx} option={option} onChange={updatedOption => updateOption(idx, updatedOption)} + isEditable={isEditable} /> {idx !== options.length - 1 && } ))} - - - - + {isEditable && ( + <> + + + + + + )} ); }; diff --git a/src/components/Guilds/ActionsBuilder/Option/EditMode.tsx b/src/components/Guilds/ActionsBuilder/Option/EditMode.tsx index 6cf3e733dc..40abd7971d 100644 --- a/src/components/Guilds/ActionsBuilder/Option/EditMode.tsx +++ b/src/components/Guilds/ActionsBuilder/Option/EditMode.tsx @@ -1,3 +1,4 @@ +import styled from 'styled-components'; import { ProposalOptionTag } from '../common/ProposalOptionTag'; import AddButton from '../common/AddButton'; import ActionEditor from '../Action/EditMode'; @@ -8,13 +9,23 @@ import ActionModal from 'components/Guilds/ActionsModal'; import Grip from '../common/Grip'; import DataTag from '../common/DataTag'; import EditButton from '../common/EditButton'; +import ActionView from '../Action/ViewMode'; + +const ActionsWrapper = styled.div` + margin-left: ${({ indented }) => (indented ? '1.75rem' : '0')}; +`; interface OptionRowProps { option: Option; + isEditable?: boolean; onChange?: (updatedOption: Option) => void; } -const OptionEditMode: React.FC = ({ option, onChange }) => { +const OptionEditMode: React.FC = ({ + isEditable, + option, + onChange, +}) => { const [isActionsModalOpen, setIsActionsModalOpen] = useState(false); function addAction(action: DecodedAction) { @@ -35,9 +46,11 @@ const OptionEditMode: React.FC = ({ option, onChange }) => {
- - - + {isEditable && ( + + + + )} @@ -48,23 +61,34 @@ const OptionEditMode: React.FC = ({ option, onChange }) => {
-
- Edit -
+ {isEditable && ( +
+ Edit +
+ )}
- {option?.decodedActions?.map((action, index) => ( - updateAction(index, updatedAction)} - /> - ))} + + {option?.actions?.map((action, index) => ( + + ))} + - setIsActionsModalOpen(true)} - /> + {isEditable && + option?.decodedActions?.map((action, index) => ( + updateAction(index, updatedAction)} + /> + ))} + + {isEditable && ( + setIsActionsModalOpen(true)} + /> + )} = ({ options, onChange, }) => { - const [actionsEditMode, setActionsEditMode] = useState(editable); + const [isEditable, setIsEditable] = useState(editable); - const onEdit = () => setActionsEditMode(true); + const onEdit = () => setIsEditable(true); const onSave = () => { const encodedOptions = bulkEncodeCallsFromOptions(options); onChange(encodedOptions); - setActionsEditMode(false); + setIsEditable(false); }; return ( @@ -35,22 +34,16 @@ export const ActionsBuilder: React.FC = ({ header={ Actions - {editable && ( - (actionsEditMode ? onSave() : onEdit())} - > - {actionsEditMode ? 'Save' : 'Edit'} - - )} + (isEditable ? onSave() : onEdit())} + > + {isEditable ? 'Save' : 'Edit'} + } > - {actionsEditMode ? ( - - ) : ( - - )} + ); }; From 982cb4109c84ef69d126b496a19f1e7ce3db1406 Mon Sep 17 00:00:00 2001 From: Madusha Prasanjith Date: Wed, 6 Apr 2022 01:01:12 +0530 Subject: [PATCH 4/6] feat: Implement the new action buidler workflow. --- .../Guilds/ActionsBuilder/Action/EditMode.tsx | 33 ++++++++++------- .../Guilds/ActionsBuilder/Action/ViewMode.tsx | 22 +++++++---- .../Guilds/ActionsBuilder/Option/EditMode.tsx | 37 ++++++++++--------- .../ERC20Transfer/ERC20TransferEditor.tsx | 5 +-- .../ERC20Transfer/ERC20TransferInfoLine.tsx | 19 +++++----- .../ERC20Transfer/ERC20TransferSummary.tsx | 13 +++---- .../ERC20Transfer/Transfer/index.tsx | 24 ++++++------ .../ActionsBuilder/SupportedActions/index.tsx | 19 +++++----- src/components/Guilds/ActionsModal/index.tsx | 37 ++++++++++++++++--- .../Guilds/contracts/useContractInterface.ts | 9 +++++ src/hooks/Guilds/contracts/useDecodedCall.ts | 4 +- 11 files changed, 134 insertions(+), 88 deletions(-) create mode 100644 src/hooks/Guilds/contracts/useContractInterface.ts diff --git a/src/components/Guilds/ActionsBuilder/Action/EditMode.tsx b/src/components/Guilds/ActionsBuilder/Action/EditMode.tsx index 57abe5084f..979a58c7ad 100644 --- a/src/components/Guilds/ActionsBuilder/Action/EditMode.tsx +++ b/src/components/Guilds/ActionsBuilder/Action/EditMode.tsx @@ -1,25 +1,30 @@ -import { getEditor } from '../SupportedActions'; -import { DecodedAction, DecodedCall } from '../types'; +// import { getEditor } from '../SupportedActions'; +// import { DecodedAction, DecodedCall } from '../types'; + +import { DecodedAction } from '../types'; +import ActionView from './ViewMode'; interface ActionEditorProps { action: DecodedAction; onChange: (updatedCall: DecodedAction) => void; } -const ActionEditor: React.FC = ({ action, onChange }) => { - const Editor = getEditor(action?.decodedCall?.callType); +const ActionEditor: React.FC = ({ action }) => { + // const Editor = getEditor(action?.decodedCall?.callType); + + // const updateCall = (updatedCall: DecodedCall) => { + // onChange({ ...action, decodedCall: updatedCall }); + // }; - const updateCall = (updatedCall: DecodedCall) => { - onChange({ ...action, decodedCall: updatedCall }); - }; + return ; - return ( - - ); + // return ( + // + // ); }; export default ActionEditor; diff --git a/src/components/Guilds/ActionsBuilder/Action/ViewMode.tsx b/src/components/Guilds/ActionsBuilder/Action/ViewMode.tsx index 17f5070947..a228a87214 100644 --- a/src/components/Guilds/ActionsBuilder/Action/ViewMode.tsx +++ b/src/components/Guilds/ActionsBuilder/Action/ViewMode.tsx @@ -7,7 +7,7 @@ import { Button } from 'components/Guilds/common/Button'; import { useDecodedCall } from 'hooks/Guilds/contracts/useDecodedCall'; import { getInfoLineView, getSummaryView } from '../SupportedActions'; import CallDetails from '../CallDetails'; -import { Call } from '../types'; +import { Call, DecodedCall } from '../types'; import Grip from '../common/Grip'; import EditButton from '../common/EditButton'; @@ -81,12 +81,20 @@ const CardActions = styled.div` `; interface ActionViewProps { - call: Call; + call?: Call; + decodedCall?: DecodedCall; isEditable?: boolean; + onEdit?: () => void; } -const ActionView: React.FC = ({ call, isEditable }) => { - const { decodedCall } = useDecodedCall(call); +const ActionView: React.FC = ({ + call, + decodedCall: decodedCallFromProps, + isEditable, +}) => { + const { decodedCall: decodedCallFromCall } = useDecodedCall(call); + + const decodedCall = decodedCallFromCall || decodedCallFromProps; const [expanded, setExpanded] = useState(false); const [activeTab, setActiveTab] = useState(0); @@ -101,7 +109,7 @@ const ActionView: React.FC = ({ call, isEditable }) => { {isEditable && } - {InfoLine && } + {InfoLine && } {isEditable && Edit} @@ -137,13 +145,13 @@ const ActionView: React.FC = ({ call, isEditable }) => { {ActionSummary && activeTab === 0 && ( - + )} {(!ActionSummary || activeTab === 1) && ( - + )} diff --git a/src/components/Guilds/ActionsBuilder/Option/EditMode.tsx b/src/components/Guilds/ActionsBuilder/Option/EditMode.tsx index 40abd7971d..5850e2f275 100644 --- a/src/components/Guilds/ActionsBuilder/Option/EditMode.tsx +++ b/src/components/Guilds/ActionsBuilder/Option/EditMode.tsx @@ -69,26 +69,27 @@ const OptionEditMode: React.FC = ({ - {option?.actions?.map((action, index) => ( - - ))} - + {!isEditable && + option?.actions?.map((action, index) => ( + + ))} - {isEditable && - option?.decodedActions?.map((action, index) => ( - updateAction(index, updatedAction)} - /> - ))} + {isEditable && + option?.decodedActions?.map((action, index) => ( + updateAction(index, updatedAction)} + /> + ))} - {isEditable && ( - setIsActionsModalOpen(true)} - /> - )} + {isEditable && ( + setIsActionsModalOpen(true)} + /> + )} + = ({ - call, - contract, + decodedCall, updateCall, }) => { return ( @@ -24,7 +23,7 @@ const ERC20TransferEditor: React.FC = ({ Transfers & Mint - + diff --git a/src/components/Guilds/ActionsBuilder/SupportedActions/ERC20Transfer/ERC20TransferInfoLine.tsx b/src/components/Guilds/ActionsBuilder/SupportedActions/ERC20Transfer/ERC20TransferInfoLine.tsx index 4f3e4476ca..2940510a05 100644 --- a/src/components/Guilds/ActionsBuilder/SupportedActions/ERC20Transfer/ERC20TransferInfoLine.tsx +++ b/src/components/Guilds/ActionsBuilder/SupportedActions/ERC20Transfer/ERC20TransferInfoLine.tsx @@ -9,20 +9,17 @@ import { MAINNET_ID, shortenAddress } from 'utils'; import { ActionViewProps } from '..'; import { Segment } from '../common/infoLine'; -const ERC20TransferInfoLine: React.FC = ({ - call, - decodedCall, -}) => { +const ERC20TransferInfoLine: React.FC = ({ decodedCall }) => { const parsedData = useMemo(() => { - if (!call || !decodedCall) return null; + if (!decodedCall) return null; return { - tokenAddress: call.to, + tokenAddress: decodedCall.to, amount: BigNumber.from(decodedCall.args._value), - source: call.from, + source: decodedCall.from, destination: decodedCall.args._to as string, }; - }, [call, decodedCall]); + }, [decodedCall]); const { data: tokenInfo } = useERC20Info(parsedData?.tokenAddress); const roundedBalance = useBigNumberToNumber( @@ -53,7 +50,11 @@ const ERC20TransferInfoLine: React.FC = ({ size={24} /> - {ensName || shortenAddress(parsedData?.destination)} + + {ensName || parsedData?.destination + ? shortenAddress(parsedData?.destination) + : ''} + ); }; diff --git a/src/components/Guilds/ActionsBuilder/SupportedActions/ERC20Transfer/ERC20TransferSummary.tsx b/src/components/Guilds/ActionsBuilder/SupportedActions/ERC20Transfer/ERC20TransferSummary.tsx index 19ee32aa69..ef30547a22 100644 --- a/src/components/Guilds/ActionsBuilder/SupportedActions/ERC20Transfer/ERC20TransferSummary.tsx +++ b/src/components/Guilds/ActionsBuilder/SupportedActions/ERC20Transfer/ERC20TransferSummary.tsx @@ -9,20 +9,17 @@ import { ActionViewProps } from '..'; import { Segment } from '../common/infoLine'; import { DetailCell, DetailHeader, DetailRow } from '../common/summary'; -const ERC20TransferSummary: React.FC = ({ - call, - decodedCall, -}) => { +const ERC20TransferSummary: React.FC = ({ decodedCall }) => { const parsedData = useMemo(() => { - if (!call || !decodedCall) return null; + if (!decodedCall) return null; return { - tokenAddress: call.to, + tokenAddress: decodedCall.to, amount: BigNumber.from(decodedCall.args._value), - source: call.from, + source: decodedCall.from, destination: decodedCall.args._to, }; - }, [call, decodedCall]); + }, [decodedCall]); const { data: tokenInfo } = useERC20Info(parsedData?.tokenAddress); const roundedBalance = useBigNumberToNumber( diff --git a/src/components/Guilds/ActionsBuilder/SupportedActions/ERC20Transfer/Transfer/index.tsx b/src/components/Guilds/ActionsBuilder/SupportedActions/ERC20Transfer/Transfer/index.tsx index ec581d0ea2..1d120c15a1 100644 --- a/src/components/Guilds/ActionsBuilder/SupportedActions/ERC20Transfer/Transfer/index.tsx +++ b/src/components/Guilds/ActionsBuilder/SupportedActions/ERC20Transfer/Transfer/index.tsx @@ -74,22 +74,22 @@ interface TransferState { destination: string; } -const Transfer: React.FC = ({ call, updateCall }) => { +const Transfer: React.FC = ({ decodedCall, updateCall }) => { const [isTokenPickerOpen, setIsTokenPickerOpen] = useState(false); const { chainId } = useWeb3React(); // parse transfer state from calls const parsedData = useMemo(() => { - if (!call) return null; + if (!decodedCall) return null; return { - source: call.from, - tokenAddress: call.to, - amount: call.args._value, - destination: call.args._to, + source: decodedCall.from, + tokenAddress: decodedCall.to, + amount: decodedCall.args._value, + destination: decodedCall.args._to, }; - }, [call]); + }, [decodedCall]); const validations = useMemo(() => { return { @@ -120,9 +120,9 @@ const Transfer: React.FC = ({ call, updateCall }) => { const setTransferAddress = (walletAddress: string) => { updateCall({ - ...call, + ...decodedCall, args: { - ...call.args, + ...decodedCall.args, _to: walletAddress, }, }); @@ -130,7 +130,7 @@ const Transfer: React.FC = ({ call, updateCall }) => { const setToken = (tokenAddress: string) => { updateCall({ - ...call, + ...decodedCall, to: tokenAddress, }); }; @@ -140,9 +140,9 @@ const Transfer: React.FC = ({ call, updateCall }) => { ? utils.parseUnits(value, tokenInfo?.decimals || 18) : null; updateCall({ - ...call, + ...decodedCall, args: { - ...call.args, + ...decodedCall.args, _value: amount, }, }); diff --git a/src/components/Guilds/ActionsBuilder/SupportedActions/index.tsx b/src/components/Guilds/ActionsBuilder/SupportedActions/index.tsx index effcf97efa..373736d632 100644 --- a/src/components/Guilds/ActionsBuilder/SupportedActions/index.tsx +++ b/src/components/Guilds/ActionsBuilder/SupportedActions/index.tsx @@ -1,19 +1,20 @@ import { BigNumber, utils } from 'ethers'; import { DeepPartial, RequireAtLeastOne } from 'utils/types'; -import { Call, DecodedAction, DecodedCall, SupportedAction } from '../types'; +import { DecodedAction, DecodedCall, SupportedAction } from '../types'; import ERC20ABI from '../../../../abis/ERC20.json'; import ERC20TransferEditor from './ERC20Transfer/ERC20TransferEditor'; import ERC20TransferInfoLine from './ERC20Transfer/ERC20TransferInfoLine'; import ERC20TransferSummary from './ERC20Transfer/ERC20TransferSummary'; +export interface SupportedActionMetadata { + title: string; +} export interface ActionViewProps { - call: Call; decodedCall: DecodedCall; } export interface ActionEditorProps { - contract: utils.Interface; - call: DecodedCall; + decodedCall: DecodedCall; updateCall: (updatedCall: DecodedCall) => void; } @@ -23,35 +24,33 @@ type SupportedActionViews = { }; type SupportedActionEditors = RequireAtLeastOne<{ - bulkEditor?: React.FC; editor?: React.FC; }>; export const supportedActions: Record< SupportedAction, - SupportedActionViews & SupportedActionEditors + SupportedActionViews & SupportedActionEditors & SupportedActionMetadata > = { [SupportedAction.ERC20_TRANSFER]: { + title: 'Transfers & Mint', infoLineView: ERC20TransferInfoLine, summaryView: ERC20TransferSummary, editor: ERC20TransferEditor, }, [SupportedAction.GENERIC_CALL]: { + title: 'Generic Call', infoLineView: () =>
Generic Call
, editor: () =>
Generic Call Editor
, }, }; -let ERC20Contract = new utils.Interface(ERC20ABI); - export const defaultValues: Record< SupportedAction, DeepPartial > = { [SupportedAction.ERC20_TRANSFER]: { - contract: ERC20Contract, decodedCall: { - function: ERC20Contract.getFunction('transfer'), + function: new utils.Interface(ERC20ABI).getFunction('transfer'), to: '', value: BigNumber.from(0), args: { diff --git a/src/components/Guilds/ActionsModal/index.tsx b/src/components/Guilds/ActionsModal/index.tsx index d00f02a0d9..810a32608b 100644 --- a/src/components/Guilds/ActionsModal/index.tsx +++ b/src/components/Guilds/ActionsModal/index.tsx @@ -1,8 +1,16 @@ import { RegistryContract } from 'hooks/Guilds/contracts/useContractRegistry'; import React, { useState } from 'react'; import { useParams } from 'react-router-dom'; -import { defaultValues } from '../ActionsBuilder/SupportedActions'; -import { DecodedAction, SupportedAction } from '../ActionsBuilder/types'; +import { + defaultValues, + getEditor, + supportedActions, +} from '../ActionsBuilder/SupportedActions'; +import { + DecodedAction, + DecodedCall, + SupportedAction, +} from '../ActionsBuilder/types'; import { Modal } from '../common/Modal'; import ContractActionsList from './ContractActionsList'; import ContractsList from './ContractsList'; @@ -20,10 +28,13 @@ const ActionModal: React.FC = ({ }) => { const { guild_id: guildId } = useParams<{ guild_id?: string }>(); + const [selectedAction, setSelectedAction] = useState(null); const [selectedContract, setSelectedContract] = useState(null); const [selectedFunction, setSelectedFunction] = useState(null); + const [data, setData] = useState(null); + function getHeader() { if (selectedFunction) { return selectedContract.functions.find( @@ -35,6 +46,10 @@ const ActionModal: React.FC = ({ return selectedContract?.title; } + if (selectedAction) { + return supportedActions[selectedAction].title; + } + return 'Add action'; } @@ -52,10 +67,15 @@ const ActionModal: React.FC = ({ ); } + if (selectedAction) { + const Editor = getEditor(selectedAction); + return ; + } + return ( ); } @@ -65,16 +85,21 @@ const ActionModal: React.FC = ({ setSelectedFunction(null); } else if (selectedContract) { setSelectedContract(null); + } else if (selectedAction) { + setSelectedAction(null); } + + setData(null); } - function addSupportedAction(action: SupportedAction) { - const defaultDecodedAction = defaultValues[action]; + function setSupportedAction(action: SupportedAction) { + const defaultDecodedAction = defaultValues[action] as DecodedAction; if (!defaultDecodedAction) return null; defaultDecodedAction.decodedCall.from = guildId; defaultDecodedAction.decodedCall.callType = action; - onAddAction(defaultDecodedAction as DecodedAction); + setData(defaultDecodedAction.decodedCall); + setSelectedAction(action); } return ( diff --git a/src/hooks/Guilds/contracts/useContractInterface.ts b/src/hooks/Guilds/contracts/useContractInterface.ts new file mode 100644 index 0000000000..3353e5d9b6 --- /dev/null +++ b/src/hooks/Guilds/contracts/useContractInterface.ts @@ -0,0 +1,9 @@ +import { utils } from 'ethers'; + +const useContractInterface = (ABI: any) => { + let ERC20Contract = new utils.Interface(ABI); + + return ERC20Contract; +}; + +export default useContractInterface; diff --git a/src/hooks/Guilds/contracts/useDecodedCall.ts b/src/hooks/Guilds/contracts/useDecodedCall.ts index 92a90ca805..5cbf224b72 100644 --- a/src/hooks/Guilds/contracts/useDecodedCall.ts +++ b/src/hooks/Guilds/contracts/useDecodedCall.ts @@ -143,5 +143,7 @@ export const useDecodedCall = (call: Call) => { const { chainId } = useWeb3React(); const { contracts } = useContractRegistry(); - return decodeCall(call, contracts, chainId); + return call + ? decodeCall(call, contracts, chainId) + : { decodedCall: null, contract: null }; }; From 5860826045cf4a94fc88a55829de0b4240199457 Mon Sep 17 00:00:00 2001 From: Madusha Prasanjith Date: Wed, 6 Apr 2022 01:47:06 +0530 Subject: [PATCH 5/6] feat: Get ERC20 Transfer widget working again. --- .../Guilds/ActionsBuilder/Action/EditMode.tsx | 17 -- .../ERC20Transfer/ERC20TransferEditor.tsx | 243 ++++++++++++++--- .../ERC20Transfer/Transfer/index.tsx | 244 ------------------ .../SupportedActions/common/editor.tsx | 34 --- .../ActionsBuilder/SupportedActions/index.tsx | 5 +- src/components/Guilds/ActionsModal/index.tsx | 40 ++- 6 files changed, 256 insertions(+), 327 deletions(-) delete mode 100644 src/components/Guilds/ActionsBuilder/SupportedActions/ERC20Transfer/Transfer/index.tsx delete mode 100644 src/components/Guilds/ActionsBuilder/SupportedActions/common/editor.tsx diff --git a/src/components/Guilds/ActionsBuilder/Action/EditMode.tsx b/src/components/Guilds/ActionsBuilder/Action/EditMode.tsx index 979a58c7ad..e2d2577f48 100644 --- a/src/components/Guilds/ActionsBuilder/Action/EditMode.tsx +++ b/src/components/Guilds/ActionsBuilder/Action/EditMode.tsx @@ -1,6 +1,3 @@ -// import { getEditor } from '../SupportedActions'; -// import { DecodedAction, DecodedCall } from '../types'; - import { DecodedAction } from '../types'; import ActionView from './ViewMode'; @@ -10,21 +7,7 @@ interface ActionEditorProps { } const ActionEditor: React.FC = ({ action }) => { - // const Editor = getEditor(action?.decodedCall?.callType); - - // const updateCall = (updatedCall: DecodedCall) => { - // onChange({ ...action, decodedCall: updatedCall }); - // }; - return ; - - // return ( - // - // ); }; export default ActionEditor; diff --git a/src/components/Guilds/ActionsBuilder/SupportedActions/ERC20Transfer/ERC20TransferEditor.tsx b/src/components/Guilds/ActionsBuilder/SupportedActions/ERC20Transfer/ERC20TransferEditor.tsx index 788acd5d7b..81d0c30e44 100644 --- a/src/components/Guilds/ActionsBuilder/SupportedActions/ERC20Transfer/ERC20TransferEditor.tsx +++ b/src/components/Guilds/ActionsBuilder/SupportedActions/ERC20Transfer/ERC20TransferEditor.tsx @@ -1,35 +1,220 @@ -import { FiNavigation } from 'react-icons/fi'; -import { - EditorWrapper, - FooterWrapper, - HeaderWrapper, - IconWrapper, - TitleWrapper, -} from '../common/editor'; +import styled from 'styled-components'; +import { Input } from 'components/Guilds/common/Form/Input'; +import { FiChevronDown, FiX } from 'react-icons/fi'; +import Avatar from 'components/Guilds/Avatar'; +import { resolveUri } from 'utils/url'; +import { useWeb3React } from '@web3-react/core'; +import { useTokenList } from 'hooks/Guilds/tokens/useTokenList'; +import { useMemo, useState } from 'react'; import { ActionEditorProps } from '..'; -import Transfer from './Transfer'; -import AddButton from '../../common/AddButton'; +import { BigNumber, utils } from 'ethers'; +import { useERC20Info } from 'hooks/Guilds/ether-swr/erc20/useERC20Info'; +import useBigNumberToNumber from 'hooks/Guilds/conversions/useBigNumberToNumber'; +import useENSAvatar from 'hooks/Guilds/ether-swr/ens/useENSAvatar'; +import TokenPicker from 'components/Guilds/TokenPicker'; +import { Box } from 'components/Guilds/common/Layout'; +import { MAINNET_ID } from 'utils'; +import NumericalInput from 'components/Guilds/common/Form/NumericalInput'; +import { baseInputStyles } from 'components/Guilds/common/Form/Input'; + +const Control = styled(Box)` + display: flex; + flex-direction: column; + margin: 0.75rem 0; + width: 100%; +`; + +const ControlLabel = styled(Box)` + margin-bottom: 0.75rem; +`; + +const ControlRow = styled(Box)` + display: flex; + align-items: stretch; + height: 100%; +`; + +const Spacer = styled(Box)` + margin-right: 1rem; +`; + +const ClickableIcon = styled(Box)` + display: flex; + align-items: center; + cursor: pointer; +`; + +const TransferAmountInput = styled(NumericalInput)` + ${baseInputStyles} + display: flex; + align-items: center; + width: 100%; + &:hover, + &:focus { + border: 0.1rem solid ${({ theme }) => theme.colors.text}; + } +`; + +interface TransferState { + source: string; + tokenAddress: string; + amount: BigNumber; + destination: string; +} + +const Transfer: React.FC = ({ decodedCall, updateCall }) => { + const [isTokenPickerOpen, setIsTokenPickerOpen] = useState(false); + + const { chainId } = useWeb3React(); + + // parse transfer state from calls + const parsedData = useMemo(() => { + if (!decodedCall) return null; + + return { + source: decodedCall.from, + tokenAddress: decodedCall.to, + amount: decodedCall.args._value, + destination: decodedCall.args._to, + }; + }, [decodedCall]); + + const validations = useMemo(() => { + return { + tokenAddress: utils.isAddress(parsedData?.tokenAddress), + amount: BigNumber.isBigNumber(parsedData?.amount), + destination: utils.isAddress(parsedData?.destination), + }; + }, [parsedData]); + + // Get token details from the token address + const { tokens } = useTokenList(chainId); + const token = useMemo(() => { + if (!parsedData?.tokenAddress || !tokens) return null; + + return tokens.find(({ address }) => address === parsedData.tokenAddress); + }, [tokens, parsedData]); + + const { data: tokenInfo } = useERC20Info(parsedData?.tokenAddress); + const roundedBalance = useBigNumberToNumber( + parsedData?.amount, + tokenInfo?.decimals, + 10 + ); + const { imageUrl: destinationAvatarUrl } = useENSAvatar( + parsedData?.destination, + MAINNET_ID + ); + + const setTransferAddress = (walletAddress: string) => { + updateCall({ + ...decodedCall, + args: { + ...decodedCall.args, + _to: walletAddress, + }, + }); + }; + + const setToken = (tokenAddress: string) => { + updateCall({ + ...decodedCall, + to: tokenAddress, + }); + }; + + const setAmount = (value: string) => { + const amount = value + ? utils.parseUnits(value, tokenInfo?.decimals || 18) + : null; + updateCall({ + ...decodedCall, + args: { + ...decodedCall.args, + _value: amount, + }, + }); + }; -const ERC20TransferEditor: React.FC = ({ - decodedCall, - updateCall, -}) => { return ( - - - - - - Transfers & Mint - - - - - - - - +
+ + Recipient + + + {validations.destination && ( + + )} +
+ } + iconRight={ + parsedData?.destination ? ( + setTransferAddress('')}> + + + ) : null + } + placeholder="Ethereum address" + onChange={e => setTransferAddress(e.target.value)} + /> + + + + + + Amount + + + + + + + + + Asset + setIsTokenPickerOpen(true)}> + + {parsedData?.tokenAddress && ( + + )} + + } + iconRight={} + readOnly + /> + + + + + setIsTokenPickerOpen(false)} + onSelect={tokenAddress => { + setToken(tokenAddress); + setIsTokenPickerOpen(false); + }} + /> + ); }; -export default ERC20TransferEditor; +export default Transfer; diff --git a/src/components/Guilds/ActionsBuilder/SupportedActions/ERC20Transfer/Transfer/index.tsx b/src/components/Guilds/ActionsBuilder/SupportedActions/ERC20Transfer/Transfer/index.tsx deleted file mode 100644 index 1d120c15a1..0000000000 --- a/src/components/Guilds/ActionsBuilder/SupportedActions/ERC20Transfer/Transfer/index.tsx +++ /dev/null @@ -1,244 +0,0 @@ -import styled from 'styled-components'; -import { Input } from 'components/Guilds/common/Form/Input'; -import { FiChevronDown, FiMoreHorizontal, FiX } from 'react-icons/fi'; -import { DetailWrapper } from '../../common/editor'; -import Avatar from 'components/Guilds/Avatar'; -import { resolveUri } from 'utils/url'; -import { useWeb3React } from '@web3-react/core'; -import { useTokenList } from 'hooks/Guilds/tokens/useTokenList'; -import { useMemo, useState } from 'react'; -import { ActionEditorProps } from '../..'; -import { BigNumber, utils } from 'ethers'; -import { useERC20Info } from 'hooks/Guilds/ether-swr/erc20/useERC20Info'; -import useBigNumberToNumber from 'hooks/Guilds/conversions/useBigNumberToNumber'; -import useENSAvatar from 'hooks/Guilds/ether-swr/ens/useENSAvatar'; -import TokenPicker from 'components/Guilds/TokenPicker'; -import { Box } from 'components/Guilds/common/Layout'; -import { Button } from 'components/Guilds/common/Button'; -import { MAINNET_ID } from 'utils'; -import NumericalInput from 'components/Guilds/common/Form/NumericalInput'; -import { baseInputStyles } from 'components/Guilds/common/Form/Input'; - -const Control = styled(Box)` - display: flex; - flex-direction: column; - margin: 0.75rem 0; - width: 100%; -`; - -const ControlLabel = styled(Box)` - margin-bottom: 0.75rem; -`; - -const ControlRow = styled(Box)` - display: flex; - align-items: stretch; - height: 100%; -`; - -const Spacer = styled(Box)` - margin-right: 1rem; -`; - -const MenuButton = styled(Button).attrs(() => ({ - variant: 'secondary', -}))` - border-radius: 50%; - height: 2.7rem; - width: 2.7rem; - padding: 0; - margin: 0; -`; - -const ClickableIcon = styled(Box)` - display: flex; - align-items: center; - cursor: pointer; -`; - -const TransferAmountInput = styled(NumericalInput)` - ${baseInputStyles} - display: flex; - align-items: center; - width: 100%; - &:hover, - &:focus { - border: 0.1rem solid ${({ theme }) => theme.colors.text}; - } -`; - -interface TransferState { - source: string; - tokenAddress: string; - amount: BigNumber; - destination: string; -} - -const Transfer: React.FC = ({ decodedCall, updateCall }) => { - const [isTokenPickerOpen, setIsTokenPickerOpen] = useState(false); - - const { chainId } = useWeb3React(); - - // parse transfer state from calls - const parsedData = useMemo(() => { - if (!decodedCall) return null; - - return { - source: decodedCall.from, - tokenAddress: decodedCall.to, - amount: decodedCall.args._value, - destination: decodedCall.args._to, - }; - }, [decodedCall]); - - const validations = useMemo(() => { - return { - tokenAddress: utils.isAddress(parsedData?.tokenAddress), - amount: BigNumber.isBigNumber(parsedData?.amount), - destination: utils.isAddress(parsedData?.destination), - }; - }, [parsedData]); - - // Get token details from the token address - const { tokens } = useTokenList(chainId); - const token = useMemo(() => { - if (!parsedData?.tokenAddress || !tokens) return null; - - return tokens.find(({ address }) => address === parsedData.tokenAddress); - }, [tokens, parsedData]); - - const { data: tokenInfo } = useERC20Info(parsedData?.tokenAddress); - const roundedBalance = useBigNumberToNumber( - parsedData?.amount, - tokenInfo?.decimals, - 10 - ); - const { imageUrl: destinationAvatarUrl } = useENSAvatar( - parsedData?.destination, - MAINNET_ID - ); - - const setTransferAddress = (walletAddress: string) => { - updateCall({ - ...decodedCall, - args: { - ...decodedCall.args, - _to: walletAddress, - }, - }); - }; - - const setToken = (tokenAddress: string) => { - updateCall({ - ...decodedCall, - to: tokenAddress, - }); - }; - - const setAmount = (value: string) => { - const amount = value - ? utils.parseUnits(value, tokenInfo?.decimals || 18) - : null; - updateCall({ - ...decodedCall, - args: { - ...decodedCall.args, - _value: amount, - }, - }); - }; - - return ( - - - Recipient - - - {validations.destination && ( - - )} - - } - iconRight={ - parsedData?.destination ? ( - setTransferAddress('')}> - - - ) : null - } - placeholder="Ethereum address" - onChange={e => setTransferAddress(e.target.value)} - /> - -
- - - -
-
-
- - - - Asset - setIsTokenPickerOpen(true)}> - - {parsedData?.tokenAddress && ( - - )} - - } - iconRight={} - readOnly - /> - - - - - - - Amount - - - -
- - - -
-
-
-
- - setIsTokenPickerOpen(false)} - onSelect={tokenAddress => { - setToken(tokenAddress); - setIsTokenPickerOpen(false); - }} - /> -
- ); -}; - -export default Transfer; diff --git a/src/components/Guilds/ActionsBuilder/SupportedActions/common/editor.tsx b/src/components/Guilds/ActionsBuilder/SupportedActions/common/editor.tsx deleted file mode 100644 index 1d72dbcde4..0000000000 --- a/src/components/Guilds/ActionsBuilder/SupportedActions/common/editor.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { CardWrapper, Header } from 'components/Guilds/common/Card'; -import { Box } from 'components/Guilds/common/Layout'; -import styled from 'styled-components'; - -export const EditorWrapper = styled(CardWrapper)` - margin: 0.8rem 0; -`; - -export const HeaderWrapper = styled(Header)` - display: flex; - align-items: center; - margin: 0.875rem; -`; - -export const IconWrapper = styled.span` - display: flex; - margin-right: 0.875rem; -`; - -export const TitleWrapper = styled(Box)` - font-size: ${({ theme }) => theme.fontSizes.body}; - font-weight: ${({ theme }) => theme.fontWeights.medium}; -`; - -export const DetailWrapper = styled(Box)` - color: ${({ theme }) => theme.colors.proposalText.grey}; - padding: 1.25rem; - border-top: 1px solid ${({ theme }) => theme.colors.border.initial}; -`; - -export const FooterWrapper = styled(DetailWrapper)` - color: ${({ theme }) => theme.colors.text}; - padding: 0.75rem 1.25rem; -`; diff --git a/src/components/Guilds/ActionsBuilder/SupportedActions/index.tsx b/src/components/Guilds/ActionsBuilder/SupportedActions/index.tsx index 373736d632..a8c0930f37 100644 --- a/src/components/Guilds/ActionsBuilder/SupportedActions/index.tsx +++ b/src/components/Guilds/ActionsBuilder/SupportedActions/index.tsx @@ -44,13 +44,16 @@ export const supportedActions: Record< }, }; +const ERC20Contract = new utils.Interface(ERC20ABI); + export const defaultValues: Record< SupportedAction, DeepPartial > = { [SupportedAction.ERC20_TRANSFER]: { + contract: ERC20Contract, decodedCall: { - function: new utils.Interface(ERC20ABI).getFunction('transfer'), + function: ERC20Contract.getFunction('transfer'), to: '', value: BigNumber.from(0), args: { diff --git a/src/components/Guilds/ActionsModal/index.tsx b/src/components/Guilds/ActionsModal/index.tsx index 810a32608b..056f58ccae 100644 --- a/src/components/Guilds/ActionsModal/index.tsx +++ b/src/components/Guilds/ActionsModal/index.tsx @@ -1,6 +1,8 @@ +import { utils } from 'ethers'; import { RegistryContract } from 'hooks/Guilds/contracts/useContractRegistry'; import React, { useState } from 'react'; import { useParams } from 'react-router-dom'; +import styled from 'styled-components'; import { defaultValues, getEditor, @@ -11,10 +13,20 @@ import { DecodedCall, SupportedAction, } from '../ActionsBuilder/types'; +import { Button } from '../common/Button'; import { Modal } from '../common/Modal'; import ContractActionsList from './ContractActionsList'; import ContractsList from './ContractsList'; +export const EditorWrapper = styled.div` + margin: 1.25rem; +`; + +export const BlockButton = styled(Button)` + margin-top: 1rem; + width: 100%; +`; + interface ActionModalProps { isOpen: boolean; setIsOpen: (isOpen: boolean) => void; @@ -28,7 +40,12 @@ const ActionModal: React.FC = ({ }) => { const { guild_id: guildId } = useParams<{ guild_id?: string }>(); + // Supported Actions const [selectedAction, setSelectedAction] = useState(null); + const [selectedActionContract, setSelectedActionContract] = + useState(null); + + // Generic calls const [selectedContract, setSelectedContract] = useState(null); const [selectedFunction, setSelectedFunction] = useState(null); @@ -69,7 +86,12 @@ const ActionModal: React.FC = ({ if (selectedAction) { const Editor = getEditor(selectedAction); - return ; + return ( + + + Save Action + + ); } return ( @@ -87,6 +109,7 @@ const ActionModal: React.FC = ({ setSelectedContract(null); } else if (selectedAction) { setSelectedAction(null); + setSelectedActionContract(null); } setData(null); @@ -100,6 +123,19 @@ const ActionModal: React.FC = ({ defaultDecodedAction.decodedCall.callType = action; setData(defaultDecodedAction.decodedCall); setSelectedAction(action); + setSelectedActionContract(defaultDecodedAction.contract); + } + + function saveSupportedAction() { + if (!selectedAction || !data || !setSelectedActionContract) return; + + const decodedAction: DecodedAction = { + decodedCall: data, + contract: selectedActionContract, + }; + + onAddAction(decodedAction); + setIsOpen(false); } return ( @@ -108,7 +144,7 @@ const ActionModal: React.FC = ({ onDismiss={() => setIsOpen(false)} header={getHeader()} maxWidth={300} - backnCross={!!selectedContract} + backnCross={!!selectedAction || !!selectedContract} prevContent={goBack} > {getContent()} From 4fd3dfc06a151b5544a56d5d5d6be4884bed4a70 Mon Sep 17 00:00:00 2001 From: Madusha Prasanjith Date: Wed, 6 Apr 2022 02:51:17 +0530 Subject: [PATCH 6/6] refactor: Simplify action builder code. --- .../{Option/EditMode.tsx => Option.tsx} | 38 ++++++++++---- .../Guilds/ActionsBuilder/Option/ViewMode.tsx | 50 ------------------- .../Guilds/ActionsBuilder/Option/styles.tsx | 18 ------- .../{EditMode.tsx => OptionsList.tsx} | 10 ++-- .../ERC20Transfer/ERC20TransferEditor.tsx | 2 +- .../Guilds/ActionsBuilder/ViewMode.tsx | 22 -------- .../Guilds/ActionsBuilder/index.tsx | 22 +++++--- 7 files changed, 47 insertions(+), 115 deletions(-) rename src/components/Guilds/ActionsBuilder/{Option/EditMode.tsx => Option.tsx} (72%) delete mode 100644 src/components/Guilds/ActionsBuilder/Option/ViewMode.tsx delete mode 100644 src/components/Guilds/ActionsBuilder/Option/styles.tsx rename src/components/Guilds/ActionsBuilder/{EditMode.tsx => OptionsList.tsx} (84%) delete mode 100644 src/components/Guilds/ActionsBuilder/ViewMode.tsx diff --git a/src/components/Guilds/ActionsBuilder/Option/EditMode.tsx b/src/components/Guilds/ActionsBuilder/Option.tsx similarity index 72% rename from src/components/Guilds/ActionsBuilder/Option/EditMode.tsx rename to src/components/Guilds/ActionsBuilder/Option.tsx index 5850e2f275..a856484037 100644 --- a/src/components/Guilds/ActionsBuilder/Option/EditMode.tsx +++ b/src/components/Guilds/ActionsBuilder/Option.tsx @@ -1,15 +1,31 @@ import styled from 'styled-components'; -import { ProposalOptionTag } from '../common/ProposalOptionTag'; -import AddButton from '../common/AddButton'; -import ActionEditor from '../Action/EditMode'; -import { Detail, DetailWrapper, OptionWrapper } from './styles'; -import { DecodedAction, Option } from '../types'; +import { ProposalOptionTag } from './common/ProposalOptionTag'; +import AddButton from './common/AddButton'; +import ActionEditor from './Action/EditMode'; +import { DecodedAction, Option } from './types'; import { useState } from 'react'; import ActionModal from 'components/Guilds/ActionsModal'; -import Grip from '../common/Grip'; -import DataTag from '../common/DataTag'; -import EditButton from '../common/EditButton'; -import ActionView from '../Action/ViewMode'; +import Grip from './common/Grip'; +import DataTag from './common/DataTag'; +import EditButton from './common/EditButton'; +import ActionView from './Action/ViewMode'; +import { Box } from 'components/Guilds/common/Layout'; + +export const OptionWrapper = styled(Box)` + padding: 1rem; +`; + +export const DetailWrapper = styled(Box)` + padding: 0.5rem 0; + display: flex; + flex-direction: row; + justify-content: space-between; +`; + +export const Detail = styled(Box)` + display: inline-flex; + margin-right: 0.75rem; +`; const ActionsWrapper = styled.div` margin-left: ${({ indented }) => (indented ? '1.75rem' : '0')}; @@ -21,7 +37,7 @@ interface OptionRowProps { onChange?: (updatedOption: Option) => void; } -const OptionEditMode: React.FC = ({ +const OptionRow: React.FC = ({ isEditable, option, onChange, @@ -103,4 +119,4 @@ const OptionEditMode: React.FC = ({ ); }; -export default OptionEditMode; +export default OptionRow; diff --git a/src/components/Guilds/ActionsBuilder/Option/ViewMode.tsx b/src/components/Guilds/ActionsBuilder/Option/ViewMode.tsx deleted file mode 100644 index 08e3a0f55c..0000000000 --- a/src/components/Guilds/ActionsBuilder/Option/ViewMode.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import styled from 'styled-components'; -import { ProposalOptionTag } from '../common/ProposalOptionTag'; -import ActionView from '../Action/ViewMode'; -import { Detail, DetailWrapper, OptionWrapper } from './styles'; -import { Option } from '../types'; -import DataTag from '../common/DataTag'; -import Grip from '../common/Grip'; -import EditButton from '../common/EditButton'; - -interface OptionRowProps { - data: Option; -} - -const ActionsWrapper = styled.div` - margin-left: 1.75rem; -`; - -const OptionViewMode: React.FC = ({ data }) => { - return ( - - -
- - - - - - - - - {data?.actions?.length || 'No'} on-chain{' '} - {data?.actions?.length >= 2 ? 'actions' : 'action'} - - -
-
- Edit -
-
- - - {data?.actions?.map((action, index) => ( - - ))} - -
- ); -}; - -export default OptionViewMode; diff --git a/src/components/Guilds/ActionsBuilder/Option/styles.tsx b/src/components/Guilds/ActionsBuilder/Option/styles.tsx deleted file mode 100644 index 2ebd12178a..0000000000 --- a/src/components/Guilds/ActionsBuilder/Option/styles.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import styled from 'styled-components'; -import { Box } from 'components/Guilds/common/Layout'; - -export const OptionWrapper = styled(Box)` - padding: 1rem; -`; - -export const DetailWrapper = styled(Box)` - padding: 0.5rem 0; - display: flex; - flex-direction: row; - justify-content: space-between; -`; - -export const Detail = styled(Box)` - display: inline-flex; - margin-right: 0.75rem; -`; diff --git a/src/components/Guilds/ActionsBuilder/EditMode.tsx b/src/components/Guilds/ActionsBuilder/OptionsList.tsx similarity index 84% rename from src/components/Guilds/ActionsBuilder/EditMode.tsx rename to src/components/Guilds/ActionsBuilder/OptionsList.tsx index 06718f99c6..ee7a8953b9 100644 --- a/src/components/Guilds/ActionsBuilder/EditMode.tsx +++ b/src/components/Guilds/ActionsBuilder/OptionsList.tsx @@ -1,20 +1,20 @@ import styled from 'styled-components'; import { Divider } from '../common/Divider'; import { Box } from '../common/Layout'; -import OptionEditMode from './Option/EditMode'; +import OptionRow from './Option'; import AddButton from './common/AddButton'; import { Option } from './types'; const AddOptionWrapper = styled(Box)` padding: 1rem; `; -interface EditModeProps { +interface OptionsListProps { isEditable: boolean; options: Option[]; onChange: (options: Option[]) => void; } -const EditMode: React.FC = ({ +const OptionsList: React.FC = ({ isEditable, options, onChange, @@ -38,7 +38,7 @@ const EditMode: React.FC = ({ <> {options?.map((option, idx) => ( <> - updateOption(idx, updatedOption)} @@ -60,4 +60,4 @@ const EditMode: React.FC = ({ ); }; -export default EditMode; +export default OptionsList; diff --git a/src/components/Guilds/ActionsBuilder/SupportedActions/ERC20Transfer/ERC20TransferEditor.tsx b/src/components/Guilds/ActionsBuilder/SupportedActions/ERC20Transfer/ERC20TransferEditor.tsx index 81d0c30e44..2e68875941 100644 --- a/src/components/Guilds/ActionsBuilder/SupportedActions/ERC20Transfer/ERC20TransferEditor.tsx +++ b/src/components/Guilds/ActionsBuilder/SupportedActions/ERC20Transfer/ERC20TransferEditor.tsx @@ -172,7 +172,7 @@ const Transfer: React.FC = ({ decodedCall, updateCall }) => { Amount diff --git a/src/components/Guilds/ActionsBuilder/ViewMode.tsx b/src/components/Guilds/ActionsBuilder/ViewMode.tsx deleted file mode 100644 index 87d46d5c09..0000000000 --- a/src/components/Guilds/ActionsBuilder/ViewMode.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { Option } from './types'; -import { Divider } from '../common/Divider'; -import OptionViewMode from './Option/ViewMode'; - -interface ViewModeProps { - options: Option[]; -} - -const ViewMode: React.FC = ({ options }) => { - return ( - <> - {options?.map((option, idx) => ( - <> - - {idx !== options.length - 1 && } - - ))} - - ); -}; - -export default ViewMode; diff --git a/src/components/Guilds/ActionsBuilder/index.tsx b/src/components/Guilds/ActionsBuilder/index.tsx index eb55d3228d..51bbc80295 100644 --- a/src/components/Guilds/ActionsBuilder/index.tsx +++ b/src/components/Guilds/ActionsBuilder/index.tsx @@ -3,7 +3,7 @@ import { Header as CardHeader } from '../common/Card'; import SidebarCard, { SidebarCardHeaderSpaced, } from 'components/Guilds/SidebarCard'; -import EditMode from './EditMode'; +import OptionsList from './OptionsList'; import { Option } from './types'; import { bulkEncodeCallsFromOptions } from 'hooks/Guilds/contracts/useEncodedCall'; import EditButton from './common/EditButton'; @@ -34,16 +34,22 @@ export const ActionsBuilder: React.FC = ({ header={ Actions - (isEditable ? onSave() : onEdit())} - > - {isEditable ? 'Save' : 'Edit'} - + {editable && ( + (isEditable ? onSave() : onEdit())} + > + {isEditable ? 'Save' : 'Edit'} + + )} } > - + ); };