Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions client/blocks/product-purchase-features-list/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import {
WPCOM_FEATURES_WORDADS,
TYPE_WOOEXPRESS_MEDIUM,
TYPE_WOOEXPRESS_SMALL,
TYPE_WOO_HOSTED_BASIC,
TYPE_WOO_HOSTED_PRO,
TYPE_100_YEAR,
TYPE_STARTER,
} from '@automattic/calypso-products';
Expand Down Expand Up @@ -395,6 +397,8 @@ export class ProductPurchaseFeaturesList extends Component {
[ TYPE_ECOMMERCE ]: () => this.getEcommerceFeatures(),
[ TYPE_WOOEXPRESS_MEDIUM ]: () => this.getEcommerceFeatures(),
[ TYPE_WOOEXPRESS_SMALL ]: () => this.getEcommerceFeatures(),
[ TYPE_WOO_HOSTED_BASIC ]: () => this.getEcommerceFeatures(),
[ TYPE_WOO_HOSTED_PRO ]: () => this.getEcommerceFeatures(),
[ TYPE_BUSINESS ]: () => this.getBusinessFeatures(),
[ TYPE_PREMIUM ]: () => this.getPremiumFeatures(),
[ TYPE_PERSONAL ]: () => this.getPersonalFeatures(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ export const useQueryHandler = ( {
return externalInitialQuery;
}

if ( currentSiteUrl?.endsWith( 'commerce-garden.com' ) ) {
return 'My Commerce Site';
}

if ( currentSiteUrl ) {
return new URL( currentSiteUrl ).host.replace( /\.(wordpress|wpcomstaging)\.com$/, '' );
}
Expand Down
2 changes: 1 addition & 1 deletion client/dashboard/sites/overview-plan-card/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ function CommerceGardenPlanCard( {
} ) {
const getBillingLinkProps = () => {
if ( site.plan?.is_free ) {
return { externalLink: `/plans/${ site.slug }` };
return { externalLink: `/setup/woo-hosted/domains?siteSlug=${ site.slug }` };
}

if ( ! isDashboardBackport() ) {
Expand Down
15 changes: 15 additions & 0 deletions client/landing/stepper/declarative-flow/flows/woo-hosted/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# woo-hosted flow

## Testing instructions

Please improve the instructions on how to test this flow.

1. Go to /setup/woo-hosted.

## Owned by

@michaeldcain

## Context

<https://wp.me/pgzWbf-ND>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.is-section-stepper .woo-hosted {
.step-container-v2__top-bar-wordpress-logo-wrapper,
.step-container-v2__top-bar-divider {
display: none;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
import { WOO_HOSTED_FLOW, addPlanToCart, addProductsToCart } from '@automattic/onboarding';
import { MinimalRequestCartProduct } from '@automattic/shopping-cart';
import { useDispatch, useSelect } from '@wordpress/data';
import { addQueryArgs, getQueryArgs } from '@wordpress/url';
import { useEffect, useRef } from 'react';
import { SIGNUP_DOMAIN_ORIGIN } from 'calypso/lib/analytics/signup';
import { useQuery } from '../../../hooks/use-query';
import { useSiteSlug } from '../../../hooks/use-site-slug';
import { ONBOARD_STORE } from '../../../stores';
import { stepsWithRequiredLogin } from '../../../utils/steps-with-required-login';
import { STEPS } from '../../internals/steps';
import { AssertConditionState, ProvidedDependencies } from '../../internals/types';
import type { FlowV2 } from '../../internals/types';
import type { DomainSuggestion } from '@automattic/api-core';
import type { OnboardActions, OnboardSelect } from '@automattic/data-stores';
import './style.scss';

function initialize() {
const steps = [ STEPS.DOMAIN_SEARCH, STEPS.USE_MY_DOMAIN, STEPS.UNIFIED_PLANS ];

return stepsWithRequiredLogin( steps );
}

const wooHosted: FlowV2< typeof initialize > = {
name: WOO_HOSTED_FLOW,
__experimentalUseBuiltinAuth: true,
isSignupFlow: false,
initialize,

useStepsProps() {
return {
[ STEPS.UNIFIED_PLANS.slug ]: {
//isInSignup: false,
displayedIntervals: [ 'monthly', 'yearly' ],
},
};
},

useStepNavigation( currentStep, navigate ) {
const backTo = useQuery().get( 'back_to' );
const flowName = this.name;
const siteSlug = useSiteSlug()!;
const { getDomainCartItem } = useSelect(
( select ) => ( {
getDomainCartItem: ( select( ONBOARD_STORE ) as OnboardSelect ).getDomainCartItem,
} ),
[]
);
const {
setDomain,
setDomainCartItem,
setDomainCartItems,
setPlanCartItem,
setProductCartItems,
setSignupDomainOrigin,
setSiteUrl,
setHideFreePlan,
} = useDispatch( ONBOARD_STORE ) as OnboardActions;

const returnUrl = backTo || `/sites/${ siteSlug }`;

const submittedDomains = useRef( false );

function goBack() {
if ( currentStep === STEPS.DOMAIN_SEARCH.slug ) {
return window.location.assign( returnUrl );
}

if ( currentStep === STEPS.UNIFIED_PLANS.slug ) {
if ( ! submittedDomains.current ) {
return window.location.assign( returnUrl );
}

return navigate( STEPS.DOMAIN_SEARCH.slug );
}

if ( currentStep === STEPS.USE_MY_DOMAIN.slug ) {
return navigate( STEPS.DOMAIN_SEARCH.slug );
}

return window.location.assign( returnUrl );
}

async function submit( providedDependencies: ProvidedDependencies = {} ) {
switch ( currentStep ) {
case STEPS.DOMAIN_SEARCH.slug: {
if ( ! providedDependencies ) {
throw new Error( 'No provided dependencies found' );
}

if ( providedDependencies.navigateToUseMyDomain ) {
const currentQueryArgs = getQueryArgs( window.location.href );

const useMyDomainURL = addQueryArgs( 'use-my-domain', {
...currentQueryArgs,
initialQuery: providedDependencies.lastQuery,
} );

return navigate( useMyDomainURL as typeof currentStep );
}

submittedDomains.current = true;

const suggestion = providedDependencies.suggestion as DomainSuggestion;

setSiteUrl( providedDependencies.siteUrl as string );
setDomain( suggestion );
setDomainCartItem( providedDependencies.domainItem as MinimalRequestCartProduct );
setDomainCartItems( providedDependencies.domainCart as MinimalRequestCartProduct[] );
setSignupDomainOrigin( providedDependencies.signupDomainOrigin as string );
setHideFreePlan( true );

return navigate( STEPS.UNIFIED_PLANS.slug );
}
case STEPS.USE_MY_DOMAIN.slug: {
setSignupDomainOrigin( SIGNUP_DOMAIN_ORIGIN.USE_YOUR_DOMAIN );

if (
providedDependencies &&
'mode' in providedDependencies &&
providedDependencies.mode &&
providedDependencies.domain
) {
const destination = addQueryArgs( '/use-my-domain', {
...getQueryArgs( window.location.href ),
step: providedDependencies.mode,
initialQuery: providedDependencies.domain,
} );
return navigate( destination as typeof currentStep );
}

if ( providedDependencies && 'domainCartItem' in providedDependencies ) {
setHideFreePlan( true );
setDomainCartItem( providedDependencies.domainCartItem as MinimalRequestCartProduct );
}

submittedDomains.current = true;

return navigate( STEPS.UNIFIED_PLANS.slug );
}
case STEPS.UNIFIED_PLANS.slug: {
const cartItems = providedDependencies.cartItems;
const [ pickedPlan, ...products ] = cartItems ?? [];

// Save plan and products to the store for future reference
setPlanCartItem( pickedPlan );
setProductCartItems( products.filter( ( product ) => product !== null ) );

// Add plan to cart if one was selected
if ( pickedPlan ) {
await addPlanToCart( siteSlug, flowName, true, '', pickedPlan );
}

// Get domain from store (set in domains step) and add to cart
const domainCartItem = getDomainCartItem();
if ( domainCartItem ) {
await addProductsToCart( siteSlug, flowName, [ domainCartItem ] );
}

return window.location.assign(
`/checkout/${ siteSlug }?redirect_to=${ encodeURIComponent( returnUrl ) }`
);
}
}
}

return { submit, goBack };
},
useAssertConditions() {
const siteSlug = useSiteSlug();

if ( ! siteSlug ) {
window.location.assign( '/sites' );
return { state: AssertConditionState.FAILURE, message: 'siteSlug is required' };
}

return { state: AssertConditionState.SUCCESS };
},
useSideEffect( currentStepSlug ) {
const { resetOnboardStore } = useDispatch( ONBOARD_STORE ) as OnboardActions;

/**
* Clears the onboard store when entering the flow.
* This ensures the user starts with a clean slate.
*/
useEffect( () => {
if ( ! currentStepSlug ) {
resetOnboardStore();
}
}, [ currentStepSlug, resetOnboardStore ] );
},
};

export default wooHosted;
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
ONBOARDING_UNIFIED_FLOW,
DOMAIN_FLOW,
PLAN_UPGRADE_FLOW,
WOO_HOSTED_FLOW,
} from '@automattic/onboarding';

const FLOWS_USING_STEP_CONTAINER_V2 = [
Expand All @@ -18,6 +19,7 @@ const FLOWS_USING_STEP_CONTAINER_V2 = [
ONBOARDING_UNIFIED_FLOW,
DOMAIN_FLOW,
PLAN_UPGRADE_FLOW,
WOO_HOSTED_FLOW,
];

export const shouldUseStepContainerV2 = ( flow: string ) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
isNewHostedSiteCreationFlow,
isNewsletterFlow,
isOnboardingFlow,
isWooHostedFlow,
Step,
StepContainer,
} from '@automattic/onboarding';
Expand Down Expand Up @@ -234,6 +235,10 @@ const DomainSearchStep: StepType< {
return __( 'Find the perfect domain' );
}

if ( isWooHostedFlow( flow ) ) {
return __( 'Make your store unforgettable' );
}

return __( 'Claim your space on the web' );
}, [ flow, __ ] );

Expand All @@ -245,10 +250,15 @@ const DomainSearchStep: StepType< {
if ( isCopySiteFlow( flow ) ) {
return __( 'Make your copied site unique with a custom domain all of its own.' );
}

if ( isHundredYearPlanFlow( flow ) || isHundredYearDomainFlow( flow ) ) {
return __( 'Secure your 100-Year domain and start building your legacy.' );
}

if ( isWooHostedFlow( flow ) ) {
return __( 'Choose a site address that puts your brand front and center.' );
}

return __( 'Make it yours with a .com, .blog, or one of 350+ domain options.' );
}, [ flow, __ ] );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
ONBOARDING_UNIFIED_FLOW,
PLAN_UPGRADE_FLOW,
START_WRITING_FLOW,
WOO_HOSTED_FLOW,
Step,
useStepPersistedState,
} from '@automattic/onboarding';
Expand All @@ -29,7 +30,7 @@ import { getTheme, getThemeType } from 'calypso/state/themes/selectors';
import { shouldUseStepContainerV2 } from '../../../helpers/should-use-step-container-v2';
import { playgroundPlansIntent } from '../playground/lib/plans';
import UnifiedPlansStep from './unified-plans-step';
import { getIntervalType, getVisualSplitPlansIntent } from './util';
import { getIntervalType, getVisualSplitPlansIntent, SupportedIntervalTypes } from './util';
import type { Step as StepType } from '../../types';
import type { PlansIntent } from '@automattic/plans-grid-next';
import type { MinimalRequestCartProduct } from '@automattic/shopping-cart';
Expand Down Expand Up @@ -73,6 +74,8 @@ function getPlansIntent( flowName: string | null ): PlansIntent | null {
return 'plans-affiliate';
case PLAN_UPGRADE_FLOW:
return 'plans-upgrade';
case WOO_HOSTED_FLOW:
return 'plans-woo-hosted';
default:
return null;
}
Expand All @@ -87,6 +90,7 @@ type ProvidedDependencies = {
const PlansStepAdaptor: StepType< {
submits: ProvidedDependencies;
accepts: {
displayedIntervals?: SupportedIntervalTypes[];
isInSignup?: boolean;
isStepperUpgradeFlow?: boolean;
selectedFeature?: string;
Expand All @@ -98,7 +102,8 @@ const PlansStepAdaptor: StepType< {
};
};
} > = ( props ) => {
const { isInSignup, isStepperUpgradeFlow, selectedFeature, wrapperProps } = props;
const { displayedIntervals, isInSignup, isStepperUpgradeFlow, selectedFeature, wrapperProps } =
props;
const [ stepState, setStepState ] = useStepPersistedState< ProvidedDependencies >( 'plans-step' );
const siteSlug = useSiteSlug();

Expand Down Expand Up @@ -224,6 +229,7 @@ const PlansStepAdaptor: StepType< {
onIntentChange={ handleIntentChange }
onPlanIntervalUpdate={ onPlanIntervalUpdate }
intervalType={ planInterval }
displayedIntervals={ displayedIntervals }
wrapperProps={ {
hideBack: wrapperProps?.hideBack ?? false,
goBack: wrapperProps?.goBack ?? props.navigation.goBack,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { FREE_THEME } from '@automattic/design-picker';
import {
DOMAIN_FLOW,
isNewHostedSiteCreationFlow,
isWooHostedFlow,
isTailoredSignupFlow,
ONBOARDING_FLOW,
Step,
Expand Down Expand Up @@ -390,6 +391,10 @@ function UnifiedPlansStep( {
return translate( 'The right plan for the right project' );
}

if ( isWooHostedFlow( flowName ) ) {
return translate( 'Select a plan to launch your store' );
}

if ( intent === 'plans-wordpress-hosting' ) {
return translate( 'Managed hosting without limits' );
} else if ( intent === 'plans-website-builder' ) {
Expand Down Expand Up @@ -436,6 +441,12 @@ function UnifiedPlansStep( {
);
}

if ( isWooHostedFlow( flowName ) ) {
return translate(
'Your free trial ends in 14 days - select a plan to keep your online store.'
);
}

if ( intent === 'plans-wordpress-hosting' ) {
return null; // Use PlansFeaturesMain subheader for hosting
}
Expand Down
Loading