9aed938c79
* Add pending events to stake table * Add additional tanstack refetch on user stake/unstake/redeem rewards * refactor repeated fetch functions * clean up fetching functions * refactor & clean up * Add epoch waiting message on epoch change delay * fine tune epoch change * clean up * refactor imports * Add transaction hash to successful redeem rewards InfoModal * fix epoch time check and mobile header * Fix Loading modal width on mobile * fix epoch logic * clean up * clean up logs * add waiting for epoch to start to landing page * clean up * Add refetch of all queries on epoch change * Finalise state change on epoch change * clean up * fix build * Fix NodesTable mobile view * Fix stake table mobile view * fix typo * Fix blog articles height * Add loading skeletons to landing page cards * clean up * Add skeletons to cards * Add skeletons, and loading/error refetch on wallet balnce * clean up * Add active stakers card * clean up * change NGM to mixnet * Add TVL to Tokenomics card * Add last total stake to Stake Card * clean up * Fix stake sorting function in Stake Table * Add wrap of identity key and address to Basic Info Card * Add counter to epoch time on staking page * clean up * update epoch labels * Add circular loading on Toggle Button * Update Toggle button loading functionality * Add skeletons to account cards * Add search functionality on Enter * clean up * DOMpurify node name and description * Add column with id and identity key, wrap names to 2 lines * Set width of column headers to 110px * fix pending events for delegations * Fix Stake button proppagation * Add full country name to tooltips * Take out connect wallet from mobile menu toggle * finetune epoch change intervals * Add error text to Magic Search * fix build * Add react-markdown for Blog articles * fix graph's width and Table column headings * fix Magic Search loading * Fix grid on account page * fix account card address width * Fix permanent loading spinner on ToggleButton * clean up URL's, fix copy address on the Basic Card * replace mintscan with ping, open tx link on new page * Take out toggle button if no node bonded by address * Set fixed column width on tables * Add not-found page to account, when no node bonded * Add full country name to tables and node profile card * clean up * Table fixes * Fix sorting in Delegations table Node page * clean up * Fix line chart view * refactor epoch progress bar * remove unused imports * remove tanstack delclaration module * create epoch data provider * remove logic from togglebutton component * use epoch provider in components * invalidateQueries should be awaited * tidy up QualityIndicatorsCard component formatting * fix infinite loop in epoch provider --------- Co-authored-by: Yana <yanok87@users.noreply.github.com> Co-authored-by: fmtabbara <fmtabbara@hotmail.co.uk>
174 lines
5.0 KiB
TypeScript
174 lines
5.0 KiB
TypeScript
"use client";
|
|
|
|
import { useChain } from "@cosmos-kit/react";
|
|
import { Button, Stack } from "@mui/material";
|
|
import type { Delegation } from "@nymproject/contract-clients/Mixnet.types";
|
|
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
import { useCallback, useState } from "react";
|
|
import { fetchTotalStakerRewards } from "../../app/api";
|
|
import type { NodeRewardDetails } from "../../app/api/types";
|
|
import { COSMOS_KIT_USE_CHAIN, NYM_MIXNET_CONTRACT } from "../../config";
|
|
import { useNymClient } from "../../hooks/useNymClient";
|
|
import Loading from "../loading";
|
|
import InfoModal, { type InfoModalProps } from "../modal/InfoModal";
|
|
import RedeemRewardsModal from "../redeemRewards/RedeemRewardsModal";
|
|
|
|
const fee = { gas: "1000000", amount: [{ amount: "1000000", denom: "unym" }] };
|
|
|
|
// Fetch delegations
|
|
const fetchDelegations = async (
|
|
address: string,
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
nymClient: any,
|
|
): Promise<Delegation[]> => {
|
|
const data = await nymClient.getDelegatorDelegations({ delegator: address });
|
|
return data.delegations;
|
|
};
|
|
|
|
const SubHeaderRowActions = () => {
|
|
const [openRedeemRewardsModal, setOpenRedeemRewardsModal] =
|
|
useState<boolean>(false);
|
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
|
const [infoModalProps, setInfoModalProps] = useState<InfoModalProps>({
|
|
open: false,
|
|
});
|
|
|
|
const { address, nymClient } = useNymClient();
|
|
const { getSigningCosmWasmClient } = useChain(COSMOS_KIT_USE_CHAIN);
|
|
|
|
const queryClient = useQueryClient();
|
|
|
|
// Fetch delegations using React Query
|
|
const {
|
|
data: delegations = [],
|
|
isLoading: isDelegationsLoading,
|
|
isError: isDelegationsError,
|
|
} = useQuery({
|
|
queryKey: ["delegations", address],
|
|
queryFn: () => fetchDelegations(address || "", nymClient),
|
|
enabled: !!address && !!nymClient, // Only fetch if address and nymClient are available
|
|
});
|
|
|
|
// Fetch total rewards using React Query
|
|
const {
|
|
data: totalStakerRewards = 0,
|
|
isLoading: isRewardsLoading,
|
|
isError: isRewardsError,
|
|
refetch,
|
|
} = useQuery({
|
|
queryKey: ["totalStakerRewards", address],
|
|
queryFn: () => fetchTotalStakerRewards(address || ""),
|
|
enabled: !!address, // Only fetch if address is available
|
|
});
|
|
|
|
const handleRefetch = useCallback(async () => {
|
|
refetch();
|
|
queryClient.invalidateQueries(); // This will refetch ALL active queries
|
|
}, [queryClient, refetch]);
|
|
|
|
const handleRedeemRewards = useCallback(async () => {
|
|
setIsLoading(true);
|
|
setOpenRedeemRewardsModal(false);
|
|
|
|
try {
|
|
if (!nymClient || !address || !delegations.length) {
|
|
throw new Error("Wallet, client, or delegations not available.");
|
|
}
|
|
|
|
const messages = delegations.map((delegation: NodeRewardDetails) => ({
|
|
contractAddress: NYM_MIXNET_CONTRACT,
|
|
funds: [],
|
|
msg: {
|
|
withdraw_delegator_reward: {
|
|
node_id: delegation.node_id,
|
|
},
|
|
},
|
|
}));
|
|
|
|
const cosmWasmSigningClient = await getSigningCosmWasmClient();
|
|
|
|
const result = await cosmWasmSigningClient.executeMultiple(
|
|
address,
|
|
messages,
|
|
fee,
|
|
"Redeeming all rewards",
|
|
);
|
|
// Success state
|
|
setIsLoading(false);
|
|
setInfoModalProps({
|
|
open: true,
|
|
title: "Success",
|
|
message: "All rewards have been redeemed successfully!",
|
|
tx: result?.transactionHash,
|
|
|
|
onClose: async () => {
|
|
await handleRefetch();
|
|
setInfoModalProps({ open: false });
|
|
},
|
|
});
|
|
} catch (error) {
|
|
console.error("Error redeeming rewards:", error);
|
|
setInfoModalProps({
|
|
open: true,
|
|
title: "Error",
|
|
message:
|
|
error instanceof Error ? error.message : "Failed to redeem rewards.",
|
|
onClose: () => setInfoModalProps({ open: false }),
|
|
});
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
}, [
|
|
address,
|
|
nymClient,
|
|
delegations,
|
|
getSigningCosmWasmClient,
|
|
handleRefetch,
|
|
]);
|
|
|
|
const handleRedeemRewardsButtonClick = () => {
|
|
setOpenRedeemRewardsModal(true);
|
|
};
|
|
|
|
if (!address || !nymClient) {
|
|
return null;
|
|
}
|
|
|
|
if (isDelegationsLoading || isRewardsLoading) {
|
|
return <Loading />;
|
|
}
|
|
|
|
if (isDelegationsError || isRewardsError) {
|
|
return (
|
|
<Stack direction="row" spacing={3} justifyContent={"end"}>
|
|
<Button variant="contained" disabled>
|
|
Error loading data
|
|
</Button>
|
|
</Stack>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Stack direction="row" spacing={3} justifyContent={"end"}>
|
|
<Button
|
|
variant="contained"
|
|
onClick={handleRedeemRewardsButtonClick}
|
|
disabled={totalStakerRewards === 0}
|
|
>
|
|
Redeem NYM
|
|
</Button>
|
|
{isLoading && <Loading />}
|
|
{openRedeemRewardsModal && (
|
|
<RedeemRewardsModal
|
|
onRedeem={handleRedeemRewards}
|
|
onClose={() => setOpenRedeemRewardsModal(false)}
|
|
totalRewardsAmount={totalStakerRewards}
|
|
/>
|
|
)}
|
|
<InfoModal {...infoModalProps} />
|
|
</Stack>
|
|
);
|
|
};
|
|
|
|
export default SubHeaderRowActions;
|