Skip to content

Commit

Permalink
feat: Price range filter on PLP (#112)
Browse files Browse the repository at this point in the history
  • Loading branch information
tlgimenes authored Jun 19, 2022
1 parent 8d4e5bc commit 9916982
Show file tree
Hide file tree
Showing 23 changed files with 719 additions and 899 deletions.
99 changes: 56 additions & 43 deletions @generated/graphql/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2372,23 +2372,34 @@ export type StoreCurrency = {
symbol: Scalars['String']
}

/** Search facet information. */
export type StoreFacet = {
export type StoreFacet = StoreFacetBoolean | StoreFacetRange

/** Search facet boolean information. */
export type StoreFacetBoolean = {
/** Facet key. */
key: Scalars['String']
/** Facet label. */
label: Scalars['String']
/** Array with information on each facet value. */
values: Array<StoreFacetValueBoolean>
}

/** Search facet range information. */
export type StoreFacetRange = {
/** Facet key. */
key: Scalars['String']
/** Facet label. */
label: Scalars['String']
/** Facet type. Possible values are `BOOLEAN` and `RANGE`. */
type: StoreFacetType
max: StoreFacetValueRange
/** Array with information on each facet value. */
values: Array<StoreFacetValue>
min: StoreFacetValueRange
}

/** Search facet type. */
export type StoreFacetType = 'BOOLEAN' | 'RANGE'

/** Information of a specific facet value. */
export type StoreFacetValue = {
export type StoreFacetValueBoolean = {
/** Facet value label. */
label: Scalars['String']
/** Number of items with this facet. */
Expand All @@ -2399,6 +2410,11 @@ export type StoreFacetValue = {
value: Scalars['String']
}

export type StoreFacetValueRange = {
absolute: Scalars['Float']
selected: Scalars['Float']
}

/** Image. */
export type StoreImage = {
/** Alias for the image. */
Expand Down Expand Up @@ -2669,10 +2685,10 @@ export type ProductSummary_ProductFragment = {
}
}

export type Filter_FacetsFragment = {
export type Filter_Facets_StoreFacetBoolean_Fragment = {
__typename: 'StoreFacetBoolean'
key: string
label: string
type: StoreFacetType
values: Array<{
label: string
value: string
Expand All @@ -2681,6 +2697,18 @@ export type Filter_FacetsFragment = {
}>
}

export type Filter_Facets_StoreFacetRange_Fragment = {
__typename: 'StoreFacetRange'
key: string
label: string
min: { selected: number; absolute: number }
max: { selected: number; absolute: number }
}

export type Filter_FacetsFragment =
| Filter_Facets_StoreFacetBoolean_Fragment
| Filter_Facets_StoreFacetRange_Fragment

export type ProductDetailsFragment_ProductFragment = {
sku: string
name: string
Expand Down Expand Up @@ -2720,42 +2748,27 @@ export type ProductGalleryQueryQueryVariables = Exact<{

export type ProductGalleryQueryQuery = {
search: {
products: {
pageInfo: { totalCount: number }
edges: Array<{
node: {
slug: string
sku: string
name: string
gtin: string
id: string
brand: { name: string; brandName: string }
isVariantOf: { productGroupID: string; name: string }
image: Array<{ url: string; alternateName: string }>
offers: {
lowPrice: number
offers: Array<{
availability: string
price: number
listPrice: number
quantity: number
seller: { identifier: string }
}>
}
products: { pageInfo: { totalCount: number } }
facets: Array<
| {
__typename: 'StoreFacetBoolean'
key: string
label: string
values: Array<{
label: string
value: string
selected: boolean
quantity: number
}>
}
}>
}
facets: Array<{
key: string
label: string
type: StoreFacetType
values: Array<{
label: string
value: string
selected: boolean
quantity: number
}>
}>
| {
__typename: 'StoreFacetRange'
key: string
label: string
min: { selected: number; absolute: number }
max: { selected: number; absolute: number }
}
>
}
}

Expand Down
2 changes: 1 addition & 1 deletion @generated/graphql/persisted.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"ProductGalleryQuery": "query ProductGalleryQuery($first: Int!, $after: String!, $sort: StoreSort!, $term: String!, $selectedFacets: [IStoreSelectedFacet!]!) {\n search(\n first: $first\n after: $after\n sort: $sort\n term: $term\n selectedFacets: $selectedFacets\n ) {\n products {\n pageInfo {\n totalCount\n }\n edges {\n node {\n id: productID\n slug\n sku\n brand {\n brandName: name\n name\n }\n name\n gtin\n isVariantOf {\n productGroupID\n name\n }\n image {\n url\n alternateName\n }\n offers {\n lowPrice\n offers {\n availability\n price\n listPrice\n quantity\n seller {\n identifier\n }\n }\n }\n }\n }\n }\n facets {\n key\n label\n type\n values {\n label\n value\n selected\n quantity\n }\n }\n }\n}\n",
"ProductGalleryQuery": "query ProductGalleryQuery($first: Int!, $after: String!, $sort: StoreSort!, $term: String!, $selectedFacets: [IStoreSelectedFacet!]!) {\n search(\n first: $first\n after: $after\n sort: $sort\n term: $term\n selectedFacets: $selectedFacets\n ) {\n products {\n pageInfo {\n totalCount\n }\n }\n facets {\n ... on StoreFacetRange {\n key\n label\n min {\n selected\n absolute\n }\n max {\n selected\n absolute\n }\n __typename\n }\n ... on StoreFacetBoolean {\n key\n label\n values {\n label\n value\n selected\n quantity\n }\n __typename\n }\n }\n }\n}\n",
"CollectionPageQuery": "query CollectionPageQuery {\n site {\n siteMetadata {\n titleTemplate\n title\n description\n siteUrl\n }\n }\n}\n",
"ServerCollectionPageQuery": "query ServerCollectionPageQuery($slug: String!) {\n collection(slug: $slug) {\n seo {\n title\n description\n }\n breadcrumbList {\n itemListElement {\n item\n name\n position\n }\n }\n meta {\n selectedFacets {\n key\n value\n }\n }\n }\n}\n",
"ProductPageQuery": "query ProductPageQuery {\n site {\n siteMetadata {\n title\n description\n titleTemplate\n siteUrl\n }\n }\n}\n",
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- PriceRange component to PLP and StoryBook ([#112](https://github.com/vtex-sites/gatsby.store/pull/112))
- Applies new local tokens to `EmptyState` ([#113](https://github.com/vtex-sites/gatsby.store/pull/113))
- Applies new local tokens to `Dropdown` ([#111](https://github.com/vtex-sites/gatsby.store/pull/111))
- Creates and styles `Dropdown` component ([#111](https://github.com/vtex-sites/gatsby.store/pull/111))
Expand Down
1 change: 1 addition & 0 deletions codegen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ generates:
skipTypename: true
allowEnumStringTypes: false
namingConvention: 'change-case-all#pascalCase'
exportFragmentSpreadSubTypes: true
plugins:
- typescript
- typescript-operations
Expand Down
4 changes: 3 additions & 1 deletion cypress/integration/plp.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ describe('Search page Filters and Sorting options', () => {
// Apply filters
cy.getById('open-filter-button')
.click()
.getById('mobile-store-filter-accordion-button')
.get(
`[data-testid=mobile-store-filter-accordion-item][data-type=StoreFacetBoolean]>[data-testid=mobile-store-filter-accordion-button]`
)
.first()
.click()
.getById('mobile-store-filter-accordion-panel-checkbox')
Expand Down
3 changes: 1 addition & 2 deletions gatsby-ssr.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { CartProvider, SessionProvider } from '@faststore/sdk'
import { validateSession } from 'src/sdk/session/validate'
import UIProvider from 'src/sdk/ui/Provider'
import type { ReactNode } from 'react'
import type { GatsbySSR } from 'gatsby'

import ThirdPartyScripts from './src/components/ThirdPartyScripts'
Expand Down Expand Up @@ -54,7 +53,7 @@ type StyleComponent = {
}
}

const isStyleComponent = (node: ReactNode): node is StyleComponent =>
const isStyleComponent = (node: any): node is StyleComponent =>
typeof node === 'object' && node != null && (node as any).type === 'style'

/**
Expand Down
17 changes: 8 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,12 @@
"dependencies": {
"@builder.io/partytown": "^0.6.1",
"@envelop/core": "^1.2.0",
"@envelop/graphql-jit": "^1.1.1",
"@envelop/parser-cache": "^2.2.0",
"@envelop/validation-cache": "^2.2.0",
"@faststore/api": "^1.9.7",
"@faststore/graphql-utils": "^1.9.4",
"@faststore/sdk": "^1.9.4",
"@faststore/ui": "^1.9.4",
"@faststore/api": "^1.9.11",
"@faststore/graphql-utils": "^1.9.9",
"@faststore/sdk": "^1.9.11",
"@faststore/ui": "^1.9.11",
"gatsby": "^4.16.0",
"gatsby-plugin-gatsby-cloud": "^4.16.0",
"gatsby-plugin-manifest": "^4.16.0",
Expand All @@ -55,10 +54,10 @@
"devDependencies": {
"@babel/core": "^7.17.8",
"@cypress/code-coverage": "^3.9.10",
"@faststore/lighthouse": "^1.9.4",
"@graphql-codegen/cli": "^2.2.1",
"@graphql-codegen/typescript": "^2.2.4",
"@graphql-codegen/typescript-operations": "^2.1.8",
"@faststore/lighthouse": "^1.9.10",
"@graphql-codegen/cli": "^2.6.2",
"@graphql-codegen/typescript": "^2.5.1",
"@graphql-codegen/typescript-operations": "^2.4.2",
"@lhci/cli": "^0.9.0",
"@netlify/plugin-gatsby": "^2.0.0-beta",
"@storybook/addon-a11y": "^6.5.9",
Expand Down
99 changes: 68 additions & 31 deletions src/components/search/Filter/Facets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,24 @@ import type {
IStoreSelectedFacet,
Filter_FacetsFragment,
} from '@generated/graphql'
import PriceRange from 'src/components/ui/PriceRange'

type OnFacetChange = (
item: IStoreSelectedFacet,
type: 'BOOLEAN' | 'RANGE'
) => void

interface FacetsProps {
testId: string
facets: Filter_FacetsFragment[]
indicesExpanded: Set<number>
onFacetChange: (item: IStoreSelectedFacet) => void
onFacetChange: OnFacetChange
onAccordionChange: (index: number) => void
}

const formatRange = (min: number, max: number) =>
`${min.toFixed(2)}-to-${max.toFixed(2)}`

function Facets({
testId,
facets,
Expand All @@ -26,37 +35,65 @@ function Facets({
<div className="filter" data-store-filter data-testid={testId}>
<h2 className="text__title-mini-alt">Filters</h2>
<Accordion expandedIndices={indicesExpanded} onChange={onAccordionChange}>
{facets.map(({ label, values, key }, index) => (
<AccordionItem
key={`${label}-${index}`}
prefixId={testId}
testId={`${testId}-accordion`}
isExpanded={indicesExpanded.has(index)}
buttonLabel={label}
>
<UIList>
{values.map((item) => {
const id = `${testId}-${label}-${item.label}`
{facets.map((facet, index) => {
const isExpanded = indicesExpanded.has(index)
const { __typename: type, label } = facet

return (
<AccordionItem
key={`${label}-${index}`}
prefixId={testId}
testId={`${testId}-accordion`}
isExpanded={isExpanded}
buttonLabel={label}
data-type={type}
>
{type === 'StoreFacetBoolean' && isExpanded && (
<UIList>
{facet.values.map((item) => {
const id = `${testId}-${facet.label}-${item.label}`

return (
<li key={id} className="filter__item">
<Checkbox
id={id}
checked={item.selected}
onChange={() => onFacetChange({ key, value: item.value })}
data-testid={`${testId}-accordion-panel-checkbox`}
data-value={item.value}
data-quantity={item.quantity}
/>
<UILabel htmlFor={id} className="text__title-mini-alt">
{item.label} <Badge>{item.quantity}</Badge>
</UILabel>
</li>
)
})}
</UIList>
</AccordionItem>
))}
return (
<li key={id} className="filter__item">
<Checkbox
id={id}
checked={item.selected}
onChange={() =>
onFacetChange(
{ key: facet.key, value: item.value },
'BOOLEAN'
)
}
data-testid={`${testId}-accordion-panel-checkbox`}
data-value={item.value}
data-quantity={item.quantity}
/>
<UILabel htmlFor={id} className="text__title-mini-alt">
{item.label} <Badge>{item.quantity}</Badge>
</UILabel>
</li>
)
})}
</UIList>
)}
{type === 'StoreFacetRange' && isExpanded && (
<PriceRange
min={facet.min}
max={facet.max}
onEnd={(v) =>
onFacetChange(
{
key: facet.key,
value: formatRange(v.min, v.max),
},
'RANGE'
)
}
/>
)}
</AccordionItem>
)
})}
</Accordion>
</div>
)
Expand Down
Loading

1 comment on commit 9916982

@vercel
Copy link

@vercel vercel bot commented on 9916982 Jun 19, 2022

Choose a reason for hiding this comment

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

Please sign in to comment.