From 1939b699611c00211ab040e7b8491707953b1f66 Mon Sep 17 00:00:00 2001 From: Ghina Al Rashwani Date: Fri, 17 Oct 2025 19:22:25 +0300 Subject: [PATCH 1/2] ginar/ issue #665 adding toggle --- .../balanceHistory/BalanceHistoryChart.tsx | 382 +++++++++--------- 1 file changed, 202 insertions(+), 180 deletions(-) diff --git a/components/balanceHistory/BalanceHistoryChart.tsx b/components/balanceHistory/BalanceHistoryChart.tsx index c5bbd2a17..0b5928609 100644 --- a/components/balanceHistory/BalanceHistoryChart.tsx +++ b/components/balanceHistory/BalanceHistoryChart.tsx @@ -23,8 +23,6 @@ import { ArrowDown, ArrowUp, Minus } from "lucide-react"; import { useI18n } from "@/i18n/i18n"; import useDynamicGlobal from "@/hooks/api/homePage/useDynamicGlobal"; import { useHiveChainContext } from "@/contexts/HiveChainContext"; -import { convertVestsToHive, convertVestsToHP } from "@/utils/Calculations"; -import { grabNumericValue } from "@/utils/StringUtils"; import { Switch } from "@/components/ui/switch"; import { Label } from "@/components/ui/label"; import { useSettings } from "@/contexts/SettingsContext"; @@ -63,7 +61,7 @@ const BalanceHistoryChart: React.FC = ({ selectedCoinType, setSelectedCoinType, }) => { - const { t, dir, locale } = useI18n(); + const { t, dir } = useI18n(); const { hiveChain } = useHiveChainContext(); const { dynamicGlobalData } = useDynamicGlobal(); const { settings } = useSettings(); @@ -90,89 +88,60 @@ 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; - - return { - ...item, - convertedHive: convertedValue, - dollarValue: dollarValueFull, - }; - } - - if (type === "HIVE") { - const dollarValue = - !isNaN(item.balance) && !isNaN(hivePrice) - ? item.balance * hivePrice - : 0; + if (type === "HIVE") { + const dollarValue = !isNaN(item.balance) && !isNaN(hivePrice) ? item.balance * hivePrice : 0; + return { ...item, dollarValue }; + } - return { ...item, dollarValue }; - } + if (type === "HBD") { + return { ...item, dollarValue: !isNaN(item.balance) ? item.balance : 0 }; + } - if (type === "HBD") { - return { ...item, dollarValue: !isNaN(item.balance) ? item.balance : 0 }; - } + return item; + }); + }, + [dynamicGlobalData, hiveChain, unit] + ); - return item; - }); - }, - [dynamicGlobalData, hiveChain, unit] -); - - - const dataMap: Record< - string, - { - timestamp: string; - balance_change: number; - balance: number; - savings_balance?: number; - savings_balance_change?: number; - hivePrice: string; - dollarValue?: number; - convertedHive?: number; - }[] - > = useMemo(() => { + const dataMap = useMemo(() => { return { - [selectedCoinType]: - processedData(aggregatedAccountBalanceHistory, selectedCoinType) || [], + [selectedCoinType]: processedData(aggregatedAccountBalanceHistory, selectedCoinType) || [], }; }, [processedData, aggregatedAccountBalanceHistory, selectedCoinType]); @@ -180,14 +149,14 @@ const BalanceHistoryChart: React.FC = ({ setSelectedCoinType(coinType); }; - const displayData = useMemo(() => dataMap[selectedCoinType], [selectedCoinType]); + const displayData = useMemo(() => dataMap[selectedCoinType], [selectedCoinType, dataMap]); // ---------------- 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"; - const selectedData = displayData?.find((item) => item.timestamp === label); + const selectedData = displayData?.find((item: any) => item.timestamp === label); if (!selectedData) return null; const actualBalance = selectedData?.balance ?? 0; @@ -207,85 +176,100 @@ const BalanceHistoryChart: React.FC = ({

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

-
+
{isPositiveChange ? ( ) : isZeroChange ? ( - + ) : ( )} {` ${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")}
) : null}
- - {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)}`} + {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 + )}`} +
-
- )} + )}
); }; // ---------------- Coin toggle buttons ---------------- -const renderCoinButtons = () => ( -
- {/* Toggle on the far left */} - {selectedCoinType === "VESTS" && ( -
- - setUnit(checked ? "hp" : "vests")} - /> - + const renderCoinButtons = () => ( +
+ {/* Coin buttons always on the right */} + {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 +279,21 @@ 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 +304,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,26 +318,19 @@ const renderCoinButtons = () => ( if (!displayData || !displayData.length) return null; - const isDualAxis = selectedCoinType === "VESTS"; const primaryAxisId = isRTL ? "right" : "left"; const secondaryAxisId = isRTL ? "left" : "right"; - const leftMargin = isMobile - ? 10 - : selectedCoinType === "VESTS" - ? 50 - : 30; - return ( -
+
{renderCoinButtons()} - + @@ -375,14 +359,13 @@ const renderCoinButtons = () => ( return formatNumber(tick, false, false); }} /> - {isDualAxis && ( - `$${Math.round(tick)}`} - /> - )} + + `$${Math.round(tick)}`} + /> } /> ( dataKey={selectedCoinType === "VESTS" && unit === "hp" ? "convertedHive" : "balance"} stroke={colorMap[selectedCoinType]} strokeWidth={2} - activeDot={{ r: 6 }} - name={selectedCoinType === "VESTS" && unit === "hp" ? "HP" : selectedCoinType} dot={false} - hide={hiddenDataKeys.includes("balance")} + name={selectedCoinType === "VESTS" && unit === "hp" ? "HP" : selectedCoinType === "VESTS" ? "VESTS" : selectedCoinType} // Correct dynamic name for HIVE, VESTS, HP, HBD + hide={hiddenDataKeys.includes(selectedCoinType === "VESTS" && unit === "hp" ? "convertedHive" : "balance")} // Hide based on the actual dataKey used /> {showSavingsBalance === "yes" && selectedCoinType !== "VESTS" && ( @@ -413,9 +394,8 @@ const renderCoinButtons = () => ( dataKey="savings_balance" stroke={colorMap.SAVINGS} strokeWidth={2} - activeDot={{ r: 6 }} - name={t("balanceHistoryChart.savingsBalance")} dot={false} + name="Savings Balance" hide={hiddenDataKeys.includes("savings_balance")} /> )} @@ -427,26 +407,68 @@ const renderCoinButtons = () => ( fill="var(--color-background)" travellerWidth={10} tickFormatter={(value) => moment(value).format("MMM D")} - y={380} + y={250} x={50} className="text-xs" onChange={handleBrushAreaChange} /> )} { - const dataKey = event.dataKey as string; - const isHidden = hiddenDataKeys.includes(dataKey); - if (isHidden) setHiddenDataKeys(hiddenDataKeys.filter((key) => key !== dataKey)); - else setHiddenDataKeys([...hiddenDataKeys, dataKey]); + const dataKey = event.dataKey; + const actualDataKey = + (dataKey === selectedCoinType || dataKey === "HP" || dataKey === "VESTS") ? + (selectedCoinType === "VESTS" && unit === "hp" ? "convertedHive" : "balance") : + dataKey; + + const isHidden = hiddenDataKeys.includes(actualDataKey); + if (isHidden) + setHiddenDataKeys(hiddenDataKeys.filter((key) => key !== actualDataKey)); + else + setHiddenDataKeys([...hiddenDataKeys, actualDataKey]); }} /> + + + {/* Toggle next to legend (if VESTS is selected) */} + {selectedCoinType === "VESTS" && ( +
+ + setUnit(checked ? "hp" : "vests")} + /> + +
+ )}
); }; -export default BalanceHistoryChart; +export default BalanceHistoryChart; \ No newline at end of file -- GitLab From dcd0c396509c1915e8ff3c3c2464b9e8a2f28200 Mon Sep 17 00:00:00 2001 From: Ghina Al Rashwani Date: Wed, 22 Oct 2025 20:28:20 +0300 Subject: [PATCH 2/2] fixing toggle --- .../balanceHistory/BalanceHistoryChart.tsx | 82 ++++++++++--------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/components/balanceHistory/BalanceHistoryChart.tsx b/components/balanceHistory/BalanceHistoryChart.tsx index 0b5928609..8c413a913 100644 --- a/components/balanceHistory/BalanceHistoryChart.tsx +++ b/components/balanceHistory/BalanceHistoryChart.tsx @@ -98,18 +98,11 @@ const BalanceHistoryChart: React.FC = ({ 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 convertedHPRaw = hiveChain.vestsToHp( + vests, + dynamicGlobalData.headBlockDetails.rawTotalVestingFundHive, + dynamicGlobalData.headBlockDetails.rawTotalVestingShares + ); let convertedValue: number; if (typeof convertedHPRaw === "number") convertedValue = convertedHPRaw; @@ -119,7 +112,7 @@ const BalanceHistoryChart: React.FC = ({ else convertedValue = 0; const dollarValueFull = - !isNaN(convertedValue) && !isNaN(hivePrice) ? (convertedValue * hivePrice) / 100 : 0; + !isNaN(convertedValue) && !isNaN(hivePrice) ? (convertedValue * hivePrice) : 0; return { ...item, convertedHive: convertedValue, dollarValue: dollarValueFull }; } @@ -136,7 +129,7 @@ const BalanceHistoryChart: React.FC = ({ return item; }); }, - [dynamicGlobalData, hiveChain, unit] + [dynamicGlobalData, hiveChain] ); const dataMap = useMemo(() => { @@ -159,7 +152,10 @@ const BalanceHistoryChart: React.FC = ({ const selectedData = displayData?.find((item: any) => item.timestamp === label); if (!selectedData) return null; - const actualBalance = selectedData?.balance ?? 0; + const actualBalance = selectedCoinType === "VESTS" && unit === "hp" + ? selectedData?.convertedHive ?? 0 + : selectedData?.balance ?? 0; + const balanceChange = selectedData?.balance_change ?? 0; const savingsBalance = selectedData?.savings_balance ?? undefined; const savingsBalanceChange = selectedData?.savings_balance_change ?? 0; @@ -194,7 +190,7 @@ const BalanceHistoryChart: React.FC = ({ {` ${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")}`}
{dollarValue ? (
@@ -253,7 +249,6 @@ const BalanceHistoryChart: React.FC = ({ // ---------------- Coin toggle buttons ---------------- const renderCoinButtons = () => (
- {/* Coin buttons always on the right */} {availableCoins.map((coinType) => (