Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conditionally update UI on DIFM vs. DIY step of migration flow #97257

Merged
merged 9 commits into from
Dec 17, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Button } from '@automattic/components';
import { useTranslate } from 'i18n-calypso';
import React, { FC } from 'react';
import { HOW_TO_MIGRATE_OPTIONS } from 'calypso/landing/stepper/constants';
import './style.scss';

interface Props {
onClick: ( option: string ) => void;
}

export const DIYOption: FC< Props > = ( { onClick } ) => {
const translate = useTranslate();

return (
<Button
plain
className="how-to-migrate__experiment-diy"
onClick={ () => onClick( HOW_TO_MIGRATE_OPTIONS.DO_IT_MYSELF ) }
>
{ translate( "I'll do it myself" ) }
</Button>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.how-to-migrate__experiment-diy {
color: var(--studio-gray-90);
font-weight: 500;
text-decoration: underline;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* @jest-environment jsdom
*/
import config, { isEnabled } from '@automattic/calypso-config';
import { render, screen } from '@testing-library/react';
import { DIYOption } from '..';

const isMigrationExperimentEnabled = isEnabled( 'migration-flow/experiment' );
const onClick = jest.fn();

const restoreIsMigrationExperimentEnabled = () => {
if ( isMigrationExperimentEnabled ) {
config.enable( 'migration-flow/experiment' );
} else {
config.disable( 'migration-flow/experiment' );
}
};

describe( 'DIYOption', () => {
afterEach( () => {
restoreIsMigrationExperimentEnabled();
} );

it( 'should render the DIY link', () => {
config.enable( 'migration-flow/experiment' );

render( <DIYOption onClick={ onClick } /> );

expect( screen.queryByText( /I'll do it myself/ ) ).toBeInTheDocument();
} );
} );
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { useHasEnTranslation } from '@automattic/i18n-utils';
import { StepContainer } from '@automattic/onboarding';
import config from '@automattic/calypso-config';
import { PLAN_BUSINESS, getPlan, isWpComBusinessPlan } from '@automattic/calypso-products';
import { NextButton, StepContainer } from '@automattic/onboarding';
import { Icon, copy, globe, lockOutline, scheduled } from '@wordpress/icons';
import { useTranslate } from 'i18n-calypso';
import { FC, useCallback, useMemo } from 'react';
import DocumentHead from 'calypso/components/data/document-head';
Expand All @@ -14,6 +16,7 @@ import { recordTracksEvent } from 'calypso/lib/analytics/tracks';
import { usePresalesChat } from 'calypso/lib/presales-chat';
import useHostingProviderName from 'calypso/site-profiler/hooks/use-hosting-provider-name';
import FlowCard from '../components/flow-card';
import { DIYOption } from './diy-option';
import type { StepProps } from '../../types';
import './style.scss';

Expand All @@ -23,30 +26,22 @@ interface Props extends StepProps {
}

const SiteMigrationHowToMigrate: FC< Props > = ( props ) => {
const { navigation, headerText } = props;

const { navigation, headerText, stepName, subHeaderText } = props;
const isMigrationExperimentEnabled = config.isEnabled( 'migration-flow/experiment' );
const translate = useTranslate();
const importSiteQueryParam = useQuery().get( 'from' ) || '';
const site = useSite();
const { mutate: cancelMigration } = useMigrationCancellation( site?.ID );

usePresalesChat( 'wpcom' );

const hasEnTranslation = useHasEnTranslation();

const options = useMemo(
() => [
{
label: translate( 'Do it for me' ),
description: hasEnTranslation(
description: translate(
"Share your site with us. We'll review it and handle the migration if possible."
)
? translate(
"Share your site with us. We'll review it and handle the migration if possible."
)
: translate(
"Share your site with us, and we'll review it and handle the migration if possible."
),
),
value: HOW_TO_MIGRATE_OPTIONS.DO_IT_FOR_ME,
selected: true,
},
Expand All @@ -61,6 +56,38 @@ const SiteMigrationHowToMigrate: FC< Props > = ( props ) => {
[ translate ]
);

// Extract the display of items to a separate component if we keep this version post-experiment,
// as this format is also used on the site identification page and further into the DIFM flow.
const experimentalOptions = useMemo(
() => [
{
icon: lockOutline,
description: translate(
'Upgrade your site and securely share access to your current site.'
),
},
{
icon: copy,
description: translate(
"We'll bring over a copy of your site, without affecting the current live version."
),
},
{
icon: scheduled,
description: translate(
"You'll get an update on the progress of your migration within 2-3 business days."
),
},
{
icon: globe,
description: translate(
"We'll help you switch your domain over after the migration's completed."
),
},
],
[ translate ]
);

let importSiteHostName = '';

try {
Expand Down Expand Up @@ -88,55 +115,127 @@ const SiteMigrationHowToMigrate: FC< Props > = ( props ) => {
}
};

const hostingProviderSlug = hostingProviderData?.hosting_provider?.slug;
const shouldDisplayHostIdentificationMessage =
hostingProviderSlug &&
hostingProviderSlug !== 'unknown' &&
hostingProviderSlug !== 'automattic';

const stepContent = (
<div className="how-to-migrate__list">
{ options.map( ( option, i ) => (
<FlowCard
key={ i }
title={ option.label }
text={ option.description }
onClick={ () => handleClick( option.value ) }
/>
) ) }
</div>
);

const platformText = shouldDisplayHostIdentificationMessage
? translate( 'Your WordPress site is hosted with %(hostingProviderName)s.', {
args: { hostingProviderName },
} )
: '';

const goBack = useCallback( () => {
cancelMigration();
navigation.goBack?.();
}, [ cancelMigration, navigation ] );

const renderSubHeaderText = () => {
if ( isMigrationExperimentEnabled ) {
const planName = getPlan( PLAN_BUSINESS )?.getTitle() ?? '';
const isBusinessPlan = site?.plan?.product_slug
? isWpComBusinessPlan( site?.plan?.product_slug )
: false;

return isBusinessPlan
? // translators: %(planName)s is the name of the Business plan.
translate(
'Save yourself the headache of migrating. Our expert team takes care of everything without interrupting your current site. Plus it’s included in your %(planName)s plan.',
{
args: {
planName,
},
}
)
: translate(
'Save yourself the headache of migrating. Our expert team takes care of everything without interrupting your current site. Plus you get 50% off our annual %(planName)s plan.',
{
args: {
planName,
},
}
);
}

// Maybe extract this code to a separate component if we keep it post-experiment.
const hostingProviderSlug = hostingProviderData?.hosting_provider?.slug;
const shouldDisplayHostIdentificationMessage =
hostingProviderSlug &&
hostingProviderSlug !== 'unknown' &&
hostingProviderSlug !== 'automattic';

return shouldDisplayHostIdentificationMessage
? // translators: %(hostingProviderName)s is the name of the hosting provider.
translate( 'Your WordPress site is hosted with %(hostingProviderName)s.', {
args: { hostingProviderName },
} )
: '';
};

const renderStepContent = () => {
if ( isMigrationExperimentEnabled ) {
return (
<div className="how-to-migrate__experiment-expectations">
<NextButton onClick={ () => handleClick( HOW_TO_MIGRATE_OPTIONS.DO_IT_FOR_ME ) }>
{ translate( 'Get started' ) }
</NextButton>
<div className="how-to-migrate__process-details">
<p className="how-to-migrate__process-details-title">{ translate( 'How it works' ) }</p>
<ul className="how-to-migrate__process-details-list">
{ experimentalOptions.map( ( option, index ) => (
<li key={ index } className="how-to-migrate__process-details-list-item">
<Icon
className="how-to-migrate__process-details-icon"
icon={ option.icon }
size={ 24 }
/>
<p className="how-to-migrate__process-details-description">
{ option.description }
</p>
</li>
) ) }
</ul>
</div>
</div>
);
}

return (
<div className="how-to-migrate__list">
{ options.map( ( option, i ) => (
<FlowCard
key={ i }
title={ option.label }
text={ option.description }
onClick={ () => handleClick( option.value ) }
/>
) ) }
</div>
);
};

return (
<>
<DocumentHead title={ translate( 'How do you want to migrate?' ) } />
<DocumentHead
title={
isMigrationExperimentEnabled
? translate( 'Let us migrate your site' )
: translate( 'How do you want to migrate?' )
}
/>
<StepContainer
stepName={ props.stepName ?? 'site-migration-how-to-migrate' }
stepName={ stepName ?? 'site-migration-how-to-migrate' }
className="how-to-migrate"
shouldHideNavButtons={ false }
hideSkip
formattedHeader={
<FormattedHeader
id="how-to-migrate-header"
headerText={ headerText ?? translate( 'How do you want to migrate?' ) }
subHeaderText={ props.subHeaderText || platformText }
headerText={
headerText ?? isMigrationExperimentEnabled
? translate( 'Let us migrate your site' )
: translate( 'How do you want to migrate?' )
}
subHeaderText={ subHeaderText || renderSubHeaderText() }
align="center"
/>
}
stepContent={ stepContent }
stepContent={ renderStepContent() }
recordTracksEvent={ recordTracksEvent }
goBack={ goBack }
customizedActionButtons={
isMigrationExperimentEnabled ? <DIYOption onClick={ handleClick } /> : undefined
}
/>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,63 @@
margin: 0 auto;
}
}

.how-to-migrate__experiment-expectations {
padding: 0 0 60px;

@include break-large {
padding: 0;
}

.action-buttons__next {
display: block;
margin: auto;
width: 50%;
}

.how-to-migrate__process-details {
margin: 40px auto 0 auto;
max-width: 350px;

&-title {
color: var(--studio-gray-100);
font-size: 1.25rem;
font-weight: 500;
margin-bottom: 0.5rem;
text-align: center;
}

&-list {
background-color: #f6f7f7;
font-size: 0.75rem;
list-style: none;
margin: 0;
padding: 2rem;

&-item {
display: flex;
gap: 0.5rem;
margin-bottom: 1rem;

&:last-child {
margin-bottom: 0;
}
}
}

&-icon {
background-color: #dcdcde;
border: 2px solid #dcdcde;
border-radius: 4px;
display: flex;
fill: var(--studio-gray-70);
flex: 0 0 24px;
padding: 4px;
}

&-description {
color: var(--studio-black);
line-height: 1.66666667;
}
}
}
Loading
Loading