Git Product home page Git Product logo

react-payment's Introduction

npm version

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

Component demo

CardForm

Blank CardForm

Invalid CardForm

BankForm

Valid BankForm

Invalid BankForm

PaymentMethods

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, default false
  • getZip: show the zip code input, default false
  • styles: override styles on the elements
  • defaultValues: 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 are name, 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 button
  • showBanks: whether to show the bank list & add button
  • cards: 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

http://localhost:9001

Deployment

npm version patch
npm publish
npm run deploy-storybook

Credits

react-payment's People

Contributors

jakeols avatar lorensr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

react-payment's Issues

Visa card formatting error

It's removing the last digit from a Visa card (Mastercard seems ok) number when jumping to another field. It happens if we type a number then leave the cc number field, but it works just fine if we copy paste a number without spaces. Maybe a bug related with the added spaces between numbers.

Modify submit button "ADD CARD" label?

Is it possible, and if not I suggest, to change the submit button ("ADD CARD") label?
I think a plain simple string property would do the job...

What do you think?

CardForm account number and exp date look broken

Trying to get this package up and running (it's just what I need!), but having a few issues.

If I just try to run the example (using "npm run storybook"), it launches the interface just fine. I then navigate to the CardForm example. Though entering text/numbers into most fields works fine, the "Account Number" and "MM / YY" fields don't work.

The account number field does not take any input, attempts to type anything are ignored.
The MM / YY field allows me to enter any number 2 - 9 (resulting in 02, 03, etc). Entries of 1 or 0 are ignored. Attempts to enter the year just replace the month value.

I've tried this using several versions of node (4 - 6). This behavior occurs in the example as well as when the package is included in my project.

Any ideas?

Dropping 4th number of each block in CC field

Issue can be seen in a few places:

  • If I enter 4, 8, or 12 numbers into the credit card field and then deselect, the 4th number gets chopped
  • If I enter 16 numbers and it's a valid CC, deselecting the field chops the 16th number (this does not happen if it's an invalid CC number)

This behavior can be seen in the demo: http://lorensr.me/react-payment/?selectedKind=CardForm&selectedStory=full&full=0&down=1&left=1&panelRight=0

I attempted to fix this, but I wasn't smart enough to figure it out in the time allowed. Pretty sure the issue has to do with jQuery ("payment" module) and React disagreeing about state. Possibly just a bug in the "payment" module itself.

I ended up going with a different solution, so no rush on this.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.