3

I want to replicate a braintree demo app using ionic 3.

I have imported braintree with... import * as braintree from 'braintree';

but I am not able to connect to braintree.

The message reads... "Runtime Error: Class extends value [object Object] is not a constructor or null"

This is the code in my ts file

import { Component } from '@angular/core';
import { IonicPage, NavController, NavParams, ViewController } from 'ionic-angular';

import * as braintree from 'braintree';

@IonicPage()
@Component({
  selector: 'page-apply',
  templateUrl: 'apply.html',
})

export class ApplyPage {

  gateway: any;

  constructor(public navCtrl: NavController, public navParams: NavParams, public viewCtrl: ViewController) {
    this.gateway = braintree.connect({
      environment:  braintree.Environment.Sandbox,
      merchantId:   'personalMerchantId',
      publicKey:    'personalPublicKey',
      privateKey:   'personalPrivateKey'
    });
  }

  ionViewDidLoad() {
    console.log('ionViewDidLoad ApplyPage');
  }


}

This is the code within the index.js file of the module

'use strict';

module.exports = require('./lib/braintree');

And this code sits in the braintree.js file of which index.js points to

'use strict';

let version = require('../package.json').version;
let Config = require('./braintree/config').Config;
let Environment = require('./braintree/environment').Environment;
let BraintreeGateway = require('./braintree/braintree_gateway').BraintreeGateway;
let errorTypes = require('./braintree/error_types').errorTypes;

let Transaction = require('./braintree/transaction').Transaction;

let CreditCard = require('./braintree/credit_card').CreditCard;
let PayPalAccount = require('./braintree/paypal_account').PayPalAccount;
let AndroidPayCard = require('./braintree/android_pay_card').AndroidPayCard;
let ApplePayCard = require('./braintree/apple_pay_card').ApplePayCard;
let VenmoAccount = require('./braintree/venmo_account').VenmoAccount;
let CoinbaseAccount = require('./braintree/coinbase_account').CoinbaseAccount;
let AmexExpressCheckoutCard = require('./braintree/amex_express_checkout_card').AmexExpressCheckoutCard;
let VisaCheckoutCard = require('./braintree/visa_checkout_card').VisaCheckoutCard;
let MasterpassCard = require('./braintree/masterpass_card').MasterpassCard;

let CreditCardVerification = require('./braintree/credit_card_verification').CreditCardVerification;
let Subscription = require('./braintree/subscription').Subscription;
let MerchantAccount = require('./braintree/merchant_account').MerchantAccount;
let PaymentInstrumentTypes = require('./braintree/payment_instrument_types').PaymentInstrumentTypes;
let WebhookNotification = require('./braintree/webhook_notification').WebhookNotification;
let TestingGateway = require('./braintree/testing_gateway').TestingGateway;
let ValidationErrorCodes = require('./braintree/validation_error_codes').ValidationErrorCodes;

let CreditCardDefaults = require('./braintree/test/credit_card_defaults').CreditCardDefaults;
let CreditCardNumbers = require('./braintree/test/credit_card_numbers').CreditCardNumbers;
let MerchantAccountTest = require('./braintree/test/merchant_account').MerchantAccountTest;
let Nonces = require('./braintree/test/nonces').Nonces;
let TransactionAmounts = require('./braintree/test/transaction_amounts').TransactionAmounts;

let connect = config => new BraintreeGateway(new Config(config)); // eslint-disable-line func-style
let Test = {
  CreditCardDefaults: CreditCardDefaults,
  CreditCardNumbers: CreditCardNumbers,
  MerchantAccountTest: MerchantAccountTest,
  Nonces: Nonces,
  TransactionAmounts: TransactionAmounts
};

module.exports = {
  connect: connect,
  version: version,
  Environment: Environment,
  errorTypes: errorTypes,

  Transaction: Transaction,

  CreditCard: CreditCard,
  PayPalAccount: PayPalAccount,
  AndroidPayCard: AndroidPayCard,
  ApplePayCard: ApplePayCard,
  VenmoAccount: VenmoAccount,
  CoinbaseAccount: CoinbaseAccount,
  AmexExpressCheckoutCard: AmexExpressCheckoutCard,
  VisaCheckoutCard: VisaCheckoutCard,
  MasterpassCard: MasterpassCard,

  CreditCardVerification: CreditCardVerification,
  Subscription: Subscription,
  MerchantAccount: MerchantAccount,
  PaymentInstrumentTypes: PaymentInstrumentTypes,
  WebhookNotification: WebhookNotification,
  TestingGateway: TestingGateway,
  ValidationErrorCodes: ValidationErrorCodes,

  Test: Test
};

And this is the code that sits in the index.js file of the working ExpressJs Demo

var express = require('express');
var router = express.Router();
var braintree = require('braintree');

var gateway = braintree.connect({
    environment:  braintree.Environment.Sandbox,
    merchantId:   'personalMerchantID',
    publicKey:    'personalPublicKey',
    privateKey:   'personal_PrivateKey'
});

router.get('/', function(req, res) {
  gateway.clientToken.generate({}, function(err, response) {
    var token = response.clientToken;

    res.render('index', {token : token});
  });
});

router.post('/add', function(req, res) {

  var merchant_id = req.body.merchant_id;
  var bank_account = req.body.bank_account;
  var bank_routing = req.body.bank_routing;

  var merchantAccountParams = {
    individual: {
      firstName: "Jane",
      lastName: "Doe",
      email: "jane@14ladders.com",
      phone: "5553334444",
      dateOfBirth: "1981-11-19",
      ssn: "456-45-4567",
      address: {
        streetAddress: "111 Main St",
        locality: "Chicago",
        region: "IL",
        postalCode: "60622"
      }
    },
    funding: {
      destination: braintree.MerchantAccount.FundingDestination.Bank,
      accountNumber: bank_account,
      routingNumber: bank_routing
    },
    tosAccepted: true,
    masterMerchantAccountId: "_my_personal_master_merchant_account_ID",
    id: merchant_id
  };

  gateway.merchantAccount.create(merchantAccountParams, function (err, result) {
    res.render('addResult', {result: result});
  });

});

router.get('/find', function(req, res) {
  var merchant_id = req.query.merchant_id;

  gateway.merchantAccount.find(merchant_id, function(err, result) {
    res.render('findResult', {result: result, merchant_id: merchant_id});
  });

});

router.post('/process', function(req, res) {
  var nonce = req.body.payment_method_nonce;
  var total = req.body.total;
  var service = req.body.service;
  var merchant_id = req.body.merchant_id;

  gateway.transaction.sale({
    amount: total,
    merchantAccountId: merchant_id,
    paymentMethodNonce: nonce,
    serviceFeeAmount: service
  }, function (err, result) {
    res.render('processResult', {result: result});
  });
});

module.exports = router;

Again the above code was produced by braintree. I am sure for demo purposes only.

Patrick Odum
  • 224
  • 2
  • 14

2 Answers2

3

You should not do this.

By including the Braintree node server library in the mobile client, you are exposing your private key to anyone who is using the app. This is highly insecure.

Instead, you should have a server where you can accept a nonce generated by your app to process transactions. The Braintree Cordova Plugin that @Sampath posted looks like a reasonable way to generate a nonce in your app.

BladeBarringer
  • 807
  • 6
  • 17
  • Your are right but I was following the braintree marketplace demo which was sent to me by a braintree technician. At the moment, I am still at a loss for how to even connect. But some day this will be sorted out. Thank you. – Patrick Odum Aug 31 '17 at 18:24
  • 1
    Full disclosure: I work for Braintree. Can you provide the link they gave you? I want to know if there's a more clear way of presenting the documentation to show that a server is required. – BladeBarringer Sep 01 '17 at 19:01
  • Okay. I will heed your advise more closely and rework my code. Thank you. – Patrick Odum Sep 01 '17 at 19:04
  • They sent me these three links in an email. https://github.com/braintree/braintree_express_example , https://developers.braintreepayments.com/start/overview and https://articles.braintreepayments.com/get-started/overview – Patrick Odum Sep 02 '17 at 18:45
1

It seems you're not using any plugin with above implementation. So you have to use one.This is the Braintree Cordova Plugin.

npm install plist
npm install xcode

cordova platform remove ios
cordova plugin add https://github.com/taracque/cordova-plugin-braintree
cordova platform add ios

Here you can see how to add none native plugin to the Ionic app.

Sampath
  • 63,341
  • 64
  • 307
  • 441
  • I was able to follow the instructions in both links and had promising results. However, importing braintree node package while calling the functions in the second link yield the same results. The marketplace demo calls a connect function. When I try to call the same function I receive the original error message. Thank you for the effort – Patrick Odum Aug 30 '17 at 00:40
  • @PatrickOdum Did you ever figure out how to fix this issue? I'm getting the same error – nareeboy Aug 31 '17 at 14:44
  • Not yet. I think it has something to do with the runtime error. Maybe someone who knows typescript can provide an answer. – Patrick Odum Aug 31 '17 at 20:36
  • @nareeboy Please join my ionic 3 chat. https://chat.stackoverflow.com/rooms/153499/ionic-3 – Patrick Odum Sep 02 '17 at 18:54
  • I'm trying to follow your instructions but it says cordova is undefined. Maybe an issue with ionic serve but that is my only means to test... – Patrick Odum Oct 13 '17 at 01:58
  • You need to test this on a device. – Sampath Oct 13 '17 at 02:56
  • I found a way to do it without cordova. Like blade said, the code im running should be on a server and not the client. – Patrick Odum Nov 15 '17 at 20:48