Initial commit
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
import { useCallback, useState, useMemo } from 'react';
|
||||
import styled, { type AnyStyledComponent } from 'styled-components';
|
||||
import { TESTNET_CHAIN_ID } from '@dydxprotocol/v4-client-js';
|
||||
import { Root, Trigger, Content } from '@radix-ui/react-collapsible';
|
||||
import { StatusResponse } from '@0xsquid/sdk';
|
||||
|
||||
import { useInterval, useStringGetter } from '@/hooks';
|
||||
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
|
||||
import { formatSeconds } from '@/lib/timeUtils';
|
||||
|
||||
import { Output, OutputType } from '@/components/Output';
|
||||
import { WithReceipt } from '@/components/WithReceipt';
|
||||
import { Icon, IconName } from '@/components/Icon';
|
||||
import { TransferStatusSteps } from '@/views/TransferStatusSteps';
|
||||
import { LoadingDots } from '@/components/Loading/LoadingDots';
|
||||
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
|
||||
type ElementProps = {
|
||||
toAmount?: number;
|
||||
triggeredAt?: number;
|
||||
status?: StatusResponse;
|
||||
};
|
||||
|
||||
export const TransferStatusToast = ({
|
||||
toAmount,
|
||||
triggeredAt = Date.now(),
|
||||
status,
|
||||
}: ElementProps) => {
|
||||
const stringGetter = useStringGetter();
|
||||
const [open, setOpen] = useState<boolean>(false);
|
||||
const [secondsLeft, setSecondsLeft] = useState<number | undefined>();
|
||||
|
||||
const type = useMemo(
|
||||
() => (status?.toChain?.chainData?.chainId === TESTNET_CHAIN_ID ? 'deposit' : 'withdrawal'),
|
||||
[status]
|
||||
);
|
||||
|
||||
const updateSecondsLeft = useCallback(() => {
|
||||
const fromChainEta = (status?.fromChain?.chainData?.estimatedRouteDuration || 0) * 1000;
|
||||
const toChainEta = (status?.toChain?.chainData?.estimatedRouteDuration || 0) * 1000;
|
||||
setSecondsLeft(Math.floor((triggeredAt + fromChainEta + toChainEta - Date.now()) / 1000));
|
||||
}, [status]);
|
||||
|
||||
useInterval({ callback: updateSecondsLeft });
|
||||
|
||||
if (!status) return <LoadingDots size={3} />;
|
||||
|
||||
return (
|
||||
<Styled.Root open={open} onOpenChange={setOpen}>
|
||||
<WithReceipt
|
||||
hideReceipt={!open}
|
||||
side="bottom"
|
||||
slotReceipt={
|
||||
<Styled.Receipt>
|
||||
<TransferStatusSteps status={status} />
|
||||
</Styled.Receipt>
|
||||
}
|
||||
>
|
||||
<Styled.BridgingStatus>
|
||||
<Styled.Status>
|
||||
{stringGetter({
|
||||
key: type === 'deposit' ? STRING_KEYS.DEPOSIT_STATUS : STRING_KEYS.WITHDRAW_STATUS,
|
||||
params: {
|
||||
AMOUNT_USD: <Styled.InlineOutput type={OutputType.Fiat} value={toAmount} />,
|
||||
ESTIMATED_DURATION: (
|
||||
<Styled.InlineOutput
|
||||
type={OutputType.Text}
|
||||
value={formatSeconds(Math.max(secondsLeft || 0, 0))}
|
||||
/>
|
||||
),
|
||||
},
|
||||
})}
|
||||
</Styled.Status>
|
||||
<Styled.Trigger>
|
||||
<Styled.TriggerIcon>
|
||||
<Icon iconName={IconName.Caret} />
|
||||
</Styled.TriggerIcon>
|
||||
{stringGetter({ key: open ? STRING_KEYS.HIDE_DETAILS : STRING_KEYS.VIEW_DETAILS })}
|
||||
</Styled.Trigger>
|
||||
</Styled.BridgingStatus>
|
||||
</WithReceipt>
|
||||
</Styled.Root>
|
||||
);
|
||||
};
|
||||
|
||||
const Styled: Record<string, AnyStyledComponent> = {};
|
||||
|
||||
Styled.Root = styled(Root)`
|
||||
margin: 0.5rem -1rem -1rem -1rem;
|
||||
color: var(--color-text-0);
|
||||
font: var(--font-small-book);
|
||||
`;
|
||||
|
||||
Styled.Receipt = styled.div`
|
||||
padding: 0 1rem;
|
||||
`;
|
||||
|
||||
Styled.BridgingStatus = styled.div`
|
||||
${layoutMixins.flexColumn};
|
||||
background-color: var(--color-layer-3);
|
||||
|
||||
gap: 0.5rem;
|
||||
padding: 0 1rem 1rem 1rem;
|
||||
border-radius: 0.5rem;
|
||||
`;
|
||||
|
||||
Styled.Status = styled.div`
|
||||
color: var(--color-text-0);
|
||||
|
||||
font-size: 0.875rem;
|
||||
`;
|
||||
|
||||
Styled.InlineOutput = styled(Output)`
|
||||
display: inline-block;
|
||||
|
||||
color: var(--color-text-1);
|
||||
`;
|
||||
|
||||
Styled.Content = styled(Content)`
|
||||
${layoutMixins.flexColumn};
|
||||
|
||||
gap: 0.5rem;
|
||||
padding: 1rem;
|
||||
`;
|
||||
|
||||
Styled.Step = styled.div`
|
||||
${layoutMixins.row};
|
||||
|
||||
gap: 0.5rem;
|
||||
`;
|
||||
|
||||
Styled.Trigger = styled(Trigger)`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5em;
|
||||
|
||||
color: var(--color-accent);
|
||||
user-select: none;
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
`;
|
||||
|
||||
Styled.TriggerIcon = styled.span`
|
||||
width: 0.75em;
|
||||
|
||||
display: inline-flex;
|
||||
transition: transform 0.3s var(--ease-out-expo);
|
||||
|
||||
${Styled.Trigger}[data-state='open'] & {
|
||||
rotate: -0.5turn;
|
||||
}
|
||||
`;
|
||||
Reference in New Issue
Block a user