* transform data

* working

* better

* check for marketplace suggestions

* changelog

* copy initialInstallableExtensions before transform

* parse locales server side

* deep equality

* Match remote data to local data

* reflect changes on UI

* fix keys
This commit is contained in:
Paul Sealock 2021-05-18 14:28:13 +12:00 committed by GitHub
parent 8d2bd3bb2f
commit 9c94852932
4 changed files with 176 additions and 66 deletions

View File

@ -2,18 +2,16 @@
* External dependencies
*/
import { useEffect, useState } from '@wordpress/element';
import {
Button,
Card,
CheckboxControl,
__experimentalText as Text,
} from '@wordpress/components';
import { Button, Card, CheckboxControl, Spinner } from '@wordpress/components';
import { Text } from '@woocommerce/experimental';
import { Link } from '@woocommerce/components';
import { __, _n, sprintf } from '@wordpress/i18n';
import { Icon, chevronDown, chevronUp } from '@wordpress/icons';
import interpolateComponents from 'interpolate-components';
import { pluginNames } from '@woocommerce/data';
import { pluginNames, SETTINGS_STORE_NAME } from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
import apiFetch from '@wordpress/api-fetch';
import { useSelect } from '@wordpress/data';
/**
* Internal dependencies
@ -53,9 +51,10 @@ const generatePluginDescriptionWithLink = (
} );
};
const installableExtensions = [
const installableExtensionsData = [
{
title: __( 'Get the basics', 'woocommerce-admin' ),
key: 'basics',
plugins: [
{
slug: 'woocommerce-payments',
@ -139,7 +138,8 @@ const installableExtensions = [
],
},
{
title: 'Grow your store',
title: __( 'Grow your store', 'woocommerce-admin' ),
key: 'grow',
plugins: [
{
slug: 'mailpoet',
@ -319,6 +319,45 @@ const getVisiblePlugins = ( plugins, country, industry, productTypes ) => {
);
};
const transformRemoteExtensions = ( extensionData ) => {
return extensionData.map( ( section ) => {
const plugins = section.plugins.map( ( plugin ) => {
return {
...plugin,
description: generatePluginDescriptionWithLink(
plugin.description,
plugin.key
),
slug: plugin.key,
isVisible: () => true,
};
} );
return {
...section,
plugins,
};
} );
};
const baseValues = { install_extensions: true };
const createInitialValues = ( extensions, country, industry, productTypes ) => {
return extensions.reduce( ( acc, curr ) => {
const plugins = getVisiblePlugins(
curr.plugins,
country,
industry,
productTypes
).reduce( ( pluginAcc, { slug } ) => {
return { ...pluginAcc, [ slug ]: true };
}, {} );
return {
...acc,
...plugins,
};
}, baseValues );
};
export const SelectiveExtensionsBundle = ( {
isInstallingActivating,
onSubmit,
@ -327,29 +366,63 @@ export const SelectiveExtensionsBundle = ( {
productTypes,
} ) => {
const [ showExtensions, setShowExtensions ] = useState( false );
const [ values, setValues ] = useState( {} );
const [ values, setValues ] = useState( baseValues );
const [ installableExtensions, setInstallableExtensions ] = useState( [
{ key: 'spinner', plugins: [] },
] );
const [ isFetching, setIsFetching ] = useState( true );
const allowMarketplaceSuggestions = useSelect( ( select ) =>
select( SETTINGS_STORE_NAME ).getSetting(
'wc_admin',
'allowMarketplaceSuggestions'
)
);
useEffect( () => {
const initialValues = installableExtensions.reduce(
( acc, curr ) => {
const plugins = getVisiblePlugins(
curr.plugins,
country,
industry,
productTypes
).reduce( ( pluginAcc, { slug } ) => {
return { ...pluginAcc, [ slug ]: true };
}, {} );
const setLocalInstallableExtensions = () => {
const initialValues = createInitialValues(
installableExtensionsData,
country,
industry,
productTypes
);
setInstallableExtensions( installableExtensionsData );
setValues( initialValues );
setIsFetching( false );
};
return {
...acc,
...plugins,
};
},
{ install_extensions: true }
);
setValues( initialValues );
}, [ country ] );
if (
window.wcAdminFeatures &&
window.wcAdminFeatures[ 'remote-extensions-list' ] === true &&
allowMarketplaceSuggestions
) {
apiFetch( {
path: '/wc-admin/onboarding/free-extensions',
} )
.then( ( results ) => {
const transformedExtensions = transformRemoteExtensions(
results
);
const initialValues = createInitialValues(
transformedExtensions,
country,
industry,
productTypes
);
setInstallableExtensions( transformedExtensions );
setValues( initialValues );
setIsFetching( false );
} )
.catch( () => {
// An error has occurred, default to local config
setLocalInstallableExtensions();
} );
} else {
// Use local config
setLocalInstallableExtensions();
}
}, [ country, industry, productTypes, allowMarketplaceSuggestions ] );
const getCheckboxChangeHandler = ( slug ) => {
return ( checked ) => {
@ -415,28 +488,34 @@ export const SelectiveExtensionsBundle = ( {
/>
</div>
{ showExtensions &&
installableExtensions.map( ( { plugins, title } ) => (
<div key={ title }>
<div className="woocommerce-admin__business-details__selective-extensions-bundle__category">
{ title }
installableExtensions.map(
( { plugins, title, key } ) => (
<div key={ key }>
<div className="woocommerce-admin__business-details__selective-extensions-bundle__category">
{ title }
</div>
{ isFetching ? (
<Spinner />
) : (
getVisiblePlugins(
plugins,
country,
industry,
productTypes
).map( ( { description, slug } ) => (
<BundleExtensionCheckbox
key={ slug }
description={ description }
isChecked={ values[ slug ] }
onChange={ getCheckboxChangeHandler(
slug
) }
/>
) )
) }
</div>
{ getVisiblePlugins(
plugins,
country,
industry,
productTypes
).map( ( { description, slug } ) => (
<BundleExtensionCheckbox
key={ slug }
description={ description }
isChecked={ values[ slug ] }
onChange={ getCheckboxChangeHandler(
slug
) }
/>
) ) }
</div>
) ) }
)
) }
</div>
<div className="woocommerce-profile-wizard__business-details__free-features__action">
<Button

View File

@ -85,6 +85,7 @@ Release and roadmap notes are available on the [WooCommerce Developers Blog](htt
- Add: Add transient notices feature #6809
- Add: Add transformers in remote inbox notifications #6948
- Add: Get post install scripts from gateway and enqueue in client #6967
- Add: Free extension list powered by remote config #6952
- Dev: Update package-lock to fix versioning of local packages. #6843
- Dev: Use rule processing for remote payment methods #6830
- Dev: Update E2E jest config, so it correctly creates screenshots on failure. #6858

View File

@ -14,29 +14,22 @@ use Automattic\WooCommerce\Admin\RemoteInboxNotifications\RuleEvaluator;
*/
class EvaluateExtension {
/**
* Evaluates the spec and returns the method.
* Evaluates the spec and returns the extension.
*
* @param array $spec The method to evaluate.
* @return array The evaluated method.
* @param array $spec The extension section to evaluate.
* @return array The evaluated extension section.
*/
public static function evaluate( $spec ) {
$rule_evaluator = new RuleEvaluator();
$method = $spec;
if ( isset( $spec->is_visible ) ) {
$is_visible = $rule_evaluator->evaluate( $spec->is_visible );
$method->is_visible = $is_visible;
// Return early if visibility does not pass.
if ( ! $is_visible ) {
return $method;
foreach ( $spec->plugins as $plugin ) {
if ( isset( $plugin->is_visible ) ) {
$is_visible = $rule_evaluator->evaluate( $plugin->is_visible );
$plugin->is_visible = $is_visible;
}
}
if ( isset( $spec->is_configured ) ) {
$is_configured = $rule_evaluator->evaluate( $method->is_configured );
$method->is_configured = $is_configured;
}
return $method;
return $spec;
}
}

View File

@ -55,9 +55,46 @@ class Init {
if ( false === $specs || ! is_array( $specs ) || 0 === count( $specs ) ) {
// We are running too early, need to poll data sources first.
$specs = DataSourcePoller::read_specs_from_data_sources();
// Localize top level.
$specs = self::localize( $specs );
// Localize plugins.
foreach ( $specs as $spec ) {
$spec->plugins = self::localize( $spec->plugins );
}
set_transient( self::SPECS_TRANSIENT_NAME, $specs, 7 * DAY_IN_SECONDS );
}
return $specs;
}
/**
* Localize the provided method.
*
* @param array $specs The specs to localize.
* @return array Localized specs.
*/
public static function localize( $specs ) {
$localized_specs = array();
foreach ( $specs as $spec ) {
if ( ! isset( $spec->locales ) ) {
continue;
}
$locale = SpecRunner::get_locale( $spec->locales );
// Skip specs where no matching locale is found.
if ( ! $locale ) {
continue;
}
$data = (object) array_merge( (array) $locale, (array) $spec );
unset( $data->locales );
$localized_specs[] = $data;
}
return $localized_specs;
}
}