2020-03-27 20:42:58 +00:00
/ * *
* External dependencies
* /
import { _ _ } from '@wordpress/i18n' ;
import { Component } from '@wordpress/element' ;
import { Button , ExternalLink } from '@wordpress/components' ;
import { compose } from '@wordpress/compose' ;
import interpolateComponents from 'interpolate-components' ;
import PropTypes from 'prop-types' ;
import { get , isArray } from 'lodash' ;
2020-04-16 23:58:36 +00:00
import { PLUGINS _STORE _NAME } from '@woocommerce/data' ;
2020-09-03 21:45:40 +00:00
import { withDispatch , withSelect } from '@wordpress/data' ;
2020-08-20 04:59:52 +00:00
import { recordEvent } from '@woocommerce/tracks' ;
2020-04-16 23:58:36 +00:00
2020-03-27 20:42:58 +00:00
/ * *
* Internal dependencies
* /
import '../style.scss' ;
import DismissModal from '../dismiss-modal' ;
import SetupNotice , { setupErrorTypes } from '../setup-notice' ;
import { getWcsAssets , acceptWcsTos } from '../wcs-api' ;
2022-01-06 12:53:30 +00:00
import { getAdminSetting } from '~/utils/admin-settings' ;
2020-03-27 20:42:58 +00:00
2022-01-06 12:53:30 +00:00
const wcAdminAssetUrl = getAdminSetting ( 'wcAdminAssetUrl' , '' ) ;
2020-04-16 23:58:36 +00:00
const wcsPluginSlug = 'woocommerce-services' ;
2020-03-27 20:42:58 +00:00
export class ShippingBanner extends Component {
constructor ( props ) {
super ( props ) ;
const orderId = new URL ( window . location . href ) . searchParams . get (
'post'
) ;
this . state = {
showShippingBanner : true ,
isDismissModalOpen : false ,
setupErrorReason : setupErrorTypes . SETUP ,
orderId : parseInt ( orderId , 10 ) ,
wcsAssetsLoaded : false ,
wcsAssetsLoading : false ,
wcsSetupError : false ,
isShippingLabelButtonBusy : false ,
installText : this . getInstallText ( ) ,
isWcsModalOpen : false ,
} ;
}
componentDidMount ( ) {
const { showShippingBanner } = this . state ;
if ( showShippingBanner ) {
this . trackImpression ( ) ;
}
}
2020-04-16 23:58:36 +00:00
isSetupError = ( ) => this . state . wcsSetupError ;
2020-03-27 20:42:58 +00:00
closeDismissModal = ( ) => {
this . setState ( { isDismissModalOpen : false } ) ;
this . trackElementClicked (
'shipping_banner_dismiss_modal_close_button'
) ;
} ;
openDismissModal = ( ) => {
this . setState ( { isDismissModalOpen : true } ) ;
this . trackElementClicked ( 'shipping_banner_dimiss' ) ;
} ;
hideBanner = ( ) => {
this . setState ( { showShippingBanner : false } ) ;
} ;
createShippingLabelClicked = ( ) => {
2020-04-16 23:58:36 +00:00
const { activePlugins } = this . props ;
2020-03-27 20:42:58 +00:00
this . setState ( { isShippingLabelButtonBusy : true } ) ;
this . trackElementClicked ( 'shipping_banner_create_label' ) ;
if ( ! activePlugins . includes ( wcsPluginSlug ) ) {
this . installAndActivatePlugins ( wcsPluginSlug ) ;
} else {
this . acceptTosAndGetWCSAssets ( ) ;
}
} ;
2020-04-16 23:58:36 +00:00
async installAndActivatePlugins ( pluginSlug ) {
2020-03-27 20:42:58 +00:00
// Avoid double activating.
2020-08-31 15:13:14 +00:00
const { installPlugins , activatePlugins , isRequesting } = this . props ;
2020-03-27 20:42:58 +00:00
if ( isRequesting ) {
return false ;
}
2020-08-31 15:13:14 +00:00
const install = await installPlugins ( [ pluginSlug ] ) ;
if ( install . success !== true ) {
2020-04-16 23:58:36 +00:00
this . setState ( {
setupErrorReason : setupErrorTypes . INSTALL ,
wcsSetupError : true ,
} ) ;
return ;
}
const activation = await activatePlugins ( [ pluginSlug ] ) ;
2020-08-31 15:13:14 +00:00
if ( activation . success !== true ) {
2020-04-16 23:58:36 +00:00
this . setState ( {
setupErrorReason : setupErrorTypes . ACTIVATE ,
wcsSetupError : true ,
} ) ;
return ;
}
this . acceptTosAndGetWCSAssets ( ) ;
2020-03-27 20:42:58 +00:00
}
woocommerceServiceLinkClicked = ( ) => {
this . trackElementClicked ( 'shipping_banner_woocommerce_service_link' ) ;
} ;
trackBannerEvent = ( eventName , customProps = { } ) => {
2020-04-16 23:58:36 +00:00
const { activePlugins , isJetpackConnected } = this . props ;
2020-03-27 20:42:58 +00:00
recordEvent ( eventName , {
banner _name : 'wcadmin_install_wcs_prompt' ,
jetpack _installed : activePlugins . includes ( 'jetpack' ) ,
jetpack _connected : isJetpackConnected ,
wcs _installed : activePlugins . includes ( wcsPluginSlug ) ,
... customProps ,
} ) ;
} ;
trackImpression = ( ) => {
this . trackBannerEvent ( 'banner_impression' ) ;
} ;
trackElementClicked = ( element ) => {
this . trackBannerEvent ( 'banner_element_clicked' , {
element ,
} ) ;
} ;
acceptTosAndGetWCSAssets ( ) {
return acceptWcsTos ( )
. then ( ( ) => getWcsAssets ( ) )
. then ( ( wcsAssets ) => this . loadWcsAssets ( wcsAssets ) )
. catch ( ( ) => this . setState ( { wcsSetupError : true } ) ) ;
}
generateMetaBoxHtml ( nodeId , title , args ) {
const argsJsonString = JSON . stringify ( args ) . replace ( /"/g , '"' ) ; // JS has no native html_entities so we just replace.
const togglePanelText = _ _ ( 'Toggle panel:' , 'woocommerce-admin' ) ;
return `
< div id = "${ nodeId }" class = "postbox" >
2020-08-31 15:13:14 +00:00
< div class = "postbox-header" >
< h2 class = "hndle" > < span > $ { title } < / s p a n > < / h 2 >
< div class = "handle-actions" >
< button type = "button" class = "handlediv" aria - expanded = "true" >
< span class = "screen-reader-text" > $ { togglePanelText } $ { title } < / s p a n >
< span class = "toggle-indicator" aria - hidden = "true" > < / s p a n >
< / b u t t o n >
< / d i v >
< / d i v >
2020-03-27 20:42:58 +00:00
< div class = "inside" >
< div class = "wcc-root woocommerce wc-connect-create-shipping-label" data - args = "${ argsJsonString }" >
< / d i v >
< / d i v >
< / d i v >
` ;
}
loadWcsAssets ( { assets } ) {
if ( this . state . wcsAssetsLoaded || this . state . wcsAssetsLoading ) {
this . openWcsModal ( ) ;
return ;
}
this . setState ( { wcsAssetsLoading : true } ) ;
2020-08-31 15:13:14 +00:00
const jsPath = assets . wc _connect _admin _script ;
const stylePath = assets . wc _connect _admin _style ;
if ( undefined === window . wcsPluginData ) {
const assetPath = jsPath . substring (
0 ,
jsPath . lastIndexOf ( '/' ) + 1
) ;
window . wcsPluginData = { assetPath } ;
}
2020-03-27 20:42:58 +00:00
const { orderId } = this . state ;
const { itemsCount } = this . props ;
const shippingLabelContainerHtml = this . generateMetaBoxHtml (
'woocommerce-order-label' ,
_ _ ( 'Shipping Label' , 'woocommerce-admin' ) ,
{
2020-08-31 15:13:14 +00:00
order : { id : orderId } ,
2020-03-27 20:42:58 +00:00
context : 'shipping_label' ,
items : itemsCount ,
}
) ;
// Insert shipping label metabox just above main order details box.
document
. getElementById ( 'woocommerce-order-data' )
. insertAdjacentHTML ( 'beforebegin' , shippingLabelContainerHtml ) ;
const shipmentTrackingHtml = this . generateMetaBoxHtml (
'woocommerce-order-shipment-tracking' ,
_ _ ( 'Shipment Tracking' , 'woocommerce-admin' ) ,
{
2020-08-31 15:13:14 +00:00
order : { id : orderId } ,
2020-03-27 20:42:58 +00:00
context : 'shipment_tracking' ,
items : itemsCount ,
}
) ;
// Insert tracking metabox in the side after the order actions.
document
. getElementById ( 'woocommerce-order-actions' )
. insertAdjacentHTML ( 'afterend' , shipmentTrackingHtml ) ;
if ( window . jQuery ) {
// Need to refresh so the new metaboxes are sortable.
window . jQuery ( '#normal-sortables' ) . sortable ( 'refresh' ) ;
window . jQuery ( '#side-sortables' ) . sortable ( 'refresh' ) ;
window . jQuery ( '#woocommerce-order-label' ) . hide ( ) ;
}
Promise . all ( [
new Promise ( ( resolve , reject ) => {
const script = document . createElement ( 'script' ) ;
2020-08-31 15:13:14 +00:00
script . src = jsPath ;
2020-03-27 20:42:58 +00:00
script . async = true ;
script . onload = resolve ;
script . onerror = reject ;
document . body . appendChild ( script ) ;
} ) ,
new Promise ( ( resolve , reject ) => {
2020-08-31 15:13:14 +00:00
if ( stylePath !== '' ) {
const head = document . getElementsByTagName ( 'head' ) [ 0 ] ;
const link = document . createElement ( 'link' ) ;
link . rel = 'stylesheet' ;
link . type = 'text/css' ;
link . href = stylePath ;
link . media = 'all' ;
link . onload = resolve ;
link . onerror = reject ;
head . appendChild ( link ) ;
} else {
resolve ( ) ;
}
2020-03-27 20:42:58 +00:00
} ) ,
] ) . then ( ( ) => {
this . setState ( {
wcsAssetsLoaded : true ,
wcsAssetsLoading : false ,
isShippingLabelButtonBusy : false ,
} ) ;
this . openWcsModal ( ) ;
} ) ;
}
getInstallText = ( ) => {
2020-04-16 23:58:36 +00:00
const { activePlugins } = this . props ;
2020-03-27 20:42:58 +00:00
if ( activePlugins . includes ( wcsPluginSlug ) ) {
// If WCS is active, then the only remaining step is to agree to the ToS.
return _ _ (
'You\'ve already installed WooCommerce Shipping. By clicking "Create shipping label", you agree to its {{tosLink}}Terms of Service{{/tosLink}}.' ,
'woocommerce-admin'
) ;
}
return _ _ (
'By clicking "Create shipping label", {{wcsLink}}WooCommerce Shipping{{/wcsLink}} will be installed and you agree to its {{tosLink}}Terms of Service{{/tosLink}}.' ,
'woocommerce-admin'
) ;
} ;
openWcsModal ( ) {
2020-08-31 15:13:14 +00:00
if ( window . wcsGetAppStoreAsync ) {
window
. wcsGetAppStoreAsync ( 'wc-connect-create-shipping-label' )
. then ( ( wcsStore ) => {
const state = wcsStore . getState ( ) ;
const { orderId } = this . state ;
const siteId = state . ui . selectedSiteId ;
const wcsStoreUnsubscribe = wcsStore . subscribe ( ( ) => {
const latestState = wcsStore . getState ( ) ;
const shippingLabelState = get (
latestState ,
[
'extensions' ,
'woocommerce' ,
'woocommerceServices' ,
siteId ,
'shippingLabel' ,
orderId ,
] ,
null
) ;
const labelSettingsState = get (
latestState ,
[
'extensions' ,
'woocommerce' ,
'woocommerceServices' ,
siteId ,
'labelSettings' ,
] ,
null
) ;
const packageState = get (
latestState ,
[
'extensions' ,
'woocommerce' ,
'woocommerceServices' ,
siteId ,
'packages' ,
] ,
null
) ;
const locationsState = get ( latestState , [
'extensions' ,
'woocommerce' ,
'sites' ,
siteId ,
'data' ,
'locations' ,
] ) ;
if (
shippingLabelState &&
labelSettingsState &&
labelSettingsState . meta &&
packageState &&
locationsState
) {
if (
shippingLabelState . loaded &&
labelSettingsState . meta . isLoaded &&
packageState . isLoaded &&
isArray ( locationsState ) &&
! this . state . isWcsModalOpen
) {
if ( window . jQuery ) {
this . setState ( { isWcsModalOpen : true } ) ;
window
. jQuery (
'.shipping-label__new-label-button'
)
. click ( ) ;
}
wcsStore . dispatch ( {
type : 'NOTICE_CREATE' ,
notice : {
duration : 10000 ,
status : 'is-success' ,
text : _ _ (
'Plugin installed and activated' ,
'woocommerce-admin'
) ,
} ,
} ) ;
} else if (
shippingLabelState . showPurchaseDialog
) {
wcsStoreUnsubscribe ( ) ;
if ( window . jQuery ) {
window
. jQuery ( '#woocommerce-order-label' )
. show ( ) ;
}
}
2020-03-27 20:42:58 +00:00
}
2020-08-31 15:13:14 +00:00
} ) ;
2020-03-27 20:42:58 +00:00
2020-08-31 15:13:14 +00:00
document . getElementById (
'woocommerce-admin-print-label'
) . style . display = 'none' ;
} ) ;
2020-03-27 20:42:58 +00:00
}
}
render ( ) {
const {
isDismissModalOpen ,
showShippingBanner ,
isShippingLabelButtonBusy ,
} = this . state ;
if ( ! showShippingBanner ) {
return null ;
}
return (
< div >
< div className = "wc-admin-shipping-banner-container" >
< img
className = "wc-admin-shipping-banner-illustration"
src = { wcAdminAssetUrl + 'shippingillustration.svg' }
alt = { _ _ ( 'Shipping ' , 'woocommerce-admin' ) }
/ >
< div className = "wc-admin-shipping-banner-blob" >
< h3 >
{ _ _ (
'Print discounted shipping labels with a click.' ,
'woocommerce-admin'
) }
< / h 3 >
< p >
{ interpolateComponents ( {
mixedString : this . state . installText ,
components : {
tosLink : (
< ExternalLink
href = "https://wordpress.com/tos"
target = "_blank"
type = "external"
/ >
) ,
wcsLink : (
< ExternalLink
2021-08-03 20:56:43 +00:00
href = "https://woocommerce.com/products/shipping/?utm_medium=product"
2020-03-27 20:42:58 +00:00
target = "_blank"
type = "external"
onClick = {
this
. woocommerceServiceLinkClicked
}
/ >
) ,
} ,
} ) }
< / p >
< SetupNotice
isSetupError = { this . isSetupError ( ) }
2020-10-15 12:41:39 +00:00
errorReason = { this . state . setupErrorReason }
2020-03-27 20:42:58 +00:00
/ >
< / d i v >
< Button
disabled = { isShippingLabelButtonBusy }
isPrimary
isBusy = { isShippingLabelButtonBusy }
onClick = { this . createShippingLabelClicked }
>
{ _ _ ( 'Create shipping label' , 'woocommerce-admin' ) }
< / B u t t o n >
< button
onClick = { this . openDismissModal }
type = "button"
className = "notice-dismiss"
disabled = { this . state . isShippingLabelButtonBusy }
>
< span className = "screen-reader-text" >
{ _ _ (
'Close Print Label Banner.' ,
'woocommerce-admin'
) }
< / s p a n >
< / b u t t o n >
< / d i v >
< DismissModal
visible = { isDismissModalOpen }
onClose = { this . closeDismissModal }
onCloseAll = { this . hideBanner }
trackElementClicked = { this . trackElementClicked }
/ >
< / d i v >
) ;
}
}
ShippingBanner . propTypes = {
itemsCount : PropTypes . number . isRequired ,
isJetpackConnected : PropTypes . bool . isRequired ,
activePlugins : PropTypes . array . isRequired ,
activatePlugins : PropTypes . func . isRequired ,
2020-08-31 15:13:14 +00:00
installPlugins : PropTypes . func . isRequired ,
2020-03-27 20:42:58 +00:00
isRequesting : PropTypes . bool . isRequired ,
} ;
export default compose (
withSelect ( ( select ) => {
const {
2020-04-16 23:58:36 +00:00
isPluginsRequesting ,
2020-03-27 20:42:58 +00:00
isJetpackConnected ,
2020-04-16 23:58:36 +00:00
getActivePlugins ,
} = select ( PLUGINS _STORE _NAME ) ;
2020-03-27 20:42:58 +00:00
const isRequesting =
2020-04-16 23:58:36 +00:00
isPluginsRequesting ( 'activatePlugins' ) ||
2020-08-31 15:13:14 +00:00
isPluginsRequesting ( 'installPlugins' ) ;
2020-04-16 23:58:36 +00:00
2020-03-27 20:42:58 +00:00
return {
isRequesting ,
2020-04-16 23:58:36 +00:00
isJetpackConnected : isJetpackConnected ( ) ,
activePlugins : getActivePlugins ( ) ,
2020-03-27 20:42:58 +00:00
} ;
} ) ,
withDispatch ( ( dispatch ) => {
2020-08-31 15:13:14 +00:00
const { activatePlugins , installPlugins } = dispatch (
2020-04-16 23:58:36 +00:00
PLUGINS _STORE _NAME
) ;
2020-03-27 20:42:58 +00:00
return {
activatePlugins ,
2020-08-31 15:13:14 +00:00
installPlugins ,
2020-03-27 20:42:58 +00:00
} ;
} )
) ( ShippingBanner ) ;