From 7affb559063d93c008bf48d4b904cd1349e00778 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Fri, 6 Oct 2023 19:36:11 -0400 Subject: [PATCH] Various updates and fixes (#21) * Make auto select text work on Safari too + cleanup * getTez: Format amounts in message * Cleanup * Handle fractional amounts * Let the slider go back to the min value when steps are large * Limit length of input amount * Allow inputting 0 to type decimal * Add some margin --- getTez/getTez.ts | 10 +- src/components/Faucet/FaucetRequestButton.tsx | 120 +++++++++--------- .../Faucet/FaucetToInputRequest.tsx | 6 +- src/components/Faucet/UserInfo.tsx | 2 +- src/lib/Utils.tsx | 34 ++--- 5 files changed, 87 insertions(+), 85 deletions(-) diff --git a/getTez/getTez.ts b/getTez/getTez.ts index 91cd455..cc731c1 100755 --- a/getTez/getTez.ts +++ b/getTez/getTez.ts @@ -308,6 +308,10 @@ const verifySolution = async ({ } /* Entrypoint */ +const formatAmount = (amount: number) => + amount.toLocaleString(undefined, { + maximumFractionDigits: 7, + }) const getTez = async (args: GetTezArgs) => { const validatedArgs = await validateArgs(args) @@ -317,7 +321,11 @@ const getTez = async (args: GetTezArgs) => { ) if (!(args.amount >= minTez && args.amount <= maxTez)) { - handleError(`Amount must be between ${minTez} and ${maxTez} tez.`) + handleError( + `Amount must be between ${formatAmount(minTez)} and ${formatAmount( + maxTez + )} tez.` + ) } if (!challengesEnabled) { diff --git a/src/components/Faucet/FaucetRequestButton.tsx b/src/components/Faucet/FaucetRequestButton.tsx index 604e496..d5f53d2 100644 --- a/src/components/Faucet/FaucetRequestButton.tsx +++ b/src/components/Faucet/FaucetRequestButton.tsx @@ -6,6 +6,7 @@ import ReCAPTCHA from "react-google-recaptcha" import PowWorker from "../../powWorker?worker&inline" import Config from "../../Config" +import { autoSelectInputText } from "../../lib/Utils" import { Challenge, ChallengeResponse, @@ -15,6 +16,24 @@ import { } from "../../lib/Types" const { minTez, maxTez } = Config.application +// Compute the step for the Tezos amount range slider. +const tezRangeStep = (() => { + const magnitude = Math.floor(Math.log10(maxTez)) + + // When maxTez is greater than 1 + if (maxTez > 1) { + return Math.max(0.5, Math.pow(10, magnitude - 2)) + } + + // When maxTez is less than or equal to 1 and minTez is fractional + const minMagnitude = Math.abs(Math.floor(Math.log10(minTez))) + return Math.max(0.001, 1 / Math.pow(10, minMagnitude)) +})() + +const formatAmount = (amount: number) => + amount.toLocaleString(undefined, { + maximumFractionDigits: 5, + }) export default function FaucetRequestButton({ address, @@ -28,10 +47,17 @@ export default function FaucetRequestButton({ status: StatusContext }) { const [amount, setAmount] = useState(minTez) - const formattedAmount = amount.toLocaleString() + const formattedAmount = formatAmount(amount) + const [isLocalLoading, setLocalLoading] = useState(false) const recaptchaRef: RefObject = useRef(null) + // Ensure that `isLocalLoading` is false if user canceled pow worker. + // `status.isLoading` will be false. + useEffect(() => { + !status.isLoading && setLocalLoading(false) + }, [status.isLoading]) + const startLoading = () => { status.setLoading(true) setLocalLoading(true) @@ -53,24 +79,29 @@ export default function FaucetRequestButton({ setLocalLoading(false) } + const validateAmount = (amount: number) => + amount >= minTez && amount <= maxTez + const updateAmount = (e: React.ChangeEvent) => { - const value = Number(e.target.value) - if (value >= minTez && value <= maxTez) { + const value = Number(e.target.value.slice(0, 16)) + if (value === 0 || validateAmount(value)) { setAmount(value) } } + const validateChallenge = (data: Partial): data is Challenge => + !!( + data.challenge && + data.difficulty && + data.challengeCounter && + data.challengesNeeded + ) + const getProgress = (challengeCounter: number, challengesNeeded: number) => String( Math.min(99, Math.floor((challengeCounter / challengesNeeded) * 100)) ) - // Ensure that `isLocalLoading` is false if user canceled pow worker. - // `status.isLoading` will be false. - useEffect(() => { - !status.isLoading && setLocalLoading(false) - }, [status.isLoading]) - const execCaptcha = async () => { const captchaToken: any = await recaptchaRef.current?.executeAsync() recaptchaRef.current?.reset() @@ -111,29 +142,17 @@ export default function FaucetRequestButton({ return verifySolution({ solution: "", nonce: 0 }) } - let { challenge, difficulty, challengeCounter, challengesNeeded } = - await getChallenge() + let challengeRes = await getChallenge() const powWorker = new PowWorker() status.setPowWorker(powWorker) try { - while ( - challenge && - difficulty && - challengeCounter && - challengesNeeded - ) { - const powSolution = await solvePow( - { challenge, difficulty, challengeCounter, challengesNeeded }, - powWorker - ) - - const response = await verifySolution(powSolution) - challenge = response.challenge - difficulty = response.difficulty - challengeCounter = response.challengeCounter - challengesNeeded = response.challengesNeeded + while (validateChallenge(challengeRes)) { + const powSolution = await solvePow(challengeRes, powWorker) + + const newChallengeRes = await verifySolution(powSolution) + challengeRes = newChallengeRes } } finally { powWorker.terminate() @@ -162,7 +181,7 @@ export default function FaucetRequestButton({ { timeout: 5000 } ) - if (data.challenge && data.difficulty && data.challengeCounter) { + if (validateChallenge(data)) { return data } else { stopLoadingError(data?.message || "Error getting challenge") @@ -195,7 +214,7 @@ export default function FaucetRequestButton({ ) // If there is another challenge - if (data.challenge && data.difficulty && data.challengeCounter) { + if (validateChallenge(data)) { return data } else if (data.txHash) { // All challenges were solved @@ -217,28 +236,7 @@ export default function FaucetRequestButton({ return {} } - const computeStep = () => { - const magnitude = Math.floor(Math.log10(maxTez)) - - switch (magnitude) { - case 1: - case 2: - return 1 - case 3: - return 10 - case 4: - return 100 - case 5: - return 1_000 - case 6: - return 10_000 - default: - return 100_000 - } - } - - const currentStep = computeStep() - const adjustedMin = Math.ceil(minTez / currentStep) * currentStep + const step = amount === tezRangeStep ? minTez : tezRangeStep return ( <> @@ -253,16 +251,14 @@ export default function FaucetRequestButton({ Select Tez Amount - - {minTez.toLocaleString()} - + {formatAmount(minTez)} - - {maxTez.toLocaleString()} - + {formatAmount(maxTez)} @@ -285,12 +279,16 @@ export default function FaucetRequestButton({ value={amount} disabled={disabled} onChange={updateAmount} - onFocus={(e) => e.target.select()} + onClick={autoSelectInputText} /> -