Commit 3e0bbe14 authored by Lyza Danger Gardner's avatar Lyza Danger Gardner

Add UI to Focused User Mode

parent 674aa8bf
......@@ -4,42 +4,59 @@ const { createElement } = require('preact');
const useStore = require('../store/use-store');
const SvgIcon = require('./svg-icon');
/**
* Render a control to interact with any focused "mode" in the sidebar.
* Currently only a user-focus mode is supported but this could be broadened
* and abstracted if needed. Allow user to toggle in and out of the focus "mode."
*/
function FocusedModeHeader() {
const store = useStore(store => ({
actions: {
const actions = useStore(store => ({
setFocusModeFocused: store.setFocusModeFocused,
},
selectors: {
focusModeFocused: store.focusModeFocused,
focusModeUserPrettyName: store.focusModeUserPrettyName,
},
}));
const selectors = useStore(store => ({
focusModeFocused: store.focusModeFocused(),
focusModeHasUser: store.focusModeHasUser(),
focusModeUserPrettyName: store.focusModeUserPrettyName(),
}));
// Nothing to do here for now if we're not focused on a user
if (!selectors.focusModeHasUser) {
return null;
}
const toggleFocusedMode = () => {
store.actions.setFocusModeFocused(!store.selectors.focusModeFocused());
actions.setFocusModeFocused(!selectors.focusModeFocused);
};
const buttonText = () => {
if (store.selectors.focusModeFocused()) {
return `Annotations by ${store.selectors.focusModeUserPrettyName()}`;
const filterStatus = (
<div className="focused-mode-header__filter-status">
{selectors.focusModeFocused ? (
<span>
Annotations by <strong>{selectors.focusModeUserPrettyName}</strong>{' '}
only
</span>
) : (
<span>Everybody&rsquo;s annotations</span>
)}
</div>
);
const buttonText = (() => {
if (selectors.focusModeFocused) {
return 'Show all';
} else {
return 'All annotations';
return `Only ${selectors.focusModeUserPrettyName}`;
}
};
})();
return (
<div className="focused-mode-header">
<button
onClick={toggleFocusedMode}
className="primary-action-btn primary-action-btn--short"
title={`Toggle to show annotations only by ${store.selectors.focusModeUserPrettyName()}`}
>
{buttonText()}
<div className="focused-mode-header sheet">
{filterStatus}
<button onClick={toggleFocusedMode} className="focused-mode-header__btn">
<SvgIcon name="cancel" className="focused-mode-header__btn-icon" />
{buttonText}
</button>
</div>
);
......
......@@ -19,8 +19,9 @@ describe('FocusedModeHeader', function() {
focused: true,
},
},
focusModeFocused: sinon.stub().returns(false),
focusModeFocused: sinon.stub().returns(true),
focusModeUserPrettyName: sinon.stub().returns('Fake User'),
focusModeHasUser: sinon.stub().returns(true),
setFocusModeFocused: sinon.stub(),
};
FocusedModeHeader.$imports.$mock({
......@@ -32,29 +33,71 @@ describe('FocusedModeHeader', function() {
FocusedModeHeader.$imports.$restore();
});
it('creates the component', () => {
context('not in user-focused mode', () => {
it('should not render anything if not in user-focused mode', () => {
fakeStore.focusModeHasUser = sinon.stub().returns(false);
const wrapper = createComponent();
assert.include(wrapper.text(), 'All annotations');
assert.isFalse(wrapper.exists('.focused-mode-header'));
});
});
it("sets the button's text to the user's name when focused", () => {
fakeStore.focusModeFocused = sinon.stub().returns(true);
context('user-focused mode', () => {
context('focus is applied (focused/on)', () => {
it("should render status text indicating only that user's annotations are visible", () => {
const wrapper = createComponent();
assert.include(wrapper.text(), 'Annotations by Fake User');
assert.match(wrapper.text(), /Annotations by.+Fake User/);
});
describe('clicking the button shall toggle the focused mode', function() {
it('when focused is false, toggle to true', () => {
it('should render a button allowing the user to view all annotations', () => {
const wrapper = createComponent();
wrapper.find('button').simulate('click');
assert.calledWith(fakeStore.setFocusModeFocused, true);
const button = wrapper.find('button');
assert.include(button.text(), 'Show all');
});
});
context('focus is not applied (unfocused/off)', () => {
beforeEach(() => {
fakeStore.focusModeFocused = sinon.stub().returns(false);
});
it("should render status text indicating that all user's annotations are visible", () => {
const wrapper = createComponent();
assert.match(wrapper.text(), /Everybody.*s annotations/);
});
it('when focused is true, toggle to false', () => {
it("should render a button allowing the user to view only focus user's annotations", () => {
const wrapper = createComponent();
const button = wrapper.find('button');
assert.include(button.text(), 'Only Fake User');
});
});
describe('toggle button', () => {
it('should toggle focus mode to false if clicked when focused', () => {
fakeStore.focusModeFocused = sinon.stub().returns(true);
const wrapper = createComponent();
wrapper.find('button').simulate('click');
assert.calledWith(fakeStore.setFocusModeFocused, false);
});
it('should toggle focus mode to true if clicked when not focused', () => {
fakeStore.focusModeFocused = sinon.stub().returns(false);
const wrapper = createComponent();
wrapper.find('button').simulate('click');
assert.calledWith(fakeStore.setFocusModeFocused, true);
});
});
});
});
......@@ -55,7 +55,8 @@ function RootThread($rootScope, store, searchFilter, viewFilter) {
let filterFn;
if (shouldFilterThread()) {
const filters = searchFilter.generateFacetedFilter(state.filterQuery, {
user: store.focusModeUsername(), // `null` if no focused user
// if a focus mode is applied (focused) and we're focusing on a user
user: store.focusModeFocused() && store.focusModeUsername(),
});
filterFn = function(annot) {
......
// A dark grey button used for the primary action
// in a form
.focused-mode-header {
margin-bottom: 10px;
button {
width: 100%;
height: 24px;
margin-right: 10px;
&:focus {
outline: none;
display: flex;
align-items: center;
&__btn {
@include primary-action-btn;
@include outline-on-keyboard-focus;
display: flex;
margin-left: auto;
height: 30px;
padding-left: 6px;
padding-right: 10px;
background-color: $grey-2;
color: $grey-5;
&:hover:enabled {
background-color: $grey-3;
}
}
&__btn-icon {
margin-right: 3px;
}
&__filter-status {
font-weight: 400;
}
}
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