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

Focused Launch success view: fix CTA rendering conditions #51741

Merged
merged 5 commits into from
Apr 12, 2021
Merged
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
6 changes: 3 additions & 3 deletions packages/data-stores/src/launch/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const hasPaidDomain = ( state: State ): boolean => {
if ( ! state.domain ) {
return false;
}
return ! state.domain.is_free;
return ! state.domain.is_free; // @TODO: check if we are ever storing a paid domain
razvanpapadopol marked this conversation as resolved.
Show resolved Hide resolved
};
export const getSelectedDomain = ( state: State ): DomainSuggestions.DomainSuggestion | undefined =>
state.domain;
Expand Down Expand Up @@ -50,7 +50,7 @@ export const isSelectedPlanPaid = ( state: State ): boolean =>
*
* @param state State
*/
export const hasSelectedDomain = ( state: State ): boolean =>
export const hasSelectedDomainOrSubdomain = ( state: State ): boolean =>
razvanpapadopol marked this conversation as resolved.
Show resolved Hide resolved
!! getSelectedDomain( state ) || state.confirmedDomainSelection;

// Completion status of steps is derived from the state of the launch flow
Expand All @@ -68,7 +68,7 @@ export const isStepCompleted = ( state: State, step: LaunchStepType ): boolean =
return !! site?.title;
}
if ( step === LaunchStep.Domain ) {
return select( LAUNCH_STORE ).hasSelectedDomain();
return select( LAUNCH_STORE ).hasSelectedDomainOrSubdomain();
}
return false;
};
Expand Down
2 changes: 1 addition & 1 deletion packages/launch/src/focused-launch/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const FocusedLaunch: React.FunctionComponent = () => {
const [ hasSelectedDomain, selectedPlanProductId ] = useSelect( ( select ) => {
const { planProductId } = select( LAUNCH_STORE ).getState();

return [ select( LAUNCH_STORE ).hasSelectedDomain(), planProductId ];
return [ select( LAUNCH_STORE ).hasSelectedDomainOrSubdomain(), planProductId ];
} );

// @TODO: extract to some hook for reusability (Eg: use-products-from-cart)
Expand Down
27 changes: 17 additions & 10 deletions packages/launch/src/focused-launch/success/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { useDispatch, useSelect } from '@wordpress/data';
/**
* Internal dependencies
*/
import { useSiteDomains, useWillRedirectAfterSuccess } from '../../hooks';
import { useSiteDomains, useHasEcommercePlan } from '../../hooks';
import Confetti from './confetti';
import LaunchContext from '../../context';
import { LAUNCH_STORE, SITE_STORE } from '../../stores';
Expand All @@ -23,17 +23,20 @@ import './style.scss';
// Success is shown when the site is launched but also while the site is still launching.
// This view is technically going to be the selected view in the modal even while the user goes through the checkout flow (which is rendered on top of this view).
const Success: React.FunctionComponent = () => {
const { redirectTo, siteId, getCurrentLaunchFlowUrl } = React.useContext( LaunchContext );
const { redirectTo, siteId, getCurrentLaunchFlowUrl, isInIframe } = React.useContext(
LaunchContext
);

const isSiteLaunching = useSelect(
( select ) => select( SITE_STORE ).isSiteLaunching( siteId ),
[]
);

const isSelectedPlanPaid = useSelect(
( select ) => select( LAUNCH_STORE ).isSelectedPlanPaid(),
[]
);
const [ isSelectedPlanPaid, selectedDomain ] = useSelect( ( select ) => {
const launchStore = select( LAUNCH_STORE );

return [ launchStore.isSelectedPlanPaid(), launchStore.getSelectedDomain() ];
}, [] );

// Save the post before displaying the action buttons and launch succes message
const [ isPostSaved, setIsPostSaved ] = React.useState( false );
Expand All @@ -56,9 +59,13 @@ const Success: React.FunctionComponent = () => {
const [ displayedSiteUrl, setDisplayedSiteUrl ] = React.useState( '' );
const [ hasCopied, setHasCopied ] = React.useState( false );

// if the user has an ecommerce plan or they're using focused launch from wp-admin
// they will be automatically redirected to /checkout, in which case the CTAs are not needed
const willUserBeRedirectedAutomatically = useWillRedirectAfterSuccess();
// Show CTA buttons needed to dismiss the success view only if the user is not going to be redirected to /checkout after launch.
// When we display the CTA buttons?
// 1. All the time for the free flow (no selected custom domain or paid plan).
// 2. If the selected plan isn't Ecommerce and we are in the iframed editor (conditions when we display Checkout Modal).
const isEcommerce = useHasEcommercePlan();
const isFreeFlow = ! selectedDomain && ! isSelectedPlanPaid;
const shouldShowCTAs = isFreeFlow || ( ! isEcommerce && isInIframe );
Copy link
Contributor

@ciampo ciampo Apr 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noting that the same change in logic could have been achieved without refactoring the rest of the files in this PR and the useWillRedirectAfterSuccess hook, which in my opinion was a nice abstraction over the implementation details of the in-editor checkout modal vs redirection.

Suggested change
const shouldShowCTAs = isFreeFlow || ( ! isEcommerce && isInIframe );
const shouldShowCTAs = isFreeFlow || ! willUserBeRedirectedAutomatically;

Copy link
Member Author

@alshakero alshakero Apr 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't like that hook much because:

  1. It's doesn't really determine whether we'll redirect. As you can see here we need to check whether we're in free flow too.

  2. If we move the free flow check inside the hook, then we won't be able to use the hook here. Making it an abstraction that is used once.

Copy link
Contributor

@ciampo ciampo Apr 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's doesn't really determine whether we'll redirect. As you can see here we need to check whether we're in free flow too.

I think that the hook determined correctly whether we'll redirect. Here we're checking for the free flow in order to show/hide CTAs (it's a different check which also relies on knowing if the user will be redirected

If we move the free flow check inside the hook, then we won't be able to use the hook here. Making it an abstraction that is used once.

We wouldn't need to move the free flow check inside the hook, because that free flow check is not needed to know if the page will be redirected — it is only needed to know if we should show the CTA buttons.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that the hook determined correctly whether we'll redirect.

I don't think this is true. The hook would return true for the free plan in wp-admin (! isInIframe || ! ecommercePlan), even though we don't redirect in this case. Right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, now I get your previous reply too — you're correct indeed, we'd need to add the free plan check too.


React.useEffect( () => {
setDisplayedSiteUrl( `https://${ sitePrimaryDomain?.domain }` );
Expand Down Expand Up @@ -105,7 +112,7 @@ const Success: React.FunctionComponent = () => {
<SubTitle tagName="h3">
{ isLaunchComplete ? subtitleTextLaunched : subtitleTextLaunching }
</SubTitle>
{ ! willUserBeRedirectedAutomatically && isLaunchComplete && (
{ shouldShowCTAs && isLaunchComplete && (
<>
<div className="focused-launch-success__url-wrapper">
<span className="focused-launch-success__url-field">{ displayedSiteUrl }</span>
Expand Down
9 changes: 7 additions & 2 deletions packages/launch/src/focused-launch/summary/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,12 @@ const Summary: React.FunctionComponent = () => {
const launchStore = select( LAUNCH_STORE );
const { isSiteTitleStepVisible, domain, planProductId } = launchStore.getState();

return [ launchStore.hasSelectedDomain(), isSiteTitleStepVisible, domain, planProductId ];
return [
launchStore.hasSelectedDomainOrSubdomain(),
isSiteTitleStepVisible,
domain,
planProductId,
];
}, [] );

const isSelectedPlanPaid = useSelect(
Expand Down Expand Up @@ -632,7 +637,7 @@ const Summary: React.FunctionComponent = () => {
<PlanStep
highlighted={ isPlansStepHighlighted }
hasPaidPlan={ hasPaidPlan }
selectedPaidDomain={ selectedDomain && ! selectedDomain.is_free }
selectedPaidDomain={ selectedDomain && ! selectedDomain.is_free } // @TODO: check if selectedDomain can ever be free
razvanpapadopol marked this conversation as resolved.
Show resolved Hide resolved
hasPaidDomain={ hasPaidDomain }
stepIndex={ forwardStepIndex ? stepIndex : undefined }
key={ stepIndex }
Expand Down
2 changes: 1 addition & 1 deletion packages/launch/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ export * from './use-title';
export * from './use-site-domains';
export * from './use-plans';
export * from './use-cart';
export * from './use-will-redirect-after-success';
export * from './use-has-ecommerce-plan';
8 changes: 4 additions & 4 deletions packages/launch/src/hooks/use-cart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { useLocale } from '@automattic/i18n-utils';
import { LAUNCH_STORE, SITE_STORE, PLANS_STORE } from '../stores';
import LaunchContext from '../context';
import { getDomainProduct, getPlanProductForFlow } from '../utils';
import { useSiteDomains, useWillRedirectAfterSuccess } from '../hooks';
import { useSiteDomains, useHasEcommercePlan } from '../hooks';

type LaunchCart = {
goToCheckout: () => Promise< void >; // used in gutenboarding-launch
Expand All @@ -20,7 +20,7 @@ type LaunchCart = {
};

export function useCart(): LaunchCart {
const { siteId, flow, openCheckout } = React.useContext( LaunchContext );
const { siteId, flow, openCheckout, isInIframe } = React.useContext( LaunchContext );

const locale = useLocale();

Expand Down Expand Up @@ -49,7 +49,7 @@ export function useCart(): LaunchCart {

const [ isCartUpdating, setIsCartUpdating ] = React.useState( false );

const willRedirectAfterSuccess = useWillRedirectAfterSuccess();
const hasEcommercePlan = useHasEcommercePlan();

const addProductsToCart = async () => {
if ( isCartUpdating ) {
Expand Down Expand Up @@ -77,7 +77,7 @@ export function useCart(): LaunchCart {
};

const goToCheckoutAndLaunch = async () => {
if ( willRedirectAfterSuccess ) {
if ( ! isInIframe || hasEcommercePlan ) {
// We launch the site first and then open Checkout in these cases:
// - Focused Launch is loaded outside Calypso iframe (in wp-admin)
// - eCommerce plan is selected so Checkout will handle thank-you redirect after purchase
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,15 @@
/**
* External dependencies
*/
import * as React from 'react';
import { useSelect } from '@wordpress/data';
import { useLocale } from '@automattic/i18n-utils';

/**
* Internal dependencies
*/
import { LAUNCH_STORE, PLANS_STORE } from '../stores';
import LaunchContext from '../context';

/**
* When the user has an ecommerce plan or they're using focused launch in wp-admin
* they will be automatically redirected to /checkout after site launch.
* This hook returns true when this is the case
*
* @returns boolean
*/
export function useWillRedirectAfterSuccess(): boolean {
const { isInIframe } = React.useContext( LaunchContext );

export function useHasEcommercePlan(): boolean {
const locale = useLocale();

const planProductId = useSelect(
Expand All @@ -37,5 +26,5 @@ export function useWillRedirectAfterSuccess(): boolean {
[ planProductId, locale ]
);

return ! isInIframe || isEcommercePlan;
return isEcommercePlan;
}