Skip to content

Commit 6dfa85a

Browse files
committed
feat: Filter by shipping method delivery when dynamic estimate is selected (#3056)
## What's the purpose of this pull request? Filter by shipping method `delivery` when dynamic estimate is selected, so the products that are only for pickup in that dynamic estimate aren't returned. ## How it works? The following behaviors were introduced: - When selecting a dynamic estimate, the IS request will be built with the shipping method `delivery` - When selecting a dynamic estimate, the shipping method facets will be hidden for UX purposes - When deselecting a dynamic estimate, the shipping method facets will be displayed again - When deselecting a dynamic estimate, there won't be any shipping method facet selected - unless there is a global pickup point, in that case the pickup point will be selected. ## How to test it? In PLP/Search, use the dynamic estimate filter and note that the request to IS includes the shipping method delivery also. Test switching the DE toggle and using the shipping method filter when the toggle is deselected. Test also with and without a global pickup point. Examples: | 0 DE selected | 1 DE selected | 2 DE selected | | ---- | ---- | ---- | | <img width="1507" height="808" alt="Screenshot 2025-09-25 at 11 08 33" src="https://github.com/user-attachments/assets/346f2590-dabb-4cf5-ad5a-fbeef6583448" /> | <img width="1505" height="803" alt="Screenshot 2025-09-25 at 15 16 39" src="https://github.com/user-attachments/assets/90b6480e-0c53-4949-a4a1-a7be89d17930" /> | <img width="1502" height="800" alt="Screenshot 2025-09-25 at 15 17 24" src="https://github.com/user-attachments/assets/62c5d9ff-21b4-44d8-9727-8188a8f2f9c3" /> | | Note that the shipping method filters are displayed and there is no shipping method being sent to IS | Note that the shipping method filters aren't displayed and the `delivery` shipping method is sent to IS | | ### Starters Deploy Preview - PR: dp-faststore-org/vendemo-dp#100 - Preview: https://vendemo-cm9sir9v900u7z6llkl62l70j-78q3ujoh1.b.vtex.app/ ## References - [Jira task](https://vtex-dev.atlassian.net/browse/SFS-2767) - Slack threads ([[1](https://vtex.slack.com/archives/C069YM7R73P/p1758305111679099)], [[2](https://vtex.slack.com/archives/C08SZUBMFDK/p1758724584686339)])
1 parent ee63e58 commit 6dfa85a

File tree

2 files changed

+91
-24
lines changed

2 files changed

+91
-24
lines changed

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,10 @@ function FilterSlider({
204204
id={`${testId}-${highlightedFacet.label}-${item.value}`}
205205
testId={testId}
206206
onFacetChange={(facet) => {
207-
onDeliveryFacetChange({ facet })
208-
resetInfiniteScroll(0)
207+
onDeliveryFacetChange({
208+
facet,
209+
filterDispatch: dispatch,
210+
})
209211
}}
210212
selected={item.selected}
211213
value={item.value}

packages/core/src/sdk/deliveryPromise/useDeliveryPromise.ts

Lines changed: 87 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,13 @@ export const ALL_DELIVERY_OPTIONS_FACET_VALUE = 'all-delivery-options' as const
3333
export const DELIVERY_OPTIONS_FACET_KEY = 'delivery-options' as const
3434
export const DYNAMIC_ESTIMATE_FACET_KEY = 'dynamic-estimate' as const
3535
export const IN_STOCK_FACET_KEY = 'in-stock' as const
36+
const DELIVERY_TYPE_DELIVERY = 'delivery' as const
37+
const DELIVERY_TYPE_PICKUP_IN_POINT = 'pickup-in-point' as const
3638

3739
type Facet = SearchState['selectedFacets'][number]
38-
type DeliveryType = 'delivery' | 'pickup-in-point'
40+
type DeliveryType =
41+
| typeof DELIVERY_TYPE_DELIVERY
42+
| typeof DELIVERY_TYPE_PICKUP_IN_POINT
3943

4044
export type PickupPoint = {
4145
id: string
@@ -131,6 +135,15 @@ export function useDeliveryPromise({
131135
[selectedFacets]
132136
)
133137

138+
const generateGlobalPickupPointFacets = useCallback((): Facet[] => {
139+
if (!globalPickupPoint) return []
140+
141+
return [
142+
{ key: SHIPPING_FACET_KEY, value: PICKUP_IN_POINT_FACET_VALUE },
143+
{ key: PICKUP_POINT_FACET_KEY, value: globalPickupPoint.id },
144+
]
145+
}, [globalPickupPoint])
146+
134147
// Update Delivery Promise global state after store changes
135148
useEffect(() => {
136149
const unsubscribers = [
@@ -168,13 +181,7 @@ export function useDeliveryPromise({
168181
setSearchState({
169182
selectedFacets: toggleFacets(
170183
selectedFacets,
171-
[
172-
{ key: SHIPPING_FACET_KEY, value: PICKUP_IN_POINT_FACET_VALUE },
173-
{
174-
key: PICKUP_POINT_FACET_KEY,
175-
value: globalPickupPoint.id,
176-
},
177-
],
184+
generateGlobalPickupPointFacets(),
178185
true
179186
),
180187
page: 0,
@@ -298,6 +305,47 @@ export function useDeliveryPromise({
298305
facetsToToggle.concat(currentSelectedFacets)
299306
}
300307

308+
// Auto-select/deselect delivery shipping method when dynamic estimate is toggled
309+
if (facet?.key === DYNAMIC_ESTIMATE_FACET_KEY && facet?.value) {
310+
const shippingFacets = currentSelectedFacets.filter(
311+
({ key }) => key === SHIPPING_FACET_KEY
312+
)
313+
const isDeliveryShippingSelected = shippingFacets.some(
314+
({ value }) => value === DELIVERY_TYPE_DELIVERY
315+
)
316+
const isCurrentDynamicEstimateSelected = currentSelectedFacets.some(
317+
({ key, value }) =>
318+
key === DYNAMIC_ESTIMATE_FACET_KEY && value === facet.value
319+
)
320+
321+
// If dynamic estimate is being selected and delivery shipping is not selected, select it
322+
if (!isCurrentDynamicEstimateSelected && !isDeliveryShippingSelected) {
323+
facetsToToggle.push(...shippingFacets, {
324+
key: SHIPPING_FACET_KEY,
325+
value: DELIVERY_TYPE_DELIVERY,
326+
})
327+
}
328+
// If dynamic estimate is being deselected and delivery shipping is selected, handle shipping method state
329+
else if (
330+
isCurrentDynamicEstimateSelected &&
331+
isDeliveryShippingSelected
332+
) {
333+
const otherDynamicEstimates = currentSelectedFacets.filter(
334+
({ key, value }) =>
335+
key === DYNAMIC_ESTIMATE_FACET_KEY && value !== facet.value
336+
)
337+
338+
// Only remove delivery shipping if no other dynamic estimates will remain active
339+
if (otherDynamicEstimates.length === 0) {
340+
facetsToToggle.push(...shippingFacets)
341+
342+
if (globalPickupPoint) {
343+
facetsToToggle.push(...generateGlobalPickupPointFacets())
344+
}
345+
}
346+
}
347+
}
348+
301349
// Filter Slider should dispatch filter actions
302350
if (filterDispatch) {
303351
filterDispatch({
@@ -317,7 +365,12 @@ export function useDeliveryPromise({
317365
page: 0,
318366
})
319367
},
320-
[selectedFacets, defaultPickupPoint]
368+
[
369+
selectedFacets,
370+
defaultPickupPoint,
371+
globalPickupPoint,
372+
generateGlobalPickupPointFacets,
373+
]
321374
)
322375

323376
const facets = useMemo(() => {
@@ -443,13 +496,23 @@ export function useDeliveryPromise({
443496
return facets.find((facet) => facet.key === DYNAMIC_ESTIMATE_FACET_KEY)
444497
}, [facets, isDynamicEstimateEnabled])
445498

446-
const facetsWithoutHighlightedFacet = useMemo(
447-
() =>
448-
highlightedFacet
449-
? facets.filter((facet) => facet.key !== DYNAMIC_ESTIMATE_FACET_KEY)
450-
: facets,
451-
[facets, highlightedFacet]
452-
)
499+
const facetsWithoutHighlightedFacet = useMemo(() => {
500+
let facetsWithoutHighlight = highlightedFacet
501+
? facets.filter((facet) => facet.key !== DYNAMIC_ESTIMATE_FACET_KEY)
502+
: facets
503+
504+
// Hide shipping facet when dynamic estimate facet is selected to improve the user experience
505+
const isDynamicEstimateSelected = selectedFacets.some(
506+
({ key }) => key === DYNAMIC_ESTIMATE_FACET_KEY
507+
)
508+
if (isDynamicEstimateSelected) {
509+
facetsWithoutHighlight = facetsWithoutHighlight.filter(
510+
(facet) => facet.key !== SHIPPING_FACET_KEY
511+
)
512+
}
513+
514+
return facetsWithoutHighlight
515+
}, [facets, highlightedFacet, selectedFacets])
453516

454517
function getDynamicEstimateLabel(value: string) {
455518
if (value === 'next-day') {
@@ -548,29 +611,31 @@ export function useDeliveryPromise({
548611
(badge) => badge.typeName
549612
)
550613

551-
const hasDelivery = availableTypeNames?.includes('delivery')
552-
const hasPickupPoint = availableTypeNames?.includes('pickup-in-point')
614+
const hasDelivery = availableTypeNames?.includes(DELIVERY_TYPE_DELIVERY)
615+
const hasPickupPoint = availableTypeNames?.includes(
616+
DELIVERY_TYPE_PICKUP_IN_POINT
617+
)
553618

554619
if (hasDelivery) {
555620
badges.push({
556-
label: getBadgeLabel('delivery', true),
621+
label: getBadgeLabel(DELIVERY_TYPE_DELIVERY, true),
557622
availability: true,
558623
})
559624
} else {
560625
badges.push({
561-
label: getBadgeLabel('delivery', false),
626+
label: getBadgeLabel(DELIVERY_TYPE_DELIVERY, false),
562627
availability: false,
563628
})
564629
}
565630

566631
if (hasPickupPoint) {
567632
badges.push({
568-
label: getBadgeLabel('pickup-in-point', true),
633+
label: getBadgeLabel(DELIVERY_TYPE_PICKUP_IN_POINT, true),
569634
availability: true,
570635
})
571636
} else {
572637
badges.push({
573-
label: getBadgeLabel('pickup-in-point', false),
638+
label: getBadgeLabel(DELIVERY_TYPE_PICKUP_IN_POINT, false),
574639
availability: false,
575640
})
576641
}

0 commit comments

Comments
 (0)