-
Notifications
You must be signed in to change notification settings - Fork 21
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
base: feature/2459-campaign-creation-flow
Are you sure you want to change the base?
Changes from all commits
b207569
f65fbee
1b8abc9
3f8ac23
101412b
620b183
84879b8
a3b50fe
a9b7f13
c76a128
dcea1d6
522e635
388fddb
8ddde21
ff7f281
5200727
d93bc1d
8e95434
2fa2bdb
6dd25e8
2f91ae8
3418caa
7f25ff7
7db2664
892c016
9ba6eed
d7d5c6a
9c576b0
c790719
35fed8a
fbce5c6
814e353
17a869d
ca3dc21
d4b6a8d
38d255a
5343963
face49e
b3e3b2a
d4c376d
7cd8c5b
5d727ba
ab1f837
34c53d7
f3d74f2
8258b28
d74087c
b405e9c
94cbe5f
dd44feb
95d6452
229b41c
6ce4cd2
c239114
bb710b3
db509b4
7c958ad
5ee5437
4da52c5
25ed467
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,16 +7,22 @@ | |
/** | ||
* Internal dependencies | ||
*/ | ||
import { useAdaptiveFormContext } from '.~/components/adaptive-form'; | ||
import StepContent from '.~/components/stepper/step-content'; | ||
import StepContentHeader from '.~/components/stepper/step-content-header'; | ||
import StepContentFooter from '.~/components/stepper/step-content-footer'; | ||
import StepContentActions from '.~/components/stepper/step-content-actions'; | ||
import StepContentFooter from '.~/components/stepper/step-content-footer'; | ||
import AppDocumentationLink from '.~/components/app-documentation-link'; | ||
import { useAdaptiveFormContext } from '.~/components/adaptive-form'; | ||
import AudienceSection from '../audience-section'; | ||
import BudgetSection from '../budget-section'; | ||
import { CampaignPreviewCard } from '../campaign-preview'; | ||
import PaidAdsFaqsPanel from '../faqs-panel'; | ||
import PaidAdsFaqsPanel from './faqs-panel'; | ||
import PaidAdsFeaturesSection from './paid-ads-features-section'; | ||
import CampaignPreviewCard from '.~/components/paid-ads/campaign-preview/campaign-preview-card'; | ||
import BudgetSection from '.~/components/paid-ads/budget-section'; | ||
import BillingCard from '.~/components/paid-ads/billing-card'; | ||
import useTargetAudienceFinalCountryCodes from '.~/hooks/useTargetAudienceFinalCountryCodes'; | ||
|
||
/** | ||
* @typedef {import('.~/components/adaptive-form/adaptive-form-context').AdaptiveFormContext} AdaptiveFormContext | ||
*/ | ||
|
||
/** | ||
* @typedef {import('.~/data/actions').Campaign} Campaign | ||
|
@@ -30,81 +36,86 @@ | |
* | ||
* @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' }` | ||
* @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 {JSX.Element|Function} props.continueButton Continue button component. | ||
* @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. | ||
* @param {Campaign} [props.campaign] Campaign data to be edited. The displayCountries property will be used to fetch budget recommendation data. | ||
* @param {string} props.headerTitle The title of the step. | ||
* @param {'create-ads'|'edit-ads'|'setup-ads'|'setup-mc'} props.context A context indicating which page this component is used on. This will be the value of `context` in the track event properties. | ||
* @param {(AdaptiveFormContext) => JSX.Element|JSX.Element} [props.skipButton] A React element or function to render the "Skip" button. If a function is passed, it receives the form context and returns the button element. | ||
* @param {(AdaptiveFormContext) => JSX.Element|JSX.Element} [props.continueButton] A React element or function to render the "Continue" button. If a function is passed, it receives the form context and returns the button element. | ||
*/ | ||
export default function AdsCampaign( { | ||
campaign, | ||
headerTitle, | ||
context, | ||
skipButton, | ||
continueButton, | ||
trackingContext, | ||
} ) { | ||
const isCreation = ! campaign; | ||
const formContext = useAdaptiveFormContext(); | ||
const { data: countryCodes } = useTargetAudienceFinalCountryCodes(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This 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:
Kapture.2024-10-10.at.15.46.15.mp4There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @eason9487 This should be fixed now. We are now passing the |
||
const isOnboardingFlow = context === 'setup-mc'; | ||
const showCampaignPreviewCard = | ||
context === 'setup-ads' || | ||
context === 'create-ads' || | ||
context === 'edit-ads'; | ||
// only show the billing card during onboarding or setup Ads flow. | ||
// For creating/editing a campaign, we assume billing is already set up. | ||
const showBillingCard = context === 'setup-mc' || context === 'setup-ads'; | ||
|
||
let description = createInterpolateElement( | ||
__( | ||
'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={ context } | ||
linkId="see-what-ads-look-like" | ||
href="https://support.google.com/google-ads/answer/6275294" | ||
/> | ||
), | ||
} | ||
); | ||
|
||
const disabledBudgetSection = ! formContext.values.countryCodes.length; | ||
const helperText = isCreation | ||
? __( | ||
'You can only choose from countries you’ve selected during product listings configuration.', | ||
'google-listings-and-ads' | ||
) | ||
: __( | ||
'Once a campaign has been created, you cannot change the target country(s).', | ||
'google-listings-and-ads' | ||
); | ||
if ( isOnboardingFlow ) { | ||
description = __( | ||
'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 ( | ||
<StepContent> | ||
<StepContentHeader | ||
title={ | ||
isCreation | ||
? __( | ||
'Create your paid campaign', | ||
'google-listings-and-ads' | ||
) | ||
: __( | ||
'Edit your paid campaign', | ||
'google-listings-and-ads' | ||
) | ||
} | ||
description={ createInterpolateElement( | ||
__( | ||
'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" | ||
/> | ||
), | ||
} | ||
) } | ||
/> | ||
<AudienceSection | ||
disabled={ ! isCreation } | ||
multiple={ isCreation || campaign.allowMultiple } | ||
countrySelectHelperText={ helperText } | ||
formProps={ formContext } | ||
title={ headerTitle } | ||
description={ description } | ||
/> | ||
|
||
{ isOnboardingFlow && <PaidAdsFeaturesSection /> } | ||
|
||
<BudgetSection | ||
formProps={ formContext } | ||
disabled={ disabledBudgetSection } | ||
countryCodes={ formContext.values.countryCodes } | ||
countryCodes={ | ||
context === 'edit-ads' | ||
? campaign?.displayCountries | ||
: countryCodes | ||
} | ||
> | ||
<CampaignPreviewCard /> | ||
{ showBillingCard && <BillingCard /> } | ||
|
||
{ showCampaignPreviewCard && <CampaignPreviewCard /> } | ||
</BudgetSection> | ||
|
||
<StepContentFooter> | ||
<StepContentActions> | ||
{ typeof skipButton === 'function' | ||
? skipButton( formContext ) | ||
: skipButton } | ||
|
||
{ typeof continueButton === 'function' | ||
? continueButton( { | ||
formProps: formContext, | ||
} ) | ||
? continueButton( formContext ) | ||
: continueButton } | ||
</StepContentActions> | ||
|
||
<PaidAdsFaqsPanel /> | ||
</StepContentFooter> | ||
</StepContent> | ||
|
This file was deleted.
This file was deleted.
There was a problem hiding this comment.
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.trackingContext
seems inappropriate.isOnboardingFlow
andtrackingContext
could be consolidated and lifted to a higher abstraction level.PaidAdsSetupSections
is now purer and contains only one section.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:
isOnboardingFlow
prop and renametrackingContext
tocontext
.context
accepts one more possible string value, such as'setup-mc'
. to indicate it's being used in onboardingPaidAdsSetupSections
to reduce the complexity of a layer of components.SpinnerCard
back to theBillingCard
componentAdsCampaign
component and use the above render condition variables, for example:There was a problem hiding this comment.
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!