From 7be8a60d843d8ed796fb14942d1d7d3b87478731 Mon Sep 17 00:00:00 2001 From: nastassia Date: Fri, 28 May 2021 14:22:08 +0300 Subject: [PATCH 1/6] feat: Added Android download link to footer on mobile --- src/v2/Components/DownloadAppBadge.tsx | 131 ++++++++++++++++++++++++- src/v2/Components/Footer/Footer.tsx | 28 ++++-- 2 files changed, 148 insertions(+), 11 deletions(-) diff --git a/src/v2/Components/DownloadAppBadge.tsx b/src/v2/Components/DownloadAppBadge.tsx index eb15eb81e01..44100f9aa1f 100644 --- a/src/v2/Components/DownloadAppBadge.tsx +++ b/src/v2/Components/DownloadAppBadge.tsx @@ -5,17 +5,31 @@ import { useAnalyticsContext } from "v2/Artsy" import Events from "v2/Utils/Events" import { Box, Link } from "@artsy/palette" +export enum Device { + iPhone, + Android, +} + interface DownloadAppBadgeProps { contextModule: ContextModule + device: Device } // @ts-expect-error STRICT_NULL_CHECK export const DownloadAppBadge: React.FC = track(null, { dispatch: data => Events.postEvent(data), -})(({ contextModule }) => { +})(({ contextModule, device }) => { const tracking = useTracking() - const downloadAppUrl = - "https://apps.apple.com/us/app/artsy-buy-sell-original-art/id703796080" + + let downloadAppUrl: string = "" + if (device === Device.iPhone) { + downloadAppUrl = + "https://apps.apple.com/us/app/artsy-buy-sell-original-art/id703796080" + } else if (device === Device.Android) { + downloadAppUrl = + "https://play.google.com/store/apps/details?id=net.artsy.app" + } + const { contextPageOwnerId, contextPageOwnerSlug, @@ -42,13 +56,14 @@ export const DownloadAppBadge: React.FC = track(null, { onClick={trackClickedDownloadAppBadge} title="Download on the App Store" > - + {device === Device.iPhone && } + {device === Device.Android && } ) }) -const DownloadAppBadgeSVG = () => ( +const DownloadIPhoneAppBadgeSVG = () => ( ( ) + +const DownloadAndroidAppBadgeSVG = () => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +) diff --git a/src/v2/Components/Footer/Footer.tsx b/src/v2/Components/Footer/Footer.tsx index ebe2b437362..741d766d352 100644 --- a/src/v2/Components/Footer/Footer.tsx +++ b/src/v2/Components/Footer/Footer.tsx @@ -1,4 +1,4 @@ -import React from "react" +import React, { useEffect, useState } from "react" import styled from "styled-components" import { Media } from "v2/Utils/Responsive" import { @@ -18,7 +18,7 @@ import { useThemeConfig, WeChatIcon, } from "@artsy/palette" -import { DownloadAppBadge } from "v2/Components/DownloadAppBadge" +import { Device, DownloadAppBadge } from "v2/Components/DownloadAppBadge" import { ContextModule } from "@artsy/cohesion" import { CCPARequest } from "../CCPARequest" import { FooterDownloadAppBanner } from "./FooterDownloadAppBanner" @@ -27,6 +27,17 @@ import { RouterLink, RouterLinkProps } from "v2/Artsy/Router/RouterLink" interface FooterProps extends BoxProps {} export const Footer: React.FC = props => { + // @ts-expect-error STRICT_NULL_CHECK + const [device, setDevice] = useState(undefined) + + useEffect(() => { + if (window.navigator.userAgent.match(/Android/)) { + setDevice(Device.Android) + } else if (window.navigator.userAgent.match(/iPhone/)) { + setDevice(Device.iPhone) + } + }, []) + const tokens = useThemeConfig({ v2: { header: "mediumText" as TextVariant, @@ -53,10 +64,12 @@ export const Footer: React.FC = props => { - Get the iOS app + Get the App - - + @@ -150,7 +163,10 @@ export const Footer: React.FC = props => { Get the iOS app - + From 1b4fa04bbc41f836dbfb22f499228d61bd46c026 Mon Sep 17 00:00:00 2001 From: nastassia Date: Fri, 28 May 2021 14:49:05 +0300 Subject: [PATCH 2/6] Updated tests --- .../Footer/__tests__/Footer.jest.tsx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/v2/Components/Footer/__tests__/Footer.jest.tsx b/src/v2/Components/Footer/__tests__/Footer.jest.tsx index aea62c56e3e..63da2cc49dc 100644 --- a/src/v2/Components/Footer/__tests__/Footer.jest.tsx +++ b/src/v2/Components/Footer/__tests__/Footer.jest.tsx @@ -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() + }) + }) }) From c55f360276ac7b92cc8f5cb2739805d746829ce9 Mon Sep 17 00:00:00 2001 From: nastassia Date: Fri, 28 May 2021 15:01:37 +0300 Subject: [PATCH 3/6] Updated tests for DownloadAppBadge --- .../__tests__/DownloadAppBadge.jest.tsx | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/v2/Components/__tests__/DownloadAppBadge.jest.tsx b/src/v2/Components/__tests__/DownloadAppBadge.jest.tsx index 4d1700d9181..641cb817b19 100644 --- a/src/v2/Components/__tests__/DownloadAppBadge.jest.tsx +++ b/src/v2/Components/__tests__/DownloadAppBadge.jest.tsx @@ -2,11 +2,22 @@ import React from "react" import { mount } from "enzyme" import { useTracking } from "react-tracking" import { Link } from "@artsy/palette" -import { DownloadAppBadge } from "v2/Components/DownloadAppBadge" +import { Device, DownloadAppBadge } from "v2/Components/DownloadAppBadge" import { ContextModule } from "@artsy/cohesion" 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, + } + beforeEach(() => { const mockTracking = useTracking as jest.Mock mockTracking.mockImplementation(() => { @@ -20,19 +31,24 @@ describe("DownloadAppBadge", () => { jest.resetAllMocks() }) - it("tracks clicks on the app download badge", () => { - const badge = mount( - - ) + it("tracks clicks on the iPhone app download badge", () => { + const badge = mount() + const downloadLink = badge.find(Link) + // @ts-expect-error STRICT_NULL_CHECK + downloadLink.props().onClick({} as any) + expect(trackEvent).toHaveBeenCalledWith(expect.objectContaining(event)) + }) + + it("tracks clicks on the Android app download badge", () => { + const badge = mount() const downloadLink = badge.find(Link) // @ts-expect-error STRICT_NULL_CHECK downloadLink.props().onClick({} as any) expect(trackEvent).toHaveBeenCalledWith( expect.objectContaining({ - context_module: "footer", + ...event, destination_path: - "https://apps.apple.com/us/app/artsy-buy-sell-original-art/id703796080", - subject: "Download on the App Store", + "https://play.google.com/store/apps/details?id=net.artsy.app", }) ) }) From a0654c6f8c4b71dfe3d9fce49223fad33ae9f53d Mon Sep 17 00:00:00 2001 From: nastassia Date: Fri, 28 May 2021 16:36:52 +0300 Subject: [PATCH 4/6] refactor: Encapsulated device detection logic into hook --- src/v2/Components/DownloadAppBadge.tsx | 6 +----- src/v2/Components/Footer/Footer.tsx | 16 ++++---------- .../__tests__/DownloadAppBadge.jest.tsx | 3 ++- src/v2/Utils/Hooks/useDeviceDetection.tsx | 21 +++++++++++++++++++ 4 files changed, 28 insertions(+), 18 deletions(-) create mode 100644 src/v2/Utils/Hooks/useDeviceDetection.tsx diff --git a/src/v2/Components/DownloadAppBadge.tsx b/src/v2/Components/DownloadAppBadge.tsx index 44100f9aa1f..5190321f8ce 100644 --- a/src/v2/Components/DownloadAppBadge.tsx +++ b/src/v2/Components/DownloadAppBadge.tsx @@ -4,11 +4,7 @@ import { clickedAppDownload, ContextModule } from "@artsy/cohesion" import { useAnalyticsContext } from "v2/Artsy" import Events from "v2/Utils/Events" import { Box, Link } from "@artsy/palette" - -export enum Device { - iPhone, - Android, -} +import { Device } from "v2/Utils/Hooks/useDeviceDetection" interface DownloadAppBadgeProps { contextModule: ContextModule diff --git a/src/v2/Components/Footer/Footer.tsx b/src/v2/Components/Footer/Footer.tsx index 741d766d352..71cd2a73781 100644 --- a/src/v2/Components/Footer/Footer.tsx +++ b/src/v2/Components/Footer/Footer.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react" +import React from "react" import styled from "styled-components" import { Media } from "v2/Utils/Responsive" import { @@ -18,25 +18,17 @@ import { useThemeConfig, WeChatIcon, } from "@artsy/palette" -import { Device, DownloadAppBadge } from "v2/Components/DownloadAppBadge" +import { DownloadAppBadge } from "v2/Components/DownloadAppBadge" 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 = props => { - // @ts-expect-error STRICT_NULL_CHECK - const [device, setDevice] = useState(undefined) - - useEffect(() => { - if (window.navigator.userAgent.match(/Android/)) { - setDevice(Device.Android) - } else if (window.navigator.userAgent.match(/iPhone/)) { - setDevice(Device.iPhone) - } - }, []) + const device = useDeviceDetection() const tokens = useThemeConfig({ v2: { diff --git a/src/v2/Components/__tests__/DownloadAppBadge.jest.tsx b/src/v2/Components/__tests__/DownloadAppBadge.jest.tsx index 641cb817b19..fe30c28342a 100644 --- a/src/v2/Components/__tests__/DownloadAppBadge.jest.tsx +++ b/src/v2/Components/__tests__/DownloadAppBadge.jest.tsx @@ -2,8 +2,9 @@ import React from "react" import { mount } from "enzyme" import { useTracking } from "react-tracking" import { Link } from "@artsy/palette" -import { Device, DownloadAppBadge } from "v2/Components/DownloadAppBadge" +import { DownloadAppBadge } from "v2/Components/DownloadAppBadge" import { ContextModule } from "@artsy/cohesion" +import { Device } from "v2/Utils/Hooks/useDeviceDetection" describe("DownloadAppBadge", () => { const trackEvent = jest.fn() diff --git a/src/v2/Utils/Hooks/useDeviceDetection.tsx b/src/v2/Utils/Hooks/useDeviceDetection.tsx new file mode 100644 index 00000000000..aa8c5e57f2e --- /dev/null +++ b/src/v2/Utils/Hooks/useDeviceDetection.tsx @@ -0,0 +1,21 @@ +import { useEffect, useState } from "react" + +export enum Device { + iPhone, + Android, +} + +export const useDeviceDetection = () => { + // @ts-expect-error STRICT_NULL_CHECK + const [device, setDevice] = useState(undefined) + + useEffect(() => { + if (window.navigator.userAgent.match(/Android/)) { + setDevice(Device.Android) + } else if (window.navigator.userAgent.match(/iPhone/)) { + setDevice(Device.iPhone) + } + }, []) + + return device +} From 4b116a17f534971e1f45369999f9156b4c653b77 Mon Sep 17 00:00:00 2001 From: nastassia Date: Fri, 28 May 2021 17:31:59 +0300 Subject: [PATCH 5/6] Added download app link to mobile nav, encapsulated logic of defining url to useDeviceDetection hook --- src/v2/Components/DownloadAppBadge.tsx | 12 ++---------- src/v2/Components/Footer/Footer.tsx | 4 +++- .../Menus/MobileNavMenu/MobileNavMenu.tsx | 3 +++ .../__tests__/DownloadAppBadge.jest.tsx | 18 +++--------------- src/v2/Utils/Hooks/useDeviceDetection.tsx | 10 +++++++++- 5 files changed, 20 insertions(+), 27 deletions(-) diff --git a/src/v2/Components/DownloadAppBadge.tsx b/src/v2/Components/DownloadAppBadge.tsx index 5190321f8ce..f29f1e7d124 100644 --- a/src/v2/Components/DownloadAppBadge.tsx +++ b/src/v2/Components/DownloadAppBadge.tsx @@ -9,23 +9,15 @@ 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 = track(null, { dispatch: data => Events.postEvent(data), -})(({ contextModule, device }) => { +})(({ contextModule, device, downloadAppUrl }) => { const tracking = useTracking() - let downloadAppUrl: string = "" - if (device === Device.iPhone) { - downloadAppUrl = - "https://apps.apple.com/us/app/artsy-buy-sell-original-art/id703796080" - } else if (device === Device.Android) { - downloadAppUrl = - "https://play.google.com/store/apps/details?id=net.artsy.app" - } - const { contextPageOwnerId, contextPageOwnerSlug, diff --git a/src/v2/Components/Footer/Footer.tsx b/src/v2/Components/Footer/Footer.tsx index 71cd2a73781..226b235fa71 100644 --- a/src/v2/Components/Footer/Footer.tsx +++ b/src/v2/Components/Footer/Footer.tsx @@ -28,7 +28,7 @@ import { Device, useDeviceDetection } from "v2/Utils/Hooks/useDeviceDetection" interface FooterProps extends BoxProps {} export const Footer: React.FC = props => { - const device = useDeviceDetection() + const { device, downloadAppUrl } = useDeviceDetection() const tokens = useThemeConfig({ v2: { @@ -61,6 +61,7 @@ export const Footer: React.FC = props => { @@ -158,6 +159,7 @@ export const Footer: React.FC = props => { diff --git a/src/v2/Components/NavBar/Menus/MobileNavMenu/MobileNavMenu.tsx b/src/v2/Components/NavBar/Menus/MobileNavMenu/MobileNavMenu.tsx index c43a536f359..c3d607a32ab 100644 --- a/src/v2/Components/NavBar/Menus/MobileNavMenu/MobileNavMenu.tsx +++ b/src/v2/Components/NavBar/Menus/MobileNavMenu/MobileNavMenu.tsx @@ -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; @@ -59,6 +60,7 @@ export const MobileNavMenu: React.FC = ({ onClose, }) => { const { user } = useSystemContext() + const { downloadAppUrl } = useDeviceDetection() return ( @@ -101,6 +103,7 @@ export const MobileNavMenu: React.FC = ({ Editorial {user ? : } + Get the app diff --git a/src/v2/Components/__tests__/DownloadAppBadge.jest.tsx b/src/v2/Components/__tests__/DownloadAppBadge.jest.tsx index fe30c28342a..c6a6009b796 100644 --- a/src/v2/Components/__tests__/DownloadAppBadge.jest.tsx +++ b/src/v2/Components/__tests__/DownloadAppBadge.jest.tsx @@ -17,6 +17,8 @@ describe("DownloadAppBadge", () => { const props = { contextModule: ContextModule.footer, device: Device.iPhone, + downloadAppUrl: + "https://apps.apple.com/us/app/artsy-buy-sell-original-art/id703796080", } beforeEach(() => { @@ -32,25 +34,11 @@ describe("DownloadAppBadge", () => { jest.resetAllMocks() }) - it("tracks clicks on the iPhone app download badge", () => { + it("tracks clicks on the app download badge", () => { const badge = mount() const downloadLink = badge.find(Link) // @ts-expect-error STRICT_NULL_CHECK downloadLink.props().onClick({} as any) expect(trackEvent).toHaveBeenCalledWith(expect.objectContaining(event)) }) - - it("tracks clicks on the Android app download badge", () => { - const badge = mount() - const downloadLink = badge.find(Link) - // @ts-expect-error STRICT_NULL_CHECK - downloadLink.props().onClick({} as any) - expect(trackEvent).toHaveBeenCalledWith( - expect.objectContaining({ - ...event, - destination_path: - "https://play.google.com/store/apps/details?id=net.artsy.app", - }) - ) - }) }) diff --git a/src/v2/Utils/Hooks/useDeviceDetection.tsx b/src/v2/Utils/Hooks/useDeviceDetection.tsx index aa8c5e57f2e..c0ade613388 100644 --- a/src/v2/Utils/Hooks/useDeviceDetection.tsx +++ b/src/v2/Utils/Hooks/useDeviceDetection.tsx @@ -8,14 +8,22 @@ export enum Device { export const useDeviceDetection = () => { // @ts-expect-error STRICT_NULL_CHECK const [device, setDevice] = useState(undefined) + // @ts-expect-error STRICT_NULL_CHECK + const [downloadAppUrl, setDownloadAppUrl] = useState(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 + return { device, downloadAppUrl } } From f531a6391a6adc11c0608902e495dd7d05ebede0 Mon Sep 17 00:00:00 2001 From: nastassia Date: Fri, 28 May 2021 18:31:18 +0300 Subject: [PATCH 6/6] Updated tests --- .../Menus/MobileNavMenu/__tests__/MobileNavMenu.jest.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/v2/Components/NavBar/Menus/MobileNavMenu/__tests__/MobileNavMenu.jest.tsx b/src/v2/Components/NavBar/Menus/MobileNavMenu/__tests__/MobileNavMenu.jest.tsx index 344d774da9d..c139db739d5 100644 --- a/src/v2/Components/NavBar/Menus/MobileNavMenu/__tests__/MobileNavMenu.jest.tsx +++ b/src/v2/Components/NavBar/Menus/MobileNavMenu/__tests__/MobileNavMenu.jest.tsx @@ -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: () => {}, @@ -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") }) })