Unverified Commit 226f3826 authored by Lyza Gardner's avatar Lyza Gardner Committed by GitHub

Merge pull request #1507 from hypothesis/share-links-subcomponent

Extract `ShareLinks` component
parents 249b7b2b 94398f41
......@@ -7,6 +7,7 @@ const { copyText } = require('../util/copy-to-clipboard');
const { withServices } = require('../util/service-context');
const uiConstants = require('../ui-constants');
const ShareLinks = require('./share-links');
const SidebarPanel = require('./sidebar-panel');
const SvgIcon = require('./svg-icon');
......@@ -41,14 +42,6 @@ function ShareAnnotationsPanel({ analytics, flash }) {
}`;
})(mainFrame, focusedGroup);
// This is the double-encoded format needed for other services (the entire
// URI needs to be encoded because it's used as the value of querystring params)
const encodedURI = encodeURIComponent(shareURI);
const trackShareClick = shareTarget => {
analytics.track(analytics.events.DOCUMENT_SHARED, shareTarget);
};
const copyShareLink = () => {
try {
copyText(shareURI);
......@@ -114,46 +107,10 @@ function ShareAnnotationsPanel({ analytics, flash }) {
<em>Only Me</em>) annotations are only visible to you.
</span>
</p>
<ul className="share-annotations-panel-links">
<li className="share-annotations-panel-links__link">
<a
href={`https://twitter.com/intent/tweet?url=${encodedURI}&hashtags=annotated`}
title="Tweet share link"
onClick={trackShareClick('twitter')}
>
<SvgIcon
name="twitter"
className="share-annotations-panel-links__icon"
/>
</a>
</li>
<li className="share-annotations-panel__link">
<a
href={`https://www.facebook.com/sharer/sharer.php?u=${encodedURI}`}
title="Share on Facebook"
onClick={trackShareClick('facebook')}
>
<SvgIcon
name="facebook"
className="share-annotations-panel-links__icon"
/>
</a>
</li>
<li className="share-annotations-panel__link">
<a
href={`mailto:?subject=${encodeURIComponent(
"Let's Annotate"
)}&body=${encodedURI}`}
title="Share via email"
onClick={trackShareClick('email')}
>
<SvgIcon
name="email"
className="share-annotations-panel-links__icon"
/>
</a>
</li>
</ul>
<ShareLinks
shareURI={shareURI}
analyticsEventName={analytics.events.DOCUMENT_SHARED}
/>
</div>
)}
</SidebarPanel>
......
'use strict';
const propTypes = require('prop-types');
const { createElement } = require('preact');
const { withServices } = require('../util/service-context');
const SvgIcon = require('./svg-icon');
/**
* A list of share links to social-media platforms.
*/
function ShareLinks({ analytics, analyticsEventName, shareURI }) {
const trackShareClick = shareTarget => {
analytics.track(analyticsEventName, shareTarget);
};
// This is the double-encoded format needed for other services (the entire
// URI needs to be encoded because it's used as the value of querystring params)
const encodedURI = encodeURIComponent(shareURI);
return (
<ul className="share-links">
<li className="share-links__link">
<a
href={`https://twitter.com/intent/tweet?url=${encodedURI}&hashtags=annotated`}
title="Tweet share link"
onClick={trackShareClick('twitter')}
>
<SvgIcon name="twitter" className="share-links__icon" />
</a>
</li>
<li className="share-links__link">
<a
href={`https://www.facebook.com/sharer/sharer.php?u=${encodedURI}`}
title="Share on Facebook"
onClick={trackShareClick('facebook')}
>
<SvgIcon name="facebook" className="share-links__icon" />
</a>
</li>
<li className="share-links__link">
<a
href={`mailto:?subject=${encodeURIComponent(
"Let's Annotate"
)}&body=${encodedURI}`}
title="Share via email"
onClick={trackShareClick('email')}
>
<SvgIcon name="email" className="share-links__icon" />
</a>
</li>
</ul>
);
}
ShareLinks.propTypes = {
/** Analytics event to track when share links are clicked */
analyticsEventName: propTypes.string.isRequired,
/** URI to shared resource(s), e.g. an annotation or collection of annotations */
shareURI: propTypes.string.isRequired,
// Services/injected
analytics: propTypes.object.isRequired,
};
ShareLinks.injectedProps = ['analytics'];
module.exports = withServices(ShareLinks);
......@@ -174,43 +174,4 @@ describe('ShareAnnotationsPanel', () => {
});
});
});
describe('other share links', () => {
const shareLink =
'https://hyp.is/go?url=https%3A%2F%2Fwww.example.com&group=testprivate';
const encodedLink = encodeURIComponent(shareLink);
const encodedSubject = encodeURIComponent("Let's Annotate");
[
{
service: 'facebook',
expectedURI: `https://www.facebook.com/sharer/sharer.php?u=${encodedLink}`,
title: 'Share on Facebook',
},
{
service: 'twitter',
expectedURI: `https://twitter.com/intent/tweet?url=${encodedLink}&hashtags=annotated`,
title: 'Tweet share link',
},
{
service: 'email',
expectedURI: `mailto:?subject=${encodedSubject}&body=${encodedLink}`,
title: 'Share via email',
},
].forEach(testCase => {
it(`creates a share link for ${testCase.service} and tracks clicks`, () => {
const wrapper = createShareAnnotationsPanel();
const link = wrapper.find(`a[title="${testCase.title}"]`);
link.simulate('click');
assert.equal(link.prop('href'), testCase.expectedURI);
assert.calledWith(
fakeAnalytics.track,
fakeAnalytics.events.DOCUMENT_SHARED,
testCase.service
);
});
});
});
});
'use strict';
const { createElement } = require('preact');
const { mount } = require('enzyme');
const ShareLinks = require('../share-links');
const mockImportedComponents = require('./mock-imported-components');
describe('ShareLinks', () => {
let fakeAnalytics;
const shareLink =
'https://hyp.is/go?url=https%3A%2F%2Fwww.example.com&group=testprivate';
const createComponent = props =>
mount(
<ShareLinks
analyticsEventName="potato-peeling"
analytics={fakeAnalytics}
shareURI={shareLink}
{...props}
/>
);
beforeEach(() => {
fakeAnalytics = {
track: sinon.stub(),
};
ShareLinks.$imports.$mock(mockImportedComponents());
});
afterEach(() => {
ShareLinks.$imports.$restore();
});
const encodedLink = encodeURIComponent(shareLink);
const encodedSubject = encodeURIComponent("Let's Annotate");
[
{
service: 'facebook',
expectedURI: `https://www.facebook.com/sharer/sharer.php?u=${encodedLink}`,
title: 'Share on Facebook',
},
{
service: 'twitter',
expectedURI: `https://twitter.com/intent/tweet?url=${encodedLink}&hashtags=annotated`,
title: 'Tweet share link',
},
{
service: 'email',
expectedURI: `mailto:?subject=${encodedSubject}&body=${encodedLink}`,
title: 'Share via email',
},
].forEach(testCase => {
it(`creates a share link for ${testCase.service} and tracks clicks`, () => {
const wrapper = createComponent({ shareURI: shareLink });
const link = wrapper.find(`a[title="${testCase.title}"]`);
link.simulate('click');
assert.equal(link.prop('href'), testCase.expectedURI);
assert.calledWith(
fakeAnalytics.track,
'potato-peeling',
testCase.service
);
});
});
});
@use '../../mixins/links';
.share-links {
@include links.footer-links;
&__icon {
width: 24px;
height: 24px;
}
}
......@@ -45,6 +45,7 @@ $base-line-height: 20px;
@import './components/selection-tabs';
@import './components/share-annotations-panel';
@import './components/search-input';
@import './components/share-links';
@import './components/sidebar-panel';
@import './components/svg-icon';
@import './components/spinner';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment