diff --git a/src/custom/hooks/useIsMounted.ts b/src/custom/hooks/useIsMounted.ts new file mode 100644 index 000000000..ef187c973 --- /dev/null +++ b/src/custom/hooks/useIsMounted.ts @@ -0,0 +1,19 @@ +import { useRef, useEffect } from 'react' + +/** + * Creates a ref that can be used to solve the issue of + * "Can't perform a React state update on an unmounted component." + */ +export default function useIsMounted() { + const isMounted = useRef(false) + + useEffect(() => { + isMounted.current = true + + return () => { + isMounted.current = false + } + }, []) + + return isMounted +} diff --git a/src/custom/pages/Claim/ClaimsOnOtherChainsBanner.tsx b/src/custom/pages/Claim/ClaimsOnOtherChainsBanner.tsx index 4de6f9aa8..ad57a2ddb 100644 --- a/src/custom/pages/Claim/ClaimsOnOtherChainsBanner.tsx +++ b/src/custom/pages/Claim/ClaimsOnOtherChainsBanner.tsx @@ -1,4 +1,4 @@ -import { useMemo } from 'react' +import { useMemo, Fragment } from 'react' import styled from 'styled-components/macro' import { NETWORK_LABELS, SupportedChainId } from 'constants/chains' import { useClaimState } from 'state/claim/hooks' @@ -78,12 +78,10 @@ function ClaimsOnOtherChainsBanner({ className }: { className?: string }) { const changeNetworksCallback = () => callback(chainId) const isLastInMultiple = index === array.length - 1 && array.length > 1 return ( - <> + {isLastInMultiple && ' and'} - - {NETWORK_LABELS[chainId]} - - + {NETWORK_LABELS[chainId]} + ) })} diff --git a/src/custom/pages/Claim/index.tsx b/src/custom/pages/Claim/index.tsx index 59e15d4dc..97117a64f 100644 --- a/src/custom/pages/Claim/index.tsx +++ b/src/custom/pages/Claim/index.tsx @@ -236,7 +236,7 @@ export default function Claim() { {/* Claiming content */} {isClaimDataLoading ? ( - + ) : ( <> {/* Approve confirmation modal */} diff --git a/src/custom/pages/Claim/styled.ts b/src/custom/pages/Claim/styled.ts index 3dacf8b28..cb3f6f72c 100644 --- a/src/custom/pages/Claim/styled.ts +++ b/src/custom/pages/Claim/styled.ts @@ -23,6 +23,9 @@ export const InnerPageWrapper = styled.div` border: ${({ theme }) => theme.appBody.border}; box-shadow: ${({ theme }) => theme.appBody.boxShadow}; background: ${({ theme }) => theme.bg1}; + min-height: 450px; + justify-content: center; + align-items: center; ${({ theme }) => theme.mediaWidth.upToSmall` padding: 16px; @@ -34,6 +37,10 @@ a { color: ${({ theme }) => theme.primary4}; } +> a { + width: 100%; +} + p { font-size: 16px; display: block; diff --git a/src/custom/state/claim/hooks/index.ts b/src/custom/state/claim/hooks/index.ts index 60febf164..a63def8b6 100644 --- a/src/custom/state/claim/hooks/index.ts +++ b/src/custom/state/claim/hooks/index.ts @@ -58,6 +58,7 @@ import { import { EnhancedUserClaimData } from 'pages/Claim/types' import { supportedChainId } from 'utils/supportedChainId' import { AMOUNT_PRECISION } from 'constants/index' +import useIsMounted from 'hooks/useIsMounted' const CLAIMS_REPO_BRANCH = '2022-01-22-test-deployment-all-networks' export const CLAIMS_REPO = `https://raw.githubusercontent.com/gnosis/cow-merkle-drop/${CLAIMS_REPO_BRANCH}/` @@ -244,12 +245,16 @@ export function useUserClaims(account: Account, optionalChainId?: SupportedChain const chainId = optionalChainId || connectedChain const [claimInfo, setClaimInfo] = useState<{ [account: string]: UserClaims | null }>({}) - const [isLoading, setIsLoading] = useState(false) + const [isLoading, setIsLoading] = useState(true) // We'll have claims on multiple networks const claimKey = chainId && account && `${chainId}:${account}` useEffect(() => { + if (chainId && !account) { + setIsLoading(false) + } + if (!claimKey) { return } @@ -279,6 +284,18 @@ export function useUserClaims(account: Account, optionalChainId?: SupportedChain return { claims: claimKey ? claimInfo[claimKey] : null, isLoading } } +let fetch_deployment_timestamp_promise: Promise | null = null +function fetchDeploymentTimestamp(vCowContract: VCowType) { + if (!fetch_deployment_timestamp_promise) { + fetch_deployment_timestamp_promise = vCowContract.deploymentTimestamp().then((ts) => { + console.log(`Deployment timestamp in seconds: ${ts.toString()}`) + return ts.mul('1000').toNumber() + }) + } + + return fetch_deployment_timestamp_promise +} + /** * Fetches from contract the deployment timestamp in ms * @@ -287,6 +304,8 @@ export function useUserClaims(account: Account, optionalChainId?: SupportedChain function useDeploymentTimestamp(): number | null { const { chainId } = useActiveWeb3React() const vCowContract = useVCowContract() + const isMounted = useIsMounted() + const [timestamp, setTimestamp] = useState(null) useEffect(() => { @@ -294,11 +313,19 @@ function useDeploymentTimestamp(): number | null { return } - vCowContract.deploymentTimestamp().then((ts) => { - console.log(`Deployment timestamp in seconds: ${ts.toString()}`) - setTimestamp(ts.mul('1000').toNumber()) - }) - }, [chainId, vCowContract]) + fetchDeploymentTimestamp(vCowContract) + .then((timestamp) => { + if (isMounted.current) { + setTimestamp(timestamp) + } + }) + .catch((err) => { + if (isMounted.current) { + setTimestamp(null) + console.error('vCowContract Deployment Timestamp fetch failed', err) + } + }) + }, [chainId, isMounted, vCowContract]) return timestamp }