Commit 96f2e119 authored by tom goriunov's avatar tom goriunov Committed by GitHub

Contract interaction - floats in uint256 (#2499)

* Contract interaction - floats in uint256

Fixes #2455

* update screenshots
parent 8388b41f
......@@ -28,7 +28,9 @@ interface Props {
}
const ContractMethodFieldInput = ({ data, hideLabel, path: name, className, isDisabled, isOptional: isOptionalProp, level }: Props) => {
const ref = React.useRef<HTMLInputElement>(null);
const ref = React.useRef<HTMLInputElement>();
const [ intPower, setIntPower ] = React.useState<number>(18);
const isNativeCoin = data.fieldType === 'native_coin';
const isOptional = isOptionalProp || isNativeCoin;
......@@ -46,6 +48,8 @@ const ContractMethodFieldInput = ({ data, hideLabel, path: name, className, isDi
const hasMultiplyButton = argTypeMatchInt && Number(argTypeMatchInt.power) >= 64;
React.useImperativeHandle(field.ref, () => ref.current);
const handleChange = React.useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
const formattedValue = format(event.target.value);
field.onChange(formattedValue); // data send back to hook form
......@@ -83,6 +87,42 @@ const ContractMethodFieldInput = ({ data, hideLabel, path: name, className, isDi
setValue(name, newValue, { shouldValidate: true });
}, [ format, name, setValue ]);
const handlePaste = React.useCallback((event: React.ClipboardEvent<HTMLInputElement>) => {
if (!argTypeMatchInt || !hasMultiplyButton) {
return;
}
const value = Number(event.clipboardData.getData('text'));
if (Object.is(value, NaN)) {
return;
}
const isFloat = Number.isFinite(value) && !Number.isInteger(value);
if (!isFloat) {
return;
}
event.preventDefault();
if (field.value) {
return;
}
const newValue = value * 10 ** intPower;
const formattedValue = format(newValue.toString());
field.onChange(formattedValue);
setValue(name, formattedValue, { shouldValidate: true });
window.setTimeout(() => {
// move cursor to the end of the input
// but we have to wait for the input to get the new value
const END_OF_INPUT = 100;
ref.current?.setSelectionRange(END_OF_INPUT, END_OF_INPUT);
}, 100);
}, [ argTypeMatchInt, hasMultiplyButton, intPower, format, field, setValue, name ]);
const error = fieldState.error;
return (
......@@ -107,9 +147,14 @@ const ContractMethodFieldInput = ({ data, hideLabel, path: name, className, isDi
thousandSeparator: ' ',
decimalScale: 0,
allowNegative: !argTypeMatchInt.isUnsigned,
getInputRef: (element: HTMLInputElement) => {
ref.current = element;
},
} : {}) }
ref={ ref }
// as we use mutable ref, we have to cast it to React.LegacyRef<HTMLInputElement> to trick chakra and typescript
ref={ ref as React.LegacyRef<HTMLInputElement> | undefined }
onChange={ handleChange }
onPaste={ handlePaste }
required={ !isOptional }
isInvalid={ Boolean(error) }
placeholder={ data.type }
......@@ -148,7 +193,14 @@ const ContractMethodFieldInput = ({ data, hideLabel, path: name, className, isDi
Max
</Button>
)) }
{ hasMultiplyButton && <ContractMethodMultiplyButton onClick={ handleMultiplyButtonClick } isDisabled={ isDisabled }/> }
{ hasMultiplyButton && (
<ContractMethodMultiplyButton
onClick={ handleMultiplyButtonClick }
isDisabled={ isDisabled }
initialValue={ intPower }
onChange={ setIntPower }
/>
) }
</InputRightElement>
</InputGroup>
{ error && <Box color="error" fontSize="sm" lineHeight={ 5 } mt={ 1 }>{ error.message }</Box> }
......
......@@ -20,10 +20,12 @@ import IconSvg from 'ui/shared/IconSvg';
interface Props {
onClick: (power: number) => void;
isDisabled?: boolean;
initialValue: number;
onChange: (power: number) => void;
}
const ContractMethodMultiplyButton = ({ onClick, isDisabled }: Props) => {
const [ selectedOption, setSelectedOption ] = React.useState<number | undefined>(18);
const ContractMethodMultiplyButton = ({ onClick, isDisabled, initialValue, onChange }: Props) => {
const [ selectedOption, setSelectedOption ] = React.useState<number | undefined>(initialValue);
const [ customValue, setCustomValue ] = React.useState<number>();
const { isOpen, onToggle, onClose } = useDisclosure();
......@@ -35,13 +37,16 @@ const ContractMethodMultiplyButton = ({ onClick, isDisabled }: Props) => {
setSelectedOption((prev) => prev === id ? undefined : id);
setCustomValue(undefined);
onClose();
onChange(id);
}
}, [ onClose ]);
}, [ onClose, onChange ]);
const handleInputChange = React.useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
setCustomValue(Number(event.target.value));
const value = Number(event.target.value);
setCustomValue(value);
setSelectedOption(undefined);
}, []);
onChange(value);
}, [ onChange ]);
const value = selectedOption || customValue;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment