[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


<<:  [3D地图-CesiumJS系列] 二、建立飞航轨迹及动画

>>:  Day 28:IRQ (Part 2) - 中断突进!简单的 IRQ 程序

.Net Core Web Api_笔记12_自定义属性路由

在前几篇文章中我们都是用 微软内建的RouteAttribute跟HttpMethodAttribu...

Day 05 CSS <基础选择器>

CSS的选择器分为基础选择器以及复合选择器 本日将先说明基础选择器 DAY6将继续说明复合选择器 C...

【心得分享】第一周心得分享(4/12~4/18)

有兴趣的朋友可以点选以下连结,看到我这周撰写「系统分析师养成之路」的心得: https://itun...

使用 Google 表单快速建立实名制出入场所登记资料 COVID-19

免接触 免拿笔签名 流程 人进场 --> 手机扫描 QR --> 填写资料 -->...

资视就是力量 - Highcharts / 尾声

终於,花了一个月的时间,我们从零开始认识 Highcharts 到现在已经能够配合 Vue.js 一...