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">
<Trans> {isAndroidGALaunched ? (
Download in the App Store to safely store your tokens and NFTs, swap tokens, and connect to crypto apps. <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.
</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"