-
Notifications
You must be signed in to change notification settings - Fork 54
Claim last investment page #2227
Changes from all commits
c0502ee
a024460
53e5df4
511fb04
4e7227f
5e5067f
dfa5a1f
afee309
c87af87
42a774b
aedfd99
21e7dd5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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> | ||
) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
import { useEffect, useMemo } from 'react' | ||
|
||
import { | ||
InvestFlow, | ||
InvestContent, | ||
|
@@ -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 | ||
|
@@ -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] | ||
) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you don't need two There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've split because as explained with comments in the code, one section is used for step 1 and 2 while other section is only for step 2. |
||
|
||
useEffect(() => { | ||
initInvestFlowData() | ||
|
@@ -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> | ||
|
@@ -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) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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`}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice! Thanks for doing this. |
||
` | ||
|
||
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%; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@michelbio, should we style differently the non 100% cases?
not investing 100% is something that cannot be undone.
I would even omit the percentage if it's 100%.
This could be done in another PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes we can review.