Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
341 views
in Technique[技术] by (71.8m points)

reactjs - How to submit Stripe Payment in a Formik Wizard, using React Elements?

I'm creating a multi-step form in React using Formik and a stepper from Material-UI. That part is working (finally!) and I mostly understand how. Step 1 is a billing address, Step 2 is choosing a subscription plan, and Step 3 is payments using Stripe and their CardElements. This is where I fall off track.

I load Stripe high up in the app, so it's wrapped and available to my form. All good. I can successfully call Stripe methods when testing individually.

My Formik outer layer is here:

<Formik
    {...props}
    validationSchema={currentChild.props.validationSchema}
    onSubmit={async (values, helpers) => {
      if (isLastStep()) {
        await props.onSubmit(values, helpers);
        setCompleted(true);
      } else {
        setStep((s) => s + 1);
        helpers.setTouched({});
        if (step === 1) {
          await props.getCustomerId(values.billingEmail);
        }
      }
    }}
  >
  {... map over the steps, then the Back/Next/Submit buttons}
  </Formik>

At the formStepper creation, I call on useStripe() and useElements() and create a CardElement which gets passed into Step 3:

    const stripe = useStripe();
      const elements = useElements();
      let stripeCard = CardElement;
    
    <FormikStepper
                    initialValues={{ ...billingValues }}
                    onSubmit={(values, helpers) => {
                      createCustomer(values); //successfully sends formValues to be processed
                    }}
                    // I tried adding this here, but it isn't accessible inside the steps
// ETA: I put stripeProps inside the FormikStepper, which passes its properties down to the FormikStep inside. For non-Formik users, this works for the onBlur, onFocus, etc. as well as passing the initialValues.  Basically, I was hoping the card element could hitch a ride
                    stripeProps={{ card: stripeCard }}
                    getCustomerId={async (billingEmail) => {
                      await fetchCustomerId(billingEmail);
                    }}
                  >
                    <FormikStep
                      label="Billing Info"
                      validationSchema={object({ ...validationSchemaUsingYup })}
                    >
                      <Grid container item spacing={1}>
                        <CompanyProfile />
                      </Grid>
                    </FormikStep>
        
                    <FormikStep label="Choose Subscription">
                      <Grid container item spacing={1}>
                        <ChooseSubscription />
                      </Grid>
                    </FormikStep>
        
                    <FormikStep label="Review & Pay">
                      <Grid container item spacing={1}>
                        <StripePayment card={stripeCard} />
                      </Grid>
                    </FormikStep>
                  </FormikStepper>

Inside Step 3 I can render and use the CardElement as expected with this:

<props.card
    options={{
      style: {...styling}
    }}
  />

My confusion is in how to access this element in order to submit the data to Stripe?? How to I access the props that I passed into Step 3 and use that to process payment?
I tried putting the Stripe functions inside the function of Step 3, but they never got called, as the onSubmit functions are on the Parent of the step. I can't put the card number into the Formik initialValues without ruining the security aspect of using Stripe Elements. The closest I can get to anything is this error:

Warning: An unhandled error was caught from submitForm() IntegrationError: A valid Element name must be provided. Valid Elements are:
  card, cardNumber, cardExpiry, cardCvc, postalCode, paymentRequestButton, iban, idealBank, p24Bank, auBankAccount, fpxBank; you passed: object.

Updates in response to comments: The stripeProps was a failed attempt to package info into FormikStepper, which passes props down to the children, FormikStep. The onSubmit calls createPaymentMethod, below:

    async function createPaymentMethod(
    values,
    stripeData = stripeCard,
    customer = customerId
  ) {
    if (customer === undefined) {
      customer = fetchCustomerId(values.billingEmail);
    }

    return stripe
      .createPaymentMethod({
        type: "card",
        card: elements.getElement(stripeData), //no errors with CardElement, but not sure that's the SAME element from the form
      })
      .then((result) => {
        if (result.error) {
          console.log(result.error);
        } else {
          createSubscription({
            customer: customer,
            paymentMethodId: result.paymentMethod.id,
            items: [
              {
                price: values.TCPlan,
                quantity: values.TCPlanQuantity,
              },
            ],
          });
        }
      })
      .catch((err) => console.log(err));
  }

  // Step 2 of the Stripe process;
  // Called if createPaymentMethod is error-free
  function createSubscription({ customer, paymentMethodId, items }) {
    console.log(customer, paymentMethodId, items);
    let created = fetch(
      "https://xxxxxx.amazonaws.com/xxx/xxxx", // My API Gateway endpoint
      {
        method: "post",
        headers: {
          "Content-type": "application/json",
        },
        body: JSON.stringify({
          customerId: customer,
          paymentMethodId: paymentMethodId,
          priceId: items,
        }),
      }
    );

    created
      .then((response) => {
        console.log(response.json());
      })
      // various error-handling offered by Stripe...
  }
question from:https://stackoverflow.com/questions/65836392/how-to-submit-stripe-payment-in-a-formik-wizard-using-react-elements

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...