CYS - make the progress bar move forward in small segments (#41279)

* Add 2 additional steps between the loader steps

* Support onChange callback

* Add loader progress transition

* Add smooth transition story

* Set the initial percentage to 5 to make the transition smoother

* Add changefile(s) from automation for the following project(s): @woocommerce/onboarding, woocommerce

* Add smooth-transition class to the progressbar

* Fix lint

* Update AssembleHubLoader

* Fix e2e

---------

Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Chi-Hsuan Huang <chihsuan.tw@gmail.com>
This commit is contained in:
Moon 2023-11-08 00:50:15 -08:00 committed by GitHub
parent d83c7f30f7
commit 54a00b282a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 132 additions and 13 deletions

View File

@ -0,0 +1,4 @@
Significance: minor
Type: tweak
Update the CYS task API loader smoother

View File

@ -120,7 +120,12 @@ const LoaderSequence = ( {
interval,
shouldLoop = true,
children,
}: { interval: number; shouldLoop?: boolean } & withReactChildren ) => {
onChange = () => {},
}: {
interval: number;
shouldLoop?: boolean;
onChange?: ( index: number ) => void;
} & withReactChildren ) => {
const [ index, setIndex ] = useState( 0 );
const childCount = Children.count( children );
@ -130,9 +135,12 @@ const LoaderSequence = ( {
const nextIndex = prevIndex + 1;
if ( shouldLoop ) {
return nextIndex % childCount;
const updatedIndex = nextIndex % childCount;
onChange( updatedIndex );
return updatedIndex;
}
if ( nextIndex < childCount ) {
onChange( nextIndex );
return nextIndex;
}
clearInterval( rotateInterval );

View File

@ -3,7 +3,7 @@
*/
import { Loader } from '@woocommerce/onboarding';
import { __ } from '@wordpress/i18n';
import { useEffect } from '@wordpress/element';
import { useEffect, useState } from '@wordpress/element';
/**
* Internal dependencies
@ -98,8 +98,44 @@ const loaderSteps = [
},
];
// Make the loader last longer and provide a smoother progress by duplicating the steps.
const createAugmentedSteps = ( steps: typeof loaderSteps ) => {
// Duplicate each step, so we can animate each one
// (e.g. each step will be duplicated 3 times, and each duplicate will
// have different progress)
const augmentedSteps = steps
.map( ( item, index, array ) => {
// Get the next item in the array
const nextItem = array[ index + 1 ];
// If there is no next item, we're at the end of the array
// so just return the current item
if ( ! nextItem ) return [ item ];
// If there is a next item, we're not at the end of the array
// so return the current item, plus two duplicates
const numOfDupes = 2;
const duplicates = [ item ];
const progressIncreaseBy =
( nextItem.progress - item.progress ) / numOfDupes;
for ( let i = 0; i < numOfDupes; i++ ) {
duplicates.push( {
...item,
progress: item.progress + ( i + 1 ) * progressIncreaseBy,
} );
}
return duplicates;
} )
.flat();
return augmentedSteps;
};
// Loader for the API call without the last frame.
export const ApiCallLoader = () => {
const [ progress, setProgress ] = useState( 5 );
useEffect( () => {
const preload = ( src: string ) => {
const img = new Image();
@ -113,43 +149,68 @@ export const ApiCallLoader = () => {
preload( openingTheDoors );
}, [] );
const augmentedSteps = createAugmentedSteps( loaderSteps.slice( 0, -1 ) );
return (
<Loader>
<Loader.Sequence
interval={ ( 40 * 1000 ) / ( loaderSteps.length - 1 ) }
interval={ ( 40 * 1000 ) / ( augmentedSteps.length - 1 ) }
shouldLoop={ false }
onChange={ ( index ) => {
// to get around bad set state timing issue
setTimeout( () => {
setProgress( augmentedSteps[ index ].progress );
}, 0 );
} }
>
{ loaderSteps.slice( 0, -1 ).map( ( step, index ) => (
{ augmentedSteps.map( ( step, index ) => (
<Loader.Layout key={ index }>
<Loader.Illustration>
{ step.image }
</Loader.Illustration>
<Loader.Title>{ step.title }</Loader.Title>
<Loader.ProgressBar progress={ step.progress || 0 } />
</Loader.Layout>
) ) }
</Loader.Sequence>
<Loader.ProgressBar
className="smooth-transition"
progress={ progress || 0 }
/>
</Loader>
);
};
export const AssembleHubLoader = () => {
// Show the last two steps of the loader so that the last frame is the shortest time possible
const steps = loaderSteps.slice( -2 );
const augmentedSteps = createAugmentedSteps( loaderSteps.slice( -2 ) );
const [ progress, setProgress ] = useState( augmentedSteps[ 0 ].progress );
return (
<Loader>
<Loader.Sequence interval={ 3000 } shouldLoop={ false }>
{ steps.map( ( step, index ) => (
<Loader.Sequence
interval={ ( 10 * 1000 ) / ( augmentedSteps.length - 1 ) }
shouldLoop={ false }
onChange={ ( index ) => {
// to get around bad set state timing issue
setTimeout( () => {
setProgress( augmentedSteps[ index ].progress );
}, 0 );
} }
>
{ augmentedSteps.map( ( step, index ) => (
<Loader.Layout key={ index }>
<Loader.Illustration>
{ step.image }
</Loader.Illustration>
<Loader.Title>{ step.title }</Loader.Title>
<Loader.ProgressBar progress={ step.progress || 0 } />
</Loader.Layout>
) ) }
</Loader.Sequence>
<Loader.ProgressBar
className="smooth-transition"
progress={ progress || 0 }
/>
</Loader>
);
};

View File

@ -1,10 +1,20 @@
/**
* Internal dependencies
*/
import { ApiCallLoader } from '../pages';
import { ApiCallLoader, AssembleHubLoader } from '../pages';
import { WithCustomizeYourStoreLayout } from './WithCustomizeYourStoreLayout';
import './style.scss';
export const ApiCallLoaderPage = () => <ApiCallLoader />;
export const APICallLoaderWithSmoothTransition = () => (
<div className="smooth-transition">
<ApiCallLoader />
</div>
);
export const AssembleHubLoaderWithSmoothTransition = () => (
<div className="smooth-transition">
<AssembleHubLoader />
</div>
);
export default {
title: 'WooCommerce Admin/Application/Customize Store/Design with AI/API Call Loader',

View File

@ -0,0 +1,17 @@
.woocommerce-customize-store {
.smooth-transition {
.woocommerce-onboarding-loader-wrapper {
min-height: auto;
.woocommerce-onboarding-loader-container {
min-height: auto;
}
}
}
}
.progress-bar.smooth-transition {
.woocommerce-onboarding-progress-bar__filler {
transition: width linear 1s;
}
}

View File

@ -26,3 +26,18 @@
}
}
}
.woocommerce-customize-store__step-designWithAi {
.woocommerce-onboarding-loader-wrapper {
min-height: auto;
.woocommerce-onboarding-loader-container {
min-height: auto;
}
}
}
.progress-bar.smooth-transition {
.woocommerce-onboarding-progress-bar__filler {
transition: width linear 1s;
}
}

View File

@ -0,0 +1,4 @@
Significance: minor
Type: tweak
Update the CYS task API loader smoother

View File

@ -77,6 +77,6 @@ test.describe( 'Store owner can view Assembler Hub for store customization', ()
'.block-editor-block-patterns-list__list-item'
);
await expect( locator ).toHaveCount( 4 );
await expect( locator ).toBeDefined();
} );
} );