【问题标题】:Adding cardholder name in Stripe在 Stripe 中添加持卡人姓名
【发布时间】:2021-07-15 22:00:58
【问题描述】:

所以我面临的问题是这个。在这里,我使用 Stripe 创建了 PaymentForm。因此,当我没有输入 CardHolder 姓名的输入值时,当我按下购买按钮时,它应该显示 <h1>Please enter your cardholder name</h1> 但它没有这样做。我只想创建一个持卡人姓名的测试,我知道 Stripe 的文档显示了真正的方法。错误可能在哪里?

Payment form

import React,{useContext, useEffect, useState} from 'react'
import {CardElement, useStripe, useElements } from"@stripe/react-stripe-js"
import { CartContext } from '../../context/cart'

import {  useHistory, Link } from "react-router-dom";



const PaymentForm = () => {
  const { total} = useContext(CartContext)
  const {cart, cartItems}= useContext(CartContext)
  const history = useHistory()
  const {clearCart} = useContext(CartContext)
  const [nameError, setNameError]=useState(null)
  const [name, setName] = React.useState("");
  const [succeeded, setSucceeded] = useState(false);
  const [error, setError] = useState(null);
  const [processing, setProcessing] = useState('');
  const [disabled, setDisabled] = useState(true);
  const [clientSecret, setClientSecret] = useState('');
  const stripe = useStripe();
  const elements = useElements();
  useEffect(() => {
    // Create PaymentIntent as soon as the page loads
    window
      .fetch("http://localhost:5000/create-payment-intent", {
        method: "POST",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify({items: [{cart}]})
      })
      .then(res => {
        return res.json();
      })
      .then(data => {
        setClientSecret(data.clientSecret);
      });
  }, [cart]);
  const cardStyle = {
    style: {
      base: {
        color: "#32325d",
        fontFamily: 'Arial, sans-serif',
        fontSmoothing: "antialiased",
        fontSize: "16px",
        "::placeholder": {
          color: "#32325d"
        }
      },
      invalid: {
        color: "#fa755a",
        iconColor: "#fa755a"
      }
    }
  };
  const handleChange = async (event) => {
    setDisabled(event.empty);
    setError(event.error ? event.error.message : "");
  };
  const handleChangeInput = async (event) => {
    setDisabled(event.empty);
    setNameError(event.nameError ? event.nameError.message : "");
    setName(event.target.value)
  };

  const handleSubmit = async ev => {
    ev.preventDefault();
    setProcessing(true);
    const payload = await stripe.confirmCardPayment(clientSecret, {
      payment_method: {
        card: elements.getElement(CardElement)
      }
    });

   
    if (payload.error) {
      setError(`Payment failed ${payload.error.message}`);
      setProcessing(false);
    } else {
      setNameError(null)
      setError(null);     
      setProcessing(false);
      setSucceeded(true)
      clearCart()
    }
  };  
  useEffect(()=>{
    setTimeout(() => {  
    if(succeeded){
      history.push('/')
    }
    }, 3000);
  },[history, succeeded])
 
console.log(name)
 
  return (
    <form id="payment-form" onSubmit={handleSubmit}>
      <h2>Checkout</h2>
      <div className='payment__cont'>
       <label>Cardholder Name </label>
       <input 
        placeholder='Please enter your Cardholder name'
        type="text"
        id="name"
        value={name}
        onChange={handleChangeInput}
         />
      </div>
      <div className="stripe-input">
          <label htmlFor="card-element">
            Credit or Debit Card
            </label>
          <p className="stripe-info">
            Test using this credit card : <span>4242 4242 4242 4242</span>
            <br />
            enter any 5 digits for the zip code
            <br />
            enter any 3 digits for the CVC
          </p>
        </div>
      <CardElement id="card-element" options={cardStyle} onChange={handleChange} />
      <div className='review__order'>
      <h2>Review Order</h2>
      <h4>Total amount to pay ${total}</h4>
      <h4>Total amount of items {cartItems}</h4>
      <button
        className='purchase__button'
        disabled={processing || disabled || succeeded}
        id="submit"
      >     
        <span id="button-text">
          {processing ? (
            <div className="spinner" id="spinner"></div>
          ) : (
            "Complete purchase"
          )}
        </span>
      </button>
      <button className='edit__button'onClick={()=> {history.push('/cart')}}>Edit Items</button>
      </div>
      {error && (
        <div className="card-error" role="alert">
          {error}
        </div>
      )}

       {nameError && (
        <div className="card-error" role="alert">
          <h1>Please enter yor card holder name</h1>
        </div>
      )}
      <p className={succeeded  ? "result-message" : "result-message hidden"}>
        Payment succeeded        
          {''}
          <h1>Redirecting you yo the home</h1>
      </p>
  
    </form>
  );
}



export default PaymentForm

【问题讨论】:

    标签: javascript reactjs stripe-payments


    【解决方案1】:

    您仍然需要自己验证您的name 输入。 Stripe 不会为您做到这一点

    您的 handleChangeInput 处理程序仅在您写入 name 输入时触发,并且您将事件视为从 Stripe 组件触发,但事实并非如此,所以试试这个:

      // Validates name input only
      const handleChangeInput = async (event) => {
        const { value } = event.target;
    
        // Disable when value is empty
        setDisabled(!value); 
    
        // Set the error if value is empty
        setNameError(value ? "" : "Please enter a name");
    
        // Update form value
        setName(value)
      };
    

    【讨论】:

    • 还是不行。
    • 我应该在handleSubmit中添加错误消息
    • 如前所述,name 不是 Stripe 在 confirmCardPayment() 中需要的东西,而是您的代码正在收集的东西,因此您的代码需要检查它。然后在confirmCardPayment() 上的billing_details 哈希中传递它,如下所示:stripe.com/docs/js/payment_intents/confirm_card_payment
    • 我不能在这里写完整的代码,但你基本上只需要在那里进行if (name.length &gt; 0)类型检查,如果满足该检查,则确认 PaymentIntent(即设置了非零长度名称) .如果未通过检查,则在 else 块中设置 setErrorName
    • “确认付款”是指您拨打stripe.confirmCardPayment()的代码行
    【解决方案2】:

    我不确定您想用 Stripe 元素做什么,因为持卡人姓名实际上并不是其中的一部分。您需要自己处理。

    确保在按下卡片元素之前输入姓名字段的另一种方法是在显示/启用条纹卡片元素之前强制输入持卡人姓名字段。这样,在按下卡片元素之前,您可以更确定输入的名称(然后您可以用它做您喜欢的事情)。您可以通过多种方式做到这一点,但例如在您的渲染中:

    {name.length >= 10 ? ( //Check length of name
    <CardElement id="card-element" options={cardStyle} onChange={handleChange} />
    ) : (
       <span>Please enter your cardholder name.</span> // do nothing if check not passed  
    )}
    

    这是一个非常简单的示例,但它会检查名称的长度,然后如果大于或等于十个字符,则使卡片元素可见。您可以改为使用您的 handleChangeInput 在按钮按下等时设置布尔状态(真或假);最好让它更健壮。

    编辑:一些澄清。

    【讨论】:

    • @WhoKnowsWhereTheTimeGoes我只是想弄清楚当按下购买按钮时输入值为空或少于10个字符时我应该如何显示错误消息
    • 此解决方案中的卡片元素在满足该条件之前不会显示;错误消息显示为默认值,并且仅在更正错误后才显示卡元素。我自己在生产中使用这种条件渲染方法,它为客户提供了更清晰的顺序流程。干扰 CardElement 很难也不可取,因为它旨在传递必要的数据以进行条带化,而无需您处理它(为了符合 PCI/DSS)。在您的示例中,您想知道它是否在条纹响应之前被按下。
    • 所以在你的例子中,我必须满足第一个条件或输入持卡人姓名,然后元素出现
    • 是的。它使用内联条件渲染 (reactjs.org/docs/conditional-rendering.html) 隐藏卡片元素,直到 name.length >= 10,并在此之前显示一条消息。只要你的“名字”状态是在输入时设置的,当然;)
    猜你喜欢
    • 1970-01-01
    • 2018-04-17
    • 2016-05-14
    • 1970-01-01
    • 2018-01-30
    • 1970-01-01
    • 1970-01-01
    • 2022-11-10
    • 1970-01-01
    相关资源
    最近更新 更多