Commit 279808f8 authored by Lyza Danger Gardner's avatar Lyza Danger Gardner

Add `AnnotationShareInfo` component

- Used by `AnnotationHeader`
- Renders group and privacy info for an annotation
parent 1c164e6a
'use strict';
const propTypes = require('prop-types');
const { createElement } = require('preact');
const SvgIcon = require('./svg-icon');
const useStore = require('../store/use-store');
/**
* Render information about what group an annotation is in and
* whether it is private to the current user (only me)
*/
function AnnotationShareInfo({ annotation, isPrivate }) {
const group = useStore(store => store.getGroup(annotation.group));
// We may not have access to the group object beyond its ID
const hasGroup = !!group;
// Only show the name of the group and link to it if there is a
// URL (link) returned by the API for this group. Some groups do not have links
const linkToGroup = hasGroup && group.links && group.links.html;
return (
<div className="annotation-share-info">
{linkToGroup && (
<a
className="annotation-share-info__group"
href={group.links.html}
target="_blank"
rel="noopener noreferrer"
>
{group.type === 'open' ? (
<SvgIcon className="annotation-share-info__icon" name="public" />
) : (
<SvgIcon className="annotation-share-info__icon" name="groups" />
)}
<span className="annotation-share-info__group-info">
{group.name}
</span>
</a>
)}
{isPrivate && (
<span
className="annotation-share-info__private"
title="This annotation is visible only to you."
>
{/* Show the lock icon in all cases when the annotation is private... */}
<SvgIcon className="annotation-share-info__icon" name="lock" />
{/* but only render the "Only Me" text if we're not showing/linking a group name */}
{!linkToGroup && (
<span className="annotation-share-info__private-info">Only me</span>
)}
</span>
)}
</div>
);
}
AnnotationShareInfo.propTypes = {
/** The current annotation object for which sharing info will be rendered */
annotation: propTypes.object.isRequired,
/** Is this an "only me" (private) annotation? */
isPrivate: propTypes.bool.isRequired,
};
module.exports = AnnotationShareInfo;
'use strict';
const { createElement } = require('preact');
const { shallow } = require('enzyme');
const fixtures = require('../../test/annotation-fixtures');
const AnnotationShareInfo = require('../annotation-share-info');
describe('AnnotationShareInfo', () => {
let fakeGroup;
let fakeStore;
let fakeGetGroup;
const createAnnotationShareInfo = props => {
return shallow(
<AnnotationShareInfo
annotation={fixtures.defaultAnnotation()}
isPrivate={false}
{...props}
/>
);
};
beforeEach(() => {
fakeGroup = {
name: 'My Group',
links: {
html: 'https://www.example.com',
},
type: 'private',
};
fakeGetGroup = sinon.stub().returns(fakeGroup);
fakeStore = { getGroup: fakeGetGroup };
AnnotationShareInfo.$imports.$mock({
'../store/use-store': callback => callback(fakeStore),
});
});
afterEach(() => {
AnnotationShareInfo.$imports.$restore();
});
describe('group link', () => {
it('should show a link to the group for extant, first-party groups', () => {
const wrapper = createAnnotationShareInfo();
const groupLink = wrapper.find('.annotation-share-info__group');
const groupName = wrapper.find('.annotation-share-info__group-info');
assert.equal(groupLink.prop('href'), fakeGroup.links.html);
assert.equal(groupName.text(), fakeGroup.name);
});
it('should display a group icon for private and restricted groups', () => {
const wrapper = createAnnotationShareInfo();
const groupIcon = wrapper.find(
'.annotation-share-info__group .annotation-share-info__icon'
);
assert.equal(groupIcon.prop('name'), 'groups');
});
it('should display a public/world icon for open groups', () => {
fakeGroup.type = 'open';
const wrapper = createAnnotationShareInfo();
const groupIcon = wrapper.find(
'.annotation-share-info__group .annotation-share-info__icon'
);
assert.equal(groupIcon.prop('name'), 'public');
});
it('should not show a link to third-party groups', () => {
// Third-party groups have no `html` link
fakeGetGroup.returns({ name: 'A Group', links: {} });
const wrapper = createAnnotationShareInfo();
const groupLink = wrapper.find('.annotation-share-info__group');
assert.notOk(groupLink.exists());
});
it('should not show a link if no group available', () => {
fakeGetGroup.returns(undefined);
const wrapper = createAnnotationShareInfo();
const groupLink = wrapper.find('.annotation-share-info__group');
assert.notOk(groupLink.exists());
});
});
describe('"only you" information', () => {
it('should not show privacy information if annotation is not private', () => {
const wrapper = createAnnotationShareInfo({ isPrivate: false });
const privacy = wrapper.find('.annotation-share-info__private');
assert.notOk(privacy.exists());
});
context('private annotation', () => {
it('should show privacy icon', () => {
const wrapper = createAnnotationShareInfo({ isPrivate: true });
const privacyIcon = wrapper.find(
'.annotation-share-info__private .annotation-share-info__icon'
);
assert.isOk(privacyIcon.exists());
assert.equal(privacyIcon.prop('name'), 'lock');
});
it('should not show "only me" text for first-party group', () => {
const wrapper = createAnnotationShareInfo({ isPrivate: true });
const privacyText = wrapper.find(
'.annotation-share-info__private-info'
);
assert.notOk(privacyText.exists());
});
it('should show "only me" text for annotation in third-party group', () => {
fakeGetGroup.returns({ name: 'Some Name' });
const wrapper = createAnnotationShareInfo({ isPrivate: true });
const privacyText = wrapper.find(
'.annotation-share-info__private-info'
);
assert.isOk(privacyText.exists());
assert.equal(privacyText.text(), 'Only me');
});
});
});
});
.annotation-share-info {
display: flex;
align-items: baseline;
&__group,
&__private {
display: flex;
align-items: baseline;
font-size: $body1-font-size;
color: $grey-5;
}
&__group-info {
margin-right: 5px;
}
&__private-info {
margin-right: 5px;
}
&__icon {
margin-right: 5px;
width: 10px;
height: 10px;
}
}
...@@ -21,6 +21,7 @@ $base-line-height: 20px; ...@@ -21,6 +21,7 @@ $base-line-height: 20px;
@import './components/annotation'; @import './components/annotation';
@import './components/annotation-document-info'; @import './components/annotation-document-info';
@import './components/annotation-share-dialog'; @import './components/annotation-share-dialog';
@import './components/annotation-share-info';
@import './components/annotation-publish-control'; @import './components/annotation-publish-control';
@import './components/annotation-thread'; @import './components/annotation-thread';
@import './components/annotation-user'; @import './components/annotation-user';
......
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