Commit 55ffcbd4 authored by Jordan Frankfurt's avatar Jordan Frankfurt

Merge remote-tracking branch 'upstream/main' into merge-upstream

parents 841ea7f8 c8086e3c
...@@ -3,8 +3,8 @@ describe('Redirect', () => { ...@@ -3,8 +3,8 @@ describe('Redirect', () => {
cy.visit('/create-proposal') cy.visit('/create-proposal')
cy.url().should('match', /\/vote\/create-proposal/) cy.url().should('match', /\/vote\/create-proposal/)
}) })
it('should redirect to /swap when visiting nonexist url', () => { it('should redirect to /not-found when visiting nonexist url', () => {
cy.visit('/none-exist-url') cy.visit('/none-exist-url')
cy.url().should('match', /\/swap/) cy.url().should('match', /\/not-found/)
}) })
}) })
...@@ -9,14 +9,27 @@ export { default as LoadingButtonSpinner } from './LoadingButtonSpinner' ...@@ -9,14 +9,27 @@ export { default as LoadingButtonSpinner } from './LoadingButtonSpinner'
type ButtonProps = Omit<ButtonPropsOriginal, 'css'> type ButtonProps = Omit<ButtonPropsOriginal, 'css'>
export const BaseButton = styled(RebassButton)< const ButtonOverlay = styled.div`
{ background-color: transparent;
bottom: 0;
border-radius: inherit;
height: 100%;
left: 0;
position: absolute;
right: 0;
top: 0;
transition: 150ms ease background-color;
width: 100%;
`
type BaseButtonProps = {
padding?: string padding?: string
width?: string width?: string
$borderRadius?: string $borderRadius?: string
altDisabledStyle?: boolean altDisabledStyle?: boolean
} & ButtonProps } & ButtonProps
>`
export const BaseButton = styled(RebassButton)<BaseButtonProps>`
padding: ${({ padding }) => padding ?? '16px'}; padding: ${({ padding }) => padding ?? '16px'};
width: ${({ width }) => width ?? '100%'}; width: ${({ width }) => width ?? '100%'};
font-weight: 500; font-weight: 500;
...@@ -81,7 +94,14 @@ export const ButtonPrimary = styled(BaseButton)` ...@@ -81,7 +94,14 @@ export const ButtonPrimary = styled(BaseButton)`
} }
` `
export const ButtonLight = styled(BaseButton)` export const SmallButtonPrimary = styled(ButtonPrimary)`
width: auto;
font-size: 16px;
padding: 10px 16px;
border-radius: 12px;
`
const BaseButtonLight = styled(BaseButton)`
background-color: ${({ theme }) => theme.accentActionSoft}; background-color: ${({ theme }) => theme.accentActionSoft};
color: ${({ theme }) => theme.accentAction}; color: ${({ theme }) => theme.accentAction};
font-size: 20px; font-size: 20px;
...@@ -98,6 +118,19 @@ export const ButtonLight = styled(BaseButton)` ...@@ -98,6 +118,19 @@ export const ButtonLight = styled(BaseButton)`
box-shadow: 0 0 0 1pt ${({ theme, disabled }) => !disabled && theme.accentActionSoft}; box-shadow: 0 0 0 1pt ${({ theme, disabled }) => !disabled && theme.accentActionSoft};
background-color: ${({ theme, disabled }) => !disabled && theme.accentActionSoft}; background-color: ${({ theme, disabled }) => !disabled && theme.accentActionSoft};
} }
:hover {
${ButtonOverlay} {
background-color: ${({ theme }) => theme.stateOverlayHover};
}
}
:active {
${ButtonOverlay} {
background-color: ${({ theme }) => theme.stateOverlayPressed};
}
}
:disabled { :disabled {
opacity: 0.4; opacity: 0.4;
:hover { :hover {
...@@ -378,7 +411,7 @@ export enum ButtonEmphasis { ...@@ -378,7 +411,7 @@ export enum ButtonEmphasis {
warning, warning,
destructive, destructive,
} }
interface BaseButtonProps { interface BaseThemeButtonProps {
size: ButtonSize size: ButtonSize
emphasis: ButtonEmphasis emphasis: ButtonEmphasis
} }
...@@ -456,19 +489,8 @@ function pickThemeButtonTextColor({ theme, emphasis }: { theme: DefaultTheme; em ...@@ -456,19 +489,8 @@ function pickThemeButtonTextColor({ theme, emphasis }: { theme: DefaultTheme; em
return theme.textPrimary return theme.textPrimary
} }
} }
const ButtonOverlay = styled.div`
background-color: transparent; const BaseThemeButton = styled.button<BaseThemeButtonProps>`
bottom: 0;
border-radius: inherit;
height: 100%;
left: 0;
position: absolute;
right: 0;
top: 0;
transition: 150ms ease background-color;
width: 100%;
`
const BaseThemeButton = styled.button<BaseButtonProps>`
align-items: center; align-items: center;
background-color: ${pickThemeButtonBackgroundColor}; background-color: ${pickThemeButtonBackgroundColor};
border-radius: 16px; border-radius: 16px;
...@@ -515,7 +537,7 @@ const BaseThemeButton = styled.button<BaseButtonProps>` ...@@ -515,7 +537,7 @@ const BaseThemeButton = styled.button<BaseButtonProps>`
} }
` `
interface ThemeButtonProps extends React.ComponentPropsWithoutRef<'button'>, BaseButtonProps {} interface ThemeButtonProps extends React.ComponentPropsWithoutRef<'button'>, BaseThemeButtonProps {}
export const ThemeButton = ({ children, ...rest }: ThemeButtonProps) => { export const ThemeButton = ({ children, ...rest }: ThemeButtonProps) => {
return ( return (
...@@ -525,3 +547,12 @@ export const ThemeButton = ({ children, ...rest }: ThemeButtonProps) => { ...@@ -525,3 +547,12 @@ export const ThemeButton = ({ children, ...rest }: ThemeButtonProps) => {
</BaseThemeButton> </BaseThemeButton>
) )
} }
export const ButtonLight = ({ children, ...rest }: BaseButtonProps) => {
return (
<BaseButtonLight {...rest}>
<ButtonOverlay />
{children}
</BaseButtonLight>
)
}
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import * as Sentry from '@sentry/react' import * as Sentry from '@sentry/react'
import { ButtonLight, ButtonPrimary } from 'components/Button' import { ButtonLight, SmallButtonPrimary } from 'components/Button'
import { ChevronUpIcon } from 'nft/components/icons' import { ChevronUpIcon } from 'nft/components/icons'
import { useIsMobile } from 'nft/hooks' import { useIsMobile } from 'nft/hooks'
import React, { PropsWithChildren, useState } from 'react' import React, { PropsWithChildren, useState } from 'react'
...@@ -23,13 +23,6 @@ const BodyWrapper = styled.div<{ margin?: string }>` ...@@ -23,13 +23,6 @@ const BodyWrapper = styled.div<{ margin?: string }>`
padding: 1rem; padding: 1rem;
` `
const SmallButtonPrimary = styled(ButtonPrimary)`
width: auto;
font-size: 16px;
padding: 10px 16px;
border-radius: 12px;
`
const SmallButtonLight = styled(ButtonLight)` const SmallButtonLight = styled(ButtonLight)`
font-size: 16px; font-size: 16px;
padding: 10px 16px; padding: 10px 16px;
......
import { BaseVariant, FeatureFlag, featureFlagSettings, useUpdateFlag } from 'featureFlags' import { BaseVariant, FeatureFlag, featureFlagSettings, useUpdateFlag } from 'featureFlags'
import { useFiatOnrampFlag } from 'featureFlags/flags/fiatOnramp' import { LandingRedirectVariant, useLandingRedirectFlag } from 'featureFlags/flags/landingRedirect'
import { Permit2Variant, usePermit2Flag } from 'featureFlags/flags/permit2' import { Permit2Variant, usePermit2Flag } from 'featureFlags/flags/permit2'
import { TraceJsonRpcVariant, useTraceJsonRpcFlag } from 'featureFlags/flags/traceJsonRpc' import { TraceJsonRpcVariant, useTraceJsonRpcFlag } from 'featureFlags/flags/traceJsonRpc'
import { useAtomValue, useUpdateAtom } from 'jotai/utils' import { useAtomValue, useUpdateAtom } from 'jotai/utils'
...@@ -210,10 +210,10 @@ export default function FeatureFlagModal() { ...@@ -210,10 +210,10 @@ export default function FeatureFlagModal() {
label="Permit 2 / Universal Router" label="Permit 2 / Universal Router"
/> />
<FeatureFlagOption <FeatureFlagOption
variant={BaseVariant} variant={LandingRedirectVariant}
value={useFiatOnrampFlag()} value={useLandingRedirectFlag()}
featureFlag={FeatureFlag.fiatOnramp} featureFlag={FeatureFlag.landingRedirect}
label="Fiat on-ramp" label="Landing Page Redirect"
/> />
<FeatureFlagGroup name="Debug"> <FeatureFlagGroup name="Debug">
<FeatureFlagOption <FeatureFlagOption
......
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import { useWeb3React } from '@web3-react/core' import { useWeb3React } from '@web3-react/core'
import fiatMaskUrl from 'assets/svg/fiat_mask.svg' import fiatMaskUrl from 'assets/svg/fiat_mask.svg'
import { BaseVariant } from 'featureFlags'
import { useFiatOnrampFlag } from 'featureFlags/flags/fiatOnramp'
import { useCallback, useEffect, useState } from 'react' import { useCallback, useEffect, useState } from 'react'
import { X } from 'react-feather' import { X } from 'react-feather'
import { useToggleWalletDropdown } from 'state/application/hooks' import { useToggleWalletDropdown } from 'state/application/hooks'
...@@ -116,13 +114,12 @@ export function FiatOnrampAnnouncement() { ...@@ -116,13 +114,12 @@ export function FiatOnrampAnnouncement() {
toggleWalletDropdown() toggleWalletDropdown()
acknowledge({ user: true }) acknowledge({ user: true })
}, [acknowledge, toggleWalletDropdown]) }, [acknowledge, toggleWalletDropdown])
const fiatOnrampFlag = useFiatOnrampFlag()
const openModal = useAppSelector((state) => state.application.openModal) const openModal = useAppSelector((state) => state.application.openModal)
if ( if (
!account || !account ||
acks?.user || acks?.user ||
fiatOnrampFlag === BaseVariant.Control ||
locallyDismissed || locallyDismissed ||
sessionStorage.getItem(ANNOUNCEMENT_DISMISSED) || sessionStorage.getItem(ANNOUNCEMENT_DISMISSED) ||
acks.renderCount >= MAX_RENDER_COUNT || acks.renderCount >= MAX_RENDER_COUNT ||
......
// eslint-disable-next-line no-restricted-imports // eslint-disable-next-line no-restricted-imports
import { t } from '@lingui/macro' import { t, Trans } from '@lingui/macro'
import { sendAnalyticsEvent, Trace, TraceEvent, useTrace } from '@uniswap/analytics' import { sendAnalyticsEvent, Trace, TraceEvent, useTrace } from '@uniswap/analytics'
import { BrowserEvent, ElementName, EventName, SectionName } from '@uniswap/analytics-events' import { BrowserEvent, ElementName, EventName, SectionName } from '@uniswap/analytics-events'
import clsx from 'clsx' import clsx from 'clsx'
...@@ -156,9 +156,9 @@ export const SearchBar = () => { ...@@ -156,9 +156,9 @@ export const SearchBar = () => {
> >
<Row <Row
className={clsx( className={clsx(
` ${styles.nftSearchBar} ${!isOpen && !isMobile && magicalGradientOnHover} ${ styles.nftSearchBar,
!isOpen && !isMobile && magicalGradientOnHover,
isMobileOrTablet && (isOpen ? styles.visible : styles.hidden) isMobileOrTablet && (isOpen ? styles.visible : styles.hidden)
} `
)} )}
borderRadius={isOpen || isMobileOrTablet ? undefined : '12'} borderRadius={isOpen || isMobileOrTablet ? undefined : '12'}
borderTopRightRadius={isOpen && !isMobile ? '12' : undefined} borderTopRightRadius={isOpen && !isMobile ? '12' : undefined}
...@@ -182,9 +182,12 @@ export const SearchBar = () => { ...@@ -182,9 +182,12 @@ export const SearchBar = () => {
element={ElementName.NAVBAR_SEARCH_INPUT} element={ElementName.NAVBAR_SEARCH_INPUT}
properties={{ ...trace }} properties={{ ...trace }}
> >
<Trans
id={placeholderText}
render={({ translation }) => (
<Box <Box
as="input" as="input"
placeholder={placeholderText} placeholder={translation as string}
onChange={(event: ChangeEvent<HTMLInputElement>) => { onChange={(event: ChangeEvent<HTMLInputElement>) => {
!isOpen && toggleOpen() !isOpen && toggleOpen()
setSearchValue(event.target.value) setSearchValue(event.target.value)
...@@ -195,6 +198,8 @@ export const SearchBar = () => { ...@@ -195,6 +198,8 @@ export const SearchBar = () => {
ref={inputRef} ref={inputRef}
width="full" width="full"
/> />
)}
/>
</TraceEvent> </TraceEvent>
{!isOpen && <KeyShortCut>/</KeyShortCut>} {!isOpen && <KeyShortCut>/</KeyShortCut>}
</Row> </Row>
......
...@@ -9,14 +9,12 @@ import { AutoColumn } from '../Column' ...@@ -9,14 +9,12 @@ import { AutoColumn } from '../Column'
import ClaimPopup from './ClaimPopup' import ClaimPopup from './ClaimPopup'
import PopupItem from './PopupItem' import PopupItem from './PopupItem'
const MobilePopupWrapper = styled.div<{ height: string | number }>` const MobilePopupWrapper = styled.div`
position: relative; position: relative;
max-width: 100%; max-width: 100%;
height: ${({ height }) => height}; margin: 0 auto;
margin: ${({ height }) => (height ? '0 auto;' : 0)};
margin-bottom: ${({ height }) => (height ? '20px' : 0)};
display: none; display: none;
${({ theme }) => theme.deprecated_mediaWidth.deprecated_upToSmall` ${({ theme }) => theme.deprecated_mediaWidth.deprecated_upToSmall`
display: block; display: block;
padding-top: 20px; padding-top: 20px;
...@@ -74,7 +72,8 @@ export default function Popups() { ...@@ -74,7 +72,8 @@ export default function Popups() {
<PopupItem key={item.key} content={item.content} popKey={item.key} removeAfterMs={item.removeAfterMs} /> <PopupItem key={item.key} content={item.content} popKey={item.key} removeAfterMs={item.removeAfterMs} />
))} ))}
</FixedPopupColumn> </FixedPopupColumn>
<MobilePopupWrapper height={activePopups?.length > 0 ? 'fit-content' : 0}> {activePopups?.length > 0 && (
<MobilePopupWrapper>
<MobilePopupInner> <MobilePopupInner>
{activePopups // reverse so new items up front {activePopups // reverse so new items up front
.slice(0) .slice(0)
...@@ -84,6 +83,7 @@ export default function Popups() { ...@@ -84,6 +83,7 @@ export default function Popups() {
))} ))}
</MobilePopupInner> </MobilePopupInner>
</MobilePopupWrapper> </MobilePopupWrapper>
)}
</> </>
) )
} }
...@@ -4,4 +4,4 @@ export const LARGE_MEDIA_BREAKPOINT = '840px' ...@@ -4,4 +4,4 @@ export const LARGE_MEDIA_BREAKPOINT = '840px'
export const MEDIUM_MEDIA_BREAKPOINT = '720px' export const MEDIUM_MEDIA_BREAKPOINT = '720px'
export const SMALL_MEDIA_BREAKPOINT = '540px' export const SMALL_MEDIA_BREAKPOINT = '540px'
export const MOBILE_MEDIA_BREAKPOINT = '420px' export const MOBILE_MEDIA_BREAKPOINT = '420px'
export const SMALL_MOBILE_MEDIA_BREAKPOINT = '390px' // export const SMALL_MOBILE_MEDIA_BREAKPOINT = '390px'
...@@ -2,12 +2,8 @@ import { useWeb3React } from '@web3-react/core' ...@@ -2,12 +2,8 @@ import { useWeb3React } from '@web3-react/core'
import AddressClaimModal from 'components/claim/AddressClaimModal' import AddressClaimModal from 'components/claim/AddressClaimModal'
import ConnectedAccountBlocked from 'components/ConnectedAccountBlocked' import ConnectedAccountBlocked from 'components/ConnectedAccountBlocked'
import FiatOnrampModal from 'components/FiatOnrampModal' import FiatOnrampModal from 'components/FiatOnrampModal'
import { BaseVariant } from 'featureFlags'
import { useFiatOnrampFlag } from 'featureFlags/flags/fiatOnramp'
import useAccountRiskCheck from 'hooks/useAccountRiskCheck' import useAccountRiskCheck from 'hooks/useAccountRiskCheck'
import NftExploreBanner from 'nft/components/nftExploreBanner/NftExploreBanner'
import { lazy } from 'react' import { lazy } from 'react'
import { useLocation } from 'react-router-dom'
import { useModalIsOpen, useToggleModal } from 'state/application/hooks' import { useModalIsOpen, useToggleModal } from 'state/application/hooks'
import { ApplicationModal } from 'state/application/reducer' import { ApplicationModal } from 'state/application/reducer'
...@@ -20,13 +16,6 @@ export default function TopLevelModals() { ...@@ -20,13 +16,6 @@ export default function TopLevelModals() {
const addressClaimToggle = useToggleModal(ApplicationModal.ADDRESS_CLAIM) const addressClaimToggle = useToggleModal(ApplicationModal.ADDRESS_CLAIM)
const blockedAccountModalOpen = useModalIsOpen(ApplicationModal.BLOCKED_ACCOUNT) const blockedAccountModalOpen = useModalIsOpen(ApplicationModal.BLOCKED_ACCOUNT)
const { account } = useWeb3React() const { account } = useWeb3React()
const location = useLocation()
const fiatOnrampFlagEnabled = useFiatOnrampFlag() === BaseVariant.Enabled
const pageShowsNftPromoBanner =
!fiatOnrampFlagEnabled &&
(location.pathname.startsWith('/swap') ||
location.pathname.startsWith('/tokens') ||
location.pathname.startsWith('/pool'))
useAccountRiskCheck(account) useAccountRiskCheck(account)
const accountBlocked = Boolean(blockedAccountModalOpen && account) const accountBlocked = Boolean(blockedAccountModalOpen && account)
return ( return (
...@@ -36,8 +25,7 @@ export default function TopLevelModals() { ...@@ -36,8 +25,7 @@ export default function TopLevelModals() {
<Bag /> <Bag />
<TransactionCompleteModal /> <TransactionCompleteModal />
<AirdropModal /> <AirdropModal />
{pageShowsNftPromoBanner && <NftExploreBanner />} <FiatOnrampModal />
{fiatOnrampFlagEnabled && <FiatOnrampModal />}
</> </>
) )
} }
...@@ -7,8 +7,6 @@ import Tooltip from 'components/Tooltip' ...@@ -7,8 +7,6 @@ import Tooltip from 'components/Tooltip'
import { getConnection } from 'connection/utils' import { getConnection } from 'connection/utils'
import { getChainInfoOrDefault } from 'constants/chainInfo' import { getChainInfoOrDefault } from 'constants/chainInfo'
import { SupportedChainId } from 'constants/chains' import { SupportedChainId } from 'constants/chains'
import { BaseVariant } from 'featureFlags'
import { useFiatOnrampFlag } from 'featureFlags/flags/fiatOnramp'
import useCopyClipboard from 'hooks/useCopyClipboard' import useCopyClipboard from 'hooks/useCopyClipboard'
import useStablecoinPrice from 'hooks/useStablecoinPrice' import useStablecoinPrice from 'hooks/useStablecoinPrice'
import useNativeCurrency from 'lib/hooks/useNativeCurrency' import useNativeCurrency from 'lib/hooks/useNativeCurrency'
...@@ -228,8 +226,6 @@ const AuthenticatedHeader = () => { ...@@ -228,8 +226,6 @@ const AuthenticatedHeader = () => {
closeModal() closeModal()
}, [clearCollectionFilters, closeModal, navigate, resetSellAssets, setSellPageState]) }, [clearCollectionFilters, closeModal, navigate, resetSellAssets, setSellPageState])
const fiatOnrampFlag = useFiatOnrampFlag()
// animate the border of the buy crypto button when a user navigates here from the feature announcement // animate the border of the buy crypto button when a user navigates here from the feature announcement
// can be removed when components/FiatOnrampAnnouncment.tsx is no longer used // can be removed when components/FiatOnrampAnnouncment.tsx is no longer used
const [acknowledgements, acknowledge] = useFiatOnrampAck() const [acknowledgements, acknowledge] = useFiatOnrampAck()
...@@ -316,7 +312,6 @@ const AuthenticatedHeader = () => { ...@@ -316,7 +312,6 @@ const AuthenticatedHeader = () => {
> >
<Trans>View and sell NFTs</Trans> <Trans>View and sell NFTs</Trans>
</ProfileButton> </ProfileButton>
{fiatOnrampFlag === BaseVariant.Enabled && (
<> <>
<BuyCryptoButton <BuyCryptoButton
$animateBorder={animateBuyCryptoButtonBorder} $animateBorder={animateBuyCryptoButtonBorder}
...@@ -353,7 +348,6 @@ const AuthenticatedHeader = () => { ...@@ -353,7 +348,6 @@ const AuthenticatedHeader = () => {
</FiatOnrampNotAvailableText> </FiatOnrampNotAvailableText>
)} )}
</> </>
)}
{isUnclaimed && ( {isUnclaimed && (
<UNIButton onClick={openClaimModal} size={ButtonSize.medium} emphasis={ButtonEmphasis.medium}> <UNIButton onClick={openClaimModal} size={ButtonSize.medium} emphasis={ButtonEmphasis.medium}>
<Trans>Claim</Trans> {unclaimedAmount?.toFixed(0, { groupSeparator: ',' } ?? '-')} <Trans>reward</Trans> <Trans>Claim</Trans> {unclaimedAmount?.toFixed(0, { groupSeparator: ',' } ?? '-')} <Trans>reward</Trans>
......
...@@ -110,19 +110,10 @@ interface SwapDetailsInlineProps { ...@@ -110,19 +110,10 @@ interface SwapDetailsInlineProps {
trade: InterfaceTrade<Currency, Currency, TradeType> | undefined trade: InterfaceTrade<Currency, Currency, TradeType> | undefined
syncing: boolean syncing: boolean
loading: boolean loading: boolean
showInverted: boolean
setShowInverted: React.Dispatch<React.SetStateAction<boolean>>
allowedSlippage: Percent allowedSlippage: Percent
} }
export default function SwapDetailsDropdown({ export default function SwapDetailsDropdown({ trade, syncing, loading, allowedSlippage }: SwapDetailsInlineProps) {
trade,
syncing,
loading,
showInverted,
setShowInverted,
allowedSlippage,
}: SwapDetailsInlineProps) {
const theme = useTheme() const theme = useTheme()
const { chainId } = useWeb3React() const { chainId } = useWeb3React()
const [showDetails, setShowDetails] = useState(false) const [showDetails, setShowDetails] = useState(false)
...@@ -169,11 +160,7 @@ export default function SwapDetailsDropdown({ ...@@ -169,11 +160,7 @@ export default function SwapDetailsDropdown({
)} )}
{trade ? ( {trade ? (
<LoadingOpacityContainer $loading={syncing}> <LoadingOpacityContainer $loading={syncing}>
<TradePrice <TradePrice price={trade.executionPrice} />
price={trade.executionPrice}
showInverted={showInverted}
setShowInverted={setShowInverted}
/>
</LoadingOpacityContainer> </LoadingOpacityContainer>
) : loading || syncing ? ( ) : loading || syncing ? (
<ThemedText.DeprecatedMain fontSize={14}> <ThemedText.DeprecatedMain fontSize={14}>
......
...@@ -75,7 +75,6 @@ export default function SwapModalHeader({ ...@@ -75,7 +75,6 @@ export default function SwapModalHeader({
}) { }) {
const theme = useTheme() const theme = useTheme()
const [showInverted, setShowInverted] = useState<boolean>(false)
const [lastExecutionPrice, setLastExecutionPrice] = useState(trade.executionPrice) const [lastExecutionPrice, setLastExecutionPrice] = useState(trade.executionPrice)
const [priceUpdate, setPriceUpdate] = useState<number | undefined>() const [priceUpdate, setPriceUpdate] = useState<number | undefined>()
...@@ -153,7 +152,7 @@ export default function SwapModalHeader({ ...@@ -153,7 +152,7 @@ export default function SwapModalHeader({
</AutoColumn> </AutoColumn>
</LightCard> </LightCard>
<RowBetween style={{ marginTop: '0.25rem', padding: '0 1rem' }}> <RowBetween style={{ marginTop: '0.25rem', padding: '0 1rem' }}>
<TradePrice price={trade.executionPrice} showInverted={showInverted} setShowInverted={setShowInverted} /> <TradePrice price={trade.executionPrice} />
</RowBetween> </RowBetween>
<LightCard style={{ padding: '.75rem', marginTop: '0.5rem' }}> <LightCard style={{ padding: '.75rem', marginTop: '0.5rem' }}>
<AdvancedSwapDetails trade={trade} allowedSlippage={allowedSlippage} /> <AdvancedSwapDetails trade={trade} allowedSlippage={allowedSlippage} />
......
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import { Currency, Price } from '@uniswap/sdk-core' import { Currency, Price } from '@uniswap/sdk-core'
import useStablecoinPrice from 'hooks/useStablecoinPrice' import useStablecoinPrice from 'hooks/useStablecoinPrice'
import { useCallback } from 'react' import { useCallback, useState } from 'react'
import { Text } from 'rebass' import styled from 'styled-components/macro'
import styled, { useTheme } from 'styled-components/macro'
import { ThemedText } from 'theme' import { ThemedText } from 'theme'
import { formatDollar, formatTransactionAmount, priceToPreciseFloat } from 'utils/formatNumbers' import { formatDollar, formatTransactionAmount, priceToPreciseFloat } from 'utils/formatNumbers'
interface TradePriceProps { interface TradePriceProps {
price: Price<Currency, Currency> price: Price<Currency, Currency>
showInverted: boolean
setShowInverted: (showInverted: boolean) => void
} }
const StyledPriceContainer = styled.button` const StyledPriceContainer = styled.button`
...@@ -30,8 +27,8 @@ const StyledPriceContainer = styled.button` ...@@ -30,8 +27,8 @@ const StyledPriceContainer = styled.button`
user-select: text; user-select: text;
` `
export default function TradePrice({ price, showInverted, setShowInverted }: TradePriceProps) { export default function TradePrice({ price }: TradePriceProps) {
const theme = useTheme() const [showInverted, setShowInverted] = useState<boolean>(false)
const usdcPrice = useStablecoinPrice(showInverted ? price.baseCurrency : price.quoteCurrency) const usdcPrice = useStablecoinPrice(showInverted ? price.baseCurrency : price.quoteCurrency)
...@@ -58,9 +55,7 @@ export default function TradePrice({ price, showInverted, setShowInverted }: Tra ...@@ -58,9 +55,7 @@ export default function TradePrice({ price, showInverted, setShowInverted }: Tra
}} }}
title={text} title={text}
> >
<Text fontWeight={500} color={theme.textPrimary}> <ThemedText.BodySmall>{text}</ThemedText.BodySmall>{' '}
{text}
</Text>{' '}
{usdcPrice && ( {usdcPrice && (
<ThemedText.DeprecatedDarkGray> <ThemedText.DeprecatedDarkGray>
<Trans>({formatDollar({ num: priceToPreciseFloat(usdcPrice), isPrice: true })})</Trans> <Trans>({formatDollar({ num: priceToPreciseFloat(usdcPrice), isPrice: true })})</Trans>
......
...@@ -12,7 +12,6 @@ export const PageWrapper = styled.div` ...@@ -12,7 +12,6 @@ export const PageWrapper = styled.div`
padding: 68px 8px 0px; padding: 68px 8px 0px;
max-width: 480px; max-width: 480px;
width: 100%; width: 100%;
height: 100vh;
@media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.md}px`}) { @media only screen and (max-width: ${({ theme }) => `${theme.breakpoint.md}px`}) {
padding-top: 48px; padding-top: 48px;
......
...@@ -2,4 +2,5 @@ export enum FeatureFlag { ...@@ -2,4 +2,5 @@ export enum FeatureFlag {
fiatOnramp = 'fiatOnramp', fiatOnramp = 'fiatOnramp',
traceJsonRpc = 'traceJsonRpc', traceJsonRpc = 'traceJsonRpc',
permit2 = 'permit2', permit2 = 'permit2',
landingRedirect = 'landingRedirect',
} }
import { BaseVariant, FeatureFlag, useBaseFlag } from '../index' import { BaseVariant, FeatureFlag, useBaseFlag } from '../index'
export function useFiatOnrampFlag(): BaseVariant { export function useLandingRedirectFlag(): BaseVariant {
return useBaseFlag(FeatureFlag.fiatOnramp) return useBaseFlag(FeatureFlag.landingRedirect)
} }
export { BaseVariant as LandingRedirectVariant }
...@@ -20,13 +20,13 @@ enum SyncState { ...@@ -20,13 +20,13 @@ enum SyncState {
export enum PermitState { export enum PermitState {
INVALID, INVALID,
LOADING, LOADING,
PERMIT_NEEDED, APPROVAL_OR_PERMIT_NEEDED,
PERMITTED, APPROVAL_LOADING,
APPROVED_AND_PERMITTED,
} }
export interface Permit { export interface Permit {
state: PermitState state: PermitState
isSyncing?: boolean
signature?: PermitSignature signature?: PermitSignature
callback?: () => Promise<{ callback?: () => Promise<{
response: ContractTransaction response: ContractTransaction
...@@ -81,9 +81,8 @@ export default function usePermit(amount?: CurrencyAmount<Token>, spender?: stri ...@@ -81,9 +81,8 @@ export default function usePermit(amount?: CurrencyAmount<Token>, spender?: stri
// Permit2 should be marked syncing from the time approval is submitted (pending) until it is // Permit2 should be marked syncing from the time approval is submitted (pending) until it is
// synced in tokenAllowance, to avoid re-prompting the user for an already-submitted approval. // synced in tokenAllowance, to avoid re-prompting the user for an already-submitted approval.
// It should *not* be marked syncing if not permitted, because the user must still take action.
const [syncState, setSyncState] = useState(SyncState.SYNCED) const [syncState, setSyncState] = useState(SyncState.SYNCED)
const isSyncing = isPermitted || isSigned ? false : syncState !== SyncState.SYNCED const isApprovalLoading = syncState !== SyncState.SYNCED
const hasPendingApproval = useHasPendingApproval(amount?.currency, PERMIT2_ADDRESS) const hasPendingApproval = useHasPendingApproval(amount?.currency, PERMIT2_ADDRESS)
useEffect(() => { useEffect(() => {
if (hasPendingApproval) { if (hasPendingApproval) {
...@@ -117,13 +116,25 @@ export default function usePermit(amount?: CurrencyAmount<Token>, spender?: stri ...@@ -117,13 +116,25 @@ export default function usePermit(amount?: CurrencyAmount<Token>, spender?: stri
return { state: PermitState.INVALID } return { state: PermitState.INVALID }
} else if (!tokenAllowance || !permitAllowance) { } else if (!tokenAllowance || !permitAllowance) {
return { state: PermitState.LOADING } return { state: PermitState.LOADING }
} else if (isAllowed) { } else if (!(isPermitted || isSigned)) {
if (isPermitted) { return { state: PermitState.APPROVAL_OR_PERMIT_NEEDED, callback }
return { state: PermitState.PERMITTED } } else if (!isAllowed) {
} else if (isSigned) { return {
return { state: PermitState.PERMITTED, signature } state: isApprovalLoading ? PermitState.APPROVAL_LOADING : PermitState.APPROVAL_OR_PERMIT_NEEDED,
callback,
} }
} else {
return { state: PermitState.APPROVED_AND_PERMITTED, signature: isPermitted ? undefined : signature }
} }
return { state: PermitState.PERMIT_NEEDED, isSyncing, callback } }, [
}, [amount, callback, isAllowed, isPermitted, isSigned, isSyncing, permitAllowance, signature, tokenAllowance]) amount,
callback,
isAllowed,
isApprovalLoading,
isPermitted,
isSigned,
permitAllowance,
signature,
tokenAllowance,
])
} }
/* eslint-disable @typescript-eslint/no-var-requires */
import Modal from 'components/Modal'
import { useState } from 'react'
import { X } from 'react-feather'
import styled, { useTheme } from 'styled-components/macro'
import { ExternalLink } from 'theme/components'
import { ThemedText } from 'theme/components/text'
const Container = styled.div`
position: relative;
display: flex;
padding: 30% 24px 24px;
overflow: hidden;
height: fit-content;
user-select: none;
`
const CloseButton = styled(X)`
position: absolute;
top: 20px;
right: 24px;
cursor: pointer;
`
const Background = styled.img`
position: absolute;
top: 0;
left: 0;
width: 100%;
object-fit: contain;
`
const Content = styled.div`
display: flex;
flex-direction: column;
z-index: 1;
gap: 16px;
`
const Link = styled(ExternalLink)`
color: ${({ theme }) => theme.accentActive};
stroke: ${({ theme }) => theme.accentActive};
`
const Title = styled(ThemedText.LargeHeader)`
@media (max-width: ${({ theme }) => theme.breakpoint.xl}px) {
font-size: 20px !important;
}
`
const Paragraph = styled(ThemedText.BodySecondary)`
line-height: 24px;
@media (max-width: ${({ theme }) => theme.breakpoint.xl}px) {
font-size: 14px !important;
line-height: 20px;
}
`
const BACKGROUND_IMAGE = {
dark: {
src: require('../../../assets/images/welcomeModal-dark.jpg').default,
srcSet: `
${require('../../../assets/images/welcomeModal-dark@2x.jpg').default} 2x,
${require('../../../assets/images/welcomeModal-dark@3x.jpg').default} 3x,
`,
},
light: {
src: require('../../../assets/images/welcomeModal-light.jpg').default,
srcSet: `
${require('../../../assets/images/welcomeModal-light@2x.jpg').default} 2x,
${require('../../../assets/images/welcomeModal-light@3x.jpg').default} 3x,
`,
},
}
export function WelcomeModal({ onDismissed }: { onDismissed: () => void }) {
const [isOpen, setIsOpen] = useState(true)
const dismiss = () => {
setIsOpen(false)
setTimeout(() => onDismissed())
}
const theme = useTheme()
return (
<Modal isOpen={isOpen} onSwipe={dismiss} maxWidth={720} isBottomSheet={false}>
<Container data-testid="nft-welcome-modal">
<Background
{...(theme.darkMode ? BACKGROUND_IMAGE.dark : BACKGROUND_IMAGE.light)}
alt="Welcome modal background"
draggable={false}
/>
<Content>
<Title>Introducing NFTs on Uniswap</Title>
<Paragraph>
You can now buy and sell NFTs on Uniswap across marketplaces. Trade here to find more listings and better
prices. <br />
<br />
NFTs on Uniswap replaces Genie, which was{' '}
<Link href="https://uniswap.org/blog/genie" title="Uniswap Labs has acquired Genie">
acquired{' '}
</Link>{' '}
by Uniswap Labs earlier this year. If you have used Genie in the past, you may be eligible for a USDC
airdrop.{' '}
<Link
href="https://uniswap.org/blog/uniswap-nft-aggregator-announcement"
title="Uniswap NFT aggregator announcement"
>
Learn more.
</Link>
</Paragraph>
<CloseButton data-testid="nft-intro-modal" size={24} onClick={dismiss} />
</Content>
</Container>
</Modal>
)
}
import { Trans } from '@lingui/macro'
import { LARGE_MEDIA_BREAKPOINT, SMALL_MOBILE_MEDIA_BREAKPOINT } from 'components/Tokens/constants'
import { Box } from 'nft/components/Box'
import { bodySmall, subhead } from 'nft/css/common.css'
import { X } from 'react-feather'
import { useNavigate } from 'react-router-dom'
import { Link } from 'react-router-dom'
import { useHideNftPromoBanner } from 'state/user/hooks'
import styled, { css } from 'styled-components/macro'
import { ClickableStyle } from 'theme'
import { Z_INDEX } from 'theme/zIndex'
import nftPromoImage1 from '../nftExploreBanner/nftArt1.png'
import nftPromoImage2 from '../nftExploreBanner/nftArt2.png'
import nftPromoImage3 from '../nftExploreBanner/nftArt3.png'
function getRandom(list: any[]) {
return list[Math.floor(Math.random() * list.length)]
}
const randomizedNftImage = getRandom([nftPromoImage1, nftPromoImage2, nftPromoImage3])
const PopupContainer = styled.div<{ show: boolean }>`
background-color: ${({ theme }) => theme.backgroundSurface};
box-shadow: ${({ theme }) => theme.deepShadow};
border: 1px solid ${({ theme }) => theme.backgroundOutline};
border-radius: 12px;
cursor: pointer;
color: ${({ theme }) => theme.textPrimary};
display: ${({ show }) => (show ? 'flex' : 'none')};
flex-direction: column;
position: fixed;
right: clamp(0px, 1vw, 16px);
z-index: ${Z_INDEX.sticky};
transition: ${({
theme: {
transition: { duration, timing },
},
}) => `${duration.slow} opacity ${timing.in}`};
width: 98vw;
bottom: 55px;
@media screen and (min-width: ${LARGE_MEDIA_BREAKPOINT}) {
bottom: 48px;
}
@media screen and (min-width: ${SMALL_MOBILE_MEDIA_BREAKPOINT}) {
width: 391px;
}
:hover {
border: double 1px transparent;
border-radius: 12px;
background-image: ${({ theme }) =>
`linear-gradient(${theme.backgroundSurface}, ${theme.backgroundSurface}),
radial-gradient(circle at top left, hsla(299, 100%, 87%, 1), hsla(299, 100%, 61%, 1))`};
background-origin: border-box;
background-clip: padding-box, border-box;
}
`
const InnerContainer = styled.div`
overflow: hidden;
display: flex;
position: relative;
gap: 8px;
padding: 12px;
`
const TextContainer = styled.div`
display: flex;
flex-direction: column;
flex: 1;
justify-content: flex-start;
`
const StyledXButton = styled(X)`
color: ${({ theme }) => theme.textSecondary};
&:hover {
opacity: ${({ theme }) => theme.opacity.hover};
}
&:active {
opacity: ${({ theme }) => theme.opacity.click};
}
`
const StyledImageContainer = styled(Box)`
width: 20%;
cursor: pointer;
aspectratio: 1;
transition: transform 0.25s ease 0s;
object-fit: contain;
`
const LinkStyle = css`
color: ${({ theme }) => theme.accentActive};
stroke: ${({ theme }) => theme.accentActive};
`
const StyledLink = styled(Link)`
${ClickableStyle}
${LinkStyle}
`
export default function NftExploreBanner() {
const [hideNftPromoBanner, toggleHideNftPromoBanner] = useHideNftPromoBanner()
const navigate = useNavigate()
const navigateToNfts = () => {
navigate('/nfts')
toggleHideNftPromoBanner()
}
return (
<PopupContainer show={!hideNftPromoBanner} onClick={navigateToNfts}>
<InnerContainer>
<StyledImageContainer as="img" src={randomizedNftImage} draggable={false} />
<TextContainer>
{/* <HeaderText> */}
<div className={subhead}>
<Trans>Introducing NFTs on Uniswap</Trans>
</div>
{/* </HeaderText> */}
{/* <Description> */}
<div className={bodySmall}>
<Trans>Buy and sell NFTs across more listings at better prices.</Trans>{' '}
<StyledLink to="/nfts">
<Trans>Explore NFTs</Trans>
</StyledLink>{' '}
</div>
</TextContainer>
{/* </Description> */}
<StyledXButton
size={20}
onClick={(e) => {
e.preventDefault()
e.stopPropagation()
toggleHideNftPromoBanner()
}}
/>
</InnerContainer>
</PopupContainer>
)
}
...@@ -34,7 +34,7 @@ const ListingHeader = styled(Row)` ...@@ -34,7 +34,7 @@ const ListingHeader = styled(Row)`
margin-top: 18px; margin-top: 18px;
@media screen and (min-width: ${SMALL_MEDIA_BREAKPOINT}) { @media screen and (min-width: ${SMALL_MEDIA_BREAKPOINT}) {
margin-top: 40px; margin-top: 16px;
} }
` `
......
...@@ -10,9 +10,21 @@ import { LOOKS_RARE_CREATOR_BASIS_POINTS } from 'nft/utils' ...@@ -10,9 +10,21 @@ import { LOOKS_RARE_CREATOR_BASIS_POINTS } from 'nft/utils'
import { formatEth, formatUsdPrice } from 'nft/utils/currency' import { formatEth, formatUsdPrice } from 'nft/utils/currency'
import { fetchPrice } from 'nft/utils/fetchPrice' import { fetchPrice } from 'nft/utils/fetchPrice'
import { Dispatch, FormEvent, useEffect, useMemo, useRef, useState } from 'react' import { Dispatch, FormEvent, useEffect, useMemo, useRef, useState } from 'react'
import styled from 'styled-components/macro'
import * as styles from './ListPage.css' import * as styles from './ListPage.css'
const TableHeader = styled.div`
display: flex;
position: sticky;
align-items: center;
top: 72px;
padding-top: 24px;
padding-bottom: 24px;
z-index: 1;
background-color: ${({ theme }) => theme.backgroundBackdrop};
`
enum SetPriceMethod { enum SetPriceMethod {
SAME_PRICE, SAME_PRICE,
FLOOR_PRICE, FLOOR_PRICE,
...@@ -44,7 +56,7 @@ export const NFTListingsGrid = ({ selectedMarkets }: { selectedMarkets: ListingM ...@@ -44,7 +56,7 @@ export const NFTListingsGrid = ({ selectedMarkets }: { selectedMarkets: ListingM
return ( return (
<Column> <Column>
<Row marginTop="20"> <TableHeader>
<Column <Column
marginLeft={selectedMarkets.length > 1 ? '36' : '0'} marginLeft={selectedMarkets.length > 1 ? '36' : '0'}
transition="500" transition="500"
...@@ -86,7 +98,7 @@ export const NFTListingsGrid = ({ selectedMarkets }: { selectedMarkets: ListingM ...@@ -86,7 +98,7 @@ export const NFTListingsGrid = ({ selectedMarkets }: { selectedMarkets: ListingM
You receive You receive
</Column> </Column>
</Row> </Row>
</Row> </TableHeader>
{sellAssets.map((asset) => { {sellAssets.map((asset) => {
return ( return (
<> <>
......
...@@ -2,10 +2,8 @@ import { Trace } from '@uniswap/analytics' ...@@ -2,10 +2,8 @@ import { Trace } from '@uniswap/analytics'
import { PageName } from '@uniswap/analytics-events' import { PageName } from '@uniswap/analytics-events'
import Banner from 'nft/components/explore/Banner' import Banner from 'nft/components/explore/Banner'
import TrendingCollections from 'nft/components/explore/TrendingCollections' import TrendingCollections from 'nft/components/explore/TrendingCollections'
import { WelcomeModal } from 'nft/components/explore/WelcomeModal'
import { useBag } from 'nft/hooks' import { useBag } from 'nft/hooks'
import { useEffect } from 'react' import { useEffect } from 'react'
import { useHideNFTWelcomeModal } from 'state/user/hooks'
import styled from 'styled-components/macro' import styled from 'styled-components/macro'
const ExploreContainer = styled.div` const ExploreContainer = styled.div`
...@@ -25,7 +23,6 @@ const ExploreContainer = styled.div` ...@@ -25,7 +23,6 @@ const ExploreContainer = styled.div`
const NftExplore = () => { const NftExplore = () => {
const setBagExpanded = useBag((state) => state.setBagExpanded) const setBagExpanded = useBag((state) => state.setBagExpanded)
const [isModalHidden, hideModal] = useHideNFTWelcomeModal()
useEffect(() => { useEffect(() => {
setBagExpanded({ bagExpanded: false, manualClose: false }) setBagExpanded({ bagExpanded: false, manualClose: false })
...@@ -38,7 +35,6 @@ const NftExplore = () => { ...@@ -38,7 +35,6 @@ const NftExplore = () => {
<Banner /> <Banner />
<TrendingCollections /> <TrendingCollections />
</ExploreContainer> </ExploreContainer>
{!isModalHidden && <WelcomeModal onDismissed={hideModal} />}
</Trace> </Trace>
</> </>
) )
......
...@@ -36,6 +36,7 @@ import Manage from './Earn/Manage' ...@@ -36,6 +36,7 @@ import Manage from './Earn/Manage'
import Landing from './Landing' import Landing from './Landing'
import MigrateV2 from './MigrateV2' import MigrateV2 from './MigrateV2'
import MigrateV2Pair from './MigrateV2/MigrateV2Pair' import MigrateV2Pair from './MigrateV2/MigrateV2Pair'
import NotFound from './NotFound'
import Pool from './Pool' import Pool from './Pool'
import { PositionPage } from './Pool/PositionPage' import { PositionPage } from './Pool/PositionPage'
import PoolV2 from './Pool/v2' import PoolV2 from './Pool/v2'
...@@ -64,29 +65,19 @@ initializeAnalytics(ANALYTICS_DUMMY_KEY, OriginApplication.INTERFACE, { ...@@ -64,29 +65,19 @@ initializeAnalytics(ANALYTICS_DUMMY_KEY, OriginApplication.INTERFACE, {
isProductionEnv: isProductionEnv(), isProductionEnv: isProductionEnv(),
}) })
const AppWrapper = styled.div`
display: flex;
flex-flow: column;
align-items: flex-start;
height: 100%;
`
const BodyWrapper = styled.div` const BodyWrapper = styled.div`
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
height: 100%; min-height: 100vh;
padding: 72px 0px 0px 0px; padding: ${({ theme }) => theme.navHeight}px 0px 5rem 0px;
align-items: center; align-items: center;
flex: 1; flex: 1;
${({ theme }) => theme.deprecated_mediaWidth.deprecated_upToSmall`
padding: 52px 0px 16px 0px;
`};
` `
const MobileBottomBar = styled.div` const MobileBottomBar = styled.div`
z-index: ${Z_INDEX.sticky}; z-index: ${Z_INDEX.sticky};
position: sticky; position: fixed;
display: flex; display: flex;
bottom: 0; bottom: 0;
right: 0; right: 0;
...@@ -114,10 +105,6 @@ const HeaderWrapper = styled.div<{ transparent?: boolean }>` ...@@ -114,10 +105,6 @@ const HeaderWrapper = styled.div<{ transparent?: boolean }>`
z-index: ${Z_INDEX.dropdown}; z-index: ${Z_INDEX.dropdown};
` `
const Marginer = styled.div`
margin-top: 5rem;
`
function getCurrentPageFromLocation(locationPathname: string): PageName | undefined { function getCurrentPageFromLocation(locationPathname: string): PageName | undefined {
switch (true) { switch (true) {
case locationPathname.startsWith('/swap'): case locationPathname.startsWith('/swap'):
...@@ -205,7 +192,6 @@ export default function App() { ...@@ -205,7 +192,6 @@ export default function App() {
<ErrorBoundary> <ErrorBoundary>
<DarkModeQueryParamReader /> <DarkModeQueryParamReader />
<ApeModeQueryParamReader /> <ApeModeQueryParamReader />
<AppWrapper>
<Trace page={currentPage}> <Trace page={currentPage}>
<HeaderWrapper transparent={isHeaderTransparent}> <HeaderWrapper transparent={isHeaderTransparent}>
<NavBar /> <NavBar />
...@@ -218,6 +204,7 @@ export default function App() { ...@@ -218,6 +204,7 @@ export default function App() {
{isLoaded ? ( {isLoaded ? (
<Routes> <Routes>
<Route path="/" element={<Landing />} /> <Route path="/" element={<Landing />} />
<Route path="tokens" element={<Tokens />}> <Route path="tokens" element={<Tokens />}>
<Route path=":chainName" /> <Route path=":chainName" />
</Route> </Route>
...@@ -269,8 +256,6 @@ export default function App() { ...@@ -269,8 +256,6 @@ export default function App() {
<Route path="about" element={<About />} /> <Route path="about" element={<About />} />
<Route path="*" element={<RedirectPathToSwapOnly />} />
<Route <Route
path="/nfts" path="/nfts"
element={ element={
...@@ -312,12 +297,14 @@ export default function App() { ...@@ -312,12 +297,14 @@ export default function App() {
</Suspense> </Suspense>
} }
/> />
<Route path="*" element={<Navigate to="/not-found" replace />} />
<Route path="/not-found" element={<NotFound />} />
</Routes> </Routes>
) : ( ) : (
<Loader /> <Loader />
)} )}
</Suspense> </Suspense>
<Marginer />
</BodyWrapper> </BodyWrapper>
<MobileBottomBar> <MobileBottomBar>
<PageTabs /> <PageTabs />
...@@ -326,7 +313,6 @@ export default function App() { ...@@ -326,7 +313,6 @@ export default function App() {
</Box> </Box>
</MobileBottomBar> </MobileBottomBar>
</Trace> </Trace>
</AppWrapper>
</ErrorBoundary> </ErrorBoundary>
) )
} }
import { Trace, TraceEvent } from '@uniswap/analytics' import { Trace, TraceEvent } from '@uniswap/analytics'
import { BrowserEvent, ElementName, EventName, PageName } from '@uniswap/analytics-events' import { BrowserEvent, ElementName, EventName, PageName } from '@uniswap/analytics-events'
import { BaseButton } from 'components/Button' import { BaseButton } from 'components/Button'
import { LandingRedirectVariant, useLandingRedirectFlag } from 'featureFlags/flags/landingRedirect'
import Swap from 'pages/Swap' import Swap from 'pages/Swap'
import { useEffect } from 'react' import { useEffect, useState } from 'react'
import { useLocation } from 'react-router-dom' import { useLocation, useNavigate } from 'react-router-dom'
import { Link as NativeLink } from 'react-router-dom' import { Link as NativeLink } from 'react-router-dom'
import { useAppSelector } from 'state/hooks'
import { useIsDarkMode } from 'state/user/hooks' import { useIsDarkMode } from 'state/user/hooks'
import styled from 'styled-components/macro' import styled from 'styled-components/macro'
import { BREAKPOINTS } from 'theme' import { BREAKPOINTS } from 'theme'
...@@ -176,10 +178,27 @@ export default function Landing() { ...@@ -176,10 +178,27 @@ export default function Landing() {
} }
}, []) }, [])
const [showContent, setShowContent] = useState(false)
const selectedWallet = useAppSelector((state) => state.user.selectedWallet)
const landingRedirectFlag = useLandingRedirectFlag()
const navigate = useNavigate()
useEffect(() => {
if (selectedWallet) {
if (landingRedirectFlag === LandingRedirectVariant.Enabled) {
navigate('/swap')
} else {
setShowContent(true)
}
} else {
setShowContent(true)
}
}, [navigate, selectedWallet, landingRedirectFlag])
if (!isOpen) return null if (!isOpen) return null
return ( return (
<Trace page={PageName.LANDING_PAGE} shouldLogImpression> <Trace page={PageName.LANDING_PAGE} shouldLogImpression>
{showContent && (
<PageContainer> <PageContainer>
<TraceEvent <TraceEvent
events={[BrowserEvent.onClick]} events={[BrowserEvent.onClick]}
...@@ -210,6 +229,7 @@ export default function Landing() { ...@@ -210,6 +229,7 @@ export default function Landing() {
</ActionsContainer> </ActionsContainer>
</ContentContainer> </ContentContainer>
</PageContainer> </PageContainer>
)}
</Trace> </Trace>
) )
} }
import { Trans } from '@lingui/macro'
import { Trace } from '@uniswap/analytics'
import { SmallButtonPrimary } from 'components/Button'
import { useIsMobile } from 'nft/hooks'
import { Link } from 'react-router-dom'
import { useIsDarkMode } from 'state/user/hooks'
import styled from 'styled-components/macro'
import { ThemedText } from 'theme'
import darkImage from '../../assets/images/404-page-dark.png'
import lightImage from '../../assets/images/404-page-light.png'
const Image = styled.img`
max-width: 510px;
width: 100%;
padding: 0 75px;
`
const Container = styled.div`
display: flex;
flex-direction: column;
align-items: center;
`
const Header = styled(Container)`
gap: 30px;
`
const PageWrapper = styled(Container)`
flex: 1;
justify-content: center;
gap: 50px;
@media screen and (min-width: ${({ theme }) => theme.breakpoint.md}px) {
justify-content: space-between;
padding-top: 64px;
}
`
export default function NotFound() {
const isDarkMode = useIsDarkMode()
const isMobile = useIsMobile()
const Title = isMobile ? ThemedText.LargeHeader : ThemedText.Hero
const Paragraph = isMobile ? ThemedText.HeadlineMedium : ThemedText.HeadlineLarge
return (
<PageWrapper>
<Trace page="404-page" shouldLogImpression>
<Header>
<Container>
<Title>404</Title>
<Paragraph color="textSecondary">
<Trans>Page not found!</Trans>
</Paragraph>
</Container>
<Image src={isDarkMode ? darkImage : lightImage} alt="Liluni" />
</Header>
<SmallButtonPrimary as={Link} to="/">
<Trans>Oops, take me back to Swap</Trans>
</SmallButtonPrimary>
</Trace>
</PageWrapper>
)
}
...@@ -165,7 +165,7 @@ function WrongNetworkCard() { ...@@ -165,7 +165,7 @@ function WrongNetworkCard() {
const theme = useTheme() const theme = useTheme()
return ( return (
<div style={{ height: '100vh' }}> <>
<PageWrapper> <PageWrapper>
<AutoColumn gap="lg" justify="center"> <AutoColumn gap="lg" justify="center">
<AutoColumn gap="lg" style={{ width: '100%' }}> <AutoColumn gap="lg" style={{ width: '100%' }}>
...@@ -189,7 +189,7 @@ function WrongNetworkCard() { ...@@ -189,7 +189,7 @@ function WrongNetworkCard() {
</AutoColumn> </AutoColumn>
</PageWrapper> </PageWrapper>
<SwitchLocaleLink /> <SwitchLocaleLink />
</div> </>
) )
} }
...@@ -263,7 +263,6 @@ export default function Pool() { ...@@ -263,7 +263,6 @@ export default function Pool() {
return ( return (
<Trace page={PageName.POOL_PAGE} shouldLogImpression> <Trace page={PageName.POOL_PAGE} shouldLogImpression>
<div style={{ height: '100vh' }}>
<PageWrapper> <PageWrapper>
<AutoColumn gap="lg" justify="center"> <AutoColumn gap="lg" justify="center">
<AutoColumn gap="lg" style={{ width: '100%' }}> <AutoColumn gap="lg" style={{ width: '100%' }}>
...@@ -342,7 +341,6 @@ export default function Pool() { ...@@ -342,7 +341,6 @@ export default function Pool() {
</AutoColumn> </AutoColumn>
</PageWrapper> </PageWrapper>
<SwitchLocaleLink /> <SwitchLocaleLink />
</div>
</Trace> </Trace>
) )
} }
...@@ -299,7 +299,7 @@ export default function Swap({ className }: { className?: string }) { ...@@ -299,7 +299,7 @@ export default function Swap({ className }: { className?: string }) {
permit2Enabled ? maximumAmountIn : undefined, permit2Enabled ? maximumAmountIn : undefined,
permit2Enabled && chainId ? UNIVERSAL_ROUTER_ADDRESS(chainId) : undefined permit2Enabled && chainId ? UNIVERSAL_ROUTER_ADDRESS(chainId) : undefined
) )
const isApprovalPending = permit.isSyncing const isApprovalLoading = permit.state === PermitState.APPROVAL_LOADING
const [isPermitPending, setIsPermitPending] = useState(false) const [isPermitPending, setIsPermitPending] = useState(false)
const [isPermitFailed, setIsPermitFailed] = useState(false) const [isPermitFailed, setIsPermitFailed] = useState(false)
const addTransaction = useTransactionAdder() const addTransaction = useTransactionAdder()
...@@ -441,7 +441,6 @@ export default function Swap({ className }: { className?: string }) { ...@@ -441,7 +441,6 @@ export default function Swap({ className }: { className?: string }) {
]) ])
// errors // errors
const [showInverted, setShowInverted] = useState<boolean>(false)
const [swapQuoteReceivedDate, setSwapQuoteReceivedDate] = useState<Date | undefined>() const [swapQuoteReceivedDate, setSwapQuoteReceivedDate] = useState<Date | undefined>()
// warnings on the greater of fiat value price impact and execution price impact // warnings on the greater of fiat value price impact and execution price impact
...@@ -663,8 +662,6 @@ export default function Swap({ className }: { className?: string }) { ...@@ -663,8 +662,6 @@ export default function Swap({ className }: { className?: string }) {
trade={trade} trade={trade}
syncing={routeIsSyncing} syncing={routeIsSyncing}
loading={routeIsLoading} loading={routeIsLoading}
showInverted={showInverted}
setShowInverted={setShowInverted}
allowedSlippage={allowedSlippage} allowedSlippage={allowedSlippage}
/> />
</DetailsSwapSection> </DetailsSwapSection>
...@@ -786,10 +783,12 @@ export default function Swap({ className }: { className?: string }) { ...@@ -786,10 +783,12 @@ export default function Swap({ className }: { className?: string }) {
</ButtonError> </ButtonError>
</AutoColumn> </AutoColumn>
</AutoRow> </AutoRow>
) : isValid && permit.state === PermitState.PERMIT_NEEDED ? ( ) : isValid &&
(permit.state === PermitState.APPROVAL_OR_PERMIT_NEEDED ||
permit.state === PermitState.APPROVAL_LOADING) ? (
<ButtonYellow <ButtonYellow
onClick={updatePermit} onClick={updatePermit}
disabled={isPermitPending || isApprovalPending} disabled={isPermitPending || isApprovalLoading}
style={{ gap: 14 }} style={{ gap: 14 }}
> >
{isPermitPending ? ( {isPermitPending ? (
...@@ -806,7 +805,7 @@ export default function Swap({ className }: { className?: string }) { ...@@ -806,7 +805,7 @@ export default function Swap({ className }: { className?: string }) {
<Trans>Approval failed. Try again.</Trans> <Trans>Approval failed. Try again.</Trans>
</ThemedText.SubHeader> </ThemedText.SubHeader>
</> </>
) : isApprovalPending ? ( ) : isApprovalLoading ? (
<> <>
<Loader size="20px" stroke={theme.accentWarning} /> <Loader size="20px" stroke={theme.accentWarning} />
<ThemedText.SubHeader color="accentWarning"> <ThemedText.SubHeader color="accentWarning">
......
...@@ -4,8 +4,6 @@ import { useWeb3React } from '@web3-react/core' ...@@ -4,8 +4,6 @@ import { useWeb3React } from '@web3-react/core'
import { L2_CHAIN_IDS } from 'constants/chains' import { L2_CHAIN_IDS } from 'constants/chains'
import { SupportedLocale } from 'constants/locales' import { SupportedLocale } from 'constants/locales'
import { L2_DEADLINE_FROM_NOW } from 'constants/misc' import { L2_DEADLINE_FROM_NOW } from 'constants/misc'
import { BaseVariant } from 'featureFlags'
import { useFiatOnrampFlag } from 'featureFlags/flags/fiatOnramp'
import JSBI from 'jsbi' import JSBI from 'jsbi'
import { useCallback, useMemo } from 'react' import { useCallback, useMemo } from 'react'
import { shallowEqual } from 'react-redux' import { shallowEqual } from 'react-redux'
...@@ -21,8 +19,6 @@ import { ...@@ -21,8 +19,6 @@ import {
addSerializedToken, addSerializedToken,
updateFiatOnrampAcknowledgments, updateFiatOnrampAcknowledgments,
updateHideClosedPositions, updateHideClosedPositions,
updateHideNFTWelcomeModal,
updateShowNftPromoBanner,
updateUserClientSideRouter, updateUserClientSideRouter,
updateUserDarkMode, updateUserDarkMode,
updateUserDeadline, updateUserDeadline,
...@@ -127,15 +123,6 @@ export function useFiatOnrampAck(): [ ...@@ -127,15 +123,6 @@ export function useFiatOnrampAck(): [
) )
return [fiatOnrampAcknowledgments, setAcknowledgements] return [fiatOnrampAcknowledgments, setAcknowledgements]
} }
export function useHideNFTWelcomeModal(): [boolean | undefined, () => void] {
const dispatch = useAppDispatch()
const fiatOnrampFlagEnabled = useFiatOnrampFlag() === BaseVariant.Enabled
const hideNFTWelcomeModal = useAppSelector((state) => state.user.hideNFTWelcomeModal) || fiatOnrampFlagEnabled
const hideModal = useCallback(() => {
dispatch(updateHideNFTWelcomeModal({ hideNFTWelcomeModal: true }))
}, [dispatch])
return [hideNFTWelcomeModal, hideModal]
}
export function useClientSideRouter(): [boolean, (userClientSideRouter: boolean) => void] { export function useClientSideRouter(): [boolean, (userClientSideRouter: boolean) => void] {
const dispatch = useAppDispatch() const dispatch = useAppDispatch()
...@@ -281,17 +268,6 @@ export function useURLWarningVisible(): boolean { ...@@ -281,17 +268,6 @@ export function useURLWarningVisible(): boolean {
return useAppSelector((state: AppState) => state.user.URLWarningVisible) return useAppSelector((state: AppState) => state.user.URLWarningVisible)
} }
export function useHideNftPromoBanner(): [boolean, () => void] {
const dispatch = useAppDispatch()
const hideNftPromoBanner = useAppSelector((state) => state.user.hideNFTPromoBanner)
const toggleHideNftPromoBanner = useCallback(() => {
dispatch(updateShowNftPromoBanner({ hideNFTPromoBanner: true }))
}, [dispatch])
return [hideNftPromoBanner, toggleHideNftPromoBanner]
}
/** /**
* Given two tokens return the liquidity token that represents its liquidity shares * Given two tokens return the liquidity token that represents its liquidity shares
* @param tokenA one of the two tokens * @param tokenA one of the two tokens
......
...@@ -126,12 +126,6 @@ const userSlice = createSlice({ ...@@ -126,12 +126,6 @@ const userSlice = createSlice({
updateHideClosedPositions(state, action) { updateHideClosedPositions(state, action) {
state.userHideClosedPositions = action.payload.userHideClosedPositions state.userHideClosedPositions = action.payload.userHideClosedPositions
}, },
updateHideNFTWelcomeModal(state, action) {
state.hideNFTWelcomeModal = action.payload.hideNFTWelcomeModal
},
updateShowNftPromoBanner(state, action) {
state.hideNFTPromoBanner = action.payload.hideNFTPromoBanner
},
addSerializedToken(state, { payload: { serializedToken } }) { addSerializedToken(state, { payload: { serializedToken } }) {
if (!state.tokens) { if (!state.tokens) {
state.tokens = {} state.tokens = {}
...@@ -197,12 +191,10 @@ export const { ...@@ -197,12 +191,10 @@ export const {
updateHideClosedPositions, updateHideClosedPositions,
updateMatchesDarkMode, updateMatchesDarkMode,
updateUserClientSideRouter, updateUserClientSideRouter,
updateHideNFTWelcomeModal,
updateUserDarkMode, updateUserDarkMode,
updateUserDeadline, updateUserDeadline,
updateUserExpertMode, updateUserExpertMode,
updateUserLocale, updateUserLocale,
updateUserSlippageTolerance, updateUserSlippageTolerance,
updateShowNftPromoBanner,
} = userSlice.actions } = userSlice.actions
export default userSlice.reducer export default userSlice.reducer
...@@ -31,12 +31,18 @@ export const ThemedText = { ...@@ -31,12 +31,18 @@ export const ThemedText = {
HeadlineSmall(props: TextProps) { HeadlineSmall(props: TextProps) {
return <TextWrapper fontWeight={600} fontSize={20} lineHeight="28px" color="textPrimary" {...props} /> return <TextWrapper fontWeight={600} fontSize={20} lineHeight="28px" color="textPrimary" {...props} />
}, },
HeadlineMedium(props: TextProps) {
return <TextWrapper fontWeight={500} fontSize={28} color="textPrimary" {...props} />
},
HeadlineLarge(props: TextProps) { HeadlineLarge(props: TextProps) {
return <TextWrapper fontWeight={600} fontSize={36} lineHeight="44px" color="textPrimary" {...props} /> return <TextWrapper fontWeight={600} fontSize={36} lineHeight="36px" color="textPrimary" {...props} />
}, },
LargeHeader(props: TextProps) { LargeHeader(props: TextProps) {
return <TextWrapper fontWeight={400} fontSize={36} color="textPrimary" {...props} /> return <TextWrapper fontWeight={400} fontSize={36} color="textPrimary" {...props} />
}, },
Hero(props: TextProps) {
return <TextWrapper fontWeight={500} fontSize={48} color="textPrimary" {...props} />
},
Link(props: TextProps) { Link(props: TextProps) {
return <TextWrapper fontWeight={600} fontSize={14} color="accentAction" {...props} /> return <TextWrapper fontWeight={600} fontSize={14} color="accentAction" {...props} />
}, },
......
...@@ -91,7 +91,8 @@ function getSettings(darkMode: boolean) { ...@@ -91,7 +91,8 @@ function getSettings(darkMode: boolean) {
} }
} }
function getTheme(darkMode: boolean) { // eslint-disable-next-line import/no-unused-modules -- used in styled.d.ts
export function getTheme(darkMode: boolean) {
return { return {
darkMode, darkMode,
...(darkMode ? darkTheme : lightTheme), ...(darkMode ? darkTheme : lightTheme),
......
...@@ -4195,10 +4195,10 @@ ...@@ -4195,10 +4195,10 @@
"@typescript-eslint/types" "4.33.0" "@typescript-eslint/types" "4.33.0"
eslint-visitor-keys "^2.0.0" eslint-visitor-keys "^2.0.0"
"@uniswap/analytics-events@1.3.1": "@uniswap/analytics-events@^1.4.0":
version "1.3.1" version "1.4.0"
resolved "https://registry.yarnpkg.com/@uniswap/analytics-events/-/analytics-events-1.3.1.tgz#e1ad912001646268ea16f64622c683ca2a63002d" resolved "https://registry.yarnpkg.com/@uniswap/analytics-events/-/analytics-events-1.4.0.tgz#63b0fa55d9d258e3b29d07f38da194f9fa841d1d"
integrity sha512-EzYLBU123TpTCNPfa8cN7cI3Ap8D5Rn0771/bAtjSElZROR6YnGFNj0cjnaHwo8SIUr5Ema7JLoXbMVUyreFXQ== integrity sha512-KdY/8iRTbVirJN/ms8f68MfGM+zuCuz4E35Lw4m7xcQ03YAlE9j3Oa3UhsFSCialn8F6brmrAPsx8a8Ps6uoKw==
"@uniswap/analytics@1.2.0": "@uniswap/analytics@1.2.0":
version "1.2.0" version "1.2.0"
...@@ -4209,10 +4209,10 @@ ...@@ -4209,10 +4209,10 @@
react "^18.2.0" react "^18.2.0"
react-dom "^18.2.0" react-dom "^18.2.0"
"@uniswap/conedison@^1.1.0": "@uniswap/conedison@^1.1.1":
version "1.1.0" version "1.1.1"
resolved "https://registry.yarnpkg.com/@uniswap/conedison/-/conedison-1.1.0.tgz#462a1e7dcfc70a653e765c145655faa207fd53f7" resolved "https://registry.yarnpkg.com/@uniswap/conedison/-/conedison-1.1.1.tgz#affec246613d1f52da3cdd0571ef8195b7b54d17"
integrity sha512-mHnYkvy+xKfWDzWsqzgWKFl/V8C/KmSrj/2PCgT1R2ASxPzMCU/wzTW29HtIxf1cJ+A6sPwH2HqDZsbnNhKqNQ== integrity sha512-xFHAcWRrU+/+/BInXy6SRiiNwUG0vxLWsoYgod66wWifUvnjfpItzlvJHUer1OOpLDsz0CL5Fb70vFJOGAGi8w==
"@uniswap/default-token-list@^2.0.0": "@uniswap/default-token-list@^2.0.0":
version "2.2.0" version "2.2.0"
......
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