Skip to content

Commit

Permalink
Framework: Add notices (#1437)
Browse files Browse the repository at this point in the history
  • Loading branch information
youknowriad authored Jun 28, 2017
1 parent 9500701 commit 81ac2ab
Show file tree
Hide file tree
Showing 13 changed files with 240 additions and 11 deletions.
2 changes: 2 additions & 0 deletions components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ export { default as Dashicon } from './dashicon';
export { default as FormToggle } from './form-toggle';
export { default as FormTokenField } from './form-token-field';
export { default as IconButton } from './icon-button';
export { default as Notice } from './notice';
export { default as NoticeList } from './notice/list';
export { default as Panel } from './panel';
export { default as PanelHeader } from './panel/header';
export { default as PanelBody } from './panel/body';
Expand Down
28 changes: 28 additions & 0 deletions components/notice/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* External dependencies
*/
import { isString, noop } from 'lodash';

/**
* WordPress dependencies
*/
import { __ } from 'i18n';

/**
* Internal Dependencies
*/
import './style.scss';

function Notice( { status, content, onRemove = noop } ) {
const className = `notice notice-alt is-dismissible notice-${ status }`;
return (
<div className={ className }>
{ isString( content ) ? <p>{ content }</p> : content }
<button className="notice-dismiss" type="button" onClick={ onRemove }>
<span className="screen-reader-text">{ __( 'Dismiss this notice' ) }</span>
</button>
</div>
);
}

export default Notice;
23 changes: 23 additions & 0 deletions components/notice/list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* External depednencies
*/
import { noop } from 'lodash';

/**
* Internal dependencies
*/
import Notice from './';

function NoticeList( { notices, onRemove = noop } ) {
const removeNotice = ( id ) => () => onRemove( id );

return (
<div className="components-notice-list">
{ notices.reverse().map( ( notice ) => (
<Notice { ...notice } key={ notice.id } onRemove={ removeNotice( notice.id ) } />
) ) }
</div>
);
}

export default NoticeList;
7 changes: 7 additions & 0 deletions components/notice/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.components-notice-list {
position: fixed;
top: 40px;
right: 0;
width: 300px;
z-index: z-index( ".components-notice-list" );
}
44 changes: 44 additions & 0 deletions editor/actions.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/**
* External Dependencies
*/
import uuid from 'uuid/v4';
import { partial } from 'lodash';

export function focusBlock( uid, config ) {
return {
type: 'UPDATE_FOCUS',
Expand Down Expand Up @@ -111,3 +117,41 @@ export function stopTypingInBlock( uid ) {
uid,
};
}

/**
* Returns an action object used to create a notice
*
* @param {String} status The notice status
* @param {WPElement} content The notice content
* @param {String} id The notice id
*
* @return {Object} Action object
*/
export function createNotice( status, content, id = uuid() ) {
return {
type: 'CREATE_NOTICE',
notice: {
id,
status,
content,
},
};
}

/**
* Returns an action object used to remove a notice
*
* @param {String} id The notice id
*
* @return {Object} Action object
*/
export function removeNotice( id ) {
return {
type: 'REMOVE_NOTICE',
noticeId: id,
};
}

export const successNotice = partial( createNotice, 'success' );
export const errorNotice = partial( createNotice, 'error' );
export const warningNotice = partial( createNotice, 'warning' );
1 change: 1 addition & 0 deletions editor/assets/stylesheets/_z-index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ $z-layers: (
'.editor-post-visibility__dialog': 30,
'.editor-post-schedule__dialog': 30,
'.editor-block-mover': 30,
'.components-notice-list': 100000,
'.components-popover': 100000,
);

Expand Down
8 changes: 4 additions & 4 deletions editor/effects.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ export default {
const Model = wp.api.getPostTypeModel( getCurrentPostType( state ) );
new Model( toSend ).save().done( ( newPost ) => {
dispatch( {
type: 'REQUEST_POST_UPDATE_SUCCESS',
type: 'RESET_POST',
post: newPost,
isNew,
optimist: { type: COMMIT, id: transactionId },
} );
dispatch( {
type: 'RESET_POST',
type: 'REQUEST_POST_UPDATE_SUCCESS',
post: newPost,
isNew,
optimist: { type: COMMIT, id: transactionId },
} );
} ).fail( ( err ) => {
dispatch( {
Expand Down
28 changes: 22 additions & 6 deletions editor/layout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,34 @@
import { connect } from 'react-redux';
import classnames from 'classnames';

/**
* WordPress Dependencie
*/
import { NoticeList } from 'components';

/**
* Internal dependencies
*/
import './style.scss';
import Header from '../header';
import Sidebar from '../sidebar';
import TextEditor from '../modes/text-editor';
import VisualEditor from '../modes/visual-editor';
import { getEditorMode, isEditorSidebarOpened } from '../selectors';
import { removeNotice } from '../actions';
import {
getEditorMode,
isEditorSidebarOpened,
getNotices,
} from '../selectors';

function Layout( { mode, isSidebarOpened } ) {
function Layout( { mode, isSidebarOpened, notices, ...props } ) {
const className = classnames( 'editor-layout', {
'is-sidebar-opened': isSidebarOpened,
} );

return (
<div className={ className }>
<NoticeList onRemove={ props.removeNotice } notices={ notices } />
<Header />
<div className="editor-layout__content">
{ mode === 'text' && <TextEditor /> }
Expand All @@ -30,7 +42,11 @@ function Layout( { mode, isSidebarOpened } ) {
);
}

export default connect( ( state ) => ( {
mode: getEditorMode( state ),
isSidebarOpened: isEditorSidebarOpened( state ),
} ) )( Layout );
export default connect(
( state ) => ( {
mode: getEditorMode( state ),
isSidebarOpened: isEditorSidebarOpened( state ),
notices: getNotices( state ),
} ),
{ removeNotice }
)( Layout );
10 changes: 10 additions & 0 deletions editor/layout/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.editor-layout {
position: relative;
}

.editor-layout .components-notice-list {
position: absolute;
top: 10px;
left: 0;
right: auto;
}
12 changes: 11 additions & 1 deletion editor/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* External dependencies
*/
import moment from 'moment';
import { first, last, get } from 'lodash';
import { first, last, get, values } from 'lodash';
import createSelector from 'rememo';

/**
Expand Down Expand Up @@ -648,3 +648,13 @@ export function getSuggestedPostFormat( state ) {

return null;
}

/**
* Returns the user notices array
*
* @param {Object} state Global application state
* @return {Array} List of notices
*/
export function getNotices( state ) {
return values( state.notices );
}
19 changes: 19 additions & 0 deletions editor/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,24 @@ export function saving( state = {}, action ) {
return state;
}

export function notices( state = {}, action ) {
switch ( action.type ) {
case 'CREATE_NOTICE':
return {
...state,
[ action.notice.id ]: action.notice,
};
case 'REMOVE_NOTICE':
if ( ! state.hasOwnProperty( action.noticeId ) ) {
return state;
}

return omit( state, action.noticeId );
}

return state;
}

/**
* Creates a new instance of a Redux store.
*
Expand All @@ -479,6 +497,7 @@ export function createReduxStore() {
mode,
isSidebarOpened,
saving,
notices,
} ) );

const enhancers = [ applyMiddleware( refx( effects ) ) ];
Expand Down
17 changes: 17 additions & 0 deletions editor/test/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import {
didPostSaveRequestSucceed,
didPostSaveRequestFail,
getSuggestedPostFormat,
getNotices,
} from '../selectors';

describe( 'selectors', () => {
Expand Down Expand Up @@ -1190,4 +1191,20 @@ describe( 'selectors', () => {
expect( getSuggestedPostFormat( state ) ).to.equal( 'Quote' );
} );
} );

describe( 'getNotices', () => {
it( 'should return the notices array', () => {
const state = {
notices: {
b: { id: 'b', content: 'Post saved' },
a: { id: 'a', content: 'Error saving' },
},
};

expect( getNotices( state ) ).to.eql( [
state.notices.b,
state.notices.a,
] );
} );
} );
} );
52 changes: 52 additions & 0 deletions editor/test/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
mode,
isSidebarOpened,
saving,
notices,
showInsertionPoint,
createReduxStore,
} from '../state';
Expand Down Expand Up @@ -978,6 +979,56 @@ describe( 'state', () => {
} );
} );

describe( 'notices()', () => {
it( 'should create a notice', () => {
const originalState = {
b: {
id: 'b',
content: 'Error saving',
status: 'error',
},
};
const state = notices( originalState, {
type: 'CREATE_NOTICE',
notice: {
id: 'a',
content: 'Post saved',
status: 'success',
},
} );
expect( state ).to.eql( {
b: originalState.b,
a: {
id: 'a',
content: 'Post saved',
status: 'success',
},
} );
} );

it( 'should remove a notice', () => {
const originalState = {
a: {
id: 'a',
content: 'Post saved',
status: 'success',
},
b: {
id: 'b',
content: 'Error saving',
status: 'error',
},
};
const state = notices( originalState, {
type: 'REMOVE_NOTICE',
noticeId: 'a',
} );
expect( state ).to.eql( {
b: originalState.b,
} );
} );
} );

describe( 'createReduxStore()', () => {
it( 'should return a redux store', () => {
const store = createReduxStore();
Expand All @@ -1001,6 +1052,7 @@ describe( 'state', () => {
'isSidebarOpened',
'saving',
'showInsertionPoint',
'notices',
] );
} );
} );
Expand Down

0 comments on commit 81ac2ab

Please sign in to comment.