Skip to content

Commit 40e0f68

Browse files
committed
feat(syndicated): add cta
1 parent 7fb2d1e commit 40e0f68

File tree

3 files changed

+199
-0
lines changed

3 files changed

+199
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
import { css } from '@emotion/css'
2+
import { SIGNUP_URL } from 'common/constants'
3+
import { useInView } from 'react-intersection-observer'
4+
import { breakpointSmallDesktop } from 'common/constants' // 1023
5+
import { breakpointLargeTablet } from 'common/constants' // 1023
6+
import { useTranslation } from 'next-i18next'
7+
import { useEffect, useRef } from 'react'
8+
9+
const wrapper = css`
10+
position: relative;
11+
12+
&:before {
13+
position: absolute;
14+
top: -24px;
15+
left: -24px;
16+
height: 375px;
17+
width: 100%;
18+
content: ' ';
19+
background-color: var(--color-calloutBackgroundSecondary);
20+
}
21+
22+
div {
23+
background-color: var(--color-calloutBackgroundPrimary);
24+
padding: 3.625rem var(--spacing150) var(--spacing150);
25+
width: 100%;
26+
position: relative;
27+
}
28+
29+
h6 {
30+
font-family: var(--fontSerifAlt);
31+
font-size: 2.3125rem;
32+
font-weight: 500;
33+
line-height: 119%;
34+
margin-bottom: 1.875rem;
35+
color: var(--color-textPrimary);
36+
}
37+
38+
.zigzag {
39+
stroke: var(--color-calloutAccent);
40+
margin-left: -78px;
41+
margin-bottom: var(--spacing150);
42+
}
43+
44+
p {
45+
font-family: var(--fontSansSerif);
46+
font-size: 1rem;
47+
line-height: 150%;
48+
color: var(--color-textPrimary);
49+
}
50+
51+
.pocket-svg {
52+
display: inline-block;
53+
position: relative;
54+
height: 1.125rem;
55+
width: 1.25rem;
56+
content: ' ';
57+
background-image: url('data:image/svg+xml;utf8,<svg width="20" height="18" viewBox="0 0 20 18" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M2.46333 2.16671C2.244 2.16671 2.06283 2.34971 2.06283 2.57925V7.62041C2.06283 12.0431 5.6089 15.625 9.97949 15.625C14.3501 15.625 17.8962 12.0431 17.8962 7.62041V2.57925C17.8962 2.34971 17.715 2.16671 17.4957 2.16671H2.46333ZM2.46333 0.583374H17.4957C18.593 0.583374 19.4795 1.4788 19.4795 2.57925V7.62041C19.4795 12.9141 15.2281 17.2084 9.97949 17.2084C4.73086 17.2084 0.479492 12.9141 0.479492 7.62041V2.57925C0.479492 1.4788 1.36596 0.583374 2.46333 0.583374ZM13.3833 5.95582C13.6954 5.64959 14.1966 5.65432 14.5029 5.96639C14.8091 6.27846 14.8044 6.77969 14.4923 7.08592L10.534 10.9702C10.2261 11.2724 9.73292 11.2724 9.42501 10.9702L5.46668 7.08592C5.15461 6.77969 5.14987 6.27846 5.45611 5.96639C5.76234 5.65432 6.26357 5.64959 6.57564 5.95582L9.97949 9.29599L13.3833 5.95582Z" fill="%231A1A1A"/></svg>');
58+
background-repeat: no-repeat;
59+
background-position: center center;
60+
background-size: contain;
61+
margin: auto 0.125rem -0.25rem;
62+
}
63+
64+
.start-button:hover {
65+
background-color: var(--color-actionPrimary);
66+
text-decoration: underline;
67+
}
68+
69+
a {
70+
width: 100%;
71+
text-align: center;
72+
}
73+
74+
.close-button {
75+
position: absolute;
76+
right: var(--spacing100);
77+
top: var(--spacing100);
78+
font-size: var(--fontSize175);
79+
color: var(--color-textPrimary);
80+
&:hover {
81+
color: var(--color-textPrimary);
82+
}
83+
}
84+
85+
${breakpointSmallDesktop} {
86+
h6 {
87+
font-size: var(--fontSize175);
88+
line-height: 129%;
89+
}
90+
}
91+
`
92+
93+
const sticky = css`
94+
position: sticky;
95+
padding: 0 2rem 0 3rem;
96+
top: 8rem;
97+
margin: 0 0 8rem;
98+
margin-top: -22px;
99+
${breakpointLargeTablet} {
100+
padding: 0 1rem 0 2rem;
101+
}
102+
`
103+
104+
export function CallOutSyndicated({
105+
handleSignup,
106+
onVisible
107+
}: {
108+
handleSignup: () => null
109+
onVisible: () => null
110+
}) {
111+
const { t } = useTranslation()
112+
113+
const signupWithUTM = useRef(SIGNUP_URL)
114+
115+
useEffect(() => {
116+
signupWithUTM.current = `${SIGNUP_URL}?src=web-library-callout&utm_source=${global.location.href}&utm_medium=web`
117+
}, [])
118+
119+
// Fire a tracking event
120+
const [viewRef] = useInView({
121+
triggerOnce: true,
122+
threshold: 0.5,
123+
onChange: (inView) => inView && onVisible()
124+
})
125+
126+
return (
127+
<div>
128+
<div className={sticky}>
129+
<aside className={wrapper} ref={viewRef}>
130+
<div>
131+
<h6>
132+
{t(
133+
'discover:sign-up-to-read-this-article-later',
134+
'Sign up to read this article later'
135+
)}
136+
</h6>
137+
<svg
138+
className="zigzag"
139+
xmlns="http://www.w3.org/2000/svg"
140+
width="192"
141+
height="13"
142+
fill="none">
143+
<defs />
144+
<path
145+
stroke="#221F1F"
146+
strokeMiterlimit="10"
147+
strokeWidth="2"
148+
d="M0 1.306c13.72 0 13.72 9.91 27.42 9.91 13.7 0 13.7-9.91 27.42-9.91 13.72 0 13.72 9.91 27.42 9.91 13.72 0 13.72-9.91 27.44-9.91s13.72 9.91 27.42 9.91c13.72 0 13.72-9.91 27.44-9.91s13.72 9.91 27.44 9.91"
149+
/>
150+
</svg>
151+
<p>
152+
{t(
153+
'discover:collect-articles-cta-copy',
154+
'Collect articles, videos, and links from across the web and enjoy them on any device at any time.'
155+
)}
156+
</p>
157+
<a
158+
className="button primary start-button"
159+
rel="noopener"
160+
onClick={handleSignup}
161+
href={signupWithUTM.current}>
162+
{t('discover:sign-up', 'Sign Up')}
163+
</a>
164+
</div>
165+
</aside>
166+
</div>
167+
</div>
168+
)
169+
}

clients/web/src/connectors/snowplow/actions/syndicated-article.js

+17
Original file line numberDiff line numberDiff line change
@@ -136,5 +136,22 @@ export const syndicatedArticleActions = {
136136
},
137137
expects: ['corpusRecommendationId', 'url', 'position'],
138138
description: 'Fired when a user clicks a rec in the sidebar of a syndicated article'
139+
},
140+
'syndicated.signup.impression': {
141+
eventType: 'impression',
142+
entityTypes: ['ui'],
143+
eventData: {
144+
component: 'ui',
145+
uiType: 'button'
146+
},
147+
description: 'Signup section in the right side for logged-out users is seen'
148+
},
149+
'syndicated.signup.click': {
150+
eventType: 'engagement',
151+
entityTypes: ['ui'],
152+
eventData: {
153+
uiType: 'button'
154+
},
155+
description: 'Signup section in the right side for logged-out users is clicked through'
139156
}
140157
}

clients/web/src/containers/syndicated-article/syndicated-article.js

+13
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import { ShareToMastodon } from 'components/share-modal/share-mastodon'
3838

3939
import { mutationUpsertTransitionalItem } from 'connectors/items/mutation-upsert.state'
4040
import { mutationDeleteTransitionalItem } from 'connectors/items/mutation-delete.state'
41+
import { CallOutSyndicated } from 'components/call-out/call-out-syndicated'
4142

4243
// Possible query params passed via url
4344
const validParams = {
@@ -83,6 +84,7 @@ export function SyndicatedArticle({ queryParams = validParams, locale }) {
8384
const isMobileWebView = mobile_web_view === 'true'
8485
const isPremiumUser = premium_user === 'true' || isPremium === '1'
8586
const allowAds = userStatus === 'pending' || isPremiumUser ? false : showAds
87+
const showCTA = userStatus !== 'valid'
8688

8789
// Initialize Ads on the page
8890
// Turned off for now, but leaving for future BSA work
@@ -155,6 +157,14 @@ export function SyndicatedArticle({ queryParams = validParams, locale }) {
155157
dispatch(sendSnowplowEvent('syndicated.attribution.click', { label }))
156158
}
157159

160+
const onCTAVisible = () => {
161+
dispatch(sendSnowplowEvent('syndicated.signup.impression'))
162+
}
163+
164+
const onCTASignup = () => {
165+
dispatch(sendSnowplowEvent('syndicated.signup.click'))
166+
}
167+
158168
const showAuthors = authorNames?.length > 0
159169

160170
return (
@@ -228,6 +238,9 @@ export function SyndicatedArticle({ queryParams = validParams, locale }) {
228238

229239
{/* Right aside content such as ads and recs */}
230240
<aside className="right-aside">
241+
{showCTA ? (
242+
<CallOutSyndicated onVisible={onCTAVisible} handleSignup={onCTASignup} />
243+
) : null}
231244
<AdRailTop allowAds={allowAds} targeting={targeting} />
232245
<PublisherRecs
233246
itemId={originalItemId}

0 commit comments

Comments
 (0)