Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

fix: coin input value being cut by bottom line balance #286

Merged
merged 8 commits into from
Jun 14, 2022
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ node_modules

# testing
coverage
cypress
/cypress

# next.js
.next/
Expand Down
2 changes: 0 additions & 2 deletions packages/app/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
.env.test
cypress/videos/
cypress/screenshots/
33 changes: 17 additions & 16 deletions packages/app/cypress/e2e/App.cy.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
describe('App flow', () => {
it('should execute whole app flow', () => {
describe('End-to-end Test: 😁 Happy Path', () => {
it('should execute whole app basic flow', () => {
cy.visit('/');

cy.contains('button', /Launch app/i).click();
Expand Down Expand Up @@ -43,25 +43,25 @@ describe('App flow', () => {
if (hasPoolCreated) {
// validate add liquidity
cy.contains('Enter Ether amount');
cy.get('[aria-label="Coin From Input"]').type('0.2');
cy.getByAriaLabel('Coin From Input').type('0.2');

// make sure preview output box shows up
cy.get('[aria-label="preview-add-liquidity-output"]');
cy.getByAriaLabel('Preview Add Liquidity Output');

// make sure pool price box shows up
cy.get('[aria-label="pool-price"]');
cy.getByAriaLabel('Pool Price Box');
cy.contains('button', 'Add liquidity').click();
} else {
// validate create pool
cy.contains('Enter Ether amount');
cy.get('[aria-label="Coin From Input"]').type('0.2');
cy.get('[aria-label="Coin To Input"]').type('190');
cy.getByAriaLabel('Coin From Input').type('0.2');
cy.getByAriaLabel('Coin To Input').type('190');

// make sure preview output box shows up
cy.get('[aria-label="preview-add-liquidity-output"]');
cy.getByAriaLabel('Preview Add Liquidity Output');

// make sure pool price box shows up
cy.get('[aria-label="pool-price"]');
cy.getByAriaLabel('Pool Price Box');
cy.contains('button', 'Create liquidity').click();
}

Expand All @@ -71,22 +71,23 @@ describe('App flow', () => {
// validate swap
cy.contains('button', 'Swap').click();
cy.contains('Enter amount');
cy.get('[aria-label="Coin From Input"]').type('0.1');
cy.getByAriaLabel('Coin From Input').type('0.1');
// make sure preview output box shows up
cy.get('[aria-label="preview-swap-output"]');
cy.getByAriaLabel('Preview Swap Output');

// make sure "swap" button comes from inside swap page only
cy.contains('[aria-label="Swap button"]', 'Swap').click();
// execute swap operation
cy.getByAriaLabel('Swap button').click();
cy.contains('Swap made successfully!');

// validate remove liquidity
cy.contains('button', 'Pool').click();
cy.contains('button', 'Remove liquidity').click();
cy.get('.coinSelector--maxButton').click();
cy.getByAriaLabel('Set Maximun Balance').click();
//
// make sure preview output box shows up
cy.get('[aria-label="preview-remove-liquidity-output"]');
cy.getByAriaLabel('Preview Remove Liquidity Output');
// make sure current positions box shows up
cy.get('[aria-label="pool-current-position"]');
cy.getByAriaLabel('Pool Current Position');
cy.contains('button', 'Remove liquidity').click();
cy.contains('Liquidity removed successfully!');
});
Expand Down
4 changes: 4 additions & 0 deletions packages/app/cypress/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,7 @@
// }
// }
// }

Cypress.Commands.add('getByAriaLabel', (selector, options) =>
cy.get(`[aria-label="${selector}"]`, options)
);
16 changes: 16 additions & 0 deletions packages/app/cypress/support/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/// <reference types="cypress" />

declare namespace Cypress {
interface Chainable {
/**
* Get element by aria-label
* @example
* cy.getByAriaLabel('Aria Label');
* cy.getByAriaLabel('Aria Label', { log: false, timeout: 6000 });
*/
getByAriaLabel(
ariaLabel: string,
options?: Partial<Loggable & Timeoutable & Withinable & Shadow>
): Chainable<JQuery<E>>;
}
}
5 changes: 5 additions & 0 deletions packages/app/src/styles/components/coin-balance.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@layer components {
.coinBalance--maxButton {
@apply text-xs py-0 px-1 h-auto bg-primary-800/60 text-primary-500 hover:bg-primary-800;
}
}
2 changes: 1 addition & 1 deletion packages/app/src/styles/components/coin-input.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@layer components {
.coinInput {
@apply flex bg-gray-700 rounded-2xl p-2 border border-gray-700;
@apply bg-gray-700 rounded-2xl p-2 border border-gray-700;
}
.coinInput--input {
@apply w-[100px] flex-1 ml-2 h-10 bg-transparent placeholder:text-gray-300;
Expand Down
3 changes: 0 additions & 3 deletions packages/app/src/styles/components/coin-selector.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,4 @@
.coinSelector--root {
@apply flex flex-col items-end;
}
.coinSelector--maxButton {
@apply text-xs py-0 px-1 h-auto bg-primary-800/60 text-primary-500 hover:bg-primary-800;
}
}
2 changes: 0 additions & 2 deletions packages/app/src/systems/Core/components/AssetItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ export function AssetItem({ coin }: AssetItemProps) {
coin,
amount: coin.amount,
isReadOnly: true,
showBalance: false,
showMaxButton: false,
});

return (
Expand Down
58 changes: 58 additions & 0 deletions packages/app/src/systems/Core/components/CoinBalance.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { useMemo } from "react";

import { useBalances } from "../hooks";
import { parseToFormattedNumber } from "../utils";

import { Button, Tooltip } from "~/systems/UI";
import type { Coin } from "~/types";

export type CoinBalanceProps = {
coin?: Coin | null;
showMaxButton?: boolean;
onSetMaxBalance?: () => void;
gasFee?: bigint | null;
};

export const CoinBalance = ({
coin,
showMaxButton = true,
onSetMaxBalance,
gasFee,
}: CoinBalanceProps) => {
const { data: balances } = useBalances({ enabled: true });

const balance = useMemo(() => {
const coinBalance = balances?.find(
(item) => item.assetId === coin?.assetId
);
return parseToFormattedNumber(coinBalance?.amount || BigInt(0));
}, [balances, coin?.assetId]);

return (
<div className="flex items-center justify-end gap-2 mt-2 whitespace-nowrap">
<div
className="text-xs text-gray-400"
aria-label={`${coin?.symbol} balance`}
>
Balance: {balance}
</div>
{showMaxButton && (
<Tooltip
content={`Max = ${balance}(${coin?.symbol} balance)${
gasFee ? ` - ${parseToFormattedNumber(gasFee)}(network fee)` : ``
}`}
>
<Button
aria-label="Set Maximun Balance"
size="sm"
onPress={onSetMaxBalance}
className="text-xs py-0 px-1 h-auto bg-primary-800/60 text-primary-500 hover:bg-primary-800"
variant="ghost"
>
Max
</Button>
</Tooltip>
)}
</div>
);
};
83 changes: 46 additions & 37 deletions packages/app/src/systems/Core/components/CoinInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
ZERO,
} from "../utils";

import type { CoinBalanceProps } from "./CoinBalance";
import type { CoinSelectorProps } from "./CoinSelector";

import { DECIMAL_UNITS } from "~/config";
Expand All @@ -34,8 +35,6 @@ type UseCoinParams = {
/**
* Coins for <CoinSelector />
*/
showBalance?: boolean;
showMaxButton?: boolean;
onChangeCoin?: (coin: Coin) => void;
disableWhenEth?: boolean;
};
Expand All @@ -46,6 +45,7 @@ export type UseCoinInput = {
setGasFee: React.Dispatch<React.SetStateAction<bigint | null>>;
getInputProps: () => CoinInputProps;
getCoinSelectorProps: () => CoinSelectorProps;
getCoinBalanceProps: () => CoinBalanceProps;
formatted: string;
hasEnoughBalance: boolean;
};
Expand Down Expand Up @@ -77,8 +77,6 @@ export function useCoinInput({
gasFee: initialGasFee,
isReadOnly,
onInput,
showBalance,
showMaxButton,
onChangeCoin,
disableWhenEth,
...params
Expand Down Expand Up @@ -131,13 +129,7 @@ export function useCoinInput({
return {
coin,
isReadOnly,
showBalance,
showMaxButton,
onChange: onChangeCoin,
onSetMaxBalance: () => {
onInput?.();
handleInputPropsChange(formatValue(getSafeMaxBalance()));
},
...(disableWhenEth &&
isEth && {
isReadOnly: true,
Expand All @@ -146,6 +138,17 @@ export function useCoinInput({
} as CoinSelectorProps;
}

function getCoinBalanceProps() {
return {
coin,
gasFee,
onSetMaxBalance: () => {
onInput?.();
handleInputPropsChange(formatValue(getSafeMaxBalance()));
},
} as CoinBalanceProps;
}

useEffect(() => {
// Enable value initialAmount to be null
if (initialAmount !== undefined) setAmount(initialAmount);
Expand All @@ -157,6 +160,7 @@ export function useCoinInput({
setGasFee,
getInputProps,
getCoinSelectorProps,
getCoinBalanceProps,
formatted: formatValue(amount),
hasEnoughBalance: getSafeMaxBalance() >= (amount || ZERO),
};
Expand All @@ -173,9 +177,10 @@ type CoinInputProps = Omit<UseCoinParams, "onChange"> &
displayType: DisplayType;
autoFocus?: boolean;
isLoading?: boolean;
rightElement?: ReactNode;
isAllowed?: (values: NumberFormatValues) => boolean;
onChange?: (val: string) => void;
rightElement?: ReactNode;
bottomElement?: ReactNode;
};

export const CoinInput = forwardRef<HTMLInputElement, CoinInputProps>(
Expand All @@ -189,6 +194,7 @@ export const CoinInput = forwardRef<HTMLInputElement, CoinInputProps>(
autoFocus,
isLoading,
rightElement,
bottomElement,
...props
},
ref
Expand All @@ -204,32 +210,35 @@ export const CoinInput = forwardRef<HTMLInputElement, CoinInputProps>(

return (
<div className="coinInput">
{isLoading ? (
<div className="flex-1">
<Spinner className="self-start mt-2 ml-2" variant="base" />
</div>
) : (
<NumberFormat
{...props}
autoFocus={autoFocus}
getInputRef={ref}
allowNegative={false}
defaultValue={initialValue}
value={getRightValue(value || "", displayType)}
displayType={displayType}
isAllowed={isAllowed}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
onChange?.(e.target.value);
setValue(e.target.value);
}}
decimalScale={DECIMAL_UNITS}
placeholder="0"
className="coinInput--input"
thousandSeparator={false}
onInput={onInput}
/>
)}
{rightElement}
<div className="flex">
{isLoading ? (
<div className="flex-1">
<Spinner className="self-start mt-2 ml-2" variant="base" />
</div>
) : (
<NumberFormat
{...props}
autoFocus={autoFocus}
getInputRef={ref}
allowNegative={false}
defaultValue={initialValue}
value={getRightValue(value || "", displayType)}
displayType={displayType}
isAllowed={isAllowed}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
onChange?.(e.target.value);
setValue(e.target.value);
}}
decimalScale={DECIMAL_UNITS}
placeholder="0"
className="coinInput--input"
thousandSeparator={false}
onInput={onInput}
/>
)}
{rightElement}
</div>
{bottomElement}
</div>
);
}
Expand Down
Loading