Skip to content

Commit

Permalink
feat(DIA-1062): refetch infinite discovery (#11395)
Browse files Browse the repository at this point in the history
* added refetchable fragment to fetch more artworks

* removed a magic number

* fixed failing tests
  • Loading branch information
iskounen authored Jan 16, 2025
1 parent 9516f63 commit e0fdd7b
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 219 deletions.
90 changes: 2 additions & 88 deletions src/app/Components/FancySwiper/__tests__/FancySwiper.tests.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { fireEvent, screen, waitFor } from "@testing-library/react-native"
import { waitFor } from "@testing-library/react-native"
import { FancySwiper } from "app/Components/FancySwiper/FancySwiper"
import { Card } from "app/Components/FancySwiper/FancySwiperCard"
import { swipeLeft, swipeRight } from "app/Components/FancySwiper/__tests__/utils"
import { renderWithWrappers } from "app/utils/tests/renderWithWrappers"

describe("FancySwiper", () => {
Expand All @@ -19,93 +20,6 @@ describe("FancySwiper", () => {
})
})

const swipeLeft = () => {
swipe(-100)
}

const swipeRight = () => {
swipe(100)
}

const swipe = (moveX: number) => {
const topCard = screen.getByTestId("top-fancy-swiper-card")

const startX = 0
const startY = 0
const startTimeStamp = Date.now()
const moveTimeStamp = Date.now()
const releaseTimeStamp = Date.now()

fireEvent(topCard, "responderStart", {
touchHistory: {
indexOfSingleActiveTouch: 1,
mostRecentTimeStamp: startTimeStamp,
numberActiveTouches: 1,
touchBank: [
undefined,
{
currentPageX: startX,
currentPageY: startY,
currentTimeStamp: startTimeStamp,
previousPageX: startX,
previousPageY: startY,
previousTimeStamp: startTimeStamp,
startPageX: startX,
startPageY: startY,
startTimeStamp: startTimeStamp,
touchActive: true,
},
],
},
})

fireEvent(topCard, "responderMove", {
touchHistory: {
indexOfSingleActiveTouch: 1,
mostRecentTimeStamp: moveTimeStamp,
numberActiveTouches: 1,
touchBank: [
undefined,
{
currentPageX: moveX,
currentPageY: startY,
currentTimeStamp: moveTimeStamp,
previousPageX: startX,
previousPageY: startY,
previousTimeStamp: startTimeStamp,
startPageX: startX,
startPageY: startY,
startTimeStamp: startTimeStamp,
touchActive: true,
},
],
},
})

fireEvent(topCard, "responderRelease", {
touchHistory: {
indexOfSingleActiveTouch: 1,
mostRecentTimeStamp: releaseTimeStamp,
numberActiveTouches: 0,
touchBank: [
undefined,
{
currentPageX: moveX,
currentPageY: startY,
currentTimeStamp: releaseTimeStamp,
previousPageX: moveX,
previousPageY: startY,
previousTimeStamp: moveTimeStamp,
startPageX: startX,
startPageY: startY,
startTimeStamp: startTimeStamp,
touchActive: false,
},
],
},
})
}

const cards: Card[] = [
{
id: "1",
Expand Down
88 changes: 88 additions & 0 deletions src/app/Components/FancySwiper/__tests__/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { fireEvent, screen } from "@testing-library/react-native"

export const swipeLeft = () => {
swipe(-100)
}

export const swipeRight = () => {
swipe(100)
}

const swipe = (moveX: number) => {
const topCard = screen.getByTestId("top-fancy-swiper-card")

const startX = 0
const startY = 0
const startTimeStamp = Date.now()
const moveTimeStamp = Date.now()
const releaseTimeStamp = Date.now()

fireEvent(topCard, "responderStart", {
touchHistory: {
indexOfSingleActiveTouch: 1,
mostRecentTimeStamp: startTimeStamp,
numberActiveTouches: 1,
touchBank: [
undefined,
{
currentPageX: startX,
currentPageY: startY,
currentTimeStamp: startTimeStamp,
previousPageX: startX,
previousPageY: startY,
previousTimeStamp: startTimeStamp,
startPageX: startX,
startPageY: startY,
startTimeStamp: startTimeStamp,
touchActive: true,
},
],
},
})

fireEvent(topCard, "responderMove", {
touchHistory: {
indexOfSingleActiveTouch: 1,
mostRecentTimeStamp: moveTimeStamp,
numberActiveTouches: 1,
touchBank: [
undefined,
{
currentPageX: moveX,
currentPageY: startY,
currentTimeStamp: moveTimeStamp,
previousPageX: startX,
previousPageY: startY,
previousTimeStamp: startTimeStamp,
startPageX: startX,
startPageY: startY,
startTimeStamp: startTimeStamp,
touchActive: true,
},
],
},
})

fireEvent(topCard, "responderRelease", {
touchHistory: {
indexOfSingleActiveTouch: 1,
mostRecentTimeStamp: releaseTimeStamp,
numberActiveTouches: 0,
touchBank: [
undefined,
{
currentPageX: moveX,
currentPageY: startY,
currentTimeStamp: releaseTimeStamp,
previousPageX: moveX,
previousPageY: startY,
previousTimeStamp: moveTimeStamp,
startPageX: startX,
startPageY: startY,
startTimeStamp: startTimeStamp,
touchActive: false,
},
],
},
})
}
117 changes: 84 additions & 33 deletions src/app/Scenes/InfiniteDiscovery/InfiniteDiscovery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,51 @@ import {
useScreenDimensions,
useTheme,
} from "@artsy/palette-mobile"
import { InfiniteDiscoveryRefetchQuery } from "__generated__/InfiniteDiscoveryRefetchQuery.graphql"
import { InfiniteDiscovery_Fragment$key } from "__generated__/InfiniteDiscovery_Fragment.graphql"
import { FancySwiper } from "app/Components/FancySwiper/FancySwiper"
import { InfiniteDiscoveryBottomSheet } from "app/Scenes/InfiniteDiscovery/Components/InfiniteDiscoveryBottomSheet"
import { goBack } from "app/system/navigation/navigate"
import { extractNodes } from "app/utils/extractNodes"
import { NoFallback, withSuspense } from "app/utils/hooks/withSuspense"
import { NoFallback, SpinnerFallback, withSuspense } from "app/utils/hooks/withSuspense"
import { sizeToFit } from "app/utils/useSizeToFit"
import { useMemo, useState } from "react"
import { graphql, useLazyLoadQuery } from "react-relay"
import type { InfiniteDiscoveryQuery } from "__generated__/InfiniteDiscoveryQuery.graphql"
import { useEffect, useState } from "react"
import { graphql, useLazyLoadQuery, useRefetchableFragment } from "react-relay"
import type {
InfiniteDiscoveryQuery,
InfiniteDiscoveryQuery$data,
} from "__generated__/InfiniteDiscoveryQuery.graphql"
import type { Card } from "app/Components/FancySwiper/FancySwiperCard"

export const InfiniteDiscovery: React.FC = () => {
const data = useLazyLoadQuery<InfiniteDiscoveryQuery>(infiniteDiscoveryQuery, {})
const artworks = useMemo(() => extractNodes(data.marketingCollection?.artworksConnection), [data])
interface InfiniteDiscoveryProps {
artworks: InfiniteDiscoveryQuery$data
}

export const InfiniteDiscovery: React.FC<InfiniteDiscoveryProps> = ({ artworks: _artworks }) => {
const [data, refetch] = useRefetchableFragment<
InfiniteDiscoveryRefetchQuery,
InfiniteDiscovery_Fragment$key
>(infiniteDiscoveryFragment, _artworks)

const REFETCH_BUFFER = 2

const { color } = useTheme()
const { width: screenWidth } = useScreenDimensions()

const [index, setIndex] = useState(0)
const [artworks, setArtworks] = useState(extractNodes(data.discoverArtworks))

useEffect(() => {
setArtworks((previousArtworks) => {
// only add new artworks to the list by filtering-out existing artworks
const newArtworks = extractNodes(data.discoverArtworks).filter(
(newArtwork) =>
!previousArtworks.some((artwork) => artwork.internalID === newArtwork.internalID)
)

return [...previousArtworks, ...newArtworks]
})
}, [data, extractNodes, setArtworks])

const goToPrevious = () => {
if (index > 0) {
Expand All @@ -40,6 +66,16 @@ export const InfiniteDiscovery: React.FC = () => {
if (index < artworks.length - 1) {
setIndex(index + 1)
}

// fetch more artworks when the user is about to reach the end of the list
if (index === artworks.length - REFETCH_BUFFER) {
refetch(
{ excludeArtworkIds: artworks.map((artwork) => artwork.internalID) },
{
fetchPolicy: "network-only",
}
)
}
}

const handleBackPressed = () => {
Expand Down Expand Up @@ -74,13 +110,14 @@ export const InfiniteDiscovery: React.FC = () => {
Follow
</Button>
}
p={1}
/>
<Spacer y={2} />

<Flex alignItems="center" backgroundColor={color("purple60")}>
{!!src && <Image src={src} height={size.height} width={size.width} />}
</Flex>
<Flex flexDirection="row" justifyContent="space-between">
<Flex flexDirection="row" justifyContent="space-between" p={1}>
<Flex>
<Flex flexDirection="row" maxWidth={screenWidth - 200}>
{/* TODO: maxWidth above and ellipsizeMode + numberOfLines below are used to */}
Expand Down Expand Up @@ -137,39 +174,53 @@ export const InfiniteDiscovery: React.FC = () => {
}

export const InfiniteDiscoveryQueryRenderer = withSuspense({
Component: InfiniteDiscovery,
LoadingFallback: () => <Text>Loading...</Text>,
Component: () => {
const initialData = useLazyLoadQuery<InfiniteDiscoveryQuery>(infiniteDiscoveryQuery, {})

if (!initialData) {
return null
}

return <InfiniteDiscovery artworks={initialData} />
},
LoadingFallback: SpinnerFallback,
ErrorFallback: NoFallback,
})

export const infiniteDiscoveryQuery = graphql`
query InfiniteDiscoveryQuery {
marketingCollection(slug: "curators-picks") {
artworksConnection(first: 10) {
edges {
node {
artistNames
artists(shallow: true) {
coverArtwork {
images {
url(version: "small")
}
const infiniteDiscoveryFragment = graphql`
fragment InfiniteDiscovery_Fragment on Query
@refetchable(queryName: "InfiniteDiscoveryRefetchQuery")
@argumentDefinitions(excludeArtworkIds: { type: "[String!]" }) {
discoverArtworks(excludeArtworkIds: $excludeArtworkIds) {
edges {
node {
artistNames
artists(shallow: true) {
coverArtwork {
images {
url(version: "small")
}
formattedNationalityAndBirthday
initials
}
date
internalID @required(action: NONE)
images {
url(version: "large")
width
height
}
saleMessage
title
formattedNationalityAndBirthday
initials
}
date
internalID @required(action: NONE)
images {
url(version: "large")
width
height
}
saleMessage
title
}
}
}
}
`

export const infiniteDiscoveryQuery = graphql`
query InfiniteDiscoveryQuery {
...InfiniteDiscovery_Fragment
}
`
Loading

0 comments on commit e0fdd7b

Please sign in to comment.