/** * External dependencies */ import { __ } from '@wordpress/i18n'; import { Button, Card, CardBody } from '@wordpress/components'; import { Component, Fragment } from '@wordpress/element'; import { compose } from '@wordpress/compose'; import { difference, filter } from 'lodash'; import interpolateComponents from 'interpolate-components'; import { withDispatch, withSelect } from '@wordpress/data'; import { H, Link, Stepper, Plugins, Spinner } from '@woocommerce/components'; import { getHistory, getNewPath } from '@woocommerce/navigation'; import { getAdminLink } from '@woocommerce/wc-admin-settings'; import { ONBOARDING_STORE_NAME, OPTIONS_STORE_NAME, PLUGINS_STORE_NAME, SETTINGS_STORE_NAME, } from '@woocommerce/data'; import { recordEvent, queueRecordEvent } from '@woocommerce/tracks'; import { Text } from '@woocommerce/experimental'; /** * Internal dependencies */ import Connect from '../../dashboard/components/connect'; import { createNoticesFromResponse } from '../../lib/notices'; import { getCountryCode } from '../../dashboard/utils'; import StoreLocation from './steps/location'; class Tax extends Component { constructor( props ) { super( props ); const { hasCompleteAddress, pluginsToActivate } = props; this.initialState = { isPending: false, stepIndex: hasCompleteAddress ? 1 : 0, // Cache the value of pluginsToActivate so that we can // show/hide tasks based on it, but not have them update mid task. cachedPluginsToActivate: pluginsToActivate, }; this.state = this.initialState; this.completeStep = this.completeStep.bind( this ); } componentDidMount() { const { query } = this.props; const { auto } = query; this.reset(); if ( auto === 'true' ) { this.enableAutomatedTax(); } } reset() { this.setState( this.initialState ); } shouldShowSuccessScreen() { const { isJetpackConnected, hasCompleteAddress, pluginsToActivate, } = this.props; return ( hasCompleteAddress && ! pluginsToActivate.length && isJetpackConnected && this.isTaxJarSupported() ); } isTaxJarSupported() { const { countryCode, tasksStatus } = this.props; const { automatedTaxSupportedCountries = [], taxJarActivated, } = tasksStatus; return ( ! taxJarActivated && // WCS integration doesn't work with the official TaxJar plugin. automatedTaxSupportedCountries.includes( countryCode ) ); } completeStep() { const { stepIndex } = this.state; const steps = this.getSteps(); const nextStep = steps[ stepIndex + 1 ]; if ( nextStep ) { this.setState( { stepIndex: stepIndex + 1 } ); } } async manuallyConfigureTaxRates() { const { generalSettings, updateAndPersistSettingsForGroup, } = this.props; if ( generalSettings.woocommerce_calc_taxes !== 'yes' ) { this.setState( { isPending: true } ); updateAndPersistSettingsForGroup( 'general', { general: { ...generalSettings, woocommerce_calc_taxes: 'yes', }, } ) .then( () => this.redirectToTaxSettings() ) .catch( ( error ) => createNoticesFromResponse( error ) ); } else { this.redirectToTaxSettings(); } } updateAutomatedTax( isEnabling ) { const { clearTaskStatusCache, createNotice, updateAndPersistSettingsForGroup, generalSettings, taxSettings, } = this.props; Promise.all( [ updateAndPersistSettingsForGroup( 'tax', { tax: { ...taxSettings, wc_connect_taxes_enabled: isEnabling ? 'yes' : 'no', }, } ), updateAndPersistSettingsForGroup( 'general', { general: { ...generalSettings, woocommerce_calc_taxes: 'yes', }, } ), ] ) .then( () => { clearTaskStatusCache(); if ( isEnabling ) { createNotice( 'success', __( "You're awesome! One less item on your to-do list ✅", 'woocommerce-admin' ) ); getHistory().push( getNewPath( {}, '/', {} ) ); } else { this.redirectToTaxSettings(); } } ) .catch( () => { createNotice( 'error', __( 'There was a problem updating your tax settings', 'woocommerce-admin' ) ); } ); } redirectToTaxSettings() { window.location = getAdminLink( 'admin.php?page=wc-settings&tab=tax§ion=standard&wc_onboarding_active_task=tax' ); } doNotChargeSalesTax() { const { updateOptions } = this.props; queueRecordEvent( 'tasklist_tax_connect_store', { connect: false, no_tax: true, } ); updateOptions( { woocommerce_no_sales_tax: true, woocommerce_calc_taxes: 'no', } ).then( () => { window.location = getAdminLink( 'admin.php?page=wc-admin' ); } ); } getSteps() { const { generalSettings, isJetpackConnected, isPending, tosAccepted, updateOptions, } = this.props; const { cachedPluginsToActivate } = this.state; let step2Label, agreementText; if ( cachedPluginsToActivate.includes( 'woocommerce-services' ) ) { step2Label = __( 'Install Jetpack and WooCommerce Tax', 'woocommerce-admin' ); agreementText = __( 'By installing Jetpack and WooCommerce Tax you agree to the {{link}}Terms of Service{{/link}}.', 'woocommerce-admin' ); } else { step2Label = __( 'Install Jetpack', 'woocommerce-admin' ); agreementText = __( 'By installing Jetpack you agree to the {{link}}Terms of Service{{/link}}.', 'woocommerce-admin' ); } const steps = [ { key: 'store_location', label: __( 'Set store location', 'woocommerce-admin' ), description: __( 'The address from which your business operates', 'woocommerce-admin' ), content: ( { const country = getCountryCode( values.countryState ); recordEvent( 'tasklist_tax_set_location', { country, } ); this.completeStep(); } } isSettingsRequesting={ false } settings={ generalSettings } /> ), visible: true, }, { key: 'plugins', label: step2Label, description: __( 'Jetpack and WooCommerce Tax allow you to automate sales tax calculations', 'woocommerce-admin' ), content: ( { createNoticesFromResponse( response ); recordEvent( 'tasklist_tax_install_extensions', { install_extensions: true, } ); updateOptions( { woocommerce_setup_jetpack_opted_in: true, } ); this.completeStep(); } } onError={ ( errors, response ) => createNoticesFromResponse( response ) } onSkip={ () => { queueRecordEvent( 'tasklist_tax_install_extensions', { install_extensions: false, } ); this.manuallyConfigureTaxRates(); } } skipText={ __( 'Set up manually', 'woocommerce-admin' ) } onAbort={ () => this.doNotChargeSalesTax() } abortText={ __( "I don't charge sales tax", 'woocommerce-admin' ) } /> { ! tosAccepted && ( { interpolateComponents( { mixedString: agreementText, components: { link: ( ), }, } ) } ) } ), visible: ( cachedPluginsToActivate.length || ! tosAccepted ) && this.isTaxJarSupported(), }, { key: 'connect', label: __( 'Connect your store', 'woocommerce-admin' ), description: __( 'Connect your store to WordPress.com to enable automated sales tax calculations', 'woocommerce-admin' ), content: ( { recordEvent( 'tasklist_tax_connect_store', { connect: true, no_tax: false, } ); } } onSkip={ () => { queueRecordEvent( 'tasklist_tax_connect_store', { connect: false, no_tax: false, } ); this.manuallyConfigureTaxRates(); } } skipText={ __( 'Set up tax rates manually', 'woocommerce-admin' ) } onAbort={ () => this.doNotChargeSalesTax() } abortText={ __( "My business doesn't charge sales tax", 'woocommerce-admin' ) } /> ), visible: ! isJetpackConnected && this.isTaxJarSupported(), }, { key: 'manual_configuration', label: __( 'Configure tax rates', 'woocommerce-admin' ), description: __( 'Head over to the tax rate settings screen to configure your tax rates', 'woocommerce-admin' ), content: (

{ generalSettings.woocommerce_calc_taxes !== 'yes' && interpolateComponents( { mixedString: __( /*eslint-disable max-len*/ 'By clicking "Configure" you\'re enabling tax rates and calculations. More info {{link}}here{{/link}}.', /*eslint-enable max-len*/ 'woocommerce-admin' ), components: { link: ( ), }, } ) }

), visible: ! this.isTaxJarSupported(), }, ]; return filter( steps, ( step ) => step.visible ); } enableAutomatedTax() { recordEvent( 'tasklist_tax_setup_automated_proceed', { setup_automatically: true, } ); this.updateAutomatedTax( true ); } renderSuccessScreen() { const { isPending } = this.props; return (
🎊 { __( 'Good news!', 'woocommerce-admin' ) }

{ interpolateComponents( { mixedString: __( '{{strong}}Jetpack{{/strong}} and {{strong}}WooCommerce Tax{{/strong}} ' + 'can automate your sales tax calculations for you.', 'woocommerce-admin' ), components: { strong: , }, } ) }

); } render() { const { stepIndex } = this.state; const { isPending, isResolving } = this.props; if ( isResolving ) { return ; } const step = this.getSteps()[ stepIndex ]; return (
{ this.shouldShowSuccessScreen() ? ( this.renderSuccessScreen() ) : ( ) }
); } } export default compose( withSelect( ( select ) => { const { getSettings, isUpdateSettingsRequesting } = select( SETTINGS_STORE_NAME ); const { getOption, hasFinishedResolution } = select( OPTIONS_STORE_NAME ); const { getActivePlugins, isJetpackConnected, isPluginsRequesting, } = select( PLUGINS_STORE_NAME ); const { getTasksStatus } = select( ONBOARDING_STORE_NAME ); const { general: generalSettings = {} } = getSettings( 'general' ); const countryCode = getCountryCode( generalSettings.woocommerce_default_country ); const { woocommerce_store_address: storeAddress, woocommerce_default_country: defaultCountry, woocommerce_store_postcode: storePostCode, } = generalSettings; const hasCompleteAddress = Boolean( storeAddress && defaultCountry && storePostCode ); const { tax: taxSettings = {} } = getSettings( 'tax' ); const activePlugins = getActivePlugins(); const pluginsToActivate = difference( [ 'jetpack', 'woocommerce-services' ], activePlugins ); const connectOptions = getOption( 'wc_connect_options' ) || {}; const jetpackOptIn = getOption( 'woocommerce_setup_jetpack_opted_in' ); const tosAccepted = connectOptions.tos_accepted || jetpackOptIn === '1'; const tasksStatus = getTasksStatus(); const isPending = isUpdateSettingsRequesting( 'tax' ) || isUpdateSettingsRequesting( 'general' ); const isResolving = isPluginsRequesting( 'getJetpackConnectUrl' ) || ! hasFinishedResolution( 'getOption', [ 'woocommerce_setup_jetpack_opted_in', ] ) || ! hasFinishedResolution( 'getOption', [ 'wc_connect_options' ] ) || jetpackOptIn === undefined || connectOptions === undefined; return { countryCode, generalSettings, hasCompleteAddress, isJetpackConnected: isJetpackConnected(), isPending, isResolving, pluginsToActivate, tasksStatus, taxSettings, tosAccepted, }; } ), withDispatch( ( dispatch ) => { const { createNotice } = dispatch( 'core/notices' ); const { updateOptions } = dispatch( OPTIONS_STORE_NAME ); const { updateAndPersistSettingsForGroup } = dispatch( SETTINGS_STORE_NAME ); const { invalidateResolutionForStoreSelector } = dispatch( ONBOARDING_STORE_NAME ); return { clearTaskStatusCache: () => invalidateResolutionForStoreSelector( 'getTasksStatus' ), createNotice, updateAndPersistSettingsForGroup, updateOptions, }; } ) )( Tax );