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

Themes: Add current-theme query component #5361

Merged
merged 7 commits into from
May 13, 2016
Merged
Show file tree
Hide file tree
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
8 changes: 0 additions & 8 deletions client/components/data/current-theme/README.md

This file was deleted.

65 changes: 0 additions & 65 deletions client/components/data/current-theme/index.js

This file was deleted.

25 changes: 25 additions & 0 deletions client/components/data/query-current-theme/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Query Current Theme
===================

Use this component anywhere where you need the currently active theme for a site. It fetches data when necessary, and renders nothing.

## Usage

```jsx
<div>
<QueryCurrentTheme siteID={ site.ID }/>
</div>
```

The current theme will be available from the global app state via the `getCurrentTheme()` [selector](/client/state/themes/current-theme/selectors.js).

## 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 the current theme should be queried.
53 changes: 53 additions & 0 deletions client/components/data/query-current-theme/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/** @ssr-ready **/

/**
* External dependencies
*/
import { Component, PropTypes } from 'react';
import { connect } from 'react-redux';

/**
* Internal dependencies
*/
import { fetchCurrentTheme } from 'state/themes/actions';
import { isRequestingCurrentTheme } from 'state/themes/current-theme/selectors';

class QueryCurrentTheme extends Component {

componentDidMount() {
const { requestingCurrentTheme, siteId } = this.props;
this.refresh( requestingCurrentTheme, siteId );
}

componentWillReceiveProps( nextProps ) {
if ( nextProps.siteId === this.props.siteId ) {
return;
}
const { requestingCurrentTheme, siteId } = nextProps;
this.refresh( requestingCurrentTheme, siteId );
}

refresh( requestingCurrentTheme, siteId ) {
if ( ! requestingCurrentTheme ) {
this.props.fetchCurrentTheme( siteId );
}
}

render() {
return null;
}
}

QueryCurrentTheme.propTypes = {
siteId: PropTypes.number.isRequired,
// connected props
requestingCurrentTheme: PropTypes.bool,
fetchCurrentTheme: PropTypes.func,
};

export default connect(
( state, props ) => (
{ requestingCurrentTheme: isRequestingCurrentTheme( state, props.site && props.site.ID ) }
),
{ fetchCurrentTheme }
)( QueryCurrentTheme );
12 changes: 10 additions & 2 deletions client/my-sites/themes/current-theme/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/
import React from 'react';
import classNames from 'classnames';
import { connect } from 'react-redux';

/**
* Internal dependencies
Expand All @@ -16,6 +17,8 @@ import {
isPremium,
trackClick
} from '../helpers';
import { getCurrentTheme } from 'state/themes/current-theme/selectors';
import QueryCurrentTheme from 'components/data/query-current-theme';

/**
* Show current active theme for a site, with
Expand All @@ -37,11 +40,12 @@ const CurrentTheme = React.createClass( {
render() {
const { currentTheme, site } = this.props,
placeholderText = <span className="current-theme__placeholder">loading...</span>,
text = currentTheme ? currentTheme.name : placeholderText,
text = ( currentTheme && currentTheme.name ) ? currentTheme.name : placeholderText,
displaySupportButton = isPremium( currentTheme ) && ! site.jetpack;

return (
<Card className="current-theme">
{ site && <QueryCurrentTheme siteId={ site.ID }/> }
<div className="current-theme__info">
<span className="current-theme__label">
{ this.translate( 'Current Theme' ) }
Expand Down Expand Up @@ -75,4 +79,8 @@ const CurrentTheme = React.createClass( {
}
} );

export default CurrentTheme;
export default connect(
( state, props ) => (
{ currentTheme: getCurrentTheme( state, props.site && props.site.ID ) }
)
)( CurrentTheme );
9 changes: 3 additions & 6 deletions client/my-sites/themes/single-site.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import merge from 'lodash/merge';
* Internal dependencies
*/
import Main from 'components/main';
import CurrentThemeData from 'components/data/current-theme';
import ActivatingTheme from 'components/data/activating-theme';
import { customize, purchase, activate, clearActivated } from 'state/themes/actions';
import ThemePreview from './theme-preview';
Expand Down Expand Up @@ -154,11 +153,9 @@ const ThemesSingleSite = React.createClass( {
source={ 'list' }
clearActivated={ bindActionCreators( clearActivated, this.props.dispatch ) } />
</ActivatingTheme>
<CurrentThemeData site={ site }>
<CurrentTheme
site={ site }
canCustomize={ site && site.isCustomizable() } />
</CurrentThemeData>
<CurrentTheme
site={ site }
canCustomize={ site && site.isCustomizable() } />
<UpgradeNudge
title={ this.translate( 'Get Custom Design with Premium' ) }
message={ this.translate( 'Customize your theme using premium fonts, color palettes, and the CSS editor.' ) }
Expand Down
2 changes: 2 additions & 0 deletions client/state/action-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ export const THEME_CUSTOMIZE = 'THEME_CUSTOMIZE';
export const THEME_DETAILS_RECEIVE = 'THEME_DETAILS_RECEIVE';
export const THEME_PURCHASE = 'THEME_PURCHASE';
export const THEME_RECEIVE_CURRENT = 'THEMES_RECEIVE_CURRENT';
export const THEME_REQUEST_CURRENT = 'THEME_REQUEST_CURRENT';
export const THEME_REQUEST_CURRENT_FAILURE = 'THEME_REQUEST_CURRENT_FAILURE';
export const THEME_SIGNUP_WITH = 'THEME_SIGNUP_WITH';
export const THEMES_INCREMENT_PAGE = 'THEMES_INCREMENT_PAGE';
export const THEMES_QUERY = 'THEMES_QUERY';
Expand Down
21 changes: 17 additions & 4 deletions client/state/themes/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import {
THEME_DETAILS_RECEIVE,
THEME_PURCHASE,
THEME_RECEIVE_CURRENT,
THEME_REQUEST_CURRENT,
THEME_REQUEST_CURRENT_FAILURE,
THEME_SIGNUP_WITH,
THEMES_INCREMENT_PAGE,
THEMES_QUERY,
Expand Down Expand Up @@ -75,19 +77,30 @@ export function incrementThemesPage( site ) {
};
}

export function fetchCurrentTheme( site ) {
export function fetchCurrentTheme( siteId ) {
return dispatch => {
wpcom.undocumented().activeTheme( site.ID )
dispatch( {
type: THEME_REQUEST_CURRENT,
siteId,
} );

wpcom.undocumented().activeTheme( siteId )
.then( theme => {
debug( 'Received current theme', theme );
dispatch( {
type: THEME_RECEIVE_CURRENT,
site: site,
siteId,
themeId: theme.id,
themeName: theme.name,
themeCost: theme.cost
} );
} ); // TODO: add .catch() error handler
} ).catch( error => {
dispatch( {
type: THEME_REQUEST_CURRENT_FAILURE,
siteId,
error,
} );
} );
};
}

Expand Down
18 changes: 13 additions & 5 deletions client/state/themes/current-theme/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,31 @@ import {
THEME_ACTIVATE,
THEME_ACTIVATED,
THEME_CLEAR_ACTIVATED,
THEME_RECEIVE_CURRENT
THEME_RECEIVE_CURRENT,
THEME_REQUEST_CURRENT,
THEME_REQUEST_CURRENT_FAILURE,
} from 'state/action-types';

export const initialState = fromJS( {
isActivating: false,
hasActivated: false,
currentThemes: {}
currentThemes: {},
requesting: {},
} );

export default ( state = initialState, action ) => {
switch ( action.type ) {
case THEME_RECEIVE_CURRENT:
return state.setIn( [ 'currentThemes', action.site.ID ], {
return state.setIn( [ 'currentThemes', action.siteId ], {
name: action.themeName,
id: action.themeId,
cost: action.themeCost
} );
cost: action.themeCost,
} )
.setIn( [ 'requesting', action.siteId ], false );
case THEME_REQUEST_CURRENT:
return state.setIn( [ 'requesting', action.siteId ], true );
case THEME_REQUEST_CURRENT_FAILURE:
return state.setIn( [ 'requesting', action.siteId ], false );
case THEME_ACTIVATE:
return state.set( 'isActivating', true );
case THEME_ACTIVATED:
Expand Down
4 changes: 4 additions & 0 deletions client/state/themes/current-theme/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ export function isActivating( state ) {
export function hasActivated( state ) {
return state.themes.currentTheme.get( 'hasActivated' );
}

export function isRequestingCurrentTheme( state, siteId ) {
return !! state.themes.currentTheme.get( 'requesting' ).get( siteId );
}
2 changes: 1 addition & 1 deletion client/state/themes/current-theme/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ describe( 'current-theme', () => {
type: THEME_RECEIVE_CURRENT,
themeId: 'twentyfifteen',
themeName: 'Twenty Fifteen',
site: SITE
siteId: SITE.ID,
};

let store;
Expand Down
28 changes: 28 additions & 0 deletions client/state/themes/current-theme/test/selectors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* External dependencies
*/
import { expect } from 'chai';
import { Map } from 'immutable';

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

describe( 'selectors', () => {
describe( '#isRequestingCurrentTheme()', () => {
it( 'should return false if request not in progress', () => {
const requesting = isRequestingCurrentTheme( {
themes: {
currentTheme: Map( {
requesting: Map( {
2916284: false,
} )
} )
}
}, 2916284 );

expect( requesting ).to.eql( false );
} );
} );
} );