Skip to content

feat: add staked amount in view project details page #3816

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ import {
ProjectLogo,
StakingBannerAndModal,
} from "./components";

import { useGetApplicationStakes } from "./hooks/useGetApplicationStakes";
import { useIsStakable } from "./components/StakingBannerAndModal/hooks/useIsStakable";
export default function ViewProjectDetails() {
const [selectedTab, setSelectedTab] = useState(0);

Expand All @@ -58,6 +59,11 @@ export default function ViewProjectDetails() {
applicationId = paramApplicationId;
}

const isStakableRound = useIsStakable({
chainId: Number(chainId),
roundId,
});

const {
data: application,
error,
Expand All @@ -70,6 +76,13 @@ export default function ViewProjectDetails() {
},
dataLayer
);
const { data: totalStaked } = useGetApplicationStakes(
Number(chainId),
Number(roundId),
application?.anchorAddress ?? "",
isStakableRound
);

const { round: roundDetails } = useRoundById(Number(chainId), roundId);

const projectToRender = application && mapApplicationToProject(application);
Expand Down Expand Up @@ -218,12 +231,15 @@ export default function ViewProjectDetails() {
</div>
)}
</div>
<div className="mb-4">
<div className="mb-4 relative">
<ProjectBanner
bannerImgCid={bannerImg ?? null}
classNameOverride="h-32 w-full object-cover lg:h-80 rounded md:rounded-3xl"
resizeHeight={320}
/>
{totalStaked && Number(totalStaked) > 0 && (
<StakedAmountCard totalStaked={Number(totalStaked)} />
)}
<div className="pl-4 sm:pl-6 lg:pl-8">
<div className="sm:flex sm:items-end sm:space-x-5">
<div className="flex">
Expand Down Expand Up @@ -275,3 +291,40 @@ export default function ViewProjectDetails() {
</>
);
}

const StakedAmountCard = ({ totalStaked }: { totalStaked: number }) => {
return (
<div className="p-2 bg-white/80 rounded-2xl backdrop-blur-sm inline-flex justify-start items-center gap-2 absolute top-4 right-4">
<div data-svg-wrapper className="relative">
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M10.8334 8.33333V2.5L3.33337 11.6667H9.16671L9.16671 17.5L16.6667 8.33333L10.8334 8.33333Z"
stroke="#7D67EB"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</div>
<div className="inline-flex flex-col justify-start items-start">
<div className="self-stretch inline-flex justify-start items-center gap-1">
<div className="justify-start text-text-primary text-lg font-medium font-['DM_Mono'] leading-normal">
{totalStaked}
</div>
<div className="justify-start text-text-primary text-lg font-medium font-['DM_Mono'] leading-normal">
GTC
</div>
</div>
<div className="self-stretch justify-start text-text-primary text-sm font-normal font-['DM_Mono'] leading-[14px]">
Total staked
</div>
</div>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { useQuery } from "@tanstack/react-query";
import { gql } from "graphql-request";

const endpoint = "https://indexer.hyperindex.xyz/98cb471/v1/graphql";

const getStakesQuery = gql`
query getStakes($chainId: numeric!, $poolId: numeric!, $recipient: String!) {
TokenLock_Locked(
where: {
chainId: { _eq: $chainId }
poolId: { _eq: $poolId }
recipient: { _eq: $recipient }
}
) {
amount
chainId
poolId
recipient
sender
}
}
`;

export const useGetApplicationStakes = (
chainId: number,
poolId: number,
recipient: string,
isStakableRound: boolean
) => {
const query = useQuery({
enabled: isStakableRound,
queryKey: ["getApplicationStakes", chainId, poolId, recipient],
queryFn: () => getApplicationStakes(chainId, poolId, recipient),
});

return {
data: query.data,
isLoading: query.isLoading,
isError: query.isError,
error: query.error,
refetch: query.refetch,
};
};

const GET = async (chainId: number, poolId: number, recipient: string) => {
const response = await fetch(endpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
query: getStakesQuery,
variables: { chainId, poolId, recipient },
}),
});

if (!response.ok) {
const errorData = await response.json();
throw new Error(
`Error: ${response.status} - ${errorData.message || "Unknown error"}`
);
}

return response.json();
};

interface ApplicationStake {
amount: string;
chainId: string;
poolId: string;
recipient: string;
sender: string;
}

export async function getApplicationStakes(
chainId: number,
poolId: number,
recipient: string
): Promise<string> {
try {
const response = (await GET(chainId, poolId, recipient)).data
.TokenLock_Locked as ApplicationStake[];
const totalStakes = response.reduce(
(acc, stake) => acc + Number(stake.amount),
0
);

return (totalStakes / 10 ** 18).toFixed(3);
} catch (error) {
console.error("Error fetching pool info and stakes:", error);
throw error;
}
}