From 13880f47691351c30d9fa47136a87d50f4ee93f9 Mon Sep 17 00:00:00 2001 From: Shubham Parkhi Date: Sat, 18 May 2024 08:07:55 +0530 Subject: [PATCH 1/5] fix(web): Error message --- .../StakePanel/StakeWithdrawButton.tsx | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/web/src/pages/Courts/CourtDetails/StakePanel/StakeWithdrawButton.tsx b/web/src/pages/Courts/CourtDetails/StakePanel/StakeWithdrawButton.tsx index da7352ef1..2ce2d0958 100644 --- a/web/src/pages/Courts/CourtDetails/StakePanel/StakeWithdrawButton.tsx +++ b/web/src/pages/Courts/CourtDetails/StakePanel/StakeWithdrawButton.tsx @@ -114,13 +114,18 @@ const StakeWithdrawButton: React.FC = ({ } }; - useEffect(() => { - if (isAllowance) { - setErrorMsg(allowanceError?.shortMessage); - } else { - setErrorMsg(setStakeError?.shortMessage); - } - }, [allowanceError, setStakeError, isAllowance, isStaking, setErrorMsg]); +useEffect(() => { + let errorMessage = parsedAmount === 0n + ? "Please enter a valid amount to stake or withdraw." + : "There was an error processing your request. Please try again later."; + + if (isAllowance && allowanceError?.shortMessage) { + setErrorMsg(errorMessage); + } else if (!isAllowance && setStakeError?.shortMessage) { + setErrorMsg(errorMessage); + } +}, [allowanceError, setStakeError, isAllowance, isStaking, parsedAmount, setErrorMsg]); + const buttonProps = { [ActionType.allowance]: { From b03bc4487ccf490142b0e4c590ef5a4cfcb0fb12 Mon Sep 17 00:00:00 2001 From: Shubham Parkhi Date: Tue, 21 May 2024 02:22:00 +0530 Subject: [PATCH 2/5] refactor(web): Error handling logic --- .../CourtDetails/StakePanel/InputDisplay.tsx | 22 ++++++++++++-- .../StakePanel/StakeWithdrawButton.tsx | 30 +++++++------------ 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/web/src/pages/Courts/CourtDetails/StakePanel/InputDisplay.tsx b/web/src/pages/Courts/CourtDetails/StakePanel/InputDisplay.tsx index 4f70b3930..479bbb2a4 100644 --- a/web/src/pages/Courts/CourtDetails/StakePanel/InputDisplay.tsx +++ b/web/src/pages/Courts/CourtDetails/StakePanel/InputDisplay.tsx @@ -1,4 +1,4 @@ -import React, { useState, useMemo } from "react"; +import React, { useState, useMemo, useEffect } from "react"; import styled from "styled-components"; import { useParams } from "react-router-dom"; @@ -68,11 +68,11 @@ const InputDisplay: React.FC = ({ setAmount, }) => { const [debouncedAmount, setDebouncedAmount] = useState(""); + const [hasInteracted, setHasInteracted] = useState(false); + const [errorMsg, setErrorMsg] = useState(); useDebounce(() => setDebouncedAmount(amount), 500, [amount]); const parsedAmount = useParsedAmount(uncommify(debouncedAmount) as `${number}`); - const [errorMsg, setErrorMsg] = useState(); - const { id } = useParams(); const { address } = useAccount(); const { data: balance } = usePnkBalanceOf({ @@ -89,6 +89,18 @@ const InputDisplay: React.FC = ({ const parsedStake = formatPNK(jurorBalance?.[2] || 0n, 0, true); const isStaking = useMemo(() => action === ActionType.stake, [action]); + useEffect(() => { + if (!hasInteracted || parsedAmount === 0n) { + setErrorMsg(undefined); + } else if (isStaking && balance && parsedAmount > balance) { + setErrorMsg("Insufficient balance to stake this amount"); + } else if (!isStaking && jurorBalance && parsedAmount > jurorBalance[2]) { + setErrorMsg("Insufficient staked amount to withdraw this amount"); + } else { + setErrorMsg(undefined); + } + }, [hasInteracted, parsedAmount, isStaking, balance, jurorBalance]); + return ( <> @@ -97,6 +109,7 @@ const InputDisplay: React.FC = ({ onClick={() => { const amount = isStaking ? parsedBalance : parsedStake; setAmount(amount); + setHasInteracted(true); }} > {isStaking ? "Stake" : "Withdraw"} all @@ -108,6 +121,7 @@ const InputDisplay: React.FC = ({ value={uncommify(amount)} onChange={(e) => { setAmount(e); + setHasInteracted(true); }} placeholder={isStaking ? "Amount to stake" : "Amount to withdraw"} message={errorMsg ?? undefined} @@ -124,6 +138,8 @@ const InputDisplay: React.FC = ({ setIsSending, setIsPopupOpen, setErrorMsg, + hasInteracted, + setHasInteracted, }} /> diff --git a/web/src/pages/Courts/CourtDetails/StakePanel/StakeWithdrawButton.tsx b/web/src/pages/Courts/CourtDetails/StakePanel/StakeWithdrawButton.tsx index 2ce2d0958..f9249de27 100644 --- a/web/src/pages/Courts/CourtDetails/StakePanel/StakeWithdrawButton.tsx +++ b/web/src/pages/Courts/CourtDetails/StakePanel/StakeWithdrawButton.tsx @@ -1,4 +1,4 @@ -import React, { useMemo, useEffect } from "react"; +import React, { useMemo } from "react"; import { useParams } from "react-router-dom"; import { useAccount, usePublicClient } from "wagmi"; @@ -35,6 +35,8 @@ interface IActionButton { setAmount: (arg0: string) => void; setIsPopupOpen: (arg0: boolean) => void; setErrorMsg: (arg0: string | undefined) => void; + hasInteracted: boolean; + setHasInteracted: (arg0: boolean) => void; } const StakeWithdrawButton: React.FC = ({ @@ -43,7 +45,7 @@ const StakeWithdrawButton: React.FC = ({ isSending, setIsSending, setIsPopupOpen, - setErrorMsg, + setHasInteracted, }) => { const { id } = useParams(); const { address } = useAccount(); @@ -82,7 +84,7 @@ const StakeWithdrawButton: React.FC = ({ return 0n; }, [jurorBalance, parsedAmount, isAllowance, isStaking]); - const { config: increaseAllowanceConfig, error: allowanceError } = usePreparePnkIncreaseAllowance({ + const { config: increaseAllowanceConfig } = usePreparePnkIncreaseAllowance({ enabled: isAllowance && !isUndefined(klerosCore) && !isUndefined(targetStake) && !isUndefined(allowance), args: [klerosCore?.address, BigInt(targetStake ?? 0) - BigInt(allowance ?? 0)], }); @@ -99,7 +101,7 @@ const StakeWithdrawButton: React.FC = ({ }; const { config: setStakeConfig, error: setStakeError } = usePrepareKlerosCoreSetStake({ - enabled: !isUndefined(targetStake) && !isUndefined(id) && !isAllowance, + enabled: !isUndefined(targetStake) && !isUndefined(id) && !isAllowance && parsedAmount !== 0n, args: [BigInt(id ?? 0), targetStake], }); const { writeAsync: setStake } = useKlerosCoreSetStake(setStakeConfig); @@ -114,19 +116,6 @@ const StakeWithdrawButton: React.FC = ({ } }; -useEffect(() => { - let errorMessage = parsedAmount === 0n - ? "Please enter a valid amount to stake or withdraw." - : "There was an error processing your request. Please try again later."; - - if (isAllowance && allowanceError?.shortMessage) { - setErrorMsg(errorMessage); - } else if (!isAllowance && setStakeError?.shortMessage) { - setErrorMsg(errorMessage); - } -}, [allowanceError, setStakeError, isAllowance, isStaking, parsedAmount, setErrorMsg]); - - const buttonProps = { [ActionType.allowance]: { text: "Allow PNK", @@ -160,10 +149,13 @@ useEffect(() => { (targetStake !== 0n && targetStake < BigInt(courtDetails.court?.minStake)) || (isStaking && !isAllowance && isUndefined(setStakeConfig.request)) } - onClick={onClick} + onClick={() => { + setHasInteracted(true); + onClick(); + }} /> ); }; -export default StakeWithdrawButton; +export default StakeWithdrawButton; \ No newline at end of file From 6c8475c93d80b8bf638be998139981d267e6ec43 Mon Sep 17 00:00:00 2001 From: Shubham Parkhi Date: Tue, 21 May 2024 04:45:13 +0530 Subject: [PATCH 3/5] refactor(web): Error handling logic --- .../Courts/CourtDetails/StakePanel/InputDisplay.tsx | 10 ++-------- .../CourtDetails/StakePanel/StakeWithdrawButton.tsx | 9 +-------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/web/src/pages/Courts/CourtDetails/StakePanel/InputDisplay.tsx b/web/src/pages/Courts/CourtDetails/StakePanel/InputDisplay.tsx index 479bbb2a4..e8ac27289 100644 --- a/web/src/pages/Courts/CourtDetails/StakePanel/InputDisplay.tsx +++ b/web/src/pages/Courts/CourtDetails/StakePanel/InputDisplay.tsx @@ -68,7 +68,6 @@ const InputDisplay: React.FC = ({ setAmount, }) => { const [debouncedAmount, setDebouncedAmount] = useState(""); - const [hasInteracted, setHasInteracted] = useState(false); const [errorMsg, setErrorMsg] = useState(); useDebounce(() => setDebouncedAmount(amount), 500, [amount]); const parsedAmount = useParsedAmount(uncommify(debouncedAmount) as `${number}`); @@ -90,7 +89,7 @@ const InputDisplay: React.FC = ({ const isStaking = useMemo(() => action === ActionType.stake, [action]); useEffect(() => { - if (!hasInteracted || parsedAmount === 0n) { + if (parsedAmount === 0n) { setErrorMsg(undefined); } else if (isStaking && balance && parsedAmount > balance) { setErrorMsg("Insufficient balance to stake this amount"); @@ -99,7 +98,7 @@ const InputDisplay: React.FC = ({ } else { setErrorMsg(undefined); } - }, [hasInteracted, parsedAmount, isStaking, balance, jurorBalance]); + }, [parsedAmount, isStaking, balance, jurorBalance]); return ( <> @@ -109,7 +108,6 @@ const InputDisplay: React.FC = ({ onClick={() => { const amount = isStaking ? parsedBalance : parsedStake; setAmount(amount); - setHasInteracted(true); }} > {isStaking ? "Stake" : "Withdraw"} all @@ -121,7 +119,6 @@ const InputDisplay: React.FC = ({ value={uncommify(amount)} onChange={(e) => { setAmount(e); - setHasInteracted(true); }} placeholder={isStaking ? "Amount to stake" : "Amount to withdraw"} message={errorMsg ?? undefined} @@ -137,9 +134,6 @@ const InputDisplay: React.FC = ({ isSending, setIsSending, setIsPopupOpen, - setErrorMsg, - hasInteracted, - setHasInteracted, }} /> diff --git a/web/src/pages/Courts/CourtDetails/StakePanel/StakeWithdrawButton.tsx b/web/src/pages/Courts/CourtDetails/StakePanel/StakeWithdrawButton.tsx index f9249de27..3644d21f2 100644 --- a/web/src/pages/Courts/CourtDetails/StakePanel/StakeWithdrawButton.tsx +++ b/web/src/pages/Courts/CourtDetails/StakePanel/StakeWithdrawButton.tsx @@ -34,9 +34,6 @@ interface IActionButton { setIsSending: (arg0: boolean) => void; setAmount: (arg0: string) => void; setIsPopupOpen: (arg0: boolean) => void; - setErrorMsg: (arg0: string | undefined) => void; - hasInteracted: boolean; - setHasInteracted: (arg0: boolean) => void; } const StakeWithdrawButton: React.FC = ({ @@ -45,7 +42,6 @@ const StakeWithdrawButton: React.FC = ({ isSending, setIsSending, setIsPopupOpen, - setHasInteracted, }) => { const { id } = useParams(); const { address } = useAccount(); @@ -149,10 +145,7 @@ const StakeWithdrawButton: React.FC = ({ (targetStake !== 0n && targetStake < BigInt(courtDetails.court?.minStake)) || (isStaking && !isAllowance && isUndefined(setStakeConfig.request)) } - onClick={() => { - setHasInteracted(true); - onClick(); - }} + onClick={onClick} /> ); From 955a35dce79dd23945a9dcab68427fad511f6841 Mon Sep 17 00:00:00 2001 From: Shubham Parkhi Date: Fri, 24 May 2024 03:44:40 +0530 Subject: [PATCH 4/5] refactor(web): Error handling logic --- web/src/components/NumberInputField.tsx | 6 ++++-- .../pages/Courts/CourtDetails/StakePanel/InputDisplay.tsx | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/web/src/components/NumberInputField.tsx b/web/src/components/NumberInputField.tsx index 64460ea13..32b6a89bc 100644 --- a/web/src/components/NumberInputField.tsx +++ b/web/src/components/NumberInputField.tsx @@ -35,6 +35,7 @@ interface INumberInputField extends Omit, "on onChange?: (value: string) => void; formatter?: (value: string) => string; className?: string; + min?: number; } export const NumberInputField: React.FC = ({ @@ -45,6 +46,7 @@ export const NumberInputField: React.FC = ({ formatter, className, variant = "info", + min, }) => { const [isEditing, setIsEditing] = useState(false); @@ -61,14 +63,14 @@ export const NumberInputField: React.FC = ({ onChange?.(event.target.value); }} onBlur={toggleEditing} - {...{ value, placeholder, message, variant }} + {...{ value, placeholder, message, variant, min }} /> ) : ( )} diff --git a/web/src/pages/Courts/CourtDetails/StakePanel/InputDisplay.tsx b/web/src/pages/Courts/CourtDetails/StakePanel/InputDisplay.tsx index e8ac27289..ca6249fc6 100644 --- a/web/src/pages/Courts/CourtDetails/StakePanel/InputDisplay.tsx +++ b/web/src/pages/Courts/CourtDetails/StakePanel/InputDisplay.tsx @@ -89,8 +89,8 @@ const InputDisplay: React.FC = ({ const isStaking = useMemo(() => action === ActionType.stake, [action]); useEffect(() => { - if (parsedAmount === 0n) { - setErrorMsg(undefined); + if (parsedAmount === 0n && balance === 0n && isStaking) { + setErrorMsg("You need a non-zero PNK balance to stake"); } else if (isStaking && balance && parsedAmount > balance) { setErrorMsg("Insufficient balance to stake this amount"); } else if (!isStaking && jurorBalance && parsedAmount > jurorBalance[2]) { @@ -124,6 +124,7 @@ const InputDisplay: React.FC = ({ message={errorMsg ?? undefined} variant={!isUndefined(errorMsg) ? "error" : "info"} formatter={(number: string) => commify(roundNumberDown(Number(number)))} + min="0" /> Date: Fri, 24 May 2024 13:51:47 +0530 Subject: [PATCH 5/5] fix(web): staking-input-behaviour --- web/src/components/NumberInputField.tsx | 15 ++++++++++----- .../CourtDetails/StakePanel/InputDisplay.tsx | 5 ++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/web/src/components/NumberInputField.tsx b/web/src/components/NumberInputField.tsx index 32b6a89bc..393b71a26 100644 --- a/web/src/components/NumberInputField.tsx +++ b/web/src/components/NumberInputField.tsx @@ -35,7 +35,6 @@ interface INumberInputField extends Omit, "on onChange?: (value: string) => void; formatter?: (value: string) => string; className?: string; - min?: number; } export const NumberInputField: React.FC = ({ @@ -46,7 +45,6 @@ export const NumberInputField: React.FC = ({ formatter, className, variant = "info", - min, }) => { const [isEditing, setIsEditing] = useState(false); @@ -58,19 +56,26 @@ export const NumberInputField: React.FC = ({ {isEditing ? ( { + const value = e.currentTarget.value.replace(/[^0-9.]/g, ""); + + e.currentTarget.value = formatter ? formatter(value) : value; + return e; + }} onChange={(event: React.ChangeEvent) => { onChange?.(event.target.value); }} onBlur={toggleEditing} - {...{ value, placeholder, message, variant, min }} + value={formatter ? formatter(value ?? "0") : value} + {...{ placeholder, message, variant }} /> ) : ( )} diff --git a/web/src/pages/Courts/CourtDetails/StakePanel/InputDisplay.tsx b/web/src/pages/Courts/CourtDetails/StakePanel/InputDisplay.tsx index ca6249fc6..9e8db9a7b 100644 --- a/web/src/pages/Courts/CourtDetails/StakePanel/InputDisplay.tsx +++ b/web/src/pages/Courts/CourtDetails/StakePanel/InputDisplay.tsx @@ -89,7 +89,7 @@ const InputDisplay: React.FC = ({ const isStaking = useMemo(() => action === ActionType.stake, [action]); useEffect(() => { - if (parsedAmount === 0n && balance === 0n && isStaking) { + if (parsedAmount > 0n && balance === 0n && isStaking) { setErrorMsg("You need a non-zero PNK balance to stake"); } else if (isStaking && balance && parsedAmount > balance) { setErrorMsg("Insufficient balance to stake this amount"); @@ -123,8 +123,7 @@ const InputDisplay: React.FC = ({ placeholder={isStaking ? "Amount to stake" : "Amount to withdraw"} message={errorMsg ?? undefined} variant={!isUndefined(errorMsg) ? "error" : "info"} - formatter={(number: string) => commify(roundNumberDown(Number(number)))} - min="0" + formatter={(number: string) => (number !== "" ? commify(roundNumberDown(Number(number))) : "")} />