Remove theme step from onboarding wizard (#37671)
* Remove theme step from onboarding wizard * Remove theme step from e2e tests * Deprecated "theme" prop from profileItem type * Add changelog * Remove theme product from dashboard * Update packages/js/data/src/onboarding/types.ts Co-authored-by: Ilyas Foo <foo.ilyas@gmail.com> --------- Co-authored-by: Ilyas Foo <foo.ilyas@gmail.com>
This commit is contained in:
parent
9ae8208f26
commit
a953904d84
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: update
|
||||||
|
|
||||||
|
Remove obw theme step tests
|
|
@ -14,7 +14,6 @@ import {
|
||||||
StoreDetails,
|
StoreDetails,
|
||||||
StoreDetailsSection,
|
StoreDetailsSection,
|
||||||
} from '../sections/onboarding/StoreDetailsSection';
|
} from '../sections/onboarding/StoreDetailsSection';
|
||||||
import { ThemeSection } from '../sections/onboarding/ThemeSection';
|
|
||||||
import { BasePage } from './BasePage';
|
import { BasePage } from './BasePage';
|
||||||
|
|
||||||
export class OnboardingWizard extends BasePage {
|
export class OnboardingWizard extends BasePage {
|
||||||
|
@ -24,7 +23,6 @@ export class OnboardingWizard extends BasePage {
|
||||||
industry: IndustrySection;
|
industry: IndustrySection;
|
||||||
productTypes: ProductTypeSection;
|
productTypes: ProductTypeSection;
|
||||||
business: BusinessSection;
|
business: BusinessSection;
|
||||||
themes: ThemeSection;
|
|
||||||
|
|
||||||
constructor( page: Page ) {
|
constructor( page: Page ) {
|
||||||
super( page );
|
super( page );
|
||||||
|
@ -32,7 +30,6 @@ export class OnboardingWizard extends BasePage {
|
||||||
this.industry = new IndustrySection( page );
|
this.industry = new IndustrySection( page );
|
||||||
this.productTypes = new ProductTypeSection( page );
|
this.productTypes = new ProductTypeSection( page );
|
||||||
this.business = new BusinessSection( page );
|
this.business = new BusinessSection( page );
|
||||||
this.themes = new ThemeSection( page );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async skipStoreSetup(): Promise< void > {
|
async skipStoreSetup(): Promise< void > {
|
||||||
|
@ -90,7 +87,6 @@ export class OnboardingWizard extends BasePage {
|
||||||
productNumber: string;
|
productNumber: string;
|
||||||
currentlySelling: string;
|
currentlySelling: string;
|
||||||
};
|
};
|
||||||
themeTitle?: string;
|
|
||||||
} = {}
|
} = {}
|
||||||
): Promise< void > {
|
): Promise< void > {
|
||||||
await this.navigate();
|
await this.navigate();
|
||||||
|
@ -142,13 +138,5 @@ export class OnboardingWizard extends BasePage {
|
||||||
await this.business.uncheckAllRecommendedBusinessFeatures();
|
await this.business.uncheckAllRecommendedBusinessFeatures();
|
||||||
|
|
||||||
await this.continue();
|
await this.continue();
|
||||||
await this.themes.isDisplayed();
|
|
||||||
|
|
||||||
// This navigates to the home screen
|
|
||||||
if ( options.themeTitle ) {
|
|
||||||
await this.themes.continueWithTheme( options.themeTitle );
|
|
||||||
} else {
|
|
||||||
await this.themes.continueWithActiveTheme();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
/**
|
|
||||||
* Internal dependencies
|
|
||||||
*/
|
|
||||||
import { BasePage } from '../../pages/BasePage';
|
|
||||||
import { waitForElementByText } from '../../utils/actions';
|
|
||||||
|
|
||||||
export class ThemeSection extends BasePage {
|
|
||||||
async isDisplayed(): Promise< void > {
|
|
||||||
await waitForElementByText( 'h2', 'Choose a theme' );
|
|
||||||
await waitForElementByText( 'button', 'All themes' );
|
|
||||||
}
|
|
||||||
|
|
||||||
async continueWithActiveTheme(): Promise< void > {
|
|
||||||
await this.clickButtonWithText( 'Continue with my active theme' );
|
|
||||||
}
|
|
||||||
|
|
||||||
async continueWithTheme( themeTitle: string ): Promise< void > {
|
|
||||||
const title = await waitForElementByText( 'h2', themeTitle );
|
|
||||||
const chooseButton = await title?.evaluateHandle( ( element ) => {
|
|
||||||
const card = element.closest( '.components-card' );
|
|
||||||
return Array.from( card?.querySelectorAll( 'button' ) || [] ).find(
|
|
||||||
( el ) => el.textContent === 'Choose'
|
|
||||||
);
|
|
||||||
} );
|
|
||||||
if ( chooseButton ) {
|
|
||||||
await chooseButton.asElement()?.click();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -107,11 +107,6 @@ export const testAdminOnboardingWizard = () => {
|
||||||
await profileWizard.continue();
|
await profileWizard.continue();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
it( 'can complete the theme selection section', async () => {
|
|
||||||
await profileWizard.themes.isDisplayed();
|
|
||||||
await profileWizard.themes.continueWithActiveTheme();
|
|
||||||
} );
|
|
||||||
|
|
||||||
it( 'can select the right currency on settings page related to the onboarding country', async () => {
|
it( 'can select the right currency on settings page related to the onboarding country', async () => {
|
||||||
const settingsScreen = new WcSettings( page );
|
const settingsScreen = new WcSettings( page );
|
||||||
await settingsScreen.navigate();
|
await settingsScreen.navigate();
|
||||||
|
@ -185,7 +180,7 @@ export const testSelectiveBundleWCPay = () => {
|
||||||
await profileWizard.continue();
|
await profileWizard.continue();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
it( 'can choose not to install any extensions', async () => {
|
it( 'can choose not to install any extensions, and finish the rest of the wizard successfully', async () => {
|
||||||
await profileWizard.business.freeFeaturesIsDisplayed();
|
await profileWizard.business.freeFeaturesIsDisplayed();
|
||||||
// Add WC Pay check
|
// Add WC Pay check
|
||||||
await profileWizard.business.expandRecommendedBusinessFeatures();
|
await profileWizard.business.expandRecommendedBusinessFeatures();
|
||||||
|
@ -198,13 +193,6 @@ export const testSelectiveBundleWCPay = () => {
|
||||||
await profileWizard.continue();
|
await profileWizard.continue();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
it( 'can finish the rest of the wizard successfully', async () => {
|
|
||||||
await profileWizard.themes.isDisplayed();
|
|
||||||
|
|
||||||
// This navigates to the home screen
|
|
||||||
await profileWizard.themes.continueWithActiveTheme();
|
|
||||||
} );
|
|
||||||
|
|
||||||
it( 'should display the choose payments task, and not the woocommerce payments task', async () => {
|
it( 'should display the choose payments task, and not the woocommerce payments task', async () => {
|
||||||
const homescreen = new WcHomescreen( page );
|
const homescreen = new WcHomescreen( page );
|
||||||
await homescreen.isDisplayed();
|
await homescreen.isDisplayed();
|
||||||
|
@ -333,11 +321,8 @@ export const testDifferentStoreCurrenciesWCPay = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
await profileWizard.business.uncheckAllRecommendedBusinessFeatures();
|
await profileWizard.business.uncheckAllRecommendedBusinessFeatures();
|
||||||
await profileWizard.continue();
|
|
||||||
await profileWizard.themes.isDisplayed();
|
|
||||||
|
|
||||||
// This navigates to the home screen
|
// This navigates to the home screen
|
||||||
await profileWizard.themes.continueWithActiveTheme();
|
await profileWizard.continue();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
it( `can select ${ spec.expectedCurrency } as the currency for ${ spec.countryRegion }`, async () => {
|
it( `can select ${ spec.expectedCurrency } as the currency for ${ spec.countryRegion }`, async () => {
|
||||||
|
@ -583,7 +568,6 @@ export const testBusinessDetailsForm = () => {
|
||||||
await profileWizard.business.expandRecommendedBusinessFeatures();
|
await profileWizard.business.expandRecommendedBusinessFeatures();
|
||||||
await profileWizard.business.uncheckAllRecommendedBusinessFeatures();
|
await profileWizard.business.uncheckAllRecommendedBusinessFeatures();
|
||||||
await profileWizard.continue();
|
await profileWizard.continue();
|
||||||
await profileWizard.themes.isDisplayed();
|
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
};
|
};
|
||||||
|
|
|
@ -59,40 +59,5 @@ export const testAdminPurchaseSetupTask = () => {
|
||||||
).toBeDefined();
|
).toBeDefined();
|
||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
describe( 'selecting paid theme', () => {
|
|
||||||
beforeAll( async () => {
|
|
||||||
await resetWooCommerceState();
|
|
||||||
|
|
||||||
await profileWizard.navigate();
|
|
||||||
await profileWizard.walkThroughAndCompleteOnboardingWizard( {
|
|
||||||
themeTitle: 'Blooms',
|
|
||||||
} );
|
|
||||||
|
|
||||||
await homeScreen.isDisplayed();
|
|
||||||
await homeScreen.possiblyDismissWelcomeModal();
|
|
||||||
} );
|
|
||||||
|
|
||||||
it( 'should display add <theme name> to my store task', async () => {
|
|
||||||
expect(
|
|
||||||
await getElementByText( '*', 'Add Blooms to my store' )
|
|
||||||
).toBeDefined();
|
|
||||||
} );
|
|
||||||
|
|
||||||
it( 'should show paid features modal with option to buy now', async () => {
|
|
||||||
const task = await getElementByText(
|
|
||||||
'*',
|
|
||||||
'Add Blooms to my store'
|
|
||||||
);
|
|
||||||
await task?.click();
|
|
||||||
await waitForElementByText(
|
|
||||||
'h1',
|
|
||||||
'Would you like to add the following paid features to your store now?'
|
|
||||||
);
|
|
||||||
expect(
|
|
||||||
await getElementByText( 'button', 'Buy now' )
|
|
||||||
).toBeDefined();
|
|
||||||
} );
|
|
||||||
} );
|
|
||||||
} );
|
} );
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: dev
|
||||||
|
|
||||||
|
Deprecate "theme" prop from profileItem type
|
|
@ -129,6 +129,7 @@ export type ProfileItems = {
|
||||||
selling_venues?: string | null;
|
selling_venues?: string | null;
|
||||||
setup_client?: boolean | null;
|
setup_client?: boolean | null;
|
||||||
skipped?: boolean | null;
|
skipped?: boolean | null;
|
||||||
|
/** @deprecated This is always null, the theme step has been removed since WC 7.7. */
|
||||||
theme?: string | null;
|
theme?: string | null;
|
||||||
wccom_connected?: boolean | null;
|
wccom_connected?: boolean | null;
|
||||||
is_agree_marketing?: boolean | null;
|
is_agree_marketing?: boolean | null;
|
||||||
|
|
|
@ -203,9 +203,6 @@ const completeOnboardingWizard = async () => {
|
||||||
await verifyCheckboxIsUnset( '.components-checkbox-control__input' );
|
await verifyCheckboxIsUnset( '.components-checkbox-control__input' );
|
||||||
await waitAndClickPrimary();
|
await waitAndClickPrimary();
|
||||||
|
|
||||||
// Theme section
|
|
||||||
await waitAndClickPrimary();
|
|
||||||
|
|
||||||
// End of onboarding wizard
|
// End of onboarding wizard
|
||||||
if ( IS_RETEST_MODE ) {
|
if ( IS_RETEST_MODE ) {
|
||||||
// Home screen modal can't be reset via the rest api.
|
// Home screen modal can't be reset via the rest api.
|
||||||
|
|
|
@ -147,23 +147,6 @@ export function getProductList(
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
const onboarding = getAdminSetting( 'onboarding', {} );
|
|
||||||
let theme = null;
|
|
||||||
if ( onboarding && onboarding.themes ) {
|
|
||||||
theme = onboarding.themes.find(
|
|
||||||
( themeData ) => themeData.slug === profileItems.theme
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
theme &&
|
|
||||||
theme.id &&
|
|
||||||
getPriceValue( theme.price ) > 0 &&
|
|
||||||
( includeInstalledItems || ! theme.is_installed )
|
|
||||||
) {
|
|
||||||
productList.push( theme );
|
|
||||||
}
|
|
||||||
|
|
||||||
return productList;
|
return productList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,6 @@ import Industry from './steps/industry';
|
||||||
import ProductTypes from './steps/product-types';
|
import ProductTypes from './steps/product-types';
|
||||||
import ProfileWizardHeader from './header';
|
import ProfileWizardHeader from './header';
|
||||||
import StoreDetails from './steps/store-details';
|
import StoreDetails from './steps/store-details';
|
||||||
import Theme from './steps/theme';
|
|
||||||
import { getAdminSetting } from '~/utils/admin-settings';
|
import { getAdminSetting } from '~/utils/admin-settings';
|
||||||
import './style.scss';
|
import './style.scss';
|
||||||
|
|
||||||
|
@ -160,14 +159,6 @@ class ProfileWizard extends Component {
|
||||||
profileItems.hasOwnProperty( 'product_count' ) &&
|
profileItems.hasOwnProperty( 'product_count' ) &&
|
||||||
profileItems.product_count !== null,
|
profileItems.product_count !== null,
|
||||||
} );
|
} );
|
||||||
steps.push( {
|
|
||||||
key: 'theme',
|
|
||||||
container: Theme,
|
|
||||||
label: __( 'Theme', 'woocommerce' ),
|
|
||||||
isComplete:
|
|
||||||
profileItems.hasOwnProperty( 'theme' ) &&
|
|
||||||
profileItems.theme !== null,
|
|
||||||
} );
|
|
||||||
/**
|
/**
|
||||||
* Filter for Onboarding steps configuration.
|
* Filter for Onboarding steps configuration.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,442 +0,0 @@
|
||||||
/**
|
|
||||||
* External dependencies
|
|
||||||
*/
|
|
||||||
import { __, sprintf } from '@wordpress/i18n';
|
|
||||||
import apiFetch from '@wordpress/api-fetch';
|
|
||||||
import { Component, Fragment } from '@wordpress/element';
|
|
||||||
import { compose } from '@wordpress/compose';
|
|
||||||
import { decodeEntities } from '@wordpress/html-entities';
|
|
||||||
import InfoIcon from 'gridicons/dist/info';
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
Card,
|
|
||||||
CardBody,
|
|
||||||
CardFooter,
|
|
||||||
TabPanel,
|
|
||||||
Tooltip,
|
|
||||||
} from '@wordpress/components';
|
|
||||||
import { withDispatch, withSelect } from '@wordpress/data';
|
|
||||||
import { H } from '@woocommerce/components';
|
|
||||||
import { ONBOARDING_STORE_NAME } from '@woocommerce/data';
|
|
||||||
import { recordEvent } from '@woocommerce/tracks';
|
|
||||||
import { Text } from '@woocommerce/experimental';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal dependencies
|
|
||||||
*/
|
|
||||||
import './style.scss';
|
|
||||||
import ThemeUploader from './uploader';
|
|
||||||
import ThemePreview from './preview';
|
|
||||||
import { getPriceValue } from '../../../dashboard/utils';
|
|
||||||
import { getAdminSetting, setAdminSetting } from '~/utils/admin-settings';
|
|
||||||
|
|
||||||
class Theme extends Component {
|
|
||||||
constructor() {
|
|
||||||
super( ...arguments );
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
activeTab: 'all',
|
|
||||||
chosen: null,
|
|
||||||
demo: null,
|
|
||||||
uploadedThemes: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
this.handleUploadComplete = this.handleUploadComplete.bind( this );
|
|
||||||
this.onChoose = this.onChoose.bind( this );
|
|
||||||
this.onClosePreview = this.onClosePreview.bind( this );
|
|
||||||
this.onSelectTab = this.onSelectTab.bind( this );
|
|
||||||
this.openDemo = this.openDemo.bind( this );
|
|
||||||
this.skipStep = this.skipStep.bind( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate( prevProps ) {
|
|
||||||
const { isError, isUpdatingProfileItems, createNotice } = this.props;
|
|
||||||
const { chosen } = this.state;
|
|
||||||
const isRequestSuccessful =
|
|
||||||
! isUpdatingProfileItems &&
|
|
||||||
prevProps.isUpdatingProfileItems &&
|
|
||||||
! isError &&
|
|
||||||
chosen;
|
|
||||||
const isRequestError =
|
|
||||||
! isUpdatingProfileItems && prevProps.isRequesting && isError;
|
|
||||||
|
|
||||||
if ( isRequestSuccessful ) {
|
|
||||||
/* eslint-disable react/no-did-update-set-state */
|
|
||||||
this.setState( { chosen: null } );
|
|
||||||
/* eslint-enable react/no-did-update-set-state */
|
|
||||||
this.props.goToNextStep();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( isRequestError ) {
|
|
||||||
/* eslint-disable react/no-did-update-set-state */
|
|
||||||
this.setState( { chosen: null } );
|
|
||||||
/* eslint-enable react/no-did-update-set-state */
|
|
||||||
createNotice(
|
|
||||||
'error',
|
|
||||||
__(
|
|
||||||
'There was a problem selecting your store theme',
|
|
||||||
'woocommerce'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
skipStep() {
|
|
||||||
const { activeTheme = '' } = getAdminSetting( 'onboarding', {} );
|
|
||||||
recordEvent( 'storeprofiler_store_theme_skip_step', { activeTheme } );
|
|
||||||
this.props.goToNextStep();
|
|
||||||
}
|
|
||||||
|
|
||||||
onChoose( theme, location = '' ) {
|
|
||||||
const { updateProfileItems } = this.props;
|
|
||||||
const { is_installed: isInstalled, price, slug } = theme;
|
|
||||||
const { activeTheme = '' } = getAdminSetting( 'onboarding', {} );
|
|
||||||
|
|
||||||
this.setState( { chosen: slug } );
|
|
||||||
recordEvent( 'storeprofiler_store_theme_choose', {
|
|
||||||
theme: slug,
|
|
||||||
location,
|
|
||||||
} );
|
|
||||||
|
|
||||||
if ( slug !== activeTheme && isInstalled ) {
|
|
||||||
this.activateTheme( slug );
|
|
||||||
} else if ( slug !== activeTheme && getPriceValue( price ) <= 0 ) {
|
|
||||||
this.installTheme( slug );
|
|
||||||
} else {
|
|
||||||
updateProfileItems( { theme: slug } );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
installTheme( slug ) {
|
|
||||||
const { createNotice } = this.props;
|
|
||||||
|
|
||||||
apiFetch( {
|
|
||||||
path: '/wc-admin/onboarding/themes/install?theme=' + slug,
|
|
||||||
method: 'POST',
|
|
||||||
} )
|
|
||||||
.then( () => {
|
|
||||||
this.activateTheme( slug );
|
|
||||||
} )
|
|
||||||
.catch( ( response ) => {
|
|
||||||
this.setState( { chosen: null } );
|
|
||||||
createNotice( 'error', response.message );
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
activateTheme( slug ) {
|
|
||||||
const { createNotice, updateProfileItems } = this.props;
|
|
||||||
|
|
||||||
apiFetch( {
|
|
||||||
path: '/wc-admin/onboarding/themes/activate?theme=' + slug,
|
|
||||||
method: 'POST',
|
|
||||||
} )
|
|
||||||
.then( ( response ) => {
|
|
||||||
createNotice(
|
|
||||||
'success',
|
|
||||||
sprintf(
|
|
||||||
/* translators: The name of the theme that was installed and activated */
|
|
||||||
__(
|
|
||||||
'%s was installed and activated on your site',
|
|
||||||
'woocommerce'
|
|
||||||
),
|
|
||||||
response.name
|
|
||||||
)
|
|
||||||
);
|
|
||||||
setAdminSetting( 'onboarding', {
|
|
||||||
...getAdminSetting( 'onboarding', {} ),
|
|
||||||
activeTheme: response.slug,
|
|
||||||
} );
|
|
||||||
updateProfileItems( { theme: slug } );
|
|
||||||
} )
|
|
||||||
.catch( ( response ) => {
|
|
||||||
this.setState( { chosen: null } );
|
|
||||||
createNotice( 'error', response.message );
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
onClosePreview() {
|
|
||||||
const { demo } = this.state;
|
|
||||||
recordEvent( 'storeprofiler_store_theme_demo_close', {
|
|
||||||
theme: demo.slug,
|
|
||||||
} );
|
|
||||||
document.body.classList.remove( 'woocommerce-theme-preview-active' );
|
|
||||||
this.setState( { demo: null } );
|
|
||||||
}
|
|
||||||
|
|
||||||
openDemo( theme ) {
|
|
||||||
recordEvent( 'storeprofiler_store_theme_live_demo', {
|
|
||||||
theme: theme.slug,
|
|
||||||
} );
|
|
||||||
document.body.classList.add( 'woocommerce-theme-preview-active' );
|
|
||||||
this.setState( { demo: theme } );
|
|
||||||
}
|
|
||||||
|
|
||||||
renderTheme( theme ) {
|
|
||||||
const {
|
|
||||||
demo_url: demoUrl,
|
|
||||||
has_woocommerce_support: hasSupport,
|
|
||||||
image,
|
|
||||||
slug,
|
|
||||||
title,
|
|
||||||
} = theme;
|
|
||||||
const { chosen } = this.state;
|
|
||||||
const { activeTheme = '' } = getAdminSetting( 'onboarding', {} );
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card className="woocommerce-profile-wizard__theme" key={ slug }>
|
|
||||||
<CardBody size={ null }>
|
|
||||||
{ image && (
|
|
||||||
<div
|
|
||||||
className="woocommerce-profile-wizard__theme-image"
|
|
||||||
style={ { backgroundImage: `url(${ image })` } }
|
|
||||||
role="img"
|
|
||||||
aria-label={ title }
|
|
||||||
/>
|
|
||||||
) }
|
|
||||||
</CardBody>
|
|
||||||
<CardBody className="woocommerce-profile-wizard__theme-details">
|
|
||||||
<H className="woocommerce-profile-wizard__theme-name">
|
|
||||||
{ title }
|
|
||||||
{ ! hasSupport && (
|
|
||||||
<Tooltip
|
|
||||||
text={ __(
|
|
||||||
'This theme does not support WooCommerce.',
|
|
||||||
'woocommerce'
|
|
||||||
) }
|
|
||||||
>
|
|
||||||
<span>
|
|
||||||
<InfoIcon
|
|
||||||
role="img"
|
|
||||||
aria-hidden="true"
|
|
||||||
focusable="false"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</Tooltip>
|
|
||||||
) }
|
|
||||||
</H>
|
|
||||||
<p className="woocommerce-profile-wizard__theme-status">
|
|
||||||
{ this.getThemeStatus( theme ) }
|
|
||||||
</p>
|
|
||||||
</CardBody>
|
|
||||||
<CardFooter>
|
|
||||||
{ slug === activeTheme ? (
|
|
||||||
<Button
|
|
||||||
isPrimary
|
|
||||||
onClick={ () => this.onChoose( theme, 'card' ) }
|
|
||||||
isBusy={ chosen === slug }
|
|
||||||
disabled={ chosen === slug }
|
|
||||||
>
|
|
||||||
{ __(
|
|
||||||
'Continue with my active theme',
|
|
||||||
'woocommerce'
|
|
||||||
) }
|
|
||||||
</Button>
|
|
||||||
) : (
|
|
||||||
<Button
|
|
||||||
isSecondary
|
|
||||||
onClick={ () => this.onChoose( theme, 'card' ) }
|
|
||||||
isBusy={ chosen === slug }
|
|
||||||
disabled={ chosen === slug }
|
|
||||||
>
|
|
||||||
{ __( 'Choose', 'woocommerce' ) }
|
|
||||||
</Button>
|
|
||||||
) }
|
|
||||||
{ demoUrl && (
|
|
||||||
<Button
|
|
||||||
isTertiary
|
|
||||||
onClick={ () => this.openDemo( theme ) }
|
|
||||||
>
|
|
||||||
{ __( 'Live demo', 'woocommerce' ) }
|
|
||||||
</Button>
|
|
||||||
) }
|
|
||||||
</CardFooter>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
getThemeStatus( theme ) {
|
|
||||||
const { is_installed: isInstalled, price, slug } = theme;
|
|
||||||
const { activeTheme = '' } = getAdminSetting( 'onboarding', {} );
|
|
||||||
|
|
||||||
if ( activeTheme === slug ) {
|
|
||||||
return __( 'Currently active theme', 'woocommerce' );
|
|
||||||
}
|
|
||||||
if ( isInstalled ) {
|
|
||||||
return __( 'Installed', 'woocommerce' );
|
|
||||||
} else if ( getPriceValue( price ) <= 0 ) {
|
|
||||||
return __( 'Free', 'woocommerce' );
|
|
||||||
}
|
|
||||||
|
|
||||||
return sprintf(
|
|
||||||
__( '%s per year', 'woocommerce' ),
|
|
||||||
decodeEntities( price )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
doesActiveThemeSupportWooCommerce() {
|
|
||||||
const { activeTheme = '' } = getAdminSetting( 'onboarding', {} );
|
|
||||||
const allThemes = this.getThemes();
|
|
||||||
const currentTheme = allThemes.find(
|
|
||||||
( theme ) => theme.slug === activeTheme
|
|
||||||
);
|
|
||||||
return currentTheme && currentTheme.has_woocommerce_support;
|
|
||||||
}
|
|
||||||
|
|
||||||
onSelectTab( tab ) {
|
|
||||||
recordEvent( 'storeprofiler_store_theme_navigate', {
|
|
||||||
navigation: tab,
|
|
||||||
} );
|
|
||||||
this.setState( { activeTab: tab } );
|
|
||||||
}
|
|
||||||
|
|
||||||
getPriceValue( string ) {
|
|
||||||
return Number( decodeEntities( string ).replace( /[^0-9.-]+/g, '' ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
getThemes( activeTab = 'all' ) {
|
|
||||||
const { uploadedThemes } = this.state;
|
|
||||||
const { activeTheme = '', themes = [] } = getAdminSetting(
|
|
||||||
'onboarding',
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
const allThemes = [
|
|
||||||
...themes.filter(
|
|
||||||
( theme ) =>
|
|
||||||
theme &&
|
|
||||||
( theme.has_woocommerce_support ||
|
|
||||||
theme.slug === activeTheme )
|
|
||||||
),
|
|
||||||
...uploadedThemes,
|
|
||||||
];
|
|
||||||
|
|
||||||
switch ( activeTab ) {
|
|
||||||
case 'paid':
|
|
||||||
return allThemes.filter(
|
|
||||||
( theme ) => getPriceValue( theme.price ) > 0
|
|
||||||
);
|
|
||||||
case 'free':
|
|
||||||
return allThemes.filter(
|
|
||||||
( theme ) => getPriceValue( theme.price ) <= 0
|
|
||||||
);
|
|
||||||
case 'all':
|
|
||||||
default:
|
|
||||||
return allThemes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleUploadComplete( upload ) {
|
|
||||||
if ( upload.status === 'success' && upload.theme_data ) {
|
|
||||||
this.setState( {
|
|
||||||
uploadedThemes: [
|
|
||||||
...this.state.uploadedThemes,
|
|
||||||
upload.theme_data,
|
|
||||||
],
|
|
||||||
} );
|
|
||||||
|
|
||||||
recordEvent( 'storeprofiler_store_theme_upload', {
|
|
||||||
theme: upload.theme_data.slug,
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { activeTab, chosen, demo } = this.state;
|
|
||||||
const themes = this.getThemes( activeTab );
|
|
||||||
const activeThemeSupportsWooCommerce =
|
|
||||||
this.doesActiveThemeSupportWooCommerce();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Fragment>
|
|
||||||
<div className="woocommerce-profile-wizard__step-header">
|
|
||||||
<Text
|
|
||||||
variant="title.small"
|
|
||||||
as="h2"
|
|
||||||
size="20"
|
|
||||||
lineHeight="28px"
|
|
||||||
>
|
|
||||||
{ __( 'Choose a theme', 'woocommerce' ) }
|
|
||||||
</Text>
|
|
||||||
<Text variant="body" as="p">
|
|
||||||
{ __(
|
|
||||||
"Choose how your store appears to customers. And don't worry, you can always switch themes and edit them later.",
|
|
||||||
'woocommerce'
|
|
||||||
) }
|
|
||||||
</Text>
|
|
||||||
</div>
|
|
||||||
<TabPanel
|
|
||||||
className="woocommerce-profile-wizard__themes-tab-panel"
|
|
||||||
activeClass="is-active"
|
|
||||||
onSelect={ this.onSelectTab }
|
|
||||||
tabs={ [
|
|
||||||
{
|
|
||||||
name: 'all',
|
|
||||||
title: __( 'All themes', 'woocommerce' ),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'paid',
|
|
||||||
title: __( 'Paid themes', 'woocommerce' ),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'free',
|
|
||||||
title: __( 'Free themes', 'woocommerce' ),
|
|
||||||
},
|
|
||||||
] }
|
|
||||||
>
|
|
||||||
{ () => (
|
|
||||||
<div className="woocommerce-profile-wizard__themes">
|
|
||||||
{ themes &&
|
|
||||||
themes.map( ( theme ) =>
|
|
||||||
this.renderTheme( theme )
|
|
||||||
) }
|
|
||||||
<ThemeUploader
|
|
||||||
onUploadComplete={ this.handleUploadComplete }
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
) }
|
|
||||||
</TabPanel>
|
|
||||||
{ demo && (
|
|
||||||
<ThemePreview
|
|
||||||
theme={ demo }
|
|
||||||
onChoose={ () => this.onChoose( demo, 'card' ) }
|
|
||||||
onClose={ this.onClosePreview }
|
|
||||||
isBusy={ chosen === demo.slug }
|
|
||||||
/>
|
|
||||||
) }
|
|
||||||
{ activeThemeSupportsWooCommerce && (
|
|
||||||
<p className="woocommerce-profile-wizard__themes-skip-this-step">
|
|
||||||
<Button
|
|
||||||
isLink
|
|
||||||
className="woocommerce-profile-wizard__skip"
|
|
||||||
onClick={ () => this.skipStep() }
|
|
||||||
>
|
|
||||||
{ __( 'Skip this step', 'woocommerce' ) }
|
|
||||||
</Button>
|
|
||||||
</p>
|
|
||||||
) }
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default compose(
|
|
||||||
withSelect( ( select ) => {
|
|
||||||
const { getProfileItems, getOnboardingError, isOnboardingRequesting } =
|
|
||||||
select( ONBOARDING_STORE_NAME );
|
|
||||||
|
|
||||||
return {
|
|
||||||
isError: Boolean( getOnboardingError( 'updateProfileItems' ) ),
|
|
||||||
isUpdatingProfileItems:
|
|
||||||
isOnboardingRequesting( 'updateProfileItems' ),
|
|
||||||
profileItems: getProfileItems(),
|
|
||||||
};
|
|
||||||
} ),
|
|
||||||
withDispatch( ( dispatch ) => {
|
|
||||||
const { updateProfileItems } = dispatch( ONBOARDING_STORE_NAME );
|
|
||||||
const { createNotice } = dispatch( 'core/notices' );
|
|
||||||
|
|
||||||
return {
|
|
||||||
createNotice,
|
|
||||||
updateProfileItems,
|
|
||||||
};
|
|
||||||
} )
|
|
||||||
)( Theme );
|
|
|
@ -1,124 +0,0 @@
|
||||||
/**
|
|
||||||
* External dependencies
|
|
||||||
*/
|
|
||||||
import { __, sprintf } from '@wordpress/i18n';
|
|
||||||
import { Button } from '@wordpress/components';
|
|
||||||
import classnames from 'classnames';
|
|
||||||
import { Component } from '@wordpress/element';
|
|
||||||
import interpolateComponents from '@automattic/interpolate-components';
|
|
||||||
import { WebPreview } from '@woocommerce/components';
|
|
||||||
import { recordEvent } from '@woocommerce/tracks';
|
|
||||||
import { Icon, close } from '@wordpress/icons';
|
|
||||||
import Phone from 'gridicons/dist/phone';
|
|
||||||
import Tablet from 'gridicons/dist/tablet';
|
|
||||||
import Computer from 'gridicons/dist/computer';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal dependencies
|
|
||||||
*/
|
|
||||||
|
|
||||||
const devices = [
|
|
||||||
{
|
|
||||||
key: 'mobile',
|
|
||||||
icon: Phone,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'tablet',
|
|
||||||
icon: Tablet,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'desktop',
|
|
||||||
icon: Computer,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
class ThemePreview extends Component {
|
|
||||||
constructor() {
|
|
||||||
super( ...arguments );
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
device: 'desktop',
|
|
||||||
};
|
|
||||||
|
|
||||||
this.handleDeviceClick = this.handleDeviceClick.bind( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
handleDeviceClick( device ) {
|
|
||||||
const { theme } = this.props;
|
|
||||||
recordEvent( 'storeprofiler_store_theme_demo_device', {
|
|
||||||
device,
|
|
||||||
theme: theme.slug,
|
|
||||||
} );
|
|
||||||
this.setState( { device } );
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { isBusy, onChoose, onClose, theme } = this.props;
|
|
||||||
const { demo_url: demoUrl, slug, title } = theme;
|
|
||||||
const { device: currentDevice } = this.state;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="woocommerce-theme-preview">
|
|
||||||
<div className="woocommerce-theme-preview__toolbar">
|
|
||||||
<Button
|
|
||||||
className="woocommerce-theme-preview__close"
|
|
||||||
onClick={ onClose }
|
|
||||||
>
|
|
||||||
<Icon icon={ close } />
|
|
||||||
</Button>
|
|
||||||
<div className="woocommerce-theme-preview__theme-name">
|
|
||||||
{ interpolateComponents( {
|
|
||||||
/* translators: Describing who a previewed theme is developed by. E.g., Storefront developed by WooCommerce */
|
|
||||||
mixedString: sprintf(
|
|
||||||
__(
|
|
||||||
'{{strong}}%s{{/strong}} developed by WooCommerce',
|
|
||||||
'woocommerce'
|
|
||||||
),
|
|
||||||
title
|
|
||||||
),
|
|
||||||
components: {
|
|
||||||
strong: <strong />,
|
|
||||||
},
|
|
||||||
} ) }
|
|
||||||
</div>
|
|
||||||
<div className="woocommerce-theme-preview__devices">
|
|
||||||
{ devices.map( ( device ) => {
|
|
||||||
const DeviceTag = device.icon;
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
key={ device.key }
|
|
||||||
className={ classnames(
|
|
||||||
'woocommerce-theme-preview__device',
|
|
||||||
{
|
|
||||||
'is-selected':
|
|
||||||
device.key === currentDevice,
|
|
||||||
}
|
|
||||||
) }
|
|
||||||
onClick={ () =>
|
|
||||||
this.handleDeviceClick( device.key )
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<DeviceTag />
|
|
||||||
</Button>
|
|
||||||
);
|
|
||||||
} ) }
|
|
||||||
</div>
|
|
||||||
<Button
|
|
||||||
isPrimary
|
|
||||||
onClick={ () => onChoose( slug, 'preview' ) }
|
|
||||||
isBusy={ isBusy }
|
|
||||||
>
|
|
||||||
{ __( 'Choose', 'woocommerce' ) }
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
<WebPreview
|
|
||||||
src={ demoUrl }
|
|
||||||
title={ title }
|
|
||||||
className={ `is-${ currentDevice }` }
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ThemePreview;
|
|
|
@ -1,254 +0,0 @@
|
||||||
.woocommerce-profile-wizard__body .woocommerce-profile-wizard__container {
|
|
||||||
> .woocommerce-profile-wizard__themes-tab-panel {
|
|
||||||
margin-bottom: $gap-large;
|
|
||||||
|
|
||||||
@include breakpoint( '>782px' ) {
|
|
||||||
max-width: 810px;
|
|
||||||
|
|
||||||
.woocommerce-profile-wizard__themes {
|
|
||||||
display: grid;
|
|
||||||
grid-gap: $gap-large;
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.woocommerce-profile-wizard__themes-tab-panel .components-tab-panel__tabs {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
background: $studio-white;
|
|
||||||
box-shadow: $muriel-box-shadow-1dp;
|
|
||||||
border-radius: 3px;
|
|
||||||
margin-top: $gap-large;
|
|
||||||
margin-bottom: $gap-large;
|
|
||||||
|
|
||||||
button {
|
|
||||||
border: 0;
|
|
||||||
color: $studio-gray-50;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
background: transparent;
|
|
||||||
height: 48px;
|
|
||||||
width: 100%;
|
|
||||||
@include font-size( 14 );
|
|
||||||
font-weight: 500;
|
|
||||||
outline: none;
|
|
||||||
padding: 0 $gap-large;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
p.woocommerce-profile-wizard__themes-skip-this-step {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.woocommerce-profile-wizard__body .woocommerce-profile-wizard__theme.components-card {
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
@include breakpoint( '>782px' ) {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.woocommerce-profile-wizard__theme-image {
|
|
||||||
width: 100%;
|
|
||||||
height: 300px;
|
|
||||||
background-size: cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
.woocommerce-profile-wizard__theme-name {
|
|
||||||
margin-top: auto;
|
|
||||||
margin-bottom: $gap-smaller;
|
|
||||||
@include font-size( 24 );
|
|
||||||
font-weight: 400;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
max-width: 18px;
|
|
||||||
height: 18px;
|
|
||||||
margin-left: $gap-smaller;
|
|
||||||
|
|
||||||
path {
|
|
||||||
fill: $studio-red-50;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.woocommerce-profile-wizard__theme-status {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.woocommerce-profile-wizard__theme-learn-more {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.woocommerce-profile-wizard__body .woocommerce-theme-uploader.components-card {
|
|
||||||
margin: 0;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&.is-uploading .woocommerce-theme-uploader__dropzone-wrapper {
|
|
||||||
min-height: 382px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.woocommerce-theme-uploader__dropzone-wrapper {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
border-radius: 2px;
|
|
||||||
background: #f6f6f6;
|
|
||||||
border: 1px dashed #b0b5b8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.components-form-file-upload {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.components-form-file-upload > .components-button {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
margin: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
min-height: 380px;
|
|
||||||
|
|
||||||
> .gridicon {
|
|
||||||
width: 48px;
|
|
||||||
height: 48px;
|
|
||||||
|
|
||||||
path {
|
|
||||||
fill: #50575d;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashicons-upload {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.woocommerce-theme-uploader__title {
|
|
||||||
margin: $gap-smaller 0;
|
|
||||||
@include font-size( 24 );
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
@include font-size( 14 );
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.woocommerce-theme-preview {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
max-width: 100% !important;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
.woocommerce-theme-preview__toolbar {
|
|
||||||
background: $studio-white;
|
|
||||||
flex-direction: row;
|
|
||||||
display: flex;
|
|
||||||
height: $header-height;
|
|
||||||
border-bottom: 1px solid $studio-gray-5;
|
|
||||||
padding-left: $gap;
|
|
||||||
padding-right: $gap;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.is-button.is-primary {
|
|
||||||
height: 40px;
|
|
||||||
margin: 0;
|
|
||||||
|
|
||||||
@include breakpoint( '<782px' ) {
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.woocommerce-theme-preview__theme-name {
|
|
||||||
padding-left: $gap;
|
|
||||||
color: $studio-gray-90;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
max-width: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.woocommerce-theme-preview__close {
|
|
||||||
padding: 0 $gap 0 0;
|
|
||||||
color: $studio-gray-50;
|
|
||||||
}
|
|
||||||
|
|
||||||
.woocommerce-theme-preview__devices {
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: $gap;
|
|
||||||
|
|
||||||
.woocommerce-theme-preview__device {
|
|
||||||
padding: $gap-small;
|
|
||||||
color: $studio-gray-50;
|
|
||||||
margin: 0;
|
|
||||||
border-radius: 50%;
|
|
||||||
|
|
||||||
&.is-selected,
|
|
||||||
&:focus {
|
|
||||||
background: $studio-gray-50;
|
|
||||||
color: $studio-white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@include breakpoint( '<782px' ) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.woocommerce-web-preview {
|
|
||||||
flex: 1;
|
|
||||||
padding: $gap-largest $gap;
|
|
||||||
overflow: scroll;
|
|
||||||
|
|
||||||
.woocommerce-web-preview__iframe-wrapper {
|
|
||||||
height: 100%;
|
|
||||||
border-radius: 3px;
|
|
||||||
box-shadow: $muriel-box-shadow-1dp;
|
|
||||||
overflow: hidden;
|
|
||||||
margin: 0 auto;
|
|
||||||
|
|
||||||
iframe {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.is-mobile .woocommerce-web-preview__iframe-wrapper {
|
|
||||||
max-width: 360px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.is-tablet .woocommerce-web-preview__iframe-wrapper {
|
|
||||||
max-width: 768px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.is-desktop {
|
|
||||||
width: 100%;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
.woocommerce-web-preview__iframe-wrapper {
|
|
||||||
border-radius: 0;
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.woocommerce-theme-preview-active {
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
.woocommerce-profile-wizard__header {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,161 +0,0 @@
|
||||||
/**
|
|
||||||
* External dependencies
|
|
||||||
*/
|
|
||||||
import { __ } from '@wordpress/i18n';
|
|
||||||
import apiFetch from '@wordpress/api-fetch';
|
|
||||||
import classnames from 'classnames';
|
|
||||||
import { Component, Fragment } from '@wordpress/element';
|
|
||||||
import { compose } from '@wordpress/compose';
|
|
||||||
import {
|
|
||||||
Card,
|
|
||||||
DropZoneProvider,
|
|
||||||
DropZone,
|
|
||||||
FormFileUpload,
|
|
||||||
} from '@wordpress/components';
|
|
||||||
import CloudUploadIcon from 'gridicons/dist/cloud-upload';
|
|
||||||
import { noop } from 'lodash';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { withDispatch } from '@wordpress/data';
|
|
||||||
import { H, Spinner } from '@woocommerce/components';
|
|
||||||
import { isWpVersion } from '@woocommerce/settings';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* NOTE: This can be removed after WP version 6.0 and replaced with a div.
|
|
||||||
*
|
|
||||||
* @param {Object} props React props.
|
|
||||||
* @param {Node} [props.children] Children of react component.
|
|
||||||
* @param {string} [props.className] Additional class name to style the component.
|
|
||||||
*/
|
|
||||||
const DropZoneWrapper = ( { children, className } ) => {
|
|
||||||
const isDropzoneProviderDepreciated = isWpVersion( '5.8', '>=' );
|
|
||||||
|
|
||||||
if ( isDropzoneProviderDepreciated ) {
|
|
||||||
return <div className={ className }>{ children }</div>;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<DropZoneProvider>
|
|
||||||
<div className={ className }>{ children }</div>
|
|
||||||
</DropZoneProvider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
class ThemeUploader extends Component {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
isUploading: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.handleFilesUpload = this.handleFilesUpload.bind( this );
|
|
||||||
this.handleFilesDrop = this.handleFilesDrop.bind( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
handleFilesDrop( files ) {
|
|
||||||
const file = files[ 0 ];
|
|
||||||
this.uploadTheme( file );
|
|
||||||
}
|
|
||||||
|
|
||||||
handleFilesUpload( e ) {
|
|
||||||
const file = e.target.files[ 0 ];
|
|
||||||
this.uploadTheme( file );
|
|
||||||
}
|
|
||||||
|
|
||||||
uploadTheme( file ) {
|
|
||||||
const { createNotice, onUploadComplete } = this.props;
|
|
||||||
this.setState( { isUploading: true } );
|
|
||||||
|
|
||||||
const body = new window.FormData();
|
|
||||||
body.append( 'pluginzip', file );
|
|
||||||
|
|
||||||
return apiFetch( { path: '/wc-admin/themes', method: 'POST', body } )
|
|
||||||
.then( ( response ) => {
|
|
||||||
onUploadComplete( response );
|
|
||||||
this.setState( { isUploading: false } );
|
|
||||||
createNotice( response.status, response.message );
|
|
||||||
} )
|
|
||||||
.catch( ( error ) => {
|
|
||||||
this.setState( { isUploading: false } );
|
|
||||||
if ( error && error.message ) {
|
|
||||||
createNotice( 'error', error.message );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { className } = this.props;
|
|
||||||
const { isUploading } = this.state;
|
|
||||||
|
|
||||||
const classes = classnames( 'woocommerce-theme-uploader', className, {
|
|
||||||
'is-uploading': isUploading,
|
|
||||||
} );
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card className={ classes }>
|
|
||||||
<DropZoneWrapper className="woocommerce-theme-uploader__dropzone-wrapper">
|
|
||||||
{ ! isUploading ? (
|
|
||||||
<Fragment>
|
|
||||||
<FormFileUpload
|
|
||||||
accept=".zip"
|
|
||||||
onChange={ this.handleFilesUpload }
|
|
||||||
>
|
|
||||||
<CloudUploadIcon />
|
|
||||||
<H className="woocommerce-theme-uploader__title">
|
|
||||||
{ __( 'Upload a theme', 'woocommerce' ) }
|
|
||||||
</H>
|
|
||||||
<p>
|
|
||||||
{ __(
|
|
||||||
'Drop a theme zip file here to upload',
|
|
||||||
'woocommerce'
|
|
||||||
) }
|
|
||||||
</p>
|
|
||||||
</FormFileUpload>
|
|
||||||
<DropZone
|
|
||||||
label={ __(
|
|
||||||
'Drop your theme zip file here',
|
|
||||||
'woocommerce'
|
|
||||||
) }
|
|
||||||
onFilesDrop={ this.handleFilesDrop }
|
|
||||||
/>
|
|
||||||
</Fragment>
|
|
||||||
) : (
|
|
||||||
<Fragment>
|
|
||||||
<Spinner />
|
|
||||||
<H className="woocommerce-theme-uploader__title">
|
|
||||||
{ __( 'Uploading theme', 'woocommerce' ) }
|
|
||||||
</H>
|
|
||||||
<p>
|
|
||||||
{ __(
|
|
||||||
'Your theme is being uploaded',
|
|
||||||
'woocommerce'
|
|
||||||
) }
|
|
||||||
</p>
|
|
||||||
</Fragment>
|
|
||||||
) }
|
|
||||||
</DropZoneWrapper>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ThemeUploader.propTypes = {
|
|
||||||
/**
|
|
||||||
* Additional class name to style the component.
|
|
||||||
*/
|
|
||||||
className: PropTypes.string,
|
|
||||||
/**
|
|
||||||
* Function called when an upload has finished.
|
|
||||||
*/
|
|
||||||
onUploadComplete: PropTypes.func,
|
|
||||||
};
|
|
||||||
|
|
||||||
ThemeUploader.defaultProps = {
|
|
||||||
onUploadComplete: noop,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default compose(
|
|
||||||
withDispatch( ( dispatch ) => {
|
|
||||||
const { createNotice } = dispatch( 'core/notices' );
|
|
||||||
return { createNotice };
|
|
||||||
} )
|
|
||||||
)( ThemeUploader );
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: update
|
||||||
|
|
||||||
|
Remove theme step from onboarding wizard
|
|
@ -131,18 +131,6 @@ test.describe( 'Store owner can complete onboarding wizard', () => {
|
||||||
await onboarding.unselectBusinessFeatures( page );
|
await onboarding.unselectBusinessFeatures( page );
|
||||||
await page.click( 'button >> text=Continue' );
|
await page.click( 'button >> text=Continue' );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
test( 'can complete the theme selection section', async ( { page } ) => {
|
|
||||||
await page.goto(
|
|
||||||
'wp-admin/admin.php?page=wc-admin&path=%2Fsetup-wizard&step=theme'
|
|
||||||
);
|
|
||||||
const pageHeading = await page.textContent(
|
|
||||||
'div.woocommerce-profile-wizard__step-header > h2'
|
|
||||||
);
|
|
||||||
expect( pageHeading ).toContain( 'Choose a theme' );
|
|
||||||
// Just continue with the current theme
|
|
||||||
await page.click( 'button >> text=Continue with my active theme' );
|
|
||||||
} );
|
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// !Changed from Japanese to Liberian store, as Japanese Yen does not use decimals
|
// !Changed from Japanese to Liberian store, as Japanese Yen does not use decimals
|
||||||
|
@ -216,10 +204,12 @@ test.describe(
|
||||||
page.locator( '.woocommerce-input-toggle--disabled' )
|
page.locator( '.woocommerce-input-toggle--disabled' )
|
||||||
).toHaveCount( 3 );
|
).toHaveCount( 3 );
|
||||||
// Checklist shows when completing setup wizard
|
// Checklist shows when completing setup wizard
|
||||||
await page.goto(
|
await onboarding.completeBusinessDetailsSection( page );
|
||||||
'wp-admin/admin.php?page=wc-admin&path=%2Fsetup-wizard&step=theme'
|
await page.click( 'button >> text=Continue' );
|
||||||
);
|
|
||||||
await page.click( 'button >> text=Continue with my active theme' );
|
await onboarding.unselectBusinessFeatures( page, expect_wp_pay );
|
||||||
|
await page.click( 'button >> text=Continue' );
|
||||||
|
|
||||||
// Start test
|
// Start test
|
||||||
await page.waitForLoadState( 'networkidle' );
|
await page.waitForLoadState( 'networkidle' );
|
||||||
await expect(
|
await expect(
|
||||||
|
@ -268,7 +258,6 @@ test.describe.skip( 'Store owner can go through setup Task List', () => {
|
||||||
await page.click( '.components-checkbox-control__input' );
|
await page.click( '.components-checkbox-control__input' );
|
||||||
}
|
}
|
||||||
await page.click( 'button >> text=Continue' );
|
await page.click( 'button >> text=Continue' );
|
||||||
await page.click( 'button >> text=Continue with my active theme' );
|
|
||||||
await page.waitForLoadState( 'networkidle' ); // not autowaiting for form submission
|
await page.waitForLoadState( 'networkidle' ); // not autowaiting for form submission
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue