From 9fc1f2610ab20a490f9d11139da23d8e31acfb3b Mon Sep 17 00:00:00 2001 From: Machiko Yasuda Date: Wed, 21 Nov 2018 13:15:55 -0800 Subject: [PATCH 1/5] feat(cartitem): add subtotal --- .../src/components/CartItem/v1/CartItem.js | 48 ++++- .../src/components/CartItem/v1/CartItem.md | 38 ++++ .../components/CartItem/v1/CartItem.test.js | 3 + .../v1/__snapshots__/CartItem.test.js.snap | 188 +++++++++++++++++- .../src/components/CartItems/v1/CartItems.md | 20 +- 5 files changed, 273 insertions(+), 24 deletions(-) diff --git a/package/src/components/CartItem/v1/CartItem.js b/package/src/components/CartItem/v1/CartItem.js index 2666db899..220add778 100644 --- a/package/src/components/CartItem/v1/CartItem.js +++ b/package/src/components/CartItem/v1/CartItem.js @@ -5,6 +5,7 @@ import { withComponents } from "@reactioncommerce/components-context"; import { addTypographyStyles, applyTheme, CustomPropTypes } from "../../../utils"; const Item = styled.div` + position: relative; align-items: flex-start; border-bottom-color: ${applyTheme("CartItem.borderBottomColor")}; border-bottom-style: solid; @@ -90,6 +91,22 @@ const ItemContentPrice = styled.div` } `; +const ItemContentSubtotal = styled.div` + position: absolute; + bottom: 16px; + right: 0; + text-align: right; +`; + +const ItemContentSubtotalTitle = styled.div` + ${addTypographyStyles("ItemContentSubtotalTitle", "labelText")}; + white-space: pre; +`; + +const ItemContentSubtotalDisplay = styled.div` + ${addTypographyStyles("ItemContentSubtotalDisplay", "bodyTextSemiBold")}; +`; + const ItemRemoveButton = styled.button` ${addTypographyStyles("CartItemRemoveButton", "labelText")} align-self: flex-start; @@ -219,6 +236,12 @@ class CartItem extends Component { /** * Chosen items title */ + subtotal: PropTypes.shape({ + /** + * The display subtotal + */ + displayAmount: PropTypes.string, + }), title: PropTypes.string, /** * Quantity of chosen item in cart @@ -293,10 +316,12 @@ class CartItem extends Component { title, quantity, isLowQuantity, - price: { displayAmount: displayPrice } + price: { displayAmount: displayPrice }, + subtotal } } = this.props; + const { displayAmount: displaySubtotal } = subtotal || {}; const { displayAmount: displayCompareAtPrice } = compareAtPrice || {}; const { @@ -339,15 +364,20 @@ class CartItem extends Component { {!isReadOnly && Remove} - - - - + + + {displaySubtotal && + + Total ({quantity}): + {displaySubtotal} + + } + ); } diff --git a/package/src/components/CartItem/v1/CartItem.md b/package/src/components/CartItem/v1/CartItem.md index 89b1004da..a5062d02c 100644 --- a/package/src/components/CartItem/v1/CartItem.md +++ b/package/src/components/CartItem/v1/CartItem.md @@ -26,6 +26,9 @@ const item = { }, productSlug: "product-slug", productVendor: "Patagonia", + subtotal: { + displayAmount: "$40.00", + }, title: "A Great Product", quantity: 2 }; @@ -37,6 +40,41 @@ const item = { /> ``` +#### Default: isMiniCart + +```jsx +const item = { + _id: "123", + attributes: [{ label: "Color", value: "Red" }, { label: "Size", value: "Medium" }], + compareAtPrice: { + displayAmount: "$45.00" + }, + currentQuantity: 3, + imageURLs: { + small: "//placehold.it/150", + thumbnail: "//placehold.it/100" + }, + isLowQuantity: true, + price: { + displayAmount: "$20.00" + }, + productSlug: "product-slug", + productVendor: "Patagonia", + subtotal: { + displayAmount: "$40.00", + }, + title: "A Great Product", + quantity: 2 +}; + + console.log("cart item quantity changed to", value, "for item", _id)} + onRemoveItemFromCart={() => console.log("Item removed from cart")} +/> +``` + #### Without Compare At Price ```jsx const item = { diff --git a/package/src/components/CartItem/v1/CartItem.test.js b/package/src/components/CartItem/v1/CartItem.test.js index 1693ed5df..87ee52018 100644 --- a/package/src/components/CartItem/v1/CartItem.test.js +++ b/package/src/components/CartItem/v1/CartItem.test.js @@ -21,6 +21,9 @@ const mockItem = { }, productSlug: "product-slug", productVendor: "Patagonia", + subtotal: { + displayAmount: "$40.00", + }, title: "A Great Product", quantity: 2 }; diff --git a/package/src/components/CartItem/v1/__snapshots__/CartItem.test.js.snap b/package/src/components/CartItem/v1/__snapshots__/CartItem.test.js.snap index b1c1201c9..464ac9490 100644 --- a/package/src/components/CartItem/v1/__snapshots__/CartItem.test.js.snap +++ b/package/src/components/CartItem/v1/__snapshots__/CartItem.test.js.snap @@ -2,6 +2,7 @@ exports[`basic snapshot with empty props 1`] = ` .c0 { + position: relative; -webkit-align-items: flex-start; -webkit-box-align: flex-start; -ms-flex-align: flex-start; @@ -193,17 +194,18 @@ exports[`basic snapshot with empty props 1`] = ` Remove -
- Price(undefined) -
+ +
+ Price(undefined)
`; exports[`basic snapshot with isReadOnly prop 1`] = ` .c0 { + position: relative; -webkit-align-items: flex-start; -webkit-box-align: flex-start; -ms-flex-align: flex-start; @@ -295,6 +297,44 @@ exports[`basic snapshot with isReadOnly prop 1`] = ` right: 0; } +.c6 { + position: absolute; + bottom: 16px; + right: 0; + text-align: right; +} + +.c7 { + -webkit-font-smoothing: antialiased; + color: #505558; + font-family: 'Source Sans Pro','Helvetica Neue',Helvetica,sans-serif; + font-size: 14px; + font-style: normal; + font-stretch: normal; + font-weight: 400; + -webkit-letter-spacing: .02em; + -moz-letter-spacing: .02em; + -ms-letter-spacing: .02em; + letter-spacing: .02em; + line-height: 1.25; + white-space: pre; +} + +.c8 { + -webkit-font-smoothing: antialiased; + color: #3c3c3c; + font-family: 'Source Sans Pro','Helvetica Neue',Helvetica,sans-serif; + font-size: 16px; + font-style: normal; + font-stretch: normal; + font-weight: 600; + -webkit-letter-spacing: .03em; + -moz-letter-spacing: .03em; + -ms-letter-spacing: .03em; + letter-spacing: .03em; + line-height: 1.5; +} + @media (min-width:992px) { .c4 { -webkit-flex: 1 1 auto; @@ -349,10 +389,26 @@ exports[`basic snapshot with isReadOnly prop 1`] = ` + +
+ Price(undefined)
- Price(undefined) +
+ Total ( + 2 + ): +
+
+ $40.00 +
@@ -360,6 +416,7 @@ exports[`basic snapshot with isReadOnly prop 1`] = ` exports[`basic snapshot with productURLPath prop 1`] = ` .c0 { + position: relative; -webkit-align-items: flex-start; -webkit-box-align: flex-start; -ms-flex-align: flex-start; @@ -451,6 +508,44 @@ exports[`basic snapshot with productURLPath prop 1`] = ` right: 0; } +.c6 { + position: absolute; + bottom: 16px; + right: 0; + text-align: right; +} + +.c7 { + -webkit-font-smoothing: antialiased; + color: #505558; + font-family: 'Source Sans Pro','Helvetica Neue',Helvetica,sans-serif; + font-size: 14px; + font-style: normal; + font-stretch: normal; + font-weight: 400; + -webkit-letter-spacing: .02em; + -moz-letter-spacing: .02em; + -ms-letter-spacing: .02em; + letter-spacing: .02em; + line-height: 1.25; + white-space: pre; +} + +.c8 { + -webkit-font-smoothing: antialiased; + color: #3c3c3c; + font-family: 'Source Sans Pro','Helvetica Neue',Helvetica,sans-serif; + font-size: 16px; + font-style: normal; + font-stretch: normal; + font-weight: 600; + -webkit-letter-spacing: .03em; + -moz-letter-spacing: .03em; + -ms-letter-spacing: .03em; + letter-spacing: .03em; + line-height: 1.5; +} + @media (min-width:992px) { .c4 { -webkit-flex: 1 1 auto; @@ -505,10 +600,26 @@ exports[`basic snapshot with productURLPath prop 1`] = ` + +
+ Price(undefined)
- Price(undefined) +
+ Total ( + 2 + ): +
+
+ $40.00 +
@@ -516,6 +627,7 @@ exports[`basic snapshot with productURLPath prop 1`] = ` exports[`basic snapshot with props 1`] = ` .c0 { + position: relative; -webkit-align-items: flex-start; -webkit-box-align: flex-start; -ms-flex-align: flex-start; @@ -614,6 +726,44 @@ exports[`basic snapshot with props 1`] = ` right: 0; } +.c8 { + position: absolute; + bottom: 16px; + right: 0; + text-align: right; +} + +.c9 { + -webkit-font-smoothing: antialiased; + color: #505558; + font-family: 'Source Sans Pro','Helvetica Neue',Helvetica,sans-serif; + font-size: 14px; + font-style: normal; + font-stretch: normal; + font-weight: 400; + -webkit-letter-spacing: .02em; + -moz-letter-spacing: .02em; + -ms-letter-spacing: .02em; + letter-spacing: .02em; + line-height: 1.25; + white-space: pre; +} + +.c10 { + -webkit-font-smoothing: antialiased; + color: #3c3c3c; + font-family: 'Source Sans Pro','Helvetica Neue',Helvetica,sans-serif; + font-size: 16px; + font-style: normal; + font-stretch: normal; + font-weight: 600; + -webkit-letter-spacing: .03em; + -moz-letter-spacing: .03em; + -ms-letter-spacing: .03em; + letter-spacing: .03em; + line-height: 1.5; +} + .c6 { -webkit-font-smoothing: antialiased; color: #505558; @@ -726,10 +876,26 @@ exports[`basic snapshot with props 1`] = ` Remove + +
+ Price(undefined)
- Price(undefined) +
+ Total ( + 2 + ): +
+
+ $40.00 +
diff --git a/package/src/components/CartItems/v1/CartItems.md b/package/src/components/CartItems/v1/CartItems.md index df4397927..033940d71 100644 --- a/package/src/components/CartItems/v1/CartItems.md +++ b/package/src/components/CartItems/v1/CartItems.md @@ -26,7 +26,10 @@ const items = [{ productSlug: "product-slug", productVendor: "Patagonia", title: "A Great Product", - quantity: 2 + quantity: 2, + subtotal: { + displayAmount: "$40.00", + } }, { _id: "456", @@ -43,7 +46,10 @@ const items = [{ productSlug: "product-slug", productVendor: "Patagonia", title: "Another Great Product", - quantity: 1 + quantity: 1, + subtotal: { + displayAmount: "$40.00", + } }]; const handleChangeCartItemQuantity = (value, _id) => console.log("cart items new quantity", value, "for item", _id); @@ -77,7 +83,10 @@ const items = [{ productVendor: "Patagonia", productSlug: "product-slug", title: "A Great Product", - quantity: 2 + quantity: 2, + subtotal: { + displayAmount: "$40.00", + } }, { _id: "456", @@ -94,7 +103,10 @@ const items = [{ productSlug: "product-slug", productVendor: "Nike", title: "Another Great Product", - quantity: 1 + quantity: 1, + subtotal: { + displayAmount: "$40.00", + } }]; const handleChangeCartItemQuantity = (value, _id) => console.log("cart items new quantity", value, "for item", _id); From c9371ab1c64513b31634e730dde4f9f929d09712 Mon Sep 17 00:00:00 2001 From: Machiko Yasuda Date: Wed, 21 Nov 2018 14:50:49 -0800 Subject: [PATCH 2/5] style(cartitem): update CartItem style when mobile --- .../src/components/CartItem/v1/CartItem.js | 22 +++-- .../v1/__snapshots__/CartItem.test.js.snap | 84 +++++++++++++------ .../src/components/CartItems/v1/CartItems.md | 1 + package/src/theme/defaultComponentTheme.js | 1 + 4 files changed, 76 insertions(+), 32 deletions(-) diff --git a/package/src/components/CartItem/v1/CartItem.js b/package/src/components/CartItem/v1/CartItem.js index 220add778..506db2819 100644 --- a/package/src/components/CartItem/v1/CartItem.js +++ b/package/src/components/CartItem/v1/CartItem.js @@ -80,22 +80,28 @@ const ItemContentQuantityInput = styled.div` `; const ItemContentPrice = styled.div` - bottom: 0; - flex: 0 1 auto; - position: absolute; + position: ${(props) => (props.isMiniCart ? "absolute" : "initial")}; + bottom: ${applyTheme("CartItem.paddingBottom")}; right: 0; - + text-align: right; + @media (max-width: 768px) { + position: absolute; + } @media (min-width: 768px) { margin-left: 1.5rem; - position: ${({ isMiniCart }) => (isMiniCart ? "absolute" : "relative")}; } `; const ItemContentSubtotal = styled.div` - position: absolute; - bottom: 16px; + position: ${(props) => (props.isMiniCart ? "initial" : "absolute")}; + margin-top: ${(props) => (props.isMiniCart ? applyTheme("CartItem.subtotalDisplaySpacingAbove")(props) : "0")}; + bottom: ${applyTheme("CartItem.paddingBottom")}; right: 0; text-align: right; + @media (max-width: 768px) { + position: initial; + margin-top: ${applyTheme("CartItem.subtotalDisplaySpacingAbove")}; + } `; const ItemContentSubtotalTitle = styled.div` @@ -372,7 +378,7 @@ class CartItem extends Component { hasPriceBottom={isMiniCart} /> {displaySubtotal && - + Total ({quantity}): {displaySubtotal} diff --git a/package/src/components/CartItem/v1/__snapshots__/CartItem.test.js.snap b/package/src/components/CartItem/v1/__snapshots__/CartItem.test.js.snap index 464ac9490..6d9b63013 100644 --- a/package/src/components/CartItem/v1/__snapshots__/CartItem.test.js.snap +++ b/package/src/components/CartItem/v1/__snapshots__/CartItem.test.js.snap @@ -93,12 +93,10 @@ exports[`basic snapshot with empty props 1`] = ` } .c7 { - bottom: 0; - -webkit-flex: 0 1 auto; - -ms-flex: 0 1 auto; - flex: 0 1 auto; - position: absolute; + position: initial; + bottom: 16px; right: 0; + text-align: right; } .c6 { @@ -156,10 +154,15 @@ exports[`basic snapshot with empty props 1`] = ` } } +@media (max-width:768px) { + .c7 { + position: absolute; + } +} + @media (min-width:768px) { .c7 { margin-left: 1.5rem; - position: relative; } } @@ -289,16 +292,15 @@ exports[`basic snapshot with isReadOnly prop 1`] = ` } .c5 { - bottom: 0; - -webkit-flex: 0 1 auto; - -ms-flex: 0 1 auto; - flex: 0 1 auto; - position: absolute; + position: initial; + bottom: 16px; right: 0; + text-align: right; } .c6 { position: absolute; + margin-top: 0; bottom: 16px; right: 0; text-align: right; @@ -343,10 +345,22 @@ exports[`basic snapshot with isReadOnly prop 1`] = ` } } +@media (max-width:768px) { + .c5 { + position: absolute; + } +} + @media (min-width:768px) { .c5 { margin-left: 1.5rem; - position: relative; + } +} + +@media (max-width:768px) { + .c6 { + position: initial; + margin-top: 10px; } } @@ -500,16 +514,15 @@ exports[`basic snapshot with productURLPath prop 1`] = ` } .c5 { - bottom: 0; - -webkit-flex: 0 1 auto; - -ms-flex: 0 1 auto; - flex: 0 1 auto; - position: absolute; + position: initial; + bottom: 16px; right: 0; + text-align: right; } .c6 { position: absolute; + margin-top: 0; bottom: 16px; right: 0; text-align: right; @@ -554,10 +567,22 @@ exports[`basic snapshot with productURLPath prop 1`] = ` } } +@media (max-width:768px) { + .c5 { + position: absolute; + } +} + @media (min-width:768px) { .c5 { margin-left: 1.5rem; - position: relative; + } +} + +@media (max-width:768px) { + .c6 { + position: initial; + margin-top: 10px; } } @@ -718,16 +743,15 @@ exports[`basic snapshot with props 1`] = ` } .c7 { - bottom: 0; - -webkit-flex: 0 1 auto; - -ms-flex: 0 1 auto; - flex: 0 1 auto; - position: absolute; + position: initial; + bottom: 16px; right: 0; + text-align: right; } .c8 { position: absolute; + margin-top: 0; bottom: 16px; right: 0; text-align: right; @@ -819,10 +843,22 @@ exports[`basic snapshot with props 1`] = ` } } +@media (max-width:768px) { + .c7 { + position: absolute; + } +} + @media (min-width:768px) { .c7 { margin-left: 1.5rem; - position: relative; + } +} + +@media (max-width:768px) { + .c8 { + position: initial; + margin-top: 10px; } } diff --git a/package/src/components/CartItems/v1/CartItems.md b/package/src/components/CartItems/v1/CartItems.md index 033940d71..f685d1676 100644 --- a/package/src/components/CartItems/v1/CartItems.md +++ b/package/src/components/CartItems/v1/CartItems.md @@ -64,6 +64,7 @@ const handleRemoveItemFromCart = (_id) => console.log("cart items remove this it ``` #### In Mini Cart + ```jsx const items = [{ _id: "123", diff --git a/package/src/theme/defaultComponentTheme.js b/package/src/theme/defaultComponentTheme.js index 7a8eb8b2e..df74ec241 100644 --- a/package/src/theme/defaultComponentTheme.js +++ b/package/src/theme/defaultComponentTheme.js @@ -236,6 +236,7 @@ const rui_components = { paddingLeft: 0, paddingRight: 0, paddingTop: padding.sixteen, + subtotalDisplaySpacingAbove: padding.ten, quantityInputSpacingAbove: padding.twelve, quantityInputSpacingBelow: padding.eight, removeButtonColor_focus: colors.coolGrey, From 571ee8e51b1bff8f41714fa16bd411b65057b31d Mon Sep 17 00:00:00 2001 From: Nat Hamilton Date: Mon, 26 Nov 2018 10:10:47 -0600 Subject: [PATCH 3/5] chore: eslint --fix --- package/src/components/CartItem/v1/CartItem.js | 6 +++--- package/src/components/CartItem/v1/CartItem.test.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package/src/components/CartItem/v1/CartItem.js b/package/src/components/CartItem/v1/CartItem.js index 506db2819..5832bb39f 100644 --- a/package/src/components/CartItem/v1/CartItem.js +++ b/package/src/components/CartItem/v1/CartItem.js @@ -246,7 +246,7 @@ class CartItem extends Component { /** * The display subtotal */ - displayAmount: PropTypes.string, + displayAmount: PropTypes.string }), title: PropTypes.string, /** @@ -377,13 +377,13 @@ class CartItem extends Component { displayCompareAtPrice={displayCompareAtPrice} hasPriceBottom={isMiniCart} /> - {displaySubtotal && + {displaySubtotal && Total ({quantity}): {displaySubtotal} } - + ); } diff --git a/package/src/components/CartItem/v1/CartItem.test.js b/package/src/components/CartItem/v1/CartItem.test.js index 87ee52018..2beccf15d 100644 --- a/package/src/components/CartItem/v1/CartItem.test.js +++ b/package/src/components/CartItem/v1/CartItem.test.js @@ -22,7 +22,7 @@ const mockItem = { productSlug: "product-slug", productVendor: "Patagonia", subtotal: { - displayAmount: "$40.00", + displayAmount: "$40.00" }, title: "A Great Product", quantity: 2 From f85ff2f7be422e96bd39650aad618add830ef573 Mon Sep 17 00:00:00 2001 From: Machiko Yasuda Date: Tue, 27 Nov 2018 16:50:37 -0800 Subject: [PATCH 4/5] style: only show subtotal if there is more than 1 --- .../src/components/CartItem/v1/CartItem.js | 4 +- .../v1/__snapshots__/CartItem.test.js.snap | 59 +++++++++++++++++++ .../src/components/CartItems/v1/CartItems.md | 2 +- 3 files changed, 63 insertions(+), 2 deletions(-) diff --git a/package/src/components/CartItem/v1/CartItem.js b/package/src/components/CartItem/v1/CartItem.js index 506db2819..90d459d76 100644 --- a/package/src/components/CartItem/v1/CartItem.js +++ b/package/src/components/CartItem/v1/CartItem.js @@ -377,11 +377,13 @@ class CartItem extends Component { displayCompareAtPrice={displayCompareAtPrice} hasPriceBottom={isMiniCart} /> - {displaySubtotal && + { quantity != 1 ? Total ({quantity}): {displaySubtotal} + : + null } diff --git a/package/src/components/CartItem/v1/__snapshots__/CartItem.test.js.snap b/package/src/components/CartItem/v1/__snapshots__/CartItem.test.js.snap index 6d9b63013..62c318944 100644 --- a/package/src/components/CartItem/v1/__snapshots__/CartItem.test.js.snap +++ b/package/src/components/CartItem/v1/__snapshots__/CartItem.test.js.snap @@ -99,6 +99,45 @@ exports[`basic snapshot with empty props 1`] = ` text-align: right; } +.c8 { + position: absolute; + margin-top: 0; + bottom: 16px; + right: 0; + text-align: right; +} + +.c9 { + -webkit-font-smoothing: antialiased; + color: #505558; + font-family: 'Source Sans Pro','Helvetica Neue',Helvetica,sans-serif; + font-size: 14px; + font-style: normal; + font-stretch: normal; + font-weight: 400; + -webkit-letter-spacing: .02em; + -moz-letter-spacing: .02em; + -ms-letter-spacing: .02em; + letter-spacing: .02em; + line-height: 1.25; + white-space: pre; +} + +.c10 { + -webkit-font-smoothing: antialiased; + color: #3c3c3c; + font-family: 'Source Sans Pro','Helvetica Neue',Helvetica,sans-serif; + font-size: 16px; + font-style: normal; + font-stretch: normal; + font-weight: 600; + -webkit-letter-spacing: .03em; + -moz-letter-spacing: .03em; + -ms-letter-spacing: .03em; + letter-spacing: .03em; + line-height: 1.5; +} + .c6 { -webkit-font-smoothing: antialiased; color: #505558; @@ -166,6 +205,13 @@ exports[`basic snapshot with empty props 1`] = ` } } +@media (max-width:768px) { + .c8 { + position: initial; + margin-top: 10px; + } +} +
@@ -202,6 +248,19 @@ exports[`basic snapshot with empty props 1`] = ` className="c7" > Price(undefined) +
+
+ Total ( + ): +
+
+
`; diff --git a/package/src/components/CartItems/v1/CartItems.md b/package/src/components/CartItems/v1/CartItems.md index f685d1676..828aaa1c7 100644 --- a/package/src/components/CartItems/v1/CartItems.md +++ b/package/src/components/CartItems/v1/CartItems.md @@ -106,7 +106,7 @@ const items = [{ title: "Another Great Product", quantity: 1, subtotal: { - displayAmount: "$40.00", + displayAmount: "$78.00", } }]; From e398e88633fa873ce7473880b8e8920907c56fd4 Mon Sep 17 00:00:00 2001 From: Machiko Yasuda Date: Wed, 28 Nov 2018 10:31:49 -0800 Subject: [PATCH 5/5] chore: lint --- package/src/components/CartItem/v1/CartItem.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/src/components/CartItem/v1/CartItem.js b/package/src/components/CartItem/v1/CartItem.js index 7a7e22615..7016e0db0 100644 --- a/package/src/components/CartItem/v1/CartItem.js +++ b/package/src/components/CartItem/v1/CartItem.js @@ -377,7 +377,7 @@ class CartItem extends Component { displayCompareAtPrice={displayCompareAtPrice} hasPriceBottom={isMiniCart} /> - { quantity != 1 ? + { quantity !== 1 ? Total ({quantity}): {displaySubtotal}