Implement new design for user and org settings

Fixes #1376
This commit is contained in:
Joseph Schorr 2016-04-25 15:17:18 -04:00
parent d63ec8c6b0
commit fe735b8048
25 changed files with 784 additions and 614 deletions

View file

@ -0,0 +1,140 @@
/**
* An element which displays the billing options for a user or an organization.
*/
angular.module('quay').directive('billingManagementPanel', function () {
var directiveDefinitionObject = {
priority: 0,
templateUrl: '/static/directives/billing-management-panel.html',
replace: false,
transclude: false,
restrict: 'C',
scope: {
'user': '=user',
'organization': '=organization',
'isEnabled': '=isEnabled'
},
controller: function($scope, $element, PlanService, ApiService) {
$scope.currentCard = null;
$scope.subscription = null;
$scope.updating = true;
$scope.changeReceiptsInfo = null;
$scope.context = {};
var setSubscription = function(sub) {
$scope.subscription = sub;
// Load the plan info.
PlanService.getPlan(sub['plan'], function(plan) {
$scope.currentPlan = plan;
if (!sub.hasSubscription) {
$scope.updating = false;
return;
}
// Load credit card information.
PlanService.getCardInfo($scope.organization ? $scope.organization.name : null, function(card) {
$scope.currentCard = card;
$scope.updating = false;
});
});
};
var update = function() {
if (!$scope.isEnabled || !($scope.user || $scope.organization)) {
return;
}
$scope.entity = $scope.user ? $scope.user : $scope.organization;
$scope.invoice_email = $scope.entity.invoice_email;
$scope.invoice_email_address = $scope.entity.invoice_email_address || $scope.entity.email;
$scope.updating = true;
// Load plan information.
PlanService.getSubscription($scope.organization, setSubscription, function() {
setSubscription({ 'plan': PlanService.getFreePlan() });
});
};
// Listen to plan changes.
PlanService.registerListener(this, function(plan) {
if (plan && plan.price > 0) {
update();
}
});
$scope.$on('$destroy', function() {
PlanService.unregisterListener(this);
});
$scope.$watch('isEnabled', update);
$scope.$watch('organization', update);
$scope.$watch('user', update);
$scope.getEntityPrefix = function() {
if ($scope.organization) {
return '/organization/' + $scope.organization.name;
} else {
return '/user/' + $scope.user.username;
}
};
$scope.changeCreditCard = function() {
var callbacks = {
'opened': function() { },
'closed': function() { },
'started': function() { },
'success': function(resp) {
$scope.currentCard = resp.card;
update();
},
'failure': function(resp) {
if (!PlanService.isCardError(resp)) {
bootbox.alert('Could not change credit card. Please try again later.');
}
}
};
PlanService.changeCreditCard($scope, $scope.organization ? $scope.organization.name : null, callbacks);
};
$scope.getCreditImage = function(creditInfo) {
if (!creditInfo || !creditInfo.type) { return 'credit.png'; }
var kind = creditInfo.type.toLowerCase() || 'credit';
var supported = {
'american express': 'amex',
'credit': 'credit',
'diners club': 'diners',
'discover': 'discover',
'jcb': 'jcb',
'mastercard': 'mastercard',
'visa': 'visa'
};
kind = supported[kind] || 'credit';
return kind + '.png';
};
$scope.changeReceipts = function(info, callback) {
$scope.entity['invoice_email'] = info['sendOption'] || false;
$scope.entity['invoice_email_address'] = info['address'] || $scope.entity.email;
var errorHandler = ApiService.errorDisplay('Could not change billing options', callback);
ApiService.changeDetails($scope.organization, $scope.entity).then(function(resp) {
callback(true);
update();
}, errorHandler);
};
$scope.showChangeReceipts = function() {
$scope.changeReceiptsInfo = {
'sendOption': $scope.invoice_email,
'address': $scope.invoice_email_address
};
};
}
};
return directiveDefinitionObject;
});

View file

@ -1,130 +0,0 @@
/**
* An element which displays the billing options for a user or an organization.
*/
angular.module('quay').directive('billingOptions', function () {
var directiveDefinitionObject = {
priority: 0,
templateUrl: '/static/directives/billing-options.html',
replace: false,
transclude: false,
restrict: 'C',
scope: {
'user': '=user',
'organization': '=organization'
},
controller: function($scope, $element, PlanService, ApiService) {
$scope.invoice_email = false;
$scope.currentCard = null;
// Listen to plan changes.
PlanService.registerListener(this, function(plan) {
if (plan && plan.price > 0) {
update();
}
});
$scope.$on('$destroy', function() {
PlanService.unregisterListener(this);
});
$scope.isExpiringSoon = function(cardInfo) {
var current = new Date();
var expires = new Date(cardInfo.exp_year, cardInfo.exp_month, 1);
var difference = expires - current;
return difference < (60 * 60 * 24 * 60 * 1000 /* 60 days */);
};
$scope.changeInvoiceEmailAddress = function() {
bootbox.prompt('Enter the email address for receiving receipts', function(email) {
// Copied from Angular.
var EMAIL_REGEXP = /^[a-z0-9!#$%&'*+/=?^_`{|}~.-]+@[a-z0-9-]+(\.[a-z0-9-]+)*$/i;
if (!email || !EMAIL_REGEXP.test(email)) {
return;
}
$scope.obj['invoice_email_address'] = email;
var errorHandler = ApiService.errorDisplay('Could not change user details');
ApiService.changeDetails($scope.organization, $scope.obj).then(function(resp) {
$scope.working = false;
}, errorHandler);
});
};
$scope.changeCard = function() {
var previousCard = $scope.currentCard;
$scope.changingCard = true;
var callbacks = {
'opened': function() { $scope.changingCard = true; },
'closed': function() { $scope.changingCard = false; },
'started': function() { $scope.currentCard = null; },
'success': function(resp) {
$scope.currentCard = resp.card;
$scope.changingCard = false;
},
'failure': function(resp) {
$scope.changingCard = false;
$scope.currentCard = previousCard;
if (!PlanService.isCardError(resp)) {
$('#cannotchangecardModal').modal({});
}
}
};
PlanService.changeCreditCard($scope, $scope.organization ? $scope.organization.name : null, callbacks);
};
$scope.getCreditImage = function(creditInfo) {
if (!creditInfo || !creditInfo.type) { return 'credit.png'; }
var kind = creditInfo.type.toLowerCase() || 'credit';
var supported = {
'american express': 'amex',
'credit': 'credit',
'diners club': 'diners',
'discover': 'discover',
'jcb': 'jcb',
'mastercard': 'mastercard',
'visa': 'visa'
};
kind = supported[kind] || 'credit';
return kind + '.png';
};
var update = function() {
if (!$scope.user && !$scope.organization) { return; }
$scope.obj = $scope.user ? $scope.user : $scope.organization;
$scope.invoice_email = $scope.obj.invoice_email;
// Load the credit card information.
PlanService.getCardInfo($scope.organization ? $scope.organization.name : null, function(card) {
$scope.currentCard = card;
});
};
var save = function() {
$scope.working = true;
var errorHandler = ApiService.errorDisplay('Could not change user details');
ApiService.changeDetails($scope.organization, $scope.obj).then(function(resp) {
$scope.working = false;
}, errorHandler);
};
var checkSave = function() {
if (!$scope.obj) { return; }
if ($scope.obj.invoice_email != $scope.invoice_email) {
$scope.obj.invoice_email = $scope.invoice_email;
save();
}
};
$scope.$watch('invoice_email', checkSave);
$scope.$watch('organization', update);
$scope.$watch('user', update);
}
};
return directiveDefinitionObject;
});

View file

@ -9,14 +9,29 @@ angular.module('quay').directive('convertUserToOrg', function () {
transclude: true,
restrict: 'C',
scope: {
'user': '=user'
'info': '=info'
},
controller: function($scope, $element, $location, Features, PlanService, Config, ApiService, CookieService, UserService) {
$scope.convertStep = 0;
$scope.org = {};
$scope.loading = false;
$scope.user = null;
$scope.Features = Features;
$scope.$watch('info', function(info) {
if (info && info.user) {
$scope.user = info.user;
$scope.accountType = 'user';
$scope.convertStep = 0;
$('#convertAccountModal').modal({});
}
});
$scope.showConvertForm = function() {
$scope.convertStep = 1;
};
$scope.nextStep = function() {
if (Features.BILLING) {
PlanService.getMatchingBusinessPlan(function(plan) {
$scope.org.plan = plan;
@ -25,22 +40,19 @@ angular.module('quay').directive('convertUserToOrg', function () {
PlanService.getPlans(function(plans) {
$scope.orgPlans = plans;
});
$scope.convertStep = 2;
} else {
$scope.performConversion();
}
$scope.convertStep = 1;
};
$scope.convertToOrg = function() {
$('#reallyconvertModal').modal({});
};
$scope.reallyConvert = function() {
$scope.performConversion = function() {
if (Config.AUTHENTICATION_TYPE != 'Database') { return; }
$scope.loading = true;
$scope.convertStep = 3;
var errorHandler = ApiService.errorDisplay(function() {
$scope.loading = false;
$('#convertAccountModal').modal('hide');
});
var data = {
@ -52,6 +64,7 @@ angular.module('quay').directive('convertUserToOrg', function () {
ApiService.convertUserToOrganization(data).then(function(resp) {
CookieService.putPermanent('quay.namespace', $scope.user.username);
UserService.load();
$('#convertAccountModal').modal('hide');
$location.path('/');
}, errorHandler);
};