Skip to content

Commit

Permalink
[5.3] MSTR-286: Add support to Braintree sdk client to store credit c…
Browse files Browse the repository at this point in the history
…ards (#1144)

* MSTR-286: Add support to Braintree sdk client to store credit cards

* Add sdk client to store credit cards and remove old one

* Add interaction to the credit card section and remove unused functions

* Fix linter, clean up code

* Add fixes based on code review

* Create client token if it doesn't exist for the client
  • Loading branch information
pcandia committed Mar 16, 2024
1 parent fcaa3af commit e481a6f
Show file tree
Hide file tree
Showing 12 changed files with 173 additions and 188 deletions.
1 change: 1 addition & 0 deletions gulp/tasks/require.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const libsToExcludeFromApp = [
'ddslick',
'disableAutoFill',
'drop',
'dropin',
'duo',
'file-saver',
'fileupload',
Expand Down
59 changes: 0 additions & 59 deletions src/apps/myaccount/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -811,22 +811,6 @@ define(function(require) {
liSettings.find('.uneditable').show();
liSettings.find('.edition').hide();
});
},
settingsValidate = function(fieldName, dataForm, callback) {
var formPassword = template.find('#form_password');
var formAccountAdministrator = template.find('#form_account_administrator');

// This is still ghetto, I didn't want to re-factor the whole code to tweak the validation
// If the field is password, we start custom validation

if (formPassword.length) {
self.validatePasswordForm(formPassword, callback);
// otherwise we don't have any validation for this field, we execute the callback
} else if (formAccountAdministrator.length) {
self.validateAccountAdministratorForm(formAccountAdministrator, callback);
} else {
callback && callback();
}
};

template.find('.settings-link').on('click', function() {
Expand Down Expand Up @@ -854,49 +838,6 @@ define(function(require) {
currentElement.val(currentElement.data('original_value'));
});
});

template.find('.change').on('click', function(e) {
e.preventDefault();

var currentElement = $(this),
module = currentElement.parents('#myaccount').find('.myaccount-menu .myaccount-element.active').data('module'),
moduleToUpdate = currentElement.data('module'),
fieldName = currentElement.data('field'),
newData = (function cleanFormData(moduleToUpdate, data) {
if (moduleToUpdate === 'billing') {
data.credit_card.expiration_date = data.extra.expiration_date.month + '/' + data.extra.expiration_date.year;
}

return data;
})(moduleToUpdate, monster.ui.getFormData('form_' + fieldName));

settingsValidate(fieldName, newData,
function() {
self.settingsUpdateData(moduleToUpdate, data[moduleToUpdate], newData,
function(data) {
var args = {
callback: function(parent) {
if (fieldName === 'credit_card') {
parent.find('.edition').hide();
parent.find('.uneditable').show();
} else if (fieldName === 'colorblind') {
$('body').toggleClass('colorblind', data.data.ui_flags.colorblind);
}

self.highlightField(parent, fieldName);

/* TODO USELESS? */
if (typeof callbackUpdate === 'function') {
}
}
};

monster.pub('myaccount.' + module + '.renderContent', args);
}
);
}
);
});
},

highlightField: function(parent, fieldName) {
Expand Down
8 changes: 8 additions & 0 deletions src/apps/myaccount/style/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,14 @@
background: url(static/mastercard.png);
}

#myaccount .myaccount-content .list-settings .card-type.unionpay {
background: url(static/unionpay.png);
}

#myaccount .myaccount-content .list-settings .card-type.jcb {
background: url(static/jcb.png);
}

#myaccount .myaccount-content .list-settings {
overflow: visible;
margin: 0;
Expand Down
Binary file added src/apps/myaccount/style/static/jcb.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/apps/myaccount/style/static/unionpay.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 11 additions & 1 deletion src/apps/myaccount/submodules/billing/billing.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,14 @@
#myaccount .myaccount-content .billing-content-wrapper .credit-card-container .card .front,
#myaccount .myaccount-content .billing-content-wrapper .credit-card-container .card .back {
background: #808089;
}
}
#myaccount .myaccount-content .billing-content-wrapper .action-group .save-card {
display: none;
}
#myaccount .myaccount-content .billing-content-wrapper .action-group .save-card.show {
display: inline-block;
}

[data-braintree-id="toggle"] {
display: none;
}
215 changes: 142 additions & 73 deletions src/apps/myaccount/submodules/billing/billing.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ define(function(require) {
var $ = require('jquery'),
_ = require('lodash'),
monster = require('monster'),
card = require('card');
dropin = require('dropin');

var billing = {

Expand Down Expand Up @@ -40,28 +40,104 @@ define(function(require) {
callback(null, {});
}
});
},
accountToken: function(callback) {
self.getAccountToken({
success: function(data) {
callback(null, data);
},
error: function(data) {
self.requestUpdateBilling({
data: {
data: {
first_name: 'Test',
last_name: 'Test'
}
},
success: function(data) {
self.getAccountToken({
success: function(data) {
callback(null, data);
}
});
}
});
}
});
}
}, function(err, results) {
self.billingFormatData(results, function(results) {
var billingTemplate = $(self.getTemplate({
name: 'layout',
data: results,
submodule: 'billing'
}));
name: 'layout',
data: results,
submodule: 'billing'
})),
setCardHeader = function(creditCard, button) {
var cardType = _.get(creditCard, 'card_type', '').toLowerCase(),
newTypeClass = cardType === 'american express'
? 'card-type amex'
: 'card-type ' + cardType,
newDescription = creditCard.last_four
? '•••• •••• •••• ' + (creditCard.last_four)
: '';

billingTemplate.find('.card-type')
.removeClass()
.addClass(newTypeClass);

billingTemplate.find('.fake-number')
.text(newDescription);

if (!_.isEmpty(creditCard)) {
button.removeClass('show');
} else {
button.addClass('show');
}
};

self.billingBindEvents(billingTemplate, results);

monster.pub('myaccount.renderSubmodule', billingTemplate);

billingTemplate.find('#form_credit_card').card({
container: '.credit-card-container',
nameInput: '#first_name, #last_name',
numberInput: '#credit_card_number',
expiryInput: '#expiration_date_month, #expiration_date_year',
cvcInput: '#security_code',
values: {
number: '•••• •••• •••• ' + (results.billing.credit_card.last_four || '••••')
dropin.create({
authorization: _.get(results, 'accountToken.client_token'),
selector: '#dropin_container',
vaultManager: true,
card: {
cardholderName: {
required: true
}
}
}, function(err, instance) {
var saveButton = billingTemplate.find('.save-card'),
deleteButton = billingTemplate.find('.braintree-delete-confirmation__button[data-braintree-id="delete-confirmation__yes"]');

saveButton.on('click', function(e) {
e.preventDefault();

instance.requestPaymentMethod(function(err, payload) {
if (err) {
instance.clearSelectedPaymentMethod();
} else {
self.requestUpdateBilling({
data: {
data: {
nonce: payload.nonce
}
},
success: function(data) {
setCardHeader(_.head(_.get(data, 'credit_cards')), saveButton);
}
});
}
});
});

deleteButton.on('click', function(e) {
e.preventDefault();

setCardHeader({}, saveButton);
});
});

if (typeof args.callback === 'function') {
Expand All @@ -73,13 +149,18 @@ define(function(require) {

billingFormatData: function(data, callback) {
if (!_.isEmpty(data.billing)) {
data.billing.credit_card = data.billing.credit_cards[0] || {};
var creditCards = _.get(data, 'billing.credit_cards', {});
data.billing.credit_card = _.find(creditCards, { 'default': true }) || {};

/* If There is a credit card stored, we fill the fields with * */
if (data.billing.credit_card.last_four) {
var cardType = data.billing.credit_card.card_type.toLowerCase();

data.billing.credit_card.fake_number = '************' + data.billing.credit_card.last_four;
data.billing.credit_card.fake_cvv = '***';
data.billing.credit_card.type = data.billing.credit_card.card_type.toLowerCase();
data.billing.credit_card.type = cardType === 'american express'
? 'amex'
: cardType;
}
}

Expand All @@ -88,71 +169,22 @@ define(function(require) {

billingBindEvents: function(template, data) {
var self = this,
getCardType = function(number) {
var reg_visa = new RegExp('^4[0-9]{12}(?:[0-9]{3})?$'),
reg_mastercard = new RegExp('^5[1-5][0-9]{14}$'),
reg_amex = new RegExp('^3[47][0-9]{13}$'),
reg_discover = new RegExp('^6(?:011|5[0-9]{2})[0-9]{12}$');
//regDiners = new RegExp('^3(?:0[0-5]|[68][0-9])[0-9]{11}$'),
//regJSB= new RegExp('^(?:2131|1800|35\\d{3})\\d{11}$');

if (reg_visa.test(number)) {
return 'visa';
}

if (reg_mastercard.test(number)) {
return 'mastercard';
}

if (reg_amex.test(number)) {
return 'amex';
}

if (reg_discover.test(number)) {
return 'discover';
}

// if (reg_diners.test(number)) {
// return 'DINERS';
// }

// if (reg_JSB.test(number)) {
// return 'JSB';
// }
creditCardData = _.get(data, 'billing.credit_card');

return false;
},
displayCardType = function(cardNumber) {
var type = getCardType(cardNumber);

if (type === false) {
template.find('.edition .card-type').hide();
template.find('.add-on i').show();
} else if (!(template.find('.card-type.' + type).is(':visible'))) {
template.find('.edition .card-type').hide();
template.find('.add-on i').hide();
template.find('.edition .card-type.' + type).css('display', 'inline-block');
}
};
if (_.isEmpty(creditCardData)) {
template.find('.save-card').addClass('show');
}

template.find('.edit-credit-card').on('click', function(e) {
template.on('click', '.braintree-toggle', function(e) {
e.preventDefault();

template.find('.edition').show();
template.find('.uneditable').hide();
displayCardType('');
template.find('.save-card').addClass('show');
});

template.find('#credit_card_number').on('keyup', function(e) {
displayCardType($(this).val());
});
template.on('click', '.braintree-method', function(e) {
e.preventDefault();

template.find('#credit_card_number').on('paste', function(e) {
var currentElement = $(this);
//Hack for paste event: w/o timeout, the value is set to undefined...
setTimeout(function() {
displayCardType(currentElement.val());
}, 0);
template.find('.save-card').removeClass('show');
});

//Refreshing the card info when opening the settings-item
Expand All @@ -162,11 +194,48 @@ define(function(require) {
settingsItem.find('input').keyup();
}
});

monster.pub('myaccount.events', {
template: template,
data: data
});
},

requestUpdateBilling: function(args) {
var self = this;

self.callApi({
resource: 'billing.update',
data: _.merge({
accountId: self.accountId
}, args.data),
success: function(data) {
args.hasOwnProperty('success') && args.success(data.data);
},
error: function(parsedError) {
args.hasOwnProperty('error') && args.error(parsedError);
}
});
},

getAccountToken: function(args) {
var self = this;

self.callApi({
resource: 'billing.getToken',
data: _.merge({
accountId: self.accountId,
generateError: false
}, args.data),
success: function(data) {
args.hasOwnProperty('success') && args.success(data.data);
},
error: function(parsedError) {
args.hasOwnProperty('error') && args.error(parsedError);
}
});
}

};

return billing;
Expand Down

0 comments on commit e481a6f

Please sign in to comment.