diff --git a/addons/website/static/src/components/website_loader/website_loader.js b/addons/website/static/src/components/website_loader/website_loader.js index eb499e01c4e..123d1807093 100644 --- a/addons/website/static/src/components/website_loader/website_loader.js +++ b/addons/website/static/src/components/website_loader/website_loader.js @@ -15,6 +15,7 @@ export class WebsiteLoader extends Component { showTips: false, selectedFeatures: [], showWaitingMessages: false, + progressPercentage: 0, }; const defaultMessage = { title: _t("Building your website."), @@ -27,7 +28,7 @@ export class WebsiteLoader extends Component { }); this.waitingMessages = useState([ defaultMessage ]); this.currentWaitingMessage = useState({ ...defaultMessage }); - this.featuresInstallInfo = useState({ nbInstalled: 0, total: undefined }); + this.featuresInstallInfo = { nbInstalled: 0, total: undefined }; useEffect( (selectedFeatures) => { @@ -40,7 +41,10 @@ export class WebsiteLoader extends Component { // and already installed this.trackModules(selectedFeatures).catch(console.error); - return () => clearTimeout(this.trackModulesTimeout); + return () => { + clearTimeout(this.trackModulesTimeout); + clearInterval(this.updateProgressInterval); + }; } }, () => [this.state.selectedFeatures] @@ -71,11 +75,21 @@ export class WebsiteLoader extends Component { (isVisible) => { if (isVisible) { window.addEventListener("beforeunload", this.showRefreshConfirmation); + if (!this.state.selectedFeatures || this.state.selectedFeatures.length === 0) { + // If there is no feature selected, we fake the progress + // for theme installation and configurator_apply. If + // there is at least 1 feature selected, the progress + // bar will be initialized in trackModules(). + this.initProgressBar(); + } } else { window.removeEventListener("beforeunload", this.showRefreshConfirmation); } - return () => window.removeEventListener("beforeunload", this.showRefreshConfirmation); + return () => { + window.removeEventListener("beforeunload", this.showRefreshConfirmation); + clearInterval(this.updateProgressInterval); + }; }, () => [this.state.isVisible] ); @@ -94,6 +108,7 @@ export class WebsiteLoader extends Component { } clearInterval(messagesInterval); clearTimeout(this.trackModulesTimeout); + clearInterval(this.updateProgressInterval); }); // Action needed if the app automatically refreshes or redirects the // page without hiding/removing the WebsiteLoader. This should be @@ -103,6 +118,46 @@ export class WebsiteLoader extends Component { }); } + /** + * Initializes the progress bar. + */ + initProgressBar() { + if (this.updateProgressInterval) { + return; + } + // The progress speed decreases as it approaches its limit. This way, + // users have the feeling that the website creation progressing is fast + // and we prevent them from leaving the page too early (because they + // already did XX% of the process). + // If there is no module to install, we fake the progress from 0 to 100. + // If there is at least 1 module to install, we take 70% of the progress + // bar that we divide by the number of modules to install. We fake the + // progress of each module individually and when all modules are + // installed, we fake the progress of the remaining 30%. + const nbModulesToInstall = this.featuresInstallInfo.total || 0; + const isSomethingToInstall = nbModulesToInstall > 0; + let currentProgress = 0; + // This controls the speed of the progress bar. + const progressStep = isSomethingToInstall ? 0.04 : 0.02; + let progressForAfterModules = isSomethingToInstall ? 30 : 100; + let progressForAllModules = 100 - progressForAfterModules; + let lastTotalInstalled = 0; + let progressPerModule = isSomethingToInstall ? + progressForAllModules / nbModulesToInstall : 0; + + this.updateProgressInterval = setInterval(() => { + if (this.featuresInstallInfo.nbInstalled !== lastTotalInstalled) { + // A module just finished its install. + currentProgress = 0; + lastTotalInstalled = this.featuresInstallInfo.nbInstalled; + } + currentProgress += progressStep; + const limit = this.featuresInstallInfo.nbInstalled === nbModulesToInstall ? + progressForAfterModules : progressPerModule; + this.state.progressPercentage = (lastTotalInstalled * progressPerModule) + + Math.atan(currentProgress) / (Math.PI / 2) * limit; + }, 100); + } /** * Makes a RPC call to track the features and dependencies being installed * and, as long as the number of features installed is different from the @@ -121,8 +176,9 @@ export class WebsiteLoader extends Component { ); if (!this.featuresInstallInfo.total || this.featuresInstallInfo.nbInstalled !== installInfo.nbInstalled) { - Object.assign(this.featuresInstallInfo, installInfo); + this.featuresInstallInfo = installInfo; } + this.initProgressBar(); if (this.featuresInstallInfo.nbInstalled !== this.featuresInstallInfo.total) { this.trackModulesTimeout = setTimeout(() => this.trackModules(selectedFeatures), 1000); } diff --git a/addons/website/static/src/components/website_loader/website_loader.xml b/addons/website/static/src/components/website_loader/website_loader.xml index 51ce83533ec..fb79a5b20f5 100644 --- a/addons/website/static/src/components/website_loader/website_loader.xml +++ b/addons/website/static/src/components/website_loader/website_loader.xml @@ -18,13 +18,13 @@
pointer to build the perfect page in 7 steps.

-
-
+
+