diff --git a/backend/src/drep/drep.service.ts b/backend/src/drep/drep.service.ts index b85c5ddcf7a47a72ae81b1acb8c1fa201eb5f624..1f5dc7709af004ee81ff22ed5b3716df08666fa9 100644 --- a/backend/src/drep/drep.service.ts +++ b/backend/src/drep/drep.service.ts @@ -527,9 +527,11 @@ export class DrepService { dh.view, SUBSTRING(CAST(prop_creation_tx.hash AS TEXT) FROM 3) AS gov_action_proposal_id, prop_creation_bk.time AS prop_inception, + gp.type, gp.description, gp.voting_anchor_id, - vp.vote, + vp.vote::text, + ocvd.json AS metadata, bk.time AS time_voted, prop_creation_bk.epoch_no AS proposal_epoch, bk.epoch_no AS voting_epoch, @@ -550,6 +552,8 @@ export class DrepService { block AS prop_creation_bk ON prop_creation_tx.block_id = prop_creation_bk.id LEFT JOIN voting_anchor as va ON gp.voting_anchor_id = va.id + LEFT JOIN + off_chain_vote_data AS ocvd ON ocvd.voting_anchor_id = va.id WHERE dh.view = $1 AND bk.time::DATE BETWEEN $3::DATE AND $2::DATE diff --git a/backend/src/queries/voterGovActions.ts b/backend/src/queries/voterGovActions.ts index d8b482e860d676eb6054f6471bd27af05c229a64..811c661e1aebf322e821dc1c326cf7ad760a05b5 100644 --- a/backend/src/queries/voterGovActions.ts +++ b/backend/src/queries/voterGovActions.ts @@ -77,10 +77,10 @@ GovActions AS ( vp.vote::text, va.url, ocvd.json AS metadata, - b.epoch_no, + b.epoch_no AS voting_epoch, b.time AS time_voted, encode(vt.hash, 'hex') AS vote_tx_hash, - dh.view AS drep_id + dh.view FROM voting_procedure vp JOIN diff --git a/frontend/src/components/Loaders/GovActionLoader.tsx b/frontend/src/components/Loaders/GovActionLoader.tsx index d03ec8e19f921597d2d7368c3464bdd00503ef65..04b0b4329a5d9ef63f82b17a3b088fe7266cb237 100644 --- a/frontend/src/components/Loaders/GovActionLoader.tsx +++ b/frontend/src/components/Loaders/GovActionLoader.tsx @@ -6,7 +6,6 @@ function GovActionLoader() { <Box sx={{ width: '100%', - maxWidth: 300, bgcolor: 'rgba(0, 0, 0, 0.11)', borderRadius: '8px', padding: '12px', @@ -41,6 +40,8 @@ function GovActionLoader() { className="rounded-xl" /> + <Skeleton variant="text" width="80%" height={20} /> + <Skeleton variant="text" width="50%" height={20} /> <Skeleton variant="text" width="50%" height={20} /> </Box> ); diff --git a/frontend/src/components/atoms/DrepVoteTimelineCard.tsx b/frontend/src/components/atoms/DrepVoteTimelineCard.tsx index dc2201d07dfb4c5240f5e8446a0ba69fbdd2f5ac..8ff3deb6290e9b11165e5c5a65ac2b8203dffbe5 100644 --- a/frontend/src/components/atoms/DrepVoteTimelineCard.tsx +++ b/frontend/src/components/atoms/DrepVoteTimelineCard.tsx @@ -3,31 +3,85 @@ import { convertString } from '@/lib'; import Link from 'next/link'; import React, { useEffect, useState } from 'react'; import { CopyToClipboard } from 'react-copy-to-clipboard'; -import { Box } from "@mui/material"; +import { Box } from '@mui/material'; import axios from 'axios'; -const VoteStatusChip = ({ date, vote }: { date: string, vote: string }) => { +const VoteStatusChip = ({ date, vote }: { date: string; vote: string }) => { + const [bgcolor, setBgColor] = useState('complementary-100'); + + useEffect(() => { + if (vote === 'No') setBgColor('bg-red-100'); + else if (vote === 'Yes') setBgColor('bg-green-100'); + else if (vote === 'Abstain') setBgColor('bg-complementary-100'); + }, []); return ( <div className="flex flex-row items-center justify-between"> - <div className="flex w-fit flex-row items-center gap-1 rounded-full bg-purple-500 px-2 py-1 text-sm"> - <img src="/svgs/file-check.svg" alt="" /> - <p className='text-sm'>{vote}</p> + <div + className={`flex w-fit flex-row items-center gap-1 rounded-full ${bgcolor} px-2 py-1 text-sm`} + > + <img src="/svgs/file-check.svg" className="h-5 w-5" alt="Vote icon" /> + <p>{vote}</p> </div> - <p className='text-sm'>{new Date(date).toLocaleDateString('en-GB')}</p> + <p className="text-sm">{new Date(date).toLocaleDateString('en-GB')}</p> </div> ); }; const DrepVoteTimelineCard = ({ item }: { item: any }) => { - const [govActionName, setGovActionName] = useState('') + const [govActionName, setGovActionName] = useState(null); useEffect(() => { - axios.get(item.url). - then((response) => { - setGovActionName(response?.data?.body?.title) - }).catch((error) => { - console.log(error) + const title = item?.metadata?.body?.title; + if (title) { + setGovActionName(title); + return; + } + axios + .get(item.url) + .then((response) => { + setGovActionName(response?.data?.body?.title); }) - }, [govActionName]) + .catch((error) => { + console.log(error); + }); + }, [govActionName]); + + let actionDetais: { imgSrc: string; actionName: string } = { + imgSrc: '/svgs/exchange.svg', + actionName: '', + }; + + switch (true) { + case item?.description?.tag.includes('ParameterChange'): + actionDetais = { + imgSrc: '/svgs/exchange.svg', + actionName: 'Protocol Parameter Changes', + }; + break; + case item?.description?.tag.includes('InfoAction'): + actionDetais = { + imgSrc: '/svgs/info-circle.svg', + actionName: 'Info', + }; + break; + case item?.description?.tag.includes('HardForkInitiation'): + actionDetais = { + imgSrc: '/svgs/status-change.svg', + actionName: 'Hard-Fork Initiation', + }; + break; + case item?.description?.tag.includes('newconstitution'): + actionDetais = { + imgSrc: '/svgs/notebook.svg', + actionName: 'New Constitution or Guardrails Script', + }; + break; + case item?.description?.tag.includes('updatecommittee'): + actionDetais = { + imgSrc: '/svgs/users-group.svg', + actionName: 'Update committee and/or threshold and/or terms', + }; + break; + } return ( <Box @@ -36,17 +90,31 @@ const DrepVoteTimelineCard = ({ item }: { item: any }) => { > <VoteStatusChip date={item?.time_voted} vote={item?.vote} /> <hr /> - <Box className="flex max-w-52 flex-col gap-1"> - <p className="text-lg font-bold"> - For {item?.description?.tag || null} - </p> - <p className="text-sm mt-2">Governance Action Name:</p> - <p className="text-sm font-bold">{govActionName}</p> - <p className="text-sm mt-2">Governance Action ID:</p> - <div className="flex w-fit items-center gap-1 rounded-full border px-3 py-1 text-sm"> - <p> - {convertString(item?.gov_action_proposal_id + '#0', true) || null} + <Box className="flex flex-col gap-3"> + <Box> + <p className="overflow-hidden text-ellipsis text-sm font-bold"> + {govActionName ? govActionName : '-'} </p> + </Box> + + {actionDetais.actionName !== '' && ( + <Box> + <Box + className={`flex w-fit items-center gap-2 rounded-full bg-slate-200 p-1 px-3 py-1 text-sm`} + > + <img + src={actionDetais.imgSrc} + alt={`${actionDetais.actionName} icon`} + className="h-5 w-5" + /> + <p>{actionDetais.actionName}</p> + </Box> + </Box> + )} + + <Box className="flex w-fit items-center gap-2 rounded-full border px-3 py-1 text-sm"> + <p className="">Action ID:</p> + <p>{convertString(item?.gov_action_proposal_id, true) || null}</p> <CopyToClipboard text={item?.gov_action_proposal_id} onCopy={() => { @@ -56,24 +124,26 @@ const DrepVoteTimelineCard = ({ item }: { item: any }) => { > <img src="/svgs/copy.svg" alt="copy" /> </CopyToClipboard> - </div> + </Box> </Box> - <Box className="flex max-w-52 flex-col gap-1"> + <Box className="flex flex-col gap-1"> <p className="text-sm">View Governance Action:</p> - <Link - href={`${urls.govToolUrl}/governance_actions/${item?.gov_action_proposal_id}#0`} - target="_blank" - className="text-blue-800 text-sm" - > - Cardano Govtool - </Link> - <Link - href={`${urls.adaStatusUrl}/governances/${item?.gov_action_proposal_id}`} - target="_blank" - className="text-blue-800 text-sm mb-2" - > - Ada Status - </Link> + <Box className="ml-2 flex flex-col gap-1"> + <Link + href={`${urls.govToolUrl}/governance_actions/${item?.gov_action_proposal_id}#0`} + target="_blank" + className="text-sm text-blue-800" + > + Cardano Govtool + </Link> + <Link + href={`${urls.adaStatusUrl}/governances/${item?.gov_action_proposal_id}`} + target="_blank" + className="text-sm text-blue-800" + > + Ada Status + </Link> + </Box> </Box> </Box> ); diff --git a/frontend/src/components/voters/VoterImpact.tsx b/frontend/src/components/voters/VoterImpact.tsx index abc88e786a325082ca2f8f33e8c2453095d2c984..2a086355a2edcd81cecfb3ce9f4a5183537f835f 100644 --- a/frontend/src/components/voters/VoterImpact.tsx +++ b/frontend/src/components/voters/VoterImpact.tsx @@ -27,8 +27,11 @@ const VoterImpact = () => { }; const { voterGovActions, isVoterGovActionsLoading } = - useGetVoterGovActionsQuery(convertAddressToBech32(voterId as string), currentPage); - + useGetVoterGovActionsQuery( + convertAddressToBech32(voterId as string), + currentPage, + ); + return ( <Box className="flex flex-col gap-6"> <Typography variant="h4" fontWeight="bold"> @@ -54,7 +57,7 @@ const VoterImpact = () => { ))} </ul> )} - {!isVoterGovActionsLoading && voterGovActions?.data.length === 0 && ( + {!isVoterGovActionsLoading && !voterGovActions?.data?.length && ( <Box sx={{ py: 3 }}> <Paper elevation={2}