Skip to content

Commit

Permalink
fix: onramp fixes an cleanup (#8656)
Browse files Browse the repository at this point in the history
<!--
Before opening a pull request, please read the [contributing
guidelines](https://github.com/pancakeswap/pancake-frontend/blob/develop/CONTRIBUTING.md)
first
-->

<!-- start pr-codex -->

---

## PR-Codex overview
### Focus of this PR:
This PR focuses on making changes to the BuyCrypto feature in the web
app. It includes updates to styles, types, components, and constants
related to BuyCrypto.

### Detailed summary:
- Updated styles in `BuyCrypto/styles.tsx` and added a new styled
component `DropdownWrapper`.
- Updated types in `BuyCrypto/types.ts`.
- Updated the `toggleAccordianVisibility` function in `Accordion.tsx`.
- Removed an entry in the `pancake-supported-onramp-currency-list.json`
file.
- Added a new import and updated the `CryptoCard` component in
`Card/index.tsx`.
- Added a new component `BuyCryptoTooltip` in `Tooltip.tsx`.
- Added a new component `ProviderCampaign` in `ProviderCampaign.tsx`.
- Updated the `BuyCryptoForm` component in `BuyCryptoForm.tsx`.
- Updated constants in `constants.ts`.
- Updated translations in `translations.json`.

> The following files were skipped due to too many changes:
`packages/localization/src/config/translations.json`,
`apps/web/src/views/BuyCrypto/components/AccordionDropdown/AccordionItem.tsx`

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your
question}`

<!-- end pr-codex -->
  • Loading branch information
ChefBingbong authored Dec 23, 2023
1 parent 67f1dc8 commit 589a21c
Show file tree
Hide file tree
Showing 11 changed files with 227 additions and 169 deletions.
8 changes: 5 additions & 3 deletions apps/web/src/components/Card/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { styled } from 'styled-components'
import { Box, BoxProps } from '@pancakeswap/uikit'
import { styled } from 'styled-components'

export interface LightCardProps extends BoxProps {
width?: string
Expand Down Expand Up @@ -28,13 +28,15 @@ export const LightGreyCard = styled(Card)`
background-color: ${({ theme }) => theme.colors.background};
`

export const CryptoCard = styled(Card)<{ isClicked: boolean; isDisabled: boolean }>`
export const CryptoCard = styled(Card)<{ isClicked: boolean; isDisabled: boolean; elementHeight: number }>`
border: 1px solid ${({ theme }) => theme.colors.cardBorder};
background-color: ${({ theme, isClicked }) => (isClicked ? theme.colors.input : theme.colors.background)};
transition: max-height 0.4s ease-in-out, background-color 0.1s ease-in-out;
transition: max-height 0.3s ease-in-out, background-color 0.1s ease-in-out;
max-height: ${({ isClicked, elementHeight }) => (isClicked ? `${elementHeight}px` : `105px`)};
overflow: hidden;
&:hover {
cursor: ${({ isDisabled }) => (isDisabled ? 'not-allowed' : 'pointer')};
pointer-events: ${({ isDisabled }) => (isDisabled ? 'none' : 'auto')};
}
`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,6 @@
"chainId": 42161,
"logoURI": "https://tokens.pancakeswap.finance/images/symbol/usdc.png"
},
{
"name": "USD Coin Ethereum Bridged",
"symbol": "USDC.e",
"address": "0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8",
"chainId": 42161,
"decimals": 6,
"logoURI": "https://tokens.pancakeswap.finance/images/symbol/usdc.png"
},
{
"name": "USD Coin",
"symbol": "USDC",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ function Accordion({
<AccordionItem
key={quote.provider}
active={currentIdx === idx}
btnOnClick={() => setCurrentIdx((a) => (a === idx ? '' : idx))}
toggleAccordianVisibility={() => setCurrentIdx((a) => (a === idx ? '' : idx))}
quote={quote}
fetching={fetching}
setModalView={setModalView}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,178 +1,143 @@
import { Box, Flex, InfoFilledIcon, RowBetween, Text, TooltipText, useTooltip } from '@pancakeswap/uikit'
import getTimePeriods from '@pancakeswap/utils/getTimePeriods'
import { useTranslation } from '@pancakeswap/localization'
import { Flex, RowBetween, Text } from '@pancakeswap/uikit'
import { CryptoCard } from 'components/Card'
import { FiatOnRampModalButton } from 'components/FiatOnRampModal/FiatOnRampModal'
import Image from 'next/image'
import { Dispatch, SetStateAction, useCallback, useEffect, useRef, useState } from 'react'
import { Dispatch, SetStateAction, useEffect, useRef, useState } from 'react'
import formatLocaleNumber from 'utils/formatLocaleNumber'
import { FeeTypes, providerFeeTypes } from 'views/BuyCrypto/constants'
import { getRefValue } from 'views/BuyCrypto/hooks/useGetRefValue'
import { DropdownWrapper } from 'views/BuyCrypto/styles'
import { CryptoFormView, ProviderQuote } from 'views/BuyCrypto/types'
import { styled } from 'styled-components'
import { useTranslation } from '@pancakeswap/localization'
import { isMobile } from 'react-device-detect'
import formatLocaleNumber from 'utils/formatLocaleNumber'
import { CURRENT_CAMPAIGN_TIMESTAMP, ONRAMP_PROVIDERS, providerFeeTypes } from 'views/BuyCrypto/constants'
import pocketWatch from '../../../../../public/images/pocket-watch.svg'
import OnRampProviderLogo from '../OnRampProviderLogo/OnRampProviderLogo'
import ProviderCampaign from '../ProviderCampaign/ProviderCampaign'
import BuyCryptoTooltip from '../Tooltip/Tooltip'

const DropdownWrapper = styled.div<{ isClicked: boolean }>`
display: ${({ isClicked }) => (isClicked ? 'none' : 'block')};
width: 100%;
transition: display 0.6s ease-in-out;
`

const activeProviders: { [provider in keyof typeof ONRAMP_PROVIDERS]: boolean } = {
[ONRAMP_PROVIDERS.Mercuryo]: false,
[ONRAMP_PROVIDERS.MoonPay]: false,
[ONRAMP_PROVIDERS.Transak]: false,
}
type FeeComponents = { providerFee: number; networkFee: number }

const FeeItem = ({ feeTitle, feeAmount, currency }: { feeTitle: string; feeAmount: number; currency: string }) => {
const FeeItem = ({ feeTitle, quote }: { feeTitle: FeeTypes; quote: ProviderQuote }) => {
const {
t,
currentLanguage: { locale },
} = useTranslation()

const FeeEstimates: {
[feeType: string]: <T extends FeeComponents = FeeComponents>(args: T) => number
} = {
[FeeTypes.TotalFees]: (args) => args.networkFee + args.providerFee,
[FeeTypes.NetworkingFees]: (args) => args.networkFee,
[FeeTypes.ProviderFees]: (args) => args.providerFee,
}

return (
<RowBetween>
<Text fontSize="14px" color="textSubtle">
{feeTitle}
</Text>
<Flex alignItems="center" justifyContent="center">
<Text fontSize="14px" color="textSubtle">
{feeTitle}
</Text>
{feeTitle === FeeTypes.TotalFees && (
<BuyCryptoTooltip
opacity={0.7}
iconSize="17px"
tooltipText={t('Note that Fees are just an estimation and may vary slightly when completing a purchase')}
/>
)}
</Flex>
<Text ml="4px" fontSize="14px" color="textSubtle">
{formatLocaleNumber({ number: feeAmount, locale })} {currency}
{formatLocaleNumber({
number: FeeEstimates[feeTitle](quote),
locale,
})}{' '}
{quote.fiatCurrency}
</Text>
</RowBetween>
)
}

const HeadingRow = ({ quote, quotesExist }: { quote: ProviderQuote; quotesExist: boolean }) => {
const {
t,
currentLanguage: { locale },
} = useTranslation()

const renderQuoteDetails = () => (
<>
<Text ml="4px" fontSize="18px" color="#7A6EAA" fontWeight="bold">
{formatLocaleNumber({
number: quote.quote,
locale,
})}{' '}
{quote.cryptoCurrency}
</Text>
<RowBetween pt="12px">
<Text fontSize="15px">
{quote.cryptoCurrency} {t('rate')}
</Text>
<Text ml="4px" fontSize="16px">
= {formatLocaleNumber({ number: Number(quote.price), locale })} {quote.fiatCurrency}
</Text>
</RowBetween>
</>
)

return (
<>
<RowBetween>
<OnRampProviderLogo provider={quote.provider} />
{quotesExist ? (
renderQuoteDetails()
) : (
<BuyCryptoTooltip
tooltipText={t(
'Price quote from provider is currently unavailable. Please try again or try a different amount',
)}
tooltipHeading={t('No Quote')}
iconSize="22px"
/>
)}
</RowBetween>
</>
)
}

function AccordionItem({
active,
btnOnClick,
toggleAccordianVisibility,
quote,
fetching,
setModalView,
}: {
active: boolean
btnOnClick: any
toggleAccordianVisibility: () => void
quote: ProviderQuote
fetching: boolean
setModalView: Dispatch<SetStateAction<CryptoFormView>>
}) {
const {
t,
currentLanguage: { locale },
} = useTranslation()
const contentRef = useRef<HTMLDivElement>(null)
const [maxHeight, setMaxHeight] = useState(active ? 500 : 150)
const multiple = false
const [visibility, setVisibility] = useState(false)
const [mobileTooltipShow, setMobileTooltipShow] = useState(false)
const currentTimestamp = Math.floor(Date.now() / 1000)
const { days, hours, minutes, seconds } = getTimePeriods(currentTimestamp - CURRENT_CAMPAIGN_TIMESTAMP)
const isActive = () => (multiple ? visibility : active)

const toggleVisibility = useCallback(() => {
setVisibility((v) => !v)
btnOnClick()
}, [setVisibility, btnOnClick])
const [maxHeight, setMaxHeight] = useState<number>(105)
const quotesExist = Boolean(quote.amount !== 0)

useEffect(() => {
const contentEl = getRefValue(contentRef)
setMaxHeight(contentEl?.scrollHeight + 150)
}, [active])
const contentEl = getRefValue(contentRef)?.scrollHeight
setMaxHeight(contentEl)
}, [])

const {
tooltip: buyCryptoTooltip,
tooltipVisible: buyCryptoTooltipVisible,
targetRef: buyCryptoTargetRef,
} = useTooltip(
<Box maxWidth="150px">
<Text as="p">
{t('Price quote from provider is currently unavailable. Please try again or try a different amount')}
</Text>
</Box>,
{
placement: isMobile ? 'top' : 'bottom',
trigger: isMobile ? 'focus' : 'hover',
...(isMobile && { manualVisible: mobileTooltipShow }),
},
)

const providerFee = quote.providerFee < 3.5 && quote.provider === 'MoonPay' ? 3.5 : quote.providerFee

if (quote.amount === 0) {
return (
<Flex flexDirection="column">
<CryptoCard position="relative" isClicked={false} isDisabled>
<RowBetween>
<OnRampProviderLogo provider={quote.provider} />
<TooltipText
ref={buyCryptoTargetRef}
onClick={() => setMobileTooltipShow(false)}
display="flex"
style={{ justifyContent: 'center', alignItems: 'center' }}
>
<Flex alignItems="center" justifyContent="center">
<Text ml="4px" fontSize="15px" color="textSubtle" fontWeight="bold">
{t('Quote not available')}
</Text>
<InfoFilledIcon pl="4px" pt="2px" color="textSubtle" width="22px" />
</Flex>
</TooltipText>
{buyCryptoTooltipVisible && (!isMobile || mobileTooltipShow) && buyCryptoTooltip}
</RowBetween>
</CryptoCard>
</Flex>
)
}
return (
<Flex flexDirection="column">
<CryptoCard
padding="18px 18px"
style={{ maxHeight }}
onClick={!isActive() ? toggleVisibility : () => null}
position="relative"
onClick={toggleAccordianVisibility}
ref={contentRef}
isClicked={active}
isDisabled={false}
elementHeight={maxHeight}
isDisabled={!quotesExist}
>
<RowBetween>
<OnRampProviderLogo provider={quote.provider} />
<Text ml="4px" fontSize="18px" color="#7A6EAA" fontWeight="bold">
{formatLocaleNumber({
number: quote.quote,
locale,
})}{' '}
{quote.cryptoCurrency}
</Text>
</RowBetween>
<RowBetween pt="12px">
<Text fontSize="15px">
{quote.cryptoCurrency} {t('rate')}
</Text>
<Text ml="4px" fontSize="16px">
= {formatLocaleNumber({ number: Number(quote.price), locale })} {quote.fiatCurrency}
</Text>
</RowBetween>
<HeadingRow quote={quote} quotesExist={quotesExist} />

<DropdownWrapper ref={contentRef} isClicked={!isActive()}>
{providerFeeTypes[quote.provider].map((feeType: string, index: number) => {
let fee = 0
if (index === 0) fee = quote.networkFee + providerFee
else if (index === 1) fee = quote.networkFee
else fee = quote.providerFee
return <FeeItem key={feeType} feeTitle={feeType} feeAmount={fee} currency={quote.fiatCurrency} />
<DropdownWrapper isClicked={!active}>
{providerFeeTypes[quote.provider].map((feeType: FeeTypes) => {
return <FeeItem key={feeType} feeTitle={feeType} quote={quote} />
})}
{activeProviders[quote.provider] && seconds >= 1 ? (
<Box mt="16px" background="#F0E4E2" padding="16px" border="1px solid #D67E0A" borderRadius="16px">
<Flex>
<Image src={pocketWatch} alt="pocket-watch" height={30} width={30} />
<Text marginLeft="14px" fontSize="15px" color="#D67E0B">
{t('No provider fees. Ends in %days% days and %hours% hours and %minutes% minutes.', {
days,
hours,
minutes,
})}
</Text>
</Flex>
</Box>
) : null}
<ProviderCampaign provider={quote.provider} />
<FiatOnRampModalButton
provider={quote.provider}
inputCurrency={quote.cryptoCurrency}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { useTranslation } from '@pancakeswap/localization'
import { Box, Flex, Text } from '@pancakeswap/uikit'
import getTimePeriods from '@pancakeswap/utils/getTimePeriods'
import Image from 'next/image'
import { CURRENT_CAMPAIGN_TIMESTAMP, ONRAMP_PROVIDERS } from 'views/BuyCrypto/constants'
import pocketWatch from '../../../../../public/images/pocket-watch.svg'

const activeCampaigns: { [provider in keyof typeof ONRAMP_PROVIDERS]: boolean } = {
[ONRAMP_PROVIDERS.Mercuryo]: false,
[ONRAMP_PROVIDERS.MoonPay]: false,
[ONRAMP_PROVIDERS.Transak]: false,
}

const ProviderCampaign = ({ provider }: { provider: keyof typeof ONRAMP_PROVIDERS }) => {
const { t } = useTranslation()

const currentTimestamp = Math.floor(Date.now() / 1000)
const {
days,
hours,
minutes,
seconds: campaignEndTimeInSeconds,
} = getTimePeriods(currentTimestamp - CURRENT_CAMPAIGN_TIMESTAMP)

return (
<>
{activeCampaigns[provider] && campaignEndTimeInSeconds >= 1 ? (
<Box mt="16px" background="#F0E4E2" padding="16px" border="1px solid #D67E0A" borderRadius="16px">
<Flex>
<Image src={pocketWatch} alt="pocket-watch" height={30} width={30} />
<Text marginLeft="14px" fontSize="15px" color="#D67E0B">
{t('No provider fees. Ends in %days% days and %hours% hours and %minutes% minutes.', {
days,
hours,
minutes,
})}
</Text>
</Flex>
</Box>
) : null}
</>
)
}

export default ProviderCampaign
Loading

2 comments on commit 589a21c

@vercel
Copy link

@vercel vercel bot commented on 589a21c Dec 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

uikit – ./packages/uikit

uikit-git-develop.pancake.run
uikit.pancake.run

@vercel
Copy link

@vercel vercel bot commented on 589a21c Dec 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.