Yana/pending staking events (#5400)
* 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>
This commit is contained in:
@@ -1,9 +1,14 @@
|
||||
"use client";
|
||||
|
||||
import { COSMOS_KIT_USE_CHAIN } from "@/config";
|
||||
import { useNymClient } from "@/hooks/useNymClient";
|
||||
import { useChain } from "@cosmos-kit/react";
|
||||
import { Box, Button, Stack, Tooltip, Typography } from "@mui/material";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Stack,
|
||||
Typography,
|
||||
useMediaQuery,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { useLocalStorage } from "@uidotdev/usehooks";
|
||||
import {
|
||||
type MRT_ColumnDef,
|
||||
@@ -12,9 +17,13 @@ import {
|
||||
} from "material-react-table";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
|
||||
import { COSMOS_KIT_USE_CHAIN } from "../../config";
|
||||
import { useNymClient } from "../../hooks/useNymClient";
|
||||
import CountryFlag from "../countryFlag/CountryFlag";
|
||||
import { Favorite } from "../favorite/Favorite";
|
||||
import Loading from "../loading";
|
||||
// import Loading from "../loading";
|
||||
import InfoModal, { type InfoModalProps } from "../modal/InfoModal";
|
||||
import StakeModal from "../staking/StakeModal";
|
||||
import { fee } from "../staking/schemas";
|
||||
@@ -26,16 +35,42 @@ const ColumnHeading = ({
|
||||
}: {
|
||||
children: string | React.ReactNode;
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
|
||||
return (
|
||||
<Typography sx={{ py: 2, textAlign: "center" }} variant="h5">
|
||||
{children}
|
||||
</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
width: isMobile ? "80px" : "unset",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "flex-start",
|
||||
alignItems: "baseline",
|
||||
p: 0,
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
py: 2,
|
||||
textAlign: "center",
|
||||
whiteSpace: isMobile ? "normal" : "unset", // Ensure text can wrap
|
||||
wordWrap: isMobile ? "break-word" : "unset", // Break long words
|
||||
overflowWrap: isMobile ? "break-word" : "unset", // Ensure text breaks inside the cell
|
||||
textTransform: "uppercase",
|
||||
}}
|
||||
variant={isMobile ? "caption" : "h5"}
|
||||
>
|
||||
{children}
|
||||
</Typography>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
const NodeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
|
||||
const router = useRouter();
|
||||
const { nymClient } = useNymClient();
|
||||
const queryClient = useQueryClient();
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
|
||||
|
||||
const [infoModalProps, setInfoModalProps] = useState<InfoModalProps>({
|
||||
open: false,
|
||||
@@ -48,6 +83,10 @@ const NodeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
|
||||
const [favorites] = useLocalStorage<string[]>("nym-node-favorites", []);
|
||||
const { isWalletConnected } = useChain(COSMOS_KIT_USE_CHAIN);
|
||||
|
||||
const handleRefetch = useCallback(async () => {
|
||||
await queryClient.invalidateQueries();
|
||||
}, [queryClient]);
|
||||
|
||||
const handleStakeOnNode = useCallback(
|
||||
async ({ nodeId, amount }: { nodeId: number; amount: string }) => {
|
||||
const amountToDelegate = (Number(amount) * 1_000_000).toString();
|
||||
@@ -69,8 +108,12 @@ const NodeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
|
||||
message: "This operation can take up to one hour to process",
|
||||
tx: tx?.transactionHash,
|
||||
|
||||
onClose: () => setInfoModalProps({ open: false }),
|
||||
onClose: async () => {
|
||||
await handleRefetch();
|
||||
setInfoModalProps({ open: false });
|
||||
},
|
||||
});
|
||||
await handleRefetch();
|
||||
} catch (e) {
|
||||
const errorMessage =
|
||||
e instanceof Error ? e.message : "An error occurred while staking";
|
||||
@@ -85,7 +128,7 @@ const NodeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
|
||||
}
|
||||
setIsLoading(false);
|
||||
},
|
||||
[nymClient],
|
||||
[nymClient, handleRefetch],
|
||||
);
|
||||
|
||||
const handleOnSelectStake = useCallback(
|
||||
@@ -116,6 +159,12 @@ const NodeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
|
||||
},
|
||||
[isWalletConnected],
|
||||
);
|
||||
// get full country name
|
||||
const countryName = useCallback((countryCode: string) => {
|
||||
const regionNames = new Intl.DisplayNames(["en"], { type: "region" });
|
||||
|
||||
return <span>{regionNames.of(countryCode)}</span>;
|
||||
}, []);
|
||||
|
||||
const columns: MRT_ColumnDef<MappedNymNode>[] = useMemo(
|
||||
() => [
|
||||
@@ -131,23 +180,36 @@ const NodeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "node",
|
||||
id: "id",
|
||||
header: "",
|
||||
Header: <ColumnHeading>Node</ColumnHeading>,
|
||||
accessorKey: "identity_key",
|
||||
Header: <ColumnHeading>Node ID</ColumnHeading>,
|
||||
accessorKey: "nodeId",
|
||||
size: 90,
|
||||
Cell: ({ row }) => (
|
||||
<Stack spacing={1}>
|
||||
<Typography variant="body4">{row.original.nodeId}</Typography>
|
||||
</Stack>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "identity_key",
|
||||
header: "",
|
||||
Header: <ColumnHeading>Identity Key</ColumnHeading>,
|
||||
accessorKey: "identity_key",
|
||||
Cell: ({ row }) => (
|
||||
<Stack spacing={1}>
|
||||
<Typography variant="body5">{row.original.identity_key}</Typography>
|
||||
</Stack>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: "qos",
|
||||
header: "Quality of Service",
|
||||
header: "Qlt of Service",
|
||||
align: "center",
|
||||
accessorKey: "qualityOfService",
|
||||
Header: <ColumnHeading>Quality of Service</ColumnHeading>,
|
||||
size: 100,
|
||||
|
||||
Header: <ColumnHeading>Qlt of Service</ColumnHeading>,
|
||||
Cell: ({ row }) => (
|
||||
<Typography variant="body4">
|
||||
{row.original.qualityOfService}%
|
||||
@@ -158,17 +220,16 @@ const NodeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
|
||||
id: "location",
|
||||
header: "Location",
|
||||
accessorKey: "countryName",
|
||||
size: 160,
|
||||
Header: <ColumnHeading>Location</ColumnHeading>,
|
||||
Cell: ({ row }) =>
|
||||
row.original.countryCode && row.original.countryName ? (
|
||||
<Tooltip title={row.original.countryName}>
|
||||
<Box>
|
||||
<CountryFlag
|
||||
countryCode={row.original.countryCode || ""}
|
||||
countryName={row.original.countryCode || ""}
|
||||
/>
|
||||
</Box>
|
||||
</Tooltip>
|
||||
<Box width="100%">
|
||||
<CountryFlag
|
||||
countryCode={row.original.countryCode || ""}
|
||||
countryName={countryName(row.original.countryName) || ""}
|
||||
/>
|
||||
</Box>
|
||||
) : (
|
||||
"-"
|
||||
),
|
||||
@@ -199,6 +260,8 @@ const NodeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
|
||||
id: "Action",
|
||||
header: "Action",
|
||||
accessorKey: "Action",
|
||||
size: 120,
|
||||
|
||||
Header: <ColumnHeading>Action</ColumnHeading>,
|
||||
hidden: !isWalletConnected,
|
||||
enableColumnFilter: false,
|
||||
@@ -221,6 +284,8 @@ const NodeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
|
||||
enableColumnFilter: false,
|
||||
header: "Favorite",
|
||||
accessorKey: "Favorite",
|
||||
size: 110,
|
||||
|
||||
Header: (
|
||||
<Stack direction="row" alignItems="center">
|
||||
<ColumnHeading>Favorite</ColumnHeading>
|
||||
@@ -241,7 +306,7 @@ const NodeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
|
||||
Cell: ({ row }) => <Favorite address={row.original.owner} />,
|
||||
},
|
||||
],
|
||||
[isWalletConnected, handleOnSelectStake, favorites],
|
||||
[isWalletConnected, handleOnSelectStake, favorites, countryName],
|
||||
);
|
||||
const table = useMaterialReactTable({
|
||||
columns,
|
||||
@@ -264,7 +329,7 @@ const NodeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
|
||||
shape: "circular",
|
||||
},
|
||||
initialState: {
|
||||
columnPinning: { right: ["Action", "Favorite"] },
|
||||
columnPinning: isMobile ? {} : { right: ["Action", "Favorite"] }, // No pinning on mobile
|
||||
},
|
||||
muiColumnActionsButtonProps: {
|
||||
sx: {
|
||||
@@ -280,9 +345,17 @@ const NodeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
|
||||
bgcolor: "background.paper",
|
||||
},
|
||||
},
|
||||
muiTableHeadCellProps: {
|
||||
sx: {
|
||||
alignItems: "center",
|
||||
},
|
||||
},
|
||||
|
||||
muiTableBodyCellProps: {
|
||||
sx: {
|
||||
border: "none",
|
||||
whiteSpace: "unset", // Allow text wrapping in body cells
|
||||
wordBreak: "break-word", // Ensure long text breaks correctly
|
||||
},
|
||||
},
|
||||
muiTableBodyRowProps: ({ row }) => ({
|
||||
@@ -301,9 +374,11 @@ const NodeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{isLoading && <Loading />}
|
||||
|
||||
<StakeModal
|
||||
nodeId={selectedNodeForStaking?.nodeId}
|
||||
identityKey={selectedNodeForStaking?.identityKey}
|
||||
@@ -312,6 +387,7 @@ const NodeTable = ({ nodes }: { nodes: MappedNymNodes }) => {
|
||||
/>
|
||||
|
||||
<InfoModal {...infoModalProps} />
|
||||
|
||||
<MaterialReactTable table={table} />
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user