Update shipping partner suggestions to use data from API (#38457)
* Added shipping partner suggestions data handling in JS
* Add woocommerce services real info
* Add dynamic layout components, remove unused JS, added images to proper asset paths
* Changelog
* Update changelog and removed unused variable
* Remove console.log
* Lint fix
* Add shipping methods module in woocommerce/data
* Update data usage
* Revert "Added shipping partner suggestions data handling in JS"
This reverts commit 6a87ef2658
.
* Lint fix
This commit is contained in:
parent
ab18828e84
commit
edf95bf3f4
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: add
|
||||
|
||||
Update shipping partner suggestions to use data from API, fix default partners data, replaced hardcoded JS components and added relevant types
|
|
@ -16,6 +16,7 @@ export { NAVIGATION_STORE_NAME } from './navigation';
|
|||
export { OPTIONS_STORE_NAME } from './options';
|
||||
export { ITEMS_STORE_NAME } from './items';
|
||||
export { PAYMENT_GATEWAYS_STORE_NAME } from './payment-gateways';
|
||||
export { SHIPPING_METHODS_STORE_NAME } from './shipping-methods';
|
||||
export { PRODUCTS_STORE_NAME } from './products';
|
||||
export { ORDERS_STORE_NAME } from './orders';
|
||||
export { EXPERIMENTAL_PRODUCT_ATTRIBUTES_STORE_NAME } from './product-attributes';
|
||||
|
@ -28,6 +29,7 @@ export { EXPERIMENTAL_PRODUCT_VARIATIONS_STORE_NAME } from './product-variations
|
|||
export { EXPERIMENTAL_PRODUCT_FORM_STORE_NAME } from './product-form';
|
||||
export { EXPERIMENTAL_TAX_CLASSES_STORE_NAME } from './tax-classes';
|
||||
export { PaymentGateway } from './payment-gateways/types';
|
||||
export { ShippingMethod } from './shipping-methods/types';
|
||||
|
||||
// Export hooks
|
||||
export { withSettingsHydration } from './settings/with-settings-hydration';
|
||||
|
@ -121,6 +123,7 @@ import type { REPORTS_STORE_NAME } from './reports';
|
|||
import type { ITEMS_STORE_NAME } from './items';
|
||||
import type { COUNTRIES_STORE_NAME } from './countries';
|
||||
import type { PAYMENT_GATEWAYS_STORE_NAME } from './payment-gateways';
|
||||
import type { SHIPPING_METHODS_STORE_NAME } from './shipping-methods';
|
||||
import type { PRODUCTS_STORE_NAME } from './products';
|
||||
import type { ORDERS_STORE_NAME } from './orders';
|
||||
import type { EXPERIMENTAL_PRODUCT_ATTRIBUTES_STORE_NAME } from './product-attributes';
|
||||
|
@ -146,6 +149,7 @@ export type WCDataStoreName =
|
|||
| typeof ITEMS_STORE_NAME
|
||||
| typeof COUNTRIES_STORE_NAME
|
||||
| typeof PAYMENT_GATEWAYS_STORE_NAME
|
||||
| typeof SHIPPING_METHODS_STORE_NAME
|
||||
| typeof PRODUCTS_STORE_NAME
|
||||
| typeof ORDERS_STORE_NAME
|
||||
| typeof EXPERIMENTAL_PRODUCT_ATTRIBUTES_STORE_NAME
|
||||
|
@ -163,6 +167,7 @@ export type WCDataStoreName =
|
|||
*/
|
||||
import { WPDataSelectors } from './types';
|
||||
import { PaymentSelectors } from './payment-gateways/selectors';
|
||||
import { ShippingMethodsSelectors } from './shipping-methods/selectors';
|
||||
import { PluginSelectors } from './plugins/selectors';
|
||||
import { OnboardingSelectors } from './onboarding/selectors';
|
||||
import { OptionsSelectors } from './options/types';
|
||||
|
@ -190,6 +195,8 @@ export type WCSelectorType< T > = T extends typeof REVIEWS_STORE_NAME
|
|||
? OnboardingSelectors
|
||||
: T extends typeof PAYMENT_GATEWAYS_STORE_NAME
|
||||
? PaymentSelectors
|
||||
: T extends typeof SHIPPING_METHODS_STORE_NAME
|
||||
? ShippingMethodsSelectors
|
||||
: T extends typeof USER_STORE_NAME
|
||||
? WPDataSelectors
|
||||
: T extends typeof OPTIONS_STORE_NAME
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
export enum ACTION_TYPES {
|
||||
GET_SHIPPING_METHODS_REQUEST = 'GET_SHIPPING_METHODS_REQUEST',
|
||||
GET_SHIPPING_METHODS_SUCCESS = 'GET_SHIPPING_METHODS_SUCCESS',
|
||||
GET_SHIPPING_METHODS_ERROR = 'GET_SHIPPING_METHODS_ERROR',
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { ACTION_TYPES } from './action-types';
|
||||
import { ShippingMethod } from './types';
|
||||
|
||||
export function getShippingMethodsRequest() {
|
||||
return {
|
||||
type: ACTION_TYPES.GET_SHIPPING_METHODS_REQUEST as const,
|
||||
};
|
||||
}
|
||||
|
||||
export function getShippingMethodsSuccess( shippingMethods: ShippingMethod[] ) {
|
||||
return {
|
||||
type: ACTION_TYPES.GET_SHIPPING_METHODS_SUCCESS as const,
|
||||
shippingMethods,
|
||||
};
|
||||
}
|
||||
|
||||
export function getShippingMethodsError( error: unknown ) {
|
||||
return {
|
||||
type: ACTION_TYPES.GET_SHIPPING_METHODS_ERROR as const,
|
||||
error,
|
||||
};
|
||||
}
|
||||
|
||||
export type Actions =
|
||||
| ReturnType< typeof getShippingMethodsRequest >
|
||||
| ReturnType< typeof getShippingMethodsSuccess >
|
||||
| ReturnType< typeof getShippingMethodsError >;
|
|
@ -0,0 +1 @@
|
|||
export const STORE_KEY = 'wc/shipping-methods';
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { createReduxStore, register } from '@wordpress/data';
|
||||
import { controls } from '@wordpress/data-controls';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import * as actions from './actions';
|
||||
import * as resolvers from './resolvers';
|
||||
import * as selectors from './selectors';
|
||||
import reducer from './reducer';
|
||||
import { STORE_KEY } from './constants';
|
||||
export const SHIPPING_METHODS_STORE_NAME = STORE_KEY;
|
||||
|
||||
export const store = createReduxStore( SHIPPING_METHODS_STORE_NAME, {
|
||||
reducer,
|
||||
selectors,
|
||||
resolvers,
|
||||
controls,
|
||||
actions,
|
||||
} );
|
||||
|
||||
register( store );
|
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { Reducer } from 'redux';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { ACTION_TYPES } from './action-types';
|
||||
import { ShippingMethod } from './types';
|
||||
import { Actions } from './actions';
|
||||
|
||||
export type ShippingMethodsState = {
|
||||
shippingMethods: ShippingMethod[];
|
||||
isUpdating: boolean;
|
||||
errors: Record< string, unknown >;
|
||||
};
|
||||
|
||||
const reducer: Reducer< ShippingMethodsState, Actions > = (
|
||||
state = {
|
||||
shippingMethods: [],
|
||||
isUpdating: false,
|
||||
errors: {},
|
||||
},
|
||||
payload
|
||||
) => {
|
||||
if ( payload && 'type' in payload ) {
|
||||
switch ( payload.type ) {
|
||||
case ACTION_TYPES.GET_SHIPPING_METHODS_REQUEST:
|
||||
return {
|
||||
...state,
|
||||
isUpdating: true,
|
||||
};
|
||||
case ACTION_TYPES.GET_SHIPPING_METHODS_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
shippingMethods: payload.shippingMethods,
|
||||
isUpdating: false,
|
||||
};
|
||||
case ACTION_TYPES.GET_SHIPPING_METHODS_ERROR:
|
||||
return {
|
||||
...state,
|
||||
isUpdating: false,
|
||||
errors: {
|
||||
...state.errors,
|
||||
getShippingMethods: payload.error,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
export default reducer;
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { apiFetch } from '@wordpress/data-controls';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import {
|
||||
getShippingMethodsSuccess,
|
||||
getShippingMethodsRequest,
|
||||
getShippingMethodsError,
|
||||
} from './actions';
|
||||
import { ShippingMethod } from './types';
|
||||
import { WC_ADMIN_NAMESPACE } from '../constants';
|
||||
|
||||
export function* getShippingMethods( forceDefaultSuggestions = false ) {
|
||||
let path = WC_ADMIN_NAMESPACE + '/shipping-partner-suggestions';
|
||||
if ( forceDefaultSuggestions ) {
|
||||
path += '?force_default_suggestions=true';
|
||||
}
|
||||
yield getShippingMethodsRequest();
|
||||
try {
|
||||
const results: ShippingMethod[] = yield apiFetch( {
|
||||
path,
|
||||
method: 'GET',
|
||||
} );
|
||||
|
||||
yield getShippingMethodsSuccess( results );
|
||||
} catch ( error ) {
|
||||
yield getShippingMethodsError( error );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { ShippingMethodsState } from './reducer';
|
||||
import { ShippingMethod } from './types';
|
||||
import { WPDataSelector, WPDataSelectors } from '../types';
|
||||
|
||||
export const getShippingMethods = (
|
||||
state: ShippingMethodsState
|
||||
): ShippingMethod[] => {
|
||||
return state.shippingMethods || [];
|
||||
};
|
||||
|
||||
export function isShippingMethodsUpdating(
|
||||
state: ShippingMethodsState
|
||||
): boolean {
|
||||
return state.isUpdating || false;
|
||||
}
|
||||
export type ShippingMethodsSelectors = {
|
||||
getShippingMethods: WPDataSelector< typeof getShippingMethods >;
|
||||
} & WPDataSelectors;
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { ShippingMethod } from '../types';
|
||||
|
||||
export const shippingMethodsStub: ShippingMethod[] = [
|
||||
{
|
||||
name: 'Dummy shipping method',
|
||||
slug: 'dummy-shipping-method',
|
||||
description: 'Dummy shipping method description',
|
||||
learn_more_link: 'https://example.com',
|
||||
is_visible: true,
|
||||
available_layouts: [ 'row' ],
|
||||
layout_row: {
|
||||
image: 'https://example.com/image.png',
|
||||
features: [
|
||||
{
|
||||
icon: 'https://example.com/icon.png',
|
||||
title: 'Feature title',
|
||||
description: 'Feature description',
|
||||
},
|
||||
{
|
||||
icon: 'https://example.com/icon.png',
|
||||
title: 'Feature title 2',
|
||||
description: 'Feature description 2',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Dummy shipping method 2',
|
||||
slug: 'dummy-shipping-method-2',
|
||||
description: 'Dummy shipping method description',
|
||||
learn_more_link: 'https://example.com',
|
||||
is_visible: true,
|
||||
available_layouts: [ 'column' ],
|
||||
layout_column: {
|
||||
image: 'https://example.com/image.png',
|
||||
features: [
|
||||
{
|
||||
icon: 'https://example.com/icon.png',
|
||||
title: 'Feature title',
|
||||
description: 'Feature description',
|
||||
},
|
||||
],
|
||||
},
|
||||
dependencies: [ 'jetpack' ],
|
||||
},
|
||||
];
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* @jest-environment node
|
||||
*/
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import reducer, { ShippingMethodsState } from '../reducer';
|
||||
import { ACTION_TYPES } from '../action-types';
|
||||
import { shippingMethodsStub } from '../test-helpers/stub';
|
||||
import { Actions } from '../actions';
|
||||
|
||||
const defaultState: ShippingMethodsState = {
|
||||
shippingMethods: [],
|
||||
isUpdating: false,
|
||||
errors: {},
|
||||
};
|
||||
|
||||
const restApiError = {
|
||||
code: 'error code',
|
||||
message: 'error message',
|
||||
};
|
||||
|
||||
describe( 'Shipping methods reducer', () => {
|
||||
it( 'should return a default state', () => {
|
||||
const state = reducer( undefined, {} as Actions );
|
||||
expect( state ).toEqual( defaultState );
|
||||
expect( state ).not.toBe( defaultState );
|
||||
} );
|
||||
|
||||
it( 'should handle GET_SHIPPING_METHODS_REQUEST', () => {
|
||||
const state = reducer( defaultState, {
|
||||
type: ACTION_TYPES.GET_SHIPPING_METHODS_REQUEST,
|
||||
} );
|
||||
|
||||
expect( state.isUpdating ).toBe( true );
|
||||
} );
|
||||
|
||||
it( 'should handle GET_SHIPPING_METHODS_ERROR', () => {
|
||||
const state = reducer( defaultState, {
|
||||
type: ACTION_TYPES.GET_SHIPPING_METHODS_ERROR,
|
||||
error: restApiError,
|
||||
} );
|
||||
|
||||
expect( state.errors.getShippingMethods ).toBe( restApiError );
|
||||
} );
|
||||
|
||||
it( 'should handle GET_SHIPPING_METHODS_SUCCESS', () => {
|
||||
const state = reducer( defaultState, {
|
||||
type: ACTION_TYPES.GET_SHIPPING_METHODS_SUCCESS,
|
||||
shippingMethods: shippingMethodsStub,
|
||||
} );
|
||||
|
||||
expect( state.shippingMethods ).toHaveLength( 2 );
|
||||
expect( state.shippingMethods ).toBe( shippingMethodsStub );
|
||||
} );
|
||||
} );
|
|
@ -0,0 +1,25 @@
|
|||
// Types to describe shipping method object.
|
||||
type Feature = {
|
||||
icon: string;
|
||||
title?: string;
|
||||
description: string;
|
||||
};
|
||||
|
||||
type Layout = {
|
||||
image: string;
|
||||
features: Feature[];
|
||||
};
|
||||
|
||||
type LayoutType = 'row' | 'column';
|
||||
|
||||
export type ShippingMethod = {
|
||||
name: string;
|
||||
slug: string;
|
||||
description: string;
|
||||
learn_more_link: string;
|
||||
is_visible: boolean;
|
||||
available_layouts: LayoutType[];
|
||||
layout_column?: Layout;
|
||||
layout_row?: Layout;
|
||||
dependencies?: string[];
|
||||
};
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
.plugins-install__plugin-banner-image {
|
||||
display: flex;
|
||||
width: 150px;
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
|
|
|
@ -17,6 +17,7 @@ import {
|
|||
ONBOARDING_STORE_NAME,
|
||||
PLUGINS_STORE_NAME,
|
||||
COUNTRIES_STORE_NAME,
|
||||
SHIPPING_METHODS_STORE_NAME,
|
||||
} from '@woocommerce/data';
|
||||
import { recordEvent } from '@woocommerce/tracks';
|
||||
import { registerPlugin } from '@wordpress/plugins';
|
||||
|
@ -31,9 +32,12 @@ import Connect from '../../../dashboard/components/connect';
|
|||
import { getCountryCode } from '../../../dashboard/utils';
|
||||
import StoreLocation from '../steps/location';
|
||||
import ShippingRates from './rates';
|
||||
import { getShippingProviders } from './shipping-providers/shipping-providers';
|
||||
import { createNoticesFromResponse } from '../../../lib/notices';
|
||||
import './shipping.scss';
|
||||
import {
|
||||
ShippingLayoutColumn,
|
||||
ShippingLayoutRow,
|
||||
} from './shipping-providers/partners';
|
||||
|
||||
export class Shipping extends Component {
|
||||
constructor( props ) {
|
||||
|
@ -55,6 +59,7 @@ export class Shipping extends Component {
|
|||
window.wcAdminFeatures[ 'shipping-smart-defaults' ];
|
||||
|
||||
this.storeLocationCompleted = false;
|
||||
this.shippingPartners = props.shippingPartners;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
@ -194,8 +199,10 @@ export class Shipping extends Component {
|
|||
settings,
|
||||
task,
|
||||
updateAndPersistSettingsForGroup,
|
||||
shippingPartners,
|
||||
} = this.props;
|
||||
const pluginsToPromote = getShippingProviders( this.props.countryCode );
|
||||
const pluginsToPromote = shippingPartners;
|
||||
|
||||
const pluginsToActivate = pluginsToPromote.map( ( pluginToPromote ) => {
|
||||
return pluginToPromote.slug;
|
||||
} );
|
||||
|
@ -426,7 +433,7 @@ export class Shipping extends Component {
|
|||
pluginsToPromote.length === 1
|
||||
? getSinglePluginDescription(
|
||||
pluginsToPromote[ 0 ].name,
|
||||
pluginsToPromote[ 0 ].url
|
||||
pluginsToPromote[ 0 ].learn_more_link
|
||||
)
|
||||
: __(
|
||||
'Save time and money by printing your shipping labels right from your computer with one of these shipping solutions.',
|
||||
|
@ -436,24 +443,28 @@ export class Shipping extends Component {
|
|||
content: (
|
||||
<>
|
||||
{ pluginsToPromote.length === 1 ? (
|
||||
pluginsToPromote[ 0 ][
|
||||
'single-partner-layout'
|
||||
]()
|
||||
<ShippingLayoutColumn
|
||||
shippingMethod={ pluginsToPromote[ 0 ] }
|
||||
/>
|
||||
) : (
|
||||
<div className="woocommerce-task-shipping-recommendation_plugins-install-container">
|
||||
{ pluginsToPromote.map(
|
||||
( pluginToPromote ) => {
|
||||
( shippingMethod ) => {
|
||||
const pluginsForPartner = [
|
||||
pluginToPromote?.slug,
|
||||
pluginToPromote?.dependencies,
|
||||
shippingMethod?.slug,
|
||||
...( shippingMethod?.dependencies ??
|
||||
[] ),
|
||||
].filter(
|
||||
( element ) =>
|
||||
element !== undefined
|
||||
); // remove undefineds
|
||||
return pluginToPromote[
|
||||
'dual-partner-layout'
|
||||
]( {
|
||||
children: (
|
||||
return (
|
||||
<ShippingLayoutRow
|
||||
shippingMethod={
|
||||
shippingMethod
|
||||
}
|
||||
key={ shippingMethod.name }
|
||||
>
|
||||
<div className="woocommerce-task-shipping-recommendations_plugins-buttons">
|
||||
<Plugins
|
||||
onComplete={ (
|
||||
|
@ -486,13 +497,13 @@ export class Shipping extends Component {
|
|||
'woocommerce'
|
||||
) }
|
||||
learnMoreLink={
|
||||
pluginToPromote.url
|
||||
shippingMethod.learn_more_link
|
||||
}
|
||||
onLearnMore={ () => {
|
||||
recordEvent(
|
||||
'tasklist_shipping_label_printing_learn_more',
|
||||
{
|
||||
plugin: pluginToPromote.slug,
|
||||
plugin: shippingMethod.slug,
|
||||
}
|
||||
);
|
||||
} }
|
||||
|
@ -504,8 +515,8 @@ export class Shipping extends Component {
|
|||
}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
} );
|
||||
</ShippingLayoutRow>
|
||||
);
|
||||
}
|
||||
) }
|
||||
</div>
|
||||
|
@ -513,7 +524,10 @@ export class Shipping extends Component {
|
|||
{ pluginsToPromote.length === 1 &&
|
||||
pluginsToPromote[ 0 ].slug === undefined && ( // if it doesn't have a slug we just show a download button
|
||||
<a
|
||||
href={ pluginsToPromote[ 0 ].url }
|
||||
href={
|
||||
pluginsToPromote[ 0 ]
|
||||
.learn_more_link
|
||||
}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
|
@ -665,6 +679,10 @@ const ShippingWrapper = compose(
|
|||
settings.woocommerce_default_country
|
||||
);
|
||||
|
||||
const shippingPartners = select(
|
||||
SHIPPING_METHODS_STORE_NAME
|
||||
).getShippingMethods( true );
|
||||
|
||||
const country = countryCode ? getCountry( countryCode ) : null;
|
||||
const countryName = country ? country.name : null;
|
||||
const activePlugins = getActivePlugins();
|
||||
|
@ -676,6 +694,7 @@ const ShippingWrapper = compose(
|
|||
settings,
|
||||
activePlugins,
|
||||
isJetpackConnected: isJetpackConnected(),
|
||||
shippingPartners,
|
||||
};
|
||||
} ),
|
||||
withDispatch( ( dispatch ) => {
|
||||
|
|
|
@ -1,232 +1,56 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import { ShippingMethod } from '@woocommerce/data';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { WCSBanner } from '../../experimental-shipping-recommendation/components/wcs-banner';
|
||||
import { SinglePartnerFeatures } from '../single-partner-features';
|
||||
import { PluginBanner } from '../../experimental-shipping-recommendation/components/plugin-banner';
|
||||
import ShipStationImage from './assets/shipstation.svg';
|
||||
import SendcloudImage from './assets/sendcloud-banner-side.svg';
|
||||
import PacklinkImage from './assets/packlink-banner-side.svg';
|
||||
import EnviaImage from './assets/envia-banner-side.svg';
|
||||
import SkydropxImage from './assets/skydropx-banner-side.svg';
|
||||
import CheckIcon from './assets/check.svg';
|
||||
import SendCloudColumnImage from './assets/sendcloud-column-logo.svg';
|
||||
import PacklinkColumnImage from './assets/packlink-column-logo.svg';
|
||||
import ShipStationColumnImage from './assets/shipstation-column-logo.svg';
|
||||
|
||||
/**
|
||||
* Banner layout for Envia
|
||||
* Renders a column layout for the shipping method. Used for rendering a single shipping partner.
|
||||
*
|
||||
* @param {Object} props Component props
|
||||
* @param {Object} props.shippingMethod Shipping method object
|
||||
* @return {JSX.Element} React node
|
||||
*/
|
||||
export const EnviaSinglePartner = () => {
|
||||
export const ShippingLayoutColumn = ( {
|
||||
shippingMethod,
|
||||
}: {
|
||||
shippingMethod: ShippingMethod;
|
||||
} ) => {
|
||||
return (
|
||||
<PluginBanner
|
||||
features={ SinglePartnerFeatures }
|
||||
logo={ { image: EnviaImage } }
|
||||
features={ shippingMethod.layout_column?.features || [] }
|
||||
logo={ { image: shippingMethod.layout_column?.image || '' } }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Banner layout for Envia
|
||||
* Renders a row layout for the shipping method. Used for rendering two shipping partners side by side.
|
||||
*
|
||||
* @param {Object} props Component props
|
||||
* @param {Object} props.shippingMethod Shipping method object
|
||||
* @param {Array} props.children Children to render inside the layout
|
||||
* @return {JSX.Element} React node
|
||||
*/
|
||||
export const SkydropxSinglePartner = () => {
|
||||
return (
|
||||
<PluginBanner
|
||||
features={ SinglePartnerFeatures }
|
||||
logo={ { image: SkydropxImage } }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Banner layout for Sendcloud
|
||||
*/
|
||||
export const SendcloudSinglePartner = () => {
|
||||
return (
|
||||
<PluginBanner
|
||||
features={ SinglePartnerFeatures }
|
||||
logo={ { image: SendcloudImage } }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Narrow Column Layout for Sendcloud
|
||||
*/
|
||||
export const SendcloudDualPartner = ( {
|
||||
export const ShippingLayoutRow = ( {
|
||||
shippingMethod,
|
||||
children,
|
||||
}: {
|
||||
shippingMethod: ShippingMethod;
|
||||
children: React.ReactNode;
|
||||
} ) => {
|
||||
const features = [
|
||||
{
|
||||
icon: CheckIcon,
|
||||
description: __( 'Print labels from 80+ carriers', 'woocommerce' ),
|
||||
},
|
||||
{
|
||||
icon: CheckIcon,
|
||||
description: __(
|
||||
'Process orders in just a few clicks',
|
||||
'woocommerce'
|
||||
),
|
||||
},
|
||||
{
|
||||
icon: CheckIcon,
|
||||
description: __( 'Customize checkout options', 'woocommerce' ),
|
||||
},
|
||||
{
|
||||
icon: CheckIcon,
|
||||
description: __( 'Self-service tracking & returns', 'woocommerce' ),
|
||||
},
|
||||
{
|
||||
icon: CheckIcon,
|
||||
description: __( 'Start with a free plan', 'woocommerce' ),
|
||||
},
|
||||
];
|
||||
return (
|
||||
<PluginBanner
|
||||
layout="dual"
|
||||
features={ features }
|
||||
description={ __( 'All-in-one shipping tool:', 'woocommerce' ) }
|
||||
logo={ { image: SendCloudColumnImage } }
|
||||
features={ shippingMethod.layout_row?.features || [] }
|
||||
logo={ { image: shippingMethod.layout_row?.image || '' } }
|
||||
description={ shippingMethod.description }
|
||||
>
|
||||
{ children }
|
||||
</PluginBanner>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Banner layout for Packlink
|
||||
*/
|
||||
export const PacklinkSinglePartner = () => {
|
||||
return (
|
||||
<PluginBanner
|
||||
features={ SinglePartnerFeatures }
|
||||
logo={ { image: PacklinkImage } }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Narrow Column Layout for Packlink
|
||||
*/
|
||||
export const PacklinkDualPartner = ( {
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
} ) => {
|
||||
const features = [
|
||||
{
|
||||
icon: CheckIcon,
|
||||
description: __(
|
||||
'Automated, real-time order import',
|
||||
'woocommerce'
|
||||
),
|
||||
},
|
||||
{
|
||||
icon: CheckIcon,
|
||||
description: __(
|
||||
'Direct access to leading carriers',
|
||||
'woocommerce'
|
||||
),
|
||||
},
|
||||
{
|
||||
icon: CheckIcon,
|
||||
description: __(
|
||||
'Access competitive shipping prices',
|
||||
'woocommerce'
|
||||
),
|
||||
},
|
||||
{
|
||||
icon: CheckIcon,
|
||||
description: __( 'Quickly bulk print labels', 'woocommerce' ),
|
||||
},
|
||||
{
|
||||
icon: CheckIcon,
|
||||
description: __( 'Free shipping platform', 'woocommerce' ),
|
||||
},
|
||||
];
|
||||
return (
|
||||
<PluginBanner
|
||||
layout="dual"
|
||||
features={ features }
|
||||
logo={ { image: PacklinkColumnImage } }
|
||||
description={ __(
|
||||
'Optimize your full shipping process:',
|
||||
'woocommerce'
|
||||
) }
|
||||
>
|
||||
{ children }
|
||||
</PluginBanner>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Banner layout for ShipStation
|
||||
*/
|
||||
export const ShipStationSinglePartner = () => {
|
||||
return (
|
||||
<PluginBanner
|
||||
features={ SinglePartnerFeatures }
|
||||
logo={ { image: ShipStationImage } }
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Narrow Column Layout for ShipStation
|
||||
*/
|
||||
export const ShipStationDualPartner = ( {
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
} ) => {
|
||||
const features = [
|
||||
{
|
||||
icon: CheckIcon,
|
||||
description: __(
|
||||
'Print labels from Royal Mail, Parcel Force, DPD, and many more',
|
||||
'woocommerce'
|
||||
),
|
||||
},
|
||||
{
|
||||
icon: CheckIcon,
|
||||
description: __(
|
||||
'Shop for the best rates, in real-time',
|
||||
'woocommerce'
|
||||
),
|
||||
},
|
||||
{
|
||||
icon: CheckIcon,
|
||||
description: __( 'Connect selling channels easily', 'woocommerce' ),
|
||||
},
|
||||
{
|
||||
icon: CheckIcon,
|
||||
description: __( 'Advance automated workflows', 'woocommerce' ),
|
||||
},
|
||||
{
|
||||
icon: CheckIcon,
|
||||
description: __( '30-days free trial', 'woocommerce' ),
|
||||
},
|
||||
];
|
||||
return (
|
||||
<PluginBanner
|
||||
layout="dual"
|
||||
features={ features }
|
||||
logo={ { image: ShipStationColumnImage } }
|
||||
description={ __(
|
||||
'Powerful yet easy-to-use solution:',
|
||||
'woocommerce'
|
||||
) }
|
||||
>
|
||||
{ children }
|
||||
</PluginBanner>
|
||||
);
|
||||
};
|
||||
|
||||
export const WooCommerceShippingSinglePartner = () => {
|
||||
return <WCSBanner />;
|
||||
};
|
||||
|
|
|
@ -1,142 +0,0 @@
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import {
|
||||
EnviaSinglePartner,
|
||||
SkydropxSinglePartner,
|
||||
SendcloudSinglePartner,
|
||||
PacklinkSinglePartner,
|
||||
ShipStationSinglePartner,
|
||||
PacklinkDualPartner,
|
||||
SendcloudDualPartner,
|
||||
ShipStationDualPartner,
|
||||
WooCommerceShippingSinglePartner,
|
||||
} from './partners';
|
||||
|
||||
// Order is respected, left to right in the UI
|
||||
const shippingProviders = {
|
||||
AU: {
|
||||
shipping_providers: [ 'ShipStation' ] as const,
|
||||
},
|
||||
MX: {
|
||||
// using name instead of directly referencing the component because we want to send this over the API in the near future
|
||||
shipping_providers: [ 'Skydropx' ] as const,
|
||||
},
|
||||
CA: {
|
||||
shipping_providers: [ 'ShipStation' ] as const,
|
||||
},
|
||||
CO: {
|
||||
shipping_providers: [ 'Skydropx' ] as const,
|
||||
},
|
||||
CL: {
|
||||
shipping_providers: [ 'Envia' ] as const,
|
||||
},
|
||||
AR: {
|
||||
shipping_providers: [ 'Envia' ] as const,
|
||||
},
|
||||
PE: {
|
||||
shipping_providers: [ 'Envia' ] as const,
|
||||
},
|
||||
BR: {
|
||||
shipping_providers: [ 'Envia' ] as const,
|
||||
},
|
||||
UY: {
|
||||
shipping_providers: [ 'Envia' ] as const,
|
||||
},
|
||||
GT: {
|
||||
shipping_providers: [ 'Envia' ] as const,
|
||||
},
|
||||
NL: {
|
||||
shipping_providers: [ 'Sendcloud' ] as const,
|
||||
},
|
||||
AT: {
|
||||
shipping_providers: [ 'Sendcloud' ] as const,
|
||||
},
|
||||
BE: {
|
||||
shipping_providers: [ 'Sendcloud' ] as const,
|
||||
},
|
||||
FR: {
|
||||
shipping_providers: [ 'Sendcloud', 'Packlink' ] as const,
|
||||
},
|
||||
DE: {
|
||||
shipping_providers: [ 'Sendcloud', 'Packlink' ] as const,
|
||||
},
|
||||
ES: {
|
||||
shipping_providers: [ 'Packlink', 'Sendcloud' ] as const,
|
||||
},
|
||||
IT: {
|
||||
shipping_providers: [ 'Packlink', 'Sendcloud' ] as const,
|
||||
},
|
||||
GB: {
|
||||
shipping_providers: [ 'Sendcloud', 'ShipStation' ] as const,
|
||||
},
|
||||
US: {
|
||||
shipping_providers: [ 'WooCommerceShipping' ] as const,
|
||||
},
|
||||
};
|
||||
|
||||
const providers = {
|
||||
Envia: {
|
||||
name: 'Envia' as const,
|
||||
url: 'https://woocommerce.com/products/envia-shipping-and-fulfillment/', // no plugin yet so we link to the product page
|
||||
'single-partner-layout': EnviaSinglePartner,
|
||||
},
|
||||
Skydropx: {
|
||||
name: 'Skydropx' as const,
|
||||
slug: 'skydropx-cotizador-y-envios', // https://wordpress.org/plugins/skydropx-cotizador-y-envios/
|
||||
url: 'https://wordpress.org/plugins/skydropx-cotizador-y-envios/',
|
||||
'single-partner-layout': SkydropxSinglePartner,
|
||||
},
|
||||
Sendcloud: {
|
||||
name: 'Sendcloud' as const,
|
||||
slug: 'sendcloud-shipping', // https://wordpress.org/plugins/sendcloud-shipping/
|
||||
url: 'https://wordpress.org/plugins/sendcloud-shipping/',
|
||||
'single-partner-layout': SendcloudSinglePartner,
|
||||
'dual-partner-layout': SendcloudDualPartner,
|
||||
},
|
||||
Packlink: {
|
||||
name: 'Packlink' as const,
|
||||
slug: 'packlink-pro-shipping', // https://wordpress.org/plugins/packlink-pro-shipping/
|
||||
url: 'https://wordpress.org/plugins/packlink-pro-shipping/',
|
||||
'single-partner-layout': PacklinkSinglePartner,
|
||||
'dual-partner-layout': PacklinkDualPartner,
|
||||
},
|
||||
ShipStation: {
|
||||
name: 'ShipStation' as const,
|
||||
slug: 'woocommerce-shipstation-integration', // https://wordpress.org/plugins/woocommerce-shipstation-integration/
|
||||
url: 'https://wordpress.org/plugins/woocommerce-shipstation-integration/',
|
||||
'single-partner-layout': ShipStationSinglePartner,
|
||||
'dual-partner-layout': ShipStationDualPartner,
|
||||
},
|
||||
WooCommerceShipping: {
|
||||
name: 'WooCommerce Shipping' as const,
|
||||
slug: 'woocommerce-services', // https://wordpress.org/plugins/woocommerce-services/
|
||||
url: 'https://woocommerce.com/products/shipping',
|
||||
dependencies: 'jetpack',
|
||||
'single-partner-layout': WooCommerceShippingSinglePartner,
|
||||
},
|
||||
} as const;
|
||||
|
||||
/**
|
||||
* Gets the components for the shipping providers for a given country
|
||||
*
|
||||
* @param countryCode One of the countries above
|
||||
* @return Either a single partner component or an array containing two partner components
|
||||
*/
|
||||
export const getShippingProviders = (
|
||||
countryCode: keyof typeof shippingProviders
|
||||
) => {
|
||||
const countryProviders =
|
||||
shippingProviders[ countryCode ]?.shipping_providers;
|
||||
|
||||
if ( ! countryProviders ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return countryProviders.length === 1
|
||||
? [ providers[ countryProviders[ 0 ] ] ]
|
||||
: [
|
||||
providers[ countryProviders[ 0 ] ],
|
||||
providers[ countryProviders[ 1 ] ],
|
||||
];
|
||||
};
|
|
@ -0,0 +1,10 @@
|
|||
<svg width="29" height="28" viewBox="0 0 29 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="0.645508" width="28" height="28" rx="4" fill="#F6F7F7"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M19.9787 8.66671V16.6667L15.9787 20.6667H10.6453C9.90868 20.6667 9.31201 20.07 9.31201 19.3334V8.66671C9.31201 7.93004 9.90868 7.33337 10.6453 7.33337H18.6453C19.382 7.33337 19.9787 7.93004 19.9787 8.66671ZM11.9787 11.3334H17.312V10H11.9787V11.3334ZM11.9787 12.6667H17.312V14H11.9787V12.6667ZM18.6453 8.66671V15.3334H15.9787C15.242 15.3334 14.6453 15.93 14.6453 16.6667V19.3334H10.6453V8.66671H18.6453Z" fill="black"/>
|
||||
<mask id="mask0_887_116920" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="9" y="7" width="11" height="14">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M19.9787 8.66671V16.6667L15.9787 20.6667H10.6453C9.90868 20.6667 9.31201 20.07 9.31201 19.3334V8.66671C9.31201 7.93004 9.90868 7.33337 10.6453 7.33337H18.6453C19.382 7.33337 19.9787 7.93004 19.9787 8.66671ZM11.9787 11.3334H17.312V10H11.9787V11.3334ZM11.9787 12.6667H17.312V14H11.9787V12.6667ZM18.6453 8.66671V15.3334H15.9787C15.242 15.3334 14.6453 15.93 14.6453 16.6667V19.3334H10.6453V8.66671H18.6453Z" fill="white"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_887_116920)">
|
||||
<rect x="6.64551" y="6" width="16" height="16" fill="#8C8F94"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
|
@ -0,0 +1,9 @@
|
|||
<svg width="29" height="28" viewBox="0 0 29 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="0.645508" width="28" height="28" rx="4" fill="#F6F7F7"/>
|
||||
<mask id="mask0_887_116914" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="7" y="8" width="15" height="13">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M21.3123 17.3333H19.3123V19.3333C19.3123 20.07 18.7157 20.6667 17.979 20.6667H11.3123C10.5757 20.6667 9.979 20.07 9.979 19.3333V17.3333H7.979V12C7.979 11.2633 8.57567 10.6667 9.31234 10.6667H9.979V9.33333C9.979 8.59667 10.5757 8 11.3123 8H17.979C18.7157 8 19.3123 8.59667 19.3123 9.33333V10.6667H19.979C20.7157 10.6667 21.3123 11.2633 21.3123 12V17.3333ZM12.6457 16.6667H16.6457V18H12.6457V16.6667ZM17.979 10.6667H11.3123V9.33333H17.979V10.6667ZM17.979 15.3333H11.3123V19.3333H17.979V15.3333ZM18.979 12C19.531 12 19.979 12.448 19.979 13C19.979 13.552 19.531 14 18.979 14C18.427 14 17.979 13.552 17.979 13C17.979 12.448 18.427 12 18.979 12Z" fill="white"/>
|
||||
</mask>
|
||||
<g mask="url(#mask0_887_116914)">
|
||||
<rect x="6.64551" y="6" width="16" height="16" fill="#8C8F94"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: update
|
||||
|
||||
Fix DefaultShippingPartners data mismatch
|
|
@ -124,7 +124,7 @@ class PaymentGatewaySuggestions extends \WC_REST_Data_Controller {
|
|||
$schema = array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'title' => 'payment-gateway-suggestions',
|
||||
'type' => 'array',
|
||||
'type' => 'object',
|
||||
'properties' => array(
|
||||
'content' => array(
|
||||
'description' => __( 'Suggestion description.', 'woocommerce' ),
|
||||
|
|
|
@ -209,12 +209,29 @@ class DefaultShippingPartners {
|
|||
'available_layouts' => array( 'row', 'column' ),
|
||||
),
|
||||
array(
|
||||
'title' => 'WooCommerce Shipping',
|
||||
'name' => 'WooCommerce Shipping',
|
||||
'slug' => 'woocommerce-services',
|
||||
'description' => __( 'Save time and money by printing your shipping labels right from your computer with WooCommerce Shipping. Try WooCommerce Shipping for free.', 'woocommerce' ),
|
||||
'dependencies' => array( 'jetpack' ),
|
||||
'layout_column' => array(
|
||||
'image' => $asset_base_url . 'wcs-column.svg',
|
||||
'features' => $column_layout_features,
|
||||
'features' => array(
|
||||
array(
|
||||
'icon' => $asset_base_url . 'printer.svg',
|
||||
'title' => __( 'Buy postage when you need it', 'woocommerce' ),
|
||||
'description' => __( 'No need to wonder where that stampbook went.', 'woocommerce' ),
|
||||
),
|
||||
array(
|
||||
'icon' => $asset_base_url . 'paper.svg',
|
||||
'title' => __( 'Print at home', 'woocommerce' ),
|
||||
'description' => __( 'Pick up an order, then just pay, print, package and post.', 'woocommerce' ),
|
||||
),
|
||||
array(
|
||||
'icon' => $asset_base_url . 'discount.svg',
|
||||
'title' => __( 'Discounted rates', 'woocommerce' ),
|
||||
'description' => __( 'Access discounted shipping rates with DHL and USPS.', 'woocommerce' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
'learn_more_link' => 'https://woocommerce.com/products/shipping/',
|
||||
'is_visible' => array(
|
||||
|
|
Loading…
Reference in New Issue