Braintree
Javascript
9 February 2022
Learn to implement braintree with JavaScript and NodeJs.
CDN
    
    <!-- Braintree -->
    <script src="https://js.braintreegateway.com/web/3.85.2/js/client.min.js"></script>
    <script src='https://js.braintreegateway.com/web/3.85.2/js/three-d-secure.min.js'></script>
    <script src="https://js.braintreegateway.com/web/3.85.2/js/hosted-fields.min.js"></script>
    <script src="https://js.braintreegateway.com/web/3.85.2/js/paypal-checkout.min.js"></script>
    <!-- Braintree --&#x3E;
HTML
    <div class="form-container pt-4">
        <div class="payment-btns mt-4">
            <div class="payment-card payment-btns-item active" data-type="card"><span class="iconify" data-icon="grommet-icons:mastercard"></span></div>
            <div class="payment-paypal payment-btns-item" data-type="paypal"><span class="iconify" data-icon="logos:paypal"></span></div>
        </div>
    
        <div class="subs-plans"></div>
    
        <div class="c-card payment-method active">
            <form id="hosted-fields-form" method="post">
                <div class="row">
                    <div class="col-md-12">
                        <div class="form-group">
                            <label for="card-number">Card Number</label>
                            <div class="form-control" id="card-number"></div>
                            <small class="error"></small>
                        </div>
                    </div>
            
                    <div class="col-sm-6">
                        <div class="form-group">
                            <label for="expiration-date">Expiration Date</label>
                            <div class="form-control" id="expiration-date"></div>
                            <small class="error"></small>
                        </div>
                    </div>
                
                    <div class="col-sm-6">
                        <div class="form-group">
                            <label for="cvv">CVV</label>
                            <div class="form-control" id="cvv"></div>
                            <small class="error"></small>
                        </div>
                    </div>
                    
            
                    <div class="col-md-12">
                        <input type="submit" value="Pay" disabled />
                    </div>
                
                </div>
              </form>
        </div>
    
        <div class="paypal payment-method d-none">
            <div class="mt-2" id="paypal-button"></div>
        </div>
    </div>
CSS
    .payment-method {
        width: 500px;
    }
    
    #hosted-fields-form{
        padding: 10px;
        background-color: rgb(233, 234, 235);
        width: 100%;
        height: fit-content;
    }
    
    .form-control {
        height: 50px;
    }
    
    main {
        display: flex;
        justify-content: center;
    }
    
    .error {
        display: none;
    }
    
    .error.active {
        display: block;
    }
    
    .subs-plans {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin: 20px 0;
    }
    
    .subs-plans-items {
        background-color: rgb(233, 234, 235);
        width: 32%;
        height: 70px;
        display: flex;
        justify-content: center;
        align-items: center;
        flex-direction: column;
        cursor: pointer;
    }
    
    .subs-plans-items.active {
        background-color: #D9000D;
        color: #FFFFFF;
        font-weight: bold;
    }
    
    .payment-btns {
        display: flex;
        justify-content: space-between;
        align-items: center;
        height: 60px;
    }
    .payment-card, .payment-paypal, .payment-subscription, .payment-sales  {
        width: 49%;
        height: 100%;
        cursor: pointer;
        background-color: #ddd;
        display: flex;
        justify-content: center;
        align-items: center;
        font-size: 18px;
    }
    
    .payment-btns-item.active {
        background-color: #D9000D;
        color: #FFFFFF;
        font-weight: bold;
    }
    
    .payment-btns-item .iconify {
        width: 30px;
        height: 30px;
    }
    
    .payment-option-item.active {
        background-color: #D9000D;
        color: #FFFFFF;
        font-weight: bold;
    }
    
    .payment-option-item .iconify {
        width: 30px;
        height: 30px;
    }
JavaScript
    var form = document.querySelector('#hosted-fields-form');
    var submit = document.querySelector('input[type="submit"]');
    var threeDSecure;
    
    var subsPlans = [
        {
            name: "3 Months",
            id: "3_months",
            amount: 50
        },
        {
            name: "6 Months",
            id: "6_months",
            amount: 100
        },
        {
            name: "12 Months",
            id: "12_months",
            amount: 150
        }
    ];
    
    $('.subs-plans').html(
        subsPlans.map(plan => {
            return `
            <div class="subs-plans-items" data-id="${plan.id}" data-amount="${plan.amount}">
                ${plan.name}
                <span>${plan.amount}</span>
            </div>`
        })
    )
    
    $('.subs-plans-items').first().addClass('active');
    
    braintree.client.create({
        // Insert your tokenization key here
        authorization: "YOUR_TOKEN_GENERATED_WITH_BRAINTREE_ACCOUNT"
    }, function (clientErr, clientInstance) {
        if (clientErr) {
            console.error(clientErr);
            return;
        }
    
        // initialize 3d secure
        braintree.threeDSecure.create({
            version: 2,
            client: clientInstance
        }, function(threeDSecureErr, threeDSecureInstance) {
            if (threeDSecureErr) {
                if (threeDSecureErr) console.error(threeDSecureErr);
                // Handle error in 3D Secure component creation
                return;
              }
          
            threeDSecure = threeDSecureInstance;
        })
    
        // Create a hostedFields component to initialize the form
        braintree.hostedFields.create({
        client: clientInstance,
        // Customize the Hosted Fields.
        styles: {
            'input': {
                'font-size': '14px'
            },
            'input.invalid': {
                'color': 'red'
            },
            'input.valid': {
                'color': 'green'
            }
        },
        // Configure which fields in your card form will be generated by Hosted Fields instead
        fields: {
            number: {
                container: '#card-number',
                placeholder: '4111 1111 1111 1111'
            },
            expirationDate: {
                container: '#expiration-date',
                placeholder: '10/22'
            },
            cvv: {
                container: '#cvv',
                placeholder: '123'
            },
        }
        }, function (hostedFieldsErr, instance) {
        if (hostedFieldsErr) {
            console.error(hostedFieldsErr);
            return;
        }
    
        // Once the fields are initialized enable the submit button
        submit.removeAttribute('disabled');
    
        instance.on('validityChange', function(event) { // calls change of input values
            var field = event.fields[event.emittedBy];
            var errContainer = $(field.container).siblings('.error');
            var type = field.container.id;
    
            $(field.container).siblings('.error').addClass('active');
            $(field.container).siblings('.error').text('Working');
    
            validateInput(type, field, errContainer); // check validation call
        })
    
        function validateInput(type, field, errContainer) { // check validation
            if(field.isEmpty) {
                errContainer.addClass('active');
                switch (type) {
                    case "card-number":
                        errContainer.text("Card number is required");
                        break;
    
                    case "expiration-date":
                        errContainer.text("Expiration date  is required");
                        break;
    
                    case "cvv":
                        errContainer.text("CVV  is required");
                        break;
                
                    default:
                        break;
                }
            }
            else if(!field.isValid) {
                errContainer.addClass('active');
                switch (type) {
                    case "card-number":
                        errContainer.text("Card number is invalid, please enter valid card number");
                        break;
    
                    case "expiration-date":
                        errContainer.text("Expiration date is invalid");
                        break;
    
                    case "cvv":
                        errContainer.text("CVV  is invalid");
                        break;
                
                    default:
                        break;
                }
            }
            else {
                errContainer.removeClass('active');
            }
        }
    
        // Initialize the form submit event
        form.addEventListener('submit', function (event) {
            event.preventDefault();
    
            var state = instance.getState();
            var formValid = Object.keys(state.fields).every(function (key) {
                return state.fields[key].isValid;
            });
    
            if (formValid) {
                $('.error').removeClass('active');
    
                showLoading('Please wait', 'We are making your payment.');
    
                // Tokenize Hosted Fields
                instance.tokenize((error, payload) => {
                    if (error) console.error(error);
    
                    threeDSecure.verifyCard({
                        nonce: payload.nonce,
                        bill: payload.details.bin,
                        amount: $('.subs-plans-items.active').data('amount'),
                        onLookupComplete: function (data, next) {
                            // use `data` here, then call `next()`
                            next();
                        }
                        
                    }, function(verifyError, payload) {
                        if (verifyError) {
                            console.error(verifyError);
                            updateLoading(false, 'Server internal error!', 'Please try again in sometime.');
                            hideLoading();
                        }
                        else {
                            porcessPayment(payload.nonce);
                        }
                    })
                });
                } else {
                    Object.keys(state.fields).map((key, i) => {
                        var field = state.fields[key];
                        var type = field.container.id;
                        var errContainer = $(field.container).siblings('.error');
                        validateInput(type, field, errContainer); // check validation call
                    })
                }
                
            }, false);
        });
    });
    
    // Create a PayPal Checkout component
    // Create a client.
    braintree.client.create({
        authorization: token
    }, function (clientErr, clientInstance) {
    
        // Stop if there was a problem creating the client.
        // This could happen if there is a network error or if the authorization
        // is invalid.
        if (clientErr) {
            console.error('Error creating client:', clientErr);
            return;
        }
    
        // Create a PayPal Checkout component.
        braintree.paypalCheckout.create({
            client: clientInstance
        }, function (paypalCheckoutErr, paypalCheckoutInstance) {
                paypalCheckoutInstance.loadPayPalSDK({
                vault: true
            }, function () {
                if(paypalCheckoutErr) {
                    console.log('paypalCheckoutErr: ', paypalCheckoutErr);
                }
                paypal.Buttons({
                    createBillingAgreement: function () {
                    return paypalCheckoutInstance.createPayment({
                        flow: 'vault', // Required
                    });
                    },
    
                    onApprove: function (data, actions) {
                        data.vault = false;
    
                        showLoading('Please wait', 'We are making your payment.');
    
                        return paypalCheckoutInstance.tokenizePayment(data, function (err, payload) {
                            // Submit `payload.nonce` to your server
    
                            porcessPayment(payload.nonce);
                        });
                    },
    
                    onCancel: function (data) {
                        console.log('PayPal payment canceled', JSON.stringify(data, 0, 2));
                    },
    
                    onError: function (err) {
                        console.error('PayPal error', err);
                    }
                }).render('#paypal-button').then(function () {});
            });
        });
    });
    
    function porcessPayment(nonce) {
        console.log('nonce: ', nonce, ' planId: ', $('.subs-plans-items.active').data('id'), ' amount: ', $('.subs-plans-items.active').data('amount'));
        $.ajax({
            type: "POST",
            url: "/checkout",
            data: {nonce: nonce, plan_id: $('.subs-plans-items.active').data('id')},
            dataType: "json",
            success: function(data) {
                console.log('success: ', data);
                updateLoading(data.status, 'Success', data.msg);
                hideLoading();
            },
            error: function(err) {
                console.log('err: ', err);
            }
        })
    }
    
    $('.subs-plans-items').on('click', function() {
        $('.subs-plans-items').removeClass('active');
        $(this).addClass('active');
    })
    
    $('.payment-btns-item').on('click', function() {
        $('.payment-btns-item').removeClass('active');
        $(this).addClass('active');
    
        var type = $(this).data('type');
    
        if(type == "card") {
            $('.c-card').removeClass('d-none');
            $('.paypal').addClass('d-none');
        }
    
        if(type == "paypal") {
            $('.c-card').addClass('d-none');
            $('.paypal').removeClass('d-none');
        }
    })
NodeJs
Braintree initilization
    const braintree = require("braintree");

    const gateway = new braintree.BraintreeGateway({
        environment: braintree.Environment.Sandbox,
        merchantId: "YOUR_MERCHAND_ID",
        publicKey: "YOUR_PUBLIC_KEY",
        privateKey: "YOUR_PRIVATE_KEY"
    });
Send client token to client while rendering the page
    gateway.clientToken.generate({}, (err, response) => {
        var token = response.clientToken;
        res.render('pages/index', { title: 'Home', token: token });
    });
Create customer and subscription with checkout
    exports.checkout = (req, res, next) => {
        var nonce = req.body.nonce;
        var plan = req.body.plan_id;
    
        gateway.customer.create({
            paymentMethodNonce: nonce
        }, function (err, result) {
            if (result.success) {
                var token = result.customer.paymentMethods[0].token;
                
                gateway.subscription.create({
                    paymentMethodToken: token,
                    planId: plan
                }, function (err, result) {
                    if(err){
                        console.log(err)
                    }
                    console.log('subscription-result', result);
                    res.send({
                        result: result,
                        msg: "Payment made successfully.",
                        status: true
                     });
                });
            }
        });
    };
Comments
Leave a Comment
Your email address will not be published.