Skip to content

Commit

Permalink
feat(ONYX-380): add colours filter to saved searches (#9413)
Browse files Browse the repository at this point in the history
* feat: create new artwork filter store

* minor: separate filter data type

* feat: add filters screen wrapper

* feat: prepare your filters section

* refactor: move screen to savesearches directory

* feat: wrap the screen with the new artwork filters store

* feat: add rarity filter functionality

* chore: improve UX of selecting pills 👌

* chore: add rarity options tests

* chore: minor integrity test improvement

* fix: useDebounce logic in pill

* feat: display the applied filters on your filters

* feat: add remove filter action

* chore: add note to make sure to implement clear all

* feat: add your filters tests

* feat: add clear all button

* chore: add subtle animations: bring the screen to life

* fix: revert disabled logic in clear all button

* chore: remove commented line

* chore: remove unused fields from store

* refact: use SavedSearchStore for ClearAllButton

* refactor: update Applied fitlers to use SavedSearchStore

* chore: do not allow artistIDs pills removal

* chore: do not count artistIDs for clear all button counts

* refactor: use SavedSearchStoreProvider for rarity

* refactor: remove new filters store

* fix: rarity filter test

* chore: address review comments

* feat: add color filtering

* chore: address review comments
  • Loading branch information
MounirDhahri authored Oct 12, 2023
1 parent f580fb5 commit 0e9b4cd
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 1 deletion.
11 changes: 10 additions & 1 deletion src/app/Components/ArtworkFilter/Filters/ColorsOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,16 @@ export const COLORS_INDEXED_BY_VALUE = COLORS.reduce(
{}
)

const SWATCHES_PER_ROW = 4
export const COLOR_OPTIONS: FilterData[] = COLORS.map((color) => {
return {
// names returned by Metaphysics are actually the slugs
displayText: color.name,
paramValue: color.value,
paramName: FilterParamName.colors,
}
})

export const SWATCHES_PER_ROW = 4

type ColorsOptionsScreenProps = StackScreenProps<
ArtworkFilterNavigationStack,
Expand Down
1 change: 1 addition & 0 deletions src/app/Components/ArtworkFilter/Filters/ColorsSwatch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export const ColorsSwatch: React.FC<ColorsSwatchProps> = ({
height="18px"
marginTop="-9px"
marginLeft="-9px"
testID={`check-icon-${name}`}
fill={foregroundColor as any} // Annoying
/>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { OwnerType } from "@artsy/cohesion"
import { fireEvent, waitFor } from "@testing-library/react-native"
import {
COLORS_INDEXED_BY_VALUE,
COLOR_OPTIONS,
} from "app/Components/ArtworkFilter/Filters/ColorsOptions"
import { SavedSearchFilterColour } from "app/Scenes/SavedSearchAlert/Components/SavedSearchFilterColour"
import {
SavedSearchModel,
SavedSearchStoreProvider,
savedSearchModel,
} from "app/Scenes/SavedSearchAlert/SavedSearchStore"
import { renderWithWrappers } from "app/utils/tests/renderWithWrappers"

describe("SavedSearchFilterColour", () => {
it("shows all available color options unselected", () => {
const { getByTestId } = renderWithWrappers(
<SavedSearchStoreProvider runtimeModel={initialData}>
<SavedSearchFilterColour />
</SavedSearchStoreProvider>
)

COLOR_OPTIONS.forEach((option) => {
expect(() =>
getByTestId(`check-icon-${COLORS_INDEXED_BY_VALUE[option.paramValue as string].name}`)
).toThrow()
})
})

it("shows the right selected state", () => {
const { getByTestId } = renderWithWrappers(
<SavedSearchStoreProvider runtimeModel={{ ...initialData, attributes: { colors: ["red"] } }}>
<SavedSearchFilterColour />
</SavedSearchStoreProvider>
)

COLOR_OPTIONS.forEach((option) => {
if (option.paramValue !== "red") {
expect(() =>
getByTestId(`check-icon-${COLORS_INDEXED_BY_VALUE[option.paramValue as string].name}`)
).toThrow()
} else {
expect(
getByTestId(`check-icon-${COLORS_INDEXED_BY_VALUE[option.paramValue as string].name}`)
).toBeDefined()
}
})
})

it("Updates selected filters on press", () => {
const { getByTestId, getByText } = renderWithWrappers(
<SavedSearchStoreProvider runtimeModel={initialData}>
<SavedSearchFilterColour />
</SavedSearchStoreProvider>
)

fireEvent(getByText("Red"), "onPress")

waitFor(() => {
expect(getByTestId("check-icon-Red")).toBeDefined()
})
})
})

const initialData: SavedSearchModel = {
...savedSearchModel,
attributes: {
atAuction: true,
},
entity: {
artists: [{ id: "artistID", name: "Banksy" }],
owner: {
type: OwnerType.artist,
id: "ownerId",
slug: "ownerSlug",
},
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { Flex, Spacer, Text, useScreenDimensions, useSpace } from "@artsy/palette-mobile"
import {
COLORS_INDEXED_BY_VALUE,
COLOR_OPTIONS,
SWATCHES_PER_ROW,
} from "app/Components/ArtworkFilter/Filters/ColorsOptions"
import { ColorsSwatch } from "app/Components/ArtworkFilter/Filters/ColorsSwatch"
import { SearchCriteria } from "app/Components/ArtworkFilter/SavedSearch/types"
import { SavedSearchStore } from "app/Scenes/SavedSearchAlert/SavedSearchStore"
import { isValueSelected, useSearchCriteriaAttributes } from "app/Scenes/SavedSearchAlert/helpers"

export const SavedSearchFilterColour = () => {
const selectedAttributes = useSearchCriteriaAttributes(SearchCriteria.colors) as string[]

const { width } = useScreenDimensions()
const space = useSpace()

const setValueToAttributesByKeyAction = SavedSearchStore.useStoreActions(
(actions) => actions.setValueToAttributesByKeyAction
)
const removeValueFromAttributesByKeyAction = SavedSearchStore.useStoreActions(
(actions) => actions.removeValueFromAttributesByKeyAction
)

const handlePress = (value: string) => {
const isSelected = isValueSelected({
selectedAttributes,
value: value,
})

if (isSelected) {
removeValueFromAttributesByKeyAction({
key: SearchCriteria.colors,
value: value,
})
} else {
const newValues = (selectedAttributes || []).concat(value)
setValueToAttributesByKeyAction({
key: SearchCriteria.colors,
value: newValues,
})
}
}

return (
<Flex>
<Text px={2} variant="sm" fontWeight={500}>
Colour
</Text>

<Spacer y={1} />

<Flex flexDirection="row" flexWrap="wrap" px={1}>
{COLOR_OPTIONS.map((option, i) => {
const color = COLORS_INDEXED_BY_VALUE[String(option.paramValue)]

return (
<ColorsSwatch
key={i}
width={(width - space(1) * 2) / SWATCHES_PER_ROW}
selected={isValueSelected({
selectedAttributes,
value: option.paramValue,
})}
name={color.name}
backgroundColor={color.backgroundColor}
foregroundColor={color.foregroundColor}
onPress={() => {
handlePress(option.paramValue as string)
}}
/>
)
})}
</Flex>
</Flex>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ export const SavedSearchRarity = () => {
<Text variant="sm" fontWeight={500}>
Rarity
</Text>

<Spacer y={1} />

<Flex flexDirection="row" flexWrap="wrap">
{ATTRIBUTION_CLASS_OPTIONS.map((option) => {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useNavigation } from "@react-navigation/native"
import { SearchCriteria } from "app/Components/ArtworkFilter/SavedSearch/types"
import { FancyModalHeader } from "app/Components/FancyModal/FancyModalHeader"
import { SavedSearchAppliedFilters } from "app/Scenes/SavedSearchAlert/Components/SavedSearchFilterAppliedFilters"
import { SavedSearchFilterColour } from "app/Scenes/SavedSearchAlert/Components/SavedSearchFilterColour"
import { SavedSearchRarity } from "app/Scenes/SavedSearchAlert/Components/SavedSearchFilterRarity"
import { SavedSearchStore } from "app/Scenes/SavedSearchAlert/SavedSearchStore"
import { MotiView } from "moti"
Expand All @@ -24,6 +25,7 @@ export const SavedSearchFilterScreen: React.FC<{}> = () => {
<Join separator={<Separator my={2} borderColor="black10" />}>
<SavedSearchAppliedFilters />
<SavedSearchRarity />
<SavedSearchFilterColour />
</Join>
</Flex>
)
Expand Down

0 comments on commit 0e9b4cd

Please sign in to comment.