Skip to content

Commit

Permalink
fix(buy-crypto): Use refresh state, url parsing and undefined address (
Browse files Browse the repository at this point in the history
…#10574)

<!--
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
This PR introduces a new form atom provider in the `BuyCrypto` feature.
It also updates hooks and components to use the new form state.

### Detailed summary
- Added `BuyCryptoAtomProvider` to manage form state in `BuyCryptoPage`
- Updated hooks to use `useBuyCryptoFormState` instead of
`useBuyCryptoState`
- Created `useBuyCryptoFormDispatch` to handle form state dispatching

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

<!-- end pr-codex -->
  • Loading branch information
memoyil authored Aug 29, 2024
1 parent 9ff0ecf commit 0f5997c
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 42 deletions.
11 changes: 3 additions & 8 deletions apps/web/src/components/TokenImage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,18 @@ export const tokenImageChainNameMapping = {
}

export const getImageUrlFromToken = (token: Currency) => {
const address = token?.isNative ? token.wrapped.address : token.address
const address = token?.isNative ? token.wrapped.address : token?.address

return token
? token?.isNative && token.chainId !== ChainId.BSC
? token.isNative && token.chainId !== ChainId.BSC
? `${ASSET_CDN}/web/native/${token.chainId}.png`
: `https://tokens.pancakeswap.finance/images/${tokenImageChainNameMapping[token.chainId]}${address}.png`
: ''
}

export const getImageUrlsFromToken = (token: Currency & { logoURI?: string | undefined }) => {
const uriLocations = token?.logoURI ? uriToHttp(token?.logoURI) : []
const address = token?.isNative ? token.wrapped.address : token.address
const imageUri = token
? token?.isNative && token.chainId !== ChainId.BSC
? `${ASSET_CDN}/web/native/${token.chainId}.png`
: `https://tokens.pancakeswap.finance/images/${tokenImageChainNameMapping[token.chainId]}${address}.png`
: ''
const imageUri = getImageUrlFromToken(token)
return [...uriLocations, imageUri]
}

Expand Down
14 changes: 13 additions & 1 deletion apps/web/src/pages/buy-crypto/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
import { CHAIN_IDS } from 'utils/wagmi'
import BuyCrypto from 'views/BuyCrypto'
import { useMemo } from 'react'
import { BuyCryptoAtomProvider, createFormAtom } from 'state/buyCrypto/reducer'

const BuyCryptoPage = () => {
return <BuyCrypto />
const formAtom = useMemo(() => createFormAtom(), [])

return (
<BuyCryptoAtomProvider
value={{
formAtom,
}}
>
<BuyCrypto />
</BuyCryptoAtomProvider>
)
}

BuyCryptoPage.chains = CHAIN_IDS
Expand Down
42 changes: 20 additions & 22 deletions apps/web/src/state/buyCrypto/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { useActiveChainId } from 'hooks/useActiveChainId'
import { useAtom, useAtomValue } from 'jotai'
import { useAtom } from 'jotai'
import { atomWithStorage } from 'jotai/utils'
import { useRouter } from 'next/router'
import type { ParsedUrlQuery } from 'querystring'
import { useCallback, useEffect } from 'react'
import { buyCryptoReducerAtom, type BuyCryptoState } from 'state/buyCrypto/reducer'
import { type BuyCryptoState, useBuyCryptoFormDispatch } from 'state/buyCrypto/reducer'

import {
OnRampChainId as ChainId,
Expand All @@ -19,10 +19,6 @@ export function useAllowBtcPurchases() {
return useAtom(useEnableBtcPurchases)
}

export function useBuyCryptoState() {
return useAtomValue(buyCryptoReducerAtom)
}

function parseTokenAmountURLParameter(urlParam: unknown): string {
return typeof urlParam === 'string' && !Number.isNaN(Number.parseFloat(urlParam)) ? urlParam : ''
}
Expand All @@ -32,7 +28,7 @@ export function useBuyCryptoActionHandlers(): {
onSwitchTokens: () => void
onUserInput: (field: Field, typedValue: string | number) => void
} {
const [, dispatch] = useAtom(buyCryptoReducerAtom)
const dispatch = useBuyCryptoFormDispatch()

const onCurrencySelection = useCallback(
(field: Field, currency: Currency) => {
Expand Down Expand Up @@ -72,26 +68,28 @@ export async function queryParametersToBuyCryptoState(

const DEFAULT_FIAT_CURRENCY = [ChainId.BASE, ChainId.LINEA].find((c) => {
if (parsedChainId) {
return c.valueOf() === parseInt(parsedQs.chainId as string)
return c.toString() === parsedChainId
}
return c === chainId
})
? 'EUR'
: 'USD'

let outputCurrencyId
if (parsedQs.outputCurrency) {
const parsedKey = parsedChainId ? (parsedQs.outputCurrency as string) : `${parsedQs.outputCurrency}_${chainId}`
if (onRampCurrenciesMap[parsedKey]) {
outputCurrencyId = parsedKey
} else {
const defaultChainCurrency = Object.keys(onRampCurrenciesMap).find(([key]) => {
const [, id] = key.split('_')
return parseInt(id) === (parsedChainId ?? chainId)
})
if (defaultChainCurrency) {
outputCurrencyId = defaultChainCurrency
}
let outputCurrencyId: string | undefined
const parsedKey = parsedQs.outputCurrency
? parsedChainId
? (parsedQs.outputCurrency as string)
: `${parsedQs.outputCurrency}_${chainId}`
: undefined
if (parsedKey && onRampCurrenciesMap[parsedKey]) {
outputCurrencyId = parsedKey
} else {
const defaultChainCurrency = Object.keys(onRampCurrenciesMap).find((key) => {
const [, id] = key.split('_')
return id === (parsedChainId ?? chainId?.toString())
})
if (defaultChainCurrency) {
outputCurrencyId = defaultChainCurrency
}
}

Expand All @@ -108,7 +106,7 @@ export async function queryParametersToBuyCryptoState(
}

export function useDefaultsFromURLSearch() {
const [, dispatch] = useAtom(buyCryptoReducerAtom)
const dispatch = useBuyCryptoFormDispatch()
const { chainId } = useActiveChainId()
const { query, isReady } = useRouter()

Expand Down
20 changes: 19 additions & 1 deletion apps/web/src/state/buyCrypto/reducer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { createReducer, type ActionReducerMapBuilder } from '@reduxjs/toolkit'
import { atomWithReducer } from 'jotai/utils'
import { createContext, useContext } from 'react'
import { useAtomValue, useSetAtom } from 'jotai'
import {
Field,
replaceBuyCryptoState,
Expand Down Expand Up @@ -79,4 +81,20 @@ export const reducer = createReducer<BuyCryptoState>(
},
)

export const buyCryptoReducerAtom = atomWithReducer(initialState, reducer)
export const createFormAtom = () => atomWithReducer(initialState, reducer)

const BuyCryptoAtomContext = createContext({
formAtom: createFormAtom(),
})

export const BuyCryptoAtomProvider = BuyCryptoAtomContext.Provider

export function useBuyCryptoFormState() {
const ctx = useContext(BuyCryptoAtomContext)
return useAtomValue(ctx.formAtom)
}

export function useBuyCryptoFormDispatch() {
const ctx = useContext(BuyCryptoAtomContext)
return useSetAtom(ctx.formAtom)
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const EvmLogo = ({ mode, currency, size = 24 }: { mode: string; currency:
width={size}
height={size}
primarySrc={getImageUrlFromToken(currency)}
secondarySrc={`https://assets.pancakeswap.finance/web/chains/${currency.chainId}.png`}
secondarySrc={currency ? `https://assets.pancakeswap.finance/web/chains/${currency.chainId}.png` : ''}
/>
</Box>
)}
Expand Down
15 changes: 10 additions & 5 deletions apps/web/src/views/BuyCrypto/containers/BuyCryptoForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,13 @@ import {
type Dispatch,
type SetStateAction,
} from 'react'
import { useBuyCryptoActionHandlers, useBuyCryptoState } from 'state/buyCrypto/hooks'
import { useBuyCryptoActionHandlers } from 'state/buyCrypto/hooks'
import { Field } from 'state/swap/actions'
import { useTheme } from 'styled-components'
import { v4 } from 'uuid'
import { OnRampUnit, type OnRampProviderQuote } from 'views/BuyCrypto/types'
import OnBoardingView from 'views/Notifications/containers/OnBoardingView'
import { useBuyCryptoFormState } from 'state/buyCrypto/reducer'
import { BuyCryptoSelector } from '../components/OnRampCurrencySelect'
import { OnRampFlipButton } from '../components/OnRampFlipButton/OnRampFlipButton'
import { PopOverScreenContainer } from '../components/PopOverScreen/PopOverScreen'
Expand Down Expand Up @@ -70,7 +71,7 @@ interface OnRampCurrencySelectPopOverProps {
type InputEvent = ChangeEvent<HTMLInputElement>

export function BuyCryptoForm({ providerAvailabilities }: { providerAvailabilities: ProviderAvailabilities }) {
const { typedValue, independentField } = useBuyCryptoState()
const { typedValue, independentField } = useBuyCryptoFormState()

const { t } = useTranslation()
const isBtc = useIsBtc()
Expand All @@ -84,7 +85,11 @@ export function BuyCryptoForm({ providerAvailabilities }: { providerAvailabiliti

const bestQuoteRef = useRef<OnRampProviderQuote | undefined>(undefined)
const debouncedQuery = useDebounce(searchQuery, 200)
const externalTxIdRef = useRef<string>(v4())
const externalTxIdRef = useRef<string>()

useEffect(() => {
externalTxIdRef.current = v4()
}, [])

const { onUserInput, onCurrencySelection, onSwitchTokens } = useBuyCryptoActionHandlers()

Expand Down Expand Up @@ -169,7 +174,7 @@ export function BuyCryptoForm({ providerAvailabilities }: { providerAvailabiliti
setShowProvidersPopOver={setShowProvidersPopOver}
showProivdersPopOver={showProivdersPopOver}
/>
<NotificationsOnboradPopover
<NotificationsOnboardPopover
setShowNotificationsPopOver={setShowNotificationsPopOver}
showNotificationsPopOver={showNotificationsPopOver}
/>
Expand Down Expand Up @@ -267,7 +272,7 @@ export function BuyCryptoForm({ providerAvailabilities }: { providerAvailabiliti
)
}

const NotificationsOnboradPopover = ({
const NotificationsOnboardPopover = ({
setShowNotificationsPopOver,
showNotificationsPopOver,
}: NotificationsOnboardPopOverProps) => {
Expand Down
4 changes: 2 additions & 2 deletions apps/web/src/views/BuyCrypto/hooks/useIsBtc.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { useMemo } from 'react'
import { Field } from 'state/buyCrypto/actions'
import { useBuyCryptoState } from 'state/buyCrypto/hooks'
import { useBuyCryptoFormState } from 'state/buyCrypto/reducer'

export const useIsBtc = () => {
const {
[Field.INPUT]: { currencyId: inputCurrencyId },
[Field.OUTPUT]: { currencyId: outputCurrencyId },
} = useBuyCryptoState()
} = useBuyCryptoFormState()

return useMemo(
() => Boolean(inputCurrencyId === 'BTC_0' || outputCurrencyId === 'BTC_0'),
Expand Down
4 changes: 2 additions & 2 deletions apps/web/src/views/BuyCrypto/hooks/useOnRampCurrencyOrder.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { useMemo } from 'react'
import { Field } from 'state/buyCrypto/actions'
import { useBuyCryptoState } from 'state/buyCrypto/hooks'
import { useBuyCryptoFormState } from 'state/buyCrypto/reducer'
import { fiatCurrencyMap, getOnRampCryptoById, getOnRampFiatById, isFiat, onRampCurrenciesMap } from '../constants'
import type { OnRampUnit } from '../types'

export const useOnRampCurrencyOrder = (unit: OnRampUnit) => {
const {
[Field.INPUT]: { currencyId: inputCurrencyId },
[Field.OUTPUT]: { currencyId: outputCurrencyId },
} = useBuyCryptoState()
} = useBuyCryptoFormState()

const cryptoCurrency = useMemo(() => {
if (!inputCurrencyId || !outputCurrencyId) return onRampCurrenciesMap.BNB_56
Expand Down

0 comments on commit 0f5997c

Please sign in to comment.