Skip to content

Commit

Permalink
feat: improve portals page
Browse files Browse the repository at this point in the history
  • Loading branch information
belopash committed Dec 4, 2024
1 parent 6c57ad5 commit 689d9e2
Show file tree
Hide file tree
Showing 8 changed files with 207 additions and 110 deletions.
10 changes: 10 additions & 0 deletions src/hooks/useCountdown.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { relativeDateFormat } from '@i18n';

import { useTicker } from './useTicker';

export function useCountdown({ timestamp }: { timestamp?: Date | string | number | undefined }) {
const curTimestamp = useTicker(() => Date.now(), 1000);
const timeLeft = timestamp ? relativeDateFormat(curTimestamp, timestamp) : undefined;

return timeLeft;
}
6 changes: 3 additions & 3 deletions src/i18n/dateFormat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@ export function dateFormat(
value: Date | string | number | undefined,
tpl: 'dateTime' | 'date' | string = 'date',
) {
if (!value) return null;
if (!value) return undefined;

if (tpl === 'dateTime') {
tpl = 'dd.MM.yyyy HH:mm:ss';
} else if (tpl === 'date') {
tpl = 'dd.MM.yyyy';
}

if (value.valueOf() == 0) return null;
if (value.valueOf() == 0) return undefined;

const date = new Date(value);
if (!isValid(date)) return null;
if (!isValid(date)) return undefined;

return format(new Date(value), tpl);
}
Expand Down
8 changes: 3 additions & 5 deletions src/pages/DashboardPage/Summary.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { PropsWithChildren, useEffect, useMemo, useState } from 'react';

import { relativeDateFormat } from '@i18n';
import {
bytesFormatter,
numberWithCommasFormatter,
Expand All @@ -26,7 +25,7 @@ import { useNetworkSummary } from '@api/subsquid-network-squid';
import SquaredChip from '@components/Chip/SquaredChip';
import { HelpTooltip } from '@components/HelpTooltip';
import { Loader } from '@components/Loader';
import { useTicker } from '@hooks/useTicker';
import { useCountdown } from '@hooks/useCountdown';
import { useContracts } from '@network/useContracts';

export function ColumnLabel({ children, color }: PropsWithChildren<{ color?: string }>) {
Expand Down Expand Up @@ -108,14 +107,13 @@ function OnlineInfo() {
}

function CurrentEpochEstimation({ epochEnd }: { epochEnd: number }) {
const curTime = useTicker(() => Date.now(), 1000);
const epochEndsIn = useMemo(() => relativeDateFormat(curTime, epochEnd), [curTime, epochEnd]);
const timeLeft = useCountdown({ timestamp: epochEnd });

return (
<Stack direction="row" spacing={1}>
<span>Ends in</span>
<SquaredChip
label={<Typography variant="subtitle1">~{epochEndsIn}</Typography>}
label={<Typography variant="subtitle1">~{timeLeft}</Typography>}
color="warning"
/>
</Stack>
Expand Down
72 changes: 59 additions & 13 deletions src/pages/GatewaysPage/GatewayUnstake.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React, { useState } from 'react';

import { LockOpen as LockOpenIcon } from '@mui/icons-material';
import { dateFormat } from '@i18n';
import { Lock } from '@mui/icons-material';
import { LoadingButton } from '@mui/lab';
import { SxProps } from '@mui/material';
import { Box, SxProps, Tooltip } from '@mui/material';
import toast from 'react-hot-toast';
import { useClient } from 'wagmi';
import * as yup from 'yup';
Expand All @@ -11,6 +12,7 @@ import { gatewayRegistryAbi } from '@api/contracts';
import { useWriteSQDTransaction } from '@api/contracts/useWriteTransaction';
import { errorMessage } from '@api/contracts/utils';
import { ContractCallDialog } from '@components/ContractCallDialog';
import { useCountdown } from '@hooks/useCountdown';
import { useSquidHeight } from '@hooks/useSquidNetworkHeightHooks';
import { useContracts } from '@network/useContracts';

Expand All @@ -24,22 +26,66 @@ export const stakeSchema = yup.object({
// .max(yup.ref('max'), ({ max }) => `Amount should be less than ${formatSqd(max)} `),
});

export function GatewayUnstakeButton({ sx, disabled }: { sx?: SxProps; disabled?: boolean }) {
function UnlocksTooltip({ timestamp }: { timestamp?: Date | string | number | undefined }) {
const timeLeft = useCountdown({ timestamp });

return `Unlocks in ${timeLeft} (${dateFormat(timestamp, 'dateTime')})`;
}

export function GatewayUnstakeButton({
sx,
disabled,
source,
}: {
sx?: SxProps;
disabled?: boolean;
source: {
locked: boolean;
unlockedAt?: string;
};
}) {
const [open, setOpen] = useState(false);

return (
<>
<LoadingButton
startIcon={<LockOpenIcon />}
disabled={disabled}
loading={open}
variant="contained"
color="error"
onClick={() => setOpen(true)}
sx={sx}
<Tooltip
title={
source.unlockedAt ? (
<UnlocksTooltip timestamp={source.unlockedAt} />
) : (
'Auto-extension is enabled'
)
}
placement="top"
>
WITHDRAW
</LoadingButton>
<Box sx={{ position: 'relative', display: 'inline-flex', alignItems: 'center' }}>
{source.locked && !disabled && (
<Lock
fontSize="small"
// color="secondary"
sx={{
color: '#3e4a5c',
position: 'absolute',
top: '0px',
right: '0px',
transform: 'translate(0%, -25%)',
zIndex: 1,
}}
/>
)}
<LoadingButton
// startIcon={<LockOpenIcon />}
disabled={disabled || source.locked}
loading={open}
variant="contained"
color="error"
onClick={() => setOpen(true)}
sx={sx}
>
WITHDRAW
</LoadingButton>
</Box>
</Tooltip>
<GatewayUnstakeDialog open={open} onClose={() => setOpen(false)} />
</>
);
Expand Down
101 changes: 72 additions & 29 deletions src/pages/GatewaysPage/GatewaysPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
Avatar,
Box,
Button,
Card,
Collapse,
Divider,
IconButton,
Expand Down Expand Up @@ -44,6 +45,7 @@ import {
import SquaredChip from '@components/Chip/SquaredChip';
import { HelpTooltip } from '@components/HelpTooltip';
import { DashboardTable, NoItems } from '@components/Table';
import { useCountdown } from '@hooks/useCountdown';
import { CenteredPageWrapper } from '@layouts/NetworkLayout';
import { ConnectedWalletRequired } from '@network/ConnectedWalletRequired';
import { useAccount } from '@network/useAccount';
Expand All @@ -57,6 +59,18 @@ import { GatewayStakeButton } from './GatewayStake';
import { GatewayUnregisterButton } from './GatewayUnregister';
import { GatewayUnstakeButton } from './GatewayUnstake';

function AppliesTooltip({ timestamp }: { timestamp?: string }) {
const timeLeft = useCountdown({ timestamp });

return <span>{`Applies in ${timeLeft} (${dateFormat(timestamp, 'dateTime')})`}</span>;
}

function ExpiresTooltip({ timestamp }: { timestamp?: string }) {
const timeLeft = useCountdown({ timestamp });

return <span>{`Expires in ${timeLeft} (${dateFormat(timestamp, 'dateTime')})`}</span>;
}

export function MyStakes() {
const theme = useTheme();
const narrowXs = useMediaQuery(theme.breakpoints.down('xs'));
Expand Down Expand Up @@ -95,6 +109,14 @@ export function MyStakes() {
const { data: lastL1Block, isLoading: isL1BlockLoading } = useBlock({
chainId: l1ChainId,
});
const { data: appliedAtL1Block, isLoading: isAppliedAtBlockLoading } = useBlock({
chainId: l1ChainId,
blockNumber: stake?.lockStart,
includeTransactions: false,
query: {
enabled: stake && stake?.lockStart <= (lastL1Block?.number || 0n),
},
});
const { data: unlockedAtL1Block, isLoading: isUnlockedAtBlockLoading } = useBlock({
chainId: l1ChainId,
blockNumber: stake?.lockEnd,
Expand Down Expand Up @@ -124,15 +146,27 @@ export function MyStakes() {
stake.lockEnd >= (lastL1Block?.number || 0n);
const isExpired = !!stake?.amount && stake.lockEnd < (lastL1Block?.number || 0n);

const unlockDate = useMemo(() => {
const appliedAt = useMemo(() => {
if (!stake || !lastL1Block) return;

if (stake.lockStart < lastL1Block.number)
return new Date(Number(appliedAtL1Block?.timestamp || 0n) * 1000).toISOString();

return new Date(
Number(lastL1Block.timestamp) * 1000 +
getBlockTime(stake.lockStart - lastL1Block.number + 1n),
).toISOString();
}, [appliedAtL1Block?.timestamp, lastL1Block, stake]);

const unlockedAt = useMemo(() => {
if (!stake || !lastL1Block || stake.autoExtension) return;

if (stake.lockEnd < lastL1Block.number)
return Number(unlockedAtL1Block?.timestamp || 0n) * 1000;
return new Date(Number(unlockedAtL1Block?.timestamp || 0n) * 1000).toISOString();

return (
Number(lastL1Block.timestamp) * 1000 + getBlockTime(stake.lockEnd - lastL1Block.number + 1n)
);
return new Date(
Number(lastL1Block.timestamp) * 1000 + getBlockTime(stake.lockEnd - lastL1Block.number + 1n),
).toISOString();
}, [lastL1Block, stake, unlockedAtL1Block?.timestamp]);

const cuPerEpoch = useMemo(() => {
Expand All @@ -154,7 +188,13 @@ export function MyStakes() {
action={
<Stack direction="row" spacing={1}>
<GatewayStakeButton sources={sources} disabled={isLoading || isPending} />
<GatewayUnstakeButton disabled={isLoading || !isExpired} />
<GatewayUnstakeButton
disabled={isLoading}
source={{
locked: !isExpired,
unlockedAt,
}}
/>
</Stack>
}
>
Expand All @@ -181,14 +221,14 @@ export function MyStakes() {
lastL1Block &&
(isPending ? (
<Tooltip
title="Tokens have been locked but will become active at the start of the next epoch"
title={<AppliesTooltip timestamp={appliedAt} />}
placement="top"
>
<SquaredChip label="Pending" color="warning" />
</Tooltip>
) : isActive ? (
<Tooltip
title="Tokens have been locked and remain valid until the expiration date"
title={<ExpiresTooltip timestamp={unlockedAt} />}
placement="top"
>
<SquaredChip label="Active" color="info" />
Expand All @@ -210,7 +250,7 @@ export function MyStakes() {
<ColumnValue>{numberWithCommasFormatter(cuPerEpoch || 0)}</ColumnValue>
</Box>
</Stack>
<Stack divider={<Divider flexItem />} spacing={1} flex={1}>
{/* <Stack divider={<Divider flexItem />} spacing={1} flex={1}>
<Box>
<ColumnLabel>Expired At</ColumnLabel>
<ColumnValue>
Expand All @@ -221,7 +261,7 @@ export function MyStakes() {
: 'Auto-extension enabled'}
</ColumnValue>
</Box>
</Stack>
</Stack> */}
</Stack>
</Stack>
</SummarySection>
Expand Down Expand Up @@ -352,25 +392,28 @@ const GettingStarted = () => {
];

return (
<Alert
sx={{ mb: 2 }}
color="info"
icon={<Info />}
action={
<IconButton color="inherit" sx={{ padding: 0.5 }} onClick={() => setOpen(!open)}>
<ExpandMore
sx={{
transition: 'transform 300ms ease-out',
transform: open ? 'rotate(180deg)' : 'rotate(0deg)',
}}
/>
</IconButton>
}
>
<Typography>Getting started with your portal</Typography>
<Card sx={{ mb: 2, background: '#f3f3ff', padding: 0 }}>
<Alert
sx={{ cursor: 'pointer' }}
color="info"
icon={<Info />}
action={
<IconButton color="inherit" sx={{ padding: 0.5 }}>
<ExpandMore
sx={{
transition: 'transform 300ms ease-out',
transform: open ? 'rotate(180deg)' : 'rotate(0deg)',
}}
/>
</IconButton>
}
onClick={() => setOpen(!open)}
>
<Typography>Getting started with your portal</Typography>
</Alert>

<Collapse in={open} unmountOnExit timeout={300}>
<Box pt={1.5}>
<Collapse in={open} timeout={300}>
<Box pt={0} pl={6.5} pr={6.5} pb={2} color="#383766">
<List disablePadding>
{steps.map(({ primary, secondary }, i) => (
<ListItem
Expand Down Expand Up @@ -404,7 +447,7 @@ const GettingStarted = () => {
</Typography>
</Box>
</Collapse>
</Alert>
</Card>
);
};

Expand Down
Loading

0 comments on commit 689d9e2

Please sign in to comment.