2023-04-24 02:08:24 +00:00
/ * *
* External dependencies
* /
2023-05-18 02:50:59 +00:00
import { createMachine , assign , DoneInvokeEvent , actions , spawn } from 'xstate' ;
2023-04-24 02:08:24 +00:00
import { useMachine } from '@xstate/react' ;
2023-05-03 07:54:28 +00:00
import { useEffect , useMemo } from '@wordpress/element' ;
import { resolveSelect , dispatch } from '@wordpress/data' ;
2023-05-14 20:56:47 +00:00
import { navigateTo , getNewPath } from '@woocommerce/navigation' ;
import {
ExtensionList ,
OPTIONS_STORE_NAME ,
COUNTRIES_STORE_NAME ,
Country ,
2023-05-18 02:50:59 +00:00
ONBOARDING_STORE_NAME ,
Extension ,
2023-05-14 20:56:47 +00:00
} from '@woocommerce/data' ;
2023-05-03 07:54:28 +00:00
import { recordEvent } from '@woocommerce/tracks' ;
import { getSetting } from '@woocommerce/settings' ;
import { initializeExPlat } from '@woocommerce/explat' ;
2023-04-24 02:08:24 +00:00
/ * *
* Internal dependencies
* /
import { IntroOptIn } from './pages/IntroOptIn' ;
2023-05-22 03:21:16 +00:00
import {
UserProfile ,
BusinessChoice ,
SellingOnlineAnswer ,
SellingPlatform ,
} from './pages/UserProfile' ;
2023-04-24 02:08:24 +00:00
import { BusinessInfo } from './pages/BusinessInfo' ;
import { BusinessLocation } from './pages/BusinessLocation' ;
2023-05-14 20:56:47 +00:00
import { getCountryStateOptions } from './services/country' ;
import { Loader } from './pages/Loader' ;
2023-05-18 02:50:59 +00:00
import { Extensions } from './pages/Extensions' ;
2023-05-14 20:56:47 +00:00
2023-05-03 07:54:28 +00:00
import './style.scss' ;
2023-04-24 02:08:24 +00:00
// TODO: Typescript support can be improved, but for now lets write the types ourselves
// https://stately.ai/blog/introducing-typescript-typegen-for-xstate
2023-05-03 07:54:28 +00:00
export type InitializationCompleteEvent = {
type : 'INITIALIZATION_COMPLETE' ;
payload : { optInDataSharing : boolean } ;
} ;
2023-04-24 02:08:24 +00:00
export type IntroOptInEvent =
| { type : 'INTRO_COMPLETED' ; payload : { optInDataSharing : boolean } } // can be true or false depending on whether the user opted in or not
| { type : 'INTRO_SKIPPED' ; payload : { optInDataSharing : false } } ; // always false for now
export type UserProfileEvent =
| {
type : 'USER_PROFILE_COMPLETED' ;
payload : {
userProfile : CoreProfilerStateMachineContext [ 'userProfile' ] ;
} ; // TODO: fill in the types for this when developing this page
}
| {
type : 'USER_PROFILE_SKIPPED' ;
payload : { userProfile : { skipped : true } } ;
} ;
export type BusinessInfoEvent = {
type : 'BUSINESS_INFO_COMPLETED' ;
payload : {
businessInfo : CoreProfilerStateMachineContext [ 'businessInfo' ] ;
} ;
} ;
export type BusinessLocationEvent = {
type : 'BUSINESS_LOCATION_COMPLETED' ;
payload : {
businessInfo : CoreProfilerStateMachineContext [ 'businessInfo' ] ;
} ;
} ;
export type ExtensionsEvent = {
type : 'EXTENSIONS_COMPLETED' ;
payload : {
extensionsSelected : CoreProfilerStateMachineContext [ 'extensionsSelected' ] ;
} ;
} ;
2023-05-22 03:21:16 +00:00
// TODO: add types as we develop the pages
export type OnboardingProfile = {
business_choice : BusinessChoice ;
selling_online_answer : SellingOnlineAnswer | null ;
selling_platforms : SellingPlatform [ ] | null ;
skip? : boolean ;
} ;
2023-04-24 02:08:24 +00:00
export type CoreProfilerStateMachineContext = {
optInDataSharing : boolean ;
2023-05-22 03:21:16 +00:00
userProfile : {
businessChoice? : BusinessChoice ;
sellingOnlineAnswer? : SellingOnlineAnswer | null ;
sellingPlatforms? : SellingPlatform [ ] | null ;
skipped? : boolean ;
} ;
2023-04-24 02:08:24 +00:00
geolocatedLocation : {
location : string ;
} ;
extensionsAvailable : ExtensionList [ 'plugins' ] | [ ] ;
extensionsSelected : string [ ] ; // extension slugs
businessInfo : { foo ? : { bar : 'qux' } ; location : string } ;
2023-05-14 20:56:47 +00:00
countries : { [ key : string ] : string } ;
loader : {
progress? : number ;
className? : string ;
useStages? : string ;
stageIndex? : number ;
} ;
2023-04-24 02:08:24 +00:00
} ;
2023-05-03 07:54:28 +00:00
const getAllowTrackingOption = async ( ) = >
resolveSelect ( OPTIONS_STORE_NAME ) . getOption (
'woocommerce_allow_tracking'
) ;
const handleTrackingOption = assign ( {
optInDataSharing : (
_context ,
event : DoneInvokeEvent < 'no' | 'yes' | undefined >
) = > event . data !== 'no' ,
} ) ;
2023-05-18 02:50:59 +00:00
/ * *
* Prefetch it so that @wp / data caches it and there won ' t be a loading delay when its used
* /
const preFetchGetCountries = assign ( {
spawnGetCountriesRef : ( ) = >
spawn (
resolveSelect ( COUNTRIES_STORE_NAME ) . getCountries ( ) ,
'core-profiler-prefetch-countries'
) ,
} ) ;
2023-05-14 20:56:47 +00:00
const getCountries = async ( ) = >
resolveSelect ( COUNTRIES_STORE_NAME ) . getCountries ( ) ;
const handleCountries = assign ( {
countries : ( _context , event : DoneInvokeEvent < Country [ ] > ) = > {
return getCountryStateOptions ( event . data ) ;
} ,
} ) ;
2023-05-22 03:21:16 +00:00
const getOnboardingProfileOption = async ( ) = >
resolveSelect ( OPTIONS_STORE_NAME ) . getOption (
'woocommerce_onboarding_profile'
) ;
const handleOnboardingProfileOption = assign ( {
userProfile : (
_context ,
event : DoneInvokeEvent < OnboardingProfile | undefined >
) = > {
if ( ! event . data ) {
return { } ;
}
const {
business_choice : businessChoice ,
selling_online_answer : sellingOnlineAnswer ,
selling_platforms : sellingPlatforms ,
. . . rest
} = event . data ;
return {
. . . rest ,
businessChoice ,
sellingOnlineAnswer ,
sellingPlatforms ,
} ;
} ,
} ) ;
2023-05-14 20:56:47 +00:00
const redirectToWooHome = ( ) = > {
navigateTo ( { url : getNewPath ( { } , '/' , { } ) } ) ;
} ;
2023-05-03 07:54:28 +00:00
const recordTracksIntroCompleted = ( ) = > {
recordEvent ( 'storeprofiler_step_complete' , {
step : 'store_details' ,
wc_version : getSetting ( 'wcVersion' ) ,
} ) ;
} ;
const recordTracksIntroSkipped = ( ) = > {
recordEvent ( 'storeprofiler_store_details_skip' ) ;
} ;
const recordTracksIntroViewed = ( ) = > {
recordEvent ( 'storeprofiler_step_view' , {
step : 'store_details' ,
wc_version : getSetting ( 'wcVersion' ) ,
} ) ;
} ;
2023-05-22 03:21:16 +00:00
const recordTracksUserProfileViewed = ( ) = > {
recordEvent ( 'storeprofiler_step_view' , {
step : 'user_profile' ,
wc_version : getSetting ( 'wcVersion' ) ,
} ) ;
} ;
const recordTracksUserProfileCompleted = (
_context : CoreProfilerStateMachineContext ,
event : Extract < UserProfileEvent , { type : 'USER_PROFILE_COMPLETED' } >
) = > {
recordEvent ( 'storeprofiler_step_complete' , {
step : 'user_profile' ,
wc_version : getSetting ( 'wcVersion' ) ,
} ) ;
recordEvent ( 'storeprofiler_user_profile' , {
business_choice : event.payload.userProfile.businessChoice ,
selling_online_answer : event.payload.userProfile.sellingOnlineAnswer ,
selling_platforms : event.payload.userProfile.sellingPlatforms
? event . payload . userProfile . sellingPlatforms . join ( )
: null ,
} ) ;
} ;
const recordTracksUserProfileSkipped = ( ) = > {
recordEvent ( 'storeprofiler_user_profile_skip' ) ;
} ;
2023-05-14 20:56:47 +00:00
const recordTracksSkipBusinessLocationViewed = ( ) = > {
recordEvent ( 'storeprofiler_step_view' , {
step : 'skip_business_location' ,
wc_version : getSetting ( 'wcVersion' ) ,
} ) ;
} ;
const recordTracksSkipBusinessLocationCompleted = ( ) = > {
recordEvent ( 'storeprofiler_step_complete' , {
step : 'skp_business_location' ,
wc_version : getSetting ( 'wcVersion' ) ,
} ) ;
} ;
2023-05-03 07:54:28 +00:00
const updateTrackingOption = (
_context : CoreProfilerStateMachineContext ,
event : IntroOptInEvent
) = > {
if (
event . payload . optInDataSharing &&
typeof window . wcTracks . enable === 'function'
) {
window . wcTracks . enable ( ( ) = > {
initializeExPlat ( ) ;
} ) ;
} else if ( ! event . payload . optInDataSharing ) {
window . wcTracks . isEnabled = false ;
}
const trackingValue = event . payload . optInDataSharing ? 'yes' : 'no' ;
dispatch ( OPTIONS_STORE_NAME ) . updateOptions ( {
woocommerce_allow_tracking : trackingValue ,
} ) ;
} ;
2023-05-22 03:21:16 +00:00
const updateOnboardingProfileOption = (
context : CoreProfilerStateMachineContext
) = > {
const { businessChoice , sellingOnlineAnswer , sellingPlatforms , . . . rest } =
context . userProfile ;
return dispatch ( OPTIONS_STORE_NAME ) . updateOptions ( {
woocommerce_onboarding_profile : {
. . . rest ,
business_choice : businessChoice ,
selling_online_answer : sellingOnlineAnswer ,
selling_platforms : sellingPlatforms ,
} ,
} ) ;
} ;
2023-05-14 20:56:47 +00:00
const updateBusinessLocation = ( countryAndState : string ) = > {
return dispatch ( OPTIONS_STORE_NAME ) . updateOptions ( {
woocommerce_default_country : countryAndState ,
} ) ;
} ;
const promiseDelay = ( milliseconds : number ) = > {
return new Promise ( ( resolve ) = > {
setTimeout ( resolve , milliseconds ) ;
} ) ;
} ;
2023-05-03 07:54:28 +00:00
/ * *
* Assigns the optInDataSharing value from the event payload to the context
* /
const assignOptInDataSharing = assign ( {
optInDataSharing : ( _context , event : IntroOptInEvent ) = >
event . payload . optInDataSharing ,
} ) ;
2023-05-18 02:50:59 +00:00
/ * *
* Prefetch it so that @wp / data caches it and there won ' t be a loading delay when its used
* /
const preFetchGetExtensions = assign ( {
extensionsRef : ( ) = >
spawn (
resolveSelect ( ONBOARDING_STORE_NAME ) . getFreeExtensions ( ) ,
'core-profiler-prefetch-extensions'
) ,
} ) ;
const getExtensions = async ( ) = > {
const extensionsBundles = await resolveSelect (
ONBOARDING_STORE_NAME
) . getFreeExtensions ( ) ;
return (
extensionsBundles . find ( ( bundle ) = > bundle . key === 'obw/grow' )
? . plugins || [ ]
) ;
} ;
const handleExtensions = assign ( {
extensionsAvailable : ( _context , event : DoneInvokeEvent < Extension [ ] > ) = >
event . data ,
} ) ;
2023-05-16 00:56:39 +00:00
const coreProfilerMachineActions = {
updateTrackingOption ,
2023-05-18 02:50:59 +00:00
preFetchGetExtensions ,
preFetchGetCountries ,
2023-05-16 00:56:39 +00:00
handleTrackingOption ,
2023-05-18 02:50:59 +00:00
handleExtensions ,
2023-05-16 00:56:39 +00:00
recordTracksIntroCompleted ,
recordTracksIntroSkipped ,
recordTracksIntroViewed ,
2023-05-22 03:21:16 +00:00
recordTracksUserProfileCompleted ,
recordTracksUserProfileSkipped ,
recordTracksUserProfileViewed ,
2023-05-16 00:56:39 +00:00
recordTracksSkipBusinessLocationViewed ,
recordTracksSkipBusinessLocationCompleted ,
assignOptInDataSharing ,
handleCountries ,
2023-05-22 03:21:16 +00:00
handleOnboardingProfileOption ,
2023-05-16 00:56:39 +00:00
redirectToWooHome ,
} ;
const coreProfilerMachineServices = {
getAllowTrackingOption ,
getCountries ,
2023-05-18 02:50:59 +00:00
getExtensions ,
2023-05-22 03:21:16 +00:00
getOnboardingProfileOption ,
2023-05-16 00:56:39 +00:00
} ;
export const coreProfilerStateMachineDefinition = createMachine ( {
2023-04-24 02:08:24 +00:00
id : 'coreProfiler' ,
initial : 'initializing' ,
2023-05-03 07:54:28 +00:00
predictableActionArguments : true , // recommended setting: https://xstate.js.org/docs/guides/actions.html
2023-04-24 02:08:24 +00:00
context : {
// these are safe default values if for some reason the steps fail to complete correctly
// actual defaults displayed to the user should be handled in the steps themselves
optInDataSharing : false ,
userProfile : { skipped : true } ,
geolocatedLocation : { location : 'US:CA' } ,
businessInfo : { location : 'US:CA' } ,
extensionsAvailable : [ ] ,
extensionsSelected : [ ] ,
2023-05-14 20:56:47 +00:00
countries : { } ,
loader : { } ,
2023-04-24 02:08:24 +00:00
} as CoreProfilerStateMachineContext ,
states : {
initializing : {
on : {
2023-05-03 07:54:28 +00:00
INITIALIZATION_COMPLETE : {
target : 'introOptIn' ,
} ,
2023-04-24 02:08:24 +00:00
} ,
2023-05-18 02:50:59 +00:00
entry : [ 'preFetchGetExtensions' , 'preFetchGetCountries' ] ,
2023-04-24 02:08:24 +00:00
invoke : [
{
2023-05-03 07:54:28 +00:00
src : 'getAllowTrackingOption' ,
// eslint-disable-next-line xstate/no-ondone-outside-compound-state -- The invoke.onDone property refers to the invocation (invoke.src) being done, not the onDone property on a state node.
onDone : [
{
actions : [ 'handleTrackingOption' ] ,
target : 'introOptIn' ,
} ,
] ,
onError : {
target : 'introOptIn' , // leave it as initialised default on error
} ,
2023-04-24 02:08:24 +00:00
} ,
] ,
meta : {
progress : 0 ,
} ,
} ,
introOptIn : {
on : {
INTRO_COMPLETED : {
2023-05-22 03:21:16 +00:00
target : 'preUserProfile' ,
2023-04-24 02:08:24 +00:00
actions : [
2023-05-03 07:54:28 +00:00
'assignOptInDataSharing' ,
'updateTrackingOption' ,
2023-04-24 02:08:24 +00:00
] ,
} ,
INTRO_SKIPPED : {
// if the user skips the intro, we set the optInDataSharing to false and go to the Business Location page
2023-05-14 20:56:47 +00:00
target : 'preSkipFlowBusinessLocation' ,
2023-04-24 02:08:24 +00:00
actions : [
2023-05-03 07:54:28 +00:00
'assignOptInDataSharing' ,
'updateTrackingOption' ,
2023-04-24 02:08:24 +00:00
] ,
} ,
} ,
2023-05-03 07:54:28 +00:00
entry : [ 'recordTracksIntroViewed' ] ,
exit : actions.choose ( [
{
cond : ( _context , event ) = >
event . type === 'INTRO_COMPLETED' ,
actions : 'recordTracksIntroCompleted' ,
} ,
{
cond : ( _context , event ) = > event . type === 'INTRO_SKIPPED' ,
actions : 'recordTracksIntroSkipped' ,
} ,
] ) ,
2023-04-24 02:08:24 +00:00
meta : {
progress : 20 ,
component : IntroOptIn ,
} ,
} ,
2023-05-22 03:21:16 +00:00
preUserProfile : {
invoke : {
src : 'getOnboardingProfileOption' ,
onDone : [
{
actions : [ 'handleOnboardingProfileOption' ] ,
target : 'userProfile' ,
} ,
] ,
onError : {
target : 'userProfile' ,
} ,
} ,
} ,
2023-04-24 02:08:24 +00:00
userProfile : {
2023-05-22 03:21:16 +00:00
entry : [ 'recordTracksUserProfileViewed' ] ,
2023-04-24 02:08:24 +00:00
on : {
USER_PROFILE_COMPLETED : {
2023-05-22 03:21:16 +00:00
target : 'postUserProfile' ,
2023-04-24 02:08:24 +00:00
actions : [
assign ( {
userProfile : ( context , event : UserProfileEvent ) = >
event . payload . userProfile , // sets context.userProfile to the payload of the event
} ) ,
] ,
} ,
USER_PROFILE_SKIPPED : {
2023-05-22 03:21:16 +00:00
target : 'postUserProfile' ,
2023-04-24 02:08:24 +00:00
actions : [
assign ( {
userProfile : ( context , event : UserProfileEvent ) = >
event . payload . userProfile , // assign context.userProfile to the payload of the event
} ) ,
] ,
} ,
} ,
2023-05-22 03:21:16 +00:00
exit : actions.choose ( [
{
cond : ( _context , event ) = >
event . type === 'USER_PROFILE_COMPLETED' ,
actions : 'recordTracksUserProfileCompleted' ,
} ,
{
cond : ( _context , event ) = >
event . type === 'USER_PROFILE_SKIPPED' ,
actions : 'recordTracksUserProfileSkipped' ,
} ,
] ) ,
2023-04-24 02:08:24 +00:00
meta : {
progress : 40 ,
component : UserProfile ,
} ,
} ,
2023-05-22 03:21:16 +00:00
postUserProfile : {
invoke : {
src : ( context ) = > {
return updateOnboardingProfileOption ( context ) ;
} ,
onDone : {
target : 'preBusinessInfo' ,
} ,
onError : {
target : 'preBusinessInfo' ,
} ,
} ,
} ,
2023-04-24 02:08:24 +00:00
preBusinessInfo : {
always : [
// immediately transition to businessInfo without any events as long as geolocation parallel has completed
{
target : 'businessInfo' ,
cond : ( ) = > true , // TODO: use a custom function to check on the parallel state using meta when we implement that. https://xstate.js.org/docs/guides/guards.html#guards-condition-functions
} ,
] ,
meta : {
progress : 50 ,
} ,
} ,
businessInfo : {
on : {
BUSINESS_INFO_COMPLETED : {
target : 'preExtensions' ,
actions : [
assign ( {
businessInfo : (
_context ,
event : BusinessInfoEvent
) = > event . payload . businessInfo , // assign context.businessInfo to the payload of the event
} ) ,
] ,
} ,
} ,
meta : {
progress : 60 ,
component : BusinessInfo ,
} ,
} ,
2023-05-14 20:56:47 +00:00
preSkipFlowBusinessLocation : {
invoke : {
src : 'getCountries' ,
onDone : [
{
actions : [ 'handleCountries' ] ,
target : 'skipFlowBusinessLocation' ,
} ,
] ,
onError : {
target : 'skipFlowBusinessLocation' ,
} ,
} ,
} ,
2023-04-24 02:08:24 +00:00
skipFlowBusinessLocation : {
on : {
BUSINESS_LOCATION_COMPLETED : {
2023-05-14 20:56:47 +00:00
target : 'postSkipFlowBusinessLocation' ,
2023-04-24 02:08:24 +00:00
actions : [
assign ( {
businessInfo : (
_context ,
event : BusinessLocationEvent
) = > event . payload . businessInfo , // assign context.businessInfo to the payload of the event
} ) ,
2023-05-14 20:56:47 +00:00
'recordTracksSkipBusinessLocationCompleted' ,
2023-04-24 02:08:24 +00:00
] ,
} ,
} ,
2023-05-14 20:56:47 +00:00
entry : [ 'recordTracksSkipBusinessLocationViewed' ] ,
2023-04-24 02:08:24 +00:00
meta : {
progress : 80 ,
component : BusinessLocation ,
} ,
} ,
2023-05-14 20:56:47 +00:00
postSkipFlowBusinessLocation : {
initial : 'updateBusinessLocation' ,
states : {
updateBusinessLocation : {
entry : assign ( {
loader : {
progress : 10 ,
} ,
} ) ,
invoke : {
src : ( context ) = > {
return updateBusinessLocation (
context . businessInfo . location
) ;
} ,
onDone : {
target : 'progress20' ,
} ,
} ,
} ,
// Although we don't need to wait 3 seconds for the following states
// We will dispaly 20% and 80% progress for 1.5 seconds each
// for the sake of user experience.
progress20 : {
entry : assign ( {
loader : {
progress : 20 ,
} ,
} ) ,
invoke : {
src : ( ) = > {
return promiseDelay ( 1500 ) ;
} ,
onDone : {
target : 'progress80' ,
} ,
} ,
} ,
progress80 : {
entry : assign ( {
loader : {
progress : 80 ,
} ,
} ) ,
invoke : {
src : ( ) = > {
return promiseDelay ( 1500 ) ;
} ,
onDone : {
actions : [ 'redirectToWooHome' ] ,
} ,
} ,
} ,
} ,
meta : {
component : Loader ,
} ,
} ,
2023-04-24 02:08:24 +00:00
preExtensions : {
2023-05-18 02:50:59 +00:00
invoke : {
src : 'getExtensions' ,
onDone : [
{ target : 'extensions' , actions : 'handleExtensions' } ,
] ,
} ,
2023-04-24 02:08:24 +00:00
// add exit action to filter the extensions using a custom function here and assign it to context.extensionsAvailable
exit : assign ( {
extensionsAvailable : ( context ) = > {
return context . extensionsAvailable . filter ( ( ) = > true ) ;
} , // TODO : define an extensible filter function here
} ) ,
meta : {
progress : 70 ,
} ,
} ,
extensions : {
on : {
EXTENSIONS_COMPLETED : {
target : 'settingUpStore' ,
} ,
} ,
meta : {
progress : 80 ,
component : Extensions ,
} ,
} ,
settingUpStore : { } ,
} ,
} ) ;
2023-05-16 00:56:39 +00:00
export const CoreProfilerController = ( {
actionOverrides ,
servicesOverrides ,
} : {
actionOverrides : Partial < typeof coreProfilerMachineActions > ;
servicesOverrides : Partial < typeof coreProfilerMachineServices > ;
} ) = > {
2023-05-03 07:54:28 +00:00
const augmentedStateMachine = useMemo ( ( ) = > {
// When adding extensibility, this is the place to manipulate the state machine definition.
return coreProfilerStateMachineDefinition . withConfig ( {
actions : {
2023-05-16 00:56:39 +00:00
. . . coreProfilerMachineActions ,
. . . actionOverrides ,
2023-05-03 07:54:28 +00:00
} ,
2023-04-24 02:08:24 +00:00
services : {
2023-05-16 00:56:39 +00:00
. . . coreProfilerMachineServices ,
. . . servicesOverrides ,
2023-04-24 02:08:24 +00:00
} ,
2023-05-03 07:54:28 +00:00
} ) ;
2023-05-16 00:56:39 +00:00
} , [ actionOverrides , servicesOverrides ] ) ;
2023-05-03 07:54:28 +00:00
const [ state , send ] = useMachine ( augmentedStateMachine ) ;
2023-05-14 20:56:47 +00:00
const stateValue =
typeof state . value === 'object'
? Object . keys ( state . value ) [ 0 ]
: state . value ;
const currentNodeMeta = state . meta [ ` coreProfiler. ${ stateValue } ` ]
? state . meta [ ` coreProfiler. ${ stateValue } ` ]
2023-04-24 02:08:24 +00:00
: undefined ;
const navigationProgress = currentNodeMeta ? . progress ; // This value is defined in each state node's meta tag, we can assume it is 0-100
const CurrentComponent =
2023-05-16 00:56:39 +00:00
currentNodeMeta ? . component ? ?
( ( ) = > (
< div data - testid = "core-profiler-loading-screen" > Insert Spinner < / div >
) ) ; // If no component is defined for the state then its a loading state
2023-04-24 02:08:24 +00:00
useEffect ( ( ) = > {
document . body . classList . remove ( 'woocommerce-admin-is-loading' ) ;
document . body . classList . add ( 'woocommerce-profile-wizard__body' ) ;
document . body . classList . add ( 'woocommerce-admin-full-screen' ) ;
document . body . classList . add ( 'is-wp-toolbar-disabled' ) ;
return ( ) = > {
document . body . classList . remove (
'woocommerce-profile-wizard__body'
) ;
document . body . classList . remove ( 'woocommerce-admin-full-screen' ) ;
document . body . classList . remove ( 'is-wp-toolbar-disabled' ) ;
} ;
} ) ;
return (
< >
< div
className = { ` woocommerce-profile-wizard__container woocommerce-profile-wizard__step- ${ state . value } ` }
>
2023-05-03 07:54:28 +00:00
{
< CurrentComponent
navigationProgress = { navigationProgress }
sendEvent = { send }
context = { state . context }
/ >
}
2023-04-24 02:08:24 +00:00
< / div >
< / >
) ;
} ;
export default CoreProfilerController ;