Skip to content

Commit

Permalink
feat(DIA-931): add collection artwork rails (#10989)
Browse files Browse the repository at this point in the history
feat: add collection artwork rails
  • Loading branch information
araujobarret authored Oct 23, 2024
1 parent 55b06d9 commit 76af019
Show file tree
Hide file tree
Showing 6 changed files with 235 additions and 15 deletions.
12 changes: 6 additions & 6 deletions src/app/Components/ArtworkRail/ArtworkRail.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Box, Flex, Join, SkeletonBox, SkeletonText, Spacer } from "@artsy/palette-mobile"
import { Box, Flex, SkeletonBox, SkeletonText, Spacer } from "@artsy/palette-mobile"
import { ListRenderItem } from "@shopify/flash-list"
import {
ArtworkRail_artworks$data,
Expand All @@ -16,12 +16,11 @@ import { LEGACY_ARTWORK_RAIL_CARD_IMAGE_HEIGHT } from "app/Components/ArtworkRai
import { BrowseMoreRailCard } from "app/Components/BrowseMoreRailCard"
import { PrefetchFlashList } from "app/Components/PrefetchFlashList"
import { useFeatureFlag } from "app/utils/hooks/useFeatureFlag"
import { RandomWidthPlaceholderText, useMemoizedRandom } from "app/utils/placeholders"
import { RandomWidthPlaceholderText } from "app/utils/placeholders"
import {
ArtworkActionTrackingProps,
extractArtworkActionTrackingProps,
} from "app/utils/track/ArtworkActions"
import { times } from "lodash"
import React, { ReactElement, useCallback } from "react"
import { FlatList, ViewabilityConfig } from "react-native"
import { isTablet } from "react-native-device-info"
Expand Down Expand Up @@ -142,10 +141,11 @@ export const ArtworkRailPlaceholder: React.FC = () => {
const enableArtworkRailRedesignImageAspectRatio = useFeatureFlag(
"AREnableArtworkRailRedesignImageAspectRatio"
)
const cards = !isTablet() ? 2 : 6

return (
<Join separator={<Spacer x="15px" />}>
{times(3 + useMemoizedRandom() * 10).map((index) => (
<Flex gap={15} flexDirection="row">
{Array.from({ length: cards }).map((_, index) => (
<Flex key={index}>
{enableArtworkRailRedesignImageAspectRatio ? (
<SkeletonBox
Expand All @@ -163,6 +163,6 @@ export const ArtworkRailPlaceholder: React.FC = () => {
<RandomWidthPlaceholderText minWidth={30} maxWidth={90} />
</Flex>
))}
</Join>
</Flex>
)
}
38 changes: 32 additions & 6 deletions src/app/Scenes/CollectionsByCategory/Body.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,59 @@
import { Flex, Skeleton, SkeletonText, Text, useSpace } from "@artsy/palette-mobile"
import { useRoute } from "@react-navigation/native"
import { BodyCollectionsByCategoryQuery } from "__generated__/BodyCollectionsByCategoryQuery.graphql"
import { BodyCollectionsByCategory_marketingCollection$key } from "__generated__/BodyCollectionsByCategory_marketingCollection.graphql"
import { CollectionsChips_marketingCollections$key } from "__generated__/CollectionsChips_marketingCollections.graphql"
import {
CollectionRailPlaceholder,
CollectionRailWithSuspense,
} from "app/Scenes/CollectionsByCategory/CollectionRail"
import { CollectionsByCategoriesRouteProp } from "app/Scenes/CollectionsByCategory/CollectionsByCategory"
import {
CollectionsChips,
CollectionsChipsPlaceholder,
} from "app/Scenes/CollectionsByCategory/CollectionsChips"
import { NoFallback, withSuspense } from "app/utils/hooks/withSuspense"
import { graphql, useLazyLoadQuery } from "react-relay"
import { graphql, useLazyLoadQuery, useFragment } from "react-relay"

interface BodyProps {
marketingCollections: CollectionsChips_marketingCollections$key
marketingCollections: BodyCollectionsByCategory_marketingCollection$key &
CollectionsChips_marketingCollections$key
}

export const Body: React.FC<BodyProps> = ({ marketingCollections }) => {
export const Body: React.FC<BodyProps> = ({ marketingCollections: _marketingCollections }) => {
const space = useSpace()
const marketingCollections = useFragment(fragment, _marketingCollections)
const { params } = useRoute<CollectionsByCategoriesRouteProp>()
const category = params.props.category

if (!marketingCollections) {
return null
}

return (
<Flex px={2} gap={space(2)}>
<Flex px={2} gap={space(4)}>
<Text variant="xl">{category}</Text>

<Flex gap={space(1)}>
<Text>Explore collections with {category}</Text>
<CollectionsChips marketingCollections={marketingCollections} />
<CollectionsChips marketingCollections={_marketingCollections} />
</Flex>

{marketingCollections.map((collection) => {
const slug = collection?.slug ?? ""
return <CollectionRailWithSuspense key={`artwork_rail_${slug}`} slug={slug} />
})}
</Flex>
)
}

const fragment = graphql`
fragment BodyCollectionsByCategory_marketingCollection on MarketingCollection
@relay(plural: true) {
slug @required(action: NONE)
}
`

const BodyPlaceholder: React.FC = () => {
const space = useSpace()

Expand All @@ -44,14 +67,17 @@ const BodyPlaceholder: React.FC = () => {

<CollectionsChipsPlaceholder />
</Flex>

<CollectionRailPlaceholder />
</Flex>
</Skeleton>
)
}

const query = graphql`
query BodyCollectionsByCategoryQuery($category: String!) {
marketingCollections(category: $category, size: 10) {
marketingCollections(category: $category, first: 20) {
...BodyCollectionsByCategory_marketingCollection
...CollectionsChips_marketingCollections
}
}
Expand Down
127 changes: 127 additions & 0 deletions src/app/Scenes/CollectionsByCategory/CollectionRail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import {
ArrowRightIcon,
Flex,
Skeleton,
SkeletonText,
Spacer,
useScreenDimensions,
} from "@artsy/palette-mobile"
import { CollectionRailCollectionsByCategoryQuery } from "__generated__/CollectionRailCollectionsByCategoryQuery.graphql"
import { CollectionRail_marketingCollection$key } from "__generated__/CollectionRail_marketingCollection.graphql"
import { ArtworkRail, ArtworkRailPlaceholder } from "app/Components/ArtworkRail/ArtworkRail"
import { SectionTitle } from "app/Components/SectionTitle"
import { ElementInView } from "app/utils/ElementInView"
import { extractNodes } from "app/utils/extractNodes"
import { withSuspense, NoFallback } from "app/utils/hooks/withSuspense"
import { useClientQuery } from "app/utils/useClientQuery"
import { FC, useState } from "react"
import { graphql, useFragment } from "react-relay"

interface CollectionRailProps {
collection: CollectionRail_marketingCollection$key
}

export const CollectionRail: FC<CollectionRailProps> = ({ collection: _collection }) => {
const collection = useFragment(fragment, _collection)

if (!collection || collection.artworksConnection?.counts.total === 0) {
return null
}

const artworks = extractNodes(collection.artworksConnection)

return (
<Flex>
<SectionTitle
title={collection.title}
onPress={() => {}}
RightButtonContent={() => <ArrowRightIcon />}
/>
<ArtworkRail artworks={artworks} ListHeaderComponent={null} />
</Flex>
)
}

const fragment = graphql`
fragment CollectionRail_marketingCollection on MarketingCollection {
title @required(action: NONE)
artworksConnection(first: 10) {
counts @required(action: NONE) {
total
}
edges {
node {
...ArtworkRail_artworks
internalID
slug
href
}
}
}
}
`

export const CollectionRailPlaceholder: FC = () => {
return (
<Skeleton>
<Flex justifyContent="space-between" flexDirection="row">
<SkeletonText>Category title</SkeletonText>
<ArrowRightIcon />
</Flex>

<Spacer y={1} />

<Flex flexDirection="row">
<ArtworkRailPlaceholder />
</Flex>
</Skeleton>
)
}

const query = graphql`
query CollectionRailCollectionsByCategoryQuery($slug: String!) {
marketingCollection(slug: $slug) {
...CollectionRail_marketingCollection
title
markdownDescription
}
}
`

interface CollectionRailWithSuspenseProps {
slug: string
}

export const CollectionRailWithSuspense = withSuspense<CollectionRailWithSuspenseProps>({
Component: ({ slug }) => {
const { height } = useScreenDimensions()
const [isVisible, setIsVisible] = useState(false)
const { data, loading } = useClientQuery<CollectionRailCollectionsByCategoryQuery>({
query,
variables: { slug },
skip: !isVisible,
})

const handleOnVisible = () => {
if (!isVisible) {
setIsVisible(true)
}
}

if (loading || !data?.marketingCollection || !isVisible) {
// We don't need to overfetch all rails at once, fetch as they become closer to be visible
return (
<ElementInView onVisible={handleOnVisible} visibilityMargin={-height}>
<CollectionRailPlaceholder />
</ElementInView>
)
}

return <CollectionRail collection={data.marketingCollection} />
},
ErrorFallback: NoFallback,
LoadingFallback: CollectionRailPlaceholder,
})
39 changes: 39 additions & 0 deletions src/app/Scenes/CollectionsByCategory/__tests__/Body.tests.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { screen } from "@testing-library/react-native"
import { BodyHomeViewSectionCardsTestQuery } from "__generated__/BodyHomeViewSectionCardsTestQuery.graphql"
import { Body } from "app/Scenes/CollectionsByCategory/Body"
import { setupTestWrapper } from "app/utils/tests/setupTestWrapper"
import { graphql } from "react-relay"

jest.mock("@react-navigation/native", () => ({
useRoute: () => ({
params: {
props: { category: "mock-category" },
},
}),
}))

jest.mock("app/Scenes/CollectionsByCategory/CollectionRail", () => ({
CollectionRailWithSuspense: () => null,
CollectionRailPlaceholder: () => null,
}))

describe("Body", () => {
const { renderWithRelay } = setupTestWrapper<BodyHomeViewSectionCardsTestQuery>({
Component: ({ marketingCollections }) => <Body marketingCollections={marketingCollections} />,
query: graphql`
query BodyHomeViewSectionCardsTestQuery {
marketingCollections(category: "category", first: 20) @required(action: NONE) {
...BodyCollectionsByCategory_marketingCollection
...CollectionsChips_marketingCollections
}
}
`,
})

it("renders", () => {
renderWithRelay()

expect(screen.getByText(/Explore collections with mock-category/)).toBeOnTheScreen()
expect(screen.getByText(/<mock-value-for-field-"title">/)).toBeOnTheScreen()
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { screen } from "@testing-library/react-native"
import { CollectionRailHomeViewSectionCardsTestQuery } from "__generated__/CollectionRailHomeViewSectionCardsTestQuery.graphql"
import { CollectionRail } from "app/Scenes/CollectionsByCategory/CollectionRail"
import { setupTestWrapper } from "app/utils/tests/setupTestWrapper"
import { graphql } from "react-relay"

jest.mock("app/Components/ArtworkRail/ArtworkRail", () => ({
ArtworkRail: () => null,
ArtworkRailPlaceholder: () => null,
}))

describe("CollectionRail", () => {
const { renderWithRelay } = setupTestWrapper<CollectionRailHomeViewSectionCardsTestQuery>({
Component: ({ marketingCollection }) => <CollectionRail collection={marketingCollection} />,
query: graphql`
query CollectionRailHomeViewSectionCardsTestQuery {
marketingCollection(slug: "marketing-slug") @required(action: NONE) {
...CollectionRail_marketingCollection
}
}
`,
})

it("renders", () => {
renderWithRelay()

expect(screen.getByText(/mock-Value-for-Field-"Title"/)).toBeOnTheScreen()
})
})
5 changes: 2 additions & 3 deletions src/app/Scenes/Home/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -680,9 +680,8 @@ const HomePlaceholder: React.FC = () => {
<Box ml={2} mr={2}>
<RandomWidthPlaceholderText minWidth={100} maxWidth={200} />
<Spacer y={0.5} />
<Flex flexDirection="row">
<ArtworkRailPlaceholder />
</Flex>

<ArtworkRailPlaceholder />
</Box>
<ModuleSeparator />

Expand Down

0 comments on commit 76af019

Please sign in to comment.