Skip to content

Commit

Permalink
Themes: Use new v1.2 theme-details endpoint for Theme Sheets (#6148)
Browse files Browse the repository at this point in the history
* Themes: Use v1.2 theme details API

Corresponding endpoint change: r137641-wpcom

Use the new elasticsearch-powered theme details endpoint. Allows per-site queries. Advantages over v1.1 endpoint:
* Correctly formatted price
* No price for premium themes when site has unlimited-themes plan
* `purchased` boolean field for individually purchased premium themes

----

* Theme Sheet: Use feature slug as key

* Themes: Fix tests by updating to REST API v1.2 field layout

Also, use `equal()` for string comparison instead of deep-comparing `eql()`.


* Themes: Use presence of price prop to determine action

* Themes: Use !isPremium() to gate downloads
  • Loading branch information
seear authored Jun 23, 2016
1 parent 3f31474 commit 1db35ea
Show file tree
Hide file tree
Showing 8 changed files with 38 additions and 43 deletions.
12 changes: 9 additions & 3 deletions client/components/data/theme-details/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import omit from 'lodash/omit';
*/
import { fetchThemeDetails } from 'state/themes/actions';
import { getThemeDetails } from 'state/themes/theme-details/selectors';
import { getSelectedSiteId } from 'state/ui/selectors';

/**
* Fetches details for a theme specified by its ID
Expand All @@ -29,6 +30,7 @@ const ThemeDetailsData = React.createClass( {
description: React.PropTypes.string,
descriptionLong: React.PropTypes.string,
supportDocumentation: React.PropTypes.string,
selectedSiteId: React.PropTypes.number,
fetchThemeDetails: React.PropTypes.func.isRequired
},

Expand All @@ -43,8 +45,9 @@ const ThemeDetailsData = React.createClass( {
},

refresh( props ) {
if ( ! this.props.name && props.id ) {
this.props.fetchThemeDetails( props.id );
// todo (seear): Don't fetch if site matches existing data
if ( props.id ) {
this.props.fetchThemeDetails( props.id, props.selectedSiteId );
}
},

Expand All @@ -54,6 +57,9 @@ const ThemeDetailsData = React.createClass( {
} );

export default connect(
( state, props ) => getThemeDetails( state, props.id ),
( state, props ) => Object.assign( {},
getThemeDetails( state, props.id ),
{ selectedSiteId: getSelectedSiteId( state ) }
),
{ fetchThemeDetails }
)( ThemeDetailsData );
10 changes: 5 additions & 5 deletions client/lib/wpcom-undocumented/lib/undocumented.js
Original file line number Diff line number Diff line change
Expand Up @@ -1404,12 +1404,12 @@ Undocumented.prototype.themes = function( site, query, fn ) {
}, fn );
};

Undocumented.prototype.themeDetails = function( themeId, fn ) {
const path = `/themes/${ themeId }`;
debug( '/themes/:theme_id' );
Undocumented.prototype.themeDetails = function( themeId, site, fn ) {
const sitePath = site ? `/sites/${ site }` : '';
const path = `${ sitePath }/themes/${ themeId }`;
debug( path );
return this.wpcom.req.get( path, {
apiVersion: '1.1',
extended: 'true',
apiVersion: '1.2',
}, fn );
};

Expand Down
13 changes: 7 additions & 6 deletions client/my-sites/theme/main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ const ThemeSheet = React.createClass( {
download: React.PropTypes.string,
taxonomies: React.PropTypes.object,
stylesheet: React.PropTypes.string,
active: React.PropTypes.bool,
purchased: React.PropTypes.bool,
isLoggedIn: React.PropTypes.bool,
// Connected props
selectedSite: React.PropTypes.object,
Expand Down Expand Up @@ -90,8 +92,7 @@ const ThemeSheet = React.createClass( {
this.props.signup( this.props );
} else if ( this.isActive() ) {
this.props.customize( this.props, this.props.selectedSite );
} else if ( isPremium( this.props ) ) {
// TODO: check theme is not already purchased
} else if ( this.props.price ) {
this.selectSiteAndDispatch( 'purchase' );
} else {
this.selectSiteAndDispatch( 'activate' );
Expand Down Expand Up @@ -243,9 +244,9 @@ const ThemeSheet = React.createClass( {
},

renderFeaturesCard() {
const themeFeatures = this.props.taxonomies && this.props.taxonomies.features instanceof Array
? this.props.taxonomies.features.map( function( item, i ) {
return ( <li key={ 'theme-features-item-' + i++ }><span>{ item.name }</span></li> );
const themeFeatures = this.props.taxonomies && this.props.taxonomies.theme_feature instanceof Array
? this.props.taxonomies.theme_feature.map( function( item ) {
return ( <li key={ 'theme-features-item-' + item.slug }><span>{ item.name }</span></li> );
} ) : [];

return (
Expand All @@ -261,7 +262,7 @@ const ThemeSheet = React.createClass( {
},

renderDownload() {
if ( 'Free' !== this.props.price ) {
if ( isPremium( this.props ) ) {
return null;
}
return <ThemeDownloadCard theme={ this.props.id } href={ this.props.download } />;
Expand Down
8 changes: 5 additions & 3 deletions client/state/themes/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ export function fetchCurrentTheme( siteId ) {
};
}

export function fetchThemeDetails( id ) {
export function fetchThemeDetails( id, site ) {
return dispatch => {
wpcom.undocumented().themeDetails( id )
wpcom.undocumented().themeDetails( id, site )
.then( themeDetails => {
debug( 'Received theme details', themeDetails );
dispatch( receiveThemeDetails( themeDetails ) );
Expand All @@ -129,11 +129,13 @@ export function receiveThemeDetails( theme ) {
themeScreenshot: theme.screenshot,
themeDescription: theme.description,
themeDescriptionLong: theme.description_long,
themeSupportDocumentation: theme.extended ? theme.extended.support_documentation : undefined,
themeSupportDocumentation: theme.support_documentation || undefined,
themeDownload: theme.download_uri || undefined,
themeTaxonomies: theme.taxonomies,
themeStylesheet: theme.stylesheet,
themeDemoUri: theme.demo_uri,
themeActive: theme.active,
themePurchased: theme.purchased,
};
}

Expand Down
2 changes: 2 additions & 0 deletions client/state/themes/theme-details/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ export default ( state = Map(), action ) => {
taxonomies: action.themeTaxonomies,
stylesheet: action.themeStylesheet,
demo_uri: action.themeDemoUri,
active: action.themeActive,
purchased: action.themePurchased,
} ) );
case THEME_DETAILS_RECEIVE_FAILURE:
return state.set( action.themeId, Map( { error: action.error } ) );
Expand Down
11 changes: 0 additions & 11 deletions client/state/themes/theme-details/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,5 @@
export function getThemeDetails( state, id ) {
let theme = state.themes.themeDetails.get( id );
theme = theme ? theme.toJS() : {};
if ( theme.price ) {
theme.price = formatPrice( theme.price );
}
return theme;
}

// Convert price to format used by v1.2 themes API to fit with existing components.
// TODO (seear): remove when v1.2 theme details endpoint is added
function formatPrice( price ) {
// premium theme price.display example: "<abbr title="United States Dollars">$</abbr>65"
const priceMatcher = /^<[^>]*>([^<]*)<[^>]*>(\d*)$/;
return price.display.replace( priceMatcher, '$1$2' );
}
8 changes: 6 additions & 2 deletions client/state/themes/theme-details/test/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ describe( 'reducer', () => {
count: 0,
filter: 'raw'
} ]
}
},
themeActive: false,
themePurchased: false
} );

expect( state.get( 'mood' ).toJS() ).to.eql( {
Expand All @@ -77,7 +79,9 @@ describe( 'reducer', () => {
count: 0,
filter: 'raw'
} ]
}
},
active: false,
purchased: false
} );
} );

Expand Down
17 changes: 4 additions & 13 deletions client/state/themes/theme-details/test/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,18 @@ import { getThemeDetails } from '../selectors';

describe( 'selectors', () => {
describe( '#getThemeDetails()', () => {

const themes = {
themes: {
themeDetails: Map( {
mood: Map( {
name: 'Mood',
author: 'Automattic',
price: {
value: 65,
currency: 'USD',
display: '<abbr title=\"United States Dollars\">$</abbr>65'
},
price: '$65'
} ),
twentysixteen: Map( {
name: 'Twenty Sixteen',
author: 'Automattic',
price: {
value: 0,
currency: 'USD',
display: 'Free'
},
price: 'free',
} ),
} )
}
Expand All @@ -44,10 +35,10 @@ describe( 'selectors', () => {

it( 'should format the price as plaintext', () => {
const mood = getThemeDetails( themes, 'mood' );
expect( mood.price ).to.eql( '$65' );
expect( mood.price ).to.equal( '$65' );

const twentysixteen = getThemeDetails( themes, 'twentysixteen' );
expect( twentysixteen.price ).to.eql( 'Free' );
expect( twentysixteen.price ).to.equal( 'free' );
} );
} );
} );

0 comments on commit 1db35ea

Please sign in to comment.