Skip to content
Snippets Groups Projects
Commit 7148638a authored by Lukas Budginas's avatar Lukas Budginas Committed by Jakub Lachór
Browse files

Convert vests to HP on account page

parent b09e6866
No related branches found
No related tags found
1 merge request!380Lbudginas/#304 convert vests to hp account page
Pipeline #101320 canceled
......@@ -2,7 +2,7 @@ import { ArrowDown, ArrowUp, User } from "lucide-react";
import { Card, CardContent, CardHeader } from "../ui/card";
import Hive from "@/types/Hive";
import useAccountAuthorities from "@/api/accountPage/useAccountAuthorities";
import { useState } from "react";
import { Fragment, useState } from "react";
import Link from "next/link";
import CopyToKeyboard from "../CopyToKeyboard";
import { Table, TableBody, TableCell, TableRow } from "../ui/table";
......@@ -81,22 +81,26 @@ const AccountAuthoritiesCard: React.FC<AccountMainCardProps> = ({
<div className=" text-lg mt-2">{title}</div>
<Table>
<TableBody>
{authorities?.account_auth.map((singleAuthority, index) =>
renderAuthority(
singleAuthority[0] || "",
singleAuthority[1] || "",
true,
index
)
)}
{authorities?.key_auth.map((singleAuthority, index) =>
renderAuthority(
singleAuthority[0] || "",
singleAuthority[1] || "",
false,
index + authorities?.account_auth.length
)
)}
{authorities?.account_auth.map((singleAuthority, index) => (
<Fragment key={index}>
{renderAuthority(
singleAuthority[0] || "",
singleAuthority[1] || "",
true,
index
)}
</Fragment>
))}
{authorities?.key_auth.map((singleAuthority, index) => (
<Fragment key={index}>
{renderAuthority(
singleAuthority[0] || "",
singleAuthority[1] || "",
false,
index + authorities?.account_auth.length
)}
</Fragment>
))}
<TableRow
className={cn("font-semibold", {
"bg-gray-700": shouldMarkThreshold,
......
import { ReactNode, useState, Fragment } from "react";
import { ReactNode, Fragment } from "react";
import { Card, CardContent, CardHeader } from "../ui/card";
import { Table, TableBody, TableCell, TableRow } from "../ui/table";
import { cn, formatNumber } from "@/lib/utils";
import { convertVestsToHP, convertHiveToUSD } from "@/utils/Hooks";
import { convertVestsToHP, convertHiveToUSD } from "@/utils/Calculations";
import useDynamicGlobal from "@/api/homePage/useDynamicGlobal";
import { useHiveChainContext } from "@/contexts/HiveChainContext";
import { splitStringValue } from "@/utils/StringUtils";
type AccountBalanceCardProps = {
header: string;
userDetails: any;
};
const cardNameMap = new Map([
["hbd_balance", "HBD Liquid"],
["hbd_saving_balance", "HBD Savings"],
......@@ -21,16 +23,19 @@ const cardNameMap = new Map([
["reward_vesting_hive", "HP Unclaimed"],
["received_vesting_shares", "Received HP"],
["delegated_vesting_shares", "Delegated HP"],
["vesting_withdraw_rate", "Powering down HP"]
["vesting_withdraw_rate", "Powering down HP"],
]);
const vestsParams = ['received_vesting_shares', 'delegated_vesting_shares', 'vesting_withdraw_rate'];
const vestsParams = [
"received_vesting_shares",
"delegated_vesting_shares",
"vesting_withdraw_rate",
];
const buildTableBody = (
parameters: string[],
render_key: (key: string) => ReactNode,
convert_usd: (key:string) => ReactNode
convert_usd: (key: string) => ReactNode
) => {
return parameters.map((param: string, index: number) => {
if (cardNameMap.has(param)) {
......@@ -49,7 +54,8 @@ const buildTableBody = (
<TableCell className="text-right">{convert_usd(param)}</TableCell>
</TableRow>
</Fragment>
)}
);
}
});
};
......@@ -57,30 +63,57 @@ const AccountBalanceCard: React.FC<AccountBalanceCardProps> = ({
header,
userDetails,
}) => {
const { dynamicGlobalData } = useDynamicGlobal();
const { hiveChain } = useHiveChainContext();
if (!userDetails) return null;
if (!dynamicGlobalData || !hiveChain) return;
const {
headBlockDetails: { totalVestingFundHive, totalVestingShares, feedPrice },
} = dynamicGlobalData;
const keys = Object.keys(userDetails);
const render_key = (key: string) => {
if (vestsParams.includes(key)){
return parseFloat(formatNumber(parseFloat(
convertVestsToHP(userDetails[key]).toString()),false, true)).toFixed(3) + " HP";
if (vestsParams.includes(key)) {
const formattedHp = convertVestsToHP(
hiveChain,
userDetails[key],
totalVestingFundHive,
totalVestingShares
);
return formattedHp;
}
return userDetails[key];
}
};
const convert_usd = (key: string) => {
let displVal = "";
if (vestsParams.includes(key)){
displVal = convertHiveToUSD(parseFloat(convertVestsToHP(userDetails[key]).toString())).toFixed(2);
}else if (key.includes('hbd')){//considering hbd as stable coin = 1$
displVal = parseFloat(userDetails[key].replace(/,/g, '').split(" ")[0]).toFixed(2);;
}else{
displVal = convertHiveToUSD(userDetails[key].replace(/,/g, '').split(" ")[0]).toFixed(2);
if (vestsParams.includes(key)) {
const formattedHP = convertVestsToHP(
hiveChain,
userDetails[key],
totalVestingFundHive,
totalVestingShares
);
displVal = convertHiveToUSD(
Number(splitStringValue(formattedHP, "HP").replace(",", "")),
feedPrice
).toFixed(2);
} else if (key.includes("hbd")) {
//considering hbd as stable coin = 1$
displVal = Number(
userDetails[key].replace(/,/g, "").split(" ")[0]
).toFixed(2);
} else {
displVal = convertHiveToUSD(
userDetails[key].replace(/,/g, "").split(" ")[0],
feedPrice
).toFixed(2);
}
return '$ ' + formatNumber(parseFloat(displVal), false, true);
}
return "$ " + formatNumber(parseFloat(displVal), false, true);
};
return (
<Card
......@@ -88,19 +121,13 @@ const AccountBalanceCard: React.FC<AccountBalanceCardProps> = ({
className="overflow-hidden pb-0"
>
<CardHeader className="p-0">
<div
className="flex justify-between align-center p-2 hover:bg-slate-600 cursor-pointer px-4"
>
<div className="flex justify-between align-center p-2 hover:bg-slate-600 cursor-pointer px-4">
<div className="text-lg">{header}</div>
</div>
</CardHeader>
<CardContent
data-testid="card-content"
>
<CardContent data-testid="card-content">
<Table>
<TableBody>
{buildTableBody(keys, render_key, convert_usd)}
</TableBody>
<TableBody>{buildTableBody(keys, render_key, convert_usd)}</TableBody>
</Table>
</CardContent>
</Card>
......
......@@ -5,6 +5,9 @@ import { Card, CardContent, CardHeader } from "../ui/card";
import { Table, TableBody, TableCell, TableRow } from "../ui/table";
import { cn } from "@/lib/utils";
import CopyToKeyboard from "../CopyToKeyboard";
import { convertVestsToHP } from "@/utils/Calculations";
import useDynamicGlobal from "@/api/homePage/useDynamicGlobal";
import { useHiveChainContext } from "@/contexts/HiveChainContext";
type AccountDetailsCardProps = {
header: string;
......@@ -20,7 +23,7 @@ const EXCLUDE_KEYS = [
const LINK_KEYS = ["recovery_account", "reset_account"];
const URL_KEYS = ["url"];
const COPY_KEYS = ["signing_key"]
const COPY_KEYS = ["signing_key"];
const buildTableBody = (
keys: string[],
......@@ -53,12 +56,33 @@ const AccountDetailsCard: React.FC<AccountDetailsCardProps> = ({
header,
userDetails,
}) => {
const { dynamicGlobalData } = useDynamicGlobal();
const { hiveChain } = useHiveChainContext();
const [isPropertiesHidden, setIsPropertiesHidden] = useState(true);
if (!userDetails) return null;
if (!userDetails || !dynamicGlobalData || !hiveChain) return;
const {
headBlockDetails: { totalVestingFundHive, totalVestingShares },
} = dynamicGlobalData;
const keys = Object.keys(userDetails);
const renderConvertedHP = (userKey: string, objectKey: string) => {
if (userKey.includes("VESTS") && objectKey !== "vests") {
const formattedHP = convertVestsToHP(
hiveChain,
userKey,
totalVestingFundHive,
totalVestingShares
);
return formattedHP;
} else {
return userKey;
}
};
const render_key = (key: string) => {
if (LINK_KEYS.includes(key)) {
return (
......@@ -69,10 +93,15 @@ const AccountDetailsCard: React.FC<AccountDetailsCardProps> = ({
}
if (COPY_KEYS.includes(key)) {
let shortenedKey: string = "";
shortenedKey = `${userDetails?.[key]?.slice(0, 8)}...${userDetails?.[key]?.slice(userDetails[key].length - 5)}`
shortenedKey = `${userDetails?.[key]?.slice(0, 8)}...${userDetails?.[
key
]?.slice(userDetails[key].length - 5)}`;
return (
<CopyToKeyboard value={userDetails[key]} displayValue={shortenedKey} />
)
<CopyToKeyboard
value={userDetails[key]}
displayValue={shortenedKey}
/>
);
}
if (URL_KEYS.includes(key)) {
return (
......@@ -89,7 +118,7 @@ const AccountDetailsCard: React.FC<AccountDetailsCardProps> = ({
} else if (typeof userDetails[key] === "number") {
return userDetails[key].toLocaleString();
} else if (typeof userDetails[key] === "string") {
return userDetails[key];
return renderConvertedHP(userDetails[key], key);
} else return JSON.stringify(userDetails[key]);
};
......
import { splitStringValue } from "./StringUtils";
import { IHiveChainInterface } from "@hiveio/wax";
/**
* Function converting vests to hive power
* @param hivechain response from HiveChainContext.ts as type IHiveChainInterface | undefined,
* @param vests amount of VESTS as string, not trimmed, with keyword `VESTS` in it
* @param totalVestingFundHive amount of total_vesting_fund_hive as string, received from useGlobalDataHook() as dynamicGlobalData.headBlockDetails.totalVestingFundHive
* @param totalVestingShares amount of total_vesting_shares as string, received from useGlobalDataHook() as dynamicGlobalData.headBlockDetails.totalVestingShares
* @returns calculation result of Hive Power (HP) as number
*/
export const convertVestsToHP = (
hivechain: IHiveChainInterface,
vests: string,
totalVestingFundHive: string,
totalVestingShares: string
) => {
if (!hivechain || !vests || !totalVestingFundHive || !totalVestingShares)
return;
const formattedVests = splitStringValue(vests, "VESTS");
const formattedTotalVestingFundHive = splitStringValue(
totalVestingFundHive,
"HIVE"
);
const formattedTotalVestingShares = splitStringValue(
totalVestingShares,
"VESTS"
);
const convertedHp = hivechain.vestsToHp(
formattedVests,
formattedTotalVestingFundHive,
formattedTotalVestingShares
);
//Replace original value of `HIVE` with `HP`
const formattedHP = hivechain.formatter
.format(convertedHp)
.replace("HIVE", "HP");
return formattedHP;
};
/**
* Function converting Hive Power to USD
*
* @param hp Hive Power amount as number
* @param feedPrice amount of feed_price as string, received from useGlobalDataHook() as dynamicGlobalData.headBlockDetails.totalVestingFundHive
* @returns calculation result of USD as number
*/
export const convertHiveToUSD = (hp: number, feedPrice: string) => {
const hivePrice = feedPrice?.split(" ")[0];
return hp * parseFloat(hivePrice ?? "0"); //default to 0 if no matching price is found
};
import { useSearchParams } from "next/navigation";
// //////////////////////////////////////////////////////////////////////////////
// TODO:
// - This hooks file either should be renamed or cleaned, because hooks
// should start with `use` keyword and have seperate file for each hook.
// This file contains a lot of helper functions, and not hooks, which is misleading,
// because inside real hook you can call another hook, and here you can't because
// it's a simple function. Also hooks should be .tsx
// - Keep it clean, document every existing and new functions as in example:
/**
* hook for using debounce
*
* @param func function to be called after wait
* @param wait wait in ms
* @returns callable debounce function
*/
// //////////////////////////////////////////////////////////////////////////////
import { useRouter } from "next/router";
import {
useRef,
......@@ -272,30 +289,6 @@ const getSyncInfoData = (
};
};
export const convertVestsToHP = (vests: string) => {
const dynamicGlobalData = useDynamicGlobal().dynamicGlobalData;
return dynamicGlobalData?.headBlockDetails
? (parseFloat(vests.replace(/,/g, "").split(" ")[0]) *
parseFloat(
dynamicGlobalData?.headBlockDetails?.totalVestingFundHive
?.replace(/,/g, "")
.split(" ")[0]
)) /
parseFloat(
dynamicGlobalData?.headBlockDetails?.totalVestingShares
?.replace(/,/g, "")
.split(" ")[0]
)
: 0;
};
export const convertHiveToUSD = (hiveAmount: number) => {
const dynamicGlobalData = useDynamicGlobal().dynamicGlobalData;
const hivePrice =
dynamicGlobalData?.headBlockDetails?.feedPrice?.split(" ")[0];
return hiveAmount * parseFloat(hivePrice ?? "0"); //default to 0 if no matching price is found
};
export const useBlockchainSyncInfo = () => {
const dynamicGlobalQueryData = useDynamicGlobal().dynamicGlobalData;
const headBlockNum = useHeadBlockNumber().headBlockNumberData;
......
......@@ -98,3 +98,15 @@ export const trimAccountName = (accountName: string) => {
}
return trimmedName;
};
/**
* Returns only numbers as string type and trims last word such as `HIVE` or `VESTS`
*
* @param value string value that needs to be trimmed
* @param keyword string keyword of what we want to split from our string
* @returns trimmed string without keyword
*/
export const splitStringValue = (value: string, keyword: string) => {
return value.split(keyword)[0];
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment