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

2535: Consolidate Ad Creation #2623

Open
wants to merge 60 commits into
base: feature/2459-campaign-creation-flow
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 44 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
b207569
Move PaidAdsFeaturesSection and PaidAdsSetupSections components.
asvinb Aug 29, 2024
f65fbee
Save Work in progress.
asvinb Sep 2, 2024
1b8abc9
Consolidate AdsCampaign component.
asvinb Sep 3, 2024
3f8ac23
Revert local test changes.
asvinb Sep 3, 2024
101412b
Remove comments.
asvinb Sep 3, 2024
620b183
Clean up comments.
asvinb Sep 3, 2024
84879b8
Remove unused imports.
asvinb Sep 3, 2024
a3b50fe
Editing a campaign working.
asvinb Sep 3, 2024
a9b7f13
Fix condition to render paid ads sections.
asvinb Sep 3, 2024
c76a128
Address linting errors.
asvinb Sep 3, 2024
dcea1d6
Add headerDescription prop.
asvinb Sep 3, 2024
522e635
Remove unused comment.
asvinb Sep 3, 2024
388fddb
Remove onClick prop (?)
asvinb Sep 9, 2024
8ddde21
Show banner in create mode only.
asvinb Sep 9, 2024
ff7f281
Remove unused event prop
asvinb Sep 9, 2024
5200727
Remove unecessary isCreation prop.
asvinb Sep 9, 2024
d93bc1d
Add countryCodes field.
asvinb Sep 9, 2024
8e95434
Remove country code from edit screen.
asvinb Sep 10, 2024
2fa2bdb
Merge branch 'feature/2459-campaign-creation-flow' into update/2535-c…
asvinb Sep 23, 2024
6dd25e8
Add modal changes.
asvinb Sep 25, 2024
2f91ae8
Show paid ads sections by default.
asvinb Sep 25, 2024
3418caa
Simplify forms more.
asvinb Sep 25, 2024
7f25ff7
Move setup paid ads component.
asvinb Sep 25, 2024
7db2664
Remove unused braces.
asvinb Sep 25, 2024
892c016
Revert debugging changes.
asvinb Sep 25, 2024
9ba6eed
Fix tests for setup paid ads.
asvinb Sep 25, 2024
d7d5c6a
Remove unused args.
asvinb Sep 25, 2024
9c576b0
Fix hook return value.
asvinb Sep 25, 2024
c790719
Revert change.
asvinb Sep 25, 2024
35fed8a
Revert change.
asvinb Sep 25, 2024
fbce5c6
Set up events correctly.
asvinb Sep 25, 2024
814e353
Updated JSDocs.
asvinb Sep 25, 2024
17a869d
Remove unused files.
asvinb Sep 25, 2024
ca3dc21
Check for approval notice.
asvinb Sep 25, 2024
d4b6a8d
Update condition to show campaign preview card.
asvinb Sep 25, 2024
38d255a
Use CampaignAssetsForm within SetupPaidAds.
asvinb Sep 27, 2024
5343963
Do not load amount from local storage all the time except during onbo…
asvinb Sep 27, 2024
face49e
Merge branch 'feature/2458-streamline-onboarding' into update/2535-co…
asvinb Sep 27, 2024
b3e3b2a
Fix merge conflict for AdsCampaign.
asvinb Sep 27, 2024
d4c376d
Fix merge conflict for audienceSection test.
asvinb Sep 27, 2024
7cd8c5b
Delete unused file.
asvinb Sep 27, 2024
5d727ba
fix linting issues.
asvinb Sep 27, 2024
ab1f837
Merge pull request #2627 from woocommerce/update/2535-consolidate-ad-…
joemcgill Sep 30, 2024
34c53d7
Merge branch 'feature/2459-campaign-creation-flow' into update/2535-c…
joemcgill Sep 30, 2024
f3d74f2
Add continueButton and skipButton props.
asvinb Oct 8, 2024
8258b28
Use continueButton props.
asvinb Oct 8, 2024
d74087c
Save WIP.
asvinb Oct 8, 2024
b405e9c
Add ContinueButton component.
asvinb Oct 9, 2024
94cbe5f
Fix unit tests.
asvinb Oct 9, 2024
dd44feb
Only show BillingCard component during onboarding or Ads setup flow.
asvinb Oct 9, 2024
95d6452
Remove unused files.
asvinb Oct 9, 2024
229b41c
Address CR feedback.
asvinb Oct 11, 2024
6ce4cd2
Remove PaidAdsSetupSections component.
asvinb Oct 11, 2024
c239114
Restore campaign property.
asvinb Oct 11, 2024
bb710b3
Merge branch 'feature/2459-campaign-creation-flow' into update/2535-c…
asvinb Oct 11, 2024
db509b4
Fix unit tests.
asvinb Oct 11, 2024
7c958ad
Remove unused imports.
asvinb Oct 11, 2024
5ee5437
Fix condition to disable buttton.
asvinb Oct 11, 2024
4da52c5
Update E2E tests.
asvinb Oct 11, 2024
25ed467
Remove unused imports.
asvinb Oct 11, 2024
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
43 changes: 0 additions & 43 deletions js/src/components/audience-country-select.js

This file was deleted.

117 changes: 0 additions & 117 deletions js/src/components/paid-ads/ads-campaign.js

This file was deleted.

189 changes: 189 additions & 0 deletions js/src/components/paid-ads/ads-campaign/ads-campaign.js
Copy link
Member

Choose a reason for hiding this comment

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

Now that the AdsCampaign component has become more flexible and simple to use, however, there are still a few factors that can be polished.

  • Render logic depending on a prop named trackingContext seems inappropriate.
  • isOnboardingFlow and trackingContext could be consolidated and lifted to a higher abstraction level.
  • PaidAdsSetupSections is now purer and contains only one section.
  • Even if there is no need to render a BillingCard when creating or editing campaign, a redundant API request will still be sent to get the billing status.

Suggestions to further simplify the logic and divide component responsibilities:

  • Remove isOnboardingFlow prop and rename trackingContext to context.
    • context accepts one more possible string value, such as 'setup-mc'. to indicate it's being used in onboarding
    • Declare render condition variables within the components, for example:
      const isOnboardingFlow = context === 'setup-mc';
      const showBillingCard = context === 'setup-mc' || context === 'setup-ads';
  • Remove PaidAdsSetupSections to reduce the complexity of a layer of components.
    • Move the API request of getting billing status and SpinnerCard back to the BillingCard component
    • Moe the rest to the AdsCampaign component and use the above render condition variables, for example:
      <BudgetSection
      	formProps={ formContext }
      	countryCodes={ /* value for this prop needs to consider another comment */ }
      >
      	{ showBillingCard && <BillingCard /> }
      	{ ! isOnboardingFlow && <CampaignPreviewCard /> }
      </BudgetSection>

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thanks for the suggestions @eason9487 . Makes sense. Updated!

Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import {
createInterpolateElement,
useState,
useEffect,
} from '@wordpress/element';
import { noop } from 'lodash';

/**
* Internal dependencies
*/
import { useAdaptiveFormContext } from '.~/components/adaptive-form';
import StepContent from '.~/components/stepper/step-content';
import StepContentHeader from '.~/components/stepper/step-content-header';
import StepContentActions from '.~/components/stepper/step-content-actions';
import StepContentFooter from '.~/components/stepper/step-content-footer';
import AppDocumentationLink from '.~/components/app-documentation-link';
import AppButton from '.~/components/app-button';
import PaidAdsFaqsPanel from './faqs-panel';
import PaidAdsFeaturesSection from './paid-ads-features-section';
import PaidAdsSetupSections from './paid-ads-setup-sections';
import SkipButton from './skip-button';
import useTargetAudienceFinalCountryCodes from '.~/hooks/useTargetAudienceFinalCountryCodes';
import { ACTION_SKIP, ACTION_COMPLETE } from './constants';

/**
* @typedef {import('.~/data/actions').Campaign} Campaign
*/

/**
* Clicking on the "Complete setup" button to complete the onboarding flow with paid ads.
*
* @event gla_onboarding_complete_with_paid_ads_button_click
* @property {number} budget The budget for the campaign
* @property {string} audiences The targeted audiences for the campaign
*/

/**
* Renders the container of the form content for campaign management.
*
* Please note that this component relies on an CampaignAssetsForm's context and custom adapter,
* so it expects a `CampaignAssetsForm` to existing in its parents.
*
* @fires gla_documentation_link_click with `{ context: 'create-ads' | 'edit-ads' | 'setup-ads', link_id: 'see-what-ads-look-like', href: 'https://support.google.com/google-ads/answer/6275294' }`
* @fires gla_onboarding_complete_with_paid_ads_button_click
* @param {Object} props React props.
* @param {Campaign} [props.campaign] Campaign data to be edited. If not provided, this component will show campaign creation UI.
* @param {string} props.headerTitle The title of the step.
* @param {() => void} props.onContinue Callback called once continue button is clicked.
* @param {() => void} [props.onSkip] Callback called once skip button is clicked.
* @param {boolean} [props.hasError=false] Whether there's an error to reset the completing state.
* @param {boolean} [props.isOnboardingFlow=false] Whether this component is used in onboarding flow.
* @param {'create-ads'|'edit-ads'|'setup-ads'} props.trackingContext A context indicating which page this component is used on. This will be the value of `context` in the track event properties.
*/
export default function AdsCampaign( {
campaign,
headerTitle,
onContinue,
onSkip = noop,
hasError = false,
isOnboardingFlow = false,

Check warning on line 64 in js/src/components/paid-ads/ads-campaign/ads-campaign.js

View check run for this annotation

Codecov / codecov/patch

js/src/components/paid-ads/ads-campaign/ads-campaign.js#L62-L64

Added lines #L62 - L64 were not covered by tests
trackingContext,
} ) {
const formContext = useAdaptiveFormContext();
const { data: countryCodes } = useTargetAudienceFinalCountryCodes();
Copy link
Member

Choose a reason for hiding this comment

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

This countryCodes may lead to incorrect budget recommendation text and amount when editing an existing campaign having different target audience countries than the current ones in the free listings setup.

For example, given a campaign was created with one country code but is being edited after the free listings setup has been updated to have two country codes, the recommendation text will be incorrect:

  • Expected: Most merchants targeting Taiwan set a daily budget of 12 USD
  • Received: Most merchants targeting similar countries set a daily budget of 17 USD
Kapture.2024-10-10.at.15.46.15.mp4

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

const { isValidForm, setValue } = formContext;
const [ completing, setCompleting ] = useState( null );
const [ paidAds, setPaidAds ] = useState( {} );

Check warning on line 71 in js/src/components/paid-ads/ads-campaign/ads-campaign.js

View check run for this annotation

Codecov / codecov/patch

js/src/components/paid-ads/ads-campaign/ads-campaign.js#L66-L71

Added lines #L66 - L71 were not covered by tests

useEffect( () => {

Check warning on line 73 in js/src/components/paid-ads/ads-campaign/ads-campaign.js

View check run for this annotation

Codecov / codecov/patch

js/src/components/paid-ads/ads-campaign/ads-campaign.js#L73

Added line #L73 was not covered by tests
if ( hasError ) {
setCompleting( null );

Check warning on line 75 in js/src/components/paid-ads/ads-campaign/ads-campaign.js

View check run for this annotation

Codecov / codecov/patch

js/src/components/paid-ads/ads-campaign/ads-campaign.js#L75

Added line #L75 was not covered by tests
}
}, [ hasError ] );

const handleOnStatesReceived = ( paidAdsValues ) => {
setPaidAds( paidAdsValues );

Check warning on line 80 in js/src/components/paid-ads/ads-campaign/ads-campaign.js

View check run for this annotation

Codecov / codecov/patch

js/src/components/paid-ads/ads-campaign/ads-campaign.js#L79-L80

Added lines #L79 - L80 were not covered by tests

const { amount } = paidAdsValues;
setValue( 'amount', amount );

Check warning on line 83 in js/src/components/paid-ads/ads-campaign/ads-campaign.js

View check run for this annotation

Codecov / codecov/patch

js/src/components/paid-ads/ads-campaign/ads-campaign.js#L82-L83

Added lines #L82 - L83 were not covered by tests
};

const handleSkipCreateAds = () => {
setCompleting( ACTION_SKIP );

Check warning on line 87 in js/src/components/paid-ads/ads-campaign/ads-campaign.js

View check run for this annotation

Codecov / codecov/patch

js/src/components/paid-ads/ads-campaign/ads-campaign.js#L86-L87

Added lines #L86 - L87 were not covered by tests

onSkip( paidAds );

Check warning on line 89 in js/src/components/paid-ads/ads-campaign/ads-campaign.js

View check run for this annotation

Codecov / codecov/patch

js/src/components/paid-ads/ads-campaign/ads-campaign.js#L89

Added line #L89 was not covered by tests
};

const handleCompleteClick = ( event ) => {
setCompleting( event.target.dataset.action );

Check warning on line 93 in js/src/components/paid-ads/ads-campaign/ads-campaign.js

View check run for this annotation

Codecov / codecov/patch

js/src/components/paid-ads/ads-campaign/ads-campaign.js#L92-L93

Added lines #L92 - L93 were not covered by tests

onContinue( paidAds );

Check warning on line 95 in js/src/components/paid-ads/ads-campaign/ads-campaign.js

View check run for this annotation

Codecov / codecov/patch

js/src/components/paid-ads/ads-campaign/ads-campaign.js#L95

Added line #L95 was not covered by tests
};

// 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 || ! isValidForm;

let continueButtonProps = {

Check warning on line 103 in js/src/components/paid-ads/ads-campaign/ads-campaign.js

View check run for this annotation

Codecov / codecov/patch

js/src/components/paid-ads/ads-campaign/ads-campaign.js#L103

Added line #L103 was not covered by tests
text: __( 'Continue', 'google-listings-and-ads' ),
};

if ( isOnboardingFlow ) {
continueButtonProps = {

Check warning on line 108 in js/src/components/paid-ads/ads-campaign/ads-campaign.js

View check run for this annotation

Codecov / codecov/patch

js/src/components/paid-ads/ads-campaign/ads-campaign.js#L108

Added line #L108 was not covered by tests
'data-action': ACTION_COMPLETE,
text: __( 'Complete setup', 'google-listings-and-ads' ),
eventName: 'gla_onboarding_complete_with_paid_ads_button_click',
eventProps: {
budget: paidAds.amount,
audiences: countryCodes?.join( ',' ),
},
};
}

let description = createInterpolateElement(

Check warning on line 119 in js/src/components/paid-ads/ads-campaign/ads-campaign.js

View check run for this annotation

Codecov / codecov/patch

js/src/components/paid-ads/ads-campaign/ads-campaign.js#L119

Added line #L119 was not covered by tests
__(
'Paid Performance Max campaigns are automatically optimized for you by Google. <link>See what your ads will look like.</link>',
'google-listings-and-ads'
),
{
link: (
<AppDocumentationLink
context={ trackingContext }
linkId="see-what-ads-look-like"
href="https://support.google.com/google-ads/answer/6275294"
/>
),
}
);

if ( isOnboardingFlow ) {
description = __(

Check warning on line 136 in js/src/components/paid-ads/ads-campaign/ads-campaign.js

View check run for this annotation

Codecov / codecov/patch

js/src/components/paid-ads/ads-campaign/ads-campaign.js#L136

Added line #L136 was not covered by tests
'You’re ready to set up a Performance Max campaign to drive more sales with ads. Your products will be included in the campaign after they’re approved.',
'google-listings-and-ads'
);
}

return (

Check warning on line 142 in js/src/components/paid-ads/ads-campaign/ads-campaign.js

View check run for this annotation

Codecov / codecov/patch

js/src/components/paid-ads/ads-campaign/ads-campaign.js#L142

Added line #L142 was not covered by tests
<StepContent>
<StepContentHeader
title={ headerTitle }
description={ description }
/>

{ isOnboardingFlow && <PaidAdsFeaturesSection /> }

Check warning on line 149 in js/src/components/paid-ads/ads-campaign/ads-campaign.js

View check run for this annotation

Codecov / codecov/patch

js/src/components/paid-ads/ads-campaign/ads-campaign.js#L149

Added line #L149 was not covered by tests

<PaidAdsSetupSections
onStatesReceived={ handleOnStatesReceived }
campaign={ campaign }
countryCodes={ countryCodes }
loadCampaignFromClientSession={ isOnboardingFlow }
showCampaignPreviewCard={
trackingContext === 'setup-ads' ||
trackingContext === 'create-ads'

Check warning on line 158 in js/src/components/paid-ads/ads-campaign/ads-campaign.js

View check run for this annotation

Codecov / codecov/patch

js/src/components/paid-ads/ads-campaign/ads-campaign.js#L157-L158

Added lines #L157 - L158 were not covered by tests
}
Copy link
Member

Choose a reason for hiding this comment

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

As per the first acceptance criteria:

When a user is on the "Create your paid campaign" step of the "Set up paid ads" flow, they will see the same form used on the "Create a campaign" step of the "Get started..." onboarding flow.

I would like to confirm what the scope of the “same form” is, after all, they are currently presented differently in the campaign preview.

Copy link
Collaborator

Choose a reason for hiding this comment

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

The "same form" means that we will use the same component for both forms so that the requirements of each input section are consistent. The main difference is that the PaidAdsFeaturesSection should only be shown during onboarding.

Copy link
Member

@eason9487 eason9487 Oct 9, 2024

Choose a reason for hiding this comment

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

Thanks for the explanation.

I would suggest rephrasing it a little bit to avoid having “When a user …, they will see …” wording that confuses its goal of just having to share components in development. Or, clarify the goal is to have the same UI as before the change.

Copy link
Member

Choose a reason for hiding this comment

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

Before this PR, the preview card is shown as well when editing campaign.

Copy link
Collaborator Author

@asvinb asvinb Oct 11, 2024

Choose a reason for hiding this comment

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

Updated!

/>
eason9487 marked this conversation as resolved.
Show resolved Hide resolved

<StepContentFooter>
<StepContentActions>
{ isOnboardingFlow && (
<SkipButton

Check warning on line 165 in js/src/components/paid-ads/ads-campaign/ads-campaign.js

View check run for this annotation

Codecov / codecov/patch

js/src/components/paid-ads/ads-campaign/ads-campaign.js#L164-L165

Added lines #L164 - L165 were not covered by tests
text={ __(
'Skip paid ads creation',
'google-listings-and-ads'
) }
onSkipCreatePaidAds={ handleSkipCreateAds }
completing={ completing }
paidAds={ paidAds }
/>
) }
eason9487 marked this conversation as resolved.
Show resolved Hide resolved

<AppButton
isPrimary
disabled={ disabledComplete }
onClick={ handleCompleteClick }
loading={ completing === ACTION_COMPLETE }
{ ...continueButtonProps }
eason9487 marked this conversation as resolved.
Show resolved Hide resolved
/>
</StepContentActions>

<PaidAdsFaqsPanel />
</StepContentFooter>
</StepContent>
);
}
1 change: 1 addition & 0 deletions js/src/components/paid-ads/ads-campaign/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './ads-campaign';
Loading