Feature/show pending delegations (#1229)
* remove unused import * use correct types * set up pending delegations * remove unused import
This commit is contained in:
Generated
+3
@@ -2401,6 +2401,7 @@ checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
|
||||
dependencies = [
|
||||
"autocfg 1.1.0",
|
||||
"hashbrown",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4088,6 +4089,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6b5a3c80cea1ab61f4260238409510e814e38b4b563c06044edf91e7dc070e3"
|
||||
dependencies = [
|
||||
"dyn-clone",
|
||||
"indexmap",
|
||||
"schemars_derive",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -5388,6 +5390,7 @@ name = "validator-api-requests"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"mixnet-contract-common",
|
||||
"schemars",
|
||||
"serde",
|
||||
]
|
||||
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
import { ClientContext } from '../../context/main';
|
||||
import {
|
||||
// getMixnodeRewardEstimation,
|
||||
getMixnodeStakeSaturation,
|
||||
getMixnodeStatus,
|
||||
minorToMajor,
|
||||
getInclusionProbability,
|
||||
} from '../../requests';
|
||||
import { getMixnodeStakeSaturation, getMixnodeStatus, getInclusionProbability } from '../../requests';
|
||||
import { MixnodeStatus, InclusionProbabilityResponse } from '../../types';
|
||||
|
||||
export const useSettingsState = (shouldUpdate: boolean) => {
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import React, { useCallback, useContext, useEffect, useState } from 'react';
|
||||
import { Table, TableCell, TableHead, TableRow } from '@mui/material';
|
||||
import { minorToMajor } from 'src/requests';
|
||||
import { DelegationResult } from 'src/types';
|
||||
import { ClientContext } from 'src/context/main';
|
||||
|
||||
export const PendingEvents = ({
|
||||
pendingDelegations,
|
||||
show,
|
||||
}: {
|
||||
pendingDelegations: DelegationResult[];
|
||||
show: boolean;
|
||||
}) => {
|
||||
const [mapped, setMapped] = useState<Array<DelegationResult & { majorValue: string }>>([]);
|
||||
const { currency } = useContext(ClientContext);
|
||||
|
||||
const mapToMajorValue = useCallback(async () => {
|
||||
const mappedToMajor = await Promise.all(
|
||||
pendingDelegations.map(async (pendingDelegation) => {
|
||||
const majorValue = await minorToMajor(pendingDelegation.amount?.amount || '');
|
||||
return { ...pendingDelegation, majorValue: majorValue.amount };
|
||||
}),
|
||||
);
|
||||
setMapped(mappedToMajor);
|
||||
}, [pendingDelegations]);
|
||||
|
||||
useEffect(() => {
|
||||
mapToMajorValue();
|
||||
}, []);
|
||||
return show ? (
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell sx={{ pl: 3 }}>Address</TableCell>
|
||||
<TableCell>Amount</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
{mapped.map((delegation) => (
|
||||
<TableRow>
|
||||
<TableCell sx={{ maxWidth: 200, pl: 3 }}>{delegation.target_address}</TableCell>
|
||||
<TableCell align="left">{`${delegation.majorValue} ${currency?.major}`}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</Table>
|
||||
) : null;
|
||||
};
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import { Alert, AlertTitle, Box, Button, CircularProgress } from '@mui/material';
|
||||
import { Alert, AlertTitle, Box, Button, CircularProgress, Grid, IconButton } from '@mui/material';
|
||||
import { ArrowDropDown, ArrowDropUp } from '@mui/icons-material';
|
||||
import { EnumRequestStatus, NymCard, RequestStatus } from '../../components';
|
||||
import { UndelegateForm } from './UndelegateForm';
|
||||
import {
|
||||
@@ -8,10 +9,11 @@ import {
|
||||
getPendingVestingDelegations,
|
||||
getReverseMixDelegations,
|
||||
} from '../../requests';
|
||||
import { Epoch, PendingUndelegate, TPagedDelegations } from '../../types';
|
||||
import { DelegationResult, Epoch, PendingUndelegate, TPagedDelegations } from '../../types';
|
||||
import { ClientContext } from '../../context/main';
|
||||
import { PageLayout } from '../../layouts';
|
||||
import { removeObjectDuplicates } from '../../utils';
|
||||
import { PendingEvents } from './PendingEvents';
|
||||
|
||||
export const Undelegate = () => {
|
||||
const [message, setMessage] = useState<string>();
|
||||
@@ -19,7 +21,9 @@ export const Undelegate = () => {
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [pagedDelegations, setPagesDelegations] = useState<TPagedDelegations>();
|
||||
const [pendingUndelegations, setPendingUndelegations] = useState<PendingUndelegate[]>();
|
||||
const [pendingDelegations, setPendingDelegations] = useState<DelegationResult[]>();
|
||||
const [currentEndEpoch, setCurrentEndEpoch] = useState<Epoch['end']>();
|
||||
const [showPendingDelegations, setShowPendingDelegations] = useState(false);
|
||||
|
||||
const { clientDetails } = useContext(ClientContext);
|
||||
|
||||
@@ -30,10 +34,14 @@ export const Undelegate = () => {
|
||||
const pendingUndelegationEvents = [...pendingEvents, ...pendingVestingEvents]
|
||||
.filter((evt): evt is { Undelegate: PendingUndelegate } => 'Undelegate' in evt)
|
||||
.map((e) => ({ ...e.Undelegate }));
|
||||
const pendingDelegationEvents = [...pendingEvents, ...pendingVestingEvents]
|
||||
.filter((evt): evt is { Delegate: DelegationResult } => 'Delegate' in evt)
|
||||
.map((e) => ({ ...e.Delegate }));
|
||||
const epoch = await getCurrentEpoch();
|
||||
|
||||
setCurrentEndEpoch(epoch.end);
|
||||
setPendingUndelegations(pendingUndelegationEvents);
|
||||
setPendingDelegations(pendingDelegationEvents);
|
||||
setPagesDelegations({
|
||||
...mixnodeDelegations,
|
||||
delegations: removeObjectDuplicates(mixnodeDelegations.delegations, 'node_identity'),
|
||||
@@ -60,78 +68,102 @@ export const Undelegate = () => {
|
||||
|
||||
return (
|
||||
<PageLayout>
|
||||
<NymCard title="Undelegate" subheader="Undelegate from a mixnode" noPadding>
|
||||
{isLoading && (
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
p: 3,
|
||||
}}
|
||||
>
|
||||
<CircularProgress size={48} />
|
||||
</Box>
|
||||
)}
|
||||
<>
|
||||
{status === EnumRequestStatus.initial && pagedDelegations && (
|
||||
<UndelegateForm
|
||||
delegations={pagedDelegations?.delegations}
|
||||
pendingUndelegations={pendingUndelegations}
|
||||
currentEndEpoch={currentEndEpoch}
|
||||
onError={(m) => {
|
||||
setMessage(m);
|
||||
setStatus(EnumRequestStatus.error);
|
||||
refresh();
|
||||
}}
|
||||
onSuccess={(m) => {
|
||||
setMessage(m);
|
||||
setStatus(EnumRequestStatus.success);
|
||||
refresh();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{status !== EnumRequestStatus.initial && (
|
||||
<>
|
||||
<RequestStatus
|
||||
status={status}
|
||||
Error={
|
||||
<Alert severity="error" data-testid="request-error">
|
||||
An error occurred with the request: {message}
|
||||
</Alert>
|
||||
}
|
||||
Success={
|
||||
<Alert severity="success">
|
||||
<AlertTitle data-testid="undelegate-success">Undelegation request complete</AlertTitle>
|
||||
{message}
|
||||
</Alert>
|
||||
}
|
||||
/>
|
||||
<Grid container direction="column" spacing={2}>
|
||||
<Grid item>
|
||||
<NymCard title="Undelegate" subheader="Undelegate from a mixnode" noPadding>
|
||||
{isLoading && (
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-end',
|
||||
justifyContent: 'center',
|
||||
p: 3,
|
||||
pt: 0,
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
data-testid="finish-button"
|
||||
variant="contained"
|
||||
disableElevation
|
||||
onClick={() => {
|
||||
setStatus(EnumRequestStatus.initial);
|
||||
initialize();
|
||||
}}
|
||||
size="large"
|
||||
>
|
||||
Finish
|
||||
</Button>
|
||||
<CircularProgress size={48} />
|
||||
</Box>
|
||||
)}
|
||||
<>
|
||||
{status === EnumRequestStatus.initial && pagedDelegations && (
|
||||
<UndelegateForm
|
||||
delegations={pagedDelegations?.delegations}
|
||||
pendingUndelegations={pendingUndelegations}
|
||||
currentEndEpoch={currentEndEpoch}
|
||||
onError={(m) => {
|
||||
setMessage(m);
|
||||
setStatus(EnumRequestStatus.error);
|
||||
refresh();
|
||||
}}
|
||||
onSuccess={(m) => {
|
||||
setMessage(m);
|
||||
setStatus(EnumRequestStatus.success);
|
||||
refresh();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{status !== EnumRequestStatus.initial && (
|
||||
<>
|
||||
<RequestStatus
|
||||
status={status}
|
||||
Error={
|
||||
<Alert severity="error" data-testid="request-error">
|
||||
An error occurred with the request: {message}
|
||||
</Alert>
|
||||
}
|
||||
Success={
|
||||
<Alert severity="success">
|
||||
<AlertTitle data-testid="undelegate-success">Undelegation request complete</AlertTitle>
|
||||
{message}
|
||||
</Alert>
|
||||
}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-end',
|
||||
p: 3,
|
||||
pt: 0,
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
data-testid="finish-button"
|
||||
variant="contained"
|
||||
disableElevation
|
||||
onClick={() => {
|
||||
setStatus(EnumRequestStatus.initial);
|
||||
initialize();
|
||||
}}
|
||||
size="large"
|
||||
>
|
||||
Finish
|
||||
</Button>
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
</NymCard>
|
||||
</NymCard>
|
||||
</Grid>
|
||||
{pendingDelegations?.length && (
|
||||
<Grid item>
|
||||
<NymCard
|
||||
title="Pending events"
|
||||
subheader="Pending delegations"
|
||||
noPadding
|
||||
Action={
|
||||
<IconButton onClick={() => setShowPendingDelegations((show) => !show)}>
|
||||
{!showPendingDelegations ? <ArrowDropDown /> : <ArrowDropUp />}
|
||||
</IconButton>
|
||||
}
|
||||
>
|
||||
{pendingDelegations ? (
|
||||
<PendingEvents pendingDelegations={pendingDelegations} show={showPendingDelegations} />
|
||||
) : (
|
||||
<div>No pending delegations</div>
|
||||
)}
|
||||
</NymCard>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
</PageLayout>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { SelectionChance } from "./selectionchance";
|
||||
|
||||
export interface InclusionProbabilityResponse { in_active: SelectionChance, in_reserve: SelectionChance, }
|
||||
export interface InclusionProbabilityResponse {
|
||||
in_active: number;
|
||||
in_reserve: number;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user