Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Product Tile] Promotion callout message (@W-13974753@) #1786

Merged
merged 71 commits into from
May 23, 2024

Conversation

vmarta
Copy link
Contributor

@vmarta vmarta commented May 15, 2024

This PR implements the default behaviour for promotion callout. It relies on Alex's display-price work in her PR #1760 .

If the rendered price is a promotional price, we'll also render that promo's callout message in the ProductTile. Otherwise, if the variant has promotions, we'll show the callout from the very first promotion.

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

  • (change1)

How to Test-Drive This PR

  1. Navigate to this PLP: /search?q=roll%20sleeve%20blouse
  2. Verify the promo callout message to be "10$ Off roll sleeve blouse". 34.16 is a promotional price, and we're rendering the callout message of that promotion.

Also, try other kinds of products:

Also, try other pages:

  • homepage
  • PDP (and its recommended products)

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)

@vmarta vmarta marked this pull request as ready for review May 17, 2024 20:49
@vmarta vmarta requested a review from a team as a code owner May 17, 2024 20:49

// NOTE: API inconsistency - with getProduct call, a variant does not have productPromotions
const promos = data.productPromotions ?? product.productPromotions ?? []
const promo = promos.find((promo) => promo.promotionalPrice === minPrice) ?? promos[0]
Copy link
Collaborator

Choose a reason for hiding this comment

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

This seem to be repetitive code/execution. Can we return the applicable promotion as well in the findLowestPrice(product) method?

@@ -116,6 +91,28 @@ export const getPriceData = (product, opts = {}) => {
}
}

export const findLowestPrice = (product) => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you please add some jsx comment and unit tests for this function?

@@ -82,7 +83,7 @@ const ProductTile = (props) => {
//TODO variants needs to be filter according to selectedAttribute value
const variants = product?.variants

const priceData = getPriceData({...product, variants})
const priceData = useMemo(() => getPriceData({...product, variants}), [product, variants])
Copy link
Collaborator

Choose a reason for hiding this comment

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

Question - Do we need variants as a dependency along with product to memorize as variants is a property with in product ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The variants is there because the TODO comment made me to anticipate variants to be updated in a later PR. And I don't know what it will look like later.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@vmarta Can you try to update your branch with the feature branch? I believe we have some new code merged in that may look different from that you have on your current branch for the variant TODO above

@vmarta vmarta changed the base branch from plp-strikethrough-price to v3/product-tile-revamp May 23, 2024 00:17
@@ -168,6 +172,12 @@ const ProductTile = (props) => {
return labelsMap
}, [product, badgeDetails])

const shouldShowPromoCallout = (product) => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should we move this function outside of the Component to avoid it being re-defined whenever the tile is re-render?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Agree. We can make it as a helper function (hasPromotions(product)) in the product utils file

@@ -370,3 +380,9 @@ ProductTile.propTypes = {
}

export default ProductTile

const shouldShowPromoCallout = (productWithFilteredVariants) => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

minor: make it a helper function hasPromotions(product) in product-utils?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't want to expose this particular function more globally. For example, due to the inconsistent API (productSearch vs getProduct), I should not be calling it on the Product Details page. So I'd rather constrain this function within ProductTile only.

.filter(Boolean)
.filter(Number)
return vals.length ? Math.min(...vals) : undefined
const filtered = arr.filter((item) => Boolean(item[key])).filter((item) => Number(item[key]))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: shouldn't filter by Number() will rule out falsy value too? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In this case, I was following what's been done before: first filter with Boolean and then by Number.

Copy link
Collaborator

Choose a reason for hiding this comment

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

ah gotcha, okay confirming that we don't need to filter by Boolean here since filter Number will already rule out falsy values. Checked in browser console.

const test = [null, undefined, 1, 2, 5]
test.filter(Number)
=> [1, 2, 5]

Copy link
Contributor Author

@vmarta vmarta May 23, 2024

Choose a reason for hiding this comment

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

@alexvuong thanks for confirming it. There's something else, however. It was possible to ignore 0 in the calculation.

Now in the latest commit, if 0 is one of the values, it will be included.

* @param key
* @returns {Array} an array of such smallest value and the item containing this value
* @example
* const [value, itemContainingValue] = getSmallestValByProperty(array, key)
*/
const getSmallestValByProperty = (arr, key) => {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nice touch on this util 👍

// a hit from productSearch call
rollSleeveBlouse: {
currency: 'GBP',
hitType: 'master',
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do you want to remove any data that is not necessary for the promo call out test to reduce the file size? or you can reuse any data from app/mocks/product-search-hit-data.js?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nah, we don't need to worry about the weight of the test files :) They will not be included in the bundle, right?

I didn't want to worry about consolidating the mocks too. What if I have a particular product that does not exist in app/mocks/product-search-hit-data.js ?

Copy link
Collaborator

@alexvuong alexvuong left a comment

Choose a reason for hiding this comment

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

Minor comments, but LGTM overall

@vmarta vmarta merged commit 3a93df0 into v3/product-tile-revamp May 23, 2024
28 checks passed
@vmarta vmarta deleted the vm/promo-callout branch May 23, 2024 23:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants