Skip to content

Commit

Permalink
feat: improve gateways ux
Browse files Browse the repository at this point in the history
  • Loading branch information
belopash committed Jun 17, 2024
1 parent 1c1a410 commit 5238479
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 10 deletions.
6 changes: 6 additions & 0 deletions src/api/subsquid-network-squid/api.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,12 @@ query myGatewayStakes($address: String!) {
gatewayOperators(where: { account: { id_eq: $address, OR: { owner: { id_eq: $address } } } }) {
...GatewayStakeFragment
}

networkStats {
blockTimeL1
lastBlockL1
lastBlockTimestampL1
}
}

fragment VestingFragment on Account {
Expand Down
5 changes: 4 additions & 1 deletion src/api/subsquid-network-squid/gateways-graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,10 @@ export function useMyGatewayStakes() {
},
{
select: res => {
return res.gatewayOperators.filter(o => o.pendingStake || o.stake);
return {
operators: res.gatewayOperators.filter(o => o.pendingStake || o.stake),
...res.networkStats,
};
},
enabled,
},
Expand Down
11 changes: 11 additions & 0 deletions src/api/subsquid-network-squid/graphql.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5926,6 +5926,12 @@ export type MyGatewayStakesQuery = {
lockEnd: number;
};
}>;
networkStats: {
__typename?: 'NetworkStats';
blockTimeL1: number;
lastBlockL1: number;
lastBlockTimestampL1: string;
};
};

export type VestingFragmentFragment = {
Expand Down Expand Up @@ -6640,6 +6646,11 @@ export const MyGatewayStakesDocument = `
) {
...GatewayStakeFragment
}
networkStats {
blockTimeL1
lastBlockL1
lastBlockTimestampL1
}
}
${GatewayStakeFragmentFragmentDoc}`;

Expand Down
26 changes: 22 additions & 4 deletions src/pages/GatewaysPage/GatewayStake.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import React, { useEffect, useMemo, useState } from 'react';

import { dateFormat } from '@i18n';
import { fromSqd, toSqd } from '@lib/network/utils';
import { Button, Chip } from '@mui/material';
import { Box, Button, Chip, Stack } from '@mui/material';
import * as yup from '@schema';
import { useFormik } from 'formik';
import { useDebounce } from 'use-debounce';

import { useStakeGateway } from '@api/contracts/gateway-registration/useStakeGateway';
import { useMyGatewayStakes } from '@api/subsquid-network-squid/gateways-graphql';
import { BlockchainContractError } from '@components/BlockchainContractError';
import { ContractCallDialog } from '@components/ContractCallDialog';
import { Form, FormikSelect, FormikSwitch, FormikTextInput, FormRow } from '@components/Form';
import { HelpTooltip } from '@components/HelpTooltip';
import { Loader } from '@components/Loader';
import { useMySourceOptions } from '@components/SourceWallet/useMySourceOptions';

Expand Down Expand Up @@ -46,8 +49,7 @@ export function GatewayStake({ disabled }: { disabled?: boolean }) {
options,
isPending: isSourceLoading,
} = useMySourceOptions({
enabled: open,
sourceDisabled: s => s.balance === '0',
sourceDisabled: s => s.balance === '0' || !!data?.operators.some(o => o.account.id === s.id),
});

const formik = useFormik({
Expand Down Expand Up @@ -101,12 +103,19 @@ export function GatewayStake({ disabled }: { disabled?: boolean }) {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [source]);

const [lockDuration] = useDebounce(formik.values.durationBlocks, 500);
const unlockAt = useMemo(() => {
if (!data) return Date.now();

return lockDuration * (data.blockTimeL1 || 0) + new Date(data.lastBlockTimestampL1).getTime();
}, [data, lockDuration]);

return (
<>
<Button
onClick={handleOpen}
variant="contained"
disabled={disabled || data?.length === sources.length}
disabled={disabled || data?.operators.length === sources.length}
>
Add lock
</Button>
Expand Down Expand Up @@ -172,11 +181,20 @@ export function GatewayStake({ disabled }: { disabled?: boolean }) {
label="Lock blocks duration"
formik={formik}
showErrorOnlyOfTouched
autoComplete="off"
/>
</FormRow>
<FormRow>
<FormikSwitch id="autoExtension" label="Auto extension" formik={formik} />
</FormRow>
<Stack direction="row" justifyContent="space-between" alignContent="center">
<Box>Unlock at</Box>
<Stack direction="row">
~{dateFormat(unlockAt, 'dateTime')}
<HelpTooltip help="Automatically relocked if auto extension is enabled" />
</Stack>
</Stack>

<BlockchainContractError error={error} />
</Form>
)}
Expand Down
41 changes: 36 additions & 5 deletions src/pages/GatewaysPage/GatewaysPage.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React from 'react';
import React, { useCallback } from 'react';

import { dateFormat } from '@i18n';
import { tokenFormatter } from '@lib/formatters/formatters';
import { fromSqd } from '@lib/network';
import { Box, Button, Stack, TableBody, TableCell, TableHead, TableRow } from '@mui/material';
import { Link, Outlet } from 'react-router-dom';

import { GatewayStake as GatewayStakeGraphql } from '@api/subsquid-network-squid';
import { useMyGateways, useMyGatewayStakes } from '@api/subsquid-network-squid/gateways-graphql';
import { Card } from '@components/Card';
import { Loader } from '@components/Loader';
Expand All @@ -25,24 +26,44 @@ export function MyStakes() {
const { data, isLoading } = useMyGatewayStakes();
const { SQD_TOKEN } = useContracts();

const getUnlockAt = useCallback(
(o: {
pendingStake?: Pick<GatewayStakeGraphql, 'lockEnd'>;
stake?: Pick<GatewayStakeGraphql, 'lockEnd'>;
autoExtension: boolean;
}) => {
if (!data) return;

const stake = o.pendingStake || o.stake;
if (!stake) return;

return (
(Number(stake.lockEnd) - data.lastBlockL1 + 1) * data.blockTimeL1 +
new Date(data.lastBlockTimestampL1).getTime()
);
},
[data],
);

return (
<Box>
<NetworkPageTitle title="My Locks" endAdornment={<GatewayStake />} />
{isLoading ? (
<Loader />
) : data?.length ? (
) : data?.operators.length ? (
<Card noPadding>
<BorderedTable>
<TableHead>
<TableRow>
<TableCell>Operator</TableCell>
<TableCell>Pending</TableCell>
<TableCell>Active</TableCell>
<TableCell></TableCell>
<TableCell>Expired</TableCell>
<TableCell>Unlock at</TableCell>
</TableRow>
</TableHead>
<TableBody>
{data?.map((o, i) => {
{data?.operators.map((o, i) => {
return (
<TableRow key={i}>
<TableCell>
Expand All @@ -54,7 +75,17 @@ export function MyStakes() {
: '-'}
</TableCell>
<TableCell>
{o.stake ? tokenFormatter(fromSqd(o.stake?.amount), SQD_TOKEN) : '-'}
{o.stake && o.stake.locked
? tokenFormatter(fromSqd(o.stake?.amount), SQD_TOKEN)
: '-'}
</TableCell>
<TableCell>
{o.stake && !o.stake.locked
? tokenFormatter(fromSqd(o.stake?.amount), SQD_TOKEN)
: '-'}
</TableCell>
<TableCell>
{o.autoExtension ? '-' : dateFormat(getUnlockAt(o), 'dateTime')}
</TableCell>
<TableCell>
<Box display="flex" justifyContent="flex-end">
Expand Down

0 comments on commit 5238479

Please sign in to comment.