#skoshkarli - Paymen Element

1 messages · Page 1 of 1 (latest)

plush tapir
#

Hi 👋
Can you share how you are initializing and mounting the Payment Element?

split flower
#
              stripe={this.props.paymentProvider}
              options={{ clientSecret: this.props.clientSecret }}
            >
              <form onSubmit={() => {}}>
                <PaymentElement />
                <button disabled={!this.props.paymentProvider}>Submit</button>
              </form>
            </Elements>
#

paymentProvider is stripePromise

#

and clientSecret is returned from the subscription PaymentIntent which i create before

plush tapir
split flower
#

what do you mean by how the form is rendered?

plush tapir
#

I am not familiar with React so I was interested in the differences between how you handle the creation of the from and the onSubmit handler vs what we have documented

split flower
#

yeah i just removed the onSubmit handler all together and did what they did in the checkout component as per docs and same thing

#

it just doesn't render anything but my submit button

#

when i use the CardElement though, that shows up fine

#

but i need the PaymentElement

plush tapir
#

Can you try logging both the Payment Provider and Client secret just prior to rendering the form?

split flower
#

yes they are both there, without them i was getting another issue

turbid olive
#

I actively use paymentIntents in REact - I could show my (two) files, if you want...

#
export const PaymentEmbed = (props) => {
  const { fan } = props;

  const [options, setOptions] = useState(null);

  const [secret, setSecret] = useState(null);

  useEffect(() => {
    if (!secret) {
      (async () => {
        //this process INITIATES generation of a payment_secret
        const result = await capturePaymentMethod({ personId: fan.Id });
        result?.data && setSecret(result.data.payment_secret);
      })();
    } else {
      setOptions({
        // passing the client secret obtained in step 2
        clientSecret: secret,
        // Fully customizable with appearance API.
        appearance: {
          theme: PAYMENT_THEME
          /*...*/
        }
      });
    }
  }, [fan, secret]);

  const doConfirm = async (...args) => {
    return stripe.confirmSetup(...args);
  };

  return options ? (
    <Elements stripe={stripe} options={options}>
      <PaymentInput confirming={doConfirm} />
    </Elements>
  ) : (
    <SpinnerDiamond />
  );
};
#
export default function PaymentInput(props) {
  const { confirming } = props;
  const stripe = useStripe();
  const elements = useElements();

  const [error_message, set_error_message] = useState(null);
  const [showSpinner, setShowSpinner] = useState(true);

  const handleSubmit = async (event) => {
    // We don't want to let default form submission happen here,
    // which would refresh the page.
    event && event.preventDefault();
    if (!stripe || !elements) {
      // Stripe.js has not yet loaded.
      // Make sure to disable form submission until Stripe.js has loaded.
      return;
    }
    setShowSpinner(true);

    const result = await confirming({
      //`Elements` instance that was used to create the Payment Element
      elements,
      confirmParams: {
        return_url: window.location.href
      },
      redirect: `if_required`
    });

    if (result?.error) {
      switch (result.error.type) {
        case ERROR_TYPES.CARD_ERROR:
        case ERROR_TYPES.VALIDATION_ERROR:
          set_error_message(
            `${
              result.error.message_code
                ? "Code: " + result.error.message_code + " : "
                : ""
            }${result.error.message} Try re-submitting`
          );
          break;
        default:
          break;
      }
      // Show error to your customer (e.g., payment details incomplete)
      logger(result.error.message);
      setShowSpinner(false);
    }
    /**
     * if there is no error, the user record ("People") changes state,
     * and this entire component is removed.
     */
  };

  const handleReady = async (event) => {
    // We don't want to let default form submission happen here,
    // which would refresh the page.
    if (!stripe || !elements) {
      // Stripe.js has not yet loaded.
      // Make sure to disable form submission until Stripe.js has loaded.
      return;
    }

    setShowSpinner(false);
  };

...

#
  return (
    <form onSubmit={handleSubmit}>
      {showSpinner && <SpinnerDiamond />}
      <PaymentElement
        onReady={handleReady}
        options={{ business: { name: COMPANY_NAME } }}
      />
      <div>{error_message ? error_message : null}</div>
      <button
        className="button"
        type="submit"
        disabled={!stripe || showSpinner}
      >
        Submit
      </button>
    </form>
  );
}
split flower
#

interesting, yeah i am not doing anything different really, i see you are passing couple of props to PaymentElement, but i think those are optional

#

i am gonna try to see if i can listen to some events on paymentelement to see if i can figure out whats going on

turbid olive
#

well, the onready handler is important - it let's you know when the iFrame is rendered

#

also the issue of not rendering the payment iFrame until the client secret is ready - it does not respond to changes in the secret after it is mounted

#

(hence the first file)