VulpesOS/gaia/apps/email/js/cards/setup_progress.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

215 lines
8.1 KiB
JavaScript
Executable file

/**
* Show a spinner in for two possible steps in the setup of an account:
*
* 1) During the autoconfig step, when figuring out the capabilities of the
* server, and possibly needing an oauth jump.
*
* 2) During the manual config or password flow when finally connecting to the
* service to confirm password and settings are correct.
*
* So the possible flows are:
*
* OAuth: setup_account_info -> setup_progress -> setup_account_prefs
* autoconfig password: setup_account_info -> setup_progress ->
* setup_password -> setup_progress -> setup_account_prefs
* manual config: setup_account_info -> setup_manual_config ->
* setup_progress -> setup_account_prefs
*/
'use strict';
define(function(require) {
var MailAPI = require('api'),
cards = require('cards'),
oauthFetch = require('cards/oauth2/fetch');
return [
require('./base_card')(require('template!./setup_progress.html')),
{
onArgs: function(args) {
this.args = args;
this.callingCard = args.callingCard;
this.creationInProcess = true;
this.pushedSecondaryCard = false;
this.cardHasBeenShown = false;
this.createCanceled = false;
},
extraClasses: ['anim-fade', 'anim-overlay'],
cancelCreation: function() {
if (!this.creationInProcess) {
return;
}
// XXX implement cancellation
},
onCardVisible: function() {
if (this.cardHasBeenShown) {
// If this card was made visible because of a cancel of a secondary
// config card, just go back one more card. The setTimeout is a hack.
// Without it, the final card is not actionable because the
// onTransitionEnd is not fired on this second removeCardAndSuccessors
// call while done as part of finishing up the previous card's
// removeCardAndSuccessors. A queue approach as described in 973038 does
// not help. It seems like the _transitionEnd for the second call does
// not ever fire. Need some async delay, not sure why yet. Otherwise,
// _eatingEventsUntilNextCard ends up as true, since the reset logic for
// it in _onTransitionEnd does not fire. An immediate setTimeout is not
// enough, bothersome that it needs a time threshold.
// pushedSecondaryCard is needed besides just a cardHasBeenShown,
// because this card calls the oauth code, which may show its own cards,
// but then navigate back to this card for a moment. In that case, the
// card needs to stay up and visible.
if (this.pushedSecondaryCard) {
setTimeout(this.onBack.bind(this), 100);
}
} else {
// First time the card has been shown, can now sort out what card to
// show next. This logic could be in onArgs, but it is racy, where
// learnAbout could complete before the animation to this card completes
// which would lead to a case where think we have pushed a secondary
// card, but it is really the first time this card is shown, so it would
// be hard to know if this card was being shown for first time setup
// reasons, or because a cancel/back had occurred. Ideally, learnAbout()
// would be called in setup_account_info, but since it could take a
// moment to complete by waiting for network connections to complete as
// part of autodiscovery, this card is shown to give the user feedback
// that something is happening. Instead of using the card visible state
// as a hack to know the cancel state, switch to a callingCard card
// passing approach so the next card can give a specific callingCard
// cancel signal. However, bug 973038 needs to be solved, or some way
// to remove more than one card at a time. Passing `2` to the
// removeCardAndSuccessors call from this card if callingCard cancel
// signal was received would also work, if we get proper expectations
// around the number of ontransitioned events in that case.
this.cardHasBeenShown = true;
if (!this.args.password) {
this.learnAbout();
} else {
// The manual config pathway.
this.tryCreate();
}
}
},
onBack: function(e) {
if (e) {
e.preventDefault();
}
this.cancelCreation();
this.createCanceled = true;
cards.removeCardAndSuccessors(this, 'animate', 1);
},
/**
* Trigger the back-end's autoconfig logic based on just knowing the user's
* email address to figure out what to do next.
*/
learnAbout: function() {
MailAPI.learnAboutAccount({
emailAddress: this.args.emailAddress
}, function(details) {
var args = this.args;
args.configInfo = details.configInfo;
var result = details.result;
// - We can autoconfig and it's time to use oauth!
if (result === 'need-oauth2') {
oauthFetch(details.configInfo.oauth2Settings, {
login_hint: args.emailAddress
})
.then(function(response) {
// Cancellation means lose the progress card and go back to entering
// the user's email address.
if (response.status === 'cancel') {
this.onBack();
// Successful oauth'ing means time to complete the account creation.
} else if (response.status === 'success') {
args.configInfo.oauth2Secrets = response.secrets;
args.configInfo.oauth2Tokens = response.tokens;
this.tryCreate();
// Any other error means things did not work. Things not working
// implies things will never work and so let's dump the user into
// the manual config card.
} else {
console.error('Unknown oauthFetch status: ' + response.status);
this._divertToManualConfig();
}
}.bind(this), this.onCreationError.bind(this));
// We can autoconfig but we need the user's password.
} else if (result === 'need-password') {
// Track that a secondary card was added that could lead to a cancel
// in that case, need to cancel this card too.
this.pushedSecondaryCard = true;
cards.pushCard(
'setup_account_password', 'animate',
{
displayName: args.displayName,
emailAddress: args.emailAddress
},
'right');
// No configuration data available, the user's only option is manual
// config.
} else { // must be no-config-info and even if not, we'd want this.
this._divertToManualConfig();
}
}.bind(this));
},
/**
* learnAbout decided the only option for the user is to manually configure
* their account. Sorry, user!
*/
_divertToManualConfig: function() {
this.pushedSecondaryCard = true;
cards.pushCard('setup_manual_config', 'animate', {
displayName: this.args.displayName,
emailAddress: this.args.emailAddress
},
'right');
},
tryCreate: function() {
var args = this.args;
var options = {
displayName: args.displayName,
emailAddress: args.emailAddress,
password: args.password,
outgoingPassword: args.outgoingPassword
};
MailAPI.tryToCreateAccount(
options,
args.configInfo || null,
function(err, errDetails, account) {
this.creationInProcess = false;
if (err) {
this.onCreationError(err, errDetails);
} else {
if (this.createCanceled) {
account.deleteAccount();
} else {
this.onCreationSuccess(account);
}
}
}.bind(this));
},
onCreationError: function(err, errDetails) {
this.callingCard.showError(err, errDetails);
cards.removeCardAndSuccessors(this, 'animate', 1);
},
onCreationSuccess: function(account) {
cards.pushCard('setup_account_prefs', 'animate',
{
account: account
});
},
die: function() {
this.cancelCreation();
}
}
];
});