Skip to content

Commit

Permalink
Merge pull request #635 from Financial-Times/enterprise-gift-article
Browse files Browse the repository at this point in the history
  • Loading branch information
binaryberry authored Jan 28, 2022
2 parents 14c68cd + 8ababf3 commit 05e03f5
Show file tree
Hide file tree
Showing 21 changed files with 718 additions and 64 deletions.
3 changes: 3 additions & 0 deletions components/x-gift-article/bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
"private": true,
"dependencies": {
"o-buttons": "^6.0.0",
"o-colors": "^5.0.0",
"o-forms": "^8.0.0",
"o-icons": "^6.0.0",
"o-labels": "5.0.0",
"o-loading": "^4.0.0",
"o-message": "^4.0.0",
"o-typography": "6.0.0",
Expand Down
1 change: 1 addition & 0 deletions components/x-gift-article/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ Property | Type | Required | Note
`nativeShare` | Boolean | no | This is a property for App to display Native Sharing.
`apiProtocol` | String | no | The protocol to use when making requests to the gift article and URL shortening services. Ignored if `apiDomain` is not set.
`apiDomain` | String | no | The domain to use when making requests to the gift article and URL shortening services.
`enterpriseApiBaseUrl` | String | no | The base URL to use when making requests to the enterprise sharing service.

###
`isArticleSharingUxUpdates` boolean has been added as part of ACC-749 to enable AB testing of the impact of minor UX improvements to x-gift-article. Once AB testing is done, and decision to keep / remove has been made, the changes made in https://github.com/Financial-Times/x-dash/pull/579 need to be ditched or baked in as default.
20 changes: 16 additions & 4 deletions components/x-gift-article/src/Buttons.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,13 @@ export default ({
<button
className={ButtonWithGapClassNames}
type="button"
onClick={shareType === ShareType.gift ? actions.copyGiftUrl : actions.copyNonGiftUrl}
onClick={
shareType === ShareType.gift
? actions.copyGiftUrl
: shareType === ShareType.enterprise
? actions.copyEnterpriseUrl
: actions.copyNonGiftUrl
}
aria-label="Copy the gift article link to your clipboard">
Copy link
</button>
Expand All @@ -44,7 +50,13 @@ export default ({
href={mailtoUrl}
target="_blank"
rel="noopener noreferrer"
onClick={shareType === ShareType.gift ? actions.emailGiftUrl : actions.emailNonGiftUrl}>
onClick={
shareType === ShareType.gift
? actions.emailGiftUrl
: shareType === ShareType.enterprise
? actions.emailEnterpriseUrl
: actions.emailNonGiftUrl
}>
Email link <span className={styles['visually-hidden']}>to Share this article</span>
</a>
</div>
Expand All @@ -57,8 +69,8 @@ export default ({
className={ButtonClassNames}
disabled={!giftCredits}
type="button"
onClick={actions.createGiftUrl}>
Create gift link
onClick={shareType === ShareType.enterprise ? actions.createEnterpriseUrl : actions.createGiftUrl}>
Create {shareType === ShareType.enterprise ? 'enterprise' : 'gift'} link
</button>
</div>
)
Expand Down
6 changes: 6 additions & 0 deletions components/x-gift-article/src/Form.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ export default (props) => (
shareType={props.shareType}
isArticleSharingUxUpdates={props.isArticleSharingUxUpdates}
showGiftUrlSection={props.actions.showGiftUrlSection}
showEnterpriseUrlSection={props.actions.showEnterpriseUrlSection}
showNonGiftUrlSection={props.actions.showNonGiftUrlSection}
enterpriseLimit={props.enterpriseLimit}
enterpriseHasCredits={props.enterpriseHasCredits}
enterpriseRequestAccess={props.enterpriseRequestAccess}
enterpriseAlert={!props.enterpriseHasCredits && !props.enterpriseRequestAccess}
enterpriseEnabled={props.enterpriseEnabled}
/>
)}

Expand Down
61 changes: 57 additions & 4 deletions components/x-gift-article/src/GiftArticle.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import Loading from './Loading'
import Form from './Form'

import ApiClient from './lib/api'
import EnterpriseApiClient from './lib/enterpriseApi'
import { copyToClipboard, createMailtoUrl } from './lib/share-link-actions'
import tracking from './lib/tracking'
import * as updaters from './lib/updaters'
import { ShareType } from './lib/constants'

const isCopySupported =
typeof document !== 'undefined' && document.queryCommandSupported && document.queryCommandSupported('copy')
Expand All @@ -21,12 +23,17 @@ const withGiftFormActions = withActions(
protocol: initialProps.apiProtocol,
domain: initialProps.apiDomain
})
const enterpriseApi = new EnterpriseApiClient(initialProps.enterpriseApiBaseUrl)

return {
showGiftUrlSection() {
return updaters.showGiftUrlSection
},

showEnterpriseUrlSection() {
return updaters.showGiftEnterpriseSection
},

showNonGiftUrlSection() {
return async (state) => {
const update = updaters.showNonGiftUrlSection(state)
Expand All @@ -52,7 +59,18 @@ const withGiftFormActions = withActions(

return updaters.setGiftUrl(url, redemptionLimit, isShortened)
} else {
// TODO do something
return updaters.setErrorState(true)
}
},

async createEnterpriseUrl() {
const { redemptionUrl, redemptionLimit } = await enterpriseApi.getESUrl(initialProps.article.id)

if (redemptionUrl) {
tracking.createESLink(redemptionUrl)
return updaters.setGiftUrl(redemptionUrl, redemptionLimit, false, true)
} else {
return updaters.setErrorState(true)
}
},

Expand All @@ -67,6 +85,17 @@ const withGiftFormActions = withActions(
}
},

copyEnterpriseUrl(event) {
copyToClipboard(event)

return (state) => {
const enterpriseUrl = state.urls.enterprise
tracking.copyLink('enterpriseLink', enterpriseUrl)

return { showCopyConfirmation: true }
}
},

copyNonGiftUrl(event) {
copyToClipboard(event)

Expand All @@ -84,6 +113,12 @@ const withGiftFormActions = withActions(
}
},

emailEnterpriseUrl() {
return (state) => {
tracking.emailLink('enterpriseLink', state.urls.enterprise)
}
},

emailNonGiftUrl() {
return (state) => {
tracking.emailLink('nonGiftLink', state.urls.nonGift)
Expand All @@ -108,12 +143,28 @@ const withGiftFormActions = withActions(
}
} else {
const { giftCredits, monthlyAllowance, nextRenewalDate } = await api.getGiftArticleAllowance()

const { enabled, limit, hasCredits, firstTimeUser, requestAccess } =
await enterpriseApi.getEnterpriseArticleAllowance()
// avoid to use giftCredits >= 0 because it returns true when null and ""
if (giftCredits > 0 || giftCredits === 0) {
return updaters.setAllowance(giftCredits, monthlyAllowance, nextRenewalDate)
return {
...updaters.setAllowance(giftCredits, monthlyAllowance, nextRenewalDate),
shareType: enabled ? ShareType.enterprise : ShareType.gift,
enterpriseEnabled: enabled,
enterpriseLimit: limit,
enterpriseHasCredits: hasCredits,
enterpriseFirstTimeUser: firstTimeUser,
enterpriseRequestAccess: requestAccess
}
} else {
return { invalidResponseFromApi: true }
return {
invalidResponseFromApi: true,
enterpriseEnabled: enabled,
enterpriseLimit: limit,
enterpriseHasCredits: hasCredits,
enterpriseFirstTimeUser: firstTimeUser,
enterpriseRequestAccess: requestAccess
}
}
}
}
Expand All @@ -135,11 +186,13 @@ const withGiftFormActions = withActions(
urls: {
dummy: 'https://on.ft.com/gift_link',
gift: undefined,
enterprise: undefined,
nonGift: `${props.article.url}?shareType=nongift`
},

mailtoUrls: {
gift: undefined,
enterprise: undefined,
nonGift: createMailtoUrl(props.article.title, `${props.article.url}?shareType=nongift`)
},

Expand Down
60 changes: 51 additions & 9 deletions components/x-gift-article/src/GiftArticle.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,34 @@ $o-message-is-silent: true;
$o-typography-is-silent: true;
@import 'o-typography/main';

$o-labels-is-silent: true;
@import 'o-labels/main';

$o-colors-is-silent: true;
@import 'o-colors/main';

$o-icons-is-silent: true;
@import 'o-icons/main';


.container {
@include oTypographySans;
strong {
font-weight: 600;
}
}

.o-icons__enterprise-no-credits {
@include oIconsContent(
$icon-name: 'warning',
$color: oColorsByName('crimson'),
$size: 16
);
border-radius: 50%;
border: 2px solid oColorsByName('crimson');
margin-bottom: -5px;
}


.share-form {
max-width: none;
Expand All @@ -36,6 +57,17 @@ $o-typography-is-silent: true;

.radio-button-section {
margin-bottom: 12px;
@include oLabels($opts: (
'states': (
'content-premium'
),
));

.enterprise-label {
background-color: oColorsByName('black-10');
color: oColorsByName('black');
margin: 0px 6px;
}
}

.share-option-title {
Expand All @@ -53,14 +85,6 @@ $o-typography-is-silent: true;
.share-option-title {
@include oNormaliseVisuallyHidden();
}

.o-forms-field{
@media only screen and (min-width: 600px) {
label[for$="Link"]{
margin-bottom: 0;
}
}
}
}

@media only screen and (min-width: 600px) {
Expand Down Expand Up @@ -99,13 +123,31 @@ $o-typography-is-silent: true;
margin-top: 12px;
}

.enterprise-message {
grid-area: message;
background: oColorsByName('white-40');
border: 1px solid oColorsByName('black-5');
margin-top: oSpacingByName('s4');
padding: oSpacingByName('s4');

h4 {
@include oTypographySans($scale: 1, $weight: 'semibold');
color: oColorsByName('black-90');
font-size: 16px;
margin: 0;
}
p {
margin: oSpacingByName('s2') 0px;
}
}

.buttonBaseStyle {
@include oButtonsContent($opts: ('type': 'primary', 'size':'big'));
}

.buttons {
grid-area: buttons;
text-align: right;
text-align: left;
white-space: nowrap;
margin-top: 12px;
}
Expand Down
77 changes: 75 additions & 2 deletions components/x-gift-article/src/Message.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ export default ({
nextRenewalDateText,
redemptionLimit,
invalidResponseFromApi,
isArticleSharingUxUpdates
isArticleSharingUxUpdates,
enterpriseLimit,
enterpriseHasCredits,
enterpriseRequestAccess,
enterpriseFirstTimeUser
}) => {
if (isArticleSharingUxUpdates) {
if (isFreeArticle) {
Expand Down Expand Up @@ -80,7 +84,7 @@ export default ({

return (
<div className={messageClassName}>
You have{' '}
Uses 1 gift credit. You have{' '}
<strong>
{giftCredits} gift article {giftCredits === 1 ? 'credit' : 'credits'}
</strong>{' '}
Expand All @@ -89,6 +93,75 @@ export default ({
)
}

if (shareType === ShareType.enterprise) {
if (invalidResponseFromApi) {
return <div className={messageClassName}>Unable to create enterprise link. Please try again later</div>
}

if (isGiftUrlCreated === true) {
return (
<div className={messageClassName}>
This link can be opened by up to {enterpriseLimit} people and is valid for 90 days
</div>
)
}
if (enterpriseHasCredits === true) {
if (enterpriseFirstTimeUser) {
return (
<div className={styles['enterprise-message']}>
<h4>Engage more effectively with clients and colleagues.</h4>
<p>
Enterprise Sharing lets members of your organisation share FT article links with up to{' '}
{enterpriseLimit} people, even if they don’t have a FT subscription.
</p>
</div>
)
}
return (
<div className={messageClassName}>
Your organisation has <strong>Enterprise Sharing credits</strong> available for you to use
</div>
)
} else {
if (enterpriseRequestAccess) {
//Activation Message
return (
<div className={styles['enterprise-message']}>
<h4>Enterprise Sharing is not enabled for your team</h4>
<p>
Enterprise Sharing lets members of your organisation share FT article links with potentially
thousands people, even if they don’t have a FT subscription
</p>
<a
href="https://enterprise.ft.com/ft-enterprise-sharing-request-access/?segmentId=c87259e0-7073-3ea8-7f83-b988f05c3f94"
target="_blank"
rel="noreferrer"
className={styles['buttonBaseStyle']}>
Learn more
</a>
</div>
)
}
return (
<div className={styles['enterprise-message']}>
<h4>Your organisation has run out of share credits.</h4>
<p>
Request more credits and our Enterprise team will get in touch with the admin of your FT
subscription to arrange a top-up of sharing credits.
</p>
<a
href="https://enterprise.ft.com/ft-enterprise-sharing-request-access/?segmentId=c87259e0-7073-3ea8-7f83-b988f05c3f94"
target="_blank"
rel="noreferrer"
className={styles['buttonBaseStyle']}
type="button">
Request more credits
</a>
</div>
)
}
}

if (shareType === ShareType.nonGift) {
return <div className={messageClassName}>This link can only be read by existing subscribers</div>
}
Expand Down
Loading

0 comments on commit 05e03f5

Please sign in to comment.