2
1

More than 1 year has passed since last update.

Gatsbyで作るサイトに、use-shopping-cartを使ってStripe Checkoutを利用したECカート機能を実装する

Posted at

以前「カート機能を簡単に実装できるフックライブラリ」としてuse-shopping-cartを紹介しました。

今回は、このuse-shopping-cartをGatsbyで作成した静的サイトで利用する方法を紹介します。

事前準備

今回紹介する方法では、REST APIなどを使用せず、クライアント側の組み込みのみでCheckoutのセッションを開始します。

そのため、事前にStripeダッシュボードの設定ページで、「クライアント側のみの組み込み」を有効にしましょう。
直接飛ぶ場合: https://dashboard.stripe.com/settings/checkout

無効化されている状態

スクリーンショット 0004-03-10 14.45.33.png

有効になっている状態
スクリーンショット 0004-03-10 14.43.34.png

Gatsbyプロジェクトのセットアップ

まずはGatsbyプロジェクトをセットアップしましょう。
今回はuse-shopping-cart組み込みがメインのため、設定はデフォルトのままにしています。

$ npm init gatsby
npx: 3個のパッケージを2.144秒でインストールしました。
create-gatsby version 2.9.0



                     Welcome to Gatsby!



This command will generate a new Gatsby site for you in
/Users/sandbox with the setup you select. Let's
answer some questions:


What would you like to call your site?
✔ · My Gatsby Site
What would you like to name the folder where your site will be created?
✔ sandbox/ my-gatsby-site
✔ Will you be using a CMS?
· No (or I'll add it later)
✔ Would you like to install a styling system?
· No (or I'll add it later)
✔ Would you like to install additional features with other plugins?No items were selected



Thanks! Here's what we'll now do:

    🛠  Create a new Gatsby site in the folder my-gatsby-site
  
? Shall we do this? (Y/n) › Yes

セットアップが終わったら、プロジェクトのディレクトリへ移動します。

% cd my-gatsby-site

また、環境変数でStripeの公開可能キーを保存しておきましょう。

env.development

GATSBY_STRIPE_PUBLIC_KEY=pk_test_xxx

use-shopping-cartライブラリを追加する

続いてuse-shopping-cartをインストールしましょう。

% npm i gatsby-plugin-use-shopping-cart use-shopping-cart

use-shopping-cartの設定を行う

gatsby-plugin-use-shopping-cartを使うことで、use-shopping-cartのProvider設定をプラグイン側に任せることができます。
公開可能APIキーなどの設定はgatsby-config.jsで行いましょう。

/** @type {import('gatsby').GatsbyConfig} */
require("dotenv").config({
  path: `.env.development`,
})

module.exports = {
  siteMetadata: {
      title: ``,
      siteUrl: `https://example.com`,
  },
  plugins: [
    {
      resolve: `gatsby-plugin-use-shopping-cart`,
      options: {
        mode: "payment",
        cartMode: "client-only",
        stripePublicKey: process.env. GATSBY_ STRIPE_PUBLIC_KEY,
        successUrl: "https://example.com/success", // url must start with http or https
        cancelUrl: "https://example.com/cancel", // url must start with http or https
        currency: "JPY",
        billingAddressCollection: true,
      },
    },
  ]
}

これでセットアップは完了です。

use-shopping-cartでサイトを実装する

Gatsbyプラグインで、Providerの設定は完了しています。
あとは、useShoppingCartフックを利用して、カート操作や注文のボタンを実装しましょう。

「今すぐ注文」ボタンを作成する

まずは1つの商品をすぐに注文できるボタンを作りましょう。
今すぐ注文ボタンを作るには、checkoutSingleItemを利用します。

import * as React from "react"
import { useShoppingCart } from 'use-shopping-cart'

const IndexPage = () => {
  const { checkoutSingleItem } = useShoppingCart()
  return (
    <main>
      <div>
        <button onClick={() => {
          checkoutSingleItem('price_xxxx')
        }}>今すぐ注文</button>
      </div>
  </main>
)

export default IndexPage

これで、今すぐ注文をクリックするとStripeの注文ページにリダイレクトされるようになります。

カート機能を実装する

続いて、商品を追加・変更できるカート機能を作りましょう。

カートに商品を追加する

カートへの追加は、addItemを利用します。

import * as React from "react"
import { useShoppingCart } from 'use-shopping-cart'

const IndexPage = () => {
  const { addItem } = useShoppingCart()
  return (
    <main>
      <div>
        <button onClick={() => {
          addItem({
            name: 'バナナ',
            price_id: 'price_xxxxx',
            price: 400
          })
        }}>バナナを追加する</button>
        <button onClick={() => {
          addItem({
            name: 'パン',
            price_id: 'price_xxxxx',
            price: 400
          })
        }}>パンを追加する</button>
      </div>
  </main>
)

export default IndexPage

これで、use-shopping-cart内部にあるstoreに商品のデータを追加できるようになりm最多。

カートの中身を表示する

追加したカートの中身をみるには、cartDetailsを利用します。
また、formattedTotalPriceを利用することで、合計金額も取得できます。


import * as React from "react"
import { useShoppingCart } from 'use-shopping-cart'

const IndexPage = () => {
  const { formattedTotalPrice, cartDetails } = useShoppingCart()
  return (
    <main>
      <div>
        <ul>
          {Object.values(cartDetails).map((cart: any) => {
            return (
              <li key={cart.id}>
                {cart.name} - {cart.formattedPrice} * {cart.quantity} = {cart.formattedValue}
              </li>
            )
          })}
          <li>合計: {formattedTotalPrice}</li>
        </ul>
      </div>
  </main>
)

export default IndexPage

これで、カートの中身をユーザーに表示できるようになりました。

スクリーンショット 0004-03-10 15.09.38.png

カートの商品数を変更できるようにする

カートの数量を変更する関数もフックに用意されています。


import * as React from "react"
import { useShoppingCart } from 'use-shopping-cart'

const IndexPage = () => {
-  const { formattedTotalPrice, cartDetails } = useShoppingCart()
+  const { formattedTotalPrice, cartDetails, decrementItem, incrementItem, removeItem } = useShoppingCart()
  return (
    <main>
      <div>
        <ul>
          {Object.values(cartDetails).map((cart: any) => {
            return (
              <li key={cart.id}>
                {cart.name} - {cart.formattedPrice} * {cart.quantity} = {cart.formattedValue}
+                <button onClick={() => decrementItem(cart.price_id)}>1つ減らす</button>
+                <button onClick={() => incrementItem(cart.price_id)}>1つ増やす</button>
+                <button onClick={() => removeItem(cart.price_id)}>削除</button>
              </li>
            )
          })}
          <li>合計: {formattedTotalPrice}</li>
        </ul>
      </div>
  </main>
)

export default IndexPage

これらを組み合わせることで、とても簡素ですが通販に欠かせないカートシステムを実装できました。

スクリーンショット 0004-03-10 15.13.35.png

注文ページ(Stripe Checkout)へ移動する

最後にStripe Checkoutへのリダイレクトするボタンを追加しましょう。

注文ページへのリンクはredirectToCheckoutを利用します。


import * as React from "react"
import { useShoppingCart } from 'use-shopping-cart'

const IndexPage = () => {
-  const { formattedTotalPrice, cartDetails, decrementItem, incrementItem, removeItem } = useShoppingCart()
+  const { formattedTotalPrice, cartDetails, decrementItem, incrementItem, removeItem, redirectToCheckout } = useShoppingCart()
  return (
    <main>
      <div>
        <ul>
          {Object.values(cartDetails).map((cart: any) => {
            return (
              <li key={cart.id}>
                {cart.name} - {cart.formattedPrice} * {cart.quantity} = {cart.formattedValue}
+                <button onClick={() => decrementItem(cart.price_id)}>1つ減らす</button>
+                <button onClick={() => incrementItem(cart.price_id)}>1つ増やす</button>
+                <button onClick={() => removeItem(cart.price_id)}>削除</button>
              </li>
            )
          })}
          <li>合計: {formattedTotalPrice}</li>
        </ul>
        <button onClick={() => redirectToCheckout()}>注文する</button>
      </div>
  </main>
)

export default IndexPage

カート内の商品情報などは、use-shopping-cart側が内部的に処理してくれるため、とてもシンプルな実装で対応できます。

GatsbyでStripeの料金データを取り込む

ここまでは、料金・商品データをベタ打ちしていました。

ですが、Gatsbyプラグインを利用することで、商品・料金データの取り込みも行えます。

Gatsbyプラグインと環境変数を設定する

まずはGatsbyのビルド時にStripeのデータを取り込むためのプラグインを追加します。

% npm i gatsby-source-stripe

続いてgatsby-config.jsで接続のための設定を追加します。

  plugins: [
+    {
+      resolve: `gatsby-source-stripe`,
+      options: {
+        objects: ['Price'],
+        secretKey: process.env.STRIPE_SECRET_API_KEY,
+        downloadFiles: false,
+      },
+    },
    {
      resolve: `gatsby-plugin-use-shopping-cart`,

また、環境変数でStripeのシークレットAPIキーも保存しておきましょう。

env.development

GATSBY_STRIPE_PUBLIC_KEY=pk_test_xxx
+STRIPE_SECRET_API_KEY=sk_test_xxx

料金・商品データを取得する

GatsbyからStripeへの接続準備はできました。
あとはGraphQLを利用してデータを取得するだけです。

import * as React from "react"
import { graphql, StaticQuery } from 'gatsby'

const IndexPage = () => {
  return (
    <main>
      <StaticQuery
        query={graphql`
          query ProductPrices {
            prices: allStripePrice(
              filter: { active: { eq: true }, currency: { eq: "jpy" } }
              sort: { fields: [unit_amount] }
            ) {
              edges {
                node {
                  id
                  currency
                  unit_amount
                  product {
                    id
                    name
                  }
                }
              }
            }
          }
        `}
        render={({ prices }) => (
          <ul>
            {prices.edges.map(({ node }) => {
              const price = {
                price_id: node.id,
                name: node.product.name,
                price: node.unit_amount,
                currency: node.currency,
              }
              return (
                <pre key={node.id}>
                  <code>{JSON.stringify(node, null, 2)}</code>
                </pre>
              )
            })}
          </ul>
        )}
      />
  </main>
)

export default IndexPage

use-shopping-cartを組み込む

最後に、use-shopping-cartのaddItemを組み込んで、商品をカートに追加できるようにします。

import * as React from "react"
+import { useShoppingCart } from 'use-shopping-cart'
import { graphql, StaticQuery } from 'gatsby'

const IndexPage = () => {
  const { addItem } = useShoppingCart()
  return (
    <main>
      <StaticQuery
        query={graphql`
          query ProductPrices {
            prices: allStripePrice(
              filter: { active: { eq: true }, currency: { eq: "jpy" } }
              sort: { fields: [unit_amount] }
            ) {
              edges {
                node {
                  id
                  currency
                  unit_amount
                  product {
                    id
                    name
                  }
                }
              }
            }
          }
        `}
        render={({ prices }) => (
          <ul>
            {prices.edges.map(({ node }) => {
              const price = {
                price_id: node.id,
                name: node.product.name,
                price: node.unit_amount,
                currency: node.currency,
              }
              return (
+                <li key={price.price_id}>
+                  <button onClick={() => addItem(price)}>
+                    {price.name}を追加する
+                  </button>
+                </li>
              )
            })}
          </ul>
        )}
      />
  </main>
)

export default IndexPage

終わりに

サーバー側の処理でCheckoutセッションを開始していないため、機能に制限があることに注意が必要です。
ですが、Gatsbyのみで完結するサイトにEC機能を組み込みたい場合、use-shopping-cartとgatsby-source-stripeの組み合わせがとても便利です。

Stripeを使ったオンライン決済の第一歩として、ぜひお試しください。

[PR] Stripe開発者向け情報をQiitaにて配信中!

  • [Stripe Updates]:開発者向けStripeアップデート紹介・解説
  • ユースケース別のStripe製品や実装サンプルの紹介
  • Stripeと外部サービス・OSSとの連携方法やTipsの紹介
  • 初心者向けのチュートリアル(予定)

など、Stripeを利用してオンラインビジネスを始める方法について週に2〜3本ペースで更新中です。

-> Stripe Organizationsをフォローして最新情報をQiitaで受け取る

2
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1