diff --git a/src/custom/pages/Claim/FooterNavButtons.tsx b/src/custom/pages/Claim/FooterNavButtons.tsx index 7045543fd..a913a5bef 100644 --- a/src/custom/pages/Claim/FooterNavButtons.tsx +++ b/src/custom/pages/Claim/FooterNavButtons.tsx @@ -1,3 +1,4 @@ +import { useMemo } from 'react' import { Trans } from '@lingui/macro' import { isAddress } from '@ethersproject/address' import { useClaimDispatchers, useClaimState } from 'state/claim/hooks' @@ -33,6 +34,7 @@ export default function FooterNavButtons({ // claiming claimStatus, // investment + investFlowData, investFlowStep, isInvestFlowActive, // table select change @@ -45,6 +47,10 @@ export default function FooterNavButtons({ setIsInvestFlowActive, } = useClaimDispatchers() + const hasError = useMemo(() => { + return investFlowData.some(({ error }) => Boolean(error)) + }, [investFlowData]) + const isInputAddressValid = isAddress(resolvedAddress || '') // User is connected and has some unclaimed claims @@ -86,7 +92,7 @@ export default function FooterNavButtons({ Approve tokens ) : investFlowStep === 1 ? ( - setInvestFlowStep(2)}> + setInvestFlowStep(2)} disabled={hasError}> Review ) : ( diff --git a/src/custom/pages/Claim/InvestmentFlow/InvestOption.tsx b/src/custom/pages/Claim/InvestmentFlow/InvestOption.tsx index 2863fa21b..606e564c0 100644 --- a/src/custom/pages/Claim/InvestmentFlow/InvestOption.tsx +++ b/src/custom/pages/Claim/InvestmentFlow/InvestOption.tsx @@ -28,7 +28,7 @@ enum ErrorMsgs { export default function InvestOption({ approveData, claim, optionIndex }: InvestOptionProps) { const { currencyAmount, price, cost: maxCost } = claim - const { updateInvestAmount } = useClaimDispatchers() + const { updateInvestAmount, updateInvestError } = useClaimDispatchers() const { investFlowData, activeClaimAccount } = useClaimState() const { handleSetError, handleCloseError, ErrorModal } = useErrorModal() @@ -37,9 +37,23 @@ export default function InvestOption({ approveData, claim, optionIndex }: Invest const [percentage, setPercentage] = useState('0') const [typedValue, setTypedValue] = useState('0') - const [inputError, setInputError] = useState('') const investedAmount = investFlowData[optionIndex].investedAmount + const inputError = investFlowData[optionIndex].error + + // Syntactic sugar fns for setting/resetting global state + const setInvestedAmount = useCallback( + (amount: string) => updateInvestAmount({ index: optionIndex, amount }), + [optionIndex, updateInvestAmount] + ) + const setInputError = useCallback( + (error: string) => updateInvestError({ index: optionIndex, error }), + [optionIndex, updateInvestError] + ) + const resetInputError = useCallback( + () => updateInvestError({ index: optionIndex, error: undefined }), + [optionIndex, updateInvestError] + ) const token = currencyAmount?.currency const balance = useCurrencyBalance(account || undefined, token) @@ -56,25 +70,25 @@ export default function InvestOption({ approveData, claim, optionIndex }: Invest const value = maxCost.greaterThan(balance) ? balance : maxCost const amount = value.quotient.toString() - updateInvestAmount({ index: optionIndex, amount }) + setInvestedAmount(amount) setTypedValue(value.toExact() || '') - setInputError('') + resetInputError() setPercentage(_formatPercentage(calculatePercentage(balance, maxCost))) - }, [balance, maxCost, noBalance, optionIndex, updateInvestAmount]) + }, [balance, maxCost, noBalance, resetInputError, setInvestedAmount]) // on input field change handler const onInputChange = useCallback( (value: string) => { setTypedValue(value) - setInputError('') + resetInputError() // parse to CurrencyAmount const parsedAmount = tryParseAmount(value, token) // no amount/necessary params, return 0 if (!parsedAmount || !maxCost || !balance || !token) { - updateInvestAmount({ index: optionIndex, amount: '0' }) + setInvestedAmount('0') setPercentage('0') return } @@ -86,18 +100,18 @@ export default function InvestOption({ approveData, claim, optionIndex }: Invest if (errorMsg) { setInputError(errorMsg) - updateInvestAmount({ index: optionIndex, amount: '0' }) + setInvestedAmount('0') setPercentage('0') return } // update redux state with new investAmount value - updateInvestAmount({ index: optionIndex, amount: parsedAmount.quotient.toString() }) + setInvestedAmount(parsedAmount.quotient.toString()) // update the local state with percentage value setPercentage(_formatPercentage(calculatePercentage(parsedAmount, maxCost))) }, - [balance, maxCost, optionIndex, token, updateInvestAmount] + [balance, maxCost, resetInputError, setInputError, setInvestedAmount, token] ) // Cache approveData methods @@ -142,7 +156,7 @@ export default function InvestOption({ approveData, claim, optionIndex }: Invest setMaxAmount() } } - }, [balance, isSelfClaiming, maxCost, setMaxAmount]) + }, [balance, isSelfClaiming, maxCost, optionIndex, setInputError, setMaxAmount]) // this will set input and percentage value if you go back from the review page useEffect(() => { diff --git a/src/custom/state/claim/actions.ts b/src/custom/state/claim/actions.ts index 85c037b01..01bd3582d 100644 --- a/src/custom/state/claim/actions.ts +++ b/src/custom/state/claim/actions.ts @@ -25,6 +25,7 @@ export type ClaimActions = { setInvestFlowStep: (payload: number) => void initInvestFlowData: () => void updateInvestAmount: (payload: { index: number; amount: string }) => void + updateInvestError: (payload: { index: number; error: string | undefined }) => void // claim row selection setSelected: (payload: number[]) => void @@ -51,7 +52,10 @@ export const updateInvestAmount = createAction<{ index: number amount: string }>('claim/updateInvestAmount') - +export const updateInvestError = createAction<{ + index: number + error: string | undefined +}>('claim/updateInvestError') // claim row selection export const setSelected = createAction('claim/setSelected') export const setSelectedAll = createAction('claim/setSelectedAll') diff --git a/src/custom/state/claim/hooks/index.ts b/src/custom/state/claim/hooks/index.ts index 70bda0727..d5ce0f0aa 100644 --- a/src/custom/state/claim/hooks/index.ts +++ b/src/custom/state/claim/hooks/index.ts @@ -53,6 +53,7 @@ import { setSelectedAll, ClaimStatus, resetClaimUi, + updateInvestError, } from '../actions' import { EnhancedUserClaimData } from 'pages/Claim/types' import { supportedChainId } from 'utils/supportedChainId' @@ -767,6 +768,8 @@ export function useClaimDispatchers() { setInvestFlowStep: (payload: number) => dispatch(setInvestFlowStep(payload)), initInvestFlowData: () => dispatch(initInvestFlowData()), updateInvestAmount: (payload: { index: number; amount: string }) => dispatch(updateInvestAmount(payload)), + updateInvestError: (payload: { index: number; error: string | undefined }) => + dispatch(updateInvestError(payload)), // claim row selection setSelected: (payload: number[]) => dispatch(setSelected(payload)), setSelectedAll: (payload: boolean) => dispatch(setSelectedAll(payload)), diff --git a/src/custom/state/claim/reducer.ts b/src/custom/state/claim/reducer.ts index 4f308437c..6f48b3cdb 100644 --- a/src/custom/state/claim/reducer.ts +++ b/src/custom/state/claim/reducer.ts @@ -14,6 +14,7 @@ import { setSelectedAll, resetClaimUi, ClaimStatus, + updateInvestError, } from './actions' export const initialState: ClaimState = { @@ -39,6 +40,7 @@ export const initialState: ClaimState = { export type InvestClaim = { index: number investedAmount: string + error?: string } export type ClaimState = { @@ -101,6 +103,9 @@ export default createReducer(initialState, (builder) => .addCase(updateInvestAmount, (state, { payload: { index, amount } }) => { state.investFlowData[index].investedAmount = amount }) + .addCase(updateInvestError, (state, { payload: { index, error } }) => { + state.investFlowData[index].error = error + }) .addCase(setSelected, (state, { payload }) => { state.selected = payload })