React components for payments:
<CardForm>
: credit card entry (with validation)<BankForm>
: bank account entry (with validation)<PaymentMethods>
: list of payment methods (with add / remove buttons)
You can configure/modify some things with props and CSS, and if you need to do any further customization, they're small filesโsend me a quick PR!
Demo
CardForm
BankForm
PaymentMethods
Usage
yarn add react-payment
Since this library uses Material-UI components, you need to have a Material-UI theme. To get the default style, just wrap this module's components in a <MuiThemeProvider>
tag (see the full example).
The alternate syntax for partial imports is react-payment/dist/ComponentName
:
import { CardForm } from 'react-payment';
OR
import CardForm from 'react-payment/dist/CardForm';
CardForm usage
<CardForm>
is a credit card form. By default it only has inputs for number, expiration, and CVC.
Props:
onSubmit(card => {})
getName
: show the name input, defaultfalse
getZip
: show the zip code input, defaultfalse
styles
: override styles on the elementsdefaultValues
: initial input values. Object of the form{ inputName: defaultString }
, and the input names are:name, number, expiration, cvc, zip
. Expiration is of the format"01/44"
for January 2044.
import { CardForm } from 'react-payment';
onSubmit: (card) => {
const { number, exp_month, exp_year, cvc, name, zip } = card;
Stripe.card.createToken({
number,
exp_month,
exp_year,
cvc,
name,
address_zip: zip
}, (status, response) => {
if (response.error) {
alert('Adding card failed with error: ' + response.error.message);
} else {
const cardToken = response.id;
// send cardToken to server to be saved under the current user
// show success message and navigate away from form
}
});
}
<CardForm
onSubmit={this.onSubmit}
getName={true}
getZip={true}
/>
BankForm usage
<BankForm>
is a form for entering US bank account information.
If you would like BankForm
to intelligently validate the account & routing number, make sure that Stripe.js is loaded (see the full example below).
Props:
onSubmit(account => {})
defaultValues
: initial input values. Object of the form{ inputName: defaultString }
, and the input names arename, accountNumber, routingNumber
.
import BankForm from 'react-payment';
onSubmit(account) {
const { name, accountNumber, routingNumber, accountType } = account;
const account_holder_type = accountType === 'personal' ? 'individual' : 'company';
Stripe.bankAccount.createToken({
country: 'US',
currency: 'USD',
routing_number: routingNumber,
account_number: accountNumber,
account_holder_name: name,
account_holder_type
}, (status, response) => {
if (response.error) {
alert('Adding bank account failed with error: ' + response.error.message);
} else {
const bankAccountToken = response.id;
// send bankAccountToken to server to be saved under the current user
// show success message and navigate away from form
}
});
}
<BankForm
onSubmit={this.onSubmit}
/>
PaymentMethods usage
<PaymentMethods>
is a list of your credit cards and/or bank accounts.
Props:
showCards
: whether to show the card list & add buttonshowBanks
: whether to show the bank list & add buttoncards
: array of cards, in the format{ id: '1', last4: '1234', brand: 'visa' }
banks
: array of banks, in the format{ id: '1', last4: '1234' }
onAddCard
onAddBank
onRemoveCard(id => {})
onRemoveBank(id => {})
import { PaymentMethods } from 'react-payment';
<PaymentMethods
showCards={true}
showBanks={false}
cards={[{ id: '1', last4: '1234', brand: 'visa' }]}
onAddCard={this.showCardFormDialog}
onRemoveCard={this.removeCard}
/>
Full example
import { CardForm, BankForm, PaymentMethods } from 'react-payment';
import React, { Component } from 'react'
import Dialog from 'material-ui/Dialog';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import server from './server';
let loadedStripe = false;
export default class PaymentExample extends Component {
state = {
dialogOpen: false
cardDialog: true
};
componentWillMount() {
if (loadedStripe) {
return;
}
const script = document.createElement("script");
script.src = "https://js.stripe.com/v2/";
script.type = "text/javascript";
script.async = true;
script.onload = () => {
Stripe.setPublishableKey('pk_test_6pRNASCoBOKtIshFeQd4XMUh');
};
document.body.appendChild(script);
loadedStripe = true;
}
openDialog = (type) => {
this.setState({
dialogOpen: true,
cardDialog: type === 'card' ? true : false
});
};
closeDialog = () => {
this.setState({dialogOpen: false});
};
removeCard = (id) => {
server.removeCard(id);
};
removeBank = (id) => {
server.removeBankAccount(id);
};
onSubmitCard = (card) => {
const { number, exp_month, exp_year, cvc, name, zip } = card;
Stripe.card.createToken({
number,
exp_month,
exp_year,
cvc,
name,
address_zip: zip
}, (status, response) => {
if (response.error) {
alert('Adding card failed with error: ' + response.error.message)
} else {
const cardToken = response.id;
server.saveCard(cardToken);
this.closeDialog();
// show success message
}
});
};
onSubmitBank = (account) => {
const { name, accountNumber, routingNumber, accountType } = account;
const account_holder_type = accountType === 'personal' ? 'individual' : 'company';
Stripe.bankAccount.createToken({
country: 'US',
currency: 'USD',
routing_number: routingNumber,
account_number: accountNumber,
account_holder_name: name,
account_holder_type
}, (status, response) => {
if (response.error) {
alert('Adding bank account failed with error: ' + response.error.message);
} else {
const bankAccountToken = response.id;
server.saveBankAccount(bankAccountToken);
this.closeDialog();
// show success message
}
})
};
render() {
const title = this.state.cardDialog ? 'Add credit card' : 'Add bank account';
return (
<MuiThemeProvider>
<PaymentMethods
showCards={true}
showBanks={true}
cards={[{ id: '1', last4: '1234', brand: 'visa' }]}
banks={[]}
onAddCard={() => this.openDialog('card')}
onAddBank={() => this.openDialog('bank')}
onRemoveCard={this.removeCard}
onRemoveBank={this.removeBank}
/>
<Dialog
title={title}
modal={false}
open={this.state.dialogOpen}
onRequestClose={this.closeDialog}
>
{
this.state.cardDialog ?
<CardForm
onSubmit={this.onSubmitCard}
getName={true}
getZip={true}
/>
:
<BankForm
onSubmit={this.onSubmitBank}
/>
}
</Dialog>
</MuiThemeProvider>
);
}
}
Development
git clone [email protected]:lorensr/react-payment.git
npm install
npm run storybook
Deployment
npm version patch
npm publish
npm run deploy-storybook
Credits
- Contributions by these fine folks
- Segmented control component from
segmented-control