Next.jsとShopifyで最速でECサイトをつくる②

※この記事は [Next.jsとShopifyで最速でECサイトをつくる①](https://qiita.com/nobux42/items/c038fdd5c63334a171c3) の続きです。
まだ読んでいない人は先に前半の記事を読むことをおすすめします。

前半: [Next.jsとShopifyで最速でECサイトをつくる①](https://qiita.com/nobux42/items/c038fdd5c63334a171c3)
後半: Next.jsとShopifyで最速でECサイトをつくる② ←いまここ

## 商品詳細画面の作成
つぎに簡単な商品の詳細画面を作成します。

["pages/[id].tsx"]

```tsx
type DetailProps = {
  product?: Product
  errors?: string
};

const DetailPage = (props: DetailProps) => {
  const {product, errors} = props;

  if (errors) { return <p>Error: {props.errors}</p> }
  if (!product) { return <p>Error: Product not found</p> }

  return (
    <Layout title={product.title}>
      <div>
        <p>{product.title}</p>
        <img src={product.images[0].src} height={200}/>
      </div>
    </Layout>
  )
}

export default DetailPage
```

今回はSSGでそれぞれの商品ページを生成するので、`getStaticPaths`と`getStaticProps`を使ってそデータを取得していきます。

["pages/[id].tsx"]

```tsx
export const getStaticPaths: GetStaticPaths = async () => {
  const products: Product[] = await client.product.fetchAll();
  const paths = products.map((product) => ({
    params: { id: product.id.toString() },
  }))
  return { paths, fallback: false }
}

export const getStaticProps: GetStaticProps<DetailProps> = async ({ params }) => {
  try {
    const id = params?.id;
    if(!id) {
      return { props: { errors: "not found" } };
    }
    const productRes = await client.product.fetch(id as string);
    const product = JSON.parse(JSON.stringify(productRes));
    return { props: { product: product } }
  } catch (err) {
    return { props: { errors: "unexpected error" } };
  }
}

```

最後に、トップページからリンクを作成すれば完成です。

["pages/index.tsx"]

```diff
const IndexPage: React.FC<IndexProps> = ({ products }) => {
  console.log(products);
  return (
    <Layout title="Top">
      <h1>Hello Next.js 👋</h1>
      <ul>
        {
          products.map((product) => 
          <li key={product.id}>
+            <Link href="/[id]" as={`/${product.id}`}>
+              <a>
                {product.title}
                <img src={product.images[0].src} height={80}/>
+              </a>
+            </Link>
          </li>)
        }
      </ul>
    </Layout>
  );
}
```

リンクを押して商品詳細画面に行くと以下のような画面が表示がされていると思います。

![スクリーンショット 2020-12-30 19.03.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135243/bcd58af9-6104-f4f8-c935-568398e1e25d.png)
`http://localhost:3000/[商品ID]`

## 購入ボタンの設置
あとは購入への導線を用意してあげれば完了です。

今回は最小限のコードで試したいので、カートページは用意せずに、商品詳細画面に直接購入ボタンをおいてみたいと思います。

["pages/[id].tsx"]

```diff
const DetailPage = (props: DetailProps) => {
  const {product, errors} = props;
+  const [checkoutLink, setCheckoutLink] = useState("");

  if (errors) { return <p>Error: {props.errors}</p> }
  if (!product) { return <p>Error: Product not found</p> }
+
+  useEffect(() => {
+    client.checkout.create().then((checkout: any) => {
+      const variantsId = product.variants[0].id;
+      client.checkout.addLineItems(checkout.id, [{ variantId: variantsId, quantity: 1}])
+      .then((checkout) => {
+        console.log(checkout.lineItems); 
+        setCheckoutLink(checkout.webUrl);
+      });
+    });
+  }, []);

  return (
    <Layout title={product.title}>
      <div>
        <p>{product.title}</p>
        <img src={product.images[0].src} height={200}/>
      </div>
+      <Link href={checkoutLink}>
+        <button>購入する</button>
+      </Link>
    </Layout>
  )
}
```

処理としては`useEffect`の中で、購入処理の単位となる`checkout`を作成して、現在の商品詳細画面で表示している商品を`1`つ追加しています。
この`checkout`をカートのように使うことができますが、処理を簡単にするためにこのような単純な実装としています。

`checkout`は`webUrl`というプロパティを持っています。
これはShopifyのサイトに移動して決算ができるページのURLとなっているので、今回はこれを利用します。

あと、注意点として`addLineItems`に指定する商品のIDは`product.id`ではなく、`product.variants[x].id`となります。
Shopifyの商品データは、サイズや色などを別のバリエーションとして持つことができ、そのIDとなります。
今回は特にバリエーションは気にせず、最初のバリエーション(`product.variants[0].id`)を選択しています。

![スクリーンショット 2020-12-30 19.21.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135243/7599b20f-7112-1211-357b-bef5d050cd9b.png)

これで[購入する]ボタンが追加されたかと思います。
このボタンを押すと、Shopifyのサイトに移動して

![スクリーンショット 2020-12-30 19.22.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135243/3ab08df8-72dd-88ba-20e2-9bcd5f469115.png)

`https://nexjs-example.myshopify.com/52339802311/checkouts/[checkoutID]`

このような購入ページが表示されると思います。

## まとめ
以上でNext.jsとShopifyで最速でECサイトを作るの内容としたいと思います！

はじめてShopifyというECサービスを使ってみて、苦戦することも多かったですがなんとか購入できるところまで作成できたと思います。

ShopifyはセルフホスティングだけでECサイトを構築することができますが、今回のように便利なAPIを用意してくれているので、独自でJAMStack構成やマイクロサービス構成などにも組み込みやすくなっていると思います。

今回はStorefront API (by js-by-sdk)を使用しましたが、他にも`Shopify Buy Botton`を使う方法や、Admin APIなどもあるためできることはまだいろいろありそうです。

引き続きShopifyについて勉強していきたいと思います。

今回のソースコードはこちらにあります。
GitHub: https://github.com/nobux42/next-shopify-example