Notwithstanding Previous Misdemeanors
    Wondering what’s next for npm?Check out our public roadmap! »

    react-stripe-terminal

    0.0.4 • Public • Published

    react-stripe-terminal

    React bindings for Stripe WebPOS SDK

    NPM JavaScript Style Guide Build Status Maintainability Test Coverage

    react-stripe-terminal manages synchronization of the Stripe Terminal POS device state and react component state. This allows you to easily write React applications with Stripe Terminal by using the stripeTerminal.* methods and rendering the stripeTerminal.payment, stripeTerminal.connection and stripeTerminal.discovery provided props.

    Note: This library isn't officially supported by Stripe.

    Install

    npm install --save react-stripe-terminal

    Usage

    Create a StripeTerminalProvider component at the top-most level of your react component hierarchy where your application needs to interface with Stripe Terminal. Use injectStripeTerminal to inject the stripeTerminal propery into your component's props.

    import React, { Component } from 'react';
    import {
        StripeTerminalProvider,
        injectStripeTerminal,
    } from 'react-stripe-terminal';
    class POSComponent extends Component {
        render() {
            const { stripeTerminal } = this.props;
            return (
                <div>
                    Discovered {stripeTerminal.discoveredReaders.length} Readers
                </div>
            );
        }
    }
    const MyPOSComponent = injectStripeTerminal(MyPOSComponent);
    class App extends Component {
        render() {
            return (
                <StripeTerminalProvider
                    onFetchConnectionToken={handleFetchConnectionToken}
                    onPaymentIntentRequest={handlePaymentIntentRequest}
                    taxRate={0.10}
                >
                    <MyPOSComponent />
                </StripeTerminalProvider>
            );
        }
    }

    In the example above, POSComponent is the original point-of-sale component. injectStripeTerminal returns a wrapped version of the component (MyPOSComponent) and when rendered will have the stripeTerminal property available for rendering and calling functions upon.

    The stripeTerminal prop

    When you call injectStripeTerminal Your component will be rendered with the stripeTerminal prop. This property will contain the up-to-date (read-only) state of the terminal device with the following structure:

    {
        stripeTerminal: {
            // the actual Stripe js Terminal SDK
            terminal: terminal
            payment: {
                lineItems: [{
     
                }],
                subtotal: 0,
                tax: 0,
                balanceDue: 0
            },
            connection: {
                status: 'disconnected'|'not_connected'|'connecting'|'connected',
                reader: null,
                connecting: false
            },
            discovery: {
                isDiscovering: false,
                discoveredReaders: []
            }
        }
    }

    Example: Connection View

    Below is a sample connection dialog component

    import React, { Component } from 'react';
    import { StripeTerminalProvider, injectStripeTerminal } from 'react-stripe-terminal';
     
    class App extends Component {
        render() {
            const { stripeTerminal } = this.props;
            return (
                <div
                    className="StripePOS"
                    style={{
                        margin: 'auto',
                        width: '30%',
                    }}
                >
                    <h1>Welcome to Stripe Terminal</h1>
                    <StripeTerminalProvider
                        currency={'usd'}
                        taxRate={0.11}
                        aonFetchConnectionToken={createPosActivationToken}
                        onRegisterReader={registerDevice}
                        onPaymentIntentRequest={createIntent}
                    >
                        {injectStripeTerminal(
                            <div>Readers</div>
                            {stripeTerminal.discovery.discoveredReaders.map(
                                reader => (
                                    <div key={reader.id}>
                                        <strong>{reader.label}</strong>
                                        <p>{reader.ip_address}</p>
                                        <p>
                                            Device: {reader.device_type}{' '}
                                            <i>({reader.status})</i>
                                        </p>
                                        <p>Device ID: {reader.id}</p>
                                        <p>Serial#: {reader.serial_number}</p>
                                        <button onClick={() =>                              stripeTerminal.connectReader()
                                        }>Connect</button>
                                    <div>
                                    <div>
                                        {stripeTerminal.error ?
                                            stripeTerminal.error.message : null}
                                    </div>
                                )
                            )}
     
                        )}
                    </StripeTerminalProvider>
                </div>
            );
        }
    }
     
    export default App;

    Binding to these properties can allow you to render a full POS application with mostly jsx and minimal application logic.

    Example: Checkout Basket

    After successful connection to a reader, you can render a checkout dialog. The CheckoutComponent example below has been rendered with the stripeTerminal prop:

    class CheckoutComponent extends Component {
        render() {
            const { stripeTerminal } = this.props;
            return (
                <div>
                    <h1>Checkout Basket</h1>
                    <div className="row">
                        {t.basketItems.map(item => (
                            <div className="list-item">
                                <p>Description:{item.description}</p>
                                <p>Price: ${item.unitPrice.toFixed(2)} each</p>
                                <p>Amount: ${item.totalPrice.toFixed(2)}</p>
                            </div>
                        ))}
                    </div>
                    <div className="row right">
                        <p>Sub Total: ${stripeTerminal.totals.total.toFixed(2)}</p>
                        <p>Tax: ${stripeTerminal.totals.tax.toFixed(2)}</p>
                        <p>Total: ${stripeTerminal.totals.balanceDue.toFixed(2)}</p>
                    </div>
                    <div className="row">
                        <div className="col s6">
                            <button
                                disabled={
                                    stripeTerminal.connectionStatus !== 'connected'
                                }
                                className="btn"
                                onClick={() =>
                                    stripeTerminal.addLineItem({
                                        description: 'Silver Hat',
                                        amount: 2000,
                                        quantity: 2,
                                    })
                                }
                            >
                                Add Item
                            </button>
                        </div>
                        <div className="col s6">
                            <button
                                disabled={
                                    stripeTerminal.connection.status !== 'connected'
                                }
                                className="btn"
                            >
                                Create ${stripeTerminal.payment.balanceDue} Charge
                            </button>
                        </div>
                        <h3>Device Status: {stripeTerminal.connection.status}</h3>
                        <h3>Payment Status: {stripeTerminal.payment.status}</h3>
                    </div>
                </div>
            );
        }
    }
     
    export default injectStripeTerminal(POSPayment);

    API Documentation

    StripeTerminalProvider

    The StripeTerminalProvider is a react context provider which can inject the stripeTerminal property into any child component of StripeTerminalProvider.

    Input Type Description
    onFetchConnectionToken() required function Corresponds to onFetchConnectionToken handler of StripeTerminal.create
    onPaymentIntentRequest(paymentIntentOptions) required function Takes a paymentIntentOptions specified by the paymentIntentOptions argument you pass to stripeTerminal.createPayment. Returns Promise which resolves with Payment Intent secret in the requires_source state.
    computeTaxAmount(lineItems) optional function Given the stripeTerminal.payment.lineItems array returns the tax amount for a transaction as a number. Overrides the taxRate input
    computeSubtotal(lineItems) optional function Given the lineItems array return the subtotal amount for a transaction and overrides default behavior of sum of line items.
    taxRate optional number The tax rate as a decimal to apply to the transaction. This will be applied to stripeTerminal.payment.subtotal
    lineItems optional Array Array of LineItems to render the reader display initially. Will be copied over to stripeTerminal.payment.lineItems. See the Line Items section for more details

    stripeTerminal

    Method Returns Description
    terminal N/A The actual terminal object returned from StripeTerminal.create. Use this when you need direct access to the Stripe Terminal JS SDK
    addLineItem(lineItem, quantity = 1) Promise that resolves when reader display is updated lineItem is similar to the object in the displayInfo.lineItems array but with a unique id field. See the Line Items section. Decrements the lineItem.quantity by quantity if a line item of the id is passed.
    removeLineItem(lineItem, quantity = 1) Promise that resolves when reader display is updated with line item removal. lineItem is similar to the object in the displayInfo.lineItems array but with a unique id field. See the Line Items section. Decrements the lineItem.quantity by quantity if a line item of the id is passed.
    getLineItem(id) LineItem Returns the lineItem in the stripeTerminal managed state or null
    connectReader(reader) Promise resolving to a result as specified by the Stripe Terminal Docs Wraps terminal.connectReader and updates stripeTerminal.connection. Use stripeTerminal.discoverReaders or stripeTerminal.startDiscoverReaders to get a list of readers.
    disconnectReader() Promise that resolves after disconnection Wraps terminal.disconnectReader() and updates stripeTerminal.connection.status state
    clearPayment() Promise that resolves when reader state is cleared and stripeTerminal.payment.lineItems is cleared Wraps terminal.clearReaderDisplay and clears the stripeTerminal.payment.lineItems array
    discoverReaders(discoveryOptions) Promise resolving to a list of Readers Wraps terminal.discoverReaders and updates stripeTerminal.discoveredReaders state with the list of discovered readers. discoveryOptions is the same object passed to terminal.discoverReaders
    startDiscovery(discoveryOptions) undefined Wraps terminal.startDiscovery and continuously updates the stripeTerminal.discoveredReaders property.
    stopDiscovery(discoveryOptions) undefined Wraps terminal.stopDiscovery
    createPayment({paymentIntentOptions = {}}) Promise that resolves when a Payment is collected Calls onPaymentIntentRequest(paymentIntentOptions) and expects a Promise that resolves with payment_intent.client_secret. Then calls terminal.collectPaymentMethod and then terminal.confirmPaymentIntent. Updates stripeTerminal.payment.status throughout the process.
    cancelCreatePayment Promise resolving if the payment was successfully cancelled or rejecting if the payment could not be cancelled. Wraps terminal.cancelCollectPayment

    Line Items

    Line items on the reader display and stripeTerminal.payment.lineItems can be easily synchronized through the addLineItem and removeLineItem methods:

    stripeTerminal.addLineItem({
        {
            description: 'Silver Hat ',
            amount: 100,
            quantity: 2,
        }
    })
    stripeTerminal.addLineItem({
        {
            description: 'Silver Hat ',
            amount: 100,
            quantity: 2,
        }
    })
    //.. render updates
    console.log(stripeTerminal.payment)

    The above statements would result in the payment sub-hash to be rendered as:

    {
        lineItems: [{
            id: 'ab3e-fe93-afe3-943e'
            description: 'Silver Hat ',
            amount: 100,
            quantity: 4,
        }],
        tax: 40,
        balanceDue: 440
    }

    This ensures consistent rendering of order items in the reader display and your react application.

    Running the Example Application

    The demo application included is a simple application to demonstrate how to integrate this component into your react application.

    # Clone this repo
    git clone https://github.com/sedouard/react-stripe-terminal.git
    # Install yarn if you don't already have it
    npm i -g yarn
    yarn install
    cd ./example
    yarn install
    yarn start
    

    Development

    # Fork this repo
    git clone https://github.com/<your-user-name>/react-stripe-terminal.git
    # Install yarn if you don't already have it
    npm i -g yarn
    yarn install
    

    Running Tests

    yarn test
    

    License

    MIT © sedouard

    Install

    npm i react-stripe-terminal

    DownloadsWeekly Downloads

    6

    Version

    0.0.4

    License

    MIT

    Unpacked Size

    792 kB

    Total Files

    6

    Last publish

    Collaborators

    • avatar