🕌

Stripe関連

2023/06/25に公開

カードの変更

  1. カードフォームで新しいカード情報を入力
  2. 一時的なトークンを取得
  3. create card apiに投げてカード作成
  4. カスタマーに新しいカード紐付け

カードフォーム

CardElementを使う

  export default function CheckoutForm() {
  const userInfo = useRecoilValue(userInfoState)
  const stripe = useStripe()
  const elements = useElements()

  const [message, setMessage] = useState('')
  const [isLoading, setIsLoading] = useState(false)

  const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault()

    if (!stripe || !elements || !userInfo) {
      return
    }

    const cusId = userInfo.stripeCusId
    if (!cusId) {
      return
    }

    setIsLoading(true)
    const cardElement = elements.getElement(CardElement)
    if (!cardElement) {
      return
    }

    const result = await stripe.createToken(cardElement)
    if (result.error) {
      setMessage(result.error.message!)
      setIsLoading(false)
      return
    }

    const card = result.token.card
    if (!card) {
      setMessage('Something went wrong.')
      setIsLoading(false)
      return
    }

    const res = await fetch('/api/payment/updateCustomer', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        cusId,
        cardId: card.id,
        token: result.token.id,
      }),
    })

    const data = await res.json()
    console.log(JSON.stringify(data))

    setIsLoading(false)
  }

  return (
    <form onSubmit={handleSubmit} className="p-6">
      <CardElement
        className="py-3 px-4 border border-gray-200 rounded-md"
        options={{
          style: {
            base: {
              padding: '10px 12px',
              color: '#000000',
              fontWeight: '500',
              fontSize: '16px',
              fontSmoothing: 'antialiased',
              '::placeholder': {
                color: 'gray',
              },
            },
            invalid: {
              iconColor: '#FFC7EE',
              color: '#FFC7EE',
            },
          },
        }}
      />

      <button disabled={isLoading || !stripe || !elements} id="submit">
        <span id="button-text">
          {isLoading ? <div className="spinner" id="spinner"></div> : 'Pay now'}
        </span>
      </button>
      {message && <div id="payment-message">{message}</div>}
    </form>
  )
}

Discussion