Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Components: Extract Reusable Post Sticky Component #3114

Merged
merged 1 commit into from
Oct 27, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions editor/post-sticky/check.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* External dependencies
*/
import { connect } from 'react-redux';
import { flowRight } from 'lodash';

/**
* WordPress dependencies
*/
import { withAPIData } from '@wordpress/components';

/**
* Internal dependencies
*/
import { getCurrentPostType } from '../selectors';

export function PostStickyCheck( { postType, children, user } ) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid duplicating the "support sticky" check, I extracted it to its own component. I could reuse this approach for all the other sidebar panels.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works well.

Otherwise, I could imagine the following:

// new HoC
const withUserPrivileges = ( predicate ) =>
  flowRight(
    withAPIData( constant( { user: '/wp/v2…' } ) ),
    withRenderIf( predicate )
  );

// consumer
import withUserPrivilege from ;
const applyPostStickyCheck = withUserPrivileges( ( { postType, user } ) =>
  postType !== 'post' ||
    ! user.data ||
    ! user.data.capabilities.publish_posts ||
    ! user.data.capabilities.edit_others_posts
);

export default applyPostStickyCheck( MyComponent );

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could obfuscate component render logic, though. Right now most HoCs only deal with prop injection and side effects (like click-outside), not affecting when things should be rendered. Which is why the current way seems appropriate. 👌

if (
postType !== 'post' ||
! user.data ||
! user.data.capabilities.publish_posts ||
! user.data.capabilities.edit_others_posts
) {
return null;
}

return children;
}

const applyConnect = connect(
( state ) => {
return {
postType: getCurrentPostType( state ),
};
},
);

const applyWithAPIData = withAPIData( () => {
return {
user: '/wp/v2/users/me?context=edit',
};
} );

export default flowRight( [
applyConnect,
applyWithAPIData,
] )( PostStickyCheck );
55 changes: 55 additions & 0 deletions editor/post-sticky/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* External dependencies
*/
import { connect } from 'react-redux';
import { flowRight } from 'lodash';

/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { FormToggle, withInstanceId } from '@wordpress/components';

/**
* Internal dependencies
*/
import { getEditedPostAttribute } from '../selectors';
import { editPost } from '../actions';
import PostStickyCheck from './check';

export function PostSticky( { onUpdateSticky, postSticky = false, instanceId } ) {
const stickyToggleId = 'post-sticky-toggle-' + instanceId;

return (
<PostStickyCheck>
<label htmlFor={ stickyToggleId }>{ __( 'Stick to the Front Page' ) }</label>
<FormToggle
key="toggle"
checked={ postSticky }
onChange={ () => onUpdateSticky( ! postSticky ) }
showHint={ false }
id={ stickyToggleId }
/>
</PostStickyCheck>
);
}

const applyConnect = connect(
( state ) => {
return {
postSticky: getEditedPostAttribute( state, 'sticky' ),
};
},
( dispatch ) => {
return {
onUpdateSticky( postSticky ) {
dispatch( editPost( { sticky: postSticky } ) );
},
};
},
);

export default flowRight( [
applyConnect,
withInstanceId,
] )( PostSticky );
65 changes: 65 additions & 0 deletions editor/post-sticky/test/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/**
* External dependencies
*/
import { shallow } from 'enzyme';

/**
* Internal dependencies
*/
import { PostStickyCheck } from '../check';

describe( 'PostSticky', () => {
const user = {
data: {
capabilities: {
edit_others_posts: true,
publish_posts: true,
},
},
};

it( 'should not render anything if the post type is not "post"', () => {
const wrapper = shallow(
<PostStickyCheck postType="page" user={ user }>
Can Toggle Sticky
</PostStickyCheck>
);
expect( wrapper.type() ).toBe( null );
} );

it( 'should not render anything if the user doesn\'t have the right capabilities', () => {
let wrapper = shallow(
<PostStickyCheck postType="post" user={ {} }>
Can Toggle Sticky
</PostStickyCheck>
);
expect( wrapper.type() ).toBe( null );

wrapper = shallow(
<PostStickyCheck postType="post" user={
{ data: { capabilities: { edit_others_posts: false, publish_posts: true } } }
}>
Can Toggle Sticky
</PostStickyCheck>
);
expect( wrapper.type() ).toBe( null );

wrapper = shallow(
<PostStickyCheck postType="post" user={
{ data: { capabilities: { edit_others_posts: true, publish_posts: false } } }
}>
Can Toggle Sticky
</PostStickyCheck>
);
expect( wrapper.type() ).toBe( null );
} );

it( 'should render if the user has the correct capability', () => {
const wrapper = shallow(
<PostStickyCheck postType="post" user={ user }>
Can Toggle Sticky
</PostStickyCheck>
);
expect( wrapper.type() ).not.toBe( null );
} );
} );
68 changes: 10 additions & 58 deletions editor/sidebar/post-sticky/index.js
Original file line number Diff line number Diff line change
@@ -1,70 +1,22 @@
/**
* External dependencies
*/
import { connect } from 'react-redux';
import { flowRight } from 'lodash';

/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { PanelRow, FormToggle, withInstanceId, withAPIData } from '@wordpress/components';
import { PanelRow } from '@wordpress/components';

/**
* Internal dependencies
*/
import { getEditedPostAttribute, getCurrentPostType } from '../../selectors';
import { editPost } from '../../actions';

export function PostSticky( { onUpdateSticky, postType, postSticky = false, instanceId, user } ) {
if (
postType !== 'post' ||
! user.data ||
! user.data.capabilities.publish_posts ||
! user.data.capabilities.edit_others_posts
) {
return false;
}

const stickyToggleId = 'post-sticky-toggle-' + instanceId;
import PostStickyCheck from '../../post-sticky/check';
import PostStickyForm from '../../post-sticky';

export function PostSticky() {
return (
<PanelRow>
<label htmlFor={ stickyToggleId }>{ __( 'Stick to the Front Page' ) }</label>
<FormToggle
checked={ postSticky }
onChange={ () => onUpdateSticky( ! postSticky ) }
showHint={ false }
id={ stickyToggleId }
/>
</PanelRow>
<PostStickyCheck>
<PanelRow>
<PostStickyForm />
</PanelRow>
</PostStickyCheck>
);
}

const applyConnect = connect(
( state ) => {
return {
postType: getCurrentPostType( state ),
postSticky: getEditedPostAttribute( state, 'sticky' ),
};
},
( dispatch ) => {
return {
onUpdateSticky( postSticky ) {
dispatch( editPost( { sticky: postSticky } ) );
},
};
},
);

const applyWithAPIData = withAPIData( () => {
return {
user: '/wp/v2/users/me?context=edit',
};
} );

export default flowRight( [
applyConnect,
applyWithAPIData,
withInstanceId,
] )( PostSticky );
export default PostSticky;
43 changes: 0 additions & 43 deletions editor/sidebar/post-sticky/test/index.js

This file was deleted.