npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@tracerbuilt/use-shopping-cart

v2.2.5

Published

Shopping cart state and logic for Stripe

Downloads

1

Readme

This is my own version of this package which uses the polyfill found here to add support for older browsers to the wonderful original use-shopping-cart. Their README information is found below.

https://useshoppingcart.com

use-shopping-cart

All Contributors

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

NPM JavaScript Style Guide

All Contributors

Installation

# With Yarn
yarn add @stripe/stripe-js use-shopping-cart

# With NPM
npm install --save @stripe/stripe-js use-shopping-cart

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.

CheckoutSession mode

Creating a CheckoutSession server-side allows for a more flexible and powerful integration but requires a server component (e.g. a Netlify Function).

At the root level of your app, wrap your Root app in the <CartProvider />

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.STRIPE_API_PUBLIC)

ReactDOM.render(
  <CartProvider mode="checkout-session" stripe={stripePromise} currency="USD">
    <App />
  </CartProvider>,
  document.getElementById('root')
)

When using CheckoutSessions your product object must adhere to the following shape:

const products = [
  {
    // Line item name to be shown on the Stripe Checkout page
    name: 'Bananas',
    // Optional description to be shown on the Stripe Checkout page
    description: 'Yummy yellow fruit',
    // A unique identifier for this item (stock keeping unit)
    sku: 'sku_banana001',
    // price in smallest currency unit (e.g. cent for USD)
    price: 400,
    currency: 'USD',
    // Optional image to be shown on the Stripe Checkout page
    image: 'https://my-image.com/image.jpg'
  }
  /* ... more products */
]

Additionally, you must verify the cartItems on the server-side before creating the CheckoutSession. For this you can use the validateCartItems() helper.

Client-only Checkout mode

To operate a checkout page without any server component you need to enable client-only checkout mode and insert your product information in your Stripe Dashboard:

At the root level of your app, wrap your Root app in the <CartProvider />

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.STRIPE_API_PUBLIC)

ReactDOM.render(
  <CartProvider
    mode="client-only"
    stripe={stripePromise}
    // The URL to which Stripe should send customers when payment is complete.
    successUrl="http://localhost:3000/success"
    // The URL to which Stripe should send customers when payment is canceled.
    cancelUrl="http://localhost:3000"
    currency="USD"
    // https://stripe.com/docs/payments/checkout/client#collect-shipping-address
    allowedCountries={['US', 'GB', 'CA']}
    // https://stripe.com/docs/payments/checkout/client#collect-billing-address
    billingAddressCollection={true}
  >
    <App />
  </CartProvider>,
  document.getElementById('root')
)

When operating in client-only mode you must set the successUrl and cancelUrl props on the CartProvider component, and the product object must adhere to the following shape:

const products = [
  {
    name: 'Bananas',
    // sku ID from your Stripe Dashboard
    sku: 'sku_GBJ2Ep8246qeeT',
    // price in smallest currency unit (e.g. cent for USD)
    price: 400,
    currency: 'USD',
    // Optional image to be shown on the Stripe Checkout page
    image: 'https://my-image.com/image.jpg'
  }
  /* ... more products */
]

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 key={product.sku} 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({
    value: 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:

import { useShoppingCart } from 'use-shopping-cart'

export function CartItems() {
  const {
    cartDetails,
    decrementItem,
    incrementItem,
    removeItem
  } = 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 */}
        {/* formatted total price of that item */}
        <p>Line total: {cartEntry.formattedValue}</p>

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

        {/* What if we don't want this product at all */}
        <button
          onClick={() => removeItem(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 decrementItem() like so (note that you can also decrease by more than one):

decrementItem(cartEntry.sku)

// or decrease by a count
decrementItem(cartEntry.sku, 3)

This also works the same when trying to increase the quantity of a product:

incrementItem(cartEntry)

// increase by a count
incrementItem(cartEntry.sku, 4)

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

removeItem(cartEntry.sku)

How could the user set the quantity of an item to a specific number?

This is achievable with the setItemQuantity(sku, quantity) method (introduced in 2.0.0). It takes an SKU of a product in the cart and the quantity of that product you wish to have. Here is a very simple example:

export function GiveMeFiveDonutsPlease() {
  const { setItemQuantity } = useShoppingCart()
  return (
    <button onClick={() => setItemQuantity('donuts-1a2b3c', 5)}>
      Set donut quantity to 5
    </button>
  )
}

For a real-world robust example visit the documentation for setItemQuantity.

API

You can view the full API on our documentation page.

<CartProvider>

Props for this component in Client-only mode:

And now, CheckoutSession mode:

useShoppingCart()

Returns an object with all the following properties and methods:

formatCurrencyString(options)

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

Environment Variable Tutorials

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

License

MIT © dayhaysoos


Working on this project:

If you're working on this project don't forget to check out the CONTRIBUTING.md file.

Before you run any of the examples be sure to set your environment variables at the root of the project in a .env file (or documentation/.env for the documentation workspace). There is a .env.example and a documentation/.env.example file with the example variables you'll need to run the examples and documentation workspaces in this project. You'll need to fill them in with your own API keys from Stripe.

# .env.example
STRIPE_API_PUBLIC=
STRIPE_API_SECRET=

# documentation/.env.example
GATSBY_STRIPE_PUBLISHABLE_KEY=

Here are a couple commands to get you started in development:

# Run the development environment which builds use-shopping-cart in watch-mode
# and starts the CRA example with Netlify functions
yarn dev

# Runs tests in watch-mode
yarn test

# Runs the documentation page locally
yarn dev:docs

Warning

Please make all README edits to /use-shopping-cart/README.md. All edits to /README.md will be overwritten on commit by /use-shopping-cart/README.md. Consider /README.md read-only.

We created this hook with create-react-hook.

Contributors ✨

Thanks goes to these wonderful people (emoji key):

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