この記事は、🌟LINE DC🌟 LINE Developer Community Advent Calendar 2022 11日目の記事です。
Stripe.jsとLIFF SDKの2つを活用することで、顧客とのコミュニケーションと決済をReactなどのアプリ内で表現できます。
プロジェクトとライブラリのセットアップ
まずはReactアプリのセットアップと、依存するライブラリを準備しましょう。
ViteでReactアプリを立ち上げる
Viteを利用して、Reactアプリをセットアップします。
$ yarn create vite liff-stripe --template react
LIFFとLIFF向けReactライブラリを追加する
続いてLIFFを組み込むためのライブラリを追加します。
$ yarn add @line/liff react-liff @line/liff-mock
今回、Reactへの組み込みには、以下のライブラリを使用しています。
Stripe.jsライブラリを追加する
続けてStripe Elementsで使用するStripe.js系ライブラリも追加します。
$ yarn add @stripe/stripe-js @stripe/react-stripe-js
環境変数を設定する
StripeとLIFFで使用するAPIキーなどを環境変数として設定します。
Viteの場合、VITE_
から始めましょう。
VITE_LIFF_ID=123456789-abcdefg
VITE_STRIPE_PUBLISHABLE_API_KEY=pk_test_xxx
LIFFのセットアップ
LIFFをReactアプリに組み込みましょう。
src/main.tsx
を次のように書き換えます。
import React from 'react'
import ReactDOM from 'react-dom/client'
import { LiffProvider } from 'react-liff'
import { LiffMockPlugin } from '@line/liff-mock'
import App from './App'
import './index.css'
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<LiffProvider
liffId={import.meta.env.VITE_LIFF_ID}
plugins={[
new LiffMockPlugin()
]}
// @ts-ignore
mock={true}
>
<App />
</LiffProvider>
</React.StrictMode>
)
続いて、ユーザー名を表示させましょう。
src/App.tsx
を次のように変更します。
import { useEffect, useState } from 'react'
import './App.css'
import { useLiff } from 'react-liff'
function App() {
const [username, setUsername] = useState("")
const { isLoggedIn, liff } = useLiff()
useEffect(() => {
(async () => {
if (!liff.isLoggedIn()) {
liff.login()
}
const profile = await liff.getProfile();
setUsername(profile.displayName)
})();
}, [liff, isLoggedIn]);
return (
<div className="App">
<h1>Hello {username}</h1>
</div>
)
}
export default App
Hello Brown
と画面に出れば成功です。
src/main.tsx
のmock={true}
を削除すると、LINEログイン画面に遷移します。
- // @ts-ignore
- mock={true}
Stripe Elementで決済フォームを表示する
ここからはStripe.jsを利用して、決済フォームをLIFFアプリに追加します。
クイックスタートを利用して、 Payment Intentを用意するAPIを作成する
Stripe.jsのカード要素を表示するには、事前にPayment IntentまたはSetup Intent(カード情報などの保存のみする場合)を作成します。
StripeドキュメントのクイックスタートなどでAPIを用意しましょう。
APIを呼び出して、Payment Intentを取得する
作成したAPIを呼び出して、アプリ側でPayment IntentのClient Secretを取得しましょう。
}, [liff, isLoggedIn]);
+ const [paymentIntentClientSecret, setPIClientSecret] = useState("")
+ useEffect(() => {
+ fetch("http://localhost:3000/create_payment_intent", {
+ method: "POST"
+ }).then(data => data.json())
+ .then(data => setPIClientSecret(data.clientSecret))
+ }, [])
return (
<div className="App">
取得したPayment Intentで、決済フォームを表示する
続いてStripe.js用のProviderにClient Secretを渡します。
import { useLiff } from "react-liff"
+import { loadStripe } from "@stripe/stripe-js"
+import { Elements } from "@stripe/react-stripe-js"
function App() {
...
return (
<div className="App">
<h1>Hello {username}</h1>
+ {paymentIntentClientSecret ? (
+ <Elements
+ stripe={loadStripe(import.meta.env.VITE_STRIPE_PUBLISHABLE_API_KEY)}
+ options={{
+ clientSecret: paymentIntentClientSecret
+ }}
+ >
+
+ </Elements>
+ ): null}
</div>
)
Providerを用意しましたので、子コンポーネントを作成してフォームを表示させましょう。
import { PaymentElement, useElements, useStripe } from "@stripe/react-stripe-js"
function PaymentForm() {
const stripe = useStripe()
const elements = useElements()
return (
<form
onSubmit={async e => {
e.preventDefault()
if (!stripe || !elements) return;
const result = await stripe.confirmPayment({
elements,
redirect: 'if_required',
})
console.log(result)
}}
>
<PaymentElement />
<button type="submit">Buy</button>
</form>
)
}
このコンポーネントを、Elements
の子要素で配置すればOKです。
<Elements
stripe={loadStripe(import.meta.env.VITE_STRIPE_PUBLISHABLE_API_KEY)}
options={{
clientSecret: paymentIntentClientSecret
}}
>
+ <PaymentForm />
</Elements>
決済完了後に、LIFFでメッセージを送信する
決済が完了したタイミングで、LIFFのsendMessages
を利用してメッセージを送信できます。
PaymentForm
コンポーネントを次のように変更しましょう。
function PaymentForm({ displayName }: { displayName?: string}) {
const stripe = useStripe()
const elements = useElements()
+ const { liff } = useLiff()
return (
<form
onSubmit={async e => {
e.preventDefault()
if (!stripe || !elements) return;
const result = await stripe.confirmPayment({
elements,
redirect: 'if_required',
})
+ await liff.sendMessages([{
+ type: "text",
+ text: `Your payment id: ${result.paymentIntent?.id}`
+ }])
}}
>
<PaymentElement />
<button type="submit">Buy</button>
</form>
)
}
このように、Stripe.jsとLIFFを組み合わせることで、Reactアプリ内で決済とメッセージングを連携することができます。