diff --git a/src/modules/etherlink/components/EvmDaoSettingsModal.tsx b/src/modules/etherlink/components/EvmDaoSettingsModal.tsx new file mode 100644 index 00000000..0f9e6d70 --- /dev/null +++ b/src/modules/etherlink/components/EvmDaoSettingsModal.tsx @@ -0,0 +1,138 @@ +import React, { useContext } from "react" +import { + Grid, + styled, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + Typography, + useMediaQuery, + useTheme +} from "@material-ui/core" +import { ResponsiveDialog } from "modules/explorer/components/ResponsiveDialog" + +import { EtherlinkContext } from "services/wagmi/context" +import { CopyButton } from "modules/common/CopyButton" +import { CopyAddress } from "modules/common/CopyAddress" + +const CustomTableContainer = styled(TableContainer)(({ theme }) => ({ + width: "inherit", + [theme.breakpoints.down("sm")]: {} +})) + +const CustomTableCell = styled(TableCell)(({ theme }) => ({ + [theme.breakpoints.down("sm")]: { + paddingBottom: 0, + paddingLeft: "16px !important", + textAlign: "end" + } +})) + +const CustomTableCellValue = styled(TableCell)(({ theme }) => ({ + [theme.breakpoints.down("sm")]: { + paddingTop: 0, + paddingRight: "16px !important", + textAlign: "end", + paddingBottom: 0 + } +})) + +const RowValue = styled(Typography)(({ theme }) => ({ + fontWeight: 300, + fontSize: 18, + [theme.breakpoints.down("sm")]: { + fontSize: 16 + } +})) + +export const EvmDaoSettingModal: React.FC<{ + open: boolean + handleClose: () => void +}> = ({ open, handleClose }) => { + const { daoSelected } = useContext(EtherlinkContext) + const theme = useTheme() + const isMobileSmall = useMediaQuery(theme.breakpoints.down("sm")) + + const tableData = [ + { + key: "DAO Contract Address", + value: daoSelected?.address + }, + { + key: "Treasury Address", + value: daoSelected?.treasuryAddress + }, + { + key: "Registry Address", + value: daoSelected?.registryAddress + }, + { + key: "Governance Token", + value: daoSelected?.token + }, + { + key: "Quorum", + value: daoSelected?.quorum + }, + { + key: "Proposal Threshold", + value: daoSelected?.proposalThreshold + }, + { + key: "Voting Duration (minutes", + value: daoSelected?.votingDuration + }, + { + key: "Voting Delay (minutes)", + value: daoSelected?.votingDelay + }, + { + key: "Execution Delay (minutes)", + value: daoSelected?.executionDelay + } + ] + + return ( + <> + + + + + {daoSelected?.id && + tableData.map((item: { key: string; value: string }) => ( + + + + {item.key} + + + + {typeof item.value === "string" && item?.value?.startsWith("0x") ? ( + + {isMobileSmall ? ( + + ) : ( + <> + + {item.value} + + + + )} + + ) : ( + {item.value} + )} + + + ))} + +
+
+
+ + ) +} diff --git a/src/modules/etherlink/components/EvmDaoStatsRow.tsx b/src/modules/etherlink/components/EvmDaoStatsRow.tsx new file mode 100644 index 00000000..2b37dbef --- /dev/null +++ b/src/modules/etherlink/components/EvmDaoStatsRow.tsx @@ -0,0 +1,72 @@ +import React, { useContext, useMemo } from "react" +import { Box, Grid, styled, useTheme, Typography, Paper } from "@material-ui/core" + +import { EtherlinkContext } from "services/wagmi/context" + +const Item = styled(Paper)(({ theme }) => ({ + backgroundColor: "#24282d", + borderRadius: 8, + color: theme.palette.text.primary, + height: 84, + display: "flex", + padding: "33px 40px 30px 40px", + flexDirection: "column", + gap: 8 +})) + +const ItemContent = styled(Grid)({ + gap: 8 +}) + +const ItemTitle = styled(Typography)(({ theme }) => ({ + fontSize: 18, + fontWeight: 500, + [theme.breakpoints.down("md")]: { + fontSize: 15 + } +})) + +const ItemValue = styled(Typography)(({ theme }) => ({ + fontSize: 32, + fontWeight: 300, + overflowX: "scroll", + cursor: "default", + [theme.breakpoints.down("sm")]: { + fontSize: 28 + } +})) + +export const EvmDaoStatsRow = () => { + const { daoSelected } = useContext(EtherlinkContext) + return ( + + + {[ + { + title: "Members", + value: daoSelected?.holders + }, + { + title: "Active Proposals", + value: daoSelected?.proposals?.length || "0" + }, + { + title: "Awaiting Executions", + value: daoSelected?.awaiting_executions || "-" + } + ].map((item, index) => ( + + + + {item.title} + + + {item.value} + + + + ))} + + + ) +} diff --git a/src/modules/etherlink/components/EvmProposalDetailCard.tsx b/src/modules/etherlink/components/EvmProposalDetailCard.tsx new file mode 100644 index 00000000..267ac5d6 --- /dev/null +++ b/src/modules/etherlink/components/EvmProposalDetailCard.tsx @@ -0,0 +1,218 @@ +import React from "react" +import { Grid, styled, Typography, Link, useTheme, useMediaQuery, Popover, withStyles } from "@material-ui/core" +import { GridContainer } from "modules/common/GridContainer" +import { ProposalStatus, TableStatusBadge } from "modules/lite/explorer/components/ProposalTableRowStatusBadge" +import { CreatorBadge } from "modules/lite/explorer/components/CreatorBadge" +import { FileCopyOutlined } from "@material-ui/icons" +import Share from "assets/img/share.svg" +import { CommunityBadge } from "modules/lite/explorer/components/CommunityBadge" +import LinkIcon from "assets/img/link.svg" +import { Poll } from "models/Polls" +import dayjs from "dayjs" +import { useNotification } from "modules/common/hooks/useNotification" +import ReactHtmlParser from "react-html-parser" + +const LogoItem = styled("img")(({ theme }) => ({ + cursor: "pointer", + [theme.breakpoints.down("sm")]: { + height: 10 + } +})) + +const TextContainer = styled(Typography)(({ theme }) => ({ + display: "flex", + alignItems: "center", + gap: 10, + marginRight: 8, + [theme.breakpoints.down("sm")]: { + marginTop: 20 + } +})) + +const EndTextContainer = styled(Typography)(({ theme }) => ({ + display: "flex", + alignItems: "center", + gap: 10, + marginRight: 8, + [theme.breakpoints.down("sm")]: { + marginTop: 20 + } +})) + +const EndText = styled(Typography)(({ theme }) => ({ + [theme.breakpoints.down("sm")]: { + marginTop: 20 + } +})) + +const Divider = styled(Typography)(({ theme }) => ({ + marginLeft: 8, + marginRight: 8, + [theme.breakpoints.down("sm")]: { + marginTop: 20 + } +})) + +const StyledLink = styled(Link)(({ theme }) => ({ + fontFamily: "Roboto Flex", + fontWeight: 300, + fontSize: 16, + marginLeft: 8, + [theme.breakpoints.down("sm")]: { + fontWeight: 100, + fontSize: 10 + } +})) + +const CopyIcon = styled(FileCopyOutlined)({ + marginRight: 8, + cursor: "pointer" +}) + +const CustomPopover = withStyles({ + paper: { + "marginTop": 10, + "padding": 8, + "cursor": "pointer", + "background": "#1c1f23 !important", + "&:hover": { + background: "#81feb76b !important" + } + } +})(Popover) + +export const EvmProposalDetailCard: React.FC<{ poll: Poll | undefined }> = ({ poll }) => { + const theme = useTheme() + const isMobileSmall = useMediaQuery(theme.breakpoints.down("sm")) + const [anchorEl, setAnchorEl] = React.useState(null) + const openNotification = useNotification() + + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(anchorEl ? null : event.currentTarget) + } + + const handleClose = () => { + setAnchorEl(null) + } + + const open = Boolean(anchorEl) + const id = open ? "simple-popper" : undefined + + const handleCopy = () => { + const url = location.href + navigator.clipboard.writeText(url) + openNotification({ + message: "Proposal link copied to clipboard!", + autoHideDuration: 3000, + variant: "success" + }) + handleClose() + } + + return ( + <> + + + + + + {poll?.name} + + + + + + + + + Share + + + + + + Copy link + + + + + + + + + + + + + + {/* */} + + + + + + + + + + Start date:{" "} + + + {dayjs(Number(poll?.startTime)).format("lll")} + + - + + End date:{" "} + + + {dayjs(Number(poll?.endTime)).format("lll")} + + + + + + + {ReactHtmlParser(poll?.description ? poll?.description : "")} + + + + {poll?.externalLink ? ( + + + + {poll?.externalLink} + + + ) : null} + + + + ) +} diff --git a/src/modules/etherlink/components/EvmProposalItem.tsx b/src/modules/etherlink/components/EvmProposalItem.tsx index c8948fca..680dd0ed 100644 --- a/src/modules/etherlink/components/EvmProposalItem.tsx +++ b/src/modules/etherlink/components/EvmProposalItem.tsx @@ -1,8 +1,8 @@ -import { Box, Grid, Theme, Typography, styled, useMediaQuery, useTheme } from "@material-ui/core" +import { Grid, Theme, Typography, styled } from "@material-ui/core" import dayjs from "dayjs" import React from "react" import { toShortAddress } from "services/contracts/utils" -import { Proposal, ProposalStatus } from "services/services/dao/mappers/proposal/types" +import { Proposal } from "services/services/dao/mappers/proposal/types" import { StatusBadge } from "modules/explorer/components/StatusBadge" const ContentBlockItem = styled(Grid)(({ theme }: { theme: Theme }) => ({ @@ -20,30 +20,6 @@ const CreatedText = styled(Typography)({ color: "#bfc5ca" }) -const getStatusByHistory = (history: { active: number; executable: number; passed: number; pending: number }) => { - const statuses = Object.keys(history) - const status = statuses.reduce((maxStatus, currentStatus) => { - return history[currentStatus as keyof typeof history] > history[maxStatus as keyof typeof history] - ? currentStatus - : maxStatus - }) - // TODO: @ashutoshpw, handle more statuses - switch (status) { - case "active": - return ProposalStatus.ACTIVE - case "pending": - return ProposalStatus.PENDING - case "rejected": - return ProposalStatus.REJECTED - case "accepted": - return ProposalStatus.ACTIVE - case "executed": - return ProposalStatus.EXECUTED - default: - return ProposalStatus.NO_QUORUM - } -} - export const EvmProposalItem: React.FC<{ proposal: Proposal | any }> = ({ proposal, children }) => { @@ -61,7 +37,7 @@ export const EvmProposalItem: React.FC<{ - + diff --git a/src/modules/etherlink/components/EvmProposalVoteDetail.tsx b/src/modules/etherlink/components/EvmProposalVoteDetail.tsx new file mode 100644 index 00000000..df2ead34 --- /dev/null +++ b/src/modules/etherlink/components/EvmProposalVoteDetail.tsx @@ -0,0 +1,235 @@ +/* eslint-disable @typescript-eslint/no-non-null-asserted-optional-chain */ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +import React, { useContext, useEffect, useMemo, useState } from "react" +import { Button, Grid, LinearProgress, styled, Typography, useMediaQuery, useTheme } from "@material-ui/core" +import { GridContainer } from "modules/common/GridContainer" +import { VotesDialog } from "modules/lite/explorer/components/VotesDialog" +import { Poll } from "models/Polls" +import { Choice } from "models/Choice" + +import { useTezos } from "services/beacon/hooks/useTezos" +import { getTurnoutValue } from "services/utils/utils" +import { useTokenDelegationSupported } from "services/contracts/token/hooks/useTokenDelegationSupported" +import { DownloadCsvFile } from "modules/lite/explorer/components/DownloadCsvFile" +import { EtherlinkContext } from "services/wagmi/context" + +const Container = styled(Grid)(({ theme }) => ({ + background: theme.palette.primary.main, + borderRadius: 8 +})) + +const TitleContainer = styled(Grid)(({ theme }) => ({ + paddingTop: 18, + paddingLeft: 46, + paddingRight: 46, + paddingBottom: 18, + borderBottom: `0.3px solid ${theme.palette.primary.light}`, + [theme.breakpoints.down("sm")]: { + padding: "18px 25px" + } +})) + +const LinearContainer = styled(GridContainer)({ + paddingBottom: 0, + minHeight: 110 +}) + +const LegendContainer = styled(GridContainer)({ + minHeight: 30, + paddingBottom: 0 +}) + +const GraphicsContainer = styled(Grid)({ + paddingBottom: 25 +}) + +export const EvmProposalVoteDetail: React.FC<{ + poll: Poll | undefined + choices: Choice[] + token: any + isXTZ: boolean +}> = ({ poll, choices, token, isXTZ }) => { + const theme = useTheme() + const isMobileSmall = useMediaQuery(theme.breakpoints.down("xs")) + const isMobile = useMediaQuery(theme.breakpoints.down("sm")) + const [open, setOpen] = React.useState(false) + const { network } = useTezos() + const [turnout, setTurnout] = useState() + const [votes, setVotes] = useState([]) + const { daoSelected, daoProposalSelected } = useContext(EtherlinkContext) + const tokenData = useMemo( + () => ({ + tokenAddress: daoSelected?.token, + tokenID: daoSelected?.id, + symbol: daoSelected?.symbol, + decimals: daoSelected?.decimals + }), + [daoSelected] + ) + const { data: isTokenDelegationSupported } = useTokenDelegationSupported(tokenData?.tokenAddress) + const totalVoteCount = daoProposalSelected?.votesFor + daoProposalSelected?.votesAgainst + + const handleClickOpen = () => { + setVotes(choices.filter(elem => elem.walletAddresses.length > 0)) + setOpen(true) + } + + const handleClose = () => { + setOpen(false) + } + + const formatConfig = { + average: true, + mantissa: 1, + thousandSeparated: true, + trimMantissa: true + } + + useMemo(async () => { + if (token && tokenData) { + const value = await getTurnoutValue( + network, + tokenData?.tokenAddress, + tokenData.tokenID, + Number(poll?.referenceBlock), + totalVoteCount + ) + if (value) { + setTurnout(value) + } + } + }, [poll, network, token, tokenData, totalVoteCount]) + + return ( + + {/* Disabled as Data is wrong in Firebase */} + {/* + + Voter Turnout + + + + + + + + + */} + + + Vorting Results + + + + {choices && + choices.map((choice: Choice, index) => { + const isFor = choice.name === "For" + const voteCount = isFor ? daoProposalSelected?.votesFor : daoProposalSelected?.votesAgainst + + const linearProgressValue = totalVoteCount > 0 ? (voteCount / totalVoteCount) * 100 : 0 + return ( + + + + + {choice.name} + + + + + {voteCount} Voters - {tokenData?.symbol} + + + + + + + + + + {linearProgressValue}% + + + + + ) + })} + + + + handleClickOpen()}> + {totalVoteCount} + + handleClickOpen()}> + Votes + + {isTokenDelegationSupported && turnout && !poll?.isXTZ ? ( + + ({turnout.toFixed(2)} % Turnout) + + ) : null} + + + + {/* + {numbro(calculateProposalTotal(choices, isXTZ ? 6 : tokenData?.decimals)).format(formatConfig)} + + + {isXTZ ? "XTZ" : poll?.tokenSymbol} + */} + + {/* {!poll?.isXTZ && ( + + ( + {getTreasuryPercentage( + calculateProposalTotal(choices, isXTZ ? 6 : tokenData?.decimals), + poll?.totalSupplyAtReferenceBlock, + isXTZ ? 6 : tokenData?.decimals + ) + .dp(5, 1) + .toString()} + % of Total Supply) + + )} */} + {totalVoteCount > 0 ? ( + + ) : null} + + + + + + ) +} diff --git a/src/modules/etherlink/components/VotingPowerWidget.tsx b/src/modules/etherlink/components/VotingPowerWidget.tsx new file mode 100644 index 00000000..9e9b6a93 --- /dev/null +++ b/src/modules/etherlink/components/VotingPowerWidget.tsx @@ -0,0 +1,154 @@ +import React, { useState, useEffect } from "react" +import { Box, Select, MenuItem, Typography, Slider, Paper, styled, SelectChangeEvent, Grid } from "@mui/material" +import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown" + +export interface Org { + symbol: string +} + +export interface Member { + name: string + votingWeight: number +} + +// TODO: @ashutoshpw Replace with actual data +export const generateMembers = (): Member[] => { + return Array.from({ length: 100 }, (_, index) => ({ + name: `Member ${index + 1}`, + votingWeight: Math.random() * 100 + 1 + })) +} + +const StyledPaper = styled(Paper)(({ theme }) => ({ + minWidth: 520, + height: 30, + backgroundColor: theme.palette.grey[200], + display: "flex", + alignItems: "center", + justifyContent: "center" +})) + +const StyledSelect = styled(Select)(({ theme }) => ({ + "& .MuiSelect-select": { + paddingRight: theme.spacing(4), + fontWeight: 600, + backgroundColor: "transparent" + }, + "&:before, &:after": { + display: "none" + } +})) + +export const VotingPowerStats: React.FC<{ + membersCount: number + membersPercentage: number + votingPower: number + votingPowerPercentage: number +}> = ({ membersCount, membersPercentage, votingPower, votingPowerPercentage }) => { + return ( + + + + Number of Members + + + {membersCount} + + + {membersPercentage.toFixed(2)}% + + + + + Voting Power + + + {votingPower.toFixed(2)} + + + {votingPowerPercentage.toFixed(2)}% + + + + ) +} + +export const VotingPowerWidget: React.FC<{ tokenSymbol: string }> = ({ tokenSymbol }) => { + const [sliderValue, setSliderValue] = useState(1) + const [members, setMembers] = useState([]) + const [selectedFeature, setSelectedFeature] = useState("vote concentration") + const concentrationOptions = ["vote concentration", `${tokenSymbol} ownership`] + + useEffect(() => { + const initialMembers = generateMembers() + initialMembers.sort((a, b) => b.votingWeight - a.votingWeight) + setMembers(initialMembers) + }, []) + + const totalMembers = members.length + const totalVotingPower = members.reduce((sum, member) => sum + member.votingWeight, 0) + const percentageOfMembers = 101 - sliderValue + const membersToInclude = Math.max(1, Math.round((percentageOfMembers / 100) * totalMembers)) + const selectedMembers = members.slice(0, membersToInclude) + const cumulativeVotingPower = selectedMembers.reduce((sum, member) => sum + member.votingWeight, 0) + + const membersPercentage = (membersToInclude / totalMembers) * 100 + const votingPowerPercentage = (cumulativeVotingPower / totalVotingPower) * 100 + + return ( + + + + Drag slider to check + + + { + setSelectedFeature(event.target.value) + }} + IconComponent={KeyboardArrowDownIcon} + variant="standard" + > + {concentrationOptions.map(option => ( + + {option} + + ))} + + + + + + + + + setSliderValue(value as number)} + min={1} + max={100} + sx={{ width: 430 }} + /> + + + + ) +} diff --git a/src/modules/etherlink/explorer/EtherlinkDAO/EvmMembersPage.tsx b/src/modules/etherlink/explorer/EtherlinkDAO/EvmMembersPage.tsx index deb8e0f9..3699a972 100644 --- a/src/modules/etherlink/explorer/EtherlinkDAO/EvmMembersPage.tsx +++ b/src/modules/etherlink/explorer/EtherlinkDAO/EvmMembersPage.tsx @@ -3,6 +3,7 @@ import { TitleText } from "components/ui/TitleText" import { EvmMembersTable } from "modules/etherlink/components/EvmMembersTable" import { EtherlinkContext } from "services/wagmi/context" import { useContext } from "react" +import { VotingPowerWidget } from "modules/etherlink/components/VotingPowerWidget" export const EvmMembersPage = () => { const { daoMembers } = useContext(EtherlinkContext) @@ -16,10 +17,14 @@ export const EvmMembersPage = () => { console.log("daoMemberData", daoMemberData, daoMembers) return ( - + Members + + + + diff --git a/src/modules/etherlink/explorer/EtherlinkDAO/EvmProposalDetailsPage.tsx b/src/modules/etherlink/explorer/EtherlinkDAO/EvmProposalDetailsPage.tsx index a6732bd8..465bcb95 100644 --- a/src/modules/etherlink/explorer/EtherlinkDAO/EvmProposalDetailsPage.tsx +++ b/src/modules/etherlink/explorer/EtherlinkDAO/EvmProposalDetailsPage.tsx @@ -1,3 +1,107 @@ +import { ArrowBackIosOutlined } from "@mui/icons-material" +import { GridContainer } from "modules/common/GridContainer" +import { Button, Grid, Typography, useMediaQuery, useTheme } from "@mui/material" +import { PageContainer } from "components/ui/DaoCreator" +import { ProposalDetailCard } from "modules/lite/explorer/components/ProposalDetailCard" +import { useContext, useEffect } from "react" +import { useParams } from "react-router-dom" +import { EtherlinkContext } from "services/wagmi/context" +import { ProposalStatus } from "services/services/dao/mappers/proposal/types" +import { EvmProposalDetailCard } from "modules/etherlink/components/EvmProposalDetailCard" +import { ChoiceItemSelected } from "modules/lite/explorer/components/ChoiceItemSelected" +import { EvmProposalVoteDetail } from "modules/etherlink/components/EvmProposalVoteDetail" export const EvmProposalDetailsPage = () => { - return
Proposal Details
+ const params = useParams() as { proposalId: string } + const proposalId = params?.proposalId + + const { daoSelected, daoProposalSelected, selectDaoProposal } = useContext(EtherlinkContext) + const theme = useTheme() + const isMobileSmall = useMediaQuery(theme.breakpoints.down("sm")) + + useEffect(() => { + selectDaoProposal(proposalId) + }, [proposalId, selectDaoProposal]) + + const choices = [ + { + name: "For", + pollID: "1", + walletAddresses: [], + selected: true + }, + { + name: "Against", + pollID: "1", + walletAddresses: [], + selected: false + } + ] + console.log("daoProposalSelected", daoProposalSelected) + + return ( +
+ Proposal Details + + + + + + + {choices && choices.length > 0 ? ( + + + {/* {[choices].map((choice, index) => { + return ( + {}} + /> + ) + })} */} + + {/* {poll?.isActive === ProposalStatus.ACTIVE ? ( + + ) : null} */} + + ) : null} + + + + {/* {poll && poll !== undefined ? ( + + ) : null} */} + + + +
+ ) } diff --git a/src/modules/etherlink/explorer/EtherlinkDAO/EvmRegistryPage.tsx b/src/modules/etherlink/explorer/EtherlinkDAO/EvmRegistryPage.tsx index 88f75fa7..e2b88585 100644 --- a/src/modules/etherlink/explorer/EtherlinkDAO/EvmRegistryPage.tsx +++ b/src/modules/etherlink/explorer/EtherlinkDAO/EvmRegistryPage.tsx @@ -89,7 +89,7 @@ export const EvmRegistryPage: React.FC = () => { Registry {dao && ( { const daoId = useEtherlinkDAOID() const { data, cycleInfo, ledger } = useDAO(daoId) + const { daoSelected } = useContext(EtherlinkContext) - console.log("explorer/index.tsx", data) const theme = useTheme() const isExtraSmall = useMediaQuery(theme.breakpoints.down("xs")) - const symbol = (data && data.data.token?.symbol?.toUpperCase()) || "Unknown" + const symbol = (daoSelected && daoSelected?.token?.toUpperCase()) || "Unknown" - const name = data && data.data.name - const description = data && data.data.description + const name = daoSelected && daoSelected?.name + const description = daoSelected && daoSelected?.description const [openDialog, setOpenDialog] = useState(false) const [openChangeDialog, setChangeOpenDialog] = useState(false) @@ -45,28 +40,6 @@ export const EtherlinkDAOOverview: React.FC = () => { setChangeOpenDialog(false) } - const usersTableData = useMemo(() => { - if (data?.data?.meta?.users) { - return data.data.meta.users - } - - if (!ledger || !cycleInfo || !data) { - return [] - } - - return ledger - .sort((a, b) => b.available_balance.minus(a.available_balance).toNumber()) - .map(p => ({ - address: p.holder.address, - totalStaked: new BigNumber(p.total_balance).dp(10, 1).toString(), - availableStaked: new BigNumber(p.available_balance).dp(10, 1).toString(), - votes: p.holder.votes_cast.toString(), - proposalsVoted: p.holder.proposals_voted.toString() - })) - }, [cycleInfo, data, ledger]) - - console.log({ usersTableData }) - return ( @@ -83,7 +56,7 @@ export const EtherlinkDAOOverview: React.FC = () => { View Settings - {/* */} + setChangeOpenDialog(true)}> @@ -94,86 +67,70 @@ export const EtherlinkDAOOverview: React.FC = () => {
- {data?.data.network?.startsWith("etherlink") ? ( - <> - - - - DAO Contract - - - {data?.data.address || "-"} - { - if (data?.data.address) { - navigator.clipboard.writeText(data.data.address) - } - }} - size="small" - style={{ marginLeft: "8px", color: theme.palette.primary.light }} - > - - - - - - - Governance Token - - - {data?.data.token.symbol || "-"} - { - if (data?.data.token.symbol) { - navigator.clipboard.writeText(data.data.token.symbol) - } - }} - size="small" - style={{ marginLeft: "8px" }} - > - - - - - - {description} - - -
- - ) : ( - {description} - )} + + + + DAO Contract + + + {daoSelected?.address || "-"} + { + if (daoSelected?.address) { + navigator.clipboard.writeText(daoSelected.address) + } + }} + size="small" + style={{ marginLeft: "8px", color: theme.palette.primary.light }} + > + + + + + + + Governance Token + + + {daoSelected?.token || "-"} + { + if (daoSelected?.token) { + navigator.clipboard.writeText(daoSelected.token) + } + }} + size="small" + style={{ marginLeft: "8px" }} + > + + + + + + {description} + + +
- - - - {/* */} - +
) } diff --git a/src/modules/explorer/pages/Proposals/index.tsx b/src/modules/explorer/pages/Proposals/index.tsx index 1e75e58b..2252196f 100644 --- a/src/modules/explorer/pages/Proposals/index.tsx +++ b/src/modules/explorer/pages/Proposals/index.tsx @@ -348,7 +348,7 @@ export const EtherlinkProposals = () => { const theme = useTheme() // const isMobileSmall = useMediaQuery(theme.breakpoints.down("xs")) const [openDialog, setOpenDialog] = useState(false) - + console.log({ daoProposals }) const handleCloseModal = () => { setOpenDialog(false) } diff --git a/src/services/wagmi/context.tsx b/src/services/wagmi/context.tsx index a891b41f..78d3568d 100644 --- a/src/services/wagmi/context.tsx +++ b/src/services/wagmi/context.tsx @@ -6,6 +6,8 @@ import { etherlink, etherlinkTestnet } from "wagmi/chains" import { useSIWE, useModal, SIWESession } from "connectkit" import { useEthersProvider, useEthersSigner } from "./ethers" import useFirestoreStore from "services/contracts/etherlinkDAO/hooks/useFirestoreStore" +import { useParams } from "react-router-dom" +import { Proposal, ProposalStatus } from "services/services/dao/mappers/proposal/types" interface EtherlinkType { isConnected: boolean @@ -19,6 +21,31 @@ interface EtherlinkType { disconnect: () => void } +// TODO: @ashutoshpw, handle more statuus and move to utils +const getStatusByHistory = (history: { active: number; executable: number; passed: number; pending: number }) => { + const statuses = Object.keys(history) + const status = statuses.reduce((maxStatus, currentStatus) => { + return history[currentStatus as keyof typeof history] > history[maxStatus as keyof typeof history] + ? currentStatus + : maxStatus + }) + // TODO: @ashutoshpw, handle more statuses + switch (status) { + case "active": + return ProposalStatus.ACTIVE + case "pending": + return ProposalStatus.PENDING + case "rejected": + return ProposalStatus.REJECTED + case "accepted": + return ProposalStatus.ACTIVE + case "executed": + return ProposalStatus.EXECUTED + default: + return ProposalStatus.NO_QUORUM + } +} + export const EtherlinkContext = createContext(undefined) export const EtherlinkProvider: React.FC<{ children: ReactNode }> = ({ children }) => { @@ -66,6 +93,7 @@ export const EtherlinkProvider: React.FC<{ children: ReactNode }> = ({ children const [daoData, setDaoData] = useState([]) const [daoSelected, setDaoSelected] = useState({}) const [daoProposals, setDaoProposals] = useState([]) + const [daoProposalSelectedId, setDaoProposalSelectedId] = useState(null) const [daoProposalSelected, setDaoProposalSelected] = useState({}) const [daoMembers, setDaoMembers] = useState([]) const { data: firestoreData, loading, fetchCollection } = useFirestoreStore() @@ -83,7 +111,16 @@ export const EtherlinkProvider: React.FC<{ children: ReactNode }> = ({ children } const daoProposalKey = `daosEtherlink-Testnet/${daoSelected.id}/proposals` if (firestoreData?.[daoProposalKey]) { - setDaoProposals(firestoreData[daoProposalKey]?.sort((a: any, b: any) => b.createdAt - a.createdAt)) + setDaoProposals( + firestoreData[daoProposalKey] + ?.sort((a: any, b: any) => b.createdAt - a.createdAt) + .map(firebaseProposal => { + return { + ...firebaseProposal, + status: getStatusByHistory(firebaseProposal.statusHistory) + } + }) + ) } const daoMembersKey = `daosEtherlink-Testnet/${daoSelected.id}/members` if (firestoreData?.[daoMembersKey]) { @@ -120,6 +157,13 @@ export const EtherlinkProvider: React.FC<{ children: ReactNode }> = ({ children daoProposals: daoProposals, daoProposalSelected: daoProposalSelected, daoMembers: daoMembers, + selectDaoProposal: (proposalId: string) => { + const proposal = daoProposals.find((proposal: any) => proposal.id === proposalId) + if (proposal) { + setDaoProposalSelected(proposal) + // fetchCollection(`daosEtherlink-Testnet/${daoSelected.id}/proposals/${proposalId}`) + } + }, selectDao: (daoId: string) => { const dao = daoData.find(dao => dao.id === daoId) // alert(`dao:${daoId}`)