Have the private option in the new repo form alert the user about needing to purchase a plan and let them do so
This commit is contained in:
parent
bb2446c45c
commit
1ee21318d4
4 changed files with 133 additions and 36 deletions
|
@ -130,6 +130,16 @@
|
||||||
text-decoration: none !important;
|
text-decoration: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.new-repo .required-plan {
|
||||||
|
margin: 10px;
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-left: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-repo .required-plan .alert {
|
||||||
|
color: #444 !important;
|
||||||
|
}
|
||||||
|
|
||||||
.new-repo .new-header {
|
.new-repo .new-header {
|
||||||
font-size: 22px;
|
font-size: 22px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ quayApp = angular.module('quay', ['restangular', 'angularMoment', 'angulartics',
|
||||||
return keyService;
|
return keyService;
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
$provide.factory('PlanService', [function() {
|
$provide.factory('PlanService', ['Restangular', 'KeyService', function(Restangular, KeyService) {
|
||||||
var plans = [
|
var plans = [
|
||||||
{
|
{
|
||||||
title: 'Open Source',
|
title: 'Open Source',
|
||||||
|
@ -96,11 +96,54 @@ quayApp = angular.module('quay', ['restangular', 'angularMoment', 'angulartics',
|
||||||
|
|
||||||
planService.planList = function() {
|
planService.planList = function() {
|
||||||
return plans;
|
return plans;
|
||||||
}
|
};
|
||||||
|
|
||||||
planService.getPlan = function(planId) {
|
planService.getPlan = function(planId) {
|
||||||
return planDict[planId];
|
return planDict[planId];
|
||||||
}
|
};
|
||||||
|
|
||||||
|
planService.getMinimumPlan = function(privateCount) {
|
||||||
|
for (var i = 0; i < plans.length; i++) {
|
||||||
|
var plan = plans[i];
|
||||||
|
if (plan.privateRepos >= privateCount) {
|
||||||
|
return plan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
planService.showSubscribeDialog = function($scope, planId, started, success, failed) {
|
||||||
|
var submitToken = function(token) {
|
||||||
|
$scope.$apply(function() {
|
||||||
|
started();
|
||||||
|
});
|
||||||
|
|
||||||
|
mixpanel.track('plan_subscribe');
|
||||||
|
|
||||||
|
var subscriptionDetails = {
|
||||||
|
token: token.id,
|
||||||
|
plan: planId,
|
||||||
|
};
|
||||||
|
|
||||||
|
var createSubscriptionRequest = Restangular.one('user/plan');
|
||||||
|
$scope.$apply(function() {
|
||||||
|
createSubscriptionRequest.customPUT(subscriptionDetails).then(success, failed);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var planDetails = planService.getPlan(planId)
|
||||||
|
StripeCheckout.open({
|
||||||
|
key: KeyService.stripePublishableKey,
|
||||||
|
address: false, // TODO change to true
|
||||||
|
amount: planDetails.price,
|
||||||
|
currency: 'usd',
|
||||||
|
name: 'Quay ' + planDetails.title + ' Subscription',
|
||||||
|
description: 'Up to ' + planDetails.privateRepos + ' private repositories',
|
||||||
|
panelLabel: 'Subscribe',
|
||||||
|
token: submitToken
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return planService;
|
return planService;
|
||||||
}]);
|
}]);
|
||||||
|
|
|
@ -701,6 +701,8 @@ function UserAdminCtrl($scope, $timeout, Restangular, PlanService, UserService,
|
||||||
|
|
||||||
if (sub.usedPrivateRepos > $scope.subscribedPlan.privateRepos) {
|
if (sub.usedPrivateRepos > $scope.subscribedPlan.privateRepos) {
|
||||||
$scope.errorMessage = 'You are using more private repositories than your plan allows, please upgrate your subscription to avoid disruptions in your service.';
|
$scope.errorMessage = 'You are using more private repositories than your plan allows, please upgrate your subscription to avoid disruptions in your service.';
|
||||||
|
} else {
|
||||||
|
$scope.errorMessage = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.planLoading = false;
|
$scope.planLoading = false;
|
||||||
|
@ -709,7 +711,7 @@ function UserAdminCtrl($scope, $timeout, Restangular, PlanService, UserService,
|
||||||
mixpanel.people.set({
|
mixpanel.people.set({
|
||||||
'plan': sub.plan
|
'plan': sub.plan
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
$scope.planLoading = true;
|
$scope.planLoading = true;
|
||||||
var getSubscription = Restangular.one('user/plan');
|
var getSubscription = Restangular.one('user/plan');
|
||||||
|
@ -720,36 +722,16 @@ function UserAdminCtrl($scope, $timeout, Restangular, PlanService, UserService,
|
||||||
|
|
||||||
$scope.planChanging = false;
|
$scope.planChanging = false;
|
||||||
$scope.subscribe = function(planId) {
|
$scope.subscribe = function(planId) {
|
||||||
var submitToken = function(token) {
|
PlanService.showSubscribeDialog($scope, planId, function() {
|
||||||
$scope.$apply(function() {
|
// Subscribing.
|
||||||
mixpanel.track('plan_subscribe');
|
$scope.planChanging = true;
|
||||||
|
}, function(plan) {
|
||||||
$scope.planChanging = true;
|
// Subscribed.
|
||||||
$scope.errorMessage = undefined;
|
subscribedToPlan(plan);
|
||||||
|
}, function() {
|
||||||
var subscriptionDetails = {
|
// Failure.
|
||||||
token: token.id,
|
$scope.errorMessage = 'Unable to subscribe.';
|
||||||
plan: planId,
|
$scope.planChanging = false;
|
||||||
};
|
|
||||||
|
|
||||||
var createSubscriptionRequest = Restangular.one('user/plan');
|
|
||||||
createSubscriptionRequest.customPUT(subscriptionDetails).then(subscribedToPlan, function() {
|
|
||||||
// Failure
|
|
||||||
$scope.errorMessage = 'Unable to subscribe.';
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
var planDetails = PlanService.getPlan(planId)
|
|
||||||
StripeCheckout.open({
|
|
||||||
key: KeyService.stripePublishableKey,
|
|
||||||
address: false, // TODO change to true
|
|
||||||
amount: planDetails.price,
|
|
||||||
currency: 'usd',
|
|
||||||
name: 'Quay ' + planDetails.title + ' Subscription',
|
|
||||||
description: 'Up to ' + planDetails.privateRepos + ' private repositories',
|
|
||||||
panelLabel: 'Subscribe',
|
|
||||||
token: submitToken
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -920,7 +902,7 @@ function V1Ctrl($scope, $location, UserService) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function NewRepoCtrl($scope, $location, $http, UserService, Restangular) {
|
function NewRepoCtrl($scope, $location, $http, UserService, Restangular, PlanService) {
|
||||||
$scope.repo = {
|
$scope.repo = {
|
||||||
'is_public': 1,
|
'is_public': 1,
|
||||||
'description': '',
|
'description': '',
|
||||||
|
@ -999,6 +981,16 @@ function NewRepoCtrl($scope, $location, $http, UserService, Restangular) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var subscribedToPlan = function(sub) {
|
||||||
|
$scope.planChanging = false;
|
||||||
|
$scope.subscription = sub;
|
||||||
|
$scope.subscribedPlan = PlanService.getPlan(sub.plan);
|
||||||
|
$scope.planRequired = null;
|
||||||
|
if ($scope.subscription.usedPrivateRepos >= $scope.subscribedPlan.privateRepos) {
|
||||||
|
$scope.planRequired = PlanService.getMinimumPlan($scope.subscription.usedPrivateRepos);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
$scope.$watch( function () { return UserService.currentUser(); }, function (currentUser) {
|
$scope.$watch( function () { return UserService.currentUser(); }, function (currentUser) {
|
||||||
$scope.user = currentUser;
|
$scope.user = currentUser;
|
||||||
|
|
||||||
|
@ -1061,4 +1053,28 @@ function NewRepoCtrl($scope, $location, $http, UserService, Restangular) {
|
||||||
$scope.creating = false;
|
$scope.creating = false;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.upgradePlan = function() {
|
||||||
|
PlanService.showSubscribeDialog($scope, $scope.planRequired.stripeId, function() {
|
||||||
|
// Subscribing.
|
||||||
|
$scope.planChanging = true;
|
||||||
|
}, function(plan) {
|
||||||
|
// Subscribed.
|
||||||
|
subscribedToPlan(plan);
|
||||||
|
}, function() {
|
||||||
|
// Failure.
|
||||||
|
$('#couldnotsubscribeModal').modal();
|
||||||
|
$scope.planChanging = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.plans = PlanService.planList();
|
||||||
|
|
||||||
|
// Load the user's subscription information in case they want to create a private
|
||||||
|
// repository.
|
||||||
|
var getSubscription = Restangular.one('user/plan');
|
||||||
|
getSubscription.get().then(subscribedToPlan, function() {
|
||||||
|
// User has no subscription
|
||||||
|
$scope.planRequired = PlanService.getMinimumPlan(1);
|
||||||
|
});
|
||||||
}
|
}
|
|
@ -62,6 +62,15 @@
|
||||||
<span class="description-text">You choose who can see, pull and push from/to this repository.</span>
|
<span class="description-text">You choose who can see, pull and push from/to this repository.</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Payment -->
|
||||||
|
<div class="required-plan" ng-show="repo.is_public == '0' && planRequired">
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
In order to make this repository private, you’ll need to upgrade your plan from <b>{{ subscribedPlan.title }}</b> to <b>{{ planRequired.title }}</b>. This will cost $<span>{{ planRequired.price / 100 }}</span>/month.
|
||||||
|
</div>
|
||||||
|
<a class="btn btn-primary" ng-click="upgradePlan()" ng-show="!planChanging">Upgrade now</a>
|
||||||
|
<i class="fa fa-spinner fa-spin fa-3x" ng-show="planChanging"></i>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -91,7 +100,7 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-1"></div>
|
<div class="col-md-1"></div>
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<button class="btn btn-large btn-success" type="submit" ng-click="createNewRepo" ng-disabled="newRepoForm.$invalid">Create Repository</button>
|
<button class="btn btn-large btn-success" type="submit" ng-disabled="newRepoForm.$invalid || (repo.is_public == '0' && planRequired)">Create Repository</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -179,3 +188,22 @@
|
||||||
</div><!-- /.modal-content -->
|
</div><!-- /.modal-content -->
|
||||||
</div><!-- /.modal-dialog -->
|
</div><!-- /.modal-dialog -->
|
||||||
</div><!-- /.modal -->
|
</div><!-- /.modal -->
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Modal message dialog -->
|
||||||
|
<div class="modal fade" id="couldnotsubscribeModal">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||||
|
<h4 class="modal-title">Cannot upgrade plan</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
Your current plan could not be upgraded. Please try again.
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||||
|
</div>
|
||||||
|
</div><!-- /.modal-content -->
|
||||||
|
</div><!-- /.modal-dialog -->
|
||||||
|
</div><!-- /.modal -->
|
||||||
|
|
Reference in a new issue