Store Profiler and Product task - include Subscriptions (https://github.com/woocommerce/woocommerce-admin/pull/7734)
* Add flag * Add free subscription to Product Types step * Show copy and install WC-Pay when `Subscriptions` is checked * Fixed `Start with a template` description * Added flag to product-types and small refactor * Add test for subscriptions * Fixed wc-pay installation in product-types step * Refactor product-template-modal # Conflicts: # client/task-list/tasks/products/product-template-modal.js # client/tasks/fills/products/product-template-modal.js * Add more tests * Refactor product types list * Add wc-pay activation in store profiler * Add `wc-pay filter in business details step * Add redirection after selecting subscriptions template option * Fix prop renamed * Fix product-types list * Add changelog * Fix typo * Add check to `Free features` * Refactor `SelectiveExtensionsBundle` * Add `is_activated` to `EvaluateExtension` * Add validation to `ProductTemplateModal` component * Removed useless import * Add missing flags * Fix list * Add promise.all to `product-types` * Removed useless validation Co-authored-by: Fernando Marichal <contacto@fernandomarichal.com>
This commit is contained in:
parent
ad0afb4aba
commit
5d7661eeb9
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: Add
|
||||||
|
|
||||||
|
Store Profiler and Product task - include Subscriptions #7734
|
|
@ -178,22 +178,41 @@ export const SelectiveExtensionsBundle = ( {
|
||||||
const [ showExtensions, setShowExtensions ] = useState( false );
|
const [ showExtensions, setShowExtensions ] = useState( false );
|
||||||
const [ values, setValues ] = useState( baseValues );
|
const [ values, setValues ] = useState( baseValues );
|
||||||
|
|
||||||
const { freeExtensions, isResolving } = useSelect( ( select ) => {
|
const { freeExtensions, isResolving, profileItems } = useSelect(
|
||||||
const { getFreeExtensions, hasFinishedResolution } = select(
|
( select ) => {
|
||||||
ONBOARDING_STORE_NAME
|
const {
|
||||||
);
|
getFreeExtensions,
|
||||||
|
getProfileItems,
|
||||||
|
hasFinishedResolution,
|
||||||
|
} = select( ONBOARDING_STORE_NAME );
|
||||||
|
|
||||||
return {
|
return {
|
||||||
freeExtensions: getFreeExtensions(),
|
freeExtensions: getFreeExtensions(),
|
||||||
isResolving: ! hasFinishedResolution( 'getFreeExtensions' ),
|
isResolving: ! hasFinishedResolution( 'getFreeExtensions' ),
|
||||||
};
|
profileItems: getProfileItems(),
|
||||||
} );
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const installableExtensions = useMemo( () => {
|
const installableExtensions = useMemo( () => {
|
||||||
|
const { product_types: productTypes } = profileItems;
|
||||||
return freeExtensions.filter( ( list ) => {
|
return freeExtensions.filter( ( list ) => {
|
||||||
|
if (
|
||||||
|
window.wcAdminFeatures &&
|
||||||
|
window.wcAdminFeatures.subscriptions
|
||||||
|
) {
|
||||||
|
if ( productTypes.includes( 'subscriptions' ) ) {
|
||||||
|
list.plugins = list.plugins.filter(
|
||||||
|
( extension ) =>
|
||||||
|
extension.key !== 'woocommerce-payments' ||
|
||||||
|
( extension.key === 'woocommerce-payments' &&
|
||||||
|
! extension.is_activated )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
return ALLOWED_PLUGIN_LISTS.includes( list.key );
|
return ALLOWED_PLUGIN_LISTS.includes( list.key );
|
||||||
} );
|
} );
|
||||||
}, [ freeExtensions ] );
|
}, [ freeExtensions, profileItems ] );
|
||||||
|
|
||||||
useEffect( () => {
|
useEffect( () => {
|
||||||
const initialValues = createInitialValues( installableExtensions );
|
const initialValues = createInitialValues( installableExtensions );
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { createElement } from '@wordpress/element';
|
|
||||||
import { render } from '@testing-library/react';
|
import { render } from '@testing-library/react';
|
||||||
import { useSelect } from '@wordpress/data';
|
import { useSelect } from '@wordpress/data';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
|
@ -84,11 +83,14 @@ const freeExtensions = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const profileItems = { product_types: [] };
|
||||||
|
|
||||||
describe( 'Selective extensions bundle', () => {
|
describe( 'Selective extensions bundle', () => {
|
||||||
it( 'should list installable free extensions in footer only basics', () => {
|
it( 'should list installable free extensions in footer only basics', () => {
|
||||||
useSelect.mockReturnValue( {
|
useSelect.mockReturnValue( {
|
||||||
freeExtensions,
|
freeExtensions,
|
||||||
isResolving: false,
|
isResolving: false,
|
||||||
|
profileItems,
|
||||||
} );
|
} );
|
||||||
const { getByText, queryByText } = render(
|
const { getByText, queryByText } = render(
|
||||||
<SelectiveExtensionsBundle isInstallingActivating={ false } />
|
<SelectiveExtensionsBundle isInstallingActivating={ false } />
|
||||||
|
@ -113,6 +115,7 @@ describe( 'Selective extensions bundle', () => {
|
||||||
useSelect.mockReturnValue( {
|
useSelect.mockReturnValue( {
|
||||||
freeExtensions,
|
freeExtensions,
|
||||||
isResolving: false,
|
isResolving: false,
|
||||||
|
profileItems,
|
||||||
} );
|
} );
|
||||||
const { getAllByRole, getByText, queryByText } = render(
|
const { getAllByRole, getByText, queryByText } = render(
|
||||||
<SelectiveExtensionsBundle isInstallingActivating={ false } />
|
<SelectiveExtensionsBundle isInstallingActivating={ false } />
|
||||||
|
|
|
@ -16,12 +16,13 @@ import { includes, filter, get } from 'lodash';
|
||||||
import { getSetting } from '@woocommerce/wc-admin-settings';
|
import { getSetting } from '@woocommerce/wc-admin-settings';
|
||||||
import { recordEvent } from '@woocommerce/tracks';
|
import { recordEvent } from '@woocommerce/tracks';
|
||||||
import { withDispatch, withSelect } from '@wordpress/data';
|
import { withDispatch, withSelect } from '@wordpress/data';
|
||||||
import { ONBOARDING_STORE_NAME } from '@woocommerce/data';
|
import { ONBOARDING_STORE_NAME, PLUGINS_STORE_NAME } from '@woocommerce/data';
|
||||||
import { Text } from '@woocommerce/experimental';
|
import { Text } from '@woocommerce/experimental';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
|
import { createNoticesFromResponse } from '~/lib/notices';
|
||||||
import ProductTypeLabel from './label';
|
import ProductTypeLabel from './label';
|
||||||
import './style.scss';
|
import './style.scss';
|
||||||
|
|
||||||
|
@ -57,17 +58,45 @@ export class ProductTypes extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
onContinue() {
|
onContinue() {
|
||||||
|
const { selected } = this.state;
|
||||||
|
const { installedPlugins = [] } = this.props;
|
||||||
|
|
||||||
if ( ! this.validateField() ) {
|
if ( ! this.validateField() ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { createNotice, goToNextStep, updateProfileItems } = this.props;
|
const {
|
||||||
|
createNotice,
|
||||||
|
goToNextStep,
|
||||||
|
installAndActivatePlugins,
|
||||||
|
updateProfileItems,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
recordEvent( 'storeprofiler_store_product_type_continue', {
|
recordEvent( 'storeprofiler_store_product_type_continue', {
|
||||||
product_type: this.state.selected,
|
product_type: selected,
|
||||||
} );
|
} );
|
||||||
|
|
||||||
updateProfileItems( { product_types: this.state.selected } )
|
const promises = [ updateProfileItems( { product_types: selected } ) ];
|
||||||
|
|
||||||
|
if (
|
||||||
|
window.wcAdminFeatures &&
|
||||||
|
window.wcAdminFeatures.subscriptions &&
|
||||||
|
! installedPlugins.includes( 'woocommerce-payments' ) &&
|
||||||
|
selected.includes( 'subscriptions' )
|
||||||
|
) {
|
||||||
|
promises.push(
|
||||||
|
installAndActivatePlugins( [ 'woocommerce-payments' ] )
|
||||||
|
.then( ( response ) => {
|
||||||
|
createNoticesFromResponse( response );
|
||||||
|
} )
|
||||||
|
.catch( ( error ) => {
|
||||||
|
createNoticesFromResponse( error );
|
||||||
|
throw new Error();
|
||||||
|
} )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Promise.all( promises )
|
||||||
.then( () => goToNextStep() )
|
.then( () => goToNextStep() )
|
||||||
.catch( () =>
|
.catch( () =>
|
||||||
createNotice(
|
createNotice(
|
||||||
|
@ -104,7 +133,11 @@ export class ProductTypes extends Component {
|
||||||
render() {
|
render() {
|
||||||
const { productTypes = {} } = getSetting( 'onboarding', {} );
|
const { productTypes = {} } = getSetting( 'onboarding', {} );
|
||||||
const { error, isMonthlyPricing, selected } = this.state;
|
const { error, isMonthlyPricing, selected } = this.state;
|
||||||
const { isProfileItemsRequesting } = this.props;
|
const {
|
||||||
|
installedPlugins = [],
|
||||||
|
isInstallingActivating,
|
||||||
|
isProfileItemsRequesting,
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="woocommerce-profile-wizard__product-types">
|
<div className="woocommerce-profile-wizard__product-types">
|
||||||
|
@ -166,9 +199,14 @@ export class ProductTypes extends Component {
|
||||||
<Button
|
<Button
|
||||||
isPrimary
|
isPrimary
|
||||||
onClick={ this.onContinue }
|
onClick={ this.onContinue }
|
||||||
isBusy={ isProfileItemsRequesting }
|
isBusy={
|
||||||
|
isProfileItemsRequesting ||
|
||||||
|
isInstallingActivating
|
||||||
|
}
|
||||||
disabled={
|
disabled={
|
||||||
! selected.length || isProfileItemsRequesting
|
! selected.length ||
|
||||||
|
isProfileItemsRequesting ||
|
||||||
|
isInstallingActivating
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{ __( 'Continue', 'woocommerce-admin' ) }
|
{ __( 'Continue', 'woocommerce-admin' ) }
|
||||||
|
@ -201,6 +239,22 @@ export class ProductTypes extends Component {
|
||||||
'woocommerce-admin'
|
'woocommerce-admin'
|
||||||
) }
|
) }
|
||||||
</Text>
|
</Text>
|
||||||
|
{ window.wcAdminFeatures &&
|
||||||
|
window.wcAdminFeatures.subscriptions &&
|
||||||
|
! installedPlugins.includes( 'woocommerce-payments' ) &&
|
||||||
|
selected.includes( 'subscriptions' ) && (
|
||||||
|
<Text
|
||||||
|
variant="body"
|
||||||
|
size="12"
|
||||||
|
lineHeight="16px"
|
||||||
|
as="p"
|
||||||
|
>
|
||||||
|
{ __(
|
||||||
|
'The following extensions will be added to your site for free: WooCommerce Payments. An account is required to use this feature.',
|
||||||
|
'woocommerce-admin'
|
||||||
|
) }
|
||||||
|
</Text>
|
||||||
|
) }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -214,6 +268,9 @@ export default compose(
|
||||||
getOnboardingError,
|
getOnboardingError,
|
||||||
isOnboardingRequesting,
|
isOnboardingRequesting,
|
||||||
} = select( ONBOARDING_STORE_NAME );
|
} = select( ONBOARDING_STORE_NAME );
|
||||||
|
const { getInstalledPlugins, isPluginsRequesting } = select(
|
||||||
|
PLUGINS_STORE_NAME
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isError: Boolean( getOnboardingError( 'updateProfileItems' ) ),
|
isError: Boolean( getOnboardingError( 'updateProfileItems' ) ),
|
||||||
|
@ -221,14 +278,20 @@ export default compose(
|
||||||
isProfileItemsRequesting: isOnboardingRequesting(
|
isProfileItemsRequesting: isOnboardingRequesting(
|
||||||
'updateProfileItems'
|
'updateProfileItems'
|
||||||
),
|
),
|
||||||
|
installedPlugins: getInstalledPlugins(),
|
||||||
|
isInstallingActivating:
|
||||||
|
isPluginsRequesting( 'installPlugins' ) ||
|
||||||
|
isPluginsRequesting( 'activatePlugins' ),
|
||||||
};
|
};
|
||||||
} ),
|
} ),
|
||||||
withDispatch( ( dispatch ) => {
|
withDispatch( ( dispatch ) => {
|
||||||
const { updateProfileItems } = dispatch( ONBOARDING_STORE_NAME );
|
const { updateProfileItems } = dispatch( ONBOARDING_STORE_NAME );
|
||||||
const { createNotice } = dispatch( 'core/notices' );
|
const { createNotice } = dispatch( 'core/notices' );
|
||||||
|
const { installAndActivatePlugins } = dispatch( PLUGINS_STORE_NAME );
|
||||||
|
|
||||||
return {
|
return {
|
||||||
createNotice,
|
createNotice,
|
||||||
|
installAndActivatePlugins,
|
||||||
updateProfileItems,
|
updateProfileItems,
|
||||||
};
|
};
|
||||||
} )
|
} )
|
||||||
|
|
|
@ -32,6 +32,7 @@ describe( 'ProductTypes', () => {
|
||||||
|
|
||||||
afterEach( () => {
|
afterEach( () => {
|
||||||
setSetting( 'onboarding', {} );
|
setSetting( 'onboarding', {} );
|
||||||
|
window.wcAdminFeatures.subscriptions = false;
|
||||||
} );
|
} );
|
||||||
|
|
||||||
test( 'should render product types', () => {
|
test( 'should render product types', () => {
|
||||||
|
@ -86,4 +87,27 @@ describe( 'ProductTypes', () => {
|
||||||
expect( mockGoToNextStep ).toHaveBeenCalled();
|
expect( mockGoToNextStep ).toHaveBeenCalled();
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
|
test( 'should show a warning message at the bottom of the step', () => {
|
||||||
|
setSetting( 'onboarding', {
|
||||||
|
productTypes: {
|
||||||
|
subscriptions: {
|
||||||
|
label: 'Subscriptions',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} );
|
||||||
|
window.wcAdminFeatures.subscriptions = true;
|
||||||
|
|
||||||
|
render( <ProductTypes /> );
|
||||||
|
|
||||||
|
const subscription = screen.getByText( 'Subscriptions', {
|
||||||
|
selector: 'label',
|
||||||
|
} );
|
||||||
|
userEvent.click( subscription );
|
||||||
|
|
||||||
|
expect(
|
||||||
|
screen.queryByText(
|
||||||
|
'The following extensions will be added to your site for free: WooCommerce Payments. An account is required to use this feature.'
|
||||||
|
)
|
||||||
|
).toBeInTheDocument();
|
||||||
|
} );
|
||||||
} );
|
} );
|
||||||
|
|
|
@ -353,7 +353,7 @@ export const TaskList = ( {
|
||||||
? () => dismissTask( task )
|
? () => dismissTask( task )
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
remindMeLater={
|
onSnooze={
|
||||||
task.allowRemindMeLater
|
task.allowRemindMeLater
|
||||||
? () => remindTaskLater( task )
|
? () => remindTaskLater( task )
|
||||||
: undefined
|
: undefined
|
||||||
|
|
|
@ -4,9 +4,13 @@
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { Button, Modal, RadioControl } from '@wordpress/components';
|
import { Button, Modal, RadioControl } from '@wordpress/components';
|
||||||
import { useState } from '@wordpress/element';
|
import { useState } from '@wordpress/element';
|
||||||
import { useDispatch } from '@wordpress/data';
|
import { useDispatch, useSelect } from '@wordpress/data';
|
||||||
import { applyFilters } from '@wordpress/hooks';
|
import { addFilter, applyFilters } from '@wordpress/hooks';
|
||||||
import { ITEMS_STORE_NAME } from '@woocommerce/data';
|
import {
|
||||||
|
ITEMS_STORE_NAME,
|
||||||
|
ONBOARDING_STORE_NAME,
|
||||||
|
PLUGINS_STORE_NAME,
|
||||||
|
} from '@woocommerce/data';
|
||||||
import { getAdminLink } from '@woocommerce/wc-admin-settings';
|
import { getAdminLink } from '@woocommerce/wc-admin-settings';
|
||||||
import { recordEvent } from '@woocommerce/tracks';
|
import { recordEvent } from '@woocommerce/tracks';
|
||||||
|
|
||||||
|
@ -44,18 +48,46 @@ const PRODUCT_TEMPLATES = [
|
||||||
'woocommerce-admin'
|
'woocommerce-admin'
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'subscription',
|
||||||
|
title: __( 'Subscription product', 'woocommerce-admin' ),
|
||||||
|
subtitle: __(
|
||||||
|
'Products that customers receive or gain access to regularly by paying in advance',
|
||||||
|
'woocommerce-admin'
|
||||||
|
),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function ProductTemplateModal( { onClose } ) {
|
export default function ProductTemplateModal( { onClose } ) {
|
||||||
const [ selectedTemplate, setSelectedTemplate ] = useState( null );
|
const [ selectedTemplate, setSelectedTemplate ] = useState( null );
|
||||||
const [ isRedirecting, setIsRedirecting ] = useState( false );
|
const [ isRedirecting, setIsRedirecting ] = useState( false );
|
||||||
const { createProductFromTemplate } = useDispatch( ITEMS_STORE_NAME );
|
const { createProductFromTemplate } = useDispatch( ITEMS_STORE_NAME );
|
||||||
|
const { profileItems } = useSelect( ( select ) => {
|
||||||
|
const { getProfileItems } = select( ONBOARDING_STORE_NAME );
|
||||||
|
|
||||||
|
return {
|
||||||
|
profileItems: getProfileItems(),
|
||||||
|
};
|
||||||
|
} );
|
||||||
|
const { installedPlugins } = useSelect( ( select ) => {
|
||||||
|
const { getInstalledPlugins } = select( PLUGINS_STORE_NAME );
|
||||||
|
|
||||||
|
return {
|
||||||
|
installedPlugins: getInstalledPlugins(),
|
||||||
|
};
|
||||||
|
} );
|
||||||
|
|
||||||
const createTemplate = () => {
|
const createTemplate = () => {
|
||||||
setIsRedirecting( true );
|
setIsRedirecting( true );
|
||||||
recordEvent( 'tasklist_product_template_selection', {
|
recordEvent( 'tasklist_product_template_selection', {
|
||||||
product_type: selectedTemplate,
|
product_type: selectedTemplate,
|
||||||
} );
|
} );
|
||||||
|
if ( selectedTemplate === 'subscription' ) {
|
||||||
|
window.location = getAdminLink(
|
||||||
|
'post-new.php?post_type=product&subscription_pointers=true'
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if ( selectedTemplate ) {
|
if ( selectedTemplate ) {
|
||||||
createProductFromTemplate(
|
createProductFromTemplate(
|
||||||
{
|
{
|
||||||
|
@ -84,6 +116,22 @@ export default function ProductTemplateModal( { onClose } ) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (
|
||||||
|
( window.wcAdminFeatures && ! window.wcAdminFeatures.subscriptions ) ||
|
||||||
|
! profileItems.product_types.includes( 'subscriptions' ) ||
|
||||||
|
! installedPlugins.includes( 'woocommerce-payments' )
|
||||||
|
) {
|
||||||
|
addFilter(
|
||||||
|
ONBOARDING_PRODUCT_TEMPLATES_FILTER,
|
||||||
|
'woocommerce-admin',
|
||||||
|
( productTemplates ) => {
|
||||||
|
return productTemplates.filter(
|
||||||
|
( template ) => template.key !== 'subscription'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const templates = applyFilters(
|
const templates = applyFilters(
|
||||||
ONBOARDING_PRODUCT_TEMPLATES_FILTER,
|
ONBOARDING_PRODUCT_TEMPLATES_FILTER,
|
||||||
PRODUCT_TEMPLATES
|
PRODUCT_TEMPLATES
|
||||||
|
|
|
@ -12,6 +12,8 @@ import {
|
||||||
archive,
|
archive,
|
||||||
download,
|
download,
|
||||||
} from '@wordpress/icons';
|
} from '@wordpress/icons';
|
||||||
|
import { ONBOARDING_STORE_NAME, PLUGINS_STORE_NAME } from '@woocommerce/data';
|
||||||
|
import { useSelect } from '@wordpress/data';
|
||||||
import { List, Pill } from '@woocommerce/components';
|
import { List, Pill } from '@woocommerce/components';
|
||||||
import { getAdminLink } from '@woocommerce/wc-admin-settings';
|
import { getAdminLink } from '@woocommerce/wc-admin-settings';
|
||||||
import { recordEvent } from '@woocommerce/tracks';
|
import { recordEvent } from '@woocommerce/tracks';
|
||||||
|
@ -90,6 +92,35 @@ const subTasks = [
|
||||||
|
|
||||||
export default function Products() {
|
export default function Products() {
|
||||||
const [ selectTemplate, setSelectTemplate ] = useState( null );
|
const [ selectTemplate, setSelectTemplate ] = useState( null );
|
||||||
|
const { profileItems } = useSelect( ( select ) => {
|
||||||
|
const { getProfileItems } = select( ONBOARDING_STORE_NAME );
|
||||||
|
|
||||||
|
return {
|
||||||
|
profileItems: getProfileItems(),
|
||||||
|
};
|
||||||
|
} );
|
||||||
|
const { installedPlugins } = useSelect( ( select ) => {
|
||||||
|
const { getInstalledPlugins } = select( PLUGINS_STORE_NAME );
|
||||||
|
|
||||||
|
return {
|
||||||
|
installedPlugins: getInstalledPlugins(),
|
||||||
|
};
|
||||||
|
} );
|
||||||
|
|
||||||
|
if (
|
||||||
|
window.wcAdminFeatures &&
|
||||||
|
window.wcAdminFeatures.subscriptions &&
|
||||||
|
profileItems.product_types.includes( 'subscriptions' ) &&
|
||||||
|
installedPlugins.includes( 'woocommerce-payments' )
|
||||||
|
) {
|
||||||
|
const task = subTasks.find(
|
||||||
|
( { key } ) => key === 'addProductTemplate'
|
||||||
|
);
|
||||||
|
task.content = __(
|
||||||
|
'Use a template to add physical, digital, variable, and subscription products',
|
||||||
|
'woocommerce-admin'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const onTaskClick = ( task ) => {
|
const onTaskClick = ( task ) => {
|
||||||
task.onClick();
|
task.onClick();
|
||||||
|
|
|
@ -1,94 +0,0 @@
|
||||||
/**
|
|
||||||
* External dependencies
|
|
||||||
*/
|
|
||||||
import { render, screen, fireEvent } from '@testing-library/react';
|
|
||||||
import '@testing-library/jest-dom/extend-expect';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal dependencies
|
|
||||||
*/
|
|
||||||
import { Products, ProductTemplateModal } from '../tasks/products';
|
|
||||||
|
|
||||||
describe( 'products', () => {
|
|
||||||
describe( 'Products', () => {
|
|
||||||
afterEach( () => jest.clearAllMocks() );
|
|
||||||
|
|
||||||
it( 'should render 4 different options to add products', () => {
|
|
||||||
render( <Products /> );
|
|
||||||
|
|
||||||
expect(
|
|
||||||
screen.queryByText( 'Start with a template' )
|
|
||||||
).toBeInTheDocument();
|
|
||||||
expect( screen.queryByText( 'Add manually' ) ).toBeInTheDocument();
|
|
||||||
expect(
|
|
||||||
screen.queryByText( 'Import via CSV' )
|
|
||||||
).toBeInTheDocument();
|
|
||||||
expect(
|
|
||||||
screen.queryByText( 'Import from another service' )
|
|
||||||
).toBeInTheDocument();
|
|
||||||
} );
|
|
||||||
|
|
||||||
it( 'should not render the product template modal right away', () => {
|
|
||||||
render( <Products /> );
|
|
||||||
|
|
||||||
expect( screen.queryByText( '[ProductTemplateModal]' ) ).toBeNull();
|
|
||||||
} );
|
|
||||||
|
|
||||||
it( 'should render product template modal when start with template task is selected', () => {
|
|
||||||
render( <Products /> );
|
|
||||||
|
|
||||||
fireEvent(
|
|
||||||
screen.queryByText( 'Start with a template' ),
|
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
new MouseEvent( 'click', { bubbles: true } )
|
|
||||||
);
|
|
||||||
expect(
|
|
||||||
screen.queryByText( 'Physical product' )
|
|
||||||
).toBeInTheDocument();
|
|
||||||
expect(
|
|
||||||
screen.queryByText( 'Digital product' )
|
|
||||||
).toBeInTheDocument();
|
|
||||||
expect(
|
|
||||||
screen.queryByText( 'Variable product' )
|
|
||||||
).toBeInTheDocument();
|
|
||||||
} );
|
|
||||||
|
|
||||||
it( 'should allow the user to close the template modal', () => {
|
|
||||||
render( <Products /> );
|
|
||||||
|
|
||||||
fireEvent(
|
|
||||||
screen.queryByText( 'Start with a template' ),
|
|
||||||
// eslint-disable-next-line no-undef
|
|
||||||
new MouseEvent( 'click', { bubbles: true } )
|
|
||||||
);
|
|
||||||
expect(
|
|
||||||
screen.queryByText( 'Physical product' )
|
|
||||||
).toBeInTheDocument();
|
|
||||||
const closeButton = screen.getByRole( 'button', {
|
|
||||||
name: 'Close dialog',
|
|
||||||
} );
|
|
||||||
fireEvent.click( closeButton );
|
|
||||||
expect(
|
|
||||||
screen.queryByText( 'Physical product' )
|
|
||||||
).not.toBeInTheDocument();
|
|
||||||
} );
|
|
||||||
} );
|
|
||||||
|
|
||||||
describe( 'ProductWithTemplate', () => {
|
|
||||||
afterEach( () => jest.clearAllMocks() );
|
|
||||||
|
|
||||||
it( 'should render 3 different product types', () => {
|
|
||||||
render( <ProductTemplateModal /> );
|
|
||||||
|
|
||||||
expect(
|
|
||||||
screen.queryByText( 'Physical product' )
|
|
||||||
).toBeInTheDocument();
|
|
||||||
expect(
|
|
||||||
screen.queryByText( 'Digital product' )
|
|
||||||
).toBeInTheDocument();
|
|
||||||
expect(
|
|
||||||
screen.queryByText( 'Variable product' )
|
|
||||||
).toBeInTheDocument();
|
|
||||||
} );
|
|
||||||
} );
|
|
||||||
} );
|
|
|
@ -4,9 +4,13 @@
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { Button, Modal, RadioControl } from '@wordpress/components';
|
import { Button, Modal, RadioControl } from '@wordpress/components';
|
||||||
import { useState } from '@wordpress/element';
|
import { useState } from '@wordpress/element';
|
||||||
import { useDispatch } from '@wordpress/data';
|
import { useDispatch, useSelect } from '@wordpress/data';
|
||||||
import { applyFilters } from '@wordpress/hooks';
|
import { addFilter, applyFilters } from '@wordpress/hooks';
|
||||||
import { ITEMS_STORE_NAME } from '@woocommerce/data';
|
import {
|
||||||
|
ITEMS_STORE_NAME,
|
||||||
|
ONBOARDING_STORE_NAME,
|
||||||
|
PLUGINS_STORE_NAME,
|
||||||
|
} from '@woocommerce/data';
|
||||||
import { getAdminLink } from '@woocommerce/wc-admin-settings';
|
import { getAdminLink } from '@woocommerce/wc-admin-settings';
|
||||||
import { recordEvent } from '@woocommerce/tracks';
|
import { recordEvent } from '@woocommerce/tracks';
|
||||||
|
|
||||||
|
@ -44,18 +48,46 @@ const PRODUCT_TEMPLATES = [
|
||||||
'woocommerce-admin'
|
'woocommerce-admin'
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'subscription',
|
||||||
|
title: __( 'Subscription product', 'woocommerce-admin' ),
|
||||||
|
subtitle: __(
|
||||||
|
'Products that customers receive or gain access to regularly by paying in advance',
|
||||||
|
'woocommerce-admin'
|
||||||
|
),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function ProductTemplateModal( { onClose } ) {
|
export default function ProductTemplateModal( { onClose } ) {
|
||||||
const [ selectedTemplate, setSelectedTemplate ] = useState( null );
|
const [ selectedTemplate, setSelectedTemplate ] = useState( null );
|
||||||
const [ isRedirecting, setIsRedirecting ] = useState( false );
|
const [ isRedirecting, setIsRedirecting ] = useState( false );
|
||||||
const { createProductFromTemplate } = useDispatch( ITEMS_STORE_NAME );
|
const { createProductFromTemplate } = useDispatch( ITEMS_STORE_NAME );
|
||||||
|
const { profileItems } = useSelect( ( select ) => {
|
||||||
|
const { getProfileItems } = select( ONBOARDING_STORE_NAME );
|
||||||
|
|
||||||
|
return {
|
||||||
|
profileItems: getProfileItems(),
|
||||||
|
};
|
||||||
|
} );
|
||||||
|
const { installedPlugins } = useSelect( ( select ) => {
|
||||||
|
const { getInstalledPlugins } = select( PLUGINS_STORE_NAME );
|
||||||
|
|
||||||
|
return {
|
||||||
|
installedPlugins: getInstalledPlugins(),
|
||||||
|
};
|
||||||
|
} );
|
||||||
|
|
||||||
const createTemplate = () => {
|
const createTemplate = () => {
|
||||||
setIsRedirecting( true );
|
setIsRedirecting( true );
|
||||||
recordEvent( 'tasklist_product_template_selection', {
|
recordEvent( 'tasklist_product_template_selection', {
|
||||||
product_type: selectedTemplate,
|
product_type: selectedTemplate,
|
||||||
} );
|
} );
|
||||||
|
if ( selectedTemplate === 'subscription' ) {
|
||||||
|
window.location = getAdminLink(
|
||||||
|
'post-new.php?post_type=product&subscription_pointers=true'
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if ( selectedTemplate ) {
|
if ( selectedTemplate ) {
|
||||||
createProductFromTemplate(
|
createProductFromTemplate(
|
||||||
{
|
{
|
||||||
|
@ -84,6 +116,22 @@ export default function ProductTemplateModal( { onClose } ) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (
|
||||||
|
( window.wcAdminFeatures && ! window.wcAdminFeatures.subscriptions ) ||
|
||||||
|
! profileItems.product_types.includes( 'subscriptions' ) ||
|
||||||
|
! installedPlugins.includes( 'woocommerce-payments' )
|
||||||
|
) {
|
||||||
|
addFilter(
|
||||||
|
ONBOARDING_PRODUCT_TEMPLATES_FILTER,
|
||||||
|
'woocommerce-admin',
|
||||||
|
( productTemplates ) => {
|
||||||
|
return productTemplates.filter(
|
||||||
|
( template ) => template.key !== 'subscription'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const templates = applyFilters(
|
const templates = applyFilters(
|
||||||
ONBOARDING_PRODUCT_TEMPLATES_FILTER,
|
ONBOARDING_PRODUCT_TEMPLATES_FILTER,
|
||||||
PRODUCT_TEMPLATES
|
PRODUCT_TEMPLATES
|
||||||
|
|
|
@ -12,6 +12,8 @@ import {
|
||||||
archive,
|
archive,
|
||||||
download,
|
download,
|
||||||
} from '@wordpress/icons';
|
} from '@wordpress/icons';
|
||||||
|
import { ONBOARDING_STORE_NAME, PLUGINS_STORE_NAME } from '@woocommerce/data';
|
||||||
|
import { useSelect } from '@wordpress/data';
|
||||||
import { List, Pill } from '@woocommerce/components';
|
import { List, Pill } from '@woocommerce/components';
|
||||||
import { getAdminLink } from '@woocommerce/wc-admin-settings';
|
import { getAdminLink } from '@woocommerce/wc-admin-settings';
|
||||||
import { recordEvent } from '@woocommerce/tracks';
|
import { recordEvent } from '@woocommerce/tracks';
|
||||||
|
@ -92,6 +94,35 @@ const subTasks = [
|
||||||
|
|
||||||
const Products = () => {
|
const Products = () => {
|
||||||
const [ selectTemplate, setSelectTemplate ] = useState( null );
|
const [ selectTemplate, setSelectTemplate ] = useState( null );
|
||||||
|
const { profileItems } = useSelect( ( select ) => {
|
||||||
|
const { getProfileItems } = select( ONBOARDING_STORE_NAME );
|
||||||
|
|
||||||
|
return {
|
||||||
|
profileItems: getProfileItems(),
|
||||||
|
};
|
||||||
|
} );
|
||||||
|
const { installedPlugins } = useSelect( ( select ) => {
|
||||||
|
const { getInstalledPlugins } = select( PLUGINS_STORE_NAME );
|
||||||
|
|
||||||
|
return {
|
||||||
|
installedPlugins: getInstalledPlugins(),
|
||||||
|
};
|
||||||
|
} );
|
||||||
|
|
||||||
|
if (
|
||||||
|
window.wcAdminFeatures &&
|
||||||
|
window.wcAdminFeatures.subscriptions &&
|
||||||
|
profileItems.product_types.includes( 'subscriptions' ) &&
|
||||||
|
installedPlugins.includes( 'woocommerce-payments' )
|
||||||
|
) {
|
||||||
|
const task = subTasks.find(
|
||||||
|
( { key } ) => key === 'addProductTemplate'
|
||||||
|
);
|
||||||
|
task.content = __(
|
||||||
|
'Use a template to add physical, digital, variable, and subscription products',
|
||||||
|
'woocommerce-admin'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const onTaskClick = ( task ) => {
|
const onTaskClick = ( task ) => {
|
||||||
task.onClick();
|
task.onClick();
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
"payment-gateway-suggestions": true,
|
"payment-gateway-suggestions": true,
|
||||||
"settings": false,
|
"settings": false,
|
||||||
"shipping-label-banner": true,
|
"shipping-label-banner": true,
|
||||||
|
"subscriptions": false,
|
||||||
"store-alerts": true,
|
"store-alerts": true,
|
||||||
"tasks": false,
|
"tasks": false,
|
||||||
"transient-notices": true,
|
"transient-notices": true,
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
"remote-free-extensions": true,
|
"remote-free-extensions": true,
|
||||||
"settings": false,
|
"settings": false,
|
||||||
"shipping-label-banner": true,
|
"shipping-label-banner": true,
|
||||||
|
"subscriptions": true,
|
||||||
"store-alerts": true,
|
"store-alerts": true,
|
||||||
"tasks": true,
|
"tasks": true,
|
||||||
"transient-notices": true,
|
"transient-notices": true,
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
"payment-gateway-suggestions": true,
|
"payment-gateway-suggestions": true,
|
||||||
"settings": false,
|
"settings": false,
|
||||||
"shipping-label-banner": true,
|
"shipping-label-banner": true,
|
||||||
|
"subscriptions": false,
|
||||||
"store-alerts": true,
|
"store-alerts": true,
|
||||||
"tasks": false,
|
"tasks": false,
|
||||||
"transient-notices": true,
|
"transient-notices": true,
|
||||||
|
|
|
@ -433,37 +433,38 @@ class Onboarding {
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function get_allowed_product_types() {
|
public static function get_allowed_product_types() {
|
||||||
$product_types = self::append_product_data(
|
$products = array(
|
||||||
array(
|
'physical' => array(
|
||||||
'physical' => array(
|
'label' => __( 'Physical products', 'woocommerce-admin' ),
|
||||||
'label' => __( 'Physical products', 'woocommerce-admin' ),
|
'default' => true,
|
||||||
'default' => true,
|
),
|
||||||
),
|
'downloads' => array(
|
||||||
'downloads' => array(
|
'label' => __( 'Downloads', 'woocommerce-admin' ),
|
||||||
'label' => __( 'Downloads', 'woocommerce-admin' ),
|
),
|
||||||
),
|
'subscriptions' => array(
|
||||||
'subscriptions' => array(
|
'label' => __( 'Subscriptions', 'woocommerce-admin' ),
|
||||||
'label' => __( 'Subscriptions', 'woocommerce-admin' ),
|
),
|
||||||
'product' => 27147,
|
'memberships' => array(
|
||||||
),
|
'label' => __( 'Memberships', 'woocommerce-admin' ),
|
||||||
'memberships' => array(
|
'product' => 958589,
|
||||||
'label' => __( 'Memberships', 'woocommerce-admin' ),
|
),
|
||||||
'product' => 958589,
|
'bookings' => array(
|
||||||
),
|
'label' => __( 'Bookings', 'woocommerce-admin' ),
|
||||||
'bookings' => array(
|
'product' => 390890,
|
||||||
'label' => __( 'Bookings', 'woocommerce-admin' ),
|
),
|
||||||
'product' => 390890,
|
'product-bundles' => array(
|
||||||
),
|
'label' => __( 'Bundles', 'woocommerce-admin' ),
|
||||||
'product-bundles' => array(
|
'product' => 18716,
|
||||||
'label' => __( 'Bundles', 'woocommerce-admin' ),
|
),
|
||||||
'product' => 18716,
|
'product-add-ons' => array(
|
||||||
),
|
'label' => __( 'Customizable products', 'woocommerce-admin' ),
|
||||||
'product-add-ons' => array(
|
'product' => 18618,
|
||||||
'label' => __( 'Customizable products', 'woocommerce-admin' ),
|
),
|
||||||
'product' => 18618,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
if ( ! Features::is_enabled( 'subscriptions' ) ) {
|
||||||
|
$products['subscriptions']['product'] = 27147;
|
||||||
|
}
|
||||||
|
$product_types = self::append_product_data( $products );
|
||||||
|
|
||||||
return apply_filters( 'woocommerce_admin_onboarding_product_types', $product_types );
|
return apply_filters( 'woocommerce_admin_onboarding_product_types', $product_types );
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,9 @@ class EvaluateExtension {
|
||||||
}
|
}
|
||||||
|
|
||||||
$installed_plugins = PluginsHelper::get_installed_plugin_slugs();
|
$installed_plugins = PluginsHelper::get_installed_plugin_slugs();
|
||||||
|
$activated_plugins = PluginsHelper::get_active_plugin_slugs();
|
||||||
$extension->is_installed = in_array( explode( ':', $extension->key )[0], $installed_plugins, true );
|
$extension->is_installed = in_array( explode( ':', $extension->key )[0], $installed_plugins, true );
|
||||||
|
$extension->is_activated = in_array( explode( ':', $extension->key )[0], $activated_plugins, true );
|
||||||
|
|
||||||
return $extension;
|
return $extension;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue