Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add cancel transaction, ref #LEA-958 #5920

Draft
wants to merge 1 commit into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@
"@coinbase/cbpay-js": "2.1.0",
"@fungible-systems/zone-file": "2.0.0",
"@hirosystems/token-metadata-api-client": "1.2.0",
"@hookform/resolvers": "3.9.0",
"@leather.io/bitcoin": "0.14.2",
"@leather.io/constants": "0.12.5",
"@leather.io/crypto": "1.6.6",
Expand Down Expand Up @@ -234,6 +235,7 @@
"react-dom": "18.3.1",
"react-dom-confetti": "0.2.0",
"react-head": "3.4.2",
"react-hook-form": "7.53.1",
"react-intersection-observer": "9.5.2",
"react-lottie": "1.2.4",
"react-qr-code": "2.0.12",
Expand Down
1,617 changes: 841 additions & 776 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

16 changes: 1 addition & 15 deletions src/app/common/hooks/use-submit-stx-transaction.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useCallback } from 'react';

import { bytesToHex } from '@stacks/common';
import { StacksTransaction, broadcastTransaction } from '@stacks/transactions';

import { delay, isError } from '@leather.io/utils';
Expand All @@ -14,7 +13,6 @@ import { useLoading } from '@app/common/hooks/use-loading';
import { safelyFormatHexTxid } from '@app/common/utils/safe-handle-txid';
import { useToast } from '@app/features/toasts/use-toast';
import { useCurrentStacksNetworkState } from '@app/store/networks/networks.hooks';
import { useSubmittedTransactionsActions } from '@app/store/submitted-transactions/submitted-transactions.hooks';

const timeForApiToUpdate = 250;

Expand All @@ -27,7 +25,6 @@ interface UseSubmitTransactionCallbackArgs {
onError(error: Error | string): void;
}
export function useSubmitTransactionCallback({ loadingKey }: UseSubmitTransactionArgs) {
const submittedTransactionsActions = useSubmittedTransactionsActions();
const toast = useToast();
const refreshAccountData = useRefreshAllAccountData();

Expand All @@ -47,10 +44,6 @@ export function useSubmitTransactionCallback({ loadingKey }: UseSubmitTransactio
setIsIdle();
} else {
logger.info('Transaction broadcast', response);
submittedTransactionsActions.newTransactionSubmitted({
rawTx: bytesToHex(transaction.serialize()),
txid: safelyFormatHexTxid(response.txid),
});

await delay(500);

Expand All @@ -65,13 +58,6 @@ export function useSubmitTransactionCallback({ loadingKey }: UseSubmitTransactio
setIsIdle();
}
},
[
setIsLoading,
stacksNetwork,
toast,
setIsIdle,
submittedTransactionsActions,
refreshAccountData,
]
[setIsLoading, stacksNetwork, toast, setIsIdle, refreshAccountData]
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { ActivitySelectors } from '@tests/selectors/activity.selectors';
import { css } from 'leather-styles/css';
import { HStack, styled } from 'leather-styles/jsx';

import { ChevronDownIcon, ChevronsRightIcon, CloseIcon, DropdownMenu, Flag } from '@leather.io/ui';

interface Props {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use full name like other components 🙏🏼

onIncreaseFee(): void;
onCancelTransaction(): void;
}

export function StacksTransactionActionMenu({ onIncreaseFee, onCancelTransaction }: Props) {
return (
<DropdownMenu.Root>
<DropdownMenu.Trigger
data-testid={ActivitySelectors.ActivityItemMenuBtn}
className={css({
zIndex: 10,
borderRadius: 'sm',
px: 'space.01',
_hover: {
background: 'ink.component-background-hover',
},
})}
>
<Flag spacing="space.02" reverse img={<ChevronDownIcon variant="small" />}>
<styled.span textStyle="label.03">Options</styled.span>
</Flag>
</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content
align="end"
side="bottom"
sideOffset={8}
className={css({
zIndex: 100,
width: 'settingsMenuWidth',
})}
>
<DropdownMenu.Group>
<DropdownMenu.Item
data-testid={ActivitySelectors.ActivityItemMenuIncreaseFee}
onClick={e => {
e.stopPropagation();
onIncreaseFee();
}}
>
<HStack>
<ChevronsRightIcon />
<styled.span textStyle="label.02">Increase fee</styled.span>
</HStack>
</DropdownMenu.Item>
<DropdownMenu.Item
data-testid={ActivitySelectors.ActivityItemMenuCancelTransaction}
onClick={e => {
e.stopPropagation();
onCancelTransaction();
}}
>
<HStack>
<CloseIcon />
<styled.span textStyle="label.02">Cancel transaction</styled.span>
</HStack>
</DropdownMenu.Item>
</DropdownMenu.Group>
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useLocation, useNavigate } from 'react-router-dom';
import { useMatch, useNavigate } from 'react-router-dom';

import { StacksTx } from '@leather.io/models';

Expand All @@ -20,7 +20,7 @@ import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/s
import { useIsPrivateMode } from '@app/store/settings/settings.selectors';

import { TransactionItemLayout } from '../transaction-item/transaction-item.layout';
import { IncreaseFeeButton } from './increase-fee-button';
import { StacksTransactionActionMenu } from './stacks-transaction-action-menu';
import { StacksTransactionIcon } from './stacks-transaction-icon';
import { StacksTransactionStatus } from './stacks-transaction-status';

Expand All @@ -44,11 +44,14 @@ export function StacksTransactionItem({
const currentAccount = useCurrentStacksAccount();
const isPrivate = useIsPrivateMode();

const { pathname } = useLocation();
const navigate = useNavigate();
const { whenWallet } = useWalletType();

const cancelTransactionMatch = useMatch(RouteUrls.CancelStacksTransaction);
const increaseFeeMatch = useMatch(RouteUrls.IncreaseStacksFee);

const hasTransferDetailsData = !!caption && !!title && !!value && !!link;

if (!transaction && !hasTransferDetailsData) return null;

const openTxLink = () => {
Expand All @@ -58,10 +61,21 @@ export function StacksTransactionItem({
});
};

const onIncreaseFee = () => {
const isOriginator = transaction?.sender_address === currentAccount?.address;
const isPending = transaction && isPendingTx(transaction);

const txCaption = transaction ? getTxCaption(transaction) : caption || '';
const txIcon = transaction ? <StacksTransactionIcon transaction={transaction} /> : icon;
const txTitle = transaction ? getTxTitle(transaction) : title || '';
const txValue = transaction ? getTxValue(transaction, isOriginator) : value;

function handleTransactionAction(action: 'cancel' | 'increaseFee') {
if (!transaction) return;

const routeUrl = RouteUrls.IncreaseStxFee.replace(':txid', transaction.tx_id);
const routeUrl =
action === 'increaseFee'
? RouteUrls.IncreaseStacksFee.replace(':txid', transaction.tx_id)
: RouteUrls.CancelStacksTransaction.replace(':txid', transaction.tx_id);

whenWallet({
ledger: () =>
Expand All @@ -71,28 +85,24 @@ export function StacksTransactionItem({
})(),
software: () => navigate(routeUrl),
})();
};
}

const isOriginator = transaction?.sender_address === currentAccount?.address;
const isPending = transaction && isPendingTx(transaction);
const isTransactionActionRoute = !!cancelTransactionMatch || !!increaseFeeMatch;

const txCaption = transaction ? getTxCaption(transaction) : caption || '';
const txIcon = transaction ? <StacksTransactionIcon transaction={transaction} /> : icon;
const txTitle = transaction ? getTxTitle(transaction) : title || '';
const txValue = transaction ? getTxValue(transaction, isOriginator) : value;
const increaseFeeButton = (
<IncreaseFeeButton
isEnabled={isOriginator && isPending}
isSelected={pathname === RouteUrls.IncreaseStxFee}
onIncreaseFee={onIncreaseFee}
/>
);
const txStatus = transaction && <StacksTransactionStatus transaction={transaction} />;

const rightElement =
isOriginator && isPending && !isTransactionActionRoute ? (
<StacksTransactionActionMenu
onIncreaseFee={() => handleTransactionAction('increaseFee')}
onCancelTransaction={() => handleTransactionAction('cancel')}
/>
) : undefined;

return (
<TransactionItemLayout
openTxLink={openTxLink}
rightElement={isOriginator && isPending ? increaseFeeButton : undefined}
rightElement={rightElement}
txCaption={txCaption}
txIcon={txIcon}
txStatus={txStatus}
Expand Down
7 changes: 6 additions & 1 deletion src/app/features/activity-list/components/tab-wrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ActivitySelectors } from '@tests/selectors/activity.selectors';
import { Box } from 'leather-styles/jsx';

interface ActivityListTabWrapperProps {
Expand All @@ -10,7 +11,11 @@ export function ActivityListTabWrapper({
padContent = false,
}: ActivityListTabWrapperProps) {
return (
<Box minHeight="dialogContentHeight" py={padContent ? 'space.11' : undefined}>
<Box
minHeight="dialogContentHeight"
py={padContent ? 'space.11' : undefined}
data-testid={ActivitySelectors.ActivityList}
>
{children}
</Box>
);
Expand Down

This file was deleted.

Loading
Loading