feat: update app download tracking for Android launch (#7542)

* feat: change UniwalletModal android text

* very wip android WC

* adding android/ios disambiguated event names

* put analytics events in todos

* use analytics package

* use isAndroidGALaunched

* fix ternary

* add navbar menu element

* broken onelink changes

* replace utm with onelinks

* use microsite link in address redirect

* fix unit tests, no longer discriminate between platforms expected behavior

* nit lint
This commit is contained in:
Kristie Huang 2023-11-07 17:24:44 -05:00 committed by GitHub
parent aa056adaf9
commit 46c8caa09c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 100 additions and 97 deletions

@ -197,7 +197,7 @@
"@types/react-helmet": "^6.1.7", "@types/react-helmet": "^6.1.7",
"@types/react-window-infinite-loader": "^1.0.6", "@types/react-window-infinite-loader": "^1.0.6",
"@uniswap/analytics": "1.5.0", "@uniswap/analytics": "1.5.0",
"@uniswap/analytics-events": "^2.25.0", "@uniswap/analytics-events": "^2.28.0",
"@uniswap/governance": "^1.0.2", "@uniswap/governance": "^1.0.2",
"@uniswap/liquidity-staker": "^1.0.2", "@uniswap/liquidity-staker": "^1.0.2",
"@uniswap/merkle-distributor": "^1.0.1", "@uniswap/merkle-distributor": "^1.0.1",

@ -1,4 +1,5 @@
import { InterfaceElementName } from '@uniswap/analytics-events' import { InterfaceElementName } from '@uniswap/analytics-events'
import { useAndroidGALaunchFlagEnabled } from 'featureFlags/flags/androidGALaunch'
import { PropsWithChildren, useCallback } from 'react' import { PropsWithChildren, useCallback } from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import { ClickableStyle } from 'theme/components' import { ClickableStyle } from 'theme/components'
@ -31,7 +32,7 @@ function BaseButton({ onClick, branded, children }: PropsWithChildren<{ onClick?
) )
} }
// Launches App Store if on an iOS device, else navigates to Uniswap Wallet microsite // Launches App/Play Store if on an iOS/Android device, else navigates to Uniswap Wallet microsite
export function DownloadButton({ export function DownloadButton({
onClick, onClick,
text = 'Download', text = 'Download',
@ -41,11 +42,12 @@ export function DownloadButton({
text?: string text?: string
element: InterfaceElementName element: InterfaceElementName
}) { }) {
const isAndroidGALaunched = useAndroidGALaunchFlagEnabled()
const onButtonClick = useCallback(() => { const onButtonClick = useCallback(() => {
// handles any actions required by the parent, i.e. cancelling wallet connection attempt or dismissing an ad // handles any actions required by the parent, i.e. cancelling wallet connection attempt or dismissing an ad
onClick?.() onClick?.()
openDownloadApp({ element }) openDownloadApp({ element, isAndroidGALaunched })
}, [element, onClick]) }, [element, isAndroidGALaunched, onClick])
return ( return (
<BaseButton branded onClick={onButtonClick}> <BaseButton branded onClick={onButtonClick}>

@ -1,5 +1,5 @@
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import { InterfaceElementName } from '@uniswap/analytics-events' import { InterfaceElementName, InterfaceEventName } from '@uniswap/analytics-events'
import { WalletConnect as WalletConnectv2 } from '@web3-react/walletconnect-v2' import { WalletConnect as WalletConnectv2 } from '@web3-react/walletconnect-v2'
import { sendAnalyticsEvent } from 'analytics' import { sendAnalyticsEvent } from 'analytics'
import Column, { AutoColumn } from 'components/Column' import Column, { AutoColumn } from 'components/Column'
@ -9,11 +9,12 @@ import { uniwalletWCV2ConnectConnection } from 'connection'
import { ActivationStatus, useActivationState } from 'connection/activate' import { ActivationStatus, useActivationState } from 'connection/activate'
import { ConnectionType } from 'connection/types' import { ConnectionType } from 'connection/types'
import { UniwalletConnect as UniwalletConnectV2 } from 'connection/WalletConnectV2' import { UniwalletConnect as UniwalletConnectV2 } from 'connection/WalletConnectV2'
import { useAndroidGALaunchFlagEnabled } from 'featureFlags/flags/androidGALaunch'
import { QRCodeSVG } from 'qrcode.react' import { QRCodeSVG } from 'qrcode.react'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import styled, { useTheme } from 'styled-components' import styled, { useTheme } from 'styled-components'
import { CloseIcon, ThemedText } from 'theme/components' import { CloseIcon, ThemedText } from 'theme/components'
import { isIOS } from 'utils/userAgent' import { isAndroid, isIOS } from 'utils/userAgent'
import uniPng from '../../assets/images/uniwallet_modal_icon.png' import uniPng from '../../assets/images/uniwallet_modal_icon.png'
import { DownloadButton } from './DownloadButton' import { DownloadButton } from './DownloadButton'
@ -42,9 +43,11 @@ export default function UniwalletModal() {
const { activationState, cancelActivation } = useActivationState() const { activationState, cancelActivation } = useActivationState()
const [uri, setUri] = useState<string>() const [uri, setUri] = useState<string>()
// Displays the modal if not on iOS, a Uniswap Wallet Connection is pending, & qrcode URI is available const isAndroidGALaunched = useAndroidGALaunchFlagEnabled()
// Displays the modal if not on iOS/Android, a Uniswap Wallet Connection is pending, & qrcode URI is available
const onLaunchedMobilePlatform = isIOS || (isAndroidGALaunched && isAndroid)
const open = const open =
!isIOS && !onLaunchedMobilePlatform &&
activationState.status === ActivationStatus.PENDING && activationState.status === ActivationStatus.PENDING &&
activationState.connection.type === ConnectionType.UNISWAP_WALLET_V2 && activationState.connection.type === ConnectionType.UNISWAP_WALLET_V2 &&
!!uri !!uri
@ -57,7 +60,7 @@ export default function UniwalletModal() {
}, []) }, [])
useEffect(() => { useEffect(() => {
if (open) sendAnalyticsEvent('Uniswap wallet modal opened') if (open) sendAnalyticsEvent(InterfaceEventName.UNIWALLET_CONNECT_MODAL_OPENED)
}, [open]) }, [open])
const theme = useTheme() const theme = useTheme()
@ -102,6 +105,8 @@ const InfoSectionWrapper = styled(RowBetween)`
` `
function InfoSection() { function InfoSection() {
const isAndroidGALaunched = useAndroidGALaunchFlagEnabled()
return ( return (
<InfoSectionWrapper> <InfoSectionWrapper>
<AutoColumn gap="4px"> <AutoColumn gap="4px">
@ -109,9 +114,13 @@ function InfoSection() {
<Trans>Don&apos;t have Uniswap Wallet?</Trans> <Trans>Don&apos;t have Uniswap Wallet?</Trans>
</ThemedText.SubHeaderSmall> </ThemedText.SubHeaderSmall>
<ThemedText.BodySmall color="neutral2"> <ThemedText.BodySmall color="neutral2">
{isAndroidGALaunched ? (
<Trans>Get the Uniswap app on iOS and Android to safely store and swap tokens.</Trans>
) : (
<Trans> <Trans>
Download in the App Store to safely store your tokens and NFTs, swap tokens, and connect to crypto apps. Download in the App Store to safely store your tokens and NFTs, swap tokens, and connect to crypto apps.
</Trans> </Trans>
)}
</ThemedText.BodySmall> </ThemedText.BodySmall>
</AutoColumn> </AutoColumn>
<Column> <Column>

@ -11,7 +11,7 @@ import { useLocation } from 'react-router-dom'
import { useHideBaseWalletBanner } from 'state/user/hooks' import { useHideBaseWalletBanner } from 'state/user/hooks'
import { ThemedText } from 'theme/components' import { ThemedText } from 'theme/components'
import { openDownloadApp, openWalletMicrosite } from 'utils/openDownloadApp' import { openDownloadApp, openWalletMicrosite } from 'utils/openDownloadApp'
import { isIOS, isMobileSafari } from 'utils/userAgent' import { isAndroid, isIOS, isMobileSafari } from 'utils/userAgent'
import { BannerButton, BaseBackgroundImage, ButtonRow, PopupContainer, StyledXButton } from './styled' import { BannerButton, BaseBackgroundImage, ButtonRow, PopupContainer, StyledXButton } from './styled'
@ -60,14 +60,14 @@ export default function BaseWalletBanner() {
</ThemedText.HeadlineMedium> </ThemedText.HeadlineMedium>
<ButtonRow> <ButtonRow>
{isIOS ? ( {isIOS || (isAndroidGALaunched && isAndroid) ? (
<> <>
<BannerButton <BannerButton
backgroundColor="white" backgroundColor="white"
onClick={() => onClick={() =>
openDownloadApp({ openDownloadApp({
element: InterfaceElementName.UNISWAP_WALLET_BANNER_DOWNLOAD_BUTTON, element: InterfaceElementName.UNISWAP_WALLET_BANNER_DOWNLOAD_BUTTON,
appStoreParams: 'pt=123625782&ct=base-app-banner&mt=8', isAndroidGALaunched,
}) })
} }
> >
@ -77,14 +77,23 @@ export default function BaseWalletBanner() {
</ThemedText.LabelSmall> </ThemedText.LabelSmall>
</BannerButton> </BannerButton>
<BannerButton backgroundColor="black" onClick={() => openWalletMicrosite()}> <BannerButton
backgroundColor="black"
onClick={() =>
openWalletMicrosite({ element: InterfaceElementName.UNISWAP_WALLET_BANNER_DOWNLOAD_BUTTON })
}
>
<ThemedText.LabelSmall color="white"> <ThemedText.LabelSmall color="white">
<Trans>Learn more</Trans> <Trans>Learn more</Trans>
</ThemedText.LabelSmall> </ThemedText.LabelSmall>
</BannerButton> </BannerButton>
</> </>
) : ( ) : (
<BannerButton backgroundColor="white" width="125px" onClick={() => openWalletMicrosite()}> <BannerButton
backgroundColor="white"
width="125px"
onClick={() => openWalletMicrosite({ element: InterfaceElementName.UNISWAP_WALLET_BANNER_DOWNLOAD_BUTTON })}
>
<ThemedText.LabelSmall color="black"> <ThemedText.LabelSmall color="black">
<Trans>Learn more</Trans> <Trans>Learn more</Trans>
</ThemedText.LabelSmall> </ThemedText.LabelSmall>

@ -174,7 +174,8 @@ export const MenuDropdown = () => {
<Box <Box
onClick={() => onClick={() =>
openDownloadApp({ openDownloadApp({
element: InterfaceElementName.UNISWAP_WALLET_MODAL_DOWNLOAD_BUTTON, element: InterfaceElementName.UNISWAP_WALLET_NAVBAR_MENU_DOWNLOAD_BUTTON,
isAndroidGALaunched,
}) })
} }
> >

@ -6,6 +6,7 @@ import { AutoRow } from 'components/Row'
import { connections, deprecatedNetworkConnection, networkConnection } from 'connection' import { connections, deprecatedNetworkConnection, networkConnection } from 'connection'
import { ActivationStatus, useActivationState } from 'connection/activate' import { ActivationStatus, useActivationState } from 'connection/activate'
import { isSupportedChain } from 'constants/chains' import { isSupportedChain } from 'constants/chains'
import { useAndroidGALaunchFlagEnabled } from 'featureFlags/flags/androidGALaunch'
import { useFallbackProviderEnabled } from 'featureFlags/flags/fallbackProvider' import { useFallbackProviderEnabled } from 'featureFlags/flags/fallbackProvider'
import { useEffect } from 'react' import { useEffect } from 'react'
import styled from 'styled-components' import styled from 'styled-components'
@ -40,6 +41,7 @@ const PrivacyPolicyWrapper = styled.div`
export default function WalletModal({ openSettings }: { openSettings: () => void }) { export default function WalletModal({ openSettings }: { openSettings: () => void }) {
const { connector, chainId } = useWeb3React() const { connector, chainId } = useWeb3React()
const isAndroidGALaunched = useAndroidGALaunchFlagEnabled()
const { activationState } = useActivationState() const { activationState } = useActivationState()
const fallbackProviderEnabled = useFallbackProviderEnabled() const fallbackProviderEnabled = useFallbackProviderEnabled()
@ -66,7 +68,7 @@ export default function WalletModal({ openSettings }: { openSettings: () => void
<AutoColumn gap="16px"> <AutoColumn gap="16px">
<OptionGrid data-testid="option-grid"> <OptionGrid data-testid="option-grid">
{connections {connections
.filter((connection) => connection.shouldDisplay()) .filter((connection) => connection.shouldDisplay(isAndroidGALaunched))
.map((connection) => ( .map((connection) => (
<Option key={connection.getName()} connection={connection} /> <Option key={connection.getName()} connection={connection} />
))} ))}

@ -11,7 +11,7 @@ import COINBASE_ICON from 'assets/wallets/coinbase-icon.svg'
import UNIWALLET_ICON from 'assets/wallets/uniswap-wallet-icon.png' import UNIWALLET_ICON from 'assets/wallets/uniswap-wallet-icon.png'
import WALLET_CONNECT_ICON from 'assets/wallets/walletconnect-icon.svg' import WALLET_CONNECT_ICON from 'assets/wallets/walletconnect-icon.svg'
import { useSyncExternalStore } from 'react' import { useSyncExternalStore } from 'react'
import { isMobile, isNonIOSPhone } from 'utils/userAgent' import { isMobile, isNonIOSPhone, isNonSupportedPhone } from 'utils/userAgent'
import { RPC_URLS } from '../constants/networks' import { RPC_URLS } from '../constants/networks'
import { DEPRECATED_RPC_PROVIDERS, RPC_PROVIDERS } from '../constants/providers' import { DEPRECATED_RPC_PROVIDERS, RPC_PROVIDERS } from '../constants/providers'
@ -149,7 +149,8 @@ export const uniwalletWCV2ConnectConnection: Connection = {
hooks: web3WCV2UniwalletConnectHooks, hooks: web3WCV2UniwalletConnectHooks,
type: ConnectionType.UNISWAP_WALLET_V2, type: ConnectionType.UNISWAP_WALLET_V2,
getIcon: () => UNIWALLET_ICON, getIcon: () => UNIWALLET_ICON,
shouldDisplay: () => Boolean(!getIsInjectedMobileBrowser() && !isNonIOSPhone), shouldDisplay: (isAndroidGALaunched) =>
Boolean(!getIsInjectedMobileBrowser() && (isAndroidGALaunched ? !isNonSupportedPhone : !isNonIOSPhone)),
} }
const [web3CoinbaseWallet, web3CoinbaseWalletHooks] = initializeConnector<CoinbaseWallet>( const [web3CoinbaseWallet, web3CoinbaseWalletHooks] = initializeConnector<CoinbaseWallet>(

@ -26,6 +26,6 @@ export interface Connection {
hooks: Web3ReactHooks hooks: Web3ReactHooks
type: ConnectionType type: ConnectionType
getIcon?(isDarkMode: boolean): string getIcon?(isDarkMode: boolean): string
shouldDisplay(): boolean shouldDisplay(isAndroidGALaunched?: boolean): boolean
overrideActivate?: (chainId?: ChainId) => boolean overrideActivate?: (chainId?: ChainId) => boolean
} }

@ -25,7 +25,7 @@ import { Z_INDEX } from 'theme/zIndex'
import { STATSIG_DUMMY_KEY } from 'tracing' import { STATSIG_DUMMY_KEY } from 'tracing'
import { isPathBlocked } from 'utils/blockedPaths' import { isPathBlocked } from 'utils/blockedPaths'
import { getEnvName } from 'utils/env' import { getEnvName } from 'utils/env'
import { getDownloadAppLink } from 'utils/openDownloadApp' import { MICROSITE_LINK } from 'utils/openDownloadApp'
import { getCurrentPageFromLocation } from 'utils/urlRoutes' import { getCurrentPageFromLocation } from 'utils/urlRoutes'
import { getCLS, getFCP, getFID, getLCP, Metric } from 'web-vitals' import { getCLS, getFCP, getFID, getLCP, Metric } from 'web-vitals'
@ -145,7 +145,7 @@ export default function App() {
const shouldRedirectToAppInstall = pathname?.startsWith('/address/') const shouldRedirectToAppInstall = pathname?.startsWith('/address/')
useLayoutEffect(() => { useLayoutEffect(() => {
if (shouldRedirectToAppInstall) { if (shouldRedirectToAppInstall) {
window.location.href = getDownloadAppLink() window.location.href = MICROSITE_LINK
} }
}, [shouldRedirectToAppInstall]) }, [shouldRedirectToAppInstall])

@ -2114,7 +2114,7 @@ exports[`disable nft on landing page does not render nft information and card 1`
</div> </div>
<a <a
class="c63" class="c63"
href="https://wallet.uniswap.org/?utm_source=home_page&utm_medium=webapp&utm_campaign=wallet_microsite&utm_id=1" href="https://uniswapwallet.onelink.me/8q3y/79gveilz"
> >
<svg <svg
height="20" height="20"
@ -4727,7 +4727,7 @@ exports[`disable nft on landing page renders nft information and card 1`] = `
</div> </div>
<a <a
class="c63" class="c63"
href="https://wallet.uniswap.org/?utm_source=home_page&utm_medium=webapp&utm_campaign=wallet_microsite&utm_id=1" href="https://uniswapwallet.onelink.me/8q3y/79gveilz"
> >
<svg <svg
height="20" height="20"

@ -1,14 +0,0 @@
import { render } from 'test-utils/render'
import Landing from '.'
jest.mock('utils/userAgent', () => {
return {
isIOS: true,
}
})
it('renders ios microsite link', () => {
const { container } = render(<Landing />)
expect(container.innerHTML.includes(`https://apps.apple.com/app/apple-store/id6443944476`)).toBeTruthy()
})

@ -1,14 +0,0 @@
import { render } from 'test-utils/render'
import Landing from '.'
jest.mock('utils/userAgent', () => {
return {
isIOS: false,
}
})
it('renders non-ios microsite link', () => {
const { container } = render(<Landing />)
expect(container.innerHTML.includes(`https://wallet.uniswap.org/?utm_source=home_page`)).toBeTruthy()
})

@ -34,3 +34,10 @@ describe('disable nft on landing page', () => {
) )
}) })
}) })
describe('Uniswap wallet app download link', () => {
it('renders onelink app download', () => {
const { container } = render(<Landing />)
expect(container.innerHTML.includes('https://uniswapwallet.onelink.me/8q3y/79gveilz')).toBeTruthy()
})
})

@ -399,9 +399,8 @@ export default function Landing() {
<DownloadWalletLink <DownloadWalletLink
{...getDownloadAppLinkProps({ {...getDownloadAppLinkProps({
// landing page specific tracking params element: InterfaceElementName.UNISWAP_WALLET_LANDING_PAGE_DOWNLOAD_BUTTON,
microSiteParams: `utm_source=home_page&utm_medium=webapp&utm_campaign=wallet_microsite&utm_id=1`, isAndroidGALaunched,
appStoreParams: `ct=Uniswap-Home-Page&mt=8`,
})} })}
> >
{isAndroidGALaunched ? ( {isAndroidGALaunched ? (

@ -1,69 +1,68 @@
import { InterfaceElementName, InterfaceEventName } from '@uniswap/analytics-events' import { AppDownloadPlatform, InterfaceElementName, InterfaceEventName } from '@uniswap/analytics-events'
import { sendAnalyticsEvent } from 'analytics' import { sendAnalyticsEvent } from 'analytics'
import { isIOS } from 'utils/userAgent' import { isAndroid, isIOS } from 'utils/userAgent'
const APP_STORE_LINK = 'https://apps.apple.com/app/apple-store/id6443944476' // OneLink will direct to App/Play Store or microsite depending on user agent
const MICROSITE_LINK = 'https://wallet.uniswap.org/' const APP_DOWNLOAD_LINKS: Partial<{ [key in InterfaceElementName]: string }> = {
[InterfaceElementName.UNISWAP_WALLET_MODAL_DOWNLOAD_BUTTON]: 'https://uniswapwallet.onelink.me/8q3y/qfwlncf9',
type OpenDownloadAppOptions = { [InterfaceElementName.UNISWAP_WALLET_NAVBAR_MENU_DOWNLOAD_BUTTON]: 'https://uniswapwallet.onelink.me/8q3y/46tvu6pb',
element?: InterfaceElementName [InterfaceElementName.UNISWAP_WALLET_LANDING_PAGE_DOWNLOAD_BUTTON]: 'https://uniswapwallet.onelink.me/8q3y/79gveilz',
appStoreParams?: string [InterfaceElementName.UNISWAP_WALLET_BANNER_DOWNLOAD_BUTTON]: 'https://uniswapwallet.onelink.me/8q3y/jh9orof3',
microSiteParams?: string
} }
const defaultDownloadAppOptions = { export const MICROSITE_LINK = 'https://wallet.uniswap.org/'
appStoreParams: `pt=123625782&ct=In-App-Banners&mt=8`,
type OpenDownloadAppOptions = {
element: InterfaceElementName
isAndroidGALaunched: boolean
} }
/** /**
* Note: openDownloadApp and getDownloadAppLink are equivalent functions, the first just runs imperatively * Note: openDownloadApp is equivalent to APP_DOWNLOAD_LINKS[element], the first just runs imperatively
* and adds an analytics event, where the other only returns a link. Typically you'll use both: * and adds an analytics event, where the other only returns a link. Typically you'll use both:
* *
* <a href={getDownloadAppLink(options)} onClick={() => openDownloadApp(options)} /> * <a href={APP_DOWNLOAD_LINKS[element]} onClick={() => openDownloadApp(element)} />
* *
* This way with JS disabled and when hovering the <a /> you see and nav to the full href properly, * This way with JS disabled and when hovering the <a /> you see and nav to the full href properly,
* but with JS on it will send the analytics event before navigating to the href. * but with JS on it will send the analytics event before navigating to the href.
* *
* I've added a helper `getDownloadAppLinkProps` that unifies this behavior into one thing. * I've added a helper `getDownloadAppLinkProps` that unifies this behavior into one thing.
*/ */
export function openDownloadApp({ element, isAndroidGALaunched }: OpenDownloadAppOptions) {
export function openDownloadApp(options: OpenDownloadAppOptions = defaultDownloadAppOptions) {
if (isIOS) { if (isIOS) {
openAppStore({ element: options?.element, urlParamString: options?.appStoreParams }) openDownloadStore({ element, appPlatform: AppDownloadPlatform.IOS, linkTarget: 'uniswap_wallet_appstore' })
} else if (isAndroidGALaunched && isAndroid) {
openDownloadStore({ element, appPlatform: AppDownloadPlatform.ANDROID, linkTarget: 'uniswap_wallet_playstore' })
} else { } else {
openWalletMicrosite({ element: options?.element, urlParamString: options?.microSiteParams }) openWalletMicrosite({ element })
} }
} }
// if you need this by itself can add export, not used externally for now export const getDownloadAppLinkProps = ({ element, isAndroidGALaunched }: OpenDownloadAppOptions) => {
export const getDownloadAppLink = (options: OpenDownloadAppOptions = defaultDownloadAppOptions) =>
isIOS
? linkWithParams(APP_STORE_LINK, options?.appStoreParams)
: linkWithParams(MICROSITE_LINK, options?.microSiteParams)
export const getDownloadAppLinkProps = (options: OpenDownloadAppOptions = defaultDownloadAppOptions) => {
return { return {
href: getDownloadAppLink(options), href: APP_DOWNLOAD_LINKS[element],
onClick(e: { preventDefault: () => void }) { onClick(e: { preventDefault: () => void }) {
e.preventDefault() e.preventDefault()
openDownloadApp(options) openDownloadApp({ element, isAndroidGALaunched })
}, },
} }
} }
type AnalyticsLinkOptions = { type AnalyticsLinkOptions = {
element?: InterfaceElementName element: InterfaceElementName
urlParamString?: string appPlatform?: AppDownloadPlatform
linkTarget?: string
} }
const openAppStore = (options?: AnalyticsLinkOptions) => { const openDownloadStore = (options: AnalyticsLinkOptions) => {
sendAnalyticsEvent(InterfaceEventName.UNISWAP_WALLET_APP_DOWNLOAD_OPENED, { element: options?.element }) sendAnalyticsEvent(InterfaceEventName.UNISWAP_WALLET_APP_DOWNLOAD_OPENED, {
window.open(linkWithParams(APP_STORE_LINK, options?.urlParamString), /* target = */ 'uniswap_wallet_appstore') element: options.element,
appPlatform: options?.appPlatform,
})
window.open(APP_DOWNLOAD_LINKS[options.element], /* target = */ options.linkTarget)
} }
export const openWalletMicrosite = (options?: AnalyticsLinkOptions) => { export const openWalletMicrosite = (options: AnalyticsLinkOptions) => {
sendAnalyticsEvent(InterfaceEventName.UNISWAP_WALLET_MICROSITE_OPENED, { element: options?.element }) sendAnalyticsEvent(InterfaceEventName.UNISWAP_WALLET_MICROSITE_OPENED, { element: options.element })
window.open(linkWithParams(MICROSITE_LINK, options?.urlParamString), /* target = */ 'uniswap_wallet_microsite') window.open(APP_DOWNLOAD_LINKS[options.element], /* target = */ 'uniswap_wallet_microsite')
} }
const linkWithParams = (link: string, params?: string) => link + (params ? `?${params}` : '')

@ -7,6 +7,8 @@ const { name } = parser.getBrowser()
export const isMobile = type === 'mobile' || type === 'tablet' export const isMobile = type === 'mobile' || type === 'tablet'
const platform = parser.getOS().name const platform = parser.getOS().name
export const isIOS = platform === 'iOS' export const isIOS = platform === 'iOS'
export const isAndroid = platform === 'Android'
export const isNonIOSPhone = !isIOS && type === 'mobile' export const isNonIOSPhone = !isIOS && type === 'mobile'
export const isNonSupportedPhone = !isIOS && !isAndroid && type === 'mobile'
export const isMobileSafari = isMobile && isIOS && name?.toLowerCase().includes('safari') export const isMobileSafari = isMobile && isIOS && name?.toLowerCase().includes('safari')

@ -6059,10 +6059,10 @@
"@typescript-eslint/types" "5.59.1" "@typescript-eslint/types" "5.59.1"
eslint-visitor-keys "^3.3.0" eslint-visitor-keys "^3.3.0"
"@uniswap/analytics-events@^2.25.0": "@uniswap/analytics-events@^2.28.0":
version "2.25.0" version "2.28.0"
resolved "https://registry.yarnpkg.com/@uniswap/analytics-events/-/analytics-events-2.25.0.tgz#06f2d81342b2e4dc516bdfa1222ddaa7c274ac04" resolved "https://registry.yarnpkg.com/@uniswap/analytics-events/-/analytics-events-2.28.0.tgz#344fbbe3e120b7f8100e4d540004847f7147cf6e"
integrity sha512-0syw7gZtoHXSCVb+zV464L+Zgy1ICnGDOrbK2xoVtpiQ8rBjUXPWvcKuaiNPfTsS9tIZNtqOmEyZEjWwvFSLUw== integrity sha512-j650l315p9W5dbVPzHRu485omyZw+I6jU/ZGpzuz4OdrJIp8yCl57LTLFfmMsZGwmJYDlOxY2fB6Jrbc2lUvUA==
"@uniswap/analytics@1.5.0": "@uniswap/analytics@1.5.0":
version "1.5.0" version "1.5.0"