Feat/zipcode soft refresh query allowlist - #28
Conversation
|
Hi! I'm VTEX IO CI/CD Bot and I'll be helping you to publish your app! 🤖 Please select which version do you want to release:
And then you just need to merge your PR when you are ready! There is no need to create a release commit/tag.
|
|
Beep boop 🤖 I noticed you didn't make any changes at the
In order to keep track, I'll create an issue if you decide now is not a good time
|
Replace `location.reload()` in the five `useDeliveryPromise` callsites (`submitZipcode`, `selectPickup`, `selectDeliveryShippingOption`, `RESET_FULFILLMENT_METHOD`, `CLEAR_ZIPCODE`) with `apolloClient.reFetchObservableQueries(true)`. The `POST /api/sessions` response already applies the new `vtex_segment` cookie (which carries the delivery / pickup hashes) before our await resolves, so by the time we refetch, every `@withSegment` observable query rides the new segment. Behavior: - Apollo client is read via `useApolloClient` from react-apollo. When the provider is missing or the refetch throws, we fall back to a hard reload so the storefront always converges on the post-session state. - `setIsLoading` keeps a spinner during the refetch window now that the React tree no longer disappears. - The `reload` arg on `UPDATE_ZIPCODE` preserves its current contract: when `false`, the caller (e.g. PLP facet navigation) owns navigation and we neither refetch nor reload. Tests: - Mock `react-apollo` so existing tests continue to pass and add a new describe block covering the five soft-refresh paths plus the reload-fallback (Apollo throws, no provider mounted). Co-authored-by: Cursor <cursoragent@cursor.com>
Adds failing tests (observed red before implementation) for replacing the broad reFetchObservableQueries with a targeted refetch of only the allowlisted store-resources queries (facetsV2, productSearchV3, Products, Product, sponsoredProducts, ProductRecommendations), resetting productSearchV3 to page 1 (from: 0), and falling back to location.reload() when Apollo is unavailable, internals are inaccessible, or a refetch throws. Refs specs/zipcode-soft-refresh-query-allowlist/spec.md Co-authored-by: Cursor <cursoragent@cursor.com>
Replace the broad apolloClient.reFetchObservableQueries(true) in refreshStorefront with a targeted refetch of only the allowlisted store-resources queries that vary by @withSegment: facetsV2, productSearchV3, Products, Product, sponsoredProducts, and ProductRecommendations. apollo-client 2.6 has no public subset-refetch API, so the new helper refetchAllowlistedQueries enumerates the QueryManager's observable queries and filters by operation name, settling each refetch independently. productSearchV3 is reset to page 1 (from: 0) via QUERY_VARIABLE_OVERRIDES while preserving its other variables. Falls back to location.reload() when Apollo is unavailable, internals are inaccessible, or a refetch throws. Refs specs/zipcode-soft-refresh-query-allowlist/spec.md Co-authored-by: Cursor <cursoragent@cursor.com>
Update the Unreleased soft-refresh entry to reflect refetching only the allowlisted store-resources queries (with productSearchV3 reset to page 1) instead of the broad reFetchObservableQueries. Co-authored-by: Cursor <cursoragent@cursor.com>
…refresh Without a reload, selecting delivery/pickup or resetting the fulfillment method must (1) optimistically update deliveryPromiseMethod / selectedPickup in context state, and (2) signal the shipping-method modal to close. Adds failing tests (observed red before implementation): - SELECT_DELIVERY_SHIPPING_OPTION → method 'delivery', pickup cleared - UPDATE_PICKUP → method 'pickup-in-point', selected pickup stored - RESET_FULFILLMENT_METHOD → method/pickup cleared - ShippingMethodSelector closes the modal when fulfillmentSelectionAppliedId increments Refs specs/zipcode-soft-refresh-query-allowlist/spec.md Co-authored-by: Cursor <cursoragent@cursor.com>
The soft refresh keeps the React tree alive, so two behaviors the page reload used to provide for free are now handled explicitly: 1. State sync: selectPickup, SELECT_DELIVERY_SHIPPING_OPTION and RESET_FULFILLMENT_METHOD update deliveryPromiseMethod / selectedPickup optimistically (the values the reload re-derived from the segment), so the shipping-method selector reflects the chosen option immediately. 2. Modal close: a new context counter (fulfillmentSelectionAppliedId) increments when a fulfillment method is applied; shipping-method-selector watches it and closes the modal. The unavailable-items abort flow is preserved (the modal reopens only when the selection is not applied). Refs specs/zipcode-soft-refresh-query-allowlist/spec.md Co-authored-by: Cursor <cursoragent@cursor.com>
…efresh Adds failing tests (observed red before implementation): - selecting a pickup toggles loading exactly once (no validate→idle→select double spinner) - productSearchV3 refetch resets to the first page on BOTH from and to (from: 0, to: page size - 1), preserving other variables - removePageQueryParam drops the page query string without a reload Refs specs/zipcode-soft-refresh-query-allowlist/spec.md Co-authored-by: Cursor <cursoragent@cursor.com>
Issue 1 — double spinner: validateCartItems used to turn the loading flag off on its success path, then the selection (selectPickup / selectDeliveryShippingOption) turned it on again, producing a loading→idle→loading→idle flicker. validateCartItems now keeps loading on when the action will proceed and only turns it off when it surfaces the unavailable-items modal, so the continuation owns a single loading→idle cycle. Defensive early-return guards in the selection handlers clear loading so it can never get stuck on. Issue 2 — pagination reset: refetching productSearchV3 only reset `from`. It now resets to the first page on both `from` and `to` (from: 0, to: to - from, preserving the page size the way search-result derives it), and drops the `page` query string from the URL via history.replaceState (no reload) so the reset survives a later re-render or reload. The per-query override is now a function of the query's current variables. Refs specs/zipcode-soft-refresh-query-allowlist/spec.md Co-authored-by: Cursor <cursoragent@cursor.com>
Assert that a location change on page >= 2 reloads (resetting search-result's useFetchMore counter) instead of soft-refetching, and that removePageQueryParam reports the previous page number. Co-authored-by: Cursor <cursoragent@cursor.com>
search-result's useFetchMore pagination counter is seeded at mount and only reset on query/map/orderBy/priceRange changes, so a soft refetch after a segment change leaves the next "load more" jumping to the stale page N+1. When the shopper is on page >= 2, refreshStorefront now reloads (after stripping the page param so it lands on page 1), re-initializing that counter; page 1 keeps the soft refresh. removePageQueryParam returns the previous page to drive the decision. Co-authored-by: Cursor <cursoragent@cursor.com>
…ses loading Co-authored-by: Cursor <cursoragent@cursor.com>
Wrap `updateSession` in `selectPickup`, `selectDeliveryShippingOption`, and `RESET_FULFILLMENT_METHOD` with try/catch. On failure the previous `deliveryPromiseMethod` / `selectedPickup` values are restored, the loading flag is released (no stuck spinner), the failure is logged, and the soft refresh is skipped — the UI never claims a selection the session does not hold. `persistPickupPreference` is also moved to run only after a successful write so a failed write cannot poison the stored pickup. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
61503b6 to
43f33bd
Compare
…ock lifecycle Drive the Apollo-client scenario through a module-level override the react-apollo mock factory reads, instead of reassigning the imported useApolloClient binding (unreliable across compilers that bind named imports at import time). Reset runtime query / re-spy render-runtime and the override in beforeEach for full isolation, and use mockRejectedValue so the throwing-refetch case is robust to repeated calls. Co-authored-by: Cursor <cursoragent@cursor.com>
Use the explicit window.location reference instead of the bare global `location` so the hard-reload fallback always resolves to the current window.location. The bare global binding can desync from a redefined window.location in some jsdom environments, which made the reload fallback no-op under CI. Functionally identical in the browser. Co-authored-by: Cursor <cursoragent@cursor.com>
The three soft-refresh reload-fallback tests reassigned a module-level override binding from the test body, which the CI test runner did not honor through the hoisted jest.mock factory closure (the binding read stale, so the hook always got the healthy in-memory client and never hit the location.reload fallback). Read the client through a useApolloClient spy re-established in beforeEach (mirroring the render-runtime query mock) and build each failure scenario as a fully-constructed value assigned to the live binding before render. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Your PR has been merged! App is being published. 🚀 After the publishing process has been completed (check #vtex-io-releases) and doing A/B tests with the new version, you can deploy your release by running:
After that your app will be updated on all accounts. For more information on the deployment process check the docs. 📖 |
What problem is this solving?
Jira Card
After updating location info (zipcode or shipping-method) the component triggers a full reload of the page.
This PR changes the behavior to a soft refresh. Instead of refreshing the whole page, only the search related queries are refreshed
How to test it?
workspace
Screenshots or example usage:
output2.mp4
Describe alternatives you've considered, if any.
Related to / Depends on
How does this PR make you feel? 🔗
