Commit 4ec95d09 authored by eddie's avatar eddie Committed by GitHub

fix: URL params for widget (#5943)

* fix: URL params for widget

* fix: remove output token from tokenDetails callsite

* fix: combine props, rename initial state values

* fix: better prop types

* fix: rename prop type
parent fba6cc9e
...@@ -2,7 +2,6 @@ import { Trans } from '@lingui/macro' ...@@ -2,7 +2,6 @@ import { Trans } from '@lingui/macro'
import { Trace } from '@uniswap/analytics' import { Trace } from '@uniswap/analytics'
import { InterfacePageName } from '@uniswap/analytics-events' import { InterfacePageName } from '@uniswap/analytics-events'
import { Currency } from '@uniswap/sdk-core' import { Currency } from '@uniswap/sdk-core'
import { Field } from '@uniswap/widgets'
import { useWeb3React } from '@web3-react/core' import { useWeb3React } from '@web3-react/core'
import CurrencyLogo from 'components/Logo/CurrencyLogo' import CurrencyLogo from 'components/Logo/CurrencyLogo'
import { AboutSection } from 'components/Tokens/TokenDetails/About' import { AboutSection } from 'components/Tokens/TokenDetails/About'
...@@ -221,9 +220,10 @@ export default function TokenDetails({ ...@@ -221,9 +220,10 @@ export default function TokenDetails({
<RightPanel onClick={() => isBlockedToken && setOpenTokenSafetyModal(true)}> <RightPanel onClick={() => isBlockedToken && setOpenTokenSafetyModal(true)}>
<div style={{ pointerEvents: isBlockedToken ? 'none' : 'auto' }}> <div style={{ pointerEvents: isBlockedToken ? 'none' : 'auto' }}>
<Widget <Widget
token={token ?? undefined} defaultTokens={{
defaultField={Field.OUTPUT} default: token ?? undefined,
onTokenChange={navigateToWidgetSelectedToken} }}
onDefaultTokenChange={navigateToWidgetSelectedToken}
onReviewSwapClick={onReviewSwapClick} onReviewSwapClick={onReviewSwapClick}
/> />
</div> </div>
......
...@@ -10,7 +10,6 @@ import { Currency, TradeType } from '@uniswap/sdk-core' ...@@ -10,7 +10,6 @@ import { Currency, TradeType } from '@uniswap/sdk-core'
import { import {
AddEthereumChainParameter, AddEthereumChainParameter,
EMPTY_TOKEN_LIST, EMPTY_TOKEN_LIST,
Field,
OnReviewSwapClick, OnReviewSwapClick,
SwapWidget, SwapWidget,
SwapWidgetSkeleton, SwapWidgetSkeleton,
...@@ -32,7 +31,7 @@ import { useIsDarkMode } from 'state/user/hooks' ...@@ -32,7 +31,7 @@ import { useIsDarkMode } from 'state/user/hooks'
import { computeRealizedPriceImpact } from 'utils/prices' import { computeRealizedPriceImpact } from 'utils/prices'
import { switchChain } from 'utils/switchChain' import { switchChain } from 'utils/switchChain'
import { useSyncWidgetInputs } from './inputs' import { DefaultTokens, useSyncWidgetInputs } from './inputs'
import { useSyncWidgetSettings } from './settings' import { useSyncWidgetSettings } from './settings'
import { DARK_THEME, LIGHT_THEME } from './theme' import { DARK_THEME, LIGHT_THEME } from './theme'
import { useSyncWidgetTransactions } from './transactions' import { useSyncWidgetTransactions } from './transactions'
...@@ -46,24 +45,25 @@ function useWidgetTheme() { ...@@ -46,24 +45,25 @@ function useWidgetTheme() {
} }
interface WidgetProps { interface WidgetProps {
token?: Currency defaultTokens: DefaultTokens
width?: number | string width?: number | string
defaultField: Field onDefaultTokenChange?: (token: Currency) => void
onTokenChange?: (token: Currency) => void
onReviewSwapClick?: OnReviewSwapClick onReviewSwapClick?: OnReviewSwapClick
} }
export default function Widget({ export default function Widget({
token, defaultTokens,
width = DEFAULT_WIDGET_WIDTH, width = DEFAULT_WIDGET_WIDTH,
defaultField, onDefaultTokenChange,
onTokenChange,
onReviewSwapClick, onReviewSwapClick,
}: WidgetProps) { }: WidgetProps) {
const { connector, provider } = useWeb3React() const { connector, provider } = useWeb3React()
const locale = useActiveLocale() const locale = useActiveLocale()
const theme = useWidgetTheme() const theme = useWidgetTheme()
const { inputs, tokenSelector } = useSyncWidgetInputs({ token, onTokenChange, defaultField }) const { inputs, tokenSelector } = useSyncWidgetInputs({
defaultTokens,
onDefaultTokenChange,
})
const { settings } = useSyncWidgetSettings() const { settings } = useSyncWidgetSettings()
const { transactions } = useSyncWidgetTransactions() const { transactions } = useSyncWidgetTransactions()
...@@ -189,7 +189,7 @@ export default function Widget({ ...@@ -189,7 +189,7 @@ export default function Widget({
) )
} }
export function WidgetSkeleton() { export function WidgetSkeleton({ width = DEFAULT_WIDGET_WIDTH }: { width?: number | string }) {
const theme = useWidgetTheme() const theme = useWidgetTheme()
return <SwapWidgetSkeleton theme={theme} width={DEFAULT_WIDGET_WIDTH} /> return <SwapWidgetSkeleton theme={theme} width={width} />
} }
...@@ -8,10 +8,11 @@ const EMPTY_AMOUNT = '' ...@@ -8,10 +8,11 @@ const EMPTY_AMOUNT = ''
type SwapValue = Required<SwapController>['value'] type SwapValue = Required<SwapController>['value']
type SwapTokens = Pick<SwapValue, Field.INPUT | Field.OUTPUT> & { default?: Currency } type SwapTokens = Pick<SwapValue, Field.INPUT | Field.OUTPUT> & { default?: Currency }
export type DefaultTokens = Partial<SwapTokens>
function includesDefaultToken(tokens: SwapTokens) { function missingDefaultToken(tokens: SwapTokens) {
if (!tokens.default) return true if (!tokens.default) return false
return tokens[Field.INPUT]?.equals(tokens.default) || tokens[Field.OUTPUT]?.equals(tokens.default) return !tokens[Field.INPUT]?.equals(tokens.default) && !tokens[Field.OUTPUT]?.equals(tokens.default)
} }
/** /**
...@@ -20,30 +21,31 @@ function includesDefaultToken(tokens: SwapTokens) { ...@@ -20,30 +21,31 @@ function includesDefaultToken(tokens: SwapTokens) {
* Enforces that token is a part of the returned value. * Enforces that token is a part of the returned value.
*/ */
export function useSyncWidgetInputs({ export function useSyncWidgetInputs({
token, defaultTokens,
defaultField, onDefaultTokenChange,
onTokenChange,
}: { }: {
token?: Currency defaultTokens: DefaultTokens
defaultField: Field onDefaultTokenChange?: (token: Currency) => void
onTokenChange?: (token: Currency) => void
}) { }) {
const trace = useTrace({ section: InterfaceSectionName.WIDGET }) const trace = useTrace({ section: InterfaceSectionName.WIDGET })
const [type, setType] = useState<SwapValue['type']>(TradeType.EXACT_INPUT) const [type, setType] = useState<SwapValue['type']>(TradeType.EXACT_INPUT)
const [amount, setAmount] = useState<SwapValue['amount']>(EMPTY_AMOUNT) const [amount, setAmount] = useState<SwapValue['amount']>(EMPTY_AMOUNT)
const [tokens, setTokens] = useState<SwapTokens>({ [defaultField]: token, default: token }) const [tokens, setTokens] = useState<SwapTokens>(defaultTokens)
useEffect(() => { useEffect(() => {
if (!tokens[Field.INPUT] && !tokens[Field.OUTPUT]) {
setTokens((tokens) => { setTokens((tokens) => {
const update = { ...tokens, default: token } const update = {
if (!includesDefaultToken(update)) { ...tokens,
return { [defaultField]: update.default, default: update.default } [Field.INPUT]: defaultTokens[Field.INPUT] ?? tokens[Field.INPUT],
[Field.OUTPUT]: defaultTokens[Field.OUTPUT] ?? tokens[Field.OUTPUT] ?? defaultTokens.default,
default: defaultTokens.default,
} }
return update return update
}) })
}, [defaultField, token]) }
}, [defaultTokens, tokens])
const onAmountChange = useCallback( const onAmountChange = useCallback(
(field: Field, amount: string, origin?: 'max') => { (field: Field, amount: string, origin?: 'max') => {
...@@ -99,12 +101,12 @@ export function useSyncWidgetInputs({ ...@@ -99,12 +101,12 @@ export function useSyncWidgetInputs({
return type return type
}) })
if (!includesDefaultToken(update)) { if (missingDefaultToken(update)) {
onTokenChange?.(update[Field.OUTPUT] || selectingToken) onDefaultTokenChange?.(update[Field.OUTPUT] ?? selectingToken)
} }
setTokens(update) setTokens(update)
}, },
[onTokenChange, selectingField, tokens] [onDefaultTokenChange, selectingField, tokens]
) )
const tokenSelector = ( const tokenSelector = (
<CurrencySearchModal <CurrencySearchModal
...@@ -120,11 +122,11 @@ export function useSyncWidgetInputs({ ...@@ -120,11 +122,11 @@ export function useSyncWidgetInputs({
() => ({ () => ({
type, type,
amount, amount,
// If the default has not yet been handled, preemptively disable the widget by passing no tokens. Effectively, // If the initial state has not yet been set, preemptively disable the widget by passing no tokens. Effectively,
// this resets the widget - avoiding rendering stale state - because with no tokens the skeleton will be rendered. // this resets the widget - avoiding rendering stale state - because with no tokens the skeleton will be rendered.
...(token && tokens.default?.equals(token) ? tokens : undefined), ...(tokens[Field.INPUT] || tokens[Field.OUTPUT] ? tokens : undefined),
}), }),
[amount, token, tokens, type] [amount, tokens, type]
) )
const valueHandlers: SwapEventHandlers = useMemo( const valueHandlers: SwapEventHandlers = useMemo(
() => ({ onAmountChange, onSwitchTokens, onTokenSelectorClick }), () => ({ onAmountChange, onSwitchTokens, onTokenSelectorClick }),
......
...@@ -563,7 +563,13 @@ export default function Swap({ className }: { className?: string }) { ...@@ -563,7 +563,13 @@ export default function Swap({ className }: { className?: string }) {
/> />
<PageWrapper> <PageWrapper>
{swapWidgetEnabled ? ( {swapWidgetEnabled ? (
<Widget token={loadedInputCurrency ?? undefined} width="100%" defaultField={Field.INPUT} /> <Widget
defaultTokens={{
[Field.INPUT]: loadedInputCurrency ?? undefined,
[Field.OUTPUT]: loadedOutputCurrency ?? undefined,
}}
width="100%"
/>
) : ( ) : (
<SwapWrapper className={className} id="swap-page"> <SwapWrapper className={className} id="swap-page">
<SwapHeader allowedSlippage={allowedSlippage} /> <SwapHeader allowedSlippage={allowedSlippage} />
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment