diff --git a/src/components/Form/From/AvailableActions/index.tsx b/src/components/Form/From/AvailableActions/index.tsx
index 987a192d..a1be8a49 100644
--- a/src/components/Form/From/AvailableActions/index.tsx
+++ b/src/components/Form/From/AvailableActions/index.tsx
@@ -1,21 +1,48 @@
+import Big from 'big.js';
+import { trimToMaxDecimals, USER_INPUT_MAX_DECIMALS } from '../../../../shared/parseNumbers/maxDecimals';
+import { stringifyBigWithSignificantDecimals } from '../../../../shared/parseNumbers/metric';
+
interface AvailableActionsProps {
- max?: number;
- setValue?: (n: number) => void;
+ max?: number | Big;
+ maxDecimals?: number;
+ setValue?: (n: string) => void;
hideAvailableBalance?: boolean;
}
-export const AvailableActions = ({ max, setValue, hideAvailableBalance = false }: AvailableActionsProps) => (
-
- {max !== undefined && setValue !== undefined && (
- <>
- {hideAvailableBalance ? <>> : Available: {max.toFixed(2)}}
-
-
- >
- )}
-
-);
+export const AvailableActions = ({
+ max,
+ maxDecimals = USER_INPUT_MAX_DECIMALS.PENDULUM,
+ setValue,
+ hideAvailableBalance,
+}: AvailableActionsProps) => {
+ const handleSetValue = (percentage: number) => {
+ if (max !== undefined && setValue !== undefined) {
+ const maxBig = Big(max);
+ const trimmedValue = trimToMaxDecimals(maxBig.mul(percentage).toString(), maxDecimals);
+ setValue(trimmedValue);
+ }
+ };
+
+ const handleSetHalf = () => handleSetValue(0.5);
+ const handleSetMax = () => handleSetValue(1);
+
+ return (
+
+ {max !== undefined && setValue !== undefined && (
+ <>
+ {hideAvailableBalance ? (
+ <>>
+ ) : (
+ Available: {stringifyBigWithSignificantDecimals(Big(max), 2)}
+ )}
+
+
+ >
+ )}
+
+ );
+};
diff --git a/src/components/Form/From/NumericInput/NumericInput.test.tsx b/src/components/Form/From/NumericInput/NumericInput.test.tsx
index c62c18ce..1771b930 100644
--- a/src/components/Form/From/NumericInput/NumericInput.test.tsx
+++ b/src/components/Form/From/NumericInput/NumericInput.test.tsx
@@ -50,11 +50,14 @@ describe('NumericInput Component', () => {
expect(inputElement.value).toBe('1.1');
});
- it('should work with readOnly prop', () => {
+ it('should work with readOnly prop', async () => {
const { getByPlaceholderText } = render(
-
-
handleOnKeyPress(e, maxDecimals)}
- onInput={handleOnInput}
- pattern="^[0-9]*[.,]?[0-9]*$"
- placeholder="0.0"
- readOnly={readOnly}
- spellcheck="false"
- step="any"
- type="text"
- inputmode="decimal"
- value={defaultValue}
- autoFocus={autoFocus}
- {...register}
- />
+}: NumericInputProps) => {
+ function handleOnChange(e: KeyboardEvent): void {
+ handleOnChangeNumericInput(e, maxDecimals);
+ register.onChange(e);
+ }
+
+ return (
+
-
-);
+ );
+};
diff --git a/src/components/Form/From/index.tsx b/src/components/Form/From/index.tsx
index 1f7146eb..de473eaa 100644
--- a/src/components/Form/From/index.tsx
+++ b/src/components/Form/From/index.tsx
@@ -17,7 +17,7 @@ export interface FromProps {
error?: string;
readOnly?: boolean;
disabled?: boolean;
- setValue?: (n: number) => void;
+ setValue?: (n: string) => void;
maxDecimals?: number;
};
asset: {
diff --git a/src/components/Form/From/variants/StandardFrom.test.tsx b/src/components/Form/From/variants/StandardFrom.test.tsx
new file mode 100644
index 00000000..5aac21e9
--- /dev/null
+++ b/src/components/Form/From/variants/StandardFrom.test.tsx
@@ -0,0 +1,80 @@
+import '@testing-library/jest-dom';
+import Big from 'big.js';
+import userEvent from '@testing-library/user-event';
+import { render } from '@testing-library/preact';
+import { SpacewalkPrimitivesCurrencyId } from '@polkadot/types/lookup';
+import { useForm } from 'react-hook-form';
+
+import { BlockchainAsset } from '../../../Selector/AssetSelector/helpers';
+import { stringifyBigWithSignificantDecimals } from '../../../../shared/parseNumbers/metric';
+import { USER_INPUT_MAX_DECIMALS } from '../../../../shared/parseNumbers/maxDecimals';
+import { StandardFrom } from './StandardFrom';
+import { FromProps } from '..';
+
+jest.mock('../../../../shared/AssetIcons', () => ({
+ getIcon: () => 'icon',
+}));
+
+const mockAsset: BlockchainAsset = {
+ metadata: {
+ decimals: 10,
+ name: 'name',
+ symbol: 'symbol',
+ additional: { diaKeys: { blockchain: 'blockchain', symbol: 'symbol' } },
+ },
+ currencyId: { XCM: '1' } as unknown as SpacewalkPrimitivesCurrencyId,
+};
+
+const assets: BlockchainAsset[] = [mockAsset];
+
+// Values that Javascript shows in exponential notation
+const edgeCaseMaxBalances = [9e-7, 1e-7, 1e-10, 1e21, 1e22, 0.000000025164, 0.0000000025164];
+
+const TestingComponent = ({ max }: { max: number }) => {
+ const { setValue, register } = useForm();
+
+ const defaultProps: FromProps = {
+ formControl: {
+ max: max,
+ register: register('amount'),
+ setValue: (n: string) => setValue('amount', n),
+ error: '',
+ maxDecimals: 12,
+ },
+ asset: {
+ assets: assets,
+ selectedAsset: assets[0],
+ setSelectedAsset: jest.fn(),
+ assetSuffix: 'USD',
+ },
+ description: {
+ network: 'Network',
+ },
+ badges: {},
+ };
+
+ return
;
+};
+
+describe('StandardFrom Component', () => {
+ it.each(edgeCaseMaxBalances)(
+ 'Should set numbers with default exponential notation to be decimal notation',
+ async (maxBalance) => {
+ const { getByText, getByPlaceholderText } = render(
);
+ expect(getByText('From Network')).toBeInTheDocument();
+
+ const maxButton = getByText('MAX');
+ expect(maxButton).toBeInTheDocument();
+ expect(getByText(`Available: ${stringifyBigWithSignificantDecimals(Big(maxBalance), 2)}`)).toBeInTheDocument();
+
+ await userEvent.click(maxButton);
+
+ const inputElement = getByPlaceholderText('0.0');
+ expect(inputElement).toBeInTheDocument();
+
+ expect(getByPlaceholderText('0.0')).toHaveValue(
+ Big(maxBalance.toFixed(USER_INPUT_MAX_DECIMALS.PENDULUM)).toString(),
+ );
+ },
+ );
+});
diff --git a/src/components/Form/From/variants/StandardFrom.tsx b/src/components/Form/From/variants/StandardFrom.tsx
index 8f1e7fdb..4b65e15c 100644
--- a/src/components/Form/From/variants/StandardFrom.tsx
+++ b/src/components/Form/From/variants/StandardFrom.tsx
@@ -37,7 +37,7 @@ export const StandardFrom = ({