Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Infer artist series when creating alert form artwork screen #9631

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { screen } from "@testing-library/react-native"
import { CreateArtworkAlertModal_artwork$data } from "__generated__/CreateArtworkAlertModal_artwork.graphql"
import {
CreateArtworkAlertModal,
computeArtworkAlertProps,
useComputeArtworkAlertProps,
} from "app/Components/Artist/ArtistArtworks/CreateArtworkAlertModal"
import { CreateSavedSearchModal } from "app/Components/Artist/ArtistArtworks/CreateSavedSearchModal"
import { setupTestWrapper } from "app/utils/tests/setupTestWrapper"
Expand All @@ -11,6 +12,10 @@ jest.mock("app/Components/Artist/ArtistArtworks/CreateSavedSearchModal", () => (
CreateSavedSearchModal: () => "CreateSavedSearchModal",
}))

jest.mock("app/utils/hooks/useFeatureFlag", () => ({
useFeatureFlag: () => true,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: I would avoid this in favour of using our own __globalStoreTestUtils__?.injectFeatureFlags helper.

}))

describe("CreateArtworkAlertModal", () => {
const { renderWithRelay } = setupTestWrapper({
Component: CreateArtworkAlertModal,
Expand All @@ -24,13 +29,13 @@ describe("CreateArtworkAlertModal", () => {
})

it("returns null if artwork is ineligible", () => {
const { queryByText } = renderWithRelay({
renderWithRelay({
Artwork: () => ({
isEligibleToCreateAlert: false,
}),
})

expect(queryByText("CreateSavedSearchModal")).toBeFalsy()
expect(screen.queryByText("CreateSavedSearchModal")).toBeFalsy()
})

it("returns renders modal", () => {
Expand All @@ -48,13 +53,14 @@ describe("CreateArtworkAlertModal", () => {
})
})

describe("computeArtworkAlertProps", () => {
describe("useCmputeArtworkAlertProps", () => {
const artwork = {
artistsArray: [{ name: "foo", internalID: "bar" }],
isEligibleToCreateAlert: true,
attributionClass: {
internalID: "1",
},
artistSeriesIDs: [],
title: "Test Artwork",
internalID: "2",
slug: "test-artwork",
Expand All @@ -67,17 +73,13 @@ describe("computeArtworkAlertProps", () => {
} as unknown as CreateArtworkAlertModal_artwork$data

it("should return default props when artwork is ineligible for alert", () => {
const result = computeArtworkAlertProps({ ...artwork, isEligibleToCreateAlert: false })
const result = useComputeArtworkAlertProps({ ...artwork, isEligibleToCreateAlert: false })

expect(result).toEqual({
entity: null,
attributes: null,
aggregations: null,
})
expect(result).toEqual(null)
})

it("should return correct props when artwork is eligible for alert", () => {
const result = computeArtworkAlertProps(artwork)
const result = useComputeArtworkAlertProps(artwork)

expect(result).toEqual({
aggregations: [
Expand All @@ -89,6 +91,7 @@ describe("computeArtworkAlertProps", () => {
attributes: {
artistIDs: ["bar"],
attributionClass: ["1"],
artistSeriesIDs: [],
additionalGeneIDs: ["test-gene"],
},
entity: {
Expand All @@ -99,14 +102,15 @@ describe("computeArtworkAlertProps", () => {
})

it("should omit a medium if filterGene isnt provided", () => {
const result = computeArtworkAlertProps({ ...artwork, mediumType: { filterGene: null } })
const result = useComputeArtworkAlertProps({ ...artwork, mediumType: { filterGene: null } })

expect(result).toEqual({
aggregations: [],
attributes: {
artistIDs: ["bar"],
attributionClass: ["1"],
additionalGeneIDs: [],
artistSeriesIDs: [],
},
entity: {
artists: [{ id: "bar", name: "foo" }],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
SavedSearchEntityArtist,
SearchCriteriaAttributes,
} from "app/Components/ArtworkFilter/SavedSearch/types"
import { extractNodes } from "app/utils/extractNodes"
import { useFeatureFlag } from "app/utils/hooks/useFeatureFlag"
import { compact } from "lodash"
import { graphql, useFragment } from "react-relay"

Expand All @@ -30,6 +32,13 @@ export const CreateArtworkAlertModal: React.FC<CreateArtworkAlertModalProps> = (
const data = useFragment<CreateArtworkAlertModalProps["artwork"]>(
graphql`
fragment CreateArtworkAlertModal_artwork on Artwork {
artistSeriesConnection(first: 5) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using 5 as the maximum number of artist series used when creating an alert would cover 99.98% of the cases.(context: artsy/force#13244 (comment))

edges {
node {
slug
}
}
}
title
internalID
slug
Expand All @@ -52,38 +61,40 @@ export const CreateArtworkAlertModal: React.FC<CreateArtworkAlertModalProps> = (
artwork
)

const artworkAlert = useComputeArtworkAlertProps(data)

const { isEligibleToCreateAlert } = data

if (!isEligibleToCreateAlert) {
return null
}

const artworkAlert = computeArtworkAlertProps(data)
if (!artworkAlert) {
return null
}
Comment on lines +72 to +74
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactoring this component to be able to remove the forbidden non-null assertions.


return (
<CreateSavedSearchModal
visible={visible}
entity={artworkAlert.entity!}
attributes={artworkAlert.attributes!}
aggregations={artworkAlert.aggregations!}
entity={artworkAlert.entity}
attributes={artworkAlert.attributes}
aggregations={artworkAlert.aggregations}
closeModal={onClose}
contextModule={contextModule}
currentArtworkID={data.internalID}
/>
)
}

export const computeArtworkAlertProps = (
export const useComputeArtworkAlertProps = (
artwork: CreateArtworkAlertModal_artwork$data | BrowseSimilarWorks_artwork$data
) => {
const enableArtistSeriesFilter = useFeatureFlag("AREnableArtistSeriesFilter")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still an open discussion whether to use a second feature flag here (Slack Thread)


const { isEligibleToCreateAlert } = artwork

if (!isEligibleToCreateAlert) {
return {
entity: null,
attributes: null,
aggregations: null,
}
return null
}

let aggregations: Aggregations = []
Expand All @@ -93,7 +104,7 @@ export const computeArtworkAlertProps = (
const attributionClass = compact([artwork?.attributionClass?.internalID])
const formattedArtists: SavedSearchEntityArtist[] = artists.map((artist) => ({
id: artist.internalID,
name: artist.name!,
name: artist.name || "",
}))

const entity: SavedSearchEntity = {
Expand Down Expand Up @@ -121,10 +132,15 @@ export const computeArtworkAlertProps = (
]
}

const artistSeriesIDs = enableArtistSeriesFilter
? extractNodes(artwork?.artistSeriesConnection).map((series) => series.slug)
: []

const attributes: SearchCriteriaAttributes = {
artistIDs: formattedArtists.map((artist) => artist.id),
attributionClass,
additionalGeneIDs,
artistSeriesIDs,
}

return {
Expand Down
2 changes: 1 addition & 1 deletion src/app/Scenes/Artwork/Artwork.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -589,7 +589,7 @@ export const ArtworkContainer = createRefetchContainer(
}
}
}
artistSeriesConnection(first: 1) {
artistSeriesConnection(first: 5) {
edges {
node {
filterArtworksConnection(first: 20, input: { sort: "-decayed_merch" }) {
Expand Down
2 changes: 1 addition & 1 deletion src/app/Scenes/Artwork/Components/ArtworksInSeriesRail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const artworkFragment = graphql`
fragment ArtworksInSeriesRail_artwork on Artwork {
internalID
slug
artistSeriesConnection(first: 1) {
artistSeriesConnection(first: 5) {
edges {
node {
slug
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Flex, Screen, Box, Spacer } from "@artsy/palette-mobile"
import { BrowseSimilarWorksQuery } from "__generated__/BrowseSimilarWorksQuery.graphql"
import { BrowseSimilarWorks_artwork$key } from "__generated__/BrowseSimilarWorks_artwork.graphql"
import { computeArtworkAlertProps } from "app/Components/Artist/ArtistArtworks/CreateArtworkAlertModal"
import { useComputeArtworkAlertProps } from "app/Components/Artist/ArtistArtworks/CreateArtworkAlertModal"
import { Aggregations } from "app/Components/ArtworkFilter/ArtworkFilterHelpers"
import {
SavedSearchEntity,
Expand Down Expand Up @@ -44,19 +44,23 @@ export interface BrowseSimilarWorksProps {
const BrowseSimilarWorks: React.FC<{ artwork: BrowseSimilarWorks_artwork$key }> = (props) => {
const artwork = useFragment(similarWorksFragment, props.artwork)

const artworkAlertProps = useComputeArtworkAlertProps(artwork)

if (!artwork.isEligibleToCreateAlert) {
return null
}

const artworkAlert = computeArtworkAlertProps(artwork)

const params: BrowseSimilarWorksProps = {
aggregations: artworkAlert.aggregations!,
attributes: artworkAlert.attributes!,
entity: artworkAlert.entity!,
if (!artworkAlertProps) {
return null
}

return <BrowseSimilarWorksContent params={params} />
return (
<BrowseSimilarWorksContent
attributes={artworkAlertProps?.attributes}
aggregations={artworkAlertProps?.aggregations}
entity={artworkAlertProps?.entity}
/>
)
}

export const BrowseSimilarWorksQueryRenderer: React.FC<{ artworkID: string }> = withSuspense(
Expand All @@ -69,7 +73,7 @@ export const BrowseSimilarWorksQueryRenderer: React.FC<{ artworkID: string }> =
return <BrowseSimilarWorksErrorState />
}

return <BrowseSimilarWorks artwork={data.artwork!} />
return <BrowseSimilarWorks artwork={data.artwork} />
},
BrowseSimilarWorksPlaceholder
)
Expand All @@ -84,6 +88,13 @@ const similarWorksFragment = graphql`
internalID
name
}
artistSeriesConnection(first: 5) {
edges {
node {
slug
}
}
}
attributionClass {
internalID
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,11 @@ import { graphql, useLazyLoadQuery } from "react-relay"

const NUMBER_OF_ARTWORKS_TO_SHOW = 10

export interface BrowseSimilarWorksContentProps {
params: BrowseSimilarWorksProps
}

export const BrowseSimilarWorksContent: React.FC<BrowseSimilarWorksContentProps> = (props) => {
const { params } = props
const { attributes, aggregations, entity } = params
export const BrowseSimilarWorksContent: React.FC<BrowseSimilarWorksProps> = ({
attributes,
aggregations,
entity,
}) => {
const { localizedUnit } = useLocalizedUnit()
const { space } = useTheme()
const { bottom: bottomInset } = useSafeAreaInsets()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ describe("EditSavedSearchAlert", () => {

expect(screen.getAllByTestId("alert-pill").map(extractText)).toEqual([
"name-1",
"Monkeys",
"Lithograph",
"Paper",
])
Expand Down
15 changes: 15 additions & 0 deletions src/app/Scenes/SavedSearchAlert/pillExtractors.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { toTitleCase } from "@artsy/to-title-case"
import {
aggregationForFilter,
Aggregations,
Expand Down Expand Up @@ -156,6 +157,16 @@ export const extractAdditionalGeneIDsPills = (values: string[]): SavedSearchPill
})
}

export const extractPillFromArtistSeriesIDs = (values: string[]): SavedSearchPill[] => {
return values.map((value) => {
return {
label: toTitleCase(value.replaceAll("-", " ")),
Copy link
Contributor Author

@olerichter00 olerichter00 Dec 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't ideal, but it should be good enough for now. We have already moved the pill/label generation to Metaphysics and will remove this code soon in favor of using the backend-generated labels.

Because of this, I have decided not to write any additional code to make the name of the artist series accessible here and use this quick workaround until removing this code.

Screenshot 2023-12-08 at 12 30 02

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with this, let's push to work on the migration asap.
A small adjustment I would suggest here is to rename values to slugs and also value to slug. It would be nice to rename the method as well since you are querying for slugs instead of ids but I will leave that to you to decide since we do the same thing in other areas

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, do you mind if you add a test for this as we do for other existing extractors

value,
paramName: SearchCriteria.artistSeriesIDs,
}
})
}

export const extractPriceRangePill = (value: string): SavedSearchPill => {
const { min, max } = parseRange(value)

Expand Down Expand Up @@ -239,6 +250,10 @@ export const extractPillsFromCriteria = (
return extractAdditionalGeneIDsPills(paramValue)
}

if (paramName === SearchCriteria.artistSeriesIDs) {
return extractPillFromArtistSeriesIDs(paramValue)
}

// Extract label from aggregations
if (shouldExtractValueNamesFromAggregation.includes(paramName)) {
return extractPillFromAggregation(paramName, paramValue, aggregations)
Expand Down