iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 28
0
Modern Web

雖然你不是木村拓哉,但它也可以讓你變很行 - Gatsby.js系列 第 28

[Day 28] - Gatsby feat. EC ( 下 )

昨天我們完成了一個基本的購物流程,但程式碼內有著不安全的問題,今天我們要用 .env 的形式來規避這個風險,至於怎麼做呢?就讓我們看下去吧!

補充說明一下 Sku 指的是庫存,因此若沒有依照 Stripe Document來正確的創建產品與庫存,是無法順利地完成這篇文章的範例唷!

環境變數

首先,我們打開昨天製作的 ecommerce-gatsby-tutorial 目錄,並在裡面輸入以下指令來安裝 gatsby-source-stripe 套件

npm install gatsby-source-stripe

Gatsby-source-stripe 套件可以讓我們在 gatsby-config.js 中設定我們的 Key 與其他的私人資訊,並在需要的地方顯示出來,所以安裝完畢後,讓我們打開 gatsby-config.js 檔並貼上以下程式碼

	 {
      resolve: `gatsby-source-stripe`,
      options: {
        objects: ["Sku"],
        secretKey: process.env.STRIPE_SECRET_KEY,
        downloadFiles: true,
      },
    },

我們會將在 Stirpe 上拿到的私 Key 設定在這,不過會是代入環境變數的方式來設定。

如果對於環境變數有興趣的讀者,可以參考這一篇 Environment Variables - Gatsby

接下來我們在根目錄下新增一個 .env.development 檔,來放置我們的環境變數

STRIPE_SECRET_KEY=sk_test_xxx

建立完環境變數後,我們會在 gatsby-config.js 中引入它,引入的方式如下

require("dotenv").config({
  path: `.env.${process.env.NODE_ENV}`,
})

最後避免這隻檔案被放到 GitHub 上公開,所以我們會在 .gitignore 中新增 .env.development 此檔名,來避免他被 git 紀錄,所以我們會加入以下程式碼。

.env
.env.development
.env.production

製作商品元件

在完成變數設定後,我們到 components 目錄下在建立一個 Products 資料夾,我們會在裡面放上我們的商品元件,首先,我們會需要撈出 SKU 的元件,由於是元件,所以我們會用靜態查詢 ( StaticQuery ) 的方式來通過 GraphQL 來撈取資料,並將我們撈取的資料下去跑迴圈,就能列出我們所有的商品列表囉!

import React from "react"
import { graphql, StaticQuery } from "gatsby"

export default props => (
	// 使用靜態查詢撈資料
  <StaticQuery
    query={graphql`
      query SkusForProduct {
        skus: allStripeSku {
          edges {
            node {
              id
              currency
              price
              attributes {
                name
              }
            }
          }
        }
      }
    `}
    render={({ skus }) => (
		// 將撈取的資料跑迴圈並列出列表
      <div>
        {skus.edges.map(({ node: sku }) => (
          <p key={sku.id}>{sku.attributes.name}</p>
        ))}
      </div>
    )}
  />
)

若沒有正確的新增庫存,此時你的終端機應該會出現以下錯誤
Cannot query field "allStripeSku" on type "Query".
只要正確新增 Sku 後,即可正常顯示囉!

接著我們創建一個新頁面來放置這個列表,所以我們在 pages 中建立一個頁面名稱為 advanced.js 並在裡面貼上以下程式碼,程式碼中,我們引入了剛剛建立好的 Sku 元件,並顯示在上面。

import React from "react"
import { Link } from "gatsby"

import Layout from "../components/layout"
import SEO from "../components/seo"

import Skus from "../components/Products/Skus"

const AdvancedExamplePage = () => (
  <Layout>
    <SEO title="Advanced Example" />
    <h1>This is the advanced example</h1>
    <Skus />
  </Layout>
)

export default AdvancedExamplePage

完成後,我們可以點擊 http://localhost:8000/advanced 就能看到我們的列表囉!

雖然完成了列表,但列表只顯示單純的文字並不能讓身為視覺動物的客戶有任何的購買慾望,所以我們必須做一點視覺上的美化與增加它的互動性,所以我們在 Products 下再建立一個元件名稱為 SkuCard.js,這個元件之後會在跑完迴圈後,Render 它。

import React from "react"

// 增加產品卡片樣式
const cardStyles = {
  display: "flex",
  flexDirection: "column",
  justifyContent: "space-around",
  alignItems: "flex-start",
  padding: "1rem",
  marginBottom: "1rem",
  boxShadow: "5px 5px 25px 0 rgba(46,61,73,.2)",
  backgroundColor: "#fff",
  borderRadius: "6px",
  maxWidth: "300px",
}
const buttonStyles = {
  fontSize: "13px",
  textAlign: "center",
  color: "#fff",
  outline: "none",
  padding: "12px",
  boxShadow: "2px 5px 10px rgba(0,0,0,.1)",
  backgroundColor: "rgb(255, 178, 56)",
  borderRadius: "6px",
  letterSpacing: "1.5px",
}

const formatPrice = (amount, currency) => {
  let price = (amount / 100).toFixed(2)
  let numberFormat = new Intl.NumberFormat(["en-US"], {
    style: "currency",
    currency: currency,
    currencyDisplay: "symbol",
  })
  return numberFormat.format(price)
}

const SkuCard = class extends React.Component {
  async redirectToCheckout(event, sku, quantity = 1) {
    event.preventDefault()
    const { error } = await this.props.stripe.redirectToCheckout({
      items: [{ sku, quantity }],
      successUrl: `http://localhost:8000/page-2/`,
      cancelUrl: `http://localhost:8000/advanced`,
    })

    if (error) {
      console.warn("Error:", error)
    }
  }
  // 從 Props 中撈取對應的 sku 來確保我們找到對應的產品
  render() {
    const sku = this.props.sku
    return (
      <div style={cardStyles}>
        <h4>{sku.attributes.name}</h4>
        <p>Price: {formatPrice(sku.price, sku.currency)}</p>
        <button
          style={buttonStyles}
          onClick={event => this.redirectToCheckout(event, sku.id)}
        >
          購買
        </button>
      </div>
    )
  }
}

export default SkuCard

完成後,我們就立馬來調整剛剛的 Skus.js 元件
首先要調整的大概分為三個小部分。

  1. 引入做好的產品卡片。
import SkuCard from './SkuCard'
  1. 在 DOM 初始載入時,初始化 Stripe。
state = {
    stripe: null,
  }
  componentDidMount() {
    const stripe = window.Stripe(process.env.GATSBY_STRIPE_PUBLIC_KEY)
    this.setState({ stripe })
  }

  1. 在迴圈內將 P tag 改為我們做好的 產品卡片。
<SkuCard key={sku.id} sku={sku} stripe={this.state.stripe} />

完成後,我們重啟開發者伺服器,就能看到美美的商品卡片囉!這樣的做法是不是既方便又安全呢?若有興趣的讀者也可以嘗試用綠界或其他台灣常見的支付商家來串接看看唷!

參考資料

Gatsby E-commerce Tutorial - Gatsby


上一篇
[Day 27] - Gatsby feat. EC ( 上 )
下一篇
[Day 29] - Gatsby v.s. Next
系列文
雖然你不是木村拓哉,但它也可以讓你變很行 - Gatsby.js30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言