2019-08-21 05:58:47 +00:00
|
|
|
/**
|
|
|
|
* External dependencies
|
|
|
|
*/
|
|
|
|
import { __ } from '@wordpress/i18n';
|
|
|
|
import apiFetch from '@wordpress/api-fetch';
|
|
|
|
import { Component } from '@wordpress/element';
|
|
|
|
import { compose } from '@wordpress/compose';
|
2020-01-17 01:46:11 +00:00
|
|
|
import { difference, filter } from 'lodash';
|
2019-11-12 02:44:39 +00:00
|
|
|
import interpolateComponents from 'interpolate-components';
|
2020-03-25 03:20:17 +00:00
|
|
|
import { withDispatch, withSelect } from '@wordpress/data';
|
2019-08-21 05:58:47 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* WooCommerce dependencies
|
|
|
|
*/
|
2020-04-16 23:58:36 +00:00
|
|
|
import { Card, Link, Stepper, Plugins } from '@woocommerce/components';
|
2019-12-03 23:16:17 +00:00
|
|
|
import { getAdminLink, getSetting } from '@woocommerce/wc-admin-settings';
|
2019-08-21 05:58:47 +00:00
|
|
|
import { getHistory, getNewPath } from '@woocommerce/navigation';
|
2020-04-16 23:58:36 +00:00
|
|
|
import { SETTINGS_STORE_NAME, PLUGINS_STORE_NAME } from '@woocommerce/data';
|
2019-08-21 05:58:47 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Internal dependencies
|
|
|
|
*/
|
2020-04-16 23:58:36 +00:00
|
|
|
import Connect from 'dashboard/components/connect';
|
2019-08-26 05:49:04 +00:00
|
|
|
import { getCountryCode } from 'dashboard/utils';
|
|
|
|
import StoreLocation from '../steps/location';
|
2019-08-21 05:58:47 +00:00
|
|
|
import ShippingRates from './rates';
|
2019-10-07 20:27:34 +00:00
|
|
|
import { recordEvent } from 'lib/tracks';
|
2019-08-21 05:58:47 +00:00
|
|
|
|
|
|
|
class Shipping extends Component {
|
2020-04-16 23:58:36 +00:00
|
|
|
constructor( props ) {
|
|
|
|
super( props );
|
2019-08-21 05:58:47 +00:00
|
|
|
|
|
|
|
this.initialState = {
|
|
|
|
isPending: false,
|
|
|
|
step: 'store_location',
|
|
|
|
shippingZones: [],
|
|
|
|
};
|
|
|
|
|
2020-01-17 01:46:11 +00:00
|
|
|
// Cache active plugins to prevent removal mid-step.
|
2020-04-16 23:58:36 +00:00
|
|
|
this.activePlugins = props.activePlugins;
|
2019-08-21 05:58:47 +00:00
|
|
|
this.state = this.initialState;
|
|
|
|
this.completeStep = this.completeStep.bind( this );
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
this.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
reset() {
|
|
|
|
this.setState( this.initialState );
|
|
|
|
}
|
|
|
|
|
|
|
|
async fetchShippingZones() {
|
|
|
|
this.setState( { isPending: true } );
|
|
|
|
const { countryCode, countryName } = this.props;
|
|
|
|
|
|
|
|
// @todo The following fetches for shipping information should be moved into
|
|
|
|
// the wc-api to make these methods and states more readily available.
|
|
|
|
const shippingZones = [];
|
|
|
|
const zones = await apiFetch( { path: '/wc/v3/shipping/zones' } );
|
|
|
|
let hasCountryZone = false;
|
|
|
|
|
|
|
|
await Promise.all(
|
2020-02-14 02:23:21 +00:00
|
|
|
zones.map( async ( zone ) => {
|
2019-08-21 05:58:47 +00:00
|
|
|
// "Rest of the world zone"
|
2020-02-14 02:23:21 +00:00
|
|
|
if ( zone.id === 0 ) {
|
|
|
|
zone.methods = await apiFetch( {
|
|
|
|
path: `/wc/v3/shipping/zones/${ zone.id }/methods`,
|
|
|
|
} );
|
2019-08-21 05:58:47 +00:00
|
|
|
zone.name = __( 'Rest of the world', 'woocommerce-admin' );
|
2020-03-23 15:25:02 +00:00
|
|
|
zone.toggleable = true;
|
2019-08-21 05:58:47 +00:00
|
|
|
shippingZones.push( zone );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return any zone with a single location matching the country zone.
|
2020-02-14 02:23:21 +00:00
|
|
|
zone.locations = await apiFetch( {
|
|
|
|
path: `/wc/v3/shipping/zones/${ zone.id }/locations`,
|
|
|
|
} );
|
|
|
|
const countryLocation = zone.locations.find(
|
|
|
|
( location ) => countryCode === location.code
|
|
|
|
);
|
2019-08-21 05:58:47 +00:00
|
|
|
if ( countryLocation ) {
|
2020-02-14 02:23:21 +00:00
|
|
|
zone.methods = await apiFetch( {
|
|
|
|
path: `/wc/v3/shipping/zones/${ zone.id }/methods`,
|
|
|
|
} );
|
2019-08-21 05:58:47 +00:00
|
|
|
shippingZones.push( zone );
|
|
|
|
hasCountryZone = true;
|
|
|
|
}
|
|
|
|
} )
|
|
|
|
);
|
|
|
|
|
|
|
|
// Create the default store country zone if it doesn't exist.
|
|
|
|
if ( ! hasCountryZone ) {
|
|
|
|
const zone = await apiFetch( {
|
|
|
|
method: 'POST',
|
|
|
|
path: '/wc/v3/shipping/zones',
|
|
|
|
data: { name: countryName },
|
|
|
|
} );
|
|
|
|
zone.locations = await apiFetch( {
|
|
|
|
method: 'POST',
|
|
|
|
path: `/wc/v3/shipping/zones/${ zone.id }/locations`,
|
|
|
|
data: [ { code: countryCode, type: 'country' } ],
|
|
|
|
} );
|
|
|
|
shippingZones.push( zone );
|
|
|
|
}
|
|
|
|
|
|
|
|
shippingZones.reverse();
|
|
|
|
|
|
|
|
this.setState( { isPending: false, shippingZones } );
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidUpdate( prevProps, prevState ) {
|
2020-06-14 23:20:52 +00:00
|
|
|
const { countryCode, settings } = this.props;
|
|
|
|
const {
|
|
|
|
woocommerce_store_address: storeAddress,
|
|
|
|
woocommerce_default_country: defaultCountry,
|
|
|
|
woocommerce_store_postcode: storePostCode,
|
|
|
|
} = settings;
|
2019-08-21 05:58:47 +00:00
|
|
|
const { step } = this.state;
|
|
|
|
|
|
|
|
if (
|
2020-02-14 02:23:21 +00:00
|
|
|
step === 'rates' &&
|
|
|
|
( prevProps.countryCode !== countryCode ||
|
|
|
|
prevState.step !== 'rates' )
|
2019-08-21 05:58:47 +00:00
|
|
|
) {
|
|
|
|
this.fetchShippingZones();
|
|
|
|
}
|
2020-06-14 23:20:52 +00:00
|
|
|
|
|
|
|
const isCompleteAddress = Boolean(
|
|
|
|
storeAddress && defaultCountry && storePostCode
|
|
|
|
);
|
|
|
|
|
|
|
|
if ( step === 'store_location' && isCompleteAddress ) {
|
|
|
|
this.completeStep();
|
|
|
|
}
|
2019-08-21 05:58:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
completeStep() {
|
2020-01-06 15:27:09 +00:00
|
|
|
const { createNotice } = this.props;
|
2019-08-21 05:58:47 +00:00
|
|
|
const { step } = this.state;
|
|
|
|
const steps = this.getSteps();
|
2020-02-14 02:23:21 +00:00
|
|
|
const currentStepIndex = steps.findIndex( ( s ) => s.key === step );
|
2019-08-21 05:58:47 +00:00
|
|
|
const nextStep = steps[ currentStepIndex + 1 ];
|
|
|
|
|
|
|
|
if ( nextStep ) {
|
|
|
|
this.setState( { step: nextStep.key } );
|
|
|
|
} else {
|
2020-01-06 15:27:09 +00:00
|
|
|
createNotice(
|
|
|
|
'success',
|
|
|
|
__(
|
|
|
|
"📦 Shipping is done! Don't worry, you can always change it later.",
|
|
|
|
'woocommerce-admin'
|
|
|
|
)
|
|
|
|
);
|
2019-08-21 05:58:47 +00:00
|
|
|
getHistory().push( getNewPath( {}, '/', {} ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-17 01:46:11 +00:00
|
|
|
getPluginsToActivate() {
|
2020-05-20 09:43:09 +00:00
|
|
|
const { countryCode } = this.props;
|
2020-01-17 01:46:11 +00:00
|
|
|
|
|
|
|
const plugins = [];
|
2019-12-10 19:54:51 +00:00
|
|
|
if ( [ 'GB', 'CA', 'AU' ].includes( countryCode ) ) {
|
2020-01-17 01:46:11 +00:00
|
|
|
plugins.push( 'woocommerce-shipstation-integration' );
|
2020-02-14 02:23:21 +00:00
|
|
|
} else if ( countryCode === 'US' ) {
|
2020-01-17 01:46:11 +00:00
|
|
|
plugins.push( 'woocommerce-services' );
|
2020-05-20 09:43:09 +00:00
|
|
|
plugins.push( 'jetpack' );
|
2019-12-10 19:54:51 +00:00
|
|
|
}
|
2020-01-17 01:46:11 +00:00
|
|
|
return difference( plugins, this.activePlugins );
|
|
|
|
}
|
|
|
|
|
|
|
|
getSteps() {
|
2020-05-20 09:43:09 +00:00
|
|
|
const { countryCode, isJetpackConnected } = this.props;
|
2020-01-17 01:46:11 +00:00
|
|
|
const pluginsToActivate = this.getPluginsToActivate();
|
2020-05-20 09:43:09 +00:00
|
|
|
const requiresJetpackConnection =
|
|
|
|
! isJetpackConnected && countryCode === 'US';
|
2019-08-21 06:34:21 +00:00
|
|
|
|
2019-08-21 05:58:47 +00:00
|
|
|
const steps = [
|
|
|
|
{
|
|
|
|
key: 'store_location',
|
|
|
|
label: __( 'Set store location', 'woocommerce-admin' ),
|
2020-02-14 02:23:21 +00:00
|
|
|
description: __(
|
|
|
|
'The address from which your business operates',
|
|
|
|
'woocommerce-admin'
|
|
|
|
),
|
2019-10-07 20:27:34 +00:00
|
|
|
content: (
|
|
|
|
<StoreLocation
|
2020-04-21 00:12:38 +00:00
|
|
|
{ ...this.props }
|
2020-02-14 02:23:21 +00:00
|
|
|
onComplete={ ( values ) => {
|
|
|
|
const country = getCountryCode(
|
|
|
|
values.countryState
|
|
|
|
);
|
|
|
|
recordEvent( 'tasklist_shipping_set_location', {
|
|
|
|
country,
|
|
|
|
} );
|
2019-10-07 20:27:34 +00:00
|
|
|
this.completeStep();
|
|
|
|
} }
|
|
|
|
/>
|
|
|
|
),
|
2019-08-21 05:58:47 +00:00
|
|
|
visible: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
key: 'rates',
|
|
|
|
label: __( 'Set shipping costs', 'woocommerce-admin' ),
|
|
|
|
description: __(
|
|
|
|
'Define how much customers pay to ship to different destinations',
|
|
|
|
'woocommerce-admin'
|
|
|
|
),
|
|
|
|
content: (
|
|
|
|
<ShippingRates
|
2019-12-10 19:54:51 +00:00
|
|
|
buttonText={
|
2020-05-20 09:43:09 +00:00
|
|
|
pluginsToActivate.length ||
|
|
|
|
requiresJetpackConnection
|
2019-12-10 19:54:51 +00:00
|
|
|
? __( 'Proceed', 'woocommerce-admin' )
|
|
|
|
: __( 'Complete task', 'woocommerce-admin' )
|
|
|
|
}
|
2019-08-21 05:58:47 +00:00
|
|
|
shippingZones={ this.state.shippingZones }
|
2019-08-26 05:49:04 +00:00
|
|
|
onComplete={ this.completeStep }
|
2019-08-21 05:58:47 +00:00
|
|
|
{ ...this.props }
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
visible: true,
|
|
|
|
},
|
2019-08-21 06:34:21 +00:00
|
|
|
{
|
|
|
|
key: 'label_printing',
|
2020-02-14 02:23:21 +00:00
|
|
|
label: __(
|
|
|
|
'Enable shipping label printing',
|
|
|
|
'woocommerce-admin'
|
|
|
|
),
|
|
|
|
description: pluginsToActivate.includes(
|
|
|
|
'woocommerce-shipstation-integration'
|
|
|
|
)
|
2019-11-12 02:44:39 +00:00
|
|
|
? interpolateComponents( {
|
|
|
|
mixedString: __(
|
|
|
|
'We recommend using ShipStation to save time at the post office by printing your shipping ' +
|
|
|
|
'labels at home. Try ShipStation free for 30 days. {{link}}Learn more{{/link}}.',
|
|
|
|
'woocommerce-admin'
|
|
|
|
),
|
|
|
|
components: {
|
|
|
|
link: (
|
|
|
|
<Link
|
2019-11-12 18:23:52 +00:00
|
|
|
href="https://woocommerce.com/products/shipstation-integration"
|
2019-11-12 02:44:39 +00:00
|
|
|
target="_blank"
|
|
|
|
type="external"
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
},
|
2020-02-14 02:23:21 +00:00
|
|
|
} )
|
2019-11-12 02:44:39 +00:00
|
|
|
: __(
|
|
|
|
'With WooCommerce Services and Jetpack you can save time at the ' +
|
|
|
|
'Post Office by printing your shipping labels at home',
|
|
|
|
'woocommerce-admin'
|
2020-02-14 02:23:21 +00:00
|
|
|
),
|
2019-08-26 05:49:04 +00:00
|
|
|
content: (
|
|
|
|
<Plugins
|
2019-10-07 20:27:34 +00:00
|
|
|
onComplete={ () => {
|
2020-01-17 01:46:11 +00:00
|
|
|
recordEvent( 'tasklist_shipping_label_printing', {
|
|
|
|
install: true,
|
|
|
|
pluginsToActivate,
|
|
|
|
} );
|
2019-10-07 20:27:34 +00:00
|
|
|
this.completeStep();
|
|
|
|
} }
|
|
|
|
onSkip={ () => {
|
2020-01-17 01:46:11 +00:00
|
|
|
recordEvent( 'tasklist_shipping_label_printing', {
|
|
|
|
install: false,
|
|
|
|
pluginsToActivate,
|
|
|
|
} );
|
2019-10-07 20:27:34 +00:00
|
|
|
getHistory().push( getNewPath( {}, '/', {} ) );
|
|
|
|
} }
|
2020-01-17 01:46:11 +00:00
|
|
|
pluginSlugs={ pluginsToActivate }
|
2019-08-26 05:49:04 +00:00
|
|
|
{ ...this.props }
|
|
|
|
/>
|
|
|
|
),
|
2020-01-17 01:46:11 +00:00
|
|
|
visible: pluginsToActivate.length,
|
2019-08-21 06:34:21 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
key: 'connect',
|
|
|
|
label: __( 'Connect your store', 'woocommerce-admin' ),
|
|
|
|
description: __(
|
|
|
|
'Connect your store to WordPress.com to enable label printing',
|
|
|
|
'woocommerce-admin'
|
|
|
|
),
|
2019-10-07 20:27:34 +00:00
|
|
|
content: (
|
|
|
|
<Connect
|
2020-02-14 02:23:21 +00:00
|
|
|
redirectUrl={ getAdminLink(
|
|
|
|
'admin.php?page=wc-admin'
|
|
|
|
) }
|
2019-10-07 20:27:34 +00:00
|
|
|
completeStep={ this.completeStep }
|
|
|
|
{ ...this.props }
|
|
|
|
onConnect={ () => {
|
|
|
|
recordEvent( 'tasklist_shipping_connect_store' );
|
|
|
|
} }
|
|
|
|
/>
|
|
|
|
),
|
2020-05-20 09:43:09 +00:00
|
|
|
visible: requiresJetpackConnection,
|
2019-08-21 06:34:21 +00:00
|
|
|
},
|
2019-08-21 05:58:47 +00:00
|
|
|
];
|
|
|
|
|
2020-02-14 02:23:21 +00:00
|
|
|
return filter( steps, ( step ) => step.visible );
|
2019-08-21 05:58:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
|
|
|
const { isPending, step } = this.state;
|
|
|
|
const { isSettingsRequesting } = this.props;
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div className="woocommerce-task-shipping">
|
|
|
|
<Card className="is-narrow">
|
|
|
|
<Stepper
|
|
|
|
isPending={ isPending || isSettingsRequesting }
|
|
|
|
isVertical
|
|
|
|
currentStep={ step }
|
|
|
|
steps={ this.getSteps() }
|
|
|
|
/>
|
|
|
|
</Card>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default compose(
|
2020-04-16 23:58:36 +00:00
|
|
|
withSelect( ( select ) => {
|
|
|
|
const {
|
|
|
|
getSettings,
|
|
|
|
getSettingsError,
|
|
|
|
isGetSettingsRequesting,
|
|
|
|
} = select( SETTINGS_STORE_NAME );
|
|
|
|
const { getActivePlugins, isJetpackConnected } = select(
|
|
|
|
PLUGINS_STORE_NAME
|
2020-03-25 03:20:17 +00:00
|
|
|
);
|
2019-08-21 05:58:47 +00:00
|
|
|
|
2020-03-25 03:20:17 +00:00
|
|
|
const { general: settings = {} } = getSettings( 'general' );
|
2019-08-21 05:58:47 +00:00
|
|
|
const isSettingsError = Boolean( getSettingsError( 'general' ) );
|
|
|
|
const isSettingsRequesting = isGetSettingsRequesting( 'general' );
|
|
|
|
|
2020-02-14 02:23:21 +00:00
|
|
|
const countryCode = getCountryCode(
|
|
|
|
settings.woocommerce_default_country
|
|
|
|
);
|
2019-08-26 05:49:04 +00:00
|
|
|
|
2019-10-07 11:51:25 +00:00
|
|
|
const { countries = [] } = getSetting( 'dataEndpoints', {} );
|
2020-02-14 02:23:21 +00:00
|
|
|
const country = countryCode
|
|
|
|
? countries.find( ( c ) => c.code === countryCode )
|
|
|
|
: null;
|
2019-08-21 05:58:47 +00:00
|
|
|
const countryName = country ? country.name : null;
|
2020-04-16 23:58:36 +00:00
|
|
|
const activePlugins = getActivePlugins();
|
2019-08-21 05:58:47 +00:00
|
|
|
|
2019-12-27 09:16:39 +00:00
|
|
|
return {
|
|
|
|
countryCode,
|
|
|
|
countryName,
|
|
|
|
isSettingsError,
|
|
|
|
isSettingsRequesting,
|
|
|
|
settings,
|
2020-04-16 23:58:36 +00:00
|
|
|
activePlugins,
|
|
|
|
isJetpackConnected: isJetpackConnected(),
|
2019-12-27 09:16:39 +00:00
|
|
|
};
|
2019-08-21 05:58:47 +00:00
|
|
|
} ),
|
2020-02-14 02:23:21 +00:00
|
|
|
withDispatch( ( dispatch ) => {
|
2019-08-21 05:58:47 +00:00
|
|
|
const { createNotice } = dispatch( 'core/notices' );
|
2020-04-21 00:12:38 +00:00
|
|
|
const { updateAndPersistSettingsForGroup } = dispatch(
|
|
|
|
SETTINGS_STORE_NAME
|
|
|
|
);
|
2019-08-21 05:58:47 +00:00
|
|
|
|
|
|
|
return {
|
|
|
|
createNotice,
|
2020-04-21 00:12:38 +00:00
|
|
|
updateAndPersistSettingsForGroup,
|
2019-08-21 05:58:47 +00:00
|
|
|
};
|
|
|
|
} )
|
|
|
|
)( Shipping );
|