Skip to content

@W-20038640 Fix: 400 Error#3443

Merged
sf-shikhar-prasoon merged 11 commits intodevelopfrom
t/cc-sharks/W-20038640/400Error/main
Oct 30, 2025
Merged

@W-20038640 Fix: 400 Error#3443
sf-shikhar-prasoon merged 11 commits intodevelopfrom
t/cc-sharks/W-20038640/400Error/main

Conversation

@sf-shikhar-prasoon
Copy link
Contributor

@sf-shikhar-prasoon sf-shikhar-prasoon commented Oct 30, 2025

Description

In this PR we are fixing this issue:

When we pick color and size of the bonus variants in the modal, the Url for the PDP product also picks up the same color and size and that makes PDP product url invalid.

bug.fix-.400.error.mov

I the page is refreshed in this state, the app breaks and shows a 400 Error.

Types of Changes

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Documentation update
  • Breaking change (could cause existing functionality to not work as expected)
  • Other changes (non-breaking changes that does not fit any of the above)

Breaking changes include:

  • Removing a public function or component or prop
  • Adding a required argument to a function
  • Changing the data type of a function parameter or return value
  • Adding a new peer dependency to package.json

Changes

Architectural Changes

  • Moved modals from URL-based state to React state management:
  • Before: Modals used URL parameters for variation selections, causing conflicts with the main PDP
  • After: Modals use controlled React state (useState) for variation selections, completely isolated from URL
  • Removed: cleanUpVariantParams function - no longer needed as modals don't touch URL
  • Added: Controlled mode support to variation hooks via new props:
    • controlledVariationValues - passes React state down
    • onVariationChange - callback to update React state
    • Auto-selection logic for single-value variation attributes

File Changes

Core Hooks (added controlled mode support):
app/hooks/use-product-view-modal.js - removed all URL management
app/hooks/use-variation-params.js - reads from controlled values when provided
app/hooks/use-variant.js - passes controlled values through
app/hooks/use-variation-attributes.js - uses onClick instead of href in controlled mode
app/hooks/use-derived-product.js - aggregates and passes controlled props

Components (now use React state):

app/components/product-view/index.jsx - accepts and passes controlled props
app/components/bonus-product-view-modal/index.jsx - manages variation state with useState
app/components/product-view-modal/index.jsx - manages variation state with useState
app/components/product-view-modal/bundle.jsx - manages variation state with useState

Tests (updated and added):

app/hooks/use-product-view-modal.test.js - removed URL-related tests, added tests for simplified behavior
app/hooks/use-variation-params.test.js - added 3 new tests for controlled mode

How to Test-Drive This PR

  • MRT: https://258demoprj-cc-sharks.sfdc-3vx9f4-commerceecom.exp-delivery-staging.com/ [Edit: just realized that refresh is giving a 400 on any page for this MRT env. So please test this locally. If this is fixed, I'll update this section]
  • navigate to a product with bonus products. E.g. you can search for 25493613M on the site, it'll bring up the Long Center Seam Skirt
  • Add it to cart and enter the bonus product promotion flow
  • Click on Select. product view modal for the bonus product will open up
  • select a size
  • verify that the image of the product on the PDP (of the qualifying product on the page behind the modal) doesn't error out.
  • while on this modal with a size selected, try to refresh the page. Verify that It doesn't break the app (or break anything else) [Edit: just realized that refresh is giving a 400 on any page for this MRT env. So please test this locally. If this is fixed, I'll update this section]
  • try the bonus product selection flow on the cart page.
  • Please think of any other way of breaking things and test it

Checklists

General

  • Changes are covered by test cases
  • CHANGELOG.md updated with a short description of changes (not required for documentation updates)

Accessibility Compliance

You must check off all items in one of the follow two lists:

  • There are no changes to UI

or...

Localization

  • Changes include a UI text update in the Retail React App (which requires translation)

@sf-shikhar-prasoon sf-shikhar-prasoon added the skip changelog Skip the "Changelog Check" GitHub Actions step even if the Changelog.md files are not updated label Oct 30, 2025
@sf-shikhar-prasoon sf-shikhar-prasoon marked this pull request as ready for review October 30, 2025 16:45
@sf-shikhar-prasoon sf-shikhar-prasoon requested a review from a team as a code owner October 30, 2025 16:45
@cc-prodsec
Copy link
Collaborator

cc-prodsec commented Oct 30, 2025

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Licenses 0 0 0 0 0 issues
Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

[attributeId]: value
}))
}, [])

Copy link
Contributor

Choose a reason for hiding this comment

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

I see all 3 are using same code for auto selection of variant product.
Whats the different between three modals ? whats the use case for each ?

Also its being used at 3 places, can we extract it out in some util/helper ?

Copy link
Contributor

Choose a reason for hiding this comment

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

Also do we need this auto selection now ? Does it help with the 400 bug ? How ?

Copy link
Contributor

Choose a reason for hiding this comment

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

We need to refactor the duplicated code from:

  1. app/components/product-view-modal/index.jsx
  2. app/components/bonus-product-view-modal/index.jsx
  3. app/components/product-view-modal/bundle.jsx

Copy link
Contributor Author

@sf-shikhar-prasoon sf-shikhar-prasoon Oct 30, 2025

Choose a reason for hiding this comment

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

  • BonusProductViewModal: Shows bonus products that customers can select when they qualify for promotions (e.g., "Buy 2, get 1 free - choose your free item")
  • ProductViewModal: Quick view modal for regular products from product listing pages
  • BundleProductViewModal: Shows products that are part of a bundle on the cart page when editing bundle items

Since we are changing architecture for one modal, we should not let other modals use the URL architecture. All three needed the same refactoring because they all display products with variations that were previously using URL state.


The auto-selection logic was already there before in the old code - we just had to re-implement it in the new React state approach. Previously, auto-selection happened via URL parameters. Now, we're doing it in react state.
If I recall correctly, without it, the modal doesn't fetch image etc on the product-view modal. You had to click the size for it to start displaying the image


Yes, I'll refactor duplicate code

Copy link
Contributor Author

@sf-shikhar-prasoon sf-shikhar-prasoon Oct 30, 2025

Choose a reason for hiding this comment

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

@sf-deepali-bharmal @sf-cboscenco I changed it
Instead of all 3 modals, now only product-view modal will use react state.

A test was failing where clicking the update button on a product view modal was not sending the error notification if the update failed. I couldn't find how fix it and I was suspecting the changes to modals caused this. So I reverted making changes to other modals.

Copy link
Contributor

Choose a reason for hiding this comment

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

@sf-shikhar-prasoon Please test all three modals.

isProductPartOfSet = false,
isProductPartOfBundle = false
isProductPartOfBundle = false,
controlledVariationValues = null
Copy link
Contributor

Choose a reason for hiding this comment

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

controlledVariationValues = { } ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We use null as the default to distinguish between two modes: URL mode (when null) and controlled React state mode (when not null). The hook checks if (controlledVariationValues !== null) to decide whether to read from URL parameters or use the provided state. If we used {} as the default, the hook couldn't tell the difference between "use URL mode" vs "use controlled mode with empty state".

Copy link
Contributor

@sf-deepali-bharmal sf-deepali-bharmal Oct 30, 2025

Choose a reason for hiding this comment

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

Is there a possibility of controlledVariationValues being empty / {} ?

In that case code will return no values and will rely on the original params, how will UI behave in such case ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

When controlledVariationValues = {}

// Line 35: Falls back to product's variationValues
let value = controlledVariationValues[key] || variationValues?.[key]

UI Behavior:

Case 1: Empty {} with No Defaults
variationParams = {}
variant = undefined // No variant selected
UI will show everything unselected and Add to cart button disabled

Case 2: Empty {} but Product has defaults
Line 35 falls back to product's variationValues
UI will show the default selection selected and add to cart button will be enabled

return value ? {...acc, [key]: value} : acc
}, {})
}

Copy link
Contributor

@sf-deepali-bharmal sf-deepali-bharmal Oct 30, 2025

Choose a reason for hiding this comment

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

If you pass controlledVariationValues it returns values from that but otherwise it returns values from params.

params is basically a call usePDPSearchParams(product.id) using productId.

Why can not we also use productId of the selectedBonusProduct variant instead of passing variant info as part of controlledVariationValues.

Whats the value of product here when we are in the Bonus Modal selecting various variants?

Copy link
Contributor

Choose a reason for hiding this comment

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

On line 35 If controlledVariationValues[key] does not have key we fallback on variationValues anyway.
And variationValues comes from product which is being passed in this function.

Then why not rely on existing logic to get you params ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Question 1: Why not use productId of selected variant instead of controlledVariationValues?
the app currently follow this pattern of using useVariant() in use-variation-params.js and we are following that? And if we use productId , we would be bypassing that. If we think that the productId approach is better, I can change it.

Question 2: Whats the value of product here
product changes from master to variant as user selects

// 1. Modal Opens
product = {
    id: 'master-product-123',
    variationAttributes: [{id: 'color', values: [...]}],
    variants: [{productId: 'variant-red-M'}, ...]
}

// 2. User Selects "Red"
controlledVariationValues = {color: 'red'}
variant = {productId: 'variant-red-123', ...} // Computed from master

// 3. useProductViewModal fetches variant
useProduct({id: 'variant-red-123'})
↓
product = {
    id: 'variant-red-123',  // ← NOW it's the variant product!
    price: 29.99,
    inventory: {...},
    ...
}

We are using existing logic, just conditionally.

Copy link
Contributor

Choose a reason for hiding this comment

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

I am also saying we use existing useVariant(), but I think you don't need this new piece of code to return params using controlledVariationValues. Existing code might be doing the same already.

@ddiazccrz
Copy link
Contributor

Can you add a test to make sure the core issue of url pollution is fixed something like:
`test('bonus product variant selection does not modify PDP URL', () => {
// 1. Open PDP with URL params
const initialUrl = '/product/123?color=red&size=M'

// 2. Open bonus modal, select different variant
// Select color=blue, size=L in modal

// 3. Assert URL unchanged
expect(window.location.href).toBe(initialUrl)

})`

Also check the integration failures and fix the issues

@sf-shikhar-prasoon
Copy link
Contributor Author

@ddiazccrz added tests for URL Pollution Prevention

@sf-madhuri-uppu
Copy link
Contributor

@sf-shikhar-prasoon Could you attach a video of the working flow?

@sf-shikhar-prasoon sf-shikhar-prasoon enabled auto-merge (squash) October 30, 2025 23:08
@sf-shikhar-prasoon sf-shikhar-prasoon merged commit 9360fa5 into develop Oct 30, 2025
42 checks passed
@sf-shikhar-prasoon sf-shikhar-prasoon deleted the t/cc-sharks/W-20038640/400Error/main branch October 30, 2025 23:19
shethj pushed a commit that referenced this pull request Oct 31, 2025
* fix

* add/update tests

* variant selection fix, test fix

* fix useVariant if product is already a variant

* only use react state for product-view modal

* removed the unnecessary useCallback

* add tests- Variation State Reset | URL Pollution Prevention
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip changelog Skip the "Changelog Check" GitHub Actions step even if the Changelog.md files are not updated

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants