woocommerce/plugins/woocommerce-admin/client/launch-your-store/hub/sidebar/xstate.tsx

194 lines
4.4 KiB
TypeScript
Raw Normal View History

/**
* External dependencies
*/
import { ActorRefFrom, sendTo, setup, fromCallback } from 'xstate5';
import React from 'react';
import classnames from 'classnames';
import { getQuery } from '@woocommerce/navigation';
/**
* Internal dependencies
*/
import { LaunchYourStoreHubSidebar } from './components/launch-store-hub';
import type { LaunchYourStoreComponentProps } from '..';
import type { mainContentMachine } from '../main-content/xstate';
import { updateQueryParams, createQueryParamsListener } from '../common';
export type SidebarMachineContext = {
externalUrl: string | null;
mainContentMachineRef: ActorRefFrom< typeof mainContentMachine >;
};
export type SidebarComponentProps = LaunchYourStoreComponentProps & {
context: SidebarMachineContext;
};
export type SidebarMachineEvents =
| { type: 'EXTERNAL_URL_UPDATE' }
| { type: 'OPEN_EXTERNAL_URL'; url: string }
| { type: 'OPEN_WC_ADMIN_URL'; url: string }
| { type: 'OPEN_WC_ADMIN_URL_IN_CONTENT_AREA'; url: string }
| { type: 'LAUNCH_STORE' }
| { type: 'LAUNCH_STORE_SUCCESS' };
const sidebarQueryParamListener = fromCallback( ( { sendBack } ) => {
return createQueryParamsListener( 'sidebar', sendBack );
} );
export const sidebarMachine = setup( {
types: {} as {
context: SidebarMachineContext;
events: SidebarMachineEvents;
input: {
mainContentMachineRef: ActorRefFrom< typeof mainContentMachine >;
};
},
actions: {
openExternalUrl: ( { event } ) => {
if ( event.type === 'OPEN_EXTERNAL_URL' ) {
window.open( event.url, '_self' );
}
},
showLaunchStoreSuccessPage: sendTo(
( { context } ) => context.mainContentMachineRef,
{ type: 'SHOW_LAUNCH_STORE_SUCCESS' }
),
showLoadingPage: sendTo(
( { context } ) => context.mainContentMachineRef,
{ type: 'SHOW_LOADING' }
),
updateQueryParams: (
_,
params: { sidebar?: string; content?: string }
) => {
updateQueryParams( params );
},
},
guards: {
hasSidebarLocation: (
_,
{ sidebarLocation }: { sidebarLocation: string }
) => {
const { sidebar } = getQuery() as { sidebar?: string };
return !! sidebar && sidebar === sidebarLocation;
},
},
actors: {
sidebarQueryParamListener,
},
} ).createMachine( {
id: 'sidebar',
initial: 'navigate',
context: ( { input } ) => ( {
externalUrl: null,
mainContentMachineRef: input.mainContentMachineRef,
} ),
invoke: {
id: 'sidebarQueryParamListener',
src: 'sidebarQueryParamListener',
},
states: {
navigate: {
always: [
{
guard: {
type: 'hasSidebarLocation',
params: { sidebarLocation: 'hub' },
},
target: 'launchYourStoreHub',
},
{
guard: {
type: 'hasSidebarLocation',
params: { sidebarLocation: 'launch-success' },
},
target: 'storeLaunchSuccessful',
},
{
target: 'launchYourStoreHub',
},
],
},
launchYourStoreHub: {
initial: 'preLaunchYourStoreHub',
states: {
preLaunchYourStoreHub: {
always: 'launchYourStoreHub',
// do async stuff here such as retrieving task statuses
},
launchYourStoreHub: {
tags: 'sidebar-visible',
meta: {
component: LaunchYourStoreHubSidebar,
},
on: {
LAUNCH_STORE: {
target: '#storeLaunching',
},
},
},
},
},
storeLaunching: {
id: 'storeLaunching',
initial: 'launching',
states: {
launching: {
tags: 'fullscreen',
entry: { type: 'showLoadingPage' },
on: {
LAUNCH_STORE_SUCCESS: {
target: '#storeLaunchSuccessful',
},
},
},
},
},
storeLaunchSuccessful: {
id: 'storeLaunchSuccessful',
tags: 'fullscreen',
entry: [
{
type: 'updateQueryParams',
params: {
sidebar: 'launch-success',
content: 'launch-store-success',
},
},
{ type: 'showLaunchStoreSuccessPage' },
],
},
openExternalUrl: {
id: 'openExternalUrl',
tags: 'sidebar-visible', // unintuitive but it prevents a layout shift just before leaving
entry: [ 'openExternalUrl' ],
},
},
on: {
EXTERNAL_URL_UPDATE: {
target: '.navigate',
},
OPEN_EXTERNAL_URL: {
target: '#openExternalUrl',
},
OPEN_WC_ADMIN_URL: {},
OPEN_WC_ADMIN_URL_IN_CONTENT_AREA: {},
},
} );
export const SidebarContainer = ( {
children,
className,
}: {
children: React.ReactNode;
className?: string;
} ) => {
return (
<div
className={ classnames(
'launch-your-store-layout__sidebar',
className
) }
>
{ children }
</div>
);
};