/** * 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'; import { PLUGINS_STORE_NAME } from '@woocommerce/data'; import { withDispatch } from '@wordpress/data'; import { getSetting } from '@woocommerce/wc-admin-settings'; import { recordEvent } from '@woocommerce/tracks'; /** * Internal dependencies */ import '../style.scss'; import DismissModal from '../dismiss-modal'; import withSelect from '../../../wc-api/with-select'; import SetupNotice, { setupErrorTypes } from '../setup-notice'; import { getWcsAssets, acceptWcsTos } from '../wcs-api'; const wcAdminAssetUrl = getSetting( 'wcAdminAssetUrl', '' ); const wcsPluginSlug = 'woocommerce-services'; 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(); } } isSetupError = () => this.state.wcsSetupError; 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 = () => { const { activePlugins } = this.props; this.setState( { isShippingLabelButtonBusy: true } ); this.trackElementClicked( 'shipping_banner_create_label' ); if ( ! activePlugins.includes( wcsPluginSlug ) ) { this.installAndActivatePlugins( wcsPluginSlug ); } else { this.acceptTosAndGetWCSAssets(); } }; async installAndActivatePlugins( pluginSlug ) { // Avoid double activating. const { installPlugin, activatePlugins, isRequesting } = this.props; if ( isRequesting ) { return false; } const install = await installPlugin( pluginSlug ); if ( install.status !== 'success' ) { this.setState( { setupErrorReason: setupErrorTypes.INSTALL, wcsSetupError: true, } ); return; } const activation = await activatePlugins( [ pluginSlug ] ); if ( activation.status !== 'success' ) { this.setState( { setupErrorReason: setupErrorTypes.ACTIVATE, wcsSetupError: true, } ); return; } this.acceptTosAndGetWCSAssets(); } woocommerceServiceLinkClicked = () => { this.trackElementClicked( 'shipping_banner_woocommerce_service_link' ); }; trackBannerEvent = ( eventName, customProps = {} ) => { const { activePlugins, isJetpackConnected } = this.props; 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 `

${ title }

`; } loadWcsAssets( { assets } ) { if ( this.state.wcsAssetsLoaded || this.state.wcsAssetsLoading ) { this.openWcsModal(); return; } this.setState( { wcsAssetsLoading: true } ); const js = assets.wc_connect_admin_script; const styles = assets.wc_connect_admin_style; const { orderId } = this.state; const { itemsCount } = this.props; const shippingLabelContainerHtml = this.generateMetaBoxHtml( 'woocommerce-order-label', __( 'Shipping Label', 'woocommerce-admin' ), { orderId, 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' ), { orderId, 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' ); script.src = js; script.async = true; script.onload = resolve; script.onerror = reject; document.body.appendChild( script ); } ), new Promise( ( resolve, reject ) => { const head = document.getElementsByTagName( 'head' )[ 0 ]; const link = document.createElement( 'link' ); link.rel = 'stylesheet'; link.type = 'text/css'; link.href = styles; link.media = 'all'; link.onload = resolve; link.onerror = reject; head.appendChild( link ); } ), ] ).then( () => { this.setState( { wcsAssetsLoaded: true, wcsAssetsLoading: false, isShippingLabelButtonBusy: false, } ); this.openWcsModal(); } ); } getInstallText = () => { const { activePlugins } = this.props; 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() { if ( window.wcsGetAppStore ) { const wcsStore = window.wcsGetAppStore( 'wc-connect-create-shipping-label' ); 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(); } } } } ); document.getElementById( 'woocommerce-admin-print-label' ).style.display = 'none'; } } render() { const { isDismissModalOpen, showShippingBanner, isShippingLabelButtonBusy, } = this.state; if ( ! showShippingBanner ) { return null; } return (
{

{ __( 'Print discounted shipping labels with a click.', 'woocommerce-admin' ) }

{ interpolateComponents( { mixedString: this.state.installText, components: { tosLink: ( ), wcsLink: ( ), }, } ) }

); } } ShippingBanner.propTypes = { itemsCount: PropTypes.number.isRequired, isJetpackConnected: PropTypes.bool.isRequired, activePlugins: PropTypes.array.isRequired, activatePlugins: PropTypes.func.isRequired, installPlugin: PropTypes.func.isRequired, isRequesting: PropTypes.bool.isRequired, }; export default compose( withSelect( ( select ) => { const { isPluginsRequesting, isJetpackConnected, getActivePlugins, } = select( PLUGINS_STORE_NAME ); const isRequesting = isPluginsRequesting( 'activatePlugins' ) || isPluginsRequesting( 'installPlugin' ); return { isRequesting, isJetpackConnected: isJetpackConnected(), activePlugins: getActivePlugins(), }; } ), withDispatch( ( dispatch ) => { const { activatePlugins, installPlugin } = dispatch( PLUGINS_STORE_NAME ); return { activatePlugins, installPlugin, }; } ) )( ShippingBanner );