Skip to content
Merged
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 @@ -774,6 +774,24 @@ describe('BuildQuote View', () => {
screen.getByTestId(BuildQuoteSelectors.AMOUNT_INPUT),
).toHaveTextContent(`${denomSymbol}2`);
});

it('shows and hides the live input cursor based on focus', () => {
render(BuildQuote);

expect(
screen.queryByTestId(BuildQuoteSelectors.AMOUNT_INPUT_CURSOR),
).not.toBeOnTheScreen();

fireEvent.press(screen.getByTestId(BuildQuoteSelectors.AMOUNT_INPUT));
expect(
screen.getByTestId(BuildQuoteSelectors.AMOUNT_INPUT_CURSOR),
).toBeOnTheScreen();

fireEvent.press(getByRoleButton('Done'));
expect(
screen.queryByTestId(BuildQuoteSelectors.AMOUNT_INPUT_CURSOR),
).not.toBeOnTheScreen();
});
});

describe('Amount to sell input', () => {
Expand Down Expand Up @@ -853,7 +871,7 @@ describe('BuildQuote View', () => {
fireEvent.press(getByRoleButton(`${initialAmount} ${symbol}`));
expect(
screen.queryByText('This amount is higher than your balance'),
).toBeNull();
).not.toBeOnTheScreen();
});

it('updates the amount input with quick amount buttons', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import enContent from '../../../../../../../locales/languages/en.json';

export const BuildQuoteSelectors = {
AMOUNT_INPUT: 'amount-input',
AMOUNT_INPUT_CURSOR: 'amount-input-cursor',
AMOUNT_TO_BUY_LABEL: enContent.fiat_on_ramp_aggregator.amount_to_buy,
AMOUNT_TO_SELL_LABEL: enContent.fiat_on_ramp_aggregator.amount_to_sell,
GET_QUOTES_BUTTON: enContent.fiat_on_ramp_aggregator.get_quotes,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,7 @@ const BuildQuote = () => {
amountNumber > 0 && (!amountIsValid || amountIsOverGas)
}
currencyCode={isBuy ? currentFiatCurrency?.symbol : undefined}
tokenSymbol={isSell ? selectedAsset?.symbol : undefined}
onPress={onAmountInputPress}
loading={
isFetchingRegions ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1057,6 +1057,7 @@ exports[`BuildQuote View Balance display displays balance from useBalance for no
testID="listitemcolumn"
>
<TouchableOpacity
accessibilityLabel="$0"
accessibilityRole="button"
accessible={true}
hitSlop={
Expand Down Expand Up @@ -5303,6 +5304,7 @@ exports[`BuildQuote View Crypto Currency Data renders the loading page when cryp
testID="listitemcolumn"
>
<TouchableOpacity
accessibilityLabel="$0"
accessibilityRole="button"
accessible={true}
hitSlop={
Expand Down Expand Up @@ -8250,6 +8252,7 @@ exports[`BuildQuote View Fiat Currency Data renders the loading page when fiats
testID="listitemcolumn"
>
<TouchableOpacity
accessibilityLabel="$0"
accessibilityRole="button"
accessible={true}
hitSlop={
Expand Down Expand Up @@ -11281,6 +11284,7 @@ exports[`BuildQuote View Payment Method Data renders no icons if there are no pa
testID="listitemcolumn"
>
<TouchableOpacity
accessibilityLabel="$0"
accessibilityRole="button"
accessible={true}
hitSlop={
Expand Down Expand Up @@ -13680,6 +13684,7 @@ exports[`BuildQuote View Payment Method Data renders the loading page when payme
testID="listitemcolumn"
>
<TouchableOpacity
accessibilityLabel="$0"
accessibilityRole="button"
accessible={true}
hitSlop={
Expand Down Expand Up @@ -16603,6 +16608,7 @@ exports[`BuildQuote View Regions data renders the loading page when regions are
testID="listitemcolumn"
>
<TouchableOpacity
accessibilityLabel="$0"
accessibilityRole="button"
accessible={true}
hitSlop={
Expand Down Expand Up @@ -18975,6 +18981,7 @@ exports[`BuildQuote View renders correctly 1`] = `
testID="listitemcolumn"
>
<TouchableOpacity
accessibilityLabel="$0"
accessibilityRole="button"
accessible={true}
hitSlop={
Expand Down Expand Up @@ -21403,6 +21410,7 @@ exports[`BuildQuote View renders correctly 2`] = `
testID="listitemcolumn"
>
<TouchableOpacity
accessibilityLabel="0 ETH"
accessibilityRole="button"
accessible={true}
hitSlop={
Expand Down
21 changes: 21 additions & 0 deletions app/components/UI/Ramp/Aggregator/components/AmountInput.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import AmountInput from './AmountInput';
import { TouchableOpacity } from 'react-native';
import renderWithProvider from '../../../../../util/test/renderWithProvider';
import { backgroundState } from '../../../../../util/test/initial-root-state';
import { BuildQuoteSelectors } from '../Views/BuildQuote/BuildQuote.testIds';

const defaultState = {
engine: {
Expand Down Expand Up @@ -80,6 +81,26 @@ describe('AmountInput', () => {
expect(screen.toJSON()).toMatchSnapshot();
});

it('shows live cursor when input is highlighted', () => {
renderWithProvider(<AmountInput {...mockProps} highlighted />, {
state: defaultState,
});

expect(
screen.getByTestId(BuildQuoteSelectors.AMOUNT_INPUT_CURSOR),
).toBeOnTheScreen();
});

it('does not show live cursor when input is not highlighted', () => {
renderWithProvider(<AmountInput {...mockProps} />, {
state: defaultState,
});

expect(
screen.queryByTestId(BuildQuoteSelectors.AMOUNT_INPUT_CURSOR),
).not.toBeOnTheScreen();
});

it('does not call onPress when loading', () => {
const mockOnPress = jest.fn();
renderWithProvider(
Expand Down
172 changes: 131 additions & 41 deletions app/components/UI/Ramp/Aggregator/components/AmountInput.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { StyleSheet, TouchableOpacity } from 'react-native';
import { Animated, StyleSheet, TouchableOpacity, View } from 'react-native';
import Box from './Box';
import SkeletonText from './SkeletonText';
import DownChevronText from './DownChevronText';
Expand All @@ -12,12 +12,23 @@ import Text, {
TextColor,
} from '../../../../../component-library/components/Texts/Text';
import { BuildQuoteSelectors } from '../Views/BuildQuote/BuildQuote.testIds';
import { useTheme } from '../../../../../util/theme';
import { useBlinkingCursor } from '../../hooks/useBlinkingCursor';

const styles = StyleSheet.create({
amount: {
fontSize: 24,
lineHeight: 32,
},
amountWithCursor: {
alignItems: 'center',
flexDirection: 'row',
},
cursor: {
height: 24,
marginHorizontal: 1,
width: 1,
},
chevron: {
flex: 0,
marginLeft: 8,
Expand All @@ -32,6 +43,7 @@ export interface Props {
highlighted?: boolean;
loading?: boolean;
highlightedError?: boolean;
tokenSymbol?: string;
// TODO: Replace "any" with type
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onPress?: () => any;
Expand All @@ -48,56 +60,134 @@ const AmountInput: React.FC<Props> = ({
highlighted,
loading,
highlightedError,
tokenSymbol,
onPress,
onCurrencyPress,
}: Props) => (
<Box label={label} highlighted={highlighted} compact>
<ListItem>
<ListItemColumn widthType={WidthType.Fill}>
<TouchableOpacity
accessible
accessibilityRole="button"
onPress={onPress}
hitSlop={{ top: 20, left: 20, right: 20, bottom: 20 }}
testID={BuildQuoteSelectors.AMOUNT_INPUT}
>
{loading ? (
<SkeletonText medium />
) : (
}: Props) => {
const { colors } = useTheme();
const cursorOpacity = useBlinkingCursor(highlighted);

const textColor = highlightedError ? TextColor.Error : TextColor.Default;

const renderAmountContent = () => {
if (loading) {
return <SkeletonText medium />;
}

if (highlighted) {
const cursorView = (
<Animated.View
style={[
styles.cursor,
{
backgroundColor: colors.primary.default,
opacity: cursorOpacity,
},
]}
testID={BuildQuoteSelectors.AMOUNT_INPUT_CURSOR}
/>
);

// For sell: show "12.5 | ETH" with cursor before token symbol
if (tokenSymbol) {
const suffix = ` ${tokenSymbol}`;
const amountWithoutSymbol = amount.endsWith(suffix)
? amount.slice(0, -suffix.length)
: amount.replace(tokenSymbol, '').trimEnd();

return (
<View style={styles.amountWithCursor}>
<Text
numberOfLines={1}
adjustsFontSizeToFit
style={styles.amount}
variant={TextVariant.BodyMDMedium}
color={highlightedError ? TextColor.Error : TextColor.Default}
color={textColor}
>
{currencySymbol || ''}
{amount}
{amountWithoutSymbol}
</Text>
)}
</TouchableOpacity>
</ListItemColumn>

{onCurrencyPress ? (
<ListItemColumn style={styles.chevron}>
{loading ? (
<SkeletonText small />
) : (
<TouchableOpacity
accessible
accessibilityRole="button"
disabled={!onCurrencyPress}
onPress={onCurrencyPress}
hitSlop={{ top: 20, left: 20, right: 20, bottom: 20 }}
testID={BuildQuoteSelectors.SELECT_CURRENCY}
{cursorView}
<Text
style={styles.amount}
variant={TextVariant.BodyMDMedium}
color={textColor}
>
<DownChevronText text={currencyCode} />
</TouchableOpacity>
)}
{' '}
{tokenSymbol}
</Text>
</View>
);
}

// For buy: show "$100 |" with cursor after amount
return (
<View style={styles.amountWithCursor}>
<Text
numberOfLines={1}
adjustsFontSizeToFit
style={styles.amount}
variant={TextVariant.BodyMDMedium}
color={textColor}
>
{currencySymbol || ''}
{amount}
</Text>
{cursorView}
</View>
);
}

return (
<Text
numberOfLines={1}
adjustsFontSizeToFit
style={styles.amount}
variant={TextVariant.BodyMDMedium}
color={textColor}
>
{currencySymbol || ''}
{amount}
</Text>
);
};

return (
<Box label={label} highlighted={highlighted} compact>
<ListItem>
<ListItemColumn widthType={WidthType.Fill}>
<TouchableOpacity
accessible
accessibilityRole="button"
accessibilityLabel={`${currencySymbol || ''}${amount}`}
onPress={onPress}
hitSlop={{ top: 20, left: 20, right: 20, bottom: 20 }}
testID={BuildQuoteSelectors.AMOUNT_INPUT}
>
{renderAmountContent()}
</TouchableOpacity>
</ListItemColumn>
) : null}
</ListItem>
</Box>
);

{onCurrencyPress ? (
<ListItemColumn style={styles.chevron}>
{loading ? (
<SkeletonText small />
) : (
<TouchableOpacity
accessible
accessibilityRole="button"
disabled={!onCurrencyPress}
onPress={onCurrencyPress}
hitSlop={{ top: 20, left: 20, right: 20, bottom: 20 }}
testID={BuildQuoteSelectors.SELECT_CURRENCY}
>
<DownChevronText text={currencyCode} />
</TouchableOpacity>
)}
</ListItemColumn>
) : null}
</ListItem>
</Box>
);
};

export default AmountInput;
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ exports[`AmountInput renders correctly 1`] = `
testID="listitemcolumn"
>
<TouchableOpacity
accessibilityLabel="$100.50"
accessibilityRole="button"
accessible={true}
hitSlop={
Expand Down Expand Up @@ -176,6 +177,7 @@ exports[`AmountInput renders correctly with currency selector 1`] = `
testID="listitemcolumn"
>
<TouchableOpacity
accessibilityLabel="$100.50"
accessibilityRole="button"
accessible={true}
hitSlop={
Expand Down Expand Up @@ -359,6 +361,7 @@ exports[`AmountInput renders loading state correctly 1`] = `
testID="listitemcolumn"
>
<TouchableOpacity
accessibilityLabel="$100.50"
accessibilityRole="button"
accessible={true}
hitSlop={
Expand Down Expand Up @@ -476,6 +479,7 @@ exports[`AmountInput renders loading state correctly with currency selector 1`]
testID="listitemcolumn"
>
<TouchableOpacity
accessibilityLabel="$100.50"
accessibilityRole="button"
accessible={true}
hitSlop={
Expand Down
Loading
Loading