support for paypal through braintree
This commit is contained in:
parent
84554174ac
commit
96b8467859
|
@ -2,6 +2,7 @@
|
|||
"appSettings": {
|
||||
"apiUri": "https://preview-api.bitwarden.com",
|
||||
"identityUri": "https://preview-identity.bitwarden.com",
|
||||
"stripeKey": "pk_test_KPoCfZXu7mznb9uSCPZ2JpTD"
|
||||
"stripeKey": "pk_test_KPoCfZXu7mznb9uSCPZ2JpTD",
|
||||
"braintreeKey": "sandbox_r72q8jq6_9pnxkwm75f87sdc2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"appSettings": {
|
||||
"apiUri": "https://api.bitwarden.com",
|
||||
"identityUri": "https://identity.bitwarden.com",
|
||||
"stripeKey": "pk_live_bpN0P37nMxrMQkcaHXtAybJk"
|
||||
"stripeKey": "pk_live_bpN0P37nMxrMQkcaHXtAybJk",
|
||||
"braintreeKey": "TODO"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"appSettings": {
|
||||
"apiUri": "http://localhost:4000",
|
||||
"identityUri": "http://localhost:33656",
|
||||
"stripeKey": "pk_test_KPoCfZXu7mznb9uSCPZ2JpTD"
|
||||
"stripeKey": "pk_test_KPoCfZXu7mznb9uSCPZ2JpTD",
|
||||
"braintreeKey": "sandbox_r72q8jq6_9pnxkwm75f87sdc2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
$analytics, toastr, existingPaymentMethod) {
|
||||
$analytics.eventTrack('organizationBillingChangePaymentController', { category: 'Modal' });
|
||||
$scope.existingPaymentMethod = existingPaymentMethod;
|
||||
$scope.paymentMethod = 'card';
|
||||
$scope.showPaymentOptions = false;
|
||||
$scope.card = {};
|
||||
|
||||
$scope.submit = function () {
|
||||
$scope.submitPromise = stripe.card.createToken($scope.card).then(function (response) {
|
||||
|
|
|
@ -137,9 +137,8 @@
|
|||
trialEndDate: org.Subscription.TrialEndDate,
|
||||
cancelledDate: org.Subscription.CancelledDate,
|
||||
status: org.Subscription.Status,
|
||||
cancelled: org.Subscription.Status === 'cancelled',
|
||||
markedForCancel: (org.Subscription.Status === 'active' || org.Subscription.Status === 'trialing') &&
|
||||
org.Subscription.CancelledDate
|
||||
cancelled: org.Subscription.Cancelled,
|
||||
markedForCancel: !org.Subscription.Cancelled && org.Subscription.CancelAtEndDate
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -141,7 +141,7 @@
|
|||
</div>
|
||||
<div ng-show="!loading && paymentSource">
|
||||
<i class="fa" ng-class="{'fa-credit-card': paymentSource.type === 0,
|
||||
'fa-university': paymentSource.type === 1}"></i>
|
||||
'fa-university': paymentSource.type === 1, 'fa-paypal fa-fw text-blue': paymentSource.type === 2}"></i>
|
||||
{{paymentSource.description}}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
angular.module("bit")
|
||||
.constant("appSettings", {"apiUri":"https://api.bitwarden.com","identityUri":"https://identity.bitwarden.com","stripeKey":"pk_live_bpN0P37nMxrMQkcaHXtAybJk","version":"1.14.0","environment":"Production"});
|
||||
.constant("appSettings", {"apiUri":"https://api.bitwarden.com","identityUri":"https://identity.bitwarden.com","stripeKey":"pk_live_bpN0P37nMxrMQkcaHXtAybJk","braintreeKey":"TODO","version":"1.14.0","environment":"Production"});
|
||||
|
|
|
@ -2,14 +2,51 @@
|
|||
.module('bit.organization')
|
||||
|
||||
.controller('settingsBillingChangePaymentController', function ($scope, $state, $uibModalInstance, apiService, stripe,
|
||||
$analytics, toastr, existingPaymentMethod) {
|
||||
$analytics, toastr, existingPaymentMethod, appSettings, $timeout) {
|
||||
$analytics.eventTrack('settingsBillingChangePaymentController', { category: 'Modal' });
|
||||
$scope.existingPaymentMethod = existingPaymentMethod;
|
||||
$scope.paymentMethod = 'card';
|
||||
$scope.dropinLoaded = false;
|
||||
$scope.showPaymentOptions = true;
|
||||
$scope.card = {};
|
||||
var btInstance = null;
|
||||
|
||||
$scope.changePaymentMethod = function (val) {
|
||||
$scope.paymentMethod = val;
|
||||
if ($scope.paymentMethod !== 'paypal') {
|
||||
return;
|
||||
}
|
||||
|
||||
braintree.dropin.create({
|
||||
authorization: appSettings.braintreeKey,
|
||||
container: '#bt-dropin-container',
|
||||
paymentOptionPriority: ['paypal'],
|
||||
paypal: {
|
||||
flow: 'vault',
|
||||
buttonStyle: {
|
||||
label: 'pay',
|
||||
size: 'medium',
|
||||
shape: 'pill',
|
||||
color: 'blue'
|
||||
}
|
||||
}
|
||||
}, function (createErr, instance) {
|
||||
if (createErr) {
|
||||
console.error(createErr);
|
||||
return;
|
||||
}
|
||||
|
||||
btInstance = instance;
|
||||
$timeout(function () {
|
||||
$scope.dropinLoaded = true;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.submit = function () {
|
||||
$scope.submitPromise = stripe.card.createToken($scope.card).then(function (response) {
|
||||
$scope.submitPromise = getPaymentToken($scope.card).then(function (token) {
|
||||
var request = {
|
||||
paymentToken: response.id
|
||||
paymentToken: token
|
||||
};
|
||||
|
||||
return apiService.accounts.putPayment(null, request).$promise;
|
||||
|
@ -31,4 +68,17 @@
|
|||
$scope.close = function () {
|
||||
$uibModalInstance.dismiss('cancel');
|
||||
};
|
||||
|
||||
function getPaymentToken(card) {
|
||||
if ($scope.paymentMethod === 'paypal') {
|
||||
return btInstance.requestPaymentMethod().then(function (payload) {
|
||||
return payload.nonce;
|
||||
});
|
||||
}
|
||||
else {
|
||||
return stripe.card.createToken(card).then(function (response) {
|
||||
return response.id;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -104,8 +104,8 @@
|
|||
trialEndDate: billing.Subscription.TrialEndDate,
|
||||
cancelledDate: billing.Subscription.CancelledDate,
|
||||
status: billing.Subscription.Status,
|
||||
cancelled: billing.Subscription.Status === 'cancelled',
|
||||
markedForCancel: billing.Subscription.Status === 'active' && billing.Subscription.CancelledDate
|
||||
cancelled: billing.Subscription.Cancelled,
|
||||
markedForCancel: !billing.Subscription.Cancelled && billing.Subscription.CancelAtEndDate
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -2,28 +2,62 @@
|
|||
.module('bit.settings')
|
||||
|
||||
.controller('settingsPremiumController', function ($scope, $state, apiService, toastr, $analytics, authService, stripe,
|
||||
constants) {
|
||||
constants, $timeout, appSettings) {
|
||||
authService.getUserProfile().then(function (profile) {
|
||||
if (profile.premium) {
|
||||
return $state.go('backend.user.settingsBilling');
|
||||
}
|
||||
});
|
||||
|
||||
var btInstance = null;
|
||||
$scope.storageGbPrice = constants.storageGb.yearlyPrice;
|
||||
$scope.premiumPrice = constants.premium.price;
|
||||
$scope.paymentMethod = 'card';
|
||||
$scope.dropinLoaded = false;
|
||||
|
||||
$scope.model = {
|
||||
additionalStorageGb: null
|
||||
};
|
||||
|
||||
$scope.changePaymentMethod = function () {
|
||||
if ($scope.paymentMethod !== 'paypal') {
|
||||
return;
|
||||
}
|
||||
|
||||
braintree.dropin.create({
|
||||
authorization: appSettings.braintreeKey,
|
||||
container: '#bt-dropin-container',
|
||||
paymentOptionPriority: ['paypal'],
|
||||
paypal: {
|
||||
flow: 'vault',
|
||||
buttonStyle: {
|
||||
label: 'pay',
|
||||
size: 'medium',
|
||||
shape: 'pill',
|
||||
color: 'blue'
|
||||
}
|
||||
}
|
||||
}, function (createErr, instance) {
|
||||
if (createErr) {
|
||||
console.error(createErr);
|
||||
return;
|
||||
}
|
||||
|
||||
btInstance = instance;
|
||||
$timeout(function () {
|
||||
$scope.dropinLoaded = true;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.totalPrice = function () {
|
||||
return $scope.premiumPrice + (($scope.model.additionalStorageGb || 0) * $scope.storageGbPrice);
|
||||
};
|
||||
|
||||
$scope.submit = function (model) {
|
||||
$scope.submitPromise = stripe.card.createToken(model.card).then(function (response) {
|
||||
$scope.submitPromise = getPaymentToken(model).then(function (token) {
|
||||
var request = {
|
||||
paymentToken: response.id,
|
||||
paymentToken: token,
|
||||
additionalStorageGb: model.additionalStorageGb
|
||||
};
|
||||
|
||||
|
@ -39,4 +73,17 @@
|
|||
toastr.success('Premium upgrade complete.', 'Success');
|
||||
});
|
||||
};
|
||||
|
||||
function getPaymentToken(model) {
|
||||
if ($scope.paymentMethod === 'paypal') {
|
||||
return btInstance.requestPaymentMethod().then(function (payload) {
|
||||
return payload.nonce;
|
||||
});
|
||||
}
|
||||
else {
|
||||
return stripe.card.createToken(model.card).then(function (response) {
|
||||
return response.id;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
<div class="box-footer" ng-if="!subscription.cancelled || subscription.markedForCancel">
|
||||
<button type="button" class="btn btn-default btn-flat" ng-click="cancel()"
|
||||
ng-if="!subscription.cancelled && !subscription.markedForCancel">
|
||||
Cancel
|
||||
|
@ -82,7 +82,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
<div class="box-footer" ng-if="!subscription.cancelled">
|
||||
<button type="button" class="btn btn-default btn-flat" ng-click="adjustStorage(true)">
|
||||
Add Storage
|
||||
</button>
|
||||
|
@ -104,7 +104,7 @@
|
|||
</div>
|
||||
<div ng-show="!loading && paymentSource">
|
||||
<i class="fa" ng-class="{'fa-credit-card': paymentSource.type === 0,
|
||||
'fa-university': paymentSource.type === 1}"></i>
|
||||
'fa-university': paymentSource.type === 1, 'fa-paypal fa-fw text-blue': paymentSource.type === 2}"></i>
|
||||
{{paymentSource.description}}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -13,6 +13,21 @@
|
|||
<li ng-repeat="e in form.$errors">{{e}}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div ng-if="showPaymentOptions">
|
||||
<label class="radio-inline">
|
||||
<input type="radio" name="PaymentMethod" value="card" ng-model="paymentMethod"
|
||||
ng-change="changePaymentMethod('card')"> Credit Card
|
||||
</label>
|
||||
<label class="radio-inline">
|
||||
<input type="radio" name="PaymentMethod" value="paypal" ng-model="paymentMethod"
|
||||
ng-change="changePaymentMethod('paypal')"> PayPal
|
||||
</label>
|
||||
<hr />
|
||||
</div>
|
||||
<div ng-if="paymentMethod === 'paypal'">
|
||||
<div id="bt-dropin-container"></div>
|
||||
</div>
|
||||
<div ng-if="paymentMethod === 'card'">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="form-group" show-errors>
|
||||
|
@ -355,6 +370,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary btn-flat" ng-disabled="form.$loading">
|
||||
<i class="fa fa-refresh fa-spin loading-icon" ng-show="form.$loading"></i>Submit
|
||||
|
|
|
@ -89,6 +89,19 @@
|
|||
<h3 class="box-title">Payment Information</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<label class="radio-inline">
|
||||
<input type="radio" name="PaymentMethod" value="card" ng-model="paymentMethod"
|
||||
ng-change="changePaymentMethod()"> Credit Card
|
||||
</label>
|
||||
<label class="radio-inline">
|
||||
<input type="radio" name="PaymentMethod" value="paypal" ng-model="paymentMethod"
|
||||
ng-change="changePaymentMethod()"> PayPal
|
||||
</label>
|
||||
<hr />
|
||||
<div ng-if="paymentMethod === 'paypal'">
|
||||
<div id="bt-dropin-container"></div>
|
||||
</div>
|
||||
<div ng-if="paymentMethod === 'card'">
|
||||
<div class="row">
|
||||
<div class="col-md-5">
|
||||
<div class="form-group" show-errors>
|
||||
|
@ -434,6 +447,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
<button type="submit" class="btn btn-primary btn-flat" ng-disabled="form.$loading">
|
||||
<i class="fa fa-refresh fa-spin loading-icon" ng-show="form.$loading"></i>Submit
|
||||
|
|
|
@ -7,18 +7,25 @@
|
|||
'self';
|
||||
script-src
|
||||
'self'
|
||||
'sha256-ryoU+5+IUZTuUyTElqkrQGBJXr1brEv6r2CA62WUw8w='
|
||||
https://www.google-analytics.com
|
||||
https://js.stripe.com
|
||||
https://js.braintreegateway.com
|
||||
https://www.paypalobjects.com
|
||||
https://maxcdn.bootstrapcdn.com
|
||||
https://ajax.googleapis.com;
|
||||
style-src
|
||||
'self'
|
||||
'unsafe-inline'
|
||||
https://maxcdn.bootstrapcdn.com
|
||||
https://assets.braintreegateway.com
|
||||
https://*.paypal.com
|
||||
https://fonts.googleapis.com;
|
||||
img-src
|
||||
'self'
|
||||
data:
|
||||
https://*.paypal.com
|
||||
https://www.paypalobjects.com
|
||||
https://q.stripe.com
|
||||
https://haveibeenpwned.com
|
||||
https://chart.googleapis.com
|
||||
|
@ -30,10 +37,14 @@
|
|||
child-src
|
||||
'self'
|
||||
https://js.stripe.com
|
||||
https://assets.braintreegateway.com
|
||||
https://*.paypal.com
|
||||
https://*.duosecurity.com;
|
||||
frame-src
|
||||
'self'
|
||||
https://js.stripe.com
|
||||
https://assets.braintreegateway.com
|
||||
https://*.paypal.com
|
||||
https://*.duosecurity.com;
|
||||
connect-src
|
||||
*;">
|
||||
|
@ -43,6 +54,7 @@
|
|||
<title page-title>bitwarden.com Password Manager</title>
|
||||
|
||||
<script src="https://js.stripe.com/v2/"></script>
|
||||
<script src="https://js.braintreegateway.com/web/dropin/1.4.0/js/dropin.min.js"></script>
|
||||
<!-- @if true !>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
|
||||
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
|
||||
|
|
|
@ -620,6 +620,10 @@ h1, h2, h3, h4, h5, h6 {
|
|||
}
|
||||
}
|
||||
|
||||
.braintree-placeholder {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue