From 31253436ecfa8b6c07d02927cf0f2261666ce416 Mon Sep 17 00:00:00 2001 From: Ghina Al Rashwani Date: Thu, 16 Oct 2025 12:13:51 +0300 Subject: [PATCH] ginar/ issue #665 adding vests/hp toggle and fixing its position --- .../balanceHistory/BalanceHistoryChart.tsx | 371 +++++++++++------- 1 file changed, 224 insertions(+), 147 deletions(-) diff --git a/components/balanceHistory/BalanceHistoryChart.tsx b/components/balanceHistory/BalanceHistoryChart.tsx index c5bbd2a17..f7857a0f7 100644 --- a/components/balanceHistory/BalanceHistoryChart.tsx +++ b/components/balanceHistory/BalanceHistoryChart.tsx @@ -90,72 +90,77 @@ const BalanceHistoryChart: React.FC = ({ return () => window.removeEventListener("resize", handleResize); }, []); - const processedData = useCallback( - (data: any, type: string) => { - if (!dynamicGlobalData || !hiveChain || !data) return []; - - return data.map((item: any) => { - const hivePrice = parseFloat(item.hivePrice || "0"); - - if (type === "VESTS") { - const vests = item.balance?.toString() || "0"; - - // Convert VESTS to HP or Hive - let convertedHPRaw = unit === "hp" - ? hiveChain.vestsToHp( - vests, - dynamicGlobalData.headBlockDetails.rawTotalVestingFundHive, - dynamicGlobalData.headBlockDetails.rawTotalVestingShares - ) - : hiveChain.vestsToHp( // using vestsToHp also for Hive conversion - vests, - dynamicGlobalData.headBlockDetails.rawTotalVestingFundHive, - dynamicGlobalData.headBlockDetails.rawTotalVestingShares - ); - - // Ensure convertedValue is a number - let convertedValue: number; - if (typeof convertedHPRaw === "number") { - convertedValue = convertedHPRaw; - } else if (convertedHPRaw && typeof convertedHPRaw === "object" && "amount" in convertedHPRaw) { - convertedValue = parseFloat(convertedHPRaw.amount); - } else if (typeof convertedHPRaw === "string") { - convertedValue = parseFloat(convertedHPRaw); - } else { - convertedValue = 0; + const processedData = useCallback( + (data: any, type: string) => { + if (!dynamicGlobalData || !hiveChain || !data) return []; + + return data.map((item: any) => { + const hivePrice = parseFloat(item.hivePrice || "0"); + + if (type === "VESTS") { + const vests = item.balance?.toString() || "0"; + + let convertedHPRaw = + unit === "hp" + ? hiveChain.vestsToHp( + vests, + dynamicGlobalData.headBlockDetails.rawTotalVestingFundHive, + dynamicGlobalData.headBlockDetails.rawTotalVestingShares + ) + : hiveChain.vestsToHp( + vests, + dynamicGlobalData.headBlockDetails.rawTotalVestingFundHive, + dynamicGlobalData.headBlockDetails.rawTotalVestingShares + ); + + let convertedValue: number; + if (typeof convertedHPRaw === "number") { + convertedValue = convertedHPRaw; + } else if ( + convertedHPRaw && + typeof convertedHPRaw === "object" && + "amount" in convertedHPRaw + ) { + convertedValue = parseFloat(convertedHPRaw.amount); + } else if (typeof convertedHPRaw === "string") { + convertedValue = parseFloat(convertedHPRaw); + } else { + convertedValue = 0; + } + + const dollarValueFull = + !isNaN(convertedValue) && !isNaN(hivePrice) + ? (convertedValue * hivePrice) / 100 + : 0; + + return { + ...item, + convertedHive: convertedValue, + dollarValue: dollarValueFull, + }; } - const dollarValueFull = - !isNaN(convertedValue) && !isNaN(hivePrice) - ? convertedValue * hivePrice /100 - : 0; + if (type === "HIVE") { + const dollarValue = + !isNaN(item.balance) && !isNaN(hivePrice) + ? item.balance * hivePrice + : 0; - return { - ...item, - convertedHive: convertedValue, - dollarValue: dollarValueFull, - }; - } - - if (type === "HIVE") { - const dollarValue = - !isNaN(item.balance) && !isNaN(hivePrice) - ? item.balance * hivePrice - : 0; - - return { ...item, dollarValue }; - } - - if (type === "HBD") { - return { ...item, dollarValue: !isNaN(item.balance) ? item.balance : 0 }; - } + return { ...item, dollarValue }; + } - return item; - }); - }, - [dynamicGlobalData, hiveChain, unit] -); + if (type === "HBD") { + return { + ...item, + dollarValue: !isNaN(item.balance) ? item.balance : 0, + }; + } + return item; + }); + }, + [dynamicGlobalData, hiveChain, unit] + ); const dataMap: Record< string, @@ -183,7 +188,15 @@ const BalanceHistoryChart: React.FC = ({ const displayData = useMemo(() => dataMap[selectedCoinType], [selectedCoinType]); // ---------------- Tooltip ---------------- - const CustomTooltip = ({ active, payload, label }: { active?: boolean; payload?: any[]; label?: string; }) => { + const CustomTooltip = ({ + active, + payload, + label, + }: { + active?: boolean; + payload?: any[]; + label?: string; + }) => { const { dir: tooltipDir } = useI18n(); if (quickView || !active || !payload || payload.length === 0) return null; const isTooltipRTL = tooltipDir === "rtl"; @@ -207,17 +220,32 @@ const BalanceHistoryChart: React.FC = ({

{`${t("common.date")}: ${label}`}

-
+
{isPositiveChange ? ( ) : isZeroChange ? ( - + ) : ( )} - {` ${formatNumber(balanceChange, selectedCoinType === "VESTS" ? unit === "vests" : false)}`} + {` ${formatNumber( + balanceChange, + selectedCoinType === "VESTS" ? unit === "vests" : false + )}`} +
+
+ {`${t("common.balance")}: ${formatNumber( + actualBalance, + selectedCoinType === "VESTS" ? unit === "vests" : false + )}`}
-
{`${t("common.balance")}: ${formatNumber(actualBalance, selectedCoinType === "VESTS" ? unit === "vests" : false)}`}
{dollarValue ? (
Dollar Value: ${formatNumber(dollarValue, false, selectedCoinType === "VESTS")} @@ -225,67 +253,64 @@ const BalanceHistoryChart: React.FC = ({ ) : null}
- {showSavingsBalance === "yes" && savingsBalance !== undefined && selectedCoinType !== "VESTS" && ( -
-
- {isSavingsPositiveChange ? ( - - ) : isSavingsZeroChange ? ( - - ) : ( - - )} - {` ${formatNumber(savingsBalanceChange, selectedCoinType === "VESTS" ? unit === "vests" : false)}`} + {showSavingsBalance === "yes" && + savingsBalance !== undefined && + selectedCoinType !== "VESTS" && ( +
+
+ {isSavingsPositiveChange ? ( + + ) : isSavingsZeroChange ? ( + + ) : ( + + )} + {` ${formatNumber( + savingsBalanceChange, + selectedCoinType === "VESTS" ? unit === "vests" : false + )}`} +
+
+ {`${t("balanceHistoryChart.savingsBalance")}: ${formatNumber( + savingsBalance, + selectedCoinType === "VESTS" ? unit === "vests" : false + )}`} +
-
- {`${t("balanceHistoryChart.savingsBalance")}: ${formatNumber(savingsBalance, selectedCoinType === "VESTS" ? unit === "vests" : false)}`} -
-
- )} + )}
); }; // ---------------- Coin toggle buttons ---------------- -const renderCoinButtons = () => ( -
- {/* Toggle on the far left */} - {selectedCoinType === "VESTS" && ( -
- - setUnit(checked ? "hp" : "vests")} - /> - + const renderCoinButtons = () => ( +
+ {/* Coin buttons container — right of toggle */} +
+ {availableCoins.map((coinType) => ( + + ))} +
- )} - - {/* Coin buttons always on the right */} - {availableCoins.map((coinType) => ( - - ))} -
- -); - - + ); // ---------------- Min/Max for Y-axis ---------------- const getMinMax = (data: any[]): [number, number] => { @@ -295,14 +320,20 @@ const renderCoinButtons = () => ( if (selectedCoinType === "VESTS") { allValues = data.map((item) => item.convertedHive || 0); - const dollarValues = data.map((item) => item.dollarValue).filter((v): v is number => typeof v === "number" && !Number.isNaN(v)); + const dollarValues = data + .map((item) => item.dollarValue) + .filter((v): v is number => typeof v === "number" && !Number.isNaN(v)); allValues = allValues.concat(dollarValues); } else { allValues = data.map((item) => item.balance); - const dollarValues = data.map((item) => item.dollarValue).filter((v): v is number => typeof v === "number" && !Number.isNaN(v)); + const dollarValues = data + .map((item) => item.dollarValue) + .filter((v): v is number => typeof v === "number" && !Number.isNaN(v)); allValues = allValues.concat(dollarValues); if (showSavingsBalance === "yes") { - const savingsValues = data.map((item) => item.savings_balance).filter((v): v is number => typeof v === "number"); + const savingsValues = data + .map((item) => item.savings_balance) + .filter((v): v is number => typeof v === "number"); allValues = allValues.concat(savingsValues); } } @@ -313,7 +344,7 @@ const renderCoinButtons = () => ( const [fullDataMin, fullDataMax] = getMinMax(displayData); const [minValue, maxValue] = zoomedDomain || [fullDataMin, fullDataMax]; - const handleBrushAreaChange = (domain: { startIndex?: number; endIndex?: number; }) => { + const handleBrushAreaChange = (domain: { startIndex?: number; endIndex?: number }) => { if (!domain || domain.startIndex === undefined || domain.endIndex === undefined) { setZoomedDomain([fullDataMin, fullDataMax]); return; @@ -327,15 +358,12 @@ const renderCoinButtons = () => ( if (!displayData || !displayData.length) return null; - const isDualAxis = selectedCoinType === "VESTS"; + // Show secondary axis whenever there is dollarValue data + const isDualAxis = displayData.some((d) => d.dollarValue !== undefined); const primaryAxisId = isRTL ? "right" : "left"; const secondaryAxisId = isRTL ? "left" : "right"; - const leftMargin = isMobile - ? 10 - : selectedCoinType === "VESTS" - ? 50 - : 30; + const leftMargin = isMobile ? 10 : selectedCoinType === "VESTS" ? 50 : 30; return (
@@ -395,17 +423,19 @@ const renderCoinButtons = () => ( dot={false} hide={hiddenDataKeys.includes("balance")} /> - + {displayData.some((d) => d.dollarValue !== undefined) && ( + + )} {showSavingsBalance === "yes" && selectedCoinType !== "VESTS" && ( ( onChange={handleBrushAreaChange} /> )} + + {/* ---------- LEGEND with inline toggle ---------- */} { - const dataKey = event.dataKey as string; - const isHidden = hiddenDataKeys.includes(dataKey); - if (isHidden) setHiddenDataKeys(hiddenDataKeys.filter((key) => key !== dataKey)); - else setHiddenDataKeys([...hiddenDataKeys, dataKey]); + verticalAlign="bottom" + wrapperStyle={{ + display: "flex", + justifyContent: isRTL ? "flex-end" : "flex-start", + flexWrap: "wrap", // only wrap on very small screens + gap: "12px", // space between legend items + paddingTop: "0px", // maintain original vertical position + }} + content={(props) => { + const { payload } = props; + return ( +
    + {payload?.map((entry, index) => { + const dataKey = (entry as any).dataKey; + const isHidden = hiddenDataKeys.includes(dataKey); + return ( +
  • { + if (isHidden) + setHiddenDataKeys(hiddenDataKeys.filter((key) => key !== dataKey)); + else + setHiddenDataKeys([...hiddenDataKeys, dataKey]); + }} + > +
    + {(entry as any).value} +
  • + ); + })} + + {selectedCoinType === "VESTS" && ( +
  • + + setUnit(checked ? "hp" : "vests")} + className="w-12 h-6 flex-shrink-0" // consistent toggle size + /> + +
  • + )} +
+ ); }} /> + +
-- GitLab