Properly handle decimals in supports liquidate component. (#7648)

This commit is contained in:
Franco Montenegro 2022-07-23 18:33:00 -04:00 committed by GitHub
parent 2773cbbe6e
commit 1a9743e639
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -1,6 +1,6 @@
// @flow // @flow
import * as ICONS from 'constants/icons'; import * as ICONS from 'constants/icons';
import React, { useEffect, useState } from 'react'; import React, { useCallback, useEffect, useState } from 'react';
import CreditAmount from 'component/common/credit-amount'; import CreditAmount from 'component/common/credit-amount';
import Button from 'component/button'; import Button from 'component/button';
import { Form, FormField } from 'component/common/form'; import { Form, FormField } from 'component/common/form';
@ -24,67 +24,100 @@ type Props = {
const SupportsLiquidate = (props: Props) => { const SupportsLiquidate = (props: Props) => {
const { claim, abandonSupportForClaim, handleClose, abandonClaimError } = props; const { claim, abandonSupportForClaim, handleClose, abandonClaimError } = props;
const [previewBalance, setPreviewBalance] = useState(undefined); const [previewBalance, setPreviewBalance] = useState(undefined);
const [amount, setAmount] = useState(-1); const [defaultValueAssigned, setDefaultValueAssigned] = useState(false);
const [unlockTextAmount, setUnlockTextAmount] = useState('');
const [error, setError] = useState(false); const [error, setError] = useState(false);
const initialMessage = __('How much would you like to unlock?'); const initialMessage = __('How much would you like to unlock?');
const [message, setMessage] = useState(initialMessage); const [message, setMessage] = useState(initialMessage);
const amount = Number(unlockTextAmount) || 0;
const defaultValue = previewBalance ? previewBalance * 0.25 : 0;
const keep = const keep =
amount >= 0 amount >= 0
? Boolean(previewBalance) && Number.parseFloat(String(Number(previewBalance) - Number(amount))).toFixed(8) ? Boolean(previewBalance) && Number.parseFloat(String(Number(previewBalance) - amount)).toFixed(8)
: Boolean(previewBalance) && Number.parseFloat(String((Number(previewBalance) / 4) * 3)).toFixed(8); // default unlock 25% : Boolean(previewBalance) && Number.parseFloat(String(defaultValue * 3)).toFixed(8);
const claimId = claim && claim.claim_id; const claimId = claim && claim.claim_id;
const type = claim.value_type; const type = claim.value_type;
useEffect(() => { useEffect(() => {
if (claimId && abandonSupportForClaim) { if (claimId && abandonSupportForClaim) {
abandonSupportForClaim(claimId, type, false, true).then(r => { abandonSupportForClaim(claimId, type, false, true).then((r) => {
setPreviewBalance(r.total_input); setPreviewBalance(r.total_input);
}); });
} }
}, [abandonSupportForClaim, claimId, type, setPreviewBalance]); }, [abandonSupportForClaim, claimId, type, setPreviewBalance]);
function handleSubmit() { function handleSubmit() {
abandonSupportForClaim(claimId, type, keep, false).then(r => { abandonSupportForClaim(claimId, type, keep, false).then((r) => {
if (r) { if (r) {
handleClose(); handleClose();
} }
}); });
} }
function handleChange(a) { const handleRangeChange = useCallback(
if (a === undefined || isNaN(Number(a))) { (newValue) => {
setUnlockTextAmount(String(newValue));
},
[setUnlockTextAmount]
);
const handleChangeUnlockText = useCallback(
(newValue) => {
// Get rid of all characters except digits, commas and periods.
const onlyValidAmount = newValue.replace(/[^0-9.,]+/, '');
setUnlockTextAmount(onlyValidAmount);
},
[setUnlockTextAmount]
);
const handleUnlockTextFocus = useCallback(() => {
// Get rid of empty zero when user starts typing (small ux improvement)
if (Number(unlockTextAmount) === 0) {
setUnlockTextAmount('');
}
}, [unlockTextAmount, setUnlockTextAmount]);
const handleUnlockTextBlur = useCallback(() => {
if (!unlockTextAmount || isNaN(Number(unlockTextAmount))) {
setUnlockTextAmount(previewBalance ? String(defaultValue) : '0');
}
}, [unlockTextAmount, setUnlockTextAmount, previewBalance, defaultValue]);
useEffect(() => {
if (defaultValueAssigned || !previewBalance || unlockTextAmount) {
return;
}
setUnlockTextAmount(String(defaultValue));
setDefaultValueAssigned(true);
}, [defaultValueAssigned, previewBalance, unlockTextAmount, setUnlockTextAmount, setDefaultValueAssigned]);
// Update message & error based on unlock amount.
useEffect(() => {
const unlockAmount = Number(unlockTextAmount);
const previewBalanceNumber = Number(previewBalance);
if (unlockTextAmount && isNaN(unlockAmount)) {
setMessage(__('Amount must be a number')); setMessage(__('Amount must be a number'));
setError(true); setError(true);
setAmount(0); } else if (unlockAmount > previewBalanceNumber) {
} else if (a === '') {
setAmount(0);
setError(true);
setMessage(__('Amount cannot be blank'));
} else if (Number(a) > Number(previewBalance)) {
setMessage(__('Amount cannot be more than available')); setMessage(__('Amount cannot be more than available'));
setError(false);
} else if (Number(a) === Number(previewBalance)) {
setMessage(__(`She's about to close up the library!`));
setAmount(a);
setError(false);
} else if (Number(a) > Number(previewBalance) / 2) {
setMessage(__('Your content will do better with more staked on it'));
setAmount(a);
setError(false);
} else if (Number(a) === 0) {
setMessage(__('Amount cannot be zero'));
setAmount(0);
setError(true); setError(true);
} else if (Number(a) <= Number(previewBalance) / 2) { } else if (Math.abs(unlockAmount - previewBalanceNumber) <= Number.EPSILON) {
setMessage(__(`She's about to close up the library!`));
setError(false);
} else if (unlockAmount > previewBalanceNumber / 2) {
setMessage(__('Your content will do better with more staked on it'));
setError(false);
} else if (unlockAmount === 0) {
setMessage(__('Amount cannot be zero'));
setError(true);
} else if (unlockAmount <= previewBalanceNumber / 2) {
setMessage(__('A prudent choice')); setMessage(__('A prudent choice'));
setAmount(Number(a));
setError(false); setError(false);
} else { } else {
setMessage(initialMessage); setMessage(initialMessage);
setAmount(a);
setError(false); setError(false);
} }
} }, [unlockTextAmount, previewBalance, setMessage, setError]);
return ( return (
<Card <Card
@ -140,8 +173,8 @@ const SupportsLiquidate = (props: Props) => {
min={0} min={0}
step={0.01} step={0.01}
max={previewBalance} max={previewBalance}
value={Number(amount) >= 0 ? amount : previewBalance / 4} // by default, set it to 25% of available value={amount}
onChange={e => handleChange(e.target.value)} onChange={(e) => handleRangeChange(e.target.value)}
/> />
<label className="range__label"> <label className="range__label">
<span>0</span> <span>0</span>
@ -150,9 +183,11 @@ const SupportsLiquidate = (props: Props) => {
</label> </label>
<FormField <FormField
type="text" type="text"
value={amount >= 0 ? amount || '' : previewBalance && previewBalance / 4} value={unlockTextAmount}
helper={message} helper={message}
onChange={e => handleChange(e.target.value)} onFocus={handleUnlockTextFocus}
onChange={(e) => handleChangeUnlockText(e.target.value)}
onBlur={handleUnlockTextBlur}
/> />
</Form> </Form>
)} )}