braintree-sandboxbraintree-javascript

Getting credit card brand and show error message when using hosted fields in Braintree


I am trying to create payment page using braintree's hosted fields. I have created sandbox account.

But i am not getting additional details like Card brand, error message like Drop in UI. How to get those functionalities using Hosted fields.

import React from 'react';

var braintree = require('braintree-web');


class BillingComponent extends React.Component {
    constructor(props) {
        super(props);
        this.clientDidCreate = this.clientDidCreate.bind(this);
        this.hostedFieldsDidCreate = this.hostedFieldsDidCreate.bind(this);
        this.submitHandler = this.submitHandler.bind(this);
        this.showPaymentPage = this.showPaymentPage.bind(this);
        this.state = {
            hostedFields: null,
            errorOccurred: false,
        };
    }

    componentDidCatch(error, info) {
        this.setState({errorOccurred: true});
    }


    componentDidMount() {
        this.showPaymentPage();
    }

    showPaymentPage() {
        braintree.client.create({
            authorization: 'sandbox_xxxxx_xxxxxxx'
        }, this.clientDidCreate);
    }


    clientDidCreate(err, client) {
        braintree.hostedFields.create({
            onFieldEvent: function (event) {console.log(JSON.stringify(event))},
            client: client,
            styles: {
                'input': {
                    'font-size': '16pt',
                    'color': '#020202'
                },

                '.number': {
                    'font-family': 'monospace'
                },

                '.valid': {
                    'color': 'green'
                }
            },
            fields: {
                number: {
                    selector: '#card-number',
                    'card-brand-id': true,
                    supportedCardBrands: 'visa'
                },
                cvv: {
                    selector: '#cvv',
                    type: 'password'
                },
                expirationDate: {
                    selector: '#expiration-date',
                    prefill: "12/21"
                }
            }
        }, this.hostedFieldsDidCreate);
    }

    hostedFieldsDidCreate(err, hostedFields) {
        let submitBtn = document.getElementById('my-submit');
        this.setState({hostedFields: hostedFields});
        submitBtn.addEventListener('click', this.submitHandler);
        submitBtn.removeAttribute('disabled');
    }

    submitHandler(event) {
        let submitBtn = document.getElementById('my-submit');

        event.preventDefault();
        submitBtn.setAttribute('disabled', 'disabled');

        this.state.hostedFields.tokenize(
            function (err, payload) {
            if (err) {
                submitBtn.removeAttribute('disabled');
                console.error(err);
            }
            else {
                let form = document.getElementById('my-sample-form');
                form['payment_method_nonce'].value = payload.nonce;
                alert(payload.nonce);
                // form.submit();
            }
        });
    }

    render() {
        return (
            <div className="user-prelogin">
                <div className="row gutter-reset">
                    <div className="col">
                        <div className="prelogin-container">
                            <form action="/" id="my-sample-form">
                                <input type="hidden" name="payment_method_nonce"/>
                                <label htmlFor="card-number">Card Number</label>
                                <div className="form-control" id="card-number"></div>

                                <label htmlFor="cvv">CVV</label>
                                <div className="form-control" id="cvv"></div>

                                <label htmlFor="expiration-date">Expiration Date</label>
                                <div className="form-control" id="expiration-date"></div>
                                <input id="my-submit" type="submit" value="Pay" disabled/>

                            </form>
                        </div>
                    </div>
                </div>
            </div>

        );
    }
}

export default BillingComponent;

I am able to get basic functionalities like getting nonce from card details. But i am unable to display card brand image/error message in the page as we show in Drop in UI.

How to show card brand image and error message using hosted fields?

Page created using Hosted fields: Page using hosted fields

Page created Drop in UI - Which shows error message Drop in UI - error message

Page created Drop in UI - Which shows card brand Drop in UI Card brands


Solution

  • Though we do not get exact UI like Drop in UI, we can get the card type and display it ourselves by using listeners on cardTypeChange.

    hostedFieldsDidCreate(err, hostedFields) {
        this.setState({hostedFields: hostedFields});
        if (hostedFields !== undefined) {
            hostedFields.on('cardTypeChange', this.cardTypeProcessor);
            hostedFields.on('validityChange', this.cardValidator);
        }
    
        this.setState({load: false});
    }
    
    
    cardTypeProcessor(event) {
        if (event.cards.length === 1) {
            const cardType = event.cards[0].type;
            this.setState({cardType: cardType});
        } else {
            this.setState({cardType: null});
        }
    }
    
    cardValidator(event) {
        const fieldName = event.emittedBy;
        let field = event.fields[fieldName];
        let validCard = this.state.validCard;
    
        // Remove any previously applied error or warning classes
        $(field.container).removeClass('is-valid');
        $(field.container).removeClass('is-invalid');
    
        if (field.isValid) {
            validCard[fieldName] = true;
            $(field.container).addClass('is-valid');
        } else if (field.isPotentiallyValid) {
            // skip adding classes if the field is
            // not valid, but is potentially valid
        } else {
            $(field.container).addClass('is-invalid');
            validCard[fieldName] = false;
        }
    
        this.setState({validCard: validCard});
    }
    

    Got the following response from braintree support team.

    Hosted fields styling can be found in our developer documentation. Regarding the logos, you can download them from the card types official websites -

    1. Mastercard
    2. Visa
    3. AMEX
    4. Discover
    5. JCB

    Or online from other vendors.

    Note: Drop-In UI will automatically fetch the brand logos and provide validation errors unlike hosted fields as it is less customizable.