From cd59390a0f0422c00822dfdfdf2ae98a9d95b811 Mon Sep 17 00:00:00 2001 From: Tomas Pulenta Date: Sun, 6 Nov 2022 22:37:33 -0300 Subject: [PATCH] add component for block explorer links --- .../__snapshots__/CallDetails.test.tsx.snap | 122 +++++++++--------- .../UpdateENSContentSummary.tsx | 48 ++----- .../UpdateENSContentSummary.test.tsx.snap | 52 ++++---- .../common/Summary.styled.tsx | 13 -- .../SupportedActions/common/Summary.tsx | 23 +--- .../SupportedActions/common/types.ts | 1 - .../__snapshots__/ProposalCard.test.tsx.snap | 64 ++++----- .../primitives/Links/BlockExplorerLink.tsx | 46 +++++++ .../primitives/Links/ExternalLink.tsx | 15 +++ .../primitives/Links/StyledSegmentedLink.tsx | 14 ++ src/components/primitives/Links/index.ts | 1 + src/components/primitives/Links/types.ts | 12 ++ src/hooks/Guilds/useUpdateEnsContent.ts | 5 +- 13 files changed, 225 insertions(+), 191 deletions(-) create mode 100644 src/components/primitives/Links/BlockExplorerLink.tsx create mode 100644 src/components/primitives/Links/ExternalLink.tsx create mode 100644 src/components/primitives/Links/StyledSegmentedLink.tsx create mode 100644 src/components/primitives/Links/types.ts diff --git a/src/components/ActionsBuilder/CallDetails/__snapshots__/CallDetails.test.tsx.snap b/src/components/ActionsBuilder/CallDetails/__snapshots__/CallDetails.test.tsx.snap index ac93594a7..2901c17c4 100644 --- a/src/components/ActionsBuilder/CallDetails/__snapshots__/CallDetails.test.tsx.snap +++ b/src/components/ActionsBuilder/CallDetails/__snapshots__/CallDetails.test.tsx.snap @@ -63,12 +63,6 @@ exports[`CallDetails Should match 1`] = ` padding: 0; } -.c7 { - border-radius: 50%; - height: 24px; - width: 24px; -} - .c5 { margin-right: 0.5rem; display: -webkit-inline-box; @@ -91,28 +85,10 @@ exports[`CallDetails Should match 1`] = ` border-radius: 10px; } -.c2 { - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - margin-top: 0.5rem; - margin-bottom: 0.5rem; - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; -} - -.c3 { - color: #fff; - margin-top: 0; - white-space: pre-wrap; -} - -.c4 { - color: #A1A6B0; - margin: 0; +.c7 { + border-radius: 50%; + height: 24px; + width: 24px; } .c8 { @@ -139,6 +115,30 @@ exports[`CallDetails Should match 1`] = ` color: #fff; } +.c2 { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + margin-top: 0.5rem; + margin-bottom: 0.5rem; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.c3 { + color: #fff; + margin-top: 0; + white-space: pre-wrap; +} + +.c4 { + color: #A1A6B0; + margin: 0; +} + .c13 { margin: 0; padding: 0; @@ -320,19 +320,6 @@ exports[`CallDetails Should match with empty data 1`] = ` padding: 0; } -.c14 { - width: 100%; - min-width: 200px; - height: 1px; - background-color: #303338; -} - -.c7 { - border-radius: 50%; - height: 24px; - width: 24px; -} - .c5 { margin-right: 0.5rem; display: -webkit-inline-box; @@ -355,52 +342,65 @@ exports[`CallDetails Should match with empty data 1`] = ` border-radius: 10px; } -.c2 { +.c7 { + border-radius: 50%; + height: 24px; + width: 24px; +} + +.c8 { + color: #A1A6B0; + margin-right: 0.5rem; display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; - margin-top: 0.5rem; - margin-bottom: 0.5rem; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + -ms-flex-pack: justify; + justify-content: space-between; -webkit-align-items: center; -webkit-box-align: center; -ms-flex-align: center; align-items: center; + -webkit-text-decoration: none; + text-decoration: none; } -.c3 { +.c8:hover { + cursor: pointer; color: #fff; - margin-top: 0; - white-space: pre-wrap; } -.c4 { - color: #A1A6B0; - margin: 0; +.c14 { + width: 100%; + min-width: 200px; + height: 1px; + background-color: #303338; } -.c8 { - color: #A1A6B0; - margin-right: 0.5rem; +.c2 { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; - -webkit-box-pack: justify; - -webkit-justify-content: space-between; - -ms-flex-pack: justify; - justify-content: space-between; + margin-top: 0.5rem; + margin-bottom: 0.5rem; -webkit-align-items: center; -webkit-box-align: center; -ms-flex-align: center; align-items: center; - -webkit-text-decoration: none; - text-decoration: none; } -.c8:hover { - cursor: pointer; +.c3 { color: #fff; + margin-top: 0; + white-space: pre-wrap; +} + +.c4 { + color: #A1A6B0; + margin: 0; } .c13 { diff --git a/src/components/ActionsBuilder/SupportedActions/UpdateENSContent/UpdateENSContentSummary.tsx b/src/components/ActionsBuilder/SupportedActions/UpdateENSContent/UpdateENSContentSummary.tsx index b86d8929e..9e150b9e1 100644 --- a/src/components/ActionsBuilder/SupportedActions/UpdateENSContent/UpdateENSContentSummary.tsx +++ b/src/components/ActionsBuilder/SupportedActions/UpdateENSContent/UpdateENSContentSummary.tsx @@ -1,10 +1,5 @@ import { diffLines } from 'diff'; -import { - DetailBody, - DetailHeader, - DetailRow, - StyledSegmentLink, -} from '../common/Summary.styled'; +import { DetailBody, DetailHeader, DetailRow } from '../common/Summary.styled'; import Summary from '../common/Summary'; import { useUpdateEnsContent } from 'hooks/Guilds/useUpdateEnsContent'; import { useEnsName, useNetwork } from 'wagmi'; @@ -12,13 +7,13 @@ import { convertToIpfsHash, getIpfsUrl, isSupportedChainId } from 'utils/ipfs'; import { useTranslation } from 'react-i18next'; import { ActionViewProps } from '..'; import { useENSContentHash } from 'hooks/Guilds/ens/useENSPublicResolverContract'; -import { BiLinkExternal } from 'react-icons/bi'; import { getBlockExplorerUrl } from 'provider/chains'; import useIPFSFileMetadata from 'hooks/Guilds/ipfs/useIPFSFileMetadata'; import { useMemo } from 'react'; import { DiffView } from 'components/ActionsBuilder/DiffView'; import useIPFSFile from 'hooks/Guilds/ipfs/useIPFSFile'; import { DiffContainer, DiffDetail, DiffStat } from './styles'; +import { ExternalLink } from 'components/primitives/Links/ExternalLink'; const MAX_FILE_DIFF_BYTES = 64000; // 64kb @@ -89,28 +84,18 @@ const UpdateENSContentSummary: React.FC = ({ {t('ens.domain')} - + {ensName || parsedData?.from} - - + {t('ens.currentContent')} {currentIpfsUrl ? ( - + {currentIpfsUrl || ''} - - + ) : ( t('none') )} @@ -122,15 +107,9 @@ const UpdateENSContentSummary: React.FC = ({ {newFile ? ( - + {newIpfsUrl || ''} - - - + ---{numChanges?.removed} +++{numChanges?.added} @@ -142,18 +121,13 @@ const UpdateENSContentSummary: React.FC = ({ /> ) : ( - + {newIpfsUrl || ''} - - + )} - + ); }; diff --git a/src/components/ActionsBuilder/SupportedActions/UpdateENSContent/__snapshots__/UpdateENSContentSummary.test.tsx.snap b/src/components/ActionsBuilder/SupportedActions/UpdateENSContent/__snapshots__/UpdateENSContentSummary.test.tsx.snap index 879879f79..59e0d81ba 100644 --- a/src/components/ActionsBuilder/SupportedActions/UpdateENSContent/__snapshots__/UpdateENSContentSummary.test.tsx.snap +++ b/src/components/ActionsBuilder/SupportedActions/UpdateENSContent/__snapshots__/UpdateENSContentSummary.test.tsx.snap @@ -32,28 +32,20 @@ exports[`UpdateENSNameSummary Should match snapshot 1`] = ` margin: 0; } -.c4 { - color: #A1A6B0; +.c5 { margin-right: 0.5rem; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-box-pack: justify; - -webkit-justify-content: space-between; - -ms-flex-pack: justify; - justify-content: space-between; + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; -webkit-align-items: center; -webkit-box-align: center; -ms-flex-align: center; align-items: center; - -webkit-text-decoration: none; - text-decoration: none; -} - -.c4:hover { - cursor: pointer; - color: #fff; } .c6 { @@ -67,20 +59,28 @@ exports[`UpdateENSNameSummary Should match snapshot 1`] = ` width: 24px; } -.c5 { +.c4 { + color: #A1A6B0; margin-right: 0.5rem; - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + -ms-flex-pack: justify; + justify-content: space-between; -webkit-align-items: center; -webkit-box-align: center; -ms-flex-align: center; align-items: center; + -webkit-text-decoration: none; + text-decoration: none; +} + +.c4:hover { + cursor: pointer; + color: #fff; }
diff --git a/src/components/ActionsBuilder/SupportedActions/common/Summary.styled.tsx b/src/components/ActionsBuilder/SupportedActions/common/Summary.styled.tsx index 742300312..2f0417951 100644 --- a/src/components/ActionsBuilder/SupportedActions/common/Summary.styled.tsx +++ b/src/components/ActionsBuilder/SupportedActions/common/Summary.styled.tsx @@ -22,16 +22,3 @@ export const DetailBody = styled(DetailRow)` export const RedHighlight = styled.span` color: ${({ theme }) => theme.colors.red}; `; - -export const StyledSegmentLink = styled.a` - color: ${({ theme }) => theme.colors.grey}; - margin-right: 0.5rem; - display: flex; - justify-content: space-between; - align-items: center; - text-decoration: none; - &:hover { - cursor: pointer; - color: ${({ theme }) => theme.colors.text}; - } -`; diff --git a/src/components/ActionsBuilder/SupportedActions/common/Summary.tsx b/src/components/ActionsBuilder/SupportedActions/common/Summary.tsx index e434d625d..b0adebbc0 100644 --- a/src/components/ActionsBuilder/SupportedActions/common/Summary.tsx +++ b/src/components/ActionsBuilder/SupportedActions/common/Summary.tsx @@ -1,30 +1,25 @@ import useBigNumberToString from 'hooks/Guilds/conversions/useBigNumberToString'; -import useENSAvatar from 'hooks/Guilds/ens/useENSAvatar'; -import { Avatar } from 'components/Avatar'; import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { getNetworkById, MAINNET_ID, preventEmptyString } from 'utils'; +import { getNetworkById, preventEmptyString } from 'utils'; import { useNetwork } from 'wagmi'; -import { Segment } from './infoLine'; import { DetailBody, DetailHeader, DetailRow, RedHighlight, - StyledSegmentLink, } from './Summary.styled'; import { SummaryProps } from './types'; -import { BiLinkExternal } from 'react-icons/bi'; import { SupportedAction } from 'components/ActionsBuilder/types'; +import { BlockExplorerLink } from 'components/primitives/Links'; -const Summary = ({ decodedCall, blockExplorerUrl }: SummaryProps) => { +const Summary = ({ decodedCall }: SummaryProps) => { const { t } = useTranslation(); const parsedValueToString = useBigNumberToString( preventEmptyString(decodedCall?.value), 18 ); - const { ensName, imageUrl } = useENSAvatar(decodedCall.to, MAINNET_ID); const { chain } = useNetwork(); const nativeTokenSymbol = useMemo(() => { return getNetworkById(chain?.id).nativeAsset.symbol; @@ -51,17 +46,7 @@ const Summary = ({ decodedCall, blockExplorerUrl }: SummaryProps) => { - - - - - {ensName || decodedCall.to} - - + diff --git a/src/components/ActionsBuilder/SupportedActions/common/types.ts b/src/components/ActionsBuilder/SupportedActions/common/types.ts index 9160b7564..bb478c701 100644 --- a/src/components/ActionsBuilder/SupportedActions/common/types.ts +++ b/src/components/ActionsBuilder/SupportedActions/common/types.ts @@ -2,5 +2,4 @@ import { DecodedCall } from 'components/ActionsBuilder/types'; export interface SummaryProps { decodedCall: DecodedCall; - blockExplorerUrl?: string; } diff --git a/src/components/ProposalCard/__snapshots__/ProposalCard.test.tsx.snap b/src/components/ProposalCard/__snapshots__/ProposalCard.test.tsx.snap index 35677b25b..06f16be4e 100644 --- a/src/components/ProposalCard/__snapshots__/ProposalCard.test.tsx.snap +++ b/src/components/ProposalCard/__snapshots__/ProposalCard.test.tsx.snap @@ -117,6 +117,22 @@ exports[`ProposalCard ProposalCard Renders properly with data 1`] = ` text-decoration: none; } +.c18 { + margin-right: 0.5rem; + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + .c12 { font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 20px; @@ -253,22 +269,6 @@ exports[`ProposalCard ProposalCard Renders properly with data 1`] = ` cursor: default; } -.c18 { - margin-right: 0.5rem; - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; -} - .c19 { width: 5rem; display: -webkit-box; @@ -630,6 +630,22 @@ exports[`ProposalCard ProposalCard Renders properly with more than one option 1 text-decoration: none; } +.c18 { + margin-right: 0.5rem; + display: -webkit-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-flex; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-align-items: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + .c12 { font-family: 'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif; font-size: 20px; @@ -766,22 +782,6 @@ exports[`ProposalCard ProposalCard Renders properly with more than one option 1 cursor: default; } -.c18 { - margin-right: 0.5rem; - display: -webkit-inline-box; - display: -webkit-inline-flex; - display: -ms-inline-flexbox; - display: inline-flex; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; -} - .c19 { width: 5rem; display: -webkit-box; diff --git a/src/components/primitives/Links/BlockExplorerLink.tsx b/src/components/primitives/Links/BlockExplorerLink.tsx new file mode 100644 index 000000000..be8523dde --- /dev/null +++ b/src/components/primitives/Links/BlockExplorerLink.tsx @@ -0,0 +1,46 @@ +import { Segment } from 'components/ActionsBuilder/SupportedActions/common/infoLine'; +import { Avatar } from 'components/Avatar'; +import useENSAvatar from 'hooks/Guilds/ens/useENSAvatar'; +import { useUpdateEnsContent } from 'hooks/Guilds/useUpdateEnsContent'; +import { MAINNET_ID } from 'utils'; +import { Chain, useNetwork } from 'wagmi'; +import { ExternalLink } from './ExternalLink'; +import { BlockExplorerLinkProps } from './types'; + +const getBlockExplorerUrl = ( + chain: Chain, + address: string, + type: 'address' | 'tx' +) => { + if (!chain || !chain?.blockExplorers?.default) return null; + + return `${chain.blockExplorers.default.url}/${type}/${address}`; +}; + +export const BlockExplorerLink: React.FC = ({ + decodedCall, + showAvatar, +}) => { + const { chain } = useNetwork(); + const { parsedData } = useUpdateEnsContent({ decodedCall }); + const { ensName, imageUrl } = useENSAvatar(decodedCall.to, MAINNET_ID); + + const blockExplorerUrl = getBlockExplorerUrl( + chain, + parsedData?.from, + 'address' + ); + + return ( + <> + {showAvatar && ( + + + + )} + + {ensName || decodedCall.to} + + + ); +}; diff --git a/src/components/primitives/Links/ExternalLink.tsx b/src/components/primitives/Links/ExternalLink.tsx new file mode 100644 index 000000000..d24eb4b1f --- /dev/null +++ b/src/components/primitives/Links/ExternalLink.tsx @@ -0,0 +1,15 @@ +import { BiLinkExternal } from 'react-icons/bi'; +import { StyledSegmentLink } from './StyledSegmentedLink'; +import { ExternalLinkProps } from './types'; + +export const ExternalLink: React.FC = ({ + href, + children, +}) => { + return ( + + {children} + + + ); +}; diff --git a/src/components/primitives/Links/StyledSegmentedLink.tsx b/src/components/primitives/Links/StyledSegmentedLink.tsx new file mode 100644 index 000000000..bd0d6fcb4 --- /dev/null +++ b/src/components/primitives/Links/StyledSegmentedLink.tsx @@ -0,0 +1,14 @@ +import styled from 'styled-components'; + +export const StyledSegmentLink = styled.a` + color: ${({ theme }) => theme.colors.grey}; + margin-right: 0.5rem; + display: flex; + justify-content: space-between; + align-items: center; + text-decoration: none; + &:hover { + cursor: pointer; + color: ${({ theme }) => theme.colors.text}; + } +`; diff --git a/src/components/primitives/Links/index.ts b/src/components/primitives/Links/index.ts index bf7d8259b..785a4a326 100644 --- a/src/components/primitives/Links/index.ts +++ b/src/components/primitives/Links/index.ts @@ -1 +1,2 @@ export { UnstyledLink } from './UnstyledLink'; +export { BlockExplorerLink } from './BlockExplorerLink'; diff --git a/src/components/primitives/Links/types.ts b/src/components/primitives/Links/types.ts new file mode 100644 index 000000000..c2fc89e7f --- /dev/null +++ b/src/components/primitives/Links/types.ts @@ -0,0 +1,12 @@ +import { DecodedCall } from 'components/ActionsBuilder/types'; +import { ReactNode } from 'react'; + +export interface BlockExplorerLinkProps { + decodedCall: DecodedCall; + showAvatar?: boolean; +} + +export interface ExternalLinkProps { + href: string; + children: ReactNode; +} diff --git a/src/hooks/Guilds/useUpdateEnsContent.ts b/src/hooks/Guilds/useUpdateEnsContent.ts index 0e575ec1b..0450302ef 100644 --- a/src/hooks/Guilds/useUpdateEnsContent.ts +++ b/src/hooks/Guilds/useUpdateEnsContent.ts @@ -14,14 +14,15 @@ export const useUpdateEnsContent = ({ }): { parsedData: UpdateENSContentDecodedCall } | null => { const parsedData = useMemo(() => { if (!decodedCall) return null; + if (!decodedCall.args) return null; return { from: decodedCall.from, to: decodedCall.to, node: decodedCall.args.node, contentHash: decodedCall.args.hash, optionalProps: { - ensName: decodedCall.optionalProps.ensName, - ipfsHash: decodedCall.optionalProps.ipfsHash, + ensName: decodedCall.optionalProps?.ensName, + ipfsHash: decodedCall.optionalProps?.ipfsHash, }, }; }, [decodedCall]);