diff --git a/package.json b/package.json index 57352315..33ce9bc4 100644 --- a/package.json +++ b/package.json @@ -18,14 +18,15 @@ "@airgap/beacon-sdk": "^4.0.10", "@craco/craco": "^7.1.0", "@date-io/dayjs": "1.x", - "@emotion/react": "^11.10.4", - "@emotion/styled": "^11.10.4", + "@emotion/react": "^11.11.1", + "@emotion/styled": "^11.11.0", "@hookform/resolvers": "^2.8.1", "@material-ui/core": "^4.11.3", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "^4.0.0-alpha.57", "@microsoft/signalr": "^5.0.9", - "@mui/material": "^5.10.6", + "@mui/icons-material": "^5.14.14", + "@mui/material": "^5.14.14", "@mui/x-date-pickers": "^5.0.2", "@taquito/beacon-wallet": "^17.3.1", "@taquito/signer": "^17.3.1", @@ -50,11 +51,13 @@ "graphql": "^15.5.1", "graphql-request": "^3.4.0", "hex-to-rgba": "^2.0.1", + "html-react-parser": "^5.0.6", "https-browserify": "^1.0.0", "jsonschema": "^1.4.0", "launchdarkly-react-client-sdk": "2.27.0", "mixpanel-browser": "^2.42.0", "notistack": "^1.0.3", + "numbro": "^2.4.0", "os-browserify": "^0.3.0", "prism-themes": "^1.9.0", "prismjs": "^1.28.0", diff --git a/public/manifest.json b/public/manifest.json index 8ffbe43c..9a35ab33 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -3,7 +3,7 @@ "name": "Tezos dApp for creating and interacting with DAOs using BaseDAO framework", "icons": [ { - "src": "favicon.svg", + "src": "favicon.png", "sizes": "64x64 32x32 24x24 16x16", "type": "image/svg+xml" } diff --git a/src/App.tsx b/src/App.tsx index 46febaf3..81d1584e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -18,7 +18,7 @@ import { Landing } from "modules/home/Landing" import { WarningFooter } from "modules/common/WarningFooter" import { ActionSheetProvider } from "modules/explorer/context/ActionSheets" import { legacyTheme } from "theme/legacy" -import { Footer } from "modules/common/Footer" +import { ExplorerFooter } from "modules/common/Footer" import { FAQ } from "modules/home/FAQ" import { EnvKey, HUMANITEZ_DAO, getEnv } from "services/config" import { DAOCreatorRouter } from "modules/creator/router" @@ -134,15 +134,12 @@ const App: React.FC = () => { /> ) : null} - + - - - - + diff --git a/src/assets/img/copy_icon.svg b/src/assets/img/copy_icon.svg new file mode 100644 index 00000000..25e5b759 --- /dev/null +++ b/src/assets/img/copy_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/my-daos-icon.svg b/src/assets/img/my-daos-icon.svg new file mode 100644 index 00000000..b8b81702 --- /dev/null +++ b/src/assets/img/my-daos-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/my-daos-selected-icon.svg b/src/assets/img/my-daos-selected-icon.svg new file mode 100644 index 00000000..5f90848c --- /dev/null +++ b/src/assets/img/my-daos-selected-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/tabs-icon-selected.svg b/src/assets/img/tabs-icon-selected.svg new file mode 100644 index 00000000..aa377d42 --- /dev/null +++ b/src/assets/img/tabs-icon-selected.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/tabs-icon.svg b/src/assets/img/tabs-icon.svg new file mode 100644 index 00000000..3592db60 --- /dev/null +++ b/src/assets/img/tabs-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/img/tz_circle.svg b/src/assets/img/tz_circle.svg new file mode 100644 index 00000000..5df3e512 --- /dev/null +++ b/src/assets/img/tz_circle.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/logos/footer_discord.svg b/src/assets/logos/footer_discord.svg new file mode 100644 index 00000000..44aa5da4 --- /dev/null +++ b/src/assets/logos/footer_discord.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/assets/logos/footer_documentation.svg b/src/assets/logos/footer_documentation.svg new file mode 100644 index 00000000..87b585d2 --- /dev/null +++ b/src/assets/logos/footer_documentation.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/logos/footer_dorg.svg b/src/assets/logos/footer_dorg.svg new file mode 100644 index 00000000..39472191 --- /dev/null +++ b/src/assets/logos/footer_dorg.svg @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/logos/footer_explorer.svg b/src/assets/logos/footer_explorer.svg new file mode 100644 index 00000000..af8a14b0 --- /dev/null +++ b/src/assets/logos/footer_explorer.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/logos/footer_github.svg b/src/assets/logos/footer_github.svg new file mode 100644 index 00000000..d176fdd0 --- /dev/null +++ b/src/assets/logos/footer_github.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/logos/footer_help.svg b/src/assets/logos/footer_help.svg new file mode 100644 index 00000000..56f8f667 --- /dev/null +++ b/src/assets/logos/footer_help.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/logos/footer_logo.svg b/src/assets/logos/footer_logo.svg new file mode 100644 index 00000000..c1c3e088 --- /dev/null +++ b/src/assets/logos/footer_logo.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/assets/logos/footer_tezos.svg b/src/assets/logos/footer_tezos.svg new file mode 100644 index 00000000..186f1351 --- /dev/null +++ b/src/assets/logos/footer_tezos.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/logos/footer_youtube.svg b/src/assets/logos/footer_youtube.svg new file mode 100644 index 00000000..ba7f5acf --- /dev/null +++ b/src/assets/logos/footer_youtube.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/logos/homebase-logo.svg b/src/assets/logos/homebase-logo.svg new file mode 100644 index 00000000..7270dd82 --- /dev/null +++ b/src/assets/logos/homebase-logo.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/modules/common/ChangeNetworkButton.tsx b/src/modules/common/ChangeNetworkButton.tsx index 165c1b27..3fecf538 100644 --- a/src/modules/common/ChangeNetworkButton.tsx +++ b/src/modules/common/ChangeNetworkButton.tsx @@ -10,8 +10,11 @@ const StyledConnectedButton = styled(Box)(({ theme }: { theme: Theme }) => ({ height: "100%" }, "background": theme.palette.primary.dark, - "borderRadius": 4, - "padding": "5px 10px", + "borderRadius": 8, + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 5, + "paddingBottom": 6, "cursor": "pointer", "transition": ".15s ease-out", @@ -33,11 +36,6 @@ export const ColorDot = styled(Box)({ borderRadius: "50%" }) -const NetworkText = styled(Typography)({ - fontSize: "14px", - color: "#ddd" -}) - export const ChangeNetworkButton = () => { const { network } = useTezos() const { open } = useActionSheet(ActionSheet.Network) @@ -51,12 +49,14 @@ export const ChangeNetworkButton = () => { <> {canShow ? ( open()}> - + - {capitalize(network)} + + {capitalize(network)} + diff --git a/src/modules/common/Footer.tsx b/src/modules/common/Footer.tsx index a3447a16..e92f5899 100644 --- a/src/modules/common/Footer.tsx +++ b/src/modules/common/Footer.tsx @@ -1,11 +1,208 @@ -import { Grid, styled } from "@material-ui/core" +import React from "react" +import { Grid, Typography, styled, useMediaQuery, useTheme } from "@material-ui/core" +import HomeButton from "assets/logos/footer_logo.svg" +import Documentation from "assets/logos/footer_documentation.svg" +import Help from "assets/logos/footer_help.svg" +import Tezos from "assets/logos/footer_tezos.svg" +import Explorer from "assets/logos/footer_explorer.svg" +import Github from "assets/logos/footer_github.svg" +import Discord from "assets/logos/footer_discord.svg" +import Youtube from "assets/logos/footer_youtube.svg" +import dOrg from "assets/logos/footer_dorg.svg" +import { useTezos } from "services/beacon/hooks/useTezos" -export const Footer = styled(Grid)(({ theme }) => ({ +const Footer = styled(Grid)(({ theme }) => ({ width: "100%", - height: 60, - background: theme.palette.primary.dark, + height: "126px", + backgroundColor: "#24282d", + paddingTop: 40, + paddingBottom: 40, + marginTop: 32, + [theme.breakpoints.down("sm")]: { + height: "auto", + paddingTop: 30, + paddingBottom: 30 + } +})) + +const LogoItem = styled("img")({ + opacity: 0.65, + cursor: "pointer" +}) + +const HomebaseLogoItem = styled("img")({ + opacity: 0.65, + cursor: "default" +}) - ["@media (max-width:960px)"]: { - height: 100 +const ItemText = styled(Typography)({ + fontSize: 15, + opacity: 0.65, + cursor: "pointer" +}) + +const DesignedByText = styled(Typography)({ + fontSize: 13.5, + opacity: 0.65, + fontWeight: 300 +}) + +const BottomContainer = styled(Grid)(({ theme }) => ({ + [theme.breakpoints.down("sm")]: { + gap: 12 } })) + +const Container = styled(Grid)(({ theme }) => ({ + margin: "auto", + width: 1000, + ["@media (max-width: 1425px)"]: {}, + + ["@media (max-width:1335px)"]: {}, + + ["@media (max-width:1167px)"]: { + width: "86vw" + }, + + ["@media (max-width:1030px)"]: {}, + + ["@media (max-width:960px)"]: {} +})) + +export const ExplorerFooter: React.FC = () => { + const theme = useTheme() + const isMobileSmall = useMediaQuery(theme.breakpoints.down("sm")) + const { network } = useTezos() + + const goToFAQ = () => { + window.open("https://faq.tezos-homebase.io/homebase-faq/", "_blank") + } + + const goToExplorer = () => { + return network === "ghostnet" + ? window.open("https://ghostnet.tzkt.io/", "_blank") + : window.open("https://tzkt.io/", "_blank") + } + + const goToTezos = () => { + window.open("https://tezos.com/", "_blank") + } + + const goToGithub = () => { + window.open("https://github.com/dOrgTech/homebase-app", "_blank") + } + + const goToDiscord = () => { + window.open("https://discord.com/invite/yXaPy6s5Nr", "_blank") + } + + const goToYoutube = () => { + window.open("https://www.youtube.com/@Tezos", "_blank") + } + + const goTodOrg = () => { + window.open("https://www.dorg.tech/", "_blank") + } + + return ( +
+ + + + + + {!isMobileSmall ? : null} + + + + + Documentation + + + + Help + + + + Tezos + + + + TzKT Explorer + + + + + + + + + + + Designed & Developed by + + + + +
+ ) +} diff --git a/src/modules/common/Toolbar.tsx b/src/modules/common/Toolbar.tsx index 4445e8a1..8c63683a 100644 --- a/src/modules/common/Toolbar.tsx +++ b/src/modules/common/Toolbar.tsx @@ -2,7 +2,6 @@ import React, { useState } from "react" import { AppBar, Toolbar, - Button, styled, Typography, Box, @@ -15,7 +14,7 @@ import { import { useHistory } from "react-router-dom" import { TezosToolkit } from "@taquito/taquito" -import HomeButton from "assets/logos/homebase_logo.svg" +import HomeButton from "assets/logos/homebase-logo.svg" import { useTezos } from "services/beacon/hooks/useTezos" import { toShortAddress } from "services/contracts/utils" import { ExitToAppOutlined, FileCopyOutlined } from "@material-ui/icons" @@ -106,20 +105,21 @@ const AddressContainer = styled(Grid)({ const LogoText = styled(Typography)({ fontWeight: "bold", - fontSize: "24px", + fontSize: "26px", cursor: "pointer", fontFamily: "Roboto", letterSpacing: "initial" }) -const AddressBarWrapper = styled(Grid)({ - "boxSizing": "border-box", - "padding": "8px 16px", - "borderRadius": 4, - "&:hover": { - background: "rgba(129, 254, 183, 0.03)" - } -}) +const AddressBarWrapper = styled(Grid)(({ theme }) => ({ + borderRadius: 8, + background: theme.palette.primary.main, + paddingLeft: 16, + paddingRight: 16, + paddingTop: 5, + paddingBottom: 6, + boxSizing: "border-box" +})) const LogoItem = styled("img")({ height: "30px", @@ -249,7 +249,7 @@ export const Navbar: React.FC<{ - + diff --git a/src/modules/explorer/components/ChangeNetworkButton.tsx b/src/modules/explorer/components/ChangeNetworkButton.tsx index ac15c03d..d2f484ef 100644 --- a/src/modules/explorer/components/ChangeNetworkButton.tsx +++ b/src/modules/explorer/components/ChangeNetworkButton.tsx @@ -10,8 +10,11 @@ const StyledConnectedButton = styled(Box)(({ theme }: { theme: Theme }) => ({ height: "100%" }, "background": theme.palette.primary.main, - "borderRadius": 4, - "padding": "5px 10px", + "borderRadius": 8, + "paddingLeft": 16, + "paddingRight": 16, + "paddingTop": 5, + "paddingBottom": 6, "cursor": "pointer", "transition": ".15s ease-out", @@ -33,10 +36,6 @@ export const ColorDot = styled(Box)({ borderRadius: "50%" }) -const NetworkText = styled(Typography)({ - fontSize: "14px" -}) - export const ChangeNetworkButton = () => { const { network } = useTezos() const { open } = useActionSheet(ActionSheet.Network) @@ -50,12 +49,14 @@ export const ChangeNetworkButton = () => { <> {canShow ? ( open()}> - + - {capitalize(network)} + + {capitalize(network)} + diff --git a/src/modules/explorer/components/CopyButton.tsx b/src/modules/explorer/components/CopyButton.tsx index a33ec8a7..44fa14cf 100644 --- a/src/modules/explorer/components/CopyButton.tsx +++ b/src/modules/explorer/components/CopyButton.tsx @@ -1,16 +1,11 @@ import React, { useState } from "react" -import { Box, styled, Tooltip } from "@material-ui/core" -import { FileCopyOutlined } from "@material-ui/icons" - -const CopyIcon = styled(FileCopyOutlined)({ - cursor: "pointer" -}) +import { Box, Tooltip } from "@material-ui/core" +import { ReactComponent as CopyIcon } from "assets/img/copy_icon.svg" export const CopyButton: React.FC<{ text: string }> = ({ text }) => { const [copied, setCopied] = useState(false) return ( { navigator.clipboard.writeText(text) @@ -22,7 +17,7 @@ export const CopyButton: React.FC<{ text: string }> = ({ text }) => { }} > - + ) diff --git a/src/modules/explorer/components/DAOStatsRow.tsx b/src/modules/explorer/components/DAOStatsRow.tsx index 7f196af7..f959740a 100644 --- a/src/modules/explorer/components/DAOStatsRow.tsx +++ b/src/modules/explorer/components/DAOStatsRow.tsx @@ -1,131 +1,69 @@ import React, { useMemo } from "react" -import { ReactComponent as VotingPeriodIcon } from "assets/logos/votingPeriod.svg" -import ProgressBar from "react-customizable-progressbar" -import { Box, Grid, styled, SvgIcon, LinearProgress, useTheme, Typography, useMediaQuery } from "@material-ui/core" -import { ContentContainer } from "./ContentContainer" -import { CycleDescription } from "./CycleDescription" +import { Box, Grid, styled, useTheme, Typography, Paper } from "@material-ui/core" import { useDAO } from "services/services/dao/hooks/useDAO" import { useProposals } from "services/services/dao/hooks/useProposals" import BigNumber from "bignumber.js" import { ProposalStatus } from "services/services/dao/mappers/proposal/types" import { useDAOID } from "../pages/DAO/router" -import { useTimeLeftInCycle } from "../hooks/useTimeLeftInCycle" import { usePolls } from "modules/lite/explorer/hooks/usePolls" import dayjs from "dayjs" - -const StatsContainer = styled(ContentContainer)(({ theme }) => ({ - padding: "38px 38px", - maxHeight: "310px", - - ["@media (max-width:1030px)"]: { - maxHeight: "303px" - }, - - ["@media (max-width:831px)"]: { - minWidth: "99%" - }, - - ["@media (max-width:390px)"]: { - maxHeight: "340px" - } -})) - -const LockedTokensBar = styled(LinearProgress)(({ theme }) => ({ - "width": "100%", - "height": "8px", - "marginTop": "15px", - "marginBottom": "43px", - "&.MuiLinearProgress-colorSecondary": { - background: theme.palette.primary.light - }, - - ["@media (max-width:1030px)"]: { - marginTop: "13px", - marginBottom: "40px" - } +import AccountBalanceWalletIcon from "@mui/icons-material/AccountBalanceWallet" +import FiberSmartRecordIcon from "@mui/icons-material/FiberSmartRecord" +import LockIcon from "@mui/icons-material/Lock" +import HowToVoteIcon from "@mui/icons-material/HowToVote" +import PaletteIcon from "@mui/icons-material/Palette" +import { ReactComponent as TzIcon } from "assets/img/tz_circle.svg" +import { formatNumber } from "../utils/FormatNumber" +import { useDAOHoldings, useDAONFTHoldings } from "services/contracts/baseDAO/hooks/useDAOHoldings" + +const Item = styled(Paper)(({ theme }) => ({ + backgroundColor: theme.palette.primary.main, + borderRadius: 8, + color: theme.palette.text.primary, + height: 84, + display: "flex", + padding: "33px 40px 30px 40px", + flexDirection: "column", + gap: 8 })) -const IconContainer = styled(SvgIcon)({ - width: "auto", - height: 64 -}) - -const ProgressContainer = styled(Box)({ - marginLeft: "-18px", - marginTop: "-20px", - marginBottom: "-5px" - - // ["@media (max-width:1030px)"]: { - // marginBottom: "-7px" - // }, +const ItemContent = styled(Grid)({ + gap: 8 }) -const ProposalInfoTitle = styled(Typography)({ - fontSize: "18px", - - ["@media (max-width:1155px)"]: { - whiteSpace: "nowrap" - }, - - ["@media (max-width:1030px)"]: { - fontSize: "16.3px", - whiteSpace: "initial" - }, - - ["@media (max-width:830.99px)"]: { - fontSize: "18px" - }, - - ["@media (max-width:409.99px)"]: { - fontSize: "16px" +const ItemTitle = styled(Typography)(({ theme }) => ({ + fontSize: 18, + fontWeight: 600, + [theme.breakpoints.down("md")]: { + fontSize: 15 } -}) +})) -const LargeNumber = styled(Typography)(({ theme }) => ({ - fontSize: "36px", +const ItemValue = styled(Typography)(({ theme }) => ({ + fontSize: 36, fontWeight: 300, - color: theme.palette.text.primary, - marginTop: "7px", - - ["@media (max-width:1030px)"]: { - fontSize: "30px" + [theme.breakpoints.down("sm")]: { + fontSize: 28 } })) -const CycleTime = styled(Typography)(({ theme }) => ({ +const Percentage = styled(Typography)({ + fontSize: 18, fontWeight: 300, - color: theme.palette.text.primary, - fontSize: "20px", - - ["@media (max-width:1030px)"]: { - fontSize: "16px" - }, - - ["@media (max-width:830.99px)"]: { - fontSize: "20px" - }, - - ["@media (max-width:434px)"]: { - fontSize: "18px" - }, - - ["@media (max-width:409.99px)"]: { - fontSize: "15px" - } -})) + marginTop: 20, + paddingLeft: 18 +}) export const DAOStatsRow: React.FC = () => { const daoId = useDAOID() - const { data, cycleInfo, ledger } = useDAO(daoId) - + const { data, ledger } = useDAO(daoId) const symbol = data && data.data.token.symbol.toUpperCase() - const blocksLeft = cycleInfo && cycleInfo.blocksLeft const theme = useTheme() - const isExtraSmall = useMediaQuery(theme.breakpoints.down("xs")) const { data: activeProposals } = useProposals(daoId, ProposalStatus.ACTIVE) - const { hours, minutes, days } = useTimeLeftInCycle() const { data: polls } = usePolls(data?.liteDAOData?._id) const activeLiteProposals = polls?.filter(p => Number(p.endTime) > dayjs().valueOf()) + const { tokenHoldings } = useDAOHoldings(daoId) + const { nftHoldings } = useDAONFTHoldings(daoId) const amountLocked = useMemo(() => { if (!ledger) { @@ -151,91 +89,80 @@ export const DAOStatsRow: React.FC = () => { const amountLockedPercentage = totalTokens ? amountLocked.div(totalTokens).multipliedBy(100) : new BigNumber(0) return ( - - - - + + + + + + + Total {symbol} + - + {formatNumber(totalTokens)} + + + + + + + Voting Addresses + - - - - - - - - Current Cycle - {cycleInfo?.currentCycle} - - + {data?.data.ledger.length || "-"} + + + + + + + Tokens + - - - - - - - - - Time Left In Cycle - - - {days}d {hours}h {minutes}m ({cycleInfo?.blocksLeft} blocks) - - - + {tokenHoldings.length || "-"} + + + + + + + {symbol} Locked + + + {formatNumber(amountLocked)} + {formatNumber(amountLockedPercentage)}% - - - - + + + + + + + Active Proposals + - - - {symbol} Locked - - - {amountLocked.dp(10, 1).toString()} - - - - - + + {" "} + {activeLiteProposals + ? Number(activeProposals?.length) + Number(activeLiteProposals?.length) + : Number(activeProposals?.length)} + + + + + + + + NFTs + - - - Voting Addresses - {data?.data.ledger.length || "-"} - - - Active Proposals - - {activeLiteProposals - ? Number(activeProposals?.length) + Number(activeLiteProposals?.length) - : Number(activeProposals?.length)} - - - + {nftHoldings?.length || "-"} - - + + - + ) } diff --git a/src/modules/explorer/components/NavigationMenu.tsx b/src/modules/explorer/components/NavigationMenu.tsx index 96ff6597..ce51e220 100644 --- a/src/modules/explorer/components/NavigationMenu.tsx +++ b/src/modules/explorer/components/NavigationMenu.tsx @@ -1,4 +1,14 @@ -import { Grid, styled, Theme, Typography, useMediaQuery, useTheme, alpha } from "@material-ui/core" +import { + Grid, + styled, + Theme, + Typography, + useMediaQuery, + useTheme, + alpha, + withStyles, + makeStyles +} from "@material-ui/core" import { ReactComponent as HouseIcon } from "assets/logos/home.svg" import { ReactComponent as VotingIcon } from "assets/logos/voting.svg" import { ReactComponent as TreasuryIcon } from "assets/logos/treasury.svg" @@ -14,14 +24,18 @@ import { debounce } from "../utils/debounce" const Container = styled(Grid)(({ theme }) => ({ width: "100%", - background: theme.palette.primary.main, + background: theme.palette.primary.dark, position: "sticky", top: "0px" })) -const InnerContainer = styled(Grid)(({ theme }) => ({ +const InnerContainer = styled(Grid)(({ theme }: { theme: Theme }) => ({ width: "1000px", margin: "auto", + borderRadius: 8, + backgroundColor: theme.palette.primary.main, + padding: 16, + alignItems: "center", justifyContent: "space-between", ["@media (max-width:1167px)"]: { @@ -29,14 +43,67 @@ const InnerContainer = styled(Grid)(({ theme }) => ({ } })) +const InnerContainerExplorer = styled(Grid)(({ theme }: { theme: Theme }) => ({ + width: "1000px", + margin: "auto", + borderRadius: 8, + backgroundColor: theme.palette.primary.dark, + padding: 16, + alignItems: "center", + justifyContent: "space-between", + + ["@media (max-width:1167px)"]: { + width: "86vw" + } +})) + +const PageItemMobile = styled(Grid)(({ theme, isSelected }: { theme: Theme; isSelected: boolean }) => ({ + "display": "flex", + "alignItems": "center", + "borderTop": "2px solid transparent", + "backgroundColor": isSelected ? "rgba(129, 254, 183, 0.20)" : "inherit", + "height": "auto", + "padding": "20px 20px", + "borderRadius": 8, + "transition": isSelected ? "0s ease-in" : ".1s ease-out", + "width": 180, + "justifyContent": "center", + + "& > a > *": { + height: "100%" + }, + + "&:hover": { + "& > a > * > * > * > * > *": { + fill: isSelected ? theme.palette.secondary.main : theme.palette.secondary.main, + stroke: isSelected ? theme.palette.secondary.main : theme.palette.secondary.main, + transition: isSelected ? "none" : ".15s ease-in" + } + }, + + "& > a > * > * > * > * > *": { + transition: ".15s ease-out" + }, + + "& > a > * > * > *": { + transition: ".15s ease-out" + }, + [theme.breakpoints.down("sm")]: { + width: "45px" + } +})) + const PageItem = styled(Grid)(({ theme, isSelected }: { theme: Theme; isSelected: boolean }) => ({ - "height": "60px", "display": "flex", "alignItems": "center", - "padding": "0 8px", "borderTop": "2px solid transparent", - "borderBottom": isSelected ? "2px solid" + theme.palette.secondary.main : "2px solid transparent", + "backgroundColor": isSelected ? "rgba(129, 254, 183, 0.20)" : "inherit", + "height": 40, + "padding": "20px 20px", + "borderRadius": 8, "transition": isSelected ? "0s ease-in" : ".1s ease-out", + "width": 180, + "justifyContent": "center", "& > a > *": { height: "100%" @@ -128,12 +195,21 @@ const getPages = (daoId: string): Page[] => [ } ] +const styles = makeStyles(theme => ({ + explorer: { + backgroundColor: theme.palette.primary.dark + }, + lite: { + display: "none" + }, + home: {} +})) + const StyledBottomBar = styled(Grid)(({ theme }: { theme: Theme }) => ({ position: "fixed", height: 55, width: "100%", bottom: /*visible ? 0 : -55*/ 0, - backgroundColor: theme.palette.primary.main, boxShadow: "0px -4px 7px -4px rgba(0,0,0,0.2)", zIndex: 10000, transition: "bottom 0.5s" @@ -149,6 +225,8 @@ const BottomNavBar: React.FC = ({ children }) => { const [prevScrollPos, setPrevScrollPos] = useState(0) const [visible, setVisible] = useState(true) + const classes = styles() + useEffect(() => { const handleScroll = debounce(() => { const currentScrollPos = window.pageYOffset @@ -179,6 +257,8 @@ export const NavigationMenu: React.FC<{ disableMobileMenu?: boolean }> = ({ disa const pathId = path.pathname.split("/").slice(-1)[0] const theme = useTheme() const isMobileSmall = useMediaQuery(theme.breakpoints.down(960)) + const classes = styles() + const location = useLocation() useEffect(() => { if (dao) { @@ -194,7 +274,16 @@ export const NavigationMenu: React.FC<{ disableMobileMenu?: boolean }> = ({ disa return !isMobileSmall || disableMobileMenu ? ( - + {pages.map((page, i) => ( @@ -216,7 +305,7 @@ export const NavigationMenu: React.FC<{ disableMobileMenu?: boolean }> = ({ disa ) : ( {pages.map((page, i) => ( - + @@ -226,7 +315,7 @@ export const NavigationMenu: React.FC<{ disableMobileMenu?: boolean }> = ({ disa - + ))} ) diff --git a/src/modules/explorer/components/ProposalActionsDialog.tsx b/src/modules/explorer/components/ProposalActionsDialog.tsx index f1d710a6..2e581302 100644 --- a/src/modules/explorer/components/ProposalActionsDialog.tsx +++ b/src/modules/explorer/components/ProposalActionsDialog.tsx @@ -128,7 +128,6 @@ export const ProposalActionsDialog: React.FC = ({ open, handleClose }) => const liteDAOId = data?.liteDAOData?._id const shouldDisable = useIsProposalButtonDisabled(daoId) const { network, account } = useTezos() - const isMember = useIsMember(network, data?.liteDAOData?.tokenAddress || "", account) const handleOpenCustomProposalModal = (key: ProposalAction) => { setProposalAction(key) @@ -171,10 +170,8 @@ export const ProposalActionsDialog: React.FC = ({ open, handleClose }) => - elem.id === "off-chain" && isMember + elem.id === "off-chain" ? handleLiteProposal() - : elem.id === "off-chain" && !isMember - ? null : !shouldDisable ? elem.isLambda ? handleOpenCustomProposalModal(elem.id) @@ -182,25 +179,11 @@ export const ProposalActionsDialog: React.FC = ({ open, handleClose }) => : null } > - + {elem.name} {elem.description}{" "} diff --git a/src/modules/explorer/components/Toolbar.tsx b/src/modules/explorer/components/Toolbar.tsx index 63ada175..c4124dfd 100644 --- a/src/modules/explorer/components/Toolbar.tsx +++ b/src/modules/explorer/components/Toolbar.tsx @@ -12,7 +12,7 @@ import { Theme } from "@material-ui/core" -import HomeButton from "assets/logos/homebase_logo.svg" +import HomeButton from "assets/logos/homebase-logo.svg" import { useTezos } from "services/beacon/hooks/useTezos" import { ChangeNetworkButton } from "./ChangeNetworkButton" import { UserProfileName } from "modules/explorer/components/UserProfileName" @@ -69,20 +69,21 @@ const AddressContainer = styled(Grid)({ const LogoText = styled(Typography)({ fontWeight: "bold", - fontSize: "24px", + fontSize: "26px", cursor: "pointer", fontFamily: "Roboto", letterSpacing: "initial" }) -const AddressBarWrapper = styled(Grid)({ - "boxSizing": "border-box", - "padding": "8px 16px", - "borderRadius": 4, - "&:hover": { - background: "rgba(129, 254, 183, 0.03)" - } -}) +const AddressBarWrapper = styled(Grid)(({ theme }) => ({ + borderRadius: 8, + background: theme.palette.primary.main, + paddingLeft: 16, + paddingRight: 16, + paddingTop: 5, + paddingBottom: 6, + boxSizing: "border-box" +})) const LogoItem = styled("img")({ height: "30px", @@ -133,7 +134,7 @@ export const Navbar: React.FC<{ disableMobileMenu?: boolean }> = ({ disableMobil > {children} - + @@ -144,13 +145,13 @@ export const Navbar: React.FC<{ disableMobileMenu?: boolean }> = ({ disableMobil alignItems="center" wrap="nowrap" justifyContent="flex-end" - style={{ gap: 8 }} + style={{ gap: 16 }} > - + diff --git a/src/modules/explorer/components/UserBalances.tsx b/src/modules/explorer/components/UserBalances.tsx index 6022b413..a581e89a 100644 --- a/src/modules/explorer/components/UserBalances.tsx +++ b/src/modules/explorer/components/UserBalances.tsx @@ -71,10 +71,15 @@ const Balance = styled(Typography)({ }) const BalanceToken = styled(Typography)({ - fontSize: 24, + fontSize: 21, fontWeight: 300 }) +const OnChainTitle = styled(Typography)({ + marginBottom: 16, + fontSize: 24 +}) + export const UserBalances: React.FC<{ daoId: string }> = ({ daoId, children }) => { const { account } = useTezos() const { data: dao, ledger } = useDAO(daoId) @@ -120,6 +125,11 @@ export const UserBalances: React.FC<{ daoId: string }> = ({ daoId, children }) = {children} + + + On-Chain Balances + + {dao && balancesList.map(({ displayName, balance }, i) => ( diff --git a/src/modules/explorer/components/UsersTable.tsx b/src/modules/explorer/components/UsersTable.tsx index de05ad62..797cc1f6 100644 --- a/src/modules/explorer/components/UsersTable.tsx +++ b/src/modules/explorer/components/UsersTable.tsx @@ -13,6 +13,12 @@ import { } from "@material-ui/core" import dayjs from "dayjs" import { UserBadge } from "modules/explorer/components/UserBadge" +import { Blockie } from "modules/common/Blockie" +import { CopyButton } from "./CopyButton" +import { toShortAddress } from "services/contracts/utils" +import { formatNumber } from "../utils/FormatNumber" +import BigNumber from "bignumber.js" +import numbro from "numbro" const localizedFormat = require("dayjs/plugin/localizedFormat") dayjs.extend(localizedFormat) @@ -57,100 +63,167 @@ const TableText = styled(Typography)({ } }) -const titleDataMatcher = (title: (typeof titles)[number], rowData: RowData) => { - switch (title) { - case "Rank": - return rowData.address - case "Votes": - return rowData.votes - case "Available Staked": - return rowData.availableStaked - case "Total Staked": - return rowData.totalStaked - case "Proposals Voted": - return rowData.proposalsVoted - } -} +const Title = styled(Typography)({ + fontSize: 20 +}) -const MobileTableHeader = styled(Grid)({ - width: "100%", - padding: 20, - borderBottom: "0.3px solid rgba(125,140,139, 0.2)" +const CardContainer = styled(Grid)(({ theme }) => ({ + background: theme.palette.primary.main, + padding: "40px 48px", + borderRadius: 8 +})) + +const Value = styled(Typography)({ + marginTop: 8, + fontWeight: 300, + gap: 6, + display: "flex", + textTransform: "uppercase" +}) + +const Symbol = styled(Typography)({ + marginLeft: 4, + fontWeight: 300 }) -const MobileUsersTable: React.FC<{ data: RowData[] }> = ({ data }) => { +const formatConfig = { + average: true, + mantissa: 1, + thousandSeparated: true, + trimMantissa: true +} + +const MobileUsersTable: React.FC<{ data: RowData[]; symbol: string }> = ({ data, symbol }) => { return ( - - - - Top Addresses - - - {data.map((row, i) => ( - - {titles.map((title, j) => ( - - {title === "Rank" ? ( - - ) : ( - - {title}: {titleDataMatcher(title, row)} + <> + + + + Top Addresses + + + + {data.map((item, i) => ( + + + + + {toShortAddress(item.address)} + + + + + + + Total Votes - )} + + {numbro(item.votes).format(formatConfig)} + + + + + Proposals Voted + + + {numbro(item.proposalsVoted).format(formatConfig)} + + + + + Available Staked + + + {numbro(item.availableStaked).format(formatConfig)} + {symbol} + + + + + Total Staked + + + {numbro(item.totalStaked).format(formatConfig)} + {symbol} + + - ))} - - ))} - + + ))} + + ) } -const DesktopUsersTable: React.FC<{ data: RowData[] }> = ({ data }) => { +const DesktopUsersTable: React.FC<{ data: RowData[]; symbol: string }> = ({ data, symbol }) => { return ( <> - - - - - Top Addresses - - - - {titles.map((title, i) => ( - - {title} - - ))} - - - - {data.map((row, i) => ( - - - - - {row.votes} - {row.availableStaked} - {row.totalStaked} - {row.proposalsVoted} - - ))} - -
+ + + + Top Addresses + + + + {data.map((item, i) => ( + + + + + {item.address} + + + + + + + Total Votes + + + {numbro(item.votes).format(formatConfig)} + + + + + Proposals Voted + + + {numbro(item.proposalsVoted).format(formatConfig)} + + + + + Available Staked + + + {numbro(item.availableStaked).format(formatConfig)} + {symbol} + + + + + Total Staked + + + {numbro(item.totalStaked).format(formatConfig)} + {symbol} + + + + + ))} + ) } -export const UsersTable: React.FC<{ data: RowData[] }> = ({ data }) => { +export const UsersTable: React.FC<{ data: RowData[]; symbol: string }> = ({ data, symbol }) => { const theme = useTheme() - const isExtraSmall = useMediaQuery(theme.breakpoints.down(960)) + const isExtraSmall = useMediaQuery(theme.breakpoints.down(820)) - return isExtraSmall ? : + return isExtraSmall ? ( + + ) : ( + + ) } diff --git a/src/modules/explorer/pages/Config/components/DAOInfoTable.tsx b/src/modules/explorer/pages/Config/components/DAOInfoTable.tsx index d5794866..2f3f7b07 100644 --- a/src/modules/explorer/pages/Config/components/DAOInfoTable.tsx +++ b/src/modules/explorer/pages/Config/components/DAOInfoTable.tsx @@ -74,7 +74,7 @@ export const DaoInfoTables: React.FC = () => { return ( <> - +
{dao ? ( <> @@ -128,14 +128,8 @@ export const DaoInfoTables: React.FC = () => {
+ Proposal & Voting Settings - - - - Proposal & Voting Settings - - - {dao ? ( <> @@ -228,14 +222,8 @@ export const DaoInfoTables: React.FC = () => { + Quorum Settings
- - - - Quorum Settings - - - {dao ? ( <> diff --git a/src/modules/explorer/pages/DAO/index.tsx b/src/modules/explorer/pages/DAO/index.tsx index 7a48ceda..11606da7 100644 --- a/src/modules/explorer/pages/DAO/index.tsx +++ b/src/modules/explorer/pages/DAO/index.tsx @@ -24,12 +24,15 @@ export const StyledAvatar = styled(Avatar)({ }) const HeroContainer = styled(ContentContainer)(({ theme }) => ({ - padding: "38px 38px" + padding: 38, + [theme.breakpoints.down("sm")]: { + width: "inherit" + } })) const TitleText = styled(Typography)(({ theme }) => ({ - fontSize: 40, - fontWeight: 500, + fontSize: 36, + fontWeight: 600, lineHeight: 0.8, ["@media (max-width:642px)"]: { @@ -60,7 +63,6 @@ const ViewSettings = styled(Grid)({ const SubtitleText = styled(Typography)({ fontSize: 18, - margin: "-10px auto 0 auto", width: "875px", fontWeight: 300, maxHeight: "200px", @@ -80,16 +82,13 @@ const SubtitleText = styled(Typography)({ } }) -const TableContainer = styled(ContentContainer)({ - width: "100%" -}) - export const DAO: React.FC = () => { const daoId = useDAOID() const { data, cycleInfo, ledger } = useDAO(daoId) const { mutate } = useFlush() const theme = useTheme() const isExtraSmall = useMediaQuery(theme.breakpoints.down("xs")) + const symbol = data && data.data.token.symbol.toUpperCase() const name = data && data.data.name const description = data && data.data.description @@ -123,19 +122,19 @@ export const DAO: React.FC = () => { }, [cycleInfo, data, ledger]) return ( - + - + - + {name} setOpenDialog(true)}> - - View configuration + + View Settings @@ -149,20 +148,9 @@ export const DAO: React.FC = () => { - {data && cycleInfo && activeProposals && ( - <> - - - )} - - - + + + ) } diff --git a/src/modules/explorer/pages/DAOList/components/DAOItem.tsx b/src/modules/explorer/pages/DAOList/components/DAOItem.tsx index 5622790f..d566d6a2 100644 --- a/src/modules/explorer/pages/DAOList/components/DAOItem.tsx +++ b/src/modules/explorer/pages/DAOList/components/DAOItem.tsx @@ -1,49 +1,30 @@ import { styled, Grid, Theme, Typography, Link, useTheme, useMediaQuery } from "@material-ui/core" -import { createTheme } from "@material-ui/core/styles" -import hexToRgba from "hex-to-rgba" -import { startCase } from "lodash" import React from "react" import { EnvKey, getEnv } from "services/config" - -const SectionNames = styled(Grid)(({ theme }: { theme: Theme }) => ({ - width: "55%", - - ["@media (max-width:1030px)"]: { - width: "50%" - }, - - ["@media (max-width:960px)"]: { - width: "99%" - } -})) +import ReactHtmlParser from "react-html-parser" +import { useProposals } from "services/services/dao/hooks/useProposals" +import { ProposalStatus } from "services/services/dao/mappers/proposal/types" +import { usePolls } from "modules/lite/explorer/hooks/usePolls" +import dayjs from "dayjs" const Container = styled(Grid)(({ theme }: { theme: Theme }) => ({ "background": theme.palette.primary.main, - "minHeight": 138, + "minHeight": 282, "wordBreak": "break-all", "borderRadius": 8, "boxSizing": "border-box", - "padding": 32, "cursor": "pointer", "transition": "0.15s ease-out", - "maxWidth": 490, - - ["@media (max-width:1335px)"]: { - minHeight: 130 - }, - - ["@media (max-width:1155px)"]: { - minHeight: 123 - }, - - ["@media (max-width:1030px)"]: {}, - - ["@media (max-width:960px)"]: { - minHeight: 210 - }, + "padding": "34px 48px", + "minWidth": "340px", + "alignContent": "baseline", + "gap": 18, + "maxHeight": 282, ["@media (max-width:760px)"]: { - maxWidth: "86vw" + maxWidth: "86vw", + padding: "17px 24px", + minWidth: "inherit" }, "&:hover": { @@ -60,6 +41,8 @@ const Container = styled(Grid)(({ theme }: { theme: Theme }) => ({ const SymbolText = styled(Typography)({ fontSize: "18px", fontWeight: 300, + color: "#bfc5ca", + lineHeight: "normal", ["@media (max-width:1335px)"]: { fontSize: "16px" @@ -71,18 +54,9 @@ const NameText = styled(Typography)(({ theme }) => ({ textOverflow: "ellipsis", color: theme.palette.text.primary, overflow: "hidden", - fontSize: "32px", + fontSize: 36, maxWidth: 245, - - ["@media (max-width:1335px)"]: { - fontSize: "29px" - }, - - ["@media (max-width:1155px)"]: { - fontSize: "26px" - }, - - ["@media (max-width:1030px)"]: {}, + fontWeight: 600, ["@media (max-width:960px)"]: { fontSize: "28px", @@ -91,60 +65,41 @@ const NameText = styled(Typography)(({ theme }) => ({ } })) -const NumberText = styled(Typography)({ - fontSize: "28px", - fontWeight: 300, - - ["@media (max-width:1335px)"]: { - fontSize: "26px", - lineHeight: 1.2, - borderBottom: "7px solid transparent" - }, - - ["@media (max-width:1155px)"]: { - fontSize: "23px", - borderBottom: "9.5px solid transparent" - }, - - ["@media (max-width:960px)"]: { - fontSize: "26px", - borderBottom: "6px solid transparent" - } +const DescriptionText = styled(Typography)({ + "color": "#bfc5ca", + "overflow": "hidden", + "height": 54, + "textOverflow": "ellipsis", + "fontSize": 18, + "fontWeight": 300, + "display": "-webkit-box", + "-webkit-line-clamp": 2 /* number of lines to show */, + "line-clamp": 2, + "-webkit-box-orient": "vertical", + "maxHeight": 60 }) -const VotingAddressesText = styled(Typography)({ - fontSize: "19px", - fontWeight: 300, - - ["@media (max-width:1335px)"]: { - fontSize: "17px" - }, - - ["@media (max-width:1155px)"]: { - fontSize: "15.7px" - }, - - ["@media (max-width:960px)"]: { - fontSize: "17px" - } +const ItemText = styled(Typography)({ + fontWeight: 600, + fontSize: 16, + whiteSpace: "pre" }) const Badge = styled(Grid)(({ theme, dao_type }: { theme: Theme; dao_type: string }) => ({ - "borderRadius": 4, + "borderRadius": "50px", + "padding": "8px 16px", "height": "auto", "boxSizing": "border-box", "width": "fit-content", "textAlign": "center", - "padding": "0 7px", "float": "right", - "background": - dao_type === "lambda" ? hexToRgba(theme.palette.secondary.main, 0.4) : hexToRgba(theme.palette.warning.main, 0.4), - "color": dao_type === "lambda" ? theme.palette.secondary.main : theme.palette.warning.main, + "background": "#2d433c", + "color": theme.palette.secondary.main, "& > div": { height: "100%" }, "fontFamily": "Roboto Mono", - "fontWeight": "bold" + "fontWeight": 500 })) export const DAOItem: React.FC<{ @@ -155,6 +110,7 @@ export const DAOItem: React.FC<{ votingAddresses: string[] dao_type: { name: string } votingAddressesCount: number + description: string } }> = ({ dao }) => { const theme = useTheme() @@ -167,23 +123,46 @@ export const DAOItem: React.FC<{ ? `dao/${dao.id}` : `lite/dao/${dao.id}` + const { data: activeProposals } = useProposals(dao.id, ProposalStatus.ACTIVE) + const { data: polls } = usePolls(dao.id) + const activeLiteProposals = polls?.filter(p => Number(p.endTime) > dayjs().valueOf()) + + const getTotalActiveProposals = () => { + if (daoType === "lite") { + return activeLiteProposals?.length + } else { + return (activeProposals ? activeProposals?.length : 0) + (activeLiteProposals ? activeLiteProposals?.length : 0) + } + } + return ( - - - {dao?.symbol?.toUpperCase()} + + {dao.name} - - - + {daoType === "lambda" ? V3 : null} {daoType === "registry" || daoType === "treasury" ? V2 : null} {daoType === "lite" ? Lite : null} - - {dao.votingAddressesCount} - Voting Addresses + + + + {ReactHtmlParser(dao.description)} + + + + DAO {"\n"}Token + {dao?.symbol?.toUpperCase()} + + + Voting {"\n"}Addresses{" "} + {dao.votingAddressesCount} + + + Active {"\n"}Proposals + {getTotalActiveProposals()} diff --git a/src/modules/explorer/pages/DAOList/components/Searchbar.tsx b/src/modules/explorer/pages/DAOList/components/Searchbar.tsx index f518265e..3235e27c 100644 --- a/src/modules/explorer/pages/DAOList/components/Searchbar.tsx +++ b/src/modules/explorer/pages/DAOList/components/Searchbar.tsx @@ -12,11 +12,13 @@ const StyledInput = withStyles((theme: Theme) => ({ "height": 54, "boxSizing": "border-box", "background": theme.palette.primary.main, - "padding": "18px 22px", + "padding": 16, "width": "100%", - "borderRadius": 4, + "borderRadius": 8, "marginTop": "0px !important", "maxWidth": 571, + "fontWeight": 300, + "gap": 6, "& input": { "color": theme.palette.text.primary, "textAlign": "start", @@ -43,10 +45,6 @@ const StyledInput = withStyles((theme: Theme) => ({ } }))(TextField) -const SearchIcon = styled(SearchOutlined)({ - marginRight: 5 -}) - export const SearchInput: React.FC<{ search: any }> = ({ search }) => { return ( = ({ search }) => { InputProps={{ startAdornment: ( - + ) }} diff --git a/src/modules/explorer/pages/DAOList/index.tsx b/src/modules/explorer/pages/DAOList/index.tsx index cd9434c5..4dc63824 100644 --- a/src/modules/explorer/pages/DAOList/index.tsx +++ b/src/modules/explorer/pages/DAOList/index.tsx @@ -7,7 +7,8 @@ import { Typography, useMediaQuery, Theme, - useTheme + useTheme, + Icon } from "@material-ui/core" import { Navbar } from "../../components/Toolbar" import { TabPanel } from "modules/explorer/components/TabPanel" @@ -18,6 +19,10 @@ import { ConnectMessage } from "./components/ConnectMessage" import { DAOItem } from "./components/DAOItem" import { SearchInput } from "./components/Searchbar" import { MainButton } from "../../../common/MainButton" +import { ReactComponent as TabsIcon } from "assets/img/tabs-icon.svg" +import { ReactComponent as TabsSelectedIcon } from "assets/img/tabs-icon-selected.svg" +import { ReactComponent as MyDAOsIcon } from "assets/img/my-daos-icon.svg" +import { ReactComponent as MyDAOsSelectedIcon } from "assets/img/my-daos-selected-icon.svg" import ReactPaginate from "react-paginate" import "./styles.css" @@ -40,13 +45,23 @@ const PageContainer = styled("div")(({ theme }) => ({ })) const StyledTab = styled(Button)(({ theme, isSelected }: { theme: Theme; isSelected: boolean }) => ({ - "fontSize": 16, - "color": isSelected ? theme.palette.primary.dark : "#fff", - - "backgroundColor": isSelected ? theme.palette.secondary.main : theme.palette.primary.main, - + "fontSize": 18, + "height": 40, + "fontWeight": 400, + "paddingLeft": 20, + "paddingRight": 20, + "paddingTop": 0, + "paddingBottom": 0, + "borderRadius": 8, + "color": isSelected ? theme.palette.secondary.main : "#fff", + "backgroundColor": isSelected ? "rgba(129, 254, 183, 0.20)" : "inherit", "&:hover": { - backgroundColor: isSelected ? theme.palette.secondary.main : theme.palette.secondary.dark + backgroundColor: isSelected ? "rgba(129, 254, 183, 0.20)" : theme.palette.secondary.dark, + borderRadius: 8, + borderTopLeftRadius: "8px !important", + borderTopRightRadius: "8px !important", + borderBottomLeftRadius: "8px !important", + borderBottomRightRadius: "8px !important" } })) @@ -60,29 +75,44 @@ const Search = styled(Grid)({ }) const DAOItemGrid = styled(Grid)({ - gap: "18px", - + gap: "30px", + minHeight: "50vh", + justifyContent: "space-between", ["@media (max-width: 1155px)"]: { - gap: "16px" + gap: "32px" }, ["@media (max-width:960px)"]: { - gap: "14px" + gap: "20px" }, ["@media (max-width:830px)"]: { - gap: "12px" + width: "86vw", + gap: "20px" } }) const DAOItemCard = styled(Grid)({ - flexBasis: "49%", + flexBasis: "48.5%", + + ["@media (max-width:1500px)"]: { + flexBasis: "48.5%" + }, + + ["@media (max-width:1200px)"]: { + flexBasis: "47.5%" + }, ["@media (max-width:760px)"]: { minWidth: "100%" } }) +const TabsContainer = styled(Grid)(({ theme }) => ({ + borderRadius: 8, + gap: 30 +})) + export const DAOList: React.FC = () => { const { network, account, tezos } = useTezos() const { data: daos, isLoading } = useAllDAOs(network) @@ -104,6 +134,7 @@ export const DAOList: React.FC = () => { .map(dao => ({ id: dao.address, name: dao.name, + description: dao.description, symbol: dao.token.symbol, votingAddresses: dao.ledgers ? dao.ledgers.map(l => l.holder.address) : [], votingAddressesCount: @@ -113,7 +144,7 @@ export const DAOList: React.FC = () => { }, allowPublicAccess: dao.dao_type.name === "lite" ? dao.allowPublicAccess : true })) - .sort((a, b) => b.votingAddresses.length - a.votingAddresses.length) + .sort((a, b) => b.votingAddressesCount - a.votingAddressesCount) if (searchText) { return formattedDAOs.filter( @@ -144,6 +175,7 @@ export const DAOList: React.FC = () => { dao_type: { name: dao.dao_type.name }, + description: dao.description, allowPublicAccess: dao.dao_type.name === "lite" ? dao.allowPublicAccess : true })) .sort((a, b) => b.votingAddresses.length - a.votingAddresses.length) @@ -155,11 +187,11 @@ export const DAOList: React.FC = () => { (formattedDao.symbol && formattedDao.symbol.toLowerCase().includes(searchText.toLowerCase())) ) } - return formattedDAOs + return formattedDAOs.filter(dao => dao.votingAddresses.includes(account)) } return [] - }, [daos, searchText]) + }, [daos, searchText, account]) const filterDAOs = (filter: string) => { setSearchText(filter.trim()) @@ -182,7 +214,7 @@ export const DAOList: React.FC = () => { <> - + { - + : } variant="contained" - style={ - selectedTab !== 0 - ? { borderTopRightRadius: 0, borderBottomRightRadius: 0, zIndex: 0 } - : { borderRadius: 4, zIndex: 1 } - } disableElevation={true} onClick={() => handleChangeTab(0)} isSelected={selectedTab === 0} @@ -236,20 +264,16 @@ export const DAOList: React.FC = () => { : } disableElevation={true} variant="contained" - style={ - selectedTab !== 1 - ? { borderTopLeftRadius: 0, borderBottomLeftRadius: 0, marginLeft: -1, zIndex: 0 } - : { borderRadius: 4, marginLeft: -1, zIndex: 1 } - } onClick={() => handleChangeTab(1)} isSelected={selectedTab === 1} > My DAOs - + @@ -286,17 +310,17 @@ export const DAOList: React.FC = () => { - + {!account ? ( + ) : myDAOs.length > 0 ? ( + myDAOs.map((dao, i) => ( + + + + )) ) : ( - myDAOs - .filter(dao => dao.votingAddresses.includes(account)) - .map((dao, i) => ( - - - - )) + You have not joined any DAO )} diff --git a/src/modules/explorer/pages/ProposalDetails/index.tsx b/src/modules/explorer/pages/ProposalDetails/index.tsx index 76aff9f0..67015739 100644 --- a/src/modules/explorer/pages/ProposalDetails/index.tsx +++ b/src/modules/explorer/pages/ProposalDetails/index.tsx @@ -35,7 +35,11 @@ import Prism, { highlight } from "prismjs" import { CodeCollapse } from "modules/explorer/components/CodeCollapse" const Container = styled(ContentContainer)({ - padding: "36px 45px" + "padding": "36px 45px", + "& a": { + color: "#81feb7", + textDecoration: "underline" + } }) const HistoryItem = styled(Grid)(({ theme }: { theme: Theme }) => ({ diff --git a/src/modules/explorer/utils/FormatNumber.ts b/src/modules/explorer/utils/FormatNumber.ts index c688907f..6d770417 100644 --- a/src/modules/explorer/utils/FormatNumber.ts +++ b/src/modules/explorer/utils/FormatNumber.ts @@ -1,5 +1,4 @@ import BigNumber from "bignumber.js" - export const formatNumber = (number: BigNumber) => { if (number.isLessThan(1e3)) return number diff --git a/src/modules/home/LandingHeader.tsx b/src/modules/home/LandingHeader.tsx index 1e48a338..5a74442d 100644 --- a/src/modules/home/LandingHeader.tsx +++ b/src/modules/home/LandingHeader.tsx @@ -17,7 +17,7 @@ const LogoItem = styled("img")({ const LogoText = styled(Typography)({ fontWeight: "bold", - fontSize: "24px", + fontSize: "26px", cursor: "pointer", fontFamily: "Roboto", letterSpacing: "initial" diff --git a/src/modules/lite/creator/index.tsx b/src/modules/lite/creator/index.tsx index 4be97433..e43eebe5 100644 --- a/src/modules/lite/creator/index.tsx +++ b/src/modules/lite/creator/index.tsx @@ -26,9 +26,33 @@ import { useTezos } from "services/beacon/hooks/useTezos" import { getSignature } from "services/utils/utils" import { Navbar } from "modules/common/Toolbar" import { SmallButton } from "modules/common/SmallButton" -import { EnvKey, getEnv } from "services/config" import { saveLiteCommunity } from "services/services/lite/lite-services" import { InfoRounded } from "@material-ui/icons" +import CodeIcon from "@mui/icons-material/Code" +import CodeOffIcon from "@mui/icons-material/CodeOff" +import { ProposalCodeEditorInput } from "modules/explorer/components/ProposalFormInput" +import Prism, { highlight } from "prismjs" +import "prism-themes/themes/prism-night-owl.css" + +const CodeButton = styled(CodeIcon)(({ theme }) => ({ + background: theme.palette.primary.dark, + padding: 3, + borderTopLeftRadius: 4, + borderTopRightRadius: 4, + borderBottom: "0.5px solid", + cursor: "pointer", + color: theme.palette.secondary.main +})) + +const CodeOffButton = styled(CodeOffIcon)(({ theme }) => ({ + background: theme.palette.primary.dark, + padding: 3, + borderTopLeftRadius: 4, + borderTopRightRadius: 4, + borderBottom: "0.5px solid", + cursor: "pointer", + color: theme.palette.secondary.main +})) const CommunityContainer = styled(Grid)(({ theme }) => ({ boxSizing: "border-box", @@ -116,6 +140,7 @@ const CustomTextarea = styled(withTheme(TextareaAutosize))(props => ({ "fontWeight": 400, "padding": "21px 20px", "fontFamily": "Roboto Mono", + "borderTopRightRadius": 0, "border": "none", "fontSize": 16, "color": props.theme.palette.text.secondary, @@ -197,6 +222,27 @@ const CommunityForm = ({ submitForm, values, setFieldValue, errors, touched, set const { data: tokenMetadata, isLoading: loading, error } = useTokenMetadata(values?.tokenAddress) + const codeEditorStyles = { + minHeight: 500, + fontFamily: "Roboto Mono", + fontSize: 14, + fontWeight: 400, + outlineWidth: 0, + color: "white" + } + + const [isMarkup, setIsMarkup] = useState(false) + const grammar = Prism.languages.markup + const codeEditorPlaceholder = ` + + + Proposal Description + + +

...

+ + ` + useEffect(() => { if (tokenMetadata) { setFieldValue("tokenID", tokenMetadata.token_id) @@ -227,20 +273,54 @@ const CommunityForm = ({ submitForm, values, setFieldValue, errors, touched, set {errors?.name && touched.name ? {errors.name} : null} - - {() => ( - { - setFieldValue("description", newValue.target.value) - }} - /> - )} - + {!isMarkup ? ( +
+ + setIsMarkup(true)} /> + +
+ ) : ( +
+ + setIsMarkup(false)} /> + +
+ )} + + {!isMarkup ? ( + + {() => ( + { + setFieldValue("description", newValue.target.value) + }} + /> + )} + + ) : ( + + {() => ( + { + setFieldValue("description", newValue) + }} + highlight={code => highlight(code, grammar, "javascript")} + placeholder={codeEditorPlaceholder} + /> + )} + + )}
diff --git a/src/modules/lite/explorer/components/ChoiceItemSelected.tsx b/src/modules/lite/explorer/components/ChoiceItemSelected.tsx index 454571ba..5afbe0e5 100644 --- a/src/modules/lite/explorer/components/ChoiceItemSelected.tsx +++ b/src/modules/lite/explorer/components/ChoiceItemSelected.tsx @@ -1,18 +1,22 @@ import React, { useEffect } from "react" -import { Divider, Grid, styled, Theme, Typography, useMediaQuery, useTheme } from "@material-ui/core" +import { Button, Divider, Grid, styled, Theme, Typography, useMediaQuery, useTheme } from "@material-ui/core" import { Choice } from "models/Choice" const StyledContainer = styled(Grid)(({ theme }: { theme: Theme }) => ({ - "borderRadius": 4, - "minHeight": 75, - "border": "1px solid", - "borderColor": theme.palette.primary.light, - "cursor": "pointer", + borderRadius: 4, + minHeight: 75, + border: "1px solid", + borderColor: theme.palette.primary.light, + cursor: "pointer" +})) + +const StyledButton = styled(Button)({ + "width": "100%", + "minHeight": "inherit", "&:hover": { - border: "1px solid", - borderColor: theme.palette.secondary.main + background: "rgba(129, 254, 183, 0.62)" } -})) +}) export const ChoiceItemSelected: React.FC<{ choice: Choice @@ -31,32 +35,42 @@ export const ChoiceItemSelected: React.FC<{ } else { votesArray = votesArray.filter(vote => vote._id !== choice._id) } - const setVotes = [...new Set(votesArray)] - setVotes.forEach(vote => (vote.selected = true)) - setSelectedVotes(setVotes) + const result = votesArray.map(vote => { + vote.selected = true + return vote + }) + setSelectedVotes(result) } else { choice.selected = true setSelectedVotes([choice]) } } + const isPartOfVotes = () => { + const found = votes.filter(vote => vote._id === choice._id) + return found.length > 0 + } + return ( { - handleVotes(choice) - return - }} > - - {choice.name} - + { + handleVotes(choice) + return + }} + > + + {choice.name} + + ) } diff --git a/src/modules/lite/explorer/components/Choices.tsx b/src/modules/lite/explorer/components/Choices.tsx index 8a073525..25e33e3f 100644 --- a/src/modules/lite/explorer/components/Choices.tsx +++ b/src/modules/lite/explorer/components/Choices.tsx @@ -1,10 +1,11 @@ -import React, { useState } from "react" +import React from "react" import { Button, CircularProgress, Grid, IconButton, InputAdornment, + makeStyles, Radio, styled, Typography, @@ -13,56 +14,83 @@ import { } from "@material-ui/core" import { theme } from "theme" -import { AddCircleOutline, RemoveCircleOutline } from "@material-ui/icons" +import { AddCircleOutline, RemoveCircleOutline, DeleteTwoTone } from "@material-ui/icons" import { FieldArray, Field } from "formik" import { TextField as FormikTextField } from "formik-material-ui" import { useDAOID } from "modules/explorer/pages/DAO/router" import { useDAO } from "services/services/dao/hooks/useDAO" -import { useToken } from "../hooks/useToken" import { useTokenVoteWeight } from "services/contracts/token/hooks/useTokenVoteWeight" +import { useCommunity } from "../hooks/useCommunity" const ChoicesContainer = styled(Grid)(({ theme }) => ({ - paddingBottom: 19, - background: theme.palette.primary.main, - borderRadius: 4 + marginTop: 24, + gap: 24 })) -const RemoveCircle = styled(RemoveCircleOutline)(({ theme }) => ({ +const ErrorTextChoices = styled(Typography)({ + fontSize: 14, + color: "red" +}) + +const RemoveCircle = styled(DeleteTwoTone)(({ theme }) => ({ color: theme.palette.error.main, cursor: "pointer" })) -const Title = styled(Grid)(({ theme }) => ({ - paddingLeft: 26, - paddingRight: 26, - paddingTop: 19, - paddingBottom: 19, - borderBottom: `0.3px solid ${theme.palette.primary.light}`, - marginTop: "0px !important" -})) - -const ChoiceText = styled(Typography)({ +const ChoiceText = styled(Typography)(({ theme }) => ({ fontWeight: 300, - fontSize: 17 -}) + fontSize: 18, + marginLeft: 12, + [theme.breakpoints.down("sm")]: { + fontSize: 16 + } +})) const VotingContainer = styled(Grid)(({ theme }) => ({ - padding: "19px 26px 0px", - borderBottom: `0.3px solid ${theme.palette.primary.light}`, height: 80, [theme.breakpoints.down("sm")]: { height: 120 } })) -const CustomFormikTextField = withStyles({ +const useStyles = makeStyles({ + root: { + "&:hover": { + backgroundColor: "transparent" + } + }, + icon: { + "width": 24, + "height": 24, + "borderRadius": "50%", + "backgroundColor": "#2F3438", + + "input:disabled ~ &": { + boxShadow: "none", + background: "rgba(206,217,224,.5)" + } + }, + checkedIcon: { + "&:before": { + borderRadius: "50%", + display: "block", + width: 24, + height: 24, + background: "radial-gradient(#81FEB7,#81FEB7 27%,#2F3438 27%)", + content: '""' + } + } +}) + +const CustomFormikChoiceTextField = withStyles({ root: { "& .MuiInput-root": { fontWeight: 300, textAlign: "initial", - borderBottom: `0.3px solid ${theme.palette.primary.light} !important`, + backgroundColor: theme.palette.primary.main, marginTop: "0px !important", - padding: "19px 26px 19px" + padding: "10px 26px", + borderRadius: 8 }, "& .MuiInputBase-input": { textAlign: "initial" @@ -86,36 +114,51 @@ const MainButton = styled(Button)(({ theme }) => ({ } })) -export const Choices: React.FC = ({ choices, submitForm, isLoading, votingStrategy, setFieldValue, id }) => { +export const Choices: React.FC = ({ + choices, + submitForm, + isLoading, + votingStrategy, + setFieldValue, + id, + touched, + errors +}) => { const isMobileExtraSmall = useMediaQuery(theme.breakpoints.down("sm")) const daoId = useDAOID() const { data } = useDAO(daoId) - const liteDAOId = data?.liteDAOData?._id ? data?.liteDAOData?._id : id - const tokenAddress = useToken(liteDAOId) - const { data: userTokenVoteWeight } = useTokenVoteWeight(tokenAddress) + const community = useCommunity(id) + + const { data: userTokenVoteWeight } = useTokenVoteWeight(data?.data?.token?.contract || community?.tokenAddress) const canCreateProposal = userTokenVoteWeight && userTokenVoteWeight.gt(0) ? true : false + const classes = useStyles() + return ( - - <Typography variant={"body2"} color="textPrimary"> + <Grid item> + <Typography variant={"body1"} color="textPrimary"> Set Poll Options </Typography> - + - + {() => ( } + icon={} onClick={() => setFieldValue("votingStrategy", 0)} /> )} @@ -123,15 +166,18 @@ export const Choices: React.FC = ({ choices, submitForm, isLoading, votingS Single choice - + {() => ( } + icon={} onClick={() => setFieldValue("votingStrategy", 1)} /> )} @@ -144,18 +190,18 @@ export const Choices: React.FC = ({ choices, submitForm, isLoading, votingS ( -
+ {choices && choices.length > 0 ? choices.map((choice: any, index: number) => ( -
+ { @@ -168,32 +214,34 @@ export const Choices: React.FC = ({ choices, submitForm, isLoading, votingS ) : null }} /> -
+
)) : null} -
- arrayHelpers.insert(choices.length, "")} - > - - - - - Add Choice - - -
-
+ + arrayHelpers.insert(choices.length, "")} + item + xs={isMobileExtraSmall ? 12 : 3} + > + + + + + Add Choice + + +
)} /> + {errors && touched ? {errors} : null} {!isLoading ? ( - Create Proposal + {canCreateProposal ? "Create Proposal" : "No Voting Weight"} ) : ( diff --git a/src/modules/lite/explorer/components/DaoCardDetail.tsx b/src/modules/lite/explorer/components/DaoCardDetail.tsx index 19b8b7dc..c495d461 100644 --- a/src/modules/lite/explorer/components/DaoCardDetail.tsx +++ b/src/modules/lite/explorer/components/DaoCardDetail.tsx @@ -1,12 +1,13 @@ -import { Avatar, Button, Grid, styled, Typography, useMediaQuery, useTheme } from "@material-ui/core" +import { Avatar, Button, Grid, Link, styled, Typography, useMediaQuery, useTheme } from "@material-ui/core" import { Community } from "models/Community" import React, { useCallback, useContext, useEffect, useState } from "react" import { useHistory } from "react-router" import { useTezos } from "services/beacon/hooks/useTezos" import { DashboardContext } from "../context/ActionSheets/explorer" -import { useHoldersTotalCount } from "../hooks/useHolderTotalCount" import { updateCount } from "services/services/lite/lite-services" import { useIsMember } from "../hooks/useIsMember" +import { useHoldersTotalCount } from "../hooks/useHolderTotalCount" +import ReactHtmlParser from "react-html-parser" const StyledAvatar = styled(Avatar)({ height: 159, @@ -20,6 +21,15 @@ const MembersText = styled(Typography)({ marginBottom: 10 }) +const TermsText = styled(Link)(({ theme }) => ({ + fontSize: 14, + textDecoration: "underline", + color: theme.palette.secondary.main, + cursor: "pointer", + fontFamily: "Roboto Mono", + letterSpacing: "1px !important" +})) + const CommunityText = styled(Typography)({ fontWeight: 500, fontSize: 30, @@ -58,34 +68,31 @@ export const DaoCardDetail: React.FC = ({ community, setIsUp const { network, account } = useTezos() const theme = useTheme() const { isConnected } = useContext(DashboardContext) - const count = useHoldersTotalCount(network, community?.tokenAddress || "") const isMember = useIsMember(network, community?.tokenAddress || "", account) + const count = useHoldersTotalCount( + network, + community?.tokenAddress || "", + community?.tokenID ? Number(community?.tokenID) : 0 + ) - const updateCommunityCount = useCallback( - async (count: number) => { - if (community) { - try { - const resp = await updateCount(community._id, count) - const respData = await resp.json() + const updateCommunityCount = useCallback(async () => { + if (community) { + try { + const resp = await updateCount(community._id) + const respData = await resp.json() - if (!resp.ok) { - console.log(respData.message) - } - } catch (error) { - console.log("Error: ", error) + if (!resp.ok) { + console.log(respData.message) } + } catch (error) { + console.log("Error: ", error) } - }, - [community] - ) + } + }, [community]) useEffect(() => { - updateCommunityCount(count) - }, [count, updateCommunityCount]) - - const shouldBeDisabled = () => { - return community?.requiredTokenOwnership && isMember ? false : true - } + updateCommunityCount() + }, [updateCommunityCount]) return ( @@ -98,19 +105,21 @@ export const DaoCardDetail: React.FC = ({ community, setIsUp {count} members + + COMMUNITY TERMS +
- {community?.description} + {ReactHtmlParser(community?.description ? community?.description : "")} {isConnected ? ( ({ cursor: "pointer", @@ -195,7 +196,7 @@ export const ProposalDetailCard: React.FC<{ poll: Poll | undefined; daoId: strin - {poll?.description} + {ReactHtmlParser(poll?.description ? poll?.description : "")} @@ -209,7 +210,6 @@ export const ProposalDetailCard: React.FC<{ poll: Poll | undefined; daoId: strin ) : null} - ) ) } diff --git a/src/modules/lite/explorer/components/ProposalList.tsx b/src/modules/lite/explorer/components/ProposalList.tsx index 2351b46e..c805e5e4 100644 --- a/src/modules/lite/explorer/components/ProposalList.tsx +++ b/src/modules/lite/explorer/components/ProposalList.tsx @@ -28,7 +28,8 @@ export const StyledDivider = styled(Divider)({ height: 0.3, backgroundColor: "#7d8c8b", marginTop: 0, - marginBottom: 0 + marginBottom: 0, + width: "inherit" }) const NoProposalsText = styled(Typography)({ @@ -209,7 +210,7 @@ export const ProposalList: React.FC<{ polls: Poll[]; id: string | undefined; dao {communityPolls && communityPolls.length > 0 ? ( communityPolls.map((poll, i) => { return ( -
+
{communityPolls.length - 1 !== i ? : null}
diff --git a/src/modules/lite/explorer/components/ProposalTableRow.tsx b/src/modules/lite/explorer/components/ProposalTableRow.tsx index 26e66120..3119195c 100644 --- a/src/modules/lite/explorer/components/ProposalTableRow.tsx +++ b/src/modules/lite/explorer/components/ProposalTableRow.tsx @@ -6,6 +6,7 @@ import { useHistory } from "react-router" import { Blockie } from "modules/common/Blockie" import { toShortAddress } from "services/contracts/utils" import { Poll } from "models/Polls" +import ReactHtmlParser from "react-html-parser" export interface ProposalTableRowData { daoId?: string @@ -32,7 +33,8 @@ const BlockieContainer = styled(Grid)({ const DescriptionText = styled(Typography)(({ theme }) => ({ fontWeight: 300, fontSize: 18, - marginBottom: 25, + width: "inherit", + wordBreak: "break-word", [theme.breakpoints.down("sm")]: { fontSize: 16 } @@ -76,7 +78,7 @@ export const ProposalTableRow: React.FC<{ poll: Poll; daoId?: string }> = ({ pol - {poll.description} + {ReactHtmlParser(poll.description)} diff --git a/src/modules/lite/explorer/components/VoteDetails.tsx b/src/modules/lite/explorer/components/VoteDetails.tsx index ef06c14e..c2ff6886 100644 --- a/src/modules/lite/explorer/components/VoteDetails.tsx +++ b/src/modules/lite/explorer/components/VoteDetails.tsx @@ -67,10 +67,7 @@ export const VoteDetails: React.FC<{ poll: Poll | undefined; choices: Choice[]; const handleClickOpen = () => { setVotes(choices.filter(elem => elem.walletAddresses.length > 0)) - - if (!isMobile) { - setOpen(true) - } + setOpen(true) } const handleClose = () => { @@ -155,7 +152,7 @@ export const VoteDetails: React.FC<{ poll: Poll | undefined; choices: Choice[]; handleClickOpen()}> {getTotalVoters(choices)} - + handleClickOpen()}> Votes {isTokenDelegationSupported && turnout ? ( diff --git a/src/modules/lite/explorer/components/VotesDialog.tsx b/src/modules/lite/explorer/components/VotesDialog.tsx index 2e69a723..d756a796 100644 --- a/src/modules/lite/explorer/components/VotesDialog.tsx +++ b/src/modules/lite/explorer/components/VotesDialog.tsx @@ -8,31 +8,56 @@ import { styled, Typography, Button, - Grid + Grid, + useTheme, + useMediaQuery } from "@material-ui/core" import { toShortAddress } from "services/contracts/utils" import { FileCopyOutlined } from "@material-ui/icons" import { Choice } from "models/Choice" import { formatByDecimals, getTotalVoters } from "services/lite/utils" import { useNotification } from "modules/common/hooks/useNotification" +import { ResponsiveDialog } from "modules/explorer/components/ResponsiveDialog" -const CustomContent = styled(DialogContent)({ - padding: "0px 54px 22px 54px !important" -}) +const CustomContent = styled(DialogContent)(({ theme }) => ({ + padding: 0, + display: "grid", + marginTop: 24, + [theme.breakpoints.down("sm")]: { + marginTop: 0, + display: "inline", + paddingTop: "0px !important" + } +})) -const CustomDialogActions = styled(DialogActions)({ - justifyContent: "center !important", - paddingBottom: 20 -}) +const CustomDialogActions = styled(DialogActions)(({ theme }) => ({ + justifyContent: "flex-end !important", + paddingBottom: 20, + [theme.breakpoints.down("sm")]: { + marginTop: 46 + } +})) const CopyIcon = styled(FileCopyOutlined)({ marginLeft: 8, cursor: "pointer" }) -const CustomTitle = styled(Typography)(({ theme }) => ({ - borderBottom: `0.3px solid ${theme.palette.primary.main}`, - paddingBottom: 16 +const Row = styled(Grid)(({ theme }) => ({ + "background": theme.palette.primary.main, + "padding": "24px 48px", + "paddingBottom": "0px", + "borderBottom": "0.3px solid #7D8C8B", + "&:last-child": { + borderRadius: "0px 0px 8px 8px", + borderBottom: "none" + }, + "&:first-child": { + borderRadius: "8px 8px 0px 0px" + }, + [theme.breakpoints.down("sm")]: { + padding: "12px 24px" + } })) export const VotesDialog: React.FC<{ @@ -45,6 +70,9 @@ export const VotesDialog: React.FC<{ const descriptionElementRef = React.useRef(null) const openNotification = useNotification() + const theme = useTheme() + const isMobileSmall = useMediaQuery(theme.breakpoints.down("sm")) + React.useEffect(() => { if (open) { const { current: descriptionElement } = descriptionElementRef @@ -65,56 +93,71 @@ export const VotesDialog: React.FC<{ return (
- - - {" "} - - {getTotalVoters(choices)} Votes: - - - - {choices.map((elem: Choice, index: number) => { - { - return elem.walletAddresses.map((choice, num) => { - return ( - - - {toShortAddress(choice.address)} - copyAddress(choice.address)} color="secondary" fontSize="inherit" /> - - - - {" "} - {elem.name}{" "} - - - - - {" "} - {formatByDecimals(choice.balanceAtReferenceBlock, decimals)} {symbol}{" "} - - + {choices.map((elem: Choice, index: number) => { + { + return elem.walletAddresses.map((choice, num) => { + return ( + + + {toShortAddress(choice.address)} + copyAddress(choice.address)} color="secondary" fontSize="inherit" /> + + + + {" "} + {elem.name}{" "} + + + + + {" "} + {formatByDecimals(choice.balanceAtReferenceBlock, decimals)} {symbol}{" "} + - ) - }) - } - })} - + + ) + }) + } + })} - +
) } diff --git a/src/modules/lite/explorer/components/tables/RowContainer.tsx b/src/modules/lite/explorer/components/tables/RowContainer.tsx index 70dd3253..c1f4f713 100644 --- a/src/modules/lite/explorer/components/tables/RowContainer.tsx +++ b/src/modules/lite/explorer/components/tables/RowContainer.tsx @@ -5,6 +5,7 @@ export const RowContainer = styled(Grid)(({ theme }) => ({ padding: "44px 38px", cursor: "pointer", [theme.breakpoints.down("md")]: { - padding: "44px 38px" + padding: "34px 38px", + width: "inherit" } })) diff --git a/src/modules/lite/explorer/hooks/useHolderTotalCount.tsx b/src/modules/lite/explorer/hooks/useHolderTotalCount.tsx index 871478da..ecf68950 100644 --- a/src/modules/lite/explorer/hooks/useHolderTotalCount.tsx +++ b/src/modules/lite/explorer/hooks/useHolderTotalCount.tsx @@ -3,8 +3,9 @@ import React, { useEffect, useState } from "react" import { useNotification } from "modules/common/hooks/useNotification" import { Network } from "services/beacon" import { networkNameMap } from "services/bakingBad" +import { getTokenHoldersCount } from "services/utils/utils" -export const useHoldersTotalCount = (network: Network, tokenAddress: string) => { +export const useHoldersTotalCount = (network: Network, tokenAddress: string, tokenID: number) => { const [count, setCount] = useState(0) const openNotification = useNotification() @@ -12,36 +13,15 @@ export const useHoldersTotalCount = (network: Network, tokenAddress: string) => async function fetchTotalCount() { try { if (tokenAddress !== "") { - const url = `https://api.${networkNameMap[network]}.tzkt.io/v1/tokens/balances/?token.contract=${tokenAddress}` - await fetch(url).then(async response => { - if (!response.ok) { - openNotification({ - message: "An error has occurred", - autoHideDuration: 2000, - variant: "error" - }) - return - } - - const record: any[] = await response.json() - - const nonZeroBalance = record.filter((item: any) => item.balance !== "0") - if (!record) { - return - } - - setCount(nonZeroBalance.length) - return - }) + const holdersCount = await getTokenHoldersCount(network, tokenAddress, tokenID) + setCount(holdersCount) } - return } catch (error) { openNotification({ message: "An error has occurred", autoHideDuration: 2000, variant: "error" }) - return } } fetchTotalCount() diff --git a/src/modules/lite/explorer/hooks/usePolls.tsx b/src/modules/lite/explorer/hooks/usePolls.tsx index ee5ecc49..2b9efcab 100644 --- a/src/modules/lite/explorer/hooks/usePolls.tsx +++ b/src/modules/lite/explorer/hooks/usePolls.tsx @@ -30,12 +30,12 @@ export const usePolls = (id: any) => { return } - // @TODO Add functinolity if needed for card in proposal list - // communityPolls.map(community => { - // community.timeFormatted = isProposalActive(Number(community.endTime)) - // community.isActive = !community.timeFormatted.includes("ago") ? ProposalStatus.ACTIVE : ProposalStatus.CLOSED - // }) + communityPolls.map(community => { + community.timeFormatted = isProposalActive(Number(community.endTime)) + community.isActive = !community.timeFormatted.includes("ago") ? ProposalStatus.ACTIVE : ProposalStatus.CLOSED + }) + // @TODO Add functinolity if needed for card in proposal list // communityPolls.forEach(async poll => { // if (poll) { // await fetch(`${getEnv(EnvKey.REACT_APP_LITE_API_URL)}/choices/${poll._id}/votes`).then(async response => { diff --git a/src/modules/lite/explorer/pages/CreateProposal/index.tsx b/src/modules/lite/explorer/pages/CreateProposal/index.tsx index 6c9b42fb..96ab1847 100644 --- a/src/modules/lite/explorer/pages/CreateProposal/index.tsx +++ b/src/modules/lite/explorer/pages/CreateProposal/index.tsx @@ -9,7 +9,8 @@ import { withTheme, TextareaAutosize, useTheme, - useMediaQuery + useMediaQuery, + Tooltip } from "@material-ui/core" import { Choices } from "../../components/Choices" @@ -30,6 +31,12 @@ import { isWebUri } from "valid-url" import { useDAO } from "services/services/dao/hooks/useDAO" import { useDAOID } from "modules/explorer/pages/DAO/router" import { useUserTokenBalance } from "services/contracts/token/hooks/useUserTokenBalance" +import CodeIcon from "@mui/icons-material/Code" +import CodeOffIcon from "@mui/icons-material/CodeOff" +import { ProposalCodeEditorInput } from "modules/explorer/components/ProposalFormInput" +import Prism, { highlight } from "prismjs" +import "prism-themes/themes/prism-night-owl.css" + dayjs.extend(duration) const ProposalContainer = styled(Grid)(({ theme }) => ({ @@ -39,6 +46,26 @@ const ProposalContainer = styled(Grid)(({ theme }) => ({ } })) +const CodeButton = styled(CodeIcon)(({ theme }) => ({ + background: theme.palette.primary.main, + padding: 3, + borderTopLeftRadius: 4, + borderTopRightRadius: 4, + borderBottom: "0.5px solid", + cursor: "pointer", + color: theme.palette.secondary.main +})) + +const CodeOffButton = styled(CodeOffIcon)(({ theme }) => ({ + background: theme.palette.primary.main, + padding: 3, + borderTopLeftRadius: 4, + borderTopRightRadius: 4, + borderBottom: "0.5px solid", + cursor: "pointer", + color: theme.palette.secondary.main +})) + const CustomFormikTextField = withStyles({ root: { "& .MuiInput-root": { @@ -47,9 +74,10 @@ const CustomFormikTextField = withStyles({ }, "& .MuiInputBase-input": { textAlign: "initial", + marginTop: 16, paddingTop: 19, + borderRadius: 8, paddingLeft: 26, - borderRadius: 4, paddingBottom: 19, fontSize: 18, background: "#2f3438" @@ -67,6 +95,32 @@ const CustomFormikTextField = withStyles({ disabled: {} })(FormikTextField) +const CustomFormikTimeTextField = withStyles({ + root: { + "& .MuiInput-root": { + fontWeight: 300, + textAlign: "initial" + }, + "& .MuiInputBase-input": { + textAlign: "initial", + borderRadius: 8, + paddingLeft: 30, + fontSize: 18, + background: "#2f3438" + }, + "& .MuiInput-underline:before": { + borderBottom: "none !important" + }, + "& .MuiInput-underline:hover:before": { + borderBottom: "none !important" + }, + "& .MuiInput-underline:after": { + borderBottom: "none !important" + } + }, + disabled: {} +})(FormikTextField) + const PageContainer = styled("div")({ height: "100%", margin: "auto", @@ -79,7 +133,7 @@ const PageContainer = styled("div")({ ["@media (max-width:1335px)"]: {}, ["@media (max-width:1167px)"]: { - width: "78vw" + width: "86vw !important" }, ["@media (max-width:1030px)"]: {}, @@ -102,17 +156,18 @@ const ProposalChoices = styled(Grid)({ }) const CustomTextarea = styled(withTheme(TextareaAutosize))(props => ({ - "minHeight": 117, + "minHeight": 192, "boxSizing": "border-box", "width": "100%", "fontWeight": 300, "paddingTop": 19, "paddingLeft": 26, "border": "none", + "borderTopRightRadius": 0, "fontSize": 17, "color": props.theme.palette.text.primary, "background": props.theme.palette.primary.main, - "borderRadius": 4, + "borderRadius": 8, "paddingRight": 40, "wordBreak": "break-word", "fontFamily": "Roboto Mono", @@ -126,7 +181,7 @@ const CommunityLabel = styled(Grid)({ minWidth: 212, height: 54, background: "#2F3438", - borderRadius: 4, + borderRadius: 8, display: "inline-grid", marginBottom: 25, width: "fit-content", @@ -141,25 +196,16 @@ const ErrorText = styled(Typography)({ }) const ErrorTextTime = styled(Typography)({ - marginTop: -18, marginBottom: 0, fontSize: 14, color: "red" }) -const ErrorTextChoices = styled(Typography)({ - fontSize: 14, - color: "red", - marginBottom: -21, - marginTop: -86 -}) - const TimeBox = styled(Grid)(({ theme }) => ({ background: theme.palette.primary.main, borderRadius: 8, width: 72, minHeight: 59, - marginBottom: 16, display: "grid", [theme.breakpoints.down("sm")]: { "width": 172, @@ -172,10 +218,7 @@ const TimeBox = styled(Grid)(({ theme }) => ({ const TimeContainer = styled(Grid)(({ theme }) => ({ alignItems: "baseline", marginTop: 0, - gap: 10, - [theme.breakpoints.down("md")]: { - marginTop: 30 - } + gap: 10 })) const TimeContainerMobile = styled(Grid)(({ theme }) => ({ @@ -193,17 +236,6 @@ const hasDuplicates = (options: string[]) => { return new Set(trimOptions).size !== trimOptions.length } -const isValidHttpUrl = (externalLink: string) => { - let url - try { - url = new URL(externalLink) - } catch (_) { - return false - } - - return url.protocol === "http:" || url.protocol === "https:" -} - const validateForm = (values: Poll) => { const errors: FormikErrors = {} @@ -285,7 +317,27 @@ export const ProposalForm = ({ const { pathname } = useLocation() + const codeEditorStyles = { + minHeight: 500, + fontFamily: "Roboto Mono", + fontSize: 14, + fontWeight: 400, + outlineWidth: 0, + color: "white" + } + const shouldShowBar = pathname.includes("/lite") ? true : false + const [isMarkup, setIsMarkup] = useState(false) + const grammar = Prism.languages.markup + const codeEditorPlaceholder = ` + + + Proposal Description + + +

...

+ + ` const hasErrors = errors.endTimeDays || errors.endTimeHours || errors.endTimeMinutes return ( @@ -301,35 +353,185 @@ export const ProposalForm = ({ New Proposal ) : null} - - - + + + + Proposal Title {errors?.name && touched.name ? {errors.name} : null} - - - {() => ( - { - setFieldValue("description", newValue.target.value) - }} - /> + + {!isMobileSmall ? ( + <> + + + Set Poll Duration + + + { + if (getIn(values, "endTimeDays") === 0) { + setFieldValue("endTimeDays", "") + setFieldTouched("endTimeDays") + } + }} + onChange={(newValue: any) => { + if (newValue.target.value === "") { + setFieldValue("endTimeDays", null) + } else { + setFieldValue("endTimeDays", parseInt(newValue.target.value, 10)) + } + }} + /> + + + { + if (getIn(values, "endTimeHours") === 0) { + setFieldValue("endTimeHours", "") + } + }} + onChange={(newValue: any) => { + if (newValue.target.value === "") { + setFieldValue("endTimeHours", null) + } else { + setFieldValue("endTimeHours", parseInt(newValue.target.value, 10)) + } + }} + /> + + + + { + if (getIn(values, "endTimeMinutes") === 0) { + setFieldValue("endTimeMinutes", "") + } + }} + onChange={(newValue: any) => { + if (newValue.target.value === "") { + setFieldValue("endTimeMinutes", null) + } else { + setFieldValue("endTimeMinutes", parseInt(newValue.target.value, 10)) + } + }} + /> + + + {getIn(values, "endTimeDays") !== null && + getIn(values, "endTimeHours") !== null && + getIn(values, "endTimeMinutes") !== null && + !hasErrors ? ( + + + End date: + + + {" "} + {dayjs(Number(finalDate)).format("MM/DD/YYYY h:mm A")} + + + ) : null} + + + {errors?.endTimeDays && touched.endTimeDays ? ( + {errors.endTimeDays} + ) : null} + + + + + ) : null} + + + Description + + {!isMarkup ? ( +
+ + setIsMarkup(true)} /> + +
+ ) : ( +
+ + setIsMarkup(false)} /> + +
)} -
+ {!isMarkup ? ( + + {() => ( + { + setFieldValue("description", newValue.target.value) + }} + /> + )} + + ) : ( + + {() => ( + { + console.log(newValue) + setFieldValue("description", newValue) + }} + highlight={code => highlight(code, grammar, "javascript")} + placeholder={codeEditorPlaceholder} + /> + )} + + )} +
- + + + External Link {errors?.externalLink && touched.externalLink ? {errors.externalLink} : null} @@ -348,7 +550,7 @@ export const ProposalForm = ({ name="endTimeDays" type="number" placeholder="DD" - component={CustomFormikTextField} + component={CustomFormikTimeTextField} inputProps={{ min: 0 }} onClick={() => { if (getIn(values, "endTimeDays") === 0) { @@ -372,7 +574,7 @@ export const ProposalForm = ({ name="endTimeHours" type="number" placeholder="HH" - component={CustomFormikTextField} + component={CustomFormikTimeTextField} inputProps={{ min: 0 }} onClick={() => { if (getIn(values, "endTimeHours") === 0) { @@ -396,7 +598,7 @@ export const ProposalForm = ({ name="endTimeMinutes" type="number" placeholder="MM" - component={CustomFormikTextField} + component={CustomFormikTimeTextField} inputProps={{ min: 0 }} onClick={() => { if (getIn(values, "endTimeMinutes") === 0) { @@ -417,10 +619,10 @@ export const ProposalForm = ({ getIn(values, "endTimeMinutes") !== null && !hasErrors ? ( - + End date: - + {" "} {dayjs(Number(finalDate)).format("MM/DD/YYYY h:mm A")} @@ -442,119 +644,11 @@ export const ProposalForm = ({ submitForm={submitForm} votingStrategy={getIn(values, "votingStrategy")} setFieldValue={setFieldValue} + touched={touched.choices} + errors={errors.choices} /> - {errors?.choices && touched.choices ? {errors.choices} : null}
- - {!isMobileSmall ? ( - <> - - - Set Poll Duration - - - { - if (getIn(values, "endTimeDays") === 0) { - setFieldValue("endTimeDays", "") - setFieldTouched("endTimeDays") - } - }} - onChange={(newValue: any) => { - if (newValue.target.value === "") { - setFieldValue("endTimeDays", null) - } else { - setFieldValue("endTimeDays", parseInt(newValue.target.value, 10)) - } - }} - /> - - - { - if (getIn(values, "endTimeHours") === 0) { - setFieldValue("endTimeHours", "") - } - }} - onChange={(newValue: any) => { - if (newValue.target.value === "") { - setFieldValue("endTimeHours", null) - } else { - setFieldValue("endTimeHours", parseInt(newValue.target.value, 10)) - } - }} - /> - - - - { - if (getIn(values, "endTimeMinutes") === 0) { - setFieldValue("endTimeMinutes", "") - } - }} - onChange={(newValue: any) => { - if (newValue.target.value === "") { - setFieldValue("endTimeMinutes", null) - } else { - setFieldValue("endTimeMinutes", parseInt(newValue.target.value, 10)) - } - }} - /> - - {getIn(values, "endTimeDays") !== null && - getIn(values, "endTimeHours") !== null && - getIn(values, "endTimeMinutes") !== null && - !hasErrors ? ( - - - End date: - - - {" "} - {dayjs(Number(finalDate)).format("MM/DD/YYYY h:mm A")} - - - ) : null} - - - {errors?.endTimeDays && touched.endTimeDays ? ( - {errors.endTimeDays} - ) : null} - - - - ) : null}
@@ -657,7 +751,7 @@ export const ProposalCreator: React.FC<{ id?: string; onClose?: any }> = props = return ( - + = ({ id }) => { const theme = useTheme() const isMobileSmall = useMediaQuery(theme.breakpoints.down("sm")) const { state } = useLocation<{ poll: Poll; choices: Choice[]; daoId: string }>() - + const navigate = useHistory() const { data: dao } = useDAO(state?.daoId) const { account, wallet } = useTezos() const openNotification = useNotification() @@ -62,7 +63,10 @@ export const ProposalDetails: React.FC<{ id: string }> = ({ id }) => { const community = useCommunity(id) const poll = useSinglePoll(proposalId, id, community) const choices = usePollChoices(poll, refresh) - const { data: voteWeight } = useTokenVoteWeight(dao?.data.token.contract, poll?.referenceBlock) + const { data: voteWeight } = useTokenVoteWeight( + dao?.data.token.contract || community?.tokenAddress, + poll?.referenceBlock + ) const [selectedVotes, setSelectedVotes] = useState([]) useEffect(() => { @@ -130,7 +134,15 @@ export const ProposalDetails: React.FC<{ id: string }> = ({ id }) => { return ( - + navigate.push(`/explorer/lite/dao/${id}/community/`)} + alignItems="center" + > + + Back to community + @@ -165,7 +177,7 @@ export const ProposalDetails: React.FC<{ id: string }> = ({ id }) => { color="secondary" onClick={() => saveVote()} > - Cast your vote + {voteWeight?.gt(new BigNumber(0)) ? "Cast your vote" : "No Voting Weight"} ) : null} diff --git a/src/services/services/lite/lite-services.ts b/src/services/services/lite/lite-services.ts index 07f0105d..852452d6 100644 --- a/src/services/services/lite/lite-services.ts +++ b/src/services/services/lite/lite-services.ts @@ -131,21 +131,6 @@ export const saveLiteCommunity = async (signature: string, publicKey: string | u return resp } -export const joinLiteCommunity = async (signature: string, publicKey: string | undefined, payloadBytes: string) => { - const resp = await fetch(`${getEnv(EnvKey.REACT_APP_LITE_API_URL)}/daos/join`, { - method: "POST", - body: JSON.stringify({ - signature, - publicKey, - payloadBytes - }), - headers: { - "Content-Type": "application/json" - } - }) - return resp -} - export const saveLiteProposal = async (signature: string, publicKey: string | undefined, payloadBytes: string) => { const resp = await fetch(`${getEnv(EnvKey.REACT_APP_LITE_API_URL)}/poll/add`, { method: "POST", @@ -193,12 +178,9 @@ export const fetchLiteData = async (daoContract: string, network: Network) => { } } -export const updateCount = async (id: string, count: number) => { +export const updateCount = async (id: string) => { const resp = await fetch(`${getEnv(EnvKey.REACT_APP_LITE_API_URL)}/daos/count/${id}`, { method: "POST", - body: JSON.stringify({ - count - }), headers: { "Content-Type": "application/json" } diff --git a/src/theme/index.ts b/src/theme/index.ts index 376daa07..841a4703 100644 --- a/src/theme/index.ts +++ b/src/theme/index.ts @@ -42,7 +42,10 @@ export const theme = createTheme({ } }, subtitle1: { - fontSize: 32 + fontSize: 32, + [breakpoints.down("xs")]: { + fontSize: 26 + } }, subtitle2: { fontSize: 16, @@ -70,7 +73,7 @@ export const theme = createTheme({ body1: { fontSize: 18, [breakpoints.down("xs")]: { - fontSize: 14 + fontSize: 16 } }, body2: { @@ -84,6 +87,11 @@ export const theme = createTheme({ } }, overrides: { + MuiSvgIcon: { + colorSecondary: { + color: "#81FEB7 !important" + } + }, MuiTypography: { root: { letterSpacing: "-0.03em !important" @@ -181,6 +189,13 @@ export const theme = createTheme({ fill: "#fff" } }, + MuiIconButton: { + colorSecondary: { + "&:hover": { + background: "inherit !important" + } + } + }, MuiInput: { underline: { "&:after": { @@ -207,6 +222,7 @@ export const theme = createTheme({ }, disabled: {} }, + MuiButton: { root: { "textTransform": "capitalize", @@ -370,7 +386,7 @@ export const theme = createTheme({ }, MuiTableBody: { root: { - "& > *": { + "& > *:not(:first-child)": { borderTop: "0.3px solid rgba(125,140,139, 0.2)", minHeight: 90 } diff --git a/yarn.lock b/yarn.lock index 220ed879..9b63b4fb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1256,6 +1256,13 @@ dependencies: regenerator-runtime "^0.13.11" +"@babel/runtime@^7.23.2": + version "7.23.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.2.tgz#062b0ac103261d68a966c4c7baf2ae3e62ec3885" + integrity sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/template@^7.18.10", "@babel/template@^7.20.7", "@babel/template@^7.21.9", "@babel/template@^7.3.3": version "7.21.9" resolved "https://registry.npmjs.org/@babel/template/-/template-7.21.9.tgz" @@ -1521,10 +1528,10 @@ resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz" integrity sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA== -"@emotion/react@^11.10.4": - version "11.11.0" - resolved "https://registry.npmjs.org/@emotion/react/-/react-11.11.0.tgz" - integrity sha512-ZSK3ZJsNkwfjT3JpDAWJZlrGD81Z3ytNDsxw1LKq1o+xkmO5pnWfr6gmCC8gHEFf3nSSX/09YrG67jybNPxSUw== +"@emotion/react@^11.11.1": + version "11.11.1" + resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.11.1.tgz#b2c36afac95b184f73b08da8c214fdf861fa4157" + integrity sha512-5mlW1DquU5HaxjLkfkGN1GA/fvVGdyHURRiX/0FHl2cfIfRxSOfmxEH5YS43edp0OldZrZ+dkBKbngxcNCdZvA== dependencies: "@babel/runtime" "^7.18.3" "@emotion/babel-plugin" "^11.11.0" @@ -1551,9 +1558,9 @@ resolved "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz" integrity sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA== -"@emotion/styled@^11.10.4": +"@emotion/styled@^11.11.0": version "11.11.0" - resolved "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.0.tgz" + resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.11.0.tgz#26b75e1b5a1b7a629d7c0a8b708fbf5a9cdce346" integrity sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng== dependencies: "@babel/runtime" "^7.18.3" @@ -1630,6 +1637,33 @@ resolved "https://registry.npmjs.org/@eslint/js/-/js-8.41.0.tgz" integrity sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA== +"@floating-ui/core@^1.4.2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.5.0.tgz#5c05c60d5ae2d05101c3021c1a2a350ddc027f8c" + integrity sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg== + dependencies: + "@floating-ui/utils" "^0.1.3" + +"@floating-ui/dom@^1.5.1": + version "1.5.3" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.5.3.tgz#54e50efcb432c06c23cd33de2b575102005436fa" + integrity sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA== + dependencies: + "@floating-ui/core" "^1.4.2" + "@floating-ui/utils" "^0.1.3" + +"@floating-ui/react-dom@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.0.4.tgz#b076fafbdfeb881e1d86ae748b7ff95150e9f3ec" + integrity sha512-CF8k2rgKeh/49UrnIBs4BdxPUV6vize/Db1d/YbCLyp9GiVZ0BEwf5AiDSxJRCr6yOkGqTFHtmrULxkEfYZ7dQ== + dependencies: + "@floating-ui/dom" "^1.5.1" + +"@floating-ui/utils@^0.1.3": + version "0.1.6" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.1.6.tgz#22958c042e10b67463997bd6ea7115fe28cbcaf9" + integrity sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A== + "@hookform/resolvers@^2.8.1": version "2.9.11" resolved "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-2.9.11.tgz" @@ -2061,82 +2095,88 @@ node-fetch "^2.6.7" ws "^6.0.0" -"@mui/base@5.0.0-beta.3": - version "5.0.0-beta.3" - resolved "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.3.tgz" - integrity sha512-ErOMoGNpgf6BF5W+jgXDiRlXJnpSeg8XSRonuY5UCCMHIlOWtKDtt/LS3qDAbFFGb7tV/y6EBddbcMeexx+zHw== - dependencies: - "@babel/runtime" "^7.21.0" - "@emotion/is-prop-valid" "^1.2.1" - "@mui/types" "^7.2.4" - "@mui/utils" "^5.13.1" - "@popperjs/core" "^2.11.7" - clsx "^1.2.1" +"@mui/base@5.0.0-beta.24": + version "5.0.0-beta.24" + resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.24.tgz#1a0638388291828dacf9547b466bc21fbaad3a2a" + integrity sha512-bKt2pUADHGQtqWDZ8nvL2Lvg2GNJyd/ZUgZAJoYzRgmnxBL9j36MSlS3+exEdYkikcnvVafcBtD904RypFKb0w== + dependencies: + "@babel/runtime" "^7.23.2" + "@floating-ui/react-dom" "^2.0.4" + "@mui/types" "^7.2.9" + "@mui/utils" "^5.14.18" + "@popperjs/core" "^2.11.8" + clsx "^2.0.0" prop-types "^15.8.1" - react-is "^18.2.0" - -"@mui/core-downloads-tracker@^5.13.3": - version "5.13.3" - resolved "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.13.3.tgz" - integrity sha512-w4//nRIi9fiMow/MmhkForOezd8nc229EpSZZ5DzwpJNOmAXwypFTapOUVAGTUQiTJyeZXUNbQqYuUIrIs2nbg== -"@mui/material@^5.10.6": - version "5.13.3" - resolved "https://registry.npmjs.org/@mui/material/-/material-5.13.3.tgz" - integrity sha512-10pek+Bz+PZ4rjUf3KTKfXWjPMUqU1nSnRPf4DAXABhsjzelGGfGW/EICgrLRrttYplTJZhoponWALezAge8ug== - dependencies: - "@babel/runtime" "^7.21.0" - "@mui/base" "5.0.0-beta.3" - "@mui/core-downloads-tracker" "^5.13.3" - "@mui/system" "^5.13.2" - "@mui/types" "^7.2.4" - "@mui/utils" "^5.13.1" - "@types/react-transition-group" "^4.4.6" - clsx "^1.2.1" +"@mui/core-downloads-tracker@^5.14.18": + version "5.14.18" + resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.18.tgz#f8b187dc89756fa5c0b7d15aea537a6f73f0c2d8" + integrity sha512-yFpF35fEVDV81nVktu0BE9qn2dD/chs7PsQhlyaV3EnTeZi9RZBuvoEfRym1/jmhJ2tcfeWXiRuHG942mQXJJQ== + +"@mui/icons-material@^5.14.14": + version "5.14.18" + resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.14.18.tgz#9e92964cde8c7ba32cf50438a83403dc283f2328" + integrity sha512-o2z49R1G4SdBaxZjbMmkn+2OdT1bKymLvAYaB6pH59obM1CYv/0vAVm6zO31IqhwtYwXv6A7sLIwCGYTaVkcdg== + dependencies: + "@babel/runtime" "^7.23.2" + +"@mui/material@^5.14.14": + version "5.14.18" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.14.18.tgz#d0a89be3e27afe90135d542ddbf160b3f34e869c" + integrity sha512-y3UiR/JqrkF5xZR0sIKj6y7xwuEiweh9peiN3Zfjy1gXWXhz5wjlaLdoxFfKIEBUFfeQALxr/Y8avlHH+B9lpQ== + dependencies: + "@babel/runtime" "^7.23.2" + "@mui/base" "5.0.0-beta.24" + "@mui/core-downloads-tracker" "^5.14.18" + "@mui/system" "^5.14.18" + "@mui/types" "^7.2.9" + "@mui/utils" "^5.14.18" + "@types/react-transition-group" "^4.4.8" + clsx "^2.0.0" csstype "^3.1.2" prop-types "^15.8.1" react-is "^18.2.0" react-transition-group "^4.4.5" -"@mui/private-theming@^5.13.1": - version "5.13.1" - resolved "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.13.1.tgz" - integrity sha512-HW4npLUD9BAkVppOUZHeO1FOKUJWAwbpy0VQoGe3McUYTlck1HezGHQCfBQ5S/Nszi7EViqiimECVl9xi+/WjQ== +"@mui/private-theming@^5.14.18": + version "5.14.18" + resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.14.18.tgz#98f97139ea21570493391ab377c1deb47fc6d1a2" + integrity sha512-WSgjqRlzfHU+2Rou3HlR2Gqfr4rZRsvFgataYO3qQ0/m6gShJN+lhVEvwEiJ9QYyVzMDvNpXZAcqp8Y2Vl+PAw== dependencies: - "@babel/runtime" "^7.21.0" - "@mui/utils" "^5.13.1" + "@babel/runtime" "^7.23.2" + "@mui/utils" "^5.14.18" prop-types "^15.8.1" -"@mui/styled-engine@^5.13.2": - version "5.13.2" - resolved "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.13.2.tgz" - integrity sha512-VCYCU6xVtXOrIN8lcbuPmoG+u7FYuOERG++fpY74hPpEWkyFQG97F+/XfTQVYzlR2m7nPjnwVUgATcTCMEaMvw== +"@mui/styled-engine@^5.14.18": + version "5.14.18" + resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.14.18.tgz#82d427bc975b85cecdbab2fd9353ed6c2df7eae1" + integrity sha512-pW8bpmF9uCB5FV2IPk6mfbQCjPI5vGI09NOLhtGXPeph/4xIfC3JdIX0TILU0WcTs3aFQqo6s2+1SFgIB9rCXA== dependencies: - "@babel/runtime" "^7.21.0" + "@babel/runtime" "^7.23.2" "@emotion/cache" "^11.11.0" csstype "^3.1.2" prop-types "^15.8.1" -"@mui/system@^5.13.2": - version "5.13.2" - resolved "https://registry.npmjs.org/@mui/system/-/system-5.13.2.tgz" - integrity sha512-TPyWmRJPt0JPVxacZISI4o070xEJ7ftxpVtu6LWuYVOUOINlhoGOclam4iV8PDT3EMQEHuUrwU49po34UdWLlw== - dependencies: - "@babel/runtime" "^7.21.0" - "@mui/private-theming" "^5.13.1" - "@mui/styled-engine" "^5.13.2" - "@mui/types" "^7.2.4" - "@mui/utils" "^5.13.1" - clsx "^1.2.1" +"@mui/system@^5.14.18": + version "5.14.18" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.14.18.tgz#0f671e8f0a5e8e965b79235d77c50098f54195b5" + integrity sha512-hSQQdb3KF72X4EN2hMEiv8EYJZSflfdd1TRaGPoR7CIAG347OxCslpBUwWngYobaxgKvq6xTrlIl+diaactVww== + dependencies: + "@babel/runtime" "^7.23.2" + "@mui/private-theming" "^5.14.18" + "@mui/styled-engine" "^5.14.18" + "@mui/types" "^7.2.9" + "@mui/utils" "^5.14.18" + clsx "^2.0.0" csstype "^3.1.2" prop-types "^15.8.1" -"@mui/types@^7.2.4": - version "7.2.4" - resolved "https://registry.npmjs.org/@mui/types/-/types-7.2.4.tgz" - integrity sha512-LBcwa8rN84bKF+f5sDyku42w1NTxaPgPyYKODsh01U1fVstTClbUoSA96oyRBnSNyEiAVjKm6Gwx9vjR+xyqHA== +"@mui/types@^7.2.9": + version "7.2.9" + resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.9.tgz#730ee83a37af292a5973962f78ce5c95f31213a7" + integrity sha512-k1lN/PolaRZfNsRdAqXtcR71sTnv3z/VCCGPxU8HfdftDkzi335MdJ6scZxvofMAd/K/9EbzCZTFBmlNpQVdCg== -"@mui/utils@^5.10.3", "@mui/utils@^5.13.1": +"@mui/utils@^5.10.3": version "5.13.1" resolved "https://registry.npmjs.org/@mui/utils/-/utils-5.13.1.tgz" integrity sha512-6lXdWwmlUbEU2jUI8blw38Kt+3ly7xkmV9ljzY4Q20WhsJMWiNry9CX8M+TaP/HbtuyR8XKsdMgQW7h7MM3n3A== @@ -2147,6 +2187,16 @@ prop-types "^15.8.1" react-is "^18.2.0" +"@mui/utils@^5.14.18": + version "5.14.18" + resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.14.18.tgz#d2a46df9b06230423ba6b6317748b27185a56ac3" + integrity sha512-HZDRsJtEZ7WMSnrHV9uwScGze4wM/Y+u6pDVo+grUjt5yXzn+wI8QX/JwTHh9YSw/WpnUL80mJJjgCnWj2VrzQ== + dependencies: + "@babel/runtime" "^7.23.2" + "@types/prop-types" "^15.7.10" + prop-types "^15.8.1" + react-is "^18.2.0" + "@mui/x-date-pickers@^5.0.2": version "5.0.20" resolved "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-5.0.20.tgz" @@ -2208,9 +2258,9 @@ schema-utils "^3.0.0" source-map "^0.7.3" -"@popperjs/core@^2.11.7": +"@popperjs/core@^2.11.8": version "2.11.8" - resolved "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== "@reach/portal@^0.13.0": @@ -3162,6 +3212,11 @@ resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz" integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== +"@types/prop-types@^15.7.10": + version "15.7.10" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.10.tgz#892afc9332c4d62a5ea7e897fe48ed2085bbb08a" + integrity sha512-mxSnDQxPqsZxmeShFH+uwQ4kO4gcJcGahjjMFeLbKE95IAZiiZyiEepGZjtXJ7hN/yfu0bu9xN2ajcU0JcxX6A== + "@types/q@^1.5.1": version "1.5.5" resolved "https://registry.npmjs.org/@types/q/-/q-1.5.5.tgz" @@ -3232,13 +3287,20 @@ "@types/history" "^4.7.11" "@types/react" "*" -"@types/react-transition-group@^4.2.0", "@types/react-transition-group@^4.4.5", "@types/react-transition-group@^4.4.6": +"@types/react-transition-group@^4.2.0", "@types/react-transition-group@^4.4.5": version "4.4.6" resolved "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.6.tgz" integrity sha512-VnCdSxfcm08KjsJVQcfBmhEQAPnLB8G08hAxn39azX1qYBQ/5RVQuoHuKIcfKOdncuaUvEpFKFzEvbtIMsfVew== dependencies: "@types/react" "*" +"@types/react-transition-group@^4.4.8": + version "4.4.9" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.9.tgz#12a1a1b5b8791067198149867b0823fbace31579" + integrity sha512-ZVNmWumUIh5NhH8aMD9CR2hdW0fNuYInlocZHaZ+dgk/1K49j1w/HoAuK1ki+pgscQrOFRTlXeoURtuzEkV3dg== + dependencies: + "@types/react" "*" + "@types/react@*", "@types/react@^17", "@types/react@^17.0.3", "@types/react@~17.0.3": version "17.0.60" resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.60.tgz#a4a97dcdbebad76612c188fc06440e4995fd8ad2" @@ -4482,6 +4544,11 @@ big.js@^5.2.2: resolved "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz" integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== +"bignumber.js@^8 || ^9": + version "9.1.2" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.2.tgz#b7c4242259c008903b13707983b5f4bbd31eda0c" + integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug== + bignumber.js@^9.0.1, bignumber.js@^9.1.0: version "9.1.1" resolved "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz" @@ -4980,6 +5047,11 @@ clsx@^1.0.4, clsx@^1.1.0, clsx@^1.2.1: resolved "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz" integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== +clsx@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.0.0.tgz#12658f3fd98fafe62075595a5c30e43d18f3d00b" + integrity sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q== + co@^4.6.0: version "4.6.0" resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz" @@ -5794,12 +5866,21 @@ dom-serializer@^1.0.1: domhandler "^4.2.0" entities "^2.0.0" +dom-serializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53" + integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.2" + entities "^4.2.0" + domelementtype@1, domelementtype@^1.3.1: version "1.3.1" resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz" integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== -domelementtype@^2.0.1, domelementtype@^2.2.0: +domelementtype@^2.0.1, domelementtype@^2.2.0, domelementtype@^2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz" integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== @@ -5811,6 +5892,13 @@ domexception@^2.0.1: dependencies: webidl-conversions "^5.0.0" +domhandler@5.0.3, domhandler@^5.0.2, domhandler@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31" + integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w== + dependencies: + domelementtype "^2.3.0" + domhandler@^2.3.0, domhandler@^2.4.0: version "2.4.2" resolved "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz" @@ -5842,6 +5930,15 @@ domutils@^2.5.2, domutils@^2.8.0: domelementtype "^2.2.0" domhandler "^4.2.0" +domutils@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.1.0.tgz#c47f551278d3dc4b0b1ab8cbb42d751a6f0d824e" + integrity sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA== + dependencies: + dom-serializer "^2.0.0" + domelementtype "^2.3.0" + domhandler "^5.0.3" + dot-case@^3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz" @@ -5972,6 +6069,11 @@ entities@^2.0.0: resolved "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz" integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== +entities@^4.2.0, entities@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + error-ex@^1.3.1: version "1.3.2" resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" @@ -7322,6 +7424,14 @@ hpack.js@^2.1.6: readable-stream "^2.0.1" wbuf "^1.1.0" +html-dom-parser@5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/html-dom-parser/-/html-dom-parser-5.0.4.tgz#2941a762317d088e747db31c8cf290987ec30a55" + integrity sha512-azy8THLKd4Ar0OVJpEgX+MSjYvKdNDWlGiRBIlovMqEQYMAnLLXBhhiSwjylDD3RDdcCYT8Utg6uoRDeLHUyHg== + dependencies: + domhandler "5.0.3" + htmlparser2 "9.0.0" + html-encoding-sniffer@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz" @@ -7352,6 +7462,16 @@ html-minifier-terser@^6.0.2: relateurl "^0.2.7" terser "^5.10.0" +html-react-parser@^5.0.6: + version "5.0.6" + resolved "https://registry.yarnpkg.com/html-react-parser/-/html-react-parser-5.0.6.tgz#ee9e8ae404aa38cfbaf3825cb26fabced46024a1" + integrity sha512-aPSzFhO2bK/L/mYQbMwFz+1QG8nhxozbwENt/52HTApasrBvDX87MFD5uSQIjq7Io0bnKzH4uh7PM42zZ4ag9A== + dependencies: + domhandler "5.0.3" + html-dom-parser "5.0.4" + react-property "2.0.2" + style-to-js "1.1.9" + html-void-elements@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/html-void-elements/-/html-void-elements-2.0.1.tgz" @@ -7368,6 +7488,16 @@ html-webpack-plugin@^5.5.0: pretty-error "^4.0.0" tapable "^2.0.0" +htmlparser2@9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-9.0.0.tgz#e431142b7eeb1d91672742dea48af8ac7140cddb" + integrity sha512-uxbSI98wmFT/G4P2zXx4OVx04qWUmyFPrD2/CNepa2Zo3GPNaCaaxElDgwUrwYWkK1nr9fft0Ya8dws8coDLLQ== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.3" + domutils "^3.1.0" + entities "^4.5.0" + htmlparser2@^3.9.0: version "3.10.1" resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz" @@ -7588,6 +7718,11 @@ inline-style-parser@0.1.1: resolved "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz" integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q== +inline-style-parser@0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.2.2.tgz#d498b4e6de0373458fc610ff793f6b14ebf45633" + integrity sha512-EcKzdTHVe8wFVOGEYXiW9WmJXPjqi1T+234YpJr98RiFYKHV3cdy1+3mkTE+KHTHxFFLH51SfaGOoUdW+v7ViQ== + internal-slot@^1.0.3, internal-slot@^1.0.4, internal-slot@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz" @@ -9742,6 +9877,13 @@ nth-check@^2.0.1: dependencies: boolbase "^1.0.0" +numbro@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/numbro/-/numbro-2.4.0.tgz#3cecae307ab2c2d9fd3e1c08249f4abd504bd577" + integrity sha512-t6rVkO1CcKvffvOJJu/zMo70VIcQSR6w3AmIhfHGvmk4vHbNe6zHgomB0aWFAPZWM9JBVWBM0efJv9DBiRoSTA== + dependencies: + bignumber.js "^8 || ^9" + nwsapi@^2.2.0: version "2.2.5" resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.5.tgz" @@ -11094,7 +11236,7 @@ react-hook-form@^7.15.4: react-html-parser@^2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/react-html-parser/-/react-html-parser-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/react-html-parser/-/react-html-parser-2.0.2.tgz#6dbe1ddd2cebc1b34ca15215158021db5fc5685e" integrity sha512-XeerLwCVjTs3njZcgCOeDUqLgNIt/t+6Jgi5/qPsO/krUWl76kWKXMeVs2LhY2gwM6X378DkhLjur0zUQdpz0g== dependencies: htmlparser2 "^3.9.0" @@ -11142,6 +11284,11 @@ react-paginate@^8.2.0: dependencies: prop-types "^15" +react-property@2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/react-property/-/react-property-2.0.2.tgz#d5ac9e244cef564880a610bc8d868bd6f60fdda6" + integrity sha512-+PbtI3VuDV0l6CleQMsx2gtK0JZbZKbpdu5ynr+lbsuvtmgbNcS3VM0tuY2QjFNOcWxvXeHjDpy42RO+4U2rug== + react-query@^3.13.0: version "3.39.3" resolved "https://registry.npmjs.org/react-query/-/react-query-3.39.3.tgz" @@ -11360,6 +11507,11 @@ regenerator-runtime@^0.13.11, regenerator-runtime@^0.13.9: resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz" integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== +regenerator-runtime@^0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45" + integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA== + regenerator-transform@^0.15.1: version "0.15.1" resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz" @@ -12373,6 +12525,20 @@ style-loader@^3.3.1: resolved "https://registry.npmjs.org/style-loader/-/style-loader-3.3.3.tgz" integrity sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw== +style-to-js@1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/style-to-js/-/style-to-js-1.1.9.tgz#5bdc23ba7624016094a19d6ea90fa3f98bee34c4" + integrity sha512-6bkwhOlPOx+wKiHVlPTHjUqM4zDKv9pyccehB8zetZL0hhQ7MVp7UEWUsohjiMdxwhSsEdjMrEve+8qzUVmY4w== + dependencies: + style-to-object "1.0.4" + +style-to-object@1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-1.0.4.tgz#496fded508ce520eca13e738e8af33b8b5af98f2" + integrity sha512-KyNO6mfijxSnypdvEjeXlhvbGPSh0l1zBJp80n+ncBQvrEbSwBHwZCpo0xz6Q4AKSPfXowWwypCBAUAdfz3rFQ== + dependencies: + inline-style-parser "0.2.2" + style-to-object@^0.4.0: version "0.4.1" resolved "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.1.tgz"