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 Out of Stock Message #1229

Merged
merged 11 commits into from
Jun 6, 2019

Conversation

sudeep-cedcoss
Copy link
Contributor

@sudeep-cedcoss sudeep-cedcoss commented May 9, 2019

Description

This PR fixes an issue where the application could enter an infinite loop of error notifications when a product becomes out of stock.

Related Issue

Closes #1159 .

Verification Steps

📝 Any product should work but these steps use the Augusta Earrings.

Product In Stock

  1. Go to the Product page for Augusta Earrings
  2. Verify that it shows as expected

Product Out of Stock after being In Stock

  1. Log in to your Magento backend (MAGENTO_SITE_URL + /admin in your browser)
  2. Click Category > Products
  3. In the search field, enter VA12-SI-NA (the SKU for Augusta Earrings)
  4. Click Edit
  5. Change Quantity to 0 and Stock Status to Out of Stock
  6. Click Save
  7. Refresh the Product page in Venia
  8. Verify that a "Product out of stock" message appears

📝 Sometimes it takes a second for the cache to update and the "out of stock" message to appear.

Product Back in Stock

  1. Log in to your Magento backend (MAGENTO_SITE_URL + /admin in your browser)
  2. Click Category > Products
  3. In the search field, enter VA12-SI-NA (the SKU for Augusta Earrings)
  4. Click Edit
  5. Change Quantity to 100 and Stock Status to In Stock
  6. Click Save
  7. Refresh Venia
  8. See that the product page shows as expected

📝 For some reason it definitely takes longer for the cache to flush when the product comes back in stock as opposed to going out of stock. I am honestly unsure the cache timings and where the caching is taking place. If you want to shortcut the process, delete the apollo-cache-persist entry from local storage on your browser (Application > Local Storage) and refresh Venia using Empty Cache and Hard Reload (long press on the refresh button).

How Have YOU Tested this?

  1. yarn test
  2. Verification Steps above

Screenshots / Screen Captures (if appropriate):

Infinite Error Loop (before)

image

Out of Stock Message (after)

Screen Shot 2019-06-04 at 10 29 36 AM

Proposed Labels for Change Type/Package

  • major (e.g x.0.0 - a breaking change)
  • minor (e.g 0.x.0 - a backwards compatible addition)
  • patch (e.g 0.0.x - a bug fix)

This PR adds a new prop to the ErrorView component. Additions are backwards-compatible.

Checklist:

  • I have updated the documentation accordingly, if necessary.
  • I have added tests to cover my changes, if necessary.

Fixed magento#1159 [bug]: If user tries to access product page after it goes to out of stock then system enters a infinite loop.
@vercel
Copy link

vercel bot commented May 9, 2019

This pull request is automatically deployed with Now.
To access deployments, click Details below or on the icon next to each push.

Latest deployment for this branch: https://venia-git-fork-sudeep-cedcoss-sudeep-pr-1159-again.magento-research1.now.sh

@sirugh
Copy link
Contributor

sirugh commented May 9, 2019

Hello! Is there a reason you're closing and opening the same changeset? You previously opened #1202 #1228 for this issue. Just wondering if there was a particular reason as I couldn't see any difference in the code.

@sudeep-cedcoss
Copy link
Contributor Author

Hello Stephen,

I have just started on Magento PWA a few weeks back and those pull request were among my starting pull requests. So I was not sure how to create a pull request properly and link them properly with original issue. So that's why I created some of the pull requests by mistake. Sorry for that. Now I am getting more habitual with these things, and I will make sure that this does not happen again.

Thank you.

@sirugh
Copy link
Contributor

sirugh commented May 10, 2019

No problem! Don't worry about the linking -- we can handle that on our end. I recommend a workflow like this:

  1. Find an issue that sparks your interest. Comment in the issue saying that you'd like to work on it.
  2. Branch off develop like git checkout origin/develop && git checkout -b my_branch_name.
  3. Code away and when done, push the branch.
  4. Fill out the PR template as descriptively as possible. The more detail the easier it will be for us to review and get your changes merged!

Good luck.

@sudeep-cedcoss
Copy link
Contributor Author

Ok Thanks. I'll follow these things while creating PRs in the future. :-)

@supernova-at supernova-at self-assigned this May 29, 2019
Copy link
Contributor

@supernova-at supernova-at left a comment

Choose a reason for hiding this comment

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

Thanks for your contribution!

I think we can simplify this code a bit and have left my feedback below.

@@ -1,6 +1,8 @@
import React, { Component } from 'react';
import { string, func } from 'prop-types';

import { isUndefined } from 'util';
Copy link
Contributor

Choose a reason for hiding this comment

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

No need for this guy, we can check if an object is undefined easily without pulling this in.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, just an FYI that isUndefined is deprecated: https://nodejs.org/api/util.html#util_util_isundefined_object.

description:
typeof description === 'object' ? description.html : description
};
if (!isUndefined(product)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's do our check for undefined in the render method instead of here.

addToCart={this.props.addItemToCart}
/>
);
const productData = this.mapProduct(product);
Copy link
Contributor

Choose a reason for hiding this comment

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

Here is the result of the query for a product that is out of stock:

{
  "data": {
    "productDetail": {
      "items": []
    }
  }
}

Therefore const product = data.productDetail.items[0] will result in product being undefined here and your conditional can just be if (product) { ...

/>
);
} else {
return <div>Product Out Of Stock</div>;
Copy link
Contributor

Choose a reason for hiding this comment

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

We have a very basic ErrorView component that would work nicely here. For consistency and ease of update later, let's use that.

Feel free to add an outOfStock (boolean) prop to it that shows this message when the prop is true.

Then you can just render <ErrorView outOfStock={true} /> here 👍

@supernova-at supernova-at changed the title Fixed #1159 Product Out of Stock Message May 29, 2019
@supernova-at
Copy link
Contributor

It took us a while to give feedback on this so after waiting a week I went ahead and applied the feedback myself. Thanks for your contribution!

PR Updated:

  • Applies feedback to simplify logic in Product.js
  • Adds outOfStock to ErrorView
  • Updates PR description / verification steps

sirugh
sirugh previously requested changes Jun 4, 2019
const message = loading
? messages.get('loading')
: notFound
? messages.get('notFound')
: outOfStock
? messages.get('outOfStock')
Copy link
Contributor

Choose a reason for hiding this comment

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

We may want to allow an error string rather than using this prop. This will allow us to separate the error messages and types from the ErrorView implementation.

export const ERROR_TYPES = {
  'LOADING': 'loading',
  'OUT_OF_STOCK': 'outOfStock',
  ...
};
export const errorMap = new Map({
  'loading': loadingIndicator,
  'outOfStock': 'This Product is currently out of stock. Please try again later.',
  'default': 'Something went wrong. Please try again.'
  ...
});

class ErrorView extends Component {
  render() {
    const { type } = this.props;
    const key = ERROR_TYPES[type] || 'default';
    return <h1>{errorMap[key]}</h1>;
  }
} 

Copy link
Contributor

@supernova-at supernova-at Jun 4, 2019

Choose a reason for hiding this comment

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

Yeah the ErrorView certainly could use a refactor. I already felt like adding outOfStock was a little scope creep here and I felt like refactoring all of ErrorView would be solidly out of scope for this.

Copy link
Contributor

Choose a reason for hiding this comment

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

I can create a follow up ticket to refactor ErrorView for sure

Copy link
Contributor

Choose a reason for hiding this comment

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

That's cool -- though the component is super small and I feel like the effort to refactor now is less than the effort to create, groom and work on it later. But w/e you want to do is cool, you're the one doing this work now :D

Copy link
Contributor

Choose a reason for hiding this comment

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

A fair point, lol.

I created #1308 just to keep things moving though.

@supernova-at
Copy link
Contributor

PR Updated:

  • Adds Unit Tests to ErrorView to complete the checklist

@soumya-ashok
Copy link

soumya-ashok commented Jun 5, 2019

@supernova-at @sirugh - I think this out-of-stock message should load as a toast, since that is how we are dealing with all of the other alert messages. Thoughts?

@sudeep-cecdoss Thanks for the work! The new design for toasts was merged some time ago. Would you be able to make changes to have the message load as a toast? - I will provide a reference design mockup.

@sirugh
Copy link
Contributor

sirugh commented Jun 5, 2019

Yes! I think this is a perfect example for a toast. In order to do this properly we need to:

  1. Decide on a UX for the toast ie. message, icon, etc.
  2. Decide at what point we want to emit the toast ie within this product component.
  3. Refactor the emitting/implementing component to be a functional component so that we can use the useToasts hook.

We will probably need to do something like navigate back if we emit a toast rather than show the "empty/no product" view.

The design/discussion should happen in the issue, #1159, and then we can go from there. Just to prevent all this extra work being done after time has already been spent on coding I would recommend always talking to UX in the issue (use the needs-ux label) when you recognize a bug that is user-facing/front end.

@sirugh sirugh added the needs-ux Collaboration and review from UX team is required label Jun 5, 2019
@soumya-ashok
Copy link

soumya-ashok commented Jun 5, 2019

@sirugh After a discussion with @awilcoxa - I will open a new issue with a clearly defined user story for this because there is some complexity for us to think through from an experience perspective.

For now, I've created a mockup that addresses this bug specifically, and its purpose is to show the toast treatment for the text as well as the position of the toast within the page layout.

Product Out of Stock.png

@sirugh sirugh assigned tjwiebell and unassigned sirugh Jun 5, 2019
@brendanfalkowski
Copy link
Contributor

brendanfalkowski commented Jun 5, 2019

@soumya-ashok + @sirugh + @supernova-at — A couple thoughts on inventory that vary across sites I've worked on:

  1. If "in stock" status is treated as the default some sites don't present this state to customers (but they do show "out of stock").
  2. Sometimes when "out of stock" then adding to cart is blocked, so usually this message is positioned close the CTA that's blocked.
  3. Dismissing the inventory toast is weird, if that's the reason add-to-cart is blocked. As in-page content you'd always see it.
  4. If showing quantity of "in stock" items is important it would be page-level content — so a toast for the opposite state might be weird.
  5. If "out of stock" products can be purchased, then the warning looks a little aggressive.
  6. For sites with multiple physical locations, we sometimes need to show "store X in stock for pickup, store Y out of stock for pickup, ready to ship".

@supernova-at supernova-at removed the needs-ux Collaboration and review from UX team is required label Jun 6, 2019
Copy link
Contributor

@tjwiebell tjwiebell left a comment

Choose a reason for hiding this comment

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

LGTM, and agree that we should merge ahead of UX so this critical bug behavior is at least patched while we work on the design.

@tjwiebell tjwiebell removed their assignment Jun 6, 2019
@dpatil-magento dpatil-magento dismissed stale reviews from supernova-at and sirugh June 6, 2019 18:11

Requested changes were updated.

@dpatil-magento dpatil-magento merged commit 5544164 into magento:develop Jun 6, 2019
@soumya-ashok
Copy link

soumya-ashok commented Jun 7, 2019

@soumya-ashok + @sirugh + @supernova-at — A couple thoughts on inventory that vary across sites I've worked on:

This is a stop-gap solution for the moment @brendanfalkowski and we still need to define a strategy first on how we deal with out-of-stock items in the shopper flow for Venia.

  1. If "in stock" status is treated as the default some sites don't present this state to customers (but they do show "out of stock").
  2. Sometimes when "out of stock" then adding to cart is blocked, so usually this message is positioned close the CTA that's blocked.

My preference would be to proactively notify the user that an item is out of stock, and give them the option to save it to a list or be notified when it becomes available.

  1. Dismissing the inventory toast is weird, if that's the reason add-to-cart is blocked. As in-page content you'd always see it.

Right now we have all toasts set to auto-dismiss after a certain amount of time. In addition to the toast, we should probably have on-page text that says the item is out of stock if we block add to cart. I have seen a pattern where "Add to Cart" is disabled but "Add to List" is enabled for an out-of-stock item. Thoughts on this?

  1. If showing quantity of "in stock" items is important it would be page-level content — so a toast for the opposite state might be weird.

Noted.

  1. If "out of stock" products can be purchased, then the warning looks a little aggressive.

I think this would be dependent on how a particular merchant deals with out of stock items. For Venia, we haven't decided yet whether or not we would allow out of stock items to be added to the cart.

  1. For sites with multiple physical locations, we sometimes need to show "store X in stock for pickup, store Y out of stock for pickup, ready to ship".

_Great point, will make a note.

As always, thanks for the thoughtful feedback!_

@brendanfalkowski
Copy link
Contributor

@soumya-ashok Cool cool, inventory strategy varies a lot between merchants so definitely not expecting a one-size-fits-all solution. The toast feels good for a B2C experience.

For B2B, we try to keep the UI actions in-place but disabled, because we may block adding to cart for different contexts (EPA/brand/geo restrictions, discontinued but in stock at other locations, cannot show pricing due to account). We prefer to always show the "add to cart" action in the UI, so it's clear that exists but isn't accessible for XYZ reason. Example:

Screen Shot 2019-06-07 at 12 17 50 PM

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.

[bug]: If user tries to access product page after it goes to out of stock then system enters a infinite loop.
7 participants