Skip to content

Commit

Permalink
Merge pull request #8402 from Automattic/add/redux-post-formats
Browse files Browse the repository at this point in the history
State: Migrate lib/post-formats to Redux state
  • Loading branch information
tyxla authored Oct 7, 2016
2 parents a6f9789 + df79fd8 commit e308008
Show file tree
Hide file tree
Showing 13 changed files with 691 additions and 3 deletions.
38 changes: 38 additions & 0 deletions client/components/data/query-post-formats/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
Query Post Formats
================

`<QueryPostFormats />` is a React component used in managing network requests for post formats.

## Usage

Render the component, passing `siteId`. It does not accept any children, nor does it render any elements to the page. You can use it adjacent to other sibling components which make use of the fetched data made available through the global application state.

```jsx
import React from 'react';
import QueryPostFormats from 'components/data/query-post-formats';
import MyPostFormatsListItem from './list-item';

export default function MyPostFormatsList( { postFormats } ) {
return (
<div>
<QueryPostFormats siteId={ 12345678 } />
{ postFormats.map( ( label, id ) => {
return (
<MyPostFormatsListItem postFormatId={ id } />
);
} }
</div>
);
}
```
## Props
### `siteId`
<table>
<tr><th>Type</th><td>Number</td></tr>
<tr><th>Required</th><td>Yes</td></tr>
</table>
The site ID for which post formats should be requested.
50 changes: 50 additions & 0 deletions client/components/data/query-post-formats/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* External dependencies
*/
import { Component, PropTypes } from 'react';
import { connect } from 'react-redux';

/**
* Internal dependencies
*/
import { isRequestingPostFormats } from 'state/post-types/selectors';
import { requestPostFormats } from 'state/post-types/actions';

class QueryPostFormats extends Component {
static propTypes = {
siteId: PropTypes.number.isRequired,
requestingPostFormats: PropTypes.bool,
requestPostFormats: PropTypes.func
};

componentWillMount() {
this.request( this.props );
}

componentWillReceiveProps( nextProps ) {
if ( this.props.siteId !== nextProps.siteId ) {
this.request( nextProps );
}
}

request( props ) {
if ( props.requestingPostFormats ) {
return;
}

props.requestPostFormats( props.siteId );
}

render() {
return null;
}
}

export default connect(
( state, ownProps ) => {
return {
requestingPostFormats: isRequestingPostFormats( state, ownProps.siteId )
};
},
{ requestPostFormats }
)( QueryPostFormats );
2 changes: 1 addition & 1 deletion client/lib/wpcom-undocumented/lib/site.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ UndocumentedSite.prototype.domains = function( callback ) {
};

UndocumentedSite.prototype.postFormatsList = function( callback ) {
this.wpcom.withLocale().req.get( '/sites/' + this._id + '/post-formats', {}, callback );
return this.wpcom.withLocale().req.get( '/sites/' + this._id + '/post-formats', {}, callback );
};

UndocumentedSite.prototype.postAutosave = function( postId, attributes, callback ) {
Expand Down
4 changes: 4 additions & 0 deletions client/state/action-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,10 @@ export const POST_DELETE_FAILURE = 'POST_DELETE_FAILURE';
export const POST_DELETE_SUCCESS = 'POST_DELETE_SUCCESS';
export const POST_EDIT = 'POST_EDIT';
export const POST_EDITS_RESET = 'POST_EDITS_RESET';
export const POST_FORMATS_RECEIVE = 'POST_FORMATS_RECEIVE';
export const POST_FORMATS_REQUEST = 'POST_FORMATS_REQUEST';
export const POST_FORMATS_REQUEST_FAILURE = 'POST_FORMATS_REQUEST_FAILURE';
export const POST_FORMATS_REQUEST_SUCCESS = 'POST_FORMATS_REQUEST_SUCCESS';
export const POST_REQUEST = 'POST_REQUEST';
export const POST_REQUEST_FAILURE = 'POST_REQUEST_FAILURE';
export const POST_REQUEST_SUCCESS = 'POST_REQUEST_SUCCESS';
Expand Down
6 changes: 4 additions & 2 deletions client/state/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import notices from './notices/reducer';
import pageTemplates from './page-templates/reducer';
import plans from './plans/reducer';
import plugins from './plugins/reducer';
import postFormats from './post-formats/reducer';
import posts from './posts/reducer';
import postTypes from './post-types/reducer';
import preferences from './preferences/reducer';
Expand Down Expand Up @@ -69,10 +70,11 @@ export const reducer = combineReducers( {
pageTemplates,
plugins,
plans,
preferences,
preview,
postFormats,
posts,
postTypes,
preferences,
preview,
productsList,
purchases,
pushNotifications,
Expand Down
62 changes: 62 additions & 0 deletions client/state/post-formats/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
Post Formats
===============

A module for managing post formats.

## Actions

Used in combination with the Redux store instance `dispatch` function, actions can be used in manipulating the current global state.

### `requestPostFormats( siteId: number )`

Get a list of supported post formats for a given site.

```js
import { requestPostFormats } from 'state/post-formats/actions';

requestPostFormats( 12345678 );
```

## Reducer

Data from the aforementioned actions is added to the global state tree, under `postFormats`, with the following structure:

```js
state.postFormats = {
requesting: {
12345678: false,
87654321: true
},
items: {
12345678: {
image: 'Image',
video: 'Video'
},
87654321: {
status: 'Status'
}
}
}
```

## Selectors are intended to assist in extracting data from the global state tree for consumption by other modules.

#### `isRequestingPostFormats`

Returns true if post formats are currently fetching for the given site ID.

```js
import { isRequestingPostFormats } from 'state/post-formats/selectors';

const isRequesting = isRequestingPostFormats( state, 12345678 );
```

#### `getPostFormats`

Returns an array of all supported site formats for the given site ID.

```js
import { getPostFormats } from 'state/post-formats/selectors';

const postFormats = getPostFormats( state, 12345678 );
```
45 changes: 45 additions & 0 deletions client/state/post-formats/actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Internal dependencies
*/
import wpcom from 'lib/wp';
import {
POST_FORMATS_RECEIVE,
POST_FORMATS_REQUEST,
POST_FORMATS_REQUEST_SUCCESS,
POST_FORMATS_REQUEST_FAILURE
} from 'state/action-types';

/**
* Returns an action thunk which, when invoked, triggers a network request to
* retrieve post formats for a site.
*
* @param {Number} siteId Site ID
* @return {Function} Action thunk
*/
export function requestPostFormats( siteId ) {
return ( dispatch ) => {
dispatch( {
type: POST_FORMATS_REQUEST,
siteId
} );

return wpcom.undocumented().site( siteId ).postFormatsList().then( ( { formats } ) => {
dispatch( {
type: POST_FORMATS_RECEIVE,
siteId,
formats
} );

dispatch( {
type: POST_FORMATS_REQUEST_SUCCESS,
siteId
} );
} ).catch( ( error ) => {
dispatch( {
type: POST_FORMATS_REQUEST_FAILURE,
siteId,
error
} );
} );
};
}
49 changes: 49 additions & 0 deletions client/state/post-formats/reducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* External dependencies
*/
import { combineReducers } from 'redux';

/**
* Internal dependencies
*/
import { postFormatsItemsSchema } from './schema';
import { createReducer } from 'state/utils';
import {
POST_FORMATS_RECEIVE,
POST_FORMATS_REQUEST,
POST_FORMATS_REQUEST_SUCCESS,
POST_FORMATS_REQUEST_FAILURE
} from 'state/action-types';

/**
* Returns the updated requests state after an action has been dispatched. The
* state maps site ID keys to whether a request for post formats is in progress.
*
* @param {Object} state Current state
* @param {Object} action Action payload
* @return {Object} Updated state
*/
export const requesting = createReducer( {}, {
[ POST_FORMATS_REQUEST ]: ( state, { siteId } ) => ( { ...state, [ siteId ]: true } ),
[ POST_FORMATS_REQUEST_SUCCESS ]: ( state, { siteId } ) => ( { ...state, [ siteId ]: false } ),
[ POST_FORMATS_REQUEST_FAILURE ]: ( state, { siteId } ) => ( { ...state, [ siteId ]: false } )
} );

/**
* Returns the updated items state after an action has been dispatched. The
* state maps site ID keys to an object that contains the site supported post formats.
*
* @param {Object} state Current state
* @param {Object} action Action payload
* @return {Object} Updated state
*/
export const items = createReducer( {}, {
[ POST_FORMATS_RECEIVE ]: ( state, { siteId, formats } ) => {
return { ...state, [ siteId ]: formats };
}
}, postFormatsItemsSchema );

export default combineReducers( {
requesting,
items
} );
19 changes: 19 additions & 0 deletions client/state/post-formats/schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
export const postFormatsItemsSchema = {
type: 'object',
additionalProperties: false,
patternProperties: {
// Site ID
'^\\d+$': {
type: 'object',
description: 'List of supported post formats.',
additionalProperties: false,
patternProperties: {
// ID of the post format
'^[0-9a-z\-_]+$': {
type: 'string',
description: 'Label of the post format',
}
}
}
}
};
22 changes: 22 additions & 0 deletions client/state/post-formats/selectors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* Returns true if currently requesting post formats for the specified site ID, or
* false otherwise.
*
* @param {Object} state Global state tree
* @param {Number} siteId Site ID
* @return {Boolean} Whether post formats are being requested
*/
export function isRequestingPostFormats( state, siteId ) {
return !! state.postFormats.requesting[ siteId ];
}

/**
* Returns the supported post formats for a site.
*
* @param {Object} state Global state tree
* @param {Number} siteId Site ID
* @return {?Object} Site post formats
*/
export function getPostFormats( state, siteId ) {
return state.postFormats.items[ siteId ] || null;
}
Loading

0 comments on commit e308008

Please sign in to comment.