Repository: reactioncommerce/reaction-component-library
Pull request #133 (2018-07-16 21:55:19)

fix: update CartItem props to match GraphQL schema changes
Impact: **minor**  
Type: **bugfix**

<!-- 📦🚀 This project is deployed with [semantic-release](https://github.com/semantic-release/semantic-release) -->

<!-- Any PR with commits that start with `feat:` or `fix:` will trigger new major or minor release respectively -->

## Affected Components
- CartItem
- CartItems
- CartItemDetail

## Screenshots
No visual changes. Everything should look the same.

## Breaking changes
None

## Testing
Verify that the listed components still look and function correct.

machikoyasuda: 🚀 Preview deployed

Built with commit 824ad50106c5f61f0b419e44edc84733c2770934

https://deploy-preview-133--stoic-hodgkin-c0179e.netlify.com

Patch:
diff --git a/package/src/components/CartItem/v1/CartItem.js b/package/src/components/CartItem/v1/CartItem.js
index 0c01d880..01e16df7 100644
--- a/package/src/components/CartItem/v1/CartItem.js
+++ b/package/src/components/CartItem/v1/CartItem.js
@@ -128,45 +128,51 @@ class CartItem extends Component {
       /**
        * Array of additional attributes of the chosen item.
        */
-      attributes: PropTypes.arrayOf(PropTypes.shape({
-        /**
-           * Attribute label (i.e. "Color").
-           */
-        label: PropTypes.string,
+      attributes: PropTypes.arrayOf(PropTypes.object),
+      /**
+       * The current compareAt price (MSRP)
+       */
+      compareAtPrice: PropTypes.shape({
         /**
-           *  Attribute value (i.e. "Red").
-           */
-        value: PropTypes.string
-      })),
+         * The display price
+         */
+        displayAmount: PropTypes.string.isRequired
+      }),
       /**
        * Current stock quantity of item
        */
       currentQuantity: PropTypes.number,
       /**
-       * Image url of chosen item
+       * Image URLs of chosen item
        */
-      imageUrl: PropTypes.string,
+      imageURLs: PropTypes.shape({
+        large: PropTypes.string,
+        medium: PropTypes.string,
+        original: PropTypes.string,
+        small: PropTypes.string,
+        thumbnail: PropTypes.string
+      }),
       /**
        * Is the chosen item have a low quantity
        */
-      isLowInventoryQuantity: PropTypes.bool,
+      isLowQuantity: PropTypes.bool,
       /**
        * Price object of chosen item
        */
       price: PropTypes.shape({
         /**
-         * Chosen items compare at price
-         */
-        compareAtPrice: PropTypes.string,
-        /**
-         * Chosen items display price
+         * The display price
          */
-        displayPrice: PropTypes.string
-      }),
+        displayAmount: PropTypes.string.isRequired
+      }).isRequired,
       /**
        * Chosen items slug
        */
       productSlug: PropTypes.string,
+      /**
+       * Chosen items vendor
+       */
+      productVendor: PropTypes.string,
       /**
        * Chosen items title
        */
@@ -193,6 +199,7 @@ class CartItem extends Component {
       CartItemPriceComponent: "Cart Item Price",
       CartItemQuantityInputComponent: "Cart Item Quantity Input"
     },
+    isMiniCart: false,
     onChangeCartItemQuantity() {},
     onRemoveItemFromCart() {}
   };
@@ -212,12 +219,17 @@ class CartItem extends Component {
   };
 
   renderImage() {
-    const { isMiniCart, item: { imageUrl, productSlug } } = this.props;
+    const { isMiniCart, item: { imageURLs, productSlug } } = this.props;
+
+    const { small, thumbnail } = imageURLs || {};
+
+    if (!small || !thumbnail) return null;
+
     return (
       <a href={productSlug}>
         <picture>
-          {isMiniCart ? "" : <source srcSet={`${imageUrl}/150`} media="(min-width: 768px)" />}
-          <img src={`${imageUrl}/100`} alt="" style={{ display: "block" }} />
+          {isMiniCart ? "" : <source srcSet={small} media="(min-width: 768px)" />}
+          <img src={thumbnail} alt="" style={{ display: "block" }} />
         </picture>
       </a>
     );
@@ -234,14 +246,18 @@ class CartItem extends Component {
       isMiniCart,
       item: {
         attributes,
+        compareAtPrice,
         currentQuantity,
         productSlug,
+        productVendor,
         title,
         quantity,
-        isLowInventoryQuantity,
-        price: { displayPrice, compareAtPrice }
+        isLowQuantity,
+        price: { displayAmount: displayPrice }
       }
     } = this.props;
+    const { displayAmount: displayCompareAtPrice } = compareAtPrice || {};
+
     return (
       <Item>
         {this.renderImage()}
@@ -252,13 +268,14 @@ class CartItem extends Component {
                 <CartItemDetailComponent
                   title={title}
                   productSlug={productSlug}
+                  productVendor={productVendor}
                   attributes={attributes}
                   isMiniCart={isMiniCart}
                 />
 
                 <CartItemStockWarningComponent
                   inventoryQuantity={currentQuantity}
-                  isLowInventoryQuantity={isLowInventoryQuantity}
+                  isLowInventoryQuantity={isLowQuantity}
                 />
               </ItemContentDetailInfo>
 
@@ -273,7 +290,7 @@ class CartItem extends Component {
           <ItemContentPrice isMiniCart={isMiniCart}>
             <CartItemPriceComponent
               displayPrice={displayPrice}
-              displayCompareAtPrice={compareAtPrice}
+              displayCompareAtPrice={displayCompareAtPrice}
               hasPriceBottom={isMiniCart}
             />
           </ItemContentPrice>
diff --git a/package/src/components/CartItem/v1/CartItem.md b/package/src/components/CartItem/v1/CartItem.md
index f1cee091..30486941 100644
--- a/package/src/components/CartItem/v1/CartItem.md
+++ b/package/src/components/CartItem/v1/CartItem.md
@@ -8,15 +8,21 @@ It could be used in the future to show items that are within a "Wish List", "Sav
 ```jsx
 const item = {
   _id: "123",
-  attributes: [{ label: "vendor", value: "Patagonia" }, { label: "Color", value: "Red" }, { label: "Size", value: "Medium" }],
+  attributes: [{ label: "Color", value: "Red" }, { label: "Size", value: "Medium" }],
+  compareAtPrice: {
+    displayAmount: "$45.00"
+  },
   currentQuantity: 3,
-  imageUrl: "//placehold.it",
-  isLowInventoryQuantity: true,
+  imageURLs: {
+    small: "//placehold.it/150",
+    thumbnail: "//placehold.it/100"
+  },
+  isLowQuantity: true,
   price: {
-    displayPrice: "$20.00",
-    compareAtPrice: "$45.00"
+    displayAmount: "$20.00"
   },
   productSlug: "/product-slug",
+  productVendor: "Patagonia",
   title: "A Great Product",
   quantity: 2
 };
@@ -38,14 +44,18 @@ const item = {
 ```jsx
 const item = {
   _id: "123",
-  attributes: [{ label: "vendor", value: "Patagonia" }, { label: "Color", value: "Red" }, { label: "Size", value: "Medium" }],
+  attributes: [{ label: "Color", value: "Red" }, { label: "Size", value: "Medium" }],
   currentQuantity: 3,
-  imageUrl: "//placehold.it",
-  isLowInventoryQuantity: true,
+  imageURLs: {
+    small: "//placehold.it/150",
+    thumbnail: "//placehold.it/100"
+  },
+  isLowQuantity: true,
   price: {
-    displayPrice: "$20.00"
+    displayAmount: "$20.00"
   },
   productSlug: "/product-slug",
+  productVendor: "Patagonia",
   title: "A Great Product",
   quantity: 2
 };
@@ -67,15 +77,21 @@ const item = {
 ```jsx
 const item = {
   _id: "123",
-  attributes: [{ label: "vendor", value: "Patagonia" }, { label: "Color", value: "Red" }, { label: "Size", value: "Medium" }],
+  attributes: [{ label: "Color", value: "Red" }, { label: "Size", value: "Medium" }],
+  compareAtPrice: {
+    displayAmount: "$45.00"
+  },
   currentQuantity: 3,
-  imageUrl: "//placehold.it",
-  isLowInventoryQuantity: false,
+  imageURLs: {
+    small: "//placehold.it/150",
+    thumbnail: "//placehold.it/100"
+  },
+  isLowQuantity: false,
   price: {
-    displayPrice: "$20.00",
-    compareAtPrice: "$45.00"
+    displayAmount: "$20.00"
   },
   productSlug: "/product-slug",
+  productVendor: "Patagonia",
   title: "A Great Product",
   quantity: 2
 };
@@ -97,15 +113,21 @@ const item = {
 ```jsx
 const item = {
   _id: "123",
-  attributes: [{ label: "vendor", value: "Patagonia" }, { label: "Color", value: "Red" }, { label: "Size", value: "Medium" }],
+  attributes: [{ label: "Color", value: "Red" }, { label: "Size", value: "Medium" }],
+  compareAtPrice: {
+    displayAmount: "$45.00"
+  },
   currentQuantity: 3,
-  imageUrl: "//placehold.it",
-  isLowInventoryQuantity: true,
+  imageURLs: {
+    small: "//placehold.it/150",
+    thumbnail: "//placehold.it/100"
+  },
+  isLowQuantity: true,
   price: {
-    displayPrice: "$20.00",
-    compareAtPrice: "$45.00"
+    displayAmount: "$20.00"
   },
   productSlug: "/product-slug",
+  productVendor: "Patagonia",
   title: "A Great Product",
   quantity: 2
 };
diff --git a/package/src/components/CartItemDetail/v1/CartItemDetail.js b/package/src/components/CartItemDetail/v1/CartItemDetail.js
index 7d017440..78421c2c 100644
--- a/package/src/components/CartItemDetail/v1/CartItemDetail.js
+++ b/package/src/components/CartItemDetail/v1/CartItemDetail.js
@@ -78,12 +78,12 @@ class CartItemDetail extends Component {
      */
     attributes: PropTypes.arrayOf(PropTypes.shape({
       /**
-         * Attribute label (i.e. "Color").
-         */
+       * Attribute label (i.e. "Color").
+       */
       label: PropTypes.string,
       /**
-         * Attribute value (i.e. "Red").
-         */
+       * Attribute value (i.e. "Red").
+       */
       value: PropTypes.string
     })),
     /**
@@ -94,6 +94,10 @@ class CartItemDetail extends Component {
      * Product slug of chosen item.
      */
     productSlug: PropTypes.string,
+    /**
+     * Product vendor of chosen item.
+     */
+    productVendor: PropTypes.string,
     /**
      * Product title of chosen item.
      */
@@ -101,30 +105,36 @@ class CartItemDetail extends Component {
   };
 
   renderAttributes() {
-    let { attributes } = this.props;
-    const { isMiniCart } = this.props;
-    const { value: vendor } = attributes.find((attr) => attr.label === "vendor") || { value: undefined };
-    attributes = attributes.filter((attr) => attr.label !== "vendor");
+    const { attributes, isMiniCart, productVendor } = this.props;
+
+    if ((!attributes || attributes.length === 0) && !productVendor) return null;
+
     return (
       <Attributes isMiniCart={isMiniCart}>
-        {vendor ? <Vendor>{vendor}</Vendor> : null}
-        {attributes.map(({ label, value }) => (
-          <Attr key={label} isMiniCart={isMiniCart}>
-            <span>{label}:</span> {value}
-          </Attr>
-        ))}
+        {productVendor ? <Vendor>{productVendor}</Vendor> : null}
+        {(attributes || []).map(({ label, value }) => {
+          if (!label && !value) return null;
+
+          // For now, due to strange implementation of attributes/options in the product data,
+          // we allow labels without values and values without labels.
+          return (
+            <Attr key={label || value} isMiniCart={isMiniCart}>
+              {label ? <span>{label}:</span> : null} {value}
+            </Attr>
+          );
+        })}
       </Attributes>
     );
   }
 
   render() {
-    const { attributes, productSlug, title } = this.props;
+    const { productSlug, title } = this.props;
     return (
       <Detail>
         <Title>
           <a href={productSlug}>{title}</a>
         </Title>
-        {attributes ? this.renderAttributes() : ""}
+        {this.renderAttributes()}
       </Detail>
     );
   }
diff --git a/package/src/components/CartItemDetail/v1/CartItemDetail.md b/package/src/components/CartItemDetail/v1/CartItemDetail.md
index c8cc560a..4922feef 100644
--- a/package/src/components/CartItemDetail/v1/CartItemDetail.md
+++ b/package/src/components/CartItemDetail/v1/CartItemDetail.md
@@ -9,15 +9,14 @@ const attributes = [{ label: "Color", value: "Red" }, { label: "Size", value: "M
 <CartItemDetail title="Amazing Product Title" productSlug="/product-slug" attributes={attributes} />
 ```
 
-#### With Vendor Attribute
-If a `CartItemAttribute` has a label of `"vendor"` the `CartItemDetail` component will render the vendor value above the rest of the cart item attributes.
+#### With Product Vendor
 ```jsx
-const attributes = [{ label: "vendor", value: "Patagonia" }, { label: "Color", value: "Red" }, { label: "Size", value: "Medium" }];
-<CartItemDetail title="Amazing Product Title" productSlug="/product-slug" attributes={attributes} />
+const attributes = [{ label: "Color", value: "Red" }, { label: "Size", value: "Medium" }];
+<CartItemDetail title="Amazing Product Title" productSlug="/product-slug" productVendor="Patagonia" attributes={attributes} />
 ```
 
 #### In Mini Cart
 ```jsx
-const attributes = [{ label: "vendor", value: "Patagonia" }, { label: "Color", value: "Red" }, { label: "Size", value: "Medium" }];
-<CartItemDetail title="Amazing Product Title" productSlug="/product-slug" attributes={attributes} isMiniCart />
+const attributes = [{ label: "Color", value: "Red" }, { label: "Size", value: "Medium" }];
+<CartItemDetail title="Amazing Product Title" productSlug="/product-slug" productVendor="Patagonia" attributes={attributes} isMiniCart />
 ```
diff --git a/package/src/components/CartItems/v1/CartItems.js b/package/src/components/CartItems/v1/CartItems.js
index d35f4f53..5fff0701 100644
--- a/package/src/components/CartItems/v1/CartItems.js
+++ b/package/src/components/CartItems/v1/CartItems.js
@@ -13,82 +13,21 @@ class CartItems extends Component {
       /**
        * CartItem component
        */
-      CartItemComponent: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
-      /**
-       * CartItemDetail component
-       */
-      CartItemDetailComponent: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
-      /**
-       * Stock warning component
-       */
-      CartItemStockWarningComponent: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
-      /**
-       * Price component
-       */
-      CartItemPriceComponent: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
-      /**
-       * QuantityInput component
-       */
-      CartItemQuantityInputComponent: PropTypes.oneOfType([PropTypes.string, PropTypes.func])
+      CartItemComponent: PropTypes.oneOfType([PropTypes.string, PropTypes.func])
     }),
     /**
      * Is in a MiniCart component
      */
     isMiniCart: PropTypes.bool,
     /**
-     * CartItem data
+     * CartItem data. Only the `_id` prop is required by this component. Each item is passed to
+     * CartItemComponent, which may require additional props.
      */
     items: PropTypes.arrayOf(PropTypes.shape({
       /**
-         * The cart item ID
-         */
-      _id: PropTypes.string,
-      /**
-         * Array of additional attributes of the chosen item.
-         */
-      attributes: PropTypes.arrayOf(PropTypes.shape({
-        /**
-             * Attribute label (i.e. "Color").
-             */
-        label: PropTypes.string,
-        /**
-             *  Attribute value (i.e. "Red").
-             */
-        value: PropTypes.string
-      })),
-      /**
-         * Current stock quantity of item
-         */
-      currentQuantity: PropTypes.number,
-      /**
-         * Image url of chosen item
-         */
-      imageUrl: PropTypes.string,
-      /**
-         * Price object of chosen item
-         */
-      price: PropTypes.shape({
-        /**
-           * Chosen items compare at price
-           */
-        compareAtPrice: PropTypes.string,
-        /**
-           * Chosen items display price
-           */
-        displayPrice: PropTypes.string
-      }),
-      /**
-         * Chosen items slug
-         */
-      productSlug: PropTypes.string,
-      /**
-         * Chosen items title
-         */
-      title: PropTypes.string,
-      /**
-         * Quantity of chosen item in cart
-         */
-      quantity: PropTypes.number
+       * The cart item ID
+       */
+      _id: PropTypes.string.isRequired
     })).isRequired,
     /**
      * On cart item quantity change handler
@@ -102,12 +41,9 @@ class CartItems extends Component {
 
   static defaultProps = {
     components: {
-      CartItemComponent: "Cart Item",
-      CartItemDetailComponent: "Cart Item Detail",
-      CartItemStockWarningComponent: "Cart Item Stock Warning",
-      CartItemPriceComponent: "Cart Item Price",
-      CartItemQuantityInputComponent: "Cart Item Quantity Input"
+      CartItemComponent: "Cart Item"
     },
+    isMiniCart: false,
     onChangeCartItemQuantity() {},
     onRemoveItemFromCart() {}
   };
diff --git a/package/src/components/CartItems/v1/CartItems.md b/package/src/components/CartItems/v1/CartItems.md
index 6ecea02f..f8b50ec4 100644
--- a/package/src/components/CartItems/v1/CartItems.md
+++ b/package/src/components/CartItems/v1/CartItems.md
@@ -7,28 +7,38 @@ This component renders a list of items that are in a customers cart.
 ```jsx
 const items = [{
   _id: "123",
-  attributes: [{ label: "vendor", value: "Patagonia" }, { label: "Color", value: "Red" }, { label: "Size", value: "Medium" }],
+  attributes: [{ label: "Color", value: "Red" }, { label: "Size", value: "Medium" }],
+  compareAtPrice: {
+    displayAmount: "$45.00"
+  },
   currentQuantity: 3,
-  imageUrl: "//placehold.it",
-  isLowInventoryQuantity: true,
+  imageURLs: {
+    small: "//placehold.it/150",
+    thumbnail: "//placehold.it/100"
+  },
+  isLowQuantity: true,
   price: {
-    displayPrice: "$20.00",
-    compareAtPrice: "$45.00"
+    displayAmount: "$20.00"
   },
   productSlug: "/product-slug",
+  productVendor: "Patagonia",
   title: "A Great Product",
   quantity: 2
 },
 {
   _id: "456",
-  attributes: [{ label: "vendor", value: "Nike" }, { label: "Color", value: "Black" }, { label: "Size", value: "10" }],
+  attributes: [{ label: "Color", value: "Black" }, { label: "Size", value: "10" }],
   currentQuantity: 500,
-  imageUrl: "//placehold.it",
-  isLowInventoryQuantity: false,
+  imageURLs: {
+    small: "//placehold.it/150",
+    thumbnail: "//placehold.it/100"
+  },
+  isLowQuantity: false,
   price: {
-    displayPrice: "$78.00"
+    displayAmount: "$78.00"
   },
   productSlug: "/product-slug",
+  productVendor: "Patagonia",
   title: "Another Great Product",
   quantity: 1
 }];
@@ -49,28 +59,38 @@ const components = {
 ```jsx
 const items = [{
   _id: "123",
-  attributes: [{ label: "vendor", value: "Patagonia" }, { label: "Color", value: "Red" }, { label: "Size", value: "Medium" }],
+  attributes: [{ label: "Color", value: "Red" }, { label: "Size", value: "Medium" }],
+  compareAtPrice: {
+    displayAmount: "$45.00"
+  },
   currentQuantity: 3,
-  imageUrl: "//placehold.it",
-  isLowInventoryQuantity: true,
+  imageURLs: {
+    small: "//placehold.it/150",
+    thumbnail: "//placehold.it/100"
+  },
+  isLowQuantity: true,
   price: {
-    displayPrice: "$20.00",
-    compareAtPrice: "$45.00"
+    displayAmount: "$20.00"
   },
+  productVendor: "Patagonia",
   productSlug: "/product-slug",
   title: "A Great Product",
   quantity: 2
 },
 {
   _id: "456",
-  attributes: [{ label: "vendor", value: "Nike" }, { label: "Color", value: "Black" }, { label: "Size", value: "10" }],
+  attributes: [{ label: "Color", value: "Black" }, { label: "Size", value: "10" }],
   currentQuantity: 500,
-  imageUrl: "//placehold.it",
-  isLowInventoryQuantity: false,
+  imageURLs: {
+    small: "//placehold.it/150",
+    thumbnail: "//placehold.it/100"
+  },
+  isLowQuantity: false,
   price: {
-    displayPrice: "$78.00"
+    displayAmount: "$78.00"
   },
   productSlug: "/product-slug",
+  productVendor: "Nike",
   title: "Another Great Product",
   quantity: 1
 }];
diff --git a/package/src/components/MiniCart/v1/MiniCart.js b/package/src/components/MiniCart/v1/MiniCart.js
index d13de0cf..6e92a3af 100644
--- a/package/src/components/MiniCart/v1/MiniCart.js
+++ b/package/src/components/MiniCart/v1/MiniCart.js
@@ -57,7 +57,7 @@ class MiniCart extends Component {
             /**
              * Checkout summary subtotal display amount
              */
-            displayAmmount: PropTypes.string
+            displayAmount: PropTypes.string
           }),
           /**
            * Checkout summary tax info
@@ -71,61 +71,10 @@ class MiniCart extends Component {
         })
       }),
       /**
-       * CartItem data
+       * CartItem data. This is passed to CartItemComponent, which may require some props.
        */
-      items: PropTypes.arrayOf(PropTypes.shape({
-        /**
-           * The cart item ID
-           */
-        _id: PropTypes.string,
-        /**
-           * Array of additional attributes of the chosen item.
-           */
-        attributes: PropTypes.arrayOf(PropTypes.shape({
-          /**
-               * Attribute label (i.e. "Color").
-               */
-          label: PropTypes.string,
-          /**
-               *  Attribute value (i.e. "Red").
-               */
-          value: PropTypes.string
-        })),
-        /**
-           * Current stock quantity of item
-           */
-        currentQuantity: PropTypes.number,
-        /**
-           * Image url of chosen item
-           */
-        imageUrl: PropTypes.string,
-        /**
-           * Price object of chosen item
-           */
-        price: PropTypes.shape({
-          /**
-             * Chosen items compare at price
-             */
-          compareAtPrice: PropTypes.string,
-          /**
-             * Chosen items display price
-             */
-          displayPrice: PropTypes.string
-        }),
-        /**
-           * Chosen items slug
-           */
-        productSlug: PropTypes.string,
-        /**
-           * Chosen items title
-           */
-        title: PropTypes.string,
-        /**
-           * Quantity of chosen item in cart
-           */
-        quantity: PropTypes.number
-      }))
-    }).isRequired,
+      items: PropTypes.arrayOf(PropTypes.object).isRequired
+    }),
     /**
      * Provided child components to display item data
      */
@@ -139,25 +88,9 @@ class MiniCart extends Component {
        */
       CartSummaryComponent: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
       /**
-       * CartItem component
-       */
-      CartItemComponent: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
-      /**
-       * CartItemDetail component
-       */
-      CartItemDetailComponent: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
-      /**
-       * Stock warning component
-       */
-      CartItemStockWarningComponent: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
-      /**
-       * Price component
-       */
-      CartItemPriceComponent: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
-      /**
-       * QuantityInput component
+       * CartItems component
        */
-      CartItemQuantityInputComponent: PropTypes.oneOfType([PropTypes.string, PropTypes.func])
+      CartItemsComponent: PropTypes.oneOfType([PropTypes.string, PropTypes.func])
     }),
     /**
      * On cart item quantity change handler
@@ -173,11 +106,7 @@ class MiniCart extends Component {
     components: {
       CartCheckoutButtonComponent: "Cart Checkout Button",
       CartSummaryComponent: "Cart Summary",
-      CartItemComponent: "Cart Item",
-      CartItemDetailComponent: "Cart Item Detail",
-      CartItemStockWarningComponent: "Cart Item Stock Warning",
-      CartItemPriceComponent: "Cart Item Price",
-      CartItemQuantityInputComponent: "Cart Item Quantity Input"
+      CartItemsComponent: "Cart Items"
     },
     onChangeCartItemQuantity() {},
     onRemoveItemFromCart() {}
diff --git a/package/src/components/MiniCart/v1/MiniCart.md b/package/src/components/MiniCart/v1/MiniCart.md
index 9dd56451..55f5e064 100644
--- a/package/src/components/MiniCart/v1/MiniCart.md
+++ b/package/src/components/MiniCart/v1/MiniCart.md
@@ -15,28 +15,38 @@ const checkout = {
 const items = [
 {
   _id: "123",
-  attributes: [{ label: "vendor", value: "Patagonia" }, { label: "Color", value: "Red" }, { label: "Size", value: "Medium" }],
+  attributes: [{ label: "Color", value: "Red" }, { label: "Size", value: "Medium" }],
+  compareAtPrice: {
+    displayAmount: "$45.00"
+  },
   currentQuantity: 3,
-  imageUrl: "//placehold.it",
-  isLowInventoryQuantity: true,
+  imageURLs: {
+    small: "//placehold.it/150",
+    thumbnail: "//placehold.it/100"
+  },
+  isLowQuantity: true,
   price: {
-    displayPrice: "$20.00",
-    compareAtPrice: "$45.00"
+    displayAmount: "$20.00"
   },
   productSlug: "/product-slug",
+  productVendor: "Patagonia",
   title: "A Great Product",
   quantity: 2
 },
 {
   _id: "456",
-  attributes: [{ label: "vendor", value: "Nike" }, { label: "Color", value: "Black" }, { label: "Size", value: "10" }],
+  attributes: [{ label: "Color", value: "Black" }, { label: "Size", value: "10" }],
   currentQuantity: 500,
-  imageUrl: "//placehold.it",
-  isLowInventoryQuantity: false,
+  imageURLs: {
+    small: "//placehold.it/150",
+    thumbnail: "//placehold.it/100"
+  },
+  isLowQuantity: false,
   price: {
-    displayPrice: "$78.00"
+    displayAmount: "$78.00"
   },
   productSlug: "/product-slug",
+  productVendor: "Patagonia",
   title: "Another Great Product",
   quantity: 1
 }];
@@ -69,54 +79,72 @@ const checkout = {
 
 const items = [{
   _id: "123",
-  attributes: [{ label: "vendor", value: "Patagonia" }, { label: "Color", value: "Red" }, { label: "Size", value: "Medium" }],
+  attributes: [{ label: "Color", value: "Red" }, { label: "Size", value: "Medium" }],
+  compareAtPrice: {
+    displayAmount: "$45.00"
+  },
   currentQuantity: 3,
-  imageUrl: "//placehold.it",
-  isLowInventoryQuantity: true,
+  imageURLs: {
+    small: "//placehold.it/150",
+    thumbnail: "//placehold.it/100"
+  },
+  isLowQuantity: true,
   price: {
-    displayPrice: "$20.00",
-    compareAtPrice: "$45.00"
+    displayAmount: "$20.00"
   },
   productSlug: "/product-slug",
+  productVendor: "Patagonia",
   title: "A Great Product",
   quantity: 2
 },
 {
   _id: "456",
-  attributes: [{ label: "vendor", value: "Nike" }, { label: "Color", value: "Black" }, { label: "Size", value: "10" }],
+  attributes: [{ label: "Color", value: "Black" }, { label: "Size", value: "10" }],
   currentQuantity: 500,
-  imageUrl: "//placehold.it",
-  isLowInventoryQuantity: false,
+  imageURLs: {
+    small: "//placehold.it/150",
+    thumbnail: "//placehold.it/100"
+  },
+  isLowQuantity: false,
   price: {
-    displayPrice: "$78.00"
+    displayAmount: "$78.00"
   },
   productSlug: "/product-slug",
+  productVendor: "Nike",
   title: "Another Great Product",
   quantity: 1
 },
 {
   _id: "789",
-  attributes: [{ label: "vendor", value: "Everlane" }, { label: "Color", value: "White" }, { label: "Size", value: "Medium" }],
+  attributes: [{ label: "Color", value: "White" }, { label: "Size", value: "Medium" }],
   currentQuantity: 3,
-  imageUrl: "//placehold.it",
-  isLowInventoryQuantity: false,
+  imageURLs: {
+    small: "//placehold.it/150",
+    thumbnail: "//placehold.it/100"
+  },
+  isLowQuantity: false,
   price: {
-    displayPrice: "$20.00"
+    displayAmount: "$20.00"
   },
   productSlug: "/product-slug",
+  productVendor: "Everlane",
   title: "A Product",
   quantity: 2
 },
 {
   _id: "112",
-  attributes: [{ label: "vendor", value: "Greats" }, { label: "Color", value: "Black" }, { label: "Size", value: "10" }],
+  attributes: [{ label: "Color", value: "Black" }, { label: "Size", value: "10" }],
   currentQuantity: 500,
-  imageUrl: "//placehold.it",
-  isLowInventoryQuantity: false,
+  imageURLs: {
+    small: "//placehold.it/150",
+    thumbnail: "//placehold.it/100"
+  },
+  isLowQuantity: false,
   price: {
-    displayPrice: "$150.00"
+    displayAmount: "$150.00"
   },
   productSlug: "/product-slug",
+   productVendor: "Greats",
   title: "Another Product",
   quantity: 1
 }];


Test patch:
diff --git a/package/src/components/CartItem/v1/CartItem.test.js b/package/src/components/CartItem/v1/CartItem.test.js
index 970d826f..92a6c934 100644
--- a/package/src/components/CartItem/v1/CartItem.test.js
+++ b/package/src/components/CartItem/v1/CartItem.test.js
@@ -3,7 +3,7 @@ import renderer from "react-test-renderer";
 import CartItem from "./CartItem";
 
 test("basic snapshot with empty props", () => {
-  const component = renderer.create(<CartItem item={{ price: {} }} />);
+  const component = renderer.create(<CartItem item={{ price: { displayAmount: "$9.99" } }} />);
 
   const tree = component.toJSON();
   expect(tree).toMatchSnapshot();
@@ -12,17 +12,22 @@ test("basic snapshot with empty props", () => {
 test("basic snapshot with props", () => {
   const mockItem = {
     attributes: [
-      { label: "vendor", value: "Patagonia" },
       { label: "Color", value: "Red" },
       { label: "Size", value: "Medium" }
     ],
+    compareAtPrice: {
+      displayAmount: "$45.00"
+    },
     currentQuantity: 3,
-    imageUrl: "//placehold.it",
+    imageURLs: {
+      small: "//placehold.it/150",
+      thumbnail: "//placehold.it/100"
+    },
     price: {
-      displayPrice: "$20.00",
-      compareAtPrice: "$45.00"
+      displayAmount: "$20.00"
     },
     productSlug: "/product-slug",
+    productVendor: "Patagonia",
     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 c834304e..cc327906 100644
--- a/package/src/components/CartItem/v1/__snapshots__/CartItem.test.js.snap
+++ b/package/src/components/CartItem/v1/__snapshots__/CartItem.test.js.snap
@@ -133,25 +133,6 @@ exports[`basic snapshot with empty props 1`] = `
 <div
   className="c0"
 >
-  <a
-    href={undefined}
-  >
-    <picture>
-      <source
-        media="(min-width: 768px)"
-        srcSet="undefined/150"
-      />
-      <img
-        alt=""
-        src="undefined/100"
-        style={
-          Object {
-            "display": "block",
-          }
-        }
-      />
-    </picture>
-  </a>
   <div
     className="c1"
   >
@@ -166,8 +147,9 @@ exports[`basic snapshot with empty props 1`] = `
         >
           <Cart Item Detail
             attributes={undefined}
-            isMiniCart={undefined}
+            isMiniCart={false}
             productSlug={undefined}
+            productVendor={undefined}
             title={undefined}
           />
           <Cart Item Stock Warning
@@ -196,8 +178,8 @@ exports[`basic snapshot with empty props 1`] = `
     >
       <Cart Item Price
         displayCompareAtPrice={undefined}
-        displayPrice={undefined}
-        hasPriceBottom={undefined}
+        displayPrice="$9.99"
+        hasPriceBottom={false}
       />
     </div>
   </div>
diff --git a/package/src/components/CartItemDetail/v1/CartItemDetail.test.js b/package/src/components/CartItemDetail/v1/CartItemDetail.test.js
index 8dd44afd..217f6e49 100644
--- a/package/src/components/CartItemDetail/v1/CartItemDetail.test.js
+++ b/package/src/components/CartItemDetail/v1/CartItemDetail.test.js
@@ -19,11 +19,10 @@ test("basic snapshot with props", () => {
 
 test("basic snapshot with vendor attribute", () => {
   const attributes = [
-    { label: "vendor", value: "Patagonia" },
     { label: "Color", value: "Red" },
     { label: "Size", value: "Medium" }
   ];
-  const component = renderer.create(<CartItemDetail title="Mock Product Title" productSlug="/product-slug" attributes={attributes} />);
+  const component = renderer.create(<CartItemDetail title="Mock Product Title" productSlug="/product-slug" productVendor="Patagonia" attributes={attributes} />);
 
   const tree = component.toJSON();
   expect(tree).toMatchSnapshot();
diff --git a/package/src/components/CartItemDetail/v1/__snapshots__/CartItemDetail.test.js.snap b/package/src/components/CartItemDetail/v1/__snapshots__/CartItemDetail.test.js.snap
index 376adc27..36fcff64 100644
--- a/package/src/components/CartItemDetail/v1/__snapshots__/CartItemDetail.test.js.snap
+++ b/package/src/components/CartItemDetail/v1/__snapshots__/CartItemDetail.test.js.snap
@@ -277,6 +277,5 @@ exports[`basic snapshot without props 1`] = `
       href={undefined}
     />
   </h3>
-  
 </div>
 `;
diff --git a/package/src/components/CartItems/v1/CartItems.test.js b/package/src/components/CartItems/v1/CartItems.test.js
index 909411b5..b3a0da86 100644
--- a/package/src/components/CartItems/v1/CartItems.test.js
+++ b/package/src/components/CartItems/v1/CartItems.test.js
@@ -14,34 +14,42 @@ test("basic snapshot with props", () => {
     {
       _id: "123",
       attributes: [
-        { label: "vendor", value: "Patagonia" },
         { label: "Color", value: "Red" },
         { label: "Size", value: "Medium" }
       ],
+      compareAtPrice: {
+        displayAmount: "$45.00"
+      },
       currentQuantity: 3,
-      imageUrl: "//placehold.it",
-      isLowInventoryQuantity: true,
+      imageURLs: {
+        small: "//placehold.it/150",
+        thumbnail: "//placehold.it/100"
+      },
+      isLowQuantity: true,
       price: {
-        displayPrice: "$20.00",
-        compareAtPrice: "$45.00"
+        displayAmount: "$20.00"
       },
       productSlug: "/product-slug",
+      productVendor: "Patagonia",
       title: "A Great Product",
       quantity: 2
     },
     {
       _id: "456",
       attributes: [
-        { label: "vendor", value: "Nike" },
         { label: "Color", value: "Black" },
         { label: "Size", value: "10" }
       ],
       currentQuantity: 500,
-      imageUrl: "//placehold.it",
-      isLowInventoryQuantity: false,
+      imageURLs: {
+        small: "//placehold.it/150",
+        thumbnail: "//placehold.it/100"
+      },
+      isLowQuantity: false,
       price: {
-        displayPrice: "$78.00"
+        displayAmount: "$78.00"
       },
+      productVendor: "Nike",
       productSlug: "/product-slug",
       title: "Another Great Product",
       quantity: 1
diff --git a/package/src/components/MiniCart/v1/MiniCart.test.js b/package/src/components/MiniCart/v1/MiniCart.test.js
index 5d939597..eec54773 100644
--- a/package/src/components/MiniCart/v1/MiniCart.test.js
+++ b/package/src/components/MiniCart/v1/MiniCart.test.js
@@ -17,35 +17,43 @@ const mockItems = [
   {
     _id: "123",
     attributes: [
-      { label: "vendor", value: "Patagonia" },
       { label: "Color", value: "Red" },
       { label: "Size", value: "Medium" }
     ],
+    compareAtPrice: {
+      displayAmount: "$45.00"
+    },
     currentQuantity: 3,
-    imageUrl: "//placehold.it",
-    isLowInventoryQuantity: true,
+    imageURLs: {
+      small: "//placehold.it/150",
+      thumbnail: "//placehold.it/100"
+    },
+    isLowQuantity: true,
     price: {
-      displayPrice: "$20.00",
-      compareAtPrice: "$45.00"
+      displayAmount: "$20.00"
     },
     productSlug: "/product-slug",
+    productVendor: "Patagonia",
     title: "A Great Product",
     quantity: 2
   },
   {
     _id: "456",
     attributes: [
-      { label: "vendor", value: "Nike" },
       { label: "Color", value: "Black" },
       { label: "Size", value: "10" }
     ],
     currentQuantity: 500,
-    imageUrl: "//placehold.it",
-    isLowInventoryQuantity: false,
+    imageURLs: {
+      small: "//placehold.it/150",
+      thumbnail: "//placehold.it/100"
+    },
+    isLowQuantity: false,
     price: {
-      displayPrice: "$78.00"
+      displayAmount: "$78.00"
     },
     productSlug: "/product-slug",
+    productVendor: "Nike",
     title: "Another Great Product",
     quantity: 1
   }