From 6b56c6da58f9e3c842fd032e061a94b9fcd9dd3a Mon Sep 17 00:00:00 2001 From: Jan Jaroszczak Date: Mon, 4 Mar 2024 19:24:44 +0100 Subject: [PATCH] New Gov Actions --- .../frontend/public/icons/CopyBlueThin.svg | 11 + govtool/frontend/public/icons/Share.svg | 5 + .../src/components/atoms/CopyButton.tsx | 6 +- .../components/atoms/ExternalModalButton.tsx | 48 +++ .../src/components/atoms/IconLink.tsx | 45 +++ .../frontend/src/components/atoms/Radio.tsx | 44 ++- .../src/components/atoms/SliderArrow.tsx | 40 +++ .../frontend/src/components/atoms/Tooltip.tsx | 2 +- .../src/components/atoms/VotePill.tsx | 3 +- .../frontend/src/components/atoms/index.ts | 3 + .../components/molecules/DataActionsBar.tsx | 4 +- .../molecules/DataMissingInfoBox.tsx | 60 ++++ .../molecules/GovernanceActionCard.tsx | 235 ++++----------- .../molecules/GovernanceActionCardElement.tsx | 140 +++++++++ .../molecules/GovernanceActionCardHeader.tsx | 62 ++++ .../molecules/GovernanceActionCardMyVote.tsx | 56 ++++ .../GovernanceActionCardStatePill.tsx | 50 +++ .../GovernanceActionDetailsCardHeader.tsx | 56 ++++ .../GovernanceActionDetailsCardLinks.tsx | 47 +++ ...GovernanceActionDetailsCardOnChainData.tsx | 79 +++++ .../GovernanceActionDetailsCardVotes.tsx | 61 ++++ .../molecules/GovernanceActionsDatesBox.tsx | 124 ++++++++ .../molecules/GovernanceVotedOnCard.tsx | 285 +++++------------- .../src/components/molecules/Share.tsx | 99 ++++++ .../src/components/molecules/SliderArrows.tsx | 44 +++ .../components/molecules/VoteActionForm.tsx | 187 ++++++++---- .../components/molecules/VotesSubmitted.tsx | 57 ++-- .../src/components/molecules/index.ts | 12 + .../DashboardGovernanceActionDetails.tsx | 16 +- .../organisms/DashboardGovernanceActions.tsx | 2 +- .../DashboardGovernanceActionsVotedOn.tsx | 39 +-- .../organisms/GovernanceActionDetailsCard.tsx | 266 ++++------------ .../GovernanceActionDetailsCardData.tsx | 121 ++++++++ .../organisms/GovernanceActionsToVote.tsx | 157 +++++----- .../src/components/organisms/Slider.tsx | 185 +++++------- .../src/components/organisms/index.ts | 1 + govtool/frontend/src/consts/icons.ts | 2 + govtool/frontend/src/hooks/useSlider.ts | 27 +- govtool/frontend/src/i18n/locales/en.ts | 20 +- .../DashboardGovernanceActionsCategory.tsx | 2 + .../src/pages/GovernanceActionDetails.tsx | 8 +- .../src/pages/GovernanceActionsCategory.tsx | 2 + govtool/frontend/src/theme.ts | 55 ++++ 43 files changed, 1825 insertions(+), 943 deletions(-) create mode 100644 govtool/frontend/public/icons/CopyBlueThin.svg create mode 100644 govtool/frontend/public/icons/Share.svg create mode 100644 govtool/frontend/src/components/atoms/ExternalModalButton.tsx create mode 100644 govtool/frontend/src/components/atoms/IconLink.tsx create mode 100644 govtool/frontend/src/components/atoms/SliderArrow.tsx create mode 100644 govtool/frontend/src/components/molecules/DataMissingInfoBox.tsx create mode 100644 govtool/frontend/src/components/molecules/GovernanceActionCardElement.tsx create mode 100644 govtool/frontend/src/components/molecules/GovernanceActionCardHeader.tsx create mode 100644 govtool/frontend/src/components/molecules/GovernanceActionCardMyVote.tsx create mode 100644 govtool/frontend/src/components/molecules/GovernanceActionCardStatePill.tsx create mode 100644 govtool/frontend/src/components/molecules/GovernanceActionDetailsCardHeader.tsx create mode 100644 govtool/frontend/src/components/molecules/GovernanceActionDetailsCardLinks.tsx create mode 100644 govtool/frontend/src/components/molecules/GovernanceActionDetailsCardOnChainData.tsx create mode 100644 govtool/frontend/src/components/molecules/GovernanceActionDetailsCardVotes.tsx create mode 100644 govtool/frontend/src/components/molecules/GovernanceActionsDatesBox.tsx create mode 100644 govtool/frontend/src/components/molecules/Share.tsx create mode 100644 govtool/frontend/src/components/molecules/SliderArrows.tsx create mode 100644 govtool/frontend/src/components/organisms/GovernanceActionDetailsCardData.tsx diff --git a/govtool/frontend/public/icons/CopyBlueThin.svg b/govtool/frontend/public/icons/CopyBlueThin.svg new file mode 100644 index 000000000..2050c9abe --- /dev/null +++ b/govtool/frontend/public/icons/CopyBlueThin.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/govtool/frontend/public/icons/Share.svg b/govtool/frontend/public/icons/Share.svg new file mode 100644 index 000000000..a8b9eac2b --- /dev/null +++ b/govtool/frontend/public/icons/Share.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/govtool/frontend/src/components/atoms/CopyButton.tsx b/govtool/frontend/src/components/atoms/CopyButton.tsx index 65601c718..2783d0fb7 100644 --- a/govtool/frontend/src/components/atoms/CopyButton.tsx +++ b/govtool/frontend/src/components/atoms/CopyButton.tsx @@ -7,7 +7,7 @@ import { useTranslation } from "@hooks"; interface Props { isChecked?: boolean; text: string; - variant?: string; + variant?: "blueThin" | "blue"; } export const CopyButton = ({ isChecked, text, variant }: Props) => { @@ -19,6 +19,10 @@ export const CopyButton = ({ isChecked, text, variant }: Props) => { return ICONS.copyBlueIcon; } + if (variant === "blueThin") { + return ICONS.copyBlueThinIcon; + } + if (isChecked) { return ICONS.copyWhiteIcon; } diff --git a/govtool/frontend/src/components/atoms/ExternalModalButton.tsx b/govtool/frontend/src/components/atoms/ExternalModalButton.tsx new file mode 100644 index 000000000..c4debddc5 --- /dev/null +++ b/govtool/frontend/src/components/atoms/ExternalModalButton.tsx @@ -0,0 +1,48 @@ +import { Typography } from "@mui/material"; + +import { Button } from "@atoms"; +import { ICONS } from "@consts"; +import { useModal } from "@context"; + +export const ExternalModalButton = ({ + label, + url, +}: { + label: string; + url: string; +}) => { + const { openModal } = useModal(); + + return ( + + ); +}; diff --git a/govtool/frontend/src/components/atoms/IconLink.tsx b/govtool/frontend/src/components/atoms/IconLink.tsx new file mode 100644 index 000000000..0c12fcd1e --- /dev/null +++ b/govtool/frontend/src/components/atoms/IconLink.tsx @@ -0,0 +1,45 @@ +import { Box } from "@mui/material"; + +import { Typography } from "@atoms"; +import { openInNewTab } from "@utils"; +import { ICONS } from "@consts"; + +type IconLinkProps = { + label: string; + navTo: string; + isSmall?: boolean; +}; + +export const IconLink = ({ label, navTo, isSmall }: IconLinkProps) => { + const openLink = () => openInNewTab(navTo); + + return ( + + link + + {label} + + + ); +}; diff --git a/govtool/frontend/src/components/atoms/Radio.tsx b/govtool/frontend/src/components/atoms/Radio.tsx index 538fa7deb..bf4184681 100644 --- a/govtool/frontend/src/components/atoms/Radio.tsx +++ b/govtool/frontend/src/components/atoms/Radio.tsx @@ -1,5 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { Box, Typography } from "@mui/material"; +import { Box } from "@mui/material"; + +import { Typography } from "@atoms"; import { UseFormRegister, UseFormSetValue } from "react-hook-form"; type RadioProps = { @@ -10,11 +12,20 @@ type RadioProps = { setValue: UseFormSetValue; register: UseFormRegister; dataTestId?: string; + disabled?: boolean; }; export const Radio = ({ ...props }: RadioProps) => { - const { isChecked, name, setValue, title, value, dataTestId, register } = - props; + const { + isChecked, + name, + setValue, + title, + value, + dataTestId, + register, + disabled, + } = props; const handleClick = () => { setValue(name, value); @@ -23,13 +34,17 @@ export const Radio = ({ ...props }: RadioProps) => { return ( { + if (!disabled) handleClick(); + }} + borderRadius={isChecked ? "15px" : "12px"} + p={isChecked ? "2px" : 0} + border={isChecked ? 2 : 0} + borderColor={isChecked ? "specialCyanBorder" : undefined} sx={[{ "&:hover": { color: "blue", cursor: "pointer" } }]} - flex={1} + boxShadow={ + "0px 1px 2px 0px rgba(0, 51, 173, 0.08), 0px 1px 6px 1px rgba(0, 51, 173, 0.15)" + } > { checked={isChecked} /> {title} diff --git a/govtool/frontend/src/components/atoms/SliderArrow.tsx b/govtool/frontend/src/components/atoms/SliderArrow.tsx new file mode 100644 index 000000000..2ab59999a --- /dev/null +++ b/govtool/frontend/src/components/atoms/SliderArrow.tsx @@ -0,0 +1,40 @@ +import { Box } from "@mui/material"; +import ChevronRightIcon from "@mui/icons-material/ChevronRight"; + +import { theme } from "@/theme"; + +interface Props { + disabled: boolean; + onClick: (e: any) => void; + left?: boolean; +} + +export const SliderArrow = ({ disabled, onClick, left }: Props) => { + const { + palette: { primaryBlue, arcticWhite, lightBlue }, + } = theme; + + return ( + + + + ); +}; diff --git a/govtool/frontend/src/components/atoms/Tooltip.tsx b/govtool/frontend/src/components/atoms/Tooltip.tsx index 4b8b7a90a..4e2ccdc51 100644 --- a/govtool/frontend/src/components/atoms/Tooltip.tsx +++ b/govtool/frontend/src/components/atoms/Tooltip.tsx @@ -2,7 +2,7 @@ import { styled } from "@mui/material"; import * as TooltipMUI from "@mui/material/Tooltip"; import Typography from "@mui/material/Typography"; -type TooltipProps = Omit & { +export type TooltipProps = Omit & { heading?: string; paragraphOne?: string; paragraphTwo?: string; diff --git a/govtool/frontend/src/components/atoms/VotePill.tsx b/govtool/frontend/src/components/atoms/VotePill.tsx index d28ed9da4..de29ac900 100644 --- a/govtool/frontend/src/components/atoms/VotePill.tsx +++ b/govtool/frontend/src/components/atoms/VotePill.tsx @@ -1,6 +1,7 @@ -import { Vote } from "@models"; import { Box, Typography } from "@mui/material"; +import { Vote } from "@models"; + export const VotePill = ({ vote, width, diff --git a/govtool/frontend/src/components/atoms/index.ts b/govtool/frontend/src/components/atoms/index.ts index 7072b7635..1939a0971 100644 --- a/govtool/frontend/src/components/atoms/index.ts +++ b/govtool/frontend/src/components/atoms/index.ts @@ -5,9 +5,11 @@ export * from "./Checkbox"; export * from "./ClickOutside"; export * from "./CopyButton"; export * from "./DrawerLink"; +export * from "./ExternalModalButton"; export * from "./FormErrorMessage"; export * from "./FormHelpfulText"; export * from "./HighlightedText"; +export * from "./IconLink"; export * from "./InfoText"; export * from "./Input"; export * from "./Link"; @@ -19,6 +21,7 @@ export * from "./modal/ModalWrapper"; export * from "./Radio"; export * from "./ScrollToManage"; export * from "./ScrollToTop"; +export * from "./SliderArrow"; export * from "./Spacer"; export * from "./StakeRadio"; export * from "./TextArea"; diff --git a/govtool/frontend/src/components/molecules/DataActionsBar.tsx b/govtool/frontend/src/components/molecules/DataActionsBar.tsx index 86613a8bc..c54010f5a 100644 --- a/govtool/frontend/src/components/molecules/DataActionsBar.tsx +++ b/govtool/frontend/src/components/molecules/DataActionsBar.tsx @@ -50,7 +50,7 @@ export const DataActionsBar: FC = ({ ...props }) => { return ( <> - + setSearchText(e.target.value)} @@ -76,7 +76,7 @@ export const DataActionsBar: FC = ({ ...props }) => { fontWeight: 500, height: 48, padding: "16px 24px", - width: 231, + width: 500, }} /> { + const { t } = useTranslation(); + + return ( + + + {/* TODO: Text to confirm/change */} + The data that was originally used when this Governance Action was + created has been formatted incorrectly. + + + {/* TODO: Text to confirm/change */} + GovTool uses external sources for Governance Action data, and these + sources are maintained by the proposers of the Actions. This error means + that GovTool cannot locate the data on the URL specified when the + Governance Action was originally posted. + + + // TODO: Add the correct link + openInNewTab( + "https://docs.sanchogov.tools/how-to-use-the-govtool/getting-started/get-a-compatible-wallet" + ) + } + sx={{ + fontFamily: "Poppins", + fontSize: "16px", + lineHeight: "24px", + cursor: "pointer", + }} + > + {t("learnMore")} + + + ); +}; diff --git a/govtool/frontend/src/components/molecules/GovernanceActionCard.tsx b/govtool/frontend/src/components/molecules/GovernanceActionCard.tsx index 567a3fb50..c9f6bbeb3 100644 --- a/govtool/frontend/src/components/molecules/GovernanceActionCard.tsx +++ b/govtool/frontend/src/components/molecules/GovernanceActionCard.tsx @@ -1,16 +1,22 @@ import { FC } from "react"; import { Box } from "@mui/material"; -import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; -import { Button, Typography, Tooltip } from "@atoms"; +import { Button } from "@atoms"; +import { + GovernanceActionCardElement, + GovernanceActionCardHeader, + GovernanceActionsDatesBox, +} from "@molecules"; + import { useScreenDimension, useTranslation } from "@hooks"; import { formatDisplayDate, getFullGovActionId, getProposalTypeLabel, - getShortenedGovActionId, } from "@utils"; -import { theme } from "@/theme"; + +const mockedLongText = + "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Sit, distinctio culpa minus eaque illo quidem voluptates quisquam mollitia consequuntur ex, sequi saepe? Ad ex adipisci molestiae sed."; interface ActionTypeProps extends Omit< @@ -29,6 +35,7 @@ interface ActionTypeProps inProgress?: boolean; txHash: string; index: number; + isDataMissing: boolean; } export const GovernanceActionCard: FC = ({ ...props }) => { @@ -40,14 +47,11 @@ export const GovernanceActionCard: FC = ({ ...props }) => { createdDate, txHash, index, + isDataMissing, } = props; const { isMobile, screenWidth } = useScreenDimension(); const { t } = useTranslation(); - const { - palette: { lightBlue }, - } = theme; - const govActionId = getFullGovActionId(txHash, index); const proposalTypeNoEmptySpaces = getProposalTypeLabel(type).replace( / /g, @@ -56,188 +60,79 @@ export const GovernanceActionCard: FC = ({ ...props }) => { return ( - {inProgress && ( - - - {t("inProgress")} - - - )} - - - {t("govActions.governanceActionType")} - - - - - {getProposalTypeLabel(type)} - - - - - - - {t("govActions.governanceActionId")} - - - - - {getShortenedGovActionId(txHash, index)} - - - - + + + + + - {createdDate ? ( - - - {t("govActions.submissionDate")} - - - {formatDisplayDate(createdDate)} - - - - - - ) : null} - {expiryDate ? ( - - - {t("govActions.expiryDate")} - - - {formatDisplayDate(expiryDate)} - - - - - - ) : null} diff --git a/govtool/frontend/src/components/molecules/GovernanceActionCardElement.tsx b/govtool/frontend/src/components/molecules/GovernanceActionCardElement.tsx new file mode 100644 index 000000000..fe6baf8c2 --- /dev/null +++ b/govtool/frontend/src/components/molecules/GovernanceActionCardElement.tsx @@ -0,0 +1,140 @@ +import { Box } from "@mui/material"; +import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; + +import { Typography, Tooltip, CopyButton, TooltipProps } from "@atoms"; + +type BaseProps = { + label: string; + text: string; + dataTestId?: string; + isSliderCard?: boolean; + tooltipProps?: Omit; + marginBottom?: number; +}; + +type PillVariantProps = BaseProps & { + textVariant: "pill"; + isCopyButton?: false; +}; + +type OtherVariantsProps = BaseProps & { + textVariant?: "oneLine" | "twoLines" | "longText"; + isCopyButton?: boolean; +}; + +type GovernanceActionCardElementProps = PillVariantProps | OtherVariantsProps; + +export const GovernanceActionCardElement = ({ + label, + text, + dataTestId, + isSliderCard, + textVariant = "oneLine", + isCopyButton, + tooltipProps, + marginBottom, +}: GovernanceActionCardElementProps) => { + return ( + + + + {label} + + {tooltipProps && ( + + + + )} + + + {textVariant === "pill" ? ( + + + {text} + + + ) : ( + + + {text} + + {isCopyButton && ( + + + + )} + + )} + + + ); +}; diff --git a/govtool/frontend/src/components/molecules/GovernanceActionCardHeader.tsx b/govtool/frontend/src/components/molecules/GovernanceActionCardHeader.tsx new file mode 100644 index 000000000..148377b7e --- /dev/null +++ b/govtool/frontend/src/components/molecules/GovernanceActionCardHeader.tsx @@ -0,0 +1,62 @@ +import { Box } from "@mui/material"; +import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; + +import { Tooltip, Typography } from "@atoms"; +import { useTranslation } from "@hooks"; + +const mockedLongText = + "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Sit, distinctio culpa minus eaque illo quidem voluptates quisquam mollitia consequuntur ex, sequi saepe? Ad ex adipisci molestiae sed."; + +type GovernanceActionCardHeaderProps = { + title: string; + isDataMissing: boolean; +}; + +export const GovernanceActionCardHeader = ({ + title, + isDataMissing, +}: GovernanceActionCardHeaderProps) => { + const { t } = useTranslation(); + + return ( + + + {isDataMissing ? t("govActions.dataMissing") : title} + + {isDataMissing && ( + + + + )} + + ); +}; diff --git a/govtool/frontend/src/components/molecules/GovernanceActionCardMyVote.tsx b/govtool/frontend/src/components/molecules/GovernanceActionCardMyVote.tsx new file mode 100644 index 000000000..2beba72c8 --- /dev/null +++ b/govtool/frontend/src/components/molecules/GovernanceActionCardMyVote.tsx @@ -0,0 +1,56 @@ +import { Box } from "@mui/material"; + +import { Button, Typography, VotePill } from "@atoms"; +import { openInNewTab } from "@utils"; +import { useTranslation } from "@hooks"; +import { Vote } from "@models"; + +export const GovernanceActionCardMyVote = ({ vote }: { vote: Vote }) => { + const { t } = useTranslation(); + + return ( + + + {t("govActions.myVote")} + + + + + + + + + ); +}; diff --git a/govtool/frontend/src/components/molecules/GovernanceActionCardStatePill.tsx b/govtool/frontend/src/components/molecules/GovernanceActionCardStatePill.tsx new file mode 100644 index 000000000..d2144ea85 --- /dev/null +++ b/govtool/frontend/src/components/molecules/GovernanceActionCardStatePill.tsx @@ -0,0 +1,50 @@ +import { Box } from "@mui/material"; +import CheckIcon from "@mui/icons-material/Check"; + +import { Typography } from "@atoms"; +import { useTranslation } from "@hooks"; + +export const GovernanceActionCardStatePill = ({ + variant = "voteSubmitted", +}: { + variant?: "inProgress" | "voteSubmitted"; +}) => { + const { t } = useTranslation(); + + return ( + + + {variant === "voteSubmitted" && ( + + )} + {variant === "inProgress" + ? t("inProgress") + : t("govActions.voteSubmitted")} + + + ); +}; diff --git a/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardHeader.tsx b/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardHeader.tsx new file mode 100644 index 000000000..a54b65431 --- /dev/null +++ b/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardHeader.tsx @@ -0,0 +1,56 @@ +import { useLocation } from "react-router-dom"; +import { Box } from "@mui/material"; + +import { Typography } from "@atoms"; +import { Share } from "@molecules"; +import { useTranslation } from "@hooks"; + +type GovernanceActionDetailsCardHeaderProps = { + title: string; + isDataMissing: boolean; +}; + +export const GovernanceActionDetailsCardHeader = ({ + title, + isDataMissing, +}: GovernanceActionDetailsCardHeaderProps) => { + const { t } = useTranslation(); + const { pathname, hash } = useLocation(); + + const govActionLinkToShare = `${window.location.protocol}//${ + window.location.hostname + }${window.location.port ? `:${window.location.port}` : ""}${pathname}${hash}`; + + return ( + + + + {isDataMissing ? t("govActions.dataMissing") : title} + + + + + ); +}; diff --git a/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardLinks.tsx b/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardLinks.tsx new file mode 100644 index 000000000..795205e36 --- /dev/null +++ b/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardLinks.tsx @@ -0,0 +1,47 @@ +import { Box } from "@mui/material"; + +import { IconLink, Typography } from "@atoms"; +import { useScreenDimension, useTranslation } from "@hooks"; + +const LINKS = [ + "https://www.google.com", + "https://www.google.com", + "https://www.google.com", + "https://www.google.com", +]; + +export const GovernanceActionDetailsCardLinks = () => { + const { isMobile } = useScreenDimension(); + const { t } = useTranslation(); + + return ( + <> + + {t("govActions.supportingLinks")} + + + {LINKS.map((link, index) => ( + + ))} + + + ); +}; diff --git a/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardOnChainData.tsx b/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardOnChainData.tsx new file mode 100644 index 000000000..ae8872ad4 --- /dev/null +++ b/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardOnChainData.tsx @@ -0,0 +1,79 @@ +import { Box } from "@mui/material"; + +import { Typography } from "@atoms"; +import { useTranslation } from "@hooks"; + +type GovernanceActionDetailsCardOnChainDataProps = { + data: { + label: string; + content: string; + }[]; +}; + +export const GovernanceActionDetailsCardOnChainData = ({ + data, +}: GovernanceActionDetailsCardOnChainDataProps) => { + const { t } = useTranslation(); + + return ( + + + + {t("govActions.onChainTransactionDetails")} + + + {data.map(({ label, content }) => ( + + + {label} + {":"} + + + {content} + + + ))} + + ); +}; diff --git a/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardVotes.tsx b/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardVotes.tsx new file mode 100644 index 000000000..2abf51ca9 --- /dev/null +++ b/govtool/frontend/src/components/molecules/GovernanceActionDetailsCardVotes.tsx @@ -0,0 +1,61 @@ +import { Dispatch, SetStateAction } from "react"; +import { Box } from "@mui/material"; + +import { useScreenDimension } from "@hooks"; +import { VoteActionForm, VotesSubmitted } from "@molecules"; + +type GovernanceActionCardVotesProps = { + setIsVoteSubmitted: Dispatch>; + abstainVotes: number; + noVotes: number; + yesVotes: number; + isOneColumn: boolean; + isVoter?: boolean; + voteFromEP?: string; + isDashboard?: boolean; + isInProgress?: boolean; +}; + +export const GovernanceActionDetailsCardVotes = ({ + setIsVoteSubmitted, + abstainVotes, + noVotes, + yesVotes, + isOneColumn, + isVoter, + voteFromEP, + isDashboard, + isInProgress, +}: GovernanceActionCardVotesProps) => { + const { screenWidth } = useScreenDimension(); + + const isModifiedPadding = + (isDashboard && screenWidth < 1368) ?? screenWidth < 1100; + + return ( + + {isVoter ? ( + + ) : ( + + )} + + ); +}; diff --git a/govtool/frontend/src/components/molecules/GovernanceActionsDatesBox.tsx b/govtool/frontend/src/components/molecules/GovernanceActionsDatesBox.tsx new file mode 100644 index 000000000..8db7ef999 --- /dev/null +++ b/govtool/frontend/src/components/molecules/GovernanceActionsDatesBox.tsx @@ -0,0 +1,124 @@ +import { Box } from "@mui/material"; +import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; +import { Trans } from "react-i18next"; + +import { Tooltip, Typography } from "@atoms"; +import { useScreenDimension, useTranslation } from "@hooks"; + +type GovernanceActionsDatesBoxProps = { + createdDate: string; + expiryDate: string; + isSliderCard?: boolean; +}; + +export const GovernanceActionsDatesBox = ({ + createdDate, + expiryDate, + isSliderCard, +}: GovernanceActionsDatesBoxProps) => { + const { t } = useTranslation(); + const { screenWidth } = useScreenDimension(); + + const isFontSizeSmaller = screenWidth < 420; + + return ( + + + + , + , + ]} + /> + + + + + + + + , + , + ]} + /> + + + + + + + ); +}; diff --git a/govtool/frontend/src/components/molecules/GovernanceVotedOnCard.tsx b/govtool/frontend/src/components/molecules/GovernanceVotedOnCard.tsx index 817c8495d..a6e56f200 100644 --- a/govtool/frontend/src/components/molecules/GovernanceVotedOnCard.tsx +++ b/govtool/frontend/src/components/molecules/GovernanceVotedOnCard.tsx @@ -1,9 +1,7 @@ import { useNavigate } from "react-router-dom"; import { Box } from "@mui/material"; -import CheckIcon from "@mui/icons-material/Check"; -import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; -import { Button, VotePill, Typography, Tooltip } from "@atoms"; +import { Button } from "@atoms"; import { PATHS } from "@consts"; import { useScreenDimension, useTranslation } from "@hooks"; import { VotedProposal } from "@models"; @@ -11,23 +9,34 @@ import { formatDisplayDate, getFullGovActionId, getProposalTypeLabel, - getShortenedGovActionId, - openInNewTab, } from "@utils"; -import { theme } from "@/theme"; +import { + GovernanceActionCardElement, + GovernanceActionCardHeader, + GovernanceActionCardMyVote, + GovernanceActionCardStatePill, + GovernanceActionsDatesBox, +} from "@molecules"; + +const mockedLongText = + "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Sit, distinctio culpa minus eaque illo quidem voluptates quisquam mollitia consequuntur ex, sequi saepe? Ad ex adipisci molestiae sed."; interface Props { votedProposal: VotedProposal; + isDataMissing: boolean; + searchPhrase?: string; inProgress?: boolean; } -export const GovernanceVotedOnCard = ({ votedProposal, inProgress }: Props) => { +export const GovernanceVotedOnCard = ({ + votedProposal, + isDataMissing, + inProgress, +}: Props) => { const navigate = useNavigate(); const { proposal, vote } = votedProposal; - const { - palette: { lightBlue }, - } = theme; - const { isMobile } = useScreenDimension(); + + const { isMobile, screenWidth } = useScreenDimension(); const { t } = useTranslation(); const proposalTypeNoEmptySpaces = getProposalTypeLabel(proposal.type).replace( @@ -37,213 +46,72 @@ export const GovernanceVotedOnCard = ({ votedProposal, inProgress }: Props) => { return ( + - - {inProgress ? ( - t("inProgress") - ) : ( - <> - - {t("govActions.voteSubmitted")} - - )} - - - - - - {t("govActions.governanceActionType")} - - - - - {getProposalTypeLabel(proposal.type)} - - - - - - - {t("govActions.governanceActionId")} - - - - - {getShortenedGovActionId(proposal.txHash, proposal.index)} - - - - - - - {t("govActions.myVote")} - - - - - - - - + + + + + + - {proposal.createdDate ? ( - - - {t("govActions.submissionDate")} - - - {formatDisplayDate(proposal.createdDate)} - - - - - - ) : null} - {proposal.expiryDate ? ( - - - {t("govActions.expiryDate")} - - - {formatDisplayDate(proposal.expiryDate)} - - - - - - ) : null} diff --git a/govtool/frontend/src/components/molecules/Share.tsx b/govtool/frontend/src/components/molecules/Share.tsx new file mode 100644 index 000000000..1165c9c24 --- /dev/null +++ b/govtool/frontend/src/components/molecules/Share.tsx @@ -0,0 +1,99 @@ +import { useState } from "react"; +import { Box, Popover } from "@mui/material"; + +import { Typography } from "@atoms"; +import { ICONS } from "@consts"; +import { useSnackbar } from "@context"; +import { useTranslation } from "@hooks"; + +export const Share = ({ link }: { link: string }) => { + const { addSuccessAlert } = useSnackbar(); + const { t } = useTranslation(); + const [anchorEl, setAnchorEl] = useState(null); + const [isActive, setIsActive] = useState(true); + + const handleClick = (event: any) => { + setAnchorEl(event.currentTarget); + }; + + const handleClose = () => { + setAnchorEl(null); + }; + + const onCopy = (e: any) => { + navigator.clipboard.writeText(link); + addSuccessAlert(t("alerts.copiedToClipboard")); + setIsActive(false); + e.stopPropagation(); + }; + + const open = Boolean(anchorEl); + const id = open ? "simple-popover" : undefined; + + return ( + <> + + + + + + Share + + link + + Click to copy + + + + ); +}; diff --git a/govtool/frontend/src/components/molecules/SliderArrows.tsx b/govtool/frontend/src/components/molecules/SliderArrows.tsx new file mode 100644 index 000000000..f38a45b0e --- /dev/null +++ b/govtool/frontend/src/components/molecules/SliderArrows.tsx @@ -0,0 +1,44 @@ +import { KeenSliderHooks, KeenSliderInstance } from "keen-slider/react"; +import { SliderArrow } from "@atoms"; +import { Box } from "@mui/material"; + +interface ArrowsProps { + currentSlide: number; + instanceRef: React.MutableRefObject | null>; +} + +export const SliderArrows = ({ currentSlide, instanceRef }: ArrowsProps) => { + return ( + <> + {instanceRef.current && ( + + + e.stopPropagation() || instanceRef.current?.prev() + } + disabled={currentSlide === 0} + /> + + e.stopPropagation() || instanceRef.current?.next() + } + disabled={ + currentSlide === + instanceRef.current.track.details.slides.length - 1 + } + /> + + )} + + ); +}; diff --git a/govtool/frontend/src/components/molecules/VoteActionForm.tsx b/govtool/frontend/src/components/molecules/VoteActionForm.tsx index 16a6e1766..55b9229b6 100644 --- a/govtool/frontend/src/components/molecules/VoteActionForm.tsx +++ b/govtool/frontend/src/components/molecules/VoteActionForm.tsx @@ -1,4 +1,11 @@ -import { useState, useEffect, useMemo, useCallback } from "react"; +import { + useState, + useEffect, + useMemo, + useCallback, + Dispatch, + SetStateAction, +} from "react"; import { useLocation } from "react-router-dom"; import { Box, Link } from "@mui/material"; @@ -9,21 +16,32 @@ import { useScreenDimension, useVoteActionForm, useTranslation } from "@hooks"; import { openInNewTab } from "@utils"; import { ControlledField } from "../organisms"; +import { Trans } from "react-i18next"; + +// TODO: Change into props when BE is ready +const castVoteDate = undefined; +const castVoteChangeDeadline = "20.06.2024 (Epoch 445)"; + +type VoteActionFormProps = { + setIsVoteSubmitted: Dispatch>; + voteFromEP?: string; + yesVotes: number; + noVotes: number; + abstainVotes: number; + isInProgress?: boolean; +}; export const VoteActionForm = ({ + setIsVoteSubmitted, voteFromEP, yesVotes, noVotes, abstainVotes, -}: { - voteFromEP?: string; - yesVotes: number; - noVotes: number; - abstainVotes: number; -}) => { - const { state } = useLocation(); + isInProgress, +}: VoteActionFormProps) => { const [isContext, setIsContext] = useState(false); - const { isMobile, screenWidth } = useScreenDimension(); + const { state } = useLocation(); + const { isMobile } = useScreenDimension(); const { openModal } = useModal(); const { voter } = useCardano(); const { t } = useTranslation(); @@ -44,8 +62,10 @@ export const VoteActionForm = ({ useEffect(() => { if (state && state.vote) { setValue("vote", state.vote); + setIsVoteSubmitted(true); } else if (voteFromEP) { setValue("vote", voteFromEP); + setIsVoteSubmitted(true); } }, [state, voteFromEP, setValue]); @@ -100,56 +120,97 @@ export const VoteActionForm = ({ ); return ( - - - - {t("govActions.chooseHowToVote")} - - - - - - - - - - + + + {castVoteDate ? ( + <> + + ]} + /> + + + {t("govActions.castVoteDeadline", { + date: castVoteChangeDeadline, + })} + + + ) : ( + + {t("govActions.chooseHowToVote")} + + )} + + + + {(voter?.isRegisteredAsDRep || voter?.isRegisteredAsSoleVoter) && ( - - - {isDRep ? ( - - ) : ( - - )} - + {(isVoteSubmitted || isInProgress) && ( + + )} + + ); }; diff --git a/govtool/frontend/src/components/organisms/GovernanceActionDetailsCardData.tsx b/govtool/frontend/src/components/organisms/GovernanceActionDetailsCardData.tsx new file mode 100644 index 000000000..7ac215c13 --- /dev/null +++ b/govtool/frontend/src/components/organisms/GovernanceActionDetailsCardData.tsx @@ -0,0 +1,121 @@ +import { Box } from "@mui/material"; + +import { ExternalModalButton } from "@atoms"; +import { + GovernanceActionCardElement, + GovernanceActionDetailsCardLinks, + DataMissingInfoBox, + GovernanceActionDetailsCardHeader, + GovernanceActionsDatesBox, + GovernanceActionDetailsCardOnChainData, +} from "@molecules"; +import { useScreenDimension, useTranslation } from "@hooks"; + +const mockedLongDescription = + "I am the Cardano crusader carving his path in the blockchain battleground. With a mind sharper than a Ledger Nano X, this fearless crypto connoisseur fearlessly navigates the volatile seas of Cardano, turning code into currency. Armed with a keyboard and a heart pumping with blockchain beats, Mister Big Bad fearlessly champions decentralization, smart contracts, and the Cardano community. His Twitter feed is a mix of market analysis that rivals CNBC and memes that could break the internet."; + +const mockedOnChainData = [ + { + label: "Reward Address", + content: "Lorem ipsum dolor sit amet consectetur.", + }, + { label: "Amount", content: "₳ 12,350" }, +]; + +type GovernanceActionDetailsCardDataProps = { + type: string; + govActionId: string; + createdDate: string; + expiryDate: string; + isDataMissing: boolean; + isOneColumn: boolean; + isDashboard?: boolean; +}; + +export const GovernanceActionDetailsCardData = ({ + type, + govActionId, + createdDate, + expiryDate, + isDataMissing, + isOneColumn, + isDashboard, +}: GovernanceActionDetailsCardDataProps) => { + const { t } = useTranslation(); + const { screenWidth } = useScreenDimension(); + + const isModifiedPadding = + (isDashboard && screenWidth < 1168) ?? screenWidth < 900; + + return ( + + + {isDataMissing && } + + + {isDataMissing && ( + + )} + + + + + + + + + + ); +}; diff --git a/govtool/frontend/src/components/organisms/GovernanceActionsToVote.tsx b/govtool/frontend/src/components/organisms/GovernanceActionsToVote.tsx index 9b5a6184f..9274aa462 100644 --- a/govtool/frontend/src/components/organisms/GovernanceActionsToVote.tsx +++ b/govtool/frontend/src/components/organisms/GovernanceActionsToVote.tsx @@ -1,4 +1,3 @@ -/* eslint-disable no-unsafe-optional-chaining */ import { useMemo } from "react"; import { useNavigate, generatePath } from "react-router-dom"; import { Box, CircularProgress } from "@mui/material"; @@ -13,7 +12,7 @@ import { GovernanceActionCard } from "@molecules"; import { GOVERNANCE_ACTIONS_FILTERS, PATHS } from "@consts"; import { useCardano } from "@context"; import { getProposalTypeLabel, getFullGovActionId, openInNewTab } from "@utils"; -import { Slider } from "./Slider"; +import { Slider } from "@organisms"; type GovernanceActionsToVoteProps = { filters: string[]; @@ -44,27 +43,22 @@ export const GovernanceActionsToVote = ({ sorting, }); - const groupedByType = (data?: ActionType[]) => - data?.reduce((groups, item) => { + const groupedByType = (data?: ActionType[]) => { + return data?.reduce((groups, item) => { const itemType = item.type; - // TODO: Provide better typing for groups - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-expect-error if (!groups[itemType]) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-expect-error groups[itemType] = { title: itemType, actions: [], }; } - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-expect-error + groups[itemType].actions.push(item); return groups; }, {}); + }; const mappedData = useMemo(() => { const groupedData = groupedByType( @@ -85,75 +79,80 @@ export const GovernanceActionsToVote = ({ ) : ( <> - {mappedData?.map((item, index) => ( - - ( -
- - onDashboard && - voteTransaction?.proposalId === - action?.txHash + action?.index - ? openInNewTab( - "https://adanordic.com/latest_transactions", - ) - : navigate( - onDashboard - ? generatePath( - PATHS.dashboardGovernanceActionsAction, - { - proposalId: getFullGovActionId( - action.txHash, - action.index, + {mappedData?.map((item, index) => { + return ( + + { + return ( +
+ + onDashboard && + voteTransaction?.proposalId === + item?.txHash + item?.index + ? openInNewTab( + "https://adanordic.com/latest_transactions", + ) + : navigate( + onDashboard + ? generatePath( + PATHS.dashboardGovernanceActionsAction, + { + proposalId: getFullGovActionId( + item.txHash, + item.index, + ), + }, + ) + : PATHS.governanceActionsAction.replace( + ":proposalId", + getFullGovActionId( + item.txHash, + item.index, + ), ), - }, - ) - : PATHS.governanceActionsAction.replace( - ":proposalId", - getFullGovActionId( - action.txHash, - action.index, - ), - ), - { - state: { ...action }, - }, - ) - } - /> -
- ))} - dataLength={item.actions.slice(0, 6).length} - filters={filters} - navigateKey={item.title} - notSlicedDataLength={item.actions.length} - onDashboard={onDashboard} - searchPhrase={searchPhrase} - sorting={sorting} - title={getProposalTypeLabel(item.title)} - /> - {index < mappedData.length - 1 && ( - - )} - - ))} + { + state: { ...item }, + }, + ) + } + /> +
+ ); + })} + dataLength={item.actions.slice(0, 6).length} + filters={filters} + navigateKey={item.title} + notSlicedDataLength={item.actions.length} + onDashboard={onDashboard} + searchPhrase={searchPhrase} + sorting={sorting} + title={getProposalTypeLabel(item.title)} + /> + {index < mappedData.length - 1 && ( + + )} + + ); + })} )} diff --git a/govtool/frontend/src/components/organisms/Slider.tsx b/govtool/frontend/src/components/organisms/Slider.tsx index 6bc159e14..71f18883c 100644 --- a/govtool/frontend/src/components/organisms/Slider.tsx +++ b/govtool/frontend/src/components/organisms/Slider.tsx @@ -1,13 +1,15 @@ -import { useCallback, useEffect, useMemo } from "react"; -import { Box, Link, Typography } from "@mui/material"; +import { useEffect } from "react"; +import { generatePath, useNavigate } from "react-router-dom"; +import { Box } from "@mui/material"; import { KeenSliderOptions } from "keen-slider"; import "keen-slider/keen-slider.min.css"; -import { ICONS, PATHS } from "@consts"; import { useCardano } from "@context"; -import { useScreenDimension, useSlider, useTranslation } from "@hooks"; -import { generatePath, useNavigate } from "react-router-dom"; -import styles from "./slider.module.css"; +import { useScreenDimension, useTranslation, useSlider } from "@hooks"; +import { Button, Typography } from "@atoms"; +import { SliderArrows } from "@molecules"; +import { theme } from "@/theme"; +import { PATHS } from "@consts"; const SLIDER_MAX_LENGTH = 1000; @@ -36,39 +38,34 @@ export const Slider = ({ searchPhrase, sorting, }: SliderProps) => { - const { isMobile, screenWidth, pagePadding } = useScreenDimension(); + const { isMobile, screenWidth } = useScreenDimension(); const navigate = useNavigate(); const { voteTransaction } = useCardano(); const { t } = useTranslation(); + const { + palette: { primaryBlue, arcticWhite, lightBlue }, + } = theme; + const DEFAULT_SLIDER_CONFIG = { mode: "free", initial: 0, slides: { perView: "auto", - spacing: 24, + spacing: 20, }, } as KeenSliderOptions; - const { - currentRange, - sliderRef, - setPercentageValue, - instanceRef, - setCurrentRange, - } = useSlider({ + const isShowArrows = + screenWidth < 268 + 28 + dataLength * 350 + 20 * dataLength - 5; + + const { sliderRef, instanceRef, currentSlide } = useSlider({ config: DEFAULT_SLIDER_CONFIG, sliderMaxLength: SLIDER_MAX_LENGTH, }); - const paddingOffset = useMemo(() => { - const padding = onDashboard ? (isMobile ? 2 : 3.5) : pagePadding; - return padding * 8 * 2; - }, [isMobile, pagePadding]); - const refresh = () => { instanceRef.current?.update(instanceRef.current?.options); - setCurrentRange(0); instanceRef.current?.track.to(0); instanceRef.current?.moveToIdx(0); }; @@ -77,58 +74,66 @@ export const Slider = ({ refresh(); }, [filters, sorting, searchPhrase, voteTransaction?.proposalId, data]); - const rangeSliderCalculationElement = - dataLength < notSlicedDataLength - ? (screenWidth + - (onDashboard ? -290 - paddingOffset : -paddingOffset + 250)) / - 437 - : (screenWidth + (onDashboard ? -280 - paddingOffset : -paddingOffset)) / - 402; - - const handleLinkPress = useCallback(() => { - if (onDashboard) { - navigate( - generatePath(PATHS.dashboardGovernanceActionsCategory, { - category: navigateKey, - }), - ); - } else { - navigate( - generatePath(PATHS.governanceActionsCategory, { - category: navigateKey, - }), - ); - } - }, [onDashboard]); - return ( - - - {title} - - {isMobile && isShowAll && ( - + + - + {(notSlicedDataLength > 6 || (isMobile && isShowAll)) && ( + + )} + + {isShowArrows && dataLength > 1 && !isMobile && ( + )}
{data} - {!isMobile && isShowAll && dataLength < notSlicedDataLength && ( -
- - - {t("slider.viewAll")} - - arrow - -
- )}
- {!isMobile && Math.floor(rangeSliderCalculationElement) < dataLength && ( - - - - )}
); }; diff --git a/govtool/frontend/src/components/organisms/index.ts b/govtool/frontend/src/components/organisms/index.ts index bbded8e90..cccbc8400 100644 --- a/govtool/frontend/src/components/organisms/index.ts +++ b/govtool/frontend/src/components/organisms/index.ts @@ -17,6 +17,7 @@ export * from "./DrawerMobile"; export * from "./ExternalLinkModal"; export * from "./Footer"; export * from "./GovernanceActionDetailsCard"; +export * from "./GovernanceActionDetailsCardData"; export * from "./GovernanceActionsToVote"; export * from "./Hero"; export * from "./HomeCards"; diff --git a/govtool/frontend/src/consts/icons.ts b/govtool/frontend/src/consts/icons.ts index 2a5fc394d..dfabf260d 100644 --- a/govtool/frontend/src/consts/icons.ts +++ b/govtool/frontend/src/consts/icons.ts @@ -8,6 +8,7 @@ export const ICONS = { closeIcon: "/icons/Close.svg", closeWhiteIcon: "/icons/CloseWhite.svg", copyBlueIcon: "/icons/CopyBlue.svg", + copyBlueThinIcon: "/icons/CopyBlueThin.svg", copyIcon: "/icons/Copy.svg", copyWhiteIcon: "/icons/CopyWhite.svg", dashboardActiveIcon: "/icons/DashboardActive.svg", @@ -25,6 +26,7 @@ export const ICONS = { guidesIcon: "/icons/Guides.svg", helpIcon: "/icons/Help.svg", link: "/icons/Link.svg", + share: "/icons/Share.svg", sortActiveIcon: "/icons/SortActive.svg", sortIcon: "/icons/Sort.svg", sortWhiteIcon: "/icons/SortWhite.svg", diff --git a/govtool/frontend/src/hooks/useSlider.ts b/govtool/frontend/src/hooks/useSlider.ts index 78788791e..e73341422 100644 --- a/govtool/frontend/src/hooks/useSlider.ts +++ b/govtool/frontend/src/hooks/useSlider.ts @@ -1,4 +1,4 @@ -import { ChangeEvent, useState } from "react"; +import { useState } from "react"; import { KeenSliderOptions, useKeenSlider } from "keen-slider/react"; import type { KeenSliderInstance } from "keen-slider"; @@ -49,51 +49,26 @@ const WheelControls = (slider: KeenSliderInstance) => { export const useSlider = ({ config, - sliderMaxLength, }: { config: KeenSliderOptions; sliderMaxLength: number; }) => { const [currentSlide, setCurrentSlide] = useState(0); - const [currentRange, setCurrentRange] = useState(0); const [sliderRef, instanceRef] = useKeenSlider( { ...config, rubberband: false, detailsChanged: (slider) => { - setCurrentRange(slider.track.details.progress * sliderMaxLength); setCurrentSlide(slider.track.details.rel); }, }, [WheelControls], ); - const DATA_LENGTH = instanceRef?.current?.slides?.length ?? 10; - const ITEMS_PER_VIEW = - DATA_LENGTH - (instanceRef?.current?.track?.details?.maxIdx ?? 2); - - const setPercentageValue = (e: ChangeEvent) => { - const target = e?.target; - const currentIndexOfSlide = Math.floor( - +(target?.value ?? 0) / - (sliderMaxLength / (DATA_LENGTH - Math.floor(ITEMS_PER_VIEW))), - ); - - instanceRef.current?.track.add( - (+(target?.value ?? 0) - currentRange) * - (instanceRef.current.track.details.length / sliderMaxLength), - ); - setCurrentRange(+(target?.value ?? 0)); - setCurrentSlide(currentIndexOfSlide); - }; - return { sliderRef, instanceRef, currentSlide, - currentRange, - setCurrentRange, - setPercentageValue, }; }; diff --git a/govtool/frontend/src/i18n/locales/en.ts b/govtool/frontend/src/i18n/locales/en.ts index 39e37f929..49767b600 100644 --- a/govtool/frontend/src/i18n/locales/en.ts +++ b/govtool/frontend/src/i18n/locales/en.ts @@ -311,24 +311,39 @@ export const en = { }, }, govActions: { + about: "About", + abstract: "Abstract:", + castVote: "<0>You voted {{vote}} for this proposal\nat {{date}}", + castVoteDeadline: + "You can change your vote up to the deadline of {{date}}", changeVote: "Change vote", changeYourVote: "Change your vote", chooseHowToVote: "Choose how you want to vote:", + dataMissing: "Data Missing", details: "Governance Details:", + expiresDateWithEpoch: "Expires: <0>{{date}} <1>(Epoch {{epoch}})", expiryDate: "Expiry date:", filterTitle: "Governance Action Type", forGovAction: "for this Governance Action", governanceActionId: "Governance Action ID:", governanceActionType: "Governance Action Type:", + motivation: "Motivation", myVote: "My Vote:", noResultsForTheSearch: "No results for the search.", + onChainTransactionDetails: "On-chain Transaction Details", optional: "(optional)", provideContext: "Provide context about your vote", + rationale: "Rationale", + seeExternalData: "See external data", selectDifferentOption: "Select a different option to change your vote", showVotes: "Show votes", submissionDate: "Submission date:", + submittedDateWithEpoch: + "Submitted: <0>{{date}} <1>(Epoch {{epoch}})", + supportingLinks: "Supporting links", title: "Governance Actions", toVote: "To vote", + viewDetails: "View Details", viewOtherDetails: "View other details", viewProposalDetails: "View proposal details", vote: "Vote", @@ -493,7 +508,7 @@ export const en = { }, }, slider: { - showAll: "Show all", + showAll: "Show All", viewAll: "View all", }, soleVoter: { @@ -587,7 +602,7 @@ export const en = { continue: "Continue", delegate: "Delegate", here: "here", - inProgress: "In Progress", + inProgress: "In progress", learnMore: "Learn more", loading: "Loading...", myDRepId: "My DRep ID:", @@ -599,6 +614,7 @@ export const en = { required: "required", seeTransaction: "See transaction", select: "Select", + showMore: "Show more", skip: "Skip", sortBy: "Sort by", submit: "Submit", diff --git a/govtool/frontend/src/pages/DashboardGovernanceActionsCategory.tsx b/govtool/frontend/src/pages/DashboardGovernanceActionsCategory.tsx index d54896e55..2096bfafe 100644 --- a/govtool/frontend/src/pages/DashboardGovernanceActionsCategory.tsx +++ b/govtool/frontend/src/pages/DashboardGovernanceActionsCategory.tsx @@ -188,6 +188,8 @@ export const DashboardGovernanceActionsCategory = () => { inProgress={ voteTransaction.proposalId === item.txHash + item.index } + // TODO: Add data validation + isDataMissing={false} onClick={() => { saveScrollPosition(); diff --git a/govtool/frontend/src/pages/GovernanceActionDetails.tsx b/govtool/frontend/src/pages/GovernanceActionDetails.tsx index 34378488d..376e4156e 100644 --- a/govtool/frontend/src/pages/GovernanceActionDetails.tsx +++ b/govtool/frontend/src/pages/GovernanceActionDetails.tsx @@ -130,11 +130,7 @@ export const GovernanceActionDetails = () => {
) : data || state ? ( - + { } url={state ? state.url : data.proposal.url} yesVotes={state ? state.yesVotes : data.proposal.yesVotes} - shortenedGovActionId={shortenedGovActionId} + govActionId={fullProposalId} /> ) : ( diff --git a/govtool/frontend/src/pages/GovernanceActionsCategory.tsx b/govtool/frontend/src/pages/GovernanceActionsCategory.tsx index 9b707f8c6..6f2489d89 100644 --- a/govtool/frontend/src/pages/GovernanceActionsCategory.tsx +++ b/govtool/frontend/src/pages/GovernanceActionsCategory.tsx @@ -216,6 +216,8 @@ export const GovernanceActionsCategory = () => { {...item} txHash={item.txHash} index={item.index} + // TODO: Add data validation + isDataMissing={false} onClick={() => { saveScrollPosition(); diff --git a/govtool/frontend/src/theme.ts b/govtool/frontend/src/theme.ts index 8a8736f17..83cd35489 100644 --- a/govtool/frontend/src/theme.ts +++ b/govtool/frontend/src/theme.ts @@ -9,6 +9,59 @@ import { successGreen, } from "./consts"; +declare module "@mui/material/styles" { + interface Palette { + accentOrange: string; + accentYellow: string; + arcticWhite: string; + boxShadow1: string; + boxShadow2: string; + errorRed: string; + highlightBlue: string; + inputRed: string; + negativeRed: string; + neutralGray: string; + orangeDark: string; + neutralWhite: string; + positiveGreen: string; + primaryBlue: string; + secondaryBlue: string; + specialCyan: string; + specialCyanBorder: string; + lightBlue: string; + textBlack: string; + textGray: string; + lightOrange: string; + fadedPurple: string; + } + interface PaletteOptions { + accentOrange: string; + accentYellow: string; + arcticWhite: string; + boxShadow1: string; + boxShadow2: string; + errorRed: string; + highlightBlue: string; + orangeDark: string; + inputRed: string; + negativeRed: string; + neutralGray: string; + neutralWhite: string; + positiveGreen: string; + primaryBlue: string; + secondaryBlue: string; + specialCyan: string; + specialCyanBorder: string; + lightBlue: string; + textBlack: string; + textGray: string; + lightOrange: string; + fadedPurple: string; + } +} + +export type Theme = typeof theme; + export const theme = createTheme({ breakpoints: { values: { @@ -114,8 +167,10 @@ export const theme = createTheme({ palette: { accentOrange: "#F29339", accentYellow: "#F2D9A9", + arcticWhite: "#FBFBFF", boxShadow1: "rgba(0, 18, 61, 0.37)", boxShadow2: "rgba(47, 98, 220, 0.2)", + errorRed: "#9E2323", fadedPurple: "#716E88", highlightBlue: "#C2EFF299", inputRed: "#FAEAEB",