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

[feature]: Replace ProductQuantity on Product Page with QuantityFields stepper #2690

Merged
merged 9 commits into from Oct 1, 2020
Expand Up @@ -119,5 +119,6 @@ exports[`renders quantity correctly 1`] = `
</span>
</button>
</div>

</form>
`;
Expand Up @@ -12,7 +12,8 @@ const defaultProps = {
itemId: 'item1',
label: 'Test Quantity',
min: 0,
onChange: mockOnChange
onChange: mockOnChange,
message: ''
};

test('renders quantity correctly', () => {
Expand Down
@@ -1,4 +1,4 @@
import React from 'react';
import React, { Fragment } from 'react';
import { Form } from 'informed';
import { func, number, string } from 'prop-types';
import { Minus as MinusIcon, Plus as PlusIcon } from 'react-feather';
Expand All @@ -7,10 +7,11 @@ import { useQuantity } from '@magento/peregrine/lib/talons/CartPage/ProductListi
import { mergeClasses } from '../../../classify';
import Icon from '../../Icon';
import TextInput from '../../TextInput';
import { Message } from '../../Field';
import defaultClasses from './quantity.css';

export const QuantityFields = props => {
const { initialValue, itemId, label, min, onChange } = props;
const { initialValue, itemId, label, min, onChange, message } = props;
const classes = mergeClasses(defaultClasses, props.classes);
const iconClasses = { root: classes.icon };

Expand All @@ -29,41 +30,46 @@ export const QuantityFields = props => {
maskInput
} = talonProps;

const errorMessage = message ? <Message>{message}</Message> : null;
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks good - my only concern is that the message is a bit close to the field and not red.

Copy link
Contributor

Choose a reason for hiding this comment

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

We stuck with the same UX from the dropdown treatment, which you recently implemented 😉 it looks pretty identical to me.

#2690 (comment)


return (
<div className={classes.root}>
<label className={classes.label} htmlFor={itemId}>
{label}
</label>
<button
aria-label={'Decrease Quantity'}
className={classes.button_decrement}
disabled={isDecrementDisabled}
onClick={handleDecrement}
type="button"
>
<Icon classes={iconClasses} src={MinusIcon} size={22} />
</button>
<TextInput
aria-label="Item Quantity"
classes={{ input: classes.input }}
field="quantity"
id={itemId}
inputMode="numeric"
mask={maskInput}
min={min}
onBlur={handleBlur}
pattern="[0-9]*"
/>
<button
aria-label={'Increase Quantity'}
className={classes.button_increment}
disabled={isIncrementDisabled}
onClick={handleIncrement}
type="button"
>
<Icon classes={iconClasses} src={PlusIcon} size={20} />
</button>
</div>
<Fragment>
<div className={classes.root}>
<label className={classes.label} htmlFor={itemId}>
{label}
</label>
<button
aria-label={'Decrease Quantity'}
className={classes.button_decrement}
disabled={isDecrementDisabled}
onClick={handleDecrement}
type="button"
>
<Icon classes={iconClasses} src={MinusIcon} size={22} />
</button>
<TextInput
aria-label="Item Quantity"
classes={{ input: classes.input }}
field="quantity"
id={itemId}
inputMode="numeric"
mask={maskInput}
min={min}
onBlur={handleBlur}
pattern="[0-9]*"
/>
<button
aria-label={'Increase Quantity'}
className={classes.button_increment}
disabled={isIncrementDisabled}
onClick={handleIncrement}
type="button"
>
<Icon classes={iconClasses} src={PlusIcon} size={20} />
</button>
</div>
{errorMessage}
</Fragment>
);
};

Expand All @@ -84,7 +90,8 @@ Quantity.propTypes = {
itemId: string,
label: string,
min: number,
onChange: func
onChange: func,
message: string
};

Quantity.defaultProps = {
Expand Down
Expand Up @@ -49,10 +49,7 @@ exports[`it disables the add to cart button when the talon indicates 1`] = `
>
Quantity
</h2>
<ProductQuantity
initialValue={1}
onValueChange={[MockFunction]}
/>
QuantityFields
</section>
<section
className="cartActions"
Expand Down Expand Up @@ -144,10 +141,7 @@ exports[`it does not render options if the product is not a ConfigurableProduct
>
Quantity
</h2>
<ProductQuantity
initialValue={1}
onValueChange={[MockFunction]}
/>
QuantityFields
</section>
<section
className="cartActions"
Expand Down Expand Up @@ -245,10 +239,7 @@ exports[`it renders an error for an invalid user token when adding to cart 1`] =
>
Quantity
</h2>
<ProductQuantity
initialValue={1}
onValueChange={[MockFunction]}
/>
QuantityFields
</section>
<section
className="cartActions"
Expand Down Expand Up @@ -347,10 +338,7 @@ Array [
>
Quantity
</h2>
<ProductQuantity
initialValue={1}
onValueChange={[MockFunction]}
/>
QuantityFields
</section>
<section
className="cartActions"
Expand Down Expand Up @@ -518,10 +506,7 @@ exports[`it renders correctly 1`] = `
>
Quantity
</h2>
<ProductQuantity
initialValue={1}
onValueChange={[MockFunction]}
/>
QuantityFields
</section>
<section
className="cartActions"
Expand Down Expand Up @@ -615,11 +600,7 @@ exports[`it renders field level errors for quantity - message 1 1`] = `
>
Quantity
</h2>
<ProductQuantity
initialValue={1}
message="The requested quantity is not available."
onValueChange={[MockFunction]}
/>
QuantityFields
</section>
<section
className="cartActions"
Expand Down Expand Up @@ -713,11 +694,7 @@ exports[`it renders field level errors for quantity - message 2 1`] = `
>
Quantity
</h2>
<ProductQuantity
initialValue={1}
message="The requested quantity is not available."
onValueChange={[MockFunction]}
/>
QuantityFields
</section>
<section
className="cartActions"
Expand Down Expand Up @@ -811,11 +788,7 @@ exports[`it renders field level errors for quantity - message 3 1`] = `
>
Quantity
</h2>
<ProductQuantity
initialValue={1}
message="The requested quantity is not available."
onValueChange={[MockFunction]}
/>
QuantityFields
</section>
<section
className="cartActions"
Expand Down Expand Up @@ -913,10 +886,7 @@ exports[`it renders form level errors 1`] = `
>
Quantity
</h2>
<ProductQuantity
initialValue={1}
onValueChange={[MockFunction]}
/>
QuantityFields
</section>
<section
className="cartActions"
Expand Down
Expand Up @@ -26,7 +26,9 @@ jest.mock('../../Breadcrumbs', () => 'Breadcrumbs');
jest.mock('../../FormError', () => 'FormError');
jest.mock('../../ProductImageCarousel', () => 'ProductImageCarousel');
jest.mock('../../ProductOptions', () => () => 'ProductOptions');
jest.mock('../../ProductQuantity', () => 'ProductQuantity');
jest.mock('../../CartPage/ProductListing/quantity', () => ({
QuantityFields: () => 'QuantityFields'
}));
jest.mock('../../RichText', () => 'RichText');

jest.mock('../../../classify');
Expand Down
Expand Up @@ -166,3 +166,9 @@
.relatedTitle {
composes: sectionTitle;
}

.quantityRoot {
composes: root from '../CartPage/ProductListing/quantity.css';
grid-template-columns: auto 4rem auto;
justify-content: start;
}
Expand Up @@ -12,7 +12,7 @@ import Button from '../Button';
import Carousel from '../ProductImageCarousel';
import FormError from '../FormError';
import { fullPageLoadingIndicator } from '../LoadingIndicator';
import Quantity from '../ProductQuantity';
Copy link
Contributor

Choose a reason for hiding this comment

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

Oh also, can we throw a @deprecated label on the old ProductQuantity component? After this PR it will only be used in the legacy mini cart.

Copy link
Contributor

Choose a reason for hiding this comment

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

There were two things I wanted to do as a followup, prefer to just merge this:

#2690 (review)

Copy link
Contributor

Choose a reason for hiding this comment

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

Created PWA-960, thanks for the reminder; would have missed actually creating that in the backlog.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@tjwiebell please mention to me when you create that issue. I hope I can resolve that :D

import { QuantityFields } from '../CartPage/ProductListing/quantity';
import RichText from '../RichText';

import defaultClasses from './productFullDetail.css';
Expand Down Expand Up @@ -145,9 +145,11 @@ const ProductFullDetail = props => {
<section className={classes.options}>{options}</section>
<section className={classes.quantity}>
<h2 className={classes.quantityTitle}>Quantity</h2>
<Quantity
<QuantityFields
classes={{ root: classes.quantityRoot }}
initialValue={quantity}
onValueChange={handleSetQuantity}
onChange={handleSetQuantity}
min={1}
message={errors.get('quantity')}
/>
</section>
Expand Down