diff --git a/client/src/ui/components/hyperstructures/ContributionSummary.tsx b/client/src/ui/components/hyperstructures/ContributionSummary.tsx index 71ef6a9cb..3bc4ae641 100644 --- a/client/src/ui/components/hyperstructures/ContributionSummary.tsx +++ b/client/src/ui/components/hyperstructures/ContributionSummary.tsx @@ -1,9 +1,10 @@ import { useContributions } from "@/hooks/helpers/useContributions"; import { useRealm } from "@/hooks/helpers/useRealm"; import { ResourceIcon } from "@/ui/elements/ResourceIcon"; -import { currencyIntlFormat, divideByPrecision, formatNumber } from "@/ui/utils/utils"; +import { SelectResource } from "@/ui/elements/SelectResource"; +import { copyPlayerAddressToClipboard, currencyIntlFormat, divideByPrecision, formatNumber } from "@/ui/utils/utils"; import { ContractAddress, ID, ResourcesIds } from "@bibliothecadao/eternum"; -import { useState } from "react"; +import { useMemo, useState } from "react"; export const ContributionSummary = ({ hyperstructureEntityId, @@ -15,6 +16,9 @@ export const ContributionSummary = ({ const { getContributions, getContributionsTotalPercentage } = useContributions(); const { getAddressName } = useRealm(); + const [showContributions, setShowContributions] = useState(false); + const [selectedResource, setSelectedResource] = useState(null); + type Resource = { amount: number; resourceId: number; @@ -36,25 +40,40 @@ export const ContributionSummary = ({ const resourceContributions: Record = Object.entries(groupedContributions).reduce( (acc, [playerAddress, resources]) => { - acc[playerAddress] = Object.entries(resources).map(([resourceType, amount]) => ({ - amount: Number(amount), - resourceId: Number(resourceType), - })); + acc[playerAddress] = Object.entries(resources) + .filter(([resourceType]) => (selectedResource ? Number(resourceType) === selectedResource : true)) + .map(([resourceType, amount]) => ({ + amount: Number(amount), + resourceId: Number(resourceType), + })); return acc; }, {} as Record, ); - const [showContributions, setShowContributions] = useState(false); - // Calculate percentages and sort contributors - const sortedContributors = Object.entries(groupedContributions) - .map(([playerAddress, resources]) => ({ - playerAddress, - resources, - percentage: getContributionsTotalPercentage(hyperstructureEntityId, resourceContributions[playerAddress]) * 100, - })) - .sort((a, b) => b.percentage - a.percentage); + const sortedContributors = useMemo( + () => + Object.entries(groupedContributions) + .map(([playerAddress, resources]) => ({ + playerAddress, + resources, + percentage: + getContributionsTotalPercentage(hyperstructureEntityId, resourceContributions[playerAddress]) * 100, + })) + .filter(({ resources }) => + selectedResource ? resources[selectedResource] > 0n : Object.values(resources).some((amount) => amount > 0n), + ) + .sort((a, b) => { + if (selectedResource) { + const amountA = a.resources[selectedResource] || 0n; + const amountB = b.resources[selectedResource] || 0n; + return amountA > amountB ? -1 : amountA < amountB ? 1 : 0; + } + return b.percentage - a.percentage; + }), + [groupedContributions, selectedResource], + ); return (
@@ -66,24 +85,38 @@ export const ContributionSummary = ({
{showContributions && ( -
- {sortedContributors.map(({ playerAddress, resources, percentage }) => ( -
-
-
{getAddressName(ContractAddress(playerAddress))}
-
{formatNumber(percentage, 2)}%
-
-
- {Object.entries(resources).map(([resourceType, amount]) => ( -
- - {currencyIntlFormat(divideByPrecision(Number(amount)))} + <> + setSelectedResource(resourceId)} /> +
+ {sortedContributors.map(({ playerAddress, resources, percentage }) => { + const addressName = getAddressName(ContractAddress(playerAddress)) || "Unknown"; + + return ( +
+
+
copyPlayerAddressToClipboard(ContractAddress(playerAddress), addressName, true)} + className="text-sm font-bold cursor-pointer hover:text-gold/50" + > + {addressName} +
+
{formatNumber(percentage, 2)}%
+
+
+ {Object.entries(resources) + .filter(([resourceType]) => (selectedResource ? Number(resourceType) === selectedResource : true)) + .map(([resourceType, amount]) => ( +
+ + {currencyIntlFormat(divideByPrecision(Number(amount)))} +
+ ))}
- ))} -
-
- ))} -
+
+ ); + })} +
+ )}
); diff --git a/client/src/ui/elements/SelectResource.tsx b/client/src/ui/elements/SelectResource.tsx index e551bf468..7d6b7c21c 100644 --- a/client/src/ui/elements/SelectResource.tsx +++ b/client/src/ui/elements/SelectResource.tsx @@ -76,7 +76,10 @@ export const SelectResource: React.FC = ({ onSelect, classN "my-auto w-8 mx-auto hover:fill-gold/50 fill-gold hover:scale-125 hover:animate-pulse duration-300 transition-all", { "pointer-events-none fill-gold/50": !selectedResource }, )} - onClick={() => setSelectedResource("")} + onClick={() => { + setSelectedResource(""); + onSelect(null); + }} />