diff --git a/changelog/fix-9103-payments-settings-originated-onboarding-flow b/changelog/fix-9103-payments-settings-originated-onboarding-flow new file mode 100644 index 00000000000..8a57c714ab5 --- /dev/null +++ b/changelog/fix-9103-payments-settings-originated-onboarding-flow @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +Fix onboarding redirect loop when starting from Woo Settings Payments. diff --git a/client/checkout/woopay/express-button/express-checkout-iframe.js b/client/checkout/woopay/express-button/express-checkout-iframe.js index fa9531894da..34d85396cdd 100644 --- a/client/checkout/woopay/express-button/express-checkout-iframe.js +++ b/client/checkout/woopay/express-button/express-checkout-iframe.js @@ -17,7 +17,7 @@ import { } from '../utils'; import { getTracksIdentity } from 'tracks'; import { getAppearance } from 'wcpay/checkout/upe-styles'; -import getAppearanceType from 'wcpay/checkout/utils'; +import { getAppearanceType } from 'wcpay/checkout/utils'; export const expressCheckoutIframe = async ( api, context, emailSelector ) => { const woopayEmailInput = await getTargetElement( emailSelector ); diff --git a/client/components/account-status/account-tools/index.tsx b/client/components/account-status/account-tools/index.tsx index 34886cc95c3..de772a63fb3 100644 --- a/client/components/account-status/account-tools/index.tsx +++ b/client/components/account-status/account-tools/index.tsx @@ -12,11 +12,9 @@ import strings from './strings'; import './styles.scss'; import ResetAccountModal from 'wcpay/overview/modal/reset-account'; import { trackAccountReset } from 'wcpay/onboarding/tracking'; -import { recordEvent } from 'wcpay/tracks'; +import { isInDevMode } from 'wcpay/utils'; interface Props { - accountLink: string; - detailsSubmitted: boolean; openModal: () => void; } @@ -24,17 +22,19 @@ const handleReset = () => { trackAccountReset(); window.location.href = addQueryArgs( wcpaySettings.connectUrl, { - 'wcpay-reset-account': true, + 'wcpay-reset-account': 'true', + source: 'wcpay-reset-account', // Overwrite any existing source because we are starting over. } ); }; -export const AccountTools: React.FC< Props > = ( props: Props ) => { - const accountLink = addQueryArgs( props.accountLink, { - source: 'account-tools__finish-setup-button', - } ); - const detailsSubmitted = props.detailsSubmitted; +export const AccountTools: React.FC< Props > = () => { const [ modalVisible, setModalVisible ] = useState( false ); + // Only render when in dev/sandbox mode. + if ( ! isInDevMode() ) { + return null; + } + return ( <>
@@ -43,25 +43,8 @@ export const AccountTools: React.FC< Props > = ( props: Props ) => {

{ strings.description }

{ /* Use wrapping div to keep buttons grouped together. */ }
- { ! detailsSubmitted && ( - - ) } -
-
- -`; +exports[`AccountTools should NOT render in live mode 1`] = `
`; exports[`AccountTools should render in sandbox mode 1`] = `
@@ -59,14 +23,8 @@ exports[`AccountTools should render in sandbox mode 1`] = ` +
+
+ +

+ Active discounts +

+
+

+ Card transactions + : +

+ Euro + (EUR) + + 2.9% + 0,00 € per transaction + + 2.9% + 0,30 € per transaction +
+ + +`; + exports[`AccountStatus renders error status 1`] = `
Edit details @@ -167,39 +362,6 @@ exports[`AccountStatus renders normal status 1`] = `
-
- -

- Account Tools -

-

- Payments and deposits are disabled until account setup is completed. If you are experiencing problems completing account setup, or need to change the email/country associated with your account, you can reset your account and start from the beginning. -

-
- - Finish setup - - -
-
diff --git a/client/components/account-status/test/index.js b/client/components/account-status/test/index.js index 6af6bf36515..687a6ca507e 100644 --- a/client/components/account-status/test/index.js +++ b/client/components/account-status/test/index.js @@ -13,6 +13,7 @@ import StatusChip from '../status-chip'; describe( 'AccountStatus', () => { beforeEach( () => { global.wcpaySettings = { + devMode: false, zeroDecimalCurrencies: [], connect: { country: 'FR', @@ -78,6 +79,48 @@ describe( 'AccountStatus', () => { expect( accountStatus ).toMatchSnapshot(); } ); + test( 'renders account tools', () => { + global.wcpaySettings.devMode = true; + + const { container: accountStatus } = renderAccountStatus( + { + status: 'complete', + paymentsEnabled: 1, + deposits: { + status: 'enabled', + interval: 'weekly', + }, + progressiveOnboarding: { + isEnabled: false, + isComplete: false, + }, + }, + [ + { + payment_method: 'card', + fee: { + base: { + currency: 'EUR', + percentage_rate: 0.029, + fixed_rate: 0.3, + }, + discount: [ + { + end_time: null, + volume_allowance: null, + volume_currency: null, + current_volume: null, + percentage_rate: 0.029, + fixed_rate: 30, + }, + ], + }, + }, + ] + ); + expect( accountStatus ).toMatchSnapshot(); + } ); + function renderAccountStatus( accountStatus, accountFees ) { return render( = ( { updateAccountLink } ) => { const accountLinkWithSource = addQueryArgs( updateAccountLink, { - source: 'deposits-overview__deposit-failure-notice', + from: 'WCPAY_PAYOUTS', + source: 'wcpay-payout-failure-notice', } ); return ( diff --git a/client/components/sandbox-mode-switch-to-live-notice/index.tsx b/client/components/sandbox-mode-switch-to-live-notice/index.tsx new file mode 100644 index 00000000000..e9ce619d7b1 --- /dev/null +++ b/client/components/sandbox-mode-switch-to-live-notice/index.tsx @@ -0,0 +1,120 @@ +/** + * External dependencies + */ +import React, { useState } from 'react'; +import { Button } from '@wordpress/components'; +import { __, sprintf } from '@wordpress/i18n'; +import HelpOutlineIcon from 'gridicons/dist/help-outline'; + +/** + * Internal dependencies + */ +import BannerNotice from '../banner-notice'; +import interpolateComponents from '@automattic/interpolate-components'; +import { Link } from '@woocommerce/components'; +import { recordEvent } from 'wcpay/tracks'; +import { ClickTooltip } from 'wcpay/components/tooltip'; +import ErrorBoundary from 'wcpay/components/error-boundary'; +import SetupLivePaymentsModal from './modal'; + +interface Props { + from: string; + source: string; +} + +const SandboxModeSwitchToLiveNotice: React.FC< Props > = ( { + from, + source, +} ) => { + const [ livePaymentsModalVisible, setLivePaymentsModalVisible ] = useState( + false + ); + + const handleCtaClick = () => { + recordEvent( 'wcpay_setup_live_payments_modal_open', { + from, + source, + } ); + + setLivePaymentsModalVisible( true ); + }; + + return ( + <> + + { interpolateComponents( { + mixedString: sprintf( + /* translators: %1$s: WooPayments */ + __( + // eslint-disable-next-line max-len + '{{strong}}%1$s is in sandbox mode.{{/strong}} To accept real transactions, {{switchToLiveLink}}set up a live %1$s account.{{/switchToLiveLink}} {{learnMoreIcon/}}', + 'woocommerce-payments' + ), + 'WooPayments' + ), + components: { + strong: , + learnMoreIcon: ( + } + buttonLabel={ __( + 'Learn more about sandbox mode', + 'woocommerce-payments' + ) } + maxWidth={ '250px' } + content={ + <> + { interpolateComponents( { + mixedString: sprintf( + /* translators: %1$s: WooPayments */ + __( + // eslint-disable-next-line max-len + 'Sandbox mode gives you access to all %1$s features while checkout transactions are simulated. {{learnMoreLink}}Learn more{{/learnMoreLink}}', + 'woocommerce-payments' + ), + 'WooPayments' + ), + components: { + learnMoreLink: ( + // eslint-disable-next-line jsx-a11y/anchor-has-content + + recordEvent( + 'wcpay_overview_sandbox_mode_learn_more_clicked' + ) + } + /> + ), + }, + } ) } + + } + /> + ), + switchToLiveLink: ( +
- -
diff --git a/client/overview/modal/setup-live-payments/style.scss b/client/components/sandbox-mode-switch-to-live-notice/modal/style.scss similarity index 100% rename from client/overview/modal/setup-live-payments/style.scss rename to client/components/sandbox-mode-switch-to-live-notice/modal/style.scss diff --git a/client/overview/modal/setup-live-payments/test/index.test.tsx b/client/components/sandbox-mode-switch-to-live-notice/modal/test/index.test.tsx similarity index 79% rename from client/overview/modal/setup-live-payments/test/index.test.tsx rename to client/components/sandbox-mode-switch-to-live-notice/modal/test/index.test.tsx index ab3fa6fc3b8..2f82a5a263b 100644 --- a/client/overview/modal/setup-live-payments/test/index.test.tsx +++ b/client/components/sandbox-mode-switch-to-live-notice/modal/test/index.test.tsx @@ -26,7 +26,13 @@ describe( 'Setup Live Payments Modal', () => { }; it( 'modal is open by default', () => { - render( jest.fn() } /> ); + render( + jest.fn() } + /> + ); expect( screen.queryByText( @@ -42,7 +48,13 @@ describe( 'Setup Live Payments Modal', () => { value: new URL( window.location.href ), } ); - render( jest.fn() } /> ); + render( + jest.fn() } + /> + ); user.click( screen.getByRole( 'button', { @@ -51,7 +63,7 @@ describe( 'Setup Live Payments Modal', () => { ); expect( window.location.href ).toBe( - `https://wcpay.test/connect?wcpay-disable-onboarding-test-mode=true` + `https://wcpay.test/connect?wcpay-disable-onboarding-test-mode=true&from=bogus&source=wcpay-setup-live-payments` ); } ); } ); diff --git a/client/components/test-mode-notice/index.tsx b/client/components/test-mode-notice/index.tsx index 42b1198f62c..5e799158204 100644 --- a/client/components/test-mode-notice/index.tsx +++ b/client/components/test-mode-notice/index.tsx @@ -26,7 +26,7 @@ interface Props { currentPage: CurrentPage; actions?: React.ComponentProps< typeof BannerNotice >[ 'actions' ]; isDetailsView?: boolean; - isDevMode?: boolean; + isOnboardingTestMode?: boolean; } const nounToUse = { @@ -50,11 +50,11 @@ const verbToUse = { const getNoticeContent = ( currentPage: CurrentPage, isDetailsView: boolean, - isDevMode: boolean + isOnboardingTestMode: boolean ): JSX.Element => { switch ( currentPage ) { case 'overview': - return isDevMode ? ( + return isOnboardingTestMode ? ( <> { interpolateComponents( { mixedString: sprintf( @@ -163,7 +163,7 @@ export const TestModeNotice: React.FC< Props > = ( { currentPage, actions, isDetailsView = false, - isDevMode = false, + isOnboardingTestMode = false, } ) => { if ( ! isInTestMode() ) return null; @@ -173,7 +173,11 @@ export const TestModeNotice: React.FC< Props > = ( { isDismissible={ false } actions={ actions } > - { getNoticeContent( currentPage, isDetailsView, isDevMode ) } + { getNoticeContent( + currentPage, + isDetailsView, + isOnboardingTestMode + ) } ); }; diff --git a/client/connect-account-page/index.tsx b/client/connect-account-page/index.tsx index 1c1c10bf648..b3bb4de29bc 100644 --- a/client/connect-account-page/index.tsx +++ b/client/connect-account-page/index.tsx @@ -9,7 +9,6 @@ import { Button, Card, CardBody, - Notice, Panel, PanelBody, } from '@wordpress/components'; @@ -30,6 +29,11 @@ import strings from './strings'; import './style.scss'; import InlineNotice from 'components/inline-notice'; import { WooPaymentMethodsLogos } from 'components/payment-method-logos'; +import { sanitizeHTML } from 'wcpay/utils/sanitize'; +import { isInDevMode } from 'wcpay/utils'; +import ResetAccountModal from 'wcpay/overview/modal/reset-account'; +import { trackAccountReset } from 'wcpay/onboarding/tracking'; +import SandboxModeSwitchToLiveNotice from 'wcpay/components/sandbox-mode-switch-to-live-notice'; const SandboxModeNotice = () => ( @@ -40,8 +44,7 @@ const SandboxModeNotice = () => ( const ConnectAccountPage: React.FC = () => { const firstName = wcSettings.admin?.currentUserData?.first_name; const incentive = wcpaySettings.connectIncentive; - const isNewFlowEnabled = - wcpaySettings.progressiveOnboarding?.isNewFlowEnabled; + const [ modalVisible, setModalVisible ] = useState( false ); const [ errorMessage, setErrorMessage ] = useState< string >( wcpaySettings.errorMessage @@ -52,26 +55,52 @@ const ConnectAccountPage: React.FC = () => { connectUrl, connect: { availableCountries, country }, devMode, + onboardingTestMode, + isJetpackConnected, + isAccountConnected, + isAccountValid, } = wcpaySettings; const isCountrySupported = !! availableCountries[ country ]; + const urlParams = new URLSearchParams( window.location.search ); + const determineTrackingSource = () => { - const urlParams = new URLSearchParams( window.location.search ); - const from = urlParams.get( 'from' ) || ''; + // If we have a source query param in the current request, use that. + const urlSource = urlParams.get( 'source' )?.replace( /[^\w-]+/g, '' ); + if ( !! urlSource && 'unknown' !== urlSource ) { + return urlSource; + } - // Determine where the user came from. - let source = 'wcadmin'; - switch ( from ) { + // Next, search for a source in the Connect URL as that is determined server-side and it is reliable. + if ( connectUrl.includes( 'source=' ) ) { + const url = new URL( connectUrl ); + const source = url.searchParams.get( 'source' ); + if ( !! source && 'unknown' !== source ) { + return source; + } + } + // Finally, make some guesses based on the 'from' query param. + // We generally should not reach this step, but it's a fallback with reliable guesses. + const urlFrom = urlParams.get( 'from' ) || ''; + let sourceGuess = 'wcpay-connect-page'; + switch ( urlFrom ) { case 'WCADMIN_PAYMENT_TASK': - source = 'wcadmin-payment-task'; + sourceGuess = 'wcadmin-payment-task'; break; case 'WCADMIN_PAYMENT_SETTINGS': - source = 'wcadmin-settings-page'; + sourceGuess = 'wcadmin-settings-page'; + break; + case 'WCADMIN_PAYMENT_INCENTIVE': + sourceGuess = 'wcadmin-incentive-page'; break; } - return source; + return sourceGuess; + }; + + const determineTrackingFrom = () => { + return urlParams.get( 'from' )?.replace( /[^\w-]+/g, '' ) || ''; }; useEffect( () => { @@ -80,6 +109,7 @@ const ConnectAccountPage: React.FC = () => { ...( incentive && { incentive_id: incentive.id, } ), + from: determineTrackingFrom(), source: determineTrackingSource(), } ); // We only want to run this once. @@ -93,7 +123,10 @@ const ConnectAccountPage: React.FC = () => { }; // Redirect the merchant if merchant decided to continue const handleModalConfirmed = () => { - window.location.href = connectUrl; + window.location.href = addQueryArgs( connectUrl, { + source: determineTrackingSource(), + from: 'WCPAY_CONNECT', + } ); }; // Populate translated list of supported countries we want to render in the modal window. @@ -118,13 +151,13 @@ const ConnectAccountPage: React.FC = () => { const trackConnectAccountClicked = ( sandboxMode: boolean ) => { recordEvent( 'wcpay_connect_account_clicked', { - wpcom_connection: wcpaySettings.isJetpackConnected ? 'Yes' : 'No', - is_new_onboarding_flow: isNewFlowEnabled, + wpcom_connection: isJetpackConnected ? 'Yes' : 'No', ...( incentive && { incentive_id: incentive.id, } ), sandbox_mode: sandboxMode, path: 'payments_connect_v2', + from: determineTrackingFrom(), source: determineTrackingSource(), } ); }; @@ -155,7 +188,10 @@ const ConnectAccountPage: React.FC = () => { return handleLocationCheck(); } - window.location.href = connectUrl; + window.location.href = addQueryArgs( connectUrl, { + source: determineTrackingSource(), + from: 'WCPAY_CONNECT', + } ); }; const handleEnableSandboxMode = async () => { @@ -163,23 +199,68 @@ const ConnectAccountPage: React.FC = () => { trackConnectAccountClicked( true ); - const url = addQueryArgs( connectUrl, { - test_mode: true, - create_builder_account: true, + window.location.href = addQueryArgs( connectUrl, { + test_mode: 'true', + create_builder_account: 'true', + source: determineTrackingSource(), + from: 'WCPAY_CONNECT', + } ); + }; + + const handleReset = () => { + trackAccountReset(); + + window.location.href = addQueryArgs( wcpaySettings.connectUrl, { + 'wcpay-reset-account': 'true', + from: 'WCPAY_CONNECT', + source: determineTrackingSource(), } ); - window.location.href = url; }; + // Determine if we have the account session error message since we want to customize the UX a little bit. + let isAccountSetupSessionError = false; + if ( errorMessage && errorMessage.includes( 'account setup session' ) ) { + isAccountSetupSessionError = true; + } + + let ctaLabel = strings.button.jetpack_not_connected; + if ( isJetpackConnected ) { + ctaLabel = strings.button.account_not_connected; + // If we have the account setup session error, best not to push too much with the CTA copy. + if ( + ! isAccountSetupSessionError && + isAccountConnected && + ! isAccountValid + ) { + ctaLabel = strings.button.account_invalid; + } + } + + // If there is no error message from elsewhere, but we have: + // - a broken Jetpack connection and a connected account; + // - or working Jetpack connection and a connected but invalid account. + // show a generic error message. + if ( + ! errorMessage && + ( ( ! isJetpackConnected && isAccountConnected ) || + ( isJetpackConnected && isAccountConnected && ! isAccountValid ) ) + ) { + setErrorMessage( strings.setupErrorNotice ); + } + return ( { errorMessage && ( - - { errorMessage } - +
+
) } { wcpaySettings.onBoardingDisabled ? ( @@ -192,7 +273,25 @@ const ConnectAccountPage: React.FC = () => { { strings.nonSupportedCountry } ) } - { devMode && } + { + // Show general sandbox notice when no account is connected but sandbox mode is active. + ! isAccountConnected && devMode ? ( + + ) : ( + // If we already have a sandbox account connected (but in an invalid state) and + // a working Jetpack connection (to be able to delete the current account) + // show the switch to live sandbox notice. + isAccountConnected && + ! isAccountValid && + onboardingTestMode && + isJetpackConnected && ( + + ) + ) + }
logo @@ -248,38 +347,69 @@ const ConnectAccountPage: React.FC = () => { + { + // Only show the reset button if an account is connected and didn't complete KYC, or if we are in dev mode. + isAccountConnected && + ( ! wcpaySettings.accountStatus + .detailsSubmitted || + isInDevMode() ) && ( + + ) + }
- { incentive && } - - - - { strings.sandboxMode.description } - - - - + { + // Only show the incentive if an account is NOT connected. + ! isAccountConnected && incentive && ( + + ) + } + { + // Only show the sandbox mode panel if an account is NOT connected. + ! isAccountConnected && ( + + + + { strings.sandboxMode.description } + + + + + ) + } + setModalVisible( false ) } + onSubmit={ handleReset } + /> ) } diff --git a/client/connect-account-page/strings.tsx b/client/connect-account-page/strings.tsx index d5a3f647bd0..808b9c13705 100644 --- a/client/connect-account-page/strings.tsx +++ b/client/connect-account-page/strings.tsx @@ -9,15 +9,24 @@ import interpolateComponents from '@automattic/interpolate-components'; export default { button: { + // CTA label to use when there isn't a working WPCOM/Jetpack connection. jetpack_not_connected: __( 'Connect your store', 'woocommerce-payments' ), - jetpack_connected: __( + // CTA label to use when there is a working WPCOM/Jetpack connection but no Stripe account connected. + account_not_connected: __( 'Verify business details', 'woocommerce-payments' ), + // CTA label to use when there is a working WPCOM/Jetpack connection and a Stripe account connected, + // but only partially onboarded (not valid). + account_invalid: __( + 'Finish business details verifications', + 'woocommerce-payments' + ), sandbox: __( 'Enable sandbox mode', 'woocommerce-payments' ), + reset: __( 'Reset account', 'woocommerce-payments' ), }, heading: ( firstName?: string ): string => sprintf( @@ -83,6 +92,14 @@ export default { ), }, } ), + setupErrorNotice: sprintf( + /* translators: 1: WooPayments. */ + __( + 'Please complete your %1$s setup to process payments.', + 'woocommerce-payments' + ), + 'WooPayments' + ), infoNotice: { description: { jetpack_connected: __( diff --git a/client/connect-account-page/style.scss b/client/connect-account-page/style.scss index 0ffe38a59c7..40b3ee7f567 100644 --- a/client/connect-account-page/style.scss +++ b/client/connect-account-page/style.scss @@ -93,6 +93,7 @@ button { width: 100%; justify-content: center; + margin-right: $gap-small; @media screen and ( min-width: $break-small ) { width: auto; justify-content: left; diff --git a/client/deposits/index.tsx b/client/deposits/index.tsx index 3e49173e39f..b8ac083eda3 100644 --- a/client/deposits/index.tsx +++ b/client/deposits/index.tsx @@ -102,7 +102,8 @@ const NextDepositNotice: React.FC = () => { const DepositFailureNotice: React.FC = () => { const { hasErroredExternalAccount } = useAccountStatus(); const accountLink = addQueryArgs( wcpaySettings.accountStatus.accountLink, { - source: 'deposit__failure-notice', + from: 'WCPAY_PAYOUTS', + source: 'wcpay-payout-failure-notice', } ); return hasErroredExternalAccount ? ( @@ -123,7 +124,10 @@ const DepositFailureNotice: React.FC = () => { onClick={ () => recordEvent( 'wcpay_account_details_link_clicked', - { source: 'deposit__failure-notice' } + { + from: 'WCPAY_PAYOUTS', + source: 'wcpay-payout-failure-notice', + } ) } href={ accountLink } diff --git a/client/globals.d.ts b/client/globals.d.ts index ec99d1150b7..56fb0558d52 100644 --- a/client/globals.d.ts +++ b/client/globals.d.ts @@ -21,6 +21,8 @@ declare global { devMode: boolean; isJetpackConnected: boolean; isJetpackIdcActive: boolean; + isAccountConnected: boolean; + isAccountValid: boolean; accountStatus: { email?: string; created: string; @@ -85,7 +87,6 @@ declare global { isWelcomeTourDismissed?: boolean; }; progressiveOnboarding?: { - isNewFlowEnabled: boolean; isEnabled: boolean; isComplete: boolean; isEligibilityModalDismissed: boolean; diff --git a/client/onboarding/index.tsx b/client/onboarding/index.tsx index 375c0bbd4e2..5def61ebd4b 100644 --- a/client/onboarding/index.tsx +++ b/client/onboarding/index.tsx @@ -21,9 +21,15 @@ import './style.scss'; const OnboardingStepper = () => { const handleExit = () => { + const urlParams = new URLSearchParams( window.location.search ); + window.location.href = getAdminUrl( { page: 'wc-admin', path: '/payments/connect', + source: + urlParams.get( 'source' )?.replace( /[^\w-]+/g, '' ) || + 'unknown', + from: 'WCPAY_ONBOARDING_WIZARD', } ); }; @@ -73,8 +79,9 @@ const initialData = { const OnboardingPage: React.FC = () => { useEffect( () => { const urlParams = new URLSearchParams( window.location.search ); - const source = urlParams.get( 'source' ) || ''; - trackStarted( source.replace( /[^\w-]+/g, '' ) ); + const source = + urlParams.get( 'source' )?.replace( /[^\w-]+/g, '' ) || 'unknown'; + trackStarted( source ); // Remove loading class and add those required for full screen. document.body.classList.remove( 'woocommerce-admin-is-loading' ); diff --git a/client/onboarding/step.tsx b/client/onboarding/step.tsx index 6976f025765..c6f4aee0b17 100644 --- a/client/onboarding/step.tsx +++ b/client/onboarding/step.tsx @@ -23,7 +23,11 @@ const Step: React.FC< Props > = ( { name, children } ) => { const { trackAbandoned } = useTrackAbandoned(); const { prevStep, exit } = useStepperContext(); const handleExit = () => { - trackAbandoned( 'exit' ); + const urlParams = new URLSearchParams( window.location.search ); + const source = + urlParams.get( 'source' )?.replace( /[^\w-]+/g, '' ) || 'unknown'; + + trackAbandoned( 'exit', source ); exit(); }; diff --git a/client/onboarding/steps/loading.tsx b/client/onboarding/steps/loading.tsx index 8f2e717e9f0..297bf5fb799 100644 --- a/client/onboarding/steps/loading.tsx +++ b/client/onboarding/steps/loading.tsx @@ -56,6 +56,11 @@ const LoadingStep: React.FC< Props > = () => { const handleComplete = async () => { const { connectUrl } = wcpaySettings; + + const urlParams = new URLSearchParams( window.location.search ); + const urlSource = + urlParams.get( 'source' )?.replace( /[^\w-]+/g, '' ) || 'unknown'; + let isEligible; try { isEligible = await isEligibleForPo(); @@ -64,16 +69,16 @@ const LoadingStep: React.FC< Props > = () => { // TODO maybe log these errors in future, e.g. with tracks. isEligible = false; } - const resultUrl = addQueryArgs( connectUrl, { - self_assessment: fromDotNotation( data ), - progressive: isEligible, - source: 'onboarding-wizard', - } ); - trackRedirected( isEligible ); + trackRedirected( isEligible, urlSource ); removeTrackListener(); - window.location.href = resultUrl; + window.location.href = addQueryArgs( connectUrl, { + self_assessment: fromDotNotation( data ), + progressive: isEligible, + source: urlSource, + from: 'WCPAY_ONBOARDING_WIZARD', + } ); }; useEffect( () => { diff --git a/client/onboarding/tracking.ts b/client/onboarding/tracking.ts index deaea708ca1..c46997b0b36 100644 --- a/client/onboarding/tracking.ts +++ b/client/onboarding/tracking.ts @@ -42,10 +42,14 @@ export const trackStepCompleted = ( step: string ): void => { trackedSteps.add( step ); }; -export const trackRedirected = ( isEligible: boolean ): void => { +export const trackRedirected = ( + isEligible: boolean, + source: string +): void => { recordEvent( 'wcpay_onboarding_flow_redirected', { is_po_eligible: isEligible, elapsed: elapsed( startTime ), + source, } ); }; @@ -53,20 +57,22 @@ export const trackAccountReset = (): void => recordEvent( 'wcpay_onboarding_flow_reset' ); export const trackEligibilityModalClosed = ( - action: 'dismiss' | 'setup_deposits' | 'enable_payments_only' + action: 'dismiss' | 'setup_deposits' | 'enable_payments_only', + source: string ): void => recordEvent( 'wcpay_onboarding_flow_eligibility_modal_closed', { action, + source, } ); export const useTrackAbandoned = (): { - trackAbandoned: ( method: 'hide' | 'exit' ) => void; + trackAbandoned: ( method: 'hide' | 'exit', source: string ) => void; removeTrackListener: () => void; } => { const { errors, touched } = useOnboardingContext(); const { currentStep: step } = useStepperContext(); - const trackEvent = ( method = 'hide' ) => { + const trackEvent = ( method = 'hide', source = 'unknown' ) => { const event = method === 'hide' ? 'wcpay_onboarding_flow_hidden' @@ -79,12 +85,17 @@ export const useTrackAbandoned = (): { step, errored, elapsed: elapsed( startTime ), + source, } ); }; const listener = () => { if ( document.visibilityState === 'hidden' ) { - trackEvent(); + const urlParams = new URLSearchParams( window.location.search ); + const source = + urlParams.get( 'source' )?.replace( /[^\w-]+/g, '' ) || + 'unknown'; + trackEvent( 'hide', source ); } }; @@ -97,8 +108,8 @@ export const useTrackAbandoned = (): { }, [ step, errors, touched ] ); return { - trackAbandoned: ( method: string ) => { - trackEvent( method ); + trackAbandoned: ( method: string, source = 'unknown' ) => { + trackEvent( method, source ); document.removeEventListener( 'visibilitychange', listener ); }, removeTrackListener: () => diff --git a/client/overview/index.js b/client/overview/index.js index ab6ca7e8404..11c7564234a 100644 --- a/client/overview/index.js +++ b/client/overview/index.js @@ -3,10 +3,10 @@ /** * External dependencies */ -import React, { useState } from 'react'; -import { Button, Card, Notice } from '@wordpress/components'; +import React from 'react'; +import { Card, Notice } from '@wordpress/components'; import { getQuery } from '@woocommerce/navigation'; -import { __, sprintf } from '@wordpress/i18n'; +import { __ } from '@wordpress/i18n'; /** * Internal dependencies. @@ -25,17 +25,11 @@ import Welcome from 'components/welcome'; import { TestModeNotice } from 'components/test-mode-notice'; import InboxNotifications from './inbox-notifications'; import ProgressiveOnboardingEligibilityModal from './modal/progressive-onboarding-eligibility'; -import SetupLivePaymentsModal from './modal/setup-live-payments'; import TaskList from './task-list'; import { getTasks, taskSort } from './task-list/tasks'; import { useDisputes, useGetSettings, useSettings } from 'data'; +import SandboxModeSwitchToLiveNotice from 'wcpay/components/sandbox-mode-switch-to-live-notice'; import './style.scss'; -import BannerNotice from 'wcpay/components/banner-notice'; -import interpolateComponents from '@automattic/interpolate-components'; -import { Link } from '@woocommerce/components'; -import { recordEvent } from 'wcpay/tracks'; -import { ClickTooltip } from 'wcpay/components/tooltip'; -import HelpOutlineIcon from 'gridicons/dist/help-outline'; const OverviewPageError = () => { const queryParams = getQuery(); @@ -58,74 +52,6 @@ const OverviewPageError = () => { ); }; -const OverviewSandboxModeNotice = ( { ctaAction = () => {} } ) => { - return ( - - { interpolateComponents( { - mixedString: sprintf( - /* translators: %1$s: WooPayments */ - __( - // eslint-disable-next-line max-len - '{{strong}}%1$s is in sandbox mode.{{/strong}} To accept real transactions, {{switchToLiveLink}}set up a live %1$s account.{{/switchToLiveLink}} {{learnMoreIcon/}}', - 'woocommerce-payments' - ), - 'WooPayments' - ), - components: { - strong: , - learnMoreIcon: ( - } - buttonLabel={ __( - 'Learn more about sandbox mode', - 'woocommerce-payments' - ) } - maxWidth={ '250px' } - content={ - <> - { interpolateComponents( { - mixedString: sprintf( - /* translators: %1$s: WooPayments */ - __( - // eslint-disable-next-line max-len - 'Sandbox mode gives you access to all %1$s features while checkout transactions are simulated. {{learnMoreLink}}Learn more{{/learnMoreLink}}', - 'woocommerce-payments' - ), - 'WooPayments' - ), - components: { - learnMoreLink: ( - // eslint-disable-next-line jsx-a11y/anchor-has-content - - recordEvent( - 'wcpay_overview_sandbox_mode_learn_more_clicked' - ) - } - /> - ), - }, - } ) } - - } - /> - ), - switchToLiveLink: ( -