RyanWarner / use-shopping-cart

Shopping cart state and logic for Stripe

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

use-shopping-cart

All Contributors

A React Hook that handles shopping cart state and logic for Stripe.

NPM JavaScript Style Guide

All Contributors

Installation

npm install --save @stripe/stripe-js use-shopping-cart

# or

yarn add @stripe/stripe-js use-shopping-cart

Development

To run this package for development run:

yarn dev

To run tests:

yarn test

Usage

Initialization

At the root level of your application (or the highest point you'll be using Stripe from), wrap your components in a <CartProvider>.

<CartProvider> comes with several props that allow you to interact with the Stripe API and customize the Stripe experience.

When loading up Stripe, don't forget to use your public Stripe API key with it. If you need help setting up your environment variables for this, view a list of environment variable tutorials.

import ReactDOM from 'react-dom';

import { loadStripe } from '@stripe/stripe-js';
import { CartProvider } from 'use-shopping-cart';

import App from './App';

// Remember to add your public Stripe key
const stripePromise = loadStripe(process.env.REACT_APP_STRIPE_API_PUBLIC);

ReactDOM.render(
  <CartProvider
    stripe={stripePromise}
    successUrl="stripe.com"
    cancelUrl="twitter.com/dayhaysoos"
    currency="USD"
    allowedCountries={['US', 'UK', 'CA']}
    billingAddressCollection={true}
  >
    <App />
  </CartProvider>,
  document.getElementById('root')
);

Using the hook

The hook useShoppingCart() provides several utilities and pieces of data for you to use in your application. The examples below won't cover every part of the useShoppingCart() API but you can look at the API below.

import { useShoppingCart } from 'use-shopping-cart';
import { Product } from './Product';
import { CartItems } from './CartItems';

const productData = [
  {
    name: 'Bananas',
    sku: 'sku_GBJ2Ep8246qeeT',
    price: 400,
    image: 'https://www.fillmurray.com/300/300',
    currency: 'USD',
  },
  {
    name: 'Tangerines',
    sku: 'sku_GBJ2WWfMaGNC2Z',
    price: 100,
    image: 'https://www.fillmurray.com/300/300',
    currency: 'USD',
  },
];

export function App() {
  /* Gets the totalPrice and a method for redirecting to stripe */
  const { totalPrice, redirectToCheckout, cartCount } = useShoppingCart();

  return (
    <div>
      {/* Renders the products */}
      {productData.map((product) => (
        <Product product={product} />
      ))}

      {/* This is where we'll render our cart */}
      <p>Number of Items: {cartCount}</p>
      <p>Total: {totalPrice()}</p>
      <CartItems />

      {/* Redirects the user to Stripe */}
      <button onClick={redirectToCheckout}>Checkout</button>
    </div>
  );
}

How do I add an item to the user's cart?

To add a product to the cart, use useShoppingCart()'s addItem(product) method. It takes in your product object, which must have a sku and a price, and adds it to the cart.

import { useShoppingCart, formatCurrencyString } from 'use-shopping-cart';

export function Product({ product }) {
  const { addItem } = useShoppingCart();

  /* A helper function that turns the price into a readable format */
  const price = formatCurrencyString({
    price: product.price,
    currency: product.currency,
    language: navigator.language,
  });

  return (
    <article>
      <figure>
        <img src={product.image} alt={`Image of ${product.name}`} />
        <figcaption>{product.name}</figcaption>
      </figure>
      <p>{price}</p>

      {/* Adds the item to the cart */}
      <button
        onClick={() => addItem(product)}
        aria-label={`Add ${product.name} to your cart`}
      >
        Add to cart
      </button>
    </article>
  );
}

Now how do I display the cart to the user?

Once the user has added their items to the cart, you can use the cartDetails object to display the different data about each product in their cart.

Each product in cartDetails contains the same data you provided when you called addItem(product). In addition, cartDetails also provides the following properties:

Name Value
quantity Number of that product added to the cart
value The price * quantity
formattedValue A currency formatted version of value
import { useShoppingCart } from 'use-shopping-cart';

export function CartItems() {
  const {
    cartDetails,
    reduceItemByOne,
    addItem,
    removeCartItem,
  } = useShoppingCart();

  const cart = [];
  // Note: Object.keys().map() takes 2x as long as a for-in loop
  for (const sku in cartDetails) {
    const cartEntry = cartDetails[sku];

    // all of your basic product data still exists (i.e. name, image, price)
    cart.push(
      <article>
        {/* image here */}
        {/* name here */}
        <p>Line total: {cartEntry.formattedValue}</p>

        {/* What if we want to remove one of the item... or add one */}
        <button
          onClick={() => reduceItemByOne(cartEntry.sku)}
          aria-label={`Remove one ${cartEntry.name} from your cart`}
        >
          -
        </button>
        <p>Quantity: {cartEntry.quantity}</p>
        <button
          onClick={() => addItem(cartEntry)}
          aria-label={`Add one ${cartEntry.name} to your cart`}
        >
          +
        </button>

        {/* What if we don't want this product at all */}
        <button
          onClick={() => removeCartItem(cartEntry.sku)}
          aria-label={`Remove all ${cartEntry.name} from your cart`}
        >
          Remove
        </button>
      </article>
    );
  }

  return cart;
}

Note that in the above code, to reduce the quantity of a product in the user's cart, you must pass an SKU to reduceItemByOne() like so:

reduceItemByOne(cartEntry.sku);

Just like you can reduce the quantity of a product you can remove the product entirely with removeCartItem():

removeCartItem(cartEntry.sku);

However, those two examples differ from the way that you increase the quantity of a product in the user's cart. Currently, to do this, you must pass the entire cartEntry to addItem():

addItem(cartEntry);

API

You can view the full API on our documentation page.

<CartProvider>

Props for this component:

Name Type
stripe Stripe | undefined
successUrl string
cancelUrl string
currency string
language string
billingAddressCollection boolean
allowedCountries null | string[]

useShoppingCart()

Returns an object with all the following properties and methods:

Name Type/Args Return Type
addItem() product: Object N/A
reduceItemByOne() sku: string N/A
removeCartItem() sku: string N/A
totalPrice() N/A string
cartCount number N/A
cartDetails Object of cart entries N/A
redirectToCheckout() sessionId?: string Error (if one occurrs)
clearCart() N/A N/A

formatCurrencyString(options)

This function takes one options argument, these are the options for this function:

Name Type
value number
currency string
language string

Environment Variable Tutorials

The following tutorials teach how to set up your custom environment variables for your project.

License

MIT © dayhaysoos


We created this hook with create-react-hook.

Contributors ✨

Thanks goes to these wonderful people (emoji key):


Thor 雷神

📖 💻 ⚠️

Kevin Cunningham

⚠️ 💻

Ian Jones

⚠️

Christopher Brown

📖 ⚠️ 💻

Nick DeJesus

💻 ⚠️

Shodipo Ayomide

📖

Anders Bech Mellson

💻

This project follows the all-contributors specification. Contributions of any kind welcome!

About

Shopping cart state and logic for Stripe


Languages

Language:JavaScript 100.0%