Consume Remote Free Extensions from UI (https://github.com/woocommerce/woocommerce-admin/pull/6952)
* 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:
parent
8d2bd3bb2f
commit
9c94852932
|
@ -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,19 +319,29 @@ const getVisiblePlugins = ( plugins, country, industry, productTypes ) => {
|
|||
);
|
||||
};
|
||||
|
||||
export const SelectiveExtensionsBundle = ( {
|
||||
isInstallingActivating,
|
||||
onSubmit,
|
||||
country,
|
||||
industry,
|
||||
productTypes,
|
||||
} ) => {
|
||||
const [ showExtensions, setShowExtensions ] = useState( false );
|
||||
const [ values, setValues ] = useState( {} );
|
||||
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,
|
||||
};
|
||||
} );
|
||||
};
|
||||
|
||||
useEffect( () => {
|
||||
const initialValues = installableExtensions.reduce(
|
||||
( acc, curr ) => {
|
||||
const baseValues = { install_extensions: true };
|
||||
const createInitialValues = ( extensions, country, industry, productTypes ) => {
|
||||
return extensions.reduce( ( acc, curr ) => {
|
||||
const plugins = getVisiblePlugins(
|
||||
curr.plugins,
|
||||
country,
|
||||
|
@ -345,11 +355,74 @@ export const SelectiveExtensionsBundle = ( {
|
|||
...acc,
|
||||
...plugins,
|
||||
};
|
||||
},
|
||||
{ install_extensions: true }
|
||||
}, baseValues );
|
||||
};
|
||||
|
||||
export const SelectiveExtensionsBundle = ( {
|
||||
isInstallingActivating,
|
||||
onSubmit,
|
||||
country,
|
||||
industry,
|
||||
productTypes,
|
||||
} ) => {
|
||||
const [ showExtensions, setShowExtensions ] = useState( false );
|
||||
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 setLocalInstallableExtensions = () => {
|
||||
const initialValues = createInitialValues(
|
||||
installableExtensionsData,
|
||||
country,
|
||||
industry,
|
||||
productTypes
|
||||
);
|
||||
setInstallableExtensions( installableExtensionsData );
|
||||
setValues( initialValues );
|
||||
}, [ country ] );
|
||||
setIsFetching( false );
|
||||
};
|
||||
|
||||
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,12 +488,16 @@ export const SelectiveExtensionsBundle = ( {
|
|||
/>
|
||||
</div>
|
||||
{ showExtensions &&
|
||||
installableExtensions.map( ( { plugins, title } ) => (
|
||||
<div key={ title }>
|
||||
installableExtensions.map(
|
||||
( { plugins, title, key } ) => (
|
||||
<div key={ key }>
|
||||
<div className="woocommerce-admin__business-details__selective-extensions-bundle__category">
|
||||
{ title }
|
||||
</div>
|
||||
{ getVisiblePlugins(
|
||||
{ isFetching ? (
|
||||
<Spinner />
|
||||
) : (
|
||||
getVisiblePlugins(
|
||||
plugins,
|
||||
country,
|
||||
industry,
|
||||
|
@ -434,9 +511,11 @@ export const SelectiveExtensionsBundle = ( {
|
|||
slug
|
||||
) }
|
||||
/>
|
||||
) ) }
|
||||
) )
|
||||
) }
|
||||
</div>
|
||||
) ) }
|
||||
)
|
||||
) }
|
||||
</div>
|
||||
<div className="woocommerce-profile-wizard__business-details__free-features__action">
|
||||
<Button
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue