Feature/show pending delegations (#1229)

* remove unused import

* use correct types

* set up pending delegations

* remove unused import
This commit is contained in:
Fouad
2022-04-29 12:53:52 +01:00
committed by GitHub
parent 632612eca0
commit 96f2718b94
5 changed files with 152 additions and 76 deletions
+3
View File
@@ -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;
};
+98 -66
View File
@@ -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;
}