Компонент Stripe ‹CardElement /› по умолчанию выглядит прилично и действительно прост в использовании, и по умолчанию принимает номер карты, срок действия и CVC в одной области ввода.

Однако некоторые макеты требуют, чтобы вы отделяли ввод CVC и срок действия от номера карты. Я начинаю это руководство с того момента, как уже завершил реализацию ‹CardElement /› (код приведен ниже). Тем не менее, я не вникаю в фактическую настройку чередования, например, установку библиотек чередования для реакции, получение обещания чередования или перенос провайдера ‹Elements /› на модальный компонент оплаты.

Вот код, который я написал для создания этого простого платежного модала:

 const stripe = useStripe();
 const elements = useElements();

 const createSubscription = async () => {
    setLoading(true);
    try {
      // create a payment method
      const paymentMethod = await stripe?.createPaymentMethod({
        type: "card",
        card: elements.getElement(CardElement),
        billing_details: {
          name: GlobalAppState.getUser().name,
        }
      });
  }
  catch (error) {
      ZensoryModule.getErrorHandler().handleError(error);
      console.log(error);
    }
}
    <div className="popup-container-payment" ref={modalRef}>
      <div className="popup-header">
       
        <img
          id="btn-auth-error-popup-close"
          src={cross}
          className="popup-close-icon"
          onClick={(e) => closePopup(e)}
          alt="Close popup"
          tabIndex="0"
          onKeyDown={(e) => _handleKeyDownClose(e)}
        />
      </div>
      <div className="popup-instruction-payment">
        {getText(TextId.subscribePayment)}
      </div>
      <div className="card-entry">
        <CardElement options={cardElementOptions} />
      </div>

      {loading ? (
        <div
          style={{
            position: "relative",
            marginBottom: "40px",
            marginTop: "10px",
          }}
        >
          <SpinnerLoader />
        </div>
      ) : (
        <button
          disabled={!stripe || loading}
          id="btn-auth-error-popup-okay"
          tabIndex="0"
          className="subscribe-button"
          onClick={createSubscription}
        >
          Subscribe
        </button>
      )}

      <div>
        <img src={stripePower} alt="Powered by stripe" />
      </div>
    </div>

Однако внешний вид, которого я хотел добиться, был (это дизайн):

Для этого нам нужно заменить ‹CardElement /› на ‹CardNumberElement /›, ‹CardExpiryElement /› и ‹CardCvcElement /›.

Обновленный код:

const stripe = useStripe();
 const elements = useElements();

 const createSubscription = async () => {
    setLoading(true);
    try {
      // create a payment method
      const paymentMethod = await stripe?.createPaymentMethod({
        type: "card",
        card: elements.getElement(CardNumberElement), //please note this is changed from the original code
        billing_details: {
          name: GlobalAppState.getUser().name,
        }
      });
  }
  catch (error) {
      ZensoryModule.getErrorHandler().handleError(error);
      console.log(error);
    }
}
    <div className="popup-container-payment" ref={modalRef}>
      <div className="popup-header">
        <img
          id="btn-auth-error-popup-close"
          src={cross}
          className="popup-close-icon"
          onClick={(e) => closePopup(e)}
          alt="Close popup"
          tabIndex="0"
          onKeyDown={(e) => _handleKeyDownClose(e)}
        />
      </div>

      <div className="popup-instruction-payment">
        {getText(TextId.subscribePayment)}
      </div>

      <div className="card-entry">
        <CardNumberElement options={cardElementOptions} />
      </div>

      <div className="expiry-cvc-entry">    
      <div className="card-entry">
        <CardExpiryElement options={cardElementOptions} />
      </div>

      <div className="card-entry">
        <CardCvcElement options={cardElementOptions} />
      </div>
      </div>

      {loading ? (
        <div
          style={{
            position: "relative",
            marginBottom: "40px",
            marginTop: "10px",
          }}
        >
          <SpinnerLoader />
        </div>
      ) : (
        <button
          disabled={!stripe || loading}
          id="btn-auth-error-popup-okay"
          tabIndex="0"
          className="subscribe-button"
          onClick={createSubscription}
        >
          Subscribe
        </button>
      )}
      <div>
        <img src={stripePower} alt="Powered by stripe" />
      </div>

    </div>

Достигнутый результат:

Этот макет может быть просто требованием дизайна или выбором UX. На мой взгляд, он выглядит более профессионально, а также хорошо понятен пользователям.