From 4dc8b3cd42f6f80381159f3b257ef82ae25b49d3 Mon Sep 17 00:00:00 2001
From: Emmanuel Mutisya <emmanuelmutisya254@gmail.com>
Date: Sat, 28 Sep 2024 23:21:45 +0300
Subject: [PATCH] update the voted gov action card

---
 backend/src/drep/drep.service.ts              |   6 +-
 backend/src/queries/voterGovActions.ts        |   4 +-
 .../components/Loaders/GovActionLoader.tsx    |   3 +-
 .../components/atoms/DrepVoteTimelineCard.tsx | 148 +++++++++++++-----
 .../src/components/voters/VoterImpact.tsx     |   9 +-
 5 files changed, 124 insertions(+), 46 deletions(-)

diff --git a/backend/src/drep/drep.service.ts b/backend/src/drep/drep.service.ts
index b85c5ddc..1f5dc770 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 d8b482e8..811c661e 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 d03ec8e1..04b0b432 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 dc2201d0..8ff3deb6 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 abc88e78..2a086355 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}
-- 
GitLab