From 934433c744ee793a4406cf680529c7050b978667 Mon Sep 17 00:00:00 2001 From: Leandro Date: Fri, 14 Jan 2022 11:56:40 -0800 Subject: [PATCH 1/6] New component copied from uniswap's src/pages/Earn/Countdown --- src/custom/pages/Claim/Countdown.tsx | 75 ++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 src/custom/pages/Claim/Countdown.tsx diff --git a/src/custom/pages/Claim/Countdown.tsx b/src/custom/pages/Claim/Countdown.tsx new file mode 100644 index 000000000..262de16a3 --- /dev/null +++ b/src/custom/pages/Claim/Countdown.tsx @@ -0,0 +1,75 @@ +// Sort of a mod of but not quite from src/pages/Earn/Countdown.tsx +import { useEffect, useState } from 'react' + +import { TYPE } from 'theme' + +const MINUTE = 60 +const HOUR = MINUTE * 60 +const DAY = HOUR * 24 + +export type Props = { + start: number + end: number +} + +/** + * Copied over from src/pages/Earn/Countdown.tsx and heavily modified it + * + * If current time is past end time, returns null + * + * @param start start time in ms + * @param end end time in ms + */ +export function Countdown({ start, end }: Props) { + // get current time, store as seconds because 🤷 + const [time, setTime] = useState(() => Math.floor(Date.now() / 1000)) + + useEffect((): (() => void) | void => { + // we only need to tick if not ended yet + if (time <= end / 1000) { + const timeout = setTimeout(() => setTime(Math.floor(Date.now() / 1000)), 1000) + return () => { + clearTimeout(timeout) + } + } + }, [time, end]) + + const timeUntilGenesis = start / 1000 - time + const timeUntilEnd = end / 1000 - time + + let timeRemaining: number + if (timeUntilGenesis >= 0) { + timeRemaining = timeUntilGenesis + } else { + const ongoing = timeUntilEnd >= 0 + if (ongoing) { + timeRemaining = timeUntilEnd + } else { + timeRemaining = Infinity + } + } + + const days = (timeRemaining - (timeRemaining % DAY)) / DAY + timeRemaining -= days * DAY + const hours = (timeRemaining - (timeRemaining % HOUR)) / HOUR + timeRemaining -= hours * HOUR + const minutes = (timeRemaining - (timeRemaining % MINUTE)) / MINUTE + timeRemaining -= minutes * MINUTE + const seconds = timeRemaining + + if (!Number.isFinite(timeRemaining)) { + return null + } + + return ( + + {Number.isFinite(timeRemaining) && ( + + {`${days}:${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds + .toString() + .padStart(2, '0')}`} + + )} + + ) +} From 85a7ab2ff87da5ff18f95c733ce79adedb4fc8d3 Mon Sep 17 00:00:00 2001 From: Leandro Date: Fri, 14 Jan 2022 11:57:07 -0800 Subject: [PATCH 2/6] Exporting contract deployment time --- src/custom/state/claim/hooks/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/custom/state/claim/hooks/index.ts b/src/custom/state/claim/hooks/index.ts index ef4b0623f..f9e5cd55e 100644 --- a/src/custom/state/claim/hooks/index.ts +++ b/src/custom/state/claim/hooks/index.ts @@ -282,7 +282,7 @@ const createMockTx = (data: number[]) => ({ * * Returns null if in there's no network or vCowContract doesn't exist */ -function useDeploymentTimestamp(): number | null { +export function useDeploymentTimestamp(): number | null { const { chainId } = useActiveWeb3React() const vCowContract = useVCowContract() const [timestamp, setTimestamp] = useState(null) From 3a47af3d6aa1a3ae89d5211eba445a292b474d78 Mon Sep 17 00:00:00 2001 From: Leandro Date: Fri, 14 Jan 2022 11:58:08 -0800 Subject: [PATCH 3/6] Integrating new Countdown component into claims table --- src/custom/pages/Claim/ClaimsTable.tsx | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/custom/pages/Claim/ClaimsTable.tsx b/src/custom/pages/Claim/ClaimsTable.tsx index b5c7f50c9..f1a748fed 100644 --- a/src/custom/pages/Claim/ClaimsTable.tsx +++ b/src/custom/pages/Claim/ClaimsTable.tsx @@ -1,5 +1,11 @@ +import { + ClaimType, + useAirdropDeadline, + useClaimState, + useDeploymentTimestamp, + useInvestmentDeadline, +} from 'state/claim/hooks' import styled from 'styled-components/macro' -import { ClaimType, useClaimState } from 'state/claim/hooks' import { ClaimTable, ClaimBreakdown, TokenLogo } from 'pages/Claim/styled' import CowProtocolLogo from 'components/CowProtocolLogo' import { ClaimStatus } from 'state/claim/actions' @@ -9,6 +15,7 @@ import { EnhancedUserClaimData } from './types' import { useAllClaimingTransactionIndices } from 'state/enhancedTransactions/hooks' import { CustomLightSpinner } from 'theme' import Circle from 'assets/images/blue-loader.svg' +import { Countdown } from 'pages/Claim/Countdown' type ClaimsTableProps = { handleSelectAll: (event: React.ChangeEvent) => void @@ -22,6 +29,8 @@ type ClaimsTableProps = { type ClaimsTableRowProps = EnhancedUserClaimData & Pick & { selected: number[] + start: number | null + end: number | null isPendingClaim: boolean } @@ -50,6 +59,8 @@ const ClaimsTableRow = ({ cost, handleSelect, selected, + start, + end, }: ClaimsTableRowProps) => { return ( @@ -99,7 +110,7 @@ const ClaimsTableRow = ({ Vesting: {type === ClaimType.Airdrop ? 'No' : '4 years (linear)'} - Ends in: 28 days, 10h, 50m + Ends in: {start && end && } @@ -119,6 +130,10 @@ export default function ClaimsTable({ const hideTable = isAirdropOnly || !hasClaims || !activeClaimAccount || claimStatus !== ClaimStatus.DEFAULT || isInvestFlowActive + const start = useDeploymentTimestamp() + const investmentEnd = useInvestmentDeadline() + const airdropEnd = useAirdropDeadline() + if (hideTable) return null return ( @@ -146,6 +161,8 @@ export default function ClaimsTable({ isPendingClaim={pendingClaimsSet.has(claim.index)} selected={selected} handleSelect={handleSelect} + start={start} + end={claim.isFree ? airdropEnd : investmentEnd} /> ))} From 68fb581448c440a095da3e87004f7a42278ab1a3 Mon Sep 17 00:00:00 2001 From: Leandro Date: Fri, 14 Jan 2022 11:59:18 -0800 Subject: [PATCH 4/6] Updated sentence slightly to match what was in place before --- src/custom/pages/Claim/Countdown.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/custom/pages/Claim/Countdown.tsx b/src/custom/pages/Claim/Countdown.tsx index 262de16a3..e02b32162 100644 --- a/src/custom/pages/Claim/Countdown.tsx +++ b/src/custom/pages/Claim/Countdown.tsx @@ -65,9 +65,9 @@ export function Countdown({ start, end }: Props) { {Number.isFinite(timeRemaining) && ( - {`${days}:${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds + {`${days} days, ${hours.toString().padStart(2, '0')}h, ${minutes.toString().padStart(2, '0')}m, ${seconds .toString() - .padStart(2, '0')}`} + .padStart(2, '0')}s`} )} From 5497a34c02802167ba4a0e2dd4fa11d977f1a644 Mon Sep 17 00:00:00 2001 From: Leandro Date: Fri, 14 Jan 2022 12:09:26 -0800 Subject: [PATCH 5/6] Making the return type cleaner --- src/custom/pages/Claim/Countdown.tsx | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/custom/pages/Claim/Countdown.tsx b/src/custom/pages/Claim/Countdown.tsx index e02b32162..99e6cd9ae 100644 --- a/src/custom/pages/Claim/Countdown.tsx +++ b/src/custom/pages/Claim/Countdown.tsx @@ -1,8 +1,6 @@ // Sort of a mod of but not quite from src/pages/Earn/Countdown.tsx import { useEffect, useState } from 'react' -import { TYPE } from 'theme' - const MINUTE = 60 const HOUR = MINUTE * 60 const DAY = HOUR * 24 @@ -62,14 +60,8 @@ export function Countdown({ start, end }: Props) { } return ( - - {Number.isFinite(timeRemaining) && ( - - {`${days} days, ${hours.toString().padStart(2, '0')}h, ${minutes.toString().padStart(2, '0')}m, ${seconds - .toString() - .padStart(2, '0')}s`} - - )} - + <>{`${days} days, ${hours.toString().padStart(2, '0')}h, ${minutes.toString().padStart(2, '0')}m, ${seconds + .toString() + .padStart(2, '0')}s`} ) } From 372b1fb5b0e70dba1622bfe3688abb44f04255fe Mon Sep 17 00:00:00 2001 From: Leandro Date: Mon, 17 Jan 2022 13:54:28 -0800 Subject: [PATCH 6/6] Return a message instead of null when countdown expires --- src/custom/pages/Claim/Countdown.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/custom/pages/Claim/Countdown.tsx b/src/custom/pages/Claim/Countdown.tsx index 99e6cd9ae..74b15ca16 100644 --- a/src/custom/pages/Claim/Countdown.tsx +++ b/src/custom/pages/Claim/Countdown.tsx @@ -55,13 +55,13 @@ export function Countdown({ start, end }: Props) { timeRemaining -= minutes * MINUTE const seconds = timeRemaining - if (!Number.isFinite(timeRemaining)) { - return null - } - return ( - <>{`${days} days, ${hours.toString().padStart(2, '0')}h, ${minutes.toString().padStart(2, '0')}m, ${seconds - .toString() - .padStart(2, '0')}s`} + <> + {Number.isFinite(timeRemaining) + ? `${days} days, ${hours.toString().padStart(2, '0')}h, ${minutes.toString().padStart(2, '0')}m, ${seconds + .toString() + .padStart(2, '0')}s` + : 'No longer claimable'} + ) }