diff --git a/src/models/Community.ts b/src/models/Community.ts index 46bc878c..d09c6b4b 100644 --- a/src/models/Community.ts +++ b/src/models/Community.ts @@ -15,6 +15,7 @@ export interface Community { decimals?: string network: string votingAddressesCount: number + daoContract?: string } export interface CommunityToken { diff --git a/src/modules/lite/explorer/components/ProposalDetailCard.tsx b/src/modules/lite/explorer/components/ProposalDetailCard.tsx index 412d40e4..388ffcea 100644 --- a/src/modules/lite/explorer/components/ProposalDetailCard.tsx +++ b/src/modules/lite/explorer/components/ProposalDetailCard.tsx @@ -11,17 +11,22 @@ import { Poll } from "models/Polls" import dayjs from "dayjs" import { useNotification } from "modules/common/hooks/useNotification" -const LogoItem = styled("img")({ - height: 18, - cursor: "pointer" -}) +const LogoItem = styled("img")(({ theme }) => ({ + cursor: "pointer", + [theme.breakpoints.down("sm")]: { + height: 10 + } +})) -const TextContainer = styled(Typography)({ +const TextContainer = styled(Typography)(({ theme }) => ({ display: "flex", alignItems: "center", gap: 10, - marginRight: 8 -}) + marginRight: 8, + [theme.breakpoints.down("sm")]: { + marginTop: 20 + } +})) const EndTextContainer = styled(Typography)(({ theme }) => ({ display: "flex", @@ -47,12 +52,16 @@ const Divider = styled(Typography)(({ theme }) => ({ } })) -const StyledLink = styled(Link)({ +const StyledLink = styled(Link)(({ theme }) => ({ fontFamily: "Roboto Mono", fontWeight: 300, fontSize: 16, - marginLeft: 8 -}) + marginLeft: 8, + [theme.breakpoints.down("sm")]: { + fontWeight: 100, + fontSize: 10 + } +})) const CopyIcon = styled(FileCopyOutlined)({ marginRight: 8, @@ -64,6 +73,7 @@ const CustomPopover = withStyles({ "marginTop": 10, "padding": 8, "cursor": "pointer", + "background": "#1c1f23 !important", "&:hover": { background: "#81feb76b !important" } @@ -100,114 +110,106 @@ export const ProposalDetailCard: React.FC<{ poll: Poll | undefined; daoId: strin return ( <> - {poll && poll !== undefined ? ( - - - - - - {poll?.name} - - - - - - - - - Share - - - - - - Copy link - - + + + + + + {poll?.name} + + + + + + + + + Share + + + + + Copy link + + + - - - - - - - - - - - - + + + + + + + + + + + - - - - Start date:{" "} - - - {" "} - {dayjs(Number(poll?.startTime)).format("lll")} - - - - - {" "} - End date:{" "} - - - {" "} - {dayjs(Number(poll?.endTime)).format("lll")} - - - - - - - {poll?.description} - + + + + + Start date:{" "} + + + {dayjs(Number(poll?.startTime)).format("lll")} + + - + + End date:{" "} + + + {dayjs(Number(poll?.endTime)).format("lll")} + + - {poll?.externalLink ? ( - - - - {poll?.externalLink} - - - ) : null} + + + {poll?.description} + - - ) : ( - - Could not load the requested proposal + + {poll?.externalLink ? ( + + + + {poll?.externalLink} + + + ) : null} - )} + + ) ) } diff --git a/src/modules/lite/explorer/components/VoteDetails.tsx b/src/modules/lite/explorer/components/VoteDetails.tsx index e5282c4c..ef06c14e 100644 --- a/src/modules/lite/explorer/components/VoteDetails.tsx +++ b/src/modules/lite/explorer/components/VoteDetails.tsx @@ -12,11 +12,12 @@ import { calculateWeight, getTotalVoters, getTreasuryPercentage, - getTurnoutValue, nFormatter } from "services/lite/utils" import { useTezos } from "services/beacon/hooks/useTezos" import { useCommunityToken } from "../hooks/useCommunityToken" +import { getTurnoutValue } from "services/utils/utils" +import { useTokenDelegationSupported } from "services/contracts/token/hooks/useTokenDelegationSupported" const Container = styled(Grid)(({ theme }) => ({ background: theme.palette.primary.main, @@ -59,9 +60,10 @@ export const VoteDetails: React.FC<{ poll: Poll | undefined; choices: Choice[]; const isMobile = useMediaQuery(theme.breakpoints.down("sm")) const [open, setOpen] = React.useState(false) const { network } = useTezos() - const [turnout, setTurnout] = useState(0) + const [turnout, setTurnout] = useState() const [votes, setVotes] = useState([]) const tokenData = useCommunityToken(communityId) + const { data: isTokenDelegationSupported } = useTokenDelegationSupported(tokenData?.tokenAddress) const handleClickOpen = () => { setVotes(choices.filter(elem => elem.walletAddresses.length > 0)) @@ -76,11 +78,19 @@ export const VoteDetails: React.FC<{ poll: Poll | undefined; choices: Choice[]; } useMemo(async () => { - if (token && token !== undefined) { - const value = await getTurnoutValue(network, token, Number(poll?.referenceBlock), getTotalVoters(choices)) - setTurnout(value) + if (token && tokenData) { + const value = await getTurnoutValue( + network, + tokenData?.tokenAddress, + tokenData.tokenID, + Number(poll?.referenceBlock), + getTotalVoters(choices) + ) + if (value) { + setTurnout(value) + } } - }, [poll, choices, network, token]) + }, [poll, choices, network, token, tokenData]) return ( @@ -148,9 +158,11 @@ export const VoteDetails: React.FC<{ poll: Poll | undefined; choices: Choice[]; Votes - - ({turnout.toFixed(2)} % Turnout) - + {isTokenDelegationSupported && turnout ? ( + + ({turnout.toFixed(2)} % Turnout) + + ) : null} {poll?.tokenSymbol} - + ( {getTreasuryPercentage( calculateProposalTotal(choices, tokenData?.decimals), diff --git a/src/modules/lite/explorer/pages/CommunityDetails/router.tsx b/src/modules/lite/explorer/pages/CommunityDetails/router.tsx index d405ad09..ac49ee15 100644 --- a/src/modules/lite/explorer/pages/CommunityDetails/router.tsx +++ b/src/modules/lite/explorer/pages/CommunityDetails/router.tsx @@ -1,11 +1,22 @@ -import React from "react" +import React, { useEffect } from "react" import { Switch, Route, Redirect, useRouteMatch } from "react-router" import { CommunityDetails } from "./index" import { ProposalCreator } from "../CreateProposal" import { ProposalDetails } from "../ProposalDetails" +import { useCommunity } from "../../hooks/useCommunity" +import { useTezos } from "services/beacon/hooks/useTezos" +import { Network } from "services/beacon" export const CommunityDetailsRouter: React.FC<{ id: any }> = ({ id }): JSX.Element => { const match = useRouteMatch() + const community = useCommunity(id) + const { network, changeNetwork } = useTezos() + + useEffect(() => { + if (community && community.network.toLowerCase() !== network.toLowerCase()) { + changeNetwork(community.network.toLowerCase() as Network) + } + }, [community, changeNetwork, network]) return ( diff --git a/src/modules/lite/explorer/pages/ProposalDetails/index.tsx b/src/modules/lite/explorer/pages/ProposalDetails/index.tsx index 8087ef31..450d4395 100644 --- a/src/modules/lite/explorer/pages/ProposalDetails/index.tsx +++ b/src/modules/lite/explorer/pages/ProposalDetails/index.tsx @@ -55,7 +55,7 @@ export const ProposalDetails: React.FC<{ id: string }> = ({ id }) => { const isMobileSmall = useMediaQuery(theme.breakpoints.down("sm")) const { state } = useLocation<{ poll: Poll; choices: Choice[]; daoId: string }>() - const { data: dao } = useDAO(state.daoId) + const { data: dao } = useDAO(state?.daoId) const { account, wallet } = useTezos() const openNotification = useNotification() const [refresh, setRefresh] = useState() diff --git a/src/services/lite/utils.ts b/src/services/lite/utils.ts index fde652f1..81d8f885 100644 --- a/src/services/lite/utils.ts +++ b/src/services/lite/utils.ts @@ -36,43 +36,6 @@ export const getTotalSupplyAtReferenceBlock = async (network: Network, address: return result[0].value } -export const getTotalHolders = async (network: Network, address: string): Promise => { - const url = `https://api.${networkNameMap[network]}.tzkt.io/v1/tokens/balances/count?token.contract=${address}` - const response = await axios.get(url) - - if (!response) { - throw new Error("Failed to fetch contract current block") - } - - const result = await response.data - - return result -} - -export const getUserTotalSupplyAtReferenceBlock = async ( - network: Network, - address: string, - level: number, - userAddress: string -) => { - const url = `https://api.${networkNameMap[network]}.tzkt.io/v1/contracts/${address}/bigmaps/ledger/historical_keys/${level}` - const response = await fetch(url) - - if (!response.ok) { - throw new Error("Failed to fetch contract current block") - } - - const result = await response.json() - - let userBalance - - if (result && result.length > 0) { - userBalance = result.find((elem: any) => elem.key.address === userAddress) - return userBalance.value - } - return 0 -} - export const hasTokenBalance = async (network: Network, account: string, contract: any) => { const url = `https://api.${networkNameMap[network]}.tzkt.io/v1/tokens/balances?account=${account}&token.contract=${contract}` const response = await fetch(url) @@ -98,22 +61,6 @@ export const hasTokenBalance = async (network: Network, account: string, contrac return hasBalance } -export const getTurnoutValue = async (network: Network, address: string, level: number, voters: number) => { - const url = `https://api.${networkNameMap[network]}.tzkt.io/v1/contracts/${address}/bigmaps/ledger/historical_keys/${level}` - const response = await fetch(url) - - if (!response.ok) { - throw new Error("Failed to fetch contract current block") - } - const result = await response.json() - - if (result) { - return (voters * 100) / result.length - } - - return 0 -} - export const isProposalActive = (date: number) => { const config = { rounding: Math.floor diff --git a/src/services/utils/utils.ts b/src/services/utils/utils.ts index 1aedca94..1cd44ec5 100644 --- a/src/services/utils/utils.ts +++ b/src/services/utils/utils.ts @@ -35,13 +35,9 @@ export const getTotalSupplyAtReferenceBlock = async (network: Network, address: return result[0].value } -export const getUserTotalSupplyAtReferenceBlock = async ( - network: Network, - address: string, - level: number, - userAddress: string -) => { - const url = `https://api.${networkNameMap[network]}.tzkt.io/v1/contracts/${address}/bigmaps/ledger/historical_keys/${level}` +export const getTokenHoldersCount = async (network: Network, address: string, tokenID: number) => { + const url = `https://api.${networkNameMap[network]}.tzkt.io/v1/tokens?tokenId=${tokenID}&contract=${address}` + const response = await fetch(url) if (!response.ok) { @@ -50,13 +46,7 @@ export const getUserTotalSupplyAtReferenceBlock = async ( const result = await response.json() - let userBalance - - if (result && result.length > 0) { - userBalance = result.find((elem: any) => elem.key.address === userAddress) - return userBalance.value - } - return 0 + return result[0].holdersCount } export const hasTokenBalance = async (network: Network, account: string, contract: any) => { @@ -84,20 +74,18 @@ export const hasTokenBalance = async (network: Network, account: string, contrac return hasBalance } -export const getTurnoutValue = async (network: Network, address: string, level: number, voters: number) => { - const url = `https://api.${networkNameMap[network]}.tzkt.io/v1/contracts/${address}/bigmaps/ledger/historical_keys/${level}` - const response = await fetch(url) - - if (!response.ok) { - throw new Error("Failed to fetch contract current block") - } - const result = await response.json() +export const getTurnoutValue = async ( + network: Network, + address: string, + tokenID: number, + level: number, + voters: number +) => { + const tokenHolders = await getTokenHoldersCount(network, address, tokenID) - if (result) { - return (voters * 100) / result.length + if (tokenHolders) { + return (voters * 100) / Number(tokenHolders) } - - return 0 } export const isProposalActive = (date: number) => {