diff --git a/src/app/Components/ArtworkRail/ArtworkRail.tsx b/src/app/Components/ArtworkRail/ArtworkRail.tsx index 57357bacbe3..58df5b61315 100644 --- a/src/app/Components/ArtworkRail/ArtworkRail.tsx +++ b/src/app/Components/ArtworkRail/ArtworkRail.tsx @@ -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, @@ -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" @@ -142,10 +141,11 @@ export const ArtworkRailPlaceholder: React.FC = () => { const enableArtworkRailRedesignImageAspectRatio = useFeatureFlag( "AREnableArtworkRailRedesignImageAspectRatio" ) + const cards = !isTablet() ? 2 : 6 return ( - }> - {times(3 + useMemoizedRandom() * 10).map((index) => ( + + {Array.from({ length: cards }).map((_, index) => ( {enableArtworkRailRedesignImageAspectRatio ? ( { ))} - + ) } diff --git a/src/app/Scenes/CollectionsByCategory/Body.tsx b/src/app/Scenes/CollectionsByCategory/Body.tsx index 7f53f41caa6..a2c8e6286d4 100644 --- a/src/app/Scenes/CollectionsByCategory/Body.tsx +++ b/src/app/Scenes/CollectionsByCategory/Body.tsx @@ -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 = ({ marketingCollections }) => { +export const Body: React.FC = ({ marketingCollections: _marketingCollections }) => { const space = useSpace() + const marketingCollections = useFragment(fragment, _marketingCollections) const { params } = useRoute() const category = params.props.category + if (!marketingCollections) { + return null + } + return ( - + {category} Explore collections with {category} - + + + {marketingCollections.map((collection) => { + const slug = collection?.slug ?? "" + return + })} ) } +const fragment = graphql` + fragment BodyCollectionsByCategory_marketingCollection on MarketingCollection + @relay(plural: true) { + slug @required(action: NONE) + } +` + const BodyPlaceholder: React.FC = () => { const space = useSpace() @@ -44,6 +67,8 @@ const BodyPlaceholder: React.FC = () => { + + ) @@ -51,7 +76,8 @@ const BodyPlaceholder: React.FC = () => { const query = graphql` query BodyCollectionsByCategoryQuery($category: String!) { - marketingCollections(category: $category, size: 10) { + marketingCollections(category: $category, first: 20) { + ...BodyCollectionsByCategory_marketingCollection ...CollectionsChips_marketingCollections } } diff --git a/src/app/Scenes/CollectionsByCategory/CollectionRail.tsx b/src/app/Scenes/CollectionsByCategory/CollectionRail.tsx new file mode 100644 index 00000000000..ce0539450f8 --- /dev/null +++ b/src/app/Scenes/CollectionsByCategory/CollectionRail.tsx @@ -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 = ({ collection: _collection }) => { + const collection = useFragment(fragment, _collection) + + if (!collection || collection.artworksConnection?.counts.total === 0) { + return null + } + + const artworks = extractNodes(collection.artworksConnection) + + return ( + + {}} + RightButtonContent={() => } + /> + + + ) +} + +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 ( + + + Category title + + + + + + + + + + ) +} + +const query = graphql` + query CollectionRailCollectionsByCategoryQuery($slug: String!) { + marketingCollection(slug: $slug) { + ...CollectionRail_marketingCollection + + title + markdownDescription + } + } +` + +interface CollectionRailWithSuspenseProps { + slug: string +} + +export const CollectionRailWithSuspense = withSuspense({ + Component: ({ slug }) => { + const { height } = useScreenDimensions() + const [isVisible, setIsVisible] = useState(false) + const { data, loading } = useClientQuery({ + 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 ( + + + + ) + } + + return + }, + ErrorFallback: NoFallback, + LoadingFallback: CollectionRailPlaceholder, +}) diff --git a/src/app/Scenes/CollectionsByCategory/__tests__/Body.tests.tsx b/src/app/Scenes/CollectionsByCategory/__tests__/Body.tests.tsx new file mode 100644 index 00000000000..499d00ed329 --- /dev/null +++ b/src/app/Scenes/CollectionsByCategory/__tests__/Body.tests.tsx @@ -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({ + Component: ({ 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(//)).toBeOnTheScreen() + }) +}) diff --git a/src/app/Scenes/CollectionsByCategory/__tests__/CollectionRail.tests.tsx b/src/app/Scenes/CollectionsByCategory/__tests__/CollectionRail.tests.tsx new file mode 100644 index 00000000000..80e5ba538db --- /dev/null +++ b/src/app/Scenes/CollectionsByCategory/__tests__/CollectionRail.tests.tsx @@ -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({ + Component: ({ 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() + }) +}) diff --git a/src/app/Scenes/Home/Home.tsx b/src/app/Scenes/Home/Home.tsx index 8dd98622760..a212fb528b7 100644 --- a/src/app/Scenes/Home/Home.tsx +++ b/src/app/Scenes/Home/Home.tsx @@ -680,9 +680,8 @@ const HomePlaceholder: React.FC = () => { - - - + +