Skip to content

Commit

Permalink
Stepper framework: Add import flow (#62759)
Browse files Browse the repository at this point in the history
* Register User store

* Register Import step

* Setup main redux store in order to consume onboarding import module

* Remove duplicate stepPath

* Add currentRoute hook

* Add removeTrailingSlash util method

* Setup import/ready/preview step path

* Setup import/ready/not step path

* Setup import/ready/wpcom step path

* Setup import/list step path

* Setup import/raedy step path

* Redirect to the home step when urlData is empty

It covers the case when the user refreshes the screen and urlData is not available at that moment.

* Add back and next navigation support

* Add back and next navigation support

* Import module styles

* Replace the  button next with skip to match style with design

* Move step content to the method

* Remove extra margin from the hidden header

* Define goToImporterPage function

* Rename file from utils to util

* Remove helper method from the util

* Load missing persisted state

* Add page title for the import stepper flow

* Divide styling between signup and stepper frameworks

* Move document title setup to a more appropriate place

* Support redirecting to the root import route

* Ignore type check
Steps with slash char cause type issue ( example: import/list )

* Replace state selector with getting value from the site object

Co-authored-by: Omar Alshaker <omar@omaralshaker.com>

* Transform isAtomicSite property to boolean

* Shorthand shouldHideSkipBtn the piece of logic

* Move BASE_ROUTE constant outside the component

* Create ImportWrapper component

* Add global styles for the import steps

* Move BASE_ROUTE constant to the config file

* Introduce generateStepPath util method

* Create importList step component with route

* Create importReady step component with route

* Rename component name

* Create importReadyPreview step component with route

* Create importReadyNot step component with route

* Create importReadyWpcom step component with route

* Update generateStepPath method to return new camelCase routes

* Simplify import component showing only capture step

* Remove obsolete import paths

* Replace redirect method with navigation submit exitFlow

* Fix issue with going back to the capture screen

* Shorthand the if condition

Co-authored-by: Omar Alshaker <omar@omaralshaker.com>
  • Loading branch information
bogiii and alshakero authored May 3, 2022
1 parent f467697 commit c7136fb
Show file tree
Hide file tree
Showing 23 changed files with 410 additions and 10 deletions.
4 changes: 4 additions & 0 deletions client/landing/stepper/declarative-flow/internals/global.scss
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ button {
}
}

.import-step {
@include onboarding-block-margin;
}

/**
* Signup Header
*/
Expand Down
4 changes: 3 additions & 1 deletion client/landing/stepper/declarative-flow/internals/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const FlowRenderer: React.FC< { flow: Flow } > = ( { flow } ) => {
const history = useHistory();
const { search } = useLocation();
const stepNavigation = flow.useStepNavigation( currentRoute, ( path: StepPath ) =>
history.push( generatePath( path + search ), stepPaths )
history.push( generatePath( '/' + path + search ), stepPaths )
);
const pathToClass = ( path: string ) =>
path.replace( /([a-z0-9])([A-Z])/g, '$1-$2' ).toLowerCase();
Expand All @@ -41,6 +41,8 @@ export const FlowRenderer: React.FC< { flow: Flow } > = ( { flow } ) => {
return (
<Switch>
{ stepPaths.map( ( path ) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore - steps with slash char cause type issue ( example: import/list )
const StepComponent = Steps[ path ];
return (
<Route key={ path } path={ `/${ path }` }>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react';
import { Step } from 'calypso/landing/stepper/declarative-flow/internals/types';
import ListStep from 'calypso/signup/steps/import/list';
import { ImportWrapper } from '../import';
import { generateStepPath } from '../import/helper';
import './style.scss';

const ImportList: Step = function ImportStep( props ) {
const { navigation } = props;

return (
<ImportWrapper { ...props }>
<ListStep
goToStep={ ( step, section ) => navigation.goToStep?.( generateStepPath( step, section ) ) }
/>
</ImportWrapper>
);
};

export default ImportList;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import 'signup/steps/import/style/base';
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react';
import { Step } from 'calypso/landing/stepper/declarative-flow/internals/types';
import { recordTracksEvent } from 'calypso/lib/analytics/tracks';
import { ReadyNotStep } from 'calypso/signup/steps/import/ready';
import { ImportWrapper } from '../import';
import { generateStepPath } from '../import/helper';
import './style.scss';

const ImportReadyNot: Step = function ImportStep( props ) {
const { navigation } = props;

return (
<ImportWrapper { ...props }>
<ReadyNotStep
goToStep={ ( step, section ) => navigation.goToStep?.( generateStepPath( step, section ) ) }
recordTracksEvent={ recordTracksEvent }
/>
</ImportWrapper>
);
};

export default ImportReadyNot;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import 'signup/steps/import/style/base';
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React from 'react';
import { useSelector } from 'react-redux';
import { Step } from 'calypso/landing/stepper/declarative-flow/internals/types';
import { useSite } from 'calypso/landing/stepper/hooks/use-site';
import { useSiteSlugParam } from 'calypso/landing/stepper/hooks/use-site-slug-param';
import { recordTracksEvent } from 'calypso/lib/analytics/tracks';
import { ReadyPreviewStep } from 'calypso/signup/steps/import/ready';
import { getUrlData } from 'calypso/state/imports/url-analyzer/selectors';
import { ImportWrapper } from '../import';
import { BASE_ROUTE } from '../import/config';
import { getFinalImporterUrl } from '../import/helper';
import './style.scss';

const ImportReadyPreview: Step = function ImportStep( props ) {
const { navigation } = props;
const siteSlug = useSiteSlugParam();
const site = useSite();
const isAtomicSite = !! site?.options?.is_automated_transfer;
const urlData = useSelector( getUrlData );

/**
↓ Effects
*/
if ( ! urlData ) {
goToHomeStep();
return null;
}

/**
↓ Methods
*/
function goToImporterPage() {
const url = getFinalImporterUrl(
siteSlug as string,
urlData.url,
urlData.platform,
isAtomicSite
);

navigation.submit?.( { url } );
}

function goToHomeStep() {
navigation.goToStep?.( BASE_ROUTE );
}

/**
↓ Renders
*/
return (
<ImportWrapper { ...props }>
<ReadyPreviewStep
urlData={ urlData }
siteSlug={ siteSlug as string }
goToImporterPage={ goToImporterPage }
recordTracksEvent={ recordTracksEvent }
/>
</ImportWrapper>
);
};

export default ImportReadyPreview;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import 'signup/steps/import/style/base';
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react';
import { useSelector } from 'react-redux';
import { Step } from 'calypso/landing/stepper/declarative-flow/internals/types';
import { recordTracksEvent } from 'calypso/lib/analytics/tracks';
import { ReadyAlreadyOnWPCOMStep } from 'calypso/signup/steps/import/ready';
import { getUrlData } from 'calypso/state/imports/url-analyzer/selectors';
import { ImportWrapper } from '../import';
import { BASE_ROUTE } from '../import/config';
import { generateStepPath } from '../import/helper';
import './style.scss';

const ImportReadyNot: Step = function ImportStep( props ) {
const { navigation } = props;
const urlData = useSelector( getUrlData );

/**
↓ Effects
*/
if ( ! urlData ) {
goToHomeStep();
return null;
}

function goToHomeStep() {
navigation.goToStep?.( BASE_ROUTE );
}

return (
<ImportWrapper { ...props }>
<ReadyAlreadyOnWPCOMStep
urlData={ urlData }
goToStep={ ( step, section ) => navigation.goToStep?.( generateStepPath( step, section ) ) }
recordTracksEvent={ recordTracksEvent }
/>
</ImportWrapper>
);
};

export default ImportReadyNot;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import 'signup/steps/import/style/base';
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React from 'react';
import { useSelector } from 'react-redux';
import { Step } from 'calypso/landing/stepper/declarative-flow/internals/types';
import { useSite } from 'calypso/landing/stepper/hooks/use-site';
import { useSiteSlugParam } from 'calypso/landing/stepper/hooks/use-site-slug-param';
import { recordTracksEvent } from 'calypso/lib/analytics/tracks';
import { ReadyStep } from 'calypso/signup/steps/import/ready';
import { getUrlData } from 'calypso/state/imports/url-analyzer/selectors';
import { ImportWrapper } from '../import';
import { BASE_ROUTE } from '../import/config';
import { getFinalImporterUrl } from '../import/helper';
import './style.scss';

const ImportReady: Step = function ImportStep( props ) {
const { navigation } = props;
const siteSlug = useSiteSlugParam();
const site = useSite();
const isAtomicSite = !! site?.options?.is_automated_transfer;
const urlData = useSelector( getUrlData );

/**
↓ Effects
*/
if ( ! urlData ) {
goToHomeStep();
return null;
}

/**
↓ Methods
*/
function goToImporterPage() {
const url = getFinalImporterUrl(
siteSlug as string,
urlData.url,
urlData.platform,
isAtomicSite
);

navigation.submit?.( { url } );
}

function goToHomeStep() {
navigation.goToStep?.( BASE_ROUTE );
}

/**
↓ Renders
*/
return (
<ImportWrapper { ...props }>
<ReadyStep
platform={ urlData?.platform }
goToImporterPage={ goToImporterPage }
recordTracksEvent={ recordTracksEvent }
/>
</ImportWrapper>
);
};

export default ImportReady;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import 'signup/steps/import/style/base';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const BASE_ROUTE = 'import';
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { isEnabled } from '@automattic/calypso-config';
import { camelCase } from 'lodash';
import { ImporterPlatform } from 'calypso/signup/steps/import/types';
import {
getImporterUrl,
getWpComOnboardingUrl,
getWpOrgImporterUrl,
} from 'calypso/signup/steps/import/util';
import { BASE_ROUTE } from './config';
import type { StepPath } from '../../steps-repository';

export function getFinalImporterUrl(
targetSlug: string,
fromSite: string,
platform: ImporterPlatform,
isAtomicSite: boolean | null
) {
let importerUrl;

// Escape WordPress, has two sub-flows "Import everything" and "Content only"
// firstly show import type chooser screen and then decide about importer url
if ( isAtomicSite && platform !== 'wordpress' ) {
importerUrl = getWpOrgImporterUrl( targetSlug, platform );
} else if (
[ 'blogger', 'medium', 'squarespace', 'wix', 'wordpress' ].some( ( platform ) =>
isEnabled( `onboarding/import-from-${ platform }` )
)
) {
importerUrl = getWpComOnboardingUrl( targetSlug, platform, fromSite );
} else {
importerUrl = getImporterUrl( targetSlug, platform, fromSite );
}

return importerUrl;
}

export function generateStepPath( stepName: string, stepSectionName?: string ): StepPath {
// In the stepper framework, the capture screen is on `import` route (instead of `importCapture`)
const excludeStepName = 'capture';
const routes = [ BASE_ROUTE, stepName, stepSectionName ].filter( ( x ) => x !== 'capture' );
const path = routes.join( '_' ).replace( excludeStepName, '' );

return camelCase( path ) as StepPath;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* eslint-disable wpcalypso/jsx-classname-namespace */
import { StepContainer } from '@automattic/onboarding';
import { useI18n } from '@wordpress/react-i18n';
import React, { ReactElement } from 'react';
import DocumentHead from 'calypso/components/data/document-head';
import { useCurrentRoute } from 'calypso/landing/stepper/hooks/use-current-route';
import { recordTracksEvent } from 'calypso/lib/analytics/tracks';
import CaptureStep from 'calypso/signup/steps/import/capture';
import { BASE_ROUTE } from './config';
import { generateStepPath } from './helper';
import type { Step } from '../../types';
import './style.scss';

export const ImportWrapper: Step = function ( props ) {
const { __ } = useI18n();
const { navigation, children } = props;
const currentRoute = useCurrentRoute();
const shouldHideSkipBtn = currentRoute !== BASE_ROUTE;

return (
<>
<DocumentHead title={ __( 'Import your site content' ) } />

<StepContainer
stepName={ 'import-step' }
className={ 'import__onboarding-page' }
hideSkip={ shouldHideSkipBtn }
hideFormattedHeader={ true }
goBack={ navigation.goBack }
goNext={ navigation.goNext }
skipLabelText={ __( "I don't have a site address" ) }
isFullLayout={ true }
stepContent={ children as ReactElement }
recordTracksEvent={ recordTracksEvent }
/>
</>
);
};

const ImportStep: Step = function ImportStep( props ) {
const { navigation } = props;

return (
<ImportWrapper { ...props }>
<CaptureStep
goToStep={ ( step, section ) => navigation.goToStep?.( generateStepPath( step, section ) ) }
/>
</ImportWrapper>
);
};

export default ImportStep;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@import 'signup/steps/import/style/base';

.site-setup.import {
.import__onboarding-page {
@include onboarding-block-margin;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export function redirect( to: string ) {
window.location.href = to;
}

export function removeTrailingSlash( str: string ) {
return str.replace( /\/+$/, '' );
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ export { default as options } from './site-options';
export { default as bloggerStartingPoint } from './blogger-starting-point';
export { default as storeFeatures } from './store-features';
export { default as designSetup } from './design-setup';
export { default as import } from './import';
export { default as importList } from './import-list';
export { default as importReady } from './import-ready';
export { default as importReadyNot } from './import-ready-not';
export { default as importReadyWpcom } from './import-ready-wpcom';
export { default as importReadyPreview } from './import-ready-preview';
export { default as businessInfo } from './business-info';
export { default as storeAddress } from './store-address';
export { default as vertical } from './site-vertical';
Expand All @@ -21,6 +27,12 @@ export type StepPath =
| 'bloggerStartingPoint'
| 'storeFeatures'
| 'designSetup'
| 'import'
| 'importList'
| 'importReady'
| 'importReadyNot'
| 'importReadyWpcom'
| 'importReadyPreview'
| 'businessInfo'
| 'storeAddress'
| 'processing'
Expand Down
Loading

0 comments on commit c7136fb

Please sign in to comment.