From daa56dba9a8f7f9c318b5c1e2bc9239df64e5d74 Mon Sep 17 00:00:00 2001
From: Mohammad <mcfarhat@gmail.com>
Date: Thu, 25 Jul 2024 19:22:24 +0300
Subject: [PATCH] implement RC delegations box related to issue 285

---
 api/common/useRcDelegations.ts                | 18 ++++
 components/account/AccountDetailsSection.tsx  |  5 +
 .../account/AccountRcDelegationsCard.tsx      | 95 +++++++++++++++++++
 services/FetchingService.ts                   | 10 ++
 4 files changed, 128 insertions(+)
 create mode 100644 api/common/useRcDelegations.ts
 create mode 100644 components/account/AccountRcDelegationsCard.tsx

diff --git a/api/common/useRcDelegations.ts b/api/common/useRcDelegations.ts
new file mode 100644
index 00000000..c735b540
--- /dev/null
+++ b/api/common/useRcDelegations.ts
@@ -0,0 +1,18 @@
+import { useQuery } from "@tanstack/react-query";
+import fetchingService from "@/services/FetchingService";
+
+const useRcDelegations = (delegatorAccount: string, limit: number) => {
+  const {
+    data: rcDelegationsData,
+    isLoading: isRcDelegationsLoading,
+    isError: isRcDelegationsError,
+  } = useQuery({
+    queryKey: ["RcDelegations", delegatorAccount, limit],
+    queryFn: () => fetchingService.getRcDelegations(delegatorAccount, limit),
+    refetchOnWindowFocus: false,
+  });
+
+  return { rcDelegationsData, isRcDelegationsLoading, isRcDelegationsError };
+};
+
+export default useRcDelegations;
\ No newline at end of file
diff --git a/components/account/AccountDetailsSection.tsx b/components/account/AccountDetailsSection.tsx
index 6df8401e..013d5fdb 100644
--- a/components/account/AccountDetailsSection.tsx
+++ b/components/account/AccountDetailsSection.tsx
@@ -10,6 +10,7 @@ import VotersDialog from "../Witnesses/VotersDialog";
 import VotesHistoryDialog from "../Witnesses/VotesHistoryDialog";
 import useWitnessDetails from "@/api/common/useWitnessDetails";
 import AccountVestingDelegationsCard from "./AccountVestingDelegationsCard";
+import AccountRcDelegationsCard from "./AccountRcDelegationsCard";
 import { config } from "@/Config";
 
 interface AccountDetailsSectionProps {
@@ -74,6 +75,10 @@ const AccountDetailsSection: React.FC<AccountDetailsSectionProps> = ({
             startAccount={null}
             limit={config.maxDelegatorsCount}
           />
+      <AccountRcDelegationsCard
+        delegatorAccount={accountName}
+        limit={config.maxDelegatorsCount}
+      />
       <VotersDialog
         accountName={accountName}
         isVotersOpen={isVotersModalOpen}
diff --git a/components/account/AccountRcDelegationsCard.tsx b/components/account/AccountRcDelegationsCard.tsx
new file mode 100644
index 00000000..0f09e138
--- /dev/null
+++ b/components/account/AccountRcDelegationsCard.tsx
@@ -0,0 +1,95 @@
+import React, { useState, Fragment } from "react";
+import { ArrowDown, ArrowUp } from "lucide-react";
+import Link from "next/link";
+import { Card, CardContent, CardHeader } from "../ui/card";
+import { Table, TableBody, TableRow, TableCell } from "../ui/table";
+import { cn } from "@/lib/utils";
+import useRcDelegations from "@/api/common/useRcDelegations";
+type RcDelegation = {
+  to: string;
+  delegated_rc: number;
+};
+
+type AccountRcDelegationsCardProps = {
+  delegatorAccount: string;
+  limit: number;
+};
+
+const buildTableBody = (delegations: RcDelegation[]) => {
+  return delegations.map((delegation: RcDelegation, index: number) => {
+    const isLast = index === delegations.length - 1;
+    return (
+      <Fragment key={index}>
+        <TableRow
+          className={cn(
+            {
+              "border-t border-gray-700": index !== 0,
+              "border-b border-gray-700": !isLast,
+            },
+            "hover:bg-inherit"
+          )}
+        >
+          <TableCell>{index + 1}</TableCell>
+          <TableCell className="text-right">
+            <Link className="text-blue-400" href={`/@${delegation.to}`}>
+              {delegation.to}
+            </Link>
+          </TableCell>
+          <TableCell className="text-right">{delegation.delegated_rc}</TableCell>
+        </TableRow>
+      </Fragment>
+    );
+  });
+};
+
+const AccountRcDelegationsCard: React.FC<AccountRcDelegationsCardProps> = ({
+  delegatorAccount,
+  limit,
+}) => {
+  const [isPropertiesHidden, setIsPropertiesHidden] = useState(true);
+  const {
+    rcDelegationsData,
+    isRcDelegationsLoading,
+    isRcDelegationsError,
+  } = useRcDelegations(delegatorAccount, limit);
+
+  if (isRcDelegationsLoading) {
+    return <div></div>;
+  }
+
+  if (isRcDelegationsError) {
+    return <div></div>;
+  }
+
+  const delegations = rcDelegationsData?.result || [];
+  if (!delegations.length) return <div className="text-black"></div>;
+
+  delegations.sort((a: RcDelegation, b: RcDelegation) =>
+    a.to.toLowerCase().localeCompare(b.to.toLowerCase())
+  );
+
+  const handlePropertiesVisibility = () => {
+    setIsPropertiesHidden(!isPropertiesHidden);
+  };
+
+  return (
+    <Card data-testid="rc-delegations-dropdown" className="overflow-hidden">
+      <CardHeader className="p-0">
+        <div
+          onClick={handlePropertiesVisibility}
+          className="h-full flex justify-between align-center p-2 hover:bg-slate-600 cursor-pointer px-4"
+        >
+          <div className="text-lg">RC Delegations</div>
+          {isPropertiesHidden ? <ArrowDown /> : <ArrowUp />}
+        </div>
+      </CardHeader>
+      <CardContent hidden={isPropertiesHidden}>
+        <Table>
+          <TableBody>{buildTableBody(delegations)}</TableBody>
+        </Table>
+      </CardContent>
+    </Card>
+  );
+};
+
+export default AccountRcDelegationsCard;
\ No newline at end of file
diff --git a/services/FetchingService.ts b/services/FetchingService.ts
index 9b6feabf..cc335954 100644
--- a/services/FetchingService.ts
+++ b/services/FetchingService.ts
@@ -240,6 +240,16 @@ class FetchingService {
     return await this.makePostRequest(this.nodeUrl!, requestBody);
   }
 
+  async getRcDelegations (delegatorAccount: string, limit: number): Promise<any> {
+    const requestBody ={
+      jsonrpc: "2.0",
+      method: "condenser_api.list_rc_direct_delegations",
+      params: [[delegatorAccount, ""], limit],
+      id: 1
+    };
+    return await this.makePostRequest(this.nodeUrl!, requestBody);
+  }
+
   async getBlockByTime(date: Date): Promise<number> {
     const requestBody: Hive.GetBlockByTimeProps = {
       _timestamp: date,
-- 
GitLab