From d0caa2471d46265af713242b19066dbc4863a391 Mon Sep 17 00:00:00 2001 From: Ghina Al Rashwani Date: Thu, 9 Oct 2025 10:50:55 +0300 Subject: [PATCH 1/2] ginar/ issue #665 adding toggle for vests & hp --- .../balanceHistory/BalanceHistoryChart.tsx | 300 ++++++------------ 1 file changed, 101 insertions(+), 199 deletions(-) diff --git a/components/balanceHistory/BalanceHistoryChart.tsx b/components/balanceHistory/BalanceHistoryChart.tsx index d526507ff..4b2e9a508 100644 --- a/components/balanceHistory/BalanceHistoryChart.tsx +++ b/components/balanceHistory/BalanceHistoryChart.tsx @@ -23,8 +23,11 @@ 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 } from "@/utils/Calculations"; +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"; interface BalanceHistoryChartProps { aggregatedAccountBalanceHistory?: { @@ -63,22 +66,26 @@ const BalanceHistoryChart: React.FC = ({ const { t, dir, locale } = useI18n(); const { hiveChain } = useHiveChainContext(); const { dynamicGlobalData } = useDynamicGlobal(); + const { settings } = useSettings(); const isRTL = dir === "rtl"; const [isMobile, setIsMobile] = useState(window.innerWidth < 480); const [hiddenDataKeys, setHiddenDataKeys] = useState([]); + const [unit, setUnit] = useState<"vests" | "hp">( + settings.displayVestHpMode === "hp" ? "hp" : "vests" + ); + + useEffect(() => { + setUnit(settings.displayVestHpMode === "hp" ? "hp" : "vests"); + }, [settings.displayVestHpMode]); - // State to store available coins const availableCoins = ["HIVE", "VESTS", "HBD"]; - const [zoomedDomain, setZoomedDomain] = useState<[number, number] | null>( - null - ); + const [zoomedDomain, setZoomedDomain] = useState<[number, number] | null>(null); useEffect(() => { const handleResize = () => { setIsMobile(window.innerWidth < 480); }; - window.addEventListener("resize", handleResize); return () => window.removeEventListener("resize", handleResize); }, []); @@ -92,24 +99,30 @@ const BalanceHistoryChart: React.FC = ({ if (type === "VESTS") { const vests = item.balance?.toString() || "0"; - - const hiveAmount = grabNumericValue( - convertVestsToHive( - hiveChain, - vests, - dynamicGlobalData.headBlockDetails.rawTotalVestingFundHive, - dynamicGlobalData.headBlockDetails.rawTotalVestingShares - ) + const convertedValue = grabNumericValue( + unit === "hp" + ? convertVestsToHP( + hiveChain, + vests, + dynamicGlobalData.headBlockDetails.rawTotalVestingFundHive, + dynamicGlobalData.headBlockDetails.rawTotalVestingShares + ) + : convertVestsToHive( + hiveChain, + vests, + dynamicGlobalData.headBlockDetails.rawTotalVestingFundHive, + dynamicGlobalData.headBlockDetails.rawTotalVestingShares + ) ); const dollarValueFull = - !isNaN(hiveAmount) && !isNaN(hivePrice) - ? hiveAmount * hivePrice + !isNaN(convertedValue) && !isNaN(hivePrice) + ? convertedValue * hivePrice : 0; return { ...item, - convertedHive: hiveAmount, + convertedHive: convertedValue, dollarValue: dollarValueFull, }; } @@ -120,23 +133,17 @@ const BalanceHistoryChart: React.FC = ({ ? item.balance * hivePrice : 0; - return { - ...item, - dollarValue, - }; + return { ...item, dollarValue }; } if (type === "HBD") { - return { - ...item, - dollarValue: !isNaN(item.balance) ? item.balance : 0, - }; + return { ...item, dollarValue: !isNaN(item.balance) ? item.balance : 0 }; } return item; }); }, - [dynamicGlobalData, hiveChain] + [dynamicGlobalData, hiveChain, unit] ); const dataMap: Record< @@ -162,20 +169,9 @@ const BalanceHistoryChart: React.FC = ({ setSelectedCoinType(coinType); }; - const displayData = useMemo(() => { - return dataMap[selectedCoinType]; - //eslint-disable-next-line react-hooks/exhaustive-deps - }, [selectedCoinType]); - - const CustomTooltip = ({ - active, - payload, - label, - }: { - active?: boolean; - payload?: any[]; - label?: string; - }) => { + const displayData = useMemo(() => dataMap[selectedCoinType], [selectedCoinType]); + + 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"; @@ -198,213 +194,128 @@ const BalanceHistoryChart: React.FC = ({ return (

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

-
-
+
+
{isPositiveChange ? ( - + ) : isZeroChange ? ( - + ) : ( - + )} - {` ${formatNumber(balanceChange, selectedCoinType === "VESTS")}`} + {` ${formatNumber(balanceChange, selectedCoinType === "VESTS" ? unit === "vests" : false)}`}
-
{`${t( - "common.balance" - )}: ${formatNumber( - actualBalance, - selectedCoinType === "VESTS" - )}`}
- +
{`${t("common.balance")}: ${formatNumber(actualBalance, selectedCoinType === "VESTS" ? unit === "vests" : false)}`}
{dollarValue ? (
- Dollar Value: $ - {formatNumber(dollarValue, false, selectedCoinType === "VESTS")} + Dollar Value: ${formatNumber(dollarValue, false, selectedCoinType === "VESTS")}
) : null}
- {showSavingsBalance === "yes" && - savingsBalance !== undefined && - selectedCoinType !== "VESTS" && ( -
-
- {isSavingsPositiveChange ? ( - - ) : isSavingsZeroChange ? ( - - ) : ( - - )} - {` ${formatNumber( - savingsBalanceChange, - selectedCoinType === "VESTS" - )}`} -
-
- {`${t("balanceHistoryChart.savingsBalance")}: ${formatNumber( - savingsBalance, - selectedCoinType === "VESTS" - )}`} -
+ {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)}`} +
+
+ )}
); }; - const renderCoinButtons = () => { - return availableCoins.map((coinType) => ( - - )); - }; - const getMinMax = ( - data: { - balance: number; - savings_balance?: number; - dollarValue?: number; - convertedHive?: number; - }[] - ): [number, number] => { - if (!data || data.length === 0) { - return [0, 1]; - } + )}>{coinType} + ))} + + {selectedCoinType === "VESTS" && ( +
+ + setUnit(checked ? "hp" : "vests")} /> + +
+ )} +
+ ); + + const getMinMax = (data: { balance: number; savings_balance?: number; dollarValue?: number; convertedHive?: number; }[]): [number, number] => { + if (!data || data.length === 0) return [0, 1]; let allValues: number[] = []; if (selectedCoinType === "VESTS") { - 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); } } const minValue = Math.min(...allValues); const maxValue = Math.max(...allValues); - return [minValue, maxValue]; }; const [fullDataMin, fullDataMax] = getMinMax(displayData); const [minValue, maxValue] = zoomedDomain || [fullDataMin, fullDataMax]; - const handleBrushAreaChange = (domain: { - startIndex?: number; - endIndex?: number; - }) => { - if ( - !domain || - domain.startIndex === undefined || - domain.endIndex === undefined - ) { - // Reset zoom if brush is cleared or start/end index is undefined + const handleBrushAreaChange = (domain: { startIndex?: number; endIndex?: number; }) => { + if (!domain || domain.startIndex === undefined || domain.endIndex === undefined) { setZoomedDomain([fullDataMin, fullDataMax]); return; } - - const { startIndex, endIndex } = domain; - const visibleData = (displayData || []).slice(startIndex, endIndex + 1); - + const visibleData = (displayData || []).slice(domain.startIndex, domain.endIndex + 1); if (visibleData.length > 0) { const [min, max] = getMinMax(visibleData); setZoomedDomain([min, max]); } }; - if (!displayData || !displayData.length) return; + 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" && unit === "hp" + ? 50 // slight nudge for HP numbers + : 30; // default margin + return (
- {quickView && ( -
- {renderCoinButtons()} -
- )} - - + {renderCoinButtons()} + @@ -426,13 +337,13 @@ const BalanceHistoryChart: React.FC = ({ tickCount={6} tickFormatter={(tick) => { if (selectedCoinType === "VESTS") { + if (unit === "hp") return `${formatNumber(tick, false, false)}`; const valueInK = tick / 1_000; return `${formatNumber(valueInK, true, false).split(".")[0]} K`; } return formatNumber(tick, false, false); }} /> - {isDualAxis && ( = ({ tickFormatter={(tick) => `$${Math.round(tick)}`} /> )} - } /> = ({ stroke={colorMap[selectedCoinType]} strokeWidth={2} activeDot={{ r: 6 }} - name={selectedCoinType} + name={selectedCoinType === "VESTS" && unit === "hp" ? "HP" : selectedCoinType} dot={false} hide={hiddenDataKeys.includes("balance")} /> - = ({ dot={false} hide={hiddenDataKeys.includes("dollarValue")} /> - {showSavingsBalance === "yes" && selectedCoinType !== "VESTS" && ( = ({ hide={hiddenDataKeys.includes("savings_balance")} /> )} - {!quickView && ( = ({ wrapperStyle={{ paddingTop: isMobile ? "20px" : "0px" }} onClick={(event) => { const dataKey = event.dataKey as string; - const isHidden = hiddenDataKeys.includes(dataKey as string); - if (isHidden) { - setHiddenDataKeys( - hiddenDataKeys.filter((key) => key !== dataKey) - ); - } else { - setHiddenDataKeys([...hiddenDataKeys, dataKey]); - } + const isHidden = hiddenDataKeys.includes(dataKey); + if (isHidden) setHiddenDataKeys(hiddenDataKeys.filter((key) => key !== dataKey)); + else setHiddenDataKeys([...hiddenDataKeys, dataKey]); }} /> -- GitLab From c7b2a8f92e942e35b8229468afbbf341672cf4fb Mon Sep 17 00:00:00 2001 From: Ghina Al Rashwani Date: Thu, 9 Oct 2025 22:30:45 +0300 Subject: [PATCH 2/2] fixing vests to hp conversion --- .../balanceHistory/BalanceHistoryChart.tsx | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/components/balanceHistory/BalanceHistoryChart.tsx b/components/balanceHistory/BalanceHistoryChart.tsx index 4b2e9a508..dd10214ac 100644 --- a/components/balanceHistory/BalanceHistoryChart.tsx +++ b/components/balanceHistory/BalanceHistoryChart.tsx @@ -99,21 +99,24 @@ const BalanceHistoryChart: React.FC = ({ if (type === "VESTS") { const vests = item.balance?.toString() || "0"; - const convertedValue = grabNumericValue( - unit === "hp" - ? convertVestsToHP( + + const convertedValue = unit === "hp" + ? parseFloat( + convertVestsToHP( hiveChain, vests, dynamicGlobalData.headBlockDetails.rawTotalVestingFundHive, dynamicGlobalData.headBlockDetails.rawTotalVestingShares ) - : convertVestsToHive( + ) + : parseFloat( + convertVestsToHive( hiveChain, vests, dynamicGlobalData.headBlockDetails.rawTotalVestingFundHive, dynamicGlobalData.headBlockDetails.rawTotalVestingShares ) - ); + ); const dollarValueFull = !isNaN(convertedValue) && !isNaN(hivePrice) @@ -171,6 +174,7 @@ const BalanceHistoryChart: React.FC = ({ const displayData = useMemo(() => dataMap[selectedCoinType], [selectedCoinType]); + // ---------------- Tooltip ---------------- const CustomTooltip = ({ active, payload, label }: { active?: boolean; payload?: any[]; label?: string; }) => { const { dir: tooltipDir } = useI18n(); if (quickView || !active || !payload || payload.length === 0) return null; @@ -234,6 +238,7 @@ const BalanceHistoryChart: React.FC = ({ ); }; + // ---------------- Coin toggle buttons ---------------- const renderCoinButtons = () => (
{availableCoins.map((coinType) => ( @@ -255,28 +260,27 @@ const BalanceHistoryChart: React.FC = ({
); - const getMinMax = (data: { balance: number; savings_balance?: number; dollarValue?: number; convertedHive?: number; }[]): [number, number] => { + // ---------------- Min/Max for Y-axis ---------------- + const getMinMax = (data: any[]): [number, number] => { if (!data || data.length === 0) return [0, 1]; let allValues: number[] = []; 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)); 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)); allValues = allValues.concat(dollarValues); - if (showSavingsBalance === "yes") { const savingsValues = data.map((item) => item.savings_balance).filter((v): v is number => typeof v === "number"); allValues = allValues.concat(savingsValues); } } - const minValue = Math.min(...allValues); - const maxValue = Math.max(...allValues); - return [minValue, maxValue]; + return [Math.min(...allValues), Math.max(...allValues)]; }; const [fullDataMin, fullDataMax] = getMinMax(displayData); @@ -303,8 +307,8 @@ const BalanceHistoryChart: React.FC = ({ const leftMargin = isMobile ? 10 : selectedCoinType === "VESTS" && unit === "hp" - ? 50 // slight nudge for HP numbers - : 30; // default margin + ? 50 + : 30; return (
@@ -356,7 +360,7 @@ const BalanceHistoryChart: React.FC = ({