Skip to content

Commit 94f86fb

Browse files
authored
fix: mf-6638 fetch proposal via box api (#12139)
1 parent 6de7442 commit 94f86fb

File tree

19 files changed

+559
-188
lines changed

19 files changed

+559
-188
lines changed

packages/plugins/Snapshot/src/SiteAdaptor/InformationCard.tsx

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { formatWithCommas } from '@masknet/shared-base'
55
import { makeStyles } from '@masknet/theme'
66
import { EVMExplorerResolver } from '@masknet/web3-providers'
77
import { resolveIPFS_URL, resolveResourceURL } from '@masknet/web3-shared-base'
8-
import { formatEthereumAddress } from '@masknet/web3-shared-evm'
98
import { Avatar, Box, Link, Typography } from '@mui/material'
109
import { format as formatDateTime } from 'date-fns'
1110
import { useContext, type PropsWithChildren, type ReactNode } from 'react'
@@ -14,6 +13,7 @@ import { SNAPSHOT_IPFS } from '../constants.js'
1413
import { SnapshotContext } from '../context.js'
1514
import { useProposal } from './hooks/useProposal.js'
1615
import { SnapshotCard } from './SnapshotCard.js'
16+
import { formatLongHex, formatSpaceId } from './helpers.js'
1717

1818
interface InfoFieldProps extends withClasses<'field'>, PropsWithChildren {
1919
title: ReactNode
@@ -78,7 +78,7 @@ export function InformationCard() {
7878
const proposal = useProposal(identifier.id)
7979
const { start, end, snapshot, strategies, chainId } = proposal
8080
const authorProfile = `https://snapshot.box/#/${identifier.space}/profile/${proposal.address}`
81-
const link = `https://snapshot.box/#/${identifier.space}/proposal/${identifier.id}`
81+
const link = `https://snapshot.box/#/${identifier.space}/proposal/${identifier.id.split('/').pop()}`
8282
return (
8383
<SnapshotCard title={<Trans>Information</Trans>}>
8484
<div className={classes.infos}>
@@ -108,20 +108,22 @@ export function InformationCard() {
108108
: <EthereumBlockie address={proposal.address} />}
109109
</div>
110110
<Typography fontSize={14}>
111-
{proposal.space.id ?? formatEthereumAddress(proposal.address, 4)}
111+
{proposal.space.id ? formatSpaceId(proposal.space.id) : formatLongHex(proposal.address)}
112112
</Typography>
113113
</Link>
114114
</InfoField>
115-
<InfoField title={<Trans>IPFS</Trans>} classes={{ field: classes.infoColor }}>
116-
<Link
117-
className={classes.link}
118-
target="_blank"
119-
rel="noopener"
120-
href={resolveResourceURL(urlcat(SNAPSHOT_IPFS, proposal.ipfs))}>
121-
<Typography fontSize={14}>#{identifier.id.slice(0, 7)}</Typography>
122-
<Icons.LinkOut size={16} sx={{ paddingLeft: 1 }} />
123-
</Link>
124-
</InfoField>
115+
{proposal.ipfs ?
116+
<InfoField title={<Trans>IPFS</Trans>} classes={{ field: classes.infoColor }}>
117+
<Link
118+
className={classes.link}
119+
target="_blank"
120+
rel="noopener"
121+
href={resolveResourceURL(urlcat(SNAPSHOT_IPFS, proposal.ipfs))}>
122+
<Typography fontSize={14}>#{identifier.id.slice(0, 7)}</Typography>
123+
<Icons.LinkOut size={16} sx={{ paddingLeft: 1 }} />
124+
</Link>
125+
</InfoField>
126+
: null}
125127
<InfoField title={<Trans>Start date</Trans>} classes={{ field: classes.infoColor }}>
126128
<Typography fontSize={14} fontWeight={400}>
127129
{formatDateTime(start * 1000, 'MMM dd, yyyy, hh:mm a')}

packages/plugins/Snapshot/src/SiteAdaptor/Snapshot.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { ProposalTab } from './ProposalTab.js'
2222
import { VotingDialog } from './VotingDialog.js'
2323
import { usePower } from './hooks/usePower.js'
2424
import { useProposal } from './hooks/useProposal.js'
25+
import { formatSpaceId } from './helpers.js'
2526

2627
const useStyles = makeStyles()((theme) => {
2728
return {
@@ -149,7 +150,7 @@ export function Snapshot() {
149150
by
150151
</Typography>
151152
<Typography fontSize={14} fontWeight="700">
152-
{proposal.space.id}
153+
{formatSpaceId(proposal.space.id)}
153154
</Typography>
154155
</Box>
155156
</Box>

packages/plugins/Snapshot/src/SiteAdaptor/VotesCard.tsx

Lines changed: 68 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
/// <reference types="react/canary" />
22
import { Trans } from '@lingui/react/macro'
3-
import { EthereumBlockie } from '@masknet/shared'
3+
import { EmptyStatus, EthereumBlockie } from '@masknet/shared'
44
import type { NetworkPluginID } from '@masknet/shared-base'
55
import { makeStyles, ShadowRootTooltip, TextOverflowTooltip } from '@masknet/theme'
66
import { useChainContext } from '@masknet/web3-hooks-base'
77
import { formatCount, formatPercentage, isSameAddress } from '@masknet/web3-shared-base'
8-
import { formatEthereumAddress } from '@masknet/web3-shared-evm'
98
import { Badge, Box, Link, List, ListItem, Typography } from '@mui/material'
109
import { unstable_useCacheRefresh, useContext } from 'react'
1110
import { SnapshotContext } from '../context.js'
@@ -14,6 +13,7 @@ import { useVotes } from './hooks/useVotes.js'
1413
import { LoadingCard } from './LoadingCard.js'
1514
import { LoadingFailCard } from './LoadingFailCard.js'
1615
import { SnapshotCard } from './SnapshotCard.js'
16+
import { formatLongHex } from './helpers.js'
1717

1818
const useStyles = makeStyles()((theme) => {
1919
return {
@@ -101,73 +101,80 @@ function Content() {
101101
<Trans>Votes</Trans>
102102
</Badge>
103103
}>
104-
<List className={classes.list}>
105-
{votes.map(function voteItemIter(v) {
106-
const isAverageWeight = v.choices?.every((c) => c.weight === 1)
107-
const fullChoiceText =
108-
v.totalWeight && v.choices ?
109-
v.choices
110-
.flatMap((choice, index) => [
111-
index === 0 ? '' : ', ',
112-
!isAverageWeight ? formatPercentage(choice.weight / v.totalWeight!) + ' ' : '',
113-
choice.name,
114-
])
115-
.join('')
116-
: null
117-
const link = `https://snapshot.box/#/${identifier.space}/profile/${v.address}`
118-
return (
119-
<ListItem className={classes.listItem} key={v.address}>
120-
<Link
121-
className={cx(classes.link, classes.ellipsisText)}
122-
target="_blank"
123-
rel="noopener"
124-
href={link}>
125-
<Box className={classes.avatarWrapper}>
126-
<EthereumBlockie address={v.address} />
127-
</Box>
128-
<Typography color={theme.palette.maskColor.dark}>
129-
{isSameAddress(v.address, account) ?
130-
<Trans>You</Trans>
131-
: formatEthereumAddress(v.address, 4)}
132-
</Typography>
133-
</Link>
134-
{v.choice ?
135-
<Typography className={classes.choice}>{v.choice}</Typography>
136-
: v.choices ?
137-
<ShadowRootTooltip
104+
{votes.length ?
105+
<List className={classes.list}>
106+
{votes.map(function voteItemIter(v) {
107+
const isAverageWeight = v.choices?.every((c) => c.weight === 1)
108+
const fullChoiceText =
109+
v.totalWeight && v.choices ?
110+
v.choices
111+
.flatMap((choice, index) => [
112+
index === 0 ? '' : ', ',
113+
!isAverageWeight ? formatPercentage(choice.weight / v.totalWeight!) + ' ' : '',
114+
choice.name,
115+
])
116+
.join('')
117+
: null
118+
const link = `https://snapshot.box/#/${identifier.space}/profile/${v.address}`
119+
return (
120+
<ListItem className={classes.listItem} key={v.address}>
121+
<Link
122+
className={cx(classes.link, classes.ellipsisText)}
123+
target="_blank"
124+
rel="noopener"
125+
href={link}>
126+
<Box className={classes.avatarWrapper}>
127+
<EthereumBlockie address={v.address} />
128+
</Box>
129+
<Typography color={theme.palette.maskColor.dark}>
130+
{isSameAddress(v.address, account) ?
131+
<Trans>You</Trans>
132+
: formatLongHex(v.address)}
133+
</Typography>
134+
</Link>
135+
{v.choice ?
136+
<Typography className={classes.choice}>{v.choice}</Typography>
137+
: v.choices ?
138+
<ShadowRootTooltip
139+
PopperProps={{
140+
disablePortal: false,
141+
}}
142+
title={
143+
<Typography className={classes.shadowRootTooltip}>
144+
{fullChoiceText}
145+
</Typography>
146+
}
147+
placement="top"
148+
classes={{ tooltip: classes.tooltip, arrow: classes.arrow }}
149+
arrow>
150+
<Typography className={classes.choice}>{fullChoiceText}</Typography>
151+
</ShadowRootTooltip>
152+
: null}
153+
<TextOverflowTooltip
154+
as={ShadowRootTooltip}
138155
PopperProps={{
139-
disablePortal: false,
156+
disablePortal: true,
140157
}}
158+
classes={{ tooltip: classes.tooltip, arrow: classes.arrow }}
141159
title={
142-
<Typography className={classes.shadowRootTooltip}>{fullChoiceText}</Typography>
160+
<Typography className={classes.shadowRootTooltip}>
161+
{formatCount(v.balance, 2, true) + ' ' + v.strategySymbol.toUpperCase()}
162+
</Typography>
143163
}
144164
placement="top"
145-
classes={{ tooltip: classes.tooltip, arrow: classes.arrow }}
146165
arrow>
147-
<Typography className={classes.choice}>{fullChoiceText}</Typography>
148-
</ShadowRootTooltip>
149-
: null}
150-
<TextOverflowTooltip
151-
as={ShadowRootTooltip}
152-
PopperProps={{
153-
disablePortal: true,
154-
}}
155-
classes={{ tooltip: classes.tooltip, arrow: classes.arrow }}
156-
title={
157-
<Typography className={classes.shadowRootTooltip}>
166+
<Typography className={classes.power}>
158167
{formatCount(v.balance, 2, true) + ' ' + v.strategySymbol.toUpperCase()}
159168
</Typography>
160-
}
161-
placement="top"
162-
arrow>
163-
<Typography className={classes.power}>
164-
{formatCount(v.balance, 2, true) + ' ' + v.strategySymbol.toUpperCase()}
165-
</Typography>
166-
</TextOverflowTooltip>
167-
</ListItem>
168-
)
169-
})}
170-
</List>
169+
</TextOverflowTooltip>
170+
</ListItem>
171+
)
172+
})}
173+
</List>
174+
: <EmptyStatus>
175+
<Trans>No votes</Trans>
176+
</EmptyStatus>
177+
}
171178
</SnapshotCard>
172179
)
173180
}

packages/plugins/Snapshot/src/SiteAdaptor/helpers.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ import type { ProposalIdentifier } from '../types.js'
33
export function getProposalIdentifier(url: string): ProposalIdentifier {
44
const parsedURL = new URL(url)
55
const [, space, , id] = parsedURL.hash.split('/')
6+
if (id.match(/^\d+$/)) {
7+
return {
8+
id: `${space.split(':').pop()}/${id}`,
9+
space,
10+
}
11+
}
612
return {
713
id,
814
space,
@@ -16,3 +22,12 @@ export function resolveSnapshotSpacePageUrl(spaceId: string) {
1622
export function resolveSnapshotProposalUrl(spaceId: string, proposalId: string) {
1723
return `https://snapshot.box/#/${spaceId}/proposal/${proposalId}`
1824
}
25+
26+
export function formatLongHex(hex: string) {
27+
return hex.slice(0, 6) + '...' + hex.slice(-4)
28+
}
29+
30+
export function formatSpaceId(spaceId: string) {
31+
if (spaceId.startsWith('0x') && spaceId.length === 66) return `${spaceId.slice(0, 6)}...${spaceId.slice(-4)}`
32+
return `0x${spaceId}`
33+
}

packages/plugins/Snapshot/src/SiteAdaptor/hooks/useVotes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export function useVotes(identifier: ProposalIdentifier, account?: string) {
3636
: undefined,
3737
address: v.voter,
3838
authorIpfsHash: v.ipfs ?? v.id,
39-
balance: sumBy(scores, (score) => score[v.voter.toLowerCase()] ?? 0),
39+
balance: v.vp || sumBy(scores, (score) => score[v.voter.toLowerCase()] ?? 0),
4040
scores: scores.map((score) => score[v.voter.toLowerCase()] || 0),
4141
strategySymbol: proposal.space.symbol ?? strategies[0].params.symbol,
4242
timestamp: v.created,

0 commit comments

Comments
 (0)