Skip to content

Commit 04aedc9

Browse files
authored
Merge pull request #213 from xch-dev/cancel-offer-wc
Add offer cancellation endpoint
2 parents 971dd5b + f417673 commit 04aedc9

File tree

6 files changed

+230
-136
lines changed

6 files changed

+230
-136
lines changed
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { OfferAssets, OfferRecord } from '@/bindings';
2+
import { nftUri } from '@/lib/nftUri';
3+
import { toDecimal } from '@/lib/utils';
4+
import { useWalletState } from '@/state';
5+
import BigNumber from 'bignumber.js';
6+
7+
export interface OfferSummaryCardProps {
8+
record: OfferRecord;
9+
content: React.ReactNode;
10+
}
11+
12+
export function OfferSummaryCard({ record, content }: OfferSummaryCardProps) {
13+
return (
14+
<div className='block p-4 rounded-sm bg-neutral-100 dark:bg-neutral-900'>
15+
<div className='flex justify-between'>
16+
<div className='grid grid-cols-1 md:grid-cols-3 gap-4'>
17+
<div className='flex flex-col gap-1'>
18+
<div>
19+
{record.status === 'active'
20+
? 'Pending'
21+
: record.status === 'completed'
22+
? 'Taken'
23+
: record.status === 'cancelled'
24+
? 'Cancelled'
25+
: 'Expired'}
26+
</div>
27+
<div className='text-muted-foreground text-sm'>
28+
{record.creation_date}
29+
</div>
30+
</div>
31+
32+
<AssetPreview label='Offered' assets={record.summary.maker} />
33+
<AssetPreview label='Requested' assets={record.summary.taker} />
34+
</div>
35+
36+
{content}
37+
</div>
38+
</div>
39+
);
40+
}
41+
42+
interface AssetPreviewProps {
43+
label: string;
44+
assets: OfferAssets;
45+
}
46+
47+
function AssetPreview({ label, assets }: AssetPreviewProps) {
48+
const walletState = useWalletState();
49+
50+
return (
51+
<div className='flex flex-col gap-1 w-[125px] lg:w-[200px] xl:w-[300px]'>
52+
<div>{label}</div>
53+
{BigNumber(assets.xch.amount)
54+
.plus(assets.xch.royalty)
55+
.isGreaterThan(0) && (
56+
<div className='flex items-center gap-2'>
57+
<img src='https://icons.dexie.space/xch.webp' className='w-8 h-8' />
58+
59+
<div className='text-sm text-muted-foreground truncate'>
60+
{toDecimal(
61+
BigNumber(assets.xch.amount).plus(assets.xch.royalty).toString(),
62+
walletState.sync.unit.decimals,
63+
)}{' '}
64+
{walletState.sync.unit.ticker}
65+
</div>
66+
</div>
67+
)}
68+
{Object.entries(assets.cats).map(([_assetId, cat]) => (
69+
<div className='flex items-center gap-2'>
70+
<img src={cat.icon_url!} className='w-8 h-8' />
71+
72+
<div className='text-sm text-muted-foreground truncate'>
73+
{toDecimal(BigNumber(cat.amount).plus(cat.royalty).toString(), 3)}{' '}
74+
{cat.name ?? cat.ticker ?? 'Unknown'}
75+
</div>
76+
</div>
77+
))}
78+
{Object.entries(assets.nfts).map(([_nftId, nft]) => (
79+
<div className='flex items-center gap-2'>
80+
<img
81+
src={nftUri(nft.image_mime_type, nft.image_data)}
82+
className='w-8 h-8'
83+
/>
84+
85+
<div className='text-sm text-muted-foreground truncate'>
86+
{nft.name ?? 'Unknown'}
87+
</div>
88+
</div>
89+
))}
90+
</div>
91+
);
92+
}

src/contexts/WalletConnectContext.tsx

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1-
import { commands, OfferSummary, TransactionSummary } from '@/bindings';
1+
import {
2+
commands,
3+
OfferRecord,
4+
OfferSummary,
5+
TransactionSummary,
6+
} from '@/bindings';
27
import { AdvancedSummary } from '@/components/ConfirmationDialog';
38
import { OfferCard } from '@/components/OfferCard';
9+
import { OfferSummaryCard } from '@/components/OfferSummaryCard';
410
import { Button } from '@/components/ui/button';
511
import {
612
Dialog,
@@ -487,6 +493,39 @@ function CreateOfferDialog({ params }: CommandDialogProps<'chia_createOffer'>) {
487493
);
488494
}
489495

496+
function CancelOfferDialog({ params }: CommandDialogProps<'chia_cancelOffer'>) {
497+
const walletState = useWalletState();
498+
499+
const [record, setRecord] = useState<OfferRecord | null>(null);
500+
const { addError } = useErrors();
501+
502+
useEffect(() => {
503+
commands
504+
.getOffer({ offer_id: params.id })
505+
.then((data) => setRecord(data.offer))
506+
.catch(addError);
507+
}, [params, addError]);
508+
509+
return (
510+
<div className='space-y-2'>
511+
<div className='font-medium'>Offer ID</div>
512+
<div className='text-sm text-muted-foreground'>{params.id}</div>
513+
514+
<div className='font-medium'>Fee</div>
515+
<div className='text-sm text-muted-foreground'>
516+
{toDecimal(params.fee || 0, walletState.sync.unit.decimals)}{' '}
517+
{walletState.sync.unit.ticker}
518+
</div>
519+
520+
{record && (
521+
<div className='border rounded-md'>
522+
<OfferSummaryCard record={record} content={null} />
523+
</div>
524+
)}
525+
</div>
526+
);
527+
}
528+
490529
function SendDialog({ params }: CommandDialogProps<'chia_send'>) {
491530
const walletState = useWalletState();
492531

@@ -543,6 +582,7 @@ const COMMAND_COMPONENTS: {
543582
chip0002_signMessage: SignMessageDialog,
544583
chia_takeOffer: TakeOfferDialog,
545584
chia_createOffer: CreateOfferDialog,
585+
chia_cancelOffer: CancelOfferDialog,
546586
chia_send: SendDialog,
547587
};
548588

@@ -568,6 +608,10 @@ const COMMAND_METADATA: {
568608
title: 'Create Offer',
569609
description: 'Review and create the offer',
570610
},
611+
chia_cancelOffer: {
612+
title: 'Cancel Offer',
613+
description: 'Review and cancel the offer',
614+
},
571615
};
572616

573617
function RequestDialog({

0 commit comments

Comments
 (0)