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

feat: [M3-7373] - Sold Out Chips #10013

Merged
merged 13 commits into from
Jan 5, 2024
Merged

Conversation

abailly-akamai
Copy link
Contributor

@abailly-akamai abailly-akamai commented Dec 20, 2023

Description 📝

This PR implements sold out chips to our PlanSelection components (both Linode and Kubernetes). It helps our users with picking a GPU or Premium CPU plan by showing them plans that are actually available to them instead of trying to select unavailable plans that would lead to an API error upon submission.

It utilizes the new regions/availability endpoint which only returns availability for GPU or Premium CPU plans (it may be expanded later on). In the background, the endpoint gets refreshed at 15m via a cron job checking available resources in our DCs.

⚠️: While the endpoint is already live in production, we're waiting for an API update that will convert the plan value to our regular plan Ids. This is why this PR is to be tested with mock data.

⚠️: The feature flag is currently turned on for testing, but will be off in production till the fix above is completed. The flag controls the enabling of the API query so when off and no data is returned no plans will be shown as sold out.

Changes 🔄

  • Implement logic to add the sold out chip to GPU or Premium CPU plans
  • Add test coverage for new feature
  • Modify the useRegionsAvailabilitiesQuery to be abled to be disabled
  • Add ability to pass JSX element to subheadings mobile selection cards
  • Get rid of obsolete soldOutSingapore & soldOutTokyo flags
  • Replace instances of selectedRegionID with selectedRegionId

Preview 📷

Linode Creation Flow

Mobile Desktop
Screenshot 2023-12-21 at 11 58 57 Screenshot 2023-12-21 at 11 59 04

Kubernetes Creation Flow

Mobile Desktop
Screenshot 2023-12-21 at 12 00 07 Screenshot 2023-12-21 at 12 00 14

How to test 🧪

Prerequisites

  • pull and run code locally
  • turn on MSW

Verification steps

for both the Linode and Kubernetes creation flows:

  • select either Newark, NJ (us-east) or Dallas, TX (us-central)
  • confirm sold out chips in either the Dedicated CPU or Shared CPU tabs (those plans are not representative of what is returned by the API but what was mocked for testing purposes)
  • Confirm mobile and desktop styling
  • Confirm light and dark mode (ignore known visual defect for disabled radios which will be released at the same time)
  • Confirm chip doesn't show if panel is disabled (you can do that by making this prop true)

As an Author I have considered 🤔

Check all that apply

  • 👀 Doing a self review
  • ❔ Our contribution guidelines
  • 🤏 Splitting feature into small PRs
  • ➕ Adding a changeset
  • 🧪 Providing/Improving test coverage
  • 🔐 Removing all sensitive information from the code and PR description
  • 🚩 Using a feature flag to protect the release
  • 👣 Providing comprehensive reproduction steps
  • 📑 Providing or updating our documentation
  • 🕛 Scheduling a pair reviewing session
  • 📱 Providing mobile support
  • ♿ Providing accessibility support

@@ -16,7 +16,7 @@ export interface CardBaseProps {
headingDecoration?: JSX.Element;
renderIcon?: () => JSX.Element;
renderVariant?: () => JSX.Element | null;
subheadings: (string | undefined)[];
subheadings: (JSX.Element | string | undefined)[];
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This allows adding the chip to the selection card on mobile


return !!availability;
};

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the meat of the PR. Made sure to have early returns so we don't loop over regionAvailabilities for no reasons

@abailly-akamai abailly-akamai marked this pull request as ready for review December 21, 2023 17:21
@abailly-akamai abailly-akamai requested review from a team as code owners December 21, 2023 17:21
@abailly-akamai abailly-akamai requested review from jdamore-linode, mjac0bs and cliu-akamai and removed request for a team December 21, 2023 17:21
Copy link

github-actions bot commented Dec 21, 2023

Coverage Report:
Base Coverage: 79.14%
Current Coverage: 79.2%

@coliu-akamai coliu-akamai added Analytics Relating to Analytics migration project or Adobe Analytics Sold Out Plans and removed Analytics Relating to Analytics migration project or Adobe Analytics labels Dec 21, 2023
Copy link
Contributor

@coliu-akamai coliu-akamai left a comment

Choose a reason for hiding this comment

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

code review ✅

will be reviewing the functionality and following the steps listed above next 👍

}, [
disabled,
getTypeCount,
onAdd,
onSelect,
plans,
selectedId,
selectedRegionID,
selectedRegionId,
Copy link
Contributor

Choose a reason for hiding this comment

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

saw an eslint error for missing regionAvailabilities from dependency list

Suggested change
selectedRegionId,
regionAvailabilities,
selectedRegionId,

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed!

expect(result).toBe(false);
});

it('should return false if plan or selectedRegionId is falsy', () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
it('should return false if plan or selectedRegionId is falsy', () => {
it('should return false if selectedRegionId is falsy', () => {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed!


expect(result).toBe(false);
});

Copy link
Contributor

Choose a reason for hiding this comment

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

can we add a test for non matching planId:

it('should return false if no matching regionAvailability is found (based on planId)', () => {
    const result = getPlanSoldOutStatus({
      plan: mockPlan,
      regionAvailabilities: [
        { available: true, plan: otherMockPlan.id, region: 'us-east-1' },
      ],
      selectedRegionId: mockSelectedRegionId,
    });

    expect(result).toBe(false);
  });

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea - added!

@coliu-akamai
Copy link
Contributor

a couple of things caught my eye:

  1. at some screen widths, the sold out chip goes onto a new line however these screenwidths may not be very common viewport widths so might not be too much of an issue? (~975-1100px when the side nav is open, neglible when side nav is closed ~960-970px)
    image

  2. For the Kubernetes Plans panel, we need to make sure to disable the actions on the row (but still have the chip be clickable for accessibility I think):

Screen.Recording.2023-12-21.at.4.46.13.PM.mov

Copy link
Contributor

@mjac0bs mjac0bs left a comment

Choose a reason for hiding this comment

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

✅ Confirmed sold out chips in either the Dedicated CPU or Shared CPU tabs
✅ Confirmed mobile and desktop styling
✅ Confirmed light and dark mode (ignore known visual defect for disabled radios which will be released at the same time)
✅ Confirmed chip doesn't show if panel is disabled
✅ Test coverage looks good

Connie had some good feedback. Agreed about the weird experience of being able to add a kube cluster that is Sold Out; we should disable those buttons.

Otherwise, a small piece of feedback on the disabled table row styling, which differs between Linode and Kube: This is more noticeable in light mode. Kube styling seems preferable to me, where the disabled row is lighter than the other rows. Can we make that consistent with the Linode plans table?

Linode:
Screenshot 2023-12-29 at 1 03 17 PM

Kube:
Screenshot 2023-12-29 at 1 04 13 PM

@abailly-akamai abailly-akamai force-pushed the M3-7373 branch 2 times, most recently from a02f47f to 8a2fa6e Compare January 2, 2024 17:49
@abailly-akamai
Copy link
Contributor Author

@mjac0bs addressed all the feedback - pls take another look when you get a chance, ty!

Copy link
Member

@bnussman-akamai bnussman-akamai left a comment

Choose a reason for hiding this comment

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

Functionality and logic is looking good! Left a few optional comments/questions


// Sold Out plans
export const PLAN_IS_SOLD_OUT_COPY =
'This plan has no availability for the selected region. Please select a smaller plan or the same plan in another region.';
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
'This plan has no availability for the selected region. Please select a smaller plan or the same plan in another region.';
'This plan has no availability for the selected region. Please select a different plan or the same plan in another region.';

Was "smaller" picked because all plan above a certain size will always be sold out? (is it possible for a Dedicated 32GB to be sold out but a Dedicated 64GB to be in stock)

It feels weird to me to assume the user should pick a smaller plan.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was the recommended copy (and yes if it is based on the host's availability so theoretically a bigger plan would never be available), but i do prefer using different as well so I made that update 👍

Comment on lines 102 to 108
<TooltipIcon
data-testid="sold-out-chip"
icon={<Chip label="Sold Out" />}
status="other"
text={PLAN_IS_SOLD_OUT_COPY}
/>
Copy link
Member

Choose a reason for hiding this comment

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

Should we use a raw Tooltip and Chip here?

I'm not sure if TooltipIcon is the best fit here because of the styles and the fact that it renders a button.

Screenshot 2024-01-02 at 1 36 58 PM

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fair enough - I added a regular tooltip with Chip inside for both instance - also moved the tooltip to the SelectionCard on mobile

Comment on lines 120 to 123
/**
* Utility to map Premium & GPU plans to a selected region's availability.
*/
export const getPlanSoldOutStatus = ({
Copy link
Member

Choose a reason for hiding this comment

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

Optional naming / comment changes. I like using "is" for boolean things

Suggested change
/**
* Utility to map Premium & GPU plans to a selected region's availability.
*/
export const getPlanSoldOutStatus = ({
/**
* Utility to determine if a plan is sold out based on a region's availability.
*/
export const getIsPlanSoldOut = ({
Suggested change
/**
* Utility to map Premium & GPU plans to a selected region's availability.
*/
export const getPlanSoldOutStatus = ({
/**
* Utility to map Premium & GPU plans to a selected region's availability.
*/
export const getPlanSoldOutStatus = ({

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed, done as well!

@@ -109,6 +111,41 @@ export const getRegionsWithCapability = (
return arrayToList(withCapability ?? []);
};

interface PlanSoldOutStatus {
Copy link
Member

Choose a reason for hiding this comment

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

Optional

Suggested change
interface PlanSoldOutStatus {
interface PlanSoldOutStatusOptions {

@mjac0bs
Copy link
Contributor

mjac0bs commented Jan 2, 2024

Thanks for the congruent disabled row treatment!

One more thing to fix with Kube: in selection card mode only, the buttons aren't disabled when the plan is sold out.

Screen.Recording.2024-01-02.at.2.44.48.PM.mov

@abailly-akamai
Copy link
Contributor Author

@mjac0bs feedback addressed as well!

Copy link
Contributor

@mjac0bs mjac0bs left a comment

Choose a reason for hiding this comment

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

Thanks, Alban! Verified light and dark mode both still look good and that rows (and their buttons) are all disabled at various screen sizes once all feedback was addressed.

One tiny nitpick: with the tooltip/chip changes, it looks like we lost a little margin between the plan label and the chip - not sure if that was intentional. They look a little close together and could benefit from a bit of spacing, in my opinion.

Screenshot 2024-01-03 at 1 17 06 PM
Screenshot 2024-01-03 at 1 17 54 PM


const shouldDisplayNoRegionSelectedMessage = !selectedRegionID;
const { data: regionAvailabilities } = useRegionsAvailabilitiesQuery(
Copy link
Member

Choose a reason for hiding this comment

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

Rather than using the useRegionsAvailabilitiesQuery, can we just fetch the availability for selectedRegionId?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah good idea it's available and will make for smaller requests on RegionSelect change - done here:
7adfe39

@mjac0bs mjac0bs added Approved Multiple approvals and ready to merge! and removed Ready for Review labels Jan 4, 2024
@abailly-akamai abailly-akamai merged commit b2d5bc8 into linode:develop Jan 5, 2024
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Approved Multiple approvals and ready to merge! Sold Out Plans
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants