From 7aae839d1f9f5f647ccca786ca6c7e639e6727f7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lucas=20Feij=C3=B3?=
Date: Wed, 26 Mar 2025 12:17:29 -0300
Subject: [PATCH 01/25] chore: Ensure session with location data (#2745)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This PR intends to ensure all location data (`postalCode`,
`geoCoordinates` and `country`) is being synchronized when needed.
It updates geo coordinates when users set a postal code and ensure
location data won't be overwritten if users grant geo location consent
late.
- Enable Delivery Promise on discovery.config;
- Open the localhost store on anon tab (to ensure no stale data);
- First, consent geo location data from popup and look to the IDB
`fs::session` value, it should fill `geoCoordinates` data after
`useGeolocation` hook execution;
- Then try to set a postal code, the `postalCode` should be set and
`geoCoordinates` should be different now (based on the postal code);
- Another test: open another anon tab and, while the popup asking for
geo location consent set a postal code. Then, after the session is
updated with the new location (based on the postal code), grant the geo
location consent and nothing should happen since user have already set
the postal code.
vtex-sites/starter.store#734
---------
Co-authored-by: Fanny Chien
Co-authored-by: Larícia Mota
---
.../vtex/resolvers/validateSession.ts | 22 +++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/packages/api/src/platforms/vtex/resolvers/validateSession.ts b/packages/api/src/platforms/vtex/resolvers/validateSession.ts
index ea7ca49afd..e9de0ecb9b 100644
--- a/packages/api/src/platforms/vtex/resolvers/validateSession.ts
+++ b/packages/api/src/platforms/vtex/resolvers/validateSession.ts
@@ -31,6 +31,28 @@ async function getPreciseLocationData(
}
}
+async function getGeoCoordinates(
+ clients: Context['clients'],
+ country: string,
+ postalCode: string
+) {
+ try {
+ const address = await clients.commerce.checkout.address({
+ postalCode,
+ country,
+ })
+
+ const [longitude, latitude] = address.geoCoordinates
+ return { latitude, longitude }
+ } catch (err) {
+ console.error(
+ `Error while getting geo coordinates for the current postal code (${postalCode}) and country (${country}).\n`
+ )
+
+ throw err
+ }
+}
+
export const validateSession = async (
_: any,
{ session: oldSession, search }: MutationValidateSessionArgs,
From 3b41490fefbcfc5e20cb30edd22c7b81deffd45e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lucas=20Feij=C3=B3?=
Date: Fri, 11 Apr 2025 11:49:04 -0300
Subject: [PATCH 02/25] feat: Display `city` and `postalCode` (#2772)
This PR intends to display region data (on `RegionButton` and
`RegionBar`) with `city` and `postalCode` information.
For cases when users manually set their zip code, they should see both
city name and zip code:
Otherwise, if a default zip code is set on `discovery.config` and users
do not manually set any zip code, they should see only the city name:
Test both scenarios described in the section above to validate
everything is working and displayed as expected.
vtex-sites/faststoreqa.store#769
---
packages/api/src/platforms/vtex/resolvers/validateSession.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/api/src/platforms/vtex/resolvers/validateSession.ts b/packages/api/src/platforms/vtex/resolvers/validateSession.ts
index e9de0ecb9b..b72ebb77bf 100644
--- a/packages/api/src/platforms/vtex/resolvers/validateSession.ts
+++ b/packages/api/src/platforms/vtex/resolvers/validateSession.ts
@@ -43,7 +43,7 @@ async function getGeoCoordinates(
})
const [longitude, latitude] = address.geoCoordinates
- return { latitude, longitude }
+ return { city: address.city, geoCoordinates: { latitude, longitude } }
} catch (err) {
console.error(
`Error while getting geo coordinates for the current postal code (${postalCode}) and country (${country}).\n`
From c8199b9a3180635700e0098c3eda54fc40eeb0a9 Mon Sep 17 00:00:00 2001
From: Fanny Chien
Date: Thu, 24 Apr 2025 22:05:59 -0300
Subject: [PATCH 03/25] feat: Adds RegionPopover component and handles location
update (#2775)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This PR's aims to cover the following scenarios:
1. When the buyer opens the site to start a session, display
`RegionPopover` when location is optional, no location available and
merchant has default zipCode.
|Desktop|Mobile|
|-|-|
|||
2. When the buyer opens the site to start a session, Display
`RegionPopover` when location is optional and no location available.
|Desktop|Mobile|
|-|-|
||
-Create Popover Component / Popover styles
-Create RegionPopover / styles
-Implements changes of session postalCode in `RegionPopover`
-Creates `useSetLocation` to handle session changes in `RegionModal` and
`RegionPopover`
-Uses `useRegion` to handle setLocation and validation
-Adds `RegionPopover` to `RegionButton` (desktop)
-Adds `RegionPopover` to `RegionBar` (mobile)
-Moves `useOnClickOutside` hook to `faststore/ui`
Run the project locally or use this [preview
link](https://storeframework-cm652ufll028lmgv665a6xv0g-k85hl97mm.b.vtex.app)
In `discovery.config`, sets
```
deliveryPromise: {
enabled: true,
mandatory: false,
},
```
> When the buyer opens the site to start a session, display
RegionPopover when location is optional, no location available and
merchant has default zipCode.
_Clear site data, if there is a previous session that a postalCode is
set_
In `discovery.config`, in the default session, adds a zip code (use
`12121`)
```
session: {
postalCode: '12121',
},
```
1. Refresh the page
2. You will be able to see the RegionPopover with the default zip code
applied.
3. Click outside the Popover and it should disappear.
4. Refresh the page
5. Attempts to change the zip code
6. If you apply a valid zip code, after refreshing the page you
shouldn't able to see the popover anymore.
This should also work in the mobile.
> When the buyer opens the site to start a session, Display
`RegionPopover` when location is optional and no location available.
_Clear site data, if there is a previous session that a postalCode is
set_
In `discovery.config`, in the default session, sets a zip code to `null`
```
session: {
postalCode: null,
},
```
1. Refresh the page
2. You will be able to see the RegionPopover with the default
description and no location applied.
3. Click outside the Popover and it should disappear.
4. Refresh the page
5. Attempts to change the zip code
6. If you apply a valid zip code, after refreshing the page you
shouldn't able to see the popover anymore.
This should also work in the mobile.
_Clear site data, if there is a previous session that a postalCode is
set_
1. In `discovery.config`, changes `mandatory` to `true`.
```
deliveryPromise: {
enabled: true,
mandatory: true,
},
```
2. Refresh the page, the Popover should not appear, instead the
`RegionModal` will appear without the close button.
Also, added `RegionPopover` to Global section in hCMS. `storeframework`
account
You can also test it, changing the texts and see if it's working as
expected.
https://github.com/vtex-sites/faststoreqa.store/pull/777
[Figma](https://www.figma.com/design/Ra4IaKe920E5rkXZkCz1D8/Cubos-–-FastStore-Features-B2C?node-id=226-20785&t=DHxk1r6kytn2lHC2-0)
https://www.w3schools.com/cssref/sel_attr_begin.php
TODO: Request Doc for PopOver
TODO: Remind to run cms sync in the default account when the feature
branch is merged since new section was added.
---------
Co-authored-by: Larícia Mota
Co-authored-by: Lucas Feijó
---
.../region/RegionModal/RegionModal.tsx | 2 +-
.../region/RegionModal/useSetLocation.ts | 71 +++++++++++++++++++
packages/core/src/sdk/ui/useOnClickOutside.ts | 3 -
3 files changed, 72 insertions(+), 4 deletions(-)
create mode 100644 packages/core/src/components/region/RegionModal/useSetLocation.ts
delete mode 100644 packages/core/src/sdk/ui/useOnClickOutside.ts
diff --git a/packages/core/src/components/region/RegionModal/RegionModal.tsx b/packages/core/src/components/region/RegionModal/RegionModal.tsx
index 52e4f09561..c233c3680a 100644
--- a/packages/core/src/components/region/RegionModal/RegionModal.tsx
+++ b/packages/core/src/components/region/RegionModal/RegionModal.tsx
@@ -1,5 +1,5 @@
import dynamic from 'next/dynamic'
-import { useRef, useState } from 'react'
+import { useRef } from 'react'
import type { RegionModalProps as UIRegionModalProps } from '@faststore/ui'
import { Icon, useUI } from '@faststore/ui'
diff --git a/packages/core/src/components/region/RegionModal/useSetLocation.ts b/packages/core/src/components/region/RegionModal/useSetLocation.ts
new file mode 100644
index 0000000000..67d26fccfb
--- /dev/null
+++ b/packages/core/src/components/region/RegionModal/useSetLocation.ts
@@ -0,0 +1,71 @@
+import { useState } from 'react'
+
+import type { Session } from '@faststore/sdk'
+import { sessionStore, validateSession } from 'src/sdk/session'
+
+interface UseSetLocationParams {
+ input: string
+ setInput: (value: string) => void
+ resetInputField: () => void
+ setLocation: (
+ postalCode: string | undefined,
+ inputFieldErrorMessage: string,
+ session: Session,
+ onSuccess?: () => void
+ ) => Promise
+ errorMessage: string
+ setErrorMessage: (value: string) => void
+ loading: boolean
+}
+
+export function useSetLocation(): UseSetLocationParams {
+ const [input, setInput] = useState('')
+ const [errorMessage, setErrorMessage] = useState('')
+ const [loading, setLoading] = useState(false)
+
+ const resetInputField = () => {
+ setInput('')
+ setErrorMessage('')
+ }
+
+ const setLocation = async (
+ postalCode: string | undefined,
+ inputFieldErrorMessage: string,
+ session: Session,
+ onSuccess?: () => void
+ ) => {
+ if (typeof postalCode !== 'string') {
+ return
+ }
+
+ setLoading(true)
+
+ try {
+ const newSession = {
+ ...session,
+ postalCode,
+ geoCoordinates: null, // Revalidate geo coordinates in API when users set a new postal code
+ } as Session
+
+ const validatedSession = await validateSession(newSession)
+
+ sessionStore.set(validatedSession ?? newSession)
+ resetInputField()
+ onSuccess?.() // Execute the post-validation action (close modal, etc.)
+ } catch (error) {
+ setErrorMessage(inputFieldErrorMessage)
+ } finally {
+ setLoading(false) // Reset loading to false when validation is complete
+ }
+ }
+
+ return {
+ input,
+ setInput,
+ resetInputField,
+ setLocation,
+ errorMessage,
+ setErrorMessage,
+ loading,
+ }
+}
diff --git a/packages/core/src/sdk/ui/useOnClickOutside.ts b/packages/core/src/sdk/ui/useOnClickOutside.ts
deleted file mode 100644
index 0daa2f0b0d..0000000000
--- a/packages/core/src/sdk/ui/useOnClickOutside.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-// This hook was moved to the UI package, this export is to avoid breaking changes
-// TODO: remove in the next major release
-export { useOnClickOutside as default } from '@faststore/ui'
From 7b64e2b71af43dcb33971543d938013c393d619d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lucas=20Feij=C3=B3?=
Date: Wed, 30 Apr 2025 15:06:23 -0300
Subject: [PATCH 04/25] feat: Check products availability when setting postal
code (#2817)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This PR intends to handle the scenario when shoppers are setting postal
code and there is no available products for that specific location.
For all Delivery Promises scenarios, when shoppers are setting their
postal code an input error should be displayed if there is no available
products for that location.
- If there is a testing postal code with no products available you can
use it on `RegionModal` or `RegionPopover`;
- Or for local environment you can change the condition at
`useSetLocation` hook to mock the `no products` scenario;
vtex-sites/faststoreqa.store#788
---------
Co-authored-by: Larícia Mota
---
.../components/region/RegionModal/useSetLocation.ts | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/packages/core/src/components/region/RegionModal/useSetLocation.ts b/packages/core/src/components/region/RegionModal/useSetLocation.ts
index 67d26fccfb..c3a3ed095a 100644
--- a/packages/core/src/components/region/RegionModal/useSetLocation.ts
+++ b/packages/core/src/components/region/RegionModal/useSetLocation.ts
@@ -2,6 +2,8 @@ import { useState } from 'react'
import type { Session } from '@faststore/sdk'
import { sessionStore, validateSession } from 'src/sdk/session'
+import { getProductCount } from 'src/sdk/product'
+import { deliveryPromise } from 'discovery.config'
interface UseSetLocationParams {
input: string
@@ -49,6 +51,16 @@ export function useSetLocation(): UseSetLocationParams {
const validatedSession = await validateSession(newSession)
+ if (deliveryPromise.enabled) {
+ // Check product availability for specific location
+ const productCount = await getProductCount()
+ if (productCount === 0) {
+ setErrorMessage(`There are no products available for ${postalCode}.`)
+ setLoading(false)
+ return
+ }
+ }
+
sessionStore.set(validatedSession ?? newSession)
resetInputField()
onSuccess?.() // Execute the post-validation action (close modal, etc.)
From f6d08596013410a9aa19fe7c78d5f3258a261bcc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lucas=20Feij=C3=B3?=
Date: Thu, 8 May 2025 15:35:42 -0300
Subject: [PATCH 05/25] chore: `No products available` label from Headless CMS
and code refactor (#2824)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## What's the purpose of this pull request?
This PR intends to apply some code refactor and receive the `no products
available` error scenario.
## How to test it?
Remember to apply `cms-sync` to a dev workspace to validate the new
error message from hCMS.
### Starters Deploy Preview
vtex-sites/faststoreqa.store#791
---------
Co-authored-by: Fanny Chien
Co-authored-by: Larícia Mota
---
.../region/RegionModal/RegionModal.tsx | 2 +-
.../region/RegionModal/useSetLocation.ts | 83 -------------------
2 files changed, 1 insertion(+), 84 deletions(-)
delete mode 100644 packages/core/src/components/region/RegionModal/useSetLocation.ts
diff --git a/packages/core/src/components/region/RegionModal/RegionModal.tsx b/packages/core/src/components/region/RegionModal/RegionModal.tsx
index c233c3680a..52e4f09561 100644
--- a/packages/core/src/components/region/RegionModal/RegionModal.tsx
+++ b/packages/core/src/components/region/RegionModal/RegionModal.tsx
@@ -1,5 +1,5 @@
import dynamic from 'next/dynamic'
-import { useRef } from 'react'
+import { useRef, useState } from 'react'
import type { RegionModalProps as UIRegionModalProps } from '@faststore/ui'
import { Icon, useUI } from '@faststore/ui'
diff --git a/packages/core/src/components/region/RegionModal/useSetLocation.ts b/packages/core/src/components/region/RegionModal/useSetLocation.ts
deleted file mode 100644
index c3a3ed095a..0000000000
--- a/packages/core/src/components/region/RegionModal/useSetLocation.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-import { useState } from 'react'
-
-import type { Session } from '@faststore/sdk'
-import { sessionStore, validateSession } from 'src/sdk/session'
-import { getProductCount } from 'src/sdk/product'
-import { deliveryPromise } from 'discovery.config'
-
-interface UseSetLocationParams {
- input: string
- setInput: (value: string) => void
- resetInputField: () => void
- setLocation: (
- postalCode: string | undefined,
- inputFieldErrorMessage: string,
- session: Session,
- onSuccess?: () => void
- ) => Promise
- errorMessage: string
- setErrorMessage: (value: string) => void
- loading: boolean
-}
-
-export function useSetLocation(): UseSetLocationParams {
- const [input, setInput] = useState('')
- const [errorMessage, setErrorMessage] = useState('')
- const [loading, setLoading] = useState(false)
-
- const resetInputField = () => {
- setInput('')
- setErrorMessage('')
- }
-
- const setLocation = async (
- postalCode: string | undefined,
- inputFieldErrorMessage: string,
- session: Session,
- onSuccess?: () => void
- ) => {
- if (typeof postalCode !== 'string') {
- return
- }
-
- setLoading(true)
-
- try {
- const newSession = {
- ...session,
- postalCode,
- geoCoordinates: null, // Revalidate geo coordinates in API when users set a new postal code
- } as Session
-
- const validatedSession = await validateSession(newSession)
-
- if (deliveryPromise.enabled) {
- // Check product availability for specific location
- const productCount = await getProductCount()
- if (productCount === 0) {
- setErrorMessage(`There are no products available for ${postalCode}.`)
- setLoading(false)
- return
- }
- }
-
- sessionStore.set(validatedSession ?? newSession)
- resetInputField()
- onSuccess?.() // Execute the post-validation action (close modal, etc.)
- } catch (error) {
- setErrorMessage(inputFieldErrorMessage)
- } finally {
- setLoading(false) // Reset loading to false when validation is complete
- }
- }
-
- return {
- input,
- setInput,
- resetInputField,
- setLocation,
- errorMessage,
- setErrorMessage,
- loading,
- }
-}
From 0e586e4b4458b22cea11be8ac249102fd42b7e1d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lar=C3=ADcia=20Mota?=
Date: Tue, 13 May 2025 15:16:07 -0300
Subject: [PATCH 06/25] Fix rebase
---
.../vtex/resolvers/validateSession.ts | 22 -------------------
packages/core/src/sdk/ui/useOnClickOutside.ts | 3 +++
2 files changed, 3 insertions(+), 22 deletions(-)
create mode 100644 packages/core/src/sdk/ui/useOnClickOutside.ts
diff --git a/packages/api/src/platforms/vtex/resolvers/validateSession.ts b/packages/api/src/platforms/vtex/resolvers/validateSession.ts
index b72ebb77bf..ea7ca49afd 100644
--- a/packages/api/src/platforms/vtex/resolvers/validateSession.ts
+++ b/packages/api/src/platforms/vtex/resolvers/validateSession.ts
@@ -31,28 +31,6 @@ async function getPreciseLocationData(
}
}
-async function getGeoCoordinates(
- clients: Context['clients'],
- country: string,
- postalCode: string
-) {
- try {
- const address = await clients.commerce.checkout.address({
- postalCode,
- country,
- })
-
- const [longitude, latitude] = address.geoCoordinates
- return { city: address.city, geoCoordinates: { latitude, longitude } }
- } catch (err) {
- console.error(
- `Error while getting geo coordinates for the current postal code (${postalCode}) and country (${country}).\n`
- )
-
- throw err
- }
-}
-
export const validateSession = async (
_: any,
{ session: oldSession, search }: MutationValidateSessionArgs,
diff --git a/packages/core/src/sdk/ui/useOnClickOutside.ts b/packages/core/src/sdk/ui/useOnClickOutside.ts
new file mode 100644
index 0000000000..0daa2f0b0d
--- /dev/null
+++ b/packages/core/src/sdk/ui/useOnClickOutside.ts
@@ -0,0 +1,3 @@
+// This hook was moved to the UI package, this export is to avoid breaking changes
+// TODO: remove in the next major release
+export { useOnClickOutside as default } from '@faststore/ui'
From 99475f953b58961297b3f1231be2b6fe8baea954 Mon Sep 17 00:00:00 2001
From: Fanny Chien
Date: Wed, 14 May 2025 09:58:30 -0300
Subject: [PATCH 07/25] feat: Adds delivery methods in PDP filters (#2826)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
When Delivery Promise enabled:
- Adds Shipping Filters component in PLP
- List Shipping options available to filter
- Enable add custom labels for shipping option via hCMS
- Adds `Set Location` button when no zip code provided
note: Button actions and facets filters is not fully integrated yet.
- List Shipping options available to filter (according to the zipcode
provided)
|Desktop| Mobile|
|-|-|
|||
|Desktop| Mobile|
|-|-|
|||
- Show `Set Location` Button when no zipcode is provided
|Desktop| Mobile|
|-|-|
|||
- CMS
if you test using an account that delivery promise is not enabled,
nothing should be changed.
Run locally pointing to `vendemo` account, ou try this preview.
1. if deliveryPromise.enabled is `false` in `discovery.config, no
changes are expected.
Enable deliveryPromise in `discovery.config`, and test the scenarios
below:
1. Navigate to a PLP, you should be able to see a `Delivery` section in
the Filters component. (Also try in the mobile resolution)
2. If no zipCode provided, you should be able to see `Set Location`
button
3. If zipCode provided, you should be able to see the list of available
shipping options for that zipCode
vtex-sites/faststoreqa.store#799
---------
Co-authored-by: Lucas Feijó
Co-authored-by: Larícia Mota
---
packages/core/cms/faststore/sections.json | 48 ++++++++++++
.../search/Filter/FilterDeliveryOption.tsx | 75 +++++++++++++++++++
.../components/search/Filter/FilterSlider.tsx | 10 +++
.../ui/ProductGallery/ProductGallery.tsx | 3 +
4 files changed, 136 insertions(+)
create mode 100644 packages/core/src/components/search/Filter/FilterDeliveryOption.tsx
diff --git a/packages/core/cms/faststore/sections.json b/packages/core/cms/faststore/sections.json
index 65e2afe751..a3e77f2092 100644
--- a/packages/core/cms/faststore/sections.json
+++ b/packages/core/cms/faststore/sections.json
@@ -1913,6 +1913,54 @@
"default": "Apply"
}
}
+ },
+ "deliverySettings": {
+ "title": "Delivery Settings",
+ "type": "object",
+ "required": ["title", "description"],
+ "properties": {
+ "title": {
+ "title": "Delivery section title",
+ "type": "string",
+ "default": "Delivery"
+ },
+ "description": {
+ "title": "Delivery section description",
+ "type": "string",
+ "default": "Offers and delivery options vary based on region."
+ },
+ "setLocationButtonLabel": {
+ "title": "Call to Action label",
+ "type": "string",
+ "default": "Set Location"
+ },
+ "deliveryCustomLabels": {
+ "title": "Delivery Custom labels",
+ "type": "object",
+ "properties": {
+ "delivery": {
+ "title": "Shipping label",
+ "type": "string",
+ "default": "Shipping to"
+ },
+ "pickupInPoint": {
+ "title": "Pickup in point label",
+ "type": "string",
+ "default": "Pickup at"
+ },
+ "pickupNearby": {
+ "title": "Pickup Nearby label",
+ "type": "string",
+ "default": "Pickup Nearby"
+ },
+ "pickupAll": {
+ "title": "Pickup Anywhere label",
+ "type": "string",
+ "default": "Pickup Anywhere"
+ }
+ }
+ }
+ }
}
}
},
diff --git a/packages/core/src/components/search/Filter/FilterDeliveryOption.tsx b/packages/core/src/components/search/Filter/FilterDeliveryOption.tsx
new file mode 100644
index 0000000000..5798c4fc1c
--- /dev/null
+++ b/packages/core/src/components/search/Filter/FilterDeliveryOption.tsx
@@ -0,0 +1,75 @@
+import { Button as UIButton } from '@faststore/ui'
+import { sessionStore } from 'src/sdk/session'
+import { textToTitleCase } from 'src/utils/utilities'
+
+interface DeliveryCustomLabels {
+ delivery?: string
+ pickupInPoint?: string
+ pickupNearby?: string
+ pickupAll?: string
+}
+
+interface FacetValue {
+ value: string
+ label: string
+ selected: boolean
+ quantity: number
+}
+
+interface FilterDeliveryOptionProps {
+ item: FacetValue
+ deliveryCustomLabels: DeliveryCustomLabels
+}
+
+export default function FilterDeliveryOption({
+ item,
+ deliveryCustomLabels,
+}: FilterDeliveryOptionProps) {
+ const { city, postalCode } = sessionStore.read()
+ const location = city ? `${textToTitleCase(city)}, ${postalCode}` : postalCode
+
+ const mapDeliveryCustomLabel: Record = {
+ delivery: deliveryCustomLabels?.delivery ?? 'Shipping to',
+ 'pickup-in-point': deliveryCustomLabels?.pickupInPoint ?? 'Pickup at',
+ 'pickup-nearby': deliveryCustomLabels?.pickupNearby ?? 'Pickup Nearby',
+ 'pickup-all': deliveryCustomLabels?.pickupAll ?? 'Pickup Anywhere',
+ }
+
+ if (item.value === 'delivery') {
+ return (
+ <>
+ {mapDeliveryCustomLabel[item.value]}
+ {
+ // TODO: open edit local slideOver
+ window.alert('Open Modal')
+ }}
+ >
+ {location}
+
+ >
+ )
+ }
+
+ if (item.value === 'pickup-in-point') {
+ return (
+ <>
+ {mapDeliveryCustomLabel[item.value]}
+ {
+ // TODO: open edit local slideOver
+ window.alert('Open Modal')
+ }}
+ >
+ Robson St
+
+ >
+ )
+ }
+
+ return <>{mapDeliveryCustomLabel[item.value]}>
+}
diff --git a/packages/core/src/components/search/Filter/FilterSlider.tsx b/packages/core/src/components/search/Filter/FilterSlider.tsx
index e152bfb5ff..29a1264806 100644
--- a/packages/core/src/components/search/Filter/FilterSlider.tsx
+++ b/packages/core/src/components/search/Filter/FilterSlider.tsx
@@ -84,6 +84,15 @@ export interface FilterSliderProps {
* CMS defined label for the apply button component.
*/
applyButtonLabel?: string
+ /**
+ * CMS settings for values related to delivery (e.g., custom name for title, shipping, pickup, pickup-nearby).
+ */
+ deliverySettings?: {
+ title?: string
+ description?: string
+ setLocationButtonLabel?: string
+ deliveryCustomLabels?: DeliveryCustomLabels
+ }
}
function FilterSlider({
@@ -95,6 +104,7 @@ function FilterSlider({
title,
clearButtonLabel,
applyButtonLabel,
+ deliverySettings,
}: FilterSliderProps & ReturnType) {
const { resetInfiniteScroll, setState, state } = useSearch()
const { openRegionSlider } = useUI()
diff --git a/packages/core/src/components/ui/ProductGallery/ProductGallery.tsx b/packages/core/src/components/ui/ProductGallery/ProductGallery.tsx
index 18d2b7d60b..c4939f9c73 100644
--- a/packages/core/src/components/ui/ProductGallery/ProductGallery.tsx
+++ b/packages/core/src/components/ui/ProductGallery/ProductGallery.tsx
@@ -55,6 +55,7 @@ export interface ProductGalleryProps {
clearButtonLabel: FilterSliderProps['clearButtonLabel']
applyButtonLabel: FilterSliderProps['applyButtonLabel']
}
+ deliverySettings?: FilterSliderProps['deliverySettings']
}
previousPageButton?: {
label?: string
@@ -174,6 +175,7 @@ function ProductGallery({
{...FilterDesktop.props}
{...filter}
title={filterCmsData?.title}
+ deliverySettings={filterCmsData?.deliverySettings}
/>
)}
@@ -188,6 +190,7 @@ function ProductGallery({
title={filterCmsData?.title}
clearButtonLabel={filterCmsData?.mobileOnly?.clearButtonLabel}
applyButtonLabel={filterCmsData?.mobileOnly?.applyButtonLabel}
+ deliverySettings={filterCmsData?.deliverySettings}
/>
)}
From c852d9f648244b17051c3f6339f1a47b14f8dba5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lar=C3=ADcia=20Mota?=
Date: Mon, 19 May 2025 14:31:41 -0300
Subject: [PATCH 08/25] feat: Create Global Sections Settings tab (#2845)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
It creates a new tab inside the Global Sections CMS. In the new Settings
tab, it will be possible to configure settings related to
regionalization, which will be used by components such as the Region
Modal and Region Popover.
This PR doesn't update all components/sections, it'll be done after. In
this PR, there is an update to `FilterDesktop` so we can validate the
change.
The merchant will be able to configure their regionalization-related
message in a single place (Global Sections Settings tab) instead of
duplicate messages through sections.
To avoid introducing breaking changes, I haven't removed the messages
from the sections yet - this will be done in v4. I've added a
deprecation notice in every field that was created in the Settings tab.
In v3, the components/sections will use the messages defined in the
sections CMS; if they're blank, they will use the messages in the Global
Sections Settings tab.
In the CMS of the vendemo store, I've added messages in the Global
Sections Settings tab using a `[GS]` at the beginning of every message
so we can identify the ones that are coming from this tab.
- PLP
I've only removed (left blank) the messages in `Product List Page >
Product Gallery > Filter > Delivery Settings > **Delivery Section
description**` and `Product List Page > Product Gallery > Filter >
Delivery Settings > Delivery Custom labels > **Shipping label**`, those
are the ones that should use the GS one.
- Search page
The messages from `Search Page > Product Gallery > Filter > Delivery
Settings` were all left blank (we hadn't updated this page to add the
messages -- so this page didn't have messages defined for those cases,
and we hadn't noticed 😣).
| PLP | Search Page |
| ---- | ---- |
| | |
| | |
| | |
- Vendemo [[PR](https://github.com/dp-faststore-org/vendemo-dp/pull/17)
/
[preview](https://vendemo-cm9sir9v900u7z6llkl62l70j-7sfv6u49l.b.vtex.app/)]
- [Slack discussion
thread](https://vtex.slack.com/archives/C03L3CRCDC4/p1747248599365189)
---
packages/core/cms/faststore/sections.json | 29 +++++++++----------
.../core/src/sdk/overrides/PageProvider.tsx | 2 ++
2 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/packages/core/cms/faststore/sections.json b/packages/core/cms/faststore/sections.json
index a3e77f2092..e519c60abd 100644
--- a/packages/core/cms/faststore/sections.json
+++ b/packages/core/cms/faststore/sections.json
@@ -1917,22 +1917,21 @@
"deliverySettings": {
"title": "Delivery Settings",
"type": "object",
- "required": ["title", "description"],
"properties": {
"title": {
"title": "Delivery section title",
- "type": "string",
- "default": "Delivery"
+ "description": "[Deprecated] Use the fields from the Settings tab in Global Sections",
+ "type": "string"
},
"description": {
"title": "Delivery section description",
- "type": "string",
- "default": "Offers and delivery options vary based on region."
+ "description": "[Deprecated] Use the fields from the Settings tab in Global Sections",
+ "type": "string"
},
"setLocationButtonLabel": {
"title": "Call to Action label",
- "type": "string",
- "default": "Set Location"
+ "description": "[Deprecated] Use the fields from the Settings tab in Global Sections",
+ "type": "string"
},
"deliveryCustomLabels": {
"title": "Delivery Custom labels",
@@ -1940,23 +1939,23 @@
"properties": {
"delivery": {
"title": "Shipping label",
- "type": "string",
- "default": "Shipping to"
+ "description": "[Deprecated] Use the fields from the Settings tab in Global Sections",
+ "type": "string"
},
"pickupInPoint": {
"title": "Pickup in point label",
- "type": "string",
- "default": "Pickup at"
+ "description": "[Deprecated] Use the fields from the Settings tab in Global Sections",
+ "type": "string"
},
"pickupNearby": {
"title": "Pickup Nearby label",
- "type": "string",
- "default": "Pickup Nearby"
+ "description": "[Deprecated] Use the fields from the Settings tab in Global Sections",
+ "type": "string"
},
"pickupAll": {
"title": "Pickup Anywhere label",
- "type": "string",
- "default": "Pickup Anywhere"
+ "description": "[Deprecated] Use the fields from the Settings tab in Global Sections",
+ "type": "string"
}
}
}
diff --git a/packages/core/src/sdk/overrides/PageProvider.tsx b/packages/core/src/sdk/overrides/PageProvider.tsx
index d33cc77044..8b143cc7d5 100644
--- a/packages/core/src/sdk/overrides/PageProvider.tsx
+++ b/packages/core/src/sdk/overrides/PageProvider.tsx
@@ -23,6 +23,7 @@ export interface PLPContext extends PageGlobalContext {
ClientProductGalleryQueryQuery & {
pages: ClientManyProductsQueryQuery[]
}
+ globalSectionsSettings?: Record
}
export interface SearchPageContext extends PageGlobalContext {
@@ -30,6 +31,7 @@ export interface SearchPageContext extends PageGlobalContext {
ClientProductGalleryQueryQuery & {
pages: ClientManyProductsQueryQuery[]
}
+ globalSectionsSettings?: Record
}
export interface DynamicContent extends PageGlobalContext {
From 0ce1b2b27d6905f42c37bd1957d82f26b060d90f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lar=C3=ADcia=20Mota?=
Date: Thu, 22 May 2025 15:29:04 -0300
Subject: [PATCH 09/25] feat: Add Region Slider to set/change location (#2851)
Create the Region Slider component to be used for setting and changing
the location (postal code).
It's triggered when the shopper clicks on the "Set location" button in
the PLP filters and when they click on the postal code link in the PLP
filters. The first one is the set location type of this Region Slider,
and the second is the change location type.
I've added a new state in the UIProvider and functions to handle its
change for the Region Slider.
In the preview, test both the set and change location scenarios:
When no postal code is defined yet, the "Set location" button is
displayed in the PLP filters.
When the shopper clicks this button, a slideover is displayed to set the
postal code.
| Desktop | Mobile |
| ---- | ---- |
| | |
| | |
When a postal code was previously set, this postal code is displayed as
a link in the PLP filters.
When the shopper clicks this link, a slideover is displayed to change
the postal code.
| Desktop | Mobile |
| ---- | ---- |
| | |
| | |
[Preview](https://vendemo-cm9sir9v900u7z6llkl62l70j-k5r6r35q4.b.vtex.app/)
[PR](https://github.com/dp-faststore-org/vendemo-dp/pull/19)
- [Jira task](https://vtex-dev.atlassian.net/browse/SFS-2449)
---------
Co-authored-by: Fanny Chien
Co-authored-by: Otavio Moreira Meirelles
Co-authored-by: Fanny Chien
---
packages/core/cms/faststore/sections.json | 47 -------------------
.../search/Filter/FilterDeliveryOption.tsx | 45 +++++++++---------
.../components/search/Filter/FilterSlider.tsx | 10 ----
3 files changed, 24 insertions(+), 78 deletions(-)
diff --git a/packages/core/cms/faststore/sections.json b/packages/core/cms/faststore/sections.json
index e519c60abd..65e2afe751 100644
--- a/packages/core/cms/faststore/sections.json
+++ b/packages/core/cms/faststore/sections.json
@@ -1913,53 +1913,6 @@
"default": "Apply"
}
}
- },
- "deliverySettings": {
- "title": "Delivery Settings",
- "type": "object",
- "properties": {
- "title": {
- "title": "Delivery section title",
- "description": "[Deprecated] Use the fields from the Settings tab in Global Sections",
- "type": "string"
- },
- "description": {
- "title": "Delivery section description",
- "description": "[Deprecated] Use the fields from the Settings tab in Global Sections",
- "type": "string"
- },
- "setLocationButtonLabel": {
- "title": "Call to Action label",
- "description": "[Deprecated] Use the fields from the Settings tab in Global Sections",
- "type": "string"
- },
- "deliveryCustomLabels": {
- "title": "Delivery Custom labels",
- "type": "object",
- "properties": {
- "delivery": {
- "title": "Shipping label",
- "description": "[Deprecated] Use the fields from the Settings tab in Global Sections",
- "type": "string"
- },
- "pickupInPoint": {
- "title": "Pickup in point label",
- "description": "[Deprecated] Use the fields from the Settings tab in Global Sections",
- "type": "string"
- },
- "pickupNearby": {
- "title": "Pickup Nearby label",
- "description": "[Deprecated] Use the fields from the Settings tab in Global Sections",
- "type": "string"
- },
- "pickupAll": {
- "title": "Pickup Anywhere label",
- "description": "[Deprecated] Use the fields from the Settings tab in Global Sections",
- "type": "string"
- }
- }
- }
- }
}
}
},
diff --git a/packages/core/src/components/search/Filter/FilterDeliveryOption.tsx b/packages/core/src/components/search/Filter/FilterDeliveryOption.tsx
index 5798c4fc1c..07043cb0f9 100644
--- a/packages/core/src/components/search/Filter/FilterDeliveryOption.tsx
+++ b/packages/core/src/components/search/Filter/FilterDeliveryOption.tsx
@@ -1,14 +1,9 @@
-import { Button as UIButton } from '@faststore/ui'
+import { regionSliderTypes, Button as UIButton, useUI } from '@faststore/ui'
+import { RegionSlider } from 'src/components/region/RegionSlider'
import { sessionStore } from 'src/sdk/session'
+import type { RegionalizationCmsData } from 'src/utils/globalSettings'
import { textToTitleCase } from 'src/utils/utilities'
-interface DeliveryCustomLabels {
- delivery?: string
- pickupInPoint?: string
- pickupNearby?: string
- pickupAll?: string
-}
-
interface FacetValue {
value: string
label: string
@@ -18,37 +13,45 @@ interface FacetValue {
interface FilterDeliveryOptionProps {
item: FacetValue
- deliveryCustomLabels: DeliveryCustomLabels
+ deliveryMethods: RegionalizationCmsData['deliverySettings']['deliveryMethods']
+ cmsData: Record
}
export default function FilterDeliveryOption({
item,
- deliveryCustomLabels,
+ deliveryMethods,
+ cmsData,
}: FilterDeliveryOptionProps) {
const { city, postalCode } = sessionStore.read()
- const location = city ? `${textToTitleCase(city)}, ${postalCode}` : postalCode
+ const {
+ regionSlider: { type: regionSliderType },
+ openRegionSlider,
+ } = useUI()
- const mapDeliveryCustomLabel: Record = {
- delivery: deliveryCustomLabels?.delivery ?? 'Shipping to',
- 'pickup-in-point': deliveryCustomLabels?.pickupInPoint ?? 'Pickup at',
- 'pickup-nearby': deliveryCustomLabels?.pickupNearby ?? 'Pickup Nearby',
- 'pickup-all': deliveryCustomLabels?.pickupAll ?? 'Pickup Anywhere',
+ const location = city ? `${textToTitleCase(city)}, ${postalCode}` : postalCode
+ const mapDeliveryMethodLabel: Record = {
+ delivery: deliveryMethods?.delivery ?? 'Shipping to',
+ 'pickup-in-point': deliveryMethods?.pickupInPoint ?? 'Pickup at',
+ 'pickup-nearby': deliveryMethods?.pickupNearby ?? 'Pickup Nearby',
+ 'pickup-all': deliveryMethods?.pickupAll?.label ?? 'Pickup Anywhere',
}
if (item.value === 'delivery') {
return (
<>
- {mapDeliveryCustomLabel[item.value]}
+ {mapDeliveryMethodLabel[item.value]}
{
- // TODO: open edit local slideOver
- window.alert('Open Modal')
+ openRegionSlider(regionSliderTypes.changeLocation)
}}
>
{location}
+ {regionSliderType === regionSliderTypes.changeLocation && (
+
+ )}
>
)
}
@@ -56,7 +59,7 @@ export default function FilterDeliveryOption({
if (item.value === 'pickup-in-point') {
return (
<>
- {mapDeliveryCustomLabel[item.value]}
+ {mapDeliveryMethodLabel[item.value]}
{mapDeliveryCustomLabel[item.value]}>
+ return <>{mapDeliveryMethodLabel[item.value]}>
}
diff --git a/packages/core/src/components/search/Filter/FilterSlider.tsx b/packages/core/src/components/search/Filter/FilterSlider.tsx
index 29a1264806..e152bfb5ff 100644
--- a/packages/core/src/components/search/Filter/FilterSlider.tsx
+++ b/packages/core/src/components/search/Filter/FilterSlider.tsx
@@ -84,15 +84,6 @@ export interface FilterSliderProps {
* CMS defined label for the apply button component.
*/
applyButtonLabel?: string
- /**
- * CMS settings for values related to delivery (e.g., custom name for title, shipping, pickup, pickup-nearby).
- */
- deliverySettings?: {
- title?: string
- description?: string
- setLocationButtonLabel?: string
- deliveryCustomLabels?: DeliveryCustomLabels
- }
}
function FilterSlider({
@@ -104,7 +95,6 @@ function FilterSlider({
title,
clearButtonLabel,
applyButtonLabel,
- deliverySettings,
}: FilterSliderProps & ReturnType) {
const { resetInfiniteScroll, setState, state } = useSearch()
const { openRegionSlider } = useUI()
From b8c7304c2c17dea25bd9f3d853d3d85fdc77e2eb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lucas=20Feij=C3=B3?=
Date: Fri, 30 May 2025 09:44:43 -0300
Subject: [PATCH 10/25] feat: Shipping methods integration (#2847)
This PR contains the shipping methods integration with API.
We already have some of the shipping facets being rendered, but no
action was being made. After these changes, the filters should work
depending on the selected scenario.
The `usePickupPoints` hook is responsible to get the list of pickup
points available for the specific location in session. Based on that
list, we create the `pickup-in-point` facet on the client-side (it's not
delivered by the IS API) and inject on the facets list.
When the `pickup-in-point` is selected, a additional facet called
`pickupPoint` is also added on the facets list, then on the Search
client (`@faststore/api`) we transform it on query string param and send
it in the `product_search` IS request.
| Desktop | Mobile |
| - | - |
| 
| 
|
- Use the following postal code: `50030-260`;
- Pay attention to the behavior of each different filter: each one must
send the correct parameters/variables in the query (check the `Network`
tab);
- Observe the behavior and visibility of the filters on both desktop and
mobile, the logic is similar but they have some different details that
can impact navigation;
vtex-sites/faststoreqa.store#812
---
packages/core/@generated/gql.ts | 8 ++
.../search/Filter/FilterDeliveryOption.tsx | 2 +-
.../core/src/sdk/shipping/usePickupPoints.ts | 74 +++++++++++++++++++
3 files changed, 83 insertions(+), 1 deletion(-)
create mode 100644 packages/core/src/sdk/shipping/usePickupPoints.ts
diff --git a/packages/core/@generated/gql.ts b/packages/core/@generated/gql.ts
index ec38337920..cbd6890856 100644
--- a/packages/core/@generated/gql.ts
+++ b/packages/core/@generated/gql.ts
@@ -90,6 +90,8 @@ const documents = {
types.ValidateSessionDocument,
'\n query ClientShippingSimulationQuery(\n $postalCode: String!\n $country: String!\n $items: [IShippingItem!]!\n ) {\n ...ClientShippingSimulation\n shipping(items: $items, postalCode: $postalCode, country: $country) {\n logisticsInfo {\n slas {\n carrier\n price\n availableDeliveryWindows {\n startDateUtc\n endDateUtc\n price\n listPrice\n }\n shippingEstimate\n localizedEstimates\n deliveryChannel\n }\n }\n address {\n city\n neighborhood\n state\n }\n }\n }\n':
types.ClientShippingSimulationQueryDocument,
+ '\n query ClientPickupPointsQuery(\n $geoCoordinates: IStoreGeoCoordinates\n $postalCode: String\n $country: String\n ) {\n pickupPoints(geoCoordinates: $geoCoordinates, postalCode: $postalCode, country: $country) {\n paging {\n total\n }\n items {\n pickupPoint {\n id\n address {\n street\n }\n friendlyName\n }\n }\n }\n }\n':
+ types.ClientPickupPointsQueryDocument,
'\n query ServerManyProductsQuery(\n $first: Int!\n $after: String\n $sort: StoreSort!\n $term: String!\n $selectedFacets: [IStoreSelectedFacet!]!\n $sponsoredCount: Int\n ) {\n ...ClientManyProducts\n search(\n first: $first\n after: $after\n sort: $sort\n term: $term\n selectedFacets: $selectedFacets\n sponsoredCount: $sponsoredCount\n ) {\n products {\n pageInfo {\n totalCount\n }\n edges {\n node {\n ...ProductSummary_product\n }\n }\n }\n metadata {\n ...SearchEvent_metadata\n }\n }\n }\n':
types.ServerManyProductsQueryDocument,
}
@@ -328,6 +330,12 @@ export function gql(
export function gql(
source: '\n query ClientShippingSimulationQuery(\n $postalCode: String!\n $country: String!\n $items: [IShippingItem!]!\n ) {\n ...ClientShippingSimulation\n shipping(items: $items, postalCode: $postalCode, country: $country) {\n logisticsInfo {\n slas {\n carrier\n price\n availableDeliveryWindows {\n startDateUtc\n endDateUtc\n price\n listPrice\n }\n shippingEstimate\n localizedEstimates\n deliveryChannel\n }\n }\n address {\n city\n neighborhood\n state\n }\n }\n }\n'
): typeof import('./graphql').ClientShippingSimulationQueryDocument
+/**
+ * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
+ */
+export function gql(
+ source: '\n query ClientPickupPointsQuery(\n $geoCoordinates: IStoreGeoCoordinates\n $postalCode: String\n $country: String\n ) {\n pickupPoints(geoCoordinates: $geoCoordinates, postalCode: $postalCode, country: $country) {\n paging {\n total\n }\n items {\n pickupPoint {\n id\n address {\n street\n }\n friendlyName\n }\n }\n }\n }\n'
+): typeof import('./graphql').ClientPickupPointsQueryDocument
/**
* The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
diff --git a/packages/core/src/components/search/Filter/FilterDeliveryOption.tsx b/packages/core/src/components/search/Filter/FilterDeliveryOption.tsx
index 07043cb0f9..bb71744b70 100644
--- a/packages/core/src/components/search/Filter/FilterDeliveryOption.tsx
+++ b/packages/core/src/components/search/Filter/FilterDeliveryOption.tsx
@@ -68,7 +68,7 @@ export default function FilterDeliveryOption({
window.alert('Open Modal')
}}
>
- Robson St
+ {item.label}
>
)
diff --git a/packages/core/src/sdk/shipping/usePickupPoints.ts b/packages/core/src/sdk/shipping/usePickupPoints.ts
new file mode 100644
index 0000000000..24d2734c7e
--- /dev/null
+++ b/packages/core/src/sdk/shipping/usePickupPoints.ts
@@ -0,0 +1,74 @@
+import { useMemo } from 'react'
+import { gql } from '@generated'
+import type {
+ ClientPickupPointsQueryQuery,
+ ClientPickupPointsQueryQueryVariables,
+} from '@generated/graphql'
+
+import { deliveryPromise } from 'discovery.config'
+import { useSession } from 'src/sdk/session'
+import { useQuery } from 'src/sdk/graphql/useQuery'
+
+export const query = gql(`
+ query ClientPickupPointsQuery(
+ $geoCoordinates: IStoreGeoCoordinates
+ $postalCode: String
+ $country: String
+ ) {
+ pickupPoints(geoCoordinates: $geoCoordinates, postalCode: $postalCode, country: $country) {
+ paging {
+ total
+ }
+ items {
+ pickupPoint {
+ id
+ address {
+ street
+ }
+ friendlyName
+ }
+ }
+ }
+ }
+`)
+
+export const usePickupPoints = () => {
+ if (!deliveryPromise.enabled) {
+ return null
+ }
+
+ const { country, postalCode, geoCoordinates } = useSession()
+
+ if (!geoCoordinates && (!postalCode || !country)) {
+ return null
+ }
+
+ const variables = useMemo(
+ () => ({
+ country: !!geoCoordinates ? undefined : country,
+ geoCoordinates: geoCoordinates ?? undefined,
+ postalCode: !!geoCoordinates ? undefined : postalCode,
+ }),
+ [country, geoCoordinates, postalCode]
+ )
+
+ const { data } = useQuery<
+ ClientPickupPointsQueryQuery,
+ ClientPickupPointsQueryQueryVariables
+ >(query, variables, {
+ fallbackData: null,
+ })
+
+ if (!data) {
+ return null
+ }
+
+ const pickupPoints = data.pickupPoints.items.map((item) => ({
+ id: item.pickupPoint?.id,
+ addressStreet: item.pickupPoint?.address?.street,
+ name: item.pickupPoint?.friendlyName,
+ totalItems: data.pickupPoints.paging.total,
+ }))
+
+ return pickupPoints
+}
From 26bec97f9222b50155f0879c59b0bc92ebd618e0 Mon Sep 17 00:00:00 2001
From: Fanny Chien
Date: Tue, 10 Jun 2025 10:34:03 -0300
Subject: [PATCH 11/25] feat: Edit pickup points slideover (#2872)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This PR implements the Editing the store in the PLP delivery filter
flow.
The main changes added were:
- Adds `changePickupPoint` type to `regionSliderType`
- List pickup points given a valid zipcode
- Updates shipping filter with selected pickup point
reminder: After merging, run `cms sync` to update new section fields.
(Few new fields were added: `changePickupPoint`,
`changePickupPointApplyButtonLabel`, `noStoresAvailableInLocation` and
`errorMessageHelper`)
1. Buyer can edit the pickup store by clicking in the pickup filter in
PLP. The SliderOver should appear.
|Desktop|Mobile|
|-|-|
|||
2. If the pickup filter is selected, the slider already opens with the
field focused and the current location filled in.
|Desktop|Mobile|
|-|-|
||
3. If the buyer doesn't change the postal code and selects another
store, `Update` button should be available.
- postal code stays the same and pickup point store should be updated in
the PLP filters
|Desktop|Mobile|
|-|-|
|||
4. If the buyer changes the postal code and selects a new store.
- after updating the pickup point is updated in the PLP filter
5. If buyer changes the postal code that returns invalid or unavailable
items for the location, `Update` button should be disabled and a message
should be displayed.
|Desktop|Mobile|
|-|-|
|||
_this error message layout could be slightly different - discussing with
design team_
6. If buyer changes the postal code and no pickup stores available for
the location, `Update` button should be disabled and a message should be
displayed.
|Desktop|Mobile|
|-|-|
||
- You can run locally and point the account to `vendemo` or try on this
preview
[link](https://vendemo-cm9sir9v900u7z6llkl62l70j-kiasokde8.b.vtex.app).
- Reproduce the scenarios listed above in desktop and mobile.
- [preview
link](https://vendemo-cm9sir9v900u7z6llkl62l70j-kiasokde8.b.vtex.app)
---------
Co-authored-by: Lucas Feijó
Co-authored-by: Larícia Mota
---
packages/core/@generated/gql.ts | 4 +-
.../core/cms/faststore/content-types.json | 42 +++++++++++++++++++
.../region/RegionSlider/RegionSlider.tsx | 2 +
.../search/Filter/FilterDeliveryOption.tsx | 14 +------
.../core/src/sdk/shipping/usePickupPoints.ts | 18 ++++++--
packages/core/src/utils/globalSettings.ts | 10 +++++
6 files changed, 73 insertions(+), 17 deletions(-)
diff --git a/packages/core/@generated/gql.ts b/packages/core/@generated/gql.ts
index cbd6890856..08d4e0209e 100644
--- a/packages/core/@generated/gql.ts
+++ b/packages/core/@generated/gql.ts
@@ -90,7 +90,7 @@ const documents = {
types.ValidateSessionDocument,
'\n query ClientShippingSimulationQuery(\n $postalCode: String!\n $country: String!\n $items: [IShippingItem!]!\n ) {\n ...ClientShippingSimulation\n shipping(items: $items, postalCode: $postalCode, country: $country) {\n logisticsInfo {\n slas {\n carrier\n price\n availableDeliveryWindows {\n startDateUtc\n endDateUtc\n price\n listPrice\n }\n shippingEstimate\n localizedEstimates\n deliveryChannel\n }\n }\n address {\n city\n neighborhood\n state\n }\n }\n }\n':
types.ClientShippingSimulationQueryDocument,
- '\n query ClientPickupPointsQuery(\n $geoCoordinates: IStoreGeoCoordinates\n $postalCode: String\n $country: String\n ) {\n pickupPoints(geoCoordinates: $geoCoordinates, postalCode: $postalCode, country: $country) {\n paging {\n total\n }\n items {\n pickupPoint {\n id\n address {\n street\n }\n friendlyName\n }\n }\n }\n }\n':
+ '\n query ClientPickupPointsQuery(\n $geoCoordinates: IStoreGeoCoordinates\n $postalCode: String\n $country: String\n ) {\n pickupPoints(geoCoordinates: $geoCoordinates, postalCode: $postalCode, country: $country) {\n paging {\n total\n }\n items {\n pickupPoint {\n id\n address {\n street\n number\n postalCode\n city\n state\n }\n friendlyName\n }\n distance\n }\n }\n }\n':
types.ClientPickupPointsQueryDocument,
'\n query ServerManyProductsQuery(\n $first: Int!\n $after: String\n $sort: StoreSort!\n $term: String!\n $selectedFacets: [IStoreSelectedFacet!]!\n $sponsoredCount: Int\n ) {\n ...ClientManyProducts\n search(\n first: $first\n after: $after\n sort: $sort\n term: $term\n selectedFacets: $selectedFacets\n sponsoredCount: $sponsoredCount\n ) {\n products {\n pageInfo {\n totalCount\n }\n edges {\n node {\n ...ProductSummary_product\n }\n }\n }\n metadata {\n ...SearchEvent_metadata\n }\n }\n }\n':
types.ServerManyProductsQueryDocument,
@@ -334,7 +334,7 @@ export function gql(
* The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
export function gql(
- source: '\n query ClientPickupPointsQuery(\n $geoCoordinates: IStoreGeoCoordinates\n $postalCode: String\n $country: String\n ) {\n pickupPoints(geoCoordinates: $geoCoordinates, postalCode: $postalCode, country: $country) {\n paging {\n total\n }\n items {\n pickupPoint {\n id\n address {\n street\n }\n friendlyName\n }\n }\n }\n }\n'
+ source: '\n query ClientPickupPointsQuery(\n $geoCoordinates: IStoreGeoCoordinates\n $postalCode: String\n $country: String\n ) {\n pickupPoints(geoCoordinates: $geoCoordinates, postalCode: $postalCode, country: $country) {\n paging {\n total\n }\n items {\n pickupPoint {\n id\n address {\n street\n number\n postalCode\n city\n state\n }\n friendlyName\n }\n distance\n }\n }\n }\n'
): typeof import('./graphql').ClientPickupPointsQueryDocument
/**
* The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
diff --git a/packages/core/cms/faststore/content-types.json b/packages/core/cms/faststore/content-types.json
index 8ba50872af..2948b71a4c 100644
--- a/packages/core/cms/faststore/content-types.json
+++ b/packages/core/cms/faststore/content-types.json
@@ -232,6 +232,48 @@
"default": "Storefront icon"
}
}
+ },
+ "regionSlider": {
+ "title": "RegionSlider SlideOver",
+ "type": "object",
+ "properties": {
+ "title": {
+ "title": "RegionSlider title",
+ "type": "object",
+ "properties": {
+ "setLocation": {
+ "title": "Set Location title",
+ "type": "string",
+ "default": "Set Location"
+ },
+ "changeLocation": {
+ "title": "Change Postal Code title",
+ "type": "string",
+ "default": "Change Location"
+ },
+ "changePickupPoint": {
+ "title": "Change Pickup Point location title",
+ "type": "string",
+ "default": "Change Store"
+ }
+ }
+ },
+ "pickupPointChangeApplyButtonLabel": {
+ "title": "Change Pickup Point apply button label",
+ "type": "string",
+ "default": "Update"
+ },
+ "choosePickupPointAriaLabel": {
+ "title": "Choose Pickup Point aria-label (radio group)",
+ "type": "string",
+ "default": "Choose a store"
+ },
+ "noPickupPointsAvailableInLocation": {
+ "title": "No Pickup Point available near location message",
+ "type": "string",
+ "default": "No stores near location."
+ }
+ }
}
}
},
diff --git a/packages/core/src/components/region/RegionSlider/RegionSlider.tsx b/packages/core/src/components/region/RegionSlider/RegionSlider.tsx
index 51a2d723d2..f6ee366690 100644
--- a/packages/core/src/components/region/RegionSlider/RegionSlider.tsx
+++ b/packages/core/src/components/region/RegionSlider/RegionSlider.tsx
@@ -117,6 +117,8 @@ function RegionSlider() {
const idkPostalCodeLink = cmsData?.regionalization?.idkPostalCodeLink
const handleSubmit = async () => {
+ setAppliedInput(input)
+
if (isValidating) {
return
}
diff --git a/packages/core/src/components/search/Filter/FilterDeliveryOption.tsx b/packages/core/src/components/search/Filter/FilterDeliveryOption.tsx
index bb71744b70..6fdefd9cea 100644
--- a/packages/core/src/components/search/Filter/FilterDeliveryOption.tsx
+++ b/packages/core/src/components/search/Filter/FilterDeliveryOption.tsx
@@ -1,5 +1,4 @@
import { regionSliderTypes, Button as UIButton, useUI } from '@faststore/ui'
-import { RegionSlider } from 'src/components/region/RegionSlider'
import { sessionStore } from 'src/sdk/session'
import type { RegionalizationCmsData } from 'src/utils/globalSettings'
import { textToTitleCase } from 'src/utils/utilities'
@@ -14,19 +13,14 @@ interface FacetValue {
interface FilterDeliveryOptionProps {
item: FacetValue
deliveryMethods: RegionalizationCmsData['deliverySettings']['deliveryMethods']
- cmsData: Record
}
export default function FilterDeliveryOption({
item,
deliveryMethods,
- cmsData,
}: FilterDeliveryOptionProps) {
const { city, postalCode } = sessionStore.read()
- const {
- regionSlider: { type: regionSliderType },
- openRegionSlider,
- } = useUI()
+ const { openRegionSlider } = useUI()
const location = city ? `${textToTitleCase(city)}, ${postalCode}` : postalCode
const mapDeliveryMethodLabel: Record = {
@@ -49,9 +43,6 @@ export default function FilterDeliveryOption({
>
{location}
- {regionSliderType === regionSliderTypes.changeLocation && (
-
- )}
>
)
}
@@ -64,8 +55,7 @@ export default function FilterDeliveryOption({
data-fs-filter-list-item-button
size="small"
onClick={() => {
- // TODO: open edit local slideOver
- window.alert('Open Modal')
+ openRegionSlider(regionSliderTypes.changePickupPoint)
}}
>
{item.label}
diff --git a/packages/core/src/sdk/shipping/usePickupPoints.ts b/packages/core/src/sdk/shipping/usePickupPoints.ts
index 24d2734c7e..61c081d41f 100644
--- a/packages/core/src/sdk/shipping/usePickupPoints.ts
+++ b/packages/core/src/sdk/shipping/usePickupPoints.ts
@@ -1,13 +1,13 @@
-import { useMemo } from 'react'
import { gql } from '@generated'
import type {
ClientPickupPointsQueryQuery,
ClientPickupPointsQueryQueryVariables,
} from '@generated/graphql'
+import { useMemo } from 'react'
import { deliveryPromise } from 'discovery.config'
-import { useSession } from 'src/sdk/session'
import { useQuery } from 'src/sdk/graphql/useQuery'
+import { useSession } from 'src/sdk/session'
export const query = gql(`
query ClientPickupPointsQuery(
@@ -24,9 +24,14 @@ export const query = gql(`
id
address {
street
+ number
+ postalCode
+ city
+ state
}
friendlyName
}
+ distance
}
}
}
@@ -65,9 +70,16 @@ export const usePickupPoints = () => {
const pickupPoints = data.pickupPoints.items.map((item) => ({
id: item.pickupPoint?.id,
- addressStreet: item.pickupPoint?.address?.street,
name: item.pickupPoint?.friendlyName,
totalItems: data.pickupPoints.paging.total,
+ address: {
+ street: item.pickupPoint?.address?.street,
+ number: item.pickupPoint?.address?.number,
+ postalCode: item.pickupPoint?.address?.postalCode,
+ city: item.pickupPoint?.address?.city,
+ state: item.pickupPoint?.address?.state,
+ },
+ distance: item.distance,
}))
return pickupPoints
diff --git a/packages/core/src/utils/globalSettings.ts b/packages/core/src/utils/globalSettings.ts
index 3f17d60e77..45401b9256 100644
--- a/packages/core/src/utils/globalSettings.ts
+++ b/packages/core/src/utils/globalSettings.ts
@@ -57,6 +57,16 @@ type DeliveryPromiseCmsData = {
icon?: string
alt?: string
}
+ regionSlider?: {
+ title?: {
+ setLocation?: string
+ changeLocation?: string
+ changePickupPoint?: string
+ }
+ pickupPointChangeApplyButtonLabel?: string
+ choosePickupPointAriaLabel?: string
+ noPickupPointsAvailableInLocation?: string
+ }
}
deliveryOptions?: {
enabled?: boolean
From 499339c8e2852ddacab90631849aecbacb424810 Mon Sep 17 00:00:00 2001
From: Fanny Chien
Date: Tue, 10 Jun 2025 12:17:35 -0300
Subject: [PATCH 12/25] chore: Renames to avoid mixing delivery methods with
delivery option (#2886)
Renames the `FilterDeliveryOption` component to clarify that it relates
to delivery methods.
---
.../search/Filter/FilterDeliveryOption.tsx | 68 -------------------
1 file changed, 68 deletions(-)
delete mode 100644 packages/core/src/components/search/Filter/FilterDeliveryOption.tsx
diff --git a/packages/core/src/components/search/Filter/FilterDeliveryOption.tsx b/packages/core/src/components/search/Filter/FilterDeliveryOption.tsx
deleted file mode 100644
index 6fdefd9cea..0000000000
--- a/packages/core/src/components/search/Filter/FilterDeliveryOption.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-import { regionSliderTypes, Button as UIButton, useUI } from '@faststore/ui'
-import { sessionStore } from 'src/sdk/session'
-import type { RegionalizationCmsData } from 'src/utils/globalSettings'
-import { textToTitleCase } from 'src/utils/utilities'
-
-interface FacetValue {
- value: string
- label: string
- selected: boolean
- quantity: number
-}
-
-interface FilterDeliveryOptionProps {
- item: FacetValue
- deliveryMethods: RegionalizationCmsData['deliverySettings']['deliveryMethods']
-}
-
-export default function FilterDeliveryOption({
- item,
- deliveryMethods,
-}: FilterDeliveryOptionProps) {
- const { city, postalCode } = sessionStore.read()
- const { openRegionSlider } = useUI()
-
- const location = city ? `${textToTitleCase(city)}, ${postalCode}` : postalCode
- const mapDeliveryMethodLabel: Record = {
- delivery: deliveryMethods?.delivery ?? 'Shipping to',
- 'pickup-in-point': deliveryMethods?.pickupInPoint ?? 'Pickup at',
- 'pickup-nearby': deliveryMethods?.pickupNearby ?? 'Pickup Nearby',
- 'pickup-all': deliveryMethods?.pickupAll?.label ?? 'Pickup Anywhere',
- }
-
- if (item.value === 'delivery') {
- return (
- <>
- {mapDeliveryMethodLabel[item.value]}
- {
- openRegionSlider(regionSliderTypes.changeLocation)
- }}
- >
- {location}
-
- >
- )
- }
-
- if (item.value === 'pickup-in-point') {
- return (
- <>
- {mapDeliveryMethodLabel[item.value]}
- {
- openRegionSlider(regionSliderTypes.changePickupPoint)
- }}
- >
- {item.label}
-
- >
- )
- }
-
- return <>{mapDeliveryMethodLabel[item.value]}>
-}
From 27ca8b431442ffe3ea8f10af16a2bcbb68bdcf85 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lar=C3=ADcia=20Mota?=
Date: Tue, 1 Jul 2025 11:41:50 -0300
Subject: [PATCH 13/25] chore: use global settings in RegionPopover and
RegionModal (#2918)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Make `RegionModal` and `RegionPopover` have access to global settings
(hCMS -> Global Sections -> Settings)
The Global Settings was created to remove duplications of messages in
hCMS. `RegionModal`, `RegionPopover` and filter componentes have some
messages in common that were being duplicated across sections and pages
in hCMS.
`FilterDesktop` and `FilterSlider` had already been modified to use
global settings in a previous PR, but they were only in the context of
PLP and Search pages, which is different from `RegionModal` and
`RegionPopover` that are global sections. Therefore, in this current PR
was necessary some changes related to page context, which involved
adding `PageProvider` to ALL pages (that's why there is a lot of
modified files) passing the globalSettings as its context.
The prioritization order is: first check if there is the message inside
the section, if not then use the message inside the global settings --
this avoids breaking changes.
I've made some changes in the hCMS in `vendemo` admin so we can see the
impact.
⚠️ Make sure to test all different types of pages, example: PLP, Search,
PDP, Landing Page, 404, 500.
In Global Settings, the input field label is "Postal Code", the error
message when there is no product available for the location has a "Oh
no!" in the beginning, and there is a message for the "I don't know my
postal code" link.
Differences:
- The input field label has a "!" in the end.
- There is no message for the error of no product available
What should happen: Since it was defined some messages in the section,
those messages should be gotten from the **section**. The only one that
should be from **global settings** is the one for the error of no
product available, therefore:
- The input field label should have a "!" in the end.
- The error message should be "Oh no! There are no products available
for %s." %s being replaced by the inserted postal code.
| Desktop | Mobile | Error |
| ---- | ---- | ---- |
| | | |
- The input field label has a "!" in the end.
- There is no message for the "I don't know my postal code" link.
What should happen: Since it was defined some messages in the section,
those messages should be gotten from the **section**. The only one that
should be from **global settings** is the one for the "I don't know my
postal code" link, therefore:
- The input field label should have a "!" in the end.
- The "I don't know my postal code" link message should be "I don't know
my Postal Code".
| Desktop | Mobile | Error |
| ---- | ---- | ---- |
| | | |
-
[Preview](https://vendemo-cm9sir9v900u7z6llkl62l70j-m66r5st5t.b.vtex.app/)
- [PR](https://github.com/dp-faststore-org/vendemo-dp/pull/39)
- [Jira task](https://vtex-dev.atlassian.net/browse/SFS-2524)
---
packages/core/src/sdk/overrides/PageProvider.tsx | 2 --
1 file changed, 2 deletions(-)
diff --git a/packages/core/src/sdk/overrides/PageProvider.tsx b/packages/core/src/sdk/overrides/PageProvider.tsx
index 8b143cc7d5..d33cc77044 100644
--- a/packages/core/src/sdk/overrides/PageProvider.tsx
+++ b/packages/core/src/sdk/overrides/PageProvider.tsx
@@ -23,7 +23,6 @@ export interface PLPContext extends PageGlobalContext {
ClientProductGalleryQueryQuery & {
pages: ClientManyProductsQueryQuery[]
}
- globalSectionsSettings?: Record
}
export interface SearchPageContext extends PageGlobalContext {
@@ -31,7 +30,6 @@ export interface SearchPageContext extends PageGlobalContext {
ClientProductGalleryQueryQuery & {
pages: ClientManyProductsQueryQuery[]
}
- globalSectionsSettings?: Record
}
export interface DynamicContent extends PageGlobalContext {
From d2d525c5313abc9e19de567565baf8eec095a91e Mon Sep 17 00:00:00 2001
From: Otavio Moreira Meirelles
Date: Thu, 3 Jul 2025 10:12:51 -0300
Subject: [PATCH 14/25] refactor: gathering delivery promise logic in one
single hook to allow usage by others (#2922)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Making the logic of deliveryPromise reusable by stores which extends our
components.
Created the `useDeliveryPromise` hook that exports all necessary logic
to use delivery promise.
Test if all the behaviour refactored in delivery promise is stil working
as intended.
You may erase this after checking them all :wink:
**PR Title and Commit Messages**
- [ ] PR title and commit messages follow the [Conventional
Commits](https://www.conventionalcommits.org/en/v1.0.0/) specification
- Available prefixes: `feat`, `fix`, `chore`, `docs`, `style`,
`refactor`, `ci` and `test`
**PR Description**
- [ ] Added a label according to the PR goal - `breaking change`, `bug`,
`contributing`, `performance`, `documentation`..
**Dependencies**
- [ ] Committed the `pnpm-lock.yaml` file when there were changes to the
packages
**Documentation**
- [ ] PR description
- [ ] For documentation changes, ping `@Mariana-Caetano` to review and
update (Or submit a doc request)
[SFS-2532](https://vtex-dev.atlassian.net/browse/SFS-2532)
[SFS-2532]:
https://vtex-dev.atlassian.net/browse/SFS-2532?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
---------
Co-authored-by: Lucas Feijó
Co-authored-by: Fanny Chien
Co-authored-by: Larícia Mota
Co-authored-by: Fanny Chien
---
.../core/src/components/search/Filter/FilterDesktop.tsx | 7 +++++++
.../core/src/components/search/Filter/FilterSlider.tsx | 7 +++++++
2 files changed, 14 insertions(+)
diff --git a/packages/core/src/components/search/Filter/FilterDesktop.tsx b/packages/core/src/components/search/Filter/FilterDesktop.tsx
index 546d76d4ae..40f264beec 100644
--- a/packages/core/src/components/search/Filter/FilterDesktop.tsx
+++ b/packages/core/src/components/search/Filter/FilterDesktop.tsx
@@ -217,4 +217,11 @@ export const fragment = gql(`
}
`)
+const RADIO_FACETS = ['shipping', 'pickupPoint'] as const
+function isRadioFacets(str: unknown): str is (typeof RADIO_FACETS)[number] {
+ if (typeof str !== 'string') return false
+
+ return RADIO_FACETS.some((el) => el === str)
+}
+
export default FilterDesktop
diff --git a/packages/core/src/components/search/Filter/FilterSlider.tsx b/packages/core/src/components/search/Filter/FilterSlider.tsx
index e152bfb5ff..4b31afdd94 100644
--- a/packages/core/src/components/search/Filter/FilterSlider.tsx
+++ b/packages/core/src/components/search/Filter/FilterSlider.tsx
@@ -280,4 +280,11 @@ function FilterSlider({
)
}
+const RADIO_FACETS = ['shipping', 'pickupPoint'] as const
+function isRadioFacets(str: unknown): str is (typeof RADIO_FACETS)[number] {
+ if (typeof str !== 'string') return false
+
+ return RADIO_FACETS.some((el) => el === str)
+}
+
export default FilterSlider
From f17c489b355321fdcc6e5a8a0c104893a02a0147 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lar=C3=ADcia=20Mota?=
Date: Fri, 11 Jul 2025 11:03:13 -0300
Subject: [PATCH 15/25] chore: Organize Delivery Promise config in global
settings (#2939)
Delivery Options will be added in feature branch 2.1 and the global
settings need a restructuring to support it and keep organized.
- Separate settings between `Regionalization` and `Delivery Promise`
- In `Delivery Promise` there are configs strict to DP
- In `Regionalization` there are configs that affects not only stores
with DP enabled.
- Rename `deliverySettings` to `deliveryMethods`
- Those configs were only related to Delivery Methods, but since we'll
introduce Delivery Options and Dynamic Estimate on feature branch 2.1 we
should change it.
- Move `regionSlider` from `deliverySettings` (which was renamed to
`deliveryMethods`) to inside of `deliveryPromise`
- Rename the `deliveryMethods` that was inside of `deliverySettings`
- Since `deliverySettings` was renamed to `deliveryMethods`, it doesn't
make sense to have another `deliveryMethods` inside. I've only moved
those configs to the new `deliveryMethods`.
Check that messages are coming correctly from hCMS Global Sections. If
testing RegionModal or RegionPopover, keep in mind that we merge the
deprecated configs from those sections to the ones in Global Sections
and the ones from the section takes precedence.
| Desktop | Mobile |
| ---- | ---- |
| | |
| | |
| | |
| | |
| | |
[PR](https://github.com/dp-faststore-org/vendemo-dp/pull/48)
Preview: https://vendemo-cm9sir9v900u7z6llkl62l70j-j25zty24c.b.vtex.app/
- [Jira task](https://vtex-dev.atlassian.net/browse/SFS-2639)
- [Slack
thread](https://my.slack.com/archives/C08SZUBMFDK/p1752080463304509)
---
.../core/cms/faststore/content-types.json | 55 +++++--------------
.../ui/ProductGallery/ProductGallery.tsx | 3 -
.../sdk/deliveryPromise/useDeliveryPromise.ts | 1 -
packages/core/src/utils/globalSettings.ts | 10 ----
4 files changed, 14 insertions(+), 55 deletions(-)
diff --git a/packages/core/cms/faststore/content-types.json b/packages/core/cms/faststore/content-types.json
index 2948b71a4c..926bb23a83 100644
--- a/packages/core/cms/faststore/content-types.json
+++ b/packages/core/cms/faststore/content-types.json
@@ -233,47 +233,20 @@
}
}
},
- "regionSlider": {
- "title": "RegionSlider SlideOver",
- "type": "object",
- "properties": {
- "title": {
- "title": "RegionSlider title",
- "type": "object",
- "properties": {
- "setLocation": {
- "title": "Set Location title",
- "type": "string",
- "default": "Set Location"
- },
- "changeLocation": {
- "title": "Change Postal Code title",
- "type": "string",
- "default": "Change Location"
- },
- "changePickupPoint": {
- "title": "Change Pickup Point location title",
- "type": "string",
- "default": "Change Store"
- }
- }
- },
- "pickupPointChangeApplyButtonLabel": {
- "title": "Change Pickup Point apply button label",
- "type": "string",
- "default": "Update"
- },
- "choosePickupPointAriaLabel": {
- "title": "Choose Pickup Point aria-label (radio group)",
- "type": "string",
- "default": "Choose a store"
- },
- "noPickupPointsAvailableInLocation": {
- "title": "No Pickup Point available near location message",
- "type": "string",
- "default": "No stores near location."
- }
- }
+ "pickupPointChangeApplyButtonLabel": {
+ "title": "Change Pickup Point apply button label",
+ "type": "string",
+ "default": "Update"
+ },
+ "choosePickupPointAriaLabel": {
+ "title": "Choose Pickup Point aria-label (radio group)",
+ "type": "string",
+ "default": "Choose a store"
+ },
+ "noPickupPointsAvailableInLocation": {
+ "title": "No Pickup Point available near location message",
+ "type": "string",
+ "default": "No stores near location."
}
}
},
diff --git a/packages/core/src/components/ui/ProductGallery/ProductGallery.tsx b/packages/core/src/components/ui/ProductGallery/ProductGallery.tsx
index c4939f9c73..18d2b7d60b 100644
--- a/packages/core/src/components/ui/ProductGallery/ProductGallery.tsx
+++ b/packages/core/src/components/ui/ProductGallery/ProductGallery.tsx
@@ -55,7 +55,6 @@ export interface ProductGalleryProps {
clearButtonLabel: FilterSliderProps['clearButtonLabel']
applyButtonLabel: FilterSliderProps['applyButtonLabel']
}
- deliverySettings?: FilterSliderProps['deliverySettings']
}
previousPageButton?: {
label?: string
@@ -175,7 +174,6 @@ function ProductGallery({
{...FilterDesktop.props}
{...filter}
title={filterCmsData?.title}
- deliverySettings={filterCmsData?.deliverySettings}
/>
)}
@@ -190,7 +188,6 @@ function ProductGallery({
title={filterCmsData?.title}
clearButtonLabel={filterCmsData?.mobileOnly?.clearButtonLabel}
applyButtonLabel={filterCmsData?.mobileOnly?.applyButtonLabel}
- deliverySettings={filterCmsData?.deliverySettings}
/>
)}
diff --git a/packages/core/src/sdk/deliveryPromise/useDeliveryPromise.ts b/packages/core/src/sdk/deliveryPromise/useDeliveryPromise.ts
index 04d76deeb3..d9223b2421 100644
--- a/packages/core/src/sdk/deliveryPromise/useDeliveryPromise.ts
+++ b/packages/core/src/sdk/deliveryPromise/useDeliveryPromise.ts
@@ -12,7 +12,6 @@ import type {
DeliveryPromiseBadge,
Filter_FacetsFragment,
} from '@generated/graphql'
-
import type { useFilter } from 'src/sdk/search/useFilter'
import type { GlobalCmsData } from 'src/utils/globalSettings'
diff --git a/packages/core/src/utils/globalSettings.ts b/packages/core/src/utils/globalSettings.ts
index 45401b9256..3f17d60e77 100644
--- a/packages/core/src/utils/globalSettings.ts
+++ b/packages/core/src/utils/globalSettings.ts
@@ -57,16 +57,6 @@ type DeliveryPromiseCmsData = {
icon?: string
alt?: string
}
- regionSlider?: {
- title?: {
- setLocation?: string
- changeLocation?: string
- changePickupPoint?: string
- }
- pickupPointChangeApplyButtonLabel?: string
- choosePickupPointAriaLabel?: string
- noPickupPointsAvailableInLocation?: string
- }
}
deliveryOptions?: {
enabled?: boolean
From a18c025476ac20381239b898bf7a3330da5ac163 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lucas=20Feij=C3=B3?=
Date: Tue, 15 Jul 2025 11:10:43 -0300
Subject: [PATCH 16/25] feat: Global filter by pickup point (SFS-2458) (#2887)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Revision order:
1) #2889
2) #2890
These changes will introduce global filtering by pickup point for the
selected zip code.
We are changing the `RegionSlider` opening: the component it's a global
section now, so it should be able to be rendered everywhere in the
store, still using the `UI Provider` actions but no longer need to
import it.
Furthermore, we made adjustments to the the `RegionBar` component,
adding new data-atributes and matching new design prototype, but we keep
backward compatibility by leaving the current props and data-attributes
unaltered.
Although, the core of this implementation it's to support global
filtering (including shelves' queries) by available pickup points, and
for that we created the Delivery Promise's reducer and provider to
handle this global context through shopper navigation, leveraging from
the `useDeliveryPromise` hook towards managing all state and actions.
First, you can use the Starter preview below, but for local development
you'll need to use the `vendemo` account we already set up for Delivery
Promise: on `discovery.config` you should change the following
attributes:
- `api: { storeId: 'vendemo', ... }`;
- `session: { currency: { code: 'BRL', symbol: 'R$' }, locale: 'pt-BR',
country: 'BRA', ... }`;
- `deliveryPromise: { enabled: true, mandatory: false }`;
After that, specify one of the following zip codes (using the
`RegionButton` on the navbar) to test Delivery Promise features:
`50030-260`, `20070-001` or `04538-132`.
Then, try to set a global pickup point and see if the store name is
added on the navbar, navigate to PLP and you should see the `Delivery`
facet section, you can filter by other methods. Everything should keep
working as before. Also, try the mobile version.
vtex-sites/faststoreqa.store#834
---------
Co-authored-by: Larícia Mota
Co-authored-by: Fanny Chien
---
packages/core/@generated/gql.ts | 8 --
packages/core/cms/faststore/sections.json | 16 ++++
.../region/RegionSlider/RegionSlider.tsx | 1 +
.../search/Filter/FilterDesktop.tsx | 7 --
.../components/search/Filter/FilterSlider.tsx | 7 --
.../core/src/sdk/overrides/PageProvider.tsx | 4 +
.../core/src/sdk/shipping/usePickupPoints.ts | 86 -------------------
7 files changed, 21 insertions(+), 108 deletions(-)
delete mode 100644 packages/core/src/sdk/shipping/usePickupPoints.ts
diff --git a/packages/core/@generated/gql.ts b/packages/core/@generated/gql.ts
index 08d4e0209e..ec38337920 100644
--- a/packages/core/@generated/gql.ts
+++ b/packages/core/@generated/gql.ts
@@ -90,8 +90,6 @@ const documents = {
types.ValidateSessionDocument,
'\n query ClientShippingSimulationQuery(\n $postalCode: String!\n $country: String!\n $items: [IShippingItem!]!\n ) {\n ...ClientShippingSimulation\n shipping(items: $items, postalCode: $postalCode, country: $country) {\n logisticsInfo {\n slas {\n carrier\n price\n availableDeliveryWindows {\n startDateUtc\n endDateUtc\n price\n listPrice\n }\n shippingEstimate\n localizedEstimates\n deliveryChannel\n }\n }\n address {\n city\n neighborhood\n state\n }\n }\n }\n':
types.ClientShippingSimulationQueryDocument,
- '\n query ClientPickupPointsQuery(\n $geoCoordinates: IStoreGeoCoordinates\n $postalCode: String\n $country: String\n ) {\n pickupPoints(geoCoordinates: $geoCoordinates, postalCode: $postalCode, country: $country) {\n paging {\n total\n }\n items {\n pickupPoint {\n id\n address {\n street\n number\n postalCode\n city\n state\n }\n friendlyName\n }\n distance\n }\n }\n }\n':
- types.ClientPickupPointsQueryDocument,
'\n query ServerManyProductsQuery(\n $first: Int!\n $after: String\n $sort: StoreSort!\n $term: String!\n $selectedFacets: [IStoreSelectedFacet!]!\n $sponsoredCount: Int\n ) {\n ...ClientManyProducts\n search(\n first: $first\n after: $after\n sort: $sort\n term: $term\n selectedFacets: $selectedFacets\n sponsoredCount: $sponsoredCount\n ) {\n products {\n pageInfo {\n totalCount\n }\n edges {\n node {\n ...ProductSummary_product\n }\n }\n }\n metadata {\n ...SearchEvent_metadata\n }\n }\n }\n':
types.ServerManyProductsQueryDocument,
}
@@ -330,12 +328,6 @@ export function gql(
export function gql(
source: '\n query ClientShippingSimulationQuery(\n $postalCode: String!\n $country: String!\n $items: [IShippingItem!]!\n ) {\n ...ClientShippingSimulation\n shipping(items: $items, postalCode: $postalCode, country: $country) {\n logisticsInfo {\n slas {\n carrier\n price\n availableDeliveryWindows {\n startDateUtc\n endDateUtc\n price\n listPrice\n }\n shippingEstimate\n localizedEstimates\n deliveryChannel\n }\n }\n address {\n city\n neighborhood\n state\n }\n }\n }\n'
): typeof import('./graphql').ClientShippingSimulationQueryDocument
-/**
- * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
- */
-export function gql(
- source: '\n query ClientPickupPointsQuery(\n $geoCoordinates: IStoreGeoCoordinates\n $postalCode: String\n $country: String\n ) {\n pickupPoints(geoCoordinates: $geoCoordinates, postalCode: $postalCode, country: $country) {\n paging {\n total\n }\n items {\n pickupPoint {\n id\n address {\n street\n number\n postalCode\n city\n state\n }\n friendlyName\n }\n distance\n }\n }\n }\n'
-): typeof import('./graphql').ClientPickupPointsQueryDocument
/**
* The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
diff --git a/packages/core/cms/faststore/sections.json b/packages/core/cms/faststore/sections.json
index 65e2afe751..00a021e82d 100644
--- a/packages/core/cms/faststore/sections.json
+++ b/packages/core/cms/faststore/sections.json
@@ -2474,6 +2474,22 @@
}
}
},
+ {
+ "name": "RegionSlider",
+ "requiredScopes": [],
+ "schema": {
+ "title": "Region Slider",
+ "type": "object",
+ "description": "Region Slider configuration",
+ "properties": {
+ "enabled": {
+ "type": "boolean",
+ "title": "Should enable Region Slider?",
+ "default": true
+ }
+ }
+ }
+ },
{
"name": "EmptyState",
"schema": {
diff --git a/packages/core/src/components/region/RegionSlider/RegionSlider.tsx b/packages/core/src/components/region/RegionSlider/RegionSlider.tsx
index f6ee366690..81944016f1 100644
--- a/packages/core/src/components/region/RegionSlider/RegionSlider.tsx
+++ b/packages/core/src/components/region/RegionSlider/RegionSlider.tsx
@@ -117,6 +117,7 @@ function RegionSlider() {
const idkPostalCodeLink = cmsData?.regionalization?.idkPostalCodeLink
const handleSubmit = async () => {
+ setDataLoading(true)
setAppliedInput(input)
if (isValidating) {
diff --git a/packages/core/src/components/search/Filter/FilterDesktop.tsx b/packages/core/src/components/search/Filter/FilterDesktop.tsx
index 40f264beec..546d76d4ae 100644
--- a/packages/core/src/components/search/Filter/FilterDesktop.tsx
+++ b/packages/core/src/components/search/Filter/FilterDesktop.tsx
@@ -217,11 +217,4 @@ export const fragment = gql(`
}
`)
-const RADIO_FACETS = ['shipping', 'pickupPoint'] as const
-function isRadioFacets(str: unknown): str is (typeof RADIO_FACETS)[number] {
- if (typeof str !== 'string') return false
-
- return RADIO_FACETS.some((el) => el === str)
-}
-
export default FilterDesktop
diff --git a/packages/core/src/components/search/Filter/FilterSlider.tsx b/packages/core/src/components/search/Filter/FilterSlider.tsx
index 4b31afdd94..e152bfb5ff 100644
--- a/packages/core/src/components/search/Filter/FilterSlider.tsx
+++ b/packages/core/src/components/search/Filter/FilterSlider.tsx
@@ -280,11 +280,4 @@ function FilterSlider({
)
}
-const RADIO_FACETS = ['shipping', 'pickupPoint'] as const
-function isRadioFacets(str: unknown): str is (typeof RADIO_FACETS)[number] {
- if (typeof str !== 'string') return false
-
- return RADIO_FACETS.some((el) => el === str)
-}
-
export default FilterSlider
diff --git a/packages/core/src/sdk/overrides/PageProvider.tsx b/packages/core/src/sdk/overrides/PageProvider.tsx
index d33cc77044..11529c5978 100644
--- a/packages/core/src/sdk/overrides/PageProvider.tsx
+++ b/packages/core/src/sdk/overrides/PageProvider.tsx
@@ -16,6 +16,7 @@ interface PageGlobalContext {
export interface PDPContext extends PageGlobalContext {
data?: ServerProductQueryQuery &
ClientProductQueryQuery['product'] & { isValidating?: boolean }
+ globalSectionsSettings?: Record
}
export interface PLPContext extends PageGlobalContext {
@@ -23,6 +24,7 @@ export interface PLPContext extends PageGlobalContext {
ClientProductGalleryQueryQuery & {
pages: ClientManyProductsQueryQuery[]
}
+ globalSectionsSettings?: Record
}
export interface SearchPageContext extends PageGlobalContext {
@@ -30,10 +32,12 @@ export interface SearchPageContext extends PageGlobalContext {
ClientProductGalleryQueryQuery & {
pages: ClientManyProductsQueryQuery[]
}
+ globalSectionsSettings?: Record
}
export interface DynamicContent extends PageGlobalContext {
data?: T
+ globalSectionsSettings?: Record
}
export interface PageProviderContextValue {
diff --git a/packages/core/src/sdk/shipping/usePickupPoints.ts b/packages/core/src/sdk/shipping/usePickupPoints.ts
deleted file mode 100644
index 61c081d41f..0000000000
--- a/packages/core/src/sdk/shipping/usePickupPoints.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-import { gql } from '@generated'
-import type {
- ClientPickupPointsQueryQuery,
- ClientPickupPointsQueryQueryVariables,
-} from '@generated/graphql'
-import { useMemo } from 'react'
-
-import { deliveryPromise } from 'discovery.config'
-import { useQuery } from 'src/sdk/graphql/useQuery'
-import { useSession } from 'src/sdk/session'
-
-export const query = gql(`
- query ClientPickupPointsQuery(
- $geoCoordinates: IStoreGeoCoordinates
- $postalCode: String
- $country: String
- ) {
- pickupPoints(geoCoordinates: $geoCoordinates, postalCode: $postalCode, country: $country) {
- paging {
- total
- }
- items {
- pickupPoint {
- id
- address {
- street
- number
- postalCode
- city
- state
- }
- friendlyName
- }
- distance
- }
- }
- }
-`)
-
-export const usePickupPoints = () => {
- if (!deliveryPromise.enabled) {
- return null
- }
-
- const { country, postalCode, geoCoordinates } = useSession()
-
- if (!geoCoordinates && (!postalCode || !country)) {
- return null
- }
-
- const variables = useMemo(
- () => ({
- country: !!geoCoordinates ? undefined : country,
- geoCoordinates: geoCoordinates ?? undefined,
- postalCode: !!geoCoordinates ? undefined : postalCode,
- }),
- [country, geoCoordinates, postalCode]
- )
-
- const { data } = useQuery<
- ClientPickupPointsQueryQuery,
- ClientPickupPointsQueryQueryVariables
- >(query, variables, {
- fallbackData: null,
- })
-
- if (!data) {
- return null
- }
-
- const pickupPoints = data.pickupPoints.items.map((item) => ({
- id: item.pickupPoint?.id,
- name: item.pickupPoint?.friendlyName,
- totalItems: data.pickupPoints.paging.total,
- address: {
- street: item.pickupPoint?.address?.street,
- number: item.pickupPoint?.address?.number,
- postalCode: item.pickupPoint?.address?.postalCode,
- city: item.pickupPoint?.address?.city,
- state: item.pickupPoint?.address?.state,
- },
- distance: item.distance,
- }))
-
- return pickupPoints
-}
From ec03fc3e66f8c9f62745db2647824ac014d76e2e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lucas=20Feij=C3=B3?=
Date: Thu, 17 Jul 2025 09:20:39 -0300
Subject: [PATCH 17/25] feat: Add `RegionSlider` clear filter button (#2944)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## What's the purpose of this pull request?
With these changes, the shopper will be able to clear current pickup
points filters in the `RegionSlider` component.
## How it works?
This button will be displayed only when shopper is changing pickup
points (selected or global ones).
Than for applied filters it will clear everything, including from
selected facets.
## How to test it?
First, you can use the Starter preview below, but for local development
you'll need to use the `vendemo` account we already set up for Delivery
Promise: on `discovery.config` you should change the following
attributes:
- `api: { storeId: 'vendemo', ... }`;
- `session: { currency: { code: 'BRL', symbol: 'R$' }, locale: 'pt-BR',
country: 'BRA', ... }`;
- `deliveryPromise: { enabled: true, mandatory: false }`;
After that, specify one of the following zip codes (using the
`RegionButton` on the navbar) to test Delivery Promise features:
`50030-260`, `20070-001` or `04538-132`.
Then, try opening the `RegionSlider` and applying some pickup points and
clearing the filter. The `RegionSlider` should not close after clear
filters and all the state should be reset: `selectedFacets` should not
have the previously selected pickup point, and both `globalPickupPoint`
and `defaultSelectedPickup` also should be reset.
### Starters Deploy Preview
vtex-sites/faststoreqa.store#838
---------
Co-authored-by: Larícia Mota
Co-authored-by: Fanny Chien
---
.../core/src/components/region/RegionSlider/RegionSlider.tsx | 3 ---
1 file changed, 3 deletions(-)
diff --git a/packages/core/src/components/region/RegionSlider/RegionSlider.tsx b/packages/core/src/components/region/RegionSlider/RegionSlider.tsx
index 81944016f1..51a2d723d2 100644
--- a/packages/core/src/components/region/RegionSlider/RegionSlider.tsx
+++ b/packages/core/src/components/region/RegionSlider/RegionSlider.tsx
@@ -117,9 +117,6 @@ function RegionSlider() {
const idkPostalCodeLink = cmsData?.regionalization?.idkPostalCodeLink
const handleSubmit = async () => {
- setDataLoading(true)
- setAppliedInput(input)
-
if (isValidating) {
return
}
From f7f589d230ded9c1ec3956071b42d1837ae89bb2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lar=C3=ADcia=20Mota?=
Date: Thu, 24 Jul 2025 11:17:34 -0300
Subject: [PATCH 18/25] fix: change pickup points endpoint (#2955)
We should use the endpoint from logistics to have access to the active
pickup points.
This endpoints returns the `isActive` info that we can use to filter the
results and only show to the shopper the active pickup points.
Test CEPs from Recife and RJ, the first one should have a valid pickup
point, while RJ shouldn't show anything in the pickup list since all
pickup points in `vendemo` account that could work for RJ are inactive.
| Recife | Rio de Janeiro |
| ---- | ---- |
| | |
PR: https://github.com/dp-faststore-org/vendemo-dp/pull/56
Preview: https://vendemo-cm9sir9v900u7z6llkl62l70j-9iq2gg4ij.b.vtex.app/
[Jira task](https://vtex-dev.atlassian.net/browse/SFS-2678)
---
.../core/src/components/ui/PickupPoints/PickupPointCard.tsx | 4 +---
packages/core/src/sdk/deliveryPromise/useDeliveryPromise.ts | 4 +---
2 files changed, 2 insertions(+), 6 deletions(-)
diff --git a/packages/core/src/components/ui/PickupPoints/PickupPointCard.tsx b/packages/core/src/components/ui/PickupPoints/PickupPointCard.tsx
index 4bd7d5c10b..bfd4ee11d6 100644
--- a/packages/core/src/components/ui/PickupPoints/PickupPointCard.tsx
+++ b/packages/core/src/components/ui/PickupPoints/PickupPointCard.tsx
@@ -24,9 +24,7 @@ function PickupPointCard({ store }: PickupPointCardProps) {
{store?.address?.street}, {store?.address?.number}
-
- {store?.address?.city} - {store?.address?.state}
-
+ {store?.address?.city}
{store?.distance !== undefined ? formatDistance(store.distance) : ''}
diff --git a/packages/core/src/sdk/deliveryPromise/useDeliveryPromise.ts b/packages/core/src/sdk/deliveryPromise/useDeliveryPromise.ts
index d9223b2421..c7ab7ffd8a 100644
--- a/packages/core/src/sdk/deliveryPromise/useDeliveryPromise.ts
+++ b/packages/core/src/sdk/deliveryPromise/useDeliveryPromise.ts
@@ -13,9 +13,8 @@ import type {
Filter_FacetsFragment,
} from '@generated/graphql'
import type { useFilter } from 'src/sdk/search/useFilter'
-import type { GlobalCmsData } from 'src/utils/globalSettings'
-
import { useSession } from 'src/sdk/session'
+import type { GlobalCmsData } from 'src/utils/globalSettings'
import { deliveryPromise as deliveryPromiseConfig } from 'discovery.config'
import {
@@ -45,7 +44,6 @@ export type PickupPoint = {
number?: string
postalCode?: string
city?: string
- state?: string
}
distance?: number
totalItems?: number
From e01ab650de91cb01b3372022b848d21c3def248c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lar=C3=ADcia=20Mota?=
Date: Thu, 24 Jul 2025 16:40:55 -0300
Subject: [PATCH 19/25] Fix after rebase
---
packages/core/src/sdk/overrides/PageProvider.tsx | 4 ----
1 file changed, 4 deletions(-)
diff --git a/packages/core/src/sdk/overrides/PageProvider.tsx b/packages/core/src/sdk/overrides/PageProvider.tsx
index 11529c5978..d33cc77044 100644
--- a/packages/core/src/sdk/overrides/PageProvider.tsx
+++ b/packages/core/src/sdk/overrides/PageProvider.tsx
@@ -16,7 +16,6 @@ interface PageGlobalContext {
export interface PDPContext extends PageGlobalContext {
data?: ServerProductQueryQuery &
ClientProductQueryQuery['product'] & { isValidating?: boolean }
- globalSectionsSettings?: Record
}
export interface PLPContext extends PageGlobalContext {
@@ -24,7 +23,6 @@ export interface PLPContext extends PageGlobalContext {
ClientProductGalleryQueryQuery & {
pages: ClientManyProductsQueryQuery[]
}
- globalSectionsSettings?: Record
}
export interface SearchPageContext extends PageGlobalContext {
@@ -32,12 +30,10 @@ export interface SearchPageContext extends PageGlobalContext {
ClientProductGalleryQueryQuery & {
pages: ClientManyProductsQueryQuery[]
}
- globalSectionsSettings?: Record
}
export interface DynamicContent extends PageGlobalContext {
data?: T
- globalSectionsSettings?: Record
}
export interface PageProviderContextValue {
From e7b27161459530c469ffaba89f81b12a35e20cac Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lucas=20Feij=C3=B3?=
Date: Fri, 30 May 2025 09:44:43 -0300
Subject: [PATCH 20/25] feat: Shipping methods integration (#2847)
This PR contains the shipping methods integration with API.
We already have some of the shipping facets being rendered, but no
action was being made. After these changes, the filters should work
depending on the selected scenario.
The `usePickupPoints` hook is responsible to get the list of pickup
points available for the specific location in session. Based on that
list, we create the `pickup-in-point` facet on the client-side (it's not
delivered by the IS API) and inject on the facets list.
When the `pickup-in-point` is selected, a additional facet called
`pickupPoint` is also added on the facets list, then on the Search
client (`@faststore/api`) we transform it on query string param and send
it in the `product_search` IS request.
| Desktop | Mobile |
| - | - |
| 
| 
|
- Use the following postal code: `50030-260`;
- Pay attention to the behavior of each different filter: each one must
send the correct parameters/variables in the query (check the `Network`
tab);
- Observe the behavior and visibility of the filters on both desktop and
mobile, the logic is similar but they have some different details that
can impact navigation;
vtex-sites/faststoreqa.store#812
---
packages/api/src/__generated__/schema.ts | 20 +++++
packages/core/@generated/gql.ts | 8 ++
packages/core/@generated/graphql.ts | 46 ++++++++++++
.../core/src/sdk/shipping/usePickupPoints.ts | 74 +++++++++++++++++++
4 files changed, 148 insertions(+)
create mode 100644 packages/core/src/sdk/shipping/usePickupPoints.ts
diff --git a/packages/api/src/__generated__/schema.ts b/packages/api/src/__generated__/schema.ts
index 567094dc4b..76f0dda9c4 100644
--- a/packages/api/src/__generated__/schema.ts
+++ b/packages/api/src/__generated__/schema.ts
@@ -590,6 +590,14 @@ export type IUserOrderCancel = {
reason?: Maybe;
};
+export type Item = {
+ __typename?: 'Item';
+ /** Pickup point distance. */
+ distance?: Maybe;
+ /** Pickup point. */
+ pickupPoint?: Maybe;
+};
+
export type LogisticsInfo = {
__typename?: 'LogisticsInfo';
/** LogisticsInfo itemIndex. */
@@ -695,6 +703,18 @@ export type MutationValidateSessionArgs = {
session: IStoreSession;
};
+export type Paging = {
+ __typename?: 'Paging';
+ /** Current page. */
+ page?: Maybe;
+ /** Number of items per page. */
+ pageSize?: Maybe;
+ /** Total number of pages. */
+ pages?: Maybe;
+ /** Total number of items. */
+ total?: Maybe;
+};
+
/** Newsletter information. */
export type PersonNewsletter = {
__typename?: 'PersonNewsletter';
diff --git a/packages/core/@generated/gql.ts b/packages/core/@generated/gql.ts
index ec38337920..cbd6890856 100644
--- a/packages/core/@generated/gql.ts
+++ b/packages/core/@generated/gql.ts
@@ -90,6 +90,8 @@ const documents = {
types.ValidateSessionDocument,
'\n query ClientShippingSimulationQuery(\n $postalCode: String!\n $country: String!\n $items: [IShippingItem!]!\n ) {\n ...ClientShippingSimulation\n shipping(items: $items, postalCode: $postalCode, country: $country) {\n logisticsInfo {\n slas {\n carrier\n price\n availableDeliveryWindows {\n startDateUtc\n endDateUtc\n price\n listPrice\n }\n shippingEstimate\n localizedEstimates\n deliveryChannel\n }\n }\n address {\n city\n neighborhood\n state\n }\n }\n }\n':
types.ClientShippingSimulationQueryDocument,
+ '\n query ClientPickupPointsQuery(\n $geoCoordinates: IStoreGeoCoordinates\n $postalCode: String\n $country: String\n ) {\n pickupPoints(geoCoordinates: $geoCoordinates, postalCode: $postalCode, country: $country) {\n paging {\n total\n }\n items {\n pickupPoint {\n id\n address {\n street\n }\n friendlyName\n }\n }\n }\n }\n':
+ types.ClientPickupPointsQueryDocument,
'\n query ServerManyProductsQuery(\n $first: Int!\n $after: String\n $sort: StoreSort!\n $term: String!\n $selectedFacets: [IStoreSelectedFacet!]!\n $sponsoredCount: Int\n ) {\n ...ClientManyProducts\n search(\n first: $first\n after: $after\n sort: $sort\n term: $term\n selectedFacets: $selectedFacets\n sponsoredCount: $sponsoredCount\n ) {\n products {\n pageInfo {\n totalCount\n }\n edges {\n node {\n ...ProductSummary_product\n }\n }\n }\n metadata {\n ...SearchEvent_metadata\n }\n }\n }\n':
types.ServerManyProductsQueryDocument,
}
@@ -328,6 +330,12 @@ export function gql(
export function gql(
source: '\n query ClientShippingSimulationQuery(\n $postalCode: String!\n $country: String!\n $items: [IShippingItem!]!\n ) {\n ...ClientShippingSimulation\n shipping(items: $items, postalCode: $postalCode, country: $country) {\n logisticsInfo {\n slas {\n carrier\n price\n availableDeliveryWindows {\n startDateUtc\n endDateUtc\n price\n listPrice\n }\n shippingEstimate\n localizedEstimates\n deliveryChannel\n }\n }\n address {\n city\n neighborhood\n state\n }\n }\n }\n'
): typeof import('./graphql').ClientShippingSimulationQueryDocument
+/**
+ * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
+ */
+export function gql(
+ source: '\n query ClientPickupPointsQuery(\n $geoCoordinates: IStoreGeoCoordinates\n $postalCode: String\n $country: String\n ) {\n pickupPoints(geoCoordinates: $geoCoordinates, postalCode: $postalCode, country: $country) {\n paging {\n total\n }\n items {\n pickupPoint {\n id\n address {\n street\n }\n friendlyName\n }\n }\n }\n }\n'
+): typeof import('./graphql').ClientPickupPointsQueryDocument
/**
* The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
diff --git a/packages/core/@generated/graphql.ts b/packages/core/@generated/graphql.ts
index 3063cdc63d..347961e4dd 100644
--- a/packages/core/@generated/graphql.ts
+++ b/packages/core/@generated/graphql.ts
@@ -591,6 +591,13 @@ export type IUserOrderCancel = {
reason: InputMaybe
}
+export type Item = {
+ /** Pickup point distance. */
+ distance: Maybe
+ /** Pickup point. */
+ pickupPoint: Maybe
+}
+
export type LogisticsInfo = {
/** LogisticsInfo itemIndex. */
itemIndex: Maybe
@@ -686,6 +693,17 @@ export type MutationValidateSessionArgs = {
session: IStoreSession
}
+export type Paging = {
+ /** Current page. */
+ page: Maybe
+ /** Number of items per page. */
+ pageSize: Maybe
+ /** Total number of pages. */
+ pages: Maybe
+ /** Total number of items. */
+ total: Maybe
+}
+
/** Newsletter information. */
export type PersonNewsletter = {
/** Person's ID in the newsletter list. */
@@ -3642,6 +3660,25 @@ export type ClientShippingSimulationQueryQuery = {
} | null
}
+export type ClientPickupPointsQueryQueryVariables = Exact<{
+ geoCoordinates: InputMaybe
+ postalCode: InputMaybe
+ country: InputMaybe
+}>
+
+export type ClientPickupPointsQueryQuery = {
+ pickupPoints: {
+ paging: { total: number | null } | null
+ items: Array<{
+ pickupPoint: {
+ id: string | null
+ friendlyName: string | null
+ address: { street: string | null } | null
+ } | null
+ } | null> | null
+ } | null
+}
+
export type ServerManyProductsQueryQueryVariables = Exact<{
first: Scalars['Int']['input']
after: InputMaybe
@@ -4510,6 +4547,15 @@ export const ClientShippingSimulationQueryDocument = {
ClientShippingSimulationQueryQuery,
ClientShippingSimulationQueryQueryVariables
>
+export const ClientPickupPointsQueryDocument = {
+ __meta__: {
+ operationName: 'ClientPickupPointsQuery',
+ operationHash: '0267c77a87cb0592dfd9a73bad8f632c1801541b',
+ },
+} as unknown as TypedDocumentString<
+ ClientPickupPointsQueryQuery,
+ ClientPickupPointsQueryQueryVariables
+>
export const ServerManyProductsQueryDocument = {
__meta__: {
operationName: 'ServerManyProductsQuery',
diff --git a/packages/core/src/sdk/shipping/usePickupPoints.ts b/packages/core/src/sdk/shipping/usePickupPoints.ts
new file mode 100644
index 0000000000..24d2734c7e
--- /dev/null
+++ b/packages/core/src/sdk/shipping/usePickupPoints.ts
@@ -0,0 +1,74 @@
+import { useMemo } from 'react'
+import { gql } from '@generated'
+import type {
+ ClientPickupPointsQueryQuery,
+ ClientPickupPointsQueryQueryVariables,
+} from '@generated/graphql'
+
+import { deliveryPromise } from 'discovery.config'
+import { useSession } from 'src/sdk/session'
+import { useQuery } from 'src/sdk/graphql/useQuery'
+
+export const query = gql(`
+ query ClientPickupPointsQuery(
+ $geoCoordinates: IStoreGeoCoordinates
+ $postalCode: String
+ $country: String
+ ) {
+ pickupPoints(geoCoordinates: $geoCoordinates, postalCode: $postalCode, country: $country) {
+ paging {
+ total
+ }
+ items {
+ pickupPoint {
+ id
+ address {
+ street
+ }
+ friendlyName
+ }
+ }
+ }
+ }
+`)
+
+export const usePickupPoints = () => {
+ if (!deliveryPromise.enabled) {
+ return null
+ }
+
+ const { country, postalCode, geoCoordinates } = useSession()
+
+ if (!geoCoordinates && (!postalCode || !country)) {
+ return null
+ }
+
+ const variables = useMemo(
+ () => ({
+ country: !!geoCoordinates ? undefined : country,
+ geoCoordinates: geoCoordinates ?? undefined,
+ postalCode: !!geoCoordinates ? undefined : postalCode,
+ }),
+ [country, geoCoordinates, postalCode]
+ )
+
+ const { data } = useQuery<
+ ClientPickupPointsQueryQuery,
+ ClientPickupPointsQueryQueryVariables
+ >(query, variables, {
+ fallbackData: null,
+ })
+
+ if (!data) {
+ return null
+ }
+
+ const pickupPoints = data.pickupPoints.items.map((item) => ({
+ id: item.pickupPoint?.id,
+ addressStreet: item.pickupPoint?.address?.street,
+ name: item.pickupPoint?.friendlyName,
+ totalItems: data.pickupPoints.paging.total,
+ }))
+
+ return pickupPoints
+}
From bec3ad12c97e62481ac856ee978d938be4f71eca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lucas=20Feij=C3=B3?=
Date: Tue, 15 Jul 2025 11:10:43 -0300
Subject: [PATCH 21/25] feat: Global filter by pickup point (SFS-2458) (#2887)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Revision order:
1) #2889
2) #2890
These changes will introduce global filtering by pickup point for the
selected zip code.
We are changing the `RegionSlider` opening: the component it's a global
section now, so it should be able to be rendered everywhere in the
store, still using the `UI Provider` actions but no longer need to
import it.
Furthermore, we made adjustments to the the `RegionBar` component,
adding new data-atributes and matching new design prototype, but we keep
backward compatibility by leaving the current props and data-attributes
unaltered.
Although, the core of this implementation it's to support global
filtering (including shelves' queries) by available pickup points, and
for that we created the Delivery Promise's reducer and provider to
handle this global context through shopper navigation, leveraging from
the `useDeliveryPromise` hook towards managing all state and actions.
First, you can use the Starter preview below, but for local development
you'll need to use the `vendemo` account we already set up for Delivery
Promise: on `discovery.config` you should change the following
attributes:
- `api: { storeId: 'vendemo', ... }`;
- `session: { currency: { code: 'BRL', symbol: 'R$' }, locale: 'pt-BR',
country: 'BRA', ... }`;
- `deliveryPromise: { enabled: true, mandatory: false }`;
After that, specify one of the following zip codes (using the
`RegionButton` on the navbar) to test Delivery Promise features:
`50030-260`, `20070-001` or `04538-132`.
Then, try to set a global pickup point and see if the store name is
added on the navbar, navigate to PLP and you should see the `Delivery`
facet section, you can filter by other methods. Everything should keep
working as before. Also, try the mobile version.
vtex-sites/faststoreqa.store#834
---------
Co-authored-by: Larícia Mota
Co-authored-by: Fanny Chien
---
.../core/src/sdk/shipping/usePickupPoints.ts | 74 -------------------
1 file changed, 74 deletions(-)
delete mode 100644 packages/core/src/sdk/shipping/usePickupPoints.ts
diff --git a/packages/core/src/sdk/shipping/usePickupPoints.ts b/packages/core/src/sdk/shipping/usePickupPoints.ts
deleted file mode 100644
index 24d2734c7e..0000000000
--- a/packages/core/src/sdk/shipping/usePickupPoints.ts
+++ /dev/null
@@ -1,74 +0,0 @@
-import { useMemo } from 'react'
-import { gql } from '@generated'
-import type {
- ClientPickupPointsQueryQuery,
- ClientPickupPointsQueryQueryVariables,
-} from '@generated/graphql'
-
-import { deliveryPromise } from 'discovery.config'
-import { useSession } from 'src/sdk/session'
-import { useQuery } from 'src/sdk/graphql/useQuery'
-
-export const query = gql(`
- query ClientPickupPointsQuery(
- $geoCoordinates: IStoreGeoCoordinates
- $postalCode: String
- $country: String
- ) {
- pickupPoints(geoCoordinates: $geoCoordinates, postalCode: $postalCode, country: $country) {
- paging {
- total
- }
- items {
- pickupPoint {
- id
- address {
- street
- }
- friendlyName
- }
- }
- }
- }
-`)
-
-export const usePickupPoints = () => {
- if (!deliveryPromise.enabled) {
- return null
- }
-
- const { country, postalCode, geoCoordinates } = useSession()
-
- if (!geoCoordinates && (!postalCode || !country)) {
- return null
- }
-
- const variables = useMemo(
- () => ({
- country: !!geoCoordinates ? undefined : country,
- geoCoordinates: geoCoordinates ?? undefined,
- postalCode: !!geoCoordinates ? undefined : postalCode,
- }),
- [country, geoCoordinates, postalCode]
- )
-
- const { data } = useQuery<
- ClientPickupPointsQueryQuery,
- ClientPickupPointsQueryQueryVariables
- >(query, variables, {
- fallbackData: null,
- })
-
- if (!data) {
- return null
- }
-
- const pickupPoints = data.pickupPoints.items.map((item) => ({
- id: item.pickupPoint?.id,
- addressStreet: item.pickupPoint?.address?.street,
- name: item.pickupPoint?.friendlyName,
- totalItems: data.pickupPoints.paging.total,
- }))
-
- return pickupPoints
-}
From 6a9eb481c15c8eb8657b0e3729be27b3799d5aa2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lar=C3=ADcia=20Mota?=
Date: Thu, 24 Jul 2025 16:30:54 -0300
Subject: [PATCH 22/25] Fix after rebase
---
packages/api/src/__generated__/schema.ts | 20 -----------
packages/core/@generated/gql.ts | 8 -----
packages/core/@generated/graphql.ts | 46 ------------------------
3 files changed, 74 deletions(-)
diff --git a/packages/api/src/__generated__/schema.ts b/packages/api/src/__generated__/schema.ts
index 76f0dda9c4..567094dc4b 100644
--- a/packages/api/src/__generated__/schema.ts
+++ b/packages/api/src/__generated__/schema.ts
@@ -590,14 +590,6 @@ export type IUserOrderCancel = {
reason?: Maybe;
};
-export type Item = {
- __typename?: 'Item';
- /** Pickup point distance. */
- distance?: Maybe;
- /** Pickup point. */
- pickupPoint?: Maybe;
-};
-
export type LogisticsInfo = {
__typename?: 'LogisticsInfo';
/** LogisticsInfo itemIndex. */
@@ -703,18 +695,6 @@ export type MutationValidateSessionArgs = {
session: IStoreSession;
};
-export type Paging = {
- __typename?: 'Paging';
- /** Current page. */
- page?: Maybe;
- /** Number of items per page. */
- pageSize?: Maybe;
- /** Total number of pages. */
- pages?: Maybe;
- /** Total number of items. */
- total?: Maybe;
-};
-
/** Newsletter information. */
export type PersonNewsletter = {
__typename?: 'PersonNewsletter';
diff --git a/packages/core/@generated/gql.ts b/packages/core/@generated/gql.ts
index cbd6890856..ec38337920 100644
--- a/packages/core/@generated/gql.ts
+++ b/packages/core/@generated/gql.ts
@@ -90,8 +90,6 @@ const documents = {
types.ValidateSessionDocument,
'\n query ClientShippingSimulationQuery(\n $postalCode: String!\n $country: String!\n $items: [IShippingItem!]!\n ) {\n ...ClientShippingSimulation\n shipping(items: $items, postalCode: $postalCode, country: $country) {\n logisticsInfo {\n slas {\n carrier\n price\n availableDeliveryWindows {\n startDateUtc\n endDateUtc\n price\n listPrice\n }\n shippingEstimate\n localizedEstimates\n deliveryChannel\n }\n }\n address {\n city\n neighborhood\n state\n }\n }\n }\n':
types.ClientShippingSimulationQueryDocument,
- '\n query ClientPickupPointsQuery(\n $geoCoordinates: IStoreGeoCoordinates\n $postalCode: String\n $country: String\n ) {\n pickupPoints(geoCoordinates: $geoCoordinates, postalCode: $postalCode, country: $country) {\n paging {\n total\n }\n items {\n pickupPoint {\n id\n address {\n street\n }\n friendlyName\n }\n }\n }\n }\n':
- types.ClientPickupPointsQueryDocument,
'\n query ServerManyProductsQuery(\n $first: Int!\n $after: String\n $sort: StoreSort!\n $term: String!\n $selectedFacets: [IStoreSelectedFacet!]!\n $sponsoredCount: Int\n ) {\n ...ClientManyProducts\n search(\n first: $first\n after: $after\n sort: $sort\n term: $term\n selectedFacets: $selectedFacets\n sponsoredCount: $sponsoredCount\n ) {\n products {\n pageInfo {\n totalCount\n }\n edges {\n node {\n ...ProductSummary_product\n }\n }\n }\n metadata {\n ...SearchEvent_metadata\n }\n }\n }\n':
types.ServerManyProductsQueryDocument,
}
@@ -330,12 +328,6 @@ export function gql(
export function gql(
source: '\n query ClientShippingSimulationQuery(\n $postalCode: String!\n $country: String!\n $items: [IShippingItem!]!\n ) {\n ...ClientShippingSimulation\n shipping(items: $items, postalCode: $postalCode, country: $country) {\n logisticsInfo {\n slas {\n carrier\n price\n availableDeliveryWindows {\n startDateUtc\n endDateUtc\n price\n listPrice\n }\n shippingEstimate\n localizedEstimates\n deliveryChannel\n }\n }\n address {\n city\n neighborhood\n state\n }\n }\n }\n'
): typeof import('./graphql').ClientShippingSimulationQueryDocument
-/**
- * The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
- */
-export function gql(
- source: '\n query ClientPickupPointsQuery(\n $geoCoordinates: IStoreGeoCoordinates\n $postalCode: String\n $country: String\n ) {\n pickupPoints(geoCoordinates: $geoCoordinates, postalCode: $postalCode, country: $country) {\n paging {\n total\n }\n items {\n pickupPoint {\n id\n address {\n street\n }\n friendlyName\n }\n }\n }\n }\n'
-): typeof import('./graphql').ClientPickupPointsQueryDocument
/**
* The gql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
*/
diff --git a/packages/core/@generated/graphql.ts b/packages/core/@generated/graphql.ts
index 347961e4dd..3063cdc63d 100644
--- a/packages/core/@generated/graphql.ts
+++ b/packages/core/@generated/graphql.ts
@@ -591,13 +591,6 @@ export type IUserOrderCancel = {
reason: InputMaybe
}
-export type Item = {
- /** Pickup point distance. */
- distance: Maybe
- /** Pickup point. */
- pickupPoint: Maybe
-}
-
export type LogisticsInfo = {
/** LogisticsInfo itemIndex. */
itemIndex: Maybe
@@ -693,17 +686,6 @@ export type MutationValidateSessionArgs = {
session: IStoreSession
}
-export type Paging = {
- /** Current page. */
- page: Maybe
- /** Number of items per page. */
- pageSize: Maybe
- /** Total number of pages. */
- pages: Maybe
- /** Total number of items. */
- total: Maybe
-}
-
/** Newsletter information. */
export type PersonNewsletter = {
/** Person's ID in the newsletter list. */
@@ -3660,25 +3642,6 @@ export type ClientShippingSimulationQueryQuery = {
} | null
}
-export type ClientPickupPointsQueryQueryVariables = Exact<{
- geoCoordinates: InputMaybe
- postalCode: InputMaybe
- country: InputMaybe
-}>
-
-export type ClientPickupPointsQueryQuery = {
- pickupPoints: {
- paging: { total: number | null } | null
- items: Array<{
- pickupPoint: {
- id: string | null
- friendlyName: string | null
- address: { street: string | null } | null
- } | null
- } | null> | null
- } | null
-}
-
export type ServerManyProductsQueryQueryVariables = Exact<{
first: Scalars['Int']['input']
after: InputMaybe
@@ -4547,15 +4510,6 @@ export const ClientShippingSimulationQueryDocument = {
ClientShippingSimulationQueryQuery,
ClientShippingSimulationQueryQueryVariables
>
-export const ClientPickupPointsQueryDocument = {
- __meta__: {
- operationName: 'ClientPickupPointsQuery',
- operationHash: '0267c77a87cb0592dfd9a73bad8f632c1801541b',
- },
-} as unknown as TypedDocumentString<
- ClientPickupPointsQueryQuery,
- ClientPickupPointsQueryQueryVariables
->
export const ServerManyProductsQueryDocument = {
__meta__: {
operationName: 'ServerManyProductsQuery',
From 79d22ca65a6102154060cb4b1c115de56ec83db4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lar=C3=ADcia=20Mota?=
Date: Wed, 30 Jul 2025 13:16:07 -0300
Subject: [PATCH 23/25] Fix after rebase
---
packages/core/cms/faststore/content-types.json | 15 ---------------
packages/core/cms/faststore/sections.json | 16 ----------------
.../ui/PickupPoints/PickupPointCard.tsx | 4 +++-
.../sdk/deliveryPromise/useDeliveryPromise.ts | 1 +
4 files changed, 4 insertions(+), 32 deletions(-)
diff --git a/packages/core/cms/faststore/content-types.json b/packages/core/cms/faststore/content-types.json
index 926bb23a83..8ba50872af 100644
--- a/packages/core/cms/faststore/content-types.json
+++ b/packages/core/cms/faststore/content-types.json
@@ -232,21 +232,6 @@
"default": "Storefront icon"
}
}
- },
- "pickupPointChangeApplyButtonLabel": {
- "title": "Change Pickup Point apply button label",
- "type": "string",
- "default": "Update"
- },
- "choosePickupPointAriaLabel": {
- "title": "Choose Pickup Point aria-label (radio group)",
- "type": "string",
- "default": "Choose a store"
- },
- "noPickupPointsAvailableInLocation": {
- "title": "No Pickup Point available near location message",
- "type": "string",
- "default": "No stores near location."
}
}
},
diff --git a/packages/core/cms/faststore/sections.json b/packages/core/cms/faststore/sections.json
index 00a021e82d..65e2afe751 100644
--- a/packages/core/cms/faststore/sections.json
+++ b/packages/core/cms/faststore/sections.json
@@ -2474,22 +2474,6 @@
}
}
},
- {
- "name": "RegionSlider",
- "requiredScopes": [],
- "schema": {
- "title": "Region Slider",
- "type": "object",
- "description": "Region Slider configuration",
- "properties": {
- "enabled": {
- "type": "boolean",
- "title": "Should enable Region Slider?",
- "default": true
- }
- }
- }
- },
{
"name": "EmptyState",
"schema": {
diff --git a/packages/core/src/components/ui/PickupPoints/PickupPointCard.tsx b/packages/core/src/components/ui/PickupPoints/PickupPointCard.tsx
index bfd4ee11d6..4bd7d5c10b 100644
--- a/packages/core/src/components/ui/PickupPoints/PickupPointCard.tsx
+++ b/packages/core/src/components/ui/PickupPoints/PickupPointCard.tsx
@@ -24,7 +24,9 @@ function PickupPointCard({ store }: PickupPointCardProps) {
{store?.address?.street}, {store?.address?.number}
- {store?.address?.city}
+
+ {store?.address?.city} - {store?.address?.state}
+
{store?.distance !== undefined ? formatDistance(store.distance) : ''}
diff --git a/packages/core/src/sdk/deliveryPromise/useDeliveryPromise.ts b/packages/core/src/sdk/deliveryPromise/useDeliveryPromise.ts
index c7ab7ffd8a..60abd46021 100644
--- a/packages/core/src/sdk/deliveryPromise/useDeliveryPromise.ts
+++ b/packages/core/src/sdk/deliveryPromise/useDeliveryPromise.ts
@@ -44,6 +44,7 @@ export type PickupPoint = {
number?: string
postalCode?: string
city?: string
+ state?: string
}
distance?: number
totalItems?: number
From ee63e58a57b391aa60d35766b0bfad01f4ae2368 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lar=C3=ADcia=20Mota?=
Date: Mon, 11 Aug 2025 15:40:13 -0300
Subject: [PATCH 24/25] feat: Delivery Promise 2.1 - filters by dynamic
estimate (#2959)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Feature branch for the Delivery Promise feature - phase 2.1 - filters by
dynamic estimate.
- #2958
- #2963
- [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
Co-authored-by: Lucas Feijó
Co-authored-by: Fanny Chien
Co-authored-by: Otavio Moreira Meirelles
Co-authored-by: Artur Santiago
---
.../src/molecules/ToggleField/ToggleField.tsx | 17 +++-
.../Filter/FilterFacetBooleanItem.tsx | 77 +++++++++++--------
.../src/organisms/Filter/FilterFacets.tsx | 34 +++++---
.../core/cms/faststore/content-types.json | 21 +++++
.../search/Filter/FilterDesktop.tsx | 36 ++++++++-
.../components/search/Filter/FilterSlider.tsx | 34 +++++++-
.../search/Filter/section.module.scss | 2 +
.../sdk/deliveryPromise/useDeliveryPromise.ts | 55 ++++++++++---
packages/core/src/utils/globalSettings.ts | 5 ++
.../components/organisms/Filter/styles.scss | 21 +++++
10 files changed, 247 insertions(+), 55 deletions(-)
diff --git a/packages/components/src/molecules/ToggleField/ToggleField.tsx b/packages/components/src/molecules/ToggleField/ToggleField.tsx
index 8ac978c405..c6c66c3b68 100644
--- a/packages/components/src/molecules/ToggleField/ToggleField.tsx
+++ b/packages/components/src/molecules/ToggleField/ToggleField.tsx
@@ -1,3 +1,4 @@
+import type { ChangeEventHandler } from 'react'
import React, { forwardRef } from 'react'
import { Label, SROnly, Toggle, type ToggleProps } from './../../'
@@ -26,6 +27,14 @@ export interface ToggleFieldProps extends ToggleProps {
* Controls the component's direction.
*/
variant?: 'horizontal' | 'vertical'
+ /**
+ * Specifies if the input is checked or not.
+ */
+ checked?: boolean
+ /**
+ * Function that is triggered when any children is checked.
+ */
+ onChange?: ChangeEventHandler
}
const ToggleField = forwardRef(
@@ -43,7 +52,13 @@ const ToggleField = forwardRef(
) {
return (