Repository: reactioncommerce/reaction-component-library
Pull request #92 (2018-06-21 20:25:59)

feat: Cart checkout button
This PR adds a `CartCheckoutButton` component.

This button will allow a user to proceed with checkout when clicked.


Patch:
diff --git a/package/src/components/CartCheckoutButton/v1/CartCheckoutButton.js b/package/src/components/CartCheckoutButton/v1/CartCheckoutButton.js
new file mode 100644
index 00000000..750d2e2d
--- /dev/null
+++ b/package/src/components/CartCheckoutButton/v1/CartCheckoutButton.js
@@ -0,0 +1,52 @@
+import React, { Component } from "react";
+import PropTypes from "prop-types";
+
+
+class CartCheckoutButton extends Component {
+  static propTypes = {
+    /**
+     * Text to display inside the button
+     */
+    buttonText: PropTypes.string,
+    /**
+     * On object of component children to pass into this component
+     */
+    components: PropTypes.shape({
+      Button: PropTypes.oneOfType([PropTypes.string, PropTypes.func])
+    }),
+    /**
+     * Set to `true` to prevent the button from calling `onClick` when clicked
+     */
+    isDisabled: PropTypes.bool,
+    /**
+     * On click function to pass to the Button component. Not handled internally, directly passed
+     */
+    onClick: PropTypes.func.isRequired
+  }
+
+  static defaultProps = {
+    buttonText: "Checkout"
+  };
+
+  handleOnClick = () => {
+    this.props.onClick();
+  }
+
+  render() {
+    const { buttonText, isDisabled } = this.props;
+    const { Button } = this.props.components;
+
+    return (
+      <Button
+        actionType="important"
+        isDisabled={isDisabled}
+        onClick={this.handleOnClick}
+        fullWidth
+      >
+        {buttonText}
+      </Button>
+    );
+  }
+}
+
+export default CartCheckoutButton;
diff --git a/package/src/components/CartCheckoutButton/v1/CartCheckoutButton.md b/package/src/components/CartCheckoutButton/v1/CartCheckoutButton.md
new file mode 100644
index 00000000..a911821b
--- /dev/null
+++ b/package/src/components/CartCheckoutButton/v1/CartCheckoutButton.md
@@ -0,0 +1,27 @@
+### CartCheckoutButton
+
+#### Overview
+The `CartCheckoutButton` displays a button that allows the user to continue to checkout their cart.
+
+#### A cart checkout button will be rendered when the user needs to continue to the checkout step in the cart
+```jsx
+const onClick = () => {};
+
+  <CartCheckoutButton
+    components={{Button}}
+    isDisabled={false}
+    onClick={onClick}
+  />
+```
+
+#### It's possible to customize button text
+```jsx
+const onClick = () => {};
+
+  <CartCheckoutButton
+    buttonText="Custom button text"
+    components={{Button}}
+    isDisabled={false}
+    onClick={onClick}
+  />
+```
diff --git a/package/src/components/CartCheckoutButton/v1/index.js b/package/src/components/CartCheckoutButton/v1/index.js
new file mode 100644
index 00000000..da549e1f
--- /dev/null
+++ b/package/src/components/CartCheckoutButton/v1/index.js
@@ -0,0 +1,1 @@
+export { default } from "./CartCheckoutButton";
diff --git a/styleguide.config.js b/styleguide.config.js
index 209b0c8a..0158938b 100644
--- a/styleguide.config.js
+++ b/styleguide.config.js
@@ -98,7 +98,7 @@ module.exports = {
           name: "Product"
         }),
         generateSection({
-          componentNames: ["CartEmptyMessage", "CartSummary"],
+          componentNames: ["CartCheckoutButton", "CartEmptyMessage", "CartSummary"],
           content: "styleguide/src/sections/Cart.md",
           name: "Cart"
         }),


Test patch:
diff --git a/package/src/components/CartCheckoutButton/v1/CartCheckoutButton.test.js b/package/src/components/CartCheckoutButton/v1/CartCheckoutButton.test.js
new file mode 100644
index 00000000..c85d8f00
--- /dev/null
+++ b/package/src/components/CartCheckoutButton/v1/CartCheckoutButton.test.js
@@ -0,0 +1,56 @@
+import React from "react";
+import renderer from "react-test-renderer";
+import { shallow } from "enzyme";
+import Button from "../../Button/v1";
+import CartCheckoutButton from "./CartCheckoutButton";
+
+test("default cart checkout button", () => {
+  const onClick = () => {};
+  const isDisabled = false;
+
+  const component = renderer.create((
+    <CartCheckoutButton
+      components={{ Button }}
+      isDisabled={isDisabled}
+      onClick={onClick}
+    />
+  ));
+
+  const tree = component.toJSON();
+  expect(tree).toMatchSnapshot();
+});
+
+test("cart checkout button with custom text", () => {
+  const onClick = () => {};
+  const isDisabled = false;
+
+  const component = renderer.create((
+    <CartCheckoutButton
+      buttonText="Custom button text"
+      components={{ Button }}
+      isDisabled={isDisabled}
+      onClick={onClick}
+    />
+  ));
+
+  const tree = component.toJSON();
+  expect(tree).toMatchSnapshot();
+});
+
+
+test("cart checkout button onClick", () => {
+  const isDisabled = false;
+  const testClick = jest.fn();
+
+  const component = shallow((
+    <CartCheckoutButton
+      buttonText="Custom button text"
+      components={{ Button }}
+      isDisabled={isDisabled}
+      onClick={testClick}
+    />
+  ));
+
+  component.simulate("click");
+  expect(testClick).toHaveBeenCalled();
+});
diff --git a/package/src/components/CartCheckoutButton/v1/__snapshots__/CartCheckoutButton.test.js.snap b/package/src/components/CartCheckoutButton/v1/__snapshots__/CartCheckoutButton.test.js.snap
new file mode 100644
index 00000000..e91ae40d
--- /dev/null
+++ b/package/src/components/CartCheckoutButton/v1/__snapshots__/CartCheckoutButton.test.js.snap
@@ -0,0 +1,245 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`cart checkout button with custom text 1`] = `
+.c2 {
+  width: 1.125em;
+  height: 1.125em;
+}
+
+.c0 {
+  -webkit-font-smoothing: antialiased;
+  -webkit-align-items: center;
+  -webkit-box-align: center;
+  -ms-flex-align: center;
+  align-items: center;
+  background-color: #1999dd;
+  border-color: #1999dd;
+  border-style: solid;
+  border-width: 1px;
+  border-radius: 2px;
+  box-sizing: border-box;
+  color: #ffffff;
+  cursor: pointer;
+  display: -webkit-inline-box;
+  display: -webkit-inline-flex;
+  display: -ms-inline-flexbox;
+  display: inline-flex;
+  font-family: "Source Sans Pro","Helvetica Neue",Helvetica,sans-serif;
+  -webkit-box-pack: center;
+  -webkit-justify-content: center;
+  -ms-flex-pack: center;
+  justify-content: center;
+  margin: 0;
+  min-width: 100px;
+  outline: none;
+  padding-left: 20px;
+  padding-right: 20px;
+  padding-top: 10px;
+  padding-bottom: 10px;
+  position: relative;
+  text-align: center;
+}
+
+.c0:hover {
+  background-color: #25b0f9;
+  border-color: #25b0f9;
+  color: #ffffff;
+}
+
+.c0:active {
+  background-color: #057dbe;
+  border-color: #057dbe;
+  color: #ffffff;
+}
+
+.c1 {
+  display: -webkit-box;
+  display: -webkit-flex;
+  display: -ms-flexbox;
+  display: flex;
+  overflow: hidden;
+  padding-left: 20px;
+  -webkit-transition: width 0.2s ease-out 0s,padding-left 0.2s ease-out 0s,opacity 0.2s ease-out 0.2s;
+  transition: width 0.2s ease-out 0s,padding-left 0.2s ease-out 0s,opacity 0.2s ease-out 0.2s;
+}
+
+.c1 svg path,
+.c1 svg rect {
+  fill: #ffffff;
+}
+
+<div
+  className="c0"
+  onClick={[Function]}
+  onKeyPress={[Function]}
+  role="button"
+  tabIndex={0}
+  title={undefined}
+>
+  <div>
+    Custom button text
+  </div>
+  <div
+    className="c1"
+    style={
+      Object {
+        "opacity": 0,
+        "paddingLeft": 0,
+        "width": 0,
+      }
+    }
+  >
+    <svg
+      className="c2"
+      height="40px"
+      style={
+        Object {
+          "enableBackground": "new 0 0 50 50",
+        }
+      }
+      version="1.1"
+      viewBox="0 0 50 50"
+      width="40px"
+      x="0px"
+      y="0px"
+    >
+      <path
+        d="M43.935,25.145c0-10.318-8.364-18.683-18.683-18.683c-10.318,0-18.683,8.365-18.683,18.683h4.068c0-8.071,6.543-14.615,14.615-14.615c8.072,0,14.615,6.543,14.615,14.615H43.935z"
+        fill="#000"
+      >
+        <animateTransform
+          attributeName="transform"
+          attributeType="xml"
+          dur="1s"
+          from="0 25 25"
+          repeatCount="indefinite"
+          to="360 25 25"
+          type="rotate"
+        />
+      </path>
+    </svg>
+  </div>
+</div>
+`;
+
+exports[`default cart checkout button 1`] = `
+.c2 {
+  width: 1.125em;
+  height: 1.125em;
+}
+
+.c0 {
+  -webkit-font-smoothing: antialiased;
+  -webkit-align-items: center;
+  -webkit-box-align: center;
+  -ms-flex-align: center;
+  align-items: center;
+  background-color: #1999dd;
+  border-color: #1999dd;
+  border-style: solid;
+  border-width: 1px;
+  border-radius: 2px;
+  box-sizing: border-box;
+  color: #ffffff;
+  cursor: pointer;
+  display: -webkit-inline-box;
+  display: -webkit-inline-flex;
+  display: -ms-inline-flexbox;
+  display: inline-flex;
+  font-family: "Source Sans Pro","Helvetica Neue",Helvetica,sans-serif;
+  -webkit-box-pack: center;
+  -webkit-justify-content: center;
+  -ms-flex-pack: center;
+  justify-content: center;
+  margin: 0;
+  min-width: 100px;
+  outline: none;
+  padding-left: 20px;
+  padding-right: 20px;
+  padding-top: 10px;
+  padding-bottom: 10px;
+  position: relative;
+  text-align: center;
+}
+
+.c0:hover {
+  background-color: #25b0f9;
+  border-color: #25b0f9;
+  color: #ffffff;
+}
+
+.c0:active {
+  background-color: #057dbe;
+  border-color: #057dbe;
+  color: #ffffff;
+}
+
+.c1 {
+  display: -webkit-box;
+  display: -webkit-flex;
+  display: -ms-flexbox;
+  display: flex;
+  overflow: hidden;
+  padding-left: 20px;
+  -webkit-transition: width 0.2s ease-out 0s,padding-left 0.2s ease-out 0s,opacity 0.2s ease-out 0.2s;
+  transition: width 0.2s ease-out 0s,padding-left 0.2s ease-out 0s,opacity 0.2s ease-out 0.2s;
+}
+
+.c1 svg path,
+.c1 svg rect {
+  fill: #ffffff;
+}
+
+<div
+  className="c0"
+  onClick={[Function]}
+  onKeyPress={[Function]}
+  role="button"
+  tabIndex={0}
+  title={undefined}
+>
+  <div>
+    Checkout
+  </div>
+  <div
+    className="c1"
+    style={
+      Object {
+        "opacity": 0,
+        "paddingLeft": 0,
+        "width": 0,
+      }
+    }
+  >
+    <svg
+      className="c2"
+      height="40px"
+      style={
+        Object {
+          "enableBackground": "new 0 0 50 50",
+        }
+      }
+      version="1.1"
+      viewBox="0 0 50 50"
+      width="40px"
+      x="0px"
+      y="0px"
+    >
+      <path
+        d="M43.935,25.145c0-10.318-8.364-18.683-18.683-18.683c-10.318,0-18.683,8.365-18.683,18.683h4.068c0-8.071,6.543-14.615,14.615-14.615c8.072,0,14.615,6.543,14.615,14.615H43.935z"
+        fill="#000"
+      >
+        <animateTransform
+          attributeName="transform"
+          attributeType="xml"
+          dur="1s"
+          from="0 25 25"
+          repeatCount="indefinite"
+          to="360 25 25"
+          type="rotate"
+        />
+      </path>
+    </svg>
+  </div>
+</div>
+`;