@@ -140,7 +140,7 @@
{{charge.date | date: format: mediumDate}}
|
-
+ |
{{charge.paymentSource}}
|
@@ -155,7 +155,7 @@
diff --git a/src/app/services/apiService.js b/src/app/services/apiService.js
index 17cc386849..7178ac84e8 100644
--- a/src/app/services/apiService.js
+++ b/src/app/services/apiService.js
@@ -116,7 +116,11 @@
putKeys: { url: _apiUri + '/accounts/keys', method: 'POST', params: {} },
putKey: { url: _apiUri + '/accounts/key', method: 'POST', params: {} },
'import': { url: _apiUri + '/accounts/import', method: 'POST', params: {} },
- postDelete: { url: _apiUri + '/accounts/delete', method: 'POST', params: {} }
+ postDelete: { url: _apiUri + '/accounts/delete', method: 'POST', params: {} },
+ postPremium: { url: _apiUri + '/accounts/premium', method: 'POST', params: {} },
+ putCancelPremium: { url: _apiUri + '/accounts/cancel-premium', method: 'POST', params: {} },
+ putReinstatePremium: { url: _apiUri + '/accounts/reinstate-premium', method: 'POST', params: {} },
+ getBilling: { url: _apiUri + '/accounts/billing', method: 'GET', params: {} }
});
_service.twoFactor = $resource(_apiUri + '/two-factor', {}, {
diff --git a/src/app/settings/settingsBillingController.js b/src/app/settings/settingsBillingController.js
new file mode 100644
index 0000000000..4aa1aac704
--- /dev/null
+++ b/src/app/settings/settingsBillingController.js
@@ -0,0 +1,152 @@
+angular
+ .module('bit.settings')
+
+ .controller('settingsBillingController', function ($scope, apiService, authService, $state, $uibModal, toastr, $analytics) {
+ $scope.charges = [];
+ $scope.paymentSource = null;
+ $scope.subscription = null;
+ $scope.loading = true;
+
+ $scope.$on('$viewContentLoaded', function () {
+ load();
+ });
+
+ $scope.changePayment = function () {
+ var modal = $uibModal.open({
+ animation: true,
+ templateUrl: 'app/organization/views/settingsBillingChangePayment.html',
+ controller: 'settingsBillingChangePaymentController',
+ resolve: {
+ existingPaymentMethod: function () {
+ return $scope.paymentSource ? $scope.paymentSource.description : null;
+ }
+ }
+ });
+
+ modal.result.then(function () {
+ load();
+ });
+ };
+
+ $scope.adjustStorage = function (add) {
+ var modal = $uibModal.open({
+ animation: true,
+ templateUrl: 'app/settings/views/settingsBillingAdjustStorage.html',
+ controller: 'settingsBillingAdjustStorageController',
+ resolve: {
+ add: function () {
+ return add;
+ }
+ }
+ });
+
+ modal.result.then(function () {
+ load();
+ });
+ };
+
+ $scope.cancel = function () {
+ if (!confirm('Are you sure you want to cancel? You will lose access to all premium features at the end ' +
+ 'of this billing cycle.')) {
+ return;
+ }
+
+ apiService.accounts.putCancelPremium({}, {})
+ .$promise.then(function (response) {
+ $analytics.eventTrack('Canceled Premium');
+ toastr.success('Premium subscription has been canceled.');
+ load();
+ });
+ };
+
+ $scope.reinstate = function () {
+ if (!confirm('Are you sure you want to remove the cancellation request and reinstate your premium membership?')) {
+ return;
+ }
+
+ apiService.accounts.putReinstatePremium({}, {})
+ .$promise.then(function (response) {
+ $analytics.eventTrack('Reinstated Premium');
+ toastr.success('Premium cancellation request has been removed.');
+ load();
+ });
+ };
+
+ function load() {
+ authService.getUserProfile().then(function (profile) {
+ $scope.premium = profile.premium;
+ if (!profile.premium) {
+ return null;
+ }
+
+ return apiService.accounts.getBilling({}).$promise;
+ }).then(function (billing) {
+ if (!billing) {
+ return $state.go('backend.user.settingsPremium');
+ }
+
+ var i = 0;
+
+ $scope.subscription = null;
+ if (billing && billing.Subscription) {
+ $scope.subscription = {
+ 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
+ };
+ }
+
+ $scope.nextInvoice = null;
+ if (billing && billing.UpcomingInvoice) {
+ $scope.nextInvoice = {
+ date: billing.UpcomingInvoice.Date,
+ amount: billing.UpcomingInvoice.Amount
+ };
+ }
+
+ if (billing && billing.Subscription && billing.Subscription.Items) {
+ $scope.subscription.items = [];
+ for (i = 0; i < billing.Subscription.Items.length; i++) {
+ $scope.subscription.items.push({
+ amount: billing.Subscription.Items[i].Amount,
+ name: billing.Subscription.Items[i].Name,
+ interval: billing.Subscription.Items[i].Interval,
+ qty: billing.Subscription.Items[i].Quantity
+ });
+ }
+ }
+
+ $scope.paymentSource = null;
+ if (billing && billing.PaymentSource) {
+ $scope.paymentSource = {
+ type: billing.PaymentSource.Type,
+ description: billing.PaymentSource.Description,
+ cardBrand: billing.PaymentSource.CardBrand
+ };
+ }
+
+ var charges = [];
+ if (billing && billing.Charges) {
+ for (i = 0; i < billing.Charges.length; i++) {
+ charges.push({
+ date: billing.Charges[i].CreatedDate,
+ paymentSource: billing.Charges[i].PaymentSource ?
+ billing.Charges[i].PaymentSource.Description : '-',
+ amount: billing.Charges[i].Amount,
+ status: billing.Charges[i].Status,
+ failureMessage: billing.Charges[i].FailureMessage,
+ refunded: billing.Charges[i].Refunded,
+ partiallyRefunded: billing.Charges[i].PartiallyRefunded,
+ refundedAmount: billing.Charges[i].RefundedAmount,
+ invoiceId: billing.Charges[i].InvoiceId
+ });
+ }
+ }
+ $scope.charges = charges;
+
+ $scope.loading = false;
+ });
+ }
+ });
diff --git a/src/app/settings/settingsPremiumController.js b/src/app/settings/settingsPremiumController.js
new file mode 100644
index 0000000000..589d5f24f7
--- /dev/null
+++ b/src/app/settings/settingsPremiumController.js
@@ -0,0 +1,39 @@
+angular
+ .module('bit.settings')
+
+ .controller('settingsPremiumController', function ($scope, $state, apiService, toastr, $analytics, authService, stripe) {
+ authService.getUserProfile().then(function (profile) {
+ if (profile.premium) {
+ return $state.go('backend.user.settingsBilling');
+ }
+ });
+
+ $scope.storageGbPrice = 4;
+ $scope.premiumPrice = 10;
+
+ $scope.model = {
+ additionalStorageGb: null
+ };
+
+ $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) {
+ var request = {
+ paymentToken: response.id,
+ additionalStorageGb: model.additionalStorageGb
+ };
+
+ return apiService.accounts.postPremium(request).$promise;
+ }).then(function (result) {
+ $analytics.eventTrack('Signed Up Premium');
+ return authService.refreshAccessToken();
+ }).then(function () {
+ return $state.go('backend.user.settingsBilling');
+ }).then(function () {
+ toastr.success('Premium upgrade complete.', 'Success');
+ });
+ };
+ });
diff --git a/src/app/settings/views/settingsBilling.html b/src/app/settings/views/settingsBilling.html
new file mode 100644
index 0000000000..526c43e161
--- /dev/null
+++ b/src/app/settings/views/settingsBilling.html
@@ -0,0 +1,132 @@
+
+
+
+
+
+
+
+
+ - Status
+ - {{(subscription && subscription.status) || '-'}}
+ - Next Charge
+ - {{nextInvoice ? ((nextInvoice.date | date: format: mediumDate) + ', ' + (nextInvoice.amount | currency:'$')) : '-'}}
+
+
+
+ Details
+
+ Loading...
+
+
+
+
+
+
+ {{item.name}} {{item.qty > 1 ? '×' + item.qty : ''}}
+ @ {{item.amount | currency:'$'}}
+ |
+ {{(item.qty * item.amount) | currency:'$'}} /{{item.interval}} |
+
+
+
+
+
+
+
+
+
+
+
+
+ You membership has a total of x GB of encrypted file storage. You are currently using y GB.
+
+
+
+
+
+
+
+
+ Loading...
+
+
+ No payment method on file.
+
+
+
+ {{paymentSource.description}}
+
+
+
+
+
+
+
+
+ Loading...
+
+
+ No charges.
+
+
+
+
+
+
+ {{charge.date | date: format: mediumDate}}
+ |
+
+ {{charge.paymentSource}}
+ |
+
+ {{charge.status}}
+ |
+
+ {{charge.amount | currency:'$'}}
+ |
+
+
+
+
+
+
+
+
diff --git a/src/app/settings/views/settingsPremium.html b/src/app/settings/views/settingsPremium.html
new file mode 100644
index 0000000000..2845ff1f63
--- /dev/null
+++ b/src/app/settings/views/settingsPremium.html
@@ -0,0 +1,438 @@
+
+
diff --git a/src/app/views/userLayout.html b/src/app/views/userLayout.html
index 4da1bfa7c7..c01f7df47d 100644
--- a/src/app/views/userLayout.html
+++ b/src/app/views/userLayout.html
@@ -78,15 +78,26 @@
+ $state.is('backend.user.settingsCreateOrg') || $state.is('backend.user.settingsTwoStep') ||
+ $state.is('backend.user.settingsPremium') || $state.is('backend.user.settingsBilling')}">
Settings
|