Skip to content
This repository has been archived by the owner on Jun 24, 2022. It is now read-only.

Commit

Permalink
Claim last investment page (#2227)
Browse files Browse the repository at this point in the history
* Refactoring token logo logic

* New component InvestmentSummaryRow semi complete

* Also filtering free claims to show them on summary page

* Dynamically loading claims on investment summary page

* Refactored calculatePercentage function into utils

* Refactored new utils calculateInvestmentAmounts

* Upgradring EnhancedUserClaimData into ClaimWithInvestmentData

* Adding vCowAmount, cost and percentage to InvestmentSummaryRow

* Renamed paidClaims to selectedClaims as they are a subset only

* Refactored free and selected claims

* Fixed typo

* Further refactoring stuff on InvesmentFlow component

Co-authored-by: Leandro <[email protected]>
  • Loading branch information
alfetopito and Leandro authored Jan 20, 2022
1 parent e8dbe09 commit a116ab5
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 96 deletions.
33 changes: 7 additions & 26 deletions src/custom/pages/Claim/InvestmentFlow/InvestOption.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { useCallback, useMemo, useState, useEffect } from 'react'
import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core'

import CowProtocolLogo from 'components/CowProtocolLogo'
import { InvestTokenGroup, TokenLogo, InvestSummary, InvestInput, InvestAvailableBar } from '../styled'
Expand All @@ -18,8 +17,7 @@ import { ButtonSize } from 'theme'
import Loader from 'components/Loader'
import { useErrorModal } from 'hooks/useErrorMessageAndModal'
import { tryParseAmount } from 'state/swap/hooks'
import { ONE_HUNDRED_PERCENT, ZERO_PERCENT } from 'constants/misc'
import { PERCENTAGE_PRECISION } from 'constants/index'
import { calculateInvestmentAmounts, calculatePercentage } from 'state/claim/hooks/utils'

enum ErrorMsgs {
Initial = 'Insufficient balance to cover the selected investment amount. Either modify the investment amount or unselect the investment option to move forward',
Expand Down Expand Up @@ -61,7 +59,7 @@ export default function InvestOption({ approveData, claim, optionIndex }: Invest
setTypedValue(value.toExact() || '')
setInputError('')

setPercentage(_calculatePercentage(balance, maxCost))
setPercentage(calculatePercentage(balance, maxCost))
}, [balance, maxCost, noBalance, optionIndex, updateInvestAmount])

// on input field change handler
Expand Down Expand Up @@ -96,7 +94,7 @@ export default function InvestOption({ approveData, claim, optionIndex }: Invest
updateInvestAmount({ index: optionIndex, amount: parsedAmount.quotient.toString() })

// update the local state with percentage value
setPercentage(_calculatePercentage(parsedAmount, maxCost))
setPercentage(calculatePercentage(parsedAmount, maxCost))
},
[balance, maxCost, optionIndex, token, updateInvestAmount]
)
Expand Down Expand Up @@ -124,14 +122,10 @@ export default function InvestOption({ approveData, claim, optionIndex }: Invest
}
}, [approveCallback, handleCloseError, handleSetError, token?.symbol])

const vCowAmount = useMemo(() => {
if (!token || !price || !investedAmount) {
return
}

const investA = CurrencyAmount.fromRawAmount(token, investedAmount)
return price.quote(investA)
}, [investedAmount, price, token])
const vCowAmount = useMemo(
() => calculateInvestmentAmounts(claim, investedAmount)?.vCowAmount,
[claim, investedAmount]
)

// if its claiming for someone else we will set values to max
// if there is not enough balance then we will set an error
Expand Down Expand Up @@ -256,16 +250,3 @@ export default function InvestOption({ approveData, claim, optionIndex }: Invest
</InvestTokenGroup>
)
}

function _calculatePercentage<C1 extends Currency, C2 extends Currency>(
numerator: CurrencyAmount<C1>,
denominator: CurrencyAmount<C2>
): string {
let percentage = denominator.equalTo(ZERO_PERCENT)
? ZERO_PERCENT
: new Percent(numerator.quotient, denominator.quotient)
if (percentage.greaterThan(ONE_HUNDRED_PERCENT)) {
percentage = ONE_HUNDRED_PERCENT
}
return formatSmart(percentage, PERCENTAGE_PRECISION) || '0'
}
73 changes: 73 additions & 0 deletions src/custom/pages/Claim/InvestmentFlow/InvestSummaryRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { ClaimType } from 'state/claim/hooks'
import { calculatePercentage } from 'state/claim/hooks/utils'
import { TokenLogo } from 'pages/Claim/styled'
import { ClaimWithInvestmentData } from 'pages/Claim/types'
import CowProtocolLogo from 'components/CowProtocolLogo'
import { formatSmart } from 'utils/format'
import { AMOUNT_PRECISION } from 'constants/index'

export type Props = { claim: ClaimWithInvestmentData }

export function InvestSummaryRow(props: Props): JSX.Element | null {
const { claim } = props

const { isFree, type, price, currencyAmount, vCowAmount, cost, investmentCost } = claim

const symbol = isFree ? '' : (currencyAmount?.currency?.symbol as string)

const formattedCost =
formatSmart(investmentCost, AMOUNT_PRECISION, { thousandSeparator: true, isLocaleAware: true }) || '0'
const percentage = investmentCost && cost && calculatePercentage(investmentCost, cost)

return (
<tr>
<td>
{isFree ? (
<b>{ClaimType[type]}</b>
) : (
<>
<TokenLogo symbol={symbol} size={32} />
<CowProtocolLogo size={32} />
<span>
<b>Buy vCOW</b>
<i>with {symbol}</i>
</span>
</>
)}
</td>

<td>
{!isFree && (
<span>
<b>Investment amount:</b>{' '}
<i>
{formattedCost} {symbol} ({percentage}% of available investing opportunity)
</i>
</span>
)}
<span>
<b>Amount to receive:</b>
<i>{formatSmart(vCowAmount) || '0'} vCOW</i>
</span>
</td>

<td>
{!isFree && (
<span>
<b>Price:</b>{' '}
<i>
{formatSmart(price) || '0'} vCoW per {symbol}
</i>
</span>
)}
<span>
<b>Cost:</b> <i>{isFree ? 'Free!' : `${formattedCost} ${symbol}`}</i>
</span>
<span>
<b>Vesting:</b>
<i>{type === ClaimType.Airdrop ? 'No' : '4 years (linear)'}</i>
</span>
</td>
</tr>
)
}
119 changes: 54 additions & 65 deletions src/custom/pages/Claim/InvestmentFlow/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useEffect, useMemo } from 'react'

import {
InvestFlow,
InvestContent,
Expand All @@ -8,15 +9,19 @@ import {
Steps,
ClaimTable,
AccountClaimSummary,
TokenLogo,
} from 'pages/Claim/styled'
import { InvestSummaryRow } from 'pages/Claim/InvestmentFlow/InvestSummaryRow'

import { ClaimType, useClaimState, useUserEnhancedClaimData, useClaimDispatchers } from 'state/claim/hooks'
import { ClaimCommonTypes, EnhancedUserClaimData } from '../types'
import { ClaimStatus } from 'state/claim/actions'
import { useActiveWeb3React } from 'hooks/web3'
import { InvestClaim } from 'state/claim/reducer'
import { calculateInvestmentAmounts } from 'state/claim/hooks/utils'

import { ApprovalState, OptionalApproveCallbackParams } from 'hooks/useApproveCallback'
import { useActiveWeb3React } from 'hooks/web3'

import InvestOption from './InvestOption'
import CowProtocolLogo from 'components/CowProtocolLogo'
import { ClaimCommonTypes, ClaimWithInvestmentData, EnhancedUserClaimData } from '../types'

export type InvestOptionProps = {
claim: EnhancedUserClaimData
Expand Down Expand Up @@ -49,15 +54,52 @@ function _claimToTokenApproveData(claimType: ClaimType, tokenApproveData: TokenA
}
}

function _classifyAndFilterClaimData(claimData: EnhancedUserClaimData[], selected: number[]) {
const paid: EnhancedUserClaimData[] = []
const free: EnhancedUserClaimData[] = []

claimData.forEach((claim) => {
if (claim.isFree) {
free.push(claim)
} else if (selected.includes(claim.index)) {
paid.push(claim)
}
})
return [free, paid]
}

function _enhancedUserClaimToClaimWithInvestment(
claim: EnhancedUserClaimData,
investFlowData: InvestClaim[]
): ClaimWithInvestmentData {
const investmentAmount = claim.isFree
? undefined
: investFlowData.find(({ index }) => index === claim.index)?.investedAmount

return { ...claim, ...calculateInvestmentAmounts(claim, investmentAmount) }
}

export default function InvestmentFlow({ hasClaims, isAirdropOnly, ...tokenApproveData }: InvestmentFlowProps) {
const { account } = useActiveWeb3React()
const { selected, activeClaimAccount, claimStatus, isInvestFlowActive, investFlowStep } = useClaimState()
const { selected, activeClaimAccount, claimStatus, isInvestFlowActive, investFlowStep, investFlowData } =
useClaimState()
const { initInvestFlowData } = useClaimDispatchers()
const claimData = useUserEnhancedClaimData(activeClaimAccount)

const selectedClaims = useMemo(() => {
return claimData.filter(({ index }) => selected.includes(index))
}, [claimData, selected])
// Filtering and splitting claims into free and selected paid claims
// `selectedClaims` are used on step 1 and 2
// `freeClaims` are used on step 2
const [freeClaims, selectedClaims] = useMemo(
() => _classifyAndFilterClaimData(claimData, selected),
[claimData, selected]
)

// Merge all claims together again, with their investment data for step 2
const allClaims: ClaimWithInvestmentData[] = useMemo(
() =>
freeClaims.concat(selectedClaims).map((claim) => _enhancedUserClaimToClaimWithInvestment(claim, investFlowData)),
[freeClaims, investFlowData, selectedClaims]
)

useEffect(() => {
initInvestFlowData()
Expand Down Expand Up @@ -146,62 +188,9 @@ export default function InvestmentFlow({ hasClaims, isAirdropOnly, ...tokenAppro
</tr>
</thead>
<tbody>
<tr>
<td>
<b>Airdrop</b>
</td>
<td>
<span>
<b>Amount to receive:</b>
<i>13,120.50 vCOW</i>
</span>
</td>

<td>
<span>
<b>Cost:</b> <i>Free!</i>
</span>
<span>
<b>Vesting:</b>
<i>No</i>
</span>
</td>
</tr>

<tr>
<td>
{' '}
<TokenLogo symbol="GNO" size={32} />
<CowProtocolLogo size={32} />
<span>
<b>Buy vCOW</b>
<i>with GNO</i>
</span>
</td>

<td>
<span>
<b>Investment amount:</b> <i>1343 GNO (50% of available investing opportunity)</i>
</span>
<span>
<b>Amount to receive:</b>
<i>13,120.50 vCOW</i>
</span>
</td>

<td>
<span>
<b>Price:</b> <i>2666.6666 vCoW per GNO</i>
</span>
<span>
<b>Cost:</b> <i>0.783375 GNO</i>
</span>
<span>
<b>Vesting:</b>
<i>4 years (linear)</i>
</span>
</td>
</tr>
{allClaims.map((claim) => (
<InvestSummaryRow claim={claim} key={claim.index} />
))}
</tbody>
</table>
</ClaimTable>
Expand All @@ -214,7 +203,7 @@ export default function InvestmentFlow({ hasClaims, isAirdropOnly, ...tokenAppro
</p>
<p>
<b>Can I modify the invested amounts or invest partial amounts later?</b> No. Once you send the transaction,
you cannot increase or reduce the investment. Investment oportunities can only be exercised once.
you cannot increase or reduce the investment. Investment opportunities can only be exercised once.
</p>
<p>
<b>Important!</b> Please make sure you intend to claim and send vCOW to the mentioned receiving account(s)
Expand Down
20 changes: 16 additions & 4 deletions src/custom/pages/Claim/styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,12 +191,24 @@ export const TokenLogo = styled.div<{ symbol: string; size: number }>`
width: ${({ size }) => `${size}px`};
height: ${({ size }) => `${size}px`};
border-radius: ${({ size }) => `${size}px`};
background: ${({ symbol, theme }) =>
`url(${
symbol === 'GNO' ? LogoGNO : symbol === 'ETH' ? LogoETH : symbol === 'USDC' ? LogoUSDC : theme.blueShade3
}) no-repeat center/contain`};
background: ${({ symbol, theme }) => `url(${_getLogo(symbol) || theme.blueShade3}) no-repeat center/contain`};
`

function _getLogo(symbol: string) {
switch (symbol.toUpperCase()) {
case 'GNO':
return LogoGNO
case 'USDC':
return LogoUSDC
case 'ETH':
return LogoETH
// TODO: add xDai token logo after merging to develop
// case 'XDAI': return LogoXDAI
default:
return undefined
}
}

export const ClaimSummary = styled.div`
display: flex;
width: 100%;
Expand Down
7 changes: 7 additions & 0 deletions src/custom/pages/Claim/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,10 @@ export type EnhancedUserClaimData = UserClaimData & {
price?: Price<Currency, Currency> | undefined
cost?: CurrencyAmount<Currency> | undefined
}

export type InvestmentAmounts = {
vCowAmount?: CurrencyAmount<Currency>
investmentCost?: CurrencyAmount<Currency>
}

export type ClaimWithInvestmentData = EnhancedUserClaimData & InvestmentAmounts
Loading

0 comments on commit a116ab5

Please sign in to comment.