Skip to content

Commit

Permalink
fix: resolve conflict
Browse files Browse the repository at this point in the history
  • Loading branch information
Sotatek-TaiTruong committed Mar 29, 2024
2 parents b566856 + a92c3f6 commit 5838e0b
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 16 deletions.
1 change: 1 addition & 0 deletions src/commons/utils/api.ts
Expand Up @@ -32,6 +32,7 @@ export const API = {
POOL: "pools",
POOL_CERTIFICATE: {
POOL: "gov-actions",
POOL_CHART: "gov-actions/voting-chart",
POOL_DETAIL: (poolId: string) => `gov-actions/${poolId}/voting-procedure-detail`
},
POOL_CERTIFICATES_HISTORY: "pools/certificates-history",
Expand Down
8 changes: 8 additions & 0 deletions src/commons/utils/helper.ts
Expand Up @@ -34,6 +34,10 @@ export const getShortValue = (address = "", length = 50) => {
return address.slice(0, length);
};

export const getShortNumber = (number = 0, length = 3) => {
return Number(number.toFixed(length));
};

export const LARGE_NUMBER_ABBREVIATIONS = ["", "K", "M", "B", "T", "q", "Q", "s", "S"];

export const formatPrice = (value?: string | number, abbreviations: string[] = LARGE_NUMBER_ABBREVIATIONS): string => {
Expand Down Expand Up @@ -200,6 +204,10 @@ export const formatDateTimeLocal = (date: string) => {
return moment(moment(`${date} GMT+0000`).local(true)).format("MM/DD/YYYY HH:mm:ss");
};

export const formatDate = (date: string) => {
return moment(date).format("DD/MM/YYYY");
};

export const getEpochSlotNo = (data: IDataEpoch) => {
if (data.status === "FINISHED") {
return MAX_SLOT_EPOCH;
Expand Down
193 changes: 178 additions & 15 deletions src/components/GovernanceVotes/index.tsx
Expand Up @@ -27,11 +27,13 @@ import {
styled,
tooltipClasses,
useTheme,
ClickAwayListener
ClickAwayListener,
Link
} from "@mui/material";
import { IoIosArrowDown, IoIosArrowUp } from "react-icons/io";
import moment from "moment";
import { isUndefined, omitBy } from "lodash";
import { JsonViewer } from "@textea/json-viewer";

import {
ActionTypeIcon,
Expand All @@ -55,12 +57,12 @@ import {
} from "src/commons/resources";
import { API } from "src/commons/utils/api";
import { POOLS_ACTION_TYPE, VOTE_TYPE, STATUS_VOTE } from "src/commons/utils/constants";
import { getShortHash } from "src/commons/utils/helper";
import CardGovernanceVotes, {
GovernanceStatus,
VoteStatus,
actionTypeListDrep
} from "src/components/commons/CardGovernanceVotes";
import { formatDate, formatDateTime, getShortHash, getShortNumber } from "src/commons/utils/helper";
import CopyButton from "src/components/commons/CopyButton";
import CustomIcon from "src/components/commons/CustomIcon";
import CustomModal from "src/components/commons/CustomModal";
Expand Down Expand Up @@ -92,12 +94,29 @@ import {
import { TimeDuration } from "../TransactionLists/styles";
import NoRecord from "../commons/NoRecord";
import DynamicEllipsisText from "../DynamicEllipsisText";
import { ViewJson } from "../ScriptModal/styles";

interface DelegationGovernanceVotesProps {
hash: string;
type: VOTE_TYPE.DREP_KEY_HASH | VOTE_TYPE.STAKING_POOL_KEY_HASH;
}

interface GovernanceVoteChart {
txHash: string | null;
index: number | null;
numberOfYesVote: number;
numberOfNoVotes: number;
numberOfAbstainVotes: number;
votingChartsList: VotingChart[];
}

interface VotingChart {
voterType: string;
numberOfYesVote: number;
numberOfNoVotes: number;
numberOfAbstainVotes: number;
}

const DelegationGovernanceVotes: React.FC<DelegationGovernanceVotesProps> = ({ hash, type }) => {
const { search } = useLocation();
const history = useHistory();
Expand All @@ -118,11 +137,13 @@ const DelegationGovernanceVotes: React.FC<DelegationGovernanceVotesProps> = ({ h
voterType: type
});
}, [JSON.stringify(query)]);

const { data, total, lastUpdated, loading, initialized } = useFetchList<GovernanceVote>(
`${API.POOL_CERTIFICATE.POOL}/${hash}`,
omitBy(params, isUndefined),
false
);

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const setQuery = (query: any) => {
history.replace({ search: stringify(query) }, history.location.state);
Expand Down Expand Up @@ -207,6 +228,7 @@ const GovernanceVotesDetail: React.FC<{
}> = ({ hash, voteId, type }) => {
const theme = useTheme();
const [openHistoryVoteModal, setOpenHistoryVoteModal] = useState<boolean>(false);
const [openActionMetadataModal, setOpenActionMetadataModal] = useState<boolean>(false);
const { t } = useTranslation();
const { drepId, poolId } = useParams<{ drepId: string; poolId: string }>();

Expand All @@ -224,11 +246,32 @@ const GovernanceVotesDetail: React.FC<{
voterType: type
})}`
);

const { data: dataChart } = useFetch<GovernanceVoteChart>(
`${API.POOL_CERTIFICATE.POOL_CHART}?${stringify({
txHash: voteId,
index: 0
})}`
);

const filterDataChart = (selectVote: string) => {
switch (selectVote) {
case "SPOs":
return dataChart?.votingChartsList.filter((i) => i.voterType === "STAKING_POOL_KEY_HASH")[0];
case "DRops":
return dataChart?.votingChartsList.filter((i) => i.voterType === "DREP_KEY_HASH")[0];
case "CC":
return dataChart?.votingChartsList.filter((i) => i.voterType === "CONSTITUTIONAL_COMMITTEE_HOT_KEY_HASH")[0];

default:
return dataChart;
}
};

const [tab, setTab] = useState<string>("pool");
const handleTabChange = (newTab: string) => {
setTab(newTab);
};

const TabButton: React.FC<TabButtonProps> = ({ tabName, title, children }) => {
return (
<Box
Expand Down Expand Up @@ -262,6 +305,7 @@ const GovernanceVotesDetail: React.FC<{
tab: "governanceVotes",
page: 1,
size: 6,
governanceActionTxHash: "",
actionType: STATUS_VOTE.ALL,
actionStatus: STATUS_VOTE.ANY,
voteType: STATUS_VOTE.ANY,
Expand Down Expand Up @@ -385,7 +429,7 @@ const GovernanceVotesDetail: React.FC<{
color: theme.isDark ? theme.palette.secondary.main : theme.palette.secondary.light
}}
label={selectVote || i}
onClick={() => setSelectVote(i)}
onClick={() => setSelectVote(selectVote ? "" : i)}
/>
))}
{selectVote && (
Expand Down Expand Up @@ -426,7 +470,7 @@ const GovernanceVotesDetail: React.FC<{
)}
</Box>
) : (
<VoteRate />
<VoteRate data={filterDataChart(selectVote)} />
)}
</InfoValue>
</Item>
Expand Down Expand Up @@ -464,28 +508,46 @@ const GovernanceVotesDetail: React.FC<{
<InfoTitle paddingBottom="3px">
<StyledTitle>{t("pool.submission")}</StyledTitle>
</InfoTitle>
<InfoValue>{data?.submissionDate}</InfoValue>
<InfoValue>{formatDateTime(data?.submissionDate || "")}</InfoValue>
</Item>
<Item item xs={6} md={3}>
<CustomIcon fill={theme.palette.secondary.light} height={27} icon={SubmissionDateIcon} />
<InfoTitle paddingBottom="3px">
<StyledTitle>{t("pool.expiryDate")}</StyledTitle>
</InfoTitle>
<InfoValue>{data?.expiryDate}</InfoValue>
<InfoValue>{formatDate(data?.expiryDate || "")}</InfoValue>
</Item>
<Item item xs={6} md={3}>
<CustomIcon fill={theme.palette.secondary.light} height={25} icon={AnchorTextIcon} />
<InfoTitle paddingBottom="3px">
<StyledTitle>{t("pool.anchorText")}</StyledTitle>
</InfoTitle>
<InfoValue>Whatever the anchor text string is for this action</InfoValue>
<InfoValue>
<Button
onClick={() => {
setOpenActionMetadataModal(true);
}}
fullWidth
sx={{ height: "51px" }}
variant="outlined"
>
{t("common.viewDetails")}
</Button>
</InfoValue>
</Item>
</StyledGrid>
<VoteHistoryModal
data={data?.historyVotes}
open={openHistoryVoteModal}
onClose={() => setOpenHistoryVoteModal(false)}
/>
<ActionMetadataModal
data={data?.details}
anchorHash={data?.anchorHash}
anchorUrl={data?.anchorUrl}
open={openActionMetadataModal}
onClose={() => setOpenActionMetadataModal(false)}
/>
</DataContainer>
</Box>
);
Expand Down Expand Up @@ -516,7 +578,7 @@ const VoteBar = ({
return (
<Box display="flex" flexDirection="column" alignItems="center">
<Typography fontSize="10px" fontWeight={400}>
{percentage}%
{!percentage ? "0" : percentage}%
</Typography>
<LightTooltip
title={
Expand All @@ -533,7 +595,7 @@ const VoteBar = ({
}
placement="top"
>
<Box sx={{ background: color }} height={`${percentage === 0 ? 0.5 : percentage}px`} width="36px" />
<Box sx={{ background: color }} height={`${!percentage ? 0.5 : percentage}px`} width="36px" />
</LightTooltip>
<Typography fontSize="14px" fontWeight={400} pt="4px" textTransform="uppercase">
{label}
Expand All @@ -542,20 +604,37 @@ const VoteBar = ({
);
};

const VoteRate = () => {
const VoteRate = ({ data }: { data?: GovernanceVoteChart | VotingChart | null }) => {
const { t } = useTranslation();
const theme = useTheme();

const totalVotes = Number(
(data?.numberOfYesVote || 0) + (data?.numberOfNoVotes || 0) + (data?.numberOfAbstainVotes || 0)
);
const yesPercentage = ((data?.numberOfYesVote || 0) / totalVotes) * 100;
const noPercentage = ((data?.numberOfNoVotes || 0) / totalVotes) * 100;
const abstainPercentage = ((data?.numberOfAbstainVotes || 0) / totalVotes) * 100;

return (
<Box display="flex" alignItems="end" justifyContent="space-between" width="100%">
<VoteBar percentage={93} color={theme.palette.success[700]} icon={<VotesYesIcon />} label={t("common.yes")} />
<VoteBar
percentage={7}
percentage={getShortNumber(yesPercentage)}
color={theme.palette.success[700]}
icon={<VotesYesIcon />}
label={t("common.yes")}
/>
<VoteBar
percentage={getShortNumber(abstainPercentage)}
color={theme.palette.warning[700]}
icon={<VotesAbstainIcon />}
label={t("common.abstain")}
/>
<VoteBar percentage={0} color={theme.palette.error[700]} icon={<VotesNoIcon />} label={t("common.no")} />
<VoteBar
percentage={getShortNumber(noPercentage)}
color={theme.palette.error[700]}
icon={<VotesNoIcon />}
label={t("common.no")}
/>
</Box>
);
};
Expand Down Expand Up @@ -684,6 +763,89 @@ const VoteHistoryModal: React.FC<VoteHistoryProps> = ({ onClose, open, data }) =
);
};

interface ActionMetadataProps {
onClose?: () => void;
open: boolean;
anchorHash?: string;
anchorUrl?: string;
data?: {
type: string;
govActionId: string | null;
quorumThreshold: number;
membersForRemoval: string[];
newMembersAndTerms: Record<string, number>;
};
}

const ActionMetadataModal: React.FC<ActionMetadataProps> = ({ onClose, open, data, anchorHash, anchorUrl }) => {
const { t } = useTranslation();
const theme = useTheme();

return (
<CustomModal
open={open}
onClose={() => onClose?.()}
title={t("pool.actionMetadata")}
width={500}
sx={{ maxHeight: "70vh" }}
>
<Box display="block" pb="15px">
<Typography fontSize="16px" color={theme.palette.secondary.main}>
{t("pool.anchor")}:
</Typography>{" "}
<Box
display="flex"
flexDirection="column"
gap="24px"
mt="20px"
p="24px"
sx={{ background: theme.isDark ? "" : theme.palette.secondary[0], wordWrap: "break-word" }}
>
<Typography fontSize="16px" color={theme.palette.secondary.light}>
{anchorHash}
</Typography>
<Typography
component={Link}
fontSize="16px"
color="#0033AD !important"
fontWeight="700"
target="_blank"
rel="noopener noreferrer"
href={anchorUrl || "/"}
>
{anchorUrl}
</Typography>
</Box>
</Box>
<Box display="block" pb="25.5px">
<Typography fontSize="16px">{t("pool.metadata")}:</Typography>{" "}
<Box
display="flex"
flexDirection="column"
gap="24px"
mt="20px"
p="24px"
sx={{ background: theme.isDark ? "" : theme.palette.secondary[0] }}
>
<ViewJson maxHeight={"70vh"}>
<JsonViewer
value={data}
displayObjectSize={false}
displayDataTypes={false}
enableClipboard={false}
collapseStringsAfterLength={false}
rootName={false}
theme={theme.isDark ? "dark" : "light"}
// keyRenderer={keyRenderer}
style={{ wordBreak: "break-word", width: "98%", pointerEvents: "none" }}
/>
</ViewJson>
</Box>
</Box>
</CustomModal>
);
};

interface TabButtonProps {
tabName: string;
title?: string;
Expand Down Expand Up @@ -739,6 +901,7 @@ const FilterGovernanceVotes: React.FC<FilterGovernanceVotes> = ({ query, setQuer
page: 1,
size: 6,
tab: "governanceVotes",
governanceActionTxHash: "",
actionType: STATUS_VOTE.ALL,
actionStatus: STATUS_VOTE.ANY,
voteType: STATUS_VOTE.ANY,
Expand All @@ -754,7 +917,7 @@ const FilterGovernanceVotes: React.FC<FilterGovernanceVotes> = ({ query, setQuer
isRepeatVote: params?.isRepeatVote,
page: 1,
size: 6,
id: params?.id,
governanceActionTxHash: params?.id,
anchorText: params?.anchorText,
actionType: params?.actionType,
actionStatus: params?.currentStatus,
Expand Down

0 comments on commit 5838e0b

Please sign in to comment.