Skip to content

Commit a0d2df8

Browse files
authored
Merge pull request #1649 from woocommerce/add/1610-paid-ads-features-section
Free Listings + Paid Ads: Add the boost product listings section
2 parents eddef3c + 4520dc1 commit a0d2df8

File tree

8 files changed

+241
-16
lines changed

8 files changed

+241
-16
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
.gla-step-content-footer {
22
display: flex;
33
justify-content: flex-end;
4+
5+
&[hidden] {
6+
display: none;
7+
}
48
}

js/src/css/abstracts/_variables.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
// Typography
77

88
$gla-font-smallest: 11px;
9+
$gla-font-smaller: 12px;
910
$gla-font-small: 14px;
1011
$gla-font-small-medium: 20px;
1112
$gla-font-medium: 24px;
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/**
2+
* External dependencies
3+
*/
4+
import { __ } from '@wordpress/i18n';
5+
import { Flex, FlexItem, FlexBlock } from '@wordpress/components';
6+
import { Pill } from '@woocommerce/components';
7+
import GridiconCheckmark from 'gridicons/dist/checkmark';
8+
import GridiconGift from 'gridicons/dist/gift';
9+
10+
/**
11+
* Internal dependencies
12+
*/
13+
import Section from '.~/wcdl/section';
14+
import AppDocumentationLink from '.~/components/app-documentation-link';
15+
import './paid-ads-features-section.scss';
16+
17+
function FeatureList() {
18+
const featuresItems = [
19+
{
20+
Icon: GridiconCheckmark,
21+
content: __(
22+
'Promote your products across Google Search, YouTube, Display, Discover, Maps, Gmail, and more.',
23+
'google-listings-and-ads'
24+
),
25+
},
26+
{
27+
Icon: GridiconCheckmark,
28+
content: __(
29+
'Set a daily budget, and only pay when someone clicks.',
30+
'google-listings-and-ads'
31+
),
32+
},
33+
{
34+
Icon: GridiconGift,
35+
content: __(
36+
'Claim $500 in ads credit when you spend your first $500 with Google Ads. Terms and conditions apply.',
37+
'google-listings-and-ads'
38+
),
39+
},
40+
];
41+
42+
return (
43+
<div className="gla-paid-ads-features-section__feature-list">
44+
{ featuresItems.map( ( { Icon, content }, idx ) => (
45+
<Flex key={ idx } align="flex-start">
46+
<Icon size="18" />
47+
<FlexBlock>{ content }</FlexBlock>
48+
</Flex>
49+
) ) }
50+
</div>
51+
);
52+
}
53+
54+
// TODO: `href` is not yet ready. Will be added later.
55+
/**
56+
* @fires gla_documentation_link_click with `{ context: 'setup-paid-ads', link_id: 'paid-ads-with-performance-max-campaigns-learn-more', href: 'https://example.com' }`
57+
*/
58+
59+
/**
60+
* Renders a section layout to elaborate on the features of paid ads and show the buttons
61+
* for the next actions: skip or continue the paid ads setup.
62+
*
63+
* @param {Object} props React props.
64+
* @param {boolean} props.hideFooterButtons Whether to hide the buttons at the card footer.
65+
* @param {JSX.Element} props.skipButton Button to skip paid ads setup.
66+
* @param {JSX.Element} props.continueButton Button to continue paid ads setup.
67+
*/
68+
export default function PaidAdsFeaturesSection( {
69+
hideFooterButtons,
70+
skipButton,
71+
continueButton,
72+
} ) {
73+
return (
74+
<Section
75+
className="gla-paid-ads-features-section"
76+
topContent={
77+
<Pill>{ __( 'Recommended', 'google-listings-and-ads' ) }</Pill>
78+
}
79+
title={ __(
80+
'Boost product listings with paid ads',
81+
'google-listings-and-ads'
82+
) }
83+
description={
84+
<>
85+
<p>
86+
{ __(
87+
'Get the most out of your paid ads with Performance Max campaigns. With Google’s machine learning technology, your Performance Max campaigns will be automated to show the most impactful ads at the right time and place.',
88+
'google-listings-and-ads'
89+
) }
90+
</p>
91+
<p>
92+
<AppDocumentationLink
93+
context="setup-paid-ads"
94+
linkId="paid-ads-with-performance-max-campaigns-learn-more"
95+
href="https://example.com" // TODO: Not yet ready. Will be added later.
96+
>
97+
{ __( 'Learn more', 'google-listings-and-ads' ) }
98+
</AppDocumentationLink>
99+
</p>
100+
</>
101+
}
102+
>
103+
<Section.Card>
104+
<Section.Card.Body>
105+
<Flex align="center" gap={ 9 }>
106+
<FlexBlock>
107+
<Section.Card.Title>
108+
{ __(
109+
'Drive more traffic and sales by using both free listings and paid ads',
110+
'google-listings-and-ads'
111+
) }
112+
</Section.Card.Title>
113+
<div className="gla-paid-ads-features-section__subtitle">
114+
{ __(
115+
'Using free listings and paid ads together can double impressions and increase clicks by 50%*',
116+
'google-listings-and-ads'
117+
) }
118+
</div>
119+
<FeatureList />
120+
<cite className="gla-paid-ads-features-section__cite">
121+
{ __(
122+
'Source: Google Internal Data, July 2020',
123+
'google-listings-and-ads'
124+
) }
125+
</cite>
126+
</FlexBlock>
127+
<FlexItem>
128+
<div style={ { width: '205px' } }>
129+
Will be added by another PR
130+
</div>
131+
</FlexItem>
132+
</Flex>
133+
</Section.Card.Body>
134+
<Section.Card.Footer hidden={ hideFooterButtons }>
135+
{ skipButton }
136+
{ continueButton }
137+
</Section.Card.Footer>
138+
</Section.Card>
139+
</Section>
140+
);
141+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
.gla-paid-ads-features-section {
2+
.woocommerce-pill {
3+
color: $gray-700;
4+
}
5+
6+
.wcdl-section-card-title {
7+
margin-bottom: $grid-unit-15;
8+
line-height: $gla-line-height-medium-large;
9+
font-weight: normal;
10+
font-size: $gla-font-small-medium;
11+
color: $gray-900;
12+
}
13+
14+
&__subtitle {
15+
line-height: $gla-line-height-medium;
16+
font-size: $gla-font-small;
17+
color: $gray-800;
18+
}
19+
20+
&__feature-list {
21+
display: flex;
22+
flex-direction: column;
23+
gap: $grid-unit-20;
24+
margin: $grid-unit-30 0 $grid-unit-20;
25+
line-height: $gla-line-height-smaller;
26+
color: $gray-800;
27+
28+
.gridicon {
29+
fill: #5ec862;
30+
}
31+
}
32+
33+
&__cite {
34+
font-style: normal;
35+
font-size: $gla-font-smaller;
36+
color: $gray-600;
37+
}
38+
}

js/src/setup-mc/setup-stepper/setup-paid-ads/setup-paid-ads.js

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@ import StepContentFooter from '.~/components/stepper/step-content-footer';
1717
import FaqsSection from '.~/components/paid-ads/faqs-section';
1818
import AppButton from '.~/components/app-button';
1919
import ProductFeedStatusSection from './product-feed-status-section';
20+
import PaidAdsFeaturesSection from './paid-ads-features-section';
2021
import { getProductFeedUrl } from '.~/utils/urls';
2122
import { GUIDE_NAMES } from '.~/constants';
2223
import { API_NAMESPACE } from '.~/data/constants';
2324

2425
export default function SetupPaidAds() {
2526
const adminUrl = useAdminUrl();
2627
const { createNotice } = useDispatchCoreNotices();
28+
const [ showPaidAdsSetup, setShowPaidAdsSetup ] = useState( false );
2729
const [ completing, setCompleting ] = useState( null );
2830

2931
const finishFreeListingsSetup = async ( event ) => {
@@ -56,6 +58,19 @@ export default function SetupPaidAds() {
5658
await finishFreeListingsSetup( event );
5759
};
5860

61+
function createSkipButton( text ) {
62+
return (
63+
<AppButton
64+
isTertiary
65+
data-action="skip-ads"
66+
text={ text }
67+
loading={ completing === 'skip-ads' }
68+
disabled={ completing === 'complete-ads' }
69+
onClick={ finishFreeListingsSetup }
70+
/>
71+
);
72+
}
73+
5974
return (
6075
<StepContent>
6176
<StepContentHeader
@@ -69,30 +84,43 @@ export default function SetupPaidAds() {
6984
) }
7085
/>
7186
<ProductFeedStatusSection />
87+
<PaidAdsFeaturesSection
88+
hideFooterButtons={ showPaidAdsSetup }
89+
skipButton={ createSkipButton(
90+
__( 'Skip this step for now', 'google-listings-and-ads' )
91+
) }
92+
continueButton={
93+
<AppButton
94+
isPrimary
95+
text={ __(
96+
'Create a paid ad campaign',
97+
'google-listings-and-ads'
98+
) }
99+
disabled={ completing === 'skip-ads' }
100+
onClick={ () => setShowPaidAdsSetup( true ) }
101+
/>
102+
}
103+
/>
72104
<FaqsSection />
73-
<StepContentFooter>
105+
<StepContentFooter hidden={ ! showPaidAdsSetup }>
74106
<Flex justify="right" gap={ 4 }>
75-
<AppButton
76-
isTertiary
77-
data-action="skip-ads"
78-
loading={ completing === 'skip-ads' }
79-
disabled={ completing === 'complete-ads' }
80-
onClick={ finishFreeListingsSetup }
81-
>
82-
{ __(
107+
{ createSkipButton(
108+
__(
83109
'Skip paid ads creation',
84110
'google-listings-and-ads'
85-
) }
86-
</AppButton>
111+
)
112+
) }
87113
<AppButton
88114
isPrimary
89115
data-action="complete-ads"
116+
text={ __(
117+
'Complete setup',
118+
'google-listings-and-ads'
119+
) }
90120
loading={ completing === 'complete-ads' }
91121
disabled={ completing === 'skip-ads' }
92122
onClick={ handleCompleteClick }
93-
>
94-
{ __( 'Complete setup', 'google-listings-and-ads' ) }
95-
</AppButton>
123+
/>
96124
</Flex>
97125
</StepContentFooter>
98126
</StepContent>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
.wcdl-section-card-footer {
22
padding: calc(var(--large-gap) / 2) var(--large-gap);
3+
4+
&[hidden] {
5+
display: none;
6+
}
37
}

js/src/wcdl/section/index.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,18 @@ import './index.scss';
1616
* @param {string} [props.className] Additional CSS class name to be appended.
1717
* @param {JSX.Element} [props.title] Section title at the left side.
1818
* @param {JSX.Element} [props.description] Section description under the title.
19+
* @param {JSX.Element} [props.topContent] Content at the top of the section title.
1920
* @param {JSX.Element} [props.children] Section content at the right side.
2021
* @param {boolean} [props.disabled] Whether display the whole section in disabled style.
2122
*/
22-
const Section = ( { className, title, description, children, disabled } ) => {
23+
const Section = ( {
24+
className,
25+
title,
26+
description,
27+
topContent,
28+
children,
29+
disabled,
30+
} ) => {
2331
const sectionClassName = classnames(
2432
'wcdl-section',
2533
disabled ? 'wcdl-section--is-disabled' : false,
@@ -29,6 +37,7 @@ const Section = ( { className, title, description, children, disabled } ) => {
2937
return (
3038
<section className={ sectionClassName }>
3139
<header>
40+
{ topContent && <p>{ topContent }</p> }
3241
{ title && <h1>{ title }</h1> }
3342
{ description }
3443
</header>

js/src/wcdl/section/index.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
}
2828

2929
p {
30-
margin: 0 0 1em;
30+
margin: 0 0 $grid-unit;
3131
line-height: $gla-line-height-smaller;
3232
}
3333
}

0 commit comments

Comments
 (0)