Make the pricing page ask for signup and, if completed, redirect to the proper page to subscribe to a plan. Also fixes a redirect issue with Github signin on the new org page
This commit is contained in:
parent
91f4464cb6
commit
abe6db334d
5 changed files with 109 additions and 24 deletions
|
@ -11,9 +11,7 @@
|
||||||
<span class="inner-text">OR</span>
|
<span class="inner-text">OR</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<a id="github-signin-link"
|
<a id="github-signin-link" class="btn btn-primary btn-lg btn-block" href="javascript:void(0)" ng-click="showGithub()">
|
||||||
href="https://github.com/login/oauth/authorize?client_id={{ githubClientId }}&scope=user:email{{ mixpanelDistinctIdClause }}"
|
|
||||||
class="btn btn-primary btn-lg btn-block">
|
|
||||||
<i class="fa fa-github fa-lg"></i> Sign In with GitHub
|
<i class="fa fa-github fa-lg"></i> Sign In with GitHub
|
||||||
</a>
|
</a>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -174,7 +174,8 @@ quayApp = angular.module('quay', ['ngRoute', 'restangular', 'angularMoment', 'an
|
||||||
return keyService;
|
return keyService;
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
$provide.factory('PlanService', ['Restangular', 'KeyService', 'UserService', function(Restangular, KeyService, UserService) {
|
$provide.factory('PlanService', ['Restangular', 'KeyService', 'UserService', '$cookieStore',
|
||||||
|
function(Restangular, KeyService, UserService, $cookieStore) {
|
||||||
var plans = null;
|
var plans = null;
|
||||||
var planDict = {};
|
var planDict = {};
|
||||||
var planService = {};
|
var planService = {};
|
||||||
|
@ -193,6 +194,29 @@ quayApp = angular.module('quay', ['ngRoute', 'restangular', 'angularMoment', 'an
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
planService.notePlan = function(planId) {
|
||||||
|
$cookieStore.put('quay.notedplan', planId);
|
||||||
|
};
|
||||||
|
|
||||||
|
planService.handleNotedPlan = function() {
|
||||||
|
var planId = planService.getAndResetNotedPlan();
|
||||||
|
if (!planId) { return; }
|
||||||
|
|
||||||
|
planService.isBusinessPlan(planId, function(bus) {
|
||||||
|
if (bus) {
|
||||||
|
document.location = '/organizations/new/?plan=' + planId;
|
||||||
|
} else {
|
||||||
|
document.location = '/user?plan=' + planId;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
planService.getAndResetNotedPlan = function() {
|
||||||
|
var planId = $cookieStore.get('quay.notedplan');
|
||||||
|
$cookieStore.put('quay.notedplan', '');
|
||||||
|
return planId;
|
||||||
|
};
|
||||||
|
|
||||||
planService.handleCardError = function(resp) {
|
planService.handleCardError = function(resp) {
|
||||||
if (!planService.isCardError(resp)) { return; }
|
if (!planService.isCardError(resp)) { return; }
|
||||||
|
|
||||||
|
@ -249,6 +273,20 @@ quayApp = angular.module('quay', ['ngRoute', 'restangular', 'angularMoment', 'an
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
planService.isBusinessPlan = function(planId, callback) {
|
||||||
|
planService.verifyLoaded(function() {
|
||||||
|
planSource = plans.business;
|
||||||
|
for (var i = 0; i < planSource.length; i++) {
|
||||||
|
var plan = planSource[i];
|
||||||
|
if (plan.stripeId == planId) {
|
||||||
|
callback(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
callback(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
planService.getPlans = function(callback) {
|
planService.getPlans = function(callback) {
|
||||||
planService.verifyLoaded(callback);
|
planService.verifyLoaded(callback);
|
||||||
};
|
};
|
||||||
|
@ -602,31 +640,57 @@ quayApp.directive('signinForm', function () {
|
||||||
transclude: true,
|
transclude: true,
|
||||||
restrict: 'C',
|
restrict: 'C',
|
||||||
scope: {
|
scope: {
|
||||||
'redirectUrl': '=redirectUrl'
|
'redirectUrl': '=redirectUrl',
|
||||||
|
'signInStarted': '&signInStarted',
|
||||||
|
'signedIn': '&signedIn'
|
||||||
},
|
},
|
||||||
controller: function($scope, $location, $timeout, Restangular, KeyService, UserService) {
|
controller: function($scope, $location, $timeout, Restangular, KeyService, UserService) {
|
||||||
$scope.githubClientId = KeyService.githubClientId;
|
$scope.showGithub = function() {
|
||||||
|
$scope.markStarted();
|
||||||
|
|
||||||
var appendMixpanelId = function() {
|
var mixpanelDistinctIdClause = '';
|
||||||
if (mixpanel.get_distinct_id !== undefined) {
|
if (mixpanel.get_distinct_id !== undefined) {
|
||||||
$scope.mixpanelDistinctIdClause = "&state=" + mixpanel.get_distinct_id();
|
$scope.mixpanelDistinctIdClause = "&state=" + encodeURIComponent(mixpanel.get_distinct_id());
|
||||||
} else {
|
|
||||||
// Mixpanel not yet loaded, try again later
|
|
||||||
$timeout(appendMixpanelId, 200);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Needed to ensure that UI work done by the started callback is finished before the location
|
||||||
|
// changes.
|
||||||
|
$timeout(function() {
|
||||||
|
var url = 'https://github.com/login/oauth/authorize?client_id=' + encodeURIComponent(KeyService.githubClientId) +
|
||||||
|
'&scope=user:email' + mixpanelDistinctIdClause;
|
||||||
|
document.location = url;
|
||||||
|
}, 250);
|
||||||
};
|
};
|
||||||
|
|
||||||
appendMixpanelId();
|
$scope.markStarted = function() {
|
||||||
|
if ($scope.signInStarted != null) {
|
||||||
|
$scope.signInStarted();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
$scope.signin = function() {
|
$scope.signin = function() {
|
||||||
|
$scope.markStarted();
|
||||||
|
|
||||||
var signinPost = Restangular.one('signin');
|
var signinPost = Restangular.one('signin');
|
||||||
signinPost.customPOST($scope.user).then(function() {
|
signinPost.customPOST($scope.user).then(function() {
|
||||||
$scope.needsEmailVerification = false;
|
$scope.needsEmailVerification = false;
|
||||||
$scope.invalidCredentials = false;
|
$scope.invalidCredentials = false;
|
||||||
|
|
||||||
// Redirect to the specified page or the landing page
|
if ($scope.signedIn != null) {
|
||||||
|
$scope.signedIn();
|
||||||
|
}
|
||||||
|
|
||||||
UserService.load();
|
UserService.load();
|
||||||
$location.path($scope.redirectUrl ? $scope.redirectUrl : '/');
|
|
||||||
|
// Redirect to the specified page or the landing page
|
||||||
|
// Note: The timeout of 500ms is needed to ensure dialogs containing sign in
|
||||||
|
// forms get removed before the location changes.
|
||||||
|
$timeout(function() {
|
||||||
|
if ($scope.redirectUrl == $location.path()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$location.path($scope.redirectUrl ? $scope.redirectUrl : '/');
|
||||||
|
}, 500);
|
||||||
}, function(result) {
|
}, function(result) {
|
||||||
$scope.needsEmailVerification = result.data.needsEmailVerification;
|
$scope.needsEmailVerification = result.data.needsEmailVerification;
|
||||||
$scope.invalidCredentials = result.data.invalidCredentials;
|
$scope.invalidCredentials = result.data.invalidCredentials;
|
||||||
|
@ -1850,8 +1914,9 @@ quayApp.directive('ngBlur', function() {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
quayApp.run(['$location', '$rootScope', 'Restangular', 'UserService', '$http', '$cookieStore', '$timeout',
|
quayApp.run(['$location', '$rootScope', 'Restangular', 'UserService', 'PlanService', '$http', '$cookieStore', '$timeout',
|
||||||
function($location, $rootScope, Restangular, UserService, $http, $cookieStore, $timeout) {
|
function($location, $rootScope, Restangular, UserService, PlanService, $http, $cookieStore, $timeout) {
|
||||||
|
// Handle session expiration.
|
||||||
Restangular.setErrorInterceptor(function(response) {
|
Restangular.setErrorInterceptor(function(response) {
|
||||||
if (response.status == 401) {
|
if (response.status == 401) {
|
||||||
$('#sessionexpiredModal').modal({});
|
$('#sessionexpiredModal').modal({});
|
||||||
|
@ -1861,6 +1926,9 @@ quayApp.run(['$location', '$rootScope', 'Restangular', 'UserService', '$http', '
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Check if we need to redirect based on a previously chosen plan.
|
||||||
|
PlanService.handleNotedPlan();
|
||||||
|
|
||||||
var changeTab = function(activeTab) {
|
var changeTab = function(activeTab) {
|
||||||
$timeout(function() {
|
$timeout(function() {
|
||||||
$('a[data-toggle="tab"]').each(function(index) {
|
$('a[data-toggle="tab"]').each(function(index) {
|
||||||
|
|
|
@ -38,10 +38,17 @@ function PlansCtrl($scope, $location, UserService, PlanService) {
|
||||||
$scope.user = currentUser;
|
$scope.user = currentUser;
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
|
$scope.signedIn = function() {
|
||||||
|
$('#signinModal').modal('hide');
|
||||||
|
PlanService.handleNotedPlan();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
$scope.buyNow = function(plan) {
|
$scope.buyNow = function(plan) {
|
||||||
if ($scope.user && !$scope.user.anonymous) {
|
if ($scope.user && !$scope.user.anonymous) {
|
||||||
document.location = '/user?plan=' + plan;
|
document.location = '/user?plan=' + plan;
|
||||||
} else {
|
} else {
|
||||||
|
PlanService.notePlan(plan);
|
||||||
$('#signinModal').modal({});
|
$('#signinModal').modal({});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -50,6 +57,7 @@ function PlansCtrl($scope, $location, UserService, PlanService) {
|
||||||
if ($scope.user && !$scope.user.anonymous) {
|
if ($scope.user && !$scope.user.anonymous) {
|
||||||
document.location = '/organizations/new/?plan=' + plan;
|
document.location = '/organizations/new/?plan=' + plan;
|
||||||
} else {
|
} else {
|
||||||
|
PlanService.notePlan(plan);
|
||||||
$('#signinModal').modal({});
|
$('#signinModal').modal({});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -106,7 +114,7 @@ function RepoListCtrl($scope, Restangular, UserService) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function LandingCtrl($scope, $timeout, $location, Restangular, UserService, KeyService) {
|
function LandingCtrl($scope, $timeout, $location, Restangular, UserService, KeyService, PlanService) {
|
||||||
$scope.namespace = null;
|
$scope.namespace = null;
|
||||||
|
|
||||||
$scope.$watch('namespace', function(namespace) {
|
$scope.$watch('namespace', function(namespace) {
|
||||||
|
@ -1270,7 +1278,7 @@ function OrgsCtrl($scope, UserService) {
|
||||||
function NewOrgCtrl($scope, $routeParams, $timeout, $location, UserService, PlanService, Restangular) {
|
function NewOrgCtrl($scope, $routeParams, $timeout, $location, UserService, PlanService, Restangular) {
|
||||||
$scope.loading = true;
|
$scope.loading = true;
|
||||||
|
|
||||||
$scope.$watch( function () { return UserService.currentUser(); }, function (currentUser) {
|
$scope.$watch(function () { return UserService.currentUser(); }, function (currentUser) {
|
||||||
$scope.user = currentUser;
|
$scope.user = currentUser;
|
||||||
$scope.loading = false;
|
$scope.loading = false;
|
||||||
}, true);
|
}, true);
|
||||||
|
@ -1288,6 +1296,16 @@ function NewOrgCtrl($scope, $routeParams, $timeout, $location, UserService, Plan
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$scope.signedIn = function() {
|
||||||
|
PlanService.handleNotedPlan();
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.signinStarted = function() {
|
||||||
|
PlanService.getMinimumPlan(1, true, function(plan) {
|
||||||
|
PlanService.notePlan(plan.stripeId);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
$scope.setPlan = function(plan) {
|
$scope.setPlan = function(plan) {
|
||||||
$scope.currentPlan = plan;
|
$scope.currentPlan = plan;
|
||||||
};
|
};
|
||||||
|
|
|
@ -43,7 +43,8 @@
|
||||||
<h4 class="panel-title">Sign In</h4>
|
<h4 class="panel-title">Sign In</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div class="signin-form" redirect-url="'/organizations/new'"></div>
|
<div class="signin-form" redirect-url="'/organizations/new'" sign-in-started="signinStarted()"
|
||||||
|
signed-in="signedIn()"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -83,7 +83,7 @@
|
||||||
<h4 class="modal-title">Please Sign In</h4>
|
<h4 class="modal-title">Please Sign In</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
Please sign into Quay in order to continue
|
<div class="signin-form" signed-in="signedIn()" redirect-url="'/plans/'"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||||
|
|
Reference in a new issue