From 03b898aa96bf0793a6fec9a310c6f9da791ac4f3 Mon Sep 17 00:00:00 2001 From: wolyshaw Date: Thu, 2 Apr 2026 15:04:34 +0800 Subject: [PATCH 1/5] Fix threshold curves chart current line --- .../approvalBubbleArea/index.jsx | 25 +++++++++++-------- .../useHistoryTallyValueData.js | 19 +++++++------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/packages/next-common/components/charts/thresholdCurve/referendaCurveChart/approvalBubbleArea/index.jsx b/packages/next-common/components/charts/thresholdCurve/referendaCurveChart/approvalBubbleArea/index.jsx index 96c27223f6..dbdad83b95 100644 --- a/packages/next-common/components/charts/thresholdCurve/referendaCurveChart/approvalBubbleArea/index.jsx +++ b/packages/next-common/components/charts/thresholdCurve/referendaCurveChart/approvalBubbleArea/index.jsx @@ -1,13 +1,11 @@ import { useMemo } from "react"; import { useReferendumActions } from "next-common/components/pages/components/gov2/sidebar/tally/voteActions/table"; -import { - useBeginHeight, - useBlockSteps, -} from "next-common/utils/hooks/referenda/detail/useReferendumBlocks"; +import { useBlockSteps } from "next-common/utils/hooks/referenda/detail/useReferendumBlocks"; import BubbleItem from "./bubbleItem"; import useShowVoteActions from "next-common/hooks/useShowVoteActions"; import { clamp, inRange, last } from "lodash-es"; import { cn } from "next-common/utils"; +import { useTimelineData } from "next-common/context/post"; export default function ApprovalBubbleArea(props) { const showVoteActions = useShowVoteActions(); @@ -17,10 +15,18 @@ export default function ApprovalBubbleArea(props) { return ; } +function useDecisionStartedIndexer() { + const timeline = useTimelineData(); + + return (timeline ?? []).find((item) => item.name === "DecisionStarted") + ?.indexer; +} + const useApprovalBubbleData = (rangeData, historyApprovalData) => { const labelXLength = rangeData[1] - rangeData[0]; - const beginHeight = useBeginHeight(); const blockStep = useBlockSteps(); + const decisionStarted = useDecisionStartedIndexer(); + const startedTime = decisionStarted?.blockTime; const { loading, voteActions } = useReferendumActions(); @@ -36,11 +42,11 @@ const useApprovalBubbleData = (rangeData, historyApprovalData) => { } }; return voteActions - .sort((a, b) => a.indexer.blockHeight - b.indexer.blockHeight) + .sort((a, b) => a.indexer.blockTime - b.indexer.blockTime) .map((item) => { const { data, type, who } = item; - const blockHeight = item.indexer.blockHeight; - const currentStep = (blockHeight - beginHeight) / blockStep; + const blockTime = item.indexer.blockTime; + const currentStep = (blockTime - startedTime) / (3600 * 1000); return { data, @@ -55,13 +61,12 @@ const useApprovalBubbleData = (rangeData, historyApprovalData) => { }; }); }, [ - beginHeight, - blockStep, historyApprovalData, loading, labelXLength, rangeData, voteActions, + startedTime, ]); }; diff --git a/packages/next-common/components/charts/thresholdCurve/useHistoryTallyValueData.js b/packages/next-common/components/charts/thresholdCurve/useHistoryTallyValueData.js index 59cf25a406..5ae8a87278 100644 --- a/packages/next-common/components/charts/thresholdCurve/useHistoryTallyValueData.js +++ b/packages/next-common/components/charts/thresholdCurve/useHistoryTallyValueData.js @@ -1,13 +1,11 @@ import { last } from "lodash-es"; import BigNumber from "bignumber.js"; -import { - useBeginHeight, - useBlockSteps, -} from "next-common/utils/hooks/referenda/detail/useReferendumBlocks"; +import { useBlockSteps } from "next-common/utils/hooks/referenda/detail/useReferendumBlocks"; import { useMemo } from "react"; import { useReferendaTallyHistory } from "next-common/store/reducers/referenda/thresholdCurves"; import { isEmpty } from "lodash-es"; -import useChainOrScanHeight from "next-common/hooks/height"; +import useAhmLatestHeight from "next-common/hooks/ahm/useAhmLatestheight"; +import { useDecidingSince } from "next-common/context/post/gov2/referendum"; function calcFromOneTallyData(tally) { const { ayes, nays, support, issuance } = tally; @@ -46,6 +44,7 @@ export function calcDataFromTallyHistory( const endHeight = Math.min(latestHeight, rangeEndHeight); let iterHeight = beginHeight; + while (iterHeight <= endHeight) { const tally = tallyHistory.findLast( @@ -70,18 +69,18 @@ export function calcDataFromTallyHistory( export default function useHistoryTallyValueData(totalHours) { const tallyHistory = useReferendaTallyHistory(); - const latestHeight = useChainOrScanHeight(); + const latestHeight = useAhmLatestHeight(); const blockStep = useBlockSteps(); - const beginHeight = useBeginHeight(); - const rangeEndHeight = beginHeight + blockStep * totalHours; + const decidingSince = useDecidingSince(); + const rangeEndHeight = decidingSince + blockStep * totalHours; return useMemo(() => { return calcDataFromTallyHistory( tallyHistory, - beginHeight, + decidingSince, latestHeight, blockStep, rangeEndHeight, ); - }, [tallyHistory, beginHeight, latestHeight, blockStep, rangeEndHeight]); + }, [tallyHistory, decidingSince, latestHeight, blockStep, rangeEndHeight]); } From e69c8675974a8af99956f52f4b68a7c16153de71 Mon Sep 17 00:00:00 2001 From: wolyshaw Date: Thu, 2 Apr 2026 15:08:41 +0800 Subject: [PATCH 2/5] unused --- .../referendaCurveChart/approvalBubbleArea/index.jsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/next-common/components/charts/thresholdCurve/referendaCurveChart/approvalBubbleArea/index.jsx b/packages/next-common/components/charts/thresholdCurve/referendaCurveChart/approvalBubbleArea/index.jsx index dbdad83b95..7b392dce4a 100644 --- a/packages/next-common/components/charts/thresholdCurve/referendaCurveChart/approvalBubbleArea/index.jsx +++ b/packages/next-common/components/charts/thresholdCurve/referendaCurveChart/approvalBubbleArea/index.jsx @@ -1,6 +1,5 @@ import { useMemo } from "react"; import { useReferendumActions } from "next-common/components/pages/components/gov2/sidebar/tally/voteActions/table"; -import { useBlockSteps } from "next-common/utils/hooks/referenda/detail/useReferendumBlocks"; import BubbleItem from "./bubbleItem"; import useShowVoteActions from "next-common/hooks/useShowVoteActions"; import { clamp, inRange, last } from "lodash-es"; @@ -24,7 +23,6 @@ function useDecisionStartedIndexer() { const useApprovalBubbleData = (rangeData, historyApprovalData) => { const labelXLength = rangeData[1] - rangeData[0]; - const blockStep = useBlockSteps(); const decisionStarted = useDecisionStartedIndexer(); const startedTime = decisionStarted?.blockTime; From f93191c8e939cfc60815b3f09baebf9da8f9e3ca Mon Sep 17 00:00:00 2001 From: wolyshaw Date: Thu, 2 Apr 2026 15:25:58 +0800 Subject: [PATCH 3/5] history by time --- .../thresholdCurve/hooks/useInnerPoints.js | 11 ++++- .../useHistoryTallyValueData.js | 46 +++++++++---------- .../detail/useDecisionStartedTime.js | 11 +++++ 3 files changed, 42 insertions(+), 26 deletions(-) create mode 100644 packages/next-common/utils/hooks/referenda/detail/useDecisionStartedTime.js diff --git a/packages/next-common/components/charts/thresholdCurve/hooks/useInnerPoints.js b/packages/next-common/components/charts/thresholdCurve/hooks/useInnerPoints.js index 015519b834..d3fd4d0306 100644 --- a/packages/next-common/components/charts/thresholdCurve/hooks/useInnerPoints.js +++ b/packages/next-common/components/charts/thresholdCurve/hooks/useInnerPoints.js @@ -15,6 +15,8 @@ import { useBlockSteps } from "next-common/utils/hooks/referenda/detail/useRefer import { useMemo } from "react"; import useChainOrScanHeight from "next-common/hooks/height"; import useReferendumCurveData from "next-common/utils/hooks/referenda/detail/useReferendumCurveData"; +import useLatestBlockTime from "next-common/utils/hooks/useBlockTime"; +import useDecisionStartedTime from "next-common/utils/hooks/referenda/detail/useDecisionStartedTime"; export default function useInnerPoints(labels) { const approvalThreshold = useApprovalThreshold(); @@ -42,13 +44,20 @@ export default function useInnerPoints(labels) { export function useCurrentHeightPoints() { const { supportData, approvalData, labels } = useReferendumCurveData(); const currentHeight = useChainOrScanHeight(); + const currentTime = useLatestBlockTime(); const steps = useBlockSteps(); const beginHeight = useBeginHeight(); + const startedTime = useDecisionStartedTime(); const xValue = useMemo(() => { + if (startedTime && currentTime) { + const index = Math.floor((currentTime - startedTime) / (3600 * 1000)); + return Math.min(index, labels.length - 1); + } + const index = Math.floor((currentHeight - beginHeight) / steps); return Math.min(index, labels.length - 1); - }, [beginHeight, currentHeight, labels.length, steps]); + }, [beginHeight, currentHeight, currentTime, labels.length, startedTime, steps]); const [, supportInnerPoint] = useSupportPoints( xValue, diff --git a/packages/next-common/components/charts/thresholdCurve/useHistoryTallyValueData.js b/packages/next-common/components/charts/thresholdCurve/useHistoryTallyValueData.js index 5ae8a87278..2a7cf53594 100644 --- a/packages/next-common/components/charts/thresholdCurve/useHistoryTallyValueData.js +++ b/packages/next-common/components/charts/thresholdCurve/useHistoryTallyValueData.js @@ -1,11 +1,12 @@ import { last } from "lodash-es"; import BigNumber from "bignumber.js"; -import { useBlockSteps } from "next-common/utils/hooks/referenda/detail/useReferendumBlocks"; import { useMemo } from "react"; import { useReferendaTallyHistory } from "next-common/store/reducers/referenda/thresholdCurves"; import { isEmpty } from "lodash-es"; -import useAhmLatestHeight from "next-common/hooks/ahm/useAhmLatestheight"; -import { useDecidingSince } from "next-common/context/post/gov2/referendum"; +import useLatestBlockTime from "next-common/utils/hooks/useBlockTime"; +import useDecisionStartedTime from "next-common/utils/hooks/referenda/detail/useDecisionStartedTime"; + +const oneHour = 3600 * 1000; function calcFromOneTallyData(tally) { const { ayes, nays, support, issuance } = tally; @@ -23,16 +24,15 @@ function calcFromOneTallyData(tally) { export function calcDataFromTallyHistory( tallyHistory, - beginHeight, - latestHeight, - blockStep, - rangeEndHeight, + startedTime, + latestTime, + rangeEndTime, ) { let historySupportData = []; let historyApprovalData = []; let historyAyesData = []; let historyNaysData = []; - if (!tallyHistory || !beginHeight || isEmpty(tallyHistory)) { + if (!tallyHistory || !startedTime || !latestTime || isEmpty(tallyHistory)) { return { historySupportData, historyApprovalData, @@ -41,22 +41,20 @@ export function calcDataFromTallyHistory( }; } - const endHeight = Math.min(latestHeight, rangeEndHeight); - - let iterHeight = beginHeight; + const endTime = Math.min(latestTime, rangeEndTime); - while (iterHeight <= endHeight) { + let iterTime = startedTime; + while (iterTime <= endTime) { const tally = - tallyHistory.findLast( - (tally) => tally.indexer.blockHeight <= iterHeight, - ) || last(tallyHistory); + tallyHistory.findLast((item) => item.indexer.blockTime <= iterTime) || + last(tallyHistory); let { currentSupport, currentApprove } = calcFromOneTallyData(tally.tally); historySupportData.push(currentSupport); historyApprovalData.push(currentApprove); historyAyesData.push(tally.tally.ayes); historyNaysData.push(tally.tally.nays); - iterHeight += blockStep; + iterTime += oneHour; } return { @@ -69,18 +67,16 @@ export function calcDataFromTallyHistory( export default function useHistoryTallyValueData(totalHours) { const tallyHistory = useReferendaTallyHistory(); - const latestHeight = useAhmLatestHeight(); - const blockStep = useBlockSteps(); - const decidingSince = useDecidingSince(); - const rangeEndHeight = decidingSince + blockStep * totalHours; + const latestTime = useLatestBlockTime(); + const startedTime = useDecisionStartedTime(); + const rangeEndTime = startedTime + totalHours * oneHour; return useMemo(() => { return calcDataFromTallyHistory( tallyHistory, - decidingSince, - latestHeight, - blockStep, - rangeEndHeight, + startedTime, + latestTime, + rangeEndTime, ); - }, [tallyHistory, decidingSince, latestHeight, blockStep, rangeEndHeight]); + }, [tallyHistory, startedTime, latestTime, rangeEndTime]); } diff --git a/packages/next-common/utils/hooks/referenda/detail/useDecisionStartedTime.js b/packages/next-common/utils/hooks/referenda/detail/useDecisionStartedTime.js new file mode 100644 index 0000000000..8b8876cfb9 --- /dev/null +++ b/packages/next-common/utils/hooks/referenda/detail/useDecisionStartedTime.js @@ -0,0 +1,11 @@ +import { useMemo } from "react"; +import { useTimelineData } from "next-common/context/post"; + +export default function useDecisionStartedTime() { + const timeline = useTimelineData(); + + return useMemo(() => { + return (timeline ?? []).find((item) => item.name === "DecisionStarted") + ?.indexer?.blockTime; + }, [timeline]); +} From f7718671145bc1cf67041826cd6268caace37be9 Mon Sep 17 00:00:00 2001 From: wolyshaw Date: Thu, 2 Apr 2026 15:33:02 +0800 Subject: [PATCH 4/5] improve --- .../referendaCurveChart/approvalBubbleArea/index.jsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/next-common/components/charts/thresholdCurve/referendaCurveChart/approvalBubbleArea/index.jsx b/packages/next-common/components/charts/thresholdCurve/referendaCurveChart/approvalBubbleArea/index.jsx index 7b392dce4a..c4013edbed 100644 --- a/packages/next-common/components/charts/thresholdCurve/referendaCurveChart/approvalBubbleArea/index.jsx +++ b/packages/next-common/components/charts/thresholdCurve/referendaCurveChart/approvalBubbleArea/index.jsx @@ -8,7 +8,11 @@ import { useTimelineData } from "next-common/context/post"; export default function ApprovalBubbleArea(props) { const showVoteActions = useShowVoteActions(); - if (!showVoteActions || !props.chartArea) { + if ( + !showVoteActions || + !props.chartArea || + !props.historyApprovalData?.length + ) { return null; } return ; From a7d9845059c2c7ad2dc1dc62da79d7eb98412b34 Mon Sep 17 00:00:00 2001 From: wolyshaw Date: Thu, 2 Apr 2026 16:10:52 +0800 Subject: [PATCH 5/5] add setting --- .../thresholdCurve/hooks/useInnerPoints.js | 15 +++- .../approvalBubbleArea/index.jsx | 23 ++++- .../useHistoryTallyValueData.js | 86 ++++++++++++++++++- 3 files changed, 115 insertions(+), 9 deletions(-) diff --git a/packages/next-common/components/charts/thresholdCurve/hooks/useInnerPoints.js b/packages/next-common/components/charts/thresholdCurve/hooks/useInnerPoints.js index d3fd4d0306..2f966b64c4 100644 --- a/packages/next-common/components/charts/thresholdCurve/hooks/useInnerPoints.js +++ b/packages/next-common/components/charts/thresholdCurve/hooks/useInnerPoints.js @@ -17,6 +17,7 @@ import useChainOrScanHeight from "next-common/hooks/height"; import useReferendumCurveData from "next-common/utils/hooks/referenda/detail/useReferendumCurveData"; import useLatestBlockTime from "next-common/utils/hooks/useBlockTime"; import useDecisionStartedTime from "next-common/utils/hooks/referenda/detail/useDecisionStartedTime"; +import { useChainSettings } from "next-common/context/chain"; export default function useInnerPoints(labels) { const approvalThreshold = useApprovalThreshold(); @@ -48,16 +49,26 @@ export function useCurrentHeightPoints() { const steps = useBlockSteps(); const beginHeight = useBeginHeight(); const startedTime = useDecisionStartedTime(); + const { assethubMigration } = useChainSettings(); + const useTimeAxis = assethubMigration?.migrated; const xValue = useMemo(() => { - if (startedTime && currentTime) { + if (useTimeAxis && startedTime && currentTime) { const index = Math.floor((currentTime - startedTime) / (3600 * 1000)); return Math.min(index, labels.length - 1); } const index = Math.floor((currentHeight - beginHeight) / steps); return Math.min(index, labels.length - 1); - }, [beginHeight, currentHeight, currentTime, labels.length, startedTime, steps]); + }, [ + useTimeAxis, + beginHeight, + currentHeight, + currentTime, + labels.length, + startedTime, + steps, + ]); const [, supportInnerPoint] = useSupportPoints( xValue, diff --git a/packages/next-common/components/charts/thresholdCurve/referendaCurveChart/approvalBubbleArea/index.jsx b/packages/next-common/components/charts/thresholdCurve/referendaCurveChart/approvalBubbleArea/index.jsx index c4013edbed..b74ab7a891 100644 --- a/packages/next-common/components/charts/thresholdCurve/referendaCurveChart/approvalBubbleArea/index.jsx +++ b/packages/next-common/components/charts/thresholdCurve/referendaCurveChart/approvalBubbleArea/index.jsx @@ -1,10 +1,15 @@ import { useMemo } from "react"; import { useReferendumActions } from "next-common/components/pages/components/gov2/sidebar/tally/voteActions/table"; +import { + useBeginHeight, + useBlockSteps, +} from "next-common/utils/hooks/referenda/detail/useReferendumBlocks"; import BubbleItem from "./bubbleItem"; import useShowVoteActions from "next-common/hooks/useShowVoteActions"; import { clamp, inRange, last } from "lodash-es"; import { cn } from "next-common/utils"; import { useTimelineData } from "next-common/context/post"; +import { useChainSettings } from "next-common/context/chain"; export default function ApprovalBubbleArea(props) { const showVoteActions = useShowVoteActions(); @@ -27,8 +32,12 @@ function useDecisionStartedIndexer() { const useApprovalBubbleData = (rangeData, historyApprovalData) => { const labelXLength = rangeData[1] - rangeData[0]; + const beginHeight = useBeginHeight(); + const blockStep = useBlockSteps(); const decisionStarted = useDecisionStartedIndexer(); const startedTime = decisionStarted?.blockTime; + const { assethubMigration } = useChainSettings(); + const useTimeAxis = assethubMigration?.migrated; const { loading, voteActions } = useReferendumActions(); @@ -44,11 +53,16 @@ const useApprovalBubbleData = (rangeData, historyApprovalData) => { } }; return voteActions - .sort((a, b) => a.indexer.blockTime - b.indexer.blockTime) + .sort((a, b) => + useTimeAxis + ? a.indexer.blockTime - b.indexer.blockTime + : a.indexer.blockHeight - b.indexer.blockHeight, + ) .map((item) => { const { data, type, who } = item; - const blockTime = item.indexer.blockTime; - const currentStep = (blockTime - startedTime) / (3600 * 1000); + const currentStep = useTimeAxis + ? (item.indexer.blockTime - startedTime) / (3600 * 1000) + : (item.indexer.blockHeight - beginHeight) / blockStep; return { data, @@ -69,6 +83,9 @@ const useApprovalBubbleData = (rangeData, historyApprovalData) => { rangeData, voteActions, startedTime, + beginHeight, + blockStep, + useTimeAxis, ]); }; diff --git a/packages/next-common/components/charts/thresholdCurve/useHistoryTallyValueData.js b/packages/next-common/components/charts/thresholdCurve/useHistoryTallyValueData.js index 2a7cf53594..a3397762ac 100644 --- a/packages/next-common/components/charts/thresholdCurve/useHistoryTallyValueData.js +++ b/packages/next-common/components/charts/thresholdCurve/useHistoryTallyValueData.js @@ -1,10 +1,16 @@ import { last } from "lodash-es"; import BigNumber from "bignumber.js"; +import { + useBeginHeight, + useBlockSteps, +} from "next-common/utils/hooks/referenda/detail/useReferendumBlocks"; import { useMemo } from "react"; import { useReferendaTallyHistory } from "next-common/store/reducers/referenda/thresholdCurves"; import { isEmpty } from "lodash-es"; import useLatestBlockTime from "next-common/utils/hooks/useBlockTime"; import useDecisionStartedTime from "next-common/utils/hooks/referenda/detail/useDecisionStartedTime"; +import useChainOrScanHeight from "next-common/hooks/height"; +import { useChainSettings } from "next-common/context/chain"; const oneHour = 3600 * 1000; @@ -23,6 +29,52 @@ function calcFromOneTallyData(tally) { } export function calcDataFromTallyHistory( + tallyHistory, + beginHeight, + latestHeight, + blockStep, + rangeEndHeight, +) { + let historySupportData = []; + let historyApprovalData = []; + let historyAyesData = []; + let historyNaysData = []; + if (!tallyHistory || !beginHeight || isEmpty(tallyHistory)) { + return { + historySupportData, + historyApprovalData, + historyAyesData, + historyNaysData, + }; + } + + const endHeight = Math.min(latestHeight, rangeEndHeight); + + let iterHeight = beginHeight; + while (iterHeight <= endHeight) { + const tally = + tallyHistory.findLast( + (tally) => tally.indexer.blockHeight <= iterHeight, + ) || + last(tallyHistory); + + let { currentSupport, currentApprove } = calcFromOneTallyData(tally.tally); + historySupportData.push(currentSupport); + historyApprovalData.push(currentApprove); + historyAyesData.push(tally.tally.ayes); + historyNaysData.push(tally.tally.nays); + iterHeight += blockStep; + } + + return { + historySupportData, + historyApprovalData, + historyAyesData, + historyNaysData, + }; +} + +export function calcDataFromTallyHistoryByTime( tallyHistory, startedTime, latestTime, @@ -67,16 +119,42 @@ export function calcDataFromTallyHistory( export default function useHistoryTallyValueData(totalHours) { const tallyHistory = useReferendaTallyHistory(); + const latestHeight = useChainOrScanHeight(); const latestTime = useLatestBlockTime(); + const blockStep = useBlockSteps(); + const beginHeight = useBeginHeight(); const startedTime = useDecisionStartedTime(); + const { assethubMigration } = useChainSettings(); + const useTimeAxis = assethubMigration?.migrated; + const rangeEndHeight = beginHeight + blockStep * totalHours; const rangeEndTime = startedTime + totalHours * oneHour; return useMemo(() => { + if (useTimeAxis) { + return calcDataFromTallyHistoryByTime( + tallyHistory, + startedTime, + latestTime, + rangeEndTime, + ); + } + return calcDataFromTallyHistory( tallyHistory, - startedTime, - latestTime, - rangeEndTime, + beginHeight, + latestHeight, + blockStep, + rangeEndHeight, ); - }, [tallyHistory, startedTime, latestTime, rangeEndTime]); + }, [ + useTimeAxis, + tallyHistory, + startedTime, + latestTime, + rangeEndTime, + beginHeight, + latestHeight, + blockStep, + rangeEndHeight, + ]); }