Skip to content

Commit

Permalink
feat: pending swaps
Browse files Browse the repository at this point in the history
  • Loading branch information
dumbledope committed Jun 30, 2022
1 parent 57dc734 commit ca6feb5
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 5 deletions.
13 changes: 8 additions & 5 deletions common/store/swaps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { atomWithQuery } from 'jotai-query-toolkit';
import { fetchPrivate } from 'micro-stacks/common';
import { TransactionStatus } from '../api/stacks';
import { stxTxResultState } from './api';
import { waitForAll } from 'jotai/utils';

export const swapIdState = atom<string | undefined>(undefined);

Expand Down Expand Up @@ -151,7 +152,8 @@ export const inboundSwapState = atomFamilyWithQuery<string, InboundSwap>(
})) as string;
const swap = JSON.parse(contents) as InboundSwapStarted;
return swap;
}
},
{ refetchInterval: false }
);

export const useInboundSwapStorage = (id: string) => useQueryAtom(inboundSwapState(id));
Expand Down Expand Up @@ -255,17 +257,18 @@ export const fullOutboundSwapState = atomFamilyWithQuery<string, FullOutboundSwa
};
}
return swap;
}
},
{ refetchInterval: 60000 }
);

export const allSwapsState = atom<(InboundSwap | FullOutboundSwap)[]>(get => {
const keys = get(swapsListState);
const items = keys.map(({ dir, id }) => {
if (dir === 'outbound') {
return get(fullOutboundSwapState(id));
return fullOutboundSwapState(id);
}
const swap = get(inboundSwapState(id));
const swap = inboundSwapState(id);
return swap;
});
return items;
return get(waitForAll(items));
});
31 changes: 31 additions & 0 deletions components/icons/close.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react';
import { Box, BoxProps } from '@nelson-ui/react';

export const CloseIcon: React.FC<BoxProps> = props => {
return (
<Box display="inline-block" height="12px" width="13px" {...props}>
<svg
width="12"
height="13"
viewBox="0 0 12 13"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M1 1.5L11 11.5"
stroke="#FFA953"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M11 1.5L1 11.5"
stroke="#FFA953"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</Box>
);
};
92 changes: 92 additions & 0 deletions components/pending-swap.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { Box, SpaceBetween, Stack } from '@nelson-ui/react';
import { useAtomValue } from 'jotai/utils';
import { useRouter } from 'next/router';
import React, { useCallback, useMemo, useState } from 'react';
import { allSwapsState } from '../common/store/swaps';
import { CloseIcon } from './icons/close';
import { PendingIcon } from './icons/pending';
import { SafeSuspense } from './safe-suspense';
import { Text } from './text';

export const PendingSwap: React.FC = () => {
const allSwaps = useAtomValue(allSwapsState);
const router = useRouter();
const [hidden, setHidden] = useState(false);

const pendingSwap = useMemo(() => {
return allSwaps.find(swap => {
if ('secret' in swap) {
// outbound
if (!('btcTxid' in swap)) return false;
if (!('recoveryTxid' in swap) && !('finalizeTxid' in swap)) {
return true;
}
} else {
if (typeof swap.finalizeTxid === 'undefined') return true;
}
});
}, [allSwaps]);

const goToSwap = useCallback(() => {
if (typeof pendingSwap === 'undefined') return;
if ('secret' in pendingSwap) {
void router.push({
pathname: '/inbound/[swapId]',
query: { swapId: pendingSwap.id },
});
} else {
void router.push({
pathname: '/outbound/[txId]',
query: { txId: pendingSwap.txId },
});
}
}, [pendingSwap, router]);

const hide = useCallback(() => {
setHidden(true);
}, [setHidden]);

if (typeof pendingSwap === 'undefined') return null;
if (hidden) return null;

return (
<Box
backgroundColor="$dark-surface-warning"
border="1px solid $dark-border-warning-subdued"
p="30px"
borderRadius="16px"
>
<SpaceBetween>
<Stack isInline alignItems="center">
<PendingIcon color="var(--colors-dark-warning-action-warning)" />
<Text variant="Label02" color="$dark-warning-action-warning">
You may have a{' '}
<Text
variant="Label02"
textDecoration="underline"
color="inherit"
display="inline-block"
cursor="pointer"
onClick={goToSwap}
style={{
textDecoration: 'underline',
}}
>
swap in progress
</Text>
{'.'}
</Text>
</Stack>
<CloseIcon onClick={hide} cursor="pointer" />
</SpaceBetween>
</Box>
);
};

export const PendingSwapContainer: React.FC = () => {
return (
<SafeSuspense fallback={<></>}>
<PendingSwap />
</SafeSuspense>
);
};
2 changes: 2 additions & 0 deletions components/swap-container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { useAtomValue } from 'jotai/utils';
import { SelectSupplier } from './select-supplier';
import { RegisterSwap } from './inbound/register';
import { CSSTypes } from '@nelson-ui/core';
import { PendingSwapContainer } from './pending-swap';

export const SwapContainer: React.FC = () => {
const {
Expand Down Expand Up @@ -76,6 +77,7 @@ export const SwapContainer: React.FC = () => {
}
return (
<Stack spacing="$row-y">
<PendingSwapContainer />
<CenterBox noPadding>
<Stack spacing="$6" px="$row-x">
<SwapField dir="from" />
Expand Down

0 comments on commit ca6feb5

Please sign in to comment.