Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -163,12 +163,12 @@ describe('BatchSellReview', () => {
expect(getAllByText('100%')).toHaveLength(mockSelectedTokens.length);
});

it('keeps the review button disabled while quotes load', () => {
it('enables the review button while quote placeholders are available', () => {
const { getByTestId, getByText } = render(<BatchSellReview />);
const reviewButton = getByTestId(BatchSellReviewSelectorsIDs.REVIEW_BUTTON);

expect(getByText('Review')).toBeOnTheScreen();
expect(reviewButton.props.accessibilityState.disabled).toBe(true);
expect(reviewButton.props.accessibilityState.disabled).not.toBe(true);
});

it('shows UNKNOWN when there is no destination token match', () => {
Expand All @@ -180,7 +180,7 @@ describe('BatchSellReview', () => {

expect(getByText('UNKNOWN')).toBeOnTheScreen();
expect(queryByText('USDC')).toBeNull();
expect(reviewButton.props.accessibilityState.disabled).toBe(true);
expect(reviewButton.props.accessibilityState.disabled).not.toBe(true);
});

it('opens the destination stablecoin selector modal from the pill', () => {
Expand All @@ -195,6 +195,79 @@ describe('BatchSellReview', () => {
});
});

it('opens the quote details modal from the total received info button', () => {
const { getByTestId } = render(<BatchSellReview />);

fireEvent.press(
getByTestId(BatchSellReviewSelectorsIDs.TOTAL_RECEIVED_INFO_BUTTON),
);

expect(mockNavigate).toHaveBeenCalledWith(Routes.BRIDGE.MODALS.ROOT, {
screen: Routes.BRIDGE.MODALS.BATCH_SELL_QUOTE_DETAILS_MODAL,
params: {
tokenData: [
{
key: '0x1:0x1111111111111111111111111111111111111111',
tokenSymbol: 'ETH',
slippage: '2%',
receivedAmount: '-- USDC',
},
{
key: '0x1:0x2222222222222222222222222222222222222222',
tokenSymbol: 'UNI',
slippage: '2%',
receivedAmount: '-- USDC',
},
],
totalReceived: '-- USDC',
minimumReceived: '-- USDC',
isLoading: false,
},
});
});

it('opens the final review modal from the review button', () => {
const { getByTestId } = render(<BatchSellReview />);

fireEvent.press(getByTestId(BatchSellReviewSelectorsIDs.REVIEW_BUTTON));

expect(mockNavigate).toHaveBeenCalledWith(Routes.BRIDGE.MODALS.ROOT, {
screen: Routes.BRIDGE.MODALS.BATCH_SELL_FINAL_REVIEW_MODAL,
params: {
tokenData: [
{
key: '0x1:0x1111111111111111111111111111111111111111',
tokenSymbol: 'ETH',
slippage: '2%',
receivedAmount: '-- USDC',
},
{
key: '0x1:0x2222222222222222222222222222222222222222',
tokenSymbol: 'UNI',
slippage: '2%',
receivedAmount: '-- USDC',
},
],
totalReceived: '-- USDC',
minimumReceived: '-- USDC',
isLoading: false,
sourceTokens: [
{
key: '0x1:0x1111111111111111111111111111111111111111',
tokenSymbol: 'ETH',
},
{
key: '0x1:0x2222222222222222222222222222222222222222',
tokenSymbol: 'UNI',
},
],
networkFee: '1.20 USDC',
networkFeeFiat: '$1.20',
metamaskFeePercent: '0.875',
},
});
});

it('opens the slippage modal for a selected token row', () => {
const { getByTestId } = render(<BatchSellReview />);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export const BatchSellReviewSelectorsIDs = {
CONTAINER: 'batch-sell-review-container',
TOTAL_RECEIVED_INFO_BUTTON: 'batch-sell-review-total-received-info-button',
TOTAL_RECEIVED_SKELETON: 'batch-sell-review-total-received-skeleton',
DESTINATION_TOKEN_PILL: 'batch-sell-review-destination-token-pill',
TOKEN_ROW: 'batch-sell-review-token-row',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ import {
BoxFlexDirection,
BoxJustifyContent,
Button,
ButtonIcon,
ButtonIconSize,
ButtonSize,
ButtonVariant,
FontWeight,
HeaderStandard,
Icon,
IconColor,
IconName,
IconSize,
Text,
TextColor,
TextVariant,
Expand All @@ -41,18 +41,40 @@ import {
import { RootState } from '../../../../../reducers';
import { BridgeToken } from '../../types';
import { getBridgeTokenAssetId } from '../../utils/tokenUtils';
import { getBatchSellInitialSlippage } from '../../components/SlippageModal/utils';
import {
DEFAULT_BATCH_SELL_SLIPPAGE,
getBatchSellSlippage,
getSlippageDisplayValue,
} from '../../components/SlippageModal/utils';
import { BatchSellFinalReviewSourceTokenData } from '../../components/BatchSellFinalReviewModal/BatchSellFinalReviewModal.types';
import { BatchSellReviewSelectorsIDs } from './BatchSellReview.testIds';
import { BatchSellReviewTokenRow } from './BatchSellReviewTokenRow';

const DEFAULT_PERCENT = 100;
const UNKNOWN_DESTINATION_TOKEN_SYMBOL = 'UNKNOWN';
// TODO(SWAPS-4439): When Batch Sell quote fetching is wired, pass
// batchSellSlippages[assetId] into each token's BridgeController quote request.
const HAS_QUOTES = false;
const HAS_QUOTES = true;
const QUOTE_DETAILS_PLACEHOLDER_AMOUNT = '--';
const NETWORK_FEE_PLACEHOLDER = '1.20 USDC';
const NETWORK_FEE_FIAT_PLACEHOLDER = '$1.20';
const METAMASK_FEE_PERCENT = '0.875';

const getTokenKey = (token: BridgeToken) => `${token.chainId}:${token.address}`;

function getSourceTokenData(
token: BridgeToken,
): BatchSellFinalReviewSourceTokenData {
const sourceTokenData: BatchSellFinalReviewSourceTokenData = {
key: getTokenKey(token),
tokenSymbol: token.symbol,
};

if (token.image) sourceTokenData.image = token.image;

return sourceTokenData;
}

function areBatchSellSlippageMapsEqual(
first: Record<string, string | undefined>,
second: Record<string, string | undefined>,
Expand Down Expand Up @@ -121,7 +143,7 @@ export function BatchSellReview() {

if (!assetId) return slippageByAssetId;

slippageByAssetId[assetId] = getBatchSellInitialSlippage(
slippageByAssetId[assetId] = getBatchSellSlippage(
batchSellSlippages,
assetId,
);
Expand Down Expand Up @@ -153,6 +175,51 @@ export function BatchSellReview() {
});
}, [navigation]);

const getQuoteDetailsParams = useCallback(() => {
const destinationTokenSymbol =
selectedDestinationToken?.symbol ?? UNKNOWN_DESTINATION_TOKEN_SYMBOL;
const placeholderAmount = `${QUOTE_DETAILS_PLACEHOLDER_AMOUNT} ${destinationTokenSymbol}`;

return {
tokenData: selectedTokens.map((token) => {
const assetId = getBridgeTokenAssetId(token);
const slippage = assetId
? getBatchSellSlippage(batchSellSlippages, assetId)
: DEFAULT_BATCH_SELL_SLIPPAGE;

return {
key: getTokenKey(token),
tokenSymbol: token.symbol,
slippage: getSlippageDisplayValue(slippage),
receivedAmount: placeholderAmount,
};
}),
totalReceived: placeholderAmount,
minimumReceived: placeholderAmount,
isLoading: !HAS_QUOTES,
};
}, [batchSellSlippages, selectedDestinationToken?.symbol, selectedTokens]);

const handleOpenQuoteDetails = useCallback(() => {
navigation.navigate(Routes.BRIDGE.MODALS.ROOT, {
screen: Routes.BRIDGE.MODALS.BATCH_SELL_QUOTE_DETAILS_MODAL,
params: getQuoteDetailsParams(),
});
}, [getQuoteDetailsParams, navigation]);

const handleOpenFinalReview = useCallback(() => {
navigation.navigate(Routes.BRIDGE.MODALS.ROOT, {
screen: Routes.BRIDGE.MODALS.BATCH_SELL_FINAL_REVIEW_MODAL,
params: {
...getQuoteDetailsParams(),
sourceTokens: selectedTokens.map(getSourceTokenData),
networkFee: NETWORK_FEE_PLACEHOLDER,
networkFeeFiat: NETWORK_FEE_FIAT_PLACEHOLDER,
metamaskFeePercent: METAMASK_FEE_PERCENT,
},
});
}, [getQuoteDetailsParams, navigation, selectedTokens]);

const handleSlippagePress = useCallback(
(token: BridgeToken) => {
const assetId = getBridgeTokenAssetId(token);
Expand Down Expand Up @@ -208,10 +275,12 @@ export function BatchSellReview() {
>
{strings('bridge.batch_sell_total_received')}
</Text>
<Icon
name={IconName.Info}
size={IconSize.Sm}
color={IconColor.IconDefault}
<ButtonIcon
iconName={IconName.Info}
iconProps={{ color: IconColor.IconDefault }}
size={ButtonIconSize.Sm}
onPress={handleOpenQuoteDetails}
testID={BatchSellReviewSelectorsIDs.TOTAL_RECEIVED_INFO_BUTTON}
/>
</Box>
<Box
Expand Down Expand Up @@ -289,6 +358,7 @@ export function BatchSellReview() {
size={ButtonSize.Lg}
isFullWidth
isDisabled={!HAS_QUOTES}
onPress={handleOpenFinalReview}
testID={BatchSellReviewSelectorsIDs.REVIEW_BUTTON}
>
{strings('bridge.batch_sell_review')}
Expand Down
Loading
Loading