Skip to content

Commit b829573

Browse files
lariciamotahellofannylucasfp13ommeirellesartursantiago
committed
feat: Delivery Promise 2.1 - filters by dynamic estimate (#2959)
Feature branch for the Delivery Promise feature - phase 2.1 - filters by dynamic estimate. - #2958 - #2963 <!--- Tell us the role of the new feature, or component, in its context. Provide details about what you have implemented and screenshots if applicable. ---> <!--- Describe the steps with bullet points. Is there any external link that can be used to better test it or an example? ---> <!--- Add a link to a deploy preview from `starter.store` with this branch being used. ---> <!--- Tip: You can get an installable version of this branch from the CodeSandbox generated when this PR is created. ---> - [Jira epic](https://vtex-dev.atlassian.net/browse/SFS-2294) **Documentation** - [ ] For documentation changes, ping `@Mariana-Caetano` to review and update (Or submit a doc request) --------- Co-authored-by: Fanny Chien <[email protected]> Co-authored-by: Lucas Feijó <[email protected]> Co-authored-by: Fanny Chien <[email protected]> Co-authored-by: Otavio Moreira Meirelles <[email protected]> Co-authored-by: Artur Santiago <[email protected]>
1 parent 34530b3 commit b829573

File tree

10 files changed

+320
-121
lines changed

10 files changed

+320
-121
lines changed

packages/components/src/molecules/ToggleField/ToggleField.tsx

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { ChangeEventHandler } from 'react'
12
import React, { forwardRef } from 'react'
23
import { Label, SROnly, Toggle, type ToggleProps } from './../../'
34

@@ -26,6 +27,14 @@ export interface ToggleFieldProps extends ToggleProps {
2627
* Controls the component's direction.
2728
*/
2829
variant?: 'horizontal' | 'vertical'
30+
/**
31+
* Specifies if the input is checked or not.
32+
*/
33+
checked?: boolean
34+
/**
35+
* Function that is triggered when any children is checked.
36+
*/
37+
onChange?: ChangeEventHandler<HTMLInputElement>
2938
}
3039

3140
const ToggleField = forwardRef<HTMLDivElement, ToggleFieldProps>(
@@ -43,7 +52,13 @@ const ToggleField = forwardRef<HTMLDivElement, ToggleFieldProps>(
4352
) {
4453
return (
4554
<div ref={ref} data-fs-toggle-field data-testid={testId}>
46-
<Toggle id={id} variant={variant} disabled={disabled} {...otherProps} />
55+
<Toggle
56+
id={id}
57+
variant={variant}
58+
disabled={disabled}
59+
data-testid={`${testId}-toggle`}
60+
{...otherProps}
61+
/>
4762
{displayLabel ? (
4863
<Label data-fs-toggle-field-label htmlFor={id}>
4964
{label}

packages/components/src/organisms/Filter/FilterFacetBooleanItem.tsx

Lines changed: 47 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { ReactNode } from 'react'
22
import React from 'react'
3-
import { Badge, Checkbox, Label, RadioField } from '../..'
3+
import { Badge, Checkbox, Label, RadioField, ToggleField } from '../..'
44
import type { OnFacetChange } from './Filter'
55

66
export interface FilterFacetBooleanItemProps {
@@ -39,7 +39,7 @@ export interface FilterFacetBooleanItemProps {
3939
/**
4040
* Type of the Facet Item.
4141
*/
42-
type?: 'checkbox' | 'radio'
42+
type?: 'checkbox' | 'radio' | 'toggle'
4343
}
4444

4545
function FilterFacetBooleanItem({
@@ -53,28 +53,32 @@ function FilterFacetBooleanItem({
5353
type = 'checkbox',
5454
onFacetChange,
5555
}: FilterFacetBooleanItemProps) {
56-
return (
57-
<li key={id} data-fs-filter-list-item>
58-
{type === 'checkbox' ? (
59-
<>
60-
<Checkbox
61-
id={id}
62-
checked={selected}
63-
onChange={() => onFacetChange({ key: facetKey, value }, 'BOOLEAN')}
64-
data-fs-filter-list-item-checkbox
65-
data-testid={`${testId}-accordion-panel-checkbox`}
66-
data-value={value}
67-
data-quantity={quantity}
68-
/>
69-
<Label
70-
htmlFor={id}
71-
className="text__title-mini-alt"
72-
data-fs-filter-list-item-label
73-
>
74-
{label} <Badge data-fs-filter-list-item-badge>{quantity}</Badge>
75-
</Label>
76-
</>
77-
) : (
56+
if (type === 'checkbox') {
57+
return (
58+
<li key={id} data-fs-filter-list-item>
59+
<Checkbox
60+
id={id}
61+
checked={selected}
62+
onChange={() => onFacetChange({ key: facetKey, value }, 'BOOLEAN')}
63+
data-fs-filter-list-item-checkbox
64+
data-testid={`${testId}-accordion-panel-checkbox`}
65+
data-value={value}
66+
data-quantity={quantity}
67+
/>
68+
<Label
69+
htmlFor={id}
70+
className="text__title-mini-alt"
71+
data-fs-filter-list-item-label
72+
>
73+
{label} <Badge data-fs-filter-list-item-badge>{quantity}</Badge>
74+
</Label>
75+
</li>
76+
)
77+
}
78+
79+
if (type === 'radio') {
80+
return (
81+
<li key={id} data-fs-filter-list-item>
7882
<RadioField
7983
id={id}
8084
name={facetKey}
@@ -86,9 +90,25 @@ function FilterFacetBooleanItem({
8690
data-value={value}
8791
label={label}
8892
/>
89-
)}
90-
</li>
91-
)
93+
</li>
94+
)
95+
}
96+
97+
if (type === 'toggle') {
98+
return (
99+
<li key={id} data-fs-filter-list-item>
100+
<ToggleField
101+
id={id}
102+
label={label as string}
103+
checked={selected}
104+
onChange={() => onFacetChange({ key: facetKey, value }, 'BOOLEAN')}
105+
testId={`${testId}-accordion-panel-toggle-field`}
106+
/>
107+
</li>
108+
)
109+
}
110+
111+
return null
92112
}
93113

94114
export default FilterFacetBooleanItem

packages/components/src/organisms/Filter/FilterFacets.tsx

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,15 @@ export interface FilterFacetsProps {
1717
/**
1818
* The text displayed to identify the Facet.
1919
*/
20-
label: string
20+
label?: string
2121
/**
2222
* The description displayed to identify the Facet.
2323
*/
2424
description?: string
25+
/**
26+
* Defines if the facet should be highlighted, it will not be displayed as an accordion button and will be expanded (not collapsible).
27+
*/
28+
highlighted?: boolean
2529
}
2630

2731
function FilterFacets({
@@ -31,6 +35,7 @@ function FilterFacets({
3135
children,
3236
type,
3337
description,
38+
highlighted,
3439
}: PropsWithChildren<FilterFacetsProps>) {
3540
return (
3641
<AccordionItem
@@ -40,16 +45,25 @@ function FilterFacets({
4045
index={index}
4146
data-type={type}
4247
data-fs-filter-accordion-item
48+
data-fs-filter-accordion-item-highlighted={highlighted}
4349
>
44-
<AccordionButton testId={`${testId}-accordion-button`}>
45-
{label}
46-
</AccordionButton>
47-
<AccordionPanel>
48-
{description && (
49-
<span data-fs-filter-accordion-item-description>{description}</span>
50-
)}
51-
{children}
52-
</AccordionPanel>
50+
{highlighted ? (
51+
<>{children}</>
52+
) : (
53+
<>
54+
<AccordionButton testId={`${testId}-accordion-button`}>
55+
{label}
56+
</AccordionButton>
57+
<AccordionPanel>
58+
{description && (
59+
<span data-fs-filter-accordion-item-description>
60+
{description}
61+
</span>
62+
)}
63+
{children}
64+
</AccordionPanel>
65+
</>
66+
)}
5367
</AccordionItem>
5468
)
5569
}

packages/core/cms/faststore/content-types.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,27 @@
255255
"default": "All delivery options"
256256
}
257257
}
258+
},
259+
"dynamicEstimate": {
260+
"title": "PLP/Search Filter: Dynamic Estimate",
261+
"type": "object",
262+
"properties": {
263+
"enabled": {
264+
"title": "Should display Dynamic Estimate?",
265+
"type": "boolean",
266+
"default": true
267+
},
268+
"sameDay": {
269+
"title": "Same Day label",
270+
"type": "string",
271+
"default": "Receive Today"
272+
},
273+
"nextDay": {
274+
"title": "Next Day label",
275+
"type": "string",
276+
"default": "Receive Tomorrow"
277+
}
278+
}
258279
}
259280
}
260281
}

packages/core/src/components/search/Filter/FilterDesktop.tsx

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ interface FilterDesktopProps
3232

3333
function FilterDesktop({
3434
facets,
35-
testId,
35+
testId = 'filter-desktop',
3636
dispatch,
3737
expanded,
3838
title,
@@ -46,12 +46,14 @@ function FilterDesktop({
4646
} = useSearch()
4747
const { openRegionSlider } = useUI()
4848
const {
49-
facets: filteredFacets,
49+
highlightedFacet,
50+
facetsWithoutHighlightedFacet,
5051
deliveryLabel,
5152
deliveryOptionsLabel,
5253
isPickupAllEnabled,
5354
shouldDisplayDeliveryButton,
5455
onDeliveryFacetChange,
56+
getDynamicEstimateLabel,
5557
} = useDeliveryPromise({
5658
allFacets: facets,
5759
selectedFilterFacets: searchState.selectedFacets,
@@ -89,7 +91,35 @@ function FilterDesktop({
8991
</UIFilterFacets>
9092
)}
9193

92-
{filteredFacets.map((facet, idx) => {
94+
{highlightedFacet &&
95+
highlightedFacet.__typename === 'StoreFacetBoolean' && (
96+
<UIFilterFacets
97+
key={`${testId}-${highlightedFacet.key}`}
98+
testId={testId}
99+
highlighted
100+
type={highlightedFacet.__typename}
101+
index={undefined}
102+
>
103+
{highlightedFacet.values.map((item) => (
104+
<UIFilterFacetBooleanItem
105+
key={`${testId}-${highlightedFacet.label}-${item.value}`}
106+
id={`${testId}-${highlightedFacet.label}-${item.value}`}
107+
testId={testId}
108+
onFacetChange={(facet) => {
109+
onDeliveryFacetChange({ facet })
110+
resetInfiniteScroll(0)
111+
}}
112+
selected={item.selected}
113+
value={item.value}
114+
facetKey={highlightedFacet.key}
115+
label={getDynamicEstimateLabel(item.value) ?? item.label}
116+
type="toggle"
117+
/>
118+
))}
119+
</UIFilterFacets>
120+
)}
121+
122+
{facetsWithoutHighlightedFacet.map((facet, idx) => {
93123
const index = shouldDisplayDeliveryButton ? idx + 1 : idx
94124
const { __typename: type, label } = facet
95125
const isExpanded = expanded.has(index)

packages/core/src/components/search/Filter/FilterSlider.tsx

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,14 @@ function FilterSlider({
101101
const { deliveryPromise: deliveryPromiseSettings } = cmsData ?? {}
102102

103103
const {
104-
facets: filteredFacets,
104+
highlightedFacet,
105+
facetsWithoutHighlightedFacet,
105106
deliveryLabel,
106107
deliveryOptionsLabel,
107108
isPickupAllEnabled,
108109
shouldDisplayDeliveryButton,
109110
onDeliveryFacetChange,
111+
getDynamicEstimateLabel,
110112
} = useDeliveryPromise({
111113
selectedFilterFacets: selected,
112114
allFacets: facets,
@@ -186,7 +188,35 @@ function FilterSlider({
186188
</UIFilterFacets>
187189
)}
188190

189-
{filteredFacets.map((facet, idx) => {
191+
{highlightedFacet &&
192+
highlightedFacet.__typename === 'StoreFacetBoolean' && (
193+
<UIFilterFacets
194+
key={`${testId}-${highlightedFacet.key}`}
195+
testId={testId}
196+
highlighted
197+
type={highlightedFacet.__typename}
198+
index={undefined}
199+
>
200+
{highlightedFacet.values.map((item) => (
201+
<UIFilterFacetBooleanItem
202+
key={`${testId}-${highlightedFacet.label}-${item.value}`}
203+
id={`${testId}-${highlightedFacet.label}-${item.value}`}
204+
testId={testId}
205+
onFacetChange={(facet) => {
206+
onDeliveryFacetChange({ facet })
207+
resetInfiniteScroll(0)
208+
}}
209+
selected={item.selected}
210+
value={item.value}
211+
facetKey={highlightedFacet.key}
212+
label={getDynamicEstimateLabel(item.value) ?? item.label}
213+
type="toggle"
214+
/>
215+
))}
216+
</UIFilterFacets>
217+
)}
218+
219+
{facetsWithoutHighlightedFacet.map((facet, idx) => {
190220
const index = shouldDisplayDeliveryButton ? idx + 1 : idx
191221
const { __typename: type, label } = facet
192222
const isExpanded = expanded.has(index)

packages/core/src/components/search/Filter/section.module.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
@import "@faststore/ui/src/components/molecules/Modal/styles.scss";
1515
@import "@faststore/ui/src/components/molecules/RadioField/styles.scss";
1616
@import "@faststore/ui/src/components/molecules/SelectField/styles.scss";
17+
@import "@faststore/ui/src/components/molecules/Toggle/styles.scss";
18+
@import "@faststore/ui/src/components/molecules/ToggleField/styles.scss";
1719
@import "@faststore/ui/src/components/organisms/Filter/styles.scss";
1820
@import "@faststore/ui/src/components/organisms/FilterSlider/styles.scss";
1921
@import "@faststore/ui/src/components/organisms/PriceRange/styles.scss";

0 commit comments

Comments
 (0)