Add profile onboarding mutators and selectors to wc-api (https://github.com/woocommerce/woocommerce-admin/pull/2310)

* Add onboarding profile selectors and mutators to wc-api

* Show onboarding profiler depending on API results

* Add initial state hydration for onboarding profile

* Add onboarding namespace constant
This commit is contained in:
Joshua T Flowers 2019-05-28 22:45:52 +08:00 committed by GitHub
parent 4c8487abad
commit 3b945b4bba
10 changed files with 202 additions and 16 deletions

View File

@ -4,6 +4,7 @@
*/
import { __ } from '@wordpress/i18n';
import { Component, Fragment } from '@wordpress/element';
import { compose } from '@wordpress/compose';
/**
* Internal dependencies
@ -17,13 +18,13 @@ import { ReportFilters } from '@woocommerce/components';
import StorePerformance from './store-performance';
import TaskList from './task-list';
import ProfileWizard from './profile-wizard';
import withSelect from 'wc-api/with-select';
export default class Dashboard extends Component {
class Dashboard extends Component {
renderDashboardOutput() {
const { query, path } = this.props;
const { path, profileItems, query } = this.props;
// @todo This should check a selector client side, with wcSettings.showProfiler as initial state.
if ( window.wcAdminFeatures.onboarding && wcSettings.showProfiler ) {
if ( window.wcAdminFeatures.onboarding && ! profileItems.skipped && ! profileItems.completed ) {
return <ProfileWizard query={ query } />;
}
@ -58,3 +59,12 @@ export default class Dashboard extends Component {
);
}
}
export default compose(
withSelect( select => {
const { getProfileItems } = select( 'wc-api' );
const profileItems = getProfileItems();
return { profileItems };
} )
)( Dashboard );

View File

@ -16,6 +16,7 @@ import { updateQueryString } from '@woocommerce/navigation';
/**
* Internal depdencies
*/
import { NAMESPACE } from 'wc-api/onboarding/constants';
import ProfileWizardHeader from './header';
import Plugins from './steps/plugins';
import Start from './steps/start';
@ -105,7 +106,7 @@ class ProfileWizard extends Component {
const { addNotice } = this.props;
return apiFetch( {
path: '/wc-admin/v1/onboarding/profile',
path: `${ NAMESPACE }/onboarding/profile`,
method: 'POST',
data: params,
} ).catch( error => {

View File

@ -14,6 +14,7 @@ import { withDispatch } from '@wordpress/data';
* Internal depdencies
*/
import { H, Stepper, Card } from '@woocommerce/components';
import { NAMESPACE } from 'wc-api/onboarding/constants';
const plugins = [ 'jetpack', 'woocommerce-services' ];
@ -107,7 +108,7 @@ class Plugins extends Component {
async doPluginAction( action, plugin ) {
try {
const pluginResponse = await apiFetch( {
path: `/wc-admin/v1/onboarding/plugins/${ action }`,
path: `${ NAMESPACE }/onboarding/plugins/${ action }`,
method: 'POST',
data: {
plugin,
@ -129,7 +130,7 @@ class Plugins extends Component {
async connectJetpack() {
try {
const connectResponse = await apiFetch( {
path: '/wc-admin/v1/onboarding/plugins/connect-jetpack',
path: `${ NAMESPACE }/onboarding/plugins/connect-jetpack`,
} );
if ( connectResponse && connectResponse.connectAction ) {
window.location = connectResponse.connectAction;

View File

@ -0,0 +1,3 @@
/** @format */
export const NAMESPACE = '/wc-admin/v1';

View File

@ -0,0 +1,13 @@
/** @format */
/**
* Internal dependencies
*/
import operations from './operations';
import selectors from './selectors';
import mutations from './mutations';
export default {
operations,
selectors,
mutations,
};

View File

@ -0,0 +1,12 @@
/** @format */
const updateProfileItems = operations => fields => {
const resourceKey = 'onboarding-profile';
operations.update( [ resourceKey ], {
[ resourceKey ]: fields,
} );
};
export default {
updateProfileItems,
};

View File

@ -0,0 +1,96 @@
/** @format */
/**
* External dependencies
*/
import apiFetch from '@wordpress/api-fetch';
/**
* Internal dependencies
*/
import { getResourceName } from '../utils';
import { NAMESPACE } from './constants';
function read( resourceNames, fetch = apiFetch ) {
return [ ...readProfileItems( resourceNames, fetch ) ];
}
function update( resourceNames, data, fetch = apiFetch ) {
return [ ...updateProfileItems( resourceNames, data, fetch ) ];
}
function readProfileItems( resourceNames, fetch ) {
const resourceName = 'onboarding-profile';
if ( resourceNames.includes( resourceName ) ) {
const url = NAMESPACE + '/onboarding/profile';
return [
fetch( { path: url } )
.then( profileItemsToResources )
.catch( error => {
return { [ resourceName ]: { error: String( error.message ) } };
} ),
];
}
return [];
}
function updateProfileItems( resourceNames, data, fetch ) {
const resourceName = 'onboarding-profile';
if ( resourceNames.includes( resourceName ) ) {
const url = NAMESPACE + '/onboarding/profile';
return [
fetch( {
path: url,
method: 'POST',
data: data[ resourceName ],
} )
.then( profileItemToResource.bind( null, data[ resourceName ] ) )
.catch( error => {
return { [ resourceName ]: { error } };
} ),
];
}
return [];
}
function profileItemsToResources( items ) {
const resourceName = 'onboarding-profile';
const itemKeys = Object.keys( items );
const resources = {};
itemKeys.forEach( key => {
const item = items[ key ];
resources[ getResourceName( resourceName, key ) ] = { data: item };
} );
return {
[ resourceName ]: {
data: itemKeys,
},
...resources,
};
}
function profileItemToResource( items ) {
const resourceName = 'onboarding-profile';
const resources = {};
Object.keys( items ).forEach( key => {
const item = items[ key ];
resources[ getResourceName( resourceName, key ) ] = { data: item };
} );
return resources;
}
export default {
read,
update,
};

View File

@ -0,0 +1,50 @@
/** @format */
/**
* External dependencies
*/
import { isNil } from 'lodash';
/**
* Internal dependencies
*/
import { DEFAULT_REQUIREMENT } from '../constants';
import { getResourceName } from '../utils';
const getProfileItems = ( getResource, requireResource ) => (
requirement = DEFAULT_REQUIREMENT
) => {
const resourceName = 'onboarding-profile';
const ids = requireResource( requirement, resourceName ).data || [];
if ( ! ids.length ) {
return wcSettings.onboardingProfile;
}
const items = {};
ids.forEach( id => {
items[ id ] = getResource( getResourceName( resourceName, id ) ).data;
} );
return items;
};
const getProfileItemsError = getResource => () => {
return getResource( 'onboarding-profile' ).error;
};
const isGetProfileItemsRequesting = getResource => () => {
const { lastReceived, lastRequested } = getResource( 'onboarding-profile' );
if ( isNil( lastRequested ) || isNil( lastReceived ) ) {
return true;
}
return lastRequested > lastReceived;
};
export default {
getProfileItems,
getProfileItemsError,
isGetProfileItemsRequesting,
};

View File

@ -6,6 +6,7 @@
import items from './items';
import imports from './imports';
import notes from './notes';
import onboarding from './onboarding';
import reportItems from './reports/items';
import reportStats from './reports/stats';
import reviews from './reviews';
@ -18,6 +19,7 @@ function createWcApiSpec() {
mutations: {
...items.mutations,
...notes.mutations,
...onboarding.mutations,
...settings.mutations,
...user.mutations,
},
@ -25,6 +27,7 @@ function createWcApiSpec() {
...imports.selectors,
...items.selectors,
...notes.selectors,
...onboarding.selectors,
...reportItems.selectors,
...reportStats.selectors,
...reviews.selectors,
@ -37,6 +40,7 @@ function createWcApiSpec() {
...imports.operations.read( resourceNames ),
...items.operations.read( resourceNames ),
...notes.operations.read( resourceNames ),
...onboarding.operations.read( resourceNames ),
...reportItems.operations.read( resourceNames ),
...reportStats.operations.read( resourceNames ),
...reviews.operations.read( resourceNames ),
@ -48,6 +52,7 @@ function createWcApiSpec() {
return [
...items.operations.update( resourceNames, data ),
...notes.operations.update( resourceNames, data ),
...onboarding.operations.update( resourceNames, data ),
...settings.operations.update( resourceNames, data ),
...user.operations.update( resourceNames, data ),
];

View File

@ -41,15 +41,10 @@ class WC_Admin_Onboarding {
* @return bool
*/
public function should_show_profiler() {
// @todo Remove this once we have a proper way to dismiss the profiler.
if ( ! defined( 'WOOCOMMERCE_ADMIN_DEV_SHOW_PROFILER' ) || false === WOOCOMMERCE_ADMIN_DEV_SHOW_PROFILER ) {
return false;
}
$onboarding_data = get_option( 'wc_onboarding_profile', array() );
// @todo Update this to compare to proper bools (https://github.com/woocommerce/woocommerce-admin/issues/2299).
$is_completed = isset( $onboarding_data['completed'] ) && 'true' === $onboarding_data['completed'];
$is_skipped = isset( $onboarding_data['skipped'] ) && 'true' === $onboarding_data['skipped'];
$is_completed = isset( $onboarding_data['completed'] ) && true === $onboarding_data['completed'];
$is_skipped = isset( $onboarding_data['skipped'] ) && true === $onboarding_data['skipped'];
// @todo When merging to WooCommerce Core, we should set the `completed` flag to true during the upgrade progress.
// https://github.com/woocommerce/woocommerce-admin/pull/2300#discussion_r287237498.
@ -57,12 +52,12 @@ class WC_Admin_Onboarding {
}
/**
* Add profiler status to component settings.
* Add profiler items to component settings.
*
* @param array $settings Component settings.
*/
public function component_settings( $settings ) {
$settings['showProfiler'] = $this->should_show_profiler();
$settings['onboardingProfile'] = get_option( 'wc_onboarding_profile', array() );
return $settings;
}