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

2504: Add skip paid ads confirmation modal. #2563

Merged
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
2 changes: 2 additions & 0 deletions js/src/setup-mc/setup-stepper/setup-paid-ads/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const ACTION_COMPLETE = 'complete-ads';
export const ACTION_SKIP = 'skip-ads';
48 changes: 37 additions & 11 deletions js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js
eason9487 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ import FaqsSection from '.~/components/paid-ads/faqs-section';
import AppButton from '.~/components/app-button';
import PaidAdsFeaturesSection from './paid-ads-features-section';
import PaidAdsSetupSections from './paid-ads-setup-sections';
import SkipPaidAdsConfirmationModal from './skip-paid-ads-confirmation-modal';
import { getProductFeedUrl } from '.~/utils/urls';
import clientSession from './clientSession';
import { API_NAMESPACE, STORE_KEY } from '.~/data/constants';
import { GUIDE_NAMES } from '.~/constants';

const ACTION_COMPLETE = 'complete-ads';
const ACTION_SKIP = 'skip-ads';
import { ACTION_COMPLETE, ACTION_SKIP } from './constants';
import { recordGlaEvent } from '.~/utils/tracks';

/**
* Clicking on the "Create a paid ad campaign" button to open the paid ads setup in the onboarding flow.
Expand Down Expand Up @@ -76,6 +76,10 @@ export default function SetupPaidAds() {
);
const [ paidAds, setPaidAds ] = useState( {} );
const [ completing, setCompleting ] = useState( null );
const [
showSkipPaidAdsConfirmationModal,
setShowSkipPaidAdsConfirmationModal,
] = useState( false );

const handleContinuePaidAdsSetupClick = () => {
setShowPaidAdsSetup( true );
Expand Down Expand Up @@ -117,18 +121,17 @@ export default function SetupPaidAds() {
await finishOnboardingSetup( event, onBeforeFinish );
};

// The status check of Google Ads account connection is included in `paidAds.isReady`,
// because when there is no connected account, it will disable the budget section and set the `amount` to `undefined`.
const disabledComplete = completing === ACTION_SKIP || ! paidAds.isReady;
const handleSkipCreatePaidAds = async ( event ) => {
setShowSkipPaidAdsConfirmationModal( false );

function createSkipButton( text ) {
const eventProps = {
opened_paid_ads_setup: 'no',
google_ads_account_status: googleAdsAccount?.status,
billing_method_status: 'unknown',
campaign_form_validation: 'unknown',
};

// TODO: Review once https://github.com/woocommerce/google-listings-and-ads/issues/2500 is merged
if ( showPaidAdsSetup ) {
const selector = select( STORE_KEY );
const billing = selector.getGoogleAdsAccountBillingStatus();
Expand All @@ -140,19 +143,34 @@ export default function SetupPaidAds() {
} );
}

recordGlaEvent( 'gla_onboarding_complete_button_click', eventProps );

await finishOnboardingSetup( event );
};

const handleShowSkipPaidAdsConfirmationModal = () => {
setShowSkipPaidAdsConfirmationModal( true );
};

const handleCancelSkipPaidAdsClick = () => {
setShowSkipPaidAdsConfirmationModal( false );
};

// The status check of Google Ads account connection is included in `paidAds.isReady`,
// because when there is no connected account, it will disable the budget section and set the `amount` to `undefined`.
const disabledComplete = completing === ACTION_SKIP || ! paidAds.isReady;

function createSkipButton( text ) {
const disabledSkip =
completing === ACTION_COMPLETE || ! hasGoogleAdsConnection;

return (
<AppButton
isTertiary
data-action={ ACTION_SKIP }
text={ text }
loading={ completing === ACTION_SKIP }
disabled={ disabledSkip }
onClick={ finishOnboardingSetup }
eventName="gla_onboarding_complete_button_click"
eventProps={ eventProps }
onClick={ handleShowSkipPaidAdsConfirmationModal }
/>
);
}
Expand Down Expand Up @@ -194,6 +212,14 @@ export default function SetupPaidAds() {
<PaidAdsSetupSections onStatesReceived={ setPaidAds } />
) }
<FaqsSection />

{ showSkipPaidAdsConfirmationModal && (
<SkipPaidAdsConfirmationModal
onRequestClose={ handleCancelSkipPaidAdsClick }
onSkipCreatePaidAds={ handleSkipCreatePaidAds }
/>
) }

<StepContentFooter hidden={ ! showPaidAdsSetup }>
<Flex justify="right" gap={ 4 }>
{ createSkipButton(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import AppModal from '.~/components/app-modal';
import AppButton from '.~/components/app-button';
import AppDocumentationLink from '.~/components/app-documentation-link';
import { ACTION_SKIP } from './constants';

/**
* @fires gla_documentation_link_click with `{ context: 'skip-paid-ads-modal', link_id: 'paid-ads-with-performance-max-campaigns-learn-more', href: 'https://support.google.com/google-ads/answer/10724817' }`
*/

/**
eason9487 marked this conversation as resolved.
Show resolved Hide resolved
* Renders a modal dialog that confirms whether the user wants to skip setting up paid ads.
* It provides information about the benefits of enabling Performance Max and includes a link to learn more.
*
* @param {Object} props React props.
* @param {Function} props.onRequestClose Function to be called when the modal should be closed.
* @param {Function} props.onSkipCreatePaidAds Function to be called when the user confirms skipping the paid ads setup.
*/
const SkipPaidAdsConfirmationModal = ( {
onRequestClose,
onSkipCreatePaidAds,
} ) => {
return (
<AppModal
title={ __( 'Skip setting up ads?', 'google-listings-and-ads' ) }
buttons={ [
<AppButton key="cancel" isSecondary onClick={ onRequestClose }>
{ __( 'Cancel', 'google-listings-and-ads' ) }
</AppButton>,
<AppButton
key="complete-setup"
onClick={ onSkipCreatePaidAds }
data-action={ ACTION_SKIP }
isPrimary
>
{ __(
'Complete setup without setting up ads',
'google-listings-and-ads'
) }
</AppButton>,
] }
onRequestClose={ onRequestClose }
>
<p>
{ __(
'Enabling Performance Max is highly recommended to drive more sales and reach new audiences across Google channels like Search, YouTube and Discover.',
'google-listings-and-ads'
) }
</p>
<p>
{ __(
'Performance Max uses the best of Google’s AI to show the most impactful ads for your products at the right time and place. Google will use your product data to create ads for this campaign.',
'google-listings-and-ads'
) }
</p>
<p>
<AppDocumentationLink
href="https://support.google.com/google-ads/answer/10724817"
context="skip-paid-ads-modal"
linkId="paid-ads-with-performance-max-campaigns-learn-more"
>
{ __(
'Learn more about Performance Max.',
'google-listings-and-ads'
) }
</AppDocumentationLink>
</p>
</AppModal>
);
};

export default SkipPaidAdsConfirmationModal;
141 changes: 85 additions & 56 deletions tests/e2e/specs/setup-mc/step-4-complete-campaign.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -370,77 +370,106 @@ test.describe( 'Complete your campaign', () => {
await completeCampaign.clickCompleteSetupButton();
await requestsPromises;

const setupSuccessModal = page
.locator( '.components-modal__content' )
.filter( {
hasText:
'You’ve successfully set up Google for WooCommerce!',
} );
const setupSuccessModal =
completeCampaign.getSetupSuccessModal();
await expect( setupSuccessModal ).toBeVisible();
} );
} );
} );
} );

test.describe( 'Complete onboarding by "Skip this step for now"', () => {
test.beforeAll( async () => {
// Reset the showing status for the "Set up paid ads" section.
await page.evaluate( () => window.sessionStorage.clear() );
await setupAdsAccountPage.mockAdsAccountIncomplete();
await completeCampaign.goto();
await completeCampaign.clickSkipStepButton();
} );
test.describe(
'Ask user for confirmation when clicking "Skip this step for now"',
() => {
test.describe( 'User skips paid ads creation', () => {
test.beforeAll( async () => {
// Reset the showing status for the "Set up paid ads" section.
await page.evaluate( () => window.sessionStorage.clear() );
await setupAdsAccountPage.mockAdsAccountIncomplete();
await completeCampaign.goto();
await completeCampaign.clickSkipStepButton();
} );

test( 'should see the setup success modal', async () => {
const setupSuccessModal = page
.locator( '.components-modal__content' )
.filter( {
hasText:
'You’ve successfully set up Google for WooCommerce!',
test( 'should see the modal', async () => {
const skipPaidAdsModal =
completeCampaign.getSkipPaidAdsCreationModal();
await expect( skipPaidAdsModal ).toBeVisible();
} );
await expect( setupSuccessModal ).toBeVisible();
} );

test( 'should see the url contains product-feed', async () => {
expect( page.url() ).toMatch( /path=%2Fgoogle%2Fproduct-feed/ );
} );
} );
test( 'should see the url contains product-feed if the user skips', async () => {
await completeCampaign.clickCompleteSetupModalButton();
await page.waitForURL( /path=%2Fgoogle%2Fproduct-feed/ );
expect( page.url() ).toMatch(
/path=%2Fgoogle%2Fproduct-feed/
);
} );

test.describe( 'Complete onboarding by "Skip paid ads creation"', () => {
test.beforeAll( async () => {
await setupAdsAccountPage.mockAdsAccountIncomplete();
await completeCampaign.goto();
await completeCampaign.clickCreatePaidAdButton();
await completeCampaign.clickSkipPaidAdsCreationButon();
} );
test( 'should see the setup success modal', async () => {
const setupSuccessModal =
completeCampaign.getSetupSuccessModal();
await expect( setupSuccessModal ).toBeVisible();
} );

test( 'should also see the setup success modal', async () => {
const setupSuccessModal = page
.locator( '.components-modal__content' )
.filter( {
hasText:
'You’ve successfully set up Google for WooCommerce!',
test( 'should see buttons on Dashboard for Google Ads onboarding', async () => {
await page.keyboard.press( 'Escape' );
await page
.getByRole( 'tab', { name: 'Dashboard' } )
.click();

const buttons = page.getByRole( 'button', {
name: 'Add paid campaign',
} );

await expect( buttons ).toHaveCount( 2 );
for ( const button of await buttons.all() ) {
await expect( button ).toBeVisible();
await expect( button ).toBeEnabled();
}
} );
await expect( setupSuccessModal ).toBeVisible();
} );
} );

test( 'should also see the url contains product-feed', async () => {
expect( page.url() ).toMatch( /path=%2Fgoogle%2Fproduct-feed/ );
} );
test.describe( 'User does not skip paid ads creation', () => {
test.beforeAll( async () => {
// Reset the showing status for the "Set up paid ads" section.
await page.evaluate( () => window.sessionStorage.clear() );
await setupAdsAccountPage.mockAdsAccountIncomplete();
await completeCampaign.goto();
await completeCampaign.clickSkipStepButton();
} );

test( 'should see buttons on Dashboard for Google Ads onboarding', async () => {
await page.keyboard.press( 'Escape' );
await page.getByRole( 'tab', { name: 'Dashboard' } ).click();
test( 'should no longer see the confirmation modal', async () => {
await completeCampaign.clickCancelModalButton();

const skipPaidAdsModal =
completeCampaign.getSkipPaidAdsCreationModal();
await expect( skipPaidAdsModal ).not.toBeVisible();
} );

const buttons = page.getByRole( 'button', {
name: 'Add paid campaign',
test( 'user should stay on the same page', async () => {
await expect( page.url() ).toMatch(
/path=%2Fgoogle%2Fsetup-mc&google-mc=connected/
);
} );
} );
}
);

await expect( buttons ).toHaveCount( 2 );
for ( const button of await buttons.all() ) {
await expect( button ).toBeVisible();
await expect( button ).toBeEnabled();
}
} );
} );
// TODO: Should no longer be needed once https://github.com/woocommerce/google-listings-and-ads/issues/2500 is merged.
test.describe(
'Ask user for confirmation when clicking the "Skip paid ads creation"',
() => {
test.beforeAll( async () => {
await setupAdsAccountPage.mockAdsAccountIncomplete();
await completeCampaign.goto();
await completeCampaign.clickCreatePaidAdButton();
await completeCampaign.clickSkipPaidAdsCreationButon();
} );

test( 'should see the confirmation modal', async () => {
const skipPaidAdsModal =
completeCampaign.getSkipPaidAdsCreationModal();
await expect( skipPaidAdsModal ).toBeVisible();
} );
}
);
} );
Loading