Skip to content

Commit

Permalink
Merge pull request #7656 from artsy/anastasiapyzhik/add-android-downl…
Browse files Browse the repository at this point in the history
…oad-mobile-footer

Add android download mobile footer
  • Loading branch information
damassi authored May 28, 2021
2 parents dcf6cc8 + f531a63 commit b0e4f64
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 24 deletions.
119 changes: 114 additions & 5 deletions src/v2/Components/DownloadAppBadge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,20 @@ import { clickedAppDownload, ContextModule } from "@artsy/cohesion"
import { useAnalyticsContext } from "v2/Artsy"
import Events from "v2/Utils/Events"
import { Box, Link } from "@artsy/palette"
import { Device } from "v2/Utils/Hooks/useDeviceDetection"

interface DownloadAppBadgeProps {
contextModule: ContextModule
device: Device
downloadAppUrl: string
}

// @ts-expect-error STRICT_NULL_CHECK
export const DownloadAppBadge: React.FC<DownloadAppBadgeProps> = track(null, {
dispatch: data => Events.postEvent(data),
})(({ contextModule }) => {
})(({ contextModule, device, downloadAppUrl }) => {
const tracking = useTracking()
const downloadAppUrl =
"https://apps.apple.com/us/app/artsy-buy-sell-original-art/id703796080"

const {
contextPageOwnerId,
contextPageOwnerSlug,
Expand All @@ -42,13 +44,14 @@ export const DownloadAppBadge: React.FC<DownloadAppBadgeProps> = track(null, {
onClick={trackClickedDownloadAppBadge}
title="Download on the App Store"
>
<DownloadAppBadgeSVG />
{device === Device.iPhone && <DownloadIPhoneAppBadgeSVG />}
{device === Device.Android && <DownloadAndroidAppBadgeSVG />}
</Link>
</Box>
)
})

const DownloadAppBadgeSVG = () => (
const DownloadIPhoneAppBadgeSVG = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="119.664"
Expand Down Expand Up @@ -84,3 +87,109 @@ const DownloadAppBadgeSVG = () => (
</g>
</svg>
)

const DownloadAndroidAppBadgeSVG = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
width="134.99"
height="40"
viewBox="0 0 134.99 40"
>
<linearGradient
id="a"
gradientTransform="matrix(1 0 0 -1 0 42)"
gradientUnits="userSpaceOnUse"
x1="21.8"
x2="5.017"
y1="33.29"
y2="16.508"
>
<stop offset="0" stopColor="#00a0ff" />
<stop offset=".007" stopColor="#00a1ff" />
<stop offset=".26" stopColor="#00beff" />
<stop offset=".512" stopColor="#00d2ff" />
<stop offset=".76" stopColor="#00dfff" />
<stop offset="1" stopColor="#00e3ff" />
</linearGradient>
<linearGradient
id="b"
gradientTransform="matrix(1 0 0 -1 0 42)"
gradientUnits="userSpaceOnUse"
x1="33.834"
x2="9.637"
y1="21.999"
y2="21.999"
>
<stop offset="0" stopColor="#ffe000" />
<stop offset=".409" stopColor="#ffbd00" />
<stop offset=".775" stopColor="orange" />
<stop offset="1" stopColor="#ff9c00" />
</linearGradient>
<linearGradient
id="c"
gradientTransform="matrix(1 0 0 -1 0 42)"
gradientUnits="userSpaceOnUse"
x1="24.827"
x2="2.069"
y1="19.704"
y2="-3.054"
>
<stop offset="0" stopColor="#ff3a44" />
<stop offset="1" stopColor="#c31162" />
</linearGradient>
<linearGradient
id="d"
gradientTransform="matrix(1 0 0 -1 0 42)"
gradientUnits="userSpaceOnUse"
x1="7.297"
x2="17.46"
y1="41.824"
y2="31.661"
>
<stop offset="0" stopColor="#32a071" />
<stop offset=".069" stopColor="#2da771" />
<stop offset=".476" stopColor="#15cf74" />
<stop offset=".801" stopColor="#06e775" />
<stop offset="1" stopColor="#00f076" />
</linearGradient>
<path d="M130 40H5c-2.8 0-5-2.2-5-5V5c0-2.8 2.2-5 5-5h125c2.8 0 5 2.2 5 5v30c0 2.8-2.2 5-5 5z" />
<path
d="M130 .8c2.3 0 4.2 1.9 4.2 4.2v30c0 2.3-1.9 4.2-4.2 4.2H5C2.7 39.2.8 37.3.8 35V5C.8 2.7 2.7.8 5 .8zm0-.8H5C2.2 0 0 2.3 0 5v30c0 2.8 2.2 5 5 5h125c2.8 0 5-2.2 5-5V5c0-2.7-2.2-5-5-5z"
fill="#a6a6a6"
/>
<path
d="M47.4 10.2c0 .8-.2 1.5-.7 2-.6.6-1.3.9-2.2.9s-1.6-.3-2.2-.9-.9-1.3-.9-2.2.3-1.6.9-2.2 1.3-.9 2.2-.9c.4 0 .8.1 1.2.3s.7.4.9.7l-.5.5c-.4-.5-.9-.7-1.6-.7-.6 0-1.2.2-1.6.7-.5.4-.7 1-.7 1.7s.2 1.3.7 1.7 1 .7 1.6.7c.7 0 1.2-.2 1.7-.7.3-.3.5-.7.5-1.2h-2.2v-.8h2.9zM52 7.7h-2.7v1.9h2.5v.7h-2.5v1.9H52v.8h-3.5V7H52zm3.3 5.3h-.8V7.7h-1.7V7H57v.7h-1.7zm4.6 0V7h.8v6zm4.2 0h-.8V7.7h-1.7V7h4.1v.7H64V13zm9.5-.8c-.6.6-1.3.9-2.2.9s-1.6-.3-2.2-.9-.9-1.3-.9-2.2.3-1.6.9-2.2 1.3-.9 2.2-.9 1.6.3 2.2.9.9 1.3.9 2.2-.3 1.6-.9 2.2zm-3.8-.5c.4.4 1 .7 1.6.7s1.2-.2 1.6-.7c.4-.4.7-1 .7-1.7s-.2-1.3-.7-1.7c-.4-.4-1-.7-1.6-.7s-1.2.2-1.6.7c-.4.4-.7 1-.7 1.7s.2 1.3.7 1.7zm5.8 1.3V7h.9l2.9 4.7V7h.8v6h-.8l-3.1-4.9V13z"
fill="#fff"
stroke="#fff"
strokeMiterlimit="10"
strokeWidth=".2"
/>
<path
d="M68.1 21.8c-2.4 0-4.3 1.8-4.3 4.3 0 2.4 1.9 4.3 4.3 4.3s4.3-1.8 4.3-4.3c0-2.6-1.9-4.3-4.3-4.3zm0 6.8c-1.3 0-2.4-1.1-2.4-2.6s1.1-2.6 2.4-2.6 2.4 1 2.4 2.6c0 1.5-1.1 2.6-2.4 2.6zm-9.3-6.8c-2.4 0-4.3 1.8-4.3 4.3 0 2.4 1.9 4.3 4.3 4.3s4.3-1.8 4.3-4.3c0-2.6-1.9-4.3-4.3-4.3zm0 6.8c-1.3 0-2.4-1.1-2.4-2.6s1.1-2.6 2.4-2.6 2.4 1 2.4 2.6c0 1.5-1.1 2.6-2.4 2.6zm-11.1-5.5v1.8H52c-.1 1-.5 1.8-1 2.3-.6.6-1.6 1.3-3.3 1.3-2.7 0-4.7-2.1-4.7-4.8s2.1-4.8 4.7-4.8c1.4 0 2.5.6 3.3 1.3l1.3-1.3c-1.1-1-2.5-1.8-4.5-1.8-3.6 0-6.7 3-6.7 6.6s3.1 6.6 6.7 6.6c2 0 3.4-.6 4.6-1.9 1.2-1.2 1.6-2.9 1.6-4.2 0-.4 0-.8-.1-1.1zm45.4 1.4c-.4-1-1.4-2.7-3.6-2.7s-4 1.7-4 4.3c0 2.4 1.8 4.3 4.2 4.3 1.9 0 3.1-1.2 3.5-1.9l-1.4-1c-.5.7-1.1 1.2-2.1 1.2s-1.6-.4-2.1-1.3l5.7-2.4zm-5.8 1.4c0-1.6 1.3-2.5 2.2-2.5.7 0 1.4.4 1.6.9zM82.6 30h1.9V17.5h-1.9zm-3-7.3c-.5-.5-1.3-1-2.3-1-2.1 0-4.1 1.9-4.1 4.3s1.9 4.2 4.1 4.2c1 0 1.8-.5 2.2-1h.1v.6c0 1.6-.9 2.5-2.3 2.5-1.1 0-1.9-.8-2.1-1.5l-1.6.7c.5 1.1 1.7 2.5 3.8 2.5 2.2 0 4-1.3 4-4.4V22h-1.8zm-2.2 5.9c-1.3 0-2.4-1.1-2.4-2.6s1.1-2.6 2.4-2.6 2.3 1.1 2.3 2.6-1 2.6-2.3 2.6zm24.4-11.1h-4.5V30h1.9v-4.7h2.6c2.1 0 4.1-1.5 4.1-3.9s-2-3.9-4.1-3.9zm.1 6h-2.7v-4.3h2.7c1.4 0 2.2 1.2 2.2 2.1-.1 1.1-.9 2.2-2.2 2.2zm11.5-1.8c-1.4 0-2.8.6-3.3 1.9l1.7.7c.4-.7 1-.9 1.7-.9 1 0 1.9.6 2 1.6v.1c-.3-.2-1.1-.5-1.9-.5-1.8 0-3.6 1-3.6 2.8 0 1.7 1.5 2.8 3.1 2.8 1.3 0 1.9-.6 2.4-1.2h.1v1h1.8v-4.8c-.2-2.2-1.9-3.5-4-3.5zm-.2 6.9c-.6 0-1.5-.3-1.5-1.1 0-1 1.1-1.3 2-1.3.8 0 1.2.2 1.7.4-.2 1.2-1.2 2-2.2 2zm10.5-6.6l-2.1 5.4h-.1l-2.2-5.4h-2l3.3 7.6-1.9 4.2h1.9l5.1-11.8zm-16.8 8h1.9V17.5h-1.9z"
fill="#fff"
/>
<path
d="M10.4 7.5c-.3.3-.4.8-.4 1.4V31c0 .6.2 1.1.5 1.4l.1.1L23 20.1v-.2z"
fill="url(#a)"
/>
<path
d="M27 24.3l-4.1-4.1v-.3l4.1-4.1.1.1 4.9 2.8c1.4.8 1.4 2.1 0 2.9z"
fill="url(#b)"
/>
<path d="M27.1 24.2L22.9 20 10.4 32.5c.5.5 1.2.5 2.1.1z" fill="url(#c)" />
<path d="M27.1 15.8L12.5 7.5c-.9-.5-1.6-.4-2.1.1L22.9 20z" fill="url(#d)" />
<path
d="M27 24.1l-14.5 8.2c-.8.5-1.5.4-2 0l-.1.1.1.1c.5.4 1.2.5 2 0z"
opacity=".2"
/>
<path
d="M10.4 32.3c-.3-.3-.4-.8-.4-1.4v.1c0 .6.2 1.1.5 1.4v-.1zm21.6-11l-5 2.8.1.1 4.9-2.8c.7-.4 1-.9 1-1.4 0 .5-.4.9-1 1.3z"
opacity=".12"
/>
<path
d="M12.5 7.6L32 18.7c.6.4 1 .8 1 1.3 0-.5-.3-1-1-1.4L12.5 7.5c-1.4-.8-2.5-.2-2.5 1.4V9c0-1.5 1.1-2.2 2.5-1.4z"
fill="#fff"
opacity=".25"
/>
</svg>
)
18 changes: 14 additions & 4 deletions src/v2/Components/Footer/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@ import { ContextModule } from "@artsy/cohesion"
import { CCPARequest } from "../CCPARequest"
import { FooterDownloadAppBanner } from "./FooterDownloadAppBanner"
import { RouterLink, RouterLinkProps } from "v2/Artsy/Router/RouterLink"
import { Device, useDeviceDetection } from "v2/Utils/Hooks/useDeviceDetection"

interface FooterProps extends BoxProps {}

export const Footer: React.FC<FooterProps> = props => {
const { device, downloadAppUrl } = useDeviceDetection()

const tokens = useThemeConfig({
v2: {
header: "mediumText" as TextVariant,
Expand All @@ -53,10 +56,13 @@ export const Footer: React.FC<FooterProps> = props => {
<GridColumns pt={tokens.pt} pb={tokens.pb} gridRowGap={[4, 0]}>
<Column span={12} display={["block", "none"]}>
<Text variant={tokens.header} fontWeight="bold" mb={2}>
Get the iOS app
Get the App
</Text>

<DownloadAppBadge contextModule={ContextModule.footer} />
<DownloadAppBadge
contextModule={ContextModule.footer}
device={device}
downloadAppUrl={downloadAppUrl}
/>
</Column>

<Column span={3}>
Expand Down Expand Up @@ -150,7 +156,11 @@ export const Footer: React.FC<FooterProps> = props => {
Get the iOS app
</Text>

<DownloadAppBadge contextModule={ContextModule.footer} />
<DownloadAppBadge
contextModule={ContextModule.footer}
device={Device.iPhone}
downloadAppUrl={downloadAppUrl}
/>
</Media>
</Column>

Expand Down
19 changes: 19 additions & 0 deletions src/v2/Components/Footer/__tests__/Footer.jest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,23 @@ describe("Footer", () => {
expect(wrapper.find(CCPARequest).length).toEqual(1)
})
})

describe("renders proper badge for downloading the app", () => {
let userAgentGetter
beforeEach(() => {
userAgentGetter = jest.spyOn(window.navigator, "userAgent", "get")
})

it("to iPhone", () => {
userAgentGetter.mockReturnValue("iPhone")
const wrapper = getWrapper("xs")
expect(wrapper.find("DownloadIPhoneAppBadgeSVG").exists()).toBeTruthy()
})

it("to Android", () => {
userAgentGetter.mockReturnValue("Android")
const wrapper = getWrapper("xs")
expect(wrapper.find("DownloadAndroidAppBadgeSVG").exists()).toBeTruthy()
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
} from "./NavigatorContextProvider"
import { NAV_BAR_BORDER_OFFSET, MOBILE_NAV_HEIGHT } from "v2/Components/NavBar"
import { ArtistsLetterNav } from "v2/Apps/Artists/Components/ArtistsLetterNav"
import { useDeviceDetection } from "v2/Utils/Hooks/useDeviceDetection"

const Close = styled(Clickable)`
position: absolute;
Expand All @@ -59,6 +60,7 @@ export const MobileNavMenu: React.FC<Props> = ({
onClose,
}) => {
const { user } = useSystemContext()
const { downloadAppUrl } = useDeviceDetection()

return (
<NavigatorContextProvider>
Expand Down Expand Up @@ -101,6 +103,7 @@ export const MobileNavMenu: React.FC<Props> = ({
Editorial
</MobileLink>
{user ? <LoggedInLinks /> : <AuthenticateLinks />}
<MobileLink href={downloadAppUrl}>Get the app</MobileLink>
</ul>
</AnimatingMenuWrapper>
</MenuViewport>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,13 @@ describe("MobileNavMenu", () => {

it("calls logout auth action on logout menu click", () => {
const wrapper = getWrapper({ user: { type: "NotAdmin" } })

const MobileLink = wrapper.find("MobileLink")
const length = MobileLink.length
// @ts-expect-error STRICT_NULL_CHECK
wrapper
.find("MobileLink")
.last()
.at(length - 2)
.props()
.onClick({
preventDefault: () => {},
Expand Down Expand Up @@ -115,9 +118,7 @@ describe("MobileNavMenu", () => {
const linkContainer = getMobileMenuLinkContainer("notAdmin")
const mobileSubmenuLinks = linkContainer.children()
let linkText = mobileSubmenuLinks.last().text()
expect(linkText).toContain("Account")

expect(linkText).toContain("Works for you")
expect(linkText).toContain("Get the app")
})
})

Expand Down
27 changes: 16 additions & 11 deletions src/v2/Components/__tests__/DownloadAppBadge.jest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,23 @@ import { useTracking } from "react-tracking"
import { Link } from "@artsy/palette"
import { DownloadAppBadge } from "v2/Components/DownloadAppBadge"
import { ContextModule } from "@artsy/cohesion"
import { Device } from "v2/Utils/Hooks/useDeviceDetection"

describe("DownloadAppBadge", () => {
const trackEvent = jest.fn()
const event = {
context_module: "footer",
subject: "Download on the App Store",
destination_path:
"https://apps.apple.com/us/app/artsy-buy-sell-original-art/id703796080",
}
const props = {
contextModule: ContextModule.footer,
device: Device.iPhone,
downloadAppUrl:
"https://apps.apple.com/us/app/artsy-buy-sell-original-art/id703796080",
}

beforeEach(() => {
const mockTracking = useTracking as jest.Mock
mockTracking.mockImplementation(() => {
Expand All @@ -21,19 +35,10 @@ describe("DownloadAppBadge", () => {
})

it("tracks clicks on the app download badge", () => {
const badge = mount(
<DownloadAppBadge contextModule={ContextModule.footer} />
)
const badge = mount(<DownloadAppBadge {...props} />)
const downloadLink = badge.find(Link)
// @ts-expect-error STRICT_NULL_CHECK
downloadLink.props().onClick({} as any)
expect(trackEvent).toHaveBeenCalledWith(
expect.objectContaining({
context_module: "footer",
destination_path:
"https://apps.apple.com/us/app/artsy-buy-sell-original-art/id703796080",
subject: "Download on the App Store",
})
)
expect(trackEvent).toHaveBeenCalledWith(expect.objectContaining(event))
})
})
29 changes: 29 additions & 0 deletions src/v2/Utils/Hooks/useDeviceDetection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { useEffect, useState } from "react"

export enum Device {
iPhone,
Android,
}

export const useDeviceDetection = () => {
// @ts-expect-error STRICT_NULL_CHECK
const [device, setDevice] = useState<Device>(undefined)
// @ts-expect-error STRICT_NULL_CHECK
const [downloadAppUrl, setDownloadAppUrl] = useState<string>(undefined)

useEffect(() => {
if (window.navigator.userAgent.match(/Android/)) {
setDevice(Device.Android)
setDownloadAppUrl(
"https://play.google.com/store/apps/details?id=net.artsy.app"
)
} else if (window.navigator.userAgent.match(/iPhone/)) {
setDevice(Device.iPhone)
setDownloadAppUrl(
"https://apps.apple.com/us/app/artsy-buy-sell-original-art/id703796080"
)
}
}, [])

return { device, downloadAppUrl }
}

0 comments on commit b0e4f64

Please sign in to comment.