From 8fa9a9ab5bd50edcdb4fd7f1924bb65d3d19ac1a Mon Sep 17 00:00:00 2001 From: chaojun Date: Wed, 8 Jul 2026 15:50:17 +0800 Subject: [PATCH 1/2] Add statistics tab for multi asset bounties --- .../components/tabs/multiAssetBountiesDetailMultiTabs.js | 9 ++++++++- .../next/pages/treasury/multi-asset-bounties/[id].js | 3 +++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/next-common/components/pages/components/tabs/multiAssetBountiesDetailMultiTabs.js b/packages/next-common/components/pages/components/tabs/multiAssetBountiesDetailMultiTabs.js index fa3f68bf8a..bca2d0c224 100644 --- a/packages/next-common/components/pages/components/tabs/multiAssetBountiesDetailMultiTabs.js +++ b/packages/next-common/components/pages/components/tabs/multiAssetBountiesDetailMultiTabs.js @@ -7,6 +7,7 @@ import { usePageProps } from "next-common/context/page"; import useMultiAssetBountyTimelineData from "next-common/components/pages/components/multiAssetBounty/useMultiAssetBountyTimelineData"; import { useTimelineTabSwitch } from "next-common/hooks/useTabSwitch"; import tabsTooltipContentMap from "./tabsTooltipContentMap"; +import BountyStatistics from "next-common/components/pages/components/bounty/bountyStatistics"; const Metadata = dynamicClientOnly(() => import("next-common/components/treasury/multiAssetBounty/metadata"), @@ -23,7 +24,7 @@ const ChildBountiesTable = dynamicClientOnly(() => export default function MultiAssetBountiesDetailMultiTabs() { const router = useRouter(); const detail = usePost(); - const { childBounties } = usePageProps(); + const { childBounties, statistics } = usePageProps(); const timelineData = useMultiAssetBountyTimelineData(detail?.onchainData); const { component: timeLineTabSwitch, isCompact } = useTimelineTabSwitch(); @@ -64,6 +65,11 @@ export default function MultiAssetBountiesDetailMultiTabs() { ), }, + statistics && { + value: "statistics", + label: "Statistics", + content: , + }, ].filter(Boolean); const [defaultTab] = tabs; @@ -79,6 +85,7 @@ export default function MultiAssetBountiesDetailMultiTabs() { router.query.tab, timeLineTabSwitch, timelineData, + statistics, ]); function handleTabClick(tab) { diff --git a/packages/next/pages/treasury/multi-asset-bounties/[id].js b/packages/next/pages/treasury/multi-asset-bounties/[id].js index 5eaa5f81bd..7dbf5cd3f3 100644 --- a/packages/next/pages/treasury/multi-asset-bounties/[id].js +++ b/packages/next/pages/treasury/multi-asset-bounties/[id].js @@ -103,6 +103,7 @@ export const getServerSideProps = withCommonProps(async (context) => { { result: detail }, { result: childBounties }, { result: tracksDetail }, + { result: statistics }, ] = await Promise.all([ backendApi.fetch(`treasury/multi-asset-bounties/${id}`), backendApi.fetch( @@ -112,6 +113,7 @@ export const getServerSideProps = withCommonProps(async (context) => { }, ), backendApi.fetch(gov2TracksApi), + backendApi.fetch(`treasury/multi-asset-bounties/${id}/statistics`), ]); if (!detail) { @@ -130,6 +132,7 @@ export const getServerSideProps = withCommonProps(async (context) => { childBounties: childBounties ?? EmptyList, comments: comments ?? EmptyList, tracksDetail: tracksDetail ?? null, + statistics: statistics ?? null, ...tracksProps, }, }; From b60f45f669fb66251ec642261e05adf6e2d7f587 Mon Sep 17 00:00:00 2001 From: chaojun Date: Thu, 9 Jul 2026 11:39:38 +0800 Subject: [PATCH 2/2] fix: proposal popup --- .../proposalsPopup/content.jsx | 35 ++------- .../proposalsPopup/context.js | 72 +++++++++++++++++++ .../tabs/multiAssetBountiesDetailMultiTabs.js | 9 ++- .../tabs/treasuryBountiesDetailMultiTabs.js | 9 ++- 4 files changed, 92 insertions(+), 33 deletions(-) create mode 100644 packages/next-common/components/pages/components/bounty/bountyStatistics/proposalsPopup/context.js diff --git a/packages/next-common/components/pages/components/bounty/bountyStatistics/proposalsPopup/content.jsx b/packages/next-common/components/pages/components/bounty/bountyStatistics/proposalsPopup/content.jsx index 66ee734793..786f3ad293 100644 --- a/packages/next-common/components/pages/components/bounty/bountyStatistics/proposalsPopup/content.jsx +++ b/packages/next-common/components/pages/components/bounty/bountyStatistics/proposalsPopup/content.jsx @@ -4,13 +4,12 @@ import SummaryLayout from "next-common/components/summary/layout/layout"; import SummaryItem from "next-common/components/summary/layout/item"; import Link from "next-common/components/link"; import { cn } from "next-common/utils"; -import normalizeChildBountyListItem from "next-common/utils/viewfuncs/treasury/normalizeChildBountyListItem"; import { childBountyColumnsDef } from "./columns"; import { useAsync } from "react-use"; -import { backendApi } from "next-common/services/nextApi"; import ItemsList from "./itemsList"; import { usePost } from "next-common/context/post"; import { AddressUser } from "next-common/components/user"; +import { useChildBountiesFetcher } from "./context"; export function PostTitle({ url, index, title, noLink, className }) { return ( @@ -30,38 +29,12 @@ export function PostTitle({ url, index, title, noLink, className }) { export default function PopupContent({ data, proposalOwner, role }) { const post = usePost(); const parentBountyId = post.bountyIndex; + const fetchChildBounties = useChildBountiesFetcher(); const { value: childBounties, loading: childBountiesLoading } = useAsync(async () => { - if (!data?.childBounties?.length) { - return []; - } - const { result } = await backendApi.fetch( - "treasury/child-bounties?simple=true&" + - data.childBounties - .map( - (item) => - "ids=" + `${parentBountyId}_${item.index}_${item.blockHeight}`, - ) - .join("&"), - ); - if (!result) { - return []; - } - return result.map((item) => { - const payout = - data?.childBounties?.find((payout) => payout.index === item.index) || - {}; - const normalizedChildBounty = normalizeChildBountyListItem( - process.env.NEXT_PUBLIC_CHAIN, - item, - ); - return { - ...normalizedChildBounty, - ...payout, - }; - }); - }, [data, parentBountyId]); + return fetchChildBounties(data, parentBountyId); + }, [data, parentBountyId, fetchChildBounties]); return ( <> diff --git a/packages/next-common/components/pages/components/bounty/bountyStatistics/proposalsPopup/context.js b/packages/next-common/components/pages/components/bounty/bountyStatistics/proposalsPopup/context.js new file mode 100644 index 0000000000..4df56de899 --- /dev/null +++ b/packages/next-common/components/pages/components/bounty/bountyStatistics/proposalsPopup/context.js @@ -0,0 +1,72 @@ +import { createContext, useContext } from "react"; +import { backendApi } from "next-common/services/nextApi"; +import normalizeChildBountyListItem from "next-common/utils/viewfuncs/treasury/normalizeChildBountyListItem"; +import normalizeMultiAssetChildBountyListItem from "next-common/utils/viewfuncs/treasury/normalizeMultiAssetChildBountyListItem"; + +export async function fetchBountyChildBounties(data, parentBountyId) { + if (!data?.childBounties?.length) { + return []; + } + const { result } = await backendApi.fetch( + "treasury/child-bounties?simple=true&" + + data.childBounties + .map( + (item) => + "ids=" + `${parentBountyId}_${item.index}_${item.blockHeight}`, + ) + .join("&"), + ); + if (!result) { + return []; + } + return result.map((item) => { + const payout = + data?.childBounties?.find((payout) => payout.index === item.index) || {}; + const normalizedChildBounty = normalizeChildBountyListItem( + process.env.NEXT_PUBLIC_CHAIN, + item, + ); + return { + ...normalizedChildBounty, + ...payout, + }; + }); +} + +export async function fetchMultiAssetChildBounties(data, parentBountyId) { + if (!data?.childBounties?.length) { + return []; + } + const { result } = await backendApi.fetch( + "treasury/multi-asset-child-bounties?simple=true&" + + data.childBounties + .map( + (item) => + "ids=" + `${parentBountyId}_${item.index}_${item.blockHeight}`, + ) + .join("&"), + ); + if (!result) { + return []; + } + return result.map((item) => { + const payout = + data?.childBounties?.find((payout) => payout.index === item.index) || {}; + const normalizedChildBounty = normalizeMultiAssetChildBountyListItem( + process.env.NEXT_PUBLIC_CHAIN, + item, + ); + return { + ...normalizedChildBounty, + ...payout, + }; + }); +} + +const ChildBountiesContext = createContext(fetchBountyChildBounties); + +export function useChildBountiesFetcher() { + return useContext(ChildBountiesContext); +} + +export default ChildBountiesContext; diff --git a/packages/next-common/components/pages/components/tabs/multiAssetBountiesDetailMultiTabs.js b/packages/next-common/components/pages/components/tabs/multiAssetBountiesDetailMultiTabs.js index bca2d0c224..9eab770eea 100644 --- a/packages/next-common/components/pages/components/tabs/multiAssetBountiesDetailMultiTabs.js +++ b/packages/next-common/components/pages/components/tabs/multiAssetBountiesDetailMultiTabs.js @@ -8,6 +8,9 @@ import useMultiAssetBountyTimelineData from "next-common/components/pages/compon import { useTimelineTabSwitch } from "next-common/hooks/useTabSwitch"; import tabsTooltipContentMap from "./tabsTooltipContentMap"; import BountyStatistics from "next-common/components/pages/components/bounty/bountyStatistics"; +import ChildBountiesContext, { + fetchMultiAssetChildBounties, +} from "next-common/components/pages/components/bounty/bountyStatistics/proposalsPopup/context"; const Metadata = dynamicClientOnly(() => import("next-common/components/treasury/multiAssetBounty/metadata"), @@ -68,7 +71,11 @@ export default function MultiAssetBountiesDetailMultiTabs() { statistics && { value: "statistics", label: "Statistics", - content: , + content: ( + + + + ), }, ].filter(Boolean); diff --git a/packages/next-common/components/pages/components/tabs/treasuryBountiesDetailMultiTabs.js b/packages/next-common/components/pages/components/tabs/treasuryBountiesDetailMultiTabs.js index 81088353da..2628ec46f9 100644 --- a/packages/next-common/components/pages/components/tabs/treasuryBountiesDetailMultiTabs.js +++ b/packages/next-common/components/pages/components/tabs/treasuryBountiesDetailMultiTabs.js @@ -8,6 +8,9 @@ import useBountyTimelineData from "next-common/components/pages/components/bount import { useTimelineTabSwitch } from "next-common/hooks/useTabSwitch"; import tabsTooltipContentMap from "./tabsTooltipContentMap"; import BountyStatistics from "next-common/components/pages/components/bounty/bountyStatistics"; +import ChildBountiesContext, { + fetchBountyChildBounties, +} from "next-common/components/pages/components/bounty/bountyStatistics/proposalsPopup/context"; const Metadata = dynamicClientOnly(() => import("next-common/components/treasury/bounty/metadata"), @@ -63,7 +66,11 @@ export default function TreasuryBountiesDetailMultiTabs() { statistics && { value: "statistics", label: "Statistics", - content: , + content: ( + + + + ), }, ].filter(Boolean); const [defaultTab] = tabs;