LoF10
LoF10

Reputation: 2127

React Stripe - how do I save credit card information?

I am attempting to save credit card information using stripe and react with a node backend. I am using the react-stripe-js library since that is recommended to securely send PII data. I have set up a basic node api that creates a customer and now I want to setup Intents since according to stripe docs that's the best way to save card data for later use. But I am unsure how to send the inputs to the api. How could I modify the code below to setup an intent?

node.js

 ...
    //CREATE CUSTOMER ACCOUNT
    app.post("/makeCustomer", cors(), async (req, res) => {
        let data = {
            name: req.body.name,
            email: req.body.email
        };
        try {
            const customer = await stripe.customers.create({
                name: data.name,
                email: data.email
            });
            res.send(customer);
        } catch (error) {
            console.log(err);
            res.status(400)
            res.send({ error: err })
            return;
        }
    });
    
    //CREATE SETUP INTENT
    app.post("/makeIntent", cors(), async (req, res) => {
        try {
            const intent = await stripe.setupIntents.create({
                payment_method_types: ['card'],
                customer: customer.id
            });
            res.send(intent.client_secret );
        } catch (err) {
            console.log(err);
            res.status(400)
            res.send({ error: err })
            return;
        }
    });

Buyer.js

import React, { Component } from 'react';
import { Button, Container, Col, Row, Tabs, Tab, Form } from 'react-bootstrap';
import 'bootstrap/dist/css/bootstrap.min.css';
//import StripeCheckout from "react-stripe-checkout";
import { Elements, ElementsConsumer } from '@stripe/react-stripe-js';
import { loadStripe } from '@stripe/stripe-js';
import SaveCardForm from './SaveCardForm';

const stripePromise = loadStripe('pk_test_51HhkvNBmZZhLkiuRzN5UwsSHQQbK9y1CALJpr3l23aT7bauIx1JzCdkKlVx26FrtFkFE8QtAUZctcuUtBhRxcqti00grkBypzH');

const InjectedSaveCardForm = () => (
    <ElementsConsumer>
        {({ stripe, elements }) => (
            <SaveCardForm stripe={stripe} elements={elements} />
        )}
    </ElementsConsumer>
);


class Buyer extends Component {
    constructor() {
        super();
        this.state = {
            customerId: 'cus_INAnHdJRHAFgnG'
        }
    }

    render() {
        return (
            <Container>
                <h5 style={{ textAlign: 'center' }}>
                    As a buyer, place your information below and purchase your meal.
                </h5>
                <Tabs
                    id="controlled-tab-example"
                >
                    <Tab eventKey="creditCart" title="Credit Card">
                        <br />
                        <h5>Enter card details below:</h5>
                        <br />

                        <Row>
                            <Col>
                                <Button onClick={this.props.makeCustomer}>
                                    Create Customer
                        </Button>
                            </Col>
                            <Col>
                                <Button onClick={this.props.deleteCustomer}>
                                    Delete Customer
                        </Button>
                            </Col>
                            <Col></Col>
                        </Row>
                        <br/>
                        <Row>
                            {/**SAVE CARD HERE */}
                            <Col>
                            <Elements stripe={stripePromise}>
                                <InjectedSaveCardForm />
                            </Elements>
                            </Col>
                        </Row>
                    </Tab>
                    <Tab eventKey="ApplePay" title="Apple Pay">
                        bye
                    </Tab>
                    <Tab eventKey="AndroidPay" title="Android Pay">
                        sup
                    </Tab>
                </Tabs>
            </Container>
        );
    }
}

export default Buyer;

SaveCardForm.js

import React, { Component } from "react";
import { Stripe, CardElement, injectStripe, Elements, ElementsConsumer } from "@stripe/react-stripe-js";
import {loadStripe} from '@stripe/stripe-js';

class SaveCardForm extends Component {
    handleSubmit = async (event) => {
      event.preventDefault();
      const {stripe, elements} = this.props;
      const {error, paymentMethod} = await stripe.createPaymentMethod({
        type: 'card',
        card: elements.getElement(CardElement),
      });
    };
  
    render() {
      const {stripe} = this.props;
      return (
        <form onSubmit={this.handleSubmit}>
          <CardElement />
          <button type="submit" disabled={!stripe}>
            Save Card Data
          </button>
        </form>
      );
    }
  }

export default SaveCardForm;

Upvotes: 3

Views: 7190

Answers (1)

hmunoz
hmunoz

Reputation: 3361

I'm not a React expert but it looks like you're calling createPaymentMethod() from Stripe.js here, which isn't what you need to do.

Instead, on handleSubmit() you need to call confirmCardSetup(), and pass in 2 things:

  • The SetupIntent client_secret
  • The card Element

as shown here: https://stripe.com/docs/payments/save-and-reuse#confirm-the-setupintent

If the SetupIntent was created with a Customer specified (which yours is), then on successful confirmation of the SetupIntent, the newly tokenized card PaymentMethod will auto-attach to that Customer.

Upvotes: 2

Related Questions